add===>:增加医生排班、视频问诊、websocket。

This commit is contained in:
haown 2023-09-22 08:52:24 +08:00
parent e8f6a27df4
commit f77b1815bf
41 changed files with 3376 additions and 3 deletions

View File

@ -169,3 +169,10 @@ xss:
excludes: /system/notice
# 匹配链接
urlPatterns: /system/*,/monitor/*,/tool/*
# 腾讯云音视频
trtc:
sdkappid: 1400236771
sdksecretkey: 83ab78d1a8513af6626d58cc2bacd7b28bfb2af06515fa02b0204129ebb53422
secretid: AKIDOBpP2ICALat0wP4lcIiAMtZ7XgUJ5vMO
secretkey: zxjJhGcx75lECyweHgphKYefWCkBPSHt

View File

@ -17,6 +17,17 @@
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Spring框架基本的核心工具 -->
<dependency>
<groupId>org.springframework</groupId>
@ -135,6 +146,40 @@
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
</dependency>
<dependency>
<groupId>com.squareup.okio</groupId>
<artifactId>okio</artifactId>
<version>1.12.0</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp</groupId>
<artifactId>okhttp</artifactId>
<version>2.7.5</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</dependency>
<!--糊涂工具 https://github.com/looly/hutool/-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.4.7</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-websocket</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,55 @@
package com.xinelu.common.core.dto;
import java.util.Date;
import lombok.Data;
/**
* shitianqi <br/>
* 2022-01-19 19:02 <br/>
* 长连接消息模板
*/
@Data
public class MessageTemplate {
/**
* 发送消息对象key值消息来源
*/
private String fromKey;
/**
* 发送消息对象Name值消息来源
*/
private String fromName;
/**
* 接收消息对象key值消息去向
*/
private String toKey;
/**
* 接收消息对象name值消息去向
*/
private String toName;
/**
* 消息内容Json
*/
private String message;
/**
* 消息类型标识在{@link com.xinelu.common.enums.MessageContentType}
*/
private String msgType;
/**
* 发送时间
* */
private Date sendTime;
/**
* 问诊记录业务主键
*/
private String recordId;
/** 问诊房间号 */
private String roomNo;
}

View File

@ -0,0 +1,21 @@
package com.xinelu.common.enums;
import lombok.Getter;
/**
* shitainqi<br/>
* 2022-01-18 21:01
* 长连接内容对象枚举列表在此处增加长连接返回对象
*/
@Getter
public enum MessageContentType {
DEVICE,
NOTICE,
PUSH,
CHAT,
/** 会诊 */
CONSULTATION,
/** 问诊 */
VIDEO
}

View File

@ -0,0 +1,74 @@
package com.xinelu.common.socket;
import java.io.IOException;
import java.util.Map;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
@Slf4j
@Component
@ServerEndpoint(value = "/webSocket/{key}")
public class WebSocket {
/**
* 连接建立成功调用的方法
*/
@OnOpen
public void onOpen(@PathParam(value = "key") String key, Session session) throws IOException {
if (StringUtils.isNotBlank(key)) {
WebSocketUtils.add(key, session);
} else {
session.getAsyncRemote().sendText("来自服务器的消息您未传递key值");
}
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose(@PathParam("key") String key) throws IOException {
WebSocketUtils.remove(key);
}
/**
* 收到客户端消息后调用的方法
*
* @param message 客户端发送过来的消息
*/
@OnMessage
public void onMessage(String message, Session fromSession) {
if (message.equals("ping")) {
return;
}
for (Map.Entry<String, Session> sessionEntry : WebSocketUtils.clients.entrySet()) {
// 获取自己
if (fromSession.getId().equals(sessionEntry.getValue().getId())) {
//打印消息
WebSocketUtils.receive(sessionEntry.getKey(), message);
}
}
}
@OnError
public void onError(Session session, Throwable error) throws IOException {
for (Map.Entry<String, Session> sessionEntry : WebSocketUtils.clients.entrySet()) {
// 获取自己
if (session.getId().equals(sessionEntry.getValue().getId())) {
//清除异常连接
WebSocketUtils.remove(sessionEntry.getKey());
}
}
log.error("发生错误");
error.printStackTrace();
}
}

View File

@ -0,0 +1,17 @@
package com.xinelu.common.socket;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebSocketConfig {
/**
* 注入一个ServerEndpointExporter,该Bean会自动注册使用@ServerEndpoint注解申明的websocket endpoint
*/
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}

View File

@ -0,0 +1,102 @@
package com.xinelu.common.socket;
import com.alibaba.fastjson2.JSON;
import com.xinelu.common.core.dto.MessageTemplate;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import javax.websocket.Session;
import lombok.extern.slf4j.Slf4j;
/**
* shitianqi
* 2022-01-18 19:17
* socket类和请求和方法
*/
@Slf4j
public class WebSocketUtils {
//静态变量用来记录当前在线连接数应该把它设计成线程安全的
/**
* 记录当前在线连接数
*/
public static AtomicInteger onlineCount = new AtomicInteger();
/**
* 存放所有在线的客户端
*/
public static ConcurrentHashMap<String, Session> clients = new ConcurrentHashMap<>();
/**
* shitianqi <br/>
* 2022-01-18 19:47 <br/>
* 上线用户 <br/>
*
* @param key
* @param session
*/
public static void add(String key, Session session) throws IOException {
remove(key);
clients.put(key, session);
onlineCount.incrementAndGet(); // 在线数加1
int count = onlineCount.get();
log.info("有新连接加入:{},当前在线人数为:{}", key, count > 0? count: 0);
}
/**
* shitianqi <br/>
* 2022-01-18 19:47 <br/>
* 打印某在线用户接收消息内容和在线情况到日志 <br/>
*
* @param key
* @param message
*/
public static void receive(String key, String message) {
log.info("服务端收到客户端[{}]的消息:{}", key, message);
// log.info("当前连接数 = " + clients.size());
}
/**
* shitianqi <br/>
* 2022-01-18 19:47 <br/>
* 下线用户 <br/>
*
* @param key
*/
public static void remove(String key) throws IOException {
if (clients.containsKey(key)) {
clients.get(key).close();
clients.remove(key);
onlineCount.decrementAndGet(); // 在线数减1
// log.info("有一连接关闭:{},当前在线人数为:{}", key, onlineCount.get());
}
// log.info("当前连接数 = " + clients.size());
}
/**
* shitianqi <br/>
* 2022-01-18 19:47 <br/>
* 发送消息内容为对象json <br/>
*
* @param key
* @param msg
* @return boolean 是否成功
*/
public static boolean sendMessage(String key, MessageTemplate msg) {
// log.info("当前连接数 = " + clients.size());
if (clients.get(key) == null) {
return false;
} else {
try {
log.info("发送消息:" + JSON.toJSONString(msg));
clients.get(key).getBasicRemote().sendText(JSON.toJSONString(msg));
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
}
}

View File

@ -0,0 +1,521 @@
/*
* Copyright (c) 2018 THL A29 Limited, a Tencent company. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.xinelu.common.utils.tencentcloudapi.common;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken;
import com.squareup.okhttp.Headers;
import com.squareup.okhttp.Headers.Builder;
import com.squareup.okhttp.Response;
import com.xinelu.common.utils.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.xinelu.common.utils.tencentcloudapi.common.http.HttpConnection;
import com.xinelu.common.utils.tencentcloudapi.common.profile.ClientProfile;
import com.xinelu.common.utils.tencentcloudapi.common.profile.HttpProfile;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Type;
import java.net.URLEncoder;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.TimeZone;
import java.util.TreeMap;
import java.util.UUID;
import javax.crypto.Mac;
import javax.net.ssl.SSLContext;
import javax.xml.bind.DatatypeConverter;
/**
* 抽象client类
*/
abstract public class AbstractClient {
public static final int HTTP_RSP_OK = 200;
public static final String SDK_VERSION = "SDK_JAVA_3.0.89";
private Credential credential;
private ClientProfile profile;
private String endpoint;
private String region;
private String path;
private String sdkVersion;
private String apiVersion;
public Gson gson;
public AbstractClient(String endpoint, String version, Credential credential, String region) {
this(endpoint, version, credential, region, new ClientProfile());
}
public AbstractClient(String endpoint, String version, Credential credential, String region,
ClientProfile profile) {
this.credential = credential;
this.profile = profile;
this.endpoint = endpoint;
this.region = region;
this.path = "/";
this.sdkVersion = AbstractClient.SDK_VERSION;
this.apiVersion = version;
this.gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
warmup();
}
/**
* 设置产品地域
*
* @param region
* 产品地域
*/
public void setRegion(String region) {
this.region = region;
}
/**
* 返回产品地域
*
* @return 地域名称
*/
public String getRegion() {
return this.region;
}
/**
* 设置配置实例
*
* @param profile
* 配置实例
*/
public void setClientProfile(ClientProfile profile) {
this.profile = profile;
}
/**
* 获取配置实例
*
* @return 配置实例
*/
public ClientProfile getClientProfile() {
return this.profile;
}
/**
* 设置认证信息实例
*
* @param credential
* 认证信息实例
*/
public void setCredential(Credential credential) {
this.credential = credential;
}
/**
* 获取认证信息实例
*
* @return 认证信息实例
*/
public Credential getCredential() {
return this.credential;
}
/**
* Use post/json with tc3-hmac-sha256 signature to call any action. Ignore
* request method and signature method defined in profile.
*
* @param action
* Name of action to be called.
* @param jsonPayload
* Parameters of action serialized in json string format.
* @return Raw response from API if request succeeded, otherwise an exception
* will be raised instead of raw response
* @throws TencentCloudSDKException
*/
public String call(String action, String jsonPayload) throws TencentCloudSDKException {
String endpoint = this.endpoint;
// in case user has reset endpoint after init this client
if (!(this.profile.getHttpProfile().getEndpoint() == null)) {
endpoint = this.profile.getHttpProfile().getEndpoint();
}
// always use post tc3-hmac-sha256 signature process
// okhttp always set charset even we don't specify it,
// to ensure signature be correct, we have to set it here as well.
String contentType = "application/json; charset=utf-8";
byte[] requestPayload = jsonPayload.getBytes();
String canonicalUri = "/";
String canonicalQueryString = "";
String canonicalHeaders = "content-type:" + contentType + "\nhost:" + endpoint + "\n";
String signedHeaders = "content-type;host";
String hashedRequestPayload = "";
if (this.profile.isUnsignedPayload()) {
hashedRequestPayload = Sign.sha256Hex("UNSIGNED-PAYLOAD".getBytes());
} else {
hashedRequestPayload = Sign.sha256Hex(requestPayload);
}
String canonicalRequest = HttpProfile.REQ_POST + "\n" + canonicalUri + "\n" + canonicalQueryString + "\n"
+ canonicalHeaders + "\n" + signedHeaders + "\n" + hashedRequestPayload;
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
String date = sdf.format(new Date(Long.valueOf(timestamp + "000")));
String service = endpoint.split("\\.")[0];
String credentialScope = date + "/" + service + "/" + "tc3_request";
String hashedCanonicalRequest = Sign.sha256Hex(canonicalRequest.getBytes());
String stringToSign = "TC3-HMAC-SHA256\n" + timestamp + "\n" + credentialScope + "\n" + hashedCanonicalRequest;
String secretId = this.credential.getSecretId();
String secretKey = this.credential.getSecretKey();
byte[] secretDate = Sign.hmac256(("TC3" + secretKey).getBytes(), date);
byte[] secretService = Sign.hmac256(secretDate, service);
byte[] secretSigning = Sign.hmac256(secretService, "tc3_request");
String signature = DatatypeConverter.printHexBinary(Sign.hmac256(secretSigning, stringToSign)).toLowerCase();
String authorization = "TC3-HMAC-SHA256 " + "Credential=" + secretId + "/" + credentialScope + ", "
+ "SignedHeaders=" + signedHeaders + ", " + "Signature=" + signature;
HttpConnection conn = new HttpConnection(this.profile.getHttpProfile().getConnTimeout(),
this.profile.getHttpProfile().getReadTimeout(), this.profile.getHttpProfile().getWriteTimeout());
String url = this.profile.getHttpProfile().getProtocol() + endpoint + this.path;
Builder hb = new Headers.Builder();
hb.add("Content-Type", contentType).add("Host", endpoint).add("Authorization", authorization)
.add("X-TC-Action", action).add("X-TC-Timestamp", timestamp).add("X-TC-Version", this.apiVersion)
.add("X-TC-Region", this.getRegion()).add("X-TC-RequestClient", SDK_VERSION);
String token = this.credential.getToken();
if (token != null && !token.isEmpty()) {
hb.add("X-TC-Token", token);
}
if (this.profile.isUnsignedPayload()) {
hb.add("X-TC-Content-SHA256", "UNSIGNED-PAYLOAD");
}
Headers headers = hb.build();
Response resp = conn.postRequest(url, requestPayload, headers);
if (resp.code() != AbstractClient.HTTP_RSP_OK) {
throw new TencentCloudSDKException(resp.code() + resp.message());
}
String respbody = null;
try {
respbody = resp.body().string();
} catch (IOException e) {
throw new TencentCloudSDKException(e.getClass().getName() + "-" + e.getMessage());
}
JsonResponseModel<JsonResponseErrModel> errResp = null;
try {
Type errType = new TypeToken<JsonResponseModel<JsonResponseErrModel>>() {
}.getType();
errResp = gson.fromJson(respbody, errType);
} catch (JsonSyntaxException e) {
throw new TencentCloudSDKException(e.getClass().getName() + "-" + e.getMessage());
}
if (errResp.response.error != null) {
throw new TencentCloudSDKException(errResp.response.error.code + "-" + errResp.response.error.message,
errResp.response.requestId);
}
return respbody;
}
protected String internalRequest(AbstractModel request, String actionName) throws TencentCloudSDKException {
Response okRsp = null;
String endpoint = this.endpoint;
if (!(this.profile.getHttpProfile().getEndpoint() == null)) {
endpoint = this.profile.getHttpProfile().getEndpoint();
}
String [] binaryParams = request.getBinaryParams();
String sm = this.profile.getSignMethod();
String reqMethod = this.profile.getHttpProfile().getReqMethod();
// currently, customized params only can be supported via post json tc3-hmac-sha256
HashMap<String, Object> customizedParams = request.any();
if (customizedParams.size() > 0) {
if (binaryParams.length > 0) {
throw new TencentCloudSDKException("WrongUsage: Cannot post multipart with customized parameters.");
}
if (sm.equals(ClientProfile.SIGN_SHA1) || sm.equals(ClientProfile.SIGN_SHA256)) {
throw new TencentCloudSDKException("WrongUsage: Cannot use HmacSHA1 or HmacSHA256 with customized parameters.");
}
if (reqMethod.equals(HttpProfile.REQ_GET)) {
throw new TencentCloudSDKException("WrongUsage: Cannot use get method with customized parameters.");
}
}
if (binaryParams.length > 0 || sm.equals(ClientProfile.SIGN_TC3_256)) {
okRsp = doRequestWithTC3(endpoint, request, actionName);
} else if (sm.equals(ClientProfile.SIGN_SHA1) || sm.equals(ClientProfile.SIGN_SHA256)) {
okRsp = doRequest(endpoint, request, actionName);
} else {
throw new TencentCloudSDKException("Signature method " + sm + " is invalid or not supported yet.");
}
if (okRsp.code() != AbstractClient.HTTP_RSP_OK) {
throw new TencentCloudSDKException(okRsp.code() + okRsp.message());
}
String strResp = null;
try {
strResp = okRsp.body().string();
} catch (IOException e) {
throw new TencentCloudSDKException(e.getClass().getName() + "-" + e.getMessage());
}
JsonResponseModel<JsonResponseErrModel> errResp = null;
try {
Type errType = new TypeToken<JsonResponseModel<JsonResponseErrModel>>() {
}.getType();
errResp = gson.fromJson(strResp, errType);
} catch (JsonSyntaxException e) {
throw new TencentCloudSDKException(e.getClass().getName() + "-" + e.getMessage());
}
if (errResp.response.error != null) {
throw new TencentCloudSDKException(errResp.response.error.code + "-" + errResp.response.error.message,
errResp.response.requestId);
}
return strResp;
}
private Response doRequest(String endpoint, AbstractModel request, String action) throws TencentCloudSDKException {
HashMap<String, String> param = new HashMap<String, String>();
request.toMap(param, "");
String strParam = this.formatRequestData(action, param);
HttpConnection conn = new HttpConnection(
this.profile.getHttpProfile().getConnTimeout(),
this.profile.getHttpProfile().getReadTimeout(),
this.profile.getHttpProfile().getWriteTimeout());
String reqMethod = this.profile.getHttpProfile().getReqMethod();
String url = this.profile.getHttpProfile().getProtocol() + endpoint + this.path;
if (reqMethod.equals(HttpProfile.REQ_GET)) {
return conn.getRequest(url + "?" + strParam);
} else if (reqMethod.equals(HttpProfile.REQ_POST)) {
return conn.postRequest(url, strParam);
} else {
throw new TencentCloudSDKException("Method only support (GET, POST)");
}
}
private Response doRequestWithTC3(String endpoint, AbstractModel request, String action) throws TencentCloudSDKException {
String httpRequestMethod = this.profile.getHttpProfile().getReqMethod();
if (httpRequestMethod == null) {
throw new TencentCloudSDKException("Request method should not be null, can only be GET or POST");
}
String contentType = "application/x-www-form-urlencoded";
byte [] requestPayload = "".getBytes();
HashMap<String, String> params = new HashMap<String, String>();
request.toMap(params, "");
String [] binaryParams = request.getBinaryParams();
if ( binaryParams.length > 0 ) {
httpRequestMethod = HttpProfile.REQ_POST;
String boundary = UUID.randomUUID().toString();
// okhttp always set charset even we don't specify it,
// to ensure signature be correct, we have to set it here as well.
contentType = "multipart/form-data; charset=utf-8" + "; boundary=" + boundary;
try {
requestPayload = getMultipartPayload(request, boundary);
} catch (Exception e) {
throw new TencentCloudSDKException("Failed to generate multipart. because: " + e);
}
} else if (httpRequestMethod.equals(HttpProfile.REQ_POST)) {
requestPayload = AbstractModel.toJsonString(request).getBytes();
// okhttp always set charset even we don't specify it,
// to ensure signature be correct, we have to set it here as well.
contentType = "application/json; charset=utf-8";
}
String canonicalUri = "/";
String canonicalQueryString = this.getCanonicalQueryString(params, httpRequestMethod);
String canonicalHeaders = "content-type:" + contentType + "\nhost:" + endpoint + "\n";
String signedHeaders = "content-type;host";
String hashedRequestPayload = "";
if (this.profile.isUnsignedPayload()) {
hashedRequestPayload = Sign.sha256Hex("UNSIGNED-PAYLOAD".getBytes());
} else {
hashedRequestPayload = Sign.sha256Hex(requestPayload);
}
String canonicalRequest = httpRequestMethod + "\n" + canonicalUri + "\n" + canonicalQueryString + "\n"
+ canonicalHeaders + "\n" + signedHeaders + "\n" + hashedRequestPayload;
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
String date = sdf.format(new Date(Long.valueOf(timestamp + "000")));
String service = endpoint.split("\\.")[0];
String credentialScope = date + "/" + service + "/" + "tc3_request";
String hashedCanonicalRequest = Sign.sha256Hex(canonicalRequest.getBytes());
String stringToSign = "TC3-HMAC-SHA256\n" + timestamp + "\n" + credentialScope + "\n" + hashedCanonicalRequest;
String secretId = this.credential.getSecretId();
String secretKey = this.credential.getSecretKey();
byte[] secretDate = Sign.hmac256(("TC3" + secretKey).getBytes(), date);
byte[] secretService = Sign.hmac256(secretDate, service);
byte[] secretSigning = Sign.hmac256(secretService, "tc3_request");
String signature = DatatypeConverter.printHexBinary(Sign.hmac256(secretSigning, stringToSign)).toLowerCase();
String authorization = "TC3-HMAC-SHA256 " + "Credential=" + secretId + "/" + credentialScope + ", "
+ "SignedHeaders=" + signedHeaders + ", " + "Signature=" + signature;
HttpConnection conn = new HttpConnection(
this.profile.getHttpProfile().getConnTimeout(),
this.profile.getHttpProfile().getReadTimeout(),
this.profile.getHttpProfile().getWriteTimeout());
String url = this.profile.getHttpProfile().getProtocol() + endpoint + this.path;
Builder hb = new Headers.Builder();
hb.add("Content-Type", contentType)
.add("Host", endpoint)
.add("Authorization", authorization)
.add("X-TC-Action", action)
.add("X-TC-Timestamp", timestamp)
.add("X-TC-Version", this.apiVersion)
.add("X-TC-RequestClient", SDK_VERSION);
if (null != this.getRegion()) {
hb.add("X-TC-Region", this.getRegion());
}
String token = this.credential.getToken();
if (token != null && ! token.isEmpty()) {
hb.add("X-TC-Token", token);
}
if (this.profile.isUnsignedPayload()) {
hb.add("X-TC-Content-SHA256", "UNSIGNED-PAYLOAD");
}
Headers headers = hb.build();
if (httpRequestMethod.equals(HttpProfile.REQ_GET)) {
return conn.getRequest(url + "?" + canonicalQueryString, headers);
} else if (httpRequestMethod.equals(HttpProfile.REQ_POST)) {
return conn.postRequest(url, requestPayload, headers);
} else {
throw new TencentCloudSDKException("Method only support GET, POST");
}
}
private byte [] getMultipartPayload(AbstractModel request, String boundary) throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
String [] binaryParams = request.getBinaryParams();
for (Map.Entry<String, byte []> entry : request.getMultipartRequestParams().entrySet()) {
baos.write("--".getBytes());
baos.write(boundary.getBytes());
baos.write("\r\n".getBytes());
baos.write("Content-Disposition: form-data; name=\"".getBytes());
baos.write(entry.getKey().getBytes());
if (Arrays.asList(binaryParams).contains(entry.getKey())) {
baos.write("\"; filename=\"".getBytes());
baos.write(entry.getKey().getBytes());
baos.write("\"\r\n".getBytes());
} else {
baos.write("\"\r\n".getBytes());
}
baos.write("\r\n".getBytes());
baos.write(entry.getValue());
baos.write("\r\n".getBytes());
}
if (baos.size() != 0) {
baos.write("--".getBytes());
baos.write(boundary.getBytes());
baos.write("--\r\n".getBytes());
}
byte [] bytes = baos.toByteArray();
baos.close();
return bytes;
}
private String getCanonicalQueryString(HashMap<String, String> params, String method) throws TencentCloudSDKException {
if ( method != null && method.equals(HttpProfile.REQ_POST)) {
return "";
}
StringBuilder queryString = new StringBuilder("");
for (Map.Entry<String, String> entry : params.entrySet()) {
String v;
try {
v = URLEncoder.encode(entry.getValue(), "UTF8");
} catch (UnsupportedEncodingException e) {
throw new TencentCloudSDKException("UTF8 is not supported." + e.getMessage());
}
queryString.append("&")
.append(entry.getKey())
.append("=")
.append(v);
}
return queryString.toString().substring(1);
}
private String formatRequestData(String action, Map<String, String> param) throws TencentCloudSDKException {
param.put("Action", action);
param.put("RequestClient", this.sdkVersion);
param.put("Nonce", String.valueOf(Math.abs(new Random().nextInt())));
param.put("Timestamp", String.valueOf(System.currentTimeMillis() / 1000));
param.put("Version", this.apiVersion);
if (this.credential.getSecretId() != null && (!this.credential.getSecretId().isEmpty())) {
param.put("SecretId", this.credential.getSecretId());
}
if (this.region != null && (!this.region.isEmpty())) {
param.put("Region", this.region);
}
if (this.profile.getSignMethod() != null && (!this.profile.getSignMethod().isEmpty())) {
param.put("SignatureMethod", this.profile.getSignMethod());
}
if (this.credential.getToken() != null && (!this.credential.getToken().isEmpty())) {
param.put("Token", this.credential.getToken());
}
String endpoint = this.endpoint;
if (!(this.profile.getHttpProfile().getEndpoint() == null)) {
endpoint = this.profile.getHttpProfile().getEndpoint();
}
String sigInParam = Sign.makeSignPlainText(new TreeMap<String, String>(param),
this.profile.getHttpProfile().getReqMethod(), endpoint, this.path);
String sigOutParam = Sign.sign(this.credential.getSecretKey(), sigInParam, this.profile.getSignMethod());
String strParam = "";
try {
for (Map.Entry<String, String> entry : param.entrySet()) {
strParam += (URLEncoder.encode(entry.getKey(), "utf-8") + "="
+ URLEncoder.encode(entry.getValue(), "utf-8") + "&");
}
strParam += ("Signature=" + URLEncoder.encode(sigOutParam, "utf-8"));
} catch (UnsupportedEncodingException e) {
throw new TencentCloudSDKException(e.getClass().getName() + "-" + e.getMessage());
}
return strParam;
}
/**
* warm up, try to avoid unnecessary cost in the first request
*/
private void warmup() {
try {
// it happens in SDK signature process.
// first invoke costs around 250 ms.
Mac.getInstance("HmacSHA1");
Mac.getInstance("HmacSHA256");
// it happens inside okhttp, but I think any https framework/package will do the same.
// first invoke costs around 150 ms.
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, null, null);
} catch (Exception e) {
// ignore but print message to console
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,165 @@
/*
* Copyright (c) 2018 THL A29 Limited, a Tencent company. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.xinelu.common.utils.tencentcloudapi.common;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
/**
* 抽象model类
*/
abstract public class AbstractModel {
// any stores customized parameters which are not documented.
// You should make sure it can be correctly serialized to json string.
private HashMap<String, Object> customizedParams = new HashMap<String, Object>();
protected abstract void toMap(HashMap<String, String> map, String prefix);
/*
* valid only when it's a request object.
* some actions can only be posted in multipart format,
* this method is used to mark which parameters are binary type.
*/
protected String [] getBinaryParams() {
return new String[0];
}
/*
* valid only when it's a multipart request object.
*/
protected HashMap<String, byte []> getMultipartRequestParams() {
return new HashMap<String, byte []>();
}
protected <V> void setParamSimple(HashMap<String, String> map, String key, V value) {
if (value != null) {
key = key.substring(0, 1).toUpperCase() + key.substring(1);
key = key.replace("_", ".");
map.put(key, String.valueOf(value));
}
}
protected <V> void setParamArraySimple(HashMap<String, String> map, String prefix, V [] array) {
if (array != null) {
for (int i = 0; i < array.length; i++) {
this.setParamSimple(map, prefix + i, array[i]);
}
}
}
protected <V extends AbstractModel> void setParamObj(HashMap<String, String> map, String prefix, V obj) {
if (obj != null) {
obj.toMap(map, prefix);
}
}
protected <V extends AbstractModel> void setParamArrayObj(HashMap<String, String> map, String prefix, V [] array) {
if (array != null) {
for (int i = 0; i < array.length; i++) {
this.setParamObj(map, prefix + i + ".", array[i]);
}
}
}
/**
* 序列化函数将对象数据转化为json格式的string
*
* @param obj
* 集成自AbstractModel的子类实例
* @return json格式的string
*/
public static <O extends AbstractModel> String toJsonString(O obj) {
return toJsonObject(obj).toString();
}
/**
* Recursively generate obj's JSON object. Even if obj.any() is empty, this
* recursive progress cannot be skipped because customized additional parameter
* might be hidden in lower data structure.
*
* @param obj
* @return
*/
private static <O extends AbstractModel> JsonObject toJsonObject(O obj) {
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
JsonObject joall = new JsonObject();
JsonObject joadd = gson.toJsonTree(obj.any()).getAsJsonObject();
for (Map.Entry<String, JsonElement> entry : joadd.entrySet()) {
joall.add(entry.getKey(), entry.getValue());
}
// jopublic will override joadd if key conflict exists
JsonObject jopublic = gson.toJsonTree(obj).getAsJsonObject();
for (Map.Entry<String, JsonElement> entry : jopublic.entrySet()) {
Object fo = null;
try {
Field f = obj.getClass().getDeclaredField(entry.getKey());
f.setAccessible(true);
fo = f.get(obj);
} catch (Exception e) {
// this should never happen
e.printStackTrace();
}
if (fo instanceof AbstractModel) {
joall.add(entry.getKey(), toJsonObject((AbstractModel)fo));
} else {
joall.add(entry.getKey(), entry.getValue());
}
}
return joall;
}
/**
* 序列化函数根据传入的json格式的string实例化一个cls对象返回
*
* @param json
* json格式的string
* @param cls
* 与json匹配的类对象
* @return cls的实例
*/
public static <O> O fromJsonString(String json, Class<O> cls) {
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
return gson.fromJson(json, cls);
}
/**
* Set any key value pair to this model.
*
* @param key
* @param value
*/
public void set(String key, Object value) {
this.customizedParams.put(key, value);
}
/**
* Get customized key value pairs from this model.
*
* @return
*/
public HashMap<String, Object> any() {
return this.customizedParams;
}
}

View File

@ -0,0 +1,107 @@
/*
* Copyright (c) 2018 THL A29 Limited, a Tencent company. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.xinelu.common.utils.tencentcloudapi.common;
/**
* 认证相关信息类
*/
public class Credential {
/**
* secretId,在控制台申请
*/
private String secretId;
/**
* secretKey,在控制台申请
*/
private String secretKey;
/**
* token
*/
private String token;
/**
* @param secretId 在控制台申请
* @param secretKey 在控制台申请
*/
public Credential(String secretId, String secretKey) {
this(secretId, secretKey, "");
}
/**
* @param secretId 在控制台申请
* @param secretKey 在控制台申请
* @param token
*/
public Credential(String secretId, String secretKey, String token) {
this.secretId = secretId;
this.secretKey = secretKey;
this.token = token;
}
/**
* 设置secretId
* @param secretId
*/
public void setSecretId(String secretId) {
this.secretId = secretId;
}
/**
* 设置secretKey
* @param secretKey
*/
public void setSecretKey(String secretKey) {
this.secretKey = secretKey;
}
/**
* 设置token
* @param token
*/
public void setToken(String token) {
this.token = token;
}
/**
* 获取secretId
* @return secretId
*/
public String getSecretId() {
return this.secretId;
}
/**
* 获取secretKey
* @return secretKey
*/
public String getSecretKey() {
return this.secretKey;
}
/**
* 获取token
* @return token
*/
public String getToken() {
return this.token;
}
}

View File

@ -0,0 +1,48 @@
/*
* Copyright (c) 2018 THL A29 Limited, a Tencent company. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.xinelu.common.utils.tencentcloudapi.common;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* api 报错response类用以格式化接收失败的http response
* @author Administrator
*
*/
public class JsonResponseErrModel {
@SerializedName("RequestId")
@Expose
public String requestId;
@SerializedName("Error")
@Expose
public ErrorInfo error;
class ErrorInfo {
@SerializedName("Code")
@Expose
public String code;
@Expose
@SerializedName("Message")
public String message;
}
}

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2018 THL A29 Limited, a Tencent company. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.xinelu.common.utils.tencentcloudapi.common;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* api response类用以格式化接收http response
* @param <T> 具体对应的response类
*/
public class JsonResponseModel <T> {
@SerializedName("Response")
@Expose
public T response;
}

View File

@ -0,0 +1,127 @@
/*
* Copyright (c) 2018 THL A29 Limited, a Tencent company. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.xinelu.common.utils.tencentcloudapi.common;
import com.xinelu.common.utils.tencentcloudapi.common.exception.TencentCloudSDKException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.TreeMap;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
;
/**
* 签名工具类
*/
public class Sign {
private final static Charset UTF8 = StandardCharsets.UTF_8;
/**
*
* @param sigStr
* @param secretKey
* @param sigMethod
* @return string sign string
* @throws TencentCloudSDKException
*/
public static String sign(String secretKey, String sigStr, String sigMethod) throws TencentCloudSDKException
{
String sig = null;
try{
Mac mac = Mac.getInstance(sigMethod);
byte[] hash;
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(UTF8), mac.getAlgorithm());
mac.init(secretKeySpec);
hash = mac.doFinal(sigStr.getBytes(UTF8));
sig = DatatypeConverter.printBase64Binary(hash);
} catch (Exception e) {
throw new TencentCloudSDKException(e.getClass().getName() + "-" + e.getMessage());
}
return sig;
}
public static String makeSignPlainText(TreeMap<String, String> requestParams, String reqMethod, String host, String path) {
String retStr = "";
retStr += reqMethod;
retStr += host;
retStr += path;
retStr += buildParamStr(requestParams, reqMethod);
return retStr;
}
protected static String buildParamStr(TreeMap<String, String> requestParams, String requestMethod) {
String retStr = "";
for(String key: requestParams.keySet()) {
String value = requestParams.get(key).toString();
if (retStr.length() == 0) {
retStr += '?';
} else {
retStr += '&';
}
retStr += key.replace("_", ".") + '=' + value;
}
return retStr;
}
public static String sha256Hex(String s) throws TencentCloudSDKException {
MessageDigest md;
try {
md = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
throw new TencentCloudSDKException("SHA-256 is not supported." + e.getMessage());
}
byte[] d = md.digest(s.getBytes(UTF8));
return DatatypeConverter.printHexBinary(d).toLowerCase();
}
public static String sha256Hex(byte[] b) throws TencentCloudSDKException {
MessageDigest md;
try {
md = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
throw new TencentCloudSDKException("SHA-256 is not supported." + e.getMessage());
}
byte[] d = md.digest(b);
return DatatypeConverter.printHexBinary(d).toLowerCase();
}
public static byte[] hmac256(byte[] key, String msg) throws TencentCloudSDKException {
Mac mac;
try {
mac = Mac.getInstance("HmacSHA256");
} catch (NoSuchAlgorithmException e) {
throw new TencentCloudSDKException("HmacSHA256 is not supported." + e.getMessage());
}
SecretKeySpec secretKeySpec = new SecretKeySpec(key, mac.getAlgorithm());
try {
mac.init(secretKeySpec);
} catch (InvalidKeyException e) {
throw new TencentCloudSDKException(e.getClass().getName() + "-" + e.getMessage());
}
return mac.doFinal(msg.getBytes(UTF8));
}
}

View File

@ -0,0 +1,86 @@
/*
* Copyright (c) 2018 THL A29 Limited, a Tencent company. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.xinelu.common.utils.tencentcloudapi.common.exception;
/**
* 腾讯云api sdk异常类
*/
public class TencentCloudSDKException extends Exception {
/**
*
*/
private static final long serialVersionUID = 1L;
/**
* 请求Id,发起请求前的异常这个字段为空
*/
private String requestId;
/**
* Error code, When API returns a failure, it must have an error code.
*/
private String errorCode;
/**
* @param message 异常信息
*/
public TencentCloudSDKException(String message) {
this(message, "");
}
/**
* @param message 异常信息
* @param requestId 请求id
*/
public TencentCloudSDKException(String message, String requestId) {
super(message);
this.requestId = requestId;
}
public TencentCloudSDKException(String message, String requestId, String errorCode) {
super(message);
this.requestId = requestId;
this.errorCode = errorCode;
}
/**
* 获取请求id
* @return requestId
*/
public String getRequestId() {
return requestId;
}
/**
* Get error code
* @return A string represents error code
*/
// public String getErrorCode() {
// return errorCode;
// }
/**
* 格式化输出异常信息
* @return 异常信息
*/
public String toString() {
return "[TencentCloudSDKException]" + "message:" + this.getMessage() + " requestId:" + this.getRequestId();
}
}

View File

@ -0,0 +1,132 @@
/*
* Copyright (c) 2018 THL A29 Limited, a Tencent company. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.xinelu.common.utils.tencentcloudapi.common.http;
import com.squareup.okhttp.Headers;
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.Response;
import com.xinelu.common.utils.tencentcloudapi.common.exception.TencentCloudSDKException;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
/**
* http连接类
*/
public class HttpConnection {
private OkHttpClient client;
public HttpConnection(Integer connTimeout, Integer readTimeout, Integer writeTimeout) {
this.client = new OkHttpClient();
this.client.setConnectTimeout(connTimeout, TimeUnit.SECONDS);
this.client.setReadTimeout(readTimeout, TimeUnit.SECONDS);
this.client.setWriteTimeout(writeTimeout, TimeUnit.SECONDS);
}
public Response doRequest(Request request) throws TencentCloudSDKException {
Response response = null;
try {
response = this.client.newCall(request).execute();
} catch (IOException e) {
throw new TencentCloudSDKException(e.getClass().getName() + "-" + e.getMessage());
}
return response;
}
public Response getRequest(String url) throws TencentCloudSDKException {
Request request = null;
try {
request = new Request.Builder()
.url(url)
.get()
.build();
} catch (IllegalArgumentException e) {
throw new TencentCloudSDKException(e.getClass().getName() + "-" + e.getMessage());
}
return this.doRequest(request);
}
public Response getRequest(String url, Headers headers) throws TencentCloudSDKException {
Request request = null;
try {
request = new Request.Builder()
.url(url)
.headers(headers)
.get()
.build();
} catch (IllegalArgumentException e) {
throw new TencentCloudSDKException(e.getClass().getName() + "-" + e.getMessage());
}
return this.doRequest(request);
}
public Response postRequest(String url, String body) throws TencentCloudSDKException {
MediaType contentType = MediaType.parse("application/x-www-form-urlencoded");
Request request = null;
try {
request = new Request.Builder()
.url(url)
.post(RequestBody.create(contentType, body))
.build();
} catch (IllegalArgumentException e) {
throw new TencentCloudSDKException(e.getClass().getName() + "-" + e.getMessage());
}
return this.doRequest(request);
}
public Response postRequest(String url, String body, Headers headers) throws TencentCloudSDKException {
MediaType contentType = MediaType.parse(headers.get("Content-Type"));
Request request = null;
try {
request = new Request.Builder()
.url(url)
.post(RequestBody.create(contentType, body))
.headers(headers)
.build();
} catch (IllegalArgumentException e) {
throw new TencentCloudSDKException(e.getClass().getName() + "-" + e.getMessage());
}
return this.doRequest(request);
}
public Response postRequest(String url, byte [] body, Headers headers) throws TencentCloudSDKException {
MediaType contentType = MediaType.parse(headers.get("Content-Type"));
Request request = null;
try {
request = new Request.Builder()
.url(url)
.post(RequestBody.create(contentType, body))
.headers(headers)
.build();
} catch (IllegalArgumentException e) {
throw new TencentCloudSDKException(e.getClass().getName() + "-" + e.getMessage());
}
return this.doRequest(request);
}
}

View File

@ -0,0 +1,127 @@
/*
* Copyright (c) 2018 THL A29 Limited, a Tencent company. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.xinelu.common.utils.tencentcloudapi.common.profile;
/**
* client选项类
* @author Administrator
*
*/
public class ClientProfile {
/**
* HmacSHA1签名方法
*/
public static final String SIGN_SHA1 = "HmacSHA1";
/**
* HmacSHA256签名方法
*/
public static final String SIGN_SHA256 = "HmacSHA256";
/**
* Signature Version 3
*/
public static final String SIGN_TC3_256 = "TC3-HMAC-SHA256";
/**
* http相关选项请参考HttpProfile
*/
private HttpProfile httpProfile;
/**
* 签名方法
*/
private String signMethod;
/**
* If payload is NOT involved in signing process, true means will ignore payload,
* default is false.
*/
private boolean unsignedPayload;
/**
* @param signMethod 签名方法
* @param httpProfile HttpProfile实例
*/
public ClientProfile(String signMethod, HttpProfile httpProfile) {
if (signMethod == null || signMethod.isEmpty()) {
signMethod = SIGN_TC3_256;
}
this.signMethod = signMethod;
this.httpProfile = httpProfile;
this.unsignedPayload = false;
}
public ClientProfile(String signMethod) {
this(signMethod, new HttpProfile());
}
public ClientProfile() {
this(ClientProfile.SIGN_TC3_256, new HttpProfile());
}
/**
* 设置签名方法
* @param signMethod
*/
public void setSignMethod(String signMethod) {
this.signMethod = signMethod;
}
/**
* 设置http选项
* @param httpProfile 参考HttpProfile
*/
public void setHttpProfile(HttpProfile httpProfile) {
this.httpProfile = httpProfile;
}
/**
* 获取签名方法
* @return 签名方法
*/
public String getSignMethod() {
return this.signMethod;
}
/**
* 获取HttpProfile实例
* @return HttpProfile实例
*/
public HttpProfile getHttpProfile() {
return this.httpProfile;
}
/**
* Set the flag of whether payload should be ignored.
* Only has effect when request method is POST.
* @param flag
*/
public void setUnsignedPayload(boolean flag) {
this.unsignedPayload = flag;
}
/**
* Get the flag of whether payload is ignored.
* @return
*/
public boolean isUnsignedPayload() {
return this.unsignedPayload;
}
}

View File

@ -0,0 +1,185 @@
/*
* Copyright (c) 2018 THL A29 Limited, a Tencent company. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.xinelu.common.utils.tencentcloudapi.common.profile;
/**
* http选项类
*/
public class HttpProfile {
/**
* https协议
*/
public static final String REQ_HTTPS = "https://";
/**
* http协议
*/
public static final String REQ_HTTP = "http://";
/**
* post请求
*/
public static final String REQ_POST = "POST";
/**
* get请求
*/
public static final String REQ_GET = "GET";
/**
* 时间单位1分钟 60s
*/
public static final int TM_MINUTE = 60;
/**
* 请求方法
*/
private String reqMethod;
/**
* 请求域名
*/
private String endpoint;
/**
* 请求协议
*/
private String protocol;
/**
* 读超时时间
*/
private int readTimeout;
/**
* 写超时时间
*/
private int writeTimeout;
/**
* 连接超时时间
*/
private int connTimeout;
public HttpProfile() {
this.reqMethod = HttpProfile.REQ_POST;
this.endpoint = null;
this.protocol = HttpProfile.REQ_HTTPS;
this.readTimeout = 0;
this.writeTimeout = 0;
this.connTimeout = HttpProfile.TM_MINUTE;
}
/**
* 设置请求方法
* @param reqMethod 请求方法
*/
public void setReqMethod(String reqMethod) {
this.reqMethod = reqMethod;
}
/**
* 设置请求域名
* @param endpoint 域名(xx.[region.]tencentcloudapi.com)
*/
public void setEndpoint(String endpoint) {
this.endpoint = endpoint;
}
/**
* 设置读超时时间
* @param readTimeout 读超时时间
*/
public void setReadTimeout(int readTimeout) {
this.readTimeout = readTimeout;
}
/**
* 设置写超时时间
* @param writeTimeout 写超时时间
*/
public void setWriteTimeout(int writeTimeout) {
this.writeTimeout = writeTimeout;
}
/**
* 设置连接超时时间
* @param connTimeout 连接超时时间
*/
public void setConnTimeout(int connTimeout) {
this.connTimeout = connTimeout;
}
/**
* 设置请求协议
* @param protocol 请求协议https:// http://
*/
public void setProtocol(String protocol) {
this.protocol = protocol;
}
/**
* 获取请求方法
* @return reqMethod
*/
public String getReqMethod() {
return this.reqMethod;
}
/**
* 获取请求域名
* @return endpoint
*/
public String getEndpoint() {
return this.endpoint;
}
/**
* 获取读超时时间
* @return readTimeout
*/
public int getReadTimeout() {
return this.readTimeout;
}
/**
* 获取写超时时间
* @return writeTimeout
*/
public int getWriteTimeout() {
return this.writeTimeout;
}
/**
* 获取连接超时时间
* @return connTimeout
*/
public int getConnTimeout() {
return this.connTimeout;
}
/**
* 获取请求协议
* @return protocol
*/
public String getProtocol() {
return this.protocol;
}
}

View File

@ -0,0 +1,24 @@
package com.xinelu.common.utils.tencentcloudapi.trtc.v20190722;
import java.util.Base64;
public class Base64URL {
public static byte[] base64EncodeUrl(byte[] input) {
byte[] base64 = Base64.getEncoder().encode(input);
for (int i = 0; i < base64.length; ++i)
switch (base64[i]) {
case '+':
base64[i] = '*';
break;
case '/':
base64[i] = '-';
break;
case '=':
base64[i] = '_';
break;
default:
break;
}
return base64;
}
}

View File

@ -0,0 +1,312 @@
package com.xinelu.common.utils.tencentcloudapi.trtc.v20190722;
import com.alibaba.fastjson2.JSONObject;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Base64;
import java.util.zip.Deflater;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
public class TLSSigAPIv2 {
final private long sdkappid;
final private String key;
public TLSSigAPIv2(long sdkappid, String key) {
this.sdkappid = sdkappid;
this.key = key;
}
/**
* 功能说明用于签发 TRTC IM 服务中必须要使用的 UserSig 鉴权票据
* <p>
* 参数说明
*
* @param userid - 用户id限制长度为32字节只允许包含大小写英文字母a-zA-Z数字0-9及下划线和连词符
* @param expire - UserSig 票据的过期时间单位是秒比如 86400 代表生成的 UserSig 票据在一天后就无法再使用了
* @return usersig -生成的签名
*/
/**
* Function: Used to issue UserSig that is required by the TRTC and IM services.
* <p>
* Parameter description:
*
* @param userid - User ID. The value can be up to 32 bytes in length and contain letters (a-z and A-Z), digits (0-9), underscores (_), and hyphens (-).
* @param expire - UserSig expiration time, in seconds. For example, 86400 indicates that the generated UserSig will expire one day after being generated.
* @return usersig - Generated signature.
*/
public String genUserSig(String userid, long expire) {
return genUserSig(userid, expire, null);
}
/**
* 功能说明
* 用于签发 TRTC 进房参数中可选的 PrivateMapKey 权限票据
* PrivateMapKey 需要跟 UserSig 一起使用 PrivateMapKey UserSig 有更强的权限控制能力
* - UserSig 只能控制某个 UserID 有无使用 TRTC 服务的权限只要 UserSig 正确其对应的 UserID 可以进出任意房间
* - PrivateMapKey 则是将 UserID 的权限控制的更加严格包括能不能进入某个房间能不能在该房间里上行音视频等等
* 如果要开启 PrivateMapKey 严格权限位校验需要在实时音视频控制台/应用管理/应用信息中打开启动权限密钥开关
* <p>
* 参数说明
*
* @param userid - 用户id限制长度为32字节只允许包含大小写英文字母a-zA-Z数字0-9及下划线和连词符
* @param expire - PrivateMapKey 票据的过期时间单位是秒比如 86400 生成的 PrivateMapKey 票据在一天后就无法再使用了
* @param roomid - 房间号用于指定该 userid 可以进入的房间号
* @param privilegeMap - 权限位使用了一个字节中的 8 个比特位分别代表八个具体的功能权限开关
* - 1 0000 0001 = 1创建房间的权限
* - 2 0000 0010 = 2加入房间的权限
* - 3 0000 0100 = 4发送语音的权限
* - 4 0000 1000 = 8接收语音的权限
* - 5 0001 0000 = 16发送视频的权限
* - 6 0010 0000 = 32接收视频的权限
* - 7 0100 0000 = 64发送辅路也就是屏幕分享视频的权限
* - 8 1000 0000 = 200接收辅路也就是屏幕分享视频的权限
* - privilegeMap == 1111 1111 == 255 代表该 userid 在该 roomid 房间内的所有功能权限
* - privilegeMap == 0010 1010 == 42 代表该 userid 拥有加入房间和接收音视频数据的权限但不具备其他权限
* @return usersig - 生成带userbuf的签名
*/
/**
* Function:
* Used to issue PrivateMapKey that is optional for room entry.
* PrivateMapKey must be used together with UserSig but with more powerful permission control capabilities.
* - UserSig can only control whether a UserID has permission to use the TRTC service. As long as the UserSig is correct, the user with the corresponding UserID can enter or leave any room.
* - PrivateMapKey specifies more stringent permissions for a UserID, including whether the UserID can be used to enter a specific room and perform audio/video upstreaming in the room.
* To enable stringent PrivateMapKey permission bit verification, you need to enable permission key in TRTC console > Application Management > Application Info.
*
* Parameter description:
*
* @param userid - User ID. The value can be up to 32 bytes in length and contain letters (a-z and A-Z), digits (0-9), underscores (_), and hyphens (-).
* @param roomid - ID of the room to which the specified UserID can enter.
* @param expire - PrivateMapKey expiration time, in seconds. For example, 86400 indicates that the generated PrivateMapKey will expire one day after being generated.
* @param privilegeMap - Permission bits. Eight bits in the same byte are used as the permission switches of eight specific features:
* - Bit 1: 0000 0001 = 1, permission for room creation
* - Bit 2: 0000 0010 = 2, permission for room entry
* - Bit 3: 0000 0100 = 4, permission for audio sending
* - Bit 4: 0000 1000 = 8, permission for audio receiving
* - Bit 5: 0001 0000 = 16, permission for video sending
* - Bit 6: 0010 0000 = 32, permission for video receiving
* - Bit 7: 0100 0000 = 64, permission for substream video sending (screen sharing)
* - Bit 8: 1000 0000 = 200, permission for substream video receiving (screen sharing)
* - privilegeMap == 1111 1111 == 255: Indicates that the UserID has all feature permissions of the room specified by roomid.
* - privilegeMap == 0010 1010 == 42: Indicates that the UserID has only the permissions to enter the room and receive audio/video data.
* @return usersig - Generate signature with userbuf
*/
public String genPrivateMapKey(String userid, long expire, long roomid, long privilegeMap) {
byte[] userbuf = genUserBuf(userid, roomid, expire, privilegeMap, 0, ""); //生成userbuf
return genUserSig(userid, expire, userbuf);
}
/**
* 功能说明
* 用于签发 TRTC 进房参数中可选的 PrivateMapKey 权限票据
* PrivateMapKey 需要跟 UserSig 一起使用 PrivateMapKey UserSig 有更强的权限控制能力
* - UserSig 只能控制某个 UserID 有无使用 TRTC 服务的权限只要 UserSig 正确其对应的 UserID 可以进出任意房间
* - PrivateMapKey 则是将 UserID 的权限控制的更加严格包括能不能进入某个房间能不能在该房间里上行音视频等等
* 如果要开启 PrivateMapKey 严格权限位校验需要在实时音视频控制台/应用管理/应用信息中打开启动权限密钥开关
* <p>
* 参数说明
*
* @param userid - 用户id限制长度为32字节只允许包含大小写英文字母a-zA-Z数字0-9及下划线和连词符
* @param expire - PrivateMapKey 票据的过期时间单位是秒比如 86400 生成的 PrivateMapKey 票据在一天后就无法再使用了
* @param roomstr - 字符串房间号用于指定该 userid 可以进入的房间号
* @param privilegeMap - 权限位使用了一个字节中的 8 个比特位分别代表八个具体的功能权限开关
* - 1 0000 0001 = 1创建房间的权限
* - 2 0000 0010 = 2加入房间的权限
* - 3 0000 0100 = 4发送语音的权限
* - 4 0000 1000 = 8接收语音的权限
* - 5 0001 0000 = 16发送视频的权限
* - 6 0010 0000 = 32接收视频的权限
* - 7 0100 0000 = 64发送辅路也就是屏幕分享视频的权限
* - 8 1000 0000 = 200接收辅路也就是屏幕分享视频的权限
* - privilegeMap == 1111 1111 == 255 代表该 userid 在该 roomid 房间内的所有功能权限
* - privilegeMap == 0010 1010 == 42 代表该 userid 拥有加入房间和接收音视频数据的权限但不具备其他权限
* @return usersig - 生成带userbuf的签名
*/
/**
* Function:
* Used to issue PrivateMapKey that is optional for room entry.
* PrivateMapKey must be used together with UserSig but with more powerful permission control capabilities.
* - UserSig can only control whether a UserID has permission to use the TRTC service. As long as the UserSig is correct, the user with the corresponding UserID can enter or leave any room.
* - PrivateMapKey specifies more stringent permissions for a UserID, including whether the UserID can be used to enter a specific room and perform audio/video upstreaming in the room.
* To enable stringent PrivateMapKey permission bit verification, you need to enable permission key in TRTC console > Application Management > Application Info.
*
* Parameter description:
*
*
* @param userid - User ID. The value can be up to 32 bytes in length and contain letters (a-z and A-Z), digits (0-9), underscores (_), and hyphens (-).
* @param roomid - ID of the room to which the specified UserID can enter.
* @param expire - PrivateMapKey expiration time, in seconds. For example, 86400 indicates that the generated PrivateMapKey will expire one day after being generated.
* @param privilegeMap - Permission bits. Eight bits in the same byte are used as the permission switches of eight specific features:
* - Bit 1: 0000 0001 = 1, permission for room creation
* - Bit 2: 0000 0010 = 2, permission for room entry
* - Bit 3: 0000 0100 = 4, permission for audio sending
* - Bit 4: 0000 1000 = 8, permission for audio receiving
* - Bit 5: 0001 0000 = 16, permission for video sending
* - Bit 6: 0010 0000 = 32, permission for video receiving
* - Bit 7: 0100 0000 = 64, permission for substream video sending (screen sharing)
* - Bit 8: 1000 0000 = 200, permission for substream video receiving (screen sharing)
* - privilegeMap == 1111 1111 == 255: Indicates that the UserID has all feature permissions of the room specified by roomid.
* - privilegeMap == 0010 1010 == 42: Indicates that the UserID has only the permissions to enter the room and receive audio/video data.
* @return usersig - Generate signature with userbuf
*/
public String genPrivateMapKeyWithStringRoomID(String userid, long expire, String roomstr, long privilegeMap) {
byte[] userbuf = genUserBuf(userid, 0, expire, privilegeMap, 0, roomstr); //生成userbuf
return genUserSig(userid, expire, userbuf);
}
private String hmacsha256(String identifier, long currTime, long expire, String base64Userbuf) {
String contentToBeSigned = "TLS.identifier:" + identifier + "\n"
+ "TLS.sdkappid:" + sdkappid + "\n"
+ "TLS.time:" + currTime + "\n"
+ "TLS.expire:" + expire + "\n";
if (null != base64Userbuf) {
contentToBeSigned += "TLS.userbuf:" + base64Userbuf + "\n";
}
try {
byte[] byteKey = key.getBytes(StandardCharsets.UTF_8);
Mac hmac = Mac.getInstance("HmacSHA256");
SecretKeySpec keySpec = new SecretKeySpec(byteKey, "HmacSHA256");
hmac.init(keySpec);
byte[] byteSig = hmac.doFinal(contentToBeSigned.getBytes(StandardCharsets.UTF_8));
return (Base64.getEncoder().encodeToString(byteSig)).replaceAll("\\s*", "");
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
return "";
}
}
private String genUserSig(String userid, long expire, byte[] userbuf) {
long currTime = System.currentTimeMillis() / 1000;
JSONObject sigDoc = new JSONObject();
sigDoc.put("TLS.ver", "2.0");
sigDoc.put("TLS.identifier", userid);
sigDoc.put("TLS.sdkappid", sdkappid);
sigDoc.put("TLS.expire", expire);
sigDoc.put("TLS.time", currTime);
String base64UserBuf = null;
if (null != userbuf) {
base64UserBuf = Base64.getEncoder().encodeToString(userbuf).replaceAll("\\s*", "");
sigDoc.put("TLS.userbuf", base64UserBuf);
}
String sig = hmacsha256(userid, currTime, expire, base64UserBuf);
if (sig.length() == 0) {
return "";
}
sigDoc.put("TLS.sig", sig);
Deflater compressor = new Deflater();
compressor.setInput(sigDoc.toString().getBytes(StandardCharsets.UTF_8));
compressor.finish();
byte[] compressedBytes = new byte[2048];
int compressedBytesLength = compressor.deflate(compressedBytes);
compressor.end();
return (new String(Base64URL.base64EncodeUrl(Arrays.copyOfRange(compressedBytes,
0, compressedBytesLength)))).replaceAll("\\s*", "");
}
public byte[] genUserBuf(String account, long dwAuthID, long dwExpTime,
long dwPrivilegeMap, long dwAccountType, String RoomStr) {
//视频校验位需要用到的字段,按照网络字节序放入buf中
/*
cVer unsigned char/1 版本号填0
wAccountLen unsigned short /2 第三方自己的帐号长度
account wAccountLen 第三方自己的帐号字符
dwSdkAppid unsigned int/4 sdkappid
dwAuthID unsigned int/4 群组号码
dwExpTime unsigned int/4 过期时间 直接使用填入的值
dwPrivilegeMap unsigned int/4 权限位主播0xff观众0xab
dwAccountType unsigned int/4 第三方帐号类型
*/
//The fields required for the video check digit are placed in buf according to the network byte order.
/*
cVer unsigned char/1 Version number, fill in 0
wAccountLen unsigned short /2 Third party's own account length
account wAccountLen Third party's own account characters
dwSdkAppid unsigned int/4 sdkappid
dwAuthID unsigned int/4 group number
dwExpTime unsigned int/4 Expiration time , use the filled value directly
dwPrivilegeMap unsigned int/4 Permission bits, host 0xff, audience 0xab
dwAccountType unsigned int/4 Third-party account type
*/
int accountLength = account.length();
int roomStrLength = RoomStr.length();
int offset = 0;
int bufLength = 1 + 2 + accountLength + 20 ;
if (roomStrLength > 0) {
bufLength = bufLength + 2 + roomStrLength;
}
byte[] userbuf = new byte[bufLength];
//cVer
if (roomStrLength > 0) {
userbuf[offset++] = 1;
} else {
userbuf[offset++] = 0;
}
//wAccountLen
userbuf[offset++] = (byte) ((accountLength & 0xFF00) >> 8);
userbuf[offset++] = (byte) (accountLength & 0x00FF);
//account
for (; offset < 3 + accountLength; ++offset) {
userbuf[offset] = (byte) account.charAt(offset - 3);
}
//dwSdkAppid
userbuf[offset++] = (byte) ((sdkappid & 0xFF000000) >> 24);
userbuf[offset++] = (byte) ((sdkappid & 0x00FF0000) >> 16);
userbuf[offset++] = (byte) ((sdkappid & 0x0000FF00) >> 8);
userbuf[offset++] = (byte) (sdkappid & 0x000000FF);
//dwAuthId,房间号
//dwAuthId, room number
userbuf[offset++] = (byte) ((dwAuthID & 0xFF000000) >> 24);
userbuf[offset++] = (byte) ((dwAuthID & 0x00FF0000) >> 16);
userbuf[offset++] = (byte) ((dwAuthID & 0x0000FF00) >> 8);
userbuf[offset++] = (byte) (dwAuthID & 0x000000FF);
//expire过期时间,当前时间 + 有效期单位
//expire,Expiration time, current time + validity period (unit: seconds)
long currTime = System.currentTimeMillis() / 1000;
long expire = currTime + dwExpTime;
userbuf[offset++] = (byte) ((expire & 0xFF000000) >> 24);
userbuf[offset++] = (byte) ((expire & 0x00FF0000) >> 16);
userbuf[offset++] = (byte) ((expire & 0x0000FF00) >> 8);
userbuf[offset++] = (byte) (expire & 0x000000FF);
//dwPrivilegeMap权限位
//dwPrivilegeMapPermission bits
userbuf[offset++] = (byte) ((dwPrivilegeMap & 0xFF000000) >> 24);
userbuf[offset++] = (byte) ((dwPrivilegeMap & 0x00FF0000) >> 16);
userbuf[offset++] = (byte) ((dwPrivilegeMap & 0x0000FF00) >> 8);
userbuf[offset++] = (byte) (dwPrivilegeMap & 0x000000FF);
//dwAccountType账户类型
//dwAccountTypeaccount type
userbuf[offset++] = (byte) ((dwAccountType & 0xFF000000) >> 24);
userbuf[offset++] = (byte) ((dwAccountType & 0x00FF0000) >> 16);
userbuf[offset++] = (byte) ((dwAccountType & 0x0000FF00) >> 8);
userbuf[offset++] = (byte) (dwAccountType & 0x000000FF);
if (roomStrLength > 0) {
//roomStrLen
userbuf[offset++] = (byte) ((roomStrLength & 0xFF00) >> 8);
userbuf[offset++] = (byte) (roomStrLength & 0x00FF);
//roomStr
for (; offset < bufLength; ++offset) {
userbuf[offset] = (byte) RoomStr.charAt(offset - (bufLength - roomStrLength));
}
}
return userbuf;
}
}

View File

@ -0,0 +1,90 @@
/*
* Copyright (c) 2017-2018 THL A29 Limited, a Tencent company. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.xinelu.common.utils.tencentcloudapi.trtc.v20190722;
import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken;
import com.xinelu.common.utils.tencentcloudapi.common.AbstractClient;
import com.xinelu.common.utils.tencentcloudapi.common.Credential;
import com.xinelu.common.utils.tencentcloudapi.common.JsonResponseModel;
import com.xinelu.common.utils.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.xinelu.common.utils.tencentcloudapi.common.profile.ClientProfile;
import com.xinelu.common.utils.tencentcloudapi.trtc.v20190722.models.DissolveRoomRequest;
import com.xinelu.common.utils.tencentcloudapi.trtc.v20190722.models.DissolveRoomResponse;
import com.xinelu.common.utils.tencentcloudapi.trtc.v20190722.models.KickOutUserRequest;
import com.xinelu.common.utils.tencentcloudapi.trtc.v20190722.models.KickOutUserResponse;
import java.lang.reflect.Type;
public class TrtcClient extends AbstractClient {
private static String endpoint = "trtc.tencentcloudapi.com";
private static String version = "2019-07-22";
/**
* 构造client
* @param credential 认证信息实例
* @param region 产品地域
*/
public TrtcClient(Credential credential, String region) {
this(credential, region, new ClientProfile());
}
/**
* 构造client
* @param credential 认证信息实例
* @param region 产品地域
* @param profile 配置实例
*/
public TrtcClient(Credential credential, String region, ClientProfile profile) {
super(TrtcClient.endpoint, TrtcClient.version, credential, region, profile);
}
/**
*接口说明把房间所有用户从房间踢出解散房间支持 TRTC SDK 6.6及以上版本包括AndroidiOSWindows macOS
* @param req DissolveRoomRequest
* @return DissolveRoomResponse
* @throws TencentCloudSDKException
*/
public DissolveRoomResponse DissolveRoom(DissolveRoomRequest req) throws TencentCloudSDKException {
JsonResponseModel<DissolveRoomResponse> rsp = null;
try {
Type type = new TypeToken<JsonResponseModel<DissolveRoomResponse>>() {
}.getType();
rsp = gson.fromJson(this.internalRequest(req, "DissolveRoom"), type);
} catch (JsonSyntaxException e) {
throw new TencentCloudSDKException(e.getMessage());
}
return rsp.response;
}
/**
*接口说明将用户从房间踢出支持 TRTC SDK 6.6及以上版本包括AndroidiOSWindows macOS
* @param req KickOutUserRequest
* @return KickOutUserResponse
* @throws TencentCloudSDKException
*/
public KickOutUserResponse KickOutUser(KickOutUserRequest req) throws TencentCloudSDKException{
JsonResponseModel<KickOutUserResponse> rsp = null;
try {
Type type = new TypeToken<JsonResponseModel<KickOutUserResponse>>() {
}.getType();
rsp = gson.fromJson(this.internalRequest(req, "KickOutUser"), type);
} catch (JsonSyntaxException e) {
throw new TencentCloudSDKException(e.getMessage());
}
return rsp.response;
}
}

View File

@ -0,0 +1,80 @@
/*
* Copyright (c) 2017-2018 THL A29 Limited, a Tencent company. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.xinelu.common.utils.tencentcloudapi.trtc.v20190722.models;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import com.xinelu.common.utils.tencentcloudapi.common.AbstractModel;
import java.util.HashMap;
public class DissolveRoomRequest extends AbstractModel {
/**
* TRTC的SDKAppId
*/
@SerializedName("SdkAppId")
@Expose
private Long SdkAppId;
/**
* 房间号
*/
@SerializedName("RoomId")
@Expose
private Long RoomId;
/**
* 获取TRTC的SDKAppId
* @return SdkAppId TRTC的SDKAppId
*/
public Long getSdkAppId() {
return this.SdkAppId;
}
/**
* 设置TRTC的SDKAppId
* @param SdkAppId TRTC的SDKAppId
*/
public void setSdkAppId(Long SdkAppId) {
this.SdkAppId = SdkAppId;
}
/**
* 获取房间号
* @return RoomId 房间号
*/
public Long getRoomId() {
return this.RoomId;
}
/**
* 设置房间号
* @param RoomId 房间号
*/
public void setRoomId(Long RoomId) {
this.RoomId = RoomId;
}
/**
* 内部实现用户禁止调用
*/
public void toMap(HashMap<String, String> map, String prefix) {
this.setParamSimple(map, prefix + "SdkAppId", this.SdkAppId);
this.setParamSimple(map, prefix + "RoomId", this.RoomId);
}
}

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2017-2018 THL A29 Limited, a Tencent company. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.xinelu.common.utils.tencentcloudapi.trtc.v20190722.models;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import com.xinelu.common.utils.tencentcloudapi.common.AbstractModel;
import java.util.HashMap;
public class DissolveRoomResponse extends AbstractModel {
/**
* 唯一请求 ID每次请求都会返回定位问题时需要提供该次请求的 RequestId
*/
@SerializedName("RequestId")
@Expose
private String RequestId;
/**
* 获取唯一请求 ID每次请求都会返回定位问题时需要提供该次请求的 RequestId
* @return RequestId 唯一请求 ID每次请求都会返回定位问题时需要提供该次请求的 RequestId
*/
public String getRequestId() {
return this.RequestId;
}
/**
* 设置唯一请求 ID每次请求都会返回定位问题时需要提供该次请求的 RequestId
* @param RequestId 唯一请求 ID每次请求都会返回定位问题时需要提供该次请求的 RequestId
*/
public void setRequestId(String RequestId) {
this.RequestId = RequestId;
}
/**
* 内部实现用户禁止调用
*/
public void toMap(HashMap<String, String> map, String prefix) {
this.setParamSimple(map, prefix + "RequestId", this.RequestId);
}
}

View File

@ -0,0 +1,104 @@
/*
* Copyright (c) 2017-2018 THL A29 Limited, a Tencent company. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.xinelu.common.utils.tencentcloudapi.trtc.v20190722.models;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import com.xinelu.common.utils.tencentcloudapi.common.AbstractModel;
import java.util.HashMap;
public class KickOutUserRequest extends AbstractModel {
/**
* TRTC的SDKAppId
*/
@SerializedName("SdkAppId")
@Expose
private Long SdkAppId;
/**
* 房间号
*/
@SerializedName("RoomId")
@Expose
private Long RoomId;
/**
* 要踢的用户列表最多10个
*/
@SerializedName("UserIds")
@Expose
private String [] UserIds;
/**
* 获取TRTC的SDKAppId
* @return SdkAppId TRTC的SDKAppId
*/
public Long getSdkAppId() {
return this.SdkAppId;
}
/**
* 设置TRTC的SDKAppId
* @param SdkAppId TRTC的SDKAppId
*/
public void setSdkAppId(Long SdkAppId) {
this.SdkAppId = SdkAppId;
}
/**
* 获取房间号
* @return RoomId 房间号
*/
public Long getRoomId() {
return this.RoomId;
}
/**
* 设置房间号
* @param RoomId 房间号
*/
public void setRoomId(Long RoomId) {
this.RoomId = RoomId;
}
/**
* 获取要踢的用户列表最多10个
* @return UserIds 要踢的用户列表最多10个
*/
public String [] getUserIds() {
return this.UserIds;
}
/**
* 设置要踢的用户列表最多10个
* @param UserIds 要踢的用户列表最多10个
*/
public void setUserIds(String [] UserIds) {
this.UserIds = UserIds;
}
/**
* 内部实现用户禁止调用
*/
public void toMap(HashMap<String, String> map, String prefix) {
this.setParamSimple(map, prefix + "SdkAppId", this.SdkAppId);
this.setParamSimple(map, prefix + "RoomId", this.RoomId);
this.setParamArraySimple(map, prefix + "UserIds.", this.UserIds);
}
}

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2017-2018 THL A29 Limited, a Tencent company. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.xinelu.common.utils.tencentcloudapi.trtc.v20190722.models;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import com.xinelu.common.utils.tencentcloudapi.common.AbstractModel;
import java.util.HashMap;
public class KickOutUserResponse extends AbstractModel {
/**
* 唯一请求 ID每次请求都会返回定位问题时需要提供该次请求的 RequestId
*/
@SerializedName("RequestId")
@Expose
private String RequestId;
/**
* 获取唯一请求 ID每次请求都会返回定位问题时需要提供该次请求的 RequestId
* @return RequestId 唯一请求 ID每次请求都会返回定位问题时需要提供该次请求的 RequestId
*/
public String getRequestId() {
return this.RequestId;
}
/**
* 设置唯一请求 ID每次请求都会返回定位问题时需要提供该次请求的 RequestId
* @param RequestId 唯一请求 ID每次请求都会返回定位问题时需要提供该次请求的 RequestId
*/
public void setRequestId(String RequestId) {
this.RequestId = RequestId;
}
/**
* 内部实现用户禁止调用
*/
public void toMap(HashMap<String, String> map, String prefix) {
this.setParamSimple(map, prefix + "RequestId", this.RequestId);
}
}

View File

@ -111,7 +111,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
.antMatchers("/login", "/register", "/captchaImage").anonymous()
// 静态资源可匿名访问
.antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
.antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**", "/nurseApplet/**", "/nurseApp/**").permitAll()
.antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**", "/nurseApplet/**", "/nurseApp/**", "/webSocket/**").permitAll()
// 除上面外的所有请求全部需要鉴权认证
.anyRequest().authenticated()
.and()

View File

@ -0,0 +1,33 @@
package com.xinelu.applet.controller.appletscreeningproject;
import com.xinelu.common.core.controller.BaseController;
import com.xinelu.common.core.domain.R;
import com.xinelu.manage.domain.screeningproject.ScreeningProject;
import com.xinelu.manage.service.screeningproject.IScreeningProjectService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import java.util.List;
import javax.annotation.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @description: 项目控制器小程序
* @author: haown
* @create: 2023-03-07 14:23
**/
@RestController
@RequestMapping("/nurseApplet/screening/project")
@Api(tags = "项目控制器-小程序")
public class AppletScreeningProjectController extends BaseController {
@Resource
private IScreeningProjectService projectService;
@ApiOperation("筛查项目列表")
@GetMapping("list")
public R<List<ScreeningProject>> list(ScreeningProject project) {
List<ScreeningProject> list = projectService.findList(project);
return R.ok(list);
}
}

View File

@ -0,0 +1,131 @@
package com.xinelu.applet.controller.appletscreeningrecord;
import com.alibaba.fastjson2.JSONObject;
import com.xinelu.common.annotation.RepeatSubmit;
import com.xinelu.common.constant.ScreeningProjectConstants;
import com.xinelu.common.core.controller.BaseController;
import com.xinelu.common.core.domain.R;
import com.xinelu.common.core.page.TableDataInfo;
import com.xinelu.common.utils.DateUtils;
import com.xinelu.common.utils.StringUtils;
import com.xinelu.manage.dto.screeningrecord.ScreeningApplyDTO;
import com.xinelu.manage.dto.screeningrecord.ScreeningRecordDTO;
import com.xinelu.manage.service.patientinfo.IPatientInfoService;
import com.xinelu.manage.service.screeningrecord.IScreeningRecordService;
import com.xinelu.manage.vo.screeningrecord.ScreeningRecordVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import java.util.List;
import javax.annotation.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Author mengkuiliang
* @Description 筛查预约控制器
* @Date 2023-01-29 13:57
* @Param
* @return
**/
@RestController
@RequestMapping("/nurseApplet/screening/record")
@Api(tags = "筛查预约控制器-小程序")
public class AppletScreeningRecordController extends BaseController {
@Resource
private IScreeningRecordService screeningRecordService;
@Resource
private IPatientInfoService patientService;
@GetMapping("/record")
@ApiOperation(value = "获取筛查结果记录")
public TableDataInfo record(ScreeningRecordDTO query) {
startPage();
query.setScreeningType("1");
query.setScreeningStatus("4");
return getDataTable(screeningRecordService.record(query));
}
@GetMapping("/list")
@ApiOperation(value = "获取列表")
public TableDataInfo list(ScreeningRecordDTO query) {
startPage();
query.setScreeningType("1");
List<ScreeningRecordVo> list = screeningRecordService.list(query);
// 二维码返回
list.forEach(record -> {
StringUtils.isNotEmpty(record.getApplyBarcode());
// TODO 居民申请条码
//record.setApplyBarcode(patientService.getPicToBase64(record.getApplyBarcode()));
});
return getDataTable(list);
}
@PostMapping("/save")
@ApiOperation(value = "预约")
@RepeatSubmit(interval = 2000, message = "请求过于频繁")
public R<String> save(@RequestBody ScreeningApplyDTO body) {
try {
if(!DateUtils.formatDate(body.getApplyStartTime(), "yyyy-MM-dd").equals(DateUtils.formatDate(body.getApplyEndTime(), "yyyy-MM-dd"))) {
return R.fail("预约日期请选择在同一天");
}
return R.ok(screeningRecordService.save(body));
} catch (Exception e) {
return R.fail(e.getMessage());
}
}
@GetMapping("/cancel/{screeningId}")
@ApiOperation(value = "取消预约")
public R<String> cancel(@PathVariable String screeningId) {
// 判断是否已登记
ScreeningRecordVo screeningRecordVo = screeningRecordService.detail(screeningId);
if (StringUtils.equals(screeningRecordVo.getScreeningStatus(), "3") || StringUtils.equals(screeningRecordVo.getScreeningStatus(), "4")) {
return R.fail("该预约已登记,不能取消");
}
screeningRecordService.cancel(screeningId);
return R.ok();
}
@GetMapping("/detail/{screeningId}")
@ApiOperation(value = "获取预约详情")
public R<ScreeningRecordVo> detail(@PathVariable String screeningId) {
ScreeningRecordVo screeningRecordVo = screeningRecordService.detail(screeningId);
if (screeningRecordVo != null) {
// TODO 设置文件类型
//File fileInfo = sysFileService.getFile(screeningRecordVo.getAttachment());
//if (fileInfo != null) {
// screeningRecordVo.setFileType(fileInfo.getSuffix());
//}
if (!StringUtils.contains(screeningRecordVo.getProjectName(), ScreeningProjectConstants.ALZHEIMER)) {
screeningRecordService.getRecordDetail(screeningRecordVo);
}
}
return R.ok(screeningRecordVo);
}
@GetMapping("/getScreening/{registerId}")
@ApiOperation(value = "获取当前预约信息")
public R<ScreeningRecordVo> getScreeningByRegisterId(@PathVariable String registerId) {
return R.ok(screeningRecordService.getScreeningByRegisterId(registerId));
}
@GetMapping("/last/{registerId}/{projectId}")
@ApiOperation(value = "获取最新一次筛查结果")
public R<ScreeningRecordVo> last(@PathVariable String registerId, @PathVariable String projectId) {
ScreeningRecordVo screeningRecordVo = screeningRecordService.last(registerId, projectId);
return R.ok(screeningRecordVo);
}
@GetMapping("/getInfo/{assessRecordId}")
@ApiOperation(value = "推送筛查项目跳转查询推荐详情")
public R<JSONObject> getInfo(@PathVariable("assessRecordId") String assessRecordId) {
JSONObject jsonObject = screeningRecordService.getInfo(assessRecordId);
return R.ok(jsonObject);
}
}

View File

@ -0,0 +1,79 @@
package com.xinelu.applet.controller.videoconsultation;
import cn.hutool.core.util.RandomUtil;
import com.xinelu.common.core.domain.R;
import com.xinelu.common.core.dto.MessageTemplate;
import com.xinelu.common.enums.MessageContentType;
import com.xinelu.common.socket.WebSocketUtils;
import com.xinelu.common.utils.tencentcloudapi.common.Credential;
import com.xinelu.common.utils.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.xinelu.common.utils.tencentcloudapi.common.profile.ClientProfile;
import com.xinelu.common.utils.tencentcloudapi.common.profile.HttpProfile;
import com.xinelu.common.utils.tencentcloudapi.trtc.v20190722.TLSSigAPIv2;
import com.xinelu.common.utils.tencentcloudapi.trtc.v20190722.TrtcClient;
import com.xinelu.common.utils.tencentcloudapi.trtc.v20190722.models.DissolveRoomRequest;
import com.xinelu.common.utils.tencentcloudapi.trtc.v20190722.models.DissolveRoomResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import java.util.Date;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author gaoyu
* @description 远程会诊控制器
* @date 2022-12-07 9:49
*/
@Api(tags = "远程会诊控制器")
@RestController
@RequestMapping("/nurseApplet/consultation")
public class VideoConsultationController {
@Value("${trtc.sdkappid}")
private String sdkappid;
@Value("${trtc.secretid}")
private String secretid;
@Value("${trtc.secretkey}")
private String secretkey;
private final static String ENDPOINT = "trtc.tencentcloudapi.com";
private final static String REGION = "ap-beijing";
@ApiOperation("获取userSig")
@GetMapping("getUserSig/{userId}")
public R<String> getUserSig(@PathVariable String userId) {
TLSSigAPIv2 sigAPIv2 = new TLSSigAPIv2(1600003294, "6b8b57a7eedb92b6646d1c81bd68681ab924e53b52069cd20b0f53c8e3801a18");
String userSig = sigAPIv2.genUserSig(userId, 36000);
return R.ok(userSig);
}
@ApiOperation("开始会诊")
@GetMapping("start/{applyId}")
public R<String> start(@PathVariable String applyId) {
int roomId = RandomUtil.randomInt(1, 1000);
MessageTemplate msg = new MessageTemplate();
msg.setMessage(String.valueOf(roomId));
msg.setToKey(applyId);
msg.setMsgType(MessageContentType.CONSULTATION.name());
msg.setSendTime(new Date());
WebSocketUtils.sendMessage(applyId, msg);
return R.ok(String.valueOf(roomId));
}
@ApiOperation("解散房间")
@GetMapping("dissolveRoom/{roomId}")
public R<?> dissolveRoom(@PathVariable String roomId) throws TencentCloudSDKException {
Credential cred = new Credential(secretid, secretkey);
HttpProfile httpProfile = new HttpProfile();
httpProfile.setEndpoint(ENDPOINT);
ClientProfile clientProfile = new ClientProfile();
clientProfile.setHttpProfile(httpProfile);
TrtcClient client = new TrtcClient(cred, REGION, clientProfile);
String params = "{\"SdkAppId\":" + sdkappid + ",\"RoomId\":" + roomId + "}";
DissolveRoomRequest req = DissolveRoomRequest.fromJsonString(params, DissolveRoomRequest.class);
DissolveRoomResponse resp = client.DissolveRoom(req);
return R.ok(resp.getRequestId());
}
}

View File

@ -0,0 +1,18 @@
package com.xinelu.manage.controller.schedule;
import io.swagger.annotations.ApiModel;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @description: 排班班次控制器
* @author: haown
* @create: 2023-09-21 17:25
**/
@ApiModel(value = "排班班次控制器")
@RestController
@RequestMapping("/system/schedule")
public class ScheduleController {
}

View File

@ -29,7 +29,7 @@ import org.springframework.web.bind.annotation.RestController;
* @create: 2023-01-19 10:49
**/
@RestController
@RequestMapping("/business/project")
@RequestMapping("/system/screening/project")
@Api(tags = "项目控制器")
public class ScreeningProjectController extends BaseController {
@Resource

View File

@ -33,7 +33,7 @@ import org.springframework.web.bind.annotation.RestController;
* @return
**/
@RestController
@RequestMapping("/business/screening")
@RequestMapping("/system/screening/record")
@Api(tags = "筛查预约控制器")
public class ScreeningRecordController extends BaseController {

View File

@ -0,0 +1,85 @@
package com.xinelu.manage.domain.scheduleplan;
import com.xinelu.common.core.domain.BaseEntity;
import java.util.Date;
import lombok.Data;
/**
* 医生排班计划表
* @TableName schedule_plan
*/
@Data
public class SchedulePlan extends BaseEntity {
/**
* 主键
*/
private Long id;
/**
* 医院主键
*/
private Long hospitalId;
/**
* 医院名称
*/
private String hospitalName;
/**
* 所属部门id
*/
private Long departmentId;
/**
* 所属部门名称
*/
private String departmentName;
/**
* 班次主键
*/
private Long scheduleId;
/**
* 班次名称
*/
private String scheduleName;
/**
* 医生主键
*/
private Long doctorId;
/**
* 医生姓名
*/
private String doctorName;
/**
* 排班开始日期
*/
private Date scheduleStartDate;
/**
* 排班结束日期
*/
private Date scheduleEndDate;
/**
* 每人可预约分钟数
*/
private Integer minutesPerPatient;
/**
* 每天可预约人数
*/
private Integer patientsPerDay;
/**
* 出诊地点
*/
private String scheduleAddress;
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,55 @@
package com.xinelu.manage.domain.scheduleplandetail;
import java.io.Serializable;
import java.util.Date;
import lombok.Data;
/**
* 医生排班计划明细表
* @TableName schedule_plan_detail
*/
@Data
public class SchedulePlanDetail implements Serializable {
/**
* 主键
*/
private Long id;
/**
* 排班计划主键
*/
private Long schedulePlanId;
/**
* 医生主键
*/
private Long doctorId;
/**
* 医生姓名
*/
private String doctorName;
/**
* 排班日期
*/
private Date scheduleDate;
/**
* 开始时间
*/
private Date scheduleStartTime;
/**
* 结束时间
*/
private Date scheduleEndTime;
/**
* 预约状态0:未预约1已预约
*/
private String applyState;
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,25 @@
package com.xinelu.manage.mapper.scheduleplan;
import com.xinelu.manage.domain.scheduleplan.SchedulePlan;
/**
* @author haown
* @description 针对表schedule_plan(医生排班计划表)的数据库操作Mapper
* @createDate 2023-09-21 17:17:23
* @Entity com.xinelu.manage.domain.scheduleplan.SchedulePlan
*/
public interface SchedulePlanMapper {
int deleteByPrimaryKey(Long id);
int insert(SchedulePlan record);
int insertSelective(SchedulePlan record);
SchedulePlan selectByPrimaryKey(Long id);
int updateByPrimaryKeySelective(SchedulePlan record);
int updateByPrimaryKey(SchedulePlan record);
}

View File

@ -0,0 +1,25 @@
package com.xinelu.manage.mapper.scheduleplandetail;
import com.xinelu.manage.domain.scheduleplandetail.SchedulePlanDetail;
/**
* @author haown
* @description 针对表schedule_plan_detail(医生排班计划明细表)的数据库操作Mapper
* @createDate 2023-09-21 17:22:22
* @Entity com.xinelu.manage.domain.scheduleplandetail.SchedulePlanDetail
*/
public interface SchedulePlanDetailMapper {
int deleteByPrimaryKey(Long id);
int insert(SchedulePlanDetail record);
int insertSelective(SchedulePlanDetail record);
SchedulePlanDetail selectByPrimaryKey(Long id);
int updateByPrimaryKeySelective(SchedulePlanDetail record);
int updateByPrimaryKey(SchedulePlanDetail record);
}

View File

@ -0,0 +1,10 @@
package com.xinelu.manage.service.scheduleplan;
/**
* @author haown
* @description 针对表schedule_plan(医生排班计划表)的数据库操作Service
* @createDate 2023-09-21 17:16:40
*/
public interface SchedulePlanService {
}

View File

@ -0,0 +1,18 @@
package com.xinelu.manage.service.scheduleplan.impl;
import com.xinelu.manage.service.scheduleplan.SchedulePlanService;
import org.springframework.stereotype.Service;
/**
* @author haown
* @description 针对表schedule_plan(医生排班计划表)的数据库操作Service实现
* @createDate 2023-09-21 17:16:40
*/
@Service
public class SchedulePlanServiceImpl implements SchedulePlanService{
}

View File

@ -0,0 +1,10 @@
package com.xinelu.manage.service.scheduleplandetail;
/**
* @author haown
* @description 针对表schedule_plan_detail(医生排班计划明细表)的数据库操作Service
* @createDate 2023-09-21 17:21:38
*/
public interface SchedulePlanDetailService {
}

View File

@ -0,0 +1,18 @@
package com.xinelu.manage.service.scheduleplandetail.impl;
import com.xinelu.manage.service.scheduleplandetail.SchedulePlanDetailService;
import org.springframework.stereotype.Service;
/**
* @author haown
* @description 针对表schedule_plan_detail(医生排班计划明细表)的数据库操作Service实现
* @createDate 2023-09-21 17:21:38
*/
@Service
public class SchedulePlanDetailServiceImpl implements SchedulePlanDetailService{
}

View File

@ -0,0 +1,187 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xinelu.manage.mapper.scheduleplan.SchedulePlanMapper">
<resultMap id="BaseResultMap" type="com.xinelu.manage.domain.scheduleplan.SchedulePlan">
<id property="id" column="id" jdbcType="BIGINT"/>
<result property="hospitalId" column="hospital_id" jdbcType="BIGINT"/>
<result property="hospitalName" column="hospital_name" jdbcType="VARCHAR"/>
<result property="departmentId" column="department_id" jdbcType="BIGINT"/>
<result property="departmentName" column="department_name" jdbcType="VARCHAR"/>
<result property="scheduleId" column="schedule_id" jdbcType="BIGINT"/>
<result property="scheduleName" column="schedule_name" jdbcType="VARCHAR"/>
<result property="doctorId" column="doctor_id" jdbcType="BIGINT"/>
<result property="doctorName" column="doctor_name" jdbcType="VARCHAR"/>
<result property="scheduleStartDate" column="schedule_start_date" jdbcType="DATE"/>
<result property="scheduleEndDate" column="schedule_end_date" jdbcType="DATE"/>
<result property="minutesPerPatient" column="minutes_per_patient" jdbcType="INTEGER"/>
<result property="patientsPerDay" column="patients_per_day" jdbcType="INTEGER"/>
<result property="scheduleAddress" column="schedule_address" jdbcType="VARCHAR"/>
<result property="createBy" column="create_by" jdbcType="VARCHAR"/>
<result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
<result property="updateBy" column="update_by" jdbcType="VARCHAR"/>
<result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/>
</resultMap>
<sql id="Base_Column_List">
id,hospital_id,hospital_name,
department_id,department_name,schedule_id,
schedule_name,doctor_id,doctor_name,
schedule_start_date,schedule_end_date,minutes_per_patient,
patients_per_day,schedule_address,create_by,
create_time,update_by,update_time
</sql>
<select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from schedule_plan
where id = #{id,jdbcType=BIGINT}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.Long">
delete from schedule_plan
where id = #{id,jdbcType=BIGINT}
</delete>
<insert id="insert" keyColumn="id" keyProperty="id" parameterType="com.xinelu.manage.domain.scheduleplan.SchedulePlan" useGeneratedKeys="true">
insert into schedule_plan
( id,hospital_id,hospital_name
,department_id,department_name,schedule_id
,schedule_name,doctor_id,doctor_name
,schedule_start_date,schedule_end_date,minutes_per_patient
,patients_per_day,schedule_address,create_by
,create_time,update_by,update_time
)
values (#{id,jdbcType=BIGINT},#{hospitalId,jdbcType=BIGINT},#{hospitalName,jdbcType=VARCHAR}
,#{departmentId,jdbcType=BIGINT},#{departmentName,jdbcType=VARCHAR},#{scheduleId,jdbcType=BIGINT}
,#{scheduleName,jdbcType=VARCHAR},#{doctorId,jdbcType=BIGINT},#{doctorName,jdbcType=VARCHAR}
,#{scheduleStartDate,jdbcType=DATE},#{scheduleEndDate,jdbcType=DATE},#{minutesPerPatient,jdbcType=INTEGER}
,#{patientsPerDay,jdbcType=INTEGER},#{scheduleAddress,jdbcType=VARCHAR},#{createBy,jdbcType=VARCHAR}
,#{createTime,jdbcType=TIMESTAMP},#{updateBy,jdbcType=VARCHAR},#{updateTime,jdbcType=TIMESTAMP}
)
</insert>
<insert id="insertSelective" keyColumn="id" keyProperty="id" parameterType="com.xinelu.manage.domain.scheduleplan.SchedulePlan" useGeneratedKeys="true">
insert into schedule_plan
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">id,</if>
<if test="hospitalId != null">hospital_id,</if>
<if test="hospitalName != null">hospital_name,</if>
<if test="departmentId != null">department_id,</if>
<if test="departmentName != null">department_name,</if>
<if test="scheduleId != null">schedule_id,</if>
<if test="scheduleName != null">schedule_name,</if>
<if test="doctorId != null">doctor_id,</if>
<if test="doctorName != null">doctor_name,</if>
<if test="scheduleStartDate != null">schedule_start_date,</if>
<if test="scheduleEndDate != null">schedule_end_date,</if>
<if test="minutesPerPatient != null">minutes_per_patient,</if>
<if test="patientsPerDay != null">patients_per_day,</if>
<if test="scheduleAddress != null">schedule_address,</if>
<if test="createBy != null">create_by,</if>
<if test="createTime != null">create_time,</if>
<if test="updateBy != null">update_by,</if>
<if test="updateTime != null">update_time,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">#{id,jdbcType=BIGINT},</if>
<if test="hospitalId != null">#{hospitalId,jdbcType=BIGINT},</if>
<if test="hospitalName != null">#{hospitalName,jdbcType=VARCHAR},</if>
<if test="departmentId != null">#{departmentId,jdbcType=BIGINT},</if>
<if test="departmentName != null">#{departmentName,jdbcType=VARCHAR},</if>
<if test="scheduleId != null">#{scheduleId,jdbcType=BIGINT},</if>
<if test="scheduleName != null">#{scheduleName,jdbcType=VARCHAR},</if>
<if test="doctorId != null">#{doctorId,jdbcType=BIGINT},</if>
<if test="doctorName != null">#{doctorName,jdbcType=VARCHAR},</if>
<if test="scheduleStartDate != null">#{scheduleStartDate,jdbcType=DATE},</if>
<if test="scheduleEndDate != null">#{scheduleEndDate,jdbcType=DATE},</if>
<if test="minutesPerPatient != null">#{minutesPerPatient,jdbcType=INTEGER},</if>
<if test="patientsPerDay != null">#{patientsPerDay,jdbcType=INTEGER},</if>
<if test="scheduleAddress != null">#{scheduleAddress,jdbcType=VARCHAR},</if>
<if test="createBy != null">#{createBy,jdbcType=VARCHAR},</if>
<if test="createTime != null">#{createTime,jdbcType=TIMESTAMP},</if>
<if test="updateBy != null">#{updateBy,jdbcType=VARCHAR},</if>
<if test="updateTime != null">#{updateTime,jdbcType=TIMESTAMP},</if>
</trim>
</insert>
<update id="updateByPrimaryKeySelective" parameterType="com.xinelu.manage.domain.scheduleplan.SchedulePlan">
update schedule_plan
<set>
<if test="hospitalId != null">
hospital_id = #{hospitalId,jdbcType=BIGINT},
</if>
<if test="hospitalName != null">
hospital_name = #{hospitalName,jdbcType=VARCHAR},
</if>
<if test="departmentId != null">
department_id = #{departmentId,jdbcType=BIGINT},
</if>
<if test="departmentName != null">
department_name = #{departmentName,jdbcType=VARCHAR},
</if>
<if test="scheduleId != null">
schedule_id = #{scheduleId,jdbcType=BIGINT},
</if>
<if test="scheduleName != null">
schedule_name = #{scheduleName,jdbcType=VARCHAR},
</if>
<if test="doctorId != null">
doctor_id = #{doctorId,jdbcType=BIGINT},
</if>
<if test="doctorName != null">
doctor_name = #{doctorName,jdbcType=VARCHAR},
</if>
<if test="scheduleStartDate != null">
schedule_start_date = #{scheduleStartDate,jdbcType=DATE},
</if>
<if test="scheduleEndDate != null">
schedule_end_date = #{scheduleEndDate,jdbcType=DATE},
</if>
<if test="minutesPerPatient != null">
minutes_per_patient = #{minutesPerPatient,jdbcType=INTEGER},
</if>
<if test="patientsPerDay != null">
patients_per_day = #{patientsPerDay,jdbcType=INTEGER},
</if>
<if test="scheduleAddress != null">
schedule_address = #{scheduleAddress,jdbcType=VARCHAR},
</if>
<if test="createBy != null">
create_by = #{createBy,jdbcType=VARCHAR},
</if>
<if test="createTime != null">
create_time = #{createTime,jdbcType=TIMESTAMP},
</if>
<if test="updateBy != null">
update_by = #{updateBy,jdbcType=VARCHAR},
</if>
<if test="updateTime != null">
update_time = #{updateTime,jdbcType=TIMESTAMP},
</if>
</set>
where id = #{id,jdbcType=BIGINT}
</update>
<update id="updateByPrimaryKey" parameterType="com.xinelu.manage.domain.scheduleplan.SchedulePlan">
update schedule_plan
set
hospital_id = #{hospitalId,jdbcType=BIGINT},
hospital_name = #{hospitalName,jdbcType=VARCHAR},
department_id = #{departmentId,jdbcType=BIGINT},
department_name = #{departmentName,jdbcType=VARCHAR},
schedule_id = #{scheduleId,jdbcType=BIGINT},
schedule_name = #{scheduleName,jdbcType=VARCHAR},
doctor_id = #{doctorId,jdbcType=BIGINT},
doctor_name = #{doctorName,jdbcType=VARCHAR},
schedule_start_date = #{scheduleStartDate,jdbcType=DATE},
schedule_end_date = #{scheduleEndDate,jdbcType=DATE},
minutes_per_patient = #{minutesPerPatient,jdbcType=INTEGER},
patients_per_day = #{patientsPerDay,jdbcType=INTEGER},
schedule_address = #{scheduleAddress,jdbcType=VARCHAR},
create_by = #{createBy,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=TIMESTAMP},
update_by = #{updateBy,jdbcType=VARCHAR},
update_time = #{updateTime,jdbcType=TIMESTAMP}
where id = #{id,jdbcType=BIGINT}
</update>
</mapper>

View File

@ -0,0 +1,106 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xinelu.manage.mapper.scheduleplandetail.SchedulePlanDetailMapper">
<resultMap id="BaseResultMap" type="com.xinelu.manage.domain.scheduleplandetail.SchedulePlanDetail">
<id property="id" column="id" jdbcType="BIGINT"/>
<result property="schedulePlanId" column="schedule_plan_id" jdbcType="BIGINT"/>
<result property="doctorId" column="doctor_id" jdbcType="BIGINT"/>
<result property="doctorName" column="doctor_name" jdbcType="VARCHAR"/>
<result property="scheduleDate" column="schedule_date" jdbcType="DATE"/>
<result property="scheduleStartTime" column="schedule_start_time" jdbcType="TIME"/>
<result property="scheduleEndTime" column="schedule_end_time" jdbcType="TIME"/>
<result property="applyState" column="apply_state" jdbcType="VARCHAR"/>
</resultMap>
<sql id="Base_Column_List">
id,schedule_plan_id,doctor_id,
doctor_name,schedule_date,schedule_start_time,
schedule_end_time,apply_state
</sql>
<select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from schedule_plan_detail
where id = #{id,jdbcType=BIGINT}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.Long">
delete from schedule_plan_detail
where id = #{id,jdbcType=BIGINT}
</delete>
<insert id="insert" keyColumn="id" keyProperty="id" parameterType="com.xinelu.manage.domain.scheduleplandetail.SchedulePlanDetail" useGeneratedKeys="true">
insert into schedule_plan_detail
( id,schedule_plan_id,doctor_id
,doctor_name,schedule_date,schedule_start_time
,schedule_end_time,apply_state)
values (#{id,jdbcType=BIGINT},#{schedulePlanId,jdbcType=BIGINT},#{doctorId,jdbcType=BIGINT}
,#{doctorName,jdbcType=VARCHAR},#{scheduleDate,jdbcType=DATE},#{scheduleStartTime,jdbcType=TIME}
,#{scheduleEndTime,jdbcType=TIME},#{applyState,jdbcType=VARCHAR})
</insert>
<insert id="insertSelective" keyColumn="id" keyProperty="id" parameterType="com.xinelu.manage.domain.scheduleplandetail.SchedulePlanDetail" useGeneratedKeys="true">
insert into schedule_plan_detail
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">id,</if>
<if test="schedulePlanId != null">schedule_plan_id,</if>
<if test="doctorId != null">doctor_id,</if>
<if test="doctorName != null">doctor_name,</if>
<if test="scheduleDate != null">schedule_date,</if>
<if test="scheduleStartTime != null">schedule_start_time,</if>
<if test="scheduleEndTime != null">schedule_end_time,</if>
<if test="applyState != null">apply_state,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">#{id,jdbcType=BIGINT},</if>
<if test="schedulePlanId != null">#{schedulePlanId,jdbcType=BIGINT},</if>
<if test="doctorId != null">#{doctorId,jdbcType=BIGINT},</if>
<if test="doctorName != null">#{doctorName,jdbcType=VARCHAR},</if>
<if test="scheduleDate != null">#{scheduleDate,jdbcType=DATE},</if>
<if test="scheduleStartTime != null">#{scheduleStartTime,jdbcType=TIME},</if>
<if test="scheduleEndTime != null">#{scheduleEndTime,jdbcType=TIME},</if>
<if test="applyState != null">#{applyState,jdbcType=VARCHAR},</if>
</trim>
</insert>
<update id="updateByPrimaryKeySelective" parameterType="com.xinelu.manage.domain.scheduleplandetail.SchedulePlanDetail">
update schedule_plan_detail
<set>
<if test="schedulePlanId != null">
schedule_plan_id = #{schedulePlanId,jdbcType=BIGINT},
</if>
<if test="doctorId != null">
doctor_id = #{doctorId,jdbcType=BIGINT},
</if>
<if test="doctorName != null">
doctor_name = #{doctorName,jdbcType=VARCHAR},
</if>
<if test="scheduleDate != null">
schedule_date = #{scheduleDate,jdbcType=DATE},
</if>
<if test="scheduleStartTime != null">
schedule_start_time = #{scheduleStartTime,jdbcType=TIME},
</if>
<if test="scheduleEndTime != null">
schedule_end_time = #{scheduleEndTime,jdbcType=TIME},
</if>
<if test="applyState != null">
apply_state = #{applyState,jdbcType=VARCHAR},
</if>
</set>
where id = #{id,jdbcType=BIGINT}
</update>
<update id="updateByPrimaryKey" parameterType="com.xinelu.manage.domain.scheduleplandetail.SchedulePlanDetail">
update schedule_plan_detail
set
schedule_plan_id = #{schedulePlanId,jdbcType=BIGINT},
doctor_id = #{doctorId,jdbcType=BIGINT},
doctor_name = #{doctorName,jdbcType=VARCHAR},
schedule_date = #{scheduleDate,jdbcType=DATE},
schedule_start_time = #{scheduleStartTime,jdbcType=TIME},
schedule_end_time = #{scheduleEndTime,jdbcType=TIME},
apply_state = #{applyState,jdbcType=VARCHAR}
where id = #{id,jdbcType=BIGINT}
</update>
</mapper>