0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

SpringBoot参数验证的10个技巧2

jf_78858299 来源:JAVA旭阳 作者:JAVA旭阳 2023-04-07 15:11 次阅读

5 将 i18n 用于错误消息

如果你的应用程序支持多种语言,则必须使用国际化 (i18n) 以用户首选语言显示错误消息。

以下是在 Spring Boot 应用程序中使用 i18n 处理错误消息的示例

  1. 首先,在资源目录下创建一个包含默认错误消息的 messages.properties 文件
# messages.properties
user.name.required=Name is required.
user.email.invalid=Invalid email format.
user.age.invalid=Age must be a number between 18 and 99.
  1. 接下来,为每种支持的语言创建一个 messages_xx.properties 文件,例如,中文的 messages_zh_CN.properties
user.name.required=名称不能为空.
user.email.invalid=无效的email格式.
user.age.invalid=年龄必须在1899岁之间.
  1. 然后,更新您的验证注释以使用本地化的错误消息
public class User {
    @NotNull(message = "{user.id.required}")
    private Long id;

    @NotBlank(message = "{user.name.required}")
    private String name;

    @Email(message = "{user.email.invalid}")
    private String email;

    @NotNull(message = "{user.age.required}")
    @Min(value = 18, message = "{user.age.invalid}")
    @Max(value = 99, message = "{user.age.invalid}")
    private Integer age;
}
  1. 最后,在 Spring 配置文件中配置 MessageSource bean 以加载 i18n 消息文件
@Configuration
public class AppConfig {
    @Bean
    public MessageSource messageSource() {
        ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
        messageSource.setBasename("messages");
        messageSource.setDefaultEncoding("UTF-8");
        return messageSource;
    }

    @Bean
    public LocalValidatorFactoryBean validator() {
        LocalValidatorFactoryBean validatorFactoryBean = new LocalValidatorFactoryBean();
        validatorFactoryBean.setValidationMessageSource(messageSource());
        return validatorFactoryBean;
    }
}
  1. 现在,当发生验证错误时,错误消息将根据随请求发送的“Accept-Language”标头以用户的首选语言显示。

6 使用分组验证

验证组是 Spring Boot 验证框架的一个强大功能,允许您根据其他输入值或应用程序状态应用条件验证规则。

现在有一个包含三个字段的User类的情况下:firstNamelastNameemail。我们要确保如果 email 字段为空,则 firstNamelastName 字段必须非空。否则,所有三个字段都应该正常验证。

为此,我们将定义两个验证组:EmailNotEmptyDefaultEmailNotEmpty 组将包含当 email 字段不为空时的验证规则,而 Default 组将包含所有三个字段的正常验证规则。

  1. 创建带有验证组的 User
public class User {
    @NotBlank(groups = Default.class)
    private String firstName;

    @NotBlank(groups = Default.class)
    private String lastName;

    @Email(groups = EmailNotEmpty.class)
    private String email;

    // getters and setters omitted for brevity
    public interface EmailNotEmpty {}
    public interface Default {}
}
  • 请注意,我们在User类中定义了两个接口EmailNotEmptyDefault。这些将作为我们的验证组。
  1. 接下来,我们更新Controller使用这些验证组
@RestController
@RequestMapping("/users")
@Validated
public class UserController {
    public ResponseEntity<String> createUser(
            @Validated({org.example.model.ex6.User.EmailNotEmpty.class}) @RequestBody User userWithEmail,
            @Validated({User.Default.class}) @RequestBody User userWithoutEmail)
    {
        // Create the user and return a success response
       
    }
}
  • 我们已将@Validated注释添加到我们的控制器,表明我们想要使用验证组。我们还更新了 createUser 方法,将两个 User 对象作为输入,一个在 email 字段不为空时使用,另一个在它为空时使用。
  • @Validated 注释用于指定将哪个验证组应用于每个 User 对象。对于 userWithEmail 参数,我们指定了 EmailNotEmpty 组,而对于 userWithoutEmail 参数,我们指定了 Default 组。
  1. 进行这些更改后,现在将根据“电子邮件”字段是否为空对“用户”类进行不同的验证。如果为空,则 firstNamelastName 字段必须非空。否则,所有三个字段都将正常验证。

7 对复杂逻辑使用跨域验证

如果需要验证跨多个字段的复杂输入规则,可以使用跨字段验证来保持验证逻辑的组织性和可维护性。跨字段验证可确保所有输入值均有效且彼此一致,从而防止出现意外行为。

假设我们有一个表单,用户可以在其中输入任务的开始日期和结束日期,并且我们希望确保结束日期不早于开始日期。我们可以使用跨域验证来实现这一点。

  1. 首先,我们定义一个自定义验证注解EndDateAfterStartDate
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = EndDateAfterStartDateValidator.class)
public @interface EndDateAfterStartDate {
    String message() default "End date must be after start date";
    Class?[] groups() default {};
    Class? extends Payload[] payload() default {};
}
  1. 然后,我们创建验证器EndDateAfterStartDateValidator
public class EndDateAfterStartDateValidator implements ConstraintValidator<EndDateAfterStartDate, TaskForm> {
    @Override
    public boolean isValid(TaskForm taskForm, ConstraintValidatorContext context) {
        if (taskForm.getStartDate() == null || taskForm.getEndDate() == null) {
            return true;
        }

        return taskForm.getEndDate().isAfter(taskForm.getStartDate());
    }
}
  1. 最后,我们将EndDateAfterStartDate注释应用于我们的表单对象TaskForm
@EndDateAfterStartDate
public class TaskForm {
    @NotNull
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private LocalDate startDate;

    @NotNull
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private LocalDate endDate;
}

现在,当用户提交表单时,验证框架将自动检查结束日期是否晚于开始日期,如果不是,则提供有意义的错误消息。

8 对验证错误使用异常处理

可以使用异常处理ExceptionHandler来统一捕获和处理验证错误。

以下是如何在 Spring Boot 中使用异常处理来处理验证错误的示例:

@RestControllerAdvice
public class RestExceptionHandler extends ResponseEntityExceptionHandler {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex,
                                                                  HttpHeaders headers, HttpStatus status,
                                                                  WebRequest request) {
        Map<String, Object> body = new LinkedHashMap<>();
        body.put("timestamp", LocalDateTime.now());
        body.put("status", status.value());

        // Get all errors
        List<String> errors = ex.getBindingResult()
                .getFieldErrors()
                .stream()
                .map(x -> x.getDefaultMessage())
                .collect(Collectors.toList());

        body.put("errors", errors);

        return new ResponseEntity<>(body, headers, status);
    }
}

在这里,我们创建了一个用 @RestControllerAdvice 注解的 RestExceptionHandler 类来处理我们的 REST API 抛出的异常。然后我们创建一个用@ExceptionHandler注解的方法来处理在验证失败时抛出的 MethodArgumentNotValidException

在处理程序方法中,我们创建了一个 Map 对象来保存错误响应的详细信息,包括时间戳、HTTP 状态代码和错误消息列表。我们使用 MethodArgumentNotValidException 对象的 getBindingResult() 方法获取所有验证错误并将它们添加到错误消息列表中。

最后,我们返回一个包含错误响应详细信息的ResponseEntity对象,包括作为响应主体的错误消息列表、HTTP 标头和 HTTP 状态代码。

有了这个异常处理代码,我们的 REST API 抛出的任何验证错误都将被捕获并以结构化和有意义的格式返回给用户,从而更容易理解和解决问题。

9 测试你的验证逻辑

需要为你的验证逻辑编写单元测试,以帮助确保它正常工作。

@DataJpaTest
public class UserValidationTest {

    @Autowired
    private TestEntityManager entityManager;

    @Autowired
    private Validator validator;

    @Test
    public void testValidation() {
        User user = new User();
        user.setFirstName("John");
        user.setLastName("Doe");
        user.setEmail("invalid email");

        Set

我们使用 JUnit 5 编写一个测试来验证具有无效电子邮件地址的“用户”对象。然后我们使用 Validator 接口来验证 User 对象并检查是否返回了预期的验证错误。

10 考虑客户端验证

客户端验证可以通过向用户提供即时反馈并减少对服务器的请求数量来改善用户体验。但是,不应依赖它作为验证输入的唯一方法。客户端验证很容易被绕过或操纵,因此必须在服务器端验证输入,以确保安全性和数据完整性。

总结

有效的验证对于任何 Web 应用程序的稳定性和安全性都是必不可少的。Spring Boot 提供了一套工具和库来简化验证逻辑并使其更易于维护。通过遵循本文中讨论的最佳实践,您可以确保您的验证组件有效并提供出色的用户体验。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 应用程序
    +关注

    关注

    37

    文章

    3136

    浏览量

    56391
  • spring
    +关注

    关注

    0

    文章

    332

    浏览量

    14161
  • Boot
    +关注

    关注

    0

    文章

    142

    浏览量

    35244
  • SpringBoot
    +关注

    关注

    0

    文章

    172

    浏览量

    106
收藏 人收藏

    评论

    相关推荐

    SpringBoot配置Mybatis的2错误和修正

    SpringBoot】配置Mybatis错误
    发表于 04-19 10:31

    SpringBoot中的Druid介绍

    SpringBoot中Druid数据源配置
    发表于 05-07 09:21

    SpringBoot知识总结

    SpringBoot干货学习总结
    发表于 08-01 10:40

    springboot spring data jpa使用总结

    【本人秃顶程序员】springboot专辑:spring data jpa的使用
    发表于 04-15 11:38

    一文解析SpringBoot2整合SSM框架

    SpringBoot2整合SSM框架详解
    发表于 06-09 16:43

    怎么学习SpringBoot

    SpringBoot学习之路(X5)- 整合JPA
    发表于 06-10 14:52

    springboot集成mqtt

    springboot集成mqtt,大纲一.数据入库1.数据入库解决方案二.开发实时订阅发布展示页面1.及时通讯技术2.技术整合
    发表于 07-16 07:53

    怎样去使用springboot

    怎样去使用springboot呢?学习springboot需要懂得哪些?
    发表于 10-25 07:13

    SpringBoot应用启动运行run方法

    什么时候创建嵌入式的Servlet容器工厂?什么时候获取嵌入式的Servlet容器并启动Tomcat;获取嵌入式的Servlet容器工厂:1)、SpringBoot应用启动运行run方法2
    发表于 12-20 06:16

    怎样去设计一基于springboot+freemark+jpa+MySQL的在线电影订票系统

    实现的功能有:前台: 1、正在上映的电影浏览查看,可在线播放预告视频。 2、影院信息浏览查看,包括各影院上映场次数。 3、新闻咨询信息浏览查看。 4、地域信息查看切换。 5、用户注册登录,登录支持发送短信验证码登录和...
    发表于 01-03 07:22

    怎样去设计一基于java ssm springboot的女士电商平台系统

    java ssm springboot女士电商平台10(源码+sql+论文可运行)主要设计:登录、注册、商品浏览、分类管理、模糊查找、轮播图、热销商品、购物车、订单、订单流程控制、用户管理、修改密码
    发表于 01-03 06:14

    什么是 SpringBoot

    本文从为什么要有 `SpringBoot`,以及 `SpringBoot` 到底方便在哪里开始入手,逐步分析了 `SpringBoot` 自动装配的原理,最后手写了一个简单的 `start` 组件,通过实战来体会了 `
    的头像 发表于 04-07 11:28 1026次阅读
    什么是 <b class='flag-5'>SpringBoot</b>?

    SpringBoot的核心注解1

    今天跟大家来探讨下SpringBoot的核心注解@SpringBootApplication以及run方法,理解下springBoot为什么不需要XML,达到零配置
    的头像 发表于 04-07 14:34 491次阅读
    <b class='flag-5'>SpringBoot</b>的核心注解1

    SpringBoot的核心注解2

    今天跟大家来探讨下SpringBoot的核心注解@SpringBootApplication以及run方法,理解下springBoot为什么不需要XML,达到零配置
    的头像 发表于 04-07 14:34 1751次阅读
    <b class='flag-5'>SpringBoot</b>的核心注解2

    SpringBoot参数验证10个技巧1

    参数验证很重要,是平时开发环节中不可少的一部分,但是我想很多后端同事会偷懒,干脆不错,这样很可能给系统的稳定性和安全性带来严重的危害。那么在Spring Boot应用中如何做好参数校验工作呢,本文提供了
    的头像 发表于 04-07 15:10 342次阅读