preface
When the project runs with an exception, if the exception is not caught and handled, the following page appears:
This is obviously extremely user unfriendly.
The back end should not return an error page directly, but should return a uniform error message, such as:
{
"code": 500."data": null."message": "Service is abnormal. Please try again later."
}
Copy the code
The front end then displays a friendly prompt page based on the returned information.
Spring provides three ways to handle exceptions uniformly:
- @ExceptionHandler
- Implement the HandlerExceptionResolver interface
- @ControllerAdvice + @ExceptionHandler
So let’s actually do it.
The specific implementation
@ExceptionHandler
In this article, we define the base class BaseController for Controller, so as long as we use @ExceptionHandler in BaseController to handle exceptions, Other controllers inherit from BaseController. The implementation is as follows:
@Slf4j
public abstract class BaseController {
/** * BusinessException */
@ResponseBody
@ExceptionHandler(BusinessException.class)
public ApiResult businessExceptionHandler(BusinessException e) {
log.error(e.getMessage(), e);
// do something
return ApiResult.fail(e.getMessage());
}
/** * Exception */
@ResponseBody
@ExceptionHandler(Exception.class)
public ApiResult exceptionHandler(Exception e) {
log.error(e.getMessage(), e);
return ApiResult.fail("Service is abnormal. Please try again later."); }}Copy the code
BusinessException and Exception are handled here. BusinessException is the base class of the convention BusinessException. If the Exception is thrown actively, it is generally required to be a subclass of BusinessException. Will be handled by the Business CeptionHandler. Other exceptions, possibly unexpected exceptions, are handled by exceptionHandler.
After unified processing, the following result is displayed:
Implement the HandlerExceptionResolver interface
@Slf4j
@Component
public class GlobalHandlerExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object o, Exception e) {
log.error(e.getMessage(), e);
ApiResult apiResult;
if (e instanceof BusinessException) {
BusinessException be = (BusinessException) e;
// do something
apiResult = ApiResult.fail(be.getMessage());
} else {
apiResult = ApiResult.fail("Service is abnormal. Please try again later.");
}
WebUtils.writeJson(response, apiResult);
return null; }}Copy the code
This approach requires implementing the HandlerExceptionResolver interface and then injecting the implementation class into the Spring container.
But in the first way, with the @responseBody annotation, Spring returns json data for us, which we need to do ourselves.
The WebUtils utility class is implemented to return JSON data as follows:
public class WebUtils {
private static final Logger log = LoggerFactory.getLogger(WebUtils.class);
private static Gson gson = new GsonBuilder().serializeNulls().create();
/** * returns json data **@param response
* @param object
*/
public static void writeJson(HttpServletResponse response, int status, Object object) {
response.setHeader("Content-Type"."application/json; charset=UTF-8");
response.setContentType("application/json; charset=UTF-8");
response.setStatus(status);
PrintWriter out = null;
try {
String data = object instanceof String ? (String) object : gson.toJson(object);
out = response.getWriter();
out.print(data);
out.flush();
} catch (Exception e) {
log.error(e.getMessage(), e);
} finally {
if(out ! =null) { out.close(); }}}/** * returns json data **@param response
* @param object
*/
public static void writeJson(HttpServletResponse response, Object object) {
writeJson(response, HttpServletResponse.SC_OK, object);
}
/** * returns json data **@param response
* @param object
*/
public static void writeJson(ServletResponse response, Object object) {
if (response instanceofHttpServletResponse) { writeJson((HttpServletResponse) response, object); }}}Copy the code
Gson is used in the utility class and needs to be referenced:
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
Copy the code
@ControllerAdvice + @ExceptionHandler
This method is similar to the first method, as follows:
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {
/** * BusinessException */
@ResponseBody
@ExceptionHandler(BusinessException.class)
public ApiResult businessExceptionHandler(BusinessException e) {
log.error(e.getMessage(), e);
// do something
return ApiResult.fail(e.getMessage());
}
/** * Exception */
@ResponseBody
@ExceptionHandler(Exception.class)
public ApiResult exceptionHandler(Exception e) {
log.error(e.getMessage(), e);
return ApiResult.fail("Service is abnormal. Please try again later."); }}Copy the code
conclusion
All three methods work well for uniform exception handling, but the @Controlleradvice + @ExceptionHandler method is generally recommended to separate exception handling from business logic and to avoid handling Json data returns.
The source code
Github.com/zhuqianchan…
Review past
- Build backend frameworks from scratch – keep updating