Merge branch 'main' into frx
This commit is contained in:
commit
e48e3ba95c
@ -2,11 +2,16 @@ package cn.iocoder.yudao.framework.websocket.core.handler;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.core.util.TypeUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||
import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
|
||||
import cn.iocoder.yudao.framework.websocket.core.attendance.AttendanceConstants;
|
||||
import cn.iocoder.yudao.framework.websocket.core.listener.WebSocketMessageListener;
|
||||
import cn.iocoder.yudao.framework.websocket.core.message.JsonWebSocketMessage;
|
||||
import cn.iocoder.yudao.framework.websocket.core.session.WebSocketSessionManager;
|
||||
import cn.iocoder.yudao.framework.websocket.core.util.WebSocketFrameworkUtils;
|
||||
import com.github.yulichang.toolkit.SpringContentUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.socket.TextMessage;
|
||||
import org.springframework.web.socket.WebSocketHandler;
|
||||
@ -43,28 +48,79 @@ public class JsonWebSocketMessageHandler extends TextWebSocketHandler {
|
||||
|
||||
@Override
|
||||
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
|
||||
|
||||
// 1.1 空消息,跳过
|
||||
if (message.getPayloadLength() == 0) {
|
||||
return;
|
||||
}
|
||||
// 1.2 ping 心跳消息,直接返回 pong 消息。
|
||||
if (message.getPayloadLength() == 4 && Objects.equals(message.getPayload(), "ping")) {
|
||||
session.sendMessage(new TextMessage("pong"));
|
||||
return;
|
||||
|
||||
String payload = message.getPayload() ;
|
||||
boolean isTypeJSON = JSONUtil.isTypeJSON(payload) ;
|
||||
if( isTypeJSON ) {
|
||||
JSONObject object = new JSONObject(payload);
|
||||
String cmd = object.getStr("cmd") ; //设备请求方法
|
||||
String sn = object.getStr("sn") ; //设备编号
|
||||
// 此指令服务端不需要回复 客户端声明
|
||||
if ( cmd !=null && cmd.equals("declare") ) {
|
||||
log.info("[客户端声明]"+ "||"+ session.getId()+ "||"+ message.getPayload(), session.getId(), message.getPayload());
|
||||
//此处需要将sessionId 与sn 绑定
|
||||
WebSocketSessionManager webSocketSessionManager = SpringContentUtils.getBean(WebSocketSessionManager.class);
|
||||
webSocketSessionManager.addSession(session,sn);
|
||||
return;
|
||||
}
|
||||
|
||||
// 1.2 ping 心跳消息,直接返回 pong 消息。
|
||||
if ( cmd != null && cmd.equals("ping") ) {
|
||||
log.info("[设备心跳]"+ "||"+ session.getId()+ "||"+ message.getPayload(), session.getId(), message.getPayload());
|
||||
session.sendMessage(new TextMessage("{\"cmd\": \"pong\"}"));
|
||||
//TODO 更新设备心跳请求时间
|
||||
// 传入设备sn编码, 调用相关方法,更新对应sn的本次请求时间。
|
||||
// 并且将设备的状态,更新成在线状态
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// 1.2 ping 心跳消息,直接返回 pong 消息。
|
||||
if (message.getPayloadLength() == 4 && Objects.equals(message.getPayload(), "ping")) {
|
||||
// log.info("[WEB心跳]"+ "||"+ session.getId()+ "||"+ message.getPayload(), session.getId(), message.getPayload());
|
||||
session.sendMessage(new TextMessage("pong"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 2.1 解析消息
|
||||
try {
|
||||
// 2.1 解析消息
|
||||
JsonWebSocketMessage jsonMessage = JsonUtils.parseObject(message.getPayload(), JsonWebSocketMessage.class);
|
||||
if (jsonMessage == null) {
|
||||
if (message.getPayload() == null) {
|
||||
log.error("[handleTextMessage][session({}) message({}) 解析为空]", session.getId(), message.getPayload());
|
||||
return;
|
||||
}
|
||||
if (StrUtil.isEmpty(jsonMessage.getType())) {
|
||||
log.error("[handleTextMessage][session({}) message({}) 类型为空]", session.getId(), message.getPayload());
|
||||
|
||||
JSONObject object = new JSONObject(message.getPayload());
|
||||
String cmd = object.getStr("cmd") ;
|
||||
if (StrUtil.isEmpty( cmd )) {
|
||||
log.error("[handleTextMessage][session({}) message({}) 数据格错误]", session.getId(), message.getPayload());
|
||||
return;
|
||||
}
|
||||
// 2.2 获得对应的 WebSocketMessageListener
|
||||
|
||||
if( cmd.equals(AttendanceConstants.CMD_TO_DEVICE) ) {
|
||||
jsonMessage.setType("attendance-message-send") ;
|
||||
//服务器下发数据到设备
|
||||
//TODO 记录服务器下数据
|
||||
|
||||
|
||||
}else if( cmd.equals(AttendanceConstants.CMD_TO_CLIENT) ) {
|
||||
jsonMessage.setType("attendance-message-send") ;
|
||||
//设备的响应数据返回服务器
|
||||
//{"cmd":"to_client","form":"QT74824","from":"QT74824","to":"system","data":{"cmd":"addUserRet","code":0,"msg":"下发成功","user_id":"999999"},"extra":"null"}
|
||||
String data = object.getStr("data") ;
|
||||
JSONObject dataObject = new JSONObject(data);
|
||||
String msg= dataObject.getStr("msg") ;
|
||||
// TODO 记录响应
|
||||
}
|
||||
|
||||
// 2.2 获得对应的 WebSocketMessageListener 根据Type找到对应的处理监听器
|
||||
WebSocketMessageListener<Object> messageListener = listeners.get(jsonMessage.getType());
|
||||
if (messageListener == null) {
|
||||
log.error("[handleTextMessage][session({}) message({}) 监听器为空]", session.getId(), message.getPayload());
|
||||
@ -72,7 +128,11 @@ public class JsonWebSocketMessageHandler extends TextWebSocketHandler {
|
||||
}
|
||||
// 2.3 处理消息
|
||||
Type type = TypeUtil.getTypeArgument(messageListener.getClass(), 0);
|
||||
Object messageObj = JsonUtils.parseObject(jsonMessage.getContent(), type);
|
||||
JSONObject object1 = new JSONObject(message.getPayload());
|
||||
Object data = object1.get("data");
|
||||
object1.set("data",data.toString()) ;
|
||||
String string = object1.toString();
|
||||
Object messageObj = JsonUtils.parseObject(string, type);
|
||||
Long tenantId = WebSocketFrameworkUtils.getTenantId(session);
|
||||
TenantUtils.execute(tenantId, () -> messageListener.onMessage(session, messageObj));
|
||||
} catch (Throwable ex) {
|
||||
|
@ -2,6 +2,8 @@ package cn.iocoder.yudao.framework.websocket.core.sender;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||
import cn.iocoder.yudao.framework.websocket.core.message.JsonWebSocketMessage;
|
||||
import cn.iocoder.yudao.framework.websocket.core.session.WebSocketSessionManager;
|
||||
@ -41,6 +43,36 @@ public abstract class AbstractWebSocketMessageSender implements WebSocketMessage
|
||||
send(sessionId, null, null, messageType, messageContent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void snSend(String sn, String messageType, String messageContent) {
|
||||
SNSend(sn, messageType, messageContent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送消息
|
||||
*
|
||||
* @param sn 设备编码 编号
|
||||
* @param messageType 消息类型
|
||||
* @param messageContent 消息内容
|
||||
*/
|
||||
public void SNSend(String sn, String messageType, String messageContent) {
|
||||
// 1. 获得 Session 列表
|
||||
List<WebSocketSession> sessions = Collections.emptyList();
|
||||
System.out.println("===="+ sn) ;
|
||||
if (StrUtil.isNotEmpty(sn)) {
|
||||
WebSocketSession session = sessionManager.getSessionByDeviceNum(sn);
|
||||
if (session != null) {
|
||||
sessions = Collections.singletonList(session);
|
||||
}
|
||||
}
|
||||
if (CollUtil.isEmpty(sessions)) {
|
||||
log.info("[send][sn({}) messageType({}) messageContent({}) 未匹配到sn设备]",
|
||||
sn, messageType, messageContent);
|
||||
}
|
||||
// 2. 执行发送
|
||||
doSend(sessions, messageType, messageContent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送消息
|
||||
*
|
||||
@ -80,7 +112,10 @@ public abstract class AbstractWebSocketMessageSender implements WebSocketMessage
|
||||
*/
|
||||
public void doSend(Collection<WebSocketSession> sessions, String messageType, String messageContent) {
|
||||
JsonWebSocketMessage message = new JsonWebSocketMessage().setType(messageType).setContent(messageContent);
|
||||
String payload = JsonUtils.toJsonString(message); // 关键,使用 JSON 序列化
|
||||
|
||||
// JSONObject object = JSONUtil.parseObj(message.getContent()) ;
|
||||
//消息内容中获取text 属性下的内容,用户发送给指定的设备
|
||||
String payload = messageContent;
|
||||
sessions.forEach(session -> {
|
||||
// 1. 各种校验,保证 Session 可以被发送
|
||||
if (session == null) {
|
||||
|
@ -37,6 +37,15 @@ public interface WebSocketMessageSender {
|
||||
*/
|
||||
void send(String sessionId, String messageType, String messageContent);
|
||||
|
||||
/**
|
||||
* 发送消息给指定 Session
|
||||
*
|
||||
* @param sn 设备标号 编号
|
||||
* @param messageType 消息类型
|
||||
* @param messageContent 消息内容,JSON 格式
|
||||
*/
|
||||
void snSend(String sn, String messageType, String messageContent);
|
||||
|
||||
default void sendObject(Integer userType, Long userId, String messageType, Object messageContent) {
|
||||
send(userType, userId, messageType, JsonUtils.toJsonString(messageContent));
|
||||
}
|
||||
@ -49,4 +58,8 @@ public interface WebSocketMessageSender {
|
||||
send(sessionId, messageType, JsonUtils.toJsonString(messageContent));
|
||||
}
|
||||
|
||||
default void sendSNObject(String sn, String messageType, Object messageContent) {
|
||||
snSend(sn, messageType, JsonUtils.toJsonString(messageContent));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package cn.iocoder.yudao.framework.websocket.core.session;
|
||||
import org.springframework.web.socket.WebSocketSession;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* {@link WebSocketSession} 管理器的接口
|
||||
@ -50,4 +51,32 @@ public interface WebSocketSessionManager {
|
||||
*/
|
||||
Collection<WebSocketSession> getSessionList(Integer userType, Long userId);
|
||||
|
||||
|
||||
/**
|
||||
* 添加 Session
|
||||
*
|
||||
* @param session Session
|
||||
* @param sn 设备号
|
||||
*/
|
||||
void addSession(WebSocketSession session, String sn);
|
||||
|
||||
/**
|
||||
* 获得指定设备编号的 Session
|
||||
*
|
||||
* @param sn 设备号
|
||||
* @return Session session
|
||||
*/
|
||||
WebSocketSession getSessionByDeviceNum(String sn);
|
||||
|
||||
/**
|
||||
* 获取设备SN的集合
|
||||
* @return
|
||||
*/
|
||||
Collection<WebSocketSession> getSNSession();
|
||||
|
||||
/**
|
||||
* 获取所有在线设备的SN
|
||||
* @return
|
||||
*/
|
||||
Set<String> getOnlineSN() ;
|
||||
}
|
@ -6,10 +6,7 @@ import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
|
||||
import cn.iocoder.yudao.framework.websocket.core.util.WebSocketFrameworkUtils;
|
||||
import org.springframework.web.socket.WebSocketSession;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
@ -21,6 +18,13 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
||||
*/
|
||||
public class WebSocketSessionManagerImpl implements WebSocketSessionManager {
|
||||
|
||||
/**
|
||||
* sn 与 WebSocketSession 映射
|
||||
*
|
||||
* key:设备编号
|
||||
*/
|
||||
private final ConcurrentMap<String, WebSocketSession> snSessions = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* id 与 WebSocketSession 映射
|
||||
*
|
||||
@ -39,6 +43,7 @@ public class WebSocketSessionManagerImpl implements WebSocketSessionManager {
|
||||
|
||||
@Override
|
||||
public void addSession(WebSocketSession session) {
|
||||
System.out.println("add###############"+ session.getId());
|
||||
// 添加到 idSessions 中
|
||||
idSessions.put(session.getId(), session);
|
||||
// 添加到 userSessions 中
|
||||
@ -65,8 +70,10 @@ public class WebSocketSessionManagerImpl implements WebSocketSessionManager {
|
||||
|
||||
@Override
|
||||
public void removeSession(WebSocketSession session) {
|
||||
System.out.println("remove###############"+ session.getId());
|
||||
// 移除从 idSessions 中
|
||||
idSessions.remove(session.getId());
|
||||
snSessions.remove(session.getId());
|
||||
// 移除从 idSessions 中
|
||||
LoginUser user = WebSocketFrameworkUtils.getLoginUser(session);
|
||||
if (user == null) {
|
||||
@ -122,4 +129,29 @@ public class WebSocketSessionManagerImpl implements WebSocketSessionManager {
|
||||
return CollUtil.isNotEmpty(sessions) ? new ArrayList<>(sessions) : new ArrayList<>();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void addSession(WebSocketSession session, String sn){
|
||||
System.out.println("sn===="+ sn);
|
||||
//添加之前先删除历史sn对应的snsession
|
||||
snSessions.remove(sn) ;
|
||||
// 添加到 idSessions 中
|
||||
snSessions.put(sn, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebSocketSession getSessionByDeviceNum(String sn) {
|
||||
return snSessions.get(sn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<WebSocketSession> getSNSession(){
|
||||
return this.snSessions.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getOnlineSN() {
|
||||
Set<String> snSet = this.snSessions.keySet();
|
||||
return snSet ;
|
||||
}
|
||||
}
|
||||
|
@ -71,4 +71,16 @@ public interface WebSocketSenderApi {
|
||||
send(sessionId, messageType, JsonUtils.toJsonString(messageContent));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 发送消息给指定 SN
|
||||
*
|
||||
* @param sn 设备 编号
|
||||
* @param messageType 消息类型
|
||||
* @param messageContent 消息内容,JSON 格式
|
||||
*/
|
||||
default void sendSN(String sn, String messageType, String messageContent) {
|
||||
send(new WebSocketSendReqDTO().setSn(sn)
|
||||
.setMessageType(messageType).setMessageContent(messageContent)).checkError();
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,9 @@ import javax.validation.constraints.NotEmpty;
|
||||
@Data
|
||||
public class WebSocketSendReqDTO {
|
||||
|
||||
@Schema(description = "sn 编号", example = "QT74824")
|
||||
private String sn;
|
||||
|
||||
@Schema(description = "Session 编号", example = "abc")
|
||||
private String sessionId;
|
||||
@Schema(description = "用户编号", example = "1024")
|
||||
|
@ -20,7 +20,10 @@ public class WebSocketSenderApiImpl implements WebSocketSenderApi {
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> send(WebSocketSendReqDTO message) {
|
||||
if (StrUtil.isNotEmpty(message.getSessionId())) {
|
||||
if (StrUtil.isNotEmpty(message.getSn())) {
|
||||
webSocketMessageSender.snSend(message.getSn(),
|
||||
message.getMessageType(), message.getMessageContent());
|
||||
}else if (StrUtil.isNotEmpty(message.getSessionId())) {
|
||||
webSocketMessageSender.send(message.getSessionId(),
|
||||
message.getMessageType(), message.getMessageContent());
|
||||
} else if (message.getUserType() != null && message.getUserId() != null) {
|
||||
|
@ -0,0 +1,40 @@
|
||||
package cn.iocoder.yudao.module.infra.websocket;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||
import cn.iocoder.yudao.framework.websocket.core.listener.WebSocketMessageListener;
|
||||
import cn.iocoder.yudao.framework.websocket.core.sender.WebSocketMessageSender;
|
||||
import cn.iocoder.yudao.framework.websocket.core.util.WebSocketFrameworkUtils;
|
||||
import cn.iocoder.yudao.module.infra.websocket.message.AttendanceReceiveMessage;
|
||||
import cn.iocoder.yudao.module.infra.websocket.message.AttendanceSendMessage;
|
||||
import cn.iocoder.yudao.module.infra.websocket.message.DemoReceiveMessage;
|
||||
import cn.iocoder.yudao.module.infra.websocket.message.DemoSendMessage;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.socket.WebSocketSession;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 考勤仪设备 WebSocket 数据通信
|
||||
*
|
||||
|
||||
*/
|
||||
@Component
|
||||
public class AttendanceWebSocketMessageListener implements WebSocketMessageListener<AttendanceSendMessage> {
|
||||
|
||||
@Resource
|
||||
private WebSocketMessageSender webSocketMessageSender;
|
||||
|
||||
@Override
|
||||
public void onMessage(WebSocketSession session, AttendanceSendMessage message) {
|
||||
String sn = session.getId() ;
|
||||
AttendanceReceiveMessage toMessage = new AttendanceReceiveMessage().setFrom("system")
|
||||
.setData(message.getData());
|
||||
webSocketMessageSender.sendSNObject(sn, "attendance-message-send", toMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "attendance-message-send";
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package cn.iocoder.yudao.module.infra.websocket.message;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 示例:server -> client 同步消息
|
||||
*
|
||||
|
||||
*/
|
||||
@Data
|
||||
public class AttendanceReceiveMessage {
|
||||
|
||||
/**
|
||||
* 接收人的编号
|
||||
*/
|
||||
private String from;
|
||||
/**
|
||||
* 内容
|
||||
*/
|
||||
private String data;
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package cn.iocoder.yudao.module.infra.websocket.message;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 示例:client -> server 发送消息
|
||||
*
|
||||
|
||||
*/
|
||||
@Data
|
||||
public class AttendanceSendMessage {
|
||||
|
||||
/**
|
||||
* 发送给哪个设备
|
||||
*/
|
||||
private String to;
|
||||
/**
|
||||
* 内容
|
||||
*/
|
||||
private String data;
|
||||
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
package cn.iocoder.yudao.module.system.attendance;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 功能描述
|
||||
*
|
||||
* @author: yj
|
||||
* @date: 2024年05月27日 10:48
|
||||
*/
|
||||
@Data
|
||||
public class AttendanceBaseMessage {
|
||||
|
||||
/**
|
||||
* 固定为 to_device
|
||||
*/
|
||||
public final String cmd = AttendanceConstants.CMD_BASE;
|
||||
|
||||
/**
|
||||
* 这个字段对设备来说没有任何作用,只是在响应指令时在 to 字段中附带回服务端。
|
||||
* 可以认为是 message id 的概念,一般是让服务端区分设备响应的是具体的哪一条消息,服务端没有用到的话可以为空字符
|
||||
*/
|
||||
public String from ;
|
||||
|
||||
/**
|
||||
* 字段非必填,这个字段和 from 一样对设备来说没有任何作用,
|
||||
* 只是在响应指令时原封不动的把 extra 的内容响应回去,服务端没有用到可以不传
|
||||
*/
|
||||
public String extra ;
|
||||
|
||||
/**
|
||||
* 目标的设备编号
|
||||
*/
|
||||
public String to ;
|
||||
|
||||
/**
|
||||
* 具体指令中的数据格式,每个指令都不一样
|
||||
*/
|
||||
public JSONObject data;
|
||||
|
||||
// public void setData(Object o) {
|
||||
// this.data = JsonUtils.toJsonString(o);
|
||||
// }
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package cn.iocoder.yudao.module.system.attendance;
|
||||
|
||||
/**
|
||||
* 功能描述
|
||||
*
|
||||
* @author: yj
|
||||
* @date: 2024年05月27日 11:40
|
||||
*/
|
||||
public class AttendanceConstants {
|
||||
|
||||
public static final String CMD_BASE = "to_device" ;
|
||||
|
||||
public static class OperateUserCMD {
|
||||
|
||||
/**
|
||||
* 下发人员信息到设备
|
||||
*/
|
||||
public static final String ADD_USER_CMD = "addUser" ;
|
||||
|
||||
/**
|
||||
* 修改人员信息
|
||||
*/
|
||||
public static final String EDIT_USER_CMD = "editUser" ;
|
||||
|
||||
/**
|
||||
* 批量删除人员
|
||||
*/
|
||||
public static final String DEL_MULTI_USER_CMD = "delMultiUser" ;
|
||||
|
||||
|
||||
/**
|
||||
* 检测图片质量
|
||||
*/
|
||||
public static final String CHECK_USER_PHOTO_CMD = "verifyPhoto" ;
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package cn.iocoder.yudao.module.system.attendance;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 功能描述
|
||||
*
|
||||
* @author: yj
|
||||
* @date: 2024年05月27日 11:02
|
||||
*/
|
||||
|
||||
@Schema(description="下发人员信息到设备")
|
||||
@Data
|
||||
public class SendUserToDeviceMessage {
|
||||
|
||||
@Schema(description = "指令名称", requiredMode = Schema.RequiredMode.REQUIRED ,example = "addUser")
|
||||
@NotNull(message = "指定名称不能为空")
|
||||
public String cmd = AttendanceConstants.OperateUserCMD.ADD_USER_CMD;
|
||||
|
||||
@Schema(description = "用户id,注意 user_id 请不要使用 DL 开头", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@NotNull(message = "user_id不能为空")
|
||||
public String user_id ;
|
||||
|
||||
@Schema(description = "用户姓名", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三")
|
||||
@NotNull(message = "用户姓名不能为空")
|
||||
public String name;
|
||||
|
||||
// @Schema(description = "身份证号码,在刷身份证时会匹配这个号码是否存在", example = "362301111111111111")
|
||||
// public String user_id_card ;
|
||||
|
||||
@Schema(description = "彩色照片,可以为两种格式。\n" +
|
||||
"1.http 链接,例如 https://up.enterdesk.com/edpic/70/0e/33/700e3312f74e378fbcc2fb3819421e73.jpg\n" +
|
||||
"2.直接传图片 点击查看【2.服务规范】中的照片编码规则 。设备【验证模式】为【人脸或卡】时可以不传照片,非【人脸或卡】模式这个字段为必传", requiredMode = Schema.RequiredMode.REQUIRED, example = "http://xxx.xx.jpg")
|
||||
@NotNull(message = "照片不能为空")
|
||||
public String face_template ;
|
||||
|
||||
@Schema(description = "手机号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18888888888")
|
||||
@NotNull(message = "手机号不能为空")
|
||||
public String phone;
|
||||
|
||||
@Schema(description = "人员有效期(人员在这个时间点后,无法通行)格式:yyyy-MM-dd 或者 yyyy-MM-dd HH:mm,为 “” 则为永久", requiredMode = Schema.RequiredMode.REQUIRED, example = "")
|
||||
public final String id_valid= "";
|
||||
}
|
Loading…
Reference in New Issue
Block a user