美文网首页js css html
自身项目导入luckysheet server

自身项目导入luckysheet server

作者: 微笑碧落 | 来源:发表于2022-05-09 20:42 被阅读0次

    自身项目导入luckysheet server

    前言

    • luckysheet serverluckysheet官方的一个后台。用来和luckysheet建立ws连接、保存文档至数据库。
    • 目前最麻烦的是不好导入本身的spring boot项目。直接下载官方代码,也很难直接运行。
    • 如下是我琢磨出来的比较简单的在自身spring boot项目导入luckysheet server的办法。如果有更好的办法,请告知我。。
    • 各位可以试试模块导入方法。。。可能会更加简单。。我原本没想到luckysheet server的文件那么多那么复杂。

    1.外部环境配置

    • mysql安装

    • redis安装

    • idea安装以及新建一个spring boot web项目。(如果已经有项目就打开原来的项目)

    • 数据库初始化。注意schema名称要和配置文件的一致。

    • CREATE SCHEMA `collsheet` ;
        
        CREATE TABLE `luckysheet` (
        `id` bigint(30) NOT NULL,
        `block_id` varchar(200) NOT NULL,
        `row_col` varchar(50) DEFAULT NULL,
        `index` varchar(200) NOT NULL,
        `list_id` varchar(200) NOT NULL,
        `status` int(1) DEFAULT NULL,
        `json_data` json DEFAULT NULL,
        `order` int(3) DEFAULT NULL,
        `is_delete` int(1) DEFAULT NULL,
        PRIMARY KEY (`id`),
        KEY `lib` (`list_id`,`index`,`block_id`),
        KEY `order` (`order`),
        KEY `status` (`status`),
        KEY `is_delete` (`is_delete`)
      ) ENGINE=InnoDB DEFAULT CHARSET=armscii8;
      
      INSERT INTO luckysheet VALUES (139400313311449087, 'fblock', '', '1', '1079500#-8803#7c45f52b7d01486d88bc53cb17dcd2c3', 1, '{"row":84,"name":"Sheet1","chart":[],"color":"","index":"1","order":0,"column":60,"config":{},"status":0,"celldata":[],"ch_width":4748,"rowsplit":[],"rh_height":1790,"scrollTop":0,"scrollLeft":0,"visibledatarow":[],"visibledatacolumn":[],"jfgird_select_save":[],"jfgrid_selection_range":{}}', 0, 0);
      INSERT INTO luckysheet VALUES (139400313311449088, 'fblock', '', '2', '1079500#-8803#7c45f52b7d01486d88bc53cb17dcd2c3', 0, '{"row":84,"name":"Sheet2","chart":[],"color":"","index":"2","order":1,"column":60,"config":{},"status":0,"celldata":[],"ch_width":4748,"rowsplit":[],"rh_height":1790,"scrollTop":0,"scrollLeft":0,"visibledatarow":[],"visibledatacolumn":[],"jfgird_select_save":[],"jfgrid_selection_range":{}}', 1, 0);
      INSERT INTO luckysheet VALUES (139400313311449089, 'fblock', '', '3', '1079500#-8803#7c45f52b7d01486d88bc53cb17dcd2c3', 0, '{"row":84,"name":"Sheet3","chart":[],"color":"","index":"3","order":2,"column":60,"config":{},"status":0,"celldata":[],"ch_width":4748,"rowsplit":[],"rh_height":1790,"scrollTop":0,"scrollLeft":0,"visibledatarow":[],"visibledatacolumn":[],"jfgird_select_save":[],"jfgrid_selection_range":{}}', 2, 0);
      
      

    2.pom.xml文件修改

    • 目的是引入luckysheet server需要的依赖。

    • 注意版本号。。个别依赖版本不一致会报错。

    • 文件修改号后,需要等待idea下载好所有依赖。

    • <!--导入数据库驱动,不同数据库,驱动器不一样-->
      <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <scope>runtime</scope>
      </dependency>
      
      <!--引入 mybatis-spring-boot-starter 的依赖-->
      <dependency>
          <groupId>org.mybatis.spring.boot</groupId>
          <artifactId>mybatis-spring-boot-starter</artifactId>
          <version>2.2.0</version>
      </dependency>
      
      <!--引入 hutool-all-->
      <dependency>
          <groupId>cn.hutool</groupId>
          <artifactId>hutool-all</artifactId>
          <version>5.7.22</version>
      </dependency>
      
      <!--websokcet的starter-->
          <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-websocket</artifactId>
      </dependency>
      
      <!--JSON解析-->
      <dependency>
          <groupId>com.alibaba</groupId>
          <artifactId>fastjson</artifactId>
          <version>1.2.70</version>
      </dependency>
      
      <!--为类添加getter和setter和构造函数等-->
      <dependency>
          <groupId>org.projectlombok</groupId>
          <artifactId>lombok</artifactId>
          </dependency>
      <dependency>
      
      <!--google的gson工具-->
      <groupId>com.google.code.gson</groupId>
          <artifactId>gson</artifactId>
          <version>2.9.0</version>
          <scope>compile</scope>
      </dependency>
      
      <!--阿里的druid数据源-->
      <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.20</version>
      </dependency>
      
      <!-- redis -->
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-data-redis</artifactId>
      </dependency>
      <!-- 给redis集群用的Lettuce的连接池 -->
      <dependency>
          <groupId>org.apache.commons</groupId>
          <artifactId>commons-pool2</artifactId>
      </dependency>
      
      <dependency>
          <groupId>org.apache.commons</groupId>
          <artifactId>commons-collections4</artifactId>
          <version>4.3</version>
      </dependency>
      

      3.application.yml文件修改

      • 主要是mysql数据库配置、redis配置、日志配置等

      • 注意数据库配置有重复。。因为官方就是有重复的。。暂时还没有对重复进行去掉。

      • #服务器配置
        server:
          port: 8080
        
        #数据库配置
        spring:
          application:
            name: web
          jackson:
            time-zone: GMT+8
            date-format: yyyy-MM-dd HH:mm:ss
          http:
            encoding:
              charset: UTF-8
              enabled: true
          datasource:
            druid:
              url: jdbc:mysql://127.0.0.1:3306/collsheet
              username: root
              password: 5587699$lgg
              driver-class-name: com.mysql.cj.jdbc.Driver
          redis:
            host: 127.0.0.1
            port: 6379
            password:
            timeout: 10000ms
            lettuce:
              pool:
                max-active: 8
                max-wait: -1ms
                max-idle: 8
                min-idle: 0
            database: 0
        
        
        db:
          mysql:
            druid:
              url: jdbc:mysql://127.0.0.1:3306/collsheet
              username: root
              password: 5587699$lgg
              driver-class-name: com.mysql.cj.jdbc.Driver
          postgre:
            druid:
              url: jdbc:mysql://127.0.0.1:3306/collsheet
              username: root
              password: 5587699$lgg
              driver-class-name: com.mysql.cj.jdbc.Driver
                  
        #日记配置
        logging:
          file:
            path: my-log
          pattern:
            console: "%clr(%d{yyyy-MM-dd HH:mm:ss}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(-){faint} %clr([%14.14t]){faint} %clr(%-40.40logger.%13.13M){cyan} %clr(%3.3L) %clr(:){faint} %msg%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"
        
        #redis通道名称
        redis.channel: luckysheet.channel
        #表格中块的大小,新增加时写入每一个sheet的第一个模块中
        row_size: 500
        col_size: 500
        #使用服务器类型
        servertype: tomcat
        
        

        4. 复制class文件

    • 复制如下一大丢文件至你的项目

    • 我全部丢到一个文件夹了。。不太合适。。最好分好类。

    • 复制过来后,idea会有报错。。都是import错误。。。删掉这些报错的import错误。。然后交给idea自动import即可。

    • BaseHandle.java
      BaseModel.java
      ConfigerService.java
      ConfigMergeModel.java
      DataSourceConfig.java
      DisabledTypeEnum.java
      GridFileRedisCacheService.java
      GridRecordDataModel.java
      GzipHandle.java
      IpAndPortUtil.java
      IRecordDataInsertHandle.java
      IRecordDataUpdataHandle.java
      IRecordDelHandle.java
      IRecordSelectHandle.java
      JdbcTempleConfig.java
      JfGridConfigModel.java
      JfGridFileController.java
      JfGridFileGetService.java
      JfGridFileUtil.java
      JfGridUpdateService.java
      JsonUtil.java
      LuckySheetGridModel.java
      MSExcelUtil.java
      MyStringUtil.java
      MyURLUtil.java
      MyWebSocketHandler.java
      MyWebSocketInterceptor.java
      OperationTypeEnum.java
      Pako_GzipUtils.java
      readme.txt
      RecordDataInsertHandle.java
      RecordDataUpdataHandle.java
      RecordDelHandle.java
      RecordSelectHandle.java
      RedisCacheService.java
      RedisConfig.java
      RedisLock.java
      RedisMessageListener.java
      RedisMessageModel.java
      RedisMessagePublish.java
      RedisQueueService.java
      ScheduleService.java
      SheetOperationEnum.java
      SnowFlake.java
      SysConstant.java
      TestUtil.java
      TimeUtil.java
      WebSocketConfig.java
      WSUserModel.java
      

      5.使用

      • 至此,如果原本的项目可以运行,我们导入的luckysheet server项目也可以运行了。什么都不需要做了。
      • spring boot会自动导入各种config类,自动启动ws服务等
      • 但是还需要如下配置才能实现前端数据保存至数据库。

      5.1 使用步骤

      • 后端用uuid工具生成一个uuid。

      • 用该uuid向luckysheet表插入一条空白记录。插入语句参考如下。这个是初始化语句。目的是为了新建一个空白表格。一条记录表示一个空白sheet页面。

      • luckysheet server用分块实现sheet的保存。第一个fblock表示配置块,里面没有数据的。只有颜色等配置。

      • INSERT INTO luckysheet VALUES (139400313311449087, 'fblock', '', '1', '1079500#-8803#7c45f52b7d01486d88bc53cb17dcd2c3', 1, '{"row":84,"name":"Sheet1","chart":[],"color":"","index":"1","order":0,"column":60,"config":{},"status":0,"celldata":[],"ch_width":4748,"rowsplit":[],"rh_height":1790,"scrollTop":0,"scrollLeft":0,"visibledatarow":[],"visibledatacolumn":[],"jfgird_select_save":[],"jfgrid_selection_range":{}}', 0, 0);
        
      • 传递该uuid到前端

      • 前端的luckysheet配置如下

      • socket_url = "ws://" + window.location.host + "/websocket/luckysheet?t=" + user.name;
        luckysheetOptions = {
            container: 'luckysheet', //luckysheet为容器id
            lang: 'zh', // 设定表格语言
            showinfobar: false,
            allowUpdate: true,
            updateUrl: socket_url,
            loadUrl: "/user/load",
            gridKey: uuid,
        }
        
      • 注意loadUrl地址的controller文件。。可以根据需要使用里面的方法。里面有导入全部数据、导入sheet等。我修改为如下:(最末尾那一行)

      •     @PostMapping("/load")
            public String load(HttpServletRequest request, HttpServletResponse response, @RequestParam(defaultValue = "") String gridKey) {
                //告诉浏览器,当前发送的是gzip格式的内容
                response.setHeader("Content-Encoding", "gzip");
                response.setContentType("text/html");
                String resultStr="";
                if(gridKey.trim().length()!=0){
                    try {
                        String _checkStr=check(request,gridKey.toString(),null,OperationTypeEnum.Read);
                        if(_checkStr.length()>0){
                            return null;
                        }
                        List<JSONObject> dbObject=null;
                        //dbObject=jfGridFileGetService.getDefaultByGridKey(gridKey);
                        dbObject=jfGridFileGetService.getAllSheetByGridKey(gridKey);
        
      • 至此一切都可以正常使用了。

      6 bug处理

      • 目前发现这个后台有3个bug。按道理来说不应该。。。也可能是我的导入办法不对。

      6.1 无法删除sheet页

      • 这个是sql语句有错误。定位到RecordDelHandle.java文件

      • 原来的写法

      • /**
            * 删除sheet(非物理删除)
            *
            * @param model
            * @return
        */
            @Override
            public boolean updateDataForReDel(GridRecordDataModel model) {
                try{
                    String sql1="update "+ JfGridConfigModel.TABLENAME+" set is_delete=?  where  list_id=? and index=? ";
                    log.info("updateSql1:"+sql1);
                    luckySheetJdbcTemplate.update(sql1,new Object[]{model.getIs_delete(),model.getList_id(),model.getIndex()});
                    return true;
                }catch (Exception e){
                    log.error(e.getMessage());
                    return false;
                }
            }
        
      • 主要原因是字段名称index在mysql是系统关键词。。直接如此引用必然报错。修改如下(增加表名用t.index代替)

      •     /**
             * 删除sheet(非物理删除)
             *
             * @param model
             * @return
             */
            @Override
            public boolean updateDataForReDel(GridRecordDataModel model) {
                try{
                    String sql1="update "+ JfGridConfigModel.TABLENAME+" t  set is_delete=?  where  list_id=? and t.index=? ";
                    log.info("updateSql1:"+sql1);
                    luckySheetJdbcTemplate.update(sql1,new Object[]{model.getIs_delete(),model.getList_id(),model.getIndex()});
                    return true;
                }catch (Exception e){
                    log.error(e.getMessage());
                    return false;
                }
            }
        

        6.2 无法修改sheet名称

        • 定位RecordDataUpdataHandle.java文件137行

        • if(v instanceof JSON){
          updateSql.append("CAST('"+((JSON) v).toJSONString()+"' as JSON)");
          }else{
              //updateSql.append("\""+v+"\"");
              updateSql.append(v);
          }
          
        • 其中v是前端传递过来的sheet名称。按道理官方这么写没错。。但是不懂为什么v自身带有两个双引号。导致该sql语句是 ""v""。多了2个双引号。。所以数据库提示字符错误。

        6.3无法修改sheet的行或列的宽度和高度。

        • 这个bug事实上有很大的影响。。不仅仅是无法修改行或列。。

        • 这个bug没解决6.4的bug也没办法解决。。事实上影响到了所有表格cg( Operation_cg)操作(操作config)。

        • bug没解决前,提示sql语句存在sync错误。

        • 定位到RecordDataUpdataHandle.java449行。

        • 注释掉的是原本的报错的写法。。更换成如下写法即可。。主要是JSON_CONTAINS_PATH(t.json_data,'one',\"$."+key+"\")=0"和`"update "+JfGridConfigModel.TABLENAME+" t 需要指定一个表的别名以及告诉JSON_CONTAINS_PATH函数一个正确的列。

        • 同理还有这个类的497行。。一样的错误。。

        •             //String createSql="update "+JfGridConfigModel.TABLENAME+" t set t.json_data=json_set(json_data,\"$."+key+"\",CAST('"+newObj.getString(key)+"' AS JSON)) where 1=1 " +condition+
                      //        " and JSON_CONTAINS_PATH(jsontest,'one',\"$."+key+"\")=0";
                        
                      String createSql="update "+JfGridConfigModel.TABLENAME+" t set t.json_data=json_set(json_data,\"$."+key+"\",CAST('"+newObj.getString(key)+"' AS JSON)) where 1=1 " +condition+
                              " and JSON_CONTAINS_PATH(t.json_data,'one',\"$."+key+"\")=0";
          

        6.4 无法添加边框

        • 这个bug事实上影响也很大。。不仅仅是无法修改边框。甚至其他涉及config的都无法保存成功。

        • 解决及发现这个bug花了数天时间。最终才定位问题所在。我感觉好像是我错了。。。但是按照我这个办法修改后,可以添加边框了。

        • 根本原因是因为luckysheet的config类,比如边框、单元格大小等在后台都是用前端发过来的进行替换原本的。比如如下一个正确的config。后面那个json是前端进行更改发送给后端的。

        • 注意看如下的config的属性。有的是对象,有的是数组。。后台用fastJson框架进行处理,需要转换为JSONObject或JSONArray对象。。

        • 但是涉及到config类的保存方法中,把config的属性的类型定死为JSONObject了。。所以就会提示JSONArray无法转换为JSONObject。。。需要进行相应的判断。。

        • 解决办法更加复杂了。。因为涉及到多个方法。。这些方法的参数类型都定死了为JSONObject了。。。。。

        • 所以。。最最根本的原因是前端更改接口了!!!!后端没料到会传入JSONArray。

          "config": {
              "columnlen": {
                "2": 260,
                "3": 260
              },
              "borderInfo": [
                {
                  "color": "#000",
                  "range": [
                    {
                      "row": [
                        0,
                        9
                      ],
                      "top": 0,
                      "left": 0,
                      "width": 73,
                      "column": [
                        0,
                        4
                      ],
                      "height": 19,
                      "top_move": 0,
                      "left_move": 0,
                      "row_focus": 0,
                      "width_move": 369,
                      "height_move": 199,
                      "column_focus": 0
                    }
                  ],
                  "style": "1",
                  "rangeType": "range",
                  "borderType": "border-all"
                }
              ]
            },
          
          
           {"t":"cg","v":{"2":251,"3":203},"i":"1","k":"columnlen"}
          
        • 解决步骤:

        • JfGridUpdateService.java文件中:1168行
          //JSONObject _v = null
          Object _v = null;//需要替换的值
          
        • JfGridUpdateService.java文件中:1220行
          //JSONObject _k = JfGridFileUtil.getObjectByObject(_config, k);
          Object _k = _config.get(k);
          
        • IRecordDataUpdataUhanle.java文件中利用多态增加如下一个接口:
          boolean updateJsonbForSetRootNull(JSONObject query, String word, JSONObject db, Integer position, String words);
          
          boolean updateJsonbForSetRootNull(JSONObject query, String word, Object db, Integer position, String words);
          
        • RecordDataUpdataUhanle.java文件中利用多态实现接口:
          public boolean updateJsonbForSetRootNull(JSONObject query, String word, Object db, Integer position, String words) {
                  return updateJsonbForInsertNull(query, word, db, position, words);
          }
          
        • RecordDataUpdataUhanle.java文件中利用多态增加如下方法:
          注意在515行处增加如下判断语句:
          public boolean updateJsonbForInsertNull(JSONObject query, String word, Object db, Integer position, String words) {
              if (db instanceof JSONObject){
                  updateSql.append("CAST('"+((JSONObject)db).toString(SerializerFeature.WriteMapNullValue)+"' as JSON)");
              }
          
              if (db instanceof JSONArray){
                  updateSql.append("CAST('"+((JSONArray)db).toString(SerializerFeature.WriteMapNullValue)+"' as JSON)");
              }
          
          
              updateSql.append(") where 1=1 "+condition);
          
              log.info("updateSql:{}",updateSql.toString());
              luckySheetJdbcTemplate.update(updateSql.toString(),arr.toArray());
          }
          
    ### 6.5前端手动输入单一的单元格数值。会出现某个单元格数值不见了。
    
    - 前端手动输入单一的单元格数值。会出现某个单元格数值不见了。这个单元格可能是之前手动输入的某个数值,也可能是之前用拖动生成的数值。
    
    - 解决方法如下:
    
    - ```java
      定位JfGridUpdateService.java 1554行
      //_result = recordDataUpdataHandle.updateJsonbForElementInsert(query, "celldata", _db, 0);
      _result = recordDataUpdataHandle.updateJsonbForElementInsert(query, "celldata", _db, 999999999);
      ```
    
    - 原因:这个方法访问如下方法:
    
    - ```java
      RecordDataUpdataHandle.updateJsonbForElementInsert(JSONObject query, String word, JSONObject db, Integer position)
      ```
    
    - 最终都会执行这个sql语句:
    
    - ```sql
      update luckysheet t set t.json_data=json_set(t.json_data,"$.celldata[position]",CAST('{"r":0,"c":0,"v":{"ct":{"t":"n","fa":"General"},"v":1346,"m":"1346"}}' as JSON)) where 1=1  and t.list_id="78290eb1-c879-4ae3-9eb3-e11dab05da93"  and t.index="1"  and t.block_id="0_0" 
      ```
    
    - 如果传入的position为0。就会把celldata[0]的json给替换掉。如果position为999999999。就会插入新数据。
    
    ### 6.6 重复登录bug
    
    - 这个不能说是bug。。只能说是考虑问题。。
    
    - 2022年5月23日。。测试的时候发现。。如果一个用户可以在多个网页打开同一个项目。。经常会把该项目搞崩溃。。导致该项目无法访问。所以目前暂时定死了。。一个用户同时只能登录一个luckysheet。。
    
    - ```java
      MyWebSocketHandler.java 第52行。
      修改该变量为public。
      //private static final Hashtable<String, Hashtable<String, WSUserModel>> USER_SOCKET_SESSION_MAP;
      public static final Hashtable<String, Hashtable<String, WSUserModel>> USER_SOCKET_SESSION_MAP;
      ```
    
    - ```java
      MyWebSocketInterceptor.java 第46行增加如下4行。只要该方法返回false,就不能连接ws。
      如下通过判断是否有token登录。如果有token登录就拒绝登录。
      String str = MyWebSocketHandler.USER_SOCKET_SESSION_MAP.toString();
      if (str.indexOf(token) > -1){
          return false;
      }
      ```
    
    
    ### 6.7 双击表格的某个单元格,进入单元格编辑界面,然后马上退出编辑网页。。然后就不能再次进入这个项目了
    
    - 原因:双击某个单元格的时候,前端向后端发送如下命令
    
    ```json
    {
      "t": "mv",
      "i": "1",
      "v": {
        "op": "enterEdit",
        "range": [
          {
            "left": 148,
            "width": 73,
            "top": 60,
            "height": 19,
            "left_move": 148,
            "width_move": 73,
            "top_move": 60,
            "height_move": 19,
            "row": [
              3,
              3
            ],
            "column": [
              2,
              2
            ],
            "row_focus": 3,
            "column_focus": 2
          }
        ]
      }
    }
    ```
    
    - 注意,前端发送过来的是一个JSONObject对象。后端接收到这个命令后,什么都不做直接写入数据库
    
    ```json
    updateSql:update luckysheet t set t.json_data=json_set(t.json_data,"$.jfgird_select_save",CAST('{"op":"enterEdit","range":[{"top_move":0,"top":0,"left":148,"column_focus":2,"width":73,"left_move":148,"column":[2,2],"width_move":73,"row":[0,0],"height_move":19,"row_focus":0,"height":19}]}' as JSON)) where 1=1  and t.list_id='e4777a8b-7d29-43d0-95d6-6b17863e3bdb' and t.index='1' and t.block_id='fblock'
    ```
    
    - 注意如上sql语句。。把jfgird_select_save这个key对应的值写成了一个对象。。但是前端要求这个是一个数组。。所以前端会报错,,然后就不能进入这个文档了。。
    
    - 简单来说就是某句代码向文档写入了脏数据。。导致前端无法识别这个文档。。然后就无法进入了。
    
    - 解决办法:解决办法就是不写入整个收到的命令。而是提取该命令中的所需要的数据写入数据库。。真正需要的是v.range这个数组。
    
      ```java
      定位JfGridUpdateService.java第1769行,更换为如下写法:
      //Object db = bson.get("v");
      Object db_wrap = bson.get("v");
      if (!(db_wrap instanceof JSONObject)){
        return;
      }
      
      Object db = ((JSONObject) db_wrap).get("range");
      if (db == null){
        return;
      }
      ```
    
    ### 6.8 无法保存单元格回车信息
    
    - 如果单元格的内容有回车(excel经常见)的情况下。会出现更新失败。
    - 主要原因还是sql语句的符号错误。
    - 错误提示如下:
    
    ```java
    RecordDataUpdataHandle.DataListValue 188 : StatementCallback; SQL [update luckysheet t set t.json_data=json_set(t.json_data,"$.celldata[0].v",CAST('{"ct":{"s":[{"v":"nihao\r\nnihao"}]
    MysqlDataTruncation: Data truncation: Invalid JSON text in argument 1 to function cast_as_json: "Invalid encoding in string." at position 23
    MyWebSocketHandler.handleMessage 138 : handleUpdate--error:更新失败
    ```
    
    - 把完整的sql语句复制到mysql中执行。。报的错误是一样的。由此可见,错误的原因是sql语句符号错误。
    - 因为仅仅是回车才出现的错误。所以推测是回车的转义问题。
    - 注意到`('{"ct":{"s":[{"v":"nihao\r\nnihao"}]`的`\r\n`仅有一个`\`。试着修改为`\\n\\r`。不在提示这个错误。
    - 解决办法如下。解决思路就是用字符串替换`\r\n`为`\\r\\n`。注意顺手把"''"也替换为""。否则当单元格有‘的时候一样会报错。
    
    ```java
    定位RecordDataUpdataHandle.java文件166行。
    增加如下几行
    //log.info("updateSql:"+updateSql.toString());
    //luckySheetJdbcTemplate.update(updateSql.toString());
    String v_str = v.toString()
        .replace("\\r","\\\\r")
        .replace("\\n","\\\\n")
        .replace("'","");
    v = JSON.parse(v_str);
    ```
    
    ### 6.9 合并单元格无法保存回车信息。
    
    - 这个bug很少出现。
    
    - 我在导入excel文件的时候才发现有这个bug。具体可以看导入excel文件篇。
    
    - 某个单元格无法写入数据,更新失败。原因如上所述。当这个合并单元格有换行的时候。就会出现这个bug。
    
    - 解决方法如下:注释为原本的写法。稍微改进了下。
    
      ```java
      定位RecordDataUpdataHandle.java文件224行。
                  //updateSql.append("CAST('"+db.toString(SerializerFeature.WriteMapNullValue)+"' as JSON)");
      
      String db_str = db.toString(SerializerFeature.WriteMapNullValue)
          .replace("\\r","\\\\r")
          .replace("\\n","\\\\n")
          .replace("'","");
      updateSql.append("CAST('"+db_str+"' as JSON)");
      ```
    

    相关文章

      网友评论

        本文标题:自身项目导入luckysheet server

        本文链接:https://www.haomeiwen.com/subject/fskrurtx.html