首页 > 编程语言 > 详细

浅入SpringMVC

时间:2021-03-27 22:18:12      阅读:29      评论:0      收藏:0      [点我收藏+]

浅入SpringMVC

  1. SpringMVC
  2. 注解
  3. 数据绑定
  4. JSON数据交互RESTful支持
  5. 文件的上传和下载
  6. SpringMVC自带的表单标签库

1、SpringMVC简介

1、SpringMVC概述

SpringMVC是目前主流的实现MVC设计模式的框架,是spring框架的一个分支产品,以SpringIoC容器为基础,并利用容器的特性来简化它的配置。SpringMVC相当于Spring的一个子模块,可以很好的和Spring结合起来进行开发。


2、什么是MVC设计模式

将应用程序分为Model、View、Controller三层:模型(dao,service)视图(jsp)控制器(Servlet)。Controller接收客服请求,调用调用Model生成业务数据,传递给View。

SpringMVC就是对这套流程的封装,屏蔽了很多底层代码,开放出接口,让开发者可以更加轻松、便捷的完成基于MVC模式的Web开发。


3、SpringMVC的核心组件

  1. DispatcherServlet:前置控制器,是整个流程控制的核心,控制其他组件的执行,进行统一调度,降低组件之间的耦合性,相当于总指挥。
  2. Handler:处理器,完成具体的业务逻辑,相当于Servlet或Action。
  3. HandlerMapping:DispatcherServlet接收到请求后,通过HandlerInterceptor将不同的请求映射到不同的Handler。
  4. HandlerInterceptor:处理器拦截器,是一个接口,如果需要完成一些拦截处理,可以实现该接口。
  5. HandlerExecutionChain:处理器执行链,包括两部分:Handler和HandlerInterceptor(系统会有一个默认的HandlerInterceptor,如果需要额外设置拦截,可以添加拦截器)
  6. HandlerAdapter:处理器适配器,Handler执行业务方法之前,需要进行一系列的操作,包括表单数据的验证、数据类型的转换、将表单数据封装到JavaBean等,这些操作都是由HandlerAdapter来完成,开发者只需要将注意力集中业务逻辑的处理上,DispatcherServlet通过HandlerAdapter执行不同的Handler。
  7. ModelAndView:装载了模型数据和视图信息,作为Handler的处理结果,返回给DispatchServlet。
  8. ViewResolver:视图解析器,DispatcherServlet通过它将逻辑视图解析为物理视图。

4、SpringMVC工作流程

  1. 客服端请求被DispatcherSerlvet接收。
  2. 根据HandlerMapping映射到Handler。
  3. 生成Handler和HandlerInterceptor。
  4. Handler和HandlerInterceptor以HandlerExecutionChain的形式一并返回给DisptacherServlet。
  5. DispatcherSerlvet通过HandlerAdapter调用Handler的方法完成业务逻辑处理。
  6. Handler返回一个View给DispatcherServlet。
  7. DispatcherServlet将获取的ModelAndView对象给ViewResolver视图解析器,将逻辑视图解析为物理视图View。
  8. ViewResovler返回一个View给DispatcherServlet。
  9. DispatchServlet根据View进行视图渲染(将模型数据Model填充到视图View中)。
  10. DispatcherServlet将渲染后的结果响应给客服。

SpringMVC流程非常复杂,实际开发中很简单,因为大部分的组件不需要开发者创建、管理、只需要通过配置文s件的方式完成配置即可,真正需要开发者进行处理的只有Handler、View。

技术分享图片


第一个SpringMVC

  1. 创建Maven工程,pom.xml

     </dependencies>
    	<dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-webmvc</artifactId>
          <version>5.3.4</version>
        </dependency>
      </dependencies>
    
  2. 在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>
          <!-- 配置前端控制器DispatcherServlet -->
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
          <!-- 指定SpringMVC配置文件 -->
          <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>
    
  3. 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:mvc="http://www.springframework.org/schema/mvc"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
             http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
             http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
        <!-- 自动扫描 -->
        <context:component-scan base-package="com.southwind.controller"></context:component-scan>
        <!-- 配置视图解析器 -->
        <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
            <!-- 前缀 -->
            <property name="prefix" value="/"></property>
            <!-- 后缀 -->
            <property name="suffix" value=".jsp"></property>
        </bean>
    </beans>
    
  4. 创建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";
        }
    }
    

2、注解

  • @Controller
  • @RequestMapping相关参数
  • @RequestMapping相关参数

@Controller

@Controller在类定义处添加,将该类交给IoC容器管理(结合spring.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

SpringMVC通过@RequestMapping注解将URL请求与业务方法进行映射,在Handler的类定义处以及方法定义处都可以添加@RequestMapping,在类定义处添加,相当于客服端多了一层访问路径。

@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、PIUT、DELET

    传统的

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

    新注解

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

    上述代码表示index方法只能接收GET请求

    @GetMapping

    @PostMapping

    @putMapping等...

  3. params:指定请求中必须包含某些参数,否则无法调用该方法

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

    上述代码表示请求中包含name和id两个参数,同时id的值必须是10。

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

    @RequestParam()注解表示将Http请求中的参数赋给指定的形参

    上述代码表示将请求的参数nmae和id分别赋给了形参str和age,同时自动完成了数据类型转换,将"10"转为了int类型的10,再赋给age,这些工作都是由HandlerAdapter来完成的。

    SpringMVC也支持RESTful风格的URL。

    传统类型:http://localhost:8080/hello/index?name=zhangsan&id=10

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

  4. 映射Cookie

    SpringMVC通过映射可以直接在业务方法中获取Cookie的值。

        @RequestMapping("/cookie")
        public String cookie(@CookieValue(value = "JSESSIONID") String sessionId){
            System.out.println(sessionId);
            return "index";
        }
    
  5. JSP页面的转发重定向:

    redirect重定向

        @RequestMapping("/redirect")
        public String redirect(){
            System.out.println("redirect");
            return "redirect:jsp/index01.jsp";
        }
    

    forward请求转发

        @RequestMapping("/forward")
        public String forward(){
            System.out.println("转发");
            return "forward:jsp/index01.jsp";
        }
    

3、数据绑定

  1. 数据绑定
  2. 简单数据绑定
  3. 复杂数据绑定
  4. SpringMVC数据模型解析
  5. SpringMVC自定义数据转换器

什么是数据绑定

在后端的业务方法中直接获取客服端HttP请求中的参数,将请求参数映射到业务方法的形参中,SpringMVC中数据绑定的工作是由HandlerAdapter来完成。

简单数据绑定

客服端的Http请求中String类型的参数通过SpringMVC(HandleAdapter)转换器绑定到业务方法的形参中。

SpringMVC会根据请求参数名和JavaBean属性名进行自动匹配,自动为对象填充属性值,同时支持级联属性。

  • 使用JavaBean数据绑定
  • 使用JavaBean级联数据绑定
  • 包装类数据绑定
  • 基本数据类型绑定
  • 默认数据绑定
  1. 使用JavaBean数据绑定

    创建JavaBean(User)

    package com.southwind.entity;
    public class User {
        private long id;
        private String name;
        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", name=‘" + name + 
                    ‘}‘;
        }
        public User(long id, String name) {
            this.id = id;
            this.name = name;
        }
        public User(){
    
        }
        public long getId() {
            return id;
        }
        public void setId(long id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
    }
    

    创建jsp

    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
        <form action="/save" method="post">
            用户名id:<input type="text" name="id"><br>
            用户名:<input type="text" name="name"><br>
            <input type="submit" value="注册">
        </form>
    </body>
    </html>
    

    在Handler中添加相应方法

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

    运行User{id=1, name=‘梅西‘}

  2. 使用JavaBean级联数据绑定

    创建JavaBean(Address)

    package com.southwind.entity;
    public class Address {
        private String value;
        @Override
        public String toString() {
            return "Address{" +
                    "value=‘" + value + ‘\‘‘ +
                    ‘}‘;
        }
        public Address(String value) {
            this.value = value;
        }
        public Address(){
        }
        public String getValue() {
            return value;
        }
        public void setValue(String value) {
            this.value = value;
        }
    }
    

    在User类中添加Address类型

    private Address address;
        public Address getAddress() {
            return address;
        }
        public void setAddress(Address address) {
            this.address = address;
        }
    

    在jsp中增加一个<inpute>

    用户地址:<input type="text" name="address.value"><br>
    

    运行User{id=1, name=‘梅西‘, address=Address{value=‘东湖路‘}}

    如果出现中文乱码问题,只需在web.xml添加SpringMVC自带的过滤器。

    <!-- 解决中为乱码问题 -->
      <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>
      <servlet>
    
  3. 包装类数据绑定(包装类接收null)

    @RequestMapping("/packageType")
        @ResponseBody
        public String packageType(Integer id){
            return id+"";
        }
    

    包装类可以接收null,当HttP请求没有参数时,使用包装类定义形参的数据类型,程序不会抛出异常。

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

    @RequestParam

    value = "num":将HTTP请求中文名为num的参数赋给形参

    requried:设置num是否为必填项,true表示必填,false表示非必填,可省略。

    defaultValue = "0":如果HTTP请求中没有num参数,默认值为0。

  4. 基本数据类型绑定(基本数据类型不接受null值)基本数据类型绑定包装类数据绑定默认数据绑定

     @RequestMapping("/base")
        @ResponseBody
        public String baeaType(int id){
            return id+"";
        }
    

    客服端传来的HttP请求中的int类型的参数id,将请求参数映射到业务方法的形参中。

    @ResponseBody表示SpringMVC会直接将业务方法的返回值响应给客服端,如果上述不加@ResponseBody注解,SpringMVC会将业务方法的返回值传递给DispatchServlet,再由DispatchServlet调用ViewResolver对返回值进行解析,映射到一个JSP资源。

  5. 默认数据绑定

    • HttpSessionRequest:通过request对象获取请求信息
    • HttpSessionResponse:通过response处理响应信息请求
    • HttpSession:通过session对象得到session中存储的对象
    • Model/ModelMap:Model是一个接口,ModelMap是一个接口实现,作用是将model数据填充到request域。

复杂数据绑定

  1. 数组绑定
  2. List
  3. Map
  4. JSON
  • 数组绑定

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

    等同于

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

    @RestController表示该控制器会直接将业务的返回值响应给客服端,不进行视图解析。

    @Controller表示该控制器的每一个业务方法的返回值都会交给视图解析器进行解析,如果只需将数据响应给客服端,而不需要进行视图解析,则需要在业务方法定义处添加@RestController,也可以在类上面添加@RestController表示该类的所有方法都不进行视图解析而直接将数据响应到客服端。

  • 集合绑定

    1. List

      SpringMVC不支持List类型的直接转换,需要对List集合进行包装。

      List集合封装类

      package com.southwind.entity;
      import java.util.List;
      public class UserList {
          private List<User> users;
          @Override
          public String toString() {
              return "UserList{" +
                      "users=" + users +
                      ‘}‘;
          }
          public UserList(List<User> users) {
              this.users = users;
          }
          public UserList(){
          }
          public List<User> getUsers() {
              return users;
          }
          public void setUsers(List<User> users) {
              this.users = users;
          }
      }
      

      业务方法

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

      JSP页面action、post请求传参数

      <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>
      

      处理@ResponseBody、Response给客服端中文乱码,在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>
      
    2. Map

      Map集合封装类

      package com.southwind.entity;
      import java.util.Map;
      public class UserMap {
          private Map<String,User> users;
          @Override
          public String toString() {
              return "UserMap{" +
                      "users=" + users +
                      ‘}‘;
          }
          public UserMap(Map<String, User> users) {
              this.users = users;
          }
          public UserMap(){
          }
          public Map<String, User> getUsers() {
              return users;
          }
          public void setUsers(Map<String, User> users) {
              this.users = users;
          }
      }
      

      业务方法

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

      JSP页面action、post请求传参数

      <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>
      
    3. JSON

      客服端发生JSON格式的数据,直接通过SpringMVC绑定到业务方法的形参中。

      配置JSON运行环境

      <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.12.2</version>
          </dependency>
          <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.12.2</version>
          </dependency>
          <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.12.2</version>
          </dependency>
      

      浏览器无法加载SpringMVC静态资源,在web.xml中添加配置即可。

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

      新建jsp文件处理JSON请求和响应

      <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){
                          alert(data.id+"---"+data.name)
                      }
                  })
              });
          </script>
      </head>
      <body>
      </body>
      </html>
      

      业务方法(绑定JSON类型必须在形参类型前面加@RequestBody注解)

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

      SpringMVC中的JSON和JavaBean的转换需要借助fastjson、pom.xml引入相关依赖。

      pom.xml

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

      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>
                  <!-- 配置fastjson -->
                  <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter4"></bean>
              </mvc:message-converters>
          </mvc:annotation-driven>
      

SpringMVC数据模型解析

JSP开发中经常需要向域对象中传递数据,springMVC简化了该操作。

JSP四大作用域的内置对象:pageContext、request、session、application。

模型数据的绑定是由ViewResolver来完成,实际开发中,我们需要先添加模型数据,再交给ViewResolver来绑定。

SpringMVC提供了以下几种方式添加模式数据:

  • Map (相当于Request域对象)
  • Model (相当于Request域对象)
  • ModelAndView (相当于Request域对象)
  • 使用原生的HttpServletRequest (相当于Request域对象)
  • @ModelAttribute (相当于Request域对象)
  • **@SessionAttribute **(相当于Session域对象)
  • 使用原生的Session(相当于Session域对象)
  • 使用原生的Application (相当于Appliaction域对象)
  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 "jsp/view";
        }
    

    JSP

    <%@ 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 "jsp/view";
        }
    
  3. ModelAndView

    	//方式1
        @RequestMapping("/modelAndView")
        public ModelAndView modelAndView(){
            User user = new User();
            user.setId(1L);
            user.setName("张三");
            ModelAndView modelAndView = new ModelAndView();
            modelAndView.addObject("user",user);
            modelAndView.setViewName("/jsp/view");
            return modelAndView;
        }
        //方式2
        @RequestMapping("/modelAndView2")
        public ModelAndView modelAndView2(Model model){
            User user = new User();
            user.setId(2L);
            user.setName("c罗");
            ModelAndView modelAndView = new ModelAndView("/jsp/view");
            modelAndView.addObject("user",user);
            return modelAndView;
        }
        //方式3
        @RequestMapping("/modelAndView3")
        public ModelAndView modelAndView3(Model model){
            User user = new User();
            user.setId(2L);
            user.setName("梅西");
            ModelAndView modelAndView = new ModelAndView();
            modelAndView.addObject("user",user);
            View view = new InternalResourceView("/jsp/view.jsp");//物理路径
            modelAndView.setView(view);
            return modelAndView;
        }
        //方式4
        @RequestMapping("/modelAndView4")
        public ModelAndView modelAndView4(Model model){
            User user = new User();
            user.setId(2L);
            user.setName("梅西");
            Map<String, User> map = new HashMap<>();
            map.put("user",user);
            ModelAndView modelAndView = new ModelAndView("/jsp/view",map);
            return modelAndView;
        }
        //方式5
        @RequestMapping("/modelAndView5")
        public ModelAndView modelAndView5(Model model){
            User user = new User();
            user.setId(2L);
            user.setName("梅西");
            Map<String, User> map = new HashMap<>();
            map.put("user",user);
            View view = new InternalResourceView("/jsp/view.jsp");//物理路径
            ModelAndView modelAndView = new ModelAndView(view,map);
            return modelAndView;
        }
        //方式6
        @RequestMapping("/modelAndView6")
        public ModelAndView modelAndView6(Model model){
            User user = new User();
            user.setId(2L);
            user.setName("梅西");
            ModelAndView modelAndView = new ModelAndView("/jsp/view","user",user);
            return modelAndView;
        }
        //方式7
        @RequestMapping("/modelAndView7")
        public ModelAndView modelAndView7(Model model){
            User user = new User();
            user.setId(2L);
            user.setName("梅西");
            View view = new InternalResourceView("/jsp/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(2L);
            user.setName("梅西");
            request.setAttribute("user",user);
            return "/jsp/view";
        }
    
  5. @ModelAttribute

    • 定义一个方法,该方法专门用来返回要填充到模型数据中的对象。

      //方法1
      @ModelAttribute
          public User getUser(){	//框架来填充数据
              User user = new User();
              user.setId(6L);
              user.setName("足球");
              return user;
          }
      
      //方法2
      @ModelAttribute
          public void getUser(Model model){	//使用Model手动填充数据
              User user = new User();
              user.setId(6L);
              user.setName("足球");
              model.addAttribute("user",user);
          }
      
      //方法3 
      @ModelAttribute
          public void getUser(Map<String,User> map){	//使用Map集合手动填充数据
              User user = new User();
              user.setId(6L);
              user.setName("足球");
              map.put("user",user);
          }
      
    • 业务方法中无需再处理模型数据,只需返回视图即可。

      @RequestMapping("modelAttribute")
          public String modelAttribute(){
              return "/jsp/view";
          }
      
  6. **@SessionAttribute **

    该注解只能在类上面定义因此是该类所共有的,对于ViewHandler中所有业务方法,只要向request中添加了key="user"、key="address"(数据类型是User、Address的对象时),springMVC会自动将数据添加到session中,保存Key不变。

    //添加单个对象数据
    @SessionAttributes(value = "user")
    public class ViewHandler {
    }
    @SessionAttributes(types = User.class)
    public class ViewHandler {
    }
    
    //添加多个对象数据
    @SessionAttributes(value = {"user","assress"})
    public class ViewHandler {
    }
    @SessionAttributes(types = {User.class,Address.class})
    public class ViewHandler {
    }
    
  7. 使用原生的Session

    	//方法1
    	@RequestMapping("/session")
        public String session(HttpServletRequest httpServletRequest){
            HttpSession session = httpServletRequest.getSession();
            User user = new User();
            user.setId(8L);
            user.setName("篮球");
            session.setAttribute("user",user);
            return "/jsp/view";
        }
    	//方法2
        @RequestMapping("/session2")
        public String Session2(HttpSession httpSession){
            User user = new User();
            user.setId(888L);
            user.setName("艾弗森");
            httpSession.setAttribute("user",user);
            return "/jsp/view";
        }
    
  8. 使用原生的Application

    @RequestMapping("application")
        public String application(HttpServletRequest httpServletRequest){
            User user = new User();
            user.setId(666L);
            user.setName("李小龙");
            HttpSession session = httpServletRequest.getSession();
            session.setAttribute("user",user);
            return "/jsp/view";
        }
    
  9. 总结

    数据绑定从请求中拿到参数与服务的的形参绑定从而保存到数据库或者重新发送给客服端

    springMVC数据解析是将数据库或者其他数据同过域对象发送到客服端

SpringMVC自定义转换器

数据转换器是指将客服端HTTP请求中的参数转换为业务方法中定义的形参,自定义表示开发者可以自主设计转换的方式,HandlerAdapter已经提供了通用的转换,String、转int、String转double。表单数据的封装等,但是在特殊的业务场景下,HandlerAdapter无法进行转换,就需要开者自定义转换器。

客服端输入String类型的数据"2021-03-18",自定义转换器将该数据转换为Date类型的对象。

  1. 创建DateConverter转换器,实现Converter接口。

    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();
            Date date = null;
            try {
                simpleDateFormat.parse(s);
            } catch (ParseException e) {
                e.printStackTrace();
            }
            return date;
        }
    }
    
  2. 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"><!-- 在springMVC的转换器中关联 -->
            <!-- 消息转换器 -->
            <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>
    
  3. JSP

    <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>s
    
  4. 业务方法

    @RestController
    @RequestMapping("converter")
    public class ConverterHandler {
        @RequestMapping("date")
        public String converterDate(Date date){
            return date.toString();
        }
    }
    

客服端输入String类型的数据"id-name-age",自定义转换器将该数据转换为自定义的Student类型的对象。

String转Student

  1. 创建StudentConverter转换器,实现Converter接口。

    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;
        }
    }
    
  2. 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> -->
                    <bean class="com.southwind.converter.StudentConverter"></bean>
                </list>
            </property>
        </bean>
    
  3. JSP

    <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>
    
  4. Handler

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

4、JSON数据交互RESTful支持

JSON

JSON是一种新的数据格式,它与XML非常相似,都是用于存储数据的,但JSON相对于XML解析速度更快,占用空间更少,因此经常使用JSON格式的数据进行前后台交互。

  1. JSON概述

    • JSON(JavaScript Object Notation)是一种轻量级的数据交互格式。
    • 他是基于JavaScript的一个子集,使用了C、C++、C#、Java、JavaScript、Perl、Python等其他语言的约定,采用完全独立于编程语言的文本格式来存储和表示数据。
  2. 对象结构

    • 对象结构以 { 开始、以 } 结尾。中间以零个或多个英文逗号分隔。

    • {
          key1:value1,
          key2:value2,
          ...
      }
      

      key:必须为String类型。

      value:可以为String、Number、Object、Array等数据类型

  3. 数组结构

    • 数组结构以 [ 开始、以 ]结尾。 中间以零个或多个英文逗号分隔。

    • [
          value1,
          value2,
          ...
      ]
      

      value:可以是任何基本数据类型

  4. 对象结构、数组结构、相互嵌套

    • {
          "name":"wangchaoyu",
          "hobby":["足球","篮球","兵乓球","羽毛球"],
          "address":{
              "city":"jiujiang",
              "street":"donghulu",
              "postcode":"2021"
          }
      }
      
    • 注意:如果使用JSON存储单个数据,一定要使用数组的形式,不要使用Object形式,因为Object形式必须是key/value的形式。

  5. JSON数据绑定

    步骤:

    1. 导入jar包

      jackson-annotations:JSON转换注解包

      jackson-core:JSON转换核心包

      jackson-databind:JSON转换的数据绑定包

    2. 编写jquery-3.3.1.min.js文件

    3. web.xml中配置浏览器访问jquery-3.3.1.min.js静态资源

       <servlet-mapping>
          <servlet-name>default</servlet-name>
          <url-pattern>*.js</url-pattern>
        </servlet-mapping>
      
    4. 编写业务方法

    5. SpringMVC中的JSON和JavaBean的转换需要借助fastjson、pom.xml引入相关依赖。

      pom.xml

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

      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>
                  <!-- 配置fastjson -->
                  <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter4"></bean>
              </mvc:message-converters>
          </mvc:annotation-driven>
      
    6. 运行


RESTful

REST:Representational State Transfer,资源表现层状态转换,是目前比较主流的一种互联网软件架构,它结构清晰、标准规范、易于理解、便于扩展。简单来所RESTful风格就是把请求参数变成请求路径的一种风格。

  1. RESTful概述

    • 资源(Resource)

      网络上的实体,或者说网络中存在的一个具体信息,一段文本、一张图片、一首歌曲、一段视频等,总之就是一个具体的存在。可以用一个URL(统一资源定位符)指向它,每个资源都有对应的一个特定的URL,要获取该资源时,只需要访问对应的URL即可。

    • 表现层(Repesentation)

      资源具体呈现出来的形式,比如文本可以用tet格式表示,也可以用HTML、XML、JSON等格式来表示。

    • 状态转换(State Transfer)

      客服端如果希望操作服务器中的某个资源,就需要通过某种方式让服务端发生状态转换,而这种转换是建立在表现在表现层之上的,所以叫做"表现层状态转换"。

    • 特点

      URL更加简洁。

      有利于不同系统之间的资源共享,只需要遵守一定的规范,不需要进行其他配置即可实现资源共享。

  2. 如何使用

    REST具体操作就是HTTP协议中四个表示操作方式的动词分别对应CRUD基本操作。

    GET 用来表示获取资源

    PODT 用来表示新建资源

    PUT 用来表示修该资源

    DELETE 用来表示删除资源

    • 创建实体类Student

      package com.southwind.entity;
      
      public class Student {
          private long id;
          private String name;
          private int age;
      
          @Override
          public String toString() {
              return "Student{" +
                      "id=" + id +
                      ", name=‘" + name + ‘\‘‘ +
                      ", age=" + age +
                      ‘}‘;
          }
          public Student(long id, String name, int age) {
              this.id = id;
              this.name = name;
              this.age = age;
          }
          public Student(){
          }
          public long getId() {
              return id;
          }
          public void setId(long id) {
              this.id = id;
          }
          public String getName() {
              return name;
          }
          public void setName(String name) {
              this.name = name;
          }
          public int getAge() {
              return age;
          }
          public void setAge(int age) {
              this.age = age;
          }
      }
      
    • 新建一个接口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实现StudentRepository接口

      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 {
          
          //建立一个静态的数据库模拟数据CRUD
          private static Map<Long,Student> studentMap;
          static{
              studentMap =new HashMap<>();
              studentMap.put(1L,new Student(1L,"张三",21));
              studentMap.put(2L,new Student(2L,"李四",22));
              studentMap.put(3L,new Student(3L,"王五",23));
          }
          @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);
          }
      }
      
    • 创建一个Handler类

      package com.southwind.controller;
      import com.southwind.entity.Student;
      import com.southwind.repository.StudentRepository;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.web.bind.annotation.*;
      import java.util.Collection;
      
      @RestController
      @RequestMapping("/rest")
      public class RESTHandler {
      
           @Autowired
           private  StudentRepository studentRepository;
           @RequestMapping("/findAll")
           public Collection<Student> findAll(){
               return studentRepository.findAll();
           }
           @RequestMapping("/findById/{id}")
           public Student findById(@PathVariable("id") long id){
              return studentRepository.findById(id);
           }
           @RequestMapping("/saveOrUpdate/{student}")
           public void saveOrUpdate(@RequestBody Student student){
               studentRepository.saveOrUpdate(student);
           }
           @RequestMapping("/deleteById/{id}")
           public void deleteById(@PathVariable("id") long id){
              studentRepository.deleteById(id);
           }
      }
      
    • 总结

      RESTful只是一种规则只要遵守这规则就可以了

      上面使用规则大概是这样但是运行时出错,上面运用了多态的特性。


5、文件的上传和下载

文件上传

  1. 单文件上传

    底层是使用Apache fileupload组件完成上传,springmvc对这种方式进行了封装。

    • pom.xml

      <dependency>
            <groupId>de.unkrig.commons</groupId>
            <artifactId>commons-io</artifactId>
            <version>1.2.15</version>
          </dependency>
          <dependency>
            <groupId>com.guicedee.services</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>62</version>
          </dependency>
      
    • JSP

      <%@ 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>
      </body>
      
    ```

    1、input的type设置为post

    2、from的method设置为post(get请求只能将文件名传给服务器)

    3、form的enctype设置为multipart/form-data(如果不设置只能将文件名上传到服务器)

    • springmvc配置上传组件

      <!-- 配置自动上传组件 -->
      

    
    - web.xml添加如下配置,否则客服端无法访问png、jpg格式的文件
    
    ```xml
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.png</url-pattern>
      </servlet-mapping>
      <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.jpg</url-pattern>
      </servlet-mapping>
    
    • 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 javax.servlet.http.HttpSession;
      import java.io.File;
      import java.io.IOException;
      
      @Controller
      @RequestMapping("/file")
      public class FileHandler {
      
          @PostMapping("/upload")
          public String upload(MultipartFile img, HttpServletRequest httpServletRequest){
              if(img.getSize()>0){
               //获取保存上传文件的file路径
                  String path = httpServletRequest.getServletContext().getRealPath("file");
                  //获取上传的文件名
                  String name = img.getOriginalFilename();
                  File file = new File(path,name);
                  try {
                      img.transferTo(file);
                      //将保存的文件返回给客服端
                      httpServletRequest.setAttribute("path","/file/"+name);
                  } catch (IOException e) {
                      e.printStackTrace();
                  }
              }
              return "/jsp/upload";
          }
      

    }

    
    
  2. 多文件上传

    • JSP

      <%@ 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="上传">
              <c:forEach items="${files}" var="file">
                  <img src="${file}" width="300px">
              </c:forEach>
          </form>
      </body>
      </html>
      
    • 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 javax.servlet.http.HttpSession;
      import java.io.File;
      import java.io.IOException;
      import java.util.ArrayList;
      
      @Controller
      @RequestMapping("/file")
      public class FileHandler {
      
          @PostMapping("uploads")
          public String uploads(MultipartFile[] imgs,HttpServletRequest httpServletRequest){
              ArrayList<String> files = new ArrayList<>();
              for (MultipartFile img:imgs){
                  if(img.getSize()>0){
                      //获取保存上传文件的file路径
                      String path = httpServletRequest.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();
                      }
                  }
              }
              //将保存的文件返回给客服端
              httpServletRequest.setAttribute("files",files);
              return "/jsp/uploads";
          }
      }
      
    • 多文件上传要导入jstl包servlet相关的包springmvc框架不会提供

      	<dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
          </dependency>
      
    • 总结:

      多文件上传与单文件上传相识,多文件上传就是把多个文件保存到集合中再遍历保存在本地。


文件下载

  1. 下载

    JSP

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
        <a href="file/download1">1.png</a>
        <a href="file/download2">2.png</a>
        <a href="file/download3">3.png</a>
    </body>
    </html>
    

    Handler

    package com.southwind.controller;
    import org.apache.commons.io.FileUtils;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.multipart.MultipartFile;
    import org.springframework.stereotype.Controller;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpSession;
    import java.io.OutputStream;
    import java.io.IOException;
    import java.io.File;
    
    @Controller
    @RequestMapping("/file")
    public class FileHandler {
    
        @GetMapping("/download/{name}")
        public void download(@PathVariable("name") String name, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse){
            if (name != null){
                name += ".jpg";
                String path = httpServletRequest.getServletContext().getRealPath("file");
                File file = new File(path, name);
                OutputStream outputStream=null;
                if (file.exists()){
                    httpServletResponse.setContentType("application/forc-download");
                    httpServletResponse.setHeader("Content-Disposition","attachment;filename="+name);
                    try {
                        outputStream = httpServletResponse.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();
                            }
                        }
                    }
                }
            }
        }
    }
    
  2. 下载报错不知道那儿的问题,但是大致流程是这样子的。


6、SpringMVC框架自带的表单标签库

springMVC框架提供了一套用于简化开发的表单标签库。springframework自带的无需添加依赖。

form表单

使用springMVC自带的标签库时要先在JSP导入标签库

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

springmvc关于form表单的标签库中很多的标签如下:

  • <input type="text"/>
  • <input type="password"/>
  • <input type="checkbox"/> 复选框
  • <input type="checkbox"/> 简化
  • <input type="redio"/> 单选框
  • <input type="redio"/> 简化
  • <select name=""> <option value=""></option></select> 下拉框
  • <textarea/> 文本输入域
  • errors 处理错误信息
  1. <input tupe="textname="id" value="${student.id}"/> = <form:input path="id"/>

    form标签绑定的是模型数据,inpute标签绑定的是模型数据中的属性值,通过path属性可以与模型数据中的属性名对应,并且支持级联操作。

    • Handler

      @Controller
      @RequestMapping("/tag")
      public class TagHandler {
          @GetMapping("get")
          public ModelAndView get(){
              ModelAndView modelAndView = new ModelAndView();
              Student student = new Student(1L,"梅西",39);
      //        modelAndView.setViewName("/jsp/show");
              modelAndView.setViewName("/jsp/tag");
              modelAndView.addObject("student",student);
              return modelAndView;
          }
      }
      
    • JSP传统写法

      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <%@ page isELIgnored="false" %>
      <html>
      <head>
          <title>Title</title>
      </head>
      <body>
          <h1>学生信息</h1>
          <form>
              学生id: <input type="text" name="id" value="${student.id}">
              学生姓名:<input type="text" name="name" value="${student.name}">
              学生年龄:<input type="text" name="age" value="${student.age}">
              <input type="submit" value="提交">
          </form>
      </body>
      </html>
      
    • form标签写法

      <%@ 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>
      

      JSP页面SpringMVC表单标签库,与导入JSTL标签库的语法非常相似,浅醉prefix可以自定义,通常定义为form

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

    
    将form表单与模型数据进行绑定,通过modelAttribute属性完成绑定,将modelAttribute的值设置为模型数据对应的key值。
    
    ```jsp
    Handler: modelAndView.addObject("student",student);
    JSP: <form:form modelAttribute="student">
    

    form表单完成绑定之后,将模型数据的值取出绑定到不同的标签中,通过设置标签的path属性完成,将path属性的值设置为模型数据对应的属性名即可。

    学生id: <form:input path="id"/><br>
    学生姓名:<form:input path="name"/><br>
    学生年龄:<form:input path="age"/><br>
    
  2. <input tupe="password name="password"/> = <form:password path="password" />

    通过path属性与模型数据的属性值进行绑定,password标签的值不会在页面显示。

  3. <input type="checkbox" name="足球"/> = <form:checkbox path="ch1" value="足球"/>

    通过path与模型数据的属性值进行绑定,可以绑定boolean、数组和集合。

    如果绑定boolean值,若该变量的值为true,则表示该复选框选中,否则表示不选中。

    如果绑定数组或者集合,数组、集合中的元素与checkbox的value的属性的交集相同,则表示该复选框选中。

    sutdent.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>
    
  4. <form:checkboxes path="ch1" value="足球"/>对checkbox的简化

    需要结合items和path属性来使用,items绑定被遍历的集合或数组,path绑定被选中的集合或数组,可以这样理解,items为全部可选集合,path为默认的选中集合。

    student.setHobby(Arrays.asList("羽毛球","篮球","网球","足球","兵乓球","户外"));
    student.setSelectHobby(Arrays.asList"篮球","足球","兵乓球");
    
    爱好:<form:checkboxes path="selectHobby" items="${student.hobby}"/>
    

    需要注意的是 path可以直接绑定模型数据的属性值,items则需要通过EL表达式的形式从域对象中获取数据,不能直接写属性名。

  5. <input type="redio"/> = <form:radiobutton path="redio" value="0"/>

    绑定的数据与标签的value值相等则为选中,否则不选中。

    student.setRedio(0);
    modelAndView.addObject("student",student);
    
    <form:radiobutton path="redioId" value="0"/>radiobutton<br/>
    
  6. <form:radiobuttons items="${student.grade}" path="selectGrade"/> 对rediobutton对简化

    需要结合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.grade}" path="selectGrade"/>
    
  7. <select><option></selsct> = <form:select items="${student.cityMap}" path="selectCity"/>

    需要结合items和path两个属性来使用,items绑定被遍历的集合或数组,path绑定被选中的值,用法与<form:radiobuttons>一致。

     Map<Integer, String> cityMap = new HashMap<>();
            cityMap.put(1,"北京");
            cityMap.put(2,"上海");
            cityMap.put(3,"广州");
            cityMap.put(4,"深圳");
            student.setCityMap(cityMap);
            student.setSelectaCity(3);
            modelAndView.addObject("student",student);
    
    所在城市:<form:select items="${student.cityMap}" path="selectCity"/>
    

    select结合options(在后台定义)

    form:select结合form:options的使用,form:select只定义path属性,在form:select标签内部添加一个子标签form:options,设置items属性,获取被遍历的集合。

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

    selesct结合option(可在前台定义)

    form:select结合form:option的使用,form: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>
    		<!-- 虽然后端定义了1234为北上广深但显示时只显示杭州、成都、西安。 -->
    
  8. textarea

    path绑定模型数据的属性值,作为文本输入域的默认值。

    student.setIntroduce("你好啊");
    modelAndView.addObject("student",student);
    
    信息输入:<form:textarea path="introduce">
    
  9. errors

    处理错误信息,一般用在数据校验,该标签需要结合SpringMVC的验证器结合起来使用。

    <form:errors path="username"/><br>

SpringMVC数据校验

SpringMVC提供了两种数据校验的方式:1、基于Validator接口。2、使用AnnotationJSR-303标准进行校验。

基于Validator接口的方式需要自定义Validator验证器,每一条数据的验证规则需要开发者手动完成,使用AnnotationJSR-303标准则不需要自定义验证器,通过注解的方式可以直接在实体类中添加每一个属性的验证规则,这种方式跟加方便,实际开发中推荐使用。

  1. 基于Validator接口

    • 实体类Account

      package com.southwind.entity;
      
      public class Account {
          private String name;
          private String password;
      
          @Override
          public String toString() {
              return "Account{" +
                      "name=‘" + name + ‘\‘‘ +
                      ", password=‘" + password + ‘\‘‘ +
                      ‘}‘;
          }
          public Account(){
          }
          public Account(String name, String password) {
              this.name = name;
              this.password = password;
          }
          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;
          }
      }
      
    • 自定义验证器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,"密码不能为空");
            }
        }
      
    • springmvc.xml配置验证器否则验证器不生效

        <!-- 基于Validator的配置 -->
            <bean id="accountValidator" class="com.southwind.validator.AccountValidator"></bean>
            <mvc:annotation-driven validator="accountValidator"></mvc:annotation-driven>
      
    • JSP

      <%@ 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="account" action="/validator/login">
              姓名:<form:input path="name"/><br><form:errors path="name"></form:errors>
              密码:<form:input path="password"/><br><form:errors path="password"></form:errors>
              <input type="submit" value="登入"/>
          </form:form>
      </body>
      </html>
    
    • 控制器
    @Controller
    @RequestMapping("/validator")
    public class ValidatorHandler {
        @GetMapping("/login")
        public String login(Model model){
            model.addAttribute("account", new Account());
            return "/jsp/login";
        }
         @PostMapping("/login")
        public String login(@Validated Account account, BindingResult bindingResult){
            if(bindingResult.hasErrors()){
                return "/jsp/login";
            }
            return "index";
        }
    }
    
  2. 使用AnnotationJSR-303标准进行校验

    使用AnnotationJSR-303标准进行校验,需要导入支持这种标准的依赖jar文件,这里我们使用HibernateValidator。

    • 添加依赖pom.xml

      <!-- JSR-303 -->
          <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>7.0.1.Final</version>
          </dependency>
          <dependency>
            <groupId>io.ultreia.java4all</groupId>
            <artifactId>validation-api</artifactId>
            <version>1.0.0</version>
          </dependency>
          <dependency>
            <groupId>com.juul.tuulbox</groupId>
            <artifactId>logging</artifactId>
            <version>3.2.0</version>
          </dependency>
      
    • 通过注解的方式直接在实体类中添加相关验证规则。

      package com.southwind.entity;
      
      import jakarta.validation.constraints.Email;
      import jakarta.validation.constraints.NotEmpty;
      import jakarta.validation.constraints.Pattern;
      import jakarta.validation.constraints.Size;
      
      public class Person {
          @NotEmpty(message = "用户名不能为空")
          public 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_-]+)+$")
          private String email;
          @Pattern(regexp = "^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\\d{8}$")
          private String phone;
      
          @Override
          public String toString() {
              return "Person{" +
                      "username=‘" + username + ‘\‘‘ +
                      ", password=‘" + password + ‘\‘‘ +
                      ", email=‘" + email + ‘\‘‘ +
                      ", phone=‘" + phone + ‘\‘‘ +
                      ‘}‘;
          }
          public Person(@NotEmpty(message = "用户名不能为空") String username, @Size(min = 6, max = 12, message = "密码6-12位") String password, @Email(regexp = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$") String email, @Pattern(regexp = "^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\\d{8}$") String phone) {
              this.username = username;
              this.password = password;
              this.email = email;
              this.phone = phone;
          }
          public Person(){
          }
          public String getUsername() {
              return username;
          }
          public void setUsername(String username) {
              this.username = username;
          }
          public String getPassword() {
              return password;
          }
          public void setPassword(String password) {
              this.password = password;
          }
          public String getEmail() {
              return email;
          }
          public void setEmail(String email) {
              this.email = email;
          }
          public String getPhone() {
              return phone;
          }
          public void setPhone(String phone) {
              this.phone = phone;
          }
      }
      
    • 创建ValidatorHandler

      @GetMapping("register")
          public String register(Model model){
              model.addAttribute("person",new Person());
              return "/jsp/register";
          }
          @PostMapping("/register")
          public String register(@Valid Person person, BindingResult bindingResult){
              if (bindingResult.hasErrors()){
                  return "register";
              }
              return "index";
          }
      
    • 在springmvc.xml中配置

      <mvc:annotation-driven />
      
    • JSP

      <%@ 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/register">
              用户名:<form:input path="username"></form:input><form:errors path="username"/><br>
              密码:<form:input path="password"></form:input><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,String str = "",str不是null,其值为空。

浅入SpringMVC

原文:https://www.cnblogs.com/w-eye/p/14586302.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!