feat: 微信公众号模块
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
package com.landaiqing.auth.application.controller;
|
package com.landaiqing.auth.application.controller;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.stp.SaTokenInfo;
|
||||||
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import com.landaiqing.auth.application.convert.AuthUserDTOConverter;
|
import com.landaiqing.auth.application.convert.AuthUserDTOConverter;
|
||||||
@@ -9,10 +11,7 @@ import com.landaiqing.auth.domain.entity.AuthUserBO;
|
|||||||
import com.landaiqing.auth.domain.service.AuthUserDomainService;
|
import com.landaiqing.auth.domain.service.AuthUserDomainService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
@@ -118,6 +117,24 @@ public class UserController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequestMapping("doLogin")
|
||||||
|
public Result<SaTokenInfo> doLogin(@RequestParam("validCode") String validCode) {
|
||||||
|
try {
|
||||||
|
Preconditions.checkArgument(!StringUtils.isBlank(validCode), "验证码不能为空!");
|
||||||
|
return Result.ok(authUserDomainService.doLogin(validCode));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("UserController.doLogin.error:{}", e.getMessage(), e);
|
||||||
|
return Result.fail("用户登录失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询登录状态,浏览器访问: http://localhost:8081/user/isLogin
|
||||||
|
@RequestMapping("isLogin")
|
||||||
|
public String isLogin() {
|
||||||
|
return "当前会话是否登录:" + StpUtil.isLogin();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void checkUserInfo(@RequestBody AuthUserDTO authUserDTO) {
|
private void checkUserInfo(@RequestBody AuthUserDTO authUserDTO) {
|
||||||
Preconditions.checkArgument(!StringUtils.isBlank(authUserDTO.getUserName()),"用户名不能为空");
|
Preconditions.checkArgument(!StringUtils.isBlank(authUserDTO.getUserName()),"用户名不能为空");
|
||||||
Preconditions.checkArgument(!StringUtils.isBlank(authUserDTO.getEmail()),"邮箱不能为空");
|
Preconditions.checkArgument(!StringUtils.isBlank(authUserDTO.getEmail()),"邮箱不能为空");
|
||||||
|
|||||||
@@ -22,5 +22,7 @@ public interface AuthUserDomainService {
|
|||||||
Object update(AuthUserBO authUserBO);
|
Object update(AuthUserBO authUserBO);
|
||||||
|
|
||||||
Object delete(AuthUserBO authUserBO);
|
Object delete(AuthUserBO authUserBO);
|
||||||
|
|
||||||
|
Object doLogin(String validCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package com.landaiqing.auth.domain.service.impl;
|
package com.landaiqing.auth.domain.service.impl;
|
||||||
|
|
||||||
import cn.dev33.satoken.secure.SaSecureUtil;
|
import cn.dev33.satoken.secure.SaSecureUtil;
|
||||||
|
import cn.dev33.satoken.stp.SaTokenInfo;
|
||||||
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.landaiqing.auth.common.enums.AuthUserStatusEnum;
|
import com.landaiqing.auth.common.enums.AuthUserStatusEnum;
|
||||||
import com.landaiqing.auth.common.enums.IsDeletedFlagEnum;
|
import com.landaiqing.auth.common.enums.IsDeletedFlagEnum;
|
||||||
@@ -13,6 +15,7 @@ import com.landaiqing.auth.infra.basic.entity.*;
|
|||||||
import com.landaiqing.auth.infra.basic.service.*;
|
import com.landaiqing.auth.infra.basic.service.*;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
@@ -47,12 +50,26 @@ public class AuthUserDomainServiceImpl implements AuthUserDomainService {
|
|||||||
|
|
||||||
private String salt="landaiqing";
|
private String salt="landaiqing";
|
||||||
|
|
||||||
|
private static final String LOGIN_PREFIX = "loginCode";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public Boolean register(AuthUserBO authUserBO) {
|
public Boolean register(AuthUserBO authUserBO) {
|
||||||
|
//校验用户是否存在
|
||||||
|
AuthUser existAuthUser = new AuthUser();
|
||||||
|
existAuthUser.setUserName(authUserBO.getUserName());
|
||||||
|
List<AuthUser> existUser = authUserService.queryByCondition(existAuthUser);
|
||||||
|
if (existUser.size() > 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
AuthUser authUser = AuthUserBOConverter.INSTANCE.convertBOToEntity(authUserBO);
|
AuthUser authUser = AuthUserBOConverter.INSTANCE.convertBOToEntity(authUserBO);
|
||||||
|
if (StringUtils.isNotBlank(authUser.getPassword())) {
|
||||||
authUser.setPassword(SaSecureUtil.md5BySalt(authUser.getPassword(), salt));
|
authUser.setPassword(SaSecureUtil.md5BySalt(authUser.getPassword(), salt));
|
||||||
|
}
|
||||||
|
if (StringUtils.isBlank(authUser.getAvatar())) {
|
||||||
|
authUser.setAvatar("http://117.72.10.84:9000/user/icon/微信图片_20231203153718(1).png");
|
||||||
|
}
|
||||||
authUser.setStatus(AuthUserStatusEnum.OPEN.getCode());
|
authUser.setStatus(AuthUserStatusEnum.OPEN.getCode());
|
||||||
authUser.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());
|
authUser.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());
|
||||||
Integer count = authUserService.insert(authUser);
|
Integer count = authUserService.insert(authUser);
|
||||||
@@ -103,4 +120,19 @@ public class AuthUserDomainServiceImpl implements AuthUserDomainService {
|
|||||||
Integer count = authUserService.update(authUser);
|
Integer count = authUserService.update(authUser);
|
||||||
return count > 0;
|
return count > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SaTokenInfo doLogin(String validCode) {
|
||||||
|
String loginKey = redisUtil.buildKey(LOGIN_PREFIX, validCode);
|
||||||
|
String openId = redisUtil.get(loginKey);
|
||||||
|
if (StringUtils.isBlank(openId)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
AuthUserBO authUserBO = new AuthUserBO();
|
||||||
|
authUserBO.setUserName(openId);
|
||||||
|
this.register(authUserBO);
|
||||||
|
StpUtil.login(openId);
|
||||||
|
SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
|
||||||
|
return tokenInfo;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ spring:
|
|||||||
username: landaiqing
|
username: landaiqing
|
||||||
password: iPHzskWvLGI2TrPw2AV7pu4C8O4bfxSSeQrkIqq0ZwM5tpBmx4aI6xN/8xjYgSmIir5v2Cv35Fn2732AypFKww==
|
password: iPHzskWvLGI2TrPw2AV7pu4C8O4bfxSSeQrkIqq0ZwM5tpBmx4aI6xN/8xjYgSmIir5v2Cv35Fn2732AypFKww==
|
||||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||||
url: jdbc:mysql://116.196.80.239:3306/qing-yu-club?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=true
|
url: jdbc:mysql://116.196.80.239:3306/jc-club?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=true
|
||||||
type: com.alibaba.druid.pool.DruidDataSource
|
type: com.alibaba.druid.pool.DruidDataSource
|
||||||
druid:
|
druid:
|
||||||
initial-size: 20
|
initial-size: 20
|
||||||
|
|||||||
@@ -14,7 +14,14 @@
|
|||||||
<url>http://maven.apache.org</url>
|
<url>http://maven.apache.org</url>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
<maven.compiler.source>8</maven.compiler.source>
|
||||||
|
<maven.compiler.target>8</maven.compiler.target>
|
||||||
|
<java.version>1.8</java.version>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||||
|
<spring-boot.version>2.4.2</spring-boot.version>
|
||||||
|
<spring-cloud-alibaba.version>2021.1</spring-cloud-alibaba.version>
|
||||||
|
<spring-cloud.version>2020.0.6</spring-cloud.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ spring:
|
|||||||
username: landaiqing
|
username: landaiqing
|
||||||
password: iPHzskWvLGI2TrPw2AV7pu4C8O4bfxSSeQrkIqq0ZwM5tpBmx4aI6xN/8xjYgSmIir5v2Cv35Fn2732AypFKww==
|
password: iPHzskWvLGI2TrPw2AV7pu4C8O4bfxSSeQrkIqq0ZwM5tpBmx4aI6xN/8xjYgSmIir5v2Cv35Fn2732AypFKww==
|
||||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||||
url: jdbc:mysql://116.196.80.239:3306/qing-yu-club?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=true
|
url: jdbc:mysql://116.196.80.239:3306/jc-club?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=true
|
||||||
type: com.alibaba.druid.pool.DruidDataSource
|
type: com.alibaba.druid.pool.DruidDataSource
|
||||||
druid:
|
druid:
|
||||||
initial-size: 20
|
initial-size: 20
|
||||||
|
|||||||
123
qing-yu-wechat/pom.xml
Normal file
123
qing-yu-wechat/pom.xml
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
<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/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>com.landaiqing</groupId>
|
||||||
|
<artifactId>qing-yu-wechat</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<name>qing-yu-wechat</name>
|
||||||
|
<url>http://maven.apache.org</url>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>8</maven.compiler.source>
|
||||||
|
<maven.compiler.target>8</maven.compiler.target>
|
||||||
|
<java.version>1.8</java.version>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||||
|
<spring-boot.version>2.4.2</spring-boot.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>spring-boot-starter-logging</artifactId>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<version>1.18.16</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-log4j2</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.thoughtworks.xstream</groupId>
|
||||||
|
<artifactId>xstream</artifactId>
|
||||||
|
<version>1.4.18</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.code.gson</groupId>
|
||||||
|
<artifactId>gson</artifactId>
|
||||||
|
<version>2.8.5</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.dom4j</groupId>
|
||||||
|
<artifactId>dom4j</artifactId>
|
||||||
|
<version>2.1.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-core</artifactId>
|
||||||
|
<version>2.12.7</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-databind</artifactId>
|
||||||
|
<version>2.12.7</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-pool2</artifactId>
|
||||||
|
<version>2.9.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-dependencies</artifactId>
|
||||||
|
<version>${spring-boot.version}</version>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>import</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>central</id>
|
||||||
|
<name>aliyun maven</name>
|
||||||
|
<url>https://maven.aliyun.com/nexus/content/groups/public/</url>
|
||||||
|
<layout>default</layout>
|
||||||
|
<releases>
|
||||||
|
<enabled>true</enabled>
|
||||||
|
</releases>
|
||||||
|
<snapshots>
|
||||||
|
<enabled>true</enabled>
|
||||||
|
</snapshots>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
<build>
|
||||||
|
<finalName>${project.artifactId}</finalName>
|
||||||
|
<!--打包成jar包时的名字-->
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
<version>2.3.0.RELEASE</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>repackage</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package com.landaiqing.wechat;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 微信微服务启动类
|
||||||
|
*
|
||||||
|
* @author: landaiqing
|
||||||
|
* @date: 2024/2/7
|
||||||
|
*/
|
||||||
|
@SpringBootApplication
|
||||||
|
@ComponentScan("com.landaiqing")
|
||||||
|
public class WeChatApplication {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(WeChatApplication.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
package com.landaiqing.wechat.controller;
|
||||||
|
|
||||||
|
import com.landaiqing.wechat.handler.WeChatMsgFactory;
|
||||||
|
import com.landaiqing.wechat.handler.WeChatMsgHandler;
|
||||||
|
import com.landaiqing.wechat.utils.MessageUtil;
|
||||||
|
import com.landaiqing.wechat.utils.SHA1;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Classname CallBackController
|
||||||
|
* @BelongsProject: qing-yu-club
|
||||||
|
* @BelongsPackage: com.landaiqing.wechat.controller
|
||||||
|
* @Author: landaiqing
|
||||||
|
* @CreateTime: 2024-02-21 16:41
|
||||||
|
* @Description: TODO
|
||||||
|
* @Version: 1.0
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@Slf4j
|
||||||
|
public class CallBackController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private WeChatMsgFactory weChatMsgFactory;
|
||||||
|
private static final String token = "LDQ20020618xxx";
|
||||||
|
|
||||||
|
@RequestMapping("/test")
|
||||||
|
public String test() {
|
||||||
|
return "HELLO WORLD";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 回调消息校验
|
||||||
|
* @param: [signature, timestamp, nonce, echostr]
|
||||||
|
* @return: java.lang.String
|
||||||
|
* @author landaiqing
|
||||||
|
* @date: 2024/2/21 17:16
|
||||||
|
*/
|
||||||
|
@GetMapping("/callback")
|
||||||
|
public String callback(@RequestParam("signature") String signature,
|
||||||
|
@RequestParam("timestamp") String timestamp,
|
||||||
|
@RequestParam("nonce") String nonce,
|
||||||
|
@RequestParam("echostr") String echostr) {
|
||||||
|
log.info("get验签请求参数:signature: {},timestamp: {}, nonce: {},echostr: {}",
|
||||||
|
signature, timestamp, nonce, echostr);
|
||||||
|
|
||||||
|
String shaStr = SHA1.getSHA1(token, timestamp, nonce, "");
|
||||||
|
if (signature.equals(shaStr)) {
|
||||||
|
return echostr;
|
||||||
|
}
|
||||||
|
return "unKnown";
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping(value = "callback", produces = "application/xml;charset=UTF-8")
|
||||||
|
public String callback(
|
||||||
|
@RequestBody String requestBody,
|
||||||
|
@RequestParam("signature") String signature,
|
||||||
|
@RequestParam("timestamp") String timestamp,
|
||||||
|
@RequestParam("nonce") String nonce,
|
||||||
|
@RequestParam(value = "msg_signature", required = false) String msgSignature) {
|
||||||
|
log.info("接收到微信消息:requestBody:{}", requestBody);
|
||||||
|
Map<String, String> messageMap = MessageUtil.parseXml(requestBody);
|
||||||
|
String msgType = messageMap.get("MsgType");
|
||||||
|
String event = messageMap.get("Event") == null ? "" : messageMap.get("Event");
|
||||||
|
log.info("msgType:{},event:{}", msgType, event);
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append(msgType);
|
||||||
|
if (!StringUtils.isEmpty(event)) {
|
||||||
|
sb.append(".");
|
||||||
|
sb.append(event);
|
||||||
|
}
|
||||||
|
String msgTypeKey = sb.toString();
|
||||||
|
WeChatMsgHandler weChatMsgHandler = weChatMsgFactory.getHandlerByMsgType(msgTypeKey);
|
||||||
|
if (Objects.isNull(weChatMsgHandler)) {
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
String replyContent = weChatMsgHandler.dealMsg(messageMap);
|
||||||
|
log.info("replyContent:{}", replyContent);
|
||||||
|
return replyContent;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package com.landaiqing.wechat.handler;
|
||||||
|
|
||||||
|
import com.landaiqing.wechat.redis.RedisUtil;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
public class ReceiveTextMsgHandler implements WeChatMsgHandler {
|
||||||
|
|
||||||
|
private static final String KEY_WORD = "验证码";
|
||||||
|
|
||||||
|
private static final String LOGIN_PREFIX = "loginCode";
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private RedisUtil redisUtil;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WeChatMsgTypeEnum getMsgType() {
|
||||||
|
return WeChatMsgTypeEnum.TEXT_MSG;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String dealMsg(Map<String, String> messageMap) {
|
||||||
|
log.info("接收到文本消息事件");
|
||||||
|
String content = messageMap.get("Content");
|
||||||
|
if (!KEY_WORD.equals(content)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
String fromUserName = messageMap.get("FromUserName");
|
||||||
|
String toUserName = messageMap.get("ToUserName");
|
||||||
|
|
||||||
|
Random random = new Random();
|
||||||
|
int num = random.nextInt(1000);
|
||||||
|
String numKey = redisUtil.buildKey(LOGIN_PREFIX, String.valueOf(num));
|
||||||
|
redisUtil.setNx(numKey, fromUserName, 5L, TimeUnit.MINUTES);
|
||||||
|
String numContent = "您当前的验证码是:【" + num + "】 , 5分钟内有效";
|
||||||
|
String replyContent = "<xml>\n" +
|
||||||
|
" <ToUserName><![CDATA[" + fromUserName + "]]></ToUserName>\n" +
|
||||||
|
" <FromUserName><![CDATA[" + toUserName + "]]></FromUserName>\n" +
|
||||||
|
" <CreateTime>12345678</CreateTime>\n" +
|
||||||
|
" <MsgType><![CDATA[text]]></MsgType>\n" +
|
||||||
|
" <Content><![CDATA[" + numContent + "]]></Content>\n" +
|
||||||
|
"</xml>";
|
||||||
|
|
||||||
|
return replyContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.landaiqing.wechat.handler;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
public class SubscribeMsgHandler implements WeChatMsgHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WeChatMsgTypeEnum getMsgType() {
|
||||||
|
return WeChatMsgTypeEnum.SUBSCRIBE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String dealMsg(Map<String, String> messageMap) {
|
||||||
|
log.info("触发用户关注事件!");
|
||||||
|
String fromUserName = messageMap.get("FromUserName");
|
||||||
|
String toUserName = messageMap.get("ToUserName");
|
||||||
|
String subscribeContent = "感谢您的关注,我是清语博客!";
|
||||||
|
String content = "<xml>\n" +
|
||||||
|
" <ToUserName><![CDATA[" + fromUserName + "]]></ToUserName>\n" +
|
||||||
|
" <FromUserName><![CDATA[" + toUserName + "]]></FromUserName>\n" +
|
||||||
|
" <CreateTime>12345678</CreateTime>\n" +
|
||||||
|
" <MsgType><![CDATA[text]]></MsgType>\n" +
|
||||||
|
" <Content><![CDATA[" + subscribeContent + "]]></Content>\n" +
|
||||||
|
"</xml>";
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package com.landaiqing.wechat.handler;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class WeChatMsgFactory implements InitializingBean {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private List<WeChatMsgHandler> weChatMsgHandlerList;
|
||||||
|
|
||||||
|
private Map<WeChatMsgTypeEnum, WeChatMsgHandler> handlerMap = new HashMap<>();
|
||||||
|
|
||||||
|
public WeChatMsgHandler getHandlerByMsgType(String msgType) {
|
||||||
|
WeChatMsgTypeEnum msgTypeEnum = WeChatMsgTypeEnum.getByMsgType(msgType);
|
||||||
|
return handlerMap.get(msgTypeEnum);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterPropertiesSet() throws Exception {
|
||||||
|
for (WeChatMsgHandler weChatMsgHandler : weChatMsgHandlerList) {
|
||||||
|
handlerMap.put(weChatMsgHandler.getMsgType(), weChatMsgHandler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package com.landaiqing.wechat.handler;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public interface WeChatMsgHandler {
|
||||||
|
|
||||||
|
WeChatMsgTypeEnum getMsgType();
|
||||||
|
|
||||||
|
String dealMsg(Map<String, String> messageMap);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package com.landaiqing.wechat.handler;
|
||||||
|
|
||||||
|
public enum WeChatMsgTypeEnum {
|
||||||
|
|
||||||
|
SUBSCRIBE("event.subscribe", "用户关注事件"),
|
||||||
|
TEXT_MSG("text", "接收用户文本消息");
|
||||||
|
|
||||||
|
private String msgType;
|
||||||
|
|
||||||
|
private String desc;
|
||||||
|
|
||||||
|
WeChatMsgTypeEnum(String msgType, String desc) {
|
||||||
|
this.msgType = msgType;
|
||||||
|
this.desc = desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static WeChatMsgTypeEnum getByMsgType(String msgType) {
|
||||||
|
for (WeChatMsgTypeEnum weChatMsgTypeEnum : WeChatMsgTypeEnum.values()) {
|
||||||
|
if (weChatMsgTypeEnum.msgType.equals(msgType)) {
|
||||||
|
return weChatMsgTypeEnum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package com.landaiqing.wechat.redis;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||||
|
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
|
||||||
|
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||||
|
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redis的config处理
|
||||||
|
*
|
||||||
|
* @author: ChickenWing
|
||||||
|
* @date: 2023/10/28
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class RedisConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
|
||||||
|
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
|
||||||
|
RedisSerializer<String> redisSerializer = new StringRedisSerializer();
|
||||||
|
redisTemplate.setConnectionFactory(redisConnectionFactory);
|
||||||
|
redisTemplate.setKeySerializer(redisSerializer);
|
||||||
|
redisTemplate.setHashKeySerializer(redisSerializer);
|
||||||
|
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer());
|
||||||
|
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer());
|
||||||
|
return redisTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer() {
|
||||||
|
Jackson2JsonRedisSerializer<Object> jsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
|
||||||
|
ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
|
||||||
|
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||||
|
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
|
||||||
|
jsonRedisSerializer.setObjectMapper(objectMapper);
|
||||||
|
return jsonRedisSerializer;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
package com.landaiqing.wechat.redis;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RedisUtil工具类
|
||||||
|
*
|
||||||
|
* @author: ChickenWing
|
||||||
|
* @date: 2023/10/28
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
public class RedisUtil {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private RedisTemplate redisTemplate;
|
||||||
|
|
||||||
|
private static final String CACHE_KEY_SEPARATOR = ".";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建缓存key
|
||||||
|
*/
|
||||||
|
public String buildKey(String... strObjs) {
|
||||||
|
return Stream.of(strObjs).collect(Collectors.joining(CACHE_KEY_SEPARATOR));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否存在key
|
||||||
|
*/
|
||||||
|
public boolean exist(String key) {
|
||||||
|
return redisTemplate.hasKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除key
|
||||||
|
*/
|
||||||
|
public boolean del(String key) {
|
||||||
|
return redisTemplate.delete(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set(不带过期)
|
||||||
|
*/
|
||||||
|
public void set(String key, String value) {
|
||||||
|
redisTemplate.opsForValue().set(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set(带过期)
|
||||||
|
*/
|
||||||
|
public boolean setNx(String key, String value, Long time, TimeUnit timeUnit) {
|
||||||
|
return redisTemplate.opsForValue().setIfAbsent(key, value, time, timeUnit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取string类型缓存
|
||||||
|
*/
|
||||||
|
public String get(String key) {
|
||||||
|
return (String) redisTemplate.opsForValue().get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean zAdd(String key, String value, Long score) {
|
||||||
|
return redisTemplate.opsForZSet().add(key, value, Double.valueOf(String.valueOf(score)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long countZset(String key) {
|
||||||
|
return redisTemplate.opsForZSet().size(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<String> rangeZset(String key, long start, long end) {
|
||||||
|
return redisTemplate.opsForZSet().range(key, start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long removeZset(String key, Object value) {
|
||||||
|
return redisTemplate.opsForZSet().remove(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeZsetList(String key, Set<String> value) {
|
||||||
|
value.stream().forEach((val) -> redisTemplate.opsForZSet().remove(key, val));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Double score(String key, Object value) {
|
||||||
|
return redisTemplate.opsForZSet().score(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<String> rangeByScore(String key, long start, long end) {
|
||||||
|
return redisTemplate.opsForZSet().rangeByScore(key, Double.valueOf(String.valueOf(start)), Double.valueOf(String.valueOf(end)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object addScore(String key, Object obj, double score) {
|
||||||
|
return redisTemplate.opsForZSet().incrementScore(key, obj, score);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object rank(String key, Object obj) {
|
||||||
|
return redisTemplate.opsForZSet().rank(key, obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package com.landaiqing.wechat.utils;
|
||||||
|
|
||||||
|
import org.dom4j.Document;
|
||||||
|
import org.dom4j.Element;
|
||||||
|
import org.dom4j.io.SAXReader;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class MessageUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析微信发来的请求(XML).
|
||||||
|
*
|
||||||
|
* @param msg 消息
|
||||||
|
* @return map
|
||||||
|
*/
|
||||||
|
public static Map<String, String> parseXml(final String msg) {
|
||||||
|
// 将解析结果存储在HashMap中
|
||||||
|
Map<String, String> map = new HashMap<String, String>();
|
||||||
|
|
||||||
|
// 从request中取得输入流
|
||||||
|
try (InputStream inputStream = new ByteArrayInputStream(msg.getBytes(StandardCharsets.UTF_8.name()))) {
|
||||||
|
// 读取输入流
|
||||||
|
SAXReader reader = new SAXReader();
|
||||||
|
Document document = reader.read(inputStream);
|
||||||
|
// 得到xml根元素
|
||||||
|
Element root = document.getRootElement();
|
||||||
|
// 得到根元素的所有子节点
|
||||||
|
List<Element> elementList = root.elements();
|
||||||
|
|
||||||
|
// 遍历所有子节点
|
||||||
|
for (Element e : elementList) {
|
||||||
|
map.put(e.getName(), e.getText());
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package com.landaiqing.wechat.utils;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sha1生成签名工具
|
||||||
|
*
|
||||||
|
* @author: landaiqing
|
||||||
|
* @date: 2023/11/5
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class SHA1 {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用SHA1算法生成安全签名
|
||||||
|
*
|
||||||
|
* @param token 票据
|
||||||
|
* @param timestamp 时间戳
|
||||||
|
* @param nonce 随机字符串
|
||||||
|
* @param encrypt 密文
|
||||||
|
* @return 安全签名
|
||||||
|
*/
|
||||||
|
public static String getSHA1(String token, String timestamp, String nonce, String encrypt) {
|
||||||
|
try {
|
||||||
|
String[] array = new String[]{token, timestamp, nonce, encrypt};
|
||||||
|
StringBuffer sb = new StringBuffer();
|
||||||
|
// 字符串排序
|
||||||
|
Arrays.sort(array);
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
sb.append(array[i]);
|
||||||
|
}
|
||||||
|
String str = sb.toString();
|
||||||
|
// SHA1签名生成
|
||||||
|
MessageDigest md = MessageDigest.getInstance("SHA-1");
|
||||||
|
md.update(str.getBytes());
|
||||||
|
byte[] digest = md.digest();
|
||||||
|
|
||||||
|
StringBuffer hexStr = new StringBuffer();
|
||||||
|
String shaHex = "";
|
||||||
|
for (int i = 0; i < digest.length; i++) {
|
||||||
|
shaHex = Integer.toHexString(digest[i] & 0xFF);
|
||||||
|
if (shaHex.length() < 2) {
|
||||||
|
hexStr.append(0);
|
||||||
|
}
|
||||||
|
hexStr.append(shaHex);
|
||||||
|
}
|
||||||
|
return hexStr.toString();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("sha加密生成签名失败:", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
25
qing-yu-wechat/src/main/resources/application.yml
Normal file
25
qing-yu-wechat/src/main/resources/application.yml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
server:
|
||||||
|
port: 3012
|
||||||
|
spring:
|
||||||
|
# redis配置
|
||||||
|
redis:
|
||||||
|
# Redis数据库索引(默认为0)
|
||||||
|
database: 1
|
||||||
|
# Redis服务器地址
|
||||||
|
host: 116.196.80.239
|
||||||
|
# Redis服务器连接端口
|
||||||
|
port: 6379
|
||||||
|
# Redis服务器连接密码(默认为空)
|
||||||
|
password: LDQ20020618xxx
|
||||||
|
# 连接超时时间
|
||||||
|
timeout: 2s
|
||||||
|
lettuce:
|
||||||
|
pool:
|
||||||
|
# 连接池最大连接数
|
||||||
|
max-active: 200
|
||||||
|
# 连接池最大阻塞等待时间(使用负值表示没有限制)
|
||||||
|
max-wait: -1ms
|
||||||
|
# 连接池中的最大空闲连接
|
||||||
|
max-idle: 10
|
||||||
|
# 连接池中的最小空闲连接
|
||||||
|
min-idle: 0
|
||||||
Reference in New Issue
Block a user