系列十一、拦截器(二)#案例演示

一、案例演示

说明:如下案例通过springboot的方式演示拦截器是如何使用的,以获取Controller中的请求参数为切入点进行演示

1.1、前置准备工作

1.1.1、pom

<dependencies>
	<!-- spring-boot -->
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-devtools</artifactId>
		<scope>runtime</scope>
		<optional>true</optional>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
	</dependency>

	<!-- 工具 -->
	<dependency>
		<groupId>org.projectlombok</groupId>
		<artifactId>lombok</artifactId>
		<optional>true</optional>
	</dependency>
	<dependency>
		<groupId>com.alibaba</groupId>
		<artifactId>fastjson</artifactId>
		<version>1.2.76</version>
	</dependency>
	<dependency>
		<groupId>commons-beanutils</groupId>
		<artifactId>commons-beanutils</artifactId>
		<version>1.9.3</version>
	</dependency>
	<dependency>
		<groupId>org.apache.httpcomponents</groupId>
		<artifactId>httpclient</artifactId>
		<version>4.5.6</version>
	</dependency>
	<dependency>
		<groupId>org.apache.commons</groupId>
		<artifactId>commons-lang3</artifactId>
		<version>3.4</version>
	</dependency>
	<dependency>
		<groupId>org.apache.commons</groupId>
		<artifactId>commons-collections4</artifactId>
		<version>4.3</version>
	</dependency>

	<!-- servlet -->
	<dependency>
		<groupId>javax.servlet</groupId>
		<artifactId>javax.servlet-api</artifactId>
		<version>3.1.0</version>
		<scope>provided</scope>
	</dependency>

</dependencies>

1.1.2、WebRequestConstant

/**
 * @Author : 一叶浮萍归大海
 * @Date: 2023/11/5 11:39
 * @Description:
 */
public class WebRequestConstant {

    /**
     * 请求方法:POST
     */
    public static final String METHOD_TYPE_POST = "POST";

    /**
     * 数据类型:application/json
     */
    public static final String CONTENT_TYPE_APPLICATION_JSON = "application/json";

    /**
     * 字符解码
     */
    public static final String CHARACTER_U = "%u";

}

1.1.3、EncodeUtil 

/**
 * @Author : 一叶浮萍归大海
 * @Date: 2023/11/5 11:12
 * @Description:
 */
public class EncodeUtil {
    private static final String DEFAULT_URL_ENCODING = "UTF-8";
    private static final char[] BASE62 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray();

    /**
     * Hex编码.
     */
    public static String encodeHex(byte[] input) {
        return Hex.encodeHexString(input);
    }

    /**
     * Hex解码.
     */
    public static byte[] decodeHex(String input) {
        try {
            return Hex.decodeHex(input.toCharArray());
        } catch (DecoderException e) {
            return null;
        }
    }

    /**
     * Base64编码.
     */
    public static String encodeBase64(byte[] input) {
        return Base64.encodeBase64String(input);
    }

    /**
     * Base64编码, URL安全(将Base64中的URL非法字符'+'和'/'转为'-'和'_', 见RFC3548).
     */
    public static String encodeUrlSafeBase64(byte[] input) {
        return Base64.encodeBase64URLSafeString(input);
    }

    /**
     * Base64解码.
     */
    public static byte[] decodeBase64(String input) {
        return Base64.decodeBase64(input);
    }

    /**
     * Base62编码。
     */
    public static String encodeBase62(byte[] input) {
        char[] chars = new char[input.length];
        for (int i = 0; i < input.length; i++) {
            chars[i] = BASE62[(input[i] & 0xFF) % BASE62.length];
        }
        return new String(chars);
    }
    /**
     * Html 转码.
     */
    public static String escapeHtml(String html) {
        return StringEscapeUtils.escapeHtml4(html);
    }
    /**
     * Html 解码.
     */
    public static String unescapeHtml(String htmlEscaped) {
        return StringEscapeUtils.unescapeHtml4(htmlEscaped);
    }
    /**
     * Xml 转码.
     */
    public static String escapeXml(String xml) {
        return StringEscapeUtils.escapeXml(xml);
    }
    /**
     * Xml 解码.
     */
    public static String unescapeXml(String xmlEscaped) {
        return StringEscapeUtils.unescapeXml(xmlEscaped);
    }
    /**
     * URL 编码, Encode默认为UTF-8.
     */
    public static String urlEncode(String part) {
        try {
            return URLEncoder.encode(part, DEFAULT_URL_ENCODING);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * URL 解码, Encode默认为UTF-8.
     */
    public static String urlDecode(String part) {
        try {
            return URLDecoder.decode(part, DEFAULT_URL_ENCODING);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }
    }
}

1.1.4、StreamUtil

/**
 * @Author : 一叶浮萍归大海
 * @Date: 2023/11/5 1:15
 * @Description:
 */
public class StreamUtil {

    public static String getRequestBody(InputStream inputStream) {
        String line = "";
        StringBuilder body = new StringBuilder();
        int counter = 0;

        // 读取POST提交的数据内容
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        try {
            while ((line = reader.readLine()) != null) {
                if (counter > 0) {
                    body.append("rn");
                }
                body.append(line);
                counter++;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return body.toString();
    }

    public static HashMap<String, String[]> parseQueryString(String source) {
        String[] valueArray = null;
        if (source == null) {
            throw new IllegalArgumentException();
        }
        HashMap<String, String[]> hashMap = new HashMap<String, String[]>(16);
        StringTokenizer st = new StringTokenizer(source, "&");
        while (st.hasMoreTokens()) {
            String pair = (String) st.nextToken();
            int pos = pair.indexOf('=');
            if (pos == -1) {
                continue;
            }
            String key = pair.substring(0, pos);
            String val = pair.substring(pos + 1, pair.length());
            if (hashMap.containsKey(key)) {
                String[] oldValues = (String[]) hashMap.get(key);
                valueArray = new String[oldValues.length + 1];
                for (int i = 0; i < oldValues.length; i++) {
                    valueArray[i] = oldValues[i];
                }
                valueArray[oldValues.length] = decodeValue(val);
            } else {
                valueArray = new String[1];
                valueArray[0] = decodeValue(val);
            }
            hashMap.put(key, valueArray);
        }
        return hashMap;
    }

    /**
     * 自定义解码函数
     *
     * @param value
     * @return
     */
    private static String decodeValue(String value) {
        if (value.contains(WebRequestConstant.CHARACTER_U)) {
            return EncodeUtil.urlDecode(value);
        } else {
            try {
                return URLDecoder.decode(value, "UTF-8");
            } catch (UnsupportedEncodingException e) {
                // 非UTF-8编码
                return "";
            }
        }
    }

    public static ServletInputStream getServletInputStream(ByteArrayInputStream bais) {
        return new ServletInputStream() {

            @Override
            public int read() throws IOException {
                return bais.read();
            }

            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener arg0) {

            }
        };
    }

    public static byte[] readBytes(InputStream in) throws IOException {
        BufferedInputStream bufin = new BufferedInputStream(in);
        int buffSize = 1024;
        ByteArrayOutputStream out = new ByteArrayOutputStream(buffSize);

        byte[] temp = new byte[buffSize];
        int size = 0;
        while ((size = bufin.read(temp)) != -1) {
            out.write(temp, 0, size);
        }
        bufin.close();

        byte[] content = out.toByteArray();
        return content;
    }

}

1.1.5、MyHttpServletRequestWrapper

/**
 * @Author : 一叶浮萍归大海
 * @Date: 2023/11/4 20:50
 * @Description:
 */
@Getter
@Setter
public class MyHttpServletRequestWrapper extends HttpServletRequestWrapper {
    /**
     * 用于保存读取到的body中的数据
     */
    private byte[] body;
    private Map<String, String[]> paramsMap;

    @Override
    public Map getParameterMap() {
        return paramsMap;
    }

    @Override
    public String getParameter(String name) {
        String[] values = paramsMap.get(name);
        if (values == null || values.length == 0) {
            return null;
        }
        return values[0];
    }

    @Override
    public String[] getParameterValues(String name) {
        return paramsMap.get(name);
    }

    @Override
    public Enumeration getParameterNames() {
        return Collections.enumeration(paramsMap.keySet());
    }

    private HashMap<String, String[]> getParamMapFromPost(HttpServletRequest request) {

        String body = "";
        try {
            body = StreamUtil.getRequestBody(request.getInputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
        HashMap<String, String[]> result = new HashMap<String, String[]>(16);

        if (null == body || 0 == body.length()) {
            return result;
        }

        return StreamUtil.parseQueryString(body);
    }


    private Map<String, String[]> getParamMapFromGet(HttpServletRequest request) {
        return StreamUtil.parseQueryString(request.getQueryString());
    }

    public String getBody(){
        return new String(body);
    }

    public MyHttpServletRequestWrapper(HttpServletRequest request) throws Exception {
        super(request);
        body = StreamUtil.readBytes(request.getInputStream());
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        final ByteArrayInputStream bais = new ByteArrayInputStream(body);
        return StreamUtil.getServletInputStream(bais);
    }

}

1.1.6、UserDTO

@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class UserDTO implements Serializable {

    /**
     * 用户名
     */
    private String username;

    /**
     * 密码
     */
    private String password;

}

二、创建过滤器

2.1、MyFilter

/**
 * @Author : 一叶浮萍归大海
 * @Date: 2023/11/4 20:37
 * @Description:
 */
@Slf4j
@Component
@WebFilter(urlPatterns = "/*", filterName = "channelFilter")
public class MyFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("============= MyFilter init =============");
    }

    /**
     *      普通的参数可以通过request.getParameterMap中获取,而Controller层被@RequestBody修饰的参数需要从request的InputStream中获取,
     * 但是由于InputStream只能读取一次,如果过滤器读取了参数,那么后面的拦截器和Controller层就读取不到参数了,所以这类参数需要单独获取,可以把
     * request封装一下,copy一份request,一个用于在拦截器(过滤器)中读取参数,一个放行给Controller使用
     * 
     * @param request
     * @param response
     * @param chain
     * @throws ServletException
     * @throws IOException
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
        ServletRequest requestWrapper = null;
        String param = "";
        if (request instanceof HttpServletRequest) {
            HttpServletRequest httpServletRequest = (HttpServletRequest) request;
            String method = httpServletRequest.getMethod().toUpperCase();
            String type = httpServletRequest.getContentType();
            if (WebRequestConstant.METHOD_TYPE_POST.equals(method) && WebRequestConstant.CONTENT_TYPE_APPLICATION_JSON.equalsIgnoreCase(type)) {
                try {
                    requestWrapper = new MyHttpServletRequestWrapper((HttpServletRequest) request);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }

        if (requestWrapper == null) {
            Map<String, String[]> originRequestMap = request.getParameterMap();
            Map<String, String> requestMap = new HashMap<String, String>(16);
            for (String key : originRequestMap.keySet()) {
                String[] values = originRequestMap.get(key);
                requestMap.put(key, values[0]);
            }
            param = JSON.toJSONString(requestMap);
        } else {
            param = ((MyHttpServletRequestWrapper) requestWrapper).getBody();
        }
        log.info("过滤器param:{}", param);
        //放行
        if (requestWrapper == null) {
            chain.doFilter(request, response);
        } else {
            chain.doFilter(requestWrapper, response);
        }
    }

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

}

三、拦截器

3.1、创建拦截器

/**
 * @Author : 一叶浮萍归大海
 * @Date: 2023/11/4 18:29
 * @Description: 自定义的登录拦截器
 */
@Slf4j
@Component
public class MyLoginHandlerInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse response, Object handler) throws Exception {
        log.info("============= MyLoginHandlerInterceptor preHandle =============");
        try {

            String requestUrl = httpServletRequest.getRequestURI();
            ServletRequest requestWrapper = null;
            String param = "";
            String method = httpServletRequest.getMethod().toUpperCase();
            String type = httpServletRequest.getContentType();
            if (WebRequestConstant.METHOD_TYPE_POST.equals(method) && WebRequestConstant.CONTENT_TYPE_APPLICATION_JSON.equalsIgnoreCase(type)) {
                requestWrapper = new MyHttpServletRequestWrapper(httpServletRequest);
            }

            if (requestWrapper == null) {
                Map<String, String[]> originRequestMap = httpServletRequest.getParameterMap();
                Map<String, String> requestMap = new HashMap<String, String>(16);
                for (String key : originRequestMap.keySet()) {
                    String[] values = originRequestMap.get(key);
                    requestMap.put(key, values[0]);
                }
                param = JSON.toJSONString(requestMap);
            } else {
                param = ((MyHttpServletRequestWrapper) requestWrapper).getBody();
            }
            log.info("拦截器param:{}", param);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("============= MyLoginHandlerInterceptor postHandle =============");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("============= MyLoginHandlerInterceptor afterCompletion =============");
    }
}

3.2、注册拦截器

/**
 * @Author : 一叶浮萍归大海
 * @Date: 2023/11/4 18:37
 * @Description:
 */
@Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer {

    /**
     * 引入自定义的拦截器对象
     */
    @Resource
    private MyLoginHandlerInterceptor loginHandlerInterceptor;

    /**
     * 注册拦截器
     * @param registry
     *      addPathPatterns("/**"):拦截所有
     *      excludePathPatterns("/business/*"):放行以/business打头的请求
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginHandlerInterceptor).addPathPatterns("/**").excludePathPatterns("/business/*").order(1);
        // registry.addInterceptor(loginHandlerInterceptor).addPathPatterns("/**");
    }
}

四、使用拦截器(案例)

4.1、获取Controller层@RequestBody中的对象参数

4.1.1、LoginController#login()

@PostMapping("/login")
public String login(@RequestBody UserDTO param) {
    log.info("LoginController login param:{}", param);
    return "OK";
}

4.1.2、测试

4.2、获取Controller层普通的对象参数

4.2.1、LoginController#login2()

@PostMapping("/login2")
public String login2(UserDTO param) {
    log.info("LoginController login2 param:{}", param);
    return "OK";
}

4.2.2、测试#form-data

4.2.3、测试#x-www-form-urlencoded

4.3、获取Controller层字符串参数

4.3.1、LoginController#login3()

@GetMapping("/login3")
public String login3(String username,String password) {
    log.info("LoginController login3 param username:{},password:{}", username,password);
    return "OK";
}

4.3.2、测试

五、参考

https://blog.csdn.net/w_t_y_y/article/details/103407841

https://blog.csdn.net/weixin_45100881/article/details/128660421

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/117546.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用JMeter进行接口压力测试

1.我首先创建一个线程组 2.创建好之后如图所示 3. 进行配置 4. 然后添加一个https请求 5.创建好之后设置请求方法和对应参数 6.设置表格监听器 7.创建好之后如图所示 8.保存jmx文件后点击运行进行测试&#xff0c;结果反馈如下图

【大数据】常见的数据抽取方法

常见的数据抽取方法 1.基于查询式的数据抽取1.1 触发器方式&#xff08;又称快照式&#xff09;1.2 增量字段方式1.3 时间戳方式1.4 全表删除插入方式 2.基于日志的数据抽取 数据抽取 是指从源数据源系统抽取需要的数据。实际应用中&#xff0c;数据源较多采用的是关系数据库。…

多目标优化中的“latent action”是什么?

2020 NeurIPS 中的“latent action”&#xff1a; Our model defines latent action as a boundary that splits the region represented by a node into a high-performing and a low performing region. 这里的latent action代表一个边界&#xff08;分类器&#xff09;&…

node教程(五)接口+会话

文章目录 一.接口1.1接口是什么?1.2接口的作用1.3接口的开发与调用1.4接口的组成 一.接口 1.1接口是什么? 接口是前后端通信的桥梁 1.2接口的作用 实现前后端通信 1.3接口的开发与调用 大多数接口都是由后端工程师开发的&#xff0c;开发语言不限 一般情况下接口都是由…

MES 与ERP 什么时候能上

中小制造企业数字化转型升级近几年被炒得如火如荼&#xff0c;各种政策的支持、补贴和会议活动的举办&#xff0c;都在给中小制造企业管理者洗脑&#xff0c;一定要数字化升级&#xff0c;否则就被市场淘汰。 中小制造企业其实是弱势群体&#xff0c;向上需要维护好客户&#…

javaSE学习笔记-未完

目录 前言 一、java基础 1.1概述 1.java语言发展史 2.Java语言版本 3.Java语言平台 4.Java语言特点 5.Java语言跨平台原理-可移植性 6.JRE和JDK的概述 7.JDK的下载和安装 8.JDK安装路径下的目录解释 9.path环境变量的作用及配置方式 10.classpath环境变量的作用及…

二、GRE VPN

GRE VPN 1、GRE介绍2、GRE基本原理3、GRE报文格式4、报文在GRE中传输过程5、价值6、Keepalive检测7、GRE应用8、配置GRE隧道8.1、配置绑定GRE协议的接口8.2、配置Tunnel接口8.3、配置Tunnel路由 9、GRE配置举例9.1、GRE静态路由示例9.1.1、路由器运行动态路由协议实现互通9.1.2…

网络资料(忘传了)

1网络分层模型和应用协议 1.1分层模型 1.1.1分层的意义 当遇到一个复杂问题的时候&#xff0c;可以使用分层的思想把问题简单化 比如&#xff0c;你有半杯82年的可乐&#xff0c;想分享给你的朋友王富贵&#xff0c;但你们已经10年没有联系了。要完成这件事&#xff0c;你可…

Redis-使用java代码操作Redis

目录 一.Java连接上redis 1.导入依赖 二.Java操作redis的常见类型数据存储 1.设置值 ​编辑 2.哈希 1.1设置哈希值 ​编辑 1.2.封装工具类 1.3列表 三redis中的项目应用 一.Java连接上redis redis与Mysql都市数据库&#xff0c;Java操作redis其实跟操作mysql的过程是一…

Selenium —— 网页frame与多窗口处理!

一、多窗口处理. 1.1、多窗口简介 点击某些链接&#xff0c;会重新打开⼀个窗⼜&#xff0c;对于这种情况&#xff0c;想在新页⾯上操作&#xff0c;就 得先切换窗⼜了。 获取窗⼜的唯⼀标识⽤句柄表⽰&#xff0c;所以只需要切换句柄&#xff0c;就可以在多个页⾯灵 活操作了…

基于EPICS stream模块的直流电源的IOC控制程序实例

本实例程序实现了对优利德UDP6720系列直流电源的网络控制和访问&#xff0c;先在此介绍这个项目中使用的硬件&#xff1a; 1、UDP6721直流电源&#xff1a;受控设备 2、moxa串口服务器5150&#xff1a;将UDP6721直流电源设备串口连接转成网络连接 3、香橙派Zero3&#xff1a;运…

【iOS】知乎日报前三周总结

这几天一直在进行知乎日报的仿写&#xff0c;仿写过程中积累了许多实用的开发经验&#xff0c;并对MVC有了更深的了解&#xff0c;特撰此篇作以总结 目录 第一周将网络请求封装在一个单例类Manager中SDWebImage库的简单使用运用时间戳处理当前时间自定义NavigationBar 第二周在…

HarmonyOS(二)—— 初识ArkTS开发语言(中)之ArkTS的由来和演进

前言 在上一篇文章HarmonyOS&#xff08;二&#xff09;—— 初识ArkTS开发语言&#xff08;上&#xff09;之TypeScript入门&#xff0c;我初识了TypeScript相关知识点&#xff0c;也知道ArkTS是华为基于TypeScript发展演化而来。 从最初的基础的逻辑交互能力&#xff0c;到…

VScode配置 github 上传代码

初始化&#xff0c;设置用户名和密码 # 设置你的 Git 用户名 git config --global user.name author# 设置你的 Git 邮箱 git config --global user.email authorgmail.com# 确保 Git 输出带有颜色 git config --global color.ui auto​# 查看 Git 配置 git list1. 初始化本地…

Java8实战-总结46

Java8实战-总结46 CompletableFuture&#xff1a;组合式异步编程让代码免受阻塞之苦使用 CompletableFuture 发起异步请求寻找更好的方案 CompletableFuture&#xff1a;组合式异步编程 让代码免受阻塞之苦 使用 CompletableFuture 发起异步请求 可以使用工厂方法supplyAsyn…

数据包端到端的流程

流程 A给F发送一个数据包的流程&#xff1a; 首先 A&#xff08;192.168.0.1&#xff09;通过子网掩码&#xff08;255.255.255.0&#xff09;计算出自己与 F&#xff08;192.168.2.2&#xff09;并不在同一个子网内&#xff0c;于是决定发送给默认网关&#xff08;192.168.0.…

vue3项目实践

创建 vue3 项目 node本版&#xff1a;node 16.x.x&#xff0c; 脚手架&#xff1a;create-vue 脚手架工具&#xff0c;底层vite 创建vue3项目&#xff1a;npm init vuelatest setup函数 vue3 单文件组件 1、vite.config.js配置文件基于vite的配置 2、template模板不再要求唯…

4 函数的升级-下

重载&#xff08;overload&#xff09; 同一个标识符在不同的上下文有不同的意义 如汉语中“洗”和不同的字搭配后&#xff0c;有不同的含义&#xff0c;play 和不同的单词搭配后有不同的含义。 函数重载&#xff1a;用同一个函数名定义不同的函数&#xff0c;通过不同的参数搭…

c++11中的线程库和包装器

c11 1. 线程库1.1 线程库1.2 锁mutex 2. 包装器2.1 funciton2.2 bind 1. 线程库 1.1 线程库 C11中的线程库提供了一种方便的方式来创建和管理线程。其中&#xff0c;std::thread是一个重要的类&#xff0c;它允许我们创建新线程并控制它们的执行。以下是std::thread的一些重要…

048基于web+springboot的校园资料分享平台

欢迎大家关注&#xff0c;一起好好学习&#xff0c;天天向上 文章目录 一项目简介技术介绍 二、功能组成三、效果图四、 文章目录 一项目简介 本校园资料分享平台有管理员和用户两个角色。管理员功能有个人中心&#xff0c;学生管理&#xff0c;资料分享管理&#xff0c;资源分…