background

Exceptions are a part of software development, and in my case, I spend at least half of my time handling exceptions, so there are a lot of try {… } catch {… } finally {… } code blocks, not only have a lot of redundant code, but also affect the readability of the code. Compare the two figures below to see which style of code you are writing now? Then which coding style do you prefer?

Ugly try catch block

The elegance of the Controller

The example above, which is still at the Controller layer, might have more try catch blocks if it were at the Service layer. This can seriously affect the readability and “aesthetics” of your code.

So if it were me, I would definitely prefer the second option, where I can focus more on business code development and the code will be more concise.

Since the business code does not explicitly catch and handle exceptions, and exceptions certainly do, the system will crash all the time, so they must be caught and handled somewhere else. The public account (Java backend) has also published a lot of programming tips, pay attention to “Java backend” reply 666 download.

So the question is, how do you handle exceptions gracefully?

What is unified exception handling

In version 3.2, Spring added an annotation @ControllerAdvice, which can be used with @ExceptionHandler, @initBinder, @ModelAttribute and other annotations. If you don’t know, please refer to the new annotation @controlleradvice in Spring3.2 for a general idea.

ExceptionHandler, which literally means ExceptionHandler, does what it does: If you define an exception handling method on a Controller class and add the annotation to the method, the exception handling method will be executed when the specified exception occurs, using data binding provided by SpringMVC, such as injecting HttpServletRequest, etc. You can also accept a Throwable object that is currently thrown.

However, you would have to define a set of such exception handling methods in each Controller class, because exceptions can be different. This would result in a lot of redundant code, and if you needed to add a new exception handling logic, you would have to change all the Controller classes, which would be inelegant.

Of course, you might say, well, let’s just define a base class like BaseController, and that’s it.

This is true, but it’s not perfect, because such code is intrusive and coupled. A simple Controller, why would I want to inherit such a class, if I already inherit from another base class? Everyone knows that Java can only inherit one class.

Is there a way to apply defined exception handlers to all controllers without coupling them to controllers? So here comes the @ControllerAdvice annotation, which, in short, applies exception handlers to all controllers, not just a single controller. With this annotation, we can define a mechanism for handling different exceptions in a separate place, such as a single class, and then annotate the class’s signature with @ControllerAdvice to handle different exceptions at different stages. This is how unified exception handling works.

Notice that the above exceptions are classified by stage, which can be roughly divided into: exceptions before entering Controller and exceptions at Service layer. For details, please refer to the following figure:


Anomalies at different stages


The target

Eliminate 95% or more try catch blocks, validate business exceptions in an elegant Assert style, focus on business logic, and don’t spend a lot of effort writing redundant try Catch blocks.

Unified exception handling practice

Before defining a unified exception handling class, let’s look at how to gracefully determine an exception and throw it.

Replace throw Exception with Assert

Must Assert (claim) are familiar, such as Spring family org. Springframework. Util. Assert, when we write test cases are often used, use assertions can let’s code is a kind of general silky feeling, such as:

@Test
    public void test1(a) {... User user = userDao.selectById(userId); Assert.notNull(user,"The user does not exist."); . }@Test
    public void test2(a) {
        // Another way to write it
        User user = userDao.selectById(userId);
        if (user == null) {
            throw new IllegalArgumentException("The user does not exist."); }}Copy the code

Do you feel that the first non-empty rule is elegant, and the second rule is relatively ugly if {… } code block. So what’s behind the magical assert.notnull ()? Here’s some of the Assert source code:

public abstract class Assert {
    public Assert(a) {}public static void notNull(@Nullable Object object, String message) {
        if (object == null) {
            throw newIllegalArgumentException(message); }}}Copy the code

As you can see, Assert is basically a way of putting an if {… } encapsulate, isn’t it amazing? Simple as it is, there is no denying that the coding experience has at least improved a notch. So we can’t imitate org. Springframework. Util. Assert, also write an assertion class, but an assertion fails after the exception thrown not IllegalArgumentException these built-in exceptions, but our own custom exception. Let’s give it a try.

Assert
public interface Assert {
    /** * Create exception *@param args
     * @return* /
    BaseException newException(Object... args);

    /** * Create exception *@param t
     * @param args
     * @return* /
    BaseException newException(Throwable t, Object... args);

    /** * <p> Asserts that the object <code>obj</code> is not null. If the object <code>obj</code> is empty, an exception * * is thrown@paramObj The object to be determined */
    default void assertNotNull(Object obj) {
        if (obj == null) {
            thrownewException(obj); }}/** * <p> Asserts that the object <code>obj</code> is not null. If the object <code>obj</code> is empty, an exception is thrown. * < P > Exception message< code> Message </code> Supports passing parameters, avoiding string concatenation before judgment@paramObj The object to be judged *@paramArgs message placeholder parameter list */
    default void assertNotNull(Object obj, Object... args) {
        if (obj == null) {
            thrownewException(args); }}}Copy the code

The Assert Assert method is defined using the default method of the interface. Notice that when the Assert fails, instead of a specific exception, the two newException interface methods provide the exception. For example, if the query result is null, the thrown exception may be UserNotFoundException with a specific exception code (for example, 7001) and the exception message “User does not exist”. So it’s up to Assert’s implementation class to decide what exceptions to throw. (Here recommended the previous day’s article removed annoying! = null)

If you look at this, you might wonder if the above statement requires equal assertion classes and exception classes for as many exceptions as possible, which is obviously anti-human and not as smart as you might think. Don’t worry, just listen to me.

Considerate Enum

Custom BaseException has two attributes: code and message. Do you have any classes that define these two attributes? That’s right, enumeration classes. See how I combine Enum and Assert, and I’m sure I’ll blow your mind. As follows:

public interface IResponseEnum {
    int getCode(a);
    String getMessage(a);
}
/** * 

Service exception

*

If an exception occurs during service processing, you can throw the exception

*/
public class BusinessException extends BaseException { private static final long serialVersionUID = 1L; public BusinessException(IResponseEnum responseEnum, Object[] args, String message) { super(responseEnum, args, message); } public BusinessException(IResponseEnum responseEnum, Object[] args, String message, Throwable cause) { super(responseEnum, args, message, cause); }}public interface BusinessExceptionAssert extends IResponseEnum.Assert { @Override default BaseException newException(Object... args) { String msg = MessageFormat.format(this.getMessage(), args); return new BusinessException(this, args, msg); } @Override default BaseException newException(Throwable t, Object... args) { String msg = MessageFormat.format(this.getMessage(), args); return new BusinessException(this, args, msg, t); }}@Getter @AllArgsConstructor public enum ResponseEnum implements BusinessExceptionAssert { /** * Bad licence type */ BAD_LICENCE_TYPE(7001."Bad licence type."), /** * Licence not found */ LICENCE_NOT_FOUND(7002."Licence not found.");/** * return code */ private int code; /** * returns a message */ private String message; }Copy the code

The code example defines two instances of enumerations: BAD_LICENCE_TYPE and LICENCE_NOT_FOUND correspond to BadLicenceTypeException and LicenceNotFoundException respectively. Instead of defining an exception class for each exception, you can simply add an enumeration instance. Then let’s see how to use it. Suppose LicenceService has a method to check whether Licence exists as follows:

/** * check {@linkLicence} *@param licence
     */
    private void checkNotNull(Licence licence) {
        ResponseEnum.LICENCE_NOT_FOUND.assertNotNull(licence);
    }
Copy the code

Without assertions, the code might look like this:

private void checkNotNull(Licence licence) {
        if (licence == null) {
            throw new LicenceNotFoundException();
            // Or so
            throw new BusinessException(7001."Bad licence type."); }}Copy the code

Using enumerated classes in combination with Assert, you can throw specific exceptions (with specific exception codes and exception messages) just by defining different enumeration instances for specific exception cases, such as BAD_LICENCE_TYPE and LICENCE_NOT_FOUND. This way, you don’t have to define a lot of exception classes, but you also have good readability of assertions. Read on to find out more.

Note: The above examples are specific to specific services, and some exceptions are general, such as: busy server, network exception, server exception, parameter verification exception, 404, etc., so there are
CommonResponseEnum,
ArgumentResponseEnum,
ServletResponseEnum, including
ServletResponseEnumMore on this later.

Define a unified exception handler class

@Slf4j
@Component
@ControllerAdvice
@ConditionalOnWebApplication
@ConditionalOnMissingBean(UnifiedExceptionHandler.class)
public class UnifiedExceptionHandler {
    /** * Production environment */
    private final static String ENV_PROD = "prod";

    @Autowired
    private UnifiedMessageSource unifiedMessageSource;

    /** * Current environment */
    @Value("${spring.profiles.active}")
    private String profile;
    
    /** * get internationalization message **@paramAbnormal e *@return* /
    public String getMessage(BaseException e) {
        String code = "response." + e.getResponseEnum().toString();
        String message = unifiedMessageSource.getMessage(code, e.getArgs());

        if (message == null || message.isEmpty()) {
            return e.getMessage();
        }

        return message;
    }

    /** * Service exception **@paramAbnormal e *@returnAbnormal result */
    @ExceptionHandler(value = BusinessException.class)
    @ResponseBody
    public ErrorResponse handleBusinessException(BaseException e) {
        log.error(e.getMessage(), e);

        return new ErrorResponse(e.getResponseEnum().getCode(), getMessage(e));
    }

    /** * Custom exception **@paramAbnormal e *@returnAbnormal result */
    @ExceptionHandler(value = BaseException.class)
    @ResponseBody
    public ErrorResponse handleBaseException(BaseException e) {
        log.error(e.getMessage(), e);

        return new ErrorResponse(e.getResponseEnum().getCode(), getMessage(e));
    }

    /** * Controller related exception **@paramAbnormal e *@returnAbnormal result */
    @ExceptionHandler({
            NoHandlerFoundException.class,
            HttpRequestMethodNotSupportedException.class,
            HttpMediaTypeNotSupportedException.class,
            MissingPathVariableException.class,
            MissingServletRequestParameterException.class,
            TypeMismatchException.class,
            HttpMessageNotReadableException.class,
            HttpMessageNotWritableException.class,
            // BindException.class,
            // MethodArgumentNotValidException.class
            HttpMediaTypeNotAcceptableException.class,
            ServletRequestBindingException.class,
            ConversionNotSupportedException.class,
            MissingServletRequestPartException.class,
            AsyncRequestTimeoutException.class
    })
    @ResponseBody
    public ErrorResponse handleServletException(Exception e) {
        log.error(e.getMessage(), e);
        int code = CommonResponseEnum.SERVER_ERROR.getCode();
        try {
            ServletResponseEnum servletExceptionEnum = ServletResponseEnum.valueOf(e.getClass().getSimpleName());
            code = servletExceptionEnum.getCode();
        } catch (IllegalArgumentException e1) {
            log.error("class [{}] not defined in enum {}", e.getClass().getName(), ServletResponseEnum.class.getName());
        }

        if (ENV_PROD.equals(profile)) {
            // In a production environment, it is not appropriate to display specific exception information to users, such as 404.
            code = CommonResponseEnum.SERVER_ERROR.getCode();
            BaseException baseException = new BaseException(CommonResponseEnum.SERVER_ERROR);
            String message = getMessage(baseException);
            return new ErrorResponse(code, message);
        }

        return new ErrorResponse(code, e.getMessage());
    }


    /** * Parameter binding exception **@paramAbnormal e *@returnAbnormal result */
    @ExceptionHandler(value = BindException.class)
    @ResponseBody
    public ErrorResponse handleBindException(BindException e) {
        log.error("Parameter binding check exception", e);

        return wrapperBindingResult(e.getBindingResult());
    }

    /** * Parameter check exception, combine all the failed check exception into an error message **@paramAbnormal e *@returnAbnormal result */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    @ResponseBody
    public ErrorResponse handleValidException(MethodArgumentNotValidException e) {
        log.error("Parameter binding check exception", e);

        return wrapperBindingResult(e.getBindingResult());
    }

    /** * Wrapper binding exception result **@paramBindingResult bindingResult *@returnAbnormal result */
    private ErrorResponse wrapperBindingResult(BindingResult bindingResult) {
        StringBuilder msg = new StringBuilder();

        for (ObjectError error : bindingResult.getAllErrors()) {
            msg.append(",");
            if (error instanceof FieldError) {
                msg.append(((FieldError) error).getField()).append(":");
            }
            msg.append(error.getDefaultMessage() == null ? "" : error.getDefaultMessage());

        }

        return new ErrorResponse(ArgumentResponseEnum.VALID_ERROR.getCode(), msg.substring(2));
    }

    /** * Undefined exception **@paramAbnormal e *@returnAbnormal result */
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public ErrorResponse handleException(Exception e) {
        log.error(e.getMessage(), e);

        if (ENV_PROD.equals(profile)) {
            // In a production environment, it is not suitable to display specific exception information, such as database exception information.
            int code = CommonResponseEnum.SERVER_ERROR.getCode();
            BaseException baseException = new BaseException(CommonResponseEnum.SERVER_ERROR);
            String message = getMessage(baseException);
            return new ErrorResponse(code, message);
        }

        return newErrorResponse(CommonResponseEnum.SERVER_ERROR.getCode(), e.getMessage()); }}Copy the code

As you can see, there are only two types of exceptions: ServletException and ServiceException. Remember the classification by stage mentioned above, that is, the exceptions before entering the Controller and the exceptions at the Service layer. ServiceException is then divided into custom exceptions and unknown exceptions. The corresponding relationship is as follows:

  • Enter theControllerPrevious exceptions: handleServletException, handleBindException, handleValidException
  • Custom exceptions include handleBusinessException and handleBaseException
  • Unknown exception: handleException

These exception handlers are described in detail.

Exception Handler Description

handleServletException

An HTTP request performs a series of checks between the request information and the target Controller information before reaching the Controller. NoHandlerFoundException: if the request Url does not contain a controller, the exception will be thrown.

HttpRequestMethodNotSupportedException: if the match in the (matching result is a list of different is the HTTP methods, such as: Get, Post, etc.), attempts to match the HTTP method of the request with the controller of the list. If there is no controller corresponding to the HTTP method, the exception is thrown.

HttpMediaTypeNotSupportedException: If the controller’s parameter signature contains the @requestBody annotation, but the request’s Content-Type header does not contain application/ JSON, the exception will be thrown (of course, This is not the only case where the exception is thrown); MissingPathVariableException: path parameters was detected. For example, if the URL is /licence/{licenceId} and the parameter signature contains @pathvariable (“licenceId”), if the requested URL is /licence, if the url is not clearly defined as /licence, it will be judged as missing path parameters.

MissingServletRequestParameterException: lack of request parameters. For example, if the @requestParam (“licenceId”) String licenceId parameter is defined but not carried when the request is initiated, the exception will be thrown. TypeMismatchException: The parameter type fails to match. For example, if the received parameter is Long, but the value passed is a string, the type conversion will fail and the exception will be thrown.

HttpMessageNotReadableException: and exactly the opposite of the above HttpMediaTypeNotSupportedException examples, namely the request header to carry the “content-type: application/json; Charset = utf-8 “, @requestbody is not added to the received argument, or the pojo fails to be serialized from the json string contained in the RequestBody. HttpMessageNotWritableException: the returned pojo in serialized into json process fails, then throw the exception;

handleBindException

Parameter verification is abnormal.

handleValidException

Parameter verification is abnormal.

HandleBusinessException, handleBaseException

Handles custom business exceptions, except that handleBaseException handles all business exceptions except BusinessException. For now, these two can be combined into one.

handleException

Handle all unknown exceptions, such as database failure exceptions.

Note: above
handleServletException,
handleExceptionThe exception information returned by the two processors may be different in different environments. It is thought that the exception information is the exception information provided by the framework, which is generally in English and not easy to show to users directly. Therefore, it is returned uniformly
SERVER_ERRORRepresents the exception information.

404 is unusual

As mentioned above, NoHandlerFoundException is thrown if the request does not match the controller, but this is not the case by default. By default, a page similar to the following appears:



How does the Whitelabel Error Page come up? In fact, when a 404 occurs, the default is not to throw an exception, but instead to forward to the /error controller. Spring also provides a default error controller, as follows:



To get 404 to throw an exception, add the following configuration to the properties file:

spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.add-mappings=falseCopy the code

In this way, it can be caught in the exception handler, and then the front end can catch the exception as long as it catches the specific status code and immediately jumps to the 404 page

Unified return result

Before we validate the unified exception handler, we should mention the unified return result. In plain English, it’s about unifying the data structures that return the results. Code and message are mandatory fields in all returned results. When data needs to be returned, another field data is required to represent it. So first define a BaseResponse as the base class for all returned results;

We then define a generic return result class CommonResponse, which inherits BaseResponse and includes data.

In order to distinguish between success and failure, we define another ErrorResponse. Finally, there is a common return result, that is, the data returned with paging information. Since this kind of interface is common, it is necessary to define a separate return result class QueryDataResponse. This class inherits from CommonResponse, but restricts the data field type to QueryDdata. QueryDdata defines the corresponding page-information fields, namely totalCount, pageNo, pageSize, and Records.

CommonResponse and QueryDataResponse are only commonly used, but their names are very long, so why not define two classes with very simple names instead? So R and QR are born, and when you return the result, you just say: new R<>(data), new QR<>(queryData). The definition of all return result classes is not posted here

Verify unified exception handling

Because this uniform set of exception handling is so generic, it can be designed as a common package that each new project/module will introduce later. So to verify, you need to create a new project and import the common package.

The main code

Here is the main source for validation:

@Service
public class LicenceService extends ServiceImpl<LicenceMapper.Licence> {

    @Autowired
    private OrganizationClient organizationClient;

    /** * query {@linkLicence} * for details@param licenceId
     * @return* /
    public LicenceDTO queryDetail(Long licenceId) {
        Licence licence = this.getById(licenceId);
        checkNotNull(licence);

        OrganizationDTO org = ClientUtil.execute(() -> organizationClient.getOrganization(licence.getOrganizationId()));
        return toLicenceDTO(licence, org);
    }

    /** ** page fetch *@paramLicenceParam paging query parameter *@return* /
    public QueryData<SimpleLicenceDTO> getLicences(LicenceParam licenceParam) {
        String licenceType = licenceParam.getLicenceType();
        LicenceTypeEnum licenceTypeEnum = LicenceTypeEnum.parseOfNullable(licenceType);
        // assert, not null
        ResponseEnum.BAD_LICENCE_TYPE.assertNotNull(licenceTypeEnum);

        LambdaQueryWrapper<Licence> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Licence::getLicenceType, licenceType);
        IPage<Licence> page = this.page(new QueryPage<>(licenceParam), wrapper);
        return new QueryData<>(page, this::toSimpleLicenceDTO);
    }

    /** * new {@link Licence}
     * @paramRequest Request body *@return* /
    @Transactional(rollbackFor = Throwable.class)
    public LicenceAddRespData addLicence(LicenceAddRequest request) {
        Licence licence = new Licence();
        licence.setOrganizationId(request.getOrganizationId());
        licence.setLicenceType(request.getLicenceType());
        licence.setProductName(request.getProductName());
        licence.setLicenceMax(request.getLicenceMax());
        licence.setLicenceAllocated(request.getLicenceAllocated());
        licence.setComment(request.getComment());
        this.save(licence);

        return new LicenceAddRespData(licence.getLicenceId());
    }

    /**
     * entity -> simple dto
     * @param licence {@link Licence} entity
     * @return {@link SimpleLicenceDTO}
     */
    private SimpleLicenceDTO toSimpleLicenceDTO(Licence licence) {
        / / to omit
    }

    /**
     * entity -> dto
     * @param licence {@link Licence} entity
     * @param org {@link OrganizationDTO}
     * @return {@link LicenceDTO}
     */
    private LicenceDTO toLicenceDTO(Licence licence, OrganizationDTO org) {
        / / to omit
    }

    /** * check {@linkLicence} *@param licence
     */
    private void checkNotNull(Licence licence) { ResponseEnum.LICENCE_NOT_FOUND.assertNotNull(licence); }}Copy the code

PS: The DAO framework used here is Mybatis – Plus.

At startup, the data automatically inserted is:

-- licence
INSERT INTO licence (licence_id, organization_id, licence_type, product_name, licence_max, licence_allocated)
VALUES (1.1.'user'.'CustomerPro'.100.5);
INSERT INTO licence (licence_id, organization_id, licence_type, product_name, licence_max, licence_allocated)
VALUES (2.1.'user'.'suitability-plus'.200.189);
INSERT INTO licence (licence_id, organization_id, licence_type, product_name, licence_max, licence_allocated)
VALUES (3.2.'user'.'HR-PowerSuite'.100.4);
INSERT INTO licence (licence_id, organization_id, licence_type, product_name, licence_max, licence_allocated)
VALUES (4.2.'core-prod'.'WildCat Application Gateway'.16.16);

-- organizations
INSERT INTO organization (id, name, contact_name, contact_email, contact_phone)
VALUES (1.'customer-crm-co'.'Mark Balster'.'[email protected]'.'823-555-1212');
INSERT INTO organization (id, name, contact_name, contact_email, contact_phone)
VALUES (2.'HR-PowerSuite'.'Doug Drewry'.'[email protected]'.'920-555-1212');Copy the code

To verify

Catch custom exceptions

1. For there is no licence for details: http://localhost:10000/licence/5. Successfully responded request: licenceId=1

Inspection is not empty


License not found exception was caught


Licence not found


2. According to there is no licence type get licence list: http://localhost:10000/licence/list? LicenceType = DDD. The available licence types are user and core-prod.

Check is not empty



Catch a Bad Licence Type exception

Bad licence type


Catch the exception before entering the Controller

1. Access does not exist interface: http://localhost:10000/licence/list/ddd

Catching a 404 exception


2. HTTP method does not support: http://localhost:10000/licencePostMapping


Catch the Request Method Not Supported exception


Request method not supported


3. Check exception 1: http://localhost:10000/licence/list? licenceType=getLicences



LicenceParam



Catch a parameter binding verification exception



licence type cannot be empty


4. Check exception 2: Post request, which is simulated by Postman.

addLicence


LicenceAddRequest

The request URL is the result

Catch a parameter binding verification exception

Note: Because the way of obtaining the anomaly information of the parameter binding check anomaly is different from other anomalies, the anomalies in these two cases are separated from those before entering the Controller. The following is the collection logic of the anomaly information: Collecting the anomaly information

Catching unknown exceptions

Suppose we casually to Licence now add a field test, but not change the database table structure, and then visit: http://localhost:10000/licence/1. Add test field


Catching a database exception

Error querying database

summary

As you can see, the test exceptions can be caught and returned as code or message. Instead of defining many exception classes, each project/module only needs to define an enumeration class when defining a business exception, implement the interface BusinessExceptionAssert, and finally define an enumeration instance for each business exception. It is also convenient to use, similar to assertions.

extension

In the production environment, if an unknown exception or a ServletException is caught, it would be unprofessional to show the user a long list of exception information. Instead, we can return “network exception” when the current environment is detected as a production environment. The network Is Abnormal in the production environment



You can modify the current environment in the following ways:



Example Change the current environment to the production environment

conclusion

Using a combination of assertions and enumerated classes, combined with uniform exception handling, almost all exceptions can be caught. The reason for most exceptions is that after the introduction of Spring Cloud Security, there will also be authentication/authorization exceptions, gateway service degradation exceptions, cross-module invocation exceptions, remote invocation of third-party services exceptions, etc. The capture methods of these exceptions are different from those described in this paper, but due to space limitations, there is no detailed explanation here. A separate article will be published later. In addition, when internationalization needs to be considered, the exception information captured after the exception generally cannot be returned directly and needs to be converted into the corresponding language. However, this article has taken this into account, and the internationalization mapping has been done when the message is obtained. The logic is as follows:



Finally, global exception is a topic that has been talked about for a long time. I hope this project will be a bit instructive for us to learn through mobile phone. Everyone according to the actual situation to modify. You can also use the following jsonResult object for processing and post the code as well.

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /** * No login *@param request
     * @param response
     * @param e
     * @return* /
    @ExceptionHandler(NoLoginException.class)
    public Object noLoginExceptionHandler(HttpServletRequest request,HttpServletResponse response,Exception e)
    {
        log.error("[GlobalExceptionHandler][noLoginExceptionHandler] exception",e);
        JsonResult jsonResult = new JsonResult();
        jsonResult.setCode(JsonResultCode.NO_LOGIN);
        jsonResult.setMessage("User login has expired or timed out. Please log in first.");
        return jsonResult;
    }

    /** * Service exception *@param request
     * @param response
     * @param e
     * @return* /
    @ExceptionHandler(ServiceException.class)
    public Object businessExceptionHandler(HttpServletRequest request,HttpServletResponse response,Exception e)
    {
        log.error("[GlobalExceptionHandler][businessExceptionHandler] exception",e);
        JsonResult jsonResult = new JsonResult();
        jsonResult.setCode(JsonResultCode.FAILURE);
        jsonResult.setMessage("Service abnormal. Please contact your administrator.");
        return jsonResult;
    }

    /** * Global exception handling *@param request
     * @param response
     * @param e
     * @return* /
    @ExceptionHandler(Exception.class)
    public Object exceptionHandler(HttpServletRequest request,HttpServletResponse response,Exception e)
    {
        log.error("[GlobalExceptionHandler][exceptionHandler] exception",e);
        JsonResult jsonResult = new JsonResult();
        jsonResult.setCode(JsonResultCode.FAILURE);
        jsonResult.setMessage("System error, please contact administrator.");
        returnjsonResult; }}Copy the code


Finally, if you learn something, please like + forward + favorites!

If you see this, you like this article, please share and like it. Scan the qr code below to follow us, you will receive more high-quality articles push, there are more free VIP resources waiting for you to take