@ControllerAdvice
是Spring 框架中的注解,多用在Spring MVC应用程序中。
# 示例1
import org.apache.ibatis.javassist.NotFoundException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
@ResponseBody
public ResponseEntity<String> handleException(Exception ex) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("An error occurred");
}
@ExceptionHandler(NotFoundException.class)
public ResponseEntity<String> handleNotFoundException(NotFoundException ex) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Resource not found");
}
}
通过实现接口ResponseBodyAdvice
来修改返回值,并直接作为 ResponseBody 类型处理器 的返回值。
# 示例2
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 java.util.Map;
@ControllerAdvice
public class HelloResponseBodyAdvice implements ResponseBodyAdvice<Map<String, Object>> {
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return true;
}
@Override
public Map<String, Object> beforeBodyWrite(Map<String, Object> body, MethodParameter returnType, MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType,
ServerHttpRequest request, ServerHttpResponse response) {
// 修改返回值
System.out.println("origin map: " + body);
body.put("msg", "hello");
return body;
}
}
# 示例3
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
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 static java.util.Objects.nonNull;
@ControllerAdvice
public class HttpResponseBodyAdvice implements ResponseBodyAdvice {
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
return true;
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class clazz,
ServerHttpRequest request, ServerHttpResponse response) {
HttpHeaders headers = response.getHeaders();
// 分页信息添加到ServerHttpResponse
HttpHeaders headersContext = ResponseUtils.getHeaders();
if (nonNull(headersContext) && !headersContext.isEmpty()) {
headers.addAll(headersContext);
}
// 状态码添加到ServerHttpResponse
if (nonNull(ResponseUtils.getResponseCode())) {
response.setStatusCode(ResponseUtils.getResponseCode());
}
return body;
}
}
HelloResponseBodyAdvice
时@RestController
@RequestMapping("/test")
public class ResponseBodyAdviceController {
@RequestMapping(value = "/hello", method = RequestMethod.GET)
public Map<String, Object> hello() {
Map<String, Object> map = new HashMap<>();
map.put("a", 1);
map.put("b", 2);
return map;
}
}
结论: 返回值被 成功修改
结论:则均执行,且按照类名字母降序的顺序执行。比如
HelloResponseBodyAdvice
比 PracResponseBodyAdvice
先执行,
APracResponseBodyAdvice
比 HelloResponseBodyAdvice
先执行。
@RestController
@RequestMapping("/test")
public class ResponseBodyAdviceController {
@RequestMapping(value = "/hello", method = RequestMethod.GET)
public Map<String, Object> hello() {
int a = 0;
int b = 5;
int i = b / a;
return null;
}
}
结论:执行顺序为:GlobalExceptionHandler
→ HelloResponseBodyAdvice
→ HttpResponseBodyAdvice
结论:异常也可被修改值,所以这个修改值的操作,慎用!!! 一般微服务只有 2 个 @ControllerAdvice
,一个用作修改 HttpHeader 和 HttpStatus (示例3
),一个用作处理异常(示例1
)。
@RestController
VS @Controller
@Controller
@Slf4j
public class SearchController {
@Autowired
UserService userService;
@RequestMapping(value = "/getAllStudents", method = RequestMethod.GET)
public List<Student> login() {
List<Student> students = userService.listStudents(1, 10);
students.forEach(System.out::println);
return students;
}
}
结论:@RestController
会成功返回结果, @Controller
不会返回结果