瀏覽代碼

feat: Initialize item

Nobita 11 月之前
父節點
當前提交
8078ad68f4
共有 100 個文件被更改,包括 10335 次插入93 次删除
  1. 0 13
      himeeter-admin/src/test/java/com/lij/himeeter/admin/HimeeterAdminApplicationTests.java
  2. 22 0
      himeeter-common/src/main/java/com/lij/himeeter/common/annotation/Anonymous.java
  3. 37 0
      himeeter-common/src/main/java/com/lij/himeeter/common/annotation/DataScope.java
  4. 27 0
      himeeter-common/src/main/java/com/lij/himeeter/common/annotation/DataSource.java
  5. 201 0
      himeeter-common/src/main/java/com/lij/himeeter/common/annotation/Excel.java
  6. 25 0
      himeeter-common/src/main/java/com/lij/himeeter/common/annotation/Excels.java
  7. 56 0
      himeeter-common/src/main/java/com/lij/himeeter/common/annotation/Log.java
  8. 46 0
      himeeter-common/src/main/java/com/lij/himeeter/common/annotation/RateLimiter.java
  9. 34 0
      himeeter-common/src/main/java/com/lij/himeeter/common/annotation/RepeatSubmit.java
  10. 34 0
      himeeter-common/src/main/java/com/lij/himeeter/common/annotation/Sensitive.java
  11. 129 0
      himeeter-common/src/main/java/com/lij/himeeter/common/config/HimeeterConfig.java
  12. 57 0
      himeeter-common/src/main/java/com/lij/himeeter/common/constant/CacheConstants.java
  13. 183 0
      himeeter-common/src/main/java/com/lij/himeeter/common/constant/Constants.java
  14. 103 0
      himeeter-common/src/main/java/com/lij/himeeter/common/constant/HttpStatus.java
  15. 126 0
      himeeter-common/src/main/java/com/lij/himeeter/common/constant/UserConstants.java
  16. 254 0
      himeeter-common/src/main/java/com/lij/himeeter/common/core/RedisCache.java
  17. 226 0
      himeeter-common/src/main/java/com/lij/himeeter/common/core/domain/AjaxResult.java
  18. 127 0
      himeeter-common/src/main/java/com/lij/himeeter/common/core/domain/BaseEntity.java
  19. 111 0
      himeeter-common/src/main/java/com/lij/himeeter/common/core/domain/R.java
  20. 88 0
      himeeter-common/src/main/java/com/lij/himeeter/common/core/domain/TreeEntity.java
  21. 101 0
      himeeter-common/src/main/java/com/lij/himeeter/common/core/domain/TreeSelect.java
  22. 212 0
      himeeter-common/src/main/java/com/lij/himeeter/common/core/domain/entity/SysDept.java
  23. 184 0
      himeeter-common/src/main/java/com/lij/himeeter/common/core/domain/entity/SysDictData.java
  24. 105 0
      himeeter-common/src/main/java/com/lij/himeeter/common/core/domain/entity/SysDictType.java
  25. 283 0
      himeeter-common/src/main/java/com/lij/himeeter/common/core/domain/entity/SysMenu.java
  26. 245 0
      himeeter-common/src/main/java/com/lij/himeeter/common/core/domain/entity/SysRole.java
  27. 335 0
      himeeter-common/src/main/java/com/lij/himeeter/common/core/domain/entity/SysUser.java
  28. 70 0
      himeeter-common/src/main/java/com/lij/himeeter/common/core/domain/model/LoginBody.java
  29. 276 0
      himeeter-common/src/main/java/com/lij/himeeter/common/core/domain/model/LoginUser.java
  30. 18 0
      himeeter-common/src/main/java/com/lij/himeeter/common/core/domain/model/RegisterBody.java
  31. 101 0
      himeeter-common/src/main/java/com/lij/himeeter/common/core/text/CharsetKit.java
  32. 860 0
      himeeter-common/src/main/java/com/lij/himeeter/common/core/text/Convert.java
  33. 101 0
      himeeter-common/src/main/java/com/lij/himeeter/common/core/text/StrFormatter.java
  34. 28 0
      himeeter-common/src/main/java/com/lij/himeeter/common/enums/BusinessStatus.java
  35. 68 0
      himeeter-common/src/main/java/com/lij/himeeter/common/enums/BusinessType.java
  36. 28 0
      himeeter-common/src/main/java/com/lij/himeeter/common/enums/DataSourceType.java
  37. 69 0
      himeeter-common/src/main/java/com/lij/himeeter/common/enums/DesensitizedType.java
  38. 28 0
      himeeter-common/src/main/java/com/lij/himeeter/common/enums/LimitType.java
  39. 33 0
      himeeter-common/src/main/java/com/lij/himeeter/common/enums/OperatorType.java
  40. 77 0
      himeeter-common/src/main/java/com/lij/himeeter/common/exception/ServiceException.java
  41. 52 0
      himeeter-common/src/main/java/com/lij/himeeter/common/utils/DesensitizedUtil.java
  42. 25 0
      himeeter-common/src/main/java/com/lij/himeeter/common/utils/LogUtils.java
  43. 163 0
      himeeter-common/src/main/java/com/lij/himeeter/common/utils/SecurityUtils.java
  44. 199 0
      himeeter-common/src/main/java/com/lij/himeeter/common/utils/ServletUtils.java
  45. 591 0
      himeeter-common/src/main/java/com/lij/himeeter/common/utils/StringUtils.java
  46. 82 0
      himeeter-common/src/main/java/com/lij/himeeter/common/utils/Threads.java
  47. 18 0
      himeeter-common/src/main/java/com/lij/himeeter/common/utils/http/HttpHelper.java
  48. 219 0
      himeeter-common/src/main/java/com/lij/himeeter/common/utils/http/HttpUtils.java
  49. 64 0
      himeeter-common/src/main/java/com/lij/himeeter/common/utils/ip/AddressUtils.java
  50. 334 0
      himeeter-common/src/main/java/com/lij/himeeter/common/utils/ip/IpUtils.java
  51. 33 0
      himeeter-common/src/main/java/com/lij/himeeter/common/utils/poi/ExcelHandlerAdapter.java
  52. 18 0
      himeeter-common/src/main/java/com/lij/himeeter/common/utils/poi/ExcelUtil.java
  53. 149 0
      himeeter-common/src/main/java/com/lij/himeeter/common/utils/spring/SpringUtils.java
  54. 35 0
      himeeter-common/src/main/java/com/lij/himeeter/common/xss/Xss.java
  55. 45 0
      himeeter-common/src/main/java/com/lij/himeeter/common/xss/XssValidator.java
  56. 0 13
      himeeter-common/src/main/java/com/lij/himeeter/framework/HimeeterFrameworkApplication.java
  57. 0 1
      himeeter-common/src/main/resources/application.properties
  58. 0 13
      himeeter-framework/src/main/java/com/lij/himeeter/framework/HimeeterFrameworkApplication.java
  59. 166 0
      himeeter-framework/src/main/java/com/lij/himeeter/framework/aspectj/DataScopeAspect.java
  60. 18 0
      himeeter-framework/src/main/java/com/lij/himeeter/framework/aspectj/DataSourceAspect.java
  61. 230 0
      himeeter-framework/src/main/java/com/lij/himeeter/framework/aspectj/LogAspect.java
  62. 18 0
      himeeter-framework/src/main/java/com/lij/himeeter/framework/aspectj/RateLimiterAspect.java
  63. 64 0
      himeeter-framework/src/main/java/com/lij/himeeter/framework/manager/AsyncManager.java
  64. 103 0
      himeeter-framework/src/main/java/com/lij/himeeter/framework/manager/factory/AsyncFactory.java
  65. 34 0
      himeeter-framework/src/main/java/com/lij/himeeter/framework/security/context/PermissionContextHolder.java
  66. 18 0
      himeeter-framework/src/main/java/com/lij/himeeter/framework/web/domain/Server.java
  67. 48 0
      himeeter-framework/src/main/java/com/lij/himeeter/framework/web/domain/server/Cpu.java
  68. 44 0
      himeeter-framework/src/main/java/com/lij/himeeter/framework/web/domain/server/Jvm.java
  69. 18 0
      himeeter-framework/src/main/java/com/lij/himeeter/framework/web/domain/server/Mem.java
  70. 18 0
      himeeter-framework/src/main/java/com/lij/himeeter/framework/web/domain/server/Sys.java
  71. 18 0
      himeeter-framework/src/main/java/com/lij/himeeter/framework/web/domain/server/SysFile.java
  72. 0 1
      himeeter-framework/src/main/resources/application.properties
  73. 0 13
      himeeter-framework/src/test/java/com/lij/himeeter/framework/HimeeterFrameworkApplicationTests.java
  74. 0 13
      himeeter-generator/src/test/java/com/lij/himeeter/generator/HimeeterGeneratorApplicationTests.java
  75. 0 13
      himeeter-quartz/src/test/java/com/lij/himeeter/quartz/HimeeterQuartzApplicationTests.java
  76. 0 13
      himeeter-system/src/main/java/com/lij/himeeter/system/HimeeterSystemApplication.java
  77. 18 0
      himeeter-system/src/main/java/com/lij/himeeter/system/domin/SysCache.java
  78. 120 0
      himeeter-system/src/main/java/com/lij/himeeter/system/domin/SysConfig.java
  79. 155 0
      himeeter-system/src/main/java/com/lij/himeeter/system/domin/SysLogininfor.java
  80. 110 0
      himeeter-system/src/main/java/com/lij/himeeter/system/domin/SysNotice.java
  81. 280 0
      himeeter-system/src/main/java/com/lij/himeeter/system/domin/SysOperLog.java
  82. 132 0
      himeeter-system/src/main/java/com/lij/himeeter/system/domin/SysPost.java
  83. 55 0
      himeeter-system/src/main/java/com/lij/himeeter/system/domin/SysRoleDept.java
  84. 55 0
      himeeter-system/src/main/java/com/lij/himeeter/system/domin/SysRoleMenu.java
  85. 123 0
      himeeter-system/src/main/java/com/lij/himeeter/system/domin/SysUserOnline.java
  86. 55 0
      himeeter-system/src/main/java/com/lij/himeeter/system/domin/SysUserPost.java
  87. 55 0
      himeeter-system/src/main/java/com/lij/himeeter/system/domin/SysUserRole.java
  88. 102 0
      himeeter-system/src/main/java/com/lij/himeeter/system/domin/vo/MetaVO.java
  89. 140 0
      himeeter-system/src/main/java/com/lij/himeeter/system/domin/vo/RouterVO.java
  90. 86 0
      himeeter-system/src/main/java/com/lij/himeeter/system/mapper/SysConfigMapper.java
  91. 128 0
      himeeter-system/src/main/java/com/lij/himeeter/system/mapper/SysDeptMapper.java
  92. 105 0
      himeeter-system/src/main/java/com/lij/himeeter/system/mapper/SysDictDataMapper.java
  93. 92 0
      himeeter-system/src/main/java/com/lij/himeeter/system/mapper/SysDictTypeMapper.java
  94. 52 0
      himeeter-system/src/main/java/com/lij/himeeter/system/mapper/SysLogininforMapper.java
  95. 134 0
      himeeter-system/src/main/java/com/lij/himeeter/system/mapper/SysMenuMapper.java
  96. 70 0
      himeeter-system/src/main/java/com/lij/himeeter/system/mapper/SysNoticeMapper.java
  97. 58 0
      himeeter-system/src/main/java/com/lij/himeeter/system/mapper/SysOperLogMapper.java
  98. 108 0
      himeeter-system/src/main/java/com/lij/himeeter/system/mapper/SysPostMapper.java
  99. 53 0
      himeeter-system/src/main/java/com/lij/himeeter/system/mapper/SysRoleDeptMapper.java
  100. 117 0
      himeeter-system/src/main/java/com/lij/himeeter/system/mapper/SysRoleMapper.java

+ 0 - 13
himeeter-admin/src/test/java/com/lij/himeeter/admin/HimeeterAdminApplicationTests.java

@@ -1,13 +0,0 @@
-package com.lij.himeeter.admin;
-
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-
-@SpringBootTest
-class HimeeterAdminApplicationTests {
-
-    @Test
-    void contextLoads() {
-    }
-
-}

+ 22 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/annotation/Anonymous.java

@@ -0,0 +1,22 @@
+package com.lij.himeeter.common.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  Anonymous
+ * 创建时间 : 2024年12月25日 15:59
+ *
+ * 文件描述 : 匿名访问不鉴权注解
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Anonymous {
+}

+ 37 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/annotation/DataScope.java

@@ -0,0 +1,37 @@
+package com.lij.himeeter.common.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  DataScope
+ * 创建时间 : 2024年12月25日 16:23
+ *
+ * 文件描述 : 数据权限过滤注解
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface DataScope {
+
+    /**
+     * 部门表的别名
+     */
+    public String deptAlias() default "";
+
+    /**
+     * 用户表的别名
+     */
+    public String userAlias() default "";
+
+    /**
+     * 权限字符(用于多个角色匹配符合要求的权限)默认根据权限注解@ss获取,多个权限用逗号分隔开来
+     */
+    public String permission() default "";
+}

+ 27 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/annotation/DataSource.java

@@ -0,0 +1,27 @@
+package com.lij.himeeter.common.annotation;
+
+import com.lij.himeeter.common.enums.DataSourceType;
+
+import java.lang.annotation.*;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  DataSource
+ * 创建时间 : 2024年12月25日 16:27
+ *
+ * 文件描述 : 无
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+public @interface DataSource {
+
+    DataSourceType value() default DataSourceType.MASTER;
+}

+ 201 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/annotation/Excel.java

@@ -0,0 +1,201 @@
+package com.lij.himeeter.common.annotation;
+
+import com.lij.himeeter.common.utils.poi.ExcelHandlerAdapter;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.IndexedColors;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.math.BigDecimal;
+
+
+/**
+ * <pre>
+ *
+ * 文件名 :  Excel
+ * 文件描述 : 自定义导出Excel数据注解
+ *
+ * 创建时间 : 2024年12月16日 18:37
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Excel {
+
+    /**
+     * 导出时在excel中排序
+     */
+    int sort() default Integer.MAX_VALUE;
+
+    /**
+     * 导出到Excel中的名字.
+     */
+    String name() default "";
+
+    /**
+     * 日期格式, 如: yyyy-MM-dd
+     */
+    String dateFormat() default "";
+
+    /**
+     * 如果是字典类型,请设置字典的type值 (如: sys_user_sex)
+     */
+    String dictType() default "";
+
+    /**
+     * 读取内容转表达式 (如: 0=男,1=女,2=未知)
+     */
+    String readConverterExp() default "";
+
+    /**
+     * 分隔符,读取字符串组内容
+     */
+    String separator() default ",";
+
+    /**
+     * BigDecimal 精度 默认:-1(默认不开启BigDecimal格式化)
+     */
+    int scale() default -1;
+
+    /**
+     * BigDecimal 舍入规则 默认:BigDecimal.ROUND_HALF_EVEN
+     */
+    int roundingMode() default BigDecimal.ROUND_HALF_EVEN;
+
+    /**
+     * 导出时在excel中每个列的高度
+     */
+    double height() default 14;
+
+    /**
+     * 导出时在excel中每个列的宽度
+     */
+    double width() default 16;
+
+    /**
+     * 文字后缀,如% 90 变成90%
+     */
+    String suffix() default "";
+
+    /**
+     * 当值为空时,字段的默认值
+     */
+    String defaultValue() default "";
+
+    /**
+     * 提示信息
+     */
+    String prompt() default "";
+
+    /**
+     * 是否允许内容换行
+     */
+    boolean wrapText() default false;
+
+    /**
+     * 设置只能选择不能输入的列内容.
+     */
+    String[] combo() default {};
+
+    /**
+     * 是否从字典读数据到combo,默认不读取,如读取需要设置dictType注解.
+     */
+    boolean comboReadDict() default false;
+
+    /**
+     * 是否需要纵向合并单元格,应对需求:含有list集合单元格)
+     */
+    boolean needMerge() default false;
+
+    /**
+     * 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写.
+     */
+    boolean isExport() default true;
+
+    /**
+     * 另一个类中的属性名称,支持多级获取,以小数点隔开
+     */
+    String targetAttr() default "";
+
+    /**
+     * 是否自动统计数据,在最后追加一行统计数据总和
+     */
+    boolean isStatistics() default false;
+
+    /**
+     * 导出类型(0数字 1字符串 2图片)
+     */
+    ColumnType cellType() default ColumnType.STRING;
+
+    /**
+     * 导出列头背景颜色
+     */
+    IndexedColors headerBackgroundColor() default IndexedColors.GREY_50_PERCENT;
+
+    /**
+     * 导出列头字体颜色
+     */
+    IndexedColors headerColor() default IndexedColors.WHITE;
+
+    /**
+     * 导出单元格背景颜色
+     */
+    IndexedColors backgroundColor() default IndexedColors.WHITE;
+
+    /**
+     * 导出单元格字体颜色
+     */
+    IndexedColors color() default IndexedColors.BLACK;
+
+    /**
+     * 导出字段对齐方式
+     */
+    HorizontalAlignment align() default HorizontalAlignment.CENTER;
+
+    /**
+     * 自定义数据处理器
+     */
+    Class<?> handler() default ExcelHandlerAdapter.class;
+
+    /**
+     * 自定义数据处理器参数
+     */
+    String[] args() default {};
+
+    /**
+     * 字段类型(0:导出导入;1:仅导出;2:仅导入)
+     */
+    Type type() default Type.ALL;
+
+    enum Type {
+        ALL(0), EXPORT(1), IMPORT(2);
+        private final int value;
+
+        Type(int value) {
+            this.value = value;
+        }
+
+        public int value() {
+            return this.value;
+        }
+    }
+
+    enum ColumnType {
+        NUMERIC(0), STRING(1), IMAGE(2), TEXT(3);
+        private final int value;
+
+        ColumnType(int value) {
+            this.value = value;
+        }
+
+        public int value() {
+            return this.value;
+        }
+    }
+
+}

+ 25 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/annotation/Excels.java

@@ -0,0 +1,25 @@
+package com.lij.himeeter.common.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  Excels
+ * 创建时间 : 2024年12月25日 16:27
+ *
+ * 文件描述 : Excel注解集
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Excels {
+    Excel[] value();
+}

+ 56 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/annotation/Log.java

@@ -0,0 +1,56 @@
+package com.lij.himeeter.common.annotation;
+
+import com.lij.himeeter.common.enums.BusinessType;
+import com.lij.himeeter.common.enums.OperatorType;
+
+import java.lang.annotation.*;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  Log
+ * 创建时间 : 2024年12月25日 16:27
+ *
+ * 文件描述 : 自定义操作日志记录注解
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+@Target({ElementType.PARAMETER, ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Log {
+
+    /**
+     * 模块
+     */
+    String title() default "";
+
+    /**
+     * 功能
+     */
+    BusinessType businessType() default BusinessType.OTHER;
+
+    /**
+     * 操作人类别
+     */
+    OperatorType operatorType() default OperatorType.MANAGE;
+
+    /**
+     * 是否保存请求的参数
+     */
+    boolean isSaveRequestData() default true;
+
+    /**
+     * 是否保存响应的参数
+     */
+    boolean isSaveResponseData() default true;
+
+    /**
+     * 排除指定的请求参数
+     */
+    String[] excludeParamNames() default {};
+}

+ 46 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/annotation/RateLimiter.java

@@ -0,0 +1,46 @@
+package com.lij.himeeter.common.annotation;
+
+import com.lij.himeeter.common.constant.CacheConstants;
+import com.lij.himeeter.common.enums.LimitType;
+
+import java.lang.annotation.*;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  RateLimiter
+ * 创建时间 : 2024年12月25日 16:28
+ *
+ * 文件描述 : 限流注解
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+@Documented
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface RateLimiter {
+
+    /**
+     * 限流key
+     */
+    String key() default CacheConstants.RATE_LIMIT_KEY;
+
+    /**
+     * 限流时间,单位秒
+     */
+    int time() default 60;
+
+    /**
+     * 限流次数
+     */
+    int count() default 100;
+
+    /**
+     * 限流类型
+     */
+    LimitType limitType() default LimitType.DEFAULT;
+}

+ 34 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/annotation/RepeatSubmit.java

@@ -0,0 +1,34 @@
+package com.lij.himeeter.common.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  RepeatSubmit
+ * 创建时间 : 2024年12月25日 16:28
+ *
+ * 文件描述 : 无
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+@Inherited
+@Documented
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface RepeatSubmit {
+
+    /**
+     * 间隔时间(ms),小于此时间视为重复提交
+     */
+    int interval() default 5000;
+
+    /**
+     * 提示消息
+     */
+    String message() default "不允许重复提交,请稍候再试";
+}

+ 34 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/annotation/Sensitive.java

@@ -0,0 +1,34 @@
+package com.lij.himeeter.common.annotation;
+
+import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.SerializableSerializer;
+import com.lij.himeeter.common.enums.DesensitizedType;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  Sensitive
+ * 创建时间 : 2024年12月25日 16:28
+ *
+ * 文件描述 : 数据脱敏注解
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+@JacksonAnnotationsInside
+@JsonSerialize(using = SerializableSerializer.class)
+public @interface Sensitive {
+
+    DesensitizedType desensitizedType();
+}

+ 129 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/config/HimeeterConfig.java

@@ -0,0 +1,129 @@
+package com.lij.himeeter.common.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  HimeeterConfig
+ * 创建时间 : 2024年12月26日 17:59
+ *
+ * 文件描述 : 读取项目相关配置
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+@Component
+@ConfigurationProperties(prefix = "himeeter")
+public class HimeeterConfig {
+
+    /**
+     * 项目名称
+     */
+    private String name;
+
+    /**
+     * 版本
+     */
+    private String version;
+
+    /**
+     * 版权年份
+     */
+    private String copyrightYear;
+
+    /**
+     * 上传路径
+     */
+    private static String profile;
+
+    /**
+     * 获取地址开关
+     */
+    private static boolean addressEnabled;
+
+    /**
+     * 验证码类型
+     */
+    private static String captchaType;
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getVersion() {
+        return version;
+    }
+
+    public void setVersion(String version) {
+        this.version = version;
+    }
+
+    public String getCopyrightYear() {
+        return copyrightYear;
+    }
+
+    public void setCopyrightYear(String copyrightYear) {
+        this.copyrightYear = copyrightYear;
+    }
+
+    public static String getProfile() {
+        return profile;
+    }
+
+    public void setProfile(String profile) {
+        HimeeterConfig.profile = profile;
+    }
+
+    public static boolean isAddressEnabled() {
+        return addressEnabled;
+    }
+
+    public void setAddressEnabled(boolean addressEnabled) {
+        HimeeterConfig.addressEnabled = addressEnabled;
+    }
+
+    public static String getCaptchaType() {
+        return captchaType;
+    }
+
+    public void setCaptchaType(String captchaType) {
+        HimeeterConfig.captchaType = captchaType;
+    }
+
+    /**
+     * 获取导入上传路径
+     */
+    public static String getImportPath() {
+        return getProfile() + "/import";
+    }
+
+    /**
+     * 获取头像上传路径
+     */
+    public static String getAvatarPath() {
+        return getProfile() + "/avatar";
+    }
+
+    /**
+     * 获取下载路径
+     */
+    public static String getDownloadPath() {
+        return getProfile() + "/download/";
+    }
+
+    /**
+     * 获取上传路径
+     */
+    public static String getUploadPath() {
+        return getProfile() + "/upload";
+    }
+
+}

+ 57 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/constant/CacheConstants.java

@@ -0,0 +1,57 @@
+package com.lij.himeeter.common.constant;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  CacheConstants
+ * 创建时间 : 2024年12月26日 15:03
+ *
+ * 文件描述 : 缓存的key 常量
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public interface CacheConstants {
+
+
+    String PROJECT_NAME = "Himeeter-system";
+
+
+    /**
+     * 登录用户 redis key
+     */
+    String LOGIN_TOKEN_KEY = PROJECT_NAME + "login_tokens:";
+
+    /**
+     * 验证码 redis key
+     */
+    String CAPTCHA_CODE_KEY = PROJECT_NAME + "captcha_codes:";
+
+    /**
+     * 参数管理 cache key
+     */
+    String SYS_CONFIG_KEY = PROJECT_NAME + "sys_config:";
+
+    /**
+     * 字典管理 cache key
+     */
+    String SYS_DICT_KEY = PROJECT_NAME + "sys_dict:";
+
+    /**
+     * 防重提交 redis key
+     */
+    String REPEAT_SUBMIT_KEY = PROJECT_NAME + "repeat_submit:";
+
+    /**
+     * 限流 redis key
+     */
+    String RATE_LIMIT_KEY = PROJECT_NAME + "rate_limit:";
+
+    /**
+     * 登录账户密码错误次数 redis key
+     */
+    String PWD_ERR_CNT_KEY = PROJECT_NAME + "pwd_err_cnt:";
+}

+ 183 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/constant/Constants.java

@@ -0,0 +1,183 @@
+package com.lij.himeeter.common.constant;
+
+import io.jsonwebtoken.Claims;
+
+import java.util.Locale;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  Constants
+ * 创建时间 : 2024年12月26日 17:50
+ *
+ * 文件描述 : 无
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public interface Constants {
+
+    /**
+     * UTF-8 字符集
+     */
+    String UTF8 = "UTF-8";
+
+    /**
+     * GBK 字符集
+     */
+    String GBK = "GBK";
+
+    /**
+     * 系统语言
+     */
+    Locale DEFAULT_LOCALE = Locale.SIMPLIFIED_CHINESE;
+
+    /**
+     * www主域
+     */
+    String WWW = "www.";
+
+    /**
+     * http请求
+     */
+    String HTTP = "http://";
+
+    /**
+     * https请求
+     */
+    String HTTPS = "https://";
+
+    /**
+     * 通用成功标识
+     */
+    String SUCCESS = "0";
+
+    /**
+     * 通用失败标识
+     */
+    String FAIL = "1";
+
+    /**
+     * 登录成功
+     */
+    String LOGIN_SUCCESS = "Success";
+
+    /**
+     * 注销
+     */
+    String LOGOUT = "Logout";
+
+    /**
+     * 注册
+     */
+    String REGISTER = "Register";
+
+    /**
+     * 登录失败
+     */
+    String LOGIN_FAIL = "Error";
+
+    /**
+     * 所有权限标识
+     */
+    String ALL_PERMISSION = "*:*:*";
+
+    /**
+     * 管理员角色权限标识
+     */
+    String SUPER_ADMIN = "admin";
+
+    /**
+     * 角色权限分隔符
+     */
+    String ROLE_DELIMETER = ",";
+
+    /**
+     * 权限标识分隔符
+     */
+    String PERMISSION_DELIMETER = ",";
+
+    /**
+     * 验证码有效期(分钟)
+     */
+    Integer CAPTCHA_EXPIRATION = 2;
+
+    /**
+     * 令牌
+     */
+    String TOKEN = "token";
+
+    /**
+     * 令牌前缀
+     */
+    String TOKEN_PREFIX = "Bearer ";
+
+    /**
+     * 令牌前缀
+     */
+    String LOGIN_USER_KEY = "login_user_key";
+
+    /**
+     * 用户ID
+     */
+    String JWT_USERID = "userid";
+
+    /**
+     * 用户名称
+     */
+    String JWT_USERNAME = Claims.SUBJECT;
+
+    /**
+     * 用户头像
+     */
+    String JWT_AVATAR = "avatar";
+
+    /**
+     * 创建时间
+     */
+    String JWT_CREATED = "created";
+
+    /**
+     * 用户权限
+     */
+    String JWT_AUTHORITIES = "authorities";
+
+    /**
+     * 资源映射路径 前缀
+     */
+    String RESOURCE_PREFIX = "/profile";
+
+    /**
+     * RMI 远程方法调用
+     */
+    String LOOKUP_RMI = "rmi:";
+
+    /**
+     * LDAP 远程方法调用
+     */
+    String LOOKUP_LDAP = "ldap:";
+
+    /**
+     * LDAPS 远程方法调用
+     */
+    String LOOKUP_LDAPS = "ldaps:";
+
+    /**
+     * 自动识别json对象白名单配置(仅允许解析的包名,范围越小越安全)
+     */
+    String[] JSON_WHITELIST_STR = {"org.springframework", "com.lij.himeeter"};
+
+    /**
+     * 定时任务白名单配置(仅允许访问的包名,如其他需要可以自行添加)
+     */
+    String[] JOB_WHITELIST_STR = {"com.lij.himeeter.quartz.task"};
+
+    /**
+     * 定时任务违规的字符
+     */
+    String[] JOB_ERROR_STR = {"java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml",
+            "org.springframework", "org.apache", "com.lij.himeeter.common.utils.file", "com.lij.himeeter.common.config", "com.lij.himeeter.generator"};
+}

+ 103 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/constant/HttpStatus.java

@@ -0,0 +1,103 @@
+package com.lij.himeeter.common.constant;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  HttpStatus
+ * 创建时间 : 2024年12月27日 15:40
+ *
+ * 文件描述 : 返回状态码
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public interface HttpStatus {
+
+    /**
+     * 操作成功
+     */
+    int SUCCESS = 200;
+
+    /**
+     * 对象创建成功
+     */
+    int CREATED = 201;
+
+    /**
+     * 请求已经被接受
+     */
+    int ACCEPTED = 202;
+
+    /**
+     * 操作已经执行成功,但是没有返回数据
+     */
+    int NO_CONTENT = 204;
+
+    /**
+     * 资源已被移除
+     */
+    int MOVED_PERM = 301;
+
+    /**
+     * 重定向
+     */
+    int SEE_OTHER = 303;
+
+    /**
+     * 资源没有被修改
+     */
+    int NOT_MODIFIED = 304;
+
+    /**
+     * 参数列表错误(缺少,格式不匹配)
+     */
+    int BAD_REQUEST = 400;
+
+    /**
+     * 未授权
+     */
+    int UNAUTHORIZED = 401;
+
+    /**
+     * 访问受限,授权过期
+     */
+    int FORBIDDEN = 403;
+
+    /**
+     * 资源,服务未找到
+     */
+    int NOT_FOUND = 404;
+
+    /**
+     * 不允许的http方法
+     */
+    int BAD_METHOD = 405;
+
+    /**
+     * 资源冲突,或者资源被锁
+     */
+    int CONFLICT = 409;
+
+    /**
+     * 不支持的数据,媒体类型
+     */
+    int UNSUPPORTED_TYPE = 415;
+
+    /**
+     * 系统内部错误
+     */
+    int ERROR = 500;
+
+    /**
+     * 接口未实现
+     */
+    int NOT_IMPLEMENTED = 501;
+
+    /**
+     * 系统警告消息
+     */
+    int WARN = 601;
+}

+ 126 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/constant/UserConstants.java

@@ -0,0 +1,126 @@
+package com.lij.himeeter.common.constant;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  UserConstants
+ * 创建时间 : 2024年12月27日 14:30
+ *
+ * 文件描述 : 用户常量信息
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public interface UserConstants {
+
+    /**
+     * 平台内系统用户的唯一标志
+     */
+    String SYS_USER = "SYS_USER";
+
+    /**
+     * 正常状态
+     */
+    String NORMAL = "0";
+
+    /**
+     * 异常状态
+     */
+    String EXCEPTION = "1";
+
+    /**
+     * 用户封禁状态
+     */
+    String USER_DISABLE = "1";
+
+    /**
+     * 角色正常状态
+     */
+    String ROLE_NORMAL = "0";
+
+    /**
+     * 角色封禁状态
+     */
+    String ROLE_DISABLE = "1";
+
+    /**
+     * 部门正常状态
+     */
+    String DEPT_NORMAL = "0";
+
+    /**
+     * 部门停用状态
+     */
+    String DEPT_DISABLE = "1";
+
+    /**
+     * 字典正常状态
+     */
+    String DICT_NORMAL = "0";
+
+    /**
+     * 是否为系统默认(是)
+     */
+    String YES = "Y";
+
+    /**
+     * 是否菜单外链(是)
+     */
+    String YES_FRAME = "0";
+
+    /**
+     * 是否菜单外链(否)
+     */
+    String NO_FRAME = "1";
+
+    /**
+     * 菜单类型(目录)
+     */
+    String TYPE_DIR = "M";
+
+    /**
+     * 菜单类型(菜单)
+     */
+    String TYPE_MENU = "C";
+
+    /**
+     * 菜单类型(按钮)
+     */
+    String TYPE_BUTTON = "F";
+
+    /**
+     * Layout组件标识
+     */
+    String LAYOUT = "Layout";
+
+    /**
+     * ParentView组件标识
+     */
+    String PARENT_VIEW = "ParentView";
+
+    /**
+     * InnerLink组件标识
+     */
+    String INNER_LINK = "InnerLink";
+
+    /**
+     * 校验是否唯一的返回标识
+     */
+    boolean UNIQUE = true;
+    boolean NOT_UNIQUE = false;
+
+    /**
+     * 用户名长度限制
+     */
+    int USERNAME_MIN_LENGTH = 2;
+    int USERNAME_MAX_LENGTH = 20;
+
+    /**
+     * 密码长度限制
+     */
+    int PASSWORD_MIN_LENGTH = 5;
+    int PASSWORD_MAX_LENGTH = 20;
+}

+ 254 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/core/RedisCache.java

@@ -0,0 +1,254 @@
+package com.lij.himeeter.common.core;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.BoundSetOperations;
+import org.springframework.data.redis.core.HashOperations;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.ValueOperations;
+import org.springframework.stereotype.Component;
+
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  RedisCache
+ * 创建时间 : 2024年12月30日 18:22
+ *
+ * 文件描述 : spring redis 工具类
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+@SuppressWarnings(value = {"unchecked", "rawtypes"})
+@Component
+public class RedisCache {
+
+    @Autowired
+    public RedisTemplate redisTemplate;
+
+    /**
+     * 缓存基本的对象,Integer、String、实体类等
+     *
+     * @param key   缓存的键值
+     * @param value 缓存的值
+     */
+    public <T> void setCacheObject(final String key, final T value) {
+        redisTemplate.opsForValue().set(key, value);
+    }
+
+    /**
+     * 缓存基本的对象,Integer、String、实体类等
+     *
+     * @param key      缓存的键值
+     * @param value    缓存的值
+     * @param timeout  时间
+     * @param timeUnit 时间颗粒度
+     */
+    public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) {
+        redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
+    }
+
+    /**
+     * 设置有效时间
+     *
+     * @param key     Redis键
+     * @param timeout 超时时间
+     * @return true=设置成功;false=设置失败
+     */
+    public boolean expire(final String key, final long timeout) {
+        return expire(key, timeout, TimeUnit.SECONDS);
+    }
+
+    /**
+     * 设置有效时间
+     *
+     * @param key     Redis键
+     * @param timeout 超时时间
+     * @param unit    时间单位
+     * @return true=设置成功;false=设置失败
+     */
+    public boolean expire(final String key, final long timeout, final TimeUnit unit) {
+        return redisTemplate.expire(key, timeout, unit);
+    }
+
+    /**
+     * 获取有效时间
+     *
+     * @param key Redis键
+     * @return 有效时间
+     */
+    public long getExpire(final String key) {
+        return redisTemplate.getExpire(key);
+    }
+
+    /**
+     * 判断 key是否存在
+     *
+     * @param key 键
+     * @return true 存在 false不存在
+     */
+    public Boolean hasKey(String key) {
+        return redisTemplate.hasKey(key);
+    }
+
+    /**
+     * 获得缓存的基本对象。
+     *
+     * @param key 缓存键值
+     * @return 缓存键值对应的数据
+     */
+    public <T> T getCacheObject(final String key) {
+        ValueOperations<String, T> operation = redisTemplate.opsForValue();
+        return operation.get(key);
+    }
+
+    /**
+     * 删除单个对象
+     *
+     * @param key
+     */
+    public boolean deleteObject(final String key) {
+        return redisTemplate.delete(key);
+    }
+
+    /**
+     * 删除集合对象
+     *
+     * @param collection 多个对象
+     * @return
+     */
+    public boolean deleteObject(final Collection collection) {
+        return redisTemplate.delete(collection) > 0;
+    }
+
+    /**
+     * 缓存List数据
+     *
+     * @param key      缓存的键值
+     * @param dataList 待缓存的List数据
+     * @return 缓存的对象
+     */
+    public <T> long setCacheList(final String key, final List<T> dataList) {
+        Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
+        return count == null ? 0 : count;
+    }
+
+    /**
+     * 获得缓存的list对象
+     *
+     * @param key 缓存的键值
+     * @return 缓存键值对应的数据
+     */
+    public <T> List<T> getCacheList(final String key) {
+        return redisTemplate.opsForList().range(key, 0, -1);
+    }
+
+    /**
+     * 缓存Set
+     *
+     * @param key     缓存键值
+     * @param dataSet 缓存的数据
+     * @return 缓存数据的对象
+     */
+    public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet) {
+        BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
+        Iterator<T> it = dataSet.iterator();
+        while (it.hasNext()) {
+            setOperation.add(it.next());
+        }
+        return setOperation;
+    }
+
+    /**
+     * 获得缓存的set
+     *
+     * @param key
+     * @return
+     */
+    public <T> Set<T> getCacheSet(final String key) {
+        return redisTemplate.opsForSet().members(key);
+    }
+
+    /**
+     * 缓存Map
+     *
+     * @param key
+     * @param dataMap
+     */
+    public <T> void setCacheMap(final String key, final Map<String, T> dataMap) {
+        if (dataMap != null) {
+            redisTemplate.opsForHash().putAll(key, dataMap);
+        }
+    }
+
+    /**
+     * 获得缓存的Map
+     *
+     * @param key
+     * @return
+     */
+    public <T> Map<String, T> getCacheMap(final String key) {
+        return redisTemplate.opsForHash().entries(key);
+    }
+
+    /**
+     * 往Hash中存入数据
+     *
+     * @param key   Redis键
+     * @param hKey  Hash键
+     * @param value 值
+     */
+    public <T> void setCacheMapValue(final String key, final String hKey, final T value) {
+        redisTemplate.opsForHash().put(key, hKey, value);
+    }
+
+    /**
+     * 获取Hash中的数据
+     *
+     * @param key  Redis键
+     * @param hKey Hash键
+     * @return Hash中的对象
+     */
+    public <T> T getCacheMapValue(final String key, final String hKey) {
+        HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
+        return opsForHash.get(key, hKey);
+    }
+
+    /**
+     * 获取多个Hash中的数据
+     *
+     * @param key   Redis键
+     * @param hKeys Hash键集合
+     * @return Hash对象集合
+     */
+    public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys) {
+        return redisTemplate.opsForHash().multiGet(key, hKeys);
+    }
+
+    /**
+     * 删除Hash中的某条数据
+     *
+     * @param key  Redis键
+     * @param hKey Hash键
+     * @return 是否成功
+     */
+    public boolean deleteCacheMapValue(final String key, final String hKey) {
+        return redisTemplate.opsForHash().delete(key, hKey) > 0;
+    }
+
+    /**
+     * 获得缓存的基本对象列表
+     *
+     * @param pattern 字符串前缀
+     * @return 对象列表
+     */
+    public Collection<String> keys(final String pattern) {
+        return redisTemplate.keys(pattern);
+    }
+
+}

+ 226 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/core/domain/AjaxResult.java

@@ -0,0 +1,226 @@
+package com.lij.himeeter.common.core.domain;
+
+import com.lij.himeeter.common.constant.HttpStatus;
+import com.lij.himeeter.common.utils.StringUtils;
+
+import java.util.HashMap;
+import java.util.Objects;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  AjaxResult
+ * 创建时间 : 2024年12月27日 15:32
+ *
+ * 文件描述 : 操作消息提醒
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class AjaxResult extends HashMap<String, Object> {
+
+    private static final long serialVersionUID = 1L;
+
+    /** 状态码 */
+    public static final String CODE_TAG = "code";
+
+    /** 返回内容 */
+    public static final String MSG_TAG = "msg";
+
+    /** 数据对象 */
+    public static final String DATA_TAG = "data";
+
+    /**
+     * 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。
+     */
+    public AjaxResult()
+    {
+    }
+
+    /**
+     * 初始化一个新创建的 AjaxResult 对象
+     *
+     * @param code 状态码
+     * @param msg 返回内容
+     */
+    public AjaxResult(int code, String msg)
+    {
+        super.put(CODE_TAG, code);
+        super.put(MSG_TAG, msg);
+    }
+
+    /**
+     * 初始化一个新创建的 AjaxResult 对象
+     *
+     * @param code 状态码
+     * @param msg 返回内容
+     * @param data 数据对象
+     */
+    public AjaxResult(int code, String msg, Object data)
+    {
+        super.put(CODE_TAG, code);
+        super.put(MSG_TAG, msg);
+        if (StringUtils.isNotNull(data))
+        {
+            super.put(DATA_TAG, data);
+        }
+    }
+
+    /**
+     * 返回成功消息
+     *
+     * @return 成功消息
+     */
+    public static AjaxResult success()
+    {
+        return AjaxResult.success("操作成功");
+    }
+
+    /**
+     * 返回成功数据
+     *
+     * @return 成功消息
+     */
+    public static AjaxResult success(Object data)
+    {
+        return AjaxResult.success("操作成功", data);
+    }
+
+    /**
+     * 返回成功消息
+     *
+     * @param msg 返回内容
+     * @return 成功消息
+     */
+    public static AjaxResult success(String msg)
+    {
+        return AjaxResult.success(msg, null);
+    }
+
+    /**
+     * 返回成功消息
+     *
+     * @param msg 返回内容
+     * @param data 数据对象
+     * @return 成功消息
+     */
+    public static AjaxResult success(String msg, Object data)
+    {
+        return new AjaxResult(HttpStatus.SUCCESS, msg, data);
+    }
+
+    /**
+     * 返回警告消息
+     *
+     * @param msg 返回内容
+     * @return 警告消息
+     */
+    public static AjaxResult warn(String msg)
+    {
+        return AjaxResult.warn(msg, null);
+    }
+
+    /**
+     * 返回警告消息
+     *
+     * @param msg 返回内容
+     * @param data 数据对象
+     * @return 警告消息
+     */
+    public static AjaxResult warn(String msg, Object data)
+    {
+        return new AjaxResult(HttpStatus.WARN, msg, data);
+    }
+
+    /**
+     * 返回错误消息
+     *
+     * @return 错误消息
+     */
+    public static AjaxResult error()
+    {
+        return AjaxResult.error("操作失败");
+    }
+
+    /**
+     * 返回错误消息
+     *
+     * @param msg 返回内容
+     * @return 错误消息
+     */
+    public static AjaxResult error(String msg)
+    {
+        return AjaxResult.error(msg, null);
+    }
+
+    /**
+     * 返回错误消息
+     *
+     * @param msg 返回内容
+     * @param data 数据对象
+     * @return 错误消息
+     */
+    public static AjaxResult error(String msg, Object data)
+    {
+        return new AjaxResult(HttpStatus.ERROR, msg, data);
+    }
+
+    /**
+     * 返回错误消息
+     *
+     * @param code 状态码
+     * @param msg 返回内容
+     * @return 错误消息
+     */
+    public static AjaxResult error(int code, String msg)
+    {
+        return new AjaxResult(code, msg, null);
+    }
+
+    /**
+     * 是否为成功消息
+     *
+     * @return 结果
+     */
+    public boolean isSuccess()
+    {
+        return Objects.equals(HttpStatus.SUCCESS, this.get(CODE_TAG));
+    }
+
+    /**
+     * 是否为警告消息
+     *
+     * @return 结果
+     */
+    public boolean isWarn()
+    {
+        return Objects.equals(HttpStatus.WARN, this.get(CODE_TAG));
+    }
+
+    /**
+     * 是否为错误消息
+     *
+     * @return 结果
+     */
+    public boolean isError()
+    {
+        return Objects.equals(HttpStatus.ERROR, this.get(CODE_TAG));
+    }
+
+    /**
+     * 方便链式调用
+     *
+     * @param key 键
+     * @param value 值
+     * @return 数据对象
+     */
+    @Override
+    public AjaxResult put(String key, Object value)
+    {
+        super.put(key, value);
+        return this;
+    }
+}

+ 127 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/core/domain/BaseEntity.java

@@ -0,0 +1,127 @@
+package com.lij.himeeter.common.core.domain;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonInclude;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  BaseEntity
+ * 创建时间 : 2024年12月26日 18:42
+ *
+ * 文件描述 : Entity基类
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class BaseEntity implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 搜索值
+     */
+    @JsonIgnore
+    private String searchValue;
+
+    /**
+     * 创建者
+     */
+    private String createBy;
+
+    /**
+     * 创建时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date createTime;
+
+    /**
+     * 更新者
+     */
+    private String updateBy;
+
+    /**
+     * 更新时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date updateTime;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+    /**
+     * 请求参数
+     */
+    @JsonInclude(JsonInclude.Include.NON_EMPTY)
+    private Map<String, Object> params;
+
+    public String getSearchValue() {
+        return searchValue;
+    }
+
+    public void setSearchValue(String searchValue) {
+        this.searchValue = searchValue;
+    }
+
+    public String getCreateBy() {
+        return createBy;
+    }
+
+    public void setCreateBy(String createBy) {
+        this.createBy = createBy;
+    }
+
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    public String getUpdateBy() {
+        return updateBy;
+    }
+
+    public void setUpdateBy(String updateBy) {
+        this.updateBy = updateBy;
+    }
+
+    public Date getUpdateTime() {
+        return updateTime;
+    }
+
+    public void setUpdateTime(Date updateTime) {
+        this.updateTime = updateTime;
+    }
+
+    public String getRemark() {
+        return remark;
+    }
+
+    public void setRemark(String remark) {
+        this.remark = remark;
+    }
+
+    public Map<String, Object> getParams() {
+        if (params == null) {
+            params = new HashMap<>();
+        }
+        return params;
+    }
+
+    public void setParams(Map<String, Object> params) {
+        this.params = params;
+    }
+
+}

+ 111 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/core/domain/R.java

@@ -0,0 +1,111 @@
+package com.lij.himeeter.common.core.domain;
+
+import com.lij.himeeter.common.constant.HttpStatus;
+
+import java.io.Serializable;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  R
+ * 创建时间 : 2024年12月27日 15:32
+ *
+ * 文件描述 : 响应信息主体
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class R<T> implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 成功
+     */
+    public static final int SUCCESS = HttpStatus.SUCCESS;
+
+    /**
+     * 失败
+     */
+    public static final int FAIL = HttpStatus.ERROR;
+
+    private int code;
+
+    private String msg;
+
+    private T data;
+
+    public static <T> R<T> ok() {
+        return restResult(null, SUCCESS, "操作成功");
+    }
+
+    public static <T> R<T> ok(T data) {
+        return restResult(data, SUCCESS, "操作成功");
+    }
+
+    public static <T> R<T> ok(T data, String msg) {
+        return restResult(data, SUCCESS, msg);
+    }
+
+    public static <T> R<T> fail() {
+        return restResult(null, FAIL, "操作失败");
+    }
+
+    public static <T> R<T> fail(String msg) {
+        return restResult(null, FAIL, msg);
+    }
+
+    public static <T> R<T> fail(T data) {
+        return restResult(data, FAIL, "操作失败");
+    }
+
+    public static <T> R<T> fail(T data, String msg) {
+        return restResult(data, FAIL, msg);
+    }
+
+    public static <T> R<T> fail(int code, String msg) {
+        return restResult(null, code, msg);
+    }
+
+    private static <T> R<T> restResult(T data, int code, String msg) {
+        R<T> apiResult = new R<>();
+        apiResult.setCode(code);
+        apiResult.setData(data);
+        apiResult.setMsg(msg);
+        return apiResult;
+    }
+
+    public int getCode() {
+        return code;
+    }
+
+    public void setCode(int code) {
+        this.code = code;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public void setMsg(String msg) {
+        this.msg = msg;
+    }
+
+    public T getData() {
+        return data;
+    }
+
+    public void setData(T data) {
+        this.data = data;
+    }
+
+    public static <T> Boolean isError(R<T> ret) {
+        return !isSuccess(ret);
+    }
+
+    public static <T> Boolean isSuccess(R<T> ret) {
+        return R.SUCCESS == ret.getCode();
+    }
+}

+ 88 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/core/domain/TreeEntity.java

@@ -0,0 +1,88 @@
+package com.lij.himeeter.common.core.domain;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  TreeEntity
+ * 创建时间 : 2024年12月27日 15:33
+ *
+ * 文件描述 : Tree基类
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class TreeEntity extends BaseEntity {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 父菜单名称
+     */
+    private String parentName;
+
+    /**
+     * 父菜单ID
+     */
+    private Long parentId;
+
+    /**
+     * 显示顺序
+     */
+    private Integer orderNum;
+
+    /**
+     * 祖级列表
+     */
+    private String ancestors;
+
+    /**
+     * 子部门
+     */
+    private List<?> children = new ArrayList<>();
+
+    public String getParentName() {
+        return parentName;
+    }
+
+    public void setParentName(String parentName) {
+        this.parentName = parentName;
+    }
+
+    public Long getParentId() {
+        return parentId;
+    }
+
+    public void setParentId(Long parentId) {
+        this.parentId = parentId;
+    }
+
+    public Integer getOrderNum() {
+        return orderNum;
+    }
+
+    public void setOrderNum(Integer orderNum) {
+        this.orderNum = orderNum;
+    }
+
+    public String getAncestors() {
+        return ancestors;
+    }
+
+    public void setAncestors(String ancestors) {
+        this.ancestors = ancestors;
+    }
+
+    public List<?> getChildren() {
+        return children;
+    }
+
+    public void setChildren(List<?> children) {
+        this.children = children;
+    }
+
+}

+ 101 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/core/domain/TreeSelect.java

@@ -0,0 +1,101 @@
+package com.lij.himeeter.common.core.domain;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.lij.himeeter.common.constant.UserConstants;
+import com.lij.himeeter.common.core.domain.entity.SysDept;
+import com.lij.himeeter.common.core.domain.entity.SysMenu;
+import com.lij.himeeter.common.utils.StringUtils;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  TreeSelect
+ * 创建时间 : 2024年12月27日 15:33
+ *
+ * 文件描述 : TreeSelect 树结构实体类
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class TreeSelect implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 节点ID
+     */
+    private Long id;
+
+    /**
+     * 节点名称
+     */
+    private String label;
+
+    /**
+     * 节点禁用
+     */
+    private boolean disabled = false;
+
+    /**
+     * 子节点
+     */
+    @JsonInclude(JsonInclude.Include.NON_EMPTY)
+    private List<TreeSelect> children;
+
+    public TreeSelect() {
+
+    }
+
+    public TreeSelect(SysDept dept) {
+        this.id = dept.getDeptId();
+        this.label = dept.getDeptName();
+        this.disabled = StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus());
+        this.children = dept.getChildren().stream().map(TreeSelect::new).collect(Collectors.toList());
+    }
+
+    public TreeSelect(SysMenu menu) {
+        this.id = menu.getMenuId();
+        this.label = menu.getMenuName();
+        this.children = menu.getChildren().stream().map(TreeSelect::new).collect(Collectors.toList());
+    }
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getLabel() {
+        return label;
+    }
+
+    public void setLabel(String label) {
+        this.label = label;
+    }
+
+    public boolean isDisabled() {
+        return disabled;
+    }
+
+    public void setDisabled(boolean disabled) {
+        this.disabled = disabled;
+    }
+
+    public List<TreeSelect> getChildren() {
+        return children;
+    }
+
+    public void setChildren(List<TreeSelect> children) {
+        this.children = children;
+    }
+
+}

+ 212 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/core/domain/entity/SysDept.java

@@ -0,0 +1,212 @@
+package com.lij.himeeter.common.core.domain.entity;
+
+import com.lij.himeeter.common.core.domain.BaseEntity;
+import jakarta.validation.constraints.Email;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SysDept
+ * 创建时间 : 2024年12月26日 18:50
+ *
+ * 文件描述 : 部门表 sys_dept
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class SysDept extends BaseEntity {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 部门ID
+     */
+    private Long deptId;
+
+    /**
+     * 父部门ID
+     */
+    private Long parentId;
+
+    /**
+     * 祖级列表
+     */
+    private String ancestors;
+
+    /**
+     * 部门名称
+     */
+    private String deptName;
+
+    /**
+     * 显示顺序
+     */
+    private Integer orderNum;
+
+    /**
+     * 负责人
+     */
+    private String leader;
+
+    /**
+     * 联系电话
+     */
+    private String phone;
+
+    /**
+     * 邮箱
+     */
+    private String email;
+
+    /**
+     * 部门状态:0正常,1停用
+     */
+    private String status;
+
+    /**
+     * 删除标志(0代表存在 2代表删除)
+     */
+    private String delFlag;
+
+    /**
+     * 父部门名称
+     */
+    private String parentName;
+
+    /**
+     * 子部门
+     */
+    private List<SysDept> children = new ArrayList<SysDept>();
+
+    public Long getDeptId() {
+        return deptId;
+    }
+
+    public void setDeptId(Long deptId) {
+        this.deptId = deptId;
+    }
+
+    public Long getParentId() {
+        return parentId;
+    }
+
+    public void setParentId(Long parentId) {
+        this.parentId = parentId;
+    }
+
+    public String getAncestors() {
+        return ancestors;
+    }
+
+    public void setAncestors(String ancestors) {
+        this.ancestors = ancestors;
+    }
+
+    @NotBlank(message = "部门名称不能为空")
+    @Size(min = 0, max = 30, message = "部门名称长度不能超过30个字符")
+    public String getDeptName() {
+        return deptName;
+    }
+
+    public void setDeptName(String deptName) {
+        this.deptName = deptName;
+    }
+
+    @NotNull(message = "显示顺序不能为空")
+    public Integer getOrderNum() {
+        return orderNum;
+    }
+
+    public void setOrderNum(Integer orderNum) {
+        this.orderNum = orderNum;
+    }
+
+    public String getLeader() {
+        return leader;
+    }
+
+    public void setLeader(String leader) {
+        this.leader = leader;
+    }
+
+    @Size(min = 0, max = 11, message = "联系电话长度不能超过11个字符")
+    public String getPhone() {
+        return phone;
+    }
+
+    public void setPhone(String phone) {
+        this.phone = phone;
+    }
+
+    @Email(message = "邮箱格式不正确")
+    @Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符")
+    public String getEmail() {
+        return email;
+    }
+
+    public void setEmail(String email) {
+        this.email = email;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public String getDelFlag() {
+        return delFlag;
+    }
+
+    public void setDelFlag(String delFlag) {
+        this.delFlag = delFlag;
+    }
+
+    public String getParentName() {
+        return parentName;
+    }
+
+    public void setParentName(String parentName) {
+        this.parentName = parentName;
+    }
+
+    public List<SysDept> getChildren() {
+        return children;
+    }
+
+    public void setChildren(List<SysDept> children) {
+        this.children = children;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+                .append("deptId", getDeptId())
+                .append("parentId", getParentId())
+                .append("ancestors", getAncestors())
+                .append("deptName", getDeptName())
+                .append("orderNum", getOrderNum())
+                .append("leader", getLeader())
+                .append("phone", getPhone())
+                .append("email", getEmail())
+                .append("status", getStatus())
+                .append("delFlag", getDelFlag())
+                .append("createBy", getCreateBy())
+                .append("createTime", getCreateTime())
+                .append("updateBy", getUpdateBy())
+                .append("updateTime", getUpdateTime())
+                .toString();
+    }
+}

+ 184 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/core/domain/entity/SysDictData.java

@@ -0,0 +1,184 @@
+package com.lij.himeeter.common.core.domain.entity;
+
+import com.lij.himeeter.common.annotation.Excel;
+import com.lij.himeeter.common.annotation.Excel.ColumnType;
+import com.lij.himeeter.common.constant.UserConstants;
+import com.lij.himeeter.common.core.domain.BaseEntity;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.Size;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SysDictData
+ * 创建时间 : 2024年12月26日 18:50
+ *
+ * 文件描述 : 字典数据表 sys_dict_data
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class SysDictData extends BaseEntity {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 字典编码
+     */
+    @Excel(name = "字典编码", cellType = ColumnType.NUMERIC)
+    private Long dictCode;
+
+    /**
+     * 字典排序
+     */
+    @Excel(name = "字典排序", cellType = ColumnType.NUMERIC)
+    private Long dictSort;
+
+    /**
+     * 字典标签
+     */
+    @Excel(name = "字典标签")
+    private String dictLabel;
+
+    /**
+     * 字典键值
+     */
+    @Excel(name = "字典键值")
+    private String dictValue;
+
+    /**
+     * 字典类型
+     */
+    @Excel(name = "字典类型")
+    private String dictType;
+
+    /**
+     * 样式属性(其他样式扩展)
+     */
+    private String cssClass;
+
+    /**
+     * 表格字典样式
+     */
+    private String listClass;
+
+    /**
+     * 是否默认(Y是 N否)
+     */
+    @Excel(name = "是否默认", readConverterExp = "Y=是,N=否")
+    private String isDefault;
+
+    /**
+     * 状态(0正常 1停用)
+     */
+    @Excel(name = "状态", readConverterExp = "0=正常,1=停用")
+    private String status;
+
+    public Long getDictCode() {
+        return dictCode;
+    }
+
+    public void setDictCode(Long dictCode) {
+        this.dictCode = dictCode;
+    }
+
+    public Long getDictSort() {
+        return dictSort;
+    }
+
+    public void setDictSort(Long dictSort) {
+        this.dictSort = dictSort;
+    }
+
+    @NotBlank(message = "字典标签不能为空")
+    @Size(min = 0, max = 100, message = "字典标签长度不能超过100个字符")
+    public String getDictLabel() {
+        return dictLabel;
+    }
+
+    public void setDictLabel(String dictLabel) {
+        this.dictLabel = dictLabel;
+    }
+
+    @NotBlank(message = "字典键值不能为空")
+    @Size(min = 0, max = 100, message = "字典键值长度不能超过100个字符")
+    public String getDictValue() {
+        return dictValue;
+    }
+
+    public void setDictValue(String dictValue) {
+        this.dictValue = dictValue;
+    }
+
+    @NotBlank(message = "字典类型不能为空")
+    @Size(min = 0, max = 100, message = "字典类型长度不能超过100个字符")
+    public String getDictType() {
+        return dictType;
+    }
+
+    public void setDictType(String dictType) {
+        this.dictType = dictType;
+    }
+
+    @Size(min = 0, max = 100, message = "样式属性长度不能超过100个字符")
+    public String getCssClass() {
+        return cssClass;
+    }
+
+    public void setCssClass(String cssClass) {
+        this.cssClass = cssClass;
+    }
+
+    public String getListClass() {
+        return listClass;
+    }
+
+    public void setListClass(String listClass) {
+        this.listClass = listClass;
+    }
+
+    public boolean getDefault() {
+        return UserConstants.YES.equals(this.isDefault);
+    }
+
+    public String getIsDefault() {
+        return isDefault;
+    }
+
+    public void setIsDefault(String isDefault) {
+        this.isDefault = isDefault;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+                .append("dictCode", getDictCode())
+                .append("dictSort", getDictSort())
+                .append("dictLabel", getDictLabel())
+                .append("dictValue", getDictValue())
+                .append("dictType", getDictType())
+                .append("cssClass", getCssClass())
+                .append("listClass", getListClass())
+                .append("isDefault", getIsDefault())
+                .append("status", getStatus())
+                .append("createBy", getCreateBy())
+                .append("createTime", getCreateTime())
+                .append("updateBy", getUpdateBy())
+                .append("updateTime", getUpdateTime())
+                .append("remark", getRemark())
+                .toString();
+    }
+}

+ 105 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/core/domain/entity/SysDictType.java

@@ -0,0 +1,105 @@
+package com.lij.himeeter.common.core.domain.entity;
+
+import com.lij.himeeter.common.annotation.Excel;
+import com.lij.himeeter.common.annotation.Excel.ColumnType;
+import com.lij.himeeter.common.core.domain.BaseEntity;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.Pattern;
+import jakarta.validation.constraints.Size;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SysDictType
+ * 创建时间 : 2024年12月26日 18:50
+ *
+ * 文件描述 : 字典类型表 sys_dict_type
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class SysDictType extends BaseEntity {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 字典主键
+     */
+    @Excel(name = "字典主键", cellType = ColumnType.NUMERIC)
+    private Long dictId;
+
+    /**
+     * 字典名称
+     */
+    @Excel(name = "字典名称")
+    private String dictName;
+
+    /**
+     * 字典类型
+     */
+    @Excel(name = "字典类型")
+    private String dictType;
+
+    /**
+     * 状态(0正常 1停用)
+     */
+    @Excel(name = "状态", readConverterExp = "0=正常,1=停用")
+    private String status;
+
+    public Long getDictId() {
+        return dictId;
+    }
+
+    public void setDictId(Long dictId) {
+        this.dictId = dictId;
+    }
+
+    @NotBlank(message = "字典名称不能为空")
+    @Size(min = 0, max = 100, message = "字典类型名称长度不能超过100个字符")
+    public String getDictName() {
+        return dictName;
+    }
+
+    public void setDictName(String dictName) {
+        this.dictName = dictName;
+    }
+
+    @NotBlank(message = "字典类型不能为空")
+    @Size(min = 0, max = 100, message = "字典类型类型长度不能超过100个字符")
+    @Pattern(regexp = "^[a-z][a-z0-9_]*$", message = "字典类型必须以字母开头,且只能为(小写字母,数字,下滑线)")
+    public String getDictType() {
+        return dictType;
+    }
+
+    public void setDictType(String dictType) {
+        this.dictType = dictType;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+                .append("dictId", getDictId())
+                .append("dictName", getDictName())
+                .append("dictType", getDictType())
+                .append("status", getStatus())
+                .append("createBy", getCreateBy())
+                .append("createTime", getCreateTime())
+                .append("updateBy", getUpdateBy())
+                .append("updateTime", getUpdateTime())
+                .append("remark", getRemark())
+                .toString();
+    }
+}

+ 283 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/core/domain/entity/SysMenu.java

@@ -0,0 +1,283 @@
+package com.lij.himeeter.common.core.domain.entity;
+
+import com.lij.himeeter.common.core.domain.BaseEntity;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SysMenu
+ * 创建时间 : 2024年12月26日 18:51
+ *
+ * 文件描述 : 菜单权限表 sys_menu
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class SysMenu extends BaseEntity {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 菜单ID
+     */
+    private Long menuId;
+
+    /**
+     * 菜单名称
+     */
+    private String menuName;
+
+    /**
+     * 父菜单名称
+     */
+    private String parentName;
+
+    /**
+     * 父菜单ID
+     */
+    private Long parentId;
+
+    /**
+     * 显示顺序
+     */
+    private Integer orderNum;
+
+    /**
+     * 路由地址
+     */
+    private String path;
+
+    /**
+     * 组件路径
+     */
+    private String component;
+
+    /**
+     * 路由参数
+     */
+    private String query;
+
+    /**
+     * 路由名称,默认和路由地址相同的驼峰格式(注意:因为vue3版本的router会删除名称相同路由,为避免名字的冲突,特殊情况可以自定义)
+     */
+    private String routeName;
+
+    /**
+     * 是否为外链(0是 1否)
+     */
+    private String isFrame;
+
+    /**
+     * 是否缓存(0缓存 1不缓存)
+     */
+    private String isCache;
+
+    /**
+     * 类型(M目录 C菜单 F按钮)
+     */
+    private String menuType;
+
+    /**
+     * 显示状态(0显示 1隐藏)
+     */
+    private String visible;
+
+    /**
+     * 菜单状态(0正常 1停用)
+     */
+    private String status;
+
+    /**
+     * 权限字符串
+     */
+    private String perms;
+
+    /**
+     * 菜单图标
+     */
+    private String icon;
+
+    /**
+     * 子菜单
+     */
+    private List<SysMenu> children = new ArrayList<SysMenu>();
+
+    public Long getMenuId() {
+        return menuId;
+    }
+
+    public void setMenuId(Long menuId) {
+        this.menuId = menuId;
+    }
+
+    @NotBlank(message = "菜单名称不能为空")
+    @Size(min = 0, max = 50, message = "菜单名称长度不能超过50个字符")
+    public String getMenuName() {
+        return menuName;
+    }
+
+    public void setMenuName(String menuName) {
+        this.menuName = menuName;
+    }
+
+    public String getParentName() {
+        return parentName;
+    }
+
+    public void setParentName(String parentName) {
+        this.parentName = parentName;
+    }
+
+    public Long getParentId() {
+        return parentId;
+    }
+
+    public void setParentId(Long parentId) {
+        this.parentId = parentId;
+    }
+
+    @NotNull(message = "显示顺序不能为空")
+    public Integer getOrderNum() {
+        return orderNum;
+    }
+
+    public void setOrderNum(Integer orderNum) {
+        this.orderNum = orderNum;
+    }
+
+    @Size(min = 0, max = 200, message = "路由地址不能超过200个字符")
+    public String getPath() {
+        return path;
+    }
+
+    public void setPath(String path) {
+        this.path = path;
+    }
+
+    @Size(min = 0, max = 200, message = "组件路径不能超过255个字符")
+    public String getComponent() {
+        return component;
+    }
+
+    public void setComponent(String component) {
+        this.component = component;
+    }
+
+    public String getQuery() {
+        return query;
+    }
+
+    public void setQuery(String query) {
+        this.query = query;
+    }
+
+    public String getRouteName() {
+        return routeName;
+    }
+
+    public void setRouteName(String routeName) {
+        this.routeName = routeName;
+    }
+
+    public String getIsFrame() {
+        return isFrame;
+    }
+
+    public void setIsFrame(String isFrame) {
+        this.isFrame = isFrame;
+    }
+
+    public String getIsCache() {
+        return isCache;
+    }
+
+    public void setIsCache(String isCache) {
+        this.isCache = isCache;
+    }
+
+    @NotBlank(message = "菜单类型不能为空")
+    public String getMenuType() {
+        return menuType;
+    }
+
+    public void setMenuType(String menuType) {
+        this.menuType = menuType;
+    }
+
+    public String getVisible() {
+        return visible;
+    }
+
+    public void setVisible(String visible) {
+        this.visible = visible;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    @Size(min = 0, max = 100, message = "权限标识长度不能超过100个字符")
+    public String getPerms() {
+        return perms;
+    }
+
+    public void setPerms(String perms) {
+        this.perms = perms;
+    }
+
+    public String getIcon() {
+        return icon;
+    }
+
+    public void setIcon(String icon) {
+        this.icon = icon;
+    }
+
+    public List<SysMenu> getChildren() {
+        return children;
+    }
+
+    public void setChildren(List<SysMenu> children) {
+        this.children = children;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+                .append("menuId", getMenuId())
+                .append("menuName", getMenuName())
+                .append("parentId", getParentId())
+                .append("orderNum", getOrderNum())
+                .append("path", getPath())
+                .append("component", getComponent())
+                .append("query", getQuery())
+                .append("routeName", getRouteName())
+                .append("isFrame", getIsFrame())
+                .append("IsCache", getIsCache())
+                .append("menuType", getMenuType())
+                .append("visible", getVisible())
+                .append("status ", getStatus())
+                .append("perms", getPerms())
+                .append("icon", getIcon())
+                .append("createBy", getCreateBy())
+                .append("createTime", getCreateTime())
+                .append("updateBy", getUpdateBy())
+                .append("updateTime", getUpdateTime())
+                .append("remark", getRemark())
+                .toString();
+    }
+}

+ 245 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/core/domain/entity/SysRole.java

@@ -0,0 +1,245 @@
+package com.lij.himeeter.common.core.domain.entity;
+
+import com.lij.himeeter.common.annotation.Excel;
+import com.lij.himeeter.common.annotation.Excel.ColumnType;
+import com.lij.himeeter.common.core.domain.BaseEntity;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.util.Set;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SysRole
+ * 创建时间 : 2024年12月26日 18:51
+ *
+ * 文件描述 : 无
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class SysRole extends BaseEntity {
+
+    /**
+     * 角色ID
+     */
+    @Excel(name = "角色序号", cellType = ColumnType.NUMERIC)
+    private Long roleId;
+
+    /**
+     * 角色名称
+     */
+    @Excel(name = "角色名称")
+    private String roleName;
+
+    /**
+     * 角色权限
+     */
+    @Excel(name = "角色权限")
+    private String roleKey;
+
+    /**
+     * 角色排序
+     */
+    @Excel(name = "角色排序")
+    private Integer roleSort;
+
+    /**
+     * 数据范围(1:所有数据权限;2:自定义数据权限;3:本部门数据权限;4:本部门及以下数据权限;5:仅本人数据权限)
+     */
+    @Excel(name = "数据范围", readConverterExp = "1=所有数据权限,2=自定义数据权限,3=本部门数据权限,4=本部门及以下数据权限,5=仅本人数据权限")
+    private String dataScope;
+
+    /**
+     * 菜单树选择项是否关联显示( 0:父子不互相关联显示 1:父子互相关联显示)
+     */
+    private boolean menuCheckStrictly;
+
+    /**
+     * 部门树选择项是否关联显示(0:父子不互相关联显示 1:父子互相关联显示 )
+     */
+    private boolean deptCheckStrictly;
+
+    /**
+     * 角色状态(0正常 1停用)
+     */
+    @Excel(name = "角色状态", readConverterExp = "0=正常,1=停用")
+    private String status;
+
+    /**
+     * 删除标志(0代表存在 2代表删除)
+     */
+    private String delFlag;
+
+    /**
+     * 用户是否存在此角色标识 默认不存在
+     */
+    private boolean flag = false;
+
+    /**
+     * 菜单组
+     */
+    private Long[] menuIds;
+
+    /**
+     * 部门组(数据权限)
+     */
+    private Long[] deptIds;
+
+    /**
+     * 角色菜单权限
+     */
+    private Set<String> permissions;
+
+    public SysRole() {
+
+    }
+
+    public SysRole(Long roleId) {
+        this.roleId = roleId;
+    }
+
+    public Long getRoleId() {
+        return roleId;
+    }
+
+    public void setRoleId(Long roleId) {
+        this.roleId = roleId;
+    }
+
+    public boolean isAdmin() {
+        return isAdmin(this.roleId);
+    }
+
+    public static boolean isAdmin(Long roleId) {
+        return roleId != null && 1L == roleId;
+    }
+
+    @NotBlank(message = "角色名称不能为空")
+    @Size(min = 0, max = 30, message = "角色名称长度不能超过30个字符")
+    public String getRoleName() {
+        return roleName;
+    }
+
+    public void setRoleName(String roleName) {
+        this.roleName = roleName;
+    }
+
+    @NotBlank(message = "权限字符不能为空")
+    @Size(min = 0, max = 100, message = "权限字符长度不能超过100个字符")
+    public String getRoleKey() {
+        return roleKey;
+    }
+
+    public void setRoleKey(String roleKey) {
+        this.roleKey = roleKey;
+    }
+
+    @NotNull(message = "显示顺序不能为空")
+    public Integer getRoleSort() {
+        return roleSort;
+    }
+
+    public void setRoleSort(Integer roleSort) {
+        this.roleSort = roleSort;
+    }
+
+    public String getDataScope() {
+        return dataScope;
+    }
+
+    public void setDataScope(String dataScope) {
+        this.dataScope = dataScope;
+    }
+
+    public boolean isMenuCheckStrictly() {
+        return menuCheckStrictly;
+    }
+
+    public void setMenuCheckStrictly(boolean menuCheckStrictly) {
+        this.menuCheckStrictly = menuCheckStrictly;
+    }
+
+    public boolean isDeptCheckStrictly() {
+        return deptCheckStrictly;
+    }
+
+    public void setDeptCheckStrictly(boolean deptCheckStrictly) {
+        this.deptCheckStrictly = deptCheckStrictly;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public String getDelFlag() {
+        return delFlag;
+    }
+
+    public void setDelFlag(String delFlag) {
+        this.delFlag = delFlag;
+    }
+
+    public boolean isFlag() {
+        return flag;
+    }
+
+    public void setFlag(boolean flag) {
+        this.flag = flag;
+    }
+
+    public Long[] getMenuIds() {
+        return menuIds;
+    }
+
+    public void setMenuIds(Long[] menuIds) {
+        this.menuIds = menuIds;
+    }
+
+    public Long[] getDeptIds() {
+        return deptIds;
+    }
+
+    public void setDeptIds(Long[] deptIds) {
+        this.deptIds = deptIds;
+    }
+
+    public Set<String> getPermissions() {
+        return permissions;
+    }
+
+    public void setPermissions(Set<String> permissions) {
+        this.permissions = permissions;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+                .append("roleId", getRoleId())
+                .append("roleName", getRoleName())
+                .append("roleKey", getRoleKey())
+                .append("roleSort", getRoleSort())
+                .append("dataScope", getDataScope())
+                .append("menuCheckStrictly", isMenuCheckStrictly())
+                .append("deptCheckStrictly", isDeptCheckStrictly())
+                .append("status", getStatus())
+                .append("delFlag", getDelFlag())
+                .append("createBy", getCreateBy())
+                .append("createTime", getCreateTime())
+                .append("updateBy", getUpdateBy())
+                .append("updateTime", getUpdateTime())
+                .append("remark", getRemark())
+                .toString();
+    }
+}

+ 335 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/core/domain/entity/SysUser.java

@@ -0,0 +1,335 @@
+package com.lij.himeeter.common.core.domain.entity;
+
+import com.lij.himeeter.common.annotation.Excel;
+import com.lij.himeeter.common.annotation.Excel.Type;
+import com.lij.himeeter.common.annotation.Excel.ColumnType;
+import com.lij.himeeter.common.annotation.Excels;
+import com.lij.himeeter.common.core.domain.BaseEntity;
+import com.lij.himeeter.common.xss.Xss;
+import jakarta.validation.constraints.Email;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.Size;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SysUser
+ * 创建时间 : 2024年12月26日 18:41
+ *
+ * 文件描述 : 用户对象 sys_user
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class SysUser extends BaseEntity {
+    private static final long serialVersionUID = 1L;
+
+    /** 用户ID */
+    @Excel(name = "用户序号", type = Type.EXPORT, cellType = ColumnType.NUMERIC, prompt = "用户编号")
+    private Long userId;
+
+    /** 部门ID */
+    @Excel(name = "部门编号", type = Type.IMPORT)
+    private Long deptId;
+
+    /** 用户账号 */
+    @Excel(name = "登录名称")
+    private String userName;
+
+    /** 用户昵称 */
+    @Excel(name = "用户名称")
+    private String nickName;
+
+    /** 用户邮箱 */
+    @Excel(name = "用户邮箱")
+    private String email;
+
+    /** 手机号码 */
+    @Excel(name = "手机号码", cellType = ColumnType.TEXT)
+    private String phonenumber;
+
+    /** 用户性别 */
+    @Excel(name = "用户性别", readConverterExp = "0=男,1=女,2=未知")
+    private String sex;
+
+    /** 用户头像 */
+    private String avatar;
+
+    /** 密码 */
+    private String password;
+
+    /** 帐号状态(0正常 1停用) */
+    @Excel(name = "帐号状态", readConverterExp = "0=正常,1=停用")
+    private String status;
+
+    /** 删除标志(0代表存在 2代表删除) */
+    private String delFlag;
+
+    /** 最后登录IP */
+    @Excel(name = "最后登录IP", type = Type.EXPORT)
+    private String loginIp;
+
+    /** 最后登录时间 */
+    @Excel(name = "最后登录时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", type = Type.EXPORT)
+    private Date loginDate;
+
+    /** 部门对象 */
+    @Excels({
+            @Excel(name = "部门名称", targetAttr = "deptName", type = Type.EXPORT),
+            @Excel(name = "部门负责人", targetAttr = "leader", type = Type.EXPORT)
+    })
+    private SysDept dept;
+
+    /** 角色对象 */
+    private List<SysRole> roles;
+
+    /** 角色组 */
+    private Long[] roleIds;
+
+    /** 岗位组 */
+    private Long[] postIds;
+
+    /** 角色ID */
+    private Long roleId;
+
+    public SysUser()
+    {
+
+    }
+
+    public SysUser(Long userId)
+    {
+        this.userId = userId;
+    }
+
+    public Long getUserId()
+    {
+        return userId;
+    }
+
+    public void setUserId(Long userId)
+    {
+        this.userId = userId;
+    }
+
+    public boolean isAdmin()
+    {
+        return isAdmin(this.userId);
+    }
+
+    public static boolean isAdmin(Long userId)
+    {
+        return userId != null && 1L == userId;
+    }
+
+    public Long getDeptId()
+    {
+        return deptId;
+    }
+
+    public void setDeptId(Long deptId)
+    {
+        this.deptId = deptId;
+    }
+
+    @Xss(message = "用户昵称不能包含脚本字符")
+    @Size(min = 0, max = 30, message = "用户昵称长度不能超过30个字符")
+    public String getNickName()
+    {
+        return nickName;
+    }
+
+    public void setNickName(String nickName)
+    {
+        this.nickName = nickName;
+    }
+
+    @Xss(message = "用户账号不能包含脚本字符")
+    @NotBlank(message = "用户账号不能为空")
+    @Size(min = 0, max = 30, message = "用户账号长度不能超过30个字符")
+    public String getUserName()
+    {
+        return userName;
+    }
+
+    public void setUserName(String userName)
+    {
+        this.userName = userName;
+    }
+
+    @Email(message = "邮箱格式不正确")
+    @Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符")
+    public String getEmail()
+    {
+        return email;
+    }
+
+    public void setEmail(String email)
+    {
+        this.email = email;
+    }
+
+    @Size(min = 0, max = 11, message = "手机号码长度不能超过11个字符")
+    public String getPhonenumber()
+    {
+        return phonenumber;
+    }
+
+    public void setPhonenumber(String phonenumber)
+    {
+        this.phonenumber = phonenumber;
+    }
+
+    public String getSex()
+    {
+        return sex;
+    }
+
+    public void setSex(String sex)
+    {
+        this.sex = sex;
+    }
+
+    public String getAvatar()
+    {
+        return avatar;
+    }
+
+    public void setAvatar(String avatar)
+    {
+        this.avatar = avatar;
+    }
+
+    public String getPassword()
+    {
+        return password;
+    }
+
+    public void setPassword(String password)
+    {
+        this.password = password;
+    }
+
+    public String getStatus()
+    {
+        return status;
+    }
+
+    public void setStatus(String status)
+    {
+        this.status = status;
+    }
+
+    public String getDelFlag()
+    {
+        return delFlag;
+    }
+
+    public void setDelFlag(String delFlag)
+    {
+        this.delFlag = delFlag;
+    }
+
+    public String getLoginIp()
+    {
+        return loginIp;
+    }
+
+    public void setLoginIp(String loginIp)
+    {
+        this.loginIp = loginIp;
+    }
+
+    public Date getLoginDate()
+    {
+        return loginDate;
+    }
+
+    public void setLoginDate(Date loginDate)
+    {
+        this.loginDate = loginDate;
+    }
+
+    public SysDept getDept()
+    {
+        return dept;
+    }
+
+    public void setDept(SysDept dept)
+    {
+        this.dept = dept;
+    }
+
+    public List<SysRole> getRoles()
+    {
+        return roles;
+    }
+
+    public void setRoles(List<SysRole> roles)
+    {
+        this.roles = roles;
+    }
+
+    public Long[] getRoleIds()
+    {
+        return roleIds;
+    }
+
+    public void setRoleIds(Long[] roleIds)
+    {
+        this.roleIds = roleIds;
+    }
+
+    public Long[] getPostIds()
+    {
+        return postIds;
+    }
+
+    public void setPostIds(Long[] postIds)
+    {
+        this.postIds = postIds;
+    }
+
+    public Long getRoleId()
+    {
+        return roleId;
+    }
+
+    public void setRoleId(Long roleId)
+    {
+        this.roleId = roleId;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+                .append("userId", getUserId())
+                .append("deptId", getDeptId())
+                .append("userName", getUserName())
+                .append("nickName", getNickName())
+                .append("email", getEmail())
+                .append("phonenumber", getPhonenumber())
+                .append("sex", getSex())
+                .append("avatar", getAvatar())
+                .append("password", getPassword())
+                .append("status", getStatus())
+                .append("delFlag", getDelFlag())
+                .append("loginIp", getLoginIp())
+                .append("loginDate", getLoginDate())
+                .append("createBy", getCreateBy())
+                .append("createTime", getCreateTime())
+                .append("updateBy", getUpdateBy())
+                .append("updateTime", getUpdateTime())
+                .append("remark", getRemark())
+                .append("dept", getDept())
+                .toString();
+    }
+}

+ 70 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/core/domain/model/LoginBody.java

@@ -0,0 +1,70 @@
+package com.lij.himeeter.common.core.domain.model;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  LoginBody
+ * 创建时间 : 2024年12月27日 15:31
+ *
+ * 文件描述 : 用户登录对象
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class LoginBody {
+
+    /**
+     * 用户名
+     */
+    private String username;
+
+    /**
+     * 用户密码
+     */
+    private String password;
+
+    /**
+     * 验证码
+     */
+    private String code;
+
+    /**
+     * 唯一标识
+     */
+    private String uuid;
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public String getUuid() {
+        return uuid;
+    }
+
+    public void setUuid(String uuid) {
+        this.uuid = uuid;
+    }
+}

+ 276 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/core/domain/model/LoginUser.java

@@ -0,0 +1,276 @@
+package com.lij.himeeter.common.core.domain.model;
+
+import com.alibaba.fastjson2.annotation.JSONField;
+import com.lij.himeeter.common.core.domain.entity.SysUser;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+
+import java.util.Collection;
+import java.util.Set;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  LoginUser
+ * 创建时间 : 2024年12月26日 18:01
+ *
+ * 文件描述 : 登录用户身份权限
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class LoginUser implements UserDetails {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 用户ID
+     */
+    private Long userId;
+
+    /**
+     * 部门ID
+     */
+    private Long deptId;
+
+    /**
+     * 用户唯一标识
+     */
+    private String token;
+
+    /**
+     * 登录时间
+     */
+    private Long loginTime;
+
+    /**
+     * 过期时间
+     */
+    private Long expireTime;
+
+    /**
+     * 登录IP地址
+     */
+    private String ipaddr;
+
+    /**
+     * 登录地点
+     */
+    private String loginLocation;
+
+    /**
+     * 浏览器类型
+     */
+    private String browser;
+
+    /**
+     * 操作系统
+     */
+    private String os;
+
+    /**
+     * 权限列表
+     */
+    private Set<String> permissions;
+
+    /**
+     * 用户信息
+     */
+    private SysUser user;
+
+    public LoginUser()
+    {
+    }
+
+    public LoginUser(SysUser user, Set<String> permissions)
+    {
+        this.user = user;
+        this.permissions = permissions;
+    }
+
+    public LoginUser(Long userId, Long deptId, SysUser user, Set<String> permissions)
+    {
+        this.userId = userId;
+        this.deptId = deptId;
+        this.user = user;
+        this.permissions = permissions;
+    }
+
+    public Long getUserId()
+    {
+        return userId;
+    }
+
+    public void setUserId(Long userId)
+    {
+        this.userId = userId;
+    }
+
+    public Long getDeptId()
+    {
+        return deptId;
+    }
+
+    public void setDeptId(Long deptId)
+    {
+        this.deptId = deptId;
+    }
+
+    public String getToken()
+    {
+        return token;
+    }
+
+    public void setToken(String token)
+    {
+        this.token = token;
+    }
+
+    @JSONField(serialize = false)
+    @Override
+    public String getPassword()
+    {
+        return user.getPassword();
+    }
+
+    @Override
+    public String getUsername()
+    {
+        return user.getUserName();
+    }
+
+    /**
+     * 账户是否未过期,过期无法验证
+     */
+    @JSONField(serialize = false)
+    @Override
+    public boolean isAccountNonExpired()
+    {
+        return true;
+    }
+
+    /**
+     * 指定用户是否解锁,锁定的用户无法进行身份验证
+     *
+     * @return
+     */
+    @JSONField(serialize = false)
+    @Override
+    public boolean isAccountNonLocked()
+    {
+        return true;
+    }
+
+    /**
+     * 指示是否已过期的用户的凭据(密码),过期的凭据防止认证
+     *
+     * @return
+     */
+    @JSONField(serialize = false)
+    @Override
+    public boolean isCredentialsNonExpired()
+    {
+        return true;
+    }
+
+    /**
+     * 是否可用 ,禁用的用户不能身份验证
+     *
+     * @return
+     */
+    @JSONField(serialize = false)
+    @Override
+    public boolean isEnabled()
+    {
+        return true;
+    }
+
+    public Long getLoginTime()
+    {
+        return loginTime;
+    }
+
+    public void setLoginTime(Long loginTime)
+    {
+        this.loginTime = loginTime;
+    }
+
+    public String getIpaddr()
+    {
+        return ipaddr;
+    }
+
+    public void setIpaddr(String ipaddr)
+    {
+        this.ipaddr = ipaddr;
+    }
+
+    public String getLoginLocation()
+    {
+        return loginLocation;
+    }
+
+    public void setLoginLocation(String loginLocation)
+    {
+        this.loginLocation = loginLocation;
+    }
+
+    public String getBrowser()
+    {
+        return browser;
+    }
+
+    public void setBrowser(String browser)
+    {
+        this.browser = browser;
+    }
+
+    public String getOs()
+    {
+        return os;
+    }
+
+    public void setOs(String os)
+    {
+        this.os = os;
+    }
+
+    public Long getExpireTime()
+    {
+        return expireTime;
+    }
+
+    public void setExpireTime(Long expireTime)
+    {
+        this.expireTime = expireTime;
+    }
+
+    public Set<String> getPermissions()
+    {
+        return permissions;
+    }
+
+    public void setPermissions(Set<String> permissions)
+    {
+        this.permissions = permissions;
+    }
+
+    public SysUser getUser()
+    {
+        return user;
+    }
+
+    public void setUser(SysUser user)
+    {
+        this.user = user;
+    }
+
+    @Override
+    public Collection<? extends GrantedAuthority> getAuthorities()
+    {
+        return null;
+    }
+
+}

+ 18 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/core/domain/model/RegisterBody.java

@@ -0,0 +1,18 @@
+package com.lij.himeeter.common.core.domain.model;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  RegisterBody
+ * 创建时间 : 2024年12月27日 15:32
+ *
+ * 文件描述 : 用户注册对象
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class RegisterBody extends LoginBody{
+}

+ 101 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/core/text/CharsetKit.java

@@ -0,0 +1,101 @@
+package com.lij.himeeter.common.core.text;
+
+import com.lij.himeeter.common.utils.StringUtils;
+
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  CharsetKit
+ * 创建时间 : 2024年12月26日 17:44
+ *
+ * 文件描述 : 无
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class CharsetKit {
+
+    /**
+     * ISO-8859-1
+     */
+    public static final String ISO_8859_1 = "ISO-8859-1";
+    /**
+     * UTF-8
+     */
+    public static final String UTF_8 = "UTF-8";
+    /**
+     * GBK
+     */
+    public static final String GBK = "GBK";
+
+    /**
+     * ISO-8859-1
+     */
+    public static final Charset CHARSET_ISO_8859_1 = Charset.forName(ISO_8859_1);
+    /**
+     * UTF-8
+     */
+    public static final Charset CHARSET_UTF_8 = Charset.forName(UTF_8);
+    /**
+     * GBK
+     */
+    public static final Charset CHARSET_GBK = Charset.forName(GBK);
+
+    /**
+     * 转换为Charset对象
+     *
+     * @param charset 字符集,为空则返回默认字符集
+     * @return Charset
+     */
+    public static Charset charset(String charset) {
+        return StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset);
+    }
+
+    /**
+     * 转换字符串的字符集编码
+     *
+     * @param source      字符串
+     * @param srcCharset  源字符集,默认ISO-8859-1
+     * @param destCharset 目标字符集,默认UTF-8
+     * @return 转换后的字符集
+     */
+    public static String convert(String source, String srcCharset, String destCharset) {
+        return convert(source, Charset.forName(srcCharset), Charset.forName(destCharset));
+    }
+
+    /**
+     * 转换字符串的字符集编码
+     *
+     * @param source      字符串
+     * @param srcCharset  源字符集,默认ISO-8859-1
+     * @param destCharset 目标字符集,默认UTF-8
+     * @return 转换后的字符集
+     */
+    public static String convert(String source, Charset srcCharset, Charset destCharset) {
+        if (null == srcCharset) {
+            srcCharset = StandardCharsets.ISO_8859_1;
+        }
+
+        if (null == destCharset) {
+            destCharset = StandardCharsets.UTF_8;
+        }
+
+        if (StringUtils.isEmpty(source) || srcCharset.equals(destCharset)) {
+            return source;
+        }
+        return new String(source.getBytes(srcCharset), destCharset);
+    }
+
+    /**
+     * @return 系统字符集编码
+     */
+    public static String systemCharset() {
+        return Charset.defaultCharset().name();
+    }
+}

+ 860 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/core/text/Convert.java

@@ -0,0 +1,860 @@
+package com.lij.himeeter.common.core.text;
+
+import com.lij.himeeter.common.utils.StringUtils;
+import org.apache.commons.lang3.ArrayUtils;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.math.RoundingMode;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.text.NumberFormat;
+import java.util.Set;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  Convert
+ * 创建时间 : 2024年12月26日 17:21
+ *
+ * 文件描述 : 类型转换器
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class Convert {
+
+    /**
+     * 转换为字符串<br>
+     * 如果给定的值为null,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value        被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static String toStr(Object value, String defaultValue) {
+        if (null == value) {
+            return defaultValue;
+        }
+        if (value instanceof String) {
+            return (String) value;
+        }
+        return value.toString();
+    }
+
+    /**
+     * 转换为字符串<br>
+     * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static String toStr(Object value) {
+        return toStr(value, null);
+    }
+
+    /**
+     * 转换为字符<br>
+     * 如果给定的值为null,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value        被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static Character toChar(Object value, Character defaultValue) {
+        if (null == value) {
+            return defaultValue;
+        }
+        if (value instanceof Character) {
+            return (Character) value;
+        }
+
+        final String valueStr = toStr(value, null);
+        return StringUtils.isEmpty(valueStr) ? defaultValue : valueStr.charAt(0);
+    }
+
+    /**
+     * 转换为字符<br>
+     * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Character toChar(Object value) {
+        return toChar(value, null);
+    }
+
+    /**
+     * 转换为byte<br>
+     * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value        被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static Byte toByte(Object value, Byte defaultValue) {
+        if (value == null) {
+            return defaultValue;
+        }
+        if (value instanceof Byte) {
+            return (Byte) value;
+        }
+        if (value instanceof Number) {
+            return ((Number) value).byteValue();
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr)) {
+            return defaultValue;
+        }
+        try {
+            return Byte.parseByte(valueStr);
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为byte<br>
+     * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Byte toByte(Object value) {
+        return toByte(value, null);
+    }
+
+    /**
+     * 转换为Short<br>
+     * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value        被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static Short toShort(Object value, Short defaultValue) {
+        if (value == null) {
+            return defaultValue;
+        }
+        if (value instanceof Short) {
+            return (Short) value;
+        }
+        if (value instanceof Number) {
+            return ((Number) value).shortValue();
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr)) {
+            return defaultValue;
+        }
+        try {
+            return Short.parseShort(valueStr.trim());
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为Short<br>
+     * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Short toShort(Object value) {
+        return toShort(value, null);
+    }
+
+    /**
+     * 转换为Number<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value        被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static Number toNumber(Object value, Number defaultValue) {
+        if (value == null) {
+            return defaultValue;
+        }
+        if (value instanceof Number) {
+            return (Number) value;
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr)) {
+            return defaultValue;
+        }
+        try {
+            return NumberFormat.getInstance().parse(valueStr);
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为Number<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Number toNumber(Object value) {
+        return toNumber(value, null);
+    }
+
+    /**
+     * 转换为int<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value        被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static Integer toInt(Object value, Integer defaultValue) {
+        if (value == null) {
+            return defaultValue;
+        }
+        if (value instanceof Integer) {
+            return (Integer) value;
+        }
+        if (value instanceof Number) {
+            return ((Number) value).intValue();
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr)) {
+            return defaultValue;
+        }
+        try {
+            return Integer.parseInt(valueStr.trim());
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为int<br>
+     * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Integer toInt(Object value) {
+        return toInt(value, null);
+    }
+
+    /**
+     * 转换为Integer数组<br>
+     *
+     * @param str 被转换的值
+     * @return 结果
+     */
+    public static Integer[] toIntArray(String str) {
+        return toIntArray(",", str);
+    }
+
+    /**
+     * 转换为Long数组<br>
+     *
+     * @param str 被转换的值
+     * @return 结果
+     */
+    public static Long[] toLongArray(String str) {
+        return toLongArray(",", str);
+    }
+
+    /**
+     * 转换为Integer数组<br>
+     *
+     * @param split 分隔符
+     * @param str   被转换的值
+     * @return 结果
+     */
+    public static Integer[] toIntArray(String split, String str) {
+        if (StringUtils.isEmpty(str)) {
+            return new Integer[]{};
+        }
+        String[] arr = str.split(split);
+        final Integer[] ints = new Integer[arr.length];
+        for (int i = 0; i < arr.length; i++) {
+            final Integer v = toInt(arr[i], 0);
+            ints[i] = v;
+        }
+        return ints;
+    }
+
+    /**
+     * 转换为Long数组<br>
+     *
+     * @param split 分隔符
+     * @param str   被转换的值
+     * @return 结果
+     */
+    public static Long[] toLongArray(String split, String str) {
+        if (StringUtils.isEmpty(str)) {
+            return new Long[]{};
+        }
+        String[] arr = str.split(split);
+        final Long[] longs = new Long[arr.length];
+        for (int i = 0; i < arr.length; i++) {
+            final Long v = toLong(arr[i], null);
+            longs[i] = v;
+        }
+        return longs;
+    }
+
+    /**
+     * 转换为String数组<br>
+     *
+     * @param str 被转换的值
+     * @return 结果
+     */
+    public static String[] toStrArray(String str) {
+        if (StringUtils.isEmpty(str)) {
+            return new String[]{};
+        }
+        return toStrArray(",", str);
+    }
+
+    /**
+     * 转换为String数组<br>
+     *
+     * @param split 分隔符
+     * @param str   被转换的值
+     * @return 结果
+     */
+    public static String[] toStrArray(String split, String str) {
+        return str.split(split);
+    }
+
+    /**
+     * 转换为long<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value        被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static Long toLong(Object value, Long defaultValue) {
+        if (value == null) {
+            return defaultValue;
+        }
+        if (value instanceof Long) {
+            return (Long) value;
+        }
+        if (value instanceof Number) {
+            return ((Number) value).longValue();
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr)) {
+            return defaultValue;
+        }
+        try {
+            // 支持科学计数法
+            return new BigDecimal(valueStr.trim()).longValue();
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为long<br>
+     * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Long toLong(Object value) {
+        return toLong(value, null);
+    }
+
+    /**
+     * 转换为double<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value        被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static Double toDouble(Object value, Double defaultValue) {
+        if (value == null) {
+            return defaultValue;
+        }
+        if (value instanceof Double) {
+            return (Double) value;
+        }
+        if (value instanceof Number) {
+            return ((Number) value).doubleValue();
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr)) {
+            return defaultValue;
+        }
+        try {
+            // 支持科学计数法
+            return new BigDecimal(valueStr.trim()).doubleValue();
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为double<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Double toDouble(Object value) {
+        return toDouble(value, null);
+    }
+
+    /**
+     * 转换为Float<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value        被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static Float toFloat(Object value, Float defaultValue) {
+        if (value == null) {
+            return defaultValue;
+        }
+        if (value instanceof Float) {
+            return (Float) value;
+        }
+        if (value instanceof Number) {
+            return ((Number) value).floatValue();
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr)) {
+            return defaultValue;
+        }
+        try {
+            return Float.parseFloat(valueStr.trim());
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为Float<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Float toFloat(Object value) {
+        return toFloat(value, null);
+    }
+
+    /**
+     * 转换为boolean<br>
+     * String支持的值为:true、false、yes、ok、no,1,0 如果给定的值为空,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value        被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static Boolean toBool(Object value, Boolean defaultValue) {
+        if (value == null) {
+            return defaultValue;
+        }
+        if (value instanceof Boolean) {
+            return (Boolean) value;
+        }
+        String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr)) {
+            return defaultValue;
+        }
+        valueStr = valueStr.trim().toLowerCase();
+        return switch (valueStr) {
+            case "true", "yes", "ok", "1" -> true;
+            case "false", "no", "0" -> false;
+            default -> defaultValue;
+        };
+    }
+
+    /**
+     * 转换为boolean<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Boolean toBool(Object value) {
+        return toBool(value, null);
+    }
+
+    /**
+     * 转换为Enum对象<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<br>
+     *
+     * @param clazz        Enum的Class
+     * @param value        值
+     * @param defaultValue 默认值
+     * @return Enum
+     */
+    public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value, E defaultValue) {
+        if (value == null) {
+            return defaultValue;
+        }
+        if (clazz.isAssignableFrom(value.getClass())) {
+            @SuppressWarnings("unchecked")
+            E myE = (E) value;
+            return myE;
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr)) {
+            return defaultValue;
+        }
+        try {
+            return Enum.valueOf(clazz, valueStr);
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为Enum对象<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
+     *
+     * @param clazz Enum的Class
+     * @param value 值
+     * @return Enum
+     */
+    public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value) {
+        return toEnum(clazz, value, null);
+    }
+
+    /**
+     * 转换为BigInteger<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value        被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static BigInteger toBigInteger(Object value, BigInteger defaultValue) {
+        if (value == null) {
+            return defaultValue;
+        }
+        if (value instanceof BigInteger) {
+            return (BigInteger) value;
+        }
+        if (value instanceof Long) {
+            return BigInteger.valueOf((Long) value);
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr)) {
+            return defaultValue;
+        }
+        try {
+            return new BigInteger(valueStr);
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为BigInteger<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static BigInteger toBigInteger(Object value) {
+        return toBigInteger(value, null);
+    }
+
+    /**
+     * 转换为BigDecimal<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value        被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static BigDecimal toBigDecimal(Object value, BigDecimal defaultValue) {
+        if (value == null) {
+            return defaultValue;
+        }
+        if (value instanceof BigDecimal) {
+            return (BigDecimal) value;
+        }
+        if (value instanceof Long) {
+            return new BigDecimal((Long) value);
+        }
+        if (value instanceof Double) {
+            return BigDecimal.valueOf((Double) value);
+        }
+        if (value instanceof Integer) {
+            return new BigDecimal((Integer) value);
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr)) {
+            return defaultValue;
+        }
+        try {
+            return new BigDecimal(valueStr);
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为BigDecimal<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static BigDecimal toBigDecimal(Object value) {
+        return toBigDecimal(value, null);
+    }
+
+    /**
+     * 将对象转为字符串<br>
+     * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法
+     *
+     * @param obj 对象
+     * @return 字符串
+     */
+    public static String utf8Str(Object obj) {
+        return str(obj, CharsetKit.CHARSET_UTF_8);
+    }
+
+    /**
+     * 将对象转为字符串<br>
+     * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法
+     *
+     * @param obj         对象
+     * @param charsetName 字符集
+     * @return 字符串
+     */
+    public static String str(Object obj, String charsetName) {
+        return str(obj, Charset.forName(charsetName));
+    }
+
+    /**
+     * 将对象转为字符串<br>
+     * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法
+     *
+     * @param obj     对象
+     * @param charset 字符集
+     * @return 字符串
+     */
+    public static String str(Object obj, Charset charset) {
+        if (null == obj) {
+            return null;
+        }
+
+        if (obj instanceof String) {
+            return (String) obj;
+        } else if (obj instanceof byte[]) {
+            return str((byte[]) obj, charset);
+        } else if (obj instanceof Byte[]) {
+            byte[] bytes = ArrayUtils.toPrimitive((Byte[]) obj);
+            return str(bytes, charset);
+        } else if (obj instanceof ByteBuffer) {
+            return str((ByteBuffer) obj, charset);
+        }
+        return obj.toString();
+    }
+
+    /**
+     * 将byte数组转为字符串
+     *
+     * @param bytes   byte数组
+     * @param charset 字符集
+     * @return 字符串
+     */
+    public static String str(byte[] bytes, String charset) {
+        return str(bytes, StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset));
+    }
+
+    /**
+     * 解码字节码
+     *
+     * @param data    字符串
+     * @param charset 字符集,如果此字段为空,则解码的结果取决于平台
+     * @return 解码后的字符串
+     */
+    public static String str(byte[] data, Charset charset) {
+        if (data == null) {
+            return null;
+        }
+
+        if (null == charset) {
+            return new String(data);
+        }
+        return new String(data, charset);
+    }
+
+    /**
+     * 将编码的byteBuffer数据转换为字符串
+     *
+     * @param data    数据
+     * @param charset 字符集,如果为空使用当前系统字符集
+     * @return 字符串
+     */
+    public static String str(ByteBuffer data, String charset) {
+        if (data == null) {
+            return null;
+        }
+
+        return str(data, Charset.forName(charset));
+    }
+
+    /**
+     * 将编码的byteBuffer数据转换为字符串
+     *
+     * @param data    数据
+     * @param charset 字符集,如果为空使用当前系统字符集
+     * @return 字符串
+     */
+    public static String str(ByteBuffer data, Charset charset) {
+        if (null == charset) {
+            charset = Charset.defaultCharset();
+        }
+        return charset.decode(data).toString();
+    }
+
+    // ----------------------------------------------------------------------- 全角半角转换
+
+    /**
+     * 半角转全角
+     *
+     * @param input String.
+     * @return 全角字符串.
+     */
+    public static String toSBC(String input) {
+        return toSBC(input, null);
+    }
+
+    /**
+     * 半角转全角
+     *
+     * @param input         String
+     * @param notConvertSet 不替换的字符集合
+     * @return 全角字符串.
+     */
+    public static String toSBC(String input, Set<Character> notConvertSet) {
+        char[] c = input.toCharArray();
+        for (int i = 0; i < c.length; i++) {
+            if (null != notConvertSet && notConvertSet.contains(c[i])) {
+                // 跳过不替换的字符
+                continue;
+            }
+
+            if (c[i] == ' ') {
+                c[i] = '\u3000';
+            } else if (c[i] < '\177') {
+                c[i] = (char) (c[i] + 65248);
+
+            }
+        }
+        return new String(c);
+    }
+
+    /**
+     * 全角转半角
+     *
+     * @param input String.
+     * @return 半角字符串
+     */
+    public static String toDBC(String input) {
+        return toDBC(input, null);
+    }
+
+    /**
+     * 替换全角为半角
+     *
+     * @param text          文本
+     * @param notConvertSet 不替换的字符集合
+     * @return 替换后的字符
+     */
+    public static String toDBC(String text, Set<Character> notConvertSet) {
+        char[] c = text.toCharArray();
+        for (int i = 0; i < c.length; i++) {
+            if (null != notConvertSet && notConvertSet.contains(c[i])) {
+                // 跳过不替换的字符
+                continue;
+            }
+
+            if (c[i] == '\u3000') {
+                c[i] = ' ';
+            } else if (c[i] > '\uFF00' && c[i] < '\uFF5F') {
+                c[i] = (char) (c[i] - 65248);
+            }
+        }
+        String returnString = new String(c);
+
+        return returnString;
+    }
+
+    /**
+     * 数字金额大写转换 先写个完整的然后将如零拾替换成零
+     *
+     * @param n 数字
+     * @return 中文大写数字
+     */
+    public static String digitUppercase(double n) {
+        String[] fraction = {"角", "分"};
+        String[] digit = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};
+        String[][] unit = {{"元", "万", "亿"}, {"", "拾", "佰", "仟"}};
+
+        String head = n < 0 ? "负" : "";
+        n = Math.abs(n);
+
+        String s = "";
+        for (int i = 0; i < fraction.length; i++) {
+            // 优化double计算精度丢失问题
+            BigDecimal nNum = new BigDecimal(n);
+            BigDecimal decimal = new BigDecimal(10);
+            BigDecimal scale = nNum.multiply(decimal).setScale(2, RoundingMode.HALF_EVEN);
+            double d = scale.doubleValue();
+            s += (digit[(int) (Math.floor(d * Math.pow(10, i)) % 10)] + fraction[i]).replaceAll("(零.)+", "");
+        }
+        if (s.length() < 1) {
+            s = "整";
+        }
+        int integerPart = (int) Math.floor(n);
+
+        for (int i = 0; i < unit[0].length && integerPart > 0; i++) {
+            String p = "";
+            for (int j = 0; j < unit[1].length && n > 0; j++) {
+                p = digit[integerPart % 10] + unit[1][j] + p;
+                integerPart = integerPart / 10;
+            }
+            s = p.replaceAll("(零.)*零$", "").replaceAll("^$", "零") + unit[0][i] + s;
+        }
+        return head + s.replaceAll("(零.)*零元", "元").replaceFirst("(零.)+", "").replaceAll("(零.)+", "零").replaceAll("^整$", "零元整");
+    }
+}

+ 101 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/core/text/StrFormatter.java

@@ -0,0 +1,101 @@
+package com.lij.himeeter.common.core.text;
+
+import com.lij.himeeter.common.utils.StringUtils;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  StrFormatter
+ * 创建时间 : 2024年12月26日 17:19
+ *
+ * 文件描述 : 字符串格式化
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class StrFormatter {
+
+    public static final String EMPTY_JSON = "{}";
+    public static final char C_BACKSLASH = '\\';
+    public static final char C_DELIM_START = '{';
+    public static final char C_DELIM_END = '}';
+
+    /**
+     * 格式化字符串<br>
+     * 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
+     * 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
+     * 例:<br>
+     * 通常使用:format("this is {} for {}", "a", "b") -> this is a for b<br>
+     * 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a<br>
+     * 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
+     *
+     * @param strPattern 字符串模板
+     * @param argArray 参数列表
+     * @return 结果
+     */
+    public static String format(final String strPattern, final Object... argArray)
+    {
+        if (StringUtils.isEmpty(strPattern) || StringUtils.isEmpty(argArray))
+        {
+            return strPattern;
+        }
+        final int strPatternLength = strPattern.length();
+
+        // 初始化定义好的长度以获得更好的性能
+        StringBuilder sbuf = new StringBuilder(strPatternLength + 50);
+
+        int handledPosition = 0;
+        int delimIndex;// 占位符所在位置
+        for (int argIndex = 0; argIndex < argArray.length; argIndex++)
+        {
+            delimIndex = strPattern.indexOf(EMPTY_JSON, handledPosition);
+            if (delimIndex == -1)
+            {
+                if (handledPosition == 0)
+                {
+                    return strPattern;
+                }
+                else
+                { // 字符串模板剩余部分不再包含占位符,加入剩余部分后返回结果
+                    sbuf.append(strPattern, handledPosition, strPatternLength);
+                    return sbuf.toString();
+                }
+            }
+            else
+            {
+                if (delimIndex > 0 && strPattern.charAt(delimIndex - 1) == C_BACKSLASH)
+                {
+                    if (delimIndex > 1 && strPattern.charAt(delimIndex - 2) == C_BACKSLASH)
+                    {
+                        // 转义符之前还有一个转义符,占位符依旧有效
+                        sbuf.append(strPattern, handledPosition, delimIndex - 1);
+                        sbuf.append(Convert.utf8Str(argArray[argIndex]));
+                        handledPosition = delimIndex + 2;
+                    }
+                    else
+                    {
+                        // 占位符被转义
+                        argIndex--;
+                        sbuf.append(strPattern, handledPosition, delimIndex - 1);
+                        sbuf.append(C_DELIM_START);
+                        handledPosition = delimIndex + 1;
+                    }
+                }
+                else
+                {
+                    // 正常占位符
+                    sbuf.append(strPattern, handledPosition, delimIndex);
+                    sbuf.append(Convert.utf8Str(argArray[argIndex]));
+                    handledPosition = delimIndex + 2;
+                }
+            }
+        }
+        // 加入最后一个占位符后所有的字符
+        sbuf.append(strPattern, handledPosition, strPattern.length());
+
+        return sbuf.toString();
+    }
+}

+ 28 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/enums/BusinessStatus.java

@@ -0,0 +1,28 @@
+package com.lij.himeeter.common.enums;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  BusinessStatus
+ * 创建时间 : 2024年12月30日 14:40
+ *
+ * 文件描述 : 操作状态
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public enum BusinessStatus {
+
+    /**
+     * 成功
+     */
+    SUCCESS,
+
+    /**
+     * 失败
+     */
+    FAIL,
+}

+ 68 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/enums/BusinessType.java

@@ -0,0 +1,68 @@
+package com.lij.himeeter.common.enums;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  BusinessType
+ * 创建时间 : 2024年12月26日 01:03
+ *
+ * 文件描述 : 业务操作类型
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public enum BusinessType {
+
+    /**
+     * 其它
+     */
+    OTHER,
+
+    /**
+     * 新增
+     */
+    INSERT,
+
+    /**
+     * 修改
+     */
+    UPDATE,
+
+    /**
+     * 删除
+     */
+    DELETE,
+
+    /**
+     * 授权
+     */
+    GRANT,
+
+    /**
+     * 导出
+     */
+    EXPORT,
+
+    /**
+     * 导入
+     */
+    IMPORT,
+
+    /**
+     * 强退
+     */
+    FORCE,
+
+    /**
+     * 生成代码
+     */
+    GENCODE,
+
+    /**
+     * 清空数据
+     */
+    CLEAN,
+}

+ 28 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/enums/DataSourceType.java

@@ -0,0 +1,28 @@
+package com.lij.himeeter.common.enums;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  DataSourceType
+ * 创建时间 : 2024年12月25日 17:02
+ *
+ * 文件描述 : 数据源
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public enum DataSourceType {
+
+    /**
+     * 主库
+     */
+    MASTER,
+
+    /**
+     * 从库
+     */
+    SLAVE
+}

+ 69 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/enums/DesensitizedType.java

@@ -0,0 +1,69 @@
+package com.lij.himeeter.common.enums;
+
+import com.lij.himeeter.common.utils.DesensitizedUtil;
+
+import java.util.function.Function;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  DesensitizedType
+ * 创建时间 : 2024年12月26日 15:33
+ *
+ * 文件描述 : 脱敏类型
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public enum DesensitizedType {
+
+    /**
+     * 姓名,第2位星号替换
+     */
+    USERNAME(s -> s.replaceAll("(\\S)\\S(\\S*)", "$1*$2")),
+
+    /**
+     * 密码,全部字符都用*代替
+     */
+    PASSWORD(DesensitizedUtil::password),
+
+    /**
+     * 身份证,中间10位星号替换
+     */
+    ID_CARD(s -> s.replaceAll("(\\d{4})\\d{10}(\\d{3}[Xx]|\\d{4})", "$1** **** ****$2")),
+
+    /**
+     * 手机号,中间4位星号替换
+     */
+    PHONE(s -> s.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2")),
+
+    /**
+     * 电子邮箱,仅显示第一个字母和@后面的地址显示,其他星号替换
+     */
+    EMAIL(s -> s.replaceAll("(^.)[^@]*(@.*$)", "$1****$2")),
+
+    /**
+     * 银行卡号,保留最后4位,其他星号替换
+     */
+    BANK_CARD(s -> s.replaceAll("\\d{15}(\\d{3})", "**** **** **** **** $1")),
+
+    /**
+     * 车牌号码,包含普通车辆、新能源车辆
+     */
+    CAR_LICENSE(DesensitizedUtil::carLicense);
+
+    private final Function<String, String> desensitizer;
+
+    DesensitizedType(Function<String, String> desensitizer)
+    {
+        this.desensitizer = desensitizer;
+    }
+
+    public Function<String, String> desensitizer()
+    {
+        return desensitizer;
+    }
+}

+ 28 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/enums/LimitType.java

@@ -0,0 +1,28 @@
+package com.lij.himeeter.common.enums;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  LimitType
+ * 创建时间 : 2024年12月26日 15:29
+ *
+ * 文件描述 : 限流类型
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public enum LimitType {
+
+    /**
+     * 默认策略全局限流
+     */
+    DEFAULT,
+
+    /**
+     * 根据请求者IP进行限流
+     */
+    IP
+}

+ 33 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/enums/OperatorType.java

@@ -0,0 +1,33 @@
+package com.lij.himeeter.common.enums;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  OperatorType
+ * 创建时间 : 2024年12月26日 01:04
+ *
+ * 文件描述 : 操作人类别
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public enum OperatorType {
+
+    /**
+     * 其它
+     */
+    OTHER,
+
+    /**
+     * 后台用户
+     */
+    MANAGE,
+
+    /**
+     * 手机端用户
+     */
+    MOBILE
+}

+ 77 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/exception/ServiceException.java

@@ -0,0 +1,77 @@
+package com.lij.himeeter.common.exception;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  ServiceException
+ * 创建时间 : 2024年12月27日 16:10
+ *
+ * 文件描述 : 无
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class ServiceException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 错误码
+     */
+    private Integer code;
+
+    /**
+     * 错误提示
+     */
+    private String message;
+
+    /**
+     * 错误明细,内部调试错误
+     */
+    private String detailMessage;
+
+    /**
+     * 空构造方法,避免反序列化问题
+     */
+    public ServiceException() {
+    }
+
+    public ServiceException(String message) {
+        this.message = message;
+    }
+
+    public ServiceException(String message, Integer code) {
+        this.message = message;
+        this.code = code;
+    }
+
+    public String getDetailMessage()
+    {
+        return detailMessage;
+    }
+
+    @Override
+    public String getMessage()
+    {
+        return message;
+    }
+
+    public Integer getCode()
+    {
+        return code;
+    }
+
+    public ServiceException setMessage(String message)
+    {
+        this.message = message;
+        return this;
+    }
+
+    public ServiceException setDetailMessage(String detailMessage)
+    {
+        this.detailMessage = detailMessage;
+        return this;
+    }
+}

+ 52 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/utils/DesensitizedUtil.java

@@ -0,0 +1,52 @@
+package com.lij.himeeter.common.utils;
+
+
+/**
+ * <pre>
+ *
+ * 文件名 :  DesensitizedUtil
+ * 创建时间 : 2024年12月26日 15:36
+ *
+ * 文件描述 : 脱敏工具类
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class DesensitizedUtil {
+
+    /**
+     * 密码的全部字符都用*代替,比如:******
+     *
+     * @param password 密码
+     * @return 脱敏后的密码
+     */
+    public static String password(String password) {
+        if (StringUtils.isBlank(password)) {
+            return StringUtils.EMPTY;
+        }
+        return StringUtils.repeat('*', password.length());
+    }
+
+    /**
+     * 车牌中间用*代替,如果是错误的车牌,不处理
+     *
+     * @param carLicense 完整的车牌号
+     * @return 脱敏后的车牌
+     */
+    public static String carLicense(String carLicense) {
+        if (StringUtils.isBlank(carLicense)) {
+            return StringUtils.EMPTY;
+        }
+        // 普通车牌
+        if (carLicense.length() == 7) {
+            carLicense = StringUtils.hide(carLicense, 3, 6);
+        } else if (carLicense.length() == 8) {
+            // 新能源车牌
+            carLicense = StringUtils.hide(carLicense, 3, 7);
+        }
+        return carLicense;
+    }
+}

+ 25 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/utils/LogUtils.java

@@ -0,0 +1,25 @@
+package com.lij.himeeter.common.utils;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  LogUtils
+ * 创建时间 : 2024年12月30日 15:11
+ *
+ * 文件描述 : 处理并记录日志文件
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class LogUtils {
+
+    public static String getBlock(Object msg) {
+        if (msg == null) {
+            msg = "";
+        }
+        return "[" + msg.toString() + "]";
+    }
+}

+ 163 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/utils/SecurityUtils.java

@@ -0,0 +1,163 @@
+package com.lij.himeeter.common.utils;
+
+import com.lij.himeeter.common.constant.Constants;
+import com.lij.himeeter.common.constant.HttpStatus;
+import com.lij.himeeter.common.core.domain.entity.SysRole;
+import com.lij.himeeter.common.core.domain.model.LoginUser;
+import com.lij.himeeter.common.exception.ServiceException;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.util.PatternMatchUtils;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SecurityUtils
+ * 创建时间 : 2024年12月27日 15:54
+ *
+ * 文件描述 : 安全服务工具类
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class SecurityUtils {
+
+    /**
+     * 获取用户ID
+     */
+    public static Long getUserId() {
+
+        try {
+            return getLoginUser().getUserId();
+        } catch (Exception e) {
+            throw new ServiceException("获取用户ID异常", HttpStatus.UNAUTHORIZED);
+        }
+    }
+
+    /**
+     * 获取部门ID
+     **/
+    public static Long getDeptId() {
+        try {
+            return getLoginUser().getDeptId();
+        } catch (Exception e) {
+            throw new ServiceException("获取部门ID异常", HttpStatus.UNAUTHORIZED);
+        }
+    }
+
+    /**
+     * 获取用户账户
+     **/
+    public static String getUsername() {
+        try {
+            return getLoginUser().getUsername();
+        } catch (Exception e) {
+            throw new ServiceException("获取用户账户异常", HttpStatus.UNAUTHORIZED);
+        }
+    }
+
+    /**
+     * 获取用户
+     **/
+    public static LoginUser getLoginUser() {
+        try {
+            return (LoginUser) getAuthentication().getPrincipal();
+        } catch (Exception e) {
+            throw new ServiceException("获取用户信息异常", HttpStatus.UNAUTHORIZED);
+        }
+    }
+
+    /**
+     * 获取Authentication
+     */
+    public static Authentication getAuthentication() {
+        return SecurityContextHolder.getContext().getAuthentication();
+    }
+
+    /**
+     * 生成BCryptPasswordEncoder密码
+     *
+     * @param password 密码
+     * @return 加密字符串
+     */
+    public static String encryptPassword(String password) {
+        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
+        return passwordEncoder.encode(password);
+    }
+
+    /**
+     * 判断密码是否相同
+     *
+     * @param rawPassword     真实密码
+     * @param encodedPassword 加密后字符
+     * @return 结果
+     */
+    public static boolean matchesPassword(String rawPassword, String encodedPassword) {
+        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
+        return passwordEncoder.matches(rawPassword, encodedPassword);
+    }
+
+    /**
+     * 是否为管理员
+     *
+     * @param userId 用户ID
+     * @return 结果
+     */
+    public static boolean isAdmin(Long userId) {
+        return userId != null && 1L == userId;
+    }
+
+    /**
+     * 验证用户是否具备某权限
+     *
+     * @param permission 权限字符串
+     * @return 用户是否具备某权限
+     */
+    public static boolean hasPermi(String permission) {
+        return hasPermi(getLoginUser().getPermissions(), permission);
+    }
+
+    /**
+     * 判断是否包含权限
+     *
+     * @param authorities 权限列表
+     * @param permission  权限字符串
+     * @return 用户是否具备某权限
+     */
+    public static boolean hasPermi(Collection<String> authorities, String permission) {
+        return authorities.stream().filter(StringUtils::hasText)
+                .anyMatch(x -> Constants.ALL_PERMISSION.equals(x) || PatternMatchUtils.simpleMatch(x, permission));
+    }
+
+    /**
+     * 验证用户是否拥有某个角色
+     *
+     * @param role 角色标识
+     * @return 用户是否具备某角色
+     */
+    public static boolean hasRole(String role) {
+        List<SysRole> roleList = getLoginUser().getUser().getRoles();
+        Collection<String> roles = roleList.stream().map(SysRole::getRoleKey).collect(Collectors.toSet());
+        return hasRole(roles, role);
+    }
+
+    /**
+     * 判断是否包含角色
+     *
+     * @param roles 角色列表
+     * @param role  角色
+     * @return 用户是否具备某角色权限
+     */
+    public static boolean hasRole(Collection<String> roles, String role) {
+        return roles.stream().filter(StringUtils::hasText)
+                .anyMatch(x -> Constants.SUPER_ADMIN.equals(x) || PatternMatchUtils.simpleMatch(x, role));
+    }
+}

+ 199 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/utils/ServletUtils.java

@@ -0,0 +1,199 @@
+package com.lij.himeeter.common.utils;
+
+import com.lij.himeeter.common.constant.Constants;
+import com.lij.himeeter.common.core.text.Convert;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.servlet.http.HttpSession;
+import org.springframework.web.context.request.RequestAttributes;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  ServletUtils
+ * 创建时间 : 2024年12月30日 14:54
+ *
+ * 文件描述 : 客户端工具类
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class ServletUtils {
+
+    /**
+     * 获取String参数
+     */
+    public static String getParameter(String name) {
+        return getRequest().getParameter(name);
+    }
+
+    /**
+     * 获取String参数
+     */
+    public static String getParameter(String name, String defaultValue) {
+        return Convert.toStr(getRequest().getParameter(name), defaultValue);
+    }
+
+    /**
+     * 获取Integer参数
+     */
+    public static Integer getParameterToInt(String name) {
+        return Convert.toInt(getRequest().getParameter(name));
+    }
+
+    /**
+     * 获取Integer参数
+     */
+    public static Integer getParameterToInt(String name, Integer defaultValue) {
+        return Convert.toInt(getRequest().getParameter(name), defaultValue);
+    }
+
+    /**
+     * 获取Boolean参数
+     */
+    public static Boolean getParameterToBool(String name) {
+        return Convert.toBool(getRequest().getParameter(name));
+    }
+
+    /**
+     * 获取Boolean参数
+     */
+    public static Boolean getParameterToBool(String name, Boolean defaultValue) {
+        return Convert.toBool(getRequest().getParameter(name), defaultValue);
+    }
+
+    /**
+     * 获得所有请求参数
+     *
+     * @param request 请求对象{@link ServletRequest}
+     * @return Map
+     */
+    public static Map<String, String[]> getParams(ServletRequest request) {
+        final Map<String, String[]> map = request.getParameterMap();
+        return Collections.unmodifiableMap(map);
+    }
+
+    /**
+     * 获得所有请求参数
+     *
+     * @param request 请求对象{@link ServletRequest}
+     * @return Map
+     */
+    public static Map<String, String> getParamMap(ServletRequest request) {
+        Map<String, String> params = new HashMap<>();
+        for (Map.Entry<String, String[]> entry : getParams(request).entrySet()) {
+            params.put(entry.getKey(), StringUtils.join(entry.getValue(), ","));
+        }
+        return params;
+    }
+
+    /**
+     * 获取request
+     */
+    public static HttpServletRequest getRequest() {
+        return getRequestAttributes().getRequest();
+    }
+
+    /**
+     * 获取response
+     */
+    public static HttpServletResponse getResponse() {
+        return getRequestAttributes().getResponse();
+    }
+
+    /**
+     * 获取session
+     */
+    public static HttpSession getSession() {
+        return getRequest().getSession();
+    }
+
+    public static ServletRequestAttributes getRequestAttributes() {
+        RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
+        return (ServletRequestAttributes) attributes;
+    }
+
+    /**
+     * 将字符串渲染到客户端
+     *
+     * @param response 渲染对象
+     * @param string   待渲染的字符串
+     */
+    public static void renderString(HttpServletResponse response, String string) {
+        try {
+            response.setStatus(200);
+            response.setContentType("application/json");
+            response.setCharacterEncoding("utf-8");
+            response.getWriter().print(string);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 是否是Ajax异步请求
+     *
+     * @param request
+     */
+    public static boolean isAjaxRequest(HttpServletRequest request) {
+        String accept = request.getHeader("accept");
+        if (accept != null && accept.contains("application/json")) {
+            return true;
+        }
+
+        String xRequestedWith = request.getHeader("X-Requested-With");
+        if (xRequestedWith != null && xRequestedWith.contains("XMLHttpRequest")) {
+            return true;
+        }
+
+        String uri = request.getRequestURI();
+        if (StringUtils.inStringIgnoreCase(uri, ".json", ".xml")) {
+            return true;
+        }
+
+        String ajax = request.getParameter("__ajax");
+        return StringUtils.inStringIgnoreCase(ajax, "json", "xml");
+    }
+
+    /**
+     * 内容编码
+     *
+     * @param str 内容
+     * @return 编码后的内容
+     */
+    public static String urlEncode(String str) {
+        try {
+            return URLEncoder.encode(str, Constants.UTF8);
+        } catch (UnsupportedEncodingException e) {
+            return StringUtils.EMPTY;
+        }
+    }
+
+    /**
+     * 内容解码
+     *
+     * @param str 内容
+     * @return 解码后的内容
+     */
+    public static String urlDecode(String str) {
+        try {
+            return URLDecoder.decode(str, Constants.UTF8);
+        } catch (UnsupportedEncodingException e) {
+            return StringUtils.EMPTY;
+        }
+    }
+}

+ 591 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/utils/StringUtils.java

@@ -0,0 +1,591 @@
+package com.lij.himeeter.common.utils;
+
+import com.lij.himeeter.common.constant.Constants;
+import com.lij.himeeter.common.core.text.StrFormatter;
+import org.springframework.util.AntPathMatcher;
+
+import java.util.*;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  StringUtils
+ * 创建时间 : 2024年12月26日 17:00
+ *
+ * 文件描述 : 字符串工具类
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class StringUtils extends org.apache.commons.lang3.StringUtils {
+
+    /**
+     * 空字符串
+     */
+    private static final String NULLSTR = "";
+
+    /**
+     * 下划线
+     */
+    private static final char SEPARATOR = '_';
+
+    /**
+     * 星号
+     */
+    private static final char ASTERISK = '*';
+
+    /**
+     * 获取参数不为空值
+     *
+     * @param value defaultValue 要判断的value
+     * @return value 返回值
+     */
+    public static <T> T nvl(T value, T defaultValue) {
+        return value != null ? value : defaultValue;
+    }
+
+    /**
+     * * 判断一个Collection是否为空, 包含List,Set,Queue
+     *
+     * @param coll 要判断的Collection
+     * @return true:为空 false:非空
+     */
+    public static boolean isEmpty(Collection<?> coll) {
+        return isNull(coll) || coll.isEmpty();
+    }
+
+    /**
+     * * 判断一个Collection是否非空,包含List,Set,Queue
+     *
+     * @param coll 要判断的Collection
+     * @return true:非空 false:空
+     */
+    public static boolean isNotEmpty(Collection<?> coll) {
+        return !isEmpty(coll);
+    }
+
+    /**
+     * * 判断一个对象数组是否为空
+     *
+     * @param objects 要判断的对象数组
+     *                * @return true:为空 false:非空
+     */
+    public static boolean isEmpty(Object[] objects) {
+        return isNull(objects) || (objects.length == 0);
+    }
+
+    /**
+     * * 判断一个对象数组是否非空
+     *
+     * @param objects 要判断的对象数组
+     * @return true:非空 false:空
+     */
+    public static boolean isNotEmpty(Object[] objects) {
+        return !isEmpty(objects);
+    }
+
+    /**
+     * * 判断一个Map是否为空
+     *
+     * @param map 要判断的Map
+     * @return true:为空 false:非空
+     */
+    public static boolean isEmpty(Map<?, ?> map) {
+        return isNull(map) || map.isEmpty();
+    }
+
+    /**
+     * * 判断一个Map是否为空
+     *
+     * @param map 要判断的Map
+     * @return true:非空 false:空
+     */
+    public static boolean isNotEmpty(Map<?, ?> map) {
+        return !isEmpty(map);
+    }
+
+    /**
+     * * 判断一个字符串是否为空串
+     *
+     * @param str String
+     * @return true:为空 false:非空
+     */
+    public static boolean isEmpty(String str) {
+        return isNull(str) || NULLSTR.equals(str.trim());
+    }
+
+    /**
+     * * 判断一个字符串是否为非空串
+     *
+     * @param str String
+     * @return true:非空串 false:空串
+     */
+    public static boolean isNotEmpty(String str) {
+        return !isEmpty(str);
+    }
+
+    /**
+     * * 判断一个对象是否为空
+     *
+     * @param object Object
+     * @return true:为空 false:非空
+     */
+    public static boolean isNull(Object object) {
+        return object == null;
+    }
+
+    /**
+     * * 判断一个对象是否非空
+     *
+     * @param object Object
+     * @return true:非空 false:空
+     */
+    public static boolean isNotNull(Object object) {
+        return !isNull(object);
+    }
+
+    /**
+     * * 判断一个对象是否是数组类型(Java基本型别的数组)
+     *
+     * @param object 对象
+     * @return true:是数组 false:不是数组
+     */
+    public static boolean isArray(Object object) {
+        return isNotNull(object) && object.getClass().isArray();
+    }
+
+    /**
+     * 去空格
+     */
+    public static String trim(String str) {
+        return (str == null ? "" : str.trim());
+    }
+
+    /**
+     * 替换指定字符串的指定区间内字符为"*"
+     *
+     * @param str          字符串
+     * @param startInclude 开始位置(包含)
+     * @param endExclude   结束位置(不包含)
+     * @return 替换后的字符串
+     */
+    public static String hide(CharSequence str, int startInclude, int endExclude) {
+        if (isEmpty(str)) {
+            return NULLSTR;
+        }
+        final int strLength = str.length();
+        if (startInclude > strLength) {
+            return NULLSTR;
+        }
+        if (endExclude > strLength) {
+            endExclude = strLength;
+        }
+        if (startInclude > endExclude) {
+            // 如果起始位置大于结束位置,不替换
+            return NULLSTR;
+        }
+        final char[] chars = new char[strLength];
+        for (int i = 0; i < strLength; i++) {
+            if (i >= startInclude && i < endExclude) {
+                chars[i] = ASTERISK;
+            } else {
+                chars[i] = str.charAt(i);
+            }
+        }
+        return new String(chars);
+    }
+
+    /**
+     * 截取字符串
+     *
+     * @param str   字符串
+     * @param start 开始
+     * @return 结果
+     */
+    public static String substring(final String str, int start) {
+        if (str == null) {
+            return NULLSTR;
+        }
+
+        if (start < 0) {
+            start = str.length() + start;
+        }
+
+        if (start < 0) {
+            start = 0;
+        }
+        if (start > str.length()) {
+            return NULLSTR;
+        }
+
+        return str.substring(start);
+    }
+
+    /**
+     * 截取字符串
+     *
+     * @param str   字符串
+     * @param start 开始
+     * @param end   结束
+     * @return 结果
+     */
+    public static String substring(final String str, int start, int end) {
+        if (str == null) {
+            return NULLSTR;
+        }
+
+        if (end < 0) {
+            end = str.length() + end;
+        }
+        if (start < 0) {
+            start = str.length() + start;
+        }
+
+        if (end > str.length()) {
+            end = str.length();
+        }
+
+        if (start > end) {
+            return NULLSTR;
+        }
+
+        if (start < 0) {
+            start = 0;
+        }
+        if (end < 0) {
+            end = 0;
+        }
+
+        return str.substring(start, end);
+    }
+
+    /**
+     * 判断是否为空,并且不是空白字符
+     *
+     * @param str 要判断的value
+     * @return 结果
+     */
+    public static boolean hasText(String str) {
+        return (str != null && !str.isEmpty() && containsText(str));
+    }
+
+    private static boolean containsText(CharSequence str) {
+        int strLen = str.length();
+        for (int i = 0; i < strLen; i++) {
+            if (!Character.isWhitespace(str.charAt(i))) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 格式化文本, {} 表示占位符<br>
+     * 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
+     * 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
+     * 例:<br>
+     * 通常使用:format("this is {} for {}", "a", "b") -> this is a for b<br>
+     * 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a<br>
+     * 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
+     *
+     * @param template 文本模板,被替换的部分用 {} 表示
+     * @param params   参数值
+     * @return 格式化后的文本
+     */
+    public static String format(String template, Object... params) {
+        if (isEmpty(params) || isEmpty(template)) {
+            return template;
+        }
+        return StrFormatter.format(template, params);
+    }
+
+    /**
+     * 是否为http(s)://开头
+     *
+     * @param link 链接
+     * @return 结果
+     */
+    public static boolean ishttp(String link) {
+        return StringUtils.startsWithAny(link, Constants.HTTP, Constants.HTTPS);
+    }
+
+    /**
+     * 字符串转set
+     *
+     * @param str 字符串
+     * @param sep 分隔符
+     * @return set集合
+     */
+    public static final Set<String> str2Set(String str, String sep) {
+        return new HashSet<String>(str2List(str, sep, true, false));
+    }
+
+    /**
+     * 字符串转list
+     *
+     * @param str         字符串
+     * @param sep         分隔符
+     * @param filterBlank 过滤纯空白
+     * @param trim        去掉首尾空白
+     * @return list集合
+     */
+    public static final List<String> str2List(String str, String sep, boolean filterBlank, boolean trim) {
+        List<String> list = new ArrayList<String>();
+        if (StringUtils.isEmpty(str)) {
+            return list;
+        }
+
+        // 过滤空白字符串
+        if (filterBlank && StringUtils.isBlank(str)) {
+            return list;
+        }
+        String[] split = str.split(sep);
+        for (String string : split) {
+            if (filterBlank && StringUtils.isBlank(string)) {
+                continue;
+            }
+            if (trim) {
+                string = string.trim();
+            }
+            list.add(string);
+        }
+
+        return list;
+    }
+
+    /**
+     * 判断给定的collection列表中是否包含数组array 判断给定的数组array中是否包含给定的元素value
+     *
+     * @param collection 给定的集合
+     * @param array      给定的数组
+     * @return boolean 结果
+     */
+    public static boolean containsAny(Collection<String> collection, String... array) {
+        if (isEmpty(collection) || isEmpty(array)) {
+            return false;
+        } else {
+            for (String str : array) {
+                if (collection.contains(str)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    /**
+     * 查找指定字符串是否包含指定字符串列表中的任意一个字符串同时串忽略大小写
+     *
+     * @param cs                  指定字符串
+     * @param searchCharSequences 需要检查的字符串数组
+     * @return 是否包含任意一个字符串
+     */
+    public static boolean containsAnyIgnoreCase(CharSequence cs, CharSequence... searchCharSequences) {
+        if (isEmpty(cs) || isEmpty(searchCharSequences)) {
+            return false;
+        }
+        for (CharSequence testStr : searchCharSequences) {
+            if (containsIgnoreCase(cs, testStr)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 驼峰转下划线命名
+     */
+    public static String toUnderScoreCase(String str) {
+        if (str == null) {
+            return null;
+        }
+        StringBuilder sb = new StringBuilder();
+        // 前置字符是否大写
+        boolean preCharIsUpperCase = true;
+        // 当前字符是否大写
+        boolean curreCharIsUpperCase = true;
+        // 下一字符是否大写
+        boolean nexteCharIsUpperCase = true;
+        for (int i = 0; i < str.length(); i++) {
+            char c = str.charAt(i);
+            if (i > 0) {
+                preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));
+            } else {
+                preCharIsUpperCase = false;
+            }
+
+            curreCharIsUpperCase = Character.isUpperCase(c);
+
+            if (i < (str.length() - 1)) {
+                nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));
+            }
+
+            if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase) {
+                sb.append(SEPARATOR);
+            } else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase) {
+                sb.append(SEPARATOR);
+            }
+            sb.append(Character.toLowerCase(c));
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * 是否包含字符串
+     *
+     * @param str  验证字符串
+     * @param strs 字符串组
+     * @return 包含返回true
+     */
+    public static boolean inStringIgnoreCase(String str, String... strs) {
+        if (str != null && strs != null) {
+            for (String s : strs) {
+                if (str.equalsIgnoreCase(trim(s))) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->HelloWorld
+     *
+     * @param name 转换前的下划线大写方式命名的字符串
+     * @return 转换后的驼峰式命名的字符串
+     */
+    public static String convertToCamelCase(String name) {
+        StringBuilder result = new StringBuilder();
+        // 快速检查
+        if (name == null || name.isEmpty()) {
+            // 没必要转换
+            return "";
+        } else if (!name.contains("_")) {
+            // 不含下划线,仅将首字母大写
+            return name.substring(0, 1).toUpperCase() + name.substring(1);
+        }
+        // 用下划线将原始字符串分割
+        String[] camels = name.split("_");
+        for (String camel : camels) {
+            // 跳过原始字符串中开头、结尾的下换线或双重下划线
+            if (camel.isEmpty()) {
+                continue;
+            }
+            // 首字母大写
+            result.append(camel.substring(0, 1).toUpperCase());
+            result.append(camel.substring(1).toLowerCase());
+        }
+        return result.toString();
+    }
+
+    /**
+     * 驼峰式命名法
+     * 例如:user_name->userName
+     */
+    public static String toCamelCase(String s) {
+        if (s == null) {
+            return null;
+        }
+        if (s.indexOf(SEPARATOR) == -1) {
+            return s;
+        }
+        s = s.toLowerCase();
+        StringBuilder sb = new StringBuilder(s.length());
+        boolean upperCase = false;
+        for (int i = 0; i < s.length(); i++) {
+            char c = s.charAt(i);
+
+            if (c == SEPARATOR) {
+                upperCase = true;
+            } else if (upperCase) {
+                sb.append(Character.toUpperCase(c));
+                upperCase = false;
+            } else {
+                sb.append(c);
+            }
+        }
+        return sb.toString();
+    }
+
+    /**
+     * 查找指定字符串是否匹配指定字符串列表中的任意一个字符串
+     *
+     * @param str  指定字符串
+     * @param strs 需要检查的字符串数组
+     * @return 是否匹配
+     */
+    public static boolean matches(String str, List<String> strs) {
+        if (isEmpty(str) || isEmpty(strs)) {
+            return false;
+        }
+        for (String pattern : strs) {
+            if (isMatch(pattern, str)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 判断url是否与规则配置:
+     * ? 表示单个字符;
+     * * 表示一层路径内的任意字符串,不可跨层级;
+     * ** 表示任意层路径;
+     *
+     * @param pattern 匹配规则
+     * @param url     需要匹配的url
+     * @return
+     */
+    public static boolean isMatch(String pattern, String url) {
+        AntPathMatcher matcher = new AntPathMatcher();
+        return matcher.match(pattern, url);
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T> T cast(Object obj) {
+        return (T) obj;
+    }
+
+    /**
+     * 数字左边补齐0,使之达到指定长度。注意,如果数字转换为字符串后,长度大于size,则只保留 最后size个字符。
+     *
+     * @param num  数字对象
+     * @param size 字符串指定长度
+     * @return 返回数字的字符串格式,该字符串为指定长度。
+     */
+    public static final String padl(final Number num, final int size) {
+        return padl(num.toString(), size, '0');
+    }
+
+    /**
+     * 字符串左补齐。如果原始字符串s长度大于size,则只保留最后size个字符。
+     *
+     * @param s    原始字符串
+     * @param size 字符串指定长度
+     * @param c    用于补齐的字符
+     * @return 返回指定长度的字符串,由原字符串左补齐或截取得到。
+     */
+    public static final String padl(final String s, final int size, final char c) {
+        final StringBuilder sb = new StringBuilder(size);
+        if (s != null) {
+            final int len = s.length();
+            if (s.length() <= size) {
+                for (int i = size - len; i > 0; i--) {
+                    sb.append(c);
+                }
+                sb.append(s);
+            } else {
+                return s.substring(len - size, len);
+            }
+        } else {
+            for (int i = size; i > 0; i--) {
+                sb.append(c);
+            }
+        }
+        return sb.toString();
+    }
+}

+ 82 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/utils/Threads.java

@@ -0,0 +1,82 @@
+package com.lij.himeeter.common.utils;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.concurrent.*;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  Threads
+ * 创建时间 : 2024年12月30日 15:00
+ *
+ * 文件描述 : 线程相关工具类
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class Threads {
+    private static final Logger logger = LoggerFactory.getLogger(Threads.class);
+
+    /**
+     * sleep等待,单位为毫秒
+     */
+    public static void sleep(long milliseconds) {
+        try {
+            Thread.sleep(milliseconds);
+        } catch (InterruptedException e) {
+            return;
+        }
+    }
+
+    /**
+     * 停止线程池
+     * 先使用shutdown, 停止接收新任务并尝试完成所有已存在任务.
+     * 如果超时, 则调用shutdownNow, 取消在workQueue中Pending的任务,并中断所有阻塞函数.
+     * 如果仍然超時,則強制退出.
+     * 另对在shutdown时线程本身被调用中断做了处理.
+     */
+    public static void shutdownAndAwaitTermination(ExecutorService pool) {
+        if (pool != null && !pool.isShutdown()) {
+            pool.shutdown();
+            try {
+                if (!pool.awaitTermination(120, TimeUnit.SECONDS)) {
+                    pool.shutdownNow();
+                    if (!pool.awaitTermination(120, TimeUnit.SECONDS)) {
+                        logger.info("Pool did not terminate");
+                    }
+                }
+            } catch (InterruptedException ie) {
+                pool.shutdownNow();
+                Thread.currentThread().interrupt();
+            }
+        }
+    }
+
+    /**
+     * 打印线程异常信息
+     */
+    public static void printException(Runnable r, Throwable t) {
+        if (t == null && r instanceof Future<?>) {
+            try {
+                Future<?> future = (Future<?>) r;
+                if (future.isDone()) {
+                    future.get();
+                }
+            } catch (CancellationException ce) {
+                t = ce;
+            } catch (ExecutionException ee) {
+                t = ee.getCause();
+            } catch (InterruptedException ie) {
+                Thread.currentThread().interrupt();
+            }
+        }
+        if (t != null) {
+            logger.error(t.getMessage(), t);
+        }
+    }
+}

+ 18 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/utils/http/HttpHelper.java

@@ -0,0 +1,18 @@
+package com.lij.himeeter.common.utils.http;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  HttpHelper
+ * 创建时间 : 2024年12月30日 15:08
+ *
+ * 文件描述 : 无
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class HttpHelper {
+}

+ 219 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/utils/http/HttpUtils.java

@@ -0,0 +1,219 @@
+package com.lij.himeeter.common.utils.http;
+
+import com.lij.himeeter.common.constant.Constants;
+import com.lij.himeeter.common.utils.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.net.ssl.*;
+import java.io.*;
+import java.net.ConnectException;
+import java.net.SocketTimeoutException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.nio.charset.StandardCharsets;
+import java.security.cert.X509Certificate;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  HttpUtils
+ * 创建时间 : 2024年12月30日 15:08
+ *
+ * 文件描述 : 通用http发送方法
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class HttpUtils {
+    private static final Logger log = LoggerFactory.getLogger(HttpUtils.class);
+
+    /**
+     * 向指定 URL 发送GET方法的请求
+     *
+     * @param url 发送请求的 URL
+     * @return 所代表远程资源的响应结果
+     */
+    public static String sendGet(String url) {
+        return sendGet(url, StringUtils.EMPTY);
+    }
+
+    /**
+     * 向指定 URL 发送GET方法的请求
+     *
+     * @param url   发送请求的 URL
+     * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
+     * @return 所代表远程资源的响应结果
+     */
+    public static String sendGet(String url, String param) {
+        return sendGet(url, param, Constants.UTF8);
+    }
+
+    /**
+     * 向指定 URL 发送GET方法的请求
+     *
+     * @param url         发送请求的 URL
+     * @param param       请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
+     * @param contentType 编码类型
+     * @return 所代表远程资源的响应结果
+     */
+    public static String sendGet(String url, String param, String contentType) {
+        StringBuilder result = new StringBuilder();
+        BufferedReader in = null;
+        try {
+            String urlNameString = StringUtils.isNotBlank(param) ? url + "?" + param : url;
+            log.info("sendGet - {}", urlNameString);
+            URL realUrl = new URL(urlNameString);
+            URLConnection connection = realUrl.openConnection();
+            connection.setRequestProperty("accept", "*/*");
+            connection.setRequestProperty("connection", "Keep-Alive");
+            connection.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
+            connection.connect();
+            in = new BufferedReader(new InputStreamReader(connection.getInputStream(), contentType));
+            String line;
+            while ((line = in.readLine()) != null) {
+                result.append(line);
+            }
+            log.info("recv - {}", result);
+        } catch (ConnectException e) {
+            log.error("调用HttpUtils.sendGet ConnectException, url=" + url + ",param=" + param, e);
+        } catch (SocketTimeoutException e) {
+            log.error("调用HttpUtils.sendGet SocketTimeoutException, url=" + url + ",param=" + param, e);
+        } catch (IOException e) {
+            log.error("调用HttpUtils.sendGet IOException, url=" + url + ",param=" + param, e);
+        } catch (Exception e) {
+            log.error("调用HttpsUtil.sendGet Exception, url=" + url + ",param=" + param, e);
+        } finally {
+            try {
+                if (in != null) {
+                    in.close();
+                }
+            } catch (Exception ex) {
+                log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
+            }
+        }
+        return result.toString();
+    }
+
+    /**
+     * 向指定 URL 发送POST方法的请求
+     *
+     * @param url   发送请求的 URL
+     * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
+     * @return 所代表远程资源的响应结果
+     */
+    public static String sendPost(String url, String param) {
+        PrintWriter out = null;
+        BufferedReader in = null;
+        StringBuilder result = new StringBuilder();
+        try {
+            log.info("sendPost - {}", url);
+            URL realUrl = new URL(url);
+            URLConnection conn = realUrl.openConnection();
+            conn.setRequestProperty("accept", "*/*");
+            conn.setRequestProperty("connection", "Keep-Alive");
+            conn.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
+            conn.setRequestProperty("Accept-Charset", "utf-8");
+            conn.setRequestProperty("contentType", "utf-8");
+            conn.setDoOutput(true);
+            conn.setDoInput(true);
+            out = new PrintWriter(conn.getOutputStream());
+            out.print(param);
+            out.flush();
+            in = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
+            String line;
+            while ((line = in.readLine()) != null) {
+                result.append(line);
+            }
+            log.info("recv - {}", result);
+        } catch (ConnectException e) {
+            log.error("调用HttpUtils.sendPost ConnectException, url=" + url + ",param=" + param, e);
+        } catch (SocketTimeoutException e) {
+            log.error("调用HttpUtils.sendPost SocketTimeoutException, url=" + url + ",param=" + param, e);
+        } catch (IOException e) {
+            log.error("调用HttpUtils.sendPost IOException, url=" + url + ",param=" + param, e);
+        } catch (Exception e) {
+            log.error("调用HttpsUtil.sendPost Exception, url=" + url + ",param=" + param, e);
+        } finally {
+            try {
+                if (out != null) {
+                    out.close();
+                }
+                if (in != null) {
+                    in.close();
+                }
+            } catch (IOException ex) {
+                log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
+            }
+        }
+        return result.toString();
+    }
+
+    public static String sendSSLPost(String url, String param) {
+        StringBuilder result = new StringBuilder();
+        String urlNameString = url + "?" + param;
+        try {
+            log.info("sendSSLPost - {}", urlNameString);
+            SSLContext sc = SSLContext.getInstance("SSL");
+            sc.init(null, new TrustManager[]{new TrustAnyTrustManager()}, new java.security.SecureRandom());
+            URL console = new URL(urlNameString);
+            HttpsURLConnection conn = (HttpsURLConnection) console.openConnection();
+            conn.setRequestProperty("accept", "*/*");
+            conn.setRequestProperty("connection", "Keep-Alive");
+            conn.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
+            conn.setRequestProperty("Accept-Charset", "utf-8");
+            conn.setRequestProperty("contentType", "utf-8");
+            conn.setDoOutput(true);
+            conn.setDoInput(true);
+
+            conn.setSSLSocketFactory(sc.getSocketFactory());
+            conn.setHostnameVerifier(new TrustAnyHostnameVerifier());
+            conn.connect();
+            InputStream is = conn.getInputStream();
+            BufferedReader br = new BufferedReader(new InputStreamReader(is));
+            String ret = "";
+            while ((ret = br.readLine()) != null) {
+                if (ret != null && !"".equals(ret.trim())) {
+                    result.append(new String(ret.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8));
+                }
+            }
+            log.info("recv - {}", result);
+            conn.disconnect();
+            br.close();
+        } catch (ConnectException e) {
+            log.error("调用HttpUtils.sendSSLPost ConnectException, url=" + url + ",param=" + param, e);
+        } catch (SocketTimeoutException e) {
+            log.error("调用HttpUtils.sendSSLPost SocketTimeoutException, url=" + url + ",param=" + param, e);
+        } catch (IOException e) {
+            log.error("调用HttpUtils.sendSSLPost IOException, url=" + url + ",param=" + param, e);
+        } catch (Exception e) {
+            log.error("调用HttpsUtil.sendSSLPost Exception, url=" + url + ",param=" + param, e);
+        }
+        return result.toString();
+    }
+
+    private static class TrustAnyTrustManager implements X509TrustManager {
+        @Override
+        public void checkClientTrusted(X509Certificate[] chain, String authType) {
+        }
+
+        @Override
+        public void checkServerTrusted(X509Certificate[] chain, String authType) {
+        }
+
+        @Override
+        public X509Certificate[] getAcceptedIssuers() {
+            return new X509Certificate[]{};
+        }
+    }
+
+    private static class TrustAnyHostnameVerifier implements HostnameVerifier {
+        @Override
+        public boolean verify(String hostname, SSLSession session) {
+            return true;
+        }
+    }
+}

+ 64 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/utils/ip/AddressUtils.java

@@ -0,0 +1,64 @@
+package com.lij.himeeter.common.utils.ip;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.lij.himeeter.common.config.HimeeterConfig;
+import com.lij.himeeter.common.constant.Constants;
+import com.lij.himeeter.common.utils.StringUtils;
+import com.lij.himeeter.common.utils.http.HttpUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  AddressUtils
+ * 创建时间 : 2024年12月30日 15:04
+ *
+ * 文件描述 : 无
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class AddressUtils {
+    private static final Logger log = LoggerFactory.getLogger(AddressUtils.class);
+
+    // IP地址查询
+    public static final String IP_URL = "http://whois.pconline.com.cn/ipJson.jsp";
+
+    // 未知地址
+    public static final String UNKNOWN = "XX XX";
+
+    public static String getRealAddressByIP(String ip)
+    {
+        // 内网不查询
+        if (IpUtils.internalIp(ip))
+        {
+            return "内网IP";
+        }
+        if (HimeeterConfig.isAddressEnabled())
+        {
+            try
+            {
+                String rspStr = HttpUtils.sendGet(IP_URL, "ip=" + ip + "&json=true", Constants.GBK);
+                if (StringUtils.isEmpty(rspStr))
+                {
+                    log.error("获取地理位置异常 {}", ip);
+                    return UNKNOWN;
+                }
+                JSONObject obj = JSON.parseObject(rspStr);
+                String region = obj.getString("pro");
+                String city = obj.getString("city");
+                return String.format("%s %s", region, city);
+            }
+            catch (Exception e)
+            {
+                log.error("获取地理位置异常 {}", ip);
+            }
+        }
+        return UNKNOWN;
+    }
+}

+ 334 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/utils/ip/IpUtils.java

@@ -0,0 +1,334 @@
+package com.lij.himeeter.common.utils.ip;
+
+import com.lij.himeeter.common.utils.ServletUtils;
+import com.lij.himeeter.common.utils.StringUtils;
+import jakarta.servlet.http.HttpServletRequest;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  IpUtils
+ * 创建时间 : 2024年12月30日 14:51
+ *
+ * 文件描述 : 获取IP方法
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class IpUtils {
+
+    public final static String REGX_0_255 = "(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d)";
+    // 匹配 ip
+    public final static String REGX_IP = "((" + REGX_0_255 + "\\.){3}" + REGX_0_255 + ")";
+    public final static String REGX_IP_WILDCARD = "(((\\*\\.){3}\\*)|(" + REGX_0_255 + "(\\.\\*){3})|(" + REGX_0_255 + "\\." + REGX_0_255 + ")(\\.\\*){2}" + "|((" + REGX_0_255 + "\\.){3}\\*))";
+    // 匹配网段
+    public final static String REGX_IP_SEG = "(" + REGX_IP + "\\-" + REGX_IP + ")";
+
+    /**
+     * 获取客户端IP
+     *
+     * @return IP地址
+     */
+    public static String getIpAddr() {
+        return getIpAddr(ServletUtils.getRequest());
+    }
+
+    /**
+     * 获取客户端IP
+     *
+     * @param request 请求对象
+     * @return IP地址
+     */
+    public static String getIpAddr(HttpServletRequest request) {
+        if (request == null) {
+            return "unknown";
+        }
+        String ip = request.getHeader("x-forwarded-for");
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+            ip = request.getHeader("Proxy-Client-IP");
+        }
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+            ip = request.getHeader("X-Forwarded-For");
+        }
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+            ip = request.getHeader("WL-Proxy-Client-IP");
+        }
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+            ip = request.getHeader("X-Real-IP");
+        }
+
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+            ip = request.getRemoteAddr();
+        }
+
+        return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : getMultistageReverseProxyIp(ip);
+    }
+
+    /**
+     * 检查是否为内部IP地址
+     *
+     * @param ip IP地址
+     * @return 结果
+     */
+    public static boolean internalIp(String ip) {
+        byte[] addr = textToNumericFormatV4(ip);
+        return internalIp(addr) || "127.0.0.1".equals(ip);
+    }
+
+    /**
+     * 检查是否为内部IP地址
+     *
+     * @param addr byte地址
+     * @return 结果
+     */
+    private static boolean internalIp(byte[] addr) {
+        if (StringUtils.isNull(addr) || addr.length < 2) {
+            return true;
+        }
+        final byte b0 = addr[0];
+        final byte b1 = addr[1];
+        // 10.x.x.x/8
+        final byte SECTION_1 = 0x0A;
+        // 172.16.x.x/12
+        final byte SECTION_2 = (byte) 0xAC;
+        final byte SECTION_3 = (byte) 0x10;
+        final byte SECTION_4 = (byte) 0x1F;
+        // 192.168.x.x/16
+        final byte SECTION_5 = (byte) 0xC0;
+        final byte SECTION_6 = (byte) 0xA8;
+        switch (b0) {
+            case SECTION_1:
+                return true;
+            case SECTION_2:
+                if (b1 >= SECTION_3 && b1 <= SECTION_4) {
+                    return true;
+                }
+            case SECTION_5:
+                switch (b1) {
+                    case SECTION_6:
+                        return true;
+                }
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * 将IPv4地址转换成字节
+     *
+     * @param text IPv4地址
+     * @return byte 字节
+     */
+    public static byte[] textToNumericFormatV4(String text) {
+        if (text.length() == 0) {
+            return null;
+        }
+
+        byte[] bytes = new byte[4];
+        String[] elements = text.split("\\.", -1);
+        try {
+            long l;
+            int i;
+            switch (elements.length) {
+                case 1:
+                    l = Long.parseLong(elements[0]);
+                    if ((l < 0L) || (l > 4294967295L)) {
+                        return null;
+                    }
+                    bytes[0] = (byte) (int) (l >> 24 & 0xFF);
+                    bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF);
+                    bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
+                    bytes[3] = (byte) (int) (l & 0xFF);
+                    break;
+                case 2:
+                    l = Integer.parseInt(elements[0]);
+                    if ((l < 0L) || (l > 255L)) {
+                        return null;
+                    }
+                    bytes[0] = (byte) (int) (l & 0xFF);
+                    l = Integer.parseInt(elements[1]);
+                    if ((l < 0L) || (l > 16777215L)) {
+                        return null;
+                    }
+                    bytes[1] = (byte) (int) (l >> 16 & 0xFF);
+                    bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
+                    bytes[3] = (byte) (int) (l & 0xFF);
+                    break;
+                case 3:
+                    for (i = 0; i < 2; ++i) {
+                        l = Integer.parseInt(elements[i]);
+                        if ((l < 0L) || (l > 255L)) {
+                            return null;
+                        }
+                        bytes[i] = (byte) (int) (l & 0xFF);
+                    }
+                    l = Integer.parseInt(elements[2]);
+                    if ((l < 0L) || (l > 65535L)) {
+                        return null;
+                    }
+                    bytes[2] = (byte) (int) (l >> 8 & 0xFF);
+                    bytes[3] = (byte) (int) (l & 0xFF);
+                    break;
+                case 4:
+                    for (i = 0; i < 4; ++i) {
+                        l = Integer.parseInt(elements[i]);
+                        if ((l < 0L) || (l > 255L)) {
+                            return null;
+                        }
+                        bytes[i] = (byte) (int) (l & 0xFF);
+                    }
+                    break;
+                default:
+                    return null;
+            }
+        } catch (NumberFormatException e) {
+            return null;
+        }
+        return bytes;
+    }
+
+    /**
+     * 获取IP地址
+     *
+     * @return 本地IP地址
+     */
+    public static String getHostIp() {
+        try {
+            return InetAddress.getLocalHost().getHostAddress();
+        } catch (UnknownHostException e) {
+        }
+        return "127.0.0.1";
+    }
+
+    /**
+     * 获取主机名
+     *
+     * @return 本地主机名
+     */
+    public static String getHostName() {
+        try {
+            return InetAddress.getLocalHost().getHostName();
+        } catch (UnknownHostException e) {
+        }
+        return "未知";
+    }
+
+    /**
+     * 从多级反向代理中获得第一个非unknown IP地址
+     *
+     * @param ip 获得的IP地址
+     * @return 第一个非unknown IP地址
+     */
+    public static String getMultistageReverseProxyIp(String ip) {
+        // 多级反向代理检测
+        if (ip != null && ip.indexOf(",") > 0) {
+            final String[] ips = ip.trim().split(",");
+            for (String subIp : ips) {
+                if (false == isUnknown(subIp)) {
+                    ip = subIp;
+                    break;
+                }
+            }
+        }
+        return StringUtils.substring(ip, 0, 255);
+    }
+
+    /**
+     * 检测给定字符串是否为未知,多用于检测HTTP请求相关
+     *
+     * @param checkString 被检测的字符串
+     * @return 是否未知
+     */
+    public static boolean isUnknown(String checkString) {
+        return StringUtils.isBlank(checkString) || "unknown".equalsIgnoreCase(checkString);
+    }
+
+    /**
+     * 是否为IP
+     */
+    public static boolean isIP(String ip) {
+        return StringUtils.isNotBlank(ip) && ip.matches(REGX_IP);
+    }
+
+    /**
+     * 是否为IP,或 *为间隔的通配符地址
+     */
+    public static boolean isIpWildCard(String ip) {
+        return StringUtils.isNotBlank(ip) && ip.matches(REGX_IP_WILDCARD);
+    }
+
+    /**
+     * 检测参数是否在ip通配符里
+     */
+    public static boolean ipIsInWildCardNoCheck(String ipWildCard, String ip) {
+        String[] s1 = ipWildCard.split("\\.");
+        String[] s2 = ip.split("\\.");
+        boolean isMatchedSeg = true;
+        for (int i = 0; i < s1.length && !s1[i].equals("*"); i++) {
+            if (!s1[i].equals(s2[i])) {
+                isMatchedSeg = false;
+                break;
+            }
+        }
+        return isMatchedSeg;
+    }
+
+    /**
+     * 是否为特定格式如:“10.10.10.1-10.10.10.99”的ip段字符串
+     */
+    public static boolean isIPSegment(String ipSeg) {
+        return StringUtils.isNotBlank(ipSeg) && ipSeg.matches(REGX_IP_SEG);
+    }
+
+    /**
+     * 判断ip是否在指定网段中
+     */
+    public static boolean ipIsInNetNoCheck(String iparea, String ip) {
+        int idx = iparea.indexOf('-');
+        String[] sips = iparea.substring(0, idx).split("\\.");
+        String[] sipe = iparea.substring(idx + 1).split("\\.");
+        String[] sipt = ip.split("\\.");
+        long ips = 0L, ipe = 0L, ipt = 0L;
+        for (int i = 0; i < 4; ++i) {
+            ips = ips << 8 | Integer.parseInt(sips[i]);
+            ipe = ipe << 8 | Integer.parseInt(sipe[i]);
+            ipt = ipt << 8 | Integer.parseInt(sipt[i]);
+        }
+        if (ips > ipe) {
+            long t = ips;
+            ips = ipe;
+            ipe = t;
+        }
+        return ips <= ipt && ipt <= ipe;
+    }
+
+    /**
+     * 校验ip是否符合过滤串规则
+     *
+     * @param filter 过滤IP列表,支持后缀'*'通配,支持网段如:`10.10.10.1-10.10.10.99`
+     * @param ip     校验IP地址
+     * @return boolean 结果
+     */
+    public static boolean isMatchedIp(String filter, String ip) {
+        if (StringUtils.isEmpty(filter) || StringUtils.isEmpty(ip)) {
+            return false;
+        }
+        String[] ips = filter.split(";");
+        for (String iStr : ips) {
+            if (isIP(iStr) && iStr.equals(ip)) {
+                return true;
+            } else if (isIpWildCard(iStr) && ipIsInWildCardNoCheck(iStr, ip)) {
+                return true;
+            } else if (isIPSegment(iStr) && ipIsInNetNoCheck(iStr, ip)) {
+                return true;
+            }
+        }
+        return false;
+    }
+}

+ 33 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/utils/poi/ExcelHandlerAdapter.java

@@ -0,0 +1,33 @@
+package com.lij.himeeter.common.utils.poi;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.Workbook;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  ExcelHandlerAdapter
+ * 创建时间 : 2024年12月25日 17:16
+ *
+ * 文件描述 : Excel数据格式处理适配器
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public interface ExcelHandlerAdapter {
+
+    /**
+     * 格式化
+     *
+     * @param value 单元格数据值
+     * @param args excel注解args参数组
+     * @param cell 单元格对象
+     * @param wb 工作簿对象
+     *
+     * @return 处理后的值
+     */
+    Object format(Object value, String[] args, Cell cell, Workbook wb);
+}

+ 18 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/utils/poi/ExcelUtil.java

@@ -0,0 +1,18 @@
+package com.lij.himeeter.common.utils.poi;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  ExcelUtil
+ * 创建时间 : 2024年12月25日 17:15
+ *
+ * 文件描述 : 无
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class ExcelUtil {
+}

+ 149 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/utils/spring/SpringUtils.java

@@ -0,0 +1,149 @@
+package com.lij.himeeter.common.utils.spring;
+
+import com.lij.himeeter.common.utils.StringUtils;
+import org.springframework.aop.framework.AopContext;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SpringUtils
+ * 创建时间 : 2024年12月30日 14:58
+ *
+ * 文件描述 : spring工具类 方便在非spring管理环境中获取bean
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class SpringUtils implements BeanFactoryPostProcessor, ApplicationContextAware {
+
+    /**
+     * Spring应用上下文环境
+     */
+    private static ConfigurableListableBeanFactory beanFactory;
+
+    private static ApplicationContext applicationContext;
+
+    @Override
+    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
+        SpringUtils.beanFactory = beanFactory;
+    }
+
+    @Override
+    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+        SpringUtils.applicationContext = applicationContext;
+    }
+
+    /**
+     * 获取对象
+     *
+     * @param name
+     * @return Object 一个以所给名字注册的bean的实例
+     * @throws org.springframework.beans.BeansException
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T getBean(String name) throws BeansException {
+        return (T) beanFactory.getBean(name);
+    }
+
+    /**
+     * 获取类型为requiredType的对象
+     *
+     * @param clz
+     * @return
+     * @throws org.springframework.beans.BeansException
+     */
+    public static <T> T getBean(Class<T> clz) throws BeansException {
+        T result = (T) beanFactory.getBean(clz);
+        return result;
+    }
+
+    /**
+     * 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true
+     *
+     * @param name
+     * @return boolean
+     */
+    public static boolean containsBean(String name) {
+        return beanFactory.containsBean(name);
+    }
+
+    /**
+     * 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException)
+     *
+     * @param name
+     * @return boolean
+     * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
+     */
+    public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
+        return beanFactory.isSingleton(name);
+    }
+
+    /**
+     * @param name
+     * @return Class 注册对象的类型
+     * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
+     */
+    public static Class<?> getType(String name) throws NoSuchBeanDefinitionException {
+        return beanFactory.getType(name);
+    }
+
+    /**
+     * 如果给定的bean名字在bean定义中有别名,则返回这些别名
+     *
+     * @param name
+     * @return
+     * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
+     */
+    public static String[] getAliases(String name) throws NoSuchBeanDefinitionException {
+        return beanFactory.getAliases(name);
+    }
+
+    /**
+     * 获取aop代理对象
+     *
+     * @param invoker
+     * @return
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T getAopProxy(T invoker) {
+        return (T) AopContext.currentProxy();
+    }
+
+    /**
+     * 获取当前的环境配置,无配置返回null
+     *
+     * @return 当前的环境配置
+     */
+    public static String[] getActiveProfiles() {
+        return applicationContext.getEnvironment().getActiveProfiles();
+    }
+
+    /**
+     * 获取当前的环境配置,当有多个环境配置时,只获取第一个
+     *
+     * @return 当前的环境配置
+     */
+    public static String getActiveProfile() {
+        final String[] activeProfiles = getActiveProfiles();
+        return StringUtils.isNotEmpty(activeProfiles) ? activeProfiles[0] : null;
+    }
+
+    /**
+     * 获取配置文件中的值
+     *
+     * @param key 配置文件的key
+     * @return 当前的配置文件的值
+     */
+    public static String getRequiredProperty(String key) {
+        return applicationContext.getEnvironment().getRequiredProperty(key);
+    }
+}

+ 35 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/xss/Xss.java

@@ -0,0 +1,35 @@
+package com.lij.himeeter.common.xss;
+
+import jakarta.validation.Constraint;
+import jakarta.validation.Payload;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  Xss
+ * 创建时间 : 2024年12月27日 14:58
+ *
+ * 文件描述 : 自定义xss校验注解
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(value = {ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
+@Constraint(validatedBy = {XssValidator.class})
+public @interface Xss {
+
+    String message() default "不允许任何脚本运行";
+
+    Class<?>[] groups() default {};
+
+    Class<? extends Payload>[] payload() default {};
+}

+ 45 - 0
himeeter-common/src/main/java/com/lij/himeeter/common/xss/XssValidator.java

@@ -0,0 +1,45 @@
+package com.lij.himeeter.common.xss;
+
+import com.lij.himeeter.common.utils.StringUtils;
+import jakarta.validation.ConstraintValidator;
+import jakarta.validation.ConstraintValidatorContext;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  XssValidator
+ * 创建时间 : 2024年12月27日 14:58
+ *
+ * 文件描述 : 无
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class XssValidator implements ConstraintValidator<Xss, String> {
+
+    private static final String HTML_PATTERN = "<(\\S*?)[^>]*>.*?|<.*? />";
+
+    @Override
+    public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
+        if (StringUtils.isBlank(value)) {
+            return true;
+        }
+        return !containsHtml(value);
+    }
+
+    public static boolean containsHtml(String value) {
+        StringBuilder sHtml = new StringBuilder();
+        Pattern pattern = Pattern.compile(HTML_PATTERN);
+        Matcher matcher = pattern.matcher(value);
+        while (matcher.find()) {
+            sHtml.append(matcher.group());
+        }
+        return pattern.matcher(sHtml).matches();
+    }
+}

+ 0 - 13
himeeter-common/src/main/java/com/lij/himeeter/framework/HimeeterFrameworkApplication.java

@@ -1,13 +0,0 @@
-package com.lij.himeeter.framework;
-
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-
-@SpringBootApplication
-public class HimeeterFrameworkApplication {
-
-    public static void main(String[] args) {
-        SpringApplication.run(HimeeterFrameworkApplication.class, args);
-    }
-
-}

+ 0 - 1
himeeter-common/src/main/resources/application.properties

@@ -1 +0,0 @@
-spring.application.name=himeeter-framework

+ 0 - 13
himeeter-framework/src/main/java/com/lij/himeeter/framework/HimeeterFrameworkApplication.java

@@ -1,13 +0,0 @@
-package com.lij.himeeter.framework;
-
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-
-@SpringBootApplication
-public class HimeeterFrameworkApplication {
-
-    public static void main(String[] args) {
-        SpringApplication.run(HimeeterFrameworkApplication.class, args);
-    }
-
-}

+ 166 - 0
himeeter-framework/src/main/java/com/lij/himeeter/framework/aspectj/DataScopeAspect.java

@@ -0,0 +1,166 @@
+package com.lij.himeeter.framework.aspectj;
+
+
+import com.lij.himeeter.common.annotation.DataScope;
+import com.lij.himeeter.common.constant.UserConstants;
+import com.lij.himeeter.common.core.domain.BaseEntity;
+import com.lij.himeeter.common.core.domain.entity.SysRole;
+import com.lij.himeeter.common.core.domain.entity.SysUser;
+import com.lij.himeeter.common.core.domain.model.LoginUser;
+import com.lij.himeeter.common.core.text.Convert;
+import com.lij.himeeter.common.utils.SecurityUtils;
+import com.lij.himeeter.common.utils.StringUtils;
+import com.lij.himeeter.framework.security.context.PermissionContextHolder;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  DataScopeAspect
+ * 创建时间 : 2024年12月16日 18:43
+ *
+ * 文件描述 : 数据过滤处理
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+@Aspect
+@Component
+public class DataScopeAspect {
+
+    /**
+     * 全部数据权限
+     */
+    public static final String DATA_SCOPE_ALL = "1";
+
+    /**
+     * 自定数据权限
+     */
+    public static final String DATA_SCOPE_CUSTOM = "2";
+
+    /**
+     * 部门数据权限
+     */
+    public static final String DATA_SCOPE_DEPT = "3";
+
+    /**
+     * 部门及以下数据权限
+     */
+    public static final String DATA_SCOPE_DEPT_AND_CHILD = "4";
+
+    /**
+     * 仅本人数据权限
+     */
+    public static final String DATA_SCOPE_SELF = "5";
+
+    /**
+     * 数据权限过滤关键字
+     */
+    public static final String DATA_SCOPE = "dataScope";
+
+    @Before("@annotation(controllerDataScope)")
+    public void doBefore(JoinPoint point, DataScope controllerDataScope) throws Throwable {
+        clearDataScope(point);
+        handleDataScope(point, controllerDataScope);
+    }
+
+    protected void handleDataScope(final JoinPoint joinPoint, DataScope controllerDataScope) {
+        // 获取当前的用户
+        LoginUser loginUser = SecurityUtils.getLoginUser();
+        if (StringUtils.isNotNull(loginUser)) {
+            SysUser currentUser = loginUser.getUser();
+            // 如果是超级管理员,则不过滤数据
+            if (StringUtils.isNotNull(currentUser) && !currentUser.isAdmin()) {
+                String permission = StringUtils.defaultIfEmpty(controllerDataScope.permission(), PermissionContextHolder.getContext());
+                dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(), controllerDataScope.userAlias(), permission);
+            }
+        }
+    }
+
+    /**
+     * 数据范围过滤
+     *
+     * @param joinPoint  切点
+     * @param user       用户
+     * @param deptAlias  部门别名
+     * @param userAlias  用户别名
+     * @param permission 权限字符
+     */
+    public static void dataScopeFilter(JoinPoint joinPoint, SysUser user, String deptAlias, String userAlias, String permission) {
+        StringBuilder sqlString = new StringBuilder();
+        List<String> conditions = new ArrayList<String>();
+        List<String> scopeCustomIds = new ArrayList<String>();
+        user.getRoles().forEach(role -> {
+            if (DATA_SCOPE_CUSTOM.equals(role.getDataScope()) && StringUtils.equals(role.getStatus(), UserConstants.ROLE_NORMAL) && StringUtils.containsAny(role.getPermissions(), Convert.toStrArray(permission))) {
+                scopeCustomIds.add(Convert.toStr(role.getRoleId()));
+            }
+        });
+
+        for (SysRole role : user.getRoles()) {
+            String dataScope = role.getDataScope();
+            if (conditions.contains(dataScope) || StringUtils.equals(role.getStatus(), UserConstants.ROLE_DISABLE)) {
+                continue;
+            }
+            if (!StringUtils.containsAny(role.getPermissions(), Convert.toStrArray(permission))) {
+                continue;
+            }
+            if (DATA_SCOPE_ALL.equals(dataScope)) {
+                sqlString = new StringBuilder();
+                conditions.add(dataScope);
+                break;
+            } else if (DATA_SCOPE_CUSTOM.equals(dataScope)) {
+                if (scopeCustomIds.size() > 1) {
+                    // 多个自定数据权限使用in查询,避免多次拼接。
+                    sqlString.append(StringUtils.format(" OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id in ({}) ) ", deptAlias, String.join(",", scopeCustomIds)));
+                } else {
+                    sqlString.append(StringUtils.format(" OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ", deptAlias, role.getRoleId()));
+                }
+            } else if (DATA_SCOPE_DEPT.equals(dataScope)) {
+                sqlString.append(StringUtils.format(" OR {}.dept_id = {} ", deptAlias, user.getDeptId()));
+            } else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope)) {
+                sqlString.append(StringUtils.format(" OR {}.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )", deptAlias, user.getDeptId(), user.getDeptId()));
+            } else if (DATA_SCOPE_SELF.equals(dataScope)) {
+                if (StringUtils.isNotBlank(userAlias)) {
+                    sqlString.append(StringUtils.format(" OR {}.user_id = {} ", userAlias, user.getUserId()));
+                } else {
+                    // 数据权限为仅本人且没有userAlias别名不查询任何数据
+                    sqlString.append(StringUtils.format(" OR {}.dept_id = 0 ", deptAlias));
+                }
+            }
+            conditions.add(dataScope);
+        }
+
+        // 角色都不包含传递过来的权限字符,这个时候sqlString也会为空,所以要限制一下,不查询任何数据
+        if (StringUtils.isEmpty(conditions)) {
+            sqlString.append(StringUtils.format(" OR {}.dept_id = 0 ", deptAlias));
+        }
+
+        if (StringUtils.isNotBlank(sqlString.toString())) {
+            Object params = joinPoint.getArgs()[0];
+            if (StringUtils.isNotNull(params) && params instanceof BaseEntity) {
+                BaseEntity baseEntity = (BaseEntity) params;
+                baseEntity.getParams().put(DATA_SCOPE, " AND (" + sqlString.substring(4) + ")");
+            }
+        }
+    }
+
+    /**
+     * 拼接权限sql前先清空params.dataScope参数防止注入
+     */
+    private void clearDataScope(final JoinPoint joinPoint) {
+        Object params = joinPoint.getArgs()[0];
+        if (StringUtils.isNotNull(params) && params instanceof BaseEntity) {
+            BaseEntity baseEntity = (BaseEntity) params;
+            baseEntity.getParams().put(DATA_SCOPE, "");
+        }
+    }
+}

+ 18 - 0
himeeter-framework/src/main/java/com/lij/himeeter/framework/aspectj/DataSourceAspect.java

@@ -0,0 +1,18 @@
+package com.lij.himeeter.framework.aspectj;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  DataSourceAspect
+ * 创建时间 : 2024年12月27日 17:29
+ *
+ * 文件描述 : 无
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class DataSourceAspect {
+}

+ 230 - 0
himeeter-framework/src/main/java/com/lij/himeeter/framework/aspectj/LogAspect.java

@@ -0,0 +1,230 @@
+package com.lij.himeeter.framework.aspectj;
+
+import com.alibaba.fastjson2.JSON;
+import com.lij.himeeter.common.annotation.Log;
+import com.lij.himeeter.common.core.domain.entity.SysUser;
+import com.lij.himeeter.common.core.domain.model.LoginUser;
+import com.lij.himeeter.common.enums.BusinessStatus;
+import com.lij.himeeter.common.utils.SecurityUtils;
+import com.lij.himeeter.common.utils.ServletUtils;
+import com.lij.himeeter.common.utils.StringUtils;
+import com.lij.himeeter.common.utils.ip.IpUtils;
+import com.lij.himeeter.framework.manager.AsyncManager;
+import com.lij.himeeter.system.domin.SysOperLog;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.apache.commons.lang3.ArrayUtils;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.AfterReturning;
+import org.aspectj.lang.annotation.AfterThrowing;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.core.NamedThreadLocal;
+import org.springframework.http.HttpMethod;
+import org.springframework.stereotype.Component;
+import org.springframework.validation.BindingResult;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  LogAspect
+ * 创建时间 : 2024年12月27日 17:30
+ *
+ * 文件描述 : 操作日志记录处理
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+@Aspect
+@Component
+public class LogAspect {
+    public static final Logger log = LoggerFactory.getLogger(LogAspect.class);
+
+    /**
+     * 排除敏感属性字段
+     */
+    public static final String[] EXCLUDE_PROPERTIES = {"password", "oldPassword", "newPassword", "confirmPassword"};
+
+    /**
+     * 计算操作消耗时间
+     */
+    private static final ThreadLocal<Long> TIME_THREADLOCAL = new NamedThreadLocal<Long>("Cost Time");
+
+    /**
+     * 处理请求前执行
+     */
+    @Before(value = "@annotation(controllerLog)")
+    public void boBefore(JoinPoint joinPoint, Log controllerLog) {
+        TIME_THREADLOCAL.set(System.currentTimeMillis());
+    }
+
+    /**
+     * 处理完请求后执行
+     *
+     * @param joinPoint 切点
+     */
+    @AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")
+    public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult) {
+        handleLog(joinPoint, controllerLog, null, jsonResult);
+    }
+
+    /**
+     * 拦截异常操作
+     *
+     * @param joinPoint 切点
+     * @param e         异常
+     */
+    @AfterThrowing(value = "@annotation(controllerLog)", throwing = "e")
+    public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e) {
+        handleLog(joinPoint, controllerLog, e, null);
+    }
+
+    protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult) {
+        try {
+            // 获取当前的用户
+            LoginUser loginUser = SecurityUtils.getLoginUser();
+
+            // *========数据库日志=========*//
+            SysOperLog operLog = new SysOperLog();
+            operLog.setStatus(BusinessStatus.SUCCESS.ordinal());
+            // 请求的地址
+            String ip = IpUtils.getIpAddr();
+            operLog.setOperIp(ip);
+            operLog.setOperUrl(StringUtils.substring(ServletUtils.getRequest().getRequestURI(), 0, 255));
+            if (loginUser != null) {
+                operLog.setOperName(loginUser.getUsername());
+                SysUser currentUser = loginUser.getUser();
+                if (StringUtils.isNotNull(currentUser) && StringUtils.isNotNull(currentUser.getDept())) {
+                    operLog.setDeptName(currentUser.getDept().getDeptName());
+                }
+            }
+
+            if (e != null) {
+                operLog.setStatus(BusinessStatus.FAIL.ordinal());
+                operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000));
+            }
+            // 设置方法名称
+            String className = joinPoint.getTarget().getClass().getName();
+            String methodName = joinPoint.getSignature().getName();
+            operLog.setMethod(className + "." + methodName + "()");
+            // 设置请求方式
+            operLog.setRequestMethod(ServletUtils.getRequest().getMethod());
+            // 处理设置注解上的参数
+            getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult);
+            // 设置消耗时间
+            operLog.setCostTime(System.currentTimeMillis() - TIME_THREADLOCAL.get());
+            // 保存数据库
+            AsyncManager.me().execute(AsyncFactory.recordOper(operLog));
+        } catch (Exception exp) {
+            // 记录本地异常日志
+            log.error("异常信息:{}", exp.getMessage());
+            exp.printStackTrace();
+        } finally {
+            TIME_THREADLOCAL.remove();
+        }
+    }
+
+    /**
+     * 获取注解中对方法的描述信息 用于Controller层注解
+     *
+     * @param log     日志
+     * @param operLog 操作日志
+     * @throws Exception
+     */
+    public void getControllerMethodDescription(JoinPoint joinPoint, Log log, SysOperLog operLog, Object jsonResult) throws Exception {
+        // 设置action动作
+        operLog.setBusinessType(log.businessType().ordinal());
+        // 设置标题
+        operLog.setTitle(log.title());
+        // 设置操作人类别
+        operLog.setOperatorType(log.operatorType().ordinal());
+        // 是否需要保存request,参数和值
+        if (log.isSaveRequestData()) {
+            // 获取参数的信息,传入到数据库中。
+            setRequestValue(joinPoint, operLog, log.excludeParamNames());
+        }
+        // 是否需要保存response,参数和值
+        if (log.isSaveResponseData() && StringUtils.isNotNull(jsonResult)) {
+            operLog.setJsonResult(StringUtils.substring(JSON.toJSONString(jsonResult), 0, 2000));
+        }
+    }
+
+    /**
+     * 获取请求的参数,放到log中
+     *
+     * @param operLog 操作日志
+     * @throws Exception 异常
+     */
+    private void setRequestValue(JoinPoint joinPoint, SysOperLog operLog, String[] excludeParamNames) throws Exception {
+        Map<?, ?> paramsMap = ServletUtils.getParamMap(ServletUtils.getRequest());
+        String requestMethod = operLog.getRequestMethod();
+        if (StringUtils.isEmpty(paramsMap) && StringUtils.equalsAny(requestMethod, HttpMethod.PUT.name(), HttpMethod.POST.name(), HttpMethod.DELETE.name())) {
+            String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames);
+            operLog.setOperParam(StringUtils.substring(params, 0, 2000));
+        } else {
+            operLog.setOperParam(StringUtils.substring(JSON.toJSONString(paramsMap, excludePropertyPreFilter(excludeParamNames)), 0, 2000));
+        }
+    }
+
+    /**
+     * 参数拼装
+     */
+    private String argsArrayToString(Object[] paramsArray, String[] excludeParamNames) {
+        String params = "";
+        if (paramsArray != null && paramsArray.length > 0) {
+            for (Object o : paramsArray) {
+                if (StringUtils.isNotNull(o) && !isFilterObject(o)) {
+                    try {
+                        String jsonObj = JSON.toJSONString(o, excludePropertyPreFilter(excludeParamNames));
+                        params += jsonObj.toString() + " ";
+                    } catch (Exception e) {
+                    }
+                }
+            }
+        }
+        return params.trim();
+    }
+
+    /**
+     * 忽略敏感属性
+     */
+    public PropertyPreExcludeFilter excludePropertyPreFilter(String[] excludeParamNames) {
+        return new PropertyPreExcludeFilter().addExcludes(ArrayUtils.addAll(EXCLUDE_PROPERTIES, excludeParamNames));
+    }
+
+    /**
+     * 判断是否需要过滤的对象。
+     *
+     * @param o 对象信息。
+     * @return 如果是需要过滤的对象,则返回true;否则返回false。
+     */
+    @SuppressWarnings("rawtypes")
+    public boolean isFilterObject(final Object o) {
+        Class<?> clazz = o.getClass();
+        if (clazz.isArray()) {
+            return clazz.getComponentType().isAssignableFrom(MultipartFile.class);
+        } else if (Collection.class.isAssignableFrom(clazz)) {
+            Collection collection = (Collection) o;
+            for (Object value : collection) {
+                return value instanceof MultipartFile;
+            }
+        } else if (Map.class.isAssignableFrom(clazz)) {
+            Map map = (Map) o;
+            for (Object value : map.entrySet()) {
+                Map.Entry entry = (Map.Entry) value;
+                return entry.getValue() instanceof MultipartFile;
+            }
+        }
+        return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse
+                || o instanceof BindingResult;
+    }
+}

+ 18 - 0
himeeter-framework/src/main/java/com/lij/himeeter/framework/aspectj/RateLimiterAspect.java

@@ -0,0 +1,18 @@
+package com.lij.himeeter.framework.aspectj;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  RateLimiterAspect
+ * 创建时间 : 2024年12月27日 17:30
+ *
+ * 文件描述 : 无
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class RateLimiterAspect {
+}

+ 64 - 0
himeeter-framework/src/main/java/com/lij/himeeter/framework/manager/AsyncManager.java

@@ -0,0 +1,64 @@
+package com.lij.himeeter.framework.manager;
+
+import com.lij.himeeter.common.utils.Threads;
+import com.lij.himeeter.common.utils.spring.SpringUtils;
+
+import java.util.TimerTask;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  AsyncManager
+ * 创建时间 : 2024年12月30日 14:56
+ *
+ * 文件描述 : 异步任务管理器
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class AsyncManager {
+
+    /**
+     * 操作延迟10毫秒
+     */
+    private final int OPERATE_DELAY_TIME = 10;
+
+    /**
+     * 异步操作任务调度线程池
+     */
+    private ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService");
+
+    /**
+     * 单例模式
+     */
+    private AsyncManager() {
+    }
+
+    private static AsyncManager me = new AsyncManager();
+
+    public static AsyncManager me() {
+        return me;
+    }
+
+    /**
+     * 执行任务
+     *
+     * @param task 任务
+     */
+    public void execute(TimerTask task) {
+        executor.schedule(task, OPERATE_DELAY_TIME, TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * 停止任务线程池
+     */
+    public void shutdown() {
+        Threads.shutdownAndAwaitTermination(executor);
+    }
+
+}

+ 103 - 0
himeeter-framework/src/main/java/com/lij/himeeter/framework/manager/factory/AsyncFactory.java

@@ -0,0 +1,103 @@
+package com.lij.himeeter.framework.manager.factory;
+
+import com.lij.himeeter.common.constant.Constants;
+import com.lij.himeeter.common.utils.LogUtils;
+import com.lij.himeeter.common.utils.ServletUtils;
+import com.lij.himeeter.common.utils.StringUtils;
+import com.lij.himeeter.common.utils.ip.AddressUtils;
+import com.lij.himeeter.common.utils.ip.IpUtils;
+import com.lij.himeeter.common.utils.spring.SpringUtils;
+import com.lij.himeeter.system.domin.SysLogininfor;
+import com.lij.himeeter.system.domin.SysOperLog;
+import com.lij.himeeter.system.service.ISysLogininforService;
+import com.lij.himeeter.system.service.ISysOperLogService;
+import eu.bitwalker.useragentutils.UserAgent;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.TimerTask;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  AsyncFactory
+ * 创建时间 : 2024年12月30日 15:02
+ *
+ * 文件描述 : 异步工厂(产生任务用)
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class AsyncFactory {
+
+    private static final Logger sys_user_logger = LoggerFactory.getLogger("sys-user");
+
+    /**
+     * 记录登录信息
+     *
+     * @param username 用户名
+     * @param status   状态
+     * @param message  消息
+     * @param args     列表
+     * @return 任务task
+     */
+    public static TimerTask recordLogininfor(final String username, final String status, final String message,
+                                             final Object... args) {
+        final UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
+        final String ip = IpUtils.getIpAddr();
+        return new TimerTask() {
+            @Override
+            public void run() {
+                String address = AddressUtils.getRealAddressByIP(ip);
+                StringBuilder s = new StringBuilder();
+                s.append(LogUtils.getBlock(ip));
+                s.append(address);
+                s.append(LogUtils.getBlock(username));
+                s.append(LogUtils.getBlock(status));
+                s.append(LogUtils.getBlock(message));
+                // 打印信息到日志
+                sys_user_logger.info(s.toString(), args);
+                // 获取客户端操作系统
+                String os = userAgent.getOperatingSystem().getName();
+                // 获取客户端浏览器
+                String browser = userAgent.getBrowser().getName();
+                // 封装对象
+                SysLogininfor logininfor = new SysLogininfor();
+                logininfor.setUserName(username);
+                logininfor.setIpaddr(ip);
+                logininfor.setLoginLocation(address);
+                logininfor.setBrowser(browser);
+                logininfor.setOs(os);
+                logininfor.setMsg(message);
+                // 日志状态
+                if (StringUtils.equalsAny(status, Constants.LOGIN_SUCCESS, Constants.LOGOUT, Constants.REGISTER)) {
+                    logininfor.setStatus(Constants.SUCCESS);
+                } else if (Constants.LOGIN_FAIL.equals(status)) {
+                    logininfor.setStatus(Constants.FAIL);
+                }
+                // 插入数据
+                SpringUtils.getBean(ISysLogininforService.class).insertLogininfor(logininfor);
+            }
+        };
+    }
+
+    /**
+     * 操作日志记录
+     *
+     * @param operLog 操作日志信息
+     * @return 任务task
+     */
+    public static TimerTask recordOper(final SysOperLog operLog) {
+        return new TimerTask() {
+            @Override
+            public void run() {
+                // 远程查询操作地点
+                operLog.setOperLocation(AddressUtils.getRealAddressByIP(operLog.getOperIp()));
+                SpringUtils.getBean(ISysOperLogService.class).insertOperlog(operLog);
+            }
+        };
+    }
+}

+ 34 - 0
himeeter-framework/src/main/java/com/lij/himeeter/framework/security/context/PermissionContextHolder.java

@@ -0,0 +1,34 @@
+package com.lij.himeeter.framework.security.context;
+
+import com.lij.himeeter.common.core.text.Convert;
+import org.springframework.web.context.request.RequestAttributes;
+import org.springframework.web.context.request.RequestContextHolder;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  PermissionContextHolder
+ * 创建时间 : 2024年12月27日 16:20
+ *
+ * 文件描述 : 权限信息
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class PermissionContextHolder {
+
+    private static final String PERMISSION_CONTEXT_ATTRIBUTES = "PERMISSION_CONTEXT";
+
+    public static void setContext(String permission) {
+        RequestContextHolder.currentRequestAttributes().setAttribute(PERMISSION_CONTEXT_ATTRIBUTES, permission,
+                RequestAttributes.SCOPE_REQUEST);
+    }
+
+    public static String getContext() {
+        return Convert.toStr(RequestContextHolder.currentRequestAttributes().getAttribute(PERMISSION_CONTEXT_ATTRIBUTES,
+                RequestAttributes.SCOPE_REQUEST));
+    }
+}

+ 18 - 0
himeeter-framework/src/main/java/com/lij/himeeter/framework/web/domain/Server.java

@@ -0,0 +1,18 @@
+package com.lij.himeeter.framework.web.domain;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  Server
+ * 创建时间 : 2024年12月16日 18:51
+ *
+ * 文件描述 : 无
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class Server {
+}

+ 48 - 0
himeeter-framework/src/main/java/com/lij/himeeter/framework/web/domain/server/Cpu.java

@@ -0,0 +1,48 @@
+package com.lij.himeeter.framework.web.domain.server;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  Cpu
+ * 创建时间 : 2024年12月16日 18:52
+ *
+ * 文件描述 : CPU相关信息
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class Cpu {
+
+    /**
+     * 核心数
+     */
+    private int cpuNum;
+
+    /**
+     * CPU总的使用率
+     */
+    private double total;
+
+    /**
+     * CPU系统使用率
+     */
+    private double sys;
+
+    /**
+     * CPU用户使用率
+     */
+    private double used;
+
+    /**
+     * CPU当前等待率
+     */
+    private double wait;
+
+    /**
+     * CPU当前空闲率
+     */
+    private double free;
+}

+ 44 - 0
himeeter-framework/src/main/java/com/lij/himeeter/framework/web/domain/server/Jvm.java

@@ -0,0 +1,44 @@
+package com.lij.himeeter.framework.web.domain.server;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  Jvm
+ * 创建时间 : 2024年12月16日 18:53
+ * 文件描述 : JVM相关信息
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class Jvm {
+
+    /**
+     * 当前JVM占用的内存总数(M)
+     */
+    private double total;
+
+    /**
+     * JVM最大可用内存总数(M)
+     */
+    private double max;
+
+    /**
+     * JVM空闲内存(M)
+     */
+    private double free;
+
+    /**
+     * JDK版本
+     */
+    private String version;
+
+    /**
+     * JDK路径
+     */
+    private String home;
+
+
+}

+ 18 - 0
himeeter-framework/src/main/java/com/lij/himeeter/framework/web/domain/server/Mem.java

@@ -0,0 +1,18 @@
+package com.lij.himeeter.framework.web.domain.server;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  Mem
+ * 创建时间 : 2024年12月16日 18:53
+ *
+ * 文件描述 : 无
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class Mem {
+}

+ 18 - 0
himeeter-framework/src/main/java/com/lij/himeeter/framework/web/domain/server/Sys.java

@@ -0,0 +1,18 @@
+package com.lij.himeeter.framework.web.domain.server;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  Sys
+ * 创建时间 : 2024年12月16日 18:54
+ *
+ * 文件描述 : 无
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class Sys {
+}

+ 18 - 0
himeeter-framework/src/main/java/com/lij/himeeter/framework/web/domain/server/SysFile.java

@@ -0,0 +1,18 @@
+package com.lij.himeeter.framework.web.domain.server;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SysFile
+ * 创建时间 : 2024年12月16日 18:54
+ *
+ * 文件描述 : 无
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class SysFile {
+}

+ 0 - 1
himeeter-framework/src/main/resources/application.properties

@@ -1 +0,0 @@
-spring.application.name=himeeter-framework

+ 0 - 13
himeeter-framework/src/test/java/com/lij/himeeter/framework/HimeeterFrameworkApplicationTests.java

@@ -1,13 +0,0 @@
-package com.lij.himeeter.framework;
-
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-
-@SpringBootTest
-class HimeeterFrameworkApplicationTests {
-
-    @Test
-    void contextLoads() {
-    }
-
-}

+ 0 - 13
himeeter-generator/src/test/java/com/lij/himeeter/generator/HimeeterGeneratorApplicationTests.java

@@ -1,13 +0,0 @@
-package com.lij.himeeter.generator;
-
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-
-@SpringBootTest
-class HimeeterGeneratorApplicationTests {
-
-    @Test
-    void contextLoads() {
-    }
-
-}

+ 0 - 13
himeeter-quartz/src/test/java/com/lij/himeeter/quartz/HimeeterQuartzApplicationTests.java

@@ -1,13 +0,0 @@
-package com.lij.himeeter.quartz;
-
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-
-@SpringBootTest
-class HimeeterQuartzApplicationTests {
-
-    @Test
-    void contextLoads() {
-    }
-
-}

+ 0 - 13
himeeter-system/src/main/java/com/lij/himeeter/system/HimeeterSystemApplication.java

@@ -1,13 +0,0 @@
-package com.lij.himeeter.system;
-
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-
-@SpringBootApplication
-public class HimeeterSystemApplication {
-
-    public static void main(String[] args) {
-        SpringApplication.run(HimeeterSystemApplication.class, args);
-    }
-
-}

+ 18 - 0
himeeter-system/src/main/java/com/lij/himeeter/system/domin/SysCache.java

@@ -0,0 +1,18 @@
+package com.lij.himeeter.system.domin;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SysCache
+ * 创建时间 : 2024年12月30日 15:36
+ *
+ * 文件描述 : 无
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class SysCache {
+}

+ 120 - 0
himeeter-system/src/main/java/com/lij/himeeter/system/domin/SysConfig.java

@@ -0,0 +1,120 @@
+package com.lij.himeeter.system.domin;
+
+import com.lij.himeeter.common.annotation.Excel;
+import com.lij.himeeter.common.annotation.Excel.ColumnType;
+import com.lij.himeeter.common.core.domain.BaseEntity;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.Size;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SysConfig
+ * 创建时间 : 2024年12月30日 15:36
+ *
+ * 文件描述 : 无
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class SysConfig extends BaseEntity {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 参数主键
+     */
+    @Excel(name = "参数主键", cellType = ColumnType.NUMERIC)
+    private Long configId;
+
+    /**
+     * 参数名称
+     */
+    @Excel(name = "参数名称")
+    private String configName;
+
+    /**
+     * 参数键名
+     */
+    @Excel(name = "参数键名")
+    private String configKey;
+
+    /**
+     * 参数键值
+     */
+    @Excel(name = "参数键值")
+    private String configValue;
+
+    /**
+     * 系统内置(Y是 N否)
+     */
+    @Excel(name = "系统内置", readConverterExp = "Y=是,N=否")
+    private String configType;
+
+    public Long getConfigId() {
+        return configId;
+    }
+
+    public void setConfigId(Long configId) {
+        this.configId = configId;
+    }
+
+    @NotBlank(message = "参数名称不能为空")
+    @Size(min = 0, max = 100, message = "参数名称不能超过100个字符")
+    public String getConfigName() {
+        return configName;
+    }
+
+    public void setConfigName(String configName) {
+        this.configName = configName;
+    }
+
+    @NotBlank(message = "参数键名长度不能为空")
+    @Size(min = 0, max = 100, message = "参数键名长度不能超过100个字符")
+    public String getConfigKey() {
+        return configKey;
+    }
+
+    public void setConfigKey(String configKey) {
+        this.configKey = configKey;
+    }
+
+    @NotBlank(message = "参数键值不能为空")
+    @Size(min = 0, max = 500, message = "参数键值长度不能超过500个字符")
+    public String getConfigValue() {
+        return configValue;
+    }
+
+    public void setConfigValue(String configValue) {
+        this.configValue = configValue;
+    }
+
+    public String getConfigType() {
+        return configType;
+    }
+
+    public void setConfigType(String configType) {
+        this.configType = configType;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+                .append("configId", getConfigId())
+                .append("configName", getConfigName())
+                .append("configKey", getConfigKey())
+                .append("configValue", getConfigValue())
+                .append("configType", getConfigType())
+                .append("createBy", getCreateBy())
+                .append("createTime", getCreateTime())
+                .append("updateBy", getUpdateBy())
+                .append("updateTime", getUpdateTime())
+                .append("remark", getRemark())
+                .toString();
+    }
+}

+ 155 - 0
himeeter-system/src/main/java/com/lij/himeeter/system/domin/SysLogininfor.java

@@ -0,0 +1,155 @@
+package com.lij.himeeter.system.domin;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.lij.himeeter.common.annotation.Excel;
+import com.lij.himeeter.common.annotation.Excel.ColumnType;
+import com.lij.himeeter.common.core.domain.BaseEntity;
+
+import java.util.Date;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SysLogininfor
+ * 创建时间 : 2024年12月30日 15:14
+ *
+ * 文件描述 : 系统访问记录表 sys_logininfor
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class SysLogininfor extends BaseEntity {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * ID
+     */
+    @Excel(name = "序号", cellType = ColumnType.NUMERIC)
+    private Long infoId;
+
+    /**
+     * 用户账号
+     */
+    @Excel(name = "用户账号")
+    private String userName;
+
+    /**
+     * 登录状态 0成功 1失败
+     */
+    @Excel(name = "登录状态", readConverterExp = "0=成功,1=失败")
+    private String status;
+
+    /**
+     * 登录IP地址
+     */
+    @Excel(name = "登录地址")
+    private String ipaddr;
+
+    /**
+     * 登录地点
+     */
+    @Excel(name = "登录地点")
+    private String loginLocation;
+
+    /**
+     * 浏览器类型
+     */
+    @Excel(name = "浏览器")
+    private String browser;
+
+    /**
+     * 操作系统
+     */
+    @Excel(name = "操作系统")
+    private String os;
+
+    /**
+     * 提示消息
+     */
+    @Excel(name = "提示消息")
+    private String msg;
+
+    /**
+     * 访问时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "访问时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    private Date loginTime;
+
+    public Long getInfoId() {
+        return infoId;
+    }
+
+    public void setInfoId(Long infoId) {
+        this.infoId = infoId;
+    }
+
+    public String getUserName() {
+        return userName;
+    }
+
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public String getIpaddr() {
+        return ipaddr;
+    }
+
+    public void setIpaddr(String ipaddr) {
+        this.ipaddr = ipaddr;
+    }
+
+    public String getLoginLocation() {
+        return loginLocation;
+    }
+
+    public void setLoginLocation(String loginLocation) {
+        this.loginLocation = loginLocation;
+    }
+
+    public String getBrowser() {
+        return browser;
+    }
+
+    public void setBrowser(String browser) {
+        this.browser = browser;
+    }
+
+    public String getOs() {
+        return os;
+    }
+
+    public void setOs(String os) {
+        this.os = os;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public void setMsg(String msg) {
+        this.msg = msg;
+    }
+
+    public Date getLoginTime() {
+        return loginTime;
+    }
+
+    public void setLoginTime(Date loginTime) {
+        this.loginTime = loginTime;
+    }
+
+}

+ 110 - 0
himeeter-system/src/main/java/com/lij/himeeter/system/domin/SysNotice.java

@@ -0,0 +1,110 @@
+package com.lij.himeeter.system.domin;
+
+import com.lij.himeeter.common.core.domain.BaseEntity;
+import com.lij.himeeter.common.xss.Xss;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.Size;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SysNotice
+ * 创建时间 : 2024年12月30日 15:37
+ *
+ * 文件描述 : 无
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class SysNotice extends BaseEntity {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 公告ID
+     */
+    private Long noticeId;
+
+    /**
+     * 公告标题
+     */
+    private String noticeTitle;
+
+    /**
+     * 公告类型(1通知 2公告)
+     */
+    private String noticeType;
+
+    /**
+     * 公告内容
+     */
+    private String noticeContent;
+
+    /**
+     * 公告状态(0正常 1关闭)
+     */
+    private String status;
+
+    public Long getNoticeId() {
+        return noticeId;
+    }
+
+    public void setNoticeId(Long noticeId) {
+        this.noticeId = noticeId;
+    }
+
+    public void setNoticeTitle(String noticeTitle) {
+        this.noticeTitle = noticeTitle;
+    }
+
+    @Xss(message = "公告标题不能包含脚本字符")
+    @NotBlank(message = "公告标题不能为空")
+    @Size(min = 0, max = 50, message = "公告标题不能超过50个字符")
+    public String getNoticeTitle() {
+        return noticeTitle;
+    }
+
+    public void setNoticeType(String noticeType) {
+        this.noticeType = noticeType;
+    }
+
+    public String getNoticeType() {
+        return noticeType;
+    }
+
+    public void setNoticeContent(String noticeContent) {
+        this.noticeContent = noticeContent;
+    }
+
+    public String getNoticeContent() {
+        return noticeContent;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+                .append("noticeId", getNoticeId())
+                .append("noticeTitle", getNoticeTitle())
+                .append("noticeType", getNoticeType())
+                .append("noticeContent", getNoticeContent())
+                .append("status", getStatus())
+                .append("createBy", getCreateBy())
+                .append("createTime", getCreateTime())
+                .append("updateBy", getUpdateBy())
+                .append("updateTime", getUpdateTime())
+                .append("remark", getRemark())
+                .toString();
+    }
+}

+ 280 - 0
himeeter-system/src/main/java/com/lij/himeeter/system/domin/SysOperLog.java

@@ -0,0 +1,280 @@
+package com.lij.himeeter.system.domin;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.lij.himeeter.common.annotation.Excel;
+import com.lij.himeeter.common.annotation.Excel.ColumnType;
+import com.lij.himeeter.common.core.domain.BaseEntity;
+
+import java.util.Date;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SysOperLog
+ * 创建时间 : 2024年12月30日 03:25
+ *
+ * 文件描述 : 操作日志记录表 oper_log
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class SysOperLog extends BaseEntity {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 日志主键
+     */
+    @Excel(name = "操作序号", cellType = ColumnType.NUMERIC)
+    private Long operId;
+
+    /**
+     * 操作模块
+     */
+    @Excel(name = "操作模块")
+    private String title;
+
+    /**
+     * 业务类型(0其它 1新增 2修改 3删除)
+     */
+    @Excel(name = "业务类型", readConverterExp = "0=其它,1=新增,2=修改,3=删除,4=授权,5=导出,6=导入,7=强退,8=生成代码,9=清空数据")
+    private Integer businessType;
+
+    /**
+     * 业务类型数组
+     */
+    private Integer[] businessTypes;
+
+    /**
+     * 请求方法
+     */
+    @Excel(name = "请求方法")
+    private String method;
+
+    /**
+     * 请求方式
+     */
+    @Excel(name = "请求方式")
+    private String requestMethod;
+
+    /**
+     * 操作类别(0其它 1后台用户 2手机端用户)
+     */
+    @Excel(name = "操作类别", readConverterExp = "0=其它,1=后台用户,2=手机端用户")
+    private Integer operatorType;
+
+    /**
+     * 操作人员
+     */
+    @Excel(name = "操作人员")
+    private String operName;
+
+    /**
+     * 部门名称
+     */
+    @Excel(name = "部门名称")
+    private String deptName;
+
+    /**
+     * 请求url
+     */
+    @Excel(name = "请求地址")
+    private String operUrl;
+
+    /**
+     * 操作地址
+     */
+    @Excel(name = "操作地址")
+    private String operIp;
+
+    /**
+     * 操作地点
+     */
+    @Excel(name = "操作地点")
+    private String operLocation;
+
+    /**
+     * 请求参数
+     */
+    @Excel(name = "请求参数")
+    private String operParam;
+
+    /**
+     * 返回参数
+     */
+    @Excel(name = "返回参数")
+    private String jsonResult;
+
+    /**
+     * 操作状态(0正常 1异常)
+     */
+    @Excel(name = "状态", readConverterExp = "0=正常,1=异常")
+    private Integer status;
+
+    /**
+     * 错误消息
+     */
+    @Excel(name = "错误消息")
+    private String errorMsg;
+
+    /**
+     * 操作时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "操作时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    private Date operTime;
+
+    /**
+     * 消耗时间
+     */
+    @Excel(name = "消耗时间", suffix = "毫秒")
+    private Long costTime;
+
+    public Long getOperId() {
+        return operId;
+    }
+
+    public void setOperId(Long operId) {
+        this.operId = operId;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public Integer getBusinessType() {
+        return businessType;
+    }
+
+    public void setBusinessType(Integer businessType) {
+        this.businessType = businessType;
+    }
+
+    public Integer[] getBusinessTypes() {
+        return businessTypes;
+    }
+
+    public void setBusinessTypes(Integer[] businessTypes) {
+        this.businessTypes = businessTypes;
+    }
+
+    public String getMethod() {
+        return method;
+    }
+
+    public void setMethod(String method) {
+        this.method = method;
+    }
+
+    public String getRequestMethod() {
+        return requestMethod;
+    }
+
+    public void setRequestMethod(String requestMethod) {
+        this.requestMethod = requestMethod;
+    }
+
+    public Integer getOperatorType() {
+        return operatorType;
+    }
+
+    public void setOperatorType(Integer operatorType) {
+        this.operatorType = operatorType;
+    }
+
+    public String getOperName() {
+        return operName;
+    }
+
+    public void setOperName(String operName) {
+        this.operName = operName;
+    }
+
+    public String getDeptName() {
+        return deptName;
+    }
+
+    public void setDeptName(String deptName) {
+        this.deptName = deptName;
+    }
+
+    public String getOperUrl() {
+        return operUrl;
+    }
+
+    public void setOperUrl(String operUrl) {
+        this.operUrl = operUrl;
+    }
+
+    public String getOperIp() {
+        return operIp;
+    }
+
+    public void setOperIp(String operIp) {
+        this.operIp = operIp;
+    }
+
+    public String getOperLocation() {
+        return operLocation;
+    }
+
+    public void setOperLocation(String operLocation) {
+        this.operLocation = operLocation;
+    }
+
+    public String getOperParam() {
+        return operParam;
+    }
+
+    public void setOperParam(String operParam) {
+        this.operParam = operParam;
+    }
+
+    public String getJsonResult() {
+        return jsonResult;
+    }
+
+    public void setJsonResult(String jsonResult) {
+        this.jsonResult = jsonResult;
+    }
+
+    public Integer getStatus() {
+        return status;
+    }
+
+    public void setStatus(Integer status) {
+        this.status = status;
+    }
+
+    public String getErrorMsg() {
+        return errorMsg;
+    }
+
+    public void setErrorMsg(String errorMsg) {
+        this.errorMsg = errorMsg;
+    }
+
+    public Date getOperTime() {
+        return operTime;
+    }
+
+    public void setOperTime(Date operTime) {
+        this.operTime = operTime;
+    }
+
+    public Long getCostTime() {
+        return costTime;
+    }
+
+    public void setCostTime(Long costTime) {
+        this.costTime = costTime;
+    }
+
+}

+ 132 - 0
himeeter-system/src/main/java/com/lij/himeeter/system/domin/SysPost.java

@@ -0,0 +1,132 @@
+package com.lij.himeeter.system.domin;
+
+import com.lij.himeeter.common.annotation.Excel;
+import com.lij.himeeter.common.annotation.Excel.ColumnType;
+import com.lij.himeeter.common.core.domain.BaseEntity;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SysPost
+ * 创建时间 : 2024年12月30日 03:24
+ *
+ * 文件描述 : 岗位表 sys_post
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class SysPost extends BaseEntity {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 岗位序号
+     */
+    @Excel(name = "岗位序号", cellType = ColumnType.NUMERIC)
+    private Long postId;
+
+    /**
+     * 岗位编码
+     */
+    @Excel(name = "岗位编码")
+    private String postCode;
+
+    /**
+     * 岗位名称
+     */
+    @Excel(name = "岗位名称")
+    private String postName;
+
+    /**
+     * 岗位排序
+     */
+    @Excel(name = "岗位排序")
+    private Integer postSort;
+
+    /**
+     * 状态(0正常 1停用)
+     */
+    @Excel(name = "状态", readConverterExp = "0=正常,1=停用")
+    private String status;
+
+    /**
+     * 用户是否存在此岗位标识 默认不存在
+     */
+    private boolean flag = false;
+
+    public Long getPostId() {
+        return postId;
+    }
+
+    public void setPostId(Long postId) {
+        this.postId = postId;
+    }
+
+    @NotBlank(message = "岗位编码不能为空")
+    @Size(min = 0, max = 64, message = "岗位编码长度不能超过64个字符")
+    public String getPostCode() {
+        return postCode;
+    }
+
+    public void setPostCode(String postCode) {
+        this.postCode = postCode;
+    }
+
+    @NotBlank(message = "岗位名称不能为空")
+    @Size(min = 0, max = 50, message = "岗位名称长度不能超过50个字符")
+    public String getPostName() {
+        return postName;
+    }
+
+    public void setPostName(String postName) {
+        this.postName = postName;
+    }
+
+    @NotNull(message = "显示顺序不能为空")
+    public Integer getPostSort() {
+        return postSort;
+    }
+
+    public void setPostSort(Integer postSort) {
+        this.postSort = postSort;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public boolean isFlag() {
+        return flag;
+    }
+
+    public void setFlag(boolean flag) {
+        this.flag = flag;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+                .append("postId", getPostId())
+                .append("postCode", getPostCode())
+                .append("postName", getPostName())
+                .append("postSort", getPostSort())
+                .append("status", getStatus())
+                .append("createBy", getCreateBy())
+                .append("createTime", getCreateTime())
+                .append("updateBy", getUpdateBy())
+                .append("updateTime", getUpdateTime())
+                .append("remark", getRemark())
+                .toString();
+    }
+}

+ 55 - 0
himeeter-system/src/main/java/com/lij/himeeter/system/domin/SysRoleDept.java

@@ -0,0 +1,55 @@
+package com.lij.himeeter.system.domin;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SysRoleDept
+ * 创建时间 : 2024年12月30日 15:38
+ *
+ * 文件描述 : 角色和部门关联 sys_role_dept
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class SysRoleDept {
+
+    /**
+     * 角色ID
+     */
+    private Long roleId;
+
+    /**
+     * 部门ID
+     */
+    private Long deptId;
+
+    public Long getRoleId() {
+        return roleId;
+    }
+
+    public void setRoleId(Long roleId) {
+        this.roleId = roleId;
+    }
+
+    public Long getDeptId() {
+        return deptId;
+    }
+
+    public void setDeptId(Long deptId) {
+        this.deptId = deptId;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+                .append("roleId", getRoleId())
+                .append("deptId", getDeptId())
+                .toString();
+    }
+}

+ 55 - 0
himeeter-system/src/main/java/com/lij/himeeter/system/domin/SysRoleMenu.java

@@ -0,0 +1,55 @@
+package com.lij.himeeter.system.domin;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SysRoleMenu
+ * 创建时间 : 2024年12月30日 15:38
+ *
+ * 文件描述 : 角色和菜单关联 sys_role_menu
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class SysRoleMenu {
+
+    /**
+     * 角色ID
+     */
+    private Long roleId;
+
+    /**
+     * 菜单ID
+     */
+    private Long menuId;
+
+    public Long getRoleId() {
+        return roleId;
+    }
+
+    public void setRoleId(Long roleId) {
+        this.roleId = roleId;
+    }
+
+    public Long getMenuId() {
+        return menuId;
+    }
+
+    public void setMenuId(Long menuId) {
+        this.menuId = menuId;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+                .append("roleId", getRoleId())
+                .append("menuId", getMenuId())
+                .toString();
+    }
+}

+ 123 - 0
himeeter-system/src/main/java/com/lij/himeeter/system/domin/SysUserOnline.java

@@ -0,0 +1,123 @@
+package com.lij.himeeter.system.domin;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SysUserOnline
+ * 创建时间 : 2024年12月30日 15:38
+ *
+ * 文件描述 : 当前在线会话
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class SysUserOnline {
+
+    /**
+     * 会话编号
+     */
+    private String tokenId;
+
+    /**
+     * 部门名称
+     */
+    private String deptName;
+
+    /**
+     * 用户名称
+     */
+    private String userName;
+
+    /**
+     * 登录IP地址
+     */
+    private String ipaddr;
+
+    /**
+     * 登录地址
+     */
+    private String loginLocation;
+
+    /**
+     * 浏览器类型
+     */
+    private String browser;
+
+    /**
+     * 操作系统
+     */
+    private String os;
+
+    /**
+     * 登录时间
+     */
+    private Long loginTime;
+
+    public String getTokenId() {
+        return tokenId;
+    }
+
+    public void setTokenId(String tokenId) {
+        this.tokenId = tokenId;
+    }
+
+    public String getDeptName() {
+        return deptName;
+    }
+
+    public void setDeptName(String deptName) {
+        this.deptName = deptName;
+    }
+
+    public String getUserName() {
+        return userName;
+    }
+
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
+    public String getIpaddr() {
+        return ipaddr;
+    }
+
+    public void setIpaddr(String ipaddr) {
+        this.ipaddr = ipaddr;
+    }
+
+    public String getLoginLocation() {
+        return loginLocation;
+    }
+
+    public void setLoginLocation(String loginLocation) {
+        this.loginLocation = loginLocation;
+    }
+
+    public String getBrowser() {
+        return browser;
+    }
+
+    public void setBrowser(String browser) {
+        this.browser = browser;
+    }
+
+    public String getOs() {
+        return os;
+    }
+
+    public void setOs(String os) {
+        this.os = os;
+    }
+
+    public Long getLoginTime() {
+        return loginTime;
+    }
+
+    public void setLoginTime(Long loginTime) {
+        this.loginTime = loginTime;
+    }
+
+}

+ 55 - 0
himeeter-system/src/main/java/com/lij/himeeter/system/domin/SysUserPost.java

@@ -0,0 +1,55 @@
+package com.lij.himeeter.system.domin;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SysUserPost
+ * 创建时间 : 2024年12月30日 15:38
+ *
+ * 文件描述 : 用户和岗位关联 sys_user_post
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class SysUserPost {
+
+    /**
+     * 用户ID
+     */
+    private Long userId;
+
+    /**
+     * 岗位ID
+     */
+    private Long postId;
+
+    public Long getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Long userId) {
+        this.userId = userId;
+    }
+
+    public Long getPostId() {
+        return postId;
+    }
+
+    public void setPostId(Long postId) {
+        this.postId = postId;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+                .append("userId", getUserId())
+                .append("postId", getPostId())
+                .toString();
+    }
+}

+ 55 - 0
himeeter-system/src/main/java/com/lij/himeeter/system/domin/SysUserRole.java

@@ -0,0 +1,55 @@
+package com.lij.himeeter.system.domin;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SysUserRole
+ * 创建时间 : 2024年12月30日 15:39
+ *
+ * 文件描述 : 用户和角色关联 sys_user_role
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class SysUserRole {
+
+    /**
+     * 用户ID
+     */
+    private Long userId;
+
+    /**
+     * 角色ID
+     */
+    private Long roleId;
+
+    public Long getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Long userId) {
+        this.userId = userId;
+    }
+
+    public Long getRoleId() {
+        return roleId;
+    }
+
+    public void setRoleId(Long roleId) {
+        this.roleId = roleId;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+                .append("userId", getUserId())
+                .append("roleId", getRoleId())
+                .toString();
+    }
+}

+ 102 - 0
himeeter-system/src/main/java/com/lij/himeeter/system/domin/vo/MetaVO.java

@@ -0,0 +1,102 @@
+package com.lij.himeeter.system.domin.vo;
+
+import com.lij.himeeter.common.utils.StringUtils;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  MetaVO
+ * 创建时间 : 2024年12月30日 15:35
+ *
+ * 文件描述 : 路由显示信息
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class MetaVO {
+
+    /**
+     * 设置该路由在侧边栏和面包屑中展示的名字
+     */
+    private String title;
+
+    /**
+     * 设置该路由的图标,对应路径src/assets/icons/svg
+     */
+    private String icon;
+
+    /**
+     * 设置为true,则不会被 <keep-alive>缓存
+     */
+    private boolean noCache;
+
+    /**
+     * 内链地址(http(s)://开头)
+     */
+    private String link;
+
+    public MetaVO() {
+    }
+
+    public MetaVO(String title, String icon) {
+        this.title = title;
+        this.icon = icon;
+    }
+
+    public MetaVO(String title, String icon, boolean noCache) {
+        this.title = title;
+        this.icon = icon;
+        this.noCache = noCache;
+    }
+
+    public MetaVO(String title, String icon, String link) {
+        this.title = title;
+        this.icon = icon;
+        this.link = link;
+    }
+
+    public MetaVO(String title, String icon, boolean noCache, String link) {
+        this.title = title;
+        this.icon = icon;
+        this.noCache = noCache;
+        if (StringUtils.ishttp(link)) {
+            this.link = link;
+        }
+    }
+
+    public boolean isNoCache() {
+        return noCache;
+    }
+
+    public void setNoCache(boolean noCache) {
+        this.noCache = noCache;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public String getIcon() {
+        return icon;
+    }
+
+    public void setIcon(String icon) {
+        this.icon = icon;
+    }
+
+    public String getLink() {
+        return link;
+    }
+
+    public void setLink(String link) {
+        this.link = link;
+    }
+}
+

+ 140 - 0
himeeter-system/src/main/java/com/lij/himeeter/system/domin/vo/RouterVO.java

@@ -0,0 +1,140 @@
+package com.lij.himeeter.system.domin.vo;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+
+import java.util.List;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  RouterVO
+ * 创建时间 : 2024年12月30日 15:36
+ *
+ * 文件描述 : 路由配置信息
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+public class RouterVO {
+    /**
+     * 路由名字
+     */
+    private String name;
+
+    /**
+     * 路由地址
+     */
+    private String path;
+
+    /**
+     * 是否隐藏路由,当设置 true 的时候该路由不会再侧边栏出现
+     */
+    private boolean hidden;
+
+    /**
+     * 重定向地址,当设置 noRedirect 的时候该路由在面包屑导航中不可被点击
+     */
+    private String redirect;
+
+    /**
+     * 组件地址
+     */
+    private String component;
+
+    /**
+     * 路由参数:如 {"id": 1, "name": "ry"}
+     */
+    private String query;
+
+    /**
+     * 当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式--如组件页面
+     */
+    private Boolean alwaysShow;
+
+    /**
+     * 其他元素
+     */
+    private MetaVO meta;
+
+    /**
+     * 子路由
+     */
+    private List<RouterVO> children;
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getPath() {
+        return path;
+    }
+
+    public void setPath(String path) {
+        this.path = path;
+    }
+
+    public boolean getHidden() {
+        return hidden;
+    }
+
+    public void setHidden(boolean hidden) {
+        this.hidden = hidden;
+    }
+
+    public String getRedirect() {
+        return redirect;
+    }
+
+    public void setRedirect(String redirect) {
+        this.redirect = redirect;
+    }
+
+    public String getComponent() {
+        return component;
+    }
+
+    public void setComponent(String component) {
+        this.component = component;
+    }
+
+    public String getQuery() {
+        return query;
+    }
+
+    public void setQuery(String query) {
+        this.query = query;
+    }
+
+    public Boolean getAlwaysShow() {
+        return alwaysShow;
+    }
+
+    public void setAlwaysShow(Boolean alwaysShow) {
+        this.alwaysShow = alwaysShow;
+    }
+
+    public MetaVO getMeta() {
+        return meta;
+    }
+
+    public void setMeta(MetaVO meta) {
+        this.meta = meta;
+    }
+
+    public List<RouterVO> getChildren() {
+        return children;
+    }
+
+    public void setChildren(List<RouterVO> children) {
+        this.children = children;
+    }
+
+
+}

+ 86 - 0
himeeter-system/src/main/java/com/lij/himeeter/system/mapper/SysConfigMapper.java

@@ -0,0 +1,86 @@
+package com.lij.himeeter.system.mapper;
+
+import com.lij.himeeter.system.domin.SysConfig;
+
+import java.util.List;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SysConfigMapper
+ * 创建时间 : 2024年12月30日 17:31
+ *
+ * 文件描述 : 参数配置 数据层
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public interface SysConfigMapper {
+
+    /**
+     * 查询参数配置信息
+     *
+     * @param config 参数配置信息
+     * @return 参数配置信息
+     */
+    SysConfig selectConfig(SysConfig config);
+
+    /**
+     * 通过ID查询配置
+     *
+     * @param configId 参数ID
+     * @return 参数配置信息
+     */
+    SysConfig selectConfigById(Long configId);
+
+    /**
+     * 查询参数配置列表
+     *
+     * @param config 参数配置信息
+     * @return 参数配置集合
+     */
+    List<SysConfig> selectConfigList(SysConfig config);
+
+    /**
+     * 根据键名查询参数配置信息
+     *
+     * @param configKey 参数键名
+     * @return 参数配置信息
+     */
+    SysConfig checkConfigKeyUnique(String configKey);
+
+    /**
+     * 新增参数配置
+     *
+     * @param config 参数配置信息
+     * @return 结果
+     */
+    int insertConfig(SysConfig config);
+
+    /**
+     * 修改参数配置
+     *
+     * @param config 参数配置信息
+     * @return 结果
+     */
+    int updateConfig(SysConfig config);
+
+    /**
+     * 删除参数配置
+     *
+     * @param configId 参数ID
+     * @return 结果
+     */
+    int deleteConfigById(Long configId);
+
+    /**
+     * 批量删除参数信息
+     *
+     * @param configIds 需要删除的参数ID
+     * @return 结果
+     */
+    int deleteConfigByIds(Long[] configIds);
+}

+ 128 - 0
himeeter-system/src/main/java/com/lij/himeeter/system/mapper/SysDeptMapper.java

@@ -0,0 +1,128 @@
+package com.lij.himeeter.system.mapper;
+
+import com.lij.himeeter.common.core.domain.entity.SysDept;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SysDeptMapper
+ * 创建时间 : 2024年12月30日 17:31
+ *
+ * 文件描述 : 部门管理 数据层
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public interface SysDeptMapper {
+
+    /**
+     * 查询部门管理数据
+     *
+     * @param dept 部门信息
+     * @return 部门信息集合
+     */
+    List<SysDept> selectDeptList(SysDept dept);
+
+    /**
+     * 根据角色ID查询部门树信息
+     *
+     * @param roleId            角色ID
+     * @param deptCheckStrictly 部门树选择项是否关联显示
+     * @return 选中部门列表
+     */
+    List<Long> selectDeptListByRoleId(@Param("roleId") Long roleId, @Param("deptCheckStrictly") boolean deptCheckStrictly);
+
+    /**
+     * 根据部门ID查询信息
+     *
+     * @param deptId 部门ID
+     * @return 部门信息
+     */
+    SysDept selectDeptById(Long deptId);
+
+    /**
+     * 根据ID查询所有子部门
+     *
+     * @param deptId 部门ID
+     * @return 部门列表
+     */
+    List<SysDept> selectChildrenDeptById(Long deptId);
+
+    /**
+     * 根据ID查询所有子部门(正常状态)
+     *
+     * @param deptId 部门ID
+     * @return 子部门数
+     */
+    int selectNormalChildrenDeptById(Long deptId);
+
+    /**
+     * 是否存在子节点
+     *
+     * @param deptId 部门ID
+     * @return 结果
+     */
+    int hasChildByDeptId(Long deptId);
+
+    /**
+     * 查询部门是否存在用户
+     *
+     * @param deptId 部门ID
+     * @return 结果
+     */
+    int checkDeptExistUser(Long deptId);
+
+    /**
+     * 校验部门名称是否唯一
+     *
+     * @param deptName 部门名称
+     * @param parentId 父部门ID
+     * @return 结果
+     */
+    SysDept checkDeptNameUnique(@Param("deptName") String deptName, @Param("parentId") Long parentId);
+
+    /**
+     * 新增部门信息
+     *
+     * @param dept 部门信息
+     * @return 结果
+     */
+    int insertDept(SysDept dept);
+
+    /**
+     * 修改部门信息
+     *
+     * @param dept 部门信息
+     * @return 结果
+     */
+    int updateDept(SysDept dept);
+
+    /**
+     * 修改所在部门正常状态
+     *
+     * @param deptIds 部门ID组
+     */
+    void updateDeptStatusNormal(Long[] deptIds);
+
+    /**
+     * 修改子元素关系
+     *
+     * @param depts 子元素
+     * @return 结果
+     */
+    int updateDeptChildren(@Param("depts") List<SysDept> depts);
+
+    /**
+     * 删除部门管理信息
+     *
+     * @param deptId 部门ID
+     * @return 结果
+     */
+    int deleteDeptById(Long deptId);
+}

+ 105 - 0
himeeter-system/src/main/java/com/lij/himeeter/system/mapper/SysDictDataMapper.java

@@ -0,0 +1,105 @@
+package com.lij.himeeter.system.mapper;
+
+import com.lij.himeeter.common.core.domain.entity.SysDictData;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SysDictDataMapper
+ * 创建时间 : 2024年12月30日 17:31
+ *
+ * 文件描述 : 字典表 数据层
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public interface SysDictDataMapper {
+
+    /**
+     * 根据条件分页查询字典数据
+     *
+     * @param dictData 字典数据信息
+     * @return 字典数据集合信息
+     */
+    List<SysDictData> selectDictDataList(SysDictData dictData);
+
+    /**
+     * 根据字典类型查询字典数据
+     *
+     * @param dictType 字典类型
+     * @return 字典数据集合信息
+     */
+    List<SysDictData> selectDictDataByType(String dictType);
+
+    /**
+     * 根据字典类型和字典键值查询字典数据信息
+     *
+     * @param dictType  字典类型
+     * @param dictValue 字典键值
+     * @return 字典标签
+     */
+    String selectDictLabel(@Param("dictType") String dictType, @Param("dictValue") String dictValue);
+
+    /**
+     * 根据字典数据ID查询信息
+     *
+     * @param dictCode 字典数据ID
+     * @return 字典数据
+     */
+    SysDictData selectDictDataById(Long dictCode);
+
+    /**
+     * 查询字典数据
+     *
+     * @param dictType 字典类型
+     * @return 字典数据
+     */
+    int countDictDataByType(String dictType);
+
+    /**
+     * 通过字典ID删除字典数据信息
+     *
+     * @param dictCode 字典数据ID
+     * @return 结果
+     */
+    int deleteDictDataById(Long dictCode);
+
+    /**
+     * 批量删除字典数据信息
+     *
+     * @param dictCodes 需要删除的字典数据ID
+     * @return 结果
+     */
+    int deleteDictDataByIds(Long[] dictCodes);
+
+    /**
+     * 新增字典数据信息
+     *
+     * @param dictData 字典数据信息
+     * @return 结果
+     */
+    int insertDictData(SysDictData dictData);
+
+    /**
+     * 修改字典数据信息
+     *
+     * @param dictData 字典数据信息
+     * @return 结果
+     */
+    int updateDictData(SysDictData dictData);
+
+    /**
+     * 同步修改字典类型
+     *
+     * @param oldDictType 旧字典类型
+     * @param newDictType 新旧字典类型
+     * @return 结果
+     */
+    int updateDictDataType(@Param("oldDictType") String oldDictType, @Param("newDictType") String newDictType);
+}

+ 92 - 0
himeeter-system/src/main/java/com/lij/himeeter/system/mapper/SysDictTypeMapper.java

@@ -0,0 +1,92 @@
+package com.lij.himeeter.system.mapper;
+
+import com.lij.himeeter.common.core.domain.entity.SysDictType;
+
+import java.util.List;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SysDictTypeMapper
+ * 创建时间 : 2024年12月30日 17:32
+ *
+ * 文件描述 : 字典表 数据层
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public interface SysDictTypeMapper {
+    /**
+     * 根据条件分页查询字典类型
+     *
+     * @param dictType 字典类型信息
+     * @return 字典类型集合信息
+     */
+    List<SysDictType> selectDictTypeList(SysDictType dictType);
+
+    /**
+     * 根据所有字典类型
+     *
+     * @return 字典类型集合信息
+     */
+    List<SysDictType> selectDictTypeAll();
+
+    /**
+     * 根据字典类型ID查询信息
+     *
+     * @param dictId 字典类型ID
+     * @return 字典类型
+     */
+    SysDictType selectDictTypeById(Long dictId);
+
+    /**
+     * 根据字典类型查询信息
+     *
+     * @param dictType 字典类型
+     * @return 字典类型
+     */
+    SysDictType selectDictTypeByType(String dictType);
+
+    /**
+     * 通过字典ID删除字典信息
+     *
+     * @param dictId 字典ID
+     * @return 结果
+     */
+    int deleteDictTypeById(Long dictId);
+
+    /**
+     * 批量删除字典类型信息
+     *
+     * @param dictIds 需要删除的字典ID
+     * @return 结果
+     */
+    int deleteDictTypeByIds(Long[] dictIds);
+
+    /**
+     * 新增字典类型信息
+     *
+     * @param dictType 字典类型信息
+     * @return 结果
+     */
+    int insertDictType(SysDictType dictType);
+
+    /**
+     * 修改字典类型信息
+     *
+     * @param dictType 字典类型信息
+     * @return 结果
+     */
+    int updateDictType(SysDictType dictType);
+
+    /**
+     * 校验字典类型称是否唯一
+     *
+     * @param dictType 字典类型
+     * @return 结果
+     */
+    SysDictType checkDictTypeUnique(String dictType);
+}

+ 52 - 0
himeeter-system/src/main/java/com/lij/himeeter/system/mapper/SysLogininforMapper.java

@@ -0,0 +1,52 @@
+package com.lij.himeeter.system.mapper;
+
+import com.lij.himeeter.system.domin.SysLogininfor;
+
+import java.util.List;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SysLogininforMapper
+ * 创建时间 : 2024年12月30日 15:19
+ *
+ * 文件描述 : 系统访问日志情况信息 数据层
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public interface SysLogininforMapper {
+
+    /**
+     * 新增系统登录日志
+     *
+     * @param logininfor 访问日志对象
+     */
+    void insertLogininfor(SysLogininfor logininfor);
+
+    /**
+     * 查询系统登录日志集合
+     *
+     * @param logininfor 访问日志对象
+     * @return 登录记录集合
+     */
+    List<SysLogininfor> selectLogininforList(SysLogininfor logininfor);
+
+    /**
+     * 批量删除系统登录日志
+     *
+     * @param infoIds 需要删除的登录日志ID
+     * @return 结果
+     */
+    int deleteLogininforByIds(Long[] infoIds);
+
+    /**
+     * 清空系统登录日志
+     *
+     * @return 结果
+     */
+    int cleanLogininfor();
+}

+ 134 - 0
himeeter-system/src/main/java/com/lij/himeeter/system/mapper/SysMenuMapper.java

@@ -0,0 +1,134 @@
+package com.lij.himeeter.system.mapper;
+
+import com.lij.himeeter.common.core.domain.entity.SysMenu;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SysMenuMapper
+ * 创建时间 : 2024年12月30日 17:49
+ *
+ * 文件描述 : 菜单表 数据层
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public interface SysMenuMapper {
+    /**
+     * 查询系统菜单列表
+     *
+     * @param menu 菜单信息
+     * @return 菜单列表
+     */
+    List<SysMenu> selectMenuList(SysMenu menu);
+
+    /**
+     * 根据用户所有权限
+     *
+     * @return 权限列表
+     */
+    List<String> selectMenuPerms();
+
+    /**
+     * 根据用户查询系统菜单列表
+     *
+     * @param menu 菜单信息
+     * @return 菜单列表
+     */
+    List<SysMenu> selectMenuListByUserId(SysMenu menu);
+
+    /**
+     * 根据角色ID查询权限
+     *
+     * @param roleId 角色ID
+     * @return 权限列表
+     */
+    List<String> selectMenuPermsByRoleId(Long roleId);
+
+    /**
+     * 根据用户ID查询权限
+     *
+     * @param userId 用户ID
+     * @return 权限列表
+     */
+    List<String> selectMenuPermsByUserId(Long userId);
+
+    /**
+     * 根据用户ID查询菜单
+     *
+     * @return 菜单列表
+     */
+    List<SysMenu> selectMenuTreeAll();
+
+    /**
+     * 根据用户ID查询菜单
+     *
+     * @param userId 用户ID
+     * @return 菜单列表
+     */
+    List<SysMenu> selectMenuTreeByUserId(Long userId);
+
+    /**
+     * 根据角色ID查询菜单树信息
+     *
+     * @param roleId            角色ID
+     * @param menuCheckStrictly 菜单树选择项是否关联显示
+     * @return 选中菜单列表
+     */
+    List<Long> selectMenuListByRoleId(@Param("roleId") Long roleId, @Param("menuCheckStrictly") boolean menuCheckStrictly);
+
+    /**
+     * 根据菜单ID查询信息
+     *
+     * @param menuId 菜单ID
+     * @return 菜单信息
+     */
+    SysMenu selectMenuById(Long menuId);
+
+    /**
+     * 是否存在菜单子节点
+     *
+     * @param menuId 菜单ID
+     * @return 结果
+     */
+    int hasChildByMenuId(Long menuId);
+
+    /**
+     * 新增菜单信息
+     *
+     * @param menu 菜单信息
+     * @return 结果
+     */
+    int insertMenu(SysMenu menu);
+
+    /**
+     * 修改菜单信息
+     *
+     * @param menu 菜单信息
+     * @return 结果
+     */
+    int updateMenu(SysMenu menu);
+
+    /**
+     * 删除菜单管理信息
+     *
+     * @param menuId 菜单ID
+     * @return 结果
+     */
+    int deleteMenuById(Long menuId);
+
+    /**
+     * 校验菜单名称是否唯一
+     *
+     * @param menuName 菜单名称
+     * @param parentId 父菜单ID
+     * @return 结果
+     */
+    SysMenu checkMenuNameUnique(@Param("menuName") String menuName, @Param("parentId") Long parentId);
+}

+ 70 - 0
himeeter-system/src/main/java/com/lij/himeeter/system/mapper/SysNoticeMapper.java

@@ -0,0 +1,70 @@
+package com.lij.himeeter.system.mapper;
+
+import com.lij.himeeter.system.domin.SysNotice;
+
+import java.util.List;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SysNoticeMapper
+ * 创建时间 : 2024年12月30日 17:50
+ *
+ * 文件描述 : 通知公告表 数据层
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public interface SysNoticeMapper {
+
+    /**
+     * 查询公告信息
+     *
+     * @param noticeId 公告ID
+     * @return 公告信息
+     */
+    SysNotice selectNoticeById(Long noticeId);
+
+    /**
+     * 查询公告列表
+     *
+     * @param notice 公告信息
+     * @return 公告集合
+     */
+    List<SysNotice> selectNoticeList(SysNotice notice);
+
+    /**
+     * 新增公告
+     *
+     * @param notice 公告信息
+     * @return 结果
+     */
+    int insertNotice(SysNotice notice);
+
+    /**
+     * 修改公告
+     *
+     * @param notice 公告信息
+     * @return 结果
+     */
+    int updateNotice(SysNotice notice);
+
+    /**
+     * 批量删除公告
+     *
+     * @param noticeId 公告ID
+     * @return 结果
+     */
+    int deleteNoticeById(Long noticeId);
+
+    /**
+     * 批量删除公告信息
+     *
+     * @param noticeIds 需要删除的公告ID
+     * @return 结果
+     */
+    int deleteNoticeByIds(Long[] noticeIds);
+}

+ 58 - 0
himeeter-system/src/main/java/com/lij/himeeter/system/mapper/SysOperLogMapper.java

@@ -0,0 +1,58 @@
+package com.lij.himeeter.system.mapper;
+
+import com.lij.himeeter.system.domin.SysOperLog;
+
+import java.util.List;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SysOperLogMapper
+ * 创建时间 : 2024年12月30日 15:31
+ *
+ * 文件描述 : 无
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public interface SysOperLogMapper {
+
+    /**
+     * 新增操作日志
+     *
+     * @param operLog 操作日志对象
+     */
+    void insertOperlog(SysOperLog operLog);
+
+    /**
+     * 查询系统操作日志集合
+     *
+     * @param operLog 操作日志对象
+     * @return 操作日志集合
+     */
+    List<SysOperLog> selectOperLogList(SysOperLog operLog);
+
+    /**
+     * 批量删除系统操作日志
+     *
+     * @param operIds 需要删除的操作日志ID
+     * @return 结果
+     */
+    int deleteOperLogByIds(Long[] operIds);
+
+    /**
+     * 查询操作日志详细
+     *
+     * @param operId 操作ID
+     * @return 操作日志对象
+     */
+    SysOperLog selectOperLogById(Long operId);
+
+    /**
+     * 清空操作日志
+     */
+    void cleanOperLog();
+}

+ 108 - 0
himeeter-system/src/main/java/com/lij/himeeter/system/mapper/SysPostMapper.java

@@ -0,0 +1,108 @@
+package com.lij.himeeter.system.mapper;
+
+import com.lij.himeeter.system.domin.SysPost;
+
+import java.util.List;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SysPostMapper
+ * 创建时间 : 2024年12月30日 17:50
+ *
+ * 文件描述 : 岗位信息 数据层
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public interface SysPostMapper {
+    /**
+     * 查询岗位数据集合
+     *
+     * @param post 岗位信息
+     * @return 岗位数据集合
+     */
+    List<SysPost> selectPostList(SysPost post);
+
+    /**
+     * 查询所有岗位
+     *
+     * @return 岗位列表
+     */
+    List<SysPost> selectPostAll();
+
+    /**
+     * 通过岗位ID查询岗位信息
+     *
+     * @param postId 岗位ID
+     * @return 角色对象信息
+     */
+    SysPost selectPostById(Long postId);
+
+    /**
+     * 根据用户ID获取岗位选择框列表
+     *
+     * @param userId 用户ID
+     * @return 选中岗位ID列表
+     */
+    List<Long> selectPostListByUserId(Long userId);
+
+    /**
+     * 查询用户所属岗位组
+     *
+     * @param userName 用户名
+     * @return 结果
+     */
+    List<SysPost> selectPostsByUserName(String userName);
+
+    /**
+     * 删除岗位信息
+     *
+     * @param postId 岗位ID
+     * @return 结果
+     */
+    int deletePostById(Long postId);
+
+    /**
+     * 批量删除岗位信息
+     *
+     * @param postIds 需要删除的岗位ID
+     * @return 结果
+     */
+    int deletePostByIds(Long[] postIds);
+
+    /**
+     * 修改岗位信息
+     *
+     * @param post 岗位信息
+     * @return 结果
+     */
+    int updatePost(SysPost post);
+
+    /**
+     * 新增岗位信息
+     *
+     * @param post 岗位信息
+     * @return 结果
+     */
+    int insertPost(SysPost post);
+
+    /**
+     * 校验岗位名称
+     *
+     * @param postName 岗位名称
+     * @return 结果
+     */
+    SysPost checkPostNameUnique(String postName);
+
+    /**
+     * 校验岗位编码
+     *
+     * @param postCode 岗位编码
+     * @return 结果
+     */
+    SysPost checkPostCodeUnique(String postCode);
+}

+ 53 - 0
himeeter-system/src/main/java/com/lij/himeeter/system/mapper/SysRoleDeptMapper.java

@@ -0,0 +1,53 @@
+package com.lij.himeeter.system.mapper;
+
+import com.lij.himeeter.system.domin.SysRoleDept;
+
+import java.util.List;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SysRoleDeptMapper
+ * 创建时间 : 2024年12月30日 17:51
+ *
+ * 文件描述 : 角色与部门关联表 数据层
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public interface SysRoleDeptMapper {
+    /**
+     * 通过角色ID删除角色和部门关联
+     *
+     * @param roleId 角色ID
+     * @return 结果
+     */
+    int deleteRoleDeptByRoleId(Long roleId);
+
+    /**
+     * 批量删除角色部门关联信息
+     *
+     * @param ids 需要删除的数据ID
+     * @return 结果
+     */
+    int deleteRoleDept(Long[] ids);
+
+    /**
+     * 查询部门使用数量
+     *
+     * @param deptId 部门ID
+     * @return 结果
+     */
+    int selectCountRoleDeptByDeptId(Long deptId);
+
+    /**
+     * 批量新增角色部门信息
+     *
+     * @param roleDeptList 角色部门列表
+     * @return 结果
+     */
+    int batchRoleDept(List<SysRoleDept> roleDeptList);
+}

+ 117 - 0
himeeter-system/src/main/java/com/lij/himeeter/system/mapper/SysRoleMapper.java

@@ -0,0 +1,117 @@
+package com.lij.himeeter.system.mapper;
+
+import com.lij.himeeter.common.core.domain.entity.SysRole;
+
+import java.util.List;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SysRoleMapper
+ * 创建时间 : 2024年12月30日 17:52
+ *
+ * 文件描述 : 角色表 数据层
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public interface SysRoleMapper {
+
+    /**
+     * 根据条件分页查询角色数据
+     *
+     * @param role 角色信息
+     * @return 角色数据集合信息
+     */
+    List<SysRole> selectRoleList(SysRole role);
+
+    /**
+     * 根据用户ID查询角色
+     *
+     * @param userId 用户ID
+     * @return 角色列表
+     */
+    List<SysRole> selectRolePermissionByUserId(Long userId);
+
+    /**
+     * 查询所有角色
+     *
+     * @return 角色列表
+     */
+    List<SysRole> selectRoleAll();
+
+    /**
+     * 根据用户ID获取角色选择框列表
+     *
+     * @param userId 用户ID
+     * @return 选中角色ID列表
+     */
+    List<Long> selectRoleListByUserId(Long userId);
+
+    /**
+     * 通过角色ID查询角色
+     *
+     * @param roleId 角色ID
+     * @return 角色对象信息
+     */
+    SysRole selectRoleById(Long roleId);
+
+    /**
+     * 根据用户ID查询角色
+     *
+     * @param userName 用户名
+     * @return 角色列表
+     */
+    List<SysRole> selectRolesByUserName(String userName);
+
+    /**
+     * 校验角色名称是否唯一
+     *
+     * @param roleName 角色名称
+     * @return 角色信息
+     */
+    SysRole checkRoleNameUnique(String roleName);
+
+    /**
+     * 校验角色权限是否唯一
+     *
+     * @param roleKey 角色权限
+     * @return 角色信息
+     */
+    SysRole checkRoleKeyUnique(String roleKey);
+
+    /**
+     * 修改角色信息
+     *
+     * @param role 角色信息
+     * @return 结果
+     */
+    int updateRole(SysRole role);
+
+    /**
+     * 新增角色信息
+     *
+     * @param role 角色信息
+     * @return 结果
+     */
+    int insertRole(SysRole role);
+
+    /**
+     * 通过角色ID删除角色
+     *
+     * @param roleId 角色ID
+     * @return 结果
+     */
+    int deleteRoleById(Long roleId);
+
+    /**
+     * 批量删除角色信息
+     *
+     * @param roleIds 需要删除的角色ID
+     * @return 结果
+     */
+    int deleteRoleByIds(Long[] roleIds);
+}

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