使用过struts2后感觉最方便的就是这个框架能自动把表单的参数赋值到action里面的对象中
但现在主要使用Spring框架的MVC,虽然也有@ModelAttribute可以使用但是明显感觉不方便。
好吧,那就自己再造一个轮子吧。
原理都知道,就是利用反射进行字段的赋值,下面贴代码
主要类如下:
import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public class MapToEntryConvertUtils { private static Log log = LogFactory.getLog(MapToEntryConvertUtils.class); /** * 缓存类的属性信息 */ private static Map<String,ConvertEntryItem> convertItemCache = new HashMap<String,ConvertEntryItem>(); /** * Map转换为Entry * @param <T> * @param valueMap 泛型类型为<String,Object> * @param entityClass * @param prefix 从map中取值的key为 prefix + attr * @return */ @SuppressWarnings("rawtypes") public static <T> T convert(Map valueMap,Class<T> entityClass,String prefix){ ConvertEntryItem convertItem = convertItemCache.get(entityClass.getName()); if(convertItem == null){ convertItem = ConvertEntryItem.createConvertItem(entityClass); convertItemCache.put(entityClass.getName(), convertItem); } //entityClass 的可访问字段名 List<String> fieldNameList = convertItem.getFieldNameList(); //字段名和对应的set方法映射 Map<String,Method> fieldSetMethodMap = convertItem.getFieldSetMethodMap(); T entity = null; try { entity = entityClass.newInstance(); } catch (InstantiationException e) { log.error("create "+entityClass.getName()+" instance failed, Do it has a empty constructed function ?", e); return null; } catch (IllegalAccessException e) { log.error("create "+entityClass.getName()+" instance failed, Do it has a empty constructed function ?", e); return null; } Object fieldValue = null; Method m; Class<?>[] parameterTypes; Object targetValue; if(prefix == null) prefix = ""; //遍历字段列表,分别调用每个字段的set方法 for(String fieldName: fieldNameList){ fieldValue = valueMap.get(prefix+fieldName); if(fieldValue == null) continue; m = fieldSetMethodMap.get(fieldName); if(m == null) continue; //set方法的参数类型 parameterTypes = m.getParameterTypes(); if(parameterTypes.length != 1) continue; //只支持单个参数的set方法 //如果第一个参数类型和当前类型相同,则直接使用 if(parameterTypes[0].isAssignableFrom(fieldValue.getClass())){ targetValue = fieldValue; }else{ //转换当前的值为目标参数类型 targetValue = ConvertFactory.convert(parameterTypes[0], fieldValue); } if(targetValue != null){ try { //调用set方法进行赋值 m.invoke(entity, targetValue); } catch (Exception e) { log.error("set value failed:{method="+m.getName()+",value="+targetValue+"}", e); } } } return entity; } static class ConvertEntryItem{ private List<String> fieldNameList = new ArrayList<String>(); private Map<String,Method> fieldSetMethodMap = new HashMap<String, Method>(); private ConvertEntryItem(){} public List<String> getFieldNameList() { return fieldNameList; } public Map<String, Method> getFieldSetMethodMap() { return fieldSetMethodMap; } private void parseEntry(Class<?> cls){ Field[] allField = cls.getDeclaredFields(); Method m = null; String methodName; for(Field f: allField){ methodName = f.getName(); methodName = "set"+methodName.substring(0, 1).toUpperCase()+methodName.substring(1); try { //只返回和当前字段类型相符的set方法,不支持多参数以及不同类型的set方法 m = cls.getDeclaredMethod(methodName, f.getType()); if(m != null){ fieldNameList.add(f.getName()); fieldSetMethodMap.put(f.getName(), m); } } catch (SecurityException e) { log.error("parseEntry failed: SecurityException", e); } catch (NoSuchMethodException e) { log.info("NoSuchMethod in "+cls.getName()+": "+methodName); } } } public static ConvertEntryItem createConvertItem(Class<?> cls){ ConvertEntryItem ci = new ConvertEntryItem(); ci.parseEntry(cls); return ci; } } }
转换接口贴上,实话实说,偷的Spring里面的接口
/** * 类型转换接口 * @param <S> 源类型 * @param <T> 目标类型 */ public interface Convert<S,T> { T convert(S source); }
再来个具体调用转换的类:
import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public class ConvertFactory { private static Log log = LogFactory.getLog(ConvertFactory.class); public static Map<String,Convert<?,?>> convertHandlers = new HashMap<String, Convert<?,?>>(); /** * 注册转换器 */ static{ convertHandlers.put(String[].class.getName()+"To"+Float[].class.getName(), new ObjectArrToFloatArrConvert()); convertHandlers.put(String[].class.getName()+"To"+float[].class.getName(), new ObjectArrToFloaArrConvert()); convertHandlers.put(String[].class.getName()+"To"+Double[].class.getName(), new ObjectArrToDoubleArrConvert()); convertHandlers.put(String[].class.getName()+"To"+double[].class.getName(), new ObjectArrToDoublArrConvert()); convertHandlers.put(String[].class.getName()+"To"+Integer[].class.getName(), new ObjectArrToIntegerArrConvert()); convertHandlers.put(String[].class.getName()+"To"+int[].class.getName(), new ObjectArrToIntArrConvert()); convertHandlers.put(String.class.getName()+"To"+Date.class.getName(), new ObjectToDateConvert()); convertHandlers.put(String.class.getName()+"To"+Double.class.getName(), new ObjectToFloatConvert()); convertHandlers.put(String.class.getName()+"To"+double.class.getName(), new ObjectToFloatConvert()); convertHandlers.put(String.class.getName()+"To"+Float.class.getName(), new ObjectToFloatConvert()); convertHandlers.put(String.class.getName()+"To"+float.class.getName(), new ObjectToFloatConvert()); convertHandlers.put(String.class.getName()+"To"+Integer.class.getName(), new ObjectToIntegerConvert()); convertHandlers.put(String.class.getName()+"To"+int.class.getName(), new ObjectToIntegerConvert()); Set<Entry<String, Convert<?,?>>> entites = convertHandlers.entrySet(); StringBuilder b = new StringBuilder(); b.append("{"); for(Entry<String, Convert<?,?>> entry: entites){ b.append(entry.getKey()).append("=").append(entry.getValue()).append(","); } b.append("}"); log.debug("all support convert type: "+b.toString().replaceFirst(",}", "}")); } @SuppressWarnings({ "unchecked", "rawtypes" }) public static <T> T convert(Class<T> clazz,Object val){ Convert cv = convertHandlers.get(val.getClass().getName()+"To"+clazz.getName()); if(cv == null){ log.info(clazz.getName()+"To"+val.getClass().getName()+ " convert failed: unsupport type"); return null; } return (T)cv.convert(val); } }
下面贴出来各种转换实现类:
import org.apache.commons.logging.LogFactory; public class ObjectArrToDoublArrConvert implements Convert<Object[],double[]> { @Override public double[] convert(Object[] source) { if(source == null) return null; double[] res = new double[source.length]; for(int i=0;i<source.length;i++){ try { res[i] = Double.parseDouble(source[i].toString()); } catch (NumberFormatException e) { LogFactory.getLog(getClass()).info("ObjectArrToDoublArrConvert failed, bad value: "+source[i].toString(), e); return null; } } return res; } }
import org.apache.commons.logging.LogFactory; public class ObjectArrToDoubleArrConvert implements Convert<Object[],Double[]> { @Override public Double[] convert(Object[] source) { if(source == null) return null; Double[] res = new Double[source.length]; for(int i=0;i<source.length;i++){ try { res[i] = Double.parseDouble(source[i].toString()); } catch (NumberFormatException e) { LogFactory.getLog(getClass()).info("ObjectArrToDoubleArrConvert failed, bad value: "+source[i].toString(), e); return null; } } return res; } }
import org.apache.commons.logging.LogFactory; public class ObjectArrToFloaArrConvert implements Convert<Object[],float[]> { @Override public float[] convert(Object[] source) { if(source == null) return null; float[] res = new float[source.length]; for(int i=0;i<source.length;i++){ try { res[i] = Float.parseFloat(source[i].toString()); } catch (NumberFormatException e) { LogFactory.getLog(getClass()).info("ObjectArrToFloaArrConvert failed, bad value: "+source[i].toString(), e); return null; } } return res; } }
import org.apache.commons.logging.LogFactory; public class ObjectArrToFloatArrConvert implements Convert<Object[],Float[]> { @Override public Float[] convert(Object[] source) { if(source == null) return null; Float[] res = new Float[source.length]; for(int i=0;i<source.length;i++){ try { res[i] = Float.parseFloat(source[i].toString()); } catch (NumberFormatException e) { LogFactory.getLog(getClass()).info("ObjectArrToFloatArrConvert failed, bad value: "+source[i].toString(), e); return null; } } return res; } }
import org.apache.commons.logging.LogFactory; public class ObjectArrToIntArrConvert implements Convert<Object[],int[]> { @Override public int[] convert(Object[] source) { if(source == null) return null; int[] res = new int[source.length]; for(int i=0;i<source.length;i++){ try { res[i] = Integer.parseInt(source[i].toString()); } catch (NumberFormatException e) { LogFactory.getLog(getClass()).info("ObjectArrToIntArrConvert failed, bad value: "+source[i].toString(), e); return null; } } return res; } }
import org.apache.commons.logging.LogFactory; public class ObjectArrToIntegerArrConvert implements Convert<Object[],Integer[]> { @Override public Integer[] convert(Object[] source) { if(source == null) return null; Integer[] res = new Integer[source.length]; for(int i=0;i<source.length;i++){ try { res[i] = Integer.parseInt(source[i].toString()); } catch (NumberFormatException e) { LogFactory.getLog(getClass()).info("ObjectArrToIntegerArrConvert failed, bad value: "+source[i].toString(), e); return null; } } return res; } }
public class ObjectArrToStringArrConvert implements Convert<Object[],String[]> { @Override public String[] convert(Object[] source) { if(source == null) return null; String[] res = new String[source.length]; for(int i=0;i<source.length;i++){ res[i] = source[i].toString(); } return res; } }
import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.regex.Pattern; import org.apache.commons.logging.LogFactory; /** *支持的日期格式为:<br> *yyyy-MM-dd<br> *yyyy-MM-dd HH:mm<br> *yyyy-MM-dd HH:mm:ss<br> *yyyy/MM/dd<br> *yyyy/MM/dd HH:mm<br> *yyyy/MM/dd HH:mm:ss<br> */ public class ObjectToDateConvert implements Convert<Object,Date> { Object[][] patterns = { {Pattern.compile("^\\d+-\\d+-\\d+$"),"yyyy-MM-dd"}, {Pattern.compile("^\\d+-\\d+-\\d+ \\d+:\\d+$"),"yyyy-MM-dd HH:mm"}, {Pattern.compile("^\\d+-\\d+-\\d+ \\d+:\\d+:\\d+$"),"yyyy-MM-dd HH:mm:ss"}, {Pattern.compile("^\\d+/\\d+/\\d+$"),"yyyy/MM/dd"}, {Pattern.compile("^\\d+/\\d+/\\d+ \\d+:\\d+$"),"yyyy/MM/dd HH:mm"}, {Pattern.compile("^\\d+/\\d+/\\d+ \\d+:\\d+:\\d+$"),"yyyy/MM/dd HH:mm:ss"} }; @Override public Date convert(Object source) { if(source == null) return null; String val = source.toString(); val = val.trim(); String format = null; Pattern p; for(Object[] item:patterns){ p = (Pattern)item[0]; if(p.matcher(val).matches()){ format = item[1].toString(); break; } } if(format == null) { LogFactory.getLog(getClass()).info("ObjectToDateConvert failed, unsupport value: "+source); return null; } try { return new SimpleDateFormat(format).parse(val); } catch (ParseException e) { LogFactory.getLog(getClass()).info("ObjectToDateConvert failed, bad value: "+source,e); return null; } } }
import org.apache.commons.logging.LogFactory; public class ObjectToFloatConvert implements Convert<Object,Float> { @Override public Float convert(Object source) { if(source == null) return null; try { return Float.parseFloat(source.toString().trim()); } catch (NumberFormatException e) { LogFactory.getLog(getClass()).info("ObjectToFloatConvert failed: "+source, e); return null; } } }
import org.apache.commons.logging.LogFactory; public class ObjectToIntegerConvert implements Convert<Object,Integer> { @Override public Integer convert(Object source) { if(source == null) return null; try { return Integer.parseInt(source.toString().trim()); } catch (NumberFormatException e) { LogFactory.getLog(getClass()).info("ObjectToIntegerConvert failed: "+source, e); return null; } } }
使用方法如下:
Map<String,Object> map = new HashMap<String, Object>(); map.put("intVal", "1"); map.put("integerVal", "1"); map.put("floatVal", "1.0"); map.put("doubleVal", "1.0"); map.put("dateVal", "2012-12-12 23:00:00"); map.put("intArr", new String[]{"1","2"}); map.put("integerArr", new String[]{"1","2"}); map.put("strArr", new String[]{"A","B"}); map.put("floatArr", new String[]{"1.0","1.0"}); MapToEntryConvertUtils.convert(map, TestEntry.class, ""); MapToEntryConvertUtils.convert(map, TestEntry.class, "");
第一次转换比较慢,但是第二次因为缓存了类的属性信息所以很快