使用过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 convertItemCache = new HashMap();
/**
* Map转换为Entry
* @param
* @param valueMap 泛型类型为
* @param entityClass
* @param prefix 从map中取值的key为 prefix + attr
* @return
*/
@SuppressWarnings("rawtypes")
public static T convert(Map valueMap,Class entityClass,String prefix){
ConvertEntryItem convertItem = convertItemCache.get(entityClass.getName());
if(convertItem == null){
convertItem = ConvertEntryItem.createConvertItem(entityClass);
convertItemCache.put(entityClass.getName(), convertItem);
}
//entityClass 的可访问字段名
List fieldNameList = convertItem.getFieldNameList();
//字段名和对应的set方法映射
Map 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 fieldNameList = new ArrayList();
private Map fieldSetMethodMap = new HashMap();
private ConvertEntryItem(){}
public List getFieldNameList() {
return fieldNameList;
}
public Map 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 源类型
* @param 目标类型
*/
public interface Convert {
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> convertHandlers = new HashMap>();
/**
* 注册转换器
*/
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>> entites = convertHandlers.entrySet();
StringBuilder b = new StringBuilder();
b.append("{");
for(Entry> 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 convert(Class 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
import org.apache.commons.logging.LogFactory;
public class ObjectArrToDoubleArrConvert implements Convert
import org.apache.commons.logging.LogFactory;
public class ObjectArrToFloaArrConvert implements Convert
import org.apache.commons.logging.LogFactory;
public class ObjectArrToFloatArrConvert implements Convert
import org.apache.commons.logging.LogFactory;
public class ObjectArrToIntArrConvert implements Convert
import org.apache.commons.logging.LogFactory;
public class ObjectArrToIntegerArrConvert implements Convert
public class ObjectArrToStringArrConvert implements Convert
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.regex.Pattern;
import org.apache.commons.logging.LogFactory;
/**
*支持的日期格式为:
*yyyy-MM-dd
*yyyy-MM-dd HH:mm
*yyyy-MM-dd HH:mm:ss
*yyyy/MM/dd
*yyyy/MM/dd HH:mm
*yyyy/MM/dd HH:mm:ss
*/
public class ObjectToDateConvert implements Convert
import org.apache.commons.logging.LogFactory;
public class ObjectToFloatConvert implements Convert
import org.apache.commons.logging.LogFactory;
public class ObjectToIntegerConvert implements Convert
使用方法如下:
Map map = new HashMap();
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, "");
第一次转换比较慢,但是第二次因为缓存了类的属性信息所以很快