init v1.0.0

This commit is contained in:
ageer
2024-02-27 20:52:19 +08:00
parent 1f7f97e86a
commit a079ef44e5
602 changed files with 163057 additions and 95 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 184 KiB

After

Width:  |  Height:  |  Size: 547 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 532 KiB

After

Width:  |  Height:  |  Size: 222 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 MiB

After

Width:  |  Height:  |  Size: 139 KiB

28
pom.xml
View File

@@ -10,7 +10,7 @@
<name>ruoyi-ai</name> <name>ruoyi-ai</name>
<url>https://gitee.com/ageerle/ruoyi-ai</url> <url>https://gitee.com/ageerle/ruoyi-ai</url>
<description>AI助手后台管理系统</description> <description>AI助手</description>
<properties> <properties>
<revision>1.0.0</revision> <revision>1.0.0</revision>
@@ -242,16 +242,16 @@
<version>${tencent.sms.version}</version> <version>${tencent.sms.version}</version>
</dependency> </dependency>
<dependency> <!-- <dependency>-->
<groupId>de.codecentric</groupId> <!-- <groupId>de.codecentric</groupId>-->
<artifactId>spring-boot-admin-starter-server</artifactId> <!-- <artifactId>spring-boot-admin-starter-server</artifactId>-->
<version>${spring-boot-admin.version}</version> <!-- <version>${spring-boot-admin.version}</version>-->
</dependency> <!-- </dependency>-->
<dependency> <!-- <dependency>-->
<groupId>de.codecentric</groupId> <!-- <groupId>de.codecentric</groupId>-->
<artifactId>spring-boot-admin-starter-client</artifactId> <!-- <artifactId>spring-boot-admin-starter-client</artifactId>-->
<version>${spring-boot-admin.version}</version> <!-- <version>${spring-boot-admin.version}</version>-->
</dependency> <!-- </dependency>-->
<!--redisson--> <!--redisson-->
<dependency> <dependency>
@@ -318,6 +318,12 @@
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<dependency>
<groupId>com.xmzs</groupId>
<artifactId>ruoyi-midjourney</artifactId>
<version>${revision}</version>
</dependency>
<dependency> <dependency>
<groupId>com.xmzs</groupId> <groupId>com.xmzs</groupId>
<artifactId>ruoyi-generator</artifactId> <artifactId>ruoyi-generator</artifactId>

View File

@@ -59,6 +59,11 @@
<artifactId>ruoyi-job</artifactId> <artifactId>ruoyi-job</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.xmzs</groupId>
<artifactId>ruoyi-midjourney</artifactId>
</dependency>
<!-- 代码生成--> <!-- 代码生成-->
<dependency> <dependency>
<groupId>com.xmzs</groupId> <groupId>com.xmzs</groupId>
@@ -71,10 +76,10 @@
<artifactId>ruoyi-demo</artifactId> <artifactId>ruoyi-demo</artifactId>
</dependency> </dependency>
<dependency> <!-- <dependency>-->
<groupId>de.codecentric</groupId> <!-- <groupId>de.codecentric</groupId>-->
<artifactId>spring-boot-admin-starter-client</artifactId> <!-- <artifactId>spring-boot-admin-starter-client</artifactId>-->
</dependency> <!-- </dependency>-->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>

View File

@@ -94,7 +94,7 @@ public class CaptchaController {
String code = RandomUtil.randomNumbers(4); String code = RandomUtil.randomNumbers(4);
RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION)); RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
try { try {
MailUtils.sendText(emailRequest.getUsername(), "GPT助手】登录验证码", "您本次验证码为:" + code + ",有效性为" + Constants.CAPTCHA_EXPIRATION + "分钟,请尽快填写。"); MailUtils.sendText(emailRequest.getUsername(), "熊猫助手】登录验证码", "您本次验证码为:" + code + ",有效性为" + Constants.CAPTCHA_EXPIRATION + "分钟,请尽快填写。");
} catch (Exception e) { } catch (Exception e) {
log.error("验证码短信发送异常 => {}", e.getMessage()); log.error("验证码短信发送异常 => {}", e.getMessage());
return R.fail(e.getMessage()); return R.fail(e.getMessage());

View File

@@ -3,7 +3,10 @@ package com.xmzs.controller;
import com.xmzs.common.chat.domain.request.ChatRequest; import com.xmzs.common.chat.domain.request.ChatRequest;
import com.xmzs.common.chat.domain.request.Dall3Request; import com.xmzs.common.chat.domain.request.Dall3Request;
import com.xmzs.common.chat.domain.request.MjTaskRequest;
import com.xmzs.common.chat.entity.Tts.TextToSpeech;
import com.xmzs.common.chat.entity.images.Item; import com.xmzs.common.chat.entity.images.Item;
import com.xmzs.common.chat.entity.whisper.WhisperResponse;
import com.xmzs.common.core.domain.R; import com.xmzs.common.core.domain.R;
import com.xmzs.common.core.domain.model.LoginUser; import com.xmzs.common.core.domain.model.LoginUser;
import com.xmzs.common.core.exception.base.BaseException; import com.xmzs.common.core.exception.base.BaseException;
@@ -13,19 +16,30 @@ import com.xmzs.common.satoken.utils.LoginHelper;
import com.xmzs.system.domain.bo.ChatMessageBo; import com.xmzs.system.domain.bo.ChatMessageBo;
import com.xmzs.system.domain.vo.ChatMessageVo; import com.xmzs.system.domain.vo.ChatMessageVo;
import com.xmzs.system.service.IChatMessageService; import com.xmzs.system.service.IChatMessageService;
import com.xmzs.system.service.SseService; import com.xmzs.system.service.ISseService;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import org.springframework.core.io.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.util.List; import java.util.List;
import retrofit2.Response;
/** /**
* 描述: * 描述:
* *
@@ -37,38 +51,58 @@ import java.util.List;
@RequiredArgsConstructor @RequiredArgsConstructor
public class ChatController { public class ChatController {
private final SseService sseService; private final ISseService ISseService;
private final IChatMessageService chatMessageService; private final IChatMessageService chatMessageService;
/** /**
* 聊天接口 * 聊天接口
*/ */
@PostMapping("/chat") @PostMapping("/chat")
@ResponseBody @ResponseBody
public SseEmitter sseChat(@RequestBody @Valid ChatRequest chatRequest) { public SseEmitter sseChat(@RequestBody @Valid ChatRequest chatRequest, HttpServletResponse response) {
if("gpt-4-all".equals(chatRequest.getModel()) return ISseService.sseChat(chatRequest);
|| chatRequest.getModel().startsWith("gpt-4-gizmo")
|| chatRequest.getModel().startsWith("net-")
){
return sseService.transitChat(chatRequest);
}
if("azure-gpt-3.5".equals(chatRequest.getModel())){
return sseService.azureChat(chatRequest);
}
return sseService.sseChat(chatRequest);
} }
/**
* 语音转文本
*
* @param file
*/
@PostMapping("/audio")
@ResponseBody
public WhisperResponse audio(@RequestParam("file") MultipartFile file) {
WhisperResponse whisperResponse = ISseService.speechToTextTranscriptionsV2(file);
return whisperResponse;
}
/**
* 文本转语音
*
* @param textToSpeech
*/
@PostMapping("/speech")
@ResponseBody
public ResponseEntity<Resource> speech(@RequestBody TextToSpeech textToSpeech) {
return ISseService.textToSpeed(textToSpeech);
}
@PostMapping("/dall3") @PostMapping("/dall3")
@ResponseBody @ResponseBody
public R<List<Item>> dall3(@RequestBody @Valid Dall3Request request) { public R<List<Item>> dall3(@RequestBody @Valid Dall3Request request) {
return R.ok(sseService.dall3(request)); return R.ok(ISseService.dall3(request));
} }
/**
* 扣除mj绘图费用
*
* @return
*/
@PostMapping("/mjTask") @PostMapping("/mjTask")
@ResponseBody @ResponseBody
public R<String> mjTask() { public R<String> mjTask(@RequestBody MjTaskRequest mjTaskRequest) {
sseService.mjTask(); ISseService.mjTask(mjTaskRequest);
return R.ok(); return R.ok();
} }
@@ -77,7 +111,7 @@ public class ChatController {
*/ */
@PostMapping("/chatList") @PostMapping("/chatList")
@ResponseBody @ResponseBody
public R<TableDataInfo<ChatMessageVo>> list(@RequestBody @Valid ChatMessageBo chatRequest,@RequestBody PageQuery pageQuery) { public R<TableDataInfo<ChatMessageVo>> list(@RequestBody @Valid ChatMessageBo chatRequest, @RequestBody PageQuery pageQuery) {
// 默认查询当前登录用户消息记录 // 默认查询当前登录用户消息记录
LoginUser loginUser = LoginHelper.getLoginUser(); LoginUser loginUser = LoginHelper.getLoginUser();
if (loginUser == null) { if (loginUser == null) {

View File

@@ -73,7 +73,6 @@ public class PayController {
return R.ok(paymentOrdersVo); return R.ok(paymentOrdersVo);
} }
/** /**
* 跳转通知地址 * 跳转通知地址
* *
@@ -138,6 +137,9 @@ public class PayController {
BeanUtil.copyProperties(paymentOrdersVo,paymentOrdersBo); BeanUtil.copyProperties(paymentOrdersVo,paymentOrdersBo);
paymentOrdersService.updateByBo(paymentOrdersBo); paymentOrdersService.updateByBo(paymentOrdersBo);
SysUserVo sysUserVo = userService.selectUserById(paymentOrdersVo.getUserId()); SysUserVo sysUserVo = userService.selectUserById(paymentOrdersVo.getUserId());
if(money>9.9){
money = money*2;
}
sysUserVo.setUserBalance(sysUserVo.getUserBalance()+money); sysUserVo.setUserBalance(sysUserVo.getUserBalance()+money);
SysUserBo sysUserBo = new SysUserBo(); SysUserBo sysUserBo = new SysUserBo();
BeanUtil.copyProperties(sysUserVo,sysUserBo); BeanUtil.copyProperties(sysUserVo,sysUserBo);

View File

@@ -0,0 +1,51 @@
package com.xmzs.controller;
import cn.dev33.satoken.annotation.SaIgnore;
import com.xmzs.common.wechat.Wechat;
import com.xmzs.system.cofing.KeywordConfig;
import com.xmzs.system.cofing.QqConfig;
import com.xmzs.system.cofing.WechatConfig;
import com.xmzs.system.handler.WechatMessageHandler;
import com.xmzs.system.service.ISseService;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 个人微信扩展控制器
*
* @author WangLe
*/
@SaIgnore
@Slf4j
@Validated
@RequiredArgsConstructor
@RestController
public class WeChatController {
@Getter
private Wechat wechatBot;
private final WechatConfig wechatConfig;
private final ISseService sseService;
private final KeywordConfig keywordConfig;
/**
* 获取微信登录二维码
*
*/
@PostMapping("/getQr")
public void getQr() {
//微信
if (wechatConfig.getEnable()){
log.info("正在登录微信,请按提示操作:");
wechatBot = new Wechat(new WechatMessageHandler(sseService, keywordConfig), wechatConfig.getQrPath());
wechatBot.start();
}
}
}

View File

@@ -51,7 +51,7 @@ spring:
# rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题) # rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题)
url: jdbc:mysql://127.0.0.1:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true url: jdbc:mysql://127.0.0.1:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
username: ry-vue username: ry-vue
password: ry-vue password: xxx
# 从库数据源 # 从库数据源
# slave: # slave:

View File

@@ -220,11 +220,11 @@ mail:
# 是否需要用户名密码验证 # 是否需要用户名密码验证
auth: true auth: true
# 发送方遵循RFC-822标准 # 发送方遵循RFC-822标准
from: xxx@163.com from: ageerle@163.com
# 用户名注意如果使用foxmail邮箱此处user为qq号 # 用户名注意如果使用foxmail邮箱此处user为qq号
user: xxx@163.com user: ageerle@163.com
# 密码(填写授权码) # 密码(填写授权码)
pass: pass pass: TOGXBVPYFVPFRQMQ
# 使用 STARTTLS安全连接STARTTLS是对纯文本通信协议的扩展。 # 使用 STARTTLS安全连接STARTTLS是对纯文本通信协议的扩展。
starttlsEnable: true starttlsEnable: true
# 使用SSL安全连接 # 使用SSL安全连接
@@ -318,14 +318,10 @@ websocket:
path: '' path: ''
# 设置访问源地址 # 设置访问源地址
allowedOrigins: '*' allowedOrigins: '*'
# AI助手配置信息 # chatgpt配置信息
chat: chat:
apiKey: '' apiKey: 'sk-uMCP3lTg1dQ9L7Xs2bF352Fa216a4c9280577b205dE67e12'
apiHost: '' apiHost: 'https://api.pandarobot.chat/'
# 中转接口
transit:
apiKey: ''
apiHost: 'https://api.gptgod.online/'
# 微信小程序配置信息 # 微信小程序配置信息
wx: wx:
miniapp: miniapp:
@@ -343,3 +339,37 @@ baidu:
apiKey: '' # apiKey apiKey: '' # apiKey
secretKey: '' # secretKey secretKey: '' # secretKey
wechat:
# 是否使用微信 true/false
enable: true
# 生成的登录二维码路径 默认与项目同级
qrPath: "./"
keyword:
# 重置会话指令
reset: "重置会话"
# ai画图指令(DALL·E模型 https://platform.openai.com/docs/models/dall-e)
# generation 根据关键词生成图片(https://platform.openai.com/docs/guides/images/generations)
image: "ai画图"
# ai语音指令(TTS模型 https://platform.openai.com/docs/api-reference/audio)
audio: "ai语音"
mj:
api-secret:
task-store:
type: in_memory
timeout: 30d
translate-way: gpt
# proxy:
# host: 127.0.0.1
# port: 10809
ng-discord:
server: https://discord.pandarobot.chat/
cdn: https://app.pandarobot.chat/
wss: https://gateway.pandarobot.chat/
openai:
gpt-api-url: 'https://api.pandarobot.chat/'
gpt-api-key: 'sk-xxx'
accounts:
- guild-id: 'xxxxx'
channel-id: 'xxxxx'
user-token: 'xx.xx'

View File

@@ -34,6 +34,7 @@
<module>ruoyi-common-tenant</module> <module>ruoyi-common-tenant</module>
<module>ruoyi-common-chat</module> <module>ruoyi-common-chat</module>
<module>ruoyi-common-pay</module> <module>ruoyi-common-pay</module>
<module>ruoyi-common-wechat</module>
</modules> </modules>
<artifactId>ruoyi-common</artifactId> <artifactId>ruoyi-common</artifactId>

View File

@@ -166,6 +166,13 @@
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<!-- 微信模块 -->
<dependency>
<groupId>com.xmzs</groupId>
<artifactId>ruoyi-common-wechat</artifactId>
<version>${revision}</version>
</dependency>
<!-- 支付模块 --> <!-- 支付模块 -->
<dependency> <dependency>
<groupId>com.xmzs</groupId> <groupId>com.xmzs</groupId>

View File

@@ -70,13 +70,6 @@
<version>0.5.0</version> <version>0.5.0</version>
</dependency> </dependency>
<!-- azure-ai -->
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-ai-openai</artifactId>
<version>1.0.0-beta.6</version>
</dependency>
<dependency> <dependency>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId> <artifactId>hutool-all</artifactId>

View File

@@ -12,15 +12,17 @@ public class OpenAIConst {
public final static int SUCCEED_CODE = 200; public final static int SUCCEED_CODE = 200;
public final static double GPT3_COST = 0.03; public final static double GPT3_COST = 0.05;
public final static double GPT4_COST = 0.3; public final static double GPT4_COST = 0.3;
public final static double GPT4_ALL_COST = 0.3;
/** 绘图费用 */ /** 绘图费用 */
public final static double DALL3_COST = 0.3; public final static double DALL3_COST = 0.4;
/** 绘图费用-高清 */ /** 绘图费用-高清 */
public final static double DALL3_HD_COST = 0.6; public final static double DALL3_HD_COST = 0.8;
/** mdjourney绘图费用 */ /** mdjourney绘图费用 */
public final static double MJ_COST = 0.3; public final static double MJ_COST = 0.3;

View File

@@ -0,0 +1,15 @@
package com.xmzs.common.chat.domain.request;
import jakarta.validation.constraints.NotEmpty;
import lombok.Data;
/**
* mj任务请求实体类
*
* @author WangLe
*/
@Data
public class MjTaskRequest {
private String prompt;
}

View File

@@ -0,0 +1,48 @@
package com.xmzs.common.chat.entity.Tts;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.*;
@Data
@Builder
@JsonInclude(JsonInclude.Include.NON_NULL)
@NoArgsConstructor
@AllArgsConstructor
public class TextToSpeech {
@Builder.Default
private String model = Model.TTS_1.getName();
/**
* 音频声音源
*
* @see TtsVoice
*/
private String voice;
/**
* 输入内容
*/
private String input;
/**
* 输出音频文件格式
*
* @see TtsFormat
*/
@JsonProperty("response_format")
private String responseFormat;
/**
* 速度调节默认是1取值范围0.25——4.0
*/
private Double speed;
@Getter
@AllArgsConstructor
public enum Model {
TTS_1("tts-1"),
TTS_1_HD("tts-1-hd"),
;
private final String name;
}
}

View File

@@ -0,0 +1,15 @@
package com.xmzs.common.chat.entity.Tts;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum TtsFormat {
MP3("mp3"),
OPUS("opus"),
AAC("aac"),
FLAC("flac"),
;
private final String name;
}

View File

@@ -0,0 +1,23 @@
package com.xmzs.common.chat.entity.Tts;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 生成不同声音的音频
* <p>具体语音效果参考https://platform.openai.com/docs/guides/text-to-speech</p>
*/
@Getter
@AllArgsConstructor
public enum TtsVoice {
ALLOY("alloy"),
ECHO("echo"),
FABLE("fable"),
ONYX("onyx"),
NOVA("nova"),
SHIMMER("shimmer"),
;
private final String name;
}

View File

@@ -174,6 +174,10 @@ public class BaseChatCompletion implements Serializable {
* gpt-3.5-turbo-16k-0613 超长上下文 支持函数 * gpt-3.5-turbo-16k-0613 超长上下文 支持函数
*/ */
GPT_3_5_TURBO_16K_0613("gpt-3.5-turbo-16k-0613"), GPT_3_5_TURBO_16K_0613("gpt-3.5-turbo-16k-0613"),
/**
* gpt-3.5-turbo-0125 超长上下文 支持函数
*/
GPT_3_5_TURBO_0125("gpt-3.5-turbo-0125"),
/** /**
* GPT4.0 * GPT4.0
*/ */
@@ -209,6 +213,10 @@ public class BaseChatCompletion implements Serializable {
* 支持图片 * 支持图片
*/ */
GPT_4_VISION_PREVIEW("gpt-4-vision-preview"), GPT_4_VISION_PREVIEW("gpt-4-vision-preview"),
/**
* gpt-4-0613支持函数
*/
GPT_4_0125_PREVIEW("gpt-4-0125-preview"),
; ;
private final String name; private final String name;
} }

View File

@@ -1,5 +1,6 @@
package com.xmzs.common.chat.openai; package com.xmzs.common.chat.openai;
import com.xmzs.common.chat.entity.Tts.TextToSpeech;
import com.xmzs.common.chat.entity.chat.ChatCompletionWithPicture; import com.xmzs.common.chat.entity.chat.ChatCompletionWithPicture;
import io.reactivex.Single; import io.reactivex.Single;
import okhttp3.MultipartBody; import okhttp3.MultipartBody;
@@ -33,6 +34,7 @@ import com.xmzs.common.chat.entity.models.ModelResponse;
import com.xmzs.common.chat.entity.moderations.Moderation; import com.xmzs.common.chat.entity.moderations.Moderation;
import com.xmzs.common.chat.entity.moderations.ModerationResponse; import com.xmzs.common.chat.entity.moderations.ModerationResponse;
import com.xmzs.common.chat.entity.whisper.WhisperResponse; import com.xmzs.common.chat.entity.whisper.WhisperResponse;
import retrofit2.Call;
import retrofit2.http.*; import retrofit2.http.*;
import java.time.LocalDate; import java.time.LocalDate;
@@ -340,4 +342,15 @@ public interface OpenAiApi {
*/ */
@POST("v1/chat/completions") @POST("v1/chat/completions")
Single<ChatCompletionResponse> chatCompletionWithPicture(@Body ChatCompletionWithPicture chatCompletion); Single<ChatCompletionResponse> chatCompletionWithPicture(@Body ChatCompletionWithPicture chatCompletion);
/**
* 文本转语音
*
* @param textToSpeech 参数
* @return ResponseBody body
* @since 1.1.2
*/
@POST("v1/audio/speech")
@Streaming
Call<ResponseBody> textToSpeech(@Body TextToSpeech textToSpeech);
} }

View File

@@ -668,7 +668,6 @@ public class OpenAiClient {
return this.chatCompletion(chatCompletion); return this.chatCompletion(chatCompletion);
} }
/** /**
* 语音翻译:目前仅支持翻译为英文 * 语音翻译:目前仅支持翻译为英文
* *

View File

@@ -5,6 +5,7 @@ import cn.hutool.core.util.StrUtil;
import cn.hutool.http.ContentType; import cn.hutool.http.ContentType;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.xmzs.common.chat.config.LocalCache; import com.xmzs.common.chat.config.LocalCache;
import com.xmzs.common.chat.entity.Tts.TextToSpeech;
import com.xmzs.common.chat.entity.billing.BillingUsage; import com.xmzs.common.chat.entity.billing.BillingUsage;
import com.xmzs.common.chat.entity.billing.KeyInfo; import com.xmzs.common.chat.entity.billing.KeyInfo;
import com.xmzs.common.chat.entity.billing.Subscription; import com.xmzs.common.chat.entity.billing.Subscription;
@@ -37,10 +38,12 @@ import com.xmzs.common.chat.entity.chat.ChatCompletion;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter; import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import retrofit2.Call;
import retrofit2.Retrofit; import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.jackson.JacksonConverterFactory; import retrofit2.converter.jackson.JacksonConverterFactory;
import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.http.HttpClient; import java.net.http.HttpClient;
import java.net.http.HttpRequest; import java.net.http.HttpRequest;
@@ -344,6 +347,67 @@ public class OpenAiStreamClient {
Transcriptions transcriptions = Transcriptions.builder().build(); Transcriptions transcriptions = Transcriptions.builder().build();
return this.speechToTextTranscriptions(file, transcriptions); return this.speechToTextTranscriptions(file, transcriptions);
} }
/**
* 文本转语音(异步)
*
* @param textToSpeech 参数
* @param callback 返回值接收
* @since 1.1.2
*/
public void textToSpeech(TextToSpeech textToSpeech, retrofit2.Callback callback) {
retrofit2.Call<ResponseBody> responseBody = this.openAiApi.textToSpeech(textToSpeech);
responseBody.enqueue(callback);
}
/**
* 文本转语音(同步)
*
* @param textToSpeech 参数
* @since 1.1.3
*/
public ResponseBody textToSpeech(TextToSpeech textToSpeech){
Call<ResponseBody> responseBody = this.openAiApi.textToSpeech(textToSpeech);
try {
return responseBody.execute().body();
} catch (IOException e) {
throw new BaseException("文本转语音(同步)失败: "+e.getMessage());
}
}
/**
* 文本转语音(克隆)
*
* @param textToSpeech
* @return
*/
public ResponseBody textToSpeechClone(TextToSpeech textToSpeech) {
String baseUrl = "http://localhost:8081";
String spk = "三月七";
String text = textToSpeech.getInput();
String lang = "zh";
// 创建OkHttpClient实例
OkHttpClient client = new OkHttpClient();
// 构建请求URL
HttpUrl.Builder urlBuilder = HttpUrl.parse(baseUrl).newBuilder();
urlBuilder.addQueryParameter("spk", spk);
urlBuilder.addQueryParameter("text", text);
urlBuilder.addQueryParameter("lang", lang);
String url = urlBuilder.build().toString();
// 创建请求对象
Request request = new Request.Builder()
.url(url)
.build();
// 发送请求并处理响应
try {
return client.newCall(request).execute().body();
} catch (IOException e) {
throw new BaseException("语音克隆失败!{}",e.getMessage());
}
}
/** /**
* 构造 * 构造

View File

@@ -6,6 +6,7 @@ import com.knuddels.jtokkit.api.Encoding;
import com.knuddels.jtokkit.api.EncodingRegistry; import com.knuddels.jtokkit.api.EncodingRegistry;
import com.knuddels.jtokkit.api.EncodingType; import com.knuddels.jtokkit.api.EncodingType;
import com.knuddels.jtokkit.api.ModelType; import com.knuddels.jtokkit.api.ModelType;
import com.xmzs.common.chat.entity.chat.BaseChatCompletion;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import com.xmzs.common.chat.entity.chat.ChatCompletion; import com.xmzs.common.chat.entity.chat.ChatCompletion;
@@ -39,11 +40,13 @@ public class TikTokensUtil {
modelMap.put(ChatCompletion.Model.GPT_3_5_TURBO_0613.getName(), registry.getEncodingForModel(ModelType.GPT_3_5_TURBO)); modelMap.put(ChatCompletion.Model.GPT_3_5_TURBO_0613.getName(), registry.getEncodingForModel(ModelType.GPT_3_5_TURBO));
modelMap.put(ChatCompletion.Model.GPT_3_5_TURBO_16K.getName(), registry.getEncodingForModel(ModelType.GPT_3_5_TURBO)); modelMap.put(ChatCompletion.Model.GPT_3_5_TURBO_16K.getName(), registry.getEncodingForModel(ModelType.GPT_3_5_TURBO));
modelMap.put(ChatCompletion.Model.GPT_3_5_TURBO_16K_0613.getName(), registry.getEncodingForModel(ModelType.GPT_3_5_TURBO)); modelMap.put(ChatCompletion.Model.GPT_3_5_TURBO_16K_0613.getName(), registry.getEncodingForModel(ModelType.GPT_3_5_TURBO));
modelMap.put(ChatCompletion.Model.GPT_3_5_TURBO_0125.getName(), registry.getEncodingForModel(ModelType.GPT_3_5_TURBO));
modelMap.put(ChatCompletion.Model.GPT_4_32K.getName(), registry.getEncodingForModel(ModelType.GPT_4)); modelMap.put(ChatCompletion.Model.GPT_4_32K.getName(), registry.getEncodingForModel(ModelType.GPT_4));
modelMap.put(ChatCompletion.Model.GPT_4_0613.getName(), registry.getEncodingForModel(ModelType.GPT_4)); modelMap.put(ChatCompletion.Model.GPT_4_0613.getName(), registry.getEncodingForModel(ModelType.GPT_4));
modelMap.put(ChatCompletion.Model.GPT_4_32K_0613.getName(), registry.getEncodingForModel(ModelType.GPT_4)); modelMap.put(ChatCompletion.Model.GPT_4_32K_0613.getName(), registry.getEncodingForModel(ModelType.GPT_4));
modelMap.put(ChatCompletion.Model.GPT_4_1106_PREVIEW.getName(), registry.getEncodingForModel(ModelType.GPT_4)); modelMap.put(ChatCompletion.Model.GPT_4_1106_PREVIEW.getName(), registry.getEncodingForModel(ModelType.GPT_4));
modelMap.put(ChatCompletion.Model.GPT_4_VISION_PREVIEW.getName(), registry.getEncodingForModel(ModelType.GPT_4)); modelMap.put(ChatCompletion.Model.GPT_4_VISION_PREVIEW.getName(), registry.getEncodingForModel(ModelType.GPT_4));
modelMap.put(ChatCompletion.Model.GPT_4_0125_PREVIEW.getName(), registry.getEncodingForModel(ModelType.GPT_4));
} }
/** /**

View File

@@ -10,28 +10,33 @@ public class PayConfig {
/** /**
* 商户ID * 商户ID
*/ */
public static String pid = "xx"; public static String pid = "xxx";
/**
* 接口地址
*/
public static String payUrl = "https://pay-cloud.vip/mapi.php";
/**
* 私钥
*/
public static String key = "xxx";
/**
* 服务器异步通知地址
*/
public static String notify_url = "https://www.pandarobot.chat/pay/returnUrl";
/**
* 页面跳转通知地址
*/
public static String return_url = "https://www.pandarobot.chat/pay/notifyUrl";
/** /**
* 支付方式 * 支付方式
*/ */
public static String type = "wxpay"; public static String type = "wxpay";
/**
* 接口地址
*/
public static String payUrl = "https://pay.bluetuo.com/mapi.php";
/**
* 服务器异步通知地址
*/
public static String notify_url = "http://xx/pay/returnUrl";
/**
* 页面跳转通知地址
*/
public static String return_url = "http://xx/pay/notifyUrl";
/** /**
* 设备类型 * 设备类型
*/ */
@@ -40,12 +45,6 @@ public class PayConfig {
/** /**
* 加密方式默认MD5 * 加密方式默认MD5
*/ */
public static String sign_type = "MD5"; public static String sign_type = "MD5";
/**
* 私钥
*/
public static String key = "xx";
} }

View File

@@ -19,5 +19,4 @@ public interface PayService {
* @return String * @return String
**/ **/
String getPayUrl(String orderNo, String name, double money, String clientIp); String getPayUrl(String orderNo, String name, double money, String clientIp);
} }

View File

@@ -40,5 +40,4 @@ public class PayServiceImpl implements PayService {
JSONObject jsonObject = new JSONObject(body); JSONObject jsonObject = new JSONObject(body);
return (String) jsonObject.get("qrcode"); return (String) jsonObject.get("qrcode");
} }
} }

View File

@@ -30,8 +30,10 @@ public class AllUrlHandler implements InitializingBean {
Map<RequestMappingInfo, HandlerMethod> map = mapping.getHandlerMethods(); Map<RequestMappingInfo, HandlerMethod> map = mapping.getHandlerMethods();
map.keySet().forEach(info -> { map.keySet().forEach(info -> {
// 获取注解上边的 path 替代 path variable 为 * // 获取注解上边的 path 替代 path variable 为 *
Objects.requireNonNull(info.getPathPatternsCondition().getPatterns()) if(info.getPathPatternsCondition()!=null){
Objects.requireNonNull(info.getPathPatternsCondition().getPatterns())
.forEach(url -> set.add(ReUtil.replaceAll(url.getPatternString(), PATTERN, "*"))); .forEach(url -> set.add(ReUtil.replaceAll(url.getPatternString(), PATTERN, "*")));
}
}); });
urls.addAll(set); urls.addAll(set);
} }

View File

@@ -0,0 +1,51 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>com.xmzs</groupId>
<artifactId>ruoyi-common</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ruoyi-common-wechat</artifactId>
<description>
ruoyi-common-wechat 微信服务
</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- emoji -->
<dependency>
<groupId>com.vdurmont</groupId>
<artifactId>emoji-java</artifactId>
<version>3.2.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.activation/activation -->
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
<!-- qq -->
<dependency>
<groupId>net.mamoe</groupId>
<artifactId>mirai-core-jvm</artifactId>
<version>2.16.0</version>
</dependency>
<dependency>
<groupId>com.xmzs</groupId>
<artifactId>ruoyi-common-json</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,34 @@
package com.xmzs.common.wechat;
import com.xmzs.common.wechat.controller.LoginController;
import com.xmzs.common.wechat.core.MsgCenter;
import com.xmzs.common.wechat.face.IMsgHandlerFace;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Wechat {
private static final Logger LOG = LoggerFactory.getLogger(Wechat.class);
private IMsgHandlerFace msgHandler;
public Wechat(IMsgHandlerFace msgHandler, String qrPath) {
System.setProperty("jsse.enableSNIExtension", "false"); // 防止SSL错误
this.msgHandler = msgHandler;
// 登陆
LoginController login = new LoginController();
login.login(qrPath);
}
public void start() {
LOG.info("+++++++++++++++++++开始消息处理+++++++++++++++++++++");
new Thread(new Runnable() {
@Override
public void run() {
MsgCenter.handleMsg(msgHandler);
}
}).start();
}
}

View File

@@ -0,0 +1,43 @@
package com.xmzs.common.wechat.api;
import java.io.File;
import java.io.IOException;
import okhttp3.Call;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
/**
* 辅助工具类,该类暂时未用,请忽略
*
* @author https://github.com/yaphone
* @date 创建时间2017年5月22日 下午10:34:46
* @version 1.0
*
*/
public class AssistTools {
private static OkHttpClient client = new OkHttpClient();
private static final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");
public static boolean sendQrPicToServer(String username, String password, String uploadUrl, String localPath)
throws IOException {
File file = new File(localPath);
RequestBody requestBody = new MultipartBody.Builder().addFormDataPart("username", username)
.addFormDataPart("password", password)
.addFormDataPart("file", file.getName(), RequestBody.create(MEDIA_TYPE_PNG, file)).build();
Request request = new Request.Builder().url(uploadUrl).post(requestBody).build();
Call call = client.newCall(request);
try {
Response response = call.execute();
System.out.println(response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
return true;
}
}

View File

@@ -0,0 +1,424 @@
package com.xmzs.common.wechat.api;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import javax.activation.MimetypesFileTypeMap;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xmzs.common.wechat.beans.BaseMsg;
import com.xmzs.common.wechat.beans.RecommendInfo;
import com.xmzs.common.wechat.core.Core;
import com.xmzs.common.wechat.utils.Config;
import com.xmzs.common.wechat.utils.MyHttpClient;
import com.xmzs.common.wechat.utils.enums.StorageLoginInfoEnum;
import com.xmzs.common.wechat.utils.enums.URLEnum;
import com.xmzs.common.wechat.utils.enums.VerifyFriendEnum;
/**
* 消息处理类
*
* @author https://github.com/yaphone
* @date 创建时间2017年4月23日 下午2:30:37
* @version 1.0
*
*/
public class MessageTools {
private static Logger LOG = LoggerFactory.getLogger(MessageTools.class);
private static Core core = Core.getInstance();
private static MyHttpClient myHttpClient = core.getMyHttpClient();
/**
* 根据UserName发送文本消息
*
* @author https://github.com/yaphone
* @date 2017年5月4日 下午11:17:38
* @param msg
* @param toUserName
*/
private static void sendMsg(String text, String toUserName) {
if (text == null) {
return;
}
LOG.info(String.format("发送消息 %s: %s", toUserName, text));
webWxSendMsg(1, text, toUserName);
}
/**
* 根据ID发送文本消息
*
* @author https://github.com/yaphone
* @date 2017年5月6日 上午11:45:51
* @param text
* @param id
*/
public static void sendMsgById(String text, String id) {
if (text == null) {
return;
}
sendMsg(text, id);
}
/**
* 根据NickName发送文本消息
*
* @author https://github.com/yaphone
* @date 2017年5月4日 下午11:17:38
* @param text
* @param nickName
*/
public static boolean sendMsgByNickName(String text, String nickName) {
if (nickName != null) {
String toUserName = WechatTools.getUserNameByNickName(nickName);
if (toUserName != null) {
webWxSendMsg(1, text, toUserName);
return true;
}
}
return false;
}
/**
* 消息发送
*
* @author https://github.com/yaphone
* @date 2017年4月23日 下午2:32:02
* @param msgType
* @param content
* @param toUserName
*/
public static void webWxSendMsg(int msgType, String content, String toUserName) {
String url = String.format(URLEnum.WEB_WX_SEND_MSG.getUrl(), core.getLoginInfo().get("url"));
Map<String, Object> msgMap = new HashMap<String, Object>();
msgMap.put("Type", msgType);
msgMap.put("Content", content);
msgMap.put("FromUserName", core.getUserName());
msgMap.put("ToUserName", toUserName == null ? core.getUserName() : toUserName);
msgMap.put("LocalID", new Date().getTime() * 10);
msgMap.put("ClientMsgId", new Date().getTime() * 10);
Map<String, Object> paramMap = core.getParamMap();
paramMap.put("Msg", msgMap);
paramMap.put("Scene", 0);
try {
String paramStr = JSON.toJSONString(paramMap);
HttpEntity entity = myHttpClient.doPost(url, paramStr);
EntityUtils.toString(entity, Consts.UTF_8);
} catch (Exception e) {
LOG.error("webWxSendMsg", e);
}
}
/**
* 上传多媒体文件到 微信服务器目前应该支持3种类型: 1. pic 直接显示,包含图片,表情 2.video 3.doc 显示为文件包含PDF等
*
* @author https://github.com/yaphone
* @date 2017年5月7日 上午12:41:13
* @param filePath
* @return
*/
private static JSONObject webWxUploadMedia(String filePath) {
File file = new File(filePath);
if (!file.exists() && file.isFile()) {
LOG.info("file is not exist");
return null;
}
String url = String.format(URLEnum.WEB_WX_UPLOAD_MEDIA.getUrl(), core.getLoginInfo().get("fileUrl"));
String mimeType = new MimetypesFileTypeMap().getContentType(file);
String mediaType = "";
if (mimeType == null) {
mimeType = "text/plain";
} else {
mediaType = mimeType.split("/")[0].equals("image") ? "pic" : "doc";
}
String lastModifieDate = new SimpleDateFormat("yyyy MM dd HH:mm:ss").format(new Date());
long fileSize = file.length();
String passTicket = (String) core.getLoginInfo().get("pass_ticket");
String clientMediaId = new Date().getTime()
+ String.valueOf(new Random().nextLong()).substring(0, 4);
String webwxDataTicket = MyHttpClient.getCookie("webwx_data_ticket");
if (webwxDataTicket == null) {
LOG.error("get cookie webwx_data_ticket error");
return null;
}
Map<String, Object> paramMap = core.getParamMap();
paramMap.put("ClientMediaId", clientMediaId);
paramMap.put("TotalLen", fileSize);
paramMap.put("StartPos", 0);
paramMap.put("DataLen", fileSize);
paramMap.put("MediaType", 4);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
builder.addTextBody("id", "WU_FILE_0", ContentType.TEXT_PLAIN);
builder.addTextBody("name", filePath, ContentType.TEXT_PLAIN);
builder.addTextBody("type", mimeType, ContentType.TEXT_PLAIN);
builder.addTextBody("lastModifieDate", lastModifieDate, ContentType.TEXT_PLAIN);
builder.addTextBody("size", String.valueOf(fileSize), ContentType.TEXT_PLAIN);
builder.addTextBody("mediatype", mediaType, ContentType.TEXT_PLAIN);
builder.addTextBody("uploadmediarequest", JSON.toJSONString(paramMap), ContentType.TEXT_PLAIN);
builder.addTextBody("webwx_data_ticket", webwxDataTicket, ContentType.TEXT_PLAIN);
builder.addTextBody("pass_ticket", passTicket, ContentType.TEXT_PLAIN);
builder.addBinaryBody("filename", file, ContentType.create(mimeType), filePath);
HttpEntity reqEntity = builder.build();
HttpEntity entity = myHttpClient.doPostFile(url, reqEntity);
if (entity != null) {
try {
String result = EntityUtils.toString(entity, Consts.UTF_8);
return JSON.parseObject(result);
} catch (Exception e) {
LOG.error("webWxUploadMedia 错误: ", e);
}
}
return null;
}
/**
* 根据NickName发送图片消息
*
* @author https://github.com/yaphone
* @date 2017年5月7日 下午10:32:45
* @param nackName
* @return
*/
public static boolean sendPicMsgByNickName(String nickName, String filePath) {
String toUserName = WechatTools.getUserNameByNickName(nickName);
if (toUserName != null) {
return sendPicMsgByUserId(toUserName, filePath);
}
return false;
}
/**
* 根据用户id发送图片消息
*
* @author https://github.com/yaphone
* @date 2017年5月7日 下午10:34:24
* @param userId
* @param filePath
* @return
*/
public static boolean sendPicMsgByUserId(String userId, String filePath) {
JSONObject responseObj = webWxUploadMedia(filePath);
if (responseObj != null) {
String mediaId = responseObj.getString("MediaId");
if (mediaId != null) {
return webWxSendMsgImg(userId, mediaId);
}
}
return false;
}
/**
* 发送图片消息,内部调用
*
* @author https://github.com/yaphone
* @date 2017年5月7日 下午10:38:55
* @return
*/
private static boolean webWxSendMsgImg(String userId, String mediaId) {
String url = String.format("%s/webwxsendmsgimg?fun=async&f=json&pass_ticket=%s", core.getLoginInfo().get("url"),
core.getLoginInfo().get("pass_ticket"));
Map<String, Object> msgMap = new HashMap<String, Object>();
msgMap.put("Type", 3);
msgMap.put("MediaId", mediaId);
msgMap.put("FromUserName", core.getUserSelf().getString("UserName"));
msgMap.put("ToUserName", userId);
String clientMsgId = String.valueOf(new Date().getTime())
+ String.valueOf(new Random().nextLong()).substring(1, 5);
msgMap.put("LocalID", clientMsgId);
msgMap.put("ClientMsgId", clientMsgId);
Map<String, Object> paramMap = core.getParamMap();
paramMap.put("BaseRequest", core.getParamMap().get("BaseRequest"));
paramMap.put("Msg", msgMap);
String paramStr = JSON.toJSONString(paramMap);
HttpEntity entity = myHttpClient.doPost(url, paramStr);
if (entity != null) {
try {
String result = EntityUtils.toString(entity, Consts.UTF_8);
return JSON.parseObject(result).getJSONObject("BaseResponse").getInteger("Ret") == 0;
} catch (Exception e) {
LOG.error("webWxSendMsgImg 错误: ", e);
}
}
return false;
}
/**
* 根据用户id发送文件
*
* @author https://github.com/yaphone
* @date 2017年5月7日 下午11:57:36
* @param userId
* @param filePath
* @return
*/
public static boolean sendFileMsgByUserId(String userId, String filePath) {
String title = new File(filePath).getName();
Map<String, String> data = new HashMap<String, String>();
data.put("appid", Config.API_WXAPPID);
data.put("title", title);
data.put("totallen", "");
data.put("attachid", "");
data.put("type", "6"); // APPMSGTYPE_ATTACH
data.put("fileext", title.split("\\.")[1]); // 文件后缀
JSONObject responseObj = webWxUploadMedia(filePath);
if (responseObj != null) {
data.put("totallen", responseObj.getString("StartPos"));
data.put("attachid", responseObj.getString("MediaId"));
} else {
LOG.error("sednFileMsgByUserId 错误: ", data);
}
return webWxSendAppMsg(userId, data);
}
/**
* 根据用户昵称发送文件消息
*
* @author https://github.com/yaphone
* @date 2017年5月10日 下午10:59:27
* @param nickName
* @param filePath
* @return
*/
public static boolean sendFileMsgByNickName(String nickName, String filePath) {
String toUserName = WechatTools.getUserNameByNickName(nickName);
if (toUserName != null) {
return sendFileMsgByUserId(toUserName, filePath);
}
return false;
}
/**
* 内部调用
*
* @author https://github.com/yaphone
* @date 2017年5月10日 上午12:21:28
* @param userId
* @param data
* @return
*/
private static boolean webWxSendAppMsg(String userId, Map<String, String> data) {
String url = String.format("%s/webwxsendappmsg?fun=async&f=json&pass_ticket=%s", core.getLoginInfo().get("url"),
core.getLoginInfo().get("pass_ticket"));
String clientMsgId = String.valueOf(new Date().getTime())
+ String.valueOf(new Random().nextLong()).substring(1, 5);
String content = "<appmsg appid='wxeb7ec651dd0aefa9' sdkver=''><title>" + data.get("title")
+ "</title><des></des><action></action><type>6</type><content></content><url></url><lowurl></lowurl>"
+ "<appattach><totallen>" + data.get("totallen") + "</totallen><attachid>" + data.get("attachid")
+ "</attachid><fileext>" + data.get("fileext") + "</fileext></appattach><extinfo></extinfo></appmsg>";
Map<String, Object> msgMap = new HashMap<String, Object>();
msgMap.put("Type", data.get("type"));
msgMap.put("Content", content);
msgMap.put("FromUserName", core.getUserSelf().getString("UserName"));
msgMap.put("ToUserName", userId);
msgMap.put("LocalID", clientMsgId);
msgMap.put("ClientMsgId", clientMsgId);
/*
* Map<String, Object> paramMap = new HashMap<String, Object>();
*
* @SuppressWarnings("unchecked") Map<String, Map<String, String>>
* baseRequestMap = (Map<String, Map<String, String>>)
* core.getLoginInfo() .get("baseRequest"); paramMap.put("BaseRequest",
* baseRequestMap.get("BaseRequest"));
*/
Map<String, Object> paramMap = core.getParamMap();
paramMap.put("Msg", msgMap);
paramMap.put("Scene", 0);
String paramStr = JSON.toJSONString(paramMap);
HttpEntity entity = myHttpClient.doPost(url, paramStr);
if (entity != null) {
try {
String result = EntityUtils.toString(entity, Consts.UTF_8);
return JSON.parseObject(result).getJSONObject("BaseResponse").getInteger("Ret") == 0;
} catch (Exception e) {
LOG.error("错误: ", e);
}
}
return false;
}
/**
* 被动添加好友
*
* @date 2017年6月29日 下午10:08:43
* @param msg
* @param accept
* true 接受 false 拒绝
*/
public static void addFriend(BaseMsg msg, boolean accept) {
if (!accept) { // 不添加
return;
}
int status = VerifyFriendEnum.ACCEPT.getCode(); // 接受好友请求
RecommendInfo recommendInfo = msg.getRecommendInfo();
String userName = recommendInfo.getUserName();
String ticket = recommendInfo.getTicket();
// 更新好友列表
// TODO 此处需要更新好友列表
// core.getContactList().add(msg.getJSONObject("RecommendInfo"));
String url = String.format(URLEnum.WEB_WX_VERIFYUSER.getUrl(), core.getLoginInfo().get("url"),
String.valueOf(System.currentTimeMillis() / 3158L), core.getLoginInfo().get("pass_ticket"));
List<Map<String, Object>> verifyUserList = new ArrayList<Map<String, Object>>();
Map<String, Object> verifyUser = new HashMap<String, Object>();
verifyUser.put("Value", userName);
verifyUser.put("VerifyUserTicket", ticket);
verifyUserList.add(verifyUser);
List<Integer> sceneList = new ArrayList<Integer>();
sceneList.add(33);
JSONObject body = new JSONObject();
body.put("BaseRequest", core.getParamMap().get("BaseRequest"));
body.put("Opcode", status);
body.put("VerifyUserListSize", 1);
body.put("VerifyUserList", verifyUserList);
body.put("VerifyContent", "");
body.put("SceneListCount", 1);
body.put("SceneList", sceneList);
body.put("skey", core.getLoginInfo().get(StorageLoginInfoEnum.skey.getKey()));
String result = null;
try {
String paramStr = JSON.toJSONString(body);
HttpEntity entity = myHttpClient.doPost(url, paramStr);
result = EntityUtils.toString(entity, Consts.UTF_8);
} catch (Exception e) {
LOG.error("webWxSendMsg", e);
}
if (StringUtils.isBlank(result)) {
LOG.error("被动添加好友失败");
}
LOG.debug(result);
}
}

View File

@@ -0,0 +1,215 @@
package com.xmzs.common.wechat.api;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xmzs.common.wechat.core.Core;
import com.xmzs.common.wechat.utils.enums.StorageLoginInfoEnum;
import com.xmzs.common.wechat.utils.enums.URLEnum;
/**
* 微信小工具,如获好友列表等
*
* @author https://github.com/yaphone
* @date 创建时间2017年5月4日 下午10:49:16
* @version 1.0
*
*/
public class WechatTools {
private static Logger LOG = LoggerFactory.getLogger(WechatTools.class);
private static Core core = Core.getInstance();
/**
* 根据用户名发送文本消息
*
* @author https://github.com/yaphone
* @date 2017年5月4日 下午10:43:14
* @param msg
* @param toUserName
*/
public static void sendMsgByUserName(String msg, String toUserName) {
MessageTools.sendMsgById(msg, toUserName);
}
/**
* <p>
* 通过RealName获取本次UserName
* </p>
* <p>
* 如NickName为"yaphone"则获取UserName=
* "@1212d3356aea8285e5bbe7b91229936bc183780a8ffa469f2d638bf0d2e4fc63"
* 可通过UserName发送消息
* </p>
*
* @author https://github.com/yaphone
* @date 2017年5月4日 下午10:56:31
* @param name
* @return
*/
public static String getUserNameByNickName(String nickName) {
for (JSONObject o : core.getContactList()) {
if (o.getString("NickName").equals(nickName)) {
return o.getString("UserName");
}
}
return null;
}
/**
* 返回好友昵称列表
*
* @author https://github.com/yaphone
* @date 2017年5月4日 下午11:37:20
* @return
*/
public static List<String> getContactNickNameList() {
List<String> contactNickNameList = new ArrayList<String>();
for (JSONObject o : core.getContactList()) {
contactNickNameList.add(o.getString("NickName"));
}
return contactNickNameList;
}
/**
* 返回好友完整信息列表
*
* @date 2017年6月26日 下午9:45:39
* @return
*/
public static List<JSONObject> getContactList() {
return core.getContactList();
}
/**
* 返回群列表
*
* @author https://github.com/yaphone
* @date 2017年5月5日 下午9:55:21
* @return
*/
public static List<JSONObject> getGroupList() {
return core.getGroupList();
}
/**
* 获取群ID列表
*
* @date 2017年6月21日 下午11:42:56
* @return
*/
public static List<String> getGroupIdList() {
return core.getGroupIdList();
}
/**
* 获取群NickName列表
*
* @date 2017年6月21日 下午11:43:38
* @return
*/
public static List<String> getGroupNickNameList() {
return core.getGroupNickNameList();
}
/**
* 根据groupIdList返回群成员列表
*
* @date 2017年6月13日 下午11:12:31
* @param groupId
* @return
*/
public static JSONArray getMemberListByGroupId(String groupId) {
return core.getGroupMemeberMap().get(groupId);
}
/**
* 退出微信
*
* @author https://github.com/yaphone
* @date 2017年5月18日 下午11:56:54
*/
public static void logout() {
webWxLogout();
}
private static boolean webWxLogout() {
String url = String.format(URLEnum.WEB_WX_LOGOUT.getUrl(),
core.getLoginInfo().get(StorageLoginInfoEnum.url.getKey()));
List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
params.add(new BasicNameValuePair("redirect", "1"));
params.add(new BasicNameValuePair("type", "1"));
params.add(
new BasicNameValuePair("skey", (String) core.getLoginInfo().get(StorageLoginInfoEnum.skey.getKey())));
try {
HttpEntity entity = core.getMyHttpClient().doGet(url, params, false, null);
String text = EntityUtils.toString(entity, Consts.UTF_8); // 无消息
return true;
} catch (Exception e) {
LOG.debug(e.getMessage());
}
return false;
}
public static void setUserInfo() {
for (JSONObject o : core.getContactList()) {
core.getUserInfoMap().put(o.getString("NickName"), o);
core.getUserInfoMap().put(o.getString("UserName"), o);
}
}
/**
*
* 根据用户昵称设置备注名称
*
* @date 2017年5月27日 上午12:21:40
* @param userName
* @param remName
*/
public static void remarkNameByNickName(String nickName, String remName) {
String url = String.format(URLEnum.WEB_WX_REMARKNAME.getUrl(), core.getLoginInfo().get("url"),
core.getLoginInfo().get(StorageLoginInfoEnum.pass_ticket.getKey()));
Map<String, Object> msgMap = new HashMap<String, Object>();
Map<String, Object> msgMap_BaseRequest = new HashMap<String, Object>();
msgMap.put("CmdId", 2);
msgMap.put("RemarkName", remName);
msgMap.put("UserName", core.getUserInfoMap().get(nickName).get("UserName"));
msgMap_BaseRequest.put("Uin", core.getLoginInfo().get(StorageLoginInfoEnum.wxuin.getKey()));
msgMap_BaseRequest.put("Sid", core.getLoginInfo().get(StorageLoginInfoEnum.wxsid.getKey()));
msgMap_BaseRequest.put("Skey", core.getLoginInfo().get(StorageLoginInfoEnum.skey.getKey()));
msgMap_BaseRequest.put("DeviceID", core.getLoginInfo().get(StorageLoginInfoEnum.deviceid.getKey()));
msgMap.put("BaseRequest", msgMap_BaseRequest);
try {
String paramStr = JSON.toJSONString(msgMap);
HttpEntity entity = core.getMyHttpClient().doPost(url, paramStr);
// String result = EntityUtils.toString(entity, Consts.UTF_8);
LOG.info("修改备注" + remName);
} catch (Exception e) {
LOG.error("remarkNameByUserName", e);
}
}
/**
* 获取微信在线状态
*
* @date 2017年6月16日 上午12:47:46
* @return
*/
public static boolean getWechatStatus() {
return core.isAlive();
}
}

View File

@@ -0,0 +1,37 @@
package com.xmzs.common.wechat.beans;
import java.io.Serializable;
/**
* AppInfo
*
* @author https://github.com/yaphone
* @date 创建时间2017年7月3日 下午10:38:14
* @version 1.0
*
*/
public class AppInfo implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private int type;
private String appId;
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
}

View File

@@ -0,0 +1,293 @@
package com.xmzs.common.wechat.beans;
import java.io.Serializable;
/**
* 收到的微信消息
*
* @author https://github.com/yaphone
* @date 创建时间2017年7月3日 下午10:28:06
* @version 1.0
*
*/
public class BaseMsg implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private int subMsgType;
private int voiceLength;
private String fileName;
private int imgHeight;
private String toUserName;
private int hasProductId;
private int imgStatus;
private String url;
private int imgWidth;
private int forwardFlag;
private int status;
private String Ticket;
/** 推荐消息报文 **/
private RecommendInfo recommendInfo;
private long createTime;
private String newMsgId;
/** 文本消息内容 **/
private String text;
/** 消息类型 **/
private int msgType;
/** 是否为群消息 **/
private boolean groupMsg;
private String msgId;
private int statusNotifyCode;
private AppInfo appInfo;
private int appMsgType;
private String Type;
private int playLength;
private String mediaId;
private String content;
private String statusNotifyUserName;
/** 消息发送者ID **/
private String fromUserName;
private String oriContent;
private String fileSize;
public int getSubMsgType() {
return subMsgType;
}
public void setSubMsgType(int subMsgType) {
this.subMsgType = subMsgType;
}
public int getVoiceLength() {
return voiceLength;
}
public void setVoiceLength(int voiceLength) {
this.voiceLength = voiceLength;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public int getImgHeight() {
return imgHeight;
}
public void setImgHeight(int imgHeight) {
this.imgHeight = imgHeight;
}
public String getToUserName() {
return toUserName;
}
public void setToUserName(String toUserName) {
this.toUserName = toUserName;
}
public int getHasProductId() {
return hasProductId;
}
public void setHasProductId(int hasProductId) {
this.hasProductId = hasProductId;
}
public int getImgStatus() {
return imgStatus;
}
public void setImgStatus(int imgStatus) {
this.imgStatus = imgStatus;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public int getImgWidth() {
return imgWidth;
}
public void setImgWidth(int imgWidth) {
this.imgWidth = imgWidth;
}
public int getForwardFlag() {
return forwardFlag;
}
public void setForwardFlag(int forwardFlag) {
this.forwardFlag = forwardFlag;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public String getTicket() {
return Ticket;
}
public void setTicket(String ticket) {
Ticket = ticket;
}
public RecommendInfo getRecommendInfo() {
return recommendInfo;
}
public void setRecommendInfo(RecommendInfo recommendInfo) {
this.recommendInfo = recommendInfo;
}
public long getCreateTime() {
return createTime;
}
public void setCreateTime(long createTime) {
this.createTime = createTime;
}
public String getNewMsgId() {
return newMsgId;
}
public void setNewMsgId(String newMsgId) {
this.newMsgId = newMsgId;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public int getMsgType() {
return msgType;
}
public void setMsgType(int msgType) {
this.msgType = msgType;
}
public boolean isGroupMsg() {
return groupMsg;
}
public void setGroupMsg(boolean groupMsg) {
this.groupMsg = groupMsg;
}
public String getMsgId() {
return msgId;
}
public void setMsgId(String msgId) {
this.msgId = msgId;
}
public int getStatusNotifyCode() {
return statusNotifyCode;
}
public void setStatusNotifyCode(int statusNotifyCode) {
this.statusNotifyCode = statusNotifyCode;
}
public AppInfo getAppInfo() {
return appInfo;
}
public void setAppInfo(AppInfo appInfo) {
this.appInfo = appInfo;
}
public int getAppMsgType() {
return appMsgType;
}
public void setAppMsgType(int appMsgType) {
this.appMsgType = appMsgType;
}
public String getType() {
return Type;
}
public void setType(String type) {
Type = type;
}
public int getPlayLength() {
return playLength;
}
public void setPlayLength(int playLength) {
this.playLength = playLength;
}
public String getMediaId() {
return mediaId;
}
public void setMediaId(String mediaId) {
this.mediaId = mediaId;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getStatusNotifyUserName() {
return statusNotifyUserName;
}
public void setStatusNotifyUserName(String statusNotifyUserName) {
this.statusNotifyUserName = statusNotifyUserName;
}
public String getFromUserName() {
return fromUserName;
}
public void setFromUserName(String fromUserName) {
this.fromUserName = fromUserName;
}
public String getOriContent() {
return oriContent;
}
public void setOriContent(String oriContent) {
this.oriContent = oriContent;
}
public String getFileSize() {
return fileSize;
}
public void setFileSize(String fileSize) {
this.fileSize = fileSize;
}
}

View File

@@ -0,0 +1,146 @@
package com.xmzs.common.wechat.beans;
import java.io.Serializable;
/**
* RecommendInfo
*
* @author https://github.com/yaphone
* @date 创建时间2017年7月3日 下午10:35:14
* @version 1.0
*
*/
public class RecommendInfo implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private String ticket;
private String userName;
private int sex;
private int attrStatus;
private String city;
private String nickName;
private int scene;
private String province;
private String content;
private String alias;
private String signature;
private int opCode;
private int qQNum;
private int verifyFlag;
public String getTicket() {
return ticket;
}
public void setTicket(String ticket) {
this.ticket = ticket;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public int getSex() {
return sex;
}
public void setSex(int sex) {
this.sex = sex;
}
public int getAttrStatus() {
return attrStatus;
}
public void setAttrStatus(int attrStatus) {
this.attrStatus = attrStatus;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
public int getScene() {
return scene;
}
public void setScene(int scene) {
this.scene = scene;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getAlias() {
return alias;
}
public void setAlias(String alias) {
this.alias = alias;
}
public String getSignature() {
return signature;
}
public void setSignature(String signature) {
this.signature = signature;
}
public int getOpCode() {
return opCode;
}
public void setOpCode(int opCode) {
this.opCode = opCode;
}
public int getqQNum() {
return qQNum;
}
public void setqQNum(int qQNum) {
this.qQNum = qQNum;
}
public int getVerifyFlag() {
return verifyFlag;
}
public void setVerifyFlag(int verifyFlag) {
this.verifyFlag = verifyFlag;
}
}

View File

@@ -0,0 +1,90 @@
package com.xmzs.common.wechat.controller;
import com.xmzs.common.wechat.utils.SleepUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.xmzs.common.wechat.api.WechatTools;
import com.xmzs.common.wechat.core.Core;
import com.xmzs.common.wechat.service.ILoginService;
import com.xmzs.common.wechat.service.impl.LoginServiceImpl;
import com.xmzs.common.wechat.thread.CheckLoginStatusThread;
import com.xmzs.common.wechat.utils.tools.CommonTools;
/**
* 登陆控制器
*
* @author https://github.com/yaphone
* @date 创建时间2017年5月13日 下午12:56:07
* @version 1.0
*
*/
public class LoginController {
private static Logger LOG = LoggerFactory.getLogger(LoginController.class);
private ILoginService loginService = new LoginServiceImpl();
private static Core core = Core.getInstance();
public void login(String qrPath) {
if (core.isAlive()) { // 已登陆
LOG.info("itchat4j已登陆");
return;
}
while (true) {
for (int count = 0; count < 10; count++) {
LOG.info("获取UUID");
while (loginService.getUuid() == null) {
LOG.info("1. 获取微信UUID");
while (loginService.getUuid() == null) {
LOG.warn("1.1. 获取微信UUID失败两秒后重新获取");
SleepUtils.sleep(2000);
}
}
LOG.info("2. 获取登陆二维码图片");
if (loginService.getQR(qrPath)) {
break;
} else if (count == 10) {
LOG.error("2.2. 获取登陆二维码图片失败,系统退出");
System.exit(0);
}
}
LOG.info("3. 请扫描二维码图片,并在手机上确认");
if (!core.isAlive()) {
loginService.login();
core.setAlive(true);
LOG.info(("登陆成功"));
break;
}
LOG.info("4. 登陆超时,请重新扫描二维码图片");
}
LOG.info("5. 登陆成功,微信初始化");
if (!loginService.webWxInit()) {
LOG.info("6. 微信初始化异常");
System.exit(0);
}
LOG.info("6. 开启微信状态通知");
loginService.wxStatusNotify();
LOG.info("7. 清除。。。。");
CommonTools.clearScreen();
LOG.info(String.format("欢迎回来, %s", core.getNickName()));
LOG.info("8. 开始接收消息");
loginService.startReceiving();
LOG.info("9. 获取联系人信息");
loginService.webWxGetContact();
LOG.info("10. 获取群好友及群好友列表");
loginService.WebWxBatchGetContact();
LOG.info("11. 缓存本次登陆好友相关消息");
WechatTools.setUserInfo(); // 登陆成功后缓存本次登陆好友相关消息NickName, UserName
LOG.info("12.开启微信状态检测线程");
new Thread(new CheckLoginStatusThread()).start();
}
}

View File

@@ -0,0 +1,276 @@
package com.xmzs.common.wechat.core;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xmzs.common.wechat.beans.BaseMsg;
import com.xmzs.common.wechat.utils.MyHttpClient;
import com.xmzs.common.wechat.utils.enums.parameters.BaseParaEnum;
/**
* 核心存储类,全局只保存一份,单例模式
*
* @author https://github.com/yaphone
* @date 创建时间2017年4月23日 下午2:33:56
* @version 1.0
*
*/
public class Core {
private static Core instance;
private Core() {
}
public static Core getInstance() {
if (instance == null) {
synchronized (Core.class) {
instance = new Core();
}
}
return instance;
}
boolean alive = false;
private int memberCount = 0;
private String indexUrl;
private String userName;
private String nickName;
private List<BaseMsg> msgList = new ArrayList<BaseMsg>();
private JSONObject userSelf; // 登陆账号自身信息
private List<JSONObject> memberList = new ArrayList<JSONObject>(); // 好友+群聊+公众号+特殊账号
private List<JSONObject> contactList = new ArrayList<JSONObject>();// 好友
private List<JSONObject> groupList = new ArrayList<JSONObject>();; // 群
private Map<String, JSONArray> groupMemeberMap = new HashMap<String, JSONArray>(); // 群聊成员字典
private List<JSONObject> publicUsersList = new ArrayList<JSONObject>();;// 公众号/服务号
private List<JSONObject> specialUsersList = new ArrayList<JSONObject>();;// 特殊账号
private List<String> groupIdList = new ArrayList<String>(); // 群ID列表
private List<String> groupNickNameList = new ArrayList<String>(); // 群NickName列表
private Map<String, JSONObject> userInfoMap = new HashMap<String, JSONObject>();
Map<String, Object> loginInfo = new HashMap<String, Object>();
// CloseableHttpClient httpClient = HttpClients.createDefault();
MyHttpClient myHttpClient = MyHttpClient.getInstance();
String uuid = null;
boolean useHotReload = false;
String hotReloadDir = "itchat.pkl";
int receivingRetryCount = 5;
private long lastNormalRetcodeTime; // 最后一次收到正常retcode的时间秒为单位
/**
* 请求参数
*/
public Map<String, Object> getParamMap() {
return new HashMap<String, Object>(1) {
/**
*
*/
private static final long serialVersionUID = 1L;
{
Map<String, String> map = new HashMap<String, String>();
for (BaseParaEnum baseRequest : BaseParaEnum.values()) {
map.put(baseRequest.para(), getLoginInfo().get(baseRequest.value()).toString());
}
put("BaseRequest", map);
}
};
}
public boolean isAlive() {
return alive;
}
public void setAlive(boolean alive) {
this.alive = alive;
}
public List<JSONObject> getMemberList() {
return memberList;
}
public void setMemberList(List<JSONObject> memberList) {
this.memberList = memberList;
}
public Map<String, Object> getLoginInfo() {
return loginInfo;
}
public void setLoginInfo(Map<String, Object> loginInfo) {
this.loginInfo = loginInfo;
}
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
public int getMemberCount() {
return memberCount;
}
public void setMemberCount(int memberCount) {
this.memberCount = memberCount;
}
public boolean isUseHotReload() {
return useHotReload;
}
public void setUseHotReload(boolean useHotReload) {
this.useHotReload = useHotReload;
}
public String getHotReloadDir() {
return hotReloadDir;
}
public void setHotReloadDir(String hotReloadDir) {
this.hotReloadDir = hotReloadDir;
}
public int getReceivingRetryCount() {
return receivingRetryCount;
}
public void setReceivingRetryCount(int receivingRetryCount) {
this.receivingRetryCount = receivingRetryCount;
}
public MyHttpClient getMyHttpClient() {
return myHttpClient;
}
public List<BaseMsg> getMsgList() {
return msgList;
}
public void setMsgList(List<BaseMsg> msgList) {
this.msgList = msgList;
}
public void setMyHttpClient(MyHttpClient myHttpClient) {
this.myHttpClient = myHttpClient;
}
public List<String> getGroupIdList() {
return groupIdList;
}
public void setGroupIdList(List<String> groupIdList) {
this.groupIdList = groupIdList;
}
public List<JSONObject> getContactList() {
return contactList;
}
public void setContactList(List<JSONObject> contactList) {
this.contactList = contactList;
}
public List<JSONObject> getGroupList() {
return groupList;
}
public void setGroupList(List<JSONObject> groupList) {
this.groupList = groupList;
}
public List<JSONObject> getPublicUsersList() {
return publicUsersList;
}
public void setPublicUsersList(List<JSONObject> publicUsersList) {
this.publicUsersList = publicUsersList;
}
public List<JSONObject> getSpecialUsersList() {
return specialUsersList;
}
public void setSpecialUsersList(List<JSONObject> specialUsersList) {
this.specialUsersList = specialUsersList;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
public JSONObject getUserSelf() {
return userSelf;
}
public void setUserSelf(JSONObject userSelf) {
this.userSelf = userSelf;
}
public Map<String, JSONObject> getUserInfoMap() {
return userInfoMap;
}
public void setUserInfoMap(Map<String, JSONObject> userInfoMap) {
this.userInfoMap = userInfoMap;
}
public synchronized long getLastNormalRetcodeTime() {
return lastNormalRetcodeTime;
}
public synchronized void setLastNormalRetcodeTime(long lastNormalRetcodeTime) {
this.lastNormalRetcodeTime = lastNormalRetcodeTime;
}
public List<String> getGroupNickNameList() {
return groupNickNameList;
}
public void setGroupNickNameList(List<String> groupNickNameList) {
this.groupNickNameList = groupNickNameList;
}
public Map<String, JSONArray> getGroupMemeberMap() {
return groupMemeberMap;
}
public void setGroupMemeberMap(Map<String, JSONArray> groupMemeberMap) {
this.groupMemeberMap = groupMemeberMap;
}
public String getIndexUrl() {
return indexUrl;
}
public void setIndexUrl(String indexUrl) {
this.indexUrl = indexUrl;
}
}

View File

@@ -0,0 +1,171 @@
package com.xmzs.common.wechat.core;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import com.xmzs.common.wechat.utils.enums.MsgCodeEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xmzs.common.wechat.api.MessageTools;
import com.xmzs.common.wechat.beans.BaseMsg;
import com.xmzs.common.wechat.face.IMsgHandlerFace;
import com.xmzs.common.wechat.utils.enums.MsgTypeEnum;
import com.xmzs.common.wechat.utils.tools.CommonTools;
/**
* 消息处理中心
*
* @author https://github.com/yaphone
* @date 创建时间2017年5月14日 下午12:47:50
* @version 1.0
*
*/
public class MsgCenter {
private static Logger LOG = LoggerFactory.getLogger(MsgCenter.class);
private static Core core = Core.getInstance();
/**
* 接收消息,放入队列
*
* @author https://github.com/yaphone
* @date 2017年4月23日 下午2:30:48
* @param msgList
* @return
*/
public static JSONArray produceMsg(JSONArray msgList) {
JSONArray result = new JSONArray();
for (int i = 0; i < msgList.size(); i++) {
JSONObject msg = new JSONObject();
JSONObject m = msgList.getJSONObject(i);
m.put("groupMsg", false);// 是否是群消息
if (m.getString("FromUserName").contains("@@") || m.getString("ToUserName").contains("@@")) { // 群聊消息
if (m.getString("FromUserName").contains("@@")
&& !core.getGroupIdList().contains(m.getString("FromUserName"))) {
core.getGroupIdList().add((m.getString("FromUserName")));
} else if (m.getString("ToUserName").contains("@@")
&& !core.getGroupIdList().contains(m.getString("ToUserName"))) {
core.getGroupIdList().add((m.getString("ToUserName")));
}
// 群消息与普通消息不同的是在其消息体Content中会包含发送者id及":<br/>"消息,这里需要处理一下,去掉多余信息,只保留消息内容
if (m.getString("Content").contains("<br/>")) {
String content = m.getString("Content").substring(m.getString("Content").indexOf("<br/>") + 5);
m.put("Content", content);
m.put("groupMsg", true);
}
} else {
CommonTools.msgFormatter(m, "Content");
}
if (m.getInteger("MsgType").equals(MsgCodeEnum.MSGTYPE_TEXT.getCode())) { // words
// 文本消息
if (m.getString("Url").length() != 0) {
String regEx = "(.+?\\(.+?\\))";
Matcher matcher = CommonTools.getMatcher(regEx, m.getString("Content"));
String data = "Map";
if (matcher.find()) {
data = matcher.group(1);
}
msg.put("Type", "Map");
msg.put("Text", data);
} else {
msg.put("Type", MsgTypeEnum.TEXT.getType());
msg.put("Text", m.getString("Content"));
}
m.put("Type", msg.getString("Type"));
m.put("Text", msg.getString("Text"));
} else if (m.getInteger("MsgType").equals(MsgCodeEnum.MSGTYPE_IMAGE.getCode())
|| m.getInteger("MsgType").equals(MsgCodeEnum.MSGTYPE_EMOTICON.getCode())) { // 图片消息
m.put("Type", MsgTypeEnum.PIC.getType());
} else if (m.getInteger("MsgType").equals(MsgCodeEnum.MSGTYPE_VOICE.getCode())) { // 语音消息
m.put("Type", MsgTypeEnum.VOICE.getType());
} else if (m.getInteger("MsgType").equals(MsgCodeEnum.MSGTYPE_VERIFYMSG.getCode())) {// friends
// 好友确认消息
// MessageTools.addFriend(core, userName, 3, ticket); // 确认添加好友
m.put("Type", MsgTypeEnum.VERIFYMSG.getType());
} else if (m.getInteger("MsgType").equals(MsgCodeEnum.MSGTYPE_SHARECARD.getCode())) { // 共享名片
m.put("Type", MsgTypeEnum.NAMECARD.getType());
} else if (m.getInteger("MsgType").equals(MsgCodeEnum.MSGTYPE_VIDEO.getCode())
|| m.getInteger("MsgType").equals(MsgCodeEnum.MSGTYPE_MICROVIDEO.getCode())) {// viedo
m.put("Type", MsgTypeEnum.VIEDO.getType());
} else if (m.getInteger("MsgType").equals(MsgCodeEnum.MSGTYPE_MEDIA.getCode())) { // 多媒体消息
m.put("Type", MsgTypeEnum.MEDIA.getType());
} else if (m.getInteger("MsgType").equals(MsgCodeEnum.MSGTYPE_STATUSNOTIFY.getCode())) {// phone
// init
// 微信初始化消息
} else if (m.getInteger("MsgType").equals(MsgCodeEnum.MSGTYPE_SYS.getCode())) {// 系统消息
m.put("Type", MsgTypeEnum.SYS.getType());
} else if (m.getInteger("MsgType").equals(MsgCodeEnum.MSGTYPE_RECALLED.getCode())) { // 撤回消息
} else {
LOG.info("Useless msg");
}
LOG.info("收到消息一条,来自: " + m.getString("FromUserName"));
result.add(m);
}
return result;
}
/**
* 消息处理
*
* @author https://github.com/yaphone
* @date 2017年5月14日 上午10:52:34
* @param msgHandler
*/
public static void handleMsg(IMsgHandlerFace msgHandler) {
while (true) {
if (core.getMsgList().size() > 0 && core.getMsgList().get(0).getContent() != null) {
if (core.getMsgList().get(0).getContent().length() > 0) {
BaseMsg msg = core.getMsgList().get(0);
if (msg.getType() != null) {
try {
if (msg.getType().equals(MsgTypeEnum.TEXT.getType())) {
String result = msgHandler.textMsgHandle(msg);
MessageTools.sendMsgById(result, core.getMsgList().get(0).getFromUserName());
} else if (msg.getType().equals(MsgTypeEnum.PIC.getType())) {
String result = msgHandler.picMsgHandle(msg);
MessageTools.sendMsgById(result, core.getMsgList().get(0).getFromUserName());
} else if (msg.getType().equals(MsgTypeEnum.VOICE.getType())) {
String result = msgHandler.voiceMsgHandle(msg);
MessageTools.sendMsgById(result, core.getMsgList().get(0).getFromUserName());
} else if (msg.getType().equals(MsgTypeEnum.VIEDO.getType())) {
String result = msgHandler.viedoMsgHandle(msg);
MessageTools.sendMsgById(result, core.getMsgList().get(0).getFromUserName());
} else if (msg.getType().equals(MsgTypeEnum.NAMECARD.getType())) {
String result = msgHandler.nameCardMsgHandle(msg);
MessageTools.sendMsgById(result, core.getMsgList().get(0).getFromUserName());
} else if (msg.getType().equals(MsgTypeEnum.SYS.getType())) { // 系统消息
msgHandler.sysMsgHandle(msg);
} else if (msg.getType().equals(MsgTypeEnum.VERIFYMSG.getType())) { // 确认添加好友消息
String result = msgHandler.verifyAddFriendMsgHandle(msg);
MessageTools.sendMsgById(result,
core.getMsgList().get(0).getRecommendInfo().getUserName());
} else if (msg.getType().equals(MsgTypeEnum.MEDIA.getType())) { // 多媒体消息
String result = msgHandler.mediaMsgHandle(msg);
MessageTools.sendMsgById(result, core.getMsgList().get(0).getFromUserName());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
core.getMsgList().remove(0);
}
try {
TimeUnit.MILLISECONDS.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

View File

@@ -0,0 +1,91 @@
package com.xmzs.common.wechat.face;
import com.xmzs.common.wechat.beans.BaseMsg;
/**
* 消息处理接口
*
* @author https://github.com/yaphone
* @date 创建时间2017年4月20日 上午12:13:49
* @version 1.0
*
*/
public interface IMsgHandlerFace {
/**
*
* @author https://github.com/yaphone
* @date 2017年4月20日 上午12:15:00
* @param msg
* @return
*/
public String textMsgHandle(BaseMsg msg);
/**
* 处理图片消息
*
* @author https://github.com/yaphone
* @date 2017年4月21日 下午11:07:06
* @param msg
* @return
*/
public String picMsgHandle(BaseMsg msg);
/**
* 处理声音消息
*
* @author https://github.com/yaphone
* @date 2017年4月22日 上午12:09:44
* @param msg
* @return
*/
public String voiceMsgHandle(BaseMsg msg);
/**
* 处理小视频消息
*
* @author https://github.com/yaphone
* @date 2017年4月23日 下午12:19:50
* @param msg
* @return
*/
public String viedoMsgHandle(BaseMsg msg);
/**
* 处理名片消息
*
* @author https://github.com/yaphone
* @date 2017年5月1日 上午12:50:50
* @param msg
* @return
*/
public String nameCardMsgHandle(BaseMsg msg);
/**
* 处理系统消息
*
* @author Relyn
* @date 2017年6月21日17:43:51
* @param msg
* @return
*/
public void sysMsgHandle(BaseMsg msg);
/**
* 处理确认添加好友消息
*
* @date 2017年6月28日 下午10:15:30
* @param msg
* @return
*/
public String verifyAddFriendMsgHandle(BaseMsg msg);
/**
* 处理收到的文件消息
*
* @date 2017年7月21日 下午11:59:14
* @param msg
* @return
*/
public String mediaMsgHandle(BaseMsg msg);
}

View File

@@ -0,0 +1,82 @@
package com.xmzs.common.wechat.service;
/**
* 登陆服务接口
*
* @author https://github.com/yaphone
* @date 创建时间2017年5月13日 上午12:07:21
* @version 1.0
*
*/
public interface ILoginService {
/**
* 登陆
*
* @author https://github.com/yaphone
* @date 2017年5月13日 上午12:14:07
* @return
*/
boolean login();
/**
* 获取UUID
*
* @author https://github.com/yaphone
* @date 2017年5月13日 上午12:21:40
* @param qrPath
* @return
*/
String getUuid();
/**
* 获取二维码图片
*
* @author https://github.com/yaphone
* @date 2017年5月13日 上午12:13:51
* @param qrPath
* @return
*/
boolean getQR(String qrPath);
/**
* web初始化
*
* @author https://github.com/yaphone
* @date 2017年5月13日 上午12:14:13
* @return
*/
boolean webWxInit();
/**
* 微信状态通知
*
* @author https://github.com/yaphone
* @date 2017年5月13日 上午12:14:24
*/
void wxStatusNotify();
/**
* 接收消息
*
* @author https://github.com/yaphone
* @date 2017年5月13日 上午12:14:37
*/
void startReceiving();
/**
* 获取微信联系人
*
* @author https://github.com/yaphone
* @date 2017年5月13日 下午2:26:18
*/
void webWxGetContact();
/**
* 批量获取联系人信息
*
* @date 2017年6月22日 下午11:24:35
*/
void WebWxBatchGetContact();
}

View File

@@ -0,0 +1,38 @@
package com.xmzs.common.wechat.thread;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.xmzs.common.wechat.core.Core;
import com.xmzs.common.wechat.utils.SleepUtils;
/**
* 检查微信在线状态
* <p>
* 如何来感知微信状态?
* 微信会有心跳包LoginServiceImpl.syncCheck()正常在线情况下返回的消息中retcode报文应该为"0"心跳间隔一般在25秒
* 那么可以通过最后收到正常报文的时间来作为判断是否在线的依据。若报文间隔大于60秒则认为已掉线。
* </p>
*
* @author https://github.com/yaphone
* @date 创建时间2017年5月17日 下午10:53:15
* @version 1.0
*
*/
public class CheckLoginStatusThread implements Runnable {
private static Logger LOG = LoggerFactory.getLogger(CheckLoginStatusThread.class);
private Core core = Core.getInstance();
@Override
public void run() {
while (core.isAlive()) {
long t1 = System.currentTimeMillis(); // 秒为单位
if (t1 - core.getLastNormalRetcodeTime() > 60 * 1000) { // 超过60秒判为离线
core.setAlive(false);
LOG.info("微信已离线");
}
SleepUtils.sleep(10 * 1000); // 休眠10秒
}
}
}

View File

@@ -0,0 +1,81 @@
package com.xmzs.common.wechat.utils;
import com.xmzs.common.wechat.utils.enums.OsNameEnum;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
/**
* 配置信息
*
* @author https://github.com/yaphone
* @date 创建时间2017年4月23日 下午2:26:21
* @version 1.0
*
*/
public class Config {
public static final String API_WXAPPID = "API_WXAPPID";
public static final String picDir = "D://itchat4j";
public static final String VERSION = "1.4.1";
public static final String BASE_URL = "https://login.weixin.qq.com";
public static final String REFERER = "https://wx.qq.com/?&lang=zh_CN&target=t";
public static final String OS = "";
public static final String DIR = "";
public static final String DEFAULT_QR = "QR.jpg";
public static final String USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36";
public static final String UOS_PATCH_CLIENT_VERSION = "2.0.0";
public static final String UOS_PATCH_EXTSPAM =
"Go8FCIkFEokFCggwMDAwMDAwMRAGGvAESySibk50w5Wb3uTl2c2h64jVVrV7gNs06GFlWplHQbY/5FfiO++1yH4ykCyNPWKXmco+wfQzK5R98D3so7rJ5LmGFvBLjGceleySrc3SOf2Pc1gVehzJgODeS0lDL3/I/0S2SSE98YgKleq6Uqx6ndTy9yaL9qFxJL7eiA/R3SEfTaW1SBoSITIu+EEkXff+Pv8NHOk7N57rcGk1w0ZzRrQDkXTOXFN2iHYIzAAZPIOY45Lsh+A4slpgnDiaOvRtlQYCt97nmPLuTipOJ8Qc5pM7ZsOsAPPrCQL7nK0I7aPrFDF0q4ziUUKettzW8MrAaiVfmbD1/VkmLNVqqZVvBCtRblXb5FHmtS8FxnqCzYP4WFvz3T0TcrOqwLX1M/DQvcHaGGw0B0y4bZMs7lVScGBFxMj3vbFi2SRKbKhaitxHfYHAOAa0X7/MSS0RNAjdwoyGHeOepXOKY+h3iHeqCvgOH6LOifdHf/1aaZNwSkGotYnYScW8Yx63LnSwba7+hESrtPa/huRmB9KWvMCKbDThL/nne14hnL277EDCSocPu3rOSYjuB9gKSOdVmWsj9Dxb/iZIe+S6AiG29Esm+/eUacSba0k8wn5HhHg9d4tIcixrxveflc8vi2/wNQGVFNsGO6tB5WF0xf/plngOvQ1/ivGV/C1Qpdhzznh0ExAVJ6dwzNg7qIEBaw+BzTJTUuRcPk92Sn6QDn2Pu3mpONaEumacjW4w6ipPnPw+g2TfywJjeEcpSZaP4Q3YV5HG8D6UjWA4GSkBKculWpdCMadx0usMomsSS/74QgpYqcPkmamB4nVv1JxczYITIqItIKjD35IGKAUwAA==";
public static final ArrayList<String> API_SPECIAL_USER = new ArrayList<String>(Arrays.asList("filehelper", "weibo",
"qqmail", "fmessage", "tmessage", "qmessage", "qqsync", "floatbottle", "lbsapp", "shakeapp", "medianote",
"qqfriend", "readerapp", "blogapp", "facebookapp", "masssendapp", "meishiapp", "feedsapp", "voip",
"blogappweixin", "brandsessionholder", "weixin", "weixinreminder", "officialaccounts", "wxitil",
"notification_messages", "wxid_novlwrv3lqwv11", "gh_22b87fa7cb3c", "userexperience_alarm"));
/**
* 获取文件目录
*
* @author https://github.com/yaphone
* @date 2017年4月8日 下午10:27:42
* @return
*/
public static String getLocalPath() {
String localPath = null;
try {
localPath = new File("").getCanonicalPath();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return localPath;
}
/**
* 获取系统平台
*
* @author https://github.com/yaphone
* @date 2017年4月8日 下午10:27:53
*/
public static OsNameEnum getOsNameEnum() {
String os = System.getProperty("os.name").toUpperCase();
if (os.indexOf(OsNameEnum.DARWIN.toString()) >= 0) {
return OsNameEnum.DARWIN;
} else if (os.indexOf(OsNameEnum.WINDOWS.toString()) >= 0) {
return OsNameEnum.WINDOWS;
} else if (os.indexOf(OsNameEnum.LINUX.toString()) >= 0) {
return OsNameEnum.LINUX;
} else if (os.indexOf(OsNameEnum.MAC.toString()) >= 0) {
return OsNameEnum.MAC;
}
return OsNameEnum.OTHER;
}
}

View File

@@ -0,0 +1,34 @@
package com.xmzs.common.wechat.utils;
/**
* 常量
*
* @author https=//github.com/yaphone
* @date 创建时间2017年5月5日 下午11=29=04
* @version 1.0
*
*/
public class ConstantConfigEnum {
public static final int APPMSGTYPE_TEXT = 1;
public static final int APPMSGTYPE_IMG = 2;
public static final int APPMSGTYPE_AUDIO = 3;
public static final int APPMSGTYPE_VIDEO = 4;
public static final int APPMSGTYPE_URL = 5;
public static final int APPMSGTYPE_ATTACH = 6;
public static final int APPMSGTYPE_OPEN = 7;
public static final int APPMSGTYPE_EMOJI = 8;
public static final int APPMSGTYPE_VOICE_REMIND = 9;
public static final int APPMSGTYPE_SCAN_GOOD = 10;
public static final int APPMSGTYPE_GOOD = 13;
public static final int APPMSGTYPE_EMOTION = 15;
public static final int APPMSGTYPE_CARD_TICKET = 16;
public static final int APPMSGTYPE_REALTIME_SHARE_LOCATION = 17;
// public static final int APPMSGTYPE_TRANSFERS = 2e3;
public static final int APPMSGTYPE_RED_ENVELOPES = 2001;
public static final int APPMSGTYPE_READER_TYPE = 100001;
public static final int UPLOAD_MEDIA_TYPE_IMAGE = 1;
public static final int UPLOAD_MEDIA_TYPE_VIDEO = 2;
public static final int UPLOAD_MEDIA_TYPE_AUDIO = 3;
public static final int UPLOAD_MEDIA_TYPE_ATTACHMENT = 4;
}

View File

@@ -0,0 +1,6 @@
package com.xmzs.common.wechat.utils;
public class MsgKeywords {
public static String newFriendStr = "我通过了你的朋友验证请求";
}

View File

@@ -0,0 +1,194 @@
package com.xmzs.common.wechat.utils;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.logging.Logger;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CookieStore;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.cookie.Cookie;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
/**
* HTTP访问类对Apache HttpClient进行简单封装适配器模式
*
* @author https://github.com/yaphone
* @date 创建时间2017年4月9日 下午7:05:04
* @version 1.0
*
*/
public class MyHttpClient {
private Logger logger = Logger.getLogger("MyHttpClient");
private static CloseableHttpClient httpClient = HttpClients.createDefault();
private static MyHttpClient instance = null;
private static CookieStore cookieStore;
static {
cookieStore = new BasicCookieStore();
// 将CookieStore设置到httpClient中
httpClient = HttpClients.custom().setDefaultCookieStore(cookieStore).build();
}
public static String getCookie(String name) {
List<Cookie> cookies = cookieStore.getCookies();
for (Cookie cookie : cookies) {
if (cookie.getName().equalsIgnoreCase(name)) {
return cookie.getValue();
}
}
return null;
}
private MyHttpClient() {
}
/**
* 获取cookies
*
* @author https://github.com/yaphone
* @date 2017年5月7日 下午8:37:17
* @return
*/
public static MyHttpClient getInstance() {
if (instance == null) {
synchronized (MyHttpClient.class) {
if (instance == null) {
instance = new MyHttpClient();
}
}
}
return instance;
}
/**
* 处理GET请求
*
* @author https://github.com/yaphone
* @date 2017年4月9日 下午7:06:19
* @param url
* @param params
* @return
*/
public HttpEntity doGet(String url, List<BasicNameValuePair> params, boolean redirect,
Map<String, String> headerMap) {
HttpEntity entity = null;
HttpGet httpGet = new HttpGet();
try {
if (params != null) {
String paramStr = EntityUtils.toString(new UrlEncodedFormEntity(params, Consts.UTF_8));
httpGet = new HttpGet(url + "?" + paramStr);
} else {
httpGet = new HttpGet(url);
}
if (!redirect) {
httpGet.setConfig(RequestConfig.custom().setRedirectsEnabled(false).build()); // 禁止重定向
}
httpGet.setHeader("User-Agent", Config.USER_AGENT);
httpGet.setHeader("client-version", Config.UOS_PATCH_CLIENT_VERSION);
httpGet.setHeader("extspam", Config.UOS_PATCH_EXTSPAM);
httpGet.setHeader("referer", Config.REFERER);
if (headerMap != null) {
Set<Entry<String, String>> entries = headerMap.entrySet();
for (Entry<String, String> entry : entries) {
httpGet.setHeader(entry.getKey(), entry.getValue());
}
}
CloseableHttpResponse response = httpClient.execute(httpGet);
entity = response.getEntity();
} catch (ClientProtocolException e) {
logger.info(e.getMessage());
} catch (IOException e) {
logger.info(e.getMessage());
}
return entity;
}
/**
* 处理POST请求
*
* @author https://github.com/yaphone
* @date 2017年4月9日 下午7:06:35
* @param url
* @param params
* @return
*/
public HttpEntity doPost(String url, String paramsStr) {
HttpEntity entity = null;
HttpPost httpPost = new HttpPost();
try {
StringEntity params = new StringEntity(paramsStr, Consts.UTF_8);
httpPost = new HttpPost(url);
httpPost.setEntity(params);
httpPost.setHeader("Content-type", "application/json; charset=utf-8");
httpPost.setHeader("User-Agent", Config.USER_AGENT);
httpPost.setHeader("client-version", Config.UOS_PATCH_CLIENT_VERSION);
httpPost.setHeader("extspam", Config.UOS_PATCH_EXTSPAM);
httpPost.setHeader("referer", Config.REFERER);
CloseableHttpResponse response = httpClient.execute(httpPost);
entity = response.getEntity();
} catch (ClientProtocolException e) {
logger.info(e.getMessage());
} catch (IOException e) {
logger.info(e.getMessage());
}
return entity;
}
/**
* 上传文件到服务器
*
* @author https://github.com/yaphone
* @date 2017年5月7日 下午9:19:23
* @param url
* @param reqEntity
* @return
*/
public HttpEntity doPostFile(String url, HttpEntity reqEntity) {
HttpEntity entity = null;
HttpPost httpPost = new HttpPost(url);
httpPost.setHeader("User-Agent", Config.USER_AGENT);
httpPost.setHeader("client-version", Config.UOS_PATCH_CLIENT_VERSION);
httpPost.setHeader("extspam", Config.UOS_PATCH_EXTSPAM);
httpPost.setHeader("referer", Config.REFERER);
httpPost.setEntity(reqEntity);
try {
CloseableHttpResponse response = httpClient.execute(httpPost);
entity = response.getEntity();
} catch (Exception e) {
logger.info(e.getMessage());
}
return entity;
}
public static CloseableHttpClient getHttpClient() {
return httpClient;
}
}

View File

@@ -0,0 +1,20 @@
package com.xmzs.common.wechat.utils;
/**
* Created by xiaoxiaomo on 2017/5/6.
*/
public class SleepUtils {
/**
* 毫秒为单位
* @param time
*/
public static void sleep( long time ){
try {
Thread.sleep( time );
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,68 @@
package com.xmzs.common.wechat.utils.enums;
/**
* 消息类型
*
* @author https://github.com/yaphone
* @date 创建时间2017年4月23日 下午12:15:00
* @version 1.0
*
*/
public enum MsgCodeEnum {
// public static final int MSGTYPE_TEXT = 1; // 文本消息类型
// public static final int MSGTYPE_IMAGE = 3; // 图片消息
// public static final int MSGTYPE_VOICE = 34; // 语音消息
// public static final int MSGTYPE_VIDEO = 43; // 小视频消息
// public static final int MSGTYPE_MICROVIDEO = 62; // 短视频消息
// public static final int MSGTYPE_EMOTICON = 47; // 表情消息
// public static final int MSGTYPE_APP = 49;
// public static final int MSGTYPE_VOIPMSG = 50;
// public static final int MSGTYPE_VOIPNOTIFY = 52;
// public static final int MSGTYPE_VOIPINVITE = 53;
// public static final int MSGTYPE_LOCATION = 48;
// public static final int MSGTYPE_STATUSNOTIFY = 51;
// public static final int MSGTYPE_SYSNOTICE = 9999;
// public static final int MSGTYPE_POSSIBLEFRIEND_MSG = 40;
// public static final int MSGTYPE_VERIFYMSG = 37;
// public static final int MSGTYPE_SHARECARD = 42;
// public static final int MSGTYPE_SYS = 10000;
// public static final int MSGTYPE_RECALLED = 10002;
MSGTYPE_TEXT(1, "文本消息类型"),
MSGTYPE_IMAGE(3, "图片消息"),
MSGTYPE_VOICE(34, "语音消息"),
MSGTYPE_VIDEO(43, "小视频消息"),
MSGTYPE_MICROVIDEO(62, "短视频消息"),
MSGTYPE_EMOTICON(47, "表情消息"),
MSGTYPE_MEDIA(49, "多媒体消息"),
MSGTYPE_VOIPMSG(50, ""),
MSGTYPE_VOIPNOTIFY(52, ""),
MSGTYPE_VOIPINVITE(53, ""),
MSGTYPE_LOCATION(48, ""),
MSGTYPE_STATUSNOTIFY(51, ""),
MSGTYPE_SYSNOTICE(9999, ""),
MSGTYPE_POSSIBLEFRIEND_MSG(40, ""),
MSGTYPE_VERIFYMSG(37, "好友请求"),
MSGTYPE_SHARECARD(42, ""),
MSGTYPE_SYS(10000, "系统消息"),
MSGTYPE_RECALLED(10002, "")
;
private int code;
private String type;
MsgCodeEnum(int code, String type) {
this.code = code;
this.type = type;
}
public int getCode() {
return code;
}
public String getType() {
return type;
}
}

Some files were not shown because too many files have changed in this diff Show More