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

news2024/11/15 2:19:42

个人博客: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.coloradmin.cn/o/1696609.html

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

相关文章

《Ai学习笔记》自然语言处理 (Natural Language Processing):机器阅读理解-基础概念解析01

自然语言处理 (Natural Language Processing)&#xff1a; NLP四大基本任务 序列标注&#xff1a; 分词、词性标注 分类任务&#xff1a; 文本分类、情感分析 句子关系&#xff1a;问答系统、对话系统 生成任务&#xff1a;机器翻译、文章摘要 机器阅读理解的定义 Machi…

创建带有公共头部的Electron窗口

创建带有公共头部的Electron窗口 创建一个公共头部的html文件 1.我们在项目根目录创建一个名为app-header的文件夹 2.在app-header创建一个文件名为header.html的文件 结构如下&#xff1a; 基本结构和脚本如下 <body> <div class"header"><div c…

Node Video Pro v6.40.0,媲美电脑的专业手机剪辑APP

软件介绍 Node Video Pro&#xff0c;作为一款高端的视频编辑与共享平台&#xff0c;为用户提供了一套完备的视频制作工具集。该应用集成了视频剪辑、视觉特效增强、以及音乐背景选择等功能&#xff0c;允许用户在移动设备上实施专业级别的视频处理。它所具备的高级功能配合其…

Go使用结构体实现类(面向对象)

前置 package main ​ import ("fmt" ) ​ // 矩形结构体 type Rectangle struct {Length intWidth int } ​ // 计算矩形面积 func (r *Rectangle) Area() int {return r.Length * r.Width } ​ func main() {r : Rectangle{4, 2}// 调用 Area() 方法&#xff0c;计…

SpringBoot运维篇(打包,多环境,日志)

文章目录 一、SpringBoot程序的打包与运行二、配置高级三、多环境开发四、日志 一、SpringBoot程序的打包与运行 刚开始做开发学习的小伙伴可能在有一个知识上面有错误的认知&#xff0c;我们天天写程序是在Idea下写的&#xff0c;运行也是在Idea下运行的。 ​但是实际开发完成…

springboot vue 开源 会员收银系统 (4) 门店模块开发

前言 完整版演示 前面我们对会员系统 springboot vue 开源 会员收银系统 (3) 会员管理的开发 实现了简单的会员添加 下面我们将从会员模块进行延伸 门店模块的开发 首先我们先分析一下常见门店的管理模式 常见的管理形式为总公司 - 区域管理&#xff08;若干个门店&#xff…

打造有情感的AI智能体-情感问答

目录 文心智能体平台简介 情感问答智能体介绍 优势1主动提问深入分析你的困扰&#xff0c;合理建议 优势2多次主动提问&#xff0c;引导用户补全信息。 优势3整合多种强大工具 最近发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c…

勒索软件分析_Conti

0. Conti介绍 勒索软件即服务&#xff08;Ransomware as a Service&#xff0c;RaaS&#xff09;变体 Conti 推出还不到两年&#xff0c;已经进行了第七次迭代。Conti被证明是一种敏捷而熟练的恶意软件威胁&#xff0c;能够自主和引导操作&#xff0c;并具有无与伦比的加密速度…

今日早报 每日精选15条新闻简报 每天一分钟 知晓天下事 5月26日,星期日

每天一分钟&#xff0c;知晓天下事&#xff01; 2024年5月26日 星期日 农历四月十九 1、 医保局&#xff1a;支持将符合条件的村卫生室纳入医保定点&#xff0c;方便农村居民就医。 2、 网传养老金储备严重不足&#xff1f;央视辟谣&#xff1a;这笔钱二十多年来从未动用过&a…

SAP HCM WPBP的几个变量含义

WPBP起源 WPBP是SAP HCM的主数据的集合内表,集合、内表这两个名词如何理解,集合就是多个主数据的汇总,内表是ABAP的几个数据结构,就和我们EXCEL的多行一行。 wpbp数据来源 WPBP的主数据来源于SAP HCM 0000、0001、0007、0027、0008信息类型的汇总,SAP HCM是以时间轴为核心…

Linux/Ubuntu 中安装 ZeroTier,实现内网穿透,2分钟搞定

相信很多人都有远程连接家中设备的需求&#xff0c;如远程连接家中的NAS、Windows等服务&#xff0c;所以会涉及到一个内网穿透工具的使用&#xff0c;如果没有公网IP的情况下&#xff0c;推荐大家使用ZeroTier&#xff0c;这是一款强大的内网穿透工具。 mac和windows版的操作…

Python实现SMA黏菌优化算法优化随机森林分类模型(RandomForestClassifier算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 黏菌优化算法&#xff08;Slime mould algorithm&#xff0c;SMA&#xff09;由Li等于2020年提出&…

LeetCode刷题之HOT100之二叉树的直径

2024/5/25 阴天。这几天睡眠质量都非常好&#xff0c;一切似乎都在慢慢上升。先把题做了 1、题目描述 2、逻辑分析 题目要求就是给一个二叉树&#xff0c;求出两个节点之间的最大长度即为二叉树的直径。怎么做呢&#xff1f;我想不出来。看一下题解吧。题解给出的解法是深度优…

Elasticsearch集群许可证过期问题解决方法汇总

最近在使用elasticsearch的过程中,使用elastic-head进行可视化展示集群的状态和信息,从2024年5月18日突然elastic-head无法现在集群的状态界面啦,elasticsearch集群状态是正常,命令如下: curl -X GET "localhost:9200/_cluster/health?pretty" 在google页面上通过…

小程序的这些知识你知道吗?

一:导航传参 无论是编程式还是声明式导肮传参都是在url?keyvalue&key1value1,无论是否是tabbar页面. 对于回退页面,没办法传参. 这个参数是,跳转到页面的时候,跳转到另一个页面,这个页面就是刚开始执行,等数据执行之后,触发onload,传递的参数放在内存中,跳转是内部底层触…

SpringBoot学习小结之RocketMQ

文章目录 前言一、架构设计1.1 架构图1.2 消息1.3 工作流程 二、部署2.1 单机2.2 集群 三、Springboot Producter3.1 准备3.2 pom依赖、yml 配置3.3 普通消息3.4 顺序、批量、延迟消息3.5 事务消息 四、Springboot Consumer4.1 配置4.2 普通Push消费4.3 回复4.4 集群和广播4.5 …

华为造车布局全曝光,对标奔驰、迈巴赫等

文 | Auto芯球 作者 | 雷慢 这一刻&#xff0c;我承认我格局小了&#xff0c; 就在刚刚&#xff0c;余承东曝光了华为智选车的布局计划&#xff0c; 华为问界、智界、享界等&#xff0c;将全面对标奔驰、迈巴赫、劳斯莱斯等车系&#xff0c; 这布局&#xff0c;确实是世界…

Spring MVC+mybatis 项目入门:旅游网(二) dispatcher与controller与Spring MVC

个人博客&#xff1a;Spring MVCmybatis 项目入门:旅游网&#xff08;二&#xff09;dispatcher与controller与Spring MVC | iwtss blog 先看这个&#xff01; 这是18年的文章&#xff0c;回收站里恢复的&#xff0c;现阶段看基本是没有参考意义的&#xff0c;技术老旧脱离时代…

大规模团队的数据库开发,如何用OceanBase工具快速建立企业级账号体系

前言 为了让数据库开发的安全性与可靠性得以充分保障&#xff0c;数据库开发工具的管控能力显得尤为关键。构建一个健全的账号体系&#xff0c;能够协助开发团队实现对数据库开发工具的全方位管控&#xff0c;从而有效防范各类数据安全隐患&#xff0c;确保数据库开发的顺利进…

深度神经网络——什么是混淆矩阵?

概述 混淆矩阵是一种在机器学习和数据科学中广泛使用的分析工具&#xff0c;用于评估分类模型的性能。它通过比较实际类别和模型预测的类别来提供模型性能的详细信息。以下是混淆矩阵的一些关键点&#xff1a; 结构&#xff1a;混淆矩阵是一个表格&#xff0c;通常有两行两列&…