Compare commits

...

48 Commits

Author SHA1 Message Date
91d99c7f6d test(message): 更新通知类型为 MESSAGE
- 在 NoticeBuilder 中将通知类型从 other 修改为 MESSAGE
- 在 NoticeServiceTest 和 UserNoticeControllerTest 中更新相关测试用例- 统一使用 NoticeType.MESSAGE 作为通知类型
2025-01-10 10:40:10 +08:00
3db1dfa5fc feat(iot): 重构设备属性和扩展参数处理
- 将 JsonTypeHandler 重命名为 JsonbTypeHandler,支持 JSONB 类型
- 更新 Device 实体类中的 extendParams 和 properties 字段类型- 修改数据库表结构,将 JSON 字段改为 JSONB 类型- 优化 JSONB 数据的插入和查询方式
2025-01-09 17:28:33 +08:00
275b7fbe50 refactor(iot): 重构设备属性和扩展参数的存储方式- 将设备属性和扩展参数从 Map<String, Object> 改为 List<Map<String, Object>> 类型
- 更新了相关的 DTO、Entity 和 Mapper 文件
- 重命名并重构了 JsonTypeHandler 类,使其支持多种 JSON 格式的处理
- 更新了 Menu 类中的 Type 枚举,使其实现 IEnum 接口
2025-01-08 21:56:26 +08:00
616d640228 refactor(transaction): 在服务层方法中添加事务注解
- 在多个服务类的创建、更新和删除方法中添加 @Transactional 注解
- 优化数据库操作,确保数据一致性
- 主要涉及设备、产品、参数、属性、事件和服务等模块
2025-01-08 19:34:05 +08:00
b431bf1c08 refactor(module): 重构消息模块代码
- 重命名多个类和文件,将 notice 替换为 message
- 更新包名和引用
- 删除部分未使用的代码
- 对menu的权限进行增加
2025-01-08 18:55:05 +08:00
2f04a305be Merge remote-tracking branch 'origin/feature/iot' into iot 2025-01-08 11:31:29 +08:00
bc82a1bfd1 refactor(iot): 调整设备映射和数据库脚本
- 修改 DeviceMapper.xml 中 name 字段的属性映射,从 name 改为 productName
-移除 gateway.sql 中的冗余数据插入和表删除语句- 优化 RoleServiceImpl 中的角色权限更新逻辑
2025-01-08 11:30:36 +08:00
1e4fb52905 refactor(exception): 优化异常处理并统一异常类型
- 移除 ApiExceptionHandler 中的重复异常处理方法
- 在 PropertyServiceImpl 中使用自定义 ApiException 替代 RuntimeException- 删除 DeviceService 中未使用的导入
- 移除 SpringSecurityConfig 中的 @EnableWebSecurity 注解
2025-01-08 10:17:44 +08:00
bd6f4c2ed6 refactor(iot): 重构物联网模块代码
- 优化设备管理相关代码,调整数据结构
- 改进产品管理功能,增加数据校验
- 重构事件和服务相关代码,提高可维护性
- 优化记录数据处理逻辑,使用Lambda查询
-调整数据库表结构,使用BigSerial类型
2025-01-08 10:09:54 +08:00
5e49367cf5 refactor(test): 重构测试用例并添加备注字段
- 在 DeviceServiceTest、EventServiceTest、ParamServiceTest、PropertyServiceTest 和 ServeServiceTest 中添加备注字段- 移除了未使用的导入语句
- 删除了 UserServiceTest 中的注释代码
2025-01-08 10:07:39 +08:00
c97e485305 test(system): 重构系统模块测试用例
- 更新了 Dept、Role 和 User 相关的测试用例
- 优化了测试数据的初始化和清理逻辑
- 调整了部分测试方法的实现方式,提高了可读性和维护性
- 移除了未使用的测试用例和冗余代码
2025-01-07 16:32:45 +08:00
6161f8abfb test(iot): 新增 IoT相关测试用例
- 新增 Device、Event、Product、Property 相关的测试用例- 更新 Param 相关的测试用例
- 新增对应的 Builder 类方便测试数据的构建
- 优化测试用例的结构,增加 setup 和 teardown 方法
2025-01-06 14:24:47 +08:00
4d58a790ab test: 添加 IoT 和 notice 模块的测试用例
- 新增 Device、Product、Serve 和 Message 相关的测试用例- 更新 Authority 和 Bulletin 服务的测试用例
- 修复 Param 服务的更新逻辑
2025-01-06 01:19:34 +08:00
f1e1c21dbf feat(iot): 添加设备服务接口和产品 DTO 更新
- 在 DeviceService 接口中添加了 create 方法,用于创建设备
- 在 ProductDto 中将 type 字段重命名为 productType,以更好地反映其含义
- 在 iot_device 表中添加了 dept_id 列,用于存储部门权限 ID
2025-01-06 01:18:00 +08:00
7d73b813c1 feat(iot): 服务参数添加外键类型和 ID 字段- 在 ServeMapper.xml 中添加了 input_param_foreign_type 和 input_param_foreign_id 字段
- 同样在 ServeMapper.xml 中添加了 output_param_foreign_type 和 output_param_foreign_id 字段
- 新增 sys_message 表用于消息管理,包括消息类型、发送方式、标题、内容等信息
2025-01-05 15:30:34 +08:00
68e00e21d5 refactor(notice): 重构公告模块
- 移除了 AttachmentServiceImpl、BulletinServiceImpl 中未使用的导入- 删除了未使用的 BulletinUser、BulletinUserRepository、MessageAttachmentRepository 类
- 更新了 EventMapper、ProductMapper、ServeMapper 中的查询语句,使用 foreign_type 和 foreign_id 字段
- 在数据库中添加了测试消息数据
2025-01-05 15:28:51 +08:00
df72492f90 refactor(test): 重构测试包结构并优化设备查询功能
- 重构测试包结构,按模块重新组织测试类
- 优化设备查询功能,增加模糊查询接口
- 更新数据库脚本,添加部门数据初始化
- 调整部分类名以更好地反映其功能和所在包
2025-01-04 15:53:55 +08:00
75d640cf3c fix(iot): 补充设备、事件和服务名称非空校验
- 在创建和更新设备、事件和服务时,增加了对名称非空的校验
- 抛出 ConstraintException 异常,提示名称不能为空
- 优化了数据完整性验证,防止非法数据入库
2024-12-28 20:54:04 +08:00
e1a027e55a refactor(iot): 重构产品和服务参数处理逻辑
- 移除 ProductParam 实体和相关操作
- 更新 Param 实体,增加 foreignType 和 foreignId 字段- 修改 ProductServiceImpl,使用 ParamService 处理参数
- 更新 Serve 实体,区分输入和输出参数
- 调整 ServeDto,分离 inputs 和 outputs
- 注释掉 JpaUserDetailsServiceImpl 中的权限查询代码
2024-12-28 20:44:32 +08:00
a9c7236a4e feat(iot): 重构物模型参数创建逻辑
- 移除 EventParam、ProductParam、ServeParam 等中间表
-将参数创建、更新和删除逻辑移至 ParamService
- 为 Param 实体添加 deptId 字段
- 优化 Bulletin 相关代码,增加单元测试
2024-12-26 14:30:02 +08:00
vertoryao
5e508a5db2 fix(菜单模块): 处理合并代码的报错 2024-12-26 09:50:32 +08:00
vertoryao
1eb01519ad Merge remote-tracking branch 'origin/feature/iot' into develop
# Conflicts:
#	src/main/java/com/zsc/edu/gateway/FirstTimeInitializer.java
#	src/main/java/com/zsc/edu/gateway/framework/mybatisplus/MyMetaObjectHandler.java
#	src/main/java/com/zsc/edu/gateway/framework/security/JpaUserDetailsServiceImpl.java
#	src/main/java/com/zsc/edu/gateway/framework/security/SpringSecurityConfig.java
#	src/main/java/com/zsc/edu/gateway/modules/system/controller/DeptController.java
#	src/main/java/com/zsc/edu/gateway/modules/system/entity/Authority.java
#	src/main/java/com/zsc/edu/gateway/modules/system/service/DeptService.java
#	src/main/java/com/zsc/edu/gateway/modules/system/service/impl/DeptServiceImpl.java
#	src/main/resources/mappers/DeptMapper.xml
#	src/main/resources/mappers/RoleMapper.xml
#	src/main/resources/mappers/systemMappers/UserMapper.xml
2024-12-25 16:58:28 +08:00
vertoryao
3772c2d33b fix(菜单模块): 优化菜单模块 2024-12-25 16:54:13 +08:00
vertoryao
b6c72c9b90 feat(菜单模块): 优化菜单模块 2024-12-24 17:12:19 +08:00
vertoryao
6a1fcc9871 feat(菜单模块): 优化菜单模块 2024-12-20 14:53:56 +08:00
be080ffb3a refactor(iot): 重构参数处理逻辑
- 合并参数创建和更新方法,减少重复代码
- 优化参数查询和删除逻辑,提高效率
-调整服务和产品相关方法,适应新的参数处理方式
-移除未使用的 ParamType 枚举
2024-12-19 15:26:54 +08:00
vertoryao
547021ca13 feat(菜单模块): 修改部分权限代码 2024-12-19 09:50:56 +08:00
f6a12e2b35 refactor(iot): 重构 IoT 模块代码
- 优化了多个控制器、服务和 mapper 类的实现
- 删除了不必要的代码和注释
- 改进了查询逻辑,使用 LambdaQueryWrapper替代复杂的 XML 配置- 统一了分页查询的实现方式
- 删除了未使用的 AttachmentVo 类
-调整了 Event 和 Product 相关的 mapper 配置
2024-12-17 14:29:37 +08:00
1c1c9586e6 refactor(iot): 重构 IoT 相关代码
- 优化了 ParamMapper 接口,删除了未使用的代码
- 改进了 ProductServiceImpl 中的代码格式和命名
- 调整了 PropertyQuery 和 PropertyServiceImpl 中的代码结构
- 删除了 GlobalResponseHandler 类,简化了响应处理逻辑
2024-12-12 15:19:11 +08:00
6f4a7a3345 refactor(iot): 重构设备和事件相关代码
- 修改设备和事件的 Mapper、Repository、Service 层代码
- 优化查询接口,改用 DeviceVo 和 EventVo 返回结果
- 移除不必要的关联查询,提高查询效率- 修正部分字段名称和数据类型,使其更加合理
2024-12-12 14:37:08 +08:00
ad31cfbd09 refactor(iot): 重构设备和事件相关代码
- 更新设备和事件的实体类定义,增加必要的字段和注解
-重构设备和事件的控制器、服务层和数据访问层接口
- 优化分页查询逻辑,使用 MP 的 IPage 接口- 删除不必要的方法和注释- 统一异常处理方式
2024-12-10 15:22:07 +08:00
1e9bf7ec46 feat(iot): 新增设备和事件相关功能
- 新增设备相关实体、DTO、控制器、服务、仓库等
- 新增事件相关实体、DTO、控制器、服务、仓库等
- 移除了一些未使用的旧代码
- 添加了fastjson依赖
2024-12-09 18:08:42 +08:00
94423833dc feat(gateway): 添加全局响应处理器和统一返回结果封装
- 新增 GlobalResponseHandler 类实现全局响应处理
- 添加 Result 类用于统一返回结果封装
- 实现 JsonUtil 工具类用于对象与 JSON 字符串转换
-优化了返回类型为 String 时的处理逻辑
2024-12-09 16:41:47 +08:00
8da7e6a32a refactor: 删除未使用的树操作工具类
- 移除 DeptTreeUtil.java 文件,该类未被使用
- 移除 TreeUtil.java 文件,该类也未被使用
2024-12-09 16:35:10 +08:00
396dfc5d2c refactor(notice): 删除冗余注释
- 移除了 BulletinServiceImpl 类中 delete 方法上的 TODO 注释
- 该注释标记了需要解决重复问题,但没有提供具体描述或解决方案
2024-12-09 16:17:09 +08:00
6fd1c6b81d refactor(notice): 重构公告模块
- 优化公告查询接口,新增分页查询功能
- 重构公告发布逻辑,支持批量发布
- 完善公告详情接口,增加用户信息
- 新增公告删除接口
- 优化公告状态切换逻辑
-调整公告附件处理方式
2024-12-09 16:16:21 +08:00
528318ff0a refactor(notice): 重构公告模块
- 优化公告查询接口,新增分页查询功能
- 重构公告发布逻辑,支持批量发布
- 完善公告详情接口,增加用户信息
- 新增公告删除接口
- 优化公告状态切换逻辑
-调整公告附件处理方式
2024-12-09 16:16:04 +08:00
e535b745ea feat(消息模块与部门模块): 修改了消息模块的bug并从新建消息接口中独立出添加附件接口,部门模块新添加了部门树返回接口 2024-12-07 17:31:11 +08:00
30338520cf feat(消息模块与部门模块): 修改了消息模块的bug并从新建消息接口中独立出添加附件接口,部门模块新添加了部门树返回接口 2024-12-06 16:01:27 +08:00
dbbc9e82db feat(消息模块与部门模块): 修改了消息模块的bug并从新建消息接口中独立出添加附件接口,部门模块新添加了部门树返回接口 2024-12-06 16:01:14 +08:00
8521262f69 feat(消息模块与部门模块): 修改了消息模块的bug并从新建消息接口中独立出添加附件接口,部门模块新添加了部门树返回接口 2024-12-06 13:09:20 +08:00
vertoryao
4948086526 feat(菜单模块): 整理了一些权限相关代码 2024-12-05 17:18:55 +08:00
13372326c0 feat(消息模块与部门模块): 修改了消息模块的bug并从新建消息接口中独立出添加附件接口,部门模块新添加了部门树返回接口 2024-12-03 17:03:30 +08:00
8706f58ebb feat(消息模块与部门模块): 修改了消息模块的bug并从新建消息接口中独立出添加附件接口,部门模块新添加了部门树返回接口 2024-12-03 16:32:33 +08:00
8d6fa0b244 feat(消息模块与部门模块): 修改了消息模块的bug并从新建消息接口中独立出添加附件接口,部门模块新添加了部门树返回接口 2024-12-03 14:31:51 +08:00
vertoryao
992af01f8f feat(菜单模块): 新增菜单模块
- 实现菜单模块的增删改查
- 设置与角色的管理
- 重写Spring Security中获取用户权限的逻辑
- 修改权限字符串(在改)
2024-11-29 17:07:08 +08:00
vertoryao
dc52d7701d first update 2024-11-29 17:05:19 +08:00
vertoryao
571bfc27b3 first update 2024-11-28 16:40:22 +08:00
239 changed files with 8708 additions and 1998 deletions
pom.xml
src/main/java/com/zsc/edu/gateway
FirstTimeInitializer.java
common
exception
framework
modules
attachment
iot
message

20
pom.xml
View File

@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.5</version>
<version>3.4.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.zsc.edu</groupId>
@ -28,14 +28,14 @@
</scm>
<properties>
<java.version>17</java.version>
<mybatis-plus.version>3.5.8</mybatis-plus.version>
<mybatis-plus.version>3.5.9</mybatis-plus.version>
<mapstruct.version>1.6.2</mapstruct.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-data-mongodb</artifactId>-->
<!-- </dependency>-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
@ -84,13 +84,18 @@
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
<scope>42.6</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-jsqlparser</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
@ -126,7 +131,6 @@
<artifactId>commons-codec</artifactId>
<version>1.17.1</version>
</dependency>
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-core</artifactId>

View File

@ -1,61 +1,93 @@
package com.zsc.edu.gateway;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zsc.edu.gateway.modules.system.dto.RoleDto;
import com.zsc.edu.gateway.modules.system.entity.*;
import com.zsc.edu.gateway.modules.system.entity.Authority;
import com.zsc.edu.gateway.modules.system.entity.Dept;
import com.zsc.edu.gateway.modules.system.entity.Role;
import com.zsc.edu.gateway.modules.system.entity.User;
import com.zsc.edu.gateway.modules.system.repo.DeptRepository;
import com.zsc.edu.gateway.modules.system.repo.RoleRepository;
import com.zsc.edu.gateway.modules.system.repo.UserRepository;
import com.zsc.edu.gateway.modules.system.repo.UserRolesRepository;
import com.zsc.edu.gateway.modules.system.service.AuthorityService;
import com.zsc.edu.gateway.modules.system.service.DeptService;
import com.zsc.edu.gateway.modules.system.service.RoleService;
import lombok.RequiredArgsConstructor;
import com.zsc.edu.gateway.modules.system.service.UserService;
import lombok.AllArgsConstructor;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Profile;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
/**
* @author zhuang
* 系统初始化程序
*
* @author harry_yao
*/
@RequiredArgsConstructor
@AllArgsConstructor
@Component
@Profile("!test")
public class FirstTimeInitializer implements CommandLineRunner {
private final DeptRepository deptRepo;
private final RoleRepository roleRepo;
private final AuthorityService authorityService;
private final UserService userService;
private final RoleService roleService;
private final UserRolesRepository userRolesRepo;
private final UserRepository userRepo;
private final DeptService deptService;
private final DeptRepository deptRepo;
private final PasswordEncoder passwordEncoder;
@Override
public void run(String... args) throws Exception {
Dept dept1 = new Dept();
Role role = new Role();
if (deptRepo.selectCount(new QueryWrapper<>()) == 0) {
dept1.setName("管理部门");
deptRepo.insert(dept1);
public void run(String... args) {
// if (authorityService.count() == 0L) {
// Authority userPerm = new Authority(null, "用户模块", "用户管理", "SYSTEM:USER", true, null);
// Authority rolePerm = new Authority(null, "角色模块", "角色管理", "SYSTEM:ROLE", true, null);
// Authority deptPerm = new Authority(null, "部门模块", "部门管理", "SYSTEM:DEPT", true, null);
// Authority AuthorityPerm = new Authority(null, "权限模块", "权限管理", "SYSTEM:AUTHORITY", true, null);
// authorityService.saveBatch(List.of(userPerm, rolePerm, deptPerm, AuthorityPerm));
// List<Authority> authorities = new ArrayList<>();
// authorities.add(new Authority(userPerm.getId(), "用户管理", "用户列表", "SYSTEM:USER:QUERY", true, null));
// authorities.add(new Authority(userPerm.getId(), "用户管理", "用户新增", "SYSTEM:USER:CREATE",true, null));
// authorities.add(new Authority(userPerm.getId(), "用户管理", "用户修改", "SYSTEM:USER:UPDATE",true, null));
// authorities.add(new Authority(userPerm.getId(), "用户管理", "用户删除", "SYSTEM:USER:DELETE",true, null));
// authorities.add(new Authority(rolePerm.getId(), "角色管理", "角色列表", "SYSTEM:ROLE:QUERY", true, null));
// authorities.add(new Authority(rolePerm.getId(), "角色管理", "角色新增", "SYSTEM:ROLE:CREATE",true, null));
// authorities.add(new Authority(rolePerm.getId(), "角色管理", "角色修改", "SYSTEM:ROLE:UPDATE",true, null));
// authorities.add(new Authority(rolePerm.getId(), "角色管理", "角色删除", "SYSTEM:ROLE:DELETE",true, null));
// authorities.add(new Authority(deptPerm.getId(), "部门管理", "部门列表", "SYSTEM:DEPT:QUERY", true, null));
// authorities.add(new Authority(deptPerm.getId(), "部门管理", "部门新增", "SYSTEM:DEPT:CREATE",true, null));
// authorities.add(new Authority(deptPerm.getId(), "部门管理", "部门修改", "SYSTEM:DEPT:UPDATE",true, null));
// authorities.add(new Authority(deptPerm.getId(), "部门管理", "部门删除", "SYSTEM:DEPT:DELETE",true, null));
// authorities.add(new Authority(AuthorityPerm.getId(), "权限管理", "权限列表", "SYSTEM:AUTHORITY:QUERY", true, null));
// authorities.add(new Authority(AuthorityPerm.getId(), "权限管理", "权限新增", "SYSTEM:AUTHORITY:CREATE",true, null));
// authorities.add(new Authority(AuthorityPerm.getId(), "权限管理", "权限修改", "SYSTEM:AUTHORITY:UPDATE",true, null));
// authorities.add(new Authority(AuthorityPerm.getId(), "权限管理", "权限删除", "SYSTEM:AUTHORITY:DELETE",true, null));
// authorityService.saveBatch(authorities);
// }
if (roleService.count() == 0L) {
Role admin = new Role();
admin.setName("管理员");
admin.setEnabled(true);
roleService.save(admin);
}
if (roleRepo.selectCount(new QueryWrapper<>()) == 0) {
RoleDto dto = new RoleDto();
dto.setName("超级管理员");
// dto.setAuthorities(new HashSet<>(Arrays.asList(Authority.values())));
role = roleService.create(dto);
if (deptService.count() == 0L) {
Dept dept = new Dept();
dept.setName("总公司");
deptService.save(dept);
}
if (userRepo.selectCount(new QueryWrapper<>()) == 0) {
if (userService.count() == 0L) {
Dept dept = deptService.getOne(new QueryWrapper<>());
Role role = roleService.getOne(new QueryWrapper<>());
User user = new User();
user.setUsername("管理员");
user.setPassword(passwordEncoder.encode("123456"));
user.setEnableState(true);
user.setPhone("13827993921");
user.setEmail("123@qq.com");
user.setDeptId(dept1.getId());
user.setUsername("admin");
user.setPassword(passwordEncoder.encode("admin"));
user.setPhone("15913375741");
user.setEmail("admin@zsc.edu.cn");
user.setName("admin");
user.setRoleId(role.getId());
userRepo.insert(user);
user.setDeptId(dept.getId());
userService.save(user);
}
}
}

View File

@ -6,12 +6,16 @@ import java.util.List;
public interface BaseMapper<D, E> {
D toDto(E entity);
E toEntity(D dto);
List<D> toDto(List<E> entityList);
List<E> toEntity(List<D> dtoList);
/**
* 更新实体类
*
* @param dto
* @param entity
*/

View File

@ -0,0 +1,130 @@
package com.zsc.edu.gateway.common.util;
import java.util.*;
import java.util.function.*;
import java.util.stream.Collectors;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
/**
* @Description: 树操作方法工具类
* @Copyright: Copyright (c) 赵侠客
* @Date: 2024-07-22 10:42
* @Version: 1.0
*/
public class TreeUtil {
/**
* 将list合成树
*
* @param list 需要合成树的List
* @param rootCheck 判断E中为根节点的条件x->x.getPId()==-1L , x->x.getParentId()==null,x->x.getParentMenuId()==0
* @param parentCheck 判断E中为父节点条件(x,y)->x.getId().equals(y.getPId())
* @param setSubChildren E中设置下级数据方法Menu::setSubMenus
* @param <E> 泛型实体对象
* @return 合成好的树
*/
public static <E> List<E> makeTree(List<E> list, Predicate<E> rootCheck, BiFunction<E, E, Boolean> parentCheck, BiConsumer<E, List<E>> setSubChildren) {
return list.stream().filter(rootCheck).peek(x -> setSubChildren.accept(x, makeChildren(x, list, parentCheck, setSubChildren))).collect(Collectors.toList());
}
/**
* 将树打平成tree
*
* @param tree 需要打平的树
* @param getSubChildren 设置下级数据方法Menu::getSubMenus,x->x.setSubMenus(null)
* @param setSubChildren 将下级数据置空方法x->x.setSubMenus(null)
* @param <E> 泛型实体对象
* @return 打平后的数据
*/
public static <E> List<E> flat(List<E> tree, Function<E, List<E>> getSubChildren, Consumer<E> setSubChildren) {
List<E> res = new ArrayList<>();
forPostOrder(tree, item -> {
setSubChildren.accept(item);
res.add(item);
}, getSubChildren);
return res;
}
/**
* 前序遍历
*
* @param tree 需要遍历的树
* @param consumer 遍历后对单个元素的处理方法x-> System.out.println(x) System.out::println打印元素
* @param setSubChildren 设置下级数据方法Menu::getSubMenus,x->x.setSubMenus(null)
* @param <E> 泛型实体对象
*/
public static <E> void forPreOrder(List<E> tree, Consumer<E> consumer, Function<E, List<E>> setSubChildren) {
for (E l : tree) {
consumer.accept(l);
List<E> es = setSubChildren.apply(l);
if (es != null && es.size() > 0) {
forPreOrder(es, consumer, setSubChildren);
}
}
}
/**
* 层序遍历
*
* @param tree 需要遍历的树
* @param consumer 遍历后对单个元素的处理方法x-> System.out.println(x) System.out::println打印元素
* @param setSubChildren 设置下级数据方法Menu::getSubMenus,x->x.setSubMenus(null)
* @param <E> 泛型实体对象
*/
public static <E> void forLevelOrder(List<E> tree, Consumer<E> consumer, Function<E, List<E>> setSubChildren) {
Queue<E> queue = new LinkedList<>(tree);
while (!queue.isEmpty()) {
E item = queue.poll();
consumer.accept(item);
List<E> childList = setSubChildren.apply(item);
if (childList != null && !childList.isEmpty()) {
queue.addAll(childList);
}
}
}
/**
* 后序遍历
*
* @param tree 需要遍历的树
* @param consumer 遍历后对单个元素的处理方法x-> System.out.println(x) System.out::println打印元素
* @param setSubChildren 设置下级数据方法Menu::getSubMenus,x->x.setSubMenus(null)
* @param <E> 泛型实体对象
*/
public static <E> void forPostOrder(List<E> tree, Consumer<E> consumer, Function<E, List<E>> setSubChildren) {
for (E item : tree) {
List<E> childList = setSubChildren.apply(item);
if (childList != null && !childList.isEmpty()) {
forPostOrder(childList, consumer, setSubChildren);
}
consumer.accept(item);
}
}
/**
* 对树所有子节点按comparator排序
*
* @param tree 需要排序的树
* @param comparator 排序规则ComparatorComparator.comparing(MenuVo::getRank)按Rank正序 ,(x,y)->y.getRank().compareTo(x.getRank())按Rank倒序
* @param getChildren 获取下级数据方法MenuVo::getSubMenus
* @param <E> 泛型实体对象
* @return 排序好的树
*/
public static <E> List<E> sort(List<E> tree, Comparator<? super E> comparator, Function<E, List<E>> getChildren) {
for (E item : tree) {
List<E> childList = getChildren.apply(item);
if (childList != null && !childList.isEmpty()) {
sort(childList, comparator, getChildren);
}
}
tree.sort(comparator);
return tree;
}
private static <E> List<E> makeChildren(E parent, List<E> allData, BiFunction<E, E, Boolean> parentCheck, BiConsumer<E, List<E>> children) {
return allData.stream().filter(x -> parentCheck.apply(parent, x)).peek(x -> children.accept(x, makeChildren(x, allData, parentCheck, children))).collect(Collectors.toList());
}
}

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,10 +0,0 @@
package com.zsc.edu.gateway.exception;
/**
* @author zhuang
*/
public class EmptyIdsException extends RuntimeException {
public EmptyIdsException(String message) {
super(message);
}
}

View File

@ -1,13 +0,0 @@
package com.zsc.edu.gateway.exception;
/**
* @author zhuang
*/
public class PublishFailedException extends RuntimeException {
public PublishFailedException(String message) {
super(message);
}
}

View File

@ -1,66 +0,0 @@
package com.zsc.edu.gateway.framework;
import com.zsc.edu.gateway.modules.system.entity.Dept;
import com.zsc.edu.gateway.modules.system.entity.User;
import com.zsc.edu.gateway.modules.system.vo.DeptTree;
import com.zsc.edu.gateway.modules.system.vo.UserTree;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@Component
public class DeptTreeUtil {
public static <E> List<E> makeTree(List<E> list, Predicate<E> rootCheck, BiFunction<E, E, Boolean> parentCheck, BiConsumer<E, List<E>> setSubChildren) {
return list.stream()
.filter(rootCheck)
.peek(x -> setSubChildren.accept(x, makeChildren(x, list, parentCheck, setSubChildren)))
.collect(Collectors.toList());
}
private static <E> List<E> makeChildren(E parent, List<E> allData, BiFunction<E, E, Boolean> parentCheck, BiConsumer<E, List<E>> setSubChildren) {
return allData.stream()
.filter(x -> parentCheck.apply(parent, x))
.peek(x -> setSubChildren.accept(x, makeChildren(x, allData, parentCheck, setSubChildren)))
.collect(Collectors.toList());
}
public static List<DeptTree> buildDeptTree(List<Dept> depots, Map<Long, List<User>> userMap) {
List<DeptTree> deptTrees = depots.stream()
.map(DeptTreeUtil::convertToDeptTree)
.collect(Collectors.toList());
deptTrees.forEach(deptTree -> {
List<User> users = userMap.getOrDefault(deptTree.getId(), Collections.emptyList());
deptTree.setMembers(users.stream()
.map(DeptTreeUtil::convertToUserTree)
.collect(Collectors.toList()));
});
return makeTree(
deptTrees,
deptTree -> deptTree.getPid() == null || deptTree.getPid() == 0L,
(parent, child) -> parent.getId().equals(child.getPid()),
DeptTree::setChildren
);
}
private static DeptTree convertToDeptTree(Dept dept) {
DeptTree deptTree = new DeptTree();
deptTree.setId(dept.getId());
deptTree.setPid(dept.getPid());
deptTree.setName(dept.getName());
return deptTree;
}
private static UserTree convertToUserTree(User user) {
UserTree userTree = new UserTree();
userTree.setId(user.getId());
userTree.setName(user.getName());
return userTree;
}
}

View File

@ -0,0 +1,25 @@
package com.zsc.edu.gateway.framework.jackson;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import java.text.SimpleDateFormat;
@Configuration
public class JacksonConfig {
@Bean
public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() {
return builder -> builder.serializationInclusion(JsonInclude.Include.NON_NULL)
.serializationInclusion(JsonInclude.Include.NON_EMPTY);
}
}

View File

@ -0,0 +1,19 @@
package com.zsc.edu.gateway.framework.json;
import com.fasterxml.jackson.annotation.JsonInclude;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author veryao
*/
@Configuration
public class JsonConfig {
@Bean
public Jackson2ObjectMapperBuilderCustomizer customizer() {
return builder -> builder.serializationInclusion(JsonInclude.Include.NON_NULL)
.serializationInclusion(JsonInclude.Include.NON_EMPTY);
}
}

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

@ -1,15 +1,13 @@
package com.zsc.edu.gateway.framework.message.email;
import com.zsc.edu.gateway.modules.attachment.entity.Attachment;
import com.zsc.edu.gateway.modules.attachment.service.AttachmentService;
import com.zsc.edu.gateway.modules.notice.entity.Message;
import com.zsc.edu.gateway.modules.message.entity.Notice;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import jakarta.annotation.Resource;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.scheduling.annotation.Async;
@ -43,7 +41,7 @@ public class EmailSender {
private final AttachmentService attachmentService;
@Async
public void send(String email, Message message) {
public void send(String email, Notice notice) {
if (StringUtils.hasText(email)) {
return;
}
@ -54,11 +52,11 @@ public class EmailSender {
} catch (AddressException e) {
return;
}
send(new InternetAddress[]{to}, message);
send(new InternetAddress[]{to}, notice);
}
@Async
public void send(Set<String> emails, Message message) {
public void send(Set<String> emails, Notice notice) {
InternetAddress[] to = emails.stream().filter(Objects::nonNull).map(email ->
{
try {
@ -77,29 +75,29 @@ public class EmailSender {
if (to.length == 0) {
return;
}
send(to, message);
send(to, notice);
}
private void send(InternetAddress[] to, Message message) {
private void send(InternetAddress[] to, Notice notice) {
try {
MimeMessage mimeMessage = sender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
helper.setTo(to);
helper.setFrom(config.username);
helper.setSubject(message.getTitle());
if (message.html) {
helper.setSubject(notice.getTitle());
if (notice.html) {
StringWriter sw = new StringWriter();
Template tp = freemarkerConfig.getTemplate(TEMPLATE, "UTF-8");
tp.process(message, sw);
tp.process(notice, sw);
helper.setText(sw.toString(), true);
} else {
helper.setText(message.content);
}
if (Objects.nonNull(message.attachments)) {
for (Attachment attachment : message.attachments) {
helper.addAttachment(attachment.fileName, attachmentService.loadAsResource(attachment.id), attachment.mimeType);
}
helper.setText(notice.content);
}
// if (Objects.nonNull(message.attachments)) {
// for (Attachment attachment : message.attachments) {
// helper.addAttachment(attachment.fileName, attachmentService.loadAsResource(attachment.id), attachment.mimeType);
// }
// }
sender.send(mimeMessage);
} catch (MessagingException | IOException | TemplateException e) {
e.printStackTrace();

View File

@ -6,6 +6,7 @@ import com.zsc.edu.gateway.framework.security.UserDetailsImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.time.LocalDateTime;
@ -20,17 +21,22 @@ public class MyMetaObjectHandler implements MetaObjectHandler {
public void insertFill(MetaObject metaObject) {
UserDetailsImpl userInfo = SecurityUtil.getUserInfo();
this.strictInsertFill(metaObject, "createTime", LocalDateTime::now, LocalDateTime.class);
this.strictInsertFill(metaObject, "createdBy", userInfo::getUsername, String.class);
if (userInfo.getUsername() == null) {
userInfo.setUsername("system");
}
this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
this.strictInsertFill(metaObject, "createBy", String.class, userInfo.getUsername());
}
@Override
public void updateFill(MetaObject metaObject) {
UserDetailsImpl userInfo = SecurityUtil.getUserInfo();
if (userInfo.getUsername() == null) {
userInfo.setUsername("system");
}
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime::now, LocalDateTime.class);
this.strictUpdateFill(metaObject, "updatedBy", userInfo::getUsername, String.class);
this.strictUpdateFill(metaObject, "updateBy", userInfo::getUsername, String.class);
}

View File

@ -10,7 +10,7 @@ import org.springframework.context.annotation.Configuration;
/**
* @author Yao
*/
@MapperScan(basePackages = "com.zsc.edu.gateway.modules.*.repo")
@MapperScan(basePackages = "com.zsc.edu.gateway.modules.**.repo")
@Configuration
public class MybatisPlusConfig {
@ -23,9 +23,8 @@ public class MybatisPlusConfig {
// // 添加自定义的数据权限处理器
// dataPermissionInterceptor.setDataPermissionHandler(new MyDataPermissionHandler());
// interceptor.addInnerInterceptor(dataPermissionInterceptor);
return interceptor;
}
}

View File

@ -0,0 +1,72 @@
package com.zsc.edu.gateway.framework.redis;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
/**
* @author zhuang
*/
@Component
public class RedisUtils {
@Autowired
private StringRedisTemplate stringRedisTemplate;
/**
* 设置键值对
*
* @param key
* @param value
*/
public void set(String key, String value) {
ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
ops.set(key, value);
}
/**
* 设置键值对并设置过期时间
*
* @param key
* @param value
* @param timeout 过期时间
* @param unit 时间单位
*/
public void set(String key, String value, long timeout, TimeUnit unit) {
ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
ops.set(key, value, timeout, unit);
}
/**
* 获取键值对
*
* @param key
* @return
*/
public String get(String key) {
ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
return ops.get(key);
}
/**
* 检查键是否存在
*
* @param key
* @return 是否存在
*/
public boolean hasKey(String key) {
return Boolean.TRUE.equals(stringRedisTemplate.hasKey(key));
}
/**
* 删除键
*
* @param key
*/
public void delete(String key) {
stringRedisTemplate.delete(key);
}
}

View File

@ -0,0 +1,71 @@
//package com.zsc.edu.gateway.framework.response;
//
//import com.fasterxml.jackson.core.JsonProcessingException;
//import com.fasterxml.jackson.databind.ObjectMapper;
//import jakarta.annotation.Resource;
//import lombok.extern.slf4j.Slf4j;
//import org.springframework.core.MethodParameter;
//import org.springframework.http.HttpHeaders;
//import org.springframework.http.MediaType;
//import org.springframework.http.converter.HttpMessageConverter;
//import org.springframework.http.server.ServerHttpRequest;
//import org.springframework.http.server.ServerHttpResponse;
//import org.springframework.web.bind.annotation.RestControllerAdvice;
//import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
//
///**
// * 响应统一封装
// * <p>
// * 将响应数据封装成统一的数据格式
// * <p>
// * 通过本处理器将接口方法返回的数据统一封装到 ResponseResult data 字段中如果接口方法返回为 void data 字段的值为 null
// *
// * @author zhuang
// */
//@Slf4j
//@RestControllerAdvice(basePackages = "com.zsc.edu.gateway")
//public class GlobalResponseHandler implements ResponseBodyAdvice<Object> {
//
// @Resource
// private ObjectMapper objectMapper;
//
// /**
// * 此组件是否支持给定的控制器方法返回类型和选定的 {@code HttpMessageConverter} 类型
// *
// * @return 如果应该调用 {@link #beforeBodyWrite} 则为 {@code true}否则为false
// */
// @Override
// public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
// // 返回类型不为ResponseResult才需要封装
// return returnType.getParameterType() != ResponseResult.class;
// }
//
// /**
// * 统一封装返回响应数据
// */
// @Override
// public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
// Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
// ServerHttpResponse response) {
//
// // 数据封装为ResponseResult将接口方法返回的数据封装到 ResponseResult.data 字段中
// ResponseResult<Object> responseResult = ResponseResult.success(body);
//
// // 返回类型不是 String直接返回
// if (returnType.getParameterType() != String.class) {
// return responseResult;
// }
//
// // 返回类型是 String不能直接返回需要进行额外处理
// // 1. Content-Type 设为 application/json 返回类型是String时默认 Content-Type = text/plain
// HttpHeaders headers = response.getHeaders();
// headers.setContentType(MediaType.APPLICATION_JSON);
// // 2. ResponseResult 转为 Json字符串 再返回
// // 否则会报错 java.lang.ClassCastException: com.example.core.model.ResponseResult cannot be cast to java.lang.String
// try {
// return objectMapper.writeValueAsString(responseResult);
// } catch (JsonProcessingException e) {
// throw new RuntimeException(e);
// }
// }
//}

View File

@ -0,0 +1,93 @@
//package com.zsc.edu.gateway.framework.response;
//
//import lombok.Getter;
//
///**
// * Http状态返回枚举
// *
// * @author javadog
// **/
//@Getter
//public enum HttpStatusEnum {
//
//
// /**
// * 操作成功
// */
// SUCCESS(200, "操作成功"),
// /**
// * 对象创建成功
// */
// CREATED(201, "对象创建成功"),
// /**
// * 请求已经被接受
// */
// ACCEPTED(202, "请求已经被接受"),
// /**
// * 操作已经执行成功但是没有返回数据
// */
// NO_CONTENT(204, "操作已经执行成功,但是没有返回数据"),
// /**
// * 资源已被移除
// */
// MOVED_PERM(301, "资源已被移除"),
// /**
// * 重定向
// */
// SEE_OTHER(303, "重定向"),
// /**
// * 资源没有被修改
// */
// NOT_MODIFIED(304, "资源没有被修改"),
// /**
// * 参数列表错误缺少格式不匹配
// */
// BAD_REQUEST(400, "参数列表错误(缺少,格式不匹配)"),
// /**
// * 未授权
// */
// UNAUTHORIZED(401, "未授权"),
// /**
// * 访问受限授权过期
// */
// FORBIDDEN(403, "访问受限,授权过期"),
// /**
// * 资源服务未找到
// */
// NOT_FOUND(404, "资源,服务未找!"),
// /**
// * 不允许的http方法
// */
// BAD_METHOD(405, "不允许的http方法"),
// /**
// * 资源冲突或者资源被锁
// */
// CONFLICT(409, "资源冲突,或者资源被锁"),
// /**
// * 不支持的数据媒体类型
// */
// UNSUPPORTED_TYPE(415, "不支持的数据,媒体类型"),
// /**
// * 系统内部错误
// */
// ERROR(500, "系统内部错误"),
// /**
// * 接口未实现
// */
// NOT_IMPLEMENTED(501, "接口未实现"),
// /**
// * 系统警告消息
// */
// WARN(601, "系统警告消息");
//
// private final Integer code;
// private final String message;
//
// HttpStatusEnum(Integer code, String message) {
//
//
// this.code = code;
// this.message = message;
// }
//}
//

View File

@ -0,0 +1,264 @@
//package com.zsc.edu.gateway.framework.response;
//
//import lombok.AllArgsConstructor;
//import lombok.Data;
//import lombok.NoArgsConstructor;
//
///**
// * 返回结果集
// *
// * @author javadog
// **/
//@Data
//@AllArgsConstructor
//@NoArgsConstructor
//public class ResponseResult<T> {
//
// /**
// * 状态码
// */
// private Integer code;
//
// /**
// * 状态信息
// */
// private Boolean status;
//
// /**
// * 返回信息
// */
// private String message;
//
// /**
// * 数据
// */
// private T data;
//
// /**
// * 全参数方法
// *
// * @param code 状态码
// * @param status 状态
// * @param message 返回信息
// * @param data 返回数据
// * @param <T> 泛型
// * @return {@link ResponseResult<T>}
// */
// private static <T> ResponseResult<T> response(Integer code, Boolean status, String message, T data) {
//
//
// ResponseResult<T> responseResult = new ResponseResult<>();
// responseResult.setCode(code);
// responseResult.setStatus(status);
// responseResult.setMessage(message);
// responseResult.setData(data);
// return responseResult;
// }
//
// /**
// * 全参数方法
// *
// * @param code 状态码
// * @param status 状态
// * @param message 返回信息
// * @param <T> 泛型
// * @return {@link ResponseResult<T>}
// */
// private static <T> ResponseResult<T> response(Integer code, Boolean status, String message) {
//
//
// ResponseResult<T> responseResult = new ResponseResult<>();
// responseResult.setCode(code);
// responseResult.setStatus(status);
// responseResult.setMessage(message);
// return responseResult;
// }
//
// /**
// * 成功返回无参
// *
// * @param <T> 泛型
// * @return {@link ResponseResult<T>}
// */
// public static <T> ResponseResult<T> success() {
//
//// return response(HttpStatus.OK.value(), true, HttpStatus.OK.getReasonPhrase(), null);
// return response(HttpStatusEnum.SUCCESS.getCode(), true, HttpStatusEnum.SUCCESS.getMessage(), null);
// }
//
// /**
// * 成功返回枚举参数
// *
// * @param httpResponseEnum 枚举参数
// * @param <T> 泛型
// * @return {@link ResponseResult<T>}
// */
// public static <T> ResponseResult<T> success(HttpStatusEnum httpResponseEnum) {
//
//
// return response(httpResponseEnum.getCode(), true, httpResponseEnum.getMessage());
// }
//
// /**
// * 成功返回状态码+返回信息
// *
// * @param code 状态码
// * @param message 返回信息
// * @param <T> 泛型
// * @return {@link ResponseResult<T>}
// */
// public static <T> ResponseResult<T> success(Integer code, String message) {
//
//
// return response(code, true, message);
// }
//
// /**
// * 成功返回返回信息 + 数据
// *
// * @param message 返回信息
// * @param data 数据
// * @param <T> 泛型
// * @return {@link ResponseResult<T>}
// */
// public static <T> ResponseResult<T> success(String message, T data) {
//
//
// return response(HttpStatusEnum.SUCCESS.getCode(), true, message, data);
// }
//
// /**
// * 成功返回状态码+返回信息+数据
// *
// * @param code 状态码
// * @param message 返回信息
// * @param data 数据
// * @param <T> 泛型
// * @return {@link ResponseResult<T>}
// */
// public static <T> ResponseResult<T> success(Integer code, String message, T data) {
//
//
// return response(code, true, message, data);
// }
//
// /**
// * 成功返回数据
// *
// * @param data 数据
// * @param <T> 泛型
// * @return {@link ResponseResult<T>}
// */
// public static <T> ResponseResult<T> success(T data) {
//
//
// return response(HttpStatusEnum.SUCCESS.getCode(), true, HttpStatusEnum.SUCCESS.getMessage(), data);
// }
//
// /**
// * 成功返回返回信息
// *
// * @param message 返回信息
// * @param <T> 泛型
// * @return {@link ResponseResult<T>}
// */
// public static <T> ResponseResult<T> success(String message) {
//
//
// return response(HttpStatusEnum.SUCCESS.getCode(), true, message, null);
// }
//
// /**
// * 失败返回无参
// *
// * @param <T> 泛型
// * @return {@link ResponseResult<T>}
// */
// public static <T> ResponseResult<T> fail() {
//
//
// return response(HttpStatusEnum.ERROR.getCode(), false, HttpStatusEnum.ERROR.getMessage(), null);
// }
//
// /**
// * 失败返回枚举
// *
// * @param httpResponseEnum 枚举
// * @param <T> 泛型
// * @return {@link ResponseResult<T>}
// */
// public static <T> ResponseResult<T> fail(HttpStatusEnum httpResponseEnum) {
//
//
// return response(httpResponseEnum.getCode(), false, httpResponseEnum.getMessage());
// }
//
// /**
// * 失败返回状态码+返回信息
// *
// * @param code 状态码
// * @param message 返回信息
// * @param <T> 泛型
// * @return {@link ResponseResult<T>}
// */
// public static <T> ResponseResult<T> fail(Integer code, String message) {
//
//
// return response(code, false, message);
// }
//
// /**
// * 失败返回返回信息+数据
// *
// * @param message 返回信息
// * @param data 数据
// * @param <T> 泛型
// * @return {@link ResponseResult<T>}
// */
// public static <T> ResponseResult<T> fail(String message, T data) {
//
//
// return response(HttpStatusEnum.ERROR.getCode(), false, message, data);
// }
//
// /**
// * 失败返回状态码+返回信息+数据
// *
// * @param code 状态码
// * @param message 返回消息
// * @param data 数据
// * @param <T> 泛型
// * @return {@link ResponseResult<T>}
// */
// public static <T> ResponseResult<T> fail(Integer code, String message, T data) {
//
//
// return response(code, false, message, data);
// }
//
// /**
// * 失败返回数据
// *
// * @param data 数据
// * @param <T> 泛型
// * @return {@link ResponseResult<T>}
// */
// public static <T> ResponseResult<T> fail(T data) {
//
//
// return response(HttpStatusEnum.ERROR.getCode(), false, HttpStatusEnum.ERROR.getMessage(), data);
// }
//
// /**
// * 失败返回返回信息
// *
// * @param message 返回信息
// * @param <T> 泛型
// * @return {@link ResponseResult<T>}
// */
// public static <T> ResponseResult<T> fail(String message) {
//
//
// return response(HttpStatusEnum.ERROR.getCode(), false, message, null);
// }
//}

View File

@ -0,0 +1,51 @@
//package com.zsc.edu.gateway.framework.response;
//
//import lombok.*;
//
///**
// * 返回响应统一封装实体
// *
// * @param <T> 数据实体泛型
// * @author zhuang
// */
//@Getter
//@ToString
//@EqualsAndHashCode
//@AllArgsConstructor(access = AccessLevel.PRIVATE)
//public class Result<T> {
//
// private String userMessage;
//
// /**
// * 错误码<br>
// * 调用成功时 null<br>
// * 示例A0211
// */
// private String errorCode;
//
// /**
// * 错误信息<br>
// * 调用成功时 null<br>
// * 示例"用户输入密码错误次数超限"
// */
// private String errorMessage;
//
// /**
// * 数据实体泛型<br>
// * 当接口没有返回数据时 null
// */
// private T data;
//
//
// public static <T> Result<T> success(T data) {
// return new Result<>("操作成功!", null, null, data);
// }
//
//
// public static <T> Result<T> fail(String userMessage, String errorCode, String errorMessage) {
// return new Result<>(userMessage, errorCode, errorMessage, null);
// }
//
//}
//
//

View File

@ -1,13 +1,18 @@
package com.zsc.edu.gateway.framework.security;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
import org.springframework.security.web.csrf.CsrfTokenRepository;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.Map;
/**
* @author harry_yao
@ -16,12 +21,10 @@ import java.io.IOException;
@Component
public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
// private final OnlineUserService onlineUserService;
// private final UserService userService;
// private final LoginLogService loginLogService;
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
// response.sendRedirect("/api/rest/user/me");
request.getRequestDispatcher("/api/rest/user/me").forward(request, response);
// Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
// String sessionId = request.getRequestedSessionId();
// String remoteAddr = request.getRemoteAddr();

View File

@ -1,30 +1,33 @@
package com.zsc.edu.gateway.framework.security;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zsc.edu.gateway.exception.ExceptionResult;
import com.zsc.edu.gateway.framework.SpringBeanUtil;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.HttpStatus;
import org.springframework.security.web.session.SessionInformationExpiredEvent;
import org.springframework.security.web.session.SessionInformationExpiredStrategy;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.Map;
/**
* @author harry_yao
*/
@Component
public class CustomSessionInformationExpiredStrategy implements SessionInformationExpiredStrategy {
@Override
public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException {
ObjectMapper objectMapper = SpringBeanUtil.getBean(ObjectMapper.class);
HttpServletResponse response = event.getResponse();
response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.setContentType("application/json;charset=utf-8");
ExceptionResult result = new ExceptionResult("会话已过期(有可能是您同时登录了太多的太多的客户端)",
HttpStatus.UNAUTHORIZED.value(),
LocalDateTime.now());
response.getWriter().print(objectMapper.writeValueAsString(result));
ObjectMapper objectMapper = new ObjectMapper();
response.getWriter().print(objectMapper.writeValueAsString(Map.of(
"msg", "会话已过期(有可能是您同时登录了太多的太多的客户端)",
"code", HttpStatus.UNAUTHORIZED.value(),
"timestamp", LocalDateTime.now()
)));
response.flushBuffer();
}
}
}

View File

@ -1,8 +1,12 @@
package com.zsc.edu.gateway.framework.security;
import com.zsc.edu.gateway.exception.StateException;
import com.zsc.edu.gateway.modules.system.entity.Menu;
import com.zsc.edu.gateway.modules.system.entity.RoleAuthority;
import com.zsc.edu.gateway.modules.system.entity.User;
import com.zsc.edu.gateway.modules.system.repo.AuthorityRepository;
import com.zsc.edu.gateway.modules.system.repo.MenuRepository;
import com.zsc.edu.gateway.modules.system.repo.RoleAuthoritiesRepository;
import com.zsc.edu.gateway.modules.system.repo.UserRepository;
import lombok.AllArgsConstructor;
import org.springframework.security.core.userdetails.UserDetails;
@ -11,6 +15,10 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* @author harry_yao
*/
@ -19,7 +27,9 @@ import org.springframework.transaction.annotation.Transactional;
public class JpaUserDetailsServiceImpl implements UserDetailsService {
private final UserRepository userRepo;
// private final RoleAuthoritiesRepository roleAuthoritiesRepository;
private final AuthorityRepository authorityRepository;
private final MenuRepository menuRepository;
@Override
@Transactional(rollbackFor = Exception.class)
@ -29,18 +39,10 @@ public class JpaUserDetailsServiceImpl implements UserDetailsService {
throw new StateException("用户 '" + username + "' 已被禁用!请联系管理员");
}
user.role.authorities = authorityRepository.selectAuthoritiesByRoleId(user.getRoleId());
// =roleAuthorities.stream()
// .map(i -> Authority.valueOf(i.getAuthority()))
// .collect(Collectors.toSet());
// .orElseThrow(() ->
// new UsernameNotFoundException("用户 '" + username + "' 不存在!")
// );
// user.getIdentities().stream().filter(identity -> identity.role.enableState == EnableState.启用)
// .forEach(identity -> Hibernate.initialize(identity.role.roleAuthorities));
return UserDetailsImpl.from(user);
// List<RoleAuthority> roleAuthorities= roleAuthoritiesRepository.selectByRoleId(user.getRoleId());
// user.role.authorities = authorityRepository.selectAuthoritiesByRoleId(user.getRoleId());
List<Menu> menus = menuRepository.selectByRoleId(user.getRoleId());
Set<String> permissions = menus.stream().map(Menu::getPermissions).collect(Collectors.toSet());
return UserDetailsImpl.from(user, permissions);
}
}

View File

@ -14,6 +14,7 @@ import java.io.IOException;
import java.util.Map;
public class JsonAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
@ -25,12 +26,12 @@ public class JsonAuthenticationFilter extends UsernamePasswordAuthenticationFilt
Map map = new ObjectMapper().readValue(request.getInputStream(), Map.class);
String username = map.get("username").toString();
String password = map.get("password").toString();
username = (username != null) ? username : "";
username = username.trim();
password = (password != null) ? password : "";
password = password.trim();
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
UsernamePasswordAuthenticationToken authRequest =
UsernamePasswordAuthenticationToken.unauthenticated(username, password);
// Allow subclasses to set the "details" property
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
@ -40,6 +41,4 @@ public class JsonAuthenticationFilter extends UsernamePasswordAuthenticationFilt
}
return super.attemptAuthentication(request, response);
}
}

View File

@ -1,19 +1,41 @@
package com.zsc.edu.gateway.framework.security;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import java.util.Objects;
import java.util.Optional;
/**
* @author Yao
*/
public class SecurityUtil {
public static UserDetailsImpl getUserInfo() {
return getPrincipal();
}
private static UserDetailsImpl getPrincipal() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (Objects.isNull(authentication)) {
return new UserDetailsImpl();
}
return (UserDetailsImpl) authentication.getPrincipal();
}
public static Optional<String> getCurrentAuditor() {
try {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication instanceof AnonymousAuthenticationToken) {
return Optional.of("system");
} else {
if (authentication == null) {
return Optional.of("system");
}
UserDetailsImpl user = (UserDetailsImpl) authentication.getPrincipal();
return Optional.of(user.getUsername());
}
} catch (Exception ex) {
// log.error("get user Authentication failed: " + ex.getMessage(), ex);
return Optional.of("system");
}
}
}

View File

@ -8,14 +8,22 @@ import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.security.web.csrf.CsrfTokenRepository;
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
import org.springframework.util.AntPathMatcher;
import javax.sql.DataSource;
@ -23,6 +31,7 @@ import javax.sql.DataSource;
* @author harry_yao
*/
@AllArgsConstructor
@EnableMethodSecurity
@Configuration
public class SpringSecurityConfig {
@ -33,15 +42,22 @@ public class SpringSecurityConfig {
private final CustomAccessDeniedHandler customAccessDeniedHandler;
private final SessionRegistry sessionRegistry;
private final SecurityBeanConfig securityBeanConfig;
private final CustomSessionInformationExpiredStrategy customSessionInformationExpiredStrategy;
@Resource
private final DataSource dataSource;
// @Bean
// public BCryptPasswordEncoder bCryptPasswordEncoder() {
// return new BCryptPasswordEncoder();
// };
@Bean
public PersistentTokenRepository persistentTokenRepository() {
JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
tokenRepository.setDataSource(dataSource);
return tokenRepository;
}
@Bean
@ -69,9 +85,48 @@ public class SpringSecurityConfig {
return http
.authorizeHttpRequests(auth -> auth
.requestMatchers(HttpMethod.GET, "/api/rest/user/me","/api/rest/user/register","/api/rest/user/send-email").permitAll()
.requestMatchers(HttpMethod.GET, "/api/rest/user/menu","/api/rest/user/register","/api/rest/user/send-email").permitAll()
.requestMatchers(HttpMethod.POST, "/api/rest/user/login","/api/rest/user/register").permitAll()
.requestMatchers("/api/**").authenticated())
.requestMatchers("/api/rest/user/me").permitAll()
.requestMatchers("/api/**").authenticated()
)
// 不用注解直接通过判断路径实现动态访问权限
// .requestMatchers("/api/**").access((authentication, object) -> {
// //表示请求的 URL 地址和数据库的地址是否匹配上了
// boolean isMatch = false;
// //获取当前请求的 URL 地址
// String requestURI = object.getRequest().getRequestURI();
// List<MenuWithRoleVO> menuWithRole = menuService.getMenuWithRole();
// for (MenuWithRoleVO m : menuWithRole) {
// AntPathMatcher antPathMatcher = new AntPathMatcher();
// if (antPathMatcher.match(m.getUrl(), requestURI)) {
// isMatch = true;
// //说明找到了请求的地址了
// //这就是当前请求需要的角色
// List<Role> roles = m.getRoles();
// //获取当前登录用户的角色
// Collection<? extends GrantedAuthority> authorities = authentication.get().getAuthorities();
// for (GrantedAuthority authority : authorities) {
// for (Role role : roles) {
// if (authority.getAuthority().equals(role.getName())) {
// //说明当前登录用户具备当前请求所需要的角色
// return new AuthorizationDecision(true);
// }
// }
// }
// }
// }
// if (!isMatch) {
// //说明请求的 URL 地址和数据库的地址没有匹配上对于这种请求统一只要登录就能访问
// if (authentication.get() instanceof AnonymousAuthenticationToken) {
// return new AuthorizationDecision(false);
// } else {
// //说明用户已经认证了
// return new AuthorizationDecision(true);
// }
// }
// return new AuthorizationDecision(false);
// }))
.addFilterAt(jsonAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.formLogin(form -> form
.loginPage("/user/login")
@ -93,7 +148,7 @@ public class SpringSecurityConfig {
.sessionManagement(session -> session
.maximumSessions(3)
.sessionRegistry(sessionRegistry)
.expiredSessionStrategy(new CustomSessionInformationExpiredStrategy()))
.expiredSessionStrategy(customSessionInformationExpiredStrategy))
.build();
}

View File

@ -1,7 +1,6 @@
package com.zsc.edu.gateway.framework.security;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.zsc.edu.gateway.common.enums.EnableState;
import com.zsc.edu.gateway.modules.system.entity.Authority;
import com.zsc.edu.gateway.modules.system.entity.Dept;
import com.zsc.edu.gateway.modules.system.entity.Role;
@ -34,8 +33,9 @@ public class UserDetailsImpl implements UserDetails {
public Dept dept;
public Role role;
public Set<Authority> authorities;
public Set<String> permissions;
public UserDetailsImpl(Long id, String username, String password, String name, Boolean enableState, Dept dept, Role role, Set<Authority> authorities) {
public UserDetailsImpl(Long id, String username, String password, String name, Boolean enableState, Dept dept, Role role, Set<Authority> authorities, Set<String> permissions) {
this.id = id;
this.username = username;
this.password = password;
@ -44,9 +44,10 @@ public class UserDetailsImpl implements UserDetails {
this.dept = dept;
this.role = role;
this.authorities = authorities;
this.permissions = permissions;
}
public static UserDetailsImpl from(User user) {
public static UserDetailsImpl from(User user, Set<String> permissions) {
return new UserDetailsImpl(
user.id,
user.username,
@ -55,14 +56,15 @@ public class UserDetailsImpl implements UserDetails {
user.enableState,
user.dept,
user.role,
user.role.authorities
user.role.authorities,
permissions
);
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities.stream().map(authority -> new SimpleGrantedAuthority(authority.getName())).collect(Collectors.toSet());
// return authorities.stream().map(authority -> new SimpleGrantedAuthority(authority.getName())).collect(Collectors.toSet());
return permissions.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toSet());
}
@Override

View File

@ -8,6 +8,7 @@ import org.springframework.core.io.Resource;
import org.springframework.http.ContentDisposition;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.parameters.P;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
@ -77,7 +78,12 @@ public class AttachmentController {
public Attachment getAttachmentInfo(@PathVariable("id") String id) {
return service.getById(id);
}
@PostMapping("uploadMultipleFiles")
/**
* 批量上传附件
*/
@PostMapping("multipartFile")
public List<Attachment> uploadMultipleFiles(
@RequestParam(defaultValue = "其他") Attachment.Type type,
@RequestParam("files") List<MultipartFile> files
@ -91,4 +97,12 @@ public class AttachmentController {
return attachments;
}
/**
* 根据附件ID删除附件信息
*/
@DeleteMapping("delete/{id}")
public Boolean delete(@PathVariable("id") String id) {
return service.delete(id);
}
}

View File

@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import lombok.*;
import org.springframework.core.io.FileSystemResource;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.time.LocalDateTime;
@ -49,9 +50,14 @@ public class Attachment implements Serializable {
/**
* 文件上传时间
*/
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
public LocalDateTime uploadTime;
/**
* 部门ID(权限)
*/
public Long deptId;
/**
* 文件下载链接
*/

View File

@ -2,11 +2,13 @@ package com.zsc.edu.gateway.modules.attachment.repo;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.zsc.edu.gateway.modules.attachment.entity.Attachment;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
/**
* @author ftz
* 创建时间:29/1/2024 上午9:55
* 描述: TODO
*/
public interface AttachmentRepository extends BaseMapper<Attachment>{
}

View File

@ -6,6 +6,7 @@ import org.springframework.core.io.Resource;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.List;
/**
* @author fantianzhi
@ -20,4 +21,8 @@ public interface AttachmentService extends IService<Attachment> {
Resource loadAsResource(String id);
Attachment.Wrapper loadAsWrapper(String id);
List<Attachment> selectList(List<String> dis);
Boolean delete(String id);
}

View File

@ -15,6 +15,7 @@ import org.apache.tika.Tika;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
@ -127,7 +128,7 @@ public class AttachmentServiceImpl extends ServiceImpl<AttachmentRepository, Att
public Attachment store(Attachment.Type type, Path file) throws IOException {
String filename = file.getFileName().toString();
MessageDigest digest = DigestUtils.getSha1Digest();
if (filename != null) {
if (StringUtils.hasText(filename)) {
digest.update(filename.getBytes());
}
Tika tika = new Tika();
@ -201,4 +202,22 @@ public class AttachmentServiceImpl extends ServiceImpl<AttachmentRepository, Att
return attachment;
}
@Override
public List<Attachment> selectList(List<String> dis) {
return repo.selectList(new LambdaQueryWrapper<Attachment>().in(Attachment::getId, dis));
}
@Override
public Boolean delete(String id) {
if (Files.exists(attachmentPath.resolve(id))) {
try {
repo.deleteById(id);
Files.delete(attachmentPath.resolve(id));
return true;
} catch (IOException e) {
log.error("删除文件失败", e);
}
}
return false;
}
}

View File

@ -1,12 +0,0 @@
package com.zsc.edu.gateway.modules.attachment.vo;
import lombok.Data;
/**
* @author zhuang
*/
@Data
public class AttachmentVo {
public String fileName;
public String url;
}

View File

@ -0,0 +1,113 @@
package com.zsc.edu.gateway.modules.iot.device.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
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.query.DeviceQuery;
import com.zsc.edu.gateway.modules.iot.device.service.DeviceService;
import com.zsc.edu.gateway.modules.iot.device.vo.DeviceVo;
import com.zsc.edu.gateway.modules.iot.record.entity.RecordData;
import com.zsc.edu.gateway.modules.iot.record.service.RecordDataService;
import lombok.AllArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @author zhuang
*/
@AllArgsConstructor
@RestController
@RequestMapping("api/rest/device")
public class DeviceController {
DeviceService service;
RecordDataService recordService;
/**
* 创建设备
*/
@PostMapping
@PreAuthorize("hasAuthority('iot:device:create')")
public Device create(@RequestBody DeviceDto deviceDto) {
return service.create(deviceDto);
}
/**
* 批量创建设备
*/
@PostMapping("batch")
@PreAuthorize("hasAuthority('iot:device:create')")
public List<Device> batchCreate(@RequestBody BatchDeviceDto batchDeviceDto) {
return service.batchCreate(batchDeviceDto);
}
/**
* 更新设备
*/
@PatchMapping("{id}")
@PreAuthorize("hasAuthority('iot:device:update')")
public Device update(@RequestBody DeviceDto deviceDto, @PathVariable("id") Long id) {
return service.update(deviceDto, id);
}
/**
* 分页查询设备
*/
@GetMapping
@PreAuthorize("hasAuthority('iot:device:query')")
public Page<Device> query(Page<Device> page, DeviceQuery query) {
return service.page(page, query.wrapper());
}
/**
* 删除设备
*/
@DeleteMapping("{id}")
@PreAuthorize("hasAuthority('iot:device:delete')")
public Boolean delete(@PathVariable("id") Long id) {
return service.removeById(id);
}
/**
* 设备
* 查询详情
*/
@GetMapping("{id}")
@PreAuthorize("hasAuthority('iot:device:query')")
public DeviceVo detail(@PathVariable("id") Long id) {
return service.detail(id);
}
/**
* 手动触发事件
*/
@PostMapping("serve")
@PreAuthorize("hasAuthority('iot:device:create')")
public ResponseEntity<String> serve(@RequestBody DeviceServeDto dto) {
if (service.serve(dto)) {
return ResponseEntity.ok("服务执行成功");
} else {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("服务执行失败");
}
}
/**
* 查询设备上报记录
*/
@GetMapping("record/data")
@PreAuthorize("hasAuthority('iot:device:query')")
public List<RecordData> recordData(String clientId) {
return recordService.recordData(clientId);
}
}

View File

@ -0,0 +1,60 @@
package com.zsc.edu.gateway.modules.iot.device.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import java.util.List;
import java.util.Map;
/**
* @author yao
*/
@Data
@EqualsAndHashCode(callSuper = false)
@AllArgsConstructor
@NoArgsConstructor
public class BatchDeviceDto {
/**
* 设备数量
*/
@NotNull
private Integer num;
/**
* 设备前缀
*/
@NotBlank(message = "前缀不能为空")
private String prefix;
/**
* 扩展属性
*/
private List<Map<String, Object>> extendParams;
/**
* 设备物模型属性
*/
private List<Map<String, Object>> properties;
/**
* 固件版本
*/
private String firmwareVersion;
/**
* 硬件版本
*/
private String hardwareVersion;
/**
* 所属产品
*/
@NotBlank(message = "所属产品不为空")
private Long productId;
/**
* 备注
*/
private String remark;
}

View File

@ -0,0 +1,57 @@
package com.zsc.edu.gateway.modules.iot.device.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import jakarta.validation.constraints.NotBlank;
import java.util.List;
import java.util.Map;
/**
* @author 15864
*/
@Data
@EqualsAndHashCode(callSuper = false)
@AllArgsConstructor
@NoArgsConstructor
public class DeviceDto {
/**
* 设备名称
*/
@NotBlank(message = "设备名不能为空")
private String name;
/**
* 硬件版本
*/
private String hardwareVersion;
/**
* 固件版本
*/
private String firmwareVersion;
/**
* 扩展属性
*/
private List<Map<String, Object>> extendParams;
/**
* 设备物模型属性
*/
private List<Map<String, Object>> properties;
/**
* 所属产品
*/
private Long productId;
/**
* 备注
*/
private String remark;
}

View File

@ -0,0 +1,41 @@
package com.zsc.edu.gateway.modules.iot.device.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import jakarta.validation.constraints.NotNull;
import java.util.Map;
/**
* @author 15864
*/
@Data
@EqualsAndHashCode(callSuper = false)
@AllArgsConstructor
@NoArgsConstructor
public class DeviceServeDto {
/**
* 设备ID
*/
@NotNull
public Long id;
/**
* 客户ID
*/
@NotNull
public String clientId;
/**
* 触发事件名称
*/
public String serveName;
/**
* 参数
*/
public Map<String, Object> params;
}

View File

@ -0,0 +1,118 @@
package com.zsc.edu.gateway.modules.iot.device.entity;
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.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 java.util.List;
import java.util.Map;
/**
* @author 15864
*/
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@TableName("iot_device")
public class Device extends BaseEntity {
/**
* 设备名称
*/
private String name;
/**
* 设备是否在线默认在线
*/
private Boolean online = false;
/**
* 设备状态
*/
private Status state = Status.UNACTIVATED;
/**
* 硬件版本
*/
private String hardwareVersion;
/**
* 固件版本
*/
private String firmwareVersion;
/**
* 出厂ID
*/
private String factoryId;
/**
* 客户ID
*/
private String clientId;
/**
* 扩展配置
*/
@TableField(typeHandler = JsonbTypeHandler.class)
private List<Map<String, Object>> extendParams;
/**
* 设备属性
*/
@TableField(typeHandler = JsonbTypeHandler.class)
private List<Map<String, Object>> properties;
/**
* 所属产品ID
*/
public Long productId;
/**
* 部门ID(权限)
*/
public Long deptId;
/**
* 所属产品
*/
@TableField(exist = false)
public Product product;
public enum Status implements IEnum<Integer>, IState<Status> {
UNACTIVATED(0, "未激活"),
LOCKED(1, "已锁定"),
ACTIVATED(2, "已激活"),
DISCARDED(3, "已报废");
private final int value;
private final String description;
Status(int value, String description) {
this.value = value;
this.description = description;
}
@Override
public Integer getValue() {
return this.value;
}
@Override
public String toString() {
return this.description;
}
}
}

View File

@ -0,0 +1,15 @@
package com.zsc.edu.gateway.modules.iot.device.mapper;
import com.zsc.edu.gateway.common.mapstruct.BaseMapper;
import com.zsc.edu.gateway.modules.iot.device.dto.DeviceDto;
import com.zsc.edu.gateway.modules.iot.device.entity.Device;
import org.mapstruct.Mapper;
import org.mapstruct.ReportingPolicy;
/**
* @author 15864
*/
@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface DeviceMapper extends BaseMapper<DeviceDto, Device> {
}

View File

@ -0,0 +1,52 @@
package com.zsc.edu.gateway.modules.iot.device.query;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zsc.edu.gateway.modules.iot.device.entity.Device;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.util.StringUtils;
import java.util.Objects;
/**
* @author zhuang
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class DeviceQuery {
/**
* 设备名称
*/
public String name;
/**
* 客户ID
*/
public String clientId;
/**
* 产品Id
*/
public Long productId;
/**
* 设备状态
*/
public Device.Status state;
/**
* 设态是否在线
*/
public Boolean isOnline;
public LambdaQueryWrapper<Device> wrapper() {
LambdaQueryWrapper<Device> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.like(StringUtils.hasText(this.name), Device::getName, this.name);
queryWrapper.eq(StringUtils.hasText(this.clientId), Device::getClientId, this.clientId);
queryWrapper.eq(Objects.nonNull(this.productId), Device::getProductId, this.productId);
queryWrapper.eq(Objects.nonNull(this.isOnline), Device::getOnline, this.isOnline);
queryWrapper.eq(Objects.nonNull(this.state), Device::getState, this.state);
return queryWrapper;
}
}

View File

@ -0,0 +1,23 @@
package com.zsc.edu.gateway.modules.iot.device.repo;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.zsc.edu.gateway.modules.iot.device.entity.Device;
import com.zsc.edu.gateway.modules.iot.device.vo.DeviceVo;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
/**
* @author zhuang
*/
public interface DeviceRepository extends BaseMapper<Device> {
@Select("select * from iot_device where name=#{name}")
Device findByName(@Param("name") String name);
DeviceVo findById(@Param("id") Long id);
@Select("select * from iot_device where client_id=#{clientId} and state=#{status} and online=#{online}")
Device findByClientIdAndStateAndOnline(@Param("clientId") String clientId,
@Param("status") Device.Status status,
@Param("online") Boolean online);
}

View File

@ -0,0 +1,25 @@
package com.zsc.edu.gateway.modules.iot.device.service;
import com.baomidou.mybatisplus.extension.service.IService;
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.vo.DeviceVo;
import java.util.List;
/**
* @author zhuang
*/
public interface DeviceService extends IService<Device> {
Device create(DeviceDto dto);
List<Device> batchCreate(BatchDeviceDto dto);
Device update(DeviceDto dto, Long id);
DeviceVo detail(Long id);
Boolean serve(DeviceServeDto dto);
}

View File

@ -0,0 +1,159 @@
package com.zsc.edu.gateway.modules.iot.device.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zsc.edu.gateway.exception.ConstraintException;
import com.zsc.edu.gateway.exception.OutlineException;
import com.zsc.edu.gateway.framework.redis.RedisUtils;
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.mapper.DeviceMapper;
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;
import com.zsc.edu.gateway.modules.iot.product.entity.Product;
import com.zsc.edu.gateway.modules.iot.product.repo.ProductRepository;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author 15864
*/
@Slf4j
@Service
public class DeviceServiceImpl extends ServiceImpl<DeviceRepository, Device> implements DeviceService {
@Resource
private DeviceMapper mapper;
@Resource
private ProductRepository productRepo;
@Resource
private RedisUtils redisUtils;
/**
* 新建设备
*/
@Override
@Transactional
public Device create(DeviceDto dto) {
if (baseMapper.findByName(dto.getName()) != null) {
throw new ConstraintException("该设备已存在!");
}
Device device = mapper.toEntity(dto);
save(device);
return device;
}
/**
* 批量新增
*/
@Override
@Transactional
public List<Device> batchCreate(BatchDeviceDto dto) {
if (dto.getNum() == null || dto.getNum() <= 0) {
throw new ConstraintException("设备数量必须大于0");
}
if (dto.getPrefix() == null) {
throw new ConstraintException("前缀不能为空!");
}
if (dto.getProductId() == null) {
throw new ConstraintException("产品ID不能为空");
}
// 获取产品信息
Product product = productRepo.selectById(dto.getProductId());
if (product == null) {
throw new ConstraintException("该产品不存在!");
}
// 生成设备名称列表
List<String> names = new ArrayList<>();
for (int i = 0; i < dto.getNum(); i++) {
String name = String.format("%s%05d", dto.getPrefix(), i + 1);
names.add(name);
}
// 检查设备名称是否已存在
LambdaQueryWrapper<Device> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.in(Device::getName, names);
List<Device> existingDevices = baseMapper.selectList(queryWrapper);
if (!existingDevices.isEmpty()) {
List<String> existingNames = existingDevices.stream()
.map(Device::getName)
.collect(Collectors.toList());
throw new ConstraintException("设备已存在!已存在的设备名称: " + String.join(", ", existingNames));
}
// 创建设备列表
List<Device> devices = new ArrayList<>();
for (int i = 0; i < dto.getNum(); i++) {
String name = String.format("%s%05d", dto.getPrefix(), i + 1);
DeviceDto deviceDto = new DeviceDto();
deviceDto.setName(name);
deviceDto.setProductId(product.getId());
deviceDto.setExtendParams(dto.getExtendParams());
deviceDto.setProperties(dto.getProperties());
deviceDto.setFirmwareVersion(dto.getFirmwareVersion());
deviceDto.setHardwareVersion(dto.getHardwareVersion());
Device device = mapper.toEntity(deviceDto);
String productType = product.getProductType();
int typeCode = Math.abs(productType.hashCode()) % 100;
device.setClientId(String.format("%s%02d%02d%05d", "001", typeCode, 3, i + 1));
devices.add(device);
}
// 批量插入设备
baseMapper.insert(devices);
return devices;
}
/**
* 更新设备
*/
@Override
@Transactional
public Device update(DeviceDto dto, Long id) {
Device device = baseMapper.selectById(id);
if (device == null) {
throw new ConstraintException("设备不存在!");
}
mapper.convert(dto, device);
updateById(device);
return device;
}
/**
* 通过Id查找设备详情
*
* @param id
* @return 设备详情
*/
@Override
public DeviceVo detail(Long id) {
return baseMapper.findById(id);
}
/**
* 物模型配置的服务
*
* @param dto
* @return
*/
@Override
public Boolean serve(DeviceServeDto dto) {
Device device = baseMapper.findByClientIdAndStateAndOnline(dto.clientId, Device.Status.ACTIVATED, true);
if (device != null) {
// amqpTemplate.convertAndSend(exchange, "send", json);
redisUtils.set("serve:sendTime:" + dto.serveName + ":" + dto.clientId, String.valueOf(new Date()));
return true;
} else {
throw new OutlineException("设备[" + dto.clientId + "]不在线!");
}
}
}

View File

@ -0,0 +1,155 @@
package com.zsc.edu.gateway.modules.iot.device.vo;
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 java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author zhuang
*/
@Data
public class DeviceVo {
/**
* 设备id
*/
private Long id;
/**
* 设备名称
*/
private String name;
/**
* 设备是否在线默认在线
*/
private Boolean online = false;
/**
* 设备状态
*/
private Device.Status state = Device.Status.UNACTIVATED;
/**
* 硬件版本
*/
private String hardwareVersion;
/**
* 固件版本
*/
private String firmwareVersion;
/**
* 出厂ID
*/
private String factoryId;
/**
* 客户ID
*/
private String clientId;
/**
* 扩展配置
*/
private List<Map<String, Object>> extendParams;
/**
* 设备属性
*/
private List<Map<String, Object>> properties;
/**
* 备注说明
*/
public String deviceRemark;
/**
* 创建时间
*/
public LocalDateTime deviceCreateTime;
/**
* 创建者
*/
public String deviceCreateBy;
/**
* 更新时间
*/
public LocalDateTime deviceUpdateTime;
/**
* 更新者
*/
public String deviceUpdateBy;
/**
* 所属产品ID
*/
public Long productId;
/**
* 产品名称
*/
private String productName;
/**
* 部门ID
*/
private Long deptId;
/**
* 产品类型
*/
private String productType;
/**
* 产品型号
*/
private String model;
/**
* 接入方式
*/
private Product.LinkType link;
/**
* 备注说明
*/
public String remark;
/**
* 创建时间
*/
public LocalDateTime createTime;
/**
* 创建者
*/
public String createBy;
/**
* 更新时间
*/
public LocalDateTime updateTime;
/**
* 更新者
*/
public String updateBy;
/**
* 设备包含的扩展属性产品不同设备所包含的属性也略有不同
*/
private Set<Param> params;
}

View File

@ -0,0 +1,105 @@
package com.zsc.edu.gateway.modules.iot.product.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zsc.edu.gateway.modules.iot.product.dto.ProductDto;
import com.zsc.edu.gateway.modules.iot.product.entity.Product;
import com.zsc.edu.gateway.modules.iot.product.query.ProductQuery;
import com.zsc.edu.gateway.modules.iot.product.service.ProductService;
import com.zsc.edu.gateway.modules.iot.product.service.impl.ProductServiceImpl;
import lombok.AllArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.web.PageableDefault;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.Collection;
/**
* @author zhuang
*/
@AllArgsConstructor
@RestController
@RequestMapping("api/rest/product")
public class ProductController {
private final ProductService service;
/**
* 创建产品
*
* @param dto 创建的产品
* @return 新的产品
*/
@PostMapping
@PreAuthorize("hasAuthority('iot:product:create')")
public Product create(@RequestBody ProductDto dto) {
return service.create(dto);
}
/**
* 更新产品
*
* @return 更新后的产品
*/
@PatchMapping("{id}")
@PreAuthorize("hasAuthority('iot:product:update')")
public Product update(@RequestBody ProductDto dto, @PathVariable("id") Long id) {
return service.update(dto, id);
}
/**
* 查询产品
*
* @param query 产品的查询表单
* @param page 分页参数
* @return Page<Device> 产品分页数据
*/
@GetMapping
@PreAuthorize("hasAuthority('iot:product:query')")
public Page<Product> page(Page<Product> page, ProductQuery query) {
return service.page(page, query.wrapper());
}
/**
* 模糊查询名字最多返回5条数据
*
* @param query 查询参数
* @return 部门列表
*/
@GetMapping("fuzzy")
@PreAuthorize("hasAuthority('iot:product:query')")
public Page<Product> fuzzyQuery(Page<Product> page, ProductQuery query) {
return service.page(page, query.fuzzyWrapper());
}
/**
* 删除产品
*
* @param id 产品编号
* @return 被删除的产品
*/
@DeleteMapping("{id}")
@PreAuthorize("hasAuthority('iot:product:delete')")
public Boolean delete(@PathVariable("id") Long id) {
return service.delete(id);
}
/**
* 产品
* 查询详情
*
* @param id ID
* @return 任务
*/
@GetMapping("{id}")
@PreAuthorize("hasAuthority('iot:product:query')")
public Product detail(@PathVariable("id") Long id) {
return service.detail(id);
}
}

View File

@ -0,0 +1,54 @@
package com.zsc.edu.gateway.modules.iot.product.dto;
import com.zsc.edu.gateway.modules.iot.product.entity.Product;
import com.zsc.edu.gateway.modules.iot.tsl.dto.ParamDto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import jakarta.validation.constraints.NotBlank;
import java.util.List;
/**
* @author Yao
*/
@Data
@EqualsAndHashCode(callSuper = false)
@NoArgsConstructor
@AllArgsConstructor
public class ProductDto {
/**
* 产品名称
*/
@NotBlank(message = "产品名称不能为空")
public String name;
/**
* 产品分类
*/
public String productType;
/**
* 产品类型
*/
public String model;
/**
* 接入方式
*/
public Product.LinkType link;
/**
* 参数
*/
private List<ParamDto> params;
/**
* 说明
*/
public String remark;
}

View File

@ -0,0 +1,90 @@
package com.zsc.edu.gateway.modules.iot.product.entity;
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.modules.iot.tsl.entity.Param;
import com.zsc.edu.gateway.modules.system.entity.BaseEntity;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.util.Set;
/**
* @author 15864
*/
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@TableName("iot_product")
public class Product extends BaseEntity {
/**
* 产品名称
*/
private String name;
/**
* 部门ID
*/
private Long deptId;
/**
* 产品类型
*/
private String productType;
/**
* 产品型号
*/
private String model;
/**
* 接入方式
*/
private LinkType link;
/**
* 设备包含的扩展属性产品不同设备所包含的属性也略有不同
*/
@TableField(exist = false)
private Set<Param> params;
/**
* 接入方式
*/
public enum LinkType implements IEnum<Integer>, IState<LinkType> {
/**
* TCP
*/
TCP(1, "TCP"),
/**
* HTTP
*/
HTTP(2, "HTTP"),
/**
* MQTT
*/
MQTT(3, "MQTT");
private final int value;
private final String description;
LinkType(int value, String description) {
this.value = value;
this.description = description;
}
@Override
public Integer getValue() {
return this.value;
}
@Override
public String toString() {
return this.description;
}
}
}

View File

@ -0,0 +1,15 @@
package com.zsc.edu.gateway.modules.iot.product.mapper;
import com.zsc.edu.gateway.common.mapstruct.BaseMapper;
import com.zsc.edu.gateway.modules.iot.product.dto.ProductDto;
import com.zsc.edu.gateway.modules.iot.product.entity.Product;
import com.zsc.edu.gateway.modules.iot.tsl.mapper.ParamMapper;
import org.mapstruct.Mapper;
import org.mapstruct.ReportingPolicy;
/**
* @author lenovo
*/
@Mapper(componentModel = "spring", uses = {ParamMapper.class}, unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface ProductMapper extends BaseMapper<ProductDto, Product> {
}

View File

@ -0,0 +1,46 @@
package com.zsc.edu.gateway.modules.iot.product.query;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zsc.edu.gateway.modules.iot.product.entity.Product;
import lombok.Data;
import org.springframework.util.StringUtils;
import java.util.List;
import java.util.Objects;
/**
* @author zhuang
*/
@Data
public class ProductQuery {
/**
* 设备名称
*/
public String name;
/**
* 产品分类
*/
public String type;
/**
* 接入方式
*/
public List<Product.LinkType> links;
public LambdaQueryWrapper<Product> wrapper() {
LambdaQueryWrapper<Product> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.like(StringUtils.hasText(this.name), Product::getName, this.name);
queryWrapper.eq(StringUtils.hasText(this.type), Product::getProductType, this.type);
if (Objects.nonNull(this.links) && !this.links.isEmpty()) {
queryWrapper.in(Product::getLink, this.links);
}
return queryWrapper;
}
public LambdaQueryWrapper<Product> fuzzyWrapper() {
LambdaQueryWrapper<Product> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.like(StringUtils.hasText(this.name), Product::getName, this.name);
return queryWrapper;
}
}

View File

@ -0,0 +1,17 @@
package com.zsc.edu.gateway.modules.iot.product.repo;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.zsc.edu.gateway.modules.iot.product.entity.Product;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
/**
* @author Yao
*/
public interface ProductRepository extends BaseMapper<Product> {
@Select("select * from iot_product where name=#{name}")
Product findByName(@Param("name") String name);
Product selectById(@Param("id") Long id);
}

View File

@ -0,0 +1,21 @@
package com.zsc.edu.gateway.modules.iot.product.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.zsc.edu.gateway.modules.iot.product.dto.ProductDto;
import com.zsc.edu.gateway.modules.iot.product.entity.Product;
import com.zsc.edu.gateway.modules.iot.product.query.ProductQuery;
/**
* @author zhuang
*/
public interface ProductService extends IService<Product> {
Product create(ProductDto dto);
Product update(ProductDto dto, Long id);
Product detail(Long id);
boolean delete(Long id);
}

View File

@ -0,0 +1,80 @@
package com.zsc.edu.gateway.modules.iot.product.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zsc.edu.gateway.exception.ConstraintException;
import com.zsc.edu.gateway.modules.iot.product.dto.ProductDto;
import com.zsc.edu.gateway.modules.iot.product.entity.Product;
import com.zsc.edu.gateway.modules.iot.product.mapper.ProductMapper;
import com.zsc.edu.gateway.modules.iot.product.repo.ProductRepository;
import com.zsc.edu.gateway.modules.iot.product.service.ProductService;
import com.zsc.edu.gateway.modules.iot.tsl.entity.Param;
import com.zsc.edu.gateway.modules.iot.tsl.service.ParamService;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* @author zhaung
*/
@AllArgsConstructor
@Service
public class ProductServiceImpl extends ServiceImpl<ProductRepository, Product> implements ProductService {
private final ProductMapper mapper;
private final ParamService paramService;
/**
* 新建产品
*/
@Override
@Transactional
public Product create(ProductDto dto) {
if (baseMapper.findByName(dto.getName()) != null) {
throw new ConstraintException("该设备已存在!");
}
if (dto.getName() == null) {
throw new ConstraintException("设备名称不能为空!");
}
Product product = mapper.toEntity(dto);
save(product);
if (dto.getParams() != null) {
paramService.create(dto.getParams(), product.getId(), Param.ForeignType.PRODUCT);
}
return product;
}
/**
* 更新产品
*/
@Override
@Transactional
public Product update(ProductDto dto, Long id) {
if (dto.getName() == null) {
throw new ConstraintException("设备名称不能为空!");
}
Product product = baseMapper.selectById(id);
mapper.convert(dto, product);
updateById(product);
paramService.update(dto.getParams(), product.getId());
return product;
}
@Override
public Product detail(Long id) {
Product product = baseMapper.selectById(id);
if (product == null) {
throw new RuntimeException("产品不存在请检查产品ID是否正确");
}
return product;
}
/**
* 删除
*/
@Override
@Transactional
public boolean delete(Long id) {
removeById(id);
paramService.delete(id);
return true;
}
}

View File

@ -0,0 +1,34 @@
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.MapJsonTypeHandler;
import lombok.*;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import java.util.Map;
/**
* @author zhuang
*/
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@TableName("iot_record_data")
public class RecordData {
@TableId
private String id;
private String clientId;
private String attachmentId;
// @TableField(typeHandler = MapJsonTypeHandler.class)
private Map<String, Object> content;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime recordTime;
}

View File

@ -0,0 +1,18 @@
package com.zsc.edu.gateway.modules.iot.record.repo;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.zsc.edu.gateway.modules.iot.record.entity.RecordData;
import org.apache.ibatis.annotations.Select;
import java.time.LocalDateTime;
import java.util.List;
/**
* @author zhuang
*/
public interface RecordDataRepository extends BaseMapper<RecordData> {
@Select("select * from iot_record_data where record_time_str = #{recordTimeStr}")
List<RecordData> findByRecordTimeStr(String recordTimeStr);
}

View File

@ -0,0 +1,18 @@
package com.zsc.edu.gateway.modules.iot.record.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.zsc.edu.gateway.modules.iot.record.entity.RecordData;
import java.util.List;
/**
* @author zhuang
*/
public interface RecordDataService extends IService<RecordData> {
RecordData create(RecordData record);
List<RecordData> page(IPage<RecordData> page, String clientId);
List<RecordData> recordData(String clientId);
}

View File

@ -0,0 +1,54 @@
package com.zsc.edu.gateway.modules.iot.record.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zsc.edu.gateway.framework.redis.RedisUtils;
import com.zsc.edu.gateway.modules.iot.record.entity.RecordData;
import com.zsc.edu.gateway.modules.iot.record.repo.RecordDataRepository;
import com.zsc.edu.gateway.modules.iot.record.service.RecordDataService;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.time.format.DateTimeParseException;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
/**
* @author zhuang
*/
@AllArgsConstructor
@Service
public class RecordDataServiceImpl extends ServiceImpl<RecordDataRepository, RecordData> implements RecordDataService {
RedisUtils redisUtils;
@Override
public RecordData create(RecordData record) {
save(record);
return record;
}
@Override
public List<RecordData> page(IPage<RecordData> page, String clientId) {
LambdaQueryWrapper<RecordData> queryWrapper = new LambdaQueryWrapper<>();
if (clientId != null) {
queryWrapper.eq(RecordData::getClientId, clientId);
return baseMapper.selectList(page, queryWrapper);
}
return baseMapper.selectList(page, queryWrapper);
}
@Override
public List<RecordData> recordData(String clientId) {
LocalDateTime recordTime = LocalDateTime.parse(redisUtils.get("serve:sendTime:photograph:" + clientId));
List<RecordData> records = baseMapper.selectList(new LambdaQueryWrapper<RecordData>()
.eq(RecordData::getClientId, clientId).le(RecordData::getRecordTime, recordTime));
Optional<RecordData> first = records.stream().max(Comparator.comparing(RecordData::getRecordTime));
if (first.isPresent()) {
String recordTimeStr = (String) first.get().getContent().get("recordTimeStr");
return baseMapper.findByRecordTimeStr(recordTimeStr);
} else {
return records;
}
}
}

View File

@ -0,0 +1,89 @@
package com.zsc.edu.gateway.modules.iot.tsl.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zsc.edu.gateway.modules.iot.tsl.dto.EventDto;
import com.zsc.edu.gateway.modules.iot.tsl.entity.Event;
import com.zsc.edu.gateway.modules.iot.tsl.query.EventQuery;
import com.zsc.edu.gateway.modules.iot.tsl.service.EventService;
import lombok.AllArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
/**
* @author zhuang
*/
@AllArgsConstructor
@RestController
@RequestMapping("api/rest/tsl/event")
public class EventController {
private final EventService service;
/**
* 创建事件
*
* @param dto 创建的事件
*/
@PostMapping
@PreAuthorize("hasAuthority('iot:event:create')")
public Event create(@RequestBody EventDto dto) {
return service.create(dto);
}
/**
* 更新事件
*
* @return 更新后的事件
*/
@PatchMapping("{id}")
@PreAuthorize("hasAuthority('iot:event:update')")
public Event update(@RequestBody EventDto dto, @PathVariable("id") Long id) {
return service.update(dto, id);
}
/**
* 查询事件
*
* @param query 事件的查询表单
* @param page 分页参数
* @return Page<Device> 事件分页数据
*/
@GetMapping
@PreAuthorize("hasAuthority('iot:event:query')")
public Page<Event> page(Page<Event> page, EventQuery query) {
return service.page(page, query.wrapper());
}
/**
* 删除事件
*
* @param id 事件编号
* @return 被删除的事件
*/
@DeleteMapping("{id}")
@PreAuthorize("hasAuthority('iot:event:delete')")
public Boolean delete(@PathVariable("id") Long id) {
return service.delete(id);
}
/**
* 事件
* 查询详情
*
* @param id ID
* @return 任务
*/
@GetMapping("{id}")
@PreAuthorize("hasAuthority('iot:event:delete')")
public Event detail(@PathVariable("id") Long id) {
return service.detail(id);
}
}

View File

@ -0,0 +1,86 @@
package com.zsc.edu.gateway.modules.iot.tsl.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zsc.edu.gateway.modules.iot.tsl.dto.PropertyDto;
import com.zsc.edu.gateway.modules.iot.tsl.entity.Property;
import com.zsc.edu.gateway.modules.iot.tsl.query.PropertyQuery;
import com.zsc.edu.gateway.modules.iot.tsl.service.PropertyService;
import lombok.AllArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @author Yao
*/
@AllArgsConstructor
@RestController
@RequestMapping("api/rest/tsl/property")
public class PropertyController {
private final PropertyService service;
/**
* 创建属性
*
* @param dto 创建的属性
* @return
*/
@PostMapping
@PreAuthorize("hasAuthority('iot:property:create')")
public Property create(@RequestBody PropertyDto dto) {
return service.create(dto);
}
/**
* 更新属性
*
* @return 更新后的属性
*/
@PatchMapping("{id}")
@PreAuthorize("hasAuthority('iot:property:update')")
public Property update(@RequestBody PropertyDto dto, @PathVariable("id") Long id) {
return service.update(dto, id);
}
/**
* 查询属性
*
* @param query 属性的查询表单
* @param page 分页参数
* @return Page<Device> 属性分页数据
*/
@GetMapping
@PreAuthorize("hasAuthority('iot:property:query')")
public Page<Property> query(PropertyQuery query, Page<Property> page) {
return service.page(page, query.wrapper());
}
/**
* 删除属性
*
* @param id 属性编号
* @return 被删除的属性
*/
@DeleteMapping("{id}")
@PreAuthorize("hasAuthority('iot:property:delete')")
public Boolean delete(@PathVariable("id") Long id) {
return service.removeById(id);
}
/**
* 属性
* 查询详情
*
* @param id ID
* @return 任务
*/
@GetMapping("{id}")
@PreAuthorize("hasAuthority('iot:property:query')")
public Property detail(@PathVariable("id") Long id) {
return service.detail(id);
}
}

View File

@ -0,0 +1,86 @@
package com.zsc.edu.gateway.modules.iot.tsl.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zsc.edu.gateway.modules.iot.tsl.dto.ServeDto;
import com.zsc.edu.gateway.modules.iot.tsl.entity.Serve;
import com.zsc.edu.gateway.modules.iot.tsl.query.ServeQuery;
import com.zsc.edu.gateway.modules.iot.tsl.service.ServeService;
import lombok.AllArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
/**
* @author Yao
*/
@AllArgsConstructor
@RestController
@RequestMapping("api/rest/tsl/serve")
public class ServeController {
private final ServeService serveService;
/**
* 创建服务
*
* @param dto 创建的服务
* @return
*/
@PostMapping
@PreAuthorize("hasAnyAuthority('iot:server:create')")
public Serve create(@RequestBody ServeDto dto) {
return serveService.create(dto);
}
/**
* 更新服务
*
* @return 更新后的服务
*/
@PatchMapping("{id}")
@PreAuthorize("hasAnyAuthority('iot:server:update')")
public Serve update(@RequestBody ServeDto dto, @PathVariable("id") Long id) {
return serveService.update(dto, id);
}
/**
* 查询服务
*
* @param query 服务的查询表单
* @param page 服务参数
* @return Page<Device> 服务分页数据
*/
@GetMapping
@PreAuthorize("hasAnyAuthority('iot:server:query')")
public Page<Serve> page(Page<Serve> page, ServeQuery query) {
return serveService.page(page, query.wrapper());
}
/**
* 删除服务
*
* @param id 服务编号
* @return 被删除的服务
*/
@DeleteMapping("{id}")
@PreAuthorize("hasAnyAuthority('iot:server:delete')")
public Boolean delete(@PathVariable("id") Long id) {
return serveService.delete(id);
}
/**
* 服务
* 查询详情
*
* @param id ID
* @return 任务
*/
@GetMapping("{id}")
@PreAuthorize("hasAnyAuthority('iot:server:query')")
public Serve detail(@PathVariable("id") Long id) {
return serveService.detail(id);
}
}

View File

@ -0,0 +1,30 @@
package com.zsc.edu.gateway.modules.iot.tsl.dto;
import com.zsc.edu.gateway.modules.iot.tsl.entity.Event;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
import java.util.Set;
/**
* @author zhuang
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class EventDto {
public Long productId;
public String name;
public String identifier;
public String remark;
public Event.Type type;
private List<ParamDto> outputs;
}

View File

@ -0,0 +1,27 @@
package com.zsc.edu.gateway.modules.iot.tsl.dto;
import com.zsc.edu.gateway.modules.iot.tsl.entity.DataType;
import com.zsc.edu.gateway.modules.iot.tsl.entity.Param;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author Yao
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ParamDto {
public String name;
public String identifier;
public String remark;
public DataType dataType;
public Param.Type type;
}

View File

@ -0,0 +1,29 @@
package com.zsc.edu.gateway.modules.iot.tsl.dto;
import com.zsc.edu.gateway.modules.iot.tsl.entity.DataType;
import com.zsc.edu.gateway.modules.iot.tsl.entity.Property;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author Yao
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PropertyDto {
public Long productId;
public String name;
public String identifier;
public String remark;
public DataType dataType;
public Property.IoType ioType;
}

View File

@ -0,0 +1,28 @@
package com.zsc.edu.gateway.modules.iot.tsl.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
import java.util.Set;
/**
* @author zhuang
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ServeDto {
public Long productId;
public String name;
public String identifier;
public String remark;
private List<ParamDto> inputs;
private List<ParamDto> outputs;
}

View File

@ -0,0 +1,43 @@
package com.zsc.edu.gateway.modules.iot.tsl.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.io.Serializable;
/**
* @author rehtd
* &#064;description 物模型事件
*/
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class BaseParam implements Serializable {
/**
* 序列化主键有数据库提供非自增
*/
@TableId(type = IdType.AUTO)
private Long id;
/**
* 标识
*/
private String identifier;
/**
* 名称
*/
private String name;
/**
* 说明
*/
private String remark;
}

View File

@ -0,0 +1,57 @@
package com.zsc.edu.gateway.modules.iot.tsl.entity;
import com.baomidou.mybatisplus.annotation.IEnum;
import com.zsc.edu.gateway.common.enums.IState;
/**
* @author lenovo
*/
public enum DataType implements IEnum<Integer>, IState<DataType> {
/**
* 整型
*/
INT(1, "整型"),
/**
* 单精度浮点型
*/
FLOAT(2, "单精度浮点型"),
/**
* 双精度浮点型
*/
DOUBLE(3, "双精度浮点型"),
/**
* 布尔型
*/
BOOLEAN(4, "布尔型"),
/**
* 字符串
*/
STRING(5, "字符串"),
/**
* 日期型
*/
DATE(6, "日期型"),
/**
* 透传
*/
RAW(7, "透传");
private final int value;
private final String description;
DataType(int value, String description) {
this.value = value;
this.description = description;
}
@Override
public Integer getValue() {
return value;
}
@Override
public String toString() {
return this.description;
}
}

View File

@ -0,0 +1,69 @@
package com.zsc.edu.gateway.modules.iot.tsl.entity;
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.modules.iot.product.entity.Product;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.context.annotation.ImportSelector;
import java.util.List;
import java.util.Set;
/**
* @author Yao
* @desciption 物模型服务
*/
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@TableName("iot_event")
public class Event extends BaseParam {
private Long productId;
/**
* 事件类型
*/
private Type type;
/**
* 服务输出的参数
*/
@TableField(exist = false)
private List<Param> outputs;
public enum Type implements IEnum<Integer>, IState<Type> {
/**
* 主动
*/
ACTIVE(1, "主动"),
/**
* 被动
*/
PASSIVE(2, "被动");
private final int value;
private final String description;
Type(int value, String description) {
this.value = value;
this.description = description;
}
@Override
public Integer getValue() {
return value;
}
@Override
public String toString() {
return this.description;
}
}
}

View File

@ -0,0 +1,109 @@
package com.zsc.edu.gateway.modules.iot.tsl.entity;
import com.baomidou.mybatisplus.annotation.IEnum;
import com.baomidou.mybatisplus.annotation.TableName;
import com.zsc.edu.gateway.common.enums.IState;
import lombok.*;
/**
* @author Yao
* &#064;desciption 参数
*/
@Setter
@Getter
@EqualsAndHashCode(callSuper = false)
@NoArgsConstructor
@AllArgsConstructor
@TableName("iot_param")
public class Param extends BaseParam {
/**
* 数据类型
*/
private DataType dataType;
/**
* 单位
*/
private String uint;
/**
* 输入输出类型
*/
private Type type;
/**
* 联表的类型
*/
private ForeignType foreignType;
/**
* 联表的id
*/
private Long foreignId;
public enum Type implements IEnum<Integer>, IState<Type> {
/**
* 物模型输入
*/
INPUT(1, "Input"),
/**
* 物模型输出
*/
OUTPUT(2, "Output"),
/**
* 读写属性
*/
RW(3, "Read Write");
private final int value;
private final String description;
Type(int value, String description) {
this.value = value;
this.description = description;
}
@Override
public Integer getValue() {
return value;
}
@Override
public String toString() {
return this.description;
}
}
public enum ForeignType implements IEnum<Integer>, IState<ForeignType> {
/**
* 事件
*/
EVENT(1, "Event"),
/**
* 服务
*/
SERVE(2, "Service"),
/**
* 产品
*/
PRODUCT(3, "Product");
private final int value;
private final String description;
ForeignType(int value, String description) {
this.value = value;
this.description = description;
}
@Override
public Integer getValue() {
return value;
}
@Override
public String toString() {
return this.description;
}
}
}

View File

@ -0,0 +1,65 @@
package com.zsc.edu.gateway.modules.iot.tsl.entity;
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.modules.iot.product.entity.Product;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
/**
* @author Yao
* &#064;desciption 物模型属性
*/
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@TableName("iot_property")
public class Property extends BaseParam {
private Long productId;
/**
* 数据类型
*/
private DataType dataType;
/**
* 读写类型
*/
private IoType ioType;
public enum IoType implements IEnum<Integer>, IState<IoType> {
/**
* 可读写
*/
READ_WRITE(1, "可读写"),
/**
* 只读
*/
READ_ONLY(2, "只读");
private final int value;
private final String description;
IoType(int value, String description) {
this.value = value;
this.description = description;
}
@Override
public Integer getValue() {
return value;
}
@Override
public String toString() {
return this.description;
}
}
}

View File

@ -0,0 +1,37 @@
package com.zsc.edu.gateway.modules.iot.tsl.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.zsc.edu.gateway.modules.iot.tsl.dto.ParamDto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.util.List;
import java.util.Set;
/**
* @author Yao
* @desciption 物模型服务
*/
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@TableName("iot_serve")
public class Serve extends BaseParam {
private Long productId;
/**
* 服务输入/输出参数根据param中的type区分
*/
@TableField(exist = false)
private List<ParamDto> inputs;
@TableField(exist = false)
private List<ParamDto> outputs;
}

View File

@ -0,0 +1,14 @@
package com.zsc.edu.gateway.modules.iot.tsl.mapper;
import com.zsc.edu.gateway.common.mapstruct.BaseMapper;
import com.zsc.edu.gateway.modules.iot.tsl.dto.EventDto;
import com.zsc.edu.gateway.modules.iot.tsl.entity.Event;
import org.mapstruct.Mapper;
import org.mapstruct.ReportingPolicy;
/**
* @author zhuang
*/
@Mapper(componentModel = "spring", uses = {ParamMapper.class}, unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface EventMapper extends BaseMapper<EventDto, Event> {
}

View File

@ -0,0 +1,14 @@
package com.zsc.edu.gateway.modules.iot.tsl.mapper;
import com.zsc.edu.gateway.common.mapstruct.BaseMapper;
import com.zsc.edu.gateway.modules.iot.tsl.dto.ParamDto;
import com.zsc.edu.gateway.modules.iot.tsl.entity.Param;
import org.mapstruct.Mapper;
import org.mapstruct.ReportingPolicy;
/**
* @author zhuang
*/
@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface ParamMapper extends BaseMapper<ParamDto, Param> {
}

View File

@ -0,0 +1,14 @@
package com.zsc.edu.gateway.modules.iot.tsl.mapper;
import com.zsc.edu.gateway.common.mapstruct.BaseMapper;
import com.zsc.edu.gateway.modules.iot.tsl.dto.PropertyDto;
import com.zsc.edu.gateway.modules.iot.tsl.entity.Property;
import org.mapstruct.Mapper;
import org.mapstruct.ReportingPolicy;
/**
* @author zhuang
*/
@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface PropertyMapper extends BaseMapper<PropertyDto, Property> {
}

View File

@ -0,0 +1,14 @@
package com.zsc.edu.gateway.modules.iot.tsl.mapper;
import com.zsc.edu.gateway.common.mapstruct.BaseMapper;
import com.zsc.edu.gateway.modules.iot.tsl.dto.ServeDto;
import com.zsc.edu.gateway.modules.iot.tsl.entity.Serve;
import org.mapstruct.Mapper;
import org.mapstruct.ReportingPolicy;
/**
* @author zhuang
*/
@Mapper(componentModel = "spring", uses = {ParamMapper.class}, unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface ServeMapper extends BaseMapper<ServeDto, Serve> {
}

View File

@ -0,0 +1,49 @@
package com.zsc.edu.gateway.modules.iot.tsl.query;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zsc.edu.gateway.modules.iot.product.entity.Product;
import com.zsc.edu.gateway.modules.iot.tsl.entity.Event;
import lombok.Data;
import org.springframework.util.StringUtils;
import java.util.Objects;
/**
* @author zhuang
*/
@Data
public class EventQuery {
/**
* 标识
*/
public String identifier;
/**
* 名称
*/
public String name;
/**
* 1异常上报
* 0普通上报
* 事件级别
*/
public String level;
/**
* 名称
*/
public Long productId;
public LambdaQueryWrapper<Event> wrapper() {
LambdaQueryWrapper<Event> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.like(StringUtils.hasText(this.name), Event::getName, this.name);
queryWrapper.like(StringUtils.hasText(this.identifier), Event::getIdentifier, this.identifier);
queryWrapper.eq(StringUtils.hasText(this.level), Event::getType, this.level);
queryWrapper.eq(Objects.nonNull(this.productId), Event::getProductId, this.productId);
return queryWrapper;
}
}

View File

@ -0,0 +1,45 @@
package com.zsc.edu.gateway.modules.iot.tsl.query;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zsc.edu.gateway.modules.iot.tsl.entity.Property;
import com.zsc.edu.gateway.modules.system.entity.Dept;
import lombok.Data;
import org.springframework.util.StringUtils;
import java.util.Objects;
/**
* @author zhuang
*/
@Data
public class PropertyQuery {
/**
* 标识
*/
public String identifier;
/**
* 名称
*/
public String name;
/**
* 名称
*/
public Long productId;
/**
* 读写类型
*/
public Property.IoType type;
public LambdaQueryWrapper<Property> wrapper() {
LambdaQueryWrapper<Property> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(this.type != null, Property::getIoType, this.type);
queryWrapper.like(StringUtils.hasText(this.identifier), Property::getIdentifier, this.identifier);
queryWrapper.eq(Objects.nonNull(this.productId), Property::getProductId, this.productId);
queryWrapper.like(StringUtils.hasText(this.name), Property::getName, this.name);
return queryWrapper;
}
}

View File

@ -0,0 +1,39 @@
package com.zsc.edu.gateway.modules.iot.tsl.query;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zsc.edu.gateway.modules.iot.tsl.entity.Event;
import com.zsc.edu.gateway.modules.iot.tsl.entity.Serve;
import lombok.Data;
import org.springframework.util.StringUtils;
import java.util.Objects;
/**
* @author 15864
*/
@Data
public class ServeQuery {
/**
* 标识
*/
public String identifier;
/**
* 名称
*/
public String name;
/**
* 名称
*/
public Long productId;
public LambdaQueryWrapper<Serve> wrapper() {
LambdaQueryWrapper<Serve> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.like(StringUtils.hasText(this.name), Serve::getName, this.name);
queryWrapper.like(StringUtils.hasText(this.identifier), Serve::getIdentifier, this.identifier);
queryWrapper.eq(Objects.nonNull(this.productId), Serve::getProductId, this.productId);
return queryWrapper;
}
}

View File

@ -0,0 +1,27 @@
package com.zsc.edu.gateway.modules.iot.tsl.repo;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zsc.edu.gateway.modules.iot.tsl.entity.Event;
import com.zsc.edu.gateway.modules.iot.tsl.query.EventQuery;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
import java.util.Optional;
/**
* @author Yao
*/
public interface EventRepository extends BaseMapper<Event> {
@Select("select * from iot_event where name=#{name}")
Event findByName(String name);
// List<Event> findByProductId(Long productId);
// IPage<Event> page(Page<Event> page, @Param("query") EventQuery query);
Event selectById(@Param("id") Long id);
}

View File

@ -0,0 +1,10 @@
package com.zsc.edu.gateway.modules.iot.tsl.repo;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.zsc.edu.gateway.modules.iot.tsl.entity.Param;
/**
* @author lenovo
*/
public interface ParamRepository extends BaseMapper<Param> {
}

View File

@ -0,0 +1,22 @@
package com.zsc.edu.gateway.modules.iot.tsl.repo;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zsc.edu.gateway.modules.iot.tsl.entity.Event;
import com.zsc.edu.gateway.modules.iot.tsl.entity.Property;
import com.zsc.edu.gateway.modules.iot.tsl.query.PropertyQuery;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* @author zhuang
*/
public interface PropertyRepository extends BaseMapper<Property> {
@Select("select * from iot_property where name=#{name}")
Property findByName(@Param("name") String name);
}

View File

@ -0,0 +1,30 @@
package com.zsc.edu.gateway.modules.iot.tsl.repo;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zsc.edu.gateway.modules.iot.tsl.entity.Property;
import com.zsc.edu.gateway.modules.iot.tsl.entity.Serve;
import com.zsc.edu.gateway.modules.iot.tsl.query.PropertyQuery;
import com.zsc.edu.gateway.modules.iot.tsl.query.ServeQuery;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
import java.util.Optional;
/**
* @author Yao
*/
public interface ServeRepository extends BaseMapper<Serve> {
@Select("select * from iot_serve where name=#{name}")
Serve findByName(@Param("name") String name);
// List<Serve> findByProductId(Long productId);
// IPage<Serve> page(Page<Serve> page, @Param("query") ServeQuery query);
Serve selectById(@Param("id") Long id);
}

View File

@ -0,0 +1,21 @@
package com.zsc.edu.gateway.modules.iot.tsl.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.zsc.edu.gateway.modules.iot.tsl.dto.EventDto;
import com.zsc.edu.gateway.modules.iot.tsl.entity.Event;
import com.zsc.edu.gateway.modules.iot.tsl.query.EventQuery;
/**
* @author zhuang
*/
public interface EventService extends IService<Event> {
Event create(EventDto dto);
Event update(EventDto dto, Long id);
Event detail(Long id);
boolean delete(Long id);
}

View File

@ -0,0 +1,19 @@
package com.zsc.edu.gateway.modules.iot.tsl.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.zsc.edu.gateway.modules.iot.tsl.dto.ParamDto;
import com.zsc.edu.gateway.modules.iot.tsl.entity.Param;
import java.util.List;
/**
* @author zhuang
*/
public interface ParamService extends IService<Param> {
Boolean create(List<ParamDto> params, Long id, Param.ForeignType foreignType);
Boolean update(List<ParamDto> paramDto, Long id);
Boolean delete(Long id);
}

View File

@ -0,0 +1,20 @@
package com.zsc.edu.gateway.modules.iot.tsl.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.zsc.edu.gateway.modules.iot.tsl.dto.PropertyDto;
import com.zsc.edu.gateway.modules.iot.tsl.entity.Property;
import com.zsc.edu.gateway.modules.iot.tsl.query.PropertyQuery;
/**
* @author zhuang
*/
public interface PropertyService extends IService<Property> {
Property create(PropertyDto dto);
Property update(PropertyDto dto, Long id);
Property detail(Long id);
}

View File

@ -0,0 +1,21 @@
package com.zsc.edu.gateway.modules.iot.tsl.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.zsc.edu.gateway.modules.iot.tsl.dto.ServeDto;
import com.zsc.edu.gateway.modules.iot.tsl.entity.Serve;
import com.zsc.edu.gateway.modules.iot.tsl.query.ServeQuery;
/**
* @author zhuang
*/
public interface ServeService extends IService<Serve> {
Serve create(ServeDto dto);
Serve update(ServeDto dto, Long id);
Serve detail(Long id);
Boolean delete(Long id);
}

View File

@ -0,0 +1,81 @@
package com.zsc.edu.gateway.modules.iot.tsl.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zsc.edu.gateway.exception.ConstraintException;
import com.zsc.edu.gateway.modules.iot.tsl.dto.EventDto;
import com.zsc.edu.gateway.modules.iot.tsl.entity.Event;
import com.zsc.edu.gateway.modules.iot.tsl.entity.Param;
import com.zsc.edu.gateway.modules.iot.tsl.mapper.EventMapper;
import com.zsc.edu.gateway.modules.iot.tsl.repo.EventRepository;
import com.zsc.edu.gateway.modules.iot.tsl.service.EventService;
import com.zsc.edu.gateway.modules.iot.tsl.service.ParamService;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* @author Yao
*/
@Service
@AllArgsConstructor
public class EventServiceImpl extends ServiceImpl<EventRepository, Event> implements EventService {
private final EventMapper mapper;
private final ParamService paramService;
/**
* 新建物模型事件
*/
@Override
@Transactional
public Event create(EventDto dto) {
if (baseMapper.findByName(dto.getName()) != null) {
throw new ConstraintException("该事件已存在!");
}
if (dto.getName() == null) {
throw new ConstraintException("事件名称不能为空!");
}
Event event = mapper.toEntity(dto);
save(event);
paramService.create(dto.getOutputs(), event.getId(), Param.ForeignType.EVENT);
return event;
}
/**
* 更新物模型事件
*/
@Override
@Transactional
public Event update(EventDto dto, Long id) {
if (dto.getName() == null) {
throw new ConstraintException("事件名称不能为空!");
}
Event event = baseMapper.selectById(id);
mapper.convert(dto, event);
updateById(event);
paramService.update(dto.getOutputs(), event.getId());
return event;
}
/**
* 查询详情
* @param id Id
* @return Event
*/
@Override
public Event detail(Long id) {
Event event = baseMapper.selectById(id);
if (event == null) {
throw new ConstraintException("该事件不存在请检查输入ID是否正确");
}
return event;
}
/**
*删除
*/
@Override
@Transactional
public boolean delete(Long id) {
removeById(id);
return paramService.delete(id);
}
}

View File

@ -0,0 +1,69 @@
package com.zsc.edu.gateway.modules.iot.tsl.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zsc.edu.gateway.modules.iot.tsl.dto.ParamDto;
import com.zsc.edu.gateway.modules.iot.tsl.entity.Param;
import com.zsc.edu.gateway.modules.iot.tsl.mapper.ParamMapper;
import com.zsc.edu.gateway.modules.iot.tsl.repo.ParamRepository;
import com.zsc.edu.gateway.modules.iot.tsl.service.ParamService;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
/**
* @author zhuang
*/
@AllArgsConstructor
@Service
public class ParamServiceImpl extends ServiceImpl<ParamRepository, Param> implements ParamService {
private final ParamMapper mapper;
private final ParamMapper paramMapper;
@Override
@Transactional
public Boolean create(List<ParamDto> params, Long id, Param.ForeignType foreignType) {
List<Param> paramsToInsert = params.stream()
.map(dto -> {
Param param = mapper.toEntity(dto);
param.setForeignId(id);
param.setForeignType(foreignType);
return param;
})
.collect(Collectors.toList());
baseMapper.insert(paramsToInsert);
return true;
}
@Override
@Transactional
public Boolean update(List<ParamDto> paramDto, Long id) {
List<Param> params = baseMapper.selectList(new LambdaQueryWrapper<Param>()
.eq(Objects.nonNull(id), Param::getForeignId, id));
if (!params.isEmpty() && !paramDto.isEmpty()) {
List<Param> updatedParams = IntStream.range(0, Math.min(params.size(), paramDto.size()))
.parallel()
.mapToObj(i -> {
Param param = params.get(i);
ParamDto dto = paramDto.get(i);
paramMapper.convert(dto, param);
return param;
})
.collect(Collectors.toList());
baseMapper.updateById(updatedParams);
}
return true;
}
@Override
@Transactional
public Boolean delete(Long id) {
return baseMapper.delete(new LambdaQueryWrapper<Param>()
.eq(Objects.nonNull(id), Param::getForeignId, id)) > 0;
}
}

View File

@ -0,0 +1,60 @@
package com.zsc.edu.gateway.modules.iot.tsl.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zsc.edu.gateway.exception.ApiException;
import com.zsc.edu.gateway.modules.iot.tsl.dto.PropertyDto;
import com.zsc.edu.gateway.modules.iot.tsl.entity.Property;
import com.zsc.edu.gateway.modules.iot.tsl.mapper.PropertyMapper;
import com.zsc.edu.gateway.modules.iot.tsl.repo.PropertyRepository;
import com.zsc.edu.gateway.modules.iot.tsl.service.PropertyService;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* @author 15864
*/
@AllArgsConstructor
@Service
public class PropertyServiceImpl extends ServiceImpl<PropertyRepository, Property> implements PropertyService {
private final PropertyMapper mapper;
/**
* 新建物模型属性
*/
@Override
@Transactional
public Property create(PropertyDto dto) {
if (baseMapper.findByName(dto.getName()) != null) {
throw new ApiException("该属性已存在!");
}
Property property = mapper.toEntity(dto);
save(property);
return property;
}
/**
* 更新属性
*/
@Override
@Transactional
public Property update(PropertyDto dto, Long id) {
Property property = baseMapper.selectById(id);
if (property == null) {
throw new ApiException("Serve not found with id: " + id);
}
mapper.convert(dto, property);
baseMapper.updateById(property);
return property;
}
@Override
public Property detail(Long id) {
Property property = baseMapper.selectById(id);
if (property == null) {
throw new ApiException("属性不存在请检查输入ID是否正确");
}
return property;
}
}

View File

@ -0,0 +1,92 @@
package com.zsc.edu.gateway.modules.iot.tsl.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zsc.edu.gateway.exception.ConstraintException;
import com.zsc.edu.gateway.modules.iot.tsl.dto.ParamDto;
import com.zsc.edu.gateway.modules.iot.tsl.dto.ServeDto;
import com.zsc.edu.gateway.modules.iot.tsl.entity.*;
import com.zsc.edu.gateway.modules.iot.tsl.mapper.ServeMapper;
import com.zsc.edu.gateway.modules.iot.tsl.repo.ServeRepository;
import com.zsc.edu.gateway.modules.iot.tsl.service.ParamService;
import com.zsc.edu.gateway.modules.iot.tsl.service.ServeService;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
/**
* @author 15864
*/
@AllArgsConstructor
@Service
public class ServeServiceImpl extends ServiceImpl<ServeRepository, Serve> implements ServeService {
private final ServeMapper mapper;
private final ParamService paramService;
/**
* 新建功能
*/
@Override
@Transactional
public Serve create(ServeDto dto) {
if (baseMapper.findByName(dto.getName()) != null) {
throw new ConstraintException("该服务已存在!");
}
if (dto.getName() == null) {
throw new ConstraintException("服务名称不能为空!");
}
Serve serve = mapper.toEntity(dto);
save(serve);
List<ParamDto> params = new ArrayList<>(dto.getInputs());
params.addAll(dto.getOutputs());
paramService.create(params, serve.getId(), Param.ForeignType.SERVE);
return serve;
}
/**
* 更新功能
*/
@Override
@Transactional
public Serve update(ServeDto dto, Long id) {
if (dto.getName() == null) {
throw new ConstraintException("服务名称不能为空!");
}
Serve serve = baseMapper.selectById(id);
mapper.convert(dto, serve);
updateById(serve);
List<ParamDto> params = new ArrayList<>(dto.getInputs());
params.addAll(dto.getOutputs());
paramService.update(params, serve.getId());
return serve;
}
/**
* 查询详情
* @param id 主键
* @return Serve
*/
@Override
public Serve detail(Long id) {
Serve serve = baseMapper.selectById(id);
if (serve == null) {
throw new ConstraintException("该服务不存在请检查输入ID是否正确");
}
return serve;
}
/**
* 删除功能
*
* @param id serveId
* @return true
*/
@Override
@Transactional
public Boolean delete(Long id) {
removeById(id);
return paramService.delete(id);
}
}

View File

@ -1,20 +1,18 @@
package com.zsc.edu.gateway.modules.notice.controller;
package com.zsc.edu.gateway.modules.message.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zsc.edu.gateway.framework.security.UserDetailsImpl;
import com.zsc.edu.gateway.modules.notice.dto.BulletinDto;
import com.zsc.edu.gateway.modules.notice.entity.Bulletin;
import com.zsc.edu.gateway.modules.notice.query.BulletinQuery;
import com.zsc.edu.gateway.modules.notice.service.BulletinService;
import com.zsc.edu.gateway.modules.notice.vo.BulletinVo;
import com.zsc.edu.gateway.modules.message.dto.BulletinDto;
import com.zsc.edu.gateway.modules.message.entity.Bulletin;
import com.zsc.edu.gateway.modules.message.query.BulletinQuery;
import com.zsc.edu.gateway.modules.message.service.BulletinService;
import com.zsc.edu.gateway.modules.message.vo.BulletinVo;
import lombok.AllArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Set;
/**
* 公告Controller
@ -34,7 +32,7 @@ public class BulletinController {
* @return 公告
*/
@GetMapping("/self/{id}")
public List<BulletinVo> selfDetail(@AuthenticationPrincipal UserDetailsImpl userDetails, @PathVariable("id") Long id) {
public BulletinVo selfDetail(@AuthenticationPrincipal UserDetailsImpl userDetails, @PathVariable("id") Long id) {
return service.detail(userDetails,id, Bulletin.State.publish);
}
@ -45,10 +43,9 @@ public class BulletinController {
* @return 分页数据
*/
@GetMapping("/self")
public IPage<BulletinVo> getBulletins( BulletinQuery query) {
public Page<Bulletin> getBulletins(Page<Bulletin> page, BulletinQuery query) {
query.setState(Bulletin.State.publish);
Page<BulletinVo> page = new Page<>(query.getPageNum(), query.getPageSize());
return service.selectPageByConditions(page, query);
return service.page(page, query.wrapper());
}
/**
@ -58,8 +55,8 @@ public class BulletinController {
* @return 公告
*/
@GetMapping("/{id}")
@PreAuthorize("hasAuthority('BULLETIN_QUERY')")
public List<BulletinVo> detail(@AuthenticationPrincipal UserDetailsImpl userDetails, @PathVariable("id") Long id) {
@PreAuthorize("hasAuthority('message:bulletin:query')")
public BulletinVo detail(@AuthenticationPrincipal UserDetailsImpl userDetails, @PathVariable("id") Long id) {
return service.detail(userDetails,id, null);
}
@ -70,10 +67,9 @@ public class BulletinController {
* @return 分页数据
*/
@GetMapping()
@PreAuthorize("hasAuthority('BULLETIN_QUERY')")
public IPage<BulletinVo> query( BulletinQuery query) {
Page<BulletinVo> page = new Page<>(query.getPageNum(), query.getPageSize());
return service.selectPageByConditions(page, query);
@PreAuthorize("hasAuthority('message:bulletin:query')")
public Page<Bulletin> query(Page<Bulletin> page, BulletinQuery query) {
return service.page(page, query.wrapper());
}
/**
@ -84,7 +80,7 @@ public class BulletinController {
* @return 公告
*/
@PostMapping
@PreAuthorize("hasAuthority('BULLETIN_CREATE')")
@PreAuthorize("hasAuthority('message:bulletin:create')")
public Bulletin create(@AuthenticationPrincipal UserDetailsImpl userDetails, @RequestBody BulletinDto dto) {
return service.create(userDetails, dto);
}
@ -98,7 +94,7 @@ public class BulletinController {
* @return 公告
*/
@PatchMapping("/{id}")
@PreAuthorize("hasAuthority('BULLETIN_UPDATE')")
@PreAuthorize("hasAuthority('message:bulletin:update')")
public Boolean update(@AuthenticationPrincipal UserDetailsImpl userDetails, @RequestBody BulletinDto dto, @PathVariable("id") Long id) {
return service.update(userDetails, dto, id);
}
@ -110,7 +106,7 @@ public class BulletinController {
* @return 公告
*/
@PatchMapping("/{id}/toggle-top")
@PreAuthorize("hasAuthority('BULLETIN_UPDATE')")
@PreAuthorize("hasAuthority('message:bulletin:update')")
public Boolean toggleTop(@PathVariable("id") Long id) {
return service.toggleTop(id);
}
@ -123,8 +119,8 @@ public class BulletinController {
* @return 公告
*/
@PatchMapping("/publish")
@PreAuthorize("hasAuthority('BULLETIN_PUBLISH')")
public List<String> publish(@AuthenticationPrincipal UserDetailsImpl userDetails,@RequestBody List<Long> ids) {
@PreAuthorize("hasAuthority('message:bulletin:update')")
public Boolean publish(@AuthenticationPrincipal UserDetailsImpl userDetails, @RequestBody List<Long> ids) {
return service.publish(userDetails, ids);
}
@ -136,7 +132,7 @@ public class BulletinController {
* @return 公告
*/
@PatchMapping("/{id}/toggleClose")
@PreAuthorize("hasAuthority('BULLETIN_CLOSE')")
@PreAuthorize("hasAuthority('message:bulletin:update')")
public Boolean toggleClose(@AuthenticationPrincipal UserDetailsImpl userDetails, @PathVariable("id") Long id) {
return service.close(userDetails, id);
}
@ -148,17 +144,9 @@ public class BulletinController {
* @return
*/
@DeleteMapping("/{id}")
@PreAuthorize("hasAuthority('BULLETIN_DELETE')")
@PreAuthorize("hasAuthority('message:bulletin:delete')")
public Boolean delete(@PathVariable("id") Long id) {
return service.removeById(id);
return service.delete(id);
}
/**
*为公告添加附件
*/
@PostMapping("/{id}/add")
@PreAuthorize("hasAuthority('BULLETIN_CREATE')")
public Boolean insertInto(@PathVariable Long id,@RequestBody Set<String> attachments){
return service.insertInto(id, attachments);
}
}

View File

@ -0,0 +1,126 @@
package com.zsc.edu.gateway.modules.message.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zsc.edu.gateway.framework.security.UserDetailsImpl;
import com.zsc.edu.gateway.modules.message.dto.UserNoticeDto;
import com.zsc.edu.gateway.modules.message.query.AdminNoticeQuery;
import com.zsc.edu.gateway.modules.message.query.UserNoticeQuery;
import com.zsc.edu.gateway.modules.message.service.UserNoticeService;
import com.zsc.edu.gateway.modules.message.vo.AdminNoticeVo;
import com.zsc.edu.gateway.modules.message.vo.UserNoticeVo;
import lombok.AllArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 用户消息Controller
*
* @author harry_yao
*/
@AllArgsConstructor
@RestController
@RequestMapping("api/rest/notice")
public class UserNoticeController {
private final UserNoticeService service;
/**
* 普通用户查看消息详情
*
* @param userDetails 操作用户
* @param noticeId 消息ID
* @return 用户消息详情
*/
@GetMapping("/self/{noticeId}")
public UserNoticeVo selfDetail(@AuthenticationPrincipal UserDetailsImpl userDetails, @PathVariable("noticeId") Long noticeId) {
return service.detail(noticeId, userDetails.getId());
}
/**
* 普通用户分页查询消息不能设置查询参数userId和username
*
* @param userDetails 操作用户
* @param query 查询参数
* @return 分页数据
*/
@GetMapping("/self")
public IPage<UserNoticeVo> selfPage(Page<UserNoticeVo> pageParam, @AuthenticationPrincipal UserDetailsImpl userDetails, UserNoticeQuery query) {
query.userId = userDetails.id;
query.name = null;
return service.page(pageParam, query);
}
/**
* 普通用户统计自己未读消息数量
*
* @param userDetails 操作用户
* @return 数据
*/
@GetMapping("/countUnread")
public int countUnread(@AuthenticationPrincipal UserDetailsImpl userDetails) {
return service.countUnread(userDetails);
}
/**
* 普通用户确认消息已读如果提交的已读消息ID集合为空则将所有未读消息设为已读
*
* @param userDetails 操作用户
* @param noticeIds 已读消息ID集合
* @return 确认已读数量
*/
@PatchMapping("/read")
public Boolean acknowledge(@AuthenticationPrincipal UserDetailsImpl userDetails, @RequestBody List<Long> noticeIds) {
return service.markAsRead(userDetails, noticeIds);
}
/**
* 普通用户确认消息已读如果提交的已读消息ID集合为空则将所有未读消息设为已读
*
* @param userDetails 操作用户
* @return 确认已读数量
*/
@PatchMapping("/readAll")
public Boolean readAll(@AuthenticationPrincipal UserDetailsImpl userDetails) {
return service.markAllAsRead(userDetails);
}
/**
* 管理查询消息详情
*
* @param noticeId 消息ID
* @return 用户消息详情
*/
@GetMapping("/{userId}/{noticeId}")
@PreAuthorize("hasAuthority('message:notice:query')")
public UserNoticeVo detail(@PathVariable("userId") Long userId, @PathVariable("noticeId") Long noticeId) {
return service.detail(noticeId, userId);
}
/**
* 管理员分页查询消息
*
* @param query 查询参数
* @return 分页数据
*/
@GetMapping
@PreAuthorize("hasAuthority('message:notice:query')")
public IPage<AdminNoticeVo> page(Page<UserNoticeVo> page, AdminNoticeQuery query) {
return service.getAdminNoticePage(page, query);
}
/**
* 管理员手动创建消息
*
* @param dto 表单数据
* @return 消息列表
*/
@PostMapping
@PreAuthorize("hasAuthority('message:notice:create')")
public Boolean create(@RequestBody UserNoticeDto dto) {
return service.createByAdmin(dto);
}
}

View File

@ -1,4 +1,4 @@
package com.zsc.edu.gateway.modules.notice.dto;
package com.zsc.edu.gateway.modules.message.dto;
import lombok.AllArgsConstructor;
import lombok.Data;

View File

@ -1,4 +1,4 @@
package com.zsc.edu.gateway.modules.notice.dto;
package com.zsc.edu.gateway.modules.message.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
@ -25,7 +25,7 @@ public class BulletinDto {
/**
* 是否置顶
*/
public boolean top;
public Boolean top;
/**
* 内容
@ -36,9 +36,9 @@ public class BulletinDto {
* 备注
*/
public String remark;
//
// /**
// * 附件ID集合
// */
// private List<String> attachmentIds;
/**
* 附件ID集合
*/
private List<String> attachmentIds;
}

View File

@ -1,4 +1,4 @@
package com.zsc.edu.gateway.modules.notice.dto;
package com.zsc.edu.gateway.modules.message.dto;
import lombok.Data;

View File

@ -1,6 +1,6 @@
package com.zsc.edu.gateway.modules.notice.dto;
package com.zsc.edu.gateway.modules.message.dto;
import com.zsc.edu.gateway.modules.notice.entity.MessageType;
import com.zsc.edu.gateway.modules.message.entity.NoticeType;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@ -16,7 +16,7 @@ import java.util.Set;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserMessageDto {
public class UserNoticeDto {
/**
* 用户ID集合
@ -28,7 +28,7 @@ public class UserMessageDto {
* 消息类型
*/
@NotNull(message = "消息类型不能为空")
public MessageType type;
public NoticeType type;
/**
* 是否需要发送邮件

View File

@ -1,4 +1,4 @@
package com.zsc.edu.gateway.modules.notice.entity;
package com.zsc.edu.gateway.modules.message.entity;
import com.baomidou.mybatisplus.annotation.IEnum;
import com.baomidou.mybatisplus.annotation.TableField;
@ -7,6 +7,7 @@ import com.zsc.edu.gateway.common.enums.IState;
import com.zsc.edu.gateway.modules.system.entity.BaseEntity;
import com.zsc.edu.gateway.modules.attachment.entity.Attachment;
import lombok.*;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import java.util.List;
@ -33,6 +34,11 @@ public class Bulletin extends BaseEntity {
*/
public State state = State.edit;
/**
* 部门ID(权限)
*/
public Long deptId;
/**
* 是否置顶
*/
@ -68,6 +74,7 @@ public class Bulletin extends BaseEntity {
/**
* 审核发布时间
*/
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
public LocalDateTime publishTime;
/**
@ -84,6 +91,7 @@ public class Bulletin extends BaseEntity {
/**
* 关闭时间
*/
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
public LocalDateTime closeTime;
/**

View File

@ -1,4 +1,4 @@
package com.zsc.edu.gateway.modules.notice.entity;
package com.zsc.edu.gateway.modules.message.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;

View File

@ -1,15 +1,12 @@
package com.zsc.edu.gateway.modules.notice.entity;
package com.zsc.edu.gateway.modules.message.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.zsc.edu.gateway.modules.system.entity.BaseEntity;
import com.zsc.edu.gateway.modules.attachment.entity.Attachment;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.util.List;
/**
* 消息
*
@ -19,24 +16,25 @@ import java.util.List;
@Getter
@NoArgsConstructor
@AllArgsConstructor
@TableName("sys_message")
public class Message extends BaseEntity {
@TableName("sys_notice")
public class Notice extends BaseEntity {
/**
* 消息类型
*/
public MessageType type = MessageType.other;
public NoticeType type = NoticeType.MESSAGE;
/**
* 是否系统生成
*/
public Boolean system;
public Boolean system = false;
/**
* 是否需要发送邮件
*/
public Boolean email;
/**
* 是否需要发送短信
*/
@ -58,8 +56,7 @@ public class Message extends BaseEntity {
public String content;
/**
* 附件
* 部门ID(权限)
*/
public List<Attachment> attachments;
public Long deptId;
}

View File

@ -1,4 +1,4 @@
package com.zsc.edu.gateway.modules.notice.entity;
package com.zsc.edu.gateway.modules.message.entity;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@ -8,20 +8,20 @@ import java.time.format.DateTimeFormatter;
*
* @author harry_yao
*/
public abstract class MessagePayload {
public abstract class NoticePayload {
public MessageType type;
public NoticeType type;
public String content;
public Boolean html;
public static class Other extends MessagePayload {
public static class Other extends NoticePayload {
public Other(String content) {
this.content = content;
this.type = MessageType.other;
this.type = NoticeType.MESSAGE;
}
}
public static class ResetPassword extends MessagePayload {
public static class ResetPassword extends NoticePayload {
public String username;
public String password;
public LocalDateTime resetTime;
@ -30,7 +30,7 @@ public abstract class MessagePayload {
this.username = username;
this.password = password;
this.resetTime = resetTime;
this.type =MessageType.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

@ -1,4 +1,4 @@
package com.zsc.edu.gateway.modules.notice.entity;
package com.zsc.edu.gateway.modules.message.entity;
import com.baomidou.mybatisplus.annotation.IEnum;
import com.zsc.edu.gateway.common.enums.IState;
@ -8,14 +8,14 @@ import com.zsc.edu.gateway.common.enums.IState;
*
* @author zhuang
*/
public enum MessageType implements IEnum<Integer>,IState<MessageType> {
other(1,"其他"),
resetThePassword(2,"重置密码");
public enum NoticeType implements IEnum<Integer>, IState<NoticeType> {
MESSAGE(1, "消息"),
NOTICE(2, "通知");
private final Integer value;
private final String name;
MessageType(Integer value, String name) {
NoticeType(Integer value, String name) {
this.value = value;
this.name = name;
}

View File

@ -1,10 +1,10 @@
package com.zsc.edu.gateway.modules.notice.entity;
package com.zsc.edu.gateway.modules.message.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.zsc.edu.gateway.modules.system.entity.User;
import lombok.*;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.time.LocalDateTime;
@ -17,10 +17,10 @@ import java.time.LocalDateTime;
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("sys_user_message")
public class UserMessage implements Serializable {
@TableName("sys_user_notice")
public class UserNotice implements Serializable {
@TableId
@TableId(type = IdType.AUTO)
private Long id;
/**
@ -32,7 +32,7 @@ public class UserMessage implements Serializable {
/**
* 消息ID
*/
public Long messageId;
public Long noticeId;
/**
@ -43,6 +43,7 @@ public class UserMessage implements Serializable {
/**
* 阅读时间
*/
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
public LocalDateTime readTime;
}

View File

@ -1,8 +1,8 @@
package com.zsc.edu.gateway.modules.notice.mapper;
package com.zsc.edu.gateway.modules.message.mapper;
import com.zsc.edu.gateway.common.mapstruct.BaseMapper;
import com.zsc.edu.gateway.modules.notice.dto.BulletinAttachmentDto;
import com.zsc.edu.gateway.modules.notice.entity.BulletinAttachment;
import com.zsc.edu.gateway.modules.message.dto.BulletinAttachmentDto;
import com.zsc.edu.gateway.modules.message.entity.BulletinAttachment;
import org.mapstruct.Mapper;
import org.mapstruct.ReportingPolicy;

Some files were not shown because too many files have changed in this diff Show More