如何调用移动端拍照,上传到单据图片字段原创
金蝶云社区-吴锐雄
吴锐雄
1人赞赏了该文章 778次浏览 未经作者许可,禁止转载编辑于2023年07月27日 11:20:01

关键词:移动端,拍照,文件服务,图片字段


一、需求

在某些业务场景下,需要通过拍照功能,给其他单据页面上的图片字段赋值。

本篇文章,以云之家app为案例,在云之家中访问苍穹页面,调起拍照功能,并给其他。


二、思路与方案

  • 移动端拍照,可以通过executeClientCommand执行指令的方式,调起拍照功能。

  • 拍照之后,在customEvent事件中,返回拍照结果,拍照结果是一个字符串,是经过Base64编码的图片资源。

  • 图片资源解码,然后转成byte数组,调用文件服务进行上传。

  • 查询某个带有图片字段的单据,将上传路径与文件名拼接之后,赋值给图片字段,并且保存。


在idea的断点中,可以看到拍照之后,获取的图片资源是一个  "/9j"  为开头的字符串,这是一个经过base64编码之后的jpg图片,关于"/9j",感兴趣的开发者,可以在必应、百度搜一下相关文档。

image.png



三、实现过程

1.开发移动端页面

简单设计一个移动端页面,拖入一个按钮用来触发点击即可。

image.png


2.开发插件代码

触发按钮点击时,调用executeClientCommand,调起摄像头

@Override
public void click(EventObject evt) {
    super.click(evt);
    if (evt.getSource() instanceof Control) {
        switch (((Control) evt.getSource()).getKey()) {
            case "kdec_camera": {
                System.out.println();
                HashMap map = new HashMap();
                map.put("method", "selectPic"); //selectPic 为云之家方法名
                HashMap args = new HashMap();
                args.put("type", "camera"); //类型,“camera”代表“相机”,“photo”代表“相册”,不传表示从相机、相册中选择
                map.put("args", args);  //args 调用该云之家方法需要传递的参数
                this.getView().executeClientCommand("callAPPApi", map);
            }
            break;
        }
    }
}


在customEvent事件中,接收拍照结果,转为inputStream,使用FileService进行上传,最后将文件路径保存到图片字段上。

@Override
public void customEvent(CustomEventArgs e) {
    super.customEvent(e);
        switch (e.getEventName()) {
            case "selectPic":
                JSONObject jsonObject = JSONObject.parseObject(e.getEventArgs());
                String fileExt = jsonObject.get("fileExt").toString();
                String fileData = jsonObject.get("fileData").toString();

                FileService fileService = FileServiceFactory.getAttachmentFileService();

                // 构建文件名和文件上传路径
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
                String fileName = sdf.format(new Date()) + "." + fileExt;
                String uploadPath = "/image/test/" + fileName;

                OutputStream outputStream = new ByteArrayOutputStream();
                InputStream inputStream = null;
                try {
                    // 字符串解码为byte数组
                    byte[] bytes = decode(fileData);
                    outputStream.write(bytes);
                    inputStream = parse(outputStream);

                    // 文件服务上传
                    fileService.upload(new FileItem(fileName, uploadPath, inputStream));
                    // 打印日志
                    log.info("文件路径为:"+uploadPath);
                    //System.out.println("文件路径为:"+uploadPath);
                } catch (Exception ex) {
                    // 如果抛异常,将文件路径置空
                    uploadPath = null;
                    throw new RuntimeException(ex);
                } finally {
                    try {
                        outputStream.close();
                        if (inputStream != null) {
                            inputStream.close();
                        }
                    } catch (IOException ex) {
                        throw new RuntimeException(ex);
                    }
                }

                // 保存,判断文件路径为空(在处理Stream的时候、上传的时候抛异常),则不保存
                if (uploadPath != null) {
                    saveObject(uploadPath);
                }
                break;
        }
}


拍照的结果是一个字符串,是经过Base64编码的图片资源,以下方法可以将图片的字符串转为byte数组

public byte[] decode (String fileData) {
    // 解密
    Base64.Decoder decoder = Base64.getMimeDecoder();
    // 去掉base64前缀 data:image/jpeg;base64,
    fileData = fileData.substring(fileData.indexOf(",", 1) + 1, fileData.length());
    byte[] bytes = decoder.decode(fileData);
    // 处理数据
    for (int i = 0; i < bytes.length; ++i) {
        if (bytes[i] < 0) {
            bytes[i] += 256;
        }
    }
    return bytes;
}


stream(输出流转输入流)转换方法

public ByteArrayInputStream parse(final OutputStream out) throws Exception {
    ByteArrayOutputStream baos = (ByteArrayOutputStream) out;
    final ByteArrayInputStream swapStream = new ByteArrayInputStream(baos.toByteArray());
    return swapStream;
}


保存方法,

注意,这里保存的是我的苍穹环境上的“纺织物”单据上的图片字段,这里仅作为参考,请各位开发者根据自己的业务需求修改代码。

public OperationResult saveObject (String uploadPath) {
    DynamicObject[] dynamicObjects = BusinessDataServiceHelper.load("kdec_textline_bill", "id,billno,kdec_textline_name,kdec_picturefield", new QFilter("billno", QCP.like, "CSDES-2022-10-14-601").toArray());
    if (dynamicObjects.length > 0) {
        dynamicObjects[0].set("kdec_picturefield", uploadPath);
    }
    // 保存到纺织物单据上
    OperationResult result = SaveServiceHelper.saveOperate("kdec_textline_bill", dynamicObjects);
    return result;
}


四,效果图

点击按钮

image.png

拍照


image.png


在日志中找到文件路径

image.png


拼接url,http://ip地址:端口号/ierp/attachment/preview.do?path=文件路径。

预览发现,文件已上传成功。

image.png


进入“纺织物”单据中,发现该图片已经展示在页面上的图片字段中:

image.png


五、开发环境版本

苍穹5.0


六、注意事项

有些开发者,想要在企业微信上使用该功能,企业微信也可以支持拍照,调用之前需要在企业微信的应用管理平台,配置鉴权。

参考文档:https://vip.kingdee.com/link/s/lxhQ6

image.png


七、参考资料

设置企业微信网页授权及JS-SDK、设置企业可信IP

如何调用扫码、拍照等移动客户端的API

文件服务


赞 1