();
291 | result.add(AllowedOps.REPLACE);
292 | result.add(AllowedOps.GET_JSON);
293 |
294 | TreePath selection = jTree.getSelectionPath();
295 | if (selection == null) {
296 | return result;
297 | }
298 |
299 | JsonJTreeNode selectedNode = (JsonJTreeNode) selection.getLastPathComponent();
300 | JsonJTreeNode parentNode = null;
301 |
302 | if (selectedNode != null) {
303 | result.add(AllowedOps.DELETE);
304 | parentNode = (JsonJTreeNode) selectedNode.getParent();
305 | }
306 | if (parentNode != null) {
307 | result.add(AllowedOps.APPEND);
308 | result.add(AllowedOps.INSERT);
309 | }
310 | if (selectedNode.dataType.equals(JsonJTreeNode.DataType.ARRAY) || selectedNode.dataType.equals(JsonJTreeNode.DataType.OBJECT)) {
311 | result.add(AllowedOps.AS_CHILD);
312 | }
313 | if ((parentNode != null) && (parentNode.dataType.equals(JsonJTreeNode.DataType.OBJECT))) {
314 | result.add(AllowedOps.RENAME);
315 | }
316 | return result;
317 | }
318 | }
319 |
--------------------------------------------------------------------------------
/src/main/java/com/longforus/apidebugger/ui/JsonJTreeNode.java:
--------------------------------------------------------------------------------
1 | package com.longforus.apidebugger.ui;
2 |
3 | import com.google.gson.JsonArray;
4 | import com.google.gson.JsonElement;
5 | import com.google.gson.JsonObject;
6 | import com.google.gson.JsonParser;
7 | import com.google.gson.JsonSyntaxException;
8 | import java.util.Enumeration;
9 | import java.util.Iterator;
10 | import java.util.Map.Entry;
11 | import javax.swing.tree.DefaultMutableTreeNode;
12 | import org.apache.commons.lang3.StringUtils;
13 |
14 | /**
15 | * Provides the model for translating JsonElement into JTree data nodes. This class is not thread safe.
16 | *
17 | * @author Stephen Owens
18 | *
19 | * Provides the model for translating JsonElement into JTree data nodes.
20 | *
21 | *
22 | * Copyright 2011 Stephen P. Owens : steve@doitnext.com
23 | *
24 | *
25 | * Licensed under the Apache License, Version 2.0 (the "License");
26 | * you may not use this file except in compliance with the License.
27 | * You may obtain a copy of the License at
28 | *
29 | *
30 | * http://www.apache.org/licenses/LICENSE-2.0
31 | *
32 | *
33 | * Unless required by applicable law or agreed to in writing, software
34 | * distributed under the License is distributed on an "AS IS" BASIS,
35 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
36 | * See the License for the specific language governing permissions and
37 | * limitations under the License.
38 | *
39 | */
40 | @Deprecated
41 | public class JsonJTreeNode extends DefaultMutableTreeNode {
42 | /**
43 | * Using default serial id.
44 | */
45 | private static final long serialVersionUID = 1L;
46 |
47 | public enum DataType {
48 | ARRAY,
49 | OBJECT,
50 | VALUE
51 | }
52 |
53 | ;
54 | final DataType dataType;
55 | final int index;
56 | String fieldName;
57 | final String value;
58 | private int childCount = 0;
59 |
60 | public String getFieldName() {
61 | return fieldName;
62 | }
63 |
64 | /**
65 | * @param fieldName - name of field if applicable or null
66 | * @param index - index of element in the array or -1 if not part of an array
67 | * @param jsonElement - element to represent
68 | */
69 | public JsonJTreeNode(String fieldName, int index, JsonElement jsonElement) {
70 | this.index = index;
71 | this.fieldName = fieldName;
72 | if (jsonElement.isJsonArray()) {
73 | this.dataType = DataType.ARRAY;
74 | this.value = jsonElement.toString();
75 | populateChildren(jsonElement);
76 | } else if (jsonElement.isJsonObject()) {
77 | this.dataType = DataType.OBJECT;
78 | this.value = jsonElement.toString();
79 | populateChildren(jsonElement);
80 | } else if (jsonElement.isJsonPrimitive()) {
81 | this.dataType = DataType.VALUE;
82 | this.value = jsonElement.toString();
83 | } else if (jsonElement.isJsonNull()) {
84 | this.dataType = DataType.VALUE;
85 | this.value = jsonElement.toString();
86 | } else {
87 | throw new IllegalArgumentException("jsonElement is an unknown element type.");
88 | }
89 | }
90 |
91 | private void populateChildren(JsonElement myJsonElement) {
92 | switch (dataType) {
93 | case ARRAY:
94 | int index = 0;
95 | JsonArray array = myJsonElement.getAsJsonArray();
96 | childCount = array.size();
97 | Iterator it = array.iterator();
98 | while (it.hasNext()) {
99 | JsonElement element = it.next();
100 | JsonJTreeNode childNode = new JsonJTreeNode(null, index, element);
101 | this.add(childNode);
102 | index++;
103 | }
104 | break;
105 | case OBJECT:
106 | JsonObject object = myJsonElement.getAsJsonObject();
107 | childCount = object.size();
108 | for (Entry entry : object.entrySet()) {
109 | JsonJTreeNode childNode = new JsonJTreeNode(entry.getKey(), -1, entry.getValue());
110 | this.add(childNode);
111 | }
112 | break;
113 | default:
114 | throw new IllegalStateException("Internal coding error this should never happen.");
115 | }
116 | }
117 |
118 | public JsonElement asJsonElement() {
119 | StringBuilder sb = new StringBuilder();
120 | buildJsonString(sb);
121 | String json = sb.toString().trim();
122 | if (json.startsWith("{") || json.startsWith("[")) {
123 | return new JsonParser().parse(sb.toString());
124 | } else {
125 | // Safety check the JSON, if it is of a named value object
126 | // We cheat a little if it is an orphan name value pair then
127 | // if we wrap it in {} chars it will parse if it isn't the parse
128 | // fails.
129 | String testValue = "{" + json + "}";
130 | try {
131 | JsonElement wrapperElt = new JsonParser().parse(testValue);
132 | JsonObject obj = (JsonObject) wrapperElt;
133 | Iterator> it = obj.entrySet().iterator();
134 | Entry entry = it.next();
135 | return entry.getValue();
136 | } catch (JsonSyntaxException jse) {
137 | JsonElement rawElement = new JsonParser().parse(json);
138 | return rawElement;
139 | }
140 | }
141 | }
142 |
143 | @SuppressWarnings("unchecked")
144 | private void buildJsonString(StringBuilder sb) {
145 | if (!StringUtils.isEmpty(this.fieldName)) {
146 | sb.append("\"" + this.fieldName + "\":");
147 | }
148 | Enumeration children;
149 | switch (dataType) {
150 | case ARRAY:
151 | sb.append("[");
152 | children = this.children();
153 | processNode(sb, children);
154 | sb.append("]");
155 | break;
156 | case OBJECT:
157 | sb.append("{");
158 | children = this.children();
159 | processNode(sb, children);
160 | sb.append("}");
161 | break;
162 | default: {
163 | // Use the JSON parser to parse the value for safety
164 | JsonElement elt = new JsonParser().parse(this.value);
165 | sb.append(elt.toString());
166 | }
167 | }
168 | }
169 |
170 | private void processNode(StringBuilder sb, Enumeration children) {
171 | while (children.hasMoreElements()) {
172 | JsonJTreeNode child = (JsonJTreeNode) children.nextElement();
173 | child.buildJsonString(sb);
174 | if (children.hasMoreElements()) {
175 | sb.append(",");
176 | }
177 | }
178 | }
179 |
180 | @Override
181 | public String toString() {
182 | switch (dataType) {
183 | case ARRAY:
184 | if (index >= 0) {
185 | return String.format("%d [%d]", index, childCount);
186 | }else if (fieldName != null) {
187 | return String.format("%s [%d]", fieldName, childCount);
188 | }else {
189 | return String.format("(%s)", dataType.name());
190 | }
191 | case OBJECT:
192 | if (index >= 0) {
193 | return String.format("%d {%d}", index, childCount);
194 | }else if (fieldName != null) {
195 | return String.format("%s {%d}", fieldName, childCount);
196 | } else {
197 | return String.format("(%s)", dataType.name());
198 | }
199 | default:
200 | if (index >= 0) {
201 | return String.format("[%d] %s", index, value);
202 | } else if (fieldName != null) {
203 | return String.format("%s: %s", fieldName, value);
204 | } else {
205 | return String.format("%s",value);
206 | }
207 | }
208 | }
209 | public String toSSearchStr() {
210 | switch (dataType) {
211 | case ARRAY:
212 | if (index >= 0) {
213 | return String.format("%d [%d]", index, childCount);
214 | }else if (fieldName != null) {
215 | return String.format("%s [%d]", fieldName, childCount);
216 | }else {
217 | return String.format("(%s)", dataType.name());
218 | }
219 | case OBJECT:
220 | if (index >= 0) {
221 | return String.format("%d {%d}", index, childCount);
222 | }else if (fieldName != null) {
223 | return String.format("%s {%d}", fieldName, childCount);
224 | } else {
225 | return String.format("(%s)", dataType.name());
226 | }
227 | default:
228 | if (index >= 0) {
229 | return String.format("[%d] %s", index, value);
230 | } else if (fieldName != null) {
231 | return String.format("\"%s\": %s", fieldName, value);
232 | } else {
233 | return String.format("%s",value);
234 | }
235 | }
236 | }
237 | /*
238 | @Override
239 | public String toString() {
240 | switch(dataType) {
241 | case ARRAY:
242 | case OBJECT:
243 | if(index >= 0) {
244 | return String.format("[%d] (%s)", index, dataType.name());
245 | } else if(fieldName != null) {
246 | return String.format("%s (%s)", fieldName, dataType.name());
247 | } else {
248 | return String.format("(%s)", dataType.name());
249 | }
250 | default:
251 | if(index >= 0) {
252 | return String.format("[%d] %s", index, value);
253 | } else if(fieldName != null) {
254 | return String.format("%s: %s", fieldName, value);
255 | } else {
256 | return String.format("%s", value);
257 | }
258 |
259 | }
260 | }
261 | */
262 | }
263 |
--------------------------------------------------------------------------------
/src/main/java/com/longforus/apidebugger/ui/JsonTreeCellRenderer.java:
--------------------------------------------------------------------------------
1 | package com.longforus.apidebugger.ui;
2 |
3 | import java.awt.Component;
4 | import javax.swing.JTree;
5 | import javax.swing.tree.DefaultTreeCellRenderer;
6 |
7 | /**
8 | * 自定义树描述类,将树的每个节点设置成不同的图标
9 | *
10 | * @author RuiLin.Xie - xKF24276
11 | */
12 | @Deprecated
13 | public class JsonTreeCellRenderer extends DefaultTreeCellRenderer {
14 | /**
15 | * ID
16 | */
17 | private static final long serialVersionUID = 1L;
18 |
19 | /**
20 | * 重写父类DefaultTreeCellRenderer的方法
21 | */
22 | @Override
23 | public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
24 |
25 | //执行父类原型操作
26 | super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
27 |
28 | setText(value.toString());
29 |
30 | if (sel) {
31 | setForeground(getTextSelectionColor());
32 | } else {
33 | setForeground(getTextNonSelectionColor());
34 | }
35 | this.setIcon(null);
36 | return this;
37 | }
38 | }
--------------------------------------------------------------------------------
/src/main/java/com/longforus/apidebugger/ui/MainPanel.form:
--------------------------------------------------------------------------------
1 |
2 |
272 |
--------------------------------------------------------------------------------
/src/main/java/com/longforus/apidebugger/ui/MainPanel.java:
--------------------------------------------------------------------------------
1 | package com.longforus.apidebugger.ui;
2 |
3 | import com.jgoodies.forms.layout.CellConstraints;
4 | import com.jgoodies.forms.layout.FormLayout;
5 | import com.longforus.apidebugger.ExtFunKt;
6 | import com.longforus.apidebugger.MyValueHandler;
7 | import com.longforus.apidebugger.OB;
8 | import com.longforus.apidebugger.UIActionHandler;
9 | import com.longforus.apidebugger.UILifecycleHandler;
10 | import com.longforus.apidebugger.bean.ApiBean;
11 | import com.longforus.apidebugger.encrypt.IEncryptHandler;
12 | import com.teamdev.jxbrowser.chromium.Browser;
13 | import com.teamdev.jxbrowser.chromium.BrowserContext;
14 | import com.teamdev.jxbrowser.chromium.BrowserException;
15 | import com.teamdev.jxbrowser.chromium.JSValue;
16 | import com.teamdev.jxbrowser.chromium.ProtocolService;
17 | import com.teamdev.jxbrowser.chromium.URLResponse;
18 | import com.teamdev.jxbrowser.chromium.swing.BrowserView;
19 | import java.awt.Color;
20 | import java.awt.Dimension;
21 | import java.awt.FlowLayout;
22 | import java.awt.HeadlessException;
23 | import java.awt.Image;
24 | import java.awt.Insets;
25 | import java.awt.Toolkit;
26 | import java.awt.event.ItemEvent;
27 | import java.awt.event.KeyAdapter;
28 | import java.awt.event.KeyEvent;
29 | import java.awt.event.KeyListener;
30 | import java.awt.event.MouseEvent;
31 | import java.io.DataInputStream;
32 | import java.io.InputStream;
33 | import java.io.UnsupportedEncodingException;
34 | import java.net.MalformedURLException;
35 | import java.net.URL;
36 | import javax.swing.BorderFactory;
37 | import javax.swing.DefaultComboBoxModel;
38 | import javax.swing.ImageIcon;
39 | import javax.swing.JButton;
40 | import javax.swing.JComboBox;
41 | import javax.swing.JComponent;
42 | import javax.swing.JFrame;
43 | import javax.swing.JLabel;
44 | import javax.swing.JMenuItem;
45 | import javax.swing.JPanel;
46 | import javax.swing.JPopupMenu;
47 | import javax.swing.JProgressBar;
48 | import javax.swing.JScrollPane;
49 | import javax.swing.JTable;
50 | import javax.swing.JTextField;
51 | import javax.swing.JTextPane;
52 | import javax.swing.SizeRequirements;
53 | import javax.swing.event.MouseInputAdapter;
54 | import javax.swing.text.Element;
55 | import javax.swing.text.View;
56 | import javax.swing.text.ViewFactory;
57 | import javax.swing.text.html.HTMLEditorKit;
58 | import javax.swing.text.html.InlineView;
59 | import javax.swing.text.html.ParagraphView;
60 |
61 | /**
62 | * Created by XQ Yang on 8/30/2018 10:34 AM.
63 | * Description :
64 | */
65 |
66 | public class MainPanel extends JFrame {
67 | private ParamsTableModel mParamsTableModel;
68 | private JComboBox mCbBaseUrl;
69 | private JButton mBtnSaveBaseUrl;
70 | private JComboBox mCbApiUrl;
71 | private JButton mBtnSend;
72 | private JComboBox mCbEncrypt;
73 | private JTable mTbParams;
74 | private JTextPane mTpInfo;
75 | private JLabel lbStatus;
76 | private JPanel baseP;
77 | private JButton btnDelUrl;
78 | private JButton btnDelApi;
79 | private JComboBox mCbMethod;
80 | private JButton btnAddRow;
81 | private JButton btnDelRow;
82 | private JButton btnClear;
83 | private BrowserView mBrowserView;
84 | private JButton mbtnDp;
85 | private JTextField tvTestCount;
86 | private JButton mBtnStartTest;
87 | private JProgressBar mPb;
88 | private Browser mBrowser;
89 |
90 | public JProgressBar getPb() {
91 | return mPb;
92 | }
93 |
94 | public JTextField getTvTestCount() {
95 | return tvTestCount;
96 | }
97 |
98 | public JComboBox getCbMethod() {
99 | return mCbMethod;
100 | }
101 |
102 | public JTable getTbParams() {
103 | return mTbParams;
104 | }
105 |
106 | public ParamsTableModel getParamsTableModel() {
107 | return mParamsTableModel;
108 | }
109 |
110 | public JComboBox getCbEncrypt() {
111 | return mCbEncrypt;
112 | }
113 |
114 | public JLabel getLbStatus() {
115 | return lbStatus;
116 | }
117 |
118 | public JTextPane getTpInfo() {
119 | return mTpInfo;
120 | }
121 |
122 | public JComboBox getCbBaseUrl() {
123 | return mCbBaseUrl;
124 | }
125 |
126 | public JComboBox getCbApiUrl() {
127 | return mCbApiUrl;
128 | }
129 |
130 | public int getSelectedEncryptID() {
131 | return MyValueHandler.INSTANCE.encryptIndex2Id(mCbEncrypt.getSelectedIndex());
132 | }
133 |
134 | public int getSelectedMethodType() {
135 | return mCbMethod.getSelectedIndex();
136 | }
137 |
138 | public MainPanel(String title) throws HeadlessException {
139 | super(title);
140 | $$$setupUI$$$();
141 |
142 | setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
143 | String filename = getClass().getResource("") + "jsonView/send.png";
144 | try {
145 | ImageIcon icon = new ImageIcon(new URL(filename));
146 | setIconImage(icon.getImage());
147 | icon.setImage(icon.getImage().getScaledInstance(68, 68, Image.SCALE_SMOOTH));
148 |
149 | mBtnSend.setIcon(icon);
150 | } catch (MalformedURLException e) {
151 | e.printStackTrace();
152 | }
153 | mCbMethod.setModel(new DefaultComboBoxModel(new String[] { "POST", "GET" }));
154 | //限制只能输入数字
155 | tvTestCount.addKeyListener(new KeyAdapter() {
156 | public void keyTyped(KeyEvent e) {
157 | int keyChar = e.getKeyChar();
158 | if (keyChar < KeyEvent.VK_0 || keyChar > KeyEvent.VK_9) {
159 | e.consume(); //关键,屏蔽掉非法输入
160 | }
161 | }
162 | });
163 |
164 | setContentPane(baseP);
165 | setJMenuBar(UILifecycleHandler.INSTANCE.getMenuBar());
166 | initEvent();
167 | //mCbApiUrl.setRenderer(new DeleteBtnComboBoxRenderer(o -> UIActionHandler.INSTANCE.onDelApiUrl((ApiBean) o)));
168 | //mCbBaseUrl.setRenderer(new DeleteBtnComboBoxRenderer(UIActionHandler.INSTANCE :: onDelBaseUrl));
169 | initTextPanel();
170 | initTable();
171 | pack();
172 | Dimension screensize = Toolkit.getDefaultToolkit().getScreenSize();
173 | int x = (int) screensize.getWidth() / 2 - baseP.getPreferredSize().width / 2;
174 | int y = 0;
175 | setLocation(x, y);
176 | setVisible(true);
177 | browserInit();
178 | //Observable.create((ObservableOnSubscribe) emitter -> emitter.onNext("{}")).delay(10, TimeUnit.MILLISECONDS).subscribe(
179 | // s -> mBrowser.executeJavaScript("app.doc" + "._id || (document.location.href = document.location.pathname + \"#/new\", location.reload())"));
180 |
181 | }
182 |
183 | public void setJsonData(String jsonData) {
184 | JSValue app = mBrowser.executeJavaScriptAndReturnValue("app");
185 | JSValue write = app.asObject().getProperty("setData");
186 | write.asFunction().invoke(app.asObject(), jsonData);
187 | }
188 |
189 | private void browserInit() {
190 | BrowserContext browserContext = mBrowser.getContext();
191 | ProtocolService protocolService = browserContext.getProtocolService();
192 | protocolService.setProtocolHandler("jar", request -> {
193 | try {
194 | URLResponse response = new URLResponse();
195 | URL path = new URL(request.getURL());
196 | InputStream inputStream = path.openStream();
197 | DataInputStream stream = new DataInputStream(inputStream);
198 | byte[] data = new byte[stream.available()];
199 | stream.readFully(data);
200 | response.setData(data);
201 | String mimeType = getMimeType(path.toString());
202 | response.getHeaders().setHeader("Content-Type", mimeType);
203 | return response;
204 | } catch (Exception ignored) {
205 | }
206 | return null;
207 | });
208 |
209 | // Assume that we need to load a resource related to this class in the JAR file
210 | String url = getClass().getResource("") + "jsonView/index.html";
211 | mBrowser.loadURL(url);
212 | }
213 |
214 | private static String getMimeType(String path) {
215 | if (path.endsWith(".html")) {
216 | return "text/html";
217 | }
218 | if (path.endsWith(".css")) {
219 | return "text/css";
220 | }
221 | if (path.endsWith(".js")) {
222 | return "text/javascript";
223 | }
224 | if (path.endsWith(".png")) {
225 | return "image/png";
226 | }
227 | if (path.endsWith(".svg")) {
228 | return "image/svg+xml";
229 | }
230 | if (path.endsWith(".ico")) {
231 | return "image/x-icon";
232 | }
233 | return "text/html";
234 | }
235 |
236 | private void initEvent() {
237 | mBtnSaveBaseUrl.addActionListener(e -> UIActionHandler.INSTANCE.onSaveBaseUrl(mCbBaseUrl.getModel().getSelectedItem()));
238 | btnDelUrl.addActionListener(e -> UIActionHandler.INSTANCE.onDelBaseUrl(mCbBaseUrl.getModel().getSelectedItem()));
239 | btnDelApi.addActionListener(e -> UIActionHandler.INSTANCE.onDelApiUrl((ApiBean) mCbApiUrl.getModel().getSelectedItem()));
240 | mCbApiUrl.addItemListener(e -> {
241 | if (e.getStateChange() == ItemEvent.SELECTED) {
242 | if (e.getItem() instanceof ApiBean) {
243 | UIActionHandler.INSTANCE.onApiItemChanged(((ApiBean) e.getItem()));
244 | }
245 | }
246 | });
247 | mBtnSend.addActionListener(e -> UIActionHandler.INSTANCE.onSend());
248 |
249 | mCbMethod.addItemListener(e -> UIActionHandler.INSTANCE.onMethodChanged(mCbMethod.getSelectedIndex()));
250 | mCbEncrypt.addItemListener(e -> UIActionHandler.INSTANCE.onEncryptTypeChanged(((IEncryptHandler) e.getItem()).getTypeCode()));
251 | mbtnDp.addActionListener(e -> showDefaultParamsDialog());
252 | mBtnStartTest.addActionListener(e -> UIActionHandler.INSTANCE.onStartTest());
253 | }
254 |
255 | private void showDefaultParamsDialog() {
256 | if (MyValueHandler.INSTANCE.getCurProject() == null) {
257 | ExtFunKt.showErrorMsg("Please create the project first");
258 | return;
259 | }
260 | DefaultParamsDialog paramsDialog = new DefaultParamsDialog();
261 | paramsDialog.pack();
262 | paramsDialog.setLocation((getX() + getWidth() / 2) - (paramsDialog.getWidth() / 2), getY() + getHeight() / 2 - paramsDialog.getHeight() / 2);
263 | paramsDialog.setVisible(true);
264 | }
265 |
266 | private void initTextPanel() {
267 | mTpInfo.addMouseListener(new MouseInputAdapter() {
268 | @Override
269 | public void mouseClicked(MouseEvent e) {
270 | super.mouseClicked(e);
271 | if (e.getButton() == MouseEvent.BUTTON3) {
272 | JPopupMenu menu = new JPopupMenu("Clear");
273 | JMenuItem clear1 = menu.add(new JMenuItem("clear"));
274 | clear1.addActionListener(e1 -> mTpInfo.setText(""));
275 | menu.show(mTpInfo, e.getX(), e.getY());
276 | }
277 | }
278 | });
279 | //支持自动换行
280 | HTMLEditorKit editorKit = new HTMLEditorKit() {
281 | @Override
282 | public ViewFactory getViewFactory() {
283 |
284 | return new HTMLFactory() {
285 | public View create(Element e) {
286 | View v = super.create(e);
287 | if (v instanceof InlineView) {
288 | return new InlineView(e) {
289 | public int getBreakWeight(int axis, float pos, float len) {
290 | return GoodBreakWeight;
291 | }
292 |
293 | public View breakView(int axis, int p0, float pos, float len) {
294 | if (axis == View.X_AXIS) {
295 | checkPainter();
296 | int p1 = getGlyphPainter().getBoundedPosition(this, p0, pos, len);
297 | if (p0 == getStartOffset() && p1 == getEndOffset()) {
298 | return this;
299 | }
300 | return createFragment(p0, p1);
301 | }
302 | return this;
303 | }
304 | };
305 | } else if (v instanceof ParagraphView) {
306 | return new ParagraphView(e) {
307 | protected SizeRequirements calculateMinorAxisRequirements(int axis, SizeRequirements r) {
308 | if (r == null) {
309 | r = new SizeRequirements();
310 | }
311 | float pref = layoutPool.getPreferredSpan(axis);
312 | float min = layoutPool.getMinimumSpan(axis);
313 | // Don't include insets, Box.getXXXSpan will include them.
314 | r.minimum = (int) min;
315 | r.preferred = Math.max(r.minimum, (int) pref);
316 | r.maximum = Integer.MAX_VALUE;
317 | r.alignment = 0.5f;
318 | return r;
319 | }
320 | };
321 | }
322 | return v;
323 | }
324 | };
325 | }
326 | };
327 | mTpInfo.setEditorKit(editorKit);
328 | }
329 |
330 | public void resetParamsTbModel() {
331 | mParamsTableModel = MainPanel.resetParamsTbModel(mTbParams);
332 | }
333 |
334 | public static ParamsTableModel resetParamsTbModel(JTable table) {
335 | ParamsTableModel model = new ParamsTableModel();
336 | table.setModel(model);
337 | table.getColumnModel().getColumn(0).setPreferredWidth(50);
338 | table.getColumnModel().getColumn(1).setPreferredWidth(120);
339 | table.getColumnModel().getColumn(2).setPreferredWidth(350);
340 | return model;
341 | }
342 |
343 | private void initTable() {
344 | mParamsTableModel = resetParamsTbModel(mTbParams);
345 | mTbParams.addKeyListener(new KeyListener() {
346 | @Override
347 | public void keyTyped(KeyEvent e) {
348 |
349 | }
350 |
351 | @Override
352 | public void keyPressed(KeyEvent e) {
353 |
354 | }
355 |
356 | @Override
357 | public void keyReleased(KeyEvent e) {
358 | if (e.getKeyCode() == KeyEvent.VK_DELETE) {
359 | mParamsTableModel.removeRow(mTbParams.getSelectedRow());
360 | }
361 | }
362 | });
363 | btnAddRow.addActionListener(e -> {
364 | mParamsTableModel.addEmptyRow();
365 | mTbParams.requestFocus();
366 | int index = mParamsTableModel.getRowCount() - 1;
367 | mTbParams.setRowSelectionInterval(index, index);//最后一行获得焦点
368 | mTbParams.editCellAt(index, 1);
369 | });
370 | btnDelRow.addActionListener(e -> mParamsTableModel.removeRow(mTbParams.getSelectedRow()));
371 | btnClear.addActionListener(e -> UIActionHandler.INSTANCE.onClearParams());
372 | }
373 |
374 | private void createUIComponents() {
375 | try {
376 | mBrowser = new Browser();
377 | } catch (BrowserException e) {
378 | ExtFunKt.showErrorMsg("already been opened !!!");
379 | }
380 | mBrowserView = new BrowserView(mBrowser);
381 | }
382 |
383 | @Override
384 | protected void finalize() throws Throwable {
385 | super.finalize();
386 | OB.INSTANCE.onExit();
387 | }
388 |
389 | public String getCurApiUrl() {
390 | if (mCbApiUrl.getEditor().getItem() != null) {
391 | return mCbApiUrl.getEditor().getItem().toString();
392 | }
393 | return "";
394 | }
395 |
396 | public int getCurMethod() {
397 | return mCbMethod.getSelectedIndex();
398 | }
399 |
400 | public int getCurEncryptCode() {
401 | return mCbEncrypt.getSelectedIndex();
402 | }
403 |
404 | public String getCurBaseUrl() {
405 | return (String) mCbBaseUrl.getSelectedItem();
406 | }
407 |
408 | /**
409 | * Method generated by IntelliJ IDEA GUI Designer
410 | * >>> IMPORTANT!! <<<
411 | * DO NOT edit this method OR call it in your code!
412 | *
413 | * @noinspection ALL
414 | */
415 | private void $$$setupUI$$$() {
416 | createUIComponents();
417 | baseP = new JPanel();
418 | baseP.setLayout(new FormLayout(
419 | "fill:d:noGrow,left:4dlu:noGrow,fill:300px:noGrow,left:4dlu:noGrow,fill:d:noGrow,left:4dlu:noGrow,fill:max(d;4px):noGrow,left:4dlu:noGrow,fill:d:noGrow," +
420 | "left:4dlu:noGrow,fill:d:noGrow,left:4dlu:noGrow,fill:600px:grow",
421 | "center:d:noGrow,center:max(d;4px):noGrow,top:4dlu:noGrow,center:33px:noGrow,center:33px:noGrow,center:200px:noGrow,center:40px:noGrow,top:4dlu:noGrow,center:p:grow," +
422 | "center:max(d;4px):noGrow"));
423 | baseP.setName("Api debugger");
424 | baseP.setPreferredSize(new Dimension(1341, 980));
425 | baseP.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1), null));
426 | final JLabel label1 = new JLabel();
427 | label1.setText("Base Url:");
428 | CellConstraints cc = new CellConstraints();
429 | baseP.add(label1, cc.xy(1, 2));
430 | mCbBaseUrl = new JComboBox();
431 | mCbBaseUrl.setEditable(true);
432 | baseP.add(mCbBaseUrl, cc.xy(3, 2));
433 | mBtnSaveBaseUrl = new JButton();
434 | mBtnSaveBaseUrl.setText("Save");
435 | baseP.add(mBtnSaveBaseUrl, cc.xy(5, 2));
436 | final JScrollPane scrollPane1 = new JScrollPane();
437 | baseP.add(scrollPane1, cc.xyw(1, 6, 11, CellConstraints.FILL, CellConstraints.FILL));
438 | scrollPane1.setBorder(BorderFactory.createTitledBorder("Request Parameter"));
439 | mTbParams = new JTable();
440 | mTbParams.setRowHeight(25);
441 | scrollPane1.setViewportView(mTbParams);
442 | lbStatus = new JLabel();
443 | lbStatus.setText("Status:");
444 | baseP.add(lbStatus, cc.xyw(1, 10, 11));
445 | final JScrollPane scrollPane2 = new JScrollPane();
446 | baseP.add(scrollPane2, cc.xywh(13, 1, 1, 7, CellConstraints.FILL, CellConstraints.FILL));
447 | scrollPane2.setBorder(BorderFactory.createTitledBorder("Request Information"));
448 | mTpInfo = new JTextPane();
449 | mTpInfo.setText("");
450 | scrollPane2.setViewportView(mTpInfo);
451 | mCbEncrypt = new JComboBox();
452 | baseP.add(mCbEncrypt, cc.xy(11, 2));
453 | btnDelUrl = new JButton();
454 | btnDelUrl.setText("Delete");
455 | baseP.add(btnDelUrl, cc.xy(7, 2));
456 | mCbMethod = new JComboBox();
457 | baseP.add(mCbMethod, cc.xy(9, 2));
458 | final JLabel label2 = new JLabel();
459 | label2.setText("Api Url:");
460 | baseP.add(label2, cc.xy(1, 4));
461 | mCbApiUrl = new JComboBox();
462 | mCbApiUrl.setEditable(true);
463 | baseP.add(mCbApiUrl, cc.xyw(3, 4, 5));
464 | final JPanel panel1 = new JPanel();
465 | panel1.setLayout(new FlowLayout(FlowLayout.RIGHT, 3, 0));
466 | baseP.add(panel1, cc.xyw(1, 7, 11));
467 | btnAddRow = new JButton();
468 | btnAddRow.setText("Add Row");
469 | panel1.add(btnAddRow);
470 | btnDelRow = new JButton();
471 | btnDelRow.setText("Delete Row");
472 | panel1.add(btnDelRow);
473 | btnClear = new JButton();
474 | btnClear.setText("Clear");
475 | panel1.add(btnClear);
476 | mBtnSend = new JButton();
477 | mBtnSend.setBorderPainted(false);
478 | mBtnSend.setIconTextGap(1);
479 | mBtnSend.setInheritsPopupMenu(false);
480 | mBtnSend.setMargin(new Insets(5, 5, 5, 5));
481 | mBtnSend.setMaximumSize(new Dimension(78, 78));
482 | mBtnSend.setMinimumSize(new Dimension(78, 78));
483 | mBtnSend.setOpaque(true);
484 | mBtnSend.setPreferredSize(new Dimension(78, 78));
485 | mBtnSend.setRequestFocusEnabled(false);
486 | mBtnSend.setText("");
487 | mBtnSend.setToolTipText("Send");
488 | baseP.add(mBtnSend, cc.xywh(11, 4, 1, 2));
489 | final JPanel panel2 = new JPanel();
490 | panel2.setLayout(new com.intellij.uiDesigner.core.GridLayoutManager(1, 3, new Insets(0, 0, 0, 0), -1, -1));
491 | panel2.setBackground(new Color(-15856893));
492 | baseP.add(panel2, cc.xyw(1, 5, 3));
493 | final JLabel label3 = new JLabel();
494 | label3.setForeground(new Color(-1));
495 | label3.setText("Pressure test");
496 | panel2.add(label3, new com.intellij.uiDesigner.core.GridConstraints(0, 0, 1, 1, com.intellij.uiDesigner.core.GridConstraints.ANCHOR_WEST,
497 | com.intellij.uiDesigner.core.GridConstraints.FILL_NONE, com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_FIXED,
498 | com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
499 | tvTestCount = new JTextField();
500 | tvTestCount.setToolTipText("test count");
501 | panel2.add(tvTestCount, new com.intellij.uiDesigner.core.GridConstraints(0, 1, 1, 1, com.intellij.uiDesigner.core.GridConstraints.ANCHOR_WEST,
502 | com.intellij.uiDesigner.core.GridConstraints.FILL_HORIZONTAL, com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_WANT_GROW,
503 | com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_FIXED, null, new Dimension(150, -1), null, 0, false));
504 | mBtnStartTest = new JButton();
505 | mBtnStartTest.setText("Start");
506 | panel2.add(mBtnStartTest, new com.intellij.uiDesigner.core.GridConstraints(0, 2, 1, 1, com.intellij.uiDesigner.core.GridConstraints.ANCHOR_CENTER,
507 | com.intellij.uiDesigner.core.GridConstraints.FILL_HORIZONTAL,
508 | com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_CAN_SHRINK | com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_CAN_GROW,
509 | com.intellij.uiDesigner.core.GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
510 | baseP.add(mBrowserView, cc.xywh(1, 8, 13, 2));
511 | btnDelApi = new JButton();
512 | btnDelApi.setText("Delete");
513 | baseP.add(btnDelApi, cc.xy(9, 4));
514 | mbtnDp = new JButton();
515 | mbtnDp.setText(" Default Parameter");
516 | mbtnDp.setToolTipText(" Set Current Project Default Parameter");
517 | baseP.add(mbtnDp, cc.xyw(7, 5, 3));
518 | mPb = new JProgressBar();
519 | mPb.setMaximumSize(new Dimension(50, 10));
520 | mPb.setPreferredSize(new Dimension(50, 10));
521 | baseP.add(mPb, cc.xy(13, 10, CellConstraints.FILL, CellConstraints.DEFAULT));
522 | }
523 |
524 | /** @noinspection ALL */
525 | public JComponent $$$getRootComponent$$$() {
526 | return baseP;
527 | }
528 | }
529 |
--------------------------------------------------------------------------------
/src/main/java/com/longforus/apidebugger/ui/ParamsTableModel.java:
--------------------------------------------------------------------------------
1 | package com.longforus.apidebugger.ui;
2 |
3 | import com.longforus.apidebugger.bean.TableBean;
4 | import java.util.ArrayList;
5 | import java.util.List;
6 | import java.util.stream.Collectors;
7 | import javax.swing.table.AbstractTableModel;
8 | import org.apache.commons.lang3.StringUtils;
9 |
10 | public class ParamsTableModel extends AbstractTableModel {
11 | //单元格元素类型
12 | private Class[] cellType = { Boolean.class, String.class, String.class };
13 | //表头
14 | private String title[] = { "select", "key", "value" };
15 | //模拟数据
16 | //private Object data[][] = {
17 | // { "1", new ImageIcon("e://image/3.jpg"), new Boolean(true), 0, new JButton("start1") }, {
18 | // "2", new ImageIcon("e://image/1.jpg"), new Boolean(false), 60, new JButton("start2") }, {
19 | // "3", new ImageIcon("e://image/4.png"), new Boolean(false), 25, new JButton("start3") } };
20 |
21 | private List data = new ArrayList<>();
22 |
23 | public ParamsTableModel() {
24 | }
25 |
26 | public List getData() {
27 | return data.stream().filter(tableBean -> StringUtils.isNotEmpty(tableBean.getKey()) && StringUtils.isNotEmpty(tableBean.getValue())).collect(Collectors.toList());
28 | }
29 |
30 | public void setData(List data) {
31 | this.data.clear();
32 | this.data.addAll(data);
33 | fireTableDataChanged();
34 | }
35 |
36 | public void clear() {
37 | int size = this.data.size();
38 | this.data.clear();
39 | fireTableRowsDeleted(0, size);
40 | }
41 |
42 | public void addEmptyRow() {
43 | data.add(new TableBean(true, "", ""));
44 | fireTableRowsInserted(data.size() - 1, data.size() - 1);
45 | }
46 |
47 | public void removeRow(int row) {
48 | if (row > -1 && row < data.size()) {
49 | data.remove(row);
50 | }
51 | fireTableRowsDeleted(row, row);
52 | }
53 |
54 | @Override
55 | public Class> getColumnClass(int arg0) {
56 | return cellType[arg0];
57 | }
58 |
59 | @Override
60 | public String getColumnName(int arg0) {
61 | return title[arg0];
62 | }
63 |
64 | @Override
65 | public int getColumnCount() {
66 | return title.length;
67 | }
68 |
69 | @Override
70 | public int getRowCount() {
71 | return data.size();
72 | }
73 |
74 | @Override
75 | public Object getValueAt(int rowIndex, int columnIndex) {
76 | if (rowIndex < data.size()) {
77 | switch (columnIndex) {
78 | case 0:
79 | return data.get(rowIndex).getSelected();
80 | case 1:
81 | return data.get(rowIndex).getKey();
82 | case 2:
83 | return data.get(rowIndex).getValue();
84 | }
85 | }
86 | return null;
87 | }
88 |
89 | //重写isCellEditable方法
90 |
91 | @Override
92 | public boolean isCellEditable(int rowIndex, int columnIndex) {
93 | return true;
94 | }
95 |
96 | //重写setValueAt方法
97 |
98 | @Override
99 | public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
100 | if (rowIndex < data.size()) {
101 | switch (columnIndex) {
102 | case 0:
103 | data.get(rowIndex).setSelected((Boolean) aValue);
104 | break;
105 | case 1:
106 | data.get(rowIndex).setKey((String) aValue);
107 | break;
108 | case 2:
109 | data.get(rowIndex).setValue((String) aValue);
110 | break;
111 | }
112 | }
113 | this.fireTableCellUpdated(rowIndex, columnIndex);
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/longforus/apidebugger/ExtFun.kt:
--------------------------------------------------------------------------------
1 | package com.longforus.apidebugger
2 |
3 | import java.awt.Color
4 | import javax.swing.JOptionPane
5 | import javax.swing.JTextPane
6 | import javax.swing.text.BadLocationException
7 | import javax.swing.text.MutableAttributeSet
8 | import javax.swing.text.SimpleAttributeSet
9 | import javax.swing.text.StyleConstants
10 |
11 | /**
12 | * Created by XQ Yang on 8/30/2018 3:05 PM.
13 | * Description :
14 | */
15 | fun JTextPane.append(str:String,color: Color? = null,autoScroll:Boolean = true){
16 | val doc = this.document
17 | if (doc != null) {
18 | try {
19 | var attr: MutableAttributeSet? = null
20 | if (color != null) {
21 | attr = SimpleAttributeSet()
22 | StyleConstants.setForeground(attr, color)
23 | StyleConstants.setBold(attr, true)
24 | }
25 | doc.insertString(doc.length, str, attr)
26 | if (autoScroll) {
27 | this.caretPosition = this.styledDocument.length
28 | }
29 | } catch (e: BadLocationException) {
30 | }
31 |
32 | }
33 | }
34 |
35 | fun showErrorMsg(msg:String){
36 | JOptionPane.showMessageDialog(null, msg,"Error", JOptionPane.ERROR_MESSAGE)
37 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/longforus/apidebugger/HttpManage.kt:
--------------------------------------------------------------------------------
1 | package com.longforus.apidebugger
2 |
3 | import com.google.gson.JsonObject
4 | import com.longforus.apidebugger.MyValueHandler.mGson
5 | import com.longforus.apidebugger.ui.MainPanel
6 | import okhttp3.*
7 | import java.awt.Color
8 | import java.io.IOException
9 | import java.util.concurrent.TimeUnit
10 |
11 |
12 | /**
13 | * Created by XQ Yang on 8/30/2018 2:29 PM.
14 | * Description :
15 | */
16 | object HttpManage {
17 |
18 | lateinit var mainPanel: MainPanel
19 | val okHttpClient = OkHttpClient.Builder().writeTimeout(30, TimeUnit.SECONDS)
20 | .readTimeout(30, TimeUnit.SECONDS)
21 | .connectTimeout(30, TimeUnit.SECONDS).build()
22 |
23 |
24 | fun sendTestRequest(request: Request? = getRequest(), isLast: Boolean = false, allCount: Int = 0,startTime:Long = 0) {
25 | request?.let {
26 | if (!isLast) {
27 | okHttpClient.newCall(request).enqueue(object : Callback {
28 | override fun onFailure(call: Call, e: IOException) {
29 | }
30 |
31 | override fun onResponse(call: Call, response: Response) {
32 | synchronized(this@HttpManage) {
33 | com.longforus.apidebugger.mainPanel.pb.value += 1
34 | }
35 | }
36 | })
37 | } else {
38 | doRequest(request,startTime,allCount)
39 | }
40 | }
41 | }
42 |
43 | fun sendRequest(request: Request? = getRequest()) {
44 | request?.let {
45 | doRequest(request)
46 | }
47 | }
48 |
49 |
50 | fun getRequest(): Request? {
51 | val url = getAbsoluteUrl(mainPanel.curApiUrl)
52 | if (url.isEmpty()) {
53 | return null
54 | }
55 | return buildRequest(url, UIActionHandler.getParamsMap(mainPanel.paramsTableModel, false), mainPanel.curMethod, mainPanel.curEncryptCode)
56 | }
57 |
58 |
59 | private fun doRequest(request: Request, startTime: Long = System.currentTimeMillis(), allCount: Int = 0) {
60 | okHttpClient.newCall(request).enqueue(object : Callback {
61 | override fun onFailure(call: Call, e: IOException) {
62 | mainPanel.lbStatus.text = "onFailure message : ${e.message}\n"
63 | mainPanel.tpInfo.append( "\nonFailure \n message : ${e.message}\n", Color.RED)
64 | mainPanel.tpInfo.append(" consuming: ${System.currentTimeMillis() - startTime}ms \n", Color.RED)
65 | }
66 |
67 | @Throws(IOException::class)
68 | override fun onResponse(call: Call, response: Response) {
69 | UIActionHandler.onSaveApi(mainPanel.cbApiUrl.editor.item)
70 | mainPanel.lbStatus.text = "onResponse code: ${response.code()} "
71 | mainPanel.tpInfo.append("\nconsuming: ${System.currentTimeMillis() - startTime}ms \n", Color.BLUE)
72 | if (response.isSuccessful) {
73 | val body = response.body() ?: return
74 | val bytes = body.bytes()
75 | val resStr = String(bytes)
76 | mainPanel.tpInfo.append("response size: ${bytes.size} byte \n", Color.BLUE)
77 | val json = mGson.fromJson(resStr, JsonObject::class.java)
78 | val jsonStr = mGson.toJson(json, JsonObject::class.java)
79 | MyValueHandler.curShowJsonStr = jsonStr
80 | mainPanel.setJsonData(jsonStr)
81 | } else {
82 | mainPanel.tpInfo.append("\non response but not success\n", Color.RED)
83 | mainPanel.tpInfo.append("code = ${response.code()} \n ", Color.RED)
84 | mainPanel.tpInfo.append("message = ${response.message()} \n", Color.RED)
85 | }
86 | if (allCount!=0) {
87 | mainPanel.tpInfo.append("\nAll test count: $allCount \n", Color.GREEN)
88 | mainPanel.tpInfo.append("\nSuccess test count: ${mainPanel.pb.value} \n", Color.GREEN)
89 | mainPanel.tpInfo.append("\nThe total time consuming: ${System.currentTimeMillis() - startTime}ms \n", Color.GREEN)
90 | }
91 | }
92 | })
93 | }
94 |
95 | /**
96 | * 根据网络请求方式构建联网请求时所需的request
97 | *
98 | * @param httpMethodType 联网请求方式
99 | * @return 联网所需的request
100 | */
101 |
102 | @Throws(Exception::class)
103 | private fun buildRequest(url: String, params: Map?, httpMethodType: Int, encryptType: Int): Request {
104 | val builder = Request.Builder()
105 | val iEncryptHandler = MyValueHandler.encryptImplList[encryptType]
106 | if (httpMethodType == 1) {
107 | mainPanel.tpInfo.append("\n~~~~~~~~~~~~~~~~~~~~~~~~~~~这是一条分割线~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", Color.ORANGE)
108 | mainPanel.tpInfo.append("OkHttp GET \n", Color.RED)
109 | iEncryptHandler.onGetMethodEncrypt(params, builder, url)
110 | builder.get()
111 | } else if (httpMethodType == 0) {
112 | mainPanel.tpInfo.append("\n~~~~~~~~~~~~~~~~~~~~~~~~~~~这是一条分割线~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", Color.ORANGE)
113 | mainPanel.tpInfo.append("OkHttp POST \n", Color.RED)
114 | builder.url(url)
115 | builder.post(iEncryptHandler.onPostMethodEncrypt(params, builder, url))
116 | }
117 | return builder.build()
118 | }
119 |
120 |
121 | /**
122 | * 根据相对路径获取全路径
123 | *
124 | * @param relativeUrl 相对路径
125 | */
126 | private fun getAbsoluteUrl(relativeUrl: String): String {
127 | if (mainPanel.curBaseUrl.isNullOrEmpty()) {
128 | showErrorMsg("BaseURL is Null")
129 | return ""
130 | }
131 | return mainPanel.curBaseUrl + relativeUrl
132 | }
133 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/longforus/apidebugger/JsonTreeActionHandler.kt:
--------------------------------------------------------------------------------
1 | package com.longforus.apidebugger
2 |
3 | import com.longforus.apidebugger.ui.JsonJTreeNode
4 | import javax.swing.event.TreeSelectionEvent
5 | import javax.swing.event.TreeSelectionListener
6 |
7 | /**
8 | * Created by XQ Yang on 8/30/2018 4:00 PM.
9 | * Description :
10 | */
11 |
12 | object JsonTreeActionHandler: TreeSelectionListener {
13 | override fun valueChanged(e: TreeSelectionEvent?) {
14 | println(e.toString())
15 | e?.newLeadSelectionPath?.lastPathComponent?.let {
16 | val treeNode = it as JsonJTreeNode
17 | val start = MyValueHandler.curShowJsonStr.indexOf(treeNode.toSSearchStr())
18 | // mainPanel.tpResponse.select(start,start+treeNode.toSSearchStr().length)
19 | }
20 | }
21 |
22 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/longforus/apidebugger/Main.kt:
--------------------------------------------------------------------------------
1 | package com.longforus.apidebugger
2 |
3 | import com.longforus.apidebugger.ui.MainPanel
4 | import com.teamdev.jxbrowser.chromium.az
5 | import java.awt.EventQueue
6 | import java.lang.reflect.Field
7 | import java.lang.reflect.Modifier
8 | import java.math.BigInteger
9 |
10 |
11 |
12 | /**
13 | * Created by XQ Yang on 8/30/2018 10:07 AM.
14 | * Description :
15 | */
16 |
17 | lateinit var mainPanel: MainPanel
18 | val appName = "Api debugger"
19 |
20 |
21 | fun main(args: Array) {
22 | jxInit()
23 | OB.init()
24 | EventQueue.invokeLater {
25 | mainPanel = MainPanel(appName)
26 | UILifecycleHandler.onResume(mainPanel)
27 | HttpManage.mainPanel = mainPanel
28 | }
29 | }
30 |
31 | fun jxInit() {
32 | try {
33 | val e = az::class.java.getDeclaredField("e")
34 | e.isAccessible = true
35 | val f = az::class.java.getDeclaredField("f")
36 | f.isAccessible = true
37 | val modifersField = Field::class.java.getDeclaredField("modifiers")
38 | modifersField.isAccessible = true
39 | modifersField.setInt(e, e.modifiers and Modifier.FINAL.inv())
40 | modifersField.setInt(f, f.modifiers and Modifier.FINAL.inv())
41 | e.set(null, BigInteger("1"))
42 | f.set(null, BigInteger("1"))
43 | modifersField.isAccessible = false
44 | } catch (e1: Exception) {
45 | e1.printStackTrace()
46 | }
47 | }
48 |
49 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/longforus/apidebugger/MyValueHandler.kt:
--------------------------------------------------------------------------------
1 | package com.longforus.apidebugger
2 |
3 | import com.google.gson.GsonBuilder
4 | import com.longforus.apidebugger.bean.ApiBean
5 | import com.longforus.apidebugger.bean.ProjectBean
6 | import com.longforus.apidebugger.encrypt.DefaultEncryptHandler
7 | import com.longforus.apidebugger.encrypt.IEncryptHandler
8 | import java.awt.Toolkit
9 | import java.awt.datatransfer.StringSelection
10 |
11 |
12 | /**
13 | * Created by XQ Yang on 8/30/2018 5:24 PM.
14 | * Description :
15 | */
16 |
17 | object MyValueHandler {
18 |
19 |
20 | val encryptImplList = listOf( DefaultEncryptHandler())
21 | // val encryptImplList = listOf( DefaultEncryptHandler())
22 | val mGson =GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create()
23 |
24 | var curProject: ProjectBean? = null
25 | set(value) {
26 | if (value == field) {
27 | return
28 | }
29 | field = value
30 | value?.let {
31 | UILifecycleHandler.initProject(it, mainPanel)
32 | }
33 | }
34 |
35 |
36 | var curApi: ApiBean? = null
37 | set(value) {
38 | if (value == field) {
39 | return
40 | }
41 | field = value
42 | UILifecycleHandler.initApi(value)
43 | }
44 |
45 | var curBaseUrl = ""
46 | var curShowJsonStr = ""
47 |
48 | fun encryptId2Index(id: Int): Int {
49 | encryptImplList.forEachIndexed { index, iEncryptHandler ->
50 | if (iEncryptHandler.typeCode == id) {
51 | return index
52 | }
53 | }
54 | return 0
55 | }
56 | fun encryptIndex2Id(index: Int)=encryptImplList[index].typeCode
57 |
58 |
59 |
60 |
61 | /**
62 | * 将字符串复制到剪切板。
63 | */
64 | fun setSysClipboardText(writeMe: String) {
65 | val clip = Toolkit.getDefaultToolkit().systemClipboard
66 | val tText = StringSelection(writeMe)
67 | clip.setContents(tText, null)
68 | }
69 |
70 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/longforus/apidebugger/OB.kt:
--------------------------------------------------------------------------------
1 | package com.longforus.apidebugger
2 |
3 | import com.longforus.apidebugger.bean.ApiBean
4 | import com.longforus.apidebugger.bean.MyObjectBox
5 | import com.longforus.apidebugger.bean.ProjectBean
6 | import com.longforus.apidebugger.bean.TableBean
7 | import io.objectbox.Box
8 | import io.objectbox.BoxStore
9 | import io.objectbox.kotlin.boxFor
10 |
11 | /**
12 | * Created by XQ Yang on 8/31/2018 9:44 AM.
13 | * Description :
14 | */
15 |
16 |
17 | object OB{
18 |
19 | lateinit var store:BoxStore
20 | lateinit var projectBox: Box
21 | lateinit var apiBox: Box
22 | lateinit var paramsBox: Box
23 | fun init(){
24 | store = MyObjectBox.builder().name("api-debugger-db").build()
25 | projectBox= store.boxFor()
26 | apiBox= store.boxFor()
27 | paramsBox= store.boxFor()
28 | }
29 |
30 | fun onExit(){
31 | store.close()
32 | }
33 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/longforus/apidebugger/UIActionHandler.kt:
--------------------------------------------------------------------------------
1 | package com.longforus.apidebugger
2 |
3 | import com.longforus.apidebugger.bean.ApiBean
4 | import com.longforus.apidebugger.ui.ParamsTableModel
5 | import javax.swing.DefaultComboBoxModel
6 |
7 | /**
8 | * Created by XQ Yang on 8/31/2018 11:21 AM.
9 | * Description :
10 | */
11 | object UIActionHandler {
12 |
13 | fun onSaveBaseUrl(selectedItem: Any) {
14 | MyValueHandler.curProject?.let {
15 | if (!it.baseUrlList.contains(selectedItem as String)) {
16 | it.baseUrlList.add(0, selectedItem)
17 | MyValueHandler.curBaseUrl = selectedItem
18 | OB.projectBox.put(it)
19 | val model = mainPanel.cbBaseUrl.model as DefaultComboBoxModel
20 | model.insertElementAt(selectedItem, 0)
21 | }
22 | }
23 | }
24 |
25 | fun onSaveApi(selectedItem: Any) {
26 | MyValueHandler.curProject?.let {
27 | val apiBean: ApiBean
28 | if (selectedItem is String) {
29 | apiBean = ApiBean(selectedItem, it.id)
30 | if (!it.apis.contains(apiBean)) {
31 | apiBean.encryptType = mainPanel.selectedEncryptID
32 | apiBean.method = mainPanel.selectedMethodType
33 | apiBean.paramsMap = getParamsMap(mainPanel.paramsTableModel)
34 | it.apis.add(0, apiBean)
35 | val model = mainPanel.cbApiUrl.model as DefaultComboBoxModel
36 | model.insertElementAt(apiBean, 0)
37 | mainPanel.cbApiUrl.selectedIndex = 0
38 | MyValueHandler.curApi = apiBean
39 | }
40 | } else {
41 | apiBean = selectedItem as ApiBean
42 | apiBean.encryptType = mainPanel.selectedEncryptID
43 | apiBean.method = mainPanel.selectedMethodType
44 | apiBean.paramsMap = getParamsMap(mainPanel.paramsTableModel)
45 | }
46 | OB.apiBox.put(apiBean)
47 | }
48 | }
49 |
50 | fun getParamsMap(model: ParamsTableModel, isSave: Boolean = true): MutableMap {
51 | val map = HashMap()
52 | for (bean in model.data) {
53 | if (bean.selected || isSave) {
54 | map[bean.key] = bean.value
55 | }
56 | }
57 | return map
58 | }
59 |
60 | fun onNewApi() {
61 | val clone = MyValueHandler.curApi?.clone() as ApiBean?
62 | clone?.let {
63 | OB.apiBox.put(it)
64 | MyValueHandler.curApi = it
65 | mainPanel.cbApiUrl.insertItemAt(it, 0)
66 | mainPanel.cbApiUrl.selectedIndex = 0
67 | }
68 | }
69 |
70 | fun onSend() {
71 | if (MyValueHandler.curProject == null) {
72 | showErrorMsg("Please create the project first")
73 | } else {
74 | HttpManage.sendRequest()
75 | }
76 | }
77 |
78 | fun onDelBaseUrl(selectedItem: Any) {
79 | MyValueHandler.curProject?.baseUrlList?.remove(selectedItem)
80 | mainPanel.cbBaseUrl.removeItem(selectedItem)
81 | OB.projectBox.put(MyValueHandler.curProject)
82 | }
83 |
84 | fun onDelApiUrl(selectedItem: ApiBean) {
85 | MyValueHandler.curProject?.apis?.remove(selectedItem)
86 | mainPanel.cbApiUrl.removeItem(selectedItem)
87 | OB.apiBox.remove(selectedItem)
88 | MyValueHandler.curApi = MyValueHandler.curProject?.apis?.get(0)
89 | }
90 |
91 | fun onApiItemChanged(item: ApiBean) {
92 | MyValueHandler.curApi = item
93 | }
94 |
95 | fun onMethodChanged(index: Int) {
96 | if (MyValueHandler.curApi?.method != index) {
97 | MyValueHandler.curApi?.method = index
98 | if (MyValueHandler.curApi != null) {
99 | OB.apiBox.put(MyValueHandler.curApi)
100 | }
101 | }
102 | }
103 |
104 | fun onEncryptTypeChanged(typeCode: Int) {
105 | if (MyValueHandler.curApi?.encryptType != typeCode) {
106 | MyValueHandler.curApi?.encryptType = typeCode
107 | if (MyValueHandler.curApi != null) {
108 | OB.apiBox.put(MyValueHandler.curApi)
109 | }
110 | }
111 | }
112 |
113 | fun onClearParams() {
114 | MyValueHandler.curApi?.paramsMap?.clear()
115 | mainPanel.paramsTableModel.clear()
116 | if (MyValueHandler.curApi != null) {
117 | OB.apiBox.put(MyValueHandler.curApi)
118 | }
119 | }
120 |
121 | fun onStartTest() {
122 | val str = mainPanel.tvTestCount.text
123 | if (str.isNullOrEmpty()) {
124 | showErrorMsg("Test times cannot be empty")
125 | return
126 | }
127 | val count = str.toInt()
128 | if (count > 0) {
129 | mainPanel.pb.minimum = 0
130 | mainPanel.pb.value = 0
131 | mainPanel.pb.maximum = count
132 | mainPanel.lbStatus.text = "Stress testing..."
133 | val startTime = System.currentTimeMillis()
134 | val request = HttpManage.getRequest()
135 | request?.let {
136 | for (i in 0..count) {
137 | if (i == count) {
138 | HttpManage.sendTestRequest(it,true,count,startTime)
139 | } else {
140 | HttpManage.sendTestRequest(it,false)
141 | }
142 | }
143 | }
144 |
145 | }
146 | }
147 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/longforus/apidebugger/UILifecycleHandler.kt:
--------------------------------------------------------------------------------
1 | package com.longforus.apidebugger
2 |
3 | import com.longforus.apidebugger.MyValueHandler.curApi
4 | import com.longforus.apidebugger.MyValueHandler.curProject
5 | import com.longforus.apidebugger.bean.ApiBean
6 | import com.longforus.apidebugger.bean.ProjectBean
7 | import com.longforus.apidebugger.bean.ProjectBean_
8 | import com.longforus.apidebugger.ui.MainPanel
9 | import io.objectbox.kotlin.query
10 | import javax.swing.*
11 |
12 | /**
13 | * Created by XQ Yang on 8/31/2018 11:23 AM.
14 | * Description :
15 | */
16 | object UILifecycleHandler {
17 |
18 | val cacheMenu = mutableMapOf()
19 |
20 | fun onResume(mainPanel: MainPanel) {
21 | mainPanel.cbEncrypt.model = DefaultComboBoxModel(MyValueHandler.encryptImplList.toTypedArray())
22 | val allProject = OB.projectBox.query().build().find()
23 | if (allProject.isNotEmpty()) {
24 | curProject = allProject.last()
25 | }
26 | }
27 |
28 | fun initProject(it: ProjectBean, mainPanel: MainPanel) {
29 | mainPanel.title= " $appName Current Project : ${it.name}"
30 | mainPanel.cbBaseUrl.model = DefaultComboBoxModel(it.baseUrlList.toTypedArray())
31 | if (it.baseUrlList.isNotEmpty()) {
32 | MyValueHandler.curBaseUrl = it.baseUrlList.last()
33 | }
34 | val apis = it.apis
35 | mainPanel.cbApiUrl.model = DefaultComboBoxModel(apis.toTypedArray())
36 | curApi = if (apis.isNotEmpty()) {
37 | apis[0]
38 | } else {
39 | null
40 | }
41 | }
42 |
43 | fun initApi(api: ApiBean?){
44 | if (api == null) {
45 | mainPanel.cbEncrypt.selectedIndex = 0
46 | mainPanel.cbMethod.selectedIndex = 0
47 | mainPanel.resetParamsTbModel()
48 | } else {
49 | val id2Index = MyValueHandler.encryptId2Index(api.encryptType)
50 | mainPanel.cbEncrypt.selectedIndex = id2Index
51 | mainPanel.cbMethod.selectedIndex = api.method
52 | if (api.paramsMap.isEmpty()) {
53 | mainPanel.resetParamsTbModel()
54 | } else {
55 | // api.paramsMap.entries.forEachIndexed { index, entry ->
56 | // mainPanel.tbParame.model.setValueAt(entry.key, index, 1)
57 | // mainPanel.tbParame.model.setValueAt(entry.value, index, 2)
58 | // }
59 | mainPanel.paramsTableModel.data = ApiBean.getTableValueList(api)
60 | }
61 | }
62 | }
63 |
64 | fun getMenuBar(): JMenuBar {
65 | val menuBar = JMenuBar()
66 | val pm = JMenu("Project")
67 | val item = JMenuItem("new")
68 | item.addActionListener {
69 | val projectName = JOptionPane.showInputDialog("Input Project Name")
70 | if (projectName.isNullOrEmpty()) {
71 | return@addActionListener
72 | }
73 | val count = OB.projectBox.query {
74 | equal(ProjectBean_.name, projectName)
75 | }.count()
76 | if (count > 0) {
77 | showErrorMsg("Project existing")
78 | } else {
79 | val project = ProjectBean()
80 | project.name = projectName
81 | val newPro = JMenuItem(projectName)
82 | cacheMenu[projectName] = newPro
83 | newPro.addActionListener {_->
84 | curProject = project
85 | }
86 | pm.insert(newPro,2)
87 | OB.projectBox.put(project)
88 | curProject = project
89 | }
90 | }
91 | pm.add(item)
92 | pm.addSeparator()
93 | OB.projectBox.query().build().find().sortedByDescending { it.id }.forEach {pro->
94 | val tempItem = JMenuItem(pro.name)
95 | cacheMenu[pro.name] = tempItem
96 | tempItem.addActionListener {
97 | curProject = pro
98 | }
99 | pm.add(tempItem)
100 | }
101 | pm.addSeparator()
102 | val deleteItem = JMenuItem("delete current open project")
103 | deleteItem.addActionListener {
104 | if (curProject != null) {
105 | OB.projectBox.remove(curProject)
106 | val jMenuItem = cacheMenu.remove(curProject?.name)
107 | pm.remove(jMenuItem)
108 | val mutableList = OB.projectBox.query().build().find()
109 | if (mutableList.isNotEmpty()) {
110 | val last = mutableList.last()
111 | if (last != null) {
112 | curProject = last
113 | }
114 | }
115 | }
116 | }
117 | pm.add(deleteItem)
118 |
119 | val am = JMenu("About")
120 | val item1 = JMenuItem("about")
121 | am.add(item1)
122 | item1.addActionListener {
123 | JOptionPane.showMessageDialog(null,"version 1.0 \nAuthor longforus \nQQ 89082243 ","About",JOptionPane.INFORMATION_MESSAGE)
124 | }
125 | menuBar.add(pm)
126 | menuBar.add(am)
127 | return menuBar
128 | }
129 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/longforus/apidebugger/bean/ApiBean.kt:
--------------------------------------------------------------------------------
1 | package com.longforus.apidebugger.bean
2 |
3 | import io.objectbox.annotation.Convert
4 | import io.objectbox.annotation.Entity
5 | import io.objectbox.annotation.Id
6 | import io.objectbox.annotation.Index
7 |
8 | /**
9 | * Created by XQ Yang on 8/30/2018 5:41 PM.
10 | * Description :
11 | */
12 | @Entity
13 | class ApiBean(@Id(assignable = true)
14 | var id: Long = 0,
15 | var method: Int = 0,
16 | var url: String = "",
17 | @Convert(converter = MapDbConverter::class,
18 | dbType = String::class)
19 | var paramsMap: MutableMap = HashMap(),
20 | var encryptType: Int = 0, @Index var projectId: Long = 0, val createDate: Long = System.currentTimeMillis()) : kotlin.Cloneable {
21 |
22 | constructor(url: String, projectId: Long) : this() {
23 | this.url = url
24 | this.projectId = projectId
25 | this.id = hashCode().toLong()
26 | }
27 |
28 |
29 | companion object {
30 | fun getTableValueList(bean: ApiBean): MutableList {
31 | if (bean.paramsMap.isEmpty()) {
32 | return mutableListOf()
33 | }
34 | val list = mutableListOf()
35 | bean.paramsMap.forEach {
36 | list.add(TableBean(selected= true,key = it.key,value = it.value))
37 | }
38 | return list
39 | }
40 | }
41 |
42 |
43 | override fun toString(): String {
44 | return url
45 | }
46 |
47 |
48 | public override fun clone(): Any {
49 | val map = HashMap()
50 | paramsMap.forEach { t, u ->
51 | map[t] = u
52 | }
53 | val bean = ApiBean(method = this.method, url = this.url + "新", paramsMap = map, encryptType = this.encryptType, projectId = this.projectId)
54 | bean.id = bean.hashCode().toLong()
55 | return bean
56 | }
57 |
58 | override fun equals(other: Any?): Boolean {
59 | if (this === other) return true
60 | if (javaClass != other?.javaClass) return false
61 |
62 | other as ApiBean
63 |
64 | if (url != other.url) return false
65 | if (projectId != other.projectId) return false
66 |
67 | return true
68 | }
69 |
70 | override fun hashCode(): Int {
71 | var result = url.hashCode()
72 | result = 31 * result + projectId.hashCode()
73 | return result
74 | }
75 |
76 |
77 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/longforus/apidebugger/bean/ListDbConverter.kt:
--------------------------------------------------------------------------------
1 | package com.longforus.apidebugger.bean
2 |
3 | import com.google.gson.reflect.TypeToken
4 | import com.longforus.apidebugger.MyValueHandler
5 | import io.objectbox.converter.PropertyConverter
6 |
7 | /**
8 | * Created by XQ Yang on 8/30/2018 5:48 PM.
9 | * Description :
10 | */
11 | class ListDbConverter : PropertyConverter, String> {
12 |
13 | override fun convertToEntityProperty(databaseValue: String?): List {
14 | if (databaseValue.isNullOrEmpty()) {
15 | return mutableListOf()
16 | }
17 | val type = object : TypeToken>() {}.type
18 | return MyValueHandler.mGson.fromJson(databaseValue, type)
19 | }
20 |
21 | override fun convertToDatabaseValue(entityProperty: List?): String {
22 | if (entityProperty == null) {
23 | return ""
24 | }
25 | return MyValueHandler.mGson.toJson(entityProperty)
26 | }
27 |
28 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/longforus/apidebugger/bean/MapDbConverter.kt:
--------------------------------------------------------------------------------
1 | package com.longforus.apidebugger.bean
2 |
3 | import com.google.gson.reflect.TypeToken
4 | import com.longforus.apidebugger.MyValueHandler
5 | import io.objectbox.converter.PropertyConverter
6 |
7 | /**
8 | * Created by XQ Yang on 8/30/2018 5:48 PM.
9 | * Description :
10 | */
11 | class MapDbConverter : PropertyConverter