Parcourir la source

分批次提交

傅行帆 il y a 4 ans
Parent
révision
77fb8b0f7a
100 fichiers modifiés avec 7563 ajouts et 0 suppressions
  1. 132
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/common/api/ApiCode.java
  2. 162
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/common/api/ApiResult.java
  3. 91
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/common/bean/ClientInfo.java
  4. 44
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/common/bean/DeviceInfo.java
  5. 30
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/common/controller/BaseController.java
  6. 42
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/common/controller/CsrfController.java
  7. 103
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/common/controller/EnumController.java
  8. 52
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/common/controller/IndexController.java
  9. 32
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/common/entity/BaseEntity.java
  10. 66
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/common/enums/BaseEnum.java
  11. 42
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/common/exception/BusinessException.java
  12. 41
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/common/exception/DaoException.java
  13. 64
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/common/exception/GlobalErrorController.java
  14. 67
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/common/exception/SpringBootPlusConfigException.java
  15. 66
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/common/exception/SpringBootPlusException.java
  16. 39
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/common/param/IdParam.java
  17. 29
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/common/service/BaseService.java
  18. 61
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/common/service/impl/BaseServiceImpl.java
  19. 47
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/common/vo/EnumVo.java
  20. 48
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/config/converter/ConverterConfig.java
  21. 36
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/config/converter/StringToDateConverter.java
  22. 109
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/config/converter/StringToDateUtil.java
  23. 34
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/config/converter/StringToDoubleConverter.java
  24. 41
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/config/converter/StringToDoubleUtil.java
  25. 34
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/config/converter/StringToIntegerConverter.java
  26. 40
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/config/converter/StringToIntegerUtil.java
  27. 42
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/config/jackson/deserializer/JacksonDateDeserializer.java
  28. 38
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/config/jackson/deserializer/JacksonDoubleDeserializer.java
  29. 47
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/config/jackson/deserializer/JacksonLocalDateTimeDeserializer.java
  30. 45
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/config/jackson/serializer/JacksonDateSerializer.java
  31. 38
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/config/jackson/serializer/JacksonIntegerDeserializer.java
  32. 48
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/config/jackson/serializer/JacksonLocalDateTimeSerializer.java
  33. 45
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/core/bean/RequestDetail.java
  34. 64
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/core/filter/RequestDetailFilter.java
  35. 48
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/core/interceptor/PermissionInterceptor.java
  36. 55
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/core/pagination/BasePageOrderParam.java
  37. 62
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/core/pagination/BasePageParam.java
  38. 108
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/core/pagination/OrderMapping.java
  39. 165
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/core/pagination/PageInfo.java
  40. 76
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/core/pagination/Paging.java
  41. 54
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/core/util/RequestDetailThreadLocal.java
  42. 52
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/core/validator/EnumTypeValidator.java
  43. 45
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/core/validator/IdCardValidator.java
  44. 46
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/core/validator/PhoneValidator.java
  45. 49
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/core/validator/constraints/EnumType.java
  46. 46
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/core/validator/constraints/IdCard.java
  47. 46
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/core/validator/constraints/Phone.java
  48. 28
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/core/validator/groups/Add.java
  49. 28
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/core/validator/groups/Update.java
  50. 50
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/core/xss/XssFilter.java
  51. 62
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/core/xss/XssHttpServletRequestWrapper.java
  52. 41
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/core/xss/XssJacksonDeserializer.java
  53. 42
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/core/xss/XssJacksonSerializer.java
  54. 58
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/ip/entity/IpAddress.java
  55. 41
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/ip/mapper/IpAddressMapper.java
  56. 54
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/ip/service/IpAddressService.java
  57. 74
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/ip/service/impl/IpAddressServiceImpl.java
  58. 49
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/log/annotation/Module.java
  59. 64
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/log/annotation/OperationLog.java
  60. 34
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/log/annotation/OperationLogIgnore.java
  61. 990
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/log/aop/BaseLogAop.java
  62. 67
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/log/bean/OperationLogInfo.java
  63. 140
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/log/bean/RequestInfo.java
  64. 68
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/log/controller/SysLoginLogController.java
  65. 63
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/log/controller/SysOperationLogController.java
  66. 119
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/log/entity/SysLoginLog.java
  67. 152
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/log/entity/SysOperationLog.java
  68. 88
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/log/enums/OperationLogType.java
  69. 33
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/log/mapper/SysLoginLogMapper.java
  70. 33
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/log/mapper/SysOperationLogMapper.java
  71. 39
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/log/param/SysLoginLogPageParam.java
  72. 39
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/log/param/SysOperationLogPageParam.java
  73. 69
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/log/service/SysLoginLogService.java
  74. 69
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/log/service/SysOperationLogService.java
  75. 74
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/log/service/impl/SysLoginLogServiceImpl.java
  76. 74
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/log/service/impl/SysOperationLogServiceImpl.java
  77. 98
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/shiro/cache/LoginRedisService.java
  78. 199
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/shiro/cache/impl/LoginRedisServiceImpl.java
  79. 43
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/shiro/convert/LoginSysUserVoConvert.java
  80. 44
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/shiro/convert/ShiroMapstructConvert.java
  81. 43
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/shiro/exception/ShiroConfigException.java
  82. 47
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/shiro/jwt/JwtCredentialsMatcher.java
  83. 181
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/shiro/jwt/JwtFilter.java
  84. 104
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/shiro/jwt/JwtRealm.java
  85. 98
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/shiro/jwt/JwtToken.java
  86. 36
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/shiro/service/LoginToken.java
  87. 36
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/shiro/service/LoginUsername.java
  88. 42
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/shiro/service/ShiroLoginService.java
  89. 115
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/shiro/service/impl/ShiroLoginServiceImpl.java
  90. 81
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/shiro/util/JwtTokenUtil.java
  91. 204
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/shiro/util/JwtUtil.java
  92. 77
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/shiro/util/SaltUtil.java
  93. 64
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/shiro/vo/JwtTokenRedisVo.java
  94. 47
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/shiro/vo/LoginSysUserRedisVo.java
  95. 73
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/shiro/vo/LoginSysUserVo.java
  96. 58
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/util/AnsiUtil.java
  97. 151
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/util/BaseEnumUtil.java
  98. 89
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/util/BrowserUtil.java
  99. 120
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/util/ClientInfoUtil.java
  100. 0
    0
      framework/src/main/java/io/geekidea/springbootplus/framework/util/ContentTypeUtil.java

+ 132
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/common/api/ApiCode.java Voir le fichier

@@ -0,0 +1,132 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.common.api;
18
+
19
+/**
20
+ * <p>
21
+ * REST API 响应码
22
+ * </p>
23
+ *
24
+ * @author geekidea
25
+ * @since 2018-11-08
26
+ */
27
+public enum ApiCode {
28
+
29
+    /**
30
+     * 操作成功
31
+     **/
32
+    SUCCESS(200, "操作成功"),
33
+    /**
34
+     * 非法访问
35
+     **/
36
+    UNAUTHORIZED(401, "非法访问"),
37
+    /**
38
+     * 没有权限
39
+     **/
40
+    NOT_PERMISSION(403, "没有权限"),
41
+    /**
42
+     * 你请求的资源不存在
43
+     **/
44
+    NOT_FOUND(404, "你请求的资源不存在"),
45
+    /**
46
+     * 操作失败
47
+     **/
48
+    FAIL(500, "操作失败"),
49
+    /**
50
+     * 登录失败
51
+     **/
52
+    LOGIN_EXCEPTION(4000, "登录失败"),
53
+    /**
54
+     * 系统异常
55
+     **/
56
+    SYSTEM_EXCEPTION(5000, "系统异常"),
57
+    /**
58
+     * 请求参数校验异常
59
+     **/
60
+    PARAMETER_EXCEPTION(5001, "请求参数校验异常"),
61
+    /**
62
+     * 请求参数解析异常
63
+     **/
64
+    PARAMETER_PARSE_EXCEPTION(5002, "请求参数解析异常"),
65
+    /**
66
+     * HTTP内容类型异常
67
+     **/
68
+    HTTP_MEDIA_TYPE_EXCEPTION(5003, "HTTP内容类型异常"),
69
+    /**
70
+     * 系统处理异常
71
+     **/
72
+    SPRING_BOOT_PLUS_EXCEPTION(5100, "系统处理异常"),
73
+    /**
74
+     * 业务处理异常
75
+     **/
76
+    BUSINESS_EXCEPTION(5101, "业务处理异常"),
77
+    /**
78
+     * 数据库处理异常
79
+     **/
80
+    DAO_EXCEPTION(5102, "数据库处理异常"),
81
+    /**
82
+     * 验证码校验异常
83
+     **/
84
+    VERIFICATION_CODE_EXCEPTION(5103, "验证码校验异常"),
85
+    /**
86
+     * 登录授权异常
87
+     **/
88
+    AUTHENTICATION_EXCEPTION(5104, "登录授权异常"),
89
+    /**
90
+     * 没有访问权限
91
+     **/
92
+    UNAUTHENTICATED_EXCEPTION(5105, "没有访问权限"),
93
+    /**
94
+     * 没有访问权限
95
+     **/
96
+    UNAUTHORIZED_EXCEPTION(5106, "没有访问权限"),
97
+    /**
98
+     * JWT Token解析异常
99
+     **/
100
+    JWTDECODE_EXCEPTION(5107, "Token解析异常"),
101
+
102
+    HTTP_REQUEST_METHOD_NOT_SUPPORTED_EXCEPTION(5108, "METHOD NOT SUPPORTED"),
103
+
104
+    ;
105
+
106
+    private final int code;
107
+    private final String message;
108
+
109
+    ApiCode(final int code, final String message) {
110
+        this.code = code;
111
+        this.message = message;
112
+    }
113
+
114
+    public static ApiCode getApiCode(int code) {
115
+        ApiCode[] ecs = ApiCode.values();
116
+        for (ApiCode ec : ecs) {
117
+            if (ec.getCode() == code) {
118
+                return ec;
119
+            }
120
+        }
121
+        return SUCCESS;
122
+    }
123
+
124
+    public int getCode() {
125
+        return code;
126
+    }
127
+
128
+    public String getMessage() {
129
+        return message;
130
+    }
131
+
132
+}

+ 162
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/common/api/ApiResult.java Voir le fichier

@@ -0,0 +1,162 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.common.api;
18
+
19
+import com.alibaba.fastjson.annotation.JSONField;
20
+import com.fasterxml.jackson.annotation.JsonFormat;
21
+import lombok.AllArgsConstructor;
22
+import lombok.Builder;
23
+import lombok.Data;
24
+import lombok.experimental.Accessors;
25
+import org.apache.commons.lang3.StringUtils;
26
+
27
+import java.io.Serializable;
28
+import java.util.Date;
29
+import java.util.HashMap;
30
+import java.util.Map;
31
+
32
+/**
33
+ * <p>
34
+ * REST API 返回结果
35
+ * </p>
36
+ *
37
+ * @author geekidea
38
+ * @since 2018-11-08
39
+ */
40
+@Data
41
+@Accessors(chain = true)
42
+@Builder
43
+@AllArgsConstructor
44
+public class ApiResult<T> implements Serializable {
45
+	private static final long serialVersionUID = 8004487252556526569L;
46
+
47
+	/**
48
+     * 响应码
49
+     */
50
+    private int code;
51
+
52
+    /**
53
+     * 是否成功
54
+     */
55
+    private boolean success;
56
+
57
+    /**
58
+     * 响应消息
59
+     */
60
+    private String message;
61
+
62
+    /**
63
+     * 响应数据
64
+     */
65
+    private T data;
66
+
67
+    /**
68
+     * 响应时间
69
+     */
70
+    @JSONField(format = "yyyy-MM-dd HH:mm:ss")
71
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
72
+    private Date time;
73
+
74
+    public ApiResult() {
75
+        time  = new Date();
76
+    }
77
+
78
+    public static ApiResult<Boolean> result(boolean flag){
79
+        if (flag){
80
+            return ok();
81
+        }
82
+        return fail();
83
+    }
84
+
85
+    public static ApiResult<Boolean> result(ApiCode apiCode){
86
+        return result(apiCode,null);
87
+    }
88
+
89
+    public static <T> ApiResult<T> result(ApiCode apiCode,T data){
90
+        return result(apiCode,null,data);
91
+    }
92
+
93
+    public static <T> ApiResult<T> result(ApiCode apiCode,String message,T data){
94
+        boolean success = false;
95
+        if (apiCode.getCode() == ApiCode.SUCCESS.getCode()){
96
+            success = true;
97
+        }
98
+        String apiMessage = apiCode.getMessage();
99
+        if (StringUtils.isNotBlank(apiMessage)){
100
+            message = apiMessage;
101
+        }
102
+        return (ApiResult<T>) ApiResult.builder()
103
+                .code(apiCode.getCode())
104
+                .message(message)
105
+                .data(data)
106
+                .success(success)
107
+                .time(new Date())
108
+                .build();
109
+    }
110
+
111
+    public static ApiResult<Boolean> ok(){
112
+        return ok(null);
113
+    }
114
+
115
+    public static <T> ApiResult<T> ok(T data){
116
+        return result(ApiCode.SUCCESS,data);
117
+    }
118
+
119
+    public static <T> ApiResult<T> ok(T data,String message){
120
+        return result(ApiCode.SUCCESS,message,data);
121
+    }
122
+
123
+    public static ApiResult<Map<String,Object>> okMap(String key,Object value){
124
+        Map<String,Object> map = new HashMap<>(1);
125
+        map.put(key,value);
126
+        return ok(map);
127
+    }
128
+
129
+    public static ApiResult<Boolean> fail(ApiCode apiCode){
130
+        return result(apiCode,null);
131
+    }
132
+
133
+    public static ApiResult<String> fail(String message){
134
+        return result(ApiCode.FAIL,message,null);
135
+
136
+    }
137
+
138
+    public static <T> ApiResult<T> fail(ApiCode apiCode,T data){
139
+        if (ApiCode.SUCCESS == apiCode){
140
+            throw new RuntimeException("失败结果状态码不能为" + ApiCode.SUCCESS.getCode());
141
+        }
142
+        return result(apiCode,data);
143
+
144
+    }
145
+
146
+    public static  ApiResult<String> fail(Integer errorCode,String message){
147
+        return new ApiResult<String>()
148
+                .setSuccess(false)
149
+                .setCode(errorCode)
150
+                .setMessage(message);
151
+    }
152
+
153
+    public static ApiResult<Map<String,Object>> fail(String key,Object value){
154
+        Map<String,Object> map = new HashMap<>(1);
155
+        map.put(key,value);
156
+        return result(ApiCode.FAIL,map);
157
+    }
158
+
159
+    public static ApiResult<Boolean> fail() {
160
+        return fail(ApiCode.FAIL);
161
+    }
162
+}

+ 91
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/common/bean/ClientInfo.java Voir le fichier

@@ -0,0 +1,91 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.common.bean;
18
+
19
+import lombok.Data;
20
+
21
+import java.io.Serializable;
22
+
23
+/**
24
+ * <p>
25
+ * 用户客户端信息对象
26
+ * </p>
27
+ *
28
+ * @author geekidea
29
+ * @date 2019-05-23
30
+ **/
31
+@Data
32
+public class ClientInfo implements Serializable {
33
+
34
+    private static final long serialVersionUID = -5549531244606897514L;
35
+
36
+    /**
37
+     * ip
38
+     */
39
+    private String ip;
40
+
41
+    /**
42
+     * ip对应的地址
43
+     */
44
+    private String addree;
45
+
46
+    /**
47
+     * 浏览器名称
48
+     */
49
+    private String browserName;
50
+
51
+    /**
52
+     * 浏览器版本
53
+     */
54
+    private String browserversion;
55
+
56
+    /**
57
+     * 浏览器引擎名称
58
+     */
59
+    private String engineName;
60
+
61
+    /**
62
+     * 浏览器引擎版本
63
+     */
64
+    private String engineVersion;
65
+
66
+    /**
67
+     * 系统名称
68
+     */
69
+    private String osName;
70
+
71
+    /**
72
+     * 平台名称
73
+     */
74
+    private String platformName;
75
+
76
+    /**
77
+     * 是否是手机
78
+     */
79
+    private boolean mobile;
80
+
81
+    /**
82
+     * 移动端设备型号
83
+     */
84
+    private String deviceName;
85
+
86
+    /**
87
+     * 移动端设备型号
88
+     */
89
+    private String deviceModel;
90
+
91
+}

+ 44
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/common/bean/DeviceInfo.java Voir le fichier

@@ -0,0 +1,44 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.common.bean;
18
+
19
+import lombok.Data;
20
+
21
+import java.io.Serializable;
22
+
23
+/**
24
+ * <p>
25
+ * 设备信息
26
+ * </p>
27
+ *
28
+ * @author geekidea
29
+ * @date 2019-05-24
30
+ **/
31
+@Data
32
+public class DeviceInfo implements Serializable {
33
+    private static final long serialVersionUID = -5912785220335057555L;
34
+
35
+    /**
36
+     * 设备名称
37
+     */
38
+    private String name;
39
+
40
+    /**
41
+     * 设备型号
42
+     */
43
+    private String model;
44
+}

+ 30
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/common/controller/BaseController.java Voir le fichier

@@ -0,0 +1,30 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.common.controller;
18
+
19
+import lombok.extern.slf4j.Slf4j;
20
+
21
+/**
22
+ * Controller父类
23
+ *
24
+ * @author geekidea
25
+ * @date 2018-11-08
26
+ */
27
+@Slf4j
28
+public abstract class BaseController {
29
+
30
+}

+ 42
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/common/controller/CsrfController.java Voir le fichier

@@ -0,0 +1,42 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.common.controller;
18
+
19
+import io.geekidea.springbootplus.framework.log.annotation.OperationLogIgnore;
20
+import io.geekidea.springbootplus.framework.util.UUIDUtil;
21
+import org.springframework.web.bind.annotation.RequestMapping;
22
+import org.springframework.web.bind.annotation.RequestMethod;
23
+import org.springframework.web.bind.annotation.RestController;
24
+import springfox.documentation.annotations.ApiIgnore;
25
+
26
+/**
27
+ * CSRF 供swagger调用
28
+ *
29
+ * @author geekidea
30
+ * @date 2019/12/10
31
+ **/
32
+@ApiIgnore
33
+@OperationLogIgnore
34
+@RestController
35
+public class CsrfController {
36
+
37
+    @RequestMapping(value = "/csrf", method = {RequestMethod.GET, RequestMethod.POST})
38
+    public String csrf() {
39
+        return UUIDUtil.getUuid();
40
+    }
41
+
42
+}

+ 103
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/common/controller/EnumController.java Voir le fichier

@@ -0,0 +1,103 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.common.controller;
18
+
19
+import io.geekidea.springbootplus.framework.common.api.ApiResult;
20
+import io.geekidea.springbootplus.framework.common.enums.BaseEnum;
21
+import io.geekidea.springbootplus.framework.common.vo.EnumVo;
22
+import io.geekidea.springbootplus.framework.log.annotation.OperationLogIgnore;
23
+import io.geekidea.springbootplus.framework.util.BaseEnumUtil;
24
+import io.swagger.annotations.Api;
25
+import lombok.extern.slf4j.Slf4j;
26
+import org.apache.commons.collections4.CollectionUtils;
27
+import org.reflections.Reflections;
28
+import org.springframework.beans.factory.annotation.Value;
29
+import org.springframework.web.bind.annotation.GetMapping;
30
+import org.springframework.web.bind.annotation.RestController;
31
+
32
+import javax.annotation.PostConstruct;
33
+import java.util.*;
34
+import java.util.concurrent.ConcurrentHashMap;
35
+
36
+/**
37
+ * <p>
38
+ * 展示实现BaseEnum接口的所有枚举值
39
+ * </p>
40
+ *
41
+ * @author geekidea
42
+ * @date 2018/11/02
43
+ */
44
+@RestController
45
+@Slf4j
46
+@OperationLogIgnore
47
+@Api(value = "枚举字典", tags = {"枚举字典"})
48
+public class EnumController {
49
+
50
+    private static final List<String> FRAMEWORK_ENUM_PACKAGES = Arrays.asList(
51
+            "io.geekidea.springbootplus.framework.common.enums",
52
+            "io.geekidea.springbootplus.system.enums");
53
+
54
+    /**
55
+     * 枚举包路径
56
+     */
57
+    @Value("${spring-boot-plus.enum-packages}")
58
+    private List<String> enumPackages;
59
+
60
+    @GetMapping("/enum")
61
+    public ApiResult<Map<String, Map<Integer, EnumVo<? extends BaseEnum>>>> enumList() {
62
+        log.debug("enumList...");
63
+        return ApiResult.ok(BaseEnumUtil.getEnumMap());
64
+    }
65
+
66
+    @PostConstruct
67
+    public void init() {
68
+        try {
69
+            if (enumPackages == null) {
70
+                enumPackages = new ArrayList<>();
71
+            }
72
+            enumPackages.addAll(FRAMEWORK_ENUM_PACKAGES);
73
+
74
+            // 获取BaseEnum接口的所有实现
75
+            log.debug("enumPackages:" + enumPackages);
76
+            Reflections reflections = new Reflections(enumPackages);
77
+            Set<Class<? extends BaseEnum>> set = reflections.getSubTypesOf(BaseEnum.class);
78
+            if (CollectionUtils.isEmpty(set)) {
79
+                return;
80
+            }
81
+            // 循环获取BaseEnum枚举
82
+            for (Class<? extends BaseEnum> clazz : set) {
83
+                BaseEnum[] enumConstants = clazz.getEnumConstants();
84
+                Map<Integer, EnumVo<? extends BaseEnum>> enumVoMap = new ConcurrentHashMap<>(enumConstants.length);
85
+                for (BaseEnum baseEnum : enumConstants) {
86
+                    Integer code = baseEnum.getCode();
87
+                    String desc = baseEnum.getDesc();
88
+                    EnumVo<BaseEnum> enumVo = new EnumVo<BaseEnum>()
89
+                            .setCode(code)
90
+                            .setDesc(desc)
91
+                            .setBaseEnum(baseEnum);
92
+                    enumVoMap.put(code, enumVo);
93
+                }
94
+                // 设置map
95
+                BaseEnumUtil.getEnumMap().put(clazz.getName(), enumVoMap);
96
+            }
97
+            log.debug("enumMap:{}", BaseEnumUtil.getEnumMap());
98
+        } catch (Exception e) {
99
+            log.error("获取BaseEnum枚举map异常", e);
100
+        }
101
+    }
102
+
103
+}

+ 52
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/common/controller/IndexController.java Voir le fichier

@@ -0,0 +1,52 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.common.controller;
18
+
19
+import io.geekidea.springbootplus.framework.log.annotation.OperationLogIgnore;
20
+import io.swagger.annotations.Api;
21
+import lombok.extern.slf4j.Slf4j;
22
+import org.springframework.stereotype.Controller;
23
+import org.springframework.web.bind.annotation.GetMapping;
24
+
25
+/**
26
+ * <p>
27
+ * 项目根路径提示信息
28
+ * </p>
29
+ *
30
+ * @author geekidea
31
+ * @date 2018/11/12
32
+ */
33
+@Slf4j
34
+@Controller
35
+@OperationLogIgnore
36
+@Api(value = "Index API", tags = {"Index"})
37
+public class IndexController {
38
+
39
+    @GetMapping("/")
40
+    public String home() {
41
+        return "redirect:/index.html";
42
+    }
43
+
44
+    /**
45
+     * SwaggerUI
46
+     */
47
+    @GetMapping("/docs")
48
+    public String swagger() {
49
+        return "redirect:/swagger-ui.html";
50
+    }
51
+
52
+}

+ 32
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/common/entity/BaseEntity.java Voir le fichier

@@ -0,0 +1,32 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.common.entity;
18
+
19
+import io.swagger.annotations.ApiModel;
20
+
21
+import java.io.Serializable;
22
+
23
+/**
24
+ * 实体父类
25
+ * @author geekidea
26
+ * @date 2018-11-08
27
+ */
28
+@ApiModel("BaseEntity")
29
+public abstract class BaseEntity implements Serializable{
30
+	private static final long serialVersionUID = -7176390653391227433L;
31
+	
32
+}

+ 66
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/common/enums/BaseEnum.java Voir le fichier

@@ -0,0 +1,66 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.common.enums;
18
+
19
+
20
+/**
21
+ * 枚举类型父接口
22
+ *
23
+ * @author geekidea
24
+ * @date 2018-11-08
25
+ */
26
+public interface BaseEnum {
27
+
28
+    /**
29
+     * 获取枚举标识
30
+     *
31
+     * @return
32
+     */
33
+    Integer getCode();
34
+
35
+    /**
36
+     * 获取枚举描述
37
+     *
38
+     * @return
39
+     */
40
+    String getDesc();
41
+
42
+    /**
43
+     * 通过枚举类型和code值获取对应的枚举类型
44
+     * @param enumType
45
+     * @param code
46
+     * @param <T>
47
+     * @return
48
+     */
49
+    static <T extends BaseEnum> T valueOf(Class<? extends BaseEnum> enumType, Integer code) {
50
+        if (enumType == null || code == null) {
51
+            return null;
52
+        }
53
+        T[] enumConstants = (T[]) enumType.getEnumConstants();
54
+        if (enumConstants == null) {
55
+            return null;
56
+        }
57
+        for (T enumConstant : enumConstants) {
58
+            int enumCode = enumConstant.getCode();
59
+            if (code.equals(enumCode)) {
60
+                return enumConstant;
61
+            }
62
+        }
63
+        return null;
64
+    }
65
+
66
+}

+ 42
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/common/exception/BusinessException.java Voir le fichier

@@ -0,0 +1,42 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.common.exception;
18
+
19
+import io.geekidea.springbootplus.framework.common.api.ApiCode;
20
+
21
+/**
22
+ * 业务异常
23
+ *
24
+ * @author geekidea
25
+ * @date 2018-11-08
26
+ */
27
+public class BusinessException extends SpringBootPlusException {
28
+	private static final long serialVersionUID = -2303357122330162359L;
29
+
30
+	public BusinessException(String message) {
31
+        super(message);
32
+    }
33
+
34
+    public BusinessException(Integer errorCode, String message) {
35
+        super(errorCode, message);
36
+    }
37
+
38
+    public BusinessException(ApiCode apiCode) {
39
+        super(apiCode);
40
+    }
41
+
42
+}

+ 41
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/common/exception/DaoException.java Voir le fichier

@@ -0,0 +1,41 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.common.exception;
18
+
19
+import io.geekidea.springbootplus.framework.common.api.ApiCode;
20
+
21
+/**
22
+ * DAO异常
23
+ *
24
+ * @author geekidea
25
+ * @date 2018-11-08
26
+ */
27
+public class DaoException extends SpringBootPlusException {
28
+	private static final long serialVersionUID = -6912618737345878854L;
29
+
30
+	public DaoException(String message) {
31
+        super(message);
32
+    }
33
+
34
+    public DaoException(Integer errorCode, String message) {
35
+        super(errorCode, message);
36
+    }
37
+
38
+    public DaoException(ApiCode apiCode) {
39
+        super(apiCode);
40
+    }
41
+}

+ 64
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/common/exception/GlobalErrorController.java Voir le fichier

@@ -0,0 +1,64 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.common.exception;
18
+
19
+import io.geekidea.springbootplus.framework.common.api.ApiCode;
20
+import io.geekidea.springbootplus.framework.common.api.ApiResult;
21
+import lombok.extern.slf4j.Slf4j;
22
+import org.springframework.boot.web.servlet.error.ErrorController;
23
+import org.springframework.web.bind.annotation.RequestMapping;
24
+import org.springframework.web.bind.annotation.RestController;
25
+import springfox.documentation.annotations.ApiIgnore;
26
+
27
+import javax.servlet.http.HttpServletRequest;
28
+import javax.servlet.http.HttpServletResponse;
29
+
30
+
31
+/**
32
+ * 全局Error/404处理
33
+ * @author geekidea
34
+ * @date 2018-11-08
35
+ */
36
+@ApiIgnore
37
+@RestController
38
+@Slf4j
39
+public class GlobalErrorController implements ErrorController {
40
+
41
+    private static final String ERROR_PATH = "/error";
42
+
43
+    @RequestMapping(ERROR_PATH)
44
+    public ApiResult<?> handleError(HttpServletRequest request,HttpServletResponse response){
45
+        int status = response.getStatus();
46
+        switch (status){
47
+            case HttpServletResponse.SC_UNAUTHORIZED:
48
+                return ApiResult.fail(ApiCode.UNAUTHORIZED);
49
+            case HttpServletResponse.SC_FORBIDDEN:
50
+                return ApiResult.fail(ApiCode.NOT_PERMISSION);
51
+            case HttpServletResponse.SC_NOT_FOUND:
52
+                return ApiResult.fail(ApiCode.NOT_FOUND);
53
+            default:
54
+                break;
55
+        }
56
+        return ApiResult.fail(ApiCode.FAIL);
57
+    }
58
+
59
+    @Override
60
+    public String getErrorPath() {
61
+        log.error("errorPath....");
62
+        return ERROR_PATH;
63
+    }
64
+}

+ 67
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/common/exception/SpringBootPlusConfigException.java Voir le fichier

@@ -0,0 +1,67 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.common.exception;
18
+
19
+import io.geekidea.springbootplus.framework.common.api.ApiCode;
20
+import lombok.Data;
21
+import lombok.EqualsAndHashCode;
22
+
23
+/**
24
+ * spring-boot-plus配置异常
25
+ *
26
+ * @author geekidea
27
+ * @date 2020/3/21
28
+ */
29
+@Data
30
+@EqualsAndHashCode(callSuper = true)
31
+public class SpringBootPlusConfigException extends SpringBootPlusException {
32
+
33
+    private static final long serialVersionUID = 8952028631871769425L;
34
+
35
+    private Integer errorCode;
36
+    private String message;
37
+
38
+    public SpringBootPlusConfigException() {
39
+        super();
40
+    }
41
+
42
+    public SpringBootPlusConfigException(String message) {
43
+        super(message);
44
+        this.message = message;
45
+    }
46
+
47
+    public SpringBootPlusConfigException(Integer errorCode, String message) {
48
+        super(message);
49
+        this.errorCode = errorCode;
50
+        this.message = message;
51
+    }
52
+
53
+    public SpringBootPlusConfigException(ApiCode apiCode) {
54
+        super(apiCode.getMessage());
55
+        this.errorCode = apiCode.getCode();
56
+        this.message = apiCode.getMessage();
57
+    }
58
+
59
+    public SpringBootPlusConfigException(String message, Throwable cause) {
60
+        super(message, cause);
61
+    }
62
+
63
+    public SpringBootPlusConfigException(Throwable cause) {
64
+        super(cause);
65
+    }
66
+
67
+}

+ 66
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/common/exception/SpringBootPlusException.java Voir le fichier

@@ -0,0 +1,66 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.common.exception;
18
+
19
+import io.geekidea.springbootplus.framework.common.api.ApiCode;
20
+import lombok.Data;
21
+import lombok.EqualsAndHashCode;
22
+
23
+/**
24
+ * 自定义异常
25
+ * @author geekidea
26
+ * @date 2018-11-08
27
+ */
28
+@Data
29
+@EqualsAndHashCode(callSuper = true)
30
+public class SpringBootPlusException extends RuntimeException{
31
+
32
+    private static final long serialVersionUID = -2470461654663264392L;
33
+
34
+    private Integer errorCode;
35
+    private String message;
36
+
37
+    public SpringBootPlusException() {
38
+        super();
39
+    }
40
+
41
+    public SpringBootPlusException(String message) {
42
+        super(message);
43
+        this.message = message;
44
+    }
45
+
46
+    public SpringBootPlusException(Integer errorCode, String message) {
47
+        super(message);
48
+        this.errorCode = errorCode;
49
+        this.message = message;
50
+    }
51
+
52
+    public SpringBootPlusException(ApiCode apiCode) {
53
+        super(apiCode.getMessage());
54
+        this.errorCode = apiCode.getCode();
55
+        this.message = apiCode.getMessage();
56
+    }
57
+
58
+    public SpringBootPlusException(String message, Throwable cause) {
59
+        super(message, cause);
60
+    }
61
+
62
+    public SpringBootPlusException(Throwable cause) {
63
+        super(cause);
64
+    }
65
+
66
+}

+ 39
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/common/param/IdParam.java Voir le fichier

@@ -0,0 +1,39 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.common.param;
18
+
19
+import io.swagger.annotations.ApiModel;
20
+import lombok.Data;
21
+
22
+import javax.validation.constraints.NotNull;
23
+import java.io.Serializable;
24
+
25
+/**
26
+ * ID参数
27
+ *
28
+ * @author geekidea
29
+ * @date 2018-11-08
30
+ */
31
+@Data
32
+@ApiModel("ID参数")
33
+public class IdParam implements Serializable {
34
+    private static final long serialVersionUID = -5353973980674510450L;
35
+
36
+    @NotNull(message = "ID不能为空")
37
+    private Long id;
38
+
39
+}

+ 29
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/common/service/BaseService.java Voir le fichier

@@ -0,0 +1,29 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.common.service;
18
+
19
+import com.baomidou.mybatisplus.extension.service.IService;
20
+
21
+/**
22
+ * 公共Service接口
23
+ *
24
+ * @author geekidea
25
+ * @date 2018-11-08
26
+ */
27
+public interface BaseService<T> extends IService<T> {
28
+
29
+}

+ 61
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/common/service/impl/BaseServiceImpl.java Voir le fichier

@@ -0,0 +1,61 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.common.service.impl;
18
+
19
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
20
+import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
21
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
22
+import io.geekidea.springbootplus.framework.common.service.BaseService;
23
+import io.geekidea.springbootplus.framework.util.LambdaColumn;
24
+
25
+import java.lang.reflect.ParameterizedType;
26
+import java.lang.reflect.Type;
27
+
28
+/**
29
+ * 公共Service父类
30
+ *
31
+ * @author geekidea
32
+ * @date 2018-11-08
33
+ */
34
+public abstract class BaseServiceImpl<M extends BaseMapper<T>, T> extends ServiceImpl<M, T> implements BaseService<T> {
35
+
36
+    /**
37
+     * 实体类型
38
+     */
39
+    private Class<?> entityClass;
40
+
41
+    {
42
+        Class<?> clazz = this.getClass();
43
+        Type type = clazz.getGenericSuperclass();
44
+        if (type instanceof ParameterizedType) {
45
+            Type[] p = ((ParameterizedType) type).getActualTypeArguments();
46
+            this.entityClass = (Class<T>) p[1];
47
+        }
48
+    }
49
+
50
+    /**
51
+     * 获取对应字段的数据表列名称
52
+     *
53
+     * @param func
54
+     * @return
55
+     */
56
+    public String getLambdaColumn(SFunction<T, ?> func) {
57
+        return new LambdaColumn<T>().get(func);
58
+    }
59
+
60
+
61
+}

+ 47
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/common/vo/EnumVo.java Voir le fichier

@@ -0,0 +1,47 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.common.vo;
18
+
19
+import lombok.Data;
20
+import lombok.experimental.Accessors;
21
+
22
+/**
23
+ * 枚举类型VO
24
+ *
25
+ * @author geekidea
26
+ * @date 2019-11-02
27
+ **/
28
+@Data
29
+@Accessors(chain = true)
30
+public class EnumVo<T> {
31
+
32
+    /**
33
+     * 枚举code
34
+     */
35
+    private Integer code;
36
+
37
+    /**
38
+     * 枚举描述
39
+     */
40
+    private String desc;
41
+
42
+    /**
43
+     * 枚举类型
44
+     */
45
+    private T baseEnum;
46
+
47
+}

+ 48
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/config/converter/ConverterConfig.java Voir le fichier

@@ -0,0 +1,48 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.config.converter;
18
+
19
+import org.springframework.context.annotation.Bean;
20
+import org.springframework.context.annotation.Configuration;
21
+import org.springframework.core.convert.converter.Converter;
22
+
23
+import java.util.Date;
24
+
25
+/**
26
+ * 转换器配置
27
+ * @author geekidea
28
+ * @date 2018-11-08
29
+ */
30
+@Configuration
31
+public class ConverterConfig {
32
+
33
+    @Bean
34
+    public Converter<String, Date> stringToDateConverter() {
35
+        return new StringToDateConverter();
36
+    }
37
+
38
+    @Bean
39
+    public Converter<String, Integer> stringToIntegerConverter() {
40
+        return new StringToIntegerConverter();
41
+    }
42
+
43
+    @Bean
44
+    public Converter<String, Double> stringToDoubleConverter() {
45
+        return new StringToDoubleConverter();
46
+    }
47
+
48
+}

+ 36
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/config/converter/StringToDateConverter.java Voir le fichier

@@ -0,0 +1,36 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.config.converter;
18
+
19
+import org.springframework.core.convert.converter.Converter;
20
+
21
+import java.util.Date;
22
+
23
+/**
24
+ * <code>
25
+ * 日期转换器,将请求参数的日期字符串转换成java.util.Date类型
26
+ * </code>
27
+ * @author geekidea
28
+ * @date 2018-11-08
29
+ */
30
+public class StringToDateConverter implements Converter<String, Date> {
31
+
32
+	@Override
33
+	public Date convert(String source) {
34
+		return StringToDateUtil.convert(source);
35
+	}
36
+}

+ 109
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/config/converter/StringToDateUtil.java Voir le fichier

@@ -0,0 +1,109 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.config.converter;
18
+
19
+import org.apache.commons.lang3.StringUtils;
20
+
21
+import java.text.DateFormat;
22
+import java.text.ParseException;
23
+import java.text.SimpleDateFormat;
24
+import java.util.Date;
25
+
26
+/**
27
+ * <code>
28
+ * <pre>
29
+ * 日期转换器,将请求参数的日期字符串转换成java.util.Date类型
30
+ * 日期格式顺序:
31
+ * 	1.yyyy-MM-dd HH:mm:ss:S
32
+ * 	2.yyyy-MM-dd HH:mm:ss
33
+ * 	3.yyyy-MM-dd HH:mm
34
+ * 	4.yyyy-MM-dd HH
35
+ * 	5.yyyy-MM-dd
36
+ * </pre>
37
+ * </code>
38
+ *
39
+ * @author geekidea
40
+ * @date 2018-11-08
41
+ */
42
+public class StringToDateUtil {
43
+
44
+    /**
45
+     * 时间戳字符长度,不包含毫秒
46
+     */
47
+    private static final Integer TIMESTAMP_LENGTH = 10;
48
+
49
+    /**
50
+     * 日期格式化数组
51
+     */
52
+    private static DateFormat[] dateFormats = {
53
+            new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:S"),
54
+            new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"),
55
+            new SimpleDateFormat("yyyy-MM-dd HH:mm"),
56
+            new SimpleDateFormat("yyyy-MM-dd HH"),
57
+            new SimpleDateFormat("yyyy-MM-dd"),
58
+            new SimpleDateFormat("yyyy-MM")
59
+    };
60
+
61
+    /**
62
+     * <code>
63
+     * <pre>
64
+     * 1.如果日期字符串为空,则直接返回空
65
+     * 2.使用格式化组进行格式化,如果解析成功,则直接返回
66
+     * 4.否则,抛出非法参数异常
67
+     * @param source 请求的日期参数
68
+     * @return 解析后的日期类型:java.util.Date
69
+     * @exception IllegalArgumentException 非法参数异常
70
+     * </pre>
71
+     * </code>
72
+     */
73
+    public static Date convert(String source) {
74
+        if (StringUtils.isBlank(source)) {
75
+            return null;
76
+        }
77
+        source = source.trim();
78
+
79
+        try {
80
+            int timeLength = source.length();
81
+            Long time = Long.parseLong(source);
82
+            if (timeLength == TIMESTAMP_LENGTH) {
83
+                time = time * 1000;
84
+            }
85
+            Date date = new Date(time);
86
+            return date;
87
+        } catch (Exception e) {
88
+
89
+        }
90
+
91
+        Date date = null;
92
+        boolean flag = false;
93
+        for (DateFormat dateFormat : dateFormats) {
94
+            try {
95
+                date = dateFormat.parse(source);
96
+                flag = true;
97
+                break;
98
+            } catch (ParseException e) {
99
+            }
100
+        }
101
+
102
+        if (flag) {
103
+            return date;
104
+        } else {
105
+            throw new IllegalArgumentException("不能解析日期:" + source);
106
+        }
107
+
108
+    }
109
+}

+ 34
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/config/converter/StringToDoubleConverter.java Voir le fichier

@@ -0,0 +1,34 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.config.converter;
18
+
19
+import org.springframework.core.convert.converter.Converter;
20
+
21
+/**
22
+ * <code>
23
+ *
24
+ * </code>
25
+ * @author geekidea
26
+ * @date 2018-11-08
27
+ */
28
+public class StringToDoubleConverter implements Converter<String, Double> {
29
+
30
+	@Override
31
+	public Double convert(String source) {
32
+		return StringToDoubleUtil.convert(source);
33
+	}
34
+}

+ 41
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/config/converter/StringToDoubleUtil.java Voir le fichier

@@ -0,0 +1,41 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.config.converter;
18
+
19
+
20
+import org.apache.commons.lang3.StringUtils;
21
+
22
+/**
23
+ * <code>
24
+ * <pre>
25
+ * 空字符串("")转换成Double的null
26
+ *
27
+ * </pre>
28
+ * </code>
29
+ * @author geekidea
30
+ * @date 2018-11-08
31
+ */
32
+public class StringToDoubleUtil {
33
+
34
+	public static Double convert(String source) {
35
+		if (StringUtils.isBlank(source)){
36
+			return null;
37
+		}
38
+		Double d = Double.parseDouble(source);
39
+		return d;
40
+	}
41
+}

+ 34
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/config/converter/StringToIntegerConverter.java Voir le fichier

@@ -0,0 +1,34 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.config.converter;
18
+
19
+import org.springframework.core.convert.converter.Converter;
20
+
21
+/**
22
+ * <code>
23
+ *
24
+ * </code>
25
+ * @author geekidea
26
+ * @date 2018-11-08
27
+ */
28
+public class StringToIntegerConverter implements Converter<String, Integer> {
29
+
30
+	@Override
31
+	public Integer convert(String source) {
32
+		return StringToIntegerUtil.convert(source);
33
+	}
34
+}

+ 40
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/config/converter/StringToIntegerUtil.java Voir le fichier

@@ -0,0 +1,40 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.config.converter;
18
+
19
+import org.apache.commons.lang3.StringUtils;
20
+
21
+/**
22
+ * <code>
23
+ * <pre>
24
+ * 空字符串("")转换成Integer的null
25
+ *
26
+ * </pre>
27
+ * </code>
28
+ * @author geekidea
29
+ * @date 2018-11-08
30
+ */
31
+public class StringToIntegerUtil {
32
+
33
+	public static Integer convert(String source) {
34
+		if (StringUtils.isBlank(source)){
35
+			return null;
36
+		}
37
+		Integer i = Integer.parseInt(source);
38
+		return i;
39
+	}
40
+}

+ 42
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/config/jackson/deserializer/JacksonDateDeserializer.java Voir le fichier

@@ -0,0 +1,42 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.config.jackson.deserializer;
18
+
19
+import com.fasterxml.jackson.core.JsonParser;
20
+import com.fasterxml.jackson.core.JsonProcessingException;
21
+import com.fasterxml.jackson.databind.DeserializationContext;
22
+import com.fasterxml.jackson.databind.JsonDeserializer;
23
+import io.geekidea.springbootplus.framework.config.converter.StringToDateUtil;
24
+
25
+import java.io.IOException;
26
+import java.util.Date;
27
+
28
+/**
29
+ * <p>
30
+ *     Jackson Date序列化器
31
+ * </p>
32
+ * @author geekidea
33
+ * @date 2018-11-08
34
+ */
35
+public class JacksonDateDeserializer extends JsonDeserializer<Date> {
36
+    @Override
37
+    public Date deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
38
+        String date = jp.getText();
39
+        return StringToDateUtil.convert(date);
40
+    }
41
+
42
+}

+ 38
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/config/jackson/deserializer/JacksonDoubleDeserializer.java Voir le fichier

@@ -0,0 +1,38 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.config.jackson.deserializer;
18
+
19
+import com.fasterxml.jackson.core.JsonParser;
20
+import com.fasterxml.jackson.core.JsonProcessingException;
21
+import com.fasterxml.jackson.databind.DeserializationContext;
22
+import com.fasterxml.jackson.databind.JsonDeserializer;
23
+import io.geekidea.springbootplus.framework.config.converter.StringToDoubleUtil;
24
+
25
+import java.io.IOException;
26
+
27
+/**
28
+ * @author geekidea
29
+ * @date 2018-11-08
30
+ */
31
+public class JacksonDoubleDeserializer extends JsonDeserializer<Double> {
32
+
33
+    @Override
34
+    public Double deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
35
+        String string = jsonParser.getText();
36
+        return StringToDoubleUtil.convert(string);
37
+    }
38
+}

+ 47
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/config/jackson/deserializer/JacksonLocalDateTimeDeserializer.java Voir le fichier

@@ -0,0 +1,47 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.config.jackson.deserializer;
18
+
19
+import com.fasterxml.jackson.core.JsonParser;
20
+import com.fasterxml.jackson.databind.DeserializationContext;
21
+import com.fasterxml.jackson.databind.JsonDeserializer;
22
+import io.geekidea.springbootplus.config.constant.DatePattern;
23
+import org.apache.commons.lang3.StringUtils;
24
+
25
+import java.io.IOException;
26
+import java.time.LocalDateTime;
27
+import java.time.format.DateTimeFormatter;
28
+
29
+/**
30
+ * <p>
31
+ *     Jackson LocaDateTime反序列化器
32
+ * </p>
33
+ * @author geekidea
34
+ * @date 2018-11-08
35
+ */
36
+public class JacksonLocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
37
+
38
+    @Override
39
+    public LocalDateTime deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
40
+        String string = jp.getText();
41
+        if (StringUtils.isBlank(string)){
42
+            return null;
43
+        }
44
+        return LocalDateTime.parse(string, DateTimeFormatter.ofPattern(DatePattern.YYYY_MM_DD_HH_MM_SS));
45
+    }
46
+
47
+}

+ 45
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/config/jackson/serializer/JacksonDateSerializer.java Voir le fichier

@@ -0,0 +1,45 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.config.jackson.serializer;
18
+
19
+import com.fasterxml.jackson.core.JsonGenerator;
20
+import com.fasterxml.jackson.core.JsonProcessingException;
21
+import com.fasterxml.jackson.databind.JsonSerializer;
22
+import com.fasterxml.jackson.databind.SerializerProvider;
23
+import io.geekidea.springbootplus.framework.util.DateUtil;
24
+
25
+import java.io.IOException;
26
+import java.util.Date;
27
+
28
+/**
29
+ * <p>
30
+ * Jackson Date反序列化器
31
+ * </p>
32
+ *
33
+ * @author geekidea
34
+ * @date 2018-11-08
35
+ */
36
+public class JacksonDateSerializer extends JsonSerializer<Date> {
37
+    @Override
38
+    public void serialize(Date date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
39
+        String string = null;
40
+        if (date != null) {
41
+            string = DateUtil.getDateTimeString(date);
42
+        }
43
+        jsonGenerator.writeString(string);
44
+    }
45
+}

+ 38
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/config/jackson/serializer/JacksonIntegerDeserializer.java Voir le fichier

@@ -0,0 +1,38 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.config.jackson.serializer;
18
+
19
+import com.fasterxml.jackson.core.JsonParser;
20
+import com.fasterxml.jackson.core.JsonProcessingException;
21
+import com.fasterxml.jackson.databind.DeserializationContext;
22
+import com.fasterxml.jackson.databind.JsonDeserializer;
23
+import io.geekidea.springbootplus.framework.config.converter.StringToIntegerUtil;
24
+
25
+import java.io.IOException;
26
+
27
+/**
28
+ * @author geekidea
29
+ * @date 2018-11-08
30
+ */
31
+public class JacksonIntegerDeserializer extends JsonDeserializer<Integer> {
32
+
33
+    @Override
34
+    public Integer deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
35
+        String string = jsonParser.getText();
36
+        return StringToIntegerUtil.convert(string);
37
+    }
38
+}

+ 48
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/config/jackson/serializer/JacksonLocalDateTimeSerializer.java Voir le fichier

@@ -0,0 +1,48 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.config.jackson.serializer;
18
+
19
+import com.fasterxml.jackson.core.JsonGenerator;
20
+import com.fasterxml.jackson.core.JsonProcessingException;
21
+import com.fasterxml.jackson.databind.JsonSerializer;
22
+import com.fasterxml.jackson.databind.SerializerProvider;
23
+import io.geekidea.springbootplus.config.constant.DatePattern;
24
+
25
+import java.io.IOException;
26
+import java.time.LocalDateTime;
27
+import java.time.format.DateTimeFormatter;
28
+
29
+/**
30
+ * <p>
31
+ * Jackson LocalDateTime 自定义序列化器
32
+ * </p>
33
+ *
34
+ * @author geekidea
35
+ * @date 2018/11/8
36
+ */
37
+public class JacksonLocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {
38
+
39
+    @Override
40
+    public void serialize(LocalDateTime localDateTime, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
41
+        String string = null;
42
+        if (localDateTime != null) {
43
+            string = localDateTime.format(DateTimeFormatter.ofPattern(DatePattern.YYYY_MM_DD_HH_MM_SS));
44
+        }
45
+        jsonGenerator.writeString(string);
46
+    }
47
+
48
+}

+ 45
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/core/bean/RequestDetail.java Voir le fichier

@@ -0,0 +1,45 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.core.bean;
18
+
19
+import lombok.Data;
20
+import lombok.experimental.Accessors;
21
+
22
+import java.io.Serializable;
23
+
24
+/**
25
+ * Filter请求详情信息
26
+ *
27
+ * @author geekidea
28
+ * @date 2020/3/26
29
+ **/
30
+@Data
31
+@Accessors(chain = true)
32
+public class RequestDetail implements Serializable {
33
+	private static final long serialVersionUID = 2543641512850125440L;
34
+
35
+	/**
36
+     * 请求ip地址
37
+     */
38
+    private String ip;
39
+
40
+    /**
41
+     * 请求路径
42
+     */
43
+    private String path;
44
+
45
+}

+ 64
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/core/filter/RequestDetailFilter.java Voir le fichier

@@ -0,0 +1,64 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.core.filter;
18
+
19
+import io.geekidea.springbootplus.framework.core.bean.RequestDetail;
20
+import io.geekidea.springbootplus.framework.core.util.RequestDetailThreadLocal;
21
+import io.geekidea.springbootplus.framework.util.IpUtil;
22
+import lombok.extern.slf4j.Slf4j;
23
+
24
+import javax.servlet.*;
25
+import javax.servlet.http.HttpServletRequest;
26
+import java.io.IOException;
27
+
28
+/**
29
+ * 请求详情信息Filter
30
+ *
31
+ * @author geekidea
32
+ * @date 2020/3/25
33
+ **/
34
+@Slf4j
35
+public class RequestDetailFilter implements Filter {
36
+
37
+    @Override
38
+    public void init(FilterConfig filterConfig) throws ServletException {
39
+        log.info("RequestDetailFilter init");
40
+    }
41
+
42
+    @Override
43
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
44
+        // 设置请求详情信息
45
+        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
46
+        // 请求IP
47
+        String ip = IpUtil.getRequestIp(httpServletRequest);
48
+        // 请求路径
49
+        String path = httpServletRequest.getRequestURI();
50
+        RequestDetail requestDetail = new RequestDetail()
51
+                .setIp(ip)
52
+                .setPath(path);
53
+        // 设置请求详情信息
54
+        RequestDetailThreadLocal.setRequestDetail(requestDetail);
55
+        chain.doFilter(request, response);
56
+        // 释放
57
+        RequestDetailThreadLocal.remove();
58
+    }
59
+
60
+    @Override
61
+    public void destroy() {
62
+        log.info("RequestDetailFilter destroy");
63
+    }
64
+}

+ 48
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/core/interceptor/PermissionInterceptor.java Voir le fichier

@@ -0,0 +1,48 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.core.interceptor;
18
+
19
+import lombok.extern.slf4j.Slf4j;
20
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
21
+import org.springframework.web.servlet.ModelAndView;
22
+import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
23
+
24
+import javax.servlet.http.HttpServletRequest;
25
+import javax.servlet.http.HttpServletResponse;
26
+
27
+/**
28
+ * 自定义权限拦截器
29
+ *
30
+ * @author geekidea
31
+ * @since 2018-11-08
32
+ */
33
+@Slf4j
34
+@ConditionalOnProperty(value = {"spring-boot-plus.interceptor.permission.enable"}, matchIfMissing = true)
35
+public class PermissionInterceptor extends HandlerInterceptorAdapter {
36
+
37
+    @Override
38
+    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
39
+            throws Exception {
40
+        return true;
41
+    }
42
+
43
+    @Override
44
+    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
45
+
46
+    }
47
+
48
+}

+ 55
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/core/pagination/BasePageOrderParam.java Voir le fichier

@@ -0,0 +1,55 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.core.pagination;
18
+
19
+import com.baomidou.mybatisplus.core.metadata.OrderItem;
20
+import io.swagger.annotations.ApiModel;
21
+import io.swagger.annotations.ApiModelProperty;
22
+import lombok.Data;
23
+import lombok.EqualsAndHashCode;
24
+import org.apache.commons.collections.CollectionUtils;
25
+
26
+import java.util.Arrays;
27
+import java.util.List;
28
+
29
+/**
30
+ * 可排序查询参数对象
31
+ *
32
+ * @author geekidea
33
+ * @since 2019-08-04
34
+ */
35
+@Data
36
+@EqualsAndHashCode(callSuper = true)
37
+@ApiModel("可排序查询参数对象")
38
+public abstract class BasePageOrderParam extends BasePageParam {
39
+    private static final long serialVersionUID = 57714391204790143L;
40
+
41
+    @ApiModelProperty("排序")
42
+    private List<OrderItem> pageSorts;
43
+
44
+    public void defaultPageSort(OrderItem orderItem) {
45
+        this.defaultPageSorts(Arrays.asList(orderItem));
46
+    }
47
+
48
+    public void defaultPageSorts(List<OrderItem> pageSorts) {
49
+        if (CollectionUtils.isEmpty(pageSorts)) {
50
+            return;
51
+        }
52
+        this.pageSorts = pageSorts;
53
+    }
54
+
55
+}

+ 62
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/core/pagination/BasePageParam.java Voir le fichier

@@ -0,0 +1,62 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.core.pagination;
18
+
19
+import io.geekidea.springbootplus.config.constant.CommonConstant;
20
+import io.swagger.annotations.ApiModel;
21
+import io.swagger.annotations.ApiModelProperty;
22
+import lombok.Data;
23
+
24
+import java.io.Serializable;
25
+
26
+/**
27
+ * 查询参数
28
+ *
29
+ * @author geekidea
30
+ * @since 2018-11-08
31
+ */
32
+@Data
33
+@ApiModel("查询参数对象")
34
+public abstract class BasePageParam implements Serializable {
35
+    private static final long serialVersionUID = -3263921252635611410L;
36
+
37
+    @ApiModelProperty(value = "页码,默认为1", example = "1")
38
+    private Long pageIndex = CommonConstant.DEFAULT_PAGE_INDEX;
39
+
40
+    @ApiModelProperty(value = "页大小,默认为10", example = "10")
41
+    private Long pageSize = CommonConstant.DEFAULT_PAGE_SIZE;
42
+
43
+    @ApiModelProperty(value = "搜索字符串", example = "")
44
+    private String keyword;
45
+
46
+    public void setPageIndex(Long pageIndex) {
47
+        if (pageIndex == null || pageIndex <= 0) {
48
+            this.pageIndex = CommonConstant.DEFAULT_PAGE_INDEX;
49
+        } else {
50
+            this.pageIndex = pageIndex;
51
+        }
52
+    }
53
+
54
+    public void setPageSize(Long pageSize) {
55
+        if (pageSize == null || pageSize <= 0) {
56
+            this.pageSize = CommonConstant.DEFAULT_PAGE_SIZE;
57
+        } else {
58
+            this.pageSize = pageSize;
59
+        }
60
+    }
61
+
62
+}

+ 108
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/core/pagination/OrderMapping.java Voir le fichier

@@ -0,0 +1,108 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.core.pagination;
18
+
19
+import com.baomidou.mybatisplus.core.metadata.OrderItem;
20
+import com.google.common.base.CaseFormat;
21
+import io.geekidea.springbootplus.framework.util.PropertyColumnUtil;
22
+import lombok.Data;
23
+import lombok.experimental.Accessors;
24
+import org.apache.commons.collections4.CollectionUtils;
25
+import org.apache.commons.collections4.MapUtils;
26
+import org.apache.commons.lang3.StringUtils;
27
+
28
+import java.util.List;
29
+import java.util.Map;
30
+import java.util.concurrent.ConcurrentHashMap;
31
+
32
+/**
33
+ * 排序列映射
34
+ *
35
+ * @author geekidea
36
+ * @date 2020/3/14
37
+ **/
38
+@Data
39
+@Accessors(chain = true)
40
+public class OrderMapping {
41
+
42
+    private boolean underLineMode;
43
+
44
+    public OrderMapping() {
45
+
46
+    }
47
+
48
+    public OrderMapping(boolean underLineMode) {
49
+        this.underLineMode = underLineMode;
50
+    }
51
+
52
+    private Map<String, String> map = new ConcurrentHashMap<>();
53
+
54
+    public OrderMapping mapping(String property, String column) {
55
+        map.put(property, column);
56
+        return this;
57
+    }
58
+
59
+    public OrderMapping mapping(String property, String tablePrefix, String column) {
60
+        if (StringUtils.isNotBlank(tablePrefix)) {
61
+            column = tablePrefix + "." + column;
62
+        }
63
+        map.put(property, column);
64
+        return this;
65
+    }
66
+
67
+
68
+    public OrderMapping mapping(String property, Class<?> clazz) {
69
+        String column = PropertyColumnUtil.getColumn(clazz, property);
70
+        map.put(property, column);
71
+        return this;
72
+    }
73
+
74
+    public OrderMapping mapping(String property, String tablePrefix, Class<?> clazz) {
75
+        String column = PropertyColumnUtil.getColumn(clazz, property);
76
+        mapping(property, tablePrefix, column);
77
+        return this;
78
+    }
79
+
80
+    public String getMappingColumn(String property) {
81
+        if (StringUtils.isBlank(property)) {
82
+            return null;
83
+        }
84
+        return map.get(property);
85
+    }
86
+
87
+    public void filterOrderItems(List<OrderItem> orderItems) {
88
+        if (CollectionUtils.isEmpty(orderItems)) {
89
+            return;
90
+        }
91
+        // 如果集合不为空,则按照PropertyColumnUtil映射
92
+        if (MapUtils.isNotEmpty(map)) {
93
+            orderItems.forEach(item -> {
94
+                item.setColumn(this.getMappingColumn(item.getColumn()));
95
+            });
96
+        } else if (underLineMode) {
97
+            // 如果开启下划线模式,自动转换成下划线
98
+            orderItems.forEach(item -> {
99
+                String column = item.getColumn();
100
+                if (StringUtils.isNotBlank(column)) {
101
+                    // 驼峰转换成下划线
102
+                    item.setColumn(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, column));
103
+                }
104
+            });
105
+        }
106
+    }
107
+
108
+}

+ 165
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/core/pagination/PageInfo.java Voir le fichier

@@ -0,0 +1,165 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.core.pagination;
18
+
19
+import com.baomidou.mybatisplus.core.metadata.OrderItem;
20
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
21
+import lombok.Data;
22
+import lombok.EqualsAndHashCode;
23
+import lombok.experimental.Accessors;
24
+import org.apache.commons.collections4.CollectionUtils;
25
+
26
+import java.util.Arrays;
27
+import java.util.List;
28
+
29
+/**
30
+ * 自定义分页参数
31
+ *
32
+ * @author geekidea
33
+ * @date 2020/3/27
34
+ **/
35
+@Data
36
+@Accessors(chain = true)
37
+@EqualsAndHashCode(callSuper = true)
38
+public class PageInfo<T> extends Page<T> {
39
+	private static final long serialVersionUID = -2211095086394170578L;
40
+
41
+	/**
42
+     * 分页参数
43
+     */
44
+    private BasePageParam pageParam;
45
+
46
+    /**
47
+     * 默认排序字段信息
48
+     */
49
+    private OrderItem defaultOrderItem;
50
+
51
+    /**
52
+     * 排序字段映射
53
+     */
54
+    private OrderMapping orderMapping;
55
+
56
+
57
+    public PageInfo() {
58
+
59
+    }
60
+
61
+    /**
62
+     * 传入分页参数
63
+     *
64
+     * @param pageParam
65
+     */
66
+    public PageInfo(BasePageParam pageParam) {
67
+        this(pageParam, null, null);
68
+    }
69
+
70
+    /**
71
+     * 传入分页参数,默认排序
72
+     *
73
+     * @param basePageParam
74
+     * @param defaultOrderItem
75
+     */
76
+    public PageInfo(BasePageParam basePageParam, OrderItem defaultOrderItem) {
77
+        this(basePageParam, defaultOrderItem, null);
78
+    }
79
+
80
+    /**
81
+     * 传入分页参数,排序字段映射
82
+     *
83
+     * @param pageParam
84
+     * @param orderMapping
85
+     */
86
+    public PageInfo(BasePageParam pageParam, OrderMapping orderMapping) {
87
+        this(pageParam, null, orderMapping);
88
+    }
89
+
90
+    /**
91
+     * 传入分页参数,默认排序,排序字段映射
92
+     *
93
+     * @param pageParam
94
+     * @param defaultOrderItem
95
+     * @param orderMapping
96
+     */
97
+    public PageInfo(BasePageParam pageParam, OrderItem defaultOrderItem, OrderMapping orderMapping) {
98
+        this.pageParam = pageParam;
99
+        this.defaultOrderItem = defaultOrderItem;
100
+        this.orderMapping = orderMapping;
101
+        this.handle();
102
+    }
103
+
104
+    /**
105
+     * 分页构造函数
106
+     *
107
+     * @param current 当前页
108
+     * @param size    每页显示条数
109
+     */
110
+    public PageInfo(long current, long size) {
111
+        super(current, size, 0);
112
+    }
113
+
114
+    public PageInfo(long current, long size, long total) {
115
+        super(current, size, total, true);
116
+    }
117
+
118
+    public PageInfo(long current, long size, boolean isSearchCount) {
119
+        super(current, size, isSearchCount);
120
+    }
121
+
122
+    public PageInfo(long current, long size, long total, boolean isSearchCount) {
123
+        super(current, size, total, isSearchCount);
124
+    }
125
+
126
+    /**
127
+     * 如果是pageParam是OrderPageParam,并且不为空,则使用前端排序
128
+     * 否则使用默认排序
129
+     */
130
+    private void handle() {
131
+        if (pageParam == null) {
132
+            return;
133
+        }
134
+        // 设置pageIndex/pageSize
135
+        super.setCurrent(pageParam.getPageIndex());
136
+        super.setSize(pageParam.getPageSize());
137
+        // 排序字段处理
138
+        BasePageOrderParam basePageOrderParam = (BasePageOrderParam) pageParam;
139
+        List<OrderItem> orderItems = basePageOrderParam.getPageSorts();
140
+        if (CollectionUtils.isEmpty(orderItems)) {
141
+            setDefaultOrder(defaultOrderItem);
142
+            return;
143
+        }
144
+        if (orderMapping == null) {
145
+            orderMapping = new OrderMapping(true);
146
+        }
147
+        orderMapping.filterOrderItems(orderItems);
148
+        super.setOrders(orderItems);
149
+    }
150
+
151
+    /**
152
+     * 设置默认排序
153
+     *
154
+     * @param defaultOrderItem
155
+     * @return
156
+     */
157
+    public PageInfo<T> setDefaultOrder(OrderItem defaultOrderItem) {
158
+        if (defaultOrderItem != null) {
159
+            this.defaultOrderItem = defaultOrderItem;
160
+            super.setOrders(Arrays.asList(defaultOrderItem));
161
+        }
162
+        return this;
163
+    }
164
+
165
+}

+ 76
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/core/pagination/Paging.java Voir le fichier

@@ -0,0 +1,76 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.core.pagination;
18
+
19
+import com.alibaba.fastjson.annotation.JSONField;
20
+import com.baomidou.mybatisplus.core.metadata.IPage;
21
+import com.fasterxml.jackson.annotation.JsonProperty;
22
+import io.geekidea.springbootplus.config.constant.CommonConstant;
23
+import io.swagger.annotations.ApiModel;
24
+import io.swagger.annotations.ApiModelProperty;
25
+import lombok.Data;
26
+import lombok.extern.slf4j.Slf4j;
27
+
28
+import java.io.Serializable;
29
+import java.util.Collections;
30
+import java.util.List;
31
+
32
+/**
33
+ * 分页结果对象
34
+ *
35
+ * @author geekidea
36
+ * @date 2018-11-08
37
+ */
38
+
39
+@Slf4j
40
+@Data
41
+@ApiModel("分页结果对象")
42
+public class Paging<T> implements Serializable {
43
+    private static final long serialVersionUID = 4784961132604516495L;
44
+
45
+    @ApiModelProperty("总行数")
46
+    @JSONField(name = CommonConstant.PAGE_TOTAL_NAME)
47
+    @JsonProperty(CommonConstant.PAGE_TOTAL_NAME)
48
+    private long total = 0;
49
+
50
+    @ApiModelProperty("数据列表")
51
+    @JSONField(name = CommonConstant.PAGE_RECORDS_NAME)
52
+    @JsonProperty(CommonConstant.PAGE_RECORDS_NAME)
53
+    private List<T> records = Collections.emptyList();
54
+
55
+    @ApiModelProperty(value = "页码")
56
+    @JSONField(name = CommonConstant.PAGE_INDEX_NAME)
57
+    @JsonProperty(CommonConstant.PAGE_INDEX_NAME)
58
+    private Long pageIndex;
59
+
60
+    @ApiModelProperty(value = "页大小")
61
+    @JSONField(name = CommonConstant.PAGE_SIZE_NAME)
62
+    @JsonProperty(CommonConstant.PAGE_SIZE_NAME)
63
+    private Long pageSize;
64
+
65
+    public Paging() {
66
+
67
+    }
68
+
69
+    public Paging(IPage<T> page) {
70
+        this.total = page.getTotal();
71
+        this.records = page.getRecords();
72
+        this.pageIndex = page.getCurrent();
73
+        this.pageSize = page.getSize();
74
+    }
75
+
76
+}

+ 54
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/core/util/RequestDetailThreadLocal.java Voir le fichier

@@ -0,0 +1,54 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.core.util;
18
+
19
+import io.geekidea.springbootplus.framework.core.bean.RequestDetail;
20
+
21
+/**
22
+ * 记录请求详情信息到当前线程中,可在任何地方获取
23
+ *
24
+ * @author geekidea
25
+ * @date 2020/3/26
26
+ **/
27
+public class RequestDetailThreadLocal {
28
+
29
+    private static ThreadLocal<RequestDetail> threadLocal = new ThreadLocal<>();
30
+
31
+    /**
32
+     * 设置请求信息到当前线程中
33
+     *
34
+     * @param requestDetail
35
+     */
36
+    public static void setRequestDetail(RequestDetail requestDetail) {
37
+        threadLocal.set(requestDetail);
38
+    }
39
+
40
+    /**
41
+     * 从当前线程中获取请求信息
42
+     */
43
+    public static RequestDetail getRequestDetail() {
44
+        return threadLocal.get();
45
+    }
46
+
47
+    /**
48
+     * 销毁
49
+     */
50
+    public static void remove() {
51
+        threadLocal.remove();
52
+    }
53
+
54
+}

+ 52
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/core/validator/EnumTypeValidator.java Voir le fichier

@@ -0,0 +1,52 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.core.validator;
18
+
19
+import io.geekidea.springbootplus.framework.common.enums.BaseEnum;
20
+import io.geekidea.springbootplus.framework.common.exception.BusinessException;
21
+import io.geekidea.springbootplus.framework.core.validator.constraints.EnumType;
22
+import io.geekidea.springbootplus.framework.util.BaseEnumUtil;
23
+
24
+import javax.validation.ConstraintValidator;
25
+import javax.validation.ConstraintValidatorContext;
26
+
27
+/**
28
+ * 自定义系统内的枚举验证注解实现类
29
+ *
30
+ * @author geekidea
31
+ * @date 2018-11-08
32
+ */
33
+public class EnumTypeValidator implements ConstraintValidator<EnumType, Integer> {
34
+
35
+    private Class<? extends BaseEnum> baseEnum;
36
+
37
+    @Override
38
+    public void initialize(EnumType parameters) {
39
+        baseEnum = parameters.type();
40
+        if (baseEnum == null) {
41
+            throw new BusinessException("请传入枚举类型类");
42
+        }
43
+    }
44
+
45
+    @Override
46
+    public boolean isValid(Integer value, ConstraintValidatorContext constraintValidatorContext) {
47
+        if (value == null) {
48
+            return true;
49
+        }
50
+        return BaseEnumUtil.exists(baseEnum, value);
51
+    }
52
+}

+ 45
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/core/validator/IdCardValidator.java Voir le fichier

@@ -0,0 +1,45 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.core.validator;
18
+
19
+import io.geekidea.springbootplus.framework.core.validator.constraints.IdCard;
20
+
21
+import javax.validation.ConstraintValidator;
22
+import javax.validation.ConstraintValidatorContext;
23
+import java.util.regex.Pattern;
24
+
25
+/**
26
+ * 自定义身份证号码验证注解实现类
27
+ * @author geekidea
28
+ * @date 2018-11-08
29
+ */
30
+public class IdCardValidator implements ConstraintValidator<IdCard, String> {
31
+	private static final String REG_EX = "(^[1-9]\\d{7}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{2}[0-9Xx]$)|(^[1-9]\\d{5}[1-9]\\d{3}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}[0-9Xx]$)";
32
+	private static final Pattern PATTERN = Pattern.compile(REG_EX);
33
+
34
+	@Override
35
+	public void initialize(IdCard parameters) {
36
+	}
37
+
38
+	@Override
39
+	public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
40
+		if (value ==null){
41
+			return true;
42
+		}
43
+		return PATTERN.matcher(value).matches();
44
+	}
45
+}

+ 46
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/core/validator/PhoneValidator.java Voir le fichier

@@ -0,0 +1,46 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.core.validator;
18
+
19
+import io.geekidea.springbootplus.framework.core.validator.constraints.Phone;
20
+
21
+import javax.validation.ConstraintValidator;
22
+import javax.validation.ConstraintValidatorContext;
23
+import java.util.regex.Pattern;
24
+
25
+/**
26
+ * 自定义手机号码验证注解实现类
27
+ * @author geekidea
28
+ * @date 2018-11-08
29
+ */
30
+public class PhoneValidator implements ConstraintValidator<Phone, String> {
31
+
32
+	private static final String REG_EX = "^1[3,4,5,6,7,8,9]\\d{9}$";
33
+	private static final Pattern PATTERN = Pattern.compile(REG_EX);
34
+
35
+	@Override
36
+	public void initialize(Phone parameters) {
37
+	}
38
+
39
+	@Override
40
+	public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
41
+		if (value ==null){
42
+			return true;
43
+		}
44
+		return PATTERN.matcher(value).matches();
45
+	}
46
+}

+ 49
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/core/validator/constraints/EnumType.java Voir le fichier

@@ -0,0 +1,49 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.core.validator.constraints;
18
+
19
+import io.geekidea.springbootplus.framework.common.enums.BaseEnum;
20
+import io.geekidea.springbootplus.framework.core.validator.EnumTypeValidator;
21
+
22
+import javax.validation.Constraint;
23
+import javax.validation.Payload;
24
+import java.lang.annotation.Documented;
25
+import java.lang.annotation.Retention;
26
+import java.lang.annotation.Target;
27
+
28
+import static java.lang.annotation.ElementType.*;
29
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
30
+
31
+/**
32
+ * 枚举类型注解
33
+ * @author geekidea
34
+ * @date 2018-11-08
35
+ */
36
+@Documented
37
+@Constraint(validatedBy = { EnumTypeValidator.class })
38
+@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
39
+@Retention(RUNTIME)
40
+public @interface EnumType {
41
+	String message() default "请输入正确的类型值";
42
+
43
+	Class<? extends BaseEnum> type();
44
+
45
+	Class<?>[] groups() default { };
46
+
47
+	Class<? extends Payload>[] payload() default { };
48
+
49
+}

+ 46
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/core/validator/constraints/IdCard.java Voir le fichier

@@ -0,0 +1,46 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.core.validator.constraints;
18
+
19
+import io.geekidea.springbootplus.framework.core.validator.IdCardValidator;
20
+
21
+import javax.validation.Constraint;
22
+import javax.validation.Payload;
23
+import java.lang.annotation.Documented;
24
+import java.lang.annotation.Retention;
25
+import java.lang.annotation.Target;
26
+
27
+import static java.lang.annotation.ElementType.*;
28
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
29
+
30
+/**
31
+ * 自定义身份证号码正则验证注解
32
+ * @author geekidea
33
+ * @date 2018-11-08
34
+ */
35
+@Documented
36
+@Constraint(validatedBy = { IdCardValidator.class })
37
+@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
38
+@Retention(RUNTIME)
39
+public @interface IdCard {
40
+	String message() default "请输入有效的身份证号码";
41
+
42
+	Class<?>[] groups() default { };
43
+
44
+	Class<? extends Payload>[] payload() default { };
45
+
46
+}

+ 46
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/core/validator/constraints/Phone.java Voir le fichier

@@ -0,0 +1,46 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.core.validator.constraints;
18
+
19
+import io.geekidea.springbootplus.framework.core.validator.PhoneValidator;
20
+
21
+import javax.validation.Constraint;
22
+import javax.validation.Payload;
23
+import java.lang.annotation.Documented;
24
+import java.lang.annotation.Retention;
25
+import java.lang.annotation.Target;
26
+
27
+import static java.lang.annotation.ElementType.*;
28
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
29
+
30
+/**
31
+ * 自定义手机号码正则验证注解
32
+ * @author geekidea
33
+ * @date 2018-11-08
34
+ */
35
+@Documented
36
+@Constraint(validatedBy = { PhoneValidator.class })
37
+@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
38
+@Retention(RUNTIME)
39
+public @interface Phone {
40
+	String message() default "请输入有效的手机号码";
41
+
42
+	Class<?>[] groups() default { };
43
+
44
+	Class<? extends Payload>[] payload() default { };
45
+
46
+}

+ 28
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/core/validator/groups/Add.java Voir le fichier

@@ -0,0 +1,28 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.core.validator.groups;
18
+
19
+import javax.validation.groups.Default;
20
+
21
+/**
22
+ * Validator分组验证:添加
23
+ *
24
+ * @author geekidea
25
+ * @date 2020/3/8
26
+ **/
27
+public interface Add extends Default {
28
+}

+ 28
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/core/validator/groups/Update.java Voir le fichier

@@ -0,0 +1,28 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.core.validator.groups;
18
+
19
+import javax.validation.groups.Default;
20
+
21
+/**
22
+ * Validator分组验证:修改
23
+ *
24
+ * @author geekidea
25
+ * @date 2020/3/8
26
+ **/
27
+public interface Update extends Default {
28
+}

+ 50
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/core/xss/XssFilter.java Voir le fichier

@@ -0,0 +1,50 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.core.xss;
18
+
19
+import lombok.extern.slf4j.Slf4j;
20
+
21
+import javax.servlet.*;
22
+import javax.servlet.http.HttpServletRequest;
23
+import java.io.IOException;
24
+
25
+/**
26
+ * Xss过滤器
27
+ *
28
+ * @author geekidea
29
+ * @date 2019-10-10
30
+ * @since 1.3.1.RELEASE
31
+ **/
32
+@Slf4j
33
+public class XssFilter implements Filter {
34
+    @Override
35
+    public void init(FilterConfig filterConfig) throws ServletException {
36
+        log.info("XssFilter init");
37
+    }
38
+
39
+    @Override
40
+    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
41
+        HttpServletRequest request = (HttpServletRequest) servletRequest;
42
+        XssHttpServletRequestWrapper xssHttpServletRequestWrapper = new XssHttpServletRequestWrapper(request);
43
+        filterChain.doFilter(xssHttpServletRequestWrapper, servletResponse);
44
+    }
45
+
46
+    @Override
47
+    public void destroy() {
48
+        log.info("XssFilter destroy");
49
+    }
50
+}

+ 62
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/core/xss/XssHttpServletRequestWrapper.java Voir le fichier

@@ -0,0 +1,62 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.core.xss;
18
+
19
+import org.apache.commons.lang3.ArrayUtils;
20
+import org.apache.commons.text.StringEscapeUtils;
21
+
22
+import javax.servlet.http.HttpServletRequest;
23
+import javax.servlet.http.HttpServletRequestWrapper;
24
+
25
+/**
26
+ * XSS 跨站脚本攻击(Cross Site Scripting) 处理
27
+ *
28
+ * @author geekidea
29
+ * @date 2019-10-10
30
+ * @since 1.3.1.RELEASE
31
+ **/
32
+public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
33
+
34
+    public XssHttpServletRequestWrapper(HttpServletRequest request) {
35
+        super(request);
36
+    }
37
+
38
+    @Override
39
+    public String getQueryString() {
40
+        return StringEscapeUtils.escapeHtml4(super.getQueryString());
41
+    }
42
+
43
+    @Override
44
+    public String getParameter(String name) {
45
+        return StringEscapeUtils.escapeHtml4(super.getParameter(name));
46
+    }
47
+
48
+    @Override
49
+    public String[] getParameterValues(String name) {
50
+        String[] values = super.getParameterValues(name);
51
+        if (ArrayUtils.isEmpty(values)) {
52
+            return values;
53
+        }
54
+        int length = values.length;
55
+        String[] escapeValues = new String[length];
56
+        for (int i = 0; i < length; i++) {
57
+            escapeValues[i] = StringEscapeUtils.escapeHtml4(values[i]);
58
+        }
59
+        return escapeValues;
60
+    }
61
+
62
+}

+ 41
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/core/xss/XssJacksonDeserializer.java Voir le fichier

@@ -0,0 +1,41 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.core.xss;
18
+
19
+import com.fasterxml.jackson.core.JsonParser;
20
+import com.fasterxml.jackson.core.JsonProcessingException;
21
+import com.fasterxml.jackson.databind.DeserializationContext;
22
+import com.fasterxml.jackson.databind.JsonDeserializer;
23
+import org.apache.commons.text.StringEscapeUtils;
24
+
25
+import java.io.IOException;
26
+
27
+/**
28
+ * Jackson请求参数字符串转义处理
29
+ *
30
+ * @author geekidea
31
+ * @date 2019-10-10
32
+ * @since 1.3.1.RELEASE
33
+ **/
34
+public class XssJacksonDeserializer extends JsonDeserializer<String> {
35
+
36
+    @Override
37
+    public String deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
38
+        return StringEscapeUtils.escapeHtml4(jsonParser.getText());
39
+    }
40
+
41
+}

+ 42
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/core/xss/XssJacksonSerializer.java Voir le fichier

@@ -0,0 +1,42 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.core.xss;
18
+
19
+import com.fasterxml.jackson.core.JsonGenerator;
20
+import com.fasterxml.jackson.databind.JsonSerializer;
21
+import com.fasterxml.jackson.databind.SerializerProvider;
22
+import lombok.extern.slf4j.Slf4j;
23
+import org.apache.commons.text.StringEscapeUtils;
24
+
25
+import java.io.IOException;
26
+
27
+/**
28
+ * Jackson响应参数字符串转义处理
29
+ *
30
+ * @author geekidea
31
+ * @date 2019-10-10
32
+ * @since 1.3.1.RELEASE
33
+ **/
34
+@Slf4j
35
+public class XssJacksonSerializer extends JsonSerializer<String> {
36
+
37
+    @Override
38
+    public void serialize(String s, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
39
+        jsonGenerator.writeString(StringEscapeUtils.escapeHtml4(s));
40
+    }
41
+
42
+}

+ 58
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/ip/entity/IpAddress.java Voir le fichier

@@ -0,0 +1,58 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.ip.entity;
18
+
19
+import com.baomidou.mybatisplus.annotation.IdType;
20
+import com.baomidou.mybatisplus.annotation.TableId;
21
+import io.geekidea.springbootplus.framework.common.entity.BaseEntity;
22
+import io.swagger.annotations.ApiModel;
23
+import io.swagger.annotations.ApiModelProperty;
24
+import lombok.Data;
25
+import lombok.EqualsAndHashCode;
26
+import lombok.experimental.Accessors;
27
+
28
+/**
29
+ * IP地址
30
+ *
31
+ * @author geekidea
32
+ * @since 2020-03-25
33
+ */
34
+@Data
35
+@Accessors(chain = true)
36
+@EqualsAndHashCode(callSuper = true)
37
+@ApiModel(value = "IpAddress对象")
38
+public class IpAddress extends BaseEntity {
39
+    private static final long serialVersionUID = 1L;
40
+
41
+    @TableId(value = "id", type = IdType.AUTO)
42
+    private Long id;
43
+
44
+    private String ipStart;
45
+
46
+    private String ipEnd;
47
+
48
+    @ApiModelProperty("区域")
49
+    private String area;
50
+
51
+    @ApiModelProperty("运营商")
52
+    private String operator;
53
+
54
+    private Long ipStartNum;
55
+
56
+    private Long ipEndNum;
57
+
58
+}

+ 41
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/ip/mapper/IpAddressMapper.java Voir le fichier

@@ -0,0 +1,41 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.ip.mapper;
18
+
19
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
20
+import io.geekidea.springbootplus.framework.ip.entity.IpAddress;
21
+import org.apache.ibatis.annotations.Param;
22
+import org.springframework.stereotype.Repository;
23
+
24
+/**
25
+ * IP地址 Mapper 接口
26
+ *
27
+ * @author geekidea
28
+ * @since 2020-03-25
29
+ */
30
+@Repository
31
+public interface IpAddressMapper extends BaseMapper<IpAddress> {
32
+
33
+    /**
34
+     * 通过ip地址获取IP对象
35
+     *
36
+     * @param ip
37
+     * @return
38
+     */
39
+    IpAddress getByIp(@Param("ip") String ip);
40
+
41
+}

+ 54
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/ip/service/IpAddressService.java Voir le fichier

@@ -0,0 +1,54 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.ip.service;
18
+
19
+import io.geekidea.springbootplus.framework.common.service.BaseService;
20
+import io.geekidea.springbootplus.framework.ip.entity.IpAddress;
21
+
22
+/**
23
+ * IP地址 服务类
24
+ *
25
+ * @author geekidea
26
+ * @since 2020-03-25
27
+ */
28
+public interface IpAddressService extends BaseService<IpAddress> {
29
+
30
+    /**
31
+     * 通过ip地址获取IP对象
32
+     *
33
+     * @param ip
34
+     * @return
35
+     */
36
+    IpAddress getByIp(String ip);
37
+
38
+    /**
39
+     * 通过ip地址获取区域
40
+     *
41
+     * @param ip
42
+     * @return
43
+     */
44
+    String getAreaByIp(String ip);
45
+
46
+    /**
47
+     * 通过ip地址获取运营商
48
+     *
49
+     * @param ip
50
+     * @return
51
+     */
52
+    String getOperatorByIp(String ip);
53
+
54
+}

+ 74
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/ip/service/impl/IpAddressServiceImpl.java Voir le fichier

@@ -0,0 +1,74 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.ip.service.impl;
18
+
19
+import io.geekidea.springbootplus.config.constant.CommonConstant;
20
+import io.geekidea.springbootplus.framework.common.service.impl.BaseServiceImpl;
21
+import io.geekidea.springbootplus.framework.ip.entity.IpAddress;
22
+import io.geekidea.springbootplus.framework.ip.mapper.IpAddressMapper;
23
+import io.geekidea.springbootplus.framework.ip.service.IpAddressService;
24
+import lombok.extern.slf4j.Slf4j;
25
+import org.apache.commons.lang3.StringUtils;
26
+import org.springframework.beans.factory.annotation.Autowired;
27
+import org.springframework.stereotype.Service;
28
+
29
+/**
30
+ * IP地址 服务实现类
31
+ *
32
+ * @author geekidea
33
+ * @since 2020-03-25
34
+ */
35
+@Slf4j
36
+@Service
37
+public class IpAddressServiceImpl extends BaseServiceImpl<IpAddressMapper, IpAddress> implements IpAddressService {
38
+
39
+    @Autowired
40
+    private IpAddressMapper ipAddressMapper;
41
+
42
+
43
+    @Override
44
+    public IpAddress getByIp(String ip) {
45
+        if (StringUtils.isBlank(ip)) {
46
+            return null;
47
+        }
48
+        if (CommonConstant.LOCALHOST_IP.equals(ip)) {
49
+            return new IpAddress().setArea(CommonConstant.LOCALHOST_IP_NAME);
50
+        }
51
+        if (CommonConstant.LAN_IP.equals(ip)) {
52
+            return new IpAddress().setArea(CommonConstant.LAN_IP_NAME);
53
+        }
54
+        return ipAddressMapper.getByIp(ip);
55
+    }
56
+
57
+    @Override
58
+    public String getAreaByIp(String ip) {
59
+        IpAddress ipAddress = getByIp(ip);
60
+        if (ipAddress != null) {
61
+            return ipAddress.getArea();
62
+        }
63
+        return null;
64
+    }
65
+
66
+    @Override
67
+    public String getOperatorByIp(String ip) {
68
+        IpAddress ipAddress = getByIp(ip);
69
+        if (ipAddress != null) {
70
+            return ipAddress.getOperator();
71
+        }
72
+        return null;
73
+    }
74
+}

+ 49
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/log/annotation/Module.java Voir le fichier

@@ -0,0 +1,49 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.log.annotation;
18
+
19
+import org.springframework.core.annotation.AliasFor;
20
+
21
+import java.lang.annotation.*;
22
+
23
+/**
24
+ * 模块名称注解
25
+ *
26
+ * @author geekidea
27
+ * @date 2020/3/19
28
+ **/
29
+@Target({ElementType.TYPE})
30
+@Retention(RetentionPolicy.RUNTIME)
31
+@Documented
32
+public @interface Module {
33
+
34
+    /**
35
+     * 模块名称
36
+     *
37
+     * @return
38
+     */
39
+    String name() default "";
40
+
41
+    /**
42
+     * 模块名称
43
+     *
44
+     * @return
45
+     */
46
+    @AliasFor("name")
47
+    String value() default "";
48
+
49
+}

+ 64
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/log/annotation/OperationLog.java Voir le fichier

@@ -0,0 +1,64 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.log.annotation;
18
+
19
+import io.geekidea.springbootplus.framework.log.enums.OperationLogType;
20
+import org.springframework.core.annotation.AliasFor;
21
+
22
+import java.lang.annotation.*;
23
+
24
+/**
25
+ * 操作日志注解
26
+ * 记录:日志名称,日志类型,日志备注
27
+ *
28
+ * @author geekidea
29
+ * @date 2020/3/19
30
+ **/
31
+@Target({ElementType.METHOD})
32
+@Retention(RetentionPolicy.RUNTIME)
33
+@Documented
34
+public @interface OperationLog {
35
+
36
+    /**
37
+     * 日志名称
38
+     *
39
+     * @return
40
+     */
41
+    String name() default "";
42
+
43
+    /**
44
+     * 日志名称
45
+     *
46
+     * @return
47
+     */
48
+    @AliasFor("name")
49
+    String value() default "";
50
+
51
+    /**
52
+     * 日志类型
53
+     *
54
+     * @return
55
+     */
56
+    OperationLogType type() default OperationLogType.OTHER;
57
+
58
+    /**
59
+     * 日志备注
60
+     *
61
+     * @return
62
+     */
63
+    String remark() default "";
64
+}

+ 34
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/log/annotation/OperationLogIgnore.java Voir le fichier

@@ -0,0 +1,34 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.log.annotation;
18
+
19
+import java.lang.annotation.*;
20
+
21
+/**
22
+ * 忽略操作日志记录注解
23
+ * 在controller上标注该方法后,将不会记录操作日志
24
+ * 可以标注在类和方法上,如果标记在类上,则会忽略controller中的所有方法
25
+ *
26
+ * @author geekidea
27
+ * @date 2020/3/19
28
+ **/
29
+@Target({ElementType.TYPE, ElementType.METHOD})
30
+@Retention(RetentionPolicy.RUNTIME)
31
+@Documented
32
+public @interface OperationLogIgnore {
33
+
34
+}

+ 990
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/log/aop/BaseLogAop.java Voir le fichier

@@ -0,0 +1,990 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.log.aop;
18
+
19
+import com.alibaba.fastjson.JSONObject;
20
+import com.auth0.jwt.exceptions.JWTDecodeException;
21
+import com.baomidou.mybatisplus.core.toolkit.IdWorker;
22
+import io.geekidea.springbootplus.config.constant.CommonConstant;
23
+import io.geekidea.springbootplus.config.properties.SpringBootPlusAopProperties;
24
+import io.geekidea.springbootplus.framework.common.api.ApiCode;
25
+import io.geekidea.springbootplus.framework.common.api.ApiResult;
26
+import io.geekidea.springbootplus.framework.common.bean.ClientInfo;
27
+import io.geekidea.springbootplus.framework.common.exception.SpringBootPlusException;
28
+import io.geekidea.springbootplus.framework.ip.entity.IpAddress;
29
+import io.geekidea.springbootplus.framework.ip.service.IpAddressService;
30
+import io.geekidea.springbootplus.framework.log.annotation.Module;
31
+import io.geekidea.springbootplus.framework.log.annotation.OperationLog;
32
+import io.geekidea.springbootplus.framework.log.annotation.OperationLogIgnore;
33
+import io.geekidea.springbootplus.framework.log.bean.OperationLogInfo;
34
+import io.geekidea.springbootplus.framework.log.bean.RequestInfo;
35
+import io.geekidea.springbootplus.framework.log.entity.SysLoginLog;
36
+import io.geekidea.springbootplus.framework.log.entity.SysOperationLog;
37
+import io.geekidea.springbootplus.framework.log.service.SysLoginLogService;
38
+import io.geekidea.springbootplus.framework.log.service.SysOperationLogService;
39
+import io.geekidea.springbootplus.framework.shiro.service.LoginToken;
40
+import io.geekidea.springbootplus.framework.shiro.service.LoginUsername;
41
+import io.geekidea.springbootplus.framework.shiro.util.JwtTokenUtil;
42
+import io.geekidea.springbootplus.framework.shiro.util.JwtUtil;
43
+import io.geekidea.springbootplus.framework.util.*;
44
+import lombok.extern.slf4j.Slf4j;
45
+import org.apache.commons.codec.digest.DigestUtils;
46
+import org.apache.commons.collections4.CollectionUtils;
47
+import org.apache.commons.collections4.MapUtils;
48
+import org.apache.commons.lang3.ArrayUtils;
49
+import org.apache.commons.lang3.StringUtils;
50
+import org.apache.shiro.authz.annotation.*;
51
+import org.aspectj.lang.JoinPoint;
52
+import org.aspectj.lang.ProceedingJoinPoint;
53
+import org.aspectj.lang.Signature;
54
+import org.aspectj.lang.reflect.MethodSignature;
55
+import org.fusesource.jansi.Ansi;
56
+import org.slf4j.MDC;
57
+import org.springframework.beans.factory.annotation.Autowired;
58
+import org.springframework.beans.factory.annotation.Value;
59
+import org.springframework.scheduling.annotation.Async;
60
+import org.springframework.web.bind.annotation.RequestBody;
61
+import org.springframework.web.context.request.RequestContextHolder;
62
+import org.springframework.web.context.request.ServletRequestAttributes;
63
+import org.springframework.web.multipart.MultipartFile;
64
+import org.springframework.web.servlet.ModelAndView;
65
+
66
+import javax.servlet.http.HttpServletRequest;
67
+import javax.servlet.http.HttpServletResponse;
68
+import java.lang.annotation.Annotation;
69
+import java.lang.reflect.AnnotatedType;
70
+import java.lang.reflect.Method;
71
+import java.util.*;
72
+
73
+/**
74
+ * <p>
75
+ * Controller Aop 抽象类
76
+ * 获取响应结果信息
77
+ * <p>
78
+ * 日志输出类型:print-type
79
+ * 1. 请求和响应分开,按照执行顺序打印
80
+ * 2. ThreadLocal线程绑定,方法执行结束时,连续打印请求和响应日志
81
+ * 3. ThreadLocal线程绑定,方法执行结束时,同时打印请求和响应日志
82
+ * </p>
83
+ *
84
+ * @author geekidea
85
+ * @date 2018-11-08
86
+ */
87
+@Slf4j
88
+public abstract class BaseLogAop {
89
+
90
+    @Autowired
91
+    protected SysOperationLogService sysOperationLogService;
92
+
93
+    @Autowired
94
+    private IpAddressService ipAddressService;
95
+
96
+    @Autowired
97
+    private SysLoginLogService sysLoginLogService;
98
+
99
+    /**
100
+     * 本地线程变量,保存请求参数信息到当前线程中
101
+     */
102
+    protected static ThreadLocal<String> threadLocal = new ThreadLocal<>();
103
+    protected static ThreadLocal<RequestInfo> requestInfoThreadLocal = new ThreadLocal<>();
104
+    protected static ThreadLocal<OperationLogInfo> operationLogThreadLocal = new ThreadLocal<>();
105
+
106
+    /**
107
+     * 请求ID
108
+     */
109
+    private static final String REQUEST_ID = "requestId";
110
+    /**
111
+     * 零
112
+     */
113
+    private static final int ZERO = 0;
114
+    /**
115
+     * 截取字符串的最多长度
116
+     */
117
+    private static final int MAX_LENGTH = 300;
118
+    /**
119
+     * 登录日志:登录类型
120
+     */
121
+    private static final int LOGIN_TYPE = 1;
122
+    /**
123
+     * 登录日志:登出类型
124
+     */
125
+    private static final int LOGOUT_TYPE = 2;
126
+
127
+    /**
128
+     * 项目上下文路径
129
+     */
130
+    @Value("${server.servlet.context-path}")
131
+    private String contextPath;
132
+
133
+    /**
134
+     * Aop日志配置
135
+     */
136
+    protected SpringBootPlusAopProperties.LogAopConfig logAopConfig;
137
+
138
+    /**
139
+     * 日志打印类型
140
+     */
141
+    protected SpringBootPlusAopProperties.LogPrintType logPrintType;
142
+
143
+    /**
144
+     * 是否启用请求ID
145
+     */
146
+    protected boolean enableRequestId;
147
+
148
+    /**
149
+     * requestId生成类型
150
+     */
151
+    protected SpringBootPlusAopProperties.RequestIdType requestIdType;
152
+
153
+    /**
154
+     * Aop操作日志配置
155
+     */
156
+    protected SpringBootPlusAopProperties.OperationLogConfig operationLogConfig;
157
+
158
+    /**
159
+     * Aop登录日志配置
160
+     */
161
+    protected SpringBootPlusAopProperties.LoginLogConfig loginLogConfig;
162
+
163
+    @Autowired
164
+    public void setSpringBootPlusAopProperties(SpringBootPlusAopProperties springBootPlusAopProperties) {
165
+        logAopConfig = springBootPlusAopProperties.getLog();
166
+        logPrintType = logAopConfig.getLogPrintType();
167
+        enableRequestId = logAopConfig.isEnableRequestId();
168
+        requestIdType = logAopConfig.getRequestIdType();
169
+        operationLogConfig = springBootPlusAopProperties.getOperationLog();
170
+        loginLogConfig = springBootPlusAopProperties.getLoginLog();
171
+        log.debug("logAopConfig = " + logAopConfig);
172
+        log.debug("logPrintType = " + logPrintType);
173
+        log.debug("enableRequestId = " + enableRequestId);
174
+        log.debug("requestIdType = " + requestIdType);
175
+        log.debug("operationLogConfig = " + operationLogConfig);
176
+        log.debug("loginLogConfig = " + loginLogConfig);
177
+        log.debug("contextPath = " + contextPath);
178
+    }
179
+
180
+    /**
181
+     * 环绕通知
182
+     * 方法执行前打印请求参数信息
183
+     * 方法执行后打印响应结果信息
184
+     *
185
+     * @param joinPoint
186
+     * @return
187
+     * @throws Throwable
188
+     */
189
+    public abstract Object doAround(ProceedingJoinPoint joinPoint) throws Throwable;
190
+
191
+    /**
192
+     * 异常通知方法
193
+     *
194
+     * @param joinPoint
195
+     * @param exception
196
+     */
197
+    public abstract void afterThrowing(JoinPoint joinPoint, Exception exception);
198
+
199
+    /**
200
+     * 设置请求ID
201
+     *
202
+     * @param requestInfo
203
+     */
204
+    protected abstract void setRequestId(RequestInfo requestInfo);
205
+
206
+    /**
207
+     * 获取请求信息对象
208
+     *
209
+     * @param requestInfo
210
+     */
211
+    protected abstract void getRequestInfo(RequestInfo requestInfo);
212
+
213
+    /**
214
+     * 获取响应结果对象
215
+     *
216
+     * @param apiResult
217
+     */
218
+    protected abstract void getResponseResult(Object result);
219
+
220
+    /**
221
+     * 请求响应处理完成之后的回调方法
222
+     *
223
+     * @param requestInfo
224
+     * @param operationLogInfo
225
+     * @param result
226
+     * @param exception
227
+     */
228
+    protected abstract void finish(RequestInfo requestInfo, OperationLogInfo operationLogInfo, Object result, Exception exception);
229
+
230
+    /**
231
+     * 处理
232
+     *
233
+     * @param joinPoint
234
+     * @return
235
+     * @throws Throwable
236
+     */
237
+    public Object handle(ProceedingJoinPoint joinPoint) throws Throwable {
238
+        // 获取请求相关信息
239
+        try {
240
+            // 获取当前的HttpServletRequest对象
241
+            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
242
+            HttpServletRequest request = attributes.getRequest();
243
+
244
+            // HTTP请求信息对象
245
+            RequestInfo requestInfo = new RequestInfo();
246
+
247
+            // 请求路径 /api/foobar/add
248
+            String path = request.getRequestURI();
249
+            requestInfo.setPath(path);
250
+            // 获取实际路径 /foobar/add
251
+            String realPath = getRealPath(path);
252
+            requestInfo.setRealPath(realPath);
253
+
254
+            // 排除路径
255
+            Set<String> excludePaths = logAopConfig.getExcludePaths();
256
+            // 请求路径
257
+            if (handleExcludePaths(excludePaths, realPath)) {
258
+                return joinPoint.proceed();
259
+            }
260
+
261
+            // 获取请求类名和方法名称
262
+            Signature signature = joinPoint.getSignature();
263
+
264
+            // 获取真实的方法对象
265
+            MethodSignature methodSignature = (MethodSignature) signature;
266
+            Method method = methodSignature.getMethod();
267
+
268
+            // 处理操作日志信息
269
+            handleOperationLogInfo(method);
270
+
271
+            // IP地址
272
+            String ip = IpUtil.getRequestIp();
273
+            requestInfo.setIp(ip);
274
+
275
+            // 获取请求方式
276
+            String requestMethod = request.getMethod();
277
+            requestInfo.setRequestMethod(requestMethod);
278
+
279
+            // 获取请求内容类型
280
+            String contentType = request.getContentType();
281
+            requestInfo.setContentType(contentType);
282
+
283
+            // 判断控制器方法参数中是否有RequestBody注解
284
+            Annotation[][] annotations = method.getParameterAnnotations();
285
+            boolean isRequestBody = isRequestBody(annotations);
286
+            requestInfo.setRequestBody(isRequestBody);
287
+
288
+            AnnotatedType[] annotatedTypes = method.getAnnotatedParameterTypes();
289
+
290
+            // 获取Shiro注解值,并记录到map中
291
+            handleShiroAnnotationValue(requestInfo, method);
292
+
293
+            // 设置请求参数
294
+            Object requestParamObject = getRequestParamObject(joinPoint, request, requestMethod, contentType, isRequestBody);
295
+            requestInfo.setParam(requestParamObject);
296
+            requestInfo.setTime(DateUtil.getDateTimeString(new Date()));
297
+
298
+            // 获取请求头token
299
+            String token = request.getHeader(JwtTokenUtil.getTokenName());
300
+            requestInfo.setToken(token);
301
+            if (StringUtils.isNotBlank(token)) {
302
+                requestInfo.setTokenMd5(DigestUtils.md5Hex(token));
303
+            }
304
+
305
+            // 用户浏览器代理字符串
306
+            requestInfo.setUserAgent(request.getHeader(CommonConstant.USER_AGENT));
307
+
308
+            // 记录请求ID
309
+            setRequestId(requestInfo);
310
+
311
+            // 调用子类重写方法,控制请求信息日志处理
312
+            getRequestInfo(requestInfo);
313
+        } catch (Exception e) {
314
+            log.error("请求日志AOP处理异常", e);
315
+        }
316
+
317
+        // 执行目标方法,获得返回值
318
+        // 方法异常时,会调用子类的@AfterThrowing注解的方法,不会调用下面的代码,异常单独处理
319
+        Object result = joinPoint.proceed();
320
+        try {
321
+            // 调用子类重写方法,控制响应结果日志处理
322
+            getResponseResult(result);
323
+        } catch (Exception e) {
324
+            log.error("处理响应结果异常", e);
325
+        } finally {
326
+            handleAfterReturn(result, null);
327
+        }
328
+        return result;
329
+    }
330
+
331
+    /**
332
+     * 正常调用返回或者异常结束后调用此方法
333
+     *
334
+     * @param result
335
+     * @param exception
336
+     */
337
+    protected void handleAfterReturn(Object result, Exception exception) {
338
+        // 获取RequestInfo
339
+        RequestInfo requestInfo = requestInfoThreadLocal.get();
340
+        // 获取OperationLogInfo
341
+        OperationLogInfo operationLogInfo = operationLogThreadLocal.get();
342
+        // 调用抽象方法,是否保存日志操作,需要子类重写该方法,手动调用saveSysOperationLog
343
+        finish(requestInfo, operationLogInfo, result, null);
344
+        // 释放资源
345
+        remove();
346
+    }
347
+
348
+    /**
349
+     * 处理异常
350
+     *
351
+     * @param exception
352
+     */
353
+    public void handleAfterThrowing(Exception exception) {
354
+        // 获取RequestInfo
355
+        RequestInfo requestInfo = requestInfoThreadLocal.get();
356
+        // 获取OperationLogInfo
357
+        OperationLogInfo operationLogInfo = operationLogThreadLocal.get();
358
+        // 调用抽象方法,是否保存日志操作,需要子类重写该方法,手动调用saveSysOperationLog
359
+        finish(requestInfo, operationLogInfo, null, exception);
360
+        // 释放资源
361
+        remove();
362
+    }
363
+
364
+
365
+    private void handleOperationLogInfo(Method method) {
366
+        // 设置控制器类名称和方法名称
367
+        OperationLogInfo operationLogInfo = new OperationLogInfo()
368
+                .setControllerClassName(method.getDeclaringClass().getName())
369
+                .setControllerMethodName(method.getName());
370
+
371
+        // 获取Module类注解
372
+        Class<?> controllerClass = method.getDeclaringClass();
373
+        Module module = controllerClass.getAnnotation(Module.class);
374
+        if (module != null) {
375
+            String moduleName = module.name();
376
+            String moduleValue = module.value();
377
+            if (StringUtils.isNotBlank(moduleValue)) {
378
+                operationLogInfo.setModule(moduleValue);
379
+            }
380
+            if (StringUtils.isNotBlank(moduleName)) {
381
+                operationLogInfo.setModule(moduleName);
382
+            }
383
+        }
384
+        // 获取OperationLogIgnore注解
385
+        OperationLogIgnore classOperationLogIgnore = controllerClass.getAnnotation(OperationLogIgnore.class);
386
+        if (classOperationLogIgnore != null) {
387
+            // 不记录日志
388
+            operationLogInfo.setIgnore(true);
389
+        }
390
+        // 判断方法是否要过滤
391
+        OperationLogIgnore operationLogIgnore = method.getAnnotation(OperationLogIgnore.class);
392
+        if (operationLogIgnore != null) {
393
+            operationLogInfo.setIgnore(true);
394
+        }
395
+        // 从方法上获取OperationLog注解
396
+        OperationLog operationLog = method.getAnnotation(OperationLog.class);
397
+        if (operationLog != null) {
398
+            String operationLogName = operationLog.name();
399
+            String operationLogValue = operationLog.value();
400
+            if (StringUtils.isNotBlank(operationLogValue)) {
401
+                operationLogInfo.setName(operationLogValue);
402
+            }
403
+            if (StringUtils.isNotBlank(operationLogName)) {
404
+                operationLogInfo.setName(operationLogName);
405
+            }
406
+            operationLogInfo.setType(operationLog.type().getCode()).setRemark(operationLog.remark());
407
+        }
408
+        operationLogThreadLocal.set(operationLogInfo);
409
+    }
410
+
411
+    /**
412
+     * 获取Shiro注解值,并记录到map中
413
+     *
414
+     * @param map
415
+     * @param method
416
+     */
417
+    protected void handleShiroAnnotationValue(RequestInfo requestInfo, Method method) {
418
+        RequiresRoles requiresRoles = method.getAnnotation(RequiresRoles.class);
419
+        if (requiresRoles != null) {
420
+            String[] requiresRolesValues = requiresRoles.value();
421
+            if (ArrayUtils.isNotEmpty(requiresRolesValues)) {
422
+                String requiresRolesString = Arrays.toString(requiresRolesValues);
423
+                requestInfo.setRequiresRoles(requiresRolesString);
424
+            }
425
+        }
426
+
427
+        RequiresPermissions requiresPermissions = method.getAnnotation(RequiresPermissions.class);
428
+        if (requiresPermissions != null) {
429
+            String[] requiresPermissionsValues = requiresPermissions.value();
430
+            if (ArrayUtils.isNotEmpty(requiresPermissionsValues)) {
431
+                String requiresPermissionsString = Arrays.toString(requiresPermissionsValues);
432
+                requestInfo.setRequiresPermissions(requiresPermissionsString);
433
+            }
434
+        }
435
+
436
+        RequiresAuthentication requiresAuthentication = method.getAnnotation(RequiresAuthentication.class);
437
+        if (requiresAuthentication != null) {
438
+            requestInfo.setRequiresAuthentication(true);
439
+        }
440
+
441
+        RequiresUser requiresUser = method.getAnnotation(RequiresUser.class);
442
+        if (requiresUser != null) {
443
+            requestInfo.setRequiresUser(true);
444
+        }
445
+
446
+        RequiresGuest requiresGuest = method.getAnnotation(RequiresGuest.class);
447
+        if (requiresGuest != null) {
448
+            requestInfo.setRequiresGuest(true);
449
+        }
450
+
451
+    }
452
+
453
+    /**
454
+     * 处理请求ID
455
+     *
456
+     * @param requestInfo
457
+     */
458
+    protected void handleRequestId(RequestInfo requestInfo) {
459
+        if (!enableRequestId) {
460
+            return;
461
+        }
462
+        String requestId = null;
463
+        if (SpringBootPlusAopProperties.RequestIdType.IDWORK == requestIdType) {
464
+            requestId = IdWorker.getIdStr();
465
+        } else if (SpringBootPlusAopProperties.RequestIdType.UUID == requestIdType) {
466
+            requestId = UUIDUtil.getUuid();
467
+        }
468
+        // 设置请求ID
469
+        MDC.put(REQUEST_ID, requestId);
470
+        requestInfo.setRequestId(requestId);
471
+    }
472
+
473
+    /**
474
+     * 处理请求参数
475
+     *
476
+     * @param requestInfo
477
+     */
478
+    protected void handleRequestInfo(RequestInfo requestInfo) {
479
+        requestInfoThreadLocal.set(requestInfo);
480
+        if (SpringBootPlusAopProperties.LogPrintType.NONE == logPrintType) {
481
+            return;
482
+        }
483
+        // 获取请求信息
484
+        String requestInfoString = formatRequestInfo(requestInfo);
485
+        // 如果打印方式为顺序打印,则直接打印,否则,保存的threadLocal中
486
+        if (SpringBootPlusAopProperties.LogPrintType.ORDER == logPrintType) {
487
+            printRequestInfoString(requestInfoString);
488
+        } else {
489
+            threadLocal.set(requestInfoString);
490
+        }
491
+    }
492
+
493
+    /**
494
+     * 处理响应结果
495
+     *
496
+     * @param result
497
+     */
498
+    protected void handleResponseResult(Object result) {
499
+        if (SpringBootPlusAopProperties.LogPrintType.NONE == logPrintType) {
500
+            return;
501
+        }
502
+        if (result != null && result instanceof ApiResult) {
503
+            ApiResult<?> apiResult = (ApiResult<?>) result;
504
+            int code = apiResult.getCode();
505
+            // 获取格式化后的响应结果
506
+            String responseResultString = formatResponseResult(apiResult);
507
+            if (SpringBootPlusAopProperties.LogPrintType.ORDER == logPrintType) {
508
+                printResponseResult(code, responseResultString);
509
+            } else {
510
+                // 从threadLocal中获取线程请求信息
511
+                String requestInfoString = threadLocal.get();
512
+                // 如果是连续打印,则先打印请求参数,再打印响应结果
513
+                if (SpringBootPlusAopProperties.LogPrintType.LINE == logPrintType) {
514
+                    printRequestInfoString(requestInfoString);
515
+                    printResponseResult(code, responseResultString);
516
+                } else if (SpringBootPlusAopProperties.LogPrintType.MERGE == logPrintType) {
517
+                    printRequestResponseString(code, requestInfoString, responseResultString);
518
+                }
519
+            }
520
+        }
521
+    }
522
+
523
+    /**
524
+     * 同时打印请求和响应信息
525
+     *
526
+     * @param code
527
+     * @param requestInfoString
528
+     * @param responseResultString
529
+     */
530
+    protected void printRequestResponseString(int code, String requestInfoString, String responseResultString) {
531
+        if (code == ApiCode.SUCCESS.getCode()) {
532
+            log.info(requestInfoString + "\n" + responseResultString);
533
+        } else {
534
+            log.error(requestInfoString + "\n" + responseResultString);
535
+        }
536
+    }
537
+
538
+
539
+    /**
540
+     * 格式化请求信息
541
+     *
542
+     * @param requestInfo
543
+     * @return
544
+     */
545
+    protected String formatRequestInfo(RequestInfo requestInfo) {
546
+        String requestInfoString = null;
547
+        try {
548
+            if (logAopConfig.isRequestLogFormat()) {
549
+                requestInfoString = "\n" + Jackson.toJsonStringNonNull(requestInfo, true);
550
+            } else {
551
+                requestInfoString = Jackson.toJsonStringNonNull(requestInfo);
552
+            }
553
+        } catch (Exception e) {
554
+            log.error("格式化请求信息日志异常", e);
555
+        }
556
+        return AnsiUtil.getAnsi(Ansi.Color.GREEN, "requestInfo:" + requestInfoString);
557
+    }
558
+
559
+    /**
560
+     * 打印请求信息
561
+     *
562
+     * @param requestInfoString
563
+     */
564
+    protected void printRequestInfoString(String requestInfoString) {
565
+        log.info(requestInfoString);
566
+    }
567
+
568
+    /**
569
+     * 格式化响应信息
570
+     *
571
+     * @param apiResult
572
+     * @return
573
+     */
574
+    protected String formatResponseResult(ApiResult<?> apiResult) {
575
+        String responseResultString = "responseResult:";
576
+        try {
577
+            if (logAopConfig.isResponseLogFormat()) {
578
+                responseResultString += "\n" + Jackson.toJsonString(apiResult, true);
579
+            } else {
580
+                responseResultString += Jackson.toJsonString(apiResult);
581
+            }
582
+            int code = apiResult.getCode();
583
+            if (code == ApiCode.SUCCESS.getCode()) {
584
+                return AnsiUtil.getAnsi(Ansi.Color.BLUE, responseResultString);
585
+            } else {
586
+                return AnsiUtil.getAnsi(Ansi.Color.RED, responseResultString);
587
+            }
588
+        } catch (Exception e) {
589
+            log.error("格式化响应日志异常", e);
590
+        }
591
+        return responseResultString;
592
+    }
593
+
594
+    /**
595
+     * 打印响应信息
596
+     *
597
+     * @param code
598
+     * @param responseResultString
599
+     */
600
+    protected void printResponseResult(int code, String responseResultString) {
601
+        if (code == ApiCode.SUCCESS.getCode()) {
602
+            log.info(responseResultString);
603
+        } else {
604
+            log.error(responseResultString);
605
+        }
606
+    }
607
+
608
+    /**
609
+     * 获取请求参数JSON字符串
610
+     *
611
+     * @param joinPoint
612
+     * @param request
613
+     * @param requestMethod
614
+     * @param contentType
615
+     * @param isRequestBody
616
+     */
617
+    protected Object getRequestParamObject(ProceedingJoinPoint joinPoint, HttpServletRequest request, String requestMethod, String contentType, boolean isRequestBody) {
618
+        Object paramObject = null;
619
+        if (isRequestBody) {
620
+            // POST,application/json,RequestBody的类型,简单判断,然后序列化成JSON字符串
621
+            Object[] args = joinPoint.getArgs();
622
+            paramObject = getArgsObject(args);
623
+        } else {
624
+            // 获取getParameterMap中所有的值,处理后序列化成JSON字符串
625
+            Map<String, String[]> paramsMap = request.getParameterMap();
626
+            paramObject = getParamJSONObject(paramsMap);
627
+        }
628
+        return paramObject;
629
+    }
630
+
631
+    /**
632
+     * 判断控制器方法参数中是否有RequestBody注解
633
+     *
634
+     * @param annotations
635
+     * @return
636
+     */
637
+    protected boolean isRequestBody(Annotation[][] annotations) {
638
+        boolean isRequestBody = false;
639
+        for (Annotation[] annotationArray : annotations) {
640
+            for (Annotation annotation : annotationArray) {
641
+                if (annotation instanceof RequestBody) {
642
+                    isRequestBody = true;
643
+                }
644
+            }
645
+        }
646
+        return isRequestBody;
647
+    }
648
+
649
+    /**
650
+     * 请求参数拼装
651
+     *
652
+     * @param args
653
+     * @return
654
+     */
655
+    protected Object getArgsObject(Object[] args) {
656
+        if (args == null) {
657
+            return null;
658
+        }
659
+        // 去掉HttpServletRequest和HttpServletResponse
660
+        List<Object> realArgs = new ArrayList<>();
661
+        for (Object arg : args) {
662
+            if (arg instanceof HttpServletRequest) {
663
+                continue;
664
+            }
665
+            if (arg instanceof HttpServletResponse) {
666
+                continue;
667
+            }
668
+            if (arg instanceof MultipartFile) {
669
+                continue;
670
+            }
671
+            if (arg instanceof ModelAndView) {
672
+                continue;
673
+            }
674
+            realArgs.add(arg);
675
+        }
676
+        if (realArgs.size() == 1) {
677
+            return realArgs.get(0);
678
+        } else {
679
+            return realArgs;
680
+        }
681
+    }
682
+
683
+
684
+    /**
685
+     * 获取参数Map的JSON字符串
686
+     *
687
+     * @param paramsMap
688
+     * @return
689
+     */
690
+    protected JSONObject getParamJSONObject(Map<String, String[]> paramsMap) {
691
+        if (MapUtils.isEmpty(paramsMap)) {
692
+            return null;
693
+        }
694
+        JSONObject jsonObject = new JSONObject();
695
+        for (Map.Entry<String, String[]> kv : paramsMap.entrySet()) {
696
+            String key = kv.getKey();
697
+            String[] values = kv.getValue();
698
+            // 没有值
699
+            if (values == null) {
700
+                jsonObject.put(key, null);
701
+            } else if (values.length == 1) {
702
+                // 一个值
703
+                jsonObject.put(key, values[0]);
704
+            } else {
705
+                // 多个值
706
+                jsonObject.put(key, values);
707
+            }
708
+        }
709
+        return jsonObject;
710
+    }
711
+
712
+    /**
713
+     * 处理排除路径,匹配返回true,否则返回false
714
+     *
715
+     * @param excludePaths 排除路径
716
+     * @param realPath     请求实际路径
717
+     * @return
718
+     */
719
+    protected boolean handleExcludePaths(Set<String> excludePaths, String realPath) {
720
+        if (CollectionUtils.isEmpty(excludePaths) || StringUtils.isBlank(realPath)) {
721
+            return false;
722
+        }
723
+        // 如果是排除路径,则跳过
724
+        if (excludePaths.contains(realPath)) {
725
+            return true;
726
+        }
727
+        return false;
728
+    }
729
+
730
+    /**
731
+     * 获取实际路径
732
+     *
733
+     * @param requestPath
734
+     * @return
735
+     */
736
+    private String getRealPath(String requestPath) {
737
+        // 如果项目路径不为空,则去掉项目路径,获取实际访问路径
738
+        if (StringUtils.isNotBlank(contextPath)) {
739
+            return requestPath.substring(contextPath.length());
740
+        }
741
+        return requestPath;
742
+    }
743
+
744
+    /**
745
+     * 异步保存系统操作日志
746
+     *
747
+     * @param requestInfo
748
+     * @param operationLogInfo
749
+     * @param result
750
+     * @param exception
751
+     */
752
+    @Async
753
+    protected void saveSysOperationLog(RequestInfo requestInfo, OperationLogInfo operationLogInfo, Object result, Exception exception) {
754
+        try {
755
+            // 如果不记录操作日志,则跳过
756
+            if (!operationLogConfig.isEnable()) {
757
+                return;
758
+            }
759
+            // 排除路径
760
+            Set<String> excludePaths = operationLogConfig.getExcludePaths();
761
+            // 请求路径
762
+            if (handleExcludePaths(excludePaths, requestInfo.getRealPath())) {
763
+                return;
764
+            }
765
+
766
+            // 操作日志
767
+            SysOperationLog sysOperationLog = new SysOperationLog();
768
+            // 设置操作日志信息
769
+            if (operationLogInfo != null) {
770
+                // 如果类或方法上标注有OperationLogIgnore,则跳过
771
+                if (operationLogInfo.isIgnore()) {
772
+                    return;
773
+                }
774
+                sysOperationLog.setModule(operationLogInfo.getModule())
775
+                        .setName(operationLogInfo.getName())
776
+                        .setType(operationLogInfo.getType())
777
+                        .setRemark(operationLogInfo.getRemark())
778
+                        .setClassName(operationLogInfo.getControllerClassName())
779
+                        .setMethodName(operationLogInfo.getControllerMethodName());
780
+            }
781
+            // 设置请求参数信息
782
+            if (requestInfo != null) {
783
+                sysOperationLog.setIp(requestInfo.getIp())
784
+                        .setPath(requestInfo.getPath())
785
+                        .setRequestId(requestInfo.getRequestId())
786
+                        .setRequestMethod(requestInfo.getRequestMethod())
787
+                        .setContentType(requestInfo.getContentType())
788
+                        .setRequestBody(requestInfo.getRequestBody())
789
+                        .setToken(requestInfo.getTokenMd5());
790
+
791
+                // 设置参数字符串
792
+                sysOperationLog.setParam(Jackson.toJsonStringNonNull(requestInfo.getParam()));
793
+                // User-Agent
794
+                ClientInfo clientInfo = ClientInfoUtil.get(requestInfo.getUserAgent());
795
+                if (clientInfo != null) {
796
+                    sysOperationLog.setBrowserName(clientInfo.getBrowserName())
797
+                            .setBrowserVersion(clientInfo.getBrowserversion())
798
+                            .setEngineName(clientInfo.getEngineName())
799
+                            .setEngineVersion(clientInfo.getEngineVersion())
800
+                            .setOsName(clientInfo.getOsName())
801
+                            .setPlatformName(clientInfo.getPlatformName())
802
+                            .setMobile(clientInfo.isMobile())
803
+                            .setDeviceName(clientInfo.getDeviceName())
804
+                            .setDeviceModel(clientInfo.getDeviceModel());
805
+                }
806
+                // 设置IP区域
807
+                IpAddress ipAddress = ipAddressService.getByIp(requestInfo.getIp());
808
+                if (ipAddress != null) {
809
+                    requestInfo.setIpAddress(ipAddress);
810
+                    sysOperationLog.setArea(ipAddress.getArea()).setOperator(ipAddress.getOperator());
811
+                }
812
+            }
813
+
814
+            // 设置响应结果
815
+            if (result != null && result instanceof ApiResult) {
816
+                ApiResult<?> apiResult = (ApiResult<?>) result;
817
+                apiResult.getCode();
818
+                sysOperationLog.setSuccess(apiResult.isSuccess())
819
+                        .setCode(apiResult.getCode())
820
+                        .setMessage(apiResult.getMessage());
821
+            }
822
+
823
+            // 设置当前登录信息
824
+            sysOperationLog.setUserId(LoginUtil.getUserId()).setUserName(LoginUtil.getUsername());
825
+
826
+            // 设置异常信息
827
+            if (exception != null) {
828
+                Integer errorCode = null;
829
+                String exceptionMessage = exception.getMessage();
830
+                if (StringUtils.isNotBlank(exceptionMessage)) {
831
+                    exceptionMessage = StringUtils.substring(exceptionMessage, ZERO, MAX_LENGTH);
832
+                }
833
+                if (exception instanceof SpringBootPlusException) {
834
+                    SpringBootPlusException springBootPlusException = (SpringBootPlusException) exception;
835
+                    errorCode = springBootPlusException.getErrorCode();
836
+                }
837
+                // 异常字符串长度截取
838
+                sysOperationLog.setSuccess(false)
839
+                        .setCode(errorCode)
840
+                        .setExceptionMessage(exceptionMessage)
841
+                        .setExceptionName(exception.getClass().getName());
842
+            }
843
+            // 保存日志到数据库
844
+            sysOperationLogService.saveSysOperationLog(sysOperationLog);
845
+
846
+
847
+        } catch (Exception e) {
848
+            if (e instanceof JWTDecodeException) {
849
+                JWTDecodeException jwtDecodeException = (JWTDecodeException) e;
850
+                throw jwtDecodeException;
851
+            }
852
+            log.error("保存系统操作日志失败", e);
853
+        }
854
+    }
855
+
856
+    /**
857
+     * 异步保存系统登录日志
858
+     *
859
+     * @param requestInfo
860
+     * @param operationLogInfo
861
+     * @param result
862
+     * @param exception
863
+     */
864
+    @Async
865
+    protected void saveSysLoginLog(RequestInfo requestInfo, OperationLogInfo operationLogInfo, Object result, Exception exception) {
866
+        try {
867
+            // 如果不记录登录日志,则跳过
868
+            if (!loginLogConfig.isEnable()) {
869
+                return;
870
+            }
871
+            String realPath = requestInfo.getRealPath();
872
+            if (StringUtils.isBlank(realPath)) {
873
+                return;
874
+            }
875
+
876
+            boolean flag = false;
877
+            Integer type = null;
878
+            // 判断是否是登录路径
879
+            if (realPath.equals(loginLogConfig.getLoginPath())) {
880
+                flag = true;
881
+                type = LOGIN_TYPE;
882
+            } else if (realPath.equals(loginLogConfig.getLogoutPath())) {
883
+                flag = true;
884
+                type = LOGOUT_TYPE;
885
+            }
886
+
887
+            // 保存登录登出日志
888
+            if (flag) {
889
+                SysLoginLog sysLoginLog = new SysLoginLog();
890
+                sysLoginLog.setType(type);
891
+                // 设置异常信息
892
+                if (exception != null) {
893
+                    Integer errorCode = null;
894
+                    String exceptionMessage = exception.getMessage();
895
+                    if (StringUtils.isNotBlank(exceptionMessage)) {
896
+                        exceptionMessage = StringUtils.substring(exceptionMessage, ZERO, MAX_LENGTH);
897
+                    }
898
+                    if (exception instanceof SpringBootPlusException) {
899
+                        SpringBootPlusException springBootPlusException = (SpringBootPlusException) exception;
900
+                        errorCode = springBootPlusException.getErrorCode();
901
+                    }
902
+                    // 异常字符串长度截取
903
+                    sysLoginLog.setCode(errorCode).setExceptionMessage(exceptionMessage);
904
+                }
905
+
906
+                // 判断登录登出结果
907
+                if (result != null && result instanceof ApiResult) {
908
+                    ApiResult<?> apiResult = (ApiResult<?>) result;
909
+                    sysLoginLog.setSuccess(apiResult.isSuccess()).setCode(apiResult.getCode());
910
+                    if (apiResult.isSuccess()) {
911
+                        if (LOGIN_TYPE == type) {
912
+                            Object object = apiResult.getData();
913
+                            if (object != null && object instanceof LoginToken) {
914
+                                LoginToken loginToken = (LoginToken) object;
915
+                                String token = loginToken.getToken();
916
+                                if (StringUtils.isNotBlank(token)) {
917
+                                    // 设置登录token
918
+                                    String tokenMd5 = DigestUtils.md5Hex(token);
919
+                                    sysLoginLog.setToken(tokenMd5);
920
+                                }
921
+                            }
922
+                        }
923
+                    } else {
924
+                        sysLoginLog.setExceptionMessage(apiResult.getMessage());
925
+                    }
926
+                }
927
+
928
+                // 设置请求参数信息
929
+                if (requestInfo != null) {
930
+                    sysLoginLog.setIp(requestInfo.getIp()).setRequestId(requestInfo.getRequestId());
931
+                    // 设置登录用户名
932
+                    if (LOGIN_TYPE == type) {
933
+                        Object paramObject = requestInfo.getParam();
934
+                        if (paramObject != null && paramObject instanceof LoginUsername) {
935
+                            LoginUsername loginUsername = (LoginUsername) paramObject;
936
+                            String username = loginUsername.getUsername();
937
+                            sysLoginLog.setUsername(username);
938
+                        }
939
+                    } else if (LOGOUT_TYPE == type) {
940
+                        String username = JwtUtil.getUsername(requestInfo.getToken());
941
+                        sysLoginLog.setUsername(username);
942
+                        // 设置登出token
943
+                        sysLoginLog.setToken(requestInfo.getTokenMd5());
944
+                    }
945
+
946
+                    // User-Agent
947
+                    String userAgent = requestInfo.getUserAgent();
948
+                    if (StringUtils.isNotBlank(userAgent)) {
949
+                        sysLoginLog.setUserAgent(StringUtils.substring(userAgent, ZERO, MAX_LENGTH));
950
+                    }
951
+                    ClientInfo clientInfo = ClientInfoUtil.get(userAgent);
952
+                    if (clientInfo != null) {
953
+                        sysLoginLog.setBrowserName(clientInfo.getBrowserName())
954
+                                .setBrowserVersion(clientInfo.getBrowserversion())
955
+                                .setEngineName(clientInfo.getEngineName())
956
+                                .setEngineVersion(clientInfo.getEngineVersion())
957
+                                .setOsName(clientInfo.getOsName())
958
+                                .setPlatformName(clientInfo.getPlatformName())
959
+                                .setMobile(clientInfo.isMobile())
960
+                                .setDeviceName(clientInfo.getDeviceName())
961
+                                .setDeviceModel(clientInfo.getDeviceModel());
962
+                    }
963
+                    IpAddress ipAddress = requestInfo.getIpAddress();
964
+                    if (ipAddress == null) {
965
+                        ipAddress = ipAddressService.getByIp(requestInfo.getIp());
966
+                    }
967
+                    if (ipAddress != null) {
968
+                        sysLoginLog.setArea(ipAddress.getArea()).setOperator(ipAddress.getOperator());
969
+                    }
970
+                    // 保存登录日志
971
+                    sysLoginLogService.saveSysLoginLog(sysLoginLog);
972
+                }
973
+            }
974
+        } catch (Exception e) {
975
+            log.error("保存系统登录日志失败", e);
976
+        }
977
+    }
978
+
979
+
980
+    /**
981
+     * 释放资源
982
+     */
983
+    protected void remove() {
984
+        threadLocal.remove();
985
+        requestInfoThreadLocal.remove();
986
+        operationLogThreadLocal.remove();
987
+        MDC.clear();
988
+    }
989
+
990
+}

+ 67
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/log/bean/OperationLogInfo.java Voir le fichier

@@ -0,0 +1,67 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.log.bean;
18
+
19
+import lombok.Data;
20
+import lombok.experimental.Accessors;
21
+
22
+/**
23
+ * 操作日志信息
24
+ *
25
+ * @author geekidea
26
+ * @date 2020/3/19
27
+ **/
28
+@Data
29
+@Accessors(chain = true)
30
+public class OperationLogInfo {
31
+
32
+    /**
33
+     * 是否忽略
34
+     */
35
+    private boolean ignore;
36
+
37
+    /**
38
+     * 模块名称
39
+     */
40
+    private String module;
41
+
42
+    /**
43
+     * 日志名称
44
+     */
45
+    private String name;
46
+
47
+    /**
48
+     * 日志类型
49
+     */
50
+    private Integer type;
51
+
52
+    /**
53
+     * 日志备注
54
+     */
55
+    private String remark;
56
+
57
+    /**
58
+     * controller类名称
59
+     */
60
+    private String controllerClassName;
61
+
62
+    /**
63
+     * controller目标方法名称
64
+     */
65
+    private String controllerMethodName;
66
+
67
+}

+ 140
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/log/bean/RequestInfo.java Voir le fichier

@@ -0,0 +1,140 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.log.bean;
18
+
19
+import com.alibaba.fastjson.annotation.JSONField;
20
+import com.fasterxml.jackson.annotation.JsonIgnore;
21
+import io.geekidea.springbootplus.framework.ip.entity.IpAddress;
22
+import lombok.Data;
23
+import lombok.experimental.Accessors;
24
+
25
+import java.io.Serializable;
26
+
27
+/**
28
+ * HTTP请求信息对象
29
+ *
30
+ * @author geekidea
31
+ * @date 2020/3/18
32
+ **/
33
+@Data
34
+@Accessors(chain = true)
35
+public class RequestInfo implements Serializable {
36
+    private static final long serialVersionUID = 1421424612944015973L;
37
+
38
+    /**
39
+     * 请求路径
40
+     * /api/foobar/add
41
+     */
42
+    private String path;
43
+
44
+    /**
45
+     * 请求ID
46
+     */
47
+    @JsonIgnore
48
+    @JSONField(serialize = false)
49
+    private String requestId;
50
+
51
+    /**
52
+     * 请求实际路径
53
+     * /foobar/add
54
+     */
55
+    @JsonIgnore
56
+    @JSONField(serialize = false)
57
+    private String realPath;
58
+
59
+    /**
60
+     * 请求IP地址
61
+     */
62
+    private String ip;
63
+
64
+    /**
65
+     * 请求IP对象
66
+     */
67
+    @JsonIgnore
68
+    @JSONField(serialize = false)
69
+    private IpAddress ipAddress;
70
+
71
+    /**
72
+     * 请求方式,GET/POST
73
+     */
74
+    private String requestMethod;
75
+
76
+    /**
77
+     * 请求内容类型
78
+     */
79
+    private String contentType;
80
+
81
+    /**
82
+     * 判断控制器方法参数中是否有RequestBody注解
83
+     */
84
+    private Boolean requestBody;
85
+
86
+    /**
87
+     * 请求参数对象
88
+     */
89
+    private Object param;
90
+
91
+    /**
92
+     * 请求时间字符串
93
+     */
94
+    private String time;
95
+
96
+    /**
97
+     * 请求token
98
+     */
99
+    private String token;
100
+
101
+    /**
102
+     * 请求token MD5值
103
+     */
104
+    @JsonIgnore
105
+    @JSONField(serialize = false)
106
+    private String tokenMd5;
107
+
108
+    /**
109
+     * 用户代理字符串
110
+     */
111
+    @JsonIgnore
112
+    @JSONField(serialize = false)
113
+    private String userAgent;
114
+
115
+    /**
116
+     * requiresRoles值
117
+     */
118
+    private String requiresRoles;
119
+
120
+    /**
121
+     * requiresPermissions值
122
+     */
123
+    private String requiresPermissions;
124
+
125
+    /**
126
+     * requiresAuthentication
127
+     */
128
+    private Boolean requiresAuthentication;
129
+
130
+    /**
131
+     * requiresUser
132
+     */
133
+    private Boolean requiresUser;
134
+
135
+    /**
136
+     * requiresGuest
137
+     */
138
+    private Boolean requiresGuest;
139
+
140
+}

+ 68
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/log/controller/SysLoginLogController.java Voir le fichier

@@ -0,0 +1,68 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.log.controller;
18
+
19
+import io.geekidea.springbootplus.framework.common.api.ApiResult;
20
+import io.geekidea.springbootplus.framework.common.controller.BaseController;
21
+import io.geekidea.springbootplus.framework.core.pagination.Paging;
22
+import io.geekidea.springbootplus.framework.log.annotation.Module;
23
+import io.geekidea.springbootplus.framework.log.annotation.OperationLog;
24
+import io.geekidea.springbootplus.framework.log.entity.SysLoginLog;
25
+import io.geekidea.springbootplus.framework.log.enums.OperationLogType;
26
+import io.geekidea.springbootplus.framework.log.param.SysLoginLogPageParam;
27
+import io.geekidea.springbootplus.framework.log.service.SysLoginLogService;
28
+import io.swagger.annotations.Api;
29
+import io.swagger.annotations.ApiOperation;
30
+import lombok.extern.slf4j.Slf4j;
31
+import org.apache.shiro.authz.annotation.RequiresPermissions;
32
+import org.springframework.beans.factory.annotation.Autowired;
33
+import org.springframework.validation.annotation.Validated;
34
+import org.springframework.web.bind.annotation.PostMapping;
35
+import org.springframework.web.bind.annotation.RequestBody;
36
+import org.springframework.web.bind.annotation.RequestMapping;
37
+import org.springframework.web.bind.annotation.RestController;
38
+
39
+/**
40
+ * 系统登录日志 控制器
41
+ *
42
+ * @author geekidea
43
+ * @since 2020-03-24
44
+ */
45
+@Slf4j
46
+@RestController
47
+@RequestMapping("/sysLoginLog")
48
+@Module("log")
49
+@Api(value = "系统登录日志API", tags = {"系统登录日志"})
50
+public class SysLoginLogController extends BaseController {
51
+
52
+    @Autowired
53
+    private SysLoginLogService sysLoginLogService;
54
+
55
+    /**
56
+     * 系统登录日志分页列表
57
+     */
58
+    @PostMapping("/getPageList")
59
+    @RequiresPermissions("sys:login:log:page")
60
+    @OperationLog(name = "系统登录日志分页列表", type = OperationLogType.PAGE)
61
+    @ApiOperation(value = "系统登录日志分页列表", response = SysLoginLog.class)
62
+    public ApiResult<Paging<SysLoginLog>> getSysLoginLogPageList(@Validated @RequestBody SysLoginLogPageParam sysLoginLogPageParam) throws Exception {
63
+        Paging<SysLoginLog> paging = sysLoginLogService.getSysLoginLogPageList(sysLoginLogPageParam);
64
+        return ApiResult.ok(paging);
65
+    }
66
+
67
+}
68
+

+ 63
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/log/controller/SysOperationLogController.java Voir le fichier

@@ -0,0 +1,63 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.log.controller;
18
+
19
+import io.geekidea.springbootplus.framework.common.api.ApiResult;
20
+import io.geekidea.springbootplus.framework.common.controller.BaseController;
21
+import io.geekidea.springbootplus.framework.core.pagination.Paging;
22
+import io.geekidea.springbootplus.framework.log.entity.SysOperationLog;
23
+import io.geekidea.springbootplus.framework.log.param.SysOperationLogPageParam;
24
+import io.geekidea.springbootplus.framework.log.service.SysOperationLogService;
25
+import io.swagger.annotations.Api;
26
+import io.swagger.annotations.ApiOperation;
27
+import lombok.extern.slf4j.Slf4j;
28
+import org.apache.shiro.authz.annotation.RequiresPermissions;
29
+import org.springframework.beans.factory.annotation.Autowired;
30
+import org.springframework.validation.annotation.Validated;
31
+import org.springframework.web.bind.annotation.PostMapping;
32
+import org.springframework.web.bind.annotation.RequestBody;
33
+import org.springframework.web.bind.annotation.RequestMapping;
34
+import org.springframework.web.bind.annotation.RestController;
35
+
36
+/**
37
+ * 系统操作日志 控制器
38
+ *
39
+ * @author geekidea
40
+ * @since 2020-03-19
41
+ */
42
+@Slf4j
43
+@RestController
44
+@RequestMapping("/sysOperationLog")
45
+@Api(value = "系统操作日志API", tags = {"系统操作日志"})
46
+public class SysOperationLogController extends BaseController {
47
+
48
+    @Autowired
49
+    private SysOperationLogService sysOperationLogService;
50
+
51
+    /**
52
+     * 系统操作日志分页列表
53
+     */
54
+    @PostMapping("/getPageList")
55
+    @RequiresPermissions("sys:operation:log:page")
56
+    @ApiOperation(value = "系统操作日志分页列表", response = SysOperationLog.class)
57
+    public ApiResult<Paging<SysOperationLog>> getSysOperationLogPageList(@Validated @RequestBody SysOperationLogPageParam sysOperationLogPageParam) throws Exception {
58
+        Paging<SysOperationLog> paging = sysOperationLogService.getSysOperationLogPageList(sysOperationLogPageParam);
59
+        return ApiResult.ok(paging);
60
+    }
61
+
62
+}
63
+

+ 119
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/log/entity/SysLoginLog.java Voir le fichier

@@ -0,0 +1,119 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.log.entity;
18
+
19
+import com.baomidou.mybatisplus.annotation.IdType;
20
+import com.baomidou.mybatisplus.annotation.TableId;
21
+import io.geekidea.springbootplus.framework.common.entity.BaseEntity;
22
+import io.geekidea.springbootplus.framework.core.validator.groups.Update;
23
+import io.swagger.annotations.ApiModel;
24
+import io.swagger.annotations.ApiModelProperty;
25
+import lombok.Data;
26
+import lombok.EqualsAndHashCode;
27
+import lombok.experimental.Accessors;
28
+
29
+import javax.validation.constraints.NotNull;
30
+import java.util.Date;
31
+
32
+/**
33
+ * 系统登录日志
34
+ *
35
+ * @author geekidea
36
+ * @since 2020-03-24
37
+ */
38
+@Data
39
+@Accessors(chain = true)
40
+@EqualsAndHashCode(callSuper = true)
41
+@ApiModel(value = "SysLoginLog对象")
42
+public class SysLoginLog extends BaseEntity {
43
+    private static final long serialVersionUID = 1L;
44
+
45
+    @NotNull(message = "id不能为空", groups = {Update.class})
46
+    @ApiModelProperty("主键")
47
+    @TableId(value = "id", type = IdType.AUTO)
48
+    private Long id;
49
+
50
+    @ApiModelProperty("请求ID")
51
+    private String requestId;
52
+
53
+    @ApiModelProperty("用户名称")
54
+    private String username;
55
+
56
+    @ApiModelProperty("IP")
57
+    private String ip;
58
+
59
+    @ApiModelProperty("区域")
60
+    private String area;
61
+
62
+    @ApiModelProperty("运营商")
63
+    private String operator;
64
+
65
+    @ApiModelProperty("tokenMd5值")
66
+    private String token;
67
+
68
+    @ApiModelProperty("1:登录,2:登出")
69
+    private Integer type;
70
+
71
+    @ApiModelProperty("是否成功 true:成功/false:失败")
72
+    private Boolean success;
73
+
74
+    @ApiModelProperty("响应码")
75
+    private Integer code;
76
+
77
+    @ApiModelProperty("失败消息记录")
78
+    private String exceptionMessage;
79
+
80
+    @ApiModelProperty("浏览器名称")
81
+    private String userAgent;
82
+
83
+    @ApiModelProperty("浏览器名称")
84
+    private String browserName;
85
+
86
+    @ApiModelProperty("浏览器版本")
87
+    private String browserVersion;
88
+
89
+    @ApiModelProperty("浏览器引擎名称")
90
+    private String engineName;
91
+
92
+    @ApiModelProperty("浏览器引擎版本")
93
+    private String engineVersion;
94
+
95
+    @ApiModelProperty("系统名称")
96
+    private String osName;
97
+
98
+    @ApiModelProperty("平台名称")
99
+    private String platformName;
100
+
101
+    @ApiModelProperty("是否是手机,0:否,1:是")
102
+    private Boolean mobile;
103
+
104
+    @ApiModelProperty("移动端设备名称")
105
+    private String deviceName;
106
+
107
+    @ApiModelProperty("移动端设备型号")
108
+    private String deviceModel;
109
+
110
+    @ApiModelProperty("备注")
111
+    private String remark;
112
+
113
+    @ApiModelProperty("创建时间")
114
+    private Date createTime;
115
+
116
+    @ApiModelProperty("修改时间")
117
+    private Date updateTime;
118
+
119
+}

+ 152
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/log/entity/SysOperationLog.java Voir le fichier

@@ -0,0 +1,152 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.log.entity;
18
+
19
+import com.baomidou.mybatisplus.annotation.IdType;
20
+import com.baomidou.mybatisplus.annotation.TableId;
21
+import io.geekidea.springbootplus.framework.common.entity.BaseEntity;
22
+import io.geekidea.springbootplus.framework.core.validator.groups.Update;
23
+import io.swagger.annotations.ApiModel;
24
+import io.swagger.annotations.ApiModelProperty;
25
+import lombok.Data;
26
+import lombok.EqualsAndHashCode;
27
+import lombok.experimental.Accessors;
28
+
29
+import javax.validation.constraints.NotNull;
30
+import java.util.Date;
31
+
32
+/**
33
+ * 系统操作日志
34
+ *
35
+ * @author geekidea
36
+ * @since 2020-03-19
37
+ */
38
+@Data
39
+@Accessors(chain = true)
40
+@EqualsAndHashCode(callSuper = true)
41
+@ApiModel(value = "SysOperationLog对象")
42
+public class SysOperationLog extends BaseEntity {
43
+    private static final long serialVersionUID = 1L;
44
+
45
+    @ApiModelProperty("主键")
46
+    @TableId(value = "id", type = IdType.AUTO)
47
+    @NotNull(message = "id不能为空", groups = {Update.class})
48
+    private Long id;
49
+
50
+    @ApiModelProperty("请求ID")
51
+    private String requestId;
52
+
53
+    @ApiModelProperty("用户ID")
54
+    private Long userId;
55
+
56
+    @ApiModelProperty("用户名称")
57
+    private String userName;
58
+
59
+    @ApiModelProperty("日志名称")
60
+    private String name;
61
+
62
+    @ApiModelProperty("IP")
63
+    private String ip;
64
+
65
+    @ApiModelProperty("区域")
66
+    private String area;
67
+
68
+    @ApiModelProperty("运营商")
69
+    private String operator;
70
+
71
+    @ApiModelProperty("全路径")
72
+    private String path;
73
+
74
+    @ApiModelProperty("模块名称")
75
+    private String module;
76
+
77
+    @ApiModelProperty("类名")
78
+    private String className;
79
+
80
+    @ApiModelProperty("方法名称")
81
+    private String methodName;
82
+
83
+    @ApiModelProperty("请求方式,GET/POST")
84
+    private String requestMethod;
85
+
86
+    @ApiModelProperty("内容类型")
87
+    private String contentType;
88
+
89
+    @ApiModelProperty("是否是JSON请求映射参数")
90
+    private Boolean requestBody;
91
+
92
+    @ApiModelProperty("请求参数")
93
+    private String param;
94
+
95
+    @ApiModelProperty("tokenMd5值")
96
+    private String token;
97
+
98
+    @ApiModelProperty("0:其它,1:新增,2:修改,3:删除,4:详情查询,5:所有列表,6:分页列表,7:其它查询,8:上传文件")
99
+    private Integer type;
100
+
101
+    @ApiModelProperty("0:失败,1:成功")
102
+    private Boolean success;
103
+
104
+    @ApiModelProperty("响应结果状态码")
105
+    private Integer code;
106
+
107
+    @ApiModelProperty("响应结果消息")
108
+    private String message;
109
+
110
+    @ApiModelProperty("异常类名称")
111
+    private String exceptionName;
112
+
113
+    @ApiModelProperty("异常信息")
114
+    private String exceptionMessage;
115
+
116
+    @ApiModelProperty("浏览器名称")
117
+    private String browserName;
118
+
119
+    @ApiModelProperty("浏览器版本")
120
+    private String browserVersion;
121
+
122
+    @ApiModelProperty("浏览器引擎名称")
123
+    private String engineName;
124
+
125
+    @ApiModelProperty("浏览器引擎版本")
126
+    private String engineVersion;
127
+
128
+    @ApiModelProperty("系统名称")
129
+    private String osName;
130
+
131
+    @ApiModelProperty("平台名称")
132
+    private String platformName;
133
+
134
+    @ApiModelProperty("是否是手机,0:否,1:是")
135
+    private Boolean mobile;
136
+
137
+    @ApiModelProperty("移动端设备名称")
138
+    private String deviceName;
139
+
140
+    @ApiModelProperty("移动端设备型号")
141
+    private String deviceModel;
142
+
143
+    @ApiModelProperty("备注")
144
+    private String remark;
145
+
146
+    @ApiModelProperty("创建时间")
147
+    private Date createTime;
148
+
149
+    @ApiModelProperty("修改时间")
150
+    private Date updateTime;
151
+
152
+}

+ 88
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/log/enums/OperationLogType.java Voir le fichier

@@ -0,0 +1,88 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.log.enums;
18
+
19
+import io.geekidea.springbootplus.framework.common.enums.BaseEnum;
20
+import lombok.AllArgsConstructor;
21
+import lombok.Getter;
22
+
23
+/**
24
+ * 操作日志类型枚举
25
+ *
26
+ * @author geekidea
27
+ * @date 2020/3/19
28
+ **/
29
+@Getter
30
+@AllArgsConstructor
31
+public enum OperationLogType implements BaseEnum {
32
+    /**
33
+     * 其它
34
+     **/
35
+    OTHER(0, "其它"),
36
+    /**
37
+     * 添加
38
+     **/
39
+    ADD(1, "添加"),
40
+    /**
41
+     * 修改
42
+     **/
43
+    UPDATE(2, "修改"),
44
+    /**
45
+     * 删除
46
+     **/
47
+    DELETE(3, "删除"),
48
+    /**
49
+     * 查询
50
+     **/
51
+    query(4, "详情查询"),
52
+    /**
53
+     * 详情查询
54
+     **/
55
+    INFO(5, "详情查询"),
56
+    /**
57
+     * 列表查询
58
+     **/
59
+    LIST(6, "列表查询"),
60
+    /**
61
+     * 分页列表
62
+     **/
63
+    PAGE(7, "分页列表"),
64
+    /**
65
+     * 其它查询
66
+     **/
67
+    OTHER_QUERY(8, "其它查询"),
68
+    /**
69
+     * 文件上传
70
+     **/
71
+    UPLOAD(9, "文件上传"),
72
+    /**
73
+     * 文件下载
74
+     **/
75
+    download(10, "文件下载"),
76
+    /**
77
+     * Excel导入
78
+     **/
79
+    excel_import(11, "Excel导入"),
80
+    /**
81
+     * Excel导出
82
+     **/
83
+    EXCEL_EXPORT(12, "Excel导出");
84
+
85
+    private Integer code;
86
+    private String desc;
87
+
88
+}

+ 33
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/log/mapper/SysLoginLogMapper.java Voir le fichier

@@ -0,0 +1,33 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.log.mapper;
18
+
19
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
20
+import io.geekidea.springbootplus.framework.log.entity.SysLoginLog;
21
+import org.springframework.stereotype.Repository;
22
+
23
+/**
24
+ * 系统登录日志 Mapper 接口
25
+ *
26
+ * @author geekidea
27
+ * @since 2020-03-24
28
+ */
29
+@Repository
30
+public interface SysLoginLogMapper extends BaseMapper<SysLoginLog> {
31
+
32
+
33
+}

+ 33
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/log/mapper/SysOperationLogMapper.java Voir le fichier

@@ -0,0 +1,33 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.log.mapper;
18
+
19
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
20
+import io.geekidea.springbootplus.framework.log.entity.SysOperationLog;
21
+import org.springframework.stereotype.Repository;
22
+
23
+/**
24
+ * 系统操作日志 Mapper 接口
25
+ *
26
+ * @author geekidea
27
+ * @since 2020-03-19
28
+ */
29
+@Repository
30
+public interface SysOperationLogMapper extends BaseMapper<SysOperationLog> {
31
+
32
+
33
+}

+ 39
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/log/param/SysLoginLogPageParam.java Voir le fichier

@@ -0,0 +1,39 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.log.param;
18
+
19
+import io.geekidea.springbootplus.framework.core.pagination.BasePageOrderParam;
20
+import io.swagger.annotations.ApiModel;
21
+import lombok.Data;
22
+import lombok.EqualsAndHashCode;
23
+import lombok.experimental.Accessors;
24
+
25
+/**
26
+ * <pre>
27
+ * 系统登录日志 分页参数对象
28
+ * </pre>
29
+ *
30
+ * @author geekidea
31
+ * @date 2020-03-24
32
+ */
33
+@Data
34
+@Accessors(chain = true)
35
+@EqualsAndHashCode(callSuper = true)
36
+@ApiModel(value = "系统登录日志分页参数")
37
+public class SysLoginLogPageParam extends BasePageOrderParam {
38
+    private static final long serialVersionUID = 1L;
39
+}

+ 39
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/log/param/SysOperationLogPageParam.java Voir le fichier

@@ -0,0 +1,39 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.log.param;
18
+
19
+import io.geekidea.springbootplus.framework.core.pagination.BasePageOrderParam;
20
+import io.swagger.annotations.ApiModel;
21
+import lombok.Data;
22
+import lombok.EqualsAndHashCode;
23
+import lombok.experimental.Accessors;
24
+
25
+/**
26
+ * <pre>
27
+ * 系统操作日志 分页参数对象
28
+ * </pre>
29
+ *
30
+ * @author geekidea
31
+ * @date 2020-03-19
32
+ */
33
+@Data
34
+@Accessors(chain = true)
35
+@EqualsAndHashCode(callSuper = true)
36
+@ApiModel(value = "系统操作日志分页参数")
37
+public class SysOperationLogPageParam extends BasePageOrderParam {
38
+    private static final long serialVersionUID = 1L;
39
+}

+ 69
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/log/service/SysLoginLogService.java Voir le fichier

@@ -0,0 +1,69 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.log.service;
18
+
19
+import io.geekidea.springbootplus.framework.common.service.BaseService;
20
+import io.geekidea.springbootplus.framework.core.pagination.Paging;
21
+import io.geekidea.springbootplus.framework.log.entity.SysLoginLog;
22
+import io.geekidea.springbootplus.framework.log.param.SysLoginLogPageParam;
23
+
24
+/**
25
+ * 系统登录日志 服务类
26
+ *
27
+ * @author geekidea
28
+ * @since 2020-03-24
29
+ */
30
+public interface SysLoginLogService extends BaseService<SysLoginLog> {
31
+
32
+    /**
33
+     * 保存
34
+     *
35
+     * @param sysLoginLog
36
+     * @return
37
+     * @throws Exception
38
+     */
39
+    boolean saveSysLoginLog(SysLoginLog sysLoginLog) throws Exception;
40
+
41
+    /**
42
+     * 修改
43
+     *
44
+     * @param sysLoginLog
45
+     * @return
46
+     * @throws Exception
47
+     */
48
+    boolean updateSysLoginLog(SysLoginLog sysLoginLog) throws Exception;
49
+
50
+    /**
51
+     * 删除
52
+     *
53
+     * @param id
54
+     * @return
55
+     * @throws Exception
56
+     */
57
+    boolean deleteSysLoginLog(Long id) throws Exception;
58
+
59
+
60
+    /**
61
+     * 获取分页对象
62
+     *
63
+     * @param sysLoginLogQueryParam
64
+     * @return
65
+     * @throws Exception
66
+     */
67
+    Paging<SysLoginLog> getSysLoginLogPageList(SysLoginLogPageParam sysLoginLogPageParam) throws Exception;
68
+
69
+}

+ 69
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/log/service/SysOperationLogService.java Voir le fichier

@@ -0,0 +1,69 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.log.service;
18
+
19
+import io.geekidea.springbootplus.framework.common.service.BaseService;
20
+import io.geekidea.springbootplus.framework.core.pagination.Paging;
21
+import io.geekidea.springbootplus.framework.log.entity.SysOperationLog;
22
+import io.geekidea.springbootplus.framework.log.param.SysOperationLogPageParam;
23
+
24
+/**
25
+ * 系统操作日志 服务类
26
+ *
27
+ * @author geekidea
28
+ * @since 2020-03-19
29
+ */
30
+public interface SysOperationLogService extends BaseService<SysOperationLog> {
31
+
32
+    /**
33
+     * 保存
34
+     *
35
+     * @param sysOperationLog
36
+     * @return
37
+     * @throws Exception
38
+     */
39
+    boolean saveSysOperationLog(SysOperationLog sysOperationLog) throws Exception;
40
+
41
+    /**
42
+     * 修改
43
+     *
44
+     * @param sysOperationLog
45
+     * @return
46
+     * @throws Exception
47
+     */
48
+    boolean updateSysOperationLog(SysOperationLog sysOperationLog) throws Exception;
49
+
50
+    /**
51
+     * 删除
52
+     *
53
+     * @param id
54
+     * @return
55
+     * @throws Exception
56
+     */
57
+    boolean deleteSysOperationLog(Long id) throws Exception;
58
+
59
+
60
+    /**
61
+     * 获取分页对象
62
+     *
63
+     * @param sysOperationLogQueryParam
64
+     * @return
65
+     * @throws Exception
66
+     */
67
+    Paging<SysOperationLog> getSysOperationLogPageList(SysOperationLogPageParam sysOperationLogPageParam) throws Exception;
68
+
69
+}

+ 74
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/log/service/impl/SysLoginLogServiceImpl.java Voir le fichier

@@ -0,0 +1,74 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.log.service.impl;
18
+
19
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
20
+import com.baomidou.mybatisplus.core.metadata.IPage;
21
+import com.baomidou.mybatisplus.core.metadata.OrderItem;
22
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
23
+import io.geekidea.springbootplus.framework.common.service.impl.BaseServiceImpl;
24
+import io.geekidea.springbootplus.framework.core.pagination.PageInfo;
25
+import io.geekidea.springbootplus.framework.core.pagination.Paging;
26
+import io.geekidea.springbootplus.framework.log.entity.SysLoginLog;
27
+import io.geekidea.springbootplus.framework.log.mapper.SysLoginLogMapper;
28
+import io.geekidea.springbootplus.framework.log.param.SysLoginLogPageParam;
29
+import io.geekidea.springbootplus.framework.log.service.SysLoginLogService;
30
+import lombok.extern.slf4j.Slf4j;
31
+import org.springframework.beans.factory.annotation.Autowired;
32
+import org.springframework.stereotype.Service;
33
+import org.springframework.transaction.annotation.Transactional;
34
+
35
+/**
36
+ * 系统登录日志 服务实现类
37
+ *
38
+ * @author geekidea
39
+ * @since 2020-03-24
40
+ */
41
+@Slf4j
42
+@Service
43
+public class SysLoginLogServiceImpl extends BaseServiceImpl<SysLoginLogMapper, SysLoginLog> implements SysLoginLogService {
44
+
45
+    @Autowired
46
+    private SysLoginLogMapper sysLoginLogMapper;
47
+
48
+    @Transactional(rollbackFor = Exception.class)
49
+    @Override
50
+    public boolean saveSysLoginLog(SysLoginLog sysLoginLog) throws Exception {
51
+        return super.save(sysLoginLog);
52
+    }
53
+
54
+    @Transactional(rollbackFor = Exception.class)
55
+    @Override
56
+    public boolean updateSysLoginLog(SysLoginLog sysLoginLog) throws Exception {
57
+        return super.updateById(sysLoginLog);
58
+    }
59
+
60
+    @Transactional(rollbackFor = Exception.class)
61
+    @Override
62
+    public boolean deleteSysLoginLog(Long id) throws Exception {
63
+        return super.removeById(id);
64
+    }
65
+
66
+    @Override
67
+    public Paging<SysLoginLog> getSysLoginLogPageList(SysLoginLogPageParam sysLoginLogPageParam) throws Exception {
68
+        Page<SysLoginLog> page = new PageInfo<>(sysLoginLogPageParam,OrderItem.desc(getLambdaColumn(SysLoginLog::getCreateTime)));
69
+        LambdaQueryWrapper<SysLoginLog> wrapper = new LambdaQueryWrapper<>();
70
+        IPage<SysLoginLog> iPage = sysLoginLogMapper.selectPage(page, wrapper);
71
+        return new Paging<SysLoginLog>(iPage);
72
+    }
73
+
74
+}

+ 74
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/log/service/impl/SysOperationLogServiceImpl.java Voir le fichier

@@ -0,0 +1,74 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.log.service.impl;
18
+
19
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
20
+import com.baomidou.mybatisplus.core.metadata.IPage;
21
+import com.baomidou.mybatisplus.core.metadata.OrderItem;
22
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
23
+import io.geekidea.springbootplus.framework.common.service.impl.BaseServiceImpl;
24
+import io.geekidea.springbootplus.framework.core.pagination.PageInfo;
25
+import io.geekidea.springbootplus.framework.core.pagination.Paging;
26
+import io.geekidea.springbootplus.framework.log.entity.SysOperationLog;
27
+import io.geekidea.springbootplus.framework.log.mapper.SysOperationLogMapper;
28
+import io.geekidea.springbootplus.framework.log.param.SysOperationLogPageParam;
29
+import io.geekidea.springbootplus.framework.log.service.SysOperationLogService;
30
+import lombok.extern.slf4j.Slf4j;
31
+import org.springframework.beans.factory.annotation.Autowired;
32
+import org.springframework.stereotype.Service;
33
+import org.springframework.transaction.annotation.Transactional;
34
+
35
+/**
36
+ * 系统操作日志 服务实现类
37
+ *
38
+ * @author geekidea
39
+ * @since 2020-03-19
40
+ */
41
+@Slf4j
42
+@Service
43
+public class SysOperationLogServiceImpl extends BaseServiceImpl<SysOperationLogMapper, SysOperationLog> implements SysOperationLogService {
44
+
45
+    @Autowired
46
+    private SysOperationLogMapper sysOperationLogMapper;
47
+
48
+    @Transactional(rollbackFor = Exception.class)
49
+    @Override
50
+    public boolean saveSysOperationLog(SysOperationLog sysOperationLog) throws Exception {
51
+        return super.save(sysOperationLog);
52
+    }
53
+
54
+    @Transactional(rollbackFor = Exception.class)
55
+    @Override
56
+    public boolean updateSysOperationLog(SysOperationLog sysOperationLog) throws Exception {
57
+        return super.updateById(sysOperationLog);
58
+    }
59
+
60
+    @Transactional(rollbackFor = Exception.class)
61
+    @Override
62
+    public boolean deleteSysOperationLog(Long id) throws Exception {
63
+        return super.removeById(id);
64
+    }
65
+
66
+    @Override
67
+    public Paging<SysOperationLog> getSysOperationLogPageList(SysOperationLogPageParam sysOperationLogPageParam) throws Exception {
68
+        Page<SysOperationLog> page = new PageInfo<>(sysOperationLogPageParam,OrderItem.desc(getLambdaColumn(SysOperationLog::getCreateTime)));
69
+        LambdaQueryWrapper<SysOperationLog> wrapper = new LambdaQueryWrapper<>();
70
+        IPage<SysOperationLog> iPage = sysOperationLogMapper.selectPage(page, wrapper);
71
+        return new Paging<SysOperationLog>(iPage);
72
+    }
73
+
74
+}

+ 98
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/shiro/cache/LoginRedisService.java Voir le fichier

@@ -0,0 +1,98 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.shiro.cache;
18
+
19
+
20
+import io.geekidea.springbootplus.framework.shiro.jwt.JwtToken;
21
+import io.geekidea.springbootplus.framework.shiro.vo.LoginSysUserRedisVo;
22
+import io.geekidea.springbootplus.framework.shiro.vo.LoginSysUserVo;
23
+
24
+/**
25
+ * 登录信息Redis缓存操作服务
26
+ *
27
+ * @author geekidea
28
+ * @date 2019-09-30
29
+ * @since 1.3.0.RELEASE
30
+ **/
31
+public interface LoginRedisService {
32
+
33
+    /**
34
+     * 缓存登录信息
35
+     *
36
+     * @param jwtToken
37
+     * @param loginSysUserVo
38
+     */
39
+    void cacheLoginInfo(JwtToken jwtToken, LoginSysUserVo loginSysUserVo);
40
+
41
+
42
+    /**
43
+     * 刷新登录信息
44
+     *
45
+     * @param oldToken
46
+     * @param username
47
+     * @param newJwtToken
48
+     */
49
+    void refreshLoginInfo(String oldToken, String username, JwtToken newJwtToken);
50
+
51
+    /**
52
+     * 通过用户名,从缓存中获取登录用户LoginSysUserRedisVo
53
+     *
54
+     * @param username
55
+     * @return
56
+     */
57
+    LoginSysUserRedisVo getLoginSysUserRedisVo(String username);
58
+
59
+    /**
60
+     * 获取登录用户对象
61
+     *
62
+     * @param username
63
+     * @return
64
+     */
65
+    LoginSysUserVo getLoginSysUserVo(String username);
66
+
67
+    /**
68
+     * 通过用户名称获取盐值
69
+     *
70
+     * @param username
71
+     * @return
72
+     */
73
+    String getSalt(String username);
74
+
75
+    /**
76
+     * 删除对应用户的Redis缓存
77
+     *
78
+     * @param token
79
+     * @param username
80
+     */
81
+    void deleteLoginInfo(String token, String username);
82
+
83
+    /**
84
+     * 判断token在redis中是否存在
85
+     *
86
+     * @param token
87
+     * @return
88
+     */
89
+    boolean exists(String token);
90
+
91
+    /**
92
+     * 删除用户所有登录缓存
93
+     *
94
+     * @param username
95
+     */
96
+    void deleteUserAllCache(String username);
97
+
98
+}

+ 199
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/shiro/cache/impl/LoginRedisServiceImpl.java Voir le fichier

@@ -0,0 +1,199 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.shiro.cache.impl;
18
+
19
+import io.geekidea.springbootplus.config.constant.CommonRedisKey;
20
+import io.geekidea.springbootplus.config.properties.JwtProperties;
21
+import io.geekidea.springbootplus.framework.common.bean.ClientInfo;
22
+import io.geekidea.springbootplus.framework.shiro.cache.LoginRedisService;
23
+import io.geekidea.springbootplus.framework.shiro.convert.LoginSysUserVoConvert;
24
+import io.geekidea.springbootplus.framework.shiro.convert.ShiroMapstructConvert;
25
+import io.geekidea.springbootplus.framework.shiro.jwt.JwtToken;
26
+import io.geekidea.springbootplus.framework.shiro.vo.JwtTokenRedisVo;
27
+import io.geekidea.springbootplus.framework.shiro.vo.LoginSysUserRedisVo;
28
+import io.geekidea.springbootplus.framework.shiro.vo.LoginSysUserVo;
29
+import io.geekidea.springbootplus.framework.util.ClientInfoUtil;
30
+import io.geekidea.springbootplus.framework.util.HttpServletRequestUtil;
31
+import org.apache.commons.codec.digest.DigestUtils;
32
+import org.apache.commons.collections4.CollectionUtils;
33
+import org.apache.commons.lang3.StringUtils;
34
+import org.springframework.beans.factory.annotation.Autowired;
35
+import org.springframework.data.redis.core.RedisTemplate;
36
+import org.springframework.stereotype.Service;
37
+
38
+import java.time.Duration;
39
+import java.util.List;
40
+import java.util.Set;
41
+
42
+/**
43
+ * 登录信息Redis缓存服务类
44
+ *
45
+ * @author geekidea
46
+ * @date 2019-09-30
47
+ * @since 1.3.0.RELEASE
48
+ **/
49
+@Service
50
+public class LoginRedisServiceImpl implements LoginRedisService {
51
+
52
+    @Autowired
53
+    private JwtProperties jwtProperties;
54
+
55
+    @Autowired
56
+    private RedisTemplate redisTemplate;
57
+
58
+    /**
59
+     * key-value: 有过期时间-->token过期时间
60
+     * 1. tokenMd5:jwtTokenRedisVo
61
+     * 2. username:loginSysUserRedisVo
62
+     * 3. username:salt
63
+     * hash: 没有过期时间,统计在线的用户信息
64
+     * username:num
65
+     */
66
+    @Override
67
+    public void cacheLoginInfo(JwtToken jwtToken, LoginSysUserVo loginSysUserVo) {
68
+        if (jwtToken == null) {
69
+            throw new IllegalArgumentException("jwtToken不能为空");
70
+        }
71
+        if (loginSysUserVo == null) {
72
+            throw new IllegalArgumentException("loginSysUserVo不能为空");
73
+        }
74
+        // token
75
+        String token = jwtToken.getToken();
76
+        // 盐值
77
+        String salt = jwtToken.getSalt();
78
+        // 登录用户名称
79
+        String username = loginSysUserVo.getUsername();
80
+        // token md5值
81
+        String tokenMd5 = DigestUtils.md5Hex(token);
82
+
83
+        // Redis缓存JWT Token信息
84
+        JwtTokenRedisVo jwtTokenRedisVo = ShiroMapstructConvert.INSTANCE.jwtTokenToJwtTokenRedisVo(jwtToken);
85
+
86
+        // 用户客户端信息
87
+        ClientInfo clientInfo = ClientInfoUtil.get(HttpServletRequestUtil.getRequest());
88
+
89
+        // Redis缓存登录用户信息
90
+        // 将LoginSysUserVo对象复制到LoginSysUserRedisVo,使用mapstruct进行对象属性复制
91
+        LoginSysUserRedisVo loginSysUserRedisVo = LoginSysUserVoConvert.INSTANCE.voToRedisVo(loginSysUserVo);
92
+        loginSysUserRedisVo.setSalt(salt);
93
+        loginSysUserRedisVo.setClientInfo(clientInfo);
94
+
95
+        // Redis过期时间与JwtToken过期时间一致
96
+        Duration expireDuration = Duration.ofSeconds(jwtToken.getExpireSecond());
97
+
98
+        // 判断是否启用单个用户登录,如果是,这每个用户只有一个有效token
99
+        boolean singleLogin = jwtProperties.isSingleLogin();
100
+        if (singleLogin) {
101
+            deleteUserAllCache(username);
102
+        }
103
+
104
+        // 1. tokenMd5:jwtTokenRedisVo
105
+        String loginTokenRedisKey = String.format(CommonRedisKey.LOGIN_TOKEN, tokenMd5);
106
+        redisTemplate.opsForValue().set(loginTokenRedisKey, jwtTokenRedisVo, expireDuration);
107
+        // 2. username:loginSysUserRedisVo
108
+        redisTemplate.opsForValue().set(String.format(CommonRedisKey.LOGIN_USER, username), loginSysUserRedisVo, expireDuration);
109
+        // 3. salt hash,方便获取盐值鉴权
110
+        redisTemplate.opsForValue().set(String.format(CommonRedisKey.LOGIN_SALT, username), salt, expireDuration);
111
+        // 4. login user token
112
+        redisTemplate.opsForValue().set(String.format(CommonRedisKey.LOGIN_USER_TOKEN, username, tokenMd5), loginTokenRedisKey, expireDuration);
113
+    }
114
+
115
+    @Override
116
+    public void refreshLoginInfo(String oldToken, String username, JwtToken newJwtToken) {
117
+        // 获取缓存的登录用户信息
118
+        LoginSysUserRedisVo loginSysUserRedisVo = getLoginSysUserRedisVo(username);
119
+        // 删除之前的token信息
120
+        deleteLoginInfo(oldToken, username);
121
+        // 缓存登录信息
122
+        cacheLoginInfo(newJwtToken, loginSysUserRedisVo);
123
+    }
124
+
125
+    @Override
126
+    public LoginSysUserRedisVo getLoginSysUserRedisVo(String username) {
127
+        if (StringUtils.isBlank(username)) {
128
+            throw new IllegalArgumentException("username不能为空");
129
+        }
130
+        return (LoginSysUserRedisVo) redisTemplate.opsForValue().get(String.format(CommonRedisKey.LOGIN_USER, username));
131
+    }
132
+
133
+    @Override
134
+    public LoginSysUserVo getLoginSysUserVo(String username) {
135
+        if (StringUtils.isBlank(username)) {
136
+            throw new IllegalArgumentException("username不能为空");
137
+        }
138
+        LoginSysUserRedisVo userRedisVo = getLoginSysUserRedisVo(username);
139
+        return userRedisVo;
140
+    }
141
+
142
+    @Override
143
+    public String getSalt(String username) {
144
+        if (StringUtils.isBlank(username)) {
145
+            throw new IllegalArgumentException("username不能为空");
146
+        }
147
+        String salt = (String) redisTemplate.opsForValue().get(String.format(CommonRedisKey.LOGIN_SALT, username));
148
+        return salt;
149
+    }
150
+
151
+    @Override
152
+    public void deleteLoginInfo(String token, String username) {
153
+        if (token == null) {
154
+            throw new IllegalArgumentException("token不能为空");
155
+        }
156
+        if (username == null) {
157
+            throw new IllegalArgumentException("username不能为空");
158
+        }
159
+        String tokenMd5 = DigestUtils.md5Hex(token);
160
+        // 1. delete tokenMd5
161
+        redisTemplate.delete(String.format(CommonRedisKey.LOGIN_TOKEN, tokenMd5));
162
+        // 2. delete username
163
+        redisTemplate.delete(String.format(CommonRedisKey.LOGIN_USER, username));
164
+        // 3. delete salt
165
+        redisTemplate.delete(String.format(CommonRedisKey.LOGIN_SALT, username));
166
+        // 4. delete user token
167
+        redisTemplate.delete(String.format(CommonRedisKey.LOGIN_USER_TOKEN, username, tokenMd5));
168
+    }
169
+
170
+    @Override
171
+    public boolean exists(String token) {
172
+        if (token == null) {
173
+            throw new IllegalArgumentException("token不能为空");
174
+        }
175
+        String tokenMd5 = DigestUtils.md5Hex(token);
176
+        Object object = redisTemplate.opsForValue().get(String.format(CommonRedisKey.LOGIN_TOKEN, tokenMd5));
177
+        return object != null;
178
+    }
179
+
180
+    @Override
181
+    public void deleteUserAllCache(String username) {
182
+        Set<String> userTokenMd5Set = redisTemplate.keys(String.format(CommonRedisKey.LOGIN_USER_ALL_TOKEN, username));
183
+        if (CollectionUtils.isEmpty(userTokenMd5Set)) {
184
+            return;
185
+        }
186
+
187
+        // 1. 删除登录用户的所有token信息
188
+        List<String> tokenMd5List = redisTemplate.opsForValue().multiGet(userTokenMd5Set);
189
+        redisTemplate.delete(tokenMd5List);
190
+        // 2. 删除登录用户的所有user:token信息
191
+        redisTemplate.delete(userTokenMd5Set);
192
+        // 3. 删除登录用户信息
193
+        redisTemplate.delete(String.format(CommonRedisKey.LOGIN_USER, username));
194
+        // 4. 删除登录用户盐值信息
195
+        redisTemplate.delete(String.format(CommonRedisKey.LOGIN_SALT, username));
196
+    }
197
+
198
+
199
+}

+ 43
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/shiro/convert/LoginSysUserVoConvert.java Voir le fichier

@@ -0,0 +1,43 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.shiro.convert;
18
+
19
+import io.geekidea.springbootplus.framework.shiro.vo.LoginSysUserRedisVo;
20
+import io.geekidea.springbootplus.framework.shiro.vo.LoginSysUserVo;
21
+import org.mapstruct.Mapper;
22
+import org.mapstruct.factory.Mappers;
23
+
24
+/**
25
+ * 登录系统用户VO对象属性复制转换器
26
+ *
27
+ * @author geekidea
28
+ * @date 2020/3/24
29
+ **/
30
+@Mapper
31
+public interface LoginSysUserVoConvert {
32
+
33
+    LoginSysUserVoConvert INSTANCE = Mappers.getMapper(LoginSysUserVoConvert.class);
34
+
35
+    /**
36
+     * LoginSysUserVo对象转换成LoginSysUserRedisVo
37
+     *
38
+     * @param loginSysUserVo
39
+     * @return
40
+     */
41
+    LoginSysUserRedisVo voToRedisVo(LoginSysUserVo loginSysUserVo);
42
+
43
+}

+ 44
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/shiro/convert/ShiroMapstructConvert.java Voir le fichier

@@ -0,0 +1,44 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.shiro.convert;
18
+
19
+import io.geekidea.springbootplus.framework.shiro.jwt.JwtToken;
20
+import io.geekidea.springbootplus.framework.shiro.vo.JwtTokenRedisVo;
21
+import org.mapstruct.Mapper;
22
+import org.mapstruct.factory.Mappers;
23
+
24
+/**
25
+ * Shiro包下使用mapstruct对象属性复制转换器
26
+ *
27
+ * @author geekidea
28
+ * @date 2019-09-30
29
+ * @since 1.3.0.RELEASE
30
+ **/
31
+@Mapper
32
+public interface ShiroMapstructConvert {
33
+
34
+    ShiroMapstructConvert INSTANCE = Mappers.getMapper(ShiroMapstructConvert.class);
35
+
36
+    /**
37
+     * JwtToken对象转换成JwtTokenRedisVo
38
+     *
39
+     * @param jwtToken
40
+     * @return
41
+     */
42
+    JwtTokenRedisVo jwtTokenToJwtTokenRedisVo(JwtToken jwtToken);
43
+
44
+}

+ 43
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/shiro/exception/ShiroConfigException.java Voir le fichier

@@ -0,0 +1,43 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.shiro.exception;
18
+
19
+import io.geekidea.springbootplus.framework.common.api.ApiCode;
20
+import io.geekidea.springbootplus.framework.common.exception.SpringBootPlusException;
21
+
22
+/**
23
+ * Shiro配置异常
24
+ *
25
+ * @author geekidea
26
+ * @date 2019-09-29
27
+ * @since 1.3.0.RELEASE
28
+ **/
29
+public class ShiroConfigException extends SpringBootPlusException {
30
+	private static final long serialVersionUID = -4573955712491628431L;
31
+
32
+	public ShiroConfigException(String message) {
33
+        super(message);
34
+    }
35
+
36
+    public ShiroConfigException(Integer errorCode, String message) {
37
+        super(errorCode, message);
38
+    }
39
+
40
+    public ShiroConfigException(ApiCode apiCode) {
41
+        super(apiCode);
42
+    }
43
+}

+ 47
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/shiro/jwt/JwtCredentialsMatcher.java Voir le fichier

@@ -0,0 +1,47 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.shiro.jwt;
18
+
19
+import io.geekidea.springbootplus.framework.shiro.util.JwtUtil;
20
+import lombok.extern.slf4j.Slf4j;
21
+import org.apache.shiro.authc.AuthenticationInfo;
22
+import org.apache.shiro.authc.AuthenticationToken;
23
+import org.apache.shiro.authc.credential.CredentialsMatcher;
24
+
25
+/**
26
+ * JWT证书匹配
27
+ *
28
+ * @author geekidea
29
+ * @date 2019-09-30
30
+ * @since 1.3.0.RELEASE
31
+ **/
32
+@Slf4j
33
+public class JwtCredentialsMatcher implements CredentialsMatcher {
34
+
35
+    @Override
36
+    public boolean doCredentialsMatch(AuthenticationToken authenticationToken, AuthenticationInfo authenticationInfo) {
37
+        String token = authenticationToken.getCredentials().toString();
38
+        String salt = authenticationInfo.getCredentials().toString();
39
+        try {
40
+            return JwtUtil.verifyToken(token, salt);
41
+        } catch (Exception e) {
42
+            log.error("JWT Token CredentialsMatch Exception:" + e.getMessage(), e);
43
+        }
44
+        return false;
45
+    }
46
+
47
+}

+ 181
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/shiro/jwt/JwtFilter.java Voir le fichier

@@ -0,0 +1,181 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.shiro.jwt;
18
+
19
+import io.geekidea.springbootplus.config.properties.JwtProperties;
20
+import io.geekidea.springbootplus.framework.common.api.ApiCode;
21
+import io.geekidea.springbootplus.framework.common.api.ApiResult;
22
+import io.geekidea.springbootplus.framework.shiro.cache.LoginRedisService;
23
+import io.geekidea.springbootplus.framework.shiro.service.ShiroLoginService;
24
+import io.geekidea.springbootplus.framework.shiro.util.JwtTokenUtil;
25
+import io.geekidea.springbootplus.framework.shiro.util.JwtUtil;
26
+import io.geekidea.springbootplus.framework.util.HttpServletResponseUtil;
27
+import lombok.extern.slf4j.Slf4j;
28
+import org.apache.commons.lang3.StringUtils;
29
+import org.apache.shiro.authc.AuthenticationException;
30
+import org.apache.shiro.authc.AuthenticationToken;
31
+import org.apache.shiro.subject.Subject;
32
+import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
33
+import org.apache.shiro.web.util.WebUtils;
34
+
35
+import javax.servlet.ServletRequest;
36
+import javax.servlet.ServletResponse;
37
+import javax.servlet.http.HttpServletRequest;
38
+import javax.servlet.http.HttpServletResponse;
39
+
40
+/**
41
+ * Shiro JWT授权过滤器
42
+ *
43
+ * @author geekidea
44
+ * @date 2019-09-27
45
+ * @since 1.3.0.RELEASE
46
+ **/
47
+@Slf4j
48
+public class JwtFilter extends AuthenticatingFilter {
49
+
50
+    private ShiroLoginService shiroLoginService;
51
+
52
+    private LoginRedisService loginRedisService;
53
+
54
+    private JwtProperties jwtProperties;
55
+
56
+    public JwtFilter(ShiroLoginService shiroLoginService, LoginRedisService loginRedisService, JwtProperties jwtProperties) {
57
+        this.shiroLoginService = shiroLoginService;
58
+        this.loginRedisService = loginRedisService;
59
+        this.jwtProperties = jwtProperties;
60
+    }
61
+
62
+    /**
63
+     * 将JWT Token包装成AuthenticationToken
64
+     *
65
+     * @param servletRequest
66
+     * @param servletResponse
67
+     * @return
68
+     * @throws Exception
69
+     */
70
+    @Override
71
+    protected AuthenticationToken createToken(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
72
+        String token = JwtTokenUtil.getToken();
73
+        if (StringUtils.isBlank(token)) {
74
+            throw new AuthenticationException("token不能为空");
75
+        }
76
+        if (JwtUtil.isExpired(token)) {
77
+            throw new AuthenticationException("JWT Token已过期,token:" + token);
78
+        }
79
+
80
+        // 如果开启redis二次校验,或者设置为单个用户token登录,则先在redis中判断token是否存在
81
+        if (jwtProperties.isRedisCheck() || jwtProperties.isSingleLogin()) {
82
+            boolean redisExpired = loginRedisService.exists(token);
83
+            if (!redisExpired) {
84
+                throw new AuthenticationException("Redis Token不存在,token:" + token);
85
+            }
86
+        }
87
+
88
+        String username = JwtUtil.getUsername(token);
89
+        String salt;
90
+        if (jwtProperties.isSaltCheck()){
91
+            salt = loginRedisService.getSalt(username);
92
+        }else{
93
+            salt = jwtProperties.getSecret();
94
+        }
95
+        return JwtToken.build(token, username, salt, jwtProperties.getExpireSecond());
96
+    }
97
+
98
+    /**
99
+     * 访问失败处理
100
+     *
101
+     * @param request
102
+     * @param response
103
+     * @return
104
+     * @throws Exception
105
+     */
106
+    @Override
107
+    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
108
+        HttpServletRequest httpServletRequest = WebUtils.toHttp(request);
109
+        HttpServletResponse httpServletResponse = WebUtils.toHttp(response);
110
+        // 返回401
111
+        httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
112
+        // 设置响应码为401或者直接输出消息
113
+        String url = httpServletRequest.getRequestURI();
114
+        log.error("onAccessDenied url:{}", url);
115
+        ApiResult<Boolean> apiResult = ApiResult.fail(ApiCode.UNAUTHORIZED);
116
+        HttpServletResponseUtil.printJson(httpServletResponse, apiResult);
117
+        return false;
118
+    }
119
+
120
+    /**
121
+     * 判断是否允许访问
122
+     *
123
+     * @param request
124
+     * @param response
125
+     * @param mappedValue
126
+     * @return
127
+     */
128
+    @Override
129
+    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
130
+        String url = WebUtils.toHttp(request).getRequestURI();
131
+        log.debug("isAccessAllowed url:{}", url);
132
+        if (this.isLoginRequest(request, response)) {
133
+            return true;
134
+        }
135
+        boolean allowed = false;
136
+        try {
137
+            allowed = executeLogin(request, response);
138
+        } catch (IllegalStateException e) { //not found any token
139
+            log.error("Token不能为空", e);
140
+        } catch (Exception e) {
141
+            log.error("访问错误", e);
142
+        }
143
+        return allowed || super.isPermissive(mappedValue);
144
+    }
145
+
146
+    /**
147
+     * 登录成功处理
148
+     *
149
+     * @param token
150
+     * @param subject
151
+     * @param request
152
+     * @param response
153
+     * @return
154
+     * @throws Exception
155
+     */
156
+    @Override
157
+    protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {
158
+        String url = WebUtils.toHttp(request).getRequestURI();
159
+        log.debug("鉴权成功,token:{},url:{}", token, url);
160
+        // 刷新token
161
+        JwtToken jwtToken = (JwtToken) token;
162
+        HttpServletResponse httpServletResponse = WebUtils.toHttp(response);
163
+        shiroLoginService.refreshToken(jwtToken, httpServletResponse);
164
+        return true;
165
+    }
166
+
167
+    /**
168
+     * 登录失败处理
169
+     *
170
+     * @param token
171
+     * @param e
172
+     * @param request
173
+     * @param response
174
+     * @return
175
+     */
176
+    @Override
177
+    protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
178
+        log.error("登录失败,token:" + token + ",error:" + e.getMessage(), e);
179
+        return false;
180
+    }
181
+}

+ 104
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/shiro/jwt/JwtRealm.java Voir le fichier

@@ -0,0 +1,104 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.shiro.jwt;
18
+
19
+import io.geekidea.springbootplus.framework.shiro.cache.LoginRedisService;
20
+import io.geekidea.springbootplus.framework.shiro.vo.LoginSysUserRedisVo;
21
+import lombok.extern.slf4j.Slf4j;
22
+import org.apache.commons.collections4.SetUtils;
23
+import org.apache.commons.lang3.StringUtils;
24
+import org.apache.shiro.authc.AuthenticationException;
25
+import org.apache.shiro.authc.AuthenticationInfo;
26
+import org.apache.shiro.authc.AuthenticationToken;
27
+import org.apache.shiro.authc.SimpleAuthenticationInfo;
28
+import org.apache.shiro.authz.AuthorizationInfo;
29
+import org.apache.shiro.authz.SimpleAuthorizationInfo;
30
+import org.apache.shiro.realm.AuthorizingRealm;
31
+import org.apache.shiro.subject.PrincipalCollection;
32
+
33
+/**
34
+ * Shiro 授权认证
35
+ *
36
+ * @author geekidea
37
+ * @date 2019-09-27
38
+ * @since 1.3.0.RELEASE
39
+ **/
40
+@Slf4j
41
+public class JwtRealm extends AuthorizingRealm {
42
+
43
+    private LoginRedisService loginRedisService;
44
+
45
+    public JwtRealm(LoginRedisService loginRedisService) {
46
+        this.loginRedisService = loginRedisService;
47
+    }
48
+
49
+    @Override
50
+    public boolean supports(AuthenticationToken token) {
51
+        return token != null && token instanceof JwtToken;
52
+    }
53
+
54
+    /**
55
+     * 授权认证,设置角色/权限信息
56
+     *
57
+     * @param principalCollection
58
+     * @return
59
+     */
60
+    @Override
61
+    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
62
+        log.debug("doGetAuthorizationInfo principalCollection...");
63
+        // 设置角色/权限信息
64
+        JwtToken jwtToken = (JwtToken) principalCollection.getPrimaryPrincipal();
65
+        // 获取username
66
+        String username = jwtToken.getUsername();
67
+        // 获取登录用户角色权限信息
68
+        LoginSysUserRedisVo loginSysUserRedisVo = loginRedisService.getLoginSysUserRedisVo(username);
69
+        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
70
+        // 设置角色
71
+        authorizationInfo.setRoles(SetUtils.hashSet(loginSysUserRedisVo.getRoleCode()));
72
+        // 设置权限
73
+        authorizationInfo.setStringPermissions(loginSysUserRedisVo.getPermissionCodes());
74
+        return authorizationInfo;
75
+    }
76
+
77
+    /**
78
+     * 登录认证
79
+     *
80
+     * @param authenticationToken
81
+     * @return
82
+     * @throws AuthenticationException
83
+     */
84
+    @Override
85
+    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
86
+        log.debug("doGetAuthenticationInfo authenticationToken...");
87
+        // 校验token
88
+        JwtToken jwtToken = (JwtToken) authenticationToken;
89
+        if (jwtToken == null) {
90
+            throw new AuthenticationException("jwtToken不能为空");
91
+        }
92
+        String salt = jwtToken.getSalt();
93
+        if (StringUtils.isBlank(salt)) {
94
+            throw new AuthenticationException("salt不能为空");
95
+        }
96
+        return new SimpleAuthenticationInfo(
97
+                jwtToken,
98
+                salt,
99
+                getName()
100
+        );
101
+
102
+    }
103
+
104
+}

+ 98
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/shiro/jwt/JwtToken.java Voir le fichier

@@ -0,0 +1,98 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.shiro.jwt;
18
+
19
+import com.auth0.jwt.interfaces.DecodedJWT;
20
+import io.geekidea.springbootplus.framework.shiro.util.JwtUtil;
21
+import io.geekidea.springbootplus.framework.util.IpUtil;
22
+import lombok.Data;
23
+import lombok.experimental.Accessors;
24
+import org.apache.shiro.authc.HostAuthenticationToken;
25
+
26
+import java.util.Date;
27
+
28
+/**
29
+ * Shiro JwtToken对象
30
+ *
31
+ * @author geekidea
32
+ * @date 2019-09-27
33
+ * @since 1.3.0.RELEASE
34
+ **/
35
+@Data
36
+@Accessors(chain = true)
37
+public class JwtToken implements HostAuthenticationToken {
38
+	private static final long serialVersionUID = 5101247566043093405L;
39
+	
40
+	/**
41
+     * 登录ip
42
+     */
43
+    private String host;
44
+    /**
45
+     * 登录用户名称
46
+     */
47
+    private String username;
48
+    /**
49
+     * 登录盐值
50
+     */
51
+    private String salt;
52
+    /**
53
+     * 登录token
54
+     */
55
+    private String token;
56
+    /**
57
+     * 创建时间
58
+     */
59
+    private Date createDate;
60
+    /**
61
+     * 多长时间过期,默认一小时
62
+     */
63
+    private long expireSecond;
64
+    /**
65
+     * 过期日期
66
+     */
67
+    private Date expireDate;
68
+
69
+    private String principal;
70
+
71
+    private String credentials;
72
+
73
+    @Override
74
+    public Object getPrincipal() {
75
+        return token;
76
+    }
77
+
78
+    @Override
79
+    public Object getCredentials() {
80
+        return token;
81
+    }
82
+
83
+    public static JwtToken build(String token, String username, String salt, long expireSecond) {
84
+        DecodedJWT decodedJwt = JwtUtil.getJwtInfo(token);
85
+        Date createDate = decodedJwt.getIssuedAt();
86
+        Date expireDate = decodedJwt.getExpiresAt();
87
+        return new JwtToken()
88
+                .setUsername(username)
89
+                .setToken(token)
90
+                .setHost(IpUtil.getRequestIp())
91
+                .setSalt(salt)
92
+                .setCreateDate(createDate)
93
+                .setExpireSecond(expireSecond)
94
+                .setExpireDate(expireDate);
95
+
96
+    }
97
+
98
+}

+ 36
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/shiro/service/LoginToken.java Voir le fichier

@@ -0,0 +1,36 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.shiro.service;
18
+
19
+import java.io.Serializable;
20
+
21
+/**
22
+ * 获取登录token
23
+ *
24
+ * @author geekidea
25
+ * @date 2020/3/25
26
+ **/
27
+public interface LoginToken extends Serializable {
28
+
29
+    /**
30
+     * 获取登录token
31
+     *
32
+     * @return
33
+     */
34
+    String getToken();
35
+
36
+}

+ 36
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/shiro/service/LoginUsername.java Voir le fichier

@@ -0,0 +1,36 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.shiro.service;
18
+
19
+import java.io.Serializable;
20
+
21
+/**
22
+ * 获取登录用户名称
23
+ *
24
+ * @author geekidea
25
+ * @date 2020/3/24
26
+ **/
27
+public interface LoginUsername extends Serializable {
28
+
29
+    /**
30
+     * 获取用户名
31
+     *
32
+     * @return
33
+     */
34
+    String getUsername();
35
+
36
+}

+ 42
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/shiro/service/ShiroLoginService.java Voir le fichier

@@ -0,0 +1,42 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.shiro.service;
18
+
19
+import io.geekidea.springbootplus.framework.shiro.jwt.JwtToken;
20
+
21
+import javax.servlet.http.HttpServletResponse;
22
+
23
+/**
24
+ * @author geekidea
25
+ * @date 2020/3/24
26
+ **/
27
+public interface ShiroLoginService {
28
+    /**
29
+     * 如果(当前时间+倒计时) > 过期时间,则刷新token
30
+     * 并更新缓存
31
+     * 当前token失效,返回新token
32
+     * 当前请求有效,返回状态码:460
33
+     * 前端下次使用新token
34
+     * 如果token继续发往后台,则提示,此token已失效,请使用新token,不在返回新token,返回状态码:461
35
+     *
36
+     * @param jwtToken
37
+     * @param httpServletResponse
38
+     * @throws Exception
39
+     */
40
+    void refreshToken(JwtToken jwtToken, HttpServletResponse httpServletResponse) throws Exception;
41
+
42
+}

+ 115
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/shiro/service/impl/ShiroLoginServiceImpl.java Voir le fichier

@@ -0,0 +1,115 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.shiro.service.impl;
18
+
19
+import io.geekidea.springbootplus.config.constant.CommonConstant;
20
+import io.geekidea.springbootplus.config.properties.JwtProperties;
21
+import io.geekidea.springbootplus.config.properties.SpringBootPlusProperties;
22
+import io.geekidea.springbootplus.framework.shiro.cache.LoginRedisService;
23
+import io.geekidea.springbootplus.framework.shiro.jwt.JwtToken;
24
+import io.geekidea.springbootplus.framework.shiro.service.ShiroLoginService;
25
+import io.geekidea.springbootplus.framework.shiro.util.JwtTokenUtil;
26
+import io.geekidea.springbootplus.framework.shiro.util.JwtUtil;
27
+import lombok.extern.slf4j.Slf4j;
28
+import org.apache.commons.lang3.StringUtils;
29
+import org.apache.commons.lang3.time.DateUtils;
30
+import org.apache.shiro.authc.AuthenticationException;
31
+import org.springframework.beans.factory.annotation.Autowired;
32
+import org.springframework.context.annotation.Lazy;
33
+import org.springframework.data.redis.core.RedisTemplate;
34
+import org.springframework.stereotype.Service;
35
+
36
+import javax.servlet.http.HttpServletResponse;
37
+import java.time.Duration;
38
+import java.util.Date;
39
+
40
+/**
41
+ * Shiro登录服务
42
+ *
43
+ * @author geekidea
44
+ * @date 2020/3/24
45
+ **/
46
+@Slf4j
47
+@Service
48
+public class ShiroLoginServiceImpl implements ShiroLoginService {
49
+
50
+
51
+    @Lazy
52
+    @Autowired
53
+    private LoginRedisService loginRedisService;
54
+
55
+    @Lazy
56
+    @Autowired
57
+    private JwtProperties jwtProperties;
58
+
59
+    @Lazy
60
+    @Autowired
61
+    private SpringBootPlusProperties springBootPlusProperties;
62
+
63
+    @Lazy
64
+    @Autowired
65
+    private RedisTemplate redisTemplate;
66
+
67
+
68
+    @Override
69
+    public void refreshToken(JwtToken jwtToken, HttpServletResponse httpServletResponse) throws Exception {
70
+        if (jwtToken == null) {
71
+            return;
72
+        }
73
+        String token = jwtToken.getToken();
74
+        if (StringUtils.isBlank(token)) {
75
+            return;
76
+        }
77
+        // 判断是否刷新token
78
+        boolean isRefreshToken = jwtProperties.isRefreshToken();
79
+        if (!isRefreshToken) {
80
+            return;
81
+        }
82
+        // 获取过期时间
83
+        Date expireDate = JwtUtil.getExpireDate(token);
84
+        // 获取倒计时
85
+        Integer countdown = jwtProperties.getRefreshTokenCountdown();
86
+        // 如果(当前时间+倒计时) > 过期时间,则刷新token
87
+        boolean refresh = DateUtils.addSeconds(new Date(), countdown).after(expireDate);
88
+
89
+        if (!refresh) {
90
+            return;
91
+        }
92
+
93
+        // 如果token继续发往后台,则提示,此token已失效,请使用新token,不在返回新token,返回状态码:461
94
+        // 如果Redis缓存中没有,JwtToken没有过期,则说明,已经刷新token
95
+        boolean exists = loginRedisService.exists(token);
96
+        if (!exists) {
97
+            httpServletResponse.setStatus(CommonConstant.JWT_INVALID_TOKEN_CODE);
98
+            throw new AuthenticationException("token已无效,请使用已刷新的token");
99
+        }
100
+        String username = jwtToken.getUsername();
101
+        String salt = jwtToken.getSalt();
102
+        Long expireSecond = jwtProperties.getExpireSecond();
103
+        // 生成新token字符串
104
+        String newToken = JwtUtil.generateToken(username, salt, Duration.ofSeconds(expireSecond));
105
+        // 生成新JwtToken对象
106
+        JwtToken newJwtToken = JwtToken.build(newToken, username, salt, expireSecond);
107
+        // 更新redis缓存
108
+        loginRedisService.refreshLoginInfo(token, username, newJwtToken);
109
+        log.debug("刷新token成功,原token:{},新token:{}", token, newToken);
110
+        // 设置响应头
111
+        // 刷新token
112
+        httpServletResponse.setStatus(CommonConstant.JWT_REFRESH_TOKEN_CODE);
113
+        httpServletResponse.setHeader(JwtTokenUtil.getTokenName(), newToken);
114
+    }
115
+}

+ 81
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/shiro/util/JwtTokenUtil.java Voir le fichier

@@ -0,0 +1,81 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.shiro.util;
18
+
19
+import io.geekidea.springbootplus.config.properties.JwtProperties;
20
+import io.geekidea.springbootplus.framework.util.HttpServletRequestUtil;
21
+import lombok.extern.slf4j.Slf4j;
22
+import org.apache.commons.lang3.StringUtils;
23
+import org.springframework.stereotype.Component;
24
+
25
+import javax.servlet.http.HttpServletRequest;
26
+
27
+/**
28
+ * JwtToken工具类
29
+ *
30
+ * @author geekidea
31
+ * @date 2019-10-03
32
+ * @since 1.3.0.RELEASE
33
+ **/
34
+@Slf4j
35
+@Component
36
+public class JwtTokenUtil {
37
+
38
+    private static String tokenName;
39
+
40
+    public JwtTokenUtil(JwtProperties jwtProperties) {
41
+        tokenName = jwtProperties.getTokenName();
42
+        log.debug("tokenName:{}", tokenName);
43
+    }
44
+
45
+    /**
46
+     * 获取token名称
47
+     *
48
+     * @return
49
+     */
50
+    public static String getTokenName() {
51
+        return tokenName;
52
+    }
53
+
54
+    /**
55
+     * 从请求头或者请求参数中
56
+     *
57
+     * @return
58
+     */
59
+    public static String getToken() {
60
+        return getToken(HttpServletRequestUtil.getRequest());
61
+    }
62
+
63
+    /**
64
+     * 从请求头或者请求参数中
65
+     *
66
+     * @param request
67
+     * @return
68
+     */
69
+    public static String getToken(HttpServletRequest request) {
70
+        if (request == null) {
71
+            throw new IllegalArgumentException("request不能为空");
72
+        }
73
+        // 从请求头中获取token
74
+        String token = request.getHeader(tokenName);
75
+        if (StringUtils.isBlank(token)) {
76
+            // 从请求参数中获取token
77
+            token = request.getParameter(tokenName);
78
+        }
79
+        return token;
80
+    }
81
+}

+ 204
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/shiro/util/JwtUtil.java Voir le fichier

@@ -0,0 +1,204 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.shiro.util;
18
+
19
+import com.alibaba.fastjson.JSON;
20
+import com.auth0.jwt.JWT;
21
+import com.auth0.jwt.JWTVerifier;
22
+import com.auth0.jwt.algorithms.Algorithm;
23
+import com.auth0.jwt.interfaces.DecodedJWT;
24
+import io.geekidea.springbootplus.config.constant.CommonConstant;
25
+import io.geekidea.springbootplus.config.properties.JwtProperties;
26
+import io.geekidea.springbootplus.framework.util.UUIDUtil;
27
+import lombok.extern.slf4j.Slf4j;
28
+import org.apache.commons.lang3.StringUtils;
29
+import org.apache.commons.lang3.time.DateUtils;
30
+import org.springframework.stereotype.Component;
31
+
32
+import java.time.Duration;
33
+import java.util.Date;
34
+
35
+/**
36
+ * JWT工具类
37
+ * https://github.com/auth0/java-jwt
38
+ *
39
+ * @author geekidea
40
+ * @date 2019-09-30
41
+ * @since 1.3.0.RELEASE
42
+ **/
43
+@Slf4j
44
+@Component
45
+public class JwtUtil {
46
+
47
+    private static JwtProperties jwtProperties;
48
+
49
+    public JwtUtil(JwtProperties jwtProperties) {
50
+        JwtUtil.jwtProperties = jwtProperties;
51
+        log.info(JSON.toJSONString(JwtUtil.jwtProperties));
52
+    }
53
+
54
+    /**
55
+     * 生成JWT Token
56
+     *
57
+     * @param username       用户名
58
+     * @param salt           盐值
59
+     * @param expireDuration 过期时间和单位
60
+     * @return token
61
+     */
62
+    public static String generateToken(String username, String salt, Duration expireDuration) {
63
+        try {
64
+            if (StringUtils.isBlank(username)) {
65
+                log.error("username不能为空");
66
+                return null;
67
+            }
68
+            log.debug("username:{}", username);
69
+
70
+            // 如果盐值为空,则使用默认值:666666
71
+            if (StringUtils.isBlank(salt)) {
72
+                salt = jwtProperties.getSecret();
73
+            }
74
+            log.debug("salt:{}", salt);
75
+
76
+            // 过期时间,单位:秒
77
+            Long expireSecond;
78
+            // 默认过期时间为1小时
79
+            if (expireDuration == null) {
80
+                expireSecond = jwtProperties.getExpireSecond();
81
+            } else {
82
+                expireSecond = expireDuration.getSeconds();
83
+            }
84
+            log.debug("expireSecond:{}", expireSecond);
85
+            Date expireDate = DateUtils.addSeconds(new Date(), expireSecond.intValue());
86
+            log.debug("expireDate:{}", expireDate);
87
+
88
+            // 生成token
89
+            Algorithm algorithm = Algorithm.HMAC256(salt);
90
+            String token = JWT.create()
91
+                    .withClaim(CommonConstant.JWT_USERNAME, username)
92
+                    // jwt唯一id
93
+                    .withJWTId(UUIDUtil.getUuid())
94
+                    // 签发人
95
+                    .withIssuer(jwtProperties.getIssuer())
96
+                    // 主题
97
+                    .withSubject(jwtProperties.getSubject())
98
+                    // 签发的目标
99
+                    .withAudience(jwtProperties.getAudience())
100
+                    // 签名时间
101
+                    .withIssuedAt(new Date())
102
+                    // token过期时间
103
+                    .withExpiresAt(expireDate)
104
+                    // 签名
105
+                    .sign(algorithm);
106
+            return token;
107
+        } catch (Exception e) {
108
+            log.error("generateToken exception", e);
109
+        }
110
+        return null;
111
+    }
112
+
113
+    public static boolean verifyToken(String token, String salt) {
114
+        try {
115
+            Algorithm algorithm = Algorithm.HMAC256(salt);
116
+            JWTVerifier verifier = JWT.require(algorithm)
117
+                    // 签发人
118
+                    .withIssuer(jwtProperties.getIssuer())
119
+                    // 主题
120
+                    .withSubject(jwtProperties.getSubject())
121
+                    // 签发的目标
122
+                    .withAudience(jwtProperties.getAudience())
123
+                    .build();
124
+            DecodedJWT jwt = verifier.verify(token);
125
+            if (jwt != null) {
126
+                return true;
127
+            }
128
+        } catch (Exception e) {
129
+            log.error("Verify Token Exception", e);
130
+        }
131
+        return false;
132
+    }
133
+
134
+    /**
135
+     * 解析token,获取token数据
136
+     *
137
+     * @param token
138
+     * @return
139
+     */
140
+    public static DecodedJWT getJwtInfo(String token) {
141
+        return JWT.decode(token);
142
+    }
143
+
144
+    /**
145
+     * 获取用户名
146
+     *
147
+     * @param token
148
+     * @return
149
+     */
150
+    public static String getUsername(String token) {
151
+        if (StringUtils.isBlank(token)){
152
+            return null;
153
+        }
154
+        DecodedJWT decodedJwt = getJwtInfo(token);
155
+        if (decodedJwt == null) {
156
+            return null;
157
+        }
158
+        String username = decodedJwt.getClaim(CommonConstant.JWT_USERNAME).asString();
159
+        return username;
160
+    }
161
+
162
+    /**
163
+     * 获取创建时间
164
+     *
165
+     * @param token
166
+     * @return
167
+     */
168
+    public static Date getIssuedAt(String token) {
169
+        DecodedJWT decodedJwt = getJwtInfo(token);
170
+        if (decodedJwt == null) {
171
+            return null;
172
+        }
173
+        return decodedJwt.getIssuedAt();
174
+    }
175
+
176
+    /**
177
+     * 获取过期时间
178
+     *
179
+     * @param token
180
+     * @return
181
+     */
182
+    public static Date getExpireDate(String token) {
183
+        DecodedJWT decodedJwt = getJwtInfo(token);
184
+        if (decodedJwt == null) {
185
+            return null;
186
+        }
187
+        return decodedJwt.getExpiresAt();
188
+    }
189
+
190
+    /**
191
+     * 判断token是否已过期
192
+     *
193
+     * @param token
194
+     * @return
195
+     */
196
+    public static boolean isExpired(String token) {
197
+        Date expireDate = getExpireDate(token);
198
+        if (expireDate == null) {
199
+            return true;
200
+        }
201
+        return expireDate.before(new Date());
202
+    }
203
+
204
+}

+ 77
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/shiro/util/SaltUtil.java Voir le fichier

@@ -0,0 +1,77 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.shiro.util;
18
+
19
+import io.geekidea.springbootplus.config.properties.JwtProperties;
20
+import org.apache.commons.codec.digest.DigestUtils;
21
+import org.apache.commons.lang3.StringUtils;
22
+import org.apache.shiro.crypto.SecureRandomNumberGenerator;
23
+
24
+/**
25
+ * 盐值包装工具类
26
+ *
27
+ * @author geekidea
28
+ * @date 2019-09-30
29
+ * @since 1.3.0.RELEASE
30
+ **/
31
+public class SaltUtil {
32
+
33
+    /**
34
+     * 盐值包装
35
+     *
36
+     * @param secret 配置文件中配置的附加盐值
37
+     * @param salt   数据库中保存的盐值
38
+     * @return
39
+     */
40
+    public static String getSalt(String secret, String salt) {
41
+        if (StringUtils.isBlank(secret) && StringUtils.isBlank(salt)) {
42
+            return null;
43
+        }
44
+        // 加密方法
45
+        String newSalt = DigestUtils.sha256Hex(secret + salt);
46
+        return newSalt;
47
+    }
48
+
49
+    /**
50
+     * 生成32位随机盐
51
+     *
52
+     * @return
53
+     */
54
+    public static String generateSalt() {
55
+        return new SecureRandomNumberGenerator().nextBytes(16).toHex();
56
+    }
57
+
58
+    /**
59
+     * 加工盐值
60
+     *
61
+     * @param salt
62
+     * @param jwtProperties
63
+     * @return
64
+     */
65
+    public static String getSalt(String salt, JwtProperties jwtProperties) {
66
+        String newSalt;
67
+        if (jwtProperties.isSaltCheck()) {
68
+            // 包装盐值
69
+            newSalt = SaltUtil.getSalt(jwtProperties.getSecret(), salt);
70
+        } else {
71
+            newSalt = jwtProperties.getSecret();
72
+        }
73
+        return newSalt;
74
+    }
75
+
76
+}
77
+

+ 64
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/shiro/vo/JwtTokenRedisVo.java Voir le fichier

@@ -0,0 +1,64 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.shiro.vo;
18
+
19
+import lombok.Data;
20
+import lombok.experimental.Accessors;
21
+
22
+import java.io.Serializable;
23
+import java.util.Date;
24
+
25
+/**
26
+ * JwtToken Redis缓存对象
27
+ *
28
+ * @author geekidea
29
+ * @date 2019-09-30
30
+ **/
31
+@Data
32
+@Accessors(chain = true)
33
+public class JwtTokenRedisVo implements Serializable {
34
+    private static final long serialVersionUID = 1831633309466775223L;
35
+    /**
36
+     * 登录ip
37
+     */
38
+    private String host;
39
+    /**
40
+     * 登录用户名称
41
+     */
42
+    private String username;
43
+    /**
44
+     * 登录盐值
45
+     */
46
+    private String salt;
47
+    /**
48
+     * 登录token
49
+     */
50
+    private String token;
51
+    /**
52
+     * 创建时间
53
+     */
54
+    private Date createDate;
55
+    /**
56
+     * 多长时间过期,默认一小时
57
+     */
58
+    private long expireSecond;
59
+    /**
60
+     * 过期日期
61
+     */
62
+    private Date expireDate;
63
+
64
+}

+ 47
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/shiro/vo/LoginSysUserRedisVo.java Voir le fichier

@@ -0,0 +1,47 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.shiro.vo;
18
+
19
+import io.geekidea.springbootplus.framework.common.bean.ClientInfo;
20
+import lombok.Data;
21
+import lombok.EqualsAndHashCode;
22
+import lombok.experimental.Accessors;
23
+
24
+/**
25
+ * 登录用户Redis对象,后台使用
26
+ *
27
+ * @author geekidea
28
+ * @date 2019-9-30
29
+ **/
30
+@Data
31
+@Accessors(chain = true)
32
+@EqualsAndHashCode(callSuper = false)
33
+public class LoginSysUserRedisVo extends LoginSysUserVo {
34
+
35
+    private static final long serialVersionUID = -3858850188055605806L;
36
+
37
+    /**
38
+     * 包装后的盐值
39
+     */
40
+    private String salt;
41
+
42
+    /**
43
+     * 登录ip
44
+     */
45
+    private ClientInfo clientInfo;
46
+
47
+}

+ 73
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/shiro/vo/LoginSysUserVo.java Voir le fichier

@@ -0,0 +1,73 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.shiro.vo;
18
+
19
+import io.swagger.annotations.ApiModelProperty;
20
+import lombok.Data;
21
+import lombok.experimental.Accessors;
22
+
23
+import java.io.Serializable;
24
+import java.util.Set;
25
+
26
+/**
27
+ * <p>
28
+ * 登录用户对象,响应给前端
29
+ * </p>
30
+ *
31
+ * @author geekidea
32
+ * @date 2019-05-15
33
+ **/
34
+@Data
35
+@Accessors(chain = true)
36
+public class LoginSysUserVo implements Serializable {
37
+
38
+    private static final long serialVersionUID = -1758338570596088158L;
39
+
40
+    @ApiModelProperty("主键")
41
+    private Long id;
42
+
43
+    @ApiModelProperty("用户名")
44
+    private String username;
45
+
46
+    @ApiModelProperty("昵称")
47
+    private String nickname;
48
+
49
+    @ApiModelProperty("性别,0:女,1:男,默认1")
50
+    private Integer gender;
51
+
52
+    @ApiModelProperty("状态,0:禁用,1:启用,2:锁定")
53
+    private Integer state;
54
+
55
+    @ApiModelProperty("部门id")
56
+    private Long departmentId;
57
+
58
+    @ApiModelProperty("部门名称")
59
+    private String departmentName;
60
+
61
+    @ApiModelProperty("角色id")
62
+    private Long roleId;
63
+
64
+    @ApiModelProperty("角色名称")
65
+    private String roleName;
66
+
67
+    @ApiModelProperty("角色编码")
68
+    private String roleCode;
69
+
70
+    @ApiModelProperty("权限编码列表")
71
+    private Set<String> permissionCodes;
72
+
73
+}

+ 58
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/util/AnsiUtil.java Voir le fichier

@@ -0,0 +1,58 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.util;
18
+
19
+import lombok.extern.slf4j.Slf4j;
20
+import org.fusesource.jansi.Ansi;
21
+import org.springframework.core.env.Environment;
22
+
23
+/**
24
+ * @author geekidea
25
+ * @date 2018-11-08
26
+ */
27
+@Slf4j
28
+public class AnsiUtil {
29
+
30
+    private static boolean enableAnsi;
31
+
32
+    static {
33
+        Boolean value = false;
34
+        try {
35
+            Environment environment = SpringContextUtil.getBean(Environment.class);
36
+            value = environment.getProperty("spring-boot-plus.enable-ansi",boolean.class);
37
+            value = value == null ? false : value;
38
+        } catch (Exception e) {
39
+            e.printStackTrace();
40
+        }
41
+        enableAnsi = value;
42
+    }
43
+
44
+    public static String getAnsi(Ansi.Color color,String text){
45
+
46
+        if (enableAnsi){
47
+            return Ansi.ansi().eraseScreen().fg(color).a(text).reset().toString();
48
+        }
49
+        return text;
50
+    }
51
+
52
+    public static String getAnsi(Ansi.Color color,String text,boolean flag){
53
+        if (flag){
54
+            return Ansi.ansi().eraseScreen().fg(color).a(text).reset().toString();
55
+        }
56
+        return text;
57
+    }
58
+}

+ 151
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/util/BaseEnumUtil.java Voir le fichier

@@ -0,0 +1,151 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.util;
18
+
19
+import io.geekidea.springbootplus.framework.common.enums.BaseEnum;
20
+import io.geekidea.springbootplus.framework.common.vo.EnumVo;
21
+import org.apache.commons.collections4.MapUtils;
22
+
23
+import java.util.Collection;
24
+import java.util.LinkedHashMap;
25
+import java.util.Map;
26
+import java.util.Set;
27
+
28
+/**
29
+ * BaseEnum枚举工具类
30
+ *
31
+ * @author geekidea
32
+ * @date 2018-11-08
33
+ */
34
+public class BaseEnumUtil {
35
+
36
+    private static final Map<String, Map<Integer, EnumVo<? extends BaseEnum>>> ENUM_MAP = new LinkedHashMap<>();
37
+
38
+    /**
39
+     * 通过code获取描述
40
+     *
41
+     * @param baseEnumType
42
+     * @param code
43
+     * @return
44
+     */
45
+    public static BaseEnum getEnum(Class<? extends BaseEnum> baseEnumType, Integer code) {
46
+        EnumVo<? extends BaseEnum> enumVo = getEnumVo(baseEnumType, code);
47
+        if (enumVo == null) {
48
+            return null;
49
+        }
50
+        return enumVo.getBaseEnum();
51
+    }
52
+
53
+    /**
54
+     * 通过code获取描述
55
+     *
56
+     * @param baseEnumType
57
+     * @param code
58
+     * @return
59
+     */
60
+    public static EnumVo<? extends BaseEnum> getEnumVo(Class<? extends BaseEnum> baseEnumType, Integer code) {
61
+        Map<Integer, EnumVo<? extends BaseEnum>> map = getMap(baseEnumType);
62
+        if (MapUtils.isEmpty(map)) {
63
+            return null;
64
+        }
65
+        return map.get(code);
66
+    }
67
+
68
+    /**
69
+     * 判断code在枚举中是否存在
70
+     *
71
+     * @param baseEnumType
72
+     * @param code
73
+     * @return
74
+     */
75
+    public static boolean exists(Class<? extends BaseEnum> baseEnumType, Integer code) {
76
+        EnumVo<? extends BaseEnum> enumVo = getEnumVo(baseEnumType, code);
77
+        if (enumVo == null) {
78
+            return false;
79
+        }
80
+        return true;
81
+    }
82
+
83
+    /**
84
+     * 判断code在枚举中是否不存在
85
+     *
86
+     * @param baseEnumType
87
+     * @param code
88
+     * @return
89
+     */
90
+    public static boolean notExists(Class<? extends BaseEnum> baseEnumType, Integer code) {
91
+        return !exists(baseEnumType, code);
92
+    }
93
+
94
+    /**
95
+     * 通过code获取描述
96
+     *
97
+     * @param baseEnumType
98
+     * @param code
99
+     * @return
100
+     */
101
+    public static String getDesc(Class<? extends BaseEnum> baseEnumType, Integer code) {
102
+        EnumVo<? extends BaseEnum> enumVo = getEnumVo(baseEnumType, code);
103
+        if (enumVo == null) {
104
+            return null;
105
+        }
106
+        return enumVo.getDesc();
107
+    }
108
+
109
+    /**
110
+     * 通过类型获取枚举Map
111
+     *
112
+     * @param baseEnumType
113
+     * @return
114
+     */
115
+    public static Map<Integer, EnumVo<? extends BaseEnum>> getMap(Class<? extends BaseEnum> baseEnumType) {
116
+        return ENUM_MAP.get(baseEnumType.getName());
117
+    }
118
+
119
+    /**
120
+     * 通过类型获取枚举code集合
121
+     *
122
+     * @param baseEnumType
123
+     * @return
124
+     */
125
+    public static Set<Integer> getCodeSet(Class<? extends BaseEnum> baseEnumType) {
126
+        Map<Integer, EnumVo<? extends BaseEnum>> map = getMap(baseEnumType);
127
+        if (MapUtils.isEmpty(map)) {
128
+            return null;
129
+        }
130
+        return map.keySet();
131
+    }
132
+
133
+    /**
134
+     * 通过类型获取枚举desc集合
135
+     *
136
+     * @param baseEnumType
137
+     * @return
138
+     */
139
+    public static Collection<EnumVo<? extends BaseEnum>> getDescList(Class<? extends BaseEnum> baseEnumType) {
140
+        Map<Integer, EnumVo<? extends BaseEnum>> map = getMap(baseEnumType);
141
+        if (MapUtils.isEmpty(map)) {
142
+            return null;
143
+        }
144
+        return map.values();
145
+    }
146
+
147
+    public static Map<String, Map<Integer, EnumVo<? extends BaseEnum>>> getEnumMap() {
148
+        return ENUM_MAP;
149
+    }
150
+
151
+}

+ 89
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/util/BrowserUtil.java Voir le fichier

@@ -0,0 +1,89 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.util;
18
+
19
+import javax.servlet.http.HttpServletRequest;
20
+
21
+/**
22
+ * <code>
23
+ * 浏览器工具类<br/>
24
+ * 1.获取当前浏览器名称
25
+ * 2.判断当前用户的浏览器
26
+ * </code>
27
+ *
28
+ * @author geekidea
29
+ * @since 2018-11-08
30
+ */
31
+public final class BrowserUtil {
32
+    public static final String IE = "msie";
33
+    public static final String FIREFOX = "firefox";
34
+    public static final String CHROME = "chrome";
35
+
36
+    private BrowserUtil() {
37
+        throw new AssertionError();
38
+    }
39
+
40
+    /**
41
+     * 获取当前浏览器名称
42
+     *
43
+     * @param request
44
+     * @return 返回浏览器名称
45
+     */
46
+    public static String getCurrent(HttpServletRequest request) {
47
+        String userAgent = request.getHeader("USER-AGENT").toLowerCase();
48
+        if (userAgent != null && !("".equals(userAgent.trim()))) {
49
+            if (userAgent.indexOf(CHROME) >= 0) {
50
+                return CHROME;
51
+            } else if (userAgent.indexOf(FIREFOX) >= 0) {
52
+                return FIREFOX;
53
+            } else if (userAgent.indexOf(IE) >= 0) {
54
+                return IE;
55
+            }
56
+        }
57
+        return null;
58
+    }
59
+
60
+    /**
61
+     * 是否是IE浏览器
62
+     *
63
+     * @param request
64
+     * @return
65
+     */
66
+    public static boolean isIe(HttpServletRequest request) {
67
+        return IE.equals(getCurrent(request));
68
+    }
69
+
70
+    /**
71
+     * 是否是Firefox浏览器
72
+     *
73
+     * @param request
74
+     * @return
75
+     */
76
+    public static boolean isFirefox(HttpServletRequest request) {
77
+        return FIREFOX.equals(getCurrent(request));
78
+    }
79
+
80
+    /**
81
+     * 是否是Chrome浏览器
82
+     *
83
+     * @param request
84
+     * @return
85
+     */
86
+    public static boolean isChrome(HttpServletRequest request) {
87
+        return CHROME.equals(getCurrent(request));
88
+    }
89
+}

+ 120
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/util/ClientInfoUtil.java Voir le fichier

@@ -0,0 +1,120 @@
1
+/*
2
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package io.geekidea.springbootplus.framework.util;
18
+
19
+import cn.hutool.http.useragent.UserAgent;
20
+import cn.hutool.http.useragent.UserAgentUtil;
21
+import io.geekidea.springbootplus.config.constant.CommonConstant;
22
+import io.geekidea.springbootplus.framework.common.bean.ClientInfo;
23
+import io.geekidea.springbootplus.framework.common.bean.DeviceInfo;
24
+
25
+import javax.servlet.http.HttpServletRequest;
26
+import java.util.regex.Matcher;
27
+import java.util.regex.Pattern;
28
+
29
+/**
30
+ * <p>
31
+ *  用户客户端信息工具类
32
+ * </p>
33
+ * @author geekidea
34
+ * @date 2019-05-24
35
+ **/
36
+public class ClientInfoUtil {
37
+
38
+    private static final Pattern DEVICE_INFO_PATTERN = Pattern.compile(";\\s?(\\S*?\\s?\\S*?)\\s?Build/(\\S*?)[;)]");
39
+    private static final Pattern DEVICE_INFO_PATTERN_1 = Pattern.compile(";\\s?(\\S*?\\s?\\S*?)\\s?\\)");
40
+
41
+    /**
42
+     * 获取用户客户端信息
43
+     * @param request
44
+     * @return
45
+     */
46
+    public static ClientInfo get(HttpServletRequest request){
47
+        String userAgent = request.getHeader(CommonConstant.USER_AGENT);
48
+        return get(userAgent);
49
+    }
50
+
51
+    /**
52
+     * 获取用户客户端信息
53
+     * @param userAgentString
54
+     * @return
55
+     */
56
+    public static ClientInfo get(String userAgentString){
57
+        ClientInfo clientInfo = new ClientInfo();
58
+
59
+        UserAgent userAgent = UserAgentUtil.parse(userAgentString);
60
+
61
+        // 浏览器名称
62
+        clientInfo.setBrowserName(userAgent.getBrowser().getName());
63
+        // 浏览器版本
64
+        clientInfo.setBrowserversion(userAgent.getVersion());
65
+        // 浏览器引擎名称
66
+        clientInfo.setEngineName(userAgent.getEngine().getName());
67
+        // 浏览器引擎版本
68
+        clientInfo.setEngineVersion(userAgent.getEngineVersion());
69
+        // 用户操作系统名称
70
+        clientInfo.setOsName(userAgent.getOs().getName());
71
+        // 用户操作平台名称
72
+        clientInfo.setPlatformName(userAgent.getPlatform().getName());
73
+        // 是否是手机
74
+        clientInfo.setMobile(userAgent.isMobile());
75
+
76
+        // 获取移动设备名称和机型
77
+        DeviceInfo deviceInfo = getDeviceInfo(userAgentString);
78
+        // 设置移动设备名称和机型
79
+        clientInfo.setDeviceName(deviceInfo.getName());
80
+        clientInfo.setDeviceModel(deviceInfo.getModel());
81
+
82
+        // ip
83
+        clientInfo.setIp(IpUtil.getRequestIp());
84
+
85
+        return clientInfo;
86
+    }
87
+
88
+    /**
89
+     * 获取移动端用户设备的名称和机型
90
+     * @param userAgentString
91
+     * @return
92
+     */
93
+    public static DeviceInfo getDeviceInfo(String userAgentString){
94
+        DeviceInfo deviceInfo = new DeviceInfo();
95
+        try {
96
+
97
+            Matcher matcher = DEVICE_INFO_PATTERN.matcher(userAgentString);
98
+            String model = null;
99
+            String name = null;
100
+
101
+            if (matcher.find()) {
102
+                model = matcher.group(1);
103
+                name = matcher.group(2);
104
+            }
105
+
106
+            if (model == null && name == null){
107
+                matcher = DEVICE_INFO_PATTERN_1.matcher(userAgentString);
108
+                if (matcher.find()) {
109
+                    model = matcher.group(1);
110
+                }
111
+            }
112
+           
113
+            deviceInfo.setName(name);
114
+            deviceInfo.setModel(model);
115
+        } catch (Exception e) {
116
+            e.printStackTrace();
117
+        }
118
+        return deviceInfo;
119
+    }
120
+}

+ 0
- 0
framework/src/main/java/io/geekidea/springbootplus/framework/util/ContentTypeUtil.java Voir le fichier


Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff