[spring] Spring MVC Thymeleaf(下)

news2024/11/20 18:45:09

[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 />
    
        <form
          th: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)  -->
          <span
            th: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 {
    @InitBinder
    public 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)  -->
<span
  th: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)  -->
<span
  th: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;
    
        @Override
        public void initialize(CourseCode courseCode) {
            coursePrefix = courseCode.value();
        }
    
        @Override
        public boolean isValid(String code, ConstraintValidatorContext constraintValidatorContext) {
            // handle null value, since when user doesn't provide any input, code will be null
            if (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 模板的部分就省略了,最终的实现效果如下:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1855163.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【深度学习】智能手写数字识别系统

文章目录 一&#xff0e;实验课题背景说明1.1实验目的1.2实验环境1.2.1安装PyTorch1.2.2安装其他必要的库 二&#xff0e;模型说明2.1模型概述2.2模型结构 三&#xff0e;数据说明3.1 输入数据3.1.1输入数据特征3.1.2输入数据维度3.1.3输入数据预处理 3.2 数据格式3.2.1输出数据…

两个方法,批量替换PPT中的字体

经常制作ppt的朋友可能会遇到需要批量替换字体的情况&#xff0c;如果我们想要更换ppt中的字体&#xff0c;今天分享PPT批量替换字体的两个方法。 方法一&#xff1a; 找到功能栏中的编辑选项卡&#xff0c;点击替换 – 替换字体&#xff0c;在里面选择我们想要替换的字体就可…

【因果推断python】51_去偏/正交机器学习3

目录 What is Non-Parametric About? What is Non-Parametric About? 在我们继续之前&#xff0c;我只想强调一个常见的误解。当我们考虑使用非参数 Double-ML 模型来估计 CATE 时&#xff0c;我们似乎会得到一个非线性治疗效果。例如&#xff0c;让我们假设一个非常简单的数…

LeetCode665.非递减数列

LeetCode刷题记录 文章目录 &#x1f4dc;题目描述&#x1f4a1;解题思路⌨C代码 &#x1f4dc;题目描述 给你一个长度为 n 的整数数组 nums &#xff0c;请你判断在 最多 改变 1 个元素的情况下&#xff0c;该数组能否变成一个非递减数列。 我们是这样定义一个非递减数列的&am…

昆明理工大学24计算机考研各专业复试线大幅下降,B区国家线即可复试!

昆明理工大学&#xff08;Kunming University of Science and Technology&#xff09;&#xff0c;位于云南省昆明市&#xff0c;是云南省综合性重点大学&#xff0c;由国防科技工业局与云南省人民政府共建高校&#xff0c;入选“中西部高校基础能力建设工程”、国家建设高水平…

第10关:视图1 、第11关:视图2 、第12关:用户。

目录 第10关&#xff1a;视图1 任务描述 知识补充 答案 第11关&#xff1a;视图2 任务描述 知识补充 答案 第12关&#xff1a;用户 任务描述 知识补充 答案 本篇博客声明&#xff1a;所有题的答案不在一起&#xff0c;可以去作者博客专栏寻找其它文章。 第10关&…

Phi-3 模型手机部署教程(微软发布的可与GPT-3.5媲美的小模型)

前面几篇博文&#xff0c;老牛同学和大家一起在个人电脑部署了Qwen2、GLM4、Llama3、ChatTTS和Stable Diffusion等 LLM 大模型&#xff0c;也通过 API 和 WebUI 的方式完成了体验。 但是这些大模型因为部署在个人电脑本地&#xff0c;不能够随时携带。如果能在手机上部署大模型…

EtherCAT笔记(三) —— 主站与从站的硬件组成

1. EtherCAT 主站的硬件组成 EtherCAT主站使用标准以太网控制器&#xff0c;也即EtherCAT主站可以使用以太网控制器的任何设备。当我们有一台带网口的笔记本、工控机&#xff0c;甚至是树莓派也可以作为EtherCAT主站。 EtherCAT协议是对Ethernet协议在实时控制等方面的优化&am…

一篇文章带你快速入门java

文章目录 一、一个简单的java代码1.1 Java程序的结构由三个不成组成&#xff1a;1.2 运行java程序1.3 JDK,JRE,JVM之间的关系&#xff1f;(面试题)1.4 标识符1.5 注释1.6 关键字 一、一个简单的java代码 public class HelloJava {public static void main(String[] args) {Sys…

【建议收藏】Android中高级大厂面试源码秘籍,为你备战2021金三银四,直通大厂

首先来说下为什么要读源码&#xff0c;有学习源码的必要吗&#xff1f; 为什么要阅读源码&#xff1f; 关于为什么阅读和学习源码&#xff0c;我个人认为可能有以下几点&#xff1a; &#xff08;一&#xff09;吊打面试官&#xff0c;应对面试 为了找到更好的工作&#xff…

Linux配置中文环境

文章目录 前言中文语言包中文输入法中文字体 前言 在Linux系统中修改为中文环境&#xff0c;通常涉及以下几个步骤&#xff1a; 中文语言包 更新源列表&#xff1a; 更新系统的软件源列表和语言环境设置&#xff0c;确保可以安装所需的语言包。 sudo apt update sudo apt ins…

Python+Pytest+Yaml+Request+Allure框架源代码之(一)common公共方法封装

common模块&#xff1a; get_path.py&#xff1a;获取路径方法 # -*- coding: UTF-8 -*- import os# 项目根目录 BASE_DIR os.path.dirname(os.path.dirname(os.path.abspath(__file__)))# 配置文件目录 CONFIG_DIR os.path.join(BASE_DIR,config)# 测试用例文件目录 TESTCA…

康奈尔大学之论文审稿模型Reviewer2及我司七月对其的实现(含PeerRead)

前言 自从我司于23年7月开始涉足论文审稿领域之后「截止到24年6月份&#xff0c;我司的七月论文审稿GPT已经迭代到了第五版&#xff0c;详见此文的8.1 七月论文审稿GPT(从第1版到第5版)」&#xff0c;在业界的影响力越来越大&#xff0c;所以身边朋友如发现业界有相似的工作&a…

年薪50w+的项目经理,手把手教你如何复盘

复盘是一种重要的学习和改进工具&#xff0c;对于项目经理来说&#xff0c;能帮助识别项目中的成功与失败&#xff0c;为未来的项目管理提供宝贵经验。 理论部分 定义目标。在开始复盘之前&#xff0c;明确复盘的目标是什么。是为了找出项目中的问题并提出解决方案&#xff0c…

自动驾驶规划中使用 OSQP 进行二次规划 代码原理详细解读

目录 1 问题描述 什么是稀疏矩阵 CSC 形式 QP Path Planning 问题 1. Cost function 1.1 The first term: 1.2 The second term: 1.3 The thrid term: 1.4 The forth term: 对 Qx 矩阵公式的验证 整体 Q 矩阵&#xff08;就是 P 矩阵&#xff0c;二次项的权重矩阵&…

Android开发:自定义TabLayout,神奇效果竟是如此简单

此时有的小伙伴可能会想&#xff0c;自定义view太麻烦&#xff0c;不如让UI直接把这个弧度切出来&#xff0c;不是一共就三个tab项嘛&#xff0c;Textview&#xff0c;ImageView… 这样横着排起来&#xff0c;然后做适当的显示和隐藏不就行啦。 是的&#xff0c;确实是可以&am…

人工智能在数字病理切片虚拟染色以及染色标准化领域的研究进展|顶刊速递·24-06-23

小罗碎碎念 本期推文主题&#xff1a;人工智能在数字病理切片虚拟染色以及染色标准化领域的研究进展 这一期的推文是我发自内心觉得为数不多&#xff0c;特别宝贵的一篇推文&#xff0c;原因很简单——可参考的文献相对较少&方向非常具有研究意义&现在不卷。 数字病理…

nginx服务器连接数告警

序言 只要系统之间有交互&#xff0c;那么就会有连接数&#xff0c;连接数的告警阈值一般设置个几万&#xff0c;当连接数开始告警之后&#xff0c;怎么来排查呢&#xff1f; 连接数过多&#xff0c;会消耗cpu&#xff0c;内存&#xff0c;文件句柄等资源&#xff0c;其实也还好…

《算法笔记》总结No.2——模拟

一.简单模拟 考察代码能力&#xff0c;不涉及算法&#xff1a;一类题目怎么说你就怎么做的类型~ 巴音布鲁克比赛&#xff0c;以车队为基准评选冠军。业务要求是&#xff1a;第一行输入正整数N&#xff0c;代表车手的总个数&#xff1b;接下来的N行每行键入两个数字&#xff1a…

【TOOL】ceres学习笔记(二) —— 自定义函数练习

文章目录 一、曲线方程1. 问题描述2. 实现方案 一、曲线方程 1. 问题描述 现有数学模型为 f ( x ) A e x B s i n ( x ) C x D f(x)Ae^xBsin(x)Cx^D f(x)AexBsin(x)CxD &#xff0c;但不知道 A A A 、 B B B 、 C C C 、 D D D 各参数系数&#xff0c;实验数据中含有噪声…