sevlet中本身存在很多自带的过滤器
使用sevlet3.0开发自定义注解:
1、需要在启动类里面加上@ServletConponetScan
2、新建一个Filter类,并implements Filter,并实现对应的接口
3、@Webfilter标记一个类为filter,并被spring扫描
4、urlPatterns:定义拦截规则
5、控制chain、dofilter的方法的调用
一般用在权限控制、登录校验扥场景中
@WebFilter(urlPatterns = "/api/v1/login/*",filterName = "loginFiler")
public class LoginFilter implements Filter {
// springboot容器启动的时候
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO
Filter.super.init(filterConfig);
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 需要准换成http的形式,然后从head里面获取信息
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
String token = req.getHeader("token");
if(StringUtils.isEmpty(token)){
// token 一般在head里面或者parame里面
token = req.getParameter("token");
}
if(StringUtils.isEmpty(token)){
// TODO 返回未登录的状态码
return ;
}else{
// 判断token是否合法,即判断token和user的映射关系是否正确 TODO
// 加入模拟token--user的hashmap,一般token是放在redis里面的
User user = serviseImpl.session.get("token");
if(user != null){
chain.doFilter(request,response); // 表示这个被放行
}
}
}
/**
* 容器销毁的时候
*/
@Override
public void destroy() {
// TODO
Filter.super.destroy();
}
}
分布式应用是将token存在redis里面;
注解原生sevlet:
@WebServlet(name = "userServlet",urlPatterns = "/api/vi/test/servlet")
public class UserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
PrintWriter writer = resp.getWriter();
writer.write("test sevlet");
writer.flush();
writer.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}
监听器:
- ServletContextListener 应用启动监听 使用的最多的
- HttpSessionLisener 会话监听
- ServletRequestListener 请求监听
对不同类型的监听器,就是继承不同的接口
@WebListener // 表名这个类是一个监听器
public class ApplicationLister implements ServletContextListener {
/**
* 重写初始化方法
* @param sce
*/
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("启动的时候调用的方法");
}
/**
* 重写销毁方法
* @param sce
*/
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("销毁时调用的方法,也就是关闭项目的时候");
}
}
@WebListener // 表名这个类是一个监听器
public class ApplicationLister implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent se) {
HttpSessionListener.super.sessionCreated(se);
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
HttpSessionListener.super.sessionDestroyed(se);
}
}
拦截器的定义与使用:
拦截器不生效的常见问题:
- 是否有加@Configuration
- 拦截路径是否有问题**和*
- 拦截器最后的路径一定要 /** 如果是目录的话 /*/
-
自定义拦截器 HandlerInterceptor
- preHandle:调用Controller方法之前
- postHandle:Controller调用,视图渲染之前,如果之后控制器出现异常,则不会执行
- afterCompletion:不管有没有异常,这个afterCompletion都会被调用,资源回收
-
Filter 和 Interceptor 是 AOP 编程思想的基本功能,可以实现拦截功能更强大,过滤器可以做一些事情,它可以做一些事情 过滤器只在 Servlet 前面存在,而拦截器可以到达方法前后、异常抛出前后等 filter于Servlet容器即web应用中依赖,而Interceptor不依赖于Servlet容器所以可以运行在各种环境中。 在接口调用的生命周期中,拦截器可以被多次调用,而过滤器只能在应用初始化时首次调用。 过滤器和拦截器的执行顺序 过滤前->拦截前->动作执行->拦截后->过滤后
1、定义拦截策略
package net.xclass.intercepter;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import net.xclass.enums.BizCodeEnum;
import net.xclass.model.LoginUser;
import net.xclass.util.CommonUtil;
import net.xclass.util.JWTUtil;
import net.xclass.util.JsonData;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 存放拦截器的包,自定义拦截器
* 拦截器需要继承 HandlerInterceptor
*/
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
/**
* 存储token
*/
public static ThreadLocal<LoginUser> threadLocal = new ThreadLocal<>();
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 获取token
String accessToken = request.getHeader("token");
// 有些情况下url不能通过head进行传递,而是通过url进行传递
if(accessToken == null){
accessToken = request.getParameter("token");
}
if(StringUtils.isNotBlank(accessToken)){
// 不为空
Claims claims = JWTUtil.checkJWT(accessToken);
if(claims== null){
// 未登录,响应结果给前端
CommonUtil.sendJsonMessage(response, JsonData.buildResult(BizCodeEnum.ACCOUNT_UNLOGIN));
return false;
}
// 已经登录的时候
long userId = Long.valueOf(claims.get("id").toString());
String headImg = (String)claims.get("head_img");
String name = (String)claims.get("name");
String mail = (String)claims.get("mail");
// LoginUser loginUser = new LoginUser();
// loginUser.setHeadImg(headImg);
// loginUser.setId(userId);
// loginUser.setMail(mail);
// loginUser.setName(name);
LoginUser loginUser = LoginUser.builder()
.headImg(headImg).name(name).id(userId).mail(mail).build();
/**
* 解密后需要传递登录信息
*/
// 通过attribute传递用户信息
// request.setAttribute("loginUser",loginUser);
// 通过threadlocal传递用户信息 TODO
threadLocal.set(loginUser);
return true;
}
CommonUtil.sendJsonMessage(response,JsonData.buildResult(BizCodeEnum.ACCOUNT_UNLOGIN));
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
threadLocal.remove(); // 完成后需要移除
}
}
2、添加拦截路径
/**
* 拦截器的拦截策略
* 通过重写WebMvcConfigurer接口中的一些方法来实现拦截器的策略
*/
@Configuration
@Slf4j
public class IntercepterConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor()) // 传入的参数是拦截器即拦截策略
.addPathPatterns("/api/coupon/*/**","/api/coupon_record/*/**")
// 排除不拦截的路径
.excludePathPatterns("/api/coupon/*/page_coupon","api/coupon/*/new_user_coupon");
}
}
在执行的时候,如果访问的url在拦截策略里面,就会去执行prehandle里面的内容,如果返回true,继续往下执行,如果返回的是false,不能往下执行;