Commit de3de82d authored by dingzhiwei's avatar dingzhiwei
Browse files

初始化Jeepay项目

parent 40dcaf4a
MIT License GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (c) 2017 https://github.com/jmdhappy/xxpay-master
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Permission is hereby granted, free of charge, to any person obtaining a copy Everyone is permitted to copy and distribute verbatim copies
of this software and associated documentation files (the "Software"), to deal of this license document, but changing it is not allowed.
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is This version of the GNU Lesser General Public License incorporates
furnished to do so, subject to the following conditions: the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software. 0. Additional Definitions.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR As used herein, "this License" refers to version 3 of the GNU Lesser
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, General Public License, and the "GNU GPL" refers to version 3 of the GNU
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE General Public License.
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, "The Library" refers to a covered work governed by this License,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE other than an Application or a Combined Work as defined below.
SOFTWARE.
\ No newline at end of file An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
\ No newline at end of file
### 郑重声明 <p align="center">
<a href="https://www.jeepay.vip"><img src="https://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/jeepay_logo.svg"></a>
</p>
<p align="center">
<strong>适合互联网企业使用的开源支付系统</strong>
</p>
<p align="center">
👉 <a href="https://www.jeepay.vip">https://www.jeepay.vip</a> 👈
</p>
<p align="center">
<a target="_blank" href="https://spring.io/projects/spring-boot">
<img src="https://img.shields.io/badge/spring%20boot-2.4.5-yellowgreen" />
</a>
<a target="_blank" href="https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html">
<img src="https://img.shields.io/badge/JDK-8+-green.svg" />
</a>
<a target="_blank" href="http://www.gnu.org/licenses/lgpl.html">
<img src="https://img.shields.io/badge/license-LGPL--3.0-blue" />
</a>
<a href='https://gitee.com/jeequan/jeepay/stargazers' target="_blank">
<img src='https://gitee.com/jeequan/jeepay/badge/star.svg?theme=gvp' alt='star'></img>
</a>
<a target="_blank" href='https://github.com/jeequan/jeepay'>
<img src="https://img.shields.io/github/stars/jeequan/jeepay.svg?style=social" alt="github star"/>
</a>
</p>
<br/>
<p align="center">
<a href="https://jq.qq.com/?_wv=1027&k=94WnXmdL">
<img src="https://img.shields.io/badge/qq%E7%BE%A4%E2%91%A0-635647058-critical"/>
</a>
</p>
-------------------------------------------------------------------------------
## 📚 项目介绍
Jeepay是一套适合互联网企业使用的开源支付系统,支持多渠道服务商和普通商户模式。已对接`微信支付``支付宝``云闪付`官方接口,支持聚合码支付。
Jeepay使用`Spring Boot``Ant Design Vue`开发,集成`Spring Security`实现权限管理功能,是一套非常实用的web开发框架。
### 🎁 名称的由来
Jeepay = Jee + pay,是由原XxPay支付系统作者带领团队开发,“Jee”是公司计全科技名称的表示,pay表示支付。中文名称为计全支付,释为:计出万全、支付安全,让支付更加方便安全。
### 🍟 项目体验
- Jeepay支付流程体验:[https://www.jeequan.com/demo/jeepay_cashier.html](https://www.jeequan.com/demo/jeepay_cashier.html "Jeepay支付体验")
- Jeepay运营平台和商户系统演体验:[https://www.jeequan.com/doc/detail_84.html](https://www.jeequan.com/doc/detail_84.html "Jeepay支付系统体验")
- Jeepay项目文档:[https://www.jeepay.vip](https://www.jeepay.vip "Jeepay项目文档")
### 🍎 项目特点
* 支持多渠道对接,支付网关自动路由
* 已对接`微信`服务商和普通商户接口,支持`V2``V3`接口
* 已对接`支付宝`服务商和普通商户接口,支持RSA和RSA2签名
* 已对接`云闪付`服务商接口,可选择多家支付机构
* 提供http形式接口,提供各语言的`sdk`实现,方便对接
* 接口请求和响应数据采用签名机制,保证交易安全可靠
* 系统安全,支持`分布式`部署,`高并发`
* 管理端包括`运营平台``商户系统`
* 管理平台操作界面简洁、易用
* 支付平台到商户系统的订单通知使用MQ实现,保证了高可用,消息可达
* 支付渠道的接口参数配置界面自动化生成
* 使用`spring security`实现权限管理
* 前后端分离架构,方便二次开发
* 由原`XxPay`团队开发,有着多年支付系统开发经验
## 🥞 系统架构
> Jeepay计全支付系统架构图
![Jeepay系统架构图](https://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/jeepay_framework.png "Jeepay系统架构图") ![Jeepay系统架构图](https://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/jeepay_framework.png "Jeepay系统架构图")
> 原`XxPay聚合支付`项目已更名为Jeepay,由原XxPay团队开发维护。目前`Jeepay`开发已经进入收尾阶段,最晚6月初会发布源码到Github和码云上。 > 核心技术栈
> 新版Jeepay支付系统,使用SpringBoot + Ant Vue开发,适合互联网企业搭建内部支付系统。支持普通商户和服务商模式,已对接微信、支付宝、云闪付官方通道。统一的下单接口,实现主扫/被扫(聚合)。 | 软件名称 | 描述 | 版本
|---|---|---
> 请关注官方网站[www.jeequan.com](https://www.jeequan.com "计全科技官网")或官方公众号(微信搜索:计全科技),获取Jeepay最新发布消息,如果您喜欢该项目,不妨随手Star下。 |Jdk | Java环境 | 1.8
|Spring Boot | 开发框架 | 2.4.5
> 待发布源码时,会更公布官方qq或微信技术交流群,同时会发布使用文档及演示地址。 |Redis | 分布式缓存 | 3.2.8 或 高版本
|MySQL | 数据库 | 5.7.X
### 功能列表 |ActiveMQ | 消息中间件 | 5.15.8 或 高版本
|[Ant Design Vue](https://www.antdv.com/docs/vue/introduce-cn/) | Ant Design的Vue实现,前端开发使用 | 2.1.2
|[MyBatis-Plus](https://mp.baomidou.com/) | MyBatis增强工具 | 3.4.2
|[WxJava](https://gitee.com/binary/weixin-java-tools) | 微新开发Java SDK | 4.0.0
|[Hutool](https://www.hutool.cn/) | Java工具类库 | 5.6.6
> 项目结构
```lua
jeepay-ui -- https://gitee.com/jeequan/jeepay-ui
jeepay
├── conf -- 存放系统部署使用的.yml文件
└── docs -- 存放项目相关文档说明
├── script -- 项目启动shell脚本
└── sql -- 初始化sql文件
├── jeepay-core -- 核心依赖包
├── jeepay-manager -- 运营平台服务端[9217]
├── jeepay-merchant -- 商户系统服务端[9218]
├── jeepay-payment -- 支付网关[9216]
├── jeepay-service -- 业务层代码
└── jeepay-z-codegen -- mybatis代码生成
```
> 开发部署
- 系统开发:[https://www.jeepay.vip/#/develop/dev_serv](https://www.jeepay.vip/#/develop/dev_serv)
- 通道对接:[https://www.jeepay.vip/#/develop/dev_channel](https://www.jeepay.vip/#/develop/dev_channel)
- 线上部署:[https://www.jeepay.vip/#/develop/deploy](https://www.jeepay.vip/#/develop/deploy)
- 接口文档:[https://www.jeepay.vip/#/interface/payment_api](https://www.jeepay.vip/#/interface/payment_api)
## 🍿 功能模块
> Jeepay运营平台功能 > Jeepay运营平台功能
...@@ -20,7 +124,7 @@ ...@@ -20,7 +124,7 @@
![Jeepay商户系统功能](https://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/jeepay_mch.png "Jeepay商户系统功能") ![Jeepay商户系统功能](https://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/jeepay_mch.png "Jeepay商户系统功能")
### 功能预览 ## 🍯 系统截图
`以下截图是从实际已完成功能界面截取,截图时间为:2021-05-29 02:05` `以下截图是从实际已完成功能界面截取,截图时间为:2021-05-29 02:05`
...@@ -28,18 +132,10 @@ ...@@ -28,18 +132,10 @@
![Jeepay演示界面](http://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/yanshi/002.png "Jeepay演示界面") ![Jeepay演示界面](http://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/yanshi/002.png "Jeepay演示界面")
![Jeepay演示界面](http://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/yanshi/003.png "Jeepay演示界面")
![Jeepay演示界面](http://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/yanshi/004.png "Jeepay演示界面")
![Jeepay演示界面](http://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/yanshi/005.png "Jeepay演示界面") ![Jeepay演示界面](http://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/yanshi/005.png "Jeepay演示界面")
![Jeepay演示界面](http://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/yanshi/006.png "Jeepay演示界面") ![Jeepay演示界面](http://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/yanshi/006.png "Jeepay演示界面")
![Jeepay演示界面](http://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/yanshi/007.png "Jeepay演示界面")
![Jeepay演示界面](http://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/yanshi/008.png "Jeepay演示界面")
![Jeepay演示界面](http://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/yanshi/009.png "Jeepay演示界面") ![Jeepay演示界面](http://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/yanshi/009.png "Jeepay演示界面")
![Jeepay演示界面](http://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/yanshi/010.png "Jeepay演示界面") ![Jeepay演示界面](http://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/yanshi/010.png "Jeepay演示界面")
...@@ -54,21 +150,9 @@ ...@@ -54,21 +150,9 @@
![Jeepay演示界面](http://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/yanshi/015.png "Jeepay演示界面") ![Jeepay演示界面](http://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/yanshi/015.png "Jeepay演示界面")
![Jeepay演示界面](http://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/yanshi/016.png "Jeepay演示界面")
![Jeepay演示界面](http://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/yanshi/017.png "Jeepay演示界面")
![Jeepay演示界面](http://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/yanshi/018.png "Jeepay演示界面")
![Jeepay演示界面](http://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/yanshi/019.png "Jeepay演示界面")
![Jeepay演示界面](http://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/yanshi/020.png "Jeepay演示界面")
![Jeepay演示界面](http://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/yanshi/021.png "Jeepay演示界面")
![Jeepay演示界面](http://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/yanshi/022.png "Jeepay演示界面") ![Jeepay演示界面](http://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/yanshi/022.png "Jeepay演示界面")
### 关于我们 ## 🥪 关于我们
*** ***
微信扫描下面二维码,关注官方公众号:计全科技,获取更多精彩内容。 微信扫描下面二维码,关注官方公众号:计全科技,获取更多精彩内容。
......
#################################
# 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文件只配置与环境相关的参数, 其他配置读取项目下的配置项
#
#################################
server:
port: 9217 #设置端口为 9217
spring:
datasource:
# yml填写url连接串, 无需将&符号进行转义
url: jdbc:mysql://127.0.0.1:3306/jeepaydb?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&useSSL=false
username: jeepay
password: 123456
redis:
host: 127.0.0.1
port: 6379
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: ./logs #日志存放地址
#系统业务参数
isys:
allow-cors: false #是否允许跨域请求 [生产环境建议关闭, 若api与前端项目没有在同一个域名下时,应开启此配置或在nginx统一配置允许跨域]
jwt-secret: t7w3P8X6472qWc3u #生成jwt的秘钥。 要求每个系统有单独的秘钥管理机制。
# 文件系统配置项(系统内oss, 并非云oss)
oss-file:
root-path: /home/jeepay/upload #存储根路径 ( 无需以‘/’结尾 )
#################################
# 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文件只配置与环境相关的参数, 其他配置读取项目下的配置项
#
#################################
server:
port: 9218 # 设置端口为 9218
spring:
datasource:
# yml填写url连接串, 无需将&符号进行转义
url: jdbc:mysql://127.0.0.1:3306/jeepaydb?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&useSSL=false
username: jeepay
password: 123456
redis:
host: 127.0.0.1
port: 6379
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: ./logs #日志存放地址
#系统业务参数
isys:
allow-cors: false #是否允许跨域请求 [生产环境建议关闭, 若api与前端项目没有在同一个域名下时,应开启此配置或在nginx统一配置允许跨域]
jwt-secret: ARNXp4MzjOOQqxtv #生成jwt的秘钥。 要求每个系统有单独的秘钥管理机制。
# 文件系统配置项(系统内oss, 并非云oss)
oss-file:
root-path: /home/jeepay/upload #存储根路径 ( 无需以‘/’结尾 )
\ No newline at end of file
#################################
# 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文件只配置与环境相关的参数, 其他配置读取项目下的配置项
#
#################################
server:
port: 9216 #设置端口为 9216
spring:
datasource:
# yml填写url连接串, 无需将&符号进行转义
url: jdbc:mysql://127.0.0.1:3306/jeepaydb?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&useSSL=false
username: jeepay
password: 123456
redis:
host: 127.0.0.1
port: 6379
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: ./logs #日志存放地址
#系统业务参数
isys:
allow-cors: false #是否允许跨域请求 [生产环境建议关闭, 若api与前端项目没有在同一个域名下时,应开启此配置或在nginx统一配置允许跨域]
# 文件系统配置项(系统内oss, 并非云oss)
oss-file:
root-path: /home/jeepay/upload #存储根路径 ( 无需以‘/’结尾 )
\ No newline at end of file
#!/bin/sh
#功能简介:启动 xxx.jar 文件
#请先cd到项目下执行
#注意:在sh文件中=赋值,左右两侧不能有空格
# .Power by terrfly
#当前所在目录
PROJECT_PATH=$(cd `dirname $0`; pwd)
#当前所在文件夹名
PROJECT_NAME="${PROJECT_PATH##*/}"
#jar名称
APP_NAME='jeepay-'$PROJECT_NAME'.jar'
#=======================================================================
#当前应用进行的变量标识
APP_PID=''
# 重新获取APPID
function refAppPID(){
APP_PID=`ps -ef|grep $APP_NAME|grep -v grep|grep -v kill|awk '{print $2}'`
}
# 获取运行程序的pid 进程号
function getAppPID(){
if [ ! $APP_PID ]; then #未获取过
refAppPID
fi
}
# 启动
function start(){
refAppPID #获取进程PID, 需重新获取, 避免restart时无法正确启动。
if [ $APP_PID ]; then
echo " [$APP_NAME] App is running. this start fail. "
return 0
fi
nohup java -jar $APP_NAME >/dev/null 2>start.log &
# tail -200f start.log
echo " [$APP_NAME] App starting ... "
}
# 停止
function stop(){
getAppPID #获取进程PID
if [ ! $APP_PID ]; then
echo " [$APP_NAME] App is NOT running. "
return 0
fi
echo " [$APP_NAME] [pid=$APP_PID] [kill -15] stop process... "
kill -15 $APP_PID # kill-15 :正常退出程序
sleep 5 #等待5s
# 重新获取PID
refAppPID
#仍然存在 需要kill -9
if [ $APP_PID ]; then
forcekill
fi
echo " [$APP_NAME] Stop Success! "
}
# 检查
function check(){
getAppPID #获取进程PID
if [ $APP_PID ]; then
echo " [$APP_NAME] App is running. PID:[$APP_PID] "
else
echo " [$APP_NAME] App is NOT running. "
fi
}
# 强制kill进程
function forcekill(){
getAppPID #获取进程PID
if [ $APP_PID ]; then
echo " [$APP_NAME] [pid=$APP_PID] [kill -9] Kill ing ... "
kill -9 $APP_PID
echo " [$APP_NAME] [pid=$APP_PID] [kill -9] Kill Success! "
else
echo " [$APP_NAME] App is NOT running. "
fi
}
echo ''
command=$1
if [ "${command}" == "start" ]; then
start
elif [ "${command}" == "stop" ]; then
stop
elif [ "${command}" == "restart" ]; then
stop
start
elif [ "${command}" == "check" ]; then
check
elif [ "${command}" == "kill" ]; then
forcekill
else
echo "Usage: $0 {start|stop|restart|check|kill|}"
fi
echo ''
This diff is collapsed.
/* 支付中心相关表结构 */
CREATE TABLE `t_mch_info` (
`MchId` varchar(30) NOT NULL COMMENT '商户ID',
`Name` varchar(30) NOT NULL COMMENT '名称',
`Type` varchar(24) NOT NULL COMMENT '类型',
`ReqKey` varchar(128) NOT NULL COMMENT '请求私钥',
`ResKey` varchar(128) NOT NULL COMMENT '响应私钥',
`State` tinyint(6) NOT NULL DEFAULT '1' COMMENT '商户状态,0-停止使用,1-使用中',
`CreateTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`UpdateTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`MchId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商户信息表';
CREATE TABLE `t_pay_channel` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '渠道主键ID',
`ChannelId` varchar(24) NOT NULL COMMENT '渠道ID',
`ChannelName` varchar(30) NOT NULL COMMENT '渠道名称,如:alipay,wechat',
`ChannelMchId` varchar(32) NOT NULL COMMENT '渠道商户ID',
`MchId` varchar(30) NOT NULL COMMENT '商户ID',
`State` tinyint(6) NOT NULL DEFAULT '1' COMMENT '渠道状态,0-停止使用,1-使用中',
`Param` varchar(4096) NOT NULL COMMENT '配置参数,json字符串',
`Remark` varchar(128) DEFAULT NULL COMMENT '备注',
`CreateTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`UpdateTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`ID`),
UNIQUE KEY `IDX_MchId_MchOrderNo` (`ChannelId`, `MchId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='支付渠道表';
CREATE TABLE `t_pay_order` (
`PayOrderId` varchar(30) NOT NULL COMMENT '支付订单号',
`MchId` varchar(30) NOT NULL COMMENT '商户ID',
`MchOrderNo` varchar(30) NOT NULL COMMENT '商户订单号',
`ChannelId` varchar(24) NOT NULL COMMENT '渠道ID',
`Amount` bigint(20) NOT NULL COMMENT '支付金额,单位分',
`Currency` varchar(3) NOT NULL DEFAULT 'cny' COMMENT '三位货币代码,人民币:cny',
`Status` tinyint(6) NOT NULL DEFAULT '0' COMMENT '支付状态,0-订单生成,1-支付中(目前未使用),2-支付成功,3-业务处理完成',
`ClientIp` varchar(32) DEFAULT NULL COMMENT '客户端IP',
`Device` varchar(64) DEFAULT NULL COMMENT '设备',
`Subject` varchar(64) NOT NULL COMMENT '商品标题',
`Body` varchar(256) NOT NULL COMMENT '商品描述信息',
`Extra` varchar(512) DEFAULT NULL COMMENT '特定渠道发起时额外参数',
`ChannelMchId` varchar(32) NOT NULL COMMENT '渠道商户ID',
`ChannelOrderNo` varchar(64) DEFAULT NULL COMMENT '渠道订单号',
`ErrCode` varchar(64) DEFAULT NULL COMMENT '渠道支付错误码',
`ErrMsg` varchar(128) DEFAULT NULL COMMENT '渠道支付错误描述',
`Param1` varchar(64) DEFAULT NULL COMMENT '扩展参数1',
`Param2` varchar(64) DEFAULT NULL COMMENT '扩展参数2',
`NotifyUrl` varchar(128) NOT NULL COMMENT '通知地址',
`NotifyCount` tinyint(6) NOT NULL DEFAULT 0 COMMENT '通知次数',
`LastNotifyTime` bigint(20) DEFAULT NULL COMMENT '最后一次通知时间',
`ExpireTime` bigint(20) DEFAULT NULL COMMENT '订单失效时间',
`PaySuccTime` bigint(20) DEFAULT NULL COMMENT '订单支付成功时间',
`CreateTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`UpdateTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`PayOrderId`),
UNIQUE KEY `IDX_MchId_MchOrderNo` (`MchId`, MchOrderNo)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='支付订单表';
CREATE TABLE `t_iap_receipt` (
`PayOrderId` varchar(30) NOT NULL COMMENT '支付订单号',
`MchId` varchar(30) NOT NULL COMMENT '商户ID',
`TransactionId` varchar(24) NOT NULL COMMENT 'IAP业务号',
`ReceiptData` TEXT NOT NULL COMMENT '渠道ID',
`Status` tinyint(6) NOT NULL DEFAULT '0' COMMENT '处理状态:0-未处理,1-处理成功,-1-处理失败',
`HandleCount` tinyint(6) NOT NULL DEFAULT 0 COMMENT '处理次数',
`CreateTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`UpdateTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`PayOrderId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='苹果支付凭据表';
CREATE TABLE `t_trans_order` (
`TransOrderId` varchar(30) NOT NULL COMMENT '转账订单号',
`MchId` varchar(30) NOT NULL COMMENT '商户ID',
`MchTransNo` varchar(30) NOT NULL COMMENT '商户转账单号',
`ChannelId` varchar(24) NOT NULL COMMENT '渠道ID',
`Amount` bigint(20) NOT NULL COMMENT '转账金额,单位分',
`Currency` varchar(3) NOT NULL DEFAULT 'cny' COMMENT '三位货币代码,人民币:cny',
`Status` tinyint(6) NOT NULL DEFAULT '0' COMMENT '转账状态:0-订单生成,1-转账中,2-转账成功,3-转账失败,4-业务处理完成',
`Result` tinyint(6) NOT NULL DEFAULT '0' COMMENT '转账结果:0-不确认结果,1-等待手动处理,2-确认成功,3-确认失败',
`ClientIp` varchar(32) DEFAULT NULL COMMENT '客户端IP',
`Device` varchar(64) DEFAULT NULL COMMENT '设备',
`RemarkInfo` varchar(256) DEFAULT NULL COMMENT '备注',
`ChannelUser` varchar(32) DEFAULT NULL COMMENT '渠道用户标识,如微信openId,支付宝账号',
`UserName` varchar(24) DEFAULT NULL COMMENT '用户姓名',
`ChannelMchId` varchar(32) NOT NULL COMMENT '渠道商户ID',
`ChannelOrderNo` varchar(32) DEFAULT NULL COMMENT '渠道订单号',
`ChannelErrCode` varchar(128) DEFAULT NULL COMMENT '渠道错误码',
`ChannelErrMsg` varchar(128) DEFAULT NULL COMMENT '渠道错误描述',
`Extra` varchar(512) DEFAULT NULL COMMENT '特定渠道发起时额外参数',
`NotifyUrl` varchar(128) NOT NULL COMMENT '通知地址',
`Param1` varchar(64) DEFAULT NULL COMMENT '扩展参数1',
`Param2` varchar(64) DEFAULT NULL COMMENT '扩展参数2',
`ExpireTime` datetime DEFAULT NULL COMMENT '订单失效时间',
`TransSuccTime` datetime DEFAULT NULL COMMENT '订单转账成功时间',
`CreateTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`UpdateTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`TransOrderId`),
UNIQUE KEY `IDX_MchId_MchOrderNo` (`MchId`, MchTransNo)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='转账订单表';
CREATE TABLE `t_refund_order` (
`RefundOrderId` varchar(30) NOT NULL COMMENT '退款订单号',
`PayOrderId` varchar(30) NOT NULL COMMENT '支付订单号',
`ChannelPayOrderNo` varchar(64) DEFAULT NULL COMMENT '渠道支付单号',
`MchId` varchar(30) NOT NULL COMMENT '商户ID',
`MchRefundNo` varchar(30) NOT NULL COMMENT '商户退款单号',
`ChannelId` varchar(24) NOT NULL COMMENT '渠道ID',
`PayAmount` bigint(20) NOT NULL COMMENT '支付金额,单位分',
`RefundAmount` bigint(20) NOT NULL COMMENT '退款金额,单位分',
`Currency` varchar(3) NOT NULL DEFAULT 'cny' COMMENT '三位货币代码,人民币:cny',
`Status` tinyint(6) NOT NULL DEFAULT '0' COMMENT '退款状态:0-订单生成,1-退款中,2-退款成功,3-退款失败,4-业务处理完成',
`Result` tinyint(6) NOT NULL DEFAULT '0' COMMENT '退款结果:0-不确认结果,1-等待手动处理,2-确认成功,3-确认失败',
`ClientIp` varchar(32) DEFAULT NULL COMMENT '客户端IP',
`Device` varchar(64) DEFAULT NULL COMMENT '设备',
`RemarkInfo` varchar(256) DEFAULT NULL COMMENT '备注',
`ChannelUser` varchar(32) DEFAULT NULL COMMENT '渠道用户标识,如微信openId,支付宝账号',
`UserName` varchar(24) DEFAULT NULL COMMENT '用户姓名',
`ChannelMchId` varchar(32) NOT NULL COMMENT '渠道商户ID',
`ChannelOrderNo` varchar(32) DEFAULT NULL COMMENT '渠道订单号',
`ChannelErrCode` varchar(128) DEFAULT NULL COMMENT '渠道错误码',
`ChannelErrMsg` varchar(128) DEFAULT NULL COMMENT '渠道错误描述',
`Extra` varchar(512) DEFAULT NULL COMMENT '特定渠道发起时额外参数',
`NotifyUrl` varchar(128) NOT NULL COMMENT '通知地址',
`Param1` varchar(64) DEFAULT NULL COMMENT '扩展参数1',
`Param2` varchar(64) DEFAULT NULL COMMENT '扩展参数2',
`ExpireTime` datetime DEFAULT NULL COMMENT '订单失效时间',
`RefundSuccTime` datetime DEFAULT NULL COMMENT '订单退款成功时间',
`CreateTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`UpdateTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`RefundOrderId`),
UNIQUE KEY `IDX_MchId_MchOrderNo` (`MchId`, MchRefundNo)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='退款订单表';
CREATE TABLE `t_mch_notify` (
`OrderId` varchar(24) NOT NULL COMMENT '订单ID',
`MchId` varchar(30) NOT NULL COMMENT '商户ID',
`MchOrderNo` varchar(30) NOT NULL COMMENT '商户订单号',
`OrderType` varchar(8) NOT NULL COMMENT '订单类型:1-支付,2-转账,3-退款',
`NotifyUrl` varchar(2048) NOT NULL COMMENT '通知地址',
`NotifyCount` tinyint(6) NOT NULL DEFAULT 0 COMMENT '通知次数',
`Result` varchar(2048) DEFAULT NULL COMMENT '通知响应结果',
`Status` tinyint(6) NOT NULL DEFAULT '1' COMMENT '通知状态,1-通知中,2-通知成功,3-通知失败',
`LastNotifyTime` datetime DEFAULT NULL COMMENT '最后一次通知时间',
`CreateTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`UpdateTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`OrderId`),
UNIQUE KEY `IDX_MchId_OrderType_MchOrderNo` (`MchId`, `OrderType`, `MchOrderNo`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商户通知表';
/* 支付演示商城相关表 */
CREATE TABLE `t_goods_order` (
`GoodsOrderId` varchar(30) NOT NULL COMMENT '商品订单ID',
`GoodsId` varchar(30) NOT NULL COMMENT '商品ID',
`GoodsName` varchar(64) NOT NULL DEFAULT '' COMMENT '商品名称',
`Amount` bigint(20) NOT NULL COMMENT '金额,单位分',
`UserId` varchar(30) NOT NULL COMMENT '用户ID',
`Status` tinyint(6) NOT NULL DEFAULT '0' COMMENT '订单状态,订单生成(0),支付成功(1),处理完成(2),处理失败(-1)',
`PayOrderId` varchar(30) DEFAULT NULL COMMENT '支付订单号',
`ChannelId` varchar(24) DEFAULT NULL COMMENT '渠道ID',
`ChannelUserId` varchar(64) DEFAULT NULL COMMENT '支付渠道用户ID(微信openID或支付宝账号等第三方支付账号)',
`CreateTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`UpdateTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`GoodsOrderId`),
UNIQUE KEY `IDX_PayOrderId` (PayOrderId)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品订单表';
\ 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-core</artifactId> <!-- 项目名称 -->
<packaging>jar</packaging> <!-- 项目的最终打包类型/发布形式, 可选[jar, war, pom, maven-plugin]等 -->
<version>${isys.version}</version> <!-- 项目当前版本号 -->
<description>Jeepay计全支付系统 [jeepay-core]</description> <!-- 项目描述 -->
<url>https://www.jeequan.com</url>
<parent>
<groupId>com.jeequan</groupId>
<artifactId>jeepay</artifactId>
<version>1.0.0</version>
</parent>
<!-- 项目依赖声明 -->
<dependencies>
<!-- 依赖 [spring-context] 基础包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<scope>provided</scope>
</dependency>
<!-- 可选依赖 [spring-redis] -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<scope>provided</scope>
</dependency>
<!-- 添加 spring-webmvc 基础依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<scope>provided</scope> <!-- 仅编译依赖该jar, 运行时存在 -->
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope> <!-- 仅编译依赖该jar, 运行时存在 -->
</dependency>
<!-- mybatis plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis.plus.starter.version}</version>
<scope>provided</scope>
</dependency>
<!-- JWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<scope>provided</scope>
</dependency>
<!-- Spring Security -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<scope>provided</scope>
</dependency>
<!-- alibaba FastJSON -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<!-- commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</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.core.aop;
import java.lang.annotation.*;
/*
* 方法级日志切面注解
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 18:00
*/
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MethodLog {
String remark() default "";
}
/*
* 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.core.beans;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.exception.BizException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import javax.servlet.http.HttpServletRequest;
import java.util.Iterator;
import java.util.Map;
/*
* 基于spring的 req 工具类
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/7 12:16
*/
@Slf4j
@Component
public class RequestKitBean {
@Autowired(required = false)
protected HttpServletRequest request; //自动注入request
/** reqContext对象中的key: 转换好的json对象 */
private static final String REQ_CONTEXT_KEY_PARAMJSON = "REQ_CONTEXT_KEY_PARAMJSON";
/**request.getParameter 获取参数 并转换为JSON格式 **/
public JSONObject reqParam2JSON() {
JSONObject returnObject = new JSONObject();
if(isConvertJSON()){
String body = "";
try {
String str;
while((str = request.getReader().readLine()) != null){
body += str;
}
if(StringUtils.isEmpty(body)) return returnObject;
return JSONObject.parseObject(body);
} catch (Exception e) {
log.error("请求参数转换异常! params=[{}]", body);
throw new BizException(ApiCodeEnum.PARAMS_ERROR, "转换异常");
}
}
// 参数Map
Map properties = request.getParameterMap();
// 返回值Map
Iterator entries = properties.entrySet().iterator();
Map.Entry entry;
String name;
String value = "";
while (entries.hasNext()) {
entry = (Map.Entry) entries.next();
name = (String) entry.getKey();
Object valueObj = entry.getValue();
if(null == valueObj){
value = "";
}else if(valueObj instanceof String[]){
String[] values = (String[])valueObj;
for(int i=0;i<values.length;i++){
value = values[i] + ",";
}
value = value.substring(0, value.length()-1);
}else{
value = valueObj.toString();
}
if(!name.contains("[")){
returnObject.put(name, value);
continue;
}
//添加对json对象解析的支持 example: {ps[abc] : 1}
String mainKey = name.substring(0, name.indexOf("["));
String subKey = name.substring(name.indexOf("[") + 1 , name.indexOf("]"));
JSONObject subJson = new JSONObject();
if(returnObject.get(mainKey) != null) {
subJson = (JSONObject)returnObject.get(mainKey);
}
subJson.put(subKey, value);
returnObject.put(mainKey, subJson);
}
return returnObject;
}
/** 获取json格式的请求参数 **/
public JSONObject getReqParamJSON(){
//将转换好的reqParam JSON格式的对象保存在当前请求上下文对象中进行保存;
// 注意1: springMVC的CTRL默认单例模式, 不可使用局部变量保存,会出现线程安全问题;
// 注意2: springMVC的请求模式为线程池,如果采用ThreadLocal保存对象信息,可能会出现不清空或者被覆盖的问题。
Object reqParamObject = RequestContextHolder.getRequestAttributes().getAttribute(REQ_CONTEXT_KEY_PARAMJSON, RequestAttributes.SCOPE_REQUEST);
if(reqParamObject == null){
JSONObject reqParam = reqParam2JSON();
RequestContextHolder.getRequestAttributes().setAttribute(REQ_CONTEXT_KEY_PARAMJSON, reqParam, RequestAttributes.SCOPE_REQUEST);
return reqParam;
}
return (JSONObject) reqParamObject;
}
/** 判断请求参数是否转换为json格式 */
private boolean isConvertJSON(){
String contentType = request.getContentType();
//有contentType && json格式, get请求不转换
if(contentType != null
&& contentType.toLowerCase().indexOf("application/json") >= 0
&& !request.getMethod().equalsIgnoreCase("GET")
){ //application/json 需要转换为json格式;
return true;
}
return false;
}
/** 获取客户端ip地址 **/
public String getClientIp() {
String ipAddress = null;
ipAddress = request.getHeader("x-forwarded-for");
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("Proxy-Client-IP");
}
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("WL-Proxy-Client-IP");
}
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getRemoteAddr();
}
// 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
if (ipAddress != null && ipAddress.length() > 15) {
if (ipAddress.indexOf(",") > 0) {
ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
}
}
return ipAddress;
}
}
/*
* 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.core.cache;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.model.security.JeeUserDetails;
/*
* token service
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/5/24 09:06
*/
public class ITokenService {
/** 处理token信息
* 1. 如果不允许多用户则踢掉之前的所有用户信息
* 2. 更新token 缓存时间信息
* 3. 更新用户token列表
* **/
public static void processTokenCache(JeeUserDetails userDetail, String cacheKey){
userDetail.setCacheKey(cacheKey); //设置cacheKey
//当前用户的所有登录token 集合
// if(!PropKit.isAllowMultiUser()){ //不允许多用户登录
//
// List<String> allTokenList = new ArrayList<>();
// for (String token : allTokenList) {
// if(!cacheKey.equalsIgnoreCase(token)){
// RedisUtil.del(token);
// }
// }
// }
//保存token
RedisUtil.set(cacheKey, userDetail, CS.TOKEN_TIME); //缓存时间2小时, 保存具体信息而只是uid, 因为很多场景需要得到信息, 例如验证接口权限, 每次请求都需要获取。 将信息封装在一起减少磁盘请求次数, 如果放置多个key会增加非顺序读取。
}
/** 退出时,清除token信息 */
public static void removeIToken(String iToken, Long currentUID){
//1. 清除token的信息
RedisUtil.del(iToken);
}
/**
* 刷新数据
* **/
public static void refData(JeeUserDetails currentUserInfo){
//保存token 和 tokenList信息
RedisUtil.set(currentUserInfo.getCacheKey(), currentUserInfo, CS.TOKEN_TIME); //缓存时间2小时, 保存具体信息而只是uid, 因为很多场景需要得到信息, 例如验证接口权限, 每次请求都需要获取。 将信息封装在一起减少磁盘请求次数, 如果放置多个key会增加非顺序读取。
}
}
/*
* 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.core.cache;
import com.alibaba.fastjson.JSON;
import com.jeequan.jeepay.core.utils.SpringBeansUtil;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.CollectionUtils;
import java.util.Collection;
import java.util.concurrent.TimeUnit;
/*
* Redis工具类
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/5/24 17:58
*/
public class RedisUtil {
private static StringRedisTemplate stringRedisTemplate = null;
/** 获取RedisTemplate对象, 默认使用 StringRedisTemplate, 客户端可查询 **/
private static final RedisTemplate getStringRedisTemplate(){
if(stringRedisTemplate == null){
if(SpringBeansUtil.getApplicationContext().containsBean("defaultStringRedisTemplate")){
stringRedisTemplate = SpringBeansUtil.getBean("defaultStringRedisTemplate", StringRedisTemplate.class);
}else{
stringRedisTemplate = SpringBeansUtil.getBean(StringRedisTemplate.class);
}
}
return stringRedisTemplate;
}
/** 获取缓存数据, String类型 */
public static String getString(String key) {
if(key == null) return null;
return (String)getStringRedisTemplate().opsForValue().get(key);
}
/** 获取缓存数据对象 */
public static <T> T getObject(String key, Class<T> cls) {
String val = getString(key);
return JSON.parseObject(val, cls);
}
/** 放置缓存对象 */
public static void setString(String key, String value) {
getStringRedisTemplate().opsForValue().set(key, value);
}
/** 普通缓存放入并设置时间, 默认单位:秒 */
public static void setString(String key, String value, long time) {
getStringRedisTemplate().opsForValue().set(key, value, time, TimeUnit.SECONDS);
}
/** 普通缓存放入并设置时间 */
public static void setString(String key, String value, long time, TimeUnit timeUnit) {
getStringRedisTemplate().opsForValue().set(key, value, time, timeUnit);
}
/** 放置缓存对象 */
public static void set(String key, Object value) {
setString(key, JSON.toJSONString(value));
}
/** 普通缓存放入并设置时间, 默认单位:秒 */
public static void set(String key, Object value, long time) {
setString(key, JSON.toJSONString(value), time);
}
/** 普通缓存放入并设置时间 */
public static void set(String key, Object value, long time, TimeUnit timeUnit) {
setString(key, JSON.toJSONString(value), time, timeUnit);
}
/** 指定缓存失效时间 */
public static void expire(String key, long time) {
getStringRedisTemplate().expire(key, time, TimeUnit.SECONDS);
}
/** 指定缓存失效时间 */
public static void expire(String key, long time, TimeUnit timeUnit) {
getStringRedisTemplate().expire(key, time, timeUnit);
}
/**
* 根据key 获取过期时间
* @param key 键 不能为null
* @return 时间(秒) 返回0代表为永久有效
*/
public static long getExpire(String key) {
return getStringRedisTemplate().getExpire(key, TimeUnit.SECONDS);
}
/** 判断key是否存在 */
public static boolean hasKey(String key) {
return getStringRedisTemplate().hasKey(key);
}
/** 删除缓存 **/
public static void del(String... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
getStringRedisTemplate().delete(key[0]);
} else {
getStringRedisTemplate().delete(CollectionUtils.arrayToList(key));
}
}
}
/** 查询keys */
public static Collection<String> keys(String pattern) {
return getStringRedisTemplate().keys(pattern);
}
}
/*
* 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.core.constants;
/*
* 接口返回码
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/5/24 17:07
*/
public enum ApiCodeEnum{
SUCCESS(0, "SUCCESS"), //请求成功
CUSTOM_FAIL(9999, "自定义业务异常"), //自定义业务异常
SYSTEM_ERROR(10, "系统异常[%s]"),
PARAMS_ERROR(11, "参数有误[%s]"),
DB_ERROR(12, "数据库服务异常"),
SYS_OPERATION_FAIL_CREATE(5000, "新增失败"),
SYS_OPERATION_FAIL_DELETE(5001, "删除失败"),
SYS_OPERATION_FAIL_UPDATE(5002, "修改失败"),
SYS_OPERATION_FAIL_SELETE(5003, "记录不存在"),
SYS_PERMISSION_ERROR(5004, "权限错误,当前用户不支持此操作");
private int code;
private String msg;
ApiCodeEnum(int code, String msg) {
this.code = code;
this.msg = msg;
}
public int getCode(){
return this.code;
}
public String getMsg() {
return this.msg;
}
}
/*
* 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.core.constants;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* @Author terrfly
* @Date 2019/11/16 15:09
* @Description Constants 常量对象
**/
public class CS {
/** 系统类型定义 **/
public interface SYS_TYPE{
String MCH = "MCH";
String MGR = "MGR";
Map<String, String> SYS_TYPE_MAP = new HashMap<>();
}
static {
SYS_TYPE.SYS_TYPE_MAP.put(SYS_TYPE.MCH, "商户系统");
SYS_TYPE.SYS_TYPE_MAP.put(SYS_TYPE.MGR, "运营平台");
}
/** yes or no **/
public static final byte NO = 0;
public static final byte YES = 1;
/** 通用 可用 / 禁用 **/
public static final int PUB_USABLE = 1;
public static final int PUB_DISABLE = 0;
public static final Map<Integer, String> PUB_USABLE_MAP = new HashMap<>();
static {
PUB_USABLE_MAP.put(PUB_USABLE, "正常");
PUB_USABLE_MAP.put(PUB_DISABLE, "停用");
}
/**
* 账号类型:1-服务商 2-商户
*/
public static final byte INFO_TYPE_ISV = 1;
public static final byte INFO_TYPE_MCH = 2;
/**
* 商户类型:1-普通商户 2-特约商户
*/
public static final byte MCH_TYPE_NORMAL = 1;
public static final byte MCH_TYPE_ISVSUB = 2;
/**
* 性别 1- 男, 2-女
*/
public static final byte SEX_UNKNOWN = 0;
public static final byte SEX_MALE = 1;
public static final byte SEX_FEMALE = 2;
/** 默认密码 */
public static final String DEFAULT_PWD = "jeepay666";
/**
* 允许上传的的图片文件格式,需要与 WebSecurityConfig对应
*/
public static final Set<String> ALLOW_UPLOAD_IMG_SUFFIX = new HashSet<>();
static{
ALLOW_UPLOAD_IMG_SUFFIX.add("jpg");
ALLOW_UPLOAD_IMG_SUFFIX.add("png");
ALLOW_UPLOAD_IMG_SUFFIX.add("jpeg");
ALLOW_UPLOAD_IMG_SUFFIX.add("gif");
ALLOW_UPLOAD_IMG_SUFFIX.add("mp4");
}
public static final long TOKEN_TIME = 60 * 60 * 2; //单位:s, 两小时
//access_token 名称
public static final String ACCESS_TOKEN_NAME = "iToken";
/** !!不同系统请放置不同的redis库 !! **/
/** 缓存key: 当前用户所有用户的token集合 example: TOKEN_1001_HcNheNDqHzhTIrT0lUXikm7xU5XY4Q */
public static final String CACHE_KEY_TOKEN = "TOKEN_%s_%s";
public static String getCacheKeyToken(Long sysUserId, String uuid){
return String.format(CACHE_KEY_TOKEN, sysUserId, uuid);
}
/** 图片验证码 缓存key **/
public static final String CACHE_KEY_IMG_CODE = "img_code_%s";
public static String getCacheKeyImgCode(String imgToken){
return String.format(CACHE_KEY_IMG_CODE, imgToken);
}
/** 登录认证类型 **/
public interface AUTH_TYPE{
byte LOGIN_USER_NAME = 1; //登录用户名
byte TELPHONE = 2; //手机号
byte EMAIL = 3; //邮箱
byte WX_UNION_ID = 10; //微信unionId
byte WX_MINI = 11; //微信小程序
byte WX_MP = 12; //微信公众号
byte QQ = 20; //QQ
}
public interface MQ{
/** 更新配置的通知消息 **/
String TOPIC_MODIFY_SYS_CONFIG = "topic.modify.sys.config";
/** 更新商户配置信息 **/
String TOPIC_MODIFY_MCH_INFO = "topic.modify.mch.info";
/** 更新服务商配置信息 **/
String TOPIC_MODIFY_ISV_INFO = "topic.modify.isv.info";
/** 支付订单 商户通知MQ **/
String QUEUE_PAYORDER_MCH_NOTIFY = "queue.payorder.mch.notify";
/** 轮询查单 MQ **/
String QUEUE_CHANNEL_ORDER_QUERY = "queue.channel.order.query";
/** 清除商户登录用户信息 **/
String QUEUE_MODIFY_MCH_USER_REMOVE = "queue.modify.mch.user.remove";
}
//菜单类型
public interface ENT_TYPE{
String MENU_LEFT = "ML"; //左侧显示菜单
String MENU_OTHER = "MO"; //其他菜单
String PAGE_OR_BTN = "PB"; //页面 or 按钮
}
//接口类型
public interface IF_CODE{
String ALIPAY = "alipay"; //支付宝官方支付
String WXPAY = "wxpay"; //微信官方支付
String YSFPAY = "ysfpay"; //云闪付开放平台
}
//支付方式代码
public interface PAY_WAY_CODE{
// 特殊支付方式
String QR_CASHIER = "QR_CASHIER"; // ( 通过二维码跳转到收银台完成支付, 已集成获取用户ID的实现。 )
String AUTO_BAR = "AUTO_BAR"; // 条码聚合支付(自动分类条码类型)
String ALI_BAR = "ALI_BAR"; //支付宝条码支付
String ALI_JSAPI = "ALI_JSAPI"; //支付宝服务窗支付
String ALI_APP = "ALI_APP"; //支付宝 app支付
String ALI_PC = "ALI_PC"; //支付宝 电脑网站支付
String ALI_WAP = "ALI_WAP"; //支付宝 wap支付
String ALI_QR = "ALI_QR"; //支付宝 二维码付款
String YSF_BAR = "YSF_BAR"; //云闪付条码支付
String YSF_JSAPI = "YSF_JSAPI"; //云闪付服务窗支付
String WX_JSAPI = "WX_JSAPI"; //微信jsapi支付
String WX_LITE = "WX_LITE"; //微信小程序支付
String WX_BAR = "WX_BAR"; //微信条码支付
String WX_H5 = "WX_H5"; //微信H5支付
String WX_NATIVE = "WX_NATIVE"; //微信扫码支付
}
//支付数据包 类型
public interface PAY_DATA_TYPE {
String PAY_URL = "payurl"; //跳转链接的方式 redirectUrl
String FORM = "form"; //表单提交
String WX_APP = "wxapp"; //微信app参数
String ALI_APP = "aliapp"; //支付宝app参数
String YSF_APP = "ysfapp"; //云闪付app参数
String CODE_URL = "codeUrl"; //二维码URL
String CODE_IMG_URL = "codeImgUrl"; //二维码图片显示URL
String NONE = "none"; //无参数
// String QR_CONTENT = "qrContent"; //二维码实际内容
}
//接口版本
public interface PAY_IF_VERSION{
String WX_V2 = "V2"; //微信接口版本V2
String WX_V3 = "V3"; //微信接口版本V3
}
}
/*
* 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.core.ctrls;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
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.beans.RequestKitBean;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.BaseModel;
import com.jeequan.jeepay.core.utils.DateKit;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.MutablePair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/*
* 抽象公共Ctrl
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2020/02/18 17:28
*/
public abstract class AbstractCtrl {
protected static final Logger logger = LoggerFactory.getLogger(AbstractCtrl.class);
private static final String PAGE_INDEX_PARAM_NAME = "pageNumber"; //分页页码 参数名
private static final String PAGE_SIZE_PARAM_NAME = "pageSize"; //分页条数 参数名
private static final int DEFAULT_PAGE_INDEX = 1; // 默认页码: 第一页
private static final int DEFAULT_PAGE_SIZE = 20; // 默认条数: 20
private static final String SORT_FIELD_PARAM_NAME = "sortField"; //排序字段
private static final String SORT_ORDER_FLAG_PARAM_NAME = "sortOrder"; // 排序正序, 倒序标志
@Autowired
protected HttpServletRequest request; //自动注入request
@Autowired
protected HttpServletResponse response; //自动注入response
@Autowired
protected RequestKitBean requestKitBean;
/** 获取json格式的请求参数 **/
protected JSONObject getReqParamJSON(){
return requestKitBean.getReqParamJSON();
}
/** 获取页码 **/
protected int getPageIndex() {
Integer pageIndex = getReqParamJSON().getInteger(PAGE_INDEX_PARAM_NAME);
if(pageIndex == null) return DEFAULT_PAGE_INDEX;
return pageIndex;
}
/** 获取条数, 默认不允许查询全部数据 **/
protected int getPageSize() {
return getPageSize(false);
}
/** 获取条数, 加入条件:是否允许获取全部数据 **/
protected int getPageSize(boolean allowQueryAll) {
Integer pageSize = getReqParamJSON().getInteger(PAGE_SIZE_PARAM_NAME);
if(allowQueryAll && pageSize != null && pageSize == -1) return Integer.MAX_VALUE; // -1代表获取全部数据,查询int最大值的数据
if(pageSize == null || pageSize < 0) return DEFAULT_PAGE_SIZE;
return pageSize;
}
/** 获取Ipage分页信息, 默认不允许获取全部数据 **/
protected IPage getIPage(){
return new Page(getPageIndex(), getPageSize());
}
/** 获取Ipage分页信息, 加入条件:是否允许获取全部数据 **/
protected IPage getIPage(boolean allowQueryAll){
return new Page(getPageIndex(), getPageSize(allowQueryAll));
}
/** 获取排序字段 MutablePair<是否正序, 排序字段> **/
protected MutablePair<Boolean, String> getSortInfo() {
String sortField = getReqParamJSON().getString(SORT_FIELD_PARAM_NAME);
String sortOrderFlag = getReqParamJSON().getString(SORT_ORDER_FLAG_PARAM_NAME);
if(StringUtils.isAllEmpty(sortField, sortField)){
return null;
}
return MutablePair.of("ascend".equalsIgnoreCase(sortOrderFlag), StrUtil.toUnderlineCase(sortField).toLowerCase());
}
/** 获取请求参数值 [ T 类型 ], [ 非必填 ] **/
protected <T> T getVal(String key, Class<T> cls) {
return getReqParamJSON().getObject(key, cls);
}
/** 获取请求参数值 [ T 类型 ], [ 必填 ] **/
protected <T> T getValRequired(String key, Class<T> cls) {
T value = getVal(key, cls);
if(ObjectUtils.isEmpty(value)) {
throw new BizException(ApiCodeEnum.PARAMS_ERROR, genParamRequiredMsg(key));
}
return value;
}
/** 获取请求参数值 [ T 类型 ], [ 如为null返回默认值 ] **/
protected <T> T getValDefault(String key, T defaultValue, Class<T> cls) {
T value = getVal(key, cls);
if(value == null) return defaultValue;
return value;
}
/** 获取请求参数值 String 类型相关函数 **/
protected String getValString(String key) {
return getVal(key, String.class);
}
protected String getValStringRequired(String key) {
return getValRequired(key, String.class);
}
protected String getValStringDefault(String key, String defaultValue) {
return getValDefault(key, defaultValue, String.class);
}
/** 获取请求参数值 Byte 类型相关函数 **/
protected Byte getValByte(String key) {
return getVal(key, Byte.class);
}
protected Byte getValByteRequired(String key) {
return getValRequired(key, Byte.class);
}
protected Byte getValByteDefault(String key, Byte defaultValue) {
return getValDefault(key, defaultValue, Byte.class);
}
/** 获取请求参数值 Integer 类型相关函数 **/
protected Integer getValInteger(String key) {
return getVal(key, Integer.class);
}
protected Integer getValIntegerRequired(String key) {
return getValRequired(key, Integer.class);
}
protected Integer getValIntegerDefault(String key, Integer defaultValue) {
return getValDefault(key, defaultValue, Integer.class);
}
/** 获取请求参数值 Long 类型相关函数 **/
protected Long getValLong(String key) {
return getVal(key, Long.class);
}
protected Long getValLongRequired(String key) {
return getValRequired(key, Long.class);
}
protected Long getValLongDefault(String key, Long defaultValue) {
return getValDefault(key, defaultValue, Long.class);
}
/** 获取请求参数值 BigDecimal 类型相关函数 **/
protected BigDecimal getValBigDecimal(String key) {
return getVal(key, BigDecimal.class);
}
protected BigDecimal getValBigDecimalRequired(String key) {
return getValRequired(key, BigDecimal.class);
}
protected BigDecimal getValBigDecimalDefault(String key, BigDecimal defaultValue) {
return getValDefault(key, defaultValue, BigDecimal.class);
}
/** 获取对象类型 **/
protected <T> T getObject(Class<T> clazz) {
JSONObject params = getReqParamJSON();
T result = params.toJavaObject(clazz);
if(result instanceof BaseModel){ //如果属于BaseModel, 处理apiExtVal
JSONObject resultTemp = (JSONObject) JSON.toJSON(result);
for (String key : params.keySet()) { //遍历原始参数
if(!resultTemp.containsKey(key)){
((BaseModel) result).addExt(key, params.get(key));
}
}
}
return result;
}
/** 生成参数必填错误信息 **/
private String genParamRequiredMsg(String key) {
return "参数" + key + "必填";
}
/** 校验参数值不能为空 */
protected void checkRequired(String... keys) {
for(String key : keys) {
String value = getReqParamJSON().getString(key);
if(StringUtils.isEmpty(value)) throw new BizException(ApiCodeEnum.PARAMS_ERROR, genParamRequiredMsg(key));
}
}
/** 得到前端传入的金额元,转换成长整型分 **/
public Long getRequiredAmountL(String name) {
String amountStr = getValStringRequired(name); // 前端填写的为元,可以为小数点2位
Long amountL = new BigDecimal(amountStr.trim()).multiply(new BigDecimal(100)).longValue(); // // 转成分
return amountL;
}
/** 得到前端传入的金额元,转换成长整型分 (非必填) **/
public Long getAmountL(String name) {
String amountStr = getValString(name); // 前端填写的为元,可以为小数点2位
if(StringUtils.isEmpty(amountStr)) return null;
Long amountL = new BigDecimal(amountStr.trim()).multiply(new BigDecimal(100)).longValue(); // // 转成分
return amountL;
}
/**
* 处理参数中的金额(将前端传入金额元转成分)
* modify: 20181206 添加JSON对象中的对象属性转换为分 格式[xxx.xxx]
* @param names
*/
public void handleParamAmount(String... names) {
for(String name : names) {
String amountStr = getValString(name); // 前端填写的为元,可以为小数点2位
if(StringUtils.isNotBlank(amountStr)) {
Long amountL = new BigDecimal(amountStr.trim()).multiply(new BigDecimal(100)).longValue(); // // 转成分
if(name.indexOf(".") < 0 ){
getReqParamJSON().put(name, amountL);
continue;
}
getReqParamJSON().getJSONObject(name.substring(0, name.indexOf("."))).put(name.substring(name.indexOf(".")+1), amountL);
}
}
}
/**
* 获取查询的时间范围
* @return
*/
protected Date[] getQueryDateRange(){
return DateKit.getQueryDateRange(getReqParamJSON().getString("queryDateRange")); //默认参数为 queryDateRange
}
/** 请求参数转换为map格式 **/
public Map<String, Object> request2payResponseMap(HttpServletRequest request, String[] paramArray) {
Map<String, Object> responseMap = new HashMap<>();
for (int i = 0;i < paramArray.length; i++) {
String key = paramArray[i];
String v = request.getParameter(key);
if (v != null) {
responseMap.put(key, v);
}
}
return responseMap;
}
/** 将上传的文件进行保存 - 公共函数 **/
protected void saveFile(MultipartFile file, String savePath) throws Exception {
File saveFile = new File(savePath);
//如果文件夹不存在则创建文件夹
File dir = saveFile.getParentFile();
if(!dir.exists()) dir.mkdirs();
file.transferTo(saveFile);
}
/** 获取客户端ip地址 **/
public String getClientIp() {
return requestKitBean.getClientIp();
}
public String getUserAgent(){
String userAgent = request.getHeader("User-Agent");
return StringUtils.isNotEmpty(userAgent) ? userAgent: "未知";
}
}
/*
* 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.core.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.jeequan.jeepay.core.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* <p>
* 服务商信息表
* </p>
*
* @author [mybatis plus generator]
* @since 2021-04-27
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("t_isv_info")
public class IsvInfo extends BaseModel implements Serializable {
//gw
public static final LambdaQueryWrapper<IsvInfo> gw(){
return new LambdaQueryWrapper<>();
}
private static final long serialVersionUID=1L;
/**
* 服务商号
*/
@TableId(value = "isv_no", type = IdType.INPUT)
private String isvNo;
/**
* 服务商名称
*/
private String isvName;
/**
* 服务商简称
*/
private String isvShortName;
/**
* 联系人姓名
*/
private String contactName;
/**
* 联系人手机号
*/
private String contactTel;
/**
* 联系人邮箱
*/
private String contactEmail;
/**
* 状态: 0-停用, 1-正常
*/
private Byte state;
/**
* 备注
*/
private String remark;
/**
* 创建者用户ID
*/
private Long createdUid;
/**
* 创建者姓名
*/
private String createdBy;
/**
* 创建时间
*/
private Date createdAt;
/**
* 更新时间
*/
private Date updatedAt;
}
/*
* 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.core.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.jeequan.jeepay.core.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* <p>
* 商户信息表
* </p>
*
* @author [mybatis plus generator]
* @since 2021-04-27
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("t_mch_info")
public class MchInfo extends BaseModel implements Serializable {
//gw
public static final LambdaQueryWrapper<MchInfo> gw(){
return new LambdaQueryWrapper<>();
}
private static final long serialVersionUID=1L;
public static final byte TYPE_NORMAL = 1; //商户类型: 1-普通商户
public static final byte TYPE_ISVSUB = 2; //商户类型: 2-特约商户
/**
* 商户号
*/
@TableId(value = "mch_no", type = IdType.INPUT)
private String mchNo;
/**
* 商户名称
*/
private String mchName;
/**
* 商户简称
*/
private String mchShortName;
/**
* 类型: 1-普通商户, 2-特约商户(服务商模式)
*/
private Byte type;
/**
* 服务商号
*/
private String isvNo;
/**
* 联系人姓名
*/
private String contactName;
/**
* 联系人手机号
*/
private String contactTel;
/**
* 联系人邮箱
*/
private String contactEmail;
/**
* 私钥
*/
private String privateKey;
/**
* 商户状态: 0-停用, 1-正常
*/
private Byte state;
/**
* 商户备注
*/
private String remark;
/**
* 初始用户ID(创建商户时,允许商户登录的用户)
*/
private Long initUserId;
/**
* 创建者用户ID
*/
private Long createdUid;
/**
* 创建者姓名
*/
private String createdBy;
/**
* 创建时间
*/
private Date createdAt;
/**
* 更新时间
*/
private Date updatedAt;
}
/*
* 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.core.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.jeequan.jeepay.core.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* <p>
* 商户通知记录表
* </p>
*
* @author [mybatis plus generator]
* @since 2021-04-27
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("t_mch_notify_record")
public class MchNotifyRecord extends BaseModel implements Serializable {
//订单类型:1-支付,2-退款
public static final Byte TYPE_PAY_ORDER = 1;
public static final Byte TYPE_REFUND_ORDER = 2;
//通知状态
public static final Byte STATE_ING = 1;
public static final Byte STATE_SUCCESS = 2;
public static final Byte STATE_FAIL = 3;
//gw
public static final LambdaQueryWrapper<MchNotifyRecord> gw(){
return new LambdaQueryWrapper<>();
}
private static final long serialVersionUID=1L;
/**
* 商户通知记录ID
*/
@TableId(value = "notify_id", type = IdType.AUTO)
private Long notifyId;
/**
* 订单ID
*/
private String orderId;
/**
* 订单类型:1-支付,2-退款
*/
private Byte orderType;
/**
* 商户订单号
*/
private String mchOrderNo;
/**
* 商户号
*/
private String mchNo;
/**
* 服务商号
*/
private String isvNo;
/**
* 通知地址
*/
private String notifyUrl;
/**
* 通知响应结果
*/
private String resResult;
/**
* 通知次数
*/
private Integer notifyCount;
/**
* 通知状态,1-通知中,2-通知成功,3-通知失败
*/
private Byte state;
/**
* 最后一次通知时间
*/
private Date lastNotifyTime;
/**
* 创建时间
*/
private Date createdAt;
/**
* 更新时间
*/
private Date updatedAt;
}
/*
* 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.core.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.jeequan.jeepay.core.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
/**
* <p>
* 商户支付通道表
* </p>
*
* @author [mybatis plus generator]
* @since 2021-04-27
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("t_mch_pay_passage")
public class MchPayPassage extends BaseModel implements Serializable {
public static final LambdaQueryWrapper<MchPayPassage> gw(){
return new LambdaQueryWrapper<>();
}
private static final long serialVersionUID=1L;
/**
* ID
*/
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 商户号
*/
private String mchNo;
/**
* 支付接口
*/
private String ifCode;
/**
* 支付方式
*/
private String wayCode;
/**
* 支付方式费率
*/
private BigDecimal rate;
/**
* 风控数据
*/
private String riskConfig;
/**
* 状态: 0-停用, 1-启用
*/
private Byte state;
/**
* 创建时间
*/
private Date createdAt;
/**
* 更新时间
*/
private Date updatedAt;
}
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