Spring 对请求参数的优雅处方式(重写序列化方法)

Spring 对请求参数的优雅处方式(重写序列化方法)

描述

在我们日常项目开发过程中,往往会遇到前端请求参数中有空格的情况,前端提交后后端的字符串什么形式的都有(例: " xxx ", " xxxxx ", "", "null" 等等),这样不对空格进行处理直接传参,不仅浪费空间,还会造成数据跟查询结果有出入的情况,引起很多不必要的麻烦。那么,怎么快速的去除前端传参中字符串类型参数的前后空格呢?

前端传参方式介绍

在开发过程中,后端接收前端的传参有两种方式:

  1. 使用 url 或者 form 表单进行传参,后端通过 @RequestParam 注解的方式,从 url 中获取参数。
  2. 使用 body 进行传参,后端通过 @RequestBody 注解进行参数的接收。

对于 url 或者 form 表单的方式,我们在参数绑定时注册下面的类即可对参数进行处理

java 复制代码
@RestControllerAdvice
public class GlobalHandler {

    private static final Logger LOGGER = LoggerFactory.getLogger(GlobalHandler.class);

    /**
     *  url和form表单中的参数trim
     * @param binder
     */
    @InitBinder
    public void initBinder(WebDataBinder binder) {
        // 构造方法中 boolean 参数含义为如果是空白字符串, 是否转换为 null
        // 即如果为 true, 那么 "" 会被转换为 null, 否者为""
        binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
    }
}

对于使用 body 中的 JSON 或者 XML 的传参方式,在 Spring 中,默认是使用的 Jackson 对参数进行序列化处理,所以对 Jackson 加入如下的自定义转换器即可实现:

java 复制代码
@Configuration
public class ApplicationConfig {

    /**
     * Request Body中JSON或XML对象参数trim
     *
     * @return
     */
    @Bean
    public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
        return jacksonObjectMapperBuilder -> {
            // 时区问题
            jacksonObjectMapperBuilder.timeZone(TimeZone.getDefault());
            jacksonObjectMapperBuilder.deserializerByType(String.class, new StdScalarDeserializer<String>(String.class) {
                @Override
                public String deserialize(JsonParser jsonParser, DeserializationContext ctx)
                        throws IOException {
                    // 去除前后空格
                    return StringUtils.trimWhitespace(jsonParser.getValueAsString());
                }
            });
        };
    }
}

代码实现:

1、重写序列化方式代码

对于上述的两种传参方式,我们优化一下,将两个合并成一个统一的类来进行实现;

java 复制代码
package com.wblog.framework.config;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdScalarDeserializer;
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.servlet.Servlet;
import java.io.IOException;

/**
 * 序列化处理前端请求数据的前后空格
 * @author wangxk
 * @date 2023-12-27
 */
@Configuration
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
@AutoConfigureAfter(WebMvcAutoConfiguration.class)
public class WebMvcStringTrimAutoConfiguration {

    @ControllerAdvice
    public static class ControllerStringParamTrimConfig {
        /**
         * url和form表单中的参数trim
         */
        @InitBinder
        public void initBinder(WebDataBinder binder) {
            // 构造方法中 boolean 参数含义为如果是空白字符串,是否转换为null
            // 即如果为true,那么 " " 会被转换为 null,否者为 ""
            StringTrimmerEditor stringTrimmerEditor = new StringTrimmerEditor(false);
            binder.registerCustomEditor(String.class, stringTrimmerEditor);
        }
    }

    /**
     * Request Body中JSON或XML对象参数trim
     */
    @Bean
    public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
        return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder
                .deserializerByType(String.class, new StdScalarDeserializer<String>(String.class) {
                    @Override
                    public String deserialize(JsonParser jsonParser, DeserializationContext ctx)
                            throws IOException {
                        System.out.println("Jackson2ObjectMapperBuilderCustomizer jsonParser.getValueAsString() = " + jsonParser.getValueAsString());
                        return StringUtils.trimWhitespace(jsonParser.getValueAsString());
                    }
                });
    }
}

2、设置类自动加载到 Spring 中

由于 Spring 启动时,是默认加载同级别目录下所有的 Bean,如果我们重写的 WebMvcStringTrimAutoConfiguration 类是在外部目录时,我们就需要手动去指定一下需要加载的类,在 resurces 下创建 META-INF/spring.factories 文件,将我们的类加到里面去:

powershell 复制代码
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.wblog.framework.config.WebMvcStringTrimAutoConfiguration

参考链接:

  1. SpringBoot去除字符串类型参数的前后空格
  2. Springmvc请求参数的优雅处方式
相关推荐
Jason-河山2 分钟前
利用 Python 爬虫采集 1688商品详情
java·http
计算机源码社3 分钟前
分享一个餐饮连锁店点餐系统 餐馆食材采购系统Java、python、php三个版本(源码、调试、LW、开题、PPT)
java·python·php·毕业设计项目·计算机课程设计·计算机毕业设计源码·计算机毕业设计选题
Zww08917 分钟前
idea插件市场安装没反应
java·ide·intellij-idea
夜雨翦春韭8 分钟前
【代码随想录Day31】贪心算法Part05
java·数据结构·算法·leetcode·贪心算法
计算机学姐8 分钟前
基于微信小程序的调查问卷管理系统
java·vue.js·spring boot·mysql·微信小程序·小程序·mybatis
problc19 分钟前
Android 组件化利器:WMRouter 与 DRouter 的选择与实践
android·java
程序员南飞2 小时前
ps aux | grep smart_webrtc这条指令代表什么意思
java·linux·ubuntu·webrtc
弥琉撒到我2 小时前
微服务swagger解析部署使用全流程
java·微服务·架构·swagger
一颗花生米。3 小时前
深入理解JavaScript 的原型继承
java·开发语言·javascript·原型模式
问道飞鱼3 小时前
Java基础-单例模式的实现
java·开发语言·单例模式