如有侵权,请联系~
如有错误,欢迎批评指正!
1、自定义实现函数参数注解
背景:作为服务端参数的定义都是符合驼峰命名规则,但是客户端一般都是使用下划线。例如客户端版本号:服务端使用String versionName来接受,而客户端使用version_name进行传递。因此,服务端需要进行映射,每个接口都要进行映射,代码不够美观简练。所以函数参数注解诞生。
1.1、 声明定义注解
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestParamMapping {
// 增加属性
// boolean required() default true;
}
这个注解比较简单,没有任何属性。不过如果想要扩展功能,可以直接增加属性即可。在参数解析的时候使用
RequestParamMapping requestParamMapping = methodParameter.getParameterAnnotation(RequestParamMapping.class);
requestParamMapping.required(); // 这样就可以获取到上述属性,根据属性值做不同的逻辑处理。
1.2 实现HandlerMethodArgumentResolver接口
@Slf4j
public class ParameterNameConverterResolver implements HandlerMethodArgumentResolver {
public static Logger SCRIBE_LOGGER = LoggerFactory.getLogger("scribe");
/**
* 参数中是不是有RequestParamMapping注解
*
* @param methodParameter the method parameter to check
* @return
*/
@Override
public boolean supportsParameter(MethodParameter methodParameter) {
return methodParameter.hasParameterAnnotation(RequestParamMapping.class);
}
@Override
public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer,
NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory)
throws Exception {
HttpServletRequest request = nativeWebRequest.getNativeRequest(HttpServletRequest.class);
Parameter parameter = methodParameter.getParameter();
Class aClass = Class.forName(parameter.getType().getName());
// 获取该类声明的所有属性
Field[] declaredFields = aClass.getDeclaredFields();
// 获取该类及其父类声明的所有public属性
Field[] baseFields = aClass.getFields();
// 去重,筛选该类中所有的public属性
Set<Field> fieldSet = new HashSet<>(declaredFields.length + baseFields.length);
fieldSet.addAll(Arrays.asList(declaredFields));
fieldSet.addAll(Arrays.asList(baseFields));
Object obj = aClass.newInstance();
for (Field declaredField : fieldSet) {
declaredField.setAccessible(true);
String fieldName = declaredField.getName();
String[] requestParameters = getRequestParamValues(request, fieldName);
Object requestValue = null;
try {
requestValue = typeTransformer(declaredField, requestParameters);
} catch (Exception e) {
log.warn("request param transfer error", e);
}
// 防止赋值失败的异常,例如常量不能赋值,jacoco自动注入的变量$jacocoData
try {
declaredField.set(obj, requestValue);
} catch (IllegalArgumentException | IllegalAccessException e) {
continue;
}
}
return obj;
}
/**
* 从请求参数中获取数据的顺序:属性从驼峰转换成下划线 > 属性本身 > 首字母大写
* 例如:对象属性为userId 从请求参数中获取的顺序 user_id > userId > UserId
*
* @param request
* @param fieldName
* @return
*/
private String[] getRequestParamValues(HttpServletRequest request, String fieldName) {
String underlineCase = StrUtil.toUnderlineCase(fieldName);
String[] requestParameters = request.getParameterValues(underlineCase);
if (ArrayUtil.isEmpty(requestParameters)) {
requestParameters = request.getParameterValues(fieldName);
}
if (ArrayUtil.isEmpty(requestParameters)) {
requestParameters = request.getParameterValues(StringUtils.capitalize(fieldName));
}
return requestParameters;
}
/**
* 将获取到的数据转换为对象需要的类型
*
* @param declaredField
* @param requestParameter
* @return
*/
private Object typeTransformer(Field declaredField, String[] requestParameter) {
if (ArrayUtil.isEmpty(requestParameter)) {
return null;
}
if (declaredField.getType().equals(Integer.class)) {
return Integer.valueOf(requestParameter[0]);
} else if (declaredField.getType().equals(Long.class)) {
return Long.valueOf(requestParameter[0]);
} else if (declaredField.getType().equals(Boolean.class)) {
return Boolean.valueOf(requestParameter[0]);
} else if (declaredField.getType().equals(Double.class)) {
return Double.valueOf(requestParameter[0]);
} else if (List.class.isAssignableFrom(declaredField.getType())) {
return Arrays.asList(requestParameter);
} else if (Set.class.isAssignableFrom(declaredField.getType())) {
List<String> list = Arrays.asList(requestParameter);
return new HashSet<>(list);
}
return StringUtils.join(requestParameter, ",");
}
}