天天看點

springboot接口入參下劃線轉駝峰以及傳回參數駝峰轉下劃線實作

1.背景

在實際開發中,通常來說java裡面是使用駝峰的命名規則;

但是有時候在對接其他三方平台的接口時,要求使用下劃線的命名規則,這時候就涉及到如何讓自己的接口滿足三方平台的下劃線;

實作方式有

1.java裡面也使用下下劃線的方式接收和響應,但是不推薦這樣,因為雖然滿足了接口需求,但是不符合java裡面的命名規範;

2.java裡面使用駝峰,接收到參數後手動轉換,這樣做太麻煩.

3.java裡面使用駝峰,寫一個工具方法,通過注解的方式,統一轉換,推薦,也是實際開發中常用的方式

那些地方需要轉換

1.傳入參數的時候(下換線轉為駝峰)

2.響應結果的時候(駝峰轉為下劃線)

因為響應結果的時候(駝峰轉為下劃線)比較簡單,先搞定這個

方式一:在傳回對象的類上加注解(推介)

@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
案例如下:      

方法二:在字段上注解

@JsonProperty(value = "order_card")      

3.傳入參數的時候(下換線轉為駝峰)

方式一:自己手動封裝,不推薦,略;

方式二:接收為Map對接,通過Json轉換(如果系統中隻有少數個别接口需要轉換,可以這樣寫);

步驟一:接收對象上的字段上加注解 @JsonProperty(value = "order_card")

 步驟二:控制層出的寫法如下

方式三:通過實作接口HandlerMethodArgumentResolver的方式,強烈推薦

步驟一:自定義注解 ParameterConvert

springboot接口入參下劃線轉駝峰以及傳回參數駝峰轉下劃線實作
@Target(value = ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface ParameterConvert {
}      

View Code

步驟二:自定義類AbstractCustomizeResolver

springboot接口入參下劃線轉駝峰以及傳回參數駝峰轉下劃線實作
springboot接口入參下劃線轉駝峰以及傳回參數駝峰轉下劃線實作
import org.springframework.core.Conventions;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Errors;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import java.lang.annotation.Annotation;

/**
 * @Copyright (C) XXXXXXXXXXX科技股份技有限公司
 * @Author: lidongping
 * @Date: 2021-05-13 19:24
 * @Description:
 */
public abstract class AbstractCustomizeResolver implements HandlerMethodArgumentResolver {
    /**
     * 校驗
     *
     * @param parameter
     * @param mavContainer
     * @param webRequest
     * @param binderFactory
     * @param arg
     * @throws Exception
     */
    protected void valid(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory, Object arg) throws Exception {
        String name = Conventions.getVariableNameForParameter(parameter);
        WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
        if (arg != null) {
            validateIfApplicable(binder, parameter);
            if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
                throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
            }
        }
        mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
    }

    /**
     * @param binder
     * @param parameter
     */
    protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) {
        Annotation[] annotations = parameter.getParameterAnnotations();
        for (Annotation ann : annotations) {
            Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class);
            if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) {
                Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(ann));
                Object[] validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[]{hints});
                binder.validate(validationHints);
                break;
            }
        }
    }

    protected boolean isBindExceptionRequired(WebDataBinder binder, MethodParameter parameter) {
        int i = parameter.getParameterIndex();
        Class<?>[] paramTypes = parameter.getMethod().getParameterTypes();
        boolean hasBindingResult = (paramTypes.length > (i + 1) && Errors.class.isAssignableFrom(paramTypes[i + 1]));
        return !hasBindingResult;
    }

}      

步驟三:自定義類 UnderlineToCamelArgumentResolver

springboot接口入參下劃線轉駝峰以及傳回參數駝峰轉下劃線實作
springboot接口入參下劃線轉駝峰以及傳回參數駝峰轉下劃線實作
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.ModelAndViewContainer;

import java.util.Iterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class UnderlineToCamelArgumentResolver extends AbstractCustomizeResolver {
    /**
     * 比對_加任意一個字元
     */
    private static final Pattern UNDER_LINE_PATTERN = Pattern.compile("_(\\w)");

    @Override
    public boolean supportsParameter(MethodParameter methodParameter) {
        return methodParameter.hasParameterAnnotation(ParameterConvert.class);
    }

    @Override
    public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer,
                                  NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
        Object org = handleParameterNames(methodParameter, nativeWebRequest);
        valid(methodParameter, modelAndViewContainer, nativeWebRequest, webDataBinderFactory, org);
        return org;
    }

    /**
     * 處理參數
     *
     * @param parameter
     * @param webRequest
     * @return
     */
    private Object handleParameterNames(MethodParameter parameter, NativeWebRequest webRequest) {
        Object obj = BeanUtils.instantiate(parameter.getParameterType());
        BeanWrapper wrapper = PropertyAccessorFactory.forBeanPropertyAccess(obj);
        Iterator<String> paramNames = webRequest.getParameterNames();
        while (paramNames.hasNext()) {
            String paramName = paramNames.next();
            Object o = webRequest.getParameter(paramName);
            System.out.println(paramName + "=" + o);
            wrapper.setPropertyValue(underLineToCamel(paramName), o);
        }
        return obj;
    }

    /**
     * 下換線轉駝峰
     *
     * @param source
     * @return
     */
    private String underLineToCamel(String source) {
        Matcher matcher = UNDER_LINE_PATTERN.matcher(source);
        StringBuffer result = new StringBuffer();
        while (matcher.find()) {
            matcher.appendReplacement(result, matcher.group(1).toUpperCase());
        }
        matcher.appendTail(result);
        return result.toString();
    }
}      

步驟四:整合到springboot中,在WebConfig中添加如下代碼

springboot接口入參下劃線轉駝峰以及傳回參數駝峰轉下劃線實作
springboot接口入參下劃線轉駝峰以及傳回參數駝峰轉下劃線實作
@Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        argumentResolvers.add(new UnderlineToCamelArgumentResolver());
    }      

 步驟五:使用,很簡單,在接收參數的對象前加注解

4.完美