Spring Boot 请求包装器的实现

请求包装器
placeholder image
admin 发布于:2022-05-22 21:07:03
阅读:loading

基本介绍

对于请求包装器的定义也许不是很准确,这里所谓的请求包装器是将所有URL的请求参数进行拦截过滤,将参数中的特殊字符进行拦截转换,来提升系统安全与稳定性,想要实现这一目的的方法是多样的但是基于本文所述的实现方式个人认为还是比较优雅的。早在2011年的时候写了一篇Struts2的请求包装器的文章,当时主要的实现是在Struts项目架构下,配合使用JSP的后台渲染开发模式,所有的请求无论是基于Form的表单提交还是使用Ajax请求的交互均是仅使用了GET/POST两种提交方式,所以在请求的包装实现也仅仅是重写request的getParameter、getParameterValues和getParameterMap即可,而本次的博客2.0系统中对于请求包装器的功能同样是不能少,所以在实现的过程中主要拓展的实现除了要在Spring MVC架构下使用以外,还要考虑更多的请求交互方式(PUT/DELETE等),同时要覆盖到Spring MVC的多种参数传值的应用场景。

所以关于请求包装器的理论和实践还是有必要参考前面一篇的具体实现,这么多年来唯一不变的请求包装仍然是对于特殊字符的过滤、对于敏感词的过滤,所以本次实践是在Spring Boot项目架构下的请求包装实现,目的是对于Spring MVC中的多种参数传输方式额过滤要求覆盖到位,所以目前考虑的参数传递方式过滤方式如下:

(1)基于@PathVariable注解的URL路径参数传递;

(2)默认无注解标识的参数传递;

(3)基于@RequestParam注解的请求参数传递;

(4)基于@RequestBody注解的JSON对象的请求参数传递;

(5)基于@RequestBody注解的String字符串的请求参数传递;

(6)原生request.getParameter和request.getParameterValues以及request.getParameterMap参数获取;

先来说一下最终实现的结果吧,基于@PathVariable的参数传值方式直接是在URL层面,个人认为这个路径变量的正确用法应是用于传递ID类的数据(纯数字或者英文字母),并不适合传递其它非ID类的数值,同时由于ID被使用的范围有限,所以本次的实践并未对此路径变量的取值来做参数的包装,其它五个方面的参数包装的实现本篇文章的实例均已经实现,详细参见下文。

特殊字符范围定义

本次是基于纯净项目的简单实现,在案例中只提供了三组特殊字符的参数包装,在当前的博客系统实现时有更加细粒度的实现(可见前文中的介绍),主要是针对特殊字符的包装、对于敏感词汇的包装、对于某些参数的部分包装(富文本编辑器)等,而本次的包装示例特殊字符有:将“我日”转换为“我R”;将“<”转换为“&lt;”;将“>”转换为“>”;即将请求参数中出现的某部分数值替换为对应匹配的参数值即可(请求参数的包装是在过滤器中实现,此时还并未执行对应功能的Controller及Service),例如此处的小于号直接被转换为html转义字符的小于号;大于号则是直接转换成了特殊字符中的大于号;我日被转换成了稍微文明一些的我R;至于其它更多的参数转换可自行实现,在本站系统中除了对敏感词过滤以外还对特殊字符的“<>'"”等几种字符进行了过滤。参考如下代码所示:

public static final Map<String , String> MATCH_WORDS = Maps.newHashMap();

static {
    MATCH_WORDS.put("我日" , "我R");
    MATCH_WORDS.put("<" , "&lt;");
    MATCH_WORDS.put(">" , ">");
}

controller定义

package cn.chendd.modules.wrapper.controller;

import ...;

import java.util.List;

/**
 * http request请求包装器Controller定义
 *
 * @author chendd
 * @date 2022/6/15 20:00
 */
@RestController
@RequestMapping(value = "/wrapper", produces = MediaType.APPLICATION_JSON_VALUE)
@Api(value = "请求参数包装器", tags = {"请求参数包装器解析响应验证"})
public class RequestWrapperController extends BaseController {

    @GetMapping(value = "/request_param")
    @ApiOperation(value = "@RequestParam参数传递", notes = "测试响应结果集(<b>@RequestParam参数传递</b>)",
            consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
    @ApiOperationSupport(order = 10)
    public String requestParam(@ApiParam(name = "name" , value = "名称") @RequestParam String name ,
                               @ApiParam(name = "ids" , value = "ids数组") @RequestParam List<String> ids) {
        StringBuilder paramBuilder = new StringBuilder();
        paramBuilder.append("name = ").append(name).append(",ids = ").append(ids);
        return paramBuilder.toString();
    }

    @PutMapping(value = "request_body")
    @ApiOperation(value = "@RequestBody参数传递", notes = "测试响应结果集(<b>@RequestBody参数传递</b>)",
            consumes = MediaType.APPLICATION_JSON_VALUE)
    @ApiOperationSupport(order = 20)
    public UserBo requestBody(@ApiParam(name = "user" , value = "用户数据对象") @RequestBody UserBo userBo) {
        return userBo;
    }

    @PutMapping(value = "request_body_string")
    @ApiOperation(value = "@RequestBody String参数传递", notes = "测试响应结果集(<b>@RequestBody String参数传递</b>)",
            consumes = MediaType.APPLICATION_JSON_VALUE)
    @ApiOperationSupport(order = 30)
    public String requestBody(@ApiParam(name = "user" , value = "用户数据对象") @RequestBody String bodyString) {
        return bodyString;
    }

    @GetMapping(value = "/request_other/{id}")
    @ApiOperation(value = "Request Other参数传递", notes = "测试响应结果集(<b>@RequestBody参数传递</b>)",
            consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
    @ApiOperationSupport(order = 40)
    public String requestOther(
            @ApiParam(name = "id" , value = "Id数据") @PathVariable String id ,
            @ApiParam(name = "name" , value = "名称") @RequestParam String name ,
            @ApiParam(name = "values" , value = "ids数组") @RequestParam List<String> values) {
        System.out.println("@PathVariable:" + id);
        System.out.println("getParameter:" + request.getParameter("name"));
        System.out.println("getParameterMap:" + JSONObject.toJSONString(request.getParameterMap()));
        return "示例结果需要查看控制台输出";
    }

}

上述代码的定义主要是涵盖了Spring MVC接收参数的时的多种取值实现,均能有效的进行过滤,请注意运行结果的参数输出结果。

运行结果输出

image.png

(@RequestParam参数传递)

image.png

(@RequestBody参数传递)

image.png

(@RequestBody String参数传递)

image.png

image.png

(Request Other参数传递)

源码下载

源码工程下载可转至https://gitee.com/88911006/chendd-blog-examples项目的RequestWrapper分支;

 点赞


 发表评论

当前回复:作者

 评论列表


留言区