您的位置:首页 > 编程语言 > Java开发

[ JAVA ] 通过反射动态解析实例对象

2018-02-27 16:47 281 查看

通过反射动态解析实例对象

代码背景

1、人员信息导出为Excel的时候,简化操作步骤,直接通过解析数据对象Do的成员变量作用域来生成Excel的数据
2、人员信息Excel导入的时候,直接通过成员变量名逆向拼装获取Set方法,自动封装数据对象Do,以便保存到数据库中
3、以上操作的复用,针对不同类别的人员,相似的操作可以通过修改极少量的代码来实现功能


一、利用反射解析数据对象Do成员变量(PrisonMemberDo)

/**
* 导出
*
* @param memberQo
* @return
*/
@Override
public String export(PrisonMemberQo memberQo) throws BusinessException {

final List<PrisonMemberDo> prisonMemberDoList = prisonMemberMapper.query(memberQo);

final List<List<String>> exportList = getExportList(prisonMemberDoList);
final String folderPath = propertyConfig.get("export.url", "/icooper/appdata/hbsf/export/");
final String fileName = ExportConstants.FILE_NAME_PRISON_MEM + ExportConstants.UNDER_LINE + TimeUtils.currTime1()
+ SCConstants.FMT_XLS;
final String filePath = folderPath + fileName;
final ExportExcel ex = new ExportExcel(ExportConstants.TITLE_PRISON_MEM, ExportConstants.HEADER_PRISON_MEM, exportList,
folderPath, fileName);
try {
ex.export();
} catch (final Exception e) {
log.error("服刑人员导出失败", e);
throw new BusinessException("服刑人员导出失败");
}
return filePath;
}

//省略部分代码...

/**
* 导出数据解析
*
* @param dataList
* @return
*/
private List<List<String>> getExportList(List<PrisonMemberDo> dataList) {
final List<List<String>> exportList = new ArrayList<List<String>>();
int rowNo = 0;
for (final PrisonMemberDo prisonMemberDo : dataList) {
final List<String> rowData = new ArrayList<String>();
rowNo += 1;
rowData.add(String.valueOf(rowNo));
autoFillRowData(rowData, prisonMemberDo, PrisonMemberDo.class);
exportList.add(rowData);
}
return exportList;
}

/**
* 利用反射批量解析字段
*
* @param rowData
* @param o
* @param c
*/
private void autoFillRowData(List<String> rowData, Object o, Class<PrisonMemberDo> c) {
Field[] fields = c.getDeclaredFields();
// 循环遍历字段,获取字段相应的属性值
for (Field field : fields) {
// 假设不为空。设置可见性,然后返回
field.setAccessible(true);
try {
// 设置字段可见,就可以用get方法获取属性值。
if (!field.getName().equals("id")) {
//特殊字段处理数据库中保存的是int,根据字典表切换为对应汉字
if (field.getType() == Date.class) {
rowData.add(sdf.format(new Date(field.get(o).toString())));
} else if (codeMap.get(field.getName()) != null) {
CodeDo code = codeMapper.parserCodeName(codeMap.get(field.getName()), field.get(o).toString());
rowData.add(code == null ? "未定义" : code.getCodeName());
} else {
rowData.add(field.get(o).toString());
}
}
} catch (Exception e) {
log.error("反射获取导出对象的成员域失败!", e);
}
}
}


二、利用反射动态封装数据对象Do成员变量(PrisonMemberDo)

/**
* 人员导入
*
* @param file
* @return
*/
@Override
public Integer upload(MultipartFile file) {
Sheet sheet = null;
try {
sheet = POIUtils.parseSheet(file, 0);
} catch (final java.io.IOException e) {
e.printStackTrace();
}
int num = 0;
for (int i = 3; i <= sheet.getLastRowNum(); i++) {
final Row row = sheet.getRow(i);
if (null != row && row.getCell(0) != null && StringUtils.notEmpty(row.getCell(0).toString())) {
num = parserExcel(row, num);
}
}
return num;
}
/**
* 解析Excel文件
*
* @param row
* @param num
* @return
*/
private int parserExcel(Row row, int num) {
final PrisonMemberDo memberDo = new PrisonMemberDo();
try {
final String name = POIUtils.parseStr(row.getCell(2));
final String memCode = POIUtils.parseStr(row.getCell(1));
if (StringUtils.isEmpty(memCode) || StringUtils.isEmpty(name)) {
return num;
}
if(prisonMemberMapper.selectSameCode(memCode) != null){
return num;
}
Field[] fields = memberDo.getClass().getDeclaredFields();
int cellIndex = 0;
String cellVal = "";
// 循环遍历字段,获取字段相应的属性值
for (Field field : fields) {
// 假设不为空。设置可见性,然后返回
field.setAccessible(true);
cellVal = POIUtils.parseStr(row.getCell(cellIndex));
try {
// 设置字段可见,就可以用get方法获取属性值。
if (!field.getName().equals("id")&&!field.getName().equals("updatetime")) {
//特殊类型特殊处理 Date的日期格式限定为'yyyy-MM-dd',字典表汉字向数字转化
if (field.getType() == Date.class) {
getSetMethod(memberDo.getClass(), field.getName()).invoke(memberDo, new Object[]{sdf.parse(cellVal)});
} else if (codeMap.get(field.getName()) != null) {
CodeDo code = codeMapper.parserCodeVal(codeMap.get(field.getName()), POIUtils.parseStr(row.getCell(cellIndex)));
if(code!=null){
getSetMethod(memberDo.getClass(), field.getName()).invoke(memberDo, new Integer[]{Integer.parseInt(code.getCode().toString())});
}
} else {
getSetMethod(memberDo.getClass(), field.getName()).invoke(memberDo, new Object[]{cellVal});
}
}
} catch (Exception e) {
log.error("反射获取并解析对象的成员域失败!", e);
}
cellIndex++;
}
memberDo.setUpdatetime(new Date());
prisonMemberMapper.insertSelective(memberDo);
num++;
return num;
} catch (final Exception e) {
log.error("解析Excel表格失败!", e);
return num;
}
}
/**
* 根据成员变量名获取对应set方法
* @param objectClass
* @param fieldName
* @return
*/
public static Method getSetMethod(Class objectClass, String fieldName) {
try {
Class[] parameterTypes = new Class[1];
Field field = objectClass.getDeclaredField(fieldName);
parameterTypes[0] = field.getType();
StringBuffer sb = new StringBuffer();
sb.append("set");
sb.append(fieldName.substring(0, 1).toUpperCase());
sb.append(fieldName.substring(1));
Method method = objectClass.getMethod(sb.toString(), parameterTypes);
return method;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}


备注:

1、成员变量的动态解析需要注意Excel的头部数据定义顺序和成员变量顺序是否一致,如果不一致,会导致数据封装异常!对于自定义的字段需要跨过(like:序号)

2、对于占位符和标题需要跨过,cell的下标起始点应与实际Excel中有效数据保持一致,如果Excel中未展示数据库中所有字段,需根据成员变量名做过滤。

Excel头部定义


public static final String FILE_NAME_PRISON_MEM = "司法厅服刑人员信息";
public static final String TITLE_PRISON_MEM = "司法厅服刑人员信息";
public static final String[] HEADER_PRISON_MEM = new String[] { "序号", "编码","姓名","组织编码","部门名称","性别","民族","出生日期", "证件类型","证件号码","文化程度", "原政治面貌",
"户籍所在地","固定居住地","家庭电话","移动电话","婚姻状况","判决书号","判决机关","判决日期","罪名","刑种","原判刑期","刑期起始日期","刑期结束日期","附加刑",
"刑期变动","曾受惩处","主要联系人","主要联系人地址","主要联系人电话","相互关系","备注", "更新时间" };


数据对象Do


package cn.showclear.www.pojo.base;

import java.util.Date;

public class PrisonMemberDo {
/** ID */
private Integer id;

/** 编码(可唯一标识) */
private String code;

/** 姓名 */
private String name;

/** 组织编码 */
private String orgCode;

/** + 部门名称 */
private String  deptName;

/** 性别(1:男 2“女) */
private Integer sex;

/** 民族 */
private String nation;

/** 出生日期 */
private Date birthDate;

/** 证件类型,包括1(居民身份证)、2(军人身份证件)、3(武警身份证件)、9(其他)。 */
private Integer paperType;

/** 证件号码 */
private String paperNumber;

/** 文化程度(1:文盲 2:小学 3:初中 4:高中(含中专,技校)5:大专  6:本科  7:硕士  8 :博士  9:其他) */
private Integer degreeType;

/** 原政治面貌(1:中共党员 :2:中共预备党员 3:共青团员 :4:民革党员 5:民盟盟员 6:民建会员 7:民进会员 8:农工党党员 9:致公党党员 10:九三学社社员 11:台盟盟员 12:群众) */
private Integer politicalStatusOld;

/** 户籍所在地 */
private String registerAddress;

/** 固定居住地 */
private String fixedAddress;

/** 家庭电话 */
private String homePhone;

/** 移动电话 */
private String mobilePhone;

/** 婚姻状况(1:未婚 2:已婚 3:离异 4:丧偶) */
private Integer maritalStatus;

/** 判决书号 */
private String sentenceNumber;

/** 判决机关 */
private String sentenceUnit;

/** 判决日期 */
private Date sentenceDate;

/** 罪名 */
private String charge;

/** 刑种(1:死缓 2:无期 3:有期 4:拘役 5:管制) */
private Integer punishmentKind;

/** 原判刑期 */
private String prisonTerm;

/** 刑期起始日期 */
private Date prisonBeginDate;

/** 刑期结束日期 */
private Date prisonEndDate;

/** 附加刑 */
private String punishmentOther;

/** 刑期变动 */
private String punishmentChange;

/** 曾受惩处 */
private String punished;

/** 主要联系人 */
private String mainContactName;

/** 主要联系人地址 */
private String mainContactAddr;

/** 主要联系人电话 */
private String mainContactTel;

/** 相互关系 */
private String interrelation;

/** 备注 */
private String remark;

/** 更新时间 */
private Date updatetime;

public PrisonMemberDo() {
}

//...get && set

}


三、反射实例

遍历成员变量

/**
* 利用反射批量解析字段
*
* @param rowData
* @param o
* @param c
*/
private void autoFillRowData(List<String> rowData, Object o, Class<PrisonMemberDo> c) {
Field[] fields = c.getDeclaredFields();
// 循环遍历字段,获取字段相应的属性值
for (Field field : fields) {
// 假设不为空。设置可见性,然后返回
field.setAccessible(true);
try {
// 设置字段可见,就可以用get方法获取属性值。
if (!field.getName().equals("id")) {
if (field.getType() == Date.class) {
rowData.add(sdf.format(new Date(field.get(o).toString())));
} else if (codeMap.get(field.getName()) != null) {
CodeDo code = codeMapper.parserCodeName(codeMap.get(field.getName()), field.get(o).toString());
rowData.add(code == null ? "未定义" : code.getCodeName());
} else {
rowData.add(field.get(o).toString());
}
}
} catch (Exception e) {
log.error("反射获取导出对象的成员域失败!", e);
}
}
}


获取Set和Get方法

/**
* java反射bean的get和set方法
*
* @param objectClass
* @param fieldName
* @param fnType "get" or "set"
* @return
*/
@SuppressWarnings("unchecked")
public static Method getFnMethod(Class objectClass, String fieldName,String fnType) {
StringBuffer sb = new StringBuffer();
sb.append(fnType);
sb.append(fieldName.substring(0, 1).toUpperCase());
sb.append(fieldName.substring(1));
try {
return objectClass.getMethod(sb.toString());
} catch (Exception e) {

}
return null;
}


执行set或get方法

/**
* 执行方法
*
* @param o 执行对象
* @param fieldName 属性
* @param value 值
* @param fnType "get" or "set"
*/
public static void invokeFn(Object o, String fieldName, Object value,String fnType) {
Method method = getFnMethod(o.getClass(), fieldName,fnType);
try {
//指定对象的成员类型,可以切换Object为对应类型进行Set和Get
method.invoke(o, new Object[] { value });
} catch (Exception e) {
e.printStackTrace();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: