前言:
Lrmx文件本质就是读取xml文件,数据库字段设计和类的属性设计都xml中节点保持了一致。那么就可以用类的反射来实现给字段赋值,这样可以大大节省代码的编写量。
一、加载文件并遍历所有的节点:
File f = new File(this.LrmxFilePath);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// 创建一个DocumentBuilder对象
DocumentBuilder builder = factory.newDocumentBuilder();
// 使用DocumentBuilder对象的parse方法解析XML文件,得到一个Document对象
org.w3c.dom.Document document = builder.parse(f);
// 获取根节点
Element root = document.getDocumentElement();
NodeList nl = root.getChildNodes();
使用记事本打开lrmx文件,我们可以看到我们需要的内容都在Person节点的子节点下,除了家庭成员外信息还有子节点,其他包括简历、考核情况、奖惩都是放在一个子节点信息里面。
二、通过反射给对象赋值
遍历所有子节点,对于简历、家庭成员做特殊处理。Person 是定义的类,属性就是对应所有节点。另外还定义有类 JianLi ,JiaTingChengYuan 对于奖惩记录和 年度考核结果这里暂时不做处理。
1. 遍历子节点,对于子节点名称不是 #text 的做处理
for (int i = 0; i < nl.getLength(); i++) { //循环遍历
if (!nl.item(i).getNodeName().equals("#text") ) {
//只处理节点名称不是 #text 的
//后续处理逻辑放在此处
}
}
2. 通过反射获取属性的set方法
String name = nl.item(i).getNodeName();
Field field = p.getClass().getDeclaredField(name);
name = name.substring(0, 1).toUpperCase() + name.substring(1);
Method m = p.getClass().getDeclaredMethod("set" + name, field.getType());
属性的set方法都是 set + 属性名称,属性名称第一个字符需要大写。通过类的.getClass().getDeclareField(name) 获取到属性, 通过 getClass().getDeclaredMethod("set" +name, field.getType()) 来获取到方法,在通过调用invoke方法来给类实体赋值。
m.invoke(p, nl.item(i).getTextContent());
3. 简历的处理:
正常填写一行就是一段简历,对应数据库中简历表就是一条记录。首先定义一个list用来存放建立的记录了。
List<JianLi> jianLiList = new ArrayList<>();
定义一个字符串,用来接收xml中建立内容
String JianLi = nl.item(i).getTextContent();
如果正常填写,那么用换行符“\n” 既可以那倒1行行简历的数据。但是也存在有不正常的现象,往往会一行经历显示不全,那么就会分成两行,如果用“\n”换行,会错误的认为是两条经历,而实际上是上一条经历没有写完,这里就要做个特殊处理了。我的处理是,正常简历一行记录的开头是以年开始如:
那么就判断拿到的行数据不是以数字开头,就判断位上一条经历没有写完,需要把这行内容补充回上一条经历。
处理建立还有一个难点就是需要分割出 起始日期以及工作经历。首先用空格进行分割,认为空格前面的就是起止时间,后面的就是经历。起止时间通过“-” 或者“--” 来做分割,前面的是开始,后面的是截止。 对于最后一段经历,终止时间是空或者些至今.那么久截止日期设置为空即可,对于日期这里的处理需要根据不同情况来做if处理了.
4. 家庭成员信息的处理:
这里本身填写的时候就是一行一行的, 不知道为什么这么多版本的简历填写不能做下规范,家庭成员的处理就没有太多特别的. 就是JiaTingChengYuan 这个节点再去遍历他的子节点,同样是用反射的手段来给类赋值. 其中对于出生年月的填写要做些判断了.
if (name.equals("JiaTingChengYuan")) {
//家庭成员信息
NodeList nl2List = nl.item(i).getChildNodes();
List<JiaTingChengYuan> jtcyList = new ArrayList<>();
for (int j = 0; j < nl2List.getLength(); j++) {
if (!nl2List.item(j).getNodeName().equals("#text")) {
JiaTingChengYuan jtcy = new JiaTingChengYuan();
NodeList nl3 = nl2List.item(j).getChildNodes();
for (int k = 0; k < nl3.getLength(); k++) {
if (!nl3.item(k).getNodeName().equals("#text")) {
String name2 = nl3.item(k).getNodeName();
Field field2 = jtcy.getClass().getDeclaredField(name2);
name2 = name2.substring(0, 1).toUpperCase() + name2.substring(1);
Method m2 = jtcy.getClass().getDeclaredMethod("set" + name2, field2.getType());
m2.invoke(jtcy, nl3.item(k).getTextContent().trim());
}
}
jtcy.setChuShengRiQi(jtcy.getChuShengRiQi().trim().replaceAll("\n",""));
if (!jtcy.getChuShengRiQi().equals("") && ( jtcy.getChuShengRiQi().length() == 6 || jtcy.getChuShengRiQi().length() == 8)) {
jtcy.setNianLing(JiSuanNianLing(p, jtcy.getChuShengRiQi()));
}
jtcyList.add(jtcy);
}
}
p.setJiaTingChengYuan(jtcyList);
}
三、完整的for循环处理代码:
for (int i = 0; i < nl.getLength(); i++) {
if (!nl.item(i).getNodeName().equals("#text") ) {
String name = nl.item(i).getNodeName();
Field field = p.getClass().getDeclaredField(name);
name = name.substring(0, 1).toUpperCase() + name.substring(1);
Method m = p.getClass().getDeclaredMethod("set" + name, field.getType());
if (!name.equals("JianLi") && !name.equals("JiaTingChengYuan")) { //简历和家庭成员需要做特殊的处理
if(nl.item(i).getTextContent().trim().equals("\r\n") || nl.item(i).getTextContent().trim().equals("\n") || nl.item(i).getTextContent().equals("\n ") ){
m.invoke(p,"");
}else{
m.invoke(p, nl.item(i).getTextContent());}
}
if (name.equals("JianLi")) {
List<JianLi> jianLiList = new ArrayList<>();
String JianLi = nl.item(i).getTextContent();
int rowNums =0;
String[] JianLiArrayTmp = JianLi.split("\n"); //调试表明用的\n
List<String> JianLiArray = new ArrayList<>();
for (String s: JianLiArrayTmp){
if(!s.replaceAll("\n","").trim().equals("")){
JianLiArray.add(s);
}
}
for (String line : JianLiArray) {
if (!line.trim().equals("")) {
if(!Tools.isStartWithNumber(line.trim())){ //如果行不是以数字开头那么就将简历附加到上一条
jianLiList.get(rowNums -1).setJingLi(jianLiList.get(rowNums -1).getJingLi() + " " + line.trim());
continue;
}
JianLi jl = new JianLi();
String[] partArray = line.split(" ");
int tmpNum = 0;
String jingli = "";
for (String s : partArray) {
if(tmpNum ==0){
//第一列分割的用来做时间拆分
String[] a ;
a = s.split("--|——");
if(a.length ==1){
a = s.split("-|—");
}
jl.setKaiShiNianYue(a[0].trim());
if(a.length ==1){
jl.setJieSuNianYue("");
}else{
jl.setJieSuNianYue(a[1].trim());
}
tmpNum ++ ;
}else{
//且他都用来做经历
jingli +=s.trim();
}
}
jl.setJingLi(jingli);
jianLiList.add(jl);
rowNums ++;
}
}
p.setJianLi(jianLiList);
}
if (name.equals("JiaTingChengYuan")) {
//家庭成员信息
NodeList nl2List = nl.item(i).getChildNodes();
List<JiaTingChengYuan> jtcyList = new ArrayList<>();
for (int j = 0; j < nl2List.getLength(); j++) {
if (!nl2List.item(j).getNodeName().equals("#text")) {
JiaTingChengYuan jtcy = new JiaTingChengYuan();
NodeList nl3 = nl2List.item(j).getChildNodes();
for (int k = 0; k < nl3.getLength(); k++) {
if (!nl3.item(k).getNodeName().equals("#text")) {
String name2 = nl3.item(k).getNodeName();
Field field2 = jtcy.getClass().getDeclaredField(name2);
name2 = name2.substring(0, 1).toUpperCase() + name2.substring(1);
Method m2 = jtcy.getClass().getDeclaredMethod("set" + name2, field2.getType());
m2.invoke(jtcy, nl3.item(k).getTextContent().trim());
}
}
jtcy.setChuShengRiQi(jtcy.getChuShengRiQi().trim().replaceAll("\n",""));
if (!jtcy.getChuShengRiQi().equals("") && ( jtcy.getChuShengRiQi().length() == 6 || jtcy.getChuShengRiQi().length() == 8)) {
jtcy.setNianLing(JiSuanNianLing(p, jtcy.getChuShengRiQi()));
}
jtcyList.add(jtcy);
}
}
p.setJiaTingChengYuan(jtcyList);
}
}
总结:
在这种属性繁多,如果一一些set那么代码量会很多。通过反射的功能,能够大大节约代码量。后续很多处理主要是考虑到一些录入场景不规范的问题的处理了。