集成小程序登录和微信支付
This commit is contained in:
parent
cc85130b76
commit
221947f966
13
pom.xml
13
pom.xml
|
@ -60,6 +60,8 @@
|
|||
<maven-compiler-plugin.verison>3.11.0</maven-compiler-plugin.verison>
|
||||
<maven-surefire-plugin.version>3.1.2</maven-surefire-plugin.version>
|
||||
<flatten-maven-plugin.version>1.3.0</flatten-maven-plugin.version>
|
||||
<!-- 微信支付 -->
|
||||
<weixin-java.version>4.6.0</weixin-java.version>
|
||||
</properties>
|
||||
|
||||
<profiles>
|
||||
|
@ -381,6 +383,17 @@
|
|||
<artifactId>rouyi-scale</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>weixin-java-pay</artifactId>
|
||||
<version>${weixin-java.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>weixin-java-miniapp</artifactId>
|
||||
<version>${weixin-java.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
|
|
|
@ -23,20 +23,20 @@
|
|||
<artifactId>mysql-connector-j</artifactId>
|
||||
</dependency>
|
||||
<!-- Oracle -->
|
||||
<dependency>
|
||||
<groupId>com.oracle.database.jdbc</groupId>
|
||||
<artifactId>ojdbc8</artifactId>
|
||||
</dependency>
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>com.oracle.database.jdbc</groupId>-->
|
||||
<!-- <artifactId>ojdbc8</artifactId>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- PostgreSql -->
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
</dependency>
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.postgresql</groupId>-->
|
||||
<!-- <artifactId>postgresql</artifactId>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- SqlServer -->
|
||||
<dependency>
|
||||
<groupId>com.microsoft.sqlserver</groupId>
|
||||
<artifactId>mssql-jdbc</artifactId>
|
||||
</dependency>
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>com.microsoft.sqlserver</groupId>-->
|
||||
<!-- <artifactId>mssql-jdbc</artifactId>-->
|
||||
<!-- </dependency>-->
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
|
@ -58,6 +58,11 @@
|
|||
<artifactId>ruoyi-common-mail</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-wxlogin</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-system</artifactId>
|
||||
|
@ -90,6 +95,8 @@
|
|||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
<!-- skywalking 整合 logback -->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.apache.skywalking</groupId>-->
|
||||
|
@ -105,7 +112,7 @@
|
|||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
<finalName>mental-tenant-api</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
|
|
|
@ -110,6 +110,39 @@ public class AuthController {
|
|||
return R.ok(loginVo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信登录方法
|
||||
*
|
||||
* @param body 登录信息
|
||||
* @return 结果
|
||||
*/
|
||||
@PostMapping("/wx/login")
|
||||
public R<LoginVo> wxLogin(@RequestBody String body) {
|
||||
LoginBody loginBody = JsonUtils.parseObject(body, LoginBody.class);
|
||||
ValidatorUtils.validate(loginBody);
|
||||
// 授权类型和客户端id
|
||||
String clientId = loginBody.getClientId();
|
||||
String grantType = loginBody.getGrantType();
|
||||
SysClientVo client = clientService.queryByClientId(clientId);
|
||||
// 查询不到 client 或 client 内不包含 grantType
|
||||
if (ObjectUtil.isNull(client) || !StringUtils.contains(client.getGrantType(), grantType)) {
|
||||
log.info("客户端id: {} 认证类型:{} 异常!.", clientId, grantType);
|
||||
return R.fail(MessageUtils.message("auth.grant.type.error"));
|
||||
} else if (!UserConstants.NORMAL.equals(client.getStatus())) {
|
||||
return R.fail(MessageUtils.message("auth.grant.type.blocked"));
|
||||
}
|
||||
// 校验租户
|
||||
if (StringUtils.isEmpty(loginBody.getTenantId())) {
|
||||
//没有则默认注册在主租户下;
|
||||
loginBody.setTenantId("000000");
|
||||
} else {
|
||||
loginService.checkTenant(loginBody.getTenantId());
|
||||
}
|
||||
// 登录
|
||||
LoginVo loginVo = IAuthStrategy.login(body, client, grantType);
|
||||
return R.ok(loginVo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 第三方登录请求
|
||||
*
|
||||
|
@ -142,8 +175,8 @@ public class AuthController {
|
|||
public R<Void> socialCallback(@RequestBody SocialLoginBody loginBody) {
|
||||
// 获取第三方登录信息
|
||||
AuthResponse<AuthUser> response = SocialUtils.loginAuth(
|
||||
loginBody.getSource(), loginBody.getSocialCode(),
|
||||
loginBody.getSocialState(), socialProperties);
|
||||
loginBody.getSource(), loginBody.getSocialCode(),
|
||||
loginBody.getSocialState(), socialProperties);
|
||||
AuthUser authUserData = response.getData();
|
||||
// 判断授权响应是否成功
|
||||
if (!response.ok()) {
|
||||
|
@ -226,7 +259,7 @@ public class AuthController {
|
|||
}
|
||||
// 根据域名进行筛选
|
||||
List<TenantListVo> list = StreamUtils.filter(voList, vo ->
|
||||
StringUtils.equals(vo.getDomain(), host));
|
||||
StringUtils.equals(vo.getDomain(), host));
|
||||
result.setVoList(CollUtil.isNotEmpty(list) ? list : voList);
|
||||
return R.ok(result);
|
||||
}
|
||||
|
|
|
@ -1,22 +1,29 @@
|
|||
package org.dromara.web.service.impl;
|
||||
|
||||
import cn.binarywang.wx.miniapp.api.WxMaService;
|
||||
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
|
||||
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
|
||||
import cn.binarywang.wx.miniapp.util.WxMaConfigHolder;
|
||||
import cn.dev33.satoken.secure.BCrypt;
|
||||
import cn.dev33.satoken.stp.SaLoginModel;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import org.dromara.common.core.domain.model.XcxLoginBody;
|
||||
import org.dromara.common.core.domain.model.XcxLoginUser;
|
||||
import org.dromara.common.core.enums.UserStatus;
|
||||
import org.dromara.common.core.exception.user.UserException;
|
||||
import org.dromara.common.core.utils.ValidatorUtils;
|
||||
import org.dromara.common.json.utils.JsonUtils;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.system.domain.SysClient;
|
||||
import org.dromara.common.tenant.helper.TenantHelper;
|
||||
import org.dromara.system.domain.SysUser;
|
||||
import org.dromara.system.domain.vo.SysClientVo;
|
||||
import org.dromara.system.domain.vo.SysUserVo;
|
||||
import org.dromara.system.mapper.SysUserMapper;
|
||||
import org.dromara.web.domain.vo.LoginVo;
|
||||
import org.dromara.web.service.IAuthStrategy;
|
||||
import org.dromara.web.service.SysLoginService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
|
@ -29,22 +36,39 @@ import org.springframework.stereotype.Service;
|
|||
@RequiredArgsConstructor
|
||||
public class XcxAuthStrategy implements IAuthStrategy {
|
||||
|
||||
private final SysLoginService loginService;
|
||||
//private final SysLoginService loginService;
|
||||
|
||||
private final WxMaService wxMaService;
|
||||
|
||||
private final SysUserMapper userMapper;
|
||||
|
||||
@Override
|
||||
public LoginVo login(String body, SysClientVo client) {
|
||||
XcxLoginBody loginBody = JsonUtils.parseObject(body, XcxLoginBody.class);
|
||||
ValidatorUtils.validate(loginBody);
|
||||
// xcxCode 为 小程序调用 wx.login 授权后获取
|
||||
String xcxCode = loginBody.getXcxCode();
|
||||
// 多个小程序识别使用
|
||||
String appid = loginBody.getAppid();
|
||||
|
||||
// todo 以下自行实现
|
||||
// 校验 appid + appsrcret + xcxCode 调用登录凭证校验接口 获取 session_key 与 openid
|
||||
String openid = "";
|
||||
String tenantId = loginBody.getTenantId();
|
||||
// code 为 小程序调用 wx.login 授权后获取
|
||||
String code = loginBody.getCode();
|
||||
String encryptedData = loginBody.getEncryptedData();
|
||||
String iv = loginBody.getIv();
|
||||
String openid;
|
||||
String phoneNumber;
|
||||
try {
|
||||
WxMaJscode2SessionResult session = wxMaService.getUserService().getSessionInfo(code);
|
||||
String sessionKey = session.getSessionKey();
|
||||
openid = session.getOpenid();
|
||||
WxMaPhoneNumberInfo phoneNoInfo = wxMaService.getUserService().getPhoneNoInfo(sessionKey, encryptedData, iv);
|
||||
phoneNumber = phoneNoInfo.getPhoneNumber();
|
||||
} catch (WxErrorException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return new LoginVo();
|
||||
} finally {
|
||||
WxMaConfigHolder.remove();//清理ThreadLocal
|
||||
}
|
||||
// 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
|
||||
SysUserVo user = loadUserByOpenid(openid);
|
||||
SysUser user = loadUserByOpenidAndPhoneNumber(openid, phoneNumber, tenantId);
|
||||
|
||||
// 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
|
||||
XcxLoginUser loginUser = new XcxLoginUser();
|
||||
|
@ -75,18 +99,30 @@ public class XcxAuthStrategy implements IAuthStrategy {
|
|||
return loginVo;
|
||||
}
|
||||
|
||||
private SysUserVo loadUserByOpenid(String openid) {
|
||||
private SysUser loadUserByOpenidAndPhoneNumber(String openid, String phoneNumber, String tenantId) {
|
||||
// 使用 openid 查询绑定用户 如未绑定用户 则根据业务自行处理 例如 创建默认用户
|
||||
// todo 自行实现 userService.selectUserByOpenid(openid);
|
||||
SysUserVo user = new SysUserVo();
|
||||
if (ObjectUtil.isNull(user)) {
|
||||
log.info("登录用户:{} 不存在.", openid);
|
||||
// todo 用户不存在 业务逻辑自行实现
|
||||
} else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
|
||||
log.info("登录用户:{} 已被停用.", openid);
|
||||
// todo 用户已被停用 业务逻辑自行实现
|
||||
}
|
||||
return user;
|
||||
return TenantHelper.ignore(() -> {
|
||||
SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUserName, phoneNumber));
|
||||
if (ObjectUtil.isNull(user)) {
|
||||
//newUser.setDeptId(100L);
|
||||
SysUser newUser = new SysUser();
|
||||
newUser.setPassword(BCrypt.hashpw("123456"));
|
||||
newUser.setTenantId(tenantId);
|
||||
newUser.setUserName(phoneNumber);
|
||||
newUser.setNickName("健康土豆");
|
||||
newUser.setPhonenumber(phoneNumber);
|
||||
newUser.setOpenId(openid);
|
||||
newUser.setUserType("sys_user");
|
||||
userMapper.insert(newUser);
|
||||
return newUser;
|
||||
} else {
|
||||
if (user.getOpenId().equals(openid)) {
|
||||
return user;
|
||||
} else {
|
||||
throw new UserException("此用户已被其他微信号绑定", phoneNumber);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -256,3 +256,19 @@ justauth:
|
|||
client-id: 10**********6
|
||||
client-secret: 1f7d08**********5b7**********29e
|
||||
redirect-uri: ${justauth.address}/social-callback?source=gitlab
|
||||
|
||||
wx:
|
||||
pay:
|
||||
appId: wx2e09db4124332242
|
||||
mchId: #微信支付商户号
|
||||
mchKey: #微信支付商户密钥
|
||||
subAppId: #服务商模式下的子商户公众账号ID
|
||||
subMchId: #服务商模式下的子商户号
|
||||
keyPath: # p12证书的位置,可以指定绝对路径,也可以指定类路径(以classpath:开头)
|
||||
miniapp:
|
||||
configs:
|
||||
- appid: wx2e09db4124332242
|
||||
secret: #微信小程序的Secret
|
||||
token: #微信小程序消息服务器配置的token
|
||||
aesKey: #微信小程序消息服务器配置的EncodingAESKey
|
||||
msgDataFormat: JSON
|
||||
|
|
|
@ -56,24 +56,24 @@ spring:
|
|||
url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
|
||||
username:
|
||||
password:
|
||||
# oracle:
|
||||
# type: ${spring.datasource.type}
|
||||
# driverClassName: oracle.jdbc.OracleDriver
|
||||
# url: jdbc:oracle:thin:@//localhost:1521/XE
|
||||
# username: ROOT
|
||||
# password: root
|
||||
# postgres:
|
||||
# type: ${spring.datasource.type}
|
||||
# driverClassName: org.postgresql.Driver
|
||||
# url: jdbc:postgresql://localhost:5432/postgres?useUnicode=true&characterEncoding=utf8&useSSL=true&autoReconnect=true&reWriteBatchedInserts=true
|
||||
# username: root
|
||||
# password: root
|
||||
# sqlserver:
|
||||
# type: ${spring.datasource.type}
|
||||
# driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
|
||||
# url: jdbc:sqlserver://localhost:1433;DatabaseName=tempdb;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true
|
||||
# username: SA
|
||||
# password: root
|
||||
# oracle:
|
||||
# type: ${spring.datasource.type}
|
||||
# driverClassName: oracle.jdbc.OracleDriver
|
||||
# url: jdbc:oracle:thin:@//localhost:1521/XE
|
||||
# username: ROOT
|
||||
# password: root
|
||||
# postgres:
|
||||
# type: ${spring.datasource.type}
|
||||
# driverClassName: org.postgresql.Driver
|
||||
# url: jdbc:postgresql://localhost:5432/postgres?useUnicode=true&characterEncoding=utf8&useSSL=true&autoReconnect=true&reWriteBatchedInserts=true
|
||||
# username: root
|
||||
# password: root
|
||||
# sqlserver:
|
||||
# type: ${spring.datasource.type}
|
||||
# driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
|
||||
# url: jdbc:sqlserver://localhost:1433;DatabaseName=tempdb;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true
|
||||
# username: SA
|
||||
# password: root
|
||||
hikari:
|
||||
# 最大连接池数量
|
||||
maxPoolSize: 20
|
||||
|
@ -258,3 +258,19 @@ justauth:
|
|||
client-id: 10**********6
|
||||
client-secret: 1f7d08**********5b7**********29e
|
||||
redirect-uri: ${justauth.address}/social-callback?source=gitlab
|
||||
|
||||
wx:
|
||||
pay:
|
||||
appId: #微信公众号或者小程序等的appid
|
||||
mchId: #微信支付商户号
|
||||
mchKey: #微信支付商户密钥
|
||||
subAppId: #服务商模式下的子商户公众账号ID
|
||||
subMchId: #服务商模式下的子商户号
|
||||
keyPath: # p12证书的位置,可以指定绝对路径,也可以指定类路径(以classpath:开头)
|
||||
miniapp:
|
||||
configs:
|
||||
- appid: #微信小程序的appid
|
||||
secret: #微信小程序的Secret
|
||||
token: #微信小程序消息服务器配置的token
|
||||
aesKey: #微信小程序消息服务器配置的EncodingAESKey
|
||||
msgDataFormat: JSON
|
||||
|
|
|
@ -256,3 +256,19 @@ justauth:
|
|||
client-id: 10**********6
|
||||
client-secret: 1f7d08**********5b7**********29e
|
||||
redirect-uri: ${justauth.address}/social-callback?source=gitlab
|
||||
|
||||
wx:
|
||||
pay:
|
||||
appId: #微信公众号或者小程序等的appid
|
||||
mchId: #微信支付商户号
|
||||
mchKey: #微信支付商户密钥
|
||||
subAppId: #服务商模式下的子商户公众账号ID
|
||||
subMchId: #服务商模式下的子商户号
|
||||
keyPath: # p12证书的位置,可以指定绝对路径,也可以指定类路径(以classpath:开头)
|
||||
miniapp:
|
||||
configs:
|
||||
- appid: #微信小程序的appid
|
||||
secret: #微信小程序的Secret
|
||||
token: #微信小程序消息服务器配置的token
|
||||
aesKey: #微信小程序消息服务器配置的EncodingAESKey
|
||||
msgDataFormat: JSON
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
<module>ruoyi-common-encrypt</module>
|
||||
<module>ruoyi-common-tenant</module>
|
||||
<module>ruoyi-common-websocket</module>
|
||||
<module>ruoyi-common-wxpay</module>
|
||||
<module>ruoyi-common-wxlogin</module>
|
||||
</modules>
|
||||
|
||||
<artifactId>ruoyi-common</artifactId>
|
||||
|
|
|
@ -172,6 +172,18 @@
|
|||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 微信支付模块 -->
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-wxpay</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<!-- 微信登录模块 -->
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-wxlogin</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
|
|
|
@ -23,6 +23,12 @@ public class XcxLoginBody extends LoginBody {
|
|||
* 小程序code
|
||||
*/
|
||||
@NotBlank(message = "{xcx.code.not.blank}")
|
||||
private String xcxCode;
|
||||
private String code;
|
||||
|
||||
@NotBlank(message = "小程序[encryptedData]不能为空")
|
||||
private String encryptedData;
|
||||
|
||||
@NotBlank(message = "小程序[iv]不能为空")
|
||||
private String iv;
|
||||
|
||||
}
|
||||
|
|
|
@ -190,5 +190,4 @@ public class TenantHelper {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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">
|
||||
<parent>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>ruoyi-common-wxlogin</artifactId>
|
||||
|
||||
<description>
|
||||
ruoyi-common-wxlogin 小程序登录功能
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
<!-- RuoYi Common Core-->
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>weixin-java-miniapp</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,135 @@
|
|||
package org.dromara.common.wxlogin.config;
|
||||
|
||||
import cn.binarywang.wx.miniapp.api.WxMaService;
|
||||
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
|
||||
import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage;
|
||||
import cn.binarywang.wx.miniapp.bean.WxMaSubscribeMessage;
|
||||
import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
|
||||
import cn.binarywang.wx.miniapp.message.WxMaMessageHandler;
|
||||
import cn.binarywang.wx.miniapp.message.WxMaMessageRouter;
|
||||
import com.google.common.collect.Lists;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.common.error.WxRuntimeException;
|
||||
import org.dromara.common.wxlogin.config.properties.WxMaProperties;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(WxMaProperties.class)
|
||||
public class WxMaConfiguration {
|
||||
private final WxMaProperties properties;
|
||||
|
||||
@Autowired
|
||||
public WxMaConfiguration(WxMaProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Lazy
|
||||
@Bean
|
||||
public WxMaService wxMaService() {
|
||||
List<WxMaProperties.Config> configs = this.properties.getConfigs();
|
||||
if (configs == null) {
|
||||
throw new WxRuntimeException("大哥,拜托先看下项目首页的说明(readme文件),添加下相关配置,注意别配错了!");
|
||||
}
|
||||
WxMaService maService = new WxMaServiceImpl();
|
||||
maService.setMultiConfigs(
|
||||
configs.stream()
|
||||
.map(a -> {
|
||||
WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl();
|
||||
// WxMaDefaultConfigImpl config = new WxMaRedisConfigImpl(new JedisPool());
|
||||
// 使用上面的配置时,需要同时引入jedis-lock的依赖,否则会报类无法找到的异常
|
||||
config.setAppid(a.getAppid());
|
||||
config.setSecret(a.getSecret());
|
||||
config.setToken(a.getToken());
|
||||
config.setAesKey(a.getAesKey());
|
||||
config.setMsgDataFormat(a.getMsgDataFormat());
|
||||
return config;
|
||||
}).collect(Collectors.toMap(WxMaDefaultConfigImpl::getAppid, a -> a, (o, n) -> o)));
|
||||
return maService;
|
||||
}
|
||||
|
||||
@Lazy
|
||||
@Bean
|
||||
public WxMaMessageRouter wxMaMessageRouter(WxMaService wxMaService) {
|
||||
final WxMaMessageRouter router = new WxMaMessageRouter(wxMaService);
|
||||
router
|
||||
.rule().handler(logHandler).next()
|
||||
.rule().async(false).content("订阅消息").handler(subscribeMsgHandler).end()
|
||||
.rule().async(false).content("文本").handler(textHandler).end()
|
||||
.rule().async(false).content("图片").handler(picHandler).end()
|
||||
.rule().async(false).content("二维码").handler(qrcodeHandler).end();
|
||||
return router;
|
||||
}
|
||||
|
||||
private final WxMaMessageHandler subscribeMsgHandler = (wxMessage, context, service, sessionManager) -> {
|
||||
service.getMsgService().sendSubscribeMsg(WxMaSubscribeMessage.builder()
|
||||
.templateId("此处更换为自己的模板id")
|
||||
.data(Lists.newArrayList(
|
||||
new WxMaSubscribeMessage.MsgData("keyword1", "339208499")))
|
||||
.toUser(wxMessage.getFromUser())
|
||||
.build());
|
||||
return null;
|
||||
};
|
||||
|
||||
private final WxMaMessageHandler logHandler = (wxMessage, context, service, sessionManager) -> {
|
||||
log.info("收到消息:" + wxMessage.toString());
|
||||
service.getMsgService().sendKefuMsg(WxMaKefuMessage.newTextBuilder().content("收到信息为:" + wxMessage.toJson())
|
||||
.toUser(wxMessage.getFromUser()).build());
|
||||
return null;
|
||||
};
|
||||
|
||||
private final WxMaMessageHandler textHandler = (wxMessage, context, service, sessionManager) -> {
|
||||
service.getMsgService().sendKefuMsg(WxMaKefuMessage.newTextBuilder().content("回复文本消息")
|
||||
.toUser(wxMessage.getFromUser()).build());
|
||||
return null;
|
||||
};
|
||||
|
||||
private final WxMaMessageHandler picHandler = (wxMessage, context, service, sessionManager) -> {
|
||||
try {
|
||||
WxMediaUploadResult uploadResult = service.getMediaService()
|
||||
.uploadMedia("image", "png",
|
||||
ClassLoader.getSystemResourceAsStream("tmp.png"));
|
||||
service.getMsgService().sendKefuMsg(
|
||||
WxMaKefuMessage
|
||||
.newImageBuilder()
|
||||
.mediaId(uploadResult.getMediaId())
|
||||
.toUser(wxMessage.getFromUser())
|
||||
.build());
|
||||
} catch (WxErrorException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
private final WxMaMessageHandler qrcodeHandler = (wxMessage, context, service, sessionManager) -> {
|
||||
try {
|
||||
final File file = service.getQrcodeService().createQrcode("123", 430);
|
||||
WxMediaUploadResult uploadResult = service.getMediaService().uploadMedia("image", file);
|
||||
service.getMsgService().sendKefuMsg(
|
||||
WxMaKefuMessage
|
||||
.newImageBuilder()
|
||||
.mediaId(uploadResult.getMediaId())
|
||||
.toUser(wxMessage.getFromUser())
|
||||
.build());
|
||||
} catch (WxErrorException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package org.dromara.common.wxlogin.config.properties;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
@Data
|
||||
@ConfigurationProperties(prefix = "wx.miniapp")
|
||||
public class WxMaProperties {
|
||||
|
||||
private List<Config> configs;
|
||||
|
||||
@Data
|
||||
public static class Config {
|
||||
/**
|
||||
* 设置微信小程序的appid
|
||||
*/
|
||||
private String appid;
|
||||
|
||||
/**
|
||||
* 设置微信小程序的Secret
|
||||
*/
|
||||
private String secret;
|
||||
|
||||
/**
|
||||
* 设置微信小程序消息服务器配置的token
|
||||
*/
|
||||
private String token;
|
||||
|
||||
/**
|
||||
* 设置微信小程序消息服务器配置的EncodingAESKey
|
||||
*/
|
||||
private String aesKey;
|
||||
|
||||
/**
|
||||
* 消息格式,XML或者JSON
|
||||
*/
|
||||
private String msgDataFormat;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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">
|
||||
<parent>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>ruoyi-common-wxpay</artifactId>
|
||||
|
||||
<description>
|
||||
ruoyi-common-pay 支付功能
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
<!-- RuoYi Common Core-->
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>weixin-java-pay</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,45 @@
|
|||
package org.dromara.common.wxpay.config;
|
||||
|
||||
import com.github.binarywang.wxpay.config.WxPayConfig;
|
||||
import com.github.binarywang.wxpay.service.WxPayService;
|
||||
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dromara.common.wxpay.config.properties.WxPayProperties;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
|
||||
/**
|
||||
* @author Binary Wang
|
||||
*/
|
||||
//@Configuration
|
||||
@ConditionalOnClass(WxPayService.class)
|
||||
@EnableConfigurationProperties(WxPayProperties.class)
|
||||
@AllArgsConstructor
|
||||
public class WxPayConfiguration {
|
||||
private WxPayProperties properties;
|
||||
|
||||
@Lazy
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public WxPayService wxService() {
|
||||
WxPayConfig payConfig = new WxPayConfig();
|
||||
payConfig.setAppId(StringUtils.trimToNull(this.properties.getAppId()));
|
||||
payConfig.setMchId(StringUtils.trimToNull(this.properties.getMchId()));
|
||||
payConfig.setMchKey(StringUtils.trimToNull(this.properties.getMchKey()));
|
||||
payConfig.setSubAppId(StringUtils.trimToNull(this.properties.getSubAppId()));
|
||||
payConfig.setSubMchId(StringUtils.trimToNull(this.properties.getSubMchId()));
|
||||
payConfig.setKeyPath(StringUtils.trimToNull(this.properties.getKeyPath()));
|
||||
|
||||
// 可以指定是否使用沙箱环境
|
||||
payConfig.setUseSandboxEnv(false);
|
||||
|
||||
WxPayService wxPayService = new WxPayServiceImpl();
|
||||
wxPayService.setConfig(payConfig);
|
||||
return wxPayService;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package org.dromara.common.wxpay.config.properties;
|
||||
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* wxpay pay properties.
|
||||
*
|
||||
* @author Binary Wang
|
||||
*/
|
||||
@Data
|
||||
@ConfigurationProperties(prefix = "wx.pay")
|
||||
public class WxPayProperties {
|
||||
/**
|
||||
* 设置微信公众号或者小程序等的appid
|
||||
*/
|
||||
private String appId;
|
||||
|
||||
/**
|
||||
* 微信支付商户号
|
||||
*/
|
||||
private String mchId;
|
||||
|
||||
/**
|
||||
* 微信支付商户密钥
|
||||
*/
|
||||
private String mchKey;
|
||||
|
||||
/**
|
||||
* 服务商模式下的子商户公众账号ID,普通模式请不要配置,请在配置文件中将对应项删除
|
||||
*/
|
||||
private String subAppId;
|
||||
|
||||
/**
|
||||
* 服务商模式下的子商户号,普通模式请不要配置,最好是请在配置文件中将对应项删除
|
||||
*/
|
||||
private String subMchId;
|
||||
|
||||
/**
|
||||
* apiclient_cert.p12文件的绝对路径,或者如果放在项目中,请以classpath:开头指定
|
||||
*/
|
||||
private String keyPath;
|
||||
|
||||
}
|
|
@ -84,6 +84,11 @@
|
|||
<artifactId>ruoyi-common-websocket</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-wxpay</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.deepoove</groupId>
|
||||
<artifactId>poi-tl</artifactId>
|
||||
|
|
|
@ -10,7 +10,6 @@ import org.dromara.common.log.enums.BusinessType;
|
|||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.scale.domain.bo.SubmitAnswerBo;
|
||||
import org.dromara.scale.domain.vo.QuestionAnswerVo;
|
||||
import org.dromara.scale.domain.vo.SysScalePublishVo;
|
||||
import org.dromara.scale.domain.vo.SysScaleVo;
|
||||
import org.dromara.scale.service.IWebService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
@ -29,7 +28,7 @@ import java.util.Map;
|
|||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/web/scale")
|
||||
@RequestMapping("/wx")
|
||||
public class WebController extends BaseController {
|
||||
|
||||
private final IWebService webService;
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
package org.dromara.scale.controller.wx;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* <p>TODO<p>
|
||||
*
|
||||
* @author cjw
|
||||
* @version V1.0.0
|
||||
* @date 2024/7/29 14:08
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/wx/pay")
|
||||
public class WxPayController {
|
||||
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package org.dromara.scale.controller.wx;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.scale.domain.bo.SysScaleBo;
|
||||
import org.dromara.scale.domain.vo.SysScaleVo;
|
||||
import org.dromara.scale.service.ISysScaleService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* <p>TODO<p>
|
||||
*
|
||||
* @author cjw
|
||||
* @version V1.0.0
|
||||
* @date 2024/7/29 10:01
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/wx/scale")
|
||||
public class WxScaleController extends BaseController {
|
||||
|
||||
private final ISysScaleService sysScaleService;
|
||||
|
||||
/**
|
||||
* 查询心理测评量列表
|
||||
*/
|
||||
@GetMapping("/pageList")
|
||||
public TableDataInfo<SysScaleVo> list(SysScaleBo bo, PageQuery pageQuery) {
|
||||
return sysScaleService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
/**
|
||||
* 获取心理测评量详细信息
|
||||
*
|
||||
* @param scaleId 主键
|
||||
*/
|
||||
@GetMapping("/{scaleId}")
|
||||
public R<SysScaleVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long scaleId) {
|
||||
//todo
|
||||
return R.ok(sysScaleService.queryById(scaleId));
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ import org.dromara.common.mybatis.core.domain.BaseEntity;
|
|||
import org.dromara.scale.domain.vo.SysScaleVo;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 心理测评量对象 sys_scale
|
||||
|
@ -110,4 +111,8 @@ public class SysScale extends BaseEntity {
|
|||
*/
|
||||
private String scaleTime;
|
||||
|
||||
private Integer freeFlag;
|
||||
|
||||
private BigDecimal price;
|
||||
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import org.dromara.common.core.validate.EditGroup;
|
|||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import org.dromara.scale.domain.SysScale;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
@ -116,4 +117,9 @@ public class SysScaleBo extends BaseEntity {
|
|||
*/
|
||||
@NotBlank(message = "测评时长不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private String scaleTime;
|
||||
|
||||
@NotNull(message = "价格类型不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private Integer freeFlag;
|
||||
|
||||
private BigDecimal price;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import lombok.Data;
|
|||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
|
@ -118,4 +119,8 @@ public class SysScaleVo implements Serializable {
|
|||
|
||||
private Long recordId;
|
||||
|
||||
private Integer freeFlag;
|
||||
|
||||
private BigDecimal price;
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package org.dromara.scale.starter;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.redis.utils.QueueUtils;
|
||||
import org.dromara.scale.constant.StatusEnum;
|
||||
import org.dromara.scale.domain.SysScalePublish;
|
||||
|
@ -16,6 +17,7 @@ import org.springframework.stereotype.Component;
|
|||
* @version V1.0.0
|
||||
* @date 2024/4/15 15:08
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
@Order(value = 99)
|
||||
|
@ -29,6 +31,7 @@ public class ApplicationStarter implements CommandLineRunner {
|
|||
}
|
||||
|
||||
private void subscribeRedisDelayedQueue(){
|
||||
log.info("=======================延迟队列回调开始===============");
|
||||
// 项目初始化设置一次即可
|
||||
QueueUtils.subscribeBlockingQueue("endPublish-delay-queue", (Long batchNo) -> {
|
||||
SysScalePublish publish = new SysScalePublish();
|
||||
|
|
|
@ -42,6 +42,8 @@ public class SysUser extends TenantEntity {
|
|||
*/
|
||||
private String nickName;
|
||||
|
||||
private String openId;
|
||||
|
||||
/**
|
||||
* 用户类型(sys_user系统用户)
|
||||
*/
|
||||
|
|
|
@ -48,6 +48,8 @@ public class SysUserVo implements Serializable {
|
|||
*/
|
||||
private String userName;
|
||||
|
||||
private String openId;
|
||||
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue