需求:
现在有一个实体类,若使用spring mvc自定义的 @RequestBody 会自动注入相应字段名的属性,但这要求字段名和实体类的属性名一致才行,然而由于前期的一些缘故,前端的字段是下划线的形式,不是小驼峰形式,因此无法找到相应的字段,从而无法注入;
解决方案:自定义参数解析器
package golden.utils;
import com.alibaba.fastjson.JSONObject;
import org.springframework.core.MethodParameter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
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 javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
//用于处理前端json传来的对象属性,支持下划线和驼峰
public class RequestBodyBindingHandler implements HandlerMethodArgumentResolver {
private static MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
@Override
public boolean supportsParameter(MethodParameter methodParameter) {
return methodParameter.hasParameterAnnotation(RequestBodyBinding.class);
}
@Override
public Object resolveArgument(MethodParameter methodParameter,
ModelAndViewContainer modelAndViewContainer,
NativeWebRequest nativeWebRequest,
WebDataBinderFactory webDataBinderFactory) throws Exception {
HttpServletRequest httpServletRequest = nativeWebRequest.getNativeRequest(HttpServletRequest.class);
String body = readBody(httpServletRequest);
Type targetObject = methodParameter.getParameterType();
return convert(body, targetObject.getTypeName());
}
private Object convert(String body, String clazzName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, ClassNotFoundException {
Class<?> aClass = Class.forName(clazzName);
Object instance = aClass.getConstructor().newInstance();
JSONObject jsonObject = JSONObject.parseObject(body);
Field[] fields = aClass.getDeclaredFields();
Map<String, Field> fieldsMap = new HashMap<>(fields.length);
for (int i = 0; i < fields.length; i++) {
fieldsMap.put(fields[i].getName(), fields[i]);
}
jsonObject.forEach((key, val) -> {
String name = modifyUnderLineToHump(key);
if (fieldsMap.containsKey(name)) {
Field field = fieldsMap.get(name);
field.setAccessible(true);
try {
field.set(instance, val);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
});
return instance;
}
private String modifyUnderLineToHump(String key) {
char[] chars = key.toCharArray();
int j = 0;
boolean bonux = false;
for (int i = 0; i < chars.length; i++) {
if (chars[i] == '_') {
bonux = true;
continue;
}
if (bonux) {
chars[j++] = (char) (chars[i] & '_');
bonux = false;
} else {
chars[j++] = chars[i];
}
}
char[] chars1 = Arrays.copyOf(chars, j);
return new String(chars1);
}
private String readBody(HttpServletRequest httpServletRequest) throws IOException {
BufferedReader reader = httpServletRequest.getReader();
StringBuilder str = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
str.append(line);
}
return str.toString();
}
}
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="golden.utils.RequestBodyBindingHandler"/>
</mvc:argument-resolvers>
</mvc:annotation-driven>