金山办公在线编辑Java后端对接

对接前提条件:拥有 accessKey、secretKey

步骤一:application.yml配置公私钥、并设置host,也就是访问金山的ip

 

 步骤二:自定义接口,生成在线编辑访问链接,供给前端访问调用

Controller:只需要传文件Id

/**
  * 方法描述:【在线编辑 】
  *
  * @author hdj
  * @date 2023-06-28 13:43
  */
@RequestMapping(value = "/onlineEditing", method = RequestMethod.GET)
@ResponseBody
public Object onlineEditing(@RequestParam("fileId") String fileId) throws UnsupportedEncodingException {
    return service.onlineEditing(fileId);
}

ServiceImpl

@Autowired
private Environment env;

/**
 * 方法描述:【在线编辑 】
 *
 * @author hdj
 * @date 2023年06月14日 14点42分46秒
 */
public Object onlineEditing(String fileId) throws UnsupportedEncodingException {
    String host = env.getProperty("wps.office.host");
    String accessKey = env.getProperty("wps.office.accessKey");
    String secretKey = env.getProperty("wps.office.secretKey");
    if (!StringUtils.hasLength(host) || !StringUtils.hasLength(accessKey) || !StringUtils.hasLength(secretKey)) {
        throw new LocalException("缺失环境配置");
    }

    String userId = UserUtils.getLoginUserId();
    String userName = NameCache.getUserName(userId);

    StringBuilder builder = new StringBuilder();
    String url = builder.append("/api/edit/v1/files/")
            .append(fileId).append("/link")
            .append("?")
            .append("type=w&_w_third_type=write")
            .append("&_w_third_user_id=").append(userId)
            .append("&_w_third_user_name=").append(URLEncoder.encode(userName, "UTF-8"))
            .toString();

    DateFormat dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.US);
    dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
    String date = dateFormat.format(new Date());

    String contentType = "application/json";
    String body = "";
    WPS4Signature signature = new WPS4Signature(accessKey, secretKey);
    Map<String, String> headers = signature.getSignatureHeaders2("GET", url, body, date, contentType);

    String result = HttpUtil.createGet(host.concat("/open").concat(url)).addHeaders(headers).execute().body();

    JSONObject resultObj = JSONObject.parseObject(result);
    return resultObj;
}

HMacUtils

/**
 * @date 2022/5/20$ 18:20$
 */
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class HMacUtils {

    public static String HMACSHA256(String data, String key) throws Exception {
        Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
        SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");
        sha256_HMAC.init(secret_key);
        byte[] array = sha256_HMAC.doFinal(data.getBytes("UTF-8"));
        StringBuilder sb = new StringBuilder();
        for (byte item : array) {
            sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
        }
        return sb.toString();
    }


    /**
     * 利用java原生的摘要实现SHA256加密
     * @param str 加密后的报文
     * @return
     */
    public static String getSHA256StrJava(byte[] str){
        MessageDigest messageDigest;
        String encodeStr = "";
        try {
            messageDigest = MessageDigest.getInstance("SHA-256");
            messageDigest.update(str);
            encodeStr = byte2Hex(messageDigest.digest());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return encodeStr;
    }
    /**
     * 将byte转为16进制
     * @param bytes
     * @return
     */
    private static String byte2Hex(byte[] bytes){
        StringBuffer stringBuffer = new StringBuffer();
        String temp = null;
        for (int i=0;i<bytes.length;i++){
            temp = Integer.toHexString(bytes[i] & 0xFF);
            if (temp.length()==1){
                //1得到一位的进行补0操作
                stringBuffer.append("0");
            }
            stringBuffer.append(temp);
        }
        return stringBuffer.toString();
    }
}

 WPS4Signature


import org.apache.commons.lang3.StringUtils;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * WPS-3签名,需要引入依赖包
 * <pre>
 * org.apache.commons.commons-lang3
 * commons-codec.commons-codec
 * </pre>
 */
public class WPS4Signature {

    public final static String HTTP_HEADER_AUTHORIZATION = "Wps-Docs-Authorization";
    public final static String HTTP_HEADER_DATE = "Wps-Docs-Date";
    public final static String HTTP_HEADER_CONTENT_TYPE = "Content-Type";

    private String appId; // 应用id
    private String secretKey; // 应用秘钥

    public WPS4Signature(String appId, String secretKey) {
        this.appId = appId;
        this.secretKey = secretKey;
    }

    /**
     * 获取请求body MD5
     *
     * @param content 请求body
     * @return
     */
    public String getSHA256(String content) {
        if (StringUtils.isBlank(content)) {
            return HMacUtils.getSHA256StrJava("".getBytes());
        } else {
            return HMacUtils.getSHA256StrJava(content.getBytes());
        }
    }

    /**
     * 获取日期字符串
     *
     * @param date
     * @return
     */
    public static String getGMTDateString(Date date) {
        SimpleDateFormat format = new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss", Locale.US);
        format.setTimeZone(TimeZone.getTimeZone("GMT"));
        return format.format(date) + " GMT";
    }

    /**
     * 签名
     *
     * @param uriWithQuerystring
     * @param contentMD5         签名参数MD5
     * @param dateString
     * @return
     */
    public String getSignature(String method, String uriWithQuerystring, String contentMD5, String dateString, String contentType) throws Exception {
        return HMacUtils.HMACSHA256("WPS-4" + method + uriWithQuerystring + contentType + dateString + contentMD5, this.secretKey);
    }

    /**
     * 获取X-Auth
     *
     * @param uriWithQuerystring 请求url,带querystring
     * @param contentMD5         请求body MD5
     * @param dateString         日期字符串,例如:Mon, 15 Nov 2021 02:34:04 GMT
     * @param contentType        application/json
     * @return
     */
    public String getAuthorization(String method, String uriWithQuerystring, String contentMD5, String dateString, String contentType) throws Exception {
        String authorization = String.format(Locale.US, "WPS-4 %s:%s",
                this.appId,
                getSignature(method, uriWithQuerystring, contentMD5, dateString, contentType));
        return authorization;
    }

    /**
     * 获取签名请求头
     *
     * @param uriWithQuerystring 请求url,带querystring
     * @param content            请求body
     * @param date               日期,默认为 new Date()
     * @param contentType        默认为 application/json
     * @return
     */
    public Map<String, String> getSignatureHeaders(String method, String uriWithQuerystring, String content, Date date, String contentType) {
        if (uriWithQuerystring == null) {
            uriWithQuerystring = "";
        }
        if (content == null || StringUtils.isBlank(content)) {
            content = "";
        } else {
            content = getSHA256(content);
        }
        if (date == null) {
            date = new Date();
        }
        if (contentType == null) {
            contentType = "application/json";
        }

        String dateString = getGMTDateString(date);
        String authorization = "";
        try {
            authorization = getAuthorization(method, uriWithQuerystring, content, dateString, contentType);
        } catch (Exception e) {

        }

        Map<String, String> headers = new HashMap<>();
        headers.put(WPS4Signature.HTTP_HEADER_AUTHORIZATION, authorization);
        headers.put(WPS4Signature.HTTP_HEADER_CONTENT_TYPE, contentType);
        headers.put(WPS4Signature.HTTP_HEADER_DATE, dateString);
        return headers;
    }


    /**
     * 获取签名请求头
     *
     * @param uriWithQuerystring 请求url,带querystring
     * @param content            请求body
     * @param date               日期,默认为 new Date()
     * @param contentType        默认为 application/json
     * @return
     */
    public Map<String, String> getSignatureHeaders2(String method, String uriWithQuerystring, String content, String date, String contentType) {
        if (uriWithQuerystring == null) {
            uriWithQuerystring = "";
        }
        if (content == null || StringUtils.isBlank(content)) {
            content = "";
        } else {
            content = getSHA256(content);
        }
        if (contentType == null) {
            contentType = "application/json";
        }

        String dateString = date;
        String authorization = "";
        try {
            authorization = getAuthorization(method, uriWithQuerystring, content, dateString, contentType);
        } catch (Exception e) {

        }

        Map<String, String> headers = new HashMap<>();
        headers.put(WPS4Signature.HTTP_HEADER_AUTHORIZATION, authorization);
        headers.put(WPS4Signature.HTTP_HEADER_CONTENT_TYPE, contentType);
        headers.put(WPS4Signature.HTTP_HEADER_DATE, dateString);
        return headers;
    }
}

步骤三:实现两个回调接口,分别是“文件信息获取接口”、“文件保存接口”

所需对象

FileModel :

@Data
public class FileModel implements Serializable {

    private static final long serialVersionUID = 1L;

    /** 文件id 不超过64位**/
    public String id;
    /** 文件名称,带后缀 **/
    public String name;
    /** 版本号,位数小于11位 **/
    public Integer version;
    /** 文件大小,字节,文件太大会出异常 **/
    public Integer size;
    /** 创建者id 不超过32位 **/
    public String creator;
    /** 创建时间,时间戳,单位:秒 **/
    public Integer create_time;
    /** 修改者id **/
    public String modifier;
    /** 修改时间,时间戳,单位:秒 **/
    public Integer modify_time;
    /** 文档下载地址 **/
    public String download_url;
    /** 限制预览页数,具体参考金山文档 **/
    public Integer preview_pages;
    /** 用户权限模块 **/
    public UserAclModel user_acl;
    /** 水印模块 **/
    public WaterMarkModel watermark;

}

 UserAclModel:

@Data
public class UserAclModel implements Serializable {

    private static final long serialVersionUID = 1L;

    /** 重命名权限,1 打开,0 关闭,默认 0 **/
    public Integer rename;
    /** 历史文件打开权限,1 打开,0 关闭,默认 1 **/
    public Integer history;
    /** 复制权限,1 打开,0 关闭,默认 1 **/
    public Integer copy;
    /** 导出权限,1 打开,0 关闭,默认 1 **/
    public Integer export;
    /** 打印权限,1 打开,0 关闭,默认 1 **/
    public Integer print;
    /** 只读情况下可评论权限,1 打开,0 关闭,默认 0 **/
    public Integer comment;
    /** 限制在当前系统内复制粘贴,1 打开,0 关闭,默认 0 **/
    public Integer copy_control;

}

WaterMarkModel: 

@Data
public class WaterMarkModel implements Serializable {

    private static final long serialVersionUID = 1L;

    /** 水印类型: 0 无水印,1 文字水印 **/
    public Integer type;
    /** 水印的文字 **/
    public String value;
    /** 水印颜色 **/
    public String filestyle;
    /** 字体 **/
    public String font;
    /** 水印旋转度 **/
    public Float rotate;
    /** 水印水平间距 默认 50 **/
    public Integer horizontal;
    /** 水印垂直间距 默认 100 **/
    public Integer vertical;
}

UserModel: 

@Data
public class UserModel implements Serializable {

    private static final long serialVersionUID = 1L;

    /** 用户id 不超过64位**/
    public String id;
    /** 用户名称 **/
    public String name;
    /** 用户操作权限: write 编辑, read 只读 **/
    public String permission;
    /** 用户头像地址, 支持url和base64 **/
    public String avatar_url;

}
文件信息获取接口:

 Controller:_w_third前缀为自定义参数

    /**
     * 方法描述:【附件信息获取 】
     *
     * @author hdj
     * @date 2023-06-28 13:43
     */
    @RequestMapping(value = "/v1/3rd/file/info", method = RequestMethod.GET)
    @ResponseBody
    public Object getFileInfo(@RequestParam("_w_third_type") String type, @RequestParam("_w_third_user_id") String userId, @RequestParam("_w_third_user_name") String userName, HttpServletRequest request) {
        return service.getFileInfo(type, userId, userName, request);
    }

ServiceImpl:获取数据库的dao对象自己修改成所需要的。其次需要提供一个自定义在线下载文件链接。

/**
     * 方法描述:【附件信息获取 】
     *
     * @author hdj
     * @date 2023年06月14日 14点42分46秒
     */
    public Object getFileInfo(String type, String userId, String userName, HttpServletRequest request) {
        String host = env.getProperty("wps.office.host");

        JSONObject resultObject = new JSONObject();

        FileModel fileModel = new FileModel();
        UserModel userModel = new UserModel();
        resultObject.put("file", fileModel);
        resultObject.put("user", userModel);

        String fileId = request.getHeader("x-weboffice-file-id");
        FlowAttachment attachment = fileInfoDao.get(fileId);
        if (Objects.isNull(attachment)) {
            throw new ParamException("文件不存在");
        }

        try {
            //设置文件信息
            fileModel.setId(attachment.getId());
            fileModel.setName(attachment.getFileName());
            fileModel.setVersion(Objects.isNull(attachment.getVersion()) ? 1 : attachment.getVersion());
            fileModel.setSize(Integer.valueOf(attachment.getFileSize()));
            fileModel.setCreator(attachment.getCreateBy());
            fileModel.setCreate_time((int) (attachment.getCreateDate().getTime() / 1000));
            fileModel.setModifier(attachment.getUpdateBy());
            fileModel.setModify_time((int) (attachment.getUpdateDate().getTime() / 1000));
            fileModel.setDownload_url(host + attachment.getFilePath());
            fileModel.setPreview_pages(StaticValue.STATIC_ZERO_INT);

            //设置用户信息
            userModel.setId(userId);
            userModel.setName(userName);
            userModel.setPermission(type);
        } catch (Exception e) {
            e.printStackTrace();
        }
        log.info("在线编辑文件信息: {}", resultObject);

        return resultObject;
    }
文件保存接口:

Controller:

    /**
     * 方法描述:【附件信息存储 】
     *
     * @author hdj
     * @date 2023-06-28 13:43
     */
    @RequestMapping(value = "/v1/3rd/file/save", method = RequestMethod.POST)
    @ResponseBody
    public Object save(@RequestParam("file") MultipartFile file, HttpServletRequest request) {
        return service.save(file, request);
    }

ServiceImpl:获取数据库Dao逻辑需自己修改,数据库表需要有一个version版本号字段

    /**
     * 方法描述:【附件信息存储 】
     *
     * @author hdj
     * @date 2023年06月14日 14点42分46秒
     */
    public Object save(MultipartFile file, HttpServletRequest request) {
        String fileId = request.getHeader("x-weboffice-file-id");
        FlowAttachment attachment = fileInfoDao.get(fileId);
        if (Objects.isNull(attachment)) {
            throw new ParamException("文件不存在");
        }

        if (!file.isEmpty()) {
            String filePath = AttachmentConfig.fileUploadFolder + attachment.getFilePath();
            try {
                BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(new File(filePath)));
                out.write(file.getBytes());
                out.flush();
                out.close();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        //更新版本号
        Integer version = Objects.isNull(attachment.getVersion()) ? 2 : attachment.getVersion() + 1;
        attachment.setVersion(version);
        fileInfoDao.updateSelective(attachment);

        String host = env.getProperty("wps.office.host");

        JSONObject resultModel = new JSONObject();
        JSONObject fileModel = new JSONObject();
        fileModel.put("id", attachment.getId());
        fileModel.put("name", attachment.getFileName());
        fileModel.put("version", attachment.getVersion());
        fileModel.put("size", Integer.valueOf(attachment.getFileSize()));
        fileModel.put("download_url", host + attachment.getFilePath());

        resultModel.put("file", fileModel);
        log.info("在线保存文件信息: {}", resultModel);

        return resultModel;
    }

步骤四:编写好回调接口后,设置回调地址

在哪里设置?我这个是金山给的应用管理平台上进行设置的

 步骤五:设置好回调地址后,就可访问测试

Java 对接金山文档在线可以通过调用金山文档的 RESTful API 来实现。以下是一个基本的对接示例: 首先,需要通过 Java 的 HTTP 客户端库发送 HTTP 请求来访问金山文档的 API。可以使用例如 Apache HttpClient 或 OkHttp 这样的库来发送 HTTP 请求。 在发送 HTTP 请求时,需要使用金山文档提供的 API 地址和相关的授权信息,包括 API key 和 secret key。这些授权信息可以在金山文档的开发者中心中获取。 请求的内容要根据金山文档的 API 文档来构建。例如,可以通过发送 POST 请求来上传文档,发送 GET 请求获取文档信息等。 对于上传文档,需要将文档的二进制数据以及相关的参数(如文档类型、文件名等)作为请求体发送给金山文档的上传 API。在发送请求后,可以通过解析 API 的响应来获取上传后的文档的 ID 或其他相关信息。 对于获取文档信息,可以通过发送 GET 请求,将文档的 ID 作为请求参数,然后解析 API 的响应来获取文档的元数据,如文件名、大小、创建时间等。 可以根据需要使用相应的 HTTP 方法和 API 接口来实现其他功能,如更新文档、删除文档等。 以上是一个简单的对接金山文档在线Java 示例。实际应用中,还需考虑异常处理、请求的验证与加密等方面的功能。具体实现时可以参考金山文档提供的 API 文档和 Java 客户端库的使用指南。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值