包装正常返回结果
Spring 提供了 ResponseBodyAdvice interface, 处理ResonseEntity 返回值,这个接口实现了两个方法,可以实现返回结果的自定义处理
@ControllerAdvice(annotations = {RestController.class})
public class ApiResponseAdvice implements ResponseBodyAdvice {
@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 (selectedContentType.includes(MediaType.APPLICATION_JSON) ||
selectedContentType.includes(MediaType.APPLICATION_JSON_UTF8)) {
if (!response.getHeaders().containsKey(SDKConstant.NOT_TRANSFORM_BODY)) { //有些错误已经格式化为指定的返回类型
Map<String, Object> map = new HashMap<>();
map.put("errorCode", 200);
map.put("message", "success");
map.put("data", body);
return map;
} else {
return body;
}
}
return body;
}
}
-
@ControllerAdvice 这个Annotation 是指定要处理的Controller, 这个处理所有带 @RestController 的Controller.
-
supports(...) 方法,可以指定需要处理的方法
-
beforeBodyWrite(...) 方法,进一步过滤处理最后的结果
Controller 异常处理
@ControllerAdvice(annotations = {RestController.class})
public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler{
@ExceptionHandler(value = ScBaseException.class)
public void exceptionHandle(...){
// 这里你可以返回新的body
}
}
-
@ExceptionHandle 这个新增的注解就是用来处理最后抛到Controller的异常,这个也是自定义可以控制的地方非常多,比如我们自定的异常
-
但是这个好像捕获不了参数校验等异常,所以再加上第三步
Validator 异常 和 参数错误等校验异常处理
在RestController 中, Validator 异常 和 参数错误等校验异常处理,会重定向至 /error 的请求,所以我们会在这里做处理
Validator 异常
@RequestMapping(value = "/search/code", method = RequestMethod.GET)
public ResponseEntity<Object> getCompanyCodeSearchResult(@Valid CompanyCodeReq companyCodeReq,
BindingResult result, HttpServletResponse response) {
// 处理 Validator 出错的情况
if(result.hasErrors()){
Map<String, Object> errorMap = ResponseUtil.buildFieldBindErrorMap(result.getFieldError().getDefaultMessage());
response.addHeader(SDKConstant.NOT_TRANSFORM_BODY, HttpStatus.BAD_REQUEST.toString());
return ResponseEntity.badRequest().body(errorMap);
}
CompanyCodeResp searchResult = companyApiService.getCodeSearchResult();
return new ResponseEntity<>(searchResult, HttpStatus.OK);
}
- 在Controller 中获取 BindingResult 的结果,并在其中获取出错的消息,返回异常的结果
- ResponseEntity.badRequest().body(errorMap) ,这个方法就可以放回指定的结果了,这里设置了 header,用于上面的 ControllerAdvice 做过滤使用。
参数错误等校验异常处理
@RequestMapping(path = "/error", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
public Map<String, Object> handle(HttpServletRequest request) {
Map<String, Object> map = new HashMap<>();
map.put("errorCode",request.getAttribute("javax.servlet.error.status_code"));
if (StringUtils.isNoneBlank(request.getAttribute("javax.servlet.error.message").toString())) {
map.put("message", request.getAttribute("javax.servlet.error.message"));
} else {
map.put("message", "请求参数或方法错误");
}
map.put("data", null);
return map;
}
这个就相当于 做 Spring MVC 的时候,View 的功能
<error-page>
<location>/error</location>
</error-page>