SpringMVC详解
一.SpringMVC概述
1.SpringMVC基本介绍
Spring MVC是Spring框架提供的基于MVC框架并继承了Servlet API的Web开发框架。它遵循MVC模式的原则,提供了一套完整的开发流程和特性。通过Spring框架的支持,它能够实现灵活性、可配置性和可扩展性,帮助开发者构建高性能的Web应用程序。
(1).MVC框架
MVC是一种设计思想,将一个应用分成3个基本部分,分别代表着Web应用程序中的3种职责:
-
Model(模型):用于存储数据和完成业务逻辑处理
-
View(视图):用于显示数据和向控制器提交数据请求
-
Controller(控制器):根据视图请求调用Model完成业务处理,将处理后的结果交由View进行展示
(2).MVC和 SpringMVC的关系
- Spring MVC是一个Web框架,而MVC是一种架构模式。Spring MVC是基于MVC模式的实现之一。
- MVC是一种将应用程序的不同方面分离的设计模式,包括模型(Model)、视图(View)和控制器(Controller)。
- Spring MVC遵循MVC设计模式,将应用程序的不同方面分离开来,通过模型、视图和控制器的协作来处理Web请求。
2.SpringMVC的优点
- 基于 MVC 架构,功能分工明确,解除耦合。
- 容易理解、上手快、使用简单。就可以开发一个注解的 SpringMVC 项目,SpringMVC 也是轻量级的,jar 很小。不依赖的特定的接口和类。
- 作为 Spring 框架一部分,能够使用 Spring 的 IoC 和 Aop。方便整合Strtus、MyBatis、Hiberate、 JPA 等其他框架。
- SpringMVC 强化注解的使用,在控制器、Service、Dao 都可以使用注解 , 方便灵活。使用@Controller 创建处理器对象, @Service 创建业务对象, @Autowired 或者@Resource 在控制器类中注入 Service, Service 类中注入Dao。
二.SpringMVC框架工作原理
1.Spring MVC框架的组件
Spring MVC框架的主要组件包括:
前端控制器(Front Controller):前端控制器是Spring MVC框架的核心组件,它负责接收所有的请求,并将请求分派给相应的控制器进行处理。
控制器(Controller):控制器是Spring MVC框架的另一个关键组件,它负责处理请求,并将处理结果返回给前端控制器。
视图解析器(View Resolver):视图解析器负责将模型数据和视图模板组合成最终的视图,然后将视图返回给客户端。
模型(Model):模型是Spring MVC框架中的一个组件,它负责处理数据,为控制器提供数据支持。
视图(View):视图是Spring MVC框架中的另一个组件,它负责展示数据,为客户端提供交互界面。
2.SpringMVC工作原理
①客户端发送请求至前端控制器DispatcherServlet。
②DispatcherServlet收到请求调用HandlerMapping处理器映射器根据请求的URL找到对应的处理器(Controller)。
③Controller调用业务逻辑后,将ModelAndView对象(封装视图和模型信息)返回给DispatcherServlet
④ DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
⑤ViewReslover视图解析器解析后返回具体的View给DispatcherServlet
⑥DispatcherServlet根据View和Model渲染视图响应给客户端
三. Spring MVC框架的开发流程
1.配置Spring MVC框架
在Web应用程序的配置文件中添加Spring MVC框架的配置。Spring MVC框架的配置通常涉及到以下几个方面:
-
DispatcherServlet的配置:DispatcherServlet是Spring MVC框架的前端控制器,它负责接收所有的请求,并将请求分派给相应的控制器进行处理。在Web应用程序的配置文件中,需要配置DispatcherServlet的相关参数,例如URL映射、视图解析器等。
-
配置控制器:在Spring MVC框架中,控制器负责处理客户端请求。在Web应用程序的配置文件中,需要配置控制器的相关参数,例如请求映射、处理方法等。
-
配置视图解析器:视图解析器负责将模型数据和视图模板组合成最终的视图。
2.创建控制器
在Spring MVC框架中,创建控制器用来创建一个或多个控制器来处理客户端请求。控制器是处理客户端请求的关键组件。控制器通常包含多个处理方法,每个处理方法负责处理一个或多个客户端请求。
以下是一个使用注解定义请求映射和处理方法的示例控制器:
@Controller
public class MyController {
@RequestMapping(value = "/hello")
public String hello() {
return "index.jsp"
}
}
在上面的示例中,@Controller注解表示这是一个控制器类。@RequestMapping注解表示这个控制器处理的URL路径是/hello,请求方法是GET。hello()方法负责处理客户端的/hello请求,它返回的字符串是是一个视图。
3.定义请求映射:
在Spring MVC框架中,在控制器中定义请求映射,用于将客户端请求映射到相应的处理方法。
以下是一个使用注解定义请求映射的示例:
@Controller
@RequestMapping("/users")
public class UserController {
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
public ModelAndView getUser(@PathVariable("id") int userId) {
// 处理获取用户信息的业务逻辑
}
@RequestMapping(value = "/{id}", method = RequestMethod.PUT)
public ModelAndView updateUser(@PathVariable("id") int userId, @RequestBody User user) {
// 处理更新用户信息的业务逻辑
}
}
在上面的示例中,@RequestMapping注解表示这个控制器处理的URL路径是/users。getUser()方法处理的URL路径是/users/{id},请求方法是GET。updateUser()方法处理的URL路径也是/users/{id},请求方法是PUT。@PathVariable注解表示将URL路径中的{id}参数映射到方法的参数中。
4.处理客户端请求
在Spring MVC框架中,在处理方法中处理客户端请求,并返回相应的模型数据和视图名称。处理方法可以返回不同类型的结果,例如ModelAndView对象、字符串、JSON对象等。
以下是一个处理方法的示例:
@RequestMapping(value = "/hello", method = RequestMethod.GET)
public ModelAndView hello() {
ModelAndView modelAndView = new ModelAndView("hello");
modelAndView.addObject("message", "Hello Spring MVC!");
return modelAndView;
}
在上面的示例中,hello()方法处理的URL路径是/hello,请求方法是GET。它返回一个包含视图名称和模型数据的ModelAndView对象。
5.创建视图
在Spring MVC框架中,视图用于将模型数据和视图组合成最终的视图。负责展示数据,为客户端提供交互界面。视图通常是一个JSP页面或者一个HTML模板。
以下是一个JSP视图的示例:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Hello Spring MVC</title>
</head>
<body>
<h1>${message}</h1>
</body>
</html>
在上面的示例中,${message}是一个EL表达式,它表示从模型中获取名为message的数据。
6.返回响应
在Spring MVC框架中,返回响应将最终的视图返回给客户端,完成请求处理。处理方法返回的结果会被转换成响应格式,然后返回给客户端。响应格式可以是HTML、JSON、XML等。
以下是一个处理方法返回JSON格式数据的示例:
@RequestMapping(value = "/users/{id}", method = RequestMethod.GET)
@ResponseBody
public User getUser(@PathVariable("id") int userId)
{ User user = userService.getUserById(userId);
return user;
}
在上面的示例中,@ResponseBody注解表示将返回的User对象转换成JSON格式数据返回给客户端。
四.springMVC的创建
1.新建Maven项目
2.导入相关依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.8</version>
</dependency>
</dependencies>
3.配置web.xml
在web.xml中声明DispatcherServlet对象
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!-- 配置DispatcherServlet -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 配置DispatcherServlet接受所有URL请求 -->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
说明:
-
load-on-startup
(1)当值为0或者大于0时,表示tomcat在应用启动时就加载这个servlet
(2)当是一个负数时或者没有指定时,则表示第一次URL请求的时候加载该servlet
-
servlet-mapping用于配置servlet接受哪些URL请求,/表示接受所有请求
-
注意,千万不要写成/*
4.在web.xml中添加过滤器
在 web.xml添加 SpringMVC的一个过滤器,用于将请求和响应进行编码,以免中文乱码
<!-- 编码过滤器,解决中文乱码问题 -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
5.创建Spring MVC的配置文件“spring-mvc.xml”
- 在“resources”下创建配置文件“spring-mvc.xml”
- 编辑“spring-mvc.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.xsd">
<!-- 这里添加其他配置 -->
</beans>
6.修改“web.xml”
配置在tomcat启动的时候自动加载“spring-mvc.xml”配置
<!-- 配置DispatcherServlet -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 加载类路径下的spring-mvc.xml -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
7.新建“hello.jsp”页面
①在“WEB-INF”文件夹下,新建views文件夹,用来统一管理所有的jsp页面(WEB-INF下的页面是不能通过浏览器的
url直接访问的,保证系统安全性)
②在views文件夹下新建“hello.jsp”页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
</head>
<body>
helloworld!!!
</body>
</html>
8.创建控制器Controller
在“src”下新建包“controller”,包下新建控制器类“HelloController”
@Controller
public class HelloController {
//通过"/hello"来访问hello.jsp页面
@RequestMapping("/hello")
public String hello(){
return "/WEB-INF/views/hello.jsp";
}
}
通过“http://localhost:8080/springmvc_demo/hello” 来访问hello.jsp页面
说明:
1、@Controller注解标识该类为控制器
2、@RequestMapping("/hello")注解表示用户请求访问hello方法的映射路径url
3、控制器中的方法我们称为Action
9.修改“spring-mvc.xml”配置文件
通过扫描将controller配置到Spring容器中
<!-- 将控制器扫描到容器中 -->
<context:component-scan base-package="controller"/>
<!-- 开启SpringMVC框架的注解驱动 -->
<mvc:annotation-driven/>
10.运行tomcat
至此:第一个springMVC框架项目搭建完成
将该项目添加至tomcat运行,在浏览器中输入url进行验证,如下:http://localhost:8080/springmvc_demo/hello
11.优化控制器返回的视图地址
在“spring-mvc.xml”配置文件中加入视图解析器配置:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
@Controller
public class HelloController {
@RequestMapping("/hello")
public String hello(){
return "hello";
}
}
视图解析器会帮助我们在控制器中返回视图的时候自动加上前缀和后缀
五.获取参数
1.传递单个参数
在SpringMVC中可以直接用方法中的参数来实现传参:
@RequestMapping("/hello")
public String sayHi(String name){
return "hello " + name;
}
2.传递多个参数/表单参数传递
@RequestMapping("/prams")
public String prams(String name,Integer id) {
return "name : "+name+" ,id:" +id;
}
注意:当有多个参数时,前后端进行参数匹配时,是根据参数的名称进行匹配的,并不会因为参数的顺序和位置发生变化影响后端获取参数的结果。
3.传递对象
SpringMVC可以自动的实现对象参数的赋值,比如Person对象:
import lombok.Data;
@Data //自动生成setter和getter、toString方法
public class Person {
private int id;
private String name;
}
传递对象实现:
@RequestMapping("/person")
public String person(Person person) {
return person.getName()+ ":" + person.getId();
}
4.后端参数重命名(后端参数映射)
可以通过在@RequestParam注解中指定value或name属性来实现前后端参数值重命名。
下面是使用@RequestParam注解进行参数重命名的示例:
@GetMapping("/search")
public String search(@RequestParam(value = "q") String query) {
// ...
return query;
}
注意:如果此时不传入参数就会报错
这是因为后端声明了前端必须传递一个“q”参数,但是前端没有给后端传递,于是就报错了,我们查看以下@RequestParam的注解实现细节就可以发现问题,注解实现如下:
在未明确指定required属性时,默认值为true,即传递参数为必需的。如果请求中没有传递该参数,服务器将返回400 Bad Request错误。
5.非必传参数设置
如果我们要实现前端参数是一个非必传参数,可以通过设置@RequestParam种的required=false来避免不传递参数而报错:
@RequestMapping("/search")
public String search(@RequestParam(value = "q",required = false) String query) {
// ...
return "Search result for: " + query;
}
如果将required属性设置为false,则查询参数变为可选,不再强制要求请求中包含该参数。此时,如果请求中没有传递该查询参数,方法参数将被设置为null,并且方法仍然能够正常调用。
6.接收JSON对象
还是person类
import lombok.Data;
@Data //自动生成setter、getter等方法
public class Person {
private int id;
private String name;
}
接收代码:
import org.springframework.web.bind.annotation.*;
@RequestMapping(value = "/person",method = RequestMethod.POST)
public Person person(@ResponseBody Person person) {
System.out.println(person.getId()+": "+person.getName());
return person;
}
使用**@RequestBody**注解将请求体的JSON数据绑定到方法参数上。然后,将参数声明为一个合适的Java对象类型,Spring将根据请求体的JSON数据自动进行反序列化,并将其转换为该Java对象。
为了能够正确地进行序列化和反序列化,确保Person类拥有与JSON数据结构对应的属性以及正确的getter和setter方法。
如果去掉参数上的@ResponseBody,将接收不到JSON对象数据。
7.获取URL中参数
- 通常有两种传参:
通过路径传递的参数,在URL的路径部分进行传递。
@PathVariablea , path(url):/user/123
通过查询字符串(Query String)传递的参数,在URL的查询字符串部分进行传递。
@RequestPram:/user?id=123
例如:
@RequestMapping("/reg/{name}/{pwd}")
public String reg(@PathVariable String name,@PathVariable String pwd){
return name+ ": "+ pwd;
}
注意:此时参数传参位置要和后端参数顺序位置一致。
六.响应数据
1.返回视图
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
@Controller
@RequestMapping("/hero")
public class HeroController {
@RequestMapping("/hello")
public String hello(){
System.out.println("hello···");
return "hello";
}
}
2.返回字符串形式
-
**直接返回字符串:**此种方式会将返回的字符串与视图解析器的前后缀拼接后跳转
资源地址:/WEB-INF/views/hello.jsp
-
返回带有前缀的字符串:
转发:forward:/WEB-INF/views/hello.jsp
重定向:redirect:/index.jsp
@RequestMapping("/forward") public String forword(){ System.out.println("forward···"); return "forward:/WEB-INF/views/index.jsp"; } @RequestMapping("/redirect") public String redirect(){ System.out.println("redirect···"); return "redirect:/login.jsp"; }
3.返回ModelAndView对象
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
你好,SpringMVC!${username}
</body>
</html>
@RequestMapping("/hello2")
public ModelAndView hello2(){
//Model:模型,用于封装数据
//View:视图,用于展示数据
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("username","pep7chiao");
modelAndView.setViewName("hello");
return modelAndView;
}
@RequestMapping("/hello3")
public ModelAndView hello3(ModelAndView modelAndView){
modelAndView.addObject("username","pep7chiao");
modelAndView.setViewName("hello");
return modelAndView;
}
@RequestMapping("/hello4")
public String hello4(Model model){
model.addAttribute("username","messi");
return "hello";
}
4.回写数据
-
直接返回字符串
Web基础阶段,客户端访问服务器端,如果想直接回写字符串作为响应体返回的话,只需要使用response.getWriter().print(“hello world”))即可,那么在Controller中想直接回写字符串该怎样呢?
- 通过SpringMVC框架注入的response对象,使用response.getWriter().print(“hello world”)回写数
据,此时不需要视图跳转,业务方法返回值为void。
@RequestMapping("/data1") public void data1(HttpServletResponse response) throws IOException { response.setContentType("text/html;charset=utf-8"); response.getWriter().print("重庆工程学院"); }
-
将需要回写的字符串直接返回,但此时需要通过**@ResponseBody**注解告知SpringMVC框架,方法返回的字符串不是跳
转,而是直接在http响应体中返回。
@RequestMapping(value = "/data2",produces = "text/html;charset=utf-8") @ResponseBody public String data2(){ return "软件工程研究所"; }
-
返回对象或集合
- 导入json相关依赖
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.0</version> </dependency>
- 通过SpringMVC帮助我们对对象或集合进行json字符串的转换并回写,为处理器适配器配置消息转换参数,指定使用jackson进行对象或集合的转换,因此需要在spring-mvc.xml中进行如下配置:
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
</bean>
</list>
</property>
</bean>
@RequestMapping("/data3")
@ResponseBody
public Hero data3() throws IOException {
Hero hero = new Hero();
hero.setId(1L);
hero.setHeroName("李白");
return hero;
}
- 在方法上添加@ResponseBody就可以返回json格式的字符串,但是这样配置比较麻烦,配置的代码比较多,因此,我们可以使用mvc的注解驱动代替上述配置。
<mvc:annotation-driven/>
- 在SpringMVC的各个组件中,处理器映射器、处理器适配器、视图解析器称为SpringMVC的三大组件。使用<mvc:annotation-driven>自动加载RequestMappingHandlerMapping (处理映射器)和
RequestMappingHandlerAdapter(处理适配器),可用在Springmvc.xml配置文件中使用<mvc:annotation-driven>替代注解处理器和适配器的配置。 - 同时使用<mvc:annotation-driven>默认底层就会集成jackson进行对象或集合的json格式字符串的转换。
七.请求文件上传
-
文件上传客户端三要素
- 表单项type=“file”
- 表单的提交方式是post
- 表单的enctype属性是多部分表单形式,及enctype= “multipart/form-data"
<form action="${pageContext.request.contextPath}/hero/upload" method="post" enctype="multipart/form-data"> <p>英雄名称:<input type="text" name="heroName"></p> <p>英雄图片:<input type="file" name="heroImg"></p> <p><input type="submit" value="提交"></p> </form>
-
文件上传原理
- 当form表单修改为多部分表单时,request.getParameter()将失效。
- enctype= “application/x-www-form-urlencoded”时,form表单的正文内容格式是:key=value&key=value&key=value
- 当form表单的enctype取值为Mutilpart/form-data时,请求正文内容就变成多部分形式:
-
单文件上传步骤
(1)导入fileupload和io坐标
<dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.2.2</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version> </dependency>
(2)配置文件上传解析器
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSize" value="5242880"></property> <property name="maxUploadSizePerFile" value="5242880"></property> <property name="defaultEncoding" value="UTF-8"></property> </bean>
(3)编写文件上传代码
@RequestMapping("/upload") @ResponseBody public void upload(String heroName, MultipartFile heroImg) throws IOException { String originalFilename = heroImg.getOriginalFilename(); System.out.println("文件名称:"+originalFilename); heroImg.transferTo(new File("D:\\DevelopWork\\javaweb\\springmvc-demo\\web\\upload\\"+originalFilename)); }
-
多文件上传实现
<form action="${pageContext.request.contextPath}/hero/uploads" method="post" enctype="multipart/form-data"> <p>英雄名称:<input type="text" name="heroName"></p> <p>英雄图片1:<input type="file" name="heroImgs"></p> <p>英雄图片2:<input type="file" name="heroImgs"></p> <p>英雄图片3:<input type="file" name="heroImgs"></p> <p>英雄图片4:<input type="file" name="heroImgs"></p> <p><input type="submit" value="提交"></p> </form>
或者:
<form action="${pageContext.request.contextPath}/hero/uploads" method="post" enctype="multipart/form-data"> <p>英雄名称:<input type="text" name="heroName"></p> <p>英雄图片:<input type="file" name="heroImgs" multiple></p> <p><input type="submit" value="提交"></p> </form>
@RequestMapping("/uploads") @ResponseBody public void uploads(String heroName, MultipartFile[] heroImgs) throws IOException { for (MultipartFile heroImg : heroImgs) { String originalFilename = heroImg.getOriginalFilename(); System.out.println("文件名称:"+originalFilename); heroImg.transferTo(new File("D:\\DevelopWork\\javaweb\\springmvc-demo\\web\\upload\\"+originalFilename)); } }
八.拦截器
-
拦截器的作用
Spring MVC的拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。
将拦截器按一定的顺序联结成一条链,这条链称为拦截器链(Interceptor Chain)。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。拦截器也是AOP思想的具体实现。
-
拦截器和过滤器的区别
区别 过滤器 拦截器 使用范围 是servlet规范中的一部分,任何Java Web工程都可以使用 是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能用 拦截范围 在url-pattern中配置了/*之后,可以对所有要访问的资源拦截 只会拦截访问的控制器方法,如果访问的是jsp,html,css,image或者js 是不会进行拦截的 -
拦截器的快速入门
(1)创建拦截器类实现Handlerlnterceptor接口
public class MyIntercepter implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("目标方法执行之前执行···"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("目标方法执行之后,视图对象返回之前执行···"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("流程都执行完毕之后执行···"); } }
(2)配置拦截器
<mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/hero/*"/> <bean class="com.cqgcxy.interceptor.MyIntercepter"></bean> </mvc:interceptor> </mvc:interceptors>
(3)测试拦截器的拦截效果
-
拦截器方法说明
方法名 说明 preHandle 方法将在请求处理之前进行调用,该方法的返回值是布尔值Boolean类型的,当它返回为false时,表示请求结束,后续的Interceptor和Controller都不会再执行;当返回值为true时就会继续调用下一个Interceptor的preHandle方法 postHandle 该方法是在当前请求进行处理之后被调用,前提是preHandle方法的返回值为true时才能被调用,且它会在DispatcherServlet进行视图返回渲染之前被调用,所以我们可以在这个方法中对Controller处理之后的ModelAndView对象进行操作 afterCompletion 该方法将在整个请求结束之后,也就是在DispatcherServlet渲染了对应的视图之后执行,前提是preHandle方法的返回值为true时才能被调用 -
练习:
案例需求:使用拦截器,验证用户是否登录。
- 当访问/hero/路径下的子路径时会被自定义的拦截器所拦截。该拦截器从session中判断是否有已经登录的信息,如果有则放行,如果没有,则跳转到登录页面。
public class LoginIntercepter implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session = request.getSession(); String username = (String)session.getAttribute("username"); if(StringUtils.hasText(username)){ return true; } response.sendRedirect(request.getContextPath()+"/hero/login"); return false; } }
<mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/hero/*"/> <mvc:exclude-mapping path="/hero/login"/> <bean class="com.cqgcxy.interceptor.LoginIntercepter"></bean> </mvc:interceptor> </mvc:interceptors>
@RequestMapping(value = "/login",method = RequestMethod.GET) public String login(){ return "forward:/login.jsp"; } @RequestMapping(value = "/login",method = RequestMethod.POST) public String login(String username, String password, HttpSession session){ //模拟登录验证 if("pep".equals(username)&&"123".equals(password)){ session.setAttribute("username",username); } return "redirect:/hero/index"; }
<form action="${pageContext.request.contextPath}/hero/login" method="post"> <p> 账号:<input type="text" name="username"> </p> <p> 密码:<input type="text" name="password"> </p> <p> <input type="submit" value="登录"> </p> </form>
九.异常处理
-
异常处理思路
- 系统中异常包括两类:预期异常和运行时异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试等手段减少运行时异常的发生。
- 系统的Dao、Service、Controller出现都通过throws Exception向上抛出,最后由SpringMVC前端控制器交由异常处理器进行异常处理。
-
异常处理两种方式
(1)使用Spring MVC提供的简单异常处理器SimpleMappingExceptionResolver
(2)实现Spring的异常处理接口HandlerExceptionResolver自定义自己的异常处理器
-
简单异常处理器SimpleMappingExceptionResolver
SpringMVC已经定义好了该类型转换器,在使用时可以根据项目情况进行相应异常与视图的映射配置
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="defaultErrorView" value="error"></property> <property name="exceptionMappings"> <map> <entry key="java.lang.ArithmeticException" value="error1"></entry> <entry key="java.lang.ClassCastException" value="error2"> </entry> </map> </property> </bean>
-
自定义异常处理步骤
(1)创建异常处理器类实现HandlerExceptionResolver
public class MyResolver implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) { //创建要跳转的错误视图页面 ModelAndView modelAndView = new ModelAndView(); if(e instanceof ArithmeticException){ modelAndView.addObject("info","算数异常"); }else if(e instanceof ClassCastException){ modelAndView.addObject("info","类转换异常"); } modelAndView.setViewName("error"); return modelAndView; } }
(2)配置异常处理器
<bean class="com.cqgcxy.resolver.MyResolver"></bean>
(3)编写异常页面
(4)测试异常跳转
十.注解模式
-
web.xml替换
public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer { @Override protected WebApplicationContext createServletApplicationContext() { AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); ctx.register(SpringMvcConfig.class); return ctx; } @Override protected String[] getServletMappings() { return new String[]{"/"}; } @Override protected WebApplicationContext createRootApplicationContext() { AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); ctx.register(SpringConfig.class); return ctx; } @Override protected Filter[] getServletFilters() { CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter(); characterEncodingFilter.setEncoding("UTF-8"); return new Filter[]{characterEncodingFilter}; } }
-
springmvc.xml替换
@Configuration //@ComponentScan({"com.cqgcxy.controller","com.cqgcxy.service"}) @ComponentScan("com.cqgcxy.controller") public class SpringMvcConfig { }
-
applicationContext.xml替换
@Configuration //@ComponentScan({"com.cqgcxy.service","com.cqgcxy.dao"}) @ComponentScan(value = "com.cqgcxy", excludeFilters = @ComponentScan.Filter( type = FilterType.ANNOTATION, classes = Controller.class ) ) public class SpringConfig { }
-
拦截器配置
-
添加扫描配置类所在的配置包和拦截器包
@ComponentScan({"com.cqgcxy.controller","com.cqgcxy.config","com.cqgcxy.interceptor"})
-
把创建的拦截器通过注解@Component放入spring容器中
@Configuration public class SpringMvcSupport extends WebMvcConfigurationSupport { @Autowired private LoginIntercepter loginIntercepter; @Autowired private MyIntercepter myIntercepter; @Override protected void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(myIntercepter).addPathPatterns("/hero","/hero/**"); registry.addInterceptor(loginIntercepter).addPathPatterns("/hero","/hero/**").excludePathPatterns("/hero/login"); } }
或者:
@Configuration public class SpringMvcSupport implements WebMvcConfigurer { @Autowired private LoginIntercepter loginIntercepter; @Autowired private MyIntercepter myIntercepter; //使用默认的servlet处理静态资源 default-servlet-handler public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { configurer.enable(); } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(myIntercepter).addPathPatterns("/hero","/hero/**"); registry.addInterceptor(loginIntercepter).addPathPatterns("/hero","/hero/**").excludePathPatterns("/hero/login"); } }
-
-
使用默认的servlet处理静态资源 default-servlet-handler
@Configuration public class SpringMvcSupport implements WebMvcConfigurer { //使用默认的servlet处理静态资源 default-servlet-handler public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { configurer.enable(); } }
-
配置视图解析器
@Bean public ViewResolver getViewResolver(){ InternalResourceViewResolver viewResolver = new InternalResourceViewResolver(); viewResolver.setPrefix("/WEB-INF/views/"); viewResolver.setSuffix(".jsp"); return viewResolver; }
-
配置文件上传解析器
@Bean public MultipartResolver multipartResolver(){ CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver(); commonsMultipartResolver.setMaxUploadSize(5242880); commonsMultipartResolver.setMaxUploadSizePerFile(5242880); commonsMultipartResolver.setDefaultEncoding("UTF-8"); return commonsMultipartResolver; }
-
配置异常处理器
- 简单异常处理器
@Bean public SimpleMappingExceptionResolver getSimpleMappingExceptionResolver(){ SimpleMappingExceptionResolver exceptionResolver = new SimpleMappingExceptionResolver(); exceptionResolver.setDefaultErrorView("error"); Properties properties = new Properties(); properties.setProperty("java.lang.ArithmeticException","error1"); properties.setProperty("java.lang.ClassCastException","error2"); exceptionResolver.setExceptionMappings(properties); return exceptionResolver; }
- 自定义异常处理器
@Bean public HandlerExceptionResolver getMyResolver(){ return new MyResolver(); }