@ControllerAdvice 使用场景

@ControllerAdvice 是Spring 框架中的注解,多用在Spring MVC应用程序中。

使用场景1:处理异常

# 示例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");
    }
}

在这里插入图片描述

使用场景2:修改返回值

通过实现接口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;
    }
}

验证

CASE1:只有1个 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;
    }
}

@ControllerAdvice 使用场景_第1张图片

结论: 返回值被 成功修改

CASE2:有2个 ResponseBodyAdvice 时

结论:则均执行,且按照类名字母降序的顺序执行。比如
HelloResponseBodyAdvicePracResponseBodyAdvice 先执行,
APracResponseBodyAdviceHelloResponseBodyAdvice 先执行。

CASE3:发生异常时

@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;
    }
}

@ControllerAdvice 使用场景_第2张图片
结论:执行顺序为:GlobalExceptionHandlerHelloResponseBodyAdviceHttpResponseBodyAdvice
结论:异常也可被修改值,所以这个修改值的操作,慎用!!! 一般微服务只有 2 个 @ControllerAdvice ,一个用作修改 HttpHeader 和 HttpStatus (示例3),一个用作处理异常(示例1)。

CASE4:@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不会返回结果

你可能感兴趣的:(SpringBoot,java)