background

Recently the Dragon Boat Festival for a long time and two fat get together, so about two fat to the people’s square to kill him a meal, just recently he job-hunting salary. <br/>

ITwo fat heard that you recently job-hopping, and still jump from the traditional software company to the Internet company, the salary is not up a little ah, today you treat. <br/>

Two fat: Don’t say it, the salary is a little higher, but the cost performance has become lower, before the point to work, now work home almost 12 o ‘clock. <br/>

IA: How is the new company fitting in? Except for the long hours at work. <br/>

Two fatAh, this is really a little bit uncomfortable, this is not just in no matter what,leaderI was assigned a simple user save function (parameter check). I had spent two or three days in the new company, which had been done in one hour in the previous company. I changed it a couple of times and eventuallyleaderHe nodded his head with satisfaction.

Interface streaking

  • According to the two fat in the previous company writing method and the traditional company anyway, the system is the service of the internal staff, write parameter verification is not a thing at the back end, completely trust the content of the front end. This is not written code self-test a found that can save data, on the fart of the initiated codereviewTwo fat in the previous company codereviewIt does not exist, as long as the function is implemented). justleaderI have some time today to see the code submitted by my new colleagues and see how it is written. Look at this streaking interface,leaderTwo fat call in the past, earnest language long of with two fat say: “you this parameter check not to write? Aren’t you afraid people will attack your interface? No validation, just use it. Aren’t you afraid to introduce SQL injection? I don’t want to check if the mailbox is formatted? This sentence empty also do not write, not afraid of a large number of empty Pointers, the service fuse? …” . In the face ofleaderOf desperately 13 ask, 2 fat wish probation to be afraid to be a little sad? Can only lower the head to return to the station to followleaderThe education was rectified, and then resubmitted.

Parameter check if judgment

The leader took a look and said, “The code this time is much better than last time, and the function is basically fine. But can this piece of code be optimized? It’s not very elegant to write this way.”

If (objects.isNull (user)){throw new IllegalArgumentException(" user cannot be null "); } if(StringUtils.IsEmpty (User.getUserName ())){throw new IllegalArgumentException(" Username cannot be empty "); } if(StringUtils.IsEmpty (User.getUserName ())){throw new IllegalArgumentException(" Username cannot be empty "); } if(StringUtils.IsEmpty (User.getSex ())){throw new IllegalArgumentException(" User gender cannot be empty "); } if(objects.isNull (User.getUserDetail ())){throw New IllegalArgumentException(" User details cannot be empty "); } if(objects.isNull (User.getUserDetail ().getAddress())){throw new IllegalArgumentException(" User address cannot be empty "); } if(!" M".equals(user.getSex()) && !" F".equals(User.getSex ())){throw new IllegalArgumentException(" User gender is not valid "); }

Two fat is also a burst of depression, or miss the former company ah, function realization is good, code want how to write how to write. Internet companies are rules, write code to write a single test, but also to monitor a bunch of broken things, deserve this group of people. Time is spent on that. You should complain but the code needs to be changed. It’s hard to find a job during this epidemic and I can’t lose it. Two dogs think of before is not learned AOP? Then with a custom annotation, so the code should be more elegant, said to do it.

Custom annotation implementation

  • First I customize an annotation because I want to validate the parameters
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.METHOD})
public @interface ParameterValidator {

}
  • Configure a section, which resolvesParameterValidatorThe method of annotation.

It then gets all the requested parameters through the facets, and after getting the parameters, the annotations above the parameters are parsed. Configuring the facets is easy, but the reflection parsing parameter is a bit more complicated, because it involves the nested structure of the request parameter. Two fat habitually oriented baidu programming can copy the code of others determined not to write their own. Baidu is basically out of the single-layer structure, simple basic types of objects, not involved in the type of nested, cascaded taste parameters. Finally, I looked around on GitHub, but I couldn’t find a suitable one. Since bring doctrine no result that can only hum hum of their own write, fortunately, they have learned the knowledge of reflection. Took an hour to write a rough version with recursive calls, which was pretty rough and there were a lot of scenarios I didn’t take into account. However, it can meet the conditions. Part of the code is as follows:

public static void checkField(Object object, Class<? > aClass) throws IllegalAccessException { boolean primitive = isPrimitive(aClass); if (primitive) { return; } Field[] declaredFields = filterField(aClass.getDeclaredFields()); for (Field field : declaredFields) { makeAccessible(field); // verify our custom annotation myNotBlank FieldAnnotation = field.getAnnotation(myNotBlank. Class); Object currentObject = field.get(object); if (Objects.nonNull(fieldAnnotation)) { if (StringUtils.isEmpty(currentObject)) { throw new IllegalArgumentException(field.getName()+":"+fieldAnnotation.message()); } } if (! IsJavaClass (field.getType())) {// CheckField (currentObject) when cascading arguments are present; } else if (field.getType().isPrimitive()) {} else if (field.getType().isAssignableFrom(list.class)) {// Recursive, GetList (Field, CurrentObject); }}}

Then quickly test a wave, it is good to achieve the basic function, can realize the null test, can also achieve the cascade check. The effect is as follows:



However, this one now supports primitive types andString,Listthe

Then if the parameter type is array, orMapAnd so on and so forth. At this time, two dogs from the side of the colleague, see two fat so seriously in the code. <br/>

Two dogsTwo fat what are you writingbugAh. <br/>

Two fat: Build your own wheel and write a general parameter check. <br/>

Two dogs: Isn’t there already a solution for this on the market?jsr(Java Specification Requests)You can go to know about it. <br/>

Two fatB: OK. I’ll check the information right away.

Java Specification Requests (JSR

  • When it comes tojsrWe need to know what isJCP (Java Community Process)?

The JCP (Java Community Process) is an open international organization, mainly composed of Java developers and licensees, whose function is development and renewal.

  • What is a JSR?

It is a formal request to the JCP to add a standardized technical specification. Anyone can submit a JSR (you can submit one if you feel awesome).


To add new APIs and services to the Java platform. The JSR has become an important standard in the Java world.

Bean Validation

Bean Validation is, as the name implies, a Validation for Java beans. So far, there are three specifications for validating beans in Java.

  • JSR-303 : Bean Validation
  • JSR 349: Bean Validation 1.1
  • JSR 380: Bean Validation 2.0

Hibernate-Validator

Hibernate Validator is the reference implementation for Bean Validation. The Hibernate Validator provides the implementation of all the built-in constraints in the JSR 303 specification. In addition, there are some additional constraints.

Code implementation

  • If the framework of the project is Spring Boot, the dependencies of Hibernate- Validator are already included in the spring-boot-starter-web (Version must be prior to 2.3).2.3Later versionspring-boot-starter-webThis dependency has been removed and needs to be introduced manuallyHibernate-validatorDependencies, see detailsWebsite description
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-validation</artifactId>
</dependency>
  • nonspringbootProject words are directly introduced
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> < version > 6.0.17. Final < / version > < / dependency >

Code: The @Valid annotation before the method is required, otherwise it will not be Valid.

    @PostMapping(value = "/save2")
    @ResponseBody
    public ResultViewModel save2(@Valid @RequestBody User user){
        boolean saveUser = saveUser(user);
        if (saveUser) {
            return ResultViewModelUtil.success();
        }
        return ResultViewModelUtil.error();
    }

Entity classes are annotated with rules that need to be validated.

// The value of an annotated element must be a string, not null, and the length must be greater than 0 @NotBlank(message = "") after the trim() call. @NotNull(message = "") // AnnotNull cannot be the value of an annotated element, and the length must be greater than 0. Typically used above the collection class @notempty (message = "") // The annotated element must conform to the specified regular expression. @Pattern(regexp = "", message = "") // The size of the annotated element must be within the specified range. @Size(min =, Max =) @Size(min =, Max =) @Size(min =, Max =) @Size(min =, Max =) @Size(min =, Max =) @Size(min =, Max =) @Size(min =, Max =) @Size(min =, Max =) @Size(min =, Max =) @Size(min =, Max =) @Size(min =, Max =)) @Size(min =, Max =) @Size(min =, Max =) And the value must be less than or equal to the specified maximum @Max(value = value within long, message = "") // The commented element, the value must be a number, The value must be greater than or equal to the specified minimum @Decimalmin (value = can be a decimal, message = "") // The annotated element, the value must be a number, The value must be less than or equal to the specified maximum @DecimalMax(value = can be a decimal, message = "") // The annotated element must be NULL @NULL (message = "") // The annotated element must be a number, @Digits(Integer =, Fraction =) @Digits(Integer =, Fraction =) @Digits(Integer =, Fraction =) @Digits(Integer =, Fraction =) @Digits(Integer =, Fraction =) Value must be false @assertfalse (message = "") // The annotated element must be a Past date @past (message = "") // The annotated element must be a Future date @future (message = "") // The annotated element must be @Email(regexp = "", message = "") // The annotated element must be in the appropriate Range @Range(min =, Max =, Message = "") // The size of the annotated string must be in the specified range @length (min =, Max =, message = "")

The only thing you have to be careful about is if it’s a cascading check you have to put it in the outermost layer@Valid

Why do I need to mark the last time I check@ValidThis annotation, the validation inside the column will be valid, right? Have to know or interested in can go to see the source code to give me a message oh.



After configuring a global exception catcher, the code is not posted due to space, and the code is uploadedgithubOn.

Verification results:

conclusion

  • Hibernate-ValidatorYou can also customize the annotation implementation.
  • Group validation is also possible (there is a scenario where new user information is added without validationuserId(because the system is generated); You need to verify when you modify ituserId, at which point the user is availablevalidatorGroup verification function of the
  • If the project is notspringbootOf, such as the use of isJfinal framework(This is a domestic framework that most people don’t know), orsoaHow can columns be used when invoking parameter validation?
  • More gestures you are interested in can go to the official website to unlock Oh, but the daily development of the above introduction can basically meet the needs.
  • Two fat see this richapi“, and the simple use of stir-fried chicken. I quickly deleted the wheel I wrote and replaced it with this oneHibernate-ValidatorFramework. After resubmitting the modification,leaderHis face finally showed a satisfied smile.
  • The project address

The end of the

  • Due to their lack of talent and knowledge, it is inevitable that there will be mistakes, if you find the wrong place, but also hope to leave a message to me to point out, I will correct it.
  • If you think the article is good, your retweet, share, compliment, thumb up, comment is the biggest encouragement to me.
  • Thank you for reading, welcome and thank you for your attention.

Refer to http://docs.jboss.org/hiberna… (website, Chinese version close) https://docs.jboss.org/hibern… https://juejin.im/post/5dd8d4… https://www.cnblogs.com/mr-ya…