个人博客开发之blog-api项目统一结果集api封装

kenx 等级 506 0 0

前言

由于返回json api 格式接口,所以我们需要通过java bean封装一个统一数据返回格式,便于和前端约定交互,

状态码枚举ResultCode

package cn.soboys.core.ret;


import lombok.Getter;

/**
 * @author kenx
 * @version 1.0
 * @date 2021/6/17 15:35
 * 响应码枚举,对应HTTP状态码
 */
@Getter
public enum ResultCode {

    SUCCESS(200, "成功"),//成功
    //FAIL(400, "失败"),//失败
    BAD_REQUEST(400, "Bad Request"),
    UNAUTHORIZED(401, "认证失败"),//未认证
    NOT_FOUND(404, "接口不存在"),//接口不存在
    INTERNAL_SERVER_ERROR(500, "系统繁忙"),//服务器内部错误
    METHOD_NOT_ALLOWED(405,"方法不被允许"),

    /*参数错误:1001-1999*/
    PARAMS_IS_INVALID(1001, "参数无效"),
    PARAMS_IS_BLANK(1002, "参数为空");
    /*用户错误2001-2999*/


    private Integer code;
    private String message;

    ResultCode(int code, String message) {
        this.code = code;
        this.message = message;
    }
}

结果体Result

package cn.soboys.core.ret;

import lombok.Data;

import java.io.Serializable;

/**
 * @author kenx
 * @version 1.0
 * @date 2021/6/17 15:47
 * 统一API响应结果格式封装
 */
@Data
public class Result<T> implements Serializable {

    private static final long serialVersionUID = 6308315887056661996L;
    private Integer code;
    private String message;
    private T data;


    public Result setResult(ResultCode resultCode) {
        this.code = resultCode.getCode();
        this.message = resultCode.getMessage();
        return this;
    }

    public Result setResult(ResultCode resultCode, T data) {
        this.code = resultCode.getCode();
        this.message = resultCode.getMessage();
        this.setData(data);
        return this;
    }


}

响应结果方法工具类

package cn.soboys.core.ret;

/**
 * @author kenx
 * @version 1.0
 * @date 2021/6/17 16:30
 * 响应结果返回封装
 */
public class ResultResponse {
    private static final String DEFAULT_SUCCESS_MESSAGE = "SUCCESS";

    // 只返回状态
    public static Result success() {
        return new Result()
                .setResult(ResultCode.SUCCESS);
    }

    // 成功返回数据
    public static Result success(Object data) {
        return new Result()
                .setResult(ResultCode.SUCCESS, data);


    }

    // 失败
    public static Result failure(ResultCode resultCode) {
        return new Result()
                .setResult(resultCode);
    }

    // 失败
    public static Result failure(ResultCode resultCode, Object data) {
        return new Result()
                .setResult(resultCode, data);
    }



}

自定义解析controller拦截

注解@ResponseResult

package cn.soboys.core.ret;

import java.lang.annotation.*;

/**
 * @author kenx
 * @version 1.0
 * @date 2021/6/17 16:43
 * 统一包装接口返回的值 Result
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ResponseResult {
}

请求拦截ResponseResultInterceptor

package cn.soboys.core.ret;

import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;

/**
 * @author kenx
 * @version 1.0
 * @date 2021/6/17 17:10
 * 请求拦截
 */
public class ResponseResultInterceptor implements HandlerInterceptor {

    //标记名称
    public static final String RESPONSE_RESULT_ANN = "RESPONSE-RESULT-ANN";

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //请求方法
        if (handler instanceof HandlerMethod) {
            final HandlerMethod handlerMethod = (HandlerMethod) handler;
            final Class<?> clazz = handlerMethod.getBeanType();
            final Method method = handlerMethod.getMethod();
            //判断是否在对象上加了注解
            if (clazz.isAnnotationPresent(ResponseResult.class)) {
                //设置此请求返回体需要包装,往下传递,在ResponseBodyAdvice接口进行判断
                request.setAttribute(RESPONSE_RESULT_ANN, clazz.getAnnotation(ResponseResult.class));
                //方法体上是否有注解
            } else if (method.isAnnotationPresent(ResponseResult.class)) {
                //设置此请求返回体需要包装,往下传递,在ResponseBodyAdvice接口进行判断
                request.setAttribute(RESPONSE_RESULT_ANN, clazz.getAnnotation(ResponseResult.class));
            }
        }
        return true;
    }
}

请求全局解析ResponseResultHandler

package cn.soboys.core.ret;

import cn.soboys.core.utils.HttpContextUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import javax.servlet.http.HttpServletRequest;

/**
 * @author kenx
 * @version 1.0
 * @date 2021/6/17 16:47
 * 全局统一响应返回体处理
 */
@Slf4j
@ControllerAdvice
public class ResponseResultHandler implements ResponseBodyAdvice<Object> {

    public static final String RESPONSE_RESULT_ANN = "RESPONSE-RESULT-ANN";

    /**
     * @param methodParameter
     * @param aClass
     * @return 此处如果返回false , 则不执行当前Advice的业务
     * 是否请求包含了包装注解 标记,没有直接返回不需要重写返回体,
     */
    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        HttpServletRequest request = HttpContextUtil.getRequest();
        //判断请求是否有包装标志
        ResponseResult responseResultAnn = (ResponseResult) request.getAttribute(RESPONSE_RESULT_ANN);
        return responseResultAnn == null ? false : true;
    }

    /**
     * @param body
     * @param methodParameter
     * @param mediaType
     * @param aClass
     * @param serverHttpRequest
     * @param serverHttpResponse
     * @return 处理响应的具体业务方法
     */
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        if (body instanceof Result) {
            return body;
        } else if (body instanceof String) {
            return JSON.toJSONString(ResultResponse.success(body));
        } else {
            return ResultResponse.success(body);
        }
    }
}

具体详细内容请参考我这边文章 Spring Boot 无侵入式 实现RESTful API接口统一JSON格式返回

收藏
评论区

相关推荐

Swift与Objective-C混合编程之Swift与Objective-C API映射
原创文章,欢迎转载。转载请注明:关东升的博客 Swift与ObjectiveC API映射 在混合编程过程中Swift与ObjectiveC调用是双向的,由于不同语言对于相同API的表述是不同的,他们之间是有某种映射规律的,这种API映射规律主要体现在构造函数和方法两个方面。 1、构造函数映射 在Swift与ObjectiveC语言进行混合
js数组Api之reduce()方法的详解
reduce()的基础概念和用法在上一篇已经粗略讲过,本篇主要来讲一讲它的高级用法。reduce()能实现的功能,我们用常规的for()/forEach()也能搞定,但是相对来说reduce()算得上是捷径 我们先来用例子解析一下initialValue参数 var arr 1, 2, 3, 4; var sum arr.reduc
Vue3.0 高频出现的几道面试题
1. Vue 3.0 性能提升主要是通过哪几方面体现的? 1.响应式系统提升 vue2在初始化的时候,对data中的每个属性使用definepropery调用getter和setter使之变为响应式对象。如果属性值为对象,还会递归调用defineproperty使之变为响应式对象。 vue3使用proxy对象重写响应式。proxy的性能本来比def
Vue3.0 所采用的 Composition Api 与 Vue2.x 使用的 Options Api 有什么不同?
开始之前 Composition API 可以说是Vue3最大的特点,那么为什么要推出Composition Api,解决了什么问题? 通常使用Vue2开发
uni-app实战之社区交友APP(11)API环境搭建和登录API开发
牛年第一篇文章,金鼠辞旧岁、金牛报春时,我携全家以及秘书安南、保镖普京、管家布莱尔、司机布什、家奴小泉、水扁等向各位读者大佬朋友们致以节日的问候:祝新年快乐,玩得开心o( ̄▽ ̄)o 如需查看本项目实际运行效果,可点击uniapp实战之社区交友APP(1)项目介绍和环境搭建(https://blog.csdn.net/CUFEECR/article/d
笔趣阁小说api
笔趣阁api小说api,提供小说相关api接口,目前支持笔趣阁(https://m.bqkan.com/)。ip地址:http://49.234.123.245:8082 笔趣阁(https://m.bqkan.com/) 1. 首页 ip/getHome 2. 小说分类 ip/
Fabric1.4:Go 链码开发与编写
1 链码结构 1.1 链码接口 链码启动必须通过调用 shim 包中的 Start 函数,传递一个类型为 Chaincode 的参数,该参数是一个接口类型,有两个重要的函数 Init 与 Invoke 。 type Chainc
Hook API 索引 – React
Hook API 索引_Hook_ 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。本页面主要描述 React 中内置的 Hook API。如果你刚开始接触 Hook,那么可能需要先查阅 。你也可以在 章节中获取有用的信息。 基础 Hook
初识Windows API
Windows API是什么 Windows系统是一个很大的服务中心,调用这个服务中心的各种服务(每一种服务 ,就是一个函数)可以帮应用程序达到开启视窗、描绘图形、使用周边设备等,由于这些函数服务的对象是应用程序(Applicati
Fetch API 教程
Fetch API 教程作者: 日期: fetch()是 XMLHttpRequest 的升级版,用于在 JavaScript 脚本里面发出 HTTP 请求。浏览器原生提供这个对象。本文详细介绍它的用法。一、基本用法fetch()的功能与 XMLHttpRequest 基本相同,但有三个主要的差异。(1)fetc
Javascript本地存储 - 入门指南
在讲解之前,我们需要明白之间的差别server side storage,并client side storage当涉及到网站和应用程序。服务器端意味着我们使用数据库将数据存储在服务器上,客户端包含JavaScript API,这些API可让您在客户端(在浏览器中)存储数据。什么是本地存储? 简而言之,local storage可以将其与数据库进行比较,只
Vue3 - 响应性API
前言Vue3.x正式版发布已经快半年了,相信大家也多多少少也用Vue3.x开发过项目。那么,我们今天就整理下Vue3.x中的响应性API。响应性API reactive作用: 创建一个响应式数据。本质: 传入数据(复杂类型:数组和json对象)包装成一个Proxy对象。如果传入其他对象,默认情况下修改对象,界面不会自动更新,如果想更新,可以通过重新赋值(创建
cpu分析利器 — async-profiler
本文已收录 https://github.com/lkxiaolou/lkxiaolou 欢迎star。 简介asyncprofiler是一款采集分析java性能的工具,翻译一下github上的项目介绍:asyncprofiler是一款没有Safepoint bias problem的低开销java采集分析器,它利用HotSpot特殊的api来收集栈信息以及
Spring Boot 无侵入式 实现RESTful API接口统一JSON格式返回
前言现在我们做项目基本上中大型项目都是选择前后端分离,前后端分离已经成了一个趋势了,所以总这样·我们就要和前端约定统一的api 接口返回json 格式,这样我们需要封装一个统一通用全局 模版api返回格式,下次再写项目时候直接拿来用就可以了 约定JSON格式一般我们和前端约定json格式是这样的json "code": 200, "message
个人博客开发之blog-api项目统一结果集api封装
前言由于返回json api 格式接口,所以我们需要通过java bean封装一个统一数据返回格式,便于和前端约定交互, 状态码枚举ResultCodejavapackage cn.soboys.core.ret;import lombok.Getter;/ @author kenx @version 1.0 @date 2021/6/17 15:35