Java编程高频的“技术点”-03:“下划线命名”参数,后端用"驼峰命名"接收

在 Spring Boot 中,前端传递下划线命名(如 data_type)的参数,后端使用驼峰命名(如 dataType)接收是非常常见的需求。

具体的处理方式取决于请求方式参数格式

以下是几种主流且优雅的解决方案:

1. JSON 格式请求体的处理方式(最推荐)

方式一:全局配置(一劳永逸)

如果你的请求是 POST/PUT,并且以 JSON 格式(application/json)发送,Spring Boot 默认使用 Jackson 进行反序列化。你有两种方式处理:

  • 全局配置(推荐) :如果整个项目都采用这种风格,可以 在 application.ymlapplication.properties 中进行全局配置。这样所有的 JSON 字段都会自动在下划线和驼峰之间转换:
yaml 复制代码
spring:
  jackson:
    property-naming-strategy: SNAKE_CASE
  • 局部注解 :如果只是个别接口或类需要转换,可以在实体类的字段上添加 @JsonProperty 注解,或者在类级别使用 @JsonNaming 注解:
kotlin 复制代码
import com.fasterxml.jackson.annotation.JsonProperty; // 注意包名不要引错
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
import lombok.Data;<websource>source_group_web_2</websource>

@Data
// 方式2a:类级别统一转换
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) 
public class EventDTO {
    private String id;
    private String name;
    
    // 方式2b:仅针对单个字段指定映射关系
    @JsonProperty("data_type") 
    private Boolean dataType;
}

2. GET 请求或表单提交的处理方式

对于非 JSON 格式的传参,Jackson 的注解会失效。这里提供两种优雅的解决方案:

方式一:自定义过滤器(Filter)

通过包装 Request,在获取参数时自动将驼峰转换为下划线去查找:

scala 复制代码
@Component
public class ParameterNameConverterFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, 
        HttpServletResponse response, 
        FilterChain filterChain) throws ServletException, IOException {
        // 使用自定义的 Wrapper 替换原始 request
        ParameterNameRequestWrapper requestWrapper 
                = new ParameterNameRequestWrapper(request);
        filterChain.doFilter(requestWrapper, response);
    }
}


class ParameterNameRequestWrapper extends HttpServletRequestWrapper {

    public ParameterNameRequestWrapper(HttpServletRequest request) { 
        super(request);
    }
    
    @Override
    public String getParameter(String name) {
        // 优先尝试原名称,若为空则尝试转为下划线查找
        String value = super.getParameter(name);
        if (value == null) {
            // 假设引入了 Hutool 工具包进行转换
            String underlineName = StrUtil.toUnderlineCase(name); 
            return super.getParameter(underlineName);
        }
        return value;
    }
}

方式二:自定义参数解析器(ArgumentResolver)

定义一个专属注解,并在 Spring MVC 配置中注册解析器,实现业务代码零侵入:

java 复制代码
// 1. 定义注解
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface SnakeToCamel {}<websource>source_group_web_4</websource>

// 2. 编写解析器核心逻辑
public class SnakeToCamelAttributeProcessor 
    extends ServletModelAttributeMethodProcessor {

    public SnakeToCamelAttributeProcessor(boolean annotationNotRequired) {
        super(annotationNotRequired);
    }
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(SnakeToCamel.class);
    }
    @Override
    protected void bindRequestParameters(WebDataBinder binder, 
                                    NativeWebRequest request) {
        // 在这里实现下划线到驼峰的绑定逻辑...
        ServletRequest servletRequest
                 = request.getNativeRequest(ServletRequest.class);
        new SnakeToCamelRequestDataBinder(binder.getTarget()).bind(servletRequest);
    }
}

// 3. 注册到 WebMvcConfigurer
@Configuration
public class AppWebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(new SnakeToCamelAttributeProcessor(true));
    }
}

// 4. Controller 中使用
@GetMapping("/event")
public ResponseEntity<?> getEvent(@SnakeToCamel EventDTO eventDTO) {
    return ResponseEntity.ok(eventDTO);
}

3. "笨"办法(手动接收)

如果参数极少且不想做任何额外配置,可以直接在 Controller 方法上逐个声明并映射:

less 复制代码
@GetMapping("/event")
public ResponseEntity<EventDTO> getEvent(

        @RequestParam("id") String id,
        @RequestParam("name") String name,
        @RequestParam("data_type") Boolean dataType) {
    
    // 手动组装 DTO 对象
    EventDTO dto = new EventDTO();
    dto.setId(id);
    dto.setName(name);
    dto.setDataType(dataType);
    
    return ResponseEntity.ok(dto);
}

相关推荐
终将老去的穷苦程序员11 分钟前
基于SpringBoot的餐饮管理系统
java·spring boot·后端
心之伊始12 分钟前
Spring AI Tool Calling 实战:让 Java Agent 调用本地 Bean 工具方法
java·spring boot·agent·spring ai·tool calling
wb0430720114 分钟前
阿明的二次创业——从阿明用 AI 开第二家店,看 AI 原生创业的四阶段方法论
大数据·人工智能·架构
张忠琳14 分钟前
【Go 1.26.4】Golang Map 深度解析
开发语言·后端·golang
AI人工智能+电脑小能手17 分钟前
【大白话说Java面试题 第110题】【并发篇】第10题:CAS 存在哪些问题?
java·开发语言·面试
瀚高PG实验室36 分钟前
java中间件无法连接数据库
java·数据库·中间件·瀚高数据库
东南门吹雪39 分钟前
JAVA TCP socket编程框架
java·高并发·socket·tcp·nio
xingyuzhisuan40 分钟前
缓存命中率提升方案:从 30% 优化至 82% 全流程优化记录
java·开发语言·缓存·ai
一条泥憨鱼1 小时前
Java开发效率神器:Lombok从入门到精通!
java·后端·学习·开发·lombok
Jinkxs1 小时前
Python基础 - 初识内置函数 Python自带的便捷工具
android·java·python