自定义注解实现返回API统一格式数据


通过添加在WEB层的自定义注解来判断是否对接口返回格式数据进行处理

1.新建注解

package com.api.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ResponseResult {

}

2.新建拦截器,并配置拦截器

拦截器用来拦截请求,并根据该URI是否添加@ResponseResult来设置该RUI是否需要对返回数据进行封装

package com.api.interceptor;

import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import com.api.annotation.ResponseResult;
import com.api.cache.ResponseURICache;

@Component
public class ResponsResultInterceptor implements HandlerInterceptor {

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		//请求的方法
		if(handler instanceof HandlerMethod){
			HandlerMethod handlerMethod = (HandlerMethod) handler;
			Class<?> clazz = handlerMethod.getBeanType();
			Method method = handlerMethod.getMethod();
			String rui = request.getRequestURI();
			if(null == ResponseURICache.getInstance().get(rui)) {
				if(clazz.isAnnotationPresent(ResponseResult.class)){
					ResponseURICache.getInstance().set(rui, true);
				}else if(method.isAnnotationPresent(ResponseResult.class)){
					ResponseURICache.getInstance().set(rui, true);
				}else{
					ResponseURICache.getInstance().set(rui, false);
				}
			}
		}
		return true;
	}
	
	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception)
			throws Exception {
		// TODO Auto-generated method stub

	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView view)
			throws Exception {
		// TODO Auto-generated method stub

	}

}

配置拦截器

package com.api.config;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.validation.MessageCodesResolver;
import org.springframework.validation.Validator;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import com.api.interceptor.ResponsResultInterceptor;

@Configuration
public class WebConfigurer implements WebMvcConfigurer {
	
	@Autowired
	private ResponsResultInterceptor responsResultInterceptor;

	@Override
	public void addInterceptors(InterceptorRegistry interceptorRegistry) {
		// addPathPatterns("/**") 表示拦截所有的请求,
        // excludePathPatterns("/login", "/register") 表示除了登陆与注册之外,因为登陆注册不需要登陆也可以访问
		interceptorRegistry.addInterceptor(responsResultInterceptor).addPathPatterns("/**");
	}

	@Override
	public void addResourceHandlers(ResourceHandlerRegistry resourceHandlerRegistry) {
		// TODO Auto-generated method stub

	}

	@Override
	public void addArgumentResolvers(List<HandlerMethodArgumentResolver> arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void addCorsMappings(CorsRegistry arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void addFormatters(FormatterRegistry arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void addViewControllers(ViewControllerRegistry arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void configureAsyncSupport(AsyncSupportConfigurer arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void configureContentNegotiation(ContentNegotiationConfigurer arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void configureDefaultServletHandling(DefaultServletHandlerConfigurer arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void configureMessageConverters(List<HttpMessageConverter<?>> arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void configurePathMatch(PathMatchConfigurer arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void configureViewResolvers(ViewResolverRegistry arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void extendMessageConverters(List<HttpMessageConverter<?>> arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public MessageCodesResolver getMessageCodesResolver() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Validator getValidator() {
		// TODO Auto-generated method stub
		return null;
	}

}

3.新建返回枚举类,返回格式封装类,错误返回格式类

3.1 格式定义

package com.api.result;

public enum ResultCode {
	//成功
	SUCCESS(1,"成功"),
	//参数错误100-199
	PARAM_IS_INVALID(101,"参数无效"),
	PARAM_IS_BLANK(102,"参数为空"),
	PARAM_TYPE_BIND_ERROR(103,"参数类型错误"),
	PARAM_NOT_COMPLETE(104,"参数缺失"),
	//用户错误200-299
	USER_NOT_LOGGED_IN(201,"用户未登录,访问的路径需要验证,请登录"),
	USER_LOGIN_ERROR(202,"账号不存在或密码错误"),
	USER_ACCOUNT_FORBIDDEN(203,"账号已被禁用"),
	USER_NOT_EXIST(204,"用户不存在"),
	USER_HAS_EXISTED(205,"用户已存在");
	
	private Integer code;
	
	private String message;
	
	ResultCode(Integer code, String message) {
		this.code = code;
		this.message = message;
	}
	
	public Integer code() {
		return this.code;
	}

	public String message() {
		return this.message;
	}
	
}

3.2 统一返回格式

package com.api.result;

import java.io.Serializable;

public class Result implements Serializable {
	
	private static final long serialVersionUID = 1L;

	private Integer code;
	
	private String message;

	private Object data;

	public Result() {
	}

	public Result(ResultCode resultCode, Object data) {
		this.code = resultCode.code();
		this.message = resultCode.message();
		this.data = data;
	}
	
	public static Result success(){
		Result result = new Result();
		result.setResultCode(ResultCode.SUCCESS);
		return result;
	}
	
	private void setResultCode(ResultCode resultCode) {
		this.code = resultCode.code();
		this.message = resultCode.message();
	}

	public static Result success(Object data){
		Result result = new Result();
		result.setResultCode(ResultCode.SUCCESS);
		result.setData(data);
		return result;
	}
	
	public static Result failure(ResultCode resultCode){
		Result result = new Result();
		result.setResultCode(resultCode);
		return result;
	}
	
	public static Result failure(ResultCode resultCode, Object data){
		Result result = new Result();
		result.setResultCode(resultCode);
		result.setData(data);
		return result;
	}
	
	public static Result failure(Integer code, String message, Object errors) {
		Result result = new Result();
		result.setCode(code);
		result.setMessage(message);
		result.setData(errors);
		return result;
	}

	public Integer getCode() {
		return code;
	}

	public void setCode(Integer code) {
		this.code = code;
	}

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}

	public Object getData() {
		return data;
	}

	public void setData(Object data) {
		this.data = data;
	}

}

3.3 异常返回格式

package com.api.result;

public class ErrorResult {
	
	private Integer code;
	
	private String message;
	
	private Object errors;

	public Integer getCode() {
		return code;
	}

	public void setCode(Integer code) {
		this.code = code;
	}

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}

	public Object getErrors() {
		return errors;
	}

	public void setErrors(Object errors) {
		this.errors = errors;
	}

}

3.4 新建ResponseResultHandle 类实现ResponseBodyAdvice接口,用于实现自定义返回类型,全局异常处理

package com.api.handler;

import javax.servlet.http.HttpServletRequest;

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.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 com.api.cache.ResponseURICache;
import com.api.result.ErrorResult;
import com.api.result.Result;

@ControllerAdvice
public class ResponseResultHandle implements ResponseBodyAdvice<Object> {

	//是否请求包含了包装注解标记,没有就直接返回,不需要重写返回体
	@Override
	public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
		ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
		HttpServletRequest request = sra.getRequest();
		//判断请求是否有包装标记
		return ResponseURICache.getInstance().get(request.getRequestURI());
	}
	
	@Override
	public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
			Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
		//进入返回体重写格式
		if(body instanceof ErrorResult){
			//返回值异常,作包装处理
			ErrorResult errorResult = (ErrorResult) body;
			return Result.failure(errorResult.getCode(), errorResult.getMessage(), errorResult.getErrors());
		}
		return Result.success(body);
	}
	
	@ExceptionHandler(Exception.class)
	@ResponseBody
	public ErrorResult handleRuntimeException(Exception e){
		ErrorResult errorResult = new ErrorResult();
		errorResult.setCode(500);
		errorResult.setMessage("服务器异常");
		errorResult.setErrors(errorResult.getErrors());
		return errorResult;
	}

}

4.新建缓存类

可以根据具体需求使用缓存数据库代替缓存类,这里使用一个用hashMap实现缓存类

package com.api.cache;

import java.util.HashMap;
import java.util.Map;

public class ResponseURICache {
	
	//缓存map
    private Map<String, Boolean> cacheMap = new HashMap<String, Boolean>();
    
    //禁止指令重排优化
  	private static volatile ResponseURICache URICACHE;
  	
  	private ResponseURICache(){}

  	public static ResponseURICache getInstance(){
  		if(null == URICACHE){
  			synchronized(ResponseURICache.class){
  				if(null == URICACHE){
  					URICACHE = new ResponseURICache();
  				}
  			}
  		}
  		return URICACHE;
  	}

    /**
     *  设置缓存值
     * @param key
     * @param value
     */
    public void set(String key, Boolean value) {
        cacheMap.put(key, value);
    }

    /**
     *  获取缓存key的value值
     * @param key
     * @return
     */
    public Boolean get(String key) {
        if (!cacheMap.containsKey(key)) {
            return null;
        }
        return cacheMap.get(key);
    }
}

5.Web控制层添加注解

package com.api.controll;

import java.util.HashMap;
import java.util.Map;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import com.api.annotation.ResponseResult;

@RestController
@ResponseBody
public class BookControll {
	
	@GetMapping("book")
	@ResponseResult
	public Object getBook(){
		Map<String, String> map = new HashMap<String, String>();
		map.put("title", "倾城之恋");
		map.put("author", "张爱玲");
		return map;
	}

	@GetMapping("/book/name")
	public Object getBookById(){
		Map<String, String> map = new HashMap<String, String>();
		map.put("title", "金锁记");
		map.put("author", "张爱玲");
		return map;
	}
	
}
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值