commit 89028fb9298a306f290db83419ccbf051ad370f6 Author: pioneer Date: Tue Dec 6 16:19:45 2022 +0800 open diff --git a/README.md b/README.md new file mode 100644 index 0000000..e7e3445 --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +# open-JSD-10259 + +JSD-10259 预览以及打印时调用客户接口返回图片作为公章水印;及导出支持txt\ +免责说明:该源码为第三方爱好者提供,不保证源码和方案的可靠性,也不提供任何形式的源码教学指导和协助!\ +仅作为开发者学习参考使用!禁止用于任何商业用途!\ +为保护开发者隐私,开发者信息已隐去!若原开发者希望公开自己的信息,可联系【pioneer】处理。 \ No newline at end of file diff --git a/lib/commons-logging-1.2.jar b/lib/commons-logging-1.2.jar new file mode 100644 index 0000000..93a3b9f Binary files /dev/null and b/lib/commons-logging-1.2.jar differ diff --git a/lib/finekit-10.0.jar b/lib/finekit-10.0.jar new file mode 100644 index 0000000..19d504a Binary files /dev/null and b/lib/finekit-10.0.jar differ diff --git a/lib/fontbox-2.0.26.jar b/lib/fontbox-2.0.26.jar new file mode 100644 index 0000000..cd7eb49 Binary files /dev/null and b/lib/fontbox-2.0.26.jar differ diff --git a/lib/pdfbox-2.0.26.jar b/lib/pdfbox-2.0.26.jar new file mode 100644 index 0000000..1beb91a Binary files /dev/null and b/lib/pdfbox-2.0.26.jar differ diff --git a/plugin.xml b/plugin.xml new file mode 100644 index 0000000..2cd3e1b --- /dev/null +++ b/plugin.xml @@ -0,0 +1,33 @@ + + com.fr.plugin.third.party.jsdbacfj + + yes + 1.0.26 + 10.0 + 2019-01-01 + fr.open + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/third/party/jsdbacfj/OutputPluginLifecycleMonitor.java b/src/main/java/com/fr/plugin/third/party/jsdbacfj/OutputPluginLifecycleMonitor.java new file mode 100644 index 0000000..7b09b96 --- /dev/null +++ b/src/main/java/com/fr/plugin/third/party/jsdbacfj/OutputPluginLifecycleMonitor.java @@ -0,0 +1,28 @@ +package com.fr.plugin.third.party.jsdbacfj; + +import com.fr.intelli.record.Focus; +import com.fr.intelli.record.Original; +import com.fr.plugin.context.PluginContext; +import com.fr.plugin.observer.inner.AbstractPluginLifecycleMonitor; +import com.fr.plugin.third.party.jsdbacfj.config.CustomDataConfig; +import com.fr.plugin.third.party.jsdbacfj.export.TxtIconLoader; +import com.fr.record.analyzer.EnableMetrics; +import com.fr.stable.fun.Authorize; + + +/** + * 配置信息初始化 + */ +@EnableMetrics +public class OutputPluginLifecycleMonitor extends AbstractPluginLifecycleMonitor { + @Override + @Focus(id = "com.fr.plugin.third.party.jsdbacfj", text = "plugin-jsdbacfj", source = Original.PLUGIN) + public void afterRun(PluginContext pluginContext) { + CustomDataConfig.getInstance(); + TxtIconLoader.loadIcon(); + } + + @Override + public void beforeStop(PluginContext pluginContext) { + } +} diff --git a/src/main/java/com/fr/plugin/third/party/jsdbacfj/StampUtils.java b/src/main/java/com/fr/plugin/third/party/jsdbacfj/StampUtils.java new file mode 100644 index 0000000..ff049e2 --- /dev/null +++ b/src/main/java/com/fr/plugin/third/party/jsdbacfj/StampUtils.java @@ -0,0 +1,754 @@ +package com.fr.plugin.third.party.jsdbacfj; + +import com.fanruan.api.log.LogKit; +import com.fanruan.api.util.StringKit; +import com.fr.base.Base64; +import com.fr.data.NetworkHelper; +import com.fr.file.CacheManager; +import com.fr.general.ReportDeclareRecordType; +import com.fr.io.exporter.PDFEmbExporter; +import com.fr.io.exporter.PDFExporterForPrint; +import com.fr.json.JSONArray; +import com.fr.json.JSONObject; +import com.fr.log.LogUtils; +import com.fr.page.PageSetProvider; +import com.fr.plugin.context.PluginContexts; +import com.fr.plugin.third.party.jsdbacfj.config.CustomDataConfig; +import com.fr.report.ReportContext; +import com.fr.report.controller.PrintOffsetController; +import com.fr.report.entity.PrintOffsetEntity; +import com.fr.report.print.PrintOffsetSign; +import com.fr.report.print.TypeIP; +import com.fr.stable.StringUtils; +import com.fr.stable.web.SessionProvider; +import com.fr.third.org.apache.commons.io.FileUtils; +import com.fr.third.org.apache.commons.lang3.time.DateFormatUtils; +import com.fr.third.org.apache.http.impl.client.CloseableHttpClient; +import com.fr.web.core.ReportRepositoryDeal; +import com.fr.web.core.ReportSessionIDInfor; +import com.fr.web.core.SessionPoolManager; +import com.fr.web.utils.WebUtils; +import org.apache.pdfbox.cos.COSName; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.PDPageContentStream; +import org.apache.pdfbox.pdmodel.common.PDRectangle; +import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject; +import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState; + +import javax.servlet.FilterChain; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.*; +import java.math.BigDecimal; +import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.WritableByteChannel; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +public class StampUtils { + public static String getImgBase64() { + String stampBase64 = getStampBase64(); + if (StringKit.isEmpty(stampBase64)) { + return ""; + } + String dataBase64 = "data:image/png;base64," + stampBase64; + return dataBase64; + } + + public static String getStampBase64() { + return getStampBase64("012101"); + } + + public static String getStampBase64(String orgId) { + try { + + String temp = ""; + if (StringKit.isNotEmpty(temp)) { + return temp; + } + + String url = CustomDataConfig.getInstance().getStampEsbUrl(); + if (StringKit.isEmpty(url)) { + return ""; + } + + if (StringKit.isEmpty(orgId)) { + orgId = "012101"; + } + + String bodyContent = "{\"sysHead\":\n" + + "{\"userLang\":\"CHINESE\",\n" + + "\"svcCd\":\"xx\",\n" + + "\"scnCd\":\"xx\",\n" + + "\"cnsmSysId\":\"xx\",\n" + + "\"subSeqNo\":\"" + getId() + "\",\n" + + "\"seqNo\":\"" + getId() + "\",\n" + + "\"tranMode\":\"xx\",\n" + + "\"systemId\":\"xx\",\n" + + "\"tranDate\":\"" + getcurrentDate() + "\",\n" + + "\"tranTimestamp\":\"" + getcurrentTimeStamp() + "\",\n" + + "\"fileFlg\":\"0\",\n" + + "\"userId\":\"\",\n" + + "\"branchId\":\"\",\n" + + "\"company\":\"\",\n" + + "\"sourceBranchNo\":\"\",\n" + + "\"apprUserId\":\"\",\n" + + "\"macValue\":\"\",\n" + + "\"srcSysTmnlNo\":\"\",\n" + + "\"srcSysSvrId\":\"\",\n" + + "\"filePath\":\"\",\n" + + "\"authFlag\":\"\",\n" + + "\"apprFlag\":\"\",\n" + + "\"cnsmSysSvrId\":\"\",\n" + + "\"destBranchNo\":\"\",\n" + + "\"tmnIdNo\":\"\",\n" + + "\"sourceType\":\"\",\n" + + "\"authUserId\":\"\",\n" + + "\"programId\":\"\"\n" + + "},\n" + + "\"appHead\": {},\n" + + "\"body\": {\n" + + "\"tranCd\": \"xx\",\n" + + "\"chnlNo\": \"xxx\",\n" + + "\"subBnkNo\": \"xxx\",\n" + + "\"brNo\": \"xxx." + orgId + "\",\n" + + "\"tlrNo\": \"xxx\",\n" + + "\"bsnDt\": \"" + getcurrentDate() + "\",\n" + + "\"bsnTm\": \"" + getcurrentTime() + "\",\n" + + "\"chnlSeqNo\": \"" + getId() + "\",\n" + + "\"mvmtBsnData\": \"\",\n" + + "\"stmpId\": \"xx\"\n" + + "}\n" + + "}"; + + LogKit.info("印章集成,请求链接:" + url); + LogKit.info("印章集成,请求内容:\n" + bodyContent); + + + CloseableHttpClient httpClient = Utils.createHttpClient(url); + String resBodyContent = Utils.createHttpPostContent(httpClient, url, bodyContent, "", "application/json;charset=UTF-8"); + httpClient.close(); + if (StringKit.isEmpty(resBodyContent)) { + return ""; + } + LogKit.info("印章集成,响应内容:\n" + resBodyContent); + + + JSONObject jsonObject = new JSONObject(resBodyContent); + if (!jsonObject.containsKey("body")) { + return ""; + } + JSONObject bodyJson = jsonObject.getJSONObject("body"); + if (!bodyJson.containsKey("stmpImgCntnt")) { + return ""; + } + String base64Content = bodyJson.getString("stmpImgCntnt"); + if (StringKit.isEmpty(base64Content)) { + return ""; + } + return base64Content; + } catch (Exception e) { + LogKit.info("印章集成,获取印章出错," + e.getMessage(), e); + } + return ""; + } + + private static String getId() { + String value = "ORSJ" + DateFormatUtils.format(System.currentTimeMillis(), "yyyyMMddHHmmssSSS"); + return value; + } + + private static String getcurrentDate() { + String value = DateFormatUtils.format(System.currentTimeMillis(), "yyyyMMdd"); + return value; + } + + private static String getcurrentTime() { + String value = DateFormatUtils.format(System.currentTimeMillis(), "HHmmss"); + return value; + } + + private static String getcurrentTimeStamp() { + String value = DateFormatUtils.format(System.currentTimeMillis(), "HHmmssSSS"); + return value; + } + + + public static Set getStampReportNames() { + Set names = new HashSet<>(); + String content = StringKit.trim(CustomDataConfig.getInstance().getStampReportName()); + if (StringKit.isEmpty(content)) { + return names; + } + String[] tempNames = content.split(","); + if ((tempNames == null) || (tempNames.length <= 0)) { + return names; + } + + String tempName; + for (int i = 0, max = tempNames.length - 1; i <= max; i++) { + tempName = StringKit.trim(tempNames[i]); + if (StringKit.isEmpty(content)) { + continue; + } + names.add(tempName); + } + return names; + } + + public static boolean isStampReport(String path) { + if (StringKit.isEmpty(path)) { + return false; + } + Set tempNames = getStampReportNames(); + if (tempNames.size() <= 0) { + return false; + } + if (tempNames.contains(path)) { + return true; + } + return false; + } + + public static boolean isNotStampReport(String path) { + return !isStampReport(path); + } + + //[{reportlet: '印章测试/垫款-保证.cpt', orgId:123456}] + //FR.doURLPDFPrint + public static boolean isDoURLPDFPrint(String path) { + if (StringKit.isEmpty(path)) { + return false; + } + try { + JSONArray jsons = new JSONArray(path); + if ((jsons == null) || (jsons.size() <= 0)) { + return false; + } + JSONObject json = jsons.getJSONObject(0); + if (!json.containsKey("reportlet")) { + return false; + } + } catch (Exception e) { + return false; + } + return true; + } + + public static boolean isNotDoURLPDFPrint(String path) { + return !isDoURLPDFPrint(path); + } + + public static String getOrgIdByDoURLPDFPrint(String path) { + if (isNotDoURLPDFPrint(path)) { + return ""; + } + JSONArray jsons = new JSONArray(path); + if ((jsons == null) || (jsons.size() <= 0)) { + return ""; + } + JSONObject json = jsons.getJSONObject(0); + String orgId = json.getString("orgId", ""); + return orgId; + } + + public static final String TEMP_DIRECTORY_NAME = "jsdbacfj-export-temp"; + + + /** + * 获取临时目录 + * + * @return + */ + public static String getTempDirectory() { + File file = new File(CacheManager.getProviderInstance().getCacheDirectory(), TEMP_DIRECTORY_NAME); + return file.getAbsolutePath(); + } + + + /** + * 获取临时导出目录 + * + * @return + */ + public static String getTempExportPath() { + String path = UUID.randomUUID().toString(); + File file = new File(getTempDirectory(), path); + return file.getAbsolutePath(); + } + + /** + * 删除临时目录 + */ + public static void deleteTempDirectory() throws IOException { + deleteFile(getTempDirectory()); + } + + /** + * jvm退出时删除临时目录 + */ + public static void deleteTempDirectoryByShutdownHook() { + Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { + @Override + public void run() { + try { + LogKit.info("Delete temporary directory on Shutdown"); + deleteTempDirectory(); + } catch (IOException e) { + LogKit.error("Delete temporary directory on Shutdown," + e.getMessage()); + } + } + }) { + }); + } + + + /** + * 删除文件 + * + * @param target + * @throws IOException + */ + public static void deleteFile(String target) throws IOException { + deleteFile(Paths.get(target)); + } + + /** + * 删除文件 + * + * @param target + * @throws IOException + */ + public static void deleteFile(Path target) throws IOException { + if (Files.isDirectory(target)) { + FileUtils.deleteDirectory(target.toFile()); + return; + } + Files.deleteIfExists(target); + } + + /** + * 复制流 + * + * @param inputStream + * @param outputStream + * @throws IOException + */ + public static void copyStreamByNio(InputStream inputStream, OutputStream outputStream) throws IOException { + int bufferSize = 10485760;//1024 * 1024 * 10; + ReadableByteChannel input = Channels.newChannel(inputStream); + WritableByteChannel output = Channels.newChannel(outputStream); + ByteBuffer byteBuffer = ByteBuffer.allocate(bufferSize); + while ((input.read(byteBuffer)) != -1) { + //切换读取模式 + byteBuffer.flip(); + output.write(byteBuffer); + byteBuffer.clear(); + } + input.close(); + outputStream.flush(); + outputStream.close(); + } + + + /** + * 判断是否是打印请求,需要加上印章 + * + * @param req + * @return + */ + public static boolean isAddStamp(HttpServletRequest req) { + if (req == null) { + return false; + } + String method = req.getMethod(); + if (!"GET".equalsIgnoreCase(method)) { + return false; + } + + String reqUrl = req.getRequestURL().toString(); + if (!reqUrl.endsWith("/decision/view/report")) { + return false; + } + String op = WebUtils.getHTTPRequestParameter(req, "op"); + if (!"fr_pdfprint".equals(op)) { + return false; + } + + String cmd = WebUtils.getHTTPRequestParameter(req, "cmd"); + if (!"native".equals(cmd)) { + return false; + } + + String sessionID = WebUtils.getHTTPRequestParameter(req, "sessionID"); + if (StringKit.isEmpty(sessionID)) { + return false; + } + + ReportSessionIDInfor reportSessionIDInfor = SessionPoolManager.getSessionIDInfor(sessionID, ReportSessionIDInfor.class); + if (reportSessionIDInfor == null) { + return false; + } + + String relativePath = reportSessionIDInfor.getRelativePath(); + if (isStampFlag(reportSessionIDInfor) || StampUtils.isStampReport(relativePath) || StampUtils.isDoURLPDFPrint(relativePath)) { + return true; + } + return false; + } + + public static boolean isStampFlag(ReportSessionIDInfor reportSessionIDInfor) { + if (reportSessionIDInfor == null) { + return false; + } + Object value = reportSessionIDInfor.getParameterValue("STAMP"); + if (value == null) { + return false; + } + if ("1".equals(value)) { + return true; + } + return false; + } + + public static String getOrgIdByReportSessionIDInfor(ReportSessionIDInfor reportSessionIDInfor) { + if (!isStampFlag(reportSessionIDInfor)) { + return ""; + } + Object value = reportSessionIDInfor.getParameterValue("ORGID"); + if (value == null) { + return ""; + } + String orgId = String.valueOf(value); + return orgId; + } + + public static void addStamp(HttpServletRequest req, HttpServletResponse res, FilterChain filterChain) throws Exception { + if (!PluginContexts.currentContext().isAvailable()) { + LogKit.error("印章集成插件试用过期, 请添加许可证"); + filterChain.doFilter(req, res); + return; + } + + + String sessionID = WebUtils.getHTTPRequestParameter(req, "sessionID"); + ReportSessionIDInfor reportSessionIDInfor = SessionPoolManager.getSessionIDInfor(sessionID, ReportSessionIDInfor.class); + if (reportSessionIDInfor == null) { + filterChain.doFilter(req, res); + return; + } + String relativePath = reportSessionIDInfor.getRelativePath(); + String orgId = StampUtils.getOrgIdByDoURLPDFPrint(relativePath); + if (StringKit.isEmpty(orgId)) { + orgId = StampUtils.getOrgIdByReportSessionIDInfor(reportSessionIDInfor); + } + String stampBase64 = StampUtils.getStampBase64(orgId); + if (StringKit.isEmpty(stampBase64)) { + filterChain.doFilter(req, res); + return; + } + + String dirPath = StampUtils.getTempExportPath(); + Path path = Paths.get(dirPath); + Files.createDirectories(path); + String filePath = dirPath + "/a.pdf"; + String filePath1 = dirPath + "/b.pdf"; + createPrintPdf(req, filePath, reportSessionIDInfor, sessionID); + addStampWithPdf(stampBase64, filePath, filePath1); + writePdfToResponse(req, res, reportSessionIDInfor, filePath1); + deleteFile(path); + } + + private static void writePdfToResponse(HttpServletRequest req, HttpServletResponse res, ReportSessionIDInfor reportSessionIDInfor, String pdfPath) throws IOException { + addFrameOptions(req, res); + boolean previewOption = Boolean.parseBoolean(WebUtils.getHTTPRequestParameter(req, "preview")); + if (!previewOption) { + LogUtils.recordPrintInformation(reportSessionIDInfor.getRelativePath(), reportSessionIDInfor.getParameterMap4Execute4Consisent(), ReportDeclareRecordType.PRINT_TYPE_NO_CLIENT, reportSessionIDInfor); + } + writePdfToResponse(res, pdfPath); + } + + public static void writePdfToResponse(HttpServletResponse res, String pdfPath) throws IOException { + res.setContentType("application/pdf"); + ServletOutputStream servletOutputStream = res.getOutputStream(); + FileInputStream fileInputStream = new FileInputStream(pdfPath); + copyStreamByNio(fileInputStream, servletOutputStream); + } + + public static void addFrameOptions(HttpServletRequest req, HttpServletResponse res) { + String referer = req.getHeader("Referer"); + if (StringUtils.isEmpty(referer)) { + return; + } + String host = getHost(referer); + Collection headerNames = res.getHeaderNames(); + if (headerNames.contains("X-Frame-Options")) { + res.setHeader("X-Frame-Options", "ALLOW-FROM " + host); + } + } + + private static String getHost(String value) { + int index = value.indexOf("/", value.indexOf("//") + 2); + return index == -1 ? value : value.substring(0, index); + } + + private static void createPrintPdf(HttpServletRequest req, String filePath, ReportSessionIDInfor reportSessionIDInfor, String sessionID) throws Exception { + float[] offset = getOffset(reportSessionIDInfor); + reportSessionIDInfor.getPrintContext().setOffset(offset); + PageSetProvider pageSet = reportSessionIDInfor.getPrintPreviewPageSet4Traversing(); + FileOutputStream fileOutputStream = new FileOutputStream(filePath); + PDFExporterForPrint pdfExporter = new PDFExporterForPrint(); + pdfExporter.export(fileOutputStream, pageSet); + fileOutputStream.flush(); + fileOutputStream.close(); + LogUtils.recordPrintInformation(reportSessionIDInfor.getRelativePath(), reportSessionIDInfor.getParameterMap4Execute4Consisent(), ReportDeclareRecordType.PRINT_TYPE_PDF, reportSessionIDInfor); + boolean needKeepSession = NetworkHelper.getHTTPRequestBoolParameter(req, "needKeepSession"); + if (!needKeepSession) { + SessionPoolManager.closeSession(sessionID); + } + } + + + public static float[] getOffset(SessionProvider sessionIDInfor) { + return getOffset(sessionIDInfor.getWebContext().getAddress(), sessionIDInfor.getWebTitle(), new TypeIP()); + } + + + public static float[] getOffset(String remote_IP, String cptName, TypeIP type) { + try { + float[] offset = getRemoteOffset(remote_IP, type); + type.setType(PrintOffsetSign.SIGN_ALL); + PrintOffsetController controller = ReportContext.getInstance().getPrintOffsetController(); + if (controller.findOne(remote_IP, cptName, PrintOffsetSign.SIGN_SINGLE.getSign()) != null) { + type.setIP(""); + offset = getRemoteOffset(remote_IP, cptName, type); + type.setType(PrintOffsetSign.SIGN_SINGLE); + } + + return offset; + } catch (Exception e) { + LogKit.error(e.getMessage(), e); + } + type.setType(PrintOffsetSign.SIGN_NONE); + return new float[2]; + } + + + private static float[] getRemoteOffset(String remote_IP, TypeIP type) { + return getRemoteOffset(remote_IP, "", PrintOffsetSign.SIGN_ALL.getSign(), type); + } + + private static float[] getRemoteOffset(String remote_IP, String cptName, TypeIP type) { + return getRemoteOffset(remote_IP, cptName, PrintOffsetSign.SIGN_SINGLE.getSign(), type); + } + + private static float[] getRemoteOffset(String remote_IP, String cptName, String sign, TypeIP type) { + float[] offset = new float[]{0.0F, 0.0F}; + PrintOffsetController controller = ReportContext.getInstance().getPrintOffsetController(); + PrintOffsetEntity entity = controller.findOne(remote_IP, cptName, sign); + if (entity != null) { + type.setIP(entity.getIp()); + offset[0] = Float.parseFloat(entity.getOffsetX()); + offset[1] = Float.parseFloat(entity.getOffsetY()); + } + return offset; + } + + public static void addStampWithPdf111(String stampBase64, String srcFilePath, String targetFilePath) throws Exception { + PDDocument doc = PDDocument.load(new File(srcFilePath)); + + float width = getZoomValue(609f); + float height = getZoomValue(397f); + width = 182.7f; + height = 119.1f; + + byte[] stampBytes = Base64.decode(stampBase64); + PDImageXObject pdImage = PDImageXObject.createFromByteArray(doc, stampBytes, "stamp.png"); + PDExtendedGraphicsState pdExtGfxState = new PDExtendedGraphicsState(); + // 设置透明度 + pdExtGfxState.setNonStrokingAlphaConstant(getStampOpacity()); + pdExtGfxState.setAlphaSourceFlag(true); + pdExtGfxState.getCOSObject().setItem(COSName.BM, COSName.MULTIPLY); + + float configX = CustomDataConfig.getInstance().getStampPositionX(); + float configY = CustomDataConfig.getInstance().getStampPositionY(); + float x = 0; + float y = 0; + PDPage page; + PDPageContentStream contentStream; + PDRectangle rectangle; + for (int i = 0, max = doc.getNumberOfPages() - 1; i <= max; i++) { + page = doc.getPage(i); + if (i == 0) { + rectangle = page.getMediaBox(); + x = getFitValue(configX, rectangle.getWidth(), width); + y = getFitValue(configY, rectangle.getHeight(), height); + x = 300; + y = 100; + } + contentStream = new PDPageContentStream(doc, page, PDPageContentStream.AppendMode.APPEND, true, true); + contentStream.setGraphicsStateParameters(pdExtGfxState); + contentStream.drawImage(pdImage, x, y, width, height); + contentStream.close(); + } + doc.save(targetFilePath); + doc.close(); + } + + public static void addStampWithPdf(String stampBase64, String srcFilePath, String targetFilePath) throws Exception { + addStampWithPdf(stampBase64, srcFilePath, targetFilePath, -1, -1, -1, -1, -1); + } + + /** + * 在pdf上面添加印章 + * + * @param stampBase64 图片base64 + * @param srcFilePath pdf源位置 + * @param targetFilePath pdf目标位置 + * @param stampXThousandths 印章横向位置 按1000来 + * @param stampYThousandths 印章纵向位置 按1000来 + * @param stampIntervalThousandths 印章间隔 按1000来 + * @param stampWidthThousandths 印章宽 按1000来 + * @param stampHeightThousandths 印章高 按1000来 + * @throws Exception + */ + public static void addStampWithPdf(String stampBase64, String srcFilePath, String targetFilePath, int stampXThousandths, int stampYThousandths, int stampIntervalThousandths, int stampWidthThousandths, int stampHeightThousandths) throws Exception { + float defaultX = 300; + float defaultY = 100; + float defaultWidth = 182.7f; + float defaultHeight = 119.1f; + + if (StringKit.isEmpty(stampBase64)) { + return; + } + + PDDocument doc = PDDocument.load(new File(srcFilePath)); + byte[] stampBytes = Base64.decode(stampBase64); + PDImageXObject pdImage = PDImageXObject.createFromByteArray(doc, stampBytes, "stamp.png"); + PDExtendedGraphicsState pdExtGfxState = new PDExtendedGraphicsState(); + + // 设置透明度 + pdExtGfxState.setNonStrokingAlphaConstant(getStampOpacity()); + pdExtGfxState.setAlphaSourceFlag(true); + pdExtGfxState.getCOSObject().setItem(COSName.BM, COSName.MULTIPLY); + + PDPage page; + PDPageContentStream contentStream; + PDRectangle rectangle; + + + float stampX = 0, stampY = 0, stampInterval = 0; + float stampWidth = 0, stampHeight = 0; + + float pageWidth = 0; + float pageHeight = 0; + for (int i = 0, max = doc.getNumberOfPages() - 1; i <= max; i++) { + page = doc.getPage(i); + rectangle = page.getMediaBox(); + pageWidth = rectangle.getWidth(); + pageHeight = rectangle.getHeight(); + stampX = defaultX; + stampY = defaultY; + stampInterval = 0; + stampWidth = defaultWidth; + stampHeight = defaultHeight; + if (stampXThousandths >= 0) { + stampX = getRealValue(stampXThousandths, pageWidth); + } + if (stampYThousandths >= 0) { + stampY = getRealValue(stampYThousandths, pageHeight); + } + if (stampIntervalThousandths > 0) { + stampInterval = getRealValue(stampIntervalThousandths, pageHeight); + } + + if (stampWidthThousandths > 0) { + stampWidth = getRealValue(stampWidthThousandths, pageWidth); + } + if (stampHeightThousandths > 0) { + stampHeight = getRealValue(stampHeightThousandths, pageHeight); + } + + contentStream = new PDPageContentStream(doc, page, PDPageContentStream.AppendMode.APPEND, true, true); + contentStream.setGraphicsStateParameters(pdExtGfxState); + contentStream.drawImage(pdImage, stampX, stampY, stampWidth, stampHeight); + if (stampInterval > 0) { + stampY = stampY + stampInterval; + while (stampY < pageHeight) { + contentStream.drawImage(pdImage, stampX, stampY, stampWidth, stampHeight); + stampY = stampY + stampInterval; + } + } + contentStream.close(); + } + doc.save(targetFilePath); + doc.close(); + + + } + + private static float getRealValue(int thousandths, float baseValue) { + if ((thousandths <= 0) || (baseValue <= 0)) { + return 0f; + } + if (thousandths >= 1000) { + return baseValue; + } + + float value = thousandths * 0.001f * baseValue; + return value; + } + + + private static float getFitValue(float configValue, float maxValue, float blankValue) { + if (configValue <= 0) { + return 0; + } + float tempValue; + if ((configValue + blankValue) >= maxValue) { + tempValue = maxValue - blankValue; + if (tempValue <= 0) { + tempValue = 0; + } + return tempValue; + } + return configValue; + } + + private static float getZoomValue(float value) { + int zoom = CustomDataConfig.getInstance().getStampScaling(); + if (zoom <= 0) { + zoom = 20; + } + BigDecimal b = new BigDecimal(String.valueOf(value)); + b = b.multiply(new BigDecimal(String.valueOf(zoom))); + b = b.multiply(new BigDecimal("0.01")); + b = b.setScale(1, BigDecimal.ROUND_HALF_UP); + return b.floatValue(); + } + + public static float getStampOpacity() { + int value = CustomDataConfig.getInstance().getStampTransparent(); + if (value <= 0) { + value = 0; + } + if (value >= 100) { + value = 100; + } + int tempValue = 100 - value; + BigDecimal b0 = new BigDecimal(String.valueOf(tempValue)); + BigDecimal b1 = new BigDecimal("100"); + BigDecimal b2 = b0.divide(b1, 2, BigDecimal.ROUND_HALF_UP); + float opacityValue = b2.floatValue(); + return opacityValue; + } +} diff --git a/src/main/java/com/fr/plugin/third/party/jsdbacfj/Utils.java b/src/main/java/com/fr/plugin/third/party/jsdbacfj/Utils.java new file mode 100644 index 0000000..c1c5e36 --- /dev/null +++ b/src/main/java/com/fr/plugin/third/party/jsdbacfj/Utils.java @@ -0,0 +1,376 @@ +package com.fr.plugin.third.party.jsdbacfj; + +import com.fanruan.api.log.LogKit; +import com.fanruan.api.util.StringKit; +import com.fr.decision.authority.AuthorityContext; +import com.fr.decision.authority.data.Authority; +import com.fr.decision.authority.data.User; +import com.fr.decision.webservice.bean.user.UserBean; +import com.fr.decision.webservice.bean.user.UserUpdateBean; +import com.fr.decision.webservice.v10.user.UserService; +import com.fr.json.JSONObject; +import com.fr.plugin.third.party.jsdbacfj.config.CustomDataConfig; +import com.fr.stable.StringUtils; +import com.fr.third.org.apache.commons.lang3.time.DateFormatUtils; +import com.fr.third.org.apache.http.HttpEntity; +import com.fr.third.org.apache.http.HttpStatus; +import com.fr.third.org.apache.http.client.config.RequestConfig; +import com.fr.third.org.apache.http.client.methods.CloseableHttpResponse; +import com.fr.third.org.apache.http.client.methods.HttpGet; +import com.fr.third.org.apache.http.client.methods.HttpPost; +import com.fr.third.org.apache.http.conn.ssl.NoopHostnameVerifier; +import com.fr.third.org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import com.fr.third.org.apache.http.entity.StringEntity; +import com.fr.third.org.apache.http.impl.client.CloseableHttpClient; +import com.fr.third.org.apache.http.impl.client.HttpClients; +import com.fr.third.org.apache.http.ssl.SSLContextBuilder; +import com.fr.third.org.apache.http.ssl.TrustStrategy; +import com.fr.third.org.apache.http.util.EntityUtils; +import com.fr.third.springframework.web.util.UriUtils; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLContext; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class Utils { + public static String DEFAULT_USER_AGENT = "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36"; + public static RequestConfig REQUEST_CONFIG = RequestConfig.custom() + .setConnectionRequestTimeout(30000) + .setSocketTimeout(30000) // 服务端相应超时 + .setConnectTimeout(30000) // 建立socket链接超时时间 + .build(); + + public static CloseableHttpClient createSslHttpClient() { + try { + SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() { + + @Override + public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { + return true; + } + }).build(); + HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE; + SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, hostnameVerifier); + return HttpClients.custom() + .setSSLSocketFactory(sslsf) + .build(); + } catch (Exception e) { + LogKit.error(e.getMessage(), e); + } + return HttpClients.createDefault(); + } + + public static CloseableHttpClient createDefaultHttpClient() { + CloseableHttpClient httpClient = HttpClients.custom() + .build(); + return httpClient; + } + + public static synchronized CloseableHttpClient createHttpClient(String url) { + CloseableHttpClient httpClient = null; + if (StringKit.isEmpty(url)) { + httpClient = createDefaultHttpClient(); + return httpClient; + } + + if (url.startsWith("https://")) { + httpClient = createSslHttpClient(); + return httpClient; + } + httpClient = createDefaultHttpClient(); + return httpClient; + } + + public static synchronized String createHttpGetContent(CloseableHttpClient httpClient, String url, String basicAuth) throws IOException { + if ((httpClient == null) || (StringKit.isEmpty(url))) { + return ""; + } + + HttpGet httpGet = new HttpGet(url); + httpGet.addHeader("User-Agent", Utils.DEFAULT_USER_AGENT); + if (StringKit.isNotEmpty(basicAuth)) { + httpGet.addHeader("Authorization", basicAuth); + } + + httpGet.setConfig(Utils.REQUEST_CONFIG); + CloseableHttpResponse response = httpClient.execute(httpGet); + int statusCode = response.getStatusLine().getStatusCode(); + if (statusCode != HttpStatus.SC_OK) { + response.close(); + LogKit.info("http请求出错,http status:" + statusCode); + return ""; + } + + HttpEntity httpEntity = response.getEntity(); + if (httpEntity == null) { + response.close(); + LogKit.info("http请求出错,http响应内容为空"); + return ""; + } + String responseContent = EntityUtils.toString(httpEntity, "UTF-8"); + response.close(); + if (StringKit.isEmpty(responseContent)) { + LogKit.info("http请求出错,http响应内容为空1"); + return ""; + } + return responseContent; + } + + public static synchronized String createHttpPostContent(CloseableHttpClient httpClient, String url, String bodyContent, String basicAuth, String contentType) throws IOException { + if ((httpClient == null) || (StringKit.isEmpty(url))) { + return ""; + } + + HttpPost httpPost = new HttpPost(url); + httpPost.addHeader("User-Agent", Utils.DEFAULT_USER_AGENT); + httpPost.setConfig(Utils.REQUEST_CONFIG); + if (StringKit.isNotEmpty(basicAuth)) { + httpPost.addHeader("Authorization", basicAuth); + } + if (StringKit.isNotEmpty(contentType)) { + httpPost.addHeader("Content-Type", contentType); + } + StringEntity bodyEntity = new StringEntity(bodyContent, "UTF-8"); + httpPost.setEntity(bodyEntity); + CloseableHttpResponse response = httpClient.execute(httpPost); + int statusCode = response.getStatusLine().getStatusCode(); + if (statusCode != HttpStatus.SC_OK) { + response.close(); + LogKit.info("http请求出错,http status:" + statusCode); + return ""; + } + + HttpEntity httpEntity = response.getEntity(); + if (httpEntity == null) { + response.close(); + LogKit.info("http请求出错,http响应内容为空"); + return ""; + } + String responseContent = EntityUtils.toString(httpEntity, "UTF-8"); + response.close(); + if (StringKit.isEmpty(responseContent)) { + LogKit.info("http请求出错,http响应内容为空1"); + return ""; + } + return responseContent; + } + + + /** + * 获取完整请求链接 + * + * @param req 请求 + * @return + */ + public static String getFullRequestUrl(HttpServletRequest req) { + if (req == null) { + return ""; + } + String url = req.getRequestURL().toString(); + String queryUrl = req.getQueryString(); + if ((queryUrl == null) || "null".equalsIgnoreCase(queryUrl)) { + queryUrl = ""; + } else { + queryUrl = "?" + queryUrl; + } + String fullUrl = url + queryUrl; + return fullUrl; + } + + + /** + * 重定向 + * + * @param res + * @param url + */ + public static void sendRedirect(HttpServletResponse res, String url) { + if ((res == null) || (StringKit.isEmpty(url))) { + return; + } + res.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); + res.setHeader("Location", url); + } + + + public static synchronized String getUuid() { + String uuid = UUID.randomUUID().toString().replace("-", ""); + return uuid; + } + + + /** + * 获取用户信息 + * + * @param userCount 用户数,-1为不限制用户数 + * @param isAdminContained 是否包含管理员用户 + * @return + * @throws Exception + */ + public static List getAllUsers(int userCount, boolean isAdminContained) throws Exception { + List userBeans = new ArrayList<>(); + + return userBeans; + } + + + /** + * 获取不包含管理员的用户信息 + * + * @param userCount + * @return + * @throws Exception + */ + public static List getAllUsersWithoutAdmin(int userCount) throws Exception { + return getAllUsers(userCount, false); + } + + public static List getAllUserNames(int userCount, boolean isAdminContained) throws Exception { + List userNames = new ArrayList<>(); + List userBeans = getAllUsers(userCount, isAdminContained); + UserBean userBean; + for (int i = 0, max = userBeans.size() - 1; i <= max; i++) { + userBean = userBeans.get(i); + userNames.add(userBean.getUsername()); + } + return userNames; + } + + public static List getAllUserNamesWithoutAdmin(int userCount) throws Exception { + return getAllUserNames(userCount, false); + } + + /** + * 通过用户名删除用户,管理员用户无法删除 + * + * @param username 用户名 + * @return + * @throws Exception + */ + public static int deleteUsersByUsername(String username) throws Exception { + if (StringUtils.isEmpty(username)) { + return 0; + } + User user = UserService.getInstance().getUserByUserName(username); + if (user == null) { + return 0; + } + String userId = user.getId(); + List adminUserIds = UserService.getInstance().getAdminUserIdList(); + if ((adminUserIds != null) && (adminUserIds.size() >= 1) && (adminUserIds.contains(userId))) { + return 0; + } + UserUpdateBean userUpdateBean = new UserUpdateBean(); + userUpdateBean.setRemoveUserIds(new String[]{userId}); + return UserService.getInstance().deleteUsers(userUpdateBean); + } + + public static int deleteUsersByUsernames(List usernames) throws Exception { + if ((usernames == null) || (usernames.size() <= 0)) { + return 0; + } + String username; + int totalCount = 0, count; + for (int i = 0, max = usernames.size() - 1; i <= max; i++) { + username = usernames.get(i); + count = deleteUsersByUsername(username); + totalCount = totalCount + count; + } + return totalCount; + } + + public static void editRealNameByUsername(String username, String realName) throws Exception { + if (StringUtils.isEmpty(username) || StringUtils.isEmpty(realName)) { + return; + } + User user = UserService.getInstance().getUserByUserName(username); + if (user == null) { + return; + } + UserBean userBean = new UserBean(user.getEmail(), user.isEnable(), user.getMobile(), realName, user.getUserName(), user.getId()); + UserService.getInstance().editAccount(username, userBean); + } + + /** + * 根据链接获取报表路径 + * + * @param url + * @return + */ + public static String getReportPathByUrl(String url) { + if (StringKit.isEmpty(url)) { + return ""; + } + String reportPath = ""; + try { + reportPath = getReportPathWithViewletValueByUrl(url); + if (StringKit.isEmpty(reportPath)) { + reportPath = getReportPathWithEntryIdByUrl(url); + } + } catch (Exception e) { + LogKit.error("根据链接获取报表路径出错," + e.getMessage(), e); + return ""; + } + return reportPath; + } + + private static String getReportPathWithViewletValueByUrl(String url) throws UnsupportedEncodingException { + if (StringKit.isEmpty(url)) { + return ""; + } + int index = url.indexOf("viewlet="); + if (index < 0) { + return ""; + } + int index1 = url.indexOf("&", index); + String tempValue = ""; + if (index1 >= 0) { + tempValue = url.substring(index + "viewlet=".length(), index1); + } else { + tempValue = url.substring(index + "viewlet=".length()); + } + if (StringKit.isEmpty(tempValue)) { + return ""; + } + String reportName = UriUtils.decode(UriUtils.decode(tempValue, "UTF-8"), "UTF-8"); + return reportName; + } + + private static String getReportPathWithEntryIdByUrl(String url) throws Exception { + //http://localhost:8075/webroot/decision/v10/entry/access/7bfe66ce-8c24-4c9a-8426-f814fb195a89?width=389&height=866 + if (StringKit.isEmpty(url)) { + return ""; + } + String tempStr = "decision/v10/entry/access/"; + int index = url.indexOf(tempStr); + if (index <= 0) { + return ""; + } + String tempUrl = url.substring(index + tempStr.length()); + String entryId = ""; + index = tempUrl.indexOf("?"); + if (index >= 0) { + entryId = tempUrl.substring(0, index); + } else { + entryId = tempUrl; + } + Authority entry = AuthorityContext.getInstance().getAuthorityController().getById(entryId); + if (entry == null) { + return ""; + } + String reportPath = entry.getPath(); + return reportPath; + } + + + + +} diff --git a/src/main/java/com/fr/plugin/third/party/jsdbacfj/config/CustomDataConfig.java b/src/main/java/com/fr/plugin/third/party/jsdbacfj/config/CustomDataConfig.java new file mode 100644 index 0000000..d46f081 --- /dev/null +++ b/src/main/java/com/fr/plugin/third/party/jsdbacfj/config/CustomDataConfig.java @@ -0,0 +1,106 @@ +package com.fr.plugin.third.party.jsdbacfj.config; + +import com.fr.config.*; +import com.fr.config.holder.Conf; +import com.fr.config.holder.factory.Holders; + +/** + * 配置数据保存 + */ +@Visualization(category = "印章集成配置") +public class CustomDataConfig extends DefaultConfiguration { + public String getNameSpace() { + return this.getClass().getName(); + } + + private static volatile CustomDataConfig config = null; + + public static CustomDataConfig getInstance() { + if (config == null) { + config = ConfigContext.getConfigInstance(CustomDataConfig.class); + } + return config; + } + + + @Identifier(value = "stampEsbUrl", name = "印章ESB地址", description = "", status = Status.SHOW) + private Conf stampEsbUrl = Holders.simple(""); + + @Identifier(value = "stampReportName", name = "印章报表名称", description = "多个报表用逗号隔开", status = Status.SHOW) + private Conf stampReportName = Holders.simple(""); + + @Identifier(value = "stampTransparent", name = "印章透明度(%)", description = "此值0至100,值越大越透明", status = Status.SHOW) + private Conf stampTransparent = Holders.simple(75); + + + @Identifier(value = "stampScaling", name = "印章缩放(%)", description = "值越大越图片越大", status = Status.SHOW) + private Conf stampScaling = Holders.simple(75); + + + @Identifier(value = "stampPositionX", name = "印章位置X轴", description = "", status = Status.HIDE) + private Conf stampPositionX = Holders.simple(75); + + @Identifier(value = "stampPositionY", name = "印章位置Y轴", description = "", status = Status.HIDE) + private Conf stampPositionY = Holders.simple(75); + + + public String getStampEsbUrl() { + return stampEsbUrl.get(); + } + + public void setStampEsbUrl(String stampEsbUrl) { + this.stampEsbUrl.set(stampEsbUrl); + } + + public String getStampReportName() { + return stampReportName.get(); + } + + public void setStampReportName(String stampReportName) { + this.stampReportName.set(stampReportName); + } + + public Integer getStampTransparent() { + return stampTransparent.get(); + } + + public void setStampTransparent(Integer stampTransparent) { + this.stampTransparent.set(stampTransparent); + } + + public Integer getStampScaling() { + return stampScaling.get(); + } + + public void setStampScaling(Integer stampScaling) { + this.stampScaling.set(stampScaling); + } + + public Integer getStampPositionX() { + return stampPositionX.get(); + } + + public void setStampPositionX(Integer stampPositionX) { + this.stampPositionX.set(stampPositionX); + } + + public Integer getStampPositionY() { + return stampPositionY.get(); + } + + public void setStampPositionY(Integer stampPositionY) { + this.stampPositionY.set(stampPositionY); + } + + @Override + public Object clone() throws CloneNotSupportedException { + CustomDataConfig cloned = (CustomDataConfig) super.clone(); + cloned.stampEsbUrl = (Conf) stampEsbUrl.clone(); + cloned.stampReportName = (Conf) stampReportName.clone(); + cloned.stampTransparent = (Conf) stampTransparent.clone(); + cloned.stampScaling = (Conf) stampScaling.clone(); + cloned.stampPositionX = (Conf) stampPositionX.clone(); + cloned.stampPositionY = (Conf) stampPositionY.clone(); + return cloned; + } +} diff --git a/src/main/java/com/fr/plugin/third/party/jsdbacfj/export/TxtConstant.java b/src/main/java/com/fr/plugin/third/party/jsdbacfj/export/TxtConstant.java new file mode 100644 index 0000000..c5a7649 --- /dev/null +++ b/src/main/java/com/fr/plugin/third/party/jsdbacfj/export/TxtConstant.java @@ -0,0 +1,6 @@ +package com.fr.plugin.third.party.jsdbacfj.export; + +public class TxtConstant { + public static String ICON_NAME ="txt"; + public static String ICON_PATH ="/com/fr/plugin/third/party/jsdbacfj/txt.png"; +} diff --git a/src/main/java/com/fr/plugin/third/party/jsdbacfj/export/TxtDelimiterAttrMark.java b/src/main/java/com/fr/plugin/third/party/jsdbacfj/export/TxtDelimiterAttrMark.java new file mode 100644 index 0000000..4031844 --- /dev/null +++ b/src/main/java/com/fr/plugin/third/party/jsdbacfj/export/TxtDelimiterAttrMark.java @@ -0,0 +1,88 @@ +package com.fr.plugin.third.party.jsdbacfj.export; + +import com.fr.json.JSONException; +import com.fr.json.JSONObject; +import com.fr.stable.fun.impl.AbstractIOFileAttrMark; +import com.fr.stable.xml.XMLPrintWriter; +import com.fr.stable.xml.XMLableReader; + +public class TxtDelimiterAttrMark extends AbstractIOFileAttrMark { + public static final String TAG = "TxtDelimiterAttrMark"; + public static final String DEFAULT_DELIMITER = ","; + + /** + * 分隔符 + */ + private String delimiter = DEFAULT_DELIMITER; + + private boolean enableSpecifiedFormat = false; + + private String startCell = "A1"; + + @Override + public String xmlTag() { + return TAG; + } + + @Override + public void readXML(XMLableReader reader) { + String tag = reader.getTagName(); + if (XML_TAG.equals(tag)) { + delimiter = reader.getAttrAsString("delimiter", ","); + enableSpecifiedFormat = reader.getAttrAsBoolean("enableSpecifiedFormat", false); + startCell = reader.getAttrAsString("startCell", "A1"); + } + } + + @Override + public void writeXML(XMLPrintWriter writer) { + writer.startTAG(XML_TAG); + writer.attr("delimiter", delimiter); + writer.attr("enableSpecifiedFormat", enableSpecifiedFormat); + writer.attr("startCell", startCell); + writer.end(); + } + + @Override + public TxtDelimiterAttrMark clone() { + TxtDelimiterAttrMark obj = (TxtDelimiterAttrMark) super.clone(); + obj.delimiter = delimiter; + obj.enableSpecifiedFormat = enableSpecifiedFormat; + obj.startCell = startCell; + return obj; + } + + @Override + public JSONObject createJSONConfig() throws JSONException { + JSONObject json = super.createJSONConfig(); + json.put("delimiter", delimiter); + json.put("enableSpecifiedFormat", enableSpecifiedFormat); + json.put("startCell", startCell); + return json; + } + + + public String getDelimiter() { + return delimiter; + } + + public void setDelimiter(String delimiter) { + this.delimiter = delimiter; + } + + public boolean isEnableSpecifiedFormat() { + return enableSpecifiedFormat; + } + + public void setEnableSpecifiedFormat(boolean enableSpecifiedFormat) { + this.enableSpecifiedFormat = enableSpecifiedFormat; + } + + public String getStartCell() { + return startCell; + } + + public void setStartCell(String startCell) { + this.startCell = startCell; + } +} diff --git a/src/main/java/com/fr/plugin/third/party/jsdbacfj/export/TxtExportOperateProvider.java b/src/main/java/com/fr/plugin/third/party/jsdbacfj/export/TxtExportOperateProvider.java new file mode 100644 index 0000000..948a0b3 --- /dev/null +++ b/src/main/java/com/fr/plugin/third/party/jsdbacfj/export/TxtExportOperateProvider.java @@ -0,0 +1,19 @@ +package com.fr.plugin.third.party.jsdbacfj.export; + + +import com.fr.plugin.third.party.jsdbacfj.export.core.TxtExportOperate; +import com.fr.report.fun.impl.AbstractExportOperateProvider; +import com.fr.web.core.reserve.Operate; + +public class TxtExportOperateProvider extends AbstractExportOperateProvider { + + @Override + public Operate operate() { + return new TxtExportOperate(); + } + + @Override + public String markType() { + return "txt"; + } +} diff --git a/src/main/java/com/fr/plugin/third/party/jsdbacfj/export/TxtExportToolbarItemProvider.java b/src/main/java/com/fr/plugin/third/party/jsdbacfj/export/TxtExportToolbarItemProvider.java new file mode 100644 index 0000000..6472038 --- /dev/null +++ b/src/main/java/com/fr/plugin/third/party/jsdbacfj/export/TxtExportToolbarItemProvider.java @@ -0,0 +1,22 @@ +package com.fr.plugin.third.party.jsdbacfj.export; + +import com.fr.design.fun.impl.AbstractToolbarItem; +import com.fr.form.ui.Widget; + +public class TxtExportToolbarItemProvider extends AbstractToolbarItem { + + @Override + public Class classForWidget() { + return TxtExtensionButtonProvider.class; + } + + @Override + public String iconPathForWidget() { + return "/com/fr/plugin/third/party/jsdbacfj/txt.png"; + } + + @Override + public String nameForWidget() { + return "txt导出"; + } +} diff --git a/src/main/java/com/fr/plugin/third/party/jsdbacfj/export/TxtExtensionButtonProvider.java b/src/main/java/com/fr/plugin/third/party/jsdbacfj/export/TxtExtensionButtonProvider.java new file mode 100644 index 0000000..f218591 --- /dev/null +++ b/src/main/java/com/fr/plugin/third/party/jsdbacfj/export/TxtExtensionButtonProvider.java @@ -0,0 +1,62 @@ +package com.fr.plugin.third.party.jsdbacfj.export; + +import com.fr.form.ui.Widget; +import com.fr.js.JavaScript; +import com.fr.js.JavaScriptImpl; +import com.fr.report.fun.impl.AbstractExtensionButton; +import com.fr.stable.web.Repository; + +public class TxtExtensionButtonProvider extends AbstractExtensionButton { + + public TxtExtensionButtonProvider() { + super("txt导出", TxtIconLoader.loadIcon()); + } + + public TxtExtensionButtonProvider(String text) { + super(text); + } + + public TxtExtensionButtonProvider(String text, String iconName) { + super(text, iconName); + } + + @Override + public String widgetName() { + return this.getClass().getName(); + } + + @Override + public Class classForDirectoryButton() { + return this.getClass(); + } + + @Override + public String getParentDirectory() { + return null; + } + + @Override + public String getType() { + return "TxtExportOperateProvider.class"; + } + + @Override + public String getRelatedCheckBoxTitle() { + return null; + } + + @Override + public boolean isSelected() { + return false; + } + + @Override + public void setSelected(boolean b) { + + } + + @Override + protected JavaScript clickScript(Repository repository) { + return new JavaScriptImpl("_g().exportReportToTxt()"); + } +} diff --git a/src/main/java/com/fr/plugin/third/party/jsdbacfj/export/TxtIconLoader.java b/src/main/java/com/fr/plugin/third/party/jsdbacfj/export/TxtIconLoader.java new file mode 100644 index 0000000..c0c4f7b --- /dev/null +++ b/src/main/java/com/fr/plugin/third/party/jsdbacfj/export/TxtIconLoader.java @@ -0,0 +1,13 @@ +package com.fr.plugin.third.party.jsdbacfj.export; + +import com.fanruan.api.report.SundryKit; + +public class TxtIconLoader { + public static String loadIcon() { + String name = TxtConstant.ICON_NAME; + String path = TxtConstant.ICON_PATH; + SundryKit.loadToolbarIcon(name, path); + return name; + } + +} \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/third/party/jsdbacfj/export/TxtIconProvider.java b/src/main/java/com/fr/plugin/third/party/jsdbacfj/export/TxtIconProvider.java new file mode 100644 index 0000000..0cbb36d --- /dev/null +++ b/src/main/java/com/fr/plugin/third/party/jsdbacfj/export/TxtIconProvider.java @@ -0,0 +1,17 @@ +package com.fr.plugin.third.party.jsdbacfj.export; + +import com.fr.stable.fun.impl.AbstractIconProvider; + +import java.util.HashMap; +import java.util.Map; + +public class TxtIconProvider extends AbstractIconProvider { + private final static Map STORE = new HashMap(2); + static { + STORE.put(TxtConstant.ICON_NAME, TxtConstant.ICON_PATH); + } + + public Map map4Icons() { + return STORE; + } +} \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/third/party/jsdbacfj/export/core/TxtExportOperate.java b/src/main/java/com/fr/plugin/third/party/jsdbacfj/export/core/TxtExportOperate.java new file mode 100644 index 0000000..2da5ccd --- /dev/null +++ b/src/main/java/com/fr/plugin/third/party/jsdbacfj/export/core/TxtExportOperate.java @@ -0,0 +1,51 @@ +package com.fr.plugin.third.party.jsdbacfj.export.core; + +import com.fanruan.api.report.export.BaseOperate; +import com.fanruan.api.util.StringKit; +import com.fr.general.BaseRecordType; +import com.fr.io.collection.ExportCollection; +import com.fr.io.exporter.CSVExporter; +import com.fr.io.exporter.ExportChecker; +import com.fr.plugin.third.party.jsdbacfj.export.TxtDelimiterAttrMark; +import com.fr.stable.web.SessionProvider; +import com.fr.web.core.ReportSessionIDInfor; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class TxtExportOperate extends BaseOperate { + + @Override + public void setContent(HttpServletRequest req, HttpServletResponse res, SessionProvider sessionProvider, String fileName, boolean isEmbed) { + res.setContentType("application/octet-stream"); + res.setHeader("extension", "txt"); + res.setHeader("Content-disposition", "attachment; filename=" + fileName + ".txt"); + } + + @Override + public ExportCollection newExportCollection(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, SessionProvider sessionProvider, String s) { + ReportSessionIDInfor reportSessionIDInfor = (ReportSessionIDInfor) sessionProvider; + TxtDelimiterAttrMark txtDelimiterAttrMark = (TxtDelimiterAttrMark) reportSessionIDInfor.getIOFileAttrMark(TxtDelimiterAttrMark.TAG); + String delimiter = TxtDelimiterAttrMark.DEFAULT_DELIMITER; + boolean enableSpecifiedFormat = false; + String startCell = "A1"; + if ((txtDelimiterAttrMark != null) && (StringKit.isNotEmpty(txtDelimiterAttrMark.getDelimiter()))) { + delimiter = txtDelimiterAttrMark.getDelimiter(); + enableSpecifiedFormat = txtDelimiterAttrMark.isEnableSpecifiedFormat(); + startCell = txtDelimiterAttrMark.getStartCell(); + } + + ExportCollection collection = ExportCollection.create(); + collection.setExporter(new TxtExporter(delimiter, enableSpecifiedFormat,startCell)); + collection.setRecordType(new BaseRecordType((short) 1999, "txt")); + //collection.setRecordType(DeclareRecordType.EXPORT_TYPE_CSV); + return collection; + } + + + public ExportChecker newExportChecker(HttpServletRequest httpServletRequest) { + return null; + } + + +} diff --git a/src/main/java/com/fr/plugin/third/party/jsdbacfj/export/core/TxtExporter.java b/src/main/java/com/fr/plugin/third/party/jsdbacfj/export/core/TxtExporter.java new file mode 100644 index 0000000..81c8a07 --- /dev/null +++ b/src/main/java/com/fr/plugin/third/party/jsdbacfj/export/core/TxtExporter.java @@ -0,0 +1,321 @@ +package com.fr.plugin.third.party.jsdbacfj.export.core; + +import com.fanruan.api.util.StringKit; +import com.fr.base.ConfigManager; +import com.fr.base.Style; +import com.fr.interruption.Condition; +import com.fr.interruption.Conditions; +import com.fr.interruption.ExporterScene; +import com.fr.io.core.ExporterUtils; +import com.fr.io.exporter.CSVExporter; +import com.fr.log.FineLoggerFactory; +import com.fr.main.workbook.ResultWorkBook; +import com.fr.page.*; +import com.fr.report.ExtraReportClassManager; +import com.fr.report.cell.CellElement; +import com.fr.report.cell.cellattr.CellGUIAttr; +import com.fr.report.core.ReportUtils; +import com.fr.report.elementcase.ElementGetter; +import com.fr.report.fun.ExportEncodeProvider; +import com.fr.report.report.ECReport; +import com.fr.report.report.ResultReport; +import com.fr.stable.ColumnRow; +import com.fr.stable.monitor.MemoryHelper; +import com.fr.web.core.ReportRepositoryDeal; + +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; +import java.text.Format; +import java.util.Iterator; +import java.util.List; + +public class TxtExporter extends CSVExporter { + /** + * 分隔符 + */ + private String delimiter = ","; + + private boolean enableSpecifiedFormat = false; + + private String startCell = "A1"; + + private int startRowIndex = 0; + private int startColumnIndex = 0; + + public TxtExporter() { + setDelimiter(","); + } + + public TxtExporter(String value, boolean enable, String cell) { + if (StringKit.isEmpty(value)) { + value = ","; + } + setDelimiter(value); + setEnableSpecifiedFormat(enable); + setStartCell(cell); + } + + public void exportReport(OutputStream out, ElementGetter reportCase, int start, int end) throws Exception { + PrintWriter writer = new PrintWriter(this.getOutputWriter(out)); + int columnCount = reportCase.getColumnCount(); + Condition csvChecker = Conditions.get(ExporterScene.CSV); + + if (isEnableSpecifiedFormat()) { + setDelimiter(","); + setCellIndex(); + } + + int colIndex = 0; + int valueIndex = 0; + for (int row = start; row < end; ++row) { + StringBuffer csvRowBuf = new StringBuffer(); + Iterator it = reportCase.getRow(row); + colIndex = 0; + String str; + int mark_col; + for (mark_col = 0; it.hasNext(); ) { + CellElement cell = (CellElement) it.next(); + for (int cell_col = cell.getColumn(); mark_col < cell_col; ++mark_col) { + long cells = (long) (mark_col * row); + if ((cells & 8191L) == 0L) { + csvChecker.setMetric(cells); + MemoryHelper.getMemoryAlarmProcessor().interruptIfConditionMet(csvChecker); + } + if ((!isEnableSpecifiedFormat()) || (isEnableSpecifiedFormat() && (colIndex >= this.startColumnIndex))) { + csvRowBuf.append(this.delimiter); + } + } + + + Object value = this.getCellValue(cell); + if (isEnableSpecifiedFormat() && (row >= this.startRowIndex) && (colIndex >= this.startColumnIndex)) { + str = Style.valueToText(value, null); + valueIndex = colIndex - this.startColumnIndex + 1; + if (valueIndex == 1) { + str = getFirstValue(str); + } else if (valueIndex == 2) { + str = getSecondValue(str); + } else if (valueIndex == 3) { + str = getThirdValue(str); + } else if (valueIndex == 4) { + str = getFourthValue(str); + } else if (valueIndex == 5) { + str = getFifthValue(str); + } + if (valueIndex >= 6) { + continue; + } + } else { + Style style = cell.getStyle(); + Format format = style.getFormat(); + str = Style.valueToText(value, format); + if (str.indexOf(",") != -1 || str.indexOf(",") != -1) { + str = "\"" + str + "\""; + } + } + + if (isEnableSpecifiedFormat() && (colIndex < this.startColumnIndex)) { + colIndex++; + continue; + } + colIndex++; + csvRowBuf.append(str); + } + + for (; mark_col < columnCount; ++mark_col) { + if (mark_col != columnCount - 1) { + csvRowBuf.append(','); + } + } + + if (isEnableSpecifiedFormat() && (row < this.startRowIndex)) { + continue; + } + if (isEnableSpecifiedFormat()) { + writer.println(trimComma(csvRowBuf.toString())); + } else { + writer.println(csvRowBuf.toString()); + } + } + + writer.flush(); + } + + private OutputStreamWriter getOutputWriter(OutputStream out) throws UnsupportedEncodingException { + ExportEncodeProvider encodeProvider = ExtraReportClassManager.getInstance().getCsvExportEncodeProvider(); + return encodeProvider != null ? encodeProvider.getCsvOutputStreamWriter(out) : new OutputStreamWriter(out, ConfigManager.getProviderInstance().getServerCharset()); + } + + private Object getCellValue(CellElement cell) { + Object value = cell.getValue(); + CellGUIAttr gui = cell.getCellGUIAttr(); + if (gui != null && !gui.isPrintContent()) { + value = ""; + } + + return value == null ? "" : value; + } + + public void export(OutputStream out, ResultWorkBook book) throws Exception { + List paperSettingList = ReportUtils.getPaperSettingListFromWorkBook(book); + int i = 0; + + for (int len = book.getReportCount(); i < len; ++i) { + this.export(out, book.getResultReport(i), (PaperSettingProvider) paperSettingList.get(i)); + } + + } + + public void export(OutputStream out, ResultWorkBook workBook, PageSetCreator pageSet, ReportRepositoryDeal repo, int[] sheets) throws Exception { + this.export(out, pageSet.createPageSet()); + } + + private void export(OutputStream out, ResultReport report, PaperSettingProvider paperSetting) throws Exception { + if (report != null) { + FineLoggerFactory.getLogger().info("UnLayerReport start export"); + this.exportReport(out, (ECReport) report, 0, ((ECReport) report).getRowCount()); + } + + } + + public void export(OutputStream out, PageSetProvider pageSet) throws Exception { + for (int i = 0; i < pageSet.size(); ++i) { + ReportPageProvider reportPage = pageSet.getPage(i); + ClippedPageProvider page = ExporterUtils.support(reportPage); + if (page == null) { + break; + } + + this.exportReport(out, (ElementGetter) page, 0, ((ElementGetter) page).getRowCount()); + } + + } + + public String getDelimiter() { + return delimiter; + } + + public void setDelimiter(String delimiter) { + this.delimiter = delimiter; + } + + public boolean isEnableSpecifiedFormat() { + return enableSpecifiedFormat; + } + + public void setEnableSpecifiedFormat(boolean enable) { + this.enableSpecifiedFormat = enable; + } + + public String getStartCell() { + return startCell; + } + + public void setStartCell(String startCell) { + this.startCell = startCell; + } + + private String getFirstValue(String value) { + String tempValue = getValue(value, 6); + return tempValue; + } + + private String getSecondValue(String value) { + String tempValue = getValue(value, 4); + return tempValue; + } + + private String getThirdValue(String value) { + String tempValue = getValue(value, 20); + return tempValue; + } + + private String getFourthValue(String value) { + String tempValue = getValue(value, 1); + return tempValue; + } + + private String getFifthValue(String value) { + value = StringKit.trim(value); + if (StringKit.isEmpty(value)) { + return fillZero(12); + } + String value1 = "", value2 = ""; + int index = value.indexOf("."); + if (index >= 0) { + value1 = value.substring(0, index); + value2 = value.substring(index + 1); + } else { + value1 = value; + } + value1 = getValue(value1, 10); + if (StringKit.isEmpty(value2)) { + value2 = "00"; + } else if (value2.length() == 1) { + value2 = value2 + "0"; + } else if (value2.length() >= 2) { + value2 = value2.substring(0, 2); + } + String tempValue = value1 + value2; + return tempValue; + } + + private String fillZero(int n) { + if (n <= 0) { + return ""; + } + String value = ""; + for (int i = 0, iMax = n - 1; i <= iMax; i++) { + value = value + "0"; + } + return value; + } + + private String getValue(String value, int length) { + if (length <= 0) { + return ""; + } + value = StringKit.trim(value); + if (StringKit.isEmpty(value)) { + return fillZero(length); + } + + if (value.length() == length) { + return value; + } + if (value.length() >= length) { + return value.substring(value.length() - length); + } + + String tempValue = fillZero(length - value.length()) + value; + return tempValue; + } + + private void setCellIndex() { + if (StringKit.isEmpty(this.startCell)) { + this.startCell = "A1"; + } + ColumnRow columnRow = ColumnRow.valueOf(this.startCell); + + this.startRowIndex = columnRow.getRow(); + this.startColumnIndex = columnRow.getColumn(); + } + + private String trimComma(String value) { + value = StringKit.trim(value); + if (StringKit.isEmpty(value)) { + return ""; + } + String tempValue = value; + if (",".equals(tempValue.substring(0, 1))) { + tempValue = tempValue.substring(1); + } + if (",".equals(tempValue.substring(tempValue.length() - 1))) { + tempValue = tempValue.substring(0, tempValue.length() - 1); + } + return tempValue; + } + +} diff --git a/src/main/java/com/fr/plugin/third/party/jsdbacfj/export/menu/TextDelimiterMenuAction.java b/src/main/java/com/fr/plugin/third/party/jsdbacfj/export/menu/TextDelimiterMenuAction.java new file mode 100644 index 0000000..4b4be4f --- /dev/null +++ b/src/main/java/com/fr/plugin/third/party/jsdbacfj/export/menu/TextDelimiterMenuAction.java @@ -0,0 +1,48 @@ +package com.fr.plugin.third.party.jsdbacfj.export.menu; + +import com.fr.base.io.AttrMark; +import com.fr.design.actions.JTemplateAction; +import com.fr.design.dialog.DialogActionAdapter; +import com.fr.design.dialog.UIDialog; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.JTemplate; +import com.fr.report.fit.FitProvider; + +import java.awt.*; +import java.awt.event.ActionEvent; + +public class TextDelimiterMenuAction extends JTemplateAction { + private static final Dimension MEDIUM = new Dimension(430, 400); + + public TextDelimiterMenuAction(JTemplate template) { + super(template); + setName("TXT导出分隔符设置"); + //setSmallIcon(IconUtils.readIcon("com/tptj/demo/hg/menu/resources/image/demo.png")); + } + + @Override + public void actionPerformed(ActionEvent e) { + JTemplate jwb = getEditingComponent(); + if (null == jwb) { + return; + } + //当前的模板 + FitProvider wbTpl = (FitProvider) jwb.getTarget(); + if (!jwb.isJWorkBook()) { + //不是cpt + return; + } + TextDelimiterPane pane = new TextDelimiterPane((AttrMark) wbTpl); + UIDialog dialog = pane.showUnsizedWindow(DesignerContext.getDesignerFrame(), new DialogActionAdapter() { + @Override + public void doOk() { + //做某些操作 从 pane中读取相关的交互结果设置到当前的模板中一般是这样 + pane.update(); + jwb.fireTargetModified(); + } + }); + pane.populate(); + dialog.setSize(MEDIUM); + dialog.setVisible(true); + } +} \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/third/party/jsdbacfj/export/menu/TextDelimiterMenuHandler.java b/src/main/java/com/fr/plugin/third/party/jsdbacfj/export/menu/TextDelimiterMenuHandler.java new file mode 100644 index 0000000..cfd0c3a --- /dev/null +++ b/src/main/java/com/fr/plugin/third/party/jsdbacfj/export/menu/TextDelimiterMenuHandler.java @@ -0,0 +1,46 @@ +package com.fr.plugin.third.party.jsdbacfj.export.menu; + +import com.fr.design.fun.impl.AbstractMenuHandler; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.JTemplate; +import com.fr.design.mainframe.toolbar.ToolBarMenuDockPlus; +import com.fr.design.menu.ShortCut; + +public class TextDelimiterMenuHandler extends AbstractMenuHandler { + private static final int INSERT_POSITION = 2; + + @Override + public int insertPosition(int total) { + return INSERT_POSITION; + } + + @Override + public boolean insertSeparatorBefore() { + return true; + } + + @Override + public boolean insertSeparatorAfter() { + return false; + } + + @Override + public String category() { + return TEMPLATE; + } + + @Override + public ShortCut shortcut() { + JTemplate template = DesignerContext.getDesignerFrame().getSelectedJTemplate(); + return shortcut(template); + } + + @Override + public ShortCut shortcut(ToolBarMenuDockPlus plus) { + //往ToolBarMenuDockPlus里塞感觉也很糟. + if (!(plus instanceof JTemplate)) { + return null; + } + return new TextDelimiterMenuAction((JTemplate) plus); + } +} \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/third/party/jsdbacfj/export/menu/TextDelimiterPane.java b/src/main/java/com/fr/plugin/third/party/jsdbacfj/export/menu/TextDelimiterPane.java new file mode 100644 index 0000000..0d6cbb8 --- /dev/null +++ b/src/main/java/com/fr/plugin/third/party/jsdbacfj/export/menu/TextDelimiterPane.java @@ -0,0 +1,83 @@ +package com.fr.plugin.third.party.jsdbacfj.export.menu; + +import com.fanruan.api.design.ui.component.UICheckBox; +import com.fanruan.api.util.StringKit; +import com.fr.base.io.AttrMark; +import com.fr.design.dialog.BasicPane; +import com.fr.design.editor.editor.ColumnRowEditor; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.gui.itextfield.UITextField; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.layout.TableLayout; +import com.fr.design.layout.TableLayoutHelper; +import com.fr.plugin.third.party.jsdbacfj.export.TxtDelimiterAttrMark; +import com.fr.stable.ColumnRow; + +import javax.swing.*; +import java.awt.*; + +public class TextDelimiterPane extends BasicPane { + private UITextField delimiterText; + private UICheckBox enableSpecifiedFormatCheckBox; + private ColumnRowEditor startColumnRowEditor; + private AttrMark container; + + public TextDelimiterPane(AttrMark container) { + this.container = container; + delimiterText = new UITextField(); + enableSpecifiedFormatCheckBox = new UICheckBox(); + startColumnRowEditor = new ColumnRowEditor(); + + setLayout(FRGUIPaneFactory.createM_BorderLayout()); + JPanel pane = TableLayoutHelper.createTableLayoutPane( + new Component[][]{ + {new UILabel("导出分隔符:"), delimiterText}, + {new UILabel("导出指定格式:"), enableSpecifiedFormatCheckBox}, + {new UILabel("导出指定格式的开始位置:"), startColumnRowEditor} + }, + new double[]{TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED}, + new double[]{TableLayout.PREFERRED, TableLayout.FILL} + ); + add(pane, BorderLayout.NORTH); + } + + @Override + protected String title4PopupWindow() { + return "TXT导出分隔符设置"; + } + + public void populate() { + delimiterText.setText(TxtDelimiterAttrMark.DEFAULT_DELIMITER); + enableSpecifiedFormatCheckBox.setSelected(false); + TxtDelimiterAttrMark attr = container.getAttrMark(TxtDelimiterAttrMark.TAG); + if (null != attr) { + delimiterText.setText(attr.getDelimiter()); + enableSpecifiedFormatCheckBox.setSelected(attr.isEnableSpecifiedFormat()); + setStartValue(attr.getStartCell()); + } + } + + public void update() { + TxtDelimiterAttrMark attr = new TxtDelimiterAttrMark(); + attr.setDelimiter(delimiterText.getText()); + attr.setEnableSpecifiedFormat(enableSpecifiedFormatCheckBox.isSelected()); + attr.setStartCell(getStartValue()); + container.addAttrMark(attr); + } + + private String getStartValue() { + ColumnRow columnRow = startColumnRowEditor.getValue(); + if (columnRow == null) { + return "A1"; + } + return columnRow.toString(); + } + + private void setStartValue(String value) { + if (StringKit.isEmpty(value)) { + value = "A1"; + } + ColumnRow columnRow = ColumnRow.valueOf(value); + startColumnRowEditor.setValue(columnRow); + } +} \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/third/party/jsdbacfj/export/web/JavaScriptFileHandler.java b/src/main/java/com/fr/plugin/third/party/jsdbacfj/export/web/JavaScriptFileHandler.java new file mode 100644 index 0000000..23783d5 --- /dev/null +++ b/src/main/java/com/fr/plugin/third/party/jsdbacfj/export/web/JavaScriptFileHandler.java @@ -0,0 +1,13 @@ +package com.fr.plugin.third.party.jsdbacfj.export.web; + +import com.fr.stable.fun.impl.AbstractJavaScriptFileHandler; + +public class JavaScriptFileHandler extends AbstractJavaScriptFileHandler { + + @Override + public String[] pathsForFiles() { + return new String[]{ + "/com/fr/plugin/third/party/jsdbacfj/txt_export.js" + }; + } +} diff --git a/src/main/java/com/fr/plugin/third/party/jsdbacfj/http/CreatePdfHttpHandler.java b/src/main/java/com/fr/plugin/third/party/jsdbacfj/http/CreatePdfHttpHandler.java new file mode 100644 index 0000000..7be046c --- /dev/null +++ b/src/main/java/com/fr/plugin/third/party/jsdbacfj/http/CreatePdfHttpHandler.java @@ -0,0 +1,185 @@ +package com.fr.plugin.third.party.jsdbacfj.http; + +import com.fanruan.api.log.LogKit; +import com.fanruan.api.util.StringKit; +import com.fr.decision.fun.impl.BaseHttpHandler; +import com.fr.io.TemplateWorkBookIO; +import com.fr.io.exporter.PDFExporterForPrint; +import com.fr.main.TemplateWorkBook; +import com.fr.main.workbook.ResultWorkBook; +import com.fr.page.PageSetProvider; +import com.fr.plugin.context.PluginContexts; +import com.fr.plugin.third.party.jsdbacfj.StampUtils; +import com.fr.report.core.ReportUtils; +import com.fr.stable.PageActor; +import com.fr.third.springframework.web.bind.annotation.RequestMethod; +import com.fr.web.utils.WebUtils; +import org.apache.pdfbox.multipdf.PDFMergerUtility; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.FileOutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * + */ +public class CreatePdfHttpHandler extends BaseHttpHandler { + + @Override + public RequestMethod getMethod() { + return RequestMethod.GET; + } + + @Override + public String getPath() { + return "/jsdbacfj/stamp/pdf"; + } + + @Override + public boolean isPublic() { + return true; + } + + @Override + public void handle(HttpServletRequest req, HttpServletResponse res) throws Exception { + addStamp(req, res); + } + + private void addStamp(HttpServletRequest req, HttpServletResponse res) throws Exception { + res.setContentType("text/plain"); + LogKit.info("印章集成,批量生成印章pdf, 开始..."); + if (!PluginContexts.currentContext().isAvailable()) { + LogKit.error("印章集成插件试用过期, 请添加许可证"); + WebUtils.printAsString(res, "印章集成插件试用过期, 请添加许可证"); + return; + } + + LogKit.info("印章集成,批量生成印章pdf, 获取报表路径..."); + List reportPaths = getReportPaths(req); + if (reportPaths.size() <= 0) { + LogKit.error("印章集成,批量生成印章pdf, 没有有效的报表路径"); + WebUtils.printAsString(res, "没有有效的报表路径"); + return; + } + + LogKit.info("印章集成,批量生成印章pdf, 获取印章..."); + String orgId = WebUtils.getHTTPRequestParameter(req, "orgId"); + LogKit.info("印章集成,批量生成印章pdf, 获取印章,orgId:" + orgId); + String stampBase64 = StampUtils.getStampBase64(orgId); + if (StringKit.isEmpty(stampBase64)) { + LogKit.error("印章集成,批量生成印章pdf, 无法获取印章"); + WebUtils.printAsString(res, "无法获取印章"); + return; + } + + StampUtils.addFrameOptions(req, res); + + LogKit.info("印章集成,批量生成印章pdf, 生成pdf文件..."); + String dirPath = StampUtils.getTempExportPath(); + Path path = Paths.get(dirPath); + Files.createDirectories(path); + String filePath = dirPath + "/a.pdf"; + String filePath1 = dirPath + "/b.pdf"; + + String templatePath; + TemplateWorkBook templateWorkBook; + ResultWorkBook resultWorkBook; + PageSetProvider pageSetProvider; + FileOutputStream fileOutputStream; + Map parameterMap = createParameterMap(req); + PDFExporterForPrint pdfExporter = new PDFExporterForPrint(); + if (reportPaths.size() == 1) { + templatePath = reportPaths.get(0); + templateWorkBook = TemplateWorkBookIO.readTemplateWorkBook(templatePath); + resultWorkBook = templateWorkBook.execute(parameterMap, new PageActor()); + pageSetProvider = resultWorkBook.generateReportPageSet(ReportUtils.getPaperSettingListFromWorkBook(resultWorkBook)).traverse4Export(); + fileOutputStream = new FileOutputStream(filePath); + pdfExporter.export(fileOutputStream, pageSetProvider); + } else { + PDFMergerUtility pdfMerger = new PDFMergerUtility(); + pdfMerger.setDestinationFileName(filePath); + String tempPath; + for (int i = 0, max = reportPaths.size() - 1; i <= max; i++) { + tempPath = dirPath + "/temp" + i + ".pdf"; + templatePath = reportPaths.get(i); + templateWorkBook = TemplateWorkBookIO.readTemplateWorkBook(templatePath); + resultWorkBook = templateWorkBook.execute(parameterMap, new PageActor()); + pageSetProvider = resultWorkBook.generateReportPageSet(ReportUtils.getPaperSettingListFromWorkBook(resultWorkBook)).traverse4Export(); + fileOutputStream = new FileOutputStream(tempPath); + pdfExporter.export(fileOutputStream, pageSetProvider); + pdfMerger.addSource(tempPath); + } + pdfMerger.mergeDocuments(); + } + LogKit.info("印章集成,批量生成印章pdf, 添加印章..."); + + int stampX = WebUtils.getHTTPRequestIntParameter(req, "stampX", -1); + int stampY = WebUtils.getHTTPRequestIntParameter(req, "stampY", -1); + int stampInterval = WebUtils.getHTTPRequestIntParameter(req, "stampInterval", -1); + int stampWidth = WebUtils.getHTTPRequestIntParameter(req, "stampWidth", -1); + int stampHeight = WebUtils.getHTTPRequestIntParameter(req, "stampHeight", -1); + + StampUtils.addStampWithPdf(stampBase64, filePath, filePath1, stampX, stampY, stampInterval, stampWidth, stampHeight); + StampUtils.writePdfToResponse(res, filePath1); + StampUtils.deleteFile(path); + LogKit.info("印章集成,批量生成印章pdf, 结束..."); + } + + + private Map createParameterMap(HttpServletRequest req) { + Map tempParas = req.getParameterMap(); + if ((tempParas == null) || (tempParas.size() <= 0)) { + return new HashMap<>(); + } + Map parameterMap = new HashMap<>(); + String key; + Object valueObject; + for (Map.Entry tempEntry : tempParas.entrySet()) { + key = tempEntry.getKey(); + if ("viewlet".equals(key)) { + continue; + } + if ("reportPath".equals(key)) { + continue; + } + valueObject = req.getParameter(key); + parameterMap.put(key, valueObject); + } + return parameterMap; + } + + private List getReportPaths(HttpServletRequest req) throws Exception { + List reportPaths = new ArrayList<>(); + if (req == null) { + return reportPaths; + } + + String[] tempPaths = req.getParameterValues("reportPath"); + if ((tempPaths == null) || (tempPaths.length <= 0)) { + return reportPaths; + } + + String templatePath; + TemplateWorkBook templateWorkBook; + for (int i = 0, max = tempPaths.length - 1; i <= max; i++) { + templatePath = StringKit.trim(tempPaths[i]); + LogKit.info("印章集成,批量生成印章pdf, 报表路径:" + templatePath); + if (StringKit.isEmpty(templatePath) || reportPaths.contains(templatePath)) { + continue; + } + templateWorkBook = TemplateWorkBookIO.readTemplateWorkBook(templatePath); + if (templateWorkBook == null) { + continue; + } + reportPaths.add(templatePath); + } + return reportPaths; + } +} diff --git a/src/main/java/com/fr/plugin/third/party/jsdbacfj/http/CustomConfigHttpHandler.java b/src/main/java/com/fr/plugin/third/party/jsdbacfj/http/CustomConfigHttpHandler.java new file mode 100644 index 0000000..4ccf60b --- /dev/null +++ b/src/main/java/com/fr/plugin/third/party/jsdbacfj/http/CustomConfigHttpHandler.java @@ -0,0 +1,91 @@ +package com.fr.plugin.third.party.jsdbacfj.http; + +import com.fanruan.api.log.LogKit; +import com.fanruan.api.util.StringKit; +import com.fr.decision.fun.impl.BaseHttpHandler; +import com.fr.json.JSONObject; +import com.fr.plugin.third.party.jsdbacfj.StampUtils; +import com.fr.plugin.third.party.jsdbacfj.Utils; +import com.fr.plugin.third.party.jsdbacfj.config.CustomDataConfig; +import com.fr.third.org.apache.commons.lang3.time.DateFormatUtils; +import com.fr.third.org.apache.http.impl.client.CloseableHttpClient; +import com.fr.third.springframework.web.bind.annotation.RequestMethod; +import com.fr.web.utils.WebUtils; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Date; +import java.util.UUID; + +/** + * + */ +public class CustomConfigHttpHandler extends BaseHttpHandler { + + @Override + public RequestMethod getMethod() { + return RequestMethod.GET; + } + + @Override + public String getPath() { + return "/jsdbacfj/config"; + } + + @Override + public boolean isPublic() { + return true; + } + + @Override + public void handle(HttpServletRequest req, HttpServletResponse res) throws Exception { + res.setContentType("application/json; charset=utf-8"); + JSONObject configJson = new JSONObject(); + configJson.put("status", "failure"); + + String refererUrl = req.getHeader("Referer"); + if (StringKit.isEmpty(refererUrl)) { + LogKit.info("印章集成,请求头Referer值为空"); + configJson.put("msg", "请求头Referer值为空"); + WebUtils.printAsJSON(res, configJson); + return; + } + String currentReportPath = Utils.getReportPathByUrl(refererUrl); + if (StringKit.isEmpty(currentReportPath)) { + LogKit.info("印章集成,当前报表路径为空"); + configJson.put("msg", "当前报表路径为空"); + WebUtils.printAsJSON(res, configJson); + return; + } + String reportPath = CustomDataConfig.getInstance().getStampReportName(); + if (StringKit.isEmpty(reportPath)) { + LogKit.info("印章集成,配置报表路径为空"); + configJson.put("msg", "配置报表路径为空"); + WebUtils.printAsJSON(res, configJson); + return; + } + + LogKit.info("印章集成,当前报表路径:" + currentReportPath); + LogKit.info("印章集成,配置报表路径:" + reportPath); + if (StampUtils.isNotStampReport(currentReportPath)) { + LogKit.info("印章集成,当前报表路径与配置报表路径不同"); + configJson.put("msg", "当前报表路径与配置报表路径不同"); + WebUtils.printAsJSON(res, configJson); + return; + } + LogKit.info("印章集成,印章生效报表路径:" + currentReportPath); + + String dataBase64 = StampUtils.getImgBase64(); + if (StringKit.isEmpty(dataBase64)) { + LogKit.info("印章集成,图章为空"); + configJson.put("msg", "图章为空"); + WebUtils.printAsJSON(res, configJson); + return; + } + configJson.put("dataBase64", dataBase64); + configJson.put("stampOpacity", StampUtils.getStampOpacity()); + configJson.put("status", "success"); + WebUtils.printAsJSON(res, configJson); + } +} diff --git a/src/main/java/com/fr/plugin/third/party/jsdbacfj/http/CustomHttpHandlerProvider.java b/src/main/java/com/fr/plugin/third/party/jsdbacfj/http/CustomHttpHandlerProvider.java new file mode 100644 index 0000000..e6707c9 --- /dev/null +++ b/src/main/java/com/fr/plugin/third/party/jsdbacfj/http/CustomHttpHandlerProvider.java @@ -0,0 +1,15 @@ +package com.fr.plugin.third.party.jsdbacfj.http; + +import com.fr.decision.fun.impl.AbstractHttpHandlerProvider; +import com.fr.decision.fun.impl.BaseHttpHandler; + + +public class CustomHttpHandlerProvider extends AbstractHttpHandlerProvider { + @Override + public BaseHttpHandler[] registerHandlers() { + return new BaseHttpHandler[]{ + new CustomConfigHttpHandler(), + new CreatePdfHttpHandler() + }; + } +} diff --git a/src/main/java/com/fr/plugin/third/party/jsdbacfj/http/CustomURLAliasProvider.java b/src/main/java/com/fr/plugin/third/party/jsdbacfj/http/CustomURLAliasProvider.java new file mode 100644 index 0000000..7a68633 --- /dev/null +++ b/src/main/java/com/fr/plugin/third/party/jsdbacfj/http/CustomURLAliasProvider.java @@ -0,0 +1,17 @@ +package com.fr.plugin.third.party.jsdbacfj.http; + +import com.fr.decision.fun.impl.AbstractURLAliasProvider; +import com.fr.decision.webservice.url.alias.URLAlias; +import com.fr.decision.webservice.url.alias.URLAliasFactory; +import com.fr.stable.fun.Authorize; + +@Authorize(callSignKey = "com.fr.plugin.third.party.jsdbacfj") +public class CustomURLAliasProvider extends AbstractURLAliasProvider { + @Override + public URLAlias[] registerAlias() { + return new URLAlias[]{ + URLAliasFactory.createPluginAlias("/jsdbacfj/config", "/jsdbacfj/config", true), + URLAliasFactory.createPluginAlias("/jsdbacfj/stamp/pdf", "/jsdbacfj/stamp/pdf", true), + }; + } +} diff --git a/src/main/java/com/fr/plugin/third/party/jsdbacfj/http/SessionGlobalRequestFilterProvider.java b/src/main/java/com/fr/plugin/third/party/jsdbacfj/http/SessionGlobalRequestFilterProvider.java new file mode 100644 index 0000000..46420f7 --- /dev/null +++ b/src/main/java/com/fr/plugin/third/party/jsdbacfj/http/SessionGlobalRequestFilterProvider.java @@ -0,0 +1,52 @@ +package com.fr.plugin.third.party.jsdbacfj.http; + +import com.fanruan.api.log.LogKit; +import com.fanruan.api.util.StringKit; +import com.fr.decision.fun.impl.AbstractGlobalRequestFilterProvider; +import com.fr.plugin.third.party.jsdbacfj.StampUtils; +import com.fr.stable.fun.Authorize; + +import javax.servlet.FilterChain; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@Authorize(callSignKey = "com.fr.plugin.third.party.jsdbacfj") +public class SessionGlobalRequestFilterProvider extends AbstractGlobalRequestFilterProvider { + + @Override + public String filterName() { + return "com.fr.plugin.third.party.jsdbacfj"; + } + + @Override + public String[] urlPatterns() { + return new String[]{"/decision", "/decision/*"}; + } + + @Override + public void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain filterChain) { + try { + if (StampUtils.isAddStamp(req)) { + StampUtils.addStamp(req, res, filterChain); + return; + } + filterChain.doFilter(req, res); + } catch (Exception e) { + LogKit.error("印章集成出错," + e.getMessage(), e); + } + } + + private String getRequestFullUrl(HttpServletRequest req) { + if (req == null) { + return ""; + } + String query = req.getQueryString(); + if (StringKit.isEmpty(query) || "null".equalsIgnoreCase(query)) { + query = ""; + } else { + query = "?" + query; + } + String url = req.getRequestURL().toString() + query; + return url; + } +} diff --git a/src/main/java/com/fr/plugin/third/party/jsdbacfj/web/MainFilesComponent.java b/src/main/java/com/fr/plugin/third/party/jsdbacfj/web/MainFilesComponent.java new file mode 100644 index 0000000..02761ff --- /dev/null +++ b/src/main/java/com/fr/plugin/third/party/jsdbacfj/web/MainFilesComponent.java @@ -0,0 +1,45 @@ +package com.fr.plugin.third.party.jsdbacfj.web; + +import com.fr.web.struct.Component; +import com.fr.web.struct.Filter; +import com.fr.web.struct.browser.RequestClient; +import com.fr.web.struct.category.ScriptPath; +import com.fr.web.struct.category.StylePath; + +public class MainFilesComponent extends Component { + public static final MainFilesComponent KEY = new MainFilesComponent(); + private MainFilesComponent(){} + /** + * 返回需要引入的JS脚本路径 + * @param client 请求客户端描述 + * @return JS脚本路径 + */ + public ScriptPath script(RequestClient client ) { + //如果不需要就直接返回 ScriptPath.EMPTY + return ScriptPath.build("com/fr/plugin/third/party/jsdbacfj/main.js"); + } + + /** + * 返回需要引入的CSS样式路径 + * @param client 请求客户端描述 + * @return CSS样式路径 + */ + public StylePath style(RequestClient client ) { + //如果不需要就直接返回 StylePath.EMPTY; + return StylePath.EMPTY; + } + + /** + * 通过给定的资源过滤器控制是否加载这个资源 + * @return 资源过滤器 + */ + public Filter filter() { + return new Filter(){ + @Override + public boolean accept() { + //任何情况下我们都在平台组件加载时加载我们的组件 + return true; + } + }; + } +} \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/third/party/jsdbacfj/web/MainWebResourceProvider.java b/src/main/java/com/fr/plugin/third/party/jsdbacfj/web/MainWebResourceProvider.java new file mode 100644 index 0000000..4bc0bf1 --- /dev/null +++ b/src/main/java/com/fr/plugin/third/party/jsdbacfj/web/MainWebResourceProvider.java @@ -0,0 +1,20 @@ +package com.fr.plugin.third.party.jsdbacfj.web; + +import com.fr.decision.fun.impl.AbstractWebResourceProvider; +import com.fr.decision.web.MainComponent; +import com.fr.report.web.ReportMainComponent; +import com.fr.web.struct.Atom; + +public class MainWebResourceProvider extends AbstractWebResourceProvider { + @Override + public Atom attach() { + //在平台主组件加载时添加我们自己的组件 + return ReportMainComponent.KEY; + } + + @Override + public Atom client() { + //我们自己要引入的组件 + return MainFilesComponent.KEY; + } +} diff --git a/src/main/resources/com/fr/plugin/third/party/jsdbacfj/main.js b/src/main/resources/com/fr/plugin/third/party/jsdbacfj/main.js new file mode 100644 index 0000000..f9aa4da --- /dev/null +++ b/src/main/resources/com/fr/plugin/third/party/jsdbacfj/main.js @@ -0,0 +1,25 @@ +$(function () { + var url = FR.fineServletURL + "/url/jsdbacfj/config"; + $.get(url, + function (data, status) { + if (status == "success" && data.status && data.status == "success") { + addStamp(data.imgId, data.dataBase64, data.stampOpacity); + window.jsdbacfjConfig = window.jsdbacfjConfig || {}; + window.jsdbacfjConfig.imgId = data.imgId; + window.jsdbacfjConfig.dataBase64 = data.dataBase64; + window.jsdbacfjConfig.stampOpacity = data.stampOpacity; + var timerId = setInterval(function () { + var stampImg = $("#" + window.jsdbacfjConfig.imgId); + if (stampImg.length >= 1) { + return; + } + addStamp(window.jsdbacfjConfig.imgId, window.jsdbacfjConfig.dataBase64, window.jsdbacfjConfig.stampOpacity); + }, 500) + } + }, "json"); + + function addStamp(imgId, dataBase64, stampOpacity) { + $("#content-container").prepend('') + } + +}); \ No newline at end of file diff --git a/src/main/resources/com/fr/plugin/third/party/jsdbacfj/txt.png b/src/main/resources/com/fr/plugin/third/party/jsdbacfj/txt.png new file mode 100644 index 0000000..5cef69d Binary files /dev/null and b/src/main/resources/com/fr/plugin/third/party/jsdbacfj/txt.png differ diff --git a/src/main/resources/com/fr/plugin/third/party/jsdbacfj/txt_export.js b/src/main/resources/com/fr/plugin/third/party/jsdbacfj/txt_export.js new file mode 100644 index 0000000..39c5cf6 --- /dev/null +++ b/src/main/resources/com/fr/plugin/third/party/jsdbacfj/txt_export.js @@ -0,0 +1,91 @@ + +$(function () { + if (FR.WritePane) { + $.extend(FR.WritePane.prototype, { + exportReportToTxt: function () { + if (this.fireEvent("before_txt") === false) { + return; + } + var self = this; + window.location = FR.servletURL + "?op=export&sessionID=" + this.currentSessionID + "&format=txt"; + try { + FR.progressBar.call(this, this.currentSessionID, "txt_export"); + } catch (e) { + FR.progressBar(self.currentSessionID, "txt_export"); + } + self.fireEvent("after_txt"); + } + }); + } + if (FR.PagePane) { + $.extend(FR.PagePane.prototype, { + exportReportToTxt: function () { + if (this.fireEvent("before_txt") === false) { + return; + } + var self = this; + window.location = FR.servletURL + "?op=export&sessionID=" + this.currentSessionID + "&format=txt"; + try { + FR.progressBar.call(this, this.currentSessionID, "txt_export"); + } catch (e) { + FR.progressBar(self.currentSessionID, "txt_export"); + } + self.fireEvent("after_txt"); + } + }); + } + if (FR.ViewPane) { + $.extend(FR.ViewPane.prototype, { + exportReportToTxt: function () { + if (this.fireEvent("before_txt") === false) { + return; + } + var self = this; + window.location = FR.servletURL + "?op=export&sessionID=" + this.currentSessionID + "&format=txt"; + try { + FR.progressBar.call(this, this.currentSessionID, "txt_export"); + } catch (e) { + FR.progressBar(self.currentSessionID, "txt_export"); + } + self.fireEvent("after_txt"); + } + }); + } + + + //新填报预览 + if ((typeof (WT) != 'undefined') && (typeof (WT.ReportPage) != 'undefined')) { + $.extend(WT.ReportPage.prototype, { + exportReportToTxt: function () { + var beforeEvent = "beforetotxt"; + var afterEvent = "aftertotxt"; + + if (this.fireEvent(beforeEvent) === false) { + return + } + var self = this; + this.stopEditAndWaitCal().then(function () { + WT.net.saveContent(self._getDirtyCellListAll()).then(function (c) { + if (c !== "success") { + return WT.createPromiseResult(c) + } + self._afterContentSave(); + //WT.net.exportPDF(b) + var a = FR.buildServletUrl({ + op: "export", + format: "txt", + "fr_embedded": true, + extype: "txt", + sessionID: FR.SessionMgr.getSessionID() + }, true); + WT.net.downloadExportFile(a, "txt"); + + })["catch"](WT.toastError).then(function () { + self.fireEvent(afterEvent) + }) + }) + } + }); + } + +}); \ No newline at end of file