2. springmvc的基本用法

1 獲取請求中參數值

  1. 在servlet中我們可以通過request.getParameter(String str)來獲取請求中的參數,但是在我們編寫的SpringMVC的應用程序中,在具體請求的方法中並不包含request參數
  2. 可以使用如下註解獲取請求中的參數
    1. @RequestParam:獲取請求的參數
    2. @RequestHeader:獲取請求頭信息
    3. @CookieValue:獲取cookie中的值

1.1 @RequestParam

  1. 相當於request.getParameter
  2. @RequestParam中的屬性
    1. value:springmvc會將request中參數名爲value值的參數值,傳遞給@RequestParam修飾的形參。如果不填value,那麼@RequestParam修飾的形參名必須與request中參數名一致,否則無法將值正確傳遞
    2. required:默認值爲true,表示request中必須存在該參數,不存在會報錯,改爲false後,request中不含該參數也不會報錯
    3. 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

  1. 相當於request.getHeader
  2. @RequestHeader中的屬性:與@RequestParam中完全相同
@RequestMapping("/header")
public String header(@RequestHeader("User-Agent") String agent){
    System.out.println(agent);
    return "success";
}

1.3 @CookieValue

  1. 相當於request.getCookies
  2. @CookieValue中的屬性:與@RequestParam中完全相同
@RequestMapping("/cookie")
public String cookie(@CookieValue("JSESSIONID") String id){
    System.out.println(id);
    return "success";
}

1.4 使用對象接收請求中參數值

  1. 在SpringMVC的控制中,能直接完成對象的屬性賦值操作,不需要人爲干預
  2. 也就是說,主要參數名和對象的屬性名相同,springmvc會自動將參數值傳入對象屬性值中
  3. 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 +
                '}';
    }
}
  1. 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 + '\'' +
                '}';
    }
}
  1. 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>
  1. 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 解決亂碼問題

  1. 在servlet中,我們瞭解到,爲了解決亂碼問題,最佳方案爲,先在server.xml中添加URIEncoding=“UTF-8”,然後在servlet中request.setCharacterEncoding、response.setContentType
  2. springmvc中提供了CharacterEncodingFilter過濾器類,可以直接幫我們修改編碼
  3. 因此對於springmvc中亂碼解決的最佳實踐如下
    1. 配置CharacterEncodingFilter過濾器
    2. server.xml中添加URIEncoding=“UTF-8”
    3. 注意:由於CharacterEncodingFilter中,是通過response.setCharacterEncoding修改編碼,因此要求該編碼值應該與瀏覽器解碼時使用的字符集相同
  4. 需要注意如果配置了多個過濾器,那麼字符編碼過濾器一定要在最前面,否則失效
  5. 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

  1. 可以直接爲方法參數列表中傳入原生的servlet的API的對象,springmvc會自動爲其初始化
  2. 可以在形參中傳入的servlet的API的對象
    1. HttpSession:request.getSession
    2. HttpServletRequest
    3. HttpServletResponse
    4. Principal:安全協議相關
    5. Locale:國際化相關,request.getLocale
    6. InputStream:request.getInputStream
    7. OutputStream:response.getOutputStream
    8. Reader:request.getReader
    9. 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

  1. SpringMVC中除了可以使用原生servlet的對象傳遞數據之外(請求轉發時,使用同一個request和response),還可以使用Model,ModelMap,Map傳遞數據,放入他們的參數,默認會放入四大作用域中的request作用域中
  2. Model,ModelMap,Map實際上是同一個對象,他們最終都會轉爲子類BindingAwareModelMap對象
  3. 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";
    }
}
  1. 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

  1. 上面介紹的三個對象,最後都會通過某種方式轉換爲ModelAndView對象,最後springmvc會將這個ModelAndView放到request作用域
  2. 我們可以直接使用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作用域

  1. servlet中的方式
session = request.getSession();
session.setAttribute("00001","beijing");
  1. @SessionAttribute:此註解可以表示,當將數據保存到request作用域的同時,也在session作用域中保存一份
  2. 此註解有兩個參數
    1. value:表示將指定key值的屬性,放入到session中
    2. types:表示將對象爲指定類型的屬性放入到session中
      1. 例如:types = {User.class},那麼model.addAttribute(“heihei”, new User(865542))時,會將heihei也放在session作用域中一份
      2. 一般不用,因爲有可能會將過多數據設置到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

  1. 用在方法上
    1. 一個控制器可以擁有多個@ModelAttribute方法。同個控制器內的所有這些方法,都會在@RequestMapping方法之前被調用
      1. 方法通過返回值的方式默認地將添加一個屬性
      2. 方法接收一個Model對象,然後可以向其中添加任意數量的屬性
  2. 用在方法參數上
    1. 標註在方法參數上的@ModelAttribute說明了該方法參數的值將由model中取得。如果model中找不到,那麼該參數會先被實例化,然後被添加到model中。在model中存在以後,請求中所有名稱匹配的參數都會填充到該參數中
      1. 它可能因爲@SessionAttributes標註的使用已經存在於model中
      2. 它可能因爲在同個控制器中使用了@ModelAttribute方法已經存在於model中
      3. 它可能是由URI模板變量和類型轉換中取得的
      4. 它可能是調用了自身的默認構造器被實例化出來的
  3. 在實際工作中,有些時候我們在修改數據的時候可能只需要修改其中幾個字段,當提交屬性的時候,從form表單中獲取的數據就有可能只包含了部分屬性,此時再向數據庫更新的時候,會將form表單中未賦值的屬性在表中的數據設爲null,導致屬性丟失,因爲對象的封裝是springmvc自動幫我們new的,所以此時需要先將從數據庫獲取的對象保存下來,當提交的時候不是new新的對象,而是在原來的對象上進行屬性覆蓋,此時就需要使用@ModelAttribute註解
  4. 也就是說,正常情況,@RequestMapping方法中傳入的形參,每次會創建一個新對象,然後根據表單數據中的值,爲其賦值,但如果有了@ModelAttribute,就不會新建對象,而是使用model.addAttribute(“user”,user)中設置到model中的對象,並用表單數據更新該對象中屬性值
  5. 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 +
                '}';
    }
}
  1. 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;
    }
}
  1. 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>

  1. @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 請求轉發

  1. 當使用轉發的時,不會經過視圖解析器,所以要添加完整的路徑名
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 重定向

  1. 當使用重定向時,不會經過視圖解析器,所以要添加完整的路徑名
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 靜態資源的訪問

  1. 之前請求html時,是自己配了一個DefaultServlet,太麻煩,springmvc提供了一個更簡單的方式
  2. applicationContext.xml
<!--1. 此配置表示,如果我們配置的DispatcherServlet不能處理當前請求,那麼將給請求交由tomcat來處理-->
<mvc:default-servlet-handler/>
<!--2. 有時候使用自閉標籤會有問題,最好寫全-->
<!--3. 加上這句話,那麼spring就會讀取DispatcherServlet.properties文件,爲DispatcherServlet中的屬性(九大內置對象)進行初始化,不然默認情況下DispatcherServlet中是沒有任何處理器的-->
<mvc:annotation-driven></mvc:annotation-driven>

9 視圖解析器

  1. 視圖解析器工作流程
    1. 將@RequestMapping方法返回的String、View、ModelMap或是ModelAndView都轉換爲一個ModelAndView對象
    2. 使用ViewResolver對ModelAndView對象進行解析,將該邏輯視圖View對象解析爲一個物理視圖View對象。也就是找到ModelAndView對應的那個視圖,例如jsp文件,然後將這個jsp文件轉爲一個View對象
    3. 最後調用物理視圖View對象的render()方法進行視圖渲染,也就是寫頁面代碼,得到響應結果
  2. 如果不在applicationContext中配置視圖解析器,系統也會會默認創建一個InternalResourceViewResolver,但由於沒指定前綴和後綴,因此,@RequestMapping方法中,必須return “/WEB-INF/page/success.jsp”

9.1 自定義視圖解析器

  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";
    }
}
  1. 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;
    }
}

  1. 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";
    }
}
  1. 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>
  1. 如果使用註釋的方式,那麼就在MyViewResolver上添加@Component和@Order(1)兩個註釋

10 類型轉換器

  1. 在日常的企業開發需求中,我們輸入文本框的內容全部都是字符串類型,但是在後端處理的時候我們可以用其他基本類型來接受數據,也可以使用實體類來接受參數,這個是怎麼完成的呢?就是通過SpringMVC提供的類型轉換器,SpringMVC內部提供了非常豐富的類型轉換器的支持,但是有些情況下有可能難以滿足我們的需求,因此需要我們自己實現

10.1 自定義類型轉換器

  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 + '\'' +
                '}';
    }
}
  1. 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;
    }
}
  1. 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";
    }
}
  1. 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>
  1. 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>

  1. 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 自定義日期格式化轉換器

  1. 如果使用默認的類型轉換器,那麼在輸入日期時,必須要使用/作爲分隔,例如2099/12/31
  2. 有時候我們經常需要在頁面添加日期等相關信息,此時需要制定日期格式化轉換器,此操作非常簡單:只需要在單獨的屬性上添加@DateTimeFormat註解即可,指定對應的格式
  3. 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 +
            '}';
}
  1. 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>
  1. 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";
    }
}
  1. 想使用日期格式轉換器,正常情況下,根本無需配置conversionService,但如果同時配置了自定義類型轉換器之後,那麼日期格式轉化會失效,原因在於ConversionServiceFactoryBean對象中僅有一個屬性converters,而@DateTimeFormat需要放入ConversionServiceFactoryBean的formatters屬性中,因此可以使用FormattingConversionServiceFactoryBean替換ConversionServiceFactoryBean

  2. 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 數據校驗

  1. JSR303(Java Specification Requests意思是Java 規範提案):是Java爲Bean數據合法性校驗提供的標準框架,它已經包含在 JavaEE 6.0 中。JSR 303 通過在Bean屬性上標註類似於 @NotNull、@Max 等標準的註解指定校驗規則,並通過標準的驗證接口對 Bean 進行驗證
    在這裏插入圖片描述
  2. Hibernate Validator中提供了具體的實現,並添加了額外的註解
    在這裏插入圖片描述
  3. spring中擁有自己的數據校驗框架,同時支持JSR303標準的校驗框架,可以在通過添加註解的方式進行數據校驗。但在spring中本身沒有提供JSR303的實現,需要導入依賴的包,此處導入hibernate-validator作爲具體實現
  4. 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>
  1. appicationContext.xml
<!--數據校驗需要LocalValidatorFactroyBean,<mvc:annotation-driven/> 會默認裝配好一個 LocalValidatorFactoryBean-->
<mvc:annotation-driven ></mvc:annotation-driven>
  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"><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>

  1. 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";
        }
    }
}
  1. 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 使用原生表單在頁面顯示錯誤信息

  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>
  1. 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";
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章