import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Logger; import org.apache.poi.hssf.usermodel.HSSFCellStyle; import org.apache.poi.hssf.usermodel.HSSFFont; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.HorizontalAlignment; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.VerticalAlignment; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.usermodel.WorkbookFactory; import org.apache.poi.ss.util.CellRangeAddress; import com.google.gson.Gson; import com.**.annotations.ExcelStatisticIdentifier; import com.**.annotations.VerticalAxis; import com.**.annotations.VerticalAxisIndex; import com.**.annotations.VerticalAxisUnique; import com.**.excel.po.ExcelTitle; import com.**.excel.po.OrderExcelCount; import com.**.util.ExcelException; /** * @description: 生成导出excel类 * @author: z */ public class Excelkit { private static List titleList = null; private static Map rowReMap = new HashMap(); // 纵轴属性--行数关系映射表 private static Logger log = Logger.getLogger(Excelkit.class); private static HSSFWorkbook workbook=null; private static HSSFSheet sheet =null; private static InputStream is =null; private static String report_create_path;//服务器存取文件路径 private static String report_download_url;//文件下载路径 private static OutputStream os = null; /** * 创建Excel报表 * @param dataList 需要导出的数据集合 * @param realmName 请求访问的域名 * @param report_create_path 创建在服务器的存储路径 * @param reportName 报表和sheet名称 * @param wxcid * @param titleRowNo 表格菜单标题栏所属行号,第一行的行号为0,如果菜单标题栏上面还有顶部合并展示内容,那么这里的行号为1 * @param ifTop 是否有顶部合并展示内容 * @param ifEnd 是否有底部合并展示内容 * @param topTitle 顶部合并展示内容 * @param endTitle 底部合并展示内容 * @return * @throws ExcelException */ public static HttpServletResponse createExcelReport(List dataList,String realmName,String report_create_path,String reportName,String wxcid,int titleRowNo,boolean ifTop,boolean ifEnd,String topTitle,String endTitle,HttpServletResponse response) throws ExcelException{ //如果使用的是05.1的action请求方式,这里返回值为void checkNullOrValidLength(dataList); //获取当前日期 SimpleDateFormat sdf1=new SimpleDateFormat("yyyy"); SimpleDateFormat sdf2=new SimpleDateFormat("MM"); SimpleDateFormat sdf3=new SimpleDateFormat("dd"); String year = sdf1.format(new Date()); String month = sdf2.format(new Date()); String day = sdf3.format(new Date()); HttpServletResponse outPutExcel =null; try { File file = Excelkit.createSheet(report_create_path+"\\"+year+"\\"+month+"\\"+day+"\\",reportName, wxcid); List titleList = Excelkit.writeMiddleExcel(dataList, titleRowNo, 0); int endCellMun=titleList.size()-1; if(ifTop) {//是否有顶部合并项 Excelkit.createTotalTitle(topTitle, titleRowNo-1, 0, 0, 0, 0, endCellMun);//顶部合并项 } if(ifEnd) {//是否有底部合并项 int endmun=dataList.size()+titleRowNo+1; Excelkit.createTotalTitle(endTitle, endmun, 0, endmun,endmun, 0, endCellMun);//底部合并项 } File excel_file = Excelkit.writeEndExcel(file); String excel_name=reportName + "-" + wxcid + ".xlsx"; outPutExcel = Excelkit.outPutExcel(excel_file, excel_name, response); } catch (IOException e) { e.printStackTrace(); } catch (ExcelException e) { e.printStackTrace(); } //report_download_url=realmName+"/MSExcelReport/"+year+"/"+month+"/"+day+"/"+ reportName + "-" + wxcid + ".xlsx"; //log.debug("报表下载路径:"+report_download_url); //return report_download_url; return outPutExcel; } /** * 1.生成报表workbook和Sheet * @param fileName * @param wxcid * @return */ public static File createSheet(String report_download_url,String fileName, String wxcid) { File file =null; try { checkNullOrValidLength(fileName); checkNullOrValidLength(wxcid); report_create_path = report_download_url + fileName + "-" + wxcid + ".xlsx"; file = new File(report_create_path); checkFile(file); InputStream is = new FileInputStream(file); // 第一步,创建一个HSSFWorkbook,对应一个Excel文件 workbook = new HSSFWorkbook(); // 第二步,在workbook中添加一个sheet,对应Excel文件中的sheet sheet = workbook.createSheet(fileName); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (ExcelException e) { e.printStackTrace(); } return file; } /** * 2.创建顶部、底部等合并单元格部分 * @param topTitle 合并单元格内的内容 * @param rownum 创建合并单元格行的行号,从0开始 * @param column 创建合并单元格列的列号,从0开始,只需填写起始列号 * @param firstRow 从第*行 * @param lastRow 到第*行 * @param firstCol 从第*列 * @param lastCol 到第*列 */ public static void createTotalTitle(String topTitle,int rownum,int column,int firstRow, int lastRow, int firstCol, int lastCol) { Row row = sheet.createRow(rownum);//创建顶部行,第*行 Cell createCell = row.createCell(column);//创建第*个单元格 CellRangeAddress cellRangeAddress = new CellRangeAddress(firstRow, lastRow, firstCol, lastCol);//第firstRow至lastRow行,第firstCol至lastCol个单元格合并 sheet.addMergedRegion(cellRangeAddress); createCell.setCellValue(topTitle);//设置合并单元格内容 } /** * 3.报表中间部分:表格表头菜单+表格内容 * @param dataList * @param fileName * @param wxcid * @param titleRowNo 0.第一行 * @param titleColNo 0.第一列 * @return * @throws IOException * @throws ExcelException */ public static List writeMiddleExcel(List dataList,Integer titleRowNo, Integer titleColNo) throws IOException, ExcelException { checkNullOrValidLength(dataList); System.out.println(new Gson().toJson(dataList)); try { // 生成表头标题集合 titleList = createTitleList(dataList, titleRowNo, titleColNo); // 初始化excel头部标题栏 writeTitle(sheet, titleList, 20, setTitleStyle(workbook, null)); // 向excel写入数据 writeContent(dataList, titleList, sheet); } catch (IllegalAccessException e) { e.printStackTrace(); } return titleList; } /** * 4.Excel最后写入内容部分 * @param file * @return */ public static File writeEndExcel(File file) { try { // 写入流 os = new FileOutputStream(file); writeToStream(workbook, os); } catch (Exception e) { e.printStackTrace(); } finally { try { if (os != null) { os.close(); } if (is != null) { is.close(); } } catch (IOException e) { e.printStackTrace(); } titleList.clear(); rowReMap.clear(); //delFile(report_create_path); return file; } } /** * 5.将Excel文件以流的方式响应页面 * @param file * @param excel_name * @param response * @return */ public static HttpServletResponse outPutExcel(File file,String excel_name,HttpServletResponse response){ try { // 以流的形式下载文件。 InputStream fis = new BufferedInputStream(new FileInputStream(file)); byte[] buffer = new byte[fis.available()]; fis.read(buffer); fis.close(); // 清空response response.reset(); // 设置response的Header response.addHeader("Content-Disposition", "attachment;filename="+new String(excel_name.getBytes("UTF-8"), "iso8859-1")); response.addHeader("Content-Length", "" + file.length()); response.setContentType("application/octet-stream"); OutputStream toClient = new BufferedOutputStream(response.getOutputStream()); //workbook.write(toClient); toClient.write(buffer); toClient.flush(); toClient.close(); } catch (Exception e) { e.printStackTrace(); }finally { //下载完毕后删除服务器文件 log.debug("删除已下载的文件"); delFile(report_create_path); } return response; } /** * 通过文件绝对路径 删除单个文件 * * @param filePath */ public static void delFile(String filePath) { log.debug("删除文件:"+filePath); File delFile = new File(filePath); if (delFile.isFile() && delFile.exists()) { delFile.delete(); log.debug("删除文件成功"); } else { log.debug("没有该文件,删除失败"); } } public static void main(String[] args) { delFile("E:\\zhuzher\\//2019//04//11//前线突击统计报表-2cbc056565885f1bc7cb78be60808c36.xlsx"); } /** * 设置表头样式 * * @param workbook * @param style */ public static HSSFCellStyle setTitleStyle(HSSFWorkbook workbook, HSSFCellStyle style) { if (style == null) { style = workbook.createCellStyle(); } style.setAlignment(HorizontalAlignment.CENTER_SELECTION); // 左右居中 style.setVerticalAlignment(VerticalAlignment.CENTER);// 上下居中 /* * style.setBorderBottom(BorderStyle.THIN); //下边框 * style.setBorderLeft(BorderStyle.THIN);//左边框 * style.setBorderTop(BorderStyle.THIN);//上边框 * style.setBorderRight(BorderStyle.THIN);//右边框 */ HSSFFont font = workbook.createFont(); font.setBold(true); font.setFontHeight((short) 220); style.setFont(font); return style; } /** * 向输出流写入数据 * * @param filePath * @param workbook * @param outputStream * @throws IOException */ public static void writeToStream(Workbook workbook, OutputStream outputStream) throws IOException { workbook.write(outputStream); } /** * 向excel写入数据, 从第二行第一列开始 * * @param dataList * @param sheet * @param */ /* * public static void writeContent(List dataList,List * titleList, Sheet sheet) throws ExcelException, IllegalAccessException { * checkNullOrValidLength(dataList); writeContent(dataList,titleList, sheet); } */ /** * 根据反射,自动生成表头集合 * * @param dataList * @throws ExcelException */ public static List createTitleList(List dataList, Integer rowNo, Integer colNo) throws ExcelException { checkNullOrValidLength(dataList); checkNullOrValidLength(rowNo); checkNullOrValidLength(colNo); boolean hasExcelAnnotation = checkObjectAnnotationNotTitle(dataList.get(0), ExcelStatisticIdentifier.class); List titleList = new ArrayList(); if (hasExcelAnnotation) {// 如果实体类有注解 List colFieldList = getAnnotationFieldList(dataList.get(0), VerticalAxis.class); List colFieldList2 = getAnnotationFieldList(dataList.get(0), VerticalAxisIndex.class); for (Field field : colFieldList) { for (Field field2 : colFieldList2) { if (field.getName().equals(field2.getName())) { String cf_title = getVerticalAxisStringValue(field); String cf_title_index = getVerticalAxisIndexStringValue(field2); ExcelTitle excelTitle = new ExcelTitle(cf_title, rowNo, colNo + Integer.parseInt(cf_title_index)); titleList.add(excelTitle); } } } } // 根据标题纵坐标重新排序 Collections.sort(titleList, new Comparator() { public int compare(ExcelTitle o1, ExcelTitle o2) { return o1.getColNo() - o2.getColNo(); } }); return titleList; } /** * 向excel写入数据 * * @param dataList * @param sheet * @param */ public static void writeContent(List dataList, List titleList, Sheet sheet) throws ExcelException, IllegalAccessException { checkNullOrValidLength(dataList); boolean hasExcelAnnotation = checkObjectAnnotation(dataList.get(0), titleList, ExcelStatisticIdentifier.class); int startRow = titleList.get(0).getRowNo() + 1; int startCol = titleList.get(0).getColNo() + 1; int temp_col = startCol; System.out.println(new Gson().toJson(dataList)); for (T data : dataList) { // 如果有ExcelStatisticIdentifier注解, 说明当前实体类需要维度转换,从实体类中找出横轴注解属性,用于excel的横轴维度 if (hasExcelAnnotation) { // String ho_value = getAnnotationStringFieldValue(data, HorizontalAxis.class); // 实体类唯一分类标识符的属性 Field ve_field = getAnnotationField(data, VerticalAxisUnique.class); // 统计数值 // String statistic_value = getAnnotationStringFieldValue(data, // ExcelStatisticData.class); checkNullOrValidLength(ve_field); // 实体类唯一分类标示符的值 String ve_value = String.valueOf(ve_field.get(data)); // 实体类中当前注解上的值 List colFieldList = getAnnotationFieldList(data, VerticalAxis.class); for (ExcelTitle title : titleList) { for (Field colField : colFieldList) { // 属性注解的上的值 String cf_title = getVerticalAxisStringValue(colField); if (title.getName().equals(cf_title)) { int write_rowNo = startRow; if (rowReMap.containsKey(ve_value)) { write_rowNo = rowReMap.get(ve_value); } else { rowReMap.put(ve_value, write_rowNo); startRow++; } // 属性的值 writeToCell(colField.get(data) == null ? "" : String.valueOf(colField.get(data)), sheet, write_rowNo, title.getColNo()); } } // 如果横轴注解属性的值等于title,表示当前data的数据,属于这一列,需要进行写入操作 /* * if (title.getName().equals(ho_value)) { * * // 包含当前对象的纵轴值,说明之前已经有写入,获取到那条数据的行号 int write_rowNo = startRow; if * (rowReMap.containsKey(ve_value)) { write_rowNo = rowReMap.get(ve_value); } * else { rowReMap.put(ve_value, write_rowNo); // writeToCell(ve_value, sheet, * write_rowNo, ve_ho_colNo); // writeToCell(); startRow++; } * writeToCell(statistic_value, sheet, write_rowNo, title.getColNo()); } */ } } else { // 没有注解的情况下,直接按照实体类列表写入 Field[] fields = data.getClass().getDeclaredFields(); for (Field field : fields) { field.setAccessible(true); // 获取属性的值 String value = ((field.get(data) == null) ? "" : String.valueOf(field.get(data))); writeToCell(value, sheet, startRow, temp_col); temp_col++; } temp_col = startCol; startRow++; } } } /** * 获取VerticalAxis注解指定属性上指定注解的value值 * * @param field * @param z * @param * @return */ private static String getVerticalAxisStringValue(Field field) { Annotation annotation = field.getAnnotation(VerticalAxis.class); if (annotation == null) return null; return ((VerticalAxis) annotation).value(); } /** * 获取VerticalAxisIndex注解指定属性上指定注解的value值 * * @param field * @param z * @param * @return */ private static String getVerticalAxisIndexStringValue(Field field) { Annotation annotation = field.getAnnotation(VerticalAxisIndex.class); if (annotation == null) return null; return ((VerticalAxisIndex) annotation).value(); } /** * 获取一个对象中,标明了注解的属性 * * @param data * @param z * @param * @return * @throws IllegalAccessException */ private static Field getAnnotationField(T data, Class z) { Field[] fields = data.getClass().getDeclaredFields(); Field field_s=null; for (Field field : fields) { Annotation annotation = field.getAnnotation(z); if (annotation != null) { field.setAccessible(true); field_s=field; } } Class> superclass = data.getClass().getSuperclass(); if(superclass !=null){ Field[] fields2 = superclass.getDeclaredFields(); for (Field field : fields2) { Annotation annotation = field.getAnnotation(z); if (annotation != null) { field.setAccessible(true); field_s=field; } } } return field_s; } /** * 获取一个对象中,标明了注解的属性列表 * * @param data * @param z * @param * @return * @throws IllegalAccessException */ private static List getAnnotationFieldList(T data, Class z) { Field[] fields = data.getClass().getDeclaredFields(); Class> superclass = data.getClass().getSuperclass(); List resultList = new ArrayList(); for (Field field : fields) { Annotation annotation = field.getAnnotation(z); if (annotation != null) { field.setAccessible(true); resultList.add(field); } } if(superclass != null){ Field[] fields_father =superclass.getDeclaredFields(); for (Field field : fields_father) { Annotation annotation = field.getAnnotation(z); if (annotation != null) { field.setAccessible(true); resultList.add(field); } } } return resultList; } /** * 获取一个对象中,标明了注解的属性的值。如果类中没有相关注解,返回空。 适用于当前类中同样的注解,只标注了一个属性的情况 * * @param data * @param z * @param * @return * @throws IllegalAccessException */ private static String getAnnotationStringFieldValue(T data, Class z) throws IllegalAccessException { Field field = getAnnotationField(data, z); if (field == null) return null; field.setAccessible(true); return String.valueOf(field.get(data)); } /** * 检查实体类是否有注解,如果没有,不管。如果有,标题行为空的话,报错。 * * @param data * @param * @throws ExcelException */ private static boolean checkObjectAnnotation(T data, List titleList, Class z) throws ExcelException { boolean hasAnnotation = data.getClass().isAnnotationPresent(z); if (hasAnnotation) { // 如果titleList标题栏为空,则报错。 checkNullOrValidLength(titleList); return true; } return false; } /** * 检查实体类是否有注解,如果没有,不管。不检查标题行 * * @param data * @param * @throws ExcelException */ private static boolean checkObjectAnnotationNotTitle(T data, Class z) throws ExcelException { boolean hasAnnotation = data.getClass().isAnnotationPresent(z); if (hasAnnotation) { return true; } return false; } /** * 往sheet指定坐标单元格里面写入数据 * * @param sheet * @param row * @param col */ public static void writeToCell(String value, Sheet sheet, int row, int col) { writeToCell(value, getCell(sheet, row, col, null)); } /** * 往sheet指定坐标单元格里面写入数据 * * @param value * @param sheet * @param startRow * @param startCol */ public static void writeToCell(String value, Cell cell) { if (checkIntType(value)) { double a = Double.valueOf(value); cell.setCellValue(a); } else { cell.setCellValue(value); } } private static Boolean checkIntType(String value) { try { Integer.parseInt(value); return true; } catch (NumberFormatException e) { return false; } } /** * 根据横纵轴坐标获取单元格对象 * * @param sheet * @param row * @param col * @return */ public static Cell getCell(Sheet sheet, int rowNo, int colNo, Integer rowHeight) { Row row = getRow(sheet, rowNo, rowHeight); Cell cell = row.getCell(colNo); if (cell == null) { cell = row.createCell(colNo); } return cell; } /** * 根据横纵轴坐标获取行对象 * * @param sheet * @param rowNo * @param rowHeight * @return */ public static Row getRow(Sheet sheet, int rowNo, Integer rowHeight) { Row row = sheet.getRow(rowNo); if (row == null) { row = sheet.createRow(rowNo); if (rowHeight != null) { row.setHeightInPoints(rowHeight);// 设置行高 } } return row; } /** * 初始化excel标题, 如果标题列表为空,则不处理 * * @param sheet * @param rowHeight 行高 */ public static void writeTitle(Sheet sheet, List titleList, int rowHeight, HSSFCellStyle style) { if (titleList == null || titleList.size() == 0) return; Row row = getRow(sheet, titleList.get(0).getRowNo(), rowHeight); Integer init_colNo = titleList.get(0).getColNo(); for (int i = init_colNo; i < (init_colNo + titleList.size()); i++) { Cell cell = row.createCell(i); cell.setCellValue(titleList.get(i - init_colNo).getName()); if (style != null) { cell.setCellStyle(style);// 创建标题样式 } } } /** * @Title: getSheet @Description: 根据sheet索引号获取对应的sheet @param @param * workbook @param @param sheetIndex @param @return @return * Sheet @throws */ public static Sheet getSheet(Workbook workbook, int sheetIndex) { return workbook.getSheetAt(sheetIndex); } /** * @Title: createWorkbook @Description: 判断excel文件后缀名,生成不同的workbook @param @param * is @param @param excelFileName @param @return @param @throws * IOException @return Workbook @throws */ public static Workbook createWorkbook(InputStream is) throws IOException, InvalidFormatException { return WorkbookFactory.create(is); } /** * 检查文件是否存在,不存在则新建 * * @param file */ public static void checkFile(File file) throws ExcelException { if (file == null) { throw new ExcelException("文件路径不能为空"); } System.out.println("path--1:" + file.getPath()); if (!file.exists()) { System.out.println("0--当前文件不存在"); File parentFile = file.getParentFile(); if (!parentFile.exists()) { System.out.println("1--当前文件夹不存在,新建当前文件夹路径"); parentFile.mkdirs(); } System.out.println("2--当前文件不存在,新建当前文件"); } try { System.out.println("4--新建当前文件"); file.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } /** * 初始化excel的头部.默认从第0行,第0列开始 * * @param titleCol * @throws ExcelException */ public static void initTitle(List titleList, String... titleCols) throws ExcelException { checkNullOrValidLength(titleCols); initTitle(titleList, 0, 0, titleCols); } /** * 初始化excel的头部 * * @param titleCol * @throws ExcelException */ public static void initTitle(List titleList, int startRow, int startCol, String... titleCols) throws ExcelException { if (titleList == null) titleList = new ArrayList(); checkNullOrValidLength(titleCols); ExcelTitle excelTitle; for (String titleCol : titleCols) { excelTitle = new ExcelTitle(titleCol, startRow, startCol++); titleList.add(excelTitle); } } /** * 检查对象、数组的空值或者长度 * * @param o * @throws ExcelException */ private static void checkNullOrValidLength(Object o) throws ExcelException { if (o == null) throw new ExcelException("参数不允许为空"); if (o instanceof String[] && ((String[]) o).length == 0) { throw new ExcelException("请输入有效的数组长度"); } if (o instanceof List && ((List) o).size() == 0) { throw new ExcelException("请输入有效的数组长度"); } } } |