找回密码
 立即注册

QQ登录

只需一步,快速开始

dexteryao 讲师达人认证 悬赏达人认证 SpreadJS 开发认证

超级版主

123

主题

8927

帖子

1万

积分

超级版主

Rank: 8Rank: 8

积分
13536

讲师达人悬赏达人元老葡萄SpreadJS 认证SpreadJS 高级认证微信认证勋章

dexteryao 讲师达人认证 悬赏达人认证 SpreadJS 开发认证
超级版主   /  发表于:2020-8-31 14:52  /   查看:2824  /  回复:0
本帖最后由 dexteryao 于 2020-8-31 14:52 编辑

上一期SpreadJS 全家桶实践 - 在线Excel报表系统(一),已经搭建好了整个项目框架并集成了SpreadJS、新编辑器和GCExcel。
本期将实现模板上传加载功能,并通过GCExcel的模板功能实现数据绑定。

1. 自定义Ribbon(工具栏),添加上传、加载、绑定和模板按钮
  1. <blockquote><script src="lib/pako.min.js" type="text/javascript"></script>
复制代码
将编辑器默认配置default_config.json修改为designerConfig.js 并引入

  1. let designerConfig = {
  2.     "ribbon":[ ... ]
复制代码
添加designer.js和ribbon.file.js分离功能,方便维护
designer.js中添加自定义config,在初始化编辑器时使用自定义config
  1. var customerRibbon = {
  2.     "id": "operate",
  3.     "text": "操作",
  4.     "buttonGroups": [
  5.     ]
  6. }

  7. function initStates(designer) {
  8.     spreadTemplateJSON = undefined;
  9.     designer.setData(AllowBindingData, true)
  10.     designer.setData(AllowBackTemplate, false)
  11. }

  12. function initDesigner() {

  13.     customerRibbon.buttonGroups.push(ribbonFileConfig) //将ribbon.file config注入
  14.     designerConfig.ribbon.push(customerRibbon) //添加自定义ribbon tab

  15.     var designer = new GC.Spread.Sheets.Designer.Designer(
  16.         document.getElementById('ssDesigner'), /**designer host */
  17.         designerConfig, // designerConfigJson /**If you want to change Designer's layout or rewrite it, you can pass in your own Config JSON */ ,
  18.         undefined /**If you want to use the spread you already created instead of generating a new spread, pass in */
  19.     );
  20.     initStates(designer);
  21.     return designer
  22. }
复制代码
修改index.js,初始化调用initDesigner 方法,并引入pako,添加前端压缩解压方法
  1. var designer
  2. window.onload = function () {
  3.     GC.Spread.Common.CultureManager.culture("zh-cn");
  4.     designer = initDesigner();
  5. };
复制代码


在ribbon.file.js添加 ribbonFileConfig ,设置上传、加载、绑定和模板按钮,并指定icon和命令
  1. var ribbonFileConfig =
  2. {
  3.     "label": "文件操作",
  4.     "thumbnailClass": "ribbon-thumbnail-spreadsettings",
  5.     "commandGroup": {
  6.         "children": [
  7.             {
  8.                 "direction": "vertical",
  9.                 "commands": [
  10.                     {
  11.                         iconClass: "ribbon-button-download",
  12.                         text: "加载",
  13.                         commandName: "getTemplates",
  14.                         execute: getTemplates,
  15.                     },
  16.                     {
  17.                         iconClass: "ribbon-button-upload",
  18.                         text: "上传",
  19.                         commandName: "uploadFile",
  20.                         execute: uploadFile,
  21.                     }
  22.                 ]
  23.             },

  24.             {
  25.                 "type": "separator"
  26.             },
  27.             {
  28.                 "direction": "vertical",
  29.                 "commands": [
  30.                     {
  31.                         iconClass: "ribbon-button-namemanager",
  32.                         text: "绑定",
  33.                         commandName: "bindingData",
  34.                         execute: bindingData,
  35.                         enableContext: AllowBindingData
  36.                     },
  37.                     {
  38.                         iconClass: "ribbon-button-namemanager",
  39.                         text: "模板",
  40.                         commandName: "backTemplate",
  41.                         execute: backTemplate,
  42.                         enableContext: "AllowBackTemplate"
  43.                     }
  44.                 ]
  45.             }
  46.         ]
  47.     }
  48. };
复制代码
添加命令对应方法
getTemplates 通过接口获取服务器上模板文件,并在表单中通过超链接形式展示
点击超链接后调用loadTemplate,通过模板名称加载模板json,导入工作簿
uploadFile 方法触发文件选择器,选择文件通过接口上传,服务端GCExcel 处理后返回json,并加载。可上传.xlsx Excel文件和SpreadJS ssjson
bindingData 将模板提交GCExcel与模拟数据绑定并返回结果json
backTemplate 通过缓存的json,还原回模板状态



  1. async function getTemplates(designer) {
  2.     var spread = designer.getWorkbook();

  3.     $.post("spread/getTemplates", {}, function (data) {
  4.         if (data != "0") {
  5.             data = ungzipString(data);
  6.             console.log(data)
  7.             var files = data.split(";")
  8.             var sheet = spread.getActiveSheet();
  9.             sheet.reset();
  10.             sheet.defaults.colWidth = 180
  11.             sheet.setArray(0, 0, [files])
  12.             // var HyperLinkCellType = GC.Spread.Sheets      
  13.             var h = new GC.Spread.Sheets.CellTypes.HyperLink();
  14.             h.onClickAction(function (e) {
  15.                 var sheet = e.sheet, row = e.row, col = e.col;
  16.                 var value = sheet.getValue(row, col);
  17.                 loadTemplate(value)
  18.             })
  19.             sheet.getRange(0, 0, 1, files.length).cellType(h)
  20.         }
  21.     })
  22. }
  23. async function loadTemplate(fileName) {
  24.     var spread = designer.getWorkbook();

  25.     let formData = new FormData();
  26.     formData.append("fileName", fileName);

  27.     $.ajax({
  28.         url: "spread/loadTemplate",
  29.         type: "POST",
  30.         contentType: false,
  31.         processData: false,
  32.         data: formData,
  33.         success: function (data) {
  34.             if (data != "0") {
  35.                 data = ungzipString(data);
  36.                 var json = JSON.parse(data);
  37.                 json.calcOnDemand = true;
  38.                 spread.fromJSON(json, { doNotRecalculateAfterLoad: true });
  39.                 initStates(designer)
  40.             }
  41.         }
  42.     })
  43. }
  44. async function uploadFile(designer) {
  45.     var spread = designer.getWorkbook();
  46.     var ribbon_file_selector = document.getElementById("ribbon_file_selector");
  47.     ribbon_file_selector.onchange = function (event) {
  48.         console.log(event)
  49.         var file = event.target.files[0];
  50.         let formData = new FormData();
  51.         formData.append("file", file);
  52.         formData.append("fileName", file.name);

  53.         $.ajax({
  54.             url: "spread/uploadFile",
  55.             type: "POST",
  56.             contentType: false,
  57.             processData: false,
  58.             data: formData,
  59.             success: function (data) {
  60.                 if (data != "上传失败!") {
  61.                     data = ungzipString(data);
  62.                     var json = JSON.parse(data);
  63.                     json.calcOnDemand = true;
  64.                     spread.fromJSON(json, { doNotRecalculateAfterLoad: true });

  65.                     initStates(designer)

  66.                 }
  67.                 else {
  68.                     alert("上传失败")
  69.                 }
  70.             }
  71.         })
  72.     }
  73.     ribbon_file_selector.value = "";
  74.     ribbon_file_selector.click();

  75. }


  76. var spreadTemplateJSON;
  77. var AllowBindingData = "AllowBindingData", AllowBackTemplate = "AllowBackTemplate";
  78. async function bindingData(designer) {
  79.     var spread = designer.getWorkbook();
  80.     if (!spreadTemplateJSON) {
  81.         spreadTemplateJSON = JSON.stringify(spread.toJSON())
  82.     }
  83.     var uploadData = gzipString(spreadTemplateJSON);
  84.     $.post("spread/bindingData", { data: uploadData }, function (data) {
  85.         if (data != "0") {
  86.             data = ungzipString(data);
  87.             var json = JSON.parse(data);
  88.             json.calcOnDemand = true;
  89.             spread.fromJSON(json, { doNotRecalculateAfterLoad: true });
  90.         }
  91.     })
  92.     designer.setData(AllowBackTemplate, true)
  93. }
  94. async function backTemplate(designer) {
  95.     if (spreadTemplateJSON) {
  96.         var spread = designer.getWorkbook();
  97.         spread.fromJSON(JSON.parse(spreadTemplateJSON))
  98.         spreadTemplateJSON = undefined;
  99.     }
  100.     designer.setData(AllowBindingData, true)
  101.     designer.setData(AllowBackTemplate, false)
  102. }
复制代码

2. 添加服务支持
引入GCExcel ,pom.xml加入
  1. <!-- https://mvnrepository.com/artifact/com.grapecity.documents/gcexcel -->
  2.                 <dependency>
  3.                         <groupId>com.grapecity.documents</groupId>
  4.                         <artifactId>gcexcel</artifactId>
  5.                         <version>3.2.2</version>
  6.                 </dependency>
复制代码
新建SpreadController,提供api接口
  1. @RestController
  2. @RequestMapping({"Spread","spread"})
  3. public class SpreadController {

  4.     public SpreadController() {
  5. //        指定字体文件路径
  6. //        Workbook.FontsFolderPath = "/Users/dexteryao/Documents/Projects/IdeaProjects/common/pdfFont";
  7.     }
复制代码

getTemplates获取resources/reports中模板文件
  1. /*获取reports路径下模板文件列表,返回分号分割文件名string*/
  2.     @RequestMapping(value="/getTemplates",method= RequestMethod.POST)
  3.     public String getTemplates(){
  4.         try {
  5.             var path = "src/main/resources/reports";
  6.             File reportDir = ResourceUtils.getFile(path);
  7.             File[] files = reportDir.listFiles();
  8.             String result = "";
  9.             for(int i=0;i<files.length;i++){
  10.                 File file = files[i];
  11.                 if(file.isFile() && !file.isHidden()) {
  12.                     result += (file.getName() + ";");
  13.                     System.out.println("^^^^^" + file.getName());
  14.                 }
  15.             }
  16.              result = compress(result);
  17.             return result;
  18.         } catch (Exception e) {
  19.             e.printStackTrace();
  20.         }
  21.         return "0";
  22.     }
复制代码
loadTemplate加载模板文件,Excel文件通过GCExcel转JSON
  1.     /*通过文件名,返回压缩后json,如果是Excel文件,使用GCExcel toJSON*/
  2.     @RequestMapping(value="/loadTemplate",method= RequestMethod.POST)
  3.     public String loadTemplate(@RequestParam("fileName") String fileName){
  4.         try {
  5.             var filePath = "src/main/resources/reports/" + fileName;
  6.             String workbookJSON;
  7.             Workbook workbook = new Workbook();

  8.             System.out.println("开始获取数据:" + new Date());
  9.             if(fileName.endsWith("xlsx")) {
  10.                 URL url = ResourceUtils.getURL(filePath);
  11.                 workbook.open(url.getFile());
  12.                 workbookJSON = workbook.toJson();
  13.             }
  14.             else{
  15.                 workbookJSON = getTextFileContent(filePath);
  16.             }

  17.             System.out.println("开始压缩:" + new Date());
  18.             String result = compress(workbookJSON);

  19.             System.out.println("压缩结束:" + new Date());
  20.             return result;
  21.         } catch (Exception e) {
  22.             e.printStackTrace();
  23.         }
  24.         return "0";
  25.     }
复制代码


uploadFile上传模板,Excel通过GCExcel 预处理后返回json。此处可直接保持JSON
  1. /*上传文件,报错到reports文件夹,excel和ssjson都通过GCExcel 处理一遍后再返回压缩后ssjson,用于测试GCExcel */
  2.     @RequestMapping(value="/uploadFile", headers = ("content-type=multipart/form-data"), method=RequestMethod.POST)
  3.     public String uploadFile(@RequestParam("file") MultipartFile file,
  4.                             @RequestParam("fileName") String fileName) throws FileNotFoundException {
  5.         if (file.isEmpty()) {
  6.             System.out.println("文件空");
  7.             return "上传失败!";
  8.         }

  9.         String filePath = "src/main/resources/reports/" + fileName;
  10.         URL url = ResourceUtils.getURL(filePath);
  11.         System.out.println(filePath);
  12.         File dest = new File(url.getFile());
  13.         try {
  14.             file.transferTo(dest);

  15.             Workbook workbook = new Workbook();

  16.             if(fileName.endsWith("xlsx")) {
  17.                 workbook.open(url.getFile());
  18.             }
  19.             else{
  20.                 String workbookJSON = getTextFileContent(url.getFile());
  21.                 workbook.fromJson(workbookJSON);
  22.             }
  23.             String workbookJSON = workbook.toJson();
  24.             String result = compress(workbookJSON);

  25.             return result;
  26.         } catch (IOException e) {
  27.             e.printStackTrace();
  28.         }
  29.         return "上传失败!";
  30.     }
复制代码
bindingData绑定数据,数据为模拟数据,设计模板时候需按照数据模型设计器
  1.     /*绑定模拟数据*/
  2.     @RequestMapping(value="/bindingData",method= RequestMethod.POST)
  3.     public String BindingData(@RequestParam(value = "data", required = true) String data){
  4.         try {
  5.             String json = uncompress(data);
  6.             if(json != null && !json.equals("")) {

  7.                 Workbook workbook = new Workbook();
  8.                 workbook.setEnableCalculation(false);
  9.                 workbook.fromJson(json);

  10.                 bindingDataToWrokbook(workbook);

  11.                 System.out.println("开始toJSON:" + new Date());
  12.                 String workbookJSON = workbook.toJson();
  13.                 System.out.println("开始压缩:" + new Date());
  14.                 String result = compress(workbookJSON);
  15.                 System.out.println("结束:" + new Date());
  16.                 return result;
  17.             }
  18.             return "0";
  19.         } catch (Exception e) {
  20.             // TODO Auto-generated catch block
  21.             e.printStackTrace();
  22.         }
  23.         return "0";
  24.     }
复制代码
数据模型
  1. public class DataSourceModel {
  2.     public String SecondaryInstitution;
  3.     public String EndDate;
  4.     public String EndMonth;
  5.     public int InsuranceYear;
  6.     public String Area;
  7.     public int InsuranceCount;
  8.     public int BaseAmount;
  9. }
复制代码
模拟数据并绑定到workbook
  1. public void  bindingDataToWrokbook(Workbook workbook){

  2.         System.out.println("开始创建模拟数据:" + new Date());
  3.         List<DataSourceModel> ds1 = new ArrayList<>() ;
  4.         for(int i = 0; i< 30; i++){
  5.             for(int j = 0; j < 77; j++) {
  6.                 for(int k = 0; k < 2; k++) {
  7.                     DataSourceModel dsm = new DataSourceModel();
  8.                     dsm.Area = "地区" + j;
  9.                     dsm.BaseAmount = i * j * 6 + k;
  10.                     dsm.InsuranceYear = 2020;
  11.                     dsm.SecondaryInstitution = "机构" + j + k;
  12.                     dsm.InsuranceCount = (j % 5) * i + k;
  13.                     dsm.EndMonth = "2020-" + (k % 2 + 8);
  14.                     dsm.EndDate = dsm.EndMonth + "-" + (i + 1);
  15.                     ds1.add(dsm);
  16.                 }
  17.             }
  18.         }
  19.         System.out.println("模拟数据行数:" + ds1.size());
  20.         System.out.println("开始添加数据:" + new Date());
  21.         workbook.addDataSource("ds", ds1);
  22.         System.out.println("开始绑定数据:" + new Date());
  23.         workbook.processTemplate();
  24.         System.out.println("结束绑定数据:" + new Date());
  25.     }
复制代码


GZip压缩解压方法,获取文本文件内容
  1. public static String compress(String str) {
  2.         if (str.length() <= 0) {
  3.             return str;
  4.         }
  5.         try{
  6.             ByteArrayOutputStream bos = null;
  7.             GZIPOutputStream os=null; //使用默认缓冲区大小创建新的输出流
  8.             byte[] bs =null;
  9.             try{
  10.                 bos = new ByteArrayOutputStream();
  11.                 os = new GZIPOutputStream(bos);
  12.                 os.write(str.getBytes()); //写入输出流
  13.                 os.close();
  14.                 bos.close();
  15.                 bs = bos.toByteArray();
  16.                 return new String(bs, "ISO-8859-1");
  17.             }finally{
  18.                 bs = null;
  19.                 bos = null;
  20.                 os = null;
  21.             }
  22.         }catch(Exception ex){
  23.             return str;
  24.         }
  25.     }

  26.     public static String uncompress(String str) {
  27.         if (str.length() <= 0) {
  28.             return str;
  29.         }
  30.         try {
  31.             ByteArrayOutputStream out = new ByteArrayOutputStream();
  32.             ByteArrayInputStream in = new ByteArrayInputStream(str.getBytes("ISO-8859-1"));
  33.             GZIPInputStream ungzip = new GZIPInputStream(in);
  34.             byte[] buffer = new byte[256];
  35.             int n;
  36.             while ((n = ungzip.read(buffer)) >= 0) {
  37.                 out.write(buffer, 0, n);
  38.             }
  39.             return new String(out.toByteArray(), "UTF-8");
  40.         } catch (Exception e) {

  41.         }
  42.         return str;
  43.     }

  44.     private String getTextFileContent(String path){
  45.         try {
  46.             File file = ResourceUtils.getFile(path);
  47.             String encoding = "UTF-8";
  48.             Long fileLength = file.length();
  49.             byte[] fileContent = new byte[fileLength.intValue()];
  50.             FileInputStream in = new FileInputStream(file);
  51.             in.read(fileContent);
  52.             in.close();
  53.             String content = new String(fileContent, encoding);
  54.             return content;
  55.         }
  56.         catch (Exception e){

  57.         }
  58.         return "";
  59.     }
复制代码


至此,上传加载,数据绑定功能也已实现 image.png116287230.png





0 个回复

您需要登录后才可以回帖 登录 | 立即注册
返回顶部