【设计模式】模板模式实现报表模板
需求:报表生产都大同小异,流程一样,但是具体的实现不同(如数据不同,报表名不同,报表列不同)。
如果每一次报表都复制粘贴就太码农。所以很自然的想到了模板模式。
设计:
1.抽象类包含方法createReport(流程方法,既创建报表,生产表头,将数据放入报表中,生产报表)
2.抽象方法(各个报表不同的实现):
getReportName:获取报表名
getCloumName:获取列名生产表头
getReportData:获取数据
使用:
1.继承此类,实现抽象方法。调用createReport方法即可生成报表
2.默认生成的报表规则是根据类的属性顺序对应报表列顺序(表达能力欠缺,没关系直接看下图)
3.提供方法getDataCloumName(),可重写此方法指定顺序列,此方法返回List<String> 。
例:指定返回值为[b,a,c,d],则生成的报表如下
4.若对象中含有Date类型,会默认转换为"yyyy-MM-dd HH:mm:ss"。若想修改Date类型的格式可重写getDateFormate方法。
代码:
package com.gls.manage.service; import com.gls.pojo.Admin; import org.apache.poi.hssf.usermodel.*; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.context.request.ServletWebRequest; import javax.servlet.http.HttpServletResponse; import java.io.OutputStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @Author Stephen Hu * @Description //TODO 报表模板 * 继承此类 提供报表名 列名 报表数据 即可生成报表 * @Date 15:26 2018/7/4 **/ public abstract class ReportTemplateService<T> { private static final String defualtDateFormate = "yyyy-MM-dd HH:mm:ss"; public void createReport(HttpServletResponse response){ try { //获取报表名 String reportName = getReportName(); //获取列名 List<String> cloumName = getCloumName(); //获取报表数据 List<T> reportData = getReportData(); HSSFWorkbook hssfWorkbook = new HSSFWorkbook(); HSSFSheet sheet = hssfWorkbook.createSheet(); //设置表头 setReportHead(hssfWorkbook, sheet, cloumName); //填充数据 setReportData(hssfWorkbook, sheet, reportData, cloumName); //返回报表 String codedFileName = java.net.URLEncoder.encode(reportName, "UTF-8"); response.setContentType("application/vnd.ms-excel"); response.setHeader("Content-disposition", "attachment;filename=" + codedFileName + ".xlsx"); OutputStream ouputStream = response.getOutputStream(); hssfWorkbook.write(ouputStream); ouputStream.flush(); ouputStream.close(); }catch (Exception e){ e.printStackTrace(); } } private void setReportData(HSSFWorkbook hssfWorkbook,HSSFSheet sheet,List<T> reportData,List<String> cloumName){ if(reportData.isEmpty()){ return; } List<String> dataCloumName = getDataCloumName(); //无序列指定 if(dataCloumName==null||dataCloumName.isEmpty()){ noOraderSetReportData(hssfWorkbook,sheet,reportData,cloumName); }else{//有序列指定 oraderSetReportData(hssfWorkbook,sheet,reportData,cloumName,dataCloumName); } } private void oraderSetReportData(HSSFWorkbook hssfWorkbook,HSSFSheet sheet,List<T> reportData,List<String> cloumName,List<String> dataCloumName){ //行循环 for (int i = 0; i < reportData.size(); i++) { HSSFRow row = sheet.createRow(i + 1); //列循环 T data = reportData.get(i); for (int j = 0; j <cloumName.size();j++ ) { Object value = getGetMethodValue(data, dataCloumName.get(j)); if (value==null){ continue; } //如果为Date类型则转换为字符串 if("Date".equals(value.getClass().getSimpleName())){ value = Date2String(value); } HSSFCell cell = row.createCell(j); cell.setCellValue(value.toString()); //设置列的样式 cell.setCellStyle(getCellStyle(hssfWorkbook)); //设置列的宽度 sheet.setColumnWidth(j, value.toString().getBytes().length*2*256); } } } private void noOraderSetReportData(HSSFWorkbook hssfWorkbook,HSSFSheet sheet,List<T> reportData,List<String> cloumName){ Class<?> aClass1 = reportData.get(0).getClass(); //获取类中所有的属性 Field[] declaredFields = aClass1.getDeclaredFields(); //行循环 for (int i = 0; i < reportData.size(); i++) { HSSFRow row = sheet.createRow(i + 1); //列循环 T data = reportData.get(i); for (int j = 0,k=0; j <cloumName.size();k++ ) { Object value = getGetMethodValue(data, declaredFields[k].getName()); if (value==null){ continue; } //如果为Date类型则转换为字符串 if("Date".equals(declaredFields[k].getType().getSimpleName())){ value = Date2String(value); } HSSFCell cell = row.createCell(j); cell.setCellValue(value.toString()); //设置列的样式 cell.setCellStyle(getCellStyle(hssfWorkbook)); //设置列的宽度 sheet.setColumnWidth(j, 5000); j++; } } } private String Date2String(Object value){ String dateFormate = getDateFormate(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat(dateFormate); return simpleDateFormat.format(value); } private Object getGetMethodValue(T data,String methodName){ if("serialVersionUID".equals(methodName)){ return null; } Object value = null; //获取对象get方法 Class<?> aClass = data.getClass(); methodName = ("get"+methodName.substring(0,1).toUpperCase()+methodName.substring(1)); try { Method method = aClass.getMethod(methodName); value = method.invoke(data); } catch (Exception e) { e.printStackTrace(); } return value; } /** * @Author Stephen Hu * @Description //TODO 设置报表头 * @Date 15:52 2018/7/4 * @Param [hssfWorkbook, sheet, cloumName] * @return void **/ private void setReportHead(HSSFWorkbook hssfWorkbook,HSSFSheet sheet,List<String> cloumName){ HSSFRow row = sheet.createRow(0); for (int i = 0; i < cloumName.size(); i++) { //创建列 HSSFCell cell = row.createCell(i); cell.setCellValue(cloumName.get(i)); //设置列的样式 cell.setCellStyle(getCellStyle(hssfWorkbook)); //设置列的宽度 sheet.setColumnWidth(i, cloumName.get(i).getBytes().length*2*256); } } /** * @Author Stephen Hu * @Description //TODO 获取样式 * @Date 15:52 2018/7/4 * @Param [hssfWorkbook] * @return org.apache.poi.hssf.usermodel.HSSFCellStyle **/ private HSSFCellStyle getCellStyle(HSSFWorkbook hssfWorkbook){ //创建设置属性对象 HSSFCellStyle CellStyle = hssfWorkbook.createCellStyle(); //设置居中 CellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); CellStyle.setAlignment(HSSFCellStyle.ALIGN_RIGHT); CellStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN); //下边框 CellStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN);//左边框 CellStyle.setBorderTop(HSSFCellStyle.BORDER_THIN);//上边框 CellStyle.setBorderRight(HSSFCellStyle.BORDER_THIN);//右边框 //设置字体 HSSFFont font = hssfWorkbook.createFont(); font.setFontName("微软雅黑"); font.setFontHeightInPoints((short) 12);//设置字体大小 CellStyle.setFont(font); return CellStyle; } public abstract String getReportName(); public abstract List<String> getCloumName(); public abstract List<T> getReportData(); /** * @Author Stephen Hu * @Description //TODO * 1.此方法不重写 默认按照对象的属性顺序对应表头 * 例: * 表头 A B C * 类属性 private int id; private String name;private int age; * 则对应: A B C * id值 name值 age值 * 2.此方法重写 按照此方法指定的类属性顺序对应表头 * 例: * 表头 A B C * 类属性 private int id; private String name;private int age; * 重写方法返回的list ["name","id","age"] * 则对应:A B C * name值 id值 age值 * @Date 17:47 2018/7/4 * @Param [] * @return java.util.List<java.lang.String> **/ public List<String> getDataCloumName(){return null;}; /** * @Author Stephen Hu * @Description //TODO 如有date类型需要转成相应的格式 默认格式yyyy-MM-dd * @Date 18:13 2018/7/4 * @Param [dateFormate] * @return java.lang.String **/ public String getDateFormate(){ return defualtDateFormate; } }
基本功能都实现了 ,只是还有很多细节需要优化 。
若有好的建议或者疑问欢迎加群:474586959