spring 自定义参数解析器处理下划线参数转驼峰

先引入一篇博客: https://www.cnblogs.com/java-zhao/p/9119258.html

关于处理使用@requstBody注解后自定义参数解析器,失败,原因是spring会使用自己默认的参数解析器来处理参数解析,上面这篇博客涉及了参数解析器的顺序

因此大部门都是采用自定义注解来实现的

 

我的业务场景:  

     对接第三方平台,别人调用我的接口,但是接口文档参数已经定好位有下划线的参数,觉得不规范,但是别人又不好修改,采用自定义注解+参数解析器来讲下划线的参数名称,转为驼峰命名参数接收

 

 

RequestMappingHandlerAdapter 中查看默认的参数解析器

spring 自定义参数解析器处理下划线参数转驼峰_第1张图片

 

 

 

spring 自定义参数解析器处理下划线参数转驼峰_第2张图片

 

通用自定义参数解析类,实现 HandlerMethodArgumentResolver 接口,同时交给spring回调,来实现目的

package com.wm.resolverstudy1.config;

import com.alibaba.fastjson.JSONObject;
import com.wm.resolverstudy1.annotation.RequestPropertiesBody;
import org.springframework.core.MethodParameter;
import org.springframework.objenesis.instantiator.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
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 sun.reflect.misc.FieldUtil;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;


/**
 * @author 半卷流年
 * @date 2020-8-13 10:28
 */
public class RequestModelArgumentResolver implements HandlerMethodArgumentResolver {

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

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
       return parameter.hasParameterAnnotation(RequestPropertiesBody.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        Class parameterType = parameter.getParameterType();

        HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
        CustomHttpServletRequestWrapper requestWrapper = new CustomHttpServletRequestWrapper(request);
        String body = requestWrapper.getBody();
        //实例化对象
        Object result = ClassUtils.newInstance(parameterType);
        if(StringUtils.isEmpty(body)){
            return result;
        }
        JSONObject jsonObject = JSONObject.parseObject(body);
        //获取字段
        Field[] fields = FieldUtil.getDeclaredFields(parameterType);
        Map fieldMap = Arrays.stream(fields).collect(Collectors.toMap(Field::getName, v -> v));
        Object arg = null;
        //往对象写入值
        for (Map.Entry entry : jsonObject.entrySet()) {
            String fieldName = entry.getKey();
            //处理下划线转驼峰命名
            if(isExistUnderLine(fieldName)){
                fieldName = this.underLineToCamel(fieldName);
            }
            Field field = fieldMap.getOrDefault(fieldName, null);
            if(ObjectUtils.isEmpty(field)){
                continue;
            }
            arg = entry.getValue();
            if(ObjectUtils.isEmpty(arg)){
                continue;
            }
            if (isPrimitive(field.getType())) {
                Class parType = field.getType();
                arg = getArg(parType, arg);
            }
            Method setter = getSetterMethod(parameterType, field,fieldName);
            if (setter != null) {
                setter.invoke(result, arg);
            }
        }
        return result;
    }


    private boolean isExistUnderLine(String value){
        Matcher m = this.underLinePattern.matcher(value);
       return m.find();
    }


    private String underLineToCamel(final String 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();
    }


    private Method getSetterMethod(Class clazz, Field field,String fileName) throws NoSuchMethodException {
        return clazz.getDeclaredMethod("set" + toUpperCaseFirstOne(fileName), field.getType());
    }

    private boolean isPrimitive(Class clazz) {
        return Integer.class.equals(clazz) ||
                Double.class.equals(clazz) ||
                Float.class.equals(clazz) ||
                Boolean.class.equals(clazz) ||
                Long.class.equals(clazz) ||
                Byte.class.equals(clazz) ||
                Short.class.equals(clazz) ||
                clazz.isPrimitive();

    }


    private Object getArg(Class primitiveClass, Object value) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Object result = null;
        if (isPrimitive(primitiveClass)) {
            String primitiveName = primitiveClass.getSimpleName();
            if ("char".equals(primitiveName)) {
                return value;
            }
            String firstUpperprimitiveName = toUpperCaseFirstOne(primitiveName);
            Class encapsulationClass = "int".equals(primitiveName) ? Class.forName("java.lang." + firstUpperprimitiveName + "eger") : Class.forName("java.lang." + firstUpperprimitiveName);
            result = getParseMethod(encapsulationClass, firstUpperprimitiveName).invoke(null, value);
        }
        return result;
    }

    private Method getParseMethod(Class encapsulationClass, String firstUpperprimitiveName) throws NoSuchMethodException {
        String methodName = "parse" + firstUpperprimitiveName;
        return encapsulationClass.getDeclaredMethod(methodName, String.class);
    }

    private String toUpperCaseFirstOne(String fieldName) {
        if (Character.isUpperCase(fieldName.charAt(0))){
            return fieldName;
        }
        else {
            return String.valueOf(Character.toUpperCase(fieldName.charAt(0))) + fieldName.substring(1);
        }
    }

}

 

用到了,获取传入的json字符串,重写获取request中的数据,因为request使用一次就会关闭流的

 

package com.wm.resolverstudy1.config;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;

/**
 * @author 半卷流年
 * @date 2020-8-13 16:17
 */
public class CustomHttpServletRequestWrapper extends HttpServletRequestWrapper {
    private final String body;

    public String getBody() {
        return this.body;
    }

    public CustomHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        StringBuilder stringBuilder = new StringBuilder();
        BufferedReader bufferedReader = null;
        try {
            InputStream inputStream = request.getInputStream();
            if (inputStream != null) {
                bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                char[] charBuffer = new char[128];
                int bytesRead = -1;
                while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
                    stringBuilder.append(charBuffer, 0, bytesRead);
                }
            } else {
                stringBuilder.append("");
            }
        } catch (IOException ex) {
            throw ex;
        } finally {
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                } catch (IOException ex) {
                    throw ex;
                }
            }
        }
        body = stringBuilder.toString();
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
        ServletInputStream servletInputStream = new ServletInputStream() {
            @Override
            public boolean isFinished() {
                return false;
            }
            @Override
            public boolean isReady() {
                return false;
            }
            @Override
            public void setReadListener(ReadListener readListener) {
            }
            @Override
            public int read() throws IOException {
                return byteArrayInputStream.read();
            }
        };
        return servletInputStream;
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(this.getInputStream()));
    }
}

 

注入的spring中

package com.wm.resolverstudy1.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

/**
 * @author 半卷流年
 * @date 2020-8-13 14:20
 */
@Configuration
public class AppWebMvcConfigurer implements WebMvcConfigurer {
    @Override
    public void addArgumentResolvers(List resolvers) {
        resolvers.add(0,new RequestModelArgumentResolver());
    }
}

 

用到的实体类和自定义注解:

package com.wm.resolverstudy1.annotation;

import java.lang.annotation.*;

/**
 * @author 半卷流年
 * @date 2020-8-13 14:13
 * 模仿spring  requestBody注解
 */
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestPropertiesBody {
    boolean required() default true;

}

 

 

 

package com.wm.resolverstudy1.model;

import lombok.Data;

import java.io.Serializable;

/**
 * @author 半卷流年
 * @date 2020-8-13 10:25
 */
@Data
public class User implements Serializable {
    private static final long serialVersionUID = -7551221166493676100L;


    private String nameName;

    private String name;


}

 

 

 

测试:

package com.wm.resolverstudy1.controller;

import com.wm.resolverstudy1.annotation.RequestPropertiesBody;
import com.wm.resolverstudy1.model.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;

/**
 * @author 半卷流年
 * @date 2020-8-13 10:26
 */
@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {

    @Autowired
    private RequestMappingHandlerAdapter adapter;

    @PostMapping("/test4")
    public String test4(@RequestPropertiesBody User user){
        log.info("请求数据:{}",user);
        //return user.getNameName();
        return "ok";
    }





}

 

spring 自定义参数解析器处理下划线参数转驼峰_第3张图片

 

 

 

你可能感兴趣的:(Java,java,spring)