大家好!今天我要带大家见识一个SpringBoot的隐藏技能——如何让接口接收的参数像变魔术一样,自动把数据库风格的user_name转换成Java风格的userName!是不是光听就觉得很酷?那就让我们开始这场编程界的"变形记"吧!

一、问题背景:程序员的痛

作为后端开发者,我们经常遇到这样的场景:

  • 数据库字段:user_namecreate_time
  • Java实体类:userNamecreateTime

每次手动转换都让人头大,特别是当参数很多的时候...(扶额)难道就没有优雅的解决方案吗?

二、解决方案:自定义ServletRequestDataBinder

SpringMVC中的ServletRequestDataBinder就是处理请求参数绑定的幕后英雄!我们可以自定义它来实现自动转换。

1.转换配置

public class SnakeToCamelRequestDataBinder extends ServletRequestDataBinder {

    private final Pattern underLinePattern = Pattern.compile("_(\\w)");

    public SnakeToCamelRequestDataBinder(Object target) {
        super(target);
    }

    @Override
    protected void addBindValues(MutablePropertyValues mpv, ServletRequest request) {
        List<PropertyValue> pvs = mpv.getPropertyValueList();
        List<PropertyValue> adds = new LinkedList<>();
        for (PropertyValue pv : pvs) {
            String name = pv.getName();
            String camel = this.underLineToCamel(name);
            if (!name.equals(camel)) {
                adds.add(new PropertyValue(camel, pv.getValue()));
            }
        }
        pvs.addAll(adds);
    }

    /**
     * 下划线转驼峰方法
     * @param value 要转换的下划线字符串
     * @return 驼峰体字符串
     */
    private String underLineToCamel(final String value) {
        if(!value.contains("_")) return value;
        final StringBuffer sb = new StringBuffer();
        Matcher m = this.underLinePattern.matcher(value);
        while (m.find()){
            m.appendReplacement(sb, m.group(1).toUpperCase());
        }
        m.appendTail(sb);
        return sb.toString();
    }
}
public class SnakeToCamelAttributeProcessor extends ServletModelAttributeMethodProcessor {

    public SnakeToCamelAttributeProcessor(boolean annotationNotRequired) {
        super(annotationNotRequired);
    }

    /**
     * 请求参数的对象需要新增 UTCModelAttribute 注解 才能生效
     *
     * @param parameter 参数
     * @return boolean
     */
    @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);
        Assert.state(servletRequest != null, "No ServletRequest");
        ServletRequestDataBinder servletBinder = (ServletRequestDataBinder) binder;
        new SnakeToCamelRequestDataBinder(servletBinder.getTarget()).bind(servletRequest);
    }
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SnakeToCamel {
    @AliasFor("name")
    String value() default "";

    @AliasFor("value")
    String name() default "";

    boolean binding() default true;
}

2.添加web mvc 配置

@Configuration
public class AppWebMvcConfig implements WebMvcConfigurer {
    /**
     * 添加参数解析器
     *
     * @param resolvers 解析 器
     */
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(new SnakeToCamelAttributeProcessor(true));
    }
}
public class UserDTO {
    private String userName;  
    private Integer userAge;  
    private String createTime; 
    
    // getters and setters...
}
 @PostMapping("/user")
    public String createUser(@SnakeToCamel UserDTO user) {
        // 这里直接使用驼峰命名的属性,无需手动转换
        System.out.println("Received user: " + user.getUserName());
        return "Success! User name is: " + user.getUserName();
    }

3.前端请求

// 前端发送的JSON(数据库风格命名)
fetch('/user', {
    method: 'GET',
    body: JSON.stringify({
        user_name: "张三",
        user_age: 25,
        create_time: "2023-01-01"
    })
})

 

三、总结:优雅的编程艺术

通过以上方法,我们实现了:

1.自动转换:请求参数自动从下划线转驼峰

2.零侵入:业务代码完全不需要关心命名风格差异

3.高性能:只在必要时进行转换,不影响性能

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐