feat(iot): 重构设备属性和扩展参数处理

- 将 JsonTypeHandler 重命名为 JsonbTypeHandler,支持 JSONB 类型
- 更新 Device 实体类中的 extendParams 和 properties 字段类型- 修改数据库表结构,将 JSON 字段改为 JSONB 类型- 优化 JSONB 数据的插入和查询方式
This commit is contained in:
zhuangtianxiang 2025-01-09 17:28:33 +08:00
parent 275b7fbe50
commit 3db1dfa5fc
25 changed files with 212 additions and 180 deletions

View File

@ -84,7 +84,7 @@
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
<scope>42.6</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>

View File

@ -65,10 +65,4 @@ public class ApiExceptionHandler {
return new ResponseEntity<>(objectMapper.writeValueAsString(Map.of("msg", ex.getMessage())), HttpStatus.INTERNAL_SERVER_ERROR);
}
// @ExceptionHandler(value = {Exception.class})
// public ResponseEntity<Object> handleException(Exception ex) throws JsonProcessingException {
// log.error("Exception: {}", objectMapper.writeValueAsString(Map.of("msg", ex.getMessage())));
// return new ResponseEntity<>(objectMapper.writeValueAsString(Map.of("msg", ex.getMessage())), HttpStatus.INTERNAL_SERVER_ERROR);
// }
}

View File

@ -1,78 +0,0 @@
package com.zsc.edu.gateway.framework.json;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.springframework.stereotype.Component;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author zhuang
*/
@Component
public class JsonTypeHandler extends BaseTypeHandler<Object> {
private static final ObjectMapper objectMapper = new ObjectMapper();
@Override
public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {
try {
String jsonString;
if (parameter instanceof Map) {
jsonString = objectMapper.writeValueAsString(parameter);
} else if (parameter instanceof String) {
jsonString = (String) parameter;
} else if (parameter instanceof List) {
jsonString = objectMapper.writeValueAsString(parameter);
} else {
throw new SQLException("Unsupported parameter type: " + parameter.getClass().getName());
}
ps.setString(i, jsonString);
} catch (JsonProcessingException e) {
throw new SQLException("Error converting object to JSON", e);
}
}
@Override
public Object getNullableResult(ResultSet rs, String columnName) throws SQLException {
String json = rs.getString(columnName);
return parseJson(json);
}
@Override
public Object getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String json = rs.getString(columnIndex);
return parseJson(json);
}
@Override
public Object getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String json = cs.getString(columnIndex);
return parseJson(json);
}
private Object parseJson(String json) {
if (json == null) {
return null;
}
try {
if (json.startsWith("{")) {
return objectMapper.readValue(json, HashMap.class);
} else if (json.startsWith("[")) {
return objectMapper.readValue(json, List.class);
} else {
throw new RuntimeException("Invalid JSON format");
}
} catch (Exception e) {
throw new RuntimeException("Error parsing JSON", e);
}
}
}

View File

@ -0,0 +1,40 @@
package com.zsc.edu.gateway.framework.json;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
import org.postgresql.util.PGobject;
import java.lang.reflect.Field;
import java.sql.PreparedStatement;
import java.sql.SQLException;
@MappedTypes({Object.class})
@MappedJdbcTypes(JdbcType.VARCHAR)
public class JsonbTypeHandler<T> extends JacksonTypeHandler {
private final Class<T> clazz;
public JsonbTypeHandler(Class<T> clazz) {
super(clazz);
if (clazz == null) {
throw new IllegalArgumentException("Type argument cannot be null");
}
this.clazz = clazz;
}
// 自3.5.6版本开始支持泛型,需要加上此构造.
public JsonbTypeHandler(Class<?> type, Field field, Class<T> clazz) {
super(type, field);
this.clazz = clazz;
}
@Override
public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {
PGobject jsonbObject = new PGobject();
jsonbObject.setType("jsonb");
jsonbObject.setValue(toJson(parameter));
ps.setObject(i, jsonbObject);
}
}

View File

@ -7,7 +7,6 @@ import lombok.NoArgsConstructor;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import org.springframework.boot.configurationprocessor.json.JSONObject;
import java.util.List;
import java.util.Map;

View File

@ -6,7 +6,6 @@ import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import jakarta.validation.constraints.NotBlank;
import org.springframework.boot.configurationprocessor.json.JSONObject;
import java.util.List;
import java.util.Map;
@ -38,7 +37,6 @@ public class DeviceDto {
/**
* 扩展属性
*/
private List<Map<String, Object>> extendParams;
/**

View File

@ -4,16 +4,16 @@ import com.baomidou.mybatisplus.annotation.IEnum;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.zsc.edu.gateway.common.enums.IState;
import com.zsc.edu.gateway.framework.json.JsonTypeHandler;
import com.zsc.edu.gateway.framework.json.JsonbTypeHandler;
import com.zsc.edu.gateway.modules.iot.product.entity.Product;
import com.zsc.edu.gateway.modules.system.entity.BaseEntity;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.boot.configurationprocessor.json.JSONObject;
import java.util.List;
import java.util.Map;
/**
* @author 15864
@ -65,15 +65,14 @@ public class Device extends BaseEntity {
/**
* 扩展配置
*/
//TODO String
@TableField(typeHandler = JsonTypeHandler.class)
private List<JSONObject> extendParams;
@TableField(typeHandler = JsonbTypeHandler.class)
private List<Map<String, Object>> extendParams;
/**
* 设备属性
*/
@TableField(typeHandler = JsonTypeHandler.class)
private List<JSONObject> properties;
@TableField(typeHandler = JsonbTypeHandler.class)
private List<Map<String, Object>> properties;
/**
* 所属产品ID

View File

@ -1,25 +0,0 @@
package com.zsc.edu.gateway.modules.iot.device.entity;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
/**
* @author zhuang
*/
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class DeviceDiff {
/**
* 设备ID
*/
private Long id;
/**
* 设备名称
*/
private String name;
}

View File

@ -5,7 +5,6 @@ import com.zsc.edu.gateway.modules.iot.device.dto.BatchDeviceDto;
import com.zsc.edu.gateway.modules.iot.device.dto.DeviceDto;
import com.zsc.edu.gateway.modules.iot.device.dto.DeviceServeDto;
import com.zsc.edu.gateway.modules.iot.device.entity.Device;
import com.zsc.edu.gateway.modules.iot.device.entity.DeviceDiff;
import com.zsc.edu.gateway.modules.iot.device.vo.DeviceVo;
import java.util.List;

View File

@ -1,8 +1,6 @@
package com.zsc.edu.gateway.modules.iot.device.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zsc.edu.gateway.exception.ConstraintException;
import com.zsc.edu.gateway.exception.OutlineException;
@ -11,9 +9,7 @@ import com.zsc.edu.gateway.modules.iot.device.dto.BatchDeviceDto;
import com.zsc.edu.gateway.modules.iot.device.dto.DeviceDto;
import com.zsc.edu.gateway.modules.iot.device.dto.DeviceServeDto;
import com.zsc.edu.gateway.modules.iot.device.entity.Device;
import com.zsc.edu.gateway.modules.iot.device.entity.DeviceDiff;
import com.zsc.edu.gateway.modules.iot.device.mapper.DeviceMapper;
import com.zsc.edu.gateway.modules.iot.device.query.DeviceQuery;
import com.zsc.edu.gateway.modules.iot.device.repo.DeviceRepository;
import com.zsc.edu.gateway.modules.iot.device.service.DeviceService;
import com.zsc.edu.gateway.modules.iot.device.vo.DeviceVo;
@ -23,7 +19,6 @@ import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import java.util.*;
import java.util.stream.Collectors;
@ -124,8 +119,8 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceRepository, Device> imp
@Transactional
public Device update(DeviceDto dto, Long id) {
Device device = baseMapper.selectById(id);
if (Objects.equals(device.getName(), dto.getName())) {
throw new ConstraintException("名称为" + dto.getName() + "的设备已存在");
if (device == null) {
throw new ConstraintException("设备不存在!");
}
mapper.convert(dto, device);
updateById(device);

View File

@ -1,12 +1,11 @@
package com.zsc.edu.gateway.modules.iot.device.vo;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.zsc.edu.gateway.framework.json.JsonbTypeHandler;
import com.zsc.edu.gateway.modules.iot.device.entity.Device;
import com.zsc.edu.gateway.modules.iot.product.entity.Product;
import com.zsc.edu.gateway.modules.iot.tsl.entity.Param;
import lombok.Data;
import org.springframework.boot.configurationprocessor.json.JSONObject;
import java.time.LocalDateTime;
import java.util.List;

View File

@ -3,7 +3,7 @@ package com.zsc.edu.gateway.modules.iot.record.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.zsc.edu.gateway.framework.json.JsonTypeHandler;
//import com.zsc.edu.gateway.framework.json.MapJsonTypeHandler;
import lombok.*;
import org.springframework.format.annotation.DateTimeFormat;
@ -26,7 +26,7 @@ public class RecordData {
private String attachmentId;
@TableField(typeHandler = JsonTypeHandler.class)
// @TableField(typeHandler = MapJsonTypeHandler.class)
private Map<String, Object> content;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")

View File

@ -22,7 +22,7 @@ public class Notice extends BaseEntity {
/**
* 消息类型
*/
public NoticeType type = NoticeType.other;
public NoticeType type = NoticeType.MESSAGE;
/**
* 是否系统生成

View File

@ -17,7 +17,7 @@ public abstract class NoticePayload {
public static class Other extends NoticePayload {
public Other(String content) {
this.content = content;
this.type = NoticeType.other;
this.type = NoticeType.MESSAGE;
}
}
@ -30,7 +30,7 @@ public abstract class NoticePayload {
this.username = username;
this.password = password;
this.resetTime = resetTime;
this.type = NoticeType.resetThePassword;
this.type = NoticeType.NOTICE;
this.content = String.format("尊敬的用户%s您的密码已于%s被管理员重置新密码为%s" +
"请及时登录系统修改密码!", username, resetTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")), password);
}

View File

@ -9,8 +9,8 @@ import com.zsc.edu.gateway.common.enums.IState;
* @author zhuang
*/
public enum NoticeType implements IEnum<Integer>, IState<NoticeType> {
other(1, "消息"),
resetThePassword(2, "通知");
MESSAGE(1, "消息"),
NOTICE(2, "通知");
private final Integer value;
private final String name;

View File

@ -1,5 +1,6 @@
package com.zsc.edu.gateway.modules.message.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
@ -19,7 +20,7 @@ import java.time.LocalDateTime;
@TableName("sys_user_notice")
public class UserNotice implements Serializable {
@TableId
@TableId(type = IdType.AUTO)
private Long id;
/**

View File

@ -23,7 +23,7 @@ public class AdminNoticeVo {
/**
* 消息类型
*/
public NoticeType type = NoticeType.other;
public NoticeType type = NoticeType.MESSAGE;
/**
* 是否系统消息
*/

View File

@ -31,7 +31,7 @@ public class UserNoticeVo {
/**
* 消息类型
*/
public NoticeType type = NoticeType.other;
public NoticeType type = NoticeType.MESSAGE;
/**
* 是否系统消息
*/

View File

@ -69,6 +69,11 @@ public class DeptServiceImpl extends ServiceImpl<DeptRepository, Dept> implement
);
if (Objects.nonNull(deptId)) {
if (deptId == 0) {
// 返回全部部门树
return deptTree;
} else {
// 返回指定部门及其子部门树
List<Dept> deptChildrenTree = new ArrayList<>();
TreeUtil.forLevelOrder(deptTree, node -> {
if (node.getId().equals(deptId)) {
@ -77,6 +82,7 @@ public class DeptServiceImpl extends ServiceImpl<DeptRepository, Dept> implement
}, Dept::getChildren);
return deptChildrenTree;
}
}
return deptTree;
}

View File

@ -3,7 +3,7 @@ server:
mybatis-plus:
type-aliases-package: com.zsc.edu.gateway.modules.*.entity
mapper-locations: classpath:mappers/*/*.xml
mapper-locations: classpath*:mappers/*/*.xml
type-handlers-package: com.zsc.edu.gateway.framework.mybatisplus
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

View File

@ -472,30 +472,96 @@ VALUES ('1', 'document1.pdf', 'application/pdf', 'http://example.com/files/docum
CURRENT_TIMESTAMP - INTERVAL '3 days'),
('5', 'audio.mp3', 'audio/mpeg', 'http://example.com/files/audio.mp3', CURRENT_TIMESTAMP - INTERVAL '4 days');
INSERT INTO iot_device (id, name, online, state, hardware_version, firmware_version, factory_id, client_id, product_id,
extend_params, properties, create_by, create_time, update_by, update_time, remark)
VALUES (1, 'Device1', TRUE, 1, 'HW1.0', 'FW1.0', 'FactoryA', 'Client1', 1, '{"param1": "value1"}',
'{"prop1": "value1"}', 'Admin', CURRENT_TIMESTAMP, 'Admin', CURRENT_TIMESTAMP, 'Remark1'),
(2, 'Device2', FALSE, 2, 'HW1.1', 'FW1.1', 'FactoryB', 'Client2', 2, '{"param2": "value2"}',
'{"prop2": "value2"}', 'Admin', CURRENT_TIMESTAMP, 'Admin', CURRENT_TIMESTAMP, 'Remark2'),
(3, 'Device3', TRUE, 3, 'HW1.2', 'FW1.2', 'FactoryC', 'Client3', 3, '{"param3": "value3"}',
'{"prop3": "value3"}', 'Admin', CURRENT_TIMESTAMP, 'Admin', CURRENT_TIMESTAMP, 'Remark3'),
(4, 'Device4', FALSE, 4, 'HW1.3', 'FW1.3', 'FactoryD', 'Client4', 4, '{"param4": "value4"}',
'{"prop4": "value4"}', 'Admin', CURRENT_TIMESTAMP, 'Admin', CURRENT_TIMESTAMP, 'Remark4'),
(5, 'Device5', TRUE, 5, 'HW1.4', 'FW1.4', 'FactoryE', 'Client5', 5, '{"param5": "value5"}',
'{"prop5": "value5"}', 'Admin', CURRENT_TIMESTAMP, 'Admin', CURRENT_TIMESTAMP, 'Remark5'),
(6, 'Device6', FALSE, 6, 'HW1.5', 'FW1.5', 'FactoryF', 'Client6', 6, '{"param6": "value6"}',
'{"prop6": "value6"}', 'Admin', CURRENT_TIMESTAMP, 'Admin', CURRENT_TIMESTAMP, 'Remark6'),
(7, 'Device7', TRUE, 7, 'HW1.6', 'FW1.6', 'FactoryG', 'Client7', 7, '{"param7": "value7"}',
'{"prop7": "value7"}', 'Admin', CURRENT_TIMESTAMP, 'Admin', CURRENT_TIMESTAMP, 'Remark7'),
(8, 'Device8', FALSE, 8, 'HW1.7', 'FW1.7', 'FactoryH', 'Client8', 8, '{"param8": "value8"}',
'{"prop8": "value8"}', 'Admin', CURRENT_TIMESTAMP, 'Admin', CURRENT_TIMESTAMP, 'Remark8'),
(9, 'Device9', TRUE, 9, 'HW1.8', 'FW1.8', 'FactoryI', 'Client9', 9, '{"param9": "value9"}',
'{"prop9": "value9"}', 'Admin', CURRENT_TIMESTAMP, 'Admin', CURRENT_TIMESTAMP, 'Remark9'),
(10, 'Device10', FALSE, 10, 'HW1.9', 'FW1.9', 'FactoryJ', 'Client10', 10, '{"param10": "value10"}',
'{"prop10": "value10"}', 'Admin', CURRENT_TIMESTAMP, 'Admin', CURRENT_TIMESTAMP, 'Remark10');
INSERT INTO iot_device (name, online, state, hardware_version, firmware_version, factory_id, client_id, product_id,
extend_params, properties, create_by, create_time, update_by, update_time, remark, dept_id)
VALUES ('Device001', TRUE, 1, 'HW001', 'FW001', 'FAC001', 'CLI001', 101, '[
{
"param1"
"value1"
}
]', '[
"prop1",
"value1"
]', 'admin', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, 'Remark for Device001', 1),
('Device002', FALSE, 0, 'HW002', 'FW002', 'FAC002', 'CLI002', 102, '[
"param2",
"value2"
]', '[
"prop2",
"value2"
]', 'admin', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, 'Remark for Device002', 2),
('Device003', TRUE, 1, 'HW003', 'FW003', 'FAC003', 'CLI003', 103, '[
"param3",
"value3"
]', '[
"prop3",
"value3"
]', 'admin', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, 'Remark for Device003', 3),
('Device004', FALSE, 0, 'HW004', 'FW004', 'FAC004', 'CLI004', 104, '[
"param4",
"value4"
]', '[
"prop4",
"value4"
]', 'admin', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, 'Remark for Device004', 4),
('Device005', TRUE, 1, 'HW005', 'FW005', 'FAC005', 'CLI005', 105, '[
"param5",
"value5"
]', '[
"prop5",
"value5"
]', 'admin', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, 'Remark for Device005', 5),
('Device006', FALSE, 0, 'HW006', 'FW006', 'FAC006', 'CLI006', 106, '[
"param6",
"value6"
]', '[
"prop6",
"value6"
]', 'admin', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, 'Remark for Device006', 6),
('Device007', TRUE, 1, 'HW007', 'FW007', 'FAC007', 'CLI007', 107, '[
"param7",
"value7"
]', '[
"prop7",
"value7"
]', 'admin', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, 'Remark for Device007', 7),
('Device008', FALSE, 0, 'HW008', 'FW008', 'FAC008', 'CLI008', 108, '[
"param8",
"value8"
]', '[
"prop8",
"value8"
]', 'admin', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, 'Remark for Device008', 8),
('Device009', TRUE, 1, 'HW009', 'FW009', 'FAC009', 'CLI009', 109, '[
"param9",
"value9"
]', '[
"prop9",
"value9"
]', 'admin', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, 'Remark for Device009', 9),
('Device010', FALSE, 0, 'HW010', 'FW010', 'FAC010', 'CLI010', 110, '[
"param10",
"value10"
]', '[
"prop10",
"value10"
]', 'admin', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, 'Remark for Device010', 10);
INSERT INTO iot_product (id, name, product_type, model, link, create_by, create_time, update_by, update_time, remark,
INSERT INTO sys_user_notice (user_id, notice_id, is_read, read_time)
VALUES (1, 101, TRUE, CURRENT_TIMESTAMP - INTERVAL '1 day'),
(2, 102, FALSE, NULL),
(3, 103, TRUE, CURRENT_TIMESTAMP - INTERVAL '2 days'),
(4, 104, TRUE, CURRENT_TIMESTAMP - INTERVAL '3 days'),
(5, 105, FALSE, NULL),
(6, 106, TRUE, CURRENT_TIMESTAMP - INTERVAL '4 days'),
(7, 107, TRUE, CURRENT_TIMESTAMP - INTERVAL '5 days'),
(8, 108, FALSE, NULL),
(9, 109, TRUE, CURRENT_TIMESTAMP - INTERVAL '6 days'),
(10, 110, FALSE, NULL);
INSERT INTO iot_product (name, product_type, model, link, create_by, create_time, update_by, update_time, remark,
dept_id)
VALUES ('Product1', 'TypeA', 'ModelX', 1, 'Admin', CURRENT_TIMESTAMP, 'Admin', CURRENT_TIMESTAMP, 'Remark1', 101),
('Product2', 'TypeB', 'ModelY', 2, 'Admin', CURRENT_TIMESTAMP, 'Admin', CURRENT_TIMESTAMP, 'Remark2', 102),

View File

@ -1,6 +1,6 @@
create table iot_device
(
id bigserial not null
id bigserial
constraint _name_pk
primary key,
name varchar,
@ -11,8 +11,8 @@ create table iot_device
factory_id varchar,
client_id varchar,
product_id bigint,
extend_params varchar,
properties varchar,
extend_params jsonb,
properties jsonb,
create_by varchar,
create_time timestamp,
update_by varchar,
@ -60,3 +60,7 @@ comment on column iot_device.dept_id is '部门权限id';
alter table iot_device
owner to gitea;
r
table iot_device
owner to gitea;

View File

@ -42,3 +42,6 @@ comment on column iot_product.dept_id is '所属部门';
alter table iot_product
owner to gitea;
t_product
owner to gitea;

View File

@ -0,0 +1,32 @@
create table sys_user_notice
(
id bigint default nextval('sys_user_message_id_seq'::regclass) not null
constraint sys_user_notice_pk
primary key,
user_id bigint not null,
notice_id bigint not null,
is_read boolean not null,
read_time timestamp
);
comment
on table sys_user_notice is '用户消息';
comment
on column sys_user_notice.id is '主键';
comment
on column sys_user_notice.user_id is '用户';
comment
on column sys_user_notice.notice_id is '消息';
comment
on column sys_user_notice.is_read is '是否已读';
comment
on column sys_user_notice.read_time is '阅读时间';
alter table sys_user_notice
owner to gitea;

View File

@ -13,10 +13,10 @@
<result column="factory_id" property="factoryId"/>
<result column="client_id" property="clientId"/>
<result column="product_id" property="productId"/>
<result column="extend_params" property="extendParams"
typeHandler="com.zsc.edu.gateway.framework.json.JsonTypeHandler"/>
<result column="properties" property="properties"
typeHandler="com.zsc.edu.gateway.framework.json.JsonTypeHandler"/>
<result column="extend_params" property="extendParams" jdbcType="VARCHAR"
typeHandler="com.zsc.edu.gateway.framework.json.JsonbTypeHandler"/>
<result column="properties" property="properties" jdbcType="VARCHAR"
typeHandler="com.zsc.edu.gateway.framework.json.JsonbTypeHandler"/>
<result column="create_by" jdbcType="VARCHAR" property="deviceCreateBy"/>
<result column="update_by" jdbcType="VARCHAR" property="deviceUpdateBy"/>
<result column="create_time" jdbcType="DATE" property="deviceCreateTime"/>