拦截器
配置拦截器
- 配置springmvc.xml
<!--配置拦截器-->
<mvc:interceptors>
<!--多个拦截器顺序执行-->
<mvc:interceptor>
<!--拦截规则-->
<mvc:mapping path="/user/*"/>
<!--拦截器类-->
<bean id="MyInterceptor" class="com.hd.interceptor.MyInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
注解方式
- addPathPatterns 用于添加拦截规则
- excludePathPatterns 用户排除拦截
@Configuration
public class MyWebAppConfigurer implements WebMvcConfigurer {
/**
* 拦截器上注入Bean
* @return
*/
@Bean
MyInterceptor myInterceptor() {
return new MyInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 多个拦截器组成一个拦截器链
registry.addInterceptor(myInterceptor()).addPathPatterns("/**").excludePathPatterns("/article/**").
excludePathPatterns("/articles/**").excludePathPatterns("/register.html").excludePathPatterns("/login.html").excludePathPatterns("/user/**").excludePathPatterns("/error/**").excludePathPatterns("/findOne");
super.addInterceptors(registry);
}
}
创建拦截器类
- 继承org.springframework.web.servlet.HandlerInterceptor
- 其他拦截器接口org.springframework.web.context.request.WebRequestInterceptor,区别HandlerInterceptor接口preHandle无返回值,不能终止请求
- 方法执行顺序:
- preHandle:执行handle方法之前调用,多个拦截器会顺序执行多个preHandle方法,其中某个拦截器preHandle方法返回false都终止请求
- postHandle:执行handle方法之后,返回ModelAndView之前执行(可修改视图),多个拦截器会逆序执行多个postHandle方法
- afterCompletion:执行完handle方法之后,视图渲染之后执行,多个拦截器会逆序执行多个afterCompletion方法
- postHandle方法的ModelAndView参数可以修改视图,如改变ctntroller发往视图的参数
public class MyInterceptor implements HandlerInterceptor {
/**
*
* @param httpServletRequest 请求
* @param httpServletResponse 响应
* @param object 当前拦截器对象
* @return 是否将当前请求拦截下来,true将拦截处理并进入下一步骤,false请求将被终止
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
System.out.println("preHandle...");
return true;
}
/**
*
* @param httpServletRequest 请求
* @param httpServletResponse 响应
* @param object 当前拦截器对象
* @param modelAndView 模型视图对象,用于修改视图
* @throws Exception
*/
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle...");
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
System.out.println("afterCompletion...");
}
}
使用拦截器实现中文编码设置
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
httpServletRequest.setCharacterEncoding("utf-8");
httpServletResponse.setCharacterEncoding("utf-8");
return true;
}
多个拦截器执行顺序
- 所有拦截器链的preHandle方法返回true才会执行postHandle、afterCompletion
- 多个拦截器的preHandle()方法顺序执行,postHandle、afterCompletion逆序执行
- 可通过重写拦截器方法改变顺序
基于拦截器的用户登陆
- 创建拦截器类
- 获取session中用户数据,session中没有用户说明未登录,跳转登陆页面
- 实现自动登陆:获取Cookie中用户token,通过token获取用户数据,并保存在session中
public class MyInterceptor implements HandlerInterceptor {
@Autowired
UserService userService;
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
Object userBysession = httpServletRequest.getSession().getAttribute("user");
if (userBysession == null){
// 未登录,根据token获取用户
String loginToken = CookieUtil.findCookieByName(httpServletRequest, "vmds_login_token");
if (StringUtils.isNotBlank(loginToken)){
// 获取用户
User user = userService.getUserByToken(loginToken);
if (user != null){
// 保存用户到session
httpServletRequest.getSession().setAttribute("user", user);
return true;
} else {
// 用户未找到,清除cookie
CookieUtil.clearCookie(httpServletRequest,httpServletResponse,"vmds_login_token");
httpServletResponse.sendRedirect("/login.html");
return false;
}
}
else {
// 没有cookie,跳转登录页面
httpServletResponse.sendRedirect("/login.html");
return false;
}
}
else {
// 已登陆
return true;
}
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}
- 配置
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<!--拦截规则-->
<mvc:mapping path="/user/*"/>
<!--拦截器类-->
<bean id="MyInterceptor" class="com.hd.interceptor.MyInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
- Controller
- 保存登陆成功的用户信息到session
- 更新用户token,写入Cookie
@RequestMapping(value = "/userlogin", method = RequestMethod.POST)
@ResponseBody
public String login(@RequestParam(value = "username") String name, @RequestParam(value = "password") String password, HttpSession session,HttpServletRequest request, HttpServletResponse response) {
PageData pageData = new PageData(request);
User user = userService.getUserByLogin(pageData);
if (null == user) {
// 用户未找到
return "error";
}
// 添加cookie token
Long mi = System.currentTimeMillis();
CookieUtil.addCookie(response, "vmds_login_token", mi.toString(), 60 * 60 * 24 * 7);
// 更新用户token
user.setToken(mi.toString());
userService.saveUser(user);
session.setAttribute("user", user);
return "200";
}
过滤器
Filter(过滤器)是实现了Filter接口的java类,由 Servlet 容器进行调用和执行的,它可以决定是否将请求继续传递给 Servlet 程序,以及对请求和响应消息是否进行修改
配置过滤器
中文过滤器:解决前端传递的中文字符乱码问题
web.xml
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<!--springmvc提供的字符编码过滤器类-->
<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>
注解方式
- @WebFilter:过滤器注解
- FilterConfig:Filter 配置对象,包含初始化参数、Filter name等
- init(): Web 容器创建 Filter 的实例对象后,将立即调用该 Filter 对象的 init 方法。init 方法在 Filter 生命周期中仅被执行一次
- doFilter():doFilter 方法来激活目标 Servlet 的 service 方法
- destroy():该方法在 Web 容器卸载 Filter 对象之前被调用,也仅执行一次
@WebFilter(
urlPatterns = "/articles/*",
initParams = {@WebInitParam(name = "val1", value = "t1"), @WebInitParam(name = "val", value = "t2")})
public class TestFilter implements Filter{
/**
* 初始化,web 应用程序启动时实例化所有 Filter,实例化时执行init方法
* @param filterConfig Filter 配置对象
* @throws ServletException
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("TestFilter init");
// 初始化参数
String filterName = filterConfig.getFilterName();
Enumeration<String> initParameterNames = filterConfig.getInitParameterNames();
System.out.println("filterName = " + filterName);
while (initParameterNames.hasMoreElements()) {
String s = initParameterNames.nextElement();
System.out.println(s + " = " + filterConfig.getInitParameter(s));
}
}
/**
* 当一个 Filter 对象能够拦截访问请求时,Servlet 容器将调用 Filter 对象的 doFilter 方法
* @param request
* @param response
* @param chain 当前 Filter 链的对象
* @throws IOException
* @throws ServletException
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 目标Servlet service 方法之前
chain.doFilter(request, response); // doFilter 方法来激活目标 Servlet 的 service 方法
// 目标Servlet service 方法之后
}
@Override
public void destroy() {
System.out.println("TestFilter destroy");
}
}
拦截器、过滤器区别
- 过滤器Filter依赖于servlet,基于回掉函数,范围更大(可过滤一些资源)
- 拦截器Interceptor依赖于框架容器,基于反射机制,只能过滤url请求