项目中统一处理请求中的字符串参数的空格

测试controller

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

    @GetMapping("/testStringParamTrim")
    public TestObjectInfo testStringParamTrim(@RequestParam String goodsId, String goodsName) {
        return new TestObjectInfo().setGoodsId(goodsId).setGoodsName(goodsName);
    }

    @GetMapping("/testObjectTrim")
    public TestObjectInfo testObjectTrim(TestObjectInfo objectInfo) {
        return objectInfo;
    }

    @PostMapping("/testBodyObjectTrim")
    public TestObjectInfo testBodyObjectTrim(@RequestBody TestObjectInfo objectInfo) {
        return objectInfo;
    }

    @Data
    @Accessors(chain = true)
    public static class TestObjectInfo {
        private String goodsId;
        private String goodsName;
    }
}

测试去除 GET请求参数 和 POST请求体 的属性值的前后空格。

处理请求参数

@Configuration
public class WebConfig {

    @Autowired
    public void setWebBindingInitializer(RequestMappingHandlerAdapter requestMappingHandlerAdapter) {
        WebBindingInitializer webBindingInitializer = requestMappingHandlerAdapter.getWebBindingInitializer();
        if (webBindingInitializer instanceof ConfigurableWebBindingInitializer) {
            //添加属性编辑器注册器,注册String类型的属性编辑器
            PropertyEditorRegistrar[] propertyEditorRegistrars = ((ConfigurableWebBindingInitializer) webBindingInitializer).getPropertyEditorRegistrars();
            if (Objects.isNull(propertyEditorRegistrars)) {
                propertyEditorRegistrars = new PropertyEditorRegistrar[0];
            }
            int originalLen = propertyEditorRegistrars.length;
            propertyEditorRegistrars = Arrays.copyOf(propertyEditorRegistrars, originalLen + 1);
            propertyEditorRegistrars[originalLen] = new CustomPropertyEditorRegistrar();
            ((ConfigurableWebBindingInitializer) webBindingInitializer).setPropertyEditorRegistrars(propertyEditorRegistrars);
        }
    }

    public static class CustomPropertyEditorRegistrar implements PropertyEditorRegistrar {

        @Override
        public void registerCustomEditors(PropertyEditorRegistry registry) {
            registry.registerCustomEditor(String.class, new StringTrimmerEditor(false));
        }
    }

}

通过扩展 SpringMVC 中的 PropertyEditorRegistrar 来实现,这种方式可以实现将请求参数中的字符串参数都去除前后空格,但有一定的隐患,不确定是否会影响项目中 Spring 的其他使用场景。

处理请求体

@Component
public class CustomerJackson2ObjectMapperBuilderCustomizer implements Jackson2ObjectMapperBuilderCustomizer {
    @Override
    public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) {
        jacksonObjectMapperBuilder.deserializerByType(String.class, new JsonDeserializer<String>() {
            @Override
            public String deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
                String value = jsonParser.getValueAsString();
                if (Objects.nonNull(value)) {
                    return value.trim();
                }
                return value;
            }
        });
    }
}

这种方式通过 自定义 jackson 反序列化字符串时的逻辑,来去除前后空格,但限制了 jackson,不支持 fastjson 或者其他 json 框架且影响项目中其他的序列化场景。

更好的方式

@Configuration
public class WebConfig {

    @Bean
    public FilterRegistrationBean<ParamsFilter> paramsFilter() {
        FilterRegistrationBean<ParamsFilter> registration = new FilterRegistrationBean();
        registration.setFilter(new ParamsFilter());
        registration.addUrlPatterns("/*");
        registration.setName("paramsFilter");
        return registration;
    }

    public static class ParamsFilter extends OncePerRequestFilter {

        @Override
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
            ParameterRequestWrapper paramRequest = new ParameterRequestWrapper(request);
            filterChain.doFilter(paramRequest, response);
        }
    }

    @Slf4j
    public static class ParameterRequestWrapper extends HttpServletRequestWrapper {

        private final Map<String, String[]> params = new HashMap<>();

        public ParameterRequestWrapper(HttpServletRequest request) {
            // 将request交给父类,以便于调用对应方法的时候,将其输出,其实父亲类的实现方式和第一种new的方式类似
            super(request);
            //将参数表,赋予给当前的Map以便于持有request中的参数
            Map<String, String[]> requestMap = request.getParameterMap();
            this.params.putAll(requestMap);
            log.info("转化前请求参数:{}", JSON.toJSONString(params));
            this.modifyParameterValues();
            log.info("转化后请求参数:{}", JSON.toJSONString(params));
        }

        /**
         * 重写getInputStream方法  post类型的请求参数必须通过流才能获取到值
         */
        @Override
        public ServletInputStream getInputStream() throws IOException {
            //非json类型,直接返回
            String contentType = super.getHeader(HttpHeaders.CONTENT_TYPE);
            if (StringUtils.isEmpty(contentType) || !contentType.startsWith(MediaType.APPLICATION_JSON_VALUE)) {
                return super.getInputStream();
            }
            String json = IOUtils.toString(super.getInputStream(), StandardCharsets.UTF_8);
            log.info("转化前请求体:{}", json);
            Map<String, Object> map = StringJsonUtils.jsonStringToMap(json);
            log.info("转化后请求体:{}", JSON.toJSONString(map));
            ByteArrayInputStream bis = new ByteArrayInputStream(JSON.toJSONString(map).getBytes(StandardCharsets.UTF_8));
            return new MyServletInputStream(bis);
        }

        /**
         * 将parameter的值去除空格后重写回去
         */
        private void modifyParameterValues() {
            Map<String, String[]> newParams = new HashMap<>();
            for (Map.Entry<String, String[]> entry : params.entrySet()) {
                String key = entry.getKey();
                String[] values = entry.getValue();
                if (Objects.nonNull(values) && values.length > 0) {
                    values[0] = values[0].trim();
                }
                newParams.put(key, values);
            }
            params.putAll(newParams);
        }

        /**
         * 重写getParameter 参数从当前类中的map获取
         */
        @Override
        public String getParameter(String name) {
            String[] values = params.get(name);
            if (Objects.nonNull(values) && values.length > 0) {
                return values[0];
            }
            return null;
        }

        /**
         * 重写getParameterValues
         */
        @Override
        public String[] getParameterValues(String name) {//同上
            return params.get(name);
        }

        public static class MyServletInputStream extends ServletInputStream {
            private ByteArrayInputStream bis;

            public MyServletInputStream(ByteArrayInputStream bis) {
                this.bis = bis;
            }

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

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

            @Override
            public void setReadListener(ReadListener listener) {

            }

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

    }
}
public class StringJsonUtils {

    /**
     * jsonstring 转换成map,并去除字符串值的前后空字符串--支持嵌套 k-v v=list
     *
     * @param jsonString 必须是 {}对象
     * @return
     */
    public static Map<String, Object> jsonStringToMap(String jsonString) {
        Map<String, Object> map = JSON.parseObject(jsonString);
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            Object value = entry.getValue();
            if (Objects.isNull(value)) {
                continue;
            }
            if (value instanceof String) {
                entry.setValue(((String) value).trim());
            } else if (value instanceof Map) {
                Map<String, Object> stringObjectMap = jsonStringToMap(JSON.toJSONString(value));
                entry.setValue(stringObjectMap);
            } else if (value instanceof List) {
                List<Object> stringObjects = stringListTrim(JSON.toJSONString(value));
                entry.setValue(stringObjects);
            }
        }
        return map;
    }

    /**
     * List中的字符串去除空格
     *
     * @param jsonString
     */
    private static List<Object> stringListTrim(String jsonString) {
        JSONArray objects = JSONArray.parseArray(jsonString);
        List<Object> newObjects = new ArrayList<>();
        for (Object object : objects) {
            if (Objects.isNull(object)) {
                continue;
            }
            if (object instanceof String) {
                newObjects.add(((String) object).trim());
            } else if (object instanceof Map) {
                Map<String, Object> stringObjectMap = jsonStringToMap(JSON.toJSONString(object));
                newObjects.add(stringObjectMap);
            } else if (object instanceof List) {
                List<Object> stringObjects = stringListTrim(JSON.toJSONString(object));
                newObjects.add(stringObjects);
            } else {
                newObjects.add(object);
            }
        }
        return newObjects;
    }

}

通过一个 过滤器,来统一处理请求参数和请求体,且不耦合 Spring 及 具体的 json 框架。

posted @ 2024-04-14 13:11  strongmore  阅读(165)  评论(0编辑  收藏  举报