├── .gitignore ├── LICENSE ├── README.md ├── blog-api ├── docker-web │ ├── dockerfile │ └── readme.txt ├── docker │ ├── docker-compose.yml │ ├── dockerfile │ └── readme.txt ├── pom.xml ├── r_blog_dev.sql └── src │ └── main │ ├── java │ └── cn │ │ └── raxcl │ │ ├── BlogApiApplication.java │ │ ├── annotation │ │ ├── AccessLimit.java │ │ ├── AopProxy.java │ │ ├── OperationLogger.java │ │ └── VisitLogger.java │ │ ├── aspect │ │ ├── ExceptionLogAspect.java │ │ ├── OperationLogAspect.java │ │ └── VisitLogAspect.java │ │ ├── common │ │ ├── CommonService.java │ │ └── impl │ │ │ └── CommonServiceImpl.java │ │ ├── config │ │ ├── JwtFilter.java │ │ ├── JwtLoginFilter.java │ │ ├── MyAuthenticationEntryPoint.java │ │ ├── RedisSerializeConfig.java │ │ ├── RestTemplateConfig.java │ │ ├── SecurityConfig.java │ │ ├── WebConfig.java │ │ └── properties │ │ │ ├── BlogProperties.java │ │ │ ├── GithubProperties.java │ │ │ ├── ProxyProperties.java │ │ │ ├── TelegramProperties.java │ │ │ ├── TxYunProperties.java │ │ │ └── UploadProperties.java │ │ ├── constant │ │ ├── CommentConstants.java │ │ ├── CommonConstants.java │ │ ├── JwtConstants.java │ │ ├── PageConstants.java │ │ ├── RedisKeyConstants.java │ │ ├── SiteSettingConstants.java │ │ └── UploadConstants.java │ │ ├── controller │ │ ├── admin │ │ │ ├── AboutAdminController.java │ │ │ ├── BlogAdminController.java │ │ │ ├── CategoryAdminController.java │ │ │ ├── CommentAdminController.java │ │ │ ├── DashboardAdminController.java │ │ │ ├── ExceptionLogController.java │ │ │ ├── FriendAdminController.java │ │ │ ├── LoginAdminController.java │ │ │ ├── LoginLogController.java │ │ │ ├── MomentAdminController.java │ │ │ ├── OperationLogController.java │ │ │ ├── ScheduleJobController.java │ │ │ ├── SiteSettingAdminController.java │ │ │ ├── TagAdminController.java │ │ │ ├── VisitLogController.java │ │ │ └── VisitorAdminController.java │ │ └── view │ │ │ ├── AboutController.java │ │ │ ├── ArchiveController.java │ │ │ ├── BlogController.java │ │ │ ├── CategoryController.java │ │ │ ├── CommentController.java │ │ │ ├── FriendController.java │ │ │ ├── IndexController.java │ │ │ ├── LoginController.java │ │ │ ├── MomentController.java │ │ │ └── TagController.java │ │ ├── entity │ │ ├── About.java │ │ ├── Blog.java │ │ ├── Category.java │ │ ├── CityVisitor.java │ │ ├── Comment.java │ │ ├── ExceptionLog.java │ │ ├── Friend.java │ │ ├── LoginLog.java │ │ ├── Moment.java │ │ ├── OperationLog.java │ │ ├── ScheduleJob.java │ │ ├── ScheduleJobLog.java │ │ ├── SiteSetting.java │ │ ├── Tag.java │ │ ├── User.java │ │ ├── VisitLog.java │ │ ├── VisitRecord.java │ │ └── Visitor.java │ │ ├── enums │ │ ├── CommentOpenStateEnum.java │ │ ├── CommentPageEnum.java │ │ └── VisitBehavior.java │ │ ├── exception │ │ ├── BadRequestException.java │ │ ├── NotFoundException.java │ │ └── PersistenceException.java │ │ ├── handler │ │ └── ControllerExceptionHandler.java │ │ ├── interceptor │ │ └── AccessLimitInterceptor.java │ │ ├── mapper │ │ ├── AboutMapper.java │ │ ├── BlogMapper.java │ │ ├── CategoryMapper.java │ │ ├── CityVisitorMapper.java │ │ ├── CommentMapper.java │ │ ├── ExceptionLogMapper.java │ │ ├── FriendMapper.java │ │ ├── LoginLogMapper.java │ │ ├── MomentMapper.java │ │ ├── OperationLogMapper.java │ │ ├── ScheduleJobLogMapper.java │ │ ├── ScheduleJobMapper.java │ │ ├── SiteSettingMapper.java │ │ ├── TagMapper.java │ │ ├── UserMapper.java │ │ ├── VisitLogMapper.java │ │ ├── VisitRecordMapper.java │ │ └── VisitorMapper.java │ │ ├── model │ │ ├── bean │ │ │ ├── Badge.java │ │ │ ├── Copyright.java │ │ │ └── Favorite.java │ │ ├── dto │ │ │ ├── BlogDTO.java │ │ │ ├── BlogPasswordDTO.java │ │ │ ├── BlogViewDTO.java │ │ │ ├── BlogVisibilityDTO.java │ │ │ ├── CommentDTO.java │ │ │ ├── FriendDTO.java │ │ │ ├── LoginInfoDTO.java │ │ │ ├── VisitLogRemark.java │ │ │ └── VisitLogUuidTimeDTO.java │ │ ├── temp │ │ │ ├── LogDTO.java │ │ │ ├── PageDTO.java │ │ │ └── PostCommentDTO.java │ │ └── vo │ │ │ ├── ArchiveBlogVO.java │ │ │ ├── BlogDetailVO.java │ │ │ ├── BlogIdAndTitleVO.java │ │ │ ├── BlogInfoVO.java │ │ │ ├── CategoryBlogCountVO.java │ │ │ ├── FriendInfoVO.java │ │ │ ├── FriendVO.java │ │ │ ├── IntroductionVO.java │ │ │ ├── NewBlogVO.java │ │ │ ├── PageCommentVO.java │ │ │ ├── PageResultVO.java │ │ │ ├── QqResultVO.java │ │ │ ├── QqVO.java │ │ │ ├── RandomBlogVO.java │ │ │ ├── SearchBlogVO.java │ │ │ └── TagBlogCountVO.java │ │ ├── service │ │ ├── AboutService.java │ │ ├── BlogService.java │ │ ├── CategoryService.java │ │ ├── CityVisitorService.java │ │ ├── CommentService.java │ │ ├── DashboardService.java │ │ ├── ExceptionLogService.java │ │ ├── FriendService.java │ │ ├── LoginLogService.java │ │ ├── MailService.java │ │ ├── MomentService.java │ │ ├── OperationLogService.java │ │ ├── RedisService.java │ │ ├── ScheduleJobService.java │ │ ├── SiteSettingService.java │ │ ├── TagService.java │ │ ├── UserService.java │ │ ├── VisitLogService.java │ │ ├── VisitRecordService.java │ │ ├── VisitorService.java │ │ └── impl │ │ │ ├── AboutServiceImpl.java │ │ │ ├── BlogServiceImpl.java │ │ │ ├── CategoryServiceImpl.java │ │ │ ├── CityVisitorServiceImpl.java │ │ │ ├── CommentServiceImpl.java │ │ │ ├── DashboardServiceImpl.java │ │ │ ├── ExceptionLogServiceImpl.java │ │ │ ├── FriendServiceImpl.java │ │ │ ├── LoginLogServiceImpl.java │ │ │ ├── MailServiceImpl.java │ │ │ ├── MomentServiceImpl.java │ │ │ ├── OperationLogServiceImpl.java │ │ │ ├── RedisServiceImpl.java │ │ │ ├── ScheduleJobServiceImpl.java │ │ │ ├── SiteSettingServiceImpl.java │ │ │ ├── TagServiceImpl.java │ │ │ ├── UserServiceImpl.java │ │ │ ├── VisitLogServiceImpl.java │ │ │ ├── VisitRecordServiceImpl.java │ │ │ └── VisitorServiceImpl.java │ │ ├── task │ │ ├── MysqlBackupScheduleTask.java │ │ ├── RedisSyncScheduleTask.java │ │ └── VisitorSyncScheduleTask.java │ │ └── util │ │ ├── AopUtils.java │ │ ├── HashUtils.java │ │ ├── ImageUtils.java │ │ ├── IpAddressUtils.java │ │ ├── JacksonUtils.java │ │ ├── JwtUtils.java │ │ ├── MailUtils.java │ │ ├── QqInfoUtils.java │ │ ├── StringUtils.java │ │ ├── UserAgentUtils.java │ │ ├── comment │ │ ├── CommentUtils.java │ │ └── channel │ │ │ ├── ChannelFactory.java │ │ │ ├── CommentNotifyChannel.java │ │ │ ├── MailChannel.java │ │ │ └── TelegramChannel.java │ │ ├── common │ │ ├── Result.java │ │ ├── SpringContextUtils.java │ │ └── ValidatorUtils.java │ │ ├── markdown │ │ ├── MarkdownUtils.java │ │ └── ext │ │ │ ├── cover │ │ │ ├── Cover.java │ │ │ ├── CoverExtension.java │ │ │ └── internal │ │ │ │ ├── AbstractCoverNodeRenderer.java │ │ │ │ ├── CoverDelimiterProcessor.java │ │ │ │ ├── CoverHtmlNodeRenderer.java │ │ │ │ └── CoverTextContentNodeRenderer.java │ │ │ └── curtain │ │ │ ├── Curtain.java │ │ │ ├── CurtainExtension.java │ │ │ └── internal │ │ │ ├── AbstractCurtainNodeRenderer.java │ │ │ ├── CurtainDelimiterProcessor.java │ │ │ ├── CurtainHtmlNodeRenderer.java │ │ │ └── CurtainTextContentNodeRenderer.java │ │ ├── quartz │ │ ├── QuartzJob.java │ │ ├── ScheduleRunnable.java │ │ └── ScheduleUtils.java │ │ ├── telegram │ │ ├── TelegramBotMsgHandler.java │ │ └── TelegramUtils.java │ │ └── upload │ │ ├── UploadUtils.java │ │ └── channel │ │ ├── ChannelFactory.java │ │ ├── FileUploadChannel.java │ │ ├── GithubChannel.java │ │ ├── LocalChannel.java │ │ └── TxYunChannel.java │ └── resources │ ├── application.yml │ ├── ipdb │ └── ip2region.xdb │ ├── logback-spring.xml │ ├── mapper │ ├── AboutMapper.xml │ ├── BlogMapper.xml │ ├── CategoryMapper.xml │ ├── CityVisitorMapper.xml │ ├── CommentMapper.xml │ ├── ExceptionLogMapper.xml │ ├── FriendMapper.xml │ ├── LoginLogMapper.xml │ ├── MomentMapper.xml │ ├── OperationLogMapper.xml │ ├── ScheduleJobLogMapper.xml │ ├── ScheduleJobMapper.xml │ ├── SiteSettingMapper.xml │ ├── TagMapper.xml │ ├── UserMapper.xml │ ├── VisitLogMapper.xml │ ├── VisitRecordMapper.xml │ └── VisitorMapper.xml │ └── templates │ ├── guest.html │ └── owner.html ├── blog-cms ├── .env.development ├── .env.production ├── .gitignore ├── README.md ├── babel.config.js ├── deploy.config.js ├── package-lock.json ├── package.json ├── public │ ├── favicon.ico │ ├── img │ │ ├── avatar.jpg │ │ ├── comment-avatar │ │ │ ├── 1.jpg │ │ │ ├── 2.jpg │ │ │ ├── 3.jpg │ │ │ ├── 4.jpg │ │ │ ├── 5.jpg │ │ │ └── 6.jpg │ │ └── visitor.jpg │ └── index.html ├── src │ ├── App.vue │ ├── api │ │ ├── ExceptionLog.js │ │ ├── about.js │ │ ├── blog.js │ │ ├── category.js │ │ ├── comment.js │ │ ├── dashboard.js │ │ ├── friend.js │ │ ├── github.js │ │ ├── login.js │ │ ├── loginLog.js │ │ ├── moment.js │ │ ├── operationLog.js │ │ ├── schedule.js │ │ ├── siteSetting.js │ │ ├── tag.js │ │ ├── visitLog.js │ │ └── visitor.js │ ├── assets │ │ ├── 404_images │ │ │ ├── 404.png │ │ │ └── 404_cloud.png │ │ └── styles │ │ │ ├── base.css │ │ │ ├── element-ui.scss │ │ │ ├── index.scss │ │ │ ├── mixin.scss │ │ │ ├── sidebar.scss │ │ │ ├── transition.scss │ │ │ └── variables.scss │ ├── common │ │ └── font │ │ │ ├── dsc.ttf │ │ │ └── font.css │ ├── components │ │ ├── Breadcrumb │ │ │ └── index.vue │ │ ├── DateTimeRangePicker.vue │ │ ├── Hamburger │ │ │ └── index.vue │ │ └── SvgIcon │ │ │ └── index.vue │ ├── icons │ │ ├── index.js │ │ ├── svg │ │ │ ├── article.svg │ │ │ ├── bianjizhandian.svg │ │ │ ├── biaoqian.svg │ │ │ ├── dashboard.svg │ │ │ ├── eye-open.svg │ │ │ ├── eye.svg │ │ │ ├── friend.svg │ │ │ ├── github.svg │ │ │ ├── logout.svg │ │ │ ├── markdown.svg │ │ │ ├── password.svg │ │ │ ├── pinglun-blue.svg │ │ │ ├── pv.svg │ │ │ ├── user.svg │ │ │ └── yonghu.svg │ │ └── svgo.yml │ ├── layout │ │ ├── components │ │ │ ├── AppMain.vue │ │ │ ├── Navbar.vue │ │ │ ├── Sidebar │ │ │ │ ├── FixiOSBug.js │ │ │ │ ├── Item.vue │ │ │ │ ├── Link.vue │ │ │ │ ├── Logo.vue │ │ │ │ ├── SidebarItem.vue │ │ │ │ └── index.vue │ │ │ └── index.js │ │ ├── index.vue │ │ └── mixin │ │ │ └── ResizeHandler.js │ ├── main.js │ ├── router │ │ └── index.js │ ├── settings.js │ ├── store │ │ ├── getters.js │ │ ├── index.js │ │ └── modules │ │ │ ├── app.js │ │ │ └── settings.js │ ├── util │ │ ├── city2coord.json │ │ ├── copy.js │ │ ├── dateTimeFormatUtils.js │ │ ├── directive.js │ │ ├── get-page-title.js │ │ ├── reg.js │ │ ├── request.js │ │ ├── task-queue.js │ │ ├── uuid.js │ │ └── validate.js │ └── views │ │ ├── 404.vue │ │ ├── blog │ │ ├── blog │ │ │ ├── BlogList.vue │ │ │ └── WriteBlog.vue │ │ ├── category │ │ │ └── CategoryList.vue │ │ ├── comment │ │ │ └── CommentList.vue │ │ ├── moment │ │ │ ├── MomentList.vue │ │ │ └── WriteMoment.vue │ │ └── tag │ │ │ └── TagList.vue │ │ ├── dashboard │ │ └── index.vue │ │ ├── log │ │ ├── ExceptionLog.vue │ │ ├── LoginLog.vue │ │ ├── OperationLog.vue │ │ ├── ScheduleJobLog.vue │ │ └── VisitLog.vue │ │ ├── login │ │ └── index.vue │ │ ├── page │ │ ├── About.vue │ │ ├── FriendList.vue │ │ └── SiteSetting.vue │ │ ├── pictureHosting │ │ ├── GithubManage.vue │ │ ├── Setting.vue │ │ └── TxyunManage.vue │ │ ├── statistics │ │ └── Visitor.vue │ │ └── system │ │ └── ScheduleJobList.vue └── vue.config.js ├── blog-view ├── .env.development ├── .env.production ├── .gitignore ├── README.md ├── babel.config.js ├── package-lock.json ├── package.json ├── public │ ├── favicon.ico │ ├── img │ │ ├── avatar.jpg │ │ ├── beian.png │ │ ├── comment-avatar │ │ │ ├── 1.jpg │ │ │ ├── 2.jpg │ │ │ ├── 3.jpg │ │ │ ├── 4.jpg │ │ │ ├── 5.jpg │ │ │ ├── 6.jpg │ │ │ └── avatar.jpg │ │ ├── error.png │ │ ├── paper-plane.png │ │ ├── qr.jpg │ │ └── reward.jpg │ └── index.html ├── src │ ├── App.vue │ ├── api │ │ ├── about.js │ │ ├── archives.js │ │ ├── blog.js │ │ ├── category.js │ │ ├── comment.js │ │ ├── friend.js │ │ ├── home.js │ │ ├── index.js │ │ ├── login.js │ │ ├── moment.js │ │ └── tag.js │ ├── assets │ │ └── css │ │ │ ├── badge.css │ │ │ ├── base.css │ │ │ ├── icon │ │ │ ├── iconfont.css │ │ │ ├── iconfont.eot │ │ │ ├── iconfont.js │ │ │ ├── iconfont.json │ │ │ ├── iconfont.svg │ │ │ ├── iconfont.ttf │ │ │ ├── iconfont.woff │ │ │ └── iconfont.woff2 │ │ │ └── typo.css │ ├── common │ │ ├── font │ │ │ ├── dsc.ttf │ │ │ └── font.css │ │ └── reg.js │ ├── components │ │ ├── blog │ │ │ ├── BlogItem.vue │ │ │ ├── BlogList.vue │ │ │ └── Pagination.vue │ │ ├── comment │ │ │ ├── Comment.vue │ │ │ ├── CommentForm.vue │ │ │ ├── CommentList.vue │ │ │ └── Pagination.vue │ │ ├── index │ │ │ ├── BlogPasswordDialog.vue │ │ │ ├── Footer.vue │ │ │ ├── Header.vue │ │ │ ├── MyAPlayer.vue │ │ │ └── Nav.vue │ │ ├── live2d │ │ │ ├── lib │ │ │ │ └── live2d.min.js │ │ │ ├── live2d.vue │ │ │ └── options │ │ │ │ ├── myModels.js │ │ │ │ └── tips.js │ │ ├── mylogo │ │ │ └── mylogo.vue │ │ └── sidebar │ │ │ ├── Introduction.vue │ │ │ ├── RandomBlog.vue │ │ │ ├── Tags.vue │ │ │ └── Tocbot.vue │ ├── main.js │ ├── plugins │ │ ├── aruMapper.json │ │ ├── axios.js │ │ ├── paopaoMapper.json │ │ └── tvMapper.json │ ├── router │ │ └── index.js │ ├── store │ │ ├── actions.js │ │ ├── getters.js │ │ ├── index.js │ │ ├── mutations-types.js │ │ ├── mutations.js │ │ └── state.js │ ├── util │ │ ├── dateTimeFormatUtils.js │ │ ├── directive.js │ │ └── getPageTitle.js │ └── views │ │ ├── Index.vue │ │ ├── Login.vue │ │ ├── about │ │ └── About.vue │ │ ├── archives │ │ └── Archives.vue │ │ ├── blog │ │ └── Blog.vue │ │ ├── category │ │ └── Category.vue │ │ ├── friends │ │ └── Friends.vue │ │ ├── home │ │ └── Home.vue │ │ ├── moments │ │ └── Moments.vue │ │ └── tag │ │ └── Tag.vue └── vue.config.js ├── package-lock.json └── sql_data └── r_blog.sql /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | log/ 22 | 23 | ### NetBeans ### 24 | /nbproject/private/ 25 | /nbbuild/ 26 | /dist/ 27 | /nbdist/ 28 | /.nb-gradle/ 29 | build/ 30 | !**/src/main/**/build/ 31 | !**/src/test/**/build/ 32 | 33 | ### VS Code ### 34 | .vscode/ 35 | 36 | /blog-cms-tmp 37 | 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 raxcl 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 | -------------------------------------------------------------------------------- /blog-api/docker-web/dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx 2 | 3 | MAINTAINER cyl 4 | 5 | RUN rm /etc/nginx/conf.d/default.conf 6 | 7 | ADD default.conf /etc/nginx/conf.d/ 8 | 9 | COPY dist/ /usr/share/nginx/html/ -------------------------------------------------------------------------------- /blog-api/docker-web/readme.txt: -------------------------------------------------------------------------------- 1 | 需要将vue项目进行打包放到当前目录下的dist目录下 2 | npm run build 3 | 镜像的维护者信息为 那个cyl也要进行修改 4 | 5 | 然后运行dockerfile文件即可 6 | docker compose up -d . 7 | 8 | -------------------------------------------------------------------------------- /blog-api/docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | web: 4 | build: . 5 | ports: 6 | - "port:port" 7 | depends_on: 8 | - db 9 | - redis 10 | db: 11 | image: mysql:8.0 12 | ports: 13 | - "3306:3306" 14 | environment: 15 | MYSQL_ROOT_PASSWORD: 123456 16 | MYSQL_DATABASE: databaseName 17 | MYSQL_USER: myuser 18 | MYSQL_PASSWORD: 123456 19 | redis: 20 | image: redis:latest 21 | ports: 22 | - "6379:6379" -------------------------------------------------------------------------------- /blog-api/docker/dockerfile: -------------------------------------------------------------------------------- 1 | # 使用官方的Java基础镜像 2 | FROM openjdk:8-jdk-alpine 3 | # 将本地的打包的jar文件复制到容器中 4 | COPY xx.jar xx.jar 5 | # 暴露端口,这个根据自己需求进行更改 6 | EXPOSE 8080 7 | # 运行命令 8 | ENTRYPOINT ["java", "-jar", "/xx.jar"] -------------------------------------------------------------------------------- /blog-api/docker/readme.txt: -------------------------------------------------------------------------------- 1 | 自行更改dockerfile的jar包文件名称,和端口号,运行jar包的名称 2 | 自行更改docker-compose.yml的 ports:下面的port改成自己需要的端口号 3 | 数据库: environment: 4 | MYSQL_ROOT_PASSWORD: 123456 5 | MYSQL_DATABASE: databaseName 6 | MYSQL_USER: myuser 7 | MYSQL_PASSWORD: 123456 8 | root的密码,和需要的数据库名称都需要自行更改。 9 | 10 | 改好后: 11 | docker compose up -d . 12 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/BlogApiApplication.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.context.annotation.EnableAspectJAutoProxy; 6 | 7 | import java.util.TimeZone; 8 | 9 | /** 10 | * @author c-long.chan 11 | * @date 2022-01-04 10:36:05 12 | */ 13 | @SpringBootApplication 14 | @EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true) 15 | public class BlogApiApplication { 16 | 17 | public static void main(String[] args) { 18 | TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai")); 19 | SpringApplication.run(BlogApiApplication.class, args); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/annotation/AccessLimit.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.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 | * @author Raxcl 11 | * @date 2022-01-07 16:59:46 12 | */ 13 | @Target(ElementType.METHOD) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface AccessLimit { 16 | /** 17 | * 限制周期(秒) 18 | */ 19 | int seconds(); 20 | 21 | /** 22 | * 规定周期内限制次数 23 | */ 24 | int maxCount(); 25 | 26 | /** 27 | * 触发限制时的消息提示 28 | */ 29 | String msg() default "操作频率过高"; 30 | } -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/annotation/AopProxy.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.annotation; 2 | 3 | import org.springframework.aop.framework.AopContext; 4 | 5 | /** 6 | * 封装self()方法便于获取自身接口代理类 7 | * @author c-long.chan 8 | * 2022-01-06 10:47:50 9 | */ 10 | public interface AopProxy { 11 | /** 12 | * self()方法 13 | * @return default 14 | */ 15 | @SuppressWarnings("unchecked") 16 | default T self() { 17 | return (T) AopContext.currentProxy(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/annotation/OperationLogger.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.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 | * @author Raxcl 11 | * @date 2022-01-07 16:59:52 12 | */ 13 | @Target(ElementType.METHOD) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface OperationLogger { 16 | /** 17 | * 操作描述 18 | */ 19 | String value() default ""; 20 | } 21 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/annotation/VisitLogger.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.annotation; 2 | 3 | import cn.raxcl.enums.VisitBehavior; 4 | 5 | import java.lang.annotation.ElementType; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.RetentionPolicy; 8 | import java.lang.annotation.Target; 9 | 10 | /** 11 | * 用于需要记录访客访问日志的方法 12 | * @author Raxcl 13 | * @date 2022-01-07 16:59:57 14 | */ 15 | @Target(ElementType.METHOD) 16 | @Retention(RetentionPolicy.RUNTIME) 17 | public @interface VisitLogger { 18 | 19 | /** 20 | * 访问行为枚举 21 | */ 22 | VisitBehavior value() default VisitBehavior.UNKNOWN; 23 | } 24 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/common/CommonService.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.common; 2 | 3 | import cn.raxcl.model.temp.LogDTO; 4 | import cn.raxcl.model.temp.PageDTO; 5 | 6 | /** 7 | * @author c-long.chan 8 | */ 9 | public interface CommonService { 10 | /** 11 | * 抽取出的,保存日志公共方法 12 | * @param ip ip 13 | * @param userAgent userAgent 14 | * @return LogDTO 15 | */ 16 | LogDTO saveLog(String ip, String userAgent); 17 | 18 | /** 19 | * 分页之前的操作 20 | * @param date 分页数据 21 | * @return PageDTO 22 | */ 23 | PageDTO pageBefore(String[] date); 24 | } 25 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/config/MyAuthenticationEntryPoint.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.config; 2 | 3 | import org.springframework.security.core.AuthenticationException; 4 | import org.springframework.security.web.AuthenticationEntryPoint; 5 | import org.springframework.stereotype.Component; 6 | import cn.raxcl.util.common.Result; 7 | import cn.raxcl.util.JacksonUtils; 8 | 9 | import javax.servlet.http.HttpServletRequest; 10 | import javax.servlet.http.HttpServletResponse; 11 | import java.io.IOException; 12 | import java.io.PrintWriter; 13 | 14 | /** 15 | * 未登录 拒绝访问 16 | * @author Raxcl 17 | * @date 2022-01-07 17:47:28 18 | */ 19 | @Component 20 | public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint { 21 | @Override 22 | public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) 23 | throws IOException { 24 | response.setContentType("application/json;charset=utf-8"); 25 | PrintWriter out = response.getWriter(); 26 | Result result = Result.exception(403, "请登录"); 27 | out.write(JacksonUtils.writeValueAsString(result)); 28 | out.flush(); 29 | out.close(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/config/RedisSerializeConfig.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.data.redis.connection.RedisConnectionFactory; 6 | import org.springframework.data.redis.core.RedisTemplate; 7 | import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; 8 | 9 | /** 10 | * Redis序列化配置 11 | * @author Raxcl 12 | * @date 2022-01-07 17:47:54 13 | */ 14 | @Configuration 15 | public class RedisSerializeConfig { 16 | 17 | /** 18 | * 使用JSON序列化方式 19 | * 20 | * @param redisConnectionFactory redisConnectionFactory 21 | * @return RedisTemplate 22 | */ 23 | @Bean 24 | public RedisTemplate jsonRedisTemplate(RedisConnectionFactory redisConnectionFactory) { 25 | RedisTemplate template = new RedisTemplate<>(); 26 | template.setConnectionFactory(redisConnectionFactory); 27 | Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<>(Object.class); 28 | template.setDefaultSerializer(serializer); 29 | return template; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/config/RestTemplateConfig.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.config; 2 | 3 | import cn.raxcl.config.properties.ProxyProperties; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.http.client.SimpleClientHttpRequestFactory; 7 | import org.springframework.web.client.RestTemplate; 8 | 9 | import java.net.InetSocketAddress; 10 | import java.net.Proxy; 11 | 12 | /** 13 | * RestTemplate相关的Bean配置 14 | * 15 | * @author Raxcl 16 | * @date 2022-03-15 23:47:06 17 | */ 18 | @Configuration 19 | public class RestTemplateConfig { 20 | private final ProxyProperties proxyProperties; 21 | 22 | public RestTemplateConfig(ProxyProperties proxyProperties) { 23 | this.proxyProperties = proxyProperties; 24 | } 25 | 26 | /** 27 | * 默认的RestTemplate 28 | * 29 | * @return RestTemplate 30 | */ 31 | @Bean 32 | public RestTemplate restTemplate() { 33 | return new RestTemplate(); 34 | } 35 | 36 | /** 37 | * 配置了代理和超时时间的RestTemplate 38 | * 39 | * @return RestTemplate 40 | */ 41 | @Bean 42 | public RestTemplate restTemplateByProxy() { 43 | SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory(); 44 | Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyProperties.getHost(), proxyProperties.getPort())); 45 | requestFactory.setProxy(proxy); 46 | requestFactory.setConnectTimeout(proxyProperties.getTimeout()); 47 | return new RestTemplate(requestFactory); 48 | } 49 | } -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/config/properties/BlogProperties.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.config.properties; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | import org.springframework.boot.context.properties.ConfigurationProperties; 8 | import org.springframework.context.annotation.Configuration; 9 | 10 | /** 11 | * 博客配置(目前用于评论提醒模板中的超链接) 12 | * 13 | * @author Raxcl 14 | * @date 2022-03-15 23:47:10 15 | */ 16 | @NoArgsConstructor 17 | @Getter 18 | @Setter 19 | @ToString 20 | @Configuration 21 | @ConfigurationProperties(prefix = "blog") 22 | public class BlogProperties { 23 | /** 24 | * 博客名称 25 | */ 26 | private String name; 27 | /** 28 | * 博客后端接口URL 29 | */ 30 | private String api; 31 | /** 32 | * 博客前端后台管理URL 33 | */ 34 | private String cms; 35 | /** 36 | * 博客前端前台页面URL 37 | */ 38 | private String view; 39 | } 40 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/config/properties/GithubProperties.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.config.properties; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | import org.springframework.boot.context.properties.ConfigurationProperties; 8 | import org.springframework.context.annotation.Configuration; 9 | 10 | /** 11 | * GitHub配置(目前用于评论中QQ头像的图床) 12 | * 13 | * @author Raxcl 14 | * @date 2022-03-15 23:47:14 15 | */ 16 | @NoArgsConstructor 17 | @Getter 18 | @Setter 19 | @ToString 20 | @Configuration 21 | @ConfigurationProperties(prefix = "upload.github") 22 | public class GithubProperties { 23 | /** 24 | * GitHub token 25 | */ 26 | private String token; 27 | /** 28 | * GitHub username 29 | */ 30 | private String username; 31 | /** 32 | * GitHub 仓库名 33 | */ 34 | private String repos; 35 | /** 36 | * GitHub 仓库路径 37 | */ 38 | private String reposPath; 39 | } 40 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/config/properties/ProxyProperties.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.config.properties; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | import org.springframework.boot.context.properties.ConfigurationProperties; 8 | import org.springframework.context.annotation.Configuration; 9 | import org.springframework.http.client.SimpleClientHttpRequestFactory; 10 | 11 | /** 12 | * 代理配置(目前用于RestTemplate发送tg消息) 13 | * 14 | * @author Raxcl 15 | * @date 2022-03-15 23:47:17 16 | */ 17 | @NoArgsConstructor 18 | @Getter 19 | @Setter 20 | @ToString 21 | @Configuration 22 | @ConfigurationProperties(prefix = "http.proxy.server") 23 | public class ProxyProperties { 24 | /** 25 | * 代理服务器地址 26 | */ 27 | private String host; 28 | /** 29 | * 代理服务器端口 30 | */ 31 | private Integer port; 32 | /** 33 | * 连接超时(单位毫秒),通常不应该为0,0为无限超时时间,-1为系统的默认超时时间 34 | * 35 | * @see SimpleClientHttpRequestFactory#setConnectTimeout(int) 36 | */ 37 | private Integer timeout; 38 | } 39 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/config/properties/TelegramProperties.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.config.properties; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | import org.springframework.boot.context.properties.ConfigurationProperties; 8 | import org.springframework.context.annotation.Configuration; 9 | 10 | /** 11 | * Telegram配置 12 | * 13 | * @author Raxcl 14 | * @date 2022-03-15 23:46:53 15 | */ 16 | @NoArgsConstructor 17 | @Getter 18 | @Setter 19 | @ToString 20 | @Configuration 21 | @ConfigurationProperties(prefix = "tg.bot") 22 | public class TelegramProperties { 23 | /** 24 | * Telegram bot的api,默认是https://api.telegram.org/bot 25 | * 如果使用自己的反代,可以修改它 26 | */ 27 | private String api; 28 | /** 29 | * bot的token,可以从 @BotFather 处获取 30 | */ 31 | private String token; 32 | /** 33 | * 自己账号和bot的聊天会话id 34 | */ 35 | private String chatId; 36 | /** 37 | * 是否使用代理 38 | */ 39 | private Boolean useProxy; 40 | /** 41 | * 是否使用反向代理 42 | */ 43 | private Boolean useReverseProxy; 44 | /** 45 | * 反向代理URL 46 | */ 47 | private String reverseProxyUrl; 48 | } 49 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/config/properties/TxYunProperties.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.config.properties; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | import org.springframework.boot.context.properties.ConfigurationProperties; 8 | import org.springframework.context.annotation.Configuration; 9 | 10 | /** 11 | * 腾讯云配置(目前用于评论中QQ头像的图床) 12 | * @author dragon 13 | * @date 2022/11/6 12:09 14 | */ 15 | @NoArgsConstructor 16 | @Getter 17 | @Setter 18 | @ToString 19 | @Configuration 20 | @ConfigurationProperties(prefix = "upload.txyun") 21 | public class TxYunProperties { 22 | /** 23 | * id 24 | */ 25 | private String secretId; 26 | /** 27 | * key 28 | */ 29 | private String secretKey; 30 | /** 31 | * 腾讯云存储空间名称 32 | */ 33 | private String bucketName; 34 | /** 35 | * 地域 36 | */ 37 | private String region; 38 | /** 39 | * 存储路径 40 | */ 41 | private String path; 42 | /** 43 | * CDN访问域名 44 | */ 45 | private String domain; 46 | 47 | } 48 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/config/properties/UploadProperties.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.config.properties; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | import org.springframework.boot.context.properties.ConfigurationProperties; 8 | import org.springframework.context.annotation.Configuration; 9 | 10 | /** 11 | * 静态文件上传访问路径配置(目前用于评论中QQ头像的本地存储) 12 | * 13 | * @author Raxcl 14 | * @date 2022-03-15 23:47:01 15 | */ 16 | @NoArgsConstructor 17 | @Getter 18 | @Setter 19 | @ToString 20 | @Configuration 21 | @ConfigurationProperties(prefix = "upload") 22 | public class UploadProperties { 23 | /** 24 | * 本地文件路径 25 | */ 26 | private String path; 27 | /** 28 | * 请求地址映射 29 | */ 30 | private String accessPath; 31 | /** 32 | * 本地文件路径映射 33 | */ 34 | private String resourcesLocations; 35 | } 36 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/constant/CommentConstants.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.constant; 2 | 3 | /** 4 | * 评论相关常量 5 | * 6 | * @author Raxcl 7 | * @date 2022-03-15 23:46:31 8 | */ 9 | public class CommentConstants { 10 | private CommentConstants(){} 11 | /** 12 | * 评论提醒方式-Telegram 13 | */ 14 | public static final String TELEGRAM = "tg"; 15 | 16 | /** 17 | * 评论提醒方式-邮件 18 | */ 19 | public static final String MAIL = "mail"; 20 | } 21 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/constant/JwtConstants.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.constant; 2 | 3 | /** 4 | * jwt常量 5 | * 6 | * @author Raxcl 7 | * @date 2022/3/15 16:11 8 | */ 9 | public class JwtConstants { 10 | private JwtConstants(){} 11 | /** 12 | * 博主token前缀 13 | */ 14 | public static final String ADMIN_PREFIX = "admin:"; 15 | 16 | public static final Integer SUCCESS = 200; 17 | 18 | /** 19 | * 1000 * 60 * 60 * 24 * 3 三天 20 | */ 21 | public static final long EXPIRE_TIME = 259200000; 22 | /** 23 | * 部署上线务必修改此配置,否则无法保证token安全性(加密盐) 24 | */ 25 | public static final String SECRET_KEY = "3015b8ea-9ceb-4fa9-89ae-8c713ef1130e"; 26 | } 27 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/constant/PageConstants.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.constant; 2 | 3 | /** 4 | * 页面相关常量 5 | * 6 | * @author Raxcl 7 | * @date 2022/3/15 15:43 8 | */ 9 | public class PageConstants { 10 | private PageConstants() {} 11 | /** 12 | * 普通博客文章页面 13 | */ 14 | public static final int BLOG = 0; 15 | /** 16 | * 关于我页面 17 | */ 18 | public static final int ABOUT = 1; 19 | /** 20 | * 友链页面 21 | */ 22 | public static final int FRIEND = 2; 23 | } 24 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/constant/SiteSettingConstants.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.constant; 2 | 3 | /** 4 | * 站点设置常量 5 | * 6 | * @author Raxcl 7 | * @date 2022-03-16 17:12:30 8 | */ 9 | public class SiteSettingConstants { 10 | private SiteSettingConstants(){} 11 | 12 | public static final String COPYRIGHT = "copyright"; 13 | public static final String AVATAR = "avatar"; 14 | public static final String NAME = "name"; 15 | public static final String GITHUB = "github"; 16 | public static final String QQ = "qq"; 17 | public static final String BILI_BILI = "bilibili"; 18 | public static final String NET_EASE = "netease"; 19 | public static final String EMAIL = "email"; 20 | public static final String FAVORITE = "favorite"; 21 | public static final String ROLL_TEXT = "rollText"; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/constant/UploadConstants.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.constant; 2 | 3 | /** 4 | * 上传文件相关常量 5 | * 6 | * @author raxcl 7 | * @date 2022-03-15 18:36:15 8 | */ 9 | public class UploadConstants { 10 | private UploadConstants() {} 11 | /** 12 | * 评论中QQ头像存储方式-本地 13 | */ 14 | public static final String LOCAL = "local"; 15 | /** 16 | * 评论中QQ头像存储方式-GitHub 17 | */ 18 | public static final String GITHUB = "github"; 19 | /** 20 | * 评论中QQ头像存储方式-腾讯云 21 | */ 22 | public static final String TXYUN = "txyun"; 23 | /** 24 | * 图片ContentType 25 | */ 26 | public static final String IMAGE = "image"; 27 | } 28 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/controller/admin/AboutAdminController.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.controller.admin; 2 | 3 | import org.springframework.web.bind.annotation.GetMapping; 4 | import org.springframework.web.bind.annotation.PutMapping; 5 | import org.springframework.web.bind.annotation.RequestBody; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | import org.springframework.web.bind.annotation.RestController; 8 | import cn.raxcl.annotation.OperationLogger; 9 | import cn.raxcl.util.common.Result; 10 | import cn.raxcl.service.AboutService; 11 | 12 | import java.util.Map; 13 | 14 | /** 15 | * 关于我页面后台管理 16 | * @author Raxcl 17 | * @date 2022-01-07 08:51:09 18 | */ 19 | @RestController 20 | @RequestMapping("/admin") 21 | public class AboutAdminController { 22 | private final AboutService aboutService; 23 | 24 | public AboutAdminController(AboutService aboutService) { 25 | this.aboutService = aboutService; 26 | } 27 | 28 | /** 29 | * 获取关于我页面配置 30 | * 31 | * @return Result 32 | */ 33 | @GetMapping("/about") 34 | public Result about() { 35 | return Result.success("请求成功", aboutService.getAboutSetting()); 36 | } 37 | 38 | /** 39 | * 修改关于我页面 40 | * 41 | * @param map map 42 | * @return Result 43 | */ 44 | @OperationLogger("修改关于我页面") 45 | @PutMapping("/about") 46 | public Result updateAbout(@RequestBody Map map) { 47 | aboutService.updateAbout(map); 48 | return Result.success("修改成功"); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/controller/view/AboutController.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.controller.view; 2 | 3 | import cn.raxcl.enums.VisitBehavior; 4 | import org.springframework.web.bind.annotation.GetMapping; 5 | import org.springframework.web.bind.annotation.RestController; 6 | import cn.raxcl.annotation.VisitLogger; 7 | import cn.raxcl.util.common.Result; 8 | import cn.raxcl.service.AboutService; 9 | 10 | /** 11 | * 关于我页面 12 | * @author Raxcl 13 | * @date 2022-01-07 10:15:25 14 | */ 15 | @RestController 16 | public class AboutController { 17 | private final AboutService aboutService; 18 | 19 | public AboutController(AboutService aboutService) { 20 | this.aboutService = aboutService; 21 | } 22 | 23 | /** 24 | * 获取关于我页面信息 25 | * 26 | * @return Result 27 | */ 28 | @VisitLogger(VisitBehavior.ABOUT) 29 | @GetMapping("/about") 30 | public Result about() { 31 | return Result.success("获取成功", aboutService.getAboutInfo()); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/controller/view/ArchiveController.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.controller.view; 2 | 3 | import cn.raxcl.enums.VisitBehavior; 4 | import org.springframework.web.bind.annotation.GetMapping; 5 | import org.springframework.web.bind.annotation.RestController; 6 | import cn.raxcl.annotation.VisitLogger; 7 | import cn.raxcl.util.common.Result; 8 | import cn.raxcl.service.BlogService; 9 | 10 | import java.util.Map; 11 | 12 | /** 13 | * 归档页面 14 | * @author Raxcl 15 | * @date 2022-01-07 10:15:29 16 | */ 17 | @RestController 18 | public class ArchiveController { 19 | private final BlogService blogService; 20 | 21 | public ArchiveController(BlogService blogService) { 22 | this.blogService = blogService; 23 | } 24 | 25 | /** 26 | * 按年月分组归档公开博客 统计公开博客总数 27 | * 28 | * @return Result 29 | */ 30 | @VisitLogger(VisitBehavior.ARCHIVE) 31 | @GetMapping("/archives") 32 | public Result archives() { 33 | Map archiveBlogMap = blogService.getArchiveBlogAndCountByIsPublished(); 34 | return Result.success("请求成功", archiveBlogMap); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/controller/view/CategoryController.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.controller.view; 2 | 3 | import cn.raxcl.enums.VisitBehavior; 4 | import org.springframework.web.bind.annotation.GetMapping; 5 | import org.springframework.web.bind.annotation.RequestParam; 6 | import org.springframework.web.bind.annotation.RestController; 7 | import cn.raxcl.annotation.VisitLogger; 8 | import cn.raxcl.model.vo.BlogInfoVO; 9 | import cn.raxcl.model.vo.PageResultVO; 10 | import cn.raxcl.util.common.Result; 11 | import cn.raxcl.service.BlogService; 12 | 13 | /** 14 | * 分类 15 | * @author Raxcl 16 | * @date 2022-01-07 09:11:40 17 | */ 18 | @RestController 19 | public class CategoryController { 20 | private final BlogService blogService; 21 | 22 | public CategoryController(BlogService blogService) { 23 | this.blogService = blogService; 24 | } 25 | 26 | /** 27 | * 根据分类name分页查询公开博客列表 28 | * 29 | * @param categoryName 分类name 30 | * @param pageNum 页码 31 | * @return Result 32 | */ 33 | @VisitLogger(VisitBehavior.CATEGORY) 34 | @GetMapping("/category") 35 | public Result category(@RequestParam String categoryName, 36 | @RequestParam(defaultValue = "1") Integer pageNum) { 37 | PageResultVO pageResultVO = blogService.getBlogInfoListByCategoryNameAndIsPublished(categoryName, pageNum); 38 | return Result.success("请求成功", pageResultVO); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/controller/view/TagController.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.controller.view; 2 | 3 | import cn.raxcl.enums.VisitBehavior; 4 | import org.springframework.web.bind.annotation.GetMapping; 5 | import org.springframework.web.bind.annotation.RequestParam; 6 | import org.springframework.web.bind.annotation.RestController; 7 | import cn.raxcl.annotation.VisitLogger; 8 | import cn.raxcl.model.vo.BlogInfoVO; 9 | import cn.raxcl.model.vo.PageResultVO; 10 | import cn.raxcl.util.common.Result; 11 | import cn.raxcl.service.BlogService; 12 | 13 | /** 14 | * 标签 15 | * @author Raxcl 16 | * @date 2022-01-07 15:43:11 17 | */ 18 | @RestController 19 | public class TagController { 20 | private final BlogService blogService; 21 | 22 | public TagController(BlogService blogService) { 23 | this.blogService = blogService; 24 | } 25 | 26 | /** 27 | * 根据标签name分页查询公开博客列表 28 | * 29 | * @param tagName 标签name 30 | * @param pageNum 页码 31 | * @return Result 32 | */ 33 | @VisitLogger(VisitBehavior.TAG) 34 | @GetMapping("/tag") 35 | public Result tag(@RequestParam String tagName, 36 | @RequestParam(defaultValue = "1") Integer pageNum) { 37 | PageResultVO pageResultVO = blogService.getBlogInfoListByTagNameAndIsPublished(tagName, pageNum); 38 | return Result.success("请求成功", pageResultVO); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/entity/About.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.entity; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | 8 | /** 9 | * 关于我 10 | * @author Raxcl 11 | * @date 2022-01-07 09:52:33 12 | */ 13 | @NoArgsConstructor 14 | @Getter 15 | @Setter 16 | @ToString 17 | public class About { 18 | private Long id; 19 | private String nameEn; 20 | private String nameZh; 21 | private String value; 22 | } 23 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/entity/Category.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.entity; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | /** 12 | * 博客分类 13 | * @author Raxcl 14 | * @date 2022-01-07 09:55:09 15 | */ 16 | @NoArgsConstructor 17 | @Getter 18 | @Setter 19 | @ToString 20 | public class Category { 21 | private Long id; 22 | /** 23 | * 分类名称 24 | */ 25 | private String name; 26 | /** 27 | * 该分类下的博客文章 28 | */ 29 | private List blogs = new ArrayList<>(); 30 | } 31 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/entity/CityVisitor.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.entity; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | import lombok.ToString; 8 | 9 | /** 10 | * 城市访客数量 11 | * @author Raxcl 12 | * @date 2022-01-07 09:55:12 13 | */ 14 | @AllArgsConstructor 15 | @NoArgsConstructor 16 | @Getter 17 | @Setter 18 | @ToString 19 | public class CityVisitor { 20 | /** 21 | * 城市名称 22 | */ 23 | private String city; 24 | /** 25 | * 独立访客数量 26 | */ 27 | private Integer uv; 28 | } 29 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/entity/ExceptionLog.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.entity; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | 8 | import java.util.Date; 9 | 10 | /** 11 | * 异常日志 12 | * @author Raxcl 13 | * @date 2022-01-07 09:55:41 14 | */ 15 | @NoArgsConstructor 16 | @Getter 17 | @Setter 18 | @ToString 19 | public class ExceptionLog { 20 | private Long id; 21 | /** 22 | * 请求接口 23 | */ 24 | private String uri; 25 | /** 26 | * 请求方式 27 | */ 28 | private String method; 29 | /** 30 | * 请求参数 31 | */ 32 | private String param; 33 | /** 34 | * 操作描述 35 | */ 36 | private String description; 37 | /** 38 | * 异常信息 39 | */ 40 | private String error; 41 | /** 42 | * ip 43 | */ 44 | private String ip; 45 | /** 46 | * ip来源 47 | */ 48 | private String ipSource; 49 | /** 50 | * 操作系统 51 | */ 52 | private String os; 53 | /** 54 | * 浏览器 55 | */ 56 | private String browser; 57 | /** 58 | * 操作时间 59 | */ 60 | private Date createTime; 61 | 62 | private String userAgent; 63 | 64 | public ExceptionLog(String uri, String method, String description, String error, String ip, String userAgent) { 65 | this.uri = uri; 66 | this.method = method; 67 | this.description = description; 68 | this.error = error; 69 | this.ip = ip; 70 | this.createTime = new Date(); 71 | this.userAgent = userAgent; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/entity/Friend.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.entity; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | 8 | import java.util.Date; 9 | 10 | /** 11 | * 友链 12 | * @author Raxcl 13 | * @date 2022-01-07 09:56:51 14 | */ 15 | @NoArgsConstructor 16 | @Getter 17 | @Setter 18 | @ToString 19 | public class Friend { 20 | private Long id; 21 | /** 22 | * 昵称 23 | */ 24 | private String nickname; 25 | /** 26 | * 描述 27 | */ 28 | private String description; 29 | /** 30 | * 站点 31 | */ 32 | private String website; 33 | /** 34 | * 头像 35 | */ 36 | private String avatar; 37 | /** 38 | * 公开或隐藏 39 | */ 40 | private Boolean published; 41 | /** 42 | * 浏览次数 43 | */ 44 | private Integer views; 45 | /** 46 | * 创建时间 47 | */ 48 | private Date createTime; 49 | } 50 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/entity/LoginLog.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.entity; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | 8 | import java.util.Date; 9 | 10 | /** 11 | * 登录日志 12 | * @author Raxcl 13 | * @date 2022-01-07 18:04:08 14 | */ 15 | @NoArgsConstructor 16 | @Getter 17 | @Setter 18 | @ToString 19 | public class LoginLog { 20 | private Long id; 21 | 22 | /** 23 | * 用户名称 24 | */ 25 | private String username; 26 | /** 27 | * ip 28 | */ 29 | private String ip; 30 | /** 31 | * ip来源 32 | */ 33 | private String ipSource; 34 | /** 35 | * 操作系统 36 | */ 37 | private String os; 38 | /** 39 | * 浏览器 40 | */ 41 | private String browser; 42 | /** 43 | * 登录状态 44 | */ 45 | private Boolean status; 46 | /** 47 | * 操作信息 48 | */ 49 | private String description; 50 | /** 51 | * 操作时间 52 | */ 53 | private Date createTime; 54 | private String userAgent; 55 | 56 | public LoginLog(String username, String ip, boolean status, String description, String userAgent) { 57 | this.username = username; 58 | this.ip = ip; 59 | this.status = status; 60 | this.description = description; 61 | this.createTime = new Date(); 62 | this.userAgent = userAgent; 63 | } 64 | } -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/entity/Moment.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.entity; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | 8 | import java.util.Date; 9 | 10 | /** 11 | * 博客动态 12 | * @author Raxcl 13 | * @date 2022-01-07 09:57:48 14 | */ 15 | @NoArgsConstructor 16 | @Getter 17 | @Setter 18 | @ToString 19 | public class Moment { 20 | private Long id; 21 | /** 22 | * 动态内容 23 | */ 24 | private String content; 25 | /** 26 | * 创建时间 27 | */ 28 | private Date createTime; 29 | /** 30 | * 点赞数量 31 | */ 32 | private Integer likes; 33 | /** 34 | * 是否公开 35 | */ 36 | private Boolean published; 37 | } 38 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/entity/ScheduleJob.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.entity; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | 8 | import java.util.Date; 9 | 10 | /** 11 | * 定时任务 12 | * @author Raxcl 13 | * @date 2022-01-07 10:00:10 14 | */ 15 | @NoArgsConstructor 16 | @Getter 17 | @Setter 18 | @ToString 19 | public class ScheduleJob { 20 | /** 21 | * 任务调度参数key 22 | */ 23 | public static final String JOB_PARAM_KEY = "JOB_PARAM_KEY"; 24 | /** 25 | * 任务id 26 | */ 27 | private Long jobId; 28 | /** 29 | * spring bean名称 30 | */ 31 | private String beanName; 32 | /** 33 | * 方法名 34 | */ 35 | private String methodName; 36 | /** 37 | * 参数 38 | */ 39 | private String params; 40 | /** 41 | * cron表达式 42 | */ 43 | private String cron; 44 | /** 45 | * 任务状态 46 | */ 47 | private Boolean status; 48 | /** 49 | * 备注 50 | */ 51 | private String remark; 52 | /** 53 | * 创建时间 54 | */ 55 | private Date createTime; 56 | } 57 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/entity/ScheduleJobLog.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.entity; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | 8 | import java.util.Date; 9 | 10 | /** 11 | * 定时任务日志 12 | * @author Raxcl 13 | * @date 2022-01-07 10:02:34 14 | */ 15 | @NoArgsConstructor 16 | @Getter 17 | @Setter 18 | @ToString 19 | public class ScheduleJobLog { 20 | /** 21 | * 日志id 22 | */ 23 | private Long logId; 24 | /** 25 | * 任务id 26 | */ 27 | private Long jobId; 28 | /** 29 | * spring bean名称 30 | */ 31 | private String beanName; 32 | /** 33 | * 方法名 34 | */ 35 | private String methodName; 36 | /** 37 | * 参数 38 | */ 39 | private String params; 40 | /** 41 | * 任务执行结果 42 | */ 43 | private Boolean status; 44 | /** 45 | * 异常信息 46 | */ 47 | private String error; 48 | /** 49 | * 耗时(单位:毫秒) 50 | */ 51 | private Integer times; 52 | /** 53 | * 创建时间 54 | */ 55 | private Date createTime; 56 | } 57 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/entity/SiteSetting.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.entity; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | 8 | /** 9 | * 站点设置 10 | * @author Raxcl 11 | * @date 2022-01-07 10:04:17 12 | */ 13 | @NoArgsConstructor 14 | @Getter 15 | @Setter 16 | @ToString 17 | public class SiteSetting { 18 | private Long id; 19 | private String nameEn; 20 | private String nameZh; 21 | private String value; 22 | private Integer type; 23 | } 24 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/entity/Tag.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.entity; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | /** 12 | * 博客标签 13 | * @author Raxcl 14 | * @date 2022-01-06 20:17:48 15 | */ 16 | @NoArgsConstructor 17 | @Getter 18 | @Setter 19 | @ToString 20 | public class Tag { 21 | private Long id; 22 | /** 23 | * 标签名称 24 | */ 25 | private String name; 26 | /** 27 | * 标签颜色(与Semantic UI提供的颜色对应,可选) 28 | */ 29 | private String color; 30 | /** 31 | * 该标签下的博客文章 32 | */ 33 | private List blogs = new ArrayList<>(); 34 | } 35 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/entity/VisitRecord.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.entity; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | 8 | /** 9 | * 访问记录 10 | * @author Raxcl 11 | * @date 2022-01-07 10:13:21 12 | */ 13 | @NoArgsConstructor 14 | @Getter 15 | @Setter 16 | @ToString 17 | public class VisitRecord { 18 | private Long id; 19 | /** 20 | * 访问量 21 | */ 22 | private Integer pv; 23 | /** 24 | * 独立用户 25 | */ 26 | private Integer uv; 27 | /** 28 | * 日期"02-23" 29 | */ 30 | private String date; 31 | 32 | public VisitRecord(Integer pv, Integer uv, String date) { 33 | this.pv = pv; 34 | this.uv = uv; 35 | this.date = date; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/entity/Visitor.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.entity; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | 8 | import java.util.Date; 9 | 10 | /** 11 | * 访客记录 12 | * @author Raxcl 13 | * @date 2022-01-07 10:11:52 14 | */ 15 | @NoArgsConstructor 16 | @Getter 17 | @Setter 18 | @ToString 19 | public class Visitor { 20 | private Long id; 21 | /** 22 | * 访客标识码 23 | */ 24 | private String uuid; 25 | /** 26 | * ip 27 | */ 28 | private String ip; 29 | /** 30 | * ip来源 31 | */ 32 | private String ipSource; 33 | /** 34 | * 操作系统 35 | */ 36 | private String os; 37 | /** 38 | * 浏览器 39 | */ 40 | private String browser; 41 | /** 42 | * 首次访问时间 43 | */ 44 | private Date createTime; 45 | /** 46 | * 最后访问时间 47 | */ 48 | private Date lastTime; 49 | /** 50 | * 访问页数统计 51 | */ 52 | private Integer pv; 53 | private String userAgent; 54 | 55 | public Visitor(String uuid, String ip, String userAgent) { 56 | this.uuid = uuid; 57 | this.ip = ip; 58 | Date date = new Date(); 59 | this.createTime = date; 60 | this.lastTime = date; 61 | this.pv = 0; 62 | this.userAgent = userAgent; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/enums/CommentOpenStateEnum.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.enums; 2 | 3 | /** 4 | * 评论开放状态枚举类 5 | * @author Raxcl 6 | * @date 2022-03-15 14:47:06 7 | */ 8 | public enum CommentOpenStateEnum { 9 | /** 10 | * 博客状态不存在,或博客未公开 11 | */ 12 | NOT_FOUND, 13 | /** 14 | * 评论正常开放 15 | */ 16 | OPEN, 17 | /** 18 | * 评论已关闭 19 | */ 20 | CLOSE, 21 | /** 22 | * 评论所在页面需要密码 23 | */ 24 | PASSWORD, 25 | } 26 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/enums/CommentPageEnum.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.enums; 2 | 3 | /** 4 | * 评论页面枚举类 5 | * 6 | * @author Raxcl 7 | * @date 2022-03-15 23:47:24 8 | */ 9 | public enum CommentPageEnum { 10 | /** 11 | * 未知 12 | */ 13 | UNKNOWN("UNKNOWN", "UNKNOWN"), 14 | /** 15 | * 博客页面 16 | */ 17 | BLOG("", ""), 18 | /** 19 | * 关于我页面 20 | */ 21 | ABOUT("关于我", "/about"), 22 | /** 23 | * 友人帐页面 24 | */ 25 | FRIEND("友人帐", "/friends"), 26 | ; 27 | 28 | private String title; 29 | private String path; 30 | 31 | CommentPageEnum(String title, String path) { 32 | this.title = title; 33 | this.path = path; 34 | } 35 | 36 | public String getTitle() { 37 | return title; 38 | } 39 | //todo 40 | public void setTitle(String title) { 41 | this.title = title; 42 | } 43 | 44 | public String getPath() { 45 | return path; 46 | } 47 | 48 | public void setPath(String path) { 49 | this.path = path; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/enums/VisitBehavior.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.enums; 2 | 3 | /** 4 | * 访问行为枚举类 5 | * 6 | * @author Raxcl 7 | * @date: 2022-03-16 17:43:26 8 | */ 9 | public enum VisitBehavior { 10 | /** 11 | * UNKNOWN 12 | */ 13 | UNKNOWN("UNKNOWN", "UNKNOWN"), 14 | 15 | INDEX("访问页面", "首页"), 16 | ARCHIVE("访问页面", "归档"), 17 | MOMENT("访问页面", "动态"), 18 | FRIEND("访问页面", "友链"), 19 | ABOUT("访问页面", "关于我"), 20 | 21 | BLOG("查看博客", ""), 22 | CATEGORY("查看分类", ""), 23 | TAG("查看标签", ""), 24 | SEARCH("搜索博客", ""), 25 | CLICK_FRIEND("点击友链", ""), 26 | LIKE_MOMENT("点赞动态", ""), 27 | CHECK_PASSWORD("校验博客密码", ""), 28 | ; 29 | 30 | /** 31 | * 访问行为 32 | */ 33 | private final String behavior; 34 | /** 35 | * 访问内容 36 | */ 37 | private final String content; 38 | 39 | VisitBehavior(String behavior, String content) { 40 | this.behavior = behavior; 41 | this.content = content; 42 | } 43 | 44 | public String getBehavior() { 45 | return behavior; 46 | } 47 | 48 | public String getContent() { 49 | return content; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/exception/BadRequestException.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.exception; 2 | 3 | /** 4 | * 非法请求异常 5 | * @author Raxcl 6 | * @date 2022-01-07 18:34:51 7 | */ 8 | 9 | public class BadRequestException extends RuntimeException { 10 | 11 | public BadRequestException(String message) { 12 | super(message); 13 | } 14 | 15 | 16 | 17 | 18 | } 19 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/exception/NotFoundException.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.exception; 2 | 3 | /** 4 | * 404异常 5 | * @author Raxcl 6 | * @date 2022-01-07 18:36:01 7 | */ 8 | 9 | public class NotFoundException extends RuntimeException { 10 | 11 | public NotFoundException(String message) { 12 | super(message); 13 | } 14 | 15 | public NotFoundException(String message, Throwable cause) { 16 | super(message, cause); 17 | } 18 | 19 | 20 | } 21 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/exception/PersistenceException.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.exception; 2 | 3 | /** 4 | * 持久化异常 5 | * @author Raxcl 6 | * @date 2022-01-07 18:35:55 7 | */ 8 | 9 | public class PersistenceException extends RuntimeException { 10 | 11 | public PersistenceException(String message) { 12 | super(message); 13 | } 14 | 15 | public PersistenceException(String message, Throwable cause) { 16 | super(message, cause); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/mapper/AboutMapper.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.mapper; 2 | 3 | import org.apache.ibatis.annotations.Mapper; 4 | import org.springframework.stereotype.Repository; 5 | import cn.raxcl.entity.About; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * 关于我持久层接口 11 | * @author Raxcl 12 | * @date 2022-01-07 08:58:08 13 | */ 14 | @Mapper 15 | @Repository 16 | public interface AboutMapper { 17 | /** 18 | * 获取关于我list 19 | * @return List 20 | */ 21 | List getList(); 22 | 23 | /** 24 | * 更新关于我页面 25 | * @param nameEn nameEn 26 | * @param value value 27 | * @return int 28 | */ 29 | int updateAbout(String nameEn, String value); 30 | 31 | /** 32 | * 判断评论是否已关闭 33 | * @return String 34 | */ 35 | String getAboutCommentEnabled(); 36 | } 37 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/mapper/CategoryMapper.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.mapper; 2 | 3 | import org.apache.ibatis.annotations.Mapper; 4 | import org.springframework.stereotype.Repository; 5 | import cn.raxcl.entity.Category; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * 博客分类持久层接口 11 | * @author Raxcl 12 | * @date 2022-01-07 20:02:47 13 | */ 14 | @Mapper 15 | @Repository 16 | public interface CategoryMapper { 17 | /** 18 | * 获取博客分类列表 19 | * @return List 20 | */ 21 | List getCategoryList(); 22 | 23 | /** 24 | * 获取分类名list 25 | * @return List 26 | */ 27 | List getCategoryNameList(); 28 | 29 | /** 30 | * 保存分类 31 | * @param category category 32 | * @return int 33 | */ 34 | int saveCategory(Category category); 35 | 36 | /** 37 | * 根据id获取分类信息 38 | * @param id id 39 | * @return Category 40 | */ 41 | Category getCategoryById(Long id); 42 | 43 | /** 44 | * 根据名称获取分类信息 45 | * @param name name 46 | * @return Category 47 | */ 48 | Category getCategoryByName(String name); 49 | 50 | /** 51 | * 根据id删除分类信息 52 | * @param id id 53 | * @return int 54 | */ 55 | int deleteCategoryById(Long id); 56 | 57 | /** 58 | * 更新分类信息 59 | * @param category category 60 | * @return int 61 | */ 62 | int updateCategory(Category category); 63 | } 64 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/mapper/CityVisitorMapper.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.mapper; 2 | 3 | import org.apache.ibatis.annotations.Mapper; 4 | import org.springframework.stereotype.Repository; 5 | import cn.raxcl.entity.CityVisitor; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * 城市访客数量统计持久层接口 11 | * @author Raxcl 12 | * @date 2022-01-07 15:55:29 13 | */ 14 | @Mapper 15 | @Repository 16 | public interface CityVisitorMapper { 17 | /** 18 | * 查询城市访客数 19 | * @return List 20 | */ 21 | List getCityVisitorList(); 22 | 23 | /** 24 | * 添加访问记录 25 | * @param cityVisitor cityVisitor 26 | * @return int 27 | */ 28 | int saveCityVisitor(CityVisitor cityVisitor); 29 | } 30 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/mapper/ExceptionLogMapper.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.mapper; 2 | 3 | import org.apache.ibatis.annotations.Mapper; 4 | import org.springframework.stereotype.Repository; 5 | import cn.raxcl.entity.ExceptionLog; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * 异常日志持久层接口 11 | * @author Raxcl 12 | * @date 2022-01-07 15:58:13 13 | */ 14 | @Mapper 15 | @Repository 16 | public interface ExceptionLogMapper { 17 | /** 18 | * 查询日志 19 | * @param startDate startDate 20 | * @param endDate endDate 21 | * @return List 22 | */ 23 | List getExceptionLogListByDate(String startDate, String endDate); 24 | 25 | /** 26 | * 添加日志 27 | * @param log log 28 | * @return int 29 | */ 30 | int saveExceptionLog(ExceptionLog log); 31 | 32 | /** 33 | * 删除日志 34 | * @param id id 35 | * @return int 36 | */ 37 | int deleteExceptionLogById(Long id); 38 | } 39 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/mapper/FriendMapper.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.mapper; 2 | 3 | import cn.raxcl.model.dto.FriendDTO; 4 | import cn.raxcl.model.vo.FriendVO; 5 | import org.apache.ibatis.annotations.Mapper; 6 | import org.springframework.stereotype.Repository; 7 | import cn.raxcl.entity.Friend; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * 友链持久层接口 13 | * @author Raxcl 14 | * @date 2022-01-07 10:23:39 15 | */ 16 | @Mapper 17 | @Repository 18 | public interface FriendMapper { 19 | /** 20 | * 获取友链list 21 | * @return List 22 | */ 23 | List getFriendList(); 24 | 25 | /** 26 | * 获取友链vo列表 27 | * @return List 28 | */ 29 | List getFriendVOList(); 30 | 31 | /** 32 | * 更新可发版友链 33 | * @param id id 34 | * @param published published 35 | * @return int 36 | */ 37 | int updateFriendPublishedById(Long id, Boolean published); 38 | 39 | /** 40 | * 保存友链信息 41 | * @param friend friend 42 | * @return int 43 | */ 44 | int saveFriend(Friend friend); 45 | 46 | /** 47 | * 更新友链信息 48 | * @param friendDTO friendDTO 49 | * @return int 50 | */ 51 | int updateFriend(FriendDTO friendDTO); 52 | 53 | /** 54 | * 删除友链信息 55 | * @param id id 56 | * @return int 57 | */ 58 | int deleteFriend(Long id); 59 | 60 | /** 61 | * 按昵称增加友链浏览次数 62 | * @param nickname nickname 63 | * @return int 64 | */ 65 | int updateViewsByNickname(String nickname); 66 | } 67 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/mapper/LoginLogMapper.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.mapper; 2 | 3 | import org.apache.ibatis.annotations.Mapper; 4 | import org.springframework.stereotype.Repository; 5 | import cn.raxcl.entity.LoginLog; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * 登录日志持久层接口 11 | * @author Raxcl 12 | * @date 2022-01-07 20:02:39 13 | */ 14 | @Mapper 15 | @Repository 16 | public interface LoginLogMapper { 17 | /** 18 | * 查询日志 19 | * @param startDate 开始时间 20 | * @param endDate 结束时间 21 | * @return List 22 | */ 23 | List getLoginLogListByDate(String startDate, String endDate); 24 | 25 | /** 26 | * 保存登录日志 27 | * @param log log 28 | * @return int 29 | */ 30 | int saveLoginLog(LoginLog log); 31 | 32 | /** 33 | * 根据id删除登录日志 34 | * @param id id 35 | * @return int 36 | */ 37 | int deleteLoginLogById(Long id); 38 | } 39 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/mapper/MomentMapper.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.mapper; 2 | 3 | import org.apache.ibatis.annotations.Mapper; 4 | import org.springframework.stereotype.Repository; 5 | import cn.raxcl.entity.Moment; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * 博客动态持久层接口 11 | * @author Raxcl 12 | * @date 2022-01-07 13:08:50 13 | */ 14 | @Mapper 15 | @Repository 16 | public interface MomentMapper { 17 | /** 18 | * 查询动态List 19 | * @return List 20 | */ 21 | List getMomentList(); 22 | 23 | /** 24 | * 给动态点赞 25 | * @param momentId momentId 26 | * @return int 27 | */ 28 | int addLikeByMomentId(Long momentId); 29 | 30 | /** 31 | * 更新动态公开状态 32 | * @param momentId 动态id 33 | * @param published 是否公开 34 | * @return int 35 | */ 36 | int updateMomentPublishedById(Long momentId, Boolean published); 37 | 38 | /** 39 | * 根据id查询动态 40 | * @param id 动态id 41 | * @return Moment 42 | */ 43 | Moment getMomentById(Long id); 44 | 45 | /** 46 | * 删除动态 47 | * @param id 动态id 48 | * @return int 49 | */ 50 | int deleteMomentById(Long id); 51 | 52 | /** 53 | * 发布动态 54 | * @param moment 动态实体 55 | * @return int 56 | */ 57 | int saveMoment(Moment moment); 58 | 59 | /** 60 | * 更新动态 61 | * @param moment 动态实体 62 | * @return int 63 | */ 64 | int updateMoment(Moment moment); 65 | } 66 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/mapper/OperationLogMapper.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.mapper; 2 | 3 | import org.apache.ibatis.annotations.Mapper; 4 | import org.springframework.stereotype.Repository; 5 | import cn.raxcl.entity.OperationLog; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * 操作日志持久层接口 11 | * @author Raxcl 12 | * @date 2022-01-07 14:54:41 13 | */ 14 | @Mapper 15 | @Repository 16 | public interface OperationLogMapper { 17 | /** 18 | * 查询日志 19 | * @param startDate startDate 20 | * @param endDate endDate 21 | * @return List 22 | */ 23 | List getOperationLogListByDate(String startDate, String endDate); 24 | 25 | /** 26 | * 添加日志 27 | * @param log log 28 | * @return int 29 | */ 30 | int saveOperationLog(OperationLog log); 31 | 32 | /** 33 | * 删除日志 34 | * @param id id 35 | * @return int 36 | */ 37 | int deleteOperationLogById(Long id); 38 | } 39 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/mapper/ScheduleJobLogMapper.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.mapper; 2 | 3 | import org.apache.ibatis.annotations.Mapper; 4 | import org.springframework.stereotype.Repository; 5 | import cn.raxcl.entity.ScheduleJobLog; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * 定时任务日志持久层接口 11 | * @author Raxcl 12 | * @date 2022-01-07 15:11:09 13 | */ 14 | @Mapper 15 | @Repository 16 | public interface ScheduleJobLogMapper { 17 | /** 18 | * 分页查询定时任务日志列表 19 | * @param startDate startDate 20 | * @param endDate endDate 21 | * @return List 22 | */ 23 | List getJobLogListByDate(String startDate, String endDate); 24 | 25 | /** 26 | * 保存任务日志 27 | * @param jobLog jobLog 28 | * @return int 29 | */ 30 | int saveJobLog(ScheduleJobLog jobLog); 31 | 32 | /** 33 | * 按id删除任务日志 34 | * @param logId logId 35 | * @return int 36 | */ 37 | int deleteJobLogByLogId(Long logId); 38 | } 39 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/mapper/ScheduleJobMapper.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.mapper; 2 | 3 | import org.apache.ibatis.annotations.Mapper; 4 | import org.springframework.stereotype.Repository; 5 | import cn.raxcl.entity.ScheduleJob; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * 定时任务持久层接口 11 | * @author Raxcl 12 | * @date 2022-01-07 19:58:21 13 | */ 14 | @Mapper 15 | @Repository 16 | public interface ScheduleJobMapper { 17 | /** 18 | * List 19 | * @return List 20 | */ 21 | List getJobList(); 22 | 23 | /** 24 | * 获取调度信息 25 | * @param jobId jobId 26 | * @return ScheduleJob 27 | */ 28 | ScheduleJob getJobById(Long jobId); 29 | 30 | /** 31 | * scheduleJob 32 | * @param scheduleJob scheduleJob 33 | * @return int 34 | */ 35 | int saveJob(ScheduleJob scheduleJob); 36 | 37 | /** 38 | * scheduleJob 39 | * @param scheduleJob scheduleJob 40 | * @return int 41 | */ 42 | int updateJob(ScheduleJob scheduleJob); 43 | 44 | /** 45 | * 删除定时任务 46 | * @param jobId 任务id 47 | * @return int 48 | */ 49 | int deleteJobById(Long jobId); 50 | 51 | /** 52 | * 更新任务状态:暂停或恢复 53 | * @param jobId 任务id 54 | * @param status 状态 55 | * @return int 56 | */ 57 | int updateJobStatusById(Long jobId, Boolean status); 58 | } 59 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/mapper/SiteSettingMapper.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.mapper; 2 | 3 | import org.apache.ibatis.annotations.Mapper; 4 | import org.springframework.stereotype.Repository; 5 | import cn.raxcl.entity.SiteSetting; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * 站点设置持久层接口 11 | * @author Raxcl 12 | * @date 2022-01-07 10:30:19 13 | */ 14 | @Mapper 15 | @Repository 16 | public interface SiteSettingMapper { 17 | /** 18 | * 获取所有站点配置信息 19 | * @return List 20 | */ 21 | List getList(); 22 | 23 | /** 24 | * 查询友链页面信息 25 | * @return List 26 | */ 27 | List getFriendInfo(); 28 | 29 | /** 30 | * 查询网页标题后缀 31 | * @return String 32 | */ 33 | String getWebTitleSuffix(); 34 | 35 | /** 36 | * 更新 37 | * @param siteSetting siteSetting 38 | * @return int 39 | */ 40 | int updateSiteSetting(SiteSetting siteSetting); 41 | 42 | /** 43 | * 根据id删除站点信息 44 | * @param id id 45 | * @return int 46 | */ 47 | int deleteSiteSettingById(Integer id); 48 | 49 | /** 50 | * 添加 51 | * @param siteSetting siteSetting 52 | * @return int 53 | */ 54 | int saveSiteSetting(SiteSetting siteSetting); 55 | 56 | /** 57 | * 修改友链页面信息 58 | * @param content 具体内容 59 | * @return int 60 | */ 61 | int updateFriendInfoContent(String content); 62 | 63 | /** 64 | * 修改友链页面评论开放状态 65 | * @param commentEnabled commentEnabled 66 | * @return int 67 | */ 68 | int updateFriendInfoCommentEnabled(Boolean commentEnabled); 69 | } 70 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/mapper/TagMapper.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.mapper; 2 | 3 | import org.apache.ibatis.annotations.Mapper; 4 | import org.springframework.stereotype.Repository; 5 | import cn.raxcl.entity.Tag; 6 | import cn.raxcl.model.vo.TagBlogCountVO; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * 博客标签持久层接口 12 | * @author Raxcl 13 | * @date 2022-01-07 15:19:07 14 | */ 15 | @Mapper 16 | @Repository 17 | public interface TagMapper { 18 | /** 19 | * 获取博客标签列表 20 | * @return List 21 | */ 22 | List getTagList(); 23 | 24 | /** 25 | * 获取所有标签List不查询id 26 | * @return List 27 | */ 28 | List getTagListNotId(); 29 | 30 | /** 31 | * 按博客id查询List 32 | * @param blogId blogId 33 | * @return List 34 | */ 35 | List getTagListByBlogId(Long blogId); 36 | 37 | /** 38 | * 添加标签 39 | * @param tag tag 40 | * @return int 41 | */ 42 | int saveTag(Tag tag); 43 | 44 | /** 45 | * 按id查询标签 46 | * @param id id 47 | * @return Tag 48 | */ 49 | Tag getTagById(Long id); 50 | 51 | /** 52 | * 按name查询标签 53 | * @param name name 54 | * @return Tag 55 | */ 56 | Tag getTagByName(String name); 57 | 58 | /** 59 | * 按id删除标签 60 | * @param id id 61 | * @return int 62 | */ 63 | int deleteTagById(Long id); 64 | 65 | /** 66 | * 更新标签 67 | * @param tag tag 68 | * @return int 69 | */ 70 | int updateTag(Tag tag); 71 | 72 | /** 73 | * 查询每个标签的博客数量 74 | * @return List 75 | */ 76 | List getTagBlogCount(); 77 | } 78 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/mapper/UserMapper.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.mapper; 2 | 3 | import org.apache.ibatis.annotations.Mapper; 4 | import org.springframework.stereotype.Repository; 5 | import cn.raxcl.entity.User; 6 | 7 | /** 8 | * 用户持久层接口 9 | * @author Raxcl 10 | * @date 2022-01-07 12:07:42 11 | */ 12 | @Mapper 13 | @Repository 14 | public interface UserMapper { 15 | /** 16 | * 按用户名查询User 17 | * @param username username 18 | * @return User 19 | */ 20 | User findByUsername(String username); 21 | 22 | /** 23 | * 根据id查询用户信息 24 | * @param id id 25 | * @return User 26 | */ 27 | User findById(Long id); 28 | } 29 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/mapper/VisitLogMapper.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.mapper; 2 | 3 | import org.apache.ibatis.annotations.Mapper; 4 | import org.springframework.stereotype.Repository; 5 | import cn.raxcl.entity.VisitLog; 6 | import cn.raxcl.model.dto.VisitLogUuidTimeDTO; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * 访问日志持久层接口 12 | * @author Raxcl 13 | * @date 2022-01-07 15:29:18 14 | */ 15 | @Mapper 16 | @Repository 17 | public interface VisitLogMapper { 18 | /** 19 | * 查询日志 20 | * @param uuid uuid 21 | * @param startDate startDate 22 | * @param endDate endDate 23 | * @return List 24 | */ 25 | List getVisitLogListByUuidAndDate(String uuid, String startDate, String endDate); 26 | 27 | /** 28 | * 查询昨天的所有访问日志 29 | * @return List 30 | */ 31 | List getUuidAndCreateTimeByYesterday(); 32 | 33 | /** 34 | * 添加日志 35 | * @param log log 36 | * @return int 37 | */ 38 | int saveVisitLog(VisitLog log); 39 | 40 | /** 41 | * 删除日志 42 | * @param id id 43 | * @return int 44 | */ 45 | int deleteVisitLogById(Long id); 46 | 47 | /** 48 | * 查询今日访问量 49 | * @return int 50 | */ 51 | int countVisitLogByToday(); 52 | } 53 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/mapper/VisitRecordMapper.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.mapper; 2 | 3 | import org.apache.ibatis.annotations.Mapper; 4 | import org.springframework.stereotype.Repository; 5 | import cn.raxcl.entity.VisitRecord; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * 访问记录持久层接口 11 | * @author Raxcl 12 | * @date 2022-01-07 16:00:44 13 | */ 14 | @Mapper 15 | @Repository 16 | public interface VisitRecordMapper { 17 | /** 18 | * 按天数查询访问记录 19 | * @param limit limit 20 | * @return List 21 | */ 22 | List getVisitRecordListByLimit(Integer limit); 23 | 24 | /** 25 | * 添加访问记录 26 | * @param visitRecord visitRecord 27 | * @return int 28 | */ 29 | int saveVisitRecord(VisitRecord visitRecord); 30 | } 31 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/mapper/VisitorMapper.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.mapper; 2 | 3 | import org.apache.ibatis.annotations.Mapper; 4 | import org.springframework.stereotype.Repository; 5 | import cn.raxcl.entity.Visitor; 6 | import cn.raxcl.model.dto.VisitLogUuidTimeDTO; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * 访客统计持久层接口 12 | * @author Raxcl 13 | * @date 2022-01-07 15:35:52 14 | */ 15 | @Mapper 16 | @Repository 17 | public interface VisitorMapper { 18 | /** 19 | * 查询访客 20 | * @param startDate startDate 21 | * @param endDate endDate 22 | * @return List 23 | */ 24 | List getVisitorListByDate(String startDate, String endDate); 25 | 26 | /** 27 | * 查询昨天的所有新增访客的ip来源 28 | * @return List 29 | */ 30 | List getNewVisitorIpSourceByYesterday(); 31 | 32 | /** 33 | * 查询是否存在某个uuid 34 | * @param uuid uuid 35 | * @return int 36 | */ 37 | int hasUuid(String uuid); 38 | 39 | /** 40 | * 添加访客 41 | * @param visitor visitor 42 | * @return int 43 | */ 44 | int saveVisitor(Visitor visitor); 45 | 46 | /** 47 | * 更新访客pv和最后访问时间 48 | * @param dto dto 49 | * @return int 50 | */ 51 | int updatePvAndLastTimeByUuid(VisitLogUuidTimeDTO dto); 52 | 53 | /** 54 | * 删除访客 55 | * @param id id 56 | * @return int 57 | */ 58 | int deleteVisitorById(Long id); 59 | } 60 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/model/bean/Badge.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.model.bean; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | 8 | /** 9 | * GitHub徽标 10 | * @author Raxcl 11 | * @date 2022-01-07 18:43:43 12 | */ 13 | @NoArgsConstructor 14 | @Getter 15 | @Setter 16 | @ToString 17 | public class Badge { 18 | private String title; 19 | private String url; 20 | private String subject; 21 | private String value; 22 | private String color; 23 | } 24 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/model/bean/Copyright.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.model.bean; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | 8 | /** 9 | * copyright 10 | * @author Raxcl 11 | * @date 2022-01-07 18:43:50 12 | */ 13 | @NoArgsConstructor 14 | @Getter 15 | @Setter 16 | @ToString 17 | public class Copyright { 18 | private String title; 19 | private String siteName; 20 | } 21 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/model/bean/Favorite.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.model.bean; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | 8 | /** 9 | * 自定义爱好 10 | * @author Raxcl 11 | * @date 2022-01-07 18:43:54 12 | */ 13 | @NoArgsConstructor 14 | @Getter 15 | @Setter 16 | @ToString 17 | public class Favorite { 18 | private String title; 19 | private String content; 20 | } 21 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/model/dto/BlogPasswordDTO.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.model.dto; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | 8 | /** 9 | * 受保护文章密码DTO 10 | * @author Raxcl 11 | * @date 2022-01-07 09:12:49 12 | */ 13 | @NoArgsConstructor 14 | @Getter 15 | @Setter 16 | @ToString 17 | public class BlogPasswordDTO { 18 | private Long blogId; 19 | private String password; 20 | } 21 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/model/dto/BlogViewDTO.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.model.dto; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | 8 | /** 9 | * 博客浏览量 10 | * @author Raxcl 11 | * @date 2022-01-07 09:15:28 12 | */ 13 | @NoArgsConstructor 14 | @Getter 15 | @Setter 16 | @ToString 17 | public class BlogViewDTO { 18 | private Long id; 19 | private Integer views; 20 | } 21 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/model/dto/BlogVisibilityDTO.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.model.dto; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | 8 | /** 9 | * 博客可见性DTO 10 | * @author Raxcl 11 | * @date 2022-01-07 09:15:58 12 | */ 13 | @NoArgsConstructor 14 | @Getter 15 | @Setter 16 | @ToString 17 | public class BlogVisibilityDTO { 18 | /** 19 | * 赞赏开关 20 | */ 21 | private Boolean appreciation; 22 | 23 | /** 24 | * 推荐开关 25 | */ 26 | private Boolean recommend; 27 | 28 | /** 29 | * 评论开关 30 | */ 31 | private Boolean commentEnabled; 32 | 33 | /** 34 | * 是否置顶 35 | */ 36 | private Boolean top; 37 | 38 | /** 39 | * 公开或私密 40 | */ 41 | private Boolean published; 42 | 43 | /** 44 | * 密码保护 45 | */ 46 | private String password; 47 | } 48 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/model/dto/CommentDTO.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.model.dto; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | 8 | import java.util.Date; 9 | 10 | /** 11 | * 评论DTO 12 | * @author Raxcl 13 | * @date 2021-12-31 15:16:54 14 | */ 15 | @NoArgsConstructor 16 | @Getter 17 | @Setter 18 | @ToString 19 | public class CommentDTO { 20 | private Long id; 21 | /** 22 | * 昵称 23 | */ 24 | private String nickname; 25 | /** 26 | * 邮箱 27 | */ 28 | private String email; 29 | /** 30 | * 评论内容 31 | */ 32 | private String content; 33 | /** 34 | * 头像(图片路径) 35 | */ 36 | private String avatar; 37 | /** 38 | * 评论时间 39 | */ 40 | private Date createTime; 41 | /** 42 | * 个人网站 43 | */ 44 | private String website; 45 | /** 46 | * 评论者ip地址 47 | */ 48 | private String ip; 49 | /** 50 | * 公开或回收站 51 | */ 52 | private Boolean published; 53 | /** 54 | * 博主回复 55 | */ 56 | private Boolean adminComment; 57 | /** 58 | * 0普通文章,1关于我页面 59 | */ 60 | private Integer page; 61 | /** 62 | * 接收邮件提醒 63 | */ 64 | private Boolean notice; 65 | /** 66 | * 父评论id 67 | */ 68 | private Long parentCommentId; 69 | /** 70 | * 所属的文章id 71 | */ 72 | private Long blogId; 73 | /** 74 | * 如果评论昵称为QQ号,则将昵称和头像置为QQ昵称和QQ头像,并将此字段置为QQ号备份 75 | */ 76 | private String qq; 77 | } 78 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/model/dto/FriendDTO.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.model.dto; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | 8 | /** 9 | * 友链DTO 10 | * @author Raxcl 11 | * @date 2022-01-07 09:17:48 12 | */ 13 | @NoArgsConstructor 14 | @Getter 15 | @Setter 16 | @ToString 17 | public class FriendDTO { 18 | private Long id; 19 | /** 20 | * 昵称 21 | */ 22 | private String nickname; 23 | /** 24 | * 描述 25 | */ 26 | private String description; 27 | /** 28 | * 站点 29 | */ 30 | private String website; 31 | /** 32 | * 头像 33 | */ 34 | private String avatar; 35 | /** 36 | * 公开或隐藏 37 | */ 38 | private Boolean published; 39 | } 40 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/model/dto/LoginInfoDTO.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.model.dto; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | 8 | /** 9 | * 登录账号密码 10 | * @author Raxcl 11 | * @date 2022-01-07 09:26:14 12 | */ 13 | @NoArgsConstructor 14 | @Getter 15 | @Setter 16 | @ToString 17 | public class LoginInfoDTO { 18 | private String username; 19 | private String password; 20 | } 21 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/model/dto/VisitLogRemark.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.model.dto; 2 | 3 | import lombok.*; 4 | 5 | /** 6 | * 访问日志备注 7 | * @author Raxcl 8 | * @date 2022/3/16 15:48 9 | */ 10 | @AllArgsConstructor 11 | @NoArgsConstructor 12 | @Getter 13 | @Setter 14 | @ToString 15 | public class VisitLogRemark { 16 | /** 17 | * 访问内容 18 | */ 19 | private String content; 20 | 21 | /** 22 | * 备注 23 | */ 24 | private String remark; 25 | } 26 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/model/dto/VisitLogUuidTimeDTO.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.model.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | import lombok.ToString; 8 | 9 | import java.util.Date; 10 | 11 | /** 12 | * 访客更新DTO 13 | * @author Raxcl 14 | * @date 2022-01-07 09:26:49 15 | */ 16 | @AllArgsConstructor 17 | @NoArgsConstructor 18 | @Getter 19 | @Setter 20 | @ToString 21 | public class VisitLogUuidTimeDTO { 22 | private String uuid; 23 | private Date time; 24 | private Integer pv; 25 | } 26 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/model/temp/LogDTO.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.model.temp; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | import lombok.experimental.Accessors; 8 | 9 | /** 10 | * @author c-long.chan 11 | * 2022-01-10 08:54:50 12 | */ 13 | @NoArgsConstructor 14 | @Getter 15 | @Setter 16 | @ToString 17 | @Accessors(chain = true) 18 | public class LogDTO { 19 | /** 20 | * ip 21 | */ 22 | private String ip; 23 | 24 | private String userAgent; 25 | 26 | /** 27 | * ip来源 28 | */ 29 | private String ipSource; 30 | /** 31 | * 操作系统 32 | */ 33 | private String os; 34 | /** 35 | * 浏览器 36 | */ 37 | private String browser; 38 | 39 | public LogDTO(String ip, String userAgent) { 40 | this.ip = ip; 41 | this.userAgent = userAgent; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/model/temp/PageDTO.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.model.temp; 2 | 3 | import lombok.*; 4 | import lombok.experimental.Accessors; 5 | 6 | /** 7 | * @author c-long.chan 8 | * 2022-01-10 11:42:42 9 | */ 10 | @NoArgsConstructor 11 | @Getter 12 | @Setter 13 | @ToString 14 | @Accessors(chain = true) 15 | public class PageDTO { 16 | /** 17 | * 开始日期 18 | */ 19 | private String startDate; 20 | 21 | /** 22 | * 结束日期 23 | */ 24 | private String endDate; 25 | 26 | /** 27 | * 排序方式 28 | */ 29 | private String orderBy; 30 | 31 | } 32 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/model/temp/PostCommentDTO.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.model.temp; 2 | 3 | import cn.raxcl.entity.User; 4 | import cn.raxcl.enums.CommentOpenStateEnum; 5 | import lombok.Getter; 6 | import lombok.NoArgsConstructor; 7 | import lombok.Setter; 8 | import lombok.ToString; 9 | import org.springframework.stereotype.Component; 10 | 11 | /** 12 | * @author c-long.chan 13 | * 2022-01-05 19:28:16 14 | */ 15 | @NoArgsConstructor 16 | @Getter 17 | @Setter 18 | @ToString 19 | @Component 20 | public class PostCommentDTO { 21 | /** 22 | * 是否访客的评论 23 | */ 24 | private Boolean isVisitorComment; 25 | 26 | String subject; 27 | 28 | User admin; 29 | 30 | /** 31 | * 文章状态 32 | */ 33 | CommentOpenStateEnum judgeResult; 34 | } 35 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/model/vo/ArchiveBlogVO.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.model.vo; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | 8 | /** 9 | * 归档页面博客简要信息 10 | * @author Raxcl 11 | * @date 2022-01-07 09:27:10 12 | */ 13 | @NoArgsConstructor 14 | @Getter 15 | @Setter 16 | @ToString 17 | public class ArchiveBlogVO { 18 | private Long id; 19 | private String title; 20 | private String day; 21 | private String password; 22 | private Boolean privacy; 23 | } 24 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/model/vo/BlogDetailVO.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.model.vo; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | import cn.raxcl.entity.Category; 8 | import cn.raxcl.entity.Tag; 9 | 10 | import java.util.Date; 11 | import java.util.List; 12 | 13 | /** 14 | * 博客详情 15 | * @author Raxcl 16 | * @date 2022-01-07 09:27:58 17 | */ 18 | @NoArgsConstructor 19 | @Getter 20 | @Setter 21 | @ToString 22 | public class BlogDetailVO { 23 | private Long id; 24 | /** 25 | * 文章标题 26 | */ 27 | private String title; 28 | /** 29 | * 文章正文 30 | */ 31 | private String content; 32 | /** 33 | * 赞赏开关 34 | */ 35 | private Boolean appreciation; 36 | /** 37 | * 评论开关 38 | */ 39 | private Boolean commentEnabled; 40 | /** 41 | * 是否置顶 42 | */ 43 | private Boolean top; 44 | /** 45 | * 创建时间 46 | */ 47 | private Date createTime; 48 | /** 49 | * 更新时间 50 | */ 51 | private Date updateTime; 52 | /** 53 | * 浏览次数 54 | */ 55 | private Integer views; 56 | /** 57 | * 文章字数 58 | */ 59 | private Integer words; 60 | /** 61 | * 阅读时长(分钟) 62 | */ 63 | private Integer readTime; 64 | /** 65 | * 密码保护 66 | */ 67 | private String password; 68 | /** 69 | * 文章分类 70 | */ 71 | private Category category; 72 | /** 73 | * 文章标签 74 | */ 75 | private List tags; 76 | } 77 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/model/vo/BlogIdAndTitleVO.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.model.vo; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | 8 | /** 9 | * 评论管理页面按博客title查询评论 10 | * @author Raxcl 11 | * @date 2022-01-07 09:33:19 12 | */ 13 | @NoArgsConstructor 14 | @Getter 15 | @Setter 16 | @ToString 17 | public class BlogIdAndTitleVO { 18 | private Long id; 19 | private String title; 20 | } 21 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/model/vo/BlogInfoVO.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.model.vo; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | import cn.raxcl.entity.Category; 8 | import cn.raxcl.entity.Tag; 9 | 10 | import java.util.Date; 11 | import java.util.List; 12 | 13 | /** 14 | * 博客简要信息 15 | * @author Raxcl 16 | * @date 2022-01-07 09:33:24 17 | */ 18 | @NoArgsConstructor 19 | @Getter 20 | @Setter 21 | @ToString 22 | public class BlogInfoVO { 23 | private Long id; 24 | /** 25 | * 文章标题 26 | */ 27 | private String title; 28 | /** 29 | * 描述 30 | */ 31 | private String description; 32 | /** 33 | * 创建时间 34 | */ 35 | private Date createTime; 36 | /** 37 | * 浏览次数 38 | */ 39 | private Integer views; 40 | /** 41 | * 文章字数 42 | */ 43 | private Integer words; 44 | /** 45 | * 阅读时长(分钟) 46 | */ 47 | private Integer readTime; 48 | /** 49 | * 是否置顶 50 | */ 51 | private Boolean top; 52 | /** 53 | * 文章密码 54 | */ 55 | private String password; 56 | /** 57 | * 是否私密文章 58 | */ 59 | private Boolean privacy; 60 | /** 61 | * 文章分类 62 | */ 63 | private Category category; 64 | /** 65 | * 文章标签 66 | */ 67 | private List tags; 68 | } 69 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/model/vo/CategoryBlogCountVO.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.model.vo; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | 8 | /** 9 | * 分类和博客数量 10 | * @author Raxcl 11 | * @date 2022-01-07 09:33:29 12 | */ 13 | @NoArgsConstructor 14 | @Getter 15 | @Setter 16 | @ToString 17 | public class CategoryBlogCountVO { 18 | private Long id; 19 | /** 20 | * 分类名 21 | */ 22 | private String name; 23 | /** 24 | * 分类下博客数量 25 | */ 26 | private Integer value; 27 | } 28 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/model/vo/FriendInfoVO.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.model.vo; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | 8 | /** 9 | * 友链页面信息 10 | * @author Raxcl 11 | * @date 2022-01-07 09:33:31 12 | */ 13 | @NoArgsConstructor 14 | @Getter 15 | @Setter 16 | @ToString 17 | public class FriendInfoVO { 18 | private String content; 19 | private Boolean commentEnabled; 20 | } 21 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/model/vo/FriendVO.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.model.vo; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | 8 | /** 9 | * 友链VO 10 | * @author Raxcl 11 | * @date 2022-01-07 09:33:35 12 | */ 13 | @NoArgsConstructor 14 | @Getter 15 | @Setter 16 | @ToString 17 | public class FriendVO { 18 | /** 19 | * 昵称 20 | */ 21 | private String nickname; 22 | /** 23 | * 描述 24 | */ 25 | private String description; 26 | /** 27 | * 站点 28 | */ 29 | private String website; 30 | /** 31 | * 头像 32 | */ 33 | private String avatar; 34 | } 35 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/model/vo/IntroductionVO.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.model.vo; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | import cn.raxcl.model.bean.Favorite; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * 侧边栏资料卡 13 | * @author Raxcl 14 | * @date 2022-01-07 09:33:38 15 | */ 16 | @NoArgsConstructor 17 | @Getter 18 | @Setter 19 | @ToString 20 | public class IntroductionVO { 21 | private String avatar; 22 | private String name; 23 | private String github; 24 | private String qq; 25 | private String bilibili; 26 | private String netease; 27 | private String email; 28 | 29 | private List rollText; 30 | private List favorites; 31 | 32 | } 33 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/model/vo/NewBlogVO.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.model.vo; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | 8 | /** 9 | * 最新推荐博客 10 | * @author Raxcl 11 | * @date 2022-01-07 09:33:41 12 | */ 13 | @NoArgsConstructor 14 | @Getter 15 | @Setter 16 | @ToString 17 | public class NewBlogVO { 18 | private Long id; 19 | private String title; 20 | private String password; 21 | private Boolean privacy; 22 | } 23 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/model/vo/PageCommentVO.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.model.vo; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | 8 | import java.util.Date; 9 | import java.util.List; 10 | 11 | /** 12 | * 页面评论 13 | * @author Raxcl 14 | * @date 2022-01-07 09:33:43 15 | */ 16 | @NoArgsConstructor 17 | @Getter 18 | @Setter 19 | @ToString 20 | public class PageCommentVO { 21 | private Long id; 22 | /** 23 | * 昵称 24 | */ 25 | private String nickname; 26 | /** 27 | * 评论内容 28 | */ 29 | private String content; 30 | /** 31 | * 头像(图片路径) 32 | */ 33 | private String avatar; 34 | /** 35 | * 评论时间 36 | */ 37 | private Date createTime; 38 | /** 39 | * 个人网站 40 | */ 41 | private String website; 42 | /** 43 | * 博主回复 44 | */ 45 | private Boolean adminComment; 46 | /** 47 | * 父评论id 48 | */ 49 | private String parentCommentId; 50 | /** 51 | * 父评论昵称 52 | */ 53 | private String parentCommentNickname; 54 | /** 55 | * 回复该评论的评论 56 | */ 57 | private List replyComments; 58 | } 59 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/model/vo/PageResultVO.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.model.vo; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * 分页结果 12 | * @author Raxcl 13 | * @date 2022-01-07 09:33:46 14 | */ 15 | @NoArgsConstructor 16 | @Getter 17 | @Setter 18 | @ToString 19 | public class PageResultVO { 20 | /** 21 | * 总页数 22 | */ 23 | private Integer totalPage; 24 | 25 | /** 26 | * 数据 27 | */ 28 | private List list; 29 | 30 | public PageResultVO(Integer totalPage, List list) { 31 | this.totalPage = totalPage; 32 | this.list = list; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/model/vo/QqResultVO.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.model.vo; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.Map; 6 | 7 | /** 8 | * @author raxcl 9 | * @date 2024-01-19 9:54:53 10 | */ 11 | @Data 12 | public class QqResultVO { 13 | private String success; 14 | 15 | private String msg; 16 | 17 | private Map data; 18 | 19 | private String time; 20 | 21 | private String api_vers; 22 | } 23 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/model/vo/QqVO.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.model.vo; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @author raxcl 7 | * @date 2024-01-19 9:54:53 8 | */ 9 | @Data 10 | public class QqVO { 11 | /** 12 | * qq号 13 | */ 14 | private Long qq; 15 | 16 | /** 17 | * qq昵称 18 | */ 19 | private String name; 20 | 21 | /** 22 | * qq邮箱 23 | */ 24 | private String email; 25 | 26 | /** 27 | * qq头像 28 | */ 29 | private String avatar; 30 | } 31 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/model/vo/RandomBlogVO.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.model.vo; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | 8 | import java.util.Date; 9 | 10 | /** 11 | * 随机博客 12 | * @author Raxcl 13 | * @date 2022-01-07 09:33:49 14 | */ 15 | @NoArgsConstructor 16 | @Getter 17 | @Setter 18 | @ToString 19 | public class RandomBlogVO { 20 | private Long id; 21 | /** 22 | * 文章标题 23 | */ 24 | private String title; 25 | /** 26 | * 文章首图,用于随机文章展示 27 | */ 28 | private String firstPicture; 29 | /** 30 | * 创建时间 31 | */ 32 | private Date createTime; 33 | /** 34 | * 文章密码 35 | */ 36 | private String password; 37 | /** 38 | * 是否私密文章 39 | */ 40 | private Boolean privacy; 41 | } 42 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/model/vo/SearchBlogVO.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.model.vo; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | 8 | /** 9 | * 关键字搜索博客 10 | * @author Raxcl 11 | * @date 2022-01-07 09:33:52 12 | */ 13 | @NoArgsConstructor 14 | @Getter 15 | @Setter 16 | @ToString 17 | public class SearchBlogVO { 18 | private Long id; 19 | private String title; 20 | private String content; 21 | } 22 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/model/vo/TagBlogCountVO.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.model.vo; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | 8 | /** 9 | * 标签和博客数量 10 | * @author Raxcl 11 | * @date 2022-01-07 09:33:56 12 | */ 13 | @NoArgsConstructor 14 | @Getter 15 | @Setter 16 | @ToString 17 | public class TagBlogCountVO { 18 | private Long id; 19 | /** 20 | * 标签名 21 | */ 22 | private String name; 23 | /** 24 | * 标签下博客数量 25 | */ 26 | private Integer value; 27 | } 28 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/service/AboutService.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.service; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * @author c-long.chan 7 | * @date 2022-01-07 08:53:58 8 | */ 9 | public interface AboutService { 10 | /** 11 | * 获取关于我页面信息 12 | * @return Map 13 | */ 14 | Map getAboutInfo(); 15 | 16 | /** 17 | * 获取关于我页面配置 18 | * @return Map 19 | */ 20 | Map getAboutSetting(); 21 | 22 | /** 23 | * 修改关于我页面 24 | * @param map map 25 | */ 26 | void updateAbout(Map map); 27 | 28 | /** 29 | * 判断评论是否已关闭 30 | * @return boolean 31 | */ 32 | boolean getAboutCommentEnabled(); 33 | 34 | /** 35 | * 更新关于我页面 36 | * @param nameEn nameEn 37 | * @param value value 38 | */ 39 | void updateOneAbout(String nameEn, String value); 40 | } 41 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/service/CategoryService.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.service; 2 | 3 | import cn.raxcl.entity.Category; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * @author c-long.chan 9 | * @date 2022-01-07 09:09:16 10 | */ 11 | public interface CategoryService { 12 | /** 13 | * 获取博客分类列表 14 | * @return List 15 | */ 16 | List getCategoryList(); 17 | 18 | /** 19 | * 获取分类名list 20 | * @return List 21 | */ 22 | List getCategoryNameList(); 23 | 24 | /** 25 | * 保存分类 26 | * @param category category 27 | */ 28 | void saveCategory(Category category); 29 | 30 | /** 31 | * 根据id获取分类信息 32 | * @param id id 33 | * @return Category 34 | */ 35 | Category getCategoryById(Long id); 36 | 37 | /** 38 | * 根据名称获取分类信息 39 | * @param name name 40 | * @return Category 41 | */ 42 | Category getCategoryByName(String name); 43 | 44 | /** 45 | * 根据id删除分类信息 46 | * @param id id 47 | */ 48 | void deleteCategoryById(Long id); 49 | 50 | /** 51 | * 更新分类信息 52 | * @param category category 53 | */ 54 | void updateCategory(Category category); 55 | } 56 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/service/CityVisitorService.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.service; 2 | 3 | import cn.raxcl.entity.CityVisitor; 4 | 5 | /** 6 | * @author c-long.chan 7 | * @date 2022-01-07 16:03:47 8 | */ 9 | public interface CityVisitorService { 10 | /** 11 | * 添加访问记录 12 | * @param cityVisitor cityVisitor 13 | */ 14 | void saveCityVisitor(CityVisitor cityVisitor); 15 | } 16 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/service/DashboardService.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.service; 2 | 3 | import cn.raxcl.entity.CityVisitor; 4 | 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | /** 9 | * @author c-long.chan 10 | * @date 2022-01-07 15:51:46 11 | */ 12 | public interface DashboardService { 13 | /** 14 | * 今日访问总量 15 | * @return int 16 | */ 17 | int countVisitLogByToday(); 18 | 19 | /** 20 | * 查询博客总数 21 | * @return int 22 | */ 23 | int getBlogCount(); 24 | 25 | /** 26 | * 获取评论总数 27 | * @return int 28 | */ 29 | int getCommentCount(); 30 | 31 | /** 32 | * 获取分类总数 33 | * @return Map 34 | */ 35 | Map getCategoryBlogCountMap(); 36 | 37 | /** 38 | * 获取标签下总数 39 | * @return Map 40 | */ 41 | Map getTagBlogCountMap(); 42 | 43 | /** 44 | * 获取访客记录 45 | * @return Map 46 | */ 47 | Map getVisitRecordMap(); 48 | 49 | /** 50 | * 获取城市访问list 51 | * @return Map 52 | */ 53 | List getCityVisitorList(); 54 | } 55 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/service/ExceptionLogService.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.service; 2 | 3 | import cn.raxcl.entity.ExceptionLog; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * @author c-long.chan 9 | * @date 2022-01-07 15:58:00 10 | */ 11 | public interface ExceptionLogService { 12 | /** 13 | * 查询日志 14 | * @param startDate startDate 15 | * @param endDate endDate 16 | * @return List 17 | */ 18 | List getExceptionLogListByDate(String startDate, String endDate); 19 | 20 | 21 | /** 22 | * 添加日志 23 | * @param log log 24 | */ 25 | void saveExceptionLog(ExceptionLog log); 26 | 27 | /** 28 | * 删除日志 29 | * @param id id 30 | */ 31 | void deleteExceptionLogById(Long id); 32 | } 33 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/service/LoginLogService.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.service; 2 | 3 | import cn.raxcl.entity.LoginLog; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * @author c-long.chan 9 | * @date 2022-01-07 12:32:46 10 | */ 11 | public interface LoginLogService { 12 | /** 13 | * 查询登录日志列表 14 | * @param startDate 开始时间 15 | * @param endDate 结束时间 16 | * @return List 17 | */ 18 | List getLoginLogListByDate(String startDate, String endDate); 19 | 20 | /** 21 | * 保存登录日志 22 | * @param log log 23 | */ 24 | void saveLoginLog(LoginLog log); 25 | 26 | /** 27 | * 根据id删除登录日志 28 | * @param id id 29 | */ 30 | void deleteLoginLogById(Long id); 31 | 32 | } 33 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/service/MailService.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.service; 2 | 3 | import cn.raxcl.model.dto.CommentDTO; 4 | import java.util.Map; 5 | 6 | /** 7 | * @author c-long.chan 8 | * @date 2022-01-06 12:58:03 9 | */ 10 | public interface MailService { 11 | /** 12 | * 发送邮件提醒我自己 13 | * @param commentDTO commentDTO 14 | */ 15 | void sendMailToMe(CommentDTO commentDTO); 16 | 17 | /** 18 | * 发送邮件 19 | * @param map map 20 | * @param toAccount toAccount 21 | * @param subject subject 22 | * @param template template 23 | */ 24 | void sendHtmlTemplateMail(Map map, String toAccount, String subject, String template); 25 | 26 | } 27 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/service/MomentService.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.service; 2 | 3 | import cn.raxcl.entity.Moment; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * @author c-long.chan 9 | * @date 2022-01-07 13:14:42 10 | */ 11 | public interface MomentService { 12 | /** 13 | * 查询动态列表 14 | * @return List 15 | */ 16 | List getMomentList(); 17 | 18 | /** 19 | * 查询动态vo列表 20 | * @param pageNum pageNum 21 | * @param adminIdentity adminIdentity 22 | * @return List 23 | */ 24 | List getMomentVOList(Integer pageNum, boolean adminIdentity); 25 | 26 | /** 27 | * 给动态点赞 28 | * @param momentId momentId 29 | */ 30 | void addLikeByMomentId(Long momentId); 31 | 32 | /** 33 | * 更新动态公开状态 34 | * @param momentId 动态id 35 | * @param published 是否公开 36 | */ 37 | void updateMomentPublishedById(Long momentId, Boolean published); 38 | 39 | /** 40 | * 根据id查询动态 41 | * @param id 动态id 42 | * @return Moment 43 | */ 44 | Moment getMomentById(Long id); 45 | 46 | /** 47 | * 删除动态 48 | * @param id 动态id 49 | */ 50 | void deleteMomentById(Long id); 51 | 52 | /** 53 | * 发布动态 54 | * @param moment 动态实体 55 | */ 56 | void saveMoment(Moment moment); 57 | 58 | /** 59 | * 更新动态 60 | * @param moment 动态实体 61 | */ 62 | void updateMoment(Moment moment); 63 | } 64 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/service/OperationLogService.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.service; 2 | 3 | import cn.raxcl.entity.OperationLog; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * @author c-long.chan 9 | * @date 2022-01-07 15:02:16 10 | */ 11 | public interface OperationLogService { 12 | /** 13 | * 查询日志 14 | * @param startDate startDate 15 | * @param endDate endDate 16 | * @return List 17 | */ 18 | List getOperationLogListByDate(String startDate, String endDate); 19 | 20 | /** 21 | * 添加日志 22 | * @param log log 23 | */ 24 | void saveOperationLog(OperationLog log); 25 | 26 | /** 27 | * 删除日志 28 | * @param id id 29 | */ 30 | void deleteOperationLogById(Long id); 31 | } 32 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/service/ScheduleJobService.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.service; 2 | 3 | import cn.raxcl.entity.ScheduleJob; 4 | import cn.raxcl.entity.ScheduleJobLog; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * @author c-long.chan 10 | * @date 2022-01-07 16:02:43 11 | */ 12 | public interface ScheduleJobService { 13 | /** 14 | * 查询定时任务列表 15 | * @return List 16 | */ 17 | List getJobList(); 18 | 19 | /** 20 | * 新建定时任务 21 | * @param scheduleJob scheduleJob 22 | */ 23 | void saveJob(ScheduleJob scheduleJob); 24 | 25 | /** 26 | * 修改定时任务 27 | * @param scheduleJob scheduleJob 28 | */ 29 | void updateJob(ScheduleJob scheduleJob); 30 | 31 | /** 32 | * 删除定时任务 33 | * @param jobId 任务id 34 | */ 35 | void deleteJobById(Long jobId); 36 | 37 | /** 38 | * 立即执行任务 39 | * @param jobId 任务id 40 | */ 41 | void runJobById(Long jobId); 42 | 43 | /** 44 | * 更新任务状态:暂停或恢复 45 | * @param jobId 任务id 46 | * @param status 状态 47 | */ 48 | void updateJobStatusById(Long jobId, Boolean status); 49 | 50 | /** 51 | * 分页查询定时任务日志列表 52 | * @param startDate startDate 53 | * @param endDate endDate 54 | * @return List 55 | */ 56 | List getJobLogListByDate(String startDate, String endDate); 57 | 58 | /** 59 | * 保存任务日志 60 | * @param log log 61 | */ 62 | void saveJobLog(ScheduleJobLog log); 63 | 64 | /** 65 | * 按id删除任务日志 66 | * @param logId logId 67 | */ 68 | void deleteJobLogByLogId(Long logId); 69 | } 70 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/service/SiteSettingService.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.service; 2 | 3 | import cn.raxcl.entity.SiteSetting; 4 | 5 | import java.util.LinkedHashMap; 6 | import java.util.List; 7 | import java.util.Map; 8 | 9 | /** 10 | * @author c-long.chan 11 | * @date 2022-01-07 11:25:25 12 | */ 13 | public interface SiteSettingService { 14 | /** 15 | * 获取所有站点配置信息 16 | * @return Map> 17 | */ 18 | Map> getList(); 19 | 20 | /** 21 | * 获取站点信息 22 | * @return Map 23 | */ 24 | Map getSiteInfo(); 25 | 26 | /** 27 | * 查询网页标题后缀 28 | * @return String 29 | */ 30 | String getWebTitleSuffix(); 31 | 32 | /** 33 | * 更新站点配置 34 | * @param siteSettings siteSettings 35 | * @param deleteIds deleteIds 36 | */ 37 | void updateSiteSetting(List> siteSettings, List deleteIds); 38 | 39 | /** 40 | * 保存站点配置 41 | * @param siteSetting siteSetting 42 | */ 43 | void saveOneSiteSetting(SiteSetting siteSetting); 44 | 45 | /** 46 | * 根据id删除站点信息 47 | * @param id id 48 | */ 49 | void deleteOneSiteSettingById(Integer id); 50 | 51 | /** 52 | * 更新 53 | * @param siteSetting siteSetting 54 | */ 55 | void updateOneSiteSetting(SiteSetting siteSetting); 56 | } 57 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/service/TagService.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.service; 2 | 3 | import cn.raxcl.entity.Tag; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * @author c-long.chan 9 | * @date 2022-01-07 15:22:59 10 | */ 11 | public interface TagService { 12 | /** 13 | * 获取博客标签列表 14 | * @return List 15 | */ 16 | List getTagList(); 17 | 18 | /** 19 | * 获取所有标签List不查询id 20 | * @return List 21 | */ 22 | List getTagListNotId(); 23 | 24 | /** 25 | * 按博客id查询List 26 | * @param blogId blogId 27 | * @return List 28 | */ 29 | List getTagListByBlogId(Long blogId); 30 | 31 | /** 32 | * 添加标签 33 | * @param tag tag 34 | */ 35 | void saveTag(Tag tag); 36 | 37 | /** 38 | * 按id查询标签 39 | * @param id id 40 | * @return Tag 41 | */ 42 | Tag getTagById(Long id); 43 | 44 | /** 45 | * 查询标签 46 | * @param name name 47 | * @return Tag 48 | */ 49 | Tag getTagByName(String name); 50 | 51 | /** 52 | * 按id删除标签 53 | * @param id id 54 | */ 55 | void deleteTagById(Long id); 56 | 57 | /** 58 | * 更新标签 59 | * @param tag tag 60 | */ 61 | void updateTag(Tag tag); 62 | } 63 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/service/UserService.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.service; 2 | 3 | import cn.raxcl.entity.User; 4 | 5 | /** 6 | * @author c-long.chan 7 | * @date 2022-01-04 19:05:36 8 | */ 9 | public interface UserService { 10 | /** 11 | * 根据用户名和密码查询用户信息 12 | * @param username 用户名 13 | * @param password 密码 14 | * @return User 15 | */ 16 | User findUserByUsernameAndPassword(String username, String password); 17 | 18 | /** 19 | * 根据id查询用户信息 20 | * @param id id 21 | * @return User 22 | */ 23 | User findUserById(Long id); 24 | } 25 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/service/VisitLogService.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.service; 2 | 3 | import cn.raxcl.entity.VisitLog; 4 | import cn.raxcl.model.dto.VisitLogUuidTimeDTO; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * @author c-long.chan 10 | * @date 2022-01-07 15:35:27 11 | */ 12 | public interface VisitLogService { 13 | /** 14 | * 查询日志 15 | * @param uuid uuid 16 | * @param startDate startDate 17 | * @param endDate endDate 18 | * @return List 19 | */ 20 | List getVisitLogListByUuidAndDate(String uuid, String startDate, String endDate); 21 | 22 | /** 23 | * 查询昨天的所有访问日志 24 | * @return List 25 | */ 26 | List getUuidAndCreateTimeByYesterday(); 27 | 28 | 29 | /** 30 | * 添加日志 31 | * @param log log 32 | */ 33 | void saveVisitLog(VisitLog log); 34 | 35 | /** 36 | * 删除日志 37 | * @param id id 38 | */ 39 | void deleteVisitLogById(Long id); 40 | } 41 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/service/VisitRecordService.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.service; 2 | 3 | import cn.raxcl.entity.VisitRecord; 4 | 5 | /** 6 | * @author c-long.chan 7 | * @date 2022-01-07 16:01:14 8 | */ 9 | public interface VisitRecordService { 10 | /** 11 | * 添加访问记录 12 | * @param visitRecord visitRecord 13 | */ 14 | void saveVisitRecord(VisitRecord visitRecord); 15 | } 16 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/service/VisitorService.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.service; 2 | 3 | import cn.raxcl.entity.Visitor; 4 | import cn.raxcl.model.dto.VisitLogUuidTimeDTO; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * @author c-long.chan 10 | * @date 2022-01-07 15:41:45 11 | */ 12 | public interface VisitorService { 13 | /** 14 | * 查询访客 15 | * @param startDate startDate 16 | * @param endDate endDate 17 | * @return List 18 | */ 19 | List getVisitorListByDate(String startDate, String endDate); 20 | 21 | /** 22 | * 查询昨天的所有新增访客的ip来源 23 | * @return List 24 | */ 25 | List getNewVisitorIpSourceByYesterday(); 26 | 27 | /** 28 | * 查询是否存在某个uuid 29 | * @param uuid uuid 30 | * @return boolean 31 | */ 32 | boolean hasUuid(String uuid); 33 | 34 | 35 | /** 36 | * 添加访客 37 | * @param visitor visitor 38 | */ 39 | void saveVisitor(Visitor visitor); 40 | 41 | /** 42 | * 更新访客pv和最后访问时间 43 | * @param dto dto 44 | */ 45 | void updatePvAndLastTimeByUuid(VisitLogUuidTimeDTO dto); 46 | 47 | /** 48 | * 删除访客 49 | * @param id id 50 | * @param uuid uuid 51 | */ 52 | void deleteVisitor(Long id, String uuid); 53 | } 54 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/service/impl/CityVisitorServiceImpl.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.service.impl; 2 | 3 | import org.springframework.stereotype.Service; 4 | import cn.raxcl.entity.CityVisitor; 5 | import cn.raxcl.mapper.CityVisitorMapper; 6 | import cn.raxcl.service.CityVisitorService; 7 | 8 | /** 9 | * 城市访客数量统计业务层实现 10 | * @author Raxcl 11 | * @date 2022-01-07 15:54:12 12 | */ 13 | @Service 14 | public class CityVisitorServiceImpl implements CityVisitorService { 15 | private final CityVisitorMapper cityVisitorMapper; 16 | 17 | public CityVisitorServiceImpl(CityVisitorMapper cityVisitorMapper) { 18 | this.cityVisitorMapper = cityVisitorMapper; 19 | } 20 | 21 | @Override 22 | public void saveCityVisitor(CityVisitor cityVisitor) { 23 | cityVisitorMapper.saveCityVisitor(cityVisitor); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/service/impl/VisitRecordServiceImpl.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.service.impl; 2 | 3 | import org.springframework.stereotype.Service; 4 | import cn.raxcl.entity.VisitRecord; 5 | import cn.raxcl.mapper.VisitRecordMapper; 6 | import cn.raxcl.service.VisitRecordService; 7 | 8 | /** 9 | * 访问记录业务层实现 10 | * @author Raxcl 11 | * @date 2022-01-07 16:01:50 12 | */ 13 | @Service 14 | public class VisitRecordServiceImpl implements VisitRecordService { 15 | private final VisitRecordMapper visitRecordMapper; 16 | 17 | public VisitRecordServiceImpl(VisitRecordMapper visitRecordMapper) { 18 | this.visitRecordMapper = visitRecordMapper; 19 | } 20 | 21 | @Override 22 | public void saveVisitRecord(VisitRecord visitRecord) { 23 | visitRecordMapper.saveVisitRecord(visitRecord); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/task/RedisSyncScheduleTask.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.task; 2 | 3 | import org.springframework.stereotype.Component; 4 | import cn.raxcl.constant.RedisKeyConstants; 5 | import cn.raxcl.service.BlogService; 6 | import cn.raxcl.service.RedisService; 7 | 8 | import java.util.Map; 9 | import java.util.Set; 10 | 11 | /** 12 | * Redis相关定时任务 13 | * @author Raxcl 14 | * @date 2022-02-16 17:30:34 15 | */ 16 | @Component 17 | public class RedisSyncScheduleTask { 18 | private final RedisService redisService; 19 | private final BlogService blogService; 20 | 21 | public RedisSyncScheduleTask(RedisService redisService, BlogService blogService) { 22 | this.redisService = redisService; 23 | this.blogService = blogService; 24 | } 25 | 26 | /** 27 | * 从Redis同步博客文章浏览量到数据库 定时任务反射调用 28 | */ 29 | public void syncBlogViewsToDatabase() { 30 | String redisKey = RedisKeyConstants.BLOG_VIEWS_MAP; 31 | Map blogViewsMap = redisService.getMapByHash(redisKey); 32 | Set keys = blogViewsMap.keySet(); 33 | for (Object keyObj : keys) { 34 | Integer key = 0; 35 | if(keyObj instanceof Integer){ 36 | key = (Integer)keyObj; 37 | } 38 | Integer views = (Integer) blogViewsMap.get(key); 39 | blogService.updateViews(key.longValue(), views); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/util/AopUtils.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.util; 2 | 3 | import org.aspectj.lang.JoinPoint; 4 | import org.aspectj.lang.reflect.MethodSignature; 5 | import org.springframework.web.multipart.MultipartFile; 6 | 7 | import javax.servlet.http.HttpServletRequest; 8 | import javax.servlet.http.HttpServletResponse; 9 | import java.util.LinkedHashMap; 10 | import java.util.Map; 11 | 12 | /** 13 | * AOP工具类 14 | * @author Raxcl 15 | * @date 2022-01-07 19:43:44 16 | */ 17 | public class AopUtils { 18 | private AopUtils(){} 19 | /** 20 | * 获取请求参数 21 | * 22 | * @param joinPoint joinPoint 23 | * @return Map 24 | */ 25 | public static Map getRequestParams(JoinPoint joinPoint) { 26 | Map map = new LinkedHashMap<>(); 27 | String[] parameterNames = ((MethodSignature) joinPoint.getSignature()).getParameterNames(); 28 | Object[] args = joinPoint.getArgs(); 29 | for (int i = 0; i < args.length; i++) { 30 | if (!isFilterObject(args[i])) { 31 | map.put(parameterNames[i], args[i]); 32 | } 33 | } 34 | return map; 35 | } 36 | 37 | /** 38 | * consider if the data is file, httpRequest or response 39 | * 40 | * @param o the data 41 | * @return if match return true, else return false 42 | */ 43 | private static boolean isFilterObject(final Object o) { 44 | return o instanceof HttpServletRequest || o instanceof HttpServletResponse || o instanceof MultipartFile; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/util/HashUtils.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.util; 2 | 3 | import org.apache.commons.codec.binary.StringUtils; 4 | import org.apache.commons.codec.digest.MurmurHash3; 5 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 6 | 7 | /** 8 | * Hash工具类 9 | * @author Raxcl 10 | * @date 2022-01-11 10:52:18 11 | */ 12 | public class HashUtils { 13 | 14 | private HashUtils(){} 15 | 16 | private static final BCryptPasswordEncoder B_CRYPT_PASSWORD_ENCODER = new BCryptPasswordEncoder(); 17 | 18 | 19 | public static long getMurmurHash32(String str) { 20 | int i = MurmurHash3.hash32x86(StringUtils.getBytesUtf8(str)); 21 | return i < 0 ? Integer.MAX_VALUE - (long) i : i; 22 | } 23 | 24 | public static boolean matchBc(CharSequence rawPassword, String encodedPassword) { 25 | return B_CRYPT_PASSWORD_ENCODER.matches(rawPassword, encodedPassword); 26 | } 27 | 28 | /** 29 | * 用于生成密码 30 | * @param rawPassword 明文密码 31 | * @return String 32 | */ 33 | public static String getBc(CharSequence rawPassword) { 34 | return B_CRYPT_PASSWORD_ENCODER.encode(rawPassword); 35 | } 36 | 37 | public static void main(String[] args) { 38 | String s = "$2a$10$FtXrq62IN1ijFpEOc6pl.uWYTj21AsfrNA57fWcigEyMQ9F4wrCLu"; 39 | System.out.println(matchBc("123456", s)); 40 | System.out.println(getBc("123456")); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/util/JacksonUtils.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.util; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | 6 | import java.io.IOException; 7 | import java.io.InputStream; 8 | 9 | /** 10 | * Jackson Object Mapper 11 | * @author Raxcl 12 | * @date 2022-01-07 19:50:00 13 | */ 14 | public class JacksonUtils { 15 | private JacksonUtils(){} 16 | 17 | private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); 18 | 19 | public static String writeValueAsString(Object value) { 20 | try { 21 | return OBJECT_MAPPER.writeValueAsString(value); 22 | } catch (JsonProcessingException e) { 23 | e.printStackTrace(); 24 | return ""; 25 | } 26 | } 27 | 28 | public static T readValue(String content, Class valueType) { 29 | try { 30 | return OBJECT_MAPPER.readValue(content, valueType); 31 | } catch (IOException e) { 32 | e.printStackTrace(); 33 | return null; 34 | } 35 | } 36 | 37 | public static T readValue(InputStream src, Class valueType) { 38 | try { 39 | return OBJECT_MAPPER.readValue(src, valueType); 40 | } catch (IOException e) { 41 | e.printStackTrace(); 42 | return null; 43 | } 44 | } 45 | 46 | public static T convertValue(Object fromValue, Class toValueType) { 47 | return OBJECT_MAPPER.convertValue(fromValue, toValueType); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/util/UserAgentUtils.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.util; 2 | 3 | import nl.basjes.parse.useragent.UserAgent; 4 | import nl.basjes.parse.useragent.UserAgentAnalyzer; 5 | import org.springframework.stereotype.Component; 6 | 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | /** 11 | * UserAgent解析工具类 12 | * @author Raxcl 13 | * @date 2022-01-11 12:45:47 14 | */ 15 | @Component 16 | public class UserAgentUtils { 17 | private final UserAgentAnalyzer uaa; 18 | 19 | public UserAgentUtils() { 20 | this.uaa = UserAgentAnalyzer 21 | .newBuilder() 22 | .useJava8CompatibleCaching() 23 | .hideMatcherLoadStats() 24 | .withField("OperatingSystemNameVersionMajor") 25 | .withField("AgentNameVersion") 26 | .build(); 27 | } 28 | 29 | /** 30 | * 从User-Agent解析客户端操作系统和浏览器版本 31 | * 32 | * @param userAgent userAgent 33 | * @return Map 34 | */ 35 | public Map parseOsAndBrowser(String userAgent) { 36 | UserAgent agent = uaa.parse(userAgent); 37 | String os = agent.getValue("OperatingSystemNameVersionMajor"); 38 | String browser = agent.getValue("AgentNameVersion"); 39 | Map map = new HashMap<>(16); 40 | map.put("os", os); 41 | map.put("browser", browser); 42 | return map; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/util/comment/channel/ChannelFactory.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.util.comment.channel; 2 | 3 | import cn.raxcl.constant.CommentConstants; 4 | import cn.raxcl.exception.NotFoundException; 5 | import cn.raxcl.util.common.SpringContextUtils; 6 | 7 | /** 8 | * 评论提醒方式 9 | * 10 | * @author Raxcl 11 | * @date 2022-03-15 23:47:06 12 | */ 13 | public class ChannelFactory { 14 | private ChannelFactory(){} 15 | /** 16 | * 创建评论提醒方式 17 | * 18 | * @param channelName 方式名称 19 | * @return CommentNotifyChannel 20 | */ 21 | public static CommentNotifyChannel getChannel(String channelName) { 22 | if (CommentConstants.TELEGRAM.equalsIgnoreCase(channelName)) { 23 | return SpringContextUtils.getBean("telegramChannel", CommentNotifyChannel.class); 24 | } else if (CommentConstants.MAIL.equalsIgnoreCase(channelName)) { 25 | return SpringContextUtils.getBean("mailChannel", CommentNotifyChannel.class); 26 | } 27 | throw new NotFoundException("Unsupported value in [application.properties]: [comment.notify.channel]"); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/util/comment/channel/CommentNotifyChannel.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.util.comment.channel; 2 | 3 | import cn.raxcl.enums.CommentPageEnum; 4 | import cn.raxcl.model.dto.CommentDTO; 5 | 6 | /** 7 | * 评论提醒方式 8 | * 9 | * @author Raxcl 10 | * @date 2022-03-15 23:47:06 11 | */ 12 | public interface CommentNotifyChannel { 13 | /** 14 | * 通过指定方式通知自己 15 | * 16 | * @param commentDTO 当前收到的评论 17 | */ 18 | void notifyMyself(CommentDTO commentDTO, CommentPageEnum commentPageEnum); 19 | } 20 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/util/common/Result.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.util.common; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | 8 | /** 9 | * 封装响应结果 10 | * @author Raxcl 11 | * @date 2022-01-07 18:57:54 12 | */ 13 | 14 | @NoArgsConstructor 15 | @Getter 16 | @Setter 17 | @ToString 18 | public class Result { 19 | private Integer code; 20 | private String msg; 21 | private Object data; 22 | 23 | private Result(Integer code, String msg) { 24 | this.code = code; 25 | this.msg = msg; 26 | this.data = null; 27 | } 28 | 29 | private Result(Integer code, String msg, Object data) { 30 | this.code = code; 31 | this.msg = msg; 32 | this.data = data; 33 | } 34 | 35 | public static Result success(String msg, Object data) { 36 | return new Result(200, msg, data); 37 | } 38 | 39 | public static Result success(String msg) { 40 | return new Result(200, msg); 41 | } 42 | 43 | public static Result error(String msg) { 44 | return new Result(500, msg); 45 | } 46 | 47 | public static Result error() { 48 | return new Result(500, "异常错误"); 49 | } 50 | 51 | public static Result exception(Integer code, String msg, Object data) { 52 | return new Result(code, msg, data); 53 | } 54 | 55 | public static Result exception(Integer code, String msg) { 56 | return new Result(code, msg); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/util/common/ValidatorUtils.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.util.common; 2 | 3 | import cn.raxcl.exception.NotFoundException; 4 | 5 | import javax.validation.ConstraintViolation; 6 | import javax.validation.Validation; 7 | import javax.validation.Validator; 8 | import java.util.Set; 9 | 10 | /** 11 | * 数据校验 12 | * @author Raxcl 13 | * @date 2022-01-11 10:36:19 14 | */ 15 | public class ValidatorUtils { 16 | private ValidatorUtils(){} 17 | private static final Validator VALIDATOR; 18 | 19 | static { 20 | VALIDATOR = Validation.buildDefaultValidatorFactory().getValidator(); 21 | } 22 | 23 | /** 24 | * 校验对象 25 | * 26 | * @param object 待校验对象 27 | * @param groups 待校验的组 28 | * @throws RuntimeException 校验不通过,则报BusinessException异常 29 | */ 30 | public static void validateEntity(Object object, Class... groups) throws NotFoundException { 31 | Set> constraintViolations = VALIDATOR.validate(object, groups); 32 | if (!constraintViolations.isEmpty()) { 33 | ConstraintViolation constraint = constraintViolations.iterator().next(); 34 | throw new NotFoundException(constraint.getMessage()); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/util/markdown/ext/cover/Cover.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.util.markdown.ext.cover; 2 | 3 | import org.commonmark.node.CustomNode; 4 | import org.commonmark.node.Delimited; 5 | 6 | /** 7 | * A cover node containing text and other inline nodes nodes as children. 8 | * @author Raxcl 9 | * @date 2022-03-15 12:06:38 10 | */ 11 | public class Cover extends CustomNode implements Delimited { 12 | private static final String DELIMITER = "%%"; 13 | 14 | @Override 15 | public String getOpeningDelimiter() { 16 | return DELIMITER; 17 | } 18 | 19 | @Override 20 | public String getClosingDelimiter() { 21 | return DELIMITER; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/util/markdown/ext/cover/CoverExtension.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.util.markdown.ext.cover; 2 | 3 | import org.commonmark.Extension; 4 | import org.commonmark.parser.Parser; 5 | import org.commonmark.renderer.html.HtmlRenderer; 6 | import org.commonmark.renderer.text.TextContentRenderer; 7 | import cn.raxcl.util.markdown.ext.cover.internal.CoverDelimiterProcessor; 8 | import cn.raxcl.util.markdown.ext.cover.internal.CoverHtmlNodeRenderer; 9 | import cn.raxcl.util.markdown.ext.cover.internal.CoverTextContentNodeRenderer; 10 | 11 | /** 12 | * 自定义遮盖层拓展 13 | * @author Raxcl 14 | * @date 2022-03-15 11:41:58 15 | */ 16 | public class CoverExtension implements Parser.ParserExtension, HtmlRenderer.HtmlRendererExtension, TextContentRenderer.TextContentRendererExtension { 17 | private CoverExtension() { 18 | } 19 | 20 | public static Extension create() { 21 | return new CoverExtension(); 22 | } 23 | 24 | @Override 25 | public void extend(Parser.Builder parserBuilder) { 26 | parserBuilder.customDelimiterProcessor(new CoverDelimiterProcessor()); 27 | } 28 | 29 | @Override 30 | public void extend(HtmlRenderer.Builder rendererBuilder) { 31 | rendererBuilder.nodeRendererFactory(CoverHtmlNodeRenderer::new); 32 | } 33 | 34 | @Override 35 | public void extend(TextContentRenderer.Builder rendererBuilder) { 36 | rendererBuilder.nodeRendererFactory(CoverTextContentNodeRenderer::new); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/util/markdown/ext/cover/internal/AbstractCoverNodeRenderer.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.util.markdown.ext.cover.internal; 2 | 3 | import org.commonmark.node.Node; 4 | import org.commonmark.renderer.NodeRenderer; 5 | import cn.raxcl.util.markdown.ext.cover.Cover; 6 | 7 | import java.util.Collections; 8 | import java.util.Set; 9 | 10 | abstract class AbstractCoverNodeRenderer implements NodeRenderer { 11 | @Override 12 | public Set> getNodeTypes() { 13 | return Collections.singleton(Cover.class); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/util/markdown/ext/cover/internal/CoverHtmlNodeRenderer.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.util.markdown.ext.cover.internal; 2 | 3 | import org.commonmark.node.Node; 4 | import org.commonmark.renderer.html.HtmlNodeRendererContext; 5 | import org.commonmark.renderer.html.HtmlWriter; 6 | 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | /** 11 | * HTML节点渲染 12 | * @author Raxcl 13 | * @date 2022-03-15 12:09:34 14 | */ 15 | public class CoverHtmlNodeRenderer extends AbstractCoverNodeRenderer { 16 | private final HtmlNodeRendererContext context; 17 | private final HtmlWriter html; 18 | 19 | public CoverHtmlNodeRenderer(HtmlNodeRendererContext context) { 20 | this.context = context; 21 | this.html = context.getWriter(); 22 | } 23 | 24 | @Override 25 | public void render(Node node) { 26 | Map attributes = new HashMap<>(16); 27 | attributes.put("class", "m-text-cover"); 28 | html.tag("span", context.extendAttributes(node, "span", attributes)); 29 | renderChildren(node); 30 | html.tag("/span"); 31 | } 32 | 33 | private void renderChildren(Node parent) { 34 | Node node = parent.getFirstChild(); 35 | while (node != null) { 36 | Node next = node.getNext(); 37 | context.render(node); 38 | node = next; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/util/markdown/ext/cover/internal/CoverTextContentNodeRenderer.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.util.markdown.ext.cover.internal; 2 | 3 | import org.commonmark.node.Node; 4 | import org.commonmark.renderer.text.TextContentNodeRendererContext; 5 | import org.commonmark.renderer.text.TextContentWriter; 6 | 7 | /** 8 | * 文本节点渲染 9 | * @author Raxcl 10 | * @date 2022-03-15 12:10:10 11 | */ 12 | public class CoverTextContentNodeRenderer extends AbstractCoverNodeRenderer { 13 | private final TextContentNodeRendererContext context; 14 | private final TextContentWriter textContent; 15 | 16 | public CoverTextContentNodeRenderer(TextContentNodeRendererContext context) { 17 | this.context = context; 18 | this.textContent = context.getWriter(); 19 | } 20 | 21 | @Override 22 | public void render(Node node) { 23 | textContent.write('/'); 24 | renderChildren(node); 25 | textContent.write('/'); 26 | } 27 | 28 | private void renderChildren(Node parent) { 29 | Node node = parent.getFirstChild(); 30 | while (node != null) { 31 | Node next = node.getNext(); 32 | context.render(node); 33 | node = next; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/util/markdown/ext/curtain/Curtain.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.util.markdown.ext.curtain; 2 | 3 | import org.commonmark.node.CustomNode; 4 | import org.commonmark.node.Delimited; 5 | 6 | /** 7 | * A heimu node containing text and other inline nodes nodes as children. 8 | * @author Raxcl 9 | * @date 2022-03-15 11:31:27 10 | */ 11 | public class Curtain extends CustomNode implements Delimited { 12 | private static final String DELIMITER = "@@"; 13 | 14 | @Override 15 | public String getOpeningDelimiter() { 16 | return DELIMITER; 17 | } 18 | 19 | //TODO 暂时无法解决 markdown 方法内部实现相同(怀疑是用的切面) 20 | @Override 21 | public String getClosingDelimiter() { 22 | return DELIMITER; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/util/markdown/ext/curtain/CurtainExtension.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.util.markdown.ext.curtain; 2 | 3 | import org.commonmark.Extension; 4 | import org.commonmark.parser.Parser; 5 | import org.commonmark.renderer.html.HtmlRenderer; 6 | import org.commonmark.renderer.text.TextContentRenderer; 7 | import cn.raxcl.util.markdown.ext.curtain.internal.CurtainDelimiterProcessor; 8 | import cn.raxcl.util.markdown.ext.curtain.internal.CurtainHtmlNodeRenderer; 9 | import cn.raxcl.util.markdown.ext.curtain.internal.CurtainTextContentNodeRenderer; 10 | 11 | /** 12 | * 自定义黑幕拓展 13 | * @author Raxcl 14 | * @date 2022-03-15 11:28:47 15 | */ 16 | public class CurtainExtension implements Parser.ParserExtension, HtmlRenderer.HtmlRendererExtension, TextContentRenderer.TextContentRendererExtension { 17 | private CurtainExtension() { 18 | } 19 | 20 | public static Extension create() { 21 | return new CurtainExtension(); 22 | } 23 | 24 | @Override 25 | public void extend(Parser.Builder parserBuilder) { 26 | parserBuilder.customDelimiterProcessor(new CurtainDelimiterProcessor()); 27 | } 28 | 29 | @Override 30 | public void extend(HtmlRenderer.Builder rendererBuilder) { 31 | rendererBuilder.nodeRendererFactory(CurtainHtmlNodeRenderer::new); 32 | } 33 | 34 | @Override 35 | public void extend(TextContentRenderer.Builder rendererBuilder) { 36 | rendererBuilder.nodeRendererFactory(CurtainTextContentNodeRenderer::new); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/util/markdown/ext/curtain/internal/AbstractCurtainNodeRenderer.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.util.markdown.ext.curtain.internal; 2 | 3 | import org.commonmark.node.Node; 4 | import org.commonmark.renderer.NodeRenderer; 5 | import cn.raxcl.util.markdown.ext.curtain.Curtain; 6 | 7 | import java.util.Collections; 8 | import java.util.Set; 9 | 10 | abstract class AbstractCurtainNodeRenderer implements NodeRenderer { 11 | @Override 12 | public Set> getNodeTypes() { 13 | return Collections.singleton(Curtain.class); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/util/markdown/ext/curtain/internal/CurtainHtmlNodeRenderer.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.util.markdown.ext.curtain.internal; 2 | 3 | import org.commonmark.node.Node; 4 | import org.commonmark.renderer.html.HtmlNodeRendererContext; 5 | import org.commonmark.renderer.html.HtmlWriter; 6 | 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | /** 11 | * HTML节点渲染 12 | * @author Raxcl 13 | * @date 2022-03-15 11:39:26 14 | */ 15 | public class CurtainHtmlNodeRenderer extends AbstractCurtainNodeRenderer { 16 | private final HtmlNodeRendererContext context; 17 | private final HtmlWriter html; 18 | 19 | public CurtainHtmlNodeRenderer(HtmlNodeRendererContext context) { 20 | this.context = context; 21 | this.html = context.getWriter(); 22 | } 23 | 24 | @Override 25 | public void render(Node node) { 26 | Map attributes = new HashMap<>(16); 27 | attributes.put("class", "m-text-heimu"); 28 | attributes.put("title", "你知道的太多了"); 29 | html.tag("span", context.extendAttributes(node, "span", attributes)); 30 | renderChildren(node); 31 | html.tag("/span"); 32 | } 33 | 34 | private void renderChildren(Node parent) { 35 | Node node = parent.getFirstChild(); 36 | while (node != null) { 37 | Node next = node.getNext(); 38 | context.render(node); 39 | node = next; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/util/markdown/ext/curtain/internal/CurtainTextContentNodeRenderer.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.util.markdown.ext.curtain.internal; 2 | 3 | import org.commonmark.node.Node; 4 | import org.commonmark.renderer.text.TextContentNodeRendererContext; 5 | import org.commonmark.renderer.text.TextContentWriter; 6 | 7 | /** 8 | * 文本节点渲染 9 | * @author Raxcl 10 | * @date 2022-03-15 11:41:07 11 | */ 12 | public class CurtainTextContentNodeRenderer extends AbstractCurtainNodeRenderer { 13 | private final TextContentNodeRendererContext context; 14 | private final TextContentWriter textContent; 15 | 16 | public CurtainTextContentNodeRenderer(TextContentNodeRendererContext context) { 17 | this.context = context; 18 | this.textContent = context.getWriter(); 19 | } 20 | 21 | @Override 22 | public void render(Node node) { 23 | textContent.write('/'); 24 | renderChildren(node); 25 | textContent.write('/'); 26 | } 27 | 28 | private void renderChildren(Node parent) { 29 | Node node = parent.getFirstChild(); 30 | while (node != null) { 31 | Node next = node.getNext(); 32 | context.render(node); 33 | node = next; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/util/quartz/ScheduleRunnable.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.util.quartz; 2 | 3 | import cn.raxcl.exception.NotFoundException; 4 | import org.springframework.util.ReflectionUtils; 5 | import org.springframework.util.StringUtils; 6 | import cn.raxcl.util.common.SpringContextUtils; 7 | 8 | import java.lang.reflect.Method; 9 | 10 | /** 11 | * 执行定时任务 12 | * @author Raxcl 13 | * @date 2022-01-07 19:43:01 14 | */ 15 | public class ScheduleRunnable implements Runnable { 16 | private final Object target; 17 | private final Method method; 18 | private final String params; 19 | 20 | public ScheduleRunnable(String beanName, String methodName, String params) throws NoSuchMethodException, SecurityException { 21 | this.target = SpringContextUtils.getBean(beanName); 22 | this.params = params; 23 | if (StringUtils.hasText(params)) { 24 | this.method = target.getClass().getDeclaredMethod(methodName, String.class); 25 | } else { 26 | this.method = target.getClass().getDeclaredMethod(methodName); 27 | } 28 | } 29 | 30 | @Override 31 | public void run() { 32 | try { 33 | ReflectionUtils.makeAccessible(method); 34 | if (StringUtils.hasText(params)) { 35 | method.invoke(target, params); 36 | } else { 37 | //todo 暂时无法解决:少参数提示,暂时无法解决 38 | method.invoke(target); 39 | } 40 | } catch (Exception e) { 41 | throw new NotFoundException("执行定时任务失败", e); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/util/upload/channel/ChannelFactory.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.util.upload.channel; 2 | 3 | import cn.raxcl.constant.UploadConstants; 4 | import cn.raxcl.util.common.SpringContextUtils; 5 | 6 | /** 7 | * 文件上传方式 8 | * 9 | * @author raxcl 10 | * @date 2022-03-15 23:47:06 11 | */ 12 | public class ChannelFactory { 13 | /** 14 | * 创建文件上传方式 15 | * 16 | * @param channelName 方式名称 17 | * @return FileUploadChannel 18 | */ 19 | public static FileUploadChannel getChannel(String channelName) { 20 | switch(channelName.toLowerCase()) { 21 | case UploadConstants.LOCAL: 22 | return SpringContextUtils.getBean(LocalChannel.class); 23 | case UploadConstants.GITHUB: 24 | return SpringContextUtils.getBean(GithubChannel.class); 25 | case UploadConstants.TXYUN: 26 | return SpringContextUtils.getBean(TxYunChannel.class); 27 | default: 28 | throw new RuntimeException("Unsupported value in [application.properties]: [upload.channel]"); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/util/upload/channel/FileUploadChannel.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.util.upload.channel; 2 | 3 | import cn.raxcl.util.upload.UploadUtils; 4 | 5 | /** 6 | * 文件上传方式 7 | * 8 | * @author raxcl 9 | * @date 2022-03-15 23:47:06 10 | */ 11 | public interface FileUploadChannel { 12 | /** 13 | * 通过指定方式上传文件 14 | * 15 | * @param image 需要保存的图片 16 | * @return 访问图片的URL 17 | * @throws Exception 18 | */ 19 | String upload(UploadUtils.ImageResource image) throws Exception; 20 | } 21 | -------------------------------------------------------------------------------- /blog-api/src/main/java/cn/raxcl/util/upload/channel/LocalChannel.java: -------------------------------------------------------------------------------- 1 | package cn.raxcl.util.upload.channel; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.context.annotation.Lazy; 5 | import org.springframework.stereotype.Component; 6 | import cn.raxcl.config.properties.BlogProperties; 7 | import cn.raxcl.config.properties.UploadProperties; 8 | import cn.raxcl.util.upload.UploadUtils; 9 | 10 | import java.io.File; 11 | import java.io.FileOutputStream; 12 | import java.util.UUID; 13 | 14 | /** 15 | * 本地存储方式 16 | * 17 | * @author raxcl 18 | * @date 2022-03-15 23:47:06 19 | */ 20 | @Lazy 21 | @Component 22 | public class LocalChannel implements FileUploadChannel { 23 | @Autowired 24 | private BlogProperties blogProperties; 25 | @Autowired 26 | private UploadProperties uploadProperties; 27 | 28 | /** 29 | * 将图片保存到本地,并返回访问本地图片的URL 30 | * 31 | * @param image 需要保存的图片 32 | * @return 访问图片的URL 33 | * @throws Exception 34 | */ 35 | @Override 36 | public String upload(UploadUtils.ImageResource image) throws Exception { 37 | File folder = new File(uploadProperties.getPath()); 38 | if (!folder.exists()) { 39 | folder.mkdirs(); 40 | } 41 | String fileName = UUID.randomUUID() + "." + image.getType(); 42 | FileOutputStream fileOutputStream = new FileOutputStream(uploadProperties.getPath() + fileName); 43 | fileOutputStream.write(image.getData()); 44 | fileOutputStream.close(); 45 | return blogProperties.getApi() + "/image/" + fileName; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /blog-api/src/main/resources/ipdb/ip2region.xdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raxcl/RBlog/3f0d5d0d75c3ce1c648ed4008be26e4651651038/blog-api/src/main/resources/ipdb/ip2region.xdb -------------------------------------------------------------------------------- /blog-api/src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | ${FILE_LOG_PATTERN} 12 | 13 | 14 | 15 | 16 | ${LOG_FILE}-%d{yyyy-MM-dd}-%i.log 17 | 365 18 | 19 | 20 | 10MB 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /blog-api/src/main/resources/mapper/AboutMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | update about set value=#{value} where name_en=#{nameEn} 12 | 13 | 14 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /blog-api/src/main/resources/mapper/CityVisitorMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 14 | 15 | 16 | 17 | insert into city_visitor (city, uv) values (#{city}, #{uv}) 18 | on duplicate key update 19 | uv=uv+#{uv} 20 | 21 | -------------------------------------------------------------------------------- /blog-api/src/main/resources/mapper/UserMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 13 | 14 | -------------------------------------------------------------------------------- /blog-api/src/main/resources/mapper/VisitRecordMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 19 | insert into visit_record (pv, uv, date) values (#{pv}, #{uv}, #{date}) 20 | 21 | -------------------------------------------------------------------------------- /blog-cms/.env.development: -------------------------------------------------------------------------------- 1 | NODE_ENV = production 2 | outputDir = dev 3 | VUE_APP_ENVIRONMENT = developmentEnv 4 | VUE_APP_URL = "http://localhost:8090/RBlog/admin/" -------------------------------------------------------------------------------- /blog-cms/.env.production: -------------------------------------------------------------------------------- 1 | NODE_ENV = production 2 | outputDir = dist 3 | VUE_APP_ENVIRONMENT = productionEnv 4 | VUE_APP_URL = "/RBlog/admin/" -------------------------------------------------------------------------------- /blog-cms/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | pnpm-debug.log* 14 | 15 | # Editor directories and files 16 | .idea 17 | .vscode 18 | *.suo 19 | *.ntvs* 20 | *.njsproj 21 | *.sln 22 | *.sw? 23 | -------------------------------------------------------------------------------- /blog-cms/README.md: -------------------------------------------------------------------------------- 1 | # blog-cms 2 | 3 | ## Project setup 4 | ``` 5 | npm install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | npm run serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | npm run build 16 | ``` 17 | 18 | ### Customize configuration 19 | See [Configuration Reference](https://cli.vuejs.org/config/). 20 | -------------------------------------------------------------------------------- /blog-cms/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /blog-cms/deploy.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | projectName: "blog-cms", 3 | privateKey: "C:\\Users\\Administrator\\Desktop\\secrty", 4 | passphrase: "", 5 | cluster: [], 6 | prod: { 7 | name: "生产环境", 8 | script: "yarn build", 9 | host: "42.194.225.242", 10 | port: 22, 11 | username: "root", 12 | password: "", 13 | distPath: "dist", 14 | webDir: "/mnt/raxcl/blog_admin", 15 | isRemoveRemoteFile: true, 16 | isRemoveLocalFile: true, 17 | }, 18 | }; 19 | -------------------------------------------------------------------------------- /blog-cms/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "blog-cms", 3 | "version": "2.0.0", 4 | "description": "Raxcl cms", 5 | "author": "Raxcl ", 6 | "private": true, 7 | "scripts": { 8 | "serve": "vue-cli-service serve --open", 9 | "dev": "vue-cli-service build --mode development", 10 | "build": "vue-cli-service build --mode production" 11 | }, 12 | "dependencies": { 13 | "axios": "0.24.0", 14 | "core-js": "3.6.5", 15 | "cos-js-sdk-v5": "^1.4.10", 16 | "cos-nodejs-sdk-v5": "^2.11.15", 17 | "echarts": "4.9.0", 18 | "element-ui": "2.13.2", 19 | "font-awesome": "^4.7.0", 20 | "jinrishici": "^1.0.6", 21 | "lodash": "4.17.19", 22 | "mavon-editor": "2.9.1", 23 | "moment": "2.27.0", 24 | "normalize.css": "7.0.0", 25 | "nprogress": "0.2.0", 26 | "v-viewer": "1.5.1", 27 | "vue": "2.6.11", 28 | "vue-router": "3.3.4", 29 | "vuex": "3.5.1" 30 | }, 31 | "devDependencies": { 32 | "@vue/cli-plugin-babel": "4.5.0", 33 | "@vue/cli-plugin-router": "4.5.0", 34 | "@vue/cli-plugin-vuex": "4.5.0", 35 | "@vue/cli-service": "4.5.0", 36 | "sass": "1.26.8", 37 | "sass-loader": "8.0.2", 38 | "svg-sprite-loader": "4.1.3", 39 | "svgo": "1.2.2", 40 | "vue-template-compiler": "2.6.11" 41 | }, 42 | "browserslist": [ 43 | "> 1%", 44 | "last 2 versions", 45 | "not dead" 46 | ] 47 | } 48 | -------------------------------------------------------------------------------- /blog-cms/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raxcl/RBlog/3f0d5d0d75c3ce1c648ed4008be26e4651651038/blog-cms/public/favicon.ico -------------------------------------------------------------------------------- /blog-cms/public/img/avatar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raxcl/RBlog/3f0d5d0d75c3ce1c648ed4008be26e4651651038/blog-cms/public/img/avatar.jpg -------------------------------------------------------------------------------- /blog-cms/public/img/comment-avatar/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raxcl/RBlog/3f0d5d0d75c3ce1c648ed4008be26e4651651038/blog-cms/public/img/comment-avatar/1.jpg -------------------------------------------------------------------------------- /blog-cms/public/img/comment-avatar/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raxcl/RBlog/3f0d5d0d75c3ce1c648ed4008be26e4651651038/blog-cms/public/img/comment-avatar/2.jpg -------------------------------------------------------------------------------- /blog-cms/public/img/comment-avatar/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raxcl/RBlog/3f0d5d0d75c3ce1c648ed4008be26e4651651038/blog-cms/public/img/comment-avatar/3.jpg -------------------------------------------------------------------------------- /blog-cms/public/img/comment-avatar/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raxcl/RBlog/3f0d5d0d75c3ce1c648ed4008be26e4651651038/blog-cms/public/img/comment-avatar/4.jpg -------------------------------------------------------------------------------- /blog-cms/public/img/comment-avatar/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raxcl/RBlog/3f0d5d0d75c3ce1c648ed4008be26e4651651038/blog-cms/public/img/comment-avatar/5.jpg -------------------------------------------------------------------------------- /blog-cms/public/img/comment-avatar/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raxcl/RBlog/3f0d5d0d75c3ce1c648ed4008be26e4651651038/blog-cms/public/img/comment-avatar/6.jpg -------------------------------------------------------------------------------- /blog-cms/public/img/visitor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raxcl/RBlog/3f0d5d0d75c3ce1c648ed4008be26e4651651038/blog-cms/public/img/visitor.jpg -------------------------------------------------------------------------------- /blog-cms/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 后台管理 - RaxclBlog 9 | 10 | 11 | 12 | 15 |
16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /blog-cms/src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 19 | -------------------------------------------------------------------------------- /blog-cms/src/api/ExceptionLog.js: -------------------------------------------------------------------------------- 1 | import axios from '@/util/request' 2 | 3 | export function getExceptionLogList(queryInfo) { 4 | return axios({ 5 | url: 'exceptionLogs', 6 | method: 'GET', 7 | params: { 8 | ...queryInfo 9 | } 10 | }) 11 | } 12 | 13 | export function deleteExceptionLogById(id) { 14 | return axios({ 15 | url: 'exceptionLog', 16 | method: 'DELETE', 17 | params: { 18 | id 19 | } 20 | }) 21 | } -------------------------------------------------------------------------------- /blog-cms/src/api/about.js: -------------------------------------------------------------------------------- 1 | import axios from '@/util/request' 2 | 3 | export function getAbout() { 4 | return axios({ 5 | url: 'about', 6 | method: 'GET' 7 | }) 8 | } 9 | 10 | export function updateAbout(form) { 11 | return axios({ 12 | url: 'about', 13 | method: 'PUT', 14 | data: { 15 | ...form 16 | } 17 | }) 18 | } -------------------------------------------------------------------------------- /blog-cms/src/api/category.js: -------------------------------------------------------------------------------- 1 | import axios from '@/util/request' 2 | 3 | export function getData(queryInfo) { 4 | return axios({ 5 | url: 'categories', 6 | method: 'GET', 7 | params: { 8 | ...queryInfo 9 | } 10 | }) 11 | } 12 | 13 | export function addCategory(form) { 14 | return axios({ 15 | url: 'category', 16 | method: 'POST', 17 | data: { 18 | ...form 19 | } 20 | }) 21 | } 22 | 23 | export function editCategory(form) { 24 | return axios({ 25 | url: 'category', 26 | method: 'PUT', 27 | data: { 28 | ...form 29 | } 30 | }) 31 | } 32 | 33 | export function deleteCategoryById(id) { 34 | return axios({ 35 | url: 'category', 36 | method: 'DELETE', 37 | params: { 38 | id 39 | } 40 | }) 41 | } -------------------------------------------------------------------------------- /blog-cms/src/api/comment.js: -------------------------------------------------------------------------------- 1 | import axios from '@/util/request' 2 | 3 | export function getCommentListByQuery(queryInfo) { 4 | return axios({ 5 | url: 'comments', 6 | method: 'GET', 7 | params: { 8 | ...queryInfo 9 | } 10 | }) 11 | } 12 | 13 | export function getBlogList() { 14 | return axios({ 15 | url: 'blogIdAndTitle', 16 | method: 'GET' 17 | }) 18 | } 19 | 20 | export function updatePublished(id, published) { 21 | return axios({ 22 | url: 'comment/published', 23 | method: 'PUT', 24 | params: { 25 | id, 26 | published 27 | } 28 | }) 29 | } 30 | 31 | export function updateNotice(id, notice) { 32 | return axios({ 33 | url: 'comment/notice', 34 | method: 'PUT', 35 | params: { 36 | id, 37 | notice 38 | } 39 | }) 40 | } 41 | 42 | export function deleteCommentById(id) { 43 | return axios({ 44 | url: 'comment', 45 | method: 'DELETE', 46 | params: { 47 | id 48 | } 49 | }) 50 | } 51 | 52 | export function editComment(form) { 53 | return axios({ 54 | url: 'comment', 55 | method: 'PUT', 56 | data: { 57 | ...form 58 | } 59 | }) 60 | } -------------------------------------------------------------------------------- /blog-cms/src/api/dashboard.js: -------------------------------------------------------------------------------- 1 | import axios from '@/util/request' 2 | 3 | export function getDashboard() { 4 | return axios({ 5 | url: 'dashboard', 6 | method: 'GET' 7 | }) 8 | } -------------------------------------------------------------------------------- /blog-cms/src/api/friend.js: -------------------------------------------------------------------------------- 1 | import axios from '@/util/request' 2 | 3 | export function getFriendsByQuery(queryInfo) { 4 | return axios({ 5 | url: 'friends', 6 | method: 'GET', 7 | params: { 8 | ...queryInfo 9 | } 10 | }) 11 | } 12 | 13 | export function updatePublished(id, published) { 14 | return axios({ 15 | url: 'friend/published', 16 | method: 'PUT', 17 | params: { 18 | id, 19 | published 20 | } 21 | }) 22 | } 23 | 24 | export function saveFriend(form) { 25 | return axios({ 26 | url: 'friend', 27 | method: 'POST', 28 | data: { 29 | ...form 30 | } 31 | }) 32 | } 33 | 34 | export function updateFriend(form) { 35 | return axios({ 36 | url: 'friend', 37 | method: 'PUT', 38 | data: { 39 | ...form 40 | } 41 | }) 42 | } 43 | 44 | export function deleteFriendById(id) { 45 | return axios({ 46 | url: 'friend', 47 | method: 'DELETE', 48 | params: { 49 | id 50 | } 51 | }) 52 | } 53 | 54 | export function getFriendInfo() { 55 | return axios({ 56 | url: 'friendInfo', 57 | method: 'GET' 58 | }) 59 | } 60 | 61 | export function updateCommentEnabled(commentEnabled) { 62 | return axios({ 63 | url: 'friendInfo/commentEnabled', 64 | method: 'PUT', 65 | params: { 66 | commentEnabled 67 | } 68 | }) 69 | } 70 | 71 | export function updateContent(content) { 72 | return axios({ 73 | url: 'friendInfo/content', 74 | method: 'PUT', 75 | data: { 76 | content 77 | } 78 | }) 79 | } -------------------------------------------------------------------------------- /blog-cms/src/api/login.js: -------------------------------------------------------------------------------- 1 | import axios from '@/util/request' 2 | 3 | export function login(loginForm) { 4 | return axios({ 5 | url: 'login', 6 | method: 'POST', 7 | data: { 8 | ...loginForm 9 | } 10 | }) 11 | } 12 | -------------------------------------------------------------------------------- /blog-cms/src/api/loginLog.js: -------------------------------------------------------------------------------- 1 | import axios from '@/util/request' 2 | 3 | export function getLoginLogList(queryInfo) { 4 | return axios({ 5 | url: 'loginLogs', 6 | method: 'GET', 7 | params: { 8 | ...queryInfo 9 | } 10 | }) 11 | } 12 | 13 | export function deleteLoginLogById(id) { 14 | return axios({ 15 | url: 'loginLog', 16 | method: 'DELETE', 17 | params: { 18 | id 19 | } 20 | }) 21 | } -------------------------------------------------------------------------------- /blog-cms/src/api/moment.js: -------------------------------------------------------------------------------- 1 | import axios from '@/util/request' 2 | 3 | export function getMomentListByQuery(queryInfo) { 4 | return axios({ 5 | url: 'moments', 6 | method: 'GET', 7 | params: { 8 | ...queryInfo 9 | } 10 | }) 11 | } 12 | 13 | export function updatePublished(id, published) { 14 | return axios({ 15 | url: 'moment/published', 16 | method: 'PUT', 17 | params: { 18 | id, 19 | published 20 | } 21 | }) 22 | } 23 | 24 | export function getMomentById(id) { 25 | return axios({ 26 | url: 'moment', 27 | method: 'GET', 28 | params: { 29 | id 30 | } 31 | }) 32 | } 33 | 34 | export function deleteMomentById(id) { 35 | return axios({ 36 | url: 'moment', 37 | method: 'DELETE', 38 | params: { 39 | id 40 | } 41 | }) 42 | } 43 | 44 | export function saveMoment(moment) { 45 | return axios({ 46 | url: 'moment', 47 | method: 'POST', 48 | data: { 49 | ...moment 50 | } 51 | }) 52 | } 53 | 54 | export function updateMoment(moment) { 55 | return axios({ 56 | url: 'moment', 57 | method: 'PUT', 58 | data: { 59 | ...moment 60 | } 61 | }) 62 | } -------------------------------------------------------------------------------- /blog-cms/src/api/operationLog.js: -------------------------------------------------------------------------------- 1 | import axios from '@/util/request' 2 | 3 | export function getOperationLogList(queryInfo) { 4 | return axios({ 5 | url: 'operationLogs', 6 | method: 'GET', 7 | params: { 8 | ...queryInfo 9 | } 10 | }) 11 | } 12 | 13 | export function deleteOperationLogById(id) { 14 | return axios({ 15 | url: 'operationLog', 16 | method: 'DELETE', 17 | params: { 18 | id 19 | } 20 | }) 21 | } -------------------------------------------------------------------------------- /blog-cms/src/api/schedule.js: -------------------------------------------------------------------------------- 1 | import axios from '@/util/request' 2 | 3 | export function getJobList(queryInfo) { 4 | return axios({ 5 | url: 'jobs', 6 | method: 'GET', 7 | params: { 8 | ...queryInfo 9 | } 10 | }) 11 | } 12 | 13 | export function updateJobStatus(jobId, status) { 14 | return axios({ 15 | url: 'job/status', 16 | method: 'PUT', 17 | params: { 18 | jobId, 19 | status 20 | } 21 | }) 22 | } 23 | 24 | export function runJobOnce(jobId) { 25 | return axios({ 26 | url: 'job/run', 27 | method: 'POST', 28 | params: { 29 | jobId 30 | } 31 | }) 32 | } 33 | 34 | export function deleteJobById(jobId) { 35 | return axios({ 36 | url: 'job', 37 | method: 'DELETE', 38 | params: { 39 | jobId 40 | } 41 | }) 42 | } 43 | 44 | export function addJob(job) { 45 | return axios({ 46 | url: 'job', 47 | method: 'POST', 48 | data: { 49 | ...job 50 | } 51 | }) 52 | } 53 | 54 | export function editJob(job) { 55 | return axios({ 56 | url: 'job', 57 | method: 'PUT', 58 | data: { 59 | ...job 60 | } 61 | }) 62 | } 63 | 64 | export function getJobLogList(queryInfo) { 65 | return axios({ 66 | url: 'job/logs', 67 | method: 'GET', 68 | params: { 69 | ...queryInfo 70 | } 71 | }) 72 | } 73 | 74 | export function deleteJobLogByLogId(logId) { 75 | return axios({ 76 | url: 'job/log', 77 | method: 'DELETE', 78 | params: { 79 | logId 80 | } 81 | }) 82 | } -------------------------------------------------------------------------------- /blog-cms/src/api/siteSetting.js: -------------------------------------------------------------------------------- 1 | import axios from '@/util/request' 2 | 3 | export function getSiteSettingData() { 4 | return axios({ 5 | url: 'siteSettings', 6 | method: 'GET' 7 | }) 8 | } 9 | 10 | export function update(settings, deleteIds) { 11 | return axios({ 12 | url: 'siteSettings', 13 | method: 'POST', 14 | data: { 15 | settings, 16 | deleteIds 17 | } 18 | }) 19 | } 20 | 21 | export function getWebTitleSuffix() { 22 | return axios({ 23 | url: 'webTitleSuffix', 24 | method: 'GET' 25 | }) 26 | } -------------------------------------------------------------------------------- /blog-cms/src/api/tag.js: -------------------------------------------------------------------------------- 1 | import axios from '@/util/request' 2 | 3 | export function getData(queryInfo) { 4 | return axios({ 5 | url: 'tags', 6 | method: 'GET', 7 | params: { 8 | ...queryInfo 9 | } 10 | }) 11 | } 12 | 13 | export function addTag(form) { 14 | return axios({ 15 | url: 'tag', 16 | method: 'POST', 17 | data: { 18 | ...form 19 | } 20 | }) 21 | } 22 | 23 | export function editTag(form) { 24 | return axios({ 25 | url: 'tag', 26 | method: 'PUT', 27 | data: { 28 | ...form 29 | } 30 | }) 31 | } 32 | 33 | export function deleteTagById(id) { 34 | return axios({ 35 | url: 'tag', 36 | method: 'DELETE', 37 | params: { 38 | id 39 | } 40 | }) 41 | } -------------------------------------------------------------------------------- /blog-cms/src/api/visitLog.js: -------------------------------------------------------------------------------- 1 | import axios from '@/util/request' 2 | 3 | export function getVisitLogList(queryInfo) { 4 | return axios({ 5 | url: 'visitLogs', 6 | method: 'GET', 7 | params: { 8 | ...queryInfo 9 | } 10 | }) 11 | } 12 | 13 | export function deleteVisitLogById(id) { 14 | return axios({ 15 | url: 'visitLog', 16 | method: 'DELETE', 17 | params: { 18 | id 19 | } 20 | }) 21 | } -------------------------------------------------------------------------------- /blog-cms/src/api/visitor.js: -------------------------------------------------------------------------------- 1 | import axios from '@/util/request' 2 | 3 | export function getVisitorList(queryInfo) { 4 | return axios({ 5 | url: 'visitors', 6 | method: 'GET', 7 | params: { 8 | ...queryInfo 9 | } 10 | }) 11 | } 12 | 13 | export function deleteVisitor(id, uuid) { 14 | return axios({ 15 | url: 'visitor', 16 | method: 'DELETE', 17 | params: { 18 | id, 19 | uuid 20 | } 21 | }) 22 | } -------------------------------------------------------------------------------- /blog-cms/src/assets/404_images/404.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raxcl/RBlog/3f0d5d0d75c3ce1c648ed4008be26e4651651038/blog-cms/src/assets/404_images/404.png -------------------------------------------------------------------------------- /blog-cms/src/assets/404_images/404_cloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raxcl/RBlog/3f0d5d0d75c3ce1c648ed4008be26e4651651038/blog-cms/src/assets/404_images/404_cloud.png -------------------------------------------------------------------------------- /blog-cms/src/assets/styles/element-ui.scss: -------------------------------------------------------------------------------- 1 | // cover some element-ui styles 2 | 3 | .el-breadcrumb__inner, 4 | .el-breadcrumb__inner a { 5 | font-weight: 400 !important; 6 | } 7 | 8 | .el-upload { 9 | input[type="file"] { 10 | display: none !important; 11 | } 12 | } 13 | 14 | .el-upload__input { 15 | display: none; 16 | } 17 | 18 | 19 | // to fixed https://github.com/ElemeFE/element/issues/2461 20 | .el-dialog { 21 | transform: none; 22 | left: 0; 23 | position: relative; 24 | margin: 0 auto; 25 | } 26 | 27 | // refine element ui upload 28 | .upload-container { 29 | .el-upload { 30 | width: 100%; 31 | 32 | .el-upload-dragger { 33 | width: 100%; 34 | height: 200px; 35 | } 36 | } 37 | } 38 | 39 | // dropdown 40 | .el-dropdown-menu { 41 | a { 42 | display: block 43 | } 44 | } 45 | 46 | // to fix el-date-picker css style 47 | .el-range-separator { 48 | box-sizing: content-box; 49 | } 50 | -------------------------------------------------------------------------------- /blog-cms/src/assets/styles/index.scss: -------------------------------------------------------------------------------- 1 | @import './variables'; 2 | @import './mixin'; 3 | @import './transition'; 4 | @import './element-ui'; 5 | @import './sidebar'; 6 | @import './base.css'; 7 | 8 | body { 9 | height: 100%; 10 | -moz-osx-font-smoothing: grayscale; 11 | -webkit-font-smoothing: antialiased; 12 | text-rendering: optimizeLegibility; 13 | font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; 14 | } 15 | 16 | label { 17 | font-weight: 700; 18 | } 19 | 20 | html { 21 | height: 100%; 22 | box-sizing: border-box; 23 | } 24 | 25 | #app { 26 | height: 100%; 27 | } 28 | 29 | *, 30 | *:before, 31 | *:after { 32 | box-sizing: inherit; 33 | } 34 | 35 | a:focus, 36 | a:active { 37 | outline: none; 38 | } 39 | 40 | a, 41 | a:focus, 42 | a:hover { 43 | cursor: pointer; 44 | color: inherit; 45 | text-decoration: none; 46 | } 47 | 48 | div:focus { 49 | outline: none; 50 | } 51 | 52 | .clearfix { 53 | &:after { 54 | visibility: hidden; 55 | display: block; 56 | font-size: 0; 57 | content: " "; 58 | clear: both; 59 | height: 0; 60 | } 61 | } 62 | 63 | // main-container global css 64 | .app-container { 65 | padding: 20px; 66 | } 67 | -------------------------------------------------------------------------------- /blog-cms/src/assets/styles/mixin.scss: -------------------------------------------------------------------------------- 1 | @mixin clearfix { 2 | &:after { 3 | content: ""; 4 | display: table; 5 | clear: both; 6 | } 7 | } 8 | 9 | @mixin scrollBar { 10 | &::-webkit-scrollbar-track-piece { 11 | background: #d3dce6; 12 | } 13 | 14 | &::-webkit-scrollbar { 15 | width: 6px; 16 | } 17 | 18 | &::-webkit-scrollbar-thumb { 19 | background: #99a9bf; 20 | border-radius: 20px; 21 | } 22 | } 23 | 24 | @mixin relative { 25 | position: relative; 26 | width: 100%; 27 | height: 100%; 28 | } 29 | -------------------------------------------------------------------------------- /blog-cms/src/assets/styles/transition.scss: -------------------------------------------------------------------------------- 1 | // global transition css 2 | 3 | /* fade */ 4 | .fade-enter-active, 5 | .fade-leave-active { 6 | transition: opacity 0.28s; 7 | } 8 | 9 | .fade-enter, 10 | .fade-leave-active { 11 | opacity: 0; 12 | } 13 | 14 | /* fade-transform */ 15 | .fade-transform-leave-active, 16 | .fade-transform-enter-active { 17 | transition: all .25s; 18 | } 19 | 20 | .fade-transform-enter { 21 | opacity: 0; 22 | transform: translateX(-10px); 23 | } 24 | 25 | .fade-transform-leave-to { 26 | opacity: 0; 27 | transform: translateX(10px); 28 | } 29 | 30 | /* breadcrumb transition */ 31 | .breadcrumb-enter-active, 32 | .breadcrumb-leave-active { 33 | transition: all .25s; 34 | } 35 | 36 | .breadcrumb-enter, 37 | .breadcrumb-leave-active { 38 | opacity: 0; 39 | transform: translateX(20px); 40 | } 41 | 42 | .breadcrumb-move { 43 | transition: all .5s; 44 | } 45 | 46 | .breadcrumb-leave-active { 47 | position: absolute; 48 | } 49 | -------------------------------------------------------------------------------- /blog-cms/src/assets/styles/variables.scss: -------------------------------------------------------------------------------- 1 | // sidebar 2 | $menuText:#bfcbd9; 3 | $menuActiveText:#409EFF; 4 | $subMenuActiveText:#f4f4f5; //https://github.com/ElemeFE/element/issues/12951 5 | 6 | $menuBg:#304156; 7 | $menuHover:#263445; 8 | 9 | $subMenuBg:#1f2d3d; 10 | $subMenuHover:#001528; 11 | 12 | $sideBarWidth: 190px; 13 | 14 | // the :export directive is the magic sauce for webpack 15 | // https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass 16 | :export { 17 | menuText: $menuText; 18 | menuActiveText: $menuActiveText; 19 | subMenuActiveText: $subMenuActiveText; 20 | menuBg: $menuBg; 21 | menuHover: $menuHover; 22 | subMenuBg: $subMenuBg; 23 | subMenuHover: $subMenuHover; 24 | sideBarWidth: $sideBarWidth; 25 | } 26 | -------------------------------------------------------------------------------- /blog-cms/src/common/font/dsc.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raxcl/RBlog/3f0d5d0d75c3ce1c648ed4008be26e4651651038/blog-cms/src/common/font/dsc.ttf -------------------------------------------------------------------------------- /blog-cms/src/common/font/font.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "Delius Swash Caps"; 3 | src: url('dsc.ttf'); 4 | font-weight: normal; 5 | font-style: normal; 6 | } -------------------------------------------------------------------------------- /blog-cms/src/components/Hamburger/index.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 32 | 33 | 45 | -------------------------------------------------------------------------------- /blog-cms/src/icons/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import SvgIcon from '@/components/SvgIcon'// svg component 3 | 4 | // register globally 5 | Vue.component('svg-icon', SvgIcon) 6 | 7 | const req = require.context('./svg', false, /\.svg$/) 8 | const requireAll = requireContext => requireContext.keys().map(requireContext) 9 | requireAll(req) 10 | -------------------------------------------------------------------------------- /blog-cms/src/icons/svg/article.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /blog-cms/src/icons/svg/eye-open.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /blog-cms/src/icons/svg/eye.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /blog-cms/src/icons/svg/logout.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /blog-cms/src/icons/svg/markdown.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /blog-cms/src/icons/svg/password.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /blog-cms/src/icons/svg/pinglun-blue.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /blog-cms/src/icons/svg/user.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /blog-cms/src/icons/svgo.yml: -------------------------------------------------------------------------------- 1 | # replace default config 2 | 3 | # multipass: true 4 | # full: true 5 | 6 | plugins: 7 | 8 | # - name 9 | # 10 | # or: 11 | # - name: false 12 | # - name: true 13 | # 14 | # or: 15 | # - name: 16 | # param1: 1 17 | # param2: 2 18 | 19 | - removeAttrs: 20 | attrs: 21 | - 'fill' 22 | - 'fill-rule' 23 | -------------------------------------------------------------------------------- /blog-cms/src/layout/components/AppMain.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 19 | 20 | 34 | 35 | 43 | -------------------------------------------------------------------------------- /blog-cms/src/layout/components/Sidebar/FixiOSBug.js: -------------------------------------------------------------------------------- 1 | export default { 2 | computed: { 3 | device() { 4 | return this.$store.state.app.device 5 | } 6 | }, 7 | mounted() { 8 | // In order to fix the click on menu on the ios device will trigger the mouseleave bug 9 | // https://github.com/PanJiaChen/vue-element-admin/issues/1135 10 | this.fixBugIniOS() 11 | }, 12 | methods: { 13 | fixBugIniOS() { 14 | const $subMenu = this.$refs.subMenu 15 | if ($subMenu) { 16 | const handleMouseleave = $subMenu.handleMouseleave 17 | $subMenu.handleMouseleave = (e) => { 18 | if (this.device === 'mobile') { 19 | return 20 | } 21 | handleMouseleave(e) 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /blog-cms/src/layout/components/Sidebar/Item.vue: -------------------------------------------------------------------------------- 1 | 34 | 35 | 42 | -------------------------------------------------------------------------------- /blog-cms/src/layout/components/Sidebar/Link.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 44 | -------------------------------------------------------------------------------- /blog-cms/src/layout/components/index.js: -------------------------------------------------------------------------------- 1 | export { default as Navbar } from './Navbar' 2 | export { default as Sidebar } from './Sidebar' 3 | export { default as AppMain } from './AppMain' 4 | -------------------------------------------------------------------------------- /blog-cms/src/layout/mixin/ResizeHandler.js: -------------------------------------------------------------------------------- 1 | import store from '@/store' 2 | 3 | const { body } = document 4 | const WIDTH = 992 // refer to Bootstrap's responsive design 5 | 6 | export default { 7 | watch: { 8 | $route(route) { 9 | if (this.device === 'mobile' && this.sidebar.opened) { 10 | store.dispatch('app/closeSideBar', { withoutAnimation: false }) 11 | } 12 | } 13 | }, 14 | beforeMount() { 15 | window.addEventListener('resize', this.$_resizeHandler) 16 | }, 17 | beforeDestroy() { 18 | window.removeEventListener('resize', this.$_resizeHandler) 19 | }, 20 | mounted() { 21 | const isMobile = this.$_isMobile() 22 | if (isMobile) { 23 | store.dispatch('app/toggleDevice', 'mobile') 24 | store.dispatch('app/closeSideBar', { withoutAnimation: true }) 25 | } 26 | }, 27 | methods: { 28 | // use $_ for mixins properties 29 | // https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential 30 | $_isMobile() { 31 | const rect = body.getBoundingClientRect() 32 | return rect.width - 1 < WIDTH 33 | }, 34 | $_resizeHandler() { 35 | if (!document.hidden) { 36 | const isMobile = this.$_isMobile() 37 | store.dispatch('app/toggleDevice', isMobile ? 'mobile' : 'desktop') 38 | 39 | if (isMobile) { 40 | store.dispatch('app/closeSideBar', { withoutAnimation: true }) 41 | } 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /blog-cms/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import router from './router' 4 | import store from './store' 5 | 6 | //normalize.css 7 | import 'normalize.css/normalize.css' // A modern alternative to CSS resets 8 | //element-ui 9 | import Element from 'element-ui' 10 | import 'element-ui/lib/theme-chalk/index.css' 11 | //global css 12 | import '@/assets/styles/index.scss' 13 | //icon 14 | import '@/icons' 15 | 16 | //moment 17 | import './util/dateTimeFormatUtils.js' 18 | //mavonEditor 19 | import mavonEditor from 'mavon-editor' 20 | import 'mavon-editor/dist/css/index.css' 21 | //v-viewer 22 | import 'viewerjs/dist/viewer.css' 23 | import Viewer from 'v-viewer' 24 | // directive 25 | import './util/directive' 26 | 27 | Vue.use(mavonEditor) 28 | Vue.use(Element) 29 | Vue.use(Viewer) 30 | 31 | Vue.prototype.msgSuccess = function (msg) { 32 | this.$message.success(msg) 33 | } 34 | 35 | Vue.prototype.msgError = function (msg) { 36 | this.$message.error(msg) 37 | } 38 | 39 | Vue.config.productionTip = false 40 | 41 | new Vue({ 42 | router, 43 | store, 44 | render: h => h(App) 45 | }).$mount('#app') -------------------------------------------------------------------------------- /blog-cms/src/settings.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | /** 3 | * @type {string} 4 | * @description page title 5 | */ 6 | title: 'RBlog Admin', 7 | 8 | /** 9 | * @type {string} 10 | * @description logo URL 11 | */ 12 | logo: 'https://cdn.raxcl.cn/blog-resource/RBlogApp/img/favicon.ico', 13 | 14 | /** 15 | * @type {boolean} true | false 16 | * @description Whether fix the header 17 | */ 18 | fixedHeader: true, 19 | 20 | /** 21 | * @type {boolean} true | false 22 | * @description Whether show the logo in sidebar 23 | */ 24 | sidebarLogo: true, 25 | 26 | /** 27 | * @type {Array} 28 | * @description 默认展开的父级菜单 29 | */ 30 | defaultOpeneds: ['/blog', '/page', '/pictureHosting', '/system', '/log', '/statistics'] 31 | } -------------------------------------------------------------------------------- /blog-cms/src/store/getters.js: -------------------------------------------------------------------------------- 1 | const getters = { 2 | sidebar: state => state.app.sidebar, 3 | device: state => state.app.device, 4 | } 5 | export default getters 6 | -------------------------------------------------------------------------------- /blog-cms/src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import getters from './getters' 4 | import app from './modules/app' 5 | import settings from './modules/settings' 6 | 7 | Vue.use(Vuex) 8 | 9 | export default new Vuex.Store({ 10 | modules: { 11 | app, 12 | settings, 13 | }, 14 | getters 15 | }) 16 | -------------------------------------------------------------------------------- /blog-cms/src/store/modules/app.js: -------------------------------------------------------------------------------- 1 | const state = { 2 | sidebar: { 3 | opened: true, 4 | withoutAnimation: false 5 | }, 6 | device: 'desktop' 7 | } 8 | 9 | const mutations = { 10 | TOGGLE_SIDEBAR: state => { 11 | state.sidebar.opened = !state.sidebar.opened 12 | state.sidebar.withoutAnimation = false 13 | }, 14 | CLOSE_SIDEBAR: (state, withoutAnimation) => { 15 | state.sidebar.opened = false 16 | state.sidebar.withoutAnimation = withoutAnimation 17 | }, 18 | TOGGLE_DEVICE: (state, device) => { 19 | state.device = device 20 | } 21 | } 22 | 23 | const actions = { 24 | toggleSideBar({ commit }) { 25 | commit('TOGGLE_SIDEBAR') 26 | }, 27 | closeSideBar({ commit }, { withoutAnimation }) { 28 | commit('CLOSE_SIDEBAR', withoutAnimation) 29 | }, 30 | toggleDevice({ commit }, device) { 31 | commit('TOGGLE_DEVICE', device) 32 | } 33 | } 34 | 35 | export default { 36 | namespaced: true, 37 | state, 38 | mutations, 39 | actions 40 | } 41 | -------------------------------------------------------------------------------- /blog-cms/src/store/modules/settings.js: -------------------------------------------------------------------------------- 1 | import defaultSettings from '@/settings' 2 | 3 | const {title, logo, fixedHeader, sidebarLogo, defaultOpeneds} = defaultSettings 4 | 5 | const state = { 6 | title: title, 7 | logo: logo, 8 | fixedHeader: fixedHeader, 9 | sidebarLogo: sidebarLogo, 10 | defaultOpeneds: defaultOpeneds, 11 | } 12 | 13 | const mutations = { 14 | CHANGE_SETTING: (state, {key, value}) => { 15 | // eslint-disable-next-line no-prototype-builtins 16 | if (state.hasOwnProperty(key)) { 17 | state[key] = value 18 | } 19 | } 20 | } 21 | 22 | const actions = { 23 | changeSetting({commit}, data) { 24 | commit('CHANGE_SETTING', data) 25 | } 26 | } 27 | 28 | export default { 29 | namespaced: true, 30 | state, 31 | mutations, 32 | actions 33 | } 34 | 35 | -------------------------------------------------------------------------------- /blog-cms/src/util/copy.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 通过生成DOM节点来复制内容至剪贴板 3 | * @param {string} 需要复制的内容 4 | */ 5 | export function copy(copyCont) { 6 | let oInput = document.createElement('input') 7 | oInput.value = copyCont 8 | document.body.appendChild(oInput) 9 | oInput.select() 10 | document.execCommand('Copy') 11 | oInput.remove() 12 | } -------------------------------------------------------------------------------- /blog-cms/src/util/dateTimeFormatUtils.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import moment from 'moment' 3 | 4 | Vue.filter('dateFormat', function (value, format = 'YYYY-MM-DD HH:mm:ss') { 5 | return moment(value).format(format) 6 | }) -------------------------------------------------------------------------------- /blog-cms/src/util/directive.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | /** 4 | * 防抖 单位时间只触发最后一次 5 | * 例:刷新 6 | * 简写:刷新 7 | */ 8 | Vue.directive('debounce', { 9 | inserted: function (el, binding) { 10 | let [fn, event = "click", time = 300] = binding.value 11 | let timer 12 | el.addEventListener(event, () => { 13 | timer && clearTimeout(timer) 14 | timer = setTimeout(() => fn(), time) 15 | }) 16 | } 17 | }) 18 | 19 | /** 20 | * 节流 每单位时间可触发一次 21 | * 例:刷新 22 | * 传递参数:刷新 23 | */ 24 | Vue.directive('throttle', { 25 | inserted: function (el, binding) { 26 | let [fn, event = "click", time = 300] = binding.value 27 | let now, preTime 28 | el.addEventListener(event, () => { 29 | now = new Date() 30 | if (!preTime || now - preTime > time) { 31 | preTime = now 32 | fn() 33 | } 34 | }) 35 | } 36 | }) 37 | -------------------------------------------------------------------------------- /blog-cms/src/util/get-page-title.js: -------------------------------------------------------------------------------- 1 | import defaultSettings from '@/settings' 2 | 3 | const title = defaultSettings.title 4 | 5 | export default function getPageTitle(pageTitle) { 6 | if (pageTitle) { 7 | return `${pageTitle} - ${title}` 8 | } 9 | return `${title}` 10 | } 11 | -------------------------------------------------------------------------------- /blog-cms/src/util/request.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import NProgress from 'nprogress' 3 | import 'nprogress/nprogress.css' 4 | import {Message} from 'element-ui' 5 | 6 | const request = axios.create({ 7 | // baseURL: 'http://localhost:8090/admin/', 8 | baseURL: process.env.VUE_APP_URL, 9 | timeout: 10000 10 | }) 11 | 12 | let CancelToken = axios.CancelToken 13 | 14 | // 请求拦截 15 | request.interceptors.request.use(config => { 16 | //对于访客模式,除GET请求外,都拦截并提示 17 | const userJson = window.localStorage.getItem('user') || '{}' 18 | const user = JSON.parse(userJson) 19 | if (userJson !== '{}' && user.role !== 'ROLE_admin' && config.method !== 'get') { 20 | config.cancelToken = new CancelToken(function executor(cancel) { 21 | cancel('演示模式,不允许操作') 22 | }) 23 | return config 24 | } 25 | 26 | NProgress.start() 27 | const token = window.localStorage.getItem('token') 28 | if (token) { 29 | config.headers.Authorization = token 30 | } 31 | return config 32 | }, 33 | error => { 34 | console.info(error) 35 | return Promise.reject(error) 36 | } 37 | ) 38 | 39 | // 响应拦截 40 | request.interceptors.response.use(response => { 41 | NProgress.done() 42 | const res = response.data 43 | if (res.code !== 200) { 44 | Message.error(res.msg || 'Error') 45 | } 46 | return res 47 | }, 48 | error => { 49 | console.info(error) 50 | Message.error(error.message) 51 | return Promise.reject(error) 52 | } 53 | ) 54 | 55 | export default request -------------------------------------------------------------------------------- /blog-cms/src/util/task-queue.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 任务队列,按时间间隔执行函数 3 | * 例: taskQueue(()=>{console.log(123)},1000) 4 | */ 5 | let queue = [] 6 | let timer = null 7 | 8 | function process() { 9 | if (queue.length === 0) { 10 | clearInterval(timer) 11 | timer = null 12 | return 13 | } 14 | let fn = queue.shift() 15 | fn() 16 | if (queue.length === 0) { 17 | clearInterval(timer) 18 | timer = null 19 | } 20 | } 21 | 22 | export function taskQueue(fn, timeout/*仅第一个任务的timeout有效*/) { 23 | queue.push(fn) 24 | if (!timer) { 25 | process() 26 | timer = setInterval(process, timeout) 27 | } 28 | } -------------------------------------------------------------------------------- /blog-cms/src/util/uuid.js: -------------------------------------------------------------------------------- 1 | export function randomUUID() { 2 | return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { 3 | let r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8) 4 | return v.toString(16) 5 | }) 6 | } -------------------------------------------------------------------------------- /blog-cms/src/util/validate.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} path 3 | * @returns {Boolean} 4 | */ 5 | export function isExternal(path) { 6 | return /^(https?:|mailto:|tel:)/.test(path) 7 | } 8 | 9 | /** 10 | * https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/img 11 | * @param {string} fileName 12 | * @returns {Boolean} 13 | */ 14 | export function isImgExt(fileName) { 15 | return /\.(apng|avif|bmp|gif|ico|cur|jpg|jpeg|jfif|pjpeg|pjp|png|svg|tif|tiff|webp)$/i.test(fileName) 16 | } -------------------------------------------------------------------------------- /blog-view/.env.development: -------------------------------------------------------------------------------- 1 | NODE_ENV = development 2 | outputDir = dev 3 | VUE_APP_ENVIRONMENT = developmentEnv 4 | VUE_APP_URL = "http://localhost:8090/RBlog/" -------------------------------------------------------------------------------- /blog-view/.env.production: -------------------------------------------------------------------------------- 1 | NODE_ENV = production 2 | outputDir = dist 3 | VUE_APP_ENVIRONMENT = productionEnv 4 | VUE_APP_URL = "/RBlog/" -------------------------------------------------------------------------------- /blog-view/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | pnpm-debug.log* 14 | 15 | # Editor directories and files 16 | .idea 17 | .vscode 18 | *.suo 19 | *.ntvs* 20 | *.njsproj 21 | *.sln 22 | *.sw? 23 | -------------------------------------------------------------------------------- /blog-view/README.md: -------------------------------------------------------------------------------- 1 | # blog-view 2 | 3 | ## Project setup 4 | ``` 5 | npm install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | npm run serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | npm run build 16 | ``` 17 | 18 | ### Customize configuration 19 | See [Configuration Reference](https://cli.vuejs.org/config/). 20 | -------------------------------------------------------------------------------- /blog-view/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /blog-view/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "blog-view", 3 | "version": "1.0.0", 4 | "description": "Raxcl view", 5 | "author": "Raxcl ", 6 | "private": true, 7 | "scripts": { 8 | "serve": "vue-cli-service serve --open", 9 | "dev": "vue-cli-service build --mode development", 10 | "build": "vue-cli-service build --mode production" 11 | }, 12 | "dependencies": { 13 | "axios": "0.24.0", 14 | "core-js": "3.6.5", 15 | "element-ui": "2.13.2", 16 | "font-awesome": "^4.7.0", 17 | "gsap": "^3.9.1", 18 | "jinrishici": "^1.0.6", 19 | "moment": "2.27.0", 20 | "nprogress": "0.2.0", 21 | "sanitize-html": "2.3.3", 22 | "semantic-ui-css": "2.4.1", 23 | "v-viewer": "1.5.1", 24 | "vue": "2.6.11", 25 | "vue-router": "3.3.4", 26 | "vuex": "3.5.1" 27 | }, 28 | "devDependencies": { 29 | "@vue/cli-plugin-babel": "4.4.0", 30 | "@vue/cli-plugin-router": "4.4.0", 31 | "@vue/cli-plugin-vuex": "4.4.0", 32 | "@vue/cli-service": "4.4.0", 33 | "vue-template-compiler": "2.6.11" 34 | }, 35 | "browserslist": [ 36 | "> 1%", 37 | "last 2 versions", 38 | "not dead" 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /blog-view/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raxcl/RBlog/3f0d5d0d75c3ce1c648ed4008be26e4651651038/blog-view/public/favicon.ico -------------------------------------------------------------------------------- /blog-view/public/img/avatar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raxcl/RBlog/3f0d5d0d75c3ce1c648ed4008be26e4651651038/blog-view/public/img/avatar.jpg -------------------------------------------------------------------------------- /blog-view/public/img/beian.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raxcl/RBlog/3f0d5d0d75c3ce1c648ed4008be26e4651651038/blog-view/public/img/beian.png -------------------------------------------------------------------------------- /blog-view/public/img/comment-avatar/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raxcl/RBlog/3f0d5d0d75c3ce1c648ed4008be26e4651651038/blog-view/public/img/comment-avatar/1.jpg -------------------------------------------------------------------------------- /blog-view/public/img/comment-avatar/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raxcl/RBlog/3f0d5d0d75c3ce1c648ed4008be26e4651651038/blog-view/public/img/comment-avatar/2.jpg -------------------------------------------------------------------------------- /blog-view/public/img/comment-avatar/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raxcl/RBlog/3f0d5d0d75c3ce1c648ed4008be26e4651651038/blog-view/public/img/comment-avatar/3.jpg -------------------------------------------------------------------------------- /blog-view/public/img/comment-avatar/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raxcl/RBlog/3f0d5d0d75c3ce1c648ed4008be26e4651651038/blog-view/public/img/comment-avatar/4.jpg -------------------------------------------------------------------------------- /blog-view/public/img/comment-avatar/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raxcl/RBlog/3f0d5d0d75c3ce1c648ed4008be26e4651651038/blog-view/public/img/comment-avatar/5.jpg -------------------------------------------------------------------------------- /blog-view/public/img/comment-avatar/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raxcl/RBlog/3f0d5d0d75c3ce1c648ed4008be26e4651651038/blog-view/public/img/comment-avatar/6.jpg -------------------------------------------------------------------------------- /blog-view/public/img/comment-avatar/avatar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raxcl/RBlog/3f0d5d0d75c3ce1c648ed4008be26e4651651038/blog-view/public/img/comment-avatar/avatar.jpg -------------------------------------------------------------------------------- /blog-view/public/img/error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raxcl/RBlog/3f0d5d0d75c3ce1c648ed4008be26e4651651038/blog-view/public/img/error.png -------------------------------------------------------------------------------- /blog-view/public/img/paper-plane.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raxcl/RBlog/3f0d5d0d75c3ce1c648ed4008be26e4651651038/blog-view/public/img/paper-plane.png -------------------------------------------------------------------------------- /blog-view/public/img/qr.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raxcl/RBlog/3f0d5d0d75c3ce1c648ed4008be26e4651651038/blog-view/public/img/qr.jpg -------------------------------------------------------------------------------- /blog-view/public/img/reward.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raxcl/RBlog/3f0d5d0d75c3ce1c648ed4008be26e4651651038/blog-view/public/img/reward.jpg -------------------------------------------------------------------------------- /blog-view/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | RBlog 9 | 10 | 11 | 12 | 13 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /blog-view/src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 19 | -------------------------------------------------------------------------------- /blog-view/src/api/about.js: -------------------------------------------------------------------------------- 1 | import axios from '@/plugins/axios' 2 | 3 | export function getAbout() { 4 | return axios({ 5 | url: 'about', 6 | method: 'GET' 7 | }) 8 | } -------------------------------------------------------------------------------- /blog-view/src/api/archives.js: -------------------------------------------------------------------------------- 1 | import axios from '@/plugins/axios' 2 | 3 | export function getArchives() { 4 | return axios({ 5 | url: 'archives', 6 | method: 'GET' 7 | }) 8 | } -------------------------------------------------------------------------------- /blog-view/src/api/blog.js: -------------------------------------------------------------------------------- 1 | import axios from '@/plugins/axios' 2 | 3 | export function getBlogById(token, id) { 4 | return axios({ 5 | url: 'blog', 6 | method: 'GET', 7 | headers: { 8 | Authorization: token, 9 | }, 10 | params: { 11 | id 12 | } 13 | }) 14 | } 15 | 16 | export function checkBlogPassword(blogPasswordForm) { 17 | return axios({ 18 | url: 'checkBlogPassword', 19 | method: 'POST', 20 | data: { 21 | ...blogPasswordForm 22 | } 23 | }) 24 | } 25 | 26 | export function getSearchBlogList(query) { 27 | return axios({ 28 | url: 'searchBlog', 29 | method: 'GET', 30 | params: { 31 | query 32 | } 33 | }) 34 | } -------------------------------------------------------------------------------- /blog-view/src/api/category.js: -------------------------------------------------------------------------------- 1 | import axios from '@/plugins/axios' 2 | 3 | export function getBlogListByCategoryName(categoryName, pageNum) { 4 | return axios({ 5 | url: 'category', 6 | method: 'GET', 7 | params: { 8 | categoryName, 9 | pageNum 10 | } 11 | }) 12 | } -------------------------------------------------------------------------------- /blog-view/src/api/comment.js: -------------------------------------------------------------------------------- 1 | import axios from '@/plugins/axios' 2 | 3 | export function getCommentListByQuery(token, query) { 4 | return axios({ 5 | url: 'comments', 6 | method: 'GET', 7 | headers: { 8 | Authorization: token, 9 | }, 10 | params: { 11 | ...query 12 | } 13 | }) 14 | } 15 | 16 | export function submitComment(token, form) { 17 | return axios({ 18 | url: 'comment', 19 | method: 'POST', 20 | headers: { 21 | Authorization: token, 22 | }, 23 | data: { 24 | ...form 25 | } 26 | }) 27 | } -------------------------------------------------------------------------------- /blog-view/src/api/friend.js: -------------------------------------------------------------------------------- 1 | import axios from '@/plugins/axios' 2 | 3 | export function getData() { 4 | return axios({ 5 | url: 'friends', 6 | method: 'GET' 7 | }) 8 | } 9 | 10 | export function addViewsByNickname(nickname) { 11 | return axios({ 12 | url: 'friend', 13 | method: 'POST', 14 | params: { 15 | nickname 16 | } 17 | }) 18 | } -------------------------------------------------------------------------------- /blog-view/src/api/home.js: -------------------------------------------------------------------------------- 1 | import axios from '@/plugins/axios' 2 | 3 | export function getBlogList(pageNum) { 4 | return axios({ 5 | url: 'blogs', 6 | method: 'GET', 7 | params: { 8 | pageNum 9 | } 10 | }) 11 | } -------------------------------------------------------------------------------- /blog-view/src/api/index.js: -------------------------------------------------------------------------------- 1 | import axios from '@/plugins/axios' 2 | 3 | export function getHitokoto() { 4 | return axios({ 5 | url: 'https://v1.hitokoto.cn/?c=a', 6 | method: 'GET' 7 | }) 8 | } 9 | 10 | export function getSite() { 11 | return axios({ 12 | url: 'site', 13 | method: 'GET' 14 | }) 15 | } -------------------------------------------------------------------------------- /blog-view/src/api/login.js: -------------------------------------------------------------------------------- 1 | import axios from '@/plugins/axios' 2 | 3 | export function login(loginForm) { 4 | return axios({ 5 | url: 'login', 6 | method: 'POST', 7 | data: { 8 | ...loginForm 9 | } 10 | }) 11 | } 12 | -------------------------------------------------------------------------------- /blog-view/src/api/moment.js: -------------------------------------------------------------------------------- 1 | import axios from '@/plugins/axios' 2 | 3 | export function getMomentListByPageNum(token, pageNum) { 4 | return axios({ 5 | url: 'moments', 6 | method: 'GET', 7 | headers: { 8 | Authorization: token, 9 | }, 10 | params: { 11 | pageNum 12 | } 13 | }) 14 | } 15 | 16 | export function likeMoment(id) { 17 | return axios({ 18 | url: `moment/like/${id}`, 19 | method: 'POST', 20 | }) 21 | } -------------------------------------------------------------------------------- /blog-view/src/api/tag.js: -------------------------------------------------------------------------------- 1 | import axios from '@/plugins/axios' 2 | 3 | export function getBlogListByTagName(tagName, pageNum) { 4 | return axios({ 5 | url: 'tag', 6 | method: 'GET', 7 | params: { 8 | tagName, 9 | pageNum 10 | } 11 | }) 12 | } -------------------------------------------------------------------------------- /blog-view/src/assets/css/icon/iconfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raxcl/RBlog/3f0d5d0d75c3ce1c648ed4008be26e4651651038/blog-view/src/assets/css/icon/iconfont.eot -------------------------------------------------------------------------------- /blog-view/src/assets/css/icon/iconfont.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "1993827", 3 | "name": "blog-view", 4 | "font_family": "ali-iconfont", 5 | "css_prefix_text": "icon-", 6 | "description": "", 7 | "glyphs": [ 8 | { 9 | "icon_id": "1139074", 10 | "name": "箭头下", 11 | "font_class": "down", 12 | "unicode": "e624", 13 | "unicode_decimal": 58916 14 | }, 15 | { 16 | "icon_id": "3176645", 17 | "name": "GitHub", 18 | "font_class": "github", 19 | "unicode": "ea0a", 20 | "unicode_decimal": 59914 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /blog-view/src/assets/css/icon/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raxcl/RBlog/3f0d5d0d75c3ce1c648ed4008be26e4651651038/blog-view/src/assets/css/icon/iconfont.ttf -------------------------------------------------------------------------------- /blog-view/src/assets/css/icon/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raxcl/RBlog/3f0d5d0d75c3ce1c648ed4008be26e4651651038/blog-view/src/assets/css/icon/iconfont.woff -------------------------------------------------------------------------------- /blog-view/src/assets/css/icon/iconfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raxcl/RBlog/3f0d5d0d75c3ce1c648ed4008be26e4651651038/blog-view/src/assets/css/icon/iconfont.woff2 -------------------------------------------------------------------------------- /blog-view/src/common/font/dsc.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raxcl/RBlog/3f0d5d0d75c3ce1c648ed4008be26e4651651038/blog-view/src/common/font/dsc.ttf -------------------------------------------------------------------------------- /blog-view/src/common/font/font.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "Delius Swash Caps"; 3 | src: url('dsc.ttf'); 4 | font-weight: normal; 5 | font-style: normal; 6 | } -------------------------------------------------------------------------------- /blog-view/src/common/reg.js: -------------------------------------------------------------------------------- 1 | export const checkEmail = (rule, value, callback) => { 2 | const reg = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ 3 | if (reg.test(value)) { 4 | return callback() 5 | } 6 | callback(new Error('请输入合法的邮箱')) 7 | } 8 | 9 | export const checkUrl = (rule, value, callback) => { 10 | const reg = /^(((ht)tps?):\/\/)?[\w-]+(\.[\w-]+)+([\w.,@?^=%&:\/~+#-]*[\w@?^=%&\/~+#-])?$/ 11 | if (reg.test(value)) { 12 | return callback() 13 | } 14 | callback(new Error('请输入合法的 URL')) 15 | } -------------------------------------------------------------------------------- /blog-view/src/components/blog/BlogList.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 33 | 34 | -------------------------------------------------------------------------------- /blog-view/src/components/comment/CommentList.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 47 | 48 | -------------------------------------------------------------------------------- /blog-view/src/components/comment/Pagination.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 27 | 28 | -------------------------------------------------------------------------------- /blog-view/src/components/index/MyAPlayer.vue: -------------------------------------------------------------------------------- 1 | 5 | 10 | 11 | -------------------------------------------------------------------------------- /blog-view/src/components/sidebar/Tags.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 24 | 25 | -------------------------------------------------------------------------------- /blog-view/src/plugins/axios.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import NProgress from 'nprogress' 3 | import 'nprogress/nprogress.css' 4 | 5 | const request = axios.create({ 6 | // baseURL: 'http://localhost:8090/', 7 | baseURL: process.env.VUE_APP_URL, 8 | timeout: 10000, 9 | }) 10 | 11 | // 请求拦截 12 | request.interceptors.request.use( 13 | config => { 14 | NProgress.start() 15 | const identification = window.localStorage.getItem('identification') 16 | //identification存在,且是基于baseURL的请求 17 | if (identification && !(config.url.startsWith('http://') || config.url.startsWith('https://'))) { 18 | config.headers.identification = identification 19 | } 20 | return config 21 | } 22 | ) 23 | 24 | // 响应拦截 25 | request.interceptors.response.use( 26 | config => { 27 | NProgress.done() 28 | const identification = config.headers.identification 29 | if (identification) { 30 | //保存身份标识到localStorage 31 | window.localStorage.setItem('identification', identification) 32 | } 33 | return config.data 34 | } 35 | ) 36 | 37 | export default request -------------------------------------------------------------------------------- /blog-view/src/store/getters.js: -------------------------------------------------------------------------------- 1 | export default { 2 | 3 | } -------------------------------------------------------------------------------- /blog-view/src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import state from './state' 4 | import actions from './actions' 5 | import mutations from './mutations' 6 | import getters from './getters' 7 | 8 | Vue.use(Vuex) 9 | 10 | export default new Vuex.Store({ 11 | state, 12 | actions, 13 | mutations, 14 | getters 15 | }) 16 | -------------------------------------------------------------------------------- /blog-view/src/store/mutations-types.js: -------------------------------------------------------------------------------- 1 | export const SAVE_INTRODUCTION = 'saveIntroduction' 2 | export const SAVE_SITE_INFO = 'saveSiteInfo' 3 | export const SAVE_COMMENT_RESULT = 'saveCommentResult' 4 | export const SET_COMMENT_QUERY_PAGE = 'setCommentQueryPage' 5 | export const SET_COMMENT_QUERY_BLOG_ID = 'setCommentQueryBlogId' 6 | export const SET_COMMENT_QUERY_PAGE_NUM = 'setCommentQueryPageNum' 7 | export const SET_PARENT_COMMENT_ID = 'setParentCommentId' 8 | export const RESET_COMMENT_FORM = 'resetCommentForm' 9 | export const RESTORE_COMMENT_FORM = 'restoreCommentForm' 10 | export const SET_IS_BLOG_RENDER_COMPLETE = 'setIsBlogRenderComplete' 11 | export const SET_BLOG_PASSWORD_DIALOG_VISIBLE = 'setBlogPasswordDialogVisible' 12 | export const SET_BLOG_PASSWORD_FORM = 'setBlogPasswordForm' 13 | export const SET_FOCUS_MODE = 'setFocusMode' 14 | export const SET_IS_BLOG_TO_HOME = 'setIsBlogToHome' 15 | export const SAVE_CLIENT_SIZE = 'saveClientSize' -------------------------------------------------------------------------------- /blog-view/src/store/state.js: -------------------------------------------------------------------------------- 1 | export default { 2 | siteInfo: '', 3 | introduction: { 4 | avatar: '', 5 | name: '', 6 | rollText: [], 7 | }, 8 | commentQuery: { 9 | //用于后端判断该评论所在页面类型(文章、友链、关于我) 10 | page: 0, 11 | blogId: null, 12 | pageNum: 1, 13 | pageSize: 5 14 | }, 15 | allComment: 0, 16 | closeComment: 0, 17 | commentTotalPage: 0, 18 | comments: [], 19 | parentCommentId: -1, 20 | commentForm: { 21 | content: '', 22 | nickname: '', 23 | email: '', 24 | website: '', 25 | notice: true 26 | }, 27 | //博客文章渲染完成的标记 28 | isBlogRenderComplete: false, 29 | //受保护文章密码对话框 30 | blogPasswordDialogVisible: false, 31 | blogPasswordForm: { 32 | blogId: 0, 33 | password: '' 34 | }, 35 | //专注模式 36 | focusMode: false, 37 | //文章页面路由到首页的标记 38 | isBlogToHome: false, 39 | //可视窗口大小 40 | clientSize: { 41 | clientHeight: 0, 42 | clientWidth: 1080 43 | } 44 | } -------------------------------------------------------------------------------- /blog-view/src/util/dateTimeFormatUtils.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import moment from 'moment' 3 | 4 | //设置moment国际化语言 5 | moment.locale('zh-cn') 6 | 7 | Vue.filter('dateFormat', function (value, format = 'YYYY-MM-DD HH:mm:ss') { 8 | return moment(value).format(format) 9 | }) 10 | 11 | Vue.filter('dateFromNow', function (value) { 12 | //相对时间大于一个月,显示详细时间 13 | if (moment().diff(moment(value)) > 2592000000) { 14 | return moment(value).format('YYYY-MM-DD HH:mm') 15 | } 16 | return moment(value).fromNow() 17 | }) -------------------------------------------------------------------------------- /blog-view/src/util/directive.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | /** 4 | * 防抖 单位时间只触发最后一次 5 | * 例:刷新 6 | * 简写:刷新 7 | */ 8 | Vue.directive('debounce', { 9 | inserted: function (el, binding) { 10 | let [fn, event = "click", time = 300] = binding.value 11 | let timer 12 | el.addEventListener(event, () => { 13 | timer && clearTimeout(timer) 14 | timer = setTimeout(() => fn(), time) 15 | }) 16 | } 17 | }) 18 | 19 | /** 20 | * 节流 每单位时间可触发一次 21 | * 例:刷新 22 | * 传递参数:刷新 23 | */ 24 | Vue.directive('throttle', { 25 | inserted: function (el, binding) { 26 | let [fn, event = "click", time = 300] = binding.value 27 | let now, preTime 28 | el.addEventListener(event, () => { 29 | now = new Date() 30 | if (!preTime || now - preTime > time) { 31 | preTime = now 32 | fn() 33 | } 34 | }) 35 | } 36 | }) 37 | -------------------------------------------------------------------------------- /blog-view/src/util/getPageTitle.js: -------------------------------------------------------------------------------- 1 | import store from '@/store' 2 | 3 | export default function getPageTitle(pageTitle){ 4 | const title = store.state.siteInfo.webTitleSuffix; 5 | if (pageTitle) { 6 | if (title) { 7 | return `${pageTitle}${title}` 8 | } 9 | return pageTitle 10 | } 11 | return title 12 | } 13 | 14 | -------------------------------------------------------------------------------- /blog-view/src/views/category/Category.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 58 | 59 | -------------------------------------------------------------------------------- /blog-view/src/views/tag/Tag.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 58 | 59 | -------------------------------------------------------------------------------- /blog-view/vue.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | //publicPath:'/', //从当前目录下获取资源(由于静态资源不太一起,加了刷新页面会白屏) 3 | outputDir: process.env.outputDir, // 打包生成目录 4 | configureWebpack: { 5 | resolve: { 6 | alias: { 7 | 'assets': '@/assets', 8 | 'common': '@/common', 9 | 'components': '@/components', 10 | 'api': '@/api', 11 | 'views': '@/views', 12 | 'plugins': '@/plugins' 13 | } 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "RBlog", 3 | "lockfileVersion": 2, 4 | "requires": true, 5 | "packages": {} 6 | } 7 | --------------------------------------------------------------------------------