`
lg_asus
  • 浏览: 191639 次
  • 性别: Icon_minigender_1
  • 来自: 苏州
社区版块
存档分类
最新评论

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&lt;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是不行的。
分享到:
评论

相关推荐

    spring自定义标签例子

    在Spring框架中,自定义标签是一项非常实用的功能,它允许我们创建符合XML语法的自定义元素,以便在配置文件中更方便地表达业务逻辑。在"spring自定义标签例子"这个项目中,我们可以深入理解这一特性,特别是通过...

    spring 自定义属性编辑器

    在Spring框架中,属性编辑器(PropertyEditor)是一种强大的工具,允许我们自定义类型转换过程。当我们需要将字符串形式的数据转换为Java对象时,属性编辑器就发挥了关键作用。例如,从请求参数或配置文件中读取的...

    spring自定义注解样例

    在Spring框架中,自定义注解是一种非常强大的工具,它允许开发者根据具体需求扩展框架的功能。Spring AOP(面向切面编程)是Spring框架的重要组成部分,通过AOP,我们可以实现代码的解耦,提高可维护性和可重用性。...

    Spring 自定义注解的解析

    在Spring框架中,自定义注解的解析是一个强大的特性,允许开发者根据业务需求创建特定的注解,并在Spring容器启动时自动处理这些注解。本文将深入探讨如何在Spring环境中通过`component-scan`配置来处理自定义Java...

    spring自定义切面实例

    标题:“spring自定义切面实例” 描述:本文档将深入探讨如何在Spring框架中实现自定义切面(Aspect),并提供具体的代码示例。通过利用Spring的AOP(面向切面编程)特性,特别是@AspectJ注解的支持,我们可以创建...

    spring 自定义事务管理器,编程式事务,声明式事务@Transactional使用

    本教程将深入探讨如何在Spring中实现自定义事务管理器、编程式事务处理以及声明式事务`@Transactional`的使用。 首先,让我们了解事务管理的基本概念。事务是一组数据库操作,这些操作要么全部执行,要么全部回滚,...

    spring自定义xml配置扩展

    主要是讲spring自定义xml配置的扩展相关的内容,东西不算新的,都是比较基础的,想看就看一下 我也是为了搞点积分才上传的

    Spring自定义切面事务问题

    ### Spring自定义切面事务问题 #### 背景与挑战 在开发基于Spring框架的应用程序时,我们经常需要利用AOP(面向切面编程)来实现横切关注点(如日志记录、安全控制、事务管理等)的模块化处理。其中,事务管理是...

    Spring自定义配置文件便签[Maven]工程可运行

    在Spring框架中,自定义配置文件和标签是提高代码可读性和灵活性的重要手段。这个名为"Spring自定义配置文件便签[Maven]工程可运行"的项目,显然是一个基于Maven构建的Spring 5.0应用程序,它包含了自定义配置文件和...

    spring 自定义xml标签

    在Spring框架中,自定义XML标签是扩展Spring配置能力的重要方式。这允许开发者创建符合项目需求的特定标签,提高代码的可读性和可维护性。本文将深入探讨如何在Spring中自定义XML标签,以及其背后的原理和实现过程。...

    spring自定义编辑器

    ### Spring自定义编辑器详解 #### 一、引言 在Spring框架中,自定义编辑器主要用于处理数据类型的转换问题,特别是在将用户输入的数据转换为Java对象时非常有用。例如,用户通过表单提交了一个日期格式的字符串,...

    这一次搞懂Spring自定义标签以及注解解析原理说明

    在Spring框架中,自定义标签和注解解析是两个关键的特性,它们使得代码与配置的集成更加紧密,简化了应用程序的开发。本篇文章将深入探讨Spring如何处理这两种类型的元数据。 首先,让我们来理解Spring如何解析...

    Spring security 自定义密码加密方式的使用范例。

    Spring Security 是一个强大的Java安全框架,...通过这个项目,你可以深入理解Spring Security的工作原理,并学习如何自定义其核心组件。如果你对码云不熟悉,也可以选择其他版本控制系统,如Git,进行代码托管和协作。

    利用Spring Context上下文创建自定义对象

    本篇文章将深入探讨如何利用Spring Context上下文来创建自定义对象,并理解控制反转的原理。 首先,让我们了解什么是Spring Context。Spring Context是Spring框架的应用上下文,它充当了全局容器,存储了应用的所有...

    Spring 自定义注解注入properties文件的值jar包

    Spring 自定义注解注入properties文件的值jar包,下面为使用方法 在xml配置文件中,这样加载properties文件 ...

    自定义精简版dubbo,运用spring自定义标签、netty、zookeeper、ImportBeanDefinition实现

    自定义精简版dubbo,运用spring自定义标签、netty、zookeeper、ImportBeanDefinition实现

    Spring 5.2.9 06 源码分析-spring自定义标签解析过程

    在Spring框架中,自定义标签解析是扩展Spring配置能力的重要方式。通过自定义标签,开发者可以创建更加符合业务逻辑和可读性强的XML配置文件。本文将深入剖析Spring 5.2.9版本中自定义标签的解析过程,旨在帮助读者...

    spring自定义注解+Aspect使用1

    Spring 自定义注解和 Aspect 的使用 在本文中,我们将学习如何在 Spring 项目中使用自定义注解和 Aspect 来实现日志记录功能。我们将从头开始,创建一个简单的 Spring Boot 项目,然后使用自定义注解和 Aspect 来...

    自定义 Schema 解析 Spring Bean

    本篇文章将聚焦于“自定义Schema解析Spring Bean”这一主题,这是一项高级功能,允许开发者扩展Spring的XML配置能力,以满足特定项目的需要。 自定义Schema解析是Spring框架提供的一个强大特性,它允许开发者创建...

    spring mvc 和spring security自定义登录

    本文将深入探讨如何结合Spring MVC和Spring Security来实现自定义登录功能。 首先,Spring MVC是Spring框架的一部分,它为构建基于HTTP的Web应用程序提供了模型-视图-控制器架构。通过使用Spring MVC,开发者可以...

Global site tag (gtag.js) - Google Analytics