参考: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是不行的。
分享到:
相关推荐
在Spring框架中,自定义标签是一项非常实用的功能,它允许我们创建符合XML语法的自定义元素,以便在配置文件中更方便地表达业务逻辑。在"spring自定义标签例子"这个项目中,我们可以深入理解这一特性,特别是通过...
在Spring框架中,属性编辑器(PropertyEditor)是一种强大的工具,允许我们自定义类型转换过程。当我们需要将字符串形式的数据转换为Java对象时,属性编辑器就发挥了关键作用。例如,从请求参数或配置文件中读取的...
在Spring框架中,自定义注解是一种非常强大的工具,它允许开发者根据具体需求扩展框架的功能。Spring AOP(面向切面编程)是Spring框架的重要组成部分,通过AOP,我们可以实现代码的解耦,提高可维护性和可重用性。...
在Spring框架中,自定义注解的解析是一个强大的特性,允许开发者根据业务需求创建特定的注解,并在Spring容器启动时自动处理这些注解。本文将深入探讨如何在Spring环境中通过`component-scan`配置来处理自定义Java...
标题:“spring自定义切面实例” 描述:本文档将深入探讨如何在Spring框架中实现自定义切面(Aspect),并提供具体的代码示例。通过利用Spring的AOP(面向切面编程)特性,特别是@AspectJ注解的支持,我们可以创建...
本教程将深入探讨如何在Spring中实现自定义事务管理器、编程式事务处理以及声明式事务`@Transactional`的使用。 首先,让我们了解事务管理的基本概念。事务是一组数据库操作,这些操作要么全部执行,要么全部回滚,...
主要是讲spring自定义xml配置的扩展相关的内容,东西不算新的,都是比较基础的,想看就看一下 我也是为了搞点积分才上传的
### Spring自定义切面事务问题 #### 背景与挑战 在开发基于Spring框架的应用程序时,我们经常需要利用AOP(面向切面编程)来实现横切关注点(如日志记录、安全控制、事务管理等)的模块化处理。其中,事务管理是...
在Spring框架中,自定义配置文件和标签是提高代码可读性和灵活性的重要手段。这个名为"Spring自定义配置文件便签[Maven]工程可运行"的项目,显然是一个基于Maven构建的Spring 5.0应用程序,它包含了自定义配置文件和...
在Spring框架中,自定义XML标签是扩展Spring配置能力的重要方式。这允许开发者创建符合项目需求的特定标签,提高代码的可读性和可维护性。本文将深入探讨如何在Spring中自定义XML标签,以及其背后的原理和实现过程。...
### Spring自定义编辑器详解 #### 一、引言 在Spring框架中,自定义编辑器主要用于处理数据类型的转换问题,特别是在将用户输入的数据转换为Java对象时非常有用。例如,用户通过表单提交了一个日期格式的字符串,...
在Spring框架中,自定义标签和注解解析是两个关键的特性,它们使得代码与配置的集成更加紧密,简化了应用程序的开发。本篇文章将深入探讨Spring如何处理这两种类型的元数据。 首先,让我们来理解Spring如何解析...
Spring Security 是一个强大的Java安全框架,...通过这个项目,你可以深入理解Spring Security的工作原理,并学习如何自定义其核心组件。如果你对码云不熟悉,也可以选择其他版本控制系统,如Git,进行代码托管和协作。
本篇文章将深入探讨如何利用Spring Context上下文来创建自定义对象,并理解控制反转的原理。 首先,让我们了解什么是Spring Context。Spring Context是Spring框架的应用上下文,它充当了全局容器,存储了应用的所有...
Spring 自定义注解注入properties文件的值jar包,下面为使用方法 在xml配置文件中,这样加载properties文件 ...
自定义精简版dubbo,运用spring自定义标签、netty、zookeeper、ImportBeanDefinition实现
在Spring框架中,自定义标签解析是扩展Spring配置能力的重要方式。通过自定义标签,开发者可以创建更加符合业务逻辑和可读性强的XML配置文件。本文将深入剖析Spring 5.2.9版本中自定义标签的解析过程,旨在帮助读者...
Spring 自定义注解和 Aspect 的使用 在本文中,我们将学习如何在 Spring 项目中使用自定义注解和 Aspect 来实现日志记录功能。我们将从头开始,创建一个简单的 Spring Boot 项目,然后使用自定义注解和 Aspect 来...
本篇文章将聚焦于“自定义Schema解析Spring Bean”这一主题,这是一项高级功能,允许开发者扩展Spring的XML配置能力,以满足特定项目的需要。 自定义Schema解析是Spring框架提供的一个强大特性,它允许开发者创建...
本文将深入探讨如何结合Spring MVC和Spring Security来实现自定义登录功能。 首先,Spring MVC是Spring框架的一部分,它为构建基于HTTP的Web应用程序提供了模型-视图-控制器架构。通过使用Spring MVC,开发者可以...