spring自定义ArgumentResolver

参考:http://www.cnblogs.com/HD/p/4118829.html 介绍了几种传参数方式。

对于传多个对象或者List<对象>,spring mvc并没有提供默认实现。不过我们可以自定义。

参考:http://stackoverflow.com/questions/30715579/custom-spring-annotation-for-request-parameters/30716094

例子:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
@Documented
public @interface WebParameter {

String value() default "";

boolean required() default true;

String defaultValue() default ValueConstants.DEFAULT_NONE;
}




/**
* This class is suitable for when you pass more than one object or List<object>,or both of them.<br/>
* This class does not support Array, even the property.<br/>
* @author gche
*
*/
public class WebParameterAnnotationArgumentResolver implements HandlerMethodArgumentResolver{

private Map<Class, List<Field>> fieldMap = new WeakHashMap<Class, List<Field>>(100);

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

@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
WebParameter anno = parameter.getParameterAnnotation(WebParameter.class);
String name = anno.value();
Object arg = null;
Class parameterType = parameter.getParameterType();
Map<String,String[]> parameterMap = webRequest.getParameterMap();
if(parameterMap == null || parameterMap.isEmpty()){
String defaultValue = anno.defaultValue();
if(StringUtils.isBlank(defaultValue) && anno.required()){
throw new Exception("no value is given for " + name + ", and it is required");
}
return this.convert(defaultValue, parameterType);
}
//student[0].name, student[1].name "student" List<Student>
if(List.class.isAssignableFrom(parameterType)){//List(Object)
int size = this.getListSize(parameterMap, name);
if(size <= 0){
return Collections.emptyList();
}
arg = new ArrayList(size);
ParameterizedType type = (ParameterizedType)parameter.getGenericParameterType();
for(int i=0;i<size;i++){
Object nestedArg = BeanUtils.instantiateClass((Class)type.getActualTypeArguments()[0]);
((List)arg).add(nestedArg);
this.setValue(nestedArg, parameterMap, name + "[" + i +"]");
}
}else if(parameterType.isArray()){//Object[]
throw new Exception("array is not supported, please use List instead");
}else{
arg = BeanUtils.instantiateClass(parameterType);
this.setValue(arg, parameterMap, name);
}

return arg;
}

private int getListSize(Map<String, String[]> parameterMap, String name){
int size = -1;
Iterator<Map.Entry<String, String[]>> it = parameterMap.entrySet().iterator();
while(it.hasNext()){
Map.Entry<String, String[]> entry = it.next();
String key = entry.getKey();
int index = key.indexOf(name + "[");
int index2 = key.indexOf("]");
if(index != -1){
size = Math.max(size, Integer.valueOf(key.substring(index+(name+"[").length(), index2)));
}
}
return size + 1;
}

private void setValue(Object instance, Map<String,String[]> parameterMap, String name) throws Exception{
List<Field> fieldList = this.getFields(instance.getClass());
for(Field field : fieldList){
PropertyDescriptor property = BeanUtils.getPropertyDescriptor(instance.getClass(), field.getName());
Class propertyType = property.getPropertyType();
if(ClassUtils.isPrimitiveOrWrapper(propertyType)|| propertyType == String.class || propertyType == Date.class){
String[] value = parameterMap.get(name + "." + property.getName());
if(value == null || (value.length == 1 && StringUtils.isBlank(value[0]))){
continue;
}
Method writeMethod = property.getWriteMethod();
writeMethod.invoke(instance, this.convert(value[0], propertyType));
}else if(propertyType.isArray()){
throw new Exception("array is not supported, please use List instead");
}else if(List.class.isAssignableFrom(propertyType)){
//student.books
int size = this.getListSize(parameterMap, name + "." + field.getName());
List nestedList = size <=0 ? Collections.emptyList() : new ArrayList(size);
Method writeMethod = property.getWriteMethod();
writeMethod.invoke(instance, nestedList);
for(int i=0;i<size;i++){
Object nestedInstance = BeanUtils.instantiateClass((Class)((ParameterizedType)field.getGenericType()).getActualTypeArguments()[0]);
nestedList.add(nestedInstance);
this.setValue(nestedInstance, parameterMap, name + "." + field.getName() + "[" + i + "]");
}
}else{
//nested object
Object nestedInstance = BeanUtils.instantiateClass(propertyType);
Method writeMethod = property.getWriteMethod();
writeMethod.invoke(instance, nestedInstance);
this.setValue(nestedInstance, parameterMap, name + "." + field.getName());
}
}
}

private Object convert(String data, Class expectedType) throws ParseException{
data = data.trim();
if(expectedType == byte.class || expectedType == Byte.class){
return Byte.valueOf(data);
}
if(expectedType == char.class || expectedType == Character.class){
return data.charAt(0);
}
if(expectedType == int.class || expectedType == Integer.class){
return Integer.valueOf(data);
}
if(expectedType == float.class || expectedType == Float.class){
return Float.valueOf(data);
}
if(expectedType == double.class || expectedType == Double.class){
return Double.valueOf(data);
}
if(expectedType == long.class || expectedType == Long.class){
return Long.valueOf(data);
}
if(expectedType == short.class || expectedType == Short.class){
return Short.valueOf(data);
}
if(expectedType == boolean.class || expectedType == Boolean.class){
return Boolean.valueOf(data);
}
if(expectedType == Date.class){
//2016-05-09 10位
//2016-05-09 22:23 16位
char delimiter = data.trim().charAt(4);
if(data.length() > 10){
return DateUtils.parseDate(data, "yyyy"+delimiter+"MM"+delimiter+"dd HH:mm");
}else{
return DateUtils.parseDate(data, "yyyy"+delimiter+"MM"+delimiter+"dd");
}
}
throw new TypeMismatchException(data, expectedType);
// return data;
}

private List<Field> getFields(Class parameterType) {
if(this.fieldMap.get(parameterType) != null){
return this.fieldMap.get(parameterType);
}
Field[] fields = parameterType.getDeclaredFields();
this.fieldMap.put(parameterType, Arrays.asList(fields));
return this.fieldMap.get(parameterType);
}

}



<mvc:annotation-driven>
<mvc:argument-resolvers>
<beans:bean class="com.xxx.WebParameterAnnotationArgumentResolver"></beans:bean>
</mvc:argument-resolvers>
</mvc:annotation-driven>



@RequestMapping("xxx")
public void save(@WebParameter("activity")Activity activity, @WebParameter("strategy")List<ActivityStrategy> strategy, HttpServletResponse response)

Activity和ActivityStrategy都是POJO。

在前端数据格式是这样:

{"activity.id":111,"activity.name":'test',"strategy[0].id":222,"strategy[0].name":"aaaa","strategy[1].id":333,"strategy[1].name":"bbbb"}

目前只实现了POJO和List<POJO>,支持嵌套。
由于我喜欢用List,因此没有实现数组。
PS:spring版本是4.2.4,4.1.4是不行的。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值