@@ -26,7 +26,7 @@ import java.io.OutputStream; | |||
import static org.apache.poi.ooxml.POIXMLTypeLoader.DEFAULT_XML_OPTIONS; | |||
/** | |||
* 水印工具类,提供 WPS紧支持打印水印 | |||
* 水印工具类,WPS仅支持打印水印 | |||
* 参考 https://jingyan.baidu.com/article/6d704a137cd29d28db51ca87.html | |||
* | |||
* @author jueyue on 20-4-29. | |||
@@ -0,0 +1,54 @@ | |||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |||
<modelVersion>4.0.0</modelVersion> | |||
<parent> | |||
<groupId>cn.afterturn</groupId> | |||
<artifactId>easypoi</artifactId> | |||
<version>4.1.3</version> | |||
</parent> | |||
<artifactId>easypoi-wps</artifactId> | |||
<dependencies> | |||
<!--spring --> | |||
<dependency> | |||
<groupId>org.springframework</groupId> | |||
<artifactId>spring-web</artifactId> | |||
<scope>compile</scope> | |||
</dependency> | |||
<dependency> | |||
<groupId>org.springframework</groupId> | |||
<artifactId>spring-webmvc</artifactId> | |||
<scope>compile</scope> | |||
</dependency> | |||
<dependency> | |||
<groupId>org.springframework</groupId> | |||
<artifactId>spring-context</artifactId> | |||
<scope>compile</scope> | |||
</dependency> | |||
<dependency> | |||
<groupId>org.springframework</groupId> | |||
<artifactId>spring-core</artifactId> | |||
<scope>compile</scope> | |||
</dependency> | |||
<dependency> | |||
<groupId>org.springframework</groupId> | |||
<artifactId>spring-beans</artifactId> | |||
<scope>compile</scope> | |||
</dependency> | |||
<dependency> | |||
<groupId>javax.servlet</groupId> | |||
<artifactId>servlet-api</artifactId> | |||
<scope>provided</scope> | |||
</dependency> | |||
<dependency> | |||
<groupId>cn.afterturn</groupId> | |||
<artifactId>easypoi-base</artifactId> | |||
</dependency> | |||
<dependency> | |||
<groupId>org.projectlombok</groupId> | |||
<artifactId>lombok</artifactId> | |||
<version>1.16.20</version> | |||
<scope>provided</scope> | |||
</dependency> | |||
</dependencies> | |||
</project> |
@@ -0,0 +1,136 @@ | |||
package cn.afterturn.easypoi.wps.controller; | |||
import cn.afterturn.easypoi.wps.entity.WpsToken; | |||
import cn.afterturn.easypoi.wps.entity.resreq.*; | |||
import cn.afterturn.easypoi.wps.service.IEasyPoiWpsService; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import org.springframework.beans.factory.annotation.Autowired; | |||
import org.springframework.web.bind.annotation.*; | |||
import org.springframework.web.multipart.MultipartFile; | |||
import javax.servlet.http.HttpServletRequest; | |||
import java.io.UnsupportedEncodingException; | |||
import java.net.URLDecoder; | |||
import java.util.Map; | |||
/** | |||
* @author jueyue on 20-5-7. | |||
*/ | |||
@RestController | |||
@RequestMapping("v1/3rd/file") | |||
public class EasyPoiFileController { | |||
private static final Logger LOGGER = LoggerFactory.getLogger(EasyPoiFileController.class); | |||
@Autowired(required = false) | |||
private IEasyPoiWpsService easyPoiWpsService; | |||
/** | |||
* 获取网络文件预览URL | |||
* | |||
* @param filePath | |||
* @return t | |||
*/ | |||
@GetMapping("getViewUrl") | |||
public WpsToken getViewUrl(String filePath) { | |||
LOGGER.info("getViewUrlWebPath:filePath={}", filePath); | |||
WpsToken token = easyPoiWpsService.getViewUrl(decode(filePath)); | |||
return token; | |||
} | |||
/** | |||
* 获取文件元数据 | |||
*/ | |||
@GetMapping("info") | |||
public WpsFileResponse getFileInfo(HttpServletRequest request, @RequestParam(value = "_w_userid", required = false) String userId, | |||
@RequestParam("_w_filepath") String filePath) { | |||
LOGGER.info("获取文件元数据userId:{},path:{}", userId, filePath); | |||
String fileId = request.getHeader("x-weboffice-file-id"); | |||
WpsFileResponse fileResponse = easyPoiWpsService.getFileInfo(userId, decode(filePath), fileId); | |||
return fileResponse; | |||
} | |||
/** | |||
* 通知此文件目前有哪些人正在协作 | |||
*/ | |||
@PostMapping("online") | |||
public WpsResponse fileOnline(HttpServletRequest request, @RequestBody WpsUserRequest list) { | |||
LOGGER.info("通知此文件目前有哪些人正在协作param:{}", list); | |||
String fileId = request.getHeader("x-weboffice-file-id"); | |||
easyPoiWpsService.fileOnline(fileId, list); | |||
return WpsResponse.success(); | |||
} | |||
/** | |||
* 上传文件新版本 | |||
*/ | |||
@PostMapping("save") | |||
public WpsFileSaveResponse fileSave(HttpServletRequest request, | |||
@RequestParam(value = "_w_userid", required = false) String userId, | |||
@RequestBody MultipartFile file) { | |||
LOGGER.info("上传文件新版本"); | |||
String fileId = request.getHeader("x-weboffice-file-id"); | |||
return new WpsFileSaveResponse(easyPoiWpsService.fileSave(fileId, userId, file)); | |||
} | |||
/** | |||
* 获取特定版本的文件信息 | |||
*/ | |||
@GetMapping("version/{version}") | |||
public WpsFileSaveResponse fileVersion(HttpServletRequest request, @PathVariable Integer version, | |||
@RequestParam("_w_filepath") String filePath) { | |||
LOGGER.info("获取特定版本的文件信息version:{}", version); | |||
String fileId = request.getHeader("x-weboffice-file-id"); | |||
return new WpsFileSaveResponse(easyPoiWpsService.getFileInfoOfVersion(fileId, decode(filePath), version)); | |||
} | |||
/** | |||
* 文件重命名 | |||
*/ | |||
@PutMapping("rename") | |||
public WpsResponse fileRename(HttpServletRequest request, @RequestBody WpsRenameRequest req, | |||
@RequestParam(value = "_w_userid", required = false) String userId) { | |||
LOGGER.info("文件重命名param:{},userId:{}", req, userId); | |||
String fileId = request.getHeader("x-weboffice-file-id"); | |||
easyPoiWpsService.rename(fileId, userId, req.getName()); | |||
return WpsResponse.success(); | |||
} | |||
/** | |||
* 获取所有历史版本文件信息 | |||
*/ | |||
@PostMapping("history") | |||
public WpsFileHistoryResponse fileHistory(@RequestBody WpsFileHistoryRequest req) { | |||
LOGGER.info("获取所有历史版本文件信息param:{}", req); | |||
return easyPoiWpsService.getHistory(req); | |||
} | |||
/** | |||
* 新建文件 | |||
*/ | |||
@PostMapping("new") | |||
public WpsResponse fileNew(@RequestBody MultipartFile file, @RequestParam(value = "_w_userid", required = false) String userId) { | |||
LOGGER.info("新建文件,只打印不实现,userid:{}", userId); | |||
return WpsResponse.success(); | |||
} | |||
/** | |||
* 回调通知 | |||
*/ | |||
@PostMapping("onnotify") | |||
public WpsResponse onNotify(@RequestBody Map obj) { | |||
LOGGER.info("回调通知,只打印不实现,param:{}", obj); | |||
return WpsResponse.success(); | |||
} | |||
public String decode(String filePath) { | |||
try { | |||
filePath = URLDecoder.decode(filePath, "UTF-8"); | |||
} catch (UnsupportedEncodingException e) { | |||
LOGGER.error(e.getMessage(), e); | |||
} | |||
return filePath; | |||
} | |||
} |
@@ -0,0 +1,43 @@ | |||
package cn.afterturn.easypoi.wps.controller; | |||
import cn.afterturn.easypoi.wps.entity.WpsUserEntity; | |||
import cn.afterturn.easypoi.wps.entity.resreq.WpsUserRequest; | |||
import cn.afterturn.easypoi.wps.entity.resreq.WpsUserResponse; | |||
import cn.afterturn.easypoi.wps.service.IEasyPoiWpsUserService; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import org.springframework.beans.factory.annotation.Autowired; | |||
import org.springframework.web.bind.annotation.PostMapping; | |||
import org.springframework.web.bind.annotation.RequestBody; | |||
import org.springframework.web.bind.annotation.RequestMapping; | |||
import org.springframework.web.bind.annotation.RestController; | |||
/** | |||
* @author jueyue on 20-5-8. | |||
*/ | |||
@RestController | |||
@RequestMapping("v1/3rd/file") | |||
public class EasyPoiUserController { | |||
private static final Logger LOGGER = LoggerFactory.getLogger(EasyPoiUserController.class); | |||
@Autowired(required = false) | |||
private IEasyPoiWpsUserService userService; | |||
/** | |||
* 获取用户信息 | |||
*/ | |||
@PostMapping("info") | |||
public WpsUserResponse userInfo(@RequestBody WpsUserRequest list) { | |||
LOGGER.info("获取用户信息param:{}", list); | |||
WpsUserResponse response = new WpsUserResponse(); | |||
for (int i = 0; i < list.getIds().size(); i++) { | |||
if (userService != null) { | |||
response.getUsers().add(userService.getUser(list.getIds().get(i))); | |||
} else { | |||
response.getUsers().add(new WpsUserEntity()); | |||
} | |||
} | |||
return response; | |||
} | |||
} |
@@ -0,0 +1,48 @@ | |||
package cn.afterturn.easypoi.wps.entity; | |||
import lombok.Data; | |||
import java.io.Serializable; | |||
/** | |||
* @author jueyue on 20-5-8. | |||
*/ | |||
@Data | |||
public class WpsFileEntity implements Serializable { | |||
/** | |||
* 文件id,字符串长度小于40 | |||
*/ | |||
private String id; | |||
/** | |||
* 文件名 | |||
*/ | |||
private String name; | |||
/** | |||
* 当前版本号,位数小于11 | |||
*/ | |||
private int version = 1; | |||
/** | |||
* 文件大小,单位为kb | |||
*/ | |||
private int size; | |||
/** | |||
* 创建者id,字符串长度小于40 | |||
*/ | |||
private String creator = "0"; | |||
/** | |||
* 修改者id,字符串长度小于40 | |||
*/ | |||
private String modifier; | |||
/** | |||
* 创建时间,时间戳,单位为秒 | |||
*/ | |||
private long create_time = System.currentTimeMillis(); | |||
/** | |||
* 修改时间,时间戳,单位为秒 | |||
*/ | |||
private long modify_time; | |||
private String download_url; | |||
private WpsUserAclEntity user_acl = new WpsUserAclEntity(); | |||
private WpsWatermarkEntity watermark = new WpsWatermarkEntity(); | |||
} |
@@ -0,0 +1,40 @@ | |||
package cn.afterturn.easypoi.wps.entity; | |||
import lombok.Data; | |||
import java.io.Serializable; | |||
/** | |||
* @author jueyue on 20-5-8. | |||
*/ | |||
@Data | |||
public class WpsFileHistoryEntity implements Serializable { | |||
/** | |||
* 文件id,字符串长度小于40 | |||
*/ | |||
private String id; | |||
/** | |||
* 文件名 | |||
*/ | |||
private String name; | |||
/** | |||
* 当前版本号,位数小于11 | |||
*/ | |||
private int version = 1; | |||
/** | |||
* 文件大小,单位为kb | |||
*/ | |||
private int size; | |||
/** | |||
* 创建时间,时间戳,单位为秒 | |||
*/ | |||
private long create_time; | |||
/** | |||
* 修改时间,时间戳,单位为秒 | |||
*/ | |||
private long modify_time; | |||
private WpsUserEntity creator; | |||
private WpsUserEntity modifier; | |||
} |
@@ -0,0 +1,19 @@ | |||
package cn.afterturn.easypoi.wps.entity; | |||
import cn.afterturn.easypoi.wps.entity.resreq.WpsResponse; | |||
import lombok.Data; | |||
import java.io.Serializable; | |||
/** | |||
* @author JueYue | |||
* 界面的Token数据,默认不使用 | |||
*/ | |||
@Data | |||
public class WpsToken extends WpsResponse implements Serializable { | |||
private int expires_in; | |||
private String token; | |||
private String wpsUrl; | |||
} |
@@ -0,0 +1,29 @@ | |||
package cn.afterturn.easypoi.wps.entity; | |||
import lombok.Data; | |||
import java.io.Serializable; | |||
/** | |||
* @author jueyue on 20-5-8. | |||
*/ | |||
@Data | |||
public class WpsUserAclEntity implements Serializable { | |||
/** | |||
* 重命名权限,1为打开该权限,0为关闭该权限,默认为0 | |||
*/ | |||
private Integer rename = 0; | |||
/** | |||
* 历史版本权限,1为打开该权限,0为关闭该权限,默认为1 | |||
*/ | |||
private Integer history = 0; | |||
/** | |||
* 复制 | |||
*/ | |||
private Integer copy = 1; | |||
/** | |||
* 导出PDF | |||
*/ | |||
private Integer export = 1; | |||
private Integer print = 1; | |||
} |
@@ -0,0 +1,29 @@ | |||
package cn.afterturn.easypoi.wps.entity; | |||
import lombok.Data; | |||
import java.io.Serializable; | |||
/** | |||
* @author jueyue on 20-5-7. | |||
*/ | |||
@Data | |||
public class WpsUserEntity implements Serializable { | |||
/** | |||
* 用户id,长度小于40 | |||
*/ | |||
private String id = "0"; | |||
/** | |||
* 用户名称 | |||
*/ | |||
private String name = "悟耘-EasyPoi"; | |||
/** | |||
* 用户操作权限,write:可编辑,read:预览 | |||
*/ | |||
private String permission = "read"; | |||
/** | |||
* 用户头像地址 | |||
*/ | |||
private String avatar_url = "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=50688014,2596832035&fm=11&gp=0.jpg"; | |||
} |
@@ -0,0 +1,45 @@ | |||
package cn.afterturn.easypoi.wps.entity; | |||
import lombok.Data; | |||
import java.io.Serializable; | |||
/** | |||
* 水印配置 | |||
* | |||
* @author jueyue on 20-5-8. | |||
*/ | |||
@Data | |||
public class WpsWatermarkEntity implements Serializable { | |||
/** | |||
* 水印类型, 0为无水印; 1为文字水印 | |||
*/ | |||
private Integer type = 0; | |||
/** | |||
* 文字水印的文字,当type为1时此字段必选 | |||
*/ | |||
private Integer value; | |||
/** | |||
* 水印的透明度,非必选,有默认值 | |||
* "rgba( 192, 192, 192, 0.6 )" | |||
*/ | |||
private Integer fillstyle; | |||
/** | |||
* 水印的字体,非必选,有默认值 | |||
* "bold 20px Serif" | |||
*/ | |||
private Integer font; | |||
/** | |||
* 水印的旋转度,非必选,有默认值 | |||
* -0.7853982 | |||
*/ | |||
private String rotate; | |||
/** | |||
* 水印水平间距,非必选,有默认值 | |||
*/ | |||
private Integer horizontal; | |||
/** | |||
* 水印垂直间距,非必选,有默认值 | |||
*/ | |||
private Integer vertical; | |||
} |
@@ -0,0 +1,16 @@ | |||
package cn.afterturn.easypoi.wps.entity.resreq; | |||
import lombok.Data; | |||
import java.io.Serializable; | |||
/** | |||
* @author jueyue on 20-5-8. | |||
*/ | |||
@Data | |||
public class WpsFileHistoryRequest extends WpsResponse implements Serializable { | |||
private String id; | |||
private int offset; | |||
private int count; | |||
} |
@@ -0,0 +1,16 @@ | |||
package cn.afterturn.easypoi.wps.entity.resreq; | |||
import cn.afterturn.easypoi.wps.entity.WpsFileHistoryEntity; | |||
import lombok.Data; | |||
import java.io.Serializable; | |||
import java.util.List; | |||
/** | |||
* @author jueyue on 20-5-8. | |||
*/ | |||
@Data | |||
public class WpsFileHistoryResponse extends WpsResponse implements Serializable { | |||
private List<WpsFileHistoryEntity> histories; | |||
} |
@@ -0,0 +1,20 @@ | |||
package cn.afterturn.easypoi.wps.entity.resreq; | |||
import cn.afterturn.easypoi.wps.entity.WpsFileEntity; | |||
import cn.afterturn.easypoi.wps.entity.WpsUserEntity; | |||
import lombok.Data; | |||
import java.io.Serializable; | |||
/** | |||
* 获取文件返回对象 | |||
* | |||
* @author jueyue on 20-5-8. | |||
*/ | |||
@Data | |||
public class WpsFileResponse extends WpsResponse implements Serializable { | |||
private WpsFileEntity file; | |||
private WpsUserEntity user = new WpsUserEntity(); | |||
} |
@@ -0,0 +1,22 @@ | |||
package cn.afterturn.easypoi.wps.entity.resreq; | |||
import cn.afterturn.easypoi.wps.entity.WpsFileEntity; | |||
import lombok.Data; | |||
import java.io.Serializable; | |||
/** | |||
* @author jueyue on 20-5-8. | |||
*/ | |||
@Data | |||
public class WpsFileSaveResponse extends WpsResponse implements Serializable { | |||
public WpsFileSaveResponse() { | |||
} | |||
public WpsFileSaveResponse(WpsFileEntity file) { | |||
this.file = file; | |||
} | |||
private WpsFileEntity file; | |||
} |
@@ -0,0 +1,14 @@ | |||
package cn.afterturn.easypoi.wps.entity.resreq; | |||
import lombok.Data; | |||
import java.io.Serializable; | |||
/** | |||
* @author jueyue on 20-5-8. | |||
*/ | |||
@Data | |||
public class WpsRenameRequest extends WpsResponse implements Serializable { | |||
private String name; | |||
} |
@@ -0,0 +1,21 @@ | |||
package cn.afterturn.easypoi.wps.entity.resreq; | |||
import lombok.Data; | |||
import java.io.Serializable; | |||
/** | |||
* @author jueyue on 20-5-8. | |||
*/ | |||
@Data | |||
public class WpsResponse implements Serializable { | |||
private int code = 200; | |||
private String msg; | |||
private String status = "success"; | |||
public static WpsResponse success() { | |||
return new WpsResponse(); | |||
} | |||
} |
@@ -0,0 +1,15 @@ | |||
package cn.afterturn.easypoi.wps.entity.resreq; | |||
import lombok.Data; | |||
import java.io.Serializable; | |||
import java.util.List; | |||
/** | |||
* @author jueyue on 20-5-8. | |||
*/ | |||
@Data | |||
public class WpsUserRequest implements Serializable { | |||
List<String> ids; | |||
} |
@@ -0,0 +1,17 @@ | |||
package cn.afterturn.easypoi.wps.entity.resreq; | |||
import cn.afterturn.easypoi.wps.entity.WpsUserEntity; | |||
import lombok.Data; | |||
import java.io.Serializable; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
/** | |||
* @author jueyue on 20-5-8. | |||
*/ | |||
@Data | |||
public class WpsUserResponse extends WpsResponse implements Serializable { | |||
private List<WpsUserEntity> users = new ArrayList<>(); | |||
} |
@@ -0,0 +1,85 @@ | |||
package cn.afterturn.easypoi.wps.service; | |||
/** | |||
* @author jueyue on 20-5-8. | |||
*/ | |||
public class EasyPoiWpsFileUtil { | |||
private static String[] OFFICE = {"word", "excel", "ppt"}; | |||
private static String[] EXCEL_EXTS = {"et", "xls", "xlt", "xlsx", "xlsm", "xltx", "xltm", "csv"}; | |||
private static String[] WORD_EXTS = {"doc", "docx", "txt", "dot", "wps", "wpt", "dotx", "docm", "dotm"}; | |||
private static String[] PPT_EXTS = {"ppt", "pptx", "pptm", "pptm", "ppsm", "pps", "potx", "potm", "dpt", "dps"}; | |||
private static String[] PDF_EXTS = {"pdf"}; | |||
public static String getFileTypeCode(String fileType) { | |||
for (String et : EXCEL_EXTS) { | |||
if (et.equalsIgnoreCase(fileType)) { | |||
return "s"; | |||
} | |||
} | |||
for (String et : WORD_EXTS) { | |||
if (et.equalsIgnoreCase(fileType)) { | |||
return "w"; | |||
} | |||
} | |||
for (String et : PPT_EXTS) { | |||
if (et.equalsIgnoreCase(fileType)) { | |||
return "p"; | |||
} | |||
} | |||
for (String et : PDF_EXTS) { | |||
if (et.equalsIgnoreCase(fileType)) { | |||
return "f"; | |||
} | |||
} | |||
return null; | |||
} | |||
public static boolean checkCode(String fileType) { | |||
for (String et : OFFICE) { | |||
if (et.equalsIgnoreCase(fileType)) { | |||
return true; | |||
} | |||
} | |||
return false; | |||
} | |||
public static String getTypeCode(String fileType) { | |||
if ("word".equalsIgnoreCase(fileType)) { | |||
return "w"; | |||
} | |||
if ("excel".equalsIgnoreCase(fileType)) { | |||
return "s"; | |||
} | |||
if ("ppt".equalsIgnoreCase(fileType)) { | |||
return "p"; | |||
} | |||
return null; | |||
} | |||
public static String getFileName(String filePath) { | |||
String[] pathArr = filePath.split("/"); | |||
String fileName; | |||
if (pathArr.length > 1) { | |||
fileName = pathArr[pathArr.length - 1]; | |||
} else { | |||
fileName = filePath; | |||
} | |||
return fileName; | |||
} | |||
public static String getFileTypeByPath(String filePath) { | |||
String fileName = getFileName(filePath); | |||
String[] arr = fileName.split("\\."); | |||
return arr[arr.length - 1]; | |||
} | |||
public static String getFileTypeByName(String fileName) { | |||
String[] arr = fileName.split("\\."); | |||
return arr[arr.length - 1]; | |||
} | |||
} |
@@ -0,0 +1,92 @@ | |||
package cn.afterturn.easypoi.wps.service; | |||
import org.apache.commons.codec.digest.HmacUtils; | |||
import java.io.UnsupportedEncodingException; | |||
import java.net.URLEncoder; | |||
import java.util.ArrayList; | |||
import java.util.HashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
import static org.apache.commons.codec.binary.Base64.encodeBase64String; | |||
/** | |||
* Wps相关的工具类 | |||
* | |||
* @author jueyue on 20-5-8. | |||
*/ | |||
public class EasyPoiWpsUtil { | |||
public static String getKeyValueStr(Map<String, String> params) { | |||
List<String> keys = new ArrayList<String>() { | |||
{ | |||
for (Map.Entry<String, String> entry : params.entrySet()) { | |||
add(entry.getKey()); | |||
} | |||
} | |||
}; | |||
StringBuilder sb = new StringBuilder(); | |||
for (String key : keys) { | |||
String value = params.get(key) + "&"; | |||
sb.append(key).append("=").append(value); | |||
} | |||
return sb.toString(); | |||
} | |||
public static String getSignature(Map<String, String> params, String appSecret) { | |||
List<String> keys = new ArrayList<String>() { | |||
{ | |||
for (Map.Entry<String, String> entry : params.entrySet()) { | |||
add(entry.getKey()); | |||
} | |||
} | |||
}; | |||
// 将所有参数按key的升序排序 | |||
keys.sort(String::compareTo); | |||
// 构造签名的源字符串 | |||
StringBuilder contents = new StringBuilder(); | |||
for (String key : keys) { | |||
if (key.equals("_w_signature")) { | |||
continue; | |||
} | |||
contents.append(key).append("=").append(params.get(key)); | |||
} | |||
contents.append("_w_secretkey=").append(appSecret); | |||
// 进行hmac sha1 签名 | |||
byte[] bytes = HmacUtils.hmacSha1(appSecret.getBytes(), contents.toString().getBytes()); | |||
//字符串经过Base64编码 | |||
String sign = encodeBase64String(bytes); | |||
try { | |||
return URLEncoder.encode(sign, "UTF-8"); | |||
} catch (UnsupportedEncodingException e) { | |||
e.printStackTrace(); | |||
return null; | |||
} | |||
} | |||
public Map<String, String> paramToMap(String paramStr) { | |||
String[] params = paramStr.split("&"); | |||
return new HashMap<String, String>() { | |||
{ | |||
for (String param1 : params) { | |||
String[] param = param1.split("="); | |||
if (param.length >= 2) { | |||
String key = param[0]; | |||
StringBuilder value = new StringBuilder(param[1]); | |||
for (int j = 2; j < param.length; j++) { | |||
value.append("=").append(param[j]); | |||
} | |||
put(key, value.toString()); | |||
} | |||
} | |||
} | |||
}; | |||
} | |||
} |
@@ -0,0 +1,216 @@ | |||
package cn.afterturn.easypoi.wps.service; | |||
import cn.afterturn.easypoi.wps.entity.WpsFileEntity; | |||
import cn.afterturn.easypoi.wps.entity.WpsToken; | |||
import cn.afterturn.easypoi.wps.entity.resreq.WpsFileHistoryRequest; | |||
import cn.afterturn.easypoi.wps.entity.resreq.WpsFileHistoryResponse; | |||
import cn.afterturn.easypoi.wps.entity.resreq.WpsFileResponse; | |||
import cn.afterturn.easypoi.wps.entity.resreq.WpsUserRequest; | |||
import org.springframework.web.multipart.MultipartFile; | |||
import sun.reflect.generics.reflectiveObjects.NotImplementedException; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import java.util.UUID; | |||
/** | |||
* 获取 | |||
* | |||
* @author jueyue on 20-5-7. | |||
*/ | |||
public interface IEasyPoiWpsService { | |||
/** | |||
* 获取Wps的地址 | |||
* | |||
* @param filePath | |||
* @return | |||
*/ | |||
default WpsToken getViewUrl(String filePath) { | |||
WpsToken t = new WpsToken(); | |||
Map<String, String> values = new HashMap<String, String>() { | |||
{ | |||
put("_w_appid", getAppId()); | |||
put("_w_userid", getUserId()); | |||
put("_w_filepath", filePath); | |||
} | |||
}; | |||
String keyValueStr = EasyPoiWpsUtil.getKeyValueStr(values); | |||
String signature = EasyPoiWpsUtil.getSignature(values, getAppSecret()); | |||
String fileTypeCode = EasyPoiWpsFileUtil.getFileTypeCode(EasyPoiWpsFileUtil.getFileTypeByPath(filePath)); | |||
String wpsUrl = getDomain() + fileTypeCode + "/" + getFileId(filePath) + "?" | |||
+ keyValueStr + "_w_signature=" + signature; | |||
t.setToken(getToken()); | |||
t.setExpires_in(600); | |||
t.setWpsUrl(wpsUrl); | |||
return t; | |||
} | |||
/** | |||
* 获取用户Token有必要可以带上 | |||
* | |||
* @return | |||
*/ | |||
default String getToken() { | |||
return UUID.randomUUID().toString().replace("-", ""); | |||
} | |||
/** | |||
* 获取文件ID,如果filePath可以现实没必要,如果使用ID请实现 | |||
* | |||
* @param filePath | |||
* @return | |||
*/ | |||
default String getFileId(String filePath) { | |||
return UUID.randomUUID().toString().replace("-", ""); | |||
} | |||
/** | |||
* WPS路径 | |||
* | |||
* @return | |||
*/ | |||
default String getDomain() { | |||
return "https://wwo.wps.cn/office/"; | |||
} | |||
/** | |||
* APP秘钥 | |||
* | |||
* @return | |||
*/ | |||
String getAppSecret(); | |||
/** | |||
* 获取WPS配置的AppId | |||
* | |||
* @return | |||
*/ | |||
String getAppId(); | |||
/** | |||
* 获取当前用户ID,如果不权限校验可以不实现 | |||
* | |||
* @return | |||
*/ | |||
default String getUserId() { | |||
return "0"; | |||
} | |||
/** | |||
* 获取文件信息 | |||
* | |||
* @param userId | |||
* @param filepath | |||
* @param fileId | |||
* @return 返回文件信息 | |||
*/ | |||
default WpsFileResponse getFileInfo(String userId, String filepath, String fileId) { | |||
WpsFileResponse response = new WpsFileResponse(); | |||
WpsFileEntity fileEntity = new WpsFileEntity(); | |||
fileEntity.setId(fileId); | |||
fileEntity.setName(getFileName(filepath)); | |||
fileEntity.setSize(getFileSize(filepath)); | |||
fileEntity.setDownload_url(getDownLoadUrl(filepath)); | |||
response.setFile(fileEntity); | |||
return response; | |||
} | |||
/** | |||
* 单位为B | |||
* | |||
* @param filepath | |||
* @return | |||
*/ | |||
int getFileSize(String filepath); | |||
/** | |||
* 获取文件的下载路径 | |||
* | |||
* @param filepath | |||
* @return | |||
*/ | |||
String getDownLoadUrl(String filepath); | |||
/** | |||
* 获取文件名称 -中文或者英文 | |||
* | |||
* @param filepath | |||
* @return | |||
*/ | |||
default String getFileName(String filepath) { | |||
return EasyPoiWpsFileUtil.getFileName(filepath); | |||
} | |||
/** | |||
* 文件被那些客户协作 | |||
* | |||
* @param fileId | |||
* @param list | |||
*/ | |||
default void fileOnline(String fileId, WpsUserRequest list) { | |||
} | |||
/** | |||
* 保存文件 | |||
* | |||
* @param fileId | |||
* @param userId | |||
* @param file | |||
* @return | |||
*/ | |||
default WpsFileEntity fileSave(String fileId, String userId, MultipartFile file) { | |||
throw new NotImplementedException(); | |||
} | |||
/** | |||
* 获取特定版本的文件 | |||
* | |||
* @param fileId | |||
* @param filepath | |||
* @param version | |||
* @return | |||
*/ | |||
default WpsFileEntity getFileInfoOfVersion(String fileId, String filepath, Integer version) { | |||
WpsFileEntity fileEntity = new WpsFileEntity(); | |||
fileEntity.setId(fileId); | |||
fileEntity.setName(getFileName(filepath)); | |||
fileEntity.setDownload_url(getDownLoadUrl(filepath, version)); | |||
fileEntity.setModifier(fileEntity.getModifier()); | |||
fileEntity.setModify_time(System.currentTimeMillis()); | |||
return fileEntity; | |||
} | |||
/** | |||
* 获取特定版本的URL | |||
* | |||
* @param filepath | |||
* @param version | |||
* @return | |||
*/ | |||
default String getDownLoadUrl(String filepath, Integer version) { | |||
throw new NotImplementedException(); | |||
} | |||
/** | |||
* 文件重命名 | |||
* | |||
* @param fileId | |||
* @param userId | |||
* @param name | |||
*/ | |||
default void rename(String fileId, String userId, String name) { | |||
throw new NotImplementedException(); | |||
} | |||
/** | |||
* 获取文件历史版本 | |||
* | |||
* @param req | |||
* @return | |||
*/ | |||
default WpsFileHistoryResponse getHistory(WpsFileHistoryRequest req) { | |||
throw new NotImplementedException(); | |||
} | |||
} |
@@ -0,0 +1,19 @@ | |||
package cn.afterturn.easypoi.wps.service; | |||
import cn.afterturn.easypoi.wps.entity.WpsUserEntity; | |||
/** | |||
* 用户服务 | |||
* | |||
* @author jueyue on 20-5-8. | |||
*/ | |||
public interface IEasyPoiWpsUserService { | |||
/** | |||
* 获取用户信息 | |||
* | |||
* @param userId | |||
* @return | |||
*/ | |||
WpsUserEntity getUser(String userId); | |||
} |
@@ -0,0 +1,38 @@ | |||
<!DOCTYPE html> | |||
<html lang="en"> | |||
<head> | |||
<meta charset="UTF-8"> | |||
<title>预览</title> | |||
<script src="/easypoijs/jquery-1.9.1.min.js"></script> | |||
<script src="/easypoijs/polyfill.min.js"></script> | |||
<script src="/easypoijs/web-office-sdk-v1.1.2.umd.js"></script> | |||
<script> | |||
$(document).ready(function () { | |||
let filePath = getUrlParam('filePath'); | |||
$.get('v1/3rd/file/getViewUrl?filePath=' + filePath, function (data) { | |||
let easyWps = WebOfficeSDK.config({ | |||
mode: 'simple', | |||
url: data.wpsUrl, // 如果需要通过js-sdk传递token方式鉴权,则需要包含_w_tokentype=1参数 | |||
//mount: document.querySelector('#easypoi-wps-mount') | |||
}) | |||
easyWps.setToken({token: data.token}) | |||
// 如果需要对iframe进行特殊的处理,可以通过以下方式拿到iframe的dom对象 | |||
//console.log(easyWps.iframe) | |||
// 打开文档结果 | |||
easyWps.on('fileOpen', function (data) { | |||
console.log(data.success) | |||
}) | |||
}) | |||
}); | |||
function getUrlParam(name) { | |||
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); //构造一个含有目标参数的正则表达式对象 | |||
var r = window.location.search.substr(1).match(reg); //匹配目标参数 | |||
if (r != null) return unescape(r[2]); | |||
return null; //返回参数值 | |||
} | |||
</script> | |||
</head> | |||
<body> | |||
</body> | |||
</html> |
@@ -0,0 +1 @@ | |||
!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n():"function"==typeof define&&define.amd?define(n):n()}(0,function(){"use strict";function e(e){var n=this.constructor;return this.then(function(t){return n.resolve(e()).then(function(){return t})},function(t){return n.resolve(e()).then(function(){return n.reject(t)})})}function n(e){return!(!e||"undefined"==typeof e.length)}function t(){}function o(e){if(!(this instanceof o))throw new TypeError("Promises must be constructed via new");if("function"!=typeof e)throw new TypeError("not a function");this._state=0,this._handled=!1,this._value=undefined,this._deferreds=[],c(e,this)}function r(e,n){for(;3===e._state;)e=e._value;0!==e._state?(e._handled=!0,o._immediateFn(function(){var t=1===e._state?n.onFulfilled:n.onRejected;if(null!==t){var o;try{o=t(e._value)}catch(r){return void f(n.promise,r)}i(n.promise,o)}else(1===e._state?i:f)(n.promise,e._value)})):e._deferreds.push(n)}function i(e,n){try{if(n===e)throw new TypeError("A promise cannot be resolved with itself.");if(n&&("object"==typeof n||"function"==typeof n)){var t=n.then;if(n instanceof o)return e._state=3,e._value=n,void u(e);if("function"==typeof t)return void c(function(e,n){return function(){e.apply(n,arguments)}}(t,n),e)}e._state=1,e._value=n,u(e)}catch(r){f(e,r)}}function f(e,n){e._state=2,e._value=n,u(e)}function u(e){2===e._state&&0===e._deferreds.length&&o._immediateFn(function(){e._handled||o._unhandledRejectionFn(e._value)});for(var n=0,t=e._deferreds.length;t>n;n++)r(e,e._deferreds[n]);e._deferreds=null}function c(e,n){var t=!1;try{e(function(e){t||(t=!0,i(n,e))},function(e){t||(t=!0,f(n,e))})}catch(o){if(t)return;t=!0,f(n,o)}}var a=setTimeout;o.prototype["catch"]=function(e){return this.then(null,e)},o.prototype.then=function(e,n){var o=new this.constructor(t);return r(this,new function(e,n,t){this.onFulfilled="function"==typeof e?e:null,this.onRejected="function"==typeof n?n:null,this.promise=t}(e,n,o)),o},o.prototype["finally"]=e,o.all=function(e){return new o(function(t,o){function r(e,n){try{if(n&&("object"==typeof n||"function"==typeof n)){var u=n.then;if("function"==typeof u)return void u.call(n,function(n){r(e,n)},o)}i[e]=n,0==--f&&t(i)}catch(c){o(c)}}if(!n(e))return o(new TypeError("Promise.all accepts an array"));var i=Array.prototype.slice.call(e);if(0===i.length)return t([]);for(var f=i.length,u=0;i.length>u;u++)r(u,i[u])})},o.resolve=function(e){return e&&"object"==typeof e&&e.constructor===o?e:new o(function(n){n(e)})},o.reject=function(e){return new o(function(n,t){t(e)})},o.race=function(e){return new o(function(t,r){if(!n(e))return r(new TypeError("Promise.race accepts an array"));for(var i=0,f=e.length;f>i;i++)o.resolve(e[i]).then(t,r)})},o._immediateFn="function"==typeof setImmediate&&function(e){setImmediate(e)}||function(e){a(e,0)},o._unhandledRejectionFn=function(e){void 0!==console&&console&&console.warn("Possible Unhandled Promise Rejection:",e)};var l=function(){if("undefined"!=typeof self)return self;if("undefined"!=typeof window)return window;if("undefined"!=typeof global)return global;throw Error("unable to locate global object")}();"Promise"in l?l.Promise.prototype["finally"]||(l.Promise.prototype["finally"]=e):l.Promise=o}); |
@@ -7,9 +7,10 @@ | |||
<packaging>pom</packaging> | |||
<name>easypoi</name> | |||
<modules> | |||
<module>easypoi-annotation</module> | |||
<module>easypoi-base</module> | |||
<module>easypoi-web</module> | |||
<module>easypoi-annotation</module> | |||
<module>easypoi-wps</module> | |||
</modules> | |||
<url>http://opensource.afterturn.cn/</url> | |||
@@ -50,7 +51,7 @@ | |||
<xerces.version>2.9.1</xerces.version> | |||
<guava.version>16.0.1</guava.version> | |||
<commons-lang.version>3.2.1</commons-lang.version> | |||
<slf4j.version>1.6.1</slf4j.version> | |||
<slf4j.version>1.7.26</slf4j.version> | |||
<spring.version>5.1.7.RELEASE</spring.version> | |||
</properties> | |||
<dependencyManagement> | |||