Please, don't write a full screen try catch again!!

Keywords: Java Spring Database JSON

Author: giant brother
cnblogs.com/jurendage/p/11255197.html

background

In the process of software development, it is inevitable to deal with all kinds of exceptions. For myself, at least half of the time is spent dealing with all kinds of exceptions, so there will be a lot of try {...} catch {...} finally {...} code blocks in the code, which not only has a lot of redundant code, but also affects the readability of the code.

Compare the following two figures to see which style of code you are writing now? Then which coding style do you prefer?

Ugly try catch code block

Elegant Controller

The above example is only in the Controller layer. If it is in the Service layer, there may be more try catch code blocks. This will seriously affect the readability and aesthetics of the code.

So if it's me, I will definitely prefer the second one. I can focus more on the development of business code, and the code will become more concise.

Since the business code does not explicitly capture and handle exceptions, and exceptions must be handled, otherwise the system will crash, so there must be other places to capture and handle these exceptions.

So the question is, how to handle all kinds of exceptions gracefully?

What is unified exception handling

Spring added an annotation @ ControllerAdvice in version 3.2, which can be used with @ ExceptionHandler, @ InitBinder, @ ModelAttribute and other annotation annotations.

For the function of these annotations, I won't elaborate here. If you don't know about them, you can refer to the spring 3.2 new annotation @ ControllerAdvice. Let's have an idea first. Or WeChat official account: Java technology stack, back in the background: spring, can get my N Spring tutorial, dry cargo.

However, only the annotation @ ExceptionHandler is related to exception handling. Literally, it is the exception handler If an exception handling method is defined in a Controller class and the annotation is added to the method, the specified exception handling method will be executed. It can use the data binding provided by springmvc, such as injecting HttpServletRequest, etc., and it can also accept a Throwable object currently thrown.

However, in this way, a set of such exception handling methods must be defined in each Controller class, because exceptions can be various. In this way, a lot of redundant code will be generated, and if an exception handling logic needs to be added, all controller classes must be modified, which is not elegant.

Of course, you may say, then define a base class similar to BaseController, so that the total row.

It's true, but it's not perfect, because code like this is intrusive and coupled. Simple Controller, why do I have to inherit such a class? In case I already inherit other base classes. Everyone knows that Java can only inherit one class.

Is there a way to apply the defined exception handler to all controllers without coupling with the Controller? So the annotation @ ControllerAdvice appears. In short, it can apply exception handlers to all controllers, not to a single Controller.

With the help of this annotation, we can realize: in an independent place, such as a single class, define a set of handling mechanisms for various exceptions, and then add the annotation @ ControllerAdvice to the signature of the class to uniformly handle different exceptions in different stages. This is the principle of unified exception handling.

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

Exceptions at different stages

target

Eliminate more than 95% of try catch code blocks, verify the abnormal situation of business with elegant assert method, only focus on business logic, and do not spend a lot of energy writing redundant try catch code blocks.

Unified exception handling practice

Before defining the unified exception handling class, let's introduce how to determine the exception gracefully and throw the exception.

Replace throw exception with assert

You must be familiar with assert, such as the Spring family's org.springframework.util.Assert is often used when we write test cases. Using assertions can make us have a non general silky feeling when coding, such as:

@Test
public void test1() {
	...
	User user = userDao.selectById(userId);
	Assert.notNull(user, "user does not exist.");
	...
}

@Test
public void test2() {
	// Another way of writing
	User user = userDao.selectById(userId);
	if (user == null) {
		throw new IllegalArgumentException("user does not exist.");
	}
}

Do you feel that the first way to judge non empty writing is elegant? The second way is to write relatively ugly if {...} code blocks. So amazing Assert.notNull() what has been done behind it? Here are some source codes of assert:

public abstract class Assert {
    public Assert() {
    }

    public static void notNull(@Nullable Object object, String message) {
        if (object == null) {
            throw new IllegalArgumentException(message);
        }
    }
}

As you can see, Assert is actually to help us encapsulate if {...}. Isn't it amazing. Although very simple, it is undeniable that the coding experience has improved at least one level. So can we imitate org.springframework.util.Assert, also write an assertion class, but the exception thrown after the assertion fails is not the built-in exception of IllegalArgumentException, but the exception defined by ourselves. Let's try it.

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>Assertion object < code > obj < / code > is not empty. If the object < code > obj < / code > is empty, an exception is thrown
     *
     * @param obj Object to be judged
     */
    default void assertNotNull(Object obj) {
        if (obj == null) {
            throw newException(obj);
        }
    }

    /**
     * <p>Assertion object < code > obj < / code > is not empty. If the object < code > obj < / code > is empty, an exception is thrown
     * <p>Exception message < code > message < / code > supports parameter passing to avoid string splicing before judgment
     *
     * @param obj Object to be judged
     * @param args message Parameter list corresponding to placeholder
     */
    default void assertNotNull(Object obj, Object... args) {
        if (obj == null) {
            throw newException(args);
        }
    }
}

The above Assert assertion method is defined using the default method of the interface. Then, it is found that when the assertion fails, the exception thrown is not a specific exception, but provided by 2 newException interface methods.

Because the exceptions in business logic are basically corresponding to specific scenarios, such as obtaining user information according to user id, and the query result is null, the exception thrown may be UserNotFoundException, and there are specific exception codes (such as 7001) and exception information "user does not exist". Therefore, the specific exception thrown is determined by the implementation class of Assert.

See here, you may have such a question. According to the above statement, if there are not many exceptions, you have to define the same amount of assertion classes and exception classes. This is obviously anti-human, which is not brilliant. Don't worry. Listen to me carefully.

Considerate Enum

There are two attributes of the custom exception BaseException, namely code and message. Do you think of any class that will define these two attributes? Yes, enumeration classes. Let's see how I combine Enum and Assert. I'm sure I'll give you a glimpse. As follows:

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

/**
 * <p>Business exception</p>
 * <p>An exception occurs during business processing, which can be thrown</p>
 */
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;
    /**
     * Return message
     */
    private String message;
}

See here, do you have a bright feeling? There are two enumeration instances defined in the code example: BAD_LICENCE_TYPE,LICENCE_NOT_FOUND, corresponding to badlicensetypexception and licensenotfoundexception.

In the future, for each exception, you only need to add an enumeration instance, and no longer need to define an exception class for each exception. Then let's see how to use it. Suppose the licenseservice has a method to verify whether the license exists, as follows:

/**
 * Verify that {@ link license} exists
 * @param licence
 */
private void checkNotNull(Licence licence) {
	ResponseEnum.LICENCE\_NOT\_FOUND.assertNotNull(licence);
}

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.");
	}
}

Using enumeration classes in combination with (inheritance) Assert, you only need to define different enumeration instances according to specific exception conditions, such as the above BAD_LICENCE_TYPE,LICENCE_NOT_FOUND can throw specific exceptions according to different situations (here refers to carrying specific exception codes and exception messages). In this way, it does not need to define a large number of exception classes, but also has the good readability of assertions. Of course, the benefits of this scheme are far more than these. Please continue to read the following and slowly realize.

Note: the example above is for specific business, and some exceptions are common, such as server busy, network exception, server exception, parameter verification exception, 404, etc., so there are CommonResponseEnum, ArgumentResponseEnum, ServletResponseEnum, among which ServletResponseEnum will be explained in detail later.

Define 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 international message
     *
     * @param e abnormal
     * @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;
    }

    /**
     * Business exception
     *
     * @param e abnormal
     * @return Abnormal results
     */
    @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
     *
     * @param e abnormal
     * @return Abnormal results
     */
    @ExceptionHandler(value = BaseException.class)
    @ResponseBody
    public ErrorResponse handleBaseException(BaseException e) {
        log.error(e.getMessage(), e);

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

    /**
     * Controller Previous level related exceptions
     *
     * @param e abnormal
     * @return Abnormal results
     */
    @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)) {
            // When it is a production environment, it is not suitable 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
     *
     * @param e abnormal
     * @return Abnormal results
     */
    @ExceptionHandler(value = BindException.class)
    @ResponseBody
    public ErrorResponse handleBindException(BindException e) {
        log.error("Parameter binding verification exception", e);

        return wrapperBindingResult(e.getBindingResult());
    }

    /**
     * Parameter verification exception, which combines all exceptions failed in verification into one error message
     *
     * @param e abnormal
     * @return Abnormal results
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    @ResponseBody
    public ErrorResponse handleValidException(MethodArgumentNotValidException e) {
        log.error("Parameter binding verification exception", e);

        return wrapperBindingResult(e.getBindingResult());
    }

    /**
     * Wrapper binding exception result
     *
     * @param bindingResult Binding results
     * @return Abnormal results
     */
    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));
    }

    /**
     * No exception defined
     *
     * @param e abnormal
     * @return Abnormal results
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public ErrorResponse handleException(Exception e) {
        log.error(e.getMessage(), e);

        if (ENV_PROD.equals(profile)) {
            // When it is a production environment, it is not suitable to display specific exception information to users, 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 new ErrorResponse(CommonResponseEnum.SERVER_ERROR.getCode(), e.getMessage());
    }

}

As you can see, the above exceptions are divided into several categories, but in fact there are only two categories. One is ServletException and ServiceException. Remember the classification by stages mentioned above, which corresponds to the exception before entering the Controller and the Service layer exception. Then ServiceException is divided into custom exception and unknown exception. The corresponding relationship is as follows:

  • Exceptions before entering the Controller: handleServletException, handleBindException, handlevavalidexception

  • Custom exception: handleBusinessException, handleBaseException

  • Unknown exception: handleException

Next, we give a detailed description of these exception handlers.

Exception handler description

handleServletException

Before an http request arrives at the Controller, a series of verifications will be made between the requested information and the target Controller information. Here is a brief introduction:

NoHandlerFoundException: first, check whether there is a corresponding controller according to the request Url. If not, the exception will be thrown, which is a very familiar 404 exception;

HttpRequestMethodNotSupportedException: if it is matched (the matching result is a list, but the http method is different, such as Get, Post, etc.), try to match the http method of the request with the controller of the list. If there is no controller of the corresponding http method, throw the exception;

HttpMediaTypeNotSupportedException: then compare the request header with the one supported by the controller, such as the content type request header. If the parameter signature of the controller contains the annotation @ RequestBody, but the value of the request content type request header does not contain the application/json, then the exception will be thrown (not only in this case, of course);

MissingPathVariableException: path parameter not detected. For example, the url is / license / {licenseid}, and the parameter signature contains @ pathvariable ("licenseid"). When the requested url is / license, if the url is not clearly defined as / license, it will be determined as: the path parameter is missing;

MissingServletRequestParameterException: missing request parameter. For example, if the parameter @ requestparam ("licenseid") string licenseid is defined, but the parameter is not carried when the request is initiated, the exception will be thrown;

Typemissmachexception: parameter type matching failed. For example, if the receive parameter is Long, but the value passed in is a string, the type conversion will fail, and the exception will be thrown;

HttpMessageNotReadableException: in contrast to the above example of HttpMediaTypeNotSupportedException, the request header carries "content type: application / json; charset = UTF-8", but the receive parameter does not add the annotation @ RequestBody, or the json string carried by the request body fails to be deserialized into pojo, which will also throw the exception;

HttpMessageNotWritableException: if the returned pojo fails to be sequenced into json, throw the exception;

Recommended reading: Can you hold on to 10 questions about serialization?

handleBindException

Parameter verification is abnormal, which will be explained in detail later.

handleValidException

Parameter verification is abnormal, which will be explained in detail later.

handleBusinessException,handleBaseException

Handle custom business exceptions, but handleBaseException handles all business exceptions except for BusinessException. At present, the two can be combined into one.

handleException

Handle all unknown exceptions, such as those that fail to operate the database.

Note: the above two processors, handleServletException and handleException, may return different exception information in different environments. They think that these exception information are all the exception information of the framework, which is generally in English, which is not easy to show directly to the user, so they return the server uniformly_ The exception information represented by error.

404 different from ordinary people

As mentioned above, when the request does not match the controller, a NoHandlerFoundException exception exception will be thrown, but this is not the case by default. By default, a page similar to the following will appear:

Whitelabel Error Page

How does this page appear? In fact, when 404 occurs, the default is not to throw exceptions, but to forward to the / error controller. spring also provides a default error controller, as follows:

So, how to make 404 throw an exception, just add the following configuration in the properties file:

spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.add-mappings=false

In this way, it can be captured in the exception handler, and then the front end can jump to the 404 page as soon as it catches a specific status code

Catch the exception corresponding to 404

Unified return results

Before validating the unified exception handler, by the way, the unified return results. In fact, it is to unify the data structure of the returned results. code and message are required fields in all returned results. When data needs to be returned, another field data is needed to represent them.

First, define a BaseResponse as the base class of all returned results;

Then define a common return result class, CommonResponse, which inherits BaseResponse and has more field data;

In order to distinguish between success and failure return results, an ErrorResponse is defined

Finally, there is a common return result, that is, the returned data has paging information. Because this interface is quite common, it is necessary to define a separate return result class, QueryDataResponse, which inherits from the CommonResponse. Only the type of data field is limited to QueryDdata, and the corresponding fields of paging information are defined in QueryDdata, namely totalCount, pageNo pageSize,records.

Among them, CommonResponse and QueryDataResponse are the only common ones, but the names are too long for thieves. Why not define two super simple classes to replace them? So r and QR are born. In the future, when you return the result, you only need to write as follows: new R < > (data), new QR < > (querydata).

All the definitions of return result classes will not be pasted here

Verify unified exception handling

Because this set of unified exception handling can be said to be universal, all can be designed into a common package, and each new project / module only needs to introduce this package in the future. So in order to verify, you need to create a new project and introduce the common package.

Main code

Here is the main source code for verification:

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

    @Autowired
    private OrganizationClient organizationClient;

    /**
     * Query {@ link license} 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);
    }

    /**
     * Paging get
     * @param licenceParam Paging query parameters
     * @return
     */
    public QueryData<SimpleLicenceDTO> getLicences(LicenceParam licenceParam) {
        String licenceType = licenceParam.getLicenceType();
        LicenceTypeEnum licenceTypeEnum = LicenceTypeEnum.parseOfNullable(licenceType);
        // Assertion, non empty
        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);
    }

    /**
     * Add {@ link license}
     * @param request Requestor
     * @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) {
        // ellipsis
    }

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

    /**
     * Verify that {@ link license} exists
     * @param licence
     */
    private void checkNotNull(Licence licence) {
        ResponseEnum.LICENCE\_NOT\_FOUND.assertNotNull(licence);
    }

}

PS: the DAO framework used here is mybatis plus. At startup, the automatically inserted data 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', 'mark.balster@custcrmco.com', '823-555-1212');
INSERT INTO organization (id, name, contact\_name, contact\_email, contact_phone)
VALUES (2, 'HR-PowerSuite', 'Doug Drewry','doug.drewry@hr.com', '920-555-1212');
Start validation
Catch custom exception

1. Obtain the non-existent license details: http://localhost:10000/licence/5. Successfully responded request: licenseid = 1

Check non empty

Catch license not found exception

Licence not found

2. Obtain the license list according to the nonexistent license type: http://localhost:10000/licence/list?licenceType=ddd. Optional License type: user, core prod.

Verification is not empty

Catch bad license type exception

Bad licence type

Catch exception before entering Controller

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

Catch 404 exceptions

2. http method does not support: http://localhost:10000/licence

PostMapping

Catch Request method not supported exception

Request method not supported

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

getLicences

LicenceParam

Catch parameter binding verification exception

licence type cannot be empty

4. Verification exception 2: post request, where postman simulation is used.

addLicence

LicenceAddRequest

Request url is the result

Catch parameter binding verification exception

Note: because the exception information of parameter binding verification exception is not obtained in the same way as other exceptions, the exceptions in these two cases are separated from the exceptions before entering the Controller. The following is the collection logic of exception information:

Collection of exception information

Catch unknown exception

Suppose we add a new field test to the license, but do not modify the database table structure, and then access: http://localhost:10000/licence/1.

Recommended reading: 10 best practices for exception handling

Add test field

Catch database exception

Error querying database

Summary

As you can see, all exceptions of the test can be caught and returned in the form of code and message. For each project / module, when defining a business exception, you only need to define an enumeration class, then implement the interface BusinessExceptionAssert, and finally define the corresponding enumeration instance for each business exception instead of defining many exception classes. It is also convenient to use, similar to assertions.

extend

In the production environment, if an unknown exception or ServletException is caught, because it is a long string of exception information, if it is directly displayed to the user, it is not professional enough, so we can do this: when the current environment is detected as the production environment, then directly return "network exception".

Production environment returned "network exception"

You can modify the current environment in the following ways:

Modify current environment to production environment

summary

With the combination of assertions and enumeration classes, and with unified exception handling, most of the exceptions can be caught.

Why do you say most of the exceptions? When spring cloud security is introduced, there will be authentication / authorization exceptions, gateway service degradation exceptions, cross module call exceptions, remote call to third-party service exceptions, etc. the capture methods of these exceptions are not the same as those described in this article, but limited to the length, which will not be described in detail here, and will be introduced in a separate article in the future.

In addition, when internationalization needs to be considered, the exception information after catching the exception cannot be returned directly, and needs to be converted into the corresponding language. However, this paper has taken this into account, and the internationalization mapping has been done when obtaining the message, and the logic is as follows:

Get international message

Finally, it is concluded that the overall abnormality belongs to the topic of senior students' long-term discussion. I hope that this mobile phone project can give you some guidance in learning. We will revise it according to the actual situation.

You can also use the following jsonResult object to process and paste the code

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * not logged on
     * @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 failure or login timeout,Please log in first");
        return jsonResult;
    }

    /**
     * Business 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("Business exception,Please contact the 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 the administrator");
        return jsonResult;
    }
}

Recommend to my blog to read more:

1.Java JVM, collection, multithreading, new features series

2.Spring MVC, Spring Boot, Spring Cloud series tutorials

3.Maven, Git, Eclipse, Intellij IDEA series tools tutorial

4.Latest interview questions of Java, backend, architecture, Alibaba and other large factories

Feel good, don't forget to like + forward!

Posted by chapm4 on Mon, 08 Jun 2020 21:34:07 -0700