diff --git a/designer-base/src/main/java/com/fr/design/dialog/UIDialog.java b/designer-base/src/main/java/com/fr/design/dialog/UIDialog.java index 458daddab5..63aea87c3c 100644 --- a/designer-base/src/main/java/com/fr/design/dialog/UIDialog.java +++ b/designer-base/src/main/java/com/fr/design/dialog/UIDialog.java @@ -18,6 +18,7 @@ import java.awt.BorderLayout; import java.awt.Dialog; import java.awt.FlowLayout; import java.awt.Frame; +import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; @@ -44,6 +45,10 @@ public abstract class UIDialog extends JDialog { super(parent); } + public UIDialog(Window parent) { + super(parent); + } + public UIDialog(Frame parent, BasicPane pane) { this(parent, pane, true); diff --git a/designer-base/src/main/java/com/fr/design/mainframe/toast/SimpleToast.java b/designer-base/src/main/java/com/fr/design/mainframe/toast/SimpleToast.java new file mode 100644 index 0000000000..3764cbcd83 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/toast/SimpleToast.java @@ -0,0 +1,194 @@ +package com.fr.design.mainframe.toast; + +import com.fr.concurrent.NamedThreadFactory; +import com.fr.design.dialog.UIDialog; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.module.ModuleContext; + +import javax.swing.BorderFactory; +import javax.swing.Icon; +import javax.swing.JPanel; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.Point; +import java.awt.Window; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +/** + * toast弹窗 + * */ +public class SimpleToast extends UIDialog { + private static final int MIN_HEIGHT = 36; + private static final String TOAST_MSG_TIMER = "TOAST_MSG_TIMER"; + private static final long DEFAULT_DISAPPEAR_DELAY = 5000; + private static final TimeUnit DEFAULT_TIME_UNIT = TimeUnit.MILLISECONDS; + + + private ScheduledExecutorService timer; + private int hideHeight = 0; + private JPanel contentPane; + private boolean show = false; + private Window parent; + private boolean autoDisappear; + + public SimpleToast(Window parent, Icon icon, String text, boolean autoDisappear) { + super(parent); + this.parent = parent; + this.autoDisappear = autoDisappear; + JPanel panel = createContentPane(icon, text); + init(panel); + } + + private JPanel createContentPane(Icon icon, String text) { + JPanel pane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + + UILabel iconLabel = new UILabel(icon); + iconLabel.setVerticalAlignment(SwingConstants.TOP); + iconLabel.setBorder(BorderFactory.createEmptyBorder(3, 0, 0, 0)); + + + UILabel textLabel = new UILabel(text); + pane.add(iconLabel, BorderLayout.WEST); + pane.add(textLabel, BorderLayout.CENTER); + pane.setBorder(BorderFactory.createEmptyBorder(8, 15, 8, 15)); + + return pane; + } + + + private void init(JPanel panel) { + setFocusable(false); + setAutoRequestFocus(false); + setUndecorated(true); + contentPane = panel; + initComponent(); + } + + private void initComponent() { + this.getContentPane().setLayout(null); + this.getContentPane().add(contentPane); + Dimension dimension = calculatePreferSize(); + hideHeight = dimension.height; + setSize(new Dimension(dimension.width, 0)); + contentPane.setSize(dimension); + setRelativeLocation(dimension); + if (autoDisappear) { + disappear(contentPane); + } + } + + private void setRelativeLocation(Dimension dimension) { + int positionX = parent.getLocationOnScreen().x + (parent.getWidth() - dimension.width) / 2; + int positionY = parent.getLocationOnScreen().y + 10; + this.setLocation(positionX, positionY); + } + + private Dimension calculatePreferSize() { + Dimension contentDimension = contentPane.getPreferredSize(); + int height = Math.max(MIN_HEIGHT, contentDimension.height); + return new Dimension(contentDimension.width, height); + } + + + public void display(JPanel outerPanel) { + show = true; + outerPanel.setLocation(0, -hideHeight); + ScheduledExecutorService tipToolTimer = createToastScheduleExecutorService(); + tipToolTimer.scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + SwingUtilities.invokeLater(()->{ + displayStep(outerPanel, tipToolTimer); + }); + } + }, 0, 50, TimeUnit.MILLISECONDS); + + } + + void displayStep(JPanel outerPanel, ScheduledExecutorService timer) { + Point point = outerPanel.getLocation(); + if (point.y >= 0 && !timer.isShutdown()) { + timer.shutdown(); + } + int showDistance = 5 + point.y < 0 ? 5 : -point.y; + outerPanel.setLocation(point.x, point.y + showDistance); + Dimension dimension = SimpleToast.this.getSize(); + SimpleToast.this.setSize(new Dimension(dimension.width, dimension.height + showDistance)); + } + + + + + + + private void disappear(JPanel outerPanel, long delay, TimeUnit timeUnit) { + timer = createToastScheduleExecutorService(); + timer.schedule(new DisappearMotion(outerPanel), delay, timeUnit); + } + + /** + * toast消失的动画效果 + * */ + class DisappearMotion implements Runnable { + JPanel panel; + + DisappearMotion(JPanel panel) { + this.panel = panel; + } + + @Override + public void run() { + ScheduledExecutorService tipToolTimer = createToastScheduleExecutorService(); + tipToolTimer.scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + SwingUtilities.invokeLater(()->{ + disappearStep(tipToolTimer); + }); + } + }, 0, 50, TimeUnit.MILLISECONDS); + } + + void disappearStep(ScheduledExecutorService timer) { + Point point = panel.getLocation(); + if (point.y <= -hideHeight && !timer.isShutdown()) { + timer.shutdown(); + SimpleToast.this.setVisible(false); + SimpleToast.this.dispose(); + SimpleToast.this.show = false; + } + panel.setLocation(point.x, point.y - 5); + Dimension dimension = SimpleToast.this.getSize(); + SimpleToast.this.setSize(new Dimension(dimension.width, dimension.height - 5)); + } + } + + private void disappear(JPanel outerPanel) { + disappear(outerPanel, DEFAULT_DISAPPEAR_DELAY, DEFAULT_TIME_UNIT); + } + + private ScheduledExecutorService createToastScheduleExecutorService() { + return ModuleContext.getExecutor().newSingleThreadScheduledExecutor(new NamedThreadFactory(TOAST_MSG_TIMER)); + } + + @Override + public void checkValid() throws Exception { + } + + public void setVisible(boolean visible) { + super.setVisible(visible); + if (visible) { + display(contentPane); + } + } + + @Override + public void dispose() { + super.dispose(); + } + +} \ No newline at end of file diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/action/StartUseAction.java b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/action/StartUseAction.java index 0afd89308f..2315fbb0ed 100644 --- a/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/action/StartUseAction.java +++ b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/action/StartUseAction.java @@ -1,10 +1,20 @@ package com.fr.design.mainframe.alphafine.action; +import com.fr.common.util.Strings; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.alphafine.AlphaFineHelper; +import com.fr.design.mainframe.alphafine.download.FineMarketConstants; +import com.fr.design.mainframe.alphafine.download.FineMarketDownloadManager; import com.fr.design.mainframe.alphafine.model.TemplateResourceDetail; -import com.fr.design.mainframe.alphafine.search.helper.FineMarketClientHelper; +import com.fr.file.FileFILE; +import com.fr.log.FineLoggerFactory; +import javax.swing.SwingWorker; +import java.awt.Desktop; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.io.File; +import java.io.IOException; /** @@ -24,6 +34,53 @@ public class StartUseAction implements ActionListener { @Override public void actionPerformed(ActionEvent e) { - FineMarketClientHelper.getInstance().openBrowserAndDownload(resourceDetail.getRoot()); + new SwingWorker() { + + @Override + protected String doInBackground() throws Exception { + return FineMarketDownloadManager.getInstance().installResource(resourceDetail.getRoot(), AlphaFineHelper.getAlphaFineDialog()); + } + + @Override + protected void done() { + try { + open(get()); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e, e.getMessage()); + } + super.done(); + } + }.execute(); + } + + void open(String fileName) throws IOException { + if (Strings.isEmpty(fileName)) { + return; + } + File fileNeedOpen = new File(fileName); + if (fileName.endsWith(FineMarketConstants.ZIP)) { + File[] files = fileNeedOpen.listFiles(); + fileNeedOpen = getFirstCptOrFrm(files); + } else if (fileName.endsWith(FineMarketConstants.RAR)) { + // rar直接打开系统文件夹 + File parentDir = new File(fileName).getParentFile(); + Desktop.getDesktop().open(parentDir); + return; + } + openInDesigner(fileNeedOpen); + } + + void openInDesigner(File file) { + DesignerContext.getDesignerFrame().openTemplate(new FileFILE(file)); + } + + + private File getFirstCptOrFrm(File[] files) { + for (File f : files) { + if (f.getName().endsWith(FineMarketConstants.CPT) || f.getName().endsWith(FineMarketConstants.FRM)) { + return f; + } + } + return null; } -} \ No newline at end of file +} diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/download/FineMarketConstants.java b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/download/FineMarketConstants.java new file mode 100644 index 0000000000..f17095b093 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/download/FineMarketConstants.java @@ -0,0 +1,10 @@ +package com.fr.design.mainframe.alphafine.download; + +public class FineMarketConstants { + + public static final String REPORTLETS = "/reportlets"; + public static final String ZIP = ".zip"; + public static final String RAR = ".rar"; + public static final String CPT = ".cpt"; + public static final String FRM = ".frm"; +} diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/download/FineMarketDownloadManager.java b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/download/FineMarketDownloadManager.java new file mode 100644 index 0000000000..08a7853119 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/download/FineMarketDownloadManager.java @@ -0,0 +1,149 @@ +package com.fr.design.mainframe.alphafine.download; + +import com.fr.base.svg.IconUtils; +import com.fr.common.util.Strings; +import com.fr.design.DesignerEnvManager; +import com.fr.design.extra.Process; +import com.fr.design.i18n.Toolkit; +import com.fr.design.login.DesignerLoginHelper; +import com.fr.design.login.DesignerLoginSource; +import com.fr.design.mainframe.alphafine.AlphaFineHelper; +import com.fr.design.mainframe.alphafine.model.TemplateResource; +import com.fr.design.mainframe.alphafine.search.helper.FineMarketClientHelper; +import com.fr.design.mainframe.toast.SimpleToast; +import com.fr.log.FineLoggerFactory; +import com.fr.third.jodd.io.ZipUtil; +import com.fr.workspace.WorkContext; + +import javax.swing.SwingUtilities; +import java.awt.Window; +import java.io.File; +import java.io.IOException; +import java.util.HashMap; + + +/** + * 在这里统一管理帆软市场的下载 + * 下载的流程控制尽量都在这个类内部完成 + * 通过Process类来实现下载流程控制 + * */ +public class FineMarketDownloadManager { + + private static final FineMarketDownloadManager INSTANCE = new FineMarketDownloadManager(); + public static final FineMarketDownloadManager getInstance() { + return INSTANCE; + } + + + public static final double PROCESS_SUCCESS = 1d; + public static final double PROCESS_FAILED = -1d; + public static final double OPENING_FILE = 2d; + + private static final String OPENING_PLEASE_WAIT = Toolkit.i18nText("Fine-Design_Report_AlphaFine_Template_Resource_Opening"); + private static final String DOWNLOAD_FAILED = Toolkit.i18nText("Fine-Design_Report_AlphaFine_Template_Resource_Download_Failed_Check_Network"); + + + /** + * 下载资源并解压 + * */ + public String installResource(TemplateResource resource, Window parentWindow){ + // 验证登录 + String token = DesignerEnvManager.getEnvManager().getDesignerLoginRefreshToken(); + if (Strings.isEmpty(token)) { + DesignerLoginHelper.showLoginDialog(DesignerLoginSource.NORMAL, new HashMap<>(), AlphaFineHelper.getAlphaFineDialog()); + return null; + } + return install(resource, parentWindow); + } + + private String install(TemplateResource resource, Window parentWindow) { + // 获取报表录作为下载位置 + String workDir = WorkContext.getCurrent().getPath() + FineMarketConstants.REPORTLETS; + File destDir = new File(workDir); + + DownloadProcess downloadProcess = new DownloadProcess(parentWindow); + String fileName = null; + try { + fileName = FineMarketClientHelper.getInstance().download(resource, destDir, downloadProcess); + unzip(fileName, downloadProcess); + return fileName; + } catch (Exception e) { + downloadProcess.process(FineMarketDownloadManager.PROCESS_FAILED); + FineLoggerFactory.getLogger().error(e, e.getMessage()); + } + return null; + } + + void unzip(String fileName, DownloadProcess process) throws IOException { + process.process(OPENING_FILE); + + if (fileName.endsWith(FineMarketConstants.ZIP)) { + File file = new File(fileName); + File parentDir = file.getParentFile(); + ZipUtil.unzip(file, parentDir); + } + } + + + + + /** + * 下载流程控制,主要控制ui的显示 + * */ + class DownloadProcess implements Process { + + SimpleToast downloadingToast; + SimpleToast openingToast; + SimpleToast failedToast; + Window parent; + + public DownloadProcess(Window parentWindow) { + this.parent = parentWindow; + init(); + } + + void init() { + showLoadingToast(); + } + + @Override + public void process(Double aDouble) { + SwingUtilities.invokeLater(()->{ + if (aDouble == PROCESS_FAILED) { + downloadFailed(); + } else if (aDouble == PROCESS_SUCCESS) { + downloadSuccess(); + } else if (aDouble == OPENING_FILE) { + openingFile(); + } + }); + } + + public void downloadFailed() { + downloadingToast.setVisible(false); + showFailedToast(); + } + + public void downloadSuccess() { + downloadingToast.setVisible(false); + } + + + private void openingFile() { + downloadingToast.setVisible(false); + openingToast = new SimpleToast(AlphaFineHelper.getAlphaFineDialog(), IconUtils.readIcon("/com/fr/design/mainframe/alphafine/images/loading.svg"), OPENING_PLEASE_WAIT, true); + openingToast.setVisible(true); + } + + private void showLoadingToast() { + downloadingToast = new SimpleToast(AlphaFineHelper.getAlphaFineDialog(), IconUtils.readIcon("/com/fr/design/mainframe/alphafine/images/loading.svg"), OPENING_PLEASE_WAIT, false); + downloadingToast.setVisible(true); + } + + private void showFailedToast() { + failedToast = new SimpleToast(AlphaFineHelper.getAlphaFineDialog(), IconUtils.readIcon("/com/fr/design/mainframe/alphafine/images/caution.svg"), DOWNLOAD_FAILED, true); + failedToast.setVisible(true); + } + + } +} diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/model/TemplateResource.java b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/model/TemplateResource.java index 93d1f4d0a2..56cc25a0c0 100644 --- a/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/model/TemplateResource.java +++ b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/model/TemplateResource.java @@ -1,6 +1,8 @@ package com.fr.design.mainframe.alphafine.model; +import com.fr.common.util.Strings; import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.alphafine.download.FineMarketConstants; import com.fr.design.mainframe.alphafine.search.manager.impl.TemplateResourceSearchManager; import com.fr.general.IOUtils; import com.fr.json.JSONArray; @@ -46,6 +48,7 @@ public class TemplateResource { public static final String IMAGE_URL = "pic"; public static final String DEMO_URL = "demoUrl"; public static final String PKG_SIZE = "pkgsize"; + public static final String FILE_NAME = "fileLoca"; private static final String RECOMMEND_SEARCH_IMG_URL = "com/fr/design/mainframe/alphafine/images/more.png"; @@ -57,6 +60,7 @@ public class TemplateResource { private Image image; private String name; private String demoUrl; + private String fileName; private int pkgSize; private List recommendSearchKey; @@ -74,7 +78,7 @@ public class TemplateResource { public static TemplateResource createByJson(JSONObject jsonObject) { TemplateResource templateResource = new TemplateResource().setId(jsonObject.getString(ID)).setUuid(jsonObject.getString(UUID)).setName(jsonObject.getString(NAME)) - .setDemoUrl(jsonObject.getString(DEMO_URL)).setPkgSize(jsonObject.getInt(PKG_SIZE)); + .setDemoUrl(jsonObject.getString(DEMO_URL)).setPkgSize(jsonObject.getInt(PKG_SIZE)).setFileName(jsonObject.getString(FILE_NAME)); int pkgSize = templateResource.getPkgSize(); if (pkgSize == 0) { templateResource.type = Type.SINGLE_TEMPLATE; @@ -110,6 +114,20 @@ public class TemplateResource { } + + public String getFileName() { + return fileName; + } + + public TemplateResource setFileName(String fileName) { + if (Strings.isEmpty(fileName)) { + this.fileName = getName() + FineMarketConstants.ZIP; + } else { + this.fileName = fileName; + } + return this; + } + public Type getType() { return type; } diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/search/helper/FineMarketClientHelper.java b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/search/helper/FineMarketClientHelper.java index 81a165ca06..52e7e3a802 100644 --- a/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/search/helper/FineMarketClientHelper.java +++ b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/search/helper/FineMarketClientHelper.java @@ -1,18 +1,42 @@ package com.fr.design.mainframe.alphafine.search.helper; +import com.fr.design.DesignerEnvManager; +import com.fr.design.extra.PluginConstants; +import com.fr.design.mainframe.alphafine.download.FineMarketDownloadManager; import com.fr.design.mainframe.alphafine.model.TemplateResource; -import com.fr.design.utils.BrowseUtils; +import com.fr.file.FileCommonUtils; import com.fr.general.CloudCenter; import com.fr.general.http.HttpToolbox; import com.fr.json.JSONArray; import com.fr.json.JSONObject; +import com.fr.log.FineLoggerFactory; +import com.fr.market.key.FineMarketPublicKeyHolder; +import com.fr.security.SecurityToolbox; +import com.fr.stable.StableUtils; +import com.fr.third.org.apache.http.HttpEntity; +import com.fr.third.org.apache.http.HttpException; +import com.fr.third.org.apache.http.HttpStatus; +import com.fr.third.org.apache.http.client.config.CookieSpecs; +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.HttpUriRequest; +import com.fr.third.org.apache.http.client.methods.RequestBuilder; +import com.fr.third.org.apache.http.impl.client.BasicCookieStore; +import com.fr.third.org.apache.http.impl.client.CloseableHttpClient; +import com.fr.third.org.apache.http.impl.client.HttpClients; import org.jetbrains.annotations.Nullable; +import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class FineMarketClientHelper { private static final FineMarketClientHelper INSTANCE = new FineMarketClientHelper(); @@ -20,10 +44,10 @@ public class FineMarketClientHelper { return INSTANCE; } + private static final String CERTIFICATE_PUBLIC_KEY = FineMarketPublicKeyHolder.getInstance().getDefaultKey(); public static final String FINE_MARKET_TEMPLATE_INFO = CloudCenter.getInstance().acquireUrlByKind("market.template.info"); public static final String FINE_MARKET_TEMPLATE_URL = CloudCenter.getInstance().acquireUrlByKind("market.template.url"); - public static final String LOGIN_FINE_CLUB_AND_REDIRECT_SHOP = CloudCenter.getInstance().acquireUrlByKind("af.login.redirect.market"); - public static final String FILE_DOWNLOAD = "file/"; + public static final String FILE_DOWNLOAD = "file/download/"; public static final String PACKAGE_DOWNLOAD = "package/download/"; public static final String TEMPLATES_PARENT_PACKAGE = "parent/"; public static final String TEMPLATES_TAGS = "filter"; @@ -46,44 +70,167 @@ public class FineMarketClientHelper { * */ public String getResourceDownloadUrl(TemplateResource templateResource) { if (TemplateResource.Type.SCENARIO_SOLUTION.equals(templateResource.getType())) { - return getPackageDownloadUrl(templateResource.getId()); + return getPackageDownloadUrl(); } else { - return getFileDownLoadUrl(templateResource.getId()); + return getFileDownLoadUrl(); } } - public void openBrowserAndDownload(TemplateResource templateResource) { - String url = LOGIN_FINE_CLUB_AND_REDIRECT_SHOP; - if (TemplateResource.Type.SCENARIO_SOLUTION.equals(templateResource.getType())) { - url += getPackageDownloadUrl(templateResource.getId()); + private String getPackageDownloadUrl() { + return FINE_MARKET_TEMPLATE_INFO + PACKAGE_DOWNLOAD; + } + + private String getFileDownLoadUrl() { + return FINE_MARKET_TEMPLATE_INFO + FILE_DOWNLOAD; + } + + + public String download(TemplateResource resource, File destDir, com.fr.design.extra.Process process) throws Exception { + String resourceId = resource.getId(); + + CloseableHttpResponse fileRes = getFileResponse(resource, resourceId); + + if (fileRes.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { + + File destFile = createDestFile(destDir, resource); + + StableUtils.makesureFileExist(destFile); + + InputStream content = null; + FileOutputStream writer = null; + try { + writer = new FileOutputStream(FileCommonUtils.getAbsolutePath(destFile)); + + HttpEntity entity = fileRes.getEntity(); + long totalSize = entity.getContentLength(); + content = entity.getContent(); + + + byte[] data = new byte[PluginConstants.BYTES_NUM]; + int bytesRead; + int totalBytesRead = 0; + + while ((bytesRead = content.read(data)) > 0) { + writer.write(data, 0, bytesRead); + data = new byte[PluginConstants.BYTES_NUM]; + totalBytesRead += bytesRead; + process.process(totalBytesRead / (double) totalSize); + } + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e, e.getMessage()); + } finally { + content.close(); + writer.flush(); + writer.close(); + } + + + FineLoggerFactory.getLogger().info("download resource{} success", resourceId); + process.process(FineMarketDownloadManager.PROCESS_SUCCESS); + + return FileCommonUtils.getAbsolutePath(destFile); } else { - url += getFileDownLoadUrl(templateResource.getId()); + FineLoggerFactory.getLogger().info("download resource{} failed", resourceId); + process.process(FineMarketDownloadManager.PROCESS_FAILED); + throw new HttpException(); } - BrowseUtils.browser(url); + } - /** - * 暂时没有package的下载接口,需要用户在浏览器点击下载 - * */ - private String getPackageDownloadUrl(String id) { - return getTemplateUrlById(id); + + private CloseableHttpResponse getFileResponse(TemplateResource resource, String resourceId) throws Exception { + CloseableHttpResponse fileRes = postDownloadHttpResponse(getResourceDownloadUrl(resource), resourceId); + if (fileRes.getStatusLine().getStatusCode() == HttpStatus.SC_MOVED_TEMPORARILY) { + fileRes = getDownloadHttpResponse(fileRes.getHeaders("Location")[0].getValue()); + } + return fileRes; } /** - * 打开浏览器,下载单一模板 + * 在目标路径下(destDir)创建与资源名称相同的文件夹 (finalDir) + * 将资源下载到 destDir/finalDir + * 如果文件重复,则在文件名前加自增id * */ - private String getFileDownLoadUrl(String id) { - return FINE_MARKET_TEMPLATE_INFO + FILE_DOWNLOAD + id; + private File createDestFile(File destDir, TemplateResource resource) { + String fileName = resource.getName(); + try { + File finalDir = new File(StableUtils.pathJoin(FileCommonUtils.getAbsolutePath(destDir), fileName)); + if (!finalDir.exists()) { + finalDir.mkdir(); + } + + // 获取文件名(含后缀) + fileName = resource.getFileName(); + + // 处理重复文件名 + String fileNameFormat = "(%d)" + fileName; + Pattern pattern = Pattern.compile("\\((\\d)\\)" + fileName); + int cnt = 0; + + File[] files = finalDir.listFiles(); + for (File f : files) { + Matcher matcher = pattern.matcher(f.getName()); + if (matcher.find()) { + cnt = Math.max(cnt, Integer.parseInt(matcher.group(1))); + } + } + cnt++; + fileName = String.format(fileNameFormat, cnt); + + + + File destFile = new File(StableUtils.pathJoin(FileCommonUtils.getAbsolutePath(finalDir), fileName)); + destFile.createNewFile(); + return destFile; + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e, e.getMessage()); + } + return null; } + private static CloseableHttpResponse getDownloadHttpResponse(String url) throws Exception { + //先登录一下。不然可能失败 + CloseableHttpClient client = createClient(); + HttpUriRequest file = RequestBuilder.get() + .setUri(url) + .build(); + return client.execute(file); + } + private static CloseableHttpResponse postDownloadHttpResponse(String url, String id) throws Exception { + return postDownloadHttpResponse(url, id, new HashMap<>()); + } - /** - * 获取帆软市场模板资源页面链接 - * */ - public String getFineMarketTemplateUrl() { - return FINE_MARKET_TEMPLATE_URL; + private static CloseableHttpResponse postDownloadHttpResponse(String url, String id, Map params) throws Exception { + //先登录一下。不然可能失败 + CloseableHttpClient client = createClient(); + FineLoggerFactory.getLogger().info("login fr-market"); + FineLoggerFactory.getLogger().info("start download resource {}", id); + RequestBuilder builder = RequestBuilder.post() + .setHeader("User-Agent", "Mozilla/5.0") + .setUri(url) + .addParameter("id", SecurityToolbox.encrypt(id, CERTIFICATE_PUBLIC_KEY)) + .addParameter("userId", String.valueOf(DesignerEnvManager.getEnvManager().getDesignerLoginUid())); + + if (params != null) { + Set keys = params.keySet(); + for (String key: keys) { + builder.addParameter(key, params.get(key)); + } + } + return client.execute(builder.build()); + } + + + private static CloseableHttpClient createClient() { + + BasicCookieStore cookieStore = new BasicCookieStore(); + return HttpClients.custom() + .setDefaultRequestConfig(RequestConfig.custom() + .setCookieSpec(CookieSpecs.STANDARD).build()) + .setDefaultCookieStore(cookieStore) + .build(); } public @Nullable JSONObject getTemplateInfoById(String id) throws IOException { diff --git a/designer-realize/src/main/java/com/fr/market/key/FineMarketDefaultKeyProperties.java b/designer-realize/src/main/java/com/fr/market/key/FineMarketDefaultKeyProperties.java new file mode 100644 index 0000000000..d17a617272 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/market/key/FineMarketDefaultKeyProperties.java @@ -0,0 +1,67 @@ +package com.fr.market.key; + +import com.fr.general.IOUtils; +import com.fr.io.utils.ResourceIOUtils; +import com.fr.log.FineLoggerFactory; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +/** + * @author Link + * @version 11.0 + * Created by Yvan on 2022/8/25 + */ +public class FineMarketDefaultKeyProperties { + + private Properties properties = new Properties(); + + private Map publicKeyMap = new HashMap<>(); + + private String propertyPath; + + private FineMarketDefaultKeyProperties(String propertyPath) { + this.propertyPath = propertyPath; + load(); + } + + public static FineMarketDefaultKeyProperties create(String propertyPath) { + return new FineMarketDefaultKeyProperties(propertyPath); + } + + private void load() { + try (InputStream inputStream = IOUtils.readResource(getPropertyPath())) { + byte[] data = ResourceIOUtils.inputStream2Bytes(inputStream); + properties.load(new ByteArrayInputStream(data)); + trims(properties); + publicKeyMap.put(FineMarketPublicKeyConstants.DEFAULT_KEY_KEY, properties.getProperty(FineMarketPublicKeyConstants.DEFAULT_KEY_KEY)); + } catch (IOException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + } + + private String getPropertyPath() { + return this.propertyPath; + } + + public String getPublicKey() { + return publicKeyMap.get(FineMarketPublicKeyConstants.DEFAULT_KEY_KEY); + } + + /** + * 去除properties中value末尾的空格 + * @param properties + */ + public static void trims(Properties properties) { + for (String key : properties.stringPropertyNames()) { + String value = properties.getProperty(key); + if (value != null) { + properties.put(key, value.trim()); + } + } + } +} diff --git a/designer-realize/src/main/java/com/fr/market/key/FineMarketPublicKeyConstants.java b/designer-realize/src/main/java/com/fr/market/key/FineMarketPublicKeyConstants.java new file mode 100644 index 0000000000..cab87bec38 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/market/key/FineMarketPublicKeyConstants.java @@ -0,0 +1,29 @@ +package com.fr.market.key; + + +/** + * @author Link + * @version 11.0 + * Created by Link on 2022/8/25 + */ +public class FineMarketPublicKeyConstants { + + public static final String DEFAULT_KEY_KEY = "defaultKey"; + + public static final String DEFAULT_KEY_DIRECTORY = "/com/fr/market/key"; + + /** + * 公钥第一段 + */ + public static final String FIRST_PROPERTY = "76c1/default"; + + /** + * 公钥第二段 + */ + public static final String SECOND_PROPERTY = "943f/default"; + + /** + * 公钥第三段 + */ + public static final String THIRD_PROPERTY = "d8a3/default"; +} diff --git a/designer-realize/src/main/java/com/fr/market/key/FineMarketPublicKeyHolder.java b/designer-realize/src/main/java/com/fr/market/key/FineMarketPublicKeyHolder.java new file mode 100644 index 0000000000..b37493559f --- /dev/null +++ b/designer-realize/src/main/java/com/fr/market/key/FineMarketPublicKeyHolder.java @@ -0,0 +1,48 @@ +package com.fr.market.key; + +import com.fr.stable.StableUtils; + +/** + * 帆软市场公钥Holder + * @author Link + * @version 10.0 + * Created by Link on 2022/8/25 + */ +public class FineMarketPublicKeyHolder { + + private static FineMarketPublicKeyHolder instance = null; + + private String defaultKey; + + public static FineMarketPublicKeyHolder getInstance() { + + if (instance == null) { + synchronized (FineMarketPublicKeyHolder.class) { + if (instance == null) { + instance = new FineMarketPublicKeyHolder(); + } + } + } + return instance; + } + + private FineMarketPublicKeyHolder() { + init(); + } + + private void init() { + // 读取三个default.properties文件,组成公钥 + String firstPart = FineMarketDefaultKeyProperties.create(StableUtils.pathJoin(FineMarketPublicKeyConstants.DEFAULT_KEY_DIRECTORY, FineMarketPublicKeyConstants.FIRST_PROPERTY)).getPublicKey(); + String secondPart = FineMarketDefaultKeyProperties.create(StableUtils.pathJoin(FineMarketPublicKeyConstants.DEFAULT_KEY_DIRECTORY, FineMarketPublicKeyConstants.SECOND_PROPERTY)).getPublicKey(); + String thirdPart = FineMarketDefaultKeyProperties.create(StableUtils.pathJoin(FineMarketPublicKeyConstants.DEFAULT_KEY_DIRECTORY, FineMarketPublicKeyConstants.THIRD_PROPERTY)).getPublicKey(); + this.defaultKey = firstPart + secondPart + thirdPart; + } + + /** + * 获取默认公钥 + * @return 公钥 + */ + public String getDefaultKey() { + return this.defaultKey; + } +} diff --git a/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/caution.svg b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/caution.svg new file mode 100644 index 0000000000..731e79d0d8 --- /dev/null +++ b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/caution.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/loading.svg b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/loading.svg new file mode 100644 index 0000000000..1df6ef5f20 --- /dev/null +++ b/designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/loading.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-realize/src/main/resources/com/fr/market/key/76c1/default b/designer-realize/src/main/resources/com/fr/market/key/76c1/default new file mode 100644 index 0000000000..58044d9c0b --- /dev/null +++ b/designer-realize/src/main/resources/com/fr/market/key/76c1/default @@ -0,0 +1 @@ +defaultKey=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCtsz62CPSWXZE/IYZRiAuTSZkw \ No newline at end of file diff --git a/designer-realize/src/main/resources/com/fr/market/key/943f/default b/designer-realize/src/main/resources/com/fr/market/key/943f/default new file mode 100644 index 0000000000..80946f51c9 --- /dev/null +++ b/designer-realize/src/main/resources/com/fr/market/key/943f/default @@ -0,0 +1 @@ +defaultKey=1WOwer8+JFktK0uKLAUuQoBr+UjAMFtRA8W7JgKMDwZy/2liEAiXEOSPU/hrdV8D \ No newline at end of file diff --git a/designer-realize/src/main/resources/com/fr/market/key/d8a3/default b/designer-realize/src/main/resources/com/fr/market/key/d8a3/default new file mode 100644 index 0000000000..af41473f36 --- /dev/null +++ b/designer-realize/src/main/resources/com/fr/market/key/d8a3/default @@ -0,0 +1 @@ +defaultKey=tT541LnGi1X/hXiRwuttPWYN3L2GYm/d5blU+FBNwghBIrdAxXTzYBc6P4KL/oYXnMdTIrkz8tYkG3QoFQIDAQAB \ No newline at end of file