Java POI实现Excel导入-通用组件
在工作中,会经常大量使用到Excel导入,如果每个开发人员都自己实现一套Excel导入,带来的问题是研发效率降低,项目中存在大量重复的代码,这时就有必要将Excel导入写成通用组件,开发人员使用该组件,便可轻松实现导入功能
设计思路:
1.将Excel导入设计成模板形式,导入前需要配置此模板
2.通过反射的形式调用对应VO的属性的set方法,给属性赋值
3.返回解析后的结果集
Excel导入模板设计
在src/main/resource/excel/目录下,创建mairuan.import.template.xml文件,将要导入的Excel,配置成模板的形式,内容如下
<?xml version="1.0" encoding="UTF-8"?>
<import>
<!-- type类型:Byte,Short,Integer,Long,Float,Double,char,String,缺省为String -->
<sheet id="importRole" startRow="1" class="com.mairuan.base.system.model.RoleVO">
<column name="RoleCode" type="String"></column>
<column name="RoleName" type="String"></column>
<column name="RoleDesc" type="String"></column>
<column name="RoleState" type="String"></column>
</sheet>
</import>
说明:
1.一个sheet标签代表一个sheet页
2.startRow代表从哪行开始解析
3.class代表使用哪个对象来承载Excel中的值
4.name 对应class对应中的属性名,首字母必须大写
5.type表示该字段的数据类型,解析Excel时,得到单元格中的数据类型,和我们预想的不一至,会影响通过反射调用set方法,因此使用该字段进行类型转换
创建ImportExcelUtil工具类
1. 在工具类中增加解析mairuan.import.template.xml模板的方法
@SuppressWarnings("unchecked")
private static Element readXML(String sheetId) throws DocumentException, FileNotFoundException {
File file = ResourceUtils.getFile("classpath:/excel/mairuan.import.template.xml");
SAXReader reader = new SAXReader();
Document document = reader.read(file);
Element root = document.getRootElement();
Iterator<Element> iterator = root.elementIterator();
Element element = null;
while (iterator.hasNext()) {
element = iterator.next();
if (sheetId.equals(element.attributeValue("id"))) {
break;
}
}
return element;
}
根据传入的sheetID,查找对应的标签,如果找到,就反回
2. 在工具类中增加根据type值获得参数类型的方法
private static Class<?> getParameterType(String parameterType) {
switch (parameterType) {
case "Byte":
return Byte.class;
case "Short":
return Short.class;
case "Integer":
return Integer.class;
case "Long":
return Long.class;
case "Float":
return Float.class;
case "Double":
return Double.class;
case "char":
return char.class;
case "String":
return String.class;
case "Date":
return Date.class;
default:
return String.class;
}
}
3. 在工具类中增加解析Excel的主方法
@SuppressWarnings("unchecked")
public static List parseExcel(String sheetId, InputStream input) throws Exception {
// 根据sheetId解析xml,获取Excel模板
Element element = readXML(sheetId);
String clazzString = element.attributeValue("class");
// 从哪行开始解析
int start = Integer.valueOf(element.attributeValue("startRow"));
// 反射创建对象实例
Class<? extends Object> clazz = Class.forName(clazzString);
List<Element> columns = element.elements();
Object instance = null;
// 结果集
List resultList = new ArrayList();
// 要调用的方法
Method method = null;
// 调用Set方法要传递的参数
Class<?>[] args = null;
Cell cell = null;
XSSFWorkbook wb = null;
try
{
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
// wb = new XSSFWorkbook(file);
wb = new XSSFWorkbook(input);
// 获取第一个Sheet页
XSSFSheet sheet = wb.getSheetAt(0);
for (int i = start; i <= sheet.getLastRowNum(); i++) {
Row row = sheet.getRow(i);
if(row == null)
{
continue;
}
instance = clazz.newInstance();
StringBuffer buf = new StringBuffer();
for (int j = 0; j < row.getLastCellNum(); j++) {
cell = row.getCell(j);
if (cell == null) {
continue;
}
args = new Class[1];
args[0] = getParameterType(columns.get(j).attributeValue("type"));
Object value = getCellValue(cell,args[0],dateFormat);
//累计字符串内容
buf.append(getStringValue(value));
//Date情况转成String,其他类型保持原样
args[0] = Date.class.equals(args[0]) ? String.class : args[0];
method = clazz.getDeclaredMethod("set" + columns.get(j).attributeValue("name"), args);
method.invoke(instance, value);
}
//整行为空时丢弃该行数据
if ("".equals(buf.toString().trim()))
{
continue;
}
//加到集合中
resultList.add(instance);
}
} catch (Exception e) {
throw e;
} finally {
if (wb != null) {
wb.close();
}
}
return resultList;
}
说明:
1.外层for循环是读取Excel中的行,内层循环是解析每一行数据到对应的VO属性中
2.通过反射的方式给VO属性赋值
3.根据getCellValue方法获得不同类型的数据值,如果类型不对,反射执行赋值会失败
4.如果整行为空,则丢弃这行记录
5.最后将结果集resultList返回
最后完整的ImportExcelUtil工具类如下
package com.mairuan.base.utils;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.util.ResourceUtils;
public class ImportExcelUtil {
@SuppressWarnings("unchecked")
public static List parseExcel(String sheetId, InputStream input) throws Exception {
// 根据sheetId解析xml,获取Excel模板
Element element = readXML(sheetId);
String clazzString = element.attributeValue("class");
// 从哪行开始解析
int start = Integer.valueOf(element.attributeValue("startRow"));
// 反射创建对象实例
Class<? extends Object> clazz = Class.forName(clazzString);
List<Element> columns = element.elements();
Object instance = null;
// 结果集
List resultList = new ArrayList();
// 要调用的方法
Method method = null;
// 调用Set方法要传递的参数
Class<?>[] args = null;
Cell cell = null;
XSSFWorkbook wb = null;
try
{
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
// wb = new XSSFWorkbook(file);
wb = new XSSFWorkbook(input);
// 获取第一个Sheet页
XSSFSheet sheet = wb.getSheetAt(0);
for (int i = start; i <= sheet.getLastRowNum(); i++) {
Row row = sheet.getRow(i);
if(row == null)
{
continue;
}
instance = clazz.newInstance();
StringBuffer buf = new StringBuffer();
for (int j = 0; j < row.getLastCellNum(); j++) {
cell = row.getCell(j);
if (cell == null) {
continue;
}
args = new Class[1];
args[0] = getParameterType(columns.get(j).attributeValue("type"));
Object value = getCellValue(cell,args[0],dateFormat);
//累计字符串内容
buf.append(getStringValue(value));
//Date情况转成String,其他类型保持原样
args[0] = Date.class.equals(args[0]) ? String.class : args[0];
method = clazz.getDeclaredMethod("set" + columns.get(j).attributeValue("name"), args);
method.invoke(instance, value);
}
//整行为空时丢弃该行数据
if ("".equals(buf.toString().trim()))
{
continue;
}
//加到集合中
resultList.add(instance);
}
} catch (Exception e) {
throw e;
} finally {
if (wb != null) {
wb.close();
}
}
return resultList;
}
public static boolean checkFileType(String filename) {
if ((filename == null) || (filename.length() == 0)) {
return false;
}
String type = "";
int dot = filename.lastIndexOf('.');
if ((dot > -1) && (dot < (filename.length() - 1))) {
type = filename.substring(dot + 1);
}
if (!"xlsx".equalsIgnoreCase(type)) {
return false;
}
return true;
}
@SuppressWarnings("unchecked")
private static Element readXML(String sheetId) throws DocumentException, FileNotFoundException {
File file = ResourceUtils.getFile("classpath:/excel/mcc.base.import.xml");
SAXReader reader = new SAXReader();
Document document = reader.read(file);
Element root = document.getRootElement();
Iterator<Element> iterator = root.elementIterator();
Element element = null;
while (iterator.hasNext()) {
element = iterator.next();
if (sheetId.equals(element.attributeValue("id"))) {
break;
}
}
return element;
}
private static Object getCellValue(Cell cell,Class<? extends Object> clazz,SimpleDateFormat dateFormat) {
Object obj = null;
switch (cell.getCellType()) {
case Cell.CELL_TYPE_BOOLEAN:
obj = cell.getBooleanCellValue();
break;
case Cell.CELL_TYPE_ERROR:
obj = cell.getErrorCellValue();
break;
case Cell.CELL_TYPE_NUMERIC:
//用户自定义类型检测
if(String.class.equals(clazz))
{
DecimalFormat df = new DecimalFormat("#.#########"); // 数字格式,防止长数字成为科学计数
obj = df.format(cell.getNumericCellValue());
}else if(Date.class.equals(clazz))
{
obj = dateFormat.format(cell.getDateCellValue());
}else if(Double.class.equals(clazz)) {
obj = cell.getNumericCellValue();
}else if(Integer.class.equals(clazz)) {
DecimalFormat df = new DecimalFormat("#.#########"); // 数字格式,防止长数字成为科学计数
String val = df.format(cell.getNumericCellValue());
obj = Integer.parseInt(val);
}
break;
case Cell.CELL_TYPE_STRING:
String cellValue = cell.getStringCellValue();
if (Double.class.equals(clazz)) {
Double d = Double.valueOf(cellValue);
obj = d;
}else if(Integer.class.equals(clazz)) {
obj = Integer.parseInt(cellValue);
}else {
obj=cellValue;
}
break;
default:
break;
}
return obj;
}
/**
* 获取参数类型,默认为String
*
* @param parameterType
* @return
*/
private static Class<?> getParameterType(String parameterType) {
switch (parameterType) {
case "Byte":
return Byte.class;
case "Short":
return Short.class;
case "Integer":
return Integer.class;
case "Long":
return Long.class;
case "Float":
return Float.class;
case "Double":
return Double.class;
case "char":
return char.class;
case "String":
return String.class;
case "Date":
return Date.class;
default:
return String.class;
}
}
/**
* 获取字符串内容
* @param obj
* @return
*/
private static String getStringValue(Object obj)
{
if (obj != null)
{
return String.valueOf(obj);
}
return "";
}
}
Spring MVC控制层调用导入工具类解析Excel
@RequestMapping(value = "/importCoreList", method = RequestMethod.POST)
@ResponseBody
public ResponseVO<List<RoleVO>> importExcel(HttpServletRequest request, @RequestParam("file") MultipartFile file)
throws Exception {
ResponseVO<List<RoleVO>> response = new ResponseVO<List<RoleVO>>();
try {
if (file.isEmpty()) {
response.setStatus(ResponseVO.failCode);
response.setMessage("文件为空");
return response;
}
if (!ImportExcelUtil.checkFileType(file.getOriginalFilename())) {
response.setStatus(ResponseVO.failCode);
response.setMessage("只支持2007版以上的Excel导入");
return response;
}
String sheetId = "importRole";
List<RoleVO> result = (List<RoleVO>) ImportExcelUtil.parseExcel(sheetId, file.getInputStream());
response.setData(result );
} catch (Exception e) {
logger.error("Import Excel fail,The message is:", e);
response.setStatus(ResponseVO.failCode);
}
return response;
}
开发人员只需要通过List result = (List) ImportExcelUtil.parseExcel(sheetId, file.getInputStream());就可以将Excel中的值转换成想要的VO对应,进行后面的数据操作
还没有评论,来说两句吧...