excel导入导出优化

对于上一篇excel中出现的问题,在excel导入导出中都做了优化.还是eclipse+jdk1.8,但是这个项目是一个web项目,需要配合Tomcat服务器,并且使用了SSH框架,

I/O操作过多

首先,对于I/O操作过多,那么就不像之前一样,一条一条的添加或者更新;而且凑齐一堆,也就是一个list集合,然后统一的批量保存.

使用SessionFactory获取当前的session,然后调用session的persist方法,保存实体.只是设置了一个批量的量值.每到30条数据,就将缓存同步到数据库中.

	/**
	 * 批量保存
	 */
	@Override
	public  boolean saveEntitys(List entitys) {
		boolean flag = false;
		int batchCount = 30;
		try {
			for (int i = 1; i <= entitys.size(); i++) {
				getSession().persist(entitys.get(i - 1));
				if (i % batchCount == 0) {
					getSession().flush();
					getSession().close();
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		return flag;
	}

Excel中英文

然后是excel模板必须固定,不能更换列的顺序,且是英文字段的问题.excel模板必须固定是因为我们没有从excel中获取表头,并记录每个表头是在那一列,这样就可以根据表头中的值,知道列号,然后根据列号去相应的列中取值.

// 将列名和列号放入Map中,这样下面通过列名就能获取列号,
LinkedHashMap colNameNoMap = new LinkedHashMap();
for (int i = 0; i < excelFiledNameArray.length; i++) {
	colNameNoMap.put(excelFiledNameArray[i],
			headerRow[i].getColumn());
}

而英文问题,需要有一个中文对照表,这里就将中文和英文的对照表放到xml文件中.在WebContent文件夹下,放着studentImport.xml的配置文件.内容就是如下,这里面设置了需要导入的excel的实体,导入的excel中的Sheet名称,以及导入的普通字段是中英文对照哪些,主外键关联的字段是哪些(目前还没弄出来),以及唯一不可重复的字段是哪些.而这些配置了的字段,不论是普通字段,主外键关联字段还是唯一键字段都是excel中必须存在的字段的





	
		
		
			
			
			
			
			
		
		

		
		
			
			
		
		
	

而我们需要做的就是用Jdom或者Dom4j工具,读取这个xml文件,获取根节点importExcel,以及他的子节点Entity,可以是多个.并且Entity中的属性,是什么也要获取到.用entityName可以反射出实体的实例,而子节点NormalFieldMaps和UniqueFieldMaps可以将里面的中英文字段对照表放到map中,以及放到list中.只需要解析NormalField节点的属性name和code,以及UniqueField的name属性.

	// 记录普通节点
	private LinkedHashMap normalFieldMap;
	// 记录唯一节点
	private List uniqueFieldList;
	// 数组的形式记录唯一节点
	private String[] uniqueFieldArray = null;

	/******************** 解析{导入xml}到map中 start *******************************/
	/**
	 * 将导入的excel解析
	 * 
	 * @param inXMLFile
	 */
	private void importExcelXml2Map(InputStream inXMLFile) {

		try {
			// 1.检测
			if (null == inXMLFile) {
				throw new FileNotFoundException();
			}

			// 2.解析,使用dom4j
			SAXReader reader = new SAXReader();
			Document doc = reader.read(inXMLFile);
			// 根元素,importExcel
			Element root = doc.getRootElement();

			// 3.获取Entity节点
			Iterator iterator = root.elements("Entity").iterator();
			while (iterator.hasNext()) {
				Element entityElement = (Element) iterator.next();
				// 3.1.获取属性,entityName,以及导入的实体
				String entityName = entityElement.attributeValue("entityName");
				entityClazz = Class.forName(entityName);

				// 实例化,普通字段的map和唯一字段的list,用于放xml中的值
				// 链表的Map,空间不连续,添加,修改,删除快,读不快
				normalFieldMap = new LinkedHashMap();
				uniqueFieldList = new ArrayList();

				// 解析普通字段节点
				parseEntityNormalFieldMaps(entityElement);
				// 解析唯一字段节点
				parseEntityUniqueFieldMaps(entityElement);
			}

		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	/**
	 * 解析普通字段的Map集合节点
	 * 
	 * @param entityElement
	 */
	private void parseEntityNormalFieldMaps(Element entityElement) {
		if (null != entityElement) {
			Iterator iterator = entityElement.elements("NormalFieldMaps")
					.iterator();
			while (iterator.hasNext()) {
				Element normalFiledMapsElement = (Element) iterator.next();
				parseNormalFieldMaps(normalFiledMapsElement);
			}
		}
	}

	/**
	 * 解析普通字段,在Map集合下的
	 * 
	 * @param normalFiledMapsElement
	 */
	private void parseNormalFieldMaps(Element normalFiledMapsElement) {
		if (null != normalFiledMapsElement) {
			Iterator iterator = normalFiledMapsElement.elements("NormalField")
					.iterator();
			while (iterator.hasNext()) {
				Element normalFileElement = (Element) iterator.next();
				// 将节点上的值,赋值到Map中
				setNormalFieldMap(normalFileElement);
			}
		}

	}

	/**
	 * 将普通字段的name和code,赋值到normalFieldMap上
	 * 
	 * @param normalFileElement
	 */
	private void setNormalFieldMap(Element normalFileElement) {
		if (null != normalFileElement) {
			// 字段中文
			String name = normalFileElement.attributeValue("name");
			// 字段英文
			String code = normalFileElement.attributeValue("code");
			normalFieldMap.put(name, code);
		}

	}

	/**
	 * 解析唯一字段的Map集合节点
	 * 
	 * @param entityElement
	 */
	private void parseEntityUniqueFieldMaps(Element entityElement) {
		if (null != entityElement) {
			Iterator iterator = (Iterator) entityElement.elements(
					"UniqueFieldMaps").iterator();
			while (iterator.hasNext()) {
				Element uniqueFieldMapsElement = (Element) iterator.next();
				parseUniqueFieldMaps(uniqueFieldMapsElement);
			}
		}
	}

	/**
	 * 解析唯一字段,在map集合下的
	 * 
	 * @param uniqueFieldMapsElement
	 */
	private void parseUniqueFieldMaps(Element uniqueFieldMapsElement) {
		if (null != uniqueFieldMapsElement) {
			Iterator iterator = (Iterator) uniqueFieldMapsElement.elements(
					"UniqueField").iterator();
			while (iterator.hasNext()) {
				Element uniqueFieldElement = (Element) iterator.next();
				setUniqueFieldList(uniqueFieldElement);
			}
			setUniqueFieldArray(uniqueFieldList);
		}
	}

	/**
	 * 将唯一字段的值设置到list中
	 * 
	 * @param uniqueFieldElement
	 */
	private void setUniqueFieldList(Element uniqueFieldElement) {
		if (null != uniqueFieldElement) {
			// 唯一字段的中文名,对应普通字段的中文名
			String name = uniqueFieldElement.attributeValue("name");
			uniqueFieldList.add(name);
		}
	}

	/**
	 * 将list中的唯一值,放到Array数组中
	 * 
	 * @param uniqueFieldList
	 */
	private void setUniqueFieldArray(List uniqueFieldList) {
		if (null != uniqueFieldList) {
			int size = uniqueFieldList.size();
			uniqueFieldArray = new String[size];

			for (int i = 0; i < size; i++) {
				uniqueFieldArray[i] = uniqueFieldList.get(i);
			}
		}
	}

	/******************** 解析{导入xml}到map中 end *********************************/

这样就可以提供这样的excel模板了.表头变为中文,不用写id,hibernate可以用主键生成策略生成id.并且各列的顺序也可以随意,只是必须有这些字段.

excel导入导出优化_第1张图片

Excel路径

而excel的路径写死的问题,只需要一个界面,上传工具.下载的时候通过response放到界面上.

文件上传

jsp页面中的内容,提供上传功能.


	
导入Excel

而Contorller接收到的上传请求,会将excel和导入xml都变为输入流,然后调用工具类的导入方法,将excel导入.导入方法,主要也是解析导入xml,获取里面的配置,以及获取excel中的数据,将数据变为实体集合,最后将实体集合使用批量保存,保存到数据库中.当然,将excel的数据变成list的时候,需要对数据进行检测,若配置了唯一字段,则该字段中的值,必须是唯一的.

	/**
	 * 导入Excel
	 */
	@RequestMapping(value="importExcel")
	private void importExcel(
			@RequestParam("fileBox") CommonsMultipartFile excelFile,
			HttpServletRequest request,HttpServletResponse response) {
		//接收excel文件变为输入流
		InputStream inExcelFile = null;
		try {
			 inExcelFile = excelFile.getInputStream();
		} catch (IOException e) {
			System.err.println("excel读取出错。");
			e.printStackTrace();
		}
		
		//获取xml配置文件,也变为输入流
		String xmlFilePath = request.getSession().getServletContext().getRealPath("/")+"studentImport.xml";
		File importXMLFile = new File(xmlFilePath);
		InputStream inXMLFile  = null;
		try {
			inXMLFile = new FileInputStream(importXMLFile);
		} catch (FileNotFoundException e) {
			System.err.println("未找到xml文件。");
			e.printStackTrace();
		}
		
		try {
			//导入excel到数据库中,使用工具类parseImportExcelXml
			Boolean flag = parseImportExcelXml.importExcel(inExcelFile,inXMLFile,response);
			jacksonJsonUntil.beanToJson(response, flag);
		}catch(Exception e) {
			System.err.println("excel导入失败。");
			e.printStackTrace();
		}
		
	}

文件下载

下载到界面上,这里创建Workbook不是写一个文件路径,而是写response的输出流.然后添加表头,添加内容,设置excel名,以及response的一些参数,内容类型和头文件.

errorLines = errorMap.size();

// 创建错误列表工作簿和sheet
WritableWorkbook ewwb = Workbook.createWorkbook(response
		.getOutputStream());
WritableSheet eSheet = ewwb.createSheet("错误列表", 0);

// 添加表头
for (int n = 0; n < excelFiledNameArray.length; n++) {
	Label label = new Label(n, 0, excelFiledNameArray[n]);
	eSheet.addCell(label);
}

// 并添加两列,错误原因和所在行号
eSheet.addCell(new Label(excelFiledNameArray.length, 0, "错误原因"));
eSheet.addCell(new Label(excelFiledNameArray.length + 1, 0,
		"所在行号"));

// 添加内容
... addErrorRow(sheet, eSheet, errorMap);

// 设置文件名,当前时间
String fileName = new SimpleDateFormat("yyyyMMddhhmmss")
		.format(new Date()).toString() + "ErrorData";
response.reset();
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-disposition",
		"attachment;filename=" + fileName + ".xls");

//设置错误excel的单元格大小
setColumnAutoSize(eSheet, 10);

//写入数据,并关闭工作簿
ewwb.write();
ewwb.close();

附注

运行的效果

excel导入导出优化_第2张图片

点击导入Excel,导入成功,数据库中的数据如下.

再次导入Excel,由于数据重复,所以,生成错误excel,并且数据不写入数据库中.

excel导入导出优化_第3张图片

项目下载:Excel导入导出优化







你可能感兴趣的:(excel导入导出优化)