Exception handling and parameter checking in SpringBoot

Keywords: Programming JSON SpringBoot Spring

Hello, brothers, this time to exchange two questions with the old fellow, exception and parameter checking. Before we talk about parameter checking, let's first talk about exception handling, because the latter parameter checking involves exception handling.

exception handling

When it comes to exception handling, I don't know if you've written or encountered the following.

public void saveUser() {
        
    try {
        // All business content, visually measuring hundreds of lines
    }catch (Exception e) {
        e.printStackTrace();
    }
}

If the above code appears, it contains a lot of business code. If it is written by you, change it immediately. If it is not written by you, change it immediately.

Problems:

  • 1. Performance bottlenecks will be encountered;
  • 2. It is difficult to locate problems;
  • 3. Too many try s are nested and the readability is poor.

Whatever the reason for the above code, it's best to change it. If you don't want to try in your business code, you should only use try where exceptions might occur, not try the entire business code.

Exception capture in SpringBoot

Direct Up Code

@RestControllerAdvice
public class GlobalException {

    @ExceptionHandler(value = Exception.class) // Catched exception types
    public Object globalException(Exception ex) {

        // exception handling
        ex.printStackTrace();

        return "An exception occurred";
    }
}

So in SpringBoot, we can get the exception's place in the project through such a configuration, and we can get the detailed information of the class with the exception in this method, so are we all using Exception to handle all the exception?That must not be appropriate.

We simulate a by zero exception and then configure a handler that handles the ArithmeticException exception with the following code:

@RestControllerAdvice
public class GlobalException {


    @ExceptionHandler(value = Exception.class) // Catched exception types
    public Object globalException(Exception ex) {

        ex.printStackTrace();

        return "An exception occurred";
    }

    @ExceptionHandler(value = ArithmeticException.class)
    public Object arithmeticException(ArithmeticException ex) {

        ex.printStackTrace();
        return "by zero abnormal";
    }
}

If by zero exceptions occur at this time, take ArithmeticException exception handling because if there are smaller exception handling classes, then smaller exception handlers will be taken.A larger exception handling class for globalException will not be moved.

After this, we don't need to write so many try s in the project. Is it convenient?

In addition to using these existing exceptions, in fact, we can customize our exceptions, such as user unregistered exceptions, parameter error exceptions and so on.However, considering the length of this article, I will not write it this time. Interested friends can leave a message directly below. More people will update me as soon as possible.

Attention pit:

Share with you a trampled pit where you can no longer throw exceptions in the Filter. If you throw exceptions in the Filter and then handle them through the exception handling class, it is impossible because the processor can't catch exceptions thrown by the Filter.

Parameter Check

The old rule, let's start with a piece of code

@RequestMapping(value = "/save/user")
public Object saveUser(UserPO userPO) {

    if (userPO.getAge() == null) {
        return "Request parameter error";
    }

    if (userPO.getSex() == null) {
        return "Request parameter error";
    }
    if (userPO.getUsername() == null) {
        return "Request parameter error";
    }

    // ...

    return "SUCCESS";
}

You should have seen this kind of check parameter, I've actually written it.The more you write, the low er you feel, so try harder, or change it as soon as possible.

@Validated comment

This comment is actually provided by Spring. If your project is not a SpringBoot project, you need to refer to the pom file you need. If so, you don't need to worry. SpringBoot has already helped us introduce it.

I have read a lot of blogs on the Internet, many of them are not completely said, most of them are about the verification of JavaBean parameters, but some interfaces in our project may involve a parameter, there is no need to write a JavaBean at all. Many blogs have not said anything about single parameter verification, so we will make it clear once this time.

Checks for a single parameter

Look directly at the code

@Validated
@RestController
public class BookController {
    
    @RequestMapping(value = "/book/info", method = RequestMethod.GET)
    public Object getBookInfo(@NotBlank(message = "book ID Cannot be empty") String bookId) {

        return "SUCCESS";
    }
}

In particular, if it is a single parameter check, then we have to add the @Validated annotation on the class, or our entire single parameter check will not work. You can see that when we checked the bookId parameter, we used @NotBlank as the name implies, that is, the parameter cannot be null, nor after the trim() method has been called.Is an empty character.

If the parameter does not satisfy the requirement, a ConstraintViolationException exception is thrown, which is only thrown during single parameter checking. If your parameter is a JavaBean, it is not an exception.

Now that we know it throws exceptions and what type of exceptions it is, it's super easy for us to handle our exceptions directly using the exception handling class we just learned above.

I find one that is easier to write in. If you want to write more complex, it is possible in fact, but as a backend, I don't think it is necessary because we can't prompt the front end with too obvious error hints to prevent others from maliciously attacking us, just like the user name password error, we can't tell the user exactly whether it is a user name error or a password error, we can only mention it.Indicates a user name or password error.

If you have to print out detailed error information, you can see which parameter check failed, or you can print out specific parameter error information in the following way.The error result of the output is actually the content of the message above.

@RestControllerAdvice
public class ExceptionCatch {
    /**
     * Single parameter exception handling
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(value = ConstraintViolationException.class)
    public Object constraintViolationException(ConstraintViolationException ex) {

        // Get specific error information
        Set<ConstraintViolation<?>> violations = ex.getConstraintViolations();
        // print data
        violations.forEach(e -> System.out.println(e.getMessage()));
        
        return "single-Request parameter error";
    }
}

JavaBean Parameter Check (form-data)

Writing of JavaBean s

@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserPO {

    @NotBlank(message = "User name cannot be empty")
    private String username;

    @NotNull(message = "Age cannot be empty")
    @Min(value = 1, message = "Minimum age 1")
    @Max(value = 200, message = "Maximum age 200")
    private Integer age;

    @NotBlank(message = "Gender cannot be empty")
    private String sex;
}

Controller Writing

@RequestMapping(value = "/save/user")
public Object saveUser(@Validated UserPO userPO) {

    // ...

    return "SUCCESS";
}

Unlike single parameter checks, JavaBean s require @Validated to be written on method parameters, not classes.If a parameter check fails, an exception, BindException, is thrown as well.

/**
 * General parameter check binding exception handling
 *
 * @param ex
 * @return
 */
@ExceptionHandler(value = BindException.class)
public Object bindException(BindException ex) {

    BindingResult bindingResult = ex.getBindingResult();

    // Get all error information
    List<ObjectError> allErrors = bindingResult.getAllErrors();

    // output
    allErrors.forEach(e -> System.out.println(e.getDefaultMessage()));

    return "Request parameter error";
}

Note: There are two ways to post request, one is based on the form-data format, the other is based on the JSON format. The exceptions caused by the two methods are also different, so we have to handle the json-based parameter check exception handling separately.

JavaBean Parameter Check (json)

Let's first look at how Controller receives

@RequestMapping(value = "/save/user")
public Object saveUser(@Validated @RequestBody UserPO userPO) {

    // ...

    return "SUCCESS";
}

Corresponding parameter exception handling

/**
 * JSON Parameter Check Binding Exception Handling
 *
 * @param ex
 * @return
 */
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public Object methodArgumentNotValidException(MethodArgumentNotValidException ex) {

    BindingResult bindingResult = ex.getBindingResult();

    // Get all error information
    List<ObjectError> allErrors = bindingResult.getAllErrors();

    // output
    allErrors.forEach(e -> System.out.println(e.getDefaultMessage()));

    return "Request parameter error-json";
}

Last words

This concludes our article with two main sections, exception handling and parameter checking.It's easy, but I personally feel like a very common skill.So share it with everyone and if it helps you a little, give it a pat on the back.If you don't understand anything, please leave a message below to communicate.

More on WeChat Public Number: The Growth of a Programmer

Posted by liamjw on Mon, 20 Apr 2020 19:12:02 -0700