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);
}

相关推荐
卷无止境1 小时前
Python能做嵌入式开发吗?一份写给动手派的生态与硬件全景图
后端·python
疯狂打码的少年6 小时前
【数据库技术】关系模型基本概念(关系/属性/元组/键)
java·服务器·数据库·笔记
Sherotree7 小时前
Google Antigravity——Agent 被提到主界面
前端·ide·后端·edge浏览器
Mr数据杨7 小时前
【Codex】用学生入学评估模块建立新生能力画像
android·java·javascript·django·codex·项目开发
2601_962056238 小时前
Spring Boot 入门 与 无法解析符号 springframework 的解决
java·spring boot·后端
Mr数据杨8 小时前
【Codex】用部门管理模块维护组织架构与管理层级
架构·django·codex·项目开发
Thomas21438 小时前
Java scala 数组 链表
java·链表·scala
亚历克斯神8 小时前
低代码与 AI 的融合趋势——从可视化搭建到自然语言生成应用
java·spring·微服务
你驴我8 小时前
WhatsApp 多账号场景下的会话归档与历史消息检索优化实践
后端·python
Capricorn19888 小时前
个人知识库接入大模型频现“幻觉引用”?排查 RAG 溯源失效问题,解析知芽构建可信第三大脑的底层架构
大数据·论文阅读·人工智能·笔记·架构·论文笔记