提交 da4b1bcc authored 作者: hzh's avatar hzh

代码优化

上级 69448f0f
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ruoyi-common-hotel-zggl</artifactId>
<description>
ruoyi-common-hotel-zgg 酒店-中国国旅对接模块
</description>
<dependencies>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-core</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.22</version>
</dependency>
</dependencies>
</project>
package org.dromara.common.hotel;
import cn.hutool.core.date.StopWatch;
import cn.hutool.http.ContentType;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.dromara.common.hotel.common.ApiHttpResponse;
import org.dromara.common.hotel.enums.ApiEnum;
import org.dromara.common.hotel.enums.Domain;
import org.dromara.common.hotel.enums.DomainEnum;
import org.dromara.common.hotel.base.HttpKit;
import org.dromara.common.hotel.base.PayKit;
import org.dromara.common.hotel.base.RequestMethodEnum;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
/**
* @author hzh
* @date 2024-10-15
* @desc api相关接口
**/
@Slf4j
public class Api {
/**
* 获取接口请求的 URL
*
* @param apiEnum {@link ApiEnum} API 接口枚举
* @return {@link String} 返回完整的接口请求URL
*/
public static String getReqUrl(ApiEnum apiEnum) {
return getReqUrl(apiEnum, null);
}
/**
* 获取接口请求的 URL
*
* @param apiEnum {@link ApiEnum} API 接口枚举
* @param domain {@link Domain} API 接口域名枚举
* @return {@link String} 返回完整的接口请求URL
*/
public static String getReqUrl(ApiEnum apiEnum, Domain domain) {
if (domain == null) {
domain = DomainEnum.TEST;
}
return domain.getDomain()
.concat(apiEnum.getUrl());
}
public static <T> T v1(RequestMethodEnum method, String urlPrefix, String urlSuffix,
String token,
String body,
Class<T> clazz) {
return v1(method, urlPrefix, urlSuffix, token, null, body, null, clazz);
}
public static <T> T v1(RequestMethodEnum method, String urlPrefix, String urlSuffix,
String token,
String body,
Map<String,Object> params,
Class<T> clazz) {
return v1(method, urlPrefix, urlSuffix, token, params, body, null, clazz);
}
public static ApiHttpResponse v1(RequestMethodEnum method, String urlPrefix, String urlSuffix,
String token,
String body) {
return v1(method, urlPrefix, urlSuffix, token, null, body, null, ApiHttpResponse.class);
}
public static ApiHttpResponse v1(RequestMethodEnum method, String urlPrefix, String urlSuffix,
String token,
Map<String, Object> params, String body) {
return v1(method, urlPrefix, urlSuffix, token, params, body, null, ApiHttpResponse.class);
}
/**
* v1 接口统一执行人口
*
* @param method {@link RequestMethodEnum} 请求方法
* @param urlPrefix 可通过 {@link Domain}来获取
* @param urlSuffix 可通过 {@link ApiEnum} 来获取,URL挂载参数需要自行拼接
* @param token token
* @param params Get 接口请求参数
* @param body 接口请求参数
* @param file 文件
* @return 请求返回的结果
*/
public static <T> T v1(RequestMethodEnum method, String urlPrefix, String urlSuffix,
String token,
Map<String, Object> params, String body, File file, Class<T> clazz) {
if (null != params && !params.keySet().isEmpty()) {
urlSuffix = urlSuffix.concat("?").concat(PayKit.createLinkString(params, true));
}
// 构建 Authorization
String authorization = token;
String bodyRes = null;
if (method == RequestMethodEnum.GET) {
bodyRes = get(urlPrefix.concat(urlSuffix), authorization, params);
} else if (method == RequestMethodEnum.POST) {
bodyRes = post(urlPrefix.concat(urlSuffix), authorization, body);
} else if (method == RequestMethodEnum.DELETE) {
bodyRes = delete(urlPrefix.concat(urlSuffix), authorization, body);
} else if (method == RequestMethodEnum.UPLOAD) {
bodyRes = upload(urlPrefix.concat(urlSuffix), authorization, body, file);
} else if (method == RequestMethodEnum.PATCH) {
bodyRes = patch(urlPrefix.concat(urlSuffix), authorization, body);
} else if (method == RequestMethodEnum.PUT) {
bodyRes = put(urlPrefix.concat(urlSuffix), authorization, body);
} else if (method == RequestMethodEnum.DOWNLOAD) {
bodyRes = download(urlPrefix.concat(urlSuffix), authorization, params);
}
if (clazz == String.class) {
return (T) bodyRes;
}
return JSON.parseObject(bodyRes, clazz);
}
/**
* put 请求
*
* @param url 请求url
* @param authorization 授权信息
* @param data 请求参数
* @return {@link ApiHttpResponse} 请求返回的结果
*/
public static String put(String url, String authorization, String data) {
return put(url, data, getHeaders(authorization));
}
/**
* put 请求
*
* @param url 请求url
* @param data 请求参数
* @param headers 请求头
* @return {@link ApiHttpResponse} 请求返回的结果
*/
public static String put(String url, String data, Map<String, String> headers) {
return HttpKit.getDelegate().put(url, data, headers);
}
/**
* patch 请求
*
* @param url 请求url
* @param authorization 授权信息
* @param data 请求参数
* @return {@link ApiHttpResponse} 请求返回的结果
*/
public static String patch(String url, String authorization, String data) {
return patch(url, data, getHeaders(authorization));
}
/**
* patch 请求
*
* @param url 请求url
* @param data 请求参数
* @param headers 请求头
* @return {@link ApiHttpResponse} 请求返回的结果
*/
public static String patch(String url, String data, Map<String, String> headers) {
return HttpKit.getDelegate().patch(url, data, headers);
}
/**
* upload 请求
*
* @param url 请求url
* @param authorization 授权信息
* @param data 请求参数
* @param file 上传文件
* @return {@link ApiHttpResponse} 请求返回的结果
*/
public static String upload(String url, String authorization, String data, File file) {
Map<String, Object> paramMap = new HashMap<>(2);
paramMap.put("file", file);
paramMap.put("meta", data);
return upload(url, paramMap, getUploadHeaders(authorization));
}
/**
* upload 请求
*
* @param url 请求url
* @param params 请求参数
* @param headers 请求头
* @return {@link ApiHttpResponse} 请求返回的结果
*/
public static String upload(String url, Map<String, Object> params, Map<String, String> headers) {
return HttpKit.getDelegate().post(url, params, headers);
}
public static Map<String, String> getUploadHeaders(String authorization) {
Map<String, String> headers = getBaseHeaders(authorization);
headers.put("Content-Type", "multipart/form-data;boundary=\"boundary\"");
return headers;
}
/**
* delete 请求
*
* @param url 请求url
* @param authorization 授权信息
* @param data 请求参数
* @return {@link ApiHttpResponse} 请求返回的结果
*/
public static String delete(String url, String authorization, String data) {
return delete(url, data, getHeaders(authorization));
}
/**
* delete 请求
*
* @param url 请求url
* @param data 请求参数
* @param headers 请求头
* @return {@link ApiHttpResponse} 请求返回的结果
*/
public static String delete(String url, String data, Map<String, String> headers) {
return HttpKit.getDelegate().delete(url, data, headers);
}
/**
* post 请求
*
* @param url 请求url
* @param authorization 授权信息
* @param data 请求参数
* @return {@link ApiHttpResponse} 请求返回的结果
*/
public static String post(String url, String authorization, String data) {
return post(url, data, getHeaders(authorization));
}
/**
* post 请求
*
* @param url 请求url
* @param data 请求参数
* @param headers 请求头
* @return {@link ApiHttpResponse} 请求返回的结果
*/
public static String post(String url, String data, Map<String, String> headers) {
log.info("请求路径:{}", url);
log.info("请求头:{}", JSON.toJSONString(headers));
log.info("请求体:{}", data);
StopWatch watch = new StopWatch();
watch.start();
String body = HttpKit.getDelegate().post(url, data, headers);
log.info("返回参数:{}", body);
watch.stop();
log.info("请求耗时:{}ms", watch.getTotalTimeMillis());
return body;
}
/**
* get 请求
*
* @param url 请求url
* @param authorization 授权信息
* @param params 请求参数
* @return {@link ApiHttpResponse} 请求返回的结果
*/
public static String get(String url, String authorization, Map<String, Object> params) {
return get(url, params, getHeaders(authorization));
}
private static String download(String url, String authorization, Map<String, Object> params) {
return download(url, params, getHeaders(authorization));
}
/**
* get 请求
*
* @param url 请求url
* @param params 请求参数
* @param headers 请求头
* @return {@link ApiHttpResponse} 请求返回的结果
*/
public static String download(String url, Map<String, Object> params, Map<String, String> headers) {
log.info("请求路径:{}", url);
log.info("请求头:{}", JSON.toJSONString(headers));
log.info("请求参数:{}", params);
StopWatch watch = new StopWatch();
watch.start();
try (HttpResponse res = HttpKit.getDelegate().getToResponse(url, params, headers);) {
InputStream fileStream = res.bodyStream();
// 将流转换为字节数组
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
byte[] data = new byte[1024];
int bytesRead;
while ((bytesRead = fileStream.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, bytesRead);
}
buffer.flush();
byte[] byteArray = buffer.toByteArray();
// 转换为Base64编码
String base64String = Base64.getEncoder().encodeToString(byteArray);
log.info("返回参数:{}", base64String);
watch.stop();
log.info("请求耗时:{}ms", watch.getTotalTimeMillis());
return base64String;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* get 请求
*
* @param url 请求url
* @param params 请求参数
* @param headers 请求头
* @return {@link ApiHttpResponse} 请求返回的结果
*/
public static String get(String url, Map<String, Object> params, Map<String, String> headers) {
log.info("请求路径:{}", url);
log.info("请求头:{}", JSON.toJSONString(headers));
log.info("请求参数:{}", params);
StopWatch watch = new StopWatch();
watch.start();
String body = HttpKit.getDelegate().get(url, params, headers);
log.info("返回参数:{}", body);
watch.stop();
log.info("请求耗时:{}ms", watch.getTotalTimeMillis());
return body;
}
public static Map<String, String> getHeaders(String authorization) {
Map<String, String> headers = getBaseHeaders(authorization);
headers.put("Accept-language", "zh-CN,zh");
headers.put("Content-Type", ContentType.JSON.toString());
if (StringUtils.isNotEmpty(authorization)) {
headers.put("Authorization", "Bearer " + authorization);
}
return headers;
}
public static Map<String, String> getBaseHeaders(String authorization) {
Map<String, String> headers = new HashMap<>(5);
headers.put("Accept", ContentType.JSON.toString());
if (StringUtils.isNotEmpty(authorization)) {
headers.put("Authorization", "Bearer " + authorization);
}
return headers;
}
}
package org.dromara.common.hotel.base;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.net.SSLContextBuilder;
import cn.hutool.core.net.SSLProtocols;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import org.dromara.common.hotel.common.ApiHttpResponse;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLSocketFactory;
import java.io.File;
import java.io.InputStream;
import java.net.Proxy;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.util.Map;
/**
* <p>IJPay 让支付触手可及,封装了微信支付、支付宝支付、银联支付等常用的支付方式以及各种常用的接口。</p>
*
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
*
* <p>IJPay 交流群: 723992875、864988890</p>
*
* <p>Node.js 版: <a href="https://gitee.com/javen205/TNWX">https://gitee.com/javen205/TNWX</a></p>
*
* <p>Http 代理类</p>
*
* @author Javen
*/
public abstract class AbstractHttpDelegate {
/**
* 设置代理
*
* @return {@link Proxy} 代理对象
*/
public Proxy getProxy() {
return null;
}
/**
* get 请求
*
* @param url 请求url
* @return {@link String} 请求返回的结果
*/
public String get(String url) {
return HttpUtil.get(url);
}
/**
* get 请求
*
* @param url 请求url
* @param paramMap 请求参数
* @return {@link String} 请求返回的结果
*/
public String get(String url, Map<String, Object> paramMap) {
return HttpUtil.get(url, paramMap);
}
/**
* get 请求
*
* @param url 请求url
* @param paramMap 请求参数
* @param headers 请求头
* @return {@link ApiHttpResponse} 请求返回的结果
*/
public String get(String url, Map<String, Object> paramMap, Map<String, String> headers) {
return getToResponse(url, paramMap, headers).body();
}
/**
* post 请求
*
* @param url 请求url
* @param data 请求参数
* @return {@link String} 请求返回的结果
*/
public String post(String url, String data) {
return HttpUtil.post(url, data);
}
/**
* post 请求
*
* @param url 请求url
* @param paramMap 请求参数
* @return {@link String} 请求返回的结果
*/
public String post(String url, Map<String, Object> paramMap) {
return HttpUtil.post(url, paramMap);
}
/**
* post 请求
*
* @param url 请求url
* @param paramMap 请求参数
* @param headers 请求头
* @return {@link ApiHttpResponse} 请求返回的结果
*/
public String post(String url, Map<String, Object> paramMap, Map<String, String> headers) {
return postToResponse(url, headers, paramMap).body();
}
/**
* post 请求
*
* @param url 请求url
* @param data 请求参数
* @param headers 请求头
* @return {@link ApiHttpResponse} 请求返回的结果
*/
public String post(String url, String data, Map<String, String> headers) {
return postToResponse(url, headers, data).body();
}
/**
* patch 请求
*
* @param url 请求url
* @param paramMap 请求参数
* @param headers 请求头
* @return {@link ApiHttpResponse} 请求返回的结果
*/
public ApiHttpResponse patch(String url, Map<String, Object> paramMap, Map<String, String> headers) {
HttpResponse httpResponse = patchToResponse(url, headers, paramMap);
return JSONObject.parseObject(httpResponse.body(), ApiHttpResponse.class);
}
/**
* patch 请求
*
* @param url 请求url
* @param data 请求参数
* @param headers 请求头
* @return {@link ApiHttpResponse} 请求返回的结果
*/
public String patch(String url, String data, Map<String, String> headers) {
return patchToResponse(url, headers, data).body();
}
/**
* delete 请求
*
* @param url 请求url
* @param paramMap 请求参数
* @param headers 请求头
* @return {@link ApiHttpResponse} 请求返回的结果
*/
public ApiHttpResponse delete(String url, Map<String, Object> paramMap, Map<String, String> headers) {
HttpResponse httpResponse = deleteToResponse(url, headers, paramMap);
return JSONObject.parseObject(httpResponse.body(), ApiHttpResponse.class);
}
/**
* delete 请求
*
* @param url 请求url
* @param data 请求参数
* @param headers 请求头
* @return {@link ApiHttpResponse} 请求返回的结果
*/
public String delete(String url, String data, Map<String, String> headers) {
return deleteToResponse(url, headers, data).body();
}
/**
* put 请求
*
* @param url 请求url
* @param paramMap 请求参数
* @param headers 请求头
* @return {@link ApiHttpResponse} 请求返回的结果
*/
public ApiHttpResponse put(String url, Map<String, Object> paramMap, Map<String, String> headers) {
HttpResponse httpResponse = putToResponse(url, headers, paramMap);
return JSONObject.parseObject(httpResponse.body(), ApiHttpResponse.class);
}
/**
* put 请求
*
* @param url 请求url
* @param data 请求参数
* @param headers 请求头
* @return {@link ApiHttpResponse} 请求返回的结果
*/
public String put(String url, String data, Map<String, String> headers) {
return putToResponse(url, headers, data).body();
}
/**
* 上传文件
*
* @param url 请求url
* @param data 请求参数
* @param certPath 证书路径
* @param certPass 证书密码
* @param filePath 上传文件路径
* @param protocol 协议
* @return {@link String} 请求返回的结果
*/
public String upload(String url, String data, String certPath, String certPass, String filePath, String protocol) {
try {
File file = FileUtil.newFile(filePath);
SSLSocketFactory sslSocketFactory = getSslSocketFactory(certPath, null, certPass, protocol);
return HttpRequest.post(url)
.setProxy(getProxy())
.setSSLSocketFactory(sslSocketFactory)
.header("Content-Type", "multipart/form-data;boundary=\"boundary\"")
.form("file", file)
.form("meta", data)
.execute()
.body();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 上传文件
*
* @param url 请求url
* @param data 请求参数
* @param certPath 证书路径
* @param certPass 证书密码
* @param filePath 上传文件路径
* @return {@link String} 请求返回的结果
*/
public String upload(String url, String data, String certPath, String certPass, String filePath) {
return upload(url, data, certPath, certPass, filePath, SSLProtocols.TLSv1);
}
/**
* post 请求
*
* @param url 请求url
* @param data 请求参数
* @param certPath 证书路径
* @param certPass 证书密码
* @param protocol 协议
* @return {@link String} 请求返回的结果
*/
public String post(String url, String data, String certPath, String certPass, String protocol) {
try {
SSLSocketFactory socketFactory = getSslSocketFactory(certPath, null, certPass, protocol);
return HttpRequest.post(url)
.setProxy(getProxy())
.setSSLSocketFactory(socketFactory)
.body(data)
.execute()
.body();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* post 请求
*
* @param url 请求url
* @param data 请求参数
* @param certPath 证书路径
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public String post(String url, String data, String certPath, String certPass) {
return post(url, data, certPath, certPass, SSLProtocols.TLSv1);
}
/**
* post 请求
*
* @param url 请求url
* @param data 请求参数
* @param certFile 证书文件输入流
* @param certPass 证书密码
* @param protocol 协议
* @return {@link String} 请求返回的结果
*/
public String post(String url, String data, InputStream certFile, String certPass, String protocol) {
try {
SSLSocketFactory sslSocketFactory = getSslSocketFactory(null, certFile, certPass, protocol);
return HttpRequest.post(url)
.setProxy(getProxy())
.setSSLSocketFactory(sslSocketFactory)
.body(data)
.execute()
.body();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* post 请求
*
* @param url 请求url
* @param data 请求参数
* @param certFile 证书文件输入流
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public String post(String url, String data, InputStream certFile, String certPass) {
return post(url, data, certFile, certPass, SSLProtocols.TLSv1);
}
/**
* get 请求
*
* @param url 请求url
* @param paramMap 请求参数
* @param headers 请求头
* @return {@link HttpResponse} 请求返回的结果
*/
public HttpResponse getToResponse(String url, Map<String, Object> paramMap, Map<String, String> headers) {
return HttpRequest.get(url)
.setProxy(getProxy())
.addHeaders(headers)
.form(paramMap)
.execute();
}
/**
* post 请求
*
* @param url 请求url
* @param headers 请求头
* @param data 请求参数
* @return {@link HttpResponse} 请求返回的结果
*/
private HttpResponse postToResponse(String url, Map<String, String> headers, String data) {
return HttpRequest.post(url)
.setProxy(getProxy())
.addHeaders(headers)
.body(data)
.execute();
}
/**
* post 请求
*
* @param url 请求url
* @param headers 请求头
* @param paramMap 请求参数
* @return {@link HttpResponse} 请求返回的结果
*/
private HttpResponse postToResponse(String url, Map<String, String> headers, Map<String, Object> paramMap) {
return HttpRequest.post(url)
.setProxy(getProxy())
.addHeaders(headers)
.form(paramMap)
.execute();
}
/**
* patch 请求
*
* @param url 请求url
* @param headers 请求头
* @param paramMap 请求参数
* @return {@link HttpResponse} 请求返回的结果
*/
private HttpResponse patchToResponse(String url, Map<String, String> headers, Map<String, Object> paramMap) {
return HttpRequest.patch(url)
.setProxy(getProxy())
.addHeaders(headers)
.form(paramMap)
.execute();
}
/**
* patch 请求
*
* @param url 请求url
* @param headers 请求头
* @param data 请求参数
* @return {@link HttpResponse} 请求返回的结果
*/
private HttpResponse patchToResponse(String url, Map<String, String> headers, String data) {
return HttpRequest.patch(url)
.setProxy(getProxy())
.addHeaders(headers)
.body(data)
.execute();
}
/**
* delete 请求
*
* @param url 请求url
* @param headers 请求头
* @param data 请求参数
* @return {@link HttpResponse} 请求返回的结果
*/
private HttpResponse deleteToResponse(String url, Map<String, String> headers, String data) {
return HttpRequest.delete(url)
.setProxy(getProxy())
.addHeaders(headers)
.body(data)
.execute();
}
/**
* delete 请求
*
* @param url 请求url
* @param headers 请求头
* @param paramMap 请求参数
* @return {@link HttpResponse} 请求返回的结果
*/
private HttpResponse deleteToResponse(String url, Map<String, String> headers, Map<String, Object> paramMap) {
return HttpRequest.delete(url)
.setProxy(getProxy())
.addHeaders(headers)
.form(paramMap)
.execute();
}
/**
* put 请求
*
* @param url 请求url
* @param headers 请求头
* @param data 请求参数
* @return {@link HttpResponse} 请求返回的结果
*/
private HttpResponse putToResponse(String url, Map<String, String> headers, String data) {
return HttpRequest.put(url)
.setProxy(getProxy())
.addHeaders(headers)
.body(data)
.execute();
}
/**
* put 请求
*
* @param url 请求url
* @param headers 请求头
* @param paramMap 请求参数
* @return {@link HttpResponse} 请求返回的结果
*/
private HttpResponse putToResponse(String url, Map<String, String> headers, Map<String, Object> paramMap) {
return HttpRequest.put(url)
.setProxy(getProxy())
.addHeaders(headers)
.form(paramMap)
.execute();
}
private KeyManager[] getKeyManager(String certPass, String certPath, InputStream certFile) throws Exception {
KeyStore clientStore = KeyStore.getInstance("PKCS12");
if (certFile != null) {
clientStore.load(certFile, certPass.toCharArray());
} else {
clientStore.load(Files.newInputStream(Paths.get(certPath)), certPass.toCharArray());
}
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(clientStore, certPass.toCharArray());
return kmf.getKeyManagers();
}
private SSLSocketFactory getSslSocketFactory(String certPath, InputStream certFile, String certPass, String protocol) throws Exception {
SSLContextBuilder sslContextBuilder = SSLContextBuilder.create();
sslContextBuilder.setProtocol(protocol);
sslContextBuilder.setKeyManagers(getKeyManager(certPass, certPath, certFile));
sslContextBuilder.setSecureRandom(new SecureRandom());
return sslContextBuilder.buildChecked().getSocketFactory();
}
}
package org.dromara.common.hotel.base;
import jakarta.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* <p>IJPay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
*
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
*
* <p>IJPay 交流群: 723992875、864988890</p>
*
* <p>Node.js 版: <a href="https://gitee.com/javen205/TNWX">https://gitee.com/javen205/TNWX</a></p>
*
* <p>Http 工具类</p>
*
* @author Javen
*/
public class HttpKit {
private static AbstractHttpDelegate delegate = new DefaultHttpKit();
public static AbstractHttpDelegate getDelegate() {
return delegate;
}
public static void setDelegate(AbstractHttpDelegate delegate) {
HttpKit.delegate = delegate;
}
public static String readData(HttpServletRequest request) {
BufferedReader br = null;
try {
StringBuilder result = new StringBuilder();
br = request.getReader();
for (String line; (line = br.readLine()) != null; ) {
if (result.length() > 0) {
result.append("\n");
}
result.append(line);
}
return result.toString();
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 将同步通知的参数转化为Map
*
* @param request {@link HttpServletRequest}
* @return 转化后的 Map
*/
public static Map<String, String> toMap(HttpServletRequest request) {
Map<String, String> params = new HashMap<>();
Map<String, String[]> requestParams = request.getParameterMap();
for (String name : requestParams.keySet()) {
String[] values = requestParams.get(name);
String valueStr = "" ;
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + "," ;
}
params.put(name, valueStr);
}
return params;
}
}
/**
* 使用 huTool 实现的 Http 工具类
*
* @author Javen
*/
class DefaultHttpKit extends AbstractHttpDelegate {
}
package org.dromara.common.hotel.base;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
public class PayKit {
/**
* 把所有元素排序
*
* @param params 需要排序并参与字符拼接的参数组
* @return 拼接后字符串
*/
public static String createLinkString(Map<String, Object> params) {
return createLinkString(params, false);
}
/**
* @param params 需要排序并参与字符拼接的参数组
* @param encode 是否进行URLEncoder
* @return 拼接后字符串
*/
public static String createLinkString(Map<String, Object> params, boolean encode) {
return createLinkString(params, "&", encode);
}
/**
* @param params 需要排序并参与字符拼接的参数组
* @param connStr 连接符号
* @param encode 是否进行URLEncoder
* @return 拼接后字符串
*/
public static String createLinkString(Map<String, Object> params, String connStr, boolean encode) {
return createLinkString(params, connStr, encode, false);
}
public static String createLinkString(Map<String, Object> params, String connStr, boolean encode, boolean quotes) {
List<String> keys = new ArrayList<>(params.keySet());
Collections.sort(keys);
StringBuilder content = new StringBuilder();
for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
Object value = params.get(key);
// 参数的值为空不参与签名
if (Objects.isNull(value)) {
continue;
}
// 拼接时,不包括最后一个&字符
if (i == keys.size() - 1) {
if (quotes) {
content.append(key).append("=").append('"').append(encode ? urlEncode(value.toString()) : value).append('"');
} else {
content.append(key).append("=").append(encode ? urlEncode(value.toString()) : value);
}
} else {
if (quotes) {
content.append(key).append("=").append('"').append(encode ? urlEncode(value.toString()) : value).append('"').append(connStr);
} else {
content.append(key).append("=").append(encode ? urlEncode(value.toString()) : value).append(connStr);
}
}
}
return content.toString();
}
/**
* URL 编码
*
* @param src 需要编码的字符串
* @return 编码后的字符串
*/
public static String urlEncode(String src) {
return URLEncoder.encode(src, StandardCharsets.UTF_8).replace("+", "%20");
}
}
package org.dromara.common.hotel.base;
/**
* HTTP 请求方法枚举
*
* @author wenhe
*/
public enum RequestMethodEnum {
/**
* 上传实质是 post 请求
*/
UPLOAD("POST"),
/**
* post 请求
*/
POST("POST"),
/**
* get 请求
*/
GET("GET"),
/**
* put 请求
*/
PUT("PUT"),
/**
* delete 请求
*/
DELETE("DELETE"),
/**
* options 请求
*/
OPTIONS("OPTIONS"),
/**
* head 请求
*/
HEAD("HEAD"),
/**
* trace 请求
*/
TRACE("TRACE"),
/**
* connect 请求
*/
CONNECT("CONNECT"),
/**
* PATCH 请求
*/
PATCH("PATCH"),
/**
*
*/
DOWNLOAD("GET");
;
private final String method;
RequestMethodEnum(String method) {
this.method = method;
}
@Override
public String toString() {
return this.method;
}
}
package org.dromara.common.hotel.common;
import lombok.Data;
/**
* @author hzh
* @date 2024-10-15
* @desc 响应实体
**/
@Data
public class ApiHttpResponse {
/**
* 说明
*/
private String Message;
/**
* 返回结果状态: 200成功;500错误
*/
private int Code;
/**
* 返回数据
*/
private String Data;
}
package org.dromara.common.hotel.common;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* code返回值
*
* @author wenhe
*/
@Getter
@AllArgsConstructor
public enum Code {
/**
* 成功
*/
SUCCESS(200, "成功");
private final Integer code;
private final String message;
}
package org.dromara.common.hotel.common;
import lombok.*;
import lombok.experimental.Accessors;
import java.util.List;
import java.util.Map;
/**
* @author hzh
* @date 2024-10-18
* @desc 分页信息
**/
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class PageInfo<T> {
/**
* 额外参数
*/
private Map<String, Object> map;
/**
* 总记录数
*/
private Integer total;
/**
* 总页数
*/
private Integer pages;
/**
* 当前页数
*/
private Integer pageNum;
/**
* 每页显示的数量
*/
private Integer count;
/**
* 结果集合
*/
private List<T> list;
}
package org.dromara.common.hotel.config;
/**
* @author wenhe
*/
public interface UserConfig {
/**
* 用户名
*/
String USERNAME = "testuser";
/**
* 密码
*/
String PASSWORD = "Abc123.";
}
package org.dromara.common.hotel.enums;
import java.util.Arrays;
import java.util.Optional;
/**
* API枚举接口
*
* @author hzh
*/
public interface ApiEnum {
/**
* 根据 url 获取枚举值
*
* @param enumClass 枚举class
* @param url url
* @param <E> 枚举类
* @return 枚举值
*/
static <E extends Enum<?> & ApiEnum> Optional<E> urlOf(Class<E> enumClass, String url) {
return Arrays.stream(enumClass.getEnumConstants()).filter(e -> e.getUrl().equals(url)).findFirst();
}
/**
* 获取枚举URL
*
* @return 枚举编码
*/
String getUrl();
/**
* 获取详细的描述信息
*
* @return 描述信息
*/
String getDesc();
}
package org.dromara.common.hotel.enums;
/**
* 获取可用域名
*
* @author wenhe
*/
public interface Domain {
/**
* 获取域名
*
* @return 返回域名
*/
String getDomain();
}
package org.dromara.common.hotel.enums;
/**
* 域名枚举
*
* @author wenhe
*/
public enum DomainEnum implements Domain {
/**
* 测试域名
*/
TEST("https://beta.51weishi.com:5005"),
/**
* 生产域名
*/
PROD("https://insure.51weishi.com");
/**
* 域名
*/
private final String domain;
DomainEnum(String domain) {
this.domain = domain;
}
@Override
public String getDomain() {
return domain;
}
@Override
public String toString() {
return domain;
}
}
package org.dromara.common.hotel.enums.auth;
import org.dromara.common.hotel.enums.ApiEnum;
/**
* 认证接口
*
* @author wenhe
*/
public enum AuthApiEnum implements ApiEnum {
/**
* 获取AccessToken接口
*/
AUTHORIZE("/api/v2/Authentication/GetToken", "获取AccessToken接口");
/**
* 接口URL
*/
private final String url;
/**
* 接口描述
*/
private final String desc;
AuthApiEnum(String url, String desc) {
this.url = url;
this.desc = desc;
}
/**
* 获取枚举URL
*
* @return 枚举编码
*/
@Override
public String getUrl() {
return url;
}
/**
* 获取详细的描述信息
*
* @return 描述信息
*/
@Override
public String getDesc() {
return desc;
}
@Override
public String toString() {
return url;
}
}
package org.dromara.common.hotel.enums.hotel;
import org.dromara.common.hotel.enums.ApiEnum;
/**
* 酒店接口
*
* @author wenhe
*/
public enum HotelApiEnum implements ApiEnum {
/**
* 酒店详细信息
*/
DETAIL("/api/v2/HotelProduct/GetHotelInfo", "获取多个酒店详细信息"),
/**
* 酒店Id列表
*/
ID_LIST("api/v2/HotelProduct/GetHotelIdList", "获取可用的酒店Id的列表,后续可以根据酒店ID通过 1.酒店详细信息接口 获取酒店详细信息"),
/**
* 房型列表
*/
ROOM_INFO("/api/v2/HotelProduct/GetRoomInfo", "获取酒店的所有房型"),
/**
* 报价
*/
GET_PRICE("/api/v2/HotelProduct/GetPrice", "获取单个酒店报价"),
;
/**
* 接口URL
*/
private final String url;
/**
* 接口描述
*/
private final String desc;
HotelApiEnum(String url, String desc) {
this.url = url;
this.desc = desc;
}
/**
* 获取枚举URL
*
* @return 枚举编码
*/
@Override
public String getUrl() {
return url;
}
/**
* 获取详细的描述信息
*
* @return 描述信息
*/
@Override
public String getDesc() {
return desc;
}
@Override
public String toString() {
return url;
}
}
package org.dromara.common.hotel.enums.product;
import org.dromara.common.hotel.enums.ApiEnum;
/**
* 产品接口
*
* @author wenhe
*/
public enum OrderApiEnum implements ApiEnum {
/**
* 下单
*/
ORDER_CREATE("/api/v2/HotelOrder/Booking", "下单接口"),
/**
* 订单详情
*/
ORDER_DETAIL("/api/v2/HotelOrder/OrderQuery", "获取订单详情"),
/**
* 申请取消订单
*/
ORDER_CANCEL("/api/v2/HotelOrder/OrderCancel", "申请取消订单接口,申请提交成功后,实际取消结果以接口-2.订单详情查询结果为准"),;
/**
* 接口URL
*/
private final String url;
/**
* 接口描述
*/
private final String desc;
OrderApiEnum(String url, String desc) {
this.url = url;
this.desc = desc;
}
/**
* 获取枚举URL
*
* @return 枚举编码
*/
@Override
public String getUrl() {
return url;
}
/**
* 获取详细的描述信息
*
* @return 描述信息
*/
@Override
public String getDesc() {
return desc;
}
@Override
public String toString() {
return url;
}
}
package org.dromara.common.hotel.exception;
import java.io.Serial;
/**
* @author hzh
* @date 2025-05-12
**/
public class HotelException extends RuntimeException{
@Serial
private static final long serialVersionUID = 1L;
public HotelException(String message) {
super(message);
}
}
/**
* <p>IJPay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
*
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
*
* <p>IJPay 交流群: 723992875、864988890</p>
*
* <p>Node.js 版: <a href="https://gitee.com/javen205/TNWX">https://gitee.com/javen205/TNWX</a></p>
*
* <p>Model 公用方法</p>
*
* @author Javen
*/
package org.dromara.common.hotel.model;
import cn.hutool.core.util.StrUtil;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
public class BaseModel {
/**
* 将建构的 builder 转为 Map
*
* @return 转化后的 Map
*/
public Map<String, String> toMap() {
String[] fieldNames = getFiledNames(this);
HashMap<String, String> map = new HashMap<String, String>(fieldNames.length);
for (String name : fieldNames) {
String value = (String) getFieldValueByName(name, this);
if (StrUtil.isNotEmpty(value)) {
map.put(name, value);
}
}
return map;
}
/**
* 获取属性名数组
*
* @param obj 对象
* @return 返回对象属性名数组
*/
public String[] getFiledNames(Object obj) {
Field[] fields = obj.getClass().getDeclaredFields();
String[] fieldNames = new String[fields.length];
for (int i = 0; i < fields.length; i++) {
fieldNames[i] = fields[i].getName();
}
return fieldNames;
}
/**
* 根据属性名获取属性值
*
* @param fieldName 属性名称
* @param obj 对象
* @return 返回对应属性的值
*/
public Object getFieldValueByName(String fieldName, Object obj) {
try {
String firstLetter = fieldName.substring(0, 1).toUpperCase();
String getter = new StringBuffer().append("get")
.append(firstLetter)
.append(fieldName.substring(1))
.toString();
Method method = obj.getClass().getMethod(getter);
return method.invoke(obj);
} catch (Exception e) {
return null;
}
}
}
package org.dromara.common.hotel.model.req.auth;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class AuthRequest {
/**
* Wid
*/
private String Wid;
/**
* key
*/
private String ApiKey;
}
package org.dromara.common.hotel.model.req.hotel;
import lombok.Data;
import java.util.List;
/**
* 酒店详情请求参数封装类
* @author wenhe
*/
@Data
public class HotelDetailRequest {
/**
* 酒店ID集合(可选)
*/
private List<String> HotelIds;
/**
* CN:中国区域内酒店, 其他值:非中国区域内酒店(可选)
*/
private String SupplyArea = "";
/**
* 当前页码(可选)
*/
private int PageIndex = 1;
/**
* 每页显示记录数(可选)
*/
private int PageSize = 100;
}
package org.dromara.common.hotel.model.req.hotel;
import lombok.Data;
/**
* 酒店id集合请求参数封装类
*
* @author wenhe
*/
@Data
public class HotelIdListRequest {
/**
* CN:中国区域内酒店, 其他值:非中国区域内酒店(可选)
*/
private String SupplyArea = "";
/**
* 第一次调用传值0,后续调用使用前一次调用返回的
* 最大酒店Id,当返回的结果集的酒店Id数量小于
* PageSize,说明已经获取了所有可用的酒店ID.(必选)
*/
private String LastMaxId = "0";
/**
* 返回酒店Id的数量(必选)
*/
private Integer PageSize = 100;
}
package org.dromara.common.hotel.model.req.hotel;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.List;
/**
* 酒店价格查询请求参数类
* 用于封装调用酒店价格查询接口所需的各项参数,结合 Lombok 简化代码,自动生成 getter、setter、toString 等方法
*/
@Data
public class HotelPriceRequest {
/**
* 酒店编号(必选)
*/
private String HotelId;
/**
* 价格计划编号(可选)
*/
private String RatePlanId;
/**
* 入住日期(必选)
*/
private LocalDateTime CheckInDate;
/**
* 离店日期(必选)
*/
private LocalDateTime CheckOutDate;
/**
* 间数(必选)
*/
private Integer RoomCount;
/**
* 成人数(必选)
* 注意:每间房的成人数,不是所有房间的总成人数
*/
private Integer AdultCount;
/**
* 儿童数(可选,默认值 0)
* 注意:每间房的儿童数,不是所有房间的总儿童数
*/
private Integer ChildCount = 0;
/**
* 儿童年龄(可选)
* 注意:每间房儿童的年龄列表,不是所有房间儿童年龄的汇总,需与房间维度的儿童数对应
*/
private List<Integer> ChildAges;
/**
* 客人国籍(可选)
* 格式要求:2位国家 ISO 码,如 "CN"(中国)、"US"(美国)等
* 规则说明:报价、验价、下单流程中该值必须保持一致
*/
private String CountryCode;
}
package org.dromara.common.hotel.model.req.hotel;
import lombok.Data;
import java.util.List;
/**
* 房型列表请求参数封装类
* @author wenhe
*/
@Data
public class HotelRoomInfoRequest {
/**
* 酒店Id集合(必选)
*/
private List<String> HotelIds;
}
package org.dromara.common.hotel.model.req.order;
import lombok.Data;
/**
* 订单取消请求参数封装类
*
* @author wenhe
*/
@Data
public class OrderCancelRequest {
/**
* 订单号(必选)
*/
private Long OrderId;
}
package org.dromara.common.hotel.model.req.order;
import lombok.Data;
/**
* 订单详情查询请求参数实体类
* 规则:OrderId 和 WholesalerOrderId 必选其一,若两者都填则 OrderId 优先
*
* @author wenhe
*/
@Data
public class OrderDetailRequest {
/**
* 订单号,OrderId与WholesalerOrderId必填写 (可选)
* 一个,两者都填写则OrderId优先
*/
private Long OrderId;
/**
* 分销商订单号,OrderId与WholesalerOrderId (可选)
* 必填一个,两者都填写则OrderId优先
*/
private String WholesalerOrderId;
}
package org.dromara.common.hotel.model.req.order;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
/**
* 订单请求参数封装类
*
* @author wenhe
*/
@Data
public class OrderRequest {
/**
* 下单校验码,入参RatePlanId不为空时返(必选)
* 回该值,下单需要使用该值
*/
private String RateKey;
/**
* 酒店编号(必选)
*/
private String HotelId;
/**
* 价格计划编号(必选)
*/
private String RatePlanId;
/**
* 入住日期(必选)
*/
private LocalDateTime CheckInDate;
/**
* 离店日期(必选)
*/
private LocalDateTime CheckOutDate;
/**
* 间数(必选)
*/
private Integer RoomCount;
/**
* 总金额(必选)
*/
private BigDecimal TotalPrice;
/**
* 联系人名字(必选)
*/
private String ContactFirstName;
/**
* 联系人姓氏(必选)
*/
private String ContactLastName;
/**
* 联系人电话(必选)
*/
private String ContactMobile;
/**
* 特殊要求备注(必选)
*/
private String NoteToHotel;
/**
* 分销渠道订单号(必选)
*/
private String WholesalerOrderId;
/**
* 每日价格集合(必选)
*/
private List<PriceListInfo> PriceList;
/**
* 支付方式(必选)
* 说明:枚举值,1. 预授权 2. 余额支付(具体以接口约定为准,需与实际支付逻辑匹配)
*/
private Integer PayType;
/**
* 客人国籍(2位国家 ISO 码)(可选)
* 说明:报价、验价、下单需保持一致,示例:CN(中国)、US(美国)等
*/
private String CountryCode;
/**
* 到店自付发票金额(可选)
*/
private BigDecimal InvoicePrice;
/**
* 入住人信息合集(必选)
*/
private List<RoomListInfo> RoomList;
@Data
public static class PriceListInfo {
/**
* 入住日期
*/
private LocalDateTime Date;
/**
* 价格(每天每间价格)
*/
private BigDecimal Price;
}
@Data
public static class RoomListInfo {
/**
* 成人数
*/
private Integer AdultCount;
/**
* 成人姓名集合
*/
private List<AdultListInfo> AdultList;
/**
* 儿童人数
*/
private int ChildrenCount;
/**
* 儿童姓名集合
*/
private List<ChildrenListInfo> ChildrenList;
}
@Data
public static class AdultListInfo {
/**
* 入住人名字
*/
private String FirstName;
/**
* 入住人姓氏
*/
private String LastName;
}
@Data
public static class ChildrenListInfo {
/**
* 入住人名字
*/
private String FirstName;
/**
* 入住人姓氏
*/
private String LastName;
/**
* 年龄
*/
private Integer Age;
}
}
package org.dromara.common.hotel.model.res.auth;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class AuthResponse {
/**
* 说明
*/
private String Message;
/**
* 返回结果状态: 200成功;500错误
*/
private Integer Code;
/**
* token
*/
private String Token;
}
package org.dromara.common.hotel.model.res.hotel;
import lombok.Data;
import java.util.List;
/**
* 酒店详情响应类,用于封装酒店详情查询接口返回的数据结构
* @author wenhe
*/
@Data
public class HotelDetailResponse {
/**
* 响应状态码,200表示成功,500表示错误
*/
private int Code;
/**
* 说明
*/
private String Message;
/**
* 产品集合
*/
private List<Hotel> HotelList;
/**
* 单个酒店的详细信息类,对应接口返回中酒店的各项属性
*/
@Data
public static class Hotel {
/**
* 酒店编号
*/
private String HotelId;
/**
* 酒店中文名称
*/
private String HotelNameCN;
/**
* 酒店英文名称
*/
private String HotelNameEN;
/**
* 经度
*/
private String Longitude;
/**
* 纬度
*/
private String Latitude;
/**
* 经纬度类型,可选值为 gaode(高德)、google(谷歌)、baidu(百度)、other(其他)
*/
private String PositionType;
/**
* 酒店中文地址
*/
private String AddressCN;
/**
* 酒店英文地址
*/
private String AddressEN;
/**
* 国家编号
*/
private Integer CountryId;
/**
* 国家中文名称
*/
private String CountryNameCN;
/**
* 国家英文名称
*/
private String CountryNameEN;
/**
* 城市编号
*/
private Integer CityId;
/**
* 城市中文名称
*/
private String CityNameCN;
/**
* 城市英文名称
*/
private String CityNameEN;
/**
* 酒店联系电话
*/
private String Phone;
/**
* 酒店映射关系
*/
private List<Mapping> Mapping;
}
/**
* 酒店映射关系类,用于描述酒店与外部系统的映射关联
*/
@Data
public static class Mapping {
/**
* 映射类型,如 1-Elong、2-Meituan、3-Expedia 等(可根据实际枚举值补充说明)
*/
private int Type;
/**
* 映射ID
*/
private String MappingId;
}
}
package org.dromara.common.hotel.model.res.hotel;
import lombok.Data;
import java.util.List;
/**
* 酒店id集合详情响应类,用于封装酒店详情查询接口返回的数据结构
*
* @author wenhe
*/
@Data
public class HotelIdListResponse {
/**
* 响应状态码,200表示成功,500表示错误
*/
private Integer Code;
/**
* 说明
*/
private String Message;
/**
* 酒店Id集合
*/
private List<String> HotelIdList;
}
package org.dromara.common.hotel.model.res.hotel;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
/**
* 酒店价格查询接口返回结果封装类
* 用于接收并解析酒店价格查询接口返回的数据,结合 Lombok 简化代码,自动生成 getter、setter、toString 等方法
*/
@Data
public class HotelPriceResponse {
/**
* 返回结果状态码
* 规则:200 表示成功,500 表示错误
*/
private Integer Code;
/**
* 说明
*/
private String Message;
/**
* 报价集合
*/
private List<HotelList> HotelList;
/**
* 试单校验码
* 规则:当价格计划编号不为空时返回该值,下单流程需传入此数值
*/
private String RateKey;
/**
* 酒店信息子对象,用于封装单条酒店的详细数据
*/
@Data
public static class HotelList {
/**
* 酒店编号
* 唯一标识酒店的编码
*/
private String HotelId;
/**
* 酒店中文名称
*/
private String HotelNameCN;
/**
* 酒店英文名称
*/
private String HotelNameEN;
/**
* 房型集合
*/
private List<RoomType> RoomTypeList;
}
/**
* 房型信息封装类
* 用于接收并解析接口返回的房型数据,结合 Lombok 简化代码,自动生成 getter、setter、toString 等方法
*/
@Data
public static class RoomType {
/**
* 房型编号
*/
private String RoomTypeId;
/**
* 房型中文名称
*/
private String RoomTypeNameCN;
/**
* 房型英文名称
*/
private String RoomTypeNameEN;
/**
* 床型
* 格式要求:数量*床型
*/
private String BedType;
/**
* 窗户情况
* 枚举规则:0.有窗 1.部分有窗 2.无窗 3.未知 ,标记房型窗户配置状态
*/
private Integer Window;
/**
* 上网方式
* 枚举规则:0.无法上网 1.无线WIFI 2.有线宽带 3.无线WIFI和有线宽带 4.未知 ,说明房型网络接入方式
*/
private Integer InternetWay;
/**
* 最大入住成人数
* 规则:0 表示未知,大于 0 表示具体可入住成人数量上限
*/
private Integer MaxAdults;
/**
* 最大入住儿童数
* 规则:0 表示未知,大于 0 表示具体可入住儿童数量上限
*/
private Integer MaxChildren;
/**
* 房型面积
*/
private String UseableArea;
/**
* 楼层
*/
private String Floor;
/**
* 价格计划集合
*/
private List<RatePlan> RatePlanList;
}
/**
* 价格计划信息封装类
* 用于接收并解析接口返回的价格计划数据,结合 Lombok 简化代码,自动生成 getter、setter、toString 等方法
*/
@Data
public static class RatePlan {
/**
* 价格计划编号
*/
private String RatePlanId;
/**
* 价格计划中文名称
*/
private String RatePlanNameCN;
/**
* 价格计划英文名称
*/
private String RatePlanNameEN;
/**
* 早餐份数
*/
private Integer Breakfast;
/**
* 最小连住天数
* 规则:0 表示不限,大于 0 表示需要连续入住的最少天数
*/
private Integer ContinuousDays;
/**
* 最大连住天数
* 规则:0 表示不限,大于 0 表示最多可连续入住的天数
*/
private Integer MaxContinuousDays;
/**
* 提前预订天数
* 规则:0 表示不限,大于 0 表示需要提前预订的天数要求
*/
private Integer AdvanceDays;
/**
* 最少预订间数
* 规则:0 表示不限,大于 0 表示该价格计划最少要预订的房间数量
*/
private Integer MinRoomCount;
/**
* 最大预订间数
* 规则:0 表示不限,大于 0 表示该价格计划最多可预订的房间数量
*/
private Integer MaxRoomCount;
/**
* 最大成人数
* 规则:0 表示未知,大于 0 表示该价格计划下最多可入住的成人数量
*/
private Integer MaxAdultOccupancy;
/**
* 最大儿童数
* 规则:0 表示未知,大于 0 表示该价格计划下最多可入住的儿童数量
*/
private Integer MaxChildrenOccupancy;
/**
* 发票类型
* 枚举规则:0.无,1.酒店前台开发票,2.我司开发票
* 用于标记该价格计划对应的发票开具方式
*/
private Integer InvoiceType;
/**
* 每日价格集合
*/
private List<RatePlanPrice> RatePlanPriceList;
/**
* 礼包
*/
private List<Gift> GiftList;
/**
* 取消政策集合
*/
private List<CancellationPenalty> CancellationPenalties;
/**
* 取消政策使用的时区
*/
private String CityTimeZone;
/**
* 到店付的费或税
*/
private List<Fee> FeeList;
}
/**
* 每日价格计划信息封装类
* 用于接收并解析接口返回的每日价格计划数据,结合 Lombok 简化代码,自动生成 getter、setter、toString 等方法
*/
@Data
public static class RatePlanPrice {
/**
* 日期
*/
private LocalDateTime Date;
/**
* 价格
* 类型为 decimal,代表每天每间房的价格
*/
private BigDecimal Price;
/**
* 币种
* 字符串类型,标记价格对应的货币种类,如 "CNY"(人民币)、"USD"(美元)等
*/
private String Currency;
/**
* 可售间数
* 整数类型,标记该日期下该价格计划可销售的房间数量
*/
private Integer RoomCount;
/**
* 状态
* 枚举规则:1.上架 0.下架,标记该价格计划在对应日期的状态
*/
private Integer Flag;
}
/**
* 礼包信息封装类
* 用于接收并解析接口返回的礼包数据,结合 Lombok 简化代码,自动生成 getter、setter、toString 等方法
*/
@Data
public static class Gift {
/**
* 名称
*/
private String GiftName;
/**
* 描述
*/
private String GiftDesc;
/**
* 数量
*/
private Integer GiftCount;
/**
* 价格
*/
private String GiftPrice;
/**
* 生效时间
*/
private String StartDate;
/**
* 失效时间
*/
private String EndDate;
}
/**
* 取消政策实体类
* 用于封装取消政策相关数据,配合 Lombok 的 @Data 注解,自动生成 getter、setter、toString 等方法
*/
@Data
public static class CancellationPenalty {
/**
* 取消起始时间,使用 CityTimeZone 时区
*/
private String From;
/**
* 取消罚金金额
*/
private BigDecimal Amount;
}
/**
* 费用实体类
* 用于封装费用相关数据,配合 Lombok 的 @Data 注解,自动生成 getter、setter、toString 等方法
*/
@Data
public static class Fee {
/**
* 费用名称
*/
private String FeeName;
/**
* 费用金额
*/
private BigDecimal FeePrice;
/**
* 费用币种
*/
private String Currency;
}
}
package org.dromara.common.hotel.model.res.hotel;
import lombok.Data;
import java.util.List;
/**
* 酒店房间信息响应类
* 用于接收并解析酒店房间相关接口返回的 JSON 数据
*/
@Data
public class HotelRoomInfoResponse {
/**
* 返回结果状态: 200成功;500错
*/
private Integer Code;
/**
* 说明
*/
private String Message;
/**
* 酒店集合
*/
private List<HotelData> Data;
/**
* 酒店数据类,包含酒店 ID 及对应的房间列表
*/
@Data
public static class HotelData {
/**
* 酒店编号
*/
private String HotelId;
/**
* 房型集合
*/
private List<RoomInfo> RoomList;
}
/**
* 房间信息类,描述房间的具体属性
*/
@Data
public static class RoomInfo {
/**
* 房型编号
*/
private String RoomTypeId;
/**
* 房型中文名称
*/
private String RoomTypeNameCN;
/**
* 房型英文名称
*/
private String RoomTypeNameEN;
/**
* 最大入住成人数, 0 表示未知
*/
private Integer MaxAdults;
/**
* 最大入住儿童数, 0 表示未知
*/
private Integer MaxChildren;
/**
* 房型面积
*/
private String UseableArea;
/**
* 床型,格式: 数量*床型
*/
private String BedType;
/**
* 窗户情况:0.有窗 1.部分有窗 2.无窗 3.未知
*/
private Integer Window;
/**
* 上网方式:0.无法上网 1.无线WIFI 2.有线宽带 3.无线WIFI
* 和有线宽带 4.未知
*/
private Integer InternetWay;
/**
* 房型映射关系
*/
private List<Mapping> Mapping;
}
/**
* 酒店映射关系类,用于描述酒店与外部系统的映射关联
*/
@Data
public static class Mapping {
/**
* 映射类型,如 1-Elong、2-Meituan、3-Expedia 等(可根据实际枚举值补充说明)
*/
private Integer Type;
/**
* 映射ID
*/
private String MappingId;
}
}
package org.dromara.common.hotel.model.res.order;
import lombok.Data;
/**
* 订单取消响应结果实体类
* @author wenhe
*/
@Data
public class OrderCancelResponse {
/**
* 返回结果状态码
* 说明:200 表示成功,500 表示错误,用于快速判断接口调用结果
*/
private Integer Code;
/**
* 说明信息
* 用于返回接口调用的详细说明,如错误原因、成功提示等
*/
private String Message;
/**
* 订单号
* 类型为 long,唯一标识订单的编号,下单成功后返回,可用于后续订单查询、修改等操作
*/
private Long OrderId;
/**
* 订单状态
* 枚举值说明:
* 1. 确认有房
* 2. 等待预约确认
* 3. 确认无房
* 4. 已完成
* 5. 订单取消
* 6. 异常订单
* 7. 下单异常
* 用于标识订单当前所处的业务状态
*/
private Integer OrderStatus;
}
package org.dromara.common.hotel.model.res.order;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
/**
* 订单详情响应结果封装类
* 用于接收并解析订单详情接口返回的数据,结合 Lombok 简化代码,自动生成 getter、setter、toString 等方法
* 完整映射 JSON 结构,包含订单基础信息、价格列表、客人信息及接口状态码等
*/
@Data
public class OrderDetailResponse {
/**
* 订单详情核心数据
* 封装订单的详细信息,如订单号、酒店信息、价格列表等
*/
private OrderDetail orderDetail;
/**
* 接口返回状态码
* 规则:200 表示成功,500 表示错误(需结合实际接口约定)
*/
private Integer Code;
/**
* 说明信息
* 通常用于返回错误详情、提示等文本内容,成功时可能为空
*/
private String Message;
@Data
public static class OrderDetail {
/**
* 订单号
*/
private String OrderId;
/**
* 分销商订单号
*/
private String WholesalerOrderId;
/**
* 下单时间
* 格式:datetime 字符串,标记订单创建的时间点
*/
private String OrderDate;
/**
* 酒店编号
*/
private String HotelId;
/**
* 酒店中文名称
*/
private String HotelName;
/**
* 酒店英文名称
*/
private String HotelNameEN;
/**
* 房型编号
*/
private String RoomId;
/**
* 房型中文名称
*/
private String RoomName;
/**
* 房型英文名称
*/
private String RoomNameEN;
/**
* 间夜数
*/
private Integer RoomNum;
/**
* 入住日期
*/
private String CheckInDate;
/**
* 离店日期
*/
private String CheckOutDate;
/**
* 订单总价格
*/
private BigDecimal TotalPrice;
/**
* 每日价格集合
*/
private List<PriceListItem> PriceList;
/**
* 入住人姓名
*/
private String CustomerName;
/**
* 联系电话
*/
private String PhoneNumber;
/**
* 确认号
*/
private String ConfirmationNumber;
/**
* 订单状态
* 1.确认有房
* 3.等待房间确认
* 4.确认无房
* 5.已完成
* -1.订单取消
* 6.异常订单
* 7.下单异常
*/
private Integer OrderStatus;
/**
* 授信状态 0未授信 1已授信
*/
private Integer PaymentStatus;
}
@Data
public static class PriceListItem {
/**
* 入住日期
*/
private String Date;
/**
* 间数
*/
private Integer Count;
/**
* 币种
*/
private String Currency;
/**
* 早餐份数
*/
private Integer Breakfast;
/**
* 价格,每天每间价格
*/
private BigDecimal Price;
}
}
package org.dromara.common.hotel.model.res.order;
import lombok.Data;
/**
* 订单响应结果实体类
* 用于封装订单操作(如下单、查询等)后的返回数据,配合 Lombok 的 @Data 注解,自动生成 getter、setter、toString 等方法
*/
@Data
public class OrderResponse {
/**
* 返回结果状态码
* 说明:200 表示成功,500 表示错误,用于快速判断接口调用结果
*/
private Integer Code;
/**
* 说明信息
* 用于返回接口调用的详细说明,如错误原因、成功提示等
*/
private String Message;
/**
* 订单号
* 类型为 long,唯一标识订单的编号,下单成功后返回,可用于后续订单查询、修改等操作
*/
private Long OrderId;
/**
* 订单状态
* 枚举值说明:
* 1. 确认有房
* 2. 等待预约确认
* 3. 确认无房
* 4. 已完成
* 5. 订单取消
* 6. 异常订单
* 7. 下单异常
* 用于标识订单当前所处的业务状态
*/
private Integer OrderStatus;
}
package org.dromara.common.hotel.service;
import org.dromara.common.hotel.model.req.auth.AuthRequest;
import org.dromara.common.hotel.model.req.hotel.HotelDetailRequest;
import org.dromara.common.hotel.model.req.hotel.HotelIdListRequest;
import org.dromara.common.hotel.model.req.hotel.HotelPriceRequest;
import org.dromara.common.hotel.model.req.hotel.HotelRoomInfoRequest;
import org.dromara.common.hotel.model.req.order.OrderCancelRequest;
import org.dromara.common.hotel.model.req.order.OrderDetailRequest;
import org.dromara.common.hotel.model.req.order.OrderRequest;
import org.dromara.common.hotel.model.res.auth.AuthResponse;
import org.dromara.common.hotel.model.res.hotel.HotelDetailResponse;
import org.dromara.common.hotel.model.res.hotel.HotelIdListResponse;
import org.dromara.common.hotel.model.res.hotel.HotelPriceResponse;
import org.dromara.common.hotel.model.res.hotel.HotelRoomInfoResponse;
import org.dromara.common.hotel.model.res.order.OrderCancelResponse;
import org.dromara.common.hotel.model.res.order.OrderDetailResponse;
import org.dromara.common.hotel.model.res.order.OrderResponse;
/**
* @author wenhe
*/
public interface HotelChinaService {
/**
* 认证
*
* @param req 请求参数
* @return 响应参数
*/
AuthResponse authorize(AuthRequest req);
/**
* 酒店详情
*
* @param token token
* @param req 请求参数
* @return 响应参数
*/
HotelDetailResponse hotelDetail(String token, HotelDetailRequest req);
/**
* 酒店Id列表
*
* @param token token
* @param req 请求参数
* @return 响应参数
*/
HotelIdListResponse hotelIdList(String token, HotelIdListRequest req);
/**
* 房型列表
*
* @param token token
* @param req 请求参数
* @return 响应参数
*/
HotelRoomInfoResponse hotelRoomInfo(String token, HotelRoomInfoRequest req);
/**
* 报价
*
* @param token token
* @param req 请求参数
* @return 响应参数
*/
HotelPriceResponse hotelPrice(String token, HotelPriceRequest req);
/**
* 下单
*
* @param token token
* @param req 请求参数
* @return 响应参数
*/
OrderResponse order(String token, OrderRequest req);
/**
* 订单详情
*
* @param token token
* @param req 请求参数
* @return 响应参数
*/
OrderDetailResponse orderDetail(String token, OrderDetailRequest req);
/**
* 订单取消
*
* @param token token
* @param req 请求参数
* @return 响应参数
*/
OrderCancelResponse orderCancel(String token, OrderCancelRequest req);
}
package org.dromara.common.hotel.service.impl;
import com.alibaba.fastjson.JSON;
import org.dromara.common.hotel.Api;
import org.dromara.common.hotel.base.RequestMethodEnum;
import org.dromara.common.hotel.common.Code;
import org.dromara.common.hotel.enums.DomainEnum;
import org.dromara.common.hotel.enums.auth.AuthApiEnum;
import org.dromara.common.hotel.enums.hotel.HotelApiEnum;
import org.dromara.common.hotel.enums.product.OrderApiEnum;
import org.dromara.common.hotel.exception.HotelException;
import org.dromara.common.hotel.model.req.auth.AuthRequest;
import org.dromara.common.hotel.model.req.hotel.HotelDetailRequest;
import org.dromara.common.hotel.model.req.hotel.HotelIdListRequest;
import org.dromara.common.hotel.model.req.hotel.HotelPriceRequest;
import org.dromara.common.hotel.model.req.hotel.HotelRoomInfoRequest;
import org.dromara.common.hotel.model.req.order.OrderCancelRequest;
import org.dromara.common.hotel.model.req.order.OrderDetailRequest;
import org.dromara.common.hotel.model.req.order.OrderRequest;
import org.dromara.common.hotel.model.res.auth.AuthResponse;
import org.dromara.common.hotel.model.res.hotel.HotelDetailResponse;
import org.dromara.common.hotel.model.res.hotel.HotelIdListResponse;
import org.dromara.common.hotel.model.res.hotel.HotelPriceResponse;
import org.dromara.common.hotel.model.res.hotel.HotelRoomInfoResponse;
import org.dromara.common.hotel.model.res.order.OrderCancelResponse;
import org.dromara.common.hotel.model.res.order.OrderDetailResponse;
import org.dromara.common.hotel.model.res.order.OrderResponse;
import org.dromara.common.hotel.service.HotelChinaService;
import java.util.Objects;
/**
* @author hzh
* @date 2025-05-12
**/
public class HotelChinaServiceImpl implements HotelChinaService {
@Override
public AuthResponse authorize(AuthRequest req) {
AuthResponse res = Api.v1(RequestMethodEnum.POST,
DomainEnum.TEST.getDomain(),
AuthApiEnum.AUTHORIZE.getUrl(),
null,
JSON.toJSONString(req),
AuthResponse.class);
if (!Objects.equals(res.getCode(), Code.SUCCESS.getCode())) {
throw new HotelException(res.getMessage());
}
return res;
}
@Override
public HotelDetailResponse hotelDetail(String token, HotelDetailRequest req) {
HotelDetailResponse res = Api.v1(RequestMethodEnum.POST,
DomainEnum.TEST.getDomain(),
HotelApiEnum.DETAIL.getUrl(),
token,
JSON.toJSONString(req),
HotelDetailResponse.class);
if (!Objects.equals(res.getCode(), Code.SUCCESS.getCode())) {
throw new HotelException(res.getMessage());
}
return res;
}
@Override
public HotelIdListResponse hotelIdList(String token, HotelIdListRequest req) {
HotelIdListResponse res = Api.v1(RequestMethodEnum.POST,
DomainEnum.TEST.getDomain(),
HotelApiEnum.ID_LIST.getUrl(),
token,
JSON.toJSONString(req),
HotelIdListResponse.class);
if (!Objects.equals(res.getCode(), Code.SUCCESS.getCode())) {
throw new HotelException(res.getMessage());
}
return res;
}
@Override
public HotelRoomInfoResponse hotelRoomInfo(String token, HotelRoomInfoRequest req) {
HotelRoomInfoResponse res = Api.v1(RequestMethodEnum.POST,
DomainEnum.TEST.getDomain(),
HotelApiEnum.ROOM_INFO.getUrl(),
token,
JSON.toJSONString(req),
HotelRoomInfoResponse.class);
if (!Objects.equals(res.getCode(), Code.SUCCESS.getCode())) {
throw new HotelException(res.getMessage());
}
return res;
}
@Override
public HotelPriceResponse hotelPrice(String token, HotelPriceRequest req) {
HotelPriceResponse res = Api.v1(RequestMethodEnum.POST,
DomainEnum.TEST.getDomain(),
HotelApiEnum.GET_PRICE.getUrl(),
token,
JSON.toJSONString(req),
HotelPriceResponse.class);
if (!Objects.equals(res.getCode(), Code.SUCCESS.getCode())) {
throw new HotelException(res.getMessage());
}
return res;
}
@Override
public OrderResponse order(String token, OrderRequest req) {
OrderResponse res = Api.v1(RequestMethodEnum.POST,
DomainEnum.TEST.getDomain(),
OrderApiEnum.ORDER_CREATE.getUrl(),
token,
JSON.toJSONString(req),
OrderResponse.class);
if (!Objects.equals(res.getCode(), Code.SUCCESS.getCode())) {
throw new HotelException(res.getMessage());
}
return res;
}
@Override
public OrderDetailResponse orderDetail(String token, OrderDetailRequest req) {
OrderDetailResponse res = Api.v1(RequestMethodEnum.POST,
DomainEnum.TEST.getDomain(),
OrderApiEnum.ORDER_DETAIL.getUrl(),
token,
JSON.toJSONString(req),
OrderDetailResponse.class);
if (!Objects.equals(res.getCode(), Code.SUCCESS.getCode())) {
throw new HotelException(res.getMessage());
}
return res;
}
@Override
public OrderCancelResponse orderCancel(String token, OrderCancelRequest req) {
OrderCancelResponse res = Api.v1(RequestMethodEnum.POST,
DomainEnum.TEST.getDomain(),
OrderApiEnum.ORDER_CANCEL.getUrl(),
token,
JSON.toJSONString(req),
OrderCancelResponse.class);
if (!Objects.equals(res.getCode(), Code.SUCCESS.getCode())) {
throw new HotelException(res.getMessage());
}
return res;
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论