├── .classpath
├── .project
├── .settings
├── org.eclipse.core.resources.prefs
└── org.eclipse.jdt.core.prefs
├── LICENSE
├── README.md
├── bin
└── org
│ └── outstudio
│ └── wxtest
│ ├── Main.class
│ ├── StringUtilTest.class
│ ├── WechatUtilTest.class
│ ├── XmlUtilTest.class
│ ├── ui
│ ├── MainFrame$1.class
│ ├── MainFrame$10.class
│ ├── MainFrame$11.class
│ ├── MainFrame$2.class
│ ├── MainFrame$3.class
│ ├── MainFrame$4.class
│ ├── MainFrame$5.class
│ ├── MainFrame$6.class
│ ├── MainFrame$7.class
│ ├── MainFrame$8.class
│ ├── MainFrame$9.class
│ ├── MainFrame.class
│ ├── RawPostFrame$1.class
│ ├── RawPostFrame$2.class
│ ├── RawPostFrame$3.class
│ ├── RawPostFrame$4.class
│ ├── RawPostFrame.class
│ ├── TestLocationFrame$1.class
│ ├── TestLocationFrame$2.class
│ ├── TestLocationFrame$3.class
│ ├── TestLocationFrame$4.class
│ ├── TestLocationFrame$5.class
│ ├── TestLocationFrame$6.class
│ ├── TestLocationFrame$7.class
│ ├── TestLocationFrame$8.class
│ ├── TestLocationFrame$9.class
│ └── TestLocationFrame.class
│ └── util
│ ├── SignatureUtil.class
│ ├── SiteInfo.class
│ ├── SiteInfoUtil.class
│ ├── StringUtil.class
│ ├── WechatUtil.class
│ └── XmlUtil.class
├── lib
├── commons-io-2.4.jar
├── easywechat-20141113.jar
├── jsoup-out-1.7.3.jar
└── rsyntaxtextarea-2.5.3.jar
├── src
└── org
│ └── outstudio
│ └── wxtest
│ ├── Main.java
│ ├── ui
│ ├── MainFrame.java
│ ├── RawPostFrame.java
│ └── TestLocationFrame.java
│ └── util
│ ├── SignatureUtil.java
│ ├── SiteInfo.java
│ ├── SiteInfoUtil.java
│ ├── StringUtil.java
│ ├── WechatUtil.java
│ └── XmlUtil.java
├── test
└── org
│ └── outstudio
│ └── wxtest
│ ├── StringUtilTest.java
│ ├── WechatUtilTest.java
│ └── XmlUtilTest.java
└── test_res
├── ImageReqMsg.txt
├── LinkReqMsg.txt
├── LocationReqMsg.txt
├── TextReqMsg.txt
├── VideoReqMsg.txt
├── VoiceReqMsg.txt
└── invalid_xml_1.txt
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | WechatTestTool
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.jdt.core.javabuilder
10 |
11 |
12 |
13 |
14 |
15 | org.eclipse.jdt.core.javanature
16 |
17 |
18 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.core.resources.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | encoding/=UTF-8
3 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
4 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
5 | org.eclipse.jdt.core.compiler.compliance=1.7
6 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate
7 | org.eclipse.jdt.core.compiler.debug.localVariable=generate
8 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate
9 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
10 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
11 | org.eclipse.jdt.core.compiler.source=1.7
12 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
203 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | WechatTestTool
2 | ==============
3 |
4 | 用于测试微信公众平台应用的GUI工具,使用Java/Swing制作。
5 |
6 | 无需接入微信公众平台,即可对你的微信公众平台应用进行测试。
7 |
8 | 该工具可以向你的应用服务器模拟发送文本消息,模拟点击菜单,
9 | 还会将接收到的XML数据展现出来,并进行解析,统计响应时间等等。
10 |
--------------------------------------------------------------------------------
/bin/org/outstudio/wxtest/Main.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/bin/org/outstudio/wxtest/Main.class
--------------------------------------------------------------------------------
/bin/org/outstudio/wxtest/StringUtilTest.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/bin/org/outstudio/wxtest/StringUtilTest.class
--------------------------------------------------------------------------------
/bin/org/outstudio/wxtest/WechatUtilTest.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/bin/org/outstudio/wxtest/WechatUtilTest.class
--------------------------------------------------------------------------------
/bin/org/outstudio/wxtest/XmlUtilTest.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/bin/org/outstudio/wxtest/XmlUtilTest.class
--------------------------------------------------------------------------------
/bin/org/outstudio/wxtest/ui/MainFrame$1.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/bin/org/outstudio/wxtest/ui/MainFrame$1.class
--------------------------------------------------------------------------------
/bin/org/outstudio/wxtest/ui/MainFrame$10.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/bin/org/outstudio/wxtest/ui/MainFrame$10.class
--------------------------------------------------------------------------------
/bin/org/outstudio/wxtest/ui/MainFrame$11.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/bin/org/outstudio/wxtest/ui/MainFrame$11.class
--------------------------------------------------------------------------------
/bin/org/outstudio/wxtest/ui/MainFrame$2.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/bin/org/outstudio/wxtest/ui/MainFrame$2.class
--------------------------------------------------------------------------------
/bin/org/outstudio/wxtest/ui/MainFrame$3.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/bin/org/outstudio/wxtest/ui/MainFrame$3.class
--------------------------------------------------------------------------------
/bin/org/outstudio/wxtest/ui/MainFrame$4.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/bin/org/outstudio/wxtest/ui/MainFrame$4.class
--------------------------------------------------------------------------------
/bin/org/outstudio/wxtest/ui/MainFrame$5.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/bin/org/outstudio/wxtest/ui/MainFrame$5.class
--------------------------------------------------------------------------------
/bin/org/outstudio/wxtest/ui/MainFrame$6.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/bin/org/outstudio/wxtest/ui/MainFrame$6.class
--------------------------------------------------------------------------------
/bin/org/outstudio/wxtest/ui/MainFrame$7.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/bin/org/outstudio/wxtest/ui/MainFrame$7.class
--------------------------------------------------------------------------------
/bin/org/outstudio/wxtest/ui/MainFrame$8.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/bin/org/outstudio/wxtest/ui/MainFrame$8.class
--------------------------------------------------------------------------------
/bin/org/outstudio/wxtest/ui/MainFrame$9.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/bin/org/outstudio/wxtest/ui/MainFrame$9.class
--------------------------------------------------------------------------------
/bin/org/outstudio/wxtest/ui/MainFrame.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/bin/org/outstudio/wxtest/ui/MainFrame.class
--------------------------------------------------------------------------------
/bin/org/outstudio/wxtest/ui/RawPostFrame$1.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/bin/org/outstudio/wxtest/ui/RawPostFrame$1.class
--------------------------------------------------------------------------------
/bin/org/outstudio/wxtest/ui/RawPostFrame$2.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/bin/org/outstudio/wxtest/ui/RawPostFrame$2.class
--------------------------------------------------------------------------------
/bin/org/outstudio/wxtest/ui/RawPostFrame$3.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/bin/org/outstudio/wxtest/ui/RawPostFrame$3.class
--------------------------------------------------------------------------------
/bin/org/outstudio/wxtest/ui/RawPostFrame$4.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/bin/org/outstudio/wxtest/ui/RawPostFrame$4.class
--------------------------------------------------------------------------------
/bin/org/outstudio/wxtest/ui/RawPostFrame.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/bin/org/outstudio/wxtest/ui/RawPostFrame.class
--------------------------------------------------------------------------------
/bin/org/outstudio/wxtest/ui/TestLocationFrame$1.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/bin/org/outstudio/wxtest/ui/TestLocationFrame$1.class
--------------------------------------------------------------------------------
/bin/org/outstudio/wxtest/ui/TestLocationFrame$2.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/bin/org/outstudio/wxtest/ui/TestLocationFrame$2.class
--------------------------------------------------------------------------------
/bin/org/outstudio/wxtest/ui/TestLocationFrame$3.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/bin/org/outstudio/wxtest/ui/TestLocationFrame$3.class
--------------------------------------------------------------------------------
/bin/org/outstudio/wxtest/ui/TestLocationFrame$4.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/bin/org/outstudio/wxtest/ui/TestLocationFrame$4.class
--------------------------------------------------------------------------------
/bin/org/outstudio/wxtest/ui/TestLocationFrame$5.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/bin/org/outstudio/wxtest/ui/TestLocationFrame$5.class
--------------------------------------------------------------------------------
/bin/org/outstudio/wxtest/ui/TestLocationFrame$6.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/bin/org/outstudio/wxtest/ui/TestLocationFrame$6.class
--------------------------------------------------------------------------------
/bin/org/outstudio/wxtest/ui/TestLocationFrame$7.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/bin/org/outstudio/wxtest/ui/TestLocationFrame$7.class
--------------------------------------------------------------------------------
/bin/org/outstudio/wxtest/ui/TestLocationFrame$8.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/bin/org/outstudio/wxtest/ui/TestLocationFrame$8.class
--------------------------------------------------------------------------------
/bin/org/outstudio/wxtest/ui/TestLocationFrame$9.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/bin/org/outstudio/wxtest/ui/TestLocationFrame$9.class
--------------------------------------------------------------------------------
/bin/org/outstudio/wxtest/ui/TestLocationFrame.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/bin/org/outstudio/wxtest/ui/TestLocationFrame.class
--------------------------------------------------------------------------------
/bin/org/outstudio/wxtest/util/SignatureUtil.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/bin/org/outstudio/wxtest/util/SignatureUtil.class
--------------------------------------------------------------------------------
/bin/org/outstudio/wxtest/util/SiteInfo.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/bin/org/outstudio/wxtest/util/SiteInfo.class
--------------------------------------------------------------------------------
/bin/org/outstudio/wxtest/util/SiteInfoUtil.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/bin/org/outstudio/wxtest/util/SiteInfoUtil.class
--------------------------------------------------------------------------------
/bin/org/outstudio/wxtest/util/StringUtil.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/bin/org/outstudio/wxtest/util/StringUtil.class
--------------------------------------------------------------------------------
/bin/org/outstudio/wxtest/util/WechatUtil.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/bin/org/outstudio/wxtest/util/WechatUtil.class
--------------------------------------------------------------------------------
/bin/org/outstudio/wxtest/util/XmlUtil.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/bin/org/outstudio/wxtest/util/XmlUtil.class
--------------------------------------------------------------------------------
/lib/commons-io-2.4.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/lib/commons-io-2.4.jar
--------------------------------------------------------------------------------
/lib/easywechat-20141113.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/lib/easywechat-20141113.jar
--------------------------------------------------------------------------------
/lib/jsoup-out-1.7.3.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/lib/jsoup-out-1.7.3.jar
--------------------------------------------------------------------------------
/lib/rsyntaxtextarea-2.5.3.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/lib/rsyntaxtextarea-2.5.3.jar
--------------------------------------------------------------------------------
/src/org/outstudio/wxtest/Main.java:
--------------------------------------------------------------------------------
1 | package org.outstudio.wxtest;
2 |
3 | import org.outstudio.wxtest.ui.MainFrame;
4 |
5 | public class Main {
6 |
7 | public static void main(String[] args) {
8 | MainFrame.launch();
9 | }
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/src/org/outstudio/wxtest/ui/MainFrame.java:
--------------------------------------------------------------------------------
1 | package org.outstudio.wxtest.ui;
2 |
3 | import java.awt.BorderLayout;
4 | import java.awt.Dimension;
5 | import java.awt.EventQueue;
6 | import java.awt.Font;
7 | import java.awt.event.ActionEvent;
8 | import java.awt.event.ActionListener;
9 | import java.awt.event.ItemEvent;
10 | import java.awt.event.ItemListener;
11 | import java.io.IOException;
12 | import java.util.List;
13 |
14 | import javax.swing.JButton;
15 | import javax.swing.JComboBox;
16 | import javax.swing.JEditorPane;
17 | import javax.swing.JFrame;
18 | import javax.swing.JLabel;
19 | import javax.swing.JPanel;
20 | import javax.swing.JScrollPane;
21 | import javax.swing.JSplitPane;
22 | import javax.swing.JTextField;
23 | import javax.swing.UIManager;
24 | import javax.swing.border.EmptyBorder;
25 | import javax.swing.event.PopupMenuEvent;
26 | import javax.swing.event.PopupMenuListener;
27 |
28 | import org.easywechat.msg.BaseMsg;
29 | import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
30 | import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
31 | import org.fife.ui.rtextarea.RTextScrollPane;
32 | import org.jsoup.nodes.Document;
33 | import org.outstudio.wxtest.util.SiteInfo;
34 | import org.outstudio.wxtest.util.SiteInfoUtil;
35 | import org.outstudio.wxtest.util.WechatUtil;
36 |
37 | import java.awt.event.MouseAdapter;
38 | import java.awt.event.MouseEvent;
39 | import java.awt.Color;
40 |
41 | public class MainFrame extends JFrame {
42 |
43 | private static final long serialVersionUID = 1L;
44 |
45 | private JPanel contentPane;
46 | private JTextField tfText;
47 | private JTextField tfToken;
48 | private JComboBox cbUrl;
49 |
50 | private JSplitPane splitPane;
51 | private JScrollPane scrollPane;
52 | private JEditorPane epView;
53 | private RTextScrollPane scrollPane_1;
54 | private RSyntaxTextArea rawResp;
55 | private JLabel lblTime;
56 |
57 | private List siteInfos;
58 |
59 | /**
60 | * Launch the application.
61 | */
62 | public static void launch() {
63 | EventQueue.invokeLater(new Runnable() {
64 | public void run() {
65 | try {
66 | UIManager.setLookAndFeel(UIManager
67 | .getSystemLookAndFeelClassName());
68 | MainFrame frame = new MainFrame();
69 | frame.setVisible(true);
70 | } catch (Exception e) {
71 | e.printStackTrace();
72 | }
73 | }
74 | });
75 | }
76 |
77 | /**
78 | * Create the frame.
79 | */
80 | public MainFrame() {
81 | setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
82 | setSize(800, 600);
83 | setLocationRelativeTo(null);
84 | setTitle("微信测试工具");
85 |
86 | contentPane = new JPanel();
87 | contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
88 | contentPane.setLayout(new BorderLayout(0, 0));
89 | setContentPane(contentPane);
90 |
91 | JPanel topPane = new JPanel();
92 | contentPane.add(topPane, BorderLayout.NORTH);
93 | topPane.setLayout(null);
94 | topPane.setPreferredSize(new Dimension(getWidth(), 100));
95 |
96 | cbUrl = new JComboBox();
97 | cbUrl.setEditable(true);
98 | cbUrl.setBounds(74, 10, 270, 21);
99 | cbUrl.addPopupMenuListener(new PopupMenuListener() {
100 | @Override
101 | public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
102 | loadSiteInfo();
103 | }
104 |
105 | @Override
106 | public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
107 | }
108 |
109 | @Override
110 | public void popupMenuCanceled(PopupMenuEvent e) {
111 | }
112 | });
113 | cbUrl.addItemListener(new ItemListener() {
114 |
115 | @Override
116 | public void itemStateChanged(ItemEvent e) {
117 | String url = getUrlFromInput();
118 | for (SiteInfo siteInfo : siteInfos) {
119 | if (siteInfo.getUrl().equals(url)) {
120 | displayToken(siteInfo.getToken());
121 | }
122 | }
123 | }
124 | });
125 | topPane.add(cbUrl);
126 |
127 | JLabel lblNewLabel = new JLabel("\u9009\u62E9\u7F51\u5740\uFF1A");
128 | lblNewLabel.setBounds(10, 13, 64, 15);
129 | topPane.add(lblNewLabel);
130 |
131 | tfText = new JTextField();
132 | tfText.setBounds(10, 41, 269, 21);
133 | topPane.add(tfText);
134 | tfText.setColumns(10);
135 |
136 | JButton btnSendText = new JButton("\u53D1\u9001\u6587\u5B57");
137 | btnSendText.addActionListener(new ActionListener() {
138 | public void actionPerformed(ActionEvent e) {
139 | onBtnSendClicked();
140 | }
141 | });
142 | btnSendText.setBounds(289, 41, 93, 23);
143 | topPane.add(btnSendText);
144 |
145 | JLabel lblToken = new JLabel("token\uFF1A");
146 | lblToken.setBounds(374, 13, 54, 15);
147 | topPane.add(lblToken);
148 |
149 | tfToken = new JTextField();
150 | tfToken.setBounds(428, 10, 76, 21);
151 | topPane.add(tfToken);
152 | tfToken.setColumns(10);
153 |
154 | lblTime = new JLabel("");
155 | lblTime.setBounds(10, 72, 119, 15);
156 | topPane.add(lblTime);
157 |
158 | JButton btnMenuClick = new JButton("\u70B9\u51FB\u83DC\u5355");
159 | btnMenuClick.addActionListener(new ActionListener() {
160 | public void actionPerformed(ActionEvent e) {
161 | onBtnMenuClicked();
162 | }
163 | });
164 | btnMenuClick.setBounds(392, 41, 93, 23);
165 | topPane.add(btnMenuClick);
166 |
167 | final JLabel lblSendXml = new JLabel("\u53D1\u9001XML");
168 | lblSendXml.setForeground(Color.BLUE);
169 | lblSendXml.addMouseListener(new MouseAdapter() {
170 | @Override
171 | public void mouseClicked(MouseEvent e) {
172 | launchPawPostFrame();
173 | }
174 |
175 | @Override
176 | public void mouseEntered(MouseEvent e) {
177 | lblSendXml.setFont(new Font("宋体", Font.ITALIC, 14));
178 | }
179 |
180 | @Override
181 | public void mouseExited(MouseEvent e) {
182 | lblSendXml.setFont(new Font("宋体", Font.PLAIN, 12));
183 | }
184 | });
185 | lblSendXml.setBounds(495, 44, 70, 15);
186 | topPane.add(lblSendXml);
187 |
188 | splitPane = new JSplitPane();
189 | splitPane.setResizeWeight(0.45);
190 | contentPane.add(splitPane, BorderLayout.CENTER);
191 |
192 | scrollPane = new JScrollPane();
193 | splitPane.setLeftComponent(scrollPane);
194 |
195 | epView = new JEditorPane();
196 | scrollPane.setViewportView(epView);
197 | splitPane.setResizeWeight(0.5);
198 |
199 | rawResp = new RSyntaxTextArea();
200 | rawResp.setEditable(false);
201 | rawResp.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_XML);
202 | rawResp.setCodeFoldingEnabled(true);
203 |
204 | scrollPane_1 = new RTextScrollPane(rawResp);
205 | splitPane.setRightComponent(scrollPane_1);
206 |
207 | loadSiteInfo();
208 | }
209 |
210 | /**
211 | * 从配置文件中加载网址和token
212 | */
213 | private void loadSiteInfo() {
214 | cbUrl.removeAllItems();
215 | siteInfos = SiteInfoUtil.getSiteInfo();
216 | for (SiteInfo siteInfo : siteInfos) {
217 | String url = siteInfo.getUrl();
218 | cbUrl.addItem(url);
219 | }
220 | cbUrl.repaint();
221 | }
222 |
223 | private void onBtnSendClicked() {
224 | displayFormattedResp("正在等待服务器响应!");
225 |
226 | String rawUrl = getUrlFromInput();
227 | String token = tfToken.getText();
228 | String text = tfText.getText();
229 |
230 | if (!rawUrl.startsWith("http")) {
231 | rawUrl = "http://" + rawUrl;
232 | }
233 | String resp;
234 | try {
235 | long beginTime = System.currentTimeMillis();
236 | resp = WechatUtil.sendText(token, rawUrl, text);
237 | long endTime = System.currentTimeMillis();
238 | displayDelayTime(endTime - beginTime);
239 | } catch (IllegalArgumentException ee) {
240 | displayErrorMsg("网址格式有误!");
241 | return;
242 | } catch (IOException e) {
243 | displayErrorMsg("出现IO错误!");
244 | return;
245 | }
246 |
247 | parseAndDisplay(resp);
248 | saveSiteInfo(new SiteInfo(rawUrl, token));
249 | }
250 |
251 | private void onBtnMenuClicked() {
252 | displayFormattedResp("正在等待服务器响应!");
253 |
254 | String rawUrl = getUrlFromInput();
255 | String token = tfToken.getText();
256 | String eventKey = tfText.getText();
257 |
258 | if (!rawUrl.startsWith("http")) {
259 | rawUrl = "http://" + rawUrl;
260 | }
261 | String resp;
262 | try {
263 | long beginTime = System.currentTimeMillis();
264 | resp = WechatUtil.sendClickEvent(token, rawUrl, eventKey);
265 | long endTime = System.currentTimeMillis();
266 | displayDelayTime(endTime - beginTime);
267 | } catch (IllegalArgumentException ee) {
268 | displayErrorMsg("网址格式有误!");
269 | return;
270 | } catch (IOException e) {
271 | displayErrorMsg("出现IO错误!");
272 | return;
273 | }
274 |
275 | parseAndDisplay(resp);
276 | saveSiteInfo(new SiteInfo(rawUrl, token));
277 | }
278 |
279 | /**
280 | * 向服务器发送的XML数据
281 | */
282 | public void sendXml(String xml) {
283 | displayFormattedResp("正在等待服务器响应!");
284 |
285 | String rawUrl = getUrlFromInput();
286 | String token = tfToken.getText();
287 |
288 | if (!rawUrl.startsWith("http")) {
289 | rawUrl = "http://" + rawUrl;
290 | }
291 | String resp;
292 | try {
293 | long beginTime = System.currentTimeMillis();
294 | resp = WechatUtil.sendXml(token, rawUrl, xml);
295 | long endTime = System.currentTimeMillis();
296 | displayDelayTime(endTime - beginTime);
297 | } catch (IllegalArgumentException ee) {
298 | displayErrorMsg("网址格式有误!");
299 | return;
300 | } catch (IOException e) {
301 | displayErrorMsg("出现IO错误!");
302 | return;
303 | }
304 |
305 | parseAndDisplay(resp);
306 | saveSiteInfo(new SiteInfo(rawUrl, token));
307 | }
308 |
309 | /**
310 | * 解析返回的消息并进行展示
311 | */
312 | private void parseAndDisplay(String resp) {
313 | if (resp.trim().isEmpty()) {
314 | displayErrorMsg("返回为空!");
315 | return;
316 | }
317 |
318 | Document doc = WechatUtil.getDocFromXml(resp);
319 |
320 | displayRawRespText(doc.toString());
321 |
322 | BaseMsg msg;
323 | try {
324 | msg = WechatUtil.getMsgFromDoc(doc);
325 | } catch (Exception e) {
326 | displayFormattedResp("解析出现异常!");
327 | return;
328 | }
329 |
330 | // 将解析后的消息展现到界面中
331 | String formattedResp = WechatUtil.getPrettyString(msg);
332 | displayFormattedResp(formattedResp);
333 | }
334 |
335 | /**
336 | * 将原先不存在的服务器地址和token存进配置文件
337 | */
338 | private void saveSiteInfo(SiteInfo info) {
339 | String url = info.getUrl();
340 | String token = info.getToken();
341 |
342 | boolean hasUrl = false;
343 | for (SiteInfo siteInfo : siteInfos) {
344 | if (siteInfo.getUrl().equals(url)) {
345 | hasUrl = true;
346 | break;
347 | }
348 | }
349 | if (!hasUrl) {
350 | siteInfos.add(new SiteInfo(url, token));
351 | SiteInfoUtil.saveSiteInfo(siteInfos);
352 | }
353 | }
354 |
355 | private String getUrlFromInput() {
356 | return cbUrl.getEditor().getItem().toString();
357 | }
358 |
359 | private void displayToken(final String token) {
360 | EventQueue.invokeLater(new Runnable() {
361 | @Override
362 | public void run() {
363 | tfToken.setText(token);
364 | }
365 | });
366 | }
367 |
368 | /**
369 | * 展示响应时间
370 | */
371 | private void displayDelayTime(final long timeInMillis) {
372 | EventQueue.invokeLater(new Runnable() {
373 | @Override
374 | public void run() {
375 | lblTime.setText("用时:" + timeInMillis / 1000d + " 秒");
376 | }
377 | });
378 | }
379 |
380 | /**
381 | * 展示错误提示信息
382 | */
383 | private void displayErrorMsg(final String errMsg) {
384 | EventQueue.invokeLater(new Runnable() {
385 | @Override
386 | public void run() {
387 | epView.setText(errMsg);
388 | rawResp.setText("");
389 | }
390 | });
391 | }
392 |
393 | /**
394 | * 展示解析后的响应信息
395 | */
396 | private void displayFormattedResp(final String text) {
397 | EventQueue.invokeLater(new Runnable() {
398 | @Override
399 | public void run() {
400 | epView.setText(text);
401 | }
402 | });
403 | }
404 |
405 | /**
406 | * 展示原始响应信息
407 | */
408 | private void displayRawRespText(final String text) {
409 | EventQueue.invokeLater(new Runnable() {
410 | @Override
411 | public void run() {
412 | rawResp.setText(text);
413 | }
414 | });
415 | }
416 |
417 | /**
418 | * 开启发送XML数据的窗口
419 | */
420 | private void launchPawPostFrame() {
421 | RawPostFrame.launch(this);
422 | }
423 | }
424 |
--------------------------------------------------------------------------------
/src/org/outstudio/wxtest/ui/RawPostFrame.java:
--------------------------------------------------------------------------------
1 | package org.outstudio.wxtest.ui;
2 |
3 | import java.awt.BorderLayout;
4 | import java.awt.EventQueue;
5 | import java.awt.event.ActionEvent;
6 | import java.awt.event.ActionListener;
7 | import java.io.File;
8 | import java.io.IOException;
9 |
10 | import javax.swing.JButton;
11 | import javax.swing.JFileChooser;
12 | import javax.swing.JFrame;
13 | import javax.swing.JOptionPane;
14 | import javax.swing.JPanel;
15 | import javax.swing.border.EmptyBorder;
16 | import javax.swing.filechooser.FileFilter;
17 |
18 | import org.apache.commons.io.FileUtils;
19 | import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
20 | import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
21 | import org.fife.ui.rtextarea.RTextScrollPane;
22 | import org.outstudio.wxtest.util.XmlUtil;
23 |
24 | public class RawPostFrame extends JFrame {
25 |
26 | private static final long serialVersionUID = 1L;
27 |
28 | private MainFrame mainFrame;
29 |
30 | private JPanel contentPane;
31 | private RTextScrollPane scrollPane;
32 | private RSyntaxTextArea textArea;
33 | private JButton btnSendRaw;
34 |
35 | /**
36 | * Launch the application.
37 | */
38 | public static void launch(final MainFrame parent) {
39 | EventQueue.invokeLater(new Runnable() {
40 | public void run() {
41 | try {
42 | RawPostFrame frame = new RawPostFrame(parent);
43 | frame.setVisible(true);
44 | } catch (Exception e) {
45 | e.printStackTrace();
46 | }
47 | }
48 | });
49 | }
50 |
51 | /**
52 | * Create the frame.
53 | */
54 | public RawPostFrame(MainFrame parent) {
55 | setTitle("\u8F93\u5165XML \u6216 \u4ECEtxt\u6587\u4EF6\u4E2D\u9009\u62E9");
56 | this.mainFrame = parent;
57 | setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
58 | setBounds(100, 100, 450, 300);
59 | contentPane = new JPanel();
60 | contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
61 | contentPane.setLayout(new BorderLayout(0, 0));
62 | setContentPane(contentPane);
63 |
64 | JPanel panel = new JPanel();
65 | contentPane.add(panel, BorderLayout.NORTH);
66 |
67 | JButton btnSelectFromFile = new JButton("\u9009\u62E9txt\u6587\u4EF6");
68 | btnSelectFromFile.addActionListener(new ActionListener() {
69 | public void actionPerformed(ActionEvent e) {
70 | obBtnSelectFileClicked();
71 | }
72 | });
73 | panel.add(btnSelectFromFile);
74 |
75 | btnSendRaw = new JButton("\u53D1\u9001");
76 | btnSendRaw.addActionListener(new ActionListener() {
77 | public void actionPerformed(ActionEvent e) {
78 | onBtnSendRawClicked();
79 | }
80 | });
81 | panel.add(btnSendRaw);
82 |
83 | textArea = new RSyntaxTextArea();
84 | textArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_XML);
85 | textArea.setCodeFoldingEnabled(true);
86 |
87 | scrollPane = new RTextScrollPane(textArea);
88 | contentPane.add(scrollPane, BorderLayout.CENTER);
89 | }
90 |
91 | private void obBtnSelectFileClicked() {
92 | JFileChooser fc = new JFileChooser();
93 | fc.setFileFilter(new FileFilter() {// 只能选择txt文件
94 | @Override
95 | public String getDescription() {
96 | return null;
97 | }
98 |
99 | @Override
100 | public boolean accept(File f) {
101 | return f.isDirectory() || f.getName().endsWith(".txt");
102 | }
103 | });
104 | fc.showOpenDialog(this);
105 | File file = fc.getSelectedFile();
106 | if (!file.getName().endsWith(".txt")) {
107 | JOptionPane.showMessageDialog(this, "请选择txt文件!");
108 | return;
109 | }
110 | try {
111 | String content = FileUtils.readFileToString(file);
112 | textArea.setText(content);
113 | boolean isValidXml = XmlUtil.isValidXml(content);
114 | if (!isValidXml) {
115 | JOptionPane.showMessageDialog(this, "不符合XML格式!");
116 | }
117 | } catch (IOException e) {
118 | e.printStackTrace();
119 | }
120 | }
121 |
122 | private void onBtnSendRawClicked() {
123 | String xml = textArea.getText();
124 | boolean isValidXml = XmlUtil.isValidXml(xml);
125 | if (xml.isEmpty() || !isValidXml) {
126 | JOptionPane.showMessageDialog(this, "不符合XML格式!");
127 | return;
128 | }
129 | mainFrame.sendXml(xml);
130 | }
131 |
132 | }
133 |
--------------------------------------------------------------------------------
/src/org/outstudio/wxtest/ui/TestLocationFrame.java:
--------------------------------------------------------------------------------
1 | package org.outstudio.wxtest.ui;
2 |
3 | import java.awt.BorderLayout;
4 | import java.awt.Dimension;
5 | import java.awt.EventQueue;
6 | import java.awt.event.ActionEvent;
7 | import java.awt.event.ActionListener;
8 | import java.awt.event.ItemEvent;
9 | import java.awt.event.ItemListener;
10 | import java.io.IOException;
11 | import java.util.List;
12 |
13 | import javax.swing.JButton;
14 | import javax.swing.JComboBox;
15 | import javax.swing.JEditorPane;
16 | import javax.swing.JFrame;
17 | import javax.swing.JLabel;
18 | import javax.swing.JOptionPane;
19 | import javax.swing.JPanel;
20 | import javax.swing.JScrollPane;
21 | import javax.swing.JSplitPane;
22 | import javax.swing.JTextField;
23 | import javax.swing.UIManager;
24 | import javax.swing.border.EmptyBorder;
25 | import javax.swing.event.PopupMenuEvent;
26 | import javax.swing.event.PopupMenuListener;
27 |
28 | import org.easywechat.msg.BaseMsg;
29 | import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
30 | import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
31 | import org.fife.ui.rtextarea.RTextScrollPane;
32 | import org.jsoup.nodes.Document;
33 | import org.outstudio.wxtest.util.SiteInfo;
34 | import org.outstudio.wxtest.util.SiteInfoUtil;
35 | import org.outstudio.wxtest.util.WechatUtil;
36 |
37 | public class TestLocationFrame extends JFrame {
38 |
39 | private static final long serialVersionUID = 1L;
40 |
41 | private JPanel contentPane;
42 | private JTextField tfLat;
43 | private JTextField tfToken;
44 | private JComboBox cbUrl;
45 |
46 | private JSplitPane splitPane;
47 | private JScrollPane scrollPane;
48 | private JEditorPane epView;
49 | private RTextScrollPane scrollPane_1;
50 | private RSyntaxTextArea rawResp;
51 | private JLabel lblTime;
52 |
53 | private List siteInfos;
54 | private JTextField tfLong;
55 | private JTextField tfPrecision;
56 |
57 | /**
58 | * Launch the application.
59 | */
60 | public static void main(String[] args) {
61 | EventQueue.invokeLater(new Runnable() {
62 | public void run() {
63 | try {
64 | UIManager.setLookAndFeel(UIManager
65 | .getSystemLookAndFeelClassName());
66 | TestLocationFrame frame = new TestLocationFrame();
67 | frame.setVisible(true);
68 | } catch (Exception e) {
69 | e.printStackTrace();
70 | }
71 | }
72 | });
73 | }
74 |
75 | /**
76 | * Create the frame.
77 | */
78 | public TestLocationFrame() {
79 | setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
80 | setSize(800, 600);
81 | setLocationRelativeTo(null);
82 | setTitle("微信测试工具");
83 |
84 | contentPane = new JPanel();
85 | contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
86 | contentPane.setLayout(new BorderLayout(0, 0));
87 | setContentPane(contentPane);
88 |
89 | JPanel topPane = new JPanel();
90 | contentPane.add(topPane, BorderLayout.NORTH);
91 | topPane.setLayout(null);
92 | topPane.setPreferredSize(new Dimension(getWidth(), 100));
93 |
94 | cbUrl = new JComboBox();
95 | cbUrl.setEditable(true);
96 | cbUrl.setBounds(74, 10, 270, 21);
97 | cbUrl.addPopupMenuListener(new PopupMenuListener() {
98 | @Override
99 | public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
100 | loadSiteInfo();
101 | }
102 |
103 | @Override
104 | public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
105 | }
106 |
107 | @Override
108 | public void popupMenuCanceled(PopupMenuEvent e) {
109 | }
110 | });
111 | cbUrl.addItemListener(new ItemListener() {
112 |
113 | @Override
114 | public void itemStateChanged(ItemEvent e) {
115 | String url = getUrlFromInput();
116 | for (SiteInfo siteInfo : siteInfos) {
117 | if (siteInfo.getUrl().equals(url)) {
118 | displayToken(siteInfo.getToken());
119 | }
120 | }
121 | }
122 | });
123 | topPane.add(cbUrl);
124 |
125 | JLabel lblNewLabel = new JLabel("\u9009\u62E9\u7F51\u5740\uFF1A");
126 | lblNewLabel.setBounds(10, 13, 64, 15);
127 | topPane.add(lblNewLabel);
128 |
129 | tfLat = new JTextField();
130 | tfLat.setText("23.137466");
131 | tfLat.setBounds(39, 42, 104, 21);
132 | topPane.add(tfLat);
133 | tfLat.setColumns(10);
134 |
135 | JButton btnSend = new JButton(
136 | "\u53D1\u9001\u5730\u7406\u4F4D\u7F6E\u4E8B\u4EF6");
137 | btnSend.addActionListener(new ActionListener() {
138 | public void actionPerformed(ActionEvent e) {
139 | onBtnSendClicked();
140 | }
141 | });
142 | btnSend.setBounds(495, 41, 136, 23);
143 | topPane.add(btnSend);
144 |
145 | JLabel lblToken = new JLabel("token\uFF1A");
146 | lblToken.setBounds(374, 13, 54, 15);
147 | topPane.add(lblToken);
148 |
149 | tfToken = new JTextField();
150 | tfToken.setBounds(428, 10, 76, 21);
151 | topPane.add(tfToken);
152 | tfToken.setColumns(10);
153 |
154 | lblTime = new JLabel("");
155 | lblTime.setBounds(10, 72, 119, 15);
156 | topPane.add(lblTime);
157 |
158 | JLabel lblLat = new JLabel("Lat: ");
159 | lblLat.setBounds(10, 44, 38, 15);
160 | topPane.add(lblLat);
161 |
162 | JLabel lblLong = new JLabel("Long: ");
163 | lblLong.setBounds(163, 43, 38, 15);
164 | topPane.add(lblLong);
165 |
166 | tfLong = new JTextField();
167 | tfLong.setText("113.352425");
168 | tfLong.setColumns(10);
169 | tfLong.setBounds(198, 42, 104, 21);
170 | topPane.add(tfLong);
171 |
172 | JLabel lblPrecision = new JLabel("Precision: ");
173 | lblPrecision.setBounds(312, 43, 93, 15);
174 | topPane.add(lblPrecision);
175 |
176 | tfPrecision = new JTextField();
177 | tfPrecision.setText("119.385040");
178 | tfPrecision.setColumns(10);
179 | tfPrecision.setBounds(374, 42, 104, 21);
180 | topPane.add(tfPrecision);
181 |
182 | splitPane = new JSplitPane();
183 | splitPane.setResizeWeight(0.45);
184 | contentPane.add(splitPane, BorderLayout.CENTER);
185 |
186 | scrollPane = new JScrollPane();
187 | splitPane.setLeftComponent(scrollPane);
188 |
189 | epView = new JEditorPane();
190 | scrollPane.setViewportView(epView);
191 | splitPane.setResizeWeight(0.5);
192 |
193 | rawResp = new RSyntaxTextArea();
194 | rawResp.setEditable(false);
195 | rawResp.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_XML);
196 | rawResp.setCodeFoldingEnabled(true);
197 |
198 | scrollPane_1 = new RTextScrollPane(rawResp);
199 | splitPane.setRightComponent(scrollPane_1);
200 |
201 | loadSiteInfo();
202 | }
203 |
204 | /**
205 | * 从配置文件中加载网址和token
206 | */
207 | private void loadSiteInfo() {
208 | cbUrl.removeAllItems();
209 | siteInfos = SiteInfoUtil.getSiteInfo();
210 | for (SiteInfo siteInfo : siteInfos) {
211 | String url = siteInfo.getUrl();
212 | cbUrl.addItem(url);
213 | }
214 | cbUrl.repaint();
215 | }
216 |
217 | private void onBtnSendClicked() {
218 | displayFormattedResp("正在等待服务器响应!");
219 |
220 | String rawUrl = getUrlFromInput();
221 | String token = tfToken.getText();
222 | String strLatitude = tfLat.getText();
223 | String strLongitude = tfLong.getText();
224 | String strPrecision = tfPrecision.getText();
225 |
226 | double latitude, longitude, precision;
227 | try {
228 | latitude = Double.parseDouble(strLatitude);
229 | longitude = Double.parseDouble(strLongitude);
230 | precision = Double.parseDouble(strPrecision);
231 | } catch (Exception e) {
232 | JOptionPane.showMessageDialog(null, "填数字!");
233 | return;
234 | }
235 |
236 | if (!rawUrl.startsWith("http")) {
237 | rawUrl = "http://" + rawUrl;
238 | }
239 | String resp;
240 | try {
241 | long beginTime = System.currentTimeMillis();
242 | resp = WechatUtil.sendLocationEvent(token, rawUrl, latitude,
243 | longitude, precision);
244 | long endTime = System.currentTimeMillis();
245 | displayDelayTime(endTime - beginTime);
246 | } catch (IllegalArgumentException ee) {
247 | displayErrorMsg("网址格式有误!");
248 | return;
249 | } catch (IOException e) {
250 | displayErrorMsg("出现IO错误!");
251 | return;
252 | }
253 |
254 | parseAndDisplay(resp);
255 | saveSiteInfo(new SiteInfo(rawUrl, token));
256 | }
257 |
258 | /**
259 | * 解析返回的消息并进行展示
260 | */
261 | private void parseAndDisplay(String resp) {
262 | if (resp.trim().isEmpty()) {
263 | displayErrorMsg("返回为空!");
264 | return;
265 | }
266 |
267 | Document doc = WechatUtil.getDocFromXml(resp);
268 |
269 | displayRawRespText(doc.toString());
270 |
271 | BaseMsg msg;
272 | try {
273 | msg = WechatUtil.getMsgFromDoc(doc);
274 | } catch (Exception e) {
275 | displayFormattedResp("解析出现异常!");
276 | return;
277 | }
278 |
279 | // 将解析后的消息展现到界面中
280 | String formattedResp = WechatUtil.getPrettyString(msg);
281 | displayFormattedResp(formattedResp);
282 | }
283 |
284 | /**
285 | * 将原先不存在的服务器地址和token存进配置文件
286 | */
287 | private void saveSiteInfo(SiteInfo info) {
288 | String url = info.getUrl();
289 | String token = info.getToken();
290 |
291 | boolean hasUrl = false;
292 | for (SiteInfo siteInfo : siteInfos) {
293 | if (siteInfo.getUrl().equals(url)) {
294 | hasUrl = true;
295 | break;
296 | }
297 | }
298 | if (!hasUrl) {
299 | siteInfos.add(new SiteInfo(url, token));
300 | SiteInfoUtil.saveSiteInfo(siteInfos);
301 | }
302 | }
303 |
304 | private String getUrlFromInput() {
305 | return cbUrl.getEditor().getItem().toString();
306 | }
307 |
308 | private void displayToken(final String token) {
309 | EventQueue.invokeLater(new Runnable() {
310 | @Override
311 | public void run() {
312 | tfToken.setText(token);
313 | }
314 | });
315 | }
316 |
317 | private void displayDelayTime(final long timeInMillis) {
318 | EventQueue.invokeLater(new Runnable() {
319 | @Override
320 | public void run() {
321 | lblTime.setText("用时:" + timeInMillis / 1000d + " 秒");
322 | }
323 | });
324 | }
325 |
326 | private void displayErrorMsg(final String errMsg) {
327 | EventQueue.invokeLater(new Runnable() {
328 | @Override
329 | public void run() {
330 | epView.setText(errMsg);
331 | rawResp.setText("");
332 | }
333 | });
334 | }
335 |
336 | private void displayFormattedResp(final String text) {
337 | EventQueue.invokeLater(new Runnable() {
338 | @Override
339 | public void run() {
340 | epView.setText(text);
341 | }
342 | });
343 | }
344 |
345 | private void displayRawRespText(final String text) {
346 | EventQueue.invokeLater(new Runnable() {
347 | @Override
348 | public void run() {
349 | rawResp.setText(text);
350 | }
351 | });
352 | }
353 | }
354 |
--------------------------------------------------------------------------------
/src/org/outstudio/wxtest/util/SignatureUtil.java:
--------------------------------------------------------------------------------
1 | package org.outstudio.wxtest.util;
2 |
3 | import java.io.UnsupportedEncodingException;
4 | import java.security.MessageDigest;
5 | import java.security.NoSuchAlgorithmException;
6 | import java.util.Arrays;
7 |
8 | public class SignatureUtil {
9 |
10 | private static final char[] digit = { '0', '1', '2', '3', '4', '5', '6',
11 | '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
12 |
13 | /**
14 | * 得到签名
15 | */
16 | public static String getSignature(String token, String timestamp,
17 | String nonce) {
18 |
19 | String[] arr = new String[] { token, timestamp, nonce };
20 | // 将token、timestamp、nonce三个参数进行字典序排序
21 | Arrays.sort(arr);
22 | StringBuilder content = new StringBuilder();
23 | for (int i = 0; i < arr.length; i++) {
24 | content.append(arr[i]);
25 | }
26 | MessageDigest md = null;
27 | String tmpStr = null;
28 |
29 | try {
30 | md = MessageDigest.getInstance("SHA-1");
31 | // 将三个参数字符串拼接成一个字符串进行sha1加密
32 | byte[] digest = md.digest(content.toString().getBytes("UTF-8"));
33 | tmpStr = byteToStr(digest);
34 | } catch (NoSuchAlgorithmException e) {
35 | e.printStackTrace();
36 | } catch (UnsupportedEncodingException e) {
37 | e.printStackTrace();
38 | }
39 | // 将sha1加密后的字符串可与signature对比,标识该请求来源于微信
40 | return tmpStr;
41 | }
42 |
43 | /**
44 | * 将字节数组转换为十六进制字符串
45 | */
46 | private static String byteToStr(byte[] byteArray) {
47 | int len = byteArray.length;
48 | StringBuilder strDigest = new StringBuilder(len * 2);
49 | for (int i = 0; i < len; i++) {
50 | strDigest.append(byteToHexStr(byteArray[i]));
51 | }
52 | return strDigest.toString();
53 | }
54 |
55 | /**
56 | * 将字节转换为十六进制字符串
57 | */
58 | private static String byteToHexStr(byte mByte) {
59 | char[] tempArr = new char[2];
60 | tempArr[0] = digit[(mByte >>> 4) & 0X0F];
61 | tempArr[1] = digit[mByte & 0X0F];
62 |
63 | return new String(tempArr);
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/src/org/outstudio/wxtest/util/SiteInfo.java:
--------------------------------------------------------------------------------
1 | package org.outstudio.wxtest.util;
2 |
3 | public class SiteInfo {
4 |
5 | private String url;
6 | private String token;
7 |
8 | public SiteInfo() {
9 | }
10 |
11 | public SiteInfo(String url, String token) {
12 | this.url = url;
13 | this.token = token;
14 | }
15 |
16 | public String getUrl() {
17 | return url;
18 | }
19 |
20 | public void setUrl(String url) {
21 | this.url = url;
22 | }
23 |
24 | public String getToken() {
25 | return token;
26 | }
27 |
28 | public void setToken(String token) {
29 | this.token = token;
30 | }
31 |
32 | @Override
33 | public String toString() {
34 | return "SiteInfo [url=" + url + ", token=" + token + "]";
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/src/org/outstudio/wxtest/util/SiteInfoUtil.java:
--------------------------------------------------------------------------------
1 | package org.outstudio.wxtest.util;
2 |
3 | import java.io.File;
4 | import java.io.IOException;
5 | import java.util.ArrayList;
6 | import java.util.List;
7 |
8 | import org.apache.commons.io.FileUtils;
9 |
10 | public class SiteInfoUtil {
11 |
12 | private static final String configFilePath = "config.txt";
13 |
14 | /**
15 | * 从配置文件中读取服务器配置信息
16 | */
17 | public static List getSiteInfo() {
18 | File file = new File(configFilePath);
19 | List siteInfos = new ArrayList<>();
20 | try {
21 | List lines = FileUtils.readLines(file);
22 | if (lines.isEmpty()) {
23 | return siteInfos;
24 | }
25 | for (String line : lines) {
26 | String[] info = line.split(" ", 2);
27 | SiteInfo siteInfo = new SiteInfo();
28 | siteInfo.setUrl(info[0]);
29 | siteInfo.setToken(info[1]);
30 | siteInfos.add(siteInfo);
31 | }
32 | return siteInfos;
33 | } catch (IOException e) {
34 | return siteInfos;
35 | }
36 | }
37 |
38 | /**
39 | * 将服务器配置信息存进配置文件中
40 | */
41 | public static void saveSiteInfo(List siteInfos) {
42 | if (siteInfos == null || siteInfos.isEmpty()) {
43 | return;
44 | }
45 | List lines = new ArrayList<>();
46 | for (SiteInfo siteInfo : siteInfos) {
47 | lines.add(siteInfo.getUrl() + " " + siteInfo.getToken());
48 | }
49 | File file = new File(configFilePath);
50 | try {
51 | FileUtils.writeLines(file, lines);
52 | } catch (IOException e) {
53 | e.printStackTrace();
54 | }
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/src/org/outstudio/wxtest/util/StringUtil.java:
--------------------------------------------------------------------------------
1 | package org.outstudio.wxtest.util;
2 |
3 | public class StringUtil {
4 |
5 | /**
6 | * 将字符串补充为指定长度的字符串,从右侧添加字符
7 | *
8 | * @param str
9 | * 填充前的字符串
10 | * @param ch
11 | * 填充使用的字符
12 | * @param len
13 | * 字符串的目标长度
14 | * @return 填充后的字符串
15 | */
16 | public static String paddingRight(String str, char ch, int len) {
17 | StringBuilder sb = new StringBuilder(str);
18 | for (int i = 0; i < len - str.length(); i++) {
19 | sb.append(ch);
20 | }
21 | return sb.toString();
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/src/org/outstudio/wxtest/util/WechatUtil.java:
--------------------------------------------------------------------------------
1 | package org.outstudio.wxtest.util;
2 |
3 | import java.io.IOException;
4 | import java.sql.Timestamp;
5 | import java.util.List;
6 |
7 | import org.easywechat.msg.Article;
8 | import org.easywechat.msg.BaseMsg;
9 | import org.easywechat.msg.ImageMsg;
10 | import org.easywechat.msg.MusicMsg;
11 | import org.easywechat.msg.NewsMsg;
12 | import org.easywechat.msg.RespType;
13 | import org.easywechat.msg.TextMsg;
14 | import org.easywechat.msg.VideoMsg;
15 | import org.easywechat.msg.VoiceMsg;
16 | import org.easywechat.msg.req.BaseReq;
17 | import org.easywechat.msg.req.EventType;
18 | import org.easywechat.msg.req.LocationEvent;
19 | import org.easywechat.msg.req.MenuEvent;
20 | import org.easywechat.msg.req.TextReqMsg;
21 | import org.easywechat.util.MessageFactory;
22 | import org.jsoup.Connection;
23 | import org.jsoup.Connection.Method;
24 | import org.jsoup.Jsoup;
25 | import org.jsoup.nodes.Document;
26 | import org.jsoup.nodes.Element;
27 | import org.jsoup.parser.Parser;
28 | import org.jsoup.select.Elements;
29 |
30 | /**
31 | * 与微信相关的工具类
32 | */
33 | public class WechatUtil {
34 |
35 | /**
36 | * 模拟发送文本消息
37 | *
38 | * @return 响应信息,一般为XML格式
39 | * @throws IOException
40 | */
41 | public static String sendText(String token, String url, String text)
42 | throws IOException {
43 | String realUrl = buildUrl(token, url);
44 | String xmlData = createTextReqMsg(text).toXml();
45 |
46 | String resp = getConn(realUrl).rawData(xmlData).execute().body();
47 |
48 | return resp;
49 | }
50 |
51 | /**
52 | * 模拟发送菜单点击事件
53 | *
54 | * @return 响应信息,一般为XML格式
55 | * @throws IOException
56 | */
57 | public static String sendClickEvent(String token, String url,
58 | String eventKey) throws IOException {
59 | String realUrl = buildUrl(token, url);
60 | String xmlData = createMenuClickEvent(eventKey).toXml();
61 | System.out.println(xmlData);
62 |
63 | String resp = getConn(realUrl).rawData(xmlData).execute().body();
64 |
65 | return resp;
66 | }
67 |
68 | /**
69 | * 模拟发送地理位置事件
70 | *
71 | * @return 响应信息,一般为XML格式
72 | * @throws IOException
73 | */
74 | public static String sendLocationEvent(String token, String url,
75 | double latitude, double longitude, double precision)
76 | throws IOException {
77 | String realUrl = buildUrl(token, url);
78 | String xmlData = createLocationEvent(latitude, longitude, precision)
79 | .toXml();
80 |
81 | String resp = getConn(realUrl).rawData(xmlData).execute().body();
82 |
83 | return resp;
84 | }
85 |
86 | /**
87 | * 模拟发送XML数据
88 | *
89 | * @return 响应信息,一般为XML格式
90 | * @throws IOException
91 | */
92 | public static String sendXml(String token, String url, String xml)
93 | throws IOException {
94 | String realUrl = buildUrl(token, url);
95 |
96 | String resp = getConn(realUrl).rawData(xml).execute().body();
97 |
98 | return resp;
99 | }
100 |
101 | public static Document getDocFromXml(String xml) {
102 | return Jsoup.parse(xml, "", Parser.xmlParser());
103 | }
104 |
105 | /**
106 | * 解析Document得到微信响应消息对象
107 | *
108 | * @throws Exception
109 | * 如果解析失败
110 | */
111 | public static BaseMsg getMsgFromDoc(Document doc) throws Exception {
112 |
113 | String toUserName = getTagValue("ToUserName", doc);
114 | String fromUserName = getTagValue("FromUserName", doc);
115 | String rawCreateTime = getTagValue("CreateTime", doc);
116 | long createTime = Long.parseLong(rawCreateTime);
117 |
118 | String msgType = getTagValue("MsgType", doc);
119 |
120 | BaseMsg msg;
121 |
122 | if (msgType.equals(RespType.TEXT)) {
123 | String content = getTagValue("Content", doc);
124 | msg = MessageFactory.createTextMsg(content);
125 | } else if (msgType.equals(RespType.NEWS)) {
126 |
127 | NewsMsg newsMsg = MessageFactory.createNewsMsg();
128 |
129 | Elements items = doc.getElementsByTag("item");
130 | for (Element item : items) {
131 | String title = getTagValue("Title", item);
132 | String description = getTagValue("Description", item);
133 | String picUrl = getTagValue("PicUrl", item);
134 | String Url = getTagValue("Url", item);
135 |
136 | newsMsg.add(title, description, picUrl, Url);
137 | }
138 | msg = newsMsg;
139 | } else if (msgType.equals(RespType.IMAGE)) {
140 | String mediaId = getTagValue("MediaId", doc);
141 | msg = MessageFactory.createImageMsg(mediaId);
142 | } else if (msgType.equals(RespType.VOICE)) {
143 | String mediaId = getTagValue("MediaId", doc);
144 | msg = MessageFactory.createVoiceMsg(mediaId);
145 | } else if (msgType.equals(RespType.VIDEO)) {
146 | String mediaId = getTagValue("MediaId", doc);
147 | String title = getTagValue("Title", doc);
148 | String description = getTagValue("Description", doc);
149 | msg = MessageFactory.createVideoMsg(mediaId, title, description);
150 | } else if (msgType.equals(RespType.MUSIC)) {
151 | String title = getTagValue("Title", doc);
152 | String description = getTagValue("Description", doc);
153 | String musicUrl = getTagValue("MusicUrl", doc);
154 | String hqMusicUrl = getTagValue("HQMusicUrl", doc);
155 | String thumbMediaId = getTagValue("ThumbMediaId", doc);
156 | msg = MessageFactory.createMusicMsg(thumbMediaId, title,
157 | description, musicUrl, hqMusicUrl);
158 | } else {
159 | return null;
160 | }
161 |
162 | msg.setFromUserName(fromUserName);
163 | msg.setToUserName(toUserName);
164 | msg.setCreateTime(createTime);
165 |
166 | return msg;
167 | }
168 |
169 | /**
170 | * 得到解析后的消息对象
171 | */
172 | public static String getPrettyString(BaseMsg msg) {
173 | StringBuilder sb = new StringBuilder();
174 | String space = " ";
175 |
176 | if (msg instanceof TextMsg) {
177 | TextMsg textMsg = (TextMsg) msg;
178 | sb.append("文本消息:\n");
179 | sb.append(space).append("Content:").append(textMsg.getContent())
180 | .append("\n");
181 | } else if (msg instanceof ImageMsg) {
182 | ImageMsg imageMsg = (ImageMsg) msg;
183 | sb.append("图片消息:\n");
184 | sb.append(space).append("MediaId:").append(imageMsg.getMediaId())
185 | .append("\n");
186 | } else if (msg instanceof VoiceMsg) {
187 | VoiceMsg voiceMsg = (VoiceMsg) msg;
188 | sb.append("语音消息:\n");
189 | sb.append(space).append("MediaId:").append(voiceMsg.getMediaId())
190 | .append("\n");
191 | } else if (msg instanceof VideoMsg) {
192 | VideoMsg videoMsg = (VideoMsg) msg;
193 | sb.append("视频消息:\n");
194 | sb.append(space).append("MediaId:").append(videoMsg.getMediaId())
195 | .append("\n");
196 | sb.append(space).append("Title:").append(videoMsg.getTitle())
197 | .append("\n");
198 | sb.append(space).append("Description:")
199 | .append(videoMsg.getDescription()).append("\n");
200 | } else if (msg instanceof MusicMsg) {
201 | MusicMsg musicMsg = (MusicMsg) msg;
202 | sb.append("视频消息:\n");
203 | sb.append(space).append("Title:").append(musicMsg.getTitle())
204 | .append("\n");
205 | sb.append(space).append("Description:")
206 | .append(musicMsg.getDescription()).append("\n");
207 | sb.append(space).append("MusicUrl:").append(musicMsg.getMusicUrl())
208 | .append("\n");
209 | sb.append(space).append("HQMusicUrl:")
210 | .append(musicMsg.getHqMusicUrl()).append("\n");
211 | sb.append(space).append("ThumbMediaId:")
212 | .append(musicMsg.getThumbMediaId()).append("\n");
213 | } else if (msg instanceof NewsMsg) {
214 | NewsMsg newsMsg = (NewsMsg) msg;
215 | sb.append("图文消息:\n");
216 | List articles = newsMsg.getArticles();
217 | for (int i = 0; i < articles.size(); i++) {
218 | sb.append(space).append("第 ").append(i + 1).append(" 条:\n");
219 |
220 | Article article = articles.get(i);
221 |
222 | String title = article.getTitle();
223 | String description = article.getDescription();
224 | String picUrl = article.getPicUrl();
225 | String url = article.getUrl();
226 |
227 | if (title != null) {
228 | sb.append(space).append(space).append("Title:")
229 | .append(title).append("\n");
230 | }
231 | if (description != null) {
232 | sb.append(space).append(space).append("Description:")
233 | .append(description).append("\n");
234 | }
235 | if (picUrl != null) {
236 | sb.append(space).append(space).append("PicUrl:")
237 | .append(picUrl).append("\n");
238 | }
239 | if (url != null) {
240 | sb.append(space).append(space).append("Url:").append(url)
241 | .append("\n");
242 | }
243 | }
244 | }
245 |
246 | sb.append("\n");
247 | sb.append("FromUserName:").append(msg.getFromUserName()).append("\n");
248 | sb.append("ToUserName:").append(msg.getToUserName()).append("\n");
249 | long createTime = msg.getCreateTime();
250 | sb.append("CreateTime:").append(createTime).append("(")
251 | .append(getDatetimeFromCreateTime(createTime)).append(")\n");
252 |
253 | return sb.toString();
254 | }
255 |
256 | /**
257 | * 将微信消息的CreateTime解析成格式化的日期时间字符串
258 | */
259 | public static String getDatetimeFromCreateTime(long createTime) {
260 | String raw = String.valueOf(createTime);
261 | String strTime = StringUtil.paddingRight(raw, '0', 13);
262 | long time = Long.parseLong(strTime);
263 | return new Timestamp(time).toString().substring(0, 19);
264 | }
265 |
266 | /**
267 | * 得到适合该项目的Connection对象
268 | */
269 | private static Connection getConn(String url) {
270 | return Jsoup.connect(url).header("Content-Type", "application/json")
271 | .ignoreContentType(true).timeout(10000).method(Method.POST);
272 | }
273 |
274 | private static String buildUrl(String token, String rawUrl) {
275 | StringBuilder sb = new StringBuilder(rawUrl);
276 |
277 | String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
278 | String nonce = "zzz";
279 | String signature = SignatureUtil.getSignature(token, timestamp, nonce);
280 |
281 | sb.append("?signature=").append(signature).append("×tamp=")
282 | .append(timestamp).append("&nonce=").append(nonce);
283 | return sb.toString();
284 | }
285 |
286 | private static TextReqMsg createTextReqMsg(String content) {
287 | TextReqMsg msg = new TextReqMsg(content);
288 | buildReqBody(msg);
289 | return msg;
290 | }
291 |
292 | private static MenuEvent createMenuClickEvent(String eventKey) {
293 | MenuEvent event = new MenuEvent(eventKey);
294 | event.setEvent(EventType.CLICK);
295 | buildReqBody(event);
296 | return event;
297 | }
298 |
299 | private static LocationEvent createLocationEvent(double latitude,
300 | double longitude, double precision) {
301 | LocationEvent event = new LocationEvent(latitude, longitude, precision);
302 | event.setEvent(EventType.LOCATION);
303 | buildReqBody(event);
304 | return event;
305 | }
306 |
307 | private static void buildReqBody(BaseReq req) {
308 | req.setFromUserName("FromUserName");
309 | req.setToUserName("ToUserName");
310 | req.setCreateTime(System.currentTimeMillis() / 1000);
311 | }
312 |
313 | private static String getTagValue(String tagName, Element ele) {
314 | Elements eles = ele.getElementsByTag(tagName);
315 | return eles.isEmpty() ? null : eles.get(0).text();
316 | }
317 |
318 | }
319 |
--------------------------------------------------------------------------------
/src/org/outstudio/wxtest/util/XmlUtil.java:
--------------------------------------------------------------------------------
1 | package org.outstudio.wxtest.util;
2 |
3 | import java.io.StringReader;
4 |
5 | import javax.xml.parsers.DocumentBuilder;
6 | import javax.xml.parsers.DocumentBuilderFactory;
7 |
8 | import org.xml.sax.InputSource;
9 |
10 | public class XmlUtil {
11 |
12 | /**
13 | * 判断给定字符串是否符合XML格式
14 | */
15 | public static boolean isValidXml(String xml) {
16 | try {
17 | StringReader reader = new StringReader(xml);
18 | DocumentBuilder db = DocumentBuilderFactory.newInstance()
19 | .newDocumentBuilder();
20 | db.parse(new InputSource(reader));
21 | } catch (Exception e) {
22 | return false;
23 | }
24 | return true;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/test/org/outstudio/wxtest/StringUtilTest.java:
--------------------------------------------------------------------------------
1 | package org.outstudio.wxtest;
2 |
3 | import org.junit.Test;
4 | import org.outstudio.wxtest.util.StringUtil;
5 |
6 | import static org.junit.Assert.assertEquals;
7 |
8 | public class StringUtilTest {
9 |
10 | @Test
11 | public void paddingRightNormalCase() {
12 | String result = StringUtil.paddingRight("abc", '0', 5);
13 | assertEquals("abc00", result);
14 | }
15 |
16 | @Test
17 | public void paddingRightWhenInputStringIsLongerThanInputLength() {
18 | String result = StringUtil.paddingRight("123456789", '0', 5);
19 | assertEquals("123456789", result);
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/test/org/outstudio/wxtest/WechatUtilTest.java:
--------------------------------------------------------------------------------
1 | package org.outstudio.wxtest;
2 |
3 | import org.junit.Test;
4 | import org.outstudio.wxtest.util.WechatUtil;
5 |
6 | import static org.junit.Assert.assertEquals;
7 |
8 | public class WechatUtilTest {
9 |
10 | @Test
11 | public void getDatetimeFromCreateTimeLength10() {
12 | String time = WechatUtil.getDatetimeFromCreateTime(1413118184L);
13 | assertEquals("2014-10-12 20:49:44", time);
14 | }
15 |
16 | @Test
17 | public void getDatetimeFromCreateTimeLength13() {
18 | String time = WechatUtil.getDatetimeFromCreateTime(1413118184292L);
19 | assertEquals("2014-10-12 20:49:44", time);
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/test/org/outstudio/wxtest/XmlUtilTest.java:
--------------------------------------------------------------------------------
1 | package org.outstudio.wxtest;
2 |
3 | import static org.junit.Assert.assertEquals;
4 |
5 | import java.io.File;
6 | import java.io.IOException;
7 |
8 | import org.apache.commons.io.FileUtils;
9 | import org.junit.Test;
10 | import org.outstudio.wxtest.util.XmlUtil;
11 |
12 | public class XmlUtilTest {
13 |
14 | static String TEXT_REQ_MSG;
15 | static String IMAGE_REQ_MSG;
16 | static String VOICE_REQ_MSG;
17 | static String VIDEO_REQ_MSG;
18 | static String LOCATION_REQ_MSG;
19 | static String LINK_REQ_MSG;
20 |
21 | static String INVALID_XML_1;
22 |
23 | static {
24 | try {
25 | TEXT_REQ_MSG = FileUtils.readFileToString(new File(
26 | "./test_res/TextReqMsg.txt"));
27 | IMAGE_REQ_MSG = FileUtils.readFileToString(new File(
28 | "./test_res/ImageReqMsg.txt"));
29 | VOICE_REQ_MSG = FileUtils.readFileToString(new File(
30 | "./test_res/VoiceReqMsg.txt"));
31 | VIDEO_REQ_MSG = FileUtils.readFileToString(new File(
32 | "./test_res/VideoReqMsg.txt"));
33 | LOCATION_REQ_MSG = FileUtils.readFileToString(new File(
34 | "./test_res/LocationReqMsg.txt"));
35 | LINK_REQ_MSG = FileUtils.readFileToString(new File(
36 | "./test_res/LinkReqMsg.txt"));
37 | INVALID_XML_1 = FileUtils.readFileToString(new File(
38 | "./test_res/invalid_xml_1.txt"));
39 | } catch (IOException e) {
40 | e.printStackTrace();
41 | }
42 | }
43 |
44 | @Test
45 | public void validTextReqMsgIsValidXml() {
46 | assertEquals(true, XmlUtil.isValidXml(TEXT_REQ_MSG));
47 | }
48 |
49 | @Test
50 | public void validImageReqMsgIsValidXml() {
51 | assertEquals(true, XmlUtil.isValidXml(IMAGE_REQ_MSG));
52 | }
53 |
54 | @Test
55 | public void validVoiceReqMsgIsValidXml() {
56 | assertEquals(true, XmlUtil.isValidXml(VOICE_REQ_MSG));
57 | }
58 |
59 | @Test
60 | public void validVideoReqMsgIsValidXml() {
61 | assertEquals(true, XmlUtil.isValidXml(VIDEO_REQ_MSG));
62 | }
63 |
64 | @Test
65 | public void validLocationReqMsgIsValidXml() {
66 | assertEquals(true, XmlUtil.isValidXml(LOCATION_REQ_MSG));
67 | }
68 |
69 | @Test
70 | public void validLinkReqMsgIsValidXml() {
71 | assertEquals(true, XmlUtil.isValidXml(LINK_REQ_MSG));
72 | }
73 |
74 | @Test
75 | public void invalidXmlCase1() {
76 | assertEquals(false, XmlUtil.isValidXml(INVALID_XML_1));
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/test_res/ImageReqMsg.txt:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 1348831860
5 |
6 |
7 |
8 | 1234567890123456
9 |
--------------------------------------------------------------------------------
/test_res/LinkReqMsg.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/test_res/LinkReqMsg.txt
--------------------------------------------------------------------------------
/test_res/LocationReqMsg.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubiRUN/WechatTestTool/b53129bdaf923e00cb52105d3b9636914765d455/test_res/LocationReqMsg.txt
--------------------------------------------------------------------------------
/test_res/TextReqMsg.txt:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 1348831860
5 |
6 |
7 | 1234567890123456
8 |
--------------------------------------------------------------------------------
/test_res/VideoReqMsg.txt:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 1357290913
5 |
6 |
7 |
8 | 1234567890123456
9 |
--------------------------------------------------------------------------------
/test_res/VoiceReqMsg.txt:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 1357290913
5 |
6 |
7 |
8 | 1234567890123456
9 |
--------------------------------------------------------------------------------
/test_res/invalid_xml_1.txt:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 1348831860
5 |
6 |
7 | 1234567890123456
8 |
--------------------------------------------------------------------------------