diff --git a/pom.xml b/pom.xml index c4148ef5da8f187b6f4281f93a3ddabad01d6564..b7856d4346eb7dcee5f32cc11c328d9ae87757e2 100644 --- a/pom.xml +++ b/pom.xml @@ -35,6 +35,7 @@ 3.1 23.1 1.70 + 1.2.83 1.2 3.6 diff --git a/server/pom.xml b/server/pom.xml index 23dc67d5ddb90d70780e9da490c79fad00f4c51b..7b2d38258c287e5fc8b745fcddd74ba76e0f6e6f 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -277,7 +277,16 @@ system ${pom.basedir}/lib/jai_codec-1.1.3.jar - + + org.apache.httpcomponents + httpclient + + + + com.alibaba + fastjson + ${fastjson.version} + org.springframework.boot diff --git a/server/src/main/config/application.properties b/server/src/main/config/application.properties index 392b7a27b3248dad215a0df1ed33139d4c5bf665..a24e69e727f2f31bac502d3315e870eb28870812 100644 --- a/server/src/main/config/application.properties +++ b/server/src/main/config/application.properties @@ -53,6 +53,15 @@ cache.clean.cron = ${KK_CACHE_CLEAN_CRON:0 0 3 * * ?} #提供预览服务的地址,默认从请求url读,如果使用nginx等反向代理,需要手动设置 #base.url = https://file.keking.cn base.url = ${KK_BASE_URL:default} +#提供预览服务的办公网络地址,默认从请求url读,如果使用nginx等反向代理,需要手动设置 +base.url.office = ${KK_BASE_URL_OFFICE:default} +#提供预览服务的互联网络地址,默认从请求url读,如果使用nginx等反向代理,需要手动设置 +base.url.out = ${KK_BASE_URL_OUT:default} +#提供预览服务的办公网络地址,默认从请求url读,如果使用nginx等反向代理,需要手动设置 +#base.file.url.office = http://113.140.95.222:60533 +base.file.url.office = ${KK_BASE_FILE_URL_OFFICE:default} +#提供预览服务的互联网络地址,默认从请求url读,如果使用nginx等反向代理,需要手动设置 +base.file.url.out = ${KK_BASE_FILE_URL_OUT:default} #信任站点,多个用','隔开,设置了之后,会限制只能预览来自信任站点列表的文件,默认不限制 #trust.host = kkview.cn diff --git a/server/src/main/java/cn/keking/config/ConfigConstants.java b/server/src/main/java/cn/keking/config/ConfigConstants.java index 7528f386be394a3fa766b5901d198c85533c8d8e..b65cb969900670f66b576849cf6c32480a956a60 100644 --- a/server/src/main/java/cn/keking/config/ConfigConstants.java +++ b/server/src/main/java/cn/keking/config/ConfigConstants.java @@ -32,6 +32,10 @@ public class ConfigConstants { private static String ftpPassword; private static String ftpControlEncoding; private static String baseUrl; + private static String baseUrlOffice; + private static String baseUrlOut; + private static String baseFileUrlOffice; + private static String baseFileUrlOut; private static String fileDir = ConfigUtils.getHomePath() + File.separator + "file" + File.separator; private static String localPreviewDir; private static CopyOnWriteArraySet trustHostSet; @@ -139,6 +143,7 @@ public class ConfigConstants { public void setMediaConvertDisable(String mediaConvertDisable) { setMediaConvertDisableValue(mediaConvertDisable); } + public static void setMediaConvertDisableValue(String mediaConvertDisable) { ConfigConstants.mediaConvertDisable = mediaConvertDisable; } @@ -208,6 +213,56 @@ public class ConfigConstants { ConfigConstants.baseUrl = baseUrl; } + public static String getBaseUrlOffice() { + return baseUrlOffice; + } + + @Value("${base.url.office:default}") + public void setBaseUrlOffice(String baseUrlOffice) { + setBaseUrlOfficeValue(baseUrlOffice); + } + + public static void setBaseUrlOfficeValue(String baseUrlOffice) { + ConfigConstants.baseUrlOffice = baseUrlOffice; + } + + public static String getBaseUrlOut() { + return baseUrlOut; + } + + @Value("${base.url.out:default}") + public void setBaseUrlOut(String baseUrlOut) { + setBaseUrlOutValue(baseUrlOut); + } + public static String getBaseFileUrlOffice() { + return baseFileUrlOffice; + } + + @Value("${base.file.url.office:default}") + public void setBaseFileUrlOffice(String baseFileUrlOffice) { + setBaseFileUrlOfficeValue(baseFileUrlOffice); + } + + public static void setBaseFileUrlOfficeValue(String baseFileUrlOffice) { + ConfigConstants.baseFileUrlOffice = baseFileUrlOffice; + } + + public static String getBaseFileUrlOut() { + return baseFileUrlOut; + } + + @Value("${base.file.url.out:default}") + public void setBaseFileUrlOut(String baseFileUrlOut) { + setBaseFileUrlOutValue(baseFileUrlOut); + } + + public static void setBaseFileUrlOutValue(String baseFileUrlOut) { + ConfigConstants.baseFileUrlOut = baseFileUrlOut; + } + + public static void setBaseUrlOutValue(String baseUrlOut) { + ConfigConstants.baseUrlOut = baseUrlOut; + } public static String getFileDir() { return fileDir; } @@ -290,6 +345,7 @@ public class ConfigConstants { public void setPdfOpenFileDisable(String pdfOpenFileDisable) { setPdfOpenFileDisableValue(pdfOpenFileDisable); } + public static void setPdfOpenFileDisableValue(String pdfOpenFileDisable) { ConfigConstants.pdfOpenFileDisable = pdfOpenFileDisable; } @@ -297,10 +353,12 @@ public class ConfigConstants { public static String getPdfPrintDisable() { return pdfPrintDisable; } + @Value("${pdf.print.disable:true}") public void setPdfPrintDisable(String pdfPrintDisable) { setPdfPrintDisableValue(pdfPrintDisable); } + public static void setPdfPrintDisableValue(String pdfPrintDisable) { ConfigConstants.pdfPrintDisable = pdfPrintDisable; } @@ -313,6 +371,7 @@ public class ConfigConstants { public void setPdfDownloadDisable(String pdfDownloadDisable) { setPdfDownloadDisableValue(pdfDownloadDisable); } + public static void setPdfDownloadDisableValue(String pdfDownloadDisable) { ConfigConstants.pdfDownloadDisable = pdfDownloadDisable; } @@ -320,10 +379,12 @@ public class ConfigConstants { public static String getPdfBookmarkDisable() { return pdfBookmarkDisable; } + @Value("${pdf.bookmark.disable:true}") public void setPdfBookmarkDisable(String pdfBookmarkDisable) { setPdfBookmarkDisableValue(pdfBookmarkDisable); } + public static void setPdfBookmarkDisableValue(String pdfBookmarkDisable) { ConfigConstants.pdfBookmarkDisable = pdfBookmarkDisable; } @@ -331,10 +392,12 @@ public class ConfigConstants { public static String getOfficePreviewSwitchDisabled() { return officePreviewSwitchDisabled; } + @Value("${office.preview.switch.disabled:true}") public void setOfficePreviewSwitchDisabled(String officePreviewSwitchDisabled) { ConfigConstants.officePreviewSwitchDisabled = officePreviewSwitchDisabled; } + public static void setOfficePreviewSwitchDisabledValue(String officePreviewSwitchDisabled) { ConfigConstants.officePreviewSwitchDisabled = officePreviewSwitchDisabled; } @@ -369,16 +432,20 @@ public class ConfigConstants { public static String getBeiAn() { return beiAn; } + @Value("${beiAn:无}") public void setBeiAn(String beiAn) { setBeiAnValue(beiAn); } + public static void setBeiAnValue(String beiAn) { ConfigConstants.beiAn = beiAn; } + public static String[] getProhibit() { return prohibit; } + @Value("${prohibit:exe,dll}") public void setProhibit(String prohibit) { String[] prohibitArr = prohibit.split(","); @@ -388,13 +455,16 @@ public class ConfigConstants { public static void setProhibitValue(String[] prohibit) { ConfigConstants.prohibit = prohibit; } + public static String maxSize() { return size; } + @Value("${spring.servlet.multipart.max-file-size:500MB}") public void setSize(String size) { setSizeValue(size); } + public static void setSizeValue(String size) { ConfigConstants.size = size; } @@ -402,10 +472,12 @@ public class ConfigConstants { public static String getPassword() { return password; } + @Value("${sc.password:123456}") public void setPassword(String password) { setPasswordValue(password); } + public static void setPasswordValue(String password) { ConfigConstants.password = password; } @@ -414,10 +486,12 @@ public class ConfigConstants { public static int getPdf2JpgDpi() { return pdf2JpgDpi; } + @Value("${pdf.picture.size:105}") public void pdf2JpgDpi(int pdf2JpgDpi) { setPdf2JpgDpiValue(pdf2JpgDpi); } + public static void setPdf2JpgDpiValue(int pdf2JpgDpi) { ConfigConstants.pdf2JpgDpi = pdf2JpgDpi; } diff --git a/server/src/main/java/cn/keking/exception/CallBackException.java b/server/src/main/java/cn/keking/exception/CallBackException.java new file mode 100644 index 0000000000000000000000000000000000000000..08c78dc10bf5008593f6d41c489fc33b636599e1 --- /dev/null +++ b/server/src/main/java/cn/keking/exception/CallBackException.java @@ -0,0 +1,4 @@ +package cn.keking.exception; + +public class CallBackException extends RuntimeException{ +} diff --git a/server/src/main/java/cn/keking/service/FileConvertQueueTask.java b/server/src/main/java/cn/keking/service/FileConvertQueueTask.java index e5d6248535ae28b75fb4d07e779c58333a8f9edc..d86b89a2428cad9327b9c7d75121f02764fd130e 100644 --- a/server/src/main/java/cn/keking/service/FileConvertQueueTask.java +++ b/server/src/main/java/cn/keking/service/FileConvertQueueTask.java @@ -1,8 +1,11 @@ package cn.keking.service; +import cn.keking.exception.CallBackException; import cn.keking.model.FileAttribute; import cn.keking.model.FileType; import cn.keking.service.cache.CacheService; +import cn.keking.utils.HttpUtils; +import com.alibaba.fastjson.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; @@ -58,6 +61,11 @@ public class FileConvertQueueTask { try { url = cacheService.takeQueueTask(); if (url != null) { + String callbackUrl = null; + if (url.contains("callbackUrl")) { + callbackUrl = url.split("callbackUrl")[1]; + url = url.split("callbackUrl")[0]; + } FileAttribute fileAttribute = fileHandlerService.getFileAttribute(url, null); FileType fileType = fileAttribute.getType(); logger.info("正在处理预览转换任务,url:{},预览类型:{}", url, fileType); @@ -67,6 +75,8 @@ public class FileConvertQueueTask { } else { logger.info("预览类型无需处理,url:{},预览类型:{}", url, fileType); } + String finalCallbackUrl = callbackUrl; + new Thread(() -> callback(finalCallbackUrl)).start(); } } catch (Exception e) { try { @@ -80,9 +90,34 @@ public class FileConvertQueueTask { } } - public boolean isNeedConvert(FileType fileType) { - return fileType.equals(FileType.COMPRESS) || fileType.equals(FileType.OFFICE) || fileType.equals(FileType.CAD); + private void callback(String callbackUrl) { + if (null != callbackUrl && !callbackUrl.equals("")) { + //http回调通知 + try { + JSONObject jsonObject = HttpUtils.sendGet(callbackUrl); + if (null != jsonObject && jsonObject.getInteger("code") == 200) { + logger.info("成功回调通知地址:" + callbackUrl); + } else { + logger.error("失败回调通知地址:" + callbackUrl); + } + } catch (CallBackException e) { + try { + Thread.sleep(1000 * 10); + } catch (InterruptedException ex) { + throw new RuntimeException(ex); + } + JSONObject jsonObject1 = HttpUtils.sendGet(callbackUrl); + if (null != jsonObject1 && jsonObject1.getInteger("code") == 200) { + logger.info("成功回调通知地址:" + callbackUrl); + } else { + logger.error("失败回调通知地址:" + callbackUrl); + } + } + } + } + public boolean isNeedConvert(FileType fileType) { + return fileType.equals(FileType.COMPRESS) || fileType.equals(FileType.PDF) || fileType.equals(FileType.OFFICE) || fileType.equals(FileType.CAD); } } diff --git a/server/src/main/java/cn/keking/utils/HttpUtils.java b/server/src/main/java/cn/keking/utils/HttpUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..8e5ad3605ec997e88f88953b88e8fb79915f8140 --- /dev/null +++ b/server/src/main/java/cn/keking/utils/HttpUtils.java @@ -0,0 +1,51 @@ +package cn.keking.utils; + +import cn.keking.exception.CallBackException; +import com.alibaba.fastjson.JSONObject; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.utils.URIBuilder; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.util.EntityUtils; + +import java.io.IOException; + +/** + * @ClassName: HttpUtils + * @Description: + * @Author: wangf + * @Date: 2019/11/12 0012 14:38 + * @Version: 1.0 + **/ + +public class HttpUtils { + + /** + * 发送HttpGet请求 + * + * @param url + * @return */ + public static JSONObject sendGet(String url) { + CloseableHttpClient client = HttpClientBuilder.create().build(); + URIBuilder uriBuilder = null; + CloseableHttpResponse response = null; + String data = ""; + try { + uriBuilder = new URIBuilder(url); + response = client.execute(new HttpGet(uriBuilder.build())); + data = EntityUtils.toString(response.getEntity()); + }catch (Exception e){ + throw new CallBackException(); + }finally { + if (response != null) { + try { + response.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + return JSONObject.parseObject(data); + } +} diff --git a/server/src/main/java/cn/keking/web/controller/OnlinePreviewController.java b/server/src/main/java/cn/keking/web/controller/OnlinePreviewController.java index ba11e2168e631a5722ab3aba329456dff7248b9c..3a8a7b198670cc136811c1b7e1d13c721c9147e3 100644 --- a/server/src/main/java/cn/keking/web/controller/OnlinePreviewController.java +++ b/server/src/main/java/cn/keking/web/controller/OnlinePreviewController.java @@ -1,5 +1,6 @@ package cn.keking.web.controller; +import cn.keking.config.ConfigConstants; import cn.keking.model.FileAttribute; import cn.keking.service.FileHandlerService; import cn.keking.service.FilePreview; @@ -17,6 +18,7 @@ import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import javax.servlet.http.HttpServletRequest; @@ -51,11 +53,23 @@ public class OnlinePreviewController { this.otherFilePreview = otherFilePreview; } - @GetMapping( "/onlinePreview") + @GetMapping("/onlinePreview") public String onlinePreview(String url, Model model, HttpServletRequest req) { String fileUrl; try { fileUrl = WebUtils.decodeUrl(url); + assert fileUrl != null; + String huanjing = req.getParameter("Huanjing"); + if (null != huanjing && fileUrl.contains("http")){ + // 判断环境 + String[] split = fileUrl.split("lc-data"); + if (huanjing.equals("office")) { + fileUrl = ConfigConstants.getBaseFileUrlOffice()+"/lc-data"+split[1]; + } + if (huanjing.equals("out")) { + fileUrl = ConfigConstants.getBaseFileUrlOut()+"/lc-data"+split[1]; + } + } } catch (Exception ex) { String errorMsg = String.format(BASE64_DECODE_ERROR_MSG, "url"); return otherFilePreview.notSupportedFile(model, errorMsg); @@ -67,7 +81,7 @@ public class OnlinePreviewController { return filePreview.filePreviewHandle(fileUrl, model, fileAttribute); } - @GetMapping( "/picturesPreview") + @GetMapping("/picturesPreview") public String picturesPreview(String urls, Model model, HttpServletRequest req) { String fileUrls; try { @@ -86,7 +100,7 @@ public class OnlinePreviewController { String currentUrl = req.getParameter("currentUrl"); if (StringUtils.hasText(currentUrl)) { String decodedCurrentUrl = new String(Base64.decodeBase64(currentUrl)); - decodedCurrentUrl = KkFileUtils.htmlEscape(decodedCurrentUrl); // 防止XSS攻击 + decodedCurrentUrl = KkFileUtils.htmlEscape(decodedCurrentUrl); // 防止XSS攻击 model.addAttribute("currentUrl", decodedCurrentUrl); } else { model.addAttribute("currentUrl", imgUrls.get(0)); @@ -106,7 +120,7 @@ public class OnlinePreviewController { try { urlPath = WebUtils.decodeUrl(urlPath); } catch (Exception ex) { - logger.error(String.format(BASE64_DECODE_ERROR_MSG, urlPath),ex); + logger.error(String.format(BASE64_DECODE_ERROR_MSG, urlPath), ex); return; } HttpURLConnection urlcon; @@ -116,46 +130,46 @@ public class OnlinePreviewController { return; } logger.info("下载跨域pdf文件url:{}", urlPath); - if (!urlPath.toLowerCase().startsWith("ftp:")){ + if (!urlPath.toLowerCase().startsWith("ftp:")) { try { URL url = WebUtils.normalizedURL(urlPath); - urlcon=(HttpURLConnection)url.openConnection(); + urlcon = (HttpURLConnection) url.openConnection(); urlcon.setConnectTimeout(30000); urlcon.setReadTimeout(30000); urlcon.setInstanceFollowRedirects(false); if (urlcon.getResponseCode() == 302 || urlcon.getResponseCode() == 301) { urlcon.disconnect(); - url =new URL(urlcon.getHeaderField("Location")); - urlcon=(HttpURLConnection)url.openConnection(); + url = new URL(urlcon.getHeaderField("Location")); + urlcon = (HttpURLConnection) url.openConnection(); } - if (urlcon.getResponseCode() == 404 || urlcon.getResponseCode() == 403 || urlcon.getResponseCode() == 500 ) { + if (urlcon.getResponseCode() == 404 || urlcon.getResponseCode() == 403 || urlcon.getResponseCode() == 500) { logger.error("读取跨域文件异常,url:{}", urlPath); - return ; + return; } else { - if(urlPath.contains( ".svg")) { + if (urlPath.contains(".svg")) { response.setContentType("image/svg+xml"); } - inputStream=(url).openStream(); + inputStream = (url).openStream(); IOUtils.copy(inputStream, response.getOutputStream()); urlcon.disconnect(); } } catch (IOException | GalimatiasParseException e) { logger.error("读取跨域文件异常,url:{}", urlPath); - return ; + return; } finally { IOUtils.closeQuietly(inputStream); } } else { try { URL url = WebUtils.normalizedURL(urlPath); - if(urlPath.contains(".svg")) { + if (urlPath.contains(".svg")) { response.setContentType("image/svg+xml"); } inputStream = (url).openStream(); IOUtils.copy(inputStream, response.getOutputStream()); } catch (IOException | GalimatiasParseException e) { logger.error("读取跨域文件异常,url:{}", urlPath); - return ; + return; } finally { IOUtils.closeQuietly(inputStream); } @@ -169,9 +183,14 @@ public class OnlinePreviewController { */ @GetMapping("/addTask") @ResponseBody - public String addQueueTask(String url) { + public String addQueueTask(@RequestParam("url") String url, @RequestParam(value = "callbackUrl", required = false) String callbackUrl) { logger.info("添加转码队列url:{}", url); - cacheService.addQueueTask(url); + logger.info("回调通知url:{}", callbackUrl); + if (null != callbackUrl&&!callbackUrl.equals("")) { + cacheService.addQueueTask(url + "callbackUrl" + callbackUrl); + } else { + cacheService.addQueueTask(url); + } return "success"; } } diff --git a/server/src/main/java/cn/keking/web/filter/BaseUrlFilter.java b/server/src/main/java/cn/keking/web/filter/BaseUrlFilter.java index 96828fd90d00a49d9b31375ace15038f20b23a97..6f188261f4bd789e8ce28a1c5de3fc3d2bc09794 100644 --- a/server/src/main/java/cn/keking/web/filter/BaseUrlFilter.java +++ b/server/src/main/java/cn/keking/web/filter/BaseUrlFilter.java @@ -39,6 +39,14 @@ public class BaseUrlFilter implements Filter { String configBaseUrl = ConfigConstants.getBaseUrl(); final HttpServletRequest servletRequest = (HttpServletRequest) request; + // 判断环境 + String huanjing = servletRequest.getParameter("Huanjing"); + if (null != huanjing && huanjing.equals("office")) { + configBaseUrl = ConfigConstants.getBaseUrlOffice(); + } + if (null != huanjing && huanjing.equals("out")) { + configBaseUrl = ConfigConstants.getBaseUrlOut(); + } //1、支持通过 http header 中 X-Base-Url 来动态设置 baseUrl 以支持多个域名/项目的共享使用 final String urlInHeader = servletRequest.getHeader("X-Base-Url"); if (StringUtils.isNotEmpty(urlInHeader)) {