Unified Return Value
Today, with the separation of front-end and back-end, a unified return value format can not only make our interface look more beautiful, but also enable the front-end to handle a lot of things in a unified way, avoiding many problems.
The more general return value format is as follows:
public class Result<T> { // Interface call success or failure private Integer code = 0; // Specific code for failure private String errorCode = ""; // Information to be transmitted, such as error messages private String msg; // Data to be transferred private T data; ... }
The original interface is as follows:
@GetMapping("/test") public User test() { return new User(); }
When we need to unify the return values, we may use such a method:
@GetMapping("/test") public Result test() { return Result.success(new User()); }
This method does achieve the goal of unified interface return value, but several new problems arise:
- The return value of the interface is not obvious, and the return value of the interface can not be seen at a glance.
- Each interface requires additional code.
Fortunately, Spring Boot has provided us with a better solution. Just add the following code to the project to unify the global return value for us senselessly.
/** * Unified Encapsulation of Global Return Values */ @EnableWebMvc @Configuration public class GlobalReturnConfig { @RestControllerAdvice static class ResultResponseAdvice implements ResponseBodyAdvice<Object> { @Override public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) { return true; } @Override public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) { if (body instanceof Result) { return body; } return new Result(body); } } }
Our interface only needs to be written in the most primitive form.
@GetMapping("/test") public User test() { return new User(); }
Unified exception handling
When encapsulating return values uniformly, we do not consider the case when the interface throws an exception. When an exception is thrown by an interface, it must be unfriendly for the user to see the exception on the server directly, and it is impossible for us to try/catch every interface for processing. At this time, we only need to use the @ExceptionHandler annotation to deal with the exception universally and senselessly.
@RestControllerAdvice public class GlobalExceptionHandler { private static final Logger LOG = LoggerFactory.getLogger(GlobalExceptionHandler.class); /** * Global exception handling */ @ExceptionHandler public JsonData handleException(HttpServletRequest request, HttpServletResponse response, final Exception e) { LOG.error(e.getMessage(), e); if (e instanceof AlertException) {//Anomalies that can be found at the front end of Alert if (((AlertException) e).getRetCode() != null) {//Predefined anomaly return new Result(((AlertException) e).getRetCode()); } else { return new Result(1, e.getMessage() != null ? e.getMessage() : ""); } } else {//Other anomalies if (Util.isProduct()) {//If it's a formal environment, uniform tips return new Result(RetCode.ERROR); } else {//Test environment, alert exception information return new Result(1, StringUtils.isNotBlank(e.getMessage()) ? e.getMessage() : e.toString()); } } } }
AlertException is our custom exception, so when errors need to be thrown in the business, you can manually throw AlertException.
These are the two steps of unified processing of return values and exception.