WPS网页游览(新)

355 阅读8分钟

WPS网页游览(新)

一、账号篇

1、 账号注册及应用注册

【地址】solution.wps.cn

步骤 1: 登录 WPS 账号

在使用 WebOffice 服务前,需要先登录您的 WPS 账号。(如果您已登录,请跳过该步骤)

步骤 2: 开发者认证

进入WebOffice 控制台,如果您之前没有认证过开发者,需要在这里进行开发者认证。

填写开发者信息,您需要根据字段提示如实填写您所在企业的信息,并上传一张符合要求的营业执照。

注册-01

提交审核

审核

步骤 3: 创建测试应用

在 WebOffice 控制台完成开发者认证后即可创建测试应用,测试应用可用于接入方体验 WebOffice、格式转换服务的功能。按照要求填写信息后,点击创建即可。创建完成后可在应用信息 tab 下查看应用的 AppID 和 AppSecret。

https://qn.cache.wpscdn.cn/wwo/doc/pro/assets/flow5.e587fb46.png

开放平台的 WebOffice、格式转换服务均提供两种应用类型,分别为测试应用和正式应用:

测试应用:面向研发和调试阶段,开发者可以在这里完成应用的整体功能研发、测试、联调以及产品验收,应用创建后即为测试阶段。

正式应用:面向正式上线阶段,方便开发者将测试应用验收通过的代码、服务、资源等部署到生产环境,应用上架需要提供应用的系统截图。

两者之间具体的异同点如下表所示:

服务类型应用类型文档并发数文件大小限制是否有水印应用数量
WebOffice测试应用≤5≤5MB2 个
正式应用默认1024,可配置为无限制默认100M,最大可配置为500M无限制
服务类型应用类型文档转换次数文件大小限制是否有水印应用数量
格式转换测试应用免费赠送500次≤5MB2 个
正式应用无限制500M(超过请 联系商务开通)无限制

【大概基础知识到这里就可以了。详情请查看WPS

二、配置篇

要实现WebOffice的在线预览功能需要前后端一同参与。其中涉及文件服务的回调配置部分。

1、回调网关 配置

回调网关目前支持 http 与 https 两种协议,支持以下两种范式:

范式一:scheme://host/path_prefix(/path_prefix 可以为空)

示例:

  • http://solution.wps.cn/dev/WebOffice
  • https://solution.wps.cn

范式二:scheme://ip:port/prefix (IP 必须为公网 IP 段)

示例:

  • http://117.78.0.2:8080/dev/WebOffice
  • http://117.78.0.2:8080

solution.wps.cn ip为我系统服务的地址。这个地址用于WPS访问我们所开发的接口进行数据校验。本质就是 前端 -> WPS -> 后端。此处就是我们后端服务的地址。

【调用格式】 WebOffice 将通过回调网关拼接上 API 接口地址,然后以回调的方式请求对接方的这些接口。最终 WebOffice 集群将会向 回调网关+回调接口 发起请求。

以下为例子:

回调网关:https://solution.wps.cn/dev/WebOffice

接口:GET /v3/3rd/files/:file_id

文件 ID:1234567

最终请求地址:https://solution.wps.cn/dev/WebOffice/v3/3rd/files/1234567

2、配置流程

第一步:进入回调配置 #

进入控制台后,点击【应用管理】-【应用名称】-【回调配置】选项卡

https://qn.cache.wpscdn.cn/wwo/doc/pro/assets/callback-config.e16662d8.png

第二步: 配置回调网关

假设网关地址为https://www.****.com:####,回调接口地址是 /v3/3rd/files/${file_id},则完整的回调接口地址就是 https://www.****.com:####/v3/3rd/files/${file_id}

第三步:接口调试

针对每一个回调接口,可通过点击【调试】按钮,测试此接口能否被 WebOffice 服务器正常访问,以及接口返回的数据是否符合要求,您可以根据接口的调试信息逐步完善接口的逻辑。 https://qn.cache.wpscdn.cn/wwo/doc/pro/assets/cb3.21b185f4.png

token、file_id 从哪获取?

token 由接入方自定义, WebOffice 将会在回调接口时通过 X-Weboffice-TokenHeader 字段回传,可用于检查鉴权。

file_id可由数字、字母和下划线组成,但不能以下划线开头,它是由对接企业自己生成并管理,需要保证一个 file_id 对应一个文件,也对应一个文件的多个版本。

三、开发篇(后端)

需实现获取文件信息(GET /v3/3rd/files/:file_id),获取文件下载地址 (GET /v3/3rd/files/:file_id/download),文档用户权限(GET /v3/3rd/files/:file_id/permission)

具体请参考,开发文档

其中还有个细节问题,返回的格式需按照文档要求进行,例如:code = 0 为成功。

具体部分代码,包含业务系统鉴权部分;

1、用户token鉴权

private UserToken getBaseUser(HttpServletRequest request) {  
    String token = request.getHeader("x-wps-weboffice-token");  
    if (token == null) {  
        token = request.getHeader("X-WebOffice-Token");  
    }  
    if (token == null) {  
        token = request.getHeader(BaseConstants.ACCESS\_TOKEN);  
    }  
    if (StringUtils.isEmptyWithTrim(token)) {  
        return null;  
    }  
    String username = JwtUtils.getUserId(token);  
    if (StringUtils.isEmptyWithTrim(username)) {  
        return null;  
    }  
    String type = "";  
    if(username.contains(BaseUser.USERNAME\_SPLIT)) {  
        int index = username.lastIndexOf(BaseUser.USERNAME\_SPLIT);  
        type = username.substring(index + BaseUser.USERNAME\_SPLIT.length());  
        username = username.substring(0, index);  
    }  
  
    String redisKey = BaseRedisConstants.getRedisKey(BaseRedisConstants.TOKEN\_USER.concat(type), username);  
    String value = RedisUtilEx.get(redisKey);  
    if(StringUtils.isEmptyWithTrim(value)) {  
        return null;  
    }  
    UserToken userToken = JsonUtils.json2Bean(value, UserToken.class);;  
    if(userToken == null) {  
        return null;  
    }  
    if(!token.equals(userToken.getAccessToken())) {  
        return null;  
    }  
  
    return userToken;  
}

2、回调接口

WPS文件信息校验接口
    @GetMapping("/v3/3rd/files/{fileId}")
    @Log(title = "WPS文件信息校验接口")
    public ResponseEntity<Object> getFilesInfo(@PathVariable("fileId") String fileId, HttpServletRequest request) {
        BaseUser baseUser = getBaseUser(request);
        if (baseUser == null) {
            return Response.bad("未获取到用户信息");
        }
        String _w_filepath = URLDecoder.decode(request.getHeader("X-User-Query"), "UTF-8");
        // 校验文件参数
        if(StringUtils.isEmptyWithTrim(_w_filepath)){
            return  Response.bad("未获取到文件路径信息");
        }
        // 校验文件地址
        String regex = "url=([^&]+)";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(_w_filepath);
        if (matcher.find()) {
            String url = matcher.group(1);
            String _w_existMark = "1";
            try {
                Map<String, Object> map = fileService.getWebFilesInfo(url, _w_existMark, fileId, baseUser);
                return Response.success(map);
            } catch (Exception e) {
                return Response.bad("获取文件元数据异常");
            }
        } else {
            return Response.bad("获取文件元数据异常");
        }
    }
public interface WpsFlieService {

    Map<String, Object> getWebFilesInfo(String filePath, String fileId, String existMark, BaseUser user);

}
    /**
     * 获取文件元数据(WPS 新版本)
     * @param filePath 文件路径
     * @return
     */
    public Map<String, Object> getWebFilesInfo(String filePath, String existMark, String fileId, BaseUser baseUser){
        // 构建默认user信息
        WpsUser wpsUser = new WpsUser(
                baseUser.getUserId(), baseUser.getUserRealName(), "read", " ");

        int fileSize = Math.abs(FileUtil.getFileSize(filePath));
        WpsWatermark mark = new WpsWatermark();
        mark.setValue(baseUser.getUserRealName()+"\n"+ LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        if (!Objects.equals("1", existMark)) {
            mark.setType(0);
        }

        String fileNameWithExtension = filePath.substring(filePath.lastIndexOf('/') + 1);
        String fileID = fileNameWithExtension.substring(0, fileNameWithExtension.lastIndexOf('.'));
        // 构建文件
        WpsFile file = new WpsFile(
                fileID, FileUtil.getFileName(filePath),
                1, fileSize, "1", System.currentTimeMillis()
        );

        return new HashMap<String, Object>() {
            {
                put("data", file);
            }
        };
    }
WPS下载校验接口
@GetMapping("/v3/3rd/files/{fileId}/download")
    @Log(title = "WPS下载校验接口")
    public ResponseEntity<Object> getDownloadInfo(@PathVariable("fileId") String fileId, HttpServletRequest request) {
        BaseUser baseUser = getBaseUser(request);
        if (baseUser == null) {
            return Response.bad("未获取到用户信息");
        }
        String _w_filepath = URLDecoder.decode(request.getHeader("X-User-Query"), "UTF-8");
        // 校验文件参数
        if(StringUtils.isEmptyWithTrim(_w_filepath)){
            return  Response.bad("未获取到文件路径信息");
        }
        // 校验文件地址
        String regex = "url=([^&]+)";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(_w_filepath);
        if (matcher.find()) {
            String url = matcher.group(1);
            try {
                Map<String, Object> map = new HashMap<String, Object>() {
                    {
                        put("data", new HashMap<String, Object>() {
                            {
                                put("url", url);
                            }
                        });
                    }
                };
                return Response.success(map);
            } catch (Exception e) {
                return Response.bad("获取文件元数据异常");
            }
        } else {
            return Response.bad("获取文件元数据异常");
        }
    }

WPS权限鉴权校验接口
    @GetMapping("/v3/3rd/files/{fileId}/permission")
    @Log(title = "WPS权限鉴权校验接口")
    public ResponseEntity<Object> getPermissionInfo(@PathVariable("fileId") String fileId, HttpServletRequest request) {
        BaseUser baseUser = getBaseUser(request);
        if (baseUser == null) {
            return Response.bad("未获取到用户信息");
        }
        String _w_filepath = URLDecoder.decode(request.getHeader("X-User-Query"), "UTF-8");
        try {
            Map<String, Object> map = new HashMap<String, Object>() {
                {
                    put("data", new HashMap<String, Object>() {
                        {
                            put("comment", 0);
                            put("copy", 0);
                            put("download", 0);
                            put("history", 0);
                            put("print", 0);
                            put("read", 1);
                            put("rename", 0);
                            put("saveas", 0);
                            put("update", 0);
                            put("comment", 0);
                        }
                    });
                }
            };
            return Response.success(map);
        } catch (Exception e) {
            return Response.bad("获取文件元数据异常");
        }
    }
返回结构类
public class Response {
    // keys
    private final static String MSG_KEY = "msg";
    private final static String STATUS_KEY = "status";
    private final static String CODE_KEY = "code";
    private final static String DATA_KEY = "data";

    // msg
    private final static String SUCCESS_MSG = "ok";

    // value
    private final static String SUCCESS_VALUE = "success";

    /**
     * 请求成功,并返回请求结果集
     *
     * @param data 返回到客户端的对象
     * @return Spring mvc ResponseEntity
     */
    public static ResponseEntity<Object> success(Map<String, Object> data, String msg) {
        return getObjectResponseEntity(data, msg);
    }

    @SuppressWarnings("serial")
    public static ResponseEntity<Object> success(String msg) {
        Map<String, Object> result = new HashMap<String, Object>() {
            {
                put(STATUS_KEY, SUCCESS_VALUE);
                put(MSG_KEY, msg);
                put(CODE_KEY, 0);
            }
        };
        return getEntity(result);
    }

    @SuppressWarnings("serial")
    public static ResponseEntity<Object> success() {
        Map<String, Object> result = new HashMap<String, Object>() {
            {
                put(STATUS_KEY, SUCCESS_VALUE);
                put(MSG_KEY, SUCCESS_MSG);
                put(CODE_KEY, 0);
            }
        };
        return getEntity(result);
    }

    /**
     * 请求成功,并返回请求结果集
     *
     * @param data 返回到客户端的对象
     * @return Spring mvc ResponseEntity
     */
    public static ResponseEntity<Object> success(Map<String, Object> data) {
        return getObjectResponseEntity(data, SUCCESS_MSG);
    }

    @SuppressWarnings("serial")
    public static ResponseEntity<Object> success(Object data) {
        Map<String, Object> result = new HashMap<String, Object>() {
            {
                put(STATUS_KEY, SUCCESS_VALUE);
                put(MSG_KEY, SUCCESS_MSG);
                put(CODE_KEY, 0);
                put(DATA_KEY, data);
            }
        };
        return getEntity(result);
    }

    @SuppressWarnings("serial")
    public static ResponseEntity<Object> success(boolean data, String msg) {
        Map<String, Object> result = new HashMap<String, Object>() {
            {
                put(STATUS_KEY, SUCCESS_VALUE);
                put(MSG_KEY, msg);
                put(CODE_KEY, 0);
                put(DATA_KEY, data);
            }
        };
        return getEntity(result);
    }

    @SuppressWarnings("serial")
    public static ResponseEntity<Object> bad(String msg) {
        Map<String, Object> result = new HashMap<String, Object>() {
            {
                put(STATUS_KEY, SUCCESS_VALUE);
                put(MSG_KEY, msg);
                put(CODE_KEY, HttpStatus.BAD_REQUEST.value());
            }
        };
        return getEntity(result);
    }

    @SuppressWarnings("serial")
    private static ResponseEntity<Object> getObjectResponseEntity(Map<String, Object> data, String msg) {
        Map<String, Object> result = new HashMap<String, Object>() {
            {
//                put(STATUS_KEY, SUCCESS_VALUE);
//                put(MSG_KEY, msg);
                put(CODE_KEY, 0);
                for (Map.Entry<String, Object> entry : data.entrySet()) {
                    put(entry.getKey(), entry.getValue());
                }
            }
        };
        return getEntity(result);
    }

    @SuppressWarnings("serial")
    private static ResponseEntity<Object> getEntity(Object body) {
        List<String> contentType = new ArrayList<String>() {
            {
                add("application/json;charset=utf-8");
            }
        };
        MultiValueMap<String, String> headers = new HttpHeaders() {
            {
                put("Content-Type", contentType);
            }
        };
        return new ResponseEntity<>(body, headers, HttpStatus.OK);
    }
}

三、开发篇(前端)

1、引入WPS依赖库;

下载地址:JSSDK

因为当前开发系统是使用Vue2的技术栈,所以需使用Es结构的数据进行引入,如

import WebOfficeSDK from '@/utils/web-office-sdk-solution-v2.0.6.es.js'

我当前JS文件是在utils下的。

2、WebOfficeSDK初始化

openWps(url) {

console.log(' ---------------url------------------ ', url)

if(url){

var urlObj \= new URL(url);

var filepath \= urlObj.searchParams.get('\_w\_filepath');

console.log('输出 -------------' ,filepath); // 输出:

console.log(' getToken() -------------' , getToken()); // 输出:

if(this.isFilePath(filepath)){

var parts \= filepath.split('/');

var fileNameWithExtension \= parts\[parts.length \- 1\];

var fileName \= fileNameWithExtension.split('.')\[0\];

console.log(' ----------fileName-------- ', fileName)

console.log('输出 -------------' ,filepath); // 输出:

  

// 获取文件扩展名

var fileExtension \= filepath.split('.').pop();

var officeTypeStr \= '';

// 根据文件扩展名判断文件类型

if (fileExtension \=== 'txt' || fileExtension \=== 'doc' || fileExtension \=== 'docx') {

officeTypeStr \= WebOfficeSDK.OfficeType.Writer;

console.log("这是文字文件");

} else if (fileExtension \=== 'xls' || fileExtension \=== 'xlsx' || fileExtension \=== 'csv') {

officeTypeStr \= WebOfficeSDK.OfficeType.Spreadsheet;

console.log("这是表格文件");

} else if (fileExtension \=== 'ppt' || fileExtension \=== 'pptx') {

officeTypeStr \= WebOfficeSDK.OfficeType.Presentation;

console.log("这是演示文件");

} else if (fileExtension \=== 'pdf') {

officeTypeStr \= WebOfficeSDK.OfficeType.Pdf;

console.log("这是PDF文件");

} else {

console.log("未知文件类型");

}

  

if(officeTypeStr){

// new

WebOfficeSDK.init({

officeType: officeTypeStr,

appId: 'SX20240528THJUYB',

fileId: fileName,

mount: document.querySelector('#viewFile'),

token: getToken(),

customArgs: {

url: filepath

}

})

}

  
  
  
  
  
  

// old

// const wps = WPS.config({

// mode: 'simple',

// mount: document.querySelector('#viewFile'),

// wpsUrl: url,

// fileId: fileName,

// commonOptions: {

// isShowTopArea: false,

// isShowHeader: false,

// isIframeViewFullscreen: true,

// }

// });

// wps.setToken({ "token": getToken(),"timeout":600000});

}

}

},

isFilePath(url) {

try {

var urlObj \= new URL(url);

var pathname \= urlObj.pathname;

var fileName \= pathname.split('/').pop();

return fileName.includes('.') && fileName.lastIndexOf('.') !== 0;

} catch (e) {

return false; // 如果URL无效,返回false

}

},