最近,公司做了一个界面上的表格导出为excel并下载的一个功能.下面将具体的做法记录一下,以便后面复习.
首先先说一下需求
一.界面上有一个表格:
就上面这个表格,我是写死的,要在界面上方有一个按钮,导出并下载的功能,上图中我还没有整理,见谅.
二.先做导出,我用的是poi导出,具体的例子网上有很多,需要导包什么的,这些我就不做多的介绍了
1.我先在 界面上写一个点击事件,使用window.open()方法进入到controller
$("#exportEx2").click(function () {
var url = "${ctx}/analysis/mobileApp/" + _mobileAppId + "/demoExport2";
alert("url:"+url);
window.open(url, "_self");
});
url是controller的地址,直接用window.open(),打开
2.后台controller的写法
@RequestMapping("/mobileApp/{mobileAppId}/demoExport2")
@ResponseBody
public void doExport2(@PathVariable("mobileAppId") int mobileAppId, String _mobileAppVersionId,HttpServletRequest request, HttpServletResponse response) throws IOException {
// 文件名
String filename = "自定义事件.xls";
BufferedInputStream in = null;
BufferedOutputStream out = null;
try {
List<Map<String, String>> list = new ArrayList<Map<String, String>>();
for (int i = 0 ; i<18 ; i++) {
//组装测试数据
Map<String, String> map = new HashMap<String, String>();
map.put("ri", ""+i);
map.put("name", "test0"+i);
map.put("age", "23");
list.add(map);
}
// 第一步:定义一个新的工作簿
XSSFWorkbook wb = new XSSFWorkbook();
// 第二步:创建一个Sheet页
XSSFSheet sheet = wb.createSheet("startTimeendTime");
sheet.setDefaultRowHeight((short) (2 * 256));//设置行高
sheet.setColumnWidth(0, 4000);//设置列宽
sheet.setColumnWidth(1,5500);
sheet.setColumnWidth(2,5500);
XSSFFont font = wb.createFont();
font.setFontName("宋体");
font.setFontHeightInPoints((short) 16);
XSSFRow row = sheet.createRow(0);
XSSFCell cell = row.createCell(0);
cell.setCellValue("流水号 ");
cell = row.createCell(1);
cell.setCellValue("姓名");
cell = row.createCell(2);
cell.setCellValue("年龄");
XSSFRow rows;
XSSFCell cells;
for (int i = 0; i < list.size(); i++) {
// 第三步:在这个sheet页里创建一行
rows = sheet.createRow(i+1);
// 第四步:在该行创建一个单元格
cells = rows.createCell(0);
// 第五步:在该单元格里设置值
cells.setCellValue(list.get(i).get("ri"));
cells = rows.createCell(1);
cells.setCellValue(list.get(i).get("name"));
cells = rows.createCell(2);
cells.setCellValue(list.get(i).get("age"));
cells = rows.createCell(3);
}
//开始执行写入操作
String rootpath = request.getSession().getServletContext().getRealPath( "/");
File file = new File(rootpath+"temp.xls");
wb.write(new FileOutputStream(file));
response.setContentType("application/vnd.ms-excel; charset=utf-8") ;
String showName = "多事件/多维度表格.xlsx";
response.setHeader("Content-Disposition", "attachment;filename=" + new String(showName.getBytes("UTF-8"), "iso8859-1"));
in = new BufferedInputStream(new FileInputStream(file));
out = new BufferedOutputStream(response.getOutputStream());
byte[] data = new byte[1024];
int len = 0;
while (-1 != (len=in.read(data, 0, data.length))) {
out.write(data, 0, len);
}
} catch (Exception e) {
logger.error("download file encount error!");
} finally {
try {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
} catch (IOException e) {
logger.error("download file colse io encount error!");
}
}
}
首先这个controller的前面,我拼了一个List<Map<String, String>> ,这个里面存放的是数据.
后来使用了poi的一些api,去创建excel工作sheet等,这些我也就不细说了,回头好好看看poi的demo就啥都明白了,并且我这里是写死的数据,for循环都是遍历的死数据,还是比较简单,按理说写到这里,controller走完 ,前台就可以弹出一个框,也就是下面这个框:
然后选择下载地址就可以导出并下载了,但是事情没有想象的那么简单,我点完按钮之后,发现跳转到了一个空白页面
window.open()函数原本就是打开一个页面,我设置的"_self",也就是在本浏览器页面再打开一个页面,但是没有打开,是为什么呢,后来一遍一遍试,并且叫来了老大帮我看,发现使我们的项目会拦截这个请求,也就是说我新写的一个controller没有再拦截器的配置页面配置,所以会拦截,接下来,我在拦截器的配置页面中配置了这个controller,就弹出来了,下来下来的excel的内容是我拼接的list<Map>中的内容.
3.接下来,我怎么获取到页面中的表格中的数据,然后传到后台呢,这就用到了jquery的知识,
首先我前段页面的表格其实就是一个table 如下:
<table style="width: 100%; border: 1px solid black;" id="excelTable">
<tr style="width: 100%; height: 30px; border: 1px solid black;">
<td style="width: 20%;">时间</td>
<td>域名</td>
<td>城市</td>
<td>用户量</td>
<td>页面浏览量</td>
</tr>
<tr>
<td>09-12 周三</td>
<td>com.app.tingyun</td>
<td>北京</td>
<td>32</td>
<td>76</td>
</tr>
<tr>
<td>09-12 周四</td>
<td>com.app.tingyun</td>
<td>上海</td>
<td>32</td>
<td>76</td>
</tr>
<tr>
<td>09-12 周三</td>
<td>com.app.tingyun</td>
<td>广州</td>
<td>32</td>
<td>76</td>
</tr>
</table>
我可以试用jqyery遍历这个table,将其中的内容转换成json字符串,然后传到后台
遍历table的代码如下:
function getExcelJson(){
var excelJson = new Array();
$("#excelTable tr").each(function(i){
var arr = new Array();
$(this).children("td").each(function(j){
var aa = $(this).text();
arr.push($(this).text())
});
excelJson.push(arr);
});
var excelJsonTxt = JSON.stringify(excelJson);
return excelJsonTxt;
}
返回一个json类型的字符串,然后再url后面加上参数,使用get请求的方式传过去,其实这里肯定不能用get请求方式将这个参数传过去,得需要post请求,但是时间来不及了,我就先使用get方式传过去了,也没报错,后面我再修改成post请求方式吧,所以点击事件中的url修改为如下:
$("#exportEx2").click(function () {
var excelJsonTxt = getExcelJson();
var url = "${ctx}/analysis/mobileApp/" + _mobileAppId + "/demoExport2?excelJsonTxt="+encodeURIComponent(excelJsonTxt);
alert("url:"+url);
window.open(url, "_self");
});
这里就是将excelJsonTxt 参数传过去,并且做了一下 encode处理,我这里就不多说了,搞过前端的都懂.
4.后面的controller 相应的也需要修改,接收到excelJsonTxt 参数后,动态的填充excel,controller如下:
/**
* @Description: 导出excel
* @auther:
* @date: 2018/9/30/0030 14:34
* @return
*/
@RequestMapping("/mobileApp/{mobileAppId}/demoExport2")
@ResponseBody
public void doExport2(@PathVariable("mobileAppId") int mobileAppId, String _mobileAppVersionId,HttpServletRequest request, HttpServletResponse response) throws IOException {
// 文件名
String filename = "自定义事件.xls";
String excelJsonTxt = request.getParameter("excelJsonTxt");
JSONArray jsonArray = JSON.parseArray(excelJsonTxt);
BufferedInputStream in = null;
BufferedOutputStream out = null;
try {
// 第一步:定义一个新的工作簿
XSSFWorkbook wb = new XSSFWorkbook();
// 第二步:创建一个Sheet页
XSSFSheet sheet = wb.createSheet("startTimeendTime");
sheet.setDefaultRowHeight((short) (2 * 256));//设置行高
sheet.setColumnWidth(0, 4000);//设置列宽
sheet.setColumnWidth(1,5500);
sheet.setColumnWidth(2,5500);
XSSFFont font = wb.createFont();
font.setFontName("宋体");
font.setFontHeightInPoints((short) 16);
XSSFRow row = sheet.createRow(0);
XSSFCell cell = row.createCell(0);
JSONArray tHead = (JSONArray) jsonArray.get(0);
for(int i=0; i<tHead.size(); i++){
cell.setCellValue(tHead.get(i).toString());
cell = row.createCell(i+1);
}
XSSFRow rows;
XSSFCell cells;
for (int i = 1; i < jsonArray.size(); i++) {
// 第三步:在这个sheet页里创建一行
rows = sheet.createRow(i+1);
// 第四步:在该行创建一个单元格
cells = rows.createCell(0);
// 第五步:在该单元格里设置值
JSONArray tBody = (JSONArray) jsonArray.get(i);
for(int j=0; j<tBody.size();j++){
cells.setCellValue(tBody.get(j).toString());
cells = rows.createCell(j+1);
}
}
//开始执行写入操作
String rootpath = request.getSession().getServletContext().getRealPath( "/");
File file = new File(rootpath+"temp.xls");
wb.write(new FileOutputStream(file));
response.setContentType("application/vnd.ms-excel; charset=utf-8") ;
String showName = "多事件/多维度表格.xlsx";
response.setHeader("Content-Disposition", "attachment;filename=" + new String(showName.getBytes("UTF-8"), "iso8859-1"));
in = new BufferedInputStream(new FileInputStream(file));
out = new BufferedOutputStream(response.getOutputStream());
byte[] data = new byte[1024];
int len = 0;
while (-1 != (len=in.read(data, 0, data.length))) {
out.write(data, 0, len);
}
} catch (Exception e) {
logger.error("download file encount error!");
} finally {
try {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
} catch (IOException e) {
logger.error("download file colse io encount error!");
}
}
}
将接受到的excelJsonTxt 参数转换成JSONARRAY对象,然后填充到单元格中,后面的代码一看便知.
至此,导出为excel并下载将告一段落,其实其中还有很多没有明白的地方,以后在慢慢补充.
不积跬步,无以至千里
不积小流,无以成江海