您的位置:首页 > 其它

Excel基于POI利用反射返回Bean导入、Excel基于POI导出、Excel利用jxls导出、Excel模板导出

2018-03-07 13:26 597 查看
自述:项目中一直没有一个好用的Excel导入导出功能。所以简单实现了导入导出功能供大家参考
导入功能:基于poi导入做了一层封装、支持注解方式标识属性对应Excel列、并支持简单规则校验、具体规则校验可以根据自己需求自定义
两种导出功能:一种基于poi的导出,一种基于jxls模板导出。jxls模板导出可参考:jxls说明
别的就不多BB了,直接上代码。源码包可直接下载使用:点我取源码
1、基于maven项目的添加依赖,POM依赖如下<!-- Excel poi文件处理 -->
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.8.0</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.9</version>
</dependency>
<!-- Excel模板导出依赖 -->
<dependency>
<groupId>net.sf.jxls</groupId>
<artifactId>jxls-core</artifactId>
<version>1.0.6</version>
</dependency>
<dependency>
<groupId>net.sf.jxls</groupId>
<artifactId>jxls-reader</artifactId>
<version>1.0.6</version>
</dependency>
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant</artifactId>
<version>1.9.4</version>
</dependency> 2、Excle导入类ExcelException.java,ExcelFieldMeta.java,ExcelUtil.java,入口类为ExcelUtil.java里面提供各种静态方法
ExcelUtil.java
/**
* Excel导入
*
* @author http://blog.csdn.net/make_a_difference */
@SuppressWarnings("unchecked")
public class ExcelUtil {

private static Log logger = LogFactory.getLog(ExcelUtil.class);

// 换行标识
private final static String ENTER_STR = "\n";

/**
* 默认解析Excel第一个sheet页
*
* @param is
* 输入流
* @param startRow
* 开始解析行
* @param clazz
* 实体类
* @return
* @throws ExcelException
*/
public static <T> List<T> excelParsing(InputStream is, Integer startRow, Class<T> clazz) throws ExcelException {
return excelParsing(is, 1, startRow, clazz);
}

/**
* 默认解析Excel第一个sheet页
*
* @param is
* 输入流
* @param startRow
* 开始解析行
* @param clazz
* 实体类
* @return
* @throws ExcelException
* @throws FileNotFoundException
*/
public static <T> List<T> excelParsing(File file, Integer startRow, Class<T> clazz) throws ExcelException {
FileInputStream is;
try {
is = new FileInputStream(file);
} catch (FileNotFoundException e) {
logger.error("Excel文件异常", e);
throw new ExcelException("Excel文件异常");
}
return excelParsing(is, 1, startRow, clazz);
}

/**
* 解析Excel
*
* @param is
* 输入流
* @param sheetIndex
* sheet页数
* @param startRow
* 开始解析行
* @param clazz
* 实体类
* @return
* @throws ExcelException
*/
public static <T> List<T> excelParsing(InputStream is, Integer sheetIndex, Integer startRow, Class<T> clazz)
throws ExcelException {
// 1: 获取工作簿
Workbook wb = null;
try {
wb = ExcelUtil.getWorkbook(is);
} catch (Exception e) {
logger.error("系统解析Excel获取WorkBook错误", e);
throw new ExcelException("系统解析Excel错误");
}
// 2:获取第一个sheet页码
Sheet sheet = wb.getSheetAt(sheetIndex - 1);
return doParsing(sheet, startRow, clazz);
}

@SuppressWarnings("rawtypes")
private static <T> List<T> doParsing(Sheet sheet, Integer startRow, Class<T> clazz) throws ExcelException {
StringBuffer errorMessage = new StringBuffer("");
// 1:获取sheet页的总行数
int lastRow = sheet.getLastRowNum();
// 2: 行解析,默认从0开始,startRow属性定义了数据从该行开始解析,程序中定义的行数从1开始算,所以此处要-1
List resultList = new ArrayList(3);
try {
for (int rowIndex = startRow - 1; rowIndex <= lastRow; rowIndex++) {
Row row = sheet.getRow(rowIndex); // 得到 第 n 行
// 2.1获取的列为空则跳出循环
if (row == null) {
continue;
}
// 2.2 解析对象
Object rowBean = clazz.newInstance();
String rowErrorMessage = check(row, rowIndex, rowBean);
// 2.3 如果返回的不是null,则存在错误信息则记录错误信息
if (rowErrorMessage != null) {
errorMessage.append(rowErrorMessage + ENTER_STR);
continue;
} else if ("end".equals(rowErrorMessage)) {
resultList.add(rowBean);
return resultList;
}
// 2.4 如果正确 则不读取
resultList.add(rowBean);
}
} catch (Exception e) {
logger.error("系统解析Excel列错误", e);
throw new ExcelException("系统解析Excel错误");
}
// 3:如果存在错误则需要将异常抛出
if (errorMessage.length() > 0) {
throw new ExcelException(errorMessage.toString());
}
return resultList;
}

/**
*
* @param row
* 行信息
* @param rowIndex
* 当前行数
* @param declaredFields
* @param rowBean
* @return 错误信息
* @throws Exception
*/

private static String check(Row row, int rowIndex, Object rowBean) throws Exception {
// 1: 对象中循环取数据并赋值
for (Field field : rowBean.getClass().getDeclaredFields()) {
// 2:包含excel规则校验的注解
ExcelFieldMeta meta = field.getAnnotation(ExcelFieldMeta.class);
// 3:单元格的值
Cell cell = row.getCell(meta.cell() - 1);
String cellValue = getCellValue(cell);
Object obejctVal = null;
// 3.1 第一个单元并单元格值为空则表示读取excel结束
if (meta.cell() == 1 && (cell == null || "".equals(cellValue) || "null".equals(cellValue)))
return "end";
// 4.2校验单元格是否必填,单元格可以为空
if (!meta.isNotNull() && (cellValue == null || "".equals(cellValue))) {
continue;
}
// 4.2:可以为空且为空
if (meta.isNotNull() && (cellValue == null || "".equals(cellValue))) {
return "[" + (rowIndex + 1) + "]行-[" + (meta.cell()) + "]列:此单元格内容不能为空值";
}
// 4.3 整型、浮点型
if (field.getType() == Integer.class) {
try {
// 此处采用浮点数转换,验证value中是否含有字符。整形转换时只要整数部分的数据
obejctVal = (int) cell.getNumericCellValue();
} catch (Exception ne) {
return "[" + (rowIndex + 1) + "]行-[" + (meta.cell()) + "]列:此单元格内容只能为数值,读取时为:" + cellValue;
}
} else if (field.getType() == Double.class) {// 4.4 浮点型
try {
// 此处采用浮点数转换,验证value中是否含有字符。整形转换时只要整数部分的数据
obejctVal = cell.getNumericCellValue();
} catch (NumberFormatException ne) {
return "[" + (rowIndex + 1) + "]行-[" + (meta.cell()) + "]列:此单元格内容只能为数值,读取时为:" + cellValue;
}
} else if (field.getType() == Date.class) {// 4.5处理日期类型
SimpleDateFormat sf = new SimpleDateFormat(meta.dateFormat());
try {
obejctVal = sf.parse(cellValue);
obejctVal.toString();
} catch (ParseException e) {
return "[" + (rowIndex + 1) + "]行-[" + (meta.cell()) + "]列:此单元格内容中日期格式异常,读取时为" + cellValue;
}
} else if (field.getType() == String.class) {
obejctVal = cellValue;
}
// 4.6 长度校验
if (meta.maxLength() != -1 && cellValue.length() > meta.maxLength()) {
return "[" + (rowIndex + 1) + "]行-[" + (meta.cell()) + "]列:此单元格内容的长度不能超出" + meta.maxLength() + "个字符";
}
// 4.7设置属性
PropertyUtils.setProperty(rowBean, field.getName(), obejctVal);
}
return null;
}

/**
* 得到当前列的值
*
* @param cell
* @return
*/
private static String getCellValue(Cell cell) {
String typeString = "";
if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC) {
typeString = String.valueOf(cell.getNumericCellValue());
} else if (cell.getCellType() == Cell.CELL_TYPE_STRING) {
typeString = String.valueOf(cell.getStringCellValue());
} else if (cell.getCellType() == Cell.CELL_TYPE_FORMULA) {
typeString = String.valueOf(cell.getDateCellValue());
} else if (cell.getCellType() == Cell.CELL_TYPE_BLANK) {
typeString = String.valueOf(cell.getStringCellValue());
} else if (cell.getCellType() == Cell.CELL_TYPE_ERROR) {
typeString = "";
}
return typeString;
}

/**
* 解析不同版本的Excel文件
*
* @param in
* @return
* @throws IOException
* @throws InvalidFormatException
*/
private static Workbook getWorkbook(InputStream in) throws IOException, InvalidFormatException {
if (!in.markSupported()) {
in = new PushbackInputStream(in, 8);
}
if (POIFSFileSystem.hasPOIFSHeader(in)) {
return new HSSFWorkbook(in);
}
if (POIXMLDocument.hasOOXMLHeader(in)) {
try {
return new XSSFWorkbook(OPCPackage.open(in));
} catch (InvalidFormatException e) {
logger.error("Excel文件异常", e);
}
}
throw new IllegalArgumentException("你的excel版本目前poi不支持");
}ExcelFieldMeta.java/**
* Excel对象自定义注解
*
* @author http://blog.csdn.net/make_a_difference *
*/
@Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到
@Target({ ElementType.FIELD, ElementType.METHOD }) // 定义注解的作用目标**作用范围字段、枚举的常量/方法
@Documented // 说明该注解将被包含在javadoc中
public @interface ExcelFieldMeta {

// 对应Excel文档中的列号
int cell() default 0;

// 不能为空,默认为 是
boolean isNotNull() default true;

// 最大长度, -1 则不限制
int maxLength() default -1;

// 日期格式,默认导入格式为"yyyy/MM/dd"如"2015/5/13"
String dateFormat() default "yyyy/MM/dd";
}ExcelException.java
/**
* Excel处理异常
*
* @author http://blog.csdn.net/make_a_difference */
public class ExcelException extends Exception {

/**
* @Fields serialVersionUID: (用一句话描述这个变量表示什么)
*/
private static final long serialVersionUID = 1L;

public ExcelException() {
super();
}

public ExcelException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}

public ExcelException(String message, Throwable cause) {
super(message, cause);
}

public ExcelException(String message) {
super(message);
}

public ExcelException(Throwable cause) {
super(cause);
}

}
3、Excel基于POI导出参考代码
/**
* Excel下载
*
* @author http://blog.csdn.net/make_a_difference */
public class ExcelExport {

/**
* 下载excel文件,内容使用MAP存放 。 支持多个sheet。两个map的长度必须一致,map的key为索引(index)
*
* @param response
*            响应流
* @param headName
*            Excel表名
* @param tableHeadMap
*            每个sheet对应的表头为具体的value值
* @param tableBodyMap
*            每个sheet对应的内容为具体的value值
*/
public static void downloadExcelMap(HttpServletResponse response, String headName,
Map<Integer, List<String>> tableHeadMap, Map<Integer, List<Map<Object, Object>>> tableBodyMap)
throws Exception {
headName = replaceAllSpecial(headName);
// 1:创建一个workbook
Workbook workbook = new HSSFWorkbook();

// 创建样式
CellStyle style = workbook.createCellStyle();
Font font = workbook.createFont();
font.setBoldweight(Font.BOLDWEIGHT_BOLD); // 粗体
style.setFont(font);
style.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 水平居中
style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); // 垂直居中
style.setBorderTop((short) 1);
style.setBorderBottom((short) 1);
style.setBorderLeft((short) 1);
style.setBorderRight((short) 1);

// 设置合计样式
CellStyle style1 = workbook.createCellStyle();
style1.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 水平居中
style1.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); // 垂直居中
style1.setBorderTop((short) 1);
style1.setBorderBottom((short) 1);
style1.setBorderLeft((short) 1);
style1.setBorderRight((short) 1);

int sheetLength = tableHeadMap.size();
if (sheetLength != tableBodyMap.size()) {
throw new Exception("tableHeadMap与tableBodyMap对应的长度不一致");
}
for (int i = 0; i < sheetLength; i++) {
Sheet sheet = workbook.createSheet(headName + (i + 1));
List<String> tableHead = tableHeadMap.get(i);
List<Map<Object, Object>> tableBody = tableBodyMap.get(i);
// 2:合并单元格,表头。并设置值
CellRangeAddress cra = new CellRangeAddress(0, 0, 0, tableHead.size() - 1);
sheet.addMergedRegion(cra);
Row row = sheet.createRow(0);
Cell tableName = row.createCell(0);
tableName.setCellStyle(style);
tableName.setCellValue(headName);

// 3:设置表head
Row row1 = sheet.createRow(1);
for (int m = 0; m < tableHead.size(); m++) {
Cell createCell = row1.createCell(m);
createCell.setCellValue(tableHead.get(m));
createCell.setCellStyle(style);
}
// 4:表格内容
for (int m = 0; m < tableBody.size(); m++) {
Row rows = sheet.createRow(m + 2);
int j = 0;
for (Map.Entry<Object, Object> entry : tableBody.get(m).entrySet()) {
Cell createCell = rows.createCell(j);
if (entry.getValue() != null && !"".equals(entry.getValue())) {
createCell.setCellValue(entry.getValue().toString());
} else {
createCell.setCellValue("");
}
createCell.setCellStyle(style1);
j++;
}
}
}

// 5:设置头
response.setHeader("Content-disposition",
"attachment; filename=" + new String(headName.getBytes("GB2312"), "ISO8859-1") + ".xls");
// 6:设置头类型
response.setContentType("application/vnd.ms-excel");
// 7:写出
OutputStream toClient = response.getOutputStream();
workbook.write(toClient);
toClient.flush();
toClient.close();

}

/**
* 下载excel文件,内容使用MAP存放
*
* @param response
*            响应流
* @param headName
*            Excel文件名
* @param tableHead
*            表的title
* @param tableBody
*            表内容
* @throws IOException
*/
public static void downloadExcelMap(HttpServletResponse response, String headName, List<String> tableHead,
List<Map<Object, Object>> tableBody) throws IOException {
headName = replaceAllSpecial(headName);
// 1:创建一个workbook
Workbook workbook = new HSSFWorkbook();

// 创建样式
CellStyle style = workbook.createCellStyle();
Font font = workbook.createFont();
font.setBoldweight(Font.BOLDWEIGHT_BOLD); // 粗体
style.setFont(font);
style.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 水平居中
style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); // 垂直居中
style.setBorderTop((short) 1);
style.setBorderBottom((short) 1);
style.setBorderLeft((short) 1);
style.setBorderRight((short) 1);

// 设置合计样式
CellStyle style1 = workbook.createCellStyle();
style1.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 水平居中
style1.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); // 垂直居中
style1.setBorderTop((short) 1);
style1.setBorderBottom((short) 1);
style1.setBorderLeft((short) 1);
style1.setBorderRight((short) 1);

Sheet sheet = workbook.createSheet(headName);
// 2:合并单元格,表头。并设置值
CellRangeAddress cra = new CellRangeAddress(0, 0, 0, tableHead.size() - 1);
sheet.addMergedRegion(cra);
Row row = sheet.createRow(0);
Cell tableName = row.createCell(0);
tableName.setCellStyle(style);
tableName.setCellValue(headName);

// 3:设置表head
Row row1 = sheet.createRow(1);
for (int i = 0; i < tableHead.size(); i++) {
Cell createCell = row1.createCell(i);
createCell.setCellValue(tableHead.get(i));
createCell.setCellStyle(style);
}
// 4:表格内容
for (int i = 0; i < tableBody.size(); i++) {
Row rows = sheet.createRow(i + 2);
int j = 0;
for (Map.Entry<Object, Object> entry : tableBody.get(i).entrySet()) {
Cell createCell = rows.createCell(j);
if (entry.getValue() != null && !"".equals(entry.getValue())) {
createCell.setCellValue(entry.getValue().toString());
} else {
createCell.setCellValue("");
}
createCell.setCellStyle(style1);
j++;
}
}
// 5:设置头
response.setHeader("Content-disposition",
"attachment; filename=" + new String(headName.getBytes("GB2312"), "ISO8859-1") + ".xls");
// 6:设置头类型
response.setContentType("application/vnd.ms-excel");
// 7:写出
OutputStream toClient = response.getOutputStream();
workbook.write(toClient);
toClient.flush();
toClient.close();

}

/**
* 下载excel文件,内容使用MAP存放
*
* @param response
*            响应流
* @param headName
*            Excel文件名
* @param tableHead
*            表的title
* @param tableBody
*            表内容
* @throws IOException
*/
public static void downloadExcelObj(HttpServletResponse response, String headName, List<String> tableHead,
List<Object> tableBody) throws Exception {
// 将对象转换成map
List<Map<Object, Object>> mapBody = new ArrayList<Map<Object, Object>>();
for (int i = 0; i < tableBody.size(); i++) {
Map<Object, Object> objectMap = new LinkedHashMap<Object, Object>();
Field[] fields = tableBody.get(i).getClass().getDeclaredFields();
for (Field v : fields) {
v.setAccessible(true);
Object va = v.get(tableBody.get(i));
if (va == null) {
va = "";
}
objectMap.put(v.getName(), va);
}
mapBody.add(objectMap);
}
downloadExcelMap(response, headName, tableHead, mapBody);
}

/**
* 替换特殊字符
*
* @param str
* @return
*/
private static String replaceAllSpecial(String str) {
String regEx = "[`~!@#$%^&*()+=|{}':;',\\[\\].<>/?~!@#¥%……&*()——+|{}【】‘;:”“’。,、?]";
Pattern p = Pattern.compile(regEx);
Matcher m = p.matcher(str);
return m.replaceAll("").trim();
}
}
3、Excel基于jxls模板导出参考代码
/**
* Excel 模板下载
*
* @author http://blog.csdn.net/make_a_difference */
public class ExcelTempletExport {

/**
* 通过模板下载Excel文件
* <jx:forEach items="${list}" var="bean"> ${bean.courseName} </jx:forEach>
*
* @param templateUrl
* 模板路径 /org/gtiles/components/gtclasses/workbench/
* teacherfacecoursecount/list/templateTeacherCourse.xlsx
* @param tableBody
* 输出内容list
* @param fileName
* 文件名称
* @param response
* 相应流
*
* @throws Exception
*/
public static void downloadExcel(String templatePath, List<?> tableBody, String fileName,
HttpServletResponse response) throws Exception {
Map<String, Object> beanParams = new HashMap<String, Object>();
beanParams.put("list", tableBody);
downloadExcel(templatePath, beanParams, fileName, response);
}

/**
* 通过模板下载Excel文件
* <jx:forEach items="${list}" var="bean"> ${bean.courseName} </jx:forEach>
*
* @param templateUrl
* 模板路径 /org/gtiles/components/gtclasses/workbench/
* teacherfacecoursecount/list/templateTeacherCourse.xlsx
* @param map
* 输出内容 key-value
* @param fileName
* 文件名称
* @param response
* 相应流
*
* @throws Exception
*/
public static void downloadExcel(String templatePath, Map<String, Object> map, String fileName,
HttpServletResponse response) throws Exception {
// 1: 创建XLSTransformer对象
XLSTransformer transformer = new XLSTransformer();
// 2:获取模板,读取jar文件并返回流
InputStream is = ExcelTempletExport.class.getResourceAsStream(templatePath);
try {
// 4:设置响应头
response.setHeader("Content-Disposition",
"attachment;filename=\"" + new String(fileName.getBytes("gb2312"), "iso8859-1") + ".xlsx\"");
response.setContentType("application/vnd.ms-excel");
// 5:通过流向客户端写数据
transformer.transformXLS(is, map).write(response.getOutputStream());
} catch (Exception e) {
e.printStackTrace();
} finally {
if (is != null)
is.close();
response.getOutputStream().flush();
response.getOutputStream().close();
}
}

/**
* 通过模板将Excel写入到另外一个Excel文件中
*
* @param srcFilePath
* 模板路径
* @param tableBody
* 输出内容
* @param destFilePath
* 输出目标文件
* @throws Exception
*/
public static void downloadExcel(String srcFilePath, List<?> tableBody, String destFilePath) throws Exception {
// 1: 创建XLSTransformer对象
XLSTransformer transformer = new XLSTransformer();
// 2:将数据转换成Map格式
Map<String, Object> beanParams = new HashMap<String, Object>();
beanParams.put("list", tableBody);
// 3:写出文件
transformer.transformXLS(srcFilePath, beanParams, destFilePath);
}

}
4、Test 测试导入 /**
* test
* @author http://blog.csdn.net/make_a_difference */
public class TestBean {

@ExcelFieldMeta(cell = 1)
private String name;
@ExcelFieldMeta(cell = 2, isNotNull = false)
private Integer age;
@ExcelFieldMeta(cell = 3)
private Date birthday;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}
public Date getBirthday() {
return birthday;
}

public void setBirthday(Date birthday) {
this.birthday = birthday;
}

public static void main(String[] args) throws FileNotFoundException {
try {
// List<TestBean> excelParsing = ExcelUtil.excelParsing(new File("C:\\Users\\Administrator\\Desktop\\test.xlsx"), 1, TestBean.class);
//1:导入
List<TestBean> excelParsing = ExcelUtil.excelParsing(new FileInputStream("C:\\Users\\Administrator\\Desktop\\test.xlsx"), 1, 1, TestBean.class);
//2:导出
ExcelTempletExport.downloadExcel("模板路径",excelParsing, "文件名", response);
} catch (ExcelException e) {
System.out.println(e.toString());//excel解析的错误。例:[2]行-[2]列:此单元格内容只能为数值,读取时为:qx
}
}

Excel导入模板



Excel使用jxls导出模板

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息