Youngljx.top is a Java beginner’s personal blog

Insert a picture description here

Parameter calibration

The importance of data verification goes without saying. Even in the case of data verification in the front end, we still need to verify the data passed to the back end again to avoid users bypassing the browser directly through some HTTP tools directly request some illegal data to the back end.

The most common way to do this is to validate parameters in the business layer, but this is too tedious. Use Spring Validator and Hibernate Validator to validate parameters. Both sets of Validator dependencies are already included with the Web dependencies described above, so you can use them directly.

1. Some common annotations for field validation

  • @NotEmptyThe annotated string cannot be null or null
  • @NotBlankThe annotated string is non-null and must contain a non-whitespace character
  • @NullThe annotated element must be NULL
  • @NotNullThe annotated element must not be NULL
  • @AssertTrueThe annotated element must be true
  • @AssertFalseThe annotated element must be false
  • @Pattern(regex=,flag=)The annotated element must conform to the specified regular expression
  • @EmailThe annotated element must be in Email format.
  • @Min(value)The annotated element must be a number whose value must be greater than or equal to the specified minimum
  • @Max(value)The annotated element must be a number whose value must be less than or equal to the specified maximum
  • @DecimalMin(value)The annotated element must be a number whose value must be greater than or equal to the specified minimum
  • @DecimalMax(value)The annotated element must be a number whose value must be less than or equal to the specified maximum
  • @Size(max=, min=)The size of the annotated element must be within the specified range
  • @Digits (integer, fraction)The annotated element must be a number and its value must be within an acceptable range
  • @PastThe annotated element must be a past date
  • @FutureThe annotated element must be a future date

2.Validator + BindResult validates

Validators make it easy to write validation rules and automate validation for you. First, annotate the fields to be checked in the input parameter, and each annotation corresponds to a different check rule, and can formulate the information after the check failure:

@Data
public class User {
    @NotNull(message = "User ID cannot be empty")
    private Long id;

 @NotNull(message = "User account cannot be empty.")  @Size(min = 6, max = 11, message = "Account must be 6-11 characters long")  private String account;   @NotNull(message = "User password cannot be empty")  @Size(min = 6, max = 11, message = "Password must be 6-16 characters long")  private String password;   @NotNull(message = "User's mailbox cannot be empty.")  @Email(message = "Email format is incorrect")  private String email; } Copy the code

Validate the RequestBody

Validation rules and error information configuration has been completed, the next need only on the parameters of the interface need to check with “@ Valid” annotations, if validation fails, it throws MethodArgumentNotValidException, continue to add “BindResult” parameters can be complete validation:

@RestController
@RequestMapping("user")
public class UserController {
    @Autowired
    private UserService userService;
  @PostMapping("/addUser")  public String addUser(@RequestBody @Valid User user, BindingResult bindingResult) {  // If a parameter fails to be verified, the error message is encapsulated as an object and assembled in BindingResult  for (ObjectError error : bindingResult.getAllErrors()) {  return error.getDefaultMessage();  }  return userService.addUser(user);  } } Copy the code

When the request data is passed to the interface, the Validator completes the validation automatically, and the validation results are encapsulated in BindingResult. If there is an error message, we return it directly to the front end, and the business logic code does not execute at all.

Verify the Request Parameters (Path Variables and Request Parameters)

Make sure, make sure you don’t forget to add to the classValidatedAnnotated, this parameter tells Spring to validate method arguments.

@RestController
@RequestMapping("/api")
@Validated
public class PersonController {

 @GetMapping("/person/{id}")  public ResponseEntity<Integer> getPersonByID(@Valid @PathVariable("id") @Max(value = 5,message = "Out of range of id") Integer id) {  return ResponseEntity.ok().body(id);  } } Copy the code

Unified Exception Handling

Parameter verification failure will automatically raise an exception, we certainly can not go to manually capture the exception for processing, otherwise it would be better to use the previous BindingResult method, just use SpringBoot global exception processing to achieve the effect once and for all!

Exception handling process:

1. Customize the global exception class using @controllerAdvice, controller enhancement

2. Customize error codes and error messages. The two exceptions will be expressed in a unified message format: error code + error message.

3. Predictable exceptions are actively thrown by programmers in the code, which are uniformly captured by SpringMVC.

4. Unexpected exceptions are caused by system bugs or external factors, such as network fluctuations or server outages. The exception type is RuntimeException (RuntimeException).

We typically use @ControllerAdvice and @ExceptionHandler to handle global exceptions

Related notes:

  1. @ControllerAdviceAnnotation defines the global exception handling class
  2. @ExceptionHandler: annotation declares exception handling methods

Custom exception types

In many cases, we need to manually throw exceptions, such as in the business layer when some conditions do not conform to the business logic, I can manually throw exceptions to trigger transaction rollback. We usually deal with RuntimeExceptions, so if you need to customize the exception type, you can integrate it directly, for example:

public class ResourceNotFoundException extends RuntimeException {
    private String message;

    public ResourceNotFoundException(a) {
        super(a); }   public ResourceNotFoundException(String message) {  super(message);  this.message = message;  }   @Override  public String getMessage(a) {  return message;  }   public void setMessage(String message) {  this.message = message;  } } Copy the code

Create a new exception handling class to handle global exceptions

@ControllerAdvice(assignableTypes = {ExceptionController.class})// Specific Controller classes can be specified by assignableTypes so that the exception-handling classes only handle exceptions thrown by that particular class
@ResponseBody
public class GlobalExceptionHandler {

    ErrorResponse illegalArgumentResponse = new ErrorResponse(new IllegalArgumentException("Wrong parameter!"));
 ErrorResponse resourseNotFoundResponse = new ErrorResponse(new ResourceNotFoundException("Sorry, the resourse not found!"));   @ExceptionHandler(value = Exception.class)// Intercept all exceptions. This is just to demonstrate that it is common for a method to handle a specific exception  public ResponseEntity<ErrorResponse> exceptionHandler(Exception e) {   if (e instanceof IllegalArgumentException) {  return ResponseEntity.status(400).body(illegalArgumentResponse);  } else if (e instanceof ResourceNotFoundException) {  return ResponseEntity.status(404).body(resourseNotFoundResponse);  }  return null;  } } Copy the code

Unified result response

At present, most data is transmitted in JSON format in front and back end development. Therefore, defining a uniform and standardized data format is conducive to front and back end interaction and UI presentation.

Result class enumeration

@Getter
public enum ResultCodeEnum {
    SUCCESS(true.20000."Success"),
    UNKNOWN_ERROR(false.20001."Unknown error"),,
    PARAM_ERROR(false.20002."Parameter error"),
 ;   // Whether the response was successful  private Boolean success;  // Response status code  private Integer code;  // Response information  private String message;   ResultCodeEnum(boolean success, Integer code, String message) {  this.success = success;  this.code = code;  this.message = message;  } } Copy the code

Uniform result class

1. The constructor is private because only methods that return a uniform class can be called.

2. Built-in static method, return object;

3. In order to customize the unified result information, it is recommended to use chained programming, which will return the object class itself, namely return this;

4. As the response data is in JSON format, it can be defined as JsonObject or Map.

@Data
public class R {
    private Boolean success;

    private Integer code;
  private String message;   private Map<String, Object> data = new HashMap<>();   // Constructor is private  private R(a){}   // General returned successful  public static R ok(a) {  R r = new R();  r.setSuccess(ResultCodeEnum.SUCCESS.getSuccess());  r.setCode(ResultCodeEnum.SUCCESS.getCode());  r.setMessage(ResultCodeEnum.SUCCESS.getMessage());  return r;  }   // Generic return failure, unknown error  public static R error(a) {  R r = new R();  r.setSuccess(ResultCodeEnum.UNKNOWN_ERROR.getSuccess());  r.setCode(ResultCodeEnum.UNKNOWN_ERROR.getCode());  r.setMessage(ResultCodeEnum.UNKNOWN_ERROR.getMessage());  return r;  }   // Sets the result. The parameter is the result enumeration  public static R setResult(ResultCodeEnum result) {  R r = new R();  r.setSuccess(result.getSuccess());  r.setCode(result.getCode());  r.setMessage(result.getMessage());  return r;  }   /**------------ uses chained programming to return the class itself -----------**/   // Customize the return data  public R data(Map<String,Object> map) {  this.setData(map);  return this;  }   // Set the general data  public R data(String key,Object value) {  this.data.put(key, value);  return this;  }   // Customize the status information  public R message(String message) {  this.setMessage(message);  return this;  }   // Customize the status code  public R code(Integer code) {  this.setCode(code);  return this;  }   // Customize the return result  public R success(Boolean success) {  this.setSuccess(success);  return this;  } } Copy the code

Control layer return

@RestController
@RequestMapping("/api/v1/users")
public class TeacherAdminController {

    @Autowired
 private UserService userService;   @GetMapping  public R list(a) {  List<Teacher> list = teacherService.list(null);  return R.ok().data("itms", list).message("User List");  } } Copy the code

This is a simple summary of the record, to be continued

Reference article:

Project practice: Spring Boot three moves combination, hand in hand to teach you to play elegant back-end interface

The project manager said: Unified results, unified exceptions, unified logs

SpringBoot handles several common poses for exceptions

This article is formatted using MDNICE