【设计模式】模板模式实现报表模板

需求:报表生产都大同小异,流程一样,但是具体的实现不同(如数据不同,报表名不同,报表列不同)。

如果每一次报表都复制粘贴就太码农。所以很自然的想到了模板模式。

设计:

        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