使用前提:
使用反射机制封装赋值操作,前提是dto中的属性名和表单提交的name字段是完全一样的。
问题描述:
封装页面数据到dto中时,比如增加和修改商品表是相同的操作,对商品表和用户表的增加和修改可能也是相同的需要,所以为了提高代码的复用性和方便处理相同的业务逻辑,有必要有一个方法,根据用户传递的实体类,可以自动装配实体类和表单中数据的对应关系。
解决步骤:
1.需要获得表单中提交的数据,封装为一个数据集
2.获取JavaBean中的所以set方法并封装为集合
3.根据JavaBean中的set方法和表单中的name字段进行类型匹配,即两个字符串完全一致时才可以进行赋值
实现方法的工具类:DtoSetUtils类
package org.jiazhong.demo.service;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.jiazhong.dao.DaoException;
public class DtoSetUtils {
//给用户提供的调用接口,用户只需要将赋值的JavaBean和req传递过来,即可自动完成赋值操作
public static <T> T getBeanFromRequest(Class<T> beanClass,HttpServletRequest req) throws Exception {
List<Method> setMds = getSetMds(beanClass);
// 截取到不包含set的方法名
List<String> lists = getSubAttr(setMds);
return setMyParameter(setMds, lists, req, beanClass);
}
//获得实体类的set方法名称
private static <T> List<Method> getSetMds(Class<T> beanClass) {
List<Method> list = new ArrayList<Method>();
Method[] mds = beanClass.getMethods();// 获取元类对象所描述类的所有public方法的描述对象
for (Method md : mds) {
String mdName = md.getName();// 获取方法名称
if (mdName.startsWith("set") && mdName.length() > 3 && md.getParameterCount() == 1
&& Character.isUpperCase(mdName.charAt(3))) {
list.add(md);
}
}
return list;
}
//set方法名称小写,方便在request.getParameter(String)时调用
private static List<String> getSubAttr(List<Method> setMds) {
List<String> list = new ArrayList<String>();
for (Method setmd : setMds) {
String name = setmd.getName().substring(3).toLowerCase();
list.add(name);
}
return list;
}
/**
* 执行赋值操作前需要判断值的类型是什么,如果是字符串则可以直接赋值
* 如果是字符串数字就需要转换为数字,如Integer.parseInt()等,所以
* 在判断之后,才可以赋值
* @param <T>:泛型的类型
* @param argType:参数的类型
* @param value:参数值
* @return
*/
private static <T> T getValue(Class<T> argType, String value) {
if (argType.equals(String.class)) {
return (T) value;
} else if (argType.equals(Integer.class) || argType.equals(int.class)) {
return (T) Integer.valueOf(value);
} else if (argType.equals(Byte.class) || argType.equals(byte.class)) {
return (T) Byte.valueOf(value);
} else if (argType.equals(Short.class) || argType.equals(short.class)) {
return (T) Short.valueOf(value);
} else if (argType.equals(Long.class) || argType.equals(long.class)) {
return (T) Long.valueOf(value);
} else if (argType.equals(Float.class) || argType.equals(float.class)) {
return (T) Float.valueOf(value);
} else if (argType.equals(Double.class) || argType.equals(double.class)) {
return (T) Double.valueOf(value);
} else if (argType.equals(Boolean.class) || argType.equals(boolean.class)) {
return (T) Boolean.valueOf(value);
} else
throw new DaoException(argType + "类型暂时不匹配");
}
/**
* 处理赋值操作的主业务
* @param <T>:泛型的类型
* @param setMds:获取的所有set方法
* @param lists:获取表单input提交的name名称
* @param req:请求
* @param clazz:元类
* @return
* @throws Exception
*/
private static <T> T setMyParameter(List<Method> setMds, List<String> lists, HttpServletRequest req, Class<T> clazz) throws Exception {
//获取对象的无参构造方法,创建一个对象
T bean = clazz.getConstructor().newInstance();
for (Method setMd : setMds) {
for (String list : lists) {
/**
* 获取JavaBean中的set方法但是不包含set的方法和表单中的name进行忽略大小写比较
*/
if (!list.isEmpty() && setMd.getName().substring(3).equalsIgnoreCase(list)) {
try {
//获取表单中name值
String strValue = req.getParameter(list);
/**
* 防止有一些数据用户根本就没有添加,而进行赋值操作时出现空指针异常
*/
if (strValue != null) {
// 根据set方法的参数类型,将字符串参数转换为set方法参数类型
Object value = getValue(setMd.getParameterTypes()[0], strValue);
/**如:dto.setName(req.getParameter("name))
* 执行invoke方法
* setMd表示执行invoke的方法名,相当于setName
* bean表示执行invoke的setMd方法所属的具体类,相当于dto
* val表示赋的值,相当于req.getParameter(参数名)
*/
setMd.invoke(bean, value);
}
} catch (Exception e) {
}
}
}
}
/**
* 执行完毕要将bean返回,相当于调用者现在要使用杯子接杯水,将这个
* 操作给了执行者,执行者使用这个杯子接满水之后需要将杯子给他的调用者
* 否则调用者不知道你是否给我接没接
*/
return bean;
}
}
调用工具类:
GoodsDto gd = DtoSetUtils.getBeanFromRequest(GoodsDto.class, req);
备注:
具体的dto和页面就不在此赘述了,这个工具完全使用于任何赋值的场景中。
出现的问题1:
遇到的问题可以获得set方法,表单中的数据也可以得到,但是在使用反射机制,执行invoke方法时候发现,不能赋值。
解决在工具类中已经做出详细结束,invoke(Object,args)方法的第一个参数是执行invoke的方法所属的对象,注意是对象,而不是其他什么。
出现的问题2:
获取set方法和传递表单中的数据都没有问题,但是在执行赋值操作时出错,日志记录显示的信息是sql语句获得的参数为空,即没有给dto中的属性赋值,其实就是没有没有将处理的结果返回给调用者,自己创建了一个对象。
还是借用前面接水的例子,调用者给了个杯子让接杯水,结果执行者自己造了个杯子接满水,并且还不将杯子给调用者,所以肯定得到null值。