基于SpringBoot的拦截器学习(快速上手,超级容易)

此文章书写于 刚学习并练习过拦截器 及时进行记录,知识点并不充足,如有错误,还请见谅,请指出

我们想要自定义拦截对应的请求,放开对应的请求,或者说对一些请求进行加签,因此我们可以创建一个自定义的拦截器

什么?你不知道拦截器是什么想要赶紧去搜一下拦截器是什么?NO NO NO,我们先来使用拦截器做些什么再去对其进行更深入的了解。

我们先建一个 SpringBoot 项目

选择自己所需的 依赖(不选也可以,等下我直接把我的pom文件粘贴上来)

因为我已经试过一遍了,所以我就不创建了

各位根据这个层级目录进行创建

下面是一些代码

pom.xml
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

    <!--springboot+mybatis的依赖-->
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.1.1</version>
    </dependency>
    <!--MySQL数据库驱动-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <!--druid数据库连接池依赖-->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid-spring-boot-starter</artifactId>
        <version>1.2.8</version>
    </dependency>
    <!--Lombok依赖(可以配置也可以不用配置具体看自己)-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    <!--fastjson-->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.78</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>
application.yml
server:
  #设置端口号
  port: 8081 #默认端口是8080
spring:
  datasource:
    #数据库用户名
    username: root
    #数据库用户密码
    password: 123456
    #serverTimezone=UTC 解决市区的报错 一般mysql是8.0以上的是必须配置这个
    #userUnicode=true&characterEncoding=utf-8 指定字符编码、解码格式
    url: jdbc:mysql://localhost:3306/sauro?serverTimezone=UTC&userUnicode=true&characterEncoding=utf-8
    #设置驱动类
    driver-class-name: com.mysql.cj.jdbc.Driver
    #设置数据源
    type: com.alibaba.druid.pool.DruidDataSource

    #Spring Boot 默认是不注入这些属性值的,需要自己绑定
    #druid 数据源专有配置
    initialSize: 5
    minIdle: 5
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true
    #配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入
    #如果允许时报错  java.lang.ClassNotFoundException: org.apache.log4j.Priority
    #则导入 log4j 依赖即可,Maven 地址:https://mvnrepository.com/artifact/log4j/log4j
    filters: stat,wall,log4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

# 配置mybatis
mybatis:
  #指定pojo扫描包位置让mybatis自动扫描到指定义的pojo包下
  type-aliases-package: com.me.test.pojo
  #指定位置扫描Mapper接口对应的XML文件 classpath:xml文件位置
  mapper-locations: classpath:mapper/*.xml
model(pojo)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserInfo {
    private Integer id;
    private String username;
    private String password;
    private String authority;
    }
service
public interface UserInfoService {
    /**
     * 增加一条数据
     * @param userInfo 数据
     */
    void add(UserInfo userInfo);

    /**
     * 删除一条数据
     * @param id 被删除数据的id
     */
    void delete(Integer id);

    /**
     * 修改一条数据
     * @param userInfo 修改的数据
     */
    void update(UserInfo userInfo);

    /**
     * 根据id去查询一条数据
     * @param id 查询的id
     */
    UserInfo queryById(Integer id);

    /**
     * 查询全部数据
     * @return
     */
    List<UserInfo> queryAll();
}
serviceImpl
@Service
public class UserInfoServiceImpl implements UserInfoService {

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Override
    public void add(UserInfo userInfo) {
        userInfoMapper.add(userInfo);
    }

    @Override
    public void delete(Integer id) {
        userInfoMapper.delete(id);
    }

    @Override
    public void update(UserInfo userInfo) {
        userInfoMapper.update(userInfo);
    }

    @Override
    public UserInfo queryById(Integer id) {
        return userInfoMapper.queryById(id);
    }

    @Override
    public List<UserInfo> queryAll() {
        return userInfoMapper.queryAll();
    }
}
mapper
@Repository
@Mapper
public interface UserInfoMapper {

    /**
     * 增加一条数据
     * @param userInfo 数据
     */
    void add(UserInfo userInfo);

    /**
     * 删除一条数据
     * @param id 被删除数据的id
     */
    void delete(Integer id);

    /**
     * 修改一条数据
     * @param userInfo 修改的数据
     */
    void update(UserInfo userInfo);

    /**
     * 根据id去查询一条数据
     * @param id 查询的id
     */
    UserInfo queryById(Integer id);

    /**
     * 查询全部数据
     * @return
     */
    List<UserInfo> queryAll();
}
mapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.sauro.study.mapper.UserInfoMapper">
    <insert id="add" parameterType="com.sauro.study.model.UserInfo">
        insert into userinfo (username, password, authority)
        values (#{username},#{password},#{authority});
    </insert>

    <delete id="delete" parameterType="Integer">
        delete from userinfo where id = #{id};
    </delete>

    <update id="update" parameterType="com.sauro.study.model.UserInfo">
        update userinfo set username=#{username},password=#{password},authority=#{authority}
        where id=#{id};
    </update>

    <select id="queryById" parameterType="Integer" resultType="com.sauro.study.model.UserInfo">
        select * from userinfo where id=#{id};
    </select>

    <select id="queryAll" resultType="com.sauro.study.model.UserInfo">
        select * from userinfo;
    </select>

</mapper>
controller
@Controller
@RequestMapping(value = "/test")
public class UserInfoController {
    @Autowired
    private UserInfoService userInfoService;

 
    @GetMapping
    @ResponseBody
    public String queryAll() {
        List<UserInfo> userInfoList = userInfoService.queryAll();
        return JSON.toJSONString(userInfoList);
    } 
    
    @GetMapping(" /{id}")
    @ResponseBody
    public String query(@PathVariable(value = "id") Integer id) {
        UserInfo userInfo = userInfoService.queryById(id);
        List<UserInfo> userInfoList = new ArrayList<>();
        userInfoList.add(userInfo);
        return JSON.toJSONString(userInfoList);
    }
    
    // 这个如果按照RESTful的风格创建不应该加上这个请求路径的,但是为了后面的学习,我们还是给他加上
    @PostMapping("/post/add")
    @ResponseBody
    public String add(@RequestBody UserInfo userInfo) {
        System.out.println("此请求没有经过拦截器");
        userInfoService.add(userInfo);
        return "添加OK";
    }
 
    @DeleteMapping(value = "/delete/{id}")
    @ResponseBody
    public String delete(@PathVariable("id") Integer id) {
        userInfoService.delete(id);
        return "删除成功";
    }
 
    @PutMapping("/update/{id}")
    @ResponseBody
    public String update(@PathVariable("id") Integer id, @RequestBody UserInfo userInfo) {
        userInfo.setId(id);
        userInfoService.update(userInfo);
        return "修改成功";
    }
}

实操

项目创建完成,我们正式开始我们的拦截器学习

新建一个拦截器类在对应的包下(可以创建一个拦截器的包)

自定义拦截器我们需要实现 HandlerInterceptor 接口 ,或者继承 HandlerInterceptorAdapter 类

然后我们对 相关接口或者类中的方法进行 实现或是重写

基于接口的

public class ProjectRequestInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return HandlerInterceptor.super.preHandle(request, response, handler);
    }

    @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);
    }
}

基于类的

public class ProjectRequestInterceptor extends HandlerInterceptorAdapter {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return super.preHandle(request, response, handler);
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        super.afterCompletion(request, response, handler, ex);
    }
}

这里我采用类的方式对其进行学习

再每个方法里面输出对应的语句,便于我们运行的时候进行区分

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    System.out.println("preHandle");
    return super.preHandle(request, response, handler);
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    System.out.println("postHandle");
    super.postHandle(request, response, handler, modelAndView);
}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    System.out.println("afterCompletion");
    super.afterCompletion(request, response, handler, ex);
}

这里只是编写了一个拦截器,具体的拦截器使用我们在一个新的配置文件中进行配置

新建一个配置类在 config包下,这个配置类需要实现 webMvcConfigurer 接口

@Configuration
public class SpringMVCConfig implements WebMvcConfigurer {
    // 在配置类里我们把刚刚写的拦截器 放入Spring容器当中
    // ProjectRequestInterceptor 是我刚刚创建的拦截器的文件名
    @Bean
    public ProjectRequestInterceptor projectRequestInterceptor() {
        return new ProjectRequestInterceptor();
    }
    
    // 在 webMvcConfigurer接口中存在很多个方法,我们目前仅仅 实现 addInterceptors 方法
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 参数为我们刚刚创建的拦截器对象
        registry.addInterceptor(projectRequestInterceptor())
                // 这行代码代表 所有的请求,都需要进入 对应的拦截器当中执行对应的逻辑
                .addPathPatterns("/**")
                // 这行代码代表 这个请求不经过拦截器
                .excludePathPatterns("/test/post/add");
        WebMvcConfigurer.super.addInterceptors(registry);    
    }
}

下面我们在刚刚创建的拦截器中打上断点,并在对应请求上加上一个断点

发送请求

我们发现,这个请求首先走到了 preHandle 这个方法

放开第一个断点,才走到了我们请求对应的controller上。继续放开断点

走到了 postHandle ,再次放开断点,走到了 afterCompletion

控制台的输出顺序也是

并且postMan也是可以获得数据的。

因此我们可以的出 ,在拦截器当中这几个方法的执行顺序是 preHandle --> postHandle --> afterCompletion

并且我们注意到 preHandle 这个方法是有返回值的,我们可以尝试下在这个方法中直接返回 false 是什么情况

重启项目,再次发送请求

我们发现,这个请求仍然是首先执行 preHandle 接口,我们放开这个断点,发现请求停止了。且postMan并没有返回相关数据。

我们刚才还特意配置了一个post/add 接口,来让我们看下有什么样的效果(记得在对应的controller上打上断点)

发送请求,我们发现他并没有走到 拦截器中的 preHandle 方法中

因此我们可以得出,preHandle这段代码决定了 配置了被拦截的路径请求 是否继续向下运行。

那么我们可以使用拦截器做些什么呢?

下面我们改造一下 preHandle中的代码。

再次发送get请求,发现不能成功走到正确的 controller中

让我们修改一下 相关的请求

再次发送请求发现可以正确的发送请求

由此我们可以对一些接口进行加签的设置,例如访问一些接口需要一些特定的参数,以此来防止被恶意访问或者说限制一些人对此接口进行调用。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值