keys(final String pattern) {
253 | return redisTemplate.keys(pattern);
254 | }
255 | }
256 |
--------------------------------------------------------------------------------
/common/src/main/java/com/rosy/common/utils/SqlUtils.java:
--------------------------------------------------------------------------------
1 | package com.rosy.common.utils;
2 |
3 | /**
4 | * SQL 工具
5 | *
6 | * 校验排序字段是否合法(防止 SQL 注入)
7 | */
8 | public class SqlUtils {
9 |
10 | /**
11 | * 校验排序字段是否合法(防止 SQL 注入)
12 | */
13 | public static boolean validSortField(String sortField) {
14 | if (StringUtils.isBlank(sortField)) {
15 | return false;
16 | }
17 | return !StringUtils.containsAny(sortField, "=", "(", ")", " ");
18 | }
19 | }
--------------------------------------------------------------------------------
/common/src/main/java/com/rosy/common/utils/StringUtils.java:
--------------------------------------------------------------------------------
1 | package com.rosy.common.utils;
2 |
3 | import cn.hutool.core.text.AntPathMatcher;
4 | import cn.hutool.core.text.StrFormatter;
5 |
6 | import java.util.*;
7 |
8 | public class StringUtils extends org.apache.commons.lang3.StringUtils {
9 | /**
10 | * 空字符串
11 | */
12 | private static final String NULLSTR = "";
13 |
14 | /**
15 | * 下划线
16 | */
17 | private static final char SEPARATOR = '_';
18 |
19 | /**
20 | * 星号
21 | */
22 | private static final char ASTERISK = '*';
23 |
24 | /**
25 | * 获取参数不为空值
26 | *
27 | * @param value defaultValue 要判断的value
28 | * @return value 返回值
29 | */
30 | public static T nvl(T value, T defaultValue) {
31 | return value != null ? value : defaultValue;
32 | }
33 |
34 | /**
35 | * * 判断一个Collection是否为空, 包含List,Set,Queue
36 | *
37 | * @param coll 要判断的Collection
38 | * @return true:为空 false:非空
39 | */
40 | public static boolean isEmpty(Collection> coll) {
41 | return isNull(coll) || coll.isEmpty();
42 | }
43 |
44 | /**
45 | * * 判断一个Collection是否非空,包含List,Set,Queue
46 | *
47 | * @param coll 要判断的Collection
48 | * @return true:非空 false:空
49 | */
50 | public static boolean isNotEmpty(Collection> coll) {
51 | return !isEmpty(coll);
52 | }
53 |
54 | /**
55 | * * 判断一个对象数组是否为空
56 | *
57 | * @param objects 要判断的对象数组
58 | * * @return true:为空 false:非空
59 | */
60 | public static boolean isEmpty(Object[] objects) {
61 | return isNull(objects) || (objects.length == 0);
62 | }
63 |
64 | /**
65 | * * 判断一个对象数组是否非空
66 | *
67 | * @param objects 要判断的对象数组
68 | * @return true:非空 false:空
69 | */
70 | public static boolean isNotEmpty(Object[] objects) {
71 | return !isEmpty(objects);
72 | }
73 |
74 | /**
75 | * * 判断一个Map是否为空
76 | *
77 | * @param map 要判断的Map
78 | * @return true:为空 false:非空
79 | */
80 | public static boolean isEmpty(Map, ?> map) {
81 | return isNull(map) || map.isEmpty();
82 | }
83 |
84 | /**
85 | * * 判断一个Map是否为空
86 | *
87 | * @param map 要判断的Map
88 | * @return true:非空 false:空
89 | */
90 | public static boolean isNotEmpty(Map, ?> map) {
91 | return !isEmpty(map);
92 | }
93 |
94 | /**
95 | * * 判断一个字符串是否为空串
96 | *
97 | * @param str String
98 | * @return true:为空 false:非空
99 | */
100 | public static boolean isEmpty(String str) {
101 | return isNull(str) || NULLSTR.equals(str.trim());
102 | }
103 |
104 | /**
105 | * * 判断一个字符串是否为非空串
106 | *
107 | * @param str String
108 | * @return true:非空串 false:空串
109 | */
110 | public static boolean isNotEmpty(String str) {
111 | return !isEmpty(str);
112 | }
113 |
114 | /**
115 | * * 判断一个对象是否为空
116 | *
117 | * @param object Object
118 | * @return true:为空 false:非空
119 | */
120 | public static boolean isNull(Object object) {
121 | return object == null;
122 | }
123 |
124 | /**
125 | * * 判断一个对象是否非空
126 | *
127 | * @param object Object
128 | * @return true:非空 false:空
129 | */
130 | public static boolean isNotNull(Object object) {
131 | return !isNull(object);
132 | }
133 |
134 | /**
135 | * * 判断一个对象是否是数组类型(Java基本型别的数组)
136 | *
137 | * @param object 对象
138 | * @return true:是数组 false:不是数组
139 | */
140 | public static boolean isArray(Object object) {
141 | return isNotNull(object) && object.getClass().isArray();
142 | }
143 |
144 | /**
145 | * 去空格
146 | */
147 | public static String trim(String str) {
148 | return (str == null ? "" : str.trim());
149 | }
150 |
151 | /**
152 | * 替换指定字符串的指定区间内字符为"*"
153 | *
154 | * @param str 字符串
155 | * @param startInclude 开始位置(包含)
156 | * @param endExclude 结束位置(不包含)
157 | * @return 替换后的字符串
158 | */
159 | public static String hide(CharSequence str, int startInclude, int endExclude) {
160 | if (isEmpty(str)) {
161 | return NULLSTR;
162 | }
163 | final int strLength = str.length();
164 | if (startInclude > strLength) {
165 | return NULLSTR;
166 | }
167 | if (endExclude > strLength) {
168 | endExclude = strLength;
169 | }
170 | if (startInclude > endExclude) {
171 | // 如果起始位置大于结束位置,不替换
172 | return NULLSTR;
173 | }
174 | final char[] chars = new char[strLength];
175 | for (int i = 0; i < strLength; i++) {
176 | if (i >= startInclude && i < endExclude) {
177 | chars[i] = ASTERISK;
178 | } else {
179 | chars[i] = str.charAt(i);
180 | }
181 | }
182 | return new String(chars);
183 | }
184 |
185 | /**
186 | * 截取字符串
187 | *
188 | * @param str 字符串
189 | * @param start 开始
190 | * @return 结果
191 | */
192 | public static String substring(final String str, int start) {
193 | if (str == null) {
194 | return NULLSTR;
195 | }
196 |
197 | if (start < 0) {
198 | start = str.length() + start;
199 | }
200 |
201 | if (start < 0) {
202 | start = 0;
203 | }
204 | if (start > str.length()) {
205 | return NULLSTR;
206 | }
207 |
208 | return str.substring(start);
209 | }
210 |
211 | /**
212 | * 截取字符串
213 | *
214 | * @param str 字符串
215 | * @param start 开始
216 | * @param end 结束
217 | * @return 结果
218 | */
219 | public static String substring(final String str, int start, int end) {
220 | if (str == null) {
221 | return NULLSTR;
222 | }
223 |
224 | if (end < 0) {
225 | end = str.length() + end;
226 | }
227 | if (start < 0) {
228 | start = str.length() + start;
229 | }
230 |
231 | if (end > str.length()) {
232 | end = str.length();
233 | }
234 |
235 | if (start > end) {
236 | return NULLSTR;
237 | }
238 |
239 | if (start < 0) {
240 | start = 0;
241 | }
242 | if (end < 0) {
243 | end = 0;
244 | }
245 |
246 | return str.substring(start, end);
247 | }
248 |
249 | /**
250 | * 判断是否为空,并且不是空白字符
251 | *
252 | * @param str 要判断的value
253 | * @return 结果
254 | */
255 | public static boolean hasText(String str) {
256 | return (str != null && !str.isEmpty() && containsText(str));
257 | }
258 |
259 | private static boolean containsText(CharSequence str) {
260 | int strLen = str.length();
261 | for (int i = 0; i < strLen; i++) {
262 | if (!Character.isWhitespace(str.charAt(i))) {
263 | return true;
264 | }
265 | }
266 | return false;
267 | }
268 |
269 | /**
270 | * 格式化文本, {} 表示占位符
271 | * 此方法只是简单将占位符 {} 按照顺序替换为参数
272 | * 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可
273 | * 例:
274 | * 通常使用:format("this is {} for {}", "a", "b") -> this is a for b
275 | * 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a
276 | * 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b
277 | *
278 | * @param template 文本模板,被替换的部分用 {} 表示
279 | * @param params 参数值
280 | * @return 格式化后的文本
281 | */
282 | public static String format(String template, Object... params) {
283 | if (isEmpty(params) || isEmpty(template)) {
284 | return template;
285 | }
286 | return StrFormatter.format(template, params);
287 | }
288 |
289 | /**
290 | * 是否为http(s)://开头
291 | *
292 | * @param link 链接
293 | * @return 结果
294 | */
295 | public static boolean ishttp(String link) {
296 | return StringUtils.startsWithAny(link, "http://", "https://");
297 | }
298 |
299 | /**
300 | * 字符串转set
301 | *
302 | * @param str 字符串
303 | * @param sep 分隔符
304 | * @return set集合
305 | */
306 | public static final Set str2Set(String str, String sep) {
307 | return new HashSet(str2List(str, sep, true, false));
308 | }
309 |
310 | /**
311 | * 字符串转list
312 | *
313 | * @param str 字符串
314 | * @param sep 分隔符
315 | * @param filterBlank 过滤纯空白
316 | * @param trim 去掉首尾空白
317 | * @return list集合
318 | */
319 | public static final List str2List(String str, String sep, boolean filterBlank, boolean trim) {
320 | List list = new ArrayList();
321 | if (StringUtils.isEmpty(str)) {
322 | return list;
323 | }
324 |
325 | // 过滤空白字符串
326 | if (filterBlank && StringUtils.isBlank(str)) {
327 | return list;
328 | }
329 | String[] split = str.split(sep);
330 | for (String string : split) {
331 | if (filterBlank && StringUtils.isBlank(string)) {
332 | continue;
333 | }
334 | if (trim) {
335 | string = string.trim();
336 | }
337 | list.add(string);
338 | }
339 |
340 | return list;
341 | }
342 |
343 | /**
344 | * 判断给定的collection列表中是否包含数组array 判断给定的数组array中是否包含给定的元素value
345 | *
346 | * @param collection 给定的集合
347 | * @param array 给定的数组
348 | * @return boolean 结果
349 | */
350 | public static boolean containsAny(Collection collection, String... array) {
351 | if (isEmpty(collection) || isEmpty(array)) {
352 | return false;
353 | } else {
354 | for (String str : array) {
355 | if (collection.contains(str)) {
356 | return true;
357 | }
358 | }
359 | return false;
360 | }
361 | }
362 |
363 | /**
364 | * 查找指定字符串是否包含指定字符串列表中的任意一个字符串同时串忽略大小写
365 | *
366 | * @param cs 指定字符串
367 | * @param searchCharSequences 需要检查的字符串数组
368 | * @return 是否包含任意一个字符串
369 | */
370 | public static boolean containsAnyIgnoreCase(CharSequence cs, CharSequence... searchCharSequences) {
371 | if (isEmpty(cs) || isEmpty(searchCharSequences)) {
372 | return false;
373 | }
374 | for (CharSequence testStr : searchCharSequences) {
375 | if (containsIgnoreCase(cs, testStr)) {
376 | return true;
377 | }
378 | }
379 | return false;
380 | }
381 |
382 | /**
383 | * 驼峰转下划线命名
384 | */
385 | public static String toUnderScoreCase(String str) {
386 | if (str == null) {
387 | return null;
388 | }
389 | StringBuilder sb = new StringBuilder();
390 | // 前置字符是否大写
391 | boolean preCharIsUpperCase = true;
392 | // 当前字符是否大写
393 | boolean curreCharIsUpperCase = true;
394 | // 下一字符是否大写
395 | boolean nexteCharIsUpperCase = true;
396 | for (int i = 0; i < str.length(); i++) {
397 | char c = str.charAt(i);
398 | if (i > 0) {
399 | preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));
400 | } else {
401 | preCharIsUpperCase = false;
402 | }
403 |
404 | curreCharIsUpperCase = Character.isUpperCase(c);
405 |
406 | if (i < (str.length() - 1)) {
407 | nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));
408 | }
409 |
410 | if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase) {
411 | sb.append(SEPARATOR);
412 | } else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase) {
413 | sb.append(SEPARATOR);
414 | }
415 | sb.append(Character.toLowerCase(c));
416 | }
417 |
418 | return sb.toString();
419 | }
420 |
421 | /**
422 | * 是否包含字符串
423 | *
424 | * @param str 验证字符串
425 | * @param strs 字符串组
426 | * @return 包含返回true
427 | */
428 | public static boolean inStringIgnoreCase(String str, String... strs) {
429 | if (str != null && strs != null) {
430 | for (String s : strs) {
431 | if (str.equalsIgnoreCase(trim(s))) {
432 | return true;
433 | }
434 | }
435 | }
436 | return false;
437 | }
438 |
439 | /**
440 | * 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->HelloWorld
441 | *
442 | * @param name 转换前的下划线大写方式命名的字符串
443 | * @return 转换后的驼峰式命名的字符串
444 | */
445 | public static String convertToCamelCase(String name) {
446 | StringBuilder result = new StringBuilder();
447 | // 快速检查
448 | if (name == null || name.isEmpty()) {
449 | // 没必要转换
450 | return "";
451 | } else if (!name.contains("_")) {
452 | // 不含下划线,仅将首字母大写
453 | return name.substring(0, 1).toUpperCase() + name.substring(1);
454 | }
455 | // 用下划线将原始字符串分割
456 | String[] camels = name.split("_");
457 | for (String camel : camels) {
458 | // 跳过原始字符串中开头、结尾的下换线或双重下划线
459 | if (camel.isEmpty()) {
460 | continue;
461 | }
462 | // 首字母大写
463 | result.append(camel.substring(0, 1).toUpperCase());
464 | result.append(camel.substring(1).toLowerCase());
465 | }
466 | return result.toString();
467 | }
468 |
469 | /**
470 | * 驼峰式命名法
471 | * 例如:user_name->userName
472 | */
473 | public static String toCamelCase(String s) {
474 | if (s == null) {
475 | return null;
476 | }
477 | if (s.indexOf(SEPARATOR) == -1) {
478 | return s;
479 | }
480 | s = s.toLowerCase();
481 | StringBuilder sb = new StringBuilder(s.length());
482 | boolean upperCase = false;
483 | for (int i = 0; i < s.length(); i++) {
484 | char c = s.charAt(i);
485 |
486 | if (c == SEPARATOR) {
487 | upperCase = true;
488 | } else if (upperCase) {
489 | sb.append(Character.toUpperCase(c));
490 | upperCase = false;
491 | } else {
492 | sb.append(c);
493 | }
494 | }
495 | return sb.toString();
496 | }
497 |
498 | /**
499 | * 查找指定字符串是否匹配指定字符串列表中的任意一个字符串
500 | *
501 | * @param str 指定字符串
502 | * @param strs 需要检查的字符串数组
503 | * @return 是否匹配
504 | */
505 | public static boolean matches(String str, List strs) {
506 | if (isEmpty(str) || isEmpty(strs)) {
507 | return false;
508 | }
509 | for (String pattern : strs) {
510 | if (isMatch(pattern, str)) {
511 | return true;
512 | }
513 | }
514 | return false;
515 | }
516 |
517 | /**
518 | * 判断url是否与规则配置:
519 | * ? 表示单个字符;
520 | * * 表示一层路径内的任意字符串,不可跨层级;
521 | * ** 表示任意层路径;
522 | *
523 | * @param pattern 匹配规则
524 | * @param url 需要匹配的url
525 | * @return
526 | */
527 | public static boolean isMatch(String pattern, String url) {
528 | AntPathMatcher matcher = new AntPathMatcher();
529 | return matcher.match(pattern, url);
530 | }
531 |
532 | @SuppressWarnings("unchecked")
533 | public static T cast(Object obj) {
534 | return (T) obj;
535 | }
536 |
537 | /**
538 | * 数字左边补齐0,使之达到指定长度。注意,如果数字转换为字符串后,长度大于size,则只保留 最后size个字符。
539 | *
540 | * @param num 数字对象
541 | * @param size 字符串指定长度
542 | * @return 返回数字的字符串格式,该字符串为指定长度。
543 | */
544 | public static final String padl(final Number num, final int size) {
545 | return padl(num.toString(), size, '0');
546 | }
547 |
548 | /**
549 | * 字符串左补齐。如果原始字符串s长度大于size,则只保留最后size个字符。
550 | *
551 | * @param s 原始字符串
552 | * @param size 字符串指定长度
553 | * @param c 用于补齐的字符
554 | * @return 返回指定长度的字符串,由原字符串左补齐或截取得到。
555 | */
556 | public static final String padl(final String s, final int size, final char c) {
557 | final StringBuilder sb = new StringBuilder(size);
558 | if (s != null) {
559 | final int len = s.length();
560 | if (s.length() <= size) {
561 | for (int i = size - len; i > 0; i--) {
562 | sb.append(c);
563 | }
564 | sb.append(s);
565 | } else {
566 | return s.substring(len - size, len);
567 | }
568 | } else {
569 | for (int i = size; i > 0; i--) {
570 | sb.append(c);
571 | }
572 | }
573 | return sb.toString();
574 | }
575 | }
--------------------------------------------------------------------------------
/common/src/main/java/com/rosy/common/utils/ThrowUtils.java:
--------------------------------------------------------------------------------
1 | package com.rosy.common.utils;
2 |
3 | import com.rosy.common.enums.ErrorCode;
4 | import com.rosy.common.exception.BusinessException;
5 |
6 | /**
7 | * 抛异常工具类
8 | */
9 | public class ThrowUtils {
10 |
11 | /**
12 | * 条件成立则抛异常
13 | */
14 | public static void throwIf(boolean condition, RuntimeException runtimeException) {
15 | if (condition) {
16 | throw runtimeException;
17 | }
18 | }
19 |
20 | /**
21 | * 条件成立则抛异常
22 | */
23 | public static void throwIf(boolean condition, ErrorCode errorCode) {
24 | throwIf(condition, new BusinessException(errorCode));
25 | }
26 |
27 | /**
28 | * 条件成立则抛异常
29 | */
30 | public static void throwIf(boolean condition, ErrorCode errorCode, String message) {
31 | throwIf(condition, new BusinessException(errorCode, message));
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/framework/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 | com.rosy
6 | springboot3.4.x-init
7 | 0.0.1
8 |
9 |
10 | framework
11 |
12 | framework
13 |
14 |
15 |
16 | com.rosy
17 | main
18 |
19 |
20 |
21 | org.springframework.boot
22 | spring-boot-starter-security
23 |
24 |
25 |
26 | org.springframework.boot
27 | spring-boot-starter-aop
28 |
29 |
30 |
31 | org.springframework.boot
32 | spring-boot-starter-webflux
33 |
34 |
35 |
36 | org.springdoc
37 | springdoc-openapi-starter-webmvc-ui
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/framework/src/main/java/com/rosy/framework/aspect/LogAspect.java:
--------------------------------------------------------------------------------
1 | package com.rosy.framework.aspect;
2 |
3 | import jakarta.servlet.http.HttpServletRequest;
4 | import lombok.extern.slf4j.Slf4j;
5 | import org.aspectj.lang.ProceedingJoinPoint;
6 | import org.aspectj.lang.annotation.Around;
7 | import org.aspectj.lang.annotation.Aspect;
8 | import org.springframework.stereotype.Component;
9 | import org.springframework.util.StopWatch;
10 | import org.springframework.web.context.request.RequestAttributes;
11 | import org.springframework.web.context.request.RequestContextHolder;
12 | import org.springframework.web.context.request.ServletRequestAttributes;
13 |
14 | import java.util.Arrays;
15 | import java.util.UUID;
16 |
17 | @Aspect
18 | @Component
19 | @Slf4j
20 | public class LogAspect {
21 |
22 | /**
23 | * 拦截带有 @LogTag 注解的方法
24 | */
25 | @Around("@annotation(com.rosy.common.annotation.LogTag)")
26 | public Object doInterceptor(ProceedingJoinPoint point) throws Throwable {
27 | // 计时
28 | StopWatch stopWatch = new StopWatch();
29 | stopWatch.start();
30 | // 获取请求路径
31 | RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
32 | HttpServletRequest httpServletRequest = ((ServletRequestAttributes) requestAttributes).getRequest();
33 | // 生成请求唯一 id
34 | String requestId = UUID.randomUUID().toString();
35 | String url = httpServletRequest.getRequestURI();
36 | // 获取请求参数
37 | Object[] args = point.getArgs();
38 | String reqParam = "[" + String.join(", ", Arrays.stream(args).map(Object::toString).toArray(String[]::new)) + "]";
39 | // 输出请求日志
40 | log.info("request start,id: {}, path: {}, ip: {}, params: {}", requestId, url,
41 | httpServletRequest.getRemoteHost(), reqParam);
42 | // 执行原方法
43 | Object result = point.proceed();
44 | // 输出响应日志
45 | stopWatch.stop();
46 | long totalTimeMillis = stopWatch.getTotalTimeMillis();
47 | log.info("request end, id: {}, cost: {}ms", requestId, totalTimeMillis);
48 | return result;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/framework/src/main/java/com/rosy/framework/aspect/ValidationAspect.java:
--------------------------------------------------------------------------------
1 | package com.rosy.framework.aspect;
2 |
3 | import com.rosy.common.enums.ErrorCode;
4 | import com.rosy.common.exception.BusinessException;
5 | import org.aspectj.lang.ProceedingJoinPoint;
6 | import org.aspectj.lang.annotation.Around;
7 | import org.aspectj.lang.annotation.Aspect;
8 | import org.springframework.stereotype.Component;
9 |
10 | @Aspect
11 | @Component
12 | public class ValidationAspect {
13 | @Around("@annotation(com.rosy.common.annotation.ValidateRequest)")
14 | public Object validateRequest(ProceedingJoinPoint joinPoint) throws Throwable {
15 | for (Object arg : joinPoint.getArgs()) {
16 | if (arg == null) {
17 | throw new BusinessException(ErrorCode.PARAMS_ERROR);
18 | }
19 | }
20 | return joinPoint.proceed();
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/framework/src/main/java/com/rosy/framework/config/MybatisPlusConfig.java:
--------------------------------------------------------------------------------
1 | package com.rosy.framework.config;
2 |
3 | import com.baomidou.mybatisplus.annotation.DbType;
4 | import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
5 | import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
6 | import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
7 | import org.springframework.context.annotation.Bean;
8 | import org.springframework.context.annotation.Configuration;
9 |
10 | @Configuration
11 | public class MybatisPlusConfig {
12 | @Bean
13 | public MybatisPlusInterceptor mybatisPlusInterceptor() {
14 | MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
15 | interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); //乐观锁
16 | interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // 如果配置多个插件, 切记分页最后添加
17 | // 如果有多数据源可以不配具体类型, 否则都建议配上具体的 DbType
18 | return interceptor;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/framework/src/main/java/com/rosy/framework/config/OpenAPIConfig.java:
--------------------------------------------------------------------------------
1 | package com.rosy.framework.config;
2 |
3 | import io.swagger.v3.oas.models.OpenAPI;
4 | import io.swagger.v3.oas.models.info.Contact;
5 | import io.swagger.v3.oas.models.info.Info;
6 | import io.swagger.v3.oas.models.info.License;
7 | import org.springdoc.core.models.GroupedOpenApi;
8 | import org.springframework.context.annotation.Bean;
9 | import org.springframework.context.annotation.Configuration;
10 |
11 | @Configuration
12 | public class OpenAPIConfig {
13 |
14 | // 定制 OpenAPI 的基本信息
15 | @Bean
16 | public OpenAPI customOpenAPI() {
17 | return new OpenAPI()
18 | .info(new Info()
19 | .title("SpringBoot3.4.x-init")
20 | .description("一个简易的 SpringBoot 项目初始化模板——帮助开发者快速搭建项目")
21 | .version("1.0.0")
22 | .contact(new Contact()
23 | .name("Rosy")
24 | .email("2156722358@qq.com"))
25 | .license(new License()
26 | .name("Apache 2.0")
27 | .url("https://www.apache.org/licenses/LICENSE-2.0.html")));
28 | }
29 |
30 | // 配置 API 分组
31 | @Bean
32 | public GroupedOpenApi publicApi() {
33 | return GroupedOpenApi.builder()
34 | .group("public")
35 | .pathsToMatch("/**")
36 | .build();
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/framework/src/main/java/com/rosy/framework/config/RedisConfig.java:
--------------------------------------------------------------------------------
1 | package com.rosy.framework.config;
2 |
3 | import com.alibaba.fastjson2.JSON;
4 | import com.alibaba.fastjson2.JSONReader;
5 | import com.alibaba.fastjson2.JSONWriter;
6 | import com.alibaba.fastjson2.filter.Filter;
7 | import com.rosy.common.constant.CommonConstant;
8 | import org.springframework.cache.annotation.CachingConfigurer;
9 | import org.springframework.cache.annotation.EnableCaching;
10 | import org.springframework.context.annotation.Bean;
11 | import org.springframework.context.annotation.Configuration;
12 | import org.springframework.data.redis.connection.RedisConnectionFactory;
13 | import org.springframework.data.redis.core.RedisTemplate;
14 | import org.springframework.data.redis.core.script.DefaultRedisScript;
15 | import org.springframework.data.redis.serializer.RedisSerializer;
16 | import org.springframework.data.redis.serializer.SerializationException;
17 | import org.springframework.data.redis.serializer.StringRedisSerializer;
18 |
19 | import java.nio.charset.Charset;
20 | import java.nio.charset.StandardCharsets;
21 |
22 | @Configuration
23 | @EnableCaching
24 | public class RedisConfig implements CachingConfigurer {
25 | @Bean
26 | public RedisTemplate