数据导入导出

数据的导入只要是以excel 或者 word文件方式导入;
模板制作是数据导入/导出的核心步骤.剩下的就是使用导入导出组件关联设计的导入/导出模板实现数据的导入/导出功能

模板管理

数据导出

table的导出

DataExport组件的应用

自定义导出的原理其实是与报表模板的原理是一致的.

  • 编写导出脚本样例:
function Button1367_onClickScript(cxt: ScriptContext, btn: Button) {
    btn.getPage().components.DataExport1.export(
    {param1:'paramvalue1',param2:'paramvalue2'},
    '导出的文件名')
    //复杂参数可使用JSON字符串传递, 模板内接收并解析JSON
     btn.getPage().components.DataExport1.export(
        { json: JSON.stringify({ aa: 'aa', bb: { cc: 'cc', dd: ['a', 'b'] } }) },
        '你好中国');
}

数据导入

DataImport 导入组件的使用

  • 后台处理地址
    • word: core/word/wordin (word纯脚本方式导入)
    • excel: core/excel/excelin (excel模板导入)
    • excel: core/excel/scriptin (excel纯脚本方式处理导入)
  • 组件的属性说明

json方式excel导入

注意事项:

导入的表必须在快搭表模型内

  • 模板的设计说明
  1. 新建一个后缀名为.xls(兼容老版本excel 2003以前的版本)/.xlsx (兼容excel2003以后的版本)文件.Excel里面的列和样式按照需求添加

  2. 在首行上点击第一个单元格,右键,点击编辑批注,填写相应的批注, 批注格式为json,第一个单元格需要设置导入表的相关信息,导入表信息相关设置, 表信息设置的字段,分别为:

    • TABLESTYPE:导入表类型
    • TABLENAMEMAP:导入表名
    • TABLEDEFAULTMAP:导入表的列
    • TREERULES:导入规则
    • MAPCOLUMN:导入表的数据列
    • CHECKLIST:数据校验
    • MULTCHECK:去重校验
    • TOTALCHECKRULE:总的校验规则
    • EXCELMULTCHECK:excel去重校验
    • FILENAME:文件名,不需要带后缀
    • 注意事项
      • TABLESTYPE:导入表类型,现只支持两种,一个是单表,一个是树形表,默认导入单表,如需导入树形表则这样设置:”TABLESTYPE”:”F.TREETABLE”; 多个逗号隔开
      • TABLENAMEMAP:导入表,设置格式为:”TABLENAMEMAP”:{“F”:”BD_ORG”,”A”:”BD_DEPT”};其中F代表表别名;BD_ORG代表表真正的名字;
      • TABLEDEFAULTMAP:导入表的默认列,设置格式为:”TABLEDEFAULTMAP”:{“F.SYS_CREATOR”:”getCuruserid”};其中F代表导入表的别名, 与上述设置一致,SYS_CREATOR代表插入默认字段,getCuruserid,获取值 的方 法,不需要括号,在DataSource.groovy上编写;
      • TREERULES:导入规则,针对树形,有两种格式,一种是SYS_LEV,一种是SYS_PARENTID,设置格式为:”TREERULES”:”F.SYS_LEV”, 导入树形表且规则是SYS_LEV时excel表格数据必须是按照树形的结构排好;多个逗号 隔 开,如果TABLESTYPE的为树形表,那么TREERULES不可缺少
      • MAPCOLUMN:导入表的数据列设置格式为: “MAPCOLUMN”:{“机构代码”:{“FIELDNAME”:”F.OBJCODE”},”机构名称”:{“FIELDNAME”:”F.OBJNAME”}}, 其中:”机构代码”代表excel上显示的列名: {“FIELDNAME”:”F. OBJCODE”},指映射的数据库信息,可以设置的地段有3个:FIELDNAME,FIEDTYPE,FIEDSOURCE
        • FIELDNAME:导入表的字段,设置格式为:”FIELDNAME”:”F.OOBJAME”,其中F为表的别名, OBJNAME为导入数据表的字段名,与上述设置的TABLENAMEMAP需要一致;
        • FIEDTYPE:导入表列的类型,分为4种,为NORMAL,ID,TONUMBER,IDANDNORMAL,设置格式为:”FIEDTYPE”:”NORMAL”,NORMAL代表正常导入,即excel这列内容是什么就导入什么 ID代表这列导入的是根据内容去查 询 数 据库得出的ID,TONUMBER代表这列只有是否的选项,而数据存储则是0,1,其中0是否,1是是;IDANDNORMAL代表同时把这列的文字和ID插入, FIELDNAME需要设置为两列,且插入文字的那列必须要在第一位, 如: “FIELDNAME”:”F.OOBJAME,F.OOBJAMEID”,FIEDTYPE默认为NORMAL
        • FIEDSOURCE:数据来源,针对FIEDTYPE是ID的类型,设置格式如下:”FIEDSOURCE”:” select rwid from bd_org where objanme=” 内置4个参数:userid、roleid、deptid、orgid,分别代表当前登录用户 的 id, 角色id,部门id,机构id,使用方法 :select ** from xx where xx = :userid
        • SOURCEKEY:保存资源的key,避免相同值再去数据库查询,多个逗号隔开,如:”SOURCEKEY”:”F.ORGID”,默认值为当前列对应的数据库字段
      • CHECKLIST:数据校验规则,设置格式入下:”CHECKLIST”:[“if(cxt.isBank(row.get(‘F.OBJNAME’))){‘机构名称不能为空’}”,”if(cxt.isBank(row.get(‘F.OBJCODE’))){‘机构代码不能为空’}”,
        “checkDataIsEqual”]
        校验规则分为两部分,一部分内置函数,一部分自己在DataCheck.groovy脚本上编写的函数,内置函数后续有说明
        校验规则在DataCheck.groovy脚本上编写,checkDataIsEqual是函数名,至于函数参数有三个,第一个是当前行数据,类型为Map<String,Object> 第二个参数为错误信息,类型为List,第三个参数为excel 行 数,类型为int,在DataCheck上写的方法需要有这三个参数
        MULTCHECK:去重校验,当校验的字段组合一致时不再进行插入,如:{“F”:”F.OBJCODE,F.OBJNAME”}
        TOTALCHECKRULE:全部数据校验,后端会把所有的数据以及错误信息对象传到方法里面,如:[“checkdata”,”checksum”] 注意这些校验方法写在DataCheck.groovy脚本里面,定义的方法的应类似这样: checkdata (List<Map<String, Object>> map,List list),校验出错的信息就加入到list里面
        EXCELMULTCHECK:excel去重校验,即excel同一列不允许出现相同的值,字符串类型,多个逗号隔开,如:”F.ORGID,F.SHOUJH”
        FILENAME:文件名,不需要带上文件后缀,如:”FILENAME”:”xx”,自定义校验和获取数据源的groovy文件,存放在dataimport目录下面
  3. 编写完批注后保存文件 上传到[平台管理/模板管理]

    *注意:文件保存时需要确定批注是否全部隐藏,如发现批注未隐藏需设置隐藏;

  1. 在数据校验中,如果有新增数据校验规则,需要在DataCheck.groovy中编写数据校验脚本,编码格式遵循java代码语法,可以引入各种包和文件,编写的校验规则需返回true,false 现有的数据校验规则有checkDataIsEqual(),注意编写校验规则参数设置需为Object数组对象,需要返回RetVo对象

  2. 在新增默认列,如果有新增的数据源,需要在DataSource.groovy中编写新增的默认的列的值,编码格式遵循java代码语法,可以引入各种包和文件,方法名必须以get开头 现有的默认列的值函数有:

    • getOrgid():获取当前登录机构的id
    • getCurOrgName():获取当前登录机构的名字
    • getCurUserid():获取当前登录用户的id
    • getCurUserName():获取当前登录用户的姓名
    • getCurDeptid():获取当前登录用户部门的id
    • getCurDeptName():获取当前登录用户部门的名字
    • getCurDate():获取当前时间
  3. 内置函数说明,内置函数有两个对象,一个cxt,一个row,其中row.get()函数可以获取行的对象的值,比如row.get(‘F.OBJCODE’),就是获取F.OBJCODE这列的值其中cxt是一个类,可以通过类的方法来得到一些对字符串函数 的判断.现有的cxt部分内置函数有:

    • isBank(String value):是否为空
    • isNumber(String value):是否数字
    • toNumber(String value):转为数字
    • startWith(String source, String prefix):字符串source以prefix为开头
    • endWith(String source, String suffix):字符串source以suffix结尾
    • indexOf(String source, String str):字符串source包涵str的位置
    • contains(String source, String str):字符串source是否包涵str字符
    • toUpper(String source):字符串转大写
    • toLow(String source):字符串转小写
    • equals(String source, String tagSource):字符串source是否等于tagSource字符串
    • equalsIgnoreCase(String source, String tagSource):字符串source是否等于tagSource字符串,忽略大小写
  • 执行导入Excel

function Button1_onClickScript(cxt:ScriptContext,btn:Button){
btn.getPage().components.DataImport1.importData();
}
  • 下载导入的模板文件
function Button1_onClickScript(cxt:ScriptContext,btn:Button){
btn.getPage().components.DataImport1.downloadTemplte();

脚本方式excel导入

function btnImport_onClickScript(cxt:ScriptContext,btn:Button){
    btn.getPage().components.DataImport1.importData((err,res)=>{
        if(Common.isNotEmpty(err)){
            Common.errorMsg(err)
        }else{
            Common.successMsg(err);
        }
    },{hello:'123'})
}

  • 纯excel脚本的导入
    一般是客户提供的导入文件格式不是很有规范时候.系统需要使用自定义导入的Groovy脚本
  • 通过传递参数到模板内
    function btnImport_onClickScript(cxt:ScriptContext,btn:Button){
      btn.getPage().components.DataImport1.importData((err,res)=>{
          if(Common.isNotEmpty(err)){
              Common.errorMsg(err)
          }else{
              Common.successMsg('导入完成');
          }
      },{hello:'123'})
    }
  • word的导入
    一般是客户提供的导入文件格式不是很有规范时候.比如客户提供了word 文件的数据文件导入系统需要使用自定义导入的脚本. 下面是一个word的导入Groovy脚本的例子:

    
    /**
     * office数据文件导入脚本
     * 
     * file MultipartFile 外部传进来的参数
     */
    import groovy.ui.SystemOutputInterceptor;
    import com.kdayun.z1.core.context.Context;
    import com.kdayun.z1.core.message.MessageUtil;
    
    import java.util.UUID;
    import org.apache.poi.hssf.usermodel.HSSFCell;
    import org.apache.poi.hssf.usermodel.HSSFDateUtil;
    import org.apache.poi.hssf.usermodel.HSSFWorkbook;
    import org.apache.poi.ss.usermodel.Cell;
    import org.apache.poi.ss.usermodel.CellType;
    import org.apache.poi.ss.usermodel.Row;
    import org.apache.poi.ss.usermodel.Workbook;
    import org.apache.poi.xssf.usermodel.XSSFWorkbook;
    import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
    import org.apache.poi.xwpf.usermodel.XWPFDocument;
    import org.apache.poi.xwpf.usermodel.XWPFTable;
    import org.apache.poi.xwpf.usermodel.XWPFTableCell;
    import org.apache.poi.xwpf.usermodel.XWPFTableRow;
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.JSONArray;
    import com.alibaba.fastjson.JSONObject;
    import org.apache.commons.lang3.StringUtils;
    
    /**
     * 表头的索引
     * 注意:从零开始
     */
    headerIndex=1
    
    /**
     * 模板的列
     * 注意:这个客户提供的word模板的类字段 ,可修改模板这里必须修改,不然通不过校验
     * fields 列
     * rows 数据行
     * field 字段名(数据映射的字段名,无需更新设置成""或者null), regx:正则表达式校验合法 ,nullable: 允许为空  
     *             colIndex:列的位置(正常情况与cell[1]相等多表导致这个值与cell[1]不等)
     *             cell: 表头单元格的坐标 [row,col], data:文件内保存的字段名,用于校验表头是否与提供的一致
     */ 
    FIELDS_MAP= [
        "fields":[    
            "序号":            ["field":"" ,"regx":"" , "nullable":true,colIndex:0, cell:[0,0],data:null]
            ,"姓名":            ["field":"XINGM" ,"regx":"" , "nullable":false,colIndex:1, cell:[0,1],data:null]
            ,"现机构及职务":    ["field":"XIANDWJZW" ,"regx":"" , "nullable":false,colIndex:2, cell:[0,2],data:null]
            ,"性别":            ["field":"XINGB" ,"regx":"" , "nullable":false,colIndex:3, cell:[0,3],data:null]
            ,"出生年月":        ["field":"CHUSNY" ,"regx":"\\d{4}.\\d{1,2}" , "nullable":false,colIndex:4, cell:[0,4],data:null]
            ,"民族":            ["field":"MINZ" ,"regx":"" , "nullable":false,colIndex:5, cell:[0,5],data:null]
            ,"籍贯":            ["field":"JIG" ,"regx":"" , "nullable":false,colIndex:6, cell:[0,6],data:null]
            ,"参加工作时间":    ["field":"CANJGZSJ" ,"regx":"\\d{4}.\\d{1,2}" , "nullable":false,colIndex:7, cell:[0,7],data:null]
            ,"加入中共时间":    ["field":"JIARZGSJ" ,"regx":"\\d{4}.\\d{1,2}" , "nullable":false,colIndex:8, cell:[0,8],data:null]
            ,"全日学历":            ["field":"QUANRXL" ,"regx":"" , "nullable":false,colIndex:9, cell:[1,9],data:null]
            ,"全日学位":            ["field":"QUANRXW" ,"regx":"" , "nullable":false,colIndex:10, cell:[1,10],data:null]
            ,"全日毕业院校及专业":    ["field":"QUANRBYYXJZY" ,"regx":"" , "nullable":false,colIndex:11, cell:[1,11],data:null]
            ,"在职学历":            ["field":"ZAIZXL" ,"regx":"" , "nullable":true,colIndex:12, cell:[1,12],data:null]
            ,"在职学位":            ["field":"ZAIZXW" ,"regx":"" , "nullable":true,colIndex:13, cell:[1,13],data:null]
            ,"在职毕业院校及专业":    ["field":"ZAIZBYYXJZY" ,"regx":"" , "nullable":true,colIndex:14, cell:[1,14],data:null]
            ,"专业技术职务":    ["field":"ZHUANYJSZW" ,"regx":"" , "nullable":true,colIndex:15, cell:[0,11],data:null]
            ,"任现职时间":        ["field":"RENXZSJ" ,"regx":"" , "nullable":false,colIndex:16, cell:[0,12],data:null]
            ,"备注":            ["field":"BEIZ" ,"regx":"" , "nullable":true,colIndex:17, cell:[0,13],data:null]
        ]
        ,"rows":[]
    ]
    
    INSERST_SQL="INSERT INTO CESB_RENYDR(RWID,XINGM,XIANDWJZW,XINGB,CHUSNY,MINZ,JIG,CANJGZSJ,JIARZGSJ,QUANRXL,QUANRXW,QUANRBYYXJZY,ZAIZXL,ZAIZXW,ZAIZBYYXJZY,ZHUANYJSZW,RENXZSJ,BEIZ,  SYS_CREATOR,SYS_CREATETIME) VALUES (#{RWID},#{XINGM},#{XIANDWJZW},#{XINGB},#{CHUSNY},#{MINZ},#{JIG},#{CANJGZSJ},#{JIARZGSJ},#{QUANRXL},#{QUANRXW},#{QUANRBYYXJZY},#{ZAIZXL},#  {ZAIZXW},#{ZAIZBYYXJZY},#{ZHUANYJSZW},#{RENXZSJ},#{BEIZ},#{SYS_CREATOR},#{SYS_CREATETIME})"
    SELECT_SQL="SELECT 1 FROM CESB_RENYDR WHERE XINGM=#{XINGM}  AND CHUSNY=#{CHUSNY}"
    
    /**
     * 保存的原始数据
     */
    rawData=[]
    
    /**
     * 校验文件的格式合法性
     * 文件的格式 后缀
     * @return true 通过 则反之
     */
    def void checkImportFile() throws Exception {
        System.out.println("校验文件合法性...");
        if(null==file) {
            throw new Exception("输入文件不允许为空")
        }
    
    }
    
    /**
     * 校验文件的文数据合法
     * @return
     */
    def void checkImportData() throws Exception {
        System.out.println("校验数据合法性...");
        if(FIELDS_MAP.rows.size()==0) {
            throw new Exception("无数据可以导入")
        }
        checkFields();
        checkRows();
    
    }
    /**
     * 校验列
     */
    def checkFields() {
        for ( e in FIELDS_MAP.fields ) {
            if(StringUtils.isBlank(e.value.data)) {
                throw new Exception("导入的文件不存在数据列["+e.key+"]")
            }
        }
    }
    /**
     * 校验行
     */
    def checkRows() {
        for(int rowindex=0;rowindex<FIELDS_MAP.rows.size();rowindex++) {
            row=FIELDS_MAP.rows.get(rowindex);
            for ( e in FIELDS_MAP.fields ) {                    
                checkRowData(rowindex,row,e)
            }
        }
    }
    
    /**
     * 校验行的数据
     */
    def void checkRowData(Integer rowindex,ArrayList<String> row,def field) {
    
         value=row[field.value.colIndex];
         cellTitle="行["+rowindex+"] 列["+field.value.colIndex+"]"+field.key +" "; 
         regx=field.value.regx;
         nullable=field.value.nullable
    
         System.out.println("校验数据 "+cellTitle+" "+value);
         if(!nullable) {
             if(StringUtils.isBlank(value)) {
                 throw new Exception( cellTitle+"的数据不允许为空")
             }
             strValue= value.toString();
             if(StringUtils.isNotBlank(regx)) {
                 if(!strValue.matches(regx).find()) {
                     throw new Exception( cellTitle+"的数据格式不对")
                 }
             }         
         }else {
             if(StringUtils.isNotBlank(regx) && null!=value) {
                 strValue= value.toString();
                 if(!strValue.matches(regx).find()) {
                     throw new Exception( cellTitle+"的数据格式不对")
                 }
             }
    
         }
    }
    /**
     * 读取数据文件的数据
     * @return
     */
    def getData() {
        System.out.println("读取文件数据...");
        readWord7();        
        readFields();
        readRows();        
        System.out.println("读取文件数据结果 row:"+FIELDS_MAP.rows.size()+" field:"+FIELDS_MAP.fields.size());
    }
    /**
     * 检查是否存在行
     */
    def isExistsRow(variants) {
        List ret= cxt.exceSelectSql(SELECT_SQL,variants);
        return ret.size()>0;
    }
    def insertData(){
        System.out.println("写入数据到数据库...");
        variants=[]
        def user=Context.getInstance().securityService.getCurrentUser();
        if(null==user) {
            throw new Exception("必须选登录才能导入数据")
        }
        for(int j;j<FIELDS_MAP.rows.size();j++) {
            def row=FIELDS_MAP.rows[j];
            def vrow=[:];
            variants.add(vrow);
            //给一个组件guid
            vrow.put("RWID",UUID.randomUUID().toString().replaceAll("-", "").toUpperCase());
            vrow.put("SYS_CREATOR",user.getId());
            vrow.put("SYS_CREATETIME",new Date())
            for ( e in FIELDS_MAP.fields ) {
                if(StringUtils.isNotBlank(e.value.field)) {
                  vrow.put(e.value.field,row[e.value.colIndex]);
                }
            }
        }
        System.out.println("写入数据到数据库:"+JSON.toJSONString(variants));
        for(int j;j<FIELDS_MAP.rows.size();j++) {
            def row=FIELDS_MAP.rows[j];
            try {
                if(isExistsRow(variants[j])) {
                    throw new Exception("第"+j+"行数据已经存在,检查是否重复导入数据")
                }else {
                    cxt.exceSelectSql(INSERST_SQL,variants[j]);
                }
            }
            catch(e) {
                throw new Exception("第["+j+"行]数据写入问题:"+e.toString());
            }
        }
    
    }
    
    /**
     * 得到table单元格的值
     */
    def getCellValue(Integer rowIndex,Integer colIndex){
        return rawData.get(rowIndex).get(colIndex);
    }
    
    /**
     * 读取数据列
     */
    def readFields() {
        if(rawData.size()==0) {
            throw new Exception( "无数据可以导入")
        }
        System.out.println("读取数据列...");
        for ( e in FIELDS_MAP.fields ) {
            System.out.println("读取数据列"+JSON.toJSONString(e));
            if(e.value.cell!=null) {
                rowIndex= e.value.cell[0]
                colIndex= e.value.cell[1]
                e.value.data=getCellValue(rowIndex,colIndex).replaceAll("\\s*", "");
            }
        }
    
    }
    
    /**
     * 读取数据行
     */
    def readRows() {
        if(rawData.size()==0) {
            throw new Exception( "无数据可以导入")
        }
        System.out.println("读取数据行...");
        for(int i;i<rawData.size();i++) {
            if(i>headerIndex) {
                def row=[];
                FIELDS_MAP.rows.add(row);        
                for ( e in FIELDS_MAP.fields ) {
                    def rowIndex= i
                    def colIndex= e.value.colIndex
                    if(colIndex!=null) {
                        row.add(getCellValue(rowIndex,colIndex))
                    }
                }
            }        
        }
        System.out.println("读取数据列"+JSON.toJSONString(FIELDS_MAP));
    }
    
    def readWord7(){
        String text = null;
        InputStream inputStream =null;
        XWPFDocument doc =null;
        try {
            inputStream = file.getInputStream();
            doc = new XWPFDocument(inputStream);
            List<XWPFTable> tables = doc.getTables();
            for(int i=0;i<tables.size();i++) {
                List<XWPFTableRow> wordRows = tables.get(i).getRows();
                for(int j=0;j<wordRows.size();j++) {
                    XWPFTableRow wrodRow=wordRows.get(j);
                    List<XWPFTableCell> tableCells = wrodRow.getTableCells();
                    List<String> r=new ArrayList<String>();
                    rawData.add(r)
                    for(int n=0;n<tableCells.size();n++) {
                        XWPFTableCell cell=tableCells.get(n);
                        r.add(cell.getText())
                    }
                }
            }
            System.out.println("数据:"+JSON.toJSONString(rawData));
        }finally {
            if (doc!=null) {
                try {
                    doc.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    /**
     * 开始导入
     */
    def void start() {
        System.out.println("开始导入...");
        checkImportFile()
        getData();
        checkImportData();
        insertData();
    }
    
    start();
    
  • 执行导入Word

function Button1365_onClickScript(cxt:ScriptContext,btn:Button){
    btn.getPage().components.DataImport1.importData();
}
  • 下载导入的word模板文件
function Button1365_onClickScript(cxt:ScriptContext,btn:Button){
    btn.getPage().components.DataImport1.downloadTemplte();
}
作者:admin  创建时间:2022-12-05 16:39
最后编辑:admin  更新时间:2024-10-17 08:28