版本
Spring-boot:2.3.1
方案
使用攔截器
常量類
定義一個統一的辨別
public class Constant {
public static final String RESPONSE_RESULT_ANNOTATION = "RESPONSE_RESULT_ANNOTATION";
}
傳回體
import org.springframework.http.HttpStatus;
import java.io.Serializable;
/**
* 接口傳回對象
*/
public class Result<T> implements Serializable {
private static final long serialVersionUID = 1L;
private static Result<Object> result = new Result<>();
/**
* 失敗消息
*/
private String message;
/**
* 傳回代碼
*/
private Integer code;
/**
* 時間戳
*/
private long timestamp = System.currentTimeMillis();
/**
* 結果對象
*/
private T data;
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
private Result() {}
public static Result success() {
Result result = new Result();
result.setCode(HttpStatus.OK.value());
return result;
}
public static Result<Object> success(Object data) {
result.setCode(HttpStatus.OK.value());
result.setData(data);
return result;
}
public static Result<Object> success(Object data, String message) {
result.setCode(HttpStatus.OK.value());
result.setData(data);
result.setMessage(message);
return result;
}
public static Result<Object> failure(String message) {
result.setCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
result.setMessage(message);
return result;
}
public static Result<Object> failure(Integer code, String message) {
result.setCode(code);
result.setMessage(message);
return result;
}
}
注解類
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
public @interface ResponseResult {
}
Retention指明可以通過反射讀取
Target指明注解類可以注解到類,接口,枚舉,方法
controller統一注解封裝(可有可無)
import com.maintenance.response.ResponseResult;
import org.springframework.web.bind.annotation.RestController;
import java.lang.annotation.*;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@RestController
@ResponseResult
public @interface BaseControllerAnnotation {
}
此注解的作用就是在Controller中隻需要寫BaseControllerAnnotation就行了,不需要在寫@RestController和@ResponseResult,是以隻是用來簡化代碼的
配置類
import com.maintenance.response.ResponseResultInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebAppConfig implements WebMvcConfigurer {
/**
* 添加攔截器規則
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry){
registry.addInterceptor(new ResponseResultInterceptor()).addPathPatterns("/**");
}
}
Configuration注解指明配置類,springboot自動掃描
addInterceptors中添加攔截器,可以添加多個,這裡我們攔截了所有的請求
攔截器
import com.maintenance.pojo.BaseControllerAnnotation;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
public class ResponseResultInterceptor implements HandlerInterceptor {
@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();
/* 校驗類的注解和方法的注解,滿足條件後,添加到attribute */
if(clazz.isAnnotationPresent(ResponseResult.class)) {
request.setAttribute(Constant.RESPONSE_RESULT_ANNOTATION, clazz.getAnnotation(ResponseResult.class));
} else if(method.isAnnotationPresent(ResponseResult.class)) {
request.setAttribute(Constant.RESPONSE_RESULT_ANNOTATION, method.getAnnotation(ResponseResult.class));
} else if(clazz.isAnnotationPresent(BaseControllerAnnotation.class)) {
request.setAttribute(Constant.RESPONSE_RESULT_ANNOTATION, clazz.getAnnotation(BaseControllerAnnotation.class));
}
}
return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}
增強器(處理傳回)
import com.maintenance.excepion.RoleManagerException;
import com.maintenance.pojo.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpStatus;
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.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
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;
@ControllerAdvice
public class ResponseResultHandler implements ResponseBodyAdvice<Object> {
private Logger logger = LoggerFactory.getLogger(ResponseResultHandler.class);
/**
* 判斷元件支援的類型
* @param returnType
* @param converterType
* @return
*/
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = servletRequestAttributes.getRequest();
/* 判斷是否需要統一包裝,如果attribute中有,則表示需要處理,傳回true */
Object annotation = request.getAttribute(Constant.RESPONSE_RESULT_ANNOTATION);
return !(annotation == null);
}
/**
* 處理傳回體
* @param body
* @param returnType
* @param selectedContentType
* @param selectedConverterType
* @param request
* @param response
* @return
*/
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
if(!(body instanceof Result)) {
// 包裝傳回體
return Result.success(body);
}
return body;
}
/**
* 自定義異常
* @param e
* @return
*/
@ExceptionHandler(RoleManagerException.class)
@ResponseBody
public Result<?> exceptionHandler(RoleManagerException e) {
logger.error(e.getMessage(), e);
return Result.failure(e.getMessage());
}
/**
* 系統異常
* @param e
* @return
*/
@ExceptionHandler(Exception.class)
@ResponseBody
public Result<?> exceptionHandler(Exception e) {
logger.error(e.getMessage(), e);
return Result.failure(HttpStatus.INTERNAL_SERVER_ERROR.value(), "系統異常,請聯系管理者");
}
}
使用方法
在controller類上使用@ResponseResult或@BaseControllerAnnotation
在controller方法上使用@ResponseResult