diff --git a/pom.xml b/pom.xml index 4737dfd..a1535fe 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ 10.0 jar - 10.0-PERSIST-SNAPSHOT + 10.0-FEATURE-SNAPSHOT yyyyMMdd ${version} ${maven.build.timestamp} @@ -121,6 +121,12 @@ 1.7.1 test + + com.squareup.okhttp3 + mockwebserver + 4.0.1 + test + ${project.artifactId}-${version}-${maven.build.timestamp} @@ -162,4 +168,28 @@ + + + fanruan + fanruan + http://mvn.finedevelop.com/repository/maven-public/ + + true + always + warn + + + + + + fanruan + fanruan + http://mvn.finedevelop.com/repository/maven-public/ + + true + always + warn + + + \ No newline at end of file diff --git a/readme.md b/readme.md index 9521aa8..6adaf32 100644 --- a/readme.md +++ b/readme.md @@ -24,7 +24,7 @@ SessionKit#getSession(@NotNull String sessionID); ## 提交新API要求 -* 所有的API方法的返回值和参数,仅允许使用基本类型、接口类型或者使用了@Open标记的对象类型。 +* 所有的API方法的返回值和参数,仅允许使用JDK自带的类、接口类型、插件抽象类、注解或者使用了@Open标记的对象类型。 * 所有的API方法均需要有单元测试覆盖。 @@ -38,4 +38,26 @@ SessionKit#getSession(@NotNull String sessionID); mvn package -Dmaven.test.skip=true ``` -会在target目录下获得一个形如finekit-10.0-20190815.jar名字jar包,直接作为插件依赖jar包即可。 \ No newline at end of file +会在target目录下获得一个形如finekit-10.0-20190815.jar名字jar包,直接作为插件依赖jar包即可。 + +## 已完全依赖FineKit的插件 + +|插件名|源码| +|-----|----| +|redis数据集插件|https://git.fanruan.com/fanruan/demo-tabledata-redis| +|增强公式编辑器插件|https://git.fanruan.com/fanruan/demo-formula-script +|条件属性之文本对齐插件|https://git.fanruan.com/fanruan/demo-highlight-align| + +## 如何判断插件中调用的API需要增加到FineKit中 + +最简单的原则:除了JDK自带的类、插件接口(包括抽象类)、以及使用了@Open注解标记的类之外,是否还使用了com.fanruan.api(com.fr.third除外)之外的类,如果有则需要修改。 + +## 如何提交新的API + +1、先访问[https://git.fanruan.com](https://git.fanruan.com)并注册一个自己的账号; + +2、然后将[https://git.fanruan.com/fanruan/finekit](https://git.fanruan.com/fanruan/finekit) fork到自己账户下; + +3、克隆FineKit代码到本地,新增相关的API代码,并提交到自己的仓库; + +4、提交Pull Request到FineKit主仓库,等待审核通过被合并即可。 \ No newline at end of file diff --git a/src/main/java/com/fanruan/api/cal/ContainerKit.java b/src/main/java/com/fanruan/api/cal/ContainerKit.java new file mode 100644 index 0000000..4dbbb0b --- /dev/null +++ b/src/main/java/com/fanruan/api/cal/ContainerKit.java @@ -0,0 +1,37 @@ +package com.fanruan.api.cal; + +import com.fr.general.FArray; +import com.fr.stable.ArrayProvider; + +import java.util.Collection; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2019-08-29 + * 创建容器的工具类 + */ +public class ContainerKit { + + /** + * 创建一个插件可识别的数组对象 + * + * @param array 原始数组 + * @param 数组元素类型 + * @return 插件可识别的数组对象 + */ + public static ArrayProvider newArray(T[] array) { + return new FArray<>(array); + } + + /** + * 创建一个插件可识别的数组对象 + * + * @param collection 原始集合 + * @param 数组元素类型 + * @return 插件可识别的数组对象 + */ + public static ArrayProvider newArray(Collection collection) { + return new FArray<>(collection); + } +} diff --git a/src/main/java/com/fanruan/api/cal/FormulaKit.java b/src/main/java/com/fanruan/api/cal/FormulaKit.java index 4e7c1ce..e863d2c 100644 --- a/src/main/java/com/fanruan/api/cal/FormulaKit.java +++ b/src/main/java/com/fanruan/api/cal/FormulaKit.java @@ -16,8 +16,8 @@ import org.jetbrains.annotations.Nullable; /** * @author richie * @version 10.0 - * Created by richie on 2019-08-15 - * 公式计算相关的工具类 + * Created by richie on 2019-08-15 + * 公式计算相关的工具类 */ public class FormulaKit { diff --git a/src/main/java/com/fanruan/api/cal/ParameterKit.java b/src/main/java/com/fanruan/api/cal/ParameterKit.java index 1c2717a..963e152 100644 --- a/src/main/java/com/fanruan/api/cal/ParameterKit.java +++ b/src/main/java/com/fanruan/api/cal/ParameterKit.java @@ -1,8 +1,8 @@ package com.fanruan.api.cal; +import com.fr.base.Parameter; import com.fr.base.ParameterHelper; import com.fr.base.ParameterMapNameSpace; -import com.fr.script.CalculatorMap; import com.fr.stable.ParameterProvider; import com.fr.stable.script.NameSpace; import org.jetbrains.annotations.NotNull; @@ -15,19 +15,54 @@ import java.util.Map; * Created by richie on 2019-08-16 * 参数相关的工具类 */ -public class ParameterKit{ +public class ParameterKit { + + /** + * 创建一个参数对象实例 + * + * @return 参数对象 + */ + public static ParameterProvider newParameter() { + return new Parameter(); + } + + /** + * 创建一个参数对象实例 + * + * @param name 参数名 + * @param value 参数值 + * @return 参数对象 + */ + public static ParameterProvider newParameter(String name, Object value) { + return new Parameter(name, value); + } + + /** + * 从字符串中分析中有哪些需要的参数 + * + * @param text 字符串 + * @param hasColumnRow 是否需要分析格子类型的参数 + * @return 字符串中包含的参数集合 + */ + public static Parameter[] analyze4Parameters(String text, boolean hasColumnRow) { + return ParameterHelper.analyze4Parameters(text, hasColumnRow); + } + /** * 分析公式中所携带的参数 + * * @param text 公式内容 * @return 参数数组 */ public static @NotNull ParameterProvider[] analyze4ParametersFromFormula(String text) { return ParameterHelper.analyze4ParametersFromFormula(text); } + /** * 分析一组字符串中的参数 + * * @param paramTexts 字符串组 - * @param isFormula 是否是公式类型的字符串数组 + * @param isFormula 是否是公式类型的字符串数组 * @return 参数集合 */ public static @NotNull ParameterProvider[] analyze4Parameters(String[] paramTexts, boolean isFormula) { @@ -36,19 +71,22 @@ public class ParameterKit{ /** * 创建一个用于计算的参数对名字空间 + * * @param map 参数键值对 * @return 名字空间,用于传递给算子做计算 */ public static @NotNull NameSpace createParameterMapNameSpace(Map map) { return ParameterMapNameSpace.create(map); } + /** * 创建一个用于计算的参数对名字空间 - * @param ps ParameterProvider的数组 + * + * @param ps 参数数组数组 * @return 名字空间,用于传递给算子做计算 */ - public static @NotNull ParameterMapNameSpace createParameterProvider(ParameterProvider[] ps) { + public static @NotNull ParameterMapNameSpace createParameterMapNameSpace(ParameterProvider[] ps) { return ParameterMapNameSpace.create(ps); } } diff --git a/src/main/java/com/fanruan/api/conf/BaseConfiguration.java b/src/main/java/com/fanruan/api/conf/BaseConfiguration.java index 4c5fbba..29147d6 100644 --- a/src/main/java/com/fanruan/api/conf/BaseConfiguration.java +++ b/src/main/java/com/fanruan/api/conf/BaseConfiguration.java @@ -7,6 +7,20 @@ import com.fr.config.DefaultConfiguration; * @author richie * @version 10.0 * Created by richie on 2019-08-16 + * 插件要实现配置类的时候,直接继承该抽象类即可 + *

+ * private static class MyConf extends BaseConfiguration { + * + * private static volatile MyConf instance = null; + * + * public static MyConf getInstance() { + * if (instance == null) { + * instance = getConfigInstance(MyConf.class); + * } + * return instance; + * } + * } + *

*/ public abstract class BaseConfiguration extends DefaultConfiguration { diff --git a/src/main/java/com/fanruan/api/consts/EncodeConstantsKit.java b/src/main/java/com/fanruan/api/consts/EncodeConstantsKit.java deleted file mode 100644 index ca90bab..0000000 --- a/src/main/java/com/fanruan/api/consts/EncodeConstantsKit.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.fanruan.api.consts; -import com.fr.stable.EncodeConstants; - -public class EncodeConstantsKit { - - public static final String ENCODING_UTF_8 = EncodeConstants.ENCODING_UTF_8; - - public static final String ENCODING_GBK = EncodeConstants.ENCODING_GBK; - - public static final String ENCODING_BIG5 = EncodeConstants.ENCODING_BIG5; - - public static final String ENCODING_ISO_8859_1 = EncodeConstants.ENCODING_ISO_8859_1; - - - public static final String ENCODING_UTF_16 = EncodeConstants.ENCODING_UTF_16; - - public static final String ENCODING_EUC_JP = EncodeConstants.ENCODING_EUC_JP; - - public static final String ENCODING_EUC_KR = EncodeConstants.ENCODING_EUC_KR; - - public static final String ENCODING_CP850 = EncodeConstants.ENCODING_CP850; -} diff --git a/src/main/java/com/fanruan/api/data/ConnectionKit.java b/src/main/java/com/fanruan/api/data/ConnectionKit.java new file mode 100644 index 0000000..ed64b99 --- /dev/null +++ b/src/main/java/com/fanruan/api/data/ConnectionKit.java @@ -0,0 +1,38 @@ +package com.fanruan.api.data; + +import com.fanruan.api.util.TypeKit; +import com.fr.data.impl.Connection; +import com.fr.file.ConnectionConfig; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * 数据连接相关工具类 + */ +public class ConnectionKit { + + /** + * 获取指定名字的数据连接 + * + * @param name 名字 + * @return 数据连接 + */ + public @Nullable Connection getConnection(@NotNull String name) { + return ConnectionConfig.getInstance().getConnection(name); + } + + /** + * 获取指定名字和指定类型的数据连接 + * + * @param name 数据连接的名字 + * @param type 类型 + * @return 数据连接 + */ + public @Nullable T getConnection(@NotNull String name, Class type) { + Connection connection = getConnection(name); + if (TypeKit.objectInstanceOf(connection, type)) { + return (T) connection; + } + return null; + } +} diff --git a/src/main/java/com/fanruan/api/data/connection/NameDatabaseConnection.java b/src/main/java/com/fanruan/api/data/connection/NameDatabaseConnection.java new file mode 100644 index 0000000..408e9e8 --- /dev/null +++ b/src/main/java/com/fanruan/api/data/connection/NameDatabaseConnection.java @@ -0,0 +1,4 @@ +package com.fanruan.api.data.connection; + +public class NameDatabaseConnection extends com.fr.data.impl.NameDatabaseConnection{ +} diff --git a/src/main/java/com/fanruan/api/design/DesignKit.java b/src/main/java/com/fanruan/api/design/DesignKit.java index ca39118..267c9cb 100644 --- a/src/main/java/com/fanruan/api/design/DesignKit.java +++ b/src/main/java/com/fanruan/api/design/DesignKit.java @@ -2,6 +2,7 @@ package com.fanruan.api.design; import com.fr.base.TableData; import com.fr.design.data.datapane.preview.PreviewTablePane; +import com.fr.design.i18n.Toolkit; public class DesignKit { /** @@ -11,4 +12,23 @@ public class DesignKit { public static void previewTableData(TableData tableData){ PreviewTablePane.previewTableData(tableData, -1, -1); } + + /** + * 文本国际化 + * @param key 国际化键 + * @return 国际化后的值 + */ + public static String i18nText(String key) { + return Toolkit.i18nText(key); + } + + /** + * 带参数的文本国际化 + * @param key 国际化键 + * @param args 参数 + * @return 国际化后的值 + */ + public static String i18nText(String key, Object... args) { + return Toolkit.i18nText(key, args); + } } diff --git a/src/main/java/com/fanruan/api/design/ui/action/UpdateAction.java b/src/main/java/com/fanruan/api/design/ui/action/UpdateAction.java index ce788ba..3a2bdf3 100644 --- a/src/main/java/com/fanruan/api/design/ui/action/UpdateAction.java +++ b/src/main/java/com/fanruan/api/design/ui/action/UpdateAction.java @@ -1,8 +1,8 @@ package com.fanruan.api.design.ui.action; -import java.awt.event.ActionEvent; +/** + * 用于各种菜单动作实现的抽象类 + */ +public abstract class UpdateAction extends com.fr.design.actions.UpdateAction { -public class UpdateAction extends com.fr.design.actions.UpdateAction{ - @Override - public void actionPerformed(ActionEvent evt) {} } diff --git a/src/main/java/com/fanruan/api/design/ui/component/UICheckBox.java b/src/main/java/com/fanruan/api/design/ui/component/UICheckBox.java new file mode 100644 index 0000000..ebc7998 --- /dev/null +++ b/src/main/java/com/fanruan/api/design/ui/component/UICheckBox.java @@ -0,0 +1,28 @@ +package com.fanruan.api.design.ui.component; + +import javax.swing.*; + +/** + * @author zhaojunzhe + * @version 10.0 + * Created by zhaojunzhe on 2019-08-28 + * 复选框组件 + */ +public class UICheckBox extends com.fr.design.gui.icheckbox.UICheckBox { + + public UICheckBox() { + } + + public UICheckBox(String text) { + super(text); + } + + + public UICheckBox(String text, boolean checked) { + super(text, checked); + } + + public UICheckBox(String text, Icon icon) { + super(text, icon); + } +} diff --git a/src/main/java/com/fanruan/api/design/ui/component/UIComboBox.java b/src/main/java/com/fanruan/api/design/ui/component/UIComboBox.java new file mode 100644 index 0000000..0210e71 --- /dev/null +++ b/src/main/java/com/fanruan/api/design/ui/component/UIComboBox.java @@ -0,0 +1,115 @@ +package com.fanruan.api.design.ui.component; + +import com.fanruan.api.util.AssistKit; +import com.fr.design.gui.itextfield.UITextField; +import com.fr.stable.Constants; +import com.fr.stable.StringUtils; + +import javax.swing.*; +import javax.swing.plaf.basic.BasicComboBoxEditor; +import java.awt.*; +import java.awt.event.ActionListener; +import java.lang.reflect.Method; +import java.util.List; +import java.util.Vector; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2019-08-28 + * 下拉框 + */ +public class UIComboBox extends com.fr.design.gui.icombobox.UIComboBox { + + public UIComboBox() { + super(); + } + + public UIComboBox(ComboBoxModel model) { + super(model); + } + + public UIComboBox(T[] items) { + super(items); + } + + public UIComboBox(Vector items) { + super(items); + } + + /** + * 重新设置下拉选项 + * + * @param list 下拉选项的集合 + */ + public void refreshSelectableItems(List list) { + T el = (T) getSelectedItem(); + removeAllItems(); + for (T t : list) { + addItem(t); + } + getModel().setSelectedItem(el); + } + + public static class UIComboBoxEditor extends BasicComboBoxEditor { + protected UITextField textField; + private Object oldValue; + + public UIComboBoxEditor() { + textField = new UITextField(); + textField.setRectDirection(Constants.RIGHT); + } + + @Override + public Component getEditorComponent() { + return textField; + } + + @Override + public void setItem(Object anObject) { + if (anObject != null) { + textField.setText(anObject.toString()); + oldValue = anObject; + } else { + textField.setText(StringUtils.EMPTY); + } + + } + + @Override + public Object getItem() { + Object newValue = textField.getText(); + if (oldValue != null && !(oldValue instanceof String)) { + if (AssistKit.equals(newValue, oldValue.toString())) { + return oldValue; + } else { + Class cls = oldValue.getClass(); + try { + Method method = cls.getMethod("valueOf", new Class[]{String.class}); + newValue = method.invoke(oldValue, new Object[]{textField.getText()}); + } catch (Exception ignore) { + + } + } + } + return newValue; + + } + + @Override + public void selectAll() { + textField.selectAll(); + textField.requestFocus(); + } + + @Override + public void addActionListener(ActionListener l) { + textField.addActionListener(l); + } + + @Override + public void removeActionListener(ActionListener l) { + textField.removeActionListener(l); + } + } +} diff --git a/src/main/java/com/fanruan/api/design/ui/component/UIDescriptionTextArea.java b/src/main/java/com/fanruan/api/design/ui/component/UIDescriptionTextArea.java new file mode 100644 index 0000000..9cf38e8 --- /dev/null +++ b/src/main/java/com/fanruan/api/design/ui/component/UIDescriptionTextArea.java @@ -0,0 +1,4 @@ +package com.fanruan.api.design.ui.component; + +public class UIDescriptionTextArea extends com.fr.design.gui.itextarea.DescriptionTextArea{ +} diff --git a/src/main/java/com/fanruan/api/design/ui/component/UIDictionaryComboBox.java b/src/main/java/com/fanruan/api/design/ui/component/UIDictionaryComboBox.java new file mode 100644 index 0000000..030b236 --- /dev/null +++ b/src/main/java/com/fanruan/api/design/ui/component/UIDictionaryComboBox.java @@ -0,0 +1,14 @@ +package com.fanruan.api.design.ui.component; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2019-08-28 + * 带字典数据的下拉框,显示值和实际值通过字典进行对应 + */ +public class UIDictionaryComboBox extends com.fr.design.gui.icombobox.UIDictionaryComboBox { + + public UIDictionaryComboBox(T[] keys, String[] values) { + super(keys, values); + } +} diff --git a/src/main/java/com/fanruan/api/design/ui/component/UIIntNumberField.java b/src/main/java/com/fanruan/api/design/ui/component/UIIntNumberField.java index 15b5c26..08dafa1 100644 --- a/src/main/java/com/fanruan/api/design/ui/component/UIIntNumberField.java +++ b/src/main/java/com/fanruan/api/design/ui/component/UIIntNumberField.java @@ -1,5 +1,29 @@ package com.fanruan.api.design.ui.component; +/** + * 整数控件,该控件只能输入整数数字 + */ public class UIIntNumberField extends com.fr.design.gui.itextfield.UIIntNumberField { + public UIIntNumberField() { + + } + + /** + * 获取整数数值 + * + * @return 整数值 + */ + public int getInt() { + return (int) getValue(); + } + + /** + * 设置整数数值 + * + * @param value 整数值 + */ + public void setInt(int value) { + setValue(value); + } } diff --git a/src/main/java/com/fanruan/api/design/ui/component/UILazyComboBox.java b/src/main/java/com/fanruan/api/design/ui/component/UILazyComboBox.java new file mode 100644 index 0000000..4e5e7d0 --- /dev/null +++ b/src/main/java/com/fanruan/api/design/ui/component/UILazyComboBox.java @@ -0,0 +1,191 @@ +package com.fanruan.api.design.ui.component; + + +import com.fanruan.api.design.DesignKit; +import com.fanruan.api.log.LogKit; +import com.fanruan.api.util.StringKit; + +import javax.swing.*; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.event.PopupMenuEvent; +import javax.swing.event.PopupMenuListener; +import java.awt.*; +import java.util.concurrent.ExecutionException; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2019-08-28 + * 懒加载下拉框,点击下拉之后才开始加载数据 + */ +public abstract class UILazyComboBox extends UIComboBox implements PopupMenuListener { + + private static final int NUM = 80; + private static final String[] PENDING_CONTENT = new String[]{StringKit.EMPTY, DesignKit.i18nText("Fine-Design_Basic_Loading") + "..."}; + + /** + * 是否加载完成 + */ + protected boolean loaded = false; + + /** + * 初始化选项 + */ + private Object initialSelected = null; + + + protected UILazyComboBox() { + super(); + this.setEditor(new UILazyComboBox.FilterComboBoxEditor()); + addPopupMenuListener(this); + } + + public void setLoaded(boolean loaded) { + this.loaded = loaded; + } + + /** + * 加载下拉框中的选项 + * + * @return 下拉框中的选项 + */ + public abstract Object[] load(); + + @Override + public void setSelectedItem(Object anObject) { + initialSelected = anObject; + if (loaded) { + super.setSelectedItem(anObject); + } else { + this.setModel(new DefaultComboBoxModel<>(new Object[]{anObject})); + super.setSelectedItem(anObject); + } + } + + @Override + public void popupMenuWillBecomeVisible(PopupMenuEvent e) { + if (loaded) { + return; + } + DefaultComboBoxModel loadingModel = new DefaultComboBoxModel<>(PENDING_CONTENT); + this.setModel(loadingModel); + new SwingWorker() { + + @Override + protected Object[] doInBackground() { + return load(); + } + + @Override + public void done() { + try { + UILazyComboBox.this.loadList(get()); + } catch (InterruptedException | ExecutionException exception) { + LogKit.debug(exception.getMessage()); + } + UILazyComboBox.this.showPopup(); + } + }.execute(); + } + + + /** + * 加载下拉列表 + */ + public void loadList() { + DefaultComboBoxModel model = new DefaultComboBoxModel<>(load()); + model.setSelectedItem(initialSelected); + this.setModel(model); + this.selectedItemReminder = initialSelected; + loaded = true; + } + + /** + * 加载下拉列表 + * + * @param contents 下拉列表内容 + */ + private void loadList(Object[] contents) { + DefaultComboBoxModel model = new DefaultComboBoxModel<>(contents); + model.setSelectedItem(initialSelected); + this.setModel(model); + this.selectedItemReminder = initialSelected; + loaded = true; + } + + @Override + public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { + + } + + @Override + public void popupMenuCanceled(PopupMenuEvent e) { + + } + + @Override + public Dimension getPreferredSize() { + Dimension dim = super.getPreferredSize(); + dim.width = NUM; + return dim; + } + + class FilterComboBoxEditor extends UIComboBoxEditor implements DocumentListener { + private Object item; + private volatile boolean filtering = false; + private volatile boolean setting = false; + + public FilterComboBoxEditor() { + super(); + textField.getDocument().addDocumentListener(this); + } + + @Override + public void setItem(Object item) { + if (filtering) { + return; + } + this.item = item; + this.setting = true; + textField.setSetting(true); + String newText = (item == null) ? "" : item.toString(); + textField.setText(newText); + textField.setSetting(false); + this.setting = false; + } + + @Override + public Object getItem() { + return this.item; + } + + @Override + public void insertUpdate(DocumentEvent e) { + handleChange(); + } + + @Override + public void removeUpdate(DocumentEvent e) { + handleChange(); + } + + @Override + public void changedUpdate(DocumentEvent e) { + handleChange(); + } + + void handleChange() { + if (setting) { + return; + } + filtering = true; + String xx = textField.getText(); + UILazyComboBox.this.setSelectedItem(xx); + this.item = textField.getText(); + + setPopupVisible(true); + filtering = false; + } + } +} diff --git a/src/main/java/com/fanruan/api/design/ui/component/UINumberField.java b/src/main/java/com/fanruan/api/design/ui/component/UINumberField.java new file mode 100644 index 0000000..22db55d --- /dev/null +++ b/src/main/java/com/fanruan/api/design/ui/component/UINumberField.java @@ -0,0 +1,45 @@ +package com.fanruan.api.design.ui.component; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2019-08-28 + * 数字文本框 + */ +public class UINumberField extends com.fr.design.gui.itextfield.UINumberField { + + /** + * 默认的数字文本框,限制最大的输入整数位数为32位,限制最大的小数输入位数为16位 + */ + public UINumberField() { + super(); + } + + /** + * 默认的数字文本框,限制最大的输入整数位数为32位,限制最大的小数输入位数为16位 + * @param columns 最大的文本输入列数 + */ + public UINumberField(int columns) { + super(columns); + } + + /** + * 限制整数和小数位数的数字文本框 + * @param maxIntegerLength 最大整数位数 + * @param maxDecimalLength 最大小数位数 + */ + public UINumberField(int maxIntegerLength, int maxDecimalLength) { + super(maxIntegerLength, maxDecimalLength); + } + + /** + * 限制整数和小数位数、最大值以及最小值的数字文本框 + * @param maxIntegerLength 最大整数位数 + * @param maxDecimalLength 最大小数位数 + * @param minValue 最小值 + * @param maxValue 最大值 + */ + public UINumberField(int maxIntegerLength, int maxDecimalLength, double minValue, double maxValue) { + super(maxIntegerLength, maxDecimalLength, minValue, maxValue); + } +} diff --git a/src/main/java/com/fanruan/api/design/ui/component/UIPasswordField.java b/src/main/java/com/fanruan/api/design/ui/component/UIPasswordField.java new file mode 100644 index 0000000..5f25353 --- /dev/null +++ b/src/main/java/com/fanruan/api/design/ui/component/UIPasswordField.java @@ -0,0 +1,19 @@ +package com.fanruan.api.design.ui.component; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2019-08-28 + * 密码输入控件 + */ +public class UIPasswordField extends com.fr.design.gui.ipasswordfield.UIPassWordField { + + public UIPasswordField() { + super(); + } + + public UIPasswordField(String text) { + super(text); + } + +} diff --git a/src/main/java/com/fanruan/api/design/ui/component/UIPlaceholderTextField.java b/src/main/java/com/fanruan/api/design/ui/component/UIPlaceholderTextField.java new file mode 100644 index 0000000..f8147ac --- /dev/null +++ b/src/main/java/com/fanruan/api/design/ui/component/UIPlaceholderTextField.java @@ -0,0 +1,27 @@ +package com.fanruan.api.design.ui.component; + +import com.fr.design.gui.itextfield.PlaceholderTextField; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2019-08-28 + * 带占位文本的文本编辑器(当没有输入文本的时候,会显示占位符) + */ +public class UIPlaceholderTextField extends PlaceholderTextField { + + public UIPlaceholderTextField() { + super(); + } + + public UIPlaceholderTextField(String placeHolder) { + super(); + setPlaceholder(placeHolder); + } + + public UIPlaceholderTextField(String text, String placeHolder) { + super(text); + setPlaceholder(placeHolder); + } + +} diff --git a/src/main/java/com/fanruan/api/design/ui/component/UISpinner.java b/src/main/java/com/fanruan/api/design/ui/component/UISpinner.java new file mode 100644 index 0000000..1439377 --- /dev/null +++ b/src/main/java/com/fanruan/api/design/ui/component/UISpinner.java @@ -0,0 +1,18 @@ +package com.fanruan.api.design.ui.component; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2019-08-28 + * 数字滚动控件 + */ +public class UISpinner extends com.fr.design.gui.ispinner.UISpinner { + + public UISpinner(double minValue, double maxValue, double delta) { + super(minValue, maxValue, delta); + } + + public UISpinner(double minValue, double maxValue, double delta, double defaultValue) { + super(minValue, maxValue, delta, defaultValue); + } +} diff --git a/src/main/java/com/fanruan/api/design/ui/component/UITable.java b/src/main/java/com/fanruan/api/design/ui/component/UITable.java new file mode 100644 index 0000000..79adf0a --- /dev/null +++ b/src/main/java/com/fanruan/api/design/ui/component/UITable.java @@ -0,0 +1,35 @@ +package com.fanruan.api.design.ui.component; + +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2019-08-28 + * 表格控件 + */ +public class UITable extends com.fr.design.gui.itable.UITable { + + public UITable() { + super(); + } + + public UITable(int columnSize) { + super(columnSize); + } + + /** + * @param values 一个列表,里面装有字符串数组,每个数组代表一行内容 + */ + public UITable(@NotNull List values) { + super(values); + } + + public UITable(int columnSize, boolean needAWTEventListener) { + super(columnSize, needAWTEventListener); + } + + +} diff --git a/src/main/java/com/fanruan/api/design/ui/component/UIToolbar.java b/src/main/java/com/fanruan/api/design/ui/component/UIToolbar.java new file mode 100644 index 0000000..ddd8efb --- /dev/null +++ b/src/main/java/com/fanruan/api/design/ui/component/UIToolbar.java @@ -0,0 +1,14 @@ +package com.fanruan.api.design.ui.component; + +import com.fr.design.gui.itoolbar.UIToolBarUI; + +public class UIToolbar extends com.fr.design.gui.itoolbar.UIToolbar{ + public UIToolbar(){ + + } + + public UIToolbar(int align) { + super(align); + } + +} diff --git a/src/main/java/com/fanruan/api/design/ui/component/code/SyntaxConstants.java b/src/main/java/com/fanruan/api/design/ui/component/code/SyntaxConstants.java new file mode 100644 index 0000000..d49dc7c --- /dev/null +++ b/src/main/java/com/fanruan/api/design/ui/component/code/SyntaxConstants.java @@ -0,0 +1,35 @@ +package com.fanruan.api.design.ui.component.code; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2019-08-28 + * 代码编辑器用到的常量 + */ +public interface SyntaxConstants { + + /** + * 普通文本编辑器 + */ + String SYNTAX_STYLE_NONE = "text/plain"; + + /** + * java编辑器 + */ + String SYNTAX_STYLE_JAVA = "text/java"; + + /** + * javascript编辑器 + */ + String SYNTAX_STYLE_JAVASCRIPT = "text/javascript"; + + /** + * sql编辑器 + */ + String SYNTAX_STYLE_SQL = "text/sql"; + + /** + * 公式编辑器 + */ + String SYNTAX_STYLE_FORMULA = "text/formula"; +} diff --git a/src/main/java/com/fanruan/api/design/ui/component/code/UISyntaxTextArea.java b/src/main/java/com/fanruan/api/design/ui/component/code/UISyntaxTextArea.java new file mode 100644 index 0000000..bd1ea0f --- /dev/null +++ b/src/main/java/com/fanruan/api/design/ui/component/code/UISyntaxTextArea.java @@ -0,0 +1,37 @@ +package com.fanruan.api.design.ui.component.code; + +import com.fr.design.gui.syntax.ui.rsyntaxtextarea.RSyntaxTextArea; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2019-08-28 + * 代码编辑器,支持javascript、sql、java、公式和普通文本 + * @see com.fanruan.api.design.ui.component.code.SyntaxConstants + *

+ * UISyntaxTextArea contentTextArea = new UISyntaxTextArea(); + * contentTextArea.setCloseCurlyBraces(true); + * contentTextArea.setLineWrap(true); + * contentTextArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVASCRIPT); + * contentTextArea.setCodeFoldingEnabled(true); + * contentTextArea.setAntiAliasingEnabled(true); + *

+ */ +public class UISyntaxTextArea extends RSyntaxTextArea { + + public UISyntaxTextArea() { + super(); + } + + public UISyntaxTextArea(String text) { + super(text); + } + + public UISyntaxTextArea(int rows, int cols) { + super(rows, cols); + } + + public UISyntaxTextArea(String text, int rows, int cols) { + super(text, rows, cols); + } +} diff --git a/src/main/java/com/fanruan/api/design/ui/component/code/UISyntaxTextScrollPane.java b/src/main/java/com/fanruan/api/design/ui/component/code/UISyntaxTextScrollPane.java new file mode 100644 index 0000000..4b38e45 --- /dev/null +++ b/src/main/java/com/fanruan/api/design/ui/component/code/UISyntaxTextScrollPane.java @@ -0,0 +1,30 @@ +package com.fanruan.api.design.ui.component.code; + +import com.fr.design.gui.syntax.ui.rtextarea.RTextScrollPane; + +import java.awt.*; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2019-08-28 + * 可滚动的代码编辑器容器 + */ +public class UISyntaxTextScrollPane extends RTextScrollPane { + + public UISyntaxTextScrollPane() { + + } + + public UISyntaxTextScrollPane(Component component) { + super(component); + } + + public UISyntaxTextScrollPane(Component component, boolean lineNumbers) { + super(component, lineNumbers); + } + + public UISyntaxTextScrollPane(Component component, boolean lineNumbers, Color lineNumberColor) { + super(component, lineNumbers, lineNumberColor); + } +} diff --git a/src/main/java/com/fanruan/api/design/ui/component/formula/UIFormulaTextField.java b/src/main/java/com/fanruan/api/design/ui/component/formula/UIFormulaTextField.java new file mode 100644 index 0000000..b184e60 --- /dev/null +++ b/src/main/java/com/fanruan/api/design/ui/component/formula/UIFormulaTextField.java @@ -0,0 +1,45 @@ +package com.fanruan.api.design.ui.component.formula; + +import com.fr.design.formula.TinyFormulaPane; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2019-08-28 + * 带公式选择器的公式输入文本框 + */ +public class UIFormulaTextField extends TinyFormulaPane { + + public UIFormulaTextField() { + super(); + } + + public UIFormulaTextField(String text) { + super(); + setText(text); + } + + /** + * 设置公式文本框的内容 + * @param text 公式文本 + */ + public void setText(String text) { + populateBean(text); + } + + /** + * 获取公式文本框的内容 + * @return 公式内容 + */ + public String getText() { + return updateBean(); + } + + /** + * 公式窗口点击确定后的事件接口,该方法一般用于重载 + */ + public void okEvent() { + + } + +} diff --git a/src/main/java/com/fanruan/api/design/ui/component/table/UITableEditorPane.java b/src/main/java/com/fanruan/api/design/ui/component/table/UITableEditorPane.java new file mode 100644 index 0000000..3bff89a --- /dev/null +++ b/src/main/java/com/fanruan/api/design/ui/component/table/UITableEditorPane.java @@ -0,0 +1,21 @@ +package com.fanruan.api.design.ui.component.table; + + +import com.fanruan.api.design.ui.component.table.model.UITableModelAdapter; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2019-08-28 + * 可增、删、改的表格控件 + */ +public class UITableEditorPane extends com.fr.design.gui.itableeditorpane.UITableEditorPane { + + public UITableEditorPane(UITableModelAdapter adapter) { + super(adapter); + } + + public UITableEditorPane(UITableModelAdapter adapter, String leftLabelName) { + super(adapter, leftLabelName); + } +} diff --git a/src/main/java/com/fanruan/api/design/ui/component/table/action/UITableEditAction.java b/src/main/java/com/fanruan/api/design/ui/component/table/action/UITableEditAction.java index 0b61e42..1c441cf 100644 --- a/src/main/java/com/fanruan/api/design/ui/component/table/action/UITableEditAction.java +++ b/src/main/java/com/fanruan/api/design/ui/component/table/action/UITableEditAction.java @@ -2,7 +2,8 @@ package com.fanruan.api.design.ui.component.table.action; import java.awt.event.ActionEvent; -public class UITableEditAction extends com.fr.design.gui.itableeditorpane.UITableEditAction{ +public class UITableEditAction extends com.fr.design.gui.itableeditorpane.UITableEditAction { + @Override public void checkEnabled() { } diff --git a/src/main/java/com/fanruan/api/design/ui/component/table/model/ParameterTableModel.java b/src/main/java/com/fanruan/api/design/ui/component/table/model/ParameterTableModel.java index 2e4b4bf..1b358cc 100644 --- a/src/main/java/com/fanruan/api/design/ui/component/table/model/ParameterTableModel.java +++ b/src/main/java/com/fanruan/api/design/ui/component/table/model/ParameterTableModel.java @@ -1,28 +1,350 @@ package com.fanruan.api.design.ui.component.table.model; +import com.fanruan.api.cal.ParameterKit; +import com.fanruan.api.design.DesignKit; +import com.fanruan.api.design.ui.component.UILabel; +import com.fanruan.api.design.ui.component.UITextField; +import com.fanruan.api.design.ui.component.table.action.UITableEditAction; import com.fanruan.api.design.ui.editor.ValueEditorPane; +import com.fanruan.api.design.ui.editor.ValueEditors; +import com.fanruan.api.log.LogKit; +import com.fanruan.api.util.IOKit; +import com.fanruan.api.util.StringKit; +import com.fr.design.mainframe.DesignerContext; +import com.fr.stable.ParameterProvider; +import javax.swing.*; +import javax.swing.event.CellEditorListener; +import javax.swing.event.ChangeEvent; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.TableCellEditor; import java.awt.*; +import java.awt.event.ActionEvent; +import java.util.Collections; /** - * 表格模型 + * 编辑参数的表格模型,通常来说就是两列:参数名和参数值 */ -public class ParameterTableModel extends com.fr.design.gui.itableeditorpane.ParameterTableModel { +public class ParameterTableModel extends UITableModelAdapter { + + public static final int NO_CHART_USE = 0; + public static final int CHART_NORMAL_USE = 1; + public static final int FORM_NORMAL_USE = -1; + + private static final long serialVersionUID = 1L; + protected Component component = null; public ParameterTableModel() { - super(); + this(NO_CHART_USE); } public ParameterTableModel(int paraUseType) { - super(paraUseType); + super(new String[]{DesignKit.i18nText("Fine-Design_Basic_Parameter"), DesignKit.i18nText("Fine-Design_Basic_Value")}); + this.setColumnClass(new Class[]{ParameterEditor.class, ParameterValueEditor.class}); + this.setDefaultEditor(ParameterValueEditor.class, new ParameterValueEditor(paraUseType)); + this.setDefaultEditor(ParameterEditor.class, new ParameterEditor()); + this.setDefaultRenderer(ParameterValueEditor.class, new ParameterValueRenderer(paraUseType)); } public ParameterTableModel(int paraUseType, Component component) { - super(paraUseType, component); + super(new String[]{DesignKit.i18nText("Fine-Design_Basic_Parameter"), DesignKit.i18nText("Fine-Design_Basic_Value")}); + this.setColumnClass(new Class[]{ParameterEditor.class, ParameterValueEditor.class}); + this.setDefaultEditor(ParameterValueEditor.class, new ParameterValueEditor(paraUseType)); + this.setDefaultEditor(ParameterEditor.class, new ParameterEditor()); + this.setDefaultRenderer(ParameterValueEditor.class, new ParameterValueRenderer(paraUseType)); + this.component = component; } public ParameterTableModel(ValueEditorPane valueEditorPane, ValueEditorPane valueRenderPane, Component component) { - super(valueEditorPane, valueRenderPane, component); + super(new String[]{DesignKit.i18nText("Fine-Design_Basic_Parameter"), DesignKit.i18nText("Fine-Design_Basic_Value")}); + this.setColumnClass(new Class[]{ParameterEditor.class, ParameterValueEditor.class}); + this.setDefaultEditor(ParameterValueEditor.class, new ParameterValueEditor(valueEditorPane)); + this.setDefaultEditor(ParameterEditor.class, new ParameterEditor()); + this.setDefaultRenderer(ParameterValueEditor.class, new ParameterValueRenderer(valueRenderPane)); + this.component = component; + } + + /** + * 单元格是否可编辑 + * + * @param row 行 + * @param col 列 + * @return 是否可以编辑 + */ + public boolean isCellEditable(int row, int col) { + if (col == 1) { + return this.getList().get(row) != null && StringKit.isNotEmpty(this.getList().get(row).getName()); + } + return true; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + ParameterProvider para = this.getList().get(rowIndex); + switch (columnIndex) { + case 0: + return para.getName(); + case 1: + return para.getValue(); + } + return null; + } + + /** + * 生成工具栏上的一系列动作按钮 + * + * @return 返回table上的action数组. + */ + @Override + public UITableEditAction[] createAction() { + return new UITableEditAction[]{new AddParameterAction(), new DeleteAction(), new MoveUpAction(), new MoveDownAction()}; } + + protected class AddParameterAction extends AddTableRowAction { + + public AddParameterAction() { + super(); + } + + @Override + public void actionPerformed(ActionEvent e) { + super.actionPerformed(e); + addParameter(); + } + } + + private void addParameter() { + ParameterProvider para = ParameterKit.newParameter(); + addRow(para); + fireTableDataChanged(); + table.getSelectionModel().setSelectionInterval(table.getRowCount() - 1, table.getRowCount() - 1); + } + + protected class DeleteAction extends UITableEditAction { + + private Component component = null; + + public DeleteAction() { + this.setName(DesignKit.i18nText("Fine-Design_Report_Delete")); + this.setSmallIcon(IOKit.readIcon("/com/fr/base/images/cell/control/remove.png")); + } + + public DeleteAction(Component component) { + this.setName(DesignKit.i18nText("Fine-Design_Report_Delete")); + this.setSmallIcon(IOKit.readIcon("/com/fr/base/images/cell/control/remove.png")); + this.component = component; + } + + @Override + public void actionPerformed(ActionEvent e) { + int[] selectedRow = table.getSelectedRows(); + if (isMultiSelected()) { + JOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), DesignKit.i18nText("Fine-Design_Basic_Multiple_Select_Warn_Text")); + return; + } + if (table.getCellEditor() != null) { + try { + table.getCellEditor().stopCellEditing(); + } catch (Exception ee) { + LogKit.error(ee.getMessage(), ee); + } + } + if (getRowCount() < 1) { + return; + } + + if (component == null) { + component = DesignerContext.getDesignerFrame(); + } + int val = JOptionPane.showConfirmDialog(component, + DesignKit.i18nText("Fine-Design_Basic_Utils_Are_You_Sure_To_Remove_The_Selected_Item") + "?", DesignKit.i18nText("Fine-Design_Basic_Remove"), + JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); + if (val != JOptionPane.OK_OPTION) { + return; + } + for (int i = 0; i < selectedRow.length; i++) { + if (selectedRow[i] - i < 0) { + continue; + } + removeRow(selectedRow[i] - i); + } + fireTableDataChanged(); + int selection = selectedRow[0] > table.getRowCount() ? table.getRowCount() - 1 + : (selectedRow[0] > 1 ? selectedRow[0] - 1 : 0); + table.getSelectionModel().setSelectionInterval(selection, selection); + } + + private boolean isMultiSelected() { + int[] selectedRow = table.getSelectedRows(); + return (selectedRow.length == 1 && (selectedRow[0] > table.getRowCount() - 1 || selectedRow[0] < 0)) || selectedRow.length == 0; + } + + @Override + public void checkEnabled() { + setEnabled(!isMultiSelected()); + } + } + + protected class MoveUpAction extends UITableEditAction { + + public MoveUpAction() { + this.setName(DesignKit.i18nText("Fine-Design_Basic_Utils_Move_Up")); + this.setSmallIcon(IOKit.readIcon("/com/fr/design/images/control/up.png")); + } + + @Override + public void actionPerformed(ActionEvent e) { + int selectedRow = table.getSelectedRow(); + stopCellEditing(); + if (getList().size() < 2 || selectedRow == 0) { + return; + } + Collections.swap(getList(), selectedRow, selectedRow - 1); + fireTableDataChanged(); + table.getSelectionModel().setSelectionInterval(selectedRow - 1, selectedRow - 1); + } + + @Override + public void checkEnabled() { + } + } + + protected class MoveDownAction extends UITableEditAction { + + public MoveDownAction() { + this.setName(DesignKit.i18nText("Fine-Design_Basic_Utils_Move_Down")); + this.setSmallIcon(IOKit.readIcon("/com/fr/design/images/control/down.png")); + } + + @Override + public void actionPerformed(ActionEvent e) { + int selectedRow = table.getSelectedRow(); + stopCellEditing(); + if (getList().size() < 2 || selectedRow == getRowCount() - 1) { + return; + } + Collections.swap(getList(), selectedRow, selectedRow + 1); + fireTableDataChanged(); + table.getSelectionModel().setSelectionInterval(selectedRow + 1, selectedRow + 1); + } + + @Override + public void checkEnabled() { + } + } + + public class ParameterEditor extends AbstractCellEditor implements TableCellEditor { + + private UITextField textField; + + public ParameterEditor() { + textField = new UITextField(); + this.addCellEditorListener(new CellEditorListener() { + + @Override + public void editingCanceled(ChangeEvent e) { + + } + + @Override + public void editingStopped(ChangeEvent e) { + if (table.getSelectedRow() == -1) { + return; + } + ParameterProvider para = getList().get(table.getSelectedRow()); + String value = StringKit.trimToNull(textField.getText()); + para.setName(value); + fireTableDataChanged(); + } + }); + } + + @Override + public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { + textField.setText((String) value); + return textField; + } + + @Override + public Object getCellEditorValue() { + return textField.getText(); + } + } + + private class ParameterValueEditor extends AbstractCellEditor implements TableCellEditor { + private static final long serialVersionUID = 1L; + private ValueEditorPane editor; + + public ParameterValueEditor(int paraUseType) { + this(ValueEditors.createValueEditorPaneWithUseType(paraUseType)); + } + + public ParameterValueEditor(ValueEditorPane valueEditorPane) { + + editor = valueEditorPane; + + this.addCellEditorListener(new CellEditorListener() { + + @Override + public void editingCanceled(ChangeEvent e) { + + } + + @Override + public void editingStopped(ChangeEvent e) { + if (table.getSelectedRow() == -1) { + return; + } + ParameterProvider para = getList().get(table.getSelectedRow()); + para.setValue(getCellEditorValue()); + fireTableDataChanged(); + } + }); + } + + @Override + public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { + editor.populate(value == null ? StringKit.EMPTY : value); + return editor; + } + + @Override + public Object getCellEditorValue() { + return editor.update(); + } + + } + + private class ParameterValueRenderer extends DefaultTableCellRenderer { + private static final long serialVersionUID = 1L; + private ValueEditorPane editor; + private UILabel disableLabel; + + public ParameterValueRenderer(int paraUseType) { + this(ValueEditors.createValueEditorPaneWithUseType(paraUseType)); + } + + public ParameterValueRenderer(ValueEditorPane valueEditorPane) { + disableLabel = new UILabel(DesignKit.i18nText("Fine-Design_Basic_Set_Paramete_Name")); + disableLabel.setForeground(Color.pink); + disableLabel.setHorizontalAlignment(SwingConstants.CENTER); + + editor = valueEditorPane; + } + + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + if (table.isCellEditable(row, column)) { + if (value == null) { + editor.populate(StringKit.EMPTY); + } else { + editor.populate(value); + } + return editor; + } else { + return disableLabel; + } + } + } + } diff --git a/src/main/java/com/fanruan/api/design/ui/component/table/model/UITableModelAdapter.java b/src/main/java/com/fanruan/api/design/ui/component/table/model/UITableModelAdapter.java new file mode 100644 index 0000000..be69b7a --- /dev/null +++ b/src/main/java/com/fanruan/api/design/ui/component/table/model/UITableModelAdapter.java @@ -0,0 +1,62 @@ +package com.fanruan.api.design.ui.component.table.model; + +import com.fanruan.api.design.DesignKit; +import com.fanruan.api.design.ui.component.table.action.UITableEditAction; +import com.fanruan.api.util.IOKit; +import com.fr.design.mainframe.DesignerContext; + +import javax.swing.*; +import java.awt.event.ActionEvent; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2019-08-28 + * + */ +public abstract class UITableModelAdapter extends com.fr.design.gui.itableeditorpane.UITableModelAdapter { + + protected UITableModelAdapter(String[] strings) { + super(strings); + } + + public abstract UITableEditAction[] createAction(); + + + protected abstract class AddTableRowAction extends UITableEditAction { + + public AddTableRowAction() { + this.setName(DesignKit.i18nText("Fine-Design_Report_Insert")); + this.setSmallIcon(IOKit.readIcon("/com/fr/base/images/cell/control/add.png")); + } + + @Override + public void actionPerformed(ActionEvent e) { + stopCellEditing(); + } + + public void checkEnabled() { + + } + } + + protected abstract class EditAction extends UITableEditAction { + + public EditAction() { + this.setName(DesignKit.i18nText("Fine-Design_Report_Edit")); + this.setSmallIcon(IOKit.readIcon("/com/fr/design/images/control/edit.png")); + } + + @Override + public void actionPerformed(ActionEvent e) { + final int selectedRow = table.getSelectedRow(); + if (selectedRow > table.getRowCount() - 1 || selectedRow < 0) { + JOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), DesignKit.i18nText("Fine-Design_Basic_No-Alternatives")); + return; + } + stopCellEditing(); + + } + + } +} diff --git a/src/main/java/com/fanruan/api/design/ui/container/BasicBeanPane.java b/src/main/java/com/fanruan/api/design/ui/container/BasicBeanPane.java new file mode 100644 index 0000000..ec72cbf --- /dev/null +++ b/src/main/java/com/fanruan/api/design/ui/container/BasicBeanPane.java @@ -0,0 +1,4 @@ +package com.fanruan.api.design.ui.container; + +public abstract class BasicBeanPane extends com.fr.design.beans.BasicBeanPane{ +} diff --git a/src/main/java/com/fanruan/api/design/ui/container/BasicDialog.java b/src/main/java/com/fanruan/api/design/ui/container/BasicDialog.java new file mode 100644 index 0000000..5a65107 --- /dev/null +++ b/src/main/java/com/fanruan/api/design/ui/container/BasicDialog.java @@ -0,0 +1,36 @@ +package com.fanruan.api.design.ui.container; + +import com.fanruan.api.design.ui.container.BasicPane; + +import java.awt.*; + +public class BasicDialog extends com.fr.design.dialog.BasicDialog{ + public BasicDialog(Dialog parent){ + super(parent); + } + + public BasicDialog(Dialog parent, BasicPane pane){ + super(parent, pane); + } + + public BasicDialog(Dialog parent, BasicPane pane, boolean isNeedButton){ + super(parent, pane, isNeedButton); + } + + public BasicDialog(Frame parent){ + super(parent); + } + + public BasicDialog(Frame parent, BasicPane pane){ + super(parent, pane); + } + + public BasicDialog(Frame parent, BasicPane pane, boolean isNedButtonPane){ + super(parent, pane, isNedButtonPane); + } + + @Override + public void checkValid(){ + + } +} diff --git a/src/main/java/com/fanruan/api/design/ui/container/DialogActionAdapter.java b/src/main/java/com/fanruan/api/design/ui/container/DialogActionAdapter.java new file mode 100644 index 0000000..c7a5db5 --- /dev/null +++ b/src/main/java/com/fanruan/api/design/ui/container/DialogActionAdapter.java @@ -0,0 +1,8 @@ +package com.fanruan.api.design.ui.container; +import com.fr.design.layout.FRGUIPaneFactory; + +public class DialogActionAdapter extends com.fr.design.dialog.DialogActionAdapter{ + public DialogActionAdapter(){ + + } +} diff --git a/src/main/java/com/fanruan/api/design/ui/container/UIScrollPane.java b/src/main/java/com/fanruan/api/design/ui/container/UIScrollPane.java new file mode 100644 index 0000000..681e193 --- /dev/null +++ b/src/main/java/com/fanruan/api/design/ui/container/UIScrollPane.java @@ -0,0 +1,16 @@ +package com.fanruan.api.design.ui.container; + +import java.awt.*; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2019-08-28 + * 可滚动容器 + */ +public class UIScrollPane extends com.fr.design.gui.icontainer.UIScrollPane { + + public UIScrollPane(Component component) { + super(component); + } +} diff --git a/src/main/java/com/fanruan/api/design/ui/editor/ValueEditors.java b/src/main/java/com/fanruan/api/design/ui/editor/ValueEditors.java new file mode 100644 index 0000000..4dda75f --- /dev/null +++ b/src/main/java/com/fanruan/api/design/ui/editor/ValueEditors.java @@ -0,0 +1,445 @@ +package com.fanruan.api.design.ui.editor; + +import com.fanruan.api.design.DesignKit; +import com.fanruan.api.design.ui.component.table.model.ParameterTableModel; +import com.fanruan.api.util.StringKit; +import com.fr.base.BaseFormula; +import com.fr.design.editor.editor.BooleanEditor; +import com.fr.design.editor.editor.ColumnRowEditor; +import com.fr.design.editor.editor.ColumnRowGroupEditor; +import com.fr.design.editor.editor.ColumnSelectedEditor; +import com.fr.design.editor.editor.ConstantsEditor; +import com.fr.design.editor.editor.CursorEditor; +import com.fr.design.editor.editor.DateEditor; +import com.fr.design.editor.editor.DoubleEditor; +import com.fr.design.editor.editor.Editor; +import com.fr.design.editor.editor.FormulaEditor; +import com.fr.design.editor.editor.IntegerEditor; +import com.fr.design.editor.editor.NoneEditor; +import com.fr.design.editor.editor.ParameterEditor; +import com.fr.design.editor.editor.SpinnerIntegerEditor; +import com.fr.design.editor.editor.TextEditor; +import com.fr.design.editor.editor.WidgetNameEditor; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2019-08-28 + * 工厂类,创建多种组合编辑器 + */ +public class ValueEditors { + + /** + * 创建带编辑器的ValueEditorPane + * + * @param editors 自定义的编辑器 + * @return 返回pane + */ + public static ValueEditorPane createValueEditorPane(Editor[] editors) { + return createValueEditorPane(editors, StringKit.EMPTY, StringKit.EMPTY); + } + + /** + * 创建编辑器 名称 弹出的ValueEditorPane + * + * @param editors 编辑器 + * @param popupName 弹出的名字 + * @param textEditorValue 值 + * @return 返回pane + */ + public static ValueEditorPane createValueEditorPane(Editor[] editors, String popupName, String textEditorValue) { + return new ValueEditorPane(editors, popupName, textEditorValue); + } + + /** + * 创建编辑器 名称 弹出的ValueEditorPane + * + * @param editors 编辑器 + * @param popupName 弹出的名字 + * @param textEditorValue 值 + * @param editor_center_width 编辑器主体的宽度 + * @return 返回pane + */ + public static ValueEditorPane createValueEditorPane(Editor[] editors, String popupName, String textEditorValue, int editor_center_width) { + return new ValueEditorPane(editors, popupName, textEditorValue, editor_center_width); + } + + /** + * 创建基本的值编辑器面板 + * + * @return 返回值编辑器面板 + */ + public static ValueEditorPane createBasicValueEditorPane() { + return createValueEditorPane(basicEditors(), StringKit.EMPTY, StringKit.EMPTY); + } + + /** + * 创建公式编辑器面板 + * + * @return 返回公式编辑器面板 + */ + public static ValueEditorPane createFormulaValueEditorPane() { + return createValueEditorPane(new Editor[]{new FormulaEditor(DesignKit.i18nText("Fine-Design_Basic_Parameter_Formula"))}, + StringKit.EMPTY, StringKit.EMPTY); + } + + /** + * 创建基本的值编辑器面板 + * + * @param editorCenterWidth 指定值编辑器的主体宽度 + * @return 返回值编辑器面板 + */ + public static ValueEditorPane createBasicValueEditorPane(int editorCenterWidth) { + return createValueEditorPane(basicEditors(), StringKit.EMPTY, StringKit.EMPTY, editorCenterWidth); + } + + /** + * Process用的editorPane + * + * @return 值编辑器面板 + */ + public static ValueEditorPane createFormEditorPane() { + return createValueEditorPane(formEditors(), StringKit.EMPTY, StringKit.EMPTY); + } + + /** + * URL使用的ValueEditorPane + * + * @param popupName 弹出的名字 + * @param textEditorValue 编辑器值 + * @return 值编辑器返回 + */ + public static ValueEditorPane createURLValueEditorPane(String popupName, String textEditorValue) { + return createValueEditorPane(URLEditors(popupName, textEditorValue), StringKit.EMPTY, StringKit.EMPTY); + } + + /** + * 创建日期的ValueEditorPane + * + * @param popupName 名字 + * @param textEditorValue 值 + * @return 值编辑器面板 + */ + public static ValueEditorPane createDateValueEditorPane(String popupName, String textEditorValue) { + return createValueEditorPane(dateEditors(popupName, textEditorValue), StringKit.EMPTY, StringKit.EMPTY); + } + + /** + * 带有所有编辑器的ValueEditorPane + * + * @return 值编辑器面板 + */ + public static ValueEditorPane createAllValueEditorPane() { + return createValueEditorPane(allEditors(), StringKit.EMPTY, StringKit.EMPTY); + } + + /** + * 创建不带公式面板的pane + * + * @return 编辑器面板 + */ + public static ValueEditorPane createBasicEditorWithoutFormulaPane() { + return createValueEditorPane(basicEditorsWithoutFormula(), StringKit.EMPTY, StringKit.EMPTY); + } + + /** + * 创建日期编辑器 + * + * @return 值编辑器 + */ + public static ValueEditorPane createDateValueEditorPane() { + return createValueEditorPane(dateEditors(), StringKit.EMPTY, StringKit.EMPTY); + } + + /** + * 根据参数paraUseType 创建编辑器类型. + * + * @param paraUseType 参数类型 + * @return 值编辑器 + */ + public static ValueEditorPane createValueEditorPaneWithUseType(int paraUseType) { + return createValueEditorPaneWithUseType(paraUseType, null); + } + + public static ValueEditorPane createValueEditorPaneWithUseType(int paraUseType, Map hyperLinkEditorMap) { + if (paraUseType == ParameterTableModel.NO_CHART_USE) { + return createBasicValueEditorPane(); + } else if (paraUseType == ParameterTableModel.FORM_NORMAL_USE) { + return createFormEditorPane(); + } else { + return createChartHotValueEditorPane(hyperLinkEditorMap); + } + } + + /** + * 图表用的参数编辑器的ValueEditorPane + * + * @param hyperLinkEditorMap 超链下拉参数类型 + * @return 值编辑器 + */ + public static ValueEditorPane createChartHotValueEditorPane(Map hyperLinkEditorMap) { + return createValueEditorPane(chartHotEditors(hyperLinkEditorMap), StringKit.EMPTY, StringKit.EMPTY); + } + + /** + * 基础的一些ValueEditorPane所用到的Editors + * + * @return 值编辑器 + */ + public static Editor[] basicEditors() { + FormulaEditor formulaEditor = new FormulaEditor(DesignKit.i18nText("Fine-Design_Basic_Parameter_Formula")); + return new Editor[]{ + new TextEditor(), + new SpinnerIntegerEditor(), + new DoubleEditor(), + new DateEditor(true, DesignKit.i18nText("Fine-Design_Basic_Date")), + new BooleanEditor(), + formulaEditor + }; + } + + /** + * 表单的一些编辑器. + * + * @return 值编辑器 + */ + public static Editor[] formEditors() { + FormulaEditor formulaEditor = new FormulaEditor(DesignKit.i18nText("Fine-Design_Basic_Parameter_Formula")); + return new Editor[]{ + new TextEditor(), + new IntegerEditor(), + new DoubleEditor(), + new DateEditor(true, DesignKit.i18nText("Fine-Design_Basic_Date")), + new BooleanEditor(), + formulaEditor, + new WidgetNameEditor(DesignKit.i18nText("Fine-Design_Report_Widget")) + }; + } + + /** + * 扩展单元格的一些编辑器 + * + * @return 值编辑器 + */ + public static Editor[] extendedEditors() { + FormulaEditor formulaEditor = new FormulaEditor(DesignKit.i18nText("Fine-Design_Basic_Parameter_Formula")); + return new Editor[]{ + new TextEditor(), + new IntegerEditor(), + new DoubleEditor(), + new DateEditor(true, DesignKit.i18nText("Fine-Design_Basic_Date")), + new BooleanEditor(), + formulaEditor, + new ParameterEditor(), + new ColumnRowEditor(DesignKit.i18nText("Fine-Design_Basic_Cell")) + }; + } + + /** + * 带单元格组的编辑器 + * + * @return 值编辑器 + */ + public static Editor[] extendedCellGroupEditors() { + FormulaEditor formulaEditor = new FormulaEditor(DesignKit.i18nText("Fine-Design_Basic_Parameter_Formula")); + return new Editor[]{ + new TextEditor(), + new IntegerEditor(), + new DoubleEditor(), + new DateEditor(true, DesignKit.i18nText("Fine-Design_Basic_Date")), + new BooleanEditor(), + formulaEditor, + new ParameterEditor(), + new ColumnRowEditor(DesignKit.i18nText("Fine-Design_Basic_Cell")), + new ColumnRowGroupEditor(DesignKit.i18nText("Fine-Design_Basic_Cell_Group")) + }; + } + + /** + * 只有单元格和单元格组的编辑器 + * + * @return 编辑器b + */ + public static Editor[] cellGroupEditor() { + return new Editor[]{ + new ColumnRowEditor(DesignKit.i18nText("Fine-Design_Basic_Cell")), + new ColumnRowGroupEditor(DesignKit.i18nText("Fine-Design_Basic_Cell_Group")) + }; + } + + /** + * URL的一些编辑器. + * + * @param popupName 名字 + * @param textEditorValue 值 + * @return 值编辑器 + */ + public static Editor[] URLEditors(String popupName, String textEditorValue) { + return new Editor[]{ + new NoneEditor(textEditorValue, StringKit.isEmpty(popupName) ? DesignKit.i18nText("Fine-Design_Basic_None") : popupName), + new TextEditor() + }; + } + + /** + * 日期类型的一些编辑器 + * + * @param popupName 名字 + * @param textEditorValue 值 + * @return 值编辑器 + */ + public static Editor[] dateEditors(String popupName, String textEditorValue) { + return new Editor[]{ + new NoneEditor(textEditorValue, StringKit.isEmpty(popupName) ? DesignKit.i18nText("Fine-Design_Basic_None") : popupName), + new DateEditor(true, DesignKit.i18nText("Fine-Design_Basic_Date")), + new FormulaEditor(DesignKit.i18nText("Fine-Design_Basic_Parameter_Formula")) + }; + } + + /** + * 所有类型的编辑器 + * + * @return 值编辑器 + */ + public static Editor[] allEditors() { + FormulaEditor formulaEditor = new FormulaEditor(DesignKit.i18nText("Fine-Design_Basic_Parameter_Formula")); + return new Editor[]{ + new TextEditor(), + new IntegerEditor(), + new DoubleEditor(), + new DateEditor(true, DesignKit.i18nText("Fine-Design_Basic_Date")), + new BooleanEditor(), + formulaEditor, + new ParameterEditor(), + new ColumnRowEditor(DesignKit.i18nText("Fine-Design_Basic_Cell")), + new ColumnSelectedEditor(), + }; + } + + /** + * 不带公式编辑器 + * + * @return 编辑器不带公式 + */ + public static Editor[] basicEditorsWithoutFormula() { + return new Editor[]{ + new TextEditor(), + new IntegerEditor(), + new DoubleEditor(), + new DateEditor(true, DesignKit.i18nText("Fine-Design_Basic_Date")), + new BooleanEditor(), + }; + } + + /** + * noCRnoColumn编辑器 + * + * @return 编辑器 + */ + public static Editor[] noCRnoColumnEditors() { + FormulaEditor formulaEditor = new FormulaEditor(DesignKit.i18nText("Fine-Design_Basic_Parameter_Formula")); + return new Editor[]{ + new TextEditor(), + new IntegerEditor(), + new DoubleEditor(), + new DateEditor(true, DesignKit.i18nText("Fine-Design_Basic_Date")), + new BooleanEditor(), + formulaEditor, + new ParameterEditor(), + }; + } + + /** + * 数值编辑器 + * + * @return 编辑器 + */ + public static Editor[] numberEditors() { + FormulaEditor formulaEditor = new FormulaEditor(DesignKit.i18nText("Fine-Design_Basic_Parameter_Formula")); + return new Editor[]{ + new IntegerEditor(), + new DoubleEditor(), + formulaEditor, + new ParameterEditor(), + }; + } + + /** + * 日期编辑器 + * + * @return 编辑器 + */ + public static Editor[] dateEditors() { + FormulaEditor formulaEditor = new FormulaEditor(DesignKit.i18nText("Fine-Design_Basic_Parameter_Formula")); + return new Editor[]{ + new DateEditor(true, DesignKit.i18nText("Fine-Design_Basic_Date")), + formulaEditor, + new ParameterEditor(), + }; + } + + /** + * 存储的一些编辑器 + * + * @return 存储过程的编辑器 + */ + public static Editor[] StoreProcedureEditors() { + FormulaEditor formulaEditor = new FormulaEditor(DesignKit.i18nText("Fine-Design_Basic_Parameter_Formula")); + formulaEditor.setEnabled(true); + return new Editor[]{ + new CursorEditor(), + new TextEditor(), + new IntegerEditor(), + new DoubleEditor(), + new DateEditor(true, DesignKit.i18nText("Fine-Design_Basic_Date")), + new BooleanEditor(), + formulaEditor + }; + } + + /** + * 图表热点的一些编辑器 + * + * @return 值编辑器 + */ + public static Editor[] chartHotEditors(Map hyperLinkEditorMap) { + List list = createEditors4Chart(hyperLinkEditorMap); + + list.add(new TextEditor()); + list.add(new IntegerEditor()); + list.add(new DoubleEditor()); + list.add(new DateEditor(true, DesignKit.i18nText("Fine-Design_Basic_Date"))); + list.add(new BooleanEditor()); + + FormulaEditor formulaEditor = new FormulaEditor(DesignKit.i18nText("Fine-Design_Basic_Parameter_Formula")); + formulaEditor.setEnabled(true); + list.add(formulaEditor); + + return list.toArray(new Editor[0]); + } + + /** + * 为图表创建编辑器. + * + * @return 值编辑器 + */ + private static List createEditors4Chart(Map hyperLinkEditorMap) { + List lists = new ArrayList<>(); + if (hyperLinkEditorMap == null) { + return lists; + } + Iterator> entries = hyperLinkEditorMap.entrySet().iterator(); + while (entries.hasNext()) { + Map.Entry entry = entries.next(); + ConstantsEditor editor = new ConstantsEditor(entry.getKey(), entry.getValue()); + editor.setEnabled(false); + lists.add(editor); + } + return lists; + } +} diff --git a/src/main/java/com/fanruan/api/design/util/I18nDesignKit.java b/src/main/java/com/fanruan/api/design/util/I18nDesignKit.java deleted file mode 100644 index 0ec639f..0000000 --- a/src/main/java/com/fanruan/api/design/util/I18nDesignKit.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.fanruan.api.design.util; - -import com.fr.design.i18n.Toolkit; - -/** - * @author richie - * @version 10.0 - * Created by richie on 2019-08-28 - * 设计器国际化工具类,设计器相关类的国际化都需要调用这个类才行 - */ -public class I18nDesignKit { - - /** - * 文本国际化 - * @param key 国际化键 - * @return 国际化后的值 - */ - public String i18nText(String key) { - return Toolkit.i18nText(key); - } - - /** - * 带参数的文本国际化 - * @param key 国际化键 - * @param args 参数 - * @return 国际化后的值 - */ - public String i18nText(String key, Object... args) { - return Toolkit.i18nText(key, args); - } -} diff --git a/src/main/java/com/fanruan/api/design/work/ConnectionComboBoxPanel.java b/src/main/java/com/fanruan/api/design/work/ConnectionComboBoxPanel.java new file mode 100644 index 0000000..9e3228b --- /dev/null +++ b/src/main/java/com/fanruan/api/design/work/ConnectionComboBoxPanel.java @@ -0,0 +1,9 @@ +package com.fanruan.api.design.work; + +import com.fr.data.impl.Connection; + +public class ConnectionComboBoxPanel extends com.fr.design.data.datapane.connect.ConnectionComboBoxPanel{ + public ConnectionComboBoxPanel(Class cls) { + super(cls); + } +} diff --git a/src/main/java/com/fanruan/api/design/work/DatabaseConnectionPane.java b/src/main/java/com/fanruan/api/design/work/DatabaseConnectionPane.java new file mode 100644 index 0000000..0c5eaf9 --- /dev/null +++ b/src/main/java/com/fanruan/api/design/work/DatabaseConnectionPane.java @@ -0,0 +1,7 @@ +package com.fanruan.api.design.work; + + +import javax.swing.*; +public abstract class DatabaseConnectionPane extends com.fr.design.data.datapane.connect.DatabaseConnectionPane{ + +} diff --git a/src/main/java/com/fanruan/api/err/UtilEvalError.java b/src/main/java/com/fanruan/api/err/UtilEvalError.java new file mode 100644 index 0000000..fed9c53 --- /dev/null +++ b/src/main/java/com/fanruan/api/err/UtilEvalError.java @@ -0,0 +1,4 @@ +package com.fanruan.api.err; + +public class UtilEvalError extends com.fr.stable.UtilEvalError{ +} diff --git a/src/main/java/com/fanruan/api/macro/EncodeConstants.java b/src/main/java/com/fanruan/api/macro/EncodeConstants.java new file mode 100644 index 0000000..a26e822 --- /dev/null +++ b/src/main/java/com/fanruan/api/macro/EncodeConstants.java @@ -0,0 +1,48 @@ +package com.fanruan.api.macro; + + +/** + * 编码常量 + */ +public interface EncodeConstants { + + /** + * utf-8编码 + */ + String ENCODING_UTF_8 = com.fr.stable.EncodeConstants.ENCODING_UTF_8; + + /** + * gbk编码 + */ + String ENCODING_GBK = com.fr.stable.EncodeConstants.ENCODING_GBK; + + /** + * big5编码,一般用于繁体中文 + */ + String ENCODING_BIG5 = com.fr.stable.EncodeConstants.ENCODING_BIG5; + + /** + * ios-8859-1编码 + */ + String ENCODING_ISO_8859_1 = com.fr.stable.EncodeConstants.ENCODING_ISO_8859_1; + + /** + * utf16编码 + */ + String ENCODING_UTF_16 = com.fr.stable.EncodeConstants.ENCODING_UTF_16; + + /** + * euc-jp编码 + */ + String ENCODING_EUC_JP = com.fr.stable.EncodeConstants.ENCODING_EUC_JP; + + /** + * euc-kr编码 + */ + String ENCODING_EUC_KR = com.fr.stable.EncodeConstants.ENCODING_EUC_KR; + + /** + * cp850编码 + */ + String ENCODING_CP850 = com.fr.stable.EncodeConstants.ENCODING_CP850; +} diff --git a/src/main/java/com/fanruan/api/net/http/HttpKit.java b/src/main/java/com/fanruan/api/net/http/HttpKit.java new file mode 100644 index 0000000..6162745 --- /dev/null +++ b/src/main/java/com/fanruan/api/net/http/HttpKit.java @@ -0,0 +1,677 @@ +package com.fanruan.api.net.http; + +import com.fanruan.api.macro.EncodeConstants; +import com.fanruan.api.log.LogKit; +import com.fanruan.api.net.http.rs.BaseHttpResponseHandle; +import com.fanruan.api.net.http.rs.HttpRequest; +import com.fanruan.api.net.http.rs.HttpRequestType; +import com.fanruan.api.net.http.rs.HttpResponseType; +import com.fanruan.api.net.http.rs.StreamResponseHandle; +import com.fanruan.api.net.http.rs.TextResponseHandle; +import com.fanruan.api.net.http.rs.UploadResponseHandle; +import com.fr.third.guava.collect.Maps; +import com.fr.third.org.apache.http.HttpEntity; +import com.fr.third.org.apache.http.HttpEntityEnclosingRequest; +import com.fr.third.org.apache.http.HttpHost; +import com.fr.third.org.apache.http.NameValuePair; +import com.fr.third.org.apache.http.NoHttpResponseException; +import com.fr.third.org.apache.http.client.HttpRequestRetryHandler; +import com.fr.third.org.apache.http.client.config.RequestConfig; +import com.fr.third.org.apache.http.client.entity.UrlEncodedFormEntity; +import com.fr.third.org.apache.http.client.methods.CloseableHttpResponse; +import com.fr.third.org.apache.http.client.methods.HttpEntityEnclosingRequestBase; +import com.fr.third.org.apache.http.client.methods.HttpRequestBase; +import com.fr.third.org.apache.http.client.protocol.HttpClientContext; +import com.fr.third.org.apache.http.client.utils.URIBuilder; +import com.fr.third.org.apache.http.config.Registry; +import com.fr.third.org.apache.http.config.RegistryBuilder; +import com.fr.third.org.apache.http.conn.routing.HttpRoute; +import com.fr.third.org.apache.http.conn.socket.ConnectionSocketFactory; +import com.fr.third.org.apache.http.conn.socket.LayeredConnectionSocketFactory; +import com.fr.third.org.apache.http.conn.socket.PlainConnectionSocketFactory; +import com.fr.third.org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import com.fr.third.org.apache.http.entity.FileEntity; +import com.fr.third.org.apache.http.entity.mime.HttpMultipartMode; +import com.fr.third.org.apache.http.entity.mime.MultipartEntityBuilder; +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.impl.conn.PoolingHttpClientConnectionManager; +import com.fr.third.org.apache.http.message.BasicNameValuePair; +import com.fr.third.org.apache.http.protocol.HttpContext; +import com.fr.third.org.apache.http.ssl.SSLContexts; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLHandshakeException; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InterruptedIOException; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URLEncoder; +import java.net.UnknownHostException; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static com.fanruan.api.net.http.rs.HttpRequestType.POST; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2019-08-29 + *

+ * http请求工具类,封装了用于http请求的各种方法 + *

+ */ +public class HttpKit { + + private static final int RETRY_TIMES = 5; + + private static CloseableHttpClient httpClient = null; + + private final static Object SYNC_LOCK = new Object(); + + /** + * 根据请求地址创建HttpClient对象 + * + * @param url 请求地址 + * @return HttpClient对象 + */ + public static CloseableHttpClient getHttpClient(String url) { + String hostname = url.split("/")[2]; + int port = 80; + if (hostname.contains(":")) { + String[] arr = hostname.split(":"); + hostname = arr[0]; + port = Integer.parseInt(arr[1]); + } + if (httpClient == null) { + synchronized (SYNC_LOCK) { + if (httpClient == null) { + httpClient = createHttpClient(hostname, port, SSLContexts.createDefault()); + } + } + } + return httpClient; + } + + + public static CloseableHttpClient createHttpClient(String hostname, int port, SSLContext sslContext) { + return createHttpClient(200, 40, 100, hostname, port, sslContext); + } + + private static CloseableHttpClient createHttpClient(int maxTotal, + int maxPerRoute, + int maxRoute, + String hostname, + int port, + SSLContext sslContext) { + ConnectionSocketFactory socketFactory = PlainConnectionSocketFactory.getSocketFactory(); + LayeredConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext); + Registry registry = RegistryBuilder + .create() + .register("http", socketFactory) + .register("https", sslConnectionSocketFactory) + .build(); + PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry); + // 将最大连接数增加 + cm.setMaxTotal(maxTotal); + // 将每个路由基础的连接增加 + cm.setDefaultMaxPerRoute(maxPerRoute); + HttpHost httpHost = new HttpHost(hostname, port); + // 将目标主机的最大连接数增加 + cm.setMaxPerRoute(new HttpRoute(httpHost), maxRoute); + + // 请求重试处理 + HttpRequestRetryHandler httpRequestRetryHandler = new HttpRequestRetryHandler() { + @Override + public boolean retryRequest(IOException exception, int executionCount, HttpContext context) { + if (executionCount >= RETRY_TIMES) {// 如果已经重试了5次,就放弃 + return false; + } + if (exception instanceof NoHttpResponseException) {// 如果服务器丢掉了连接,那么就重试 + return true; + } + if (exception instanceof SSLHandshakeException) {// 不要重试SSL握手异常 + return false; + } + if (exception instanceof InterruptedIOException) {// 超时 + return false; + } + if (exception instanceof UnknownHostException) {// 目标服务器不可达 + return false; + } + if (exception instanceof SSLException) {// SSL握手异常 + return false; + } + + HttpClientContext clientContext = HttpClientContext.adapt(context); + com.fr.third.org.apache.http.HttpRequest request = clientContext.getRequest(); + // 如果请求是幂等的,就再次尝试 + return !(request instanceof HttpEntityEnclosingRequest); + } + }; + + return HttpClients.custom() + .setConnectionManager(cm) + .setRetryHandler(httpRequestRetryHandler) + .build(); + } + + /** + * 设置 httpEntity + * + * @param requestBase 请求体 + * @param httpRequest 请求 + */ + private static void setHttpEntity(@NotNull HttpEntityEnclosingRequestBase requestBase, @NotNull HttpRequest httpRequest) { + HttpEntity httpEntity = httpRequest.getHttpEntity(); + if (httpEntity != null) { + // 如果存在 httpEntity 直接设置 + requestBase.setEntity(httpEntity); + return; + } + Map params = httpRequest.getParams(); + if (params == null || params.isEmpty()) { + return; + } + List pairs = new ArrayList(); + for (Map.Entry entry : params.entrySet()) { + pairs.add(new BasicNameValuePair(entry.getKey(), entry.getValue())); + } + try { + requestBase.setEntity(new UrlEncodedFormEntity(pairs, httpRequest.getEncoding())); + } catch (UnsupportedEncodingException e) { + LogKit.error(e.getMessage(), e); + } + } + + private static Map transformMap(Map oldMap) { + if (oldMap == null) { + return null; + } + return Maps.transformEntries(oldMap, new Maps.EntryTransformer() { + @Override + public String transformEntry(@Nullable String key, @Nullable V value) { + return value == null ? null : value.toString(); + } + }); + } + + /** + * 发起POST请求并获取返回的文本 + * + * @param url 响应请求的的服务器地址 + * @param params POST请求的参数 + * @return 服务器返回的文本内容 + */ + public static String post(String url, Map params) throws IOException { + return executeAndParse(HttpRequest + .custom() + .url(url) + .post(transformMap(params)) + .build()); + } + + /** + * 发起POST请求并获取返回的文本 + * + * @param url 响应请求的的服务器地址 + * @param params POST请求的参数 + * @param responseType 返回类型 + * @return 服务器返回的文本内容 + * @see com.fanruan.api.net.http.HttpKit#execute(HttpRequest) + */ + @Deprecated + public static T post(String url, Map params, HttpResponseType responseType) throws IOException { + CloseableHttpResponse response = execute(HttpRequest + .custom() + .url(url) + .post(transformMap(params)) + .build()); + return responseType.result(response, null); + } + + /** + * 发起POST请求并获取返回的文本 + * + * @param url 响应请求的的服务器地址 + * @param params POST请求的参数 + * @param headers 请求头 + * @return 服务器返回的文本内容 + * @see com.fanruan.api.net.http.HttpKit#executeAndParse(HttpRequest) + */ + @Deprecated + public static String post(String url, Map params, Map headers) throws IOException { + return executeAndParse(HttpRequest + .custom() + .url(url) + .post(transformMap(params)) + .headers(headers) + .build()); + } + + /** + * 发起POST请求并获取返回的文本 + * + * @param url 响应请求的的服务器地址 + * @param params POST请求的参数 + * @param headers 请求头 + * @param responseType 返回类型 + * @return 服务器返回的文本内容 + * @see com.fanruan.api.net.http.HttpKit#execute(HttpRequest) + */ + @Deprecated + public static T post(String url, Map params, Map headers, HttpResponseType responseType) throws IOException { + CloseableHttpResponse response = execute(HttpRequest + .custom() + .url(url) + .post(transformMap(params)) + .headers(headers) + .build()); + return responseType.result(response, null); + } + + /** + * 发起POST请求并获取返回的文本 + * + * @param url 响应请求的的服务器地址 + * @param params POST请求的参数 + * @param responseEncoding 响应的文本的编码 + * @return 服务器返回的文本内容 + * @see com.fanruan.api.net.http.HttpKit#executeAndParse(HttpRequest, BaseHttpResponseHandle) + */ + @Deprecated + public static String post(String url, Map params, String responseEncoding) throws IOException { + return executeAndParse(HttpRequest + .custom() + .url(url) + .post(transformMap(params)) + .build(), + new TextResponseHandle(responseEncoding)); + } + + /** + * 发起POST请求并获取返回的文本 + * + * @param url 响应请求的的服务器地址 + * @param params POST请求的参数 + * @param responseEncoding 响应的文本的编码 + * @param headers 请求头 + * @return 服务器返回的文本内容 + * @see com.fanruan.api.net.http.HttpKit#executeAndParse(HttpRequest, BaseHttpResponseHandle) + */ + @Deprecated + public static String post(String url, Map params, String responseEncoding, Map headers) throws IOException { + return executeAndParse(HttpRequest + .custom() + .url(url) + .post(transformMap(params)) + .headers(headers) + .build(), + new TextResponseHandle(responseEncoding)); + } + + + /** + * 发起POST请求并获取返回的文本 + * + * @param url 响应请求的的服务器地址 + * @param params POST请求的参数 + * @param responseEncoding 响应的文本的编码 + * @param paramsEncoding 参数编码 + * @param headers 请求头 + * @return 服务器返回的文本内容 + * @see com.fanruan.api.net.http.HttpKit#executeAndParse(HttpRequest, BaseHttpResponseHandle) + */ + public static String post(String url, Map params, String responseEncoding, String paramsEncoding, Map headers) throws IOException { + return executeAndParse(HttpRequest + .custom() + .url(url) + .post(transformMap(params)) + .encoding(paramsEncoding) + .headers(headers) + .build(), + new TextResponseHandle(responseEncoding)); + } + + /** + * 发起POST请求并获取返回的文本 + * + * @param url 响应请求的的服务器地址 + * @param params POST请求的参数 + * @param responseEncoding 响应的文本的编码 + * @param paramsEncoding 参数编码 + * @param headers 请求头 + * @param responseType 返回值类型 + * @return 服务器返回的文本内容 + * @see com.fanruan.api.net.http.HttpKit#execute(HttpRequest) + */ + public static T post(String url, Map params, String responseEncoding, String paramsEncoding, Map headers, HttpResponseType responseType) throws IOException { + CloseableHttpResponse response = execute(HttpRequest + .custom() + .url(url) + .post(transformMap(params)) + .encoding(paramsEncoding) + .headers(headers) + .build()); + return responseType.result(response, responseEncoding); + } + + /** + * 发起GET请求并获取返回的文本 + * + * @param url 响应请求的的服务器地址 + * @return 服务器返回的文本内容 + */ + public static String get(String url) throws IOException { + return executeAndParse(HttpRequest.custom().url(url).build()); + } + + /** + * 发起GET请求并获取返回的文本 + * + * @param url 响应请求的的服务器地址 + * @param params 参数 + * @return 服务器返回的文本内容 + */ + public static String get(String url, Map params) throws IOException { + return executeAndParse(HttpRequest.custom().url(url).params(params).build()); + } + + /** + * 发起GET请求并获取返回的文本 + * + * @param url 响应请求的的服务器地址 + * @param params 参数 + * @param headers 请求头 + * @return 服务器返回的文本内容 + * @see com.fanruan.api.net.http.HttpKit#executeAndParse(HttpRequest, BaseHttpResponseHandle) + */ + public static String get(String url, Map params, Map headers) throws IOException { + return executeAndParse(HttpRequest.custom().url(url).params(params).headers(headers).build()); + } + + /** + * 发起GET请求并获取返回的文本 + * + * @param url 响应请求的的服务器地址 + * @param params 参数 + * @param responseEncoding 返回的文本的编码 + * @return 服务器返回的文本内容 + * @see com.fanruan.api.net.http.HttpKit#executeAndParse(HttpRequest, BaseHttpResponseHandle) + */ + public static String get(String url, Map params, String responseEncoding) throws IOException { + return executeAndParse(HttpRequest + .custom() + .url(url) + .params(params) + .build(), + new TextResponseHandle(responseEncoding)); + } + + /** + * 发起GET请求并获取返回的文本 + * + * @param url 响应请求的的服务器地址 + * @param params 参数 + * @param responseEncoding 返回的文本的编码 + * @return 服务器返回的文本内容 + * @see com.fanruan.api.net.http.HttpKit#executeAndParse(HttpRequest, BaseHttpResponseHandle) + */ + public static String get(String url, Map params, String responseEncoding, Map headers) throws IOException { + return executeAndParse(HttpRequest + .custom() + .url(url) + .params(params) + .headers(headers) + .build(), + new TextResponseHandle(responseEncoding)); + } + + /** + * 从指定的地址下载文件 + * @param url 文件下载地址 + * @return 文件的字节流 + * @throws IOException 下载过程中出现错误则抛出此异常 + */ + public static ByteArrayInputStream download(String url) throws IOException { + return executeAndParse(HttpRequest.custom().url(url).build(), StreamResponseHandle.DEFAULT); + } + + /** + * 从指定的地址下载文件 + * @param url 文件下载地址 + * @param params 参数对 + * @param responseEncoding 响应的文件编码 + * @param headers 请求头 + * @return 文件的字节流 + * @throws IOException 下载过程中出现错误则抛出此异常 + */ + public static ByteArrayInputStream download(String url, Map params, String responseEncoding, Map headers) throws IOException { + return executeAndParse(HttpRequest + .custom() + .url(url) + .params(params) + .headers(headers) + .build(), + new StreamResponseHandle(responseEncoding)); + } + + /** + * 上传文件到指定的服务器 + * + * @param url 接收文件的服务器地址 + * @param file 要上传的文件,默认的文件编码为utf-8 + * @throws IOException 上传中出现错误则抛出此异常 + */ + public static void upload(String url, File file) throws IOException { + upload(url, file, Charset.forName("utf-8")); + } + + /** + * 上传文件到指定的服务器 + * + * @param url 接收文件的服务器地址 + * @param file 要上传的文件 + * @param charset 文件的编码 + * @throws IOException 上传中出现错误则抛出此异常 + */ + public static void upload(String url, File file, Charset charset) throws IOException { + upload(url, new FileEntity(file), charset); + } + + /** + * 上传文件到指定的服务器 + * + * @param url 接收文件的服务器地址 + * @param builder 附件构造器 + * @param charset 文件的编码 + * @throws IOException 上传中出现错误则抛出此异常 + */ + public static void upload(String url, MultipartEntityBuilder builder, Charset charset) throws IOException { + upload(url, builder, charset, Collections.emptyMap(), POST); + } + + /** + * 上传文件到指定的服务器 + * + * @param url 接收文件的服务器地址 + * @param fileEntity 文件实体 + * @param charset 文件的编码 + * @throws IOException 上传中出现错误则抛出此异常 + */ + public static void upload(String url, FileEntity fileEntity, Charset charset) throws IOException { + upload(url, fileEntity, charset, Collections.emptyMap(), POST); + } + + /** + * 上传多文件到指定的服务器 + * + * @param url 接收文件的服务器地址 + * @param builder 附件构造器 + * @param charset 文件的编码 + * @param headers 请求头 + * @param httpRequestType 请求类型 + * @throws IOException 上传中出现错误则抛出此异常 + */ + public static void upload(String url, MultipartEntityBuilder builder, Charset charset, Map headers, HttpRequestType httpRequestType) throws IOException { + // richie:采用浏览器模式,防止出现乱码 + builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); + HttpEntity reqEntity = builder.setCharset(charset).build(); + upload(url, reqEntity, charset, headers, httpRequestType); + } + + /** + * 上传文件到指定的服务器 + * + * @param url 接收文件的服务器地址 + * @param reqEntity 请求实体 + * @param charset 文件的编码 + * @param headers 请求头 + * @param httpRequestType 请求类型 + * @throws IOException 上传中出现错误则抛出此异常 + */ + public static void upload(String url, HttpEntity reqEntity, Charset charset, Map headers, HttpRequestType httpRequestType) throws IOException { + executeAndParse(HttpRequest + .custom() + .url(url) + .headers(headers) + .method(httpRequestType) + .httpEntity(reqEntity) + .encoding(charset.toString()) + .build(), + UploadResponseHandle.DEFAULT); + } + + /** + * 请求资源或服务,使用默认文本http解析器,UTF-8编码 + * + * @param httpRequest httpRequest + * @return 返回处理结果 + */ + public static String executeAndParse(HttpRequest httpRequest) throws IOException { + return executeAndParse(httpRequest, TextResponseHandle.DEFAULT); + } + + /** + * 请求资源或服务,自请求参数,并指定 http 响应处理器 + * 例: + *
+     *      String res = HttpToolbox.executeAndParse(HttpRequest
+     *              .custom()
+     *              .url("")
+     *              .build(),
+     *          TextResponseHandle.DEFAULT);
+     * 
+ * + * @param httpRequest httpRequest + * @param handle http 解析器 + * @return 返回处理结果 + */ + public static T executeAndParse(HttpRequest httpRequest, BaseHttpResponseHandle handle) throws IOException { + return handle.parse(execute(httpRequest)); + } + + /** + * 请求资源或服务,传入请求参数 + * + * @param httpRequest httpRequest + * @return 返回处理结果 + */ + public static CloseableHttpResponse execute(HttpRequest httpRequest) throws IOException { + return execute(getHttpClient(httpRequest.getUrl()), httpRequest); + } + + /** + * 请求资源或服务,自定义client对象,传入请求参数 + * + * @param httpClient http客户端 + * @param httpRequest httpRequest + * @return 返回处理结果 + */ + public static CloseableHttpResponse execute(CloseableHttpClient httpClient, HttpRequest httpRequest) throws IOException { + String url = httpRequest.getUrl(); + + // 创建请求对象 + HttpRequestBase httpRequestBase = httpRequest.getMethod().createHttpRequest(url); + + // 设置header信息 + httpRequestBase.setHeader("User-Agent", "Mozilla/5.0"); + Map headers = httpRequest.getHeaders(); + if (headers != null && !headers.isEmpty()) { + for (Map.Entry entry : headers.entrySet()) { + httpRequestBase.setHeader(entry.getKey(), entry.getValue()); + } + } + + // 配置请求的设置 + RequestConfig requestConfig = httpRequest.getConfig(); + if (requestConfig != null) { + httpRequestBase.setConfig(requestConfig); + } + + // 判断是否支持设置entity(仅HttpPost、HttpPut、HttpPatch支持) + if (HttpEntityEnclosingRequestBase.class.isAssignableFrom(httpRequestBase.getClass())) { + setHttpEntity((HttpEntityEnclosingRequestBase) httpRequestBase, httpRequest); + } else { + Map params = httpRequest.getParams(); + if (params != null && !params.isEmpty()) { + // 注意get等不支持设置entity需要更新拼接之后的URL,但是url变量没有更新 + httpRequestBase.setURI(URI.create(buildUrl(url, params, httpRequest.getEncoding()))); + } + } + + return httpClient.execute(httpRequestBase); + } + + /** + * 构建 Url + * + * @param url 请求地址 + * @param params 参数 + * @return 拼接之后的地址 + */ + public static String buildUrl(String url, Map params) { + try { + return buildUrl(url, params, EncodeConstants.ENCODING_UTF_8); + } catch (UnsupportedEncodingException ignore) { + } + return url; + } + + + /** + * 构建 Url + * + * @param url 请求地址 + * @param params 参数 + * @return 拼接之后的地址 + * @throws UnsupportedEncodingException 不支持的编码 + */ + private static String buildUrl(String url, Map params, String paramsEncoding) throws UnsupportedEncodingException { + if (params == null || params.isEmpty()) { + return url; + } + URIBuilder builder; + try { + builder = new URIBuilder(url); + for (Map.Entry entry : params.entrySet()) { + String key = URLEncoder.encode(entry.getKey(), paramsEncoding); + String value = URLEncoder.encode(entry.getValue(), paramsEncoding); + builder.setParameter(key, value); + } + return builder.build().toString(); + } catch (URISyntaxException e) { + LogKit.debug("Error to build url, please check the arguments."); + } + return url; + } +} diff --git a/src/main/java/com/fanruan/api/net/http/rs/BaseHttpResponseHandle.java b/src/main/java/com/fanruan/api/net/http/rs/BaseHttpResponseHandle.java new file mode 100644 index 0000000..4198916 --- /dev/null +++ b/src/main/java/com/fanruan/api/net/http/rs/BaseHttpResponseHandle.java @@ -0,0 +1,54 @@ +package com.fanruan.api.net.http.rs; + +import com.fr.stable.EncodeConstants; +import com.fr.third.org.apache.http.client.methods.CloseableHttpResponse; + +import java.io.IOException; + +/** + * http 结果解析器 + * + * @author vito + * @date 2019-07-14 + */ +public abstract class BaseHttpResponseHandle { + + /** + * 解析编码,默认为 UTF_8 + */ + private String encoding = EncodeConstants.ENCODING_UTF_8; + + public BaseHttpResponseHandle() { + } + + public BaseHttpResponseHandle(String encoding) { + this.encoding = encoding; + } + + /** + * 获取解析编码 + * + * @return 解析编码 + */ + public String getEncoding() { + return encoding; + } + + /** + * 设置解析编码 + * + * @param encoding 解析编码 + */ + public void setEncoding(String encoding) { + this.encoding = encoding; + } + + /** + * 解析响应结果 + * + * @param response 响应 + * @return 解析结果 + * @throws IOException io异常 + */ + public abstract T parse(CloseableHttpResponse response) throws IOException; +} diff --git a/src/main/java/com/fanruan/api/net/http/rs/HttpRequest.java b/src/main/java/com/fanruan/api/net/http/rs/HttpRequest.java new file mode 100644 index 0000000..4a5250d --- /dev/null +++ b/src/main/java/com/fanruan/api/net/http/rs/HttpRequest.java @@ -0,0 +1,215 @@ +package com.fanruan.api.net.http.rs; + +import com.fanruan.api.macro.EncodeConstants; +import com.fr.third.org.apache.http.HttpEntity; +import com.fr.third.org.apache.http.client.config.RequestConfig; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; +import java.util.Map; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2019-08-29 + */ +public class HttpRequest { + + private static final int TIME_OUT = 10 * 1000; + private static final RequestConfig DEFAULT = RequestConfig + .custom() + .setConnectionRequestTimeout(TIME_OUT) + .setConnectTimeout(TIME_OUT) + .setSocketTimeout(TIME_OUT) + .build(); + /** + * 请求地址 + */ + private String url; + + /** + * 请求头 + */ + private Map headers; + + /** + * 请求参数 + */ + private Map params; + + /** + * 请求参数 + * + * @see RequestConfig + */ + @Nullable + private RequestConfig config; + + /** + * 请求参数 + * + * @see HttpEntity + */ + @Nullable + private HttpEntity httpEntity; + + /** + * 请求方法 + */ + private HttpRequestType method; + + /** + * 参数字符集 + */ + private String encoding; + + private HttpRequest(Builder builder) { + this.url = builder.url; + this.headers = builder.headers; + this.params = builder.params; + this.config = builder.config; + this.encoding = builder.encoding; + this.httpEntity = builder.httpEntity; + this.method = builder.method; + } + + public String getUrl() { + return url; + } + + public Map getHeaders() { + return headers; + } + + public Map getParams() { + return params; + } + + public RequestConfig getConfig() { + return config; + } + + public String getEncoding() { + return encoding; + } + + public HttpEntity getHttpEntity() { + return httpEntity; + } + + public HttpRequestType getMethod() { + return method; + } + + public static Builder custom() { + return new Builder(); + } + + public static final class Builder { + private String url; + private Map headers = Collections.emptyMap(); + private Map params = Collections.emptyMap(); + @Nullable + private RequestConfig config = DEFAULT; + @Nullable + private HttpEntity httpEntity; + private String encoding = EncodeConstants.ENCODING_UTF_8; + private HttpRequestType method = HttpRequestType.GET; + + private Builder() { + } + + public HttpRequest build() { + if (this.url == null) { + throw new IllegalStateException("url == null"); + } + return new HttpRequest(this); + } + + public Builder url(@NotNull String url) { + if (url == null) { + throw new NullPointerException("url == null"); + } + this.url = url; + return this; + } + + public Builder headers(Map headers) { + if (headers != null) { + this.headers = headers; + } + return this; + } + + public Builder params(Map params) { + if (params != null) { + this.params = params; + } + return this; + } + + public Builder config(RequestConfig config) { + this.config = config; + return this; + } + + public Builder get() { + this.method = HttpRequestType.GET; + return this; + } + + public Builder post(HttpEntity httpEntity) { + this.method = HttpRequestType.POST; + this.httpEntity(httpEntity); + return this; + } + + public Builder post(Map params) { + this.method = HttpRequestType.POST; + this.params(params); + return this; + } + + public Builder put(HttpEntity httpEntity) { + this.method = HttpRequestType.PUT; + this.httpEntity(httpEntity); + return this; + } + + public Builder put(Map params) { + this.method = HttpRequestType.PUT; + this.params(params); + return this; + } + + public Builder delete() { + this.method = HttpRequestType.DELETE; + return this; + } + + public Builder encoding(String encoding) { + if (encoding == null) { + throw new NullPointerException("httpEntity == null"); + } + this.encoding = encoding; + return this; + } + + public Builder httpEntity(HttpEntity httpEntity) { + this.httpEntity = httpEntity; + return this; + } + + public Builder method(@NotNull HttpRequestType method) { + if (method == null) { + throw new NullPointerException("method == null"); + } + this.method = method; + return this; + } + + } + + +} \ No newline at end of file diff --git a/src/main/java/com/fanruan/api/net/http/rs/HttpRequestType.java b/src/main/java/com/fanruan/api/net/http/rs/HttpRequestType.java new file mode 100644 index 0000000..1a1ffe9 --- /dev/null +++ b/src/main/java/com/fanruan/api/net/http/rs/HttpRequestType.java @@ -0,0 +1,114 @@ +package com.fanruan.api.net.http.rs; + +import com.fr.third.org.apache.http.client.methods.HttpDelete; +import com.fr.third.org.apache.http.client.methods.HttpGet; +import com.fr.third.org.apache.http.client.methods.HttpHead; +import com.fr.third.org.apache.http.client.methods.HttpOptions; +import com.fr.third.org.apache.http.client.methods.HttpPatch; +import com.fr.third.org.apache.http.client.methods.HttpPost; +import com.fr.third.org.apache.http.client.methods.HttpPut; +import com.fr.third.org.apache.http.client.methods.HttpRequestBase; +import com.fr.third.org.apache.http.client.methods.HttpTrace; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2019-08-29 + */ +public enum HttpRequestType { + /** + * 求获取Request-URI所标识的资源 + */ + GET("GET") { + @Override + public HttpRequestBase createHttpRequest(String url) { + return new HttpGet(url); + } + }, + + /** + * 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。 + * POST请求可能会导致新的资源的建立和/或已有资源的修改 + */ + POST("POST") { + @Override + public HttpRequestBase createHttpRequest(String url) { + return new HttpPost(url); + } + }, + + /** + * 向服务器索要与GET请求相一致的响应,只不过响应体将不会被返回。 + * 这一方法可以在不必传输整个响应内容的情况下,就可以获取包含在响应消息头中的元信息 + * 只获取响应信息报头 + */ + HEAD("HEAD") { + @Override + public HttpRequestBase createHttpRequest(String url) { + return new HttpHead(url); + } + }, + + /** + * 向指定资源位置上传其最新内容(全部更新,操作幂等) + */ + PUT("PUT") { + @Override + public HttpRequestBase createHttpRequest(String url) { + return new HttpPut(url); + } + }, + + /** + * 请求服务器删除Request-URI所标识的资源 + */ + DELETE("DELETE") { + @Override + public HttpRequestBase createHttpRequest(String url) { + return new HttpDelete(url); + } + }, + + /** + * 请求服务器回送收到的请求信息,主要用于测试或诊断 + */ + TRACE("TRACE") { + @Override + public HttpRequestBase createHttpRequest(String url) { + return new HttpTrace(url); + } + }, + + /** + * 向指定资源位置上传其最新内容(部分更新,非幂等) + */ + PATCH("PATCH") { + @Override + public HttpRequestBase createHttpRequest(String url) { + return new HttpPatch(url); + } + }, + + /** + * 返回服务器针对特定资源所支持的HTTP请求方法。 + * 也可以利用向Web服务器发送'*'的请求来测试服务器的功能性 + */ + OPTIONS("OPTIONS") { + @Override + public HttpRequestBase createHttpRequest(String url) { + return new HttpOptions(url); + } + }; + + public abstract HttpRequestBase createHttpRequest(String url); + + private String name; + + HttpRequestType(String name) { + this.name = name; + } + + public String getName() { + return name; + } +} diff --git a/src/main/java/com/fanruan/api/net/http/rs/HttpResponseType.java b/src/main/java/com/fanruan/api/net/http/rs/HttpResponseType.java new file mode 100644 index 0000000..a787422 --- /dev/null +++ b/src/main/java/com/fanruan/api/net/http/rs/HttpResponseType.java @@ -0,0 +1,103 @@ +package com.fanruan.api.net.http.rs; + +import com.fr.third.org.apache.http.HttpEntity; +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.protocol.HttpClientContext; +import com.fr.third.org.apache.http.impl.client.CloseableHttpClient; +import com.fr.third.org.apache.http.util.EntityUtils; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2019-08-29 + */ +public interface HttpResponseType { + + /** + * 处理http响应 + * + * @param client 客户端 + * @param url 地址 + * @param request 请求 + * @param charset 字符集 + * @return 处理之后的响应 + * @throws IOException 异常 + */ + @Deprecated + T result(CloseableHttpClient client, String url, HttpUriRequest request, String charset) throws IOException; + + /** + * 处理http响应 + * + * @param response 响应 + * @param charset 字符集 + * @return 处理之后的响应 + * @throws IOException 异常 + */ + T result(CloseableHttpResponse response, String charset) throws IOException; + + HttpResponseType TEXT = new HttpResponseType() { + + @Override + public String result(CloseableHttpClient client, String url, HttpUriRequest request, String charset) throws IOException { + CloseableHttpResponse response = client.execute(request, HttpClientContext.create()); + return result(response, charset); + } + + @Override + public String result(CloseableHttpResponse response, String charset) throws IOException { + try { + HttpEntity entity = response.getEntity(); + String result = EntityUtils.toString(entity, charset); + EntityUtils.consume(entity); + return result; + } finally { + if (response != null) { + response.close(); + } + } + } + }; + + HttpResponseType STREAM = new HttpResponseType() { + + @Override + public ByteArrayInputStream result(CloseableHttpClient client, String url, HttpUriRequest request, String charset) throws IOException { + CloseableHttpResponse response = client.execute(request, HttpClientContext.create()); + return result(response, charset); + } + + @Override + public ByteArrayInputStream result(CloseableHttpResponse response, String charset) throws IOException { + InputStream in = null; + try { + HttpEntity entity = response.getEntity(); + if (entity != null) { + in = entity.getContent(); + byte[] buff = new byte[8000]; + int bytesRead; + ByteArrayOutputStream bao = new ByteArrayOutputStream(); + while ((bytesRead = in.read(buff)) != -1) { + bao.write(buff, 0, bytesRead); + } + byte[] data = bao.toByteArray(); + return new ByteArrayInputStream(data); + } + return null; + } finally { + if (response != null) { + response.close(); + } + if (in != null) { + in.close(); + } + } + } + }; +} \ No newline at end of file diff --git a/src/main/java/com/fanruan/api/net/http/rs/StreamResponseHandle.java b/src/main/java/com/fanruan/api/net/http/rs/StreamResponseHandle.java new file mode 100644 index 0000000..e10bfdd --- /dev/null +++ b/src/main/java/com/fanruan/api/net/http/rs/StreamResponseHandle.java @@ -0,0 +1,55 @@ +package com.fanruan.api.net.http.rs; + +import com.fr.third.org.apache.http.HttpEntity; +import com.fr.third.org.apache.http.client.methods.CloseableHttpResponse; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * 流响应解析器 + * + * @author vito + * @date 2019-07-14 + */ +public class StreamResponseHandle extends BaseHttpResponseHandle { + + public static final StreamResponseHandle DEFAULT = new StreamResponseHandle(); + private static final int BUFFER_LENGTH = 8000; + + public StreamResponseHandle() { + } + + public StreamResponseHandle(String encoding) { + super(encoding); + } + + @Override + public ByteArrayInputStream parse(CloseableHttpResponse response) throws IOException { + InputStream in = null; + try { + HttpEntity entity = response.getEntity(); + if (entity != null) { + in = entity.getContent(); + byte[] buff = new byte[BUFFER_LENGTH]; + int bytesRead; + ByteArrayOutputStream bao = new ByteArrayOutputStream(); + while ((bytesRead = in.read(buff)) != -1) { + bao.write(buff, 0, bytesRead); + } + byte[] data = bao.toByteArray(); + return new ByteArrayInputStream(data); + } + return null; + } finally { + if (response != null) { + response.close(); + } + if (in != null) { + in.close(); + } + } + } +} diff --git a/src/main/java/com/fanruan/api/net/http/rs/TextResponseHandle.java b/src/main/java/com/fanruan/api/net/http/rs/TextResponseHandle.java new file mode 100644 index 0000000..c8c58c0 --- /dev/null +++ b/src/main/java/com/fanruan/api/net/http/rs/TextResponseHandle.java @@ -0,0 +1,39 @@ +package com.fanruan.api.net.http.rs; + +import com.fr.third.org.apache.http.HttpEntity; +import com.fr.third.org.apache.http.client.methods.CloseableHttpResponse; +import com.fr.third.org.apache.http.util.EntityUtils; + +import java.io.IOException; + +/** + * 文本响应解析器 + * + * @author vito + * @date 2019-07-14 + */ +public class TextResponseHandle extends BaseHttpResponseHandle { + + public static final TextResponseHandle DEFAULT = new TextResponseHandle(); + + public TextResponseHandle() { + } + + public TextResponseHandle(String encoding) { + super(encoding); + } + + @Override + public String parse(CloseableHttpResponse response) throws IOException { + try { + HttpEntity entity = response.getEntity(); + String result = EntityUtils.toString(entity, getEncoding()); + EntityUtils.consume(entity); + return result; + } finally { + if (response != null) { + response.close(); + } + } + } +} diff --git a/src/main/java/com/fanruan/api/net/http/rs/UploadResponseHandle.java b/src/main/java/com/fanruan/api/net/http/rs/UploadResponseHandle.java new file mode 100644 index 0000000..3b68be0 --- /dev/null +++ b/src/main/java/com/fanruan/api/net/http/rs/UploadResponseHandle.java @@ -0,0 +1,48 @@ +package com.fanruan.api.net.http.rs; + +import com.fr.third.org.apache.http.HttpEntity; +import com.fr.third.org.apache.http.HttpStatus; +import com.fr.third.org.apache.http.client.methods.CloseableHttpResponse; +import com.fr.third.org.apache.http.util.EntityUtils; + +import java.io.IOException; + +/** + * 上传响应解析器 + * + * @author vito + * @date 2019-07-14 + */ +public class UploadResponseHandle extends BaseHttpResponseHandle { + + public static final UploadResponseHandle DEFAULT = new UploadResponseHandle(); + + public UploadResponseHandle() { + } + + public UploadResponseHandle(String encoding) { + super(encoding); + } + + @Override + public Void parse(CloseableHttpResponse response) throws IOException { + try { + int statusCode = response.getStatusLine().getStatusCode(); + if (statusCode == HttpStatus.SC_OK) { + HttpEntity entity = response.getEntity(); + if (entity != null) { + EntityUtils.consume(entity); + } + } else { + HttpEntity entity = response.getEntity(); + String result = EntityUtils.toString(entity, getEncoding()); + throw new IOException("Connect error, error code:" + statusCode + "; message:" + result); + } + } finally { + if (response != null) { + response.close(); + } + } + return null; + } +} diff --git a/src/main/java/com/fanruan/api/script/ScriptKit.java b/src/main/java/com/fanruan/api/script/ScriptKit.java new file mode 100644 index 0000000..67108f2 --- /dev/null +++ b/src/main/java/com/fanruan/api/script/ScriptKit.java @@ -0,0 +1,14 @@ +package com.fanruan.api.script; +import com.fr.script.ScriptFactory; + +import javax.script.ScriptEngine; + +public class ScriptKit { + /** + * 获取一个全新的脚本执行引擎 + * @return 一个全新的脚本执行引擎 + */ + public static ScriptEngine newScriptEngine() { + return ScriptFactory.newScriptEngine(); + } +} diff --git a/src/main/java/com/fanruan/api/util/ReflectKit.java b/src/main/java/com/fanruan/api/util/ReflectKit.java deleted file mode 100644 index ef9d4b9..0000000 --- a/src/main/java/com/fanruan/api/util/ReflectKit.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.fanruan.api.util; - -import com.fr.stable.StableUtils; - -public class ReflectKit { - - /** - * 判断一个类是否是另一个类的子类 - * @param current 当前类 - * @param target 目标类 - * @return 如果当前类是目标类的子类,则返回true,否则返回false - */ - public static boolean classInstanceOf(Class current, Class target) { - return StableUtils.classInstanceOf(current, target); - } -} diff --git a/src/main/java/com/fanruan/api/util/TypeKit.java b/src/main/java/com/fanruan/api/util/TypeKit.java new file mode 100644 index 0000000..a53e362 --- /dev/null +++ b/src/main/java/com/fanruan/api/util/TypeKit.java @@ -0,0 +1,32 @@ +package com.fanruan.api.util; + +public class TypeKit { + + /** + * 判读指定的类是否是另一个类的子类 + * + * @param current 指定的类 + * @param targetClass 另一个类 + * @return 如果当前类是目标类的子类则返回true,否则返回false + */ + public static boolean classInstanceOf(Class current, Class targetClass) { + if (current == null || targetClass == null) { + return false; + } + return targetClass.isAssignableFrom(current); + } + + /** + * 判读指定的类是否是另一个类的子类 + * + * @param object 指定的类 + * @param clazz 另一个类 + * @return 如果指定类是另一个类的子类则返回true,否则返回false + */ + public static boolean objectInstanceOf(Object object, Class clazz) { + if (object == null || clazz == null) { + return false; + } + return clazz.isInstance(object); + } +} diff --git a/src/main/java/com/fanruan/api/xml/XmlKit.java b/src/main/java/com/fanruan/api/xml/XmlKit.java index 548b788..37efb56 100644 --- a/src/main/java/com/fanruan/api/xml/XmlKit.java +++ b/src/main/java/com/fanruan/api/xml/XmlKit.java @@ -1,20 +1,49 @@ package com.fanruan.api.xml; +import com.fr.general.xml.GeneralXMLTools; +import com.fr.stable.xml.XMLPrintWriter; import com.fr.stable.xml.XMLReadable; import com.fr.stable.xml.XMLTools; +import com.fr.stable.xml.XMLable; import com.fr.stable.xml.XMLableReader; -import com.fr.stable.xml.XMLPrintWriter; import java.io.InputStream; +/** + * xml读写相关类 + */ public class XmlKit { /** * 从输入流中读取对象 - * @param xmlReadable xml读取对象 - * @param inputStream xml输入流 * + * @param read xml读取对象 + * @param in xml输入流 + */ + public static void readInputStreamXML(XMLReadable read, InputStream in) throws Exception { + XMLTools.readInputStreamXML(read, in); + } + + + /** + * 将xml读取为具体的java对象 + * + * @param reader xml读取器 + * @return java对象 */ - public static void readInputStreamXML(XMLReadable xmlReadable, InputStream inputStream) throws Exception { - XMLTools.readInputStreamXML(xmlReadable, inputStream); + public static XMLable readXMLable(XMLableReader reader) { + return GeneralXMLTools.readXMLable(reader); } + + /** + * 将java对象写为xml文件 + * + * @param writer xml写入器 + * @param xml 实际java对象 + * @param tagName xml标签名 + */ + public static void writeXMLable(XMLPrintWriter writer, XMLable xml, String tagName) { + GeneralXMLTools.writeXMLable(writer, xml, tagName); + } + + } diff --git a/src/test/java/com/fanruan/api/cal/ContainerKitTest.java b/src/test/java/com/fanruan/api/cal/ContainerKitTest.java new file mode 100644 index 0000000..09209c3 --- /dev/null +++ b/src/test/java/com/fanruan/api/cal/ContainerKitTest.java @@ -0,0 +1,24 @@ +package com.fanruan.api.cal; + +import com.fr.stable.ArrayProvider; +import com.fr.third.guava.collect.Lists; +import org.junit.Assert; +import org.junit.Test; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2019-08-29 + */ +public class ContainerKitTest { + + @Test + public void newArray() { + + ArrayProvider array = ContainerKit.newArray(new String[]{"abc", "xyz"}); + Assert.assertEquals("xyz", array.elementAt(1)); + + ArrayProvider array2 = ContainerKit.newArray(Lists.newArrayList("abc", "xyz")); + Assert.assertEquals("abc", array2.elementAt(0)); + } +} \ No newline at end of file diff --git a/src/test/java/com/fanruan/api/cal/ParameterKitTest.java b/src/test/java/com/fanruan/api/cal/ParameterKitTest.java index 20bb157..9292107 100644 --- a/src/test/java/com/fanruan/api/cal/ParameterKitTest.java +++ b/src/test/java/com/fanruan/api/cal/ParameterKitTest.java @@ -1,6 +1,7 @@ package com.fanruan.api.cal; import com.fanruan.api.Prepare; +import com.fr.base.Parameter; import com.fr.script.Calculator; import com.fr.stable.ParameterProvider; import com.fr.stable.UtilEvalError; @@ -30,6 +31,33 @@ public class ParameterKitTest extends Prepare { Assert.assertArrayEquals(new String[]{"p1", "p2", "p4", "p5"}, names); } + @Test + public void analyze4Parameters() { + String sql = "SELECT * FROM Equipment where 'Tel' = ${if(true, 1, 2)}"; + ParameterProvider[] parameters = ParameterKit.analyze4Parameters(sql, false); + Assert.assertEquals(0, parameters.length); + parameters = ParameterKit.analyze4Parameters(sql, true); + Assert.assertEquals(0, parameters.length); + sql = "SELECT * FROM s订单 where 1=1 ${if(len(aa)==0,\"\",\" and 货主城市 in (\"+\"'\"+treelayer(aa,true,\"\\',\\'\")+\"'\"+\")\")}"; + parameters = ParameterKit.analyze4Parameters(sql, false); + Assert.assertEquals(1, parameters.length); + Assert.assertEquals(parameters[0].getName(), "aa"); + sql = "SELECT * FROM Equipment where 'Tel' = ${if(false, 1, 2)}"; + parameters = ParameterKit.analyze4Parameters(sql, false); + Assert.assertEquals(0, parameters.length); + parameters = ParameterKit.analyze4Parameters(sql, true); + Assert.assertEquals(0, parameters.length); + sql = "SELECT * FROM s订单 where 1=1 ${if(len(aa)==0,\"\",\" and 货主城市 in (\"+\"'\"+treelayer(aa,false,\"\\',\\'\")+\"'\"+\")\")}"; + parameters = ParameterKit.analyze4Parameters(sql, false); + Assert.assertEquals(1, parameters.length); + Assert.assertEquals(parameters[0].getName(), "aa"); + sql = "SELECT * FROM s订单 where 1=1 ${if(len(aa)==0,\"\",\" and 货主城市 in (\"+\"'\"+treelayer(aa,\"true\",\"\\',\\'\")+\"'\"+\")\")}"; + parameters = ParameterKit.analyze4Parameters(sql, false); + Assert.assertEquals(1, parameters.length); + Assert.assertEquals(parameters[0].getName(), "aa"); + + } + @Test public void createParameterMapNameSpace() { Map map = new HashMap<>(); @@ -47,4 +75,36 @@ public class ParameterKitTest extends Prepare { calculator.removeNameSpace(ns); } } + + @Test + public void createParameterMapNameSpace2() { + ParameterProvider[] parameters = new ParameterProvider[]{ + ParameterKit.newParameter("p1", 100), + ParameterKit.newParameter("p2", 200) + }; + NameSpace ns = ParameterKit.createParameterMapNameSpace(parameters); + Calculator calculator = Calculator.createCalculator(); + calculator.pushNameSpace(ns); + try { + Object r = calculator.eval("=$p1 + $p2"); + Assert.assertEquals(300, r); + } catch (UtilEvalError utilEvalError) { + Assert.fail(); + } finally { + calculator.removeNameSpace(ns); + } + } + + @Test + public void newParameter() { + ParameterProvider provider = ParameterKit.newParameter(); + Assert.assertTrue(provider instanceof Parameter); + } + + @Test + public void newParameter1() { + ParameterProvider provider = ParameterKit.newParameter("p1", "124"); + Assert.assertEquals("p1", provider.getName()); + Assert.assertEquals("124", provider.getValue()); + } } \ No newline at end of file diff --git a/src/test/java/com/fanruan/api/net/http/HttpKitTest.java b/src/test/java/com/fanruan/api/net/http/HttpKitTest.java new file mode 100644 index 0000000..a034a4a --- /dev/null +++ b/src/test/java/com/fanruan/api/net/http/HttpKitTest.java @@ -0,0 +1,153 @@ +package com.fanruan.api.net.http; + +import com.fanruan.api.Prepare; +import com.fanruan.api.net.http.rs.HttpRequest; +import com.fanruan.api.net.http.rs.HttpResponseType; +import com.fanruan.api.net.http.rs.StreamResponseHandle; +import com.fanruan.api.util.IOKit; +import com.fr.json.JSONObject; +import okhttp3.HttpUrl; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import okhttp3.mockwebserver.RecordedRequest; +import org.junit.AfterClass; +import org.junit.Test; + +import java.io.IOException; +import java.io.InputStream; +import java.net.SocketTimeoutException; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2019-08-29 + */ +public class HttpKitTest extends Prepare { + + private static MockWebServer server = new MockWebServer(); + + @AfterClass + public static void tearDown() throws Exception { + server.shutdown(); + } + + @Test + public void testGet() { + String text = null; + try { + text = HttpKit.get("http://www.baidu.com"); + } catch (IOException e) { + e.printStackTrace(); + } + assertNotNull(text); + } + + @Test + public void testPost() { + Map map = new HashMap(); + map.put("key", "bbs"); + try { + String resText = HttpKit.post("https://cloud.fanruan.com/site", map); + assertEquals("http://bbs.fanruan.com/", new JSONObject(resText).get("value")); + } catch (SocketTimeoutException ignore) { + } catch (Exception e) { + e.printStackTrace(); + fail(); + } + } + + @Test + public void testStream() { + Map map = new HashMap(); + map.put("key", "bbs"); + try { + InputStream in = HttpKit.post("https://cloud.fanruan.com/site", map, HttpResponseType.STREAM); + String text = IOKit.inputStream2String(in, StandardCharsets.UTF_8); + assertEquals("{\"value\":\"http://bbs.fanruan.com/\"}", text); + } catch (SocketTimeoutException ignore) { + } catch (Exception e) { + e.printStackTrace(); + fail(); + } + } + + @Test + public void testStreamMock() { + server.enqueue(new MockResponse().setBody("{\"value\":\"http://bbs.fanruan.com/\"}")); + String url = server.url("/site").toString(); + Map map = new HashMap(); + map.put("key", "bbs"); + try { + InputStream in = HttpKit.executeAndParse(HttpRequest + .custom() + .url(url) + .post(map) + .build(), + new StreamResponseHandle()); + String text = IOKit.inputStream2String(in, StandardCharsets.UTF_8); + RecordedRequest takeRequest = server.takeRequest(); + assertEquals("{\"value\":\"http://bbs.fanruan.com/\"}", text); + assertEquals("POST", takeRequest.getMethod()); + assertEquals("key=bbs", takeRequest.getBody().readUtf8()); + } catch (SocketTimeoutException ignore) { + } catch (Exception e) { + e.printStackTrace(); + fail(); + } + } + + @Test + public void testMethod() throws Exception { + server.enqueue(new MockResponse().setBody("get")); + server.enqueue(new MockResponse().setBody("post")); + server.enqueue(new MockResponse().setBody("put")); + server.enqueue(new MockResponse().setBody("delete")); + String url = server.url("/v1/chat/").toString(); + HttpKit.get(url); + assertEquals(server.takeRequest().getMethod(), "GET"); + HttpKit.post(url, Collections.emptyMap()); + assertEquals(server.takeRequest().getMethod(), "POST"); + HttpKit.executeAndParse(HttpRequest.custom().url(url).put(Collections.emptyMap()).build()); + assertEquals(server.takeRequest().getMethod(), "PUT"); + HttpKit.executeAndParse(HttpRequest.custom().url(url).delete().build()); + assertEquals(server.takeRequest().getMethod(), "DELETE"); + } + + @Test + public void testHeader() throws Exception { + server.enqueue(new MockResponse().setBody("hello, world!")); + HttpUrl baseUrl = server.url("/v1/chat/"); + + HashMap headers = new HashMap(1); + headers.put("Authorization", "abc"); + String s = HttpKit.executeAndParse(HttpRequest.custom().url(baseUrl.toString()).post(Collections.emptyMap()).headers(headers).build()); + assertEquals("hello, world!", s); + // 测试请求头 + RecordedRequest request = server.takeRequest(); + assertEquals(request.getHeader("Authorization"), "abc"); + assertEquals("POST /v1/chat/ HTTP/1.1", request.getRequestLine()); + } + + @Test + public void testParams() throws Exception { + server.enqueue(new MockResponse().setBody("hello, world!")); + HttpUrl baseUrl = server.url("/v1/chat/"); + + HashMap params = new HashMap(1); + params.put("key", "value"); + String s = HttpKit.executeAndParse(HttpRequest.custom().url(baseUrl.toString()).post(params).build()); + assertEquals("hello, world!", s); + // 测试参数 + RecordedRequest request = server.takeRequest(); + assertEquals("key=value", request.getBody().readUtf8()); + assertEquals("POST /v1/chat/ HTTP/1.1", request.getRequestLine()); + } +} \ No newline at end of file diff --git a/src/test/java/com/fanruan/api/util/GeneralKitTest.java b/src/test/java/com/fanruan/api/util/GeneralKitTest.java index 849a0e4..7bbefa6 100644 --- a/src/test/java/com/fanruan/api/util/GeneralKitTest.java +++ b/src/test/java/com/fanruan/api/util/GeneralKitTest.java @@ -1,9 +1,7 @@ package com.fanruan.api.util; import com.fanruan.api.Prepare; -import com.fr.third.guava.base.Objects; import com.fr.general.GeneralUtils; -import com.fr.third.javax.persistence.criteria.CriteriaBuilder; import org.junit.Assert; import org.junit.Test; @@ -20,26 +18,8 @@ public class GeneralKitTest extends Prepare { } @Test - public void equals() throws Exception{ - Integer x = 5; - Integer y = 10; - Integer z =5; - Short a = 5; - Assert.assertEquals(GeneralKit.equals(x, y), false); - Assert.assertEquals(GeneralKit.equals(x, z), true); - Assert.assertEquals(GeneralKit.equals(z, a), false); - } - - @Test - public void hashCodes() { - class A { - } - ; - Object a = new A(); - Assert.assertEquals(GeneralKit.hashCode(a), Objects.hashCode(a)); - } public void objectToString() { - Integer s = new Integer(1); + Integer s = 1; Assert.assertEquals(GeneralKit.objectToString(s),"1"); } @@ -51,10 +31,10 @@ public class GeneralKitTest extends Prepare { @Test public void compare() { - Integer s = new Integer(1); - Integer s3 = new Integer(1); - Integer s1 = new Integer(2); - Integer s2 = new Integer(0); + Integer s = 1; + Integer s3 = 1; + Integer s1 = 2; + Integer s2 = 0; Assert.assertEquals(GeneralKit.compare(s,s1),-1); Assert.assertEquals(GeneralKit.compare(s,s3),0); Assert.assertEquals(GeneralKit.compare(s,s2),1); diff --git a/src/test/java/com/fanruan/api/util/ReflectKitTest.java b/src/test/java/com/fanruan/api/util/ReflectKitTest.java deleted file mode 100644 index 1c88dfb..0000000 --- a/src/test/java/com/fanruan/api/util/ReflectKitTest.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.fanruan.api.util; - -import org.junit.Test; - -import static org.junit.Assert.*; - -public class ReflectKitTest { - - @Test - public void classInstanceOf() { - assertEquals(ReflectKit.classInstanceOf(Integer.class,Object.class),true); - assertEquals(ReflectKit.classInstanceOf(Object.class,Integer.class),false); - } -} \ No newline at end of file diff --git a/src/test/java/com/fanruan/api/util/TypeKitTest.java b/src/test/java/com/fanruan/api/util/TypeKitTest.java new file mode 100644 index 0000000..9471f5a --- /dev/null +++ b/src/test/java/com/fanruan/api/util/TypeKitTest.java @@ -0,0 +1,19 @@ +package com.fanruan.api.util; + +import org.junit.Assert; +import org.junit.Test; + +public class TypeKitTest { + + @Test + public void classInstanceOf() { + Assert.assertTrue(TypeKit.classInstanceOf(Integer.class, Object.class)); + Assert.assertFalse(TypeKit.classInstanceOf(Object.class, Integer.class)); + } + + @Test + public void objectInstanceOf() { + Assert.assertTrue(TypeKit.objectInstanceOf(1, Integer.class)); + Assert.assertFalse(TypeKit.objectInstanceOf(1.0, Integer.class)); + } +} \ No newline at end of file