在Spring微服务的开发项目过程中,经常会对返回的结果进行统一包装,需要在每个接口后都需要申明一个包装的返回类型,然后在很多时候,大家都不会按照规范进行操作,或者有时候会忘记,直接返回的对象。可以利用ResponseBodyAdvice
对返回的结果,进行统一的包装。
ScioResponseBodyAdvice
package com.scio.core.config.web;
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 com.scio.core.config.web.WebMvcConfig.StringOrMappingJackson2HttpMessageConverter;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@ControllerAdvice
public class ScioResponseBodyAdvice implements ResponseBodyAdvice<Object> {
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return !returnType.getMethod().getReturnType().isAssignableFrom(Void.TYPE)
&& converterType.isAssignableFrom(StringOrMappingJackson2HttpMessageConverter.class);
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
ServerHttpResponse response) {
if (log.isDebugEnabled()) {
log.debug("advice by ScioResponseBodyAdvice");
}
return Resp.success(body);
}
}
WebMvcConfig
package com.scio.core.config.web;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.List;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
@Override
protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
return new ApiVersionHandlerMapping();
}
// 这里需要注意,因为默认的convert是String,如果方法返回的是String,那么将会被提前返回,所以需要做一下兼容。
@Override
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(0, new StringOrMappingJackson2HttpMessageConverter());
super.extendMessageConverters(converters);
}
/**
* 兼容String和对象类型
*
* @author Wang.ch
* @date 2019/12/12
*/
public static class StringOrMappingJackson2HttpMessageConverter extends MappingJackson2HttpMessageConverter {
private static final StringHttpMessageConverter shmc = new StringHttpMessageConverter();
@Override
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
boolean canWrite = super.canWrite(clazz, mediaType);
if (!canWrite) {
canWrite = clazz.isAssignableFrom(String.class);
}
return canWrite;
}
@Override
protected void writeInternal(Object object, Type type, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
if (object != null && object instanceof String) {
outputMessage.getHeaders().setContentType(MediaType.TEXT_PLAIN);;
shmc.write((String)object, MediaType.TEXT_PLAIN, outputMessage);
return;
}
outputMessage.getHeaders().setContentType(MediaType.APPLICATION_JSON_UTF8);
super.writeInternal(object, object != null ? object.getClass() : null, outputMessage);
}
}
}
TestController
package com.scio.core.config.web;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@RequestMapping("/test")
@ApiVersion("1.0")
public void test() {
System.out.println("test");
}
@RequestMapping("/test")
@ApiVersion("2.0")
public String test2() {
return "你好";
}
@RequestMapping("/test")
@ApiVersion("3.0")
public Integer test3() {
return 1111;
}
@RequestMapping("/test")
@ApiVersion("4.0")
public Resp<String> test4() {
return Resp.badrequest("test");
}
}