diff --git a/pom.xml b/pom.xml index 2a0f1ff..c3e4885 100644 --- a/pom.xml +++ b/pom.xml @@ -60,6 +60,8 @@ 3.11.0 3.1.2 1.3.0 + + 4.6.0 @@ -381,6 +383,17 @@ rouyi-scale ${revision} + + + com.github.binarywang + weixin-java-pay + ${weixin-java.version} + + + com.github.binarywang + weixin-java-miniapp + ${weixin-java.version} + diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml index 661648d..08d646e 100644 --- a/ruoyi-admin/pom.xml +++ b/ruoyi-admin/pom.xml @@ -23,20 +23,20 @@ mysql-connector-j - - com.oracle.database.jdbc - ojdbc8 - + + + + - - org.postgresql - postgresql - + + + + - - com.microsoft.sqlserver - mssql-jdbc - + + + + org.dromara @@ -58,6 +58,11 @@ ruoyi-common-mail + + org.dromara + ruoyi-common-wxlogin + + org.dromara ruoyi-system @@ -90,6 +95,8 @@ test + + @@ -105,7 +112,7 @@ - ${project.artifactId} + mental-tenant-api org.springframework.boot diff --git a/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java b/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java index 1db68f1..06ff167 100644 --- a/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java +++ b/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java @@ -110,6 +110,39 @@ public class AuthController { return R.ok(loginVo); } + /** + * 微信登录方法 + * + * @param body 登录信息 + * @return 结果 + */ + @PostMapping("/wx/login") + public R 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 socialCallback(@RequestBody SocialLoginBody loginBody) { // 获取第三方登录信息 AuthResponse 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 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); } diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/XcxAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/XcxAuthStrategy.java index aa8be73..453bf88 100644 --- a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/XcxAuthStrategy.java +++ b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/XcxAuthStrategy.java @@ -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().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); + } + } + }); } } diff --git a/ruoyi-admin/src/main/resources/application-dev.yml b/ruoyi-admin/src/main/resources/application-dev.yml index 145c366..cee68b8 100644 --- a/ruoyi-admin/src/main/resources/application-dev.yml +++ b/ruoyi-admin/src/main/resources/application-dev.yml @@ -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 diff --git a/ruoyi-admin/src/main/resources/application-prod.yml b/ruoyi-admin/src/main/resources/application-prod.yml index 2a4bc11..22db6ff 100644 --- a/ruoyi-admin/src/main/resources/application-prod.yml +++ b/ruoyi-admin/src/main/resources/application-prod.yml @@ -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 diff --git a/ruoyi-admin/src/main/resources/application-test.yml b/ruoyi-admin/src/main/resources/application-test.yml index ea5cafa..a6653a4 100644 --- a/ruoyi-admin/src/main/resources/application-test.yml +++ b/ruoyi-admin/src/main/resources/application-test.yml @@ -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 diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml index 45493d3..87f377e 100644 --- a/ruoyi-common/pom.xml +++ b/ruoyi-common/pom.xml @@ -33,6 +33,8 @@ ruoyi-common-encrypt ruoyi-common-tenant ruoyi-common-websocket + ruoyi-common-wxpay + ruoyi-common-wxlogin ruoyi-common diff --git a/ruoyi-common/ruoyi-common-bom/pom.xml b/ruoyi-common/ruoyi-common-bom/pom.xml index 5388d8c..7cecbb2 100644 --- a/ruoyi-common/ruoyi-common-bom/pom.xml +++ b/ruoyi-common/ruoyi-common-bom/pom.xml @@ -172,6 +172,18 @@ ${revision} + + + org.dromara + ruoyi-common-wxpay + ${revision} + + + + org.dromara + ruoyi-common-wxlogin + ${revision} + diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/XcxLoginBody.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/XcxLoginBody.java index 518fe2e..b689f90 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/XcxLoginBody.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/XcxLoginBody.java @@ -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; } diff --git a/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/helper/TenantHelper.java b/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/helper/TenantHelper.java index 9d087e1..cc6aca5 100644 --- a/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/helper/TenantHelper.java +++ b/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/helper/TenantHelper.java @@ -190,5 +190,4 @@ public class TenantHelper { return false; } } - } diff --git a/ruoyi-common/ruoyi-common-wxlogin/pom.xml b/ruoyi-common/ruoyi-common-wxlogin/pom.xml new file mode 100644 index 0000000..b7ac9da --- /dev/null +++ b/ruoyi-common/ruoyi-common-wxlogin/pom.xml @@ -0,0 +1,31 @@ + + + + org.dromara + ruoyi-common + ${revision} + + 4.0.0 + + ruoyi-common-wxlogin + + + ruoyi-common-wxlogin 小程序登录功能 + + + + + + org.dromara + ruoyi-common-core + + + + com.github.binarywang + weixin-java-miniapp + + + + diff --git a/ruoyi-common/ruoyi-common-wxlogin/src/main/java/org/dromara/common/wxlogin/config/WxMaConfiguration.java b/ruoyi-common/ruoyi-common-wxlogin/src/main/java/org/dromara/common/wxlogin/config/WxMaConfiguration.java new file mode 100644 index 0000000..cb13917 --- /dev/null +++ b/ruoyi-common/ruoyi-common-wxlogin/src/main/java/org/dromara/common/wxlogin/config/WxMaConfiguration.java @@ -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 Binary Wang + */ +@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 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; + }; + +} diff --git a/ruoyi-common/ruoyi-common-wxlogin/src/main/java/org/dromara/common/wxlogin/config/properties/WxMaProperties.java b/ruoyi-common/ruoyi-common-wxlogin/src/main/java/org/dromara/common/wxlogin/config/properties/WxMaProperties.java new file mode 100644 index 0000000..41fbe8b --- /dev/null +++ b/ruoyi-common/ruoyi-common-wxlogin/src/main/java/org/dromara/common/wxlogin/config/properties/WxMaProperties.java @@ -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 Binary Wang + */ +@Data +@ConfigurationProperties(prefix = "wx.miniapp") +public class WxMaProperties { + + private List 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; + } + +} diff --git a/ruoyi-common/ruoyi-common-wxpay/pom.xml b/ruoyi-common/ruoyi-common-wxpay/pom.xml new file mode 100644 index 0000000..2833818 --- /dev/null +++ b/ruoyi-common/ruoyi-common-wxpay/pom.xml @@ -0,0 +1,31 @@ + + + + org.dromara + ruoyi-common + ${revision} + + 4.0.0 + + ruoyi-common-wxpay + + + ruoyi-common-pay 支付功能 + + + + + + org.dromara + ruoyi-common-core + + + + com.github.binarywang + weixin-java-pay + + + + diff --git a/ruoyi-common/ruoyi-common-wxpay/src/main/java/org/dromara/common/wxpay/config/WxPayConfiguration.java b/ruoyi-common/ruoyi-common-wxpay/src/main/java/org/dromara/common/wxpay/config/WxPayConfiguration.java new file mode 100644 index 0000000..29c6737 --- /dev/null +++ b/ruoyi-common/ruoyi-common-wxpay/src/main/java/org/dromara/common/wxpay/config/WxPayConfiguration.java @@ -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; + } + +} diff --git a/ruoyi-common/ruoyi-common-wxpay/src/main/java/org/dromara/common/wxpay/config/properties/WxPayProperties.java b/ruoyi-common/ruoyi-common-wxpay/src/main/java/org/dromara/common/wxpay/config/properties/WxPayProperties.java new file mode 100644 index 0000000..5d2a5fd --- /dev/null +++ b/ruoyi-common/ruoyi-common-wxpay/src/main/java/org/dromara/common/wxpay/config/properties/WxPayProperties.java @@ -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; + +} diff --git a/ruoyi-modules/rouyi-scale/pom.xml b/ruoyi-modules/rouyi-scale/pom.xml index 6d51e75..da09f7e 100644 --- a/ruoyi-modules/rouyi-scale/pom.xml +++ b/ruoyi-modules/rouyi-scale/pom.xml @@ -84,6 +84,11 @@ ruoyi-common-websocket + + org.dromara + ruoyi-common-wxpay + + com.deepoove poi-tl diff --git a/ruoyi-modules/rouyi-scale/src/main/java/org/dromara/scale/controller/web/WebController.java b/ruoyi-modules/rouyi-scale/src/main/java/org/dromara/scale/controller/web/WebController.java index 275931f..4eda3dc 100644 --- a/ruoyi-modules/rouyi-scale/src/main/java/org/dromara/scale/controller/web/WebController.java +++ b/ruoyi-modules/rouyi-scale/src/main/java/org/dromara/scale/controller/web/WebController.java @@ -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; diff --git a/ruoyi-modules/rouyi-scale/src/main/java/org/dromara/scale/controller/wx/WxPayController.java b/ruoyi-modules/rouyi-scale/src/main/java/org/dromara/scale/controller/wx/WxPayController.java new file mode 100644 index 0000000..1f4a3f9 --- /dev/null +++ b/ruoyi-modules/rouyi-scale/src/main/java/org/dromara/scale/controller/wx/WxPayController.java @@ -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; + +/** + *

TODO

+ * + * @author cjw + * @version V1.0.0 + * @date 2024/7/29 14:08 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/wx/pay") +public class WxPayController { + +} diff --git a/ruoyi-modules/rouyi-scale/src/main/java/org/dromara/scale/controller/wx/WxScaleController.java b/ruoyi-modules/rouyi-scale/src/main/java/org/dromara/scale/controller/wx/WxScaleController.java new file mode 100644 index 0000000..02e200c --- /dev/null +++ b/ruoyi-modules/rouyi-scale/src/main/java/org/dromara/scale/controller/wx/WxScaleController.java @@ -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; + +/** + *

TODO

+ * + * @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 list(SysScaleBo bo, PageQuery pageQuery) { + return sysScaleService.queryPageList(bo, pageQuery); + } + /** + * 获取心理测评量详细信息 + * + * @param scaleId 主键 + */ + @GetMapping("/{scaleId}") + public R getInfo(@NotNull(message = "主键不能为空") @PathVariable Long scaleId) { + //todo + return R.ok(sysScaleService.queryById(scaleId)); + } +} diff --git a/ruoyi-modules/rouyi-scale/src/main/java/org/dromara/scale/domain/SysScale.java b/ruoyi-modules/rouyi-scale/src/main/java/org/dromara/scale/domain/SysScale.java index ddfbd2d..0be70a4 100644 --- a/ruoyi-modules/rouyi-scale/src/main/java/org/dromara/scale/domain/SysScale.java +++ b/ruoyi-modules/rouyi-scale/src/main/java/org/dromara/scale/domain/SysScale.java @@ -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; + } diff --git a/ruoyi-modules/rouyi-scale/src/main/java/org/dromara/scale/domain/bo/SysScaleBo.java b/ruoyi-modules/rouyi-scale/src/main/java/org/dromara/scale/domain/bo/SysScaleBo.java index bfd138d..74373c3 100644 --- a/ruoyi-modules/rouyi-scale/src/main/java/org/dromara/scale/domain/bo/SysScaleBo.java +++ b/ruoyi-modules/rouyi-scale/src/main/java/org/dromara/scale/domain/bo/SysScaleBo.java @@ -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; } diff --git a/ruoyi-modules/rouyi-scale/src/main/java/org/dromara/scale/domain/vo/SysScaleVo.java b/ruoyi-modules/rouyi-scale/src/main/java/org/dromara/scale/domain/vo/SysScaleVo.java index d99a65b..269d150 100644 --- a/ruoyi-modules/rouyi-scale/src/main/java/org/dromara/scale/domain/vo/SysScaleVo.java +++ b/ruoyi-modules/rouyi-scale/src/main/java/org/dromara/scale/domain/vo/SysScaleVo.java @@ -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; + } diff --git a/ruoyi-modules/rouyi-scale/src/main/java/org/dromara/scale/starter/ApplicationStarter.java b/ruoyi-modules/rouyi-scale/src/main/java/org/dromara/scale/starter/ApplicationStarter.java index 1cb64b8..83ba01b 100644 --- a/ruoyi-modules/rouyi-scale/src/main/java/org/dromara/scale/starter/ApplicationStarter.java +++ b/ruoyi-modules/rouyi-scale/src/main/java/org/dromara/scale/starter/ApplicationStarter.java @@ -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(); diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUser.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUser.java index f644a32..38cb6e5 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUser.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUser.java @@ -42,6 +42,8 @@ public class SysUser extends TenantEntity { */ private String nickName; + private String openId; + /** * 用户类型(sys_user系统用户) */ diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java index d1f4059..8cae7b6 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java @@ -48,6 +48,8 @@ public class SysUserVo implements Serializable { */ private String userName; + private String openId; + /** * 用户昵称 */