基于freemarker实现excel的模板导出

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ZhangY1217/article/details/82383344

这里简单介绍一下使用freemarker的好处,适用于复杂的模板导出功能,并且还可以保持原有模板的一些方法。 

第一步:添加依赖

我的项目是基于maven,所以在pom.xml中添加一下依赖就可以了:

<dependency>  
   <groupId>org.freemarker</groupId>  
   <artifactId>freemarker</artifactId>  
   <version>2.3.20</version>  
</dependency>

第二步:把excel另存为xml

在这里我要说一下,excel在另存为xml时里面的图片会丢失,它并不会像word那样生成一个占位符。所以我这个导出的excel是没有图片的。言归正传,这就是我另存为的xml的样例,其中row为行,cell为单元格

第三步:把要插入的数据使用freemarker的标签----${}替换

看到这里的${},是不是觉得它很像jstl标签,它的用法确实和jstl差不多,jstl是获取session中的值,而他是获取dataMap中的值;而且都是可以循环的便利的,它的便利标签就是

<#list list as item><#--其中list为你后台在dataMap中的key-->
    <#if item.detaildata??><#--判断是否为空,如果不为空则显示内容-->

<#--${item.detaildata}是获取list的子元素的值-->
 <Cell ss:StyleID="s37"><Data ss:Type="String">${item.detaildata}</Data></Cell>
   <#else>
<#--否则显示空的单元格-->
   <Cell ss:StyleID="s37"/>
  </#if>
  </#list>

我想很多人还是不清楚我讲的,可能确实是我的语言组织能力不好,不多说直接上截图,简洁明了

第四步:把xml的后缀名改成ftl,并且在webapp中新建template,把xxx.ftl,放到里面

好了基本的操作已经做完了,下面就是后台代码了。因为我的项目是MVC的设计理念并没有使用任何框架,所以把后台分为了四个层面:数据库对象序列化(dto),数据库访问层(DAO),数据处理层(service),控制层(servlet),算了还是用一个简单的例子吧,我开发的项目可能就要从头讲了。废话不多说先上service的代码,是一个封装好的类,可以直接调用的:

public class ExportExcelService {
    public static void export(String templatePath, Map<String, Object> dataMap,
            String buildFile, String newName,HttpServletRequest request,HttpServletResponse response) {
        try {
            ServletContext application = request.getSession().getServletContext();
            Configuration configuration = new Configuration();
            configuration.setDefaultEncoding("utf-8");
            String path = application.getRealPath("template");

// 此处是本类Class.getResource()相对于模版文件的相对路径
            configuration.setDirectoryForTemplateLoading(new File(path));
            Template template = null;
            File outFile = new File(buildFile);
            Writer writer = null;
            template = configuration.getTemplate(templatePath);
            template.setEncoding("utf-8");
            writer = new BufferedWriter(new OutputStreamWriter(
                    new FileOutputStream(outFile), Charset.forName("utf-8")));// 此处为输
            template.process(dataMap, writer);
            writer.flush();
            writer.close();
            // return true;
            // 设置response的编码方式
            response.setContentType("application/x-msdownload");
            // 设置附加文件名
            response.setHeader("Content-Disposition", "attachment;filename="
                    + new String(newName.getBytes("utf-8"), "iso-8859-1"));
            // 读出文件到i/o流
            FileInputStream fis = new FileInputStream(outFile);
            BufferedInputStream buf = new BufferedInputStream(fis);
            byte[] b = new byte[1024];// 相当于我们的缓存
            long k = 0;// 该值用于计算当前实际下载了多少字节
            // 从response对象中得到输出流,准备下载
            OutputStream myout = response.getOutputStream();
            // 开始循环下载
            while (k < outFile.length()) {
                int j = buf.read(b, 0, 1024);
                k += j;
                // 将b中的数据写到客户端的内存
                myout.write(b, 0, j);
            }
            // 将写入到客户端的内存的数据,刷新到磁盘
            myout.flush();
            myout.close();
        } catch (Exception e) {
            e.printStackTrace();
            // return false;
        }
    }
}

然后我们在servlet中调用这个类中的方法,重点就看我标黄的代码,这个是自己生成的list,而不是通过其他代码生成的,标蓝色的则是单一的键值对,红色代码为如果导出的数据不是模板的7天数据,则自动补充不足的空数据,以完成模板显示空单元格如下:

@WebServlet("/excelExport")
public class exportExcelServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String uz=new String(URLDecoder.decode(req.getParameter("uz"),"utf-8"));
        ReimburseService res=new ReimburseService();
        String[] data=uz.split(",");
        String uname=uz.split(",")[1];
        String weeknumber=uz.split(",")[0];
        Model model=res.querydetail(uname, weeknumber);
        Map<String, Object> dataMap = new HashMap<String, Object>();
        dataMap.put("username",uz.split(",")[2]);
        dataMap.put("writedata",uz.split(",")[3]);
        dataMap.put("appartment",uz.split(",")[4]);

        List list=(List) model.getData();
        for(int i=list.size();i<7;i++){
            ReimburseDetail rd=new ReimburseDetail();
            rd.setDetaildata("");
            rd.setHotelfare("");
            rd.setLocation("");
            rd.setLongfare("");
            rd.setOtherfare("");
            rd.setShortfare("");
            rd.setProject("");
            rd.setFaredescription("");
             list.add(rd);
        }

        //对list进行排序
        for(int i=0;i<list.size();i++){
            ReimburseDetail rdl=(ReimburseDetail)list.get(i);
            try {
                if(!rdl.getDetaildata().equals("")){
                    int b=dayForWeek(rdl.getDetaildata());
                    if(b-1!=i){
                        Object objA= list.get(i);
                        list.set(i, list.get(b-1));
                        list.set(b-1, objA);
                    }
                }            
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        dataMap.put("list",list);
        List ls=new  ArrayList();
        String[] num={"A","B","C","D","E","F","G"};
        String[] Formula={"-9","-10","-11","-12","-13","-14","-15"};
        for(int i=0;i<num.length;i++){
            Map<String,Object> map = new HashMap<String,Object>();  
            map.put("num",num[i]);
            ReimburseDetail r=(ReimburseDetail)list.get(i);
            map.put("faredescription",r.getFaredescription());
            map.put("Formula", Formula[i]);
            map.put("col", i+1);
            ls.add(map); 
        }
        dataMap.put("ls",ls);

        ServletContext application = req.getSession().getServletContext();
        /*********输出图片未解决********************/
        String a=application.getRealPath("imgs");
        String img = getImageStr(a+"/ceit.png");
        dataMap.put("image", img);
        /***********************************/
        String  templateName = "excel.ftl";   //模板名称
        java.text.DateFormat format1 = new java.text.SimpleDateFormat("yyyy-MM-dd");
        String exportexcel = application.getRealPath("template")+format1.format(new Date())+ ".xls";
        ExportExcelService.export(templateName, dataMap, exportexcel, "每周报销单("+format1.format(new Date())+").xls",req,resp);
        
    }
    /***************获取日期是星期几*************************/
    public  static  int  dayForWeek(String pTime) throws  Exception {   
        SimpleDateFormat format = new  SimpleDateFormat("yyyy-MM-dd" );   
         Calendar c = Calendar.getInstance();   
         c.setTime(format.parse(pTime));   
         int  dayForWeek = 0 ;   
         if (c.get(Calendar.DAY_OF_WEEK) == 1 ){   
          dayForWeek = 7 ;   
         }else {   
          dayForWeek = c.get(Calendar.DAY_OF_WEEK) - 1 ;   
         }   
         return  dayForWeek;   
        }
    /**************将图片转成base64********************/
    public String getImageStr(String imgFile) {
        InputStream in = null;
        String da="";
        byte[] data = null;
        try {
            in = new FileInputStream(imgFile);
            data = new byte[in.available()];
            in.read(data);
            in.close();
             da=new String(Base64.encodeBase64(data),"UTF-8");
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
        e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return da;

    }

}
好了,文章写的这里就圆满结束了。唯一的遗憾就是图片导出还没有解决,等解决了再来补充,当然如果是导出word模板是可以导出图片的因为再把带有图片的word转xml时会生成这个标签------》<w:binDataw: name="wordml://03000001.png" xml:space ="preserve">${image}</w:binData><v:shape id="_x0000_i1025" type="#_x0000_t75" style="width:414.75pt; height:319.5pt">  <v:imagedata src="wordml://03000001.png" o:title=""/></v:shape>关于这个网上有很多,可以多去逛逛。

猜你喜欢

转载自blog.csdn.net/ZhangY1217/article/details/82383344
今日推荐