[spring] Spring MVC Thymeleaf(下)

2024-06-23 11:44
文章标签 java spring mvc thymeleaf

本文主要是介绍[spring] Spring MVC Thymeleaf(下),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

[spring] Spring MVC & Thymeleaf(下)

上篇笔记讲了一下怎么使用 thymeleaf 作为 HTML 模板,与 Spring MVC 进行沟通,这里主要说一下验证的部分

常用表单验证

一些 Spring MVC 内置的常用验证注解如下:

AnnotationDescription
@NotNullEnsures the annotated field is not null.
@NotEmptyEnsures the annotated field is not empty. This applies to Strings, Collections, Maps, and arrays.
@NotBlankEnsures the annotated string field is not null or empty.
@SizeValidates that the annotated field has a size within the specified bounds.
@MinValidates that the annotated field has a value no smaller than the specified minimum.
@MaxValidates that the annotated field has a value no larger than the specified maximum.
@EmailValidates that the annotated field is a valid email address.
@PatternValidates that the annotated field matches the specified regular expression.
@PastValidates that the annotated field contains a date in the past.
@FutureValidates that the annotated field contains a date in the future.
@PositiveValidates that the annotated field is a positive number.
@PositiveOrZeroValidates that the annotated field is a positive number or zero.
@NegativeValidates that the annotated field is a negative number.
@NegativeOrZeroValidates that the annotated field is a negative number or zero.
@DigitsValidates that the annotated field is a number within the specified integer and fraction digits.
@DecimalMinValidates that the annotated field is a decimal number no smaller than the specified minimum.
@DecimalMaxValidates that the annotated field is a decimal number no larger than the specified maximum.
@AssertTrueValidates that the annotated field is true.
@AssertFalseValidates that the annotated field is false.
@CreditCardNumberValidates that the annotated field is a valid credit card number.

这个列表只是做个参考,具体用法大同小异,后面会选几个比较常用的实现一下,以及会实现自定义验证

设置开发环境

依旧从 spring.io 下载,具体配置如下:

在这里插入图片描述

和上里的内容比起来,这里多了一个 Validator

必填选项

这里的实现步骤如下:

  1. 创建一个 DAO,并添加验证规则

    实现代码如下:

    package com.example.springdemo.mvc;import jakarta.validation.constraints.NotNull;
    import jakarta.validation.constraints.Size;
    import lombok.Data;@Data
    public class Customer {private String firstName;@NotNull(message = "is required")@Size(min = 1, message = "is required")private String lastName;
    }

    ⚠️:这里的 @NotNull@Size 是从 jakarta.validation.constraints 中导入的。这里的 message 就是验证失败后,会返回的错误信息

    👀:这里其实有一个小问题,就是如果用户提供的数据是空的字符串,那么也是可以通过验证的。空字符串的处理在后面会提到

  2. 添加 controller

    package com.example.springdemo.mvc;import jakarta.validation.Valid;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.validation.BindingResult;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.ModelAttribute;
    import org.springframework.web.bind.annotation.PostMapping;@Controller
    public class CustomerController {@GetMapping("/")public String showForm(Model model) {model.addAttribute("customer", new Customer());return "customer-form";}@PostMapping("/processForm")public String processForm(@Valid @ModelAttribute("customer") Customer customer,BindingResult bindingResult) {if (bindingResult.hasErrors()) {return "customer-form";}return "customer-confirmation";}
    }

    这里其实直接把第 4 步也做了,后面会具体提一下实现的功能

  3. 添加 HTML 和验证支持

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org"><head><meta charset="UTF-8" /><title>Customer Registration Form</title><style>.error {color: red;}</style></head><body><i>Fill out the form</i><br /><br /><formth:action="@{/processForm}"th:object="${customer}"method="post"autocomplete="off"><label>First Name:<input type="text" th:field="*{firstName}" /></label><br /><br /><label>Last Name (*):<input type="text" th:field="*{lastName}" /></label><!--  add error message (if present)  --><spanth:if="#{fields.hasErrors('lastName')}"th:errors="*{lastName}"class="error"></span><br /><br /><input type="submit" value="Submit" /></form><script src="http://localhost:35729/livereload.js"></script></body>
    </html>
    

    这里的代码和之前实现的 thymeleaf 没有什么特别大的区别,唯一的差别在于用于显示错误信息的 span 这部分

    th:if 的用法之前已经提过,这里不多赘述

    #fields 是一个内置的工具对象,可以用来检查哪个属性有错。在这个情况下,它会检查 lastName 是否验证失败

    th:errors="*{lastName}" 是一个没见过的 thymeleaf 语法,这里主要就是将报错信息渲染到 DOM 中

    class="error" 用于添加 css

  4. 在 controller 中实现验证

    @PostMapping("/processForm")public String processForm(@Valid @ModelAttribute("customer") Customer customer,BindingResult bindingResult) {if (bindingResult.hasErrors()) {return "customer-form";}return "customer-confirmation";}
    

    这里着重讲一下这部分的代码

    @Valid 注解代表 customer 对象包含验证需要被执行,这也是在 DAO 层中,在 lastName 上添加的验证

    BindingResult bindingResult 也是通过依赖注入获取的,这个对象会绑定所有的验证结果

  5. 创建 confirm 页面

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org"><head><meta charset="UTF-8" /><title>Customer Confirmation</title></head><body>The customer is confirmed:<span th:text="${customer.firstName + ' ' + customer.lastName}"></span><script src="http://localhost:35729/livereload.js"></script></body>
    </html>
    

    这部分没什么特殊的,之前已经写过很多遍了

具体的实现效果如下:

在这里插入图片描述

@InitBinder

上面的实现中,如果用户输入空白的字符串,那么也会通过检查。因此这里会使用 @InitBinder 去对数据进行一个自定义处理(预处理)

具体的使用方式如下:

public class CustomerController {@InitBinderpublic void initBinder(WebDataBinder dataBinder) {StringTrimmerEditor stringTrimmerEditor = new StringTrimmerEditor(true);dataBinder.registerCustomEditor(String.class, stringTrimmerEditor);}
}

这部分其实没有什么特别复杂的,WebDataBinder 是一个数据绑定器,传入的参数也是需要处理的数据类型,与处理的方式。如这里的实现就是对所有输入的字符串进行一个处理,处理的方式就是将空格去除

需要注意的就是,这部分的代码需要在 controller 中实现,这里的代码就是在 CustomerController 中实现的

@Min & @Max

@Min & @Max 也是两个常见的对数字进行的验证,实现方法如下:

@Data
public class Customer {@Min(value = 0, message = "must be greater than or equals to 0")@Max(value = 10, message = "must be smaller than or equals to 10")private int freePasses;
}

这里不需要修改 controller,HTML 模板的修改部分如下:

<label>Free passes:<input type="text" th:field="*{freePasses}" />
</label><!--  add error message (if present)  -->
<spanth:if="#{fields.hasErrors('freePasses')}"th:errors="*{freePasses}"class="error"
></span><br /><br />

实现效果:

在这里插入图片描述

regex,正则

验证同样可以接受正则,这里只做一个比较简单的处理方式,即邮政编码的处理,可以包含数字和大小写字母

DAO 修改如下:

    @Pattern(regexp = "^[a-zA-Z0-9]{5}", message = "only 5 chars/digits")private String postalCode;

同样不需要修改 controller,只需要更新 HTML 模板:

<label>Postal Code<input type="text" th:field="*{postalCode}" />
</label><!--  add error message (if present)  -->
<spanth:if="#{fields.hasErrors('postalCode')}"th:errors="*{postalCode}"class="error"
></span>

这是 confirmation 的修改:

Postal Code: <span th:text="${customer.postalCode}"></span>

显示效果:

在这里插入图片描述

数字的一些问题

@NotNull

数字类型使用使用 @NotNull 会造成一点问题,如:

在这里插入图片描述

这是因为 Java 的数据类型转换问题,其中一个解决方式可以吧声明的 private int freePasses; 换成 private Integer freePasses;,这样 Integer 这个包装类可以自动实现数据转换的处理

在这里插入图片描述

字符串

另一个可能会遇到的问题,就是在处理数字的输入框中输入字符串,如:

在这里插入图片描述

这种情况下,Spring 也是没有办法正常转换类型,这里可以解决的方法是在 resource 文件夹下,新建一个 messages.properties 文件

这是一个特殊的 properties 文件,Spring 会自动扫描并读取这个文件,并可以通过这个文件信息进行处理。除了报错信息外,它也经常被用于 i18n 和 l10n

配置方式如下:

typeMismatch.customer.freePasses=Invalid number

实现效果:

在这里插入图片描述

在这里插入图片描述

⚠️:使用这个配置文件也可以覆盖上面 @NotNull 带来的问题,主要因为空字符串也不是一个合法的数字,所以这个错误也会被 typeMismatch 所捕获

自定义验证

Spring 提供的验证肯定没有办法满足所有的需求,这个情况下就需要开发手动实现自定义验证

具体的实现步骤如下:

  • 创建一个自定义验证规则

    这里会使用 @interface 去创建一个注解的 interface,并且实现注解

    package com.example.springdemo.mvc.validation;import jakarta.validation.Constraint;
    import jakarta.validation.Payload;import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;@Constraint(validatedBy = CourseCodeConstraintValidator.class)
    @Target({ElementType.METHOD, ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface CourseCode {public String value() default "CS";public String message() default "must start with CS";public Class<?>[] groups() default {};public Class<? extends Payload>[] payload() default {};
    }

    注解实现:

    package com.example.springdemo.mvc.validation;import jakarta.validation.ConstraintValidator;
    import jakarta.validation.ConstraintValidatorContext;public class CourseCodeConstraintValidator  implements ConstraintValidator<CourseCode, String> {private String coursePrefix;@Overridepublic void initialize(CourseCode courseCode) {coursePrefix = courseCode.value();}@Overridepublic boolean isValid(String code, ConstraintValidatorContext constraintValidatorContext) {// handle null value, since when user doesn't provide any input, code will be nullif (code != null) return code.startsWith(coursePrefix);return false;}
    }

    到这一步就可以使用新实现的自定义验证了

    注解的部分不会涉及太多……主要是我也不太熟。等后面重新学一些 java 的新特性的时候再研究叭

  • Customer 中使用心得自定义验证

    @Data
    public class Customer {// omit other impl// it will take default value@CourseCode// can be overwritten in this way:// @CourseCode(value = "something", message = "must start with example")private String courseCode;
    }
    

    这里是用的就是默认的信息

    不使用默认信息的方法在注释掉的代码里

后面的步骤,就是更新 HTML 模板的部分就省略了,最终的实现效果如下:

在这里插入图片描述

这篇关于[spring] Spring MVC Thymeleaf(下)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1087065

相关文章

Java中流式并行操作parallelStream的原理和使用方法

《Java中流式并行操作parallelStream的原理和使用方法》本文详细介绍了Java中的并行流(parallelStream)的原理、正确使用方法以及在实际业务中的应用案例,并指出在使用并行流... 目录Java中流式并行操作parallelStream0. 问题的产生1. 什么是parallelS

Java中Redisson 的原理深度解析

《Java中Redisson的原理深度解析》Redisson是一个高性能的Redis客户端,它通过将Redis数据结构映射为Java对象和分布式对象,实现了在Java应用中方便地使用Redis,本文... 目录前言一、核心设计理念二、核心架构与通信层1. 基于 Netty 的异步非阻塞通信2. 编解码器三、

SpringBoot基于注解实现数据库字段回填的完整方案

《SpringBoot基于注解实现数据库字段回填的完整方案》这篇文章主要为大家详细介绍了SpringBoot如何基于注解实现数据库字段回填的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以了解... 目录数据库表pom.XMLRelationFieldRelationFieldMapping基础的一些代

一篇文章彻底搞懂macOS如何决定java环境

《一篇文章彻底搞懂macOS如何决定java环境》MacOS作为一个功能强大的操作系统,为开发者提供了丰富的开发工具和框架,下面:本文主要介绍macOS如何决定java环境的相关资料,文中通过代码... 目录方法一:使用 which命令方法二:使用 Java_home工具(Apple 官方推荐)那问题来了,

Java HashMap的底层实现原理深度解析

《JavaHashMap的底层实现原理深度解析》HashMap基于数组+链表+红黑树结构,通过哈希算法和扩容机制优化性能,负载因子与树化阈值平衡效率,是Java开发必备的高效数据结构,本文给大家介绍... 目录一、概述:HashMap的宏观结构二、核心数据结构解析1. 数组(桶数组)2. 链表节点(Node

Java AOP面向切面编程的概念和实现方式

《JavaAOP面向切面编程的概念和实现方式》AOP是面向切面编程,通过动态代理将横切关注点(如日志、事务)与核心业务逻辑分离,提升代码复用性和可维护性,本文给大家介绍JavaAOP面向切面编程的概... 目录一、AOP 是什么?二、AOP 的核心概念与实现方式核心概念实现方式三、Spring AOP 的关

详解SpringBoot+Ehcache使用示例

《详解SpringBoot+Ehcache使用示例》本文介绍了SpringBoot中配置Ehcache、自定义get/set方式,并实际使用缓存的过程,文中通过示例代码介绍的非常详细,对大家的学习或者... 目录摘要概念内存与磁盘持久化存储:配置灵活性:编码示例引入依赖:配置ehcache.XML文件:配置

Java 虚拟线程的创建与使用深度解析

《Java虚拟线程的创建与使用深度解析》虚拟线程是Java19中以预览特性形式引入,Java21起正式发布的轻量级线程,本文给大家介绍Java虚拟线程的创建与使用,感兴趣的朋友一起看看吧... 目录一、虚拟线程简介1.1 什么是虚拟线程?1.2 为什么需要虚拟线程?二、虚拟线程与平台线程对比代码对比示例:三

Java中的.close()举例详解

《Java中的.close()举例详解》.close()方法只适用于通过window.open()打开的弹出窗口,对于浏览器的主窗口,如果没有得到用户允许是不能关闭的,:本文主要介绍Java中的.... 目录当你遇到以下三种情况时,一定要记得使用 .close():用法作用举例如何判断代码中的 input

Spring Gateway动态路由实现方案

《SpringGateway动态路由实现方案》本文主要介绍了SpringGateway动态路由实现方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随... 目录前沿何为路由RouteDefinitionRouteLocator工作流程动态路由实现尾巴前沿S