`
qq466862016
  • 浏览: 125829 次
  • 来自: 杭州
社区版块
存档分类
最新评论

SpringMVC 日期参数转换报错问题最终解决方案

阅读更多

在用Springmvc的日期类型作为参数的时候,会碰到

 

org.springframework.beans.ConversionNotSupportedException: Failed to convert value of type '
java.lang.String' to required type 'java.util.Date'; nested exception is java.lang.
IllegalStateException:
 Cannot convert value of type [java.lang.String] to required type [java.util.Date]: 
no matchingeditors or conversion strategy found

对应不能绑定问题一般有下面几个方法:
一、Spring3的源码,略微做了下修改:在Spring3的core包下找到
org.springframework.core.convert.support.GenericConversionService.convert(Object, TypeDescriptor, TypeDescriptor);这个方法然后在assertNotNull(sourceType, targetType);  
 这个方法然后在assertNotNull(sourceType, targetType); 这句话的下面添加:
    if(targetType.getType().getName().equals("java.util.Date")  
             && source instanceof String){  
        String date = (String)source;  
        try {  
            source = YMD_DATETIME_FORMAT.parse(date);  
        } catch (ParseException e) {  
            try {  
                source = YMDHM_DATETIME_FORMAT.parse(date);  
            } catch (ParseException e1) {  
                try {  
                    source = YMDHMS_DATETIME_FORMAT.parse(date);  
                } catch (ParseException e2) {  
                    source = null;  
                }  
            }  
        }  
        sourceType = targetType;  
    }  
 最后重新编译打包core包 这样当遇到Date类型的时候就把数据转换成Date类型的,接下去就不会报错了
这种方法不推荐,修改了源代码,日期类型格式非灵活性。不建议采用
二、在mvc配置的那个xml中添加如下代码:
  <bean  
        class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">    
        <property name="cacheSeconds" value="0" />    
        <property name="webBindingInitializer">  
               <bean class="WebBinding" />   
        </property>  
    </bean> 
 添加WebBinding
import java.util.Date;  
  
import org.springframework.beans.propertyeditors.CustomDateEditor;  
import org.springframework.web.bind.WebDataBinder;  
import org.springframework.web.bind.support.WebBindingInitializer;  
import org.springframework.web.context.request.WebRequest;  
  
public class WebBinding implements WebBindingInitializer {  
      
    @Override  
    public void initBinder(WebDataBinder binder, WebRequest request) {  
        // 使用spring自带的CustomDateEditor    
        // 解决时间转换问题  
        // yyyy-MM-dd  
        binder.registerCustomEditor(Date.class,   
                new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true));   
    }  
      
      
}
 这样虽然可以解决日期类型参数报错问题也不建议采用,这样每个日期类型格式必须 yyyy-MM-dd

三、采用自定义注解方式解决日期类型参数绑定问题
 1、 定义一个自定义日期类型解析器注解
package org.dongtian.sys.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 日期类型解析器注解
 * @author gaoyuandong
 * @mailto 466862016@qq.com
 * @date   2015年9月6日 下午2:18:38
 */
@Target({ElementType.PARAMETER,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DateParser {
//名称
String name() default "";
//格式化
String pattern() default "yyyy-MM-dd hh:mm:ss";
}
  默认格式为 yyyy-MM-dd hh:mm:ss
 2、接下来我们定义一个此日期类型解析器注解对应的解析器(我们实现Springmvc自定义方法参数解析器)
package org.dongtian.sys.web.context;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.dongtian.sys.annotation.DateParser;
import org.springframework.beans.BeanUtils;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
/***
 * spring mvc 方法参数或者参数为bean中包含有日期类型的格式解析器
 * @author gaoyuandong
 * @mail   466862016@qq.com
 * @date   2015年9月13日 下午3:49:39
 */
public class DateHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {

	private static Logger log = Logger.getLogger(DateHandlerMethodArgumentResolver.class);
	
	public boolean supportsParameter(MethodParameter parameter) {
		//方法参数
		DateParser dateParser = parameter.getParameterAnnotation(DateParser.class);
		if (dateParser != null) {
			return true;
		} else { //bean的字段上是否存在@DateParser注解
			
			Class<?> targetType = parameter.getParameterType();
			Field[] fields = targetType.getDeclaredFields();
			if(fields != null && fields.length >0) {
				
				for (int i = 0; i < fields.length; i++) {
					
					Field field = fields[i];
					if(field.isAnnotationPresent(DateParser.class) == true) {
						return true;
					}
				}
			}
			
			return false;
		}
	}

	/***
	 * 解析包含有{@link  org.dongtian.sys.annotation.DateParser} 注解的参数
	 */
	public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
		
		if(binderFactory == null) return null;
		
		if(this.findDateParserAnnotationWithArguement(parameter) == true) {
			
			return this.handlerMethodArgumentDateParserAnnotation(parameter,mavContainer,webRequest,binderFactory);
		} else {
			return this.handlerBeanArgumentDateParserAnnotation(parameter,mavContainer,webRequest,binderFactory);
		}
	}

	/***
	 * 解析bean中成员变量 中包含有{@link  org.dongtian.sys.annotation.DateParser} 注解的参数
	 * @author gaoyuandong
	 * @date   2015年9月13日 下午4:39:58
	 * @param parameter
	 * @param mavContainer
	 * @param webRequest
	 * @param binderFactory
	 * @return
	 */
	private Object handlerBeanArgumentDateParserAnnotation(MethodParameter parameter,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
		
		Class<?> targetType = parameter.getParameterType();
		Object obj = BeanUtils.instantiate(targetType);
			Field[] fields = targetType.getDeclaredFields();
			WebDataBinder binder;
			try {
				binder = binderFactory.createBinder(webRequest, null, obj.getClass().getName());
				for (Field field : fields) {
					field.setAccessible(true);
					String fieldName = field.getName();
					Class<?> fieldType = field.getType();
					Object arg = null;
					
						if(!Modifier.isFinal(field.getModifiers())) {
							
							if(!StringUtils.isBlank(webRequest.getParameter(fieldName))) {
								if(field.isAnnotationPresent(DateParser.class)) {
									
									DateParser dateParser = field.getAnnotation(DateParser.class);
									String pattern = dateParser.pattern();
									String key = StringUtils.isBlank(dateParser.name()) ? parameter.getParameterName() : dateParser.name();
									//TODO
									SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);
									Date date = dateFormat.parse(webRequest.getParameter(fieldName));
									arg = date;
								} else {
									arg = binder.convertIfNecessary(webRequest.getParameter(fieldName), fieldType, parameter);
								}
							} else {
								arg = getDefaultArgumentValue(fieldType, arg); 
							}
							field.set(obj, arg);
						}
					
					
				}
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				return null;
			}
			
			return obj;
		
	
	}

	/***
	 * 获取基本数据类型默认的值
	 * @author gaoyuandong
	 * @date   2015年9月13日 下午5:27:37
	 * @param fieldType
	 * @param arg
	 * @return
	 */
	private Object getDefaultArgumentValue(Class<?> fieldType, Object arg) {
		if(this.isBasicDataType(fieldType)) {
			if(fieldType.getName().equals(Boolean.TYPE) ||fieldType.getName().equals(Void.TYPE) ) {
				
			} else {
				arg = 0;
			}
			
		}
		return arg;
	}

	/**
	 * 判定是否为基本数据类型
	 * @author gaoyuandong
	 * @date   2015年9月13日 下午5:12:53
	 * @param fieldType
	 * @return
	 */
	private boolean isBasicDataType(Class<?> fieldType) {
		return fieldType.isPrimitive()?true:false;
	}

	/***
	 * {@link org.dongtian.sys.annotation.DateParser} 注解在方法参数中数据绑定
	 * @author gaoyuandong
	 * @date   2015年9月13日 下午4:19:02
	 * @param parameter
	 * @param mavContainer
	 * @param webRequest
	 * @param binderFactory
	 * @return
	 * @throws ParseException 
	 */
	private Object handlerMethodArgumentDateParserAnnotation(MethodParameter parameter, ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, WebDataBinderFactory binderFactory)  {
		String[] vals = webRequest.getParameterValues(parameter.getParameterName());
		if (vals == null || vals.length == 0) {
			return null;
		}else {
			if (StringUtils.isBlank(vals[0])) {
				return null;
			} else {
				for (Iterator<String> itr = webRequest.getParameterNames(); itr.hasNext();) {
					String next = itr.next();
					log.debug(next + " : " + webRequest.getParameterValues(next)[0]);
				}
				DateParser dateParser = parameter.getParameterAnnotation(DateParser.class);
				String pattern = dateParser.pattern();
				String key = StringUtils.isBlank(dateParser.name()) ? parameter.getParameterName() : dateParser.name();
				// TODO
				log.debug(parameter.getParameterName());
				SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);
				Date date = null;
				try {
					date = dateFormat.parse(webRequest.getParameterValues(parameter.getParameterName())[0]);
				} catch (ParseException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				return date;
			}
			
		}
	}

	/***
	 * 是否存在{@link org.dongtian.sys.annotation.DateParser}注解
	 * @author gaoyuandong
	 * @date   2015年9月13日 下午4:14:05
	 * @param parameter
	 * @return true 存在  false 不存在
	 */
	private boolean findDateParserAnnotationWithArguement(MethodParameter parameter) {
		
		return parameter.getParameterAnnotation(DateParser.class) == null ? false:true;
	}

}
  此类可以解析作用在方法参数上和javabean中的成员变量为date类型上
 下面是作用在方法参数上
@RequestMapping("/index")
	public ModelAndView index(@DateParser(pattern="yyyy-MM-dd")Date createTime,User user, @RequestParam(defaultValue="1")Integer pageNum,@RequestParam(defaultValue="5")Integer pageSize,String userName,String nickName,String email) {
		ModelAndView andView = new ModelAndView("admin/user/index");
		System.err.println(user.getCreateTime());
		Page<User> page = new Page<User>(pageNum,pageSize);
		PageHelper.startPage(page.getPageNum(), page.getPageSize());
		List<User> userList = this.userService.findUserList(userName,nickName,email);
		int  userCount = this.userService.findUserCount(userName,nickName,email);
		page.setTotalCount(userCount);
		page.setList(userList);
		andView.addObject("page", page);
		return andView;
	}
 下面用在java bean上
@RequestMapping("/showDate")
	@ResponseBody
	public JsonResult showDate(User user) {
		
		return null;
	}



 
package org.dongtian.sys.entity;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.dongtian.sys.annotation.DateParser;
import org.springframework.format.annotation.DateTimeFormat;

import com.fasterxml.jackson.annotation.JsonFormat;

/**
 * 用户信息
 * @author gaoyuandong
 * @mailto 466862016@qq.com
 * @date   2015年8月25日 下午7:45:40
 */
public class User {

	private Integer userId;
	private String userName;
	private String password;
	private Integer state;
	private int age;
	private int sex;
	private String address;
	private String mobile;
	private String email;
	private Integer userType;
	private String nickName;
	@DateParser(pattern="yyyy-MM-dd hh:mm:ss")
	private Date createTime;
	private Date updateTime;
	private Date regTime;
	
	private List<Role> roleList = new ArrayList<Role>();
	
	
	//正常
	public final static int USER_STATE_NORMAL = 0;
	//已删除
	public final static int USER_STATE_DELETE = 1;
	//已经被锁定
	public final static int USER_STATE_LOCKED = 2;
	
	
	public Integer getUserId() {
		return userId;
	}
	public void setUserId(Integer userId) {
		this.userId = userId;
	}
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public Integer getState() {
		return state;
	}
	public void setState(Integer state) {
		this.state = state;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public int getSex() {
		return sex;
	}
	public void setSex(int sex) {
		this.sex = sex;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	public String getMobile() {
		return mobile;
	}
	public void setMobile(String mobile) {
		this.mobile = mobile;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
	public String getNickName() {
		return nickName;
	}
	public void setNickName(String nickName) {
		this.nickName = nickName;
	}
	@DateTimeFormat(pattern="yyyy-MM-dd hh:mm:ss")
	@JsonFormat(pattern="yyyy-MM-dd hh:mm:ss")
	public Date getCreateTime() {
		return createTime;
	}
	public void setCreateTime(Date createTime) {
		this.createTime = createTime;
	}
	@DateTimeFormat(pattern="yyyy-MM-dd hh:mm:ss")
	@JsonFormat(pattern="yyyy-MM-dd hh:mm:ss")
	public Date getUpdateTime() {
		return updateTime;
	}
	public void setUpdateTime(Date updateTime) {
		this.updateTime = updateTime;
	}
	@DateTimeFormat(pattern="yyyy-MM-dd hh:mm:ss")
	@JsonFormat(pattern="yyyy-MM-dd hh:mm:ss")
	public Date getRegTime() {
		return regTime;
	}
	public void setRegTime(Date regTime) {
		this.regTime = regTime;
	}
	public Integer getUserType() {
		return userType;
	}
	public void setUserType(Integer userType) {
		this.userType = userType;
	}
	public List<Role> getRoleList() {
		return roleList;
	}
	public void setRoleList(List<Role> roleList) {
		this.roleList = roleList;
	}
	
}
  4、最后我们将我们的自定义方法参数解析器在RequestMappingHandlerAdapter配置
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
	<property name="messageConverters">
		<list>
		<ref bean="mappingJacksonHttpMessageConverter"/>
		</list>
	</property>

	<property name="customArgumentResolvers">
		<list>
			<ref bean="dateHandlerMethodArgumentResolver"/>
		</list>
	</property>

</bean>

<bean id="dateHandlerMethodArgumentResolver" class="org.dongtian.sys.web.context.DateHandlerMethodArgumentResolver"></bean>
这样会更加灵活不得不承认springmcv做的如此强大,给我们更好的扩展接口这样我们不光可以解决日期类型错误,我们还可以把当前登录用户信息当做方法参数等等。


2
2
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics