前言
今天在做一个后台的管理列表,猛然发现有8~9个查询参数,心里一想:又 TMD 要想一坨子 @RequestParam了。突然就想:妈的不想这样了。想着用一个对象来封装这些查询参数。但我们公司是有要求 前端给的参数都是以下划线,而后端用的都是驼峰命名。如何转换成了问题。以下是在请教大佬之后,大佬给的方案,感谢大佬,特记下学习一下。
代码
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface PropertyNaming {
}
public class PropertyNamingStrategyArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(PropertyNaming.class);
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
String name = ModelFactory.getNameForParameter(parameter);
Object attribute = (mavContainer.containsAttribute(name) ? mavContainer.getModel().get(name) :
createAttribute(parameter));
WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
if (binder.getTarget() != null) {
if (!mavContainer.isBindingDisabled(name)) {
bindRequestParameters(binder, webRequest);
}
validateIfApplicable(binder, parameter);
if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
throw new BindException(binder.getBindingResult());
}
}
// Add resolved attribute and BindingResult at the end of the model
Map<String, Object> bindingResultModel = binder.getBindingResult().getModel();
mavContainer.removeAttributes(bindingResultModel);
mavContainer.addAllAttributes(bindingResultModel);
return binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);
}
/**
* Whether to raise a fatal bind exception on validation errors.
* @param binder the data binder used to perform data binding
* @param methodParam the method argument
* @return {@code true} if the next method argument is not of type {@link Errors}
*/
protected boolean isBindExceptionRequired(WebDataBinder binder, MethodParameter methodParam) {
int i = methodParam.getParameterIndex();
Class<?>[] paramTypes = methodParam.getMethod().getParameterTypes();
boolean hasBindingResult = (paramTypes.length > (i + 1) && Errors.class.isAssignableFrom(paramTypes[i + 1]));
return !hasBindingResult;
}
protected void validateIfApplicable(WebDataBinder binder, MethodParameter methodParam) {
Annotation[] annotations = methodParam.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 void bindRequestParameters(WebDataBinder binder, NativeWebRequest request) {
Map<String, String[]> result = new HashMap<>();
Map<String, String[]> parameterMap = request.getParameterMap();
if(!parameterMap.isEmpty()) {
Set<String> keys = parameterMap.keySet();
for (String key : keys) {
result.put(key, parameterMap.get(key));
String translate = SnakeCaseStrategy.translate(key);
if(translate.equals(key)){
continue;
}
result.put(translate, parameterMap.get(key));
}
}
MutablePropertyValues mpvs = new MutablePropertyValues(result);
binder.bind(mpvs);
}
protected Object createAttribute(MethodParameter methodParam) throws Exception {
return BeanUtils.instantiateClass(methodParam.getParameterType());
}
public static class SnakeCaseStrategy {
public static String translate(String input)
{
// garbage in, garbage out
if (input == null) return input;
int length = input.length();
StringBuilder result = new StringBuilder(length * 2);
boolean wasPrevTranslated = false;
for (int i = 0; i < length; i++)
{
// skip first starting underscore
char c = input.charAt(i);
if (i > 0 && c == '_')
{
wasPrevTranslated = true;
} else if (Character.isLowerCase(c) && wasPrevTranslated) {
result.append(Character.toUpperCase(c));
wasPrevTranslated = false;
} else {
result.append(c);
}
}
return result.toString();
}
}
}
@Configuration
public class WebConfiguration extends WebMvcConfigurationSupport {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new PropertyNamingStrategyArgumentResolver());
}
使用
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping
public String test(@PropertyNaming Test test){
return test.userName;
}
}