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 |
HandlerMapping | DispatcherServlet是通过HandlerMapping将请求映射到不同的Handler |
HandlerInterceptor | 处理器拦截器,是一个接口,如果需要进行一些拦截处理,可以通过该接口完成 |
HandlerExecutionChain | 处理器执行链,包括两部分内容:Handler和HandlerInterceptor(系统会有一个默认的HandlerInterceptor,如果需要额外拦截处理,可以添加拦截器进行设置) |
HandlerAdapter | 处理器适配器,Handler执行业务方法之前,需要进行一系列的操作包括表单的数据验证、数据类型的转换、将表单封装到POJO等 |
ModelAndView | 封装了模型数据和视图信息,作为Handler的处理结果,返回给DispatcherServlet |
ViewResolver | 视图解析器,DispatcherServlet通过它将逻辑视图解析为物理视图,最终将渲染的结果响应给客户端 |
工作流程
- 客户端请求被DispatcherServlet接收
- 根据HandlerMapping映射到Handler
- 生成Handler和HandlerInterceptor
- Handler和HandlerInterceptor以HandlerExecutionChain的形式一并返回给DispatcherServlet
- DispatcherServlet通过HandlerAdapter调用Handler的方法完成业务逻辑处理
- 返回一个ModelAndView对象给DispatcherServlet
- DispatcherServlet将获取的ModelAndView视图解析器,将逻辑视图解析成物理视图
- ViewResolver返回一个View给DispatcherServlet
- DispatcherServlet根据View进行视图渲染(将模型数据填充到视图中)
- 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";
}
}
流程梳理
- DispatcherServlet接收到URL请求index,结合@RequestMapping(“/index”)注解将该请求交给index业务方法进行处理
- 执行index业务方法,控制台打印日志,并返回"index"字符串(逻辑视图)
- 结合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的参数值
- 在业务方法定义时声明参数列表
- 给参数列表添加@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业务方法中的形参进行映射 |
required | true表示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的自定义数据类型转换器
- 创建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概念比较抽象,特点有两个:
- URL传参更加简洁
- 传统形式 URL http://localhost:8080/query/findById?id=1
- RESTful URL: http://localhost:8080/findById/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实现文件的上传下载
文件上传
单文件上传
- 底层使用的是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>