sdf 接口
This commit is contained in:
parent
b13a9f54ac
commit
db484a070d
@ -41,6 +41,14 @@
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcpkix-jdk18on</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-pool2</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.java.dev.jna</groupId>
|
||||
<artifactId>jna</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
|
@ -0,0 +1,16 @@
|
||||
package com.sunyard.chsm.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.sunyard.chsm.model.entity.TmkInfo;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* @author liulu
|
||||
* @since 2024/10/29
|
||||
*/
|
||||
@Mapper
|
||||
public interface TmkInfoMapper extends BaseMapper<TmkInfo> {
|
||||
|
||||
|
||||
|
||||
}
|
@ -23,6 +23,10 @@ public class Device {
|
||||
private String manufacturerModel;
|
||||
private String accessCredentials;
|
||||
|
||||
private Boolean connected;
|
||||
private LocalDateTime lastCheckTime;
|
||||
private LocalDateTime lastConnectedTime;
|
||||
|
||||
private Long groupId;
|
||||
private String groupName;
|
||||
private Integer weight;
|
||||
|
@ -0,0 +1,25 @@
|
||||
package com.sunyard.chsm.model.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* @author liulu
|
||||
* @since 2024/11/4
|
||||
*/
|
||||
@Data
|
||||
@TableName("sp_tmk_info")
|
||||
public class TmkInfo {
|
||||
|
||||
private Long id;
|
||||
|
||||
private String deviceSerial;
|
||||
private String encTmk;
|
||||
|
||||
private String remark;
|
||||
private LocalDateTime createTime;
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
package com.sunyard.chsm.sdf.adapter;
|
||||
|
||||
import com.sun.jna.Pointer;
|
||||
import com.sun.jna.ptr.PointerByReference;
|
||||
import com.sunyard.chsm.sdf.lib.SdfLibrary;
|
||||
import com.sunyard.chsm.sdf.model.DeviceInfo;
|
||||
import com.sunyard.chsm.sdf.model.EccKey;
|
||||
import com.sunyard.chsm.sdf.model.EccPubKey;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* @author liulu
|
||||
* @since 2024/11/4
|
||||
*/
|
||||
public abstract class JnaSdfAdaptor implements SdfApiAdapter {
|
||||
|
||||
protected static final Map<String, Pointer> DEVICE_HANDLE_CONTEXT = new ConcurrentHashMap<>();
|
||||
protected static final Map<String, Pointer> SESSION_HANDLE_CONTEXT = new ConcurrentHashMap<>();
|
||||
protected static final Map<String, Pointer> KEY_HANDLE_CONTEXT = new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
protected abstract SdfLibrary getSdfLibrary();
|
||||
|
||||
protected abstract int getAlgId(String alg);
|
||||
|
||||
@Override
|
||||
public String openDevice() {
|
||||
PointerByReference phDeviceHandle = new PointerByReference();
|
||||
getSdfLibrary().SDF_OpenDevice(phDeviceHandle);
|
||||
String key = UUID.randomUUID().toString();
|
||||
DEVICE_HANDLE_CONTEXT.put(key, phDeviceHandle.getValue());
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean closeDevice(String deviceHandle) {
|
||||
Pointer pointer = DEVICE_HANDLE_CONTEXT.remove(deviceHandle);
|
||||
if (pointer != null) {
|
||||
int res = getSdfLibrary().SDF_CloseDevice(pointer);
|
||||
return res == 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String openSession(String deviceHandle) {
|
||||
Pointer device = getDeviceHandle(deviceHandle);
|
||||
|
||||
PointerByReference phSessionHandle = new PointerByReference();
|
||||
getSdfLibrary().SDF_OpenSession(device, phSessionHandle);
|
||||
|
||||
String key = UUID.randomUUID().toString();
|
||||
SESSION_HANDLE_CONTEXT.put(key, phSessionHandle.getValue());
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeSession(String sessionHandle) {
|
||||
Pointer pointer = SESSION_HANDLE_CONTEXT.remove(sessionHandle);
|
||||
if (pointer != null) {
|
||||
getSdfLibrary().SDF_CloseSession(pointer);
|
||||
}
|
||||
}
|
||||
|
||||
protected Pointer getDeviceHandle(String deviceHandle) {
|
||||
Pointer pointer = DEVICE_HANDLE_CONTEXT.get(deviceHandle);
|
||||
Assert.notNull(pointer, "设备句柄不存在");
|
||||
return pointer;
|
||||
}
|
||||
|
||||
protected Pointer getSessionHandle(String sessionHandle) {
|
||||
Pointer pointer = SESSION_HANDLE_CONTEXT.get(sessionHandle);
|
||||
Assert.notNull(pointer, "会话句柄不存在");
|
||||
return pointer;
|
||||
}
|
||||
|
||||
protected Pointer getKeyHandle(String keyHandle) {
|
||||
Pointer pointer = KEY_HANDLE_CONTEXT.get(keyHandle);
|
||||
Assert.notNull(pointer, "密钥句柄不存在");
|
||||
return pointer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeviceInfo getDeviceInfo(String sessionHandle) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] generateRandom(String sessionHandle, int uiLength) {
|
||||
byte[] pucRandom = new byte[uiLength];
|
||||
Pointer hSessionHandle = getSessionHandle(sessionHandle);
|
||||
getSdfLibrary().SDF_GenerateRandom(hSessionHandle, uiLength, pucRandom);
|
||||
return pucRandom;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EccPubKey exportEncPublicKeyECC(String sessionHandle, int uiKeyIndex) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EccKey generateKeyPairECC(String sessionHandle, String alg, int uiKeyBits) {
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
package com.sunyard.chsm.sdf.adapter;
|
||||
|
||||
import com.sunyard.chsm.sdf.model.DeviceInfo;
|
||||
import com.sunyard.chsm.sdf.model.EccKey;
|
||||
import com.sunyard.chsm.sdf.model.EccPubKey;
|
||||
|
||||
/**
|
||||
* @author liulu
|
||||
* @since 2024/11/4
|
||||
*/
|
||||
public interface SdfApiAdapter {
|
||||
|
||||
/**
|
||||
* 打开设备
|
||||
*
|
||||
* @return 设 备 句 柄
|
||||
*/
|
||||
String openDevice();
|
||||
|
||||
/**
|
||||
* 关闭设备
|
||||
*
|
||||
* @param deviceHandle 已打开的设备句柄
|
||||
* @return 0 成功; 非0 失败,返回错误代码
|
||||
*/
|
||||
boolean closeDevice(String deviceHandle);
|
||||
|
||||
/**
|
||||
* 创建会话
|
||||
*
|
||||
* @return 与密码设备建立的新会话句柄
|
||||
*/
|
||||
String openSession(String deviceHandle);
|
||||
|
||||
void closeSession(String sessionHandle);
|
||||
|
||||
/**
|
||||
* 获取设备信息
|
||||
*
|
||||
* @param sessionHandle 与设备建立的会话句柄
|
||||
* @return 设备能力描述信息,内容及格式见设备信息定义
|
||||
*/
|
||||
DeviceInfo getDeviceInfo(String sessionHandle);
|
||||
|
||||
/**
|
||||
* 产生随机数
|
||||
*
|
||||
* @param uiLength 随机数长度
|
||||
* @return pucRandom 返回随机数
|
||||
*/
|
||||
byte[] generateRandom(String sessionHandle, int uiLength);
|
||||
|
||||
/**
|
||||
* 导出ECC加密公钥
|
||||
*
|
||||
* @param uiKeyIndex 密码设备存储的ECC密钥对索引值
|
||||
* @return pucPublicKeyEcc 返回ECC加密公钥
|
||||
*/
|
||||
EccPubKey exportEncPublicKeyECC(String sessionHandle, int uiKeyIndex);
|
||||
|
||||
/**
|
||||
* 产生ECC密钥对并输出
|
||||
*
|
||||
* @param alg 指定算法标识 SGD_SM2_1
|
||||
* @param uiKeyBits 指定密钥模长
|
||||
* @return pucPublicKeyEcc 返回公钥 | pucPrivateKeyEcc 返回私钥
|
||||
*/
|
||||
EccKey generateKeyPairECC(String sessionHandle, String alg, int uiKeyBits);
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package com.sunyard.chsm.sdf.adapter;
|
||||
|
||||
import com.sunyard.chsm.enums.ManufacturerModelEnum;
|
||||
import com.sunyard.chsm.sdf.context.DeviceContext;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author liulu
|
||||
* @since 2024/11/5
|
||||
*/
|
||||
public class SdfApiAdapterFactory {
|
||||
|
||||
|
||||
public static SdfApiAdapter newInstance(DeviceContext device) {
|
||||
|
||||
Assert.hasText(device.getManufacturerModel(), "设备型号不能为空");
|
||||
ManufacturerModelEnum model = ManufacturerModelEnum.of(device.getManufacturerModel());
|
||||
|
||||
if (Objects.isNull(model)) {
|
||||
// bc adaptor
|
||||
return null;
|
||||
}
|
||||
switch (model) {
|
||||
case enc001:
|
||||
return new SunyardJnaSdfAdaptor(device.getServiceIp(), device.getServicePort());
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
package com.sunyard.chsm.sdf.adapter;
|
||||
|
||||
import com.sun.jna.Native;
|
||||
import com.sun.jna.ptr.PointerByReference;
|
||||
import com.sunyard.chsm.sdf.lib.SdfLibrary;
|
||||
import com.sunyard.chsm.sdf.lib.SunyardSdfLibrary;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* @author liulu
|
||||
* @since 2024/11/4
|
||||
*/
|
||||
public class SunyardJnaSdfAdaptor extends JnaSdfAdaptor {
|
||||
|
||||
private static final Map<String, SunyardSdfLibrary> SDF_LIB_MAP = new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
private final String ip;
|
||||
private final Integer port;
|
||||
private final String libName;
|
||||
private final Integer connTimeout;
|
||||
private final Integer dealTimeout;
|
||||
|
||||
public SunyardJnaSdfAdaptor(String ip, int port) {
|
||||
this(ip, port, "libsdf");
|
||||
}
|
||||
|
||||
public SunyardJnaSdfAdaptor(String ip, int port, String libName) {
|
||||
this(ip, port, libName, 3000, 3000);
|
||||
}
|
||||
|
||||
public SunyardJnaSdfAdaptor(String ip, int port, String libName, int connTimeout, int dealTimeout) {
|
||||
this.ip = ip;
|
||||
this.port = port;
|
||||
this.libName = libName;
|
||||
this.connTimeout = connTimeout;
|
||||
this.dealTimeout = dealTimeout;
|
||||
SDF_LIB_MAP.computeIfAbsent(libName, k -> Native.load(libName, SunyardSdfLibrary.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String openDevice() {
|
||||
SunyardSdfLibrary sdfLibrary = (SunyardSdfLibrary) getSdfLibrary();
|
||||
PointerByReference phDeviceHandle = new PointerByReference();
|
||||
sdfLibrary.SDF_OpenDevice(phDeviceHandle, safeStringBytes(ip), port, connTimeout, dealTimeout, 0);
|
||||
String key = UUID.randomUUID().toString();
|
||||
DEVICE_HANDLE_CONTEXT.put(key, phDeviceHandle.getValue());
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SdfLibrary getSdfLibrary() {
|
||||
return SDF_LIB_MAP.get(libName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getAlgId(String alg) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static byte[] safeStringBytes(String str) {
|
||||
if (null == str || str.isEmpty()) {
|
||||
return new byte[]{0x30};
|
||||
}
|
||||
int len = str.getBytes().length;
|
||||
byte[] ret = new byte[len + 1];
|
||||
System.arraycopy(str.getBytes(), 0, ret, 0, len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package com.sunyard.chsm.sdf.context;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author liulu
|
||||
* @since 2024/11/5
|
||||
*/
|
||||
@Data
|
||||
public class DeviceContext {
|
||||
|
||||
private String serviceIp;
|
||||
private Integer servicePort;
|
||||
private String manufacturer;
|
||||
private String manufacturerModel;
|
||||
private String accessCredentials;
|
||||
private String jnaLibName;
|
||||
|
||||
private Integer weight;
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
package com.sunyard.chsm.sdf.lib;
|
||||
|
||||
import com.sun.jna.Library;
|
||||
import com.sun.jna.Pointer;
|
||||
import com.sun.jna.ptr.PointerByReference;
|
||||
|
||||
/**
|
||||
* @author liulu
|
||||
* @since 2024/11/4
|
||||
*/
|
||||
public interface SdfLibrary extends Library {
|
||||
|
||||
/**
|
||||
* 打开设备
|
||||
*
|
||||
* @param phDeviceHandle 返回设备句柄
|
||||
* @return 0 成功; 非0 失败,返回错误代码
|
||||
*/
|
||||
int SDF_OpenDevice(PointerByReference phDeviceHandle);
|
||||
|
||||
/**
|
||||
* 关闭设备
|
||||
*
|
||||
* @param hDeviceHandle 已打开的设备句柄
|
||||
* @return 0 成功; 非0 失败,返回错误代码
|
||||
*/
|
||||
int SDF_CloseDevice(Pointer hDeviceHandle);
|
||||
|
||||
/**
|
||||
* 创建会话
|
||||
*
|
||||
* @param hDeviceHandle 已打开的设备句柄
|
||||
* @param phSessionHandle 返回与密码设备建立的新会话句柄
|
||||
* @return 0 成功; 非0 失败,返回错误代码
|
||||
*/
|
||||
int SDF_OpenSession(Pointer hDeviceHandle, PointerByReference phSessionHandle);
|
||||
|
||||
/**
|
||||
* 关闭会话
|
||||
*
|
||||
* @param hSessionHandle 与密码设备已建立的会话句柄
|
||||
* @return 0 成功; 非0 失败,返回错误代码
|
||||
*/
|
||||
int SDF_CloseSession(Pointer hSessionHandle);
|
||||
|
||||
/**
|
||||
* 获取设备信息
|
||||
*
|
||||
* @param hSessionHandle 与设备建立的会话句柄
|
||||
* @param pstDeviceInfo 设备能力描述信息,内容及格式见设备信息定义
|
||||
* @return 0 成功; 非0 失败,返回错误代码
|
||||
*/
|
||||
int SDF_GetDeviceInfo(Pointer hSessionHandle, byte[] pstDeviceInfo);
|
||||
|
||||
/**
|
||||
* 产生随机数
|
||||
*
|
||||
* @param hSessionHandle 与设备建立的会话句柄
|
||||
* @param uiLength 欲获取的随机数长度
|
||||
* @param pucRandom 缓冲区指针,用于存放获取的随机数
|
||||
* @return 0 成功; 非0 失败,返回错误代码
|
||||
*/
|
||||
int SDF_GenerateRandom(Pointer hSessionHandle, int uiLength, byte[] pucRandom);
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package com.sunyard.chsm.sdf.lib;
|
||||
|
||||
import com.sun.jna.ptr.PointerByReference;
|
||||
|
||||
/**
|
||||
* @author liulu
|
||||
* @since 2024/11/4
|
||||
*/
|
||||
public interface SunyardSdfLibrary extends SdfLibrary {
|
||||
|
||||
|
||||
/**
|
||||
* 打开设备
|
||||
* @param phDeviceHandle 设备句柄
|
||||
* @return int 响应码
|
||||
*/
|
||||
int SDF_OpenDevice(PointerByReference phDeviceHandle, byte[] ip, int port, int connTimeout, int dealTimeout, int ipMode);
|
||||
|
||||
|
||||
|
||||
}
|
@ -123,6 +123,7 @@ public class DeviceServiceImpl implements DeviceService {
|
||||
Assert.isTrue(manufacturerModel.getManufacturer() == manufacturer, "设备厂商和型号不匹配");
|
||||
|
||||
checkName(save.getName());
|
||||
checkIpPort(save.getServiceIp(), save.getServicePort());
|
||||
|
||||
Device device = new Device();
|
||||
BeanUtils.copyProperties(save, device);
|
||||
@ -136,6 +137,14 @@ public class DeviceServiceImpl implements DeviceService {
|
||||
return device.getId();
|
||||
}
|
||||
|
||||
private void checkIpPort(String serviceIp, Integer servicePort) {
|
||||
LambdaQueryWrapper<Device> wrapper = new LambdaQueryWrapper<Device>()
|
||||
.eq(Device::getServiceIp, serviceIp)
|
||||
.eq(Device::getServicePort, servicePort);
|
||||
Device exist = spDeviceMapper.selectOne(wrapper);
|
||||
Assert.isNull(exist, "设备IP和端口已存在");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(DeviceDTO.DeviceSave update) {
|
||||
Assert.notNull(update.getId(), "id不能为空");
|
||||
@ -145,13 +154,16 @@ public class DeviceServiceImpl implements DeviceService {
|
||||
if (!Objects.equals(exist.getName(), update.getName())) {
|
||||
checkName(update.getName());
|
||||
}
|
||||
if (!Objects.equals(exist.getServiceIp(), update.getServiceIp())
|
||||
|| !Objects.equals(exist.getServicePort(), update.getServicePort())) {
|
||||
checkIpPort(update.getServiceIp(), update.getServicePort());
|
||||
}
|
||||
|
||||
Device up = new Device();
|
||||
BeanUtils.copyProperties(update, up);
|
||||
up.setUpdateTime(LocalDateTime.now());
|
||||
|
||||
spDeviceMapper.updateById(up);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -0,0 +1,61 @@
|
||||
package com.sunyard.chsm.task;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.sunyard.chsm.mapper.SpDeviceMapper;
|
||||
import com.sunyard.chsm.model.entity.Device;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author liulu
|
||||
* @since 2024/11/4
|
||||
*/
|
||||
@Component
|
||||
public class DeviceTask implements InitializingBean {
|
||||
|
||||
@Resource
|
||||
private SpDeviceMapper spDeviceMapper;
|
||||
|
||||
@Resource
|
||||
private ThreadPoolTaskScheduler threadPoolTaskScheduler;
|
||||
@Resource
|
||||
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
|
||||
|
||||
|
||||
private void checkDeviceStatus() {
|
||||
|
||||
for (int i = 1; i < 500; i++) {
|
||||
Page<Device> devicePage = spDeviceMapper.selectPage(
|
||||
new Page<>(i, 100L),
|
||||
new LambdaQueryWrapper<Device>().orderByAsc(Device::getId)
|
||||
);
|
||||
List<Device> records = devicePage.getRecords();
|
||||
if (CollectionUtils.isEmpty(records)) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (Device record : records) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
threadPoolTaskScheduler.scheduleWithFixedDelay(this::checkDeviceStatus, Duration.ofMinutes(5L));
|
||||
}
|
||||
}
|
@ -11,6 +11,9 @@ CREATE TABLE sp_device (
|
||||
manage_ip VARCHAR(30) COMMENT '管理ip',
|
||||
manage_port INT COMMENT '管理端口',
|
||||
access_credentials VARCHAR(1000) COMMENT '访问凭证',
|
||||
connected TINYINT NOT NULL DEFAULT 0,
|
||||
last_connected_time TIMESTAMP ,
|
||||
last_check_time TIMESTAMP ,
|
||||
status VARCHAR(25) DEFAULT '' COMMENT '设备状态',
|
||||
group_id BIGINT NOT NULL DEFAULT 0 COMMENT '设备组id',
|
||||
group_name VARCHAR(255) NOT NULL DEFAULT '' COMMENT '设备组名称',
|
||||
@ -21,6 +24,7 @@ CREATE TABLE sp_device (
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
-- 设备组
|
||||
CREATE TABLE sp_device_group (
|
||||
id BIGINT NOT NULL COMMENT 'id',
|
||||
name VARCHAR(255) NOT NULL DEFAULT '' COMMENT '服务名称',
|
||||
@ -30,6 +34,18 @@ CREATE TABLE sp_device_group (
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
-- TMK
|
||||
CREATE TABLE sp_tmk_info (
|
||||
id BIGINT NOT NULL COMMENT 'id',
|
||||
device_serial VARCHAR(255) NOT NULL DEFAULT '' COMMENT '设备序列号',
|
||||
enc_tmk VARCHAR(255) NOT NULL DEFAULT '' COMMENT 'tmk密文',
|
||||
pub_key VARCHAR(400) NOT NULL DEFAULT '' COMMENT '设备公钥',
|
||||
remark VARCHAR(500) NOT NULL DEFAULT '' COMMENT '备注',
|
||||
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP(),
|
||||
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP(),
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
-- 密码服务
|
||||
CREATE TABLE sp_crypto_service (
|
||||
id BIGINT NOT NULL COMMENT 'id',
|
||||
|
Loading…
Reference in New Issue
Block a user