1 獲取請求中參數值
- 在servlet中我們可以通過request.getParameter(String str)來獲取請求中的參數,但是在我們編寫的SpringMVC的應用程序中,在具體請求的方法中並不包含request參數
- 可以使用如下註解獲取請求中的參數
- @RequestParam:獲取請求的參數
- @RequestHeader:獲取請求頭信息
- @CookieValue:獲取cookie中的值
1.1 @RequestParam
- 相當於request.getParameter
- @RequestParam中的屬性
- value:springmvc會將request中參數名爲value值的參數值,傳遞給@RequestParam修飾的形參。如果不填value,那麼@RequestParam修飾的形參名必須與request中參數名一致,否則無法將值正確傳遞
- required:默認值爲true,表示request中必須存在該參數,不存在會報錯,改爲false後,request中不含該參數也不會報錯
- defaultValue:如果request中沒有指定的參數,爲形參定義默認值
@RequestMapping("/request")
public String request(@RequestParam(value = "user",required = false,defaultValue = "hehe") String username){
System.out.println(username);
return "success";
}
1.2 @RequestHeader
- 相當於request.getHeader
- @RequestHeader中的屬性:與@RequestParam中完全相同
@RequestMapping("/header")
public String header(@RequestHeader("User-Agent") String agent){
System.out.println(agent);
return "success";
}
1.3 @CookieValue
- 相當於request.getCookies
- @CookieValue中的屬性:與@RequestParam中完全相同
@RequestMapping("/cookie")
public String cookie(@CookieValue("JSESSIONID") String id){
System.out.println(id);
return "success";
}
1.4 使用對象接收請求中參數值
- 在SpringMVC的控制中,能直接完成對象的屬性賦值操作,不需要人爲干預
- 也就是說,主要參數名和對象的屬性名相同,springmvc會自動將參數值傳入對象屬性值中
- User.java
package com.mashibing.bean;
import java.util.Date;
public class User {
private Integer id;
private String name;
private Integer age;
private Date date;
private Address address;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", date=" + date +
", address=" + address +
'}';
}
}
- Address.java
package com.mashibing.bean;
public class Address {
private String province;
private String city;
private String town;
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getTown() {
return town;
}
public void setTown(String town) {
this.town = town;
}
@Override
public String toString() {
return "Address{" +
"province='" + province + '\'' +
", city='" + city + '\'' +
", town='" + town + '\'' +
'}';
}
}
- login.jsp
<%--
Created by IntelliJ IDEA.
User: root
Date: 2020/3/7
Time: 0:11
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="addUser" method="post">
編號:<input type="text" name="id"/><br>
姓名:<input type="text" name="name"/><br>
年齡:<input type="text" name="age"/><br>
日期:<input type="text" name="date"/><br>
<!--address爲User中的一個屬性,因此設置它的屬性時,必須用address.屬性名-->
省份:<input type="text" name="address.province"/><br>
城市:<input type="text" name="address.city"/><br>
區域:<input type="text" name="address.town"/><br>
<input type="submit" value="submit"/><br>
</form>
</body>
</html>
- UserController.java
package com.mashibing.controller;
import com.mashibing.bean.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class UserController {
@RequestMapping("/addUser")
public String addUser(User user){
System.out.println(user);
return "success";
}
}
2 解決亂碼問題
- 在servlet中,我們瞭解到,爲了解決亂碼問題,最佳方案爲,先在server.xml中添加URIEncoding=“UTF-8”,然後在servlet中request.setCharacterEncoding、response.setContentType
- springmvc中提供了CharacterEncodingFilter過濾器類,可以直接幫我們修改編碼
- 因此對於springmvc中亂碼解決的最佳實踐如下
- 配置CharacterEncodingFilter過濾器
- server.xml中添加URIEncoding=“UTF-8”
- 注意:由於CharacterEncodingFilter中,是通過response.setCharacterEncoding修改編碼,因此要求該編碼值應該與瀏覽器解碼時使用的字符集相同
- 需要注意如果配置了多個過濾器,那麼字符編碼過濾器一定要在最前面,否則失效
- web.xml
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<!--將request和response設置爲該字符集-->
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<!--爲true會同時設置request和response的CharacterEncoding-->
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
3 使用servlet的API
- 可以直接爲方法參數列表中傳入原生的servlet的API的對象,springmvc會自動爲其初始化
- 可以在形參中傳入的servlet的API的對象
- HttpSession:request.getSession
- HttpServletRequest
- HttpServletResponse
- Principal:安全協議相關
- Locale:國際化相關,request.getLocale
- InputStream:request.getInputStream
- OutputStream:response.getOutputStream
- Reader:request.getReader
- Writer:response.getWriter
@RequestMapping("api")
public String api(HttpSession session, HttpServletRequest request, HttpServletResponse response){
request.setAttribute("requestParam","request");
session.setAttribute("sessionParam","session");
return "success";
}
4 傳輸數據到頁面
4.1 使用Model、Map、ModelMap
- SpringMVC中除了可以使用原生servlet的對象傳遞數據之外(請求轉發時,使用同一個request和response),還可以使用Model,ModelMap,Map傳遞數據,放入他們的參數,默認會放入四大作用域中的request作用域中
- Model,ModelMap,Map實際上是同一個對象,他們最終都會轉爲子類BindingAwareModelMap對象
- OutputController.java
package com.mashibing.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.Map;
@Controller
public class OutputController {
@RequestMapping("output1")
public String output1(Model model){
model.addAttribute("msg","hello,Springmvc");
return "output";
}
@RequestMapping("output2")
public String output2(ModelMap model){
model.addAttribute("msg","hello,Springmvc");
return "output";
}
@RequestMapping("output3")
public String output1(Map map){
map.put("msg","hello,Springmvc");
return "output";
}
}
- output.jsp
<%--
Created by IntelliJ IDEA.
User: 含低調
Date: 2020/6/10
Time: 16:39
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<!--通過查看在哪個作用域中打出來值,就可以判斷默認放入哪個作用域中-->
page:${pageScope.msg}<br>
request:${requestScope.msg}<br>
session:${sessionScope.msg}<br>
application:${applicationScope.msg}<br>
msg:${msg}<br>
</body>
</html>
4.2 使用ModelAndView
- 上面介紹的三個對象,最後都會通過某種方式轉換爲ModelAndView對象,最後springmvc會將這個ModelAndView放到request作用域
- 我們可以直接使用ModelAndView將數據放入到request作用域中,然後傳輸數據到頁面
package com.mashibing.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class OutputController {
@RequestMapping("mv")
public ModelAndView mv(){
ModelAndView mv = new ModelAndView();
//指定要跳轉到的頁面
mv.setViewName("output");
mv.addObject("msg","hello.modelAndView");
return mv;
}
}
4.3 將數據保存到session作用域
- servlet中的方式
session = request.getSession();
session.setAttribute("00001","beijing");
- @SessionAttribute:此註解可以表示,當將數據保存到request作用域的同時,也在session作用域中保存一份
- 此註解有兩個參數
- value:表示將指定key值的屬性,放入到session中
- types:表示將對象爲指定類型的屬性放入到session中
- 例如:types = {User.class},那麼model.addAttribute(“heihei”, new User(865542))時,會將heihei也放在session作用域中一份
- 一般不用,因爲有可能會將過多數據設置到session作用中,導致session裝滿或其它異常
package com.mashibing.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.SessionAttributes;
@Controller
//注意此處可以使用數組
@SessionAttributes(value = "msg")
public class OutputController {
@RequestMapping("output1")
public String output1(Model model) {
model.addAttribute("msg", "hello,Springmvc");
System.out.println(model.getClass());
return "output";
}
}
5 @ModelAttribute
- 用在方法上
- 一個控制器可以擁有多個@ModelAttribute方法。同個控制器內的所有這些方法,都會在@RequestMapping方法之前被調用
- 方法通過返回值的方式默認地將添加一個屬性
- 方法接收一個Model對象,然後可以向其中添加任意數量的屬性
- 一個控制器可以擁有多個@ModelAttribute方法。同個控制器內的所有這些方法,都會在@RequestMapping方法之前被調用
- 用在方法參數上
- 標註在方法參數上的@ModelAttribute說明了該方法參數的值將由model中取得。如果model中找不到,那麼該參數會先被實例化,然後被添加到model中。在model中存在以後,請求中所有名稱匹配的參數都會填充到該參數中
- 它可能因爲@SessionAttributes標註的使用已經存在於model中
- 它可能因爲在同個控制器中使用了@ModelAttribute方法已經存在於model中
- 它可能是由URI模板變量和類型轉換中取得的
- 它可能是調用了自身的默認構造器被實例化出來的
- 標註在方法參數上的@ModelAttribute說明了該方法參數的值將由model中取得。如果model中找不到,那麼該參數會先被實例化,然後被添加到model中。在model中存在以後,請求中所有名稱匹配的參數都會填充到該參數中
- 在實際工作中,有些時候我們在修改數據的時候可能只需要修改其中幾個字段,當提交屬性的時候,從form表單中獲取的數據就有可能只包含了部分屬性,此時再向數據庫更新的時候,會將form表單中未賦值的屬性在表中的數據設爲null,導致屬性丟失,因爲對象的封裝是springmvc自動幫我們new的,所以此時需要先將從數據庫獲取的對象保存下來,當提交的時候不是new新的對象,而是在原來的對象上進行屬性覆蓋,此時就需要使用@ModelAttribute註解
- 也就是說,正常情況,@RequestMapping方法中傳入的形參,每次會創建一個新對象,然後根據表單數據中的值,爲其賦值,但如果有了@ModelAttribute,就不會新建對象,而是使用model.addAttribute(“user”,user)中設置到model中的對象,並用表單數據更新該對象中屬性值
- User.java
package com.mashibing.bean;
public class User {
private Integer id;
private String name;
private String password;
private Integer age;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", password='" + password + '\'' +
", age=" + age +
'}';
}
}
- UserController.java
package com.mashibing.controller;
import com.mashibing.bean.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class UserController {
Object o1 = null;
Object o2 = null;
Object o3 = null;
@RequestMapping("update")
//1. 可以省略@ModelAttribute,但如果參數名user和addAttribute中放入屬性的key值不同,就需要添加@ModelAttribute並設置value值
//2. @ModelAttribute會先找model中設置的屬性,如果沒有,會查找@SessionAttributes存放到session中的屬性,如果都沒找到會報錯
public String update(@ModelAttribute("user") User user,Model model){
System.out.println(user);
o2 = model;
//2. 可以看到所有的model都是同一個對象
System.out.println(o1==o2);
//4. 可以看到存儲的user對象也是同一個
System.out.println(user == o3);
return "output";
}
@ModelAttribute
public void MyModelAttribute(Model model){
o1 = model;
User user = new User();
user.setId(1);
user.setName("張三");
user.setAge(12);
user.setPassword("123");
//1. @RequestMapping方法中的user形參,就是該user對象,根據表單數據更新屬性值後得到的
model.addAttribute("user",user);
System.out.println("modelAttribute:"+user);
o3 = user;
}
}
- index.jsp
<%--
Created by IntelliJ IDEA.
User: root
Date: 2020/3/11
Time: 13:45
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<form action="update" method="post">
<input type="hidden" value="1" name="id">
姓名:張三<br>
密碼:<input type="text" name="password"><br>
年齡:<input type="text" name="age"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
- @ModelAttribute方法通過返回值的方式添加屬性
@ModelAttribute("u")
public User MyModelAttribute(Model model){
o1 = model;
User user = new User();
user.setId(1);
user.setName("張三");
user.setAge(12);
user.setPassword("123");
// model.addAttribute("user",user);
System.out.println("modelAttribute:"+user);
o3 = user;
return user;
}
6 請求轉發
- 當使用轉發的時,不會經過視圖解析器,所以要添加完整的路徑名
package com.mashibing.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class ForWardController {
@RequestMapping("/forward01")
public String forward(){
System.out.println("1");
return "forward:/index.jsp";
}
@RequestMapping("/forward02")
public String forward2(){
System.out.println("2");
return "forward:/forward01";
}
}
7 重定向
- 當使用重定向時,不會經過視圖解析器,所以要添加完整的路徑名
package com.mashibing.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class RedirectController {
@RequestMapping("redirect")
public String redirect(){
System.out.println("redirect");
return "redirect:/index.jsp";
}
@RequestMapping("/redirect2")
public String redirect2(){
System.out.println("redirect2");
return "redirect:/redirect";
}
}
8 靜態資源的訪問
- 之前請求html時,是自己配了一個DefaultServlet,太麻煩,springmvc提供了一個更簡單的方式
- applicationContext.xml
<!--1. 此配置表示,如果我們配置的DispatcherServlet不能處理當前請求,那麼將給請求交由tomcat來處理-->
<mvc:default-servlet-handler/>
<!--2. 有時候使用自閉標籤會有問題,最好寫全-->
<!--3. 加上這句話,那麼spring就會讀取DispatcherServlet.properties文件,爲DispatcherServlet中的屬性(九大內置對象)進行初始化,不然默認情況下DispatcherServlet中是沒有任何處理器的-->
<mvc:annotation-driven></mvc:annotation-driven>
9 視圖解析器
- 視圖解析器工作流程
- 將@RequestMapping方法返回的String、View、ModelMap或是ModelAndView都轉換爲一個ModelAndView對象
- 使用ViewResolver對ModelAndView對象進行解析,將該邏輯視圖View對象解析爲一個物理視圖View對象。也就是找到ModelAndView對應的那個視圖,例如jsp文件,然後將這個jsp文件轉爲一個View對象
- 最後調用物理視圖View對象的render()方法進行視圖渲染,也就是寫頁面代碼,得到響應結果
- 如果不在applicationContext中配置視圖解析器,系統也會會默認創建一個InternalResourceViewResolver,但由於沒指定前綴和後綴,因此,@RequestMapping方法中,必須return “/WEB-INF/page/success.jsp”
9.1 自定義視圖解析器
- MyViewController.java
package com.mashibing.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class MyViewController {
@RequestMapping("/myview")
public String myView(Model model){
model.addAttribute("msb","馬士兵");
return "msb:/index";
}
}
- MyViewResolver.java:視圖解析器
package com.mashibing.view;
import org.springframework.core.Ordered;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;
import java.util.Locale;
//1. 自定義的視圖解析器,需要實現ViewResolver和Ordered接口,Ordered接口用於爲視圖解析器排序
public class MyViewResolver implements ViewResolver, Ordered {
private int order = 0;
//viewName就是msb:/index
public View resolveViewName(String viewName, Locale locale) throws Exception {
//2. 如果前綴是msb:開頭的就進行解析
if (viewName.startsWith("msb:")){
System.out.println("msb:");
return new MyView();
}else{
//3. 如果不是,則直接返回null
return null;
}
}
public int getOrder() {
return this.order;
}
public void setOrder(Integer order) {
this.order = order;
}
}
- MyView.java:視圖
package com.mashibing.view;
import org.springframework.core.Ordered;
import org.springframework.web.servlet.View;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
public class MyView implements View {
//1. render:渲染,其實就是根據傳入的model、request、response中的數據,畫個頁面出來。猜測對jsp的渲染,就是執行jsp轉化爲class後的那段代碼
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println("保存的對象是:"+model);
response.setContentType("text/html");
response.getWriter().write("歡迎加入馬士兵教育");
}
//2. 指定返回數據內容的類型
public String getContentType() {
return "text/html";
}
}
- springmvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.mashibing"></context:component-scan>
<!--1. 使用該視圖解析器時,會爲@RequestMapping方法返回的內容加上前綴後綴後,從而找到物理視圖的位置,如果找不到,再交給下一個視圖解析器進行解析-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/page/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!--2. 默認InternalResourceViewResolver先對return的字符串攔截,如果想讓MyViewResolver先執行,也就是修改其getOrder方法的返回值大小,越小越先執行-->
<bean class="com.mashibing.view.MyViewResolver">
<property name="order" value="1"></property>
</bean>
</beans>
- 如果使用註釋的方式,那麼就在MyViewResolver上添加@Component和@Order(1)兩個註釋
10 類型轉換器
- 在日常的企業開發需求中,我們輸入文本框的內容全部都是字符串類型,但是在後端處理的時候我們可以用其他基本類型來接受數據,也可以使用實體類來接受參數,這個是怎麼完成的呢?就是通過SpringMVC提供的類型轉換器,SpringMVC內部提供了非常豐富的類型轉換器的支持,但是有些情況下有可能難以滿足我們的需求,因此需要我們自己實現
10.1 自定義類型轉換器
- User.java
package com.mashibing.bean;
public class User {
private Integer id;
private String name;
private Integer age;
private String gender;
public User() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
'}';
}
}
- MyConverter.java
package com.mashibing.converter;
import com.mashibing.bean.User;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
@Component
public class MyConverter implements Converter<String, User> {
public User convert(String source) {
User user = null;
String[] split = source.split("-");
if (source!=null && split.length==4){
user = new User();
user.setId(Integer.parseInt(split[0]));
user.setName(split[1]);
user.setAge(Integer.parseInt(split[2]));
user.setGender(split[3]);
}
return user;
}
}
- UserController.java
package com.mashibing.controller;
import com.mashibing.bean.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class UserController {
@RequestMapping("/user")
//1. 注意:形參名user,必須和表單中的屬性名相同,不然轉換器不知道具體應該將哪個屬性的值進行轉換
public String add(User user, Model model){
System.out.println(user);
model.addAttribute("user",user);
return "success";
}
}
- linux.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>123djfdkjfkjfkd</title>
</head>
<body>
<form action="/user">
user:<input type="text" name="user"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
- success.jsp
<%--
Created by IntelliJ IDEA.
User: root
Date: 2020/3/12
Time: 21:36
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${requestScope.user}
</body>
</html>
- springmvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.mashibing"></context:component-scan>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<bean class="com.mashibing.view.MyViewResolver">
<property name="order" value="1"></property>
</bean>
<!--1. 此處不寫會報錯-->
<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
<!--2. 添加自定義類型轉換器到ConversionServiceFactoryBean,bean的id必須爲conversionService-->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<ref bean="myConverter"></ref>
</set>
</property>
</bean>
</beans>
10.2 自定義日期格式化轉換器
- 如果使用默認的類型轉換器,那麼在輸入日期時,必須要使用/作爲分隔,例如2099/12/31
- 有時候我們經常需要在頁面添加日期等相關信息,此時需要制定日期格式化轉換器,此操作非常簡單:只需要在單獨的屬性上添加@DateTimeFormat註解即可,指定對應的格式
- User.java
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date birth;
...
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
...
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
", birth=" + birth +
'}';
}
- linux.html
<form action="dateConvertion" method="post">
編號:<input type="text" name="id"><br>
姓名:<input type="text" name="name"><br>
年齡:<input type="text" name="age"><br>
性別:<input type="text" name="gender"><br>
日期:<input type="text" name="birth"><br>
<input type="submit" value="提交">
</form>
- DateConvertionController.java
package com.mashibing.controller;
import com.mashibing.bean.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class DateConvertionController {
@RequestMapping("dateConvertion")
public String dateConvertion(User user){
System.out.println(user);
return "hello";
}
}
-
想使用日期格式轉換器,正常情況下,根本無需配置conversionService,但如果同時配置了自定義類型轉換器之後,那麼日期格式轉化會失效,原因在於ConversionServiceFactoryBean對象中僅有一個屬性converters,而@DateTimeFormat需要放入ConversionServiceFactoryBean的formatters屬性中,因此可以使用FormattingConversionServiceFactoryBean替換ConversionServiceFactoryBean
-
springmvc.xml
<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<ref bean="myConverter"></ref>
</set>
</property>
</bean>
11 數據校驗
- JSR303(Java Specification Requests意思是Java 規範提案):是Java爲Bean數據合法性校驗提供的標準框架,它已經包含在 JavaEE 6.0 中。JSR 303 通過在Bean屬性上標註類似於 @NotNull、@Max 等標準的註解指定校驗規則,並通過標準的驗證接口對 Bean 進行驗證
- Hibernate Validator中提供了具體的實現,並添加了額外的註解
- spring中擁有自己的數據校驗框架,同時支持JSR303標準的校驗框架,可以在通過添加註解的方式進行數據校驗。但在spring中本身沒有提供JSR303的實現,需要導入依賴的包,此處導入hibernate-validator作爲具體實現
- pom.xml,注意因爲新增了hibernate-validator的jar包,需要更新Artifacts,不然不會報錯,但校驗不生效
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mashibing</groupId>
<artifactId>springmvc_viewResolver</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.1.0.Final</version>
</dependency>
</dependencies>
</project>
- appicationContext.xml
<!--數據校驗需要LocalValidatorFactroyBean,<mvc:annotation-driven/> 會默認裝配好一個 LocalValidatorFactoryBean-->
<mvc:annotation-driven ></mvc:annotation-driven>
- index.jsp
<%--
Created by IntelliJ IDEA.
User: root
Date: 2020/3/12
Time: 15:23
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<form action="dataValidate" method="post">
編號:<input type="text" name="id"><br>
姓名:<input type="text" name="name"><br>
年齡:<input type="text" name="age"><br>
性別:<input type="text" name="gender"><br>
日期:<input type="text" name="birth"><br>
郵箱:<input type="text" name="email"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
- DataValidateController.java
package com.mashibing.controller;
import com.mashibing.bean.User;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.validation.Valid;
@Controller
public class DataValidateController {
@RequestMapping("/dataValidate")
//1. 使用@Valid註解,表示爲user添加校驗,此處也可以使用註解@Validated,功能與@Valid基本相同,這兩個註釋前者是spring提供的,後者是JSR303提供的
//2. 當校驗失敗時,默認只在後臺日誌中輸出錯誤信息,瀏覽器中看不到,但如果參數列表中加入bindingResult參數,springmvc後臺就不再報錯,而是將報錯信息轉化爲一個bindingResult對象
public String validate(@Valid User user, BindingResult bindingResult) {
System.out.println(user);
if (bindingResult.hasErrors()) {
System.out.println("驗證失敗");
return "redirect:/index.jsp";
} else {
System.out.println("驗證成功");
return "hello";
}
}
}
- User.java
package com.mashibing.bean;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.Length;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Past;
import java.util.Date;
public class User {
private Integer id;
//具體加對哪個屬性有什麼限制
@NotNull
@Length(min = 5,max = 10)
private String name;
private Integer age;
private String gender;
@Past
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date birth;
@Email
private String email;
public User() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
", birth=" + birth +
", email='" + email + '\'' +
'}';
}
}
11.1 使用原生表單在頁面顯示錯誤信息
- index.jsp
<%--
Created by IntelliJ IDEA.
User: root
Date: 2020/3/12
Time: 15:23
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<form action="/dataValidate" method="post">
編號:<input type="text" name="id">${errors.id}<br>
姓名:<input type="text" name="name">${errors.name}<br>
年齡:<input type="text" name="age">${errors.age}<br>
性別:<input type="text" name="gender">${errors.gender}<br>
日期:<input type="text" name="birth">${errors.birth}<br>
郵箱:<input type="text" name="email">${errors.email}<br>
<input type="submit" value="提交">
</form>
</body>
</html>
- DataValidateController
package com.mashibing.controller;
import com.mashibing.bean.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.validation.Valid;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Controller
public class DataValidateController {
@RequestMapping("/dataValidate")
public String validate(@Valid User user, BindingResult bindingResult, Model model) {
System.out.println(user);
Map<String, Object> errorsMap = new HashMap<String, Object>();
if (bindingResult.hasErrors()) {
System.out.println("驗證失敗");
//1. 獲取當前的所有錯誤
List<FieldError> fieldErrors = bindingResult.getFieldErrors();
for (FieldError fieldError : fieldErrors) {
System.out.println(fieldError.getDefaultMessage());
System.out.println(fieldError.getField());
//2. 可以把這些錯誤信息放到一個map中
errorsMap.put(fieldError.getField(), fieldError.getDefaultMessage());
}
//3. 然後將這個map整體放到request作用域中,之後在jsp中,就可以直接獲取對應的錯誤信息
model.addAttribute("errors", errorsMap);
//4. 返回原來的登錄界面
return "forward:/index.jsp";
} else {
System.out.println("驗證成功");
return "success";
}
}
}