Commit 48c5d532 authored by terrfly's avatar terrfly
Browse files

Merge remote-tracking branch 'origin/dev' into master

parents deb2eeb9 d657b58b
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jeequan.jeepay.oss.constant;
import lombok.Getter;
/*
* oss 服务枚举值
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/7/12 10:48
*/
@Getter
public enum OssServiceTypeEnum {
LOCAL("local"), //本地存储
ALIYUN_OSS("aliyun-oss"); //阿里云oss
/** 名称 **/
private String serviceName;
OssServiceTypeEnum(String serviceName){
this.serviceName = serviceName;
}
}
......@@ -13,23 +13,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jeequan.jeepay.mgr.ctrl.common;
package com.jeequan.jeepay.oss.ctrl;
import cn.hutool.core.lang.UUID;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.ctrls.AbstractCtrl;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.model.OssFileConfig;
import com.jeequan.jeepay.core.utils.FileKit;
import com.jeequan.jeepay.mgr.config.SystemYmlConfig;
import com.jeequan.jeepay.mgr.ctrl.CommonCtrl;
import com.jeequan.jeepay.service.impl.SysConfigService;
import com.jeequan.jeepay.oss.model.OssFileConfig;
import com.jeequan.jeepay.oss.service.IOssService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
/*
* 统一文件上传接口(ossFile)
*
......@@ -39,10 +36,9 @@ import java.io.File;
*/
@RestController
@RequestMapping("/api/ossFiles")
public class OssFileController extends CommonCtrl {
public class OssFileController extends AbstractCtrl {
@Autowired private SystemYmlConfig systemYmlConfig;
@Autowired private SysConfigService sysConfigService;
@Autowired private IOssService ossService;
/** 上传文件 (单文件上传) */
@PostMapping("/{bizType}")
......@@ -51,7 +47,6 @@ public class OssFileController extends CommonCtrl {
if( file == null ) return ApiRes.fail(ApiCodeEnum.SYSTEM_ERROR, "选择文件不存在");
try {
OssFileConfig ossFileConfig = OssFileConfig.getOssFileConfigByBizType(bizType);
//1. 判断bizType 是否可用
......@@ -70,35 +65,10 @@ public class OssFileController extends CommonCtrl {
throw new BizException("上传大小请限制在["+ossFileConfig.getMaxSize() / 1024 / 1024 +"M]以内!");
}
boolean isAllowPublicRead = ossFileConfig.isAllowPublicRead(); //是否允许公共读, true:公共读, false:私有文件
//公共读 & 是否上传到oss
boolean isYunOss = false; //TODO 暂时不支持云oss方式
if(isAllowPublicRead && isYunOss){
return null;
}
//以下为文件上传到本地
// 新文件地址
String newFileName = UUID.fastUUID() + "." + fileSuffix;
// 保存的文件夹名称
String saveFilePath = isAllowPublicRead ? systemYmlConfig.getOssFile().getPublicPath() : systemYmlConfig.getOssFile().getPrivatePath();
saveFilePath = saveFilePath + File.separator + bizType + File.separator + newFileName;
//保存文件
saveFile(file, saveFilePath);
//返回响应结果
String resultUrl = bizType + "/" + newFileName;
if(isAllowPublicRead){ //允许公共读取
resultUrl = sysConfigService.getDBApplicationConfig().getOssPublicSiteUrl() + "/" + resultUrl;
}
return ApiRes.ok(resultUrl);
// 新文件地址 (xxx/xxx.jpg 格式)
String saveDirAndFileName = bizType + "/" + UUID.fastUUID() + "." + fileSuffix;
String url = ossService.upload2PreviewUrl(ossFileConfig.getOssSavePlaceEnum(), file, saveDirAndFileName);
return ApiRes.ok(url);
} catch (BizException biz) {
throw biz;
......@@ -108,4 +78,4 @@ public class OssFileController extends CommonCtrl {
}
}
}
\ No newline at end of file
}
......@@ -13,8 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jeequan.jeepay.core.model;
package com.jeequan.jeepay.oss.model;
import com.jeequan.jeepay.oss.constant.OssSavePlaceEnum;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
......@@ -53,13 +54,13 @@ public class OssFileConfig {
private static final Map<String, OssFileConfig> ALL_BIZ_TYPE_MAP = new HashMap<>();
static{
ALL_BIZ_TYPE_MAP.put(BIZ_TYPE.AVATAR, new OssFileConfig(true, IMG_SUFFIX, DEFAULT_MAX_SIZE) );
ALL_BIZ_TYPE_MAP.put(BIZ_TYPE.IF_BG, new OssFileConfig(true, IMG_SUFFIX, DEFAULT_MAX_SIZE) );
ALL_BIZ_TYPE_MAP.put(BIZ_TYPE.CERT, new OssFileConfig(false, new HashSet<>(Arrays.asList(ALL_SUFFIX_FLAG)), DEFAULT_MAX_SIZE) );
ALL_BIZ_TYPE_MAP.put(BIZ_TYPE.AVATAR, new OssFileConfig(OssSavePlaceEnum.PUBLIC, IMG_SUFFIX, DEFAULT_MAX_SIZE) );
ALL_BIZ_TYPE_MAP.put(BIZ_TYPE.IF_BG, new OssFileConfig(OssSavePlaceEnum.PUBLIC, IMG_SUFFIX, DEFAULT_MAX_SIZE) );
ALL_BIZ_TYPE_MAP.put(BIZ_TYPE.CERT, new OssFileConfig(OssSavePlaceEnum.PRIVATE, new HashSet<>(Arrays.asList(ALL_SUFFIX_FLAG)), DEFAULT_MAX_SIZE) );
}
/** 是否允许公共读 **/
private boolean allowPublicRead = false;
/** 存储位置 **/
private OssSavePlaceEnum ossSavePlaceEnum;
/** 允许的文件后缀, 默认全部类型 **/
private Set<String> allowFileSuffix = new HashSet<>(Arrays.asList(ALL_SUFFIX_FLAG));
......
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jeequan.jeepay.oss.service;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.GetObjectRequest;
import com.jeequan.jeepay.oss.config.AliyunOssYmlConfig;
import com.jeequan.jeepay.oss.constant.OssSavePlaceEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.PostConstruct;
import java.io.File;
/**
* 阿里云OSS 实现类
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/7/12 18:20
*/
@Service
@Slf4j
@ConditionalOnProperty(name = "isys.oss.service-type", havingValue = "aliyun-oss")
public class AliyunOssService implements IOssService{
@Autowired private AliyunOssYmlConfig aliyunOssYmlConfig;
// ossClient 初始化
private OSS ossClient = null;
@PostConstruct
public void init(){
ossClient = new OSSClientBuilder().build(aliyunOssYmlConfig.getEndpoint(), aliyunOssYmlConfig.getAccessKeyId(), aliyunOssYmlConfig.getAccessKeySecret());
}
@Override
public String upload2PreviewUrl(OssSavePlaceEnum ossSavePlaceEnum, MultipartFile multipartFile, String saveDirAndFileName) {
try {
this.ossClient.putObject(aliyunOssYmlConfig.getPublicBucketName(), saveDirAndFileName, multipartFile.getInputStream());
if(ossSavePlaceEnum == OssSavePlaceEnum.PUBLIC){
// 文档:https://www.alibabacloud.com/help/zh/doc-detail/39607.htm example: https://BucketName.Endpoint/ObjectName
return "https://" + aliyunOssYmlConfig.getPublicBucketName() + "." + aliyunOssYmlConfig.getEndpoint() + "/" + saveDirAndFileName;
}
return saveDirAndFileName;
} catch (Exception e) {
log.error("error", e);
return null;
}
}
@Override
public boolean downloadFile(OssSavePlaceEnum ossSavePlaceEnum, String source, String target) {
try {
String bucket = ossSavePlaceEnum == OssSavePlaceEnum.PRIVATE ? aliyunOssYmlConfig.getPrivateBucketName() : aliyunOssYmlConfig.getPublicBucketName();
this.ossClient.getObject(new GetObjectRequest(bucket, source), new File(target));
return true;
} catch (Exception e) {
log.error("error", e);
return false;
}
}
}
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jeequan.jeepay.oss.service;
import com.jeequan.jeepay.oss.constant.OssSavePlaceEnum;
import org.springframework.web.multipart.MultipartFile;
/**
* OSSService 接口
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/7/12 18:18
*/
public interface IOssService {
/** 上传文件 & 生成下载/预览URL **/
String upload2PreviewUrl(OssSavePlaceEnum ossSavePlaceEnum, MultipartFile multipartFile, String saveDirAndFileName);
/** 将文件下载到本地
* 返回是否 写入成功
* false: 写入失败, 或者文件不存在
* **/
boolean downloadFile(OssSavePlaceEnum ossSavePlaceEnum, String source, String target);
}
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jeequan.jeepay.oss.service;
import com.jeequan.jeepay.core.service.ISysConfigService;
import com.jeequan.jeepay.oss.config.OssYmlConfig;
import com.jeequan.jeepay.oss.constant.OssSavePlaceEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
/**
* 本地存储 实现类
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/7/12 18:19
*/
@Service
@Slf4j
@ConditionalOnProperty(name = "isys.oss.service-type", havingValue = "local")
public class LocalFileService implements IOssService{
@Autowired private ISysConfigService sysConfigService;
@Autowired private OssYmlConfig ossYmlConfig;
@Override
public String upload2PreviewUrl(OssSavePlaceEnum ossSavePlaceEnum, MultipartFile multipartFile, String saveDirAndFileName) {
try {
String savePath = ossSavePlaceEnum ==
OssSavePlaceEnum.PUBLIC ? ossYmlConfig.getOss().getFilePublicPath() : ossYmlConfig.getOss().getFilePrivatePath();
File saveFile = new File(savePath + File.separator + saveDirAndFileName);
//如果文件夹不存在则创建文件夹
File dir = saveFile.getParentFile();
if(!dir.exists()) dir.mkdirs();
multipartFile.transferTo(saveFile);
} catch (Exception e) {
log.error("", e);
}
// 私有文件 不返回预览文件地址
if(ossSavePlaceEnum == OssSavePlaceEnum.PRIVATE){
return saveDirAndFileName;
}
return sysConfigService.getDBApplicationConfig().getOssPublicSiteUrl() + "/" + saveDirAndFileName;
}
@Override
public boolean downloadFile(OssSavePlaceEnum ossSavePlaceEnum, String source, String target) {
return false;
}
}
......@@ -25,6 +25,13 @@
<version>${isys.version}</version>
</dependency>
<!-- 依赖[ oss ]包 -->
<dependency>
<groupId>com.jeequan</groupId>
<artifactId>jeepay-oss</artifactId>
<version>${isys.version}</version>
</dependency>
<!-- 依赖 sping-boot-web -->
<dependency>
<groupId>org.springframework.boot</groupId>
......@@ -79,6 +86,13 @@
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<!-- 添加对rocketMQ的支持 -->
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>${rocketmq.spring.boot.starter.version}</version>
</dependency>
<!--wx_pay https://github.com/wechat-group/WxJava -->
<dependency>
<groupId>com.github.binarywang</groupId>
......
......@@ -17,6 +17,7 @@ package com.jeequan.jeepay.pay.channel.wxpay;
import com.alibaba.fastjson.JSONObject;
import com.github.binarywang.wxpay.bean.notify.SignatureHeader;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyV3Result;
import com.github.binarywang.wxpay.config.WxPayConfig;
......@@ -125,6 +126,7 @@ public class WxpayChannelNoticeService extends AbstractChannelNoticeService {
channelResult.setChannelOrderId(result.getTransactionId()); //渠道订单号
channelResult.setChannelUserId(result.getOpenid()); //支付用户ID
channelResult.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS);
channelResult.setResponseEntity(textResp(WxPayNotifyResponse.successResp("OK")));
}else if (CS.PAY_IF_VERSION.WX_V3.equals(mchAppConfigContext.getWxServiceWrapper().getApiVersion())) { // V3
// 获取回调参数
......@@ -148,17 +150,17 @@ public class WxpayChannelNoticeService extends AbstractChannelNoticeService {
channelResult.setChannelUserId(payer.getOpenid()); //支付用户ID
}
JSONObject resJSON = new JSONObject();
resJSON.put("code", "SUCCESS");
resJSON.put("message", "成功");
ResponseEntity okResponse = jsonResp(resJSON);
channelResult.setResponseEntity(okResponse); //响应数据
}else {
throw ResponseException.buildText("API_VERSION ERROR");
}
JSONObject resJSON = new JSONObject();
resJSON.put("code", "SUCCESS");
resJSON.put("message", "成功");
ResponseEntity okResponse = jsonResp(resJSON);
channelResult.setResponseEntity(okResponse); //响应数据
return channelResult;
} catch (Exception e) {
......
......@@ -17,7 +17,6 @@ package com.jeequan.jeepay.pay.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
import org.springframework.stereotype.Component;
/**
......@@ -35,22 +34,4 @@ public class SystemYmlConfig {
/** 是否允许跨域请求 [生产环境建议关闭, 若api与前端项目没有在同一个域名下时,应开启此配置或在nginx统一配置允许跨域] **/
private Boolean allowCors;
@NestedConfigurationProperty //指定该属性为嵌套值, 否则默认为简单值导致对象为空(外部类不存在该问题, 内部static需明确指定)
private OssFile ossFile;
/** 系统oss配置信息 **/
@Data
public static class OssFile{
/** 存储根路径 **/
private String rootPath;
/** 公共读取块 **/
private String publicPath;
/** 私有读取块 **/
private String privatePath;
}
}
\ No newline at end of file
}
......@@ -231,7 +231,13 @@ public abstract class AbstractPayOrderController extends ApiController {
Date nowDate = new Date();
payOrder.setExpiredTime(DateUtil.offsetHour(nowDate, 2)); //订单过期时间 默认两个小时
//订单过期时间 单位: 秒
if(rq.getExpiredTime() != null){
payOrder.setExpiredTime(DateUtil.offsetSecond(nowDate, rq.getExpiredTime()));
}else{
payOrder.setExpiredTime(DateUtil.offsetHour(nowDate, 2)); //订单过期时间 默认两个小时
}
payOrder.setCreatedAt(nowDate); //订单创建时间
return payOrder;
}
......
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jeequan.jeepay.pay.mq;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.mq.MqCommonService;
import com.jeequan.jeepay.pay.mq.receive.MqReceiveCommon;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Profile;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
/**
* 上游渠道订单轮询查单
* 如:微信的条码支付,没有回调接口, 需要轮询查单完成交易结果通知。
*
*
* @author xiaoyu
* @site https://www.jeepay.vip
* @date 2021/6/25 17:10
*/
@Slf4j
@Component
@Profile(CS.MQTYPE.ROCKET_MQ)
public class RocketMqMessage extends MqCommonService {
@Autowired private RocketMQTemplate rocketMQTemplate;
@Lazy
@Autowired
private MqReceiveCommon mqReceiveCommon;
@Override
public void send(String msg, String sendType) {
if (sendType.equals(CS.MQ.MQ_TYPE_CHANNEL_ORDER_QUERY)) {
channelOrderQuery(msg);
}else if (sendType.equals(CS.MQ.MQ_TYPE_PAY_ORDER_MCH_NOTIFY)) {
payOrderMchNotify(msg);
}
}
@Override
public void send(String msg, long delay, String sendType) {
if (sendType.equals(CS.MQ.MQ_TYPE_CHANNEL_ORDER_QUERY)) {
channelOrderQueryFixed(msg, delay);
}else if (sendType.equals(CS.MQ.MQ_TYPE_PAY_ORDER_MCH_NOTIFY)) {
payOrderMchNotifyFixed(msg, delay);
}
}
/** 发送订单查询消息 **/
public void channelOrderQuery(String msg) {
rocketMQTemplate.convertAndSend(CS.MQ.QUEUE_CHANNEL_ORDER_QUERY, msg);
}
/** 发送订单查询延迟消息 **/
public void channelOrderQueryFixed(String msg, long delay) {
rocketMQTemplate.asyncSend(CS.MQ.QUEUE_CHANNEL_ORDER_QUERY, MessageBuilder.withPayload(msg).build(), new SendCallback() {
@Override
public void onSuccess(SendResult var1) {
log.info("async onSucess SendResult :{}", var1);
}
@Override
public void onException(Throwable var1) {
log.info("async onException Throwable :{}", var1);
}
}, 300000, 2);
}
/** 发送订单回调消息 **/
public void payOrderMchNotify(String msg) {
rocketMQTemplate.convertAndSend(CS.MQ.QUEUE_PAYORDER_MCH_NOTIFY, msg);
}
/** 发送订单回调延迟消息 **/
public void payOrderMchNotifyFixed(String msg, long delay) {
rocketMQTemplate.asyncSend(CS.MQ.QUEUE_PAYORDER_MCH_NOTIFY, MessageBuilder.withPayload(msg).build(), new SendCallback() {
@Override
public void onSuccess(SendResult var1) {
log.info("async onSucess SendResult :{}", var1);
}
@Override
public void onException(Throwable var1) {
log.info("async onException Throwable :{}", var1);
}
}, 300000, 4);
}
/** 接收 查单消息 **/
@Service
@RocketMQMessageListener(topic = CS.MQ.QUEUE_CHANNEL_ORDER_QUERY, consumerGroup = CS.MQ.QUEUE_CHANNEL_ORDER_QUERY)
class receiveChannelOrderQuery implements RocketMQListener<String> {
@Override
public void onMessage(String msg) {
mqReceiveCommon.channelOrderQuery(msg);
}
}
/** 接收 支付订单商户回调消息 **/
@Service
@RocketMQMessageListener(topic = CS.MQ.QUEUE_PAYORDER_MCH_NOTIFY, consumerGroup = CS.MQ.QUEUE_PAYORDER_MCH_NOTIFY)
class receivePayOrderMchNotify implements RocketMQListener<String> {
@Override
public void onMessage(String msg) {
mqReceiveCommon.payOrderMchNotify(msg);
}
}
}
......@@ -30,7 +30,6 @@ import com.jeequan.jeepay.service.impl.PayOrderService;
import com.jeequan.jeepay.service.impl.SysConfigService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
/**
......@@ -59,21 +58,24 @@ public class MqReceiveCommon {
/** 接收 [商户配置信息] 的消息 **/
public void modifyMchInfo(String mchNo) {
log.info("接收 [商户配置信息] 的消息, msg={}", mchNo);
log.info("成功接收 [商户配置信息] 的消息, msg={}", mchNo);
configContextService.initMchInfoConfigContext(mchNo);
log.info(" [商户配置信息] 已重置");
}
/** 接收 [商户应用支付参数配置信息] 的消息 **/
public void modifyMchApp(String mchNoAndAppId) {
log.info("接收 [商户应用支付参数配置信息] 的消息, msg={}", mchNoAndAppId);
log.info("成功接收 [商户应用支付参数配置信息] 的消息, msg={}", mchNoAndAppId);
JSONObject jsonObject = (JSONObject) JSONObject.parse(mchNoAndAppId);
configContextService.initMchAppConfigContext(jsonObject.getString("mchNo"), jsonObject.getString("appId"));
log.info(" [商户应用支付参数配置信息] 已重置");
}
/** 重置ISV信息 **/
public void modifyIsvInfo(String isvNo) {
log.info("重置ISV信息, msg={}", isvNo);
log.info("成功接收 [ISV信息] 重置, msg={}", isvNo);
configContextService.initIsvConfigContext(isvNo);
log.info("[ISV信息] 已重置");
}
/** 接收商户订单回调通知 **/
......@@ -109,11 +111,13 @@ public class MqReceiveCommon {
//通知成功
if("SUCCESS".equalsIgnoreCase(res)){
mchNotifyRecordService.updateNotifyResult(notifyId, MchNotifyRecord.STATE_SUCCESS, res);
return;
}
//通知次数 >= 最大通知次数时, 更新响应结果为异常, 不在继续延迟发送消息
if( currentCount >= record.getNotifyCountLimit() ){
mchNotifyRecordService.updateNotifyResult(notifyId, MchNotifyRecord.STATE_FAIL, res);
return;
}
// 继续发送MQ 延迟发送
......
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jeequan.jeepay.pay.mq.rocketmq;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.pay.mq.receive.MqReceiveCommon;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.annotation.MessageModel;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
/**
* 消息接收
* @author pangxiaoyu
* @site https://www.jeepay.vip
* @date 2021-04-27 15:50
*/
@Slf4j
@Component
@Profile(CS.MQTYPE.ROCKET_MQ)
public class RocketMqReceive {
@Autowired private MqReceiveCommon mqReceiveCommon;
/** 接收 更新服务商信息的消息 **/
@Service
@RocketMQMessageListener(topic = CS.MQ.TOPIC_MODIFY_ISV_INFO, consumerGroup = CS.MQ.TOPIC_MODIFY_ISV_INFO)
class receiveModifyIsvInfo implements RocketMQListener<String> {
@Override
public void onMessage(String isvNo) {
mqReceiveCommon.modifyIsvInfo(isvNo);
}
}
/** 接收 [商户配置信息] 的消息
* 已知推送节点:
* 1. 更新商户基本资料和状态
* 2. 删除商户时
* **/
@Service
@RocketMQMessageListener(topic = CS.MQ.TOPIC_MODIFY_MCH_INFO, consumerGroup = CS.MQ.TOPIC_MODIFY_MCH_INFO)
class receiveModifyMchInfo implements RocketMQListener<String> {
@Override
public void onMessage(String mchNo) {
mqReceiveCommon.modifyMchInfo(mchNo);
}
}
/** 接收 [商户应用支付参数配置信息] 的消息
* 已知推送节点:
* 1. 更新商户应用配置
* 2. 删除商户应用配置
* **/
@Service
@RocketMQMessageListener(topic = CS.MQ.TOPIC_MODIFY_MCH_APP, consumerGroup = CS.MQ.TOPIC_MODIFY_MCH_APP)
class receiveModifyMchApp implements RocketMQListener<String> {
@Override
public void onMessage(String mchNoAndAppId) {
mqReceiveCommon.modifyMchApp(mchNoAndAppId);
}
}
/** 接收 更新系统配置项的消息 **/
@Service
@RocketMQMessageListener(topic = CS.MQ.TOPIC_MODIFY_SYS_CONFIG, consumerGroup = CS.MQ.TOPIC_MODIFY_SYS_CONFIG, messageModel = MessageModel.BROADCASTING)
class receiveInitDbConfig implements RocketMQListener<String> {
@Override
public void onMessage(String msg) {
mqReceiveCommon.initDbConfig(msg);
}
}
}
......@@ -72,8 +72,8 @@ public class UnifiedOrderRQ extends AbstractMchAppRQ {
/** 跳转通知地址 **/
private String returnUrl;
/** 订单失效时间 **/
private String expiredTime;
/** 订单失效时间, 单位:秒 **/
private Integer expiredTime;
/** 特定渠道发起额外参数 **/
private String channelExtra;
......
......@@ -42,6 +42,7 @@ import com.jeequan.jeepay.service.impl.IsvInfoService;
import com.jeequan.jeepay.service.impl.MchAppService;
import com.jeequan.jeepay.service.impl.MchInfoService;
import com.jeequan.jeepay.service.impl.PayInterfaceConfigService;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
......@@ -59,6 +60,7 @@ import java.util.concurrent.ConcurrentHashMap;
* @site https://www.jeepay.vip
* @date 2021/6/8 17:41
*/
@Slf4j
@Service
public class ConfigContextService {
......@@ -354,7 +356,8 @@ public class ConfigContextService {
try {
alipayClient = new DefaultAlipayClient(certAlipayRequest);
} catch (AlipayApiException e) {
e.printStackTrace();
log.error("error" ,e);
alipayClient = null;
}
}else{
alipayClient = new DefaultAlipayClient(sandbox == CS.YES ? AlipayConfig.SANDBOX_SERVER_URL : AlipayConfig.PROD_SERVER_URL
......
package com.jeequan.jeepay.pay.util;
import cn.hutool.core.io.FileUtil;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.oss.config.OssYmlConfig;
import com.jeequan.jeepay.oss.constant.OssSavePlaceEnum;
import com.jeequan.jeepay.oss.constant.OssServiceTypeEnum;
import com.jeequan.jeepay.oss.service.IOssService;
import com.jeequan.jeepay.pay.config.SystemYmlConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.IOException;
/*
* 支付平台 获取系统文件工具类
......@@ -16,13 +23,59 @@ import java.io.File;
@Component
public class ChannelCertConfigKitBean {
@Autowired private SystemYmlConfig systemYmlConfig;
@Autowired private OssYmlConfig ossYmlConfig;
@Autowired private IOssService ossService;
public String getCertFilePath(String certFilePath){
return systemYmlConfig.getOssFile().getPrivatePath() + File.separator + certFilePath;
return getCertFile(certFilePath).getAbsolutePath();
}
public File getCertFile(String certFilePath){
return new File(getCertFilePath(certFilePath));
File certFile = new File(ossYmlConfig.getOss().getFilePrivatePath() + File.separator + certFilePath);
if(certFile.exists()){ // 本地存在直接返回
return certFile;
}
// 以下为 文件不存在的处理方式
// 是否本地存储
boolean isLocalSave = OssServiceTypeEnum.LOCAL.equals(ossYmlConfig.getOss().getServiceType());
// 本地存储 & 文件不存在
if(isLocalSave){
return certFile;
}
// 已经向oss请求并且返回了空文件时
if(new File(certFile.getAbsolutePath() + ".notexists").exists()){
return certFile;
}
// 请求下载并返回 新File
return downloadFile(certFilePath, certFile);
}
/** 下载文件 **/
private synchronized File downloadFile(String dbCertFilePath, File certFile){
//请求文件并写入
boolean isSuccess = ossService.downloadFile(OssSavePlaceEnum.PRIVATE, dbCertFilePath, certFile.getAbsolutePath());
// 下载成功 返回新的File对象
if(isSuccess) {
return new File(certFile.getAbsolutePath());
}
// 下载失败, 写入.notexists文件, 避免那下次再次下载影响效率。
try {
new File(certFile.getAbsolutePath() + ".notexists").createNewFile();
} catch (IOException e) {
}
return certFile;
}
}
server:
port: 9216 #设置端口为 9216
servlet:
context-path: / #设置应用的目录. 前缀需要带/, 无需设置后缀, 示例 【 /xxx 】 or 【 / 】
spring:
mvc:
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
datasource:
# yml填写url连接串, 无需将&符号进行转义
url: jdbc:mysql://127.0.0.1:3306/jeepaydb?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&useSSL=false
username: root
password:
druid:
# 连接池配置项
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
cache:
type: redis
redis:
host: 127.0.0.1
port: 6379
timeout: 1000
database: 3 #1库:运营平台 #2库:商户系统 #3库:支付网关
password:
# 注意:以下MQ配置需注意【如需使用activeMQ则需将rabbitMQ配置注释即可】
# profiles:
# include:
# - activeMQ
# - rabbitMQ # 需要安装延迟队列插件:https://www.rabbitmq.com/blog/2015/04/16/scheduling-messages-with-rabbitmq/
#activeMQ配置
# activemq:
# broker-url: tcp://localhost:61616 #连接地址
#rabbitmq配置
# rabbitmq:
# addresses: 127.0.0.1:5672
# username: guest
# password: guest
# dynamic: true
# virtual-host: /
port: 9216 #设置端口
#日志配置参数。
# 当存在logback-spring.xml文件时: 该配置将引进到logback配置, springboot配置不生效。
# 不存在logback-spring.xml 文件时, 使用springboot的配置, 同样可用。
logging:
level:
root: info #主日志级别
com.jeequan.jeepay: debug #该项目日志级别,当需要打印sql时请开启为debug
path: E:/logs #日志存放地址
#系统业务参数
isys:
allow-cors: true #是否允许跨域请求 [生产环境建议关闭, 若api与前端项目没有在同一个域名下时,应开启此配置或在nginx统一配置允许跨域]
# 文件系统配置项(系统内oss, 并非云oss)
oss-file:
root-path: /home/jeepay/upload #存储根路径 ( 无需以‘/’结尾 )
private-path: ${isys.oss-file.root-path}/private #私有化本地访问,不允许url方式公共读取 ( 一般配合root-path参数进行设置,需以‘/’ 开头, 无需以‘/’结尾 )
spring:
redis:
database: 3 #1库:运营平台 #2库:商户系统 #3库:支付网关
......@@ -19,6 +19,7 @@ import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jeequan.jeepay.core.entity.SysConfig;
import com.jeequan.jeepay.core.model.DBApplicationConfig;
import com.jeequan.jeepay.core.service.ISysConfigService;
import com.jeequan.jeepay.service.mapper.SysConfigMapper;
import org.apache.commons.lang3.tuple.MutablePair;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -36,7 +37,7 @@ import java.util.Set;
* @since 2020-07-29
*/
@Service
public class SysConfigService extends ServiceImpl<SysConfigMapper, SysConfig> {
public class SysConfigService extends ServiceImpl<SysConfigMapper, SysConfig> implements ISysConfigService {
@Autowired
private SysConfigService sysConfigService;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment