1.html上的Table跟Chart的导出(后台使用ssm框架)

最近在工作中遇到的一个问题,要将html标签里的Table跟echarts生成报表导出到excel里面,没有搞过各种谷歌!-_-,还好解决了,就分享一下这次踩坑的经验了.

所使用的jar包:

commons-codec-1.9.jar
commons-lang3-3.3.2.jar
jsoup-1.8.3.jar
poi-3.9.jar
slf4j-api-1.7.7.jar
slf4j-simple-1.7.7.jar
table-to-xls-0.0.1-RELEASE.jar//这个可以在oscchina的git上找到的谢谢大神的代码了


首先说一说实现的思路:

  1. 前端用jquery获取Table标签的内容跟echarts报表的图片的base64----->2.ajax的post传输数据到后台----->3将获取到的数据分别处理,表格生成excel再将base64还原成图片插入到生成的excel里面

具体实现:

第一步:

        首先说明一下echarts在生成图表之前都要先初始化一个东西所以base64可以根据这个来获取

var showCharts=[];//这是个全局变量用来接收每个chart对象的

//在每个chart初始化的时候将初始化的对象放进数组
var myChart = echarts.init(document.getElementById(tagid));
showCharts.push(myChart);

第二步:通过页面上的一个按钮触发一个函数(click事件)

function export2Excel(tableId){
   var tableContext =$("#"+tableId).html();
   var datas={}
   if(tableContext.length>37){//这里为什么判断长度大于37因为表格动态生成的默认长度就有36!!:)
     tableContext="<table>"+tableContext+"</table>";
     datas.tableContext=tableContext;
   }
	  	
   if(showCharts.length!=0){
	 var imgUrls = [];
	 for(var x  =0; x<showCharts.length;x++){
	   imgUrls.push(showCharts[x].getDataURL("png"));
	 }
	datas.imgUrls=imgUrls;
    }
	  	
   if(datas.tableContext){
	 $.ajax({
	    url:url,//发送到后台处理这些数据的控制器地址(这个只是负责发送数据到后台)
	    type: "POST",
	    dataType: "json",
	    data: $.param(datas,true),//发送数组这样的数据格式必用这个东西不然很可能出问题
	    success: function (result) {
	      if(parseInt(result.status)==0){
		 location.href=url+fileName//用来处理下载请求的控制器地址跟下载的文件名,为啥要有这一步呢因为ajax不支持下载的浏览器是弹不出那个保存文件的框的(有没有草泥马)
	      }
	    },
	    failure: function (err) {
		 alert("ajax产生了错误!");
	     }
	   });
	 }else{
	    alert("必须有表格或者图表才能下载");
	  }

第三步:后台处理

//这个控制器是用来预处理ajax的post请求提交过来的数据的
@RequestMapping(value = "preExportToExcel",method=RequestMethod.POST)
@ResponseBody
public  AjaxData<Map<String,String>> preExportToExcel(String tableContext, String[] imgUrls,HttpServletRequest req,HttpServletResponse rep) throws Exception {
      AjaxData<Map<String,String>> ajax = new AjaxData<Map<String,String>>();
      tableContext=HtmlUtils.htmlUnescape(tableContext);
      String filePath=req.getSession().getServletContext().getRealPath("/")+"temp";
      filePath = filePath.replace("\\","/")+"/";
      HtmlTableToExcel html = new HtmlTableToExcel(imgUrls, filePath, tableContext);//这个对象会将传递过来的数据生成excel
      String xlsFileName = html.mergePicAndExcel();
      Map<String,String> map = new HashMap<String,String>();
      map.put("xlsFileName", xlsFileName);
      ajax.setData(map);
      return ajax;
}

//这个控制器才是真正的下载控制器对应ajax里面的location.href那句代码
//采用servlet这种方式下载的原因就是可以在下载完成的时候可以将文件删掉
@RequestMapping(value = "exportToExcel",method=RequestMethod.GET)
@ResponseBody
public void exportToExcel(String xlsFileName, HttpServletResponse rep) throws Exception {
		OutputStream out = null;
		try {
			rep.reset();
			rep.setContentType("application/vnd.ms-excel");
			rep.setHeader("Content-Disposition","attachment; filename=" + xlsFileName.substring(xlsFileName.lastIndexOf("/") + 1));
			out = rep.getOutputStream();
			System.out.println(xlsFileName);
			out.write(FileUtils.readFileToByteArray(new File(xlsFileName)));
			out.flush();
			File file = new File(xlsFileName.substring(0,xlsFileName.lastIndexOf("/")));
			File[] files= file.listFiles();
			for (File file2 : files) {
				FileUtils.deleteFile(file2.getAbsolutePath());
			}
		} catch (IOException e) {
			throw new RuntimeException(e.getMessage() + "文件下载失败");
		} finally {
			if (out != null) {
				try {
					out.close();
				} catch (IOException e) {
					throw new RuntimeException(e.getMessage() + "文件下载失败");
				}
			}
		}
	}

所用类的代码:

值得注意的是图片的后缀名必须是.png结尾的额不然透明背景的图片插入到excel里面是要变成黑乎乎的

/**
 * 将图片的base64码解密并还原图片(只支持支持格式"png","jpg",支持多张图片)
 *
 */
public class Base64ToImage {
 /**
  * Logger for this class
  */
 private static final Logger logger = Logger.getLogger(Base64ToImage.class);
 
 /**
  * 枚举类用来选择模式
  *
  */
 public static enum PictureType {
 //png的图片类型
 TYPE_PNG,TYPE_JPG;
 }
 
 /**
  * 
  * @param imgUrls  多张图片的base64码组
  * @param filePath 保存文件的路径
  * @param type     生成文件的模式
  * @return         返回生成的图片的名字
  */
 public static List<String> base64ToPicture(String[] imgUrls,String filePath,Base64ToImage.PictureType type){
 String suffix="";
 
 //判断传入的图片类型
 if(type==PictureType.TYPE_PNG) suffix=suffix+".png";
 if(type==PictureType.TYPE_JPG) suffix=suffix+".jpg";
 
 //判断空值以及0值
 if(imgUrls.length==0||imgUrls==null||StringUtils.isBlank(filePath)){
 return null;
 }
 
 List<String> fileNameList= new ArrayList<String>();
 for (String imgUrl : imgUrls) {
 String fileName = UUID.randomUUID().toString();
 String realFileName=filePath+fileName;
 if(isCreatePic(imgUrl, realFileName,suffix)) fileNameList.add(fileName+suffix);
 logger.info(fileName);
 }
 return fileNameList;
 }
 /**
  * 
  * @param imgsURl 图片的base64码
  * @param fileName 图片名称
  * @return 是否生成图片成功
  */
 private static boolean isCreatePic(String imgsURl, String fileName,String suffix){
 BASE64Decoder decoder = new BASE64Decoder();
 boolean flag = true;
 OutputStream out=null;
 try {
 String[] url = imgsURl.split(",");
 String u = url[1];
 // Base64解码
 byte[] buffer = new BASE64Decoder().decodeBuffer(u);
 // 生成图片
 out= new FileOutputStream(new File(fileName + suffix));
 out.write(buffer);
 out.flush();
 } catch (Exception e) {
 flag = false;
 }finally{
 try {
 if(out!=null)out.close();
 } catch (IOException e) {
 flag=false;
 }
 }
 return flag;
 }
}
  

 // 将页面上的html 表格导出(支持页面上的报表图片导出,只支持单表的导出,只支持png格式图片插入)
public class HtmlTableToExcel {
 private static final Logger logger = Logger.getLogger(HtmlTableToExcel.class);
 
 //图片的base64码
 private String[] imgUrls;
 
 //存放生成文件的路径
 private String filePath;
 
 //生成的文件名字
// private String fileName=UUID.randomUUID().toString();
 
 private String tableContext;

 public HtmlTableToExcel(String[] imgUrls,String filePath, String tableContext) {
 this.imgUrls = imgUrls;
 this.tableContext = tableContext;
 this.filePath=filePath;
 }
 
 public String createExcel(){
 FileOutputStream fout=null;
 try {
 String xlsFileName =this.filePath+UUID.randomUUID().toString()+".xls";
 fout = new FileOutputStream(xlsFileName);
 TableToXls.process(tableContext, fout);
 return xlsFileName;
 } catch (FileNotFoundException e) {
 e.printStackTrace();
 }finally{
 try {
 if(fout!=null)fout.close();
 } catch (IOException e) {
 e.printStackTrace();
 }
 }
 return null;
 }
 
 public String mergePicAndExcel(){
 String xlsFileName=createExcel();
 if(imgUrls!=null){
 List<String>fileNames = Base64ToImage.base64ToPicture(this.imgUrls, this.filePath, PictureType.TYPE_PNG);
 for(int x = 0;x < fileNames.size();x++){
 drawPiceToExcel(xlsFileName, this.filePath+fileNames.get(x),x);
 }
 }
 return xlsFileName;
 }
 
 private void drawPiceToExcel(String xlsFileName,String picFileName,int position){
 FileOutputStream fileOut = null;
 BufferedImage bufferImg = null;
 FileInputStream in = null;
 Workbook wb = null;
 try {

 // 先把读进来的图片放到一个ByteArrayOutputStream中,以便产生ByteArray
 ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
 bufferImg = ImageIO.read(new File(picFileName));
 ImageIO.write(bufferImg, "png", byteArrayOut);

 // 打开一个工作薄
 in = new FileInputStream(xlsFileName);
 POIFSFileSystem fs = new POIFSFileSystem(in);
 wb = new HSSFWorkbook(fs);
 HSSFSheet sheet = (HSSFSheet) wb.getSheetAt(0);
 HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
 HSSFClientAnchor anchor = new HSSFClientAnchor(0, 0, 1023, 100, (short) 0, sheet.getLastRowNum()+5*position+27*position,
 (short) (sheet.getRow(0).getPhysicalNumberOfCells()+8), sheet.getLastRowNum()+5*position+27*(position+1));
 // 插入图片
patriarch.createPicture(anchor,wb.addPicture(byteArrayOut.toByteArray(),HSSFWorkbook.PICTURE_TYPE_JPEG));

 fileOut = new FileOutputStream(xlsFileName);
 // 写入excel文件
 wb.write(fileOut);
 fileOut.close();

 } catch (IOException io) {
 throw new RuntimeException(io.getMessage()+"读取文件出问题");
 } finally {
 if (fileOut != null) {
 try {
 fileOut.close();
 } catch (IOException e) {
 e.printStackTrace();
 }
 }
 }
 }
}


转载于:https://my.oschina.net/u/1391605/blog/631752

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值