SpringMVC的拦截器与过滤器的区别:
Spring MVC可以使用拦截器对请求进行拦截处理,用户可以自定义拦截器来实现特定的功能,它可以在进入处理器之前做一些操作,或者在处理器完成后进行操作,甚至是在渲染视图后进行操作。Spring要求处理器的拦截器都要实现接口org.spring.framework.web.servlet.HandlerInterceptor,这个接口定义了三个方法:
preHandle():这个方法在业务处理器处理请求之前被调用,在该方法中对用户请求request进行处理,如果该拦截器请求进行拦截处理后还要调用其他的拦截器,或者是业务处理器去进行处理,则返回true,否则返回false
postHandle():这个方法在业务处理器处理完请求后,但是DispatcherServlet向客户端返回响应前被调用,在该方法中对用户请求request进行处理
afterCompletion():这个方法在DispatcherServlet完全处理完请求后被调用,可以在该方法中进行一些资源清理的操作,无论是否产生异常都会在渲染视图后执行的方法
public class LoginInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
User user = (User)request.getSession().getAttribute("session_user");
if(user==null) {
System.out.println("1:keketip--login====preHandle===>");
response.sendRedirect(request.getContextPath()+"/login");
return false;
}
return true;//会终止所有的请求
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("3:-----keketip==--login==postHandle===>");
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("4--->keketip=--login===afterCompletion===>");
}
}
用元素< mvc:interceptors >配置拦截器,path属性告诉springMVC该拦截器拦截什么请求,class配置指定为需要使用的拦截器,exclude-mapping排除一些请求被拦截
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/user/**"/>
<bean class="com.imooc.core.LogInterceptor">bean>
mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/user/**">mvc:mapping>
<mvc:exclude-mapping path="/user/updatepwd">mvc:exclude-mapping>
<mvc:exclude-mapping path="/user/updatebackground/*">mvc:exclude-mapping>
<bean class="com.imooc.core.LoginInterceptor">bean>
mvc:interceptor>
mvc:interceptors>
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/user/**"/>
<bean class="com.imooc.core.LogInterceptor1">bean>
mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/user/**"/>
<bean class="com.imooc.core.LogInterceptor2">bean>
mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/user/**"/>
<bean class="com.imooc.core.LogInterceptor3">bean>
mvc:interceptor>
mvc:interceptors>
Spring会先从第一个拦截器开始进入前置方法,这样的前置方法是按配置顺序运行的,然后运行处理器的代码,最后运行后置方法,后置方法和完成方法则是按照配置逆序的,和责任链模式的运行顺序的一致的
...
preHandle1
preHandle2
preHandle3
...
postHandle3
postHandle2
postHandle1
...
afterCompletion3
afterCompletion2
afterCompletion1
当其中的一个preHandle方法返回为false后,按配置顺序,后面的preHandle方法都不会运行,而控制器和所有的后置方法postHandle也不会再运行,执行过preHandle方法且该方法返回为true的拦截器的afterCompletion会按照配置的逆序执行
preHandle1
preHandle2
afterCompletion1
如果传递过来的参数名称和HTTP的保存一致,那么无须任务注解也可以获取参数
<form id="form" action="./params/commonParams.do">
<input id="roleName" name="roleName">
<input id="note" name="note">
form>
@ReuqstMapping("/commonParams")
public ModelAndView commonParams(String roleName,String note){
...
}
@ReuqstMapping("/commonParamPojo")
public ModelAndView commonParams(RoleParams roleParams){
String name = roleParams.getRoleName();
String note = roleParams.getRolenote();
...
}
2.1中如果http的参数名称变化,后台代码也需要重新绑定规则,使用注解@RequestParam可以轻松解决这类问题,而以后修改代码只需要修改@RequestParam里面的value即可
@ReuqstMapping("/requestParam")
public ModelAndView commonParams(@RequestParam("role_name") String roleName,String note){
String name = roleName
String note = note
...
}
@RequestParam注解默认情况下不能为空,如果为空系统就会抛出异常,如果希望允许它为空,就修改它的配置项required为false
(@RequestParam(value="role_name",required=false) String roleName
一些网站使用URL的形式传递参数,这符合RESTful风格,对于一些业务比较简单的应用是十分常见的,例如获取角色信息,可以把URL写作/params/getRole/1,1便是角色编号参数
//{id}代表接收一个参数
@ReuqstMapping("/params/{id}")
//注解@PathVariable表示从URL的请求地址中获取参数
public ModelAndView commonParams(@PathVariable("id") Long id){
Role role = roleService.getRole(id);
}
请求地址的如下
localhost:8080/Derrick/params/getRole/1.do
假设需要传递角色名称、备注和分页参数
public class PageParams{
private int start;
private int limit;
}
public class RoleParams{
private String roleName;
private String note;
private PageParam pageParams = null;
}
传递的JSON数据需要和对应参数的POJO保持一致,并且设置参数类型为JSON,将JSON数据转换为字符串
$(document).ready(function(){
//JSON需要和RoleParams一一对应
var data = {
roleName:'role',
note:'note',
pageParams:{
start:1,
limit:20
}
}
//JQuery的post请求
$.post({
url:"./params/findRoles.do",
//设置contentType传递参数类型为JSON
contentType:"application/json",
//将JSON转换为字符串传递
data:JSON.stringify(data),
//成功后的方法
success:function(result){
}
});
});
@ReuqstMapping("/findRoles")
public ModelAndView FindRoles(@RequestBody RoleParams roleParams){
List<Role> roleList = roleService.findRoles(roleParams);
}
$(document).ready(function(){
//删除角色数组
var idList={1,2,3};
//JQuery的post请求
$.post({
url:"./params/deleteRoles.do",
//设置contentType传递参数类型为JSON
contentType:"application/json",
//将JSON转换为字符串传递
data:JSON.stringify(idList),
//成功后的方法
success:function(result){
}
});
});
@RequestMapping("/deleteRoles")
public ModelAndView FindRoles(@RequestBody List<Long>idList){
int total = roleService.deleteRoles(idList);
}
$(document).ready(function(){
//删除角色数组
var roleList={
{roleName:'role_name_1',note:'note_1'},
{roleName:'role_name_2',note:'note_2'},
{roleName:'role_name_3',note:'note_3'}
};
//JQuery的post请求
$.post({
url:"./params/addRoles.do",
//设置contentType传递参数类型为JSON
contentType:"application/json",
//将JSON转换为字符串传递
data:JSON.stringify(roleList),
//成功后的方法
success:function(result){
}
});
});
@RequestMapping("/addRoles")
public ModelAndView FindRoles(@RequestBody List<Long>idList){
int total = roleService.deleteRoles(idList);
}
通过表单序列化也可以将表单数据转换为字符串传递给后台
将form表单序列化,传递给后台,则将数据以roleName=XXX&¬e=XXX传递
<script type="text/javascript">
$(document).ready(function(){
$("commit").click(function(){
var str=$("form").serialize();
//提交表单
$.post({
url:"./params/commonParamPojo2.do",
data:${"form"}.serialize(),
//成功的方法
success:function(result){
}
});
});
});
</script>
@RequestMapping("/commonParamPojo2")
public ModelAndView FindRoles(String roleName,String note){
...
}
当有一个showRoleJsonInfo处理器是负责将角色信息转换为视图时,当我们另外一个处理器是需要新增角色后以JSON视图的形式展示给请求者,我们可以将角色信息传递给showRoleJsonInfo
Spring MVC有一个约定,当返回的字符串带有redirect的时候,它就会认为需要的是一个重定向
@RequestMapping("/addRole")
//Model为重定向数据模型,Spring MVC会自动初始化它
public String addRole(Model model,String roleName,String note){
Role role = new Role();
role.setRoleName(roleName);
role.setNote(note);
roleService.insertRole(role);
//绑定重定向数据模型
model.addAttribute("roleName",roleName);
model.addAttribute("note",note);
model.addAttribute("id",role.getId());
return "redirect:./showRoleJsonInfo.do";
}
@RequestMapping("/addRole2")
//ModelAndView对象,Spring MVC会自动初始化它
public ModelAndView addRole2(ModelAndView mv,String roleName,String note){
Role role = new Role();
role.setRoleName(roleName);
role.setNote(note);
roleService.insertRole(role);
//绑定重定向数据模型
model.addAttribute("roleName",roleName);
model.addAttribute("note",note);
model.addAttribute("id",role.getId());
mv.setViewName("redirect:./showRoleJsonInfo.do");
return mv
}
以上都是传递一个一个参数,但有时候需要传递POJO来完成任务,而不是一个个字段的传递,我们将POJO转化为JSON视图,代码如下
@RequestMapping("/showRoleJsonInfo2")
public ModelAndView addRole(Role role){
ModelAndView mv = new ModelAndView();
mv.setView(new MappingJackson2JsonView());
mv.addObject("role",role);
return mv;
}
但是在URL重定向过程中,HTTP的重定向参数是以字符串传递的,这是并不能有效传递对象,需要借助数据模型RedirectAttribute,使用它的addFlashAttribute方法后,Spring MVC会将数据保存到Session中,重定向后就会将其清楚,流程如下
@RequestMapping("/addRole3")
public ModelAndView addRole3(RedirectAttributes ra,Role role){
roleService.insertRole(role);
//绑定重定向数据模型
ra.addFlashAttribute("role",role);
return "redirect:./showRoleJsonInfo2.do";
}
RequestAttribute注解的参数默认不能为空,有一个required配置项,它是一个boolean值,设置为false代表可以为空
//设置请求属性
request.setAttribute("id",1L);
//转发给控制器
request.getRequestDispatcher("./requestAttribute.do").forword(request,response);
@RequestMapping("/requestAttribute")
publiv ModelAndView reqAttr(@RequestAttribute(name="id",required=false) Long id){
...
}
注解和HTTP会话对象有关,在控制器中可以使用注解@SessionAttributes来设置对应的键值对,不过这个注解只能对类进行标准,不能对方法或参数注解。它可以配置属性名称或属性类型,它的作用是当这个类被注解后,Spring MVC执行完控制器的逻辑后,将数据模型中对应的属性名或属性类型保存到HTTP的Session对象中
如下代码中如果请求/attribute/sessionAttributes.do?id=1,sessionAttrs方法中数据模型保存了一个id和角色,由于它们满足了@SessionAttribute的配置,所以最后它会保存到Session对象中
@Controller
@RequestMapping("/attribute")
//可以配置数据模型的名称和类型
@SessionAttributes(name={"id"},types={Role.class})
public class AttributeController{
@RequestMapping("/sessionAttributes")
public ModleAndView sessionAttrs(Long id){
...
mv.addObject("id",id);
...
}
}
<%
//设置session属性
session.setAttribute("id",1L);
...
%>
@RequestMapping("/sessionAttribute")
public ModelAndView sessionAttr(@SessionAttribute("id")Long id){
...
}