8.SpringBoot AOP方式统一数据格式返回

image.png

使用 Java Bean 来体现统一返回数据这个结构,可以解决接口返回格式一致性,但也有几个新问题诞生了:

  • 接口返回值不明显,不能一眼看出来该接口的返回值
  • 每一个接口都需要增加额外的代码量
  • 不利于swagger对接口的返回类型的支持

所幸Spring Boot已经为我们提供了更好的解决办法,只需要在项目中加上以下代码,就可以无感知的为我们统一全局返回值。


import java.lang.reflect.Executable;
import java.util.Collection;
import java.util.LinkedHashMap;

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.ResponseBody;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;

@ControllerAdvice
public class ApiResponseBody implements ResponseBodyAdvice<Object> {

	@Override
	@SuppressWarnings("rawtypes")
	public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
		
		boolean hasMethodAnnotation = methodParameter.hasMethodAnnotation(ResponseBody.class);
		if(!hasMethodAnnotation) {
			Executable executable = methodParameter.getExecutable();
			Object clazz = ReflectUtil.getFieldValue(executable, "clazz");
			Object annotationData = ReflectUtil.getFieldValue(clazz, "annotationData");
			Object annotations = ReflectUtil.getFieldValue(annotationData, "annotations");
			if(ObjectUtil.isNotNull(annotations)) {
				LinkedHashMap map = (LinkedHashMap)annotations;
				Collection values = map.values();
				if(ObjectUtil.isNotNull(values)) {
					for (Object object : values) {
						if(StrUtil.containsAny(object.toString(), "RestController")) {
							return true;
						}
					}
				}
			}
		}
		return hasMethodAnnotation;
	}

	@Override
	public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType,
			Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest,
			ServerHttpResponse serverHttpResponse) {
		if(o instanceof ApiResponses) {
			return o;
		}
		return ApiResponses.success(o);
	}
}
复制代码

此时请求 hello接口,会报ApiResponses不能转为string的异常

{
  "timestamp": "2019-12-09T12:22:53.776+0000",
  "status": 500,
  "error": "Internal Server Error",
  "message": "com.gitee.web.api.ApiResponses cannot be cast to java.lang.String",
  "path": "/users"
}
java.lang.ClassCastException: com.gitee.web.api.ApiResponses cannot be cast to java.lang.String
	at org.springframework.http.converter.StringHttpMessageConverter.getContentLength(StringHttpMessageConverter.java:44) ~[spring-web-5.2.1.RELEASE.jar:5.2.1.RELEASE]
	at org.springframework.http.converter.AbstractHttpMessageConverter.addDefaultHeaders(AbstractHttpMessageConverter.java:260) ~[spring-web-5.2.1.RELEASE.jar:5.2.1.RELEASE]
	at org.springframework.http.converter.AbstractHttpMessageConverter.write(AbstractHttpMessageConverter.java:211) 
复制代码

解决

package com.gitee.config;

import java.util.List;

import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class MyConfig implements WebMvcConfigurer{

	@Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.set(0, new MappingJackson2HttpMessageConverter());
    }
}
复制代码

重写WebMvcConfigurerAdapter,覆盖了原有的HttpMessageConverters,此处采用:Jackson

epom-web工程pom添加jackson依赖

<dependency>
	<groupId>com.fasterxml.jackson.core</groupId>
	<artifactId>jackson-databind</artifactId>
</dependency>

<dependency>
	<groupId>com.fasterxml.jackson.datatype</groupId>
	<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
复制代码

效果

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享