Spring MVC
Spring MVC是什么?
Spring MVC是Spring框架中的一个分支,是目前最好的实现MVC设计模式的框架,以Spring框架的IoC容器为基础,并利用容器的特性来简化它的配置,Spring MVC相当于Spring的一个子模块,可以很好地和Spring框架进行整合开发,是Java Web开发者必须要掌握的框架。
Spring MVC能干什么?
实现了MVC设计模式,该设计模式是一种常用的软件架构方式:以Controller(控制层)、Model(模型层)、View(视图层)三个模块分离的形式来组织代码。
MVC流程:控制层接收到客户端请求,调用模型层生成业务数据,传递给视图层,将最终的业务数据和视图响应给客户端做展示。
Spring MVC就是对这套流程的封装,屏蔽了很多底层代码,开放出接口,让开发者可以更加轻松快捷地完成基于MVC设计模式的Web开发。
Spring MVC实现原理
Spring MVC环境搭建及其使用
Spring MVC常用的注解
映射Cookie
使用POJO绑定参数
重定向和转发
Spring MVC数据绑定
Spring MVC 视图解析
Spring MVC 自定义数据类型转换器
Spring MVC 集成RESTful架构
HiddenHttpMethodFilter
Spring MVC 文件的上传下载
Spring MVC 表单标签库
Spring MVC 实现原理
核⼼组件
- (1)DispatcherServlet:前端控制器, 负责调度其他组件的执⾏,可降低不同组件之间的耦合性,Spring MVC 的核⼼模块。
- (2)Handler:处理器, 完成具体的业务逻辑。(相当于Servlet)
- (3)HandlerMapping: DispatcherServlet 是通过 HandlerMapping 将请求映射到不同的 Handler。
- (4)HandlerInterceptor:处理器拦截器, 是⼀个接⼝,如果需要完成⼀些拦截处理,可以实现该接⼝。
- (5)HandlerExecutionChain:处理器执⾏链, 包括两部分内容,Handler 和 HandlerInterceptor。
- (6)HandlerAdapter:处理器适配器, 它可以完成执⾏业务逻辑之前的⼀些预处理,数据类型转换、封装等, DispatcherServlet 通过 HandlerAdapter 调⽤不同的Handler。
- (7)ModelAndView:装载了模型数据和视图信息, 作为 Hanlder 的处理结果,返回给DispatcherServlet。
- (8)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 对象传给 ViewResolver ,将逻辑视图解析为物理视图View。
-
8.ViewResolver 返回⼀个 View 给 DispatcherServlet。
-
9.DispatcherServlet 根据 View 进⾏视图渲染(将模型数据填充到视图中)。
-
10.DispatcherServlet 将渲染后的视图响应给客户端。
返回最顶层
Spring MVC的使用
pom.xml
web.xml
springmvc.xml
返回最顶层
pom.xml
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
</dependencies>
返回本节头部
在 web.xml 中配置 Spring MVC 的 DispatcherServlet。
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>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>
</web-app>
返回本节头部
springmvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
<!-- 配置⾃动扫描 -->
<context:component-scan base-package="com.chenny"></context:component-scan>
<!-- 配置视图解析器 -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
返回本节头部
Spring MVC常用的注解
-
@RequestMapping
Spring MVC 通过 @RequestMapping 注解将请求与业务⽅法进⾏映射,在⽅法定义处,在类定义都可以添加该注解。
Spring MVC通过@RequestMapping注解将url请求与业务方法进行映射,在控制器的类定义处以及方法定义处都可添加@RequestMapping注解,在类定义处添加@RequestMapping注解,相当于多了一层访问路径。
-
@RequestMapping 常⽤参数
- value:指定请求的实际地址, @RequestMapping 的默认值。
- method:指定请求的类型, GET、 POST、 PUT、 DELETE。
- params:指定请求必须包含的参数。
package com.chenny.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
@RequestMapping("/hello")
public class HelloHandler {
//value浏览器传入的值
@RequestMapping(value = "/index",method = RequestMethod.GET,params = {"id=10","name"})
public String index(@RequestParam("id") int num,@RequestParam("name") String name){
System.out.println(num);
System.out.println(name);
return "show";
//return 是返回的jsp页面的名字
}
@RequestMapping("/rest/{id}/{name}")
public String rest(@PathVariable("id") int num,@PathVariable("name") String name){
System.out.println(num);
System.out.println(name);
return "show";
}
}
- 参数绑定
-
在业务⽅法定义时声明参数列表。
-
给参数添加 @RequestParam 注解。
-
SpringMVC 也⽀持 RESTful ⻛格的 URL 参数获取
@RequestMapping(value = "/index",params = {"name","value"}) public String index(@RequestParam("name") String name,@RequestParam("value") String value){ System.out.println(name); System.out.println(value); return "show"; }
传统: http://localhost:8080/hello/index?id=10&name=1 RESTful: http://localhost:8080/hello/rest/10/1
/*
* 传统风格
*/
@RequestMapping(value = "/index",method = RequestMethod.GET,params = {"id=10","name"})
public String index(@RequestParam("id") int num,@RequestParam("name") String gender){
System.out.println(num);
System.out.println(gender);
return "index";
}
/*
* Restful风格
*/
@RequestMapping("/rest/{id}/{name}")
public String rest(@PathVariable("id") int id ,@PathVariable("name") String name){
return "show";
}
返回头部
映射Cookie
@RequestMapping("/cookie")
public String cookie(@CookieValue("JSESSIONID") String sessionId){
System.out.println(sessionId);
return "index";
}
返回头部
重定向和转发
Spring MVC默认以转发的形式响应JSP,也可以自主进行设置。
重定向:
@RequestMapping("/cookie")
public String getCookie(@CookieValue("JSESSIONID") String sessionId){
System.out.println(sessionId);
return "redirect:/index.jsp";
}
转发:
@RequestMapping("/cookie")
public String getCookie(@CookieValue("JSESSIONID") String sessionId){
System.out.println(sessionId);
return "forward:/index.jsp";
}
返回头部
Spring MVC 数据绑定
什么是数据绑定?在后台业务方法中,直接获取前端HTTP请求中参数的形式,将HTTP请求中的参数之间绑定到业务方法参数列表的方式就是数据绑定。
-
底层原理:HTTP请求传输的参数都是String类型,但是Handler的业务方法中的参数都是开发者指定的数据类型,如int、Object等,所以需要处理参数的类型转换。具体的转换工作不需要开发者去完成,Spring MVC的HandlerAdapter组件会在执行Handler业务方法之前,完成参数的绑定。
基本数据类型
-
以int为例,后台需要int类型的参数,直接在业务方法定义处添加int类型的形参即可,HTTP请求参数名称要与形参保持一致。
-
@ResponseBody 注解直接将数据以字符串的形式响应给客户端。
@RequestMapping("/baseType")
@ResponseBody
public String baseType(@RequestParam("id") int num){
System.out.println(num+1);
return "num:"+num;
}
包装类
@RequestMapping("/packageType")
@ResponseBody
public String packageType(@RequestParam(value = "num",required = false,defaultValue = "1") Integer num){
return "num:"+num;
}
- @RequestParam:
- value = “num”: 将HTTP请求中名为num的参数与形参进行映射。
- required = false: num参数为非必填项,可以省略。
- defaultValue = “1”: 若HTTP请求中没有num参数,默认值为1。
返回头部
数组
@RequestMapping("/arrayType")
@ResponseBody
public String arrayType(String[] name){
StringBuffer stringBuffer = new StringBuffer();
for(String item:name){
stringBuffer.append(item).append(" ");
}
return "name:"+stringBuffer.toString();
}
返回头部
List
List的自定义包装类:
public class UserList {
private List<User> users;
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
this.users = users;
}
}
@RequestMapping("/listType")
@ResponseBody
public String listType(UserList userList){
StringBuffer stringBuffer = new StringBuffer();
for(User user:userList.getUsers()){
stringBuffer.append(user).append(" ");
}
return "用户:"+stringBuffer.toString();
}
创建addList.jsp,同时添加3个用户信息,input的name指向自定义包装类UserList的users属性,及联到name和age,同时以下标区分集合中不同的对象。
<form action="/data/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"/>
<input type="submit" value="提交"/>
</form>
@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>
返回头部
Map
List的自定义包装类:
public class UserMap {
private Map<String,User> users;
public Map<String, User> getUsers() {
return users;
}
public void setUsers(Map<String, User> users) {
this.users = users;
}
}
业务方法:
@RequestMapping("/mapType")
@ResponseBody
public String mapType(UserMap userMap){
StringBuffer stringBuffer = new StringBuffer();
for (String key:userMap.getUsers().keySet()){
User user = userMap.getUsers().get(key);
stringBuffer.append(user).append(" ");
}
return "用户:"+stringBuffer.toString();
}
addMap.jsp
<form action="/data/mapType" method="post">
用户1ID:<input type="text" name="users['a'].id"/><br/>
用户1姓名:<input type="text" name="users['a'].name"/><br/>
用户2ID:<input type="text" name="users['b'].id"/><br/>
用户2姓名:<input type="text" name="users['b'].name"/><br/>
用户3ID:<input type="text" name="users['c'].id"/><br/>
用户3姓名:<input type="text" name="users['c'].name"/><br/>
<input type="submit" value="提交"/>
</form>
返回头部
Set
需要封装自定义包装类,将Set集合作为属性,不同的是,使用Set集合,需要在包装类构造函数中,为Set集合添加初始化对象。
public class UserSet {
private Set<User> userSet = new HashSet<>();
public UserSet(){
userSet.add(new User());
userSet.add(new User());
userSet.add(new User());
}
}
业务方法:
@RequestMapping("/setType")
@ResponseBody
public String setType(UserSet userSet){
StringBuffer stringBuffer = new StringBuffer();
for (User user:userSet.getUserSet()){
stringBuffer.append(user).append(" ");
}
return "用户:"+stringBuffer.toString();
}
addSet.jsp
<form action="/data/setType" 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>
JSON
JSP:Ajax请求后台业务方法,并将json格式的参数传给后台。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<script src="js/jQuery-1.8.3.js"></script>
<script type="text/javascript">
$(function () {
var user = {
"id":1,
"name": "张阿三",
};
$.ajax({
url:"data/json",
data:JSON.stringify(user),
type:"POST",
contentType:"application/json;charset=UTF-8",
dataType:"text",
success:function (data){
alert(data)
}
});
})
</script>
</head>
<body>
</body>
</html>
Spring MVC会拦截静态资源的请求,需要在web.xml中进行配置。
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.js</url-pattern>
</servlet-mapping>
业务方法:
@RequestMapping("/json")
@ResponseBody
public String json(@RequestBody User user){
System.out.println(user);
return user.toString();
}
@RequestBody:读取HTTP请求参数,通过Spring MVC提供的HttpMessageConverter接口将读取的参数转为json,xml格式的数据,绑定到业务方法的形参中。
@ResponseBody:将业务方法返回的对象,通过HttpMessageConverter接口转为指定格式的数据,json、xml等,响应给客户端。
fastjson来完成转换工作,fastjson的优势在于如果属性为空就不会将其转化为json,数据会简洁很多。
如何使用fastjson
- pom.xml中引入fastjson的依赖。
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.18</version>
</dependency>
- springmvc.xml中配置fastjson。
<mvc:annotation-driven>
<!-- 消息转换 -->
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes" value="text/html;charset=UTF-8"></property>
</bean>
<!-- fastjson -->
<bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter4"></bean>
</mvc:message-converters>
</mvc:annotation-driven>
返回最顶层
SpringMVC 视图解析
业务数据的绑定是指将业务数据绑定给 JSP 域对象,并且在客户端进行展示。pageContext、request、session、application
业务数据的绑定是由 ViewResolver 完成。
Spring MVC 提供了以下几种方式绑定业务数据:
- Map
- Model
- ModelAndView
- @SessionAttribute
- @ModelAttribute
返回最顶层
业务数据绑定到Request域对象
Map
- Spring MVC 在内部使⽤ Model 接⼝存储业务数据,在调⽤业务⽅法之前会创建⼀个隐含对象作为业务数据的存储容器。
- 设置业务⽅法的⼊参为 Map 类型,Spring MVC 会将隐含对象的引⽤传递给⼊参。
- 开发者可以对模型中的所有数据进⾏管理,包括访问和添加、修改、删除。
- 开发者只需要在业务⽅法处添加 Map 类型的⼊参,⽅法体中便可以通过对⼊参的操作来完成业务数据的添加。
@Controller
@RequestMapping("/view")
public class ViewHandler {
@RequestMapping("/map")
public String mapTest(Map<String, User> userMap){
User user = new User(1,"张三","23",new Address(1,"科技类"));
userMap.put("user",user);
return "show";
}
}
Model
与 Map 类似,业务方法通过入参来完成业务数据的绑定。
@RequestMapping("/model")
public String modelTest(Model model){
User user = new User(1,"李四","23",new Address(1,"科技类"));
model.addAttribute("user",user);
return "show";
}
Request
@RequestMapping("/request")
public String request(HttpServletRequest request){
User user = new User(1,"王五","23",new Address(1,"科技类"));
request.setAttribute("user",user);
return "show";
}
ModelAndView
与 Map、Model 不同的是,ModelAndView 不但包含了业务数据,同时也包含了视图信息,将视图和业务数据进行了整合,封装成一个对象,如果使用 ModelAndView 来处理业务数据,业务方法的返回值必须是 ModelAndView 对象。
业务方法中对 ModelAndView 进行两个操作:
- 填充业务数据
- 绑定视图信息
@RequestMapping("modelAndView")
public ModelAndView modelAndView(){
User user = new User(1,"赵六","23",new Address(1,"科技类"));
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("user",user);
modelAndView.setViewName("show");
return modelAndView;
}
@RequestMapping("modelAndView2")
public ModelAndView modelAndView2(){
User user = new User(1,"赵六","23",new Address(1,"科技类"));
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("user",user);
InternalResourceView view = new InternalResourceView("/show.jsp");
modelAndView.setView(view);
return modelAndView;
}
@RequestMapping("modelAndView3")
public ModelAndView modelAndView3(){
User user = new User(1,"威威","23",new Address(1,"科技类"));
ModelAndView modelAndView = new ModelAndView("show");
modelAndView.addObject("user",user);
return modelAndView;
}
@RequestMapping("modelAndView4")
public ModelAndView modelAndView4(){
InternalResourceView view = new InternalResourceView("/show.jsp");
ModelAndView modelAndView = new ModelAndView(view);
User user = new User(1,"宝宝","23",new Address(1,"科技类"));
modelAndView.addObject("user",user);
return modelAndView;
}
@RequestMapping("modelAndView5")
public ModelAndView modelAndView5(){
User user = new User(1,"靓靓","23",new Address(1,"科技类"));
Map<String,User> map = new HashMap<String,User>();
map.put("user",user);
ModelAndView modelAndView = new ModelAndView("show",map);
return modelAndView;
}
@RequestMapping("modelAndView6")
public ModelAndView modelAndView6(){
User user = new User(1,"侃侃","23",new Address(1,"科技类"));
Map<String,User> map = new HashMap<String,User>();
map.put("user",user);
InternalResourceView view = new InternalResourceView("/show.jsp");
ModelAndView modelAndView = new ModelAndView(view,map);
return modelAndView;
}
@RequestMapping("modelAndView7")
public ModelAndView modelAndView7(){
User user = new User(1,"阿萨","23",new Address(1,"科技类"));
ModelAndView modelAndView = new ModelAndView("show","user",user);
return modelAndView;
}
ModelAttribute
- 定义一个方法,该方法用来返回要填充到业务数据中的对象。
- 给该方法添加 @ModelAttribute 注解,该方法不是业务方法。
@RequestMapping("/modelAttribute")
public String modelAttribute(){
return "show";
}
// @ModelAttribute
// public User getUser(){
// User user = new User(1,"娥娥","23",new Address(1,"科技类"));
// return user;
// }
// @ModelAttribute
// public void getUser(Model model){
// User user = new User(1,"憨憨","23",new Address(1,"科技类"));
// model.addAttribute(user);
// }
@ModelAttribute
public void getUser(Map<String,User> map){
User user = new User(1,"淡淡","23",new Address(1,"科技类"));
map.put("user",user);
}
业务数据绑定到Session域对象
@RequestMapping("/session")
public String session(HttpServletRequest request){
User user = new User(1,"小明","23",new Address(1,"科技类"));
request.getSession().setAttribute("user",user);
return "test";
}
@RequestMapping("/session2")
public String session2(HttpSession httpSession) {
User user = new User(1, "校长", "23", new Address(1, "科技类"));
httpSession.setAttribute("user", user);
return "test";
}
sessionAttribute
在类定义处添加 @SessionAttributes 注解,只要业务方法中向域对象中存入了模型数据,则 Spring MVC 会自动把它同步到 session 中。
@Controller
@RequestMapping("/view")
@SessionAttributes(value = "user")
public class ViewHandler {
@RequestMapping("/mavtest")
public ModelAndView mavtest(){
User user = new User(1, "依依", "23", new Address(1, "科技类"));
ModelAndView modelAndView = new ModelAndView("test");
modelAndView.addObject(user);
return modelAndView;
}
}
返回最顶层
Spring MVC 自定义数据类型转换器
spring MVC
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="com.chenny.convert.DateConverter">
<constructor-arg type="java.lang.String" value="yyyy-MM-dd"></constructor-arg>
</bean>
<bean class="com.chenny.convert.StudentConvert"></bean>
</list>
</property>
</bean>
<mvc:annotation-driven conversion-service="conversionService"/>
StudentConvert
package com.chenny.convert;
import com.chenny.entity.Student;
import org.springframework.core.convert.converter.Converter;
public class StudentConvert 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(args[2]);
return student;
}
}
ConvertHandler
package com.chenny.controller;
import com.chenny.entity.Student;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Date;
@Controller
@RequestMapping("/convert")
public class ConvertHandler {
@RequestMapping("/test")
public String test(Date date){
System.out.println(date);
return "index";
}
@RequestMapping("/student")
@ResponseBody
public String student(Student student){
return student.toString();
}
}
返回最顶层
Spring MVC 集成RESTful架构
REST:Representational State Transfer 资源表现层状态转换
-
Resources:资源
-
Representation:资源表现层
-
State Transfer:状态转换
RESTful 有以下两个特点:
-
URL 传参更加简洁
传统的 URL:http://localhost/8080/test?id=1
RESTful:http://localhost/8080/test/1
-
完成不同终端之间的资源共享,RESTful 提供了一套规范,不同终端之间只需要遵守该规范,就可以实现数据交互。
RESTful 具体来讲就是 4 种表现形式,HTTP 协议中的四种请求类型(GET、POST、PUT、DELETE)分别对应四种常规操作,CRUD。
- GET 用来获取资源
- POST 用来创建资源
- PUT 用来修改资源
- DELETE 删除资源
返回最顶层
Spring MVC模型数据解析
Spring MVC提供了以下几种方法添加模型数据:
- Map
- Model
- ModelAndView
- @SessionAttributes
- @ModelAttribute
模型数据绑定到request对象中
- Map,开发者只需要在业务方法中定义Map形参,方法体中对该形参进行操作,Spring MVC框架会自动取出该形参中的数据并存入request对象,可以在JSP通过EL表达式直接获取对象。
@RequestMapping("/map")
public String map(Map<String, Course> map){
Course course = new Course(1,"Java基础",2000);
map.put("c1",course);
return "test";
}
- Model,Model的使用与Map类似。
@RequestMapping("/model")
public String model(Model model) {
Course course = new Course(1,"Java基础",2000);
model.addAttribute("c1",course);
return "test";
}
- ModelAndView
与Map、Model不同的是,ModelAndView不但包含模型数据,同时也包含了视图信息,所以使用ModelAndView来处理模型数据,业务方法的返回值必须是ModelAndView,业务方法中对ModelAndView进行两个操作:1、填充模型数据。2、绑定视图信息。
@RequestMapping("/mav1")
public ModelAndView modelAndView1(){
ModelAndView modelAndView = new ModelAndView();
Course course = new Course(1,"Java基础",2000);
modelAndView.addObject("c1",course);
modelAndView.setViewName("test");
return modelAndView;
}
@RequestMapping("/mav2")
public ModelAndView modelAndView2(){
ModelAndView modelAndView = new ModelAndView();
Course course = new Course(1,"Java基础",2000);
modelAndView.addObject("c1",course);
View view = new InternalResourceView("/test.jsp");
modelAndView.setView(view);
return modelAndView;
}
@RequestMapping("/mav3")
public ModelAndView modelAndView3(){
ModelAndView modelAndView = new ModelAndView("test");
Course course = new Course(1,"Java高级",2000);
modelAndView.addObject("c1",course);
return modelAndView;
}
@RequestMapping("/mav4")
public ModelAndView modelAndView4(){
View view = new InternalResourceView("/test.jsp");
ModelAndView modelAndView = new ModelAndView(view);
Course course = new Course(1,"Java高级",2000);
modelAndView.addObject("c1",course);
return modelAndView;
}
@RequestMapping("/mav5")
public ModelAndView modelAndView5(){
Map<String,Course> map = new HashMap<>();
Course course = new Course(3,"Spring MVC框架",3000);
map.put("c1",course);
ModelAndView modelAndView = new ModelAndView("test",map);
return modelAndView;
}
@RequestMapping("/mav6")
public ModelAndView modelAndView6(){
Map<String,Course> map = new HashMap<>();
Course course = new Course(3,"Spring MVC框架",3000);
map.put("c1",course);
View view = new InternalResourceView("/test.jsp");
ModelAndView modelAndView = new ModelAndView(view,map);
return modelAndView;
}
@RequestMapping("/mav7")
public ModelAndView modelAndView7(){
Course course = new Course(1,"Java基础",2000);
ModelAndView modelAndView = new ModelAndView("test","c1",course);
return modelAndView;
}
@RequestMapping("/mav8")
public ModelAndView modelAndView8(){
Course course = new Course(2,"Spring框架",3000);
View view = new InternalResourceView("/test.jsp");
ModelAndView modelAndView = new ModelAndView(view,"c1",course);
return modelAndView;
}
- HttpServletRequest、HttpSession
@RequestMapping("/request")
public String request(HttpServletRequest request){
Course course = new Course(1,"Java基础",2000);
request.setAttribute("c1",course);
HttpSession session = request.getSession();
session.setAttribute("c1",course);
return "test";
}
@RequestMapping("/session")
public String session(HttpSession session){
System.out.println(session);
session.setAttribute("c1",new Course(1,"Java",2000));
return "test";
}
HiddenHttpMethodFilter
实现原理:检测请求参数中是否包含 _method 参数,如果包含则获取该参数的值,判断是哪种操作后完成请求类型的转换,然后继续传递。
1、在 form 表单中添加隐藏域标签,name="_method",value=“PUT”/“DELETE”。
<form action="/rest/put" method="post">
<input type="hidden" name="_method" value="PUT"/>
<input type="submit"/>
</form>
<form action="/rest/delete" method="post">
<input type="hidden" name="_method" value="DELETE"/>
<input type="submit"/>
</form>
2、web.xml 配置 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>
3、RestHandler
package com.southwind.controller;
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.ResponseBody;
@Controller
@RequestMapping("/rest")
public class RestHandler {
@RequestMapping(value = "/put",method = RequestMethod.PUT)
@ResponseBody
public String rest(){
System.out.println("rest");
return "PUT";
}
@RequestMapping(value = "/delete",method = RequestMethod.DELETE)
@ResponseBody
public String delete(){
System.out.println("delete");
return "DELETE";
}
}
返回最顶层
需求
- 添加课程,成功则返回全部课程信息。
- 查询课程,通过 id 查询对应的课程信息。
- 修改课程,成功则返回修改之后的全部课程信息。
- 删除课程,成功则返回删除之后的全部课程信息。
1、创建实体类
package com.southwind.entity;
public class Course {
private Integer id;
private String name;
private Double price;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public Course(Integer id, String name, Double price) {
this.id = id;
this.name = name;
this.price = price;
}
}
2、CourseRepository
package com.southwind.repository;
import com.southwind.entity.Course;
import org.springframework.stereotype.Repository;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
@Repository
public class CourseRepository {
private static Map<Integer, Course> map;
static {
map = new HashMap();
map.put(1,new Course(1,"Java",6000d));
map.put(2,new Course(2,"C++",6000d));
map.put(3,new Course(3,"Python",6000d));
}
public void saveOrUpdate(Course course){
map.put(course.getId(),course);
}
public Collection<Course> findAll(){
return map.values();
}
public Course findById(Integer id){
return map.get(id);
}
public void deleteById(Integer id){
map.remove(id);
}
}
3、CourseHandler
package com.southwind.controller;
import com.southwind.entity.Course;
import com.southwind.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 CourseHandler {
@Autowired
private CourseRepository courseRepository;
// @RequestMapping(value = "/findAll",method = RequestMethod.GET)
@GetMapping("/findAll")
public ModelAndView findAll(){
ModelAndView modelAndView = new ModelAndView("course");
modelAndView.addObject("list",courseRepository.findAll());
return modelAndView;
}
@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("update");
modelAndView.addObject("course",courseRepository.findById(id));
return modelAndView;
}
@PutMapping("/update")
public String update(Course course){
courseRepository.saveOrUpdate(course);
return "redirect:/course/findAll";
}
@PostMapping("/add")
public String add(Course course){
courseRepository.saveOrUpdate(course);
return "redirect:/course/findAll";
}
}
返回最顶层
Spring MVC 的文件上传下载
- 单文件上传
pom.xml
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.7</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
JSP
- input 的 type 设置为 file
- form 表单的 method 设置为 post
- form 表单的 enctype 设置为 multipart/form-data
<%--
Created by IntelliJ IDEA.
User: 73981
Date: 2020/9/13
Time: 13:39
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@page isELIgnored="false" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/unload" method="post" enctype="multipart/form-data">
<input type="file" name="img"/>
<input type="submit" value="上传"/>
</form>
<br>
<c:if test="${filepath !=null}">
<h1>上传的图片</h1>
<img width="300px" src="${filepath}" alt="">
</c:if>
</body>
</html>
返回最顶层
Spring MVC 表单标签库
1、在 JSP 页面中导入 Spring MVC 标签库,与导入 JSTL 标签库的语法非常相似,前缀 prefix 可以自定义,通常为 from。
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
2、将 form 表单与业务数据进行绑定,通过 modelAttribute 属性完成绑定,将 modelAttribute 的值设置为控制器向 ModelAndView 对象存值时的 key 即可。
package com.chenny.controller;
import com.chenny.entity.Person;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
@RequestMapping("/person")
public class PersonHandler {
@GetMapping("/get")
public ModelAndView get(){
ModelAndView modelAndView = new ModelAndView();
Person person = new Person();
person.setId(1);
person.setName("张三");
person.setAge(22);
person.setGender("男");
modelAndView.addObject("person",person);
modelAndView.setViewName("person");
return modelAndView;
}
}
<form:form modelAttribute="person">
用户编号:<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:form>
3、form 表单与业务数据完成绑定后,接下来就是将业务数据中的值取出绑定到不同的标签中,通过设置标签的 path 属性完成,将 path 属性的值设置为业务数据对应的属性名即可。
- from 标签
<form:form modelAttribute="person" method="post"></form:form>
渲染的是 HTML 中的 ,通过 modelAttribute 属性绑定具体的业务数据。
- input 标签
<form:input path="name"/>
渲染的是 HTML 中的 ,form 标签绑定的是业务数据,input 标签绑定的是业务数据中的属性值,通过 path 与业务数据的属性名对应,并支持级联属性。
- password 标签
<form:password path="password"/>
渲染的是 HTML 中的 ,通过 path 属性与业务数据的属性名对应,password 标签的值不会在页面显示。
- checkbox 标签
<form:checkbox path="hobby" value="读书"/>读书
渲染的是 HTML 中的 ,通过 path 与业务数据的属性名对应,可以绑定 boolean、数组和集合。
如果绑定 boolean 类型的变量,该变量的值为 true,则表示选中,false 表示不选中。
如果绑定数组或者集合类型,数组/集合中的元素等于 checkbox 的 value 值,则该项选中,否则不选中。
用户爱好:<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>旅行
<hr/>
用户爱好:<form:checkbox path="hobby2" value="读书"></form:checkbox>读书
<form:checkbox path="hobby2" value="看电影"></form:checkbox>看电影
<form:checkbox path="hobby2" value="打游戏"></form:checkbox>打游戏
<form:checkbox path="hobby2" value="听音乐"></form:checkbox>听音乐
<form:checkbox path="hobby2" value="旅行"></form:checkbox>旅行
- checkboxes 标签
<form:checkboxes items="${person.hobby}" path="selectHobby" />
渲染的是 HTML 中的一组 ,这里需要结合 items 和 path 两个属性来使用,items 绑定被遍历的集合或数组,path 绑定被选中的集合或数组,可以这样理解,items 为全部选型,path 为默认选中的选型。
用户爱好:<form:checkboxes path="selectHobbys" items="${person.hobbys}"></form:checkboxes>
<hr/>
用户爱好:<form:checkboxes path="selectHobbys2" items="${person.hobbys2}"></form:checkboxes>
- radiobutton 标签
<form:radiobutton path="radioId" value="0"/>
渲染的是 HTML 只的一个 ,绑定的数据与标签的 value 值相等为选中状态,否则为不选中状态。
radio:<form:radiobutton path="radioId" value="0"></form:radiobutton>0
<form:radiobutton path="radioId" value="1"></form:radiobutton>1
- radiobuttons 标签
<form:radiobuttons items="${person.grade}" path="selectGrade">
渲染的是 HTML 中的一组 ,这里需要结合 items 和 path 两个属性来使用,items 绑定被遍历的集合或数组,path 绑定被选中的值,可以这样理解,items 为全部选型,path 为默认选中的选型,用法与 form:checkboxes 一致。
- select 标签
<form:select items="${person.citys}" path="selectCity">
渲染的是 HTML 中的一个 ,这里需要结合 items 和 path 两个属性来使用,items 绑定被遍历的集合或数组,path 绑定被选中的值,用法与 form:radiobuttons/ 一致。
- options 标签
form:select 结合 form:options 使用,form:select 只定义 path 属性,在 form:select 标签内部添加一个子标签 form:options,设置 items 属性,获取被遍历的集合。
- option 标签
from:select 结合 form:option 使用,form:select 定义 path 属性,给每一个 form:options 设置 values 属性,path 与哪个 value 相等,该项默认选中。
- textarea 标签
渲染的是 HTML 中的一个 ,path 绑定业务数据的属性值,作为文本输入域的默认值。
- errors 标签
该标签的使用需要结合 Spring MVC 的 Validator 验证器来使用,将验证结果的 error 信息渲染到 JSP 页面中。
1、创建验证器,实现 Validator 接口。
package com.chenny.validator;
import com.chenny.entity.Student;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
public class StudentValidator implements Validator {
@Override
public boolean supports(Class<?> aClass) {
return Student.class.equals(aClass);
}
@Override
public void validate(Object o, Errors errors) {
ValidationUtils.rejectIfEmpty(errors,"name",null,"姓名不能为空");
ValidationUtils.rejectIfEmpty(errors,"age",null,"年龄不能为空");
}
}
2、springmvc.xml 中添加 Validator 配置。
<bean id="studentValidator" class="com.chenny.validator.StudentValidator"></bean>
<mvc:annotation-driven validator="studentValidator"></mvc:annotation-driven>
3、创建业务方法,第一个 login 方法用来生成业务数据,跳转到 login.jsp,第二个 login 方法用来做验证。
@GetMapping("/login")
public ModelAndView login(){
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("student",new Student());
modelAndView.setViewName("login");
return modelAndView;
}
@PostMapping("/login")
public String reg(@Validated Student student, BindingResult bindingResult){
if(bindingResult.hasErrors()){
return "login";
}
return "index";
}
4、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>
<form:form action="/person/login" method="post" modelAttribute="student">
<form:input path="name"></form:input><form:errors path="name" /><br/>
<form:input path="age"></form:input><form:errors path="age"/><br/>
<input type="submit"/>
</form:form>
</body>
</html>