概述
一、引入poi包
<!-- Excel 依赖包--> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.17</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>3.17</version> </dependency>
poi包用于处理xls格式,poi-ooxml用户处理xlsx格式。
二、代码
public class ExcelUtils {
public static void exportExcel(HttpServletResponse response, String fileName, ExcelData data, Class cls) throws Exception {
// 告诉浏览器用什么软件可以打开此文件
response.setHeader("content-Type", "application/vnd.ms-excel");
// 下载文件的默认名称
response.setHeader("Content-Disposition", "attachment;filename="+ URLEncoder.encode(fileName, "utf-8"));
exportExcel(data, response.getOutputStream(), cls);
}
public static void exportExcel(ExcelData data, OutputStream out, Class cls) throws Exception {
XSSFWorkbook wb = new XSSFWorkbook();
try {
String sheetName = data.getName();
if (null == sheetName) {
sheetName = "Sheet1";
}
XSSFSheet sheet = wb.createSheet(sheetName);
writeExcel(wb, sheet, data, cls);
wb.write(out);
} finally {
wb.close();
}
}
private static void writeExcel(XSSFWorkbook wb, Sheet sheet, ExcelData data, Class cls) {
int rowIndex = 0;
rowIndex = writeTitlesToExcel(wb, sheet, data.getTitles(), cls);
writeRowsToExcel(wb, sheet, data.getRows(), rowIndex, cls);
mergeCell(sheet, data.getRows(), cls);//合并单元格
autoSizeColumns(sheet, data.getTitles().size() + 1);
}
private static int writeTitlesToExcel(XSSFWorkbook wb, Sheet sheet, List<String> titles, Class cls) {
int rowIndex = 0;
int colIndex = 0;
// 如果没有标题,则不写标题
if(titles == null || titles.size() <= 0){
return rowIndex;
}
Font titleFont = wb.createFont();
titleFont.setFontName("simsun");
titleFont.setBold(true);
// titleFont.setFontHeightInPoints((short) 14);
titleFont.setColor(IndexedColors.BLACK.index);
XSSFCellStyle titleStyle = wb.createCellStyle();
titleStyle.setAlignment(HorizontalAlignment.CENTER);
titleStyle.setVerticalAlignment(VerticalAlignment.CENTER);
titleStyle.setFillForegroundColor(new XSSFColor(new java.awt.Color(182, 184, 192)));
titleStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
titleStyle.setFont(titleFont);
setBorder(titleStyle, BorderStyle.THIN, new XSSFColor(new java.awt.Color(0, 0, 0)));
Row titleRow = sheet.createRow(rowIndex);
// titleRow.setHeightInPoints(25);
colIndex = 0;
Field[] fields = cls.getDeclaredFields();
for(Field field : fields){
String cellTile = field.getName();
if (null!=field.getAnnotation(ColumnName.class)) {
cellTile = field.getAnnotation(ColumnName.class).value();
}
Cell cell = titleRow.createCell(colIndex);
cell.setCellValue(cellTile);
cell.setCellStyle(titleStyle);
colIndex++;
}
rowIndex++;
return rowIndex;
}
private static int writeRowsToExcel(XSSFWorkbook wb, Sheet sheet, List rows, int rowIndex, Class cls) {
try{
int colIndex = 0;
Font dataFont = wb.createFont();
dataFont.setFontName("simsun");
// dataFont.setFontHeightInPoints((short) 14);
dataFont.setColor(IndexedColors.BLACK.index);
XSSFCellStyle dataStyle = wb.createCellStyle();
dataStyle.setAlignment(HorizontalAlignment.CENTER);
dataStyle.setVerticalAlignment(VerticalAlignment.CENTER);
dataStyle.setFont(dataFont);
setBorder(dataStyle, BorderStyle.THIN, new XSSFColor(new java.awt.Color(0, 0, 0)));
Map<String, Method> methods = getReadMethods(cls);
Field[] fields = cls.getDeclaredFields();
Map<String, Class<?>> types = getTypes(cls);
for (Object rowData : rows) {
Row dataRow = sheet.createRow(rowIndex);
// dataRow.setHeightInPoints(25);
colIndex = 0;
for (Field field : fields) {
Method m = methods.get(field.getName());
Class<?> type = types.get(field.getName());
try {
Object cellData = m.invoke(rowData);
Cell cell = dataRow.createCell(colIndex);
if (cellData != null) {
setCellValue(cell, type, cellData);
} else {
cell.setCellValue("");
}
cell.setCellStyle(dataStyle);
colIndex++;
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
rowIndex++;
}
} catch (Exception e){
e.printStackTrace();
}
return rowIndex;
}
private static void mergeCell(Sheet sheet, List rows, Class cls) {
try{
List<DataExport> exportDataList = rows;
int[] mergeCol = {0,1,2,3,4,5,6}; //要合并的列,从0开始
//自动合并
for (int k = 0; k < mergeCol.length; k++) {
int colNum = mergeCol[k]; //要合并的列
int d = 0; //下次要合并的行
int n = exportDataList.size()-1; //当前合并的行
for (int i = exportDataList.size()-1; i >= 1; i--) { //每一行
if(i!=(n-d)) {
continue;
}
String serialNumber = exportDataList.get(i).getSerialNumber();
serialNumber = (serialNumber == null ? "" : serialNumber);
String lastSerialNumber = exportDataList.get(i-1).getSerialNumber();
lastSerialNumber = (lastSerialNumber == null ? "" : lastSerialNumber);
if(serialNumber.equals(lastSerialNumber)){ //相邻的上下两行
int rowspan = 2;
d = rowspan;
for (int j = 2; i-j >= 0; j++) { //判断上下多行内容一样
n = i;
String tmpSerialNumber = exportDataList.get(i-j).getSerialNumber();
tmpSerialNumber = (tmpSerialNumber == null ? "" : tmpSerialNumber);
if(!serialNumber.equals(tmpSerialNumber)){
break;
}else{
rowspan = j+1;
d = rowspan;
}
}
// 合并单元格时,只保留一行数据,其它数据清空,否则数据求和时影响数据计算
int startRow = i-rowspan+2;//合并起始行
int endRow = i+1;//合并结束行
for(int m = startRow + 1; m <= endRow; m++){
Row row = sheet.getRow(m);
row.getCell(k).setCellValue("");
}
sheet.addMergedRegion(new CellRangeAddress(i-rowspan+2, i+1, colNum, colNum));
}else {
d = 0;
n = i-1;
}
}
}
} catch (Exception e){
e.printStackTrace();
}
}
/**
* 根据字段类型调用不同的写数据方法
* @param cell--写的行
* @param type--字段类型
* @param cellData--数据
*/
private static void setCellValue(Cell cell, Class<?> type, Object cellData){
if(type == String.class){
cell.setCellValue((String)cellData);
} else if (type == Integer.class || type == int.class) {
cell.setCellValue((Integer)cellData);
} else if (type == Long.class || type == long.class) {
cell.setCellValue((Long)cellData);
} else if (type == Float.class || type == float.class) {
cell.setCellValue((Float)cellData);
} else if (type == Double.class || type == double.class) {
cell.setCellValue((Double)cellData);
} else if (type == boolean.class || type == Boolean.class) {
cell.setCellValue((Boolean)cellData);
} else if (type == Date.class ) {
cell.setCellValue((Date)cellData);
} else if (type == BigDecimal.class ) {
if(cellData != null){
cell.setCellValue(((BigDecimal)cellData).doubleValue());
} else {
cell.setCellValue("");
}
} else {
cell.setCellValue(JSON.toJSONString(cellData));
}
}
// 设置列宽自适应
private static void autoSizeColumns(Sheet sheet, int columnNumber) {
for (int i = 0; i < columnNumber; i++) {
int orgWidth = sheet.getColumnWidth(i);
sheet.autoSizeColumn(i, true);
int newWidth = (int) (sheet.getColumnWidth(i) + 100);
if (newWidth > orgWidth) {
sheet.setColumnWidth(i, newWidth);
} else {
sheet.setColumnWidth(i, orgWidth);
}
}
}
private static void setBorder(XSSFCellStyle style, BorderStyle border, XSSFColor color) {
style.setBorderTop(border);
style.setBorderLeft(border);
style.setBorderRight(border);
style.setBorderBottom(border);
style.setBorderColor(XSSFCellBorder.BorderSide.TOP, color);
style.setBorderColor(XSSFCellBorder.BorderSide.LEFT, color);
style.setBorderColor(XSSFCellBorder.BorderSide.RIGHT, color);
style.setBorderColor(XSSFCellBorder.BorderSide.BOTTOM, color);
}
/**
*
* @param cls
* @return
*/
private static PropertyDescriptor[] getPropertyDescriptor(Class cls) {
PropertyDescriptor[] props = new PropertyDescriptor[0];
try {
BeanInfo beaninfo = Introspector.getBeanInfo(cls);
props = beaninfo.getPropertyDescriptors();
} catch (IntrospectionException e) {
}
return props;
}
/**
* 获取写方法
* @param cls
* @return 写方法map
*/
private static Map<String, Method> getWriteMethods(Class cls) {
Map<String, Method> methods = new HashMap<String, Method>();
PropertyDescriptor[] props = getPropertyDescriptor(cls);
for (int i = 0; i < props.length; i++) {
Method sm = props[i].getWriteMethod();
if (sm != null) {
String field = props[i].getName();
methods.put(field, sm);
}
}
return methods;
}
/**
* 获取读方法
* @param cls
* @return 读方法map
*/
public static Map<String, Method> getReadMethods(Class cls) {
Map<String, Method> methods = new HashMap<String, Method>();
PropertyDescriptor[] props = getPropertyDescriptor(cls);
for (int i = 0; i < props.length; i++) {
Method sm = props[i].getReadMethod();
if (sm != null) {
String field = props[i].getName();
methods.put(field, sm);
}
}
return methods;
}
/**
* 获取类型
* @param cls
* @return 类型map
*/
private static Map<String, Class<?>> getTypes(Class cls) {
Map<String, Class<?>> types = new HashMap<String, Class<?>>();
PropertyDescriptor[] props = getPropertyDescriptor(cls);
for (int i = 0; i < props.length; i++) {
Class<?> type = props[i].getPropertyType();
if (types != null) {
String field = props[i].getName();
types.put(field, type);
}
}
return types;
}
public static boolean isExcel2003(String fileName){
if(fileName == null){
fileName = "";
}
boolean isExcel2003 = fileName.toLowerCase().endsWith("xls") ? true : false;
return isExcel2003;
}
public static boolean isExcel2007(String fileName){
if(fileName == null){
fileName = "";
}
boolean isExcel2007 = fileName.toLowerCase().endsWith("xlsx") ? true : false;
return isExcel2007;
}
/**
*
* @param file
* @param cls
* @param ifExNull,是否排除有空字段的数据.true:排除;false:不排除
* @param <T>
* @return
* @throws IllegalAccessException
* @throws InstantiationException
*/
public static <T> Map<String, Object> parseExcelToObj(File file, Class<T> cls, boolean ifExNull) throws IllegalAccessException, InstantiationException {
Workbook wb = null;
try
{
if (isExcel2007(file.getName())) {
wb = new XSSFWorkbook(new FileInputStream(file));
} else {
wb = new HSSFWorkbook(new FileInputStream(file));
}
}
catch (IOException e)
{
e.printStackTrace();
return null;
}
Map<String, Object> resultMap = new HashMap<String, Object>();
List<T> list = new ArrayList<T>();//数据
Sheet sheet = wb.getSheetAt(0);//获取第一张表
Map<String, Integer> titlesIndexMap = getExcelTitles(sheet);
int startRow = 0;
if(titlesIndexMap.size() > 0){
startRow = 1;
}
int lastRowNum = sheet.getLastRowNum();
for (int i = startRow; i <= lastRowNum; i++)
{
T t = cls.newInstance();
Field[] fields = t.getClass().getDeclaredFields();
Row row = sheet.getRow(i);//获取索引为i的行,以0开始
boolean flag = false;
boolean isNull = false;
for(Field field : fields){
if (null!=field.getAnnotation(ColumnName.class)) {
setFieldValue(row, t, cls, field, titlesIndexMap);
flag = true;
//检查是否有值为null
field.setAccessible(true); // 设置属性是可以访问的(私有的也可以)
Object value = field.get(t);
if(value == null && ifExNull){
isNull = true;
}
}
}
if(flag && !isNull){
list.add(t);
}
}
resultMap.put("title", titlesIndexMap.keySet());//excel的每列标题
resultMap.put("data", list);// excel的数据
return resultMap;
}
/**
* 设置对象field值
*
* @param row
* @param obj
* @param cls
* @param field
* @param indexs
*/
private static <T> void setFieldValue(Row row, T obj, Class<T> cls, Field field,
Map<String, Integer> indexs) {
Map<String, Method> methods = getWriteMethods(cls);
Map<String, Class<?>> types = getTypes(cls);
String key = field.getName();
Method m = methods.get(key);
Class<?> type = types.get(key);
String cm = field.getAnnotation(ColumnName.class).value();
Integer index = indexs.get(cm);
if (index != null) {
Cell cell = row.getCell(index.intValue());
if (cell != null) {
setFieldStringValue(m, cell, type, obj);
setFieldBooleanValue(m, cell, type, obj);
setFieldDateValue(m, cell, type, obj);
setFieldDoubleValue(m, cell, type, obj);
setFieldFloatValue(m, cell, type, obj);
setFieldIntegerValue(m, cell, type, obj);
setFieldLongValue(m, cell, type, obj);
setFieldBigDecimalValue(m, cell, type, obj);
}
}
}
/**
* 设置对象field值(String型)
*
* @param m
* @param cell
* @param type
* @param obj
*/
private static <T> void setFieldStringValue(Method m, Cell cell, Class<?> type, T obj) {
try {
int ctype = cell.getCellTypeEnum().ordinal();
String cellStyle = cell.getCellStyle().getDataFormatString();
if (type == String.class && ctype == CellType.STRING.ordinal()) {
m.invoke(obj, cell.getStringCellValue());
} else if (type == String.class && ctype == CellType.NUMERIC.ordinal()) {
if(cellStyle != null && cellStyle.indexOf("%") != -1){
// 百分比类型转换为带百分号的字符串
BigDecimal value = BigDecimal.valueOf(cell.getNumericCellValue());
value = value.multiply(new BigDecimal(100));
value = value.setScale(1, BigDecimal.ROUND_HALF_UP);
String finalValue = String.valueOf(value) + "%";
m.invoke(obj, finalValue);
} else {
int decimalDigit = Utils.getNumberDecimalDigits(cell.getNumericCellValue());
if (decimalDigit == 1 || decimalDigit == 2){
// 一位小数或两位小数
m.invoke(obj, String.valueOf(cell.getNumericCellValue()));
} else {
long value = (long)cell.getNumericCellValue();
m.invoke(obj, String.valueOf(value));
}
}
} else if (type == String.class && ctype == CellType.FORMULA.ordinal()) {
m.invoke(obj, cell.getCellFormula());
}
} catch (Exception e) {
}
}
/**
* 设置对象field值(Integer型)
*
* @param m
* @param cell
* @param type
* @param obj
*/
private static <T> void setFieldIntegerValue(Method m, Cell cell, Class<?> type, T obj) {
try {
if (type == Integer.class || type == int.class) {
m.invoke(obj, (int) cell.getNumericCellValue());
}
} catch (Exception e) {
}
}
/**
* 设置对象field值(Long型)
*
* @param m
* @param cell
* @param type
* @param obj
*/
private static <T> void setFieldLongValue(Method m, Cell cell, Class<?> type, T obj) {
try {
if (type == Long.class || type == long.class) {
m.invoke(obj, (long) cell.getNumericCellValue());
return;
}
} catch (Exception e) {
}
}
/**
* 设置对象field值(Float型)
*
* @param m
* @param cell
* @param type
* @param obj
*/
private static <T> void setFieldFloatValue(Method m, Cell cell, Class<?> type, T obj) {
try {
if (type == Float.class || type == float.class) {
m.invoke(obj, (float) cell.getNumericCellValue());
return;
}
} catch (Exception e) {
}
}
/**
* 设置对象field值(Double型)
*
* @param m
* @param cell
* @param type
* @param obj
*/
private static <T> void setFieldDoubleValue(Method m, Cell cell, Class<?> type, T obj) {
try {
if (type == Double.class || type == double.class) {
m.invoke(obj, cell.getNumericCellValue());
}
} catch (Exception e) {
}
}
/**
* 设置对象field值(BigDecimal型)
*
* @param m
* @param cell
* @param type
* @param obj
*/
private static <T> void setFieldBigDecimalValue(Method m, Cell cell, Class<?> type, T obj) {
try {
if (type == BigDecimal.class){
m.invoke(obj, cell.getNumericCellValue());
}
} catch (Exception e) {
}
}
/**
* 设置对象field值(Boolean型)
*
* @param m
* @param cell
* @param type
* @param obj
*/
private static <T> void setFieldBooleanValue(Method m, Cell cell, Class<?> type, T obj) {
try {
if (type == Boolean.class || type == boolean.class) {
m.invoke(obj, cell.getBooleanCellValue());
return;
}
} catch (Exception e) {
}
}
/**
* 设置对象field值(Date型)
*
* @param m
* @param cell
* @param type
* @param obj
*/
private static <T> void setFieldDateValue(Method m, Cell cell, Class<?> type, T obj) {
try {
if (type == Date.class) {
m.invoke(obj, cell.getDateCellValue());
return;
}
} catch (Exception e) {
}
}
private static <T> Map<String, Integer> getExcelTitles(Sheet sheet){
Map<String, Integer> titlesIndexMap = new HashMap<String, Integer>();
Row row = sheet.getRow(0);
int count = row.getPhysicalNumberOfCells();
for(int i = 0; i < count; i++){
titlesIndexMap.put(row.getCell(i).getStringCellValue(), i);
}
return titlesIndexMap;
}
}
备注:
1、合并单元格的方法sheet.addMergedRegion(new CellRangeAddress(startRow, endRow, startCol, endCol)); CellRangeAddress各参数的含义分别是合并起始行、合并结束行、合并起始列、合并结束列。
2、poi提供的合并只是假合并,即仅将数据隐藏了,并没有进行数据的实际合并,这样在针对导出的合并数据进行计算时(如求和)就会将隐藏的数据一并计算。因此在检查到需要合并时,只保留一行数据,清楚合并的其他行数据,处理的代码片段:
// 合并单元格时,只保留一行数据,其它数据清空,否则数据求和时影响数据计算
int startRow = i-rowspan+2;//合并起始行
int endRow = i+1;//合并结束行
for(int m = startRow + 1; m <= endRow; m++){
Row row = sheet.getRow(m);
row.getCell(k).setCellValue("");//k表示列号
}
最后
以上就是从容树叶为你收集整理的java POI解析excel、导出及合并excel的全部内容,希望文章能够帮你解决java POI解析excel、导出及合并excel所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复