Commit de3de82d authored by dingzhiwei's avatar dingzhiwei
Browse files

初始化Jeepay项目

parent 40dcaf4a
/*
* 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.util;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/*
* 二维码生成器
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:54
*/
public class CodeImgUtil {
private static final Logger _log = LoggerFactory.getLogger(CodeImgUtil.class);
// 二维码尺寸List
private static List<Integer> sizeList = new ArrayList<Integer>();
static {
sizeList.add(258);
sizeList.add(344);
sizeList.add(430);
sizeList.add(860);
sizeList.add(1280);
}
public static List<Integer> getEwmSizeList() {
return sizeList;
}
//TODO
// 图片宽度的一般
private static final int IMAGE_WIDTH = 25;
private static final int IMAGE_HEIGHT = 25;
private static final int IMAGE_HALF_WIDTH = IMAGE_WIDTH / 2;
private static final int FRAME_WIDTH = 2;
// 二维码写码器
private static MultiFormatWriter mutiWriter = new MultiFormatWriter();
/**
*
* @param content
* 二维码显示的文本
* @param width
* 二维码的宽度
* @param height
* 二维码的高度
* @param srcImagePath
* 中间嵌套的图片
* @param destImagePath
* 二维码生成的地址
*/
public static void encode(String content, int width, int height,
String srcImagePath, String destImagePath, String fileName) {
try {
File dir = new File(destImagePath);
_log.error("==================" + destImagePath);
_log.error("==================" + srcImagePath);
if (!dir.exists()) {
_log.error("==================notExist");
boolean result = dir.mkdirs();
_log.error("==================midirsResult" + result);
}
// ImageIO.write 参数 1、BufferedImage 2、输出的格式 3、输出的文件
ImageIO.write(genBarcode(content, width, height, srcImagePath),
"jpg", new File(destImagePath + fileName));
} catch (Exception e) {
_log.error("生成二维码出错", e);
}
}
/**
* 得到BufferedImage
*
* @param content
* 二维码显示的文本
* @param width
* 二维码的宽度
* @param height
* 二维码的高度
* @param srcImagePath
* 中间嵌套的图片
* @return
* @throws WriterException
* @throws IOException
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
private static BufferedImage genBarcode(String content, int width,
int height, String srcImagePath) throws WriterException,
IOException {
// 读取源图像
BufferedImage scaleImage = scale(srcImagePath, IMAGE_WIDTH,
IMAGE_HEIGHT, false);
int[][] srcPixels = new int[IMAGE_WIDTH][IMAGE_HEIGHT];
for (int i = 0; i < scaleImage.getWidth(); i++) {
for (int j = 0; j < scaleImage.getHeight(); j++) {
srcPixels[i][j] = scaleImage.getRGB(i, j);
}
}
java.util.Hashtable hint = new java.util.Hashtable();
hint.put(EncodeHintType.CHARACTER_SET, "utf-8");
hint.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
hint.put(EncodeHintType.MARGIN, 1);
// 生成二维码
BitMatrix matrix = mutiWriter.encode(content, BarcodeFormat.QR_CODE,
width, height, hint);
// 二维矩阵转为一维像素数组
int halfW = matrix.getWidth() / 2;
int halfH = matrix.getHeight() / 2;
int[] pixels = new int[width * height];
for (int y = 0; y < matrix.getHeight(); y++) {
for (int x = 0; x < matrix.getWidth(); x++) {
// 读取图片
if (x > halfW - IMAGE_HALF_WIDTH
&& x < halfW + IMAGE_HALF_WIDTH
&& y > halfH - IMAGE_HALF_WIDTH
&& y < halfH + IMAGE_HALF_WIDTH) {
pixels[y * width + x] = srcPixels[x - halfW
+ IMAGE_HALF_WIDTH][y - halfH + IMAGE_HALF_WIDTH];
}
// 在图片四周形成边框
else if ((x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH
&& x < halfW - IMAGE_HALF_WIDTH + FRAME_WIDTH
&& y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH && y < halfH
+ IMAGE_HALF_WIDTH + FRAME_WIDTH)
|| (x > halfW + IMAGE_HALF_WIDTH - FRAME_WIDTH
&& x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH
&& y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH && y < halfH
+ IMAGE_HALF_WIDTH + FRAME_WIDTH)
|| (x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH
&& x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH
&& y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH && y < halfH
- IMAGE_HALF_WIDTH + FRAME_WIDTH)
|| (x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH
&& x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH
&& y > halfH + IMAGE_HALF_WIDTH - FRAME_WIDTH && y < halfH
+ IMAGE_HALF_WIDTH + FRAME_WIDTH)) {
pixels[y * width + x] = 0xfffffff;
} else {
// 此处可以修改二维码的颜色,可以分别制定二维码和背景的颜色;
pixels[y * width + x] = matrix.get(x, y) ? 0xff000000
: 0xfffffff;
}
}
}
BufferedImage image = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
image.getRaster().setDataElements(0, 0, width, height, pixels);
return image;
}
/**
* 把传入的原始图像按高度和宽度进行缩放,生成符合要求的图标
*
* @param srcImageFile
* 源文件地址
* @param height
* 目标高度
* @param width
* 目标宽度
* @param hasFiller
* 比例不对时是否需要补白:true为补白; false为不补白;
* @throws IOException
*/
private static BufferedImage scale(String srcImageFile, int height,
int width, boolean hasFiller) throws IOException {
double ratio = 0.0; // 缩放比例
URL url = new URL(srcImageFile);
BufferedImage srcImage = ImageIO.read(url);
Image destImage = srcImage.getScaledInstance(width, height,
BufferedImage.SCALE_SMOOTH);
// 计算比例
if ((srcImage.getHeight() > height) || (srcImage.getWidth() > width)) {
if (srcImage.getHeight() > srcImage.getWidth()) {
ratio = (new Integer(height)).doubleValue()
/ srcImage.getHeight();
} else {
ratio = (new Integer(width)).doubleValue()
/ srcImage.getWidth();
}
AffineTransformOp op = new AffineTransformOp(AffineTransform
.getScaleInstance(ratio, ratio), null);
destImage = op.filter(srcImage, null);
}
if (hasFiller) {// 补白
BufferedImage image = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
Graphics2D graphic = image.createGraphics();
graphic.setColor(Color.white);
graphic.fillRect(0, 0, width, height);
if (width == destImage.getWidth(null))
graphic.drawImage(destImage, 0, (height - destImage
.getHeight(null)) / 2, destImage.getWidth(null),
destImage.getHeight(null), Color.white, null);
else
graphic.drawImage(destImage,
(width - destImage.getWidth(null)) / 2, 0, destImage
.getWidth(null), destImage.getHeight(null),
Color.white, null);
graphic.dispose();
destImage = image;
}
return (BufferedImage) destImage;
}
/**
* 生成图像
* filePath 存放图片的路径
* fileName 图片的名称
* info 生成图片的链接地址(例如:weixin://wxpay/s/Anp43md)
* width 图片的宽度
* height 图片的高度
* @throws WriterException
* @throws IOException
*/
public static String codeImgEncode(String filePath, String fileName, String info, int width, int height) throws WriterException, IOException {
String format="png";
Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
BitMatrix bitMatrix = new MultiFormatWriter().encode(info,
BarcodeFormat.QR_CODE, width, height, hints);// 生成矩阵
Path path = FileSystems.getDefault().getPath(filePath, fileName);
File dir = new File(filePath);
_log.error("==================" + filePath);
if (!dir.exists()) {
_log.error("==================notExist");
boolean result = dir.mkdirs();
_log.error("==================midirsResult" + result);
}
MatrixToImageWriter.writeToPath(bitMatrix, format, path);// 输出图像
return path.toString();
}
public static void writeQrCode(OutputStream stream, String info, int width, int height) throws WriterException, IOException {
String format="png";
Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
hints.put(EncodeHintType.MARGIN,0);
BitMatrix bitMatrix = new MultiFormatWriter().encode(info,
BarcodeFormat.QR_CODE, width, height, hints);// 生成矩阵
bitMatrix = deleteWhite(bitMatrix);
BufferedImage bi = MatrixToImageWriter.toBufferedImage(bitMatrix);
bi = zoomInImage(bi,width,height);
ImageIO.write(bi,format,stream); // 输出图像
//MatrixToImageWriter.writeToStream(bitMatrix, format, stream);// 输出图像
}
/**
* 解析图像
*/
public static void codeImgDecode() {
String filePath = "D://zxing.png";
BufferedImage image;
try {
image = ImageIO.read(new File(filePath));
LuminanceSource source = new BufferedImageLuminanceSource(image);
Binarizer binarizer = new HybridBinarizer(source);
BinaryBitmap binaryBitmap = new BinaryBitmap(binarizer);
Map<DecodeHintType, Object> hints = new HashMap<DecodeHintType, Object>();
hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");
Result result = new MultiFormatReader().decode(binaryBitmap, hints);// 对图像进行解码
JSONObject content = JSON.parseObject(result.getText());
System.out.println("图片中内容: ");
System.out.println("author: " + content.getString("author"));
System.out.println("zxing: " + content.getString("zxing"));
System.out.println("图片中格式: ");
System.out.println("encode: " + result.getBarcodeFormat());
} catch (IOException e) {
e.printStackTrace();
} catch (NotFoundException e) {
e.printStackTrace();
}
}
/**
* 去除白边
* */
private static BitMatrix deleteWhite(BitMatrix matrix) {
int[] rec = matrix.getEnclosingRectangle();
int resWidth = rec[2] + 1;
int resHeight = rec[3] + 1;
BitMatrix resMatrix = new BitMatrix(resWidth, resHeight);
resMatrix.clear();
for (int i = 0; i < resWidth; i++) {
for (int j = 0; j < resHeight; j++) {
if (matrix.get(i + rec[0], j + rec[1]))
resMatrix.set(i, j);
}
}
return resMatrix;
}
public static BufferedImage zoomInImage(BufferedImage originalImage, int wigth, int height){
BufferedImage newImage = new BufferedImage(wigth,height,originalImage.getType());
Graphics g = newImage.getGraphics();
g.drawImage(originalImage,0,0,wigth,height,null);
g.dispose();
return newImage;
}
}
/*
* 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.util;
import cn.hutool.core.util.StrUtil;
import com.jeequan.jeepay.core.utils.SpringBeansUtil;
import com.jeequan.jeepay.pay.channel.IPaymentService;
/*
* 支付方式动态调用Utils
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:46
*/
public class PaywayUtil {
private static final String PAYWAY_PACKAGE_NAME = "payway";
private static final String PAYWAYV3_PACKAGE_NAME = "paywayV3";
/** 获取真实的支付方式Service **/
public static IPaymentService getRealPaywayService(Object obj, String wayCode){
try {
//下划线转换驼峰 & 首字母大写
String clsName = StrUtil.upperFirst(StrUtil.toCamelCase(wayCode.toLowerCase()));
return (IPaymentService) SpringBeansUtil.getBean(
Class.forName(obj.getClass().getPackage().getName()
+ "." + PAYWAY_PACKAGE_NAME
+ "." + clsName)
);
} catch (ClassNotFoundException e) {
return null;
}
}
/** 获取微信V3真实的支付方式Service **/
public static IPaymentService getRealPaywayV3Service(Object obj, String wayCode){
try {
//下划线转换驼峰 & 首字母大写
String clsName = StrUtil.upperFirst(StrUtil.toCamelCase(wayCode.toLowerCase()));
return (IPaymentService) SpringBeansUtil.getBean(
Class.forName(obj.getClass().getPackage().getName()
+ "." + PAYWAYV3_PACKAGE_NAME
+ "." + clsName)
);
} catch (ClassNotFoundException e) {
return null;
}
}
}
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/jeepay?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&useSSL=false
username: root
password: 123
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:
#activeMQ配置
activemq:
broker-url: tcp://localhost:61616 #连接地址
#日志配置参数。
# 当存在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: E:/home/jeepay/files #存储根路径 ( 无需以‘/’结尾 )
private-path: ${isys.oss-file.root-path}/private #私有化本地访问,不允许url方式公共读取 ( 一般配合root-path参数进行设置,需以‘/’ 开头, 无需以‘/’结尾 )
__
/ /___ ___ ____ ____ ___ __
__ / // _ \/ _ \/ __ \/ __ `/ / / /
/ /_/ // __/ __/ /_/ / /_/ / /_/ /
\____/ \___/\___/ .___/\__,_/\__, /
/_/ /____/
:: Jeepay :: (v1.0.0.RELEASE)
适合互联网企业使用的开源支付系统 : https://www.jeepay.vip
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="false" debug="false">
<!-- 日志存放路径, 读取application.yml 需要使用springProperty获取 -->
<springProperty scope="context" name="currentLoggerFilePath" source="logging.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="pay" />
<!-- 日志格式, 参考: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>10</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>
放置打包好的html文件。
\ No newline at end of file
<!DOCTYPE html>
<html lang="zh">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>支付完成 - 聚合支付</title>
</head>
<body>
<h1>支付成功</h1>
</body>
</html>
\ No newline at end of file
<?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">
<modelVersion>4.0.0</modelVersion> <!-- POM模型版本 -->
<groupId>com.jeequan</groupId> <!-- 组织名, 类似于包名 -->
<artifactId>jeepay-service</artifactId> <!-- 项目名称 -->
<packaging>jar</packaging> <!-- 项目的最终打包类型/发布形式, 可选[jar, war, pom, maven-plugin]等 -->
<version>${isys.version}</version> <!-- 项目当前版本号 -->
<description>Jeepay计全支付系统 [jeepay-service]</description> <!-- 项目描述 -->
<url>https://www.jeequan.com</url>
<parent>
<groupId>com.jeequan</groupId>
<artifactId>jeepay</artifactId>
<version>1.0.0</version>
</parent>
<!-- 项目依赖声明 -->
<dependencies>
<dependency>
<groupId>com.jeequan</groupId>
<artifactId>jeepay-core</artifactId>
<version>${isys.version}</version>
</dependency>
<!-- MySql 数据库连接包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- Druid 连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.6</version>
</dependency>
<!-- orm映射框架:mybatis-plus, 自动引入spring-tx -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<!-- Spring Security -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<directory>src/main/java</directory>
<includes><include>**/*.xml</include></includes><!-- maven可以将mapper.xml进行打包处理,否则仅对java文件处理 -->
</resource>
</resources>
</build>
</project>
/*
* 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.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.IsvInfo;
import com.jeequan.jeepay.core.entity.MchInfo;
import com.jeequan.jeepay.core.entity.PayInterfaceConfig;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.service.mapper.IsvInfoMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* <p>
* 服务商信息表 服务实现类
* </p>
*
* @author [mybatis plus generator]
* @since 2021-04-27
*/
@Service
public class IsvInfoService extends ServiceImpl<IsvInfoMapper, IsvInfo> {
@Autowired private MchInfoService mchInfoService;
@Autowired private IsvInfoService isvInfoService;
@Autowired private PayInterfaceConfigService payInterfaceConfigService;
@Transactional
public void removeByIsvNo(String isvNo) {
// 0.当前服务商是否存在
IsvInfo isvInfo = isvInfoService.getById(isvNo);
if (isvInfo == null) throw new BizException("该服务商不存在");
// 1.查询当前服务商下是否存在商户
int mchCount = mchInfoService.count(MchInfo.gw().eq(MchInfo::getIsvNo, isvNo).eq(MchInfo::getType, CS.INFO_TYPE_ISV));
if (mchCount > 0) throw new BizException("该服务商下存在商户,不可删除");
// 2.删除当前服务商支付接口配置参数
payInterfaceConfigService.remove(PayInterfaceConfig.gw()
.eq(PayInterfaceConfig::getInfoId, isvNo)
.eq(PayInterfaceConfig::getInfoType, CS.INFO_TYPE_ISV)
);
// 3.删除该服务商
boolean remove = isvInfoService.removeById(isvNo);
if (!remove) throw new BizException("删除服务商失败");
}
}
/*
* 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.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.*;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.service.mapper.MchInfoMapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
/**
* <p>
* 商户信息表 服务实现类
* </p>
*
* @author [mybatis plus generator]
* @since 2021-04-27
*/
@Service
public class MchInfoService extends ServiceImpl<MchInfoMapper, MchInfo> {
@Autowired private SysUserService sysUserService;
@Autowired private PayOrderService payOrderService;
@Autowired private MchPayPassageService mchPayPassageService;
@Autowired private PayInterfaceConfigService payInterfaceConfigService;
@Autowired private SysUserAuthService sysUserAuthService;
@Autowired private IsvInfoService isvInfoService;
@Transactional(rollbackFor = Exception.class)
public void addMch(MchInfo mchInfo, String loginUserName) {
// 校验特邀商户信息
if (mchInfo.getType() == CS.MCH_TYPE_ISVSUB && StringUtils.isNotEmpty(mchInfo.getIsvNo())) {
// 当前服务商状态是否正确
IsvInfo isvInfo = isvInfoService.getById(mchInfo.getIsvNo());
if (isvInfo == null || isvInfo.getState() == CS.NO) {
throw new BizException("当前服务商不可用");
}
}
// 插入商户基本信息
boolean saveResult = save(mchInfo);
if (!saveResult) throw new BizException(ApiCodeEnum.SYS_OPERATION_FAIL_CREATE);
// 插入用户信息
SysUser sysUser = new SysUser();
sysUser.setLoginUsername(loginUserName);
sysUser.setRealname(mchInfo.getContactName());
sysUser.setTelphone(mchInfo.getContactTel());
sysUser.setUserNo(mchInfo.getMchNo());
sysUser.setBelongInfoId(mchInfo.getMchNo());
sysUser.setSex(CS.SEX_MALE);
sysUser.setIsAdmin(CS.YES);
sysUser.setState(mchInfo.getState());
sysUserService.addSysUser(sysUser, CS.SYS_TYPE.MCH);
// 存入商户默认用户ID
mchInfo.setInitUserId(sysUser.getSysUserId());
updateById(mchInfo);
}
@Transactional(rollbackFor = Exception.class)
public List<Long> removeByMchNo(String mchNo) {
try {
// 0.当前商户是否存在
MchInfo mchInfo = getById(mchNo);
if (mchInfo == null) throw new BizException("该商户不存在");
// 1.查看当前商户是否存在交易数据
int payCount = payOrderService.count(PayOrder.gw().eq(PayOrder::getMchNo, mchNo));
if (payCount > 0) throw new BizException("该商户已存在交易数据,不可删除");
// 2.删除当前商户配置的支付通道
mchPayPassageService.remove(MchPayPassage.gw().eq(MchPayPassage::getMchNo, mchNo));
// 3.删除当前商户支付接口配置参数
payInterfaceConfigService.remove(PayInterfaceConfig.gw()
.eq(PayInterfaceConfig::getInfoId, mchNo)
.eq(PayInterfaceConfig::getInfoType, CS.INFO_TYPE_MCH)
);
List<SysUser> userList = sysUserService.list(SysUser.gw()
.eq(SysUser::getBelongInfoId, mchNo)
.eq(SysUser::getSystem, CS.SYS_TYPE.MCH)
);
// 返回的用户id
List<Long> userIdList = new ArrayList<>();
if (userList.size() > 0) {
for (SysUser user:userList) {
userIdList.add(user.getSysUserId());
}
// 4.删除当前商户用户子用户信息
sysUserAuthService.remove(SysUserAuth.gw().in(SysUserAuth::getUserId, userIdList));
}
// 5.删除当前商户的登录用户
sysUserService.remove(SysUser.gw()
.eq(SysUser::getBelongInfoId, mchNo)
.eq(SysUser::getSystem, CS.SYS_TYPE.MCH)
);
// 6.删除当前商户
boolean removeMchInfo = removeById(mchNo);
if (!removeMchInfo) throw new BizException("删除当前商户失败");
return userIdList;
}catch (Exception e) {
throw new BizException(e.getMessage());
}
}
}
/*
* 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.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jeequan.jeepay.core.entity.MchNotifyRecord;
import com.jeequan.jeepay.service.mapper.MchNotifyRecordMapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Service;
/**
* <p>
* 商户通知表 服务实现类
* </p>
*
* @author [mybatis plus generator]
* @since 2021-04-27
*/
@Service
public class MchNotifyRecordService extends ServiceImpl<MchNotifyRecordMapper, MchNotifyRecord> {
/** 根据订单号和类型查询 */
public MchNotifyRecord findByOrderAndType(String orderId, Byte orderType){
return getOne(
MchNotifyRecord.gw().eq(MchNotifyRecord::getOrderId, orderId).eq(MchNotifyRecord::getOrderType, orderType)
);
}
/** 查询支付订单 */
public MchNotifyRecord findByPayOrder(String orderId){
return findByOrderAndType(orderId, MchNotifyRecord.TYPE_PAY_ORDER);
}
/** 查询退款订单订单 */
public MchNotifyRecord findByRefundOrder(String orderId){
return findByOrderAndType(orderId, MchNotifyRecord.TYPE_REFUND_ORDER);
}
public Integer updateNotifyResult(Long notifyId, Byte state, String resResult){
return baseMapper.updateNotifyResult(notifyId, state, resResult);
}
}
/*
* 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.service.impl;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.MchPayPassage;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.service.mapper.MchPayPassageMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* <p>
* 商户支付通道表 服务实现类
* </p>
*
* @author [mybatis plus generator]
* @since 2021-04-27
*/
@Service
public class MchPayPassageService extends ServiceImpl<MchPayPassageMapper, MchPayPassage> {
/**
* @Author: ZhuXiao
* @Description: 根据支付方式查询可用的支付接口列表
* @Date: 9:56 2021/5/10
*/
public List<JSONObject> selectAvailablePayInterfaceList(String wayCode, String mchNo, Byte infoType, Byte mchType) {
Map params = new HashMap();
params.put("wayCode", wayCode);
params.put("mchNo", mchNo);
params.put("infoType", infoType);
params.put("mchType", mchType);
List<JSONObject> list = baseMapper.selectAvailablePayInterfaceList(params);
if (CollectionUtils.isEmpty(list)) return null;
// 添加通道状态
for (JSONObject object : list) {
MchPayPassage payPassage = baseMapper.selectOne(MchPayPassage.gw()
.eq(MchPayPassage::getMchNo, mchNo)
.eq(MchPayPassage::getWayCode, wayCode)
.eq(MchPayPassage::getIfCode, object.getString("ifCode"))
);
if (payPassage != null) {
object.put("passageId", payPassage.getId());
if (payPassage.getRate() != null) {
object.put("rate", payPassage.getRate().multiply(new BigDecimal("100")));
}
object.put("state", payPassage.getState());
}
if(object.getBigDecimal("ifRate") != null) {
object.put("ifRate", object.getBigDecimal("ifRate").multiply(new BigDecimal("100")));
}
}
return list;
}
@Transactional(rollbackFor = Exception.class)
public void saveOrUpdateBatchSelf(List<MchPayPassage> mchPayPassageList) {
saveOrUpdateBatchSelf(mchPayPassageList, null);
}
@Transactional(rollbackFor = Exception.class)
public void saveOrUpdateBatchSelf(List<MchPayPassage> mchPayPassageList, String mchNo) {
if (CollectionUtils.isEmpty(mchPayPassageList)) {
throw new BizException("操作失败");
}
for (MchPayPassage payPassage : mchPayPassageList) {
if (payPassage.getState() == CS.NO && payPassage.getId() == null) {
continue;
}
if (StrUtil.isNotBlank(mchNo)) { // 商户系统配置通道,添加商户号参数
payPassage.setMchNo(mchNo);
}
if (payPassage.getRate() != null) {
payPassage.setRate(payPassage.getRate().divide(new BigDecimal("100"), 6, BigDecimal.ROUND_HALF_UP));
}
if (!saveOrUpdate(payPassage)) {
throw new BizException("操作失败");
}
}
}
/** 根据商户号 和 支付方式, 查询出商户可用的支付接口 **/
public MchPayPassage findMchPayPassage(String mchNo, String wayCode){
List<MchPayPassage> list = list(MchPayPassage.gw()
.eq(MchPayPassage::getMchNo, mchNo)
.eq(MchPayPassage::getState, CS.YES)
.eq(MchPayPassage::getWayCode, wayCode)
);
return list.isEmpty() ? null : list.get(0);
}
}
/*
* 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.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.MchInfo;
import com.jeequan.jeepay.core.entity.PayInterfaceConfig;
import com.jeequan.jeepay.core.entity.PayInterfaceDefine;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.service.mapper.PayInterfaceConfigMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* <p>
* 支付接口配置参数表 服务实现类
* </p>
*
* @author [mybatis plus generator]
* @since 2021-04-27
*/
@Service
public class PayInterfaceConfigService extends ServiceImpl<PayInterfaceConfigMapper, PayInterfaceConfig> {
@Autowired
private PayInterfaceDefineService payInterfaceDefineService;
@Autowired
private MchInfoService mchInfoService;
/**
* @Author: ZhuXiao
* @Description: 根据 账户类型、账户号、接口类型 获取支付参数配置
* @Date: 17:20 2021/4/27
*/
public PayInterfaceConfig getByInfoIdAndIfCode(Byte infoType, String infoId, String ifCode) {
return getOne(PayInterfaceConfig.gw()
.eq(PayInterfaceConfig::getInfoType, infoType)
.eq(PayInterfaceConfig::getInfoId, infoId)
.eq(PayInterfaceConfig::getIfCode, ifCode)
);
}
/**
* @Author: ZhuXiao
* @Description: 根据 账户类型、账户号 获取支付参数配置列表
* @Date: 14:19 2021/5/7
*/
public List<PayInterfaceDefine> selectAllPayIfConfigListByInfoId(Byte infoType, String infoId) {
// 支付定义列表
LambdaQueryWrapper<PayInterfaceDefine> queryWrapper = PayInterfaceDefine.gw();
queryWrapper.eq(PayInterfaceDefine::getState, CS.YES);
// 根据商户类型,添加接口是否支持该商户类型条件
MchInfo mchInfo = null;
Map<String, PayInterfaceConfig> isvPayConfigMap = new HashMap<>(); // 服务商支付参数配置集合
if (infoType == CS.INFO_TYPE_MCH) {
//商户信息
mchInfo = mchInfoService.getById(infoId);
if (mchInfo == null || mchInfo.getState() != CS.YES) throw new BizException(ApiCodeEnum.SYS_OPERATION_FAIL_SELETE);
if (mchInfo.getType() == CS.MCH_TYPE_NORMAL) {
queryWrapper.eq(PayInterfaceDefine::getIsMchMode, CS.YES); // 支持普通商户模式
}
if (mchInfo.getType() == CS.MCH_TYPE_ISVSUB) {
queryWrapper.eq(PayInterfaceDefine::getIsIsvMode, CS.YES); // 支持服务商模式
// 商户类型为特约商户,服务商应已经配置支付参数
List<PayInterfaceConfig> isvConfigList = this.list(PayInterfaceConfig.gw()
.eq(PayInterfaceConfig::getInfoId, mchInfo.getIsvNo())
.eq(PayInterfaceConfig::getInfoType, CS.INFO_TYPE_ISV)
.eq(PayInterfaceConfig::getState, CS.YES)
.ne(PayInterfaceConfig::getIfParams, " ")
.isNotNull(PayInterfaceConfig::getIfParams));
for (PayInterfaceConfig config : isvConfigList) {
isvPayConfigMap.put(config.getIfCode(), config);
}
}
}
if (infoType == CS.INFO_TYPE_ISV) {
queryWrapper.eq(PayInterfaceDefine::getIsIsvMode, CS.YES); // 支持服务商模式
}
List<PayInterfaceDefine> defineList = payInterfaceDefineService.list(queryWrapper);
// 支付参数列表
LambdaQueryWrapper<PayInterfaceConfig> wrapper = PayInterfaceConfig.gw();
wrapper.eq(PayInterfaceConfig::getInfoId, infoId);
wrapper.eq(PayInterfaceConfig::getInfoType, infoType);
List<PayInterfaceConfig> configList = this.list(wrapper);
for (PayInterfaceDefine define : defineList) {
for (PayInterfaceConfig config : configList) {
if (define.getIfCode().equals(config.getIfCode())) {
define.addExt("ifConfigState", config.getState()); // 配置状态
}
}
if (infoType == CS.INFO_TYPE_MCH && mchInfo.getType() == CS.MCH_TYPE_ISVSUB && isvPayConfigMap.get(define.getIfCode()) == null) {
define.addExt("subMchIsvConfig", CS.NO); // 特约商户,服务商支付参数的配置状态,0表示未配置
}
}
return defineList;
}
}
/*
* 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.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jeequan.jeepay.core.entity.PayInterfaceDefine;
import com.jeequan.jeepay.service.mapper.PayInterfaceDefineMapper;
import org.springframework.stereotype.Service;
/**
* <p>
* 支付接口定义表 服务实现类
* </p>
*
* @author [mybatis plus generator]
* @since 2021-04-27
*/
@Service
public class PayInterfaceDefineService extends ServiceImpl<PayInterfaceDefineMapper, PayInterfaceDefine> {
}
/*
* 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.service.impl;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.IsvInfo;
import com.jeequan.jeepay.core.entity.MchInfo;
import com.jeequan.jeepay.core.entity.PayOrder;
import com.jeequan.jeepay.core.entity.PayWay;
import com.jeequan.jeepay.service.mapper.IsvInfoMapper;
import com.jeequan.jeepay.service.mapper.MchInfoMapper;
import com.jeequan.jeepay.service.mapper.PayOrderMapper;
import com.jeequan.jeepay.service.mapper.PayWayMapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.*;
/**
* <p>
* 支付订单表 服务实现类
* </p>
*
* @author [mybatis plus generator]
* @since 2021-04-27
*/
@Service
public class PayOrderService extends ServiceImpl<PayOrderMapper, PayOrder> {
@Autowired private PayOrderMapper payOrderMapper;
@Autowired private MchInfoMapper mchInfoMapper;
@Autowired private IsvInfoMapper isvInfoMapper;
@Autowired private PayWayMapper payWayMapper;
/** 更新订单状态 【订单生成】 --》 【支付中】 **/
public boolean updateInit2Ing(String payOrderId, String ifCode, String wayCode){
PayOrder updateRecord = new PayOrder();
updateRecord.setState(PayOrder.STATE_ING);
updateRecord.setIfCode(ifCode);
updateRecord.setWayCode(wayCode);
return update(updateRecord, new LambdaUpdateWrapper<PayOrder>()
.eq(PayOrder::getPayOrderId, payOrderId).eq(PayOrder::getState, PayOrder.STATE_INIT));
}
/** 更新订单状态 【支付中】 --》 【支付成功】 **/
public boolean updateIng2Success(String payOrderId, String channelOrderNo){
return updateIng2Success(payOrderId, channelOrderNo, null);
}
/** 更新订单状态 【支付中】 --》 【支付成功】 **/
public boolean updateIng2Success(String payOrderId, String channelOrderNo, String channelUserId){
PayOrder updateRecord = new PayOrder();
updateRecord.setState(PayOrder.STATE_SUCCESS);
updateRecord.setChannelOrderNo(channelOrderNo);
updateRecord.setChannelUser(channelUserId);
updateRecord.setSuccessTime(new Date());
return update(updateRecord, new LambdaUpdateWrapper<PayOrder>()
.eq(PayOrder::getPayOrderId, payOrderId).eq(PayOrder::getState, PayOrder.STATE_ING));
}
/** 更新订单状态 【支付中】 --》 【支付失败】 **/
public boolean updateIng2Fail(String payOrderId, String channelOrderNo, String channelErrCode, String channelErrMsg){
PayOrder updateRecord = new PayOrder();
updateRecord.setState(PayOrder.STATE_FAIL);
updateRecord.setErrCode(channelErrCode);
updateRecord.setErrMsg(channelErrMsg);
updateRecord.setChannelOrderNo(channelOrderNo);
return update(updateRecord, new LambdaUpdateWrapper<PayOrder>()
.eq(PayOrder::getPayOrderId, payOrderId).eq(PayOrder::getState, PayOrder.STATE_ING));
}
/** 更新订单状态 【支付中】 --》 【支付成功/支付失败】 **/
public boolean updateIng2SuccessOrFail(String payOrderId, Byte updateState, String channelOrderNo, String channelErrCode, String channelErrMsg){
if(updateState == PayOrder.STATE_ING){
return true;
}else if(updateState == PayOrder.STATE_SUCCESS){
return updateIng2Success(payOrderId, channelOrderNo);
}else if(updateState == PayOrder.STATE_FAIL){
return updateIng2Fail(payOrderId, channelOrderNo, channelErrCode, channelErrMsg);
}
return false;
}
/** 查询商户订单 **/
public PayOrder queryMchOrder(String mchNo, String payOrderId, String mchOrderNo){
if(StringUtils.isNotEmpty(payOrderId)){
return getOne(PayOrder.gw().eq(PayOrder::getMchNo, mchNo).eq(PayOrder::getPayOrderId, payOrderId));
}else if(StringUtils.isNotEmpty(mchOrderNo)){
return getOne(PayOrder.gw().eq(PayOrder::getMchNo, mchNo).eq(PayOrder::getMchOrderNo, mchOrderNo));
}else{
return null;
}
}
public Map payCount(String mchNo, Byte state, String dayStart, String dayEnd) {
Map param = new HashMap<>();
if (state != null) param.put("state", state);
if (StrUtil.isNotBlank(mchNo)) param.put("mchNo", mchNo);
if (StrUtil.isNotBlank(dayStart)) param.put("createTimeStart", dayStart);
if (StrUtil.isNotBlank(dayEnd)) param.put("createTimeEnd", dayEnd);
return payOrderMapper.payCount(param);
}
public List<Map> payTypeCount(String mchNo, Byte state, String dayStart, String dayEnd) {
Map param = new HashMap<>();
if (state != null) param.put("state", state);
if (StrUtil.isNotBlank(mchNo)) param.put("mchNo", mchNo);
if (StrUtil.isNotBlank(dayStart)) param.put("createTimeStart", dayStart);
if (StrUtil.isNotBlank(dayEnd)) param.put("createTimeEnd", dayEnd);
return payOrderMapper.payTypeCount(param);
}
public Map selectTotalCount(String mchNo, Byte state, String dayStart, String dayEnd) {
Map param = new HashMap<>();
if (state != null) param.put("state", state);
if (StrUtil.isNotBlank(mchNo)) param.put("mchNo", mchNo);
if (StrUtil.isNotBlank(dayStart)) param.put("createTimeStart", dayStart);
if (StrUtil.isNotBlank(dayEnd)) param.put("createTimeEnd", dayEnd);
return payOrderMapper.selectTotalCount(param);
}
/** 更新订单为 超时状态 **/
public Integer updateOrderExpired(){
PayOrder payOrder = new PayOrder();
payOrder.setState(PayOrder.STATE_CLOSED);
return baseMapper.update(payOrder,
PayOrder.gw()
.in(PayOrder::getState, Arrays.asList(PayOrder.STATE_INIT, PayOrder.STATE_ING))
.le(PayOrder::getExpiredTime, new Date())
);
}
/** 更新订单 通知状态 --> 已发送 **/
public int updateNotifySent(String payOrderId){
PayOrder payOrder = new PayOrder();
payOrder.setNotifyState(CS.YES);
payOrder.setPayOrderId(payOrderId);
return baseMapper.updateById(payOrder);
}
/** 首页支付周统计 **/
public JSONObject mainPageWeekCount(String mchNo) {
JSONObject json = new JSONObject();
Map dayAmount = new LinkedHashMap();
ArrayList array = new ArrayList<>();
BigDecimal payAmount = new BigDecimal(0); // 当日金额
BigDecimal payWeek = payAmount; // 周总收益
String todayAmount = "0.00"; // 今日金额
String todayPayCount = "0"; // 今日交易笔数
String yesterdayAmount = "0.00"; // 昨日金额
Date today = new Date();
for(int i = 0 ; i < 7 ; i++){
Date date = DateUtil.offsetDay(today, -i).toJdkDate();
String dayStart = DateUtil.beginOfDay(date).toString(DatePattern.NORM_DATETIME_MINUTE_PATTERN);
String dayEnd = DateUtil.endOfDay(date).toString(DatePattern.NORM_DATETIME_MINUTE_PATTERN);
// 每日交易金额查询
dayAmount = payCount(mchNo, PayOrder.STATE_SUCCESS, dayStart, dayEnd);
if (dayAmount != null) payAmount = new BigDecimal(dayAmount.get("payAmount").toString());
if (i == 0) {
todayAmount = dayAmount.get("payAmount").toString();
todayPayCount = dayAmount.get("payCount").toString();
}
if (i == 1) yesterdayAmount = dayAmount.get("payAmount").toString();
payWeek = payWeek.add(payAmount);
array.add(payAmount);
}
// 倒序排列
Collections.reverse(array);
json.put("dataArray", array);
json.put("todayAmount", todayAmount);
json.put("todayPayCount", todayPayCount);
json.put("payWeek", payWeek);
json.put("yesterdayAmount", yesterdayAmount);
return json;
}
/** 首页统计总数量 **/
public JSONObject mainPageNumCount(String mchNo) {
JSONObject json = new JSONObject();
// 商户总数
int mchCount = mchInfoMapper.selectCount(MchInfo.gw());
// 服务商总数
int isvCount = isvInfoMapper.selectCount(IsvInfo.gw());
// 总交易金额
Map<String, String> payCountMap = payCount(mchNo, PayOrder.STATE_SUCCESS, null, null);
json.put("totalMch", mchCount);
json.put("totalIsv", isvCount);
json.put("totalAmount", payCountMap.get("payAmount"));
json.put("totalCount", payCountMap.get("payCount"));
return json;
}
/** 首页支付统计 **/
public List<Map> mainPagePayCount(String mchNo, String createdStart, String createdEnd) {
Map param = new HashMap<>(); // 条件参数
int daySpace = 6; // 默认最近七天(含当天)
if (StringUtils.isNotEmpty(createdStart) && StringUtils.isNotEmpty(createdEnd)) {
createdStart = createdStart + " 00:00:00";
createdEnd = createdEnd + " 23:59:59";
// 计算两时间间隔天数
daySpace = Math.toIntExact(DateUtil.betweenDay(DateUtil.parseDate(createdStart), DateUtil.parseDate(createdEnd), true));
} else {
Date today = new Date();
createdStart = DateUtil.formatDate(DateUtil.offsetDay(today, -daySpace)) + " 00:00:00";
createdEnd = DateUtil.formatDate(today) + " 23:59:59";
}
if (StrUtil.isNotBlank(mchNo)) param.put("mchNo", mchNo);
param.put("createTimeStart", createdStart);
param.put("createTimeEnd", createdEnd);
// 查询收款的记录
param.put("state", PayOrder.STATE_SUCCESS);
List<Map> payOrderList = payOrderMapper.selectOrderCount(param);
// 查询退款的记录
param.put("state", PayOrder.STATE_REFUND);
List<Map> refundOrderList = payOrderMapper.selectOrderCount(param);
// 生成前端返回参数类型
List<Map> returnList = getReturnList(daySpace, createdEnd, payOrderList, refundOrderList);
return returnList;
}
/** 首页支付类型统计 **/
public ArrayList mainPagePayTypeCount(String mchNo, String createdStart, String createdEnd) {
// 返回数据列
ArrayList array = new ArrayList<>();
if (StringUtils.isNotEmpty(createdStart) && StringUtils.isNotEmpty(createdEnd)) {
createdStart = createdStart + " 00:00:00";
createdEnd = createdEnd + " 23:59:59";
}else {
Date endDay = new Date(); // 当前日期
Date startDay = DateUtil.lastWeek().toJdkDate(); // 一周前日期
String end = DateUtil.formatDate(endDay);
String start = DateUtil.formatDate(startDay);
createdStart = start + " 00:00:00";
createdEnd = end + " 23:59:59";
}
// 统计列表
List<Map> payCountMap = payTypeCount(mchNo, PayOrder.STATE_SUCCESS, createdStart, createdEnd);
// 得到所有支付方式
Map<String, String> payWayNameMap = new HashMap<>();
List<PayWay> payWayList = payWayMapper.selectList(PayWay.gw());
for (PayWay payWay:payWayList) {
payWayNameMap.put(payWay.getWayCode(), payWay.getWayName());
}
// 支付方式名称标注
for (Map payCount:payCountMap) {
if (StringUtils.isNotEmpty(payWayNameMap.get(payCount.get("wayCode")))) {
payCount.put("typeName", payWayNameMap.get(payCount.get("wayCode")));
}else {
payCount.put("typeName", payCount.get("wayCode"));
}
}
array.add(payCountMap);
return array;
}
/** 生成首页交易统计数据类型 **/
public List<Map> getReturnList(int daySpace, String createdStart, List<Map> payOrderList, List<Map> refundOrderList) {
List<Map> dayList = new ArrayList<>();
DateTime endDay = DateUtil.parseDateTime(createdStart);
// 先判断间隔天数 根据天数设置空的list
for (int i = 0; i <= daySpace ; i++) {
Map<String, String> map = new HashMap<>();
map.put("date", DateUtil.format(DateUtil.offsetDay(endDay, -i), "MM-dd"));
dayList.add(map);
}
// 日期倒序排列
Collections.reverse(dayList);
List<Map> payListMap = new ArrayList<>(); // 收款的列
List<Map> refundListMap = new ArrayList<>(); // 退款的列
for (Map dayMap:dayList) {
// 为收款列和退款列赋值默认参数【payAmount字段切记不可为string,否则前端图表解析不出来】
Map<String, Object> payMap = new HashMap<>();
payMap.put("date", dayMap.get("date").toString());
payMap.put("type", "收款");
payMap.put("payAmount", 0);
Map<String, Object> refundMap = new HashMap<>();
refundMap.put("date", dayMap.get("date").toString());
refundMap.put("type", "退款");
refundMap.put("payAmount", 0);
for (Map payOrderMap:payOrderList) {
if (dayMap.get("date").equals(payOrderMap.get("groupDate"))) {
payMap.put("payAmount", payOrderMap.get("payAmount"));
}
}
payListMap.add(payMap);
for (Map refundOrderMap:refundOrderList) {
if (dayMap.get("date").equals(refundOrderMap.get("groupDate"))) {
refundMap.put("payAmount", refundOrderMap.get("payAmount"));
}
}
refundListMap.add(refundMap);
}
payListMap.addAll(refundListMap);
return payListMap;
}
}
/*
* 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.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jeequan.jeepay.core.entity.PayWay;
import com.jeequan.jeepay.service.mapper.PayWayMapper;
import org.springframework.stereotype.Service;
/**
* <p>
* 支付方式表 服务实现类
* </p>
*
* @author [mybatis plus generator]
* @since 2021-04-27
*/
@Service
public class PayWayService extends ServiceImpl<PayWayMapper, PayWay> {
}
/*
* 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.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jeequan.jeepay.core.entity.RefundOrder;
import com.jeequan.jeepay.service.mapper.RefundOrderMapper;
import org.springframework.stereotype.Service;
/**
* <p>
* 退款订单表 服务实现类
* </p>
*
* @author [mybatis plus generator]
* @since 2021-04-27
*/
@Service
public class RefundOrderService extends ServiceImpl<RefundOrderMapper, RefundOrder> {
}
/*
* 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.service.impl;
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.service.mapper.SysConfigMapper;
import org.apache.commons.lang3.tuple.MutablePair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Map;
import java.util.Set;
/**
* <p>
* 系统配置表 服务实现类
* </p>
*
* @author [mybatis plus generator]
* @since 2020-07-29
*/
@Service
public class SysConfigService extends ServiceImpl<SysConfigMapper, SysConfig> {
@Autowired
private SysConfigService sysConfigService;
/** 数据库application配置参数 **/
private static MutablePair<String, DBApplicationConfig> APPLICATION_CONFIG = new MutablePair<>("applicationConfig", null);
public synchronized void initDBConfig(String groupKey) {
if(APPLICATION_CONFIG.getLeft().equalsIgnoreCase(groupKey)){
APPLICATION_CONFIG.right = this.selectByGroupKey(groupKey).toJavaObject(DBApplicationConfig.class);
}
}
/** 获取实际的数据 **/
public DBApplicationConfig getDBApplicationConfig() {
if(APPLICATION_CONFIG.getRight() == null ){
initDBConfig(APPLICATION_CONFIG.getLeft());
}
return APPLICATION_CONFIG.right;
}
/** 根据分组查询,并返回JSON对象格式的数据 **/
public JSONObject selectByGroupKey(String groupKey){
JSONObject result = new JSONObject();
list(SysConfig.gw().select(SysConfig::getConfigKey, SysConfig::getConfigVal).eq(SysConfig::getGroupKey, groupKey))
.stream().forEach(item -> result.put(item.getConfigKey(), item.getConfigVal()));
return result;
}
public int updateByConfigKey(Map<String, String> updateMap) {
int count = 0;
Set<String> set = updateMap.keySet();
for(String k : set) {
SysConfig sysConfig = new SysConfig();
sysConfig.setConfigKey(k);
sysConfig.setConfigVal(updateMap.get(k));
boolean update = sysConfigService.saveOrUpdate(sysConfig);
if (update) count ++;
}
return count;
}
}
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