基于freemarker实现excel的模板导出

这里简单介绍一下使用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实现excel的模板导出

第三步:把要插入的数据使用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,放到里面

基于freemarker实现excel的模板导出

好了基本的操作已经做完了,下面就是后台代码了。因为我的项目是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="

// 读出文件到i/o流

BufferedInputStream buf = new BufferedInputStream(fis);

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>关于这个网上有很多,可以多去逛逛。

相关推荐