前言
1、@RestControllerAdvice或@ControllerAdvice注解可用于扩展Controller层次结构,若想返回json格式数据,直接使用@RestControllerAdvice注解就不需要额外添加@ResponseBody注解。官方API: 1.3.7. Controller Advice.
2、SpringMVC的ResponseBodyAdvice接口可实现自定义返回数据的功能。官方API: 1.1.6. Interception.
理论基础有了,现在我们将@RestControllerAdvice注解和ResponseBodyAdvice接口实现结合起来即可。以下仅为功能演示,可根据项目自身规范自定义。
1、编写接口返回包装类:
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Response<T> {
private int code;
private String msg;
private T data;
public static <T> Response<T> ok(T data) {
int okCode = 200;
return new Response<>(okCode, "请求成功", data);
}
}
Response类定义了接口数据返回格式,用到了一些lombok的注解简化代码,详见:https://projectlombok.org/
2、编写ResponseBodyAdvice接口实现:
import com.alibaba.fastjson.JSON;
import com.filter.Response;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
@RestControllerAdvice(basePackages = "com.controller")
public class ApiResponseBody implements ResponseBodyAdvice<Object> {
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
return true;
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType
, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
// 防止二次封装
if (body instanceof Response) {
return body;
}
// 处理controller返回为字符串时, 转换报异常的bug(默认使用的jackson转换器会报类型转换的错,感兴趣可以跟下源代码)
//(如果使用FastJsonHttpMessageConverter,则不需要加下面if判断)
if (body instanceof String) {
return JSON.toJSONString(Response.ok(body));
}
return Response.ok(body);
}
}
ApiResponseBody类实现ResponseBodyAdvice接口重写接口方法,beforeBodyWrite方法体中自定义接口返回格式和数据。@RestControllerAdvice注解的basePackages属性限制仅对指定"com.controller"包下控制器添加通知。
测试:
package com.controller;
@Slf4j
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping(path = "/responseTest")
public String responseTest(@RequestParam(required = false) String param) {
return param;
}
}
请求接口:
总结:如上操作就达到了我们的目的,实际场景比本篇博文举例复杂,但是我们只要知晓原理,扩展起来就很十分简单了;