From 557873b3e3348fa58a51cb76189ba75f2b3a88b9 Mon Sep 17 00:00:00 2001 From: "Bruce.Deng" Date: Wed, 2 Jun 2021 10:43:55 +0800 Subject: [PATCH] =?UTF-8?q?REPORT-52525=20=E8=AE=BE=E8=AE=A1=E5=99=A8?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E9=9B=86=E6=9F=A5=E8=AF=A2=E7=95=8C=E9=9D=A2?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=A4=8D=E5=88=B6=E4=BC=A0=E5=8F=82=E5=90=8E?= =?UTF-8?q?sql=E7=9A=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../preview/sql/PreviewPerformedSqlPane.java | 264 ++++++++++++++++++ .../tabledatapane/DBTableDataPane.java | 17 ++ .../design/dialog/link/MessageWithLink.java | 18 +- .../java/com/fr/design/gui/UILookAndFeel.java | 1 + .../fr/design/images/lookandfeel/TipIcon.png | Bin 0 -> 402 bytes .../fr/design/images/m_file/preview_sql.png | Bin 0 -> 366 bytes 6 files changed, 297 insertions(+), 3 deletions(-) create mode 100644 designer-base/src/main/java/com/fr/design/data/datapane/preview/sql/PreviewPerformedSqlPane.java create mode 100644 designer-base/src/main/resources/com/fr/design/images/lookandfeel/TipIcon.png create mode 100644 designer-base/src/main/resources/com/fr/design/images/m_file/preview_sql.png diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/preview/sql/PreviewPerformedSqlPane.java b/designer-base/src/main/java/com/fr/design/data/datapane/preview/sql/PreviewPerformedSqlPane.java new file mode 100644 index 000000000..f0ed78c5a --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/datapane/preview/sql/PreviewPerformedSqlPane.java @@ -0,0 +1,264 @@ +package com.fr.design.data.datapane.preview.sql; + +import com.fr.base.Parameter; +import com.fr.base.ParameterHelper; +import com.fr.base.ParameterMapNameSpace; +import com.fr.data.impl.DBTableData; +import com.fr.data.impl.EscapeSqlHelper; +import com.fr.data.operator.DataOperator; +import com.fr.decision.webservice.v10.config.ConfigService; +import com.fr.design.dialog.DialogActionAdapter; +import com.fr.design.dialog.link.MessageWithLink; +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.parameter.ParameterInputPane; +import com.fr.design.utils.gui.GUICoreUtils; +import com.fr.plugin.injectable.PluginModule; +import com.fr.script.Calculator; +import com.fr.stable.ArrayUtils; +import com.fr.stable.ParameterProvider; +import com.fr.stable.StringUtils; +import com.fr.stable.fun.TableDataProvider; +import com.fr.stable.plugin.ExtraClassManagerProvider; +import com.fr.stable.script.NameSpace; + +import javax.swing.BorderFactory; +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.UIManager; +import javax.swing.text.BadLocationException; +import javax.swing.text.DefaultHighlighter; +import javax.swing.text.Highlighter; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Cursor; +import java.awt.Frame; +import java.awt.datatransfer.StringSelection; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class PreviewPerformedSqlPane extends JDialog implements ActionListener { + + private JPanel topPanel; + private JPanel centerPanel; + private JPanel bottomPanel; + + private UILabel imageLabel; + + public PreviewPerformedSqlPane(Frame frame, String sql) { + this(frame, sql, null, null, false); + } + + public PreviewPerformedSqlPane(Frame frame, String sql, List selectedSpecialCharIndex, String[] selectedSpecialChar, boolean highlight) { + super(frame, true); + // 提示信息 + topPanel = FRGUIPaneFactory.createBorderLayout_L_Pane(); + JPanel imagePanel = new JPanel(); + JPanel messagePanel; + + if (isShowSpecialCharSqlPane(selectedSpecialCharIndex)) { + imageLabel = new UILabel(UIManager.getIcon("OptionPane.warningIcon")); + MessageWithLink message = new MessageWithLink(Toolkit.i18nText("Fine-Design_Basic_Preview_Special_Char_Sql_Front_Message"), Toolkit.i18nText("Fine-Design_Basic_Sql_Injection_Prevention"), "https://help.fanruan.com/finereport/doc-view-2219.html", Toolkit.i18nText("Fine-Design_Basic_Preview_Special_Char_Sql_Back_Message")); + messagePanel = new JPanel(); + messagePanel.setLayout(FRGUIPaneFactory.createBorderLayout()); + messagePanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 0, 0)); + messagePanel.add(message); + // 提示图标 + JPanel tipPanel = FRGUIPaneFactory.createBorderLayout_L_Pane(); + UILabel tipLabel = new UILabel(UIManager.getIcon("OptionPane.tipIcon")); + StringBuilder textBuilder = new StringBuilder(); + textBuilder.append("").append(Toolkit.i18nText("Fine-Design_Basic_Processed_Special_Char")).append("
"); + for (String sChar : selectedSpecialChar) { + textBuilder.append(sChar).append("
"); + } + textBuilder.append(""); + tipLabel.setToolTipText(textBuilder.toString()); + tipPanel.add(tipLabel, BorderLayout.SOUTH); + topPanel.add(tipPanel, BorderLayout.EAST); + } else { + imageLabel = new UILabel(UIManager.getIcon("OptionPane.informationIcon")); + messagePanel = FRGUIPaneFactory.createVerticalFlowLayout_S_Pane(true); + JLabel label = new JLabel(Toolkit.i18nText("Fine-Design_Basic_Preview_Performed_Sql_Message")); + messagePanel.add(label); + } + imagePanel.add(imageLabel); + + topPanel.add(imagePanel, BorderLayout.WEST); + topPanel.add(messagePanel, BorderLayout.CENTER); + topPanel.setBorder(BorderFactory.createEmptyBorder(10,10,0,10)); + + //中间的SQL面板 + centerPanel = FRGUIPaneFactory.createBorderLayout_L_Pane(); + centerPanel.setBorder(BorderFactory.createEmptyBorder(0,10,10,10)); + JScrollPane scrollPane = new JScrollPane(); + JTextArea checkArea = new JTextArea(sql); + checkArea.setEditable(false); + checkArea.setCursor(new Cursor(Cursor.TEXT_CURSOR)); + if (highlight) { + Highlighter highLighter = checkArea.getHighlighter(); + DefaultHighlighter.DefaultHighlightPainter p = new DefaultHighlighter.DefaultHighlightPainter(Color.ORANGE); + for (int[] specialCharIndex : selectedSpecialCharIndex) { + try { + highLighter.addHighlight(specialCharIndex[0], specialCharIndex[1], p); + } catch (BadLocationException e) { + e.printStackTrace(); + } + } + } + scrollPane.setViewportView(checkArea); + scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); + centerPanel.add(scrollPane); + + //底部的按钮面板 + UIButton okButton = new UIButton(Toolkit.i18nText("Fine-Design_Report_OK")); + okButton.addActionListener(this); + bottomPanel = FRGUIPaneFactory.createBorderLayout_L_Pane(); + bottomPanel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10)); + bottomPanel.add(okButton, BorderLayout.EAST); + + this.setTitle(Toolkit.i18nText("Fine-Design_Basic_Preview_Performed_Sql")); + this.setResizable(false); + this.add(topPanel, BorderLayout.NORTH); + this.add(centerPanel, BorderLayout.CENTER); + this.add(bottomPanel, BorderLayout.SOUTH); + this.setSize(600, 400); + + GUICoreUtils.centerWindow(this); + } + + public static void previewPerformedSql(DBTableData tableData) { + Calculator calculator = Calculator.createCalculator(); + //参数 + ParameterProvider[] parameters = DataOperator.getInstance().getTableDataParameters(tableData); + if (ArrayUtils.isEmpty(parameters)) { + parameters = tableData.getParameters(Calculator.createCalculator()); + } + Map parameterMap = new HashMap<>(); + if (needInputParams(parameters)) { + showParaWindow(parameterMap, parameters); + } else { + for (ParameterProvider parameter : parameters) { + parameterMap.put(parameter.getName(), parameter.getValue()); + } + } + boolean showOriginSql = true; + for (ParameterProvider parameter : DataOperator.getInstance().getTableDataParameters(tableData)) { + if (parameterMap.containsKey(parameter.getName())) { + Object value = parameterMap.get(parameter.getName()); + if (value != null && !StringUtils.EMPTY.equals(value)) { + showOriginSql = false; + } + parameter.setValue(value); + } + } + String sql; + // 计算高亮文本位置 + List specialCharParamIndex = null; + boolean highlight = true; + if (showOriginSql) { + sql = tableData.getQuery(); + } else { + NameSpace ns = ParameterMapNameSpace.create(parameterMap); + calculator.pushNameSpace(ns); + Parameter[] paras = processParameters(tableData, calculator); + // 所有被转义参数的集合 + Set specialCharParam = EscapeSqlHelper.getInstance().getSpecialCharParam(paras); + // 将参数转义等 + Set tableDataProviders = getTableDataProviders(); + for (TableDataProvider provider : tableDataProviders) { + provider.processParametersBeforeAnalyzeSQL(paras, calculator); + } + + if (!specialCharParam.isEmpty()) { + specialCharParamIndex = ParameterHelper.analyzeCurrentContextTableData4Template(tableData.getQuery(), paras, specialCharParam); + } + String oldSql = ParameterHelper.analyzeCurrentContextTableData4Templatee(tableData.getQuery(), paras); + sql = processExtraSQL(paras, oldSql, calculator, tableDataProviders); + if (oldSql.length() != sql.length()) { + highlight = false; + } + } + // sql内容复制到剪切板 + StringSelection selection = new StringSelection(sql); + java.awt.Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection, selection); + // 弹窗 + PreviewPerformedSqlPane pane; + if (isShowSpecialCharSqlPane(specialCharParamIndex)) { + pane = new PreviewPerformedSqlPane(DesignerContext.getDesignerFrame(), sql, specialCharParamIndex, ConfigService.getInstance().getPSIConfig().getSelectedSpecialChar(), highlight); + } else { + pane = new PreviewPerformedSqlPane(DesignerContext.getDesignerFrame(), sql); + } + pane.setVisible(true); + } + + private static boolean isShowSpecialCharSqlPane(List specialCharParamIndex) { + return specialCharParamIndex != null && !specialCharParamIndex.isEmpty(); + } + + private static Parameter[] processParameters(DBTableData tableData, Calculator calculator) { + Collection parameters = tableData.getParameters(); + if (parameters.size() == 0) { + tableData.setParameters(ParameterHelper.analyze4Parameters(tableData.getQuery(), false)); + return new Parameter[0]; + } + return Parameter.providers2Parameter(Calculator.processParameters(calculator, parameters.toArray(new ParameterProvider[parameters.size()]))); + } + + private static String processExtraSQL(Parameter[] ps, String sql, Calculator ca, Set tableDataProviders) { + for (TableDataProvider provider : tableDataProviders) { + String newSql = provider.processTableDataSQL(ps, sql, ca); + if (StringUtils.isNotEmpty(newSql)) { + sql = newSql; + } + } + return sql; + } + + private static boolean needInputParams(ParameterProvider[] parameters) { + if (ArrayUtils.isNotEmpty(parameters)) { + return true; + } + for (ParameterProvider parameter : parameters) { + if (parameter.getValue() == null || StringUtils.EMPTY.equals(parameter.getValue())) { + return true; + } + } + return false; + } + + private static void showParaWindow(final Map parameterMap, ParameterProvider[] inParameters) { + final ParameterInputPane pPane = new ParameterInputPane(inParameters); + pPane.showSmallWindow(new JFrame(), new DialogActionAdapter() { + @Override + public void doOk() { + parameterMap.putAll(pPane.update()); + } + }).setVisible(true); + } + + private static Set getTableDataProviders() { + ExtraClassManagerProvider classManagerProvider = PluginModule.getAgent(PluginModule.ExtraCore); + if (classManagerProvider == null) { + return new HashSet<>(); + } + return classManagerProvider.getArray(TableDataProvider.XML_TAG, EscapeSqlHelper.getInstance()); + } + + @Override + public void actionPerformed(ActionEvent e) { + this.dispose(); + } +} diff --git a/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/DBTableDataPane.java b/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/DBTableDataPane.java index 6065d0485..fecf9c079 100644 --- a/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/DBTableDataPane.java +++ b/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/DBTableDataPane.java @@ -16,6 +16,7 @@ import com.fr.design.constants.UIConstants; import com.fr.design.data.datapane.connect.ConnectionTableProcedurePane; import com.fr.design.data.datapane.connect.ConnectionTableProcedurePane.DoubleClickSelectedNodeOnTreeListener; import com.fr.design.data.datapane.preview.PreviewTablePane; +import com.fr.design.data.datapane.preview.sql.PreviewPerformedSqlPane; import com.fr.design.data.datapane.sqlpane.SQLEditPane; import com.fr.design.dialog.BasicDialog; import com.fr.design.dialog.BasicPane; @@ -35,6 +36,7 @@ import com.fr.design.menu.ToolBarDef; import com.fr.design.utils.ParameterUtils; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.general.ComparatorUtils; +import com.fr.general.IOUtils; import com.fr.general.sql.SqlUtils; import com.fr.log.FineLoggerFactory; import com.fr.script.Calculator; @@ -227,6 +229,7 @@ public class DBTableDataPane extends AbstractTableDataPane { // p:工具栏. ToolBarDef toolBarDef = new ToolBarDef(); toolBarDef.addShortCut(new PreviewAction()); + toolBarDef.addShortCut(new PreviewPerformedSQLAction()); toolBarDef.addShortCut(SeparatorDef.DEFAULT); toolBarDef.addShortCut(new EditPageQueryAction()); dbTableDataMenuHandler = ExtraDesignClassManager.getInstance().getSingle(DBTableDataMenuHandler.MARK_STRING); @@ -368,6 +371,20 @@ public class DBTableDataPane extends AbstractTableDataPane { } } + private class PreviewPerformedSQLAction extends UpdateAction { + + public PreviewPerformedSQLAction() { + this.setName(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Preview_Performed_Sql")); + this.setSmallIcon(IOUtils.readIcon("/com/fr/design/images/m_file/preview_sql.png")); + } + + @Override + public void actionPerformed(ActionEvent e) { + checkParameter(); + PreviewPerformedSqlPane.previewPerformedSql(DBTableDataPane.this.updateBean()); + } + } + private class EditPageQueryAction extends UpdateAction { public EditPageQueryAction() { this.setName(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Layer_Page_Report_Page_Query")); diff --git a/designer-base/src/main/java/com/fr/design/dialog/link/MessageWithLink.java b/designer-base/src/main/java/com/fr/design/dialog/link/MessageWithLink.java index 889a0c3c9..2541a1b63 100644 --- a/designer-base/src/main/java/com/fr/design/dialog/link/MessageWithLink.java +++ b/designer-base/src/main/java/com/fr/design/dialog/link/MessageWithLink.java @@ -3,13 +3,14 @@ package com.fr.design.dialog.link; import com.fr.design.gui.ilable.UILabel; import com.fr.log.FineLoggerFactory; import com.fr.stable.StringUtils; + +import javax.swing.JEditorPane; +import javax.swing.event.HyperlinkEvent; +import javax.swing.event.HyperlinkListener; import java.awt.Color; import java.awt.Desktop; import java.awt.Font; import java.net.URI; -import javax.swing.JEditorPane; -import javax.swing.event.HyperlinkEvent; -import javax.swing.event.HyperlinkListener; /** * 用来构建JOptionPane带超链的消息提示 @@ -35,6 +36,10 @@ public class MessageWithLink extends JEditorPane { this(message, linkName, link, color, LABEL.getFont()); } + public MessageWithLink(String frontMessage, String linkName, String link, String backMessage) { + this(frontMessage, linkName, link, backMessage, LABEL.getBackground(), LABEL.getFont()); + } + public MessageWithLink(String message, String linkName, String link, Color color, Font font) { super("text/html", "" + message + "" + linkName + "" + ""); initListener(link); @@ -42,6 +47,13 @@ public class MessageWithLink extends JEditorPane { setBorder(null); } + public MessageWithLink(String frontMessage, String linkName, String link, String backMessage, Color color, Font font) { + super("text/html", "" + frontMessage + "" + linkName + "" + backMessage + ""); + initListener(link); + setEditable(false); + setBorder(null); + } + protected void initListener(String link) { addHyperlinkListener(new HyperlinkListener() { @Override diff --git a/designer-base/src/main/java/com/fr/design/gui/UILookAndFeel.java b/designer-base/src/main/java/com/fr/design/gui/UILookAndFeel.java index 4dbbc1af3..6d1a729d9 100644 --- a/designer-base/src/main/java/com/fr/design/gui/UILookAndFeel.java +++ b/designer-base/src/main/java/com/fr/design/gui/UILookAndFeel.java @@ -177,6 +177,7 @@ public class UILookAndFeel extends MetalLookAndFeel { table.put("OptionPane.narrow.down", loadIcon("Icon_Narrow_Down_16x16.png", this)); table.put("OptionPane.warningIcon", loadIcon("WarningIcon.png", this)); table.put("OptionPane.questionIcon", loadIcon("QuestionIcon.png", this)); + table.put("OptionPane.tipIcon", loadIcon("TipIcon.png", this)); table.put("ScrollPane.border", new UIScrollPaneBorder()); table.put("ProgressBar.border", new UIProgressBarBorder()); table.put("Spinner.border", new UITextFieldBorder(new Insets(2, 2, 2, 2))); diff --git a/designer-base/src/main/resources/com/fr/design/images/lookandfeel/TipIcon.png b/designer-base/src/main/resources/com/fr/design/images/lookandfeel/TipIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..5c9492502d1bc5501d78314e7be20685386d1414 GIT binary patch literal 402 zcmV;D0d4+?P)@j-@8M|`QYz<$8nYr%?2Xu0KoG1`xhd(AyQ2#<*VK^ z0x-6^ix{5)z-1KS#bD6uCW{M&QpK`p9{~1gVUuDP-Fl?r#Qc*1kf?!fI+qP}f zw62M;ks&FN{I+2j&q}E+y_s`<4uB|xSI@v9V&27ZypqI80mj@DL|PC+9O++n9A_QC z0x8>%dYyBAN`&ve?;WQA=WaKOpx)_tPx?Z}*ftTNl=4=uSF7%tWkE{_uaW^D{eEvT z48zY+fZrp6A%xh}>*aEJu2?L+3E|Dp1UPpeh`{iDZ{sguVuWeHScGYtI1L!v#2I63 w5n&SHVCEQyqs(!TGCkK(&X8P}=|4C73+o;05pf;-QUCw|07*qoM6N<$f-0J=WdHyG literal 0 HcmV?d00001 diff --git a/designer-base/src/main/resources/com/fr/design/images/m_file/preview_sql.png b/designer-base/src/main/resources/com/fr/design/images/m_file/preview_sql.png new file mode 100644 index 0000000000000000000000000000000000000000..ba62d487a8e85617bb710f4cf281094da4e17e7d GIT binary patch literal 366 zcmV-!0g?WRP)p^BJ}zQyn%^{9n@6h zIxMV=l`&RU&~P{Yb77O&+s#?XCd17A^Urs)9ML}yhxyUSOQ>_1+0DyxGt2cFtqY(% z@5is+-y{InCaO8WLRL?|-@7A{Ne;`JKn}p}xZvQPJ*CO@3 zYSHQ1ATr{?djH%YnA;n*p%FD{wuAsx`ONlg!|GjibOmNU5b*=z5koaIEi_QeF(<4D zfbIs6Pvi;mT7*9|09-?RK_n*v;1i7z10pvSp)a_vbOLYxNhXg%1c3Gi`--``#Lz9X zEQxx0g>&cJ);XSHv(mz%KM{=~uKtX-<1{}{M0*rmS5^IP2TxZ20^#auzg>*?-2eap M07*qoM6N<$f;Xm}2mk;8 literal 0 HcmV?d00001