在工作中我们经常会在mvc框架中遇见只有一个request传递参数给我们,然后我们就会调用request自带的方法getParameter去获取一个String类型的参数,然后根据bean的成员变量类型将String转换成对应数据类型,再调用setXxx方法将参数导入bean里面,一般看见的代码表现形式大都是:
================================================================
String fieldname = (String) request.getParameter("fieldname");
String rate = (String) request.getParameter("rate");
String fixname = (String) request.getParameter("fixname");
String fixNameValue = (String) request.getParameter("fixNameValue");
String cityNo = (String)request.getParameter("cityNo");
String baseName = (String)request.getParameter("baseName");
String down = (String)request.getParameter("down");
================================================================
可以看见这段代码阅读体验极差,不利于开发人员快速上手,需要花大量时间去熟悉类似代码,造成了时间的浪费
在这里我们可以使用java自带的内省API去实现这种繁琐的数据处理方式,如下:
================================================================
User class1 = RequestUtils.getClass(request, User.class);
public static <T> T getClass(HttpServletRequest request,Class<T> clazz) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IntrospectionException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException, SecurityException, ParseException {
if(request==null || clazz==null ){
return null;
}
T t = clazz.newInstance();
Class<?> cl = Class.forName(clazz.getName());
BeanInfo beaninfo = Introspector.getBeanInfo(cl, Object.class);
PropertyDescriptor[] pro = beaninfo.getPropertyDescriptors();
for (PropertyDescriptor propertyDescriptor : pro) {
Method writeme = propertyDescriptor.getWriteMethod();
if(!StringUtils.isEmpty(request.getParameter(propertyDescriptor.getName())) ){
String fieldType = cl.getDeclaredField(propertyDescriptor.getName()).getType().getName();
if("java.lang.Integer".equals(fieldType)) {
writeme.invoke(t,Integer.valueOf(request.getParameter(propertyDescriptor.getName())) );
}else if("java.lang.String".equals(fieldType)) {
writeme.invoke(t,request.getParameter(propertyDescriptor.getName()));
}else if("java.lang.Long".equals(fieldType)) {
String s = request.getParameter(propertyDescriptor.getName());
writeme.invoke(t,Long.valueOf(s));
}else if("java.lang.Double".equals(fieldType)) {
String s = request.getParameter(propertyDescriptor.getName());
writeme.invoke(t,Double.valueOf(s));
}else if("java.util.Date".equals(fieldType)) {
String s = request.getParameter(propertyDescriptor.getName());
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
writeme.invoke(t,sdf.parse(s));
}else {
// 不支持复杂类型
}
}
}
return t;
}
================================================================
上面我们将request和User的class对象传入getClass方法中,进入getClass方法,先进行参数的判断,然后进入代码逻辑;
根据class对象我们调用newInstance方法实现实例化,更好地利用泛型实现强转操作,尽量避免程序员手动去强转;
之后通过Class.forName方法去获取一个class对象
这时候我们就可以调用java提供的内省API(beaninfo.getPropertyDescriptors)取cl(bean)所有的变量了,包括private修饰的成员变量,这时候成员变量被包装到PropertyDescriptor对象里面,通过for循环我们从PropertyDescriptor中获取到Method对象根据成员变量名去request里面获取到String类型的参数,之后调用invoke方法等同调用setXxx方法传入参数,在这里根据成员变量类型做出判断,会对数据进行转换存入t对象中最后将t返回,我们就完成了一个反射的流程。
反射的功劳,如果没有反射很难想象如果完成同样的功能会有多么难!但是反射也有缺点,比如性能比较低、安全性比较复杂等,这里就不在讨论这些东西,后面有时间我会详细讲下new的各种姿势以及优缺点