├── .gitignore
├── LICENSE
├── README.md
├── pom.xml
└── src
├── main
├── java
│ └── xyz
│ │ └── snwjas
│ │ └── blog
│ │ ├── Application.java
│ │ ├── annotation
│ │ ├── AccessLimit.java
│ │ ├── ActionRecord.java
│ │ └── TimeCost.java
│ │ ├── aspect
│ │ ├── ActionRecordAspect.java
│ │ └── TimeCostAspect.java
│ │ ├── config
│ │ ├── AppStartConfig.java
│ │ ├── HibernateValidationConfig.java
│ │ ├── LocalDateTimeSerializerConfig.java
│ │ ├── MyBatisPlusConfig.java
│ │ ├── MyBlogConfig.java
│ │ ├── SwaggerConfig.java
│ │ ├── WebMvcConfig.java
│ │ ├── WebSecurityConfig.java
│ │ └── properties
│ │ │ └── MyBlogProperties.java
│ │ ├── constant
│ │ ├── CacheKeyPrefix.java
│ │ ├── MyBlogOptionEnum.java
│ │ ├── OptionEnum.java
│ │ ├── OtherOptionEnum.java
│ │ └── RS.java
│ │ ├── controller
│ │ ├── MainController.java
│ │ ├── admin
│ │ │ ├── AttachmentController.java
│ │ │ ├── BlogController.java
│ │ │ ├── CategoryController.java
│ │ │ ├── CommentController.java
│ │ │ ├── LinkController.java
│ │ │ ├── LogController.java
│ │ │ ├── OptionsController.java
│ │ │ ├── SpeciallistController.java
│ │ │ ├── StatisticsController.java
│ │ │ ├── TagController.java
│ │ │ └── UserController.java
│ │ └── app
│ │ │ ├── BlogController.java
│ │ │ ├── CategoryController.java
│ │ │ ├── CommentController.java
│ │ │ ├── IndexController.java
│ │ │ ├── LinkController.java
│ │ │ └── TagController.java
│ │ ├── exception
│ │ ├── MyBlogException.java
│ │ └── ServiceException.java
│ │ ├── handler
│ │ └── RestUnifiedExceptionHandler.java
│ │ ├── interceptor
│ │ ├── AccessLimitInterceptor.java
│ │ └── StatisticInterceptor.java
│ │ ├── mapper
│ │ ├── AttachmentMapper.java
│ │ ├── BlogMapper.java
│ │ ├── BlogTagMapper.java
│ │ ├── CategoryMapper.java
│ │ ├── CommentMapper.java
│ │ ├── LinkMapper.java
│ │ ├── LogMapper.java
│ │ ├── OptionsMapper.java
│ │ ├── SpecaillistMapper.java
│ │ ├── StatisticsMapper.java
│ │ ├── TagMapper.java
│ │ ├── UserMapper.java
│ │ └── xml
│ │ │ ├── AttachmentMapper.xml
│ │ │ ├── BlogMapper.xml
│ │ │ ├── BlogTagMapper.xml
│ │ │ ├── CategoryMapper.xml
│ │ │ ├── CommentMapper.xml
│ │ │ ├── LinkMapper.xml
│ │ │ ├── LogMapper.xml
│ │ │ ├── OptionsMapper.xml
│ │ │ ├── SpeciallistMapper.xml
│ │ │ ├── StatisticsMapper.xml
│ │ │ ├── TagMapper.xml
│ │ │ └── UserMapper.xml
│ │ ├── model
│ │ ├── PageResult.java
│ │ ├── R.java
│ │ ├── UserDetail.java
│ │ ├── base
│ │ │ ├── BeanConvert.java
│ │ │ └── ValidGroupType.java
│ │ ├── entity
│ │ │ ├── AttachmentEntity.java
│ │ │ ├── BaseEntity.java
│ │ │ ├── BlogEntity.java
│ │ │ ├── BlogTagEntity.java
│ │ │ ├── CategoryEntity.java
│ │ │ ├── CommentEntity.java
│ │ │ ├── LinkEntity.java
│ │ │ ├── LogEntity.java
│ │ │ ├── OptionsEntity.java
│ │ │ ├── SpeciallistEntity.java
│ │ │ ├── StatisticsEntity.java
│ │ │ ├── TagEntity.java
│ │ │ └── UserEntity.java
│ │ ├── enums
│ │ │ ├── BlogCommentAllowStatus.java
│ │ │ ├── BlogStatus.java
│ │ │ ├── CommentStatus.java
│ │ │ ├── LogType.java
│ │ │ ├── SpecialListType.java
│ │ │ └── ValueEnum.java
│ │ ├── params
│ │ │ ├── AttachmentSearchParam.java
│ │ │ ├── BasePageParam.java
│ │ │ ├── BlogSearchParam.java
│ │ │ ├── CommentSearchParam.java
│ │ │ ├── LinkSearchParam.java
│ │ │ ├── ListParam.java
│ │ │ ├── LogSearchParam.java
│ │ │ ├── SpeciallistSearchParam.java
│ │ │ └── UpdatePasswordParam.java
│ │ └── vo
│ │ │ ├── AttachmentVO.java
│ │ │ ├── BlogArchiveVO.java
│ │ │ ├── BlogDetailVO.java
│ │ │ ├── BlogSelectVO.java
│ │ │ ├── BlogSimpleVO.java
│ │ │ ├── CategoryVO.java
│ │ │ ├── CommentDetailVO.java
│ │ │ ├── CommentSimpleVO.java
│ │ │ ├── LinkVO.java
│ │ │ ├── LogVO.java
│ │ │ ├── OptionVO.java
│ │ │ ├── SpeciallistVO.java
│ │ │ ├── StatisticsBasicVO.java
│ │ │ ├── StatisticsReportVo.java
│ │ │ ├── TagVO.java
│ │ │ └── UserVO.java
│ │ ├── schedule
│ │ └── StatisticTask.java
│ │ ├── service
│ │ ├── AttachmentService.java
│ │ ├── BlogService.java
│ │ ├── CategoryService.java
│ │ ├── CommentService.java
│ │ ├── LinkService.java
│ │ ├── LogService.java
│ │ ├── OptionsService.java
│ │ ├── SpeciallistService.java
│ │ ├── StatisticsService.java
│ │ ├── TagService.java
│ │ ├── UserService.java
│ │ └── impl
│ │ │ ├── AttachmentServiceImpl.java
│ │ │ ├── BlogServiceImpl.java
│ │ │ ├── CategoryServiceImpl.java
│ │ │ ├── CommentServiceImpl.java
│ │ │ ├── LinkServiceImpl.java
│ │ │ ├── LogServiceImpl.java
│ │ │ ├── OptionsServiceImpl.java
│ │ │ ├── SpeciallistServiceImpl.java
│ │ │ ├── StatisticsServiceImpl.java
│ │ │ ├── TagServiceImpl.java
│ │ │ └── UserServiceImpl.java
│ │ ├── support
│ │ ├── cache
│ │ │ ├── CacheStore.java
│ │ │ ├── CacheWrapper.java
│ │ │ └── MemoryCacheStore.java
│ │ ├── security
│ │ │ ├── MyAuthenticationFailureHandler.java
│ │ │ ├── MyAuthenticationSuccessHandler.java
│ │ │ ├── MyLogoutSuccessHandler.java
│ │ │ └── MyUserDetailsService.java
│ │ └── wordfilter
│ │ │ ├── EndType.java
│ │ │ ├── FlagIndex.java
│ │ │ ├── WordContext.java
│ │ │ ├── WordFilter.java
│ │ │ └── WordType.java
│ │ └── utils
│ │ ├── ClassUtils.java
│ │ ├── CodeAutoGenerator.java
│ │ ├── DateUtils.java
│ │ ├── FileUtils.java
│ │ ├── IPUtils.java
│ │ ├── JsonUtils.java
│ │ ├── LambdaTypeUtils.java
│ │ ├── RUtils.java
│ │ ├── RWriterUtils.java
│ │ ├── StrUtils.java
│ │ └── URLUtils.java
└── resources
│ ├── admin
│ └── .gitkeep
│ ├── app
│ └── .gitkeep
│ ├── application-dev.yaml
│ ├── application-prod.yaml
│ ├── application.yaml
│ ├── banner.txt
│ ├── schema.sql
│ └── static
│ └── .gitkeep
└── test
└── java
└── xyz
└── snwjas
└── blog
└── .gitkeep
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | target/
3 | *.iml
4 | src/main/resources/admin/*
5 | !src/main/resources/admin/.gitkeep
6 | src/main/resources/app/*
7 | !src/main/resources/app/.gitkeep
8 | src/main/resources/static/*
9 | !src/main/resources/static/.gitkeep
10 | src/test/java/xyz/snwjas/blog/*
11 | !src/test/java/xyz/snwjas/blog/.gitkeep
12 | src/main/resources/BugRecords.md
13 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Myles
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/Application.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
6 | import org.springframework.scheduling.annotation.EnableScheduling;
7 |
8 | @EnableScheduling
9 | @ConfigurationPropertiesScan("xyz.snwjas.blog.config.properties")
10 | @SpringBootApplication
11 | public class Application {
12 |
13 | public static void main(String[] args) {
14 | SpringApplication.run(Application.class, args);
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/annotation/AccessLimit.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.annotation;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | /**
9 | * 接口防刷限流(固定时间内最大访问次数)
10 | *
11 | * @author Myles Yang
12 | */
13 | @Target({ElementType.METHOD})
14 | @Retention(RetentionPolicy.RUNTIME)
15 | public @interface AccessLimit {
16 |
17 | /**
18 | * 最大访问次数
19 | */
20 | int maxCount() default Integer.MAX_VALUE;
21 |
22 | /**
23 | * 固定时间
24 | */
25 | int seconds() default 1;
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/annotation/ActionRecord.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.annotation;
2 |
3 | import org.springframework.core.annotation.AliasFor;
4 | import xyz.snwjas.blog.aspect.ActionRecordAspect;
5 | import xyz.snwjas.blog.model.enums.LogType;
6 |
7 | import java.lang.annotation.ElementType;
8 | import java.lang.annotation.Retention;
9 | import java.lang.annotation.RetentionPolicy;
10 | import java.lang.annotation.Target;
11 |
12 | /**
13 | * 操作记录
14 | *
15 | * @author Myles Yang
16 | */
17 | @Target({ElementType.METHOD})
18 | @Retention(RetentionPolicy.RUNTIME)
19 | public @interface ActionRecord {
20 |
21 | /**
22 | * 操作内容的EL表达式,仅支持方法参数
23 | */
24 | @AliasFor("content")
25 | String value() default "";
26 |
27 | /**
28 | * 操作内容,与 value 互为别名
29 | */
30 | @AliasFor("value")
31 | String content() default "";
32 |
33 | /**
34 | * 操作类型
35 | */
36 | LogType type() default LogType.COMMON;
37 |
38 | /**
39 | * 生效条件的EL表达式
40 | * 它是通过返回值判断,返回值符号为{@link ActionRecordAspect#METHOD_RETURNING_SIGN}
41 | * 示例(函数返回值为0):
42 | * EL表达式:"#ret > 0",结果 false
43 | */
44 | String condition() default "";
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/annotation/TimeCost.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.annotation;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | /**
9 | * 方法执行计时
10 | */
11 | @Target(ElementType.METHOD)
12 | @Retention(RetentionPolicy.RUNTIME)
13 | public @interface TimeCost {
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/aspect/ActionRecordAspect.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.aspect;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import org.aspectj.lang.JoinPoint;
5 | import org.aspectj.lang.annotation.AfterReturning;
6 | import org.aspectj.lang.annotation.Aspect;
7 | import org.aspectj.lang.annotation.Pointcut;
8 | import org.aspectj.lang.reflect.MethodSignature;
9 | import org.springframework.beans.factory.annotation.Autowired;
10 | import org.springframework.expression.EvaluationContext;
11 | import org.springframework.expression.ExpressionParser;
12 | import org.springframework.expression.spel.standard.SpelExpressionParser;
13 | import org.springframework.expression.spel.support.StandardEvaluationContext;
14 | import org.springframework.stereotype.Component;
15 | import org.springframework.util.StringUtils;
16 | import xyz.snwjas.blog.annotation.ActionRecord;
17 | import xyz.snwjas.blog.model.vo.LogVO;
18 | import xyz.snwjas.blog.service.LogService;
19 | import xyz.snwjas.blog.utils.IPUtils;
20 |
21 | import javax.servlet.http.HttpServletRequest;
22 | import java.lang.reflect.Method;
23 | import java.util.Objects;
24 |
25 | /**
26 | * 操作记录注解切面
27 | *
28 | * @author Myles Yang
29 | */
30 | @Component
31 | @Aspect
32 | @Slf4j
33 | public class ActionRecordAspect {
34 |
35 | /**
36 | * 方法返回值符号
37 | */
38 | public static final String METHOD_RETURNING_SIGN = "ret";
39 |
40 | /**
41 | * el 表达式 解析器
42 | */
43 | private static final ExpressionParser SPEL_PARSER = new SpelExpressionParser();
44 |
45 | @Autowired
46 | private LogService logService;
47 |
48 |
49 | @Pointcut("@annotation(xyz.snwjas.blog.annotation.ActionRecord)")
50 | public void pointCut() {
51 | }
52 |
53 | /**
54 | * 方法正常返回的advice
55 | *
56 | * @param point 方法的连接点
57 | * @param ret 函数返回值,void的返回值为null
58 | */
59 | @AfterReturning(value = "pointCut()", returning = METHOD_RETURNING_SIGN, argNames = "point,ret")
60 | public void afterReturning(JoinPoint point, Object ret) {
61 |
62 | MethodSignature signature = (MethodSignature) point.getSignature();
63 | Method method = signature.getMethod();
64 | ActionRecord annotation = method.getAnnotation(ActionRecord.class);
65 | // 条件判断是否执行日志记录
66 | if (StringUtils.hasText(annotation.condition())) {
67 | try {
68 | Boolean condition = (Boolean) spell(annotation.condition(),
69 | new String[]{METHOD_RETURNING_SIGN}, new Object[]{ret});
70 | if (!(Objects.nonNull(condition) && condition)) {
71 | return;
72 | }
73 | } catch (Exception e) {
74 | log.error("条件EL表达式解析错误:{}", annotation.condition());
75 | e.printStackTrace();
76 | return;
77 | }
78 | }
79 |
80 | LogVO logVO = new LogVO();
81 |
82 | // 测试时 @AliasFor 失效,原因未知
83 | String content = StringUtils.isEmpty(annotation.value())
84 | ? annotation.content()
85 | : annotation.value();
86 |
87 | if (StringUtils.hasText(content)) {
88 | try {
89 | String cont = (String) spell(content,
90 | signature.getParameterNames(), point.getArgs());
91 | logVO.setContent(cont);
92 | } catch (Exception e) {
93 | log.error("内容EL表达式解析错误:{}", content);
94 | e.printStackTrace();
95 | return;
96 | }
97 | }
98 |
99 | logVO.setType(annotation.type());
100 |
101 | HttpServletRequest request = IPUtils.getRequest();
102 | if (Objects.nonNull(request)) {
103 | String ipAddress = IPUtils.getIpAddress(request);
104 | logVO.setIpAddress(ipAddress);
105 | }
106 |
107 | logService.add(logVO);
108 | }
109 |
110 | /**
111 | * el表达式解析
112 | *
113 | * @param el 表达式
114 | * @param names 参数名称数组
115 | * @param args 参数数组
116 | */
117 | public Object spell(String el, String[] names, Object[] args) {
118 | EvaluationContext context = new StandardEvaluationContext();
119 | for (int i = 0; i < args.length; i++) {
120 | context.setVariable(names[i], args[i]);
121 | }
122 | return SPEL_PARSER.parseExpression(el).getValue(context);
123 | }
124 |
125 | }
126 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/aspect/TimeCostAspect.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.aspect;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import org.aspectj.lang.JoinPoint;
5 | import org.aspectj.lang.annotation.AfterReturning;
6 | import org.aspectj.lang.annotation.Aspect;
7 | import org.aspectj.lang.annotation.Before;
8 | import org.aspectj.lang.annotation.Pointcut;
9 | import org.aspectj.lang.reflect.MethodSignature;
10 | import org.springframework.core.annotation.Order;
11 | import org.springframework.stereotype.Component;
12 |
13 | import java.lang.reflect.Method;
14 | import java.time.Instant;
15 | import java.time.temporal.ChronoUnit;
16 | import java.util.Objects;
17 |
18 | /**
19 | * 方法执行计时注解切面
20 | */
21 | @Component
22 | @Aspect
23 | @Slf4j
24 | @Order(1)
25 | public class TimeCostAspect {
26 |
27 | private final ThreadLocal instantThreadLocal = new ThreadLocal<>();
28 |
29 |
30 | @Pointcut("@annotation(xyz.snwjas.blog.annotation.TimeCost)")
31 | public void pointCut() {
32 | }
33 |
34 | @Before("pointCut()")
35 | public void before() {
36 | instantThreadLocal.set(Instant.now());
37 | }
38 |
39 | @AfterReturning("pointCut()")
40 | public void afterReturning(JoinPoint point) {
41 | if (Objects.nonNull(instantThreadLocal.get())) {
42 | Instant now = Instant.now();
43 | MethodSignature signature = (MethodSignature) point.getSignature();
44 | Method method = signature.getMethod();
45 | // String methodParameterTypes = StringUtils.join(method.getGenericParameterTypes(), ", ");
46 | log.info("类:{},方法:{},执行耗时:{}毫秒",
47 | method.getDeclaringClass().getName(),
48 | method.getName() /*+ "(" + methodParameterTypes + ")"*/,
49 | ChronoUnit.MILLIS.between(instantThreadLocal.get(), now));
50 | instantThreadLocal.remove();
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/config/AppStartConfig.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.config;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.boot.context.event.ApplicationReadyEvent;
6 | import org.springframework.context.annotation.Configuration;
7 | import org.springframework.context.event.EventListener;
8 | import org.springframework.util.StringUtils;
9 | import xyz.snwjas.blog.constant.MyBlogOptionEnum;
10 | import xyz.snwjas.blog.constant.OptionEnum;
11 | import xyz.snwjas.blog.model.enums.SpecialListType;
12 | import xyz.snwjas.blog.model.vo.OptionVO;
13 | import xyz.snwjas.blog.model.vo.SpeciallistVO;
14 | import xyz.snwjas.blog.service.OptionsService;
15 | import xyz.snwjas.blog.service.SpeciallistService;
16 | import xyz.snwjas.blog.support.wordfilter.WordFilter;
17 | import xyz.snwjas.blog.support.wordfilter.WordType;
18 | import xyz.snwjas.blog.utils.ClassUtils;
19 |
20 | import java.util.List;
21 | import java.util.Map;
22 | import java.util.Objects;
23 | import java.util.concurrent.ConcurrentHashMap;
24 |
25 | /**
26 | * 应用启动后的配置
27 | *
28 | * @author Myles Yang
29 | */
30 | @Configuration
31 | @Slf4j
32 | public class AppStartConfig {
33 |
34 | @Autowired
35 | private OptionsService optionsService;
36 |
37 | @Autowired
38 | private SpeciallistService speciallistService;
39 |
40 | @Autowired
41 | private WordFilter wordFilter;
42 |
43 |
44 | /**
45 | * 博客初始化
46 | */
47 | @EventListener(ApplicationReadyEvent.class)
48 | public void initialization() {
49 | OptionVO birthday = optionsService.get(MyBlogOptionEnum.BIRTHDAY.key());
50 | // 第一次启动应用
51 | if (Objects.isNull(birthday)) {
52 | for (Class clazz : ClassUtils.getAllClassByInterface(OptionEnum.class)) {
53 | for (OptionEnum oenum : clazz.getEnumConstants()) {
54 | if (StringUtils.hasText(oenum.key())) {
55 | String value = oenum.defaultValue() == null ? "" : oenum.defaultValue();
56 | optionsService.setIfAbsence(oenum.key(), value);
57 | }
58 | }
59 | }
60 | log.info("首次启动应用,已初始化设置");
61 | }
62 | }
63 |
64 | /**
65 | * 初始化敏感词过滤器词条
66 | */
67 | @EventListener(ApplicationReadyEvent.class)
68 | public void initWordFilter() throws Exception {
69 | Object PRESENT = new Object();
70 | Map blackList = new ConcurrentHashMap<>(128);
71 | Map whiteList = new ConcurrentHashMap<>(32);
72 | List list = speciallistService.listAll(SpecialListType.WORD_BLACK_LIST, SpecialListType.WORD_WHITE_LIST);
73 | list.stream().parallel().forEach(o -> {
74 | if (Objects.nonNull(o.getType())) {
75 | if (SpecialListType.WORD_BLACK_LIST.equals(o.getType())) {
76 | blackList.put(o.getContent(), PRESENT);
77 | } else if (SpecialListType.WORD_WHITE_LIST.equals(o.getType())) {
78 | whiteList.put(o.getContent(), PRESENT);
79 | }
80 | }
81 | });
82 | wordFilter.getContext().addWord(blackList.keySet(), WordType.BLACK);
83 | wordFilter.getContext().addWord(whiteList.keySet(), WordType.WHITE);
84 | log.info("加载敏感词词条完毕:黑名单 {} 条,白名单 {} 条", blackList.size(), whiteList.size());
85 | }
86 |
87 | }
88 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/config/HibernateValidationConfig.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.config;
2 |
3 | import org.hibernate.validator.HibernateValidator;
4 | import org.springframework.context.annotation.Bean;
5 | import org.springframework.context.annotation.Configuration;
6 | import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
7 |
8 | import javax.validation.Validation;
9 | import javax.validation.Validator;
10 | import javax.validation.ValidatorFactory;
11 |
12 | /**
13 | * Spring Validation 配置
14 | *
15 | * @author Myles Yang
16 | */
17 | @Configuration
18 | public class HibernateValidationConfig {
19 |
20 | /**
21 | * 开启Fail Fast模式,一旦校验失败就立即返回
22 | * Spring Validation 默认会校验完所有字段,然后才抛出异常。
23 | */
24 | @Bean
25 | public Validator validator() {
26 | ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
27 | .configure()
28 | .failFast(true)
29 | .buildValidatorFactory();
30 | return validatorFactory.getValidator();
31 | }
32 |
33 | /**
34 | * 方法参数检验,注意在类上添加 @Validated 注解
35 | */
36 | @Bean
37 | public MethodValidationPostProcessor methodValidationPostProcessor() {
38 | MethodValidationPostProcessor postProcessor = new MethodValidationPostProcessor();
39 | // 设置validator模式为快速失败返回
40 | postProcessor.setValidator(validator());
41 | return postProcessor;
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/config/LocalDateTimeSerializerConfig.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.config;
2 |
3 | import com.fasterxml.jackson.databind.DeserializationFeature;
4 | import com.fasterxml.jackson.databind.ObjectMapper;
5 | import com.fasterxml.jackson.databind.SerializationFeature;
6 | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
7 | import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
8 | import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
9 | import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
10 | import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
11 | import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
12 | import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
13 | import org.springframework.context.annotation.Bean;
14 | import org.springframework.context.annotation.Configuration;
15 | import org.springframework.context.annotation.Primary;
16 |
17 | import java.text.SimpleDateFormat;
18 | import java.time.LocalDate;
19 | import java.time.LocalDateTime;
20 | import java.time.LocalTime;
21 | import java.time.format.DateTimeFormatter;
22 | import java.util.List;
23 |
24 | /**
25 | * 请求、响应的日期格式全局格式化
26 | */
27 | @Configuration
28 | public class LocalDateTimeSerializerConfig {
29 |
30 | public static final String DEFAULT_DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
31 |
32 | public static final String DEFAULT_DATE_PATTERN = "yyyy-MM-dd";
33 |
34 | public static final String DEFAULT_TIME_PATTERN = "HH:mm:ss";
35 |
36 | /**
37 | * 自定义 LocalDateTime、LocalDate、LocalTime 的序列化 与 反序列化
38 | * 1.配置 MappingJackson2HttpMessageConverter{@link WebMvcConfig#customJackson2HttpMessageConverter()}
39 | * 2.重写 WebMVC 的 configureMessageConverters{@link WebMvcConfig#configureMessageConverters(List)}
40 | */
41 | @Bean
42 | @Primary
43 | public ObjectMapper objectMapper() {
44 |
45 | ObjectMapper om = new ObjectMapper();
46 | om.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
47 | om.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE);
48 |
49 | JavaTimeModule module = new JavaTimeModule();
50 | module
51 | .addSerializer(LocalDateTime.class,
52 | new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_PATTERN)))
53 | .addSerializer(LocalDate.class,
54 | new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_PATTERN)))
55 | .addSerializer(LocalTime.class,
56 | new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_PATTERN)))
57 | .addDeserializer(LocalDateTime.class,
58 | new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_PATTERN)))
59 | .addDeserializer(LocalDate.class,
60 | new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_PATTERN)))
61 | .addDeserializer(LocalTime.class,
62 | new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_PATTERN)));
63 |
64 | om.registerModule(module);
65 |
66 | om.setDateFormat(new SimpleDateFormat(DEFAULT_DATE_TIME_PATTERN));
67 |
68 | return om;
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/config/MyBatisPlusConfig.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.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.PaginationInnerInterceptor;
6 | import org.mybatis.spring.annotation.MapperScan;
7 | import org.springframework.context.annotation.Bean;
8 | import org.springframework.context.annotation.Configuration;
9 | import org.springframework.transaction.annotation.EnableTransactionManagement;
10 |
11 | @Configuration
12 | @EnableTransactionManagement
13 | @MapperScan("xyz.snwjas.blog.mapper")
14 | public class MyBatisPlusConfig {
15 |
16 | /**
17 | * MybatisPlus 拦截器
18 | */
19 | @Bean
20 | public MybatisPlusInterceptor mybatisPlusInterceptor() {
21 | MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
22 |
23 | // 注册分页插件
24 | PaginationInnerInterceptor pii = new PaginationInnerInterceptor(DbType.MYSQL);
25 | // 最大单页限制数量
26 | pii.setMaxLimit(100L);
27 |
28 | interceptor.addInnerInterceptor(pii);
29 | return interceptor;
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/config/MyBlogConfig.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.config;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import org.springframework.context.annotation.Bean;
5 | import org.springframework.context.annotation.Configuration;
6 | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
7 | import xyz.snwjas.blog.support.cache.MemoryCacheStore;
8 | import xyz.snwjas.blog.support.wordfilter.WordContext;
9 | import xyz.snwjas.blog.support.wordfilter.WordFilter;
10 |
11 | import java.util.concurrent.ThreadPoolExecutor;
12 |
13 | /**
14 | * 博客配置
15 | *
16 | * @author Myles Yang
17 | */
18 | @Configuration
19 | @Slf4j
20 | public class MyBlogConfig {
21 |
22 | /**
23 | * 自定义缓存
24 | */
25 | @Bean
26 | public MemoryCacheStore memoryCacheStore() {
27 | return new MemoryCacheStore();
28 | }
29 |
30 | /**
31 | * 敏感词过滤器
32 | */
33 | @Bean
34 | public WordFilter wordFilter() {
35 | return new WordFilter(new WordContext());
36 | }
37 |
38 | /**
39 | * 线程池
40 | */
41 | @Bean("executor")
42 | public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
43 | ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
44 | executor.setCorePoolSize(Runtime.getRuntime().availableProcessors());
45 | executor.setMaxPoolSize(128);
46 | executor.setQueueCapacity(1024);
47 | executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
48 | executor.setWaitForTasksToCompleteOnShutdown(true);
49 | executor.setAwaitTerminationSeconds(3);
50 | return executor;
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/config/SwaggerConfig.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.config;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import org.springframework.context.annotation.Bean;
5 | import org.springframework.context.annotation.Configuration;
6 | import springfox.documentation.builders.ApiInfoBuilder;
7 | import springfox.documentation.builders.PathSelectors;
8 | import springfox.documentation.builders.RequestHandlerSelectors;
9 | import springfox.documentation.service.ApiInfo;
10 | import springfox.documentation.service.Contact;
11 | import springfox.documentation.spi.DocumentationType;
12 | import springfox.documentation.spring.web.plugins.Docket;
13 | import springfox.documentation.swagger2.annotations.EnableSwagger2;
14 | import xyz.snwjas.blog.config.properties.MyBlogProperties;
15 |
16 | import java.time.temporal.Temporal;
17 |
18 | /**
19 | * Swagger 配置
20 | *
21 | * @author Myles Yang
22 | */
23 | @Configuration
24 | @EnableSwagger2
25 | @Slf4j
26 | public class SwaggerConfig {
27 |
28 | private final MyBlogProperties properties;
29 |
30 | public SwaggerConfig(MyBlogProperties properties) {
31 | this.properties = properties;
32 | }
33 |
34 | @Bean
35 | public Docket docket() {
36 | if (!properties.isDocEnable()) {
37 | log.debug("Swagger Doc has been disabled.");
38 | }
39 | return buildDocket("Default",
40 | "xyz.snwjas.blog.controller",
41 | "/**")
42 | .enable(properties.isDocEnable());
43 | }
44 |
45 | private Docket buildDocket(String groupName, String basePackage, String antPattern) {
46 | return new Docket(DocumentationType.SWAGGER_2)
47 | .groupName(groupName)
48 | .select()
49 | .apis(RequestHandlerSelectors.basePackage(basePackage))
50 | .paths(PathSelectors.ant(antPattern))
51 | .build()
52 | .apiInfo(apiInfo())
53 | .directModelSubstitute(Temporal.class, String.class);
54 |
55 | }
56 |
57 | private ApiInfo apiInfo() {
58 | return new ApiInfoBuilder()
59 | .title("MyBlog API Documentation.")
60 | .description("The API documentation for MyBlog.")
61 | .version("1.0.0")
62 | .contact(new Contact("Myles Yang", "snwjas.xyz", "myles.yang@foxmail.com"))
63 | .license("MIT")
64 | .licenseUrl("")
65 | .build();
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/config/WebSecurityConfig.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.config;
2 |
3 | import org.springframework.beans.factory.annotation.Autowired;
4 | import org.springframework.context.annotation.Bean;
5 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
6 | import org.springframework.security.config.annotation.web.builders.HttpSecurity;
7 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
8 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
9 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
10 | import org.springframework.security.crypto.password.PasswordEncoder;
11 | import org.springframework.security.web.csrf.CsrfFilter;
12 | import org.springframework.web.filter.CharacterEncodingFilter;
13 | import xyz.snwjas.blog.config.properties.MyBlogProperties;
14 | import xyz.snwjas.blog.support.security.MyAuthenticationFailureHandler;
15 | import xyz.snwjas.blog.support.security.MyAuthenticationSuccessHandler;
16 | import xyz.snwjas.blog.support.security.MyLogoutSuccessHandler;
17 | import xyz.snwjas.blog.support.security.MyUserDetailsService;
18 |
19 | /**
20 | * Spring Security 配置
21 | *
22 | * @author Myles Yang
23 | */
24 | @EnableWebSecurity
25 | public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
26 |
27 | @Autowired
28 | private MyBlogProperties properties;
29 |
30 | @Autowired
31 | private MyUserDetailsService myUserDetailsService;
32 |
33 | @Autowired
34 | private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;
35 |
36 | @Autowired
37 | private MyAuthenticationFailureHandler myAuthenticationFailureHandler;
38 |
39 | @Autowired
40 | private MyLogoutSuccessHandler myLogoutSuccessHandler;
41 |
42 | /**
43 | * 密码加密器
44 | */
45 | @Bean
46 | public PasswordEncoder passwordEncoder() {
47 | // the version of bcrypt, can be 2a,2b,2y
48 | // the log rounds to use, between 4 and 31
49 | return new BCryptPasswordEncoder(BCryptPasswordEncoder.BCryptVersion.$2Y, 5);
50 | }
51 |
52 | /**
53 | * 自定义登录业务逻辑配置
54 | */
55 | @Override
56 | protected void configure(AuthenticationManagerBuilder auth) throws Exception {
57 | auth.userDetailsService(myUserDetailsService);
58 | }
59 |
60 | /**
61 | * Http 安全配置
62 | */
63 | @Override
64 | protected void configure(HttpSecurity http) throws Exception {
65 |
66 | // 允许来自同一域的任何请求不被添加到响应中
67 | http.headers().frameOptions().sameOrigin().httpStrictTransportSecurity().disable();
68 |
69 | // 关闭csrf,允许跨域访问
70 | http.csrf().disable().cors();
71 |
72 | // 放行 与 拦截 的请求
73 | http.authorizeRequests()
74 | .antMatchers("/api/admin/user/login", "/api/admin/user/checkLogin").permitAll()
75 | .antMatchers("/api/admin/**").authenticated();
76 |
77 | // 登录表单验证处理
78 | http.formLogin()
79 | .loginPage("/api/admin/user/login")
80 | .usernameParameter("username")
81 | .passwordParameter("password")
82 | // 认证成功处理
83 | .successHandler(myAuthenticationSuccessHandler)
84 | // 认证失败处理
85 | .failureHandler(myAuthenticationFailureHandler);
86 |
87 | // 注销
88 | http.logout()
89 | .logoutUrl("/api/admin/user/logout")
90 | .deleteCookies("JSESSIONID", "rememberMe")
91 | .invalidateHttpSession(true)
92 | // 注销成功处理
93 | .logoutSuccessHandler(myLogoutSuccessHandler);
94 |
95 | // 开启登录的记住我功能,SpringSecurity中token默认有效期为两周
96 | // checkbox 支持校验的值["true", "on", "yes", "1"]
97 | // 具体参考 {@link AbstractRememberMeServices#rememberMeRequested(HttpServletRequest, String)}
98 | http.rememberMe()
99 | .rememberMeParameter("rememberMe")
100 | .tokenValiditySeconds(properties.getRememberMeTokenValiditySeconds());
101 |
102 | // 编码过滤器
103 | CharacterEncodingFilter enf = new CharacterEncodingFilter("UTF-8", false, true);
104 | http.addFilterBefore(enf, CsrfFilter.class);
105 |
106 | }
107 |
108 | }
109 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/config/properties/MyBlogProperties.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.config.properties;
2 |
3 | import lombok.Getter;
4 | import lombok.Setter;
5 | import org.springframework.boot.context.properties.ConfigurationProperties;
6 |
7 | import java.nio.file.Paths;
8 |
9 | /**
10 | * 博客配置
11 | *
12 | * @author Myles Yang
13 | */
14 | @Getter
15 | @Setter
16 | @ConfigurationProperties(prefix = "my-blog")
17 | public class MyBlogProperties {
18 | /**
19 | * swagger doc
20 | */
21 | private boolean docEnable = false;
22 |
23 | /**
24 | * 后台管理入口,不需要添加'/'
25 | */
26 | private String adminPath = "admin";
27 |
28 | /**
29 | * 自定义管理端WEB静态文件所在目录,默认为“classpath:/admin/”
30 | */
31 | private String adminWebPath = null;
32 |
33 | /**
34 | * 自定义展示前端WEB静态文件所在目录,默认为“classpath:/app/”
35 | */
36 | private String appWebPath = null;
37 |
38 | /**
39 | * 允许连续登录失败的时间(单位秒)
40 | */
41 | private int allowLoginFailureSeconds = 3600;
42 |
43 | /**
44 | * 允许登录失败的次数
45 | */
46 | private int allowLoginFailureCount = 10;
47 |
48 |
49 | /**
50 | * 登录记住我token时间(单位秒,1周 = 604800秒)
51 | */
52 | private int rememberMeTokenValiditySeconds = 604800;
53 |
54 | /**
55 | * 上传文件保存路径
56 | */
57 | private String fileSavePath = Paths.get(System.getProperty("user.home"), "MyBlog", "files").toString();
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/constant/CacheKeyPrefix.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.constant;
2 |
3 | /**
4 | * Redis key 前缀 常量
5 | *
6 | * @author Myles Yang
7 | */
8 | public interface CacheKeyPrefix {
9 |
10 | /**
11 | * 分隔符
12 | */
13 | String SEPARATOR = ":";
14 |
15 | /**
16 | * 认证失败次数前缀
17 | */
18 | String LOGIN_FAILED_COUNT = "loginFailedCount:";
19 |
20 | /**
21 | * 访问限制次数(接口限流)
22 | */
23 | String ACCESS_LIMIT_PREFIX = "accessLimit:";
24 |
25 | /**
26 | * 网站访问量
27 | */
28 | String WEB_VISIT_COUNT = "webVisitCount:";
29 |
30 | /**
31 | * 博客文章访问量
32 | */
33 | String BLOG_VISIT_COUNT = "blogVisitCount:";
34 |
35 | /**
36 | * 博客点赞
37 | */
38 | String BLOG_LIKE = "blogLike:";
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/constant/MyBlogOptionEnum.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.constant;
2 |
3 | import java.time.LocalDateTime;
4 |
5 | /**
6 | * MyBlog Option Enum
7 | *
8 | * @author Myles Yang
9 | */
10 | public enum MyBlogOptionEnum implements OptionEnum {
11 |
12 | /**
13 | * 博客主页url
14 | */
15 | URL("url", String.class, "http://"),
16 |
17 | /**
18 | * 博客名
19 | */
20 | NAME("name", String.class, "MyBlog"),
21 |
22 | /**
23 | * 博客描述
24 | */
25 | DESCRIPTION("description", String.class, "MyBlog"),
26 |
27 | /**
28 | * 博客logo
29 | */
30 | LOGO("logo", String.class, ""),
31 |
32 | /**
33 | * 博客favicon
34 | */
35 | FAVICON("favicon", String.class, ""),
36 |
37 | /**
38 | * 博客页脚信息
39 | */
40 | FOOTER("footer", String.class, "Copyright © 2020 MyBlog"),
41 |
42 | /**
43 | * 博客建立日期
44 | */
45 | BIRTHDAY("birthday", String.class, LocalDateTime.now().toString()),
46 |
47 |
48 | ;
49 |
50 | private final String key;
51 |
52 | private final Class> type;
53 |
54 | private final String defaultValue;
55 |
56 | MyBlogOptionEnum(String key, Class> type, String defaultValue) {
57 | this.key = key;
58 | this.type = type;
59 | this.defaultValue = defaultValue;
60 | }
61 |
62 | @Override
63 | public String key() {
64 | return key;
65 | }
66 |
67 | @Override
68 | public Class> type() {
69 | return type;
70 | }
71 |
72 | @Override
73 | public String defaultValue() {
74 | return defaultValue;
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/constant/OptionEnum.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.constant;
2 |
3 | /**
4 | * 博客设置枚举接口
5 | *
6 | * @author Myles Yang
7 | */
8 | public interface OptionEnum {
9 |
10 | /**
11 | * 设置项的唯一标识
12 | */
13 | String key();
14 |
15 | /**
16 | * 设置项的类型,用于解析时进行类型转换
17 | */
18 | Class> type();
19 |
20 | /**
21 | * 设置项默认值
22 | */
23 | String defaultValue();
24 |
25 |
26 | /**
27 | * 获得optionValue的原类型值
28 | */
29 | @SuppressWarnings("unchecked")
30 | static T getTrueOptionValue(String value, Class type) {
31 | if (type.isAssignableFrom(String.class)) {
32 | return (T) value;
33 | }
34 |
35 | if (type.isAssignableFrom(Integer.class)) {
36 | return (T) Integer.valueOf(value);
37 | }
38 |
39 | if (type.isAssignableFrom(Long.class)) {
40 | return (T) Long.valueOf(value);
41 | }
42 |
43 | if (type.isAssignableFrom(Boolean.class)) {
44 | return (T) Boolean.valueOf(value);
45 | }
46 |
47 | if (type.isAssignableFrom(Short.class)) {
48 | return (T) Short.valueOf(value);
49 | }
50 |
51 | if (type.isAssignableFrom(Byte.class)) {
52 | return (T) Byte.valueOf(value);
53 | }
54 |
55 | if (type.isAssignableFrom(Double.class)) {
56 | return (T) Double.valueOf(value);
57 | }
58 |
59 | if (type.isAssignableFrom(Float.class)) {
60 | return (T) Float.valueOf(value);
61 | }
62 |
63 | return (T) value;
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/constant/OtherOptionEnum.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.constant;
2 |
3 | /**
4 | * todo
5 | *
6 | * @author Myles Yang
7 | */
8 | public enum OtherOptionEnum implements OptionEnum {
9 |
10 | URL_FAVICON_PARSER("url_favicon_parser", String.class, ""),
11 |
12 | ;
13 |
14 | private final String key;
15 |
16 | private final Class> type;
17 |
18 | private final String defaultValue;
19 |
20 | OtherOptionEnum(String key, Class> type, String defaultValue) {
21 | this.key = key;
22 | this.type = type;
23 | this.defaultValue = defaultValue;
24 | }
25 |
26 | @Override
27 | public String key() {
28 | return key;
29 | }
30 |
31 | @Override
32 | public Class> type() {
33 | return type;
34 | }
35 |
36 | @Override
37 | public String defaultValue() {
38 | return defaultValue;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/constant/RS.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.constant;
2 |
3 | import org.springframework.http.HttpStatus;
4 |
5 | /**
6 | * 自定义状态码(Response Status)
7 | *
8 | * 200 成功
9 | * 1001 - 1999 参数
10 | * 2001 - 2999 用户
11 | * 3001 - 3999 权限
12 | * 4001 - 4999 数据
13 | * 5001 - 5999 业务
14 | * 6001 - 6999 接口
15 | * 7001 - 7999 系统
16 | *
17 | * @author Myles Yang
18 | */
19 | public enum RS {
20 |
21 | SUCCESS(HttpStatus.OK.value(), "成功"),
22 |
23 | /**
24 | * 参数错误
25 | */
26 | ILLEGAL_PARAMETER(1001, "非法参数"),
27 |
28 | FILE_SIZE_LIMIT(1002, "上传文件过大"),
29 |
30 | /**
31 | * 用户错误
32 | */
33 | USERNAME_PASSWORD_ERROR(2001, "用户名或密码错误"),
34 |
35 | USERNAME_ERROR(2002, "用户名错误"),
36 |
37 | PASSWORD_ERROR(2003, "密码错误"),
38 |
39 | INCONSISTENT_PASSWORDS(2004, "两次输入的密码不一致"),
40 |
41 | MULTIPLE_AUTHENTICATION_FAILURE(2005, "多次认证失败"),
42 |
43 | /**
44 | * 权限
45 | */
46 | NOT_LOGIN(3001, "用户未登录"),
47 |
48 |
49 | /**
50 | * 接口错误
51 | */
52 | FREQUENT_OPERATION(6001, "操作过于频繁,请稍后再试"),
53 |
54 | METHOD_NOT_SUPPORTED(6002, "请求方法有误"),
55 |
56 | PAGE_NOT_FOUND(6003, "请求目标不存在"),
57 |
58 | /**
59 | * 系统错误
60 | */
61 | SYSTEM_ERROR(7001, "系统错误"),
62 |
63 | ;
64 |
65 | private final int status;
66 |
67 | private final String message;
68 |
69 | RS(int status, String message) {
70 | this.status = status;
71 | this.message = message;
72 | }
73 |
74 | public int status() {
75 | return status;
76 | }
77 |
78 | public String message() {
79 | return message;
80 | }
81 |
82 | public static RS resolve(int statusCode) {
83 | for (RS rc : values()) {
84 | if (rc.status == statusCode) {
85 | return rc;
86 | }
87 | }
88 | return null;
89 | }
90 |
91 | @Override
92 | public String toString() {
93 | return "{\"status\":" + status + ",\"message\":\"" + message + "\"}";
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/controller/MainController.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.controller;
2 |
3 | import io.swagger.annotations.Api;
4 | import io.swagger.annotations.ApiOperation;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.util.StringUtils;
7 | import org.springframework.web.bind.annotation.GetMapping;
8 | import org.springframework.web.bind.annotation.RestController;
9 | import xyz.snwjas.blog.annotation.AccessLimit;
10 | import xyz.snwjas.blog.config.properties.MyBlogProperties;
11 | import xyz.snwjas.blog.constant.MyBlogOptionEnum;
12 | import xyz.snwjas.blog.model.vo.OptionVO;
13 | import xyz.snwjas.blog.service.OptionsService;
14 | import xyz.snwjas.blog.model.R;
15 | import xyz.snwjas.blog.utils.RUtils;
16 | import xyz.snwjas.blog.utils.URLUtils;
17 |
18 | import javax.servlet.http.HttpServletResponse;
19 | import java.io.IOException;
20 | import java.util.Map;
21 | import java.util.Objects;
22 |
23 | /**
24 | * Main Controller
25 | *
26 | * @author Myles Yang
27 | */
28 | @RestController
29 | @Api(value = "主控制器", tags = {"主接口"})
30 | public class MainController {
31 |
32 | @Autowired
33 | private MyBlogProperties properties;
34 |
35 | @Autowired
36 | private OptionsService optionsService;
37 |
38 | /**
39 | * 后台入口
40 | */
41 | @GetMapping("${my-blog.admin-path:admin}")
42 | @ApiOperation("后台入口")
43 | public void toAdmin(HttpServletResponse response) throws IOException {
44 | response.sendRedirect("/" + properties.getAdminPath() + "/index.html");
45 | }
46 |
47 | /**
48 | * 前台入口
49 | */
50 | @GetMapping({"/", "/index"})
51 | @ApiOperation("前台入口")
52 | public void index(HttpServletResponse response) throws IOException {
53 | response.sendRedirect("/app/index.html");
54 | }
55 |
56 | @AccessLimit(maxCount = 2)
57 | @GetMapping("/favicon.ico")
58 | @ApiOperation("获取Favicon图标")
59 | public void getFavicon(HttpServletResponse response) throws IOException {
60 | OptionVO vo = optionsService.get(MyBlogOptionEnum.FAVICON.key());
61 | if (Objects.nonNull(vo) && StringUtils.hasText(vo.getOptionValue())) {
62 | response.sendRedirect(URLUtils.encodeAll(vo.getOptionValue()));
63 | }
64 | }
65 |
66 | @AccessLimit(maxCount = 2)
67 | @GetMapping("/attributes")
68 | @ApiOperation("获取博客的基本属性")
69 | public R getAttributes() {
70 | Map attributes = optionsService.listNecessary();
71 | return RUtils.success("基本属性", attributes);
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/controller/admin/BlogController.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.controller.admin;
2 |
3 | import com.baomidou.mybatisplus.core.metadata.IPage;
4 | import io.swagger.annotations.Api;
5 | import io.swagger.annotations.ApiOperation;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.validation.annotation.Validated;
8 | import org.springframework.web.bind.annotation.*;
9 | import xyz.snwjas.blog.model.base.ValidGroupType;
10 | import xyz.snwjas.blog.model.entity.BlogEntity;
11 | import xyz.snwjas.blog.model.params.BlogSearchParam;
12 | import xyz.snwjas.blog.model.vo.BlogDetailVO;
13 | import xyz.snwjas.blog.model.vo.BlogSelectVO;
14 | import xyz.snwjas.blog.model.vo.BlogSimpleVO;
15 | import xyz.snwjas.blog.service.BlogService;
16 | import xyz.snwjas.blog.model.PageResult;
17 | import xyz.snwjas.blog.model.R;
18 | import xyz.snwjas.blog.utils.RUtils;
19 |
20 | import javax.validation.Valid;
21 | import javax.validation.constraints.Min;
22 | import java.util.List;
23 | import java.util.Objects;
24 |
25 | /**
26 | * Article Controller
27 | *
28 | * @author Myles Yang
29 | */
30 | @Validated
31 | @RestController("AdminBlogController")
32 | @RequestMapping("/api/admin/blog")
33 | @Api(value = "后台博客文章控制器", tags = {"后台博客文章接口"})
34 | public class BlogController {
35 |
36 | @Autowired
37 | private BlogService blogService;
38 |
39 | @PostMapping("/list")
40 | @ApiOperation("获取博客文章列表信息")
41 | public R listBlogs(@RequestBody @Valid BlogSearchParam param) {
42 | IPage blogEntityIPage = blogService.pageBy(param);
43 | PageResult pageResult = blogService.covertToPageResult(blogEntityIPage);
44 | return RUtils.success("博客文章列表信息", pageResult);
45 | }
46 |
47 | @GetMapping("/list/all-titles")
48 | @ApiOperation("获取所有的文章标题")
49 | public R listAllTitle() {
50 | List list = blogService.listAllTitle();
51 | return RUtils.success("所有的文章标题", list);
52 | }
53 |
54 | @GetMapping("/get/{id}")
55 | @ApiOperation("获取博客文章信息")
56 | public R getBlog(@PathVariable("id") @Min(1) Integer blogId) {
57 | BlogDetailVO detailVO = blogService.getDetailById(blogId);
58 | if (Objects.isNull(detailVO)) {
59 | return RUtils.fail("无此博客文章信息");
60 | }
61 | return RUtils.success("博客文章信息", detailVO);
62 | }
63 |
64 | @PostMapping("/add")
65 | @ApiOperation("发表博客文章")
66 | public R addBlog(@RequestBody @Validated(ValidGroupType.Save.class) BlogDetailVO vo) {
67 | int i = blogService.add(vo);
68 | return RUtils.commonFailOrNot(i, "发表博客文章");
69 | }
70 |
71 | @PostMapping("/update")
72 | @ApiOperation("更新博客文章信息")
73 | public R updateBlog(@RequestBody @Validated(ValidGroupType.Update.class) BlogDetailVO vo) {
74 | if (blogService.isExist(vo.getId(), vo.getUrl())) {
75 | return RUtils.fail("博客路径已存在");
76 | }
77 | int i = blogService.update(vo);
78 | return RUtils.commonFailOrNot(i, "博客信息文章更新");
79 | }
80 |
81 | @DeleteMapping("/delete/{blogId}")
82 | @ApiOperation("删除博客文章")
83 | public R deleteBlog(@PathVariable("blogId") @Min(1) Integer blogId) {
84 | int i = blogService.deleteById(blogId);
85 | return RUtils.commonFailOrNot(i, "删除博客文章");
86 | }
87 |
88 | }
89 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/controller/admin/CategoryController.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.controller.admin;
2 |
3 |
4 | import com.baomidou.mybatisplus.core.metadata.IPage;
5 | import io.swagger.annotations.Api;
6 | import io.swagger.annotations.ApiOperation;
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.validation.annotation.Validated;
9 | import org.springframework.web.bind.annotation.*;
10 | import xyz.snwjas.blog.model.PageResult;
11 | import xyz.snwjas.blog.model.R;
12 | import xyz.snwjas.blog.model.base.ValidGroupType;
13 | import xyz.snwjas.blog.model.entity.CategoryEntity;
14 | import xyz.snwjas.blog.model.params.BasePageParam;
15 | import xyz.snwjas.blog.model.vo.CategoryVO;
16 | import xyz.snwjas.blog.service.BlogService;
17 | import xyz.snwjas.blog.service.CategoryService;
18 | import xyz.snwjas.blog.utils.RUtils;
19 |
20 | import javax.validation.Valid;
21 | import javax.validation.constraints.Min;
22 | import javax.validation.constraints.NotNull;
23 | import java.util.List;
24 |
25 | /**
26 | * Category Controller
27 | *
28 | * @author Myles Yang
29 | */
30 | @Validated
31 | @RestController("AdminCategoryController")
32 | @RequestMapping("/api/admin/blog/category")
33 | @Api(value = "后台分类控制器", tags = {"后台分类接口"})
34 | public class CategoryController {
35 |
36 | @Autowired
37 | private CategoryService categoryService;
38 |
39 | @Autowired
40 | private BlogService blogService;
41 |
42 | @PostMapping("/list")
43 | @ApiOperation("分页获取博客分类")
44 | public R list(@RequestBody @Valid BasePageParam param) {
45 | IPage categoryPage = categoryService.pageBy(param);
46 | PageResult pageResult = categoryService.covertToPageResult(categoryPage);
47 | // 获取每个分类下的文章数目
48 | for (CategoryVO vo : pageResult.getList()) {
49 | int count = blogService.getCountByCategoryId(vo.getId(), null);
50 | vo.setBlogCount(count);
51 | }
52 | return RUtils.success("博客分类分页信息", pageResult);
53 | }
54 |
55 | @GetMapping("/list/all")
56 | @ApiOperation("获取所有博客分类")
57 | public R listAll() {
58 | List categoryVOList = categoryService.listAllCategory();
59 | return RUtils.success("所有的博客分类", categoryVOList);
60 | }
61 |
62 | @GetMapping("/list/used")
63 | @ApiOperation("获取已使用的博客分类")
64 | public R listUsed() {
65 | List usedCategory = categoryService.listUsedCategory();
66 | return RUtils.success("已使用的博客分类", usedCategory);
67 | }
68 |
69 | @DeleteMapping("/delete/{categoryId}")
70 | @ApiOperation("删除分类")
71 | public R delete(@PathVariable("categoryId") @NotNull @Min(1) Integer categoryId) {
72 | int i = categoryService.deleteById(categoryId);
73 | return RUtils.commonFailOrNot(i, "删除分类");
74 | }
75 |
76 | @PostMapping("/add")
77 | @ApiOperation("添加分类")
78 | public R add(@RequestBody @Validated({ValidGroupType.Save.class}) CategoryVO vo) {
79 | int i = categoryService.add(vo);
80 | if (i > 0) {
81 | return RUtils.success("添加分类成功");
82 | }
83 | if (i < 0) {
84 | return RUtils.fail("分类名已存在");
85 | }
86 | return RUtils.fail("添加分类失败");
87 | }
88 |
89 | @PostMapping("/update")
90 | @ApiOperation("更新分类")
91 | public R update(@RequestBody @Validated({ValidGroupType.Update.class}) CategoryVO vo) {
92 | int i = categoryService.update(vo);
93 | return RUtils.commonFailOrNot(i, "更新分类");
94 | }
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/controller/admin/CommentController.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.controller.admin;
2 |
3 |
4 | import com.baomidou.mybatisplus.core.metadata.IPage;
5 | import io.swagger.annotations.Api;
6 | import io.swagger.annotations.ApiOperation;
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.validation.annotation.Validated;
9 | import org.springframework.web.bind.annotation.*;
10 | import xyz.snwjas.blog.model.entity.CommentEntity;
11 | import xyz.snwjas.blog.model.enums.CommentStatus;
12 | import xyz.snwjas.blog.model.params.CommentSearchParam;
13 | import xyz.snwjas.blog.model.params.ListParam;
14 | import xyz.snwjas.blog.model.vo.CommentDetailVO;
15 | import xyz.snwjas.blog.model.vo.CommentSimpleVO;
16 | import xyz.snwjas.blog.service.CommentService;
17 | import xyz.snwjas.blog.model.PageResult;
18 | import xyz.snwjas.blog.model.R;
19 | import xyz.snwjas.blog.utils.RUtils;
20 |
21 | import javax.validation.Valid;
22 | import javax.validation.constraints.Min;
23 | import javax.validation.constraints.NotNull;
24 |
25 | /**
26 | * Comment Controller
27 | *
28 | * @author Myles Yang
29 | */
30 | @Validated
31 | @RestController("AdminCommentController")
32 | @RequestMapping("/api/admin/comment")
33 | @Api(value = "后台评论控制器", tags = {"后台评论接口"})
34 | public class CommentController {
35 |
36 | @Autowired
37 | private CommentService commentService;
38 |
39 | @PostMapping("/list")
40 | @ApiOperation("获取评论列表信息")
41 | public R list(@RequestBody @Valid CommentSearchParam param) {
42 | IPage blogEntityIPage = commentService.pageBy(param);
43 | PageResult pageResult = commentService.covertToDetailPageResult(blogEntityIPage);
44 | return RUtils.success("评论列表信息", pageResult);
45 | }
46 |
47 | @PostMapping("/update/status")
48 | @ApiOperation("更新评论状态")
49 | public R updateStatus(@RequestParam("id") @NotNull @Min(1) Integer id,
50 | @RequestParam("status") @NotNull CommentStatus status) {
51 | int i = commentService.changeStatus(id, status);
52 | return RUtils.commonFailOrNot(i, "更新评论状态");
53 | }
54 |
55 | @PostMapping("/update/status-batch")
56 | @ApiOperation("批量更新评论状态")
57 | public R updateStatusBatch(@RequestParam("ids") @Validated ListParam ids,
58 | @RequestParam("status") @NotNull CommentStatus status) {
59 | int count = commentService.changeStatus(ids, status);
60 | return RUtils.success("成功更新了" + count + "条评论的状态");
61 | }
62 |
63 | @DeleteMapping("/delete/{commentId}")
64 | @ApiOperation("删除评论")
65 | public R delete(@PathVariable("commentId") @Min(1) Integer commentId) {
66 | int i = commentService.deleteById(commentId);
67 | return RUtils.commonFailOrNot(i, "删除评论");
68 | }
69 |
70 | @DeleteMapping("/delete")
71 | @ApiOperation("批量删除评论")
72 | public R delete(@RequestBody @Validated ListParam commentIds) {
73 | int i = commentService.deleteByIds(commentIds);
74 | return RUtils.commonFailOrNot(i, "批量删除评论");
75 | }
76 |
77 | @PostMapping("/reply")
78 | @ApiOperation("回复评论")
79 | public R reply(@RequestBody @Validated(CommentSimpleVO.Admin.class) CommentDetailVO vo) {
80 | int i = commentService.reply(vo);
81 | return RUtils.commonFailOrNot(i, "回复评论");
82 | }
83 |
84 |
85 | }
86 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/controller/admin/LinkController.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.controller.admin;
2 |
3 |
4 | import com.baomidou.mybatisplus.core.metadata.IPage;
5 | import io.swagger.annotations.Api;
6 | import io.swagger.annotations.ApiOperation;
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.lang.NonNull;
9 | import org.springframework.validation.annotation.Validated;
10 | import org.springframework.web.bind.annotation.*;
11 | import xyz.snwjas.blog.constant.OtherOptionEnum;
12 | import xyz.snwjas.blog.model.base.ValidGroupType;
13 | import xyz.snwjas.blog.model.entity.LinkEntity;
14 | import xyz.snwjas.blog.model.params.LinkSearchParam;
15 | import xyz.snwjas.blog.model.vo.LinkVO;
16 | import xyz.snwjas.blog.service.LinkService;
17 | import xyz.snwjas.blog.model.PageResult;
18 | import xyz.snwjas.blog.model.R;
19 | import xyz.snwjas.blog.service.OptionsService;
20 | import xyz.snwjas.blog.utils.RUtils;
21 |
22 | import javax.validation.Valid;
23 | import javax.validation.constraints.Min;
24 |
25 | /**
26 | * Link Controller
27 | *
28 | * @author Myles Yang
29 | */
30 | @Validated
31 | @RestController("AdminLinkController")
32 | @RequestMapping("/api/admin/link")
33 | @Api(value = "后台友链控制器", tags = {"后台友链接口"})
34 | public class LinkController {
35 |
36 | @Autowired
37 | private LinkService linkService;
38 |
39 | @Autowired
40 | private OptionsService optionsService;
41 |
42 |
43 | @PostMapping("/list")
44 | @ApiOperation("获取友链列表信息")
45 | public R list(@RequestBody @Valid LinkSearchParam param) {
46 | IPage page = linkService.pageBy(param);
47 | PageResult pageResult = linkService.covertToPageResult(page);
48 | return RUtils.success("友链列表信息", pageResult);
49 | }
50 |
51 | @PostMapping("/update")
52 | @ApiOperation("更新友链信息")
53 | public R updateBlog(@RequestBody @Validated(ValidGroupType.Update.class) LinkVO vo) {
54 | int i = linkService.update(vo);
55 | return RUtils.commonFailOrNot(i, "友链信息更新");
56 | }
57 |
58 | @DeleteMapping("/delete/{linkId}")
59 | @ApiOperation("删除友链")
60 | public R deleteBlog(@PathVariable("linkId") @Min(1) Integer linkId) {
61 | int i = linkService.deleteById(linkId);
62 | return RUtils.commonFailOrNot(i, "删除友链");
63 | }
64 |
65 | @PostMapping("/add")
66 | @ApiOperation("添加友链")
67 | public R addBlog(@RequestBody @Validated(ValidGroupType.Save.class) LinkVO vo) {
68 | int i = linkService.add(vo);
69 | return RUtils.commonFailOrNot(i, "友链添加");
70 | }
71 |
72 | @PostMapping("/update/parser")
73 | @ApiOperation("更新网站Logo(favicon)解析API")
74 | public R updateUrlLogoParser(@RequestParam("parser") @NonNull String logoParser) {
75 | int i = optionsService.setAnyway(OtherOptionEnum.URL_FAVICON_PARSER.key(), logoParser);
76 | if (i > 0) {
77 | int j = linkService.updateLogoParser(logoParser);
78 | if (j > 0) {
79 | optionsService.resetOptionsCache();
80 | }
81 | }
82 | return RUtils.commonFailOrNot(i, "友链Logo解析API修改");
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/controller/admin/LogController.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.controller.admin;
2 |
3 | import com.baomidou.mybatisplus.core.metadata.IPage;
4 | import io.swagger.annotations.Api;
5 | import io.swagger.annotations.ApiOperation;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.validation.annotation.Validated;
8 | import org.springframework.web.bind.annotation.*;
9 | import xyz.snwjas.blog.model.PageResult;
10 | import xyz.snwjas.blog.model.R;
11 | import xyz.snwjas.blog.model.entity.LogEntity;
12 | import xyz.snwjas.blog.model.params.ListParam;
13 | import xyz.snwjas.blog.model.params.LogSearchParam;
14 | import xyz.snwjas.blog.model.vo.LogVO;
15 | import xyz.snwjas.blog.service.LogService;
16 | import xyz.snwjas.blog.utils.RUtils;
17 |
18 | import javax.validation.Valid;
19 |
20 | /**
21 | * Log Controller
22 | *
23 | * @author Myles Yang
24 | */
25 | @Validated
26 | @RestController("AdminLogController")
27 | @RequestMapping("/api/admin/log")
28 | @Api(value = "后台日志控制器", tags = {"后台日志接口"})
29 | public class LogController {
30 |
31 | @Autowired
32 | private LogService logService;
33 |
34 |
35 | @PostMapping("/list")
36 | @ApiOperation("获取日志列表信息")
37 | public R listBlogs(@RequestBody @Valid LogSearchParam param) {
38 | IPage page = logService.pageBy(param);
39 | PageResult pageResult = logService.covertToPageResult(page);
40 | return RUtils.success("日志列表信息", pageResult);
41 | }
42 |
43 | @DeleteMapping("/delete")
44 | @ApiOperation("批量删除评论")
45 | public R delete(@RequestBody @Validated ListParam logIds) {
46 | int i = logService.deleteByIds(logIds);
47 | return RUtils.commonFailOrNot(i, "批量删除日志");
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/controller/admin/OptionsController.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.controller.admin;
2 |
3 |
4 | import io.swagger.annotations.Api;
5 | import io.swagger.annotations.ApiOperation;
6 | import lombok.extern.slf4j.Slf4j;
7 | import net.coobird.thumbnailator.Thumbnails;
8 | import org.springframework.beans.factory.annotation.Autowired;
9 | import org.springframework.scheduling.annotation.Async;
10 | import org.springframework.util.StringUtils;
11 | import org.springframework.web.bind.annotation.*;
12 | import xyz.snwjas.blog.config.properties.MyBlogProperties;
13 | import xyz.snwjas.blog.service.OptionsService;
14 | import xyz.snwjas.blog.model.R;
15 | import xyz.snwjas.blog.utils.RUtils;
16 | import xyz.snwjas.blog.utils.URLUtils;
17 |
18 | import java.io.BufferedInputStream;
19 | import java.io.File;
20 | import java.net.URL;
21 | import java.net.URLConnection;
22 | import java.util.Map;
23 | import java.util.Objects;
24 | import java.util.concurrent.atomic.AtomicInteger;
25 |
26 | /**
27 | * Option Controller
28 | *
29 | * @author Myles Yang
30 | */
31 | @Slf4j
32 | @RestController("AdminOptionsController")
33 | @RequestMapping("/api/admin/option")
34 | @Api(value = "后台设置控制器", tags = {"后台设置选项接口"})
35 | public class OptionsController {
36 |
37 | @Autowired
38 | private OptionsService optionsService;
39 |
40 | @Autowired
41 | private MyBlogProperties properties;
42 |
43 | @ApiOperation("获取所有的博客设置")
44 | @GetMapping("/list")
45 | public R listAll() {
46 | Map optionsMap = optionsService.listAll();
47 | return RUtils.success("所有的博客设置", optionsMap);
48 | }
49 |
50 | @ApiOperation("修改博客设置")
51 | @PostMapping("/update")
52 | public R update(@RequestBody Map optionMap) {
53 | // 修改成功的数量
54 | AtomicInteger count = new AtomicInteger();
55 | optionMap.forEach((key, value) -> {
56 | if (StringUtils.hasText(key) && Objects.nonNull(value)) {
57 | int i = optionsService.setAnyway(key, String.valueOf(value));
58 | if (i > 0) {
59 | count.getAndIncrement();
60 | }
61 | // 保存 favicon
62 | // if (MyBlogOptionEnum.FAVICON.key().equals(key)) {
63 | // saveFavicon(String.valueOf(value));
64 | // }
65 | }
66 | });
67 |
68 | if (count.get() > 0) {
69 | optionsService.resetOptionsCache();
70 | return RUtils.success("博客设置修改成功");
71 | }
72 |
73 | return RUtils.success("博客设置未作修改");
74 | }
75 |
76 | /**
77 | * 保存 favicon 到文件中
78 | */
79 | @Async("executor")
80 | public void saveFavicon(String url) {
81 | String savePath = properties.getFileSavePath() + File.separatorChar + "favicon.ico";
82 |
83 | try (BufferedInputStream bis = new BufferedInputStream(
84 | new URL(URLUtils.encodeAll(url)).openStream())) {
85 | // 不是图片
86 | String contentType = URLConnection.guessContentTypeFromStream(bis);
87 | if (!(StringUtils.hasText(contentType) && contentType.startsWith("image"))) {
88 | log.warn("not an image url: {}", url);
89 | return;
90 | }
91 | // 压缩图片
92 | Thumbnails.of(bis)
93 | .size(32, 32)
94 | .outputFormat("jpg") // ico不支持
95 | .toFile(savePath);
96 | } catch (Exception e) {
97 | log.warn("favicon.icon url is invalid.");
98 | }
99 | }
100 |
101 | }
102 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/controller/admin/SpeciallistController.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.controller.admin;
2 |
3 | import com.baomidou.mybatisplus.core.metadata.IPage;
4 | import io.swagger.annotations.Api;
5 | import io.swagger.annotations.ApiOperation;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.validation.annotation.Validated;
8 | import org.springframework.web.bind.annotation.*;
9 | import xyz.snwjas.blog.model.PageResult;
10 | import xyz.snwjas.blog.model.R;
11 | import xyz.snwjas.blog.model.entity.SpeciallistEntity;
12 | import xyz.snwjas.blog.model.enums.SpecialListType;
13 | import xyz.snwjas.blog.model.params.ListParam;
14 | import xyz.snwjas.blog.model.params.SpeciallistSearchParam;
15 | import xyz.snwjas.blog.model.vo.SpeciallistVO;
16 | import xyz.snwjas.blog.service.SpeciallistService;
17 | import xyz.snwjas.blog.utils.RUtils;
18 |
19 | import javax.validation.Valid;
20 | import javax.validation.constraints.NotNull;
21 | import java.util.List;
22 |
23 | /**
24 | * Log Controller
25 | *
26 | * @author Myles Yang
27 | */
28 | @Validated
29 | @RestController("AdminSpeciallistController")
30 | @RequestMapping("/api/admin/speciallist")
31 | @Api(value = "后台特殊清单控制器", tags = {"后台特殊清单接口"})
32 | public class SpeciallistController {
33 |
34 | @Autowired
35 | private SpeciallistService speciallistService;
36 |
37 |
38 | @PostMapping("/list")
39 | @ApiOperation("获取清单列表")
40 | public R listBlogs(@RequestBody @Valid SpeciallistSearchParam param) {
41 | IPage page = speciallistService.pageBy(param);
42 | PageResult pageResult = speciallistService.covertToPageResult(page);
43 | return RUtils.success("清单列表", pageResult);
44 | }
45 |
46 | @DeleteMapping("/delete")
47 | @ApiOperation("批量删除清单")
48 | public R delete(@RequestBody @Validated ListParam ids) {
49 | int i = speciallistService.deleteByIds(ids);
50 | return RUtils.commonFailOrNot(i, "批量删除清单");
51 | }
52 |
53 | @PostMapping("/add")
54 | @ApiOperation("批量导入清单")
55 | public R addBatch(@RequestParam("type") @NotNull SpecialListType type,
56 | @RequestParam("content") @Validated ListParam contents) {
57 | boolean b = speciallistService.addBatch(type, contents);
58 | return RUtils.commonFailOrNot(b ? 1 : 0, "批量导入清单");
59 | }
60 |
61 | @GetMapping("/types")
62 | @ApiOperation("列出所有已枚举清单类型")
63 | public R listTypes() {
64 | List types = speciallistService.listEnumType();
65 | return RUtils.success("已枚举清单类型", types);
66 | }
67 |
68 | @GetMapping("/refresh-context/{type}")
69 | @ApiOperation("刷新上下文")
70 | public R refreshContext(@PathVariable("type") @NotNull SpecialListType type) {
71 | boolean succeed = speciallistService.refreshContext(type);
72 | return RUtils.commonFailOrNot(succeed ? 1 : 0, String.format("刷新上下文[%s]", type));
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/controller/admin/StatisticsController.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.controller.admin;
2 |
3 | import io.swagger.annotations.Api;
4 | import io.swagger.annotations.ApiOperation;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.format.annotation.DateTimeFormat;
7 | import org.springframework.validation.annotation.Validated;
8 | import org.springframework.web.bind.annotation.GetMapping;
9 | import org.springframework.web.bind.annotation.PathVariable;
10 | import org.springframework.web.bind.annotation.RequestMapping;
11 | import org.springframework.web.bind.annotation.RestController;
12 | import xyz.snwjas.blog.config.LocalDateTimeSerializerConfig;
13 | import xyz.snwjas.blog.model.R;
14 | import xyz.snwjas.blog.model.vo.StatisticsBasicVO;
15 | import xyz.snwjas.blog.model.vo.StatisticsReportVo;
16 | import xyz.snwjas.blog.service.impl.StatisticsServiceImpl;
17 | import xyz.snwjas.blog.utils.RUtils;
18 |
19 | import java.time.LocalDateTime;
20 | import java.util.List;
21 |
22 | /**
23 | * Admin Controller
24 | *
25 | * @author Myles Yang
26 | */
27 | @Validated
28 | @RestController("AdminStatisticsController")
29 | @RequestMapping("/api/admin/statistics")
30 | @Api(value = "后台统计控制器", tags = {"后台统计接口"})
31 | public class StatisticsController {
32 |
33 | @Autowired
34 | private StatisticsServiceImpl statisticsService;
35 |
36 |
37 | @GetMapping("/common")
38 | @ApiOperation("获取基本的统计信息")
39 | public R getCommonStatistics() {
40 | StatisticsBasicVO statisticsBasicVo = statisticsService.getCommonStatistics();
41 | return RUtils.success("统计信息", statisticsBasicVo);
42 | }
43 |
44 | @GetMapping("/daily/{start}/{end}")
45 | @ApiOperation("获取每日的统计信息")
46 | public R getDailyStatistics(@PathVariable("start") @DateTimeFormat(pattern =
47 | LocalDateTimeSerializerConfig.DEFAULT_DATE_TIME_PATTERN) LocalDateTime start,
48 | @PathVariable("end") @DateTimeFormat(pattern =
49 | LocalDateTimeSerializerConfig.DEFAULT_DATE_TIME_PATTERN) LocalDateTime end) {
50 | List list = statisticsService.getDailyStatistics(start, end);
51 | return RUtils.success("每日的统计数据", list);
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/controller/admin/TagController.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.controller.admin;
2 |
3 |
4 | import io.swagger.annotations.Api;
5 | import io.swagger.annotations.ApiOperation;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.validation.annotation.Validated;
8 | import org.springframework.web.bind.annotation.*;
9 | import xyz.snwjas.blog.model.base.ValidGroupType;
10 | import xyz.snwjas.blog.model.vo.TagVO;
11 | import xyz.snwjas.blog.service.TagService;
12 | import xyz.snwjas.blog.model.R;
13 | import xyz.snwjas.blog.utils.RUtils;
14 |
15 | import javax.validation.constraints.Min;
16 | import javax.validation.constraints.NotNull;
17 | import java.util.List;
18 |
19 | /**
20 | *
21 | * 标签 前端控制器
22 | *
23 | *
24 | * @author Myles Yang
25 | */
26 | @Validated
27 | @RestController("AdminTagController")
28 | @RequestMapping("/api/admin/blog/tag")
29 | @Api(value = "后台标签控制器", tags = {"后台标签接口"})
30 | public class TagController {
31 |
32 | @Autowired
33 | private TagService tagService;
34 |
35 | @GetMapping("/list")
36 | @ApiOperation("获取所有的博客标签")
37 | public R listAllTags() {
38 | List tagVOList = tagService.listAll();
39 | return RUtils.success("所有的博客标签", tagVOList);
40 | }
41 |
42 | @DeleteMapping("/delete/{tagId}")
43 | @ApiOperation("删除标签")
44 | public R delete(@PathVariable("tagId") @NotNull @Min(1) Integer tagId) {
45 | int i = tagService.deleteById(tagId);
46 | return RUtils.commonFailOrNot(i, "标签删除");
47 | }
48 |
49 | @PostMapping("/add")
50 | @ApiOperation("添加标签")
51 | public R add(@RequestBody @Validated({ValidGroupType.Save.class}) TagVO vo) {
52 | int i = tagService.add(vo);
53 | if (i > 0) {
54 | return RUtils.success("标签添加成功");
55 | }
56 | if (i < 0) {
57 | return RUtils.fail("标签名已存在");
58 | }
59 | return RUtils.fail("标签添加失败");
60 | }
61 |
62 | @PostMapping("/update")
63 | @ApiOperation("更新标签")
64 | public R update(@RequestBody @Validated({ValidGroupType.Update.class}) TagVO vo) {
65 | int i = tagService.update(vo);
66 | return RUtils.commonFailOrNot(i, "标签更新");
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/controller/app/BlogController.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.controller.app;
2 |
3 | import com.baomidou.mybatisplus.core.metadata.IPage;
4 | import io.swagger.annotations.Api;
5 | import io.swagger.annotations.ApiOperation;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.validation.annotation.Validated;
8 | import org.springframework.web.bind.annotation.*;
9 | import xyz.snwjas.blog.annotation.AccessLimit;
10 | import xyz.snwjas.blog.constant.CacheKeyPrefix;
11 | import xyz.snwjas.blog.constant.RS;
12 | import xyz.snwjas.blog.model.PageResult;
13 | import xyz.snwjas.blog.model.R;
14 | import xyz.snwjas.blog.model.entity.BlogEntity;
15 | import xyz.snwjas.blog.model.enums.BlogStatus;
16 | import xyz.snwjas.blog.model.params.BlogSearchParam;
17 | import xyz.snwjas.blog.model.vo.BlogArchiveVO;
18 | import xyz.snwjas.blog.model.vo.BlogDetailVO;
19 | import xyz.snwjas.blog.model.vo.BlogSimpleVO;
20 | import xyz.snwjas.blog.service.BlogService;
21 | import xyz.snwjas.blog.support.cache.MemoryCacheStore;
22 | import xyz.snwjas.blog.utils.IPUtils;
23 | import xyz.snwjas.blog.utils.RUtils;
24 | import xyz.snwjas.blog.utils.URLUtils;
25 |
26 | import javax.servlet.http.HttpServletRequest;
27 | import javax.validation.constraints.Min;
28 | import javax.validation.constraints.NotBlank;
29 | import java.util.List;
30 | import java.util.Map;
31 | import java.util.Objects;
32 |
33 | /**
34 | * Blog Controller
35 | *
36 | * @author Myles Yang
37 | */
38 | @Validated
39 | @RestController("AppBlogController")
40 | @RequestMapping("/api/app/blog")
41 | @Api(value = "前台博客控制器", tags = {"前台博客文章接口"})
42 | public class BlogController {
43 |
44 | private static final int PAGE_SIZE = 10;
45 |
46 | @Autowired
47 | private BlogService blogService;
48 |
49 | @Autowired
50 | private MemoryCacheStore cache;
51 |
52 | @AccessLimit(maxCount = 2)
53 | @PostMapping("/list")
54 | @ApiOperation("条件获取博客文章列表")
55 | public R listBlogs(@RequestBody @Validated BlogSearchParam param) {
56 |
57 | param.setStatus(BlogStatus.PUBLISHED);
58 | param.setPageSize(PAGE_SIZE);
59 |
60 | IPage blogPage = blogService.pageBy(param);
61 | PageResult pageResult = blogService.covertToPageResult(blogPage);
62 |
63 | return RUtils.success("博客文章列表", pageResult);
64 | }
65 |
66 | @AccessLimit(maxCount = 1)
67 | @GetMapping("/list/achievement")
68 | @ApiOperation("获取文章归档")
69 | public R listAchievement() {
70 | Map> map = blogService.listArchive();
71 |
72 | return RUtils.success("文章归档", map);
73 | }
74 |
75 | @AccessLimit(maxCount = 2)
76 | @GetMapping("/content/{blogUrl}")
77 | @ApiOperation("获取博客文章内容")
78 | public R getBlog(HttpServletRequest request,
79 | @PathVariable("blogUrl") @NotBlank String blogUrl) {
80 |
81 | String url = URLUtils.decode(blogUrl);
82 | BlogDetailVO blogContent = blogService.getByUrl(url);
83 |
84 | if (Objects.nonNull(blogContent)) {
85 | blogContent.setOriginalContent("");
86 |
87 | // 统计博客访问人数
88 | String ipAddress = IPUtils.getIpAddress(request);
89 | // 缓存在会在 StatisticTask 中清除
90 | String key = CacheKeyPrefix.BLOG_VISIT_COUNT + blogContent.getId()
91 | + CacheKeyPrefix.SEPARATOR + ipAddress;
92 | cache.setIfAbsent(key, null);
93 | }
94 |
95 | return RUtils.success("博客文章内容", blogContent);
96 | }
97 |
98 | @AccessLimit(maxCount = 3)
99 | @GetMapping("/like/{blogId}")
100 | @ApiOperation("点赞博客")
101 | public R like(@PathVariable("blogId") @Min(1) Integer blogId) {
102 | int like = blogService.like(blogId);
103 | if (like == 0) {
104 | return RUtils.fail(RS.ILLEGAL_PARAMETER);
105 | }
106 | if (like == -1) {
107 | return RUtils.success("取消点赞", like);
108 | }
109 | return RUtils.success("点赞成功", like);
110 | }
111 |
112 | }
113 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/controller/app/CategoryController.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.controller.app;
2 |
3 | import io.swagger.annotations.Api;
4 | import io.swagger.annotations.ApiOperation;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.web.bind.annotation.GetMapping;
7 | import org.springframework.web.bind.annotation.RequestMapping;
8 | import org.springframework.web.bind.annotation.RestController;
9 | import xyz.snwjas.blog.annotation.AccessLimit;
10 | import xyz.snwjas.blog.model.enums.BlogStatus;
11 | import xyz.snwjas.blog.model.vo.CategoryVO;
12 | import xyz.snwjas.blog.service.BlogService;
13 | import xyz.snwjas.blog.service.CategoryService;
14 | import xyz.snwjas.blog.model.R;
15 | import xyz.snwjas.blog.utils.RUtils;
16 |
17 | import java.util.List;
18 |
19 | /**
20 | * Category Controller
21 | *
22 | * @author Myles Yang
23 | */
24 | @RestController("AppCategoryController")
25 | @RequestMapping("/api/app/category")
26 | @Api(value = "前台分类控制器", tags = {"前台分类接口"})
27 | public class CategoryController {
28 |
29 | @Autowired
30 | private CategoryService categoryService;
31 |
32 | @Autowired
33 | private BlogService blogService;
34 |
35 |
36 | @AccessLimit(maxCount = 2)
37 | @GetMapping("/list")
38 | @ApiOperation("获取已使用的分类")
39 | public R listUsedCategory() {
40 | List usedCategoryList = categoryService.listUsedCategory();
41 | // 获取每个分类下的文章数目
42 | for (CategoryVO vo : usedCategoryList) {
43 | int count = blogService.getCountByCategoryId(vo.getId(), BlogStatus.PUBLISHED);
44 | vo.setBlogCount(count);
45 | }
46 | return RUtils.success("分类列表", usedCategoryList);
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/controller/app/CommentController.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.controller.app;
2 |
3 | import com.baomidou.mybatisplus.core.metadata.IPage;
4 | import io.swagger.annotations.Api;
5 | import io.swagger.annotations.ApiOperation;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.validation.annotation.Validated;
8 | import org.springframework.web.bind.annotation.*;
9 | import xyz.snwjas.blog.annotation.AccessLimit;
10 | import xyz.snwjas.blog.model.PageResult;
11 | import xyz.snwjas.blog.model.R;
12 | import xyz.snwjas.blog.model.entity.CommentEntity;
13 | import xyz.snwjas.blog.model.enums.CommentStatus;
14 | import xyz.snwjas.blog.model.params.BasePageParam;
15 | import xyz.snwjas.blog.model.vo.CommentDetailVO;
16 | import xyz.snwjas.blog.model.vo.CommentSimpleVO;
17 | import xyz.snwjas.blog.service.CommentService;
18 | import xyz.snwjas.blog.support.wordfilter.WordFilter;
19 | import xyz.snwjas.blog.utils.RUtils;
20 | import xyz.snwjas.blog.utils.StrUtils;
21 |
22 | import javax.validation.constraints.Min;
23 | import javax.validation.constraints.NotNull;
24 | import java.util.HashMap;
25 |
26 | /**
27 | * Comment Controller
28 | *
29 | * @author Myles Yang
30 | */
31 | @Validated
32 | @RestController("AppCommentController")
33 | @RequestMapping("/api/app/comment")
34 | @Api(value = "前台评论控制器", tags = {"前台评论接口"})
35 | public class CommentController {
36 |
37 | private static final int PAGE_SIZE = 7;
38 |
39 | @Autowired
40 | private CommentService commentService;
41 |
42 | @Autowired
43 | private WordFilter wordFilter;
44 |
45 | @AccessLimit(maxCount = 5)
46 | @PostMapping("/list")
47 | @ApiOperation("获取评论列表")
48 | public R listComments(@RequestParam("bid") @NotNull @Min(1) Integer blogId,
49 | @RequestParam("pid") @NotNull @Min(0) Integer parentId,
50 | @RequestParam("cur") @NotNull @Min(1) Integer current) {
51 |
52 | BasePageParam param = new BasePageParam()
53 | .setCurrent(current)
54 | .setPageSize(PAGE_SIZE);
55 | IPage entityPage = commentService.pageBy(blogId, parentId, param);
56 | PageResult pageResult = commentService.covertToSimplePageResult(entityPage);
57 |
58 | return RUtils.success("评论列表", pageResult);
59 | }
60 |
61 | @AccessLimit(maxCount = 5)
62 | @PostMapping("/listr")
63 | @ApiOperation("顶层往下递归获取所有评论")
64 | public R listComments(@RequestParam("bid") @NotNull @Min(1) Integer blogId,
65 | @RequestParam("cur") @NotNull @Min(1) Integer current) {
66 |
67 | BasePageParam param = new BasePageParam()
68 | .setCurrent(current)
69 | .setPageSize(PAGE_SIZE);
70 | IPage entityPage = commentService.pageBy(blogId, param);
71 | PageResult pageResult = commentService.covertToSimplePageResultByRecursively(entityPage);
72 |
73 | // 获取评论总数
74 | int count = commentService.getCountByBlogIdAndStatus(blogId, CommentStatus.PUBLISHED);
75 |
76 | HashMap map = new HashMap<>(4);
77 | map.put("all", count);
78 | map.put("total", pageResult.getTotal());
79 | map.put("list", pageResult.getList());
80 |
81 | return RUtils.success("评论列表", map);
82 | }
83 |
84 | @AccessLimit(maxCount = 5)
85 | @PostMapping("/publish")
86 | @ApiOperation("发表评论")
87 | public R publishComment(@RequestBody @Validated(CommentSimpleVO.Guest.class) CommentDetailVO vo) {
88 |
89 | String author = StrUtils.removeBlank(vo.getAuthor());
90 | vo.setAuthor(wordFilter.replace(author));
91 | String content = StrUtils.removeBlank(vo.getContent());
92 | vo.setContent(wordFilter.replace(content));
93 | int i = commentService.reply(vo);
94 | return RUtils.commonFailOrNot(i, "评论发表");
95 | }
96 |
97 | }
98 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/controller/app/IndexController.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.controller.app;
2 |
3 | import io.swagger.annotations.Api;
4 | import io.swagger.annotations.ApiOperation;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.web.bind.annotation.GetMapping;
7 | import org.springframework.web.bind.annotation.RequestMapping;
8 | import org.springframework.web.bind.annotation.RestController;
9 | import xyz.snwjas.blog.annotation.AccessLimit;
10 | import xyz.snwjas.blog.constant.MyBlogOptionEnum;
11 | import xyz.snwjas.blog.model.vo.OptionVO;
12 | import xyz.snwjas.blog.model.vo.UserVO;
13 | import xyz.snwjas.blog.service.OptionsService;
14 | import xyz.snwjas.blog.service.StatisticsService;
15 | import xyz.snwjas.blog.service.UserService;
16 | import xyz.snwjas.blog.model.R;
17 | import xyz.snwjas.blog.model.UserDetail;
18 | import xyz.snwjas.blog.utils.RUtils;
19 |
20 | import java.time.LocalDateTime;
21 | import java.util.Map;
22 |
23 | /**
24 | * Index Controller
25 | *
26 | * @author Myles Yang
27 | */
28 | @RestController("AppIndexController")
29 | @RequestMapping("/api/app")
30 | @Api(value = "前台通用控制器", tags = {"前台通用接口"})
31 | public class IndexController {
32 |
33 | @Autowired
34 | private OptionsService optionsService;
35 |
36 | @Autowired
37 | private StatisticsService statisticsService;
38 |
39 | @Autowired
40 | private UserService userService;
41 |
42 | @AccessLimit(maxCount = 1)
43 | @GetMapping("/attributes")
44 | @ApiOperation("获取博客的基本属性")
45 | public R getAttributes() {
46 |
47 | Map attributes = optionsService.listNecessary();
48 |
49 | // 建站日期
50 | MyBlogOptionEnum birthdayEnum = MyBlogOptionEnum.BIRTHDAY;
51 | OptionVO birthdayVO = optionsService.get(birthdayEnum.key());
52 | LocalDateTime birthday = LocalDateTime.parse(birthdayVO.getOptionValue());
53 | attributes.put(birthdayEnum.key(), birthday);
54 |
55 | // 页脚
56 | MyBlogOptionEnum footerEnum = MyBlogOptionEnum.FOOTER;
57 | OptionVO footerVO = optionsService.get(footerEnum.key());
58 | attributes.put(footerEnum.key(), footerVO.getOptionValue());
59 |
60 | // 网站访问数量
61 | int webTotalVisit = statisticsService.getWebTotalVisit();
62 | attributes.put("visit", webTotalVisit);
63 |
64 | return RUtils.success("基本属性", attributes);
65 | }
66 |
67 | @AccessLimit(maxCount = 1)
68 | @GetMapping("/about-me")
69 | @ApiOperation("关于我")
70 | public R getAboutMe() {
71 | // 确保账号id为1
72 | UserDetail userDetail = userService.getByUserId(1);
73 | UserVO userVO = new UserVO().convertFrom(userDetail);
74 | userVO.setUsername("");
75 |
76 | return RUtils.success("关于我", userVO);
77 | }
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/controller/app/LinkController.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.controller.app;
2 |
3 | import com.baomidou.mybatisplus.core.metadata.IPage;
4 | import io.swagger.annotations.Api;
5 | import io.swagger.annotations.ApiOperation;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.web.bind.annotation.GetMapping;
8 | import org.springframework.web.bind.annotation.RequestMapping;
9 | import org.springframework.web.bind.annotation.RestController;
10 | import xyz.snwjas.blog.annotation.AccessLimit;
11 | import xyz.snwjas.blog.model.entity.LinkEntity;
12 | import xyz.snwjas.blog.model.params.LinkSearchParam;
13 | import xyz.snwjas.blog.model.vo.LinkVO;
14 | import xyz.snwjas.blog.service.LinkService;
15 | import xyz.snwjas.blog.model.R;
16 | import xyz.snwjas.blog.utils.RUtils;
17 |
18 | import java.util.List;
19 |
20 | /**
21 | * Link Controller
22 | *
23 | * @author Myles Yang
24 | */
25 | @RestController("AppLinkController")
26 | @RequestMapping("/api/app/link")
27 | @Api(value = "前台友链控制器", tags = {"前台友链接口"})
28 | public class LinkController {
29 |
30 | @Autowired
31 | private LinkService linkService;
32 |
33 | @AccessLimit(maxCount = 2)
34 | @GetMapping("/list")
35 | @ApiOperation("获取所有的友情链接")
36 | public R listUsedCategory() {
37 | LinkSearchParam param = new LinkSearchParam();
38 | param.setCurrent(1).setPageSize(Integer.MAX_VALUE);
39 | IPage linkPage = linkService.pageBy(param);
40 | List linkVOList = linkService.covertToListVO(linkPage.getRecords());
41 | return RUtils.success("友链列表", linkVOList);
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/controller/app/TagController.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.controller.app;
2 |
3 | import io.swagger.annotations.Api;
4 | import io.swagger.annotations.ApiOperation;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.validation.annotation.Validated;
7 | import org.springframework.web.bind.annotation.GetMapping;
8 | import org.springframework.web.bind.annotation.RequestMapping;
9 | import org.springframework.web.bind.annotation.RestController;
10 | import xyz.snwjas.blog.annotation.AccessLimit;
11 | import xyz.snwjas.blog.model.vo.TagVO;
12 | import xyz.snwjas.blog.service.TagService;
13 | import xyz.snwjas.blog.model.R;
14 | import xyz.snwjas.blog.utils.RUtils;
15 |
16 | import java.util.List;
17 |
18 | /**
19 | * Tag Controller
20 | *
21 | * @author Myles Yang
22 | */
23 | @Validated
24 | @RestController("AppTagController")
25 | @RequestMapping("/api/app/tag")
26 | @Api(value = "前台标签控制器", tags = {"前台标签接口"})
27 | public class TagController {
28 |
29 | @Autowired
30 | private TagService tagService;
31 |
32 | @AccessLimit(maxCount = 2)
33 | @GetMapping("/list")
34 | @ApiOperation("获取全部已使用的博客标签")
35 | public R listUsed() {
36 | List tagVOList = tagService.listUsed();
37 | return RUtils.success("博客标签", tagVOList);
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/exception/MyBlogException.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.exception;
2 |
3 | /**
4 | * Base exception of the project.
5 | *
6 | * @author Myles Yang
7 | */
8 | public abstract class MyBlogException extends RuntimeException {
9 |
10 | private static final long serialVersionUID = 4140200838147465959L;
11 |
12 | private Object errorData;
13 |
14 | public MyBlogException(String message) {
15 | super(message);
16 | }
17 |
18 | public MyBlogException(String message, Throwable cause) {
19 | super(message, cause);
20 | }
21 |
22 | public abstract int getStatus();
23 |
24 | public Object getErrorData() {
25 | return errorData;
26 | }
27 |
28 | public void setErrorData(Object errorData) {
29 | this.errorData = errorData;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/exception/ServiceException.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.exception;
2 |
3 | import org.springframework.http.HttpStatus;
4 | import xyz.snwjas.blog.constant.RS;
5 |
6 | /**
7 | * 服务异常
8 | *
9 | * @author Myles Yang
10 | */
11 | public class ServiceException extends MyBlogException {
12 |
13 | private static final long serialVersionUID = 7951201720502956459L;
14 |
15 | private final int status;
16 |
17 | public ServiceException() {
18 | super(RS.SYSTEM_ERROR.message());
19 | this.status = RS.SYSTEM_ERROR.status();
20 | }
21 |
22 | public ServiceException(String message) {
23 | super(message);
24 | this.status = RS.SYSTEM_ERROR.status();
25 | }
26 |
27 | public ServiceException(String message, Throwable cause) {
28 | super(message, cause);
29 | this.status = RS.SYSTEM_ERROR.status();
30 | }
31 |
32 | public ServiceException(RS status) {
33 | super(status.message());
34 | this.status = status.status();
35 | }
36 |
37 | public ServiceException(HttpStatus status) {
38 | super(status.getReasonPhrase());
39 | this.status = status.value();
40 | }
41 |
42 | @Override
43 | public int getStatus() {
44 | return status;
45 | }
46 |
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/interceptor/AccessLimitInterceptor.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.interceptor;
2 |
3 | import org.springframework.stereotype.Component;
4 | import org.springframework.web.method.HandlerMethod;
5 | import org.springframework.web.servlet.HandlerInterceptor;
6 | import xyz.snwjas.blog.annotation.AccessLimit;
7 | import xyz.snwjas.blog.constant.CacheKeyPrefix;
8 | import xyz.snwjas.blog.constant.RS;
9 | import xyz.snwjas.blog.exception.ServiceException;
10 | import xyz.snwjas.blog.support.cache.MemoryCacheStore;
11 | import xyz.snwjas.blog.utils.IPUtils;
12 |
13 | import javax.servlet.http.HttpServletRequest;
14 | import javax.servlet.http.HttpServletResponse;
15 | import java.lang.reflect.Method;
16 | import java.util.Objects;
17 |
18 | /**
19 | * 接口限流防刷拦截器
20 | *
21 | * @author Myles Yang
22 | */
23 | @Component
24 | public class AccessLimitInterceptor implements HandlerInterceptor {
25 |
26 | private final MemoryCacheStore memoryCacheStore;
27 |
28 | public AccessLimitInterceptor(MemoryCacheStore memoryCacheStore) {
29 | this.memoryCacheStore = memoryCacheStore;
30 | }
31 |
32 | @Override
33 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
34 | if (!(handler instanceof HandlerMethod)) {
35 | return true;
36 | }
37 |
38 | HandlerMethod handlerMethod = (HandlerMethod) handler;
39 | Method method = handlerMethod.getMethod();
40 |
41 | AccessLimit annotation = method.getAnnotation(AccessLimit.class);
42 | if (Objects.nonNull(annotation)) {
43 | check(annotation, request);
44 | }
45 |
46 | return true;
47 | }
48 |
49 | private void check(AccessLimit annotation, HttpServletRequest request) {
50 |
51 | int maxCount = annotation.maxCount();
52 | int seconds = annotation.seconds();
53 |
54 | String key = CacheKeyPrefix.ACCESS_LIMIT_PREFIX
55 | + IPUtils.getIpAddress(request)
56 | + request.getRequestURI();
57 |
58 | Integer count = (Integer) memoryCacheStore.get(key);
59 | if (Objects.nonNull(count)) {
60 | if (count < maxCount) {
61 | memoryCacheStore.set(key, count + 1, seconds);
62 | } else {
63 | throw new ServiceException(RS.FREQUENT_OPERATION);
64 | }
65 | } else {
66 | memoryCacheStore.set(key, 1, seconds);
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/interceptor/StatisticInterceptor.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.interceptor;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.stereotype.Component;
6 | import org.springframework.web.servlet.HandlerInterceptor;
7 | import xyz.snwjas.blog.constant.CacheKeyPrefix;
8 | import xyz.snwjas.blog.support.cache.MemoryCacheStore;
9 | import xyz.snwjas.blog.utils.IPUtils;
10 |
11 | import javax.servlet.http.HttpServletRequest;
12 | import javax.servlet.http.HttpServletResponse;
13 |
14 | /**
15 | * Statistic Interceptor
16 | *
17 | * @author Myles Yang
18 | */
19 | @Component
20 | @Slf4j
21 | public class StatisticInterceptor implements HandlerInterceptor {
22 |
23 | @Autowired
24 | private MemoryCacheStore cache;
25 |
26 | @Override
27 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
28 |
29 | // 统计网站访问人数
30 |
31 | String ipAddress = IPUtils.getIpAddress(request);
32 |
33 | // 缓存在 StatisticTask 中清除
34 | String webVisitKey = CacheKeyPrefix.WEB_VISIT_COUNT + ipAddress;
35 | cache.setIfAbsent(webVisitKey, null);
36 |
37 | return true;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/mapper/AttachmentMapper.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.mapper;
2 |
3 | import xyz.snwjas.blog.model.entity.AttachmentEntity;
4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
5 |
6 | /**
7 | *
8 | * 附件 Mapper 接口
9 | *
10 | *
11 | * @author Myles Yang
12 | */
13 | public interface AttachmentMapper extends BaseMapper {
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/mapper/BlogMapper.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.mapper;
2 |
3 | import com.baomidou.mybatisplus.core.conditions.Wrapper;
4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
5 | import com.baomidou.mybatisplus.core.toolkit.Constants;
6 | import org.apache.ibatis.annotations.Param;
7 | import xyz.snwjas.blog.model.entity.BlogEntity;
8 |
9 | /**
10 | *
11 | * 博客 Mapper 接口
12 | *
13 | *
14 | * @author Myles Yang
15 | */
16 | public interface BlogMapper extends BaseMapper {
17 |
18 | /**
19 | * 对某列求和
20 | * @param column 列名
21 | * @param wrapper 条件构造器
22 | * @return 列和
23 | */
24 | Integer sum(@Param("column") String column, @Param(Constants.WRAPPER) Wrapper wrapper);
25 |
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/mapper/BlogTagMapper.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.mapper;
2 |
3 | import xyz.snwjas.blog.model.entity.BlogTagEntity;
4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
5 |
6 | /**
7 | *
8 | * 博客标签 Mapper 接口
9 | *
10 | *
11 | * @author Myles Yang
12 | */
13 | public interface BlogTagMapper extends BaseMapper {
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/mapper/CategoryMapper.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.mapper;
2 |
3 | import xyz.snwjas.blog.model.entity.CategoryEntity;
4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
5 |
6 | /**
7 | *
8 | * 分类 Mapper 接口
9 | *
10 | *
11 | * @author Myles Yang
12 | */
13 | public interface CategoryMapper extends BaseMapper {
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/mapper/CommentMapper.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.mapper;
2 |
3 | import xyz.snwjas.blog.model.entity.CommentEntity;
4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
5 |
6 | /**
7 | *
8 | * 评论 Mapper 接口
9 | *
10 | *
11 | * @author Myles Yang
12 | */
13 | public interface CommentMapper extends BaseMapper {
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/mapper/LinkMapper.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.mapper;
2 |
3 | import org.apache.ibatis.annotations.Param;
4 | import xyz.snwjas.blog.model.entity.LinkEntity;
5 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
6 |
7 | /**
8 | *
9 | * 友链 Mapper 接口
10 | *
11 | *
12 | * @author Myles Yang
13 | */
14 | public interface LinkMapper extends BaseMapper {
15 |
16 | /**
17 | * 根据Logo解析器更新全部记录Logo
18 | */
19 | Integer updateLogoByParser(@Param("parser") String parser);
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/mapper/LogMapper.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.mapper;
2 |
3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
4 | import xyz.snwjas.blog.model.entity.LogEntity;
5 |
6 | /**
7 | *
8 | * 日志 Mapper 接口
9 | *
10 | *
11 | * @author Myles Yang
12 | */
13 | public interface LogMapper extends BaseMapper {
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/mapper/OptionsMapper.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.mapper;
2 |
3 | import xyz.snwjas.blog.model.entity.OptionsEntity;
4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
5 |
6 | /**
7 | *
8 | * 系统(博客)设置 Mapper 接口
9 | *
10 | *
11 | * @author Myles Yang
12 | */
13 | public interface OptionsMapper extends BaseMapper {
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/mapper/SpecaillistMapper.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.mapper;
2 |
3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
4 | import xyz.snwjas.blog.model.entity.SpeciallistEntity;
5 |
6 | /**
7 | *
8 | * 特殊清单 Mapper 接口
9 | *
10 | *
11 | * @author Myles Yang
12 | */
13 | public interface SpecaillistMapper extends BaseMapper {
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/mapper/StatisticsMapper.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.mapper;
2 |
3 | import com.baomidou.mybatisplus.core.conditions.Wrapper;
4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
5 | import com.baomidou.mybatisplus.core.toolkit.Constants;
6 | import org.apache.ibatis.annotations.Param;
7 | import xyz.snwjas.blog.model.entity.BlogEntity;
8 | import xyz.snwjas.blog.model.entity.StatisticsEntity;
9 |
10 |
11 | /**
12 | *
13 | * 统计表(统计每日的数据) Mapper 接口
14 | *
15 | *
16 | * @author Myles Yang
17 | */
18 | public interface StatisticsMapper extends BaseMapper {
19 |
20 | /**
21 | * 对某列求和
22 | * @param column 列名
23 | * @param wrapper 条件构造器
24 | * @return 列和
25 | */
26 | Integer sum(@Param("column") String column, @Param(Constants.WRAPPER) Wrapper wrapper);
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/mapper/TagMapper.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.mapper;
2 |
3 | import xyz.snwjas.blog.model.entity.TagEntity;
4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
5 |
6 | /**
7 | *
8 | * 标签 Mapper 接口
9 | *
10 | *
11 | * @author Myles Yang
12 | */
13 | public interface TagMapper extends BaseMapper {
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/mapper/UserMapper.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.mapper;
2 |
3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
4 | import xyz.snwjas.blog.model.entity.UserEntity;
5 |
6 | /**
7 | *
8 | * 用户 Mapper 接口
9 | *
10 | *
11 | * @author Myles Yang
12 | */
13 | public interface UserMapper extends BaseMapper {
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/mapper/xml/AttachmentMapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/mapper/xml/BlogMapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
13 |
14 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/mapper/xml/BlogTagMapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/mapper/xml/CategoryMapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/mapper/xml/CommentMapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/mapper/xml/LinkMapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | update link
7 | set logo = replace(#{parser} , '{}' , url)
8 | where 1=1
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/mapper/xml/LogMapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/mapper/xml/OptionsMapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/mapper/xml/SpeciallistMapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/mapper/xml/StatisticsMapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/mapper/xml/TagMapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/mapper/xml/UserMapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/PageResult.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model;
2 |
3 | import io.swagger.annotations.ApiModel;
4 | import io.swagger.annotations.ApiModelProperty;
5 | import lombok.Data;
6 | import org.springframework.lang.NonNull;
7 |
8 | import java.io.Serializable;
9 | import java.util.List;
10 |
11 | /**
12 | * 分页结果
13 | *
14 | * @author Myles Yang
15 | */
16 | @Data
17 | @ApiModel("分页结果")
18 | public class PageResult implements Serializable {
19 |
20 | private static final long serialVersionUID = -3862949514414749919L;
21 |
22 | @ApiModelProperty("数据总条数")
23 | private long total;
24 |
25 | @ApiModelProperty("分页数据")
26 | private List list;
27 |
28 | public PageResult(@NonNull List list) {
29 | this.total = list.size();
30 | this.list = list;
31 | }
32 |
33 | public PageResult(long total, @NonNull List list) {
34 | this.total = total;
35 | this.list = list;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/R.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model;
2 |
3 | import io.swagger.annotations.ApiModel;
4 | import io.swagger.annotations.ApiModelProperty;
5 | import lombok.Data;
6 |
7 | import java.io.Serializable;
8 | import java.time.LocalDateTime;
9 |
10 | /**
11 | * 统一响应体
12 | *
13 | * @author Myles Yang
14 | */
15 | @Data
16 | @ApiModel("统一响应结果")
17 | public class R implements Serializable {
18 |
19 | private static final long serialVersionUID = -637415113996231595L;
20 |
21 | @ApiModelProperty("响应时间")
22 | private LocalDateTime timestamp;
23 |
24 | @ApiModelProperty("响应状态值")
25 | private int status;
26 |
27 | @ApiModelProperty("响应消息")
28 | private String message;
29 |
30 | @ApiModelProperty("响应数据")
31 | private Object data;
32 |
33 |
34 | public R(int status, String message, Object data) {
35 | this.timestamp = LocalDateTime.now();
36 | this.status = status;
37 | this.message = message;
38 | this.data = data;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/UserDetail.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model;
2 |
3 | import lombok.Data;
4 | import org.springframework.security.core.GrantedAuthority;
5 | import org.springframework.security.core.authority.AuthorityUtils;
6 | import org.springframework.security.core.userdetails.UserDetails;
7 | import xyz.snwjas.blog.model.base.BeanConvert;
8 |
9 | import java.util.Collection;
10 |
11 | /**
12 | * SpringSecurity 中认证的用户核心信息
13 | *
14 | * @author Myles Yang
15 | */
16 | @Data
17 | public class UserDetail implements UserDetails, BeanConvert {
18 |
19 | private static final long serialVersionUID = -1339790632097707968L;
20 |
21 | private Integer id;
22 |
23 | private String username;
24 |
25 | private String password;
26 |
27 | private String nickname;
28 |
29 | private String email;
30 |
31 | private String avatar;
32 |
33 | private String description;
34 |
35 | @Override
36 | public Collection extends GrantedAuthority> getAuthorities() {
37 | return AuthorityUtils.createAuthorityList("admin");
38 | }
39 |
40 | @Override
41 | public String getPassword() {
42 | return password;
43 | }
44 |
45 | @Override
46 | public boolean isAccountNonExpired() {
47 | return true;
48 | }
49 |
50 | @Override
51 | public boolean isAccountNonLocked() {
52 | return true;
53 | }
54 |
55 | @Override
56 | public boolean isCredentialsNonExpired() {
57 | return true;
58 | }
59 |
60 | @Override
61 | public boolean isEnabled() {
62 | return true;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/base/BeanConvert.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.base;
2 |
3 |
4 | import org.springframework.beans.BeanUtils;
5 | import org.springframework.lang.NonNull;
6 |
7 | /**
8 | * po dto vo ... bean转换
9 | *
10 | * @author Myles Yang
11 | */
12 | public interface BeanConvert{
13 |
14 | @SuppressWarnings("unchecked")
15 | default T convertFrom(@NonNull Object source, String... ignoreProperties) {
16 | if (source == null) {
17 | return null;
18 | }
19 | BeanUtils.copyProperties(source, this, ignoreProperties);
20 | return (T) this;
21 | }
22 |
23 | default T convertTo(@NonNull T target, String... ignoreProperties) {
24 | if (target == null) {
25 | return null;
26 | }
27 | BeanUtils.copyProperties(this, target, ignoreProperties);
28 | return target;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/base/ValidGroupType.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.base;
2 |
3 | /**
4 | * 参数校验分组
5 | * 根据不同的操作类型检验参数
6 | *
7 | * @author Myles Yang
8 | */
9 | public interface ValidGroupType {
10 |
11 | // 保存时的检验
12 | interface Save {
13 | }
14 |
15 | // 更新时的检验
16 | interface Update {
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/entity/AttachmentEntity.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.entity;
2 |
3 | import com.baomidou.mybatisplus.annotation.IdType;
4 | import com.baomidou.mybatisplus.annotation.TableField;
5 | import com.baomidou.mybatisplus.annotation.TableId;
6 | import com.baomidou.mybatisplus.annotation.TableName;
7 | import io.swagger.annotations.ApiModel;
8 | import io.swagger.annotations.ApiModelProperty;
9 | import lombok.Data;
10 | import lombok.EqualsAndHashCode;
11 | import lombok.experimental.Accessors;
12 |
13 | /**
14 | *
15 | * 附件
16 | *
17 | *
18 | * @author Myles Yang
19 | */
20 | @Data
21 | @EqualsAndHashCode(callSuper = true)
22 | @Accessors(chain = true)
23 | @TableName("attachment")
24 | @ApiModel(value = "AttachmentEntity对象", description = "附件")
25 | public class AttachmentEntity extends BaseEntity {
26 |
27 | private static final long serialVersionUID = 6442928839623298459L;
28 |
29 | @ApiModelProperty(value = "文件id")
30 | @TableId(value = "id", type = IdType.AUTO)
31 | private Integer id;
32 |
33 | @ApiModelProperty(value = "文件名(包括后缀)")
34 | @TableField("name")
35 | private String name;
36 |
37 | @ApiModelProperty(value = "文件大小(字节)")
38 | @TableField("size")
39 | private Long size;
40 |
41 | @ApiModelProperty(value = "文件路径")
42 | @TableField("path")
43 | private String path;
44 |
45 | @ApiModelProperty(value = "html资源类型")
46 | @TableField("media_type")
47 | private String mediaType;
48 |
49 | @ApiModelProperty(value = "文件缩略图路径")
50 | @TableField("thumb_path")
51 | private String thumbPath;
52 |
53 | @ApiModelProperty(value = "文件分组")
54 | @TableField("team")
55 | private String team;
56 |
57 | @ApiModelProperty(value = "文件为图片时,图片的宽度像素")
58 | @TableField(value = "width")
59 | private Integer width;
60 |
61 | @ApiModelProperty(value = "文件为图片时,图片的高度像素")
62 | @TableField(value = "height")
63 | private Integer height;
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/entity/BaseEntity.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.entity;
2 |
3 | import com.baomidou.mybatisplus.annotation.TableField;
4 | import io.swagger.annotations.ApiModelProperty;
5 | import lombok.Data;
6 | import lombok.EqualsAndHashCode;
7 |
8 | import java.io.Serializable;
9 | import java.time.LocalDateTime;
10 |
11 | /**
12 | * 基础实体
13 | *
14 | * @author Myles Yang
15 | */
16 | @Data
17 | @EqualsAndHashCode
18 | public class BaseEntity implements Serializable {
19 |
20 | private static final long serialVersionUID = -6489406991618570904L;
21 |
22 | @ApiModelProperty(value = "更新时间")
23 | @TableField(value = "update_time")
24 | private LocalDateTime updateTime;
25 |
26 | @ApiModelProperty(value = "创建时间")
27 | @TableField(value = "create_time")
28 | private LocalDateTime createTime;
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/entity/BlogEntity.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.entity;
2 |
3 | import com.baomidou.mybatisplus.annotation.IdType;
4 | import com.baomidou.mybatisplus.annotation.TableField;
5 | import com.baomidou.mybatisplus.annotation.TableId;
6 | import com.baomidou.mybatisplus.annotation.TableName;
7 | import io.swagger.annotations.ApiModel;
8 | import io.swagger.annotations.ApiModelProperty;
9 | import lombok.Data;
10 | import lombok.EqualsAndHashCode;
11 | import lombok.experimental.Accessors;
12 | import xyz.snwjas.blog.model.enums.BlogCommentAllowStatus;
13 | import xyz.snwjas.blog.model.enums.BlogStatus;
14 |
15 | /**
16 | *
17 | * 博客
18 | *
19 | *
20 | * @author Myles Yang
21 | */
22 | @Data
23 | @EqualsAndHashCode(callSuper = true)
24 | @Accessors(chain = true)
25 | @TableName("blog")
26 | @ApiModel(value = "BlogEntity对象", description = "博客")
27 | public class BlogEntity extends BaseEntity {
28 |
29 | private static final long serialVersionUID = 2193309050912718282L;
30 |
31 | @ApiModelProperty(value = "博客id")
32 | @TableId(value = "id", type = IdType.AUTO)
33 | private Integer id;
34 |
35 | @ApiModelProperty(value = "博客标题")
36 | @TableField("title")
37 | private String title;
38 |
39 | @ApiModelProperty(value = "原格式博客内容")
40 | @TableField("original_content")
41 | private String originalContent;
42 |
43 | @ApiModelProperty(value = "格式化(html)博客内容")
44 | @TableField("format_content")
45 | private String formatContent;
46 |
47 | @ApiModelProperty(value = "博客链接")
48 | @TableField("url")
49 | private String url;
50 |
51 | @ApiModelProperty(value = "博客摘要")
52 | @TableField("summary")
53 | private String summary;
54 |
55 | @ApiModelProperty(value = "博客缩略图链接")
56 | @TableField("thumbnail")
57 | private String thumbnail;
58 |
59 | @ApiModelProperty(value = "博客置顶排行")
60 | @TableField("top_rank")
61 | private Integer topRank;
62 |
63 | @ApiModelProperty(value = "是否允许评论,默认(1,允许但需审核)")
64 | @TableField("allow_comment")
65 | private BlogCommentAllowStatus allowComment;
66 |
67 | @ApiModelProperty(value = "喜欢的人数")
68 | @TableField("likes")
69 | private Integer likes;
70 |
71 | @ApiModelProperty(value = "博客访问人数")
72 | @TableField("visits")
73 | private Integer visits;
74 |
75 | @ApiModelProperty(value = "博客状态")
76 | @TableField("status")
77 | private BlogStatus status;
78 |
79 | @ApiModelProperty(value = "博客分类ID")
80 | @TableField("category_id")
81 | private Integer categoryId;
82 |
83 | }
84 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/entity/BlogTagEntity.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.entity;
2 |
3 | import com.baomidou.mybatisplus.annotation.IdType;
4 | import com.baomidou.mybatisplus.annotation.TableField;
5 | import com.baomidou.mybatisplus.annotation.TableId;
6 | import com.baomidou.mybatisplus.annotation.TableName;
7 | import io.swagger.annotations.ApiModel;
8 | import io.swagger.annotations.ApiModelProperty;
9 | import lombok.Data;
10 | import lombok.EqualsAndHashCode;
11 | import lombok.experimental.Accessors;
12 |
13 | /**
14 | *
15 | * 博客标签
16 | *
17 | *
18 | * @author Myles Yang
19 | */
20 | @Data
21 | @EqualsAndHashCode(callSuper = true)
22 | @Accessors(chain = true)
23 | @TableName("blog_tag")
24 | @ApiModel(value = "BlogTagEntity对象", description = "博客标签")
25 | public class BlogTagEntity extends BaseEntity {
26 |
27 | private static final long serialVersionUID = 437792569342041771L;
28 |
29 | @ApiModelProperty(value = "博客标签id")
30 | @TableId(value = "id", type = IdType.AUTO)
31 | private Integer id;
32 |
33 | @ApiModelProperty(value = "标签id")
34 | @TableField("tag_id")
35 | private Integer tagId;
36 |
37 | @ApiModelProperty(value = "博客id")
38 | @TableField("blog_id")
39 | private Integer blogId;
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/entity/CategoryEntity.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.entity;
2 |
3 | import com.baomidou.mybatisplus.annotation.IdType;
4 | import com.baomidou.mybatisplus.annotation.TableField;
5 | import com.baomidou.mybatisplus.annotation.TableId;
6 | import com.baomidou.mybatisplus.annotation.TableName;
7 | import io.swagger.annotations.ApiModel;
8 | import io.swagger.annotations.ApiModelProperty;
9 | import lombok.Data;
10 | import lombok.EqualsAndHashCode;
11 | import lombok.experimental.Accessors;
12 |
13 | /**
14 | *
15 | * 分类
16 | *
17 | *
18 | * @author Myles Yang
19 | */
20 | @Data
21 | @EqualsAndHashCode(callSuper = true)
22 | @Accessors(chain = true)
23 | @TableName("category")
24 | @ApiModel(value = "CategoryEntity对象", description = "分类")
25 | public class CategoryEntity extends BaseEntity {
26 |
27 | private static final long serialVersionUID = -524653268318328366L;
28 |
29 | @ApiModelProperty(value = "分类id")
30 | @TableId(value = "id", type = IdType.AUTO)
31 | private Integer id;
32 |
33 | @ApiModelProperty(value = "分类名")
34 | @TableField("name")
35 | private String name;
36 |
37 | @ApiModelProperty(value = "父分类id")
38 | @TableField("parent_id")
39 | private Integer parentId;
40 |
41 | @ApiModelProperty(value = "分类描述")
42 | @TableField("description")
43 | private String description;
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/entity/CommentEntity.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.entity;
2 |
3 | import com.baomidou.mybatisplus.annotation.IdType;
4 | import com.baomidou.mybatisplus.annotation.TableField;
5 | import com.baomidou.mybatisplus.annotation.TableId;
6 | import com.baomidou.mybatisplus.annotation.TableName;
7 | import io.swagger.annotations.ApiModel;
8 | import io.swagger.annotations.ApiModelProperty;
9 | import lombok.Data;
10 | import lombok.EqualsAndHashCode;
11 | import lombok.experimental.Accessors;
12 | import xyz.snwjas.blog.model.enums.CommentStatus;
13 |
14 | /**
15 | *
16 | * 评论
17 | *
18 | *
19 | * @author Myles Yang
20 | */
21 | @Data
22 | @EqualsAndHashCode(callSuper = true)
23 | @Accessors(chain = true)
24 | @TableName("comment")
25 | @ApiModel(value = "CommentEntity对象", description = "评论")
26 | public class CommentEntity extends BaseEntity {
27 |
28 | private static final long serialVersionUID = -9064254063786654890L;
29 |
30 | @ApiModelProperty(value = "评论id")
31 | @TableId(value = "id", type = IdType.AUTO)
32 | private Integer id;
33 |
34 | @ApiModelProperty(value = "父评论id")
35 | @TableField("parent_id")
36 | private Integer parentId;
37 |
38 | @ApiModelProperty(value = "评论内容")
39 | @TableField("content")
40 | private String content;
41 |
42 | @ApiModelProperty(value = "评论作者")
43 | @TableField("author")
44 | private String author;
45 |
46 | @ApiModelProperty(value = "评论作者邮箱")
47 | @TableField("email")
48 | private String email;
49 |
50 | @ApiModelProperty(value = "评论作者头像")
51 | @TableField("avatar")
52 | private String avatar;
53 |
54 | @ApiModelProperty(value = "评论作者的ip地址")
55 | @TableField("ip_address")
56 | private Integer ipAddress;
57 |
58 | @ApiModelProperty(value = "评论作者的用户代理")
59 | @TableField("user_agent")
60 | private String userAgent;
61 |
62 | @ApiModelProperty(value = "博客id")
63 | @TableField("blog_id")
64 | private Integer blogId;
65 |
66 | @ApiModelProperty(value = "评论状态")
67 | @TableField("status")
68 | private CommentStatus status;
69 |
70 | @ApiModelProperty(value = "是否是管理员评论,默认false(0)")
71 | @TableField("is_admin")
72 | private Boolean isAdmin;
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/entity/LinkEntity.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.entity;
2 |
3 | import com.baomidou.mybatisplus.annotation.IdType;
4 | import com.baomidou.mybatisplus.annotation.TableField;
5 | import com.baomidou.mybatisplus.annotation.TableId;
6 | import com.baomidou.mybatisplus.annotation.TableName;
7 | import io.swagger.annotations.ApiModel;
8 | import io.swagger.annotations.ApiModelProperty;
9 | import lombok.Data;
10 | import lombok.EqualsAndHashCode;
11 | import lombok.experimental.Accessors;
12 |
13 | /**
14 | *
15 | * 友链
16 | *
17 | *
18 | * @author Myles Yang
19 | */
20 | @Data
21 | @EqualsAndHashCode(callSuper = true)
22 | @Accessors(chain = true)
23 | @TableName("link")
24 | @ApiModel(value = "LinksEntity对象", description = "友链")
25 | public class LinkEntity extends BaseEntity {
26 |
27 | private static final long serialVersionUID = 4547836104191474484L;
28 |
29 | @ApiModelProperty(value = "友链id")
30 | @TableId(value = "id", type = IdType.AUTO)
31 | private Integer id;
32 |
33 | @ApiModelProperty(value = "友链名称")
34 | @TableField("name")
35 | private String name;
36 |
37 | @ApiModelProperty(value = "友链链接")
38 | @TableField("url")
39 | private String url;
40 |
41 | @ApiModelProperty(value = "友链logo")
42 | @TableField("logo")
43 | private String logo;
44 |
45 | @ApiModelProperty(value = "友链排行")
46 | @TableField("top_rank")
47 | private Integer topRank;
48 |
49 | @ApiModelProperty(value = "友链描述")
50 | @TableField("description")
51 | private String description;
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/entity/LogEntity.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.entity;
2 |
3 | import com.baomidou.mybatisplus.annotation.IdType;
4 | import com.baomidou.mybatisplus.annotation.TableField;
5 | import com.baomidou.mybatisplus.annotation.TableId;
6 | import com.baomidou.mybatisplus.annotation.TableName;
7 | import io.swagger.annotations.ApiModel;
8 | import io.swagger.annotations.ApiModelProperty;
9 | import lombok.Data;
10 | import lombok.EqualsAndHashCode;
11 | import lombok.experimental.Accessors;
12 | import xyz.snwjas.blog.model.enums.LogType;
13 |
14 | /**
15 | *
16 | * 日志
17 | *
18 | *
19 | * @author Myles Yang
20 | */
21 | @Data
22 | @EqualsAndHashCode(callSuper = true)
23 | @Accessors(chain = true)
24 | @TableName("log")
25 | @ApiModel(value = "LogEntity对象", description = "日志")
26 | public class LogEntity extends BaseEntity {
27 |
28 | private static final long serialVersionUID = -217049419018602936L;
29 |
30 | @ApiModelProperty(value = "日志id")
31 | @TableId(value = "id", type = IdType.AUTO)
32 | private Integer id;
33 |
34 | @ApiModelProperty(value = "操作内容")
35 | @TableField("content")
36 | private String content;
37 |
38 | @ApiModelProperty(value = "操作类型")
39 | @TableField("type")
40 | private LogType type;
41 |
42 | @ApiModelProperty(value = "操作人的ipv4地址,整型")
43 | @TableField("ip_address")
44 | private Integer ipAddress;
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/entity/OptionsEntity.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.entity;
2 |
3 | import com.baomidou.mybatisplus.annotation.IdType;
4 | import com.baomidou.mybatisplus.annotation.TableField;
5 | import com.baomidou.mybatisplus.annotation.TableId;
6 | import com.baomidou.mybatisplus.annotation.TableName;
7 | import io.swagger.annotations.ApiModel;
8 | import io.swagger.annotations.ApiModelProperty;
9 | import lombok.Data;
10 | import lombok.EqualsAndHashCode;
11 | import lombok.experimental.Accessors;
12 |
13 | /**
14 | *
15 | * 系统(博客)设置
16 | *
17 | *
18 | * @author Myles Yang
19 | */
20 | @Data
21 | @EqualsAndHashCode(callSuper = true)
22 | @Accessors(chain = true)
23 | @TableName("options")
24 | @ApiModel(value = "OptionEntity对象", description = "系统(博客)设置")
25 | public class OptionsEntity extends BaseEntity {
26 |
27 | private static final long serialVersionUID = -7423338560153552839L;
28 |
29 | @ApiModelProperty(value = "系统设置id")
30 | @TableId(value = "id", type = IdType.AUTO)
31 | private Integer id;
32 |
33 | @ApiModelProperty(value = "键")
34 | @TableField("option_key")
35 | private String optionKey;
36 |
37 | @ApiModelProperty(value = "值")
38 | @TableField("option_value")
39 | private String optionValue;
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/entity/SpeciallistEntity.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.entity;
2 |
3 | import com.baomidou.mybatisplus.annotation.IdType;
4 | import com.baomidou.mybatisplus.annotation.TableField;
5 | import com.baomidou.mybatisplus.annotation.TableId;
6 | import com.baomidou.mybatisplus.annotation.TableName;
7 | import io.swagger.annotations.ApiModel;
8 | import io.swagger.annotations.ApiModelProperty;
9 | import lombok.Data;
10 | import lombok.EqualsAndHashCode;
11 | import lombok.NoArgsConstructor;
12 | import lombok.experimental.Accessors;
13 | import xyz.snwjas.blog.model.enums.SpecialListType;
14 |
15 | /**
16 | *
17 | * 特殊名单
18 | *
19 | *
20 | * @author Myles Yang
21 | */
22 | @NoArgsConstructor
23 | @Data
24 | @EqualsAndHashCode(callSuper = true)
25 | @Accessors(chain = true)
26 | @TableName("speciallist")
27 | @ApiModel(value = "SpeciallistEntity对象", description = "特殊名单表")
28 | public class SpeciallistEntity extends BaseEntity {
29 |
30 | private static final long serialVersionUID = -8025860806817409251L;
31 |
32 | @ApiModelProperty(value = "id")
33 | @TableId(value = "id", type = IdType.AUTO)
34 | private Integer id;
35 |
36 | @ApiModelProperty(value = "类型")
37 | @TableField("type")
38 | private SpecialListType type;
39 |
40 | @ApiModelProperty(value = "内容")
41 | @TableField("content")
42 | private String content;
43 |
44 | public SpeciallistEntity(SpecialListType type, String content) {
45 | this.type = type;
46 | this.content = content;
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/entity/StatisticsEntity.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.entity;
2 |
3 | import com.baomidou.mybatisplus.annotation.*;
4 | import io.swagger.annotations.ApiModel;
5 | import io.swagger.annotations.ApiModelProperty;
6 | import lombok.Data;
7 | import lombok.EqualsAndHashCode;
8 | import lombok.experimental.Accessors;
9 |
10 | import java.time.LocalDateTime;
11 |
12 | /**
13 | *
14 | * 统计表(统计每日的数据)
15 | *
16 | *
17 | * @author Myles Yang
18 | */
19 | @Data
20 | @EqualsAndHashCode(callSuper = true)
21 | @Accessors(chain = true)
22 | @TableName("statistics")
23 | @ApiModel(value = "StatisticsEntity对象", description = "统计表(统计每日的数据)")
24 | public class StatisticsEntity extends BaseEntity {
25 |
26 | private static final long serialVersionUID = -2832150898756464414L;
27 |
28 | @ApiModelProperty(value = "id")
29 | @TableId(value = "id", type = IdType.AUTO)
30 | private Integer id;
31 |
32 | @ApiModelProperty(value = "网站访问量")
33 | @TableField("web_visit_count")
34 | private Integer webVisitCount;
35 |
36 | @ApiModelProperty(value = "文章访问量")
37 | @TableField("blog_visit_count")
38 | private Integer blogVisitCount;
39 |
40 | @ApiModelProperty(value = "评论数量")
41 | @TableField("comment_count")
42 | private Integer commentCount;
43 |
44 | @ApiModelProperty(value = "统计日期")
45 | @TableField("date")
46 | private LocalDateTime date;
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/entity/TagEntity.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.entity;
2 |
3 | import com.baomidou.mybatisplus.annotation.IdType;
4 | import com.baomidou.mybatisplus.annotation.TableField;
5 | import com.baomidou.mybatisplus.annotation.TableId;
6 | import com.baomidou.mybatisplus.annotation.TableName;
7 | import io.swagger.annotations.ApiModel;
8 | import io.swagger.annotations.ApiModelProperty;
9 | import lombok.Data;
10 | import lombok.EqualsAndHashCode;
11 | import lombok.experimental.Accessors;
12 |
13 | /**
14 | *
15 | * 标签
16 | *
17 | *
18 | * @author Myles Yang
19 | */
20 | @Data
21 | @EqualsAndHashCode(callSuper = true)
22 | @Accessors(chain = true)
23 | @TableName("tag")
24 | @ApiModel(value = "TagEntity对象", description = "标签")
25 | public class TagEntity extends BaseEntity {
26 |
27 | private static final long serialVersionUID = 2913936447152558511L;
28 |
29 | @ApiModelProperty(value = "标签id")
30 | @TableId(value = "id", type = IdType.AUTO)
31 | private Integer id;
32 |
33 | @ApiModelProperty(value = "标签名")
34 | @TableField("name")
35 | private String name;
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/entity/UserEntity.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.entity;
2 |
3 | import com.baomidou.mybatisplus.annotation.IdType;
4 | import com.baomidou.mybatisplus.annotation.TableField;
5 | import com.baomidou.mybatisplus.annotation.TableId;
6 | import com.baomidou.mybatisplus.annotation.TableName;
7 | import io.swagger.annotations.ApiModel;
8 | import io.swagger.annotations.ApiModelProperty;
9 | import lombok.Data;
10 | import lombok.EqualsAndHashCode;
11 | import lombok.experimental.Accessors;
12 |
13 | /**
14 | *
15 | * 用户
16 | *
17 | *
18 | * @author Myles Yang
19 | */
20 | @Data
21 | @EqualsAndHashCode(callSuper = true)
22 | @Accessors(chain = true)
23 | @TableName("user")
24 | @ApiModel(value = "UserEntity对象", description = "用户")
25 | public class UserEntity extends BaseEntity {
26 |
27 | private static final long serialVersionUID = 1257044767231325225L;
28 |
29 | @ApiModelProperty(value = "用户id")
30 | @TableId(value = "id", type = IdType.AUTO)
31 | private Integer id;
32 |
33 | @ApiModelProperty(value = "登录用户名")
34 | @TableField("username")
35 | private String username;
36 |
37 | @ApiModelProperty(value = "登录密码")
38 | @TableField("password")
39 | private String password;
40 |
41 | @ApiModelProperty(value = "用户昵称")
42 | @TableField("nickname")
43 | private String nickname;
44 |
45 | @ApiModelProperty(value = "用户邮箱")
46 | @TableField("email")
47 | private String email;
48 |
49 | @ApiModelProperty(value = "用户头像链接")
50 | @TableField("avatar")
51 | private String avatar;
52 |
53 | @ApiModelProperty(value = "个人描述")
54 | @TableField("description")
55 | private String description;
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/enums/BlogCommentAllowStatus.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.enums;
2 |
3 | import com.baomidou.mybatisplus.annotation.EnumValue;
4 |
5 | /**
6 | * 博客评论允许状态枚举常量
7 | *
8 | * @author Myles Yang
9 | */
10 | public enum BlogCommentAllowStatus implements ValueEnum {
11 | /**
12 | * 不允许
13 | */
14 | UNALLOWED(0),
15 |
16 | /**
17 | * 允许,但需审核
18 | */
19 | ALLOWED_AUDITING(1),
20 |
21 | /**
22 | * 允许,自动审核
23 | */
24 | ALLOWED_PASSAUTO(2);
25 |
26 | @EnumValue
27 | private final int value;
28 |
29 | BlogCommentAllowStatus(int value) {
30 | this.value = value;
31 | }
32 |
33 | @Override
34 | public Integer getValue() {
35 | return value;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/enums/BlogStatus.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.enums;
2 |
3 | import com.baomidou.mybatisplus.annotation.EnumValue;
4 | import com.baomidou.mybatisplus.core.enums.IEnum;
5 | import com.fasterxml.jackson.annotation.JsonValue;
6 |
7 | /**
8 | * 博客状态枚举常量
9 | *
10 | * @author Myles Yang
11 | */
12 | public enum BlogStatus implements ValueEnum {
13 | /**
14 | * 已发表
15 | */
16 | PUBLISHED(0),
17 | /**
18 | * 草稿
19 | */
20 | DRAFT(1),
21 | /**
22 | * 回收站
23 | */
24 | RECYCLE(2);
25 |
26 | @EnumValue
27 | private final int value;
28 |
29 | BlogStatus(int value) {
30 | this.value = value;
31 | }
32 |
33 | @Override
34 | public Integer getValue() {
35 | return value;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/enums/CommentStatus.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.enums;
2 |
3 | import com.baomidou.mybatisplus.annotation.EnumValue;
4 |
5 | /**
6 | * 评论状态枚举常量
7 | *
8 | * @author Myles Yang
9 | */
10 | public enum CommentStatus implements ValueEnum {
11 | /**
12 | * 审核中
13 | */
14 | AUDITING(0),
15 |
16 | /**
17 | * 已发布
18 | */
19 | PUBLISHED(1),
20 |
21 | /**
22 | * 回收站
23 | */
24 | RECYCLE(2);
25 |
26 | @EnumValue
27 | private final Integer value;
28 |
29 | CommentStatus(Integer value) {
30 | this.value = value;
31 | }
32 |
33 | @Override
34 | public Integer getValue() {
35 | return value;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/enums/LogType.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.enums;
2 |
3 | import com.baomidou.mybatisplus.annotation.EnumValue;
4 |
5 | /**
6 | * Log Type enum
7 | *
8 | * @author Myles Yang
9 | */
10 | public enum LogType implements ValueEnum {
11 |
12 | COMMON(0),
13 |
14 | LOGGED_IN(1),
15 |
16 | LOGGED_OUT(2),
17 |
18 | LOGIN_FAILED(3),
19 |
20 | PASSWORD_UPDATED(4),
21 |
22 | PROFILE_UPDATED(5),
23 |
24 | BLOG_PUBLISHED(6),
25 |
26 | BLOG_EDITED(7),
27 |
28 | BLOG_DELETED(8),
29 |
30 | OPTION_UPDATE(9),
31 | ;
32 |
33 | @EnumValue
34 | private final Integer value;
35 |
36 | LogType(Integer value) {
37 | this.value = value;
38 | }
39 |
40 | @Override
41 | public Integer getValue() {
42 | return value;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/enums/SpecialListType.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.enums;
2 |
3 | import com.baomidou.mybatisplus.annotation.EnumValue;
4 |
5 | /**
6 | * Special List Type enum
7 | *
8 | * @author Myles Yang
9 | */
10 | public enum SpecialListType implements ValueEnum {
11 |
12 | WORD_BLACK_LIST(1),
13 |
14 | WORD_WHITE_LIST(2),
15 |
16 | // IP_BLACK_LIST(1),
17 |
18 | // IP_WHITE_LIST(2),
19 |
20 | ;
21 |
22 |
23 | @EnumValue
24 | private final Integer value;
25 |
26 | SpecialListType(Integer value) {
27 | this.value = value;
28 | }
29 |
30 | @Override
31 | public Integer getValue() {
32 | return value;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/enums/ValueEnum.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.enums;
2 |
3 | import org.springframework.util.Assert;
4 |
5 | import java.util.stream.Stream;
6 |
7 | /**
8 | * Value Enum
9 | */
10 | public interface ValueEnum {
11 |
12 | static > E valueToEnum(Class enumType, V value) {
13 | Assert.notNull(enumType, "enum type must not be null");
14 | Assert.isTrue(enumType.isEnum(), "type must be an enum type");
15 | Assert.notNull(value, "value must not be null");
16 |
17 | return Stream.of(enumType.getEnumConstants())
18 | .filter(item -> item.getValue().equals(value))
19 | .findFirst()
20 | .orElseThrow(() -> new IllegalArgumentException("unknown value: " + value));
21 | }
22 |
23 | V getValue();
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/params/AttachmentSearchParam.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.params;
2 |
3 | import io.swagger.annotations.ApiModel;
4 | import io.swagger.annotations.ApiModelProperty;
5 | import lombok.Data;
6 | import lombok.EqualsAndHashCode;
7 | import lombok.experimental.Accessors;
8 |
9 | import java.time.LocalDateTime;
10 |
11 | /**
12 | * Attachment Search Param
13 | *
14 | * @author Myles Yang
15 | */
16 | @EqualsAndHashCode(callSuper = true)
17 | @Data
18 | @Accessors(chain = true)
19 | @ApiModel("附件搜索参数")
20 | public class AttachmentSearchParam extends BasePageParam {
21 |
22 | @ApiModelProperty("附件名")
23 | private String name;
24 |
25 | @ApiModelProperty("附件类型")
26 | private String mediaType;
27 |
28 | @ApiModelProperty("附件分组")
29 | private String team;
30 |
31 | @ApiModelProperty("附件分组模糊查询字段")
32 | private String likeTeam;
33 |
34 | private LocalDateTime createTime;
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/params/BasePageParam.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.params;
2 |
3 | import io.swagger.annotations.ApiModel;
4 | import io.swagger.annotations.ApiModelProperty;
5 | import lombok.Data;
6 | import lombok.experimental.Accessors;
7 |
8 | import javax.validation.constraints.Max;
9 | import javax.validation.constraints.Min;
10 |
11 | /**
12 | * Base Page Param
13 | *
14 | * @author Myles Yang
15 | */
16 | @Data
17 | @Accessors(chain = true)
18 | @ApiModel("基础分页参数")
19 | public class BasePageParam {
20 |
21 | @Min(1)
22 | @ApiModelProperty("当前页")
23 | private long current;
24 |
25 | @Min(1)
26 | @Max(50)
27 | @ApiModelProperty("每页数量")
28 | private long pageSize;
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/params/BlogSearchParam.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.params;
2 |
3 | import io.swagger.annotations.ApiModel;
4 | import io.swagger.annotations.ApiModelProperty;
5 | import lombok.Data;
6 | import lombok.EqualsAndHashCode;
7 | import lombok.experimental.Accessors;
8 | import xyz.snwjas.blog.model.enums.BlogStatus;
9 |
10 | /**
11 | * Blog Search Param
12 | *
13 | * @author Myles Yang
14 | */
15 | @EqualsAndHashCode(callSuper = true)
16 | @Data
17 | @Accessors(chain = true)
18 | @ApiModel("博客搜索参数")
19 | public class BlogSearchParam extends BasePageParam {
20 |
21 | @ApiModelProperty("博客文章标题")
22 | private String title;
23 |
24 | @ApiModelProperty("博客分类ID")
25 | private Integer categoryId;
26 |
27 | @ApiModelProperty("博客标签ID")
28 | private Integer tagId;
29 |
30 | @ApiModelProperty("博客状态")
31 | private BlogStatus status;
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/params/CommentSearchParam.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.params;
2 |
3 | import io.swagger.annotations.ApiModel;
4 | import io.swagger.annotations.ApiModelProperty;
5 | import lombok.Data;
6 | import lombok.EqualsAndHashCode;
7 | import lombok.experimental.Accessors;
8 | import xyz.snwjas.blog.model.enums.CommentStatus;
9 |
10 | /**
11 | * Common Search Param
12 | *
13 | * @author Myles Yang
14 | */
15 | @EqualsAndHashCode(callSuper = true)
16 | @Data
17 | @Accessors(chain = true)
18 | @ApiModel("评论搜索参数")
19 | public class CommentSearchParam extends BasePageParam {
20 |
21 | @ApiModelProperty("评论者昵称")
22 | private String author;
23 |
24 | @ApiModelProperty("评论者昵称")
25 | private String content;
26 |
27 | @ApiModelProperty("评论者邮箱地址")
28 | private String email;
29 |
30 | @ApiModelProperty("关键字:author || content || email")
31 | private String keyword; // author || content || email
32 |
33 | @ApiModelProperty("评论所属博客文章ID")
34 | private Integer blogId;
35 |
36 | @ApiModelProperty("评论状态")
37 | private CommentStatus status;
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/params/LinkSearchParam.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.params;
2 |
3 | import io.swagger.annotations.ApiModel;
4 | import io.swagger.annotations.ApiModelProperty;
5 | import lombok.Data;
6 | import lombok.EqualsAndHashCode;
7 | import lombok.experimental.Accessors;
8 |
9 | /**
10 | * Link Search Param
11 | *
12 | * @author Myles Yang
13 | */
14 | @EqualsAndHashCode(callSuper = true)
15 | @Data
16 | @Accessors(chain = true)
17 | @ApiModel("友链搜索参数")
18 | public class LinkSearchParam extends BasePageParam {
19 |
20 | @ApiModelProperty("友链名称")
21 | private String name;
22 |
23 | @ApiModelProperty("友链url")
24 | private String url;
25 |
26 | @ApiModelProperty("关键词:名称或url")
27 | private String keyword;
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/params/ListParam.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.params;
2 |
3 | import io.swagger.annotations.ApiModel;
4 | import io.swagger.annotations.ApiModelProperty;
5 | import lombok.experimental.Delegate;
6 |
7 | import javax.validation.Valid;
8 | import java.util.ArrayList;
9 | import java.util.List;
10 |
11 | @ApiModel("列表参数")
12 | public class ListParam implements List {
13 |
14 | @Delegate // @Delegate是lombok注解
15 | @Valid // 一定要加@Valid注解
16 | @ApiModelProperty("列表数据")
17 | public List list = new ArrayList<>();
18 |
19 | // 一定要记得重写toString方法
20 | @Override
21 | public String toString() {
22 | return list.toString();
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/params/LogSearchParam.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.params;
2 |
3 | import io.swagger.annotations.ApiModel;
4 | import io.swagger.annotations.ApiModelProperty;
5 | import lombok.Data;
6 | import lombok.EqualsAndHashCode;
7 | import lombok.experimental.Accessors;
8 | import xyz.snwjas.blog.model.enums.LogType;
9 |
10 | import java.util.List;
11 |
12 | /**
13 | * Log Search Param
14 | *
15 | * @author Myles Yang
16 | */
17 | @EqualsAndHashCode(callSuper = true)
18 | @Data
19 | @Accessors(chain = true)
20 | @ApiModel("日志搜索参数")
21 | public class LogSearchParam extends BasePageParam {
22 |
23 | @ApiModelProperty("日志类型")
24 | private List types;
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/params/SpeciallistSearchParam.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.params;
2 |
3 | import io.swagger.annotations.ApiModel;
4 | import io.swagger.annotations.ApiModelProperty;
5 | import lombok.Data;
6 | import lombok.EqualsAndHashCode;
7 | import lombok.experimental.Accessors;
8 | import xyz.snwjas.blog.model.enums.SpecialListType;
9 |
10 | import java.util.List;
11 |
12 | /**
13 | * Special List Search Param
14 | *
15 | * @author Myles Yang
16 | */
17 | @EqualsAndHashCode(callSuper = true)
18 | @Data
19 | @Accessors(chain = true)
20 | @ApiModel("特殊清单搜索参数")
21 | public class SpeciallistSearchParam extends BasePageParam {
22 |
23 | @ApiModelProperty("类型")
24 | private List types;
25 |
26 | @ApiModelProperty("内容")
27 | private String content;
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/params/UpdatePasswordParam.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.params;
2 |
3 | import io.swagger.annotations.ApiModel;
4 | import io.swagger.annotations.ApiModelProperty;
5 | import lombok.Data;
6 | import org.hibernate.validator.constraints.Length;
7 |
8 | import javax.validation.constraints.NotBlank;
9 |
10 | /**
11 | * Update Password Param
12 | *
13 | * @author Myles Yang
14 | */
15 | @Data
16 | @ApiModel("密码更新参数")
17 | public class UpdatePasswordParam {
18 |
19 | @NotBlank
20 | @Length(max = 63)
21 | @ApiModelProperty("原密码")
22 | private String oldPassword;
23 |
24 | @NotBlank
25 | @Length(max = 63)
26 | @ApiModelProperty("新密码")
27 | private String newPassword;
28 |
29 | @NotBlank
30 | @Length(max = 63)
31 | @ApiModelProperty("确认的新密码")
32 | private String confirmNewPassword;
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/vo/AttachmentVO.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.vo;
2 |
3 | import io.swagger.annotations.ApiModel;
4 | import io.swagger.annotations.ApiModelProperty;
5 | import lombok.Data;
6 | import lombok.experimental.Accessors;
7 | import org.hibernate.validator.constraints.Length;
8 | import xyz.snwjas.blog.model.base.BeanConvert;
9 | import xyz.snwjas.blog.model.base.ValidGroupType.Save;
10 | import xyz.snwjas.blog.model.base.ValidGroupType.Update;
11 |
12 | import javax.validation.constraints.Min;
13 | import javax.validation.constraints.NotBlank;
14 | import javax.validation.constraints.NotNull;
15 | import java.io.Serializable;
16 | import java.time.LocalDateTime;
17 |
18 | /**
19 | * Attachment VO
20 | *
21 | * @author Myles Yang
22 | */
23 | @Data
24 | @Accessors(chain = true)
25 | @ApiModel("附件视图对象")
26 | public class AttachmentVO implements BeanConvert, Serializable {
27 |
28 | private static final long serialVersionUID = 2383027373825151464L;
29 |
30 | @NotNull(groups = {Update.class})
31 | @Min(value = 1, groups = {Update.class})
32 | @ApiModelProperty("附件ID")
33 | private Integer id;
34 |
35 | @NotBlank(groups = {Save.class, Update.class})
36 | @Length(max = 255, groups = {Save.class, Update.class})
37 | @ApiModelProperty("附件名")
38 | private String name;
39 |
40 | @ApiModelProperty("附件大小(单位:字节)")
41 | private Long size;
42 |
43 | @ApiModelProperty("附件路径")
44 | private String path;
45 |
46 | @ApiModelProperty("附件资源类型")
47 | private String mediaType;
48 |
49 | @ApiModelProperty("附件缩略图路径")
50 | private String thumbPath;
51 |
52 | @ApiModelProperty(value = "文件分组")
53 | private String team;
54 |
55 | @ApiModelProperty("附件为图片时的宽度")
56 | private Integer width;
57 |
58 | @ApiModelProperty("附件为图片时的高度")
59 | private Integer height;
60 |
61 | private LocalDateTime createTime;
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/vo/BlogArchiveVO.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.vo;
2 |
3 | import io.swagger.annotations.ApiModel;
4 | import io.swagger.annotations.ApiModelProperty;
5 | import lombok.Data;
6 | import xyz.snwjas.blog.model.base.BeanConvert;
7 |
8 | import java.io.Serializable;
9 | import java.time.LocalDateTime;
10 |
11 | /**
12 | * 博客归档
13 | *
14 | * @author Myles Yang
15 | */
16 | @Data
17 | @ApiModel("博客归档视图对象")
18 | public class BlogArchiveVO implements BeanConvert, Serializable {
19 |
20 | private static final long serialVersionUID = 5910901865665778938L;
21 |
22 | @ApiModelProperty("博客文章ID")
23 | private Integer id;
24 |
25 | @ApiModelProperty("博客文章标题")
26 | private String title;
27 |
28 | @ApiModelProperty("博客文章URL")
29 | private String url;
30 |
31 | private LocalDateTime createTime;
32 |
33 | private LocalDateTime updateTime;
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/vo/BlogDetailVO.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.vo;
2 |
3 | import io.swagger.annotations.ApiModel;
4 | import io.swagger.annotations.ApiModelProperty;
5 | import lombok.Data;
6 | import lombok.EqualsAndHashCode;
7 | import lombok.experimental.Accessors;
8 | import xyz.snwjas.blog.model.base.BeanConvert;
9 |
10 | import java.io.Serializable;
11 |
12 | /**
13 | * 博客列表View Object
14 | *
15 | * @author Myles Yang
16 | */
17 | @EqualsAndHashCode(callSuper = true)
18 | @Data
19 | @Accessors(chain = true)
20 | @ApiModel("详细的博客文章视图对象")
21 | public class BlogDetailVO extends BlogSimpleVO implements BeanConvert, Serializable {
22 |
23 | private static final long serialVersionUID = 4692344576356025171L;
24 |
25 | @ApiModelProperty("源格式文本(Markdown)")
26 | private String originalContent;
27 |
28 | @ApiModelProperty("格式化文本(HTML)")
29 | private String formatContent;
30 |
31 | @ApiModelProperty("点赞数量")
32 | private Integer likes;
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/vo/BlogSelectVO.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.vo;
2 |
3 | import io.swagger.annotations.ApiModel;
4 | import io.swagger.annotations.ApiModelProperty;
5 | import lombok.Data;
6 | import lombok.experimental.Accessors;
7 | import xyz.snwjas.blog.model.base.BeanConvert;
8 |
9 | import java.io.Serializable;
10 |
11 | /**
12 | * Blog Select VO
13 | * 评论中选择文章搜索
14 | *
15 | * @author Myles Yang
16 | */
17 | @Data
18 | @Accessors(chain = true)
19 | @ApiModel("评论中选择文章搜索的视图对象")
20 | public class BlogSelectVO implements BeanConvert, Serializable {
21 |
22 | private static final long serialVersionUID = 9072913105080249037L;
23 |
24 | @ApiModelProperty("文章ID")
25 | private Integer id;
26 |
27 | @ApiModelProperty("文章标题")
28 | private String title;
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/vo/BlogSimpleVO.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.vo;
2 |
3 | import io.swagger.annotations.ApiModel;
4 | import io.swagger.annotations.ApiModelProperty;
5 | import lombok.Data;
6 | import lombok.experimental.Accessors;
7 | import org.hibernate.validator.constraints.Length;
8 | import xyz.snwjas.blog.model.base.BeanConvert;
9 | import xyz.snwjas.blog.model.base.ValidGroupType.Save;
10 | import xyz.snwjas.blog.model.base.ValidGroupType.Update;
11 | import xyz.snwjas.blog.model.enums.BlogCommentAllowStatus;
12 | import xyz.snwjas.blog.model.enums.BlogStatus;
13 |
14 | import javax.validation.constraints.Min;
15 | import javax.validation.constraints.NotNull;
16 | import java.io.Serializable;
17 | import java.time.LocalDateTime;
18 | import java.util.List;
19 |
20 | /**
21 | * 博客列表View Object
22 | *
23 | * @author Myles Yang
24 | */
25 | @Data
26 | @Accessors(chain = true)
27 | @ApiModel("简单的博客文章视图对象")
28 | public class BlogSimpleVO implements BeanConvert, Serializable {
29 |
30 | private static final long serialVersionUID = 6349521681640492470L;
31 |
32 | @NotNull(groups = Update.class, message = "博客id不能为空")
33 | @Min(value = 1, groups = Update.class)
34 | @ApiModelProperty("文章ID")
35 | private Integer id;
36 |
37 | @Length(max = 255, groups = {Save.class, Update.class})
38 | @ApiModelProperty("文章标题")
39 | private String title;
40 |
41 | @Length(max = 255, groups = {Save.class, Update.class})
42 | @ApiModelProperty("文章访问URL")
43 | private String url;
44 |
45 | @Length(max = 511, groups = {Save.class, Update.class})
46 | @ApiModelProperty("文章概要")
47 | private String summary;
48 |
49 | @Length(max = 1023, groups = {Save.class, Update.class})
50 | @ApiModelProperty("文章缩略图")
51 | private String thumbnail;
52 |
53 | @ApiModelProperty("文章置顶数值(数值越大越靠前)")
54 | private Integer topRank;
55 |
56 | @ApiModelProperty("文章访问数量")
57 | private Integer visits;
58 |
59 | @ApiModelProperty("文章状态")
60 | private BlogStatus status;
61 |
62 | @ApiModelProperty("文章分类")
63 | private CategoryVO category;
64 |
65 | @ApiModelProperty("文章是否允许评论")
66 | private BlogCommentAllowStatus allowComment;
67 |
68 | private LocalDateTime createTime;
69 |
70 | private LocalDateTime updateTime;
71 |
72 | @ApiModelProperty("评论数量")
73 | private Integer commentCount;
74 |
75 | @ApiModelProperty("文章标签列表")
76 | private List tags;
77 |
78 | }
79 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/vo/CategoryVO.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.vo;
2 |
3 | import io.swagger.annotations.ApiModel;
4 | import io.swagger.annotations.ApiModelProperty;
5 | import lombok.Data;
6 | import lombok.experimental.Accessors;
7 | import org.hibernate.validator.constraints.Length;
8 | import xyz.snwjas.blog.model.base.BeanConvert;
9 | import xyz.snwjas.blog.model.base.ValidGroupType.Save;
10 | import xyz.snwjas.blog.model.base.ValidGroupType.Update;
11 |
12 | import javax.validation.constraints.Min;
13 | import javax.validation.constraints.NotBlank;
14 | import javax.validation.constraints.NotNull;
15 | import java.io.Serializable;
16 |
17 | /**
18 | * Category VO
19 | *
20 | * @author Myles Yang
21 | */
22 | @Data
23 | @Accessors(chain = true)
24 | @ApiModel("分类视图对象")
25 | public class CategoryVO implements BeanConvert, Serializable {
26 |
27 | private static final long serialVersionUID = 7673727208979429235L;
28 |
29 | @NotNull(groups = {Update.class})
30 | @Min(value = 1, groups = {Update.class})
31 | @ApiModelProperty("分类ID")
32 | private Integer id;
33 |
34 | @NotBlank(message = "分类名不能为空", groups = {Save.class, Update.class})
35 | @Length(min = 1, max = 63, message = "分类名长度应介于1至63之间", groups = {Save.class, Update.class})
36 | @ApiModelProperty("分类名")
37 | private String name;
38 |
39 | @Length(max = 127, message = "分类描述长度应小于127", groups = {Save.class, Update.class})
40 | @ApiModelProperty("分类描述")
41 | private String description;
42 |
43 | @ApiModelProperty("该分类下的博客数量")
44 | private Integer blogCount;
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/vo/CommentDetailVO.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.vo;
2 |
3 | import io.swagger.annotations.ApiModel;
4 | import io.swagger.annotations.ApiModelProperty;
5 | import lombok.Data;
6 | import lombok.EqualsAndHashCode;
7 | import lombok.ToString;
8 | import lombok.experimental.Accessors;
9 | import org.hibernate.validator.constraints.Length;
10 | import xyz.snwjas.blog.model.enums.CommentStatus;
11 |
12 | import javax.validation.constraints.Email;
13 | import javax.validation.constraints.NotEmpty;
14 |
15 | /**
16 | * Comment VO
17 | *
18 | * @author Myles Yang
19 | */
20 | @EqualsAndHashCode(callSuper = true)
21 | @Data
22 | @ToString(callSuper = true)
23 | @Accessors(chain = true)
24 | @ApiModel("详细的评论视图对象")
25 | public class CommentDetailVO extends CommentSimpleVO {
26 |
27 | private static final long serialVersionUID = 1080754350404773083L;
28 |
29 | @NotEmpty(groups = {Guest.class}, message = "邮箱不能为空")
30 | @Email(groups = {Guest.class}, message = "邮箱格式错误")
31 | @Length(max = 127, groups = {Admin.class, Guest.class}, message = "邮箱长度不能超过127个字符")
32 | @ApiModelProperty("评论者邮件地址")
33 | private String email;
34 |
35 | @ApiModelProperty("评论者IP地址")
36 | private String ipAddress;
37 |
38 | @ApiModelProperty("评论状态")
39 | private CommentStatus status;
40 |
41 | private String blogTitle;
42 |
43 | private String blogUrl;
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/vo/CommentSimpleVO.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.vo;
2 |
3 | import io.swagger.annotations.ApiModel;
4 | import io.swagger.annotations.ApiModelProperty;
5 | import lombok.Data;
6 | import lombok.experimental.Accessors;
7 | import org.hibernate.validator.constraints.Length;
8 | import xyz.snwjas.blog.model.base.BeanConvert;
9 |
10 | import javax.validation.constraints.Min;
11 | import javax.validation.constraints.NotEmpty;
12 | import javax.validation.constraints.NotNull;
13 | import java.io.Serializable;
14 | import java.time.LocalDateTime;
15 | import java.util.List;
16 |
17 | /**
18 | * Comment VO
19 | *
20 | * @author Myles Yang
21 | */
22 | @Data
23 | @Accessors(chain = true)
24 | @ApiModel("简单的评论视图对象")
25 | public class CommentSimpleVO implements BeanConvert, Serializable {
26 |
27 | private static final long serialVersionUID = -7923533144012981489L;
28 |
29 | @ApiModelProperty("评论ID")
30 | private Integer id;
31 |
32 | @NotEmpty(groups = {Admin.class, Guest.class}, message = "评论内容不能为空")
33 | @Length(max = 1023, groups = {Admin.class, Guest.class}, message = "评论内容长度请控制在1023个字符")
34 | @ApiModelProperty("评论内容")
35 | private String content;
36 |
37 | @NotEmpty(groups = {Guest.class}, message = "昵称不能为空")
38 | @Length(max = 63, groups = {Admin.class, Guest.class}, message = "昵称长度不能超过63个字符")
39 | @ApiModelProperty("评论者昵称")
40 | private String author;
41 |
42 | @Min(value = 0, groups = {Admin.class, Guest.class})
43 | @ApiModelProperty("父评论ID")
44 | private Integer parentId;
45 |
46 | @NotNull(groups = {Admin.class, Guest.class}, message = "未知博客的评论")
47 | @Min(value = 1, groups = {Admin.class, Guest.class}, message = "未知博客的评论")
48 | @ApiModelProperty("评论所属博客文章ID")
49 | private Integer blogId;
50 |
51 | @ApiModelProperty("评论者的用户代理")
52 | private String userAgent;
53 |
54 | @ApiModelProperty("评论是否是博主发表的")
55 | private Boolean isAdmin;
56 |
57 | @ApiModelProperty(value = "评论作者头像")
58 | private String avatar;
59 |
60 | private LocalDateTime createTime;
61 |
62 | @ApiModelProperty("子评论数量")
63 | private Integer childrenCount;
64 |
65 | @ApiModelProperty("子评论")
66 | private List children;
67 |
68 | // 管理员校验
69 | public interface Admin {
70 | }
71 |
72 | // 游客校验
73 | public interface Guest {
74 | }
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/vo/LinkVO.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.vo;
2 |
3 | import io.swagger.annotations.ApiModel;
4 | import io.swagger.annotations.ApiModelProperty;
5 | import lombok.Data;
6 | import lombok.experimental.Accessors;
7 | import org.hibernate.validator.constraints.Length;
8 | import xyz.snwjas.blog.model.base.BeanConvert;
9 | import xyz.snwjas.blog.model.base.ValidGroupType;
10 |
11 | import javax.validation.constraints.Min;
12 | import javax.validation.constraints.NotBlank;
13 | import javax.validation.constraints.NotNull;
14 | import java.io.Serializable;
15 |
16 | /**
17 | * Link VO
18 | *
19 | * @author Myles Yang
20 | */
21 | @Data
22 | @Accessors(chain = true)
23 | @ApiModel("友链视图对象")
24 | public class LinkVO implements BeanConvert, Serializable {
25 |
26 | private static final long serialVersionUID = 4860407888308055369L;
27 |
28 | @NotNull(groups = {ValidGroupType.Update.class})
29 | @Min(value = 1, groups = {ValidGroupType.Update.class})
30 | @ApiModelProperty("友链ID")
31 | private Integer id;
32 |
33 | @NotBlank(groups = {ValidGroupType.Save.class, ValidGroupType.Update.class}, message = "友链名称不能为空")
34 | @Length(max = 127, groups = {ValidGroupType.Save.class, ValidGroupType.Update.class})
35 | @ApiModelProperty("友链名")
36 | private String name;
37 |
38 | @NotBlank(groups = {ValidGroupType.Save.class, ValidGroupType.Update.class}, message = "友链地址不能为空")
39 | @Length(max = 255, groups = {ValidGroupType.Save.class, ValidGroupType.Update.class})
40 | @ApiModelProperty("友链地址")
41 | private String url;
42 |
43 | @Length(max = 1023)
44 | @ApiModelProperty("友链Logo地址")
45 | private String logo;
46 |
47 | @ApiModelProperty("友链排行(值越大越靠前)")
48 | private Integer topRank;
49 |
50 | @Length(max = 512)
51 | @ApiModelProperty("友链描述")
52 | private String description;
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/vo/LogVO.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.vo;
2 |
3 | import io.swagger.annotations.ApiModel;
4 | import io.swagger.annotations.ApiModelProperty;
5 | import lombok.Data;
6 | import lombok.experimental.Accessors;
7 | import xyz.snwjas.blog.model.base.BeanConvert;
8 | import xyz.snwjas.blog.model.enums.LogType;
9 |
10 | import java.io.Serializable;
11 | import java.time.LocalDateTime;
12 |
13 | /**
14 | * Log VO
15 | *
16 | * @author Myles Yang
17 | */
18 | @Data
19 | @Accessors(chain = true)
20 | @ApiModel("日志视图对象")
21 | public class LogVO implements BeanConvert, Serializable {
22 |
23 | private static final long serialVersionUID = -4592668651066079493L;
24 |
25 | @ApiModelProperty("日志ID")
26 | private Integer id;
27 |
28 | @ApiModelProperty("操作内容")
29 | private String content;
30 |
31 | @ApiModelProperty("操作类型")
32 | private LogType type;
33 |
34 | @ApiModelProperty("操作人ipv4地址")
35 | private String ipAddress;
36 |
37 | @ApiModelProperty("操作时间")
38 | private LocalDateTime createTime;
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/vo/OptionVO.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.vo;
2 |
3 | import io.swagger.annotations.ApiModel;
4 | import io.swagger.annotations.ApiModelProperty;
5 | import lombok.Data;
6 | import lombok.experimental.Accessors;
7 | import xyz.snwjas.blog.model.base.BeanConvert;
8 |
9 | import java.io.Serializable;
10 |
11 | /**
12 | * Option VO
13 | *
14 | * @author Myles Yang
15 | */
16 | @Data
17 | @Accessors(chain = true)
18 | @ApiModel("设置选项视图对象")
19 | public class OptionVO implements BeanConvert, Serializable {
20 |
21 | private static final long serialVersionUID = -2070361214962849320L;
22 |
23 | @ApiModelProperty("选项ID")
24 | private Integer id;
25 |
26 | @ApiModelProperty("选项键")
27 | private String optionKey;
28 |
29 | @ApiModelProperty("选项值")
30 | private String optionValue;
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/vo/SpeciallistVO.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.vo;
2 |
3 | import io.swagger.annotations.ApiModel;
4 | import io.swagger.annotations.ApiModelProperty;
5 | import lombok.Data;
6 | import lombok.NoArgsConstructor;
7 | import lombok.experimental.Accessors;
8 | import xyz.snwjas.blog.model.base.BeanConvert;
9 | import xyz.snwjas.blog.model.enums.SpecialListType;
10 |
11 | import java.io.Serializable;
12 | import java.time.LocalDateTime;
13 |
14 | /**
15 | * Special List VO
16 | *
17 | * @author Myles Yang
18 | */
19 | @NoArgsConstructor
20 | @Data
21 | @Accessors(chain = true)
22 | @ApiModel("特殊清单视图对象")
23 | public class SpeciallistVO implements BeanConvert, Serializable {
24 |
25 | private static final long serialVersionUID = 1258610051667767051L;
26 |
27 | @ApiModelProperty("ID")
28 | private Integer id;
29 |
30 | @ApiModelProperty("类型")
31 | private SpecialListType type;
32 |
33 | @ApiModelProperty("内容")
34 | private String content;
35 |
36 | @ApiModelProperty("创建时间")
37 | private LocalDateTime createTime;
38 |
39 | public SpeciallistVO(SpecialListType type, String content) {
40 | this.type = type;
41 | this.content = content;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/vo/StatisticsBasicVO.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.vo;
2 |
3 | import lombok.Data;
4 | import lombok.experimental.Accessors;
5 |
6 | import java.time.LocalDateTime;
7 |
8 | /**
9 | * 博客数据统计View Object
10 | *
11 | * @author Myles Yang
12 | */
13 |
14 | @Data
15 | @Accessors(chain = true)
16 | public class StatisticsBasicVO {
17 |
18 | private static final long serialVersionUID = 4310667613112942914L;
19 |
20 | private Integer blogCount;
21 |
22 | private Integer commentCount;
23 |
24 | private Integer categoryCount;
25 |
26 | private Integer tagCount;
27 |
28 | private Integer linkCount;
29 |
30 | private Integer establishDaysCount;
31 |
32 | // @JsonFormat(pattern = "yyyy-MM-dd")
33 | private LocalDateTime birthday;
34 |
35 | private Integer blogTotalVisits;
36 |
37 | private Integer webTotalVisits;
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/vo/StatisticsReportVo.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.vo;
2 |
3 | import com.fasterxml.jackson.annotation.JsonFormat;
4 | import lombok.Data;
5 | import lombok.experimental.Accessors;
6 | import xyz.snwjas.blog.model.base.BeanConvert;
7 |
8 | import java.io.Serializable;
9 | import java.time.LocalDateTime;
10 |
11 | /**
12 | * 博客每天的统计数据
13 | *
14 | * @author Myles Yang
15 | */
16 | @Data
17 | @Accessors(chain = true)
18 | public class StatisticsReportVo implements BeanConvert, Serializable {
19 |
20 | private static final long serialVersionUID = -1362266664886856765L;
21 |
22 | private Integer webVisitCount;
23 |
24 | private Integer blogVisitCount;
25 |
26 | private Integer commentCount;
27 |
28 | @JsonFormat(pattern = "yyyy-MM-dd")
29 | private LocalDateTime date;
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/vo/TagVO.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.vo;
2 |
3 | import io.swagger.annotations.ApiModel;
4 | import io.swagger.annotations.ApiModelProperty;
5 | import lombok.Data;
6 | import lombok.experimental.Accessors;
7 | import org.hibernate.validator.constraints.Length;
8 | import xyz.snwjas.blog.model.base.BeanConvert;
9 | import xyz.snwjas.blog.model.base.ValidGroupType.Save;
10 | import xyz.snwjas.blog.model.base.ValidGroupType.Update;
11 |
12 | import javax.validation.constraints.Min;
13 | import javax.validation.constraints.NotBlank;
14 | import javax.validation.constraints.NotNull;
15 | import java.io.Serializable;
16 |
17 | /**
18 | * Tag VO
19 | *
20 | * @author Myles Yang
21 | */
22 | @Data
23 | @Accessors(chain = true)
24 | @ApiModel("标签视图对象")
25 | public class TagVO implements BeanConvert, Serializable {
26 |
27 | private static final long serialVersionUID = -2783711626542947755L;
28 |
29 | @NotNull(groups = {Update.class})
30 | @Min(value = 1, groups = {Update.class})
31 | @ApiModelProperty("标签ID")
32 | private Integer id;
33 |
34 | @NotBlank(message = "标签名不能为空", groups = {Save.class, Update.class})
35 | @Length(min = 1, max = 63, message = "标签名长度应介于1至63之间", groups = {Save.class, Update.class})
36 | @ApiModelProperty("标签名")
37 | private String name;
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/model/vo/UserVO.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.model.vo;
2 |
3 | import io.swagger.annotations.ApiModel;
4 | import io.swagger.annotations.ApiModelProperty;
5 | import lombok.Data;
6 | import org.hibernate.validator.constraints.Length;
7 | import xyz.snwjas.blog.model.base.BeanConvert;
8 |
9 | import javax.validation.constraints.Email;
10 | import java.io.Serializable;
11 |
12 | /**
13 | * User VO
14 | *
15 | * @author Myles Yang
16 | */
17 | @Data
18 | @ApiModel("用户视图对象")
19 | public class UserVO implements BeanConvert, Serializable {
20 |
21 | private static final long serialVersionUID = -2053049610535340848L;
22 |
23 | @Length(max = 63)
24 | @ApiModelProperty("用户名")
25 | private String username;
26 |
27 | @Length(max = 127)
28 | @ApiModelProperty("用户昵称")
29 | private String nickname;
30 |
31 | @Email
32 | @Length(max = 127)
33 | @ApiModelProperty("用户邮箱地址")
34 | private String email;
35 |
36 | @Length(max = 1023)
37 | @ApiModelProperty("用户头像地址")
38 | private String avatar;
39 |
40 | @Length(max = 1023)
41 | @ApiModelProperty("用户描述")
42 | private String description;
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/schedule/StatisticTask.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.schedule;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.scheduling.annotation.Async;
6 | import org.springframework.scheduling.annotation.Scheduled;
7 | import org.springframework.stereotype.Component;
8 | import xyz.snwjas.blog.service.StatisticsService;
9 |
10 | /**
11 | * 数据统计定时任务
12 | *
13 | * @author Myles Yang
14 | */
15 | @Component
16 | @Slf4j
17 | public class StatisticTask {
18 |
19 | @Autowired
20 | private StatisticsService statisticsService;
21 |
22 | /* @PostConstruct
23 | public void run() {
24 | autoStat();
25 | }*/
26 |
27 | // 每天零点统计信息
28 | @Async("executor")
29 | @Scheduled(cron = "1 0 0 */1 * ?")
30 | public void autoStat() {
31 | statisticsService.statisticsDaily();
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/service/AttachmentService.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.service;
2 |
3 | import com.baomidou.mybatisplus.core.metadata.IPage;
4 | import org.springframework.web.multipart.MultipartFile;
5 | import xyz.snwjas.blog.model.entity.AttachmentEntity;
6 | import xyz.snwjas.blog.model.params.AttachmentSearchParam;
7 | import xyz.snwjas.blog.model.vo.AttachmentVO;
8 | import xyz.snwjas.blog.model.PageResult;
9 |
10 | import java.util.List;
11 |
12 | /**
13 | * Attachment Service
14 | *
15 | * @author Myles Yang
16 | */
17 | public interface AttachmentService {
18 |
19 | /**
20 | * 添加附件
21 | */
22 | AttachmentVO add(MultipartFile file, String team);
23 |
24 | /**
25 | * 修改附件名
26 | */
27 | int updateNameById(int attachmentId, String attachmentName);
28 |
29 | /**
30 | * 删除附件
31 | */
32 | int deleteById(int attachmentId);
33 |
34 | /**
35 | * 批量删除附件
36 | */
37 | int deleteById(List attachmentIds);
38 |
39 | /**
40 | * 更新附件分组
41 | */
42 | int updateTeam(List attachmentIds, String team);
43 |
44 | /**
45 | * 获取所有的文件类型
46 | */
47 | List listAllMediaTypes();
48 |
49 | /**
50 | * 获取所有分组
51 | */
52 | List listAllTeams();
53 |
54 | IPage pageBy(AttachmentSearchParam param);
55 |
56 | PageResult covertToPageResult(IPage page);
57 |
58 | AttachmentVO covertToVO(AttachmentEntity attachmentEntity);
59 |
60 | List covertToListVO(List attachmentEntityList);
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/service/BlogService.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.service;
2 |
3 | import com.baomidou.mybatisplus.core.metadata.IPage;
4 | import xyz.snwjas.blog.model.entity.BlogEntity;
5 | import xyz.snwjas.blog.model.enums.BlogStatus;
6 | import xyz.snwjas.blog.model.params.BlogSearchParam;
7 | import xyz.snwjas.blog.model.vo.BlogArchiveVO;
8 | import xyz.snwjas.blog.model.vo.BlogDetailVO;
9 | import xyz.snwjas.blog.model.vo.BlogSelectVO;
10 | import xyz.snwjas.blog.model.vo.BlogSimpleVO;
11 | import xyz.snwjas.blog.model.PageResult;
12 |
13 | import java.util.List;
14 | import java.util.Map;
15 |
16 | /**
17 | * Blog Service
18 | *
19 | * @author Myles Yang
20 | */
21 | public interface BlogService {
22 |
23 | /**
24 | * 获取已发表的博客数量
25 | *
26 | * @param status 为null则查询全部数量
27 | */
28 | int getCount(BlogStatus status);
29 |
30 | /**
31 | * 根据分类获取博客数量
32 | *
33 | * @param status 为null则查询对应分类的全部数量
34 | */
35 | int getCountByCategoryId(int categoryId, BlogStatus status);
36 |
37 | /**
38 | * 获取博客的总访问量
39 | */
40 | int getTotalVisits();
41 |
42 | /**
43 | * 根据条件获取博客分页信息(不包括originalContent与formatContent)
44 | * 默认升序分页
45 | */
46 | IPage pageBy(BlogSearchParam param);
47 |
48 | /**
49 | * 列出所有文章标题及其Id
50 | */
51 | List listAllTitle();
52 |
53 | /**
54 | * 列出博客归档,返回对应年份的归档
55 | */
56 | Map> listArchive();
57 |
58 | /**
59 | * 根据博客id获取博客的详细信息
60 | */
61 | BlogDetailVO getDetailById(int blogId);
62 |
63 | /**
64 | * 根据博客id获取博客的简单信息(不查询博客内容)
65 | */
66 | BlogSimpleVO getSimpleById(int blogId);
67 |
68 | /**
69 | * 根据博客url获取博客的详细信息
70 | */
71 | BlogDetailVO getByUrl(String blogUrl);
72 |
73 | /**
74 | * 更新博客信息
75 | */
76 | int update(BlogDetailVO vo);
77 |
78 | /**
79 | * 删除博客
80 | */
81 | int deleteById(int blogId);
82 |
83 | /**
84 | * 添加博客
85 | */
86 | int add(BlogDetailVO vo);
87 |
88 | /**
89 | * 点赞博客
90 | *
91 | * @return -1 取消点赞, 1 点赞成功,0 博客不存在
92 | */
93 | int like(int blogId);
94 |
95 | /**
96 | * 博客是否可以评论
97 | */
98 | boolean canComment(int blogId);
99 |
100 | /**
101 | * 根据博客id判断博客是否存在
102 | */
103 | boolean isExist(int blogId);
104 |
105 | /**
106 | * 根据博客路径判断博客是否存在
107 | */
108 | boolean isExist(String url);
109 |
110 | /**
111 | * 根据博客路径判断博客是否存在
112 | */
113 | boolean isExist(int blogId, String url);
114 |
115 | /**
116 | * BlogEntity to BlogSimpleVO
117 | */
118 | BlogSimpleVO covertToSimpleVO(BlogEntity blogEntity);
119 |
120 | /**
121 | * BlogEntity to BlogDetailVO
122 | */
123 | BlogDetailVO covertToDetailVO(BlogEntity blogEntity);
124 |
125 | /**
126 | * List to List
127 | */
128 | List covertToListSimpleVO(List blogEntityList);
129 |
130 | /**
131 | * IPage to PageResult
132 | */
133 | PageResult covertToPageResult(IPage blogPage);
134 |
135 |
136 | }
137 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/service/CategoryService.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.service;
2 |
3 | import com.baomidou.mybatisplus.core.metadata.IPage;
4 | import xyz.snwjas.blog.model.entity.CategoryEntity;
5 | import xyz.snwjas.blog.model.params.BasePageParam;
6 | import xyz.snwjas.blog.model.vo.CategoryVO;
7 | import xyz.snwjas.blog.model.PageResult;
8 |
9 | import java.util.List;
10 |
11 | /**
12 | * Category Service
13 | *
14 | * @author Myles Yang
15 | */
16 | public interface CategoryService {
17 |
18 | /**
19 | * 获取分类数量
20 | */
21 | int getCount();
22 |
23 | /**
24 | * 列出已使用的博客分类名
25 | */
26 | List listUsedCategory();
27 |
28 | /**
29 | * 获取所有分类
30 | */
31 | List listAllCategory();
32 |
33 | /**
34 | * 分页查询分类
35 | */
36 | IPage pageBy(BasePageParam param);
37 |
38 | /**
39 | * 根据分类id回去分类信息
40 | */
41 | CategoryVO getById(int categoryId);
42 |
43 | /**
44 | * 根据分类名回去分类信息
45 | */
46 | CategoryVO getByName(String name);
47 |
48 | /**
49 | * 添加分类
50 | *
51 | * @return 分类id, >0:添加成功; <0:已存在分类的id负值
52 | */
53 | int add(CategoryVO categoryVO);
54 |
55 | /**
56 | * 更新分类信息
57 | *
58 | * @return >0:更新成功
59 | */
60 | int update(CategoryVO categoryVO);
61 |
62 | /**
63 | * 删除分类
64 | */
65 | int deleteById(int categoryId);
66 |
67 | CategoryVO covertToVO(CategoryEntity categoryEntity);
68 |
69 | List covertToListVO(List categoryEntityList);
70 |
71 | PageResult covertToPageResult(IPage categoryPage);
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/service/CommentService.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.service;
2 |
3 | import com.baomidou.mybatisplus.core.metadata.IPage;
4 | import org.springframework.lang.NonNull;
5 | import xyz.snwjas.blog.model.PageResult;
6 | import xyz.snwjas.blog.model.entity.CommentEntity;
7 | import xyz.snwjas.blog.model.enums.CommentStatus;
8 | import xyz.snwjas.blog.model.params.BasePageParam;
9 | import xyz.snwjas.blog.model.params.CommentSearchParam;
10 | import xyz.snwjas.blog.model.vo.CommentDetailVO;
11 | import xyz.snwjas.blog.model.vo.CommentSimpleVO;
12 |
13 | import java.util.List;
14 |
15 | /**
16 | * Comment Service
17 | *
18 | * @author Myles Yang
19 | */
20 | public interface CommentService {
21 |
22 | /**
23 | * 获取所有的评论的数量
24 | */
25 | int getCountByStatus(CommentStatus status);
26 |
27 | /**
28 | * 获取博客的评论数量
29 | */
30 | int getCountByBlogIdAndStatus(int blogId, CommentStatus status);
31 |
32 | /**
33 | * 获取子评论数量
34 | */
35 | int getCountByParentIdAndStatus(int parentId, CommentStatus status);
36 |
37 | /**
38 | * 改变评论状态
39 | */
40 | int changeStatus(int commentId, CommentStatus status);
41 |
42 | /**
43 | * 批量改变评论状态
44 | *
45 | * @return 成功更新状态的数量
46 | */
47 | int changeStatus(List commentIds, CommentStatus status);
48 |
49 | /**
50 | * 删除评论
51 | */
52 | int deleteById(int commentId);
53 |
54 | /**
55 | * 批量删除评论
56 | *
57 | * @return 成功删除的数量
58 | */
59 | int deleteByIds(@NonNull List commentIds);
60 |
61 | /**
62 | * 根据博客id删除评论
63 | */
64 | int deleteByBlogId(int blogId);
65 |
66 | /**
67 | * 回复评论
68 | *
69 | * @return > 0 评论id
70 | * 0 不允许评论
71 | * -1 文章不存在
72 | */
73 | int reply(CommentDetailVO vo);
74 |
75 | /**
76 | * 根据条件搜索评论
77 | */
78 | IPage pageBy(CommentSearchParam param);
79 |
80 | /**
81 | * 分页获取前台某层评论
82 | *
83 | * @param parentId 为 0 为顶层
84 | */
85 | IPage pageBy(int blogId, int parentId, BasePageParam param);
86 |
87 | /**
88 | * 从顶层往下递归获取所有子评论
89 | */
90 | IPage pageBy(int blogId, BasePageParam param);
91 |
92 | CommentSimpleVO covertToSimpleVO(CommentEntity commentEntity);
93 |
94 | CommentDetailVO covertToDetailVO(CommentEntity commentEntity);
95 |
96 | PageResult covertToDetailPageResult(IPage page);
97 |
98 | PageResult covertToSimplePageResult(IPage page);
99 |
100 | /**
101 | * 从顶层往下递归获取所有子评论
102 | */
103 | PageResult covertToSimplePageResultByRecursively(IPage page);
104 |
105 | List covertToListDetailVO(List commentEntityList);
106 |
107 | List covertToListSimpleVO(List commentEntityList);
108 |
109 | }
110 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/service/LinkService.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.service;
2 |
3 | import com.baomidou.mybatisplus.core.metadata.IPage;
4 | import xyz.snwjas.blog.model.entity.LinkEntity;
5 | import xyz.snwjas.blog.model.params.LinkSearchParam;
6 | import xyz.snwjas.blog.model.vo.LinkVO;
7 | import xyz.snwjas.blog.model.PageResult;
8 |
9 | import java.util.List;
10 |
11 | /**
12 | * Link Service
13 | *
14 | * @author Myles Yang
15 | */
16 | public interface LinkService {
17 |
18 | /**
19 | * 条件查询友链
20 | */
21 | IPage pageBy(LinkSearchParam param);
22 |
23 | /**
24 | * 添加友链
25 | */
26 | int add(LinkVO vo);
27 |
28 | /**
29 | * 根据id删除友链
30 | */
31 | int deleteById(int linkId);
32 |
33 | /**
34 | * 更新友链
35 | */
36 | int update(LinkVO vo);
37 |
38 | /**
39 | * 获取友链数目
40 | */
41 | int getCount();
42 |
43 | /**
44 | * 根据id获取友链
45 | */
46 | LinkVO getById(int linkId);
47 |
48 | /**
49 | * 更新 URL Logo 解析器
50 | * @param parser
51 | * @return
52 | */
53 | int updateLogoParser(String parser);
54 |
55 | LinkVO covertToVO(LinkEntity linkEntity);
56 |
57 | List covertToListVO(List linkEntityList);
58 |
59 | PageResult covertToPageResult(IPage page);
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/service/LogService.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.service;
2 |
3 | import com.baomidou.mybatisplus.core.metadata.IPage;
4 | import org.springframework.lang.NonNull;
5 | import xyz.snwjas.blog.model.PageResult;
6 | import xyz.snwjas.blog.model.entity.LogEntity;
7 | import xyz.snwjas.blog.model.params.LogSearchParam;
8 | import xyz.snwjas.blog.model.vo.LogVO;
9 |
10 | import java.util.List;
11 |
12 | /**
13 | * Log Service
14 | *
15 | * @author Myles Yang
16 | */
17 | public interface LogService {
18 |
19 | /**
20 | * 条件分页搜索日志,默认按id倒序查询
21 | */
22 | IPage pageBy(LogSearchParam param);
23 |
24 | /**
25 | * 添加日志
26 | */
27 | int add(LogVO logVO);
28 |
29 | /**
30 | * 删除日志
31 | */
32 | int deleteById(int logId);
33 |
34 | /**
35 | * 批量删除日志
36 | */
37 | int deleteByIds(@NonNull List ids);
38 |
39 | LogVO covertToVO(LogEntity logEntity);
40 |
41 | LogEntity covertToEntity(LogVO logVO);
42 |
43 | List covertToListVO(List logEntityList);
44 |
45 | PageResult covertToPageResult(IPage page);
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/service/OptionsService.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.service;
2 |
3 | import xyz.snwjas.blog.model.entity.OptionsEntity;
4 | import xyz.snwjas.blog.model.vo.OptionVO;
5 |
6 | import java.util.Map;
7 |
8 | /**
9 | * Options Service
10 | *
11 | * @author Myles Yang
12 | */
13 | public interface OptionsService {
14 |
15 | /**
16 | * 获取博客设置值
17 | *
18 | * @param optionKey key
19 | * @return {@link OptionVO} if key exists, else null
20 | */
21 | OptionVO get(String optionKey);
22 |
23 | /**
24 | * 设置值,如果存在改变,不存在新建
25 | */
26 | int setAnyway(String key, String value);
27 |
28 | /**
29 | * 设置值,如果键不存在
30 | */
31 | int setIfAbsence(String key, String value);
32 |
33 | /**
34 | * 设置值,如果键存在
35 | */
36 | int setIfPresent(String key, String value);
37 |
38 | /**
39 | * 获取所有键值
40 | */
41 | Map listAll();
42 |
43 | /**
44 | * 获取必要的键值
45 | */
46 | Map listNecessary();
47 |
48 | /**
49 | * 清空查询出来的 options Map缓存
50 | */
51 | boolean resetOptionsCache();
52 |
53 | /**
54 | * OptionsEntity to OptionVO
55 | */
56 | OptionVO covertToVO(OptionsEntity optionsEntity);
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/service/SpeciallistService.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.service;
2 |
3 | import com.baomidou.mybatisplus.core.metadata.IPage;
4 | import com.baomidou.mybatisplus.extension.service.IService;
5 | import org.springframework.lang.NonNull;
6 | import xyz.snwjas.blog.model.PageResult;
7 | import xyz.snwjas.blog.model.entity.SpeciallistEntity;
8 | import xyz.snwjas.blog.model.enums.SpecialListType;
9 | import xyz.snwjas.blog.model.params.SpeciallistSearchParam;
10 | import xyz.snwjas.blog.model.vo.SpeciallistVO;
11 |
12 | import java.util.List;
13 |
14 | /**
15 | * Log Service
16 | *
17 | * @author Myles Yang
18 | */
19 | public interface SpeciallistService extends IService {
20 |
21 | /**
22 | * 获取枚举的类型
23 | */
24 | List listEnumType();
25 |
26 | /**
27 | * 获取特定类型的所有记录
28 | */
29 | List listAll(SpecialListType... types);
30 |
31 | /**
32 | * 条件分页搜索
33 | */
34 | IPage pageBy(SpeciallistSearchParam param);
35 |
36 | /**
37 | * 添加清单
38 | */
39 | int add(SpeciallistVO vo);
40 |
41 | /**
42 | * 批量导入
43 | */
44 | boolean addBatch(SpecialListType type, @NonNull List contents);
45 |
46 | /**
47 | * 删除清单
48 | */
49 | int deleteById(int id);
50 |
51 | /**
52 | * 批量删除清单
53 | */
54 | int deleteByIds(@NonNull List ids);
55 |
56 | /**
57 | * 刷新缓存
58 | */
59 | boolean refreshContext(SpecialListType type);
60 |
61 | SpeciallistVO covertToVO(SpeciallistEntity entity);
62 |
63 | List covertToListVO(List entityList);
64 |
65 | PageResult covertToPageResult(IPage page);
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/service/StatisticsService.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.service;
2 |
3 | import xyz.snwjas.blog.model.vo.StatisticsBasicVO;
4 | import xyz.snwjas.blog.model.vo.StatisticsReportVo;
5 |
6 | import java.time.LocalDateTime;
7 | import java.util.List;
8 |
9 | /**
10 | * Statistics Service
11 | *
12 | * @author Myles Yang
13 | */
14 | public interface StatisticsService {
15 |
16 | /**
17 | * 获取基本的统计信息
18 | */
19 | StatisticsBasicVO getCommonStatistics();
20 |
21 | /**
22 | * 获取时间段 start - end 的每日统计信息
23 | */
24 | List getDailyStatistics(LocalDateTime start, LocalDateTime end);
25 |
26 | /*
27 | * 统计昨日数据
28 | */
29 | void statisticsDaily();
30 |
31 | /**
32 | * 获取网站总访问量
33 | */
34 | int getWebTotalVisit();
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/service/TagService.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.service;
2 |
3 | import xyz.snwjas.blog.model.entity.TagEntity;
4 | import xyz.snwjas.blog.model.vo.TagVO;
5 |
6 | import java.util.List;
7 | import java.util.Set;
8 |
9 | /**
10 | * Tag Service
11 | *
12 | * @author Myles Yang
13 | */
14 | public interface TagService {
15 |
16 | /**
17 | * 获取所有的博客标签的数量
18 | */
19 | int getCount();
20 |
21 | /**
22 | * 获取某博客的标签
23 | */
24 | List listBlogUsed(int blogId);
25 |
26 | /**
27 | * 获取所有标签
28 | */
29 | List listAll();
30 |
31 | /**
32 | * 获取已使用的标签
33 | */
34 | List listUsed();
35 |
36 | /**
37 | * 根据id获取单个标签
38 | */
39 | TagVO getById(int tagId);
40 |
41 | /**
42 | * 根据标签id获取已使用该标签的博客id集合
43 | */
44 | Set listBlogIds(int tagId);
45 |
46 | /**
47 | * 根据名称获取单个标签
48 | */
49 | TagVO getByName(String name);
50 |
51 | /**
52 | * 添加标签
53 | *
54 | * @return >0:标签id;<0:已存在标签的id负值
55 | */
56 | int add(TagVO tagVO);
57 |
58 | /**
59 | * 添加博客标签关联表记录
60 | */
61 | int addBlogTag(int blogId, int tagId);
62 |
63 |
64 | /**
65 | * 更新标签
66 | *
67 | * @return 更新状态,>0 :更新成功
68 | */
69 | int update(TagVO tagVO);
70 |
71 | /**
72 | * 删除标签
73 | */
74 | int deleteById(int tagId);
75 |
76 | /**
77 | * 更新博客的标签
78 | *
79 | * @return 标签更新的数量
80 | */
81 | int updateBlogUsed(int blogId, List tagVOList);
82 |
83 | /**
84 | * 删除博客标签
85 | */
86 | int deleteBlogUsed(int blogId);
87 |
88 | /**
89 | * 删除博客标签关联表记录
90 | */
91 | int deleteBlogTag(int blogId, int tagId);
92 |
93 | /**
94 | * TagEntity 转换成 TagVO
95 | */
96 | TagVO covertToTagVO(TagEntity tagEntity);
97 |
98 | /**
99 | * List 转换成 List
100 | */
101 | List covertToTagVOList(List tagEntityList);
102 |
103 | }
104 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/service/UserService.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.service;
2 |
3 | import org.springframework.lang.NonNull;
4 | import org.springframework.security.core.Authentication;
5 | import xyz.snwjas.blog.model.vo.UserVO;
6 | import xyz.snwjas.blog.model.UserDetail;
7 |
8 | /**
9 | * User Service
10 | *
11 | * @author Myles Yang
12 | */
13 | public interface UserService {
14 |
15 | /**
16 | * 根据用户名获取用户信息
17 | */
18 | UserDetail getByUsername(@NonNull String username);
19 |
20 | /**
21 | * 根据用户id获取用户信息
22 | */
23 | UserDetail getByUserId(int userId);
24 |
25 | /**
26 | * 根据id更新用户信息
27 | */
28 | int updateProfile(int userId, UserVO userVO);
29 |
30 | /**
31 | * 更新密码
32 | */
33 | int updatePassword(int userId, String newPassword);
34 |
35 | /**
36 | * 获取已登录的用户认证信息
37 | */
38 | Authentication getAuth();
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/service/impl/LogServiceImpl.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.service.impl;
2 |
3 | import com.baomidou.mybatisplus.core.conditions.Wrapper;
4 | import com.baomidou.mybatisplus.core.metadata.IPage;
5 | import com.baomidou.mybatisplus.core.toolkit.Wrappers;
6 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
7 | import org.springframework.lang.NonNull;
8 | import org.springframework.stereotype.Service;
9 | import org.springframework.util.CollectionUtils;
10 | import xyz.snwjas.blog.mapper.LogMapper;
11 | import xyz.snwjas.blog.model.PageResult;
12 | import xyz.snwjas.blog.model.entity.LogEntity;
13 | import xyz.snwjas.blog.model.params.LogSearchParam;
14 | import xyz.snwjas.blog.model.vo.LogVO;
15 | import xyz.snwjas.blog.service.LogService;
16 | import xyz.snwjas.blog.utils.IPUtils;
17 |
18 | import javax.annotation.Resource;
19 | import java.util.List;
20 | import java.util.Objects;
21 | import java.util.Set;
22 | import java.util.stream.Collectors;
23 |
24 | /**
25 | * Log Service Impl
26 | *
27 | * @author Myles Yang
28 | */
29 | @Service
30 | public class LogServiceImpl implements LogService {
31 |
32 | @Resource
33 | private LogMapper logMapper;
34 |
35 | @Override
36 | public IPage pageBy(LogSearchParam param) {
37 | Page page = new Page<>(param.getCurrent(), param.getPageSize());
38 | Wrapper wrapper = Wrappers.lambdaQuery(LogEntity.class)
39 | .in(!CollectionUtils.isEmpty(param.getTypes()), LogEntity::getType, param.getTypes())
40 | .orderByDesc(LogEntity::getId);
41 | return logMapper.selectPage(page, wrapper);
42 | }
43 |
44 | @Override
45 | public int add(LogVO logVO) {
46 | LogEntity logEntity = covertToEntity(logVO);
47 | logMapper.insert(logEntity);
48 | return logEntity.getId();
49 | }
50 |
51 | @Override
52 | public int deleteById(int logId) {
53 | return logMapper.deleteById(logId);
54 | }
55 |
56 | @Override
57 | public int deleteByIds(@NonNull List ids) {
58 | Set idSet = ids.stream()
59 | .filter(id -> Objects.nonNull(id) && id > 0)
60 | .collect(Collectors.toSet());
61 | if (idSet.isEmpty()) {
62 | return 0;
63 | }
64 | return logMapper.deleteBatchIds(idSet);
65 | }
66 |
67 | @Override
68 | public LogVO covertToVO(LogEntity logEntity) {
69 | LogVO logVO = new LogVO().convertFrom(logEntity);
70 | Integer intIpv4 = logEntity.getIpAddress();
71 | if (Objects.nonNull(intIpv4)) {
72 | logVO.setIpAddress(IPUtils.intToIpv4(intIpv4));
73 | }
74 | return logVO;
75 | }
76 |
77 | @Override
78 | public LogEntity covertToEntity(LogVO logVO) {
79 | LogEntity logEntity = logVO.convertTo(new LogEntity());
80 | boolean iPv4Valid = IPUtils.isIPv4Valid(logVO.getIpAddress());
81 | if (iPv4Valid) {
82 | int intIpv4 = IPUtils.ipv4ToInt(logVO.getIpAddress());
83 | logEntity.setIpAddress(intIpv4);
84 | }
85 | return logEntity;
86 | }
87 |
88 |
89 | @Override
90 | public List covertToListVO(@NonNull List logEntityList) {
91 | return logEntityList.stream().parallel()
92 | .map(this::covertToVO)
93 | .collect(Collectors.toList());
94 | }
95 |
96 | @Override
97 | public PageResult covertToPageResult(IPage page) {
98 | List list = covertToListVO(page.getRecords());
99 | return new PageResult<>(page.getTotal(), list);
100 | }
101 |
102 | }
103 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/support/cache/CacheStore.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.support.cache;
2 |
3 | /**
4 | * 自定义缓存接口
5 | *
6 | * @author Myles Yang
7 | */
8 | public interface CacheStore {
9 |
10 | /**
11 | * 设置一个会过期的缓存
12 | *
13 | * @param key 键
14 | * @param value 值
15 | * @param seconds 秒
16 | */
17 | void set(K key, V value, int seconds);
18 |
19 | /**
20 | * 设置一个不会过期的缓存
21 | *
22 | * @param key 键
23 | * @param value 值
24 | */
25 | void set(K key, V value);
26 |
27 |
28 | /**
29 | * 获取一个缓存
30 | *
31 | * @param key 键
32 | * @return 缓存值,如果键不存在返回 null
33 | */
34 | V get(K key);
35 |
36 | /**
37 | * 删除一个缓存
38 | *
39 | * @param key 键
40 | * @return true : 删除成功 ; false : 键不存在
41 | */
42 | boolean delete(K key);
43 |
44 | /**
45 | * 是否存在缓存
46 | *
47 | * @param key 键
48 | * @return true : 存在 ; false : 不存在
49 | */
50 | boolean containsKey(K key);
51 |
52 | /**
53 | * 清空缓存
54 | */
55 | void clear();
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/support/cache/CacheWrapper.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.support.cache;
2 |
3 | import lombok.Data;
4 |
5 | import java.util.Date;
6 |
7 | /**
8 | * 缓存数据包装类
9 | *
10 | * @param 数据类型
11 | */
12 | @Data
13 | class CacheWrapper {
14 |
15 | /**
16 | * 缓存数据
17 | */
18 | private V data;
19 |
20 | /**
21 | * 创建时间
22 | */
23 | private Date createAt;
24 |
25 | /**
26 | * 过期时间
27 | */
28 | private Date expireAt;
29 |
30 | public CacheWrapper(V data) {
31 | this.data = data;
32 | }
33 |
34 | public CacheWrapper(V data, Date createAt, Date expireAt) {
35 | this.data = data;
36 | this.createAt = createAt;
37 | this.expireAt = expireAt;
38 | }
39 |
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/support/security/MyAuthenticationFailureHandler.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.support.security;
2 |
3 | import org.springframework.security.authentication.BadCredentialsException;
4 | import org.springframework.security.core.AuthenticationException;
5 | import org.springframework.security.web.authentication.AuthenticationFailureHandler;
6 | import org.springframework.stereotype.Component;
7 | import xyz.snwjas.blog.annotation.ActionRecord;
8 | import xyz.snwjas.blog.constant.RS;
9 | import xyz.snwjas.blog.model.R;
10 | import xyz.snwjas.blog.model.enums.LogType;
11 | import xyz.snwjas.blog.utils.RUtils;
12 | import xyz.snwjas.blog.utils.RWriterUtils;
13 |
14 | import javax.servlet.ServletException;
15 | import javax.servlet.http.HttpServletRequest;
16 | import javax.servlet.http.HttpServletResponse;
17 | import java.io.IOException;
18 |
19 | /**
20 | * 认证失败处理
21 | */
22 | @Component
23 | public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
24 |
25 | @ActionRecord(content = "#exception.getMessage()", type = LogType.LOGIN_FAILED)
26 | @Override
27 | public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response
28 | , AuthenticationException exception) throws IOException, ServletException {
29 | R result = RUtils.fail(exception instanceof BadCredentialsException
30 | ? RS.USERNAME_PASSWORD_ERROR
31 | : RS.SYSTEM_ERROR);
32 | RWriterUtils.writeJson(response, result);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/support/security/MyAuthenticationSuccessHandler.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.support.security;/**
2 | * todo
3 | *
4 | * @author Myles Yang
5 | */
6 |
7 | import lombok.extern.slf4j.Slf4j;
8 | import org.springframework.beans.factory.annotation.Autowired;
9 | import org.springframework.security.core.Authentication;
10 | import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
11 | import org.springframework.stereotype.Component;
12 | import xyz.snwjas.blog.annotation.ActionRecord;
13 | import xyz.snwjas.blog.config.properties.MyBlogProperties;
14 | import xyz.snwjas.blog.constant.CacheKeyPrefix;
15 | import xyz.snwjas.blog.model.UserDetail;
16 | import xyz.snwjas.blog.model.enums.LogType;
17 | import xyz.snwjas.blog.model.vo.UserVO;
18 | import xyz.snwjas.blog.support.cache.MemoryCacheStore;
19 | import xyz.snwjas.blog.utils.IPUtils;
20 | import xyz.snwjas.blog.utils.RUtils;
21 | import xyz.snwjas.blog.utils.RWriterUtils;
22 |
23 | import javax.servlet.ServletException;
24 | import javax.servlet.http.HttpServletRequest;
25 | import javax.servlet.http.HttpServletResponse;
26 | import java.io.IOException;
27 |
28 | /**
29 | * 认证成功处理
30 | */
31 | @Component
32 | @Slf4j
33 | public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
34 |
35 | @Autowired
36 | private MemoryCacheStore memoryCacheStore;
37 |
38 | @Autowired
39 | private MyBlogProperties properties;
40 |
41 | @ActionRecord(content = "#authentication.getName()", type = LogType.LOGGED_IN)
42 | @Override
43 | public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response
44 | , Authentication authentication) throws IOException, ServletException {
45 |
46 | String ipAddress = IPUtils.getIpAddress(request);
47 | log.info("用户 [{}] 登录系统,IP:[{}]", authentication.getName(), ipAddress);
48 | // 登录成功,重置登录失败次数
49 | String key = CacheKeyPrefix.LOGIN_FAILED_COUNT + ipAddress;
50 | memoryCacheStore.set(key, 0, properties.getAllowLoginFailureSeconds());
51 | // 返回登录结果
52 | UserDetail userDetails = (UserDetail) authentication.getPrincipal();
53 | UserVO userVO = new UserVO().convertFrom(userDetails);
54 | RWriterUtils.writeJson(response, RUtils.success("登录成功", userVO));
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/support/security/MyLogoutSuccessHandler.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.support.security;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import org.springframework.security.core.Authentication;
5 | import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
6 | import org.springframework.stereotype.Component;
7 | import xyz.snwjas.blog.annotation.ActionRecord;
8 | import xyz.snwjas.blog.model.R;
9 | import xyz.snwjas.blog.model.enums.LogType;
10 | import xyz.snwjas.blog.utils.IPUtils;
11 | import xyz.snwjas.blog.utils.RUtils;
12 | import xyz.snwjas.blog.utils.RWriterUtils;
13 |
14 | import javax.servlet.ServletException;
15 | import javax.servlet.http.HttpServletRequest;
16 | import javax.servlet.http.HttpServletResponse;
17 | import java.io.IOException;
18 |
19 | /**
20 | * 注销成功处理
21 | */
22 | @Component
23 | @Slf4j
24 | public class MyLogoutSuccessHandler implements LogoutSuccessHandler {
25 |
26 | @ActionRecord(value = "#authentication.getName()", type = LogType.LOGGED_OUT)
27 | @Override
28 | public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response
29 | , Authentication authentication) throws IOException, ServletException {
30 | log.info("用户 [{}] 注销登录,IP:[{}]", authentication.getName(), IPUtils.getIpAddress(request));
31 | R result = RUtils.success("登录已注销");
32 | RWriterUtils.writeJson(response, result);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/support/security/MyUserDetailsService.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.support.security;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.security.core.userdetails.UserDetails;
6 | import org.springframework.security.core.userdetails.UserDetailsService;
7 | import org.springframework.security.core.userdetails.UsernameNotFoundException;
8 | import org.springframework.stereotype.Component;
9 | import xyz.snwjas.blog.config.properties.MyBlogProperties;
10 | import xyz.snwjas.blog.constant.CacheKeyPrefix;
11 | import xyz.snwjas.blog.constant.RS;
12 | import xyz.snwjas.blog.exception.ServiceException;
13 | import xyz.snwjas.blog.model.UserDetail;
14 | import xyz.snwjas.blog.service.impl.UserServiceImpl;
15 | import xyz.snwjas.blog.support.cache.MemoryCacheStore;
16 | import xyz.snwjas.blog.utils.IPUtils;
17 |
18 | import javax.servlet.http.HttpServletRequest;
19 | import java.util.Objects;
20 | import java.util.Optional;
21 |
22 | /**
23 | * 自定义登录业务逻辑
24 | */
25 | @Component
26 | @Slf4j
27 | public class MyUserDetailsService implements UserDetailsService {
28 |
29 | @Autowired
30 | private MemoryCacheStore memoryCacheStore;
31 |
32 | @Autowired
33 | private MyBlogProperties properties;
34 |
35 | @Autowired
36 | private UserServiceImpl userService;
37 |
38 | @Override
39 | public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
40 |
41 | HttpServletRequest request = Optional.ofNullable(IPUtils.getRequest())
42 | .orElseThrow(() -> new NullPointerException("获取IP地址出错"));
43 |
44 | String ipAddress = IPUtils.getIpAddress(request);
45 |
46 | String key = CacheKeyPrefix.LOGIN_FAILED_COUNT + ipAddress;
47 | // 获取登录失败的次数
48 | Integer count = (Integer) memoryCacheStore.get(key);
49 | // 如果同一IP在规定时间内连续认证错误xx次,则拒绝该ip登录
50 | if (Objects.nonNull(count)) {
51 | if (count < properties.getAllowLoginFailureCount()) {
52 | memoryCacheStore.set(key, count + 1, properties.getAllowLoginFailureSeconds());
53 | } else {
54 | log.info("Ip: [{}] 多次登录失败", ipAddress);
55 | throw new ServiceException(RS.MULTIPLE_AUTHENTICATION_FAILURE);
56 | }
57 | } else {
58 | memoryCacheStore.set(key, 1, properties.getAllowLoginFailureSeconds());
59 | }
60 |
61 | UserDetail userDetails = userService.getByUsername(username);
62 | if (Objects.isNull(userDetails)) {
63 | throw new UsernameNotFoundException("用户[" + username + "]不存在");
64 | }
65 |
66 | return userDetails;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/support/wordfilter/EndType.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.support.wordfilter;
2 |
3 | /**
4 | * 结束类型定义
5 | *
6 | * @author minghu.zhang
7 | **/
8 | public enum EndType {
9 |
10 | /**
11 | * 有下一个,结束
12 | */
13 | HAS_NEXT, IS_END
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/support/wordfilter/FlagIndex.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.support.wordfilter;
2 |
3 | import java.util.List;
4 |
5 | /**
6 | * 敏感词标记
7 | *
8 | * @author minghu.zhang
9 | */
10 | public class FlagIndex {
11 |
12 | /**
13 | * 标记结果
14 | */
15 | private boolean flag;
16 | /**
17 | * 是否白名单词汇
18 | */
19 | private boolean isWhiteWord;
20 | /**
21 | * 标记索引
22 | */
23 | private List index;
24 |
25 | public boolean isFlag() {
26 | return flag;
27 | }
28 |
29 | public void setFlag(boolean flag) {
30 | this.flag = flag;
31 | }
32 |
33 | public List getIndex() {
34 | return index;
35 | }
36 |
37 | public void setIndex(List index) {
38 | this.index = index;
39 | }
40 |
41 | public boolean isWhiteWord() {
42 | return isWhiteWord;
43 | }
44 |
45 | public void setWhiteWord(boolean whiteWord) {
46 | isWhiteWord = whiteWord;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/support/wordfilter/WordType.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.support.wordfilter;
2 |
3 | /**
4 | * 词汇类型
5 | *
6 | * @author minghu.zhang
7 | **/
8 | public enum WordType {
9 |
10 | /**
11 | * 黑名单/白名单
12 | */
13 | BLACK, WHITE
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/utils/ClassUtils.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.utils;
2 |
3 | import java.io.File;
4 | import java.io.IOException;
5 | import java.lang.annotation.Annotation;
6 | import java.net.URL;
7 | import java.util.ArrayList;
8 | import java.util.Enumeration;
9 | import java.util.List;
10 | import java.util.Objects;
11 |
12 | public class ClassUtils {
13 |
14 | /**
15 | * 根据一个接口返回该接口的所有类,
16 | * 注意实现类需要位于该接口的包下
17 | *
18 | * @param clazz 接口
19 | * @return List> 实现接口的所有类
20 | */
21 | @SuppressWarnings("unchecked")
22 | public static List> getAllClassByInterface(Class clazz) {
23 | ArrayList> returnClassList = new ArrayList<>();
24 | // 判断是不是接口,不是接口不作处理
25 | if (clazz.isInterface()) {
26 | // 获得当前包名
27 | String packageName = clazz.getPackage().getName();
28 | try {
29 | // 获得当前包以及子包下的所有类
30 | List> allClass = getClasses(packageName);
31 | // 判断是否是一个接口
32 | for (Class> aClass : allClass) {
33 | if (clazz.isAssignableFrom(aClass) && !clazz.equals(aClass)) {
34 | returnClassList.add((Class) aClass);
35 | }
36 | }
37 | } catch (Exception e) {
38 | // TODO: handle exception
39 | }
40 | }
41 | return returnClassList;
42 | }
43 |
44 | /**
45 | * 根据一个注解返回该接口的所有类,
46 | * 注意实现类需要位于该注解的包下
47 | *
48 | * @param clazz 注解
49 | * @return List> 实现接口的所有类
50 | */
51 | public static List> getAllClassByAnnotation(Class extends Annotation> clazz) {
52 | List> returnClassList = new ArrayList<>();
53 | // 判断是不是注解
54 | if (clazz.isAnnotation()) {
55 | //获得当前包名
56 | String pkgName = clazz.getPackage().getName();
57 | try {
58 | // 获得当前包以及子包下的所有类
59 | List> allClass = getClasses(pkgName);
60 | for (Class> aClass : allClass) {
61 | if (aClass.isAnnotationPresent(clazz)) {
62 | returnClassList.add(aClass);
63 | }
64 | }
65 | } catch (Exception e) {
66 | // TODO: handle exception
67 | }
68 | }
69 | return returnClassList;
70 | }
71 |
72 | /**
73 | * 根据包名获得该包以及子包下的所有类不查找jar包中的
74 | *
75 | * @param pkgName 包名
76 | * @return List 包下所有类
77 | */
78 | private static List> getClasses(String pkgName) throws ClassNotFoundException, IOException {
79 | ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
80 | String path = pkgName.replace(".", "/");
81 | Enumeration resources = classLoader.getResources(path);
82 | List dirs = new ArrayList<>();
83 | while (resources.hasMoreElements()) {
84 | URL resource = resources.nextElement();
85 | String newPath = resource.getFile().replace("%20", " ");
86 | dirs.add(new File(newPath));
87 | }
88 | ArrayList> classes = new ArrayList<>();
89 | for (File directory : dirs) {
90 | classes.addAll(findClass(directory, pkgName));
91 | }
92 | return classes;
93 | }
94 |
95 | private static List> findClass(File dir, String pkgName) throws ClassNotFoundException {
96 | List> classes = new ArrayList<>();
97 | if (Objects.isNull(dir) || !dir.isDirectory()) {
98 | return classes;
99 | }
100 | File[] files = dir.listFiles();
101 | for (File file : files) {
102 | if (file.isDirectory()) {
103 | assert !file.getName().contains(".");
104 | classes.addAll(findClass(file, pkgName + "." + file.getName()));
105 | } else if (file.getName().endsWith(".class")) {
106 | String className = pkgName + "." + file.getName().substring(0, file.getName().length() - 6);
107 | classes.add(Class.forName(className));
108 | }
109 | }
110 | return classes;
111 | }
112 |
113 | }
114 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/utils/CodeAutoGenerator.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.utils;
2 |
3 | import com.baomidou.mybatisplus.annotation.DbType;
4 | import com.baomidou.mybatisplus.annotation.FieldFill;
5 | import com.baomidou.mybatisplus.annotation.IdType;
6 | import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
7 | import com.baomidou.mybatisplus.core.toolkit.StringUtils;
8 | import com.baomidou.mybatisplus.generator.AutoGenerator;
9 | import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
10 | import com.baomidou.mybatisplus.generator.config.GlobalConfig;
11 | import com.baomidou.mybatisplus.generator.config.PackageConfig;
12 | import com.baomidou.mybatisplus.generator.config.StrategyConfig;
13 | import com.baomidou.mybatisplus.generator.config.po.TableFill;
14 | import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
15 |
16 | import java.util.Arrays;
17 | import java.util.List;
18 | import java.util.Scanner;
19 |
20 | /**
21 | * MyBatis-Plus 的代码生成器
22 | *
23 | * @author Myles Yang
24 | */
25 | public class CodeAutoGenerator {
26 | /**
27 | * 读取控制台内容
28 | */
29 | public static String scanner(String tip) {
30 | Scanner scanner = new Scanner(System.in);
31 | System.out.println("请输入" + tip + ":");
32 | if (scanner.hasNext()) {
33 | String ipt = scanner.next();
34 | if (StringUtils.isNotBlank(ipt)) {
35 | return ipt;
36 | }
37 | }
38 | throw new MybatisPlusException("请输入正确的" + tip + "!");
39 | }
40 |
41 | public static void main(String[] args) {
42 | String moduleName = scanner("模块名");
43 | String[] tableNamesToGenerate = scanner("表名,多个英文逗号分割").split(",");
44 |
45 | // 代码生成器
46 | AutoGenerator mpg = new AutoGenerator();
47 |
48 | // 项目根目录
49 | String projectPath = System.getProperty("user.dir");
50 |
51 | //// 全局配置
52 | GlobalConfig gc = new GlobalConfig();
53 | gc.setAuthor("snwjas")
54 | .setOutputDir(projectPath + "/src/main/java")
55 | .setSwagger2(true)
56 | // id生成策略
57 | .setIdType(IdType.AUTO)
58 | .setOpen(false);
59 | gc.setEntityName("%sEntity")
60 | .setControllerName("%sController")
61 | .setMapperName("%sMapper")
62 | .setXmlName("%sMapper")
63 | .setServiceName("%sService")
64 | .setServiceImplName("%sServiceImpl");
65 | mpg.setGlobalConfig(gc);
66 |
67 |
68 | //// 数据源配置
69 | DataSourceConfig dsc = new DataSourceConfig();
70 | dsc.setDbType(DbType.MYSQL)
71 | .setDriverName("com.mysql.cj.jdbc.Driver")
72 | .setUrl("jdbc:mysql://localhost:3306/myblogdb?useSSL=true&useUnicode=true"
73 | + "&characterEncoding=UTF8&serverTimezone=Asia/Shanghai")
74 | .setUsername("root")
75 | .setPassword("root");
76 | mpg.setDataSource(dsc);
77 |
78 |
79 | //// 包配置
80 | PackageConfig pc = new PackageConfig();
81 | pc.setModuleName(moduleName)
82 | .setParent("xyz.snwjas")
83 | .setEntity("model.entity")
84 | .setController("controller")
85 | .setMapper("mapper")
86 | .setXml("mapper.xml")
87 | .setService("service")
88 | .setServiceImpl("service.impl");
89 | mpg.setPackageInfo(pc);
90 |
91 |
92 | // 自动填充字段
93 | List tableFillList = Arrays.asList(
94 | new TableFill("create_time", FieldFill.INSERT)
95 | , new TableFill("update_time", FieldFill.INSERT_UPDATE)
96 | );
97 |
98 | //// 策略配置
99 | StrategyConfig strategy = new StrategyConfig();
100 | strategy.setNaming(NamingStrategy.underline_to_camel)
101 | .setColumnNaming(NamingStrategy.underline_to_camel)
102 | .setEntityLombokModel(true)
103 | .setRestControllerStyle(true)
104 | // 字段自动填充
105 | .setTableFillList(tableFillList)
106 | // 逻辑删除字段名
107 | .setLogicDeleteFieldName("deleted")
108 | // 生成字段注解
109 | .setEntityTableFieldAnnotationEnable(true)
110 | // 需要生成的表的名字
111 | .setInclude(tableNamesToGenerate)
112 | // 驼峰转连字符:@RequestMapping("/addUser") -> @RequestMapping("/add-user")
113 | .setControllerMappingHyphenStyle(true);
114 |
115 | mpg.setStrategy(strategy);
116 | mpg.execute();
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/utils/DateUtils.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.utils;
2 |
3 | import java.time.LocalDate;
4 | import java.time.LocalDateTime;
5 | import java.time.LocalTime;
6 |
7 | /**
8 | * Date Utils
9 | *
10 | * @author Myles Yang
11 | */
12 | public class DateUtils {
13 |
14 | /**
15 | * 获取前 before 天的 零点时刻
16 | */
17 | public static LocalDateTime getZeroDateTime(int before) {
18 | return LocalDateTime.of(LocalDate.now().minusDays(before), LocalTime.MIN);
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/utils/FileUtils.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.utils;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import org.apache.commons.lang3.StringUtils;
5 |
6 | import javax.imageio.ImageIO;
7 | import java.awt.image.BufferedImage;
8 | import java.io.File;
9 | import java.io.IOException;
10 |
11 | /**
12 | * File Utils
13 | *
14 | * @author Myles Yang
15 | */
16 | @Slf4j
17 | public class FileUtils {
18 |
19 | /**
20 | * 根据文件名获取文件名称与后缀
21 | *
22 | * @param fileName
23 | * @return [name, ext],后缀含"."
24 | */
25 | public static String[] getFileNameAndExt(String fileName) {
26 | if (StringUtils.isEmpty(fileName)) {
27 | return new String[]{"", ""};
28 | }
29 | int len = fileName.length();
30 | int idx = fileName.lastIndexOf('.');
31 | String name = fileName.substring(0, idx >= 0 ? idx : len);
32 | String ext = idx >= 0 && idx < len - 1 ? fileName.substring(idx, len) : "";
33 | return new String[]{name, ext};
34 | }
35 |
36 | /**
37 | * 文件名后添加字符串,如 word.txt 添加‘-java’, 效果 word-java.txt
38 | */
39 | public static String fileNameAppend(String fileName, String append) {
40 | StringBuilder newFileName = new StringBuilder(fileName);
41 |
42 | // 是否有后缀
43 | int i = org.apache.commons.lang3.StringUtils.lastIndexOf(fileName, '.');
44 | if (i >= 0) {
45 | newFileName.insert(i, append);
46 | } else {
47 | newFileName.append(append);
48 | }
49 |
50 | return newFileName.toString();
51 | }
52 |
53 | /**
54 | * @param filePath 文件全路径
55 | * @return {-1: "文件不存在或是是文件夹", 0: "删除失败", 1: "删除成功"}
56 | */
57 | public static int deleteFile(String filePath) {
58 | File file = new File(filePath);
59 | if (!file.exists() || file.isDirectory()) {
60 | return -1;
61 | }
62 | boolean deleted = file.delete();
63 | return deleted ? 1 : 0;
64 | }
65 |
66 | /**
67 | * 获取图片像素
68 | *
69 | * @param imageFile 图片文件
70 | * @return 图片像素 {width, height}
71 | */
72 | public static int[] getImagePixel(File imageFile) {
73 | try {
74 | BufferedImage bi = ImageIO.read(imageFile);
75 | int width = bi.getWidth();
76 | int height = bi.getHeight();
77 | return new int[]{width, height};
78 | } catch (IOException e) {
79 | log.error("获取图片像素失败", e.getCause());
80 | }
81 | return new int[]{0, 0};
82 | }
83 |
84 | /**
85 | * 获取SpringWebMVC文件资源映射路径
86 | *
87 | * @param path 映射目录
88 | */
89 | public static String getFileResLoc(String path) {
90 | if (StringUtils.isBlank(path)) {
91 | throw new IllegalArgumentException("参数不能为空");
92 | }
93 | if (!path.endsWith(File.separator)) {
94 | path += File.separator;
95 | }
96 | return "file:" + path;
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/utils/IPUtils.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.utils;
2 |
3 | import org.apache.commons.lang3.StringUtils;
4 | import org.springframework.web.context.request.RequestContextHolder;
5 | import org.springframework.web.context.request.ServletRequestAttributes;
6 |
7 | import javax.servlet.http.HttpServletRequest;
8 | import java.util.Optional;
9 | import java.util.regex.Pattern;
10 |
11 | /**
12 | * IPv4 工具类
13 | */
14 | public class IPUtils {
15 |
16 | /**
17 | * 检查 IPv4 是否合法 正则表达式 Pattern 对象
18 | */
19 | private static final String _255 = "(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)";
20 | private static final Pattern PATTERN = Pattern.compile("^(?:" + _255 + "\\.){3}" + _255 + "$");
21 |
22 | /**
23 | * 获取 HttpServletRequest
24 | */
25 | public static HttpServletRequest getRequest() {
26 | return Optional.ofNullable(RequestContextHolder.getRequestAttributes())
27 | .map(r -> ((ServletRequestAttributes) r).getRequest())
28 | .orElse(null);
29 | }
30 |
31 | /**
32 | * IPv4地址是否有效
33 | */
34 | public static boolean isIPv4Valid(String ipv4) {
35 | return ipv4 != null && PATTERN.matcher(ipv4).matches();
36 | }
37 |
38 | /**
39 | * Int类型ip转为String类型
40 | */
41 | public static String intToIpv4(int intIp) {
42 | int octet3 = (intIp >>> 24) % 256;
43 | int octet2 = (intIp >>> 16) % 256;
44 | int octet1 = (intIp >>> 8) % 256;
45 | // 负数时后8位处理
46 | int last = intIp % 256;
47 | int octet0 = last < 0 ? last + 256 : last;
48 | return octet3 + "." + octet2 + "." + octet1 + "." + octet0;
49 | }
50 |
51 | /**
52 | * String类型ip转为Int类型
53 | */
54 | public static int ipv4ToInt(String ipv4) {
55 | if (isIPv4Valid(ipv4)) {
56 | String[] octets = ipv4.split("\\.");
57 | return (Integer.parseInt(octets[0]) << 24)
58 | + (Integer.parseInt(octets[1]) << 16)
59 | + (Integer.parseInt(octets[2]) << 8)
60 | + Integer.parseInt(octets[3]);
61 | }
62 | throw new IllegalArgumentException("IPv4字符串不合法!");
63 | }
64 |
65 | /**
66 | * 是否为内网IP
67 | */
68 | public static boolean isIPv4Private(String ipv4) {
69 | int intIp = ipv4ToInt(ipv4);
70 | return (intIp >= 167772160 && intIp <= 184549375)
71 | || (intIp >= -1408237568 && intIp <= -1407188993)
72 | || (intIp >= -1062731776 && intIp <= -1062666241);
73 | // return intIp >= ipv4ToInt("10.0.0.0") && intIp <= ipv4ToInt("10.255.255.255")
74 | // || intIp >= ipv4ToInt("172.16.0.0") && intIp <= ipv4ToInt("172.31.255.255")
75 | // || intIp >= ipv4ToInt("192.168.0.0") && intIp <= ipv4ToInt("192.168.255.255");
76 | }
77 |
78 | /**
79 | * 获取请求主机IP地址
80 | * 如果通过代理进来,则透过防火墙获取真实IP地址
81 | */
82 | public static String getIpAddress(HttpServletRequest request) {
83 | String ip = request.getHeader("X-Forwarded-For");
84 | if (StringUtils.isNotEmpty(ip) && !"unknown".equalsIgnoreCase(ip)) {
85 | // 多次反向代理后会有多个ip值,第一个ip才是真实ip
86 | int index = ip.indexOf(",");
87 | return index != -1 ? ip.substring(0, index) : ip;
88 | }
89 | ip = request.getHeader("X-Real-IP");
90 | if (StringUtils.isNotEmpty(ip) && !"unknown".equalsIgnoreCase(ip)) {
91 | return ip;
92 | }
93 | for (String hd : new String[]{"Proxy-Client-IP", "WL-Proxy-Client-IP",
94 | "HTTP_CLIENT_IP", "HTTP_X_FORWARDED_FOR"}) {
95 | if (StringUtils.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {
96 | ip = request.getHeader(hd);
97 | }
98 | }
99 | if (StringUtils.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {
100 | ip = request.getRemoteAddr();
101 | }
102 | return ip;
103 | }
104 |
105 | }
106 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/utils/JsonUtils.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.utils;
2 |
3 |
4 | import com.fasterxml.jackson.core.JsonProcessingException;
5 | import com.fasterxml.jackson.databind.ObjectMapper;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.context.annotation.DependsOn;
8 | import org.springframework.lang.NonNull;
9 | import org.springframework.stereotype.Component;
10 | import org.springframework.util.Assert;
11 |
12 | import java.io.IOException;
13 | import java.util.Map;
14 |
15 | /**
16 | * Json utilities.
17 | */
18 | @Component
19 | @DependsOn("objectMapper")
20 | public class JsonUtils {
21 |
22 | private static ObjectMapper objectMapper;
23 |
24 | @Autowired
25 | public JsonUtils(ObjectMapper objectMapper) {
26 | JsonUtils.objectMapper = objectMapper;
27 | }
28 |
29 |
30 | public static T jsonToObject(@NonNull String json, @NonNull Class type) throws IOException {
31 | Assert.hasText(json, "Json content must not be blank");
32 | Assert.notNull(type, "Target type must not be null");
33 |
34 | return objectMapper.readValue(json, type);
35 | }
36 |
37 |
38 | public static String objectToJson(@NonNull Object source) throws JsonProcessingException {
39 | Assert.notNull(source, "Source object must not be null");
40 |
41 | return objectMapper.writeValueAsString(source);
42 | }
43 |
44 |
45 | public static T mapToObject(@NonNull Map sourceMap, @NonNull Class type) throws IOException {
46 | Assert.notEmpty(sourceMap, "Source map must not be empty");
47 |
48 | // Serialize the map
49 | String json = objectToJson(sourceMap);
50 |
51 | // Deserialize the json format of the map
52 | return jsonToObject(json, type);
53 | }
54 |
55 |
56 | public static Map, ?> objectToMap(@NonNull Object source) throws IOException {
57 |
58 | // Serialize the source object
59 | String json = objectToJson(source);
60 |
61 | // Deserialize the json
62 | return jsonToObject(json, Map.class);
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/utils/LambdaTypeUtils.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.utils;
2 |
3 |
4 | import com.baomidou.mybatisplus.annotation.TableField;
5 | import lombok.extern.slf4j.Slf4j;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.context.annotation.DependsOn;
8 | import org.springframework.stereotype.Component;
9 | import xyz.snwjas.blog.support.cache.MemoryCacheStore;
10 |
11 | import java.io.Serializable;
12 | import java.lang.invoke.SerializedLambda;
13 | import java.lang.reflect.Field;
14 | import java.lang.reflect.Method;
15 |
16 | /**
17 | * 通过 Lambda 获取对象属性名
18 | * 使用方法: LambdaTypeUtils.getFieldName(Test::getName)
19 | * 或
20 | * 使用MyBatis-plus 获取列名
21 | * 需要正确设置实体字段的的@TableField注解
22 | */
23 | @Slf4j
24 | @Component
25 | @DependsOn("memoryCacheStore")
26 | public class LambdaTypeUtils {
27 |
28 | @FunctionalInterface
29 | public interface SFunction extends Serializable {
30 | Object get(T source);
31 | }
32 |
33 | private static final String SERIALIZED_LAMBDA_KEY = "SLK:";
34 |
35 | private static final String COLUMN_NAME_KEY = "CNK:";
36 |
37 | private static final int KEY_TIME_OUT_SECONDS = 86400; // one day
38 |
39 | private static MemoryCacheStore cache;
40 |
41 | @Autowired
42 | public LambdaTypeUtils(MemoryCacheStore cache) {
43 | LambdaTypeUtils.cache = cache;
44 | }
45 |
46 | /**
47 | * 获取字段名
48 | * 请确保正确设置实体字段的的@TableField注解
49 | */
50 | public static String getColumnName(SFunction fn) {
51 | SerializedLambda lambda = getSerializedLambda(fn);
52 | if (null == lambda) return "";
53 |
54 | String fullName = lambda.getImplClass().replaceAll("/", ".");
55 | String fieldName = getFieldName(fn);
56 |
57 | String columnName = (String) cache.get(COLUMN_NAME_KEY + fullName + "." + fieldName);
58 | if (null == columnName) {
59 | try {
60 | Class> aClass = Class.forName(fullName);
61 | Field field = aClass.getDeclaredField(fieldName);
62 | TableField annotation = field.getAnnotation(TableField.class);
63 | columnName = annotation.value();
64 | cache.set(COLUMN_NAME_KEY + fullName + "." + fieldName, columnName, KEY_TIME_OUT_SECONDS);
65 | } catch (NoSuchFieldException | ClassNotFoundException e) {
66 | e.printStackTrace();
67 | }
68 | }
69 | return columnName;
70 | }
71 |
72 | /***
73 | * 转换方法引用为属性名
74 | */
75 | public static String getFieldName(SFunction fn) {
76 | SerializedLambda lambda = getSerializedLambda(fn);
77 | if (null == lambda) return "";
78 | // 获取方法名
79 | String methodName = lambda.getImplMethodName();
80 | String prefix = null;
81 | if (methodName.startsWith("get")) {
82 | prefix = "get";
83 | } else if (methodName.startsWith("is")) {
84 | prefix = "is";
85 | }
86 | if (null == prefix) {
87 | log.error("无效的getter方法:{}", methodName);
88 | return "";
89 | }
90 | // 截取get/is之后的字符串并转换首字母为小写
91 | return toLowerCaseFirstOne(methodName.replace(prefix, ""));
92 | }
93 |
94 | /**
95 | * 首字母转小写
96 | */
97 | private static String toLowerCaseFirstOne(String s) {
98 | if (Character.isLowerCase(s.charAt(0))) {
99 | return s;
100 | } else {
101 | return Character.toLowerCase(s.charAt(0)) + s.substring(1);
102 | }
103 | }
104 |
105 | /**
106 | * 关键在于这个方法
107 | */
108 | private static SerializedLambda getSerializedLambda(Serializable fn) {
109 | SerializedLambda lambda = (SerializedLambda) cache.get(SERIALIZED_LAMBDA_KEY + fn);
110 | if (null == lambda) {
111 | try {
112 | // 提取SerializedLambda并缓存
113 | Method method = fn.getClass().getDeclaredMethod("writeReplace");
114 | method.setAccessible(Boolean.TRUE);
115 | lambda = (SerializedLambda) method.invoke(fn);
116 | cache.set(SERIALIZED_LAMBDA_KEY + fn, lambda, KEY_TIME_OUT_SECONDS);
117 | } catch (Exception e) {
118 | e.printStackTrace();
119 | }
120 | }
121 | return lambda;
122 | }
123 |
124 |
125 | }
126 |
127 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/utils/RUtils.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.utils;
2 |
3 | import org.springframework.http.HttpStatus;
4 | import xyz.snwjas.blog.constant.RS;
5 | import xyz.snwjas.blog.model.R;
6 |
7 | /**
8 | * 统一 响应 工具
9 | *
10 | * @author Myles Yang
11 | */
12 | public class RUtils {
13 |
14 | private static final Object EMPTY_DATA = null;
15 |
16 | /**
17 | * 返回 统一 响应体
18 | *
19 | * @param status 状态码
20 | * @param message 消息
21 | * @param obj 数据
22 | * @return R
23 | */
24 | public static R result(int status, String message, Object obj) {
25 | return new R(status, message, obj);
26 | }
27 |
28 | /**
29 | * 普通的成功失败响应
30 | *
31 | * @param i 小于1失败,否则成功
32 | * @param message 消息
33 | */
34 | public static R commonFailOrNot(int i, String message) {
35 | if (i < 1) {
36 | return fail(message + "失败");
37 | }
38 | return success(message + "成功");
39 | }
40 |
41 |
42 | public static R success(String message, Object data) {
43 | return result(RS.SUCCESS.status(), message, data);
44 | }
45 |
46 | public static R success(String message) {
47 | return success(message, EMPTY_DATA);
48 | }
49 |
50 | public static R succeed() {
51 | return success(RS.SUCCESS.message());
52 | }
53 |
54 | ///////////////////////////////////////////////////////////////////////////////
55 |
56 | /**
57 | * 失败,不传 status ,默认系统错误
58 | */
59 | public static R fail(String message, Object data) {
60 | return result(RS.SYSTEM_ERROR.status(), message, data);
61 | }
62 |
63 | public static R fail(String message) {
64 | return fail(message, EMPTY_DATA);
65 | }
66 |
67 |
68 | public static R fail(RS status, Object data) {
69 | return result(status.status(), status.message(), data);
70 | }
71 |
72 | public static R fail(RS status) {
73 | return result(status.status(), status.message(), EMPTY_DATA);
74 | }
75 |
76 |
77 | public static R fail(HttpStatus httpStatus, Object data) {
78 | return result(httpStatus.value(), httpStatus.getReasonPhrase(), data);
79 | }
80 |
81 | public static R fail(HttpStatus httpStatus) {
82 | return fail(httpStatus, EMPTY_DATA);
83 | }
84 |
85 |
86 | }
87 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/utils/RWriterUtils.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.utils;
2 |
3 | import com.fasterxml.jackson.core.JsonProcessingException;
4 | import xyz.snwjas.blog.model.R;
5 |
6 | import javax.servlet.ServletResponse;
7 | import java.io.IOException;
8 | import java.nio.charset.StandardCharsets;
9 |
10 | /**
11 | * 返回 响应 结果 工具
12 | *
13 | * @author Myles Yang
14 | */
15 | public class RWriterUtils {
16 |
17 | /**
18 | * 默认编码
19 | */
20 | private static final String DEFAULT_ENCODING = StandardCharsets.UTF_8.name();
21 |
22 |
23 | public static void writeTextHtml(ServletResponse response, String textHtml) {
24 | writeString(response, "text/html", DEFAULT_ENCODING, textHtml);
25 | }
26 |
27 | public static void writeJson(ServletResponse response, String jsonString) {
28 | writeString(response, "application/json", DEFAULT_ENCODING, jsonString);
29 | }
30 |
31 | public static void writeJson(ServletResponse response, R r) {
32 | try {
33 | writeJson(response, JsonUtils.objectToJson(r));
34 | } catch (JsonProcessingException e) {
35 | throw new RuntimeException(e);
36 | }
37 | }
38 |
39 | public static void writeString(ServletResponse response, String contentType, String encoding, String string) {
40 | try {
41 | response.setContentType(contentType + ";charset=" + encoding);
42 | response.getWriter().write(string);
43 | response.getWriter().close();
44 | } catch (IOException e) {
45 | throw new RuntimeException(e);
46 | }
47 | }
48 |
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/utils/StrUtils.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.utils;
2 |
3 | import org.apache.commons.lang3.StringUtils;
4 |
5 | /**
6 | * String Utils
7 | *
8 | * @author Myles Yang
9 | */
10 | public class StrUtils {
11 |
12 | /**
13 | * 移除字符串中的空白字符
14 | */
15 | public static String removeBlank(String text) {
16 | if (StringUtils.isBlank(text)) {
17 | return "";
18 | }
19 | StringBuilder newString = new StringBuilder();
20 | char[] chars = text.toCharArray();
21 | for (char c : chars) {
22 | if (Character.isWhitespace(c)) {
23 | continue;
24 | }
25 | newString.append(c);
26 | }
27 | return newString.toString();
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/xyz/snwjas/blog/utils/URLUtils.java:
--------------------------------------------------------------------------------
1 | package xyz.snwjas.blog.utils;
2 |
3 | import java.io.UnsupportedEncodingException;
4 | import java.net.URLDecoder;
5 | import java.net.URLEncoder;
6 | import java.nio.charset.StandardCharsets;
7 | import java.util.regex.Matcher;
8 | import java.util.regex.Pattern;
9 |
10 | /**
11 | * URL utils
12 | *
13 | * @author Myles Yang
14 | */
15 | public class URLUtils {
16 |
17 | public static final String DEFAULT_ENCODING = StandardCharsets.UTF_8.name();
18 |
19 | // URL 中合法字符
20 | public static final Pattern PATTERN = Pattern.compile("[^0-9a-zA-Z-_.~!*'();:@&=+$,/?#\\[\\]]");
21 |
22 | /**
23 | * 编码整个链接
24 | */
25 | public static String encodeAll(String url) {
26 | Matcher m = PATTERN.matcher(url);
27 | StringBuffer b = new StringBuffer();
28 | try {
29 | while (m.find()) {
30 | m.appendReplacement(b, URLEncoder.encode(m.group(0), DEFAULT_ENCODING));
31 | }
32 | } catch (UnsupportedEncodingException e) {
33 | e.printStackTrace();
34 | return "";
35 | }
36 | m.appendTail(b);
37 | return b.toString();
38 | }
39 |
40 | /**
41 | * 编码链接的最后部分
42 | * 如:localhost:9527//index/img-百度logo.jpg,只编码 img-百度logo.jpg
43 | */
44 | public static String encodeLast(String url) {
45 | int i = url.lastIndexOf('/');
46 | String last = url.substring(i + 1);
47 | String encodedLast;
48 | try {
49 | encodedLast = URLEncoder.encode(last, DEFAULT_ENCODING);
50 | } catch (UnsupportedEncodingException e) {
51 | e.printStackTrace();
52 | return "";
53 | }
54 | return url.substring(0, i) + encodedLast;
55 | }
56 |
57 | public static String decode(String str) {
58 | try {
59 | return URLDecoder.decode(str, DEFAULT_ENCODING);
60 | } catch (UnsupportedEncodingException e) {
61 | throw new RuntimeException(e);
62 | }
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/src/main/resources/admin/.gitkeep:
--------------------------------------------------------------------------------
1 | # Ignore everything in this directory
2 | *
3 | # Except this file !.gitkeep
4 |
--------------------------------------------------------------------------------
/src/main/resources/app/.gitkeep:
--------------------------------------------------------------------------------
1 | # Ignore everything in this directory
2 | *
3 | # Except this file !.gitkeep
4 |
--------------------------------------------------------------------------------
/src/main/resources/application-dev.yaml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 9096
3 | tomcat:
4 | max-swallow-size: -1
5 |
6 | spring:
7 | profiles: dev
8 | datasource:
9 | driver-class-name: com.mysql.jdbc.Driver
10 | url: jdbc:mysql://localhost:3306/myblogdb?allowPublicKeyRetrieval=true&useSSL=false&useUnicode=true&characterEncoding=UTF8&serverTimezone=Asia/Shanghai
11 | username: root
12 | password: root
13 | servlet:
14 | multipart:
15 | max-file-size: 10MB
16 | max-request-size: 100MB
17 |
18 | mybatis-plus:
19 | configuration:
20 | # log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
21 | default-enum-type-handler: com.baomidou.mybatisplus.extension.handlers.MybatisEnumTypeHandler
22 | mapper-locations:
23 | - classpath:xyz/snwjas/blog/mapper/xml/*.xml
24 |
25 | my-blog:
26 | doc-enable: true
27 | admin-path: admin
28 |
29 |
--------------------------------------------------------------------------------
/src/main/resources/application-prod.yaml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 9096
3 | tomcat:
4 | max-swallow-size: -1
5 |
6 | spring:
7 | profiles: prod
8 | datasource:
9 | driver-class-name: com.mysql.jdbc.Driver
10 | url: jdbc:mysql://localhost:3306/myblogdb?allowPublicKeyRetrieval=true&useSSL=false&useUnicode=true&characterEncoding=UTF8&serverTimezone=Asia/Shanghai
11 | username: root
12 | password: root
13 | servlet:
14 | multipart:
15 | max-file-size: 10MB
16 | max-request-size: 100MB
17 |
18 | mybatis-plus:
19 | configuration:
20 | # log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
21 | default-enum-type-handler: com.baomidou.mybatisplus.extension.handlers.MybatisEnumTypeHandler
22 | mapper-locations:
23 | - classpath:xyz/snwjas/blog/mapper/xml/*.xml
24 |
25 | my-blog:
26 | doc-enable: false
27 | admin-path: madmin
28 |
29 |
--------------------------------------------------------------------------------
/src/main/resources/application.yaml:
--------------------------------------------------------------------------------
1 | spring:
2 | profiles:
3 | active: dev
4 | # active: prod
5 |
--------------------------------------------------------------------------------
/src/main/resources/banner.txt:
--------------------------------------------------------------------------------
1 | ${AnsiColor.BLUE}
2 | __ __ ____ _
3 | | \/ | _ _ | __ ) | | ___ __ _
4 | | |\/| | | | | | | _ \ | | / _ \ / _` |
5 | | | | | | |_| | | |_) | | | | (_) | | (_| |
6 | |_| |_| \__, | |____/ |_| \___/ \__, |
7 | |___/ |___/
8 | ${AnsiColor.BLUE}
9 | Version: ${application.version}
10 |
--------------------------------------------------------------------------------
/src/main/resources/static/.gitkeep:
--------------------------------------------------------------------------------
1 | # Ignore everything in this directory
2 | *
3 | # Except this file !.gitkeep
4 |
--------------------------------------------------------------------------------
/src/test/java/xyz/snwjas/blog/.gitkeep:
--------------------------------------------------------------------------------
1 | # Ignore everything in this directory
2 | *
3 | # Except this file !.gitkeep
4 |
--------------------------------------------------------------------------------