AOP应用:驼峰下划线互转

1. 概念

驼峰式参数:{"peopleName": "张三"}

下划线式参数:{"people_name": "张三"}

2. 背景介绍

后端是java服务,使用springboot框架。

原本前后端sonar的规范都要求接口参数是驼峰形式,两端可以直接无压力对接。

但是我们所有的接口都是统一记录到一个接口平台的,这个平台要求使用下划线的格式,不按照规范的话会影响绩效。

所以只能按照下面的方式设计接口

3. 后端实现

假设后端接口入参是:people_name="张三",出参是{"people_name":"张三","people_sex":"男"}

我们实际项目中用了3.2.2介绍的方式将入参转驼峰;使用了3.3介绍的方式将出参转下划线。

3.1. 指定每一个参数具体的参数值

3.1.1. @ReuqestParam指定入参是下划线

接收入参时,接口指定了入参为下划线,下面代码关键是“@ReuqestParam”所以没什么好讲的。

@RestController

public class PeopleController {

     

    @GetMapping("/people/query")

    public Result<People> queryPeople(@RequestParam("people_name") String peopleName) {

        People thePeople = findPeople(peopleName);

        return Result.success(thePeople);

    }

     

}

 

3.1.2. @JsonProperty指定出入参是下划线

如果参数是对象形式的,可以使用这个

public class PeopleQueryParam {

    @JsonProperty("people_name")

    private String peopleName;

}

这个指定每一个参数具体值的方式不太好,因为你需要给每一个参数数据都加上注解。

3.2.  自定义组件实现驼峰下划线互转

具体做法是自定义了一个组件,组件中实现驼峰转下划线的功能

3.2.1. 组件自动配置ReqRespAutoConfiguration

自动配置FilterRegistrationBean<RequestParamFilter>实例,功能是请求入参转驼峰

自动配置ResponseCamelcaseToUnderlineAdvice实例,功能是响应出参转下划线

package com.myhexin.vtuber.reqresp.config;

import com.myhexin.vtuber.reqresp.filter.RequestParamFilter;

import com.myhexin.vtuber.reqresp.globalhandler.GlobalExceptionAdvice;

import com.myhexin.vtuber.reqresp.globalhandler.I18nResponseAdvice;

import com.myhexin.vtuber.reqresp.globalhandler.ResponseCamelcaseToUnderlineAdvice;

import com.myhexin.vtuber.reqresp.i18n.I18nResolveHelper;

import com.myhexin.vtuber.reqresp.i18n.VtuberI18nMessageSource;

import com.myhexin.vtuber.reqresp.i18n.check.I18nMessageIntegrityChecker;

import com.myhexin.vtuber.reqresp.i18n.resolver.ObjectI18nResolver;

import com.myhexin.vtuber.reqresp.interceptor.I18nLocaleInterceptor;

import com.myhexin.vtuber.reqresp.props.I18nProps;

import com.myhexin.vtuber.reqresp.props.ReqRespProps;

import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;

import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;

import org.springframework.boot.context.properties.EnableConfigurationProperties;

import org.springframework.boot.web.servlet.FilterRegistrationBean;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.web.servlet.LocaleResolver;

import org.springframework.web.servlet.config.annotation.InterceptorRegistry;

import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;

import java.util.List;

import java.util.Set;

/**

 * ReqRespAutoConfiguration

 *

 * @author xxx

 */

@Configuration

@EnableConfigurationProperties(ReqRespProps.class)

public class ReqRespAutoConfiguration implements WebMvcConfigurer {

    @Override

    public void addInterceptors(InterceptorRegistry registry) {

        //访问记录

    }

    @Bean

    @ConditionalOnProperty(value = "vtuber.reqresp.convert-param-to-camelcase", havingValue = "true")

    public FilterRegistrationBean<RequestParamFilter> requestParamFilterReg() {

        return new FilterRegistrationBean<>(new RequestParamFilter());

    }

    @Bean

    @ConditionalOnProperty(value = "vtuber.reqresp.convert-result-to-underline", havingValue = "true")

    public ResponseCamelcaseToUnderlineAdvice responseCamelcaseToUnderlineAdvice() {

        return new ResponseCamelcaseToUnderlineAdvice();

    }

}

3.2.2. 请求入参转驼峰

本质上就是一个Filter

package com.myhexin.vtuber.reqresp.filter;

import cn.hutool.core.text.CharSequenceUtil;

import lombok.extern.slf4j.Slf4j;

import javax.servlet.*;

import javax.servlet.http.HttpServletRequest;

import java.io.IOException;

import java.util.HashMap;

import java.util.Map;

import java.util.Set;

/**

 * RequestParamFilter

 *

 * @author xxx

 * @date 2022/8/2 10:53

 **/

@Slf4j

public class RequestParamFilter implements Filter {

    @Override

    public void init(FilterConfig filterConfig) throws ServletException {

        log.info("request parameter filter init");

    }

    @Override

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;

        ParameterRequestWrapper newRequest = new ParameterRequestWrapper(request);

        Map<String, String[]> parameterMap = request.getParameterMap();

        Set<String> keySet = parameterMap.keySet();

        Map<String, String[]> newParamMap = new HashMap<>(parameterMap);

        for (String key : keySet) {

            String newKey = CharSequenceUtil.toCamelCase(key);

            newParamMap.put(newKey, parameterMap.get(key));

        }

        newRequest.addParameters(newParamMap);

        chain.doFilter(newRequest, resp);

    }

    @Override

    public void destroy() {

        log.info("request parameter filter destroy");

    }

}

3.2.3. 响应出参转下划线

本质上是使用了@ControllerAdvice

package com.myhexin.vtuber.reqresp.globalhandler;

import com.alibaba.fastjson.JSON;

import com.alibaba.fastjson.PropertyNamingStrategy;

import com.alibaba.fastjson.serializer.SerializeConfig;

import com.alibaba.fastjson.serializer.SerializerFeature;

import lombok.extern.slf4j.Slf4j;

import org.springframework.core.MethodParameter;

import org.springframework.core.annotation.Order;

import org.springframework.http.MediaType;

import org.springframework.http.converter.HttpMessageConverter;

import org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter;

import org.springframework.http.server.ServerHttpRequest;

import org.springframework.http.server.ServerHttpResponse;

import org.springframework.lang.Nullable;

import org.springframework.web.bind.annotation.ControllerAdvice;

import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.util.Objects;

/**

 * ResponseCamelcaseToUnderlineAdvice

 * 将结果转为下划线命名

 *

 * @author lufeng@myhexin.com

 * @date 2023/2/3

 **/

@Slf4j

@Order(10000)

@ControllerAdvice

public class ResponseCamelcaseToUnderlineAdvice implements ResponseBodyAdvice<Object> {

    @Override

    public boolean supports(

            MethodParameter returnType,

            Class<? extends HttpMessageConverter<?>> converterType) {

        return AbstractJackson2HttpMessageConverter.class.isAssignableFrom(converterType);

    }

    @Override

    public Object beforeBodyWrite(

            @Nullable Object body,

            MethodParameter returnType,

            MediaType selectedContentType,

            Class<? extends HttpMessageConverter<?>> selectedConverterType,

            ServerHttpRequest request, ServerHttpResponse response) {

        if (Objects.nonNull(body)) {

            return objectToUnderline(body);

        else {

            return body;

        }

    }

    /**

     * 对象转下划线

     *

     * @param obj obj

     * @return object

     */

    public static Object objectToUnderline(Object obj) {

        String json = objectToUnderlineJson(obj);

        return JSON.parse(json);

    }

    /**

     * 对象转下划线

     *

     * @param obj obj

     * @return object

     */

    public static String objectToUnderlineJson(Object obj) {

        if (obj == null) {

            return null;

        }

        SerializeConfig config = new SerializeConfig();

        config.propertyNamingStrategy = PropertyNamingStrategy.SnakeCase;

        return serialize(obj, config);

    }

    /**

     * 序列化(保留null值)

     *

     * @param obj    obj

     * @param config config

     * @return str

     */

    private static String serialize(Object obj, SerializeConfig config) {

        return JSON.toJSONString(

                obj,

                config,

                SerializerFeature.DisableCircularReferenceDetect,

                SerializerFeature.WriteMapNullValue

        );

    }

}

3.2.4. pom.xml

引入组件

3.2.5. yml配置

vtuber:

  reqresp:

    # 请求入参转驼峰开关

    convert-param-to-camelcase: true

    # 响应出参转下划线开关

    convert-result-to-underline: true

3.3. spring的Jackson工具提供出参处理方法

这个很简单,加个yml配置就可以了

spring:

    jackson:

        property-naming-strategy: SNACK_CASE

或者在指定要改成下划线形式的每一个出参类上加:

@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值