提交git

This commit is contained in:
2025-08-25 18:51:02 +08:00
commit 9dd33ed2b9
2171 changed files with 172166 additions and 0 deletions

81
uling-gateway/package.xml Normal file
View File

@ -0,0 +1,81 @@
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
<!--
assembly 打包配置更多配置可参考官司方文档:
http://maven.apache.org/plugins/maven-assembly-plugin/assembly.html
-->
<id>release</id>
<!--
设置打包格式可同时设置多种格式常用格式有dir、zip、tar、tar.gz
dir 格式便于在本地测试打包结果
zip 格式便于 windows 系统下解压运行
tar、tar.gz 格式便于 linux 系统下解压运行
-->
<formats>
<!-- <format>dir</format> -->
<format>zip</format>
<!-- <format>tar.gz</format> -->
</formats>
<!-- 打 zip 设置为 true 时,会在 zip 包中生成一个根目录,打 dir 时设置为 false 少层目录 -->
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<!-- src/main/resources 全部 copy 到 config 目录下 -->
<fileSet>
<directory>${basedir}/src/main/resources</directory>
<includes>
<include>*.txt</include>
<include>*.ini</include>
<include>*.xml</include>
<include>*.properties</include>
</includes>
<outputDirectory>config</outputDirectory>
</fileSet>
<fileSet>
<directory>${basedir}/src/main/resources</directory>
<excludes>
<exclude>*.txt</exclude>
<exclude>*.ini</exclude>
<exclude>*.xml</exclude>
<exclude>*.properties</exclude>
</excludes>
<outputDirectory>webapp</outputDirectory>
</fileSet>
<fileSet>
<directory>${basedir}/target/classes/webapp</directory>
<outputDirectory>webapp</outputDirectory>
</fileSet>
<!-- src/main/webapp 全部 copy 到 webapp 目录下 -->
<fileSet>
<directory>${basedir}/src/main/webapp</directory>
<outputDirectory>webapp</outputDirectory>
</fileSet>
<!-- 项目根下面的脚本文件 copy 到根目录下 -->
<fileSet>
<directory>${basedir}</directory>
<outputDirectory></outputDirectory>
<!-- 脚本文件在 linux 下的权限设为 755无需 chmod 可直接运行 -->
<fileMode>755</fileMode>
<includes>
<include>*.sh</include>
<include>*.bat</include>
</includes>
</fileSet>
</fileSets>
<!-- 依赖的 jar 包 copy 到 lib 目录下 -->
<dependencySets>
<dependencySet>
<outputDirectory>lib</outputDirectory>
</dependencySet>
</dependencySets>
</assembly>

105
uling-gateway/pom.xml Normal file
View File

@ -0,0 +1,105 @@
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cc.uling</groupId>
<artifactId>uling</artifactId>
<version>1.0</version>
</parent>
<artifactId>uling-gateway</artifactId>
<packaging>jar</packaging>
<name>gateway</name>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>cc.uling</groupId>
<artifactId>uling-system</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>cc.uling</groupId>
<artifactId>uling-yc-service</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<!-- **/* 打包代码生成器的模板文件 -->
<include>**/*.tp</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/webapp</directory>
<includes>
<include>**/*.*</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<encoding>UTF-8</encoding>
<!-- java8 保留参数名编译参数 -->
<compilerArgument>-parameters</compilerArgument>
</configuration>
</plugin>
<!--单模块打包 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<recompressZippedFiles>false</recompressZippedFiles>
<appendAssemblyId>false</appendAssemblyId>
<descriptors>
<descriptor>package.xml</descriptor>
</descriptors>
<outputDirectory>${project.build.directory}/</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

8
uling-gateway/readme Normal file
View File

@ -0,0 +1,8 @@
cd /Users/chenzigui/Workspaces/Projects/AbroadPaymentSystem/java/uling-gateway
mvn clean package
#测试服
scp /Users/chenzigui/Workspaces/Projects/AbroadPaymentSystem/java/uling-gateway/target/uling-gateway.zip \
root@43.134.84.111:/home/

View File

@ -0,0 +1,10 @@
package cc.uling.pay.gateway;
import io.jboot.app.JbootApplication;
public class YCGatewayApplication {
public static void main(String[] args) {
JbootApplication.run(args);
}
}

View File

@ -0,0 +1,80 @@
package cc.uling.pay.gateway;
import cc.uling.common.interceptor.AccessInterceptor;
import cc.uling.common.utils.HttpUtils;
import cc.uling.pay.gateway.interceptor.GatewayExceptionInterceptor;
import cn.hutool.core.date.DateUtil;
import com.jfinal.config.Constants;
import com.jfinal.config.Interceptors;
import com.jfinal.handler.Handler;
import com.jfinal.kit.PropKit;
import com.jfinal.plugin.cron4j.Cron4jPlugin;
import io.jboot.Jboot;
import io.jboot.aop.jfinal.JfinalHandlers;
import io.jboot.aop.jfinal.JfinalPlugins;
import io.jboot.core.listener.JbootAppListener;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
@Slf4j
public class YCGatewayListener implements JbootAppListener {
@Override
public void onInit() {
}
@Override
public void onPluginConfig(JfinalPlugins plugins) {
plugins.add(new Cron4jPlugin(PropKit.use("task.properties")));
}
@Override
public void onConstantConfig(Constants constants) {
constants.setDevMode(true);
constants.setInjectDependency(true);
constants.setInjectSuperClass(true);
constants.setMaxPostSize(100 * 1024 * 1024);// 最大支持 100M 文件上传
}
@Override
public void onInterceptorConfig(Interceptors interceptors) {
interceptors.addGlobalActionInterceptor(new AccessInterceptor());
interceptors.addGlobalActionInterceptor(new GatewayExceptionInterceptor());
}
@Override
public void onHandlerConfig(JfinalHandlers handlers) {
JbootAppListener.super.onHandlerConfig(handlers);
handlers.add(new Handler() {
@Override
public void handle(String target, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, boolean[] booleans) {
log.info("fetch|{}|request|{}", HttpUtils.getIpAddress(httpServletRequest), target);
try {
next.handle(target, httpServletRequest, httpServletResponse, booleans);
} catch (RuntimeException e) {
e.printStackTrace();
throw GatewayException.BAD_REQUEST;
}
}
});
}
@Override
public void onStart() {
log.info("YCGateway|onStart...{}|{}", Jboot.configValue("jboot.app.mode"), DateUtil.formatDateTime(new Date()));
}
@Override
public void onStop() {
log.info("YCGateway|onStop...{}", Jboot.configValue("jboot.app.mode"));
}
}

View File

@ -0,0 +1,26 @@
package cc.uling.pay.gateway.constants;
public interface ApiConst {
String api = "/v1";
String api_orders = api + "/orders";
String XClientID = "X-Client-ID";
String XTimestamp = "X-Timestamp";
String XSignature = "X-Signature";
/**
* 失败
*/
String error = "error";
/**
* 成功
*/
String success = "success";
}

View File

@ -0,0 +1,82 @@
package cc.uling.pay.gateway.controller;
import cc.uling.common.base.BaseController;
import cc.uling.common.manager.AsyncManager;
import cc.uling.common.utils.StringUtil;
import cc.uling.pay.gateway.GateRes;
import cc.uling.pay.gateway.GatewayException;
import cc.uling.pay.gateway.constants.ApiConst;
import cc.uling.pay.gateway.manager.DataManager;
import com.jfinal.aop.Aop;
import com.payment.expanded.ApiDemo;
import com.web.gen.model.MchInfo;
import com.web.gen.model.PayOrder;
import io.jboot.Jboot;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
public class AbController extends BaseController {
protected static Map<String, PayOrder> mDoingOrders = new ConcurrentHashMap<>();
public void renderFail(GatewayException exception) {
getResponse().setStatus(exception.getStatusCode());
renderJson(GateRes.fail(exception.getErrorCode(), exception.getErrorMsg()));
}
public Map<String, String> getParams() {
Map<String, String> map = new HashMap<>();
Enumeration<String> names = getRequest().getParameterNames();
while (names.hasMoreElements()) {
String name = names.nextElement();
map.put(name, getPara(name));
}
return map;
}
//查询支付中的订单
protected void queryOrder(PayOrder order) {
String mode = Jboot.configValue("jboot.app.mode");
String platOrderNo = order.getPayOrderId();
if (!mDoingOrders.containsKey(platOrderNo)) {
mDoingOrders.put(platOrderNo, order);
try {
AsyncManager.me().execute(new TimerTask() {
@Override
public void run() {
try {
String server = Aop.get(DataManager.class).getApiServer(mode);
MchInfo mchInfo = (MchInfo) getRequest().getAttribute(ApiConst.XClientID);
String requestUrl = server + "/api/expanded/transactions";
ApiDemo.queryPayOrder(requestUrl, mchInfo.getMchNo(), mchInfo.getSecretKey(), platOrderNo);
} catch (Exception e) {
e.printStackTrace();
} finally {
mDoingOrders.remove(platOrderNo);
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
}
protected <T> T getService(String ifCode, Class<T> clazz) {
T service = null;
String extName = clazz.getSimpleName().substring(1);
String className = clazz.getPackage().getName() + "." + ifCode + "." + StringUtil.capitalizeFirstLetter(ifCode) + extName; // 类的全限定名
try {
Class<? extends T> targetClazz = (Class<? extends T>) Class.forName(className);
service = Aop.get(targetClazz);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return service;
}
}

View File

@ -0,0 +1,106 @@
package cc.uling.pay.gateway.controller;
import cc.uling.common.constant.ResponseCode;
import cc.uling.common.enums.PayOrderStatus;
import cc.uling.common.utils.HttpUtils;
import cc.uling.common.utils.StringUtil;
import cc.uling.pay.gateway.*;
import cc.uling.pay.gateway.constants.ApiConst;
import cc.uling.pay.gateway.interceptor.SHA256SignInterceptor;
import cc.uling.pay.gateway.manager.DataManager;
import cc.uling.pay.gateway.protocol.Converter;
import cc.uling.service.BizPayOrderDetailService;
import cc.uling.web.config.ProjectConfig;
import cn.hutool.core.util.ObjectUtil;
import com.jfinal.aop.Aop;
import com.jfinal.aop.Before;
import com.jfinal.core.paragetter.Para;
import com.payment.expanded.ApiDemo;
import com.web.gen.model.MchInfo;
import com.web.gen.model.PayOrder;
import com.web.gen.service.PayOrderService;
import io.jboot.Jboot;
import io.jboot.db.model.Columns;
import io.jboot.web.controller.annotation.RequestMapping;
import lombok.extern.slf4j.Slf4j;
import javax.validation.Valid;
import java.util.Map;
@Slf4j
@Before(SHA256SignInterceptor.class)
@RequestMapping(value = ApiConst.api_orders)
public class IndexController extends AbController {
public void index() {
String platOrderId = getPara();
if (StringUtil.isEmpty(platOrderId)) {
throw GatewayException.MissingParam("transaction_id");
}
String dbName = ProjectConfig.isSandbox() ? ProjectConfig.SANDBOX : ProjectConfig.PROD;
MchInfo mchInfo = (MchInfo) getRequest().getAttribute(ApiConst.XClientID);
log.info("查询{}订单[{}]", dbName, platOrderId);
PayOrder payOrder = Aop.get(PayOrderService.class).findByColumns(dbName, Columns.create("pay_order_id", platOrderId).eq("mch_no", mchInfo.getMchNo()));
if (null == payOrder) {
throw GatewayException.NOT_FOUND;
}
if (ObjectUtil.equals(payOrder.getStatus(), PayOrderStatus.PAYING)) {
queryOrder(payOrder);
}
GateRes res = Converter.getOrderDetails(payOrder);
renderJson(res);
}
public void checkout(@Valid @Para("") CreatePayOrderRQ bizRQ) {
if (null == bizRQ) {
throw GatewayException.BAD_REQUEST;
}
bizRQ.check();
if (StringUtil.isEmpty(bizRQ.getClient_ip())) {
bizRQ.setClient_ip(HttpUtils.getIpAddress(getRequest()));
}
String dbName = ProjectConfig.isSandbox() ? ProjectConfig.SANDBOX : ProjectConfig.PROD;
MchInfo mchInfo = (MchInfo) getRequest().getAttribute(ApiConst.XClientID);
PayOrder payOrder = Aop.get(PayOrderService.class).findByColumns(dbName, Columns.create("mch_order_no", bizRQ.getOrder_id()).eq("mch_no", mchInfo.getMchNo()));
if (null != payOrder) {
throw new GatewayException(ResponseCode.UNPROCESSABLE, ErrorCode.UNPROCESSABLE, "request.fail.exists.order_id", bizRQ.getOrder_id());
}
Aop.get(BizPayOrderDetailService.class).saveOrUpdate(getRequest(), bizRQ, mchInfo);
String mode = Jboot.configValue("jboot.app.mode");
try {
Map<String, Object> dataMap = bizRQ.toMap(mchInfo, getRequest().getHeader(ApiConst.XClientID));
String server = Aop.get(DataManager.class).getApiServer(mode);
String requestUrl = server + "/api/expanded/transactions/create";
log.warn("requestUrl:{}\n", requestUrl);
String json = ApiDemo.doRequest(requestUrl, mchInfo.getMchNo(), mchInfo.getSecretKey(), dataMap);
log.warn("requestUrl:{}|response:" + json, requestUrl);
if (StringUtil.isNotEmpty(json)) {
OrderInfoRes res = Converter.getOrderDetails(json, bizRQ);
renderJson(res);
} else {
throw GatewayException.SYSTEM_ERROR;
}
} catch (GatewayException e) {
throw e;
} catch (RuntimeException e) {
e.printStackTrace();
throw GatewayException.SYSTEM_ERROR;
} catch (Exception e) {
e.printStackTrace();
throw GatewayException.SYSTEM_ERROR;
}
}
}

View File

@ -0,0 +1,214 @@
package cc.uling.pay.gateway.demo;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.stream.Collectors;
public class ApiClient {
// private static final String APP_ID = "123456"; // Application ID
// private static final String MERCHANT_KEY = "MDEyMzQ1Njc4OQ=="; // Merchant secret key
// private static final String BASE_URL = "https://api.wireupay.com"; // API base URL
private static final String APP_ID = "M9ILKMMYR2YNQXJMP2"; // Application ID
private static final String MERCHANT_KEY = "HCAIwL4LPwRiI7z81Lig66IF43="; // Merchant secret key
private static final String BASE_URL = "https://sandbox.wireupay.com"; // API base URL
public static void main(String[] args) {
// query("123456");
create(getBizParams());
}
private static Map<String, String> getBizParams() {
Map<String, String> params = new HashMap<>();
params.put("amount", "100.4");
params.put("currency", "USD");
params.put("payment_method", "checkout");
params.put("order_id", "23435435");
// params.put("client_ip", "11.11.11.11");
params.put("callback_url", "https://api.deepnudes.com/callback");
params.put("product_name", "coins");
return params;
}
public static void create(Map<String, String> params) {
try {
String requestUrl = BASE_URL + "/v1/orders/checkout";
String response = doRequest(requestUrl, APP_ID, MERCHANT_KEY, "POST", params);
System.out.println(response);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void query(String orderNo) {
try {
String requestUrl = BASE_URL + "/v1/orders/" + orderNo;
String response = doRequest(requestUrl, APP_ID, MERCHANT_KEY, "GET", null);
System.out.println(response);
} catch (Exception e) {
e.printStackTrace();
}
}
public static String doRequest(String requestUrl, String clientId, String mchKey, String httpMethod, Map<String, String> params) {
String response = null;
try {
String timestamp = System.currentTimeMillis() + "";
String signature = generateApiSignature(mchKey,
httpMethod,
timestamp,
clientId, params);
Map<String, String> headers = new HashMap<>();
headers.put("X-Client-ID", clientId);
headers.put("X-Timestamp", timestamp);
headers.put("X-Signature", signature);
response = sendRequest(httpMethod, requestUrl, params, headers);
} catch (Exception e) {
e.printStackTrace();
}
return response;
}
public static String sendRequest(String method, String url,
Map<String, String> params,
Map<String, String> headers) throws IOException {
String response = null;
HttpURLConnection connection = null;
try {
URL requestUrl = new URL(url);
connection = (HttpURLConnection) requestUrl.openConnection();
connection.setRequestMethod(method);
connection.setConnectTimeout(10000);
connection.setReadTimeout(10000);
if (headers != null) {
for (Map.Entry<String, String> header : headers.entrySet()) {
connection.setRequestProperty(header.getKey(), header.getValue());
}
}
if (!"GET".equalsIgnoreCase(method) && params != null && !params.isEmpty()) {
connection.setDoOutput(true);
try (OutputStream os = connection.getOutputStream()) {
byte[] postData = buildFormData(params).getBytes(StandardCharsets.UTF_8);
os.write(postData);
os.flush();
}
}
int responseCode = connection.getResponseCode();
try {
InputStream es = null;
try {
es = connection.getInputStream();
} catch (Exception e) {
// e.printStackTrace();
}
if (es == null) {
try {
es = connection.getErrorStream();
} catch (Exception e) {
// e.printStackTrace();
}
}
if (es != null) {
BufferedReader reader = new BufferedReader(new InputStreamReader(es, StandardCharsets.UTF_8));
response = reader.lines().collect(Collectors.joining("\n"));
}
} catch (Exception e) {
e.printStackTrace();
}
} finally {
if (connection != null) {
connection.disconnect();
}
}
return response;
}
private static String buildFormData(Map<String, String> params) throws UnsupportedEncodingException {
return params.entrySet().stream()
.map(e -> {
try {
return URLEncoder.encode(e.getKey(), "UTF-8") + "=" +
URLEncoder.encode(e.getValue(), "UTF-8");
} catch (UnsupportedEncodingException ex) {
throw new RuntimeException(ex);
}
})
.collect(Collectors.joining("&"));
}
public static String generateApiSignature(
String apiSecret,
String httpMethod,
String timestamp,
String merchantId, Map<String, String> params) throws SecurityException {
try {
// 1. Construct the base string
String sortedParams = sortParams(params);
String baseString = String.format("%s\n%s\n%s\n%s",
httpMethod,
timestamp,
merchantId,
sortedParams);
System.out.println("baseString="+baseString);
// 2. Calculate HMAC-SHA256 1
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec(
apiSecret.getBytes(StandardCharsets.UTF_8),
"HmacSHA256");
sha256_HMAC.init(secretKey);
byte[] hashBytes = sha256_HMAC.doFinal(baseString.getBytes(StandardCharsets.UTF_8));
// 3. Return hexadecimal result
return bytesToHex(hashBytes);
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
e.printStackTrace();
}
return null;
}
public static String sortParams(Map<String, String> params) {
StringBuilder sb = new StringBuilder();
if (null != params && !params.isEmpty()) {
List<String> keys = new ArrayList<>(params.keySet());
Collections.sort(keys);
for (String key : keys) {
sb.append(key).append("=").append(params.get(key)).append("&");
}
sb.deleteCharAt(sb.length() - 1);
}
return sb.toString();
}
private static String bytesToHex(byte[] bytes) {
StringBuilder result = new StringBuilder();
for (byte b : bytes) {
result.append(String.format("%02x", b));
}
return result.toString();
}
}

View File

@ -0,0 +1,267 @@
package cc.uling.pay.gateway.demo;
import cc.uling.pay.gateway.ApiSignatureGenerator;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.stream.Collectors;
public class ApiClient0 {
private static final String APP_ID = "123456"; // Application ID
private static final String MERCHANT_KEY = "MDEyMzQ1Njc4OQ==";
private static final String BASE_URL = "http://localhost:8094"; // API base URL
// private static final String APP_ID = "MLAUQBHFO9GIVPNVR2"; // Application ID
// private static final String MERCHANT_KEY = "jAVc3/bO4enU5/G5+VtSJg=="; // Merchant secret key
// private static final String BASE_URL = "https://sandbox.wireupay.com"; // API base URL
public static void main(String[] args) {
// query("123456");
create(getBizParams());
// callback();
}
private static Map<String, String> getBizParams() {
Map<String, String> params = new HashMap<>();
params.put("amount", "1.00");
params.put("currency", "USD");
params.put("payment_method", "checkout");
params.put("order_id", "ts"+System.currentTimeMillis());
params.put("client_ip", "127.0.0.1");
params.put("callback_url", "https://same.website.com/pay/notify/mch");
params.put("return_url", "https://same.website.com/pay/notify/mch");
params.put("product_name", "GoodGame");
return params;
}
public static void create(Map<String, String> params) {
try {
String requestUrl = BASE_URL + "/v1/orders/checkout";
String response = doRequest(requestUrl, APP_ID, MERCHANT_KEY, "POST", params);
System.out.println(response);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void query(String orderNo) {
try {
String requestUrl = BASE_URL + "/v1/orders/" + orderNo;
String response = doRequest(requestUrl, APP_ID, MERCHANT_KEY, "GET", null);
System.out.println(response);
} catch (Exception e) {
e.printStackTrace();
}
}
public static String doRequest(String requestUrl, String clientId, String mchKey, String httpMethod, Map<String, String> params) {
String response = null;
try {
String timestamp = System.currentTimeMillis() + "";
// String timestamp = "654321";
String signature = generateApiSignature(mchKey,
httpMethod,
timestamp,
clientId, params);
Map<String, String> headers = new HashMap<>();
headers.put("X-Client-ID", clientId);
headers.put("X-Timestamp", timestamp);
headers.put("X-Signature", signature);
System.out.println("signature:" + signature);
response = sendRequest(httpMethod, requestUrl, params, headers);
} catch (Exception e) {
e.printStackTrace();
}
return response;
}
private static void callback(){
String requestUrl = "http://localhost:8001";
// String mchKey = "HCVGWclr9qZc315pO1p2sAszJ3=";
String mchKey = "MDEyMzQ1Njc4OQ==";
String timestamp = System.currentTimeMillis() + "";
String requestBody = "{\"data\":{\"transaction_id\":\"W17465264771601854\",\"amount\":\"130.00\",\"payment_status\":\"captured\",\"currency\":\"USD\",\"order_id\":\"01JTJHE6E7SSZF36DQ8J7G0N58\"},\"event\":\"PAYMENT.CAPTURE.COMPLETED\"}";
String baseString = timestamp + "&" + requestBody;
String signature = ApiSignatureGenerator.generateApiSignature(mchKey, baseString);
// System.out.println("signature:" + signature);
HttpRequest post = HttpUtil.createPost(requestUrl)
.header("X-Timestamp", timestamp)
.header("X-Signature", signature)
.body(requestBody);
HttpResponse response = post.execute();
String res = response.body();
System.out.println("response:\n" +res);
// if (StringUtil.isNotBlank(res)) {
// String aaa = ApiSignatureGenerator.generateApiSignature(res, mchKey);
// System.out.println(aaa);
// System.out.println(signature);
// }
}
public static String sendRequest(String method, String url,
Map<String, String> params,
Map<String, String> headers) throws IOException {
String response = null;
HttpURLConnection connection = null;
try {
URL requestUrl = new URL(url);
connection = (HttpURLConnection) requestUrl.openConnection();
connection.setRequestMethod(method);
// connection.setRequestMethod("POST");
// connection.setRequestProperty("Content-Type", "application/json");
// connection.setRequestProperty("Accept", "application/json");
connection.setConnectTimeout(10000);
connection.setReadTimeout(10000);
if (headers != null) {
for (Map.Entry<String, String> header : headers.entrySet()) {
connection.setRequestProperty(header.getKey(), header.getValue());
}
}
if (!"GET".equalsIgnoreCase(method) && params != null && !params.isEmpty()) {
connection.setDoOutput(true);
try (OutputStream os = connection.getOutputStream()) {
byte[] postData = buildFormData(params).getBytes(StandardCharsets.UTF_8);
os.write(postData);
os.flush();
// JSON
// byte[] input = JSON.toJSONString(params).getBytes(StandardCharsets.UTF_8);
// os.write(input, 0, input.length);
}
}
int responseCode = connection.getResponseCode();
try {
InputStream es = null;
try {
es = connection.getInputStream();
} catch (Exception e) {
// e.printStackTrace();
}
if (es == null) {
try {
es = connection.getErrorStream();
} catch (Exception e) {
// e.printStackTrace();
}
}
if (es != null) {
BufferedReader reader = new BufferedReader(new InputStreamReader(es, StandardCharsets.UTF_8));
response = reader.lines().collect(Collectors.joining("\n"));
}
} catch (Exception e) {
e.printStackTrace();
}
} finally {
if (connection != null) {
connection.disconnect();
}
}
return response;
}
private static String buildFormData(Map<String, String> params) throws UnsupportedEncodingException {
return params.entrySet().stream()
.map(e -> {
try {
return URLEncoder.encode(e.getKey(), "UTF-8") + "=" +
URLEncoder.encode(e.getValue(), "UTF-8");
} catch (UnsupportedEncodingException ex) {
throw new RuntimeException(ex);
}
})
.collect(Collectors.joining("&"));
}
public static String generateApiSignature(
String apiSecret,
String httpMethod,
String timestamp,
String merchantId, Map<String, String> params) throws SecurityException {
try {
// 1. Construct the base string
String sortedParams = sortParams(params);
String baseString = String.format("%s\n%s\n%s\n%s",
httpMethod,
timestamp,
merchantId,
sortedParams);
System.out.println("baseString:\n"+baseString);
// 2. Calculate HMAC-SHA256
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec(
apiSecret.getBytes(StandardCharsets.UTF_8),
"HmacSHA256");
sha256_HMAC.init(secretKey);
byte[] hashBytes = sha256_HMAC.doFinal(baseString.getBytes(StandardCharsets.UTF_8));
// 3. Return hexadecimal result
return bytesToHex(hashBytes);
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
e.printStackTrace();
}
return null;
}
public static String sortParams(Map<String, String> params) {
StringBuilder sb = new StringBuilder();
if (null != params && !params.isEmpty()) {
List<String> keys = new ArrayList<>(params.keySet());
Collections.sort(keys);
for (String key : keys) {
sb.append(key).append("=").append(params.get(key)).append("&");
}
sb.deleteCharAt(sb.length() - 1);
}
return sb.toString();
}
private static String bytesToHex(byte[] bytes) {
StringBuilder result = new StringBuilder();
for (byte b : bytes) {
result.append(String.format("%02x", b));
}
return result.toString();
}
}

View File

@ -0,0 +1,56 @@
package cc.uling.pay.gateway.interceptor;
import cc.uling.common.utils.DateUtils;
import cc.uling.common.utils.HttpUtils;
import cc.uling.common.utils.ThreadContext;
import cc.uling.pay.gateway.GatewayException;
import cc.uling.pay.gateway.controller.AbController;
import com.jfinal.aop.Interceptor;
import com.jfinal.aop.Invocation;
import io.jboot.components.valid.ValidException;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.http.HttpServletRequest;
import javax.validation.ValidationException;
@Slf4j
public class GatewayExceptionInterceptor implements Interceptor {
@Override
public void intercept(Invocation inv) {
long startTime = System.currentTimeMillis();
ThreadContext.set("lang", "en");
AbController controller = (AbController) inv.getController();
try {
print(inv.getActionKey(), controller.getRequest());
inv.invoke();
} catch (ValidException | ValidationException e) {
e.printStackTrace();
String msg = e.getMessage();
// checkValidException(inv, msg);
} catch (GatewayException e) {
log.info("{}业务执行错误!{}", inv.getMethodName(), e.getMessage());
controller.renderFail(e);
} catch (RuntimeException e) {
String msg = e.getMessage();
log.info("Raw\n|{}|\n", inv.getController().getRawData());
log.info("{}/{}()运行错误!{}", inv.getController().getClass().getCanonicalName(), inv.getMethodName(), msg);
e.printStackTrace();
controller.renderFail(GatewayException.SYSTEM_ERROR);
} catch (Exception e) {
log.info("{}/{}()执行错误!{}", inv.getController().getClass().getCanonicalName(), inv.getMethodName(), e.getMessage());
e.printStackTrace();
controller.renderFail(GatewayException.SYSTEM_ERROR);
} finally {
long endTime = System.currentTimeMillis();
log.info("{}|{}|cost|{}", inv.getController().getClass().getCanonicalName(), inv.getMethodName(), DateUtils.formatTime(endTime - startTime));
}
}
protected void print(String tag, HttpServletRequest request) {
log.warn("{}\n{}", tag, null != request ? HttpUtils.getRequestInfo(request) : "");
}
}

View File

@ -0,0 +1,60 @@
package cc.uling.pay.gateway.interceptor;
import cc.uling.common.constant.ResponseCode;
import cc.uling.pay.gateway.ApiSignatureGenerator;
import cc.uling.pay.gateway.ErrorCode;
import cc.uling.pay.gateway.GatewayException;
import cc.uling.pay.gateway.constants.ApiConst;
import cc.uling.pay.gateway.controller.AbController;
import cc.uling.pay.gateway.manager.DataManager;
import com.jfinal.aop.Aop;
import com.jfinal.aop.Interceptor;
import com.jfinal.aop.Invocation;
import com.web.gen.model.MchInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
@Slf4j
public class SHA256SignInterceptor implements Interceptor {
@Override
public void intercept(Invocation invocation) {
AbController controller = (AbController) invocation.getController();
HttpServletRequest request = controller.getRequest();
String clientId = request.getHeader(ApiConst.XClientID);
String timestamp = request.getHeader(ApiConst.XTimestamp);
String signature = request.getHeader(ApiConst.XSignature);
if (StringUtils.isEmpty(clientId)) {
throw GatewayException.MissingParam(ApiConst.XClientID);
}
if (StringUtils.isEmpty(timestamp)) {
throw GatewayException.MissingParam(ApiConst.XTimestamp);
}
if (StringUtils.isEmpty(signature)) {
throw GatewayException.MissingParam(ApiConst.XSignature);
}
String method = request.getMethod().toUpperCase();
Map<String, String> params = controller.getParams();
MchInfo mchInfo = Aop.get(DataManager.class).findMchInfoByAppId(clientId);
String sysSign = ApiSignatureGenerator.generateApiSignature(mchInfo.getSecretKey(), method, timestamp, clientId, params);
if (!signature.equals(sysSign)) {
String body = controller.getRawData();
if (params.isEmpty() && StringUtils.isNotEmpty(body)) {
log.warn("body|" + body);
throw new GatewayException(ResponseCode.UNPROCESSABLE, ErrorCode.SIGN_ERROR, "request.params.post.error");
}
log.warn("error|" + sysSign + "!=" + signature);
throw GatewayException.SIGN_ERROR;
}
request.setAttribute(ApiConst.XClientID, mchInfo);
invocation.invoke();
}
}

View File

@ -0,0 +1,34 @@
package cc.uling.pay.gateway.manager;
import cc.uling.common.utils.StringUtil;
import cc.uling.pay.gateway.GatewayException;
import com.jfinal.aop.Aop;
import com.web.gen.model.MchInfo;
import com.web.gen.service.MchInfoService;
import com.web.gen.service.SysConfigService;
import io.jboot.aop.annotation.Bean;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Bean
public class DataManager {
public MchInfo findMchInfoByAppId(String appId) {
MchInfo mchInfo = Aop.get(MchInfoService.class).findByAppId(appId);
if (mchInfo == null) {
throw GatewayException.UNAUTHORIZED;
}
return mchInfo;
}
public String getApiServer(String mode) {
String host = Aop.get(SysConfigService.class).getPayGatewayHost();
if (StringUtil.isBlank(host)) {
log.warn("| has not set " + mode + " pay gateway host!");
throw GatewayException.SYSTEM_ERROR;
}
return host;
}
}

View File

@ -0,0 +1,105 @@
package cc.uling.pay.gateway.protocol;
import cc.uling.common.constant.ResponseCode;
import cc.uling.common.enums.YesOrNo;
import cc.uling.common.utils.StringUtil;
import cc.uling.pay.gateway.*;
import cc.uling.pay.gateway.constants.ApiConst;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.web.gen.model.PayOrder;
import lombok.extern.slf4j.Slf4j;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.HashMap;
import java.util.Map;
@Slf4j
public class Converter {
public static OrderInfoRes getOrderDetails(String json, CreatePayOrderRQ bizRQ) {
OrderInfoRes res = new OrderInfoRes();
try {
JSONObject jsonObject = JSON.parseObject(json);
int code = jsonObject.getIntValue("code");
if (code == ResponseCode.SUCCESS) {
res.setStatus(ApiConst.success);
JSONObject dataObject = jsonObject.getJSONObject("data");
if (dataObject != null) {
res.setOrder_id(dataObject.getString("merOrderNo"));
res.setTransaction_id(dataObject.getString("payOrderId"));
res.setAmount(bizRQ.getAmount());
res.setCurrency(bizRQ.getCurrency());
res.setPayment_details(dataObject.getString("message"));
res.setPayment_status(Convert.getPaymentStatus(dataObject.getIntValue("state")));
Map<String, String> actionMap = new HashMap<String, String>();
if (dataObject.getIntValue("payType") == YesOrNo.YES && !StringUtil.isEmpty(dataObject.getString("payUrl"))) {
actionMap.put("type", "redirect");
actionMap.put("url", dataObject.getString("payUrl"));
} else {
actionMap.put("type", "none");
}
res.setNext_action(actionMap);
}
} else {
if (code == ResponseCode.ERROR) {
code = ResponseCode.UNPROCESSABLE;
}
GatewayException exception = new GatewayException(code, getErrorCode(code));
exception.setErrorMsg(jsonObject.getString("msg"));
throw exception;
}
} catch (GatewayException e) {
log.info("here is the GatewayException|" + e.getMessage());
e.printStackTrace();
throw e;
} catch (Exception e) {
log.info("here is the exception|" + e.getMessage());
e.printStackTrace();
throw GatewayException.SYSTEM_ERROR;
}
return res;
}
public static OrderInfoRes getOrderDetails(PayOrder order) {
OrderInfoRes res = new OrderInfoRes();
try {
res.setOrder_id(order.getMchOrderNo());
res.setTransaction_id(order.getPayOrderId());
res.setCurrency(order.getCurrency());
res.setAmount(new BigDecimal(order.getAmount()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP));
res.setRefunds(null);
res.setRefunded_amount(null);
res.setPayment_status(Convert.getPaymentStatus(order.getStatus()));
res.setPayment_details(order.getErrMsg());
} catch (GatewayException e) {
e.printStackTrace();
throw e;
} catch (Exception e) {
e.printStackTrace();
throw GatewayException.SYSTEM_ERROR;
}
return res;
}
public static String getErrorCode(int code) {
if (code == ResponseCode.BAD_REQUEST) {
return ErrorCode.INVALID_REQUEST;
} else if (code == ResponseCode.SYSTEM_ERROR) {
return ErrorCode.SYSTEM_ERROR;
} else if (code == ResponseCode.UNAUTHORIZED) {
return ErrorCode.AUTHENTICATION_FAILURE;
} else if (code == ResponseCode.FORBIDDEN) {
return ErrorCode.NOT_AUTHORIZED;
} else if (code == ResponseCode.NOT_FOUND) {
return ErrorCode.RESOURCE_NOT_FOUND;
} else if (code == ResponseCode.ERROR) {
return ErrorCode.UNPROCESSABLE;
}
return ApiConst.error;
}
}

View File

@ -0,0 +1,8 @@
package cc.uling.pay.gateway.timer;
public class LogTimer implements Runnable{
@Override
public void run() {
}
}

View File

@ -0,0 +1,4 @@
package cc.uling.pay.gateway.utils;
public class ApiHelper {
}

View File

@ -0,0 +1,33 @@
package cc.uling.pay.gateway.utils;
import org.apache.commons.lang3.StringUtils;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class SignUtil {
public static String getBaseString(String method, String timestamp, String clientId) {
return MessageFormat.format("{0}\n{1}\n{2}", method, timestamp, clientId);
}
public static String sortParams(Map<String, String> params) {
StringBuilder sb = new StringBuilder();
if (null != params) {
List<String> keys = new ArrayList<>(params.keySet());
Collections.sort(keys);
for (String key : keys) {
sb.append(key).append("=").append(params.get(key)).append("&");
}
sb.deleteCharAt(sb.length() - 1);
}
return sb.toString();
}
}

View File

@ -0,0 +1 @@
YCGateway

View File

@ -0,0 +1,14 @@
request.bad=Request is not well-formed, syntactically incorrect, or violates schema.
request.forbidden=Authorization failed due to insufficient permissions.
request.unauthorized=Client authentication failed.
request.failed=failed
request.succeeded=succeeded
request.res.not_exist=The specified resource does not exist.
request.system.error=Internal server error has occurred.
request.sign.error=Signature verification failed.
#
request.param.missing={0} is missing.
request.param.invalid={0} is invalid.
#
request.fail.exists.order_id=Order [{0}] already exists.
request.params.post.error=Please pass parameters as a form instead of a body

View File

@ -0,0 +1,13 @@
# Product DB
jboot.datasource.prod.type=mysql
jboot.datasource.prod.url=jdbc:mysql://61.171.32.114:3306/yc_system_db?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false
jboot.datasource.prod.user=root
jboot.datasource.prod.password=MyNewPass4!
# SandBox
jboot.datasource.sandbox.type=mysql
jboot.datasource.sandbox.url=jdbc:mysql://localhost:3306/yc_system_sandbox_db?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false
jboot.datasource.sandbox.user=root
jboot.datasource.sandbox.password=123456
jboot.datasource.sandbox.table=yc_pay_order

View File

@ -0,0 +1,13 @@
# Product DB
jboot.datasource.prod.type=mysql
jboot.datasource.prod.url=jdbc:mysql://61.171.32.114:3306/yc_system_db?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false
jboot.datasource.prod.user=root
jboot.datasource.prod.password=MyNewPass4!
# SandBox
jboot.datasource.sandbox.type=mysql
jboot.datasource.sandbox.url=jdbc:mysql://localhost:3306/yc_system_sandbox_db?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false
jboot.datasource.sandbox.user=root
jboot.datasource.sandbox.password=123456
jboot.datasource.sandbox.table=yc_pay_order

View File

@ -0,0 +1,9 @@
#jboot dev,test,product
jboot.app.mode=dev
jboot.app.name=YCGateway
jboot.app.version=1.0.0
#
jboot.model.idCacheEnable = false
#undertow
undertow.port=8094
undertow.host=0.0.0.0

View File

@ -0,0 +1,183 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!-- 级别从高到低 OFF 、 FATAL 、 ERROR 、 WARN 、 INFO 、 DEBUG 、 TRACE 、 ALL -->
<!-- 日志输出规则 根据当前ROOT 级别日志输出时级别高于root默认的级别时 会输出 -->
<!-- 以下 每个配置的 filter 是过滤掉输出文件里面会出现高级别文件依然出现低级别的日志信息通过filter 过滤只记录本级别的日志 -->
<!-- scan 当此属性设置为true时配置文件如果发生改变将会被重新加载默认值为true。 -->
<!-- scanPeriod 设置监测配置文件是否有修改的时间间隔如果没有给出时间单位默认单位是毫秒。当scan为true时此属性生效。默认的时间间隔为1分钟。 -->
<!-- debug 当此属性设置为true时将打印出logback内部日志信息实时查看logback运行状态。默认值为false。 -->
<configuration scan="true" scanPeriod="60 seconds"
debug="false">
<!-- 动态日志级别 -->
<jmxConfigurator />
<!-- 定义日志文件 输出位置 -->
<property name="log_dir" value="logs" />
<!-- 日志最大的历史 30天 -->
<property name="maxHistory" value="30" />
<!-- ConsoleAppender 控制台输出日志 -->
<appender name="console"
class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<!-- 设置日志输出格式 -->
<pattern>
%d{yyyy-MM-dd HH:mm:ss.SSS} [%level] [%logger{25}:%L] - %msg%n
</pattern>
</encoder>
</appender>
<!-- ERROR级别日志 -->
<!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 RollingFileAppender -->
<appender name="ERROR"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 过滤器只记录WARN级别的日志 -->
<!-- 果日志级别等于配置级别过滤器会根据onMath 和 onMismatch接收或拒绝日志。 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 设置过滤级别 -->
<level>ERROR</level>
<!-- 用于配置符合过滤条件的操作 -->
<onMatch>ACCEPT</onMatch>
<!-- 用于配置不符合过滤条件的操作 -->
<onMismatch>DENY</onMismatch>
</filter>
<!-- 最常用的滚动策略,它根据时间来制定滚动策略.既负责滚动也负责出发滚动 -->
<rollingPolicy
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志输出位置 可相对、和绝对路径 -->
<fileNamePattern>
${log_dir}/error/%d{yyyy-MM-dd}/logs.log
</fileNamePattern>
<!-- 可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件假设设置每个月滚动,且<maxHistory>是6 则只保存最近6个月的文件删除之前的旧文件。注意删除旧文件是那些为了归档而创建的目录也会被删除 -->
<maxHistory>${maxHistory}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>
<!-- 设置日志输出格式 -->
%d{yyyy-MM-dd HH:mm:ss} [%-5level] %logger - %msg%n
</pattern>
</encoder>
</appender>
<!-- WARN级别日志 appender -->
<appender name="WARN"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 过滤器只记录WARN级别的日志 -->
<!-- 果日志级别等于配置级别过滤器会根据onMath 和 onMismatch接收或拒绝日志。 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 设置过滤级别 -->
<level>WARN</level>
<!-- 用于配置符合过滤条件的操作 -->
<onMatch>ACCEPT</onMatch>
<!-- 用于配置不符合过滤条件的操作 -->
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志输出位置 可相对、和绝对路径 -->
<fileNamePattern>${log_dir}/warn/%d{yyyy-MM-dd}/logs.log
</fileNamePattern>
<maxHistory>${maxHistory}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%-5level] %logger - %msg%n
</pattern>
</encoder>
</appender>
<!-- INFO级别日志 appender -->
<appender name="INFO"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log_dir}/info/%d{yyyy-MM-dd}/logs.log
</fileNamePattern>
<maxHistory>${maxHistory}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%-5level] %logger - %msg%n
</pattern>
</encoder>
</appender>
<!-- DEBUG级别日志 appender -->
<appender name="DEBUG"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log_dir}/debug/%d{yyyy-MM-dd}/logs.log
</fileNamePattern>
<maxHistory>${maxHistory}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%-5level] %logger - %msg%n
</pattern>
</encoder>
</appender>
<!-- TRACE级别日志 appender -->
<appender name="TRACE"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>TRACE</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log_dir}/trace/%d{yyyy-MM-dd}/logs.log
</fileNamePattern>
<maxHistory>${maxHistory}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%-5level] %logger - %msg%n
</pattern>
</encoder>
</appender>
<!-- 按包名区分日志级别 -->
<logger name="org.jboss" level="WARN" />
<logger name="org.xnio" level="ERROR" />
<logger name="io.undertow" level="ERROR" />
<logger name="com.zaxxer" level="ERROR" />
<logger name="io.swagger" level="ERROR" />
<logger name="org.hibernate.validator" level="WARN" />
<logger name="org.redisson" level="WARN" />
<logger name="org.apache.zookeeper" level="WARN" />
<logger name="io.netty" level="WARN" />
<logger name="org.quartz" level="ERROR" />
<!--控制台日志 -->
<root level="debug">
<appender-ref ref="console" />
</root>
<!-- root级别 DEBUG -->
<root>
<!-- 打印debug级别日志及以上级别日志 -->
<level value="DEBUG" />
<!-- 控制台输出 -->
<appender-ref ref="console" />
<!-- 文件输出 -->
<appender-ref ref="ERROR" />
<appender-ref ref="INFO" />
<appender-ref ref="WARN" />
<appender-ref ref="DEBUG" />
<appender-ref ref="TRACE" />
</root>
</configuration>

View File

@ -0,0 +1,21 @@
#\u5F00\u542F\u7684\u4EFB\u52A1\u5217\u8868\u201C,\u201D\u9694\u5F00
cron4j=log
log.cron=* * * * *
log.class=cc.uling.pay.gateway.timer.LogTimer
log.desc=\u65E5\u5FD7\u8F93\u51FA
log.enable=true
#
#
#
# cron \u8868\u8FBE\u5F0F\u7531\u4E94\u90E8\u5206\u7EC4\u6210\uFF1A\u5206 \u65F6 \u5929 \u6708 \u5468
# \u5206 \uFF1A\u4ECE 0 \u5230 59
# \u65F6 \uFF1A\u4ECE 0 \u5230 23
# \u5929 \uFF1A\u4ECE 1 \u5230 31\uFF0C\u5B57\u6BCD L \u53EF\u4EE5\u8868\u793A\u6708\u7684\u6700\u540E\u4E00\u5929
# \u6708 \uFF1A\u4ECE 1 \u5230 12\uFF0C\u53EF\u4EE5\u522B\u540D\uFF1Ajan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov" and "dec"
# \u5468 \uFF1A\u4ECE 0 \u5230 6\uFF0C0 \u8868\u793A\u5468\u65E5\uFF0C6 \u8868\u793A\u5468\u516D\uFF0C\u53EF\u4EE5\u4F7F\u7528\u522B\u540D\uFF1A "sun", "mon", "tue", "wed", "thu", "fri" and "sat"
# \u6570\u5B57 n\uFF1A\u8868\u793A\u4E00\u4E2A\u5177\u4F53\u7684\u65F6\u95F4\u70B9\uFF0C\u4F8B\u5982 5 * * * * \u8868\u793A 5 \u5206\u8FD9\u4E2A\u65F6\u95F4\u70B9\u65F6\u6267\u884C
# \u9017\u53F7 , \uFF1A\u8868\u793A\u6307\u5B9A\u591A\u4E2A\u6570\u503C\uFF0C\u4F8B\u5982 3,5 * * * * \u8868\u793A 3 \u548C 5 \u5206\u8FD9\u4E24\u4E2A\u65F6\u95F4\u70B9\u6267\u884C
# \u51CF\u53F7 -\uFF1A\u8868\u793A\u8303\u56F4\uFF0C\u4F8B\u5982 1-3 * * * * \u8868\u793A 1 \u5206\u30012 \u5206\u518D\u5230 3 \u5206\u8FD9\u4E09\u4E2A\u65F6\u95F4\u70B9\u6267\u884C
# \u661F\u53F7 *\uFF1A\u8868\u793A\u6BCF\u4E00\u4E2A\u65F6\u95F4\u70B9\uFF0C\u4F8B\u5982 * * * * * \u8868\u793A\u6BCF\u5206\u949F\u6267\u884C\uFF0C*/2 * * * * \u8868\u793A 2 \u5206\u949F\u6267\u884C\u4E00\u6B21
# \u9664\u53F7 /\uFF1A\u8868\u793A\u6307\u5B9A\u4E00\u4E2A\u503C\u7684\u589E\u52A0\u5E45\u5EA6\u3002\u4F8B\u5982 n/m\u8868\u793A\u4ECE n \u5F00\u59CB\uFF0C\u6BCF\u6B21\u589E\u52A0 m \u7684\u65F6\u95F4\u70B9\u6267\u884C

View File

@ -0,0 +1,7 @@
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
</web-app>

View File

@ -0,0 +1,5 @@
<html>
<body>
<h2>Hello World!</h2>
</body>
</html>

45
uling-gateway/start.sh Normal file
View File

@ -0,0 +1,45 @@
#!/bin/bash
MAIN_CLASS=cc.uling.pay.gateway.YCGatewayApplication
COMMAND="$1"
if [[ "$COMMAND" != "start" ]] && [[ "$COMMAND" != "stop" ]] && [[ "$COMMAND" != "restart" ]]; then
COMMAND="restart"
fi
# 生成 class path 值
APP_BASE_PATH=$(cd `dirname $0`; pwd)
CP=${APP_BASE_PATH}/config:${APP_BASE_PATH}/lib/*
function start()
{
# 运行为后台进程,并在控制台输出信息
# java -Djava.awt.headless=true -Xverify:none ${JAVA_OPTS} -cp ${CP} ${MAIN_CLASS} &
# 运行为后台进程,并且不在控制台输出信息
# nohup java -Djava.awt.headless=true -Xverify:none ${JAVA_OPTS} -cp ${CP} ${MAIN_CLASS} >/dev/null 2>&1 &
# 运行为后台进程,并且将信息输出到 output.log 文件
nohup java -Djava.awt.headless=true -Xverify:none ${JAVA_OPTS} -cp ${CP} ${MAIN_CLASS} >> output.log 2>&1 &
#tail -f /dev/null
# 运行为非后台进程,多用于开发阶段,快捷键 ctrl + c 可停止服务
# 当以此方式在Docker下启动时由于是后台进程无前台进程Docker容器启动后会马上退出
# 需加命令tail -f /dev/null就可以保持你的容器一直在前台运行
# 或者使用以下的非后台进程运行
# java -Djava.awt.headless=true -Xverify:none ${JAVA_OPTS} -cp ${CP} ${MAIN_CLASS}
}
function stop()
{
kill `pgrep -f ${APP_BASE_PATH}` 2>/dev/null
}
if [[ "$COMMAND" == "start" ]]; then
start
elif [[ "$COMMAND" == "stop" ]]; then
stop
else
stop
start
fi

View File

@ -0,0 +1,151 @@
<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/webapp" type="java-resource" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="uling-system" />
<orderEntry type="module" module-name="uling-framework" />
<orderEntry type="library" name="Maven: cn.hutool:hutool-jwt:5.8.27" level="project" />
<orderEntry type="library" name="Maven: cn.hutool:hutool-json:5.8.27" level="project" />
<orderEntry type="library" name="Maven: cn.hutool:hutool-core:5.8.27" level="project" />
<orderEntry type="library" name="Maven: cn.hutool:hutool-crypto:5.8.27" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-text:1.10.0" level="project" />
<orderEntry type="library" name="Maven: org.quartz-scheduler:quartz:2.3.2" level="project" />
<orderEntry type="library" name="Maven: com.mchange:mchange-commons-java:0.2.15" level="project" />
<orderEntry type="library" name="Maven: com.zaxxer:HikariCP-java7:2.4.13" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.5" level="project" />
<orderEntry type="library" name="Maven: cloud.tianai.captcha:tianai-captcha:1.5.1" level="project" />
<orderEntry type="library" name="Maven: io.swagger:swagger-core:1.5.21" level="project" />
<orderEntry type="library" name="Maven: io.swagger:swagger-models:1.5.21" level="project" />
<orderEntry type="library" name="Maven: io.swagger:swagger-annotations:1.5.21" level="project" />
<orderEntry type="module" module-name="uling-yc-service" />
<orderEntry type="module" module-name="uling-common" />
<orderEntry type="library" name="Maven: com.github.oshi:oshi-core:6.5.0" level="project" />
<orderEntry type="library" name="Maven: net.java.dev.jna:jna:5.14.0" level="project" />
<orderEntry type="library" name="Maven: net.java.dev.jna:jna-platform:5.14.0" level="project" />
<orderEntry type="library" name="Maven: com.google.zxing:javase:3.3.0" level="project" />
<orderEntry type="library" name="Maven: com.google.zxing:core:3.3.0" level="project" />
<orderEntry type="library" name="Maven: com.beust:jcommander:1.48" level="project" />
<orderEntry type="library" name="Maven: com.github.jai-imageio:jai-imageio-core:1.3.1" level="project" />
<orderEntry type="library" name="Maven: org.redisson:redisson:3.12.3" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-common:4.1.45.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-codec:4.1.45.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-buffer:4.1.45.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-transport:4.1.45.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-resolver:4.1.45.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-resolver-dns:4.1.45.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-codec-dns:4.1.45.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-handler:4.1.45.Final" level="project" />
<orderEntry type="library" name="Maven: javax.cache:cache-api:1.0.0" level="project" />
<orderEntry type="library" name="Maven: io.projectreactor:reactor-core:3.3.2.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.reactivestreams:reactive-streams:1.0.3" level="project" />
<orderEntry type="library" name="Maven: io.reactivex.rxjava2:rxjava:2.2.17" level="project" />
<orderEntry type="library" name="Maven: net.bytebuddy:byte-buddy:1.10.7" level="project" />
<orderEntry type="library" name="Maven: org.jodd:jodd-bean:5.0.13" level="project" />
<orderEntry type="library" name="Maven: org.jodd:jodd-core:5.0.13" level="project" />
<orderEntry type="library" name="Maven: com.sun.mail:javax.mail:1.6.2" level="project" />
<orderEntry type="library" name="Maven: javax.activation:activation:1.1" level="project" />
<orderEntry type="library" name="Maven: commons-beanutils:commons-beanutils:1.9.4" level="project" />
<orderEntry type="library" name="Maven: commons-collections:commons-collections:3.2.2" level="project" />
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpcore:4.4.6" level="project" />
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpmime:4.3.3" level="project" />
<orderEntry type="library" name="Maven: org.apache.httpcomponents:fluent-hc:4.5.2" level="project" />
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpclient:4.5.2" level="project" />
<orderEntry type="library" name="Maven: commons-httpclient:commons-httpclient:3.0.1" level="project" />
<orderEntry type="library" name="Maven: junit:junit:3.8.1" level="project" />
<orderEntry type="library" name="Maven: com.alibaba:easyexcel:4.0.3" level="project" />
<orderEntry type="library" name="Maven: com.alibaba:easyexcel-core:4.0.3" level="project" />
<orderEntry type="library" name="Maven: com.alibaba:easyexcel-support:3.3.4" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-csv:1.11.0" level="project" />
<orderEntry type="library" name="Maven: org.ehcache:ehcache:3.9.11" level="project" />
<orderEntry type="library" name="Maven: org.apache.poi:poi-ooxml:5.2.3" level="project" />
<orderEntry type="library" name="Maven: org.apache.poi:poi:5.2.3" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-math3:3.6.1" level="project" />
<orderEntry type="library" name="Maven: com.zaxxer:SparseBitSet:1.2" level="project" />
<orderEntry type="library" name="Maven: org.apache.poi:poi-ooxml-lite:5.2.3" level="project" />
<orderEntry type="library" name="Maven: org.apache.xmlbeans:xmlbeans:5.1.1" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-compress:1.21" level="project" />
<orderEntry type="library" name="Maven: com.github.virtuald:curvesapi:1.07" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-collections4:4.4" level="project" />
<orderEntry type="module" module-name="uling-components" />
<orderEntry type="library" name="Maven: com.rabbitmq:amqp-client:5.11.0" level="project" />
<orderEntry type="module" module-name="uling-api-demo" />
<orderEntry type="library" name="Maven: io.jboot:jboot:3.15.7" level="project" />
<orderEntry type="library" name="Maven: com.jfinal:jfinal:5.0.1" level="project" />
<orderEntry type="library" name="Maven: com.jfinal:cos:2022.2" level="project" />
<orderEntry type="library" name="Maven: com.jfinal:jfinal-undertow:3.1" level="project" />
<orderEntry type="library" name="Maven: io.undertow:undertow-core:2.2.18.Final" level="project" />
<orderEntry type="library" name="Maven: org.jboss.xnio:xnio-api:3.8.7.Final" level="project" />
<orderEntry type="library" name="Maven: org.wildfly.common:wildfly-common:1.5.4.Final" level="project" />
<orderEntry type="library" name="Maven: org.wildfly.client:wildfly-client-config:1.0.1.Final" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: org.jboss.xnio:xnio-nio:3.8.7.Final" level="project" />
<orderEntry type="library" name="Maven: org.jboss.threads:jboss-threads:3.1.0.Final" level="project" />
<orderEntry type="library" name="Maven: io.undertow:undertow-servlet:2.2.18.Final" level="project" />
<orderEntry type="library" name="Maven: javax.servlet:javax.servlet-api:4.0.1" level="project" />
<orderEntry type="library" name="Maven: cglib:cglib:3.3.0" level="project" />
<orderEntry type="library" name="Maven: org.ow2.asm:asm:7.1" level="project" />
<orderEntry type="library" name="Maven: io.undertow:undertow-websockets-jsr:2.2.18.Final" level="project" />
<orderEntry type="library" name="Maven: org.jboss.spec.javax.websocket:jboss-websocket-api_1.1_spec:2.0.0.Final" level="project" />
<orderEntry type="library" name="Maven: com.zaxxer:HikariCP:4.0.3" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-core:2.13.3" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.13.3" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.13.3" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.13.3" level="project" />
<orderEntry type="library" name="Maven: org.yaml:snakeyaml:1.30" level="project" />
<orderEntry type="library" name="Maven: mysql:mysql-connector-java:5.1.49" level="project" />
<orderEntry type="library" name="Maven: de.ruedigermoeller:fst:2.57" level="project" />
<orderEntry type="library" name="Maven: org.objenesis:objenesis:2.5.1" level="project" />
<orderEntry type="library" name="Maven: org.javassist:javassist:3.29.0-GA" level="project" />
<orderEntry type="library" name="Maven: com.alibaba:fastjson:1.2.83" level="project" />
<orderEntry type="library" name="Maven: com.google.guava:guava:31.1-jre" level="project" />
<orderEntry type="library" name="Maven: com.google.guava:failureaccess:1.0.1" level="project" />
<orderEntry type="library" name="Maven: com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava" level="project" />
<orderEntry type="library" name="Maven: com.google.code.findbugs:jsr305:3.0.2" level="project" />
<orderEntry type="library" name="Maven: org.checkerframework:checker-qual:3.12.0" level="project" />
<orderEntry type="library" name="Maven: com.google.errorprone:error_prone_annotations:2.11.0" level="project" />
<orderEntry type="library" name="Maven: com.google.j2objc:j2objc-annotations:1.3" level="project" />
<orderEntry type="library" name="Maven: it.sauronsoftware.cron4j:cron4j:2.2.5" level="project" />
<orderEntry type="library" name="Maven: org.jsoup:jsoup:1.14.3" level="project" />
<orderEntry type="library" name="Maven: com.github.ben-manes.caffeine:caffeine:2.9.3" level="project" />
<orderEntry type="library" name="Maven: commons-io:commons-io:2.11.0" level="project" />
<orderEntry type="library" name="Maven: javax.annotation:javax.annotation-api:1.3.2" level="project" />
<orderEntry type="library" name="Maven: org.hibernate.validator:hibernate-validator:6.0.21.Final" level="project" />
<orderEntry type="library" name="Maven: org.jboss.logging:jboss-logging:3.3.2.Final" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml:classmate:1.3.4" level="project" />
<orderEntry type="library" name="Maven: org.glassfish:javax.el:3.0.0" level="project" />
<orderEntry type="library" name="Maven: io.dropwizard.metrics:metrics-core:4.2.9" level="project" />
<orderEntry type="library" name="Maven: io.dropwizard.metrics:metrics-servlets:4.2.9" level="project" />
<orderEntry type="library" name="Maven: io.dropwizard.metrics:metrics-json:4.2.9" level="project" />
<orderEntry type="library" name="Maven: com.helger:profiler:1.1.1" level="project" />
<orderEntry type="library" name="Maven: io.dropwizard.metrics:metrics-healthchecks:4.2.9" level="project" />
<orderEntry type="library" name="Maven: io.dropwizard.metrics:metrics-jvm:4.2.9" level="project" />
<orderEntry type="library" name="Maven: io.jsonwebtoken:jjwt:0.9.1" level="project" />
<orderEntry type="library" name="Maven: c3p0:c3p0:0.9.1.2" level="project" />
<orderEntry type="library" name="Maven: com.alibaba:druid:1.0.21" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-pool2:2.4.3" level="project" />
<orderEntry type="library" name="Maven: redis.clients:jedis:3.2.0" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: org.projectlombok:lombok:1.18.16" level="project" />
<orderEntry type="library" name="Maven: ch.qos.logback:logback-core:1.2.3" level="project" />
<orderEntry type="library" name="Maven: ch.qos.logback:logback-classic:1.2.3" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.30" level="project" />
<orderEntry type="library" name="Maven: log4j:log4j:1.2.17" level="project" />
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-core:2.23.1" level="project" />
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-api:2.23.1" level="project" />
<orderEntry type="library" name="Maven: javax.validation:validation-api:2.0.1.Final" level="project" />
<orderEntry type="library" name="Maven: commons-logging:commons-logging:1.2" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.6" level="project" />
<orderEntry type="library" name="Maven: commons-codec:commons-codec:1.10" level="project" />
<orderEntry type="library" name="Maven: cn.hutool:hutool-all:5.8.29" level="project" />
<orderEntry type="library" name="Maven: pro.fessional:kaptcha:2.3.3" level="project" />
<orderEntry type="library" name="Maven: com.jhlabs:filters:2.0.235-1" level="project" />
<orderEntry type="library" name="Maven: eu.bitwalker:UserAgentUtils:1.19" level="project" />
</component>
</module>