SpringMVC概述
基本介绍
springmvc是spring框架的一个模块,springmvc和spring无需通过中间整合层进行整合。springmvc是一个基于mvc的web框架。
SpringMVC的执行过程
执行细节
- DispatcherServlet处理url请求,并通过处理器映射器(HandlerMapping)找到对应的Handler
- 处理器映射器会返回一个执行链(就是一个封装好的对象HandlerExecutionChain),里面包含了Handler以及多个拦截器(HandlerInterceptor)
- DispacherServlet不会直接执行Handler,而是请求处理器适配器(HandlerAdapter)去执行,然后HandlerAdapter会返回一个ModelAndView(模型视图对象)对象
- DispatcherServlet请求视图解析器(View resolver)对ModelAndView进行解析并返回view
- 视图渲染将模型数据填充到request域中
- response响应
执行细节(详细版本)
-
发起请求到前端控制器(DispatcherServlet)
-
前端控制器请求HandlerMapping查找 Handler(可以根据xml配置、注解进行查找)
-
处理器映射器HandlerMapping向前端控制器返回Handler
-
前端控制器调用处理器适配器去执行Handler
-
处理器适配器去执行Handler
-
Handler执行完成给适配器返回ModelAndView
-
处理器适配器向前端控制器返回ModelAndView(ModelAndView是springmvc框架的一个底层对象,包括 Model和view)
-
前端控制器请求视图解析器去进行视图解析,根据逻辑视图名解析成真正的视图(jsp)
-
视图解析器向前端控制器返回View
-
前端控制器进行视图渲染,视图渲染将模型数据(在ModelAndView对象中)填充到request域
-
前端控制器向用户响应结果
SpringMVC执行过程中涉及的组件
-
前端控制器DispatcherServlet(不需要程序员开发)
作用:接收请求,响应结果,相当于转发器,中央处理器。DispatcherServlet减少了其它组件之间的耦合度。
-
处理器映射器HandlerMapping(不需要程序员开发)
作用:根据请求的url查找Handler
-
处理器适配器HandlerAdapter
作用:按照特定规则(HandlerAdapter要求的规则)去执行Handler
-
处理器Handler(需要程序员开发)
注意:编写Handler时按照HandlerAdapter的要求去做,这样适配器才可以去正确执行Handler
-
视图解析器View resolver(不需要程序员开发)
作用:进行视图解析,根据逻辑视图名解析成真正的视图(view)
-
视图View(需要程序员开发jsp)
View是一个接口,实现类支持不同的View类型(jsp、freemarker、pdf…)
入门程序
配置步骤(非注解开发版)
配置DispatcherServlet转发器
<!--DispatcherServlet是一个Servlet,需要在web.xml中进行配置-->
<!--配置转发器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>*.action</url-pattern>
</servlet-mapping>
注意:
在配置的时候需要配置init-param,这里是为了初始化Spring容器
关于url-pattern(Servlet的拦截方式)
拦截固定后缀的url,比如设置为 .do、.action, 例如:/user/add.action
此方法最简单,不会导致静态资源(jpg,js,css)被拦截。
拦截所有,设置为/,例如:/user/add /user/add.action
此方法可以实现REST风格的url,很多互联网类型的应用使用这种方式。但是此方法会导致静态文件(jpg,js,css)被拦截后不能正常显示。需要特殊处理。
拦截所有,设置为/*,此设置方法错误,因为请求到Action,当action转到jsp时再次被拦截,提示不能根据jsp路径mapping成功。
配置处理器适配器
在Spring的配置文件中进行配置
<!--配置处理器适配器-->
<bean id="adapter" class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
- 处理器适配器可以处理所有实现了Controller接口的类
- SimpleControllerHandlerAdapter:即简单控制器处理适配器,所有实现了org.springframework.web.servlet.mvc.Controller 接口的Bean作为SpringMVC的后端控制器。
编写控制器Handler
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/*
必须实现Controller接口
*/
public class ItemList01 implements Controller {
@Override
public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception {
List<Items> list = new ArrayList<>();
for (int i = 0; i < 3; i++) {
Items items = new Items();
items.setPrice((i+1)*120.0f);
items.setCreatetime(new Date());
items.setDetail("这是第"+(i+1)+"个作品");
items.setId(i);
items.setName("电脑"+i);
list.add(items);
}
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("itemsList",list);
modelAndView.setViewName("/WEB-INF/jsp/items/itemsList.jsp");
return modelAndView;
}
}
编写处理器映射器
在Spring的配置文件中配置
<!--编写处理器映射器-->
<bean id="handlerMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
配置编写的处理器
在Spring的配置文件中配置
<!--配置Handler-->
<bean name="/queryList/itemsList.action" class="zzuli.zw.learnSpringMVC.controller.ItemList01"/>
name值将来作为访问路径url
配置试图解析器
在Spring配置文件中配置
<!--配置视图解析器-->
<bean id="resolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"/>
非注解的处理器映射器和处理器适配器
非注解的处理器映射器
在非注解情况下,我们可以使用两种方式的处理器映射器:
-
<!--编写处理器映射器--> <bean id="handlerMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
这种方式的处理器映射器会根据配置的Handler的name来查找Handler
此时的Handler配置方式
<bean name="/queryList/itemsList.action" class="zzuli.zw.learnSpringMVC.controller.ItemList01"/>
-
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="/queryList/itemsList02.action">list01</prop> <prop key="/query/itemsList.action">list01</prop> </props> </property> </bean>
其中key为url路径,值为配置的Handler的id
此时的Handler的配置方式
<!--配置Handler--> <bean id="list01" name="/queryList/itemsList.action" class="zzuli.zw.learnSpringMVC.controller.ItemList01"/>
-
注意:
- 以上两种适配器并非只能配置一种,两种可以同时配置,SpringMVC可以根据需要使用不同的映射器查找
- 不论哪种映射器,都是需要根据url来查找Handler的
非注解的处理器适配器
在非注解情况下我们也可以使用两种适配器,他们有不同的使用场景
-
<!--配置处理器适配器--> <bean id="adapter" class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
使用这种适配器,处理器必须实现Controller接口才行
此时的处理器:
public class ItemList01 implements Controller { @Override public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse){ List<Items> list = new ArrayList<>(); ModelAndView modelAndView = new ModelAndView(); modelAndView.addObject("itemsList",list); modelAndView.setViewName("/WEB-INF/jsp/items/itemsList.jsp"); return modelAndView; } }
可以看到,里面只有一个方法,而且最终返回的是ModelAndView对象
-
<bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"/>
使用这种适配器,处理器必须实现HttpRequestHandler接口
此时的处理器:
public class ItemList02 implements HttpRequestHandler { @Override public void handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException { } }
可以看到,里面同样只有一个方法,但是返回值为void,这就意味着我们可以使用response来返回json串
-
两种方式的比较:
- 第一种使用起来相对比较简单一点,但是不能返回流
- 第二种和之前的原始方式很相似,比较麻烦,但是可以通过response返回流
- 不管是第一种还是第二种都有一个缺陷就是只能写一种方法,不太方便
注解开发中的处理器映射器和处理器适配器
注解中的处理器映射器和处理器适配器需要配对使用
一般使用的是以下两个:
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
使用注解配置有两种方式:
-
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
-
<mvc:annotation-driven/>
-
实际开发过程中推荐使用第二种方式进行配置
实际案例
@Controller("itemList")
public class ItemList03 {
@RequestMapping("/itemsList/queryItems")
public ModelAndView queryItems(){
List<Items> list = new ArrayList<>();
for (int i = 0; i < 3; i++) {
Items items = new Items();
items.setPrice((i+1)*120.0f);
items.setCreatetime(new Date());
items.setDetail("这是第"+(i+1)+"个作品");
items.setId(i);
items.setName("电脑"+i);
list.add(items);
}
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("itemsList",list);
modelAndView.setViewName("/WEB-INF/jsp/items/itemsList.jsp");
return modelAndView;
}
}
其中我们可以使用@RequestMapping注解来替代原来非注解配置url的方式。
配置jsp路径的前缀和后缀
<bean id="resolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
为视图解析器配置两个参数即可
配置之前
modelAndView.setViewName("/WEB-INF/jsp/items/itemsList.jsp");
配置之后
modelAndView.setViewName("items/itemsList");
@RequestMapping
通过@RequestMapping注解可以定义不同的处理器映射规则。
URL映射
在class上添加@RequestMapping(url)指定通用请求前缀, 限制此类下的所有方法请求url必须以请求前缀开头,通过此方法对url进行分类管理。
如下:
@RequestMapping放在类名上边,设置请求前缀
@Controller
@RequestMapping("/item")
方法名上边设置请求映射url:
@RequestMapping放在方法名上边,如下:
@RequestMapping("/queryItem ")
请求方法限定
限定GET方法
@RequestMapping(method = RequestMethod.GET)
//如果通过Post访问则报错:HTTP Status 405 - Request method 'POST' not supported
限定POST方法
@RequestMapping(method = RequestMethod.POST)
GET和POST都可以
@RequestMapping(method={RequestMethod.GET,RequestMethod.POST})
Controller中方法的返回值
ModelAndView
controller方法中定义ModelAndView对象并返回,对象中可添加model数据、指定view。
public ModelAndView selectByName(){
ItemsQueryAo query = new ItemsQueryAo();
Items items = new Items();
items.setName("电脑");
query.setItems(items);
List<ItemsCustom> list = itemsService.getByName(query);
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("itemsList",list);
modelAndView.setViewName("items/itemsList");
return modelAndView;
}
该方式默认使用请求转发
String
public String queryAll(Model model){
List<ItemsCustom> list = itemsService.getByName(null);
model.addAttribute("itemsList",list);
return "items/itemsList";
}
controller方法返回字符串可以指定逻辑视图名,通过视图解析器解析为物理视图地址。
使用该凡是返回的字符串默认使用请求转发的方式解析,同时可以使用加前缀的方式来实现转发和重定向
//重定向
return "redirect:selectAll.action";
//请求转发
return "forward:selectAll.action";
void
在controller方法形参上可以定义request和response,使用request或response指定响应结果:
public void query(HttpServletRequest request, HttpResponse response){
}
参数绑定
处理器适配器在执行Handler之前需要把http请求的key/value数据绑定到Handler方法形参数上。
默认支持的参数类型
- HttpServletRequest
- HttpServletResponse
- HttpSession
- Model/ModelMap
参数绑定介绍
注解适配器对RequestMapping标记的方法进行适配,对方法中的形参会进行参数绑定,早期springmvc采用PropertyEditor(属性编辑器)进行参数绑定,将request请求的参数绑定到方法形参上,3.X之后springmvc就开始使用Converter进行参数绑定。
简单类型
- 整型
- 字符串
- 浮点数
- 布尔类型
@RequestParam
使用@RequestParam常用于处理简单类型的绑定。
value:参数名字,即入参的请求参数名字,如value=“item_id”表示请求的参数区中的名字为item_id的参数的值将传入
required:是否必须,默认是true,表示请求中一定要有相应的参数,否则将报;
TTP Status 400 - Required Integer parameter ‘XXXX’ is not present
defaultValue:默认值,表示如果请求中没有同名参数时的默认值
定义如下:
public String editItem(@RequestParam(value="item_id",required=true) String id) {
}
形参名称为id,但是这里使用value=" item_id"限定请求的参数名为item_id,所以页面传递参数的名必须为item_id。
注意:如果请求参数中没有item_id将跑出异常:
HTTP Status 500 - Required Integer parameter ‘item_id’ is not present
这里通过required=true限定item_id参数为必需传递,如果不传递则报400错误,可以使用defaultvalue设置默认值,即使required=true也可以不传item_id参数值
public String query(@RequestParam(value = "id",required = true,defaultValue = "1") Integer id){
System.out.println(id);
return "forward:/hello.html";
}
POJO/domain
将pojo对象中的属性名于传递进来的属性名对应,如果传进来的参数名称和对象中的属性名称一致则将参数值设置在pojo对象中
public void query(@RequestParam(value = "id",defaultValue = "1") Integer id,User user){
user.setId(id);
System.out.println(user);
}
包装pojo/domain(待定)
所谓包装pojo就是类似于以下方式的对象:
Public class QueryVo {
private Items items;
}
自定义参数绑定
Converter接口
在实际开发过程中我们可能需要处理各种各样的数据类型,一些简单的数据类型SpringMVC已经帮我们处理好了,但是想Date这种比较复杂的数据类型就需要我们根据需求去自定义转换器,SpringMVC为我们提供了一个接口,我们可以自己去进行实现。
public class DateConverter implements Converter<String, Date> {
@Override
public Date convert(String s) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
try {
return simpleDateFormat.parse(s);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}
Converter支持泛型,第一个泛型变量是要转换的参数,第二个是目标参数类型,例如上面就是将String转换为Date类型。
配置自定义的参数绑定
<mvc:annotation-driven conversion-service="conversionService"/>
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<ref bean="dateConverter"/>
</set>
</property>
</bean>
注意:
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
<mvc:annotation-driven conversion-service="conversionService"/>
如果需要进行自定义绑定,那么只需要留下面的配置就可以了,上面的会产生冲突,使配置失效
绑定List类型
需求:
在实际项目开发过程中,可能会需要批量增加或者删除信息,比如说批量删除购物车中的内容,或者学校系统批量增加学生信息。这时候就需要用到List集合来接受参数。
在ItemsQueryAo中添加字段
private List<ItemsCustom> customList;
Controller层设计
@RequestMapping(value = "/testList",method = {RequestMethod.GET,RequestMethod.POST})
public String testList(ItemsQueryAo queryAo){
//Stream流
Stream.of(queryAo.getCustomList()).forEach(System.out::println);
return "items/itemsList";
}
jsp视图层设计
<%这里需要注意,customList是ItemsQueryAo中的字段名称,后面是序号%>
<td><input name="customList[${status.index }].name" value="${item.name }"/></td>
参数绑定总结
-
内置的参数绑定
HttpServletRequest、HttpServletResponse、HttpSession、Model
-
基本类型参数绑定
int、double/float、String、boolean
-
简单的pojo/domain
前端的input中name名称与pojo/domain中的字段相对应即可
-
复合的pojo/domain
为了便于程序的拓展与维护,我们往往会使用复合的pojo,复合的pojo中包含简单的pojo,在使用的时候前端页面需要:
<input type="text" name="itemsCustom.name"/>
pojo:
private ItemsCustom itemsCustom;
-
List类型绑定
数据校验
所需jar包
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.1.4.Final</version>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>3.4.1.Final</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
校验器以及错误信息资源配置
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="providerClass" value="org.hibernate.validator.HibernateValidator"/>
<property name="validationMessageSource" ref="messageSource"/>
</bean>
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basenames">
<list>
<value>classpath:Message</value>
</list>
</property>
<property name="defaultEncoding" value="UTF-8"/>
<property name="fileEncodings" value="utf-8"/>
<property name="cacheSeconds" value="120"/>
</bean>
Controller层配置
public void edits(@Validated ItemsCustom itemsCustom,BindingResult bindingResult){
if (bindingResult.hasErrors()){
for (ObjectError allError : bindingResult.getAllErrors()) {
System.out.println(allError.getCode());
}
}
}
JavaBean
@Size(min = 2,max = 15,message = "{mvc.items.name.length}")
private String name;
博客参考
https://blog.csdn.net/yangqh521/article/details/81906944
注意
编码问题:
<property name="defaultEncoding" value="UTF-8"/>
不适用于校验JavaBean中复合的JavaBean。
数据回显
在实际开发中我们有时会用到数据回显,所谓的数据回显实际上就是将数据存放到request域中,这样数据就不会丢失,在jsp页面中这种回显数据的方式还是很常用的。主要可以通过三种方式来实现数据回显。
SpringMVC默认支持的数据回显方式
SpringMVC在默认情况下会将pojo数据存入request域中,key等于pojo类型(首字母小写)。
但是在一些情况下,可能jsp页面中使用的并非pojo类型(首字母小写),这时就需要使用一个注解:
@RequestAttribute("itemsCustom")
使用@ModelAttribute注解
该注解用在方法上,作用是将方法的返回值存入到request域中
@ModelAttribute("itemsCustom")
public ItemsCustom getThis(){
return new ItemsCustom();
}
使用Model对象
@RequestMapping("/sele")
public String toEdits(Model model){
model.addAttribute("itemsCustom",new ItemsCustom());
return "items/edit";
}
文件上传及案例
需要导入的jar包:
由于SpringMVC的上传是依赖于fileupload上传组件以及commons-io的,因此需要在pom.xml中添加相应的依赖。
<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.1</version>
</dependency>
配置多部件解析器
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="5242880"/>
<property name="defaultEncoding" value="UTF-8"/>
</bean>
多部件解析器用来解析前端表单的file控件内容,需要在SpringMVC的配置文件中进行相应的配置。
前端
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name="files">
<input type="submit" value="提交">
</form>
在表单设计时,我遇到了一个问题:本来只要设计enctype="multipart/form-data"
就可以了,但是在使用SpringMVC的过程中,我发现只设计成会报异常,必须指定method=“post”,不知道是什么愿意,记录一下。
后端
@RequestMapping(value = "/uploading")
public void upload(@RequestPart(value = "files") MultipartFile files, HttpServletRequest request) throws IOException {
if (files != null){
String oldFileName = files.getOriginalFilename();
if (oldFileName != null && !oldFileName.trim().isEmpty()) {
String suffix = oldFileName.substring(oldFileName.indexOf("."));
if (!suffix.trim().isEmpty()) {
String newFileName = oldFileName.substring(0, oldFileName.indexOf("."));
int index = newFileName.lastIndexOf("//");
if (index != -1){
newFileName = newFileName.substring(index+1);
}
String newUUID = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
String newUUIDFileName = newFileName+newUUID+suffix;
String realPath = request.getServletContext().getRealPath("/WEB-INF/files");
Date date = new Date();
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
int day = calendar.get(Calendar.DATE);
StringBuilder sb = new StringBuilder();
String finalFilePath = sb.append(realPath).append("/").append(year).append("/").append(month)
.append("/").append(day).append("/").append(newUUIDFileName).toString();
File file = new File(finalFilePath);
file.mkdirs();
files.transferTo(file);
// IOUtils.copy(files.getInputStream(),new FileOutputStream(file));
//将数据写入数据库
}else{
//输出错误信息,图片格式无法识别
}
}else{
//输出错误信息,请选择图片!
}
}
}
主要就是通过参数绑定:MultipartFile
来进行解析。
注意:表单中的name也需要和MulitpartFile的名称相同,也可以通过RequestParam注解来自行指定。
SpringMVC进行json交互
SpringMVC进行json交互主要依赖jackson,所以需要在pom.xml中添加相应的依赖。同时如果没有使用mvc的注解驱动,那么需要自己在控制器适配器中注入相应的依赖。
RequestBody注解
对于前端的设计来说,有的框架会将所有的表单数据封装为json对象,发送给后端,后端收到的是字符串,这是通过这个注解可以自动将前端发来的json串转换为Java对象。如果使用使用key/value的传统方式进行前后端交互,那么就不用使用此注解。
ResponseBody注解
和上面的相对应,该注解将返回值转换为json格式传递给前端解析。
SpringMVC对RESTful的支持
RESTful概述
RESTful架构,就是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。
RESTful是一种规范,这种规范在URI路径上体现的比较明显,传统方式下我们传递参数往往通过以下的方式
/items/query.action?a=1&b=2
这种格式使用起来比较复杂,不直观,在使用RESTful规范后可以写成下面的格式
/items/query/1/2
这种方式更为简洁,直观。
SpringMVC使用RESTful规范
SpringMVC配置文件
<mvc:resources mapping="/js/" location="/js/**"/>
使用RESTful规范可能会导致静态资源无法访问,因此我们需要在配置文件中配置静态资源路径进行过滤。
Controller
@RequestMapping("/add/{a}/{b}")
public String add(@PathVariable int a,@PathVariable int b, Model model){
String result = "结果为:" + a + b;
model.addAttribute("msg",result);
return "test";
}
web.xml配置
<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-config.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springMvc</servlet-name>
<!-- <url-pattern>*.action</url-pattern>-->
<url-pattern>/</url-pattern>
</servlet-mapping>
上面注释掉的是之前的使用方式,通过后缀配置url,使用RESTful需要按照下方的方式进行配置。
拦截器
拦截器的作用类似于之前的Filter,但是并不是Filter,SpringMVC使用了动态代理对方法进行增强,功能更为强大。
使用SpringMVC的拦截器
实现HandlerInterceptor接口:
public class HandlerInterceptor01 implements HandlerInterceptor {
/**
* 该方法是在Controller执行之前进行的,可以用来进行登录校验等工作,返回值为boolean类型,如果返回为true表示可以放行,否则则进行拦截
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
return false;
}
/**
*进入Handler方法之后,返回modelAndView之前执行,可以用来设置一些页面公用的东西,比如路径导航等
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {
}
/**
* 执行Handler完成执行此方法,该方法可以用来进行全局异常处理,也可以记录日志等
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
}
}
在SpringMVC的配置文件中配置拦截器
SpringMVC拦截的是处理器映射器映射的路径即注解中RequestMapping中的路径,在配置过程中,可以配置多个拦截器。
这里有两种配置方式,一种是将自定义的拦截器注入到注解处理器映射器中,一种是配置类似全局拦截器的方式。这里只对第二种进行讲解。
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="zzuli.zw.learnSpringMVC.controller.HandlerInterceptor01"/>
</mvc:interceptor>
</mvc:interceptors>
这里可以配置多个拦截器,而且是顺序执行的。
拦截器应用
需求
进行登录认证,如果是公众网页直接放行,否则重定向到登录界面
Controller
@Controller
public class LoginController {
// 登陆
@RequestMapping("/login")
public String login(HttpSession session, String username, String password)
throws Exception {
// 调用service进行用户身份验证
// ...
// 在session中保存用户身份信息
session.setAttribute("username", username);
// 重定向到商品列表页面
return "redirect:/items/queryItems.action";
}
// 退出
@RequestMapping("/logout")
public String logout(HttpSession session) throws Exception {
// 清除session
session.invalidate();
// 重定向到商品列表页面
return "redirect:/items/queryItems.action";
}
}
拦截器实现
public class LoginInterceptor implements HandlerInterceptor {
//进入 Handler方法之前执行
//用于身份认证、身份授权
//比如身份认证,如果认证通过表示当前用户没有登陆,需要此方法拦截不再向下执行
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
//获取请求的url
String url = request.getRequestURI();
//判断url是否是公开 地址(实际使用时将公开 地址配置配置文件中)
//这里公开地址是登陆提交的地址
if(url.indexOf("login.action")>=0){
//如果进行登陆提交,放行
return true;
}
//判断session
HttpSession session = request.getSession();
//从session中取出用户身份信息
String username = (String) session.getAttribute("username");
if(username != null){
//身份存在,放行
return true;
}
//执行这里表示用户身份需要认证,跳转登陆页面
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp")
.forward(request, response);
//return false表示拦截,不向下执行
//return true表示放行
return false;
}