SpringMVC框架學習重點概要筆記(1.0版本)

Spring MVC

Spring MVC 是目前主流的實現 MVC 設計模式的企業級開發框架,Spring 框架的一個子模塊,無需整合,開發起來更加便捷。

什麼是 MVC 設計模式?

將應用程序分爲 Controller、Model、View 三層,Controller 接收客戶端請求,調用 Model 生成業務數據,傳遞給 View。

Spring MVC 就是對這套流程的封裝,屏蔽了很多底層代碼,開放出接口,讓開發者可以更加輕鬆、便捷地完成基於 MVC 模式的 Web 開發。

Spring MVC 的核心組件

  • DispatcherServlet:前置控制器,是整個流程控制的核心,控制其他組件的執行,進行統一調度,降低組件之間的耦合性,相當於總指揮。
  • Handler:處理器,完成具體的業務邏輯,相當於 Servlet 或 Action。
  • HandlerMapping:DispatcherServlet 接收到請求之後,通過 HandlerMapping 將不同的請求映射到不同的 Handler。
  • HandlerInterceptor:處理器攔截器,是一個接口,如果需要完成一些攔截處理,可以實現該接口。
  • HandlerExecutionChain:處理器執行鏈,包括兩部分內容:Handler 和 HandlerInterceptor(系統會有一個默認的 HandlerInterceptor,如果需要額外設置攔截,可以添加攔截器)。
  • HandlerAdapter:處理器適配器,Handler 執行業務方法之前,需要進行一系列的操作,包括表單數據的驗證、數據類型的轉換、將表單數據封裝到 JavaBean 等,這些操作都是由 HandlerApater 來完成,開發者只需將注意力集中業務邏輯的處理上,DispatcherServlet 通過 HandlerAdapter 執行不同的 Handler。
  • ModelAndView:裝載了模型數據和視圖信息,作爲 Handler 的處理結果,返回給 DispatcherServlet。
  • ViewResolver:視圖解析器,DispatcheServlet 通過它將邏輯視圖解析爲物理視圖,最終將渲染結果響應給客戶端。

Spring MVC 的工作流程

  • 客戶端請求被 DisptacherServlet 接收。
  • 根據 HandlerMapping 映射到 Handler。
  • 生成 Handler 和 HandlerInterceptor。
  • Handler 和 HandlerInterceptor 以 HandlerExecutionChain 的形式一併返回給 DisptacherServlet。
  • DispatcherServlet 通過 HandlerAdapter 調用 Handler 的方法完成業務邏輯處理。
  • Handler 返回一個 ModelAndView 給 DispatcherServlet。
  • DispatcherServlet 將獲取的 ModelAndView 對象傳給 ViewResolver 視圖解析器,將邏輯視圖解析爲物理視圖 View。
  • ViewResovler 返回一個 View 給 DispatcherServlet。
  • DispatcherServlet 根據 View 進行視圖渲染(將模型數據 Model 填充到視圖 View 中)。
  • DispatcherServlet 將渲染後的結果響應給客戶端。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-eb6uDj47-1585898652340)(/Users/southwind/Library/Application Support/typora-user-images/image-20190313111136254.png)]

Spring MVC 流程非常複雜,實際開發中很簡單,因爲大部分的組件不需要開發者創建、管理,只需要通過配置文件的方式完成配置即可,真正需要開發者進行處理的只有 Handler 、View。

如何使用?

  • 創建 Maven 工程,pom.xml
<dependencies>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.0.11.RELEASE</version>
    </dependency>

</dependencies>
  • 在 web.xml 中配置 DispatcherServlet。
<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  
  <servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:springmvc.xml</param-value>
    </init-param>
  </servlet>
  
  <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
  
</web-app>
  • 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 http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">

    <!-- 自動掃描 -->
    <context:component-scan base-package="com.southwind"></context:component-scan>

    <!-- 配置視圖解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

</beans>
  • 創建 Handler
package com.southwind.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class HelloHandler {

    @RequestMapping("/index")
    public String index(){
        System.out.println("執行了index...");
        return "index";
    }
}

Spring MVC 註解

  • @RequestMapping

Spring MVC 通過 @RequestMapping 註解將 URL 請求與業務方法進行映射,在 Handler 的類定義處以及方法定義處都可以添加 @RequestMapping ,在類定義處添加,相當於客戶端多了一層訪問路徑。

  • @Controller

@Controller 在類定義處添加,將該類交個 IoC 容器來管理(結合 springmvc.xml 的自動掃描配置使用),同時使其成爲一個控制器,可以接收客戶端請求。

package com.southwind.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/hello")
public class HelloHandler {

    @RequestMapping("/index")
    public String index(){
        System.out.println("執行了index...");
        return "index";
    }
}
  • @RequestMapping 相關參數

1、value:指定 URL 請求的實際地址,是 @RequestMapping 的默認值。

@RequestMapping("/index")
public String index(){
    System.out.println("執行了index...");
    return "index";
}

等於

@RequestMapping(value="/index")
public String index(){
    System.out.println("執行了index...");
    return "index";
}

2、method:指定請求的 method 類型,GET、POST、PUT、DELET。

@RequestMapping(value = "/index",method = RequestMethod.GET)
public String index(){
    System.out.println("執行了index...");
    return "index";
}

上述代碼表示 index 方法只能接收 GET 請求。

3、params:指定請求中必須包含某些參數,否則無法調用該方法。

@RequestMapping(value = "/index",method = RequestMethod.GET,params = {"name","id=10"})
public String index(){
    System.out.println("執行了index...");
    return "index";
}

上述代碼表示請求中必須包含 name 和 id 兩個參數,同時 id 的值必須是 10。

關於參數綁定,在形參列表中通過添加 @RequestParam 註解完成 HTTP 請求參數與業務方法形參的映射。

@RequestMapping(value = "/index",method = RequestMethod.GET,params = {"name","id=10"})
public String index(@RequestParam("name") String str,@RequestParam("id") int age){
    System.out.println(str);
    System.out.println(age);
    System.out.println("執行了index...");
    return "index";
}

上述代碼表示將請求的參數 name 和 id 分別賦給了形參 str 和 age ,同時自動完成了數據類型轉換,將 “10” 轉爲了 int 類型的 10,再賦給 age,這些工作都是由 HandlerAdapter 來完成的。

Spring MVC 也支持 RESTful 風格的 URL。

傳統類型:http://localhost:8080/hello/index?name=zhangsan&id=10

REST:http://localhost:8080/hello/index/zhangsan/10

@RequestMapping("/rest/{name}/{id}")
public String rest(@PathVariable("name") String name,@PathVariable("id") int id){
    System.out.println(name);
    System.out.println(id);
    return "index";
}

通過 @PathVariable 註解完成請求參數與形參的映射。

  • 映射 Cookie

Spring MVC 通過映射可以直接在業務方法中獲取 Cookie 的值。

@RequestMapping("/cookie")
public String cookie(@CookieValue(value = "JSESSIONID") String sessionId){
    System.out.println(sessionId);
    return "index";
}

  • 使用 JavaBean 綁定參數

Spring MVC 會根據請求參數名和 JavaBean 屬性名進行自動匹配,自動爲對象填充屬性值,同時支持及聯屬性。

package com.southwind.entity;

import lombok.Data;

@Data
public class Address {
    private String value;
}

package com.southwind.entity;

import lombok.Data;

@Data
public class User {
    private long id;
    private String name;
    private Address address;
}

<%--
  Created by IntelliJ IDEA.
  User: southwind
  Date: 2019-03-13
  Time: 15:33
  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="/hello/save" method="post">
        用戶id:<input type="text" name="id"/><br/>
        用戶名:<input type="text" name="name"/><br/>
        用戶地址:<input type="text" name="address.value"/><br/>
        <input type="submit" value="註冊"/>
    </form>
</body>
</html>

@RequestMapping(value = "/save",method = RequestMethod.POST)
public String save(User user){
    System.out.println(user);
    return "index";
}

如果出現中文亂碼問題,只需在 web.xml 添加 Spring MVC 自帶的過濾器即可。

<filter>
    <filter-name>encodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

  • JSP 頁面的轉發和重定向:

Spring MVC 默認是以轉發的形式響應 JSP。

1、轉發

@RequestMapping("/forward")
public String forward(){
    return "forward:/index.jsp";
    //        return "index";
}

2、重定向

@RequestMapping("/redirect")
public String redirect(){
    return "redirect:/index.jsp";
}

Spring MVC 數據綁定

數據綁定:在後端的業務方法中直接獲取客戶端 HTTP 請求中的參數,將請求參數映射到業務方法的形參中,Spring MVC 中數據綁定的工作是由 HandlerAdapter 來完成的。

  • 基本數據類型
@RequestMapping("/baseType")
@ResponseBody
public String baseType(int id){
    return id+"";
}

@ResponseBody 表示 Spring MVC 會直接將業務方法的返回值響應給客戶端,如果不加 @ResponseBody 註解,Spring MVC 會將業務方法的放回值傳遞給 DispatcherServlet,再由 DisptacherServlet 調用 ViewResolver 對返回值進行解析,映射到一個 JSP 資源。

  • 包裝類
@RequestMapping("/packageType")
@ResponseBody
public String packageType(@RequestParam(value = "num",required = false,defaultValue = "0") Integer id){
    return id+"";
}

包裝類可以接收 null,當 HTTP 請求沒有參數時,使用包裝類定義形參的數據類型,程序不會拋出異常。

@RequestParam

value = “num”:將 HTTP 請求中名爲 num 的參數賦給形參 id。

requried:設置 num 是否爲必填項,true 表示必填,false 表示非必填,可省略。

defaultValue = “0”:如果 HTTP 請求中沒有 num 參數,默認值爲0.

  • 數組
@RestController
@RequestMapping("/data")
public class DataBindHandler {
    @RequestMapping("/array")
    public String array(String[] name){
        String str = Arrays.toString(name);
        return str;
    }
}

@RestController 表示該控制器會直接將業務方法的返回值響應給客戶端,不進行視圖解析。

@Controller 表示該控制器的每一個業務方法的返回值都會交給視圖解析器進行解析,如果只需要將數據響應給客戶端,而不需要進行視圖解析,則需要在對應的業務方法定義處添加 @ResponseBody。

@RestController
@RequestMapping("/data")
public class DataBindHandler {
    @RequestMapping("/array")
    public String array(String[] name){
        String str = Arrays.toString(name);
        return str;
    }
}

等同於

@Controller
@RequestMapping("/data")
public class DataBindHandler {
    @RequestMapping("/array")
    @ResponseBody
    public String array(String[] name){
        String str = Arrays.toString(name);
        return str;
    }
}

  • List

Spring MVC 不支持 List 類型的直接轉換,需要對 List 集合進行包裝。

集合封裝類

package com.southwind.entity;

import lombok.Data;

import java.util.List;

@Data
public class UserList {
    private List<User> users;
}

JSP

<%--
  Created by IntelliJ IDEA.
  User: southwind
  Date: 2019-03-14
  Time: 09:12
  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="/data/list" method="post">
        用戶1編號:<input type="text" name="users[0].id"/><br/>
        用戶1名稱:<input type="text" name="users[0].name"/><br/>
        用戶2編號:<input type="text" name="users[1].id"/><br/>
        用戶2名稱:<input type="text" name="users[1].name"/><br/>
        用戶3編號:<input type="text" name="users[2].id"/><br/>
        用戶3名稱:<input type="text" name="users[2].name"/><br/>
        <input type="submit" value="提交"/>
    </form>
</body>
</html>

業務方法

@RequestMapping("/list")
public String list(UserList userList){
    StringBuffer str = new StringBuffer();
    for(User user:userList.getUsers()){
        str.append(user);
    }
    return str.toString();
}

處理 @ResponseBody 中文亂碼,在 springmvc.xml 中配置消息轉換器。

<mvc:annotation-driven>
    <!-- 消息轉換器 -->
    <mvc:message-converters register-defaults="true">
        <bean class="org.springframework.http.converter.StringHttpMessageConverter">
            <property name="supportedMediaTypes" value="text/html;charset=UTF-8"></property>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

  • Map

自定義封裝類

package com.southwind.entity;

import lombok.Data;

import java.util.Map;

@Data
public class UserMap {
    private Map<String,User> users;
}

業務方法

@RequestMapping("/map")
public String map(UserMap userMap){
    StringBuffer str = new StringBuffer();
    for(String key:userMap.getUsers().keySet()){
        User user = userMap.getUsers().get(key);
        str.append(user);
    }
    return str.toString();
}

JSP

<%--
  Created by IntelliJ IDEA.
  User: southwind
  Date: 2019-03-14
  Time: 09:12
  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="/data/map" method="post">
        用戶1編號:<input type="text" name="users['a'].id"/><br/>
        用戶1名稱:<input type="text" name="users['a'].name"/><br/>
        用戶2編號:<input type="text" name="users['b'].id"/><br/>
        用戶2名稱:<input type="text" name="users['b'].name"/><br/>
        用戶3編號:<input type="text" name="users['c'].id"/><br/>
        用戶3名稱:<input type="text" name="users['c'].name"/><br/>
        <input type="submit" value="提交"/>
    </form>
</body>
</html>

  • JSON

客戶端發生 JSON 格式的數據,直接通過 Spring MVC 綁定到業務方法的形參中。

處理 Spring MVC 無法加載靜態資源,在 web.xml 中添加配置即可。

<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.js</url-pattern>
</servlet-mapping>

JSP

<%--
  Created by IntelliJ IDEA.
  User: southwind
  Date: 2019-03-14
  Time: 10:35
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <script type="text/javascript" src="js/jquery-3.3.1.min.js"></script>
    <script type="text/javascript">
        $(function(){
           var user = {
               "id":1,
               "name":"張三"
           };
           $.ajax({
               url:"/data/json",
               data:JSON.stringify(user),
               type:"POST",
               contentType:"application/json;charset=UTF-8",
               dataType:"JSON",
               success:function(data){
                   alter(data.id+"---"+data.name);
               }
           })
        });
    </script>
</head>
<body>

</body>
</html>

業務方法

@RequestMapping("/json")
public User json(@RequestBody User user){
    System.out.println(user);
    user.setId(6);
    user.setName("張六");
    return user;
}

Spring MVC 中的 JSON 和 JavaBean 的轉換需要藉助於 fastjson,pom.xml 引入相關依賴。

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.32</version>
</dependency>

springmvc.xml 添加 fastjson 配置。

<mvc:annotation-driven>
    <!-- 消息轉換器 -->
    <mvc:message-converters register-defaults="true">
        <bean class="org.springframework.http.converter.StringHttpMessageConverter">
            <property name="supportedMediaTypes" value="text/html;charset=UTF-8"></property>
        </bean>
        <!-- 配置fastjson -->
        <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter4"></bean>
    </mvc:message-converters>
</mvc:annotation-driven>

Spring MVC 模型數據解析

JSP 四大作用域對應的內置對象:pageContext、request、session、application。

模型數據的綁定是由 ViewResolver 來完成的,實際開發中,我們需要先添加模型數據,再交給 ViewResolver 來綁定。

Spring MVC 提供了以下幾種方式添加模型數據:

  • Map
  • Model
  • ModelAndView
  • @SessionAttribute
  • @ModelAttribute

將模式數據綁定到 request 對象。

1、Map

@RequestMapping("/map")
public String map(Map<String,User> map){
    User user = new User();
    user.setId(1L);
    user.setName("張三");
    map.put("user",user);
    return "view";
}

JSP

<%--
  Created by IntelliJ IDEA.
  User: southwind
  Date: 2019-03-14
  Time: 11:36
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    ${requestScope.user}
</body>
</html>

2、Model

@RequestMapping("/model")
public String model(Model model){
    User user = new User();
    user.setId(1L);
    user.setName("張三");
    model.addAttribute("user",user);
    return "view";
}

3、ModelAndView

@RequestMapping("/modelAndView")
public ModelAndView modelAndView(){
    User user = new User();
    user.setId(1L);
    user.setName("張三");
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.addObject("user",user);
    modelAndView.setViewName("view");
    return modelAndView;
}

@RequestMapping("/modelAndView2")
public ModelAndView modelAndView2(){
    User user = new User();
    user.setId(1L);
    user.setName("張三");
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.addObject("user",user);
    View view = new InternalResourceView("/view.jsp");
    modelAndView.setView(view);
    return modelAndView;
}

@RequestMapping("/modelAndView3")
public ModelAndView modelAndView3(){
    User user = new User();
    user.setId(1L);
    user.setName("張三");
    ModelAndView modelAndView = new ModelAndView("view");
    modelAndView.addObject("user",user);
    return modelAndView;
}

@RequestMapping("/modelAndView4")
public ModelAndView modelAndView4(){
    User user = new User();
    user.setId(1L);
    user.setName("張三");
    View view = new InternalResourceView("/view.jsp");
    ModelAndView modelAndView = new ModelAndView(view);
    modelAndView.addObject("user",user);
    return modelAndView;
}

@RequestMapping("/modelAndView5")
public ModelAndView modelAndView5(){
    User user = new User();
    user.setId(1L);
    user.setName("張三");
    Map<String,User> map = new HashMap<>();
    map.put("user",user);
    ModelAndView modelAndView = new ModelAndView("view",map);
    return modelAndView;
}

@RequestMapping("/modelAndView6")
public ModelAndView modelAndView6(){
    User user = new User();
    user.setId(1L);
    user.setName("張三");
    Map<String,User> map = new HashMap<>();
    map.put("user",user);
    View view = new InternalResourceView("/view.jsp");
    ModelAndView modelAndView = new ModelAndView(view,map);
    return modelAndView;
}

@RequestMapping("/modelAndView7")
public ModelAndView modelAndView7(){
    User user = new User();
    user.setId(1L);
    user.setName("張三");
    ModelAndView modelAndView = new ModelAndView("view","user",user);
    return modelAndView;
}

@RequestMapping("/modelAndView8")
public ModelAndView modelAndView8(){
    User user = new User();
    user.setId(1L);
    user.setName("張三");
    View view = new InternalResourceView("/view.jsp");
    ModelAndView modelAndView = new ModelAndView(view,"user",user);
    return modelAndView;
}

4、HttpServletRequest

@RequestMapping("/request")
public String request(HttpServletRequest request){
    User user = new User();
    user.setId(1L);
    user.setName("張三");
    request.setAttribute("user",user);
    return "view";
}

5、@ModelAttribute

  • 定義一個方法,該方法專門用來返回要填充到模型數據中的對象。
@ModelAttribute
public User getUser(){
    User user = new User();
    user.setId(1L);
    user.setName("張三");
    return user;
}

@ModelAttribute
public void getUser(Map<String,User> map){
    User user = new User();
    user.setId(1L);
    user.setName("張三");
    map.put("user",user);
}

@ModelAttribute
public void getUser(Model model){
    User user = new User();
    user.setId(1L);
    user.setName("張三");
    model.addAttribute("user",user);
}

  • 業務方法中無需再處理模型數據,只需返回視圖即可。
@RequestMapping("/modelAttribute")
public String modelAttribute(){
    return "view";
}

將模型數據綁定到 session 對象

1、直接使用原生的 Servlet API。

@RequestMapping("/session")
public String session(HttpServletRequest request){
    HttpSession session = request.getSession();
    User user = new User();
    user.setId(1L);
    user.setName("張三");
    session.setAttribute("user",user);
    return "view";
}

@RequestMapping("/session2")
public String session2(HttpSession session){
    User user = new User();
    user.setId(1L);
    user.setName("張三");
    session.setAttribute("user",user);
    return "view";
}

2、@SessionAttribute

@SessionAttributes(value = {"user","address"})
public class ViewHandler {
}

對於 ViewHandler 中的所有業務方法,只要向 request 中添加了 key = “user”、key = “address” 的對象時,Spring MVC 會自動將該數據添加到 session 中,保存 key 不變。

@SessionAttributes(types = {User.class,Address.class})
public class ViewHandler {
}

對於 ViewHandler 中的所有業務方法,只要向 request 中添加了數據類型是 User 、Address 的對象時,Spring MVC 會自動將該數據添加到 session 中,保存 key 不變。

將模型數據綁定到 application 對象

@RequestMapping("/application")
public String application(HttpServletRequest request){
    ServletContext application = request.getServletContext();
    User user = new User();
    user.setId(1L);
    user.setName("張三");
    application.setAttribute("user",user);
    return "view";
}

Spring MVC 自定義數據轉換器

數據轉換器是指將客戶端 HTTP 請求中的參數轉換爲業務方法中定義的形參,自定義表示開發者可以自主設計轉換的方式,HandlerApdter 已經提供了通用的轉換,String 轉 int,String 轉 double,表單數據的封裝等,但是在特殊的業務場景下,HandlerAdapter 無法進行轉換,就需要開發者自定義轉換器。

客戶端輸入 String 類型的數據 “2019-03-03”,自定義轉換器將該數據轉爲 Date 類型的對象。

  • 創建 DateConverter 轉換器,實現 Conveter 接口。
package com.southwind.converter;

import org.springframework.core.convert.converter.Converter;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class DateConverter implements Converter<String, Date> {

    private String pattern;

    public DateConverter(String pattern){
        this.pattern = pattern;
    }

    @Override
    public Date convert(String s) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(this.pattern);
        Date date = null;
        try {
            date = simpleDateFormat.parse(s);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }
}

  • springmvc.xml 配置轉換器。
<!-- 配置自定義轉換器 -->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
    <property name="converters">
        <list>
            <bean class="com.southwind.converter.DateConverter">
                <constructor-arg type="java.lang.String" value="yyyy-MM-dd"></constructor-arg>
            </bean>
        </list>
    </property>
</bean>

<mvc:annotation-driven conversion-service="conversionService">
    <!-- 消息轉換器 -->
    <mvc:message-converters register-defaults="true">
        <bean class="org.springframework.http.converter.StringHttpMessageConverter">
            <property name="supportedMediaTypes" value="text/html;charset=UTF-8"></property>
        </bean>
        <!-- 配置fastjson -->
        <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter4"></bean>
    </mvc:message-converters>
</mvc:annotation-driven>

  • JSP
<%--
  Created by IntelliJ IDEA.
  User: southwind
  Date: 2019-03-14
  Time: 14:47
  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="/converter/date" method="post">
        請輸入日期:<input type="text" name="date"/>(yyyy-MM-dd)<br/>
        <input type="submit" value="提交"/>
    </form>
</body>
</html>

  • Handler
package com.southwind.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;

@RestController
@RequestMapping("/converter")
public class ConverterHandler {

    @RequestMapping("/date")
    public String date(Date date){
        return date.toString();
    }
}

String 轉 Student

StudentConverter

package com.southwind.converter;

import com.southwind.entity.Student;
import org.springframework.core.convert.converter.Converter;

public class StudentConverter implements Converter<String, Student> {
    @Override
    public Student convert(String s) {
        String[] args = s.split("-");
        Student student = new Student();
        student.setId(Long.parseLong(args[0]));
        student.setName(args[1]);
        student.setAge(Integer.parseInt(args[2]));
        return student;
    }
}

springmvc.xml

<!-- 配置自定義轉換器 -->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
    <property name="converters">
        <list>
            <bean class="com.southwind.converter.DateConverter">
                <constructor-arg type="java.lang.String" value="yyyy-MM-dd"></constructor-arg>
            </bean>
            <bean class="com.southwind.converter.StudentConverter"></bean>
        </list>
    </property>
</bean>

<mvc:annotation-driven conversion-service="conversionService">
    <!-- 消息轉換器 -->
    <mvc:message-converters register-defaults="true">
        <bean class="org.springframework.http.converter.StringHttpMessageConverter">
            <property name="supportedMediaTypes" value="text/html;charset=UTF-8"></property>
        </bean>
        <!-- 配置fastjson -->
        <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter4"></bean>
    </mvc:message-converters>
</mvc:annotation-driven>

JSP

<%--
  Created by IntelliJ IDEA.
  User: southwind
  Date: 2019-03-14
  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="/converter/student" method="post">
        請輸入學生信息:<input type="text" name="student"/>(id-name-age)<br/>
        <input type="submit" value="提交"/>
    </form>
</body>
</html>

Handler

@RequestMapping("/student")
public String student(Student student){
    return student.toString();
}

Spring MVC REST

REST:Representational State Transfer,資源表現層狀態轉換,是目前比較主流的一種互聯網軟件架構,它結構清晰、標準規範、易於理解、便於擴展。

  • 資源(Resource)

網絡上的一個實體,或者說網絡中存在的一個具體信息,一段文本、一張圖片、一首歌曲、一段視頻等等,總之就是一個具體的存在。可以用一個 URI(統一資源定位符)指向它,每個資源都有對應的一個特定的 URI,要獲取該資源時,只需要訪問對應的 URI 即可。

  • 表現層(Representation)

資源具體呈現出來的形式,比如文本可以用 txt 格式表示,也可以用 HTML、XML、JSON等格式來表示。

  • 狀態轉換(State Transfer)

客戶端如果希望操作服務器中的某個資源,就需要通過某種方式讓服務端發生狀態轉換,而這種轉換是建立在表現層之上的,所有叫做"表現層狀態轉換"。

特點

  • URL 更加簡潔。
  • 有利於不同系統之間的資源共享,只需要遵守一定的規範,不需要進行其他配置即可實現資源共享。

如何使用

REST 具體操作就是 HTTP 協議中四個表示操作方式的動詞分別對應 CRUD 基本操作。

GET 用來表示獲取資源。

POST 用來表示新建資源。

PUT 用來表示修改資源。

DELETE 用來表示刪除資源。

Handler

package com.southwind.controller;

import com.southwind.entity.Student;
import com.southwind.entity.User;
import com.southwind.repository.StudentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.util.Collection;

@RestController
@RequestMapping("/rest")
public class RESTHandeler {

    @Autowired
    private StudentRepository studentRepository;

    @GetMapping("/findAll")
    public Collection<Student> findAll(HttpServletResponse response){
        response.setContentType("text/json;charset=UTF-8");
        return studentRepository.findAll();
    }

    @GetMapping("/findById/{id}")
    public Student findById(@PathVariable("id") long id){
        return studentRepository.findById(id);
    }

    @PostMapping("/save")
    public void save(@RequestBody Student student){
        studentRepository.saveOrUpdate(student);
    }

    @PutMapping("/update")
    public void update(@RequestBody Student student){
        studentRepository.saveOrUpdate(student);
    }

    @DeleteMapping("/deleteById/{id}")
    public void deleteById(@PathVariable("id") long id){
        studentRepository.deleteById(id);
    }

}

StudentRepository

package com.southwind.repository;

import com.southwind.entity.Student;

import java.util.Collection;

public interface StudentRepository {
    public Collection<Student> findAll();
    public Student findById(long id);
    public void saveOrUpdate(Student student);
    public void deleteById(long id);
}

StudentRepositoryImpl

package com.southwind.repository.impl;

import com.southwind.entity.Student;
import com.southwind.repository.StudentRepository;
import org.springframework.stereotype.Repository;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

@Repository
public class StudentRepositoryImpl implements StudentRepository {

    private static Map<Long,Student> studentMap;

    static{
        studentMap = new HashMap<>();
        studentMap.put(1L,new Student(1L,"張三",22));
        studentMap.put(2L,new Student(2L,"李四",23));
        studentMap.put(3L,new Student(3L,"王五",24));
    }

    @Override
    public Collection<Student> findAll() {
        return studentMap.values();
    }

    @Override
    public Student findById(long id) {
        return studentMap.get(id);
    }

    @Override
    public void saveOrUpdate(Student student) {
        studentMap.put(student.getId(),student);
    }

    @Override
    public void deleteById(long id) {
        studentMap.remove(id);
    }
}

Spring MVC 文件上傳下載

單文件上傳

底層是使用 Apache fileupload 組件完成上傳,Spring MVC 對這種方式進行了封裝。

  • pom.xml
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.5</version>
</dependency>

<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.3</version>
</dependency>

  • JSP
<%--
  Created by IntelliJ IDEA.
  User: southwind
  Date: 2019-03-15
  Time: 09:09
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <form action="/file/upload" method="post" enctype="multipart/form-data">
        <input type="file" name="img"/>
        <input type="submit" value="上傳"/>
    </form>
    <img src="${path}">
</body>
</html>

1、input 的 type 設置爲 file。

2、form 的 method 設置爲 post(get 請求只能將文件名傳給服務器)

3、from 的 enctype 設置爲 multipart-form-data(如果不設置只能將文件名傳給服務器)

  • Handler
package com.southwind.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;

@Controller
@RequestMapping("/file")
public class FileHandler {

    @PostMapping("/upload")
    public String upload(MultipartFile img, HttpServletRequest request){
        if(img.getSize()>0){
            //獲取保存上傳文件的file路徑
            String path = request.getServletContext().getRealPath("file");
            //獲取上傳的文件名
            String name = img.getOriginalFilename();
            File file = new File(path,name);
            try {
                img.transferTo(file);
                //保存上傳之後的文件路徑
                request.setAttribute("path","/file/"+name);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return "upload";
    }
}

  • springmvc.xml
<!-- 配置上傳組件 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>

  • web.xml 添加如下配置,否則客戶端無法訪問 png
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.png</url-pattern>
</servlet-mapping>

多文件上傳

pom.xml

<dependency>
    <groupId>jstl</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
</dependency>

<dependency>
    <groupId>taglibs</groupId>
    <artifactId>standard</artifactId>
    <version>1.1.2</version>
</dependency>

JSP

<%--
  Created by IntelliJ IDEA.
  User: southwind
  Date: 2019-03-15
  Time: 09:32
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <form action="/file/uploads" method="post" enctype="multipart/form-data">
        file1:<input type="file" name="imgs"/><br/>
        file2:<input type="file" name="imgs"/><br/>
        file3:<input type="file" name="imgs"><br/>
        <input type="submit" value="上傳"/>
    </form>
    <c:forEach items="${files}" var="file" >
        <img src="${file}" width="300px">
    </c:forEach>
</body>
</html>

Handler

@PostMapping("/uploads")
public String uploads(MultipartFile[] imgs,HttpServletRequest request){
    List<String> files = new ArrayList<>();
    for (MultipartFile img:imgs){
        if(img.getSize()>0){
            //獲取保存上傳文件的file路徑
            String path = request.getServletContext().getRealPath("file");
            //獲取上傳的文件名
            String name = img.getOriginalFilename();
            File file = new File(path,name);
            try {
                img.transferTo(file);
                //保存上傳之後的文件路徑
                files.add("/file/"+name);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    request.setAttribute("files",files);
    return "uploads";
}

下載

  • JSP
<%--
  Created by IntelliJ IDEA.
  User: southwind
  Date: 2019-03-15
  Time: 10: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>
    <a href="/file/download/1">1.png</a>
    <a href="/file/download/2">2.png</a>
    <a href="/file/download/3">3.png</a>
</body>
</html>

  • Handler
@GetMapping("/download/{name}")
public void download(@PathVariable("name") String name, HttpServletRequest request, HttpServletResponse response){
    if(name != null){
        name += ".png";
        String path = request.getServletContext().getRealPath("file");
        File file = new File(path,name);
        OutputStream outputStream = null;
        if(file.exists()){
            response.setContentType("application/forc-download");
            response.setHeader("Content-Disposition","attachment;filename="+name);
            try {
                outputStream = response.getOutputStream();
                outputStream.write(FileUtils.readFileToByteArray(file));
                outputStream.flush();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if(outputStream != null){
                    try {
                        outputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

Spring MVC 表單標籤庫

  • Handler
@GetMapping("/get")
public ModelAndView get(){
    ModelAndView modelAndView = new ModelAndView("tag");
    Student student = new Student(1L,"張三",22);
    modelAndView.addObject("student",student);
    return modelAndView;
}

  • JSP
<%--
  Created by IntelliJ IDEA.
  User: southwind
  Date: 2019-03-15
  Time: 10:53
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>學生信息</h1>
    <form:form modelAttribute="student">
        學生ID:<form:input path="id"/><br/>
        學生姓名:<form:input path="name"/><br/>
        學生年齡:<form:input path="age"/><br/>
        <input type="submit" value="提交"/>
    </form:form>
</body>
</html>

1、JSP 頁面導入 Spring MVC 表單標籤庫,與導入 JSTL 標籤庫的語法非常相似,前綴 prefix 可以自定義,通常定義爲 from。

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>

2、將 form 表單與模型數據進行綁定,通過 modelAttribute 屬性完成綁定,將 modelAttribute 的值設置爲模型數據對應的 key 值。

Handeler:modelAndView.addObject("student",student);
JSP:<form:form modelAttribute="student">

3、form 表單完成綁定之後,將模型數據的值取出綁定到不同的標籤中,通過設置標籤的 path 屬性完成,將 path 屬性的值設置爲模型數據對應的屬性名即可。

學生ID:<form:input path="id"/><br/>
學生姓名:<form:input path="name"/><br/>
學生年齡:<form:input path="age"/><br/>

常用的表單標籤

  • from
<form:from modelAttribute="student"/>

渲染的是 HTML 中的<form></from>,通過 modelAttribute 屬性綁定具體的模型數據。

  • input
<form:input path="name"/>

渲染的是 HTML 中的 <input type="text"/>,from 標籤綁定的是模型數據,input 標籤綁定的是模型數據中的屬性值,通過 path 屬性可以與模型數據中的屬性名對應,並且支持及聯操作。

<from:input path="address.name"/>

  • password
<form:password path="password"/>

渲染的是 HTML 中的 <input type="password"/>,通過 path 屬性與模型數據的屬性值進行綁定,password 標籤的值不會在頁面顯示。

  • checkbox
<form:checkbox path="hobby" value="讀書"/>

student.setFlag(false);

checkbox:<form:checkbox path="flag" value="flag"></form:checkbox><br/>

渲染的是 HTML 中的 <input type="checkbox"/>,通過 path 與模型數據的屬性值進行綁定,可以綁定 boolean、數組和集合。

如果綁定 boolean 值,若該變量的值爲 true,則表示該複選框選中,否則表示不選中。

如果綁定數組或者集合,數組/集合中的元素等於 checkbox 的 value 值,則選中。

student.setHobby(Arrays.asList("讀書","看電影","玩遊戲"));
modelAndView.addObject("student",student);

愛好:<form:checkbox path="hobby" value="攝影"></form:checkbox>攝影<br/>
<form:checkbox path="hobby" value="讀書"></form:checkbox>讀書<br/>
<form:checkbox path="hobby" value="聽音樂"></form:checkbox>聽音樂<br/>
<form:checkbox path="hobby" value="看電影"></form:checkbox>看電影<br/>
<form:checkbox path="hobby" value="旅遊"></form:checkbox>旅遊<br/>
<form:checkbox path="hobby" value="玩遊戲"></form:checkbox>玩遊戲<br/>
<input type="submit" value="提交"/>

  • checkboxes
<form:checkboxes items=${student.hobby} path="selecHobby"/>

渲染的是 HTML 中的一組 <input type="checkbox"/>,是對 <form:checkbox/> 的一種簡化,需要結合 items 和 path 屬性來使用,items 綁定被遍歷的集合或數組,path 綁定被選中的集合或數組,可以這樣理解,items 爲全部可選集合,path 爲默認的選中集合。

student.setHobby(Arrays.asList("攝影","讀書","聽音樂","看電影","旅遊","玩遊戲"));
student.setSelectHobby(Arrays.asList("攝影","讀書","聽音樂"));
modelAndView.addObject("student",student);

愛好:<form:checkboxes path="selectHobby" items="${student.hobby}"/><br/>

需要注意的是 path 可以直接綁定模型數據的屬性值,items 則需要通過 EL 表達式的形式從域對象中獲取數據,不能直接寫屬性名。

  • rabiobutton
<from:radiobutton path="radioId" value="0"/>

渲染的是 HTML 中的一個 <input type="radio"/>,綁定的數據與標籤的 value 值相等則爲選中,否則不選中。

student.setRadioId(1);
modelAndView.addObject("student",student);

radiobutton:<form:radiobutton path="radioId" value="1"/>radiobutton<br/>

  • radiobuttons
<form:radiobuttons itmes="${student.grade}" path="selectGrade"/>

渲染的是 HTML 中的一組 <input type="radio"/>,這裏需要結合 items 和 path 兩個屬性來使用,items 綁定被遍歷的集合或數組,path 綁定被選中的值,items 爲全部的可選類型,path 爲默認選中的選項,用法與 <form:checkboxes/> 一致。

Map<Integer,String> gradeMap = new HashMap<>();
gradeMap.put(1,"一年級");
gradeMap.put(2,"二年級");
gradeMap.put(3,"三年級");
gradeMap.put(4,"四年級");
gradeMap.put(5,"五年級");
gradeMap.put(6,"六年級");
student.setGradeMap(gradeMap);
student.setSelectGrade(3);
modelAndView.addObject("student",student);

學生年級:<form:radiobuttons items="${student.gradeMap}" path="selectGrade"/><br/>

  • select
<form:select items="${student.citys}" path="selectCity"/>

渲染的是 HTML 中的一個 <select/> 標籤,需要結合 items 和 path 兩個屬性來使用,items 綁定被遍歷的集合或數組,path 綁定被選中的值,用法與 <from:radiobuttons/>一致。

Map<Integer,String> cityMap = new HashMap<>();
cityMap.put(1,"北京");
cityMap.put(2,"上海");
cityMap.put(3,"廣州");
cityMap.put(4,"深圳");
student.setCityMap(cityMap);
student.setSelectCity(3);
modelAndView.addObject("student",student);

所在城市:<form:select items="${student.cityMap}" path="selectCity"></form:select><br/>

  • options

form:select 結合 form:options 的使用,from:select 只定義 path 屬性,在 form:select 標籤內部添加一個子標籤 form:options ,設置 items 屬性,獲取被遍歷的集合。

所在城市:<form:select path="selectCity">
  				<form:options items="${student.cityMap}"></form:options>
				</form:select><br/>

  • option

    form:select 結合 form:option 的使用,from:select 定義 path 屬性,給每一個 form:option 設置 value 值,path 的值與哪個 value 值相等,該項默認選中。

所在城市:<form:select path="selectCity">
            <form:option value="1">杭州</form:option>
            <form:option value="2">成都</form:option>
            <form:option value="3">西安</form:option>
        </form:select><br/>

  • textarea

渲染的是 HTML 中的一個 <textarea/> ,path 綁定模型數據的屬性值,作爲文本輸入域的默認值。

student.setIntroduce("你好,我是...");
modelAndView.addObject("student",student);

信息:<form:textarea path="introduce"/><br/>

  • errors

處理錯誤信息,一般用在數據校驗,該標籤需要結合 Spring MVC 的驗證器結合起來使用。

Spring MVC 數據校驗

Spring MVC 提供了兩種數據校驗的方式:1、基於 Validator 接口。2、使用 Annotation JSR - 303 標準進行校驗。

基於 Validator 接口的方式需要自定義 Validator 驗證器,每一條數據的驗證規則需要開發者手動完成,使用 Annotation JSR - 303 標準則不需要自定義驗證器,通過註解的方式可以直接在實體類中添加每個屬性的驗證規則,這種方式更加方便,實際開發中推薦使用。

基於 Validator 接口

  • 實體類 Account
package com.southwind.entity;

import lombok.Data;

@Data
public class Account {
    private String name;
    private String password;
}

  • 自定義驗證器 AccountValidator,實現 Validator 接口。
package com.southwind.validator;

import com.southwind.entity.Account;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;

public class AccountValidator implements Validator {
    @Override
    public boolean supports(Class<?> aClass) {
        return Account.class.equals(aClass);
    }

    @Override
    public void validate(Object o, Errors errors) {
        ValidationUtils.rejectIfEmpty(errors,"name",null,"姓名不能爲空");
        ValidationUtils.rejectIfEmpty(errors,"password",null,"密碼不能爲空");
    }
}

  • 控制器
package com.southwind.controller;

import com.southwind.entity.Account;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/validator")
public class ValidatorHandler {

    @GetMapping("/login")
    public String login(Model model){
        model.addAttribute("account",new Account());
        return "login";
    }

    @PostMapping("/login")
    public String login(@Validated Account account, BindingResult bindingResult){
        if(bindingResult.hasErrors()){
            return "login";
        }
        return "index";
    }
}

  • springmvc.xml 配置驗證器。
<bean id="accountValidator" class="com.southwind.validator.AccountValidator"></bean>
<mvc:annotation-driven validator="accountValidator"></mvc:annotation-driven>

  • JSP
<%--
  Created by IntelliJ IDEA.
  User: southwind
  Date: 2019-03-18
  Time: 10:31
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="from" uri="http://www.springframework.org/tags/form" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <form:form modelAttribute="account" action="/validator/login" method="post">
        姓名:<form:input path="name"/><from:errors path="name"></from:errors><br/>
        密碼:<form:input path="password"/><from:errors path="password"></from:errors><br/>
        <input type="submit" value="登錄"/>
    </form:form>
</body>
</html>

Annotation JSR - 303 標準

使用 Annotation JSR - 303 標準進行驗證,需要導入支持這種標準的依賴 jar 文件,這裏我們使用 Hibernate Validator。

  • pom.xml
<!-- JSR-303 -->
<dependency>
  <groupId>org.hibernate</groupId>
  <artifactId>hibernate-validator</artifactId>
  <version>5.3.6.Final</version>
</dependency>

<dependency>
  <groupId>javax.validation</groupId>
  <artifactId>validation-api</artifactId>
  <version>2.0.1.Final</version>
</dependency>

<dependency>
  <groupId>org.jboss.logging</groupId>
  <artifactId>jboss-logging</artifactId>
  <version>3.3.2.Final</version>
</dependency>

  • 通過註解的方式直接在實體類中添加相關的驗證規則。
package com.southwind.entity;

import lombok.Data;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotEmpty;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;

@Data
public class Person {
    @NotEmpty(message = "用戶名不能爲空")
    private String username;
    @Size(min = 6,max = 12,message = "密碼6-12位")
    private String password;
    @Email(regexp = "^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\\\\.[a-zA-Z0-9-]+)*\\\\.[a-zA-Z0-9]{2,6}$",message = "請輸入正確的郵箱格式")
    private String email;
    @Pattern(regexp = "^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(18[0,5-9]))\\\\\\\\d{8}$",message = "請輸入正確的電話")
    private String phone;
}

  • ValidatorHandler
@GetMapping("/register")
public String register(Model model){
    model.addAttribute("person",new Person());
    return "register";
}

@PostMapping("/register")
public String register(@Valid Person person, BindingResult bindingResult){
    if(bindingResult.hasErrors()){
        return "register";
    }
    return "index";
}

  • springmvc.xml
<mvc:annotation-driven />

  • JSP
<%--
  Created by IntelliJ IDEA.
  User: southwind
  Date: 2019-03-18
  Time: 11:29
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <form:form modelAttribute="person" action="/validator/register2" method="post">
        用戶名:<form:input path="username"></form:input><form:errors path="username"/><br/>
        密碼:<form:password path="password"></form:password><form:errors path="password"/><br/>
        郵箱:<form:input path="email"></form:input><form:errors path="email"/><br/>
        電話:<form:input path="phone"></form:input><form:errors path="phone"/><br/>
        <input type="submit" value="提交"/>
    </form:form>
</body>
</html>

校驗規則詳解:

@Null 被註解的元素必須爲null

@NotNull 被註解的元素不能爲null

@Min(value) 被註解的元素必須是一個數字,其值必須大於等於指定的最小值

@Max(value) 被註解的元素必須是一個數字,其值必須小於於等於指定的最大值

@Email 被註解的元素必須是電子郵箱地址

@Pattern 被註解的元素必須符合對應的正則表達式

@Length 被註解的元素的大小必須在指定的範圍內

@NotEmpty 被註解的字符串的值必須非空

Null 和 Empty 是不同的結果,String str = null,str 是 null,String str = “”,str 不是 null,其值爲空。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章