从零开始学springboot-6.手写拦截器和自定义注解

我们想实现 不同的请求路由、参数(例如token识别用户)对不同的请求做出处理和拒绝的情况,可以使用shiro和spring security,这里我们为了学习,所以我们尝试通过写自定义注解和拦截器来满足我们比较个性化的需求。

新建注解

在base目录下新建一个目录

annotation

在annotation目录下新建一个注解Admin.java,代码如下

package com.example.demo.base.annotation;

import java.lang.annotation.*;

//定义可以在方法和类上使用此注解
@Target({ElementType.METHOD,ElementType.TYPE})
//定义的这个注解是注解,会在class字节码文件中存在,在运行时可以通过反射获取到。
@Retention(RetentionPolicy.RUNTIME)
//定义子类可以继承父类中的该注解
@Inherited

public @interface Admin {
}

从零开始学springboot-6.手写拦截器和自定义注解

新建拦截器

在base目录下新建一个目录

interceptor

在interceptor目录下新建一个文件MyInterceptor.java,代码如下

package com.example.demo.base.interceptor;

import com.example.demo.base.annotation.Admin;
import com.example.demo.base.vo.Result;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyInterceptor implements HandlerInterceptor {
    /**
     * 在请求处理之前进行调用(Controller方法调用之前)
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        response.setHeader("content-type","application/json; charset=utf-8");
        //判断请求的方法上是否有注解
        boolean haveAnnotataion = handler.getClass().isAssignableFrom(HandlerMethod.class);
        //如果有注解,判断是否是MyAnnotation
        if (haveAnnotataion){
            Admin admin = ((HandlerMethod)handler).getMethodAnnotation(Admin.class);
            //判断是否有admin注解
            if(admin != null){
                String id = request.getParameter("id");
                if("1".equals(id)){
                    return true;
                }else{
                    response.getWriter().write(Result.error("你没有权限").toJsonString());
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * 请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    }

    /**
     * 在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    }
}

说明

我们主要在preHandle方法下业务代码,这里的例程是请求参数中id=1代表是admin,可以正常使用接口,否则就返回无权限

配置拦截器

在interceptor目录下新建一个文件MyInterceptorConfig.java,代码如下

package com.example.demo.base.interceptor;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * 拦截器配置类
 */
@Configuration
public class MyInterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry){
        //注册拦截器
        InterceptorRegistration registration = registry.addInterceptor(new MyInterceptor());

        //添加拦截请求
        registration.addPathPatterns("/user/**");

        //添加不拦截的请求
        registration.excludePathPatterns("/test/**");
    }

}

如何使用

在我们控制器中,想要加权限的方法上,加上@Admin即可

从零开始学springboot-6.手写拦截器和自定义注解

测试效果演示

成功的

从零开始学springboot-6.手写拦截器和自定义注解

失败的

从零开始学springboot-6.手写拦截器和自定义注解

后话

以上只是一个例子,大家可以在HttpServletRequest request中拿到各种参数,例如token,然后进行你的鉴权业务,同时,可以写很多个注解,以满足不同的业务需求。

至此,项目结构如下

从零开始学springboot-6.手写拦截器和自定义注解

上一篇:解决js计算精度丢失问题


下一篇:showdoc安装与脚本生成文档