文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

怎么通过自定义spring invalidator注解校验数据合法性

2023-07-02 15:24

关注

今天小编给大家分享一下怎么通过自定义spring invalidator注解校验数据合法性的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

自定义spring invalidator注解校验数据合法性

在项目中经常会对用户输入的数据,或者外部导入到系统的数据做合法性检查。在spring boot框架的微服务中可以使用invalidator注解对数据做合法性,安全性校验。

下面给一个样例说明如何自定义注解实现校验逻辑。

1、定义校验属性字符串长度的注解

package com.elon.springbootdemo.manager.invalidator;import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;import javax.validation.Constraint;import javax.validation.Payload;@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@Constraint(validatedBy = FieldLengthInvalidatorImpl.class)@Documentedpublic @interface FieldLengthInvalidator {    // 字段支持的最大长度(字符数)    int maxLength() default 50;    // 校验失败后返回的错误信息    String message() default "";    // 分组    Class<?>[] groups() default {};    // 负载    Class<? extends Payload>[] payload() default {};}

在定义注解时可声明变量用于辅助校验。上面的注解中定义了maxLength变量用于指定最大长度限制。变量可以设置默认值,使用注解时不传参数,变量就使用默认值。

2、实现校验逻辑,校验失败后返回错误提示

package com.elon.springbootdemo.manager.invalidator;import javax.validation.ConstraintValidator;import javax.validation.ConstraintValidatorContext;public class FieldLengthInvalidatorImpl implements ConstraintValidator<FieldLengthInvalidator, String> {    private int maxLength = 0;    @Override    public void initialize(FieldLengthInvalidator invalidator) {        maxLength = invalidator.maxLength();    }    @Override    public boolean isValid(String fieldValue, ConstraintValidatorContext context) {        if (fieldValue.length() > maxLength) {            context.disableDefaultConstraintViolation();            context.buildConstraintViolationWithTemplate("对象属性长度超过限制。").addConstraintViolation();            // 校验失败返回false。返回true上游收集不到错误信息。            return false;        }        return true;    }}

3、在模型字段属性上增加校验的注解

public class User{    private int userId = -1;    @FieldLengthInvalidator(maxLength=10)    private String name = "";}

4、提供统一的校验方法

package com.elon.springbootdemo.manager;import java.util.ArrayList;import java.util.List;import java.util.Set;import javax.validation.ConstraintViolation;import javax.validation.Validation;import javax.validation.Validator;import javax.validation.ValidatorFactory;public class InvalidatorMgr {    private InvalidatorMgr() {            }            public static InvalidatorMgr instance() {        return InvalidatorMgrBuilder.instance;    }            public <T> List<String> validate(T model) {                ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();        Validator validator = validatorFactory.getValidator();        Set<ConstraintViolation<T>> resultSet = validator.validate(model);                List<String> messageList = new ArrayList<>();        resultSet.forEach((r)->messageList.add(r.getMessage()));                return messageList;    }            private static class InvalidatorMgrBuilder{        private static InvalidatorMgr instance = new InvalidatorMgr();    }}

5、业务层调用校验方法

        User user = new User();        user.setName("ahskahskhqlwjqlwqlwhqlhwlqjwlqhwlhqwhqlwjjqlwl");        List<String> messageList = InvalidatorMgr.instance().validate(user);        System.out.println(messageList);

invalidator注解主要用于实现长度,范围,非法字符等通用的规则校验。不适合用于做业务逻辑的校验,特定的业务校验写在业务层。 

springboot 参数验证 validation

1、综述

springboot提供了强大的基于注解的、开箱即用的验证功能,这种基于bean validation的实现和 hibernate validator类似

2、依赖

创建springboot项目,包含以下依赖

<dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-web</artifactId></dependency><dependency>     <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-data-jpa</artifactId></dependency> <dependency>     <groupId>com.h3database</groupId>     <artifactId>h3</artifactId>    <version>1.4.197</version>     <scope>runtime</scope></dependency>

3、定义实体类

测试项目为了方便,直接用JPA,使用@NotBlank指定非空字段,message是验证触发后返回的信息,还有@Null、@NotNull、@NotBlank、@Email、@Max、@Min、@Size、@Negative、@DecimalMax、@DecimalMin、@Positive、@PositiveOrZero、@NegativeOrZero、@AssertTrue、@AssertFalse、@Future、@FutureOrPresent、@Past、@PastOrPresent、@Pattern

@Entitypublic class User {        @Id    @GeneratedValue(strategy = GenerationType.AUTO)    private long id;         @NotBlank(message = "Name is mandatory")    private String name;         @NotBlank(message = "Email is mandatory")    private String email;        // standard constructors / setters / getters / toString        }

创建JPA的repository定义增删改查接口

@Repositorypublic interface UserRepository extends CrudRepository<User, Long> {}

4、创建rest controller

@RestControllerpublic class UserController {     @PostMapping("/users")    ResponseEntity<String> addUser(@Valid @RequestBody User user) {        // persisting the user        return ResponseEntity.ok("User is valid");    }         // standard constructors / other methods     }

接收到的user对象添加了@Valid,当Spring Boot发现带有@Valid注解的参数时,会自动引导默认的JSR 380验证器验证参数。当目标参数未能通过验证时,Spring Boot将抛出一个MethodArgumentNotValidException

5、实现ExceptionHandler

直接抛出异常显然是不合理的,大部分情况需要经过处理返回给前端更友好的提示信息,通过@ExceptionHandler来处理抛出的异常实现该功能

@ResponseStatus(HttpStatus.BAD_REQUEST)@ExceptionHandler(MethodArgumentNotValidException.class)public Map<String, String> handleValidationExceptions(  MethodArgumentNotValidException ex) {    Map<String, String> errors = new HashMap<>();    ex.getBindingResult().getAllErrors().forEach((error) -> {        String fieldName = ((FieldError) error).getField();        String errorMessage = error.getDefaultMessage();        errors.put(fieldName, errorMessage);    });    return errors;}

MethodArgumentNotValidException作为上一步抛出的异常,当springboot执行validition触发时会调用此实现,该方法将每个无效字段的名称和验证后错误消息存储在映射中,然后它将映射作为JSON表示形式发送回客户端进行进一步处理。

6、写测试代码

使用springboot自带的插件进行测试rest controller,

@RunWith(SpringRunner.class) @WebMvcTest@AutoConfigureMockMvcpublic class UserControllerIntegrationTest {     @MockBean    private UserRepository userRepository;         @Autowired    UserController userController;     @Autowired    private MockMvc mockMvc;     //...     }

@WebMvcTest允许我们使用MockMvcRequestBuilders和MockMvcResultMatchers实现的一组静态方法测试请求和响应。测试addUser()方法,在请求体中传递一个有效的User对象和一个无效的User对象。

@Testpublic void whenPostRequestToUsersAndValidUser_thenCorrectResponse() throws Exception {    MediaType textPlainUtf8 = new MediaType(MediaType.TEXT_PLAIN, Charset.forName("UTF-8"));    String user = "{\"name\": \"bob\", \"email\" : \"bob@domain.com\"}";    mockMvc.perform(MockMvcRequestBuilders.post("/users")      .content(user)      .contentType(MediaType.APPLICATION_JSON_UTF8))      .andExpect(MockMvcResultMatchers.status().isOk())      .andExpect(MockMvcResultMatchers.content()        .contentType(textPlainUtf8));} @Testpublic void whenPostRequestToUsersAndInValidUser_thenCorrectResponse() throws Exception {    String user = "{\"name\": \"\", \"email\" : \"bob@domain.com\"}";    mockMvc.perform(MockMvcRequestBuilders.post("/users")      .content(user)      .contentType(MediaType.APPLICATION_JSON_UTF8))      .andExpect(MockMvcResultMatchers.status().isBadRequest())      .andExpect(MockMvcResultMatchers.jsonPath("$.name", Is.is("Name is mandatory")))      .andExpect(MockMvcResultMatchers.content()        .contentType(MediaType.APPLICATION_JSON_UTF8));    }}

也可以使用postman或fiddler来测试REST controller API。

7、跑测试

@SpringBootApplicationpublic class Application {         public static void main(String[] args) {        SpringApplication.run(Application.class, args);    }         @Bean    public CommandLineRunner run(UserRepository userRepository) throws Exception {        return (String[] args) -> {            User user1 = new User("Bob", "bob@domain.com");            User user2 = new User("Jenny", "jenny@domain.com");            userRepository.save(user1);            userRepository.save(user2);            userRepository.findAll().forEach(System.out::println);        };    }}

如果用没有用户名或邮箱的数据发送请求会收到返回的提示信息

{  "name":"Name is mandatory",  "email":"Email is mandatory"}

以上就是“怎么通过自定义spring invalidator注解校验数据合法性”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注编程网行业资讯频道。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     801人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     348人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     311人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     432人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     220人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯