提交
This commit is contained in:
157
jeepay-member/pom.xml
Normal file
157
jeepay-member/pom.xml
Normal file
@@ -0,0 +1,157 @@
|
||||
<?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>
|
||||
<artifactId>jeepay</artifactId>
|
||||
<groupId>com.jeequan</groupId>
|
||||
<version>Final</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>jeepay-9221-member</artifactId>
|
||||
<packaging>jar</packaging> <!-- 项目的最终打包类型/发布形式, 可选[jar, war, pom, maven-plugin]等 -->
|
||||
<version>${isys.version}</version> <!-- 项目当前版本号 -->
|
||||
<description>Jeepay计全支付系统 [会员模块]</description> <!-- 项目描述 -->
|
||||
<url>https://www.jeequan.com</url>
|
||||
|
||||
<!-- 项目属性 -->
|
||||
<properties>
|
||||
<projectRootDir>${basedir}/../</projectRootDir>
|
||||
</properties>
|
||||
|
||||
<!-- 项目依赖声明 -->
|
||||
<dependencies>
|
||||
|
||||
<!-- 显式 依赖[ service ]包, 会自动传递依赖[ core ]包。 -->
|
||||
<dependency>
|
||||
<groupId>com.jeequan</groupId>
|
||||
<artifactId>jeepay-components-db</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 依赖[ rpc-thirdparty ]包, 会自动传递依赖[ core , service ]包。 -->
|
||||
<dependency>
|
||||
<groupId>com.jeequan</groupId>
|
||||
<artifactId>jeepay-components-3rd</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 依赖[ oss ]包 -->
|
||||
<dependency>
|
||||
<groupId>com.jeequan</groupId>
|
||||
<artifactId>jeepay-components-oss</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 依赖[ bizcommons ]包 -->
|
||||
<dependency>
|
||||
<groupId>com.jeequan</groupId>
|
||||
<artifactId>jeepay-components-bizcommons</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 依赖[ mq ]包 -->
|
||||
<dependency>
|
||||
<groupId>com.jeequan</groupId>
|
||||
<artifactId>jeepay-components-mq</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 依赖 sping-boot-web -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<exclusions>
|
||||
<exclusion> <!-- 删除spring boot默认json映射器: Jackson, 引入fastJSON -->
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||
<artifactId>jackson-datatype-jdk8</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.fasterxml.jackson.module</groupId>
|
||||
<artifactId>jackson-module-parameter-names</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- spring-security -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- JWT -->
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 添加redis支持 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- xxl-job-core -->
|
||||
<dependency>
|
||||
<groupId>com.xuxueli</groupId>
|
||||
<artifactId>xxl-job-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 引入 jeepay-sdk-java -->
|
||||
<dependency>
|
||||
<groupId>com.jeequan</groupId>
|
||||
<artifactId>jeepay-sdk-java</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!--阿里云短信依赖-->
|
||||
<dependency>
|
||||
<groupId>com.aliyun</groupId>
|
||||
<artifactId>aliyun-java-sdk-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 阿里大于 -->
|
||||
<dependency>
|
||||
<groupId>com.aliyun</groupId>
|
||||
<artifactId>aliyun-java-sdk-dysmsapi</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<!-- 作为可执行jar -->
|
||||
<build>
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
|
||||
<!-- resources资源配置项 -->
|
||||
<resources>
|
||||
<!-- 通用资源文件 -->
|
||||
<resource><directory>src/main/resources</directory><includes><include>**/*.*</include></includes></resource>
|
||||
|
||||
<!-- 放置通用配置yml文件, 开发时仅配置一套参数即可。 实际生产环境下应在每个项目下 与jar同级目录下新建application.yml覆写对应参数。 -->
|
||||
<resource>
|
||||
<directory>../conf/devCommons</directory>
|
||||
<includes><include>**/*.yml</include></includes>
|
||||
</resource>
|
||||
</resources>
|
||||
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<includeSystemScope>true</includeSystemScope>
|
||||
<outputDirectory>${session.executionRootDirectory}/target/</outputDirectory>
|
||||
</configuration> <!-- 包含本地jar文件 -->
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.jeequan.jeepay.member.bootstrap;
|
||||
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import cn.hutool.crypto.SmUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.serializer.SerializeConfig;
|
||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||
import com.alibaba.fastjson.serializer.SimpleDateFormatSerializer;
|
||||
import com.jeequan.jeepay.member.config.SystemYmlConfig;
|
||||
import com.jeequan.jeepay.service.impl.SysConfigService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/*
|
||||
* 项目初始化操作
|
||||
* 比如初始化配置文件, 读取基础数据, 资源初始化等。 避免在Main函数中写业务代码。
|
||||
* CommandLineRunner / ApplicationRunner都可以达到要求, 只是调用参数有所不同。
|
||||
*
|
||||
*
|
||||
* @author terrfly
|
||||
*
|
||||
* @date 2021/6/8 17:17
|
||||
*/
|
||||
@Component
|
||||
public class InitRunner implements CommandLineRunner {
|
||||
|
||||
@Autowired private SystemYmlConfig systemYmlConfig;
|
||||
@Autowired private SysConfigService sysConfigService;
|
||||
|
||||
|
||||
@Override
|
||||
public void run(String... args) throws Exception {
|
||||
|
||||
// 配置是否使用缓存模式
|
||||
SysConfigService.IS_USE_CACHE = systemYmlConfig.getCacheConfig();
|
||||
|
||||
// 初始化系统秘钥
|
||||
SysConfigService.DB_ENCRYPT_SECRET = systemYmlConfig.getDbEncryptSecret();
|
||||
SysConfigService.DB_ENCRYPT_SM4 = SmUtil.sm4(SysConfigService.DB_ENCRYPT_SECRET.getBytes());
|
||||
SysConfigService.HTTP_MESSAGE_ENCRYPT_SECRET = systemYmlConfig.getHttpMessageEncryptSecret();
|
||||
SysConfigService.HTTP_MESSAGE_ENCRYPT_SM4 = SmUtil.sm4(SysConfigService.HTTP_MESSAGE_ENCRYPT_SECRET.getBytes());
|
||||
|
||||
// 配置是否通信加密 和 密码修改
|
||||
SysConfigService.HTTP_MSG_IS_ENCRYPT = sysConfigService.getDBSecurityConfig().httpMsgIsEncrypt();
|
||||
SysConfigService.PWD_EXPIRED_MUST_RESET = sysConfigService.getDBSecurityConfig().passwordExpiredIsMustModify();
|
||||
|
||||
// 配置 平台通信秘钥
|
||||
SysConfigService.PLATFORM_API_SECRET = sysConfigService.getDBSecurityConfig().getPlatformApiSecret();
|
||||
|
||||
//初始化处理fastjson格式
|
||||
SerializeConfig serializeConfig = SerializeConfig.getGlobalInstance();
|
||||
serializeConfig.put(Date.class, new SimpleDateFormatSerializer(DatePattern.NORM_DATETIME_PATTERN));
|
||||
|
||||
//解决json 序列化时候的 $ref:问题
|
||||
JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.DisableCircularReferenceDetect.getMask();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package com.jeequan.jeepay.member.bootstrap;
|
||||
|
||||
import com.alibaba.fastjson.parser.ParserConfig;
|
||||
import com.alibaba.fastjson.support.config.FastJsonConfig;
|
||||
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
||||
import com.jeequan.jeepay.core.task.XxlJobExecutorProp;
|
||||
import com.jeequan.jeepay.member.config.SystemYmlConfig;
|
||||
import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @Author terrfly
|
||||
* @Date 2019/11/7 15:19
|
||||
* @Description spring-boot 主启动程序
|
||||
**/
|
||||
@SpringBootApplication
|
||||
@EnableScheduling
|
||||
@MapperScan("com.jeequan.jeepay.service.mapper") //Mybatis mapper接口路径
|
||||
@ComponentScan(basePackages = "com.jeequan.jeepay.*") //由于MainApplication没有在项目根目录, 需要配置basePackages属性使得成功扫描所有Spring组件;
|
||||
@Configuration
|
||||
public class JeepayMemberApplication {
|
||||
|
||||
@Autowired private SystemYmlConfig systemYmlConfig;
|
||||
|
||||
/** main启动函数 **/
|
||||
public static void main(String[] args) {
|
||||
|
||||
//启动项目
|
||||
SpringApplication.run(JeepayMemberApplication.class, args);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/** fastJson 配置信息 **/
|
||||
@Bean
|
||||
public HttpMessageConverters fastJsonConfig(){
|
||||
|
||||
// 开启 FastJSON 安全模式!
|
||||
ParserConfig.getGlobalInstance().setSafeMode(true);
|
||||
|
||||
//新建fast-json转换器
|
||||
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
|
||||
|
||||
//fast-json 配置信息
|
||||
FastJsonConfig config = new FastJsonConfig();
|
||||
config.setDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
converter.setFastJsonConfig(config);
|
||||
|
||||
|
||||
//设置响应的 Content-Type
|
||||
converter.setSupportedMediaTypes(Arrays.asList(new MediaType[]{MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON_UTF8}));
|
||||
return new HttpMessageConverters(converter);
|
||||
}
|
||||
|
||||
/** Mybatis plus 分页插件 **/
|
||||
@Bean
|
||||
public PaginationInnerInterceptor paginationInterceptor() {
|
||||
PaginationInnerInterceptor paginationInterceptor = new PaginationInnerInterceptor();
|
||||
// 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false
|
||||
// paginationInterceptor.setOverflow(false);
|
||||
// 设置最大单页限制数量,默认 500 条,-1 不受限制
|
||||
paginationInterceptor.setMaxLimit(-1L);
|
||||
return paginationInterceptor;
|
||||
}
|
||||
|
||||
/*** 注入 定时任务 执行器 **/
|
||||
|
||||
/** xxl-job执行器配置信息 **/
|
||||
@ConfigurationProperties(prefix = "xxl-job.executor")
|
||||
@Bean
|
||||
public XxlJobExecutorProp xxlJobExecutorProp() { return new XxlJobExecutorProp(); }
|
||||
|
||||
@Autowired
|
||||
private XxlJobExecutorProp xxlJobExecutorProp;
|
||||
|
||||
@Bean
|
||||
public XxlJobSpringExecutor xxlJobExecutor() {
|
||||
XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
|
||||
xxlJobSpringExecutor.setAdminAddresses(xxlJobExecutorProp.getAdminAddress());
|
||||
xxlJobSpringExecutor.setAppname(xxlJobExecutorProp.getAppname());
|
||||
|
||||
if(xxlJobExecutorProp.getPort() != null){
|
||||
xxlJobSpringExecutor.setPort(xxlJobExecutorProp.getPort());
|
||||
}
|
||||
|
||||
xxlJobSpringExecutor.setAccessToken(xxlJobExecutorProp.getAccessToken());
|
||||
xxlJobSpringExecutor.setLogPath(xxlJobExecutorProp.getLogPath());
|
||||
xxlJobSpringExecutor.setLogRetentionDays(xxlJobExecutorProp.getLogretentiondays());
|
||||
return xxlJobSpringExecutor;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package com.jeequan.jeepay.member.config;
|
||||
|
||||
import com.jeequan.jeepay.core.cache.RedisUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
|
||||
/*
|
||||
* RedisConfig
|
||||
*
|
||||
* @author terrfly
|
||||
* @date 2021/6/8 17:25
|
||||
*/
|
||||
@Configuration
|
||||
public class RedisConfig {
|
||||
|
||||
@Value("${spring.redis.host}")
|
||||
private String host;
|
||||
|
||||
@Value("${spring.redis.port}")
|
||||
private Integer port;
|
||||
|
||||
@Value("${spring.redis.timeout}")
|
||||
private Integer timeout;
|
||||
|
||||
@Value("${spring.redis.database}")
|
||||
private Integer defaultDatabase;
|
||||
|
||||
@Value("${spring.redis.password}")
|
||||
private String password;
|
||||
|
||||
/** 作用:不同系统的前缀。 a.当连接不同的database时可以为空(物理隔离); b.当redis集群时因为必须同一个database,所以需通过前缀区分不同系统的业务。 **/
|
||||
@Value("${spring.redis.sys-prefix-key}")
|
||||
private String sysPrefixKey;
|
||||
|
||||
/** 当前系统的redis缓存操作对象 (主对象) **/
|
||||
@Primary
|
||||
@Bean(name = "defaultStringRedisTemplate")
|
||||
public StringRedisTemplate sysStringRedisTemplate() {
|
||||
|
||||
// 赋值前缀key
|
||||
RedisUtil.SYS_PREFIX_KEY = sysPrefixKey;
|
||||
|
||||
StringRedisTemplate template = new StringRedisTemplate();
|
||||
|
||||
LettuceConnectionFactory jedisConnectionFactory = new LettuceConnectionFactory();
|
||||
jedisConnectionFactory.setHostName(host);
|
||||
jedisConnectionFactory.setPort(port);
|
||||
jedisConnectionFactory.setTimeout(timeout);
|
||||
|
||||
if (!StringUtils.isEmpty(password)) {
|
||||
jedisConnectionFactory.setPassword(password);
|
||||
}
|
||||
|
||||
if (defaultDatabase != 0) {
|
||||
jedisConnectionFactory.setDatabase(defaultDatabase);
|
||||
}
|
||||
|
||||
jedisConnectionFactory.afterPropertiesSet();
|
||||
|
||||
template.setConnectionFactory(jedisConnectionFactory);
|
||||
return template;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.jeequan.jeepay.member.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 系统Yml配置参数定义Bean
|
||||
*
|
||||
* @author terrfly
|
||||
* @date 2021-04-27 15:50
|
||||
*/
|
||||
@Component
|
||||
@ConfigurationProperties(prefix="isys")
|
||||
@Data
|
||||
public class SystemYmlConfig {
|
||||
|
||||
/** 是否允许跨域请求 [生产环境建议关闭, 若api与前端项目没有在同一个域名下时,应开启此配置或在nginx统一配置允许跨域] **/
|
||||
private Boolean allowCors;
|
||||
|
||||
/** 生成jwt的秘钥。 要求每个系统有单独的秘钥管理机制。 **/
|
||||
private String jwtSecret;
|
||||
|
||||
/** DB SM4 加解密秘钥 (必须16位) [每个系统配置必须相同,否则加解密不一致导致业务异常!] **/
|
||||
private String dbEncryptSecret;
|
||||
|
||||
/** web传输加解密 秘钥 (必须16位) [每个系统配置必须相同,否则加解密不一致导致业务异常!] **/
|
||||
private String httpMessageEncryptSecret;
|
||||
|
||||
/** 支付网关的公钥和私钥(系统级别!), 请妥善保存,用于回调商户的商户侧的验证, 首次设置好之后不可随意变更! **/
|
||||
private String sysRSA2PrivateKey;
|
||||
|
||||
/**支付网关的公钥和私钥(系统级别!), 请妥善保存,用于回调商户的商户侧的验证, 首次设置好之后不可随意变更! **/
|
||||
private String sysRSA2PublicKey;
|
||||
|
||||
/** 是否内存缓存配置信息: true表示开启如支付网关地址/商户应用配置/服务商配置等, 开启后需检查MQ的广播模式是否正常; false表示直接查询DB. **/
|
||||
private Boolean cacheConfig;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
package com.jeequan.jeepay.member.ctrl;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.jeequan.jeepay.core.constants.CS;
|
||||
import com.jeequan.jeepay.core.ctrls.AbstractCtrl;
|
||||
import com.jeequan.jeepay.core.exception.BizException;
|
||||
import com.jeequan.jeepay.core.interfaces.IConfigContextQueryService;
|
||||
import com.jeequan.jeepay.core.model.BaseModel;
|
||||
import com.jeequan.jeepay.core.model.QRCodeParams;
|
||||
import com.jeequan.jeepay.core.model.context.MchAppConfigContext;
|
||||
import com.jeequan.jeepay.core.utils.JeepayKit;
|
||||
import com.jeequan.jeepay.db.entity.MchInfo;
|
||||
import com.jeequan.jeepay.db.entity.MchQrcodeCard;
|
||||
import com.jeequan.jeepay.db.entity.PayOrder;
|
||||
import com.jeequan.jeepay.member.secruity.JeeMemberDetails;
|
||||
import com.jeequan.jeepay.service.impl.MchInfoService;
|
||||
import com.jeequan.jeepay.service.impl.MchQrcodeCardService;
|
||||
import com.jeequan.jeepay.service.impl.PayOrderService;
|
||||
import com.jeequan.jeepay.service.impl.SysConfigService;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @description:
|
||||
* @author: zx
|
||||
* @date: 2023/04/13 16:53
|
||||
*/
|
||||
public class CommonCtrl extends AbstractCtrl {
|
||||
|
||||
@Autowired protected PayOrderService payOrderService;
|
||||
@Autowired protected IConfigContextQueryService configContextQueryService;
|
||||
@Autowired protected SysConfigService sysConfigService;
|
||||
@Autowired protected MchQrcodeCardService mchQrcodeCardService;
|
||||
@Autowired protected MchInfoService mchInfoService;
|
||||
|
||||
/** 获取当前会员 */
|
||||
protected JeeMemberDetails getCurrentUser(){
|
||||
return (JeeMemberDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
}
|
||||
|
||||
/** 获取当前会员ID **/
|
||||
protected String getCurrentMbrId() {
|
||||
return getCurrentUser().getMbrId();
|
||||
}
|
||||
|
||||
/** 解析聚合码token,与payment解析一致 **/
|
||||
public QRCodeParams tokenConvert(){
|
||||
QRCodeParams qrCodeParams = JSON.parseObject(JeepayKit.aesDecode(getToken()), QRCodeParams.class); //解析token
|
||||
qrCodeParams.setPageType(getCurrentPageType()); //封装页面类型
|
||||
return qrCodeParams;
|
||||
}
|
||||
|
||||
public String getToken(){
|
||||
|
||||
String token = request.getHeader(JeepayKit.TOKEN_KEY);
|
||||
if(StringUtils.isEmpty(token)) {
|
||||
throw new BizException("获取二维码参数失败");
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
public String getCurrentPageType(){
|
||||
String pageType = request.getHeader("pageType");
|
||||
if(StringUtils.isEmpty(pageType)) {
|
||||
throw new BizException("不支持的客户端");
|
||||
}
|
||||
return pageType;
|
||||
}
|
||||
|
||||
|
||||
public MchAppConfigContext getQrParamsMchAppConfigContext(QRCodeParams qrCodeParams, boolean checkState){
|
||||
|
||||
/*if(qrCodeParams.getType() == QRCodeParams.TYPE_PAY_ORDER){ // 订单
|
||||
|
||||
PayOrder payOrder = getPayOrder(checkState);
|
||||
return configContextQueryService.queryMchInfoAndAppInfo(payOrder.getMchNo(), payOrder.getAppId());
|
||||
|
||||
}else */
|
||||
if(qrCodeParams.getType() == QRCodeParams.TYPE_QRC){ // 码牌二维码
|
||||
|
||||
MchQrcodeCard mchQrCode = mchQrcodeCardService.getById(qrCodeParams.getId());
|
||||
if (mchQrCode == null || mchQrCode.getQrcState() != CS.YES) {
|
||||
throw new BizException("码牌不存在或已停用");
|
||||
}
|
||||
if (mchQrCode.getBindState() != CS.YES) {
|
||||
throw new BizException("请先绑定商户");
|
||||
}
|
||||
|
||||
return configContextQueryService.queryMchInfoAndAppInfoV2(mchQrCode.getMchNo(), mchQrCode.getAppId(),null);
|
||||
}
|
||||
throw new BizException("二维码参数有误");
|
||||
}
|
||||
|
||||
public PayOrder getPayOrder(boolean checkState){
|
||||
|
||||
JSONObject qrParams = JSON.parseObject(JeepayKit.aesDecode(getToken())); //解析token
|
||||
String payOrderId = qrParams.getString("id");
|
||||
|
||||
PayOrder payOrder = payOrderService.getById(payOrderId);
|
||||
if(checkState == false) {
|
||||
return payOrder;
|
||||
}
|
||||
if(payOrder == null) {
|
||||
throw new BizException("订单不存");
|
||||
}
|
||||
if(payOrder.getState() == PayOrder.STATE_SUCCESS) {
|
||||
throw new BizException("订单已支付");
|
||||
}
|
||||
if(payOrder.getState() != PayOrder.STATE_INIT) {
|
||||
throw new BizException("订单状态不正确");
|
||||
}
|
||||
return payOrder;
|
||||
}
|
||||
|
||||
|
||||
/** model 存入商户名称 **/
|
||||
public void setMchName(List<? extends BaseModel> modeList) {
|
||||
|
||||
if(modeList == null || modeList.isEmpty()){
|
||||
return ;
|
||||
}
|
||||
ArrayList<String> mchNoList = new ArrayList<>();
|
||||
for (BaseModel model:modeList) {
|
||||
JSONObject json = (JSONObject) JSONObject.toJSON(model);
|
||||
String mchNo = json.getString("mchNo");
|
||||
mchNoList.add(mchNo);
|
||||
}
|
||||
List<MchInfo> mchInfoList = mchInfoService.list(MchInfo.gw().select(MchInfo::getMchNo, MchInfo::getMchName).in(MchInfo::getMchNo, mchNoList));
|
||||
for (BaseModel model:modeList) {
|
||||
JSONObject json = (JSONObject) JSONObject.toJSON(model);
|
||||
String mchNo = json.getString("mchNo");
|
||||
|
||||
if(StringUtils.isBlank(mchNo)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (MchInfo info:mchInfoList) {
|
||||
if (mchNo.equals(info.getMchNo())) {
|
||||
model.addExt("mchName", info.getMchName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package com.jeequan.jeepay.member.ctrl.anon;
|
||||
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import com.jeequan.jeepay.bizcommons.manage.sms.SmsManager;
|
||||
import com.jeequan.jeepay.core.constants.CS;
|
||||
import com.jeequan.jeepay.core.exception.BizException;
|
||||
import com.jeequan.jeepay.core.model.ApiRes;
|
||||
import com.jeequan.jeepay.core.model.QRCodeParams;
|
||||
import com.jeequan.jeepay.core.model.context.MchAppConfigContext;
|
||||
import com.jeequan.jeepay.db.entity.MemberInfo;
|
||||
import com.jeequan.jeepay.member.ctrl.CommonCtrl;
|
||||
import com.jeequan.jeepay.member.service.MchRechargeRuleEntryService;
|
||||
import com.jeequan.jeepay.member.service.MemberService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 未知会员 服务入口controller
|
||||
*
|
||||
* @author zx
|
||||
* @date 2023/4/12 17:27
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/anon/member")
|
||||
public class AnonMemberController extends CommonCtrl {
|
||||
|
||||
@Autowired
|
||||
private MchRechargeRuleEntryService mchRechargeRuleService;
|
||||
@Autowired
|
||||
private MemberService memberService;
|
||||
@Autowired
|
||||
private SmsManager smsManager;
|
||||
|
||||
public final static String MCH_MBR_RECHARGE_RULE = "mch.mbr.recharge.rule"; // 获取商户会员充值规则列表
|
||||
public final static String MCH_MBR_RECHARGE_RULE_STORE = "mch.mbr.recharge.rule.store"; // 获取充值规则适用门店
|
||||
public final static String MBR_INFO = "mbr.info"; // 获取会员信息
|
||||
public final static String MCH_INFO = "mch.info"; // 获取商户信息
|
||||
public final static String MBR_TEL_BIND = "mbr.tel.bind"; // 会员手机号绑定
|
||||
public final static String MBR_TEL_SEND_SMS_CODE = "mbr.tel.send.sms.code"; // 发送手机验证码
|
||||
|
||||
/**
|
||||
* 未知会员 服务入口
|
||||
**/
|
||||
@PostMapping
|
||||
public ApiRes entry() {
|
||||
|
||||
// token转换对象
|
||||
QRCodeParams qrCodeParams = tokenConvert();
|
||||
|
||||
// 获取商户配置信息
|
||||
MchAppConfigContext mchAppConfigContext = getQrParamsMchAppConfigContext(qrCodeParams, false);
|
||||
if (mchAppConfigContext == null) {
|
||||
throw new BizException("商户或商户应用不存在");
|
||||
}
|
||||
if (mchAppConfigContext.getMchInfo() == null || mchAppConfigContext.getMchInfo().getState() != CS.YES) {
|
||||
throw new BizException("商户信息不存在或商户状态不可用");
|
||||
}
|
||||
|
||||
String method = getValStringRequired("method");
|
||||
switch (method) {
|
||||
case MCH_MBR_RECHARGE_RULE:
|
||||
return mchRechargeRuleService.getMchRechargeRule(mchAppConfigContext);
|
||||
case MCH_MBR_RECHARGE_RULE_STORE:
|
||||
return mchRechargeRuleService.getMchRechargeRuleStore(mchAppConfigContext);
|
||||
case MBR_INFO:
|
||||
return memberService.getMemberInfo(mchAppConfigContext.getMchNo(), Base64.decodeStr(getValStringRequired("channelUesrId")), qrCodeParams.getPageType());
|
||||
case MCH_INFO:
|
||||
return memberService.getMchInfo(mchAppConfigContext, qrCodeParams);
|
||||
case MBR_TEL_SEND_SMS_CODE:
|
||||
|
||||
smsManager.sendSmsVercode(Base64.decodeStr(getValStringRequired("mbrTel")), CS.SMS_TYPE_API_ENUM.TYPE_MBR_TEL_BIND);
|
||||
return ApiRes.ok();
|
||||
case MBR_TEL_BIND:
|
||||
String mbrTel = Base64.decodeStr(getValStringRequired("mbrTel"));
|
||||
String code = Base64.decodeStr(getValStringRequired("code"));
|
||||
String channelUesrId = Base64.decodeStr(getValStringRequired("channelUesrId"));
|
||||
|
||||
MemberInfo memberInfo = getObject(MemberInfo.class);
|
||||
memberInfo.setMbrTel(mbrTel); // base64解密之后
|
||||
memberInfo.setMchNo(mchAppConfigContext.getMchNo());
|
||||
return memberService.mbrTelBind(memberInfo, code, channelUesrId, qrCodeParams.getPageType());
|
||||
default:
|
||||
return ApiRes.customFail("不支持的method类型");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package com.jeequan.jeepay.member.ctrl.member;
|
||||
|
||||
import cn.hutool.core.util.DesensitizedUtil;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
|
||||
import com.jeequan.jeepay.core.model.ApiRes;
|
||||
import com.jeequan.jeepay.db.entity.MemberAccountHistory;
|
||||
import com.jeequan.jeepay.member.ctrl.CommonCtrl;
|
||||
import com.jeequan.jeepay.service.impl.MemberAccountHistoryService;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 会员账户流水
|
||||
*
|
||||
* @author xiaoyu
|
||||
* @date 2023/4/13 17:22
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/member/accountHistory")
|
||||
public class MemberAccountHistoryController extends CommonCtrl {
|
||||
|
||||
@Autowired private MemberAccountHistoryService accountHistoryService;
|
||||
|
||||
/**
|
||||
* @author: xiaoyu
|
||||
* @date: 2023/4/13 17:24
|
||||
* @describe: 会员账户流水列表
|
||||
*/
|
||||
@GetMapping
|
||||
public ApiRes list() {
|
||||
MemberAccountHistory accountHistory = getObject(MemberAccountHistory.class);
|
||||
|
||||
LambdaQueryWrapper<MemberAccountHistory> wrapper = MemberAccountHistory.gw();
|
||||
|
||||
wrapper.eq(MemberAccountHistory::getMbrId, getCurrentMbrId());
|
||||
// 查询条件
|
||||
accountHistoryService.selectParams(accountHistory, wrapper);
|
||||
|
||||
// 额外条件参数
|
||||
JSONObject paramJSON = getReqParamJSON();
|
||||
|
||||
// 二合一 会员名称/订单号/手机号
|
||||
if (paramJSON != null && StringUtils.isNotEmpty(paramJSON.getString("unionQueryParam"))) {
|
||||
wrapper.and(wr -> {
|
||||
wr.like(MemberAccountHistory::getMbrTel, paramJSON.getString("unionQueryParam"))
|
||||
.or().like(MemberAccountHistory::getMbrName, paramJSON.getString("unionQueryParam"))
|
||||
.or().like(MemberAccountHistory::getRelaBizOrderId, paramJSON.getString("unionQueryParam"));
|
||||
});
|
||||
}
|
||||
|
||||
wrapper.orderByDesc(MemberAccountHistory::getCreatedAt);
|
||||
|
||||
IPage<MemberAccountHistory> page = accountHistoryService.page(getIPage(), wrapper);
|
||||
// 手机号脱敏
|
||||
page.getRecords().stream().forEach(i -> i.setMbrTel(DesensitizedUtil.mobilePhone(i.getMbrTel())));
|
||||
|
||||
// 商户名称赋值
|
||||
setMchName(page.getRecords());
|
||||
|
||||
return ApiRes.page(page);
|
||||
}
|
||||
|
||||
/**
|
||||
* @author: xiaoyu
|
||||
* @date: 2023/4/13 17:49
|
||||
* @describe: 会员账户流水信息
|
||||
*/
|
||||
@PreAuthorize("hasAuthority('ENT_MEMBER_ACCOUNT_HISTORY_VIEW')")
|
||||
@GetMapping("/{hid}")
|
||||
public ApiRes detail(@PathVariable("hid") String hid) {
|
||||
|
||||
MemberAccountHistory history = accountHistoryService.getById(hid);
|
||||
|
||||
if (history == null || !history.getMbrId().equals(getCurrentMbrId())) {
|
||||
return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH);
|
||||
}
|
||||
|
||||
return ApiRes.ok(history);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.jeequan.jeepay.member.ctrl.member;
|
||||
|
||||
import com.jeequan.jeepay.core.model.ApiRes;
|
||||
import com.jeequan.jeepay.core.model.QRCodeParams;
|
||||
import com.jeequan.jeepay.core.model.context.MchAppConfigContext;
|
||||
import com.jeequan.jeepay.db.entity.MemberInfo;
|
||||
import com.jeequan.jeepay.member.ctrl.CommonCtrl;
|
||||
import com.jeequan.jeepay.service.impl.MemberInfoService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 会员服务入口controller
|
||||
*
|
||||
* @author zx
|
||||
* @date 2023/4/12 17:27
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/member")
|
||||
public class MemberInfoController extends CommonCtrl {
|
||||
|
||||
@Autowired private MemberInfoService memberInfoService;
|
||||
|
||||
/**
|
||||
* 获取会员信息
|
||||
*/
|
||||
@GetMapping
|
||||
public ApiRes memberInfo() {
|
||||
|
||||
// token转换对象
|
||||
QRCodeParams qrCodeParams = tokenConvert();
|
||||
|
||||
// 获取商户配置信息
|
||||
MchAppConfigContext mchAppConfigContext = getQrParamsMchAppConfigContext(qrCodeParams, false);
|
||||
|
||||
// 查询会员信息
|
||||
MemberInfo memberInfo = memberInfoService.selectOne(mchAppConfigContext.getMchNo(), getCurrentMbrId());
|
||||
memberInfo.setWxMpOpenId(null);
|
||||
memberInfo.setWxLiteOpenId(null);
|
||||
memberInfo.setAliUserId(null);
|
||||
memberInfo.setYsfUserId(null);
|
||||
|
||||
return ApiRes.ok(memberInfo);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package com.jeequan.jeepay.member.ctrl.member;
|
||||
|
||||
import com.jeequan.jeepay.components.mq.model.PushPrinterMQ;
|
||||
import com.jeequan.jeepay.components.mq.model.PushSpeakerMQ;
|
||||
import com.jeequan.jeepay.components.mq.vender.IMQSender;
|
||||
import com.jeequan.jeepay.core.constants.CS;
|
||||
import com.jeequan.jeepay.core.exception.BizException;
|
||||
import com.jeequan.jeepay.core.model.ApiRes;
|
||||
import com.jeequan.jeepay.core.model.QRCodeParams;
|
||||
import com.jeequan.jeepay.core.model.context.MchAppConfigContext;
|
||||
import com.jeequan.jeepay.db.entity.MchQrcodeCard;
|
||||
import com.jeequan.jeepay.db.entity.MemberAccountHistory;
|
||||
import com.jeequan.jeepay.db.entity.MemberInfo;
|
||||
import com.jeequan.jeepay.member.ctrl.CommonCtrl;
|
||||
import com.jeequan.jeepay.service.impl.MemberAccountHistoryService;
|
||||
import com.jeequan.jeepay.service.impl.MemberInfoService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 会员账户支付 controller
|
||||
*
|
||||
* @author zx
|
||||
* @date 2023/4/12 17:27
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/member/pay")
|
||||
public class MemberPayController extends CommonCtrl {
|
||||
|
||||
@Autowired private MemberInfoService memberInfoService;
|
||||
@Autowired private MemberAccountHistoryService memberAccountHistoryService;
|
||||
@Autowired private IMQSender mqSender;
|
||||
|
||||
/**
|
||||
* 会员账户支付
|
||||
**/
|
||||
@PostMapping
|
||||
public ApiRes pay() {
|
||||
|
||||
// token转换对象
|
||||
QRCodeParams qrCodeParams = tokenConvert();
|
||||
|
||||
MchQrcodeCard mchQrCode = mchQrcodeCardService.getById(qrCodeParams.getId());
|
||||
if(mchQrCode == null || mchQrCode.getQrcState() != CS.YES || mchQrCode.getBindState() != CS.YES){
|
||||
throw new BizException("当前静态码不存在或不可用或未绑定");
|
||||
}
|
||||
|
||||
// 获取商户配置信息
|
||||
MchAppConfigContext mchAppConfigContext = getQrParamsMchAppConfigContext(qrCodeParams, false);
|
||||
if(mchAppConfigContext == null){
|
||||
throw new BizException("商户或商户应用不存在");
|
||||
}
|
||||
if(mchAppConfigContext.getMchInfo() == null || mchAppConfigContext.getMchInfo().getState() != CS.YES){
|
||||
throw new BizException("商户信息不存在或商户状态不可用");
|
||||
}
|
||||
|
||||
Long amount = getRequiredAmountL("amount");
|
||||
if(amount <= 0) {
|
||||
throw new BizException("金额错误");
|
||||
}
|
||||
|
||||
MemberInfo memberInfo = memberInfoService.selectOne(mchAppConfigContext.getMchNo(), getCurrentMbrId());
|
||||
if (memberInfo == null || memberInfo.getState() != CS.YES) {
|
||||
throw new BizException("会员不存在或已禁用");
|
||||
}
|
||||
|
||||
MemberAccountHistory accountHistory = memberAccountHistoryService.updateMbrAccountAndInsertHistory(memberInfo.getMchNo(), mchQrCode.getStoreId(),
|
||||
mchQrCode.getQrcId(), memberInfo.getMbrId(), -amount, MemberAccountHistory.BIZ_CONSUME, null, getValString("remark"));
|
||||
|
||||
// 语音播报
|
||||
this.speak(String.valueOf(accountHistory.getHid()));
|
||||
|
||||
return ApiRes.ok();
|
||||
}
|
||||
|
||||
public void speak(String hid) {
|
||||
|
||||
// 发送订单支付成功 云喇叭通知
|
||||
mqSender.send(PushSpeakerMQ.build(hid, PushSpeakerMQ.MsgPayload.ORDER_TYPE_MEMBER));
|
||||
|
||||
// 发送订单支付成功 云打印通知
|
||||
mqSender.send(PushPrinterMQ.build(hid, PushPrinterMQ.MsgPayload.ORDER_TYPE_MEMBER));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,335 @@
|
||||
package com.jeequan.jeepay.member.ctrl.member;
|
||||
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.jeequan.jeepay.ApiField;
|
||||
import com.jeequan.jeepay.JeepayClient;
|
||||
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
|
||||
import com.jeequan.jeepay.core.constants.CS;
|
||||
import com.jeequan.jeepay.core.exception.BizException;
|
||||
import com.jeequan.jeepay.core.model.ApiRes;
|
||||
import com.jeequan.jeepay.core.model.DBApplicationConfig;
|
||||
import com.jeequan.jeepay.core.model.QRCodeParams;
|
||||
import com.jeequan.jeepay.core.model.context.MchAppConfigContext;
|
||||
import com.jeequan.jeepay.core.utils.AmountUtil;
|
||||
import com.jeequan.jeepay.core.utils.JsonKit;
|
||||
import com.jeequan.jeepay.core.utils.SeqKit;
|
||||
import com.jeequan.jeepay.db.entity.*;
|
||||
import com.jeequan.jeepay.exception.JeepayException;
|
||||
import com.jeequan.jeepay.member.ctrl.CommonCtrl;
|
||||
import com.jeequan.jeepay.model.DeviceInfo;
|
||||
import com.jeequan.jeepay.model.JeepayObject;
|
||||
import com.jeequan.jeepay.model.PayOrderCreateResModel;
|
||||
import com.jeequan.jeepay.request.PayOrderCreateRequest;
|
||||
import com.jeequan.jeepay.response.PayOrderCreateResponse;
|
||||
import com.jeequan.jeepay.service.impl.*;
|
||||
import lombok.Data;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 会员充值 服务入口controller
|
||||
*
|
||||
* @author zx
|
||||
* @date 2023/4/12 17:27
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/member/recharge")
|
||||
public class MemberRechargeController extends CommonCtrl {
|
||||
|
||||
@Autowired private MemberInfoService memberInfoService;
|
||||
@Autowired private MchAppService mchAppService;
|
||||
@Autowired private MemberRechargeRuleService memberRechargeRuleService;
|
||||
@Autowired private MemberRechargeRecordService memberRechargeRecordService;
|
||||
@Autowired private MchConfigService mchConfigService;
|
||||
@Autowired private MchApplymentService mchApplymentService;
|
||||
|
||||
/**
|
||||
* 会员充值
|
||||
**/
|
||||
@PostMapping
|
||||
public ApiRes recharge() {
|
||||
|
||||
// token转换对象
|
||||
QRCodeParams qrCodeParams = tokenConvert();
|
||||
|
||||
// 获取商户配置信息
|
||||
MchAppConfigContext mchAppConfigContext = getQrParamsMchAppConfigContext(qrCodeParams, false);
|
||||
if(mchAppConfigContext == null){
|
||||
throw new BizException("商户或商户应用不存在");
|
||||
}
|
||||
if(mchAppConfigContext.getMchInfo() == null || mchAppConfigContext.getMchInfo().getState() != CS.YES){
|
||||
throw new BizException("商户信息不存在或商户状态不可用");
|
||||
}
|
||||
|
||||
// 查询会员信息
|
||||
MemberInfo memberInfo = memberInfoService.selectOne(mchAppConfigContext.getMchNo(), getCurrentMbrId());
|
||||
if (memberInfo == null || memberInfo.getState() != CS.YES) {
|
||||
return ApiRes.customFail("会员不存在或已禁用");
|
||||
}
|
||||
|
||||
// 充值金额,前端传 充值规则ID,则以此ID为准;不传充值规则ID,则充值为自定义金额且必填
|
||||
String rechargeRuleId = getValString("rechargeRuleId");
|
||||
Long payAmount = 0L; // 实际支付金额
|
||||
Long giveAmount = 0L; // 赠送金额
|
||||
if (StringUtils.isNotBlank(rechargeRuleId)) {
|
||||
MemberRechargeRule rechargeRule = memberRechargeRuleService.getById(rechargeRuleId);
|
||||
if (rechargeRule == null || !mchAppConfigContext.getMchNo().equals(rechargeRule.getMchNo()) || rechargeRule.getState() != CS.YES) {
|
||||
throw new BizException("充值赠送规则不存在或已禁用");
|
||||
}
|
||||
payAmount = rechargeRule.getRechargeAmount();
|
||||
if (rechargeRule.getGiveAmount() != null) {
|
||||
giveAmount = rechargeRule.getGiveAmount();
|
||||
}
|
||||
}else {
|
||||
payAmount = getRequiredAmountL("rechargeAmount");
|
||||
}
|
||||
if (payAmount <= 0) {
|
||||
throw new BizException("充值金额错误!");
|
||||
}
|
||||
|
||||
// 校验商户最大储值金额
|
||||
Long memebrMaxbalance = null;
|
||||
String val = mchConfigService.getConfigValByMchNoAndKey(memberInfo.getMchNo(), MchConfig.SELF_MEMBER_MAX_BALANCE);
|
||||
if (StringUtils.isNotBlank(val) && NumberUtil.isLong(val)) {
|
||||
memebrMaxbalance = Long.parseLong(val);
|
||||
}
|
||||
if (memebrMaxbalance == null || memebrMaxbalance.equals(0L)) {
|
||||
memebrMaxbalance = sysConfigService.getDBDefaultConfig().getMchMbrMaxBalance();
|
||||
}
|
||||
if (memebrMaxbalance != null && !memebrMaxbalance.equals(0L)) {
|
||||
Long totalBalance = memberInfoService.selectTotalBalance(MemberInfo.gw().eq(MemberInfo::getMchNo, memberInfo.getMchNo()));
|
||||
if (memebrMaxbalance < totalBalance + payAmount + giveAmount) {
|
||||
throw new BizException("已超商家充值总余额上限!");
|
||||
}
|
||||
}
|
||||
|
||||
MemberRechargeRecord rechargeRecord = initMemberRechargeRecord(qrCodeParams, memberInfo, payAmount, giveAmount, getValString("remark"));
|
||||
return doPay(rechargeRecord, qrCodeParams, memberInfo);
|
||||
}
|
||||
|
||||
private ApiRes doPay(MemberRechargeRecord rechargeRecord, QRCodeParams qrCodeParams, MemberInfo memberInfo) {
|
||||
|
||||
// 会员充值仅支持码牌模式
|
||||
MchQrcodeCard mchQrcodeCard = mchQrcodeCardService.getById(qrCodeParams.getId());
|
||||
|
||||
PayOrderCreateRequest orderCreateRequest = new PayOrderCreateRequest();
|
||||
PayOrderCreateReqModelAddStoreId model = new PayOrderCreateReqModelAddStoreId();
|
||||
model.setPas(SysConfigService.PLATFORM_API_SECRET); // 通信秘钥
|
||||
orderCreateRequest.setBizModel(model);
|
||||
|
||||
model.setWayCode(rechargeRecord.getWayCode());
|
||||
if (CS.PAY_WAY_CODE_TYPE.WECHAT.equals(rechargeRecord.getWayCodeType())) {
|
||||
if(qrCodeParams.getPageType().equals(QRCodeParams.PAGE_TYPE_WECHAT_H5) ){
|
||||
model.setChannelExtra(JsonKit.newJson("openid", memberInfo.getWxMpOpenId()).toJSONString()); // 微信公众号openid
|
||||
}else if(qrCodeParams.getPageType().equals(QRCodeParams.PAGE_TYPE_WECHAT_LITE) ){
|
||||
model.setChannelExtra(JsonKit.newJson("openid", memberInfo.getWxLiteOpenId()).toJSONString()); // 微信小程序openid
|
||||
}
|
||||
|
||||
}else if (CS.PAY_WAY_CODE_TYPE.ALIPAY.equals(rechargeRecord.getWayCodeType())) {
|
||||
model.setChannelExtra(JsonKit.newJson("buyerUserId", memberInfo.getAliUserId()).toJSONString()); // 支付宝buyerUserId
|
||||
}else if (CS.PAY_WAY_CODE_TYPE.YSFPAY.equals(rechargeRecord.getWayCodeType())) {
|
||||
model.setChannelExtra(JsonKit.newJson("userId", memberInfo.getYsfUserId()).toJSONString()); // 云闪付userId
|
||||
}
|
||||
|
||||
MchAppEntity mchAppEntity = mchAppService.getById(mchQrcodeCard.getAppId()); // 商户应用
|
||||
|
||||
model.setStoreId(mchQrcodeCard.getStoreId()); // 门店ID
|
||||
model.setMchNo(rechargeRecord.getMchNo()); // 商户号
|
||||
model.setAppId(mchAppEntity.getAppId());
|
||||
model.setMchOrderNo(rechargeRecord.getRechargeRecordId()); // 商户号 <---> 充值记录ID
|
||||
model.setQrcId(qrCodeParams.getId()); // 码牌ID
|
||||
model.setAmount(rechargeRecord.getPayAmount()); // 充值记录 实际支付金额
|
||||
model.setCurrency("CNY");
|
||||
model.setClientIp(getClientIp());
|
||||
model.setSubject("[" + rechargeRecord.getMchNo() + "商户会员充值]");
|
||||
model.setBody("[" + rechargeRecord.getMchNo() + "商户会员充值]");
|
||||
model.setBuyerRemark(rechargeRecord.getRemark()); // 买家备注
|
||||
model.setNotifyUrl(rechargeRecord.getNotifyUrl()); //回调地址
|
||||
model.setReturnUrl(rechargeRecord.getReturnUrl()); //同步跳转地址
|
||||
model.setMbrId(memberInfo.getMbrId()); // 会员ID
|
||||
model.setMbrTel(memberInfo.getMbrTel()); // 会员手机号
|
||||
|
||||
|
||||
DeviceInfo deviceInfo = new DeviceInfo();
|
||||
deviceInfo.setDeviceNo(qrCodeParams.getId()); // 订单的qrcId
|
||||
deviceInfo.setDeviceType(PayOrder.DEVICE_TYPE_QR_CODE);
|
||||
|
||||
DBApplicationConfig dbApplicationConfig = sysConfigService.getDBApplicationConfig();
|
||||
JeepayClient jeepayClient = new JeepayClient(dbApplicationConfig.getPaySiteUrl(), mchAppEntity.getAppSecret());
|
||||
|
||||
try {
|
||||
// 发起支付
|
||||
PayOrderCreateResponse response = jeepayClient.execute(orderCreateRequest);
|
||||
|
||||
// 明确失败
|
||||
if(!response.isSuccess(mchAppEntity.getAppSecret())){
|
||||
// 更新充值订单为充值失败
|
||||
String errCode = response.getCode() == 0 ? response.get().getErrCode() : String.valueOf(response.getCode());
|
||||
String erMsg = response.getCode() == 0 ? response.get().getErrMsg() : response.getMsg();
|
||||
boolean result = memberRechargeRecordService.updateInit2Fail(rechargeRecord.getRechargeRecordId(), errCode, erMsg);
|
||||
if(!result){
|
||||
throw new BizException(ApiCodeEnum.SYS_OPERATION_FAIL_UPDATE);
|
||||
}
|
||||
return ApiRes.customFail(erMsg);
|
||||
}
|
||||
|
||||
// 更新充值订单为充值中
|
||||
PayOrderCreateResModel orderInfo = response.get();
|
||||
boolean result = memberRechargeRecordService.updateInit2Ing(rechargeRecord.getRechargeRecordId(), orderInfo.getPayOrderId());
|
||||
if(!result){
|
||||
throw new BizException(ApiCodeEnum.SYS_OPERATION_FAIL_UPDATE);
|
||||
}
|
||||
|
||||
JSONObject resultJSON = (JSONObject) JSONObject.toJSON(orderInfo);
|
||||
resultJSON.put("payAmount", AmountUtil.convertCent2Dollar(rechargeRecord.getPayAmount()));
|
||||
|
||||
return ApiRes.ok(resultJSON);
|
||||
} catch (JeepayException e) {
|
||||
throw new BizException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private MemberRechargeRecord initMemberRechargeRecord(QRCodeParams qrCodeParams, MemberInfo memberInfo, Long payAmount, Long giveAmount, String remark) {
|
||||
MchQrcodeCard mchQrcodeCard = mchQrcodeCardService.getById(qrCodeParams.getId());
|
||||
|
||||
MemberRechargeRecord rechargeRecord = new MemberRechargeRecord();
|
||||
rechargeRecord.setRechargeRecordId(SeqKit.genMhoOrderId()); // 商户单号
|
||||
rechargeRecord.setMbrId(memberInfo.getMbrId());
|
||||
rechargeRecord.setMbrName(memberInfo.getMbrName());
|
||||
rechargeRecord.setMbrTel(memberInfo.getMbrTel());
|
||||
rechargeRecord.setMchNo(memberInfo.getMchNo());
|
||||
rechargeRecord.setPayAmount(payAmount); // 支付金额
|
||||
rechargeRecord.setGiveAmount(giveAmount);
|
||||
rechargeRecord.setEntryAmount(payAmount + defaultLong(giveAmount)); // 账户入账金额
|
||||
rechargeRecord.setState(MemberRechargeRecord.STATE_INIT);
|
||||
|
||||
covertWayCode(qrCodeParams, rechargeRecord);
|
||||
MchApplyment applyment = mchApplymentService.getById(mchQrcodeCard.getMchApplyId());
|
||||
DBApplicationConfig dbApplicationConfig = sysConfigService.getDBApplicationConfig();
|
||||
rechargeRecord.setReturnUrl(dbApplicationConfig.genUniJsapiPayUrl(QRCodeParams.TYPE_QRC, mchQrcodeCard.getEntryPage(), mchQrcodeCard.getQrcId() + "", applyment.getIsvNo())); //同步跳转地址
|
||||
rechargeRecord.setNotifyUrl(dbApplicationConfig.getMemberSiteUrl() + "/api/anon/notify/memberRecharge"); //回调地址
|
||||
rechargeRecord.setRemark(remark);
|
||||
|
||||
boolean result = memberRechargeRecordService.save(rechargeRecord);
|
||||
if (!result) {
|
||||
throw new BizException("充值失败");
|
||||
}
|
||||
return rechargeRecord;
|
||||
}
|
||||
|
||||
/** 转换支付方式 */
|
||||
private void covertWayCode(QRCodeParams qrCodeParams, MemberRechargeRecord rechargeRecord){
|
||||
|
||||
// 是否商户自己的小程序调起的
|
||||
Byte isUseSubmchAccount = getValByteDefault("isUseSubmchAccount", CS.NO);
|
||||
|
||||
// 获取到当前页面类型
|
||||
String currentPageType = qrCodeParams.getPageType();
|
||||
|
||||
// 支付宝内 && 自行创建二维码
|
||||
if(QRCodeParams.PAGE_TYPE_ALIPAY_H5.equals(currentPageType) && qrCodeParams.getType() == QRCodeParams.TYPE_QRC){
|
||||
MchQrcodeCard mchQrCode = mchQrcodeCardService.getById(qrCodeParams.getId());
|
||||
if(CS.PAY_WAY_CODE.ALI_WAP.equals(mchQrCode.getAlipayWayCode())){ //wap支付, 无需获取
|
||||
throw new BizException("支付宝wap或自行创建二维码不支持此功能");
|
||||
}
|
||||
}
|
||||
|
||||
if(currentPageType.equals(QRCodeParams.PAGE_TYPE_ALIPAY_H5) ){
|
||||
rechargeRecord.setWayCode(CS.PAY_WAY_CODE.ALI_JSAPI);
|
||||
rechargeRecord.setWayCodeType(CS.PAY_WAY_CODE_TYPE.ALIPAY);
|
||||
|
||||
}else if( currentPageType.equals(QRCodeParams.PAGE_TYPE_ALIPAY_LITE)) {
|
||||
rechargeRecord.setWayCode(CS.PAY_WAY_CODE.ALI_LITE);
|
||||
rechargeRecord.setWayCodeType(CS.PAY_WAY_CODE_TYPE.ALIPAY);
|
||||
|
||||
}else if(currentPageType.equals(QRCodeParams.PAGE_TYPE_WECHAT_H5) ){
|
||||
rechargeRecord.setWayCode(CS.PAY_WAY_CODE.WX_JSAPI);
|
||||
rechargeRecord.setWayCodeType(CS.PAY_WAY_CODE_TYPE.WECHAT);
|
||||
|
||||
}else if(currentPageType.equals(QRCodeParams.PAGE_TYPE_WECHAT_LITE) ){
|
||||
rechargeRecord.setWayCode(CS.PAY_WAY_CODE.WX_LITE);
|
||||
rechargeRecord.setWayCodeType(CS.PAY_WAY_CODE_TYPE.WECHAT);
|
||||
|
||||
}else if(currentPageType.equals(QRCodeParams.PAGE_TYPE_YSFPAY_H5) ){
|
||||
rechargeRecord.setWayCode(CS.PAY_WAY_CODE.YSF_JSAPI);
|
||||
rechargeRecord.setWayCodeType(CS.PAY_WAY_CODE_TYPE.YSFPAY);
|
||||
|
||||
}else {
|
||||
throw new BizException("不支持的客户端");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Long defaultLong(Long amount) {
|
||||
if (amount == null) {
|
||||
return 0L;
|
||||
}
|
||||
return amount;
|
||||
}
|
||||
|
||||
|
||||
/** 与阿里云sdk一样, 直接extends PayOrderCreateReqModel无法传入到接口中对应的参数。 需要把所有的参数放进来。。。 = = 。 **/
|
||||
@Data
|
||||
public static class PayOrderCreateReqModelAddStoreId extends JeepayObject {
|
||||
|
||||
@ApiField("pas")
|
||||
private String pas;
|
||||
|
||||
@ApiField("storeId")
|
||||
private String storeId;
|
||||
@ApiField("qrcId")
|
||||
private String qrcId;
|
||||
|
||||
private static final long serialVersionUID = -3998573128290306948L;
|
||||
|
||||
@ApiField("mchNo")
|
||||
private String mchNo; // 商户号
|
||||
@ApiField("appId")
|
||||
private String appId; // 应用ID
|
||||
@ApiField("mchOrderNo")
|
||||
String mchOrderNo; // 商户订单号
|
||||
@ApiField("wayCode")
|
||||
String wayCode; // 支付方式
|
||||
@ApiField("amount")
|
||||
Long amount; // 支付金额
|
||||
@ApiField("currency")
|
||||
String currency; // 货币代码,当前只支持cny
|
||||
@ApiField("clientIp")
|
||||
String clientIp; // 客户端IP
|
||||
@ApiField("subject")
|
||||
String subject; // 商品标题
|
||||
@ApiField("body")
|
||||
String body; // 商品描述
|
||||
@ApiField("channelBizData")
|
||||
String channelBizData; // 渠道业务参数
|
||||
@ApiField("notifyUrl")
|
||||
String notifyUrl; // 异步通知地址
|
||||
@ApiField("returnUrl")
|
||||
String returnUrl; // 跳转通知地址
|
||||
@ApiField("expiredTime")
|
||||
String expiredTime; // 订单失效时间
|
||||
@ApiField("channelExtra")
|
||||
String channelExtra; // 特定渠道额外支付参数
|
||||
@ApiField("extParam")
|
||||
String extParam; // 商户扩展参数
|
||||
@ApiField("divisionMode")
|
||||
private Byte divisionMode; // 分账模式: 0-该笔订单不允许分账[默认], 1-支付成功按配置自动完成分账, 2-商户手动分账(解冻商户金额)
|
||||
@ApiField("sellerRemark")
|
||||
String sellerRemark; // 卖家备注
|
||||
@ApiField("buyerRemark")
|
||||
String buyerRemark; // 买家备注
|
||||
@ApiField("deviceInfo")
|
||||
private DeviceInfo deviceInfo; // 设备信息
|
||||
@ApiField("mbrId")
|
||||
private String mbrId; // 会员ID
|
||||
@ApiField("mbrTel")
|
||||
private String mbrTel; // 会员手机号
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package com.jeequan.jeepay.member.ctrl.member;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.jeequan.jeepay.db.entity.MchAppEntity;
|
||||
import com.jeequan.jeepay.db.entity.MemberRechargeRecord;
|
||||
import com.jeequan.jeepay.db.entity.PayOrder;
|
||||
import com.jeequan.jeepay.member.ctrl.CommonCtrl;
|
||||
import com.jeequan.jeepay.service.impl.MchAppService;
|
||||
import com.jeequan.jeepay.service.impl.MemberRechargeRecordService;
|
||||
import com.jeequan.jeepay.util.JeepayKit;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/*
|
||||
* 会员充值 - 回调函数
|
||||
*
|
||||
* @author zx
|
||||
* @date 2023/4/12 14:22
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/anon/notify")
|
||||
public class MemberRechargeNotifyController extends CommonCtrl {
|
||||
|
||||
@Autowired private MchAppService mchAppService;
|
||||
@Autowired private MemberRechargeRecordService memberRechargeRecordService;
|
||||
|
||||
/** 会员充值 - 回调函数 */
|
||||
@RequestMapping("/memberRecharge")
|
||||
public String memberRechargeNotify() {
|
||||
|
||||
String logPrefix = "===== 进入【商户会员充值回调】=====";
|
||||
|
||||
//请求参数
|
||||
JSONObject params = getReqParamJSON();
|
||||
log.info("{}通知参数={}", logPrefix, params.toJSONString());
|
||||
|
||||
// 充值记录
|
||||
String rechargeRecordId = getValString("mchOrderNo"); // 充值单号
|
||||
MemberRechargeRecord rechargeRecord = memberRechargeRecordService.getById(rechargeRecordId);
|
||||
if (rechargeRecord == null) {
|
||||
log.warn("{}充值记录不存在,充值记录ID={}", logPrefix, rechargeRecordId);
|
||||
return "memberRechargeRecord is not exists";
|
||||
}
|
||||
if (rechargeRecord.getState() == MemberRechargeRecord.STATE_SUCCESS || rechargeRecord.getState() == MemberRechargeRecord.STATE_FAIL) {
|
||||
log.info("{}充值记录状态已完结,状态={}, 充值记录ID={}", logPrefix, rechargeRecord.getState(), rechargeRecordId);
|
||||
return "success";
|
||||
}
|
||||
|
||||
String mchNo = params.getString("mchNo");
|
||||
String appId = params.getString("appId");
|
||||
String sign = params.getString("sign");
|
||||
MchAppEntity mchAppEntity = mchAppService.getById(appId);
|
||||
if(mchAppEntity == null || !mchAppEntity.getMchNo().equals(mchNo)){
|
||||
log.warn("{}商户应用不存在,充值记录ID={}", logPrefix, rechargeRecordId);
|
||||
return "app is not exists";
|
||||
}
|
||||
|
||||
// 验签
|
||||
params.remove("sign");
|
||||
if(!JeepayKit.getSign(params, mchAppEntity.getAppSecret()).equalsIgnoreCase(sign)){
|
||||
log.warn("{}验签失败,充值记录ID={}", logPrefix, rechargeRecordId);
|
||||
return "sign fail";
|
||||
}
|
||||
|
||||
int payOrderState = params.getInteger("state"); // 支付订单状态 0-订单生成 1-支付中 2-支付成功 3-支付失败
|
||||
|
||||
boolean updateOrderSuccess = true; //默认更新成功
|
||||
// 支付成功
|
||||
if (payOrderState == PayOrder.STATE_SUCCESS) {
|
||||
updateOrderSuccess = memberRechargeRecordService.updateIng2SuccessAndMbrAccount(rechargeRecordId, params.getString("payOrderId"));
|
||||
|
||||
// 支付失败
|
||||
}else if (payOrderState == PayOrder.STATE_FAIL) {
|
||||
updateOrderSuccess = memberRechargeRecordService.updateIng2Fail(rechargeRecordId, params.getString("errCode"), params.getString("errMsg"));
|
||||
}
|
||||
// 更新订单 异常
|
||||
if(!updateOrderSuccess){
|
||||
log.error("{},充值记录ID={},updateOrderSuccess={} ", logPrefix, rechargeRecordId, updateOrderSuccess);
|
||||
return "fail";
|
||||
}
|
||||
|
||||
log.info("===== {}, 通知完成。 充值记录ID={}, payOrderState={} =====", logPrefix, rechargeRecordId, payOrderState);
|
||||
return "success";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package com.jeequan.jeepay.member.ctrl.member;
|
||||
|
||||
import cn.hutool.core.util.DesensitizedUtil;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
|
||||
import com.jeequan.jeepay.core.model.ApiRes;
|
||||
import com.jeequan.jeepay.db.entity.MemberRechargeRecord;
|
||||
import com.jeequan.jeepay.db.entity.PayWay;
|
||||
import com.jeequan.jeepay.member.ctrl.CommonCtrl;
|
||||
import com.jeequan.jeepay.service.impl.MemberRechargeRecordService;
|
||||
import com.jeequan.jeepay.service.impl.PayWayService;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
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;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 会员充值记录
|
||||
*
|
||||
* @author xiaoyu
|
||||
* @date 2023/4/13 17:22
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/member/rechargeRecord")
|
||||
public class MemberRechargeRecordController extends CommonCtrl {
|
||||
|
||||
@Autowired private MemberRechargeRecordService rechargeRecordService;
|
||||
@Autowired private PayWayService payWayService;
|
||||
|
||||
/**
|
||||
* @author: xiaoyu
|
||||
* @date: 2023/4/13 17:24
|
||||
* @describe: 会员充值记录列表
|
||||
*/
|
||||
@GetMapping
|
||||
public ApiRes list() {
|
||||
MemberRechargeRecord rechargeRecord = getObject(MemberRechargeRecord.class);
|
||||
|
||||
LambdaQueryWrapper<MemberRechargeRecord> wrapper = MemberRechargeRecord.gw();
|
||||
|
||||
wrapper.eq(MemberRechargeRecord::getMbrId, getCurrentMbrId());
|
||||
// 查询参数
|
||||
rechargeRecordService.selectParams(rechargeRecord, wrapper);
|
||||
|
||||
// 额外条件参数
|
||||
JSONObject paramJSON = getReqParamJSON();
|
||||
|
||||
// 二合一 会员名称/订单号/手机号
|
||||
if (paramJSON != null && StringUtils.isNotEmpty(paramJSON.getString("unionQueryParam"))) {
|
||||
wrapper.and(wr -> {
|
||||
wr.like(MemberRechargeRecord::getMbrTel, paramJSON.getString("unionQueryParam"))
|
||||
.or().like(MemberRechargeRecord::getMbrName, paramJSON.getString("unionQueryParam"))
|
||||
.or().like(MemberRechargeRecord::getPayOrderId, paramJSON.getString("unionQueryParam"));
|
||||
});
|
||||
}
|
||||
|
||||
wrapper.orderByDesc(MemberRechargeRecord::getCreatedAt);
|
||||
|
||||
IPage<MemberRechargeRecord> page = rechargeRecordService.page(getIPage(), wrapper);
|
||||
|
||||
// 得到所有支付方式
|
||||
Map<String, String> payWayNameMap = new HashMap<>();
|
||||
List<PayWay> payWayList = payWayService.list();
|
||||
// 手机号脱敏、支付方式名称赋值
|
||||
page.getRecords().stream().forEach(i -> {
|
||||
i.setMbrTel(DesensitizedUtil.mobilePhone(i.getMbrTel()));
|
||||
if (!CollectionUtils.isEmpty(payWayList)) {
|
||||
for (PayWay payWay:payWayList) {
|
||||
payWayNameMap.put(payWay.getWayCode(), payWay.getWayName());
|
||||
}
|
||||
// 存入支付方式名称
|
||||
if (StringUtils.isNotEmpty(payWayNameMap.get(i.getWayCode()))) {
|
||||
i.addExt("wayName", payWayNameMap.get(i.getWayCode()));
|
||||
}else {
|
||||
i.addExt("wayName", i.getWayCode());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return ApiRes.page(page);
|
||||
}
|
||||
|
||||
/**
|
||||
* @author: xiaoyu
|
||||
* @date: 2023/4/13 17:49
|
||||
* @describe: 会员充值记录详情
|
||||
*/
|
||||
@GetMapping("/{recordId}")
|
||||
public ApiRes detail(@PathVariable("recordId") String recordId) {
|
||||
|
||||
MemberRechargeRecord record = rechargeRecordService.getById(recordId);
|
||||
|
||||
if (record == null || !record.getMbrId().equals(getCurrentMbrId())) {
|
||||
return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH);
|
||||
}
|
||||
|
||||
return ApiRes.ok(record);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.jeequan.jeepay.member.mq;
|
||||
|
||||
import com.jeequan.jeepay.components.mq.model.ResetAppConfigMQ;
|
||||
import com.jeequan.jeepay.core.interfaces.push.IBaiduBceService;
|
||||
import com.jeequan.jeepay.core.utils.SpringBeansUtil;
|
||||
import com.jeequan.jeepay.service.impl.SysConfigService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 接收MQ消息
|
||||
* 业务: 更新系统配置参数
|
||||
* @author terrfly
|
||||
* @date 2021/7/27 9:23
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class ResetAppConfigMQReceiver implements ResetAppConfigMQ.IMQReceiver {
|
||||
|
||||
@Autowired
|
||||
private SysConfigService sysConfigService;
|
||||
|
||||
@Override
|
||||
public void receive(ResetAppConfigMQ.MsgPayload payload) {
|
||||
|
||||
log.info("成功接收更新系统配置的订阅通知, msg={}", payload);
|
||||
sysConfigService.initDBConfig(payload.getGroupKey());
|
||||
|
||||
// 修改百度语音配置需清空redis缓存的百度token
|
||||
if (SysConfigService.BAIDU_BCE_CONFIG.getLeft().equals(payload.getGroupKey())) {
|
||||
IBaiduBceService baiduBceService = SpringBeansUtil.getBean("baiduBceService", IBaiduBceService.class);
|
||||
baiduBceService.clearBaiduBceTokenCache(SysConfigService.BAIDU_BCE_CONFIG.getRight());
|
||||
}
|
||||
log.info("系统配置静态属性已重置");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.jeequan.jeepay.member.mq;
|
||||
|
||||
import com.jeequan.jeepay.components.mq.model.ResetIsvMchAppInfoConfigMQ;
|
||||
import com.jeequan.jeepay.core.interfaces.IConfigContextService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 接收MQ消息
|
||||
* 业务: 更新服务商/商户/商户应用配置信息;
|
||||
*
|
||||
* @author terrfly
|
||||
* @since 2021/7/27 9:23
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class ResetIsvMchAppInfoMQReceiver implements ResetIsvMchAppInfoConfigMQ.IMQReceiver {
|
||||
|
||||
@Autowired(required = false)
|
||||
private IConfigContextService configContextService;
|
||||
|
||||
@Override
|
||||
public void receive(ResetIsvMchAppInfoConfigMQ.MsgPayload payload) {
|
||||
|
||||
if (payload.getResetType() == ResetIsvMchAppInfoConfigMQ.RESET_TYPE_ISV_INFO) {
|
||||
this.modifyIsvInfo(payload.getIsvNo());
|
||||
} else if (payload.getResetType() == ResetIsvMchAppInfoConfigMQ.RESET_TYPE_MCH_INFO) {
|
||||
this.modifyMchInfo(payload.getMchNo());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 接收 [商户配置信息] 的消息
|
||||
*/
|
||||
private void modifyMchInfo(String mchNo) {
|
||||
log.info("成功接收 [商户配置信息] 的消息, msg={}", mchNo);
|
||||
if (configContextService != null) configContextService.initMchInfoConfigContext(mchNo);
|
||||
log.info(" [商户配置信息] 已重置");
|
||||
}
|
||||
|
||||
/**
|
||||
* 接收 [商户应用支付参数配置信息] 的消息
|
||||
*/
|
||||
private void modifyMchApp(String mchNo, String appId) {
|
||||
log.info("成功接收 [商户应用支付参数配置信息] 的消息, mchNo={}, appId={}", mchNo, appId);
|
||||
if (configContextService != null) configContextService.initMchAppConfigContext(mchNo, appId);
|
||||
log.info(" [商户应用支付参数配置信息] 已重置");
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置ISV信息
|
||||
*/
|
||||
private void modifyIsvInfo(String isvNo) {
|
||||
log.info("成功接收 [ISV信息] 重置, msg={}", isvNo);
|
||||
if (configContextService != null) configContextService.initIsvConfigContext(isvNo);
|
||||
log.info("[ISV信息] 已重置");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.jeequan.jeepay.member.secruity;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.jeequan.jeepay.core.utils.DateKit;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* JWT payload 载体
|
||||
* 格式:
|
||||
* {
|
||||
* "mbrId": "10001",
|
||||
* "created": "1568250147846",
|
||||
* "cacheKey": "KEYKEYKEYKEY",
|
||||
* }
|
||||
*
|
||||
* @author terrfly
|
||||
* @date 2021/6/8 18:01
|
||||
*/
|
||||
@Data
|
||||
public class JWTPayload {
|
||||
|
||||
private String mbrId; //登录会员ID
|
||||
private Long created; //创建时间, 格式:13位时间戳
|
||||
private String cacheKey; //redis保存的key
|
||||
|
||||
protected JWTPayload() {
|
||||
}
|
||||
|
||||
public JWTPayload(JeeMemberDetails jeeMemberDetails) {
|
||||
|
||||
this.setMbrId(jeeMemberDetails.getMemberInfo().getMbrId());
|
||||
this.setCreated(DateKit.currentTimeMillis());
|
||||
this.setCacheKey(jeeMemberDetails.getCacheKey());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* toMap
|
||||
**/
|
||||
public Map<String, Object> toMap() {
|
||||
JSONObject json = (JSONObject) JSONObject.toJSON(this);
|
||||
return json.toJavaObject(Map.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.jeequan.jeepay.member.secruity;
|
||||
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.SignatureAlgorithm;
|
||||
|
||||
/**
|
||||
* JWT工具包
|
||||
*
|
||||
* @author terrfly
|
||||
* @date 2021/6/8 16:32
|
||||
*/
|
||||
public class JWTUtils {
|
||||
|
||||
public static long EXPIRED_TIME = 10 * 60;
|
||||
|
||||
/**
|
||||
* 生成token
|
||||
**/
|
||||
public static String generateToken(JWTPayload jwtPayload, String jwtSecret) {
|
||||
return Jwts.builder()
|
||||
.setClaims(jwtPayload.toMap())
|
||||
//过期时间 = 当前时间 + (设置过期时间[单位 :s ] ) token放置redis 过期时间无意义
|
||||
//.setExpiration(new Date(DateKit.currentTimeMillis() + (jwtExpiration * 1000) ))
|
||||
.signWith(SignatureAlgorithm.HS512, jwtSecret)
|
||||
.compact();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据token与秘钥 解析token并转换为 JWTPayload
|
||||
**/
|
||||
public static JWTPayload parseToken(String token, String secret) {
|
||||
try {
|
||||
Claims claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
|
||||
|
||||
JWTPayload result = new JWTPayload();
|
||||
result.setMbrId(claims.get("mbrId", String.class));
|
||||
result.setCreated(claims.get("created", Long.class));
|
||||
result.setCacheKey(claims.get("cacheKey", String.class));
|
||||
|
||||
return result;
|
||||
|
||||
} catch (Exception e) {
|
||||
return null; //解析失败
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.jeequan.jeepay.member.secruity;
|
||||
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 用户身份认证失败处理类
|
||||
*
|
||||
* @author terrfly
|
||||
* @date 2021/6/8 17:11
|
||||
*/
|
||||
@Component
|
||||
public class JeeAuthenticationEntryPoint implements AuthenticationEntryPoint, Serializable {
|
||||
|
||||
@Override
|
||||
public void commence(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
AuthenticationException authException) throws IOException {
|
||||
// This is invoked when user tries to access a secured REST resource without supplying any credentials
|
||||
// We should just send a 401 Unauthorized response because there is no 'login page' to redirect to
|
||||
|
||||
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
|
||||
|
||||
//返回json形式的错误信息
|
||||
// response.setCharacterEncoding("UTF-8");
|
||||
// response.setContentType("application/json");
|
||||
// response.getWriter().println("{\"code\":1001, \"msg\":\"Unauthorized\"}");
|
||||
response.getWriter().flush();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package com.jeequan.jeepay.member.secruity;
|
||||
|
||||
import com.jeequan.jeepay.core.cache.RedisUtil;
|
||||
import com.jeequan.jeepay.core.constants.CS;
|
||||
import com.jeequan.jeepay.core.utils.SpringBeansUtil;
|
||||
import com.jeequan.jeepay.member.config.SystemYmlConfig;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* <p><b>Title: </b>JwtAuthenticationTokenFilter.java
|
||||
* <p><b>Description: </b>
|
||||
* spring security框架中验证组件的前置过滤器;
|
||||
* 用于验证token有效期,并放置ContextAuthentication信息,为后续spring security框架验证提供数据;
|
||||
* 避免使用@Component等bean自动装配注解:@Component会将filter被spring实例化为web容器的全局filter,导致重复过滤。
|
||||
* @modify terrfly
|
||||
* @version V1.0
|
||||
*
|
||||
* @date 2021-04-27 15:50
|
||||
* <p>
|
||||
*/
|
||||
public class JeeAuthenticationTokenFilter extends OncePerRequestFilter {
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
|
||||
|
||||
JeeMemberDetails jeeMemberDetails = commonFilter(request);
|
||||
|
||||
if(jeeMemberDetails == null){
|
||||
chain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
//将信息放置到Spring-security context中
|
||||
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(jeeMemberDetails, null, null);
|
||||
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
|
||||
private JeeMemberDetails commonFilter(HttpServletRequest request){
|
||||
|
||||
String authToken = request.getHeader(CS.ACCESS_TOKEN_NAME);
|
||||
if(StringUtils.isEmpty(authToken)){
|
||||
authToken = request.getParameter(CS.ACCESS_TOKEN_NAME);
|
||||
}
|
||||
if(StringUtils.isEmpty(authToken)){
|
||||
return null; //放行,并交给UsernamePasswordAuthenticationFilter进行验证,返回公共错误信息.
|
||||
}
|
||||
|
||||
JWTPayload jwtPayload = JWTUtils.parseToken(authToken, SpringBeansUtil.getBean(SystemYmlConfig.class).getJwtSecret()); //反解析token信息
|
||||
//token字符串解析失败
|
||||
if( jwtPayload == null || StringUtils.isEmpty(jwtPayload.getCacheKey())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
//根据用户名查找数据库
|
||||
JeeMemberDetails jwtBaseUser = RedisUtil.getObject(jwtPayload.getCacheKey(), JeeMemberDetails.class);
|
||||
if(jwtBaseUser == null){ // 找不到对应的缓存
|
||||
RedisUtil.del(jwtPayload.getCacheKey());
|
||||
return null; //数据库查询失败,删除redis
|
||||
}
|
||||
|
||||
//续签时间
|
||||
RedisUtil.expire(jwtPayload.getCacheKey(), JWTUtils.EXPIRED_TIME);
|
||||
|
||||
return jwtBaseUser;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
package com.jeequan.jeepay.member.secruity;
|
||||
|
||||
import com.jeequan.jeepay.db.entity.MemberInfo;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* 实现Spring Security的UserDetails接口
|
||||
*
|
||||
* @author zx
|
||||
* @date 2023/4/8 16:34
|
||||
*/
|
||||
@Slf4j
|
||||
@Data
|
||||
public class JeeMemberDetails implements UserDetails {
|
||||
|
||||
/**
|
||||
* 会员信息
|
||||
**/
|
||||
private MemberInfo memberInfo;
|
||||
|
||||
/**
|
||||
* 密码
|
||||
**/
|
||||
private String credential;
|
||||
|
||||
/**
|
||||
* 角色+权限 集合 (角色必须以: ROLE_ 开头)
|
||||
**/
|
||||
private Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 缓存标志
|
||||
**/
|
||||
private String cacheKey;
|
||||
|
||||
/**
|
||||
* 登录IP
|
||||
**/
|
||||
private String loginIp;
|
||||
|
||||
/**
|
||||
* 认证类型,见 CREDENTIAL_AUTH_TYPE
|
||||
**/
|
||||
private String authType;
|
||||
|
||||
//此处的无参构造,为json反序列化提供
|
||||
public JeeMemberDetails() {
|
||||
}
|
||||
|
||||
public JeeMemberDetails(MemberInfo memberInfo) {
|
||||
this.setMemberInfo(memberInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* spring-security 需要验证的密码
|
||||
**/
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return getCredential();
|
||||
}
|
||||
|
||||
/**
|
||||
* spring-security 登录名
|
||||
**/
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return getMemberInfo().getMbrId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 账户是否过期
|
||||
**/
|
||||
@Override
|
||||
public boolean isAccountNonExpired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 账户是否已解锁
|
||||
**/
|
||||
@Override
|
||||
public boolean isAccountNonLocked() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 密码是否过期
|
||||
**/
|
||||
@Override
|
||||
public boolean isCredentialsNonExpired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 账户是否开启
|
||||
**/
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取权限集合
|
||||
**/
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
return authorities;
|
||||
}
|
||||
|
||||
public static JeeMemberDetails getCurrentMemberDetails() {
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
if (authentication == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return (JeeMemberDetails) authentication.getPrincipal();
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前登录者ID
|
||||
**/
|
||||
public String getMbrId() {
|
||||
return this.getMemberInfo() != null ? this.getMemberInfo().getMbrId() : null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.jeequan.jeepay.member.secruity;
|
||||
|
||||
import com.jeequan.jeepay.core.constants.CS;
|
||||
import com.jeequan.jeepay.core.exception.JeepayAuthenticationException;
|
||||
import com.jeequan.jeepay.db.entity.MemberInfo;
|
||||
import com.jeequan.jeepay.service.impl.MemberInfoService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* UserDetailsService实现类
|
||||
*
|
||||
* @author terrfly
|
||||
* @modify zhuxiao
|
||||
* @date 2021-04-27 15:50
|
||||
*/
|
||||
@Service
|
||||
public class JeeUserDetailsServiceImpl implements UserDetailsService {
|
||||
|
||||
@Autowired private MemberInfoService memberInfoService;
|
||||
|
||||
@Override
|
||||
public UserDetails loadUserByUsername(String loginUsernameStr) throws UsernameNotFoundException {
|
||||
|
||||
MemberInfo memberInfo = memberInfoService.getById(loginUsernameStr);
|
||||
if(memberInfo == null){ //没有该用户信息
|
||||
throw JeepayAuthenticationException.build("用户名/密码错误!");
|
||||
}
|
||||
if(CS.PUB_USABLE != memberInfo.getState()){ //状态不合法
|
||||
throw JeepayAuthenticationException.build("用户状态不可登录,请联系管理员!");
|
||||
}
|
||||
|
||||
return new JeeMemberDetails(memberInfo);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
package com.jeequan.jeepay.member.secruity;
|
||||
|
||||
import com.jeequan.jeepay.member.config.SystemYmlConfig;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
import org.springframework.web.filter.CorsFilter;
|
||||
|
||||
/**
|
||||
* Spring Security 配置项
|
||||
*
|
||||
* @author terrfly
|
||||
* @date 2021/6/8 17:11
|
||||
*/
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true) //开启@PreAuthorize @PostAuthorize 等前置后置安全校验注解
|
||||
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
|
||||
|
||||
@Autowired private UserDetailsService userDetailsService;
|
||||
@Autowired private JeeAuthenticationEntryPoint unauthorizedHandler;
|
||||
@Autowired private SystemYmlConfig systemYmlConfig;
|
||||
|
||||
@Bean
|
||||
@Override
|
||||
public AuthenticationManager authenticationManagerBean() throws Exception {
|
||||
return super.authenticationManagerBean();
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用BCrypt强哈希函数 实现PasswordEncoder
|
||||
* **/
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
|
||||
authenticationManagerBuilder
|
||||
.userDetailsService(this.userDetailsService)
|
||||
.passwordEncoder(passwordEncoder());
|
||||
}
|
||||
|
||||
/** 允许跨域请求 **/
|
||||
@Bean
|
||||
public CorsFilter corsFilter() {
|
||||
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||
if(systemYmlConfig.getAllowCors()){
|
||||
CorsConfiguration config = new CorsConfiguration();
|
||||
config.setAllowCredentials(true); //带上cookie信息
|
||||
// config.addAllowedOrigin(CorsConfiguration.ALL); //允许跨域的域名, *表示允许任何域名使用
|
||||
config.addAllowedOriginPattern(CorsConfiguration.ALL); //使用addAllowedOriginPattern 避免出现 When allowCredentials is true, allowedOrigins cannot contain the special value "*" since that cannot be set on the "Access-Control-Allow-Origin" response header. To allow credentials to a set of origins, list them explicitly or consider using "allowedOriginPatterns" instead.
|
||||
config.addAllowedHeader(CorsConfiguration.ALL); //允许任何请求头
|
||||
config.addAllowedMethod(CorsConfiguration.ALL); //允许任何方法(post、get等)
|
||||
source.registerCorsConfiguration("/**", config); // CORS 配置对所有接口都有效
|
||||
}
|
||||
return new CorsFilter(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity httpSecurity) throws Exception {
|
||||
httpSecurity
|
||||
// 由于使用的是JWT,我们这里不需要csrf
|
||||
.csrf().disable()
|
||||
|
||||
.cors().and()
|
||||
|
||||
// 认证失败处理方式
|
||||
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
|
||||
|
||||
// 基于token,所以不需要session
|
||||
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
|
||||
|
||||
.authorizeRequests()
|
||||
|
||||
// 除上面外的所有请求全部需要鉴权认证
|
||||
.anyRequest().authenticated();
|
||||
|
||||
// 添加JWT filter
|
||||
httpSecurity.addFilterBefore(new JeeAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
|
||||
|
||||
// 禁用缓存
|
||||
httpSecurity.headers().cacheControl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(WebSecurity web) throws Exception {
|
||||
//ignore文件 : 无需进入spring security 框架
|
||||
// 1.允许对于网站静态资源的无授权访问
|
||||
// 2.对于获取token的rest api要允许匿名访问
|
||||
web.ignoring().antMatchers(
|
||||
HttpMethod.GET,
|
||||
"/",
|
||||
"/*.html",
|
||||
"/favicon.ico",
|
||||
"/**/*.html",
|
||||
"/**/*.css",
|
||||
"/**/*.js",
|
||||
"/**/*.png",
|
||||
"/**/*.jpg",
|
||||
"/**/*.jpeg",
|
||||
"/**/*.svg",
|
||||
"/**/*.ico",
|
||||
"/**/*.webp",
|
||||
"/*.txt",
|
||||
"/**/*.xls",
|
||||
"/**/*.mp4" //支持mp4格式的文件匿名访问
|
||||
)
|
||||
.antMatchers(
|
||||
"/api/anon/**" //匿名访问接口
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package com.jeequan.jeepay.member.service;
|
||||
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import com.jeequan.jeepay.core.cache.RedisUtil;
|
||||
import com.jeequan.jeepay.core.constants.CS;
|
||||
import com.jeequan.jeepay.db.entity.MemberInfo;
|
||||
import com.jeequan.jeepay.member.config.SystemYmlConfig;
|
||||
import com.jeequan.jeepay.member.secruity.JWTPayload;
|
||||
import com.jeequan.jeepay.member.secruity.JWTUtils;
|
||||
import com.jeequan.jeepay.member.secruity.JeeMemberDetails;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 认证Service
|
||||
*
|
||||
* @modify zhuxiao
|
||||
* @date 2021-04-27 15:50
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class AuthService {
|
||||
|
||||
@Autowired private SystemYmlConfig systemYmlConfig;
|
||||
@Autowired private UserDetailsService userDetailsService;
|
||||
|
||||
// 通过 mbrId 登录
|
||||
public String authByMbrId(String mbrId, String existsCacheKey){
|
||||
return userDetailsProcess(userDetailsService.loadUserByUsername(mbrId), existsCacheKey);
|
||||
}
|
||||
|
||||
/** 根据用户ID 删除用户缓存信息 **/
|
||||
public void delAuthentication(List<Long> sysUserIdList){
|
||||
if(sysUserIdList == null || sysUserIdList.isEmpty()){
|
||||
return ;
|
||||
}
|
||||
for (Long sysUserId : sysUserIdList) {
|
||||
Collection<String> cacheKeyList = RedisUtil.keys(CS.getCacheKeyToken(sysUserId, "*"));
|
||||
if(cacheKeyList == null || cacheKeyList.isEmpty()){
|
||||
continue;
|
||||
}
|
||||
for (String cacheKey : cacheKeyList) {
|
||||
RedisUtil.del(cacheKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 获取到userDetail之后的操作 **/
|
||||
public String userDetailsProcess(UserDetails userDetails, String existsCacheKey) {
|
||||
|
||||
JeeMemberDetails jeeMemberDetails = (JeeMemberDetails) userDetails;
|
||||
|
||||
//验证通过后 再查询用户角色和权限信息集合
|
||||
MemberInfo memberInfo = jeeMemberDetails.getMemberInfo();
|
||||
|
||||
//生成token
|
||||
String cacheKey = StringUtils.isNotEmpty(existsCacheKey) ? existsCacheKey : CS.getCacheKeyToken(memberInfo.getMbrId(), IdUtil.fastUUID());
|
||||
|
||||
//生成iToken 并放置到缓存
|
||||
jeeMemberDetails.setCacheKey(cacheKey);
|
||||
RedisUtil.set(cacheKey, jeeMemberDetails, JWTUtils.EXPIRED_TIME); // 放置在redis,缓存时间10分钟,
|
||||
|
||||
//将信息放置到Spring-security context中
|
||||
UsernamePasswordAuthenticationToken authenticationRest = new UsernamePasswordAuthenticationToken(jeeMemberDetails, null, null);
|
||||
SecurityContextHolder.getContext().setAuthentication(authenticationRest);
|
||||
|
||||
//返回JWTToken
|
||||
return JWTUtils.generateToken(new JWTPayload(jeeMemberDetails), systemYmlConfig.getJwtSecret());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.jeequan.jeepay.member.service;
|
||||
|
||||
import com.jeequan.jeepay.core.constants.CS;
|
||||
import com.jeequan.jeepay.core.ctrls.AbstractCtrl;
|
||||
import com.jeequan.jeepay.member.config.SystemYmlConfig;
|
||||
import com.jeequan.jeepay.service.impl.*;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* 定义通用CommonService
|
||||
*
|
||||
* @author zx
|
||||
* @date 2023/4/8 17:09
|
||||
*/
|
||||
public abstract class CommonService extends AbstractCtrl {
|
||||
|
||||
@Autowired
|
||||
protected SystemYmlConfig mainConfig;
|
||||
|
||||
@Autowired
|
||||
protected PayInterfaceDefineService payInterfaceDefineService;
|
||||
|
||||
@Autowired
|
||||
protected MchInfoService mchInfoService;
|
||||
|
||||
@Autowired
|
||||
protected MchStoreService mchStoreService;
|
||||
|
||||
@Autowired
|
||||
protected AgentInfoService agentInfoService;
|
||||
|
||||
@Autowired
|
||||
protected SysConfigService sysConfigService;
|
||||
|
||||
/**
|
||||
* 获取当前用户登录IP
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected String getIp() {
|
||||
return getClientIp();
|
||||
}
|
||||
|
||||
/**
|
||||
* 会员头像地址默认值获取
|
||||
**/
|
||||
public String getMemberAvatarDefault() {
|
||||
Collections.shuffle(CS.MEMBER_AVATAR_ICON);
|
||||
return CS.MEMBER_AVATAR_ICON.get(0);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package com.jeequan.jeepay.member.service;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.jeequan.jeepay.core.constants.CS;
|
||||
import com.jeequan.jeepay.core.model.ApiRes;
|
||||
import com.jeequan.jeepay.core.model.context.MchAppConfigContext;
|
||||
import com.jeequan.jeepay.core.utils.JsonKit;
|
||||
import com.jeequan.jeepay.db.entity.MchConfig;
|
||||
import com.jeequan.jeepay.db.entity.MchStore;
|
||||
import com.jeequan.jeepay.db.entity.MemberRechargeRule;
|
||||
import com.jeequan.jeepay.service.impl.MchConfigService;
|
||||
import com.jeequan.jeepay.service.impl.MchStoreService;
|
||||
import com.jeequan.jeepay.service.impl.MemberRechargeRuleService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 商户充值规则服务类
|
||||
*
|
||||
* @author zx
|
||||
* @date 2023/4/8 17:40
|
||||
*/
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class MchRechargeRuleEntryService {
|
||||
|
||||
@Autowired
|
||||
private MemberRechargeRuleService memberRechargeRuleService;
|
||||
@Autowired
|
||||
private MchStoreService mchStoreService;
|
||||
@Autowired
|
||||
private MchConfigService mchConfigService;
|
||||
|
||||
/**
|
||||
* 获取商户充值规则
|
||||
*/
|
||||
public ApiRes getMchRechargeRule(MchAppConfigContext mchAppConfigContext) {
|
||||
|
||||
String mchNo = mchAppConfigContext.getMchNo();
|
||||
|
||||
// 查询商户充值规则
|
||||
List<MemberRechargeRule> rechargeRuleList = memberRechargeRuleService.list(MemberRechargeRule.gw()
|
||||
.select(MemberRechargeRule::getRuleId, MemberRechargeRule::getRechargeAmount, MemberRechargeRule::getGiveAmount, MemberRechargeRule::getSort)
|
||||
.eq(MemberRechargeRule::getMchNo, mchNo)
|
||||
.eq(MemberRechargeRule::getState, CS.YES)
|
||||
.orderByAsc(MemberRechargeRule::getSort)
|
||||
.orderByDesc(MemberRechargeRule::getCreatedAt)
|
||||
);
|
||||
|
||||
// 自定义充值配置查询
|
||||
MchConfig mchConfig = mchConfigService.getByMchNoAndConfigKey(mchNo, MchConfig.SELF_MEMBER_CUSTOM_AMOUNT_STATE);
|
||||
// 自定义充值金额配置
|
||||
JSONObject extJson = JsonKit.newJson(MchConfig.SELF_MEMBER_CUSTOM_AMOUNT_STATE, mchConfig == null ? MchConfig.NO : mchConfig.getConfigVal());
|
||||
|
||||
IPage<MemberRechargeRule> iPage = new Page<>();
|
||||
iPage.setRecords(rechargeRuleList);
|
||||
|
||||
return ApiRes.page(iPage, extJson);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取商户充值规则 适用门店
|
||||
*/
|
||||
public ApiRes getMchRechargeRuleStore(MchAppConfigContext mchAppConfigContext) {
|
||||
String mchNo = mchAppConfigContext.getMchNo();
|
||||
|
||||
return ApiRes.ok(mchStoreService.list(MchStore.gw()
|
||||
.select(MchStore::getStoreName)
|
||||
.eq(MchStore::getMchNo, mchNo)));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
package com.jeequan.jeepay.member.service;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.jeequan.jeepay.bizcommons.manage.sms.SmsManager;
|
||||
import com.jeequan.jeepay.core.constants.CS;
|
||||
import com.jeequan.jeepay.core.exception.BizException;
|
||||
import com.jeequan.jeepay.core.model.ApiRes;
|
||||
import com.jeequan.jeepay.core.model.QRCodeParams;
|
||||
import com.jeequan.jeepay.core.model.context.MchAppConfigContext;
|
||||
import com.jeequan.jeepay.core.utils.JeepayKit;
|
||||
import com.jeequan.jeepay.db.entity.MchQrcodeCard;
|
||||
import com.jeequan.jeepay.db.entity.MchStore;
|
||||
import com.jeequan.jeepay.db.entity.MemberInfo;
|
||||
import com.jeequan.jeepay.service.impl.MchQrcodeCardService;
|
||||
import com.jeequan.jeepay.service.impl.MemberInfoService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 查询上游订单, & 补单服务实现类
|
||||
*
|
||||
* @author terrfly
|
||||
* @date 2021/6/8 17:40
|
||||
*/
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class MemberService extends CommonService {
|
||||
|
||||
@Autowired
|
||||
private AuthService authService;
|
||||
@Autowired
|
||||
private MemberInfoService memberInfoService;
|
||||
@Autowired
|
||||
private MchQrcodeCardService mchQrcodeCardService;
|
||||
@Autowired
|
||||
private SmsManager smsManager;
|
||||
|
||||
/**
|
||||
* 查询商户信息
|
||||
*/
|
||||
public ApiRes getMchInfo(MchAppConfigContext mchAppConfigContext, QRCodeParams qrCodeParams) {
|
||||
JSONObject resultJSON = new JSONObject();
|
||||
|
||||
MchQrcodeCard mchQrCode = mchQrcodeCardService.getById(qrCodeParams.getId());
|
||||
if (mchQrCode == null || mchQrCode.getQrcState() != CS.YES) {
|
||||
throw new BizException("当前静态码不存在或不可用");
|
||||
}
|
||||
if (mchQrCode.getFixedFlag() == CS.YES) {
|
||||
resultJSON.put("amount", mchQrCode.getFixedPayAmount());
|
||||
resultJSON.put("fixedFlag", true);
|
||||
}
|
||||
|
||||
MchStore mchStore = mchStoreService.getById(mchQrCode.getStoreId());
|
||||
if (mchStore != null && StringUtils.isNotBlank(mchStore.getStoreName())) {
|
||||
resultJSON.put("mchName", mchStore.getStoreName());
|
||||
resultJSON.put("storeLogo", mchStore.getStoreLogo());
|
||||
} else {
|
||||
resultJSON.put("mchName", mchAppConfigContext.getMchInfo().getMchShortName());
|
||||
}
|
||||
|
||||
|
||||
return ApiRes.ok(resultJSON);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询会员信息
|
||||
*/
|
||||
public ApiRes getMemberInfo(String mchNo, String channelUesrId, String pageType) {
|
||||
log.info("查询会员信息接口,mchNo={}, channelUesrId={}, pageType={}", mchNo, channelUesrId, pageType);
|
||||
|
||||
MemberInfo memberInfo = memberInfoService.selectOne(mchNo, null, null, channelUesrId, pageType);
|
||||
if (memberInfo == null) {
|
||||
return ApiRes.ok();
|
||||
}
|
||||
|
||||
return ApiRes.ok(authService.authByMbrId(memberInfo.getMbrId(), null));
|
||||
}
|
||||
|
||||
/**
|
||||
* 会员绑定手机号
|
||||
*/
|
||||
public ApiRes mbrTelBind(MemberInfo memberInfo, String code, String channelUesrId, String pageType) {
|
||||
|
||||
String mbrTel = memberInfo.getMbrTel();
|
||||
|
||||
// 校验短信验证码
|
||||
smsManager.checkSmsVercodeThrowBizEx(mbrTel, code, CS.SMS_TYPE_API_ENUM.TYPE_MBR_TEL_BIND);
|
||||
|
||||
if (StringUtils.equalsAny(pageType, QRCodeParams.PAGE_TYPE_ALIPAY_H5, QRCodeParams.PAGE_TYPE_ALIPAY_LITE)) {
|
||||
memberInfo.setAliUserId(channelUesrId);
|
||||
memberInfo.setMbrName("支付宝用户" + getTel4Last(memberInfo.getMbrTel()));
|
||||
|
||||
} else if (StringUtils.equals(pageType, QRCodeParams.PAGE_TYPE_WECHAT_H5)) {
|
||||
memberInfo.setWxMpOpenId(channelUesrId);
|
||||
memberInfo.setMbrName("微信用户" + getTel4Last(memberInfo.getMbrTel()));
|
||||
|
||||
} else if (StringUtils.equals(pageType, QRCodeParams.PAGE_TYPE_WECHAT_LITE)) {
|
||||
memberInfo.setWxLiteOpenId(channelUesrId);
|
||||
memberInfo.setMbrName("微信用户" + getTel4Last(memberInfo.getMbrTel()));
|
||||
|
||||
} else if (StringUtils.equals(pageType, QRCodeParams.PAGE_TYPE_YSFPAY_H5)) {
|
||||
memberInfo.setYsfUserId(channelUesrId);
|
||||
memberInfo.setMbrName("云闪付用户" + getTel4Last(memberInfo.getMbrTel()));
|
||||
|
||||
} else {
|
||||
throw new BizException("不支持的客户端");
|
||||
}
|
||||
|
||||
// 手机号查询会员,若手机号已绑定,将更新会员的channelUserId
|
||||
MemberInfo dbRecord = memberInfoService.selectOne(memberInfo.getMchNo(), null, mbrTel, null, null);
|
||||
if (dbRecord != null) {
|
||||
memberInfo.setMbrId(dbRecord.getMbrId());
|
||||
memberInfo.setMbrName(null); // 不更新会员名称
|
||||
memberInfo.setSafeKey(null);
|
||||
} else {
|
||||
memberInfo.setMbrId("B" + DateUtil.currentSeconds());
|
||||
memberInfo.setSafeKey(JeepayKit.genAccountSafeKey(memberInfo.getMbrId(), 0L));
|
||||
memberInfo.setAvatarUrl(getMemberAvatarDefault());
|
||||
}
|
||||
|
||||
boolean result = memberInfoService.saveOrUpdate(memberInfo);
|
||||
if (!result) {
|
||||
return ApiRes.customFail("操作失败");
|
||||
}
|
||||
|
||||
return ApiRes.ok(authService.authByMbrId(memberInfo.getMbrId(), null));
|
||||
}
|
||||
|
||||
/**
|
||||
* 手机尾号4位
|
||||
**/
|
||||
public String getTel4Last(String memberTel) {
|
||||
if (StringUtils.isEmpty(memberTel)) {
|
||||
return null;
|
||||
}
|
||||
return memberTel.substring(memberTel.length() - 4);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
package com.jeequan.jeepay.member.task;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.jeequan.jeepay.db.entity.MemberRechargeRecord;
|
||||
import com.jeequan.jeepay.db.entity.PayOrder;
|
||||
import com.jeequan.jeepay.service.impl.MemberRechargeRecordService;
|
||||
import com.jeequan.jeepay.service.impl.PayOrderService;
|
||||
import com.xxl.job.core.handler.annotation.XxlJob;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 会员充值定时
|
||||
*
|
||||
* @author xiaoyu
|
||||
* @date 2023/4/15 10:07
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class MemberRechargeTask {
|
||||
|
||||
@Autowired private MemberRechargeRecordService rechargeRecordService;
|
||||
@Autowired private PayOrderService payOrderService;
|
||||
|
||||
private static final int QUERY_PAGE_SIZE = 100; //每次查询数量
|
||||
|
||||
@XxlJob("memberRechargeOrderTaskHandler")
|
||||
public void start() {
|
||||
|
||||
log.info("开始【处理会员充值任务】");
|
||||
|
||||
//查询条件:充值中的记录
|
||||
LambdaQueryWrapper<MemberRechargeRecord> lambdaQueryWrapper = MemberRechargeRecord.gw()
|
||||
.eq(MemberRechargeRecord::getState, MemberRechargeRecord.STATE_ING)
|
||||
.select(MemberRechargeRecord::getPayOrderId, MemberRechargeRecord::getRechargeRecordId);
|
||||
int currentPageIndex = 1; //当前页码
|
||||
while(true){
|
||||
|
||||
try {
|
||||
// 查询充值中的记录
|
||||
IPage<MemberRechargeRecord> resultPage = rechargeRecordService.page(new Page(currentPageIndex, QUERY_PAGE_SIZE), lambdaQueryWrapper);
|
||||
|
||||
if(resultPage == null || resultPage.getRecords().isEmpty()){ //本次查询无结果, 不再继续查询;
|
||||
break;
|
||||
}
|
||||
// 缓存订单号
|
||||
ArrayList<String> orderList = new ArrayList<>();
|
||||
resultPage.getRecords().stream().forEach(record ->{
|
||||
orderList.add(record.getPayOrderId());
|
||||
});
|
||||
|
||||
// 订单号列表为空 跳出循环
|
||||
if (CollectionUtil.isEmpty(orderList)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// 查询关联订单
|
||||
List<PayOrder> payOrderList = payOrderService.list(PayOrder.gw().in(PayOrder::getPayOrderId, orderList));
|
||||
// 缓存订单信息
|
||||
HashMap<String, PayOrder> orderMap = new HashMap<>();
|
||||
payOrderList.stream().forEach(order -> {
|
||||
orderMap.put(order.getPayOrderId(), order);
|
||||
});
|
||||
|
||||
for (MemberRechargeRecord record : resultPage.getRecords()) {
|
||||
|
||||
PayOrder payOrder = orderMap.get(record.getPayOrderId());
|
||||
if (payOrder == null) {
|
||||
log.info("【处理会员充值任务】订单{}不存在", record.getPayOrderId());
|
||||
break;
|
||||
}
|
||||
// 支付成功处理充值
|
||||
if (PayOrder.STATE_SUCCESS == payOrder.getState()) {
|
||||
|
||||
// 处理充值记录
|
||||
boolean result = rechargeRecordService.updateIng2SuccessAndMbrAccount(record.getRechargeRecordId(), payOrder.getPayOrderId());
|
||||
log.info("【处理会员充值任务】订单支付成功 rechargeId:{}, payOrderId:{}, 处理结果:{}", record.getRechargeRecordId(), payOrder.getPayOrderId(), result);
|
||||
|
||||
// 订单不为初始化、支付中、支付成功时。处理为充值失败
|
||||
}else if (PayOrder.STATE_INIT != payOrder.getState() && PayOrder.STATE_ING != payOrder.getState() && PayOrder.STATE_SUCCESS != payOrder.getState()) {
|
||||
// 处理充值记录
|
||||
rechargeRecordService.updateIng2Fail(record.getRechargeRecordId(), payOrder.getErrCode(), payOrder.getErrMsg());
|
||||
log.info("【处理会员充值任务】订单支付失败 rechargeId:{}, payOrderId:{}, errCode:{}, errMsg:{}, 订单状态:{}", record.getRechargeRecordId(), payOrder.getPayOrderId(), payOrder.getErrCode(), payOrder.getErrMsg(), payOrder.getState());
|
||||
|
||||
}else {
|
||||
// 其他状态跳过
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//已经到达页码最大量,无需再次查询
|
||||
if(resultPage.getPages() <= currentPageIndex){
|
||||
break;
|
||||
}
|
||||
currentPageIndex++;
|
||||
|
||||
} catch (Exception e) { //出现异常,直接退出,避免死循环。
|
||||
log.error("error", e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
log.info("结束【处理会员充值任务】");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.jeequan.jeepay.member.web;
|
||||
|
||||
import com.jeequan.jeepay.core.utils.ApiResBodyAdviceKit;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.server.ServerHttpRequest;
|
||||
import org.springframework.http.server.ServerHttpResponse;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
|
||||
|
||||
/**
|
||||
* 自定义springMVC返回数据格式
|
||||
*
|
||||
* @author terrfly
|
||||
* @modify zhuxiao
|
||||
* @date 2021-04-27 15:50
|
||||
*/
|
||||
@ControllerAdvice
|
||||
public class ApiResBodyAdvice implements ResponseBodyAdvice {
|
||||
|
||||
|
||||
/** 判断哪些需要拦截 **/
|
||||
@Override
|
||||
public boolean supports(MethodParameter returnType, Class converterType) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** 拦截返回数据处理 */
|
||||
@Override
|
||||
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
|
||||
Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
|
||||
//处理扩展字段
|
||||
return ApiResBodyAdviceKit.beforeBodyWrite(body);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.jeequan.jeepay.member.web;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* 数据响应拦截器
|
||||
*
|
||||
* @author terrfly
|
||||
* @modify zhuxiao
|
||||
* @date 2021-04-27 15:50
|
||||
*/
|
||||
@Component
|
||||
public class ApiResInterceptor implements HandlerInterceptor {
|
||||
|
||||
/** postHandler是在请求结束之后, 视图渲染之前执行的,但只有preHandle方法返回true的时候才会执行
|
||||
* 如果ctrl使用了@RestController或者@ResponseBody注解 则ModelAndView = null, 因为不走视图转换器, 而是走的RequestResponseBodyMethodProcessor。
|
||||
* ————————————————
|
||||
*
|
||||
* **/
|
||||
@Override
|
||||
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
|
||||
|
||||
//do
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.jeequan.jeepay.member.web;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.context.ServletContextAware;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
/**
|
||||
* 上下文配置
|
||||
*
|
||||
* @author terrfly
|
||||
* @modify zhuxiao
|
||||
* @date 2021-04-27 15:50
|
||||
*/
|
||||
@Service
|
||||
public class ApplicationContextKit implements ServletContextAware,InitializingBean{
|
||||
|
||||
private ServletContext servletContext ;
|
||||
@Override
|
||||
public void setServletContext(ServletContext servletContext) {
|
||||
|
||||
this.servletContext = servletContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* afterPropertiesSet 是在什么之后执行? 启动顺序是?
|
||||
* 调用PropKit(SpringBeansUtil.getBean获取方式) 会不会出现找不到bean的问题?
|
||||
*
|
||||
* */
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.jeequan.jeepay.member.web;
|
||||
|
||||
import com.jeequan.jeepay.core.config.WebConfig;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
|
||||
/**
|
||||
* webmvc配置
|
||||
*
|
||||
* @author terrfly
|
||||
* @modify zhuxiao
|
||||
* @date 2021-04-27 15:50
|
||||
*/
|
||||
@Configuration
|
||||
public class WebmvcConfig extends WebConfig {
|
||||
|
||||
@Autowired
|
||||
private ApiResInterceptor apiResInterceptor;
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
super.addInterceptors(registry);
|
||||
registry.addInterceptor(apiResInterceptor);
|
||||
}
|
||||
}
|
||||
148
jeepay-member/src/main/resources/application-dev.yml
Normal file
148
jeepay-member/src/main/resources/application-dev.yml
Normal file
@@ -0,0 +1,148 @@
|
||||
#################################
|
||||
# spring boot支持外部application.yml 读取优先级为:
|
||||
# 1、file:./config/(当前目录下的config文件夹)
|
||||
# 2、file:./(当前目录)
|
||||
# 3、classpath:/config/(classpath下的config目录)
|
||||
# 4、classpath:/(classpath根目录)
|
||||
# 建议: 如果是jar则放置到与jar相同的目录下, 如果解压文件放置到classpath: config目录下。 (需要将文件重命名为 application.yml )
|
||||
#
|
||||
# 该yml文件只配置与环境相关的参数, 其他配置读取项目下的配置项
|
||||
#
|
||||
#################################
|
||||
# 数据库的配置项, 自定义配置放置在配置顶层
|
||||
db-config:
|
||||
master: #主库配置(必填)
|
||||
# yml填写url连接串, 无需将&符号进行转义
|
||||
url: jdbc:mysql://127.0.0.1:3306/yinshangfu?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true
|
||||
username: root
|
||||
password: YinShangFuMysql@123456
|
||||
encrypt-account: false # 连接账号和密码是否已加密。 true:db的账密需配置密文,函数详见 DBProp.main(); false: db账密请填写明文
|
||||
# 连接池配置项
|
||||
initial-size: 5 #初始化时建立物理连接的个数
|
||||
min-idle: 5 #最小连接池数量
|
||||
max-active: 30 #最大连接池数量
|
||||
max-wait: 60000 #获取连接时最大等待时间,单位毫秒
|
||||
# 检测相关
|
||||
test-while-idle: true # 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
|
||||
test-on-borrow: false # 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
|
||||
test-on-return: false # 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
|
||||
time-between-eviction-runs-millis: 60000 #配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
|
||||
min-evictable-idle-time-millis: 300000 #连接保持空闲而不被驱逐的最小时间
|
||||
validation-query: SELECT 1 FROM DUAL
|
||||
# 是否缓存preparedStatement
|
||||
pool-prepared-statements: false # 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。
|
||||
max-pool-prepared-statement-per-connection-size: 20 # 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。
|
||||
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计 通过connectProperties属性来打开mergeSql功能;慢SQL记录
|
||||
filters: stat,wall
|
||||
connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
|
||||
|
||||
slave: #从库配置(可选), 若没有显式配置则使用master的配置项。 配置参数与master一致。
|
||||
|
||||
# spring-boot组件配置
|
||||
spring:
|
||||
servlet:
|
||||
multipart:
|
||||
enabled: true #是否启用http上传处理
|
||||
max-request-size: 10MB #最大请求文件的大小
|
||||
max-file-size: 10MB #设置单个文件最大长度
|
||||
resources:
|
||||
static-locations: classpath:/static #项目静态资源路径 (可直接通过http访问)
|
||||
freemarker:
|
||||
template-loader-path: classpath:/templates #freemarker模板目录
|
||||
template-encoding: UTF-8
|
||||
suffix: .ftl
|
||||
settings:
|
||||
classic_compatible: true # 如果变量为null,转化为空字符串,比如做比较的时候按照空字符做比较
|
||||
number_format: '#' #数字格式进行原样显示,不加格式化字符例如 100,00
|
||||
cache:
|
||||
type: redis
|
||||
redis:
|
||||
host: 127.0.0.1
|
||||
port: 6379
|
||||
database: 5 #1库:运营平台 #2库:商户系统 #3库:支付网关 #4库:代理商 #5库:会员
|
||||
timeout: 1000
|
||||
password: ax123456ax
|
||||
sys-prefix-key: PKMBR_ # 作用:不同系统的前缀。 a.当连接不同的database时可以为空(物理隔离); b.当redis集群时因为必须同一个database,所以需通过前缀区分不同系统的业务。
|
||||
|
||||
# #activeMQ配置 ( 注意: activeMQ配置项需在spring的下级 )
|
||||
rabbitmq:
|
||||
addresses: 127.0.0.1:5672
|
||||
username: root
|
||||
password: YinShangFuRabbit@123456
|
||||
dynamic: true
|
||||
virtual-host: /
|
||||
#
|
||||
# #rabbitmq配置 ( 注意: rabbitmq配置项需在spring的下级 )
|
||||
# rabbitmq:
|
||||
# addresses: 127.0.0.1:5672
|
||||
# username: guest
|
||||
# password: guest
|
||||
# dynamic: true
|
||||
# virtual-host: /
|
||||
|
||||
## rocketmq配置 ( 注意:rocketmq配置项请放置到根目录, 不是spring的二级配置! )
|
||||
#rocketmq:
|
||||
# name-server: 127.0.0.1:9876
|
||||
# producer:
|
||||
# group: JEEPAY-GROUP
|
||||
|
||||
## 阿里云rocketmq配置 ( 注意:aliyun-rocketmq配置项请放置到根目录, 不是spring的二级配置!需要阿里云开通rocketMQ产品,创建Group和Topic )
|
||||
#aliyun-rocketmq:
|
||||
# namesrvAddr: xxx
|
||||
# accessKey: xxx
|
||||
# secretKey: xxx
|
||||
# groupIdPrefix: GID_JEEPAY_ # (分组前缀, 具体名称详见AliyunRocketMQFactory.java )
|
||||
|
||||
#日志配置参数。
|
||||
# 当存在logback-spring.xml文件时: 该配置将引进到logback配置, springboot配置不生效。
|
||||
# 不存在logback-spring.xml 文件时, 使用springboot的配置, 同样可用。
|
||||
logging:
|
||||
level:
|
||||
root: info #主日志级别
|
||||
com.jeequan.jeepay: info #该项目日志级别,当需要打印sql时请开启为debug
|
||||
path: ./member/logs #日志存放地址
|
||||
# xxl-job 执行器配置项
|
||||
xxl-job:
|
||||
executor:
|
||||
admin-address: http://127.0.0.1:9300/xxl-job-admin # 调度中心部署根地址 [选填]:如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行"执行器心跳注册"和"任务结果回调";为空则关闭自动注册;
|
||||
access-token: jeepayTaskToken@2022 # 执行器通讯TOKEN
|
||||
appname: jeepay-plus-member-executor # 执行器AppName [选填]:执行器心跳注册分组依据;为空则关闭自动注册
|
||||
port: 9321 # 执行器端口号 [选填]:小于等于0则自动获取;默认端口为9999,单机部署多个执行器时,注意要配置不同执行器端口;
|
||||
log-path: ${logging.file.path} # 执行器运行日志文件存储磁盘路径 [选填] :需要对该路径拥有读写权限;为空则使用默认路径;
|
||||
logretentiondays: 7 # 执行器日志文件保存天数 [选填] : 过期日志自动清理, 限制值大于等于3时生效; 否则, 如-1, 关闭自动清理功能;
|
||||
|
||||
#xxl-job:
|
||||
# executor:
|
||||
# admin-address: http://127.0.0.1:9300/xxl-job-admin # 调度中心部署根地址 [选填]:如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行"执行器心跳注册"和"任务结果回调";为空则关闭自动注册;
|
||||
# access-token: jeepayTaskToken@2022 # 执行器通讯TOKEN
|
||||
# appname: jeepay-plus-member-executor # 执行器AppName [选填]:执行器心跳注册分组依据;为空则关闭自动注册
|
||||
# port: 9321 # 执行器端口号 [选填]:小于等于0则自动获取;默认端口为9999,单机部署多个执行器时,注意要配置不同执行器端口;
|
||||
# log-path: ${logging.file.path} # 执行器运行日志文件存储磁盘路径 [选填] :需要对该路径拥有读写权限;为空则使用默认路径;
|
||||
# logretentiondays: 7 # 执行器日志文件保存天数 [选填] : 过期日志自动清理, 限制值大于等于3时生效; 否则, 如-1, 关闭自动清理功能;
|
||||
|
||||
|
||||
#系统业务参数
|
||||
isys:
|
||||
jwt-secret: zCfdYJepLgVLBw3c #生成jwt的秘钥。 要求每个系统有单独的秘钥管理机制。
|
||||
db-encrypt-secret: 1234567890123456 #DB SM4 加解密秘钥 (必须16位) [每个系统配置必须相同,否则加解密不一致导致业务异常!]
|
||||
http-message-encrypt-secret: 1234567890123456 #web传输加解密 秘钥 (必须16位) [每个系统配置必须相同,否则加解密不一致导致业务异常!]
|
||||
|
||||
# 支付网关的公钥和私钥(系统级别!), 请妥善保存,用于回调商户的商户侧的验证, 首次设置好之后不可随意变更!
|
||||
sys-RSA2-private-key: MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCLU0lXJu9vcJCwrwFGwT1CqXUSY+JMW2iSRPtgLw6lxjU403hS1VyKxA5uTZokv80Wd+bcxDMrM9DwHeGqhjlWvbB/lqaRliJJRdgLVUedrDY+3YSN75uHBtLmxZbnaUpV6/aWA/a+lkNqHxYCWB1jggFB9DhVg2SgoMGDOYHDNA5ZDl47sKpanW0kfG9lINSV4xgDPmAJxUnhkG/7eVEBDev9EIhc+LIMC7Zj+UYc+s/TK4c31fFTW4dZAp3LVEdct9qXU5qm/fXIXxeo3E0bWyOP3VL4Xmx2S9Host1YzjzXPSi1TJjX7rxQkhmbE/dQJ+ws/VvKPuUpmLEPGsm/AgMBAAECggEBAIONCFq58KoQZw3ssA/WtbkTt+69URc31+0EJTYUOIheNjKJubq8qrx7kgSkUT8RutvUKq+YsZfBPS77h/Ay/EDiqpxN6sjcMVNuFyfcRdqimDWTg21hKEC+OLSdLHcj+4RVYGcVJw2dY9n3sBhWiqlCP12+8tILViA0qYL18YgVYJM3bL2MCXfUnm8/Rn1ut5LuDtU/UuaVz9vuCqNirZJedZx3WEq69ZRt9m44XN934NikbUGxQRlz32WRXDo+ssSTu3174UbDYc8nhqO0jUvuzfjOOMf9NYRJsgqVihxMLvvMaUhEE3w6qZPLMj6KhTiG5QHexBbyLgDxH4TZ4gECgYEAz7vZFMoKYifCi+eFykH/ad8QYYoYLlrU1EN2fpIJqwSHZbpBfB8NM5Ov26xU/aNHGKxtSOrUFva5sWub5f9OlsOAmaUOPuVuaJbsq+e3cNQ41jBcdppGJLNx1p/69zR1rF9TbI9Ambd8sOgX3OZmImA2Ldlk2KvMKRruxwc4uN8CgYEAq7J0u5KTwI3PxENLWQ/6tOBNdbCoyqFM+FdANVHRA4dhhdoJ1x0bpdt3tapPFJTBURSEspNxPl4iT+GdpoF6KwqTsQFmB5TLlfx8wY9SIc+sI/ifZvMA5Dv8vVfYWNig7rGV+vIyJCCNbJ5OMa1xvxTDc7Dx4XPxcJ4sR1ZyqyECgYAe447O8ZADsmfSR9X0EkY5ZurXpiIcWnNFMNbg0TRQ0raTYNO18iQTZEWFA6YLpQjAWXtSmWB6HavU/uxKkeEMt/taXVm17oWxVafRk/4J7/SXnM9S73O4p1opENbPhWRuAiq0fMSdVtRatdg+h5/uQqIrxSSit0D/Z7rTq3Y6vwKBgQCd8AlbJckOHiTZd8GOypkm2xHFydxqkJfZ9YCVy44Fvfnig5/7pcXx+oEStfgKiY+OQt6R2fkYksTjUDmRmZbEkvUqpIuzO5dOf7RO5MR7X6oMaL5QmAXg7KFflrfnelYHW4oIDdQ70UnmeXSaU97HE5V7DXBioCGfI5C9inLuoQKBgQCwJmQ2heyTbG1DIBuqf+GFXLuOp76M/7S9c+5R7yfxyTzAbiKRIPeSF5wlxNXEnGwK7qB9CmctlBdnV7A0qnZVFMXf7AbBDUzOCjiy1RSh04BNPnu0dTIygX2PE5inltrHiZtTgciKwj9MexT97F4mTR76kIMz5SGNZe3PscQr7g==
|
||||
sys-RSA2-public-key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAi1NJVybvb3CQsK8BRsE9Qql1EmPiTFtokkT7YC8OpcY1ONN4UtVcisQObk2aJL/NFnfm3MQzKzPQ8B3hqoY5Vr2wf5amkZYiSUXYC1VHnaw2Pt2Eje+bhwbS5sWW52lKVev2lgP2vpZDah8WAlgdY4IBQfQ4VYNkoKDBgzmBwzQOWQ5eO7CqWp1tJHxvZSDUleMYAz5gCcVJ4ZBv+3lRAQ3r/RCIXPiyDAu2Y/lGHPrP0yuHN9XxU1uHWQKdy1RHXLfal1Oapv31yF8XqNxNG1sjj91S+F5sdkvR6LLdWM481z0otUyY1+68UJIZmxP3UCfsLP1byj7lKZixDxrJvwIDAQAB
|
||||
|
||||
|
||||
#是否允许跨域请求 [生产环境建议关闭, 若api与前端项目没有在同一个域名下时,应开启此配置或在nginx统一配置允许跨域]
|
||||
allow-cors: true
|
||||
|
||||
#是否内存缓存配置信息: true表示开启如支付网关地址/商户应用配置/服务商配置等, 开启后需检查MQ的广播模式是否正常; false表示直接查询DB.
|
||||
cache-config: false
|
||||
|
||||
oss:
|
||||
file-root-path: /home/jeepay/upload #存储根路径 ( 无需以‘/’结尾 )
|
||||
file-public-path: ${isys.oss.file-root-path}/public #公共读取块 ( 一般配合root-path参数进行设置,需以‘/’ 开头, 无需以‘/’结尾 )
|
||||
file-private-path: ${isys.oss.file-root-path}/private #私有化本地访问,不允许url方式公共读取 ( 一般配合root-path参数进行设置,需以‘/’ 开头, 无需以‘/’结尾 )
|
||||
|
||||
mq:
|
||||
vender: rabbitMQ # 切换MQ厂商, 支持:【 activeMQ rabbitMQ rocketMQ aliYunRocketMQ 】, 需正确配置 【对应的yml参数】 和 【jeepay-components-mq项目下pom.xml中的依赖包】。
|
||||
|
||||
114
jeepay-member/src/main/resources/application-prod.yml
Normal file
114
jeepay-member/src/main/resources/application-prod.yml
Normal file
@@ -0,0 +1,114 @@
|
||||
# spring-boot组件配置
|
||||
spring:
|
||||
servlet:
|
||||
multipart:
|
||||
enabled: true #是否启用http上传处理
|
||||
max-request-size: 10MB #最大请求文件的大小
|
||||
max-file-size: 10MB #设置单个文件最大长度
|
||||
resources:
|
||||
static-locations: classpath:/static #项目静态资源路径 (可直接通过http访问)
|
||||
freemarker:
|
||||
template-loader-path: classpath:/templates #freemarker模板目录
|
||||
template-encoding: UTF-8
|
||||
suffix: .ftl
|
||||
settings:
|
||||
classic_compatible: true # 如果变量为null,转化为空字符串,比如做比较的时候按照空字符做比较
|
||||
number_format: '#' #数字格式进行原样显示,不加格式化字符例如 100,00
|
||||
cache:
|
||||
type: redis
|
||||
redis:
|
||||
host: 127.0.0.1
|
||||
port: 6379
|
||||
timeout: 1000
|
||||
password: ax123456ax
|
||||
activemq:
|
||||
broker-url: failover:(tcp://127.0.0.1:61616?wireFormat.maxInactivityDuration=0) #
|
||||
in-memory: false # Jeepay
|
||||
user: admin # activeMQ
|
||||
password: 123456
|
||||
pool:
|
||||
enabled: true
|
||||
max-connections: 10
|
||||
idle-timeout: 30000 #
|
||||
logging:
|
||||
level:
|
||||
root: info #主日志级别
|
||||
# xxl-job 执行器配置项
|
||||
xxl-job:
|
||||
executor:
|
||||
admin-address: http://127.0.0.1:8282/xxl-job-admin # 调度中心部署根地址 [选填]:如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行"执行器心跳注册"和"任务结果回调";为空则关闭自动注册;
|
||||
access-token: jeepayTaskToken@2022 # 执行器通讯TOKEN
|
||||
# appname: jeepay-plus-bill-executor # 执行器AppName [选填]:执行器心跳注册分组依据;为空则关闭自动注册
|
||||
# port: # 执行器端口号 [选填]:小于等于0则自动获取;默认端口为9999,单机部署多个执行器时,注意要配置不同执行器端口;
|
||||
log-path: ${logging.file.path} # 执行器运行日志文件存储磁盘路径 [选填] :需要对该路径拥有读写权限;为空则使用默认路径;
|
||||
logretentiondays: 7 # 执行器日志文件保存天数 [选填] : 过期日志自动清理, 限制值大于等于3时生效; 否则, 如-1, 关闭自动清理功能;
|
||||
|
||||
db-config:
|
||||
master: #主库配置(必填)
|
||||
# yml填写url连接串, 无需将&符号进行转义
|
||||
url: jdbc:p6spy:mysql://rm-bp1c8prh6j399epb5.mysql.rds.aliyuncs.com/yinshangfu?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true
|
||||
username: yinshangfu
|
||||
password: YinShangFuMysql@123456
|
||||
encrypt-account: false # 连接账号和密码是否已加密。 true:db的账密需配置密文,函数详见 DBProp.main(); false: db账密请填写明文
|
||||
# 连接池配置项
|
||||
initial-size: 5 #初始化时建立物理连接的个数
|
||||
min-idle: 5 #最小连接池数量
|
||||
max-active: 30 #最大连接池数量
|
||||
max-wait: 60000 #获取连接时最大等待时间,单位毫秒
|
||||
# 检测相关
|
||||
test-while-idle: true # 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
|
||||
test-on-borrow: false # 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
|
||||
test-on-return: false # 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
|
||||
time-between-eviction-runs-millis: 60000 #配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
|
||||
min-evictable-idle-time-millis: 300000 #连接保持空闲而不被驱逐的最小时间
|
||||
validation-query: SELECT 1 FROM DUAL
|
||||
# 是否缓存preparedStatement
|
||||
pool-prepared-statements: false # 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。
|
||||
max-pool-prepared-statement-per-connection-size: 20 # 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。
|
||||
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计 通过connectProperties属性来打开mergeSql功能;慢SQL记录
|
||||
filters: stat,wall
|
||||
connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
|
||||
|
||||
slave: #从库配置(可选), 若没有显式配置则使用master的配置项。 配置参数与master一致。
|
||||
# yml填写url连接串, 无需将&符号进行转义
|
||||
url: jdbc:p6spy:mysql://rm-bp1c8prh6j399epb5.mysql.rds.aliyuncs.com/yinshangfu?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true
|
||||
username: yinshangfu
|
||||
password: YinShangFuMysql@123456
|
||||
encrypt-account: false # 连接账号和密码是否已加密。 true:db的账密需配置密文,函数详见 DBProp.main(); false: db账密请填写明文
|
||||
# 连接池配置项
|
||||
initial-size: 5 #初始化时建立物理连接的个数
|
||||
min-idle: 5 #最小连接池数量
|
||||
max-active: 30 #最大连接池数量
|
||||
max-wait: 60000 #获取连接时最大等待时间,单位毫秒
|
||||
# 检测相关
|
||||
test-while-idle: true # 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
|
||||
test-on-borrow: false # 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
|
||||
test-on-return: false # 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
|
||||
time-between-eviction-runs-millis: 60000 #配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
|
||||
min-evictable-idle-time-millis: 300000 #连接保持空闲而不被驱逐的最小时间
|
||||
validation-query: SELECT 1 FROM DUAL
|
||||
# 是否缓存preparedStatement
|
||||
pool-prepared-statements: false # 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。
|
||||
max-pool-prepared-statement-per-connection-size: 20 # 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。
|
||||
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计 通过connectProperties属性来打开mergeSql功能;慢SQL记录
|
||||
filters: stat,wall
|
||||
connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
|
||||
isys:
|
||||
#是否允许跨域请求 [生产环境建议关闭, 若api与前端项目没有在同一个域名下时,应开启此配置或在nginx统一配置允许跨域]
|
||||
allow-cors: true
|
||||
|
||||
db-encrypt-secret: 1234567890123456 #DB SM4 加解密秘钥 (必须16位) [每个系统配置必须相同,否则加解密不一致导致业务异常!]
|
||||
http-message-encrypt-secret: 1234567890123456 #web传输加解密 秘钥 (必须16位) [每个系统配置必须相同,否则加解密不一致导致业务异常!]
|
||||
|
||||
# 支付网关的公钥和私钥(系统级别!), 请妥善保存,用于回调商户的商户侧的验证, 首次设置好之后不可随意变更!
|
||||
sys-RSA2-private-key: MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCLU0lXJu9vcJCwrwFGwT1CqXUSY+JMW2iSRPtgLw6lxjU403hS1VyKxA5uTZokv80Wd+bcxDMrM9DwHeGqhjlWvbB/lqaRliJJRdgLVUedrDY+3YSN75uHBtLmxZbnaUpV6/aWA/a+lkNqHxYCWB1jggFB9DhVg2SgoMGDOYHDNA5ZDl47sKpanW0kfG9lINSV4xgDPmAJxUnhkG/7eVEBDev9EIhc+LIMC7Zj+UYc+s/TK4c31fFTW4dZAp3LVEdct9qXU5qm/fXIXxeo3E0bWyOP3VL4Xmx2S9Host1YzjzXPSi1TJjX7rxQkhmbE/dQJ+ws/VvKPuUpmLEPGsm/AgMBAAECggEBAIONCFq58KoQZw3ssA/WtbkTt+69URc31+0EJTYUOIheNjKJubq8qrx7kgSkUT8RutvUKq+YsZfBPS77h/Ay/EDiqpxN6sjcMVNuFyfcRdqimDWTg21hKEC+OLSdLHcj+4RVYGcVJw2dY9n3sBhWiqlCP12+8tILViA0qYL18YgVYJM3bL2MCXfUnm8/Rn1ut5LuDtU/UuaVz9vuCqNirZJedZx3WEq69ZRt9m44XN934NikbUGxQRlz32WRXDo+ssSTu3174UbDYc8nhqO0jUvuzfjOOMf9NYRJsgqVihxMLvvMaUhEE3w6qZPLMj6KhTiG5QHexBbyLgDxH4TZ4gECgYEAz7vZFMoKYifCi+eFykH/ad8QYYoYLlrU1EN2fpIJqwSHZbpBfB8NM5Ov26xU/aNHGKxtSOrUFva5sWub5f9OlsOAmaUOPuVuaJbsq+e3cNQ41jBcdppGJLNx1p/69zR1rF9TbI9Ambd8sOgX3OZmImA2Ldlk2KvMKRruxwc4uN8CgYEAq7J0u5KTwI3PxENLWQ/6tOBNdbCoyqFM+FdANVHRA4dhhdoJ1x0bpdt3tapPFJTBURSEspNxPl4iT+GdpoF6KwqTsQFmB5TLlfx8wY9SIc+sI/ifZvMA5Dv8vVfYWNig7rGV+vIyJCCNbJ5OMa1xvxTDc7Dx4XPxcJ4sR1ZyqyECgYAe447O8ZADsmfSR9X0EkY5ZurXpiIcWnNFMNbg0TRQ0raTYNO18iQTZEWFA6YLpQjAWXtSmWB6HavU/uxKkeEMt/taXVm17oWxVafRk/4J7/SXnM9S73O4p1opENbPhWRuAiq0fMSdVtRatdg+h5/uQqIrxSSit0D/Z7rTq3Y6vwKBgQCd8AlbJckOHiTZd8GOypkm2xHFydxqkJfZ9YCVy44Fvfnig5/7pcXx+oEStfgKiY+OQt6R2fkYksTjUDmRmZbEkvUqpIuzO5dOf7RO5MR7X6oMaL5QmAXg7KFflrfnelYHW4oIDdQ70UnmeXSaU97HE5V7DXBioCGfI5C9inLuoQKBgQCwJmQ2heyTbG1DIBuqf+GFXLuOp76M/7S9c+5R7yfxyTzAbiKRIPeSF5wlxNXEnGwK7qB9CmctlBdnV7A0qnZVFMXf7AbBDUzOCjiy1RSh04BNPnu0dTIygX2PE5inltrHiZtTgciKwj9MexT97F4mTR76kIMz5SGNZe3PscQr7g==
|
||||
sys-RSA2-public-key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAi1NJVybvb3CQsK8BRsE9Qql1EmPiTFtokkT7YC8OpcY1ONN4UtVcisQObk2aJL/NFnfm3MQzKzPQ8B3hqoY5Vr2wf5amkZYiSUXYC1VHnaw2Pt2Eje+bhwbS5sWW52lKVev2lgP2vpZDah8WAlgdY4IBQfQ4VYNkoKDBgzmBwzQOWQ5eO7CqWp1tJHxvZSDUleMYAz5gCcVJ4ZBv+3lRAQ3r/RCIXPiyDAu2Y/lGHPrP0yuHN9XxU1uHWQKdy1RHXLfal1Oapv31yF8XqNxNG1sjj91S+F5sdkvR6LLdWM481z0otUyY1+68UJIZmxP3UCfsLP1byj7lKZixDxrJvwIDAQAB
|
||||
|
||||
#是否内存缓存配置信息: true表示开启如支付网关地址/商户应用配置/服务商配置等, 开启后需检查MQ的广播模式是否正常; false表示直接查询DB.
|
||||
cache-config: false
|
||||
mq:
|
||||
vender: activeMQ
|
||||
|
||||
oss:
|
||||
file-root-path: /home/www/.upload #存储根路径 ( 无需以‘/’结尾 )
|
||||
file-public-path: ${isys.oss.file-root-path}/public #公共读取块 ( 一般配合root-path参数进行设置,需以‘/’ 开头, 无需以‘/’结尾 )
|
||||
111
jeepay-member/src/main/resources/application-test.yml
Normal file
111
jeepay-member/src/main/resources/application-test.yml
Normal file
@@ -0,0 +1,111 @@
|
||||
# spring-boot组件配置
|
||||
spring:
|
||||
servlet:
|
||||
multipart:
|
||||
enabled: true #是否启用http上传处理
|
||||
max-request-size: 10MB #最大请求文件的大小
|
||||
max-file-size: 10MB #设置单个文件最大长度
|
||||
resources:
|
||||
static-locations: classpath:/static #项目静态资源路径 (可直接通过http访问)
|
||||
freemarker:
|
||||
template-loader-path: classpath:/templates #freemarker模板目录
|
||||
template-encoding: UTF-8
|
||||
suffix: .ftl
|
||||
settings:
|
||||
classic_compatible: true # 如果变量为null,转化为空字符串,比如做比较的时候按照空字符做比较
|
||||
number_format: '#' #数字格式进行原样显示,不加格式化字符例如 100,00
|
||||
cache:
|
||||
type: redis
|
||||
redis:
|
||||
host: 47.111.143.211
|
||||
port: 6379
|
||||
timeout: 1000
|
||||
password: ax123456ax
|
||||
rabbitmq:
|
||||
addresses: 47.111.143.211:5672
|
||||
username: root
|
||||
password: YinShangFuRabbit@123456
|
||||
dynamic: true
|
||||
virtual-host: /
|
||||
logging:
|
||||
level:
|
||||
root: info #主日志级别
|
||||
# xxl-job 执行器配置项
|
||||
xxl-job:
|
||||
executor:
|
||||
admin-address: http://47.111.143.211:8282/xxl-job-admin # 调度中心部署根地址 [选填]:如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行"执行器心跳注册"和"任务结果回调";为空则关闭自动注册;
|
||||
access-token: jeepayTaskToken@2022 # 执行器通讯TOKEN
|
||||
# appname: jeepay-plus-bill-executor # 执行器AppName [选填]:执行器心跳注册分组依据;为空则关闭自动注册
|
||||
# port: # 执行器端口号 [选填]:小于等于0则自动获取;默认端口为9999,单机部署多个执行器时,注意要配置不同执行器端口;
|
||||
log-path: ${logging.file.path} # 执行器运行日志文件存储磁盘路径 [选填] :需要对该路径拥有读写权限;为空则使用默认路径;
|
||||
logretentiondays: 7 # 执行器日志文件保存天数 [选填] : 过期日志自动清理, 限制值大于等于3时生效; 否则, 如-1, 关闭自动清理功能;
|
||||
|
||||
db-config:
|
||||
master: #主库配置(必填)
|
||||
# yml填写url连接串, 无需将&符号进行转义
|
||||
url: jdbc:mysql://47.111.143.211:3306/yinshangfu?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true
|
||||
username: root
|
||||
password: YinShangFuMysql@123456
|
||||
encrypt-account: false # 连接账号和密码是否已加密。 true:db的账密需配置密文,函数详见 DBProp.main(); false: db账密请填写明文
|
||||
# 连接池配置项
|
||||
initial-size: 5 #初始化时建立物理连接的个数
|
||||
min-idle: 5 #最小连接池数量
|
||||
max-active: 30 #最大连接池数量
|
||||
max-wait: 60000 #获取连接时最大等待时间,单位毫秒
|
||||
# 检测相关
|
||||
test-while-idle: true # 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
|
||||
test-on-borrow: false # 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
|
||||
test-on-return: false # 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
|
||||
time-between-eviction-runs-millis: 60000 #配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
|
||||
min-evictable-idle-time-millis: 300000 #连接保持空闲而不被驱逐的最小时间
|
||||
validation-query: SELECT 1 FROM DUAL
|
||||
# 是否缓存preparedStatement
|
||||
pool-prepared-statements: false # 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。
|
||||
max-pool-prepared-statement-per-connection-size: 20 # 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。
|
||||
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计 通过connectProperties属性来打开mergeSql功能;慢SQL记录
|
||||
filters: stat,wall
|
||||
connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
|
||||
|
||||
slave: #从库配置(可选), 若没有显式配置则使用master的配置项。 配置参数与master一致。
|
||||
# yml填写url连接串, 无需将&符号进行转义
|
||||
url: jdbc:mysql://47.111.143.211:3306/yinshangfu?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true
|
||||
username: root
|
||||
password: YinShangFuMysql@123456
|
||||
encrypt-account: false # 连接账号和密码是否已加密。 true:db的账密需配置密文,函数详见 DBProp.main(); false: db账密请填写明文
|
||||
# 连接池配置项
|
||||
initial-size: 5 #初始化时建立物理连接的个数
|
||||
min-idle: 5 #最小连接池数量
|
||||
max-active: 30 #最大连接池数量
|
||||
max-wait: 60000 #获取连接时最大等待时间,单位毫秒
|
||||
# 检测相关
|
||||
test-while-idle: true # 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
|
||||
test-on-borrow: false # 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
|
||||
test-on-return: false # 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
|
||||
time-between-eviction-runs-millis: 60000 #配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
|
||||
min-evictable-idle-time-millis: 300000 #连接保持空闲而不被驱逐的最小时间
|
||||
validation-query: SELECT 1 FROM DUAL
|
||||
# 是否缓存preparedStatement
|
||||
pool-prepared-statements: false # 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。
|
||||
max-pool-prepared-statement-per-connection-size: 20 # 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。
|
||||
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计 通过connectProperties属性来打开mergeSql功能;慢SQL记录
|
||||
filters: stat,wall
|
||||
connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
|
||||
isys:
|
||||
#是否允许跨域请求 [生产环境建议关闭, 若api与前端项目没有在同一个域名下时,应开启此配置或在nginx统一配置允许跨域]
|
||||
allow-cors: true
|
||||
|
||||
db-encrypt-secret: 1234567890123456 #DB SM4 加解密秘钥 (必须16位) [每个系统配置必须相同,否则加解密不一致导致业务异常!]
|
||||
http-message-encrypt-secret: 1234567890123456 #web传输加解密 秘钥 (必须16位) [每个系统配置必须相同,否则加解密不一致导致业务异常!]
|
||||
|
||||
# 支付网关的公钥和私钥(系统级别!), 请妥善保存,用于回调商户的商户侧的验证, 首次设置好之后不可随意变更!
|
||||
sys-RSA2-private-key: MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCLU0lXJu9vcJCwrwFGwT1CqXUSY+JMW2iSRPtgLw6lxjU403hS1VyKxA5uTZokv80Wd+bcxDMrM9DwHeGqhjlWvbB/lqaRliJJRdgLVUedrDY+3YSN75uHBtLmxZbnaUpV6/aWA/a+lkNqHxYCWB1jggFB9DhVg2SgoMGDOYHDNA5ZDl47sKpanW0kfG9lINSV4xgDPmAJxUnhkG/7eVEBDev9EIhc+LIMC7Zj+UYc+s/TK4c31fFTW4dZAp3LVEdct9qXU5qm/fXIXxeo3E0bWyOP3VL4Xmx2S9Host1YzjzXPSi1TJjX7rxQkhmbE/dQJ+ws/VvKPuUpmLEPGsm/AgMBAAECggEBAIONCFq58KoQZw3ssA/WtbkTt+69URc31+0EJTYUOIheNjKJubq8qrx7kgSkUT8RutvUKq+YsZfBPS77h/Ay/EDiqpxN6sjcMVNuFyfcRdqimDWTg21hKEC+OLSdLHcj+4RVYGcVJw2dY9n3sBhWiqlCP12+8tILViA0qYL18YgVYJM3bL2MCXfUnm8/Rn1ut5LuDtU/UuaVz9vuCqNirZJedZx3WEq69ZRt9m44XN934NikbUGxQRlz32WRXDo+ssSTu3174UbDYc8nhqO0jUvuzfjOOMf9NYRJsgqVihxMLvvMaUhEE3w6qZPLMj6KhTiG5QHexBbyLgDxH4TZ4gECgYEAz7vZFMoKYifCi+eFykH/ad8QYYoYLlrU1EN2fpIJqwSHZbpBfB8NM5Ov26xU/aNHGKxtSOrUFva5sWub5f9OlsOAmaUOPuVuaJbsq+e3cNQ41jBcdppGJLNx1p/69zR1rF9TbI9Ambd8sOgX3OZmImA2Ldlk2KvMKRruxwc4uN8CgYEAq7J0u5KTwI3PxENLWQ/6tOBNdbCoyqFM+FdANVHRA4dhhdoJ1x0bpdt3tapPFJTBURSEspNxPl4iT+GdpoF6KwqTsQFmB5TLlfx8wY9SIc+sI/ifZvMA5Dv8vVfYWNig7rGV+vIyJCCNbJ5OMa1xvxTDc7Dx4XPxcJ4sR1ZyqyECgYAe447O8ZADsmfSR9X0EkY5ZurXpiIcWnNFMNbg0TRQ0raTYNO18iQTZEWFA6YLpQjAWXtSmWB6HavU/uxKkeEMt/taXVm17oWxVafRk/4J7/SXnM9S73O4p1opENbPhWRuAiq0fMSdVtRatdg+h5/uQqIrxSSit0D/Z7rTq3Y6vwKBgQCd8AlbJckOHiTZd8GOypkm2xHFydxqkJfZ9YCVy44Fvfnig5/7pcXx+oEStfgKiY+OQt6R2fkYksTjUDmRmZbEkvUqpIuzO5dOf7RO5MR7X6oMaL5QmAXg7KFflrfnelYHW4oIDdQ70UnmeXSaU97HE5V7DXBioCGfI5C9inLuoQKBgQCwJmQ2heyTbG1DIBuqf+GFXLuOp76M/7S9c+5R7yfxyTzAbiKRIPeSF5wlxNXEnGwK7qB9CmctlBdnV7A0qnZVFMXf7AbBDUzOCjiy1RSh04BNPnu0dTIygX2PE5inltrHiZtTgciKwj9MexT97F4mTR76kIMz5SGNZe3PscQr7g==
|
||||
sys-RSA2-public-key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAi1NJVybvb3CQsK8BRsE9Qql1EmPiTFtokkT7YC8OpcY1ONN4UtVcisQObk2aJL/NFnfm3MQzKzPQ8B3hqoY5Vr2wf5amkZYiSUXYC1VHnaw2Pt2Eje+bhwbS5sWW52lKVev2lgP2vpZDah8WAlgdY4IBQfQ4VYNkoKDBgzmBwzQOWQ5eO7CqWp1tJHxvZSDUleMYAz5gCcVJ4ZBv+3lRAQ3r/RCIXPiyDAu2Y/lGHPrP0yuHN9XxU1uHWQKdy1RHXLfal1Oapv31yF8XqNxNG1sjj91S+F5sdkvR6LLdWM481z0otUyY1+68UJIZmxP3UCfsLP1byj7lKZixDxrJvwIDAQAB
|
||||
|
||||
#是否内存缓存配置信息: true表示开启如支付网关地址/商户应用配置/服务商配置等, 开启后需检查MQ的广播模式是否正常; false表示直接查询DB.
|
||||
cache-config: false
|
||||
mq:
|
||||
vender: rabbitMQ
|
||||
|
||||
oss:
|
||||
file-root-path: D:/jeepayFiles #存储根路径 ( 无需以‘/’结尾 )
|
||||
file-public-path: ${isys.oss.file-root-path}/public #公共读取块 ( 一般配合root-path参数进行设置,需以‘/’ 开头, 无需以‘/’结尾 )
|
||||
7
jeepay-member/src/main/resources/application.yml
Normal file
7
jeepay-member/src/main/resources/application.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
server:
|
||||
port: 9221 #设置端口
|
||||
servlet:
|
||||
context-path: / #设置应用的目录. 前缀需要带/, 无需设置后缀, 示例 【 /xxx 】 or 【 / 】
|
||||
spring:
|
||||
profiles:
|
||||
active: dev
|
||||
8
jeepay-member/src/main/resources/banner.txt
Normal file
8
jeepay-member/src/main/resources/banner.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
__
|
||||
/ /___ ___ ____ ____ ___ __
|
||||
__ / // _ \/ _ \/ __ \/ __ `/ / / /
|
||||
/ /_/ // __/ __/ /_/ / /_/ / /_/ /
|
||||
\____/ \___/\___/ .___/\__,_/\__, /
|
||||
/_/ /____/
|
||||
:: Jeepay Plus S3 :: (v3.3.6.RELEASE)
|
||||
计全支付 - 让支付接入更简单 : https://www.jeequan.com
|
||||
69
jeepay-member/src/main/resources/logback-spring.xml
Normal file
69
jeepay-member/src/main/resources/logback-spring.xml
Normal file
@@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration scan="false" debug="false">
|
||||
|
||||
<!-- 日志存放路径, 读取application.yml 需要使用springProperty获取 -->
|
||||
<springProperty scope="context" name="currentLoggerFilePath" source="logging.file.path"/>
|
||||
|
||||
<!-- 主日志级别配置 -->
|
||||
<springProperty scope="context" name="currentRootLevel" source="logging.level.root"/>
|
||||
|
||||
<!-- 项目配置, 如修改包名,请搜索并全部替换掉 -->
|
||||
<springProperty scope="context" name="currentProjectLevel" source="logging.level.com.jeequan.jeepay"/>
|
||||
|
||||
<!-- 日志文件名称 logback属性 -->
|
||||
<property name="currentLoggerFileName" value="mbr" />
|
||||
<!-- 日志格式, 参考:https://logback.qos.ch/manual/layouts.html -->
|
||||
<property name="currentLoggerPattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%thread] %logger{15} - %msg%n" />
|
||||
|
||||
<!-- appender: 控制台日志 -->
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder charset="UTF-8" >
|
||||
<pattern>${currentLoggerPattern}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- appender:主日志文件 -->
|
||||
<appender name="ALL_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<!-- 日志文件路径及文件名 -->
|
||||
<file>${currentLoggerFilePath}/${currentLoggerFileName}.all.log</file>
|
||||
<!-- 内容编码及格式 -->
|
||||
<encoder charset="UTF-8" ><pattern>${currentLoggerPattern}</pattern></encoder>
|
||||
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!-- 每天日志归档路径以及格式 -->
|
||||
<fileNamePattern>${currentLoggerFilePath}/${currentLoggerFileName}.all.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<maxHistory>5</maxHistory> <!--日志文件保留天数-->
|
||||
</rollingPolicy>
|
||||
</appender>
|
||||
|
||||
<!-- appender:错误信息日志文件 -->
|
||||
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<!-- 日志文件路径及文件名 -->
|
||||
<file>${currentLoggerFilePath}/${currentLoggerFileName}.error.log</file>
|
||||
<!-- 内容编码及格式 -->
|
||||
<encoder charset="UTF-8" ><pattern>${currentLoggerPattern}</pattern></encoder>
|
||||
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!-- 每天日志归档路径以及格式 -->
|
||||
<fileNamePattern>${currentLoggerFilePath}/${currentLoggerFileName}.error.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<maxHistory>20</maxHistory> <!--日志文件保留天数-->
|
||||
</rollingPolicy>
|
||||
<!-- 此日志文件只记录ERROR级别的 -->
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<level>ERROR</level>
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<!-- 主日志级别配置 -->
|
||||
<root level="${currentRootLevel}">
|
||||
<appender-ref ref="STDOUT" />
|
||||
<appender-ref ref="ALL_FILE" />
|
||||
<appender-ref ref="ERROR_FILE" />
|
||||
</root>
|
||||
|
||||
<!-- 项目日志级别配置 -->
|
||||
<logger name="com.jeequan.jeepay" level="${currentProjectLevel}"/>
|
||||
|
||||
</configuration>
|
||||
4
jeepay-member/src/main/resources/static/index.html
Normal file
4
jeepay-member/src/main/resources/static/index.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<html>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user