Spring MVC+mybatis 项目入门:旅游网(三)用户注册——控制反转以及Hibernate Validator数据验证

个人博客:Spring MVC+mybatis 项目入门:旅游网(三)用户注册 | iwts's blog

先看这个!

这是18年的文章,回收站里恢复的,现阶段看基本是没有参考意义的,技术老旧脱离时代(2024年辣铁铁)

如果你在找相关的内容,建议先自我反省一下为什么会搜这么old school的关键词,其次请直接上b站搜索Spricing boo+培训班,看最新的项目相关视频

注册原理

        其实很简单,前端页面显示一个表单,然后由dispatcher传递到controller,controller调用数据库验证,如果ok,那就写入数据库,同时返回注册成功的视图,否则可以返回注册页,或者是到一个错误页。

依赖注入与控制反转

        这里提一下,在最早接触servlet的时候,应该有老师会说,Java的POJO应该只有属性与构造方法,除此之外对于每个属性必须写其对应的getter、setter方法。而这里就是为了依赖注入。具体的理论可以百度,这里就简单说明一下构造注入与setter注入:

// 构造注入
public class Test(){private B b;public Test(B b){this.b = b;}
}// setter注入
public class Test(){private B b;public void setB(B b){this.b = b;}
}

为什么要使用依赖注入或者说控制反转?(实际上,两者是相同的,只是在不同的角度阐述了上述操作)这里应该有专门的文章论述了。篇幅有限,这里不再解答,但是推荐搞懂这两者再继续阅读,毕竟这个非常核心。否则就是只会用而不知道具体实现了。

        现在给出jsp代码与controller的代码以及User类的bean:

package me.iwts.bean;import org.hibernate.validator.constraints.Email;
import javax.validation.constraints.Size;public class User {private String account;private String passwd;private String phone;private String email;private String userName;public User(){ }public User(String account,String passwd,String phone,String email,String userName){this.account = account;this.passwd = passwd;this.email = email;this.phone = phone;this.userName = userName;}public void setEmail(String email) {this.email = email;}public void setAccount(String account) {this.account = account;}public void setPasswd(String passwd) {this.passwd = passwd;}public void setPhone(String phone) {this.phone = phone;}public void setUserName(String userName) {this.userName = userName;}public String getEmail() {return email;}public String getAccount() {return account;}public String getPasswd() {return passwd;}public String getPhone() {return phone;}public String getUserName() {return userName;}
}
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title>
</head>
<body><p>注册测试</p><form:form modelAttribute="user" action="register.action" method="post">账号:<input type="text" name="account"><br />密码:<input type="password" name="passwd"><br />手机号:<input type="text" name="phone"><br />邮箱:<input type="email" name="email"><br />用户昵称:<input type="text" name="userName"><br /><input type="submit" name="submit" value="注册"></form:form>
</body>
</html>

这个<form:form>标签是Spring MVC的标签,请当做正常的<form>标签,为什么写这个标签?后面的优化部分会说到。

package me.iwts.controller;import me.iwts.bean.User;
import me.iwts.mapper.UserMapper;
import me.iwts.tools.ViewTool;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;
import java.io.Reader;@Controller
public class UserController {// 注册@RequestMapping("register.action")public ModelAndView register(@ModelAttribute User user, Model model){}
}

具体代码我没有写,这里仅仅演示了Spring MVC如何处理依赖注入的情况。

        可以看到,form表单对应了User类的一部分,然后就直接action给提交了,并没有对表单输入的数据进行封装。而在controller类里面,我们在形参列表却传递了一个User类。这个User类使用了注解@ModelAttribute。

        其实这里在Spring MVC,完成了控制反转或者说依赖注入的操作。我们表单仍然还是只传递了一堆值,而dispatcher在获取请求以后,就利用setter注入,帮助我们封装好了整个User类,然后是将这个User对象给传递到register方法里面的。而只要我们的形参列表声明了需要这个对象,那么Spring MVC就能够给我们这个对象。这个过程,就是控制反转。

        所以说,从controller的角度看,叫控制反转,从Spring MVC的角度看,叫依赖注入。而不管怎样,我们都能够获取到这个对象,并且这个对象已经被封装成为了model,之后的操作就是数据持久化了(当然需要先进行验证)。

Hibernate Validator后端数据校验

        这里也是需要大篇幅讲解的部分。。。推荐百度搜一下,提醒一下,这里坑略多,自己搜的时候学得会好一点,就是可能有很多错,博主也是踩了很多坑。

        Spring是没有数据校验的。但是数据校验是比较重要的一环。可能比较多的同学学的是JavaScript校验,这个是在前端控制数据的正确性,例如格式问题。但是,如果某些不怀好意的同学恶意操作呢?例如直接使用http提交数据,这样就能绕过前端直接给后端传递数据。当然安全问题远远没有这么低级,但是在现阶段,这样的问题应该被我们考虑,而更难的安全问题就以后在进行处理。所以,解决这个简单的安全问题就是进行后端的数据校验——无论你怎么传,只要我能在后端校验,就能防止恶意传递数据。

        比较简单的方法就是直接处理——我们已经将对象封装好利用控制反转给获取到了,那么我们就能获取其各个属性的值,然后直接一顿操作就行了。但是我们现在想要逼格高一点的,同时还想节省代码量,所以我们选择利用其它技术来实现这个功能。

        上面也说了Spring是没有数据校验的。简而言之,Java只提供了一些规范,说,只要你能实现这个规范,就能进行数据校验了,而hibernate validator就是实现了这个规范。那么我们就只用获取其jar包,然后一顿调用,就能利用其来实现数据校验的操作。hibernate validator是实现了两套规范的,我们下面讲的主要依据最新的规范,比较简单,也更强大。

也可以移步:Spring MVC利用Hibernate Validator实现后端数据校验 | Iwts’s blog 有更为详尽的解释

        首先,jar包自然是需要的。hibernate validator所必须的jar包是2个:hibernate-validator.jar和validation-api.jar。但是个人推荐多增加两个,可以杜绝大部分错误:

但是如果还是有错的话,就只能看log了,具体缺什么jar包就去下载什么jar包。这些jar包都可以直接百度下载,或者在我的项目里面/lib/ext下查找。而具体怎么在IDE里面添加就不多说了。

约束注解

        之后,我们需要对bean进行一次升级,就是添加注解。而这个注解,就是对某个属性进行约束,规定这个属性必须满足怎么样的条件,否则就会返回错误。先看一下bean的代码:

package me.iwts.bean;import org.hibernate.validator.constraints.Email;
import javax.validation.constraints.Size;public class User {@Size(min = 6,max = 16,message = "账号不能为空,位数要为6-16位")private String account;@Size(min = 6,max = 16,message = "密码不能为空,位数要为6-14位")private String passwd;@Size(min = 11,max = 11,message = "手机不能为空,手机号码格式错误")private String phone;@Email(message = "邮箱格式错误")private String email;@Size(min = 0,max = 10,message = "昵称不能大于10位")private String userName;public User(){ }public User(String account,String passwd,String phone,String email,String userName){this.account = account;this.passwd = passwd;this.email = email;this.phone = phone;this.userName = userName;}public void setEmail(String email) {this.email = email;}public void setAccount(String account) {this.account = account;}public void setPasswd(String passwd) {this.passwd = passwd;}public void setPhone(String phone) {this.phone = phone;}public void setUserName(String userName) {this.userName = userName;}public String getEmail() {return email;}public String getAccount() {return account;}public String getPasswd() {return passwd;}public String getPhone() {return phone;}public String getUserName() {return userName;}
}

可以看到,每个属性上面对应的@Size、@Email等就是注解。不同的注解有不同的作用,这里提供一些图,是从以前的博客上截的:

利用注解,就能比较方便地进行约束。

        现在只是声明了约束,而如果违反这个约束会有什么操作这个是在controller里面执行的,但是我们需要告诉controller这里违反了约束,也就是需要提醒信息。可以看到,我们在注解里面写了message属性,而里面的内容就是我们自定义的错误信息。其实不加也行,如果我们不想让用户看到这个信息的话,默认情况下也会有错误信息,不过是英文的。但是我们选择让用户看到,这样能提醒他们你写错了。怎么让他们看?这个我们留到最后说。

后端处理

        那么现在,就看我们怎么在controller里面处理这个约束了,看一下controller里面的代码:

package me.iwts.controller;import me.iwts.bean.User;
import me.iwts.mapper.UserMapper;
import me.iwts.tools.ViewTool;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;
import java.io.Reader;@Controller
public class UserController {// 注册@RequestMapping("register.action")public ModelAndView register(@Valid @ModelAttribute User user, BindingResult bindingResult, Model model){if(bindingResult.hasErrors()){model.addAttribute("user",user);return new ModelAndView(ViewTool.REGISTER);}}
}

可以与上面代码进行一些比较,其实主要是参数部分有变化:

1.对于传入的对象,需要用注解@Valid声明。

2.增加一个BindingResult对象。

第一个操作,主要是声明,在进行依赖注入的时候,需要对这个类的属性进行数据验证,而验证方式就是根据其对应的注解。而BindingResult对象,就是在进行数据验证的时候,如果有错误,就将其message给添加到BindingResult对象里面。而调用其hasErrors()方法,就能判定是否是有错误的。

        而具体如何处理,这个就根据实际情况判定了。例如我们对于无所谓的数据,例如用户昵称。我们允许用户不写昵称,但是我们看论坛的话,发现这个昵称会默认是用户名。这就是我们处理的结果了,如果发现有用户昵称为空,我们就将用户名给赋值进去。

        当然,我们这里的逻辑就是告诉用户:你错了,请重新输入。所以可以看到,我们直接返回了一个视图,同时将user对象封装进model里面,和视图一起返回到注册页面,所以下面就是看前端如何处理了。

前端处理

        现在,我们将model返回到了前端,同时视图也返回回来了,这里先上一个完整未删减的代码:

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title>
</head>
<body><p>注册测试</p><form:form modelAttribute="user" action="register.action" method="post">账号:<input type="text" name="account" value=${requestScope.user.account}><form:errors path="account"></form:errors><span>${accountError}</span><br />密码:<input type="password" name="passwd"><form:errors path="passwd"></form:errors><br />手机号:<input type="text" name="phone" value=${requestScope.user.phone}><form:errors path="phone"></form:errors><br />邮箱:<input type="email" name="email" value="${requestScope.user.email}"><form:errors path="email"></form:errors><br />用户昵称:<input type="text" name="userName" value=${requestScope.user.userName}><form:errors path="userName"></form:errors><br /><input type="submit" name="submit" value="注册"></form:form>
</body>
</html>

同样,可以跟最早的jsp页面比较,看多了点什么东西。

        首先,类似于${requestScope.user.account}这样的代码是EL表达式。这个是非常好用的,推荐大家先去看一下什么是EL表达式,然后再回头看这里的代码。只能说,用EL表达式很爽。

        然后,下面就默认大家会一点EL表达式了。首先可以看到,多的一部分是value值。这个部分是完成了记忆功能。例如刚开始注册表单是什么都没有的,而我们注册以后,如果有错误返回,会发现表单是我们上次提交的信息,除了密码。这里就是利用value进行记忆功能,value的值就是EL表达式,而刚开始EL表达式是找不到user对象的,因为我们只有在model里面将user返回,才有这个对象,所以EL表达式的结果是空。而如果第二次返回,那么就有user对象了,从而能够将上次输入的结果给显示在界面上。

        这个不是最重要的,重要的是下面的标签:<form:errors>,这个标签能够显示hibernate validator捕获的错误数据。并且将其message给显示出来。而path属性就指定了,其显示哪一个属性出现的错误。请注意:想要使用这个标签,那么就必须使用<form:form>标签,这也是我放弃<form>标签的原因。

        所以,如果你想要让用户看到哪里错了,就需要在message属性写想让用户看到的信息,如果不想,就可以使用默认message了。给一个效果图吧:

下一章链接

https://blog.csdn.net/iwts_24/article/details/84198196

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

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

相关文章

澳大利亚.德国-门户媒体投放通稿:需要注意什么地方

概述 在现代社会&#xff0c;新闻媒体的投放成为企业和组织宣传推广的重要手段之一。澳大利亚和德国作为全球重要的经济和科技中心&#xff0c;其新闻媒体也备受关注。本文将介绍澳大利亚和德国的一些主要新闻媒体&#xff0c;并讨论发表新闻稿时需要注意的地方。 澳大利亚媒…

streamlit 学习

表情网站 https://getemoji.com/ 官网&#xff1a; https://streamlit.io/ 文档 https://docs.streamlit.io/develop/api-reference/chat/st.chat_message 安装&#xff1a; pip install streamlit启动 以下的python 文件指写streamlit 程序的脚步。 1、先切换目录到Pyth…

VMware虚拟机-设置系统网络IP、快照、克隆

1.设置网络IP 1.点击右上角开关按钮-》有线 已连接-》有线设置 2.手动修改ip 3.重启或者把开关重新关闭开启 2.快照设置 快照介绍&#xff1a; 通过快照可快速保存虚拟机当前的状态&#xff0c;后续可以使用虚拟机还原到某个快照的状态。 1.添加快照(需要先关闭虚拟机) 2.在…

[JAVASE] 类和对象(六) -- 接口(续篇)

目录 一. Comparable接口 与 compareTo方法 1.1 Comparable接口 1.2 compareTo方法的重写 1.2.1 根据年龄进行比较 1.2.2 根据姓名进行比较 1.4 compareTo 方法 的使用 1.3 compareTo方法的缺点(重点) 二. Comparator接口 与 compare方法 2.1 Comparator接口 2.2 compare 方法…

蓝桥杯算法心得——李白打酒(加强版)

大家好&#xff0c;我是晴天学长&#xff0c;记忆化搜索&#xff0c;找到技巧非常重要&#xff0c;需要的小伙伴可以关注支持一下哦&#xff01;后续会继续更新的。&#x1f4aa;&#x1f4aa;&#x1f4aa; 2) .算法思路 1.memo三维表示记录的结果 3&#xff09;.算法步骤 1…

slint esp32 tokio

源码&#xff1a;https://github.com/xiaguangbo/slint_esp32_tokio cpu 是 esp32c2&#xff0c;屏幕是 ili9341&#xff0c;触摸是 xpt2046&#xff0c;使用 spi 半双工 不使用DMA&#xff08;esp-rs还没支持&#xff09;&#xff0c;SPI 40M&#xff0c;240*320全屏刷新为1.5…

四. TensorRT模型部署优化-模型部署的基础知识

目录 前言0. 简介1. FLOPS2. TOPS3. HPC的排行&#xff0c;CPU/GPU比较4. FLOPs5. FLOPS是如何计算的6. CUDA Core vs Tensor Core总结参考 前言 自动驾驶之心推出的 《CUDA与TensorRT部署实战课程》&#xff0c;链接。记录下个人学习笔记&#xff0c;仅供自己参考 本次课程我们…

最小二乘法-超详细推导(转换为矩阵乘法推导,矩阵求导推导)

最小二乘法就是让均方误差最小。 下面是损失函数转换为矩阵方式的详解 如何让其最小&#xff0c;在导数为0的地方取极小值。 问&#xff1a;导数为0的地方可能去极大值&#xff0c;也可能是极小值&#xff0c;凭什么说导数为0就是极小值&#xff1f; 答&#xff1a;因为使用…

酷黑简洁大气体育直播自适应模板赛事直播门户网站源码

源码名称&#xff1a;酷黑简洁大气体育直播自适应模板赛事直播门户网站源码 开发环境&#xff1a;帝国cms 7.5 安装环境&#xff1a;phpmysql 支持PC与手机端同步生成html&#xff08;多端同步生成插件&#xff09; 带软件采集&#xff0c;可以挂着自动采集发布&#xff0c;无…

某某某加固系统分析

某某某加固系统内核so dump和修复&#xff1a; 某某某加固系统采取了内外两层native代码模式&#xff0c;外层主要为了保护内层核心代码&#xff0c;从分析来看外层模块主要用来反调试&#xff0c;释放内层模块&#xff0c;维护内存模块的某些运行环境达到防止分离内外模块&am…

网上比较受认可的赚钱软件有哪些?众多兼职选择中总有一个适合你

在这个互联网高速发展的时代&#xff0c;网上赚钱似乎成了一种潮流。但是&#xff0c;你是否还在靠运气寻找赚钱的机会&#xff1f;是否还在为找不到靠谱的兼职平台而苦恼&#xff1f; 今天&#xff0c;就为你揭秘那些真正靠谱的网上赚钱平台&#xff0c;让你的赚钱之路不再迷…

Python--List列表

list列表⭐⭐ 1高级数据类型 Python中的数据类型可以分为&#xff1a;数字型&#xff08;基本数据类型&#xff09;和非数字型&#xff08;高级数据类型&#xff09; ●数字型包含&#xff1a;整型int、浮点型float、布尔型bool、复数型complex ●非数字型包含&#xff1a;字符…

整合SSM框架笔记

整合SSM框架笔记 Spring5 Spring MVC MyBatis Druid MySQL Thymeleaf 感谢尚硅谷课程&#xff1a;B站课程 前言 单Spring框架时&#xff0c;是Java工程。 Spring与Spring MVC可以共用一个配置文件&#xff0c;也可以不共用一个&#xff0c;推荐不共用一个。 Spring与Sp…

Quartus 联合 ModelSim 仿真 IP 核(RAM)

文章目录 ModelSim 路径设置创建 RAM进行仿真 本文主要介绍如何在包含 IP 核的 Quartus 项目中使用 Modelsim 进行仿真&#xff0c;本文基于 IP 核 RAM: 2-PORT&#xff0c;其他 IP 核类似。 ModelSim 路径设置 点击 Tools->Options 点击 EDA Tool Options&#xff0c;设置…

string OJ题

下面分享一下string做题心得 1. 明白字符串中存储的数字为0 8 9与0 8 9 完全不同&#xff0c;字符0其实在串中存储的是48&#xff0c;要有意识的转化。字符串中如果存数字8&#xff0c;意味着存了BS&#xff08;退格&#xff09; 例如1&#xff1a; 算出结果为5&#xff0c;存…

Selenium 自动化测试工具<2>(Selenium 常用API的使用方法)

文章目录 浏览器操作浏览器最大化设置浏览器的大小浏览器的前进和后退操作浏览器滚动条 键盘事件单个按键用法键盘组合键用法 鼠标事件不同窗口搜索定位一组元素定位多层框架下拉框定位alert、confirm、prompt 的处理上传文件操作自动截屏 继上一篇文章对 Selenium API 的使用&…

RT-DRET在实时目标检测上超越YOLO8

导读 目标检测作为计算机视觉的核心任务之一&#xff0c;其研究已经从基于CNN的架构发展到基于Transformer的架构&#xff0c;如DETR&#xff0c;后者通过简化流程实现端到端检测&#xff0c;消除了手工设计的组件。尽管如此&#xff0c;DETR的高计算成本限制了其在实时目标检测…

搭建属于自己的 Git 仓库:GitLab

搭建属于自己的 Git 仓库&#xff1a;使用 GitLab 文章目录 搭建属于自己的 Git 仓库&#xff1a;使用 GitLab什么是 GitLab&#xff1f;准备工作安装 Docker使用Docker Compose 快速构建GitLab1、从docker compose快速搭建GitLab2、部署到服务器并访问3、浏览器访问 在现代软件…

【数据结构】------C语言实现二叉树

作者主页&#xff1a;作者主页 数据结构专栏&#xff1a;数据结构 创作时间 &#xff1a;2024年5月20日 一、二叉树的定义 二叉树(Binary Tree) 是由n个结点构成的有限集(n≥0)&#xff0c;n0时为空树&#xff0c;n>0时为非空树。 对于非空树&#xff1a; 有且仅有一个根…

腾讯Java社招面试题真题,最新面试题

Java中synchronized和ReentrantLock有什么区别&#xff1f; 1、锁的实现方式不同&#xff1a; synchronized是JVM层面的锁&#xff0c;主要依赖于监视器对象&#xff08;monitor&#xff09;实现。ReentrantLock是JDK层面的锁&#xff0c;通过Java代码实现&#xff0c;提供了更…