欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JAVA三種攔截方式詳解(原生過濾器Filter、springMVC攔截器、aop切面)

 更新時(shí)間:2024年05月21日 09:40:30   作者:謙風(fēng)(Java)  
在Java開發(fā)中方法攔截是一種常見的技術(shù),可以用于在方法執(zhí)行前后添加額外的邏輯或修改方法的行為,這篇文章主要給大家介紹了關(guān)于JAVA三種攔截方式的相關(guān)資料,文中介紹的方式分別是原生過濾器Filter、springMVC攔截器、aop切面,需要的朋友可以參考下

最近面試有遇到攔截方式的場(chǎng)景,結(jié)合網(wǎng)上xdm的代碼整理了下,分為以下三種:
java原生過濾器Filter、springMVC攔截器、aop切面

一、java原生過濾器Filter

package com.zhangximing.springbootinterceptor.interceptor;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Enumeration;

/**
 * 自定義Filter
 * 對(duì)請(qǐng)求的header 過濾token
 *
 * 過濾器Filter可以拿到原始的HTTP請(qǐng)求和響應(yīng)的信息,
 *     但是拿不到你真正處理請(qǐng)求方法的信息,也就是方法的信息
 *
 * @Component 注解讓攔截器注入Bean,從而讓攔截器生效
 * @WebFilter 配置攔截規(guī)則
 *
 * 攔截順序:filter—>Interceptor-->ControllerAdvice-->@Aspect -->Controller
 *
 */
@Slf4j
@Component
@WebFilter(urlPatterns = {"/**"},filterName = "authFilter")
public class MyFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("TokenFilter init {}",filterConfig.getFilterName());
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        String param = request.getParameter("param");

        response.setContentType("text/html;charset=UTF-8");

        //獲取請(qǐng)求頭token
        String token = "";
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        Enumeration<String> headerNames = httpServletRequest.getHeaderNames();
        while(headerNames.hasMoreElements()) {//判斷是否還有下一個(gè)元素
            String nextElement = headerNames.nextElement();//獲取headerNames集合中的請(qǐng)求頭
            if ("token".equals(nextElement)){
                token = httpServletRequest.getHeader(nextElement);
                log.info("請(qǐng)求頭key[" + nextElement + "]:" + token);
            }
        }

        log.info("doFilter-我攔截到了請(qǐng)求:"+ param);
        if (null != param && "pass".equals(param)){
            //驗(yàn)證token
            if ("7758258xx".equals(token)){
                chain.doFilter(request,response);//到下一個(gè)鏈
            }else{
                response.getWriter().write("doFilter-請(qǐng)求頭token不通過");
            }
        }else{
            log.info("doFilter-參數(shù)param不符合條件");
            response.getWriter().write("doFilter-參數(shù)param不通過");
        }
    }

    @Override
    public void destroy() {
        log.info("destroy");
    }
}

簡(jiǎn)單測(cè)試直接用的postman,參數(shù)是一個(gè)param和一個(gè)請(qǐng)求頭token:

這里補(bǔ)充一下:

若非springboot的情況下,不使用@WebFilter則需要自己設(shè)置配置文件

你需要在web.xml文件中配置過濾器,指定要攔截的URL以及要使用的過濾器

<filter>
    <filter-name>MyFilter</filter-name>
    <filter-class>com.zhangximing.springbootinterceptor.interceptor.MyFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>MyFilter</filter-name>
    <url-pattern>/example</url-pattern>
</filter-mapping>

二、springMVC攔截器

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;

/**
 * 自定義攔截器
 * 自定義攔截器后,需要配置進(jìn)Spring
 *
 * 攔截器Interceptor可以拿到原始的HTTP請(qǐng)求和響應(yīng)的信息,
 *    也可以拿到你真正處理請(qǐng)求方法的信息,但是拿不到傳進(jìn)參數(shù)的那個(gè)值。
 *
 *攔截順序:filter—>Interceptor-->ControllerAdvice-->@Aspect -->Controller
 */
@Slf4j
@Component
public class MyInterceptor implements HandlerInterceptor {

    /**
     * 在訪問Controller某個(gè)方法之前這個(gè)方法會(huì)被調(diào)用。
     * @param request
     * @param response
     * @param handler
     * @return false則表示不執(zhí)行postHandle方法,true 表示執(zhí)行postHandle方法
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("Interceptor preHandle {}","");
        String token = request.getHeader("token");
        log.info("Interceptor preHandle token :{}",token);
        log.info("Interceptor preHandle uri {}",request.getRequestURL().toString());

        response.setContentType("text/html;charset=UTF-8");

        //spring boot 2.0對(duì)靜態(tài)資源也進(jìn)行了攔截,當(dāng)攔截器攔截到請(qǐng)求之后,
        // 但controller里并沒有對(duì)應(yīng)的請(qǐng)求時(shí),該請(qǐng)求會(huì)被當(dāng)成是對(duì)靜態(tài)資源的請(qǐng)求。
        // 此時(shí)的handler就是 ResourceHttpRequestHandler,就會(huì)拋出上述錯(cuò)誤。
        if (handler instanceof HandlerMethod){
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Method method = handlerMethod.getMethod();
            log.info("Token Interceptor preHandle getMethod {}",method.getName());
        }else if(handler instanceof ResourceHttpRequestHandler){//靜態(tài)資源
            ResourceHttpRequestHandler resourceHttpRequestHandler = (ResourceHttpRequestHandler) handler;
            log.info("Token Interceptor preHandle getMethod {}",resourceHttpRequestHandler.getMediaTypes());
        }

        if (!"7758258xx".equals(token)){
            response.getWriter().write("doInterceptor-請(qǐng)求頭token不通過");
            return false;
        }

        //false則表示不執(zhí)行postHandle方法,不執(zhí)行下一步chain鏈,直接返回response
        return true;
    }

    /**
     * 請(qǐng)求處理之后進(jìn)行調(diào)用,但是在視圖被渲染之前(Controller方法調(diào)用之后)
     * preHandle方法處理之后這個(gè)方法會(huì)被調(diào)用,如果控制器Controller出現(xiàn)了異常,則不會(huì)執(zhí)行此方法
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("Interceptor postHandle");
    }

    /**
     * 不管有沒有異常,這個(gè)afterCompletion都會(huì)被調(diào)用
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("Interceptor afterCompletion");
    }

這里注意下,需要將攔截器配置進(jìn)spring

import com.zhangximing.springbootinterceptor.interceptor.MyInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 *  MyInterceptor 自定義攔截器后,需要配置進(jìn)Spring
 * 也可以mapping,跨域設(shè)置
 */
@Slf4j
@Configuration
public class MyInterceptorConfig implements WebMvcConfigurer {

    @Autowired
    MyInterceptor myInterceptor;

    /**
     * 添加攔截器
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        log.info("addInterceptors tokenInterceptor");
        registry.addInterceptor(myInterceptor)
                .addPathPatterns("/**")//指定該類攔截的url
        .excludePathPatterns( "/static/**");//過濾靜態(tài)資源
    }

    /**
     * 如果實(shí)現(xiàn)了Filter跨域攔截,這個(gè)跨域無效
     * 攔截器實(shí)現(xiàn) 跨域支持
     * @param registry
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        log.info("addInterceptors addCorsMappings");
        registry.addMapping("/**")
                .allowedOriginPatterns("*")  //本人測(cè)試時(shí)springboot2.7版本用的是這個(gè)
                .allowCredentials(true)
                .allowedMethods("GET", "POST", "DELETE", "PUT","OPTIONS","HEAD")
                .allowedHeaders("*")
                .maxAge(3600);
    }
}

測(cè)試同理:

三、aop切面

引入maven:

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

若出現(xiàn)無法解析aspectjweaver則需要手動(dòng)加入其他版本maven解決問題

<dependency>
   <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.4</version>
</dependency>
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;

/**
 * @Author: zhangximing
 * @Email: 530659058@qq.com
 * @Date: 2023/8/18 10:15
 * @Description: 切面
 */
@Slf4j
@Component  //表示它是一個(gè)Spring的組件
@Aspect  //表示它是一個(gè)切面
public class MyAspect {

    private static final Logger logger = LoggerFactory.getLogger(MyAspect.class);

    ThreadLocal<Long> startTime = new ThreadLocal<>();

    /**
     * 第一個(gè)*代表返回類型不限
     * 第二個(gè)*代表所有類
     * 第三個(gè)*代表所有方法
     * (..) 代表參數(shù)不限
     * com.zhangximing.springbootinterceptor.controller 測(cè)試的controller層
     */
    @Pointcut("execution(public * com.zhangximing.springbootinterceptor.controller.*.*(..))")
    public void pointCut(){};

    @Before(value = "pointCut()")
    public void before(JoinPoint joinPoint){
        System.out.println("方法執(zhí)行前執(zhí)行......before");
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        logger.info("<=====================================================");
        logger.info("請(qǐng)求來源: =》" + request.getRemoteAddr());
        logger.info("請(qǐng)求URL:" + request.getRequestURL().toString());
        logger.info("請(qǐng)求方式:" + request.getMethod());
        logger.info("響應(yīng)方法:" + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        logger.info("請(qǐng)求參數(shù):" + Arrays.toString(joinPoint.getArgs()));
        logger.info("連接點(diǎn)的方法簽名對(duì)象:"+joinPoint.getSignature());
        logger.info("連接點(diǎn)所在的目標(biāo)對(duì)象:"+joinPoint.getTarget());
        logger.info("代理對(duì)象:"+joinPoint. getThis());
        logger.info("------------------------------------------------------");
        startTime.set(System.currentTimeMillis());
    }

    // 定義需要匹配的切點(diǎn)表達(dá)式,同時(shí)需要匹配參數(shù)
    /**
     * @description 要攔截修改參數(shù)的值只有使用這個(gè)方法,Around相當(dāng)于before+after
     * @param pjp
     * @param arg 類型可以根據(jù)pointCut指定切點(diǎn)類下的方法確定,也可以使用統(tǒng)一的Object,也可以不寫參數(shù)
     * @return
     * @throws Throwable
     */
    @Around("pointCut() && args(arg)")
    public Object around(ProceedingJoinPoint pjp, Object arg) throws Throwable{
        logger.info("入?yún)ⅲ簕}",arg);
        logger.info("方法環(huán)繞start...around");

        JSONObject param = JSONObject.parseObject(JSONObject.toJSONString(arg));
        if ("zxm".equals(param.getString("name"))){
            JSONObject result = new JSONObject();
            result.put("success",false);
            result.put("msg","error");
            return result;
        }
        param.put("exist",true);
        param.put("name","cml");

        //修改值
        Object[] objects = new Object[]{param};
        Object objectNew = pjp.proceed(objects);

        logger.info("方法環(huán)繞end...around");

        return objectNew;
    }

    @After("within(com.zhangximing.springbootinterceptor.controller.*)")
    public void after(){
        System.out.println("方法之后執(zhí)行...after.");
    }

    /**
     *
     * @param AjaxResult  rst 該參數(shù)類型需要與測(cè)試的Controller層的返回值類型一致,否則不生效,也就是找不到
     *            該測(cè)試中的AjaxResult是測(cè)試項(xiàng)目中封裝好的出參
     */
    @AfterReturning(pointcut="pointCut()",returning = "rst")
    public void afterRunning(JSONObject rst){
        if(startTime.get() == null){
            startTime.set(System.currentTimeMillis());
        }
        System.out.println("方法執(zhí)行完執(zhí)行...afterRunning");
        logger.info("耗時(shí)(毫秒):" +  (System.currentTimeMillis() - startTime.get()));
        logger.info("返回?cái)?shù)據(jù):{}", rst);
        logger.info("==========================================>");
    }

    @AfterThrowing("within(com.zhangximing.springbootinterceptor.controller.*)")
    public void afterThrowing(){
        System.out.println("異常出現(xiàn)之后...afterThrowing");
    }
}

實(shí)現(xiàn)效果用的是如下controller:

@Slf4j
@RestController
@RequestMapping("/test")
public class TestController {

    @RequestMapping("/test1")
    public String test1(@RequestParam(required = false, value = "param") String param){
        log.info("test1:"+param);
        return "test1:"+param;
    }

    @RequestMapping("/test2")
    public JSONObject test2(@RequestBody JSONObject params){
        log.info("test2:"+params.toJSONString());

        params.put("success",true);
        return params;
    }
}

參數(shù)判斷攔截以及參數(shù)修改等方式都可以通過aop切面來實(shí)現(xiàn),這是比較基本的aop攔截實(shí)現(xiàn)

最后關(guān)于aop失效補(bǔ)充下,切面只能對(duì)被spring代理的對(duì)象起作用,目前是針對(duì)的請(qǐng)求入口進(jìn)行攔截,我試了下踩坑,比如說如果要對(duì)service或dao進(jìn)行攔截,可以使用注解注入的方式生效。

總結(jié) 

到此這篇關(guān)于JAVA三種攔截方式(原生過濾器Filter、springMVC攔截器、aop切面)的文章就介紹到這了,更多相關(guān)JAVA攔截方式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java非遞歸實(shí)現(xiàn)之二叉樹的前中后序遍歷詳解

    java非遞歸實(shí)現(xiàn)之二叉樹的前中后序遍歷詳解

    樹的遍歷順序大體分為三種:前序遍歷(先根遍歷、先序遍歷),中序遍歷(中根遍歷),后序遍歷(后根遍歷),本文將給大家詳細(xì)的介紹,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值
    2021-09-09
  • java中springMVC獲取請(qǐng)求參數(shù)的方法

    java中springMVC獲取請(qǐng)求參數(shù)的方法

    這篇文章主要介紹了java中springMVC獲取請(qǐng)求參數(shù)的方法,springmvc是spring框架的一個(gè)模塊,springmvc和spring無需通過中間整合層進(jìn)行整合,需要的朋友可以參考下
    2023-05-05
  • SpringBoot中獲取微信用戶信息的方法

    SpringBoot中獲取微信用戶信息的方法

    這篇文章主要介紹了SpringBoot中獲取微信用戶信息的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • Idea?中控制啟動(dòng)命令的詳細(xì)過程?區(qū)分環(huán)境案例詳解

    Idea?中控制啟動(dòng)命令的詳細(xì)過程?區(qū)分環(huán)境案例詳解

    這篇文章主要介紹了Idea?中控制啟動(dòng)命令的詳細(xì)過程?區(qū)分環(huán)境案例詳解,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-08-08
  • JavaFX如何獲取ListView(列表視圖)的選項(xiàng)

    JavaFX如何獲取ListView(列表視圖)的選項(xiàng)

    這篇文章主要介紹了JavaFX如何獲取ListView(列表視圖)的選項(xiàng),具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • Sharding-JDBC自動(dòng)實(shí)現(xiàn)MySQL讀寫分離的示例代碼

    Sharding-JDBC自動(dòng)實(shí)現(xiàn)MySQL讀寫分離的示例代碼

    本文主要介紹了Sharding-JDBC自動(dòng)實(shí)現(xiàn)MySQL讀寫分離,優(yōu)點(diǎn)在于數(shù)據(jù)源完全有Sharding-JDBC托管,寫操作自動(dòng)執(zhí)行master庫(kù),讀操作自動(dòng)執(zhí)行slave庫(kù),感興趣的可以了解一下
    2021-11-11
  • SpringBoot @PostConstruct原理用法解析

    SpringBoot @PostConstruct原理用法解析

    這篇文章主要介紹了SpringBoot @PostConstruct原理用法解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-08-08
  • 詳解Java如何使用責(zé)任鏈默認(rèn)優(yōu)雅地進(jìn)行參數(shù)校驗(yàn)

    詳解Java如何使用責(zé)任鏈默認(rèn)優(yōu)雅地進(jìn)行參數(shù)校驗(yàn)

    項(xiàng)目中參數(shù)校驗(yàn)十分重要,它可以保護(hù)我們應(yīng)用程序的安全性和合法性。這篇文章主要介紹了如何使用責(zé)任鏈默認(rèn)優(yōu)雅地進(jìn)行參數(shù)校驗(yàn),需要的可以參考一下
    2023-03-03
  • Java使用FutureTask實(shí)現(xiàn)預(yù)加載的示例詳解

    Java使用FutureTask實(shí)現(xiàn)預(yù)加載的示例詳解

    基于FutureTask的特性,通??梢允褂肍utureTask做一些預(yù)加載工作,比如一些時(shí)間較長(zhǎng)的計(jì)算等,本文就來和大家講講具體實(shí)現(xiàn)方法吧,感興趣的可以了解一下
    2023-06-06
  • JAVA中關(guān)于Long類型返回前端精度丟失問題處理辦法

    JAVA中關(guān)于Long類型返回前端精度丟失問題處理辦法

    這篇文章主要介紹了后端JavaBean的id屬性從Long類型改為雪花算法后出現(xiàn)的精度丟失問題,解決方案包括將id字段類型改為字符串或使用Jackson序列化方式,需要的朋友可以參考下
    2024-11-11

最新評(píng)論