My official account is MarkerHub and my website is Markerhub.com

For more selected articles, please click: Java Notes Complete.md

Small Hub read:

Unified structure returns, unified parameter verification, can reduce a lot of code!


  • Author: Jin Cheng
  • juejin.im/post/5d3fbeb46fb9a06b317b3c48

Javax. validation is an annotated parameter validation for spring’s javax.validation.

Why validator

Javax. Validation has a set of annotations to help you validate parameters without having to do serial validation

Otherwise our code would look something like this:

/ / http://localhost:8080/api/user/save/serial/serial check * * * * * go @ param userVO * @ return * / @ PostMapping ("/save/serial ") public Object save(@RequestBody UserVO userVO) { String mobile = userVO.getMobile(); If (stringutils.isblank (mobile)) {return rspdto. paramFail("mobile: mobile number cannot be empty "); } else if (! The Pattern matches (" ^ [1] [3,4,5,6,7,8,9] [0-9] {9} $", mobile)) {return RspDTO. ParamFail (" mobile: phone number format is wrong "); If (stringutils.isblank (uservo.getUsername ())) {throw new BizException(constant.param_fail_code, "User name cannot be empty "); } // If (stringutils.isblank (uservo.getsex ())) {map <String, Object> result = new HashMap<>(5); result.put("code", Constant.PARAM_FAIL_CODE); Result. Put (" MSG ", "gender cannot be empty "); return result; } / /... Various ways of writing... userService.save(userVO); return RspDTO.success(); }Copy the code

This is big guy see, certain say, all 9102 still write so, then be persuaded to retire… .

2. What is Javax.Validation

JSR303 is a standard for JavaBean parameter validation. It defines a number of common validation annotations that we can directly add to our JavaBean properties (annotation-oriented programming era). In SpringBoot, it is already included in the starter-Web, and in other projects it can reference dependencies and adjust the version itself:

<! --jsr 303--> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> < version > 1.1.0. Final < / version > < / dependency > <! -- hibernate validator--> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> < version > 5.2.0. Final < / version > < / dependency >Copy the code

3. Notes

  • @notnull: cannot be null, but can be empty(“”,” “,” “)

  • @notempty: cannot be null and must be longer than 0 (“”,” “)

  • @notblank: applies only to strings, not null, and must be greater than 0(“test”) after trim(), i.e. must have real characters

Most of the validation constraint annotations provided by Hibernate Validator are listed here. Please refer to the Hibernate Validator official documentation for additional validation constraint annotations and custom validation constraint annotation definitions.

We practice

Without further ado, go straight to the hands-on route, again using SpringBoot’s fast framework

See the detailed code:

Github.com/leaJone/myb…

1. @Validated Specifies the parameters to be checked

Here we make an annotation declaration at the controller layer

** @param userDTO * @RETURN */ @postMapping ("/save/valid") public RspDTO save(@requestBody @validated) UserDTO userDTO) { userService.save(userDTO); return RspDTO.success(); }Copy the code

2. Annotate the parameter fields

import lombok.Data; import org.hibernate.validator.constraints.Length; import javax.validation.constraints.*; import java.io.Serializable; import java.util.Date; /** * @author LiJing * @ClassName: UserDTO * @Description: @date 2019/7/30 13:55 */ @data public class UserDTO implements Serializable {private static final Long serialVersionUID = 1L; /*** userId */ @notnull (message = "userId cannot be null ") private Long userId; /** user name */ @notblank (message = "user name cannot be empty ") @length (Max = 20, Message = "Usernames cannot exceed 20 characters ") @pattern (regexp = "^[\\u4E00-\\ u9FA5A-za-z0-9 \\*]*$", message =" Usernames limit: A maximum of 20 characters including characters, letters and digits ") private String username; / cell phone number * * * / @ NotBlank (message = "mobile phone number can't be empty") @ the Pattern (regexp = "^ [1] [3,4,5,6,7,8,9] [0-9] {9} $". Message = "error ") private String mobile; /** sex */ private String sex; /** Email */ @notblank (message = "Email cannot be empty ") @email (message =" Email format is incorrect ") private String Email; /** password */ private String password; /*** createTime */ @future (message = "createTime must be Future time ") private Date createTime; }Copy the code

3. Add verification exceptions to the global verification

MethodArgumentNotValidException is the exception in the case of binding parameters calibration springBoot, need in springBoot processing, Need to deal with other ConstraintViolationException exception processing.

For the sake of elegance, we made a global exception by combining parameter exception and business exception, and wrapped the control layer exception into our custom exception.

In order to be more elegant, we also made a unified structure, which encapsulated the requested code, MSG and data into the structure, increasing the reusability of the code.

import com.boot.lea.mybot.dto.RspDTO; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.dao.DuplicateKeyException; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.servlet.NoHandlerFoundException; import javax.validation.ConstraintViolationException; import javax.validation.ValidationException; /** * @author LiJing * @ClassName: GlobalExceptionHandler * @Description: GlobalExceptionHandler * @date 2019/7/30 13:57 */ @restcontrolleradvice public class GlobalExceptionHandler {private Logger Logger = LoggerFactory.getLogger(getClass()); private static int DUPLICATE_KEY_CODE = 1001; private static int PARAM_FAIL_CODE = 1002; private static int VALIDATION_CODE = 1003; */ @exceptionHandler (bizException.class) public RspDTO handleRRException(BizException e) { logger.error(e.getMessage(), e); return new RspDTO(e.getCode(), e.getMessage()); } method parameters calibration / * * * * / @ ExceptionHandler (MethodArgumentNotValidException. Class) public RspDTO handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { logger.error(e.getMessage(), e); return new RspDTO(PARAM_FAIL_CODE, e.getBindingResult().getFieldError().getDefaultMessage()); } /** * ValidationException */ @ExceptionHandler(ValidationException.class) public RspDTO handleValidationException(ValidationException e) { logger.error(e.getMessage(), e); return new RspDTO(VALIDATION_CODE, e.getCause().getMessage()); } /** * ConstraintViolationException */ @ExceptionHandler(ConstraintViolationException.class) public RspDTO handleConstraintViolationException(ConstraintViolationException e) { logger.error(e.getMessage(), e); return new RspDTO(PARAM_FAIL_CODE, e.getMessage()); } @ExceptionHandler(NoHandlerFoundException.class) public RspDTO handlerNoFoundException(Exception e) { logger.error(e.getMessage(), e); Return new RspDTO(404, "path not found, please check path is correct "); } @ExceptionHandler(DuplicateKeyException.class) public RspDTO handleDuplicateKeyException(DuplicateKeyException e) { logger.error(e.getMessage(), e); Return new RspDTO(DUPLICATE_KEY_CODE, "duplicate_code "); } @ExceptionHandler(Exception.class) public RspDTO handleException(Exception e) { logger.error(e.getMessage(), e); Return new RspDTO(500, "system busy, please try again later "); }}Copy the code

4. Test

It does return abnormal information and corresponding code when parameter verification, which is convenient for us to deal with parameter verification no longer

In ValidationMessages. The properties is to check the message, has already written the default message, and is the i18n support, you can read the source code

Custom parameter annotations

1. For example, let’s make a custom ID verification annotation

@Documented @Target({ElementType.PARAMETER, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = IdentityCardNumberValidator.class) Public @interface IdentityCardNumber {String message() default "IdentityCardNumber is invalid "; Class<? >[] groups() default {}; Class<? extends Payload>[] payload() default {}; }Copy the code

This annotation is applied to the Field Field at runtime and triggers the authentication class IdentityCardNumber.

  • Message customized, mainly from ValidationMessages. Extract, the properties can also be customized according to the actual situation

  • Groups Classifies validators into groups. Different groups perform different validators

  • Payload is mainly used for beans.

2. Then customize the Validator

Here’s the actual verification logic:

public class IdentityCardNumberValidator implements ConstraintValidator<IdentityCardNumber, Object> { @Override public void initialize(IdentityCardNumber identityCardNumber) { } @Override public boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) { return IdCardValidatorUtils.isValidate18Idcard(o.toString()); }}Copy the code

IdCardValidatorUtils in the project source, you can view

3. Use custom annotations

@notblank (message = "id card number cannot be blank ") @identityCardNumber (message =" id card number cannot be blank ") private String clientCardNo;Copy the code

4. Use groups to verify

UserDTO = userId; userId = userId; username = groups; UserDTO = userId; UserDTO = userId;

Define the Create and Update group interfaces for groups

import javax.validation.groups.Default;

public interface Create extends Default {
}

import javax.validation.groups.Default;

public interface Update extends Default{
}


Copy the code

Then, declare the verification group at @, where the verification is required

@param userDTO * @return */ @postmapping ("/update/groups") public RspDTO update(@RequestBody @Validated(Update.class) UserDTO userDTO) { userService.updateById(userDTO); return RspDTO.success(); }Copy the code

Define the group type of groups = {} on the field in the DTO

@Data public class UserDTO implements Serializable { private static final long serialVersionUID = 1L; /*** userId */ @notnull (message = "userId cannot be null ", groups = update.class) private Long userId; /** * usernames */ @notblank (message = "usernames cannot be blank ") @length (Max = 20, message =" usernames cannot be blank "), groups = {create.class, Update. Class}) @ the Pattern (regexp = "^ [\ \ u4E00 - \ \ u9FA5A - Za - z0-9 \ \ *] * $", message =" user nickname restrictions: A maximum of 20 characters including characters, letters and digits ") private String username; / cell phone number * * * * / @ NotBlank (message = "mobile phone number can't be empty") @ the Pattern (regexp = "^ [1] [3,4,5,6,7,8,9] [0-9] {9} $", message =" phone number format is wrong," groups = {Create.class, Update.class}) private String mobile; /** ** private String sex; /** * Email */ @notblank (message = "Email cannot be empty ") @email (message =" Email format is incorrect ") private String Email; /** * password */ private String password; /*** createTime */ @future (message = "createTime ", groups = {create.class}) private Date createTime; }Copy the code

Note: Plus the extend as far as possible when statement grouping javax.mail. Validation. Groups. The Default or in your statement @ Validated (Update. Class), Groups = {default.class} = @email (message = “mailbox format is incorrect “);

5. Restful Usage

When verifying multiple parameters or in the @RequestParam format, add @ “Validated” to the controller

@getMapping ("/get") public RspDTO getUser(@requestParam ("userId") @notnull (message = "userId cannot be null ") Long userId) {User user = userService.selectById(userId); If (user == null) {return new RspDTO< user >(). } return new RspDTO<User>().success(user); }Copy the code
@RestController @RequestMapping("user/") @Validated public class UserController extends AbstractController { .... Saint Lo code...Copy the code

conclusion

It is very simple to use, soEasy, focus on the unified structure return, unified parameter verification, is a magic weapon to reduce our code a lot of try catch, I think in the project, to handle exceptions well, and do the exception log management, is a good upgrade, the article is simple, just a rookie advanced note… .

Here is just personal opinion, technical dishes, welcome big guy to give advice…

# # # recommended reading * * [Java notes daqo. Md] (https://github.com/MarkerHub/JavaIndex/blob/master/README.md) * * [is too great, the Java web site, what project has! https://markerhub.com](https://markerhub.com) [This B station UP master, speak Java really good!] (https://space.bilibili.com/13491144) [cool! Latest version of Java programming ideas can see online!] (https://mp.weixin.qq.com/s/jGEkHTf2X8l-wUenc-PpEw)Copy the code