深入学习SpringMVC
1.什么是SpringMVC?
SpringMVC是Spring框架内置的MVC的实现。SpringMVC就是一个Spring内置的MVC框架。
MVC框架,它解决WEB开发中常见的问题(参数接收、文件上传、表单验证、国际化等等),而且使用简单,与Spring无缝集成。 支持 RESTful风格的 URL 请求 。
采用了松散耦合可插拔组件结构,比其他 MVC 框架更具扩展性和灵活性。
2.SpringMVC底层实现
在没有使用SpringMVC之前我们都是使用的Servlet在做Web开发。但是使用Servlet开发在接受请求数据参数,数据共享,页面跳转等操作相对比较复杂。
SpringMVC底层就是的Servlet,SpringMVC就是对Servlet进行更深层次的封装。
3.SpringMVC入门示例
1.导入jar包
2.编写Controller控制器(与以前servlet类似)
创建一个类实现Controller即可
public class HelloController implements Controller { @Override public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { ModelAndView mv = new ModelAndView(); //ModelAndView对象封装了Model数据和View信息 mv.addObject("username", "张三");// 共享数据 mv.setViewName("/WEB-INF/hello.jsp");// 设置跳转页面 return mv; } }
3.在springmvc.xml配置 Controller
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd "> <!--配置springMVC控制器 name : 给当前控制器取的一个名字,相当于Servlet中的资源名称,以便浏览器访问,必须以斜杠/开头, 建议使用 name属性,不要使用id,因为早期版本 id 不支持特殊字符 如 /斜杠 --> <bean name="/hello" class="com.gjs.controller.HelloController"/> </beans>
4.在web.xml中配置前端控制器关联springmvc.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> <display-name>springMVC1-入门</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <!-- 配置springmvc框架,web.xml是项目入口,访问项目最先进入 web.xml --> <!-- 配置springmvc的前端控制器(总控) 配置前端控制器以后,用户浏览器的所有请求全部走SpringMVC,如果不配(默认走servlet) springmvc底层是基于servlet --> <servlet> <servlet-name>MVC</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> <!-- 是否在启动时加载控制器 1:是,在服务器启动以后立即创建对象 -1:否(默认),用户第一次访问时候才创建--> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>MVC</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
5.配置到Tomcat上并启动
6.结果
4.SpringMVC的全注解开发(一般都用注解不会用xml方式)
4.1 SpringMVC中的常用注解
4.2 SpringMVC使用注解步骤
1.导入相关jar包
2.在springmvc.xml中配置注解扫描及MVC注解支持
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd "> <!-- 配置要进行注解包扫描的位置 --> <context:component-scan base-package="com.gjs"/> <!-- 开启MVC注解支持, 同时还支持返回json数据--> <mvc:annotation-driven/> </beans>
3.在web.xml中配置前端控制器
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> <display-name>springMVC1-入门</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <!-- 配置springmvc框架,web.xml是项目入口,访问项目最先进入 web.xml --> <!-- 配置springmvc的前端控制器(总控) 配置前端控制器以后,用户浏览器的所有请求全部走SpringMVC,如果不配(默认走servlet) springmvc底层是基于servlet --> <servlet> <servlet-name>MVC</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> <!-- 是否启动时加载,1:是,-1:否--> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>MVC</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
4.Controller控制器
package com.gjs.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; @Controller // 声明当前类为控制器 public class HelloController { @RequestMapping("hello") public ModelAndView hello() { ModelAndView mv = new ModelAndView();// ModelAndView对象封装了Model数据和View信息 mv.addObject("username", "李四");// 共享数据 mv.setViewName("/WEB-INF/hello.jsp");// 设置跳转页面 return mv; } }
5.SpringMVC执行流程和原理
5.1SpringMVC流程:
01、用户发送出请求到前端控制器DispatcherServlet。
02、DispatcherServlet收到请求调用HandlerMapping(处理器映射器)。
03、HandlerMapping找到具体的处理器(可查找xml配置或注解配置),生成处理器对象及处理器拦截器(如果有),再一起返回给DispatcherServlet。
04、DispatcherServlet调用HandlerAdapter(处理器适配器)。
05、HandlerAdapter经过适配调用具体的处理器(Handler/Controller)。
06、Controller执行完成返回ModelAndView对象。
07、HandlerAdapter将Controller执行结果ModelAndView返回给DispatcherServlet。
08、DispatcherServlet将ModelAndView传给ViewReslover(视图解析器)。
09、ViewReslover解析后返回具体View(视图)。
10、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。
11、DispatcherServlet响应用户。
5.2 涉及组件分析:
1、前端控制器DispatcherServlet(不需要程序员开发),由框架提供,在web.xml中配置。
作用:接收请求,响应结果,相当于转发器,中央处理器。
2、处理器映射器HandlerMapping(不需要程序员开发),由框架提供。
作用:根据请求的url查找Handler(处理器/Controller),可以通过XML和注解方式来映射。
3、处理器适配器HandlerAdapter(不需要程序员开发),由框架提供。
作用:按照特定规则(HandlerAdapter要求的规则)去执行Handler。
4、处理器Handler(也称之为Controller,需要工程师开发)
注意:编写Handler时按照HandlerAdapter的要求去做,这样适配器才可以去正确执行Handler。
作用:接受用户请求信息,调用业务方法处理请求,也称之为后端控制器。
5、视图解析器ViewResolver(不需要程序员开发),由框架提供
作用:进行视图解析,把逻辑视图名解析成真正的物理视图。
SpringMVC框架支持多种View视图技术,包括:jstlView、freemarkerView、pdfView等。
6、视图View(需要工程师开发)
作用:把数据展现给用户的页面
View是一个接口,实现类支持不同的View技术(jsp、freemarker、pdf等)
具体组件的配置相关,请查阅 spring-webmvc-4.3.2.RELEASE.jar 包下面 org/springframework/web/servlet/DispatcherServlet.properties 的相关配置
6.对静态资源访问
按照第3和第4点的配置,会出现静态资源无法访问的情况(如html页面)。原因是在web.xml中配置的前端控制器的映射路径(<url-pattern>)为“/”,而Tomcat中对静态资源处理的servlet的的映射路径也是“/”。也就是说,我们配置SpringMVC中的DispatcherServlet的映射路径覆盖了Tomcat默认对静态资源的处理的路径。
Tomcat部分源码:
<servlet> <servlet-name>default</servlet-name> <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class> <init-param> <param-name>debug</param-name> <param-value>0</param-value> </init-param> <init-param> <param-name>listings</param-name> <param-value>false</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
解决方案:
方案一:如果SpringMVC要配置为/,那么就得设置Dispatcherservlet对静态资源进行支持。
在SpringMVC的配置文件中添加以下代码开启对静态资源的访问
<mvc:default-servlet-handler/>
方案二:SpringMVC映射路径不要配置为/ (也不要配置为/* ,/*会匹配所有url)
实际开发中一般推荐使用 *.后缀 如 *.do *.action
<servlet-mapping>
<servlet-name>MVC</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
注:访问时以.do结尾的url访问,配置方法的映射路径时可以不加.do(建议不加)
7.Spring请求响应
7.1.@RequestMapping
@RequestMapping注解主要用于设置SpringMVC请求的映射路径
所谓的映射路径,就是匹配请求路径和执行方法关系的路径.
请求路径:http://localhost:8080/springmvc/method1.do
映射路径:@RequestMapping(value="/method1") (“value=”可以省略)
@RequestMapping 用于贴在控制器的类上或者方法上面
如果是贴在控制器的类上面,那么在访问这个类的方法之前必须先加上类上的对应的名称类似于 项目下面的 模块名称
如果贴在方法上面,就是访问此方法的资源名称
@Controller @RequestMapping("/request") //访问时候必须加上,类似模块名称 public class RequestController { @RequestMapping(value="/method1") //资源名称 public void method1() { } }
访问地址 : http://localhost:8080/springmvc/request/method1.do
7.2两种限制
SpringMVC支持对请求的限制.如果不满足限制的条件,就不让访问执行方法。这样做,大大提高了执行方法的安全性。
主要的限制有两种:方法限制(method),参数限制
1.方法限制:
设置请求的method类型(get/post)。如果发送过来的请求与方法设置的method不一样,就不能访问执行方法。
/* * @RequestMapping 请求映射注解 * value : 请求的url地址映射,没有其他参数时“value=”可以省略,有其他参数就不能省略 * method :限定请求方式 GET /POST 默认没有限制get/post都可以 * params : 请求参数的限制: 必须有什么参数,必须没有什么参数,参数的值必须是什么 */ @RequestMapping(value="/login1",method=RequestMethod.POST) public ModelAndView login(HttpServletRequest request,HttpServletResponse reponse,HttpSession sesion ) { String username = request.getParameter("username"); String password = request.getParameter("password"); System.out.println(username); System.out.println(password); return null; }
<%-- EL表达式获取上下文路径 : ${pageContext.request.contextPath} --%> <h4>登录页面</h4> <form action="${pageContext.request.contextPath}/request/login1.do" method="get"> 账号:<input name="username"><br> 密码:<input type="password" name="pwd"><br> <button type="submit">登录</button> </form>
不支持请求方法“GET”
2.参数限制
限制请求里面必须包括哪些参数,或不包括哪些哪些,参数必须包括哪些值,不包括哪些值
限制参数格式:
1.参数必须包括:params={"username","password"}
2.参数不能包括:params={"!userid"}
3参数值必须是指定的值:params={"username=zhangsan"})
4.参数值必须不是指定的值:params={"userid!=123"})
/* * @RequestMapping * 请求映射注解 * value : 请求的url地址映射,没有其他参数时“value=”可以省略,有其他参数就不能省略 * method :限定请求方式 GET /POST 默认没有限制get/post都可以 * params : 请求参数的限制: 必须有什么参数,必须没有什么参数,参数的值必须是什么 */ @RequestMapping(value="/login2",params={"username","password"}) public ModelAndView login(HttpServletRequest request,HttpServletResponse reponse,HttpSession sesion ) { String username = request.getParameter("username"); String password = request.getParameter("password"); System.out.println(username); System.out.println(password); return null; }
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>登录</title> </head> <body> <%-- EL表达式获取上下文路径 : ${pageContext.request.contextPath} --%> <h4>登录页面</h4> <form action="${pageContext.request.contextPath}/request/login2.do" method="post"> 账号:<input name="username"><br> 密码:<input type="password" name="pwd"><br> <button type="submit">登录</button> </form> </body> </html>
参数条件“username, password”不满足,实际请求参数:username={admin}, pwd={123}
7.3SpringMVC方法参数注入
SpringMVC的方法默认可以注入 JavaWeb开发常用的数据共享对象,如:HttpServletRequest 、HttpServletResponse、HttpSession。获取这些共享对象以后,就可以向之前的Servlet一样,做任何数据共享以及页面跳转操作
8.数据绑定
8.1.数据绑定是什么
SpringMVC的数据绑定就是将请求带过来的表单数据绑定到执行方法的参数变量。
实际开发中,SpringMVC作为表现层框架,肯定会接受前台页面传递过来的参数,SpringMVC提供了丰富的接受参数的方法
8.2 接受参数的方法
1. 使用HttpServletRequest对象(C)
SpringMVC可以注入HttpServletRequest对象,直接使用getParameter()接受参数,但一般不会这种方法,还用这种方法接收参数的话使用SpringMVC的意义就不大,这种方法了解即可。
<!-- 原始方式request.getParameter() --> <fieldset> <legend> 原始方式request.getParameter()</legend> <form action="${pageContext.request.contextPath}/request/method1.do" method="get"> 账号: <input name="username"><br> 年龄: <input name="age"><br> <button type="submit">提交</button> </form> </fieldset>
@RequestMapping("/method1") public ModelAndView method1(HttpServletRequest request) { String username = request.getParameter("username"); String age = request.getParameter("age"); System.out.println(username); System.out.println(age); return null; }
2. 方法形参与请求参数同名
在方法形参上,声明和表单字段名相同的参数名(可以进行自动同名匹配,然后注入)
<fieldset> <legend>方法形参与前台参数同名</legend> <form action="${pageContext.request.contextPath}/request/method2.do" method="post"> 账号: <input name="username"><br> 年龄: <input name="age"><br> <button type="submit">提交</button> </form> </fieldset>
@RequestMapping("/method2") public ModelAndView method2(String username, Integer age) { System.out.println(username); System.out.println(age); return null; }
3.方法形参与请求参数不同名
方法形参与表单字段名参数名不同是,要使用 @RequestParam注解 绑定请求参数到方法参数
<fieldset> <legend>方法形参与前台参数不同名</legend> <form action="${pageContext.request.contextPath}/request/method3.do" method="post"> 账号: <input name="name"><br> 年龄: <input name="age"><br> <button type="submit">提交</button> </form> </fieldset>
@RequestMapping("/method3") public ModelAndView method3(@RequestParam("name") String username, Integer age) { System.out.println(username); System.out.println(age); return null; }
4.接收数组
<fieldset> <legend>接收数组或集合</legend> <form action="${pageContext.request.contextPath}/request/method4.do" method="post"> 账号: <input name="username"><br> 年龄: <input name="age"><br> 爱好: <input type="checkbox" name="hobbys" value="java">java <input type="checkbox" name="hobbys" value="C">C <input type="checkbox" name="hobbys" value="C++">C++<br /> <button type="submit">提交</button> </form> </fieldset>
@RequestMapping("/method4") public ModelAndView method4(String username, Integer age, String[] hobbys) { System.out.println(username); System.out.println(age); System.out.println(Arrays.toString(hobbys)); return null; }
如果后台接收的属性名与前台不一致需要在数组前面加上@RequestParam注解
5.接收对象
在实际开发中经常需要把接收的参数封装到javaBaen对象中。springMVC提供了直接接收javaBaen对象的方式,直接把javaBaen对象作为方法的形参,从前台接收到的参数就会自动映射注入到对象中,但必须保证javaBaen对象的属性名与从前台接收到的参数名一致,否则就无法映射
package com.gjs.pojo; import java.util.Arrays; public class User { private String username; private String password; private String email; private String phone; private String[] hobby; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public String[] getHobby() { return hobby; } public void setHobby(String[] hobby) { this.hobby = hobby; } public User() { super(); } public User(String username, String password, String email, String phone, String[] hobby) { super(); this.username = username; this.password = password; this.email = email; this.phone = phone; this.hobby = hobby; } @Override public String toString() { return "User [username=" + username + ", password=" + password + ", email=" + email + ", phone=" + phone + ", hobby=" + Arrays.toString(hobby) + "]"; } }
<fieldset> <legend>接受对象,表单参数名必须和后台pojo对象对应的属性名相同</legend> <form action="${pageContext.request.contextPath}/request/method5.do" method="get"> 账号: <input name="username"><br> 密码: <input type="password" name="password"><br> 邮箱: <input name="email"><br> 电话: <input name="phone"><br> 爱好:<input type="checkbox" name="hobby" value="java">java <input type="checkbox" name="hobby" value="C">C <input type="checkbox" name="hobby" value="C++">C++<br /> <button type="submit">提交</button> </form> </fieldset>
//接受对象,直接在方法的参数上面注入pojo对象,pojo对象的属性和表单的参数名必须一样 @RequestMapping("/method5") public ModelAndView method5(User user) { System.out.println(user); return null; }
6.接受参数封装成Map集合
有的时候我们需要接收多个参数,但又不想使用对象接收,这时可以用Map集合接收。只需要把map集合作为方法参数注入然后在map参数前面加上@RequestParam 注解即可, SpringMVC在接受表单参数时候回自动创建一个map集合, 并且把表单的参数名作为map的key,参数值作为map的value。使用map集合可以接受任意个数的参数,但需要注意map只能接受单个值的参数,接收数组类型的参数只会接收第一个元素
<fieldset> <legend>接受参数封装成Map集合</legend> <form action="${pageContext.request.contextPath}/request/method6.do" method="post"> 账号: <input name="username"><br> 密码: <input name="password"><br> 邮箱: <input name="email"><br> 电话: <input name="phone"><br> 爱好:<input type="checkbox" name="hobby" value="java">java <input type="checkbox" name="hobby" value="C">C <input type="checkbox" name="hobby" value="C++">C++<br /> <button type="submit">提交</button> </form> </fieldset>
@RequestMapping("/method6") public ModelAndView method6(@RequestParam Map<String, Object> paramsMap) { System.out.println(paramsMap); return null; }
7.RESTFUL风格支持
RESTFUL介绍:
REST(英文:Representational State Transfer,简称REST)描述了一个架构样式的网络系统,比如 web 应用程序。它首次出现在 2000 年 Roy Fielding 的博士论文中,他是 HTTP 规范的主要编写者之一。在目前主流的三种Web服务交互方案中,REST相比于SOAP(Simple Object Access protocol,简单对象访问协议)以及XML-RPC更加简单明了,REST都倾向于用更加简单轻量的方法设计和实现。值得注意的是REST并没有一个明确的标准,而更像是一种设计的风格。
RESTful一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
参数传递方法 GET
例如:根据商品id查询对应的商品信息(京东网站)
如果按照我们web开发应该是将商品id通过get方法跟在地址后面
普通方式 https://item.jd.com?product_id=100000287117 京东不支持
但是京东不是使用的此种方式,使用的 RESTFUL风格
RESTful风格 : https://item.jd.com/100000287117.html
示例代码:
@PathVariable用于将请求URL中的模板变量(动态参数)映射到功能处理方法的参数上。
// RESTful风格 @RequestMapping(value = "/method7/{product_id}.html") public ModelAndView method7(@PathVariable("product_id") Integer product_id) { System.out.println(product_id);//1231323123 return null; }
访问地址:localhost:8080/springmvc/request/method7/1231323123.html
注:.html 的url会被Tomcat当做静态资源处理了,所以配置springmvc的前端控制器时映射路径要陪 / ,然后再配置开启对静态资源的访问 <mvc:default-servlet-handler/>
使用RESTful优势
1.可以让页面伪静态,页面访问感觉像在访问静态html页面,实际上访问时动态页面(伪静态)
2.方便搜索引擎的SEO优化(html页面在搜索引擎搜索结果比较靠前)
9.请求中文乱码问题
SpringMVC默认接受的参数是ISO-8859-1编码参数,单字节,不支持中文。Spring提供了一个过滤器 org.springframework.web.filter.CharacterEncodingFilter 可以让开发者自定义请求参数的字符编码。
在web.xml中配置过滤器
<filter> <filter-name>CharacterEncodingFilter</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>CharacterEncodingFilter</filter-name> <!-- 过滤所有请求 --> <url-pattern>/*</url-pattern> </filter-mapping>
如果是get方式还需要修改Tomcat的配置:修改tomcat/conf/server.xml,在<Connector> 标签中添加属性useBodyEncodingForURI="true"(Tomcat 8之后版本可不改,默认就是utf-8)
useBodyEncodingForURI="true":是否设置用request的字符集对URL提交的数据和表单中GET方式提交的数据进行重新编码
10.响应传值方式
10.1使用原始servlet的请求和响应对象进行页面跳转和数据共享
@RequestMapping("method1") public void method1(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //数据共享 request.setAttribute("username", "张三"); //请求转发 //request.getRequestDispatcher("/WEB-INF/response.jsp").forward(request, response); //url重定向(可以跨域访问) response.sendRedirect("http://www.baidu.com"); }
10.2返回ModelAndView类型进行页面跳转和数据共享
ModelAndView :模型和视图。Spring提供此对象可以集中管理共享数据操作和设置跳转视图操作。但 ModelAndView 只能使用请求转发。
@RequestMapping("method2") public ModelAndView method2() { ModelAndView mv = new ModelAndView(); mv.addObject("username", "李四"); //数据共享 mv.setViewName("/WEB-INF/response.jsp");//设置视图地址 return mv; }
10.3 通过Model方式-设置共享数据
直接将需要共享的数据封装到Model对象,方法返回值(String字符串)为需要跳转的地址。 默认使用请求转发
@RequestMapping("method3") public String method3(Model m) { m.addAttribute("username", "王五"); //数据共享 return "/WEB-INF/response.jsp"; //返回视图地址 }
10.4 配置视图解析器
视图解析器的配置
<!-- 配置SpringMVC的视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 配置视图前缀 -->
<property name="prefix" value="/WEB-INF/"/>
<!-- 配置视图后缀 -->
<property name="suffix" value=".jsp"/>
</bean>
配置视图解析器后的代码
Controller方法返回字符串表示逻辑视图名,通过视图解析器解析为物理视图地址。
此时默认的物理视图地址为:视图前缀+逻辑视图名称+视图后缀
@RequestMapping("method2") public ModelAndView method2() { ModelAndView mv = new ModelAndView(); mv.addObject("username", "李四"); //数据共享 //配置视图解析器之前 //mv.setViewName("/WEB-INF/response.jsp");//设置视图地址 //配置视图解析器之后:配置一个逻辑视图名称 mv.setViewName("response"); return mv; } @RequestMapping("method3") public String method3(Model m) { m.addAttribute("username", "王五"); //数据共享 //配置视图解析器之前 //return "/WEB-INF/response.jsp"; //返回视图地址 //配置视图解析器之后:返回一个逻辑视图名称 return "response"; }
10.5 自定义请求转发和重定向跳转的页面
如果直接使用视图解析器的配置开发,那么必须保证视图解析器前缀目录下面有对应的页面文件才能跳转,否则报错。
默认页面跳转也只能使用请求转发跳转,不能使用重定向 需要解决问题: 除了使用视图解析器对应规则的开发,用户还得自定义跳转方式,和自定义跳转页面 方案:
使用视图解析器的 请求转发和重定向配置,可以打破默认的规则
spring源码:
public static final String REDIRECT_URL_PREFIX = "redirect:"; public static final String FORWARD_URL_PREFIX = "forward:";
重定向:redirect:
请求转发:forward:
示例代码:
// 自定义请求转发页面跳转的地址 : forward: 跳转的地址 @RequestMapping("method4") public String method4(Model m) { m.addAttribute("username", "赵六"); return "forward:/WEB-INF/response.jsp"; } // 自定义重定向页面跳转的地址 redirect: 跳转的地址 @RequestMapping("method5") public String method5(Model m) { return "redirect:http://www.baidu.com"; }
10.6 返回对象进行页面跳转和数据共享
返回对象默认使用就是请求转发,跳转的页面规则 :视图解析器前缀 + 模块名+@RequestMapping的值 + 后缀。返回的对象即共享的数据,共享的名称默认为对象类型的首字母小写。可以使用@ModelAttribute("设置共享模型的属性名称")
@RequestMapping("method6") @ModelAttribute("userKey") //设置共享模型的属性名称 public User method6() { User user = new User("马七","123", "10000@qq.com", "1", null); return user; }
10.7 转换JSON数据
在web开发中,前台页面经常会发送ajax请求从后台请求数据,ajax请求给前台的数据一般都是json 数据。
SpringMVC支持自动将对象转换JSON格式的数据响应给客户端
SpringMVC默认使用的是 jackson 作为对象转json的工具
先导入jackson的jar包
下载地址:https://mvnrepository.com/search?q=jackson
使用@ResponseBody注解方法的返回值会以字符串的形式返回,springMVC会自己调用jackson 把对象转换成json字符串
@RequestMapping("/getObjectByJson") @ResponseBody //将方法的返回值以字符串的形式返回 public User getObjectByJson() { User user = new User(); user.setUsername("小明"); user.setPassword("123"); user.setPhone("135xxxx"); user.setEmail("xiaoming@qq.com"); return user; } @RequestMapping("/getListtByJson") @ResponseBody public List<User> getListByJson() { List<User> users = new ArrayList<>(); for (int i = 0; i < 10; i++) { User user = new User(); user.setUsername("小明 : "+i); user.setPassword("123 :"+i); user.setPhone("135xxxx :"+i); user.setEmail( "xiaoming@qq.com"); users.add(user); } return users; }
11. 文件上传
在web开发中一般都会有文件上传的操作
一般在JavaWeb开发中文件上传使用的 Apache组织的Commons FileUpload组件
SpringMVC中使用 MultipartFile file对象接受上传文件,必须保证 后台参数的名称和表单提交的文件的名称一致
文件上传必须条件
1.表单必须post
2.表单必须有 file 文件域
3.表单的 enctype="multipart/form-data"
11.1 单个文件上传
步骤:
1.导入相关jar包
2.在springmvc.xml中配置上传解析器
property的value用来设置上传文件的最大尺寸,其他配置为固定配置
<!-- 配置文件上传解析器:bean的名字是固定的,底层使用的名称注入 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设置上传文件的最大尺寸为1MB -->
<property name="maxUploadSize" value="#{1024 * 1024}"></property>
</bean>
3.jsp代码
<fieldset> <legend>单个文件上传</legend> <form action="${pageContext.request.contextPath}/upload.do" method="post" enctype="multipart/form-data"> 姓名: <input name="username"><br> 头像: <input type="file" name="headImg"><br> <button type="submit">提交</button> </form> </fieldset> <fieldset>
4.后台代码
SpringMVC中使用 MultipartFile对象接受上传文件,必须保证 后台方法MultipartFile 参数的名称和表单提交的文件的名称一致
//SpringMVC中使用 MultipartFile对象接受上传文件,必须保证 后台参数的名称和表单提交的文件的名称一致 @RequestMapping("/upload") public String singleUpload(MultipartFile headImg,@RequestParam("username")String username) throws IOException { System.out.println(headImg.getName());//获取上传文件的表单参数名称 System.out.println(headImg.getContentType());//MIME类型:如html的MIME类型为text/html,用于确定文件属于哪一类型的 System.out.println(headImg.getSize());//文件大小 System.out.println(headImg.getOriginalFilename());//获取上传文件的完整名称 //获取上传文件对应的输入流 //InputStream in = headImg.getInputStream(); //创建一个磁盘目录(文件夹)用于保存文件 File destFile= new File("D:/upload"); if(!destFile.exists()) { //判断文件夹是否存在 destFile.mkdir(); } //使用uuid作为文件随机名称 String fileName = UUID.randomUUID().toString().replaceAll("-", ""); //使用FileNameUtils获取上传文件名的后缀 String extension = FilenameUtils.getExtension(headImg.getOriginalFilename());// jpg , png 等等 //创建新的文件名称 String newFileName = fileName + "."+extension; //创建要保存文件的File对象 File file = new File(destFile, newFileName); //保存文件到本地磁盘 headImg.transferTo(file); return "redirect:/upload.jsp"; }
11.2 多文件上传
<fieldset> <legend>多个文件上传</legend> <form name="files" action="${pageContext.request.contextPath}/uploads.do" method="post" enctype="multipart/form-data"> 文件1: <input type="file" name="headImgs"><br> 文件2: <input type="file" name="headImgs"><br> 文件3: <input type="file" name="headImgs"><br> <button type="submit">提交</button> </form> </fieldset>
@RequestMapping("/uploads") public String singleUploads(MultipartFile[] headImgs) throws IOException { //创建一个磁盘目录(文件夹)用于保存文件 File destFile= new File("D:/upload"); if(!destFile.exists()) { //判断文件夹是否存在 destFile.mkdir(); } if(headImgs!=null) { for (MultipartFile headImg : headImgs) { //使用uuid作为文件随机名称 String fileName = UUID.randomUUID().toString().replaceAll("-", ""); //使用FileNameUtils获取上传文件名的后缀 String extension = FilenameUtils.getExtension(headImg.getOriginalFilename());// jpg , png 等等 //拼接新的文件名称 String newFileName = fileName + "."+extension; //创建要保存文件的File对象 File file = new File(destFile, newFileName); //保存文件到本地磁盘 headImg.transferTo(file); } } return "redirect:/upload.jsp"; }
12.文件下载
文件下载,SpringMVC并没有做过多的封装,还是使用原来的下载方式
下载文件思路:
1. 接受需要下载文件名称,根据文件名称,找到磁盘对应的文件,读取到内存中形成一个输入流
2. 将输入流通过响应对象(HttpServletResponse)响应给浏览器(下载)
@RequestMapping("/download") public void download(String fileName,HttpServletResponse response) throws IOException { //通过接受到的文件名从磁盘中读取对应文件 FileInputStream input = new FileInputStream("D:/"+fileName); //获取响应对象的输出流 ServletOutputStream output = response.getOutputStream(); //将文件名的编码转为ISO-8859-1编码(响应头编码),否则传给浏览器的文件名中文会乱码 byte[] bytes = fileName.getBytes("utf-8"); fileName= new String(bytes, "ISO-8859-1"); //响应内容以附件的形式响应给浏览器,并设置文件名 response.setHeader("Content-Disposition", "attachment;filename="+fileName); //响应文件给浏览器 IOUtils.copy(input, output); }
13.SpringMVC的拦截器
拦截器 (Interceptor):Spring MVC 的拦截器类似于Servlet 开发中的过滤器Filter,用于对Controller进行预处理和后处理。拦截器只会拦截控制器请求,不会拦截jsp页面。
使用SpringMVC拦截器步骤:
1.定义拦截器类,实现接口 org.springframework.web.servlet.HandlerInterceptor
2.在applicationContext.xml中配置拦截器
13.1 定义拦截器
拦截器方法的执行时机:
1.preHandle:控制器方法执行之前执行,返回结果为true表示放行,如果返回为false,表示拦截(可以做权限拦截,登录检查拦截).
2.postHandle:控制器方法执行后,视图渲染之前执行(可以加入统一的响应信息).
3.afterCompletion:视图渲染之后执行(处理Controller异常信息,记录操作日志,清理资源等)
/** * 验证登录拦截器 */ public class CheckLoginInterceptor implements HandlerInterceptor{ /* * 控制器方法执行之前执行 * 返回结果为true表示放行,如果返回为false,表示拦截(可以做权限拦截,登录检查拦截). */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //获取session中的user对象 User user = (User)request.getSession().getAttribute("user"); if(user==null) { //user==null表示为登录 //重定向跳转到登录页面 login.jsp response.sendRedirect(request.getContextPath()+"/login.jsp"); return false; //拦截请求 } return true; //放行 } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // TODO Auto-generated method stub } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // TODO Auto-generated method stub } }
13.2 配置拦截器
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd "> <!-- 开启springMVC注解驱动 --> <mvc:annotation-driven/> <!-- 配置拦截器 --> <mvc:interceptors> <!-- 配置登录检查拦截器 --> <mvc:interceptor> <!-- 拦截的地址(只会拦截 控制器请求,不会拦截jsp页面) /*:只能拦截一级, 如:login.do /**:可以拦截多级,如:a/b/c/d/login.do --> <mvc:mapping path="/**"/> <!-- 排除拦截的地址,多个地址使用逗号隔开 --> <mvc:exclude-mapping path="/user/login.do"/> <!-- 自定义的拦截器 --> <bean class="com.gjs.ssm.interceptor.CheckLoginInterceptor"/> </mvc:interceptor> </mvc:interceptors> </beans>
14. 使用poi组件导出excel文件
14.1 导入jar包
14.2 示例代码
// 导出用户信息 @RequestMapping("/exprot") public void export(HttpServletResponse response) { //创建POI的数据对象 工作集 HSSFWorkbook book = new HSSFWorkbook(); //创建sheet HSSFSheet sheet = book.createSheet(); //创建行(索引从0开始,表示第一行) HSSFRow titleRow = sheet.createRow(0); //使用行创建列并设置数据(索引从0开始,表示第一列) titleRow.createCell(0).setCellValue("编号"); titleRow.createCell(1).setCellValue("姓名"); titleRow.createCell(2).setCellValue("邮箱"); titleRow.createCell(3).setCellValue("电话"); List<User> users = service.list(); //循环集合,每一条数据创建一行,并把对应的值设置列中 for (int i = 0; i < users.size(); i++) { User user = users.get(i); //创建行 HSSFRow row = sheet.createRow(i+1); //创建列,并将学生信息设置到对应列中 row.createCell(0).setCellValue(user.getId()); row.createCell(1).setCellValue(user.getName()); row.createCell(2).setCellValue(user.getEmail()); row.createCell(3).setCellValue(user.getPhone()); } try { //设置响应头,响应的内容是为附件形式 response.addHeader("Content-Disposition", "attachment;filename=" + new String("学生信息.xlsx".getBytes(), "ISO-8859-1")); book.write(response.getOutputStream()); } catch (Exception e) { e.printStackTrace(); } }
15. SpringMVC 控制器 Controller的生命周期
Spring 容器创建的对象默认是单例对象。可以通过@Scope注解来设置
SpringMVC对象 Controller的对象的创建有三种情况:
默认:单例,仅在服务器启动时创建,并一直存在
Request : 在用户的一次请求中生效(用户每次请求都会创建Controller对象)多例
Session : Controller对象在一次会话中创建一个对象
如果控制器中有成员变量 设置或者赋值操作,必须使用 request 返回