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.pswp.cn/bicheng/16204.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/16204.shtml
英文地址,請注明出處:http://en.pswp.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…

python文件IO之pickle 模塊讀寫對象數據

可以向一個文件中寫入字符串&#xff0c;讀取后也是讀取字符串形式&#xff0c;但是不能直接向文件中寫入像列表這樣的對象&#xff0c;需要 pickle 等模塊才行。 pickle 模塊介紹 pickle 模塊使用強大且有效的算法來進行序列化和反序列化。 序列化是指將一個對象轉換為能夠存…

前端面試手冊

前端面試手冊 崗位職責&#xff1a; 1&#xff0e;熟悉公司業務&#xff0c;能獨立高效高質地完成任務&#xff0c;負責功能的開發、測試、上線、維護&#xff1b; 2&#xff0e;負責推動、優化前端基礎架構、組件抽象&#xff0c;提升開發效率&#xff1b; 3&#xff0e;關…

四. TensorRT模型部署優化-模型部署的基礎知識

目錄 前言0. 簡介1. FLOPS2. TOPS3. HPC的排行&#xff0c;CPU/GPU比較4. FLOPs5. FLOPS是如何計算的6. CUDA Core vs Tensor Core總結參考 前言 自動駕駛之心推出的 《CUDA與TensorRT部署實戰課程》&#xff0c;鏈接。記錄下個人學習筆記&#xff0c;僅供自己參考 本次課程我們…

記一次Spark cache table導致的數據問題以及思考

目前在做 Spark 升級(3.1.1升級到3.5.0)的時候&#xff0c;遇到了cache table導致的數據重復問題&#xff0c;這種情況一般來說是很少見的&#xff0c;因為一般很少用cache table語句。 當然該問題已經在Spark3.5.1已經解決了,可以查看對應的 SPARK-46995和SPARK-45592 從以上的…

最小二乘法-超詳細推導(轉換為矩陣乘法推導,矩陣求導推導)

最小二乘法就是讓均方誤差最小。 下面是損失函數轉換為矩陣方式的詳解 如何讓其最小&#xff0c;在導數為0的地方取極小值。 問&#xff1a;導數為0的地方可能去極大值&#xff0c;也可能是極小值&#xff0c;憑什么說導數為0就是極小值&#xff1f; 答&#xff1a;因為使用…

android ndc firewall 命令type 黑名單 白名單差異

可以看到以白名單方式使能防火墻&#xff0c;fw_FORWARD fw_INPUT fw_OUTPUT 的操作是DROP或REJEDCT。即默認所有應用不允許上網&#xff0c;需要 XXX:/ # ndc firewall enable whitelist 200 0 Firewall command succeeded XXX:/ # iptables -t filter -L Chain INPUT (polic…

酷黑簡潔大氣體育直播自適應模板賽事直播門戶網站源碼

源碼名稱&#xff1a;酷黑簡潔大氣體育直播自適應模板賽事直播門戶網站源碼 開發環境&#xff1a;帝國cms 7.5 安裝環境&#xff1a;phpmysql 支持PC與手機端同步生成html&#xff08;多端同步生成插件&#xff09; 帶軟件采集&#xff0c;可以掛著自動采集發布&#xff0c;無…

【HSQL001】HiveSQL內置函數手冊總結(更新中)

1.熟悉、梳理、總結下Hive SQL相關知識體系。 2.日常研發過程中使用較少&#xff0c;隨著時間的推移&#xff0c;很快就忘得一干二凈&#xff0c;所以梳理總結下&#xff0c;以備日常使用參考 3.歡迎批評指正&#xff0c;跪謝一鍵三連&#xff01; 文章目錄 1.函數清單 1.函數清…

某某某加固系統分析

某某某加固系統內核so dump和修復&#xff1a; 某某某加固系統采取了內外兩層native代碼模式&#xff0c;外層主要為了保護內層核心代碼&#xff0c;從分析來看外層模塊主要用來反調試&#xff0c;釋放內層模塊&#xff0c;維護內存模塊的某些運行環境達到防止分離內外模塊&am…

網上比較受認可的賺錢軟件有哪些?眾多兼職選擇中總有一個適合你

在這個互聯網高速發展的時代&#xff0c;網上賺錢似乎成了一種潮流。但是&#xff0c;你是否還在靠運氣尋找賺錢的機會&#xff1f;是否還在為找不到靠譜的兼職平臺而苦惱&#xff1f; 今天&#xff0c;就為你揭秘那些真正靠譜的網上賺錢平臺&#xff0c;讓你的賺錢之路不再迷…

等保測評的流程是怎樣的

等保測評概述 等保測評&#xff0c;即信息安全等級保護測評&#xff0c;是指對信息系統安全性能進行等級評估的過程。其目的是通過評估系統的安全性能&#xff0c;為系統提供一個安全等級&#xff0c;并規定相應的保護措施。等保測評的流程通常包括定級、備案、安全建設、等級測…

Python--List列表

list列表?? 1高級數據類型 Python中的數據類型可以分為&#xff1a;數字型&#xff08;基本數據類型&#xff09;和非數字型&#xff08;高級數據類型&#xff09; ●數字型包含&#xff1a;整型int、浮點型float、布爾型bool、復數型complex ●非數字型包含&#xff1a;字符…

TypeScript-type注解對象類型

type注解對象類型 在TS中對于對象數據的類型注解&#xff0c;除了使用interface之外還可以使用類型別名來進行注解&#xff0c;作用類似 type Person {name: stringage: number }const p:Person {name: lily,age: 16 } type 交叉類型&模擬繼承 類型別名配合交叉類型…

docker創建的rabbitmq,啟動容器時報:Failed to create thread: Operation not permitted (1)

原因&#xff1a;docker內的用戶權限受限 啟動docker時加上參數 --privilegedtrue docker run --privilegedtrue -d --name rabbitmq --restartalways -p 5671:5671 -p 5672:5672 -p 15672:15672 -p 15671:15671 -p 25672:25672 -v /home/rabbitmq/data/:/var/rabbitm…