SpringMvc统一返回值

Scroll Down

通知返回实体

import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.apache.http.HttpStatus;

import java.io.Serializable;

/**
 * @author 王守钰
 * @version 1.0
 * @program boqin
 * @date 2019年12月11日
 * @description: 返回值
 */
@Data
@ToString
@EqualsAndHashCode
public class R<T> implements Serializable {

    /**
     * 状态码
     */
    private Integer code;

    /**
     * 返回消息
     */
    private String msg;

    /**
     * 返回数据
     */
    private T data;

    public R(Integer code, String msg, T data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    public R(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public R(Integer code) {
        this.code = code;
    }

    /**
     * 操作成功
     * @return
     */
    public static R success(){
        return new R(HttpStatus.SC_OK);
    }

    /**
     * 操作成功
     * @param t
     * @param <T>
     * @return
     */
    public static <T> R success(T t){
        return new R(HttpStatus.SC_OK, null, t);
    }

    /**
     * 操作失败
     * @return
     */
    public static R fail() {
        return new R(HttpStatus.SC_INTERNAL_SERVER_ERROR);
    }

    /**
     * 失败
     * @param msg
     * @return
     */
    public static R fail(String msg){
        return new R(HttpStatus.SC_INTERNAL_SERVER_ERROR, msg);
    }
}

定义注解

import java.lang.annotation.*;

/**
 * @author 王守钰
 * @version 1.0
 * @program boqin
 * @date 2020年01月30日
 * @description: 返回R类型
 */
@Documented
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE, ElementType.METHOD})
public @interface ResponseR {

}

定义常量

主要为了在mvc请求时候判断这个请求的返回结果,设置Attribute使用

/**
 * @author 王守钰
 * @version 1.0
 * @program boqin
 * @date 2020年01月30日
 * @description: MVC返回值常量
 */
public class MvcConstant {

    /**
     * 返回R类型Attribute
     */
    public static final String RESPONSE_R_ANN = "RESPONSE-R-ANN";
}

Mvc拦截器设置

这里面可以自己根据头部,或者parameter参数,或者注解等方式来进行判断是否要统一包装成想要的结果集。

import com.google.common.base.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
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 王守钰
 * @version 1.0
 * @program boqin
 * @date 2020年01月30日
 * @description: 返回R类型拦截器
 */
@Component
public class ResponseResultInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if(handler instanceof HandlerMethod){

            // 参数匹配
            String parameter = request.getParameter("Result-Format");
            if(!Strings.isNullOrEmpty(parameter) && parameter.equalsIgnoreCase("R")){
                request.setAttribute(MvcConstant.RESPONSE_R_ANN,ResponseR.class);
                return true;
            }

            // 注解匹配
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Class<?> clazz = handlerMethod.getBeanType();
            Method method = handlerMethod.getMethod();
            // 判断类上是否有ResponseR注解
            if(clazz.isAnnotationPresent(ResponseR.class) || method.isAnnotationPresent(ResponseR.class)){
                request.setAttribute(MvcConstant.RESPONSE_R_ANN,ResponseR.class);
            }
        }
        return true;
    }
}

ResponseBodyAdvice处理器

这里面做了个R类型的返回值的判断,如果原返回值已经被R包装了,就不需要再进行包装了。

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.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import javax.servlet.http.HttpServletRequest;

/**
 * @author 王守钰
 * @version 1.0
 * @program boqin
 * @date 2020年01月30日
 * @description: 返回R类型处理器
 */
@ControllerAdvice
public class ResponseResultHandler implements ResponseBodyAdvice<Object> {
    
    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        return request.getAttribute(MvcConstant.RESPONSE_R_ANN) != null ;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        if(body instanceof R){
            return body;
        }
        return R.success(body);
    }
}

Mvc拦截器激活

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

/**
 * @author 王守钰
 * @version 1.0
 * @program boqin
 * @date 2020年01月30日
 * @description: mvc配置
 */
@Configuration
public class MvcConfig extends WebMvcConfigurationSupport {
    @Autowired
    private ResponseResultInterceptor responseResultInterceptor;

    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(responseResultInterceptor).addPathPatterns("/**");
        super.addInterceptors(registry);
    }
}