Spring MVC框架

18 篇文章 1 订阅

Spring MVC

SpringMVC是Spring Framework提供的Web组件,全称是Spring Web MVC,是目前主流的实现MVC设计模式的框架,提供前端路由映射、视图解析等功能。

Spring MVC功能

MVC:Controller(控制层),Model(模型层),View(视图层)
流程:Controller接收客户端请求,调用相关业务层组件产出Model,或业务数据并返回给Controller,Controller再结合View完成业务数据的视图层渲染,并将结果响应给客户端。
Spring MVC对这套MVC流程进行封装,帮助开发者屏蔽底层代码,并且开放相关接口供开发者调用,让MVC开发变得更加简单方便。

Spring MVC实现原理

核心组件

组件作用
DispatcherServlet前置控制器,负责调度其他组件的执行,可以降低不同组件之间的耦合性,是整个Spring MVC的核心模块
Handler处理器,完成具体的业务逻辑,相当于Servlet
HandlerMappingDispatcherServlet是通过HandlerMapping将请求映射到不同的Handler
HandlerInterceptor处理器拦截器,是一个接口,如果需要进行一些拦截处理,可以通过该接口完成
HandlerExecutionChain处理器执行链,包括两部分内容:Handler和HandlerInterceptor(系统会有一个默认的HandlerInterceptor,如果需要额外拦截处理,可以添加拦截器进行设置)
HandlerAdapter处理器适配器,Handler执行业务方法之前,需要进行一系列的操作包括表单的数据验证、数据类型的转换、将表单封装到POJO等
ModelAndView封装了模型数据和视图信息,作为Handler的处理结果,返回给DispatcherServlet
ViewResolver视图解析器,DispatcherServlet通过它将逻辑视图解析为物理视图,最终将渲染的结果响应给客户端

工作流程

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

一个简单的例子:

添加一个Maven工程,导入pom依赖

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>{版本号}</version>
    </dependency>
</dependencies>

在web.xml中配置SpringMVC的DispatcherServlet

    <servlet>
        <servlet-name>springmvc</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>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

配置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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        https://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
         http://www.springframework.org/schema/cache
         http://www.springframework.org/schema/cache/spring-cache.xsd">
    <!--自动扫描-->
    <context:component-scan base-package="com.test"/>
    <!--视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--前缀-->
        <property name="prefix" value="/"></property>
        <!--后缀-->
        <property name="suffix" value=".jsp"></property>
    </bean>
</beans>

创建Handler

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

@Controller
public class HelloHandler {
    @RequestMapping("/index")
    public String index(){
        System.out.println("接收到了请求");
        //返回逻辑视图
        return "index";
    }
}

流程梳理

  1. DispatcherServlet接收到URL请求index,结合@RequestMapping(“/index”)注解将该请求交给index业务方法进行处理
  2. 执行index业务方法,控制台打印日志,并返回"index"字符串(逻辑视图)
  3. 结合springmvc.xml中的视图解析器配置,找到目标资源:index.jsp,即根目录下的index.jsp文件将该JSP资源返回给客户端完成响应
    Spring MVC环境搭建成功

Spring MVC常用注解

@RequestMapping
Spring MVC通过@RequestMapping注解将URL请求与业务方法进行映射,在控制器的类定义处以及方法定义处都可以添加@RequestMapping,在类定义处添加相当于多了一层访问路径。
如上例,在类定义处加上该注解有

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("接收到了请求");
        //返回逻辑视图
        return "index";
    }
}

则访问地址变为:http://localhost:8080/hello/index

@RequestMapping常用参数

参数用法
value指定URL请求的实际地址,是@RequestMapptin的默认值,只有一个参数时可以省略,两个或以上参数时必须写
method指定请求的method类型,包括GET、POST、PUT、DELETE等
params指定request请求中必须包含的参数值,若不包含,无法调用该方法
params同时指定多个参数则写成params={"key1=value1","key2=value2"}的形式
该形式代码表名请求中必须包含key1和key2两个参数,并且值必须为其对应的值,否则抛出400错误
参数绑定

params是对URL请求参数进行限制,不满足条件的URL无法访问该方法,需要在业务方法中获取URL的参数值

  1. 在业务方法定义时声明参数列表
  2. 给参数列表添加@RequestParam注解进行绑定

例:将controller改为post方法,且传递参数num和str

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

@Controller
public class HelloHandler {
    @RequestMapping(value = "/index",method = RequestMethod.POST)
    public String index(@RequestParam("num") Integer id,@RequestParam("str") String name){
        System.out.println("接收到了请求,参数是id="+id+",name="+name);
        return "index";
    }

Spring MVC也支持RESTful风格的URL参数获取

传统的URL:localhost:8080/index?id=1&name=tom
RESTful URL:localhost:8080/hello/index/1/tom

修改controller

    @RequestMapping("/restful/{id}/{name}")
    public String restful(@PathVariable("id") Integer id,@PathVariable("name") String name){
        System.out.println(id+"-"+name);
        return "index";
    }

将参数列表的注解改为@PathVariable即可实现。

映射Cookie

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

使用POJO绑定参数

Spring MVC会根据请求参数名和POJO属性名进行匹配,自动为该对象填充属性值,并支持级联
创建实体类User

import lombok.Data;

@Data
public class User {
    private Integer id;
    private String name;
}

新建一个addUser.jsp文件

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="/add" method="post">
    <table>
        <tr>
        <td>
            <input type="text" name="id"/>
        </td>
        </tr>
        <tr>
            <td>
                <input type="text" name="name"/>
            </td>
        </tr>
        <tr>
            <td>
                <input type="submit" value="提交"/>
            </td>
        </tr>
    </table>
</form>
</body>
</html>

在controller类中添加

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

即可实现数值接收

如果出现中文乱码问题可以通过配置过滤器来解决,在web.xml中添加:

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

再加一套User里面的实体类Address,User变为

import lombok.Data;

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

Address类

import lombok.Data;

@Data
public class Address {
    private Integer code;
    private String value;
}

addUser.jsp添加地址信息

<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="/add" method="post">
    <table>
        <tr>
            <td>编号:</td>
        <td>
            <input type="text" name="id"/>
        </td>
        </tr>
        <tr>
            <td>姓名</td>
            <td>
                <input type="text" name="name"/>
            </td>
        </tr>
        <tr>
            <td>地址编号:</td>
            <td><input type="text" name="address.code"></td>
        </tr>
        <tr>
            <td>地址信息:</td>
            <td><input type="text" name="address.value"></td>
        </tr>
        <tr>
            <td>
                <input type="submit" value="提交"/>
            </td>
        </tr>
    </table>
</form>
</body>
</html>

框架可以根据变量名找到实体类中的变量自动进行绑定

主体对象可以没有无参构造函数,但是级联对象必须有无参构造函数

JSP页面的转发和重定向

Spring MVC默认以转发的形式响应JSP,可以手动进行修改。

以上述RESTful例为例,重定向访问

    @RequestMapping("/restful/{id}/{name}")
    public String restful(@PathVariable("id") Integer id,@PathVariable("name") String name){
        System.out.println(id+"-"+name);
        return "redirect:/index.jsp";
    }

注:设置重定向的时候不能写逻辑视图,必须写明资源的物理路径,如"redirect:/index.jsp"

转发的写法:

    @RequestMapping("/restful/{id}/{name}")
    public String restful(@PathVariable("id") Integer id,@PathVariable("name") String name){
        System.out.println(id+"-"+name);
        return "forward:/index.jsp";
    }

等同于

    @RequestMapping("/restful/{id}/{name}")
    public String restful(@PathVariable("id") Integer id,@PathVariable("name") String name){
        System.out.println(id+"-"+name);
        return "index";
    }

Spring MVC数据绑定

数据绑定:在后台业务方法中,直接获取前端HTTP请求中的参数
HTTP请求传输的参数都是String类型的,Handler业务方法中参数是开发者指定的数据类型,int、Integer、Object,因此需要进行数据类型的转换。

Spring MVC的Handler Adapter组件会在执行Handler业务方法之前,完成参数的绑定,开发者可以直接使用。

  • 基本数据类型

例:在Controller添加

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

@ResponseBody会直接返回id的字符串。

客户端HTTP请求中必须包含id参数,否则抛出500异常,因为id不能为null。同时id的值必须为数值且必须为整数,否则抛出400异常。

  • 包装类
    @RequestMapping("/packageType")
    @ResponseBody
    public String packageType(Integer id){
        return "id:"+id;
    }

如果HTTP请求中没有包含id参数,不会报错,id的值就是null,会直接返回id:null给客户端。但是如果id=a或者id=1.5同样会抛出400异常,因为数据类型无法匹配。

可以给参数列表添加@RequestParam注解,可以对参数进行相关设置

    @RequestMapping("/packageType")
    @ResponseBody
    public String packageType(@RequestParam(value = "id",required = true,defaultValue = "0") Integer id){
        return "id:"+id;
    }
value="id"将HTTP请求中名为id的参数与Handler业务方法中的形参进行映射
requiredtrue表示id参数必填,false表示非必填
defaultValue="0"表示当HTTP请求中没有id参数时,形参的默认值为0
  • 数组
    @RequestMapping("/arrayType")
    @ResponseBody
    public String arrayType(String[] names){
        StringBuffer stringBuffer=new StringBuffer();
        for(String str:names)
        {
            stringBuffer.append(str).append(" ");
        }
        return "names:"+stringBuffer.toString();
    }
  • POJO
    已在上例中体现加入@ResponseBody时返回值有乱码

为了使返回值不出现乱码,所以在springmvc.xml中加入

<mvc:annotation-driven>
        <!--消息转换器-->
        <mvc:message-converters>
            <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                <property name="supportedMediaTypes" value="text/html;charset=UTF-8"></property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>
  • List

Spring MVC不支持List类型的直接转换,需要包装成Object。
List自定义包装类

类UserList

import lombok.Data;

import java.util.List;
@Data
public class UserList {
    private List<User> users;
}

addList.jsp

<html>
<head>
    <title>Title</title>
</head>
<body>
    <form action="/listType" method="post">
        用户1ID:<input type="text" name="users[0].id"/><br>
        用户1姓名:<input type="text" name="users[0].name"/><br>
        用户2ID:<input type="text" name="users[1].id"/><br>
        用户2姓名:<input type="text" name="users[1].name"/><br>
        用户3ID:<input type="text" name="users[2].id"/><br>
        用户3姓名:<input type="text" name="users[2].name"/><br>
        <input type="submit" value="提交">
    </form>
</body>
</html>

Controller类

    @RequestMapping(value = "/listType",method = RequestMethod.POST)
    @ResponseBody
    public String listType(UserList users){
        StringBuffer stringBuffer=new StringBuffer();
        for(User user:users.getUsers())
        {
            stringBuffer.append(user);
        }
        return "users:"+users.toString();
    }

User类与前例一致,需要注意的是User类一定要有无参构造器,否则报错

  • Json

在pom.xml中添加依赖

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

在springmvc.xml中配置

    <mvc:annotation-driven>
        <mvc:message-converters>
            <!--fastjson-->
            <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter4"></bean>
        </mvc:message-converters>
    </mvc:annotation-driven>

在web.xml文件中添加读取js文件的标签

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

导入jQuery.min.js文件
创建json.jsp

<html>
<head>
    <title>Title</title>
    <script type="text/javascript" src="js/jQuery.min.js"></script>
    <script type="text/javascript">
        $(function (){
            var user={
                "id":1,
                "name":"test"
            };
            $.ajax({
                url:"/jsonType",
                data:JSON.stringify(user),
                type:"POST",
                contentType:"application/json;charset=UTF-8",
                dataType:"JSON",
                success:function (data){
                    alert(data.id)
                    alert(data.name)
                }
            })
        })
    </script>

</head>
<body>

</body>
</html>

则数据从页面传入后端再由后端返回给页面

  • Json数据必须用JSON.stringify()方法转换成字符串
  • contentType:"application/json;charset=UTF-8"不能省略

业务方法

    @RequestMapping("/jsonType")
    @ResponseBody
    public User jsonType(@RequestBody User user){
       user.setId(2);
        return user;
    }

@RequestBody注解
读取HTTP请求参数,通过SpringMVC提供的HttpMessageConverter接口读取的参数转为JSON、XML格式的数据,绑定到业务方法的形参。

@ResponseBody注解
将业务方法返回的对象,通过HttpMessageConverter接口转为指定格式的数据,JSON、XML等,响应给客户端。
需要使用组件结合@RequestBody注解将JSON转换为Java Bean,这里使用FastJson,其优势是如果属性为空就不会将其转为JSON

Spring MVC视图层解析

调用Web资源给域对象传值

page

request

session

application

业务数据的绑定是指将业务数据绑定给JSP域对象,业务数据的绑定是由ViewResolver来完成,开发时,先添加业务数据,再交给ViewResolver来绑定。Spring MVC提供了以下几种方式来添加业务数据:

  • Map
  • Model
  • ModelAndView
  • @SessionAttribute
  • @ModelAttribute
  • Servlet API
业务数据绑定到request域对象
Map

Spring MVC在调用业务方法之前会创建一个隐含对象作为业务数据的存储容器,设置业务方法的入参为Map类型,Spring MVC会将隐含对象的引用传递给入参。

创建一个Controller类ViewHandler

import com.test.entity.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.Map;

@Controller
@RequestMapping("/view")
public class ViewHandler {
    @RequestMapping("/map")
    public String map(Map<String,Object> map){
        User user=new User();
        user.setId(1);
        user.setName("张三");
        map.put("user",user);
        return "show";
    }
}

创建一个show.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false"%>
<html>
<head>
    <title>Title</title>
</head>
<body>
${requestScope.user}
</body>
</html>
Model

Model与Map类似,业务方法通过入参来完成业务数据的绑定

Controller类写入

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

与Map或者Model不同的是,ModelAndView不但包含业务数据,同时也封装了视图信息,如果使用ModelAndView来处理业务数据,业务方法的返回值必须是ModelAndView对象

业务方法中对ModelAndView进行两个操作:

  • 填充业务数据
  • 绑定试图信息

方法一

 public ModelAndView modelAndView1()
    {
        ModelAndView modelAndView=new ModelAndView();
        User user=new User();
        user.setId(1);
        user.setName("张三");
        //填充业务数据
        modelAndView.addObject("user",user);
        //绑定视图信息
        modelAndView.setViewName("show");
        return modelAndView;
    }

方法二

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

方法三

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

方法四

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

方法五

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

方法六

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

方法七

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

方法八

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

Spring MVC可以在业务方法中直接获取Servlet原生Web资源,只需要在方法定义时添加HttpServletRequest入参即可,在方法体中直接使用request对象

添加pom.xml参数导入servlet

    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>2.5</version>
    </dependency>

controller

    @RequestMapping("/request")
    public String request(HttpServletRequest httpServletRequest){
        User user=new User();
        user.setId(1);
        user.setName("张三");
        httpServletRequest.setAttribute("user",user);
        return "show";
    }
@ModelAttribute

Spring MVC还可以通过@ModelAttribute注解的方式添加业务数据:

  • 定义一个方法,该方法用来放好填充到业务数据中的对象
  • 给该方法添加@ModelAttribute注解,不是响应请求的业务方法。
 @RequestMapping("/modellAttribute")
    public String modelAttribute(){
        return "show";
    }

    @ModelAttribute
    public User getUser(){
        User user=new User();
        user.setId(1);
        user.setName("张三");
        return user;
    }

@ModelAttribute注解的作用是当Handler接收到一个请求后,无论调用哪个业务方法都会优先调用被@ModelAttribute注解修饰的方法,并将其返回值作为业务数据,再进入到业务方法中,此时业务方法只需要返回视图信息即可,不需要返回业务数据,即使返回业务数据,也会被@ModelAttribute注解修饰的方法返回的数据所覆盖

域对象中存值都以key-value形式存储的,那么此时key值默认值是物业数据对应的类的类名首字母小写之后的结果。

如果getUser没有返回值则必须手动在该方法中填充业务数据,使用Map或Model均可

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

如果同时存在两个@ModelAttribute注解方法,直接给Model进行装载的方法优先级更高。

业务数据绑定到session域对象

  • HttpSession

通过session传递

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

将作用域改为sessionScope

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false"%>
<html>
<head>
    <title>Title</title>
</head>
<body>
${sessionScope.user}
</body>
</html>

@SessionAttribute

@SessionAttribute注解不是给方法添加的,而是给类添加的。

@Controller
@RequestMapping("/view")
@SessionAttributes("user")
public class ViewHandler {
    @RequestMapping("/sessionAnnotation")
    public ModelAndView sessionAnnotation(){
        ModelAndView modelAndView=new ModelAndView("show");
        User user=new User();
        user.setId(1);
        user.setName("张三");
        modelAndView.addObject("user",user);
        return modelAndView;
    }
    }

@SessionAttributes通过key值定位,多个key值时可以写作:

@SessionAttributes(value={"user","student"})

@SessionAttributes也可以通过对象名添加

@SessionAttributes(types=User.class)

@SessionAttributes(type={User.class,Address.class})

只要给类加了@SessionAttributes注解之后,无论类中的哪个业务方法被访问,将业务数据绑定到request域对象的同时,也会将业务数据绑定到session域对象中,也就是说request和session对象会同时存在业务数据,前提是request域中的key值需要和@SessionAttributes注解中的value值一致。

Spring MVC的自定义数据类型转换器

  1. 创建DateConverter类,并实现org.springframework.core.convert.converter.Converter接口,成为一个自定义数据类型转换器,需要指定泛型<String,Date>,表示将String类型转为Date类型
import org.springframework.core.convert.converter.Converter;

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);
        try{
            return simpleDateFormat.parse(s);
        }
        catch (Exception e){e.printStackTrace();}
        return null;
    }
}

在springmvc.xml中配置conversionService bean,这个bean是org.springframework.context.support.ConversionServiceFactoryBean的实例化对象,同时bean中必须包含一个converters属性,在其中注册所有需要使用的自定义转换器

    <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <list>
                <bean class="com.test.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:annotation-driven>

添加一个Student类进行转换
Student类

import lombok.Data;

@Data
public class Student {
    private Integer id;
    private String name;
    private Integer age;
}

springmvc.xml添加

    <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <list>
                <bean class="com.test.converter.StudentConverter"></bean>
            </list>
        </property>
    </bean>
<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>

添加转换类StudentConverter

import com.test.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(Integer.parseInt(args[0]));
        student.setName(args[1]);
        student.setAge(Integer.parseInt(args[2]));
        return student;
    }
}

添加jsp页面student.jsp

<%@ 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"/>(1-张三-22)
        <input type="submit" value="提交"/>
    </form>
</body>
</html>

注册controller

import com.test.entity.Student;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;


@Controller
@RequestMapping(value = "/converter")
public class ConvertHandler {
    @RequestMapping("/student")
    @ResponseBody
    public Student student(Student student, HttpServletResponse response)
    {
        response.setCharacterEncoding("UTF-8");
        return student;
    }
}

Spring MVC与RESTful集成

  • 什么是RESTful?
    RESTful是当前比较流行的一种互联网软件架构模型,通过统一的规范完成不同终端的数据访问和交互,REST全称是Representational State Transfer(资源表现层状态转换)

RESTful的优点:结构清晰、有统一的标准、拓展性好

  • Resources

资源指的是网络中的某个具体文件,类型不限,可以是文本、图片、视频、音频、数据流等,是网络中真实存在的实体。可以通过统一资源定位符找到这个实体,URI,每个资源都有一个特定的URI,通过URI就可以找到一个具体的资源。

  • Pepresentation

资源表现层,资源的具体表现形式,例如一段文字,可以使用TXT、HTML、XML、JSON等不同的形式来描述它。

  • State Transfer

状态转化是指客户端和服务端之间的数据交互,因为HTTP请求不能传输数据的状态,所有的状态都保存在服务端,如果客户端希望访问服务端的数据,就需要使其发生状态改变,同时这种状态转化是建立在表现层上的,完成转换就表示资源的表现形式发生了改变。

RESTful概念比较抽象,特点有两个:

  1. URL传参更加简洁
  • 传统形式 URL http://localhost:8080/query/findById?id=1
  • RESTful URL: http://localhost:8080/findById/1
  1. 完成不同终端之间资源共享,RESTful提供了一套规范,不同终端之间只需要遵守该规范,就可以实现数据交互。

具体来讲就是四种表现形式,HTTP协议中四种请求类型(GET、POST、PUT、DELETE)分别表示四种常规操作,CRUD

  • GET用来获取资源
  • POST用来创建资源
  • PUT用来修改资源
  • DELETE用来删除资源

两个终端要完成数据交互,基于RESTful的方式,增删改查操作分别需要使用不同的HTTP请求类型来访问。

传统的Web开发中,form只支持GET和POST,不支持DELETE和PUT,通过添加HiddenHttpMethodFilter过滤器,可以将POST请求转为PUT或DELETE。

HiddenHttpMethodFilter的实现原理

HiddenHttpMethodFilter检测请求参数中是否包含_method参数,如果包含则取出它的值,并且判断请求类型之后完成请求类型的转换,然后继续传递。

实现步骤

在form表单中添加隐藏域标签,name为_method,value为DELETE或PUT

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
  <form action="/rest/update" method="post">
      <input type="hidden" name="_method" value="PUT"/>
      <input type="submit" value="提交"/>
  </form>
</body>
</html>

在web.xml中配置HiddenHttpMethodFilter

  <!--HiddenHttpMethodFilter-->
  <filter>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
  </filter>
  
  <filter-mapping>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

Handler

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

@Controller
@RequestMapping("/rest")
public class RESTfulHandler {
    @GetMapping("/find")
    @ResponseBody
    public String find()
    {
        return "Hello";
    }

    @PostMapping("/save")
    public void save(){

    }
    @PutMapping("/update")
    @ResponseBody
    public String update(){
        return "接收到PUT请求";
    }

    @DeleteMapping("/delete")
    @ResponseBody
    public String delete(){
        return "已接受到DELETE请求";
    }

}
一个小案例

需求分析

  • 添加课程,成功则返回全部课程信息
  • 查询课程,通过id查询对应课程信息
  • 修改课程,成功则返回修改之后的全部课程信息
  • 删除课程,成功则返回删除之后的全部课程信息

jsp

  • 添加课程 add.jsp
  • 修改课程 edit.jsp
  • 课程展示 index.jsp

添加jstl依赖

    <!--JSTL-->
    <dependency>
      <groupId>jstl</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>

实体类

private Integer id;
private String name;
private Double price;

CourseRepository

@Repository
public class CourseRepository {
    private Map<Integer, Course> courseMap;

    public CourseRepository(){
        courseMap=new HashMap<>();
        courseMap.put(1,new Course(1,"Java基础",Double.parseDouble("500")));
        courseMap.put(2,new Course(2,"Java高级",Double.parseDouble("600")));
        courseMap.put(3,new Course(3,"企业级框架",Double.parseDouble("800")));
    }
    public Collection<Course> findAll(){
        return courseMap.values();
    }
    public Course findById(Integer id){
        return courseMap.get(id);
    }
    public void SaveOrUpdate(Course course){
        courseMap.put(course.getId(),course);
    }
    public void deleteById(Integer id){
        courseMap.remove(id);
    }
}

改写下index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@page isELIgnored="false"%>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <table>
        <tr>
            <th>编号</th>
            <th>名称</th>
            <th>价格</th>
        </tr>
        <c:forEach items="${list}" var="course">
            <tr>
                <td>${course.id}</td>
                <td>${course.name}</td>
                <td>${course.price}</td>
                <td>
                    <form action="/course/deleteById/${course.id}" method="post">
                        <input type="hidden" name="_method" value="DELETE"/>
                        <input type="submit" value="删除"/>
                    </form>
                    <a href="/course/findById/${course.id}">修改</a>
                </td>
            </tr>

        </c:forEach>
    </table>
</body>
</html>

CourseController

import com.test.entity.Course;
import com.test.repository.CourseRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping("/course")
public class CourseController {
    @Autowired
    private CourseRepository courseRepository;

    @GetMapping("/findAll")
    public ModelAndView findAll(){
            ModelAndView modelAndView=new ModelAndView();
            modelAndView.setViewName("index");
            modelAndView.addObject("list",courseRepository.findAll());
            return modelAndView;
    }

    @PostMapping("/save")
    public String save(Course course){
        courseRepository.saveOrUpdate(course);
        return "redirect:/course/findAll";
    }
    @DeleteMapping("/deleteById/{id}")
    public String deleteById(@PathVariable("id") Integer id){
        courseRepository.deleteById(id);
        return "redirect:/course/findAll";
    }
    @GetMapping("/findById/{id}")
    public ModelAndView findById(@PathVariable("id") Integer id){
        ModelAndView modelAndView=new ModelAndView();
        modelAndView.setViewName("edit");
        modelAndView.addObject("courser",courseRepository.findById(id));
        return modelAndView;
    }
    @PutMapping("/update")
    public String update(Course course){
        courseRepository.saveOrUpdate(course);
        return "redirect:/course/findAll";
    }
}

save.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
  <form action="/course/save" method="post">
      <table>
        <tr>
          <td>课程编号:</td>
          <td>
            <input type="text" name="id"/>
          </td>
        </tr>
        <tr>
          <td>课程名称:</td>
          <td>
            <input type="text" name="name"/>
          </td>
        </tr>
        <tr>
          <td>课程价格:</td>
          <td>
            <input type="text" name="price"/>
          </td>
        </tr>
        <tr>
            <td>
              <input type="submit" value="提交"/>
            </td>
        </tr>
      </table>
  </form>
</body>
</html>

edit.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false"%>
<html>
<head>
    <title>Title</title>
</head>
<body>
  <form action="/course/update" method="post">
    <input type="hidden" name="_method" value="PUT"/>
    <table>
      <tr>
        <td>编号:</td>
        <td>
          <input type="text" name="id" value="${courser.id}" readonly/>
        </td>
      </tr>
      <tr>
        <td>名称:</td>
        <td>
          <input type="text" name="name" value="${courser.name}"/>
        </td>
      </tr>
      <tr>
        <td>价格:</td>
        <td>
          <input type="text" name="price" value="${courser.price}"/>
        </td>
      </tr>
      <tr>
        <td><input type="submit" value="提交"></td>
      </tr>
    </table>
  </form>
</body>
</html>

Spring MVC实现文件的上传下载

文件上传

单文件上传
  1. 底层使用的是Apache fileupload组件完成上传功能,SpringMVC只是对其进行了封装,简化开发

pom.xml引入依赖

    <!--apache fileupload-->
    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.6</version>
    </dependency>
    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.3.3</version>
    </dependency>

JSP页面

input的type设置为file
form表单的method设置为post
form表单enctype设置为multipart/form-data

upload.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>
    <img src="${src}"/>
</body>
</html>

FileHandler

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

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

@Controller
@RequestMapping("/file")
public class FileHandler {
    @PostMapping("/upload")
    public String upload(@RequestParam("img") MultipartFile img, HttpServletRequest request){
        if(img.getSize()>0){
            String path=request.getSession().getServletContext().getRealPath("file");
            String fileName=img.getOriginalFilename();
            File file=new File(path,fileName);
            try{
            img.transferTo(file);
                request.setAttribute("src","/file/"+fileName);
            }
            catch (Exception e){e.printStackTrace();}
        }

        return "upload";
    }
}

在springmvc.xml中配解析器

 <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>
多文件上传

uploads.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ page isELIgnored="false" %>
<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="${list}" var="path">
    <img width="300px" src="${path}"/>
</c:forEach>
</body>
</html>

controller

    @RequestMapping("/uploads")
    public String uploads(@RequestParam("imgs") MultipartFile[] imgs,HttpServletRequest request){
        List<String> pathList=new ArrayList<>();

        for (MultipartFile img:imgs){
            if(img.getSize()>0){
                String path=request.getSession().getServletContext().getRealPath("file");
                String fileName=img.getOriginalFilename();
                File file=new File(path,fileName);
                try{
                    img.transferTo(file);
                    pathList.add("/file/"+fileName);
                }
                catch (Exception e){e.printStackTrace();}
        }
            request.setAttribute("list",pathList);
    }
        return "uploads";
}

Spring MVC数据校验

数据校验是每个项目必不可少的模块,SpringMVC提供了两种数据校验的组件:

  • 基于Validator接口进行校验
  • 使用Annotation JSR-303标准校验

使用基于Validator接口进行校验会复杂一些,具体数据校验的规则需要开发者手动设置。而使用Annotation JSR-303标准会相对简单一些,开发者不需要编写校验规则,直接通过注解的形式给每一条数据添加验证规则,具体操作是直接在实体类的属性上添加对应的校验注解即可。

基于Validator接口

例:

创建实体类:

import lombok.Data;

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

自定义数据校验器StudentValidation,实现Validation接口,重写接口的抽象方法,加入校验规则。

import com.test.Entity.Student;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;

public class StudentValidation implements Validator {
    public boolean supports(Class<?> aClass) {
        return Student.class.equals(aClass);
    }

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

ValidateHandler.java

import com.test.Entity.Student;
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("/validate")
public class ValidateHandler {
    /**
     * 给JSP表单绑定模型对象
     * */
    @GetMapping("/login")
    public String login(Model model){
        model.addAttribute(new Student());
        return "login";
    }

    /**
     * 数据校验
     * */
    @PostMapping("/login")
    public String login(@Validated Student student, BindingResult bindingResult){
        if(bindingResult.hasErrors()){
            return "login";
        }
        return "success";
    }
}

springmvc.xml配置validator

    <mvc:annotation-driven validator="studentValidator"></mvc:annotation-driven>
    <bean id="studentValidator" class="com.test.validation.StudentValidation"></bean>

JSP

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>学生登录</h1>
    <form:form modelAttribute="student" action="/validate/login" method="post">
        学生姓名:<form:input path="name"></form:input><form:errors path="name"></form:errors> <br>
        学生密码:<form:input path="password"></form:input><form:errors path="password"></form:errors>
    </form:form>
</body>
</html>
Annotation JSR-303标准

Hibernater Validator,通过注解完成校验规则的绑定。
@Null 只能为null
@NotNull 不能为null
@Size 设置数据长度
@NotEmpty 不能为空

例:

pom.xml

    <!--JSR-303-->
    <dependency>
      <groupId>org.hibernate.validator</groupId>
      <artifactId>hibernate-validator</artifactId>
      <version>6.0.11.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.4.1.Final</version>
    </dependency>

    <!--JDK9以上-->
    <dependency>
      <groupId>javax.xml.bind</groupId>
      <artifactId>jaxb-api</artifactId>
      <version>2.3.1</version>
    </dependency>
    <dependency>
      <groupId>com.sun.xml.bind</groupId>
      <artifactId>jaxb-impl</artifactId>
      <version>2.3.0</version>
    </dependency>
    <dependency>
      <groupId>com.sun.xml.bind</groupId>
      <artifactId>jaxb-core</artifactId>
      <version>2.3.0</version>
    </dependency>
    <dependency>
      <groupId>javax.activation</groupId>
      <artifactId>activation</artifactId>
      <version>1.1.1</version>
    </dependency>

创建实体类,通过注解的方式给属性指定校验规则

import lombok.Data;

import javax.validation.constraints.Email;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;

@Data
public class Account {
    @NotEmpty(message = "用户名不能为空")
    private String username;
    @Size(min=6,max=20,message = "密码长度为6-20位")
    private String password;
    @Email(regexp = "^[a-z]([a-z0-9]*[-_]?[a-z0-9]+)*@([a-z0-9]*[-_]?[a-z0-9]+)+[\\.][a-z]{2,3}([\\.][a-z]{2})?$",message = "请输入正确的邮箱")
    private String email;
    @Pattern(regexp = "^1(3|4|5|7|8)\\d{9}$",message = "请输入正确的电话格式")
    private String phone;
}

业务方法

    @GetMapping("/register")
    public String register(Model model){
        model.addAttribute(new Account());
        return "register";
    }
    @PostMapping("register")
    public String register(@Valid Account account,BindingResult bindingResult){
        if(bindingResult.hasErrors()){
            return "register";
        }
        return "success";
    }

springmvc.xml

<mvc:annotation-driven></mvc:annotation-driven>

JSP

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>用户注册</h1>
    <form:form modelAttribute="account" action="/validate/register">
        用户名:<form:input path="username"></form:input><form:errors path="username"></form:errors><br>
        密码:<form:input path="password"></form:input><form:errors path="password"></form:errors><br>
        邮箱:<form:input path="email"></form:input><form:errors path="email"></form:errors><br>
        电话:<form:input path="phone"></form:input><form:errors path="phone"></form:errors><br>
        <input type="submit" value="提交"/>
    </form:form>

</body>
</html>
Spring MVC表单标签库

例:

Student实体类

import lombok.Data;

@Data
public class Student {
    private Integer id;
    private String name;
    private Integer age;
    private String gender;
}
import com.test.entity2.Student;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/student")
public class StudentHandler {
    
    @RequestMapping("/get")
    public String get(Model model){
        Student student=new Student();
        model.addAttribute("student",student);
        return "student";
    }
}

JSP

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@page isELIgnored="false" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>修改学生信息</h1>
    <form action="" method="post">
      学生编号:<input type="text" name="id" value="${student.id}" readonly/><br>
      学生姓名:<input type="text" name="name" value="${student.name}"/><br>
      学生年龄:<input type="text" name="age" value="${student.age}"/><br>
      学会性别:<input type="text" name="gender" value="${student.gender}"/><br>
      <input type="submit" value="提交"/>
    </form>
</body>
</html>

Handler

import com.test.entity2.Student;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/student")
public class StudentHandler {

    @RequestMapping("/get")
    public String get(Model model){
        Student student=new Student();
        student.setId(1);
        student.setName("张三");
        student.setAge(22);
        student.setGender("男");
        model.addAttribute("student",student);
        return "student";
    }
}
表单标签库的使用

JSP页面导入Spring MVC表单标签库

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

将form表单与表单业务数据进行绑定,通过modelAttribute属性完成绑定,将modelAttribute的值设置为控制器想model对象存值时的name即可

<form:form modelAttribute="student" action="/student/update" method="post">
    学生编号:<form:input path="id"></form:input>
    学生姓名:<form:input path="name"></form:input>
    学生年龄:<form:input path="age"></form:input>
    学生性别:<form:input path="gender"></form:input>
    <input type="submit" value="提交"/>
</form:form>
常用标签

1.form标签

<form:form modelAttribute="student" method="post"></form:form>

渲染的时HTML中的 <form></form>,通过modelAttribute属性绑定具体业务数据。

2.input标签

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

渲染的时HTML中的<input type="text"/>,form绑定的是业务数据,input标签绑定的是业务数据中的属性值,通过path与业务数据的属性名对应,并支持级联。

例:

实体类

import lombok.Data;

@Data
public class Address {
    private Integer id;
    private String name;
}

import lombok.Data;

@Data
public class Student {
    private Integer id;
    private String name;
    private Integer age;
    private String gender;
    private Address address;
}

JSP

<form:form modelAttribute="student" action="/student/update" method="post">
    学生编号:<form:input path="id"></form:input>
    学生姓名:<form:input path="name"></form:input>
    学生年龄:<form:input path="age"></form:input>
    学生性别:<form:input path="gender"></form:input>
    学生地址:<form:input path="address.name"></form:input>
    <input type="submit" value="提交"/>
</form:form>

Handler

    @RequestMapping("/get")
    public String get(Model model){
        Student student=new Student();
        student.setId(1);
        student.setName("张三");
        student.setAge(22);
        student.setGender("男");

        Address address=new Address();
        address.setId(1);
        address.setName("科技路");
        student.setAddress(address);
        model.addAttribute("student",student);
        return "student";
    }

3.password标签

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

渲染的是HTML中的<input type="password"/>通过path与业务数据的属性名对应,password标签的值不会在页面显示。

4.checkbox标签

<form:checkbox path="hobby" value="读书"></form:checkbox>

渲染的是HTML中的<input type="checkbox"/>,通过path与业务数据的属性名对应,可以绑定boolean、数组和集合。

如果绑定boolean类型的变量,该变量值为true则表示选中,false表示不选中。

JSP

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

如果绑定数组和集合类型,集合中的元素等于checkbox的value值,则该项选中,否则不选中。

JSP

    <form:checkbox path="hobby" value="读书"></form:checkbox>读书
    <form:checkbox path="hobby" value="看电影"></form:checkbox>看电影
    <form:checkbox path="hobby" value="打游戏"></form:checkbox>打游戏
    <form:checkbox path="hobby" value="听音乐"></form:checkbox>听音乐
    <form:checkbox path="hobby" value="旅行"></form:checkbox>旅行
    <input type="submit" value="提交"/>

5.checkboxs标签

<form:checkboxs items="${student.hobby}" path="selectHobby"></form:checkboxs>

渲染的是HTML中的一组<input type="checkbox"/>,这里需要结合items和path两个属性来使用,items绑定被遍历的集合或数组,path绑定选中的集合或数组items是全部选型,path为默认选中的选型

        student.setHobby(Arrays.asList("读书","看电影","旅行"));
        student.setSelectHobby(Arrays.asList("读书","看电影"));

JSP

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

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

6.radiobutton

<form:radiobutton path="radioId" value="0"></form:radiobutton>

渲染的是HTML中的一个<input type="radio"/>,绑定的数据与标签的value值相等为选中状态,否则为不选中状态。

    private Integer radioId;

JSP

    <form:radiobutton path="radioId" value="0"></form:radiobutton>男
    <form:radiobutton path="radioId" value="1"></form:radiobutton>女

7.radiobuttons标签

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

渲染的是HTML中的一组<input type="radio"/>,这里需要结合items和path两个属性来使用,item绑定被遍历的集合或数组,path绑定被选中的值,items是全部选型,path为默认选中的选型。

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

JSP

    <form:radiobuttons path="selectGrade" items="${student.gradeMap}"></form:radiobuttons>

8.select标签

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

渲染的是HTML中的一个<select/>,这里需要结合items和path两个属性来使用,items绑定被遍历的集合或数组,path绑定被选中的值,用法与<radiobuttons/>标签一致。

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

JSP

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

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

10.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>
SpringMVC国际化

国际化是指同一个应用程序在不同语言设置的浏览器中,自动显示不同的语言,Spring MVC对国际化操作做了很好的集成,只需要简单的配置即可实现国际化。

1.springmvc.xml中配置

    <!--国际化资源文件-->
    <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <!--多语言配置文件放在根路径,以language开头-->
        <property name="basename" value="classpath:language"></property>
        <property name="useCodeAsDefaultMessage" value="true"></property>
    </bean>
    <!--拦截器-->
    <mvc:interceptors>
        <bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
            <property name="paramName" value="lang"></property>
        </bean>
    </mvc:interceptors>
    <!--配置sessionLocalResolver,动态获取Locale对象存入session-->
    <bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver"></bean>
    

创建国际化资源文件language_en_US.properties,language_zh_CN.properties,分别存储英文和中文资源

language_en_US.properties

language.en = English
language.cn = \u4e2d\u6587
info = login
username = username
password = password
repassword = repassword
tel = tel
email = email
submit = submit
reset = reset

language_zh_CN.properties

language.en = English
language.cn = \u4e2d\u6587
info = \u767b\u5f55
username = \u7528\u6237\u540d
password = \u5bc6\u7801
repassword = \u786e\u8ba4\u5bc6\u7801
tel = \u7535\u8bdd
email = \u7535\u5b50\u90ae\u7bb1
submit = \u63d0\u4ea4
reset = \u91cd\u7f6e

Handler

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

@Controller
@RequestMapping("/inter")
public class InterHandler {
    @GetMapping("/index")
    public String index(){
        return "inter";
    }
}

JSP

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<html>
<head>
    <title>Title</title>
</head>
<body>
<a href="index?lang=en_US">English</a>
<a href="index?lang=zh_CN">中文</a>
<h1><spring:message code ="info"></spring:message></h1>
    <form>
    <spring:message code="username"/>:<input type="text"/><br>
    <spring:message code="password"/>:<input type="password"/><br>
    <spring:message code="repassword"/><input type="password"/><br>
      <spring:message code="tel"/><input type="text"/><br>
      <spring:message code="email"/><input type="text"/></br>
      <input type="submit" value="<spring:message code="submit"/>"/>
      <input type="reset" value="<spring:message code="reset"/> "/>
    </form>
</body>
</html>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

盛者无名

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值