Repository: ggggborn/SpringCloud-acimage
Branch: main
Commit: 32c50a3e1d8b
Files: 718
Total size: 1.7 MB
Directory structure:
gitextract_r94k4dmb/
├── .gitignore
├── README.md
├── acimage_admin/
│ ├── .gitignore
│ ├── pom.xml
│ └── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── acimage/
│ │ │ └── admin/
│ │ │ ├── AdminApplication.java
│ │ │ ├── config/
│ │ │ │ ├── WebMvcConfig.java
│ │ │ │ └── mybatis/
│ │ │ │ ├── CommunityDataSourceConfig.java
│ │ │ │ ├── GlobalConfigBean.java
│ │ │ │ └── ImageDataSourceConfig.java
│ │ │ ├── dao/
│ │ │ │ ├── community/
│ │ │ │ │ ├── CategoryDao.java
│ │ │ │ │ ├── CommentDao.java
│ │ │ │ │ ├── HomeCarouselDao.java
│ │ │ │ │ └── TopicDao.java
│ │ │ │ ├── sys/
│ │ │ │ │ ├── ApiDao.java
│ │ │ │ │ ├── AuthorizeDao.java
│ │ │ │ │ ├── PermissionDao.java
│ │ │ │ │ ├── RoleDao.java
│ │ │ │ │ └── UserRoleDao.java
│ │ │ │ └── user/
│ │ │ │ ├── UserDao.java
│ │ │ │ └── UserPrivacyDao.java
│ │ │ ├── global/
│ │ │ │ └── consts/
│ │ │ │ └── ModuleConstants.java
│ │ │ ├── model/
│ │ │ │ ├── request/
│ │ │ │ │ ├── AdminLoginReq.java
│ │ │ │ │ ├── ApiAddReq.java
│ │ │ │ │ ├── ApiModifyReq.java
│ │ │ │ │ ├── ApiQueryReq.java
│ │ │ │ │ ├── CarouselAddReq.java
│ │ │ │ │ ├── CarouselModifyReq.java
│ │ │ │ │ ├── CommentQueryReq.java
│ │ │ │ │ ├── PermissionAddReq.java
│ │ │ │ │ ├── PermissionModifyReq.java
│ │ │ │ │ ├── RoleAddReq.java
│ │ │ │ │ ├── RoleModifyReq.java
│ │ │ │ │ ├── TopicQueryReq.java
│ │ │ │ │ └── UserQueryReq.java
│ │ │ │ └── vo/
│ │ │ │ └── WebsiteDataVo.java
│ │ │ ├── service/
│ │ │ │ ├── api/
│ │ │ │ │ ├── ApiQueryService.java
│ │ │ │ │ ├── ApiWriteService.java
│ │ │ │ │ └── impl/
│ │ │ │ │ ├── ApiQueryServiceImpl.java
│ │ │ │ │ └── ApiWriteServiceImpl.java
│ │ │ │ ├── authorize/
│ │ │ │ │ ├── AuthorizeQueryService.java
│ │ │ │ │ ├── AuthorizeWriteService.java
│ │ │ │ │ └── impl/
│ │ │ │ │ ├── AuthorizeQueryServiceImpl.java
│ │ │ │ │ └── AuthorizeWriteServiceImpl.java
│ │ │ │ ├── category/
│ │ │ │ │ ├── CategoryQueryService.java
│ │ │ │ │ └── impl/
│ │ │ │ │ └── CategoryQueryServiceImpl.java
│ │ │ │ ├── comment/
│ │ │ │ │ ├── CommentQueryService.java
│ │ │ │ │ ├── CommentWriteService.java
│ │ │ │ │ └── impl/
│ │ │ │ │ ├── CommentQueryServiceImpl.java
│ │ │ │ │ └── CommentWriteServiceImpl.java
│ │ │ │ ├── homecarousel/
│ │ │ │ │ ├── HomeCarouselQueryService.java
│ │ │ │ │ ├── HomeCarouselWriteService.java
│ │ │ │ │ └── impl/
│ │ │ │ │ ├── HomeCarouselQueryServiceImpl.java
│ │ │ │ │ └── HomeCarouselWriteServiceImpl.java
│ │ │ │ ├── login/
│ │ │ │ │ ├── LoginService.java
│ │ │ │ │ ├── VerifyCodeService.java
│ │ │ │ │ └── impl/
│ │ │ │ │ ├── LoginServiceImpl.java
│ │ │ │ │ └── VerifyCodeServiceImpl.java
│ │ │ │ ├── permission/
│ │ │ │ │ ├── PermissionQueryService.java
│ │ │ │ │ ├── PermissionWriteSercice.java
│ │ │ │ │ └── impl/
│ │ │ │ │ ├── PermissionQueryServiceImpl.java
│ │ │ │ │ └── PermissionWriteServiceImpl.java
│ │ │ │ ├── role/
│ │ │ │ │ ├── RoleQueryService.java
│ │ │ │ │ ├── RoleWriteService.java
│ │ │ │ │ └── impl/
│ │ │ │ │ ├── RoleQueryServiceImpl.java
│ │ │ │ │ └── RoleWriteServiceImpl.java
│ │ │ │ ├── topic/
│ │ │ │ │ ├── TopicQueryService.java
│ │ │ │ │ ├── TopicWriteService.java
│ │ │ │ │ └── impl/
│ │ │ │ │ ├── TopicQueryServiceImpl.java
│ │ │ │ │ └── TopicWriteServiceImpl.java
│ │ │ │ ├── user/
│ │ │ │ │ ├── UserQueryService.java
│ │ │ │ │ ├── UserWriteService.java
│ │ │ │ │ └── impl/
│ │ │ │ │ ├── UserQueryServiceImpl.java
│ │ │ │ │ └── UserWriteServiceImpl.java
│ │ │ │ ├── userrole/
│ │ │ │ │ ├── UserRoleQueryService.java
│ │ │ │ │ ├── UserRoleWriteService.java
│ │ │ │ │ └── impl/
│ │ │ │ │ ├── UserRoleQueryServiceImpl.java
│ │ │ │ │ └── UserRoleWriteServiceImpl.java
│ │ │ │ └── websitedata/
│ │ │ │ ├── WebsiteDataService.java
│ │ │ │ └── impl/
│ │ │ │ └── WebsiteDataServiceImpl.java
│ │ │ └── web/
│ │ │ └── controller/
│ │ │ ├── AdminLoginController.java
│ │ │ ├── ApiOperateController.java
│ │ │ ├── ApiQueryController.java
│ │ │ ├── AuthorizeOperateController.java
│ │ │ ├── AuthorizeQueryController.java
│ │ │ ├── CategoryController.java
│ │ │ ├── CommentOperateController.java
│ │ │ ├── CommentQueryController.java
│ │ │ ├── HomeCarouselController.java
│ │ │ ├── PermissionOperateController.java
│ │ │ ├── PermissionQueryController.java
│ │ │ ├── RoleController.java
│ │ │ ├── TopicOperateController.java
│ │ │ ├── TopicQueryController.java
│ │ │ ├── UserQueryController.java
│ │ │ ├── UserRoleOperateController.java
│ │ │ └── WebsiteDataController.java
│ │ └── resources/
│ │ ├── application-dev.yml
│ │ ├── application.yml
│ │ ├── logback-spring.xml
│ │ └── mapper/
│ │ ├── community/
│ │ │ └── TopicMapper.xml
│ │ ├── image/
│ │ │ └── HomeCarouselMapper.xml
│ │ ├── sys/
│ │ │ ├── ApiMapper.xml
│ │ │ └── PermissionMapper.xml
│ │ └── user/
│ │ └── TopicMapper.xml
│ └── test/
│ └── java/
│ └── com/
│ └── acimage/
│ └── admin/
│ ├── AdminApplicationTest.java
│ ├── dao/
│ │ ├── community/
│ │ │ ├── SpDaoTest.java
│ │ │ └── TopicDaoTest.java
│ │ └── sys/
│ │ └── ApiDaoTest.java
│ └── service/
│ └── HomeCarouselWriteServiceTest.java
├── acimage_common/
│ ├── .gitignore
│ ├── lib/
│ │ └── webp-imageio-core-0.1.0.jar
│ ├── pom.xml
│ └── src/
│ └── main/
│ ├── java/
│ │ └── com/
│ │ └── acimage/
│ │ └── common/
│ │ ├── CommonMain.java
│ │ ├── config/
│ │ │ ├── EsConfig.java
│ │ │ ├── EsProdConfig.java
│ │ │ ├── FilterConfig.java
│ │ │ ├── JacksonConfig.java
│ │ │ ├── PaginationConfig.java
│ │ │ └── RabbitmqConvertConfig.java
│ │ ├── deprecated/
│ │ │ ├── IpInterceptorBak.java
│ │ │ ├── JwtInterceptorBak.java
│ │ │ ├── PermissionInterceptorBak.java
│ │ │ ├── QiniuUtils.java
│ │ │ ├── QiniuUtilsBak.java
│ │ │ ├── UserCommunityStatistic.java
│ │ │ ├── annotation/
│ │ │ │ ├── Authentication.java
│ │ │ │ └── utils/
│ │ │ │ └── AuthenticationUtils.java
│ │ │ └── typehandler/
│ │ │ └── MatchRuleTypeHandler.java
│ │ ├── global/
│ │ │ ├── aop/
│ │ │ │ └── LogAdvice.java
│ │ │ ├── consts/
│ │ │ │ ├── EsConstants.java
│ │ │ │ ├── FileFormatConstants.java
│ │ │ │ ├── HeaderKeyConstants.java
│ │ │ │ ├── JwtConstants.java
│ │ │ │ ├── MqConstants.java
│ │ │ │ ├── StorePrefixConstants.java
│ │ │ │ ├── SysKeyConstants.java
│ │ │ │ └── TimeConstants.java
│ │ │ ├── context/
│ │ │ │ └── UserContext.java
│ │ │ ├── enums/
│ │ │ │ ├── AuthenticationType.java
│ │ │ │ ├── MatchRule.java
│ │ │ │ ├── MyHttpMethod.java
│ │ │ │ ├── ServiceType.java
│ │ │ │ └── TokenStatus.java
│ │ │ └── exception/
│ │ │ ├── BaseException.java
│ │ │ ├── BusinessException.java
│ │ │ ├── NullTokenException.java
│ │ │ └── SystemException.java
│ │ ├── model/
│ │ │ ├── Index/
│ │ │ │ └── TopicIndex.java
│ │ │ ├── domain/
│ │ │ │ ├── community/
│ │ │ │ │ ├── Category.java
│ │ │ │ │ ├── CmtyUser.java
│ │ │ │ │ ├── Comment.java
│ │ │ │ │ ├── HomeCarousel.java
│ │ │ │ │ ├── Star.java
│ │ │ │ │ ├── Tag.java
│ │ │ │ │ ├── TagTopic.java
│ │ │ │ │ ├── Topic.java
│ │ │ │ │ └── TopicHtml.java
│ │ │ │ ├── image/
│ │ │ │ │ ├── Image.java
│ │ │ │ │ └── ImageHash.java
│ │ │ │ ├── sys/
│ │ │ │ │ ├── Api.java
│ │ │ │ │ ├── Authorize.java
│ │ │ │ │ ├── Permission.java
│ │ │ │ │ ├── Role.java
│ │ │ │ │ └── UserRole.java
│ │ │ │ └── user/
│ │ │ │ ├── CommentMsg.java
│ │ │ │ ├── User.java
│ │ │ │ ├── UserMsg.java
│ │ │ │ └── UserPrivacy.java
│ │ │ ├── mq/
│ │ │ │ └── dto/
│ │ │ │ ├── EsAddDto.java
│ │ │ │ ├── EsDeleteDto.java
│ │ │ │ ├── EsUpdateByIdDto.java
│ │ │ │ ├── EsUpdateByTermDto.java
│ │ │ │ ├── ImageIdWithUrl.java
│ │ │ │ ├── ObjectWithClass.java
│ │ │ │ ├── SyncImagesUpdateDto.java
│ │ │ │ ├── UserIdWithPhotoUrl.java
│ │ │ │ └── UserIdWithUsername.java
│ │ │ └── page/
│ │ │ └── MyPage.java
│ │ ├── redis/
│ │ │ ├── QueryRedisAdvice.java
│ │ │ ├── RequestLimitAdvice.java
│ │ │ ├── annotation/
│ │ │ │ ├── KeyParam.java
│ │ │ │ ├── QueryRedis.java
│ │ │ │ └── RequestLimit.java
│ │ │ ├── enums/
│ │ │ │ ├── DataType.java
│ │ │ │ └── LimitTarget.java
│ │ │ └── utils/
│ │ │ └── RedisAnnotationUtils.java
│ │ ├── result/
│ │ │ ├── Code.java
│ │ │ └── Result.java
│ │ ├── service/
│ │ │ ├── TokenService.java
│ │ │ └── impl/
│ │ │ └── TokenServiceImpl.java
│ │ ├── utils/
│ │ │ ├── CookieUtils.java
│ │ │ ├── EsUtils.java
│ │ │ ├── ExceptionUtils.java
│ │ │ ├── HtmlUtils.java
│ │ │ ├── IdGenerator.java
│ │ │ ├── ImageUtils.java
│ │ │ ├── IpUtils.java
│ │ │ ├── JwtUtils.java
│ │ │ ├── LambdaUtils.java
│ │ │ ├── RsaUtils.java
│ │ │ ├── SensitiveWordUtils.java
│ │ │ ├── SpringContextUtils.java
│ │ │ ├── common/
│ │ │ │ ├── AopUtils.java
│ │ │ │ ├── ArrayUtils.java
│ │ │ │ ├── BeanUtils.java
│ │ │ │ ├── FileUtils.java
│ │ │ │ ├── JacksonUtils.java
│ │ │ │ ├── ListUtils.java
│ │ │ │ ├── PageUtils.java
│ │ │ │ ├── PairUtils.java
│ │ │ │ ├── ReflectUtils.java
│ │ │ │ └── StringUtils.java
│ │ │ ├── minio/
│ │ │ │ ├── MinioProperties.java
│ │ │ │ └── MinioUtils.java
│ │ │ └── redis/
│ │ │ ├── RedisLuaUtils.java
│ │ │ └── RedisUtils.java
│ │ └── web/
│ │ ├── exceptionhandler/
│ │ │ ├── ArgumentValidateExceptionHandler.java
│ │ │ ├── GlobalExceptionHandler.java
│ │ │ └── JwtExceptionHandler.java
│ │ └── interceptor/
│ │ ├── AccessInterceptor.java
│ │ └── JwtInterceptor.java
│ └── resources/
│ ├── application-common.yml
│ ├── application-qiniu-template.yml
│ ├── lua/
│ │ ├── getAndCombineAndDelete.lua
│ │ ├── incrementIfPresent.lua
│ │ ├── incrementIfPresentForFieldKey.lua
│ │ ├── incrementIfPresentForZSet.lua
│ │ ├── requestLimit.lua
│ │ └── setIfPresentForFieldKey.lua
│ └── sensitive_word.txt
├── acimage_community/
│ ├── lib/
│ │ └── webp-imageio-core-0.1.0.jar
│ ├── pom.xml
│ └── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── acimage/
│ │ │ └── community/
│ │ │ ├── CommunityApplication.java
│ │ │ ├── dao/
│ │ │ │ ├── CategoryDao.java
│ │ │ │ ├── CmtyUserDao.java
│ │ │ │ ├── CommentDao.java
│ │ │ │ ├── HomeCarrouselDao.java
│ │ │ │ ├── ImageDao.java
│ │ │ │ ├── StarDao.java
│ │ │ │ ├── TagDao.java
│ │ │ │ ├── TagTopicDao.java
│ │ │ │ ├── TopicDao.java
│ │ │ │ └── TopicHtmlDao.java
│ │ │ ├── depreted/
│ │ │ │ ├── CmtyUserDaoBak.java
│ │ │ │ ├── RabbitmqConvertConfig.java
│ │ │ │ ├── UserMixWriteService.java
│ │ │ │ ├── UserMixWriteServiceImpl.java
│ │ │ │ └── userstatistic/
│ │ │ │ ├── UserCsQueryService.java
│ │ │ │ ├── UserCsRankService.java
│ │ │ │ ├── UserCsWriteService.java
│ │ │ │ ├── consts/
│ │ │ │ │ └── KeyConstants.java
│ │ │ │ └── impl/
│ │ │ │ ├── UserCsQueryServiceImpl.java
│ │ │ │ ├── UserCsRankServiceImpl.java
│ │ │ │ └── UserCsWriteServiceImpl.java
│ │ │ ├── esdao/
│ │ │ │ └── UserEsDao.java
│ │ │ ├── global/
│ │ │ │ ├── annotation/
│ │ │ │ │ ├── RecordPageView.java
│ │ │ │ │ └── TopicId.java
│ │ │ │ ├── aop/
│ │ │ │ │ └── RecordPageViewAdvice.java
│ │ │ │ ├── config/
│ │ │ │ │ ├── JobFactory.java
│ │ │ │ │ └── WebMvcConfig.java
│ │ │ │ ├── consts/
│ │ │ │ │ ├── CommentKeyConstants.java
│ │ │ │ │ ├── CoverImageConstants.java
│ │ │ │ │ ├── PageSizeConstants.java
│ │ │ │ │ ├── StarKeyConstants.java
│ │ │ │ │ └── TopicKeyConstants.java
│ │ │ │ └── enums/
│ │ │ │ ├── SortMode.java
│ │ │ │ └── TopicAttribute.java
│ │ │ ├── listener/
│ │ │ │ ├── CommentEventListener.java
│ │ │ │ ├── PublishTopicEventListener.java
│ │ │ │ ├── StarEventListener.java
│ │ │ │ └── event/
│ │ │ │ ├── CommentEvent.java
│ │ │ │ ├── StarEvent.java
│ │ │ │ └── TopicEvent.java
│ │ │ ├── model/
│ │ │ │ ├── request/
│ │ │ │ │ ├── CommentAddReq.java
│ │ │ │ │ ├── CommentModifyReq.java
│ │ │ │ │ ├── TopicAddReq.java
│ │ │ │ │ ├── TopicModifyHtmlReq.java
│ │ │ │ │ ├── TopicQueryByCategoryIdReq.java
│ │ │ │ │ ├── TopicQueryBySortReq.java
│ │ │ │ │ ├── TopicQueryByTagIdReq.java
│ │ │ │ │ ├── TopicSearchReq.java
│ │ │ │ │ ├── UserLoginReq.java
│ │ │ │ │ └── UserRegisterReq.java
│ │ │ │ └── vo/
│ │ │ │ └── TopicInfoVo.java
│ │ │ ├── mq/
│ │ │ │ ├── config/
│ │ │ │ │ ├── SyncEsMqConfig.java
│ │ │ │ │ ├── SyncImagesMqConfig.java
│ │ │ │ │ └── UserMsgMqConfig.java
│ │ │ │ ├── consumer/
│ │ │ │ │ ├── SyncEsConsumer.java
│ │ │ │ │ └── SyncUserConsumer.java
│ │ │ │ └── producer/
│ │ │ │ ├── SyncEsMqProducer.java
│ │ │ │ ├── UserMsgMqProducer.java
│ │ │ │ └── syncImagesMqProducer.java
│ │ │ ├── runner/
│ │ │ │ ├── CreateIndexRunner.java
│ │ │ │ └── PreheatApplicationRunner.java
│ │ │ ├── schedule/
│ │ │ │ ├── UpdateActivityTimeJob.java
│ │ │ │ ├── UpdateActivityTimeJobConfig.java
│ │ │ │ ├── UpdateCommentCountJob.java
│ │ │ │ ├── UpdateCommentCountJobConfig.java
│ │ │ │ ├── UpdatePageViewJob.java
│ │ │ │ ├── UpdatePageViewJobConfig.java
│ │ │ │ ├── UpdateStarCountJob.java
│ │ │ │ └── UpdateStarCountJobConfig.java
│ │ │ ├── service/
│ │ │ │ ├── categoty/
│ │ │ │ │ ├── CategoryQueryService.java
│ │ │ │ │ └── impl/
│ │ │ │ │ └── CategoryQueryServiceImpl.java
│ │ │ │ ├── cmtyuser/
│ │ │ │ │ ├── CmtyUserQueryService.java
│ │ │ │ │ ├── CmtyUserRankService.java
│ │ │ │ │ ├── CmtyUserWriteService.java
│ │ │ │ │ └── impl/
│ │ │ │ │ ├── CmtyUserQueryServiceImpl.java
│ │ │ │ │ ├── CmtyUserRankServiceImpl.java
│ │ │ │ │ └── CmtyUserWriteServiceImpl.java
│ │ │ │ ├── comment/
│ │ │ │ │ ├── CommentInfoQueryService.java
│ │ │ │ │ ├── CommentQueryService.java
│ │ │ │ │ ├── CommentWriteService.java
│ │ │ │ │ ├── annotation/
│ │ │ │ │ │ ├── Operation.java
│ │ │ │ │ │ └── UpdateCcByReturn.java
│ │ │ │ │ └── impl/
│ │ │ │ │ ├── CommentInfoQueryServiceImpl.java
│ │ │ │ │ ├── CommentQueryServiceImpl.java
│ │ │ │ │ └── CommentWriteServiceImpl.java
│ │ │ │ ├── homecarousel/
│ │ │ │ │ ├── HomeCarouselQueryService.java
│ │ │ │ │ └── impl/
│ │ │ │ │ └── HomeCarouselQueryServiceImpl.java
│ │ │ │ ├── star/
│ │ │ │ │ ├── StarMixQueryService.java
│ │ │ │ │ ├── StarQueryService.java
│ │ │ │ │ ├── StarWriteService.java
│ │ │ │ │ └── impl/
│ │ │ │ │ ├── StarMixQueryServiceImpl.java
│ │ │ │ │ ├── StarQueryServiceImpl.java
│ │ │ │ │ └── StarWriteServiceImpl.java
│ │ │ │ ├── tag/
│ │ │ │ │ ├── TagQueryService.java
│ │ │ │ │ ├── TagTopicQueryService.java
│ │ │ │ │ ├── TagTopicWriteService.java
│ │ │ │ │ ├── TagWriteService.java
│ │ │ │ │ └── impl/
│ │ │ │ │ ├── TagQueryServiceImpl.java
│ │ │ │ │ ├── TagTopicQueryServiceImpl.java
│ │ │ │ │ ├── TagTopicWriteServiceImpl.java
│ │ │ │ │ └── TagWriteServiceImpl.java
│ │ │ │ └── topic/
│ │ │ │ ├── Impl/
│ │ │ │ │ ├── TopicEsSearchServiceImpl.java
│ │ │ │ │ ├── TopicHtmlQueryServiceImpl.java
│ │ │ │ │ ├── TopicHtmlWriteServiceImpl.java
│ │ │ │ │ ├── TopicInfoQueryServiceImpl.java
│ │ │ │ │ ├── TopicInfoWriteServiceImpl.java
│ │ │ │ │ ├── TopicPreheatServiceImpl.java
│ │ │ │ │ ├── TopicQueryServiceImpl.java
│ │ │ │ │ ├── TopicRankQueryServiceImpl.java
│ │ │ │ │ ├── TopicRankWriteServiceImpl.java
│ │ │ │ │ ├── TopicSpAttrQueryServiceImpl.java
│ │ │ │ │ ├── TopicSpAttrWriteServiceImpl.java
│ │ │ │ │ └── TopicWriteServiceImpl.java
│ │ │ │ ├── TopicEsSearchService.java
│ │ │ │ ├── TopicHtmlQueryService.java
│ │ │ │ ├── TopicHtmlWriteService.java
│ │ │ │ ├── TopicInfoQueryService.java
│ │ │ │ ├── TopicInfoWriteService.java
│ │ │ │ ├── TopicPreheatService.java
│ │ │ │ ├── TopicQueryService.java
│ │ │ │ ├── TopicRankQueryService.java
│ │ │ │ ├── TopicRankWriteService.java
│ │ │ │ ├── TopicSpAttrQueryService.java
│ │ │ │ ├── TopicSpAttrWriteService.java
│ │ │ │ └── TopicWriteService.java
│ │ │ ├── utils/
│ │ │ │ └── RsaUtils.java
│ │ │ └── web/
│ │ │ ├── controller/
│ │ │ │ ├── CategoryQueryController.java
│ │ │ │ ├── CommentOperateController.java
│ │ │ │ ├── CommentQueryController.java
│ │ │ │ ├── HomeCarouselQueryController.java
│ │ │ │ ├── StarOperateController.java
│ │ │ │ ├── StarQueryController.java
│ │ │ │ ├── TagQueryController.java
│ │ │ │ ├── TopicOperateController.java
│ │ │ │ ├── TopicQueryController.java
│ │ │ │ ├── TopicSearchController.java
│ │ │ │ └── UserRankController.java
│ │ │ └── provider/
│ │ │ ├── CmtyUserProvider.java
│ │ │ ├── CommentProvider.java
│ │ │ └── TopicProvider.java
│ │ └── resources/
│ │ ├── application-dev.yml
│ │ ├── application.yml
│ │ ├── logback-spring.xml
│ │ └── mapper/
│ │ ├── CmtyUserMapper.xml
│ │ ├── CommentMapper.xml
│ │ ├── ImageMapper.xml
│ │ ├── StarMapper.xml
│ │ ├── TagTopicMapper.xml
│ │ └── TopicMapper.xml
│ └── test/
│ └── java/
│ └── com/
│ └── acimage/
│ └── community/
│ ├── CasualTest.java
│ ├── CommunityApplicationTests.java
│ ├── dao/
│ │ ├── CommentDaoTest.java
│ │ ├── ImageDaoTest.java
│ │ ├── StarDaoTest.java
│ │ └── TopicDaoTest.java
│ ├── service/
│ │ ├── CommentWriteServiceTest.java
│ │ └── TopicEsSearchServiceTest.java
│ └── utils/
│ └── RedisTest.java
├── acimage_feign/
│ ├── pom.xml
│ └── src/
│ └── main/
│ └── java/
│ └── com/
│ └── acimage/
│ └── feign/
│ ├── FeignMain.java
│ ├── client/
│ │ ├── CmtyUserClient.java
│ │ ├── CommentClient.java
│ │ ├── TopicClient.java
│ │ └── UserClient.java
│ ├── config/
│ │ ├── FallbackFactoryBean.java
│ │ ├── FeignMultipartSupportConfig.java
│ │ └── FeignRequestInterceptorConfig.java
│ ├── depreted/
│ │ ├── FileClient.java
│ │ └── ImageClient.java
│ └── fallback/
│ ├── CmtyUserClientFallbackFactory.java
│ ├── CommentClientFallbackFactory.java
│ ├── ImageClientFallbackFactory.java
│ ├── TopicClientFallbackFactory.java
│ └── UserClientFallbackFactory.java
├── acimage_gateway/
│ ├── pom.xml
│ └── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── acimage/
│ │ │ └── gateway/
│ │ │ ├── GatewayApplication.java
│ │ │ ├── apitree/
│ │ │ │ ├── ApiTree.java
│ │ │ │ ├── ApiTreeFactory.java
│ │ │ │ ├── ApiTreeUtils.java
│ │ │ │ └── InitApiTreeApplicationRunner.java
│ │ │ ├── config/
│ │ │ │ ├── KeySolverConfig.java
│ │ │ │ └── RoleConfig.java
│ │ │ ├── dao/
│ │ │ │ ├── ApiDao.java
│ │ │ │ ├── AuthorizeDao.java
│ │ │ │ ├── PermissionDao.java
│ │ │ │ ├── RoleDao.java
│ │ │ │ └── UserRoleDao.java
│ │ │ ├── global/
│ │ │ │ └── consts/
│ │ │ │ └── NotationConstants.java
│ │ │ ├── globalfilter/
│ │ │ │ ├── AuthenticationFilter.java
│ │ │ │ ├── CustomWebsocketRoutingFilter.java
│ │ │ │ ├── PermissionFilter.java
│ │ │ │ ├── RemoveContextFilter.java
│ │ │ │ └── RequestLimitFilter.java
│ │ │ ├── schedule/
│ │ │ │ └── RefreshApiTreeSchedule.java
│ │ │ └── serivce/
│ │ │ ├── ApiQueryService.java
│ │ │ ├── AuthorizeQueryService.java
│ │ │ ├── RoleQueryService.java
│ │ │ ├── UserRoleQueryService.java
│ │ │ └── impl/
│ │ │ ├── ApiQueryQueryServiceImpl.java
│ │ │ ├── AuthorizeQueryServiceImpl.java
│ │ │ ├── RoleQueryServiceImpl.java
│ │ │ └── UserRoleQueryQueryServiceImpl.java
│ │ └── resources/
│ │ ├── application-dev.yml
│ │ ├── application.yml
│ │ └── logback-spring.xml
│ └── test/
│ └── java/
│ └── com/
│ └── acimage/
│ └── gateway/
│ ├── GatewayApplicationTest.java
│ └── apitree/
│ └── ApiTreeTest.java
├── acimage_image/
│ ├── lib/
│ │ └── webp-imageio-core-0.1.0.jar
│ ├── pom.xml
│ └── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── acimage/
│ │ │ └── image/
│ │ │ ├── ImageApplication.java
│ │ │ ├── dao/
│ │ │ │ ├── ImageDao.java
│ │ │ │ └── ImageHashDao.java
│ │ │ ├── global/
│ │ │ │ ├── consts/
│ │ │ │ │ ├── MyFileConstants.java
│ │ │ │ │ └── TopicImageKeyConstants.java
│ │ │ │ └── context/
│ │ │ │ └── DirectoryContext.java
│ │ │ ├── mq/
│ │ │ │ └── consumer/
│ │ │ │ └── SyncImagesConsumer.java
│ │ │ ├── service/
│ │ │ │ ├── config/
│ │ │ │ │ └── DhashTaskPoolConfig.java
│ │ │ │ ├── image/
│ │ │ │ │ ├── ImageMixWriteService.java
│ │ │ │ │ ├── ImageQueryService.java
│ │ │ │ │ ├── ImageWriteService.java
│ │ │ │ │ └── impl/
│ │ │ │ │ ├── ImageMixWriteServiceImpl.java
│ │ │ │ │ ├── ImageQueryServiceImpl.java
│ │ │ │ │ └── ImageWriteServiceImpl.java
│ │ │ │ ├── imagehash/
│ │ │ │ │ ├── ImageHashWriteService.java
│ │ │ │ │ ├── SearchImageService.java
│ │ │ │ │ └── impl/
│ │ │ │ │ ├── ImageHashWriteServiceImpl.java
│ │ │ │ │ └── SearchImageServiceImpl.java
│ │ │ │ └── photo/
│ │ │ │ ├── PhotoService.java
│ │ │ │ └── impl/
│ │ │ │ └── PhotoServiceImpl.java
│ │ │ ├── utils/
│ │ │ │ ├── BitUtils.java
│ │ │ │ ├── DhashUtils.java
│ │ │ │ ├── ImageFileUtils.java
│ │ │ │ └── ImageUtils.java
│ │ │ └── web/
│ │ │ ├── config/
│ │ │ │ └── WebMvcConfig.java
│ │ │ ├── controller/
│ │ │ │ ├── ImageOperateController.java
│ │ │ │ ├── PhotoOperateController.java
│ │ │ │ └── SearchImageController.java
│ │ │ └── provider/
│ │ │ └── ImageProvider.java
│ │ └── resources/
│ │ ├── application-dev.yml
│ │ ├── application.yml
│ │ ├── logback-spring.xml
│ │ └── mapper/
│ │ └── ImageMapper.xml
│ └── test/
│ └── java/
│ └── com/
│ └── acimage/
│ └── image/
│ ├── CasualTest.java
│ ├── ImageApplicationTests.java
│ ├── dao/
│ │ ├── ImageDaoTest.java
│ │ └── ImageHashDaoDaoTest.java
│ ├── service/
│ │ ├── FileServiceTest.java
│ │ └── SearchImageServiceTest.java
│ └── utils/
│ └── ImageHashDaoUtilsTest.java
├── acimage_user/
│ ├── pom.xml
│ └── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── acimage/
│ │ │ └── user/
│ │ │ ├── UserApplication.java
│ │ │ ├── dao/
│ │ │ │ ├── CommentMsgDao.java
│ │ │ │ ├── UserDao.java
│ │ │ │ ├── UserMsgDao.java
│ │ │ │ └── UserPrivacyDao.java
│ │ │ ├── global/
│ │ │ │ ├── config/
│ │ │ │ │ ├── WebMvcConfig.java
│ │ │ │ │ └── WebSocketConfig.java
│ │ │ │ └── consts/
│ │ │ │ ├── PageSizeConsts.java
│ │ │ │ ├── StorePrefixConst.java
│ │ │ │ └── WebSocketSessionConstants.java
│ │ │ ├── model/
│ │ │ │ ├── request/
│ │ │ │ │ ├── UserLoginReq.java
│ │ │ │ │ └── UserRegisterReq.java
│ │ │ │ └── vo/
│ │ │ │ └── ProfileVo.java
│ │ │ ├── mq/
│ │ │ │ ├── config/
│ │ │ │ │ └── SyncUserMqConfig.java
│ │ │ │ ├── consumer/
│ │ │ │ │ └── UserMsgConsumer.java
│ │ │ │ └── producer/
│ │ │ │ └── SyncUserMqProducer.java
│ │ │ ├── service/
│ │ │ │ ├── commentmsg/
│ │ │ │ │ ├── CommentMsgQueryService.java
│ │ │ │ │ ├── CommentMsgWriteService.java
│ │ │ │ │ └── impl/
│ │ │ │ │ ├── CommentMsgQueryServiceImpl.java
│ │ │ │ │ └── CommentMsgWriteServiceImpl.java
│ │ │ │ ├── mail/
│ │ │ │ │ ├── MainService.java
│ │ │ │ │ └── impl/
│ │ │ │ │ └── MailServiceImpl.java
│ │ │ │ ├── user/
│ │ │ │ │ ├── LoginService.java
│ │ │ │ │ ├── UserInfoService.java
│ │ │ │ │ ├── UserQueryService.java
│ │ │ │ │ ├── UserRankService.java
│ │ │ │ │ ├── UserWriteService.java
│ │ │ │ │ ├── consts/
│ │ │ │ │ │ └── KeyConstants.java
│ │ │ │ │ └── impl/
│ │ │ │ │ ├── LoginServiceImpl.java
│ │ │ │ │ ├── UserInfoServiceImpl.java
│ │ │ │ │ ├── UserQueryServiceImpl.java
│ │ │ │ │ ├── UserRankServiceImpl.java
│ │ │ │ │ └── UserWriteServiceImpl.java
│ │ │ │ ├── usermsg/
│ │ │ │ │ ├── UserMsgQueryService.java
│ │ │ │ │ ├── UserMsgWriteService.java
│ │ │ │ │ └── impl/
│ │ │ │ │ ├── UserMsgQueryServiceImpl.java
│ │ │ │ │ └── UserMsgWriteServiceImpl.java
│ │ │ │ └── verify/
│ │ │ │ ├── VerifyCodeService.java
│ │ │ │ └── impl/
│ │ │ │ └── VerifyCodeServiceImpl.java
│ │ │ └── web/
│ │ │ ├── controller/
│ │ │ │ ├── LoginController.java
│ │ │ │ ├── MessageController.java
│ │ │ │ ├── UserOperateController.java
│ │ │ │ ├── UserQueryController.java
│ │ │ │ └── VerifyCodeController.java
│ │ │ ├── provider/
│ │ │ │ └── UserProvider.java
│ │ │ └── websocket/
│ │ │ ├── MyHandshakeInterceptor.java
│ │ │ └── MyWebSocketHandler.java
│ │ └── resources/
│ │ ├── application-dev.yml
│ │ ├── application.yml
│ │ ├── logback-spring.xml
│ │ └── mapper/
│ │ ├── CommentMsgMapper.xml
│ │ └── UserMapper.xml
│ └── test/
│ └── java/
│ └── com/
│ └── acimage/
│ └── user/
│ └── AppTest.java
├── doc/
│ └── sql/
│ ├── .gitignore
│ ├── acimage_community.sql
│ ├── acimage_image.sql
│ ├── acimage_sys.sql
│ └── acimage_user.sql
├── pom.xml
├── vue-manage-system/
│ ├── .github/
│ │ └── FUNDING.yml
│ ├── .gitignore
│ ├── LICENSE
│ ├── README.md
│ ├── README_EN.md
│ ├── auto-imports.d.ts
│ ├── components.d.ts
│ ├── index.html
│ ├── package.json
│ ├── public/
│ │ ├── table.json
│ │ └── template.xlsx
│ ├── src/
│ │ ├── App.vue
│ │ ├── api/
│ │ │ ├── HomeCarousel.ts
│ │ │ ├── UserRole.ts
│ │ │ ├── WebsiteData.ts
│ │ │ ├── api.ts
│ │ │ ├── authorize.ts
│ │ │ ├── category.ts
│ │ │ ├── comment.ts
│ │ │ ├── index.ts
│ │ │ ├── login.ts
│ │ │ ├── permission.ts
│ │ │ ├── role.ts
│ │ │ ├── topic.ts
│ │ │ └── user.ts
│ │ ├── assets/
│ │ │ └── css/
│ │ │ ├── color-dark.css
│ │ │ ├── icon.css
│ │ │ └── main.css
│ │ ├── components/
│ │ │ ├── header.vue
│ │ │ ├── sidebar.vue
│ │ │ └── tags.vue
│ │ ├── config.ts
│ │ ├── main.ts
│ │ ├── router/
│ │ │ └── index.ts
│ │ ├── store/
│ │ │ ├── permiss.ts
│ │ │ ├── sidebar.ts
│ │ │ ├── store.ts
│ │ │ └── tags.ts
│ │ ├── utils/
│ │ │ ├── CommonUtils.ts
│ │ │ ├── MessageUtils.ts
│ │ │ ├── StringUtils.ts
│ │ │ ├── global.ts
│ │ │ ├── request.ts
│ │ │ ├── requestx.ts
│ │ │ ├── result.ts
│ │ │ └── utils.js
│ │ ├── views/
│ │ │ ├── 403.vue
│ │ │ ├── 404.vue
│ │ │ ├── HomeCarousel/
│ │ │ │ └── HomeCarousel.vue
│ │ │ ├── api/
│ │ │ │ └── api.vue
│ │ │ ├── authorize/
│ │ │ │ └── authorize.vue
│ │ │ ├── charts.vue
│ │ │ ├── comment/
│ │ │ │ └── comment.vue
│ │ │ ├── dashboard.vue
│ │ │ ├── donate.vue
│ │ │ ├── editor.vue
│ │ │ ├── home.vue
│ │ │ ├── icon.vue
│ │ │ ├── login.vue
│ │ │ ├── markdown.vue
│ │ │ ├── permission/
│ │ │ │ └── permission.vue
│ │ │ ├── permissionx.vue
│ │ │ ├── role/
│ │ │ │ └── role.vue
│ │ │ ├── table.vue
│ │ │ ├── tabs.vue
│ │ │ ├── topic/
│ │ │ │ └── topic.vue
│ │ │ ├── upload.vue
│ │ │ ├── user/
│ │ │ │ └── user.vue
│ │ │ └── user.vue
│ │ └── vite-env.d.ts
│ ├── tsconfig.json
│ ├── tsconfig.node.json
│ └── vite.config.ts
└── vue_acimage_web/
├── .gitignore
├── README.md
├── babel.config.js
├── jsconfig.json
├── mock/
│ ├── HomeCarousel.js
│ ├── UserRank.js
│ ├── index.js
│ └── topic.js
├── package.json
├── public/
│ ├── index.html
│ ├── static/
│ │ └── css/
│ │ └── common.css
│ └── tinymce/
│ ├── langs/
│ │ ├── README.md
│ │ └── zh-Hans.js
│ ├── license.txt
│ ├── plugins/
│ │ └── emoticons/
│ │ └── js/
│ │ ├── emojiimages.js
│ │ └── emojis.js
│ └── tinymce.d.ts
├── src/
│ ├── App.vue
│ ├── api/
│ │ ├── HomeCarousel.js
│ │ ├── TopicSearch.js
│ │ ├── UserRank.js
│ │ ├── category.js
│ │ ├── comment.js
│ │ ├── image.js
│ │ ├── login.js
│ │ ├── message.js
│ │ ├── photo.js
│ │ ├── star.js
│ │ ├── tag.js
│ │ ├── topic.js
│ │ └── user.js
│ ├── components/
│ │ ├── BaseContainer/
│ │ │ ├── BaseContainer.css
│ │ │ └── BaseContainer.vue
│ │ ├── CategoryCard/
│ │ │ ├── CategoryCard.css
│ │ │ └── CategoryCard.vue
│ │ ├── EditBoard/
│ │ │ ├── EditBoard.css
│ │ │ └── EditBoard.vue
│ │ ├── FloatImage/
│ │ │ ├── FloatImage.css
│ │ │ └── FloatImage.vue
│ │ ├── HelloWorld.vue
│ │ ├── HomeCarousel/
│ │ │ └── HomeCarousel.vue
│ │ ├── MaskImage/
│ │ │ ├── MaskImage.css
│ │ │ └── MaskImage.vue
│ │ ├── MyHeader/
│ │ │ ├── MyHeader.css
│ │ │ ├── MyHeader.vue
│ │ │ └── MyNavigation/
│ │ │ └── MyNavigation.vue
│ │ ├── ShowTinymce/
│ │ │ └── ShowTinymce.vue
│ │ ├── TagCard/
│ │ │ ├── TagCard.css
│ │ │ └── TagCard.vue
│ │ ├── TopicCard/
│ │ │ ├── TopicCard.css
│ │ │ └── TopicCard.vue
│ │ ├── TopicList/
│ │ │ ├── TopicList.css
│ │ │ └── TopicList.vue
│ │ └── TopicRank/
│ │ ├── TopicRank.css
│ │ └── TopicRank.vue
│ ├── config.js
│ ├── main.js
│ ├── router/
│ │ └── index.js
│ ├── store/
│ │ └── index.js
│ ├── utils/
│ │ ├── CommonUtils.js
│ │ ├── MessageUtils.js
│ │ ├── StringUtils.js
│ │ ├── global.js
│ │ ├── request.js
│ │ ├── result.js
│ │ └── utils.js
│ └── views/
│ ├── About/
│ │ ├── About.css
│ │ └── About.vue
│ ├── Forum/
│ │ ├── Forum.css
│ │ └── Forum.vue
│ ├── Home/
│ │ ├── Home.css
│ │ ├── Home.vue
│ │ └── UserRank/
│ │ ├── UserRank.css
│ │ └── UserRank.vue
│ ├── Login/
│ │ ├── Login.css
│ │ └── Login.vue
│ ├── MyActivity/
│ │ ├── MyActivity.css
│ │ ├── MyActivity.vue
│ │ ├── MyCommentActivity/
│ │ │ ├── MyCommentActivity.css
│ │ │ └── MyCommentActivity.vue
│ │ ├── MyStarActivity/
│ │ │ ├── MyStarActivity.css
│ │ │ └── MyStarActivity.vue
│ │ └── MyTopicActivity/
│ │ ├── MyTopicActivity.css
│ │ └── MyTopicActivity.vue
│ ├── MyMessage/
│ │ ├── CommentMessage/
│ │ │ ├── CommentMessage.css
│ │ │ └── CommentMessage.vue
│ │ ├── MyMessage.css
│ │ └── MyMessage.vue
│ ├── MyProfile/
│ │ ├── MyProfile.css
│ │ └── MyProfile.vue
│ ├── PublishTopic/
│ │ ├── PublishTopic.css
│ │ └── PublishTopic.vue
│ ├── SearchImage/
│ │ ├── SearchImage.css
│ │ └── SearchImage.vue
│ ├── SearchTopic/
│ │ ├── SearchTopic.css
│ │ └── SearchTopic.vue
│ └── TopicInfo/
│ ├── PublishComment/
│ │ ├── PublishComment.css
│ │ └── PublishComment.vue
│ ├── TopicInfo.css
│ ├── TopicInfo.vue
│ └── UserComment/
│ ├── UserComment.css
│ └── UserComment.vue
└── vue.config.js
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
/.idea
target
/temp
application-dev?.yml
application-prod.yml
application-prod?.yml
application-server.yml
application-server?.yml
application-common-secret.yml
application-qiniu.yml
================================================
FILE: README.md
================================================
# 次元印象
次元印象,一个SpringCloud构建的动漫交流论坛
## 前言
传说Github上的中国程序员有一半是二次元,于是~~为了吸引更多star~~我边学习SpringCloud技术边开发了这个动漫交流论坛。
## 项目介绍
**次元印象** ( **acimage**) 是一个**基于SpringCloud**构建的**前后端分离**的动漫交流论坛。后端使用 **SpringCloud**+**Mybatis-Plus**+**Reids**+**Rabbitmq**+**Elasticsearch**。前端使用 **Vue** + **ElementUi** + **Vite** 。项目已经上线。各位Github的二次元们,还不来点个star(๑•̀ㅂ•́)و✧。
## 网址
**次元印象o(*≧▽≦)ツ~动漫交流论坛** www.acimage.top (只适配网页端,如果画面显小,可以适当放大浏览器,视觉效果更佳)。
**首页**
**论坛页**
## 系统架构
## 项目功能
#### 用户前台
- **以图识图**,即上传图片,识别出论坛内相似图片及其所在话题。
- **多样化搜索**,可以同时根据关键词、分类、标签以及排序字段等搜索,并根据关键词高亮匹配文字。
- **相关话题推荐**,**随机推荐**。
- **话题排行榜**(按star、浏览量、评论数等、活跃时间排行)。
- **用户排行榜**(按话题数、star等排行)。
- 分类、标签,并且点击可筛选出符合相关分类或标签的话题。
- **实时展示最新活跃话题**。
- **敏感词过滤**,**图片压缩**。
- **消息通知**
- 查看个人动态、修改个人信息。
- 登录、注册、登出,**验证码防刷**,**邮箱验证**。
- 发表话题,评论,star等。
#### 后台管理
- 较为完善的RBAC权限控制,可动态调整用户角色、角色权限、接口权限等。
- 网站基本数据展示,访客量,接口调用数等。
- 首页轮播图片管理。
- 话题、评论、用户管理。
-
## 项目特点
- **JWT**实现单点登录,网关统一身份认证和鉴权,完善的**RBAC**权限控制。
- 利用**Redis+Lua脚本+定时任务**对变动比较频繁的数据(浏览量等)定时持久化。
- 利用**Redis+Lua脚本+自定义注解**,只需一个注解就可以实现针对ip、用户、和总体请求量的限流。
- 利用**Dhash**算法实现以图识图功能,效果还可以。
- 上传的图片均用webp压缩,极大地减少带宽压力。
## 项目目录
**后端服务**
- **acimage_gateway**:网关,统一身份认证、鉴权,分别针对用户和总体请求量的限流
- **acimage_user**:用户中心,用户注册、登录,邮箱服务等
- **acimage_community**:社区服务,负责论坛话题相关的核心功能
- **acimage_image**:图片服务,负责话题图片上传、头像上传、以图识图等功能
- **acimage_admin**: 管理服务
**后端模块**
- **acimage_common**:公共模块,存放实体类、公共的拦截器、公共配置以及公共工具类等
- **acimage_feign**:放置各个模块的feign客户端
**前端**
- **vue_manage_system**:后台管理页面
- **vue_acimage_web**:门户网站页面
**其它**
- **doc**: 一些文档、图片和数据库文件
## 运行与部署
**目前项目仍在不断完善,运行与部署流程以后再更新**。
- ~~将**doc/sql** 下的三个数据库分别导入到**mysql**中,四个数据库分别是四个前台服务对应的数据库~~
- ~~在每个服务的**application-dev.yml**文件中配置**mysql、redis、rabbitmq**、**nacos**相应的地址或账号密码~~
- ~~填写**acimage_common**中的**application-qiniu-template.yml**中的七牛云账号信息,包括**access-key**、**secret-key**、**domian**、**bucket**,或者给这四个属性随便赋值(不能为空,否则**NPE**),但是这样无法使用上传图片。并将**application-qiniu-template.yml**重命名为**application-qiniu.yml**~~
- ~~在**acimage_common**模块的下的**application.yml**配置 **nacos** 地址、**sentinel**地址(**sentinel**不配也不影响运行)~~
- ~~启动**nacos、redis、rabbitmq、mysql**~~
- ~~依次启动**acimage_user**、**acimage_community**、**acimage_image**、**acimage_gateway**,不这样启动的话可能会由于**rabbitmq**队列创建和绑定顺序的问题报错,如果遇到了,则全部服务再重新启动一遍。~~
- ~~运行前端(具体看**vue_acimage_web**的**README**)后点击默认弹出的链接即可访问首页~~
- ~~前台登录**:用户:wk,密码:wk123456
(还有几个用户可以从数据库sql文件看到,密码均为 用户名123456)~~
- 端口:
- **acimage_user**: 8100
- **acimage_image** : 8090
- **acimage_community**: 8080
- **acimage_gateway**: 8070
## 技术选型
#### 后端技术栈
**SpringBoot**、**SpringCloud**、**MyBatis-plus**、**Druid**(数据库连接池)、**Redis**(分布式缓存)、**Rabbitmq**(消息队列)、**Elasticsearch**(分布式搜索引擎)、**Minio**(对象存储服务)、**Nginx**(反向代理服务器)、**Docker**(应用容器引擎)
#### 用户界面前端
**Vue2**、**Vue Router**(路由)、**ElementUi**(Vue基础组件库)、**axios**(http客户端)、**jsencrypt**(基于RSA加解密的js库)、**vue-dompurify-html**(防xss攻击)、**tinymce-vue**(富文本编辑器)
#### 后台管理界面前端
**Vite**、**TypeSript**
## Todo
- [x] 分类、标签
- [x] 话题、用户排行榜
- [x] 随机推荐
- [x] 相似话题推荐
- [x] 敏感词过滤
- [x] 接口幂等
- [x] 细化限流
- [x] 完善RABC权限控制,网关统一身份认证及鉴权
- [x] 增加邮件服务,邮箱验证,验证码等
- [x] 将图片存储在minio(原来存储在七牛云)
- [x] elasticsearch多样化搜索,关键词高亮
- [x] 增加用户消息通知功能
- [ ] 利用redis+lua批量提取缓存中话题和浏览量等,减少通信次数,实时展示数据。
- [ ] 增加评论表情
- [ ] 增加关注功能
- [ ] 完善sentinel和nacos等配置和使用
- [ ] 增加爬虫模块
- [ ] 完善单元测试
- [ ] 等等等
## 交流
项目起初是为了学习技术搭建的,由于能力有限,还有很多不完善的地方,欢迎各位能够指正。如果有人感兴趣(多么希望真的有人感兴趣 手动捂脸)或者该项目遇到什么问题或有什么建议提issue,可联系邮箱1179836161@qq.com或进群692992463交流。喜欢的话记得点个star。
## 网站截图
**Web端**













**Admin端**
管理系统随便放几张吧,反正管理系统都长一个样。


## 开源协议
[Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0.html)
================================================
FILE: acimage_admin/.gitignore
================================================
/target/
================================================
FILE: acimage_admin/pom.xml
================================================
acimage
com.acimage
0.0.1-SNAPSHOT
4.0.0
acimage_admin
jar
acimage_admin
http://maven.apache.org
UTF-8
com.acimage
acimage_common
0.0.1-SNAPSHOT
com.acimage
acimage_feign
0.0.1-SNAPSHOT
org.springframework.boot
spring-boot-starter-aop
com.alibaba
druid
mysql
mysql-connector-java
runtime
com.baomidou
dynamic-datasource-spring-boot-starter
io.minio
minio
junit
junit
3.8.1
test
org.springframework.boot
spring-boot-maven-plugin
true
org.apache.maven.plugins
maven-surefire-plugin
true
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/AdminApplication.java
================================================
package com.acimage.admin;
import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableScheduling;
@Slf4j
@SpringBootApplication
@EnableDiscoveryClient
@EnableScheduling
@EnableFeignClients(basePackages="com.acimage.feign")
@ComponentScan(value={"com.acimage"})
@MapperScan(basePackages = {"com.acimage.admin.dao"})
public class AdminApplication {
public static void main(String[] args) {
SpringApplication.run(AdminApplication.class, args);
log.info("------------->>>Admin启动<<<-------------");
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/config/WebMvcConfig.java
================================================
package com.acimage.admin.config;
import com.acimage.common.web.interceptor.AccessInterceptor;
import com.acimage.common.web.interceptor.JwtInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Slf4j
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AccessInterceptor()).addPathPatterns("/**").order(30);
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/config/mybatis/CommunityDataSourceConfig.java
================================================
package com.acimage.admin.config.mybatis;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
@Deprecated
//@Configuration
//@MapperScan(basePackages = "com.acimage.admin.dao.community", sqlSessionFactoryRef = "communitySqlSessionFactory")
public class CommunityDataSourceConfig {
@Bean(name = "communityDataSource")
@ConfigurationProperties(prefix = "spring.datasource.community")
public DataSource communityDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "communitySqlSessionFactory")
public SqlSessionFactory orderSqlSessionFactory(@Qualifier("communityDataSource")DataSource dataSource,@Autowired GlobalConfig globalConfig) throws Exception {
MybatisSqlSessionFactoryBean sqlSessionFactoryBean=new MybatisSqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
sqlSessionFactoryBean.setGlobalConfig(globalConfig);
sqlSessionFactoryBean.setTypeAliasesPackage("com.acimage.common.model.domain");
sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/community/*.xml"));
sqlSessionFactoryBean.setTypeHandlersPackage("com.acimage.admin.config.mybatis.typehandler");
return sqlSessionFactoryBean.getObject();
}
@Bean(name = "communityTransactionManager")
public DataSourceTransactionManager orderTransactionManager(@Qualifier("communityDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean(name = "communitySqlSessionTemplate")
public SqlSessionTemplate memberSqlSessionTemplate(
@Qualifier("communitySqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/config/mybatis/GlobalConfigBean.java
================================================
package com.acimage.admin.config.mybatis;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
//@Configuration
@Deprecated
public class GlobalConfigBean {
@Bean
@ConfigurationProperties(prefix = "mybatis-plus.global-config")
GlobalConfig globalConfig(){
return new GlobalConfig();
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/config/mybatis/ImageDataSourceConfig.java
================================================
package com.acimage.admin.config.mybatis;
import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
@Deprecated
//@Configuration
//@MapperScan(basePackages = "com.acimage.admin.dao.image", sqlSessionFactoryRef = "imageSqlSessionFactory",sqlSessionTemplateRef ="imageSqlSessionTemplate")
public class ImageDataSourceConfig {
@Bean(name = "imageDataSource")
@ConfigurationProperties(prefix = "spring.datasource.image")
public DataSource imageDataSource() {
return DataSourceBuilder.create().build();
}
// @Bean
// @ConfigurationProperties(prefix = "mybatis-plus.global-config")
// GlobalConfig globalConfig(){
// return new GlobalConfig();
// }
@Bean(name = "imageSqlSessionFactory")
public SqlSessionFactory imageSqlSessionFactory(@Qualifier("imageDataSource") DataSource dataSource, @Autowired GlobalConfig globalConfig) throws Exception {
MybatisSqlSessionFactoryBean sqlSessionFactoryBean=new MybatisSqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
sqlSessionFactoryBean.setGlobalConfig(globalConfig);
sqlSessionFactoryBean.setTypeAliasesPackage("com.acimage.common.model.domain");
sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/image/*.xml"));
sqlSessionFactoryBean.setTypeHandlersPackage("com.acimage.admin.config.mybatis.typehandler");
return sqlSessionFactoryBean.getObject();
}
@Bean(name = "imageTransactionManager")
public DataSourceTransactionManager imageTransactionManager(@Qualifier("imageDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean(name = "imageSqlSessionTemplate")
public SqlSessionTemplate memberSqlSessionTemplate(
@Qualifier("imageSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/dao/community/CategoryDao.java
================================================
package com.acimage.admin.dao.community;
import com.acimage.common.model.domain.community.Category;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface CategoryDao extends BaseMapper {
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/dao/community/CommentDao.java
================================================
package com.acimage.admin.dao.community;
import com.acimage.common.model.domain.community.Comment;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface CommentDao extends BaseMapper {
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/dao/community/HomeCarouselDao.java
================================================
package com.acimage.admin.dao.community;
import com.acimage.common.model.domain.community.HomeCarousel;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
public interface HomeCarouselDao extends BaseMapper {
@Select("select coalesce(max(location),0) from tb_home_carousel")
Integer getMaxLocation();
List count();
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/dao/community/TopicDao.java
================================================
package com.acimage.admin.dao.community;
import com.acimage.common.model.domain.community.Topic;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface TopicDao extends BaseMapper {
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/dao/sys/ApiDao.java
================================================
package com.acimage.admin.dao.sys;
import com.acimage.common.model.domain.sys.Api;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface ApiDao extends BaseMapper {
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/dao/sys/AuthorizeDao.java
================================================
package com.acimage.admin.dao.sys;
import com.acimage.common.model.domain.sys.Authorize;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface AuthorizeDao extends BaseMapper {
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/dao/sys/PermissionDao.java
================================================
package com.acimage.admin.dao.sys;
import com.acimage.common.model.domain.sys.Permission;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import javax.annotation.Nullable;
import java.util.List;
public interface PermissionDao extends BaseMapper {
List selectTreeByParentId(@Nullable @Param("parentId") Integer parentId);
List selectPermissionsWithParent(@Param("startIndex") int startIndex,@Param("recordNumber") int recordNumber);
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/dao/sys/RoleDao.java
================================================
package com.acimage.admin.dao.sys;
import com.acimage.common.model.domain.sys.Role;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface RoleDao extends BaseMapper {
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/dao/sys/UserRoleDao.java
================================================
package com.acimage.admin.dao.sys;
import com.acimage.common.model.domain.sys.UserRole;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface UserRoleDao extends BaseMapper {
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/dao/user/UserDao.java
================================================
package com.acimage.admin.dao.user;
import com.acimage.common.model.domain.user.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface UserDao extends BaseMapper {
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/dao/user/UserPrivacyDao.java
================================================
package com.acimage.admin.dao.user;
import com.acimage.common.model.domain.user.UserPrivacy;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface UserPrivacyDao extends BaseMapper {
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/global/consts/ModuleConstants.java
================================================
package com.acimage.admin.global.consts;
public class ModuleConstants {
public static final String COMMUNITY="community";
public static final String SYS="sys";
public static final String IMAGE="image";
public static final String USER="user";
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/model/request/AdminLoginReq.java
================================================
package com.acimage.admin.model.request;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.Email;
import javax.validation.constraints.Size;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class AdminLoginReq {
@Email(message = "邮箱格式错误")
@Size(min=6,max=32,message = "邮箱长度在6到32之间")
private String email;
@Size(min = 100, max = 2000, message = "非法密码")
String password;
@Size(min=4,max=6,message = "验证码长度不符")
String verifyCode;
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/model/request/ApiAddReq.java
================================================
package com.acimage.admin.model.request;
import com.acimage.common.global.enums.MatchRule;
import com.acimage.common.global.enums.MyHttpMethod;
import com.acimage.common.model.domain.sys.Api;
import com.acimage.common.model.domain.sys.Permission;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.http.HttpMethod;
import javax.annotation.Nullable;
import javax.validation.constraints.*;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ApiAddReq {
public static final int PATH_MAX = 200;
public static final int PATH_MIN = 2;
public static final int NOTE_MAX = 100;
@NotBlank
@Pattern(regexp = Api.PATH_PATTERN)
@Size(min= Api.PATH_MIN,max=Api.PATH_MAX)
String path;
@NotNull
MyHttpMethod method;
@Positive
@NotNull
Integer permissionId;
@Size(max=Api.NOTE_MAX)
String note;
boolean enable;
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/model/request/ApiModifyReq.java
================================================
package com.acimage.admin.model.request;
import com.acimage.common.global.enums.MatchRule;
import com.acimage.common.global.enums.MyHttpMethod;
import com.acimage.common.model.domain.sys.Api;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.http.HttpMethod;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Positive;
import javax.validation.constraints.Size;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ApiModifyReq {
public static final int PATH_MAX = 200;
public static final int PATH_MIN = 2;
public static final int NOTE_MAX = 100;
@Positive
Integer id;
@Size(min = Api.PATH_MIN, max = Api.PATH_MAX)
@Pattern(regexp = Api.PATH_PATTERN)
String path;
@NotNull
MyHttpMethod method;
@Positive
@NotNull
Integer permissionId;
@Size(max = Api.NOTE_MAX)
String note;
boolean enable;
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/model/request/ApiQueryReq.java
================================================
package com.acimage.admin.model.request;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ApiQueryReq {
String keyword;
@Min(1)
Integer pageNo;
@Min(2)
@Max(20)
Integer pageSize;
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/model/request/CarouselAddReq.java
================================================
package com.acimage.admin.model.request;
import com.acimage.common.model.domain.community.HomeCarousel;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
@Data
@NoArgsConstructor
public class CarouselAddReq {
@Size(min = HomeCarousel.DESC_MIN, max = HomeCarousel.DESC_MAX, message = HomeCarousel.DESC_INVALID_MSG)
String description;
@NotNull
@Size(min = 0, max = HomeCarousel.LINK_MAX, message = HomeCarousel.LINK_INVALID_MSG)
String link;
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/model/request/CarouselModifyReq.java
================================================
package com.acimage.admin.model.request;
import com.acimage.common.model.domain.community.HomeCarousel;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Positive;
import javax.validation.constraints.Size;
@Data
@NoArgsConstructor
public class CarouselModifyReq {
@NotNull
@Positive
private Integer id;
@Size(min = HomeCarousel.DESC_MIN, max = HomeCarousel.DESC_MAX, message = HomeCarousel.DESC_INVALID_MSG)
String description;
@NotNull
@Size(min = 0, max = HomeCarousel.LINK_MAX, message = HomeCarousel.LINK_INVALID_MSG)
String link;
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/model/request/CommentQueryReq.java
================================================
package com.acimage.admin.model.request;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Range;
import javax.validation.constraints.*;
@Data
@NoArgsConstructor
public class CommentQueryReq {
Long topicId;
String keyword;
@Range(min=1)
Integer pageNo;
@Range(min=5,max=20)
Integer pageSize;
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/model/request/PermissionAddReq.java
================================================
package com.acimage.admin.model.request;
import com.acimage.common.model.domain.sys.Permission;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
@Data
@NoArgsConstructor
public class PermissionAddReq {
Integer parentId;
@Size(max = Permission.CODE_MAX,message =Permission.CODE_VALIDATION_MSG)
String code;
@Size(max = Permission.NOTE_MAX,message =Permission.NOTE_VALIDATION_MSG)
String note;
@NotNull
@Size(max = Permission.LABEL_MAX,message =Permission.LABEL_VALIDATION_MSG)
String label;
@NotNull
Boolean module;
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/model/request/PermissionModifyReq.java
================================================
package com.acimage.admin.model.request;
import com.acimage.common.model.domain.sys.Permission;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Positive;
import javax.validation.constraints.Size;
@Data
@NoArgsConstructor
public class PermissionModifyReq {
@Positive
Integer id;
Integer parentId;
@Size(max = Permission.CODE_MAX,message =Permission.CODE_VALIDATION_MSG)
String code;
@Size(max = Permission.NOTE_MAX,message =Permission.NOTE_VALIDATION_MSG)
String note;
@NotNull
@Size(max = Permission.LABEL_MAX,message =Permission.LABEL_VALIDATION_MSG)
String label;
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/model/request/RoleAddReq.java
================================================
package com.acimage.admin.model.request;
import com.acimage.common.model.domain.sys.Role;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.Size;
@Data
@NoArgsConstructor
public class RoleAddReq {
@Size(max= Role.ROLE_NAME_MAX,min=Role.ROLE_NAME_MIN,message = Role.ROLE_NAME_VALIDATION_MSG)
String roleName;
@Size(max=Role.NOTE_MAX,message = Role.NOTE_VALIDATION_MSG)
String note;
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/model/request/RoleModifyReq.java
================================================
package com.acimage.admin.model.request;
import com.acimage.common.model.domain.sys.Role;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.Positive;
import javax.validation.constraints.Size;
@Data
@NoArgsConstructor
public class RoleModifyReq {
@Positive
Integer id;
@Size(max= Role.ROLE_NAME_MAX,min=Role.ROLE_NAME_MIN,message = Role.ROLE_NAME_VALIDATION_MSG)
String roleName;
@Size(max=Role.NOTE_MAX,message = Role.NOTE_VALIDATION_MSG)
String note;
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/model/request/TopicQueryReq.java
================================================
package com.acimage.admin.model.request;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Range;
import javax.validation.constraints.*;
@Data
@NoArgsConstructor
public class TopicQueryReq {
@NotBlank
String column;
@Positive
@NotNull
Integer pageNo;
@Range(min=5,max=20)
Integer pageSize;
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/model/request/UserQueryReq.java
================================================
package com.acimage.admin.model.request;
import lombok.Data;
import javax.validation.constraints.*;
@Data
public class UserQueryReq {
String keyword;
@NotNull
@Positive
Integer pageNo;
@Min(2)
@Max(20)
Integer pageSize;
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/model/vo/WebsiteDataVo.java
================================================
package com.acimage.admin.model.vo;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
public class WebsiteDataVo {
private Integer pageView;
private Integer apiAccessCount;
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/api/ApiQueryService.java
================================================
package com.acimage.admin.service.api;
import com.acimage.admin.model.request.ApiQueryReq;
import com.acimage.common.model.domain.sys.Api;
import com.acimage.common.model.page.MyPage;
public interface ApiQueryService {
MyPage pageBy(ApiQueryReq apiQueryReq);
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/api/ApiWriteService.java
================================================
package com.acimage.admin.service.api;
import com.acimage.admin.model.request.ApiAddReq;
import com.acimage.admin.model.request.ApiModifyReq;
public interface ApiWriteService {
void save(ApiAddReq apiAddReq);
void update(ApiModifyReq apiModifyReq);
void delete(int id);
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/api/impl/ApiQueryServiceImpl.java
================================================
package com.acimage.admin.service.api.impl;
import com.acimage.admin.dao.sys.ApiDao;
import com.acimage.admin.global.consts.ModuleConstants;
import com.acimage.admin.model.request.ApiQueryReq;
import com.acimage.admin.service.api.ApiQueryService;
import com.acimage.common.model.domain.sys.Api;
import com.acimage.common.model.page.MyPage;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
@DS(ModuleConstants.SYS)
public class ApiQueryServiceImpl implements ApiQueryService {
@Autowired
ApiDao apiDao;
@Override
public MyPage pageBy(ApiQueryReq apiQueryReq) {
IPage page = new Page<>(apiQueryReq.getPageNo(), apiQueryReq.getPageSize());
LambdaQueryWrapper qw = new LambdaQueryWrapper<>();
qw.orderByAsc(Api::getPath);
String keyword = apiQueryReq.getKeyword();
if (keyword != null) {
qw.like(Api::getPath, keyword);
}
IPage resultPage=apiDao.selectPage(page, qw);
return MyPage.from(resultPage);
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/api/impl/ApiWriteServiceImpl.java
================================================
package com.acimage.admin.service.api.impl;
import com.acimage.admin.dao.sys.ApiDao;
import com.acimage.admin.global.consts.ModuleConstants;
import com.acimage.admin.model.request.ApiAddReq;
import com.acimage.admin.model.request.ApiModifyReq;
import com.acimage.admin.service.api.ApiWriteService;
import com.acimage.admin.service.permission.PermissionQueryService;
import com.acimage.common.global.exception.BusinessException;
import com.acimage.common.model.domain.sys.Api;
import com.acimage.common.model.domain.sys.Permission;
import com.acimage.common.utils.common.BeanUtils;
import com.acimage.common.utils.common.ListUtils;
import com.baomidou.dynamic.datasource.annotation.DS;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.List;
@Service
@DS(ModuleConstants.SYS)
public class ApiWriteServiceImpl implements ApiWriteService {
@Autowired
ApiDao apiDao;
@Autowired
PermissionQueryService permissionQueryService;
@Override
public void save(ApiAddReq apiAddReq){
List permissionList=permissionQueryService.listByModule(false);
List permissionIds= ListUtils.extract(Permission::getId,permissionList);
if(!permissionIds.contains(apiAddReq.getPermissionId())){
throw new BusinessException("权限不存在或非可用权限");
}
Api api= BeanUtils.copyPropertiesTo(apiAddReq,Api.class);
api.setCreateTime(new Date());
api.setUpdateTime(new Date());
apiDao.insert(api);
}
@Override
public void update(ApiModifyReq apiModifyReq){
List permissionList=permissionQueryService.listByModule(false);
List permissionIds= ListUtils.extract(Permission::getId,permissionList);
if(!permissionIds.contains(apiModifyReq.getPermissionId())){
throw new BusinessException("权限不存在或非可用权限");
}
Api api= BeanUtils.copyPropertiesTo(apiModifyReq,Api.class);
api.setCreateTime(new Date());
api.setUpdateTime(new Date());
apiDao.updateById(api);
}
@Override
public void delete(int id){
apiDao.deleteById(id);
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/authorize/AuthorizeQueryService.java
================================================
package com.acimage.admin.service.authorize;
import com.acimage.common.model.domain.sys.Authorize;
import java.util.List;
public interface AuthorizeQueryService {
List listAuthorizeByRoleId(int roleId);
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/authorize/AuthorizeWriteService.java
================================================
package com.acimage.admin.service.authorize;
public interface AuthorizeWriteService {
void save(int roleId, int permissionId);
void remove(int roleId, int permissionId);
void remove(int permissionId);
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/authorize/impl/AuthorizeQueryServiceImpl.java
================================================
package com.acimage.admin.service.authorize.impl;
import com.acimage.admin.dao.sys.AuthorizeDao;
import com.acimage.admin.service.authorize.AuthorizeQueryService;
import com.acimage.common.model.domain.sys.Authorize;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
@DS("sys")
public class AuthorizeQueryServiceImpl implements AuthorizeQueryService {
@Autowired
AuthorizeDao authorizeDao;
@Override
public List listAuthorizeByRoleId(int roleId){
LambdaQueryWrapper qw=new LambdaQueryWrapper<>();
qw.eq(Authorize::getRoleId,roleId);
return authorizeDao.selectList(qw);
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/authorize/impl/AuthorizeWriteServiceImpl.java
================================================
package com.acimage.admin.service.authorize.impl;
import com.acimage.admin.dao.sys.AuthorizeDao;
import com.acimage.admin.service.authorize.AuthorizeWriteService;
import com.acimage.admin.service.permission.PermissionQueryService;
import com.acimage.common.global.exception.BusinessException;
import com.acimage.common.model.domain.sys.Authorize;
import com.acimage.common.model.domain.sys.Permission;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
@DS("sys")
public class AuthorizeWriteServiceImpl implements AuthorizeWriteService {
@Autowired
AuthorizeDao authorizeDao;
@Autowired
PermissionQueryService permissionQueryService;
@Override
public void save(int roleId, int permissionId) {
Permission permission = permissionQueryService.getPermission(permissionId);
if (permission.isModule()) {
throw new BusinessException("该结点为模块,不可授权");
}
Authorize authorize = new Authorize(roleId, permissionId);
authorizeDao.insert(authorize);
}
@Override
public void remove(int roleId, int permissionId) {
LambdaQueryWrapper uw = new LambdaQueryWrapper<>();
uw.eq(Authorize::getRoleId, roleId)
.eq(Authorize::getPermissionId, permissionId);
authorizeDao.delete(uw);
}
@Override
public void remove(int permissionId) {
LambdaQueryWrapper uw = new LambdaQueryWrapper<>();
uw.eq(Authorize::getPermissionId, permissionId);
authorizeDao.delete(uw);
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/category/CategoryQueryService.java
================================================
package com.acimage.admin.service.category;
import com.acimage.common.model.domain.community.Category;
import java.util.List;
public interface CategoryQueryService {
List listAll();
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/category/impl/CategoryQueryServiceImpl.java
================================================
package com.acimage.admin.service.category.impl;
import com.acimage.admin.dao.community.CategoryDao;
import com.acimage.admin.global.consts.ModuleConstants;
import com.acimage.admin.service.category.CategoryQueryService;
import com.acimage.common.model.domain.community.Category;
import com.baomidou.dynamic.datasource.annotation.DS;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@DS(ModuleConstants.COMMUNITY)
@Service
public class CategoryQueryServiceImpl implements CategoryQueryService {
@Autowired
CategoryDao categoryDao;
@Override
public List listAll(){
return categoryDao.selectList(null);
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/comment/CommentQueryService.java
================================================
package com.acimage.admin.service.comment;
import com.acimage.admin.model.request.CommentQueryReq;
import com.acimage.common.model.domain.community.Comment;
import com.acimage.common.model.page.MyPage;
public interface CommentQueryService {
MyPage pageCommentsBy(CommentQueryReq commentQueryReq);
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/comment/CommentWriteService.java
================================================
package com.acimage.admin.service.comment;
public interface CommentWriteService {
void delete(long id);
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/comment/impl/CommentQueryServiceImpl.java
================================================
package com.acimage.admin.service.comment.impl;
import cn.hutool.core.util.StrUtil;
import com.acimage.admin.dao.community.CommentDao;
import com.acimage.admin.global.consts.ModuleConstants;
import com.acimage.admin.model.request.CommentQueryReq;
import com.acimage.admin.service.comment.CommentQueryService;
import com.acimage.common.model.domain.community.Comment;
import com.acimage.common.model.page.MyPage;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
@DS(ModuleConstants.COMMUNITY)
public class CommentQueryServiceImpl implements CommentQueryService {
@Autowired
CommentDao commentDao;
@Override
public MyPage pageCommentsBy(CommentQueryReq commentQueryReq) {
String keyword=commentQueryReq.getKeyword();
Long topicId=commentQueryReq.getTopicId();
int pageNo = commentQueryReq.getPageNo();
int pageSize = commentQueryReq.getPageSize();
IPage page=new Page<>(pageNo,pageSize);
LambdaQueryWrapper qw = new LambdaQueryWrapper<>();
qw.orderByDesc(Comment::getCreateTime);
if(!StrUtil.isBlank(keyword)){
qw.like(Comment::getContent,keyword);
}
if(topicId!=null&&topicId>0){
qw.eq(Comment::getTopicId,topicId);
}
IPage resultPage = commentDao.selectPage(page,qw);
return MyPage.from(resultPage);
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/comment/impl/CommentWriteServiceImpl.java
================================================
package com.acimage.admin.service.comment.impl;
import com.acimage.admin.global.consts.ModuleConstants;
import com.acimage.admin.service.comment.CommentWriteService;
import com.acimage.feign.client.CommentClient;
import com.baomidou.dynamic.datasource.annotation.DS;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
@DS(ModuleConstants.COMMUNITY)
public class CommentWriteServiceImpl implements CommentWriteService {
@Autowired
private CommentClient client;
@Override
public void delete(long id){
client.delete(id);
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/homecarousel/HomeCarouselQueryService.java
================================================
package com.acimage.admin.service.homecarousel;
import com.acimage.common.model.domain.community.HomeCarousel;
import java.util.List;
public interface HomeCarouselQueryService {
List listCurrent();
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/homecarousel/HomeCarouselWriteService.java
================================================
package com.acimage.admin.service.homecarousel;
import com.acimage.admin.model.request.CarouselAddReq;
import com.acimage.admin.model.request.CarouselModifyReq;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
public interface HomeCarouselWriteService {
@Transactional(rollbackFor = Exception.class)
void saveHomeCarouselImage(MultipartFile multipartFile, CarouselAddReq carouselAddReq);
void deleteHomeCarouselImage(long id);
void updateHomeCarouselImage(CarouselModifyReq modifyReq);
@Transactional(rollbackFor = Exception.class)
void coverHomeCarouselImage(long id, MultipartFile multipartFile);
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/homecarousel/impl/HomeCarouselQueryServiceImpl.java
================================================
package com.acimage.admin.service.homecarousel.impl;
import com.acimage.admin.dao.community.HomeCarouselDao;
import com.acimage.admin.global.consts.ModuleConstants;
import com.acimage.admin.service.homecarousel.HomeCarouselQueryService;
import com.acimage.common.model.domain.community.HomeCarousel;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
@DS(ModuleConstants.COMMUNITY)
public class HomeCarouselQueryServiceImpl implements HomeCarouselQueryService {
@Autowired
HomeCarouselDao homeCarouselDao;
@Override
public List listCurrent() {
LambdaQueryWrapper qw = new LambdaQueryWrapper<>();
qw.orderByAsc(HomeCarousel::getLocation);
return homeCarouselDao.selectList(qw);
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/homecarousel/impl/HomeCarouselWriteServiceImpl.java
================================================
package com.acimage.admin.service.homecarousel.impl;
import cn.hutool.core.util.RandomUtil;
import com.acimage.admin.dao.community.HomeCarouselDao;
import com.acimage.admin.global.consts.ModuleConstants;
import com.acimage.admin.model.request.CarouselAddReq;
import com.acimage.admin.model.request.CarouselModifyReq;
import com.acimage.admin.service.homecarousel.HomeCarouselWriteService;
import com.acimage.common.global.consts.StorePrefixConstants;
import com.acimage.common.global.context.UserContext;
import com.acimage.common.global.exception.BusinessException;
import com.acimage.common.model.domain.community.HomeCarousel;
import com.acimage.common.utils.common.FileUtils;
import com.acimage.common.utils.IdGenerator;
import com.acimage.common.utils.minio.MinioUtils;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.util.Date;
@Slf4j
@Service
@DS(ModuleConstants.COMMUNITY)
public class HomeCarouselWriteServiceImpl implements HomeCarouselWriteService {
@Autowired
HomeCarouselDao homeCarouselDao;
@Autowired
MinioUtils minioUtils;
@Override
public void saveHomeCarouselImage(MultipartFile multipartFile, CarouselAddReq carouselAddReq) {
String description = carouselAddReq.getDescription();
String link = carouselAddReq.getLink().trim();
int length = 5;
String idString = RandomUtil.randomString(length);
int size = (int) multipartFile.getSize();
int location = homeCarouselDao.getMaxLocation() + 1;
Date now = new Date();
String fileName = String.format("%s.%s", idString, FileUtils.formatOf(multipartFile));
String url = minioUtils.generateBaseUrl(StorePrefixConstants.HOME_CAROUSEL, now, fileName);
String newUrl = minioUtils.upload(multipartFile, url);
HomeCarousel homeCarousel = new HomeCarousel();
homeCarousel.setSize(size);
homeCarousel.setDescription(description);
homeCarousel.setCreateTime(now);
homeCarousel.setUpdateTime(now);
homeCarousel.setUrl(newUrl);
homeCarousel.setLocation(location);
homeCarousel.setLink(link);
homeCarouselDao.insert(homeCarousel);
}
@Override
public void deleteHomeCarouselImage(long id) {
HomeCarousel homeCarousel = homeCarouselDao.selectById(id);
if (homeCarousel == null) {
log.error("用户:{} 操作:删除主页走马灯 特殊图片id:{} 错误:图片不存在", UserContext.getUsername(), id);
throw new BusinessException("该图片不存在");
}
LambdaUpdateWrapper qw = new LambdaUpdateWrapper<>();
qw.eq(HomeCarousel::getId, id);
int col = homeCarouselDao.delete(qw);
minioUtils.deleteFile(homeCarousel.getUrl());
}
@Override
public void updateHomeCarouselImage(CarouselModifyReq modifyReq) {
Integer id = modifyReq.getId();
String description = modifyReq.getDescription();
String link = modifyReq.getLink();
LambdaUpdateWrapper uw = new LambdaUpdateWrapper<>();
uw.set(HomeCarousel::getDescription, description)
.set(HomeCarousel::getLink, link)
.set(HomeCarousel::getUpdateTime, new Date())
.eq(HomeCarousel::getId, id);
int col = homeCarouselDao.update(null, uw);
if (col == 0) {
log.error("用户:{} 操作:修改主页走马灯描述 特殊图片id:{} 错误:图片非主页走马灯图片", UserContext.getUsername(), id);
throw new BusinessException("该主页走马灯图片不存在");
}
}
@Override
public void coverHomeCarouselImage(long id, MultipartFile multipartFile) {
HomeCarousel homeCarousel = homeCarouselDao.selectById(id);
if (homeCarouselDao == null) {
log.error("用户:{} 操作:覆盖主页走马灯 特殊图片id:{} 错误:图片不存在", UserContext.getUsername(), id);
throw new BusinessException("图片不存在");
}
int size = (int) multipartFile.getSize();
Date now = new Date();
String oldUrl = homeCarousel.getUrl();
String suffix = String.format("%s.%s", IdGenerator.getSnowflakeNextId(), FileUtils.formatOf(multipartFile));
String newUrl = minioUtils.generateBaseUrl(StorePrefixConstants.HOME_CAROUSEL, now, suffix);
newUrl = minioUtils.upload(multipartFile, newUrl);
LambdaUpdateWrapper uw = new LambdaUpdateWrapper<>();
uw.set(HomeCarousel::getSize, size)
.set(HomeCarousel::getUpdateTime, now)
.set(HomeCarousel::getUrl, newUrl)
.eq(HomeCarousel::getId, id);
homeCarouselDao.update(null, uw);
//删除文件
minioUtils.deleteFile(oldUrl);
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/login/LoginService.java
================================================
package com.acimage.admin.service.login;
import com.acimage.admin.model.request.AdminLoginReq;
public interface LoginService {
String login(AdminLoginReq adminLoginReq);
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/login/VerifyCodeService.java
================================================
package com.acimage.admin.service.login;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public interface VerifyCodeService {
void writeCodeImageToResponseAndRecord(HttpServletRequest request, HttpServletResponse response);
boolean verifyAndRemoveIfSuccess(HttpServletRequest request, String code);
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/login/impl/LoginServiceImpl.java
================================================
package com.acimage.admin.service.login.impl;
import cn.hutool.crypto.digest.DigestUtil;
import com.acimage.admin.dao.user.UserDao;
import com.acimage.admin.dao.user.UserPrivacyDao;
import com.acimage.admin.global.consts.ModuleConstants;
import com.acimage.admin.model.request.AdminLoginReq;
import com.acimage.admin.service.login.LoginService;
import com.acimage.common.global.consts.JwtConstants;
import com.acimage.common.global.exception.BusinessException;
import com.acimage.common.model.domain.user.User;
import com.acimage.common.model.domain.user.UserPrivacy;
import com.acimage.common.service.TokenService;
import com.acimage.common.utils.RsaUtils;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Slf4j
@Service
@DS(ModuleConstants.USER)
public class LoginServiceImpl implements LoginService {
@Autowired
UserPrivacyDao userPrivacyDao;
@Autowired
UserDao userDao;
@Autowired
TokenService tokenService;
@Override
public String login(AdminLoginReq adminLoginReq) {
String email = adminLoginReq.getEmail();
String password = adminLoginReq.getPassword();
LambdaQueryWrapper qw = new LambdaQueryWrapper<>();
qw.eq(UserPrivacy::getEmail, email);
UserPrivacy userPrivacy = userPrivacyDao.selectOne(qw);
if (userPrivacy == null) {
throw new BusinessException("邮箱不存在");
}
//找到密码
long userId=userPrivacy.getUserId();
String salt = userPrivacy.getSalt();
String passwordDigest = userPrivacy.getPwd();
//获取私钥
String privateKey = RsaUtils.getPrivateKey();
//解密密码
String passwordDecrypt = RsaUtils.decrypt(privateKey, password);
// log.debug(" decrypt as:{}", passwordDecrypt);
//判断密码正确性
if (!DigestUtil.md5Hex(salt + passwordDecrypt).equals(passwordDigest)) {
log.warn("登录 错误:邮箱{} 或密码错误", email);
throw new BusinessException("用户名或密码错误");
}
//返回token
User user=userDao.selectById(userId);
return tokenService.createAndRecordToken(userId,
user.getUsername(),
user.getPhotoUrl(),
JwtConstants.ADMIN_EXPIRE_DAYS);
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/login/impl/VerifyCodeServiceImpl.java
================================================
package com.acimage.admin.service.login.impl;
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.ShearCaptcha;
import com.acimage.admin.service.login.VerifyCodeService;
import com.acimage.common.utils.redis.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
@Slf4j
@Service
public class VerifyCodeServiceImpl implements VerifyCodeService {
@Autowired
RedisUtils redisUtils;
public static final String STRINGKP_VERIFY_CODE="acimage:admin:verifyCode:sessionId:";
@Override
public void writeCodeImageToResponseAndRecord(HttpServletRequest request, HttpServletResponse response){
int width=100;
int height=40;
int codeCount=4;
int thickness=4;
ShearCaptcha captcha = CaptchaUtil.createShearCaptcha(width, height, codeCount, thickness);
//图形验证码写出,可以写出到文件,也可以写出到流
try {
captcha.write(response.getOutputStream());
} catch (IOException e) {
log.error("response.getOutputStream()错误 {}",e.getMessage());
throw new RuntimeException(e);
}
//获取验证码中的文字内容
String verifyCode = captcha.getCode();
//记录到redis
String sessionId=request.getSession().getId();
long timeout=30L;
redisUtils.setAsString(STRINGKP_VERIFY_CODE+sessionId,verifyCode,timeout, TimeUnit.SECONDS);
}
@Override
public boolean verifyAndRemoveIfSuccess(HttpServletRequest request, String code){
String key=STRINGKP_VERIFY_CODE+request.getSession().getId();
String trueCode=redisUtils.getForString(key);
if(trueCode==null){
return false;
}
if(trueCode.equals(code)){
redisUtils.delete(key);
return true;
}else{
return false;
}
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/permission/PermissionQueryService.java
================================================
package com.acimage.admin.service.permission;
import com.acimage.common.model.domain.sys.Permission;
import com.acimage.common.model.page.MyPage;
import java.util.List;
public interface PermissionQueryService {
Permission getPermission(int id);
List getPermissionTree();
MyPage pagePermissionsWithParent(int pageNo, int pageSize);
List listByModule(boolean isModule);
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/permission/PermissionWriteSercice.java
================================================
package com.acimage.admin.service.permission;
import com.acimage.admin.model.request.PermissionAddReq;
import com.acimage.admin.model.request.PermissionModifyReq;
import org.springframework.transaction.annotation.Transactional;
public interface PermissionWriteSercice {
void save(PermissionAddReq permissionAddReq);
@Transactional
void remove(int id);
@Transactional
void update(PermissionModifyReq permissionModifyReq);
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/permission/impl/PermissionQueryServiceImpl.java
================================================
package com.acimage.admin.service.permission.impl;
import com.acimage.admin.dao.sys.PermissionDao;
import com.acimage.admin.service.permission.PermissionQueryService;
import com.acimage.common.model.domain.sys.Permission;
import com.acimage.common.model.page.MyPage;
import com.acimage.common.utils.common.PageUtils;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
@DS("sys")
public class PermissionQueryServiceImpl implements PermissionQueryService {
@Autowired
PermissionDao permissionDao;
@Override
public Permission getPermission(int id){
return permissionDao.selectById(id);
}
@Override
public List getPermissionTree(){
return permissionDao.selectTreeByParentId(null);
}
@Override
public MyPage pagePermissionsWithParent(int pageNo, int pageSize){
int startIndex= PageUtils.startIndexOf(pageNo,pageSize);
List permissionList= permissionDao.selectPermissionsWithParent(startIndex,pageSize);
int count=permissionDao.selectCount(null);
return new MyPage<>(count,permissionList);
}
@Override
public List listByModule(boolean isModule){
LambdaQueryWrapper qw=new LambdaQueryWrapper<>();
qw.eq(Permission::isModule,isModule).orderByDesc(Permission::getCode);
return permissionDao.selectList(qw);
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/permission/impl/PermissionWriteServiceImpl.java
================================================
package com.acimage.admin.service.permission.impl;
import cn.hutool.core.bean.BeanUtil;
import com.acimage.admin.dao.sys.PermissionDao;
import com.acimage.admin.global.consts.ModuleConstants;
import com.acimage.admin.model.request.PermissionAddReq;
import com.acimage.admin.model.request.PermissionModifyReq;
import com.acimage.admin.service.authorize.AuthorizeWriteService;
import com.acimage.admin.service.permission.PermissionWriteSercice;
import com.acimage.common.model.domain.sys.Permission;
import com.baomidou.dynamic.datasource.annotation.DS;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Date;
@Service
@DS(ModuleConstants.SYS)
public class PermissionWriteServiceImpl implements PermissionWriteSercice {
@Autowired
PermissionDao permissionDao;
@Autowired
AuthorizeWriteService authorizeWriteService;
@Override
public void save(PermissionAddReq permissionAddReq){
Permission permission=new Permission();
BeanUtil.copyProperties(permissionAddReq,permission);
permissionDao.insert(permission);
}
@Override
public void remove(int id){
authorizeWriteService.remove(id);
permissionDao.deleteById(id);
}
@Override
public void update(PermissionModifyReq permissionModifyReq){
Permission permission=new Permission();
BeanUtil.copyProperties(permissionModifyReq,permission);
permission.setUpdateTime(new Date());
permissionDao.updateById(permission);
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/role/RoleQueryService.java
================================================
package com.acimage.admin.service.role;
import com.acimage.common.model.domain.sys.Role;
import java.util.List;
public interface RoleQueryService {
List listAll();
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/role/RoleWriteService.java
================================================
package com.acimage.admin.service.role;
import com.acimage.admin.model.request.RoleAddReq;
import com.acimage.admin.model.request.RoleModifyReq;
public interface RoleWriteService {
void save(RoleAddReq roleAddReq);
void remove(long id);
void update(RoleModifyReq roleModifyReq);
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/role/impl/RoleQueryServiceImpl.java
================================================
package com.acimage.admin.service.role.impl;
import com.acimage.admin.dao.sys.RoleDao;
import com.acimage.admin.service.role.RoleQueryService;
import com.acimage.common.model.domain.sys.Role;
import com.baomidou.dynamic.datasource.annotation.DS;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
@DS("sys")
public class RoleQueryServiceImpl implements RoleQueryService {
@Autowired
RoleDao roleDao;
@Override
public List listAll(){
return roleDao.selectList(null);
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/role/impl/RoleWriteServiceImpl.java
================================================
package com.acimage.admin.service.role.impl;
import cn.hutool.core.bean.BeanUtil;
import com.acimage.admin.dao.sys.RoleDao;
import com.acimage.admin.model.request.RoleAddReq;
import com.acimage.admin.model.request.RoleModifyReq;
import com.acimage.admin.service.role.RoleWriteService;
import com.acimage.common.model.domain.sys.Role;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Date;
@Service
@DS("sys")
public class RoleWriteServiceImpl implements RoleWriteService {
@Autowired
RoleDao roleDao;
@Override
public void save(RoleAddReq roleAddReq) {
Role role = new Role();
BeanUtil.copyProperties(roleAddReq,role,false);
roleDao.insert(role);
}
@Override
public void remove(long id) {
roleDao.deleteById(id);
}
@Override
public void update(RoleModifyReq roleModifyReq) {
LambdaUpdateWrapper uw = new LambdaUpdateWrapper<>();
uw.eq(Role::getId, roleModifyReq.getId())
.set(Role::getRoleName, roleModifyReq.getRoleName())
.set(Role::getNote, roleModifyReq.getNote())
.set(Role::getUpdateTime, new Date());
roleDao.update(null, uw);
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/topic/TopicQueryService.java
================================================
package com.acimage.admin.service.topic;
import com.acimage.admin.model.request.TopicQueryReq;
import com.acimage.common.model.domain.community.Topic;
import com.acimage.common.model.page.MyPage;
public interface TopicQueryService {
MyPage listOrderByColumn(TopicQueryReq topicQueryReq);
Integer getTopicCount();
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/topic/TopicWriteService.java
================================================
package com.acimage.admin.service.topic;
public interface TopicWriteService {
void remove(long topicId);
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/topic/impl/TopicQueryServiceImpl.java
================================================
package com.acimage.admin.service.topic.impl;
import com.acimage.admin.dao.community.TopicDao;
import com.acimage.admin.global.consts.ModuleConstants;
import com.acimage.admin.model.request.TopicQueryReq;
import com.acimage.admin.service.topic.TopicQueryService;
import com.acimage.common.model.domain.community.Topic;
import com.acimage.common.model.page.MyPage;
import com.acimage.common.utils.common.PageUtils;
import com.acimage.common.utils.redis.RedisUtils;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.concurrent.TimeUnit;
@DS(ModuleConstants.COMMUNITY)
@Service
public class TopicQueryServiceImpl implements TopicQueryService {
public static final String STRINGKP_TOPIC_COUNT = "acimage:admin:topic:totalCount:";
@Autowired
TopicDao topicDao;
@Autowired
RedisUtils redisUtils;
@Override
public MyPage listOrderByColumn(TopicQueryReq topicQueryReq) {
int pageNo = topicQueryReq.getPageNo();
int pageSize = topicQueryReq.getPageSize();
String column = StringUtils.camelToUnderline(topicQueryReq.getColumn()) ;
int startIndex = PageUtils.startIndexOf(pageNo, pageSize);
QueryWrapper qw = new QueryWrapper<>();
qw.orderByDesc(column).last(String.format("limit %d,%d", startIndex, pageSize));
List topicList = topicDao.selectList(qw);
int count = this.getTopicCount();
return new MyPage<>(count, topicList);
}
@Override
public Integer getTopicCount() {
Integer totalCount = redisUtils.getForString(STRINGKP_TOPIC_COUNT, Integer.class);
if (totalCount != null) {
return totalCount;
}
LambdaQueryWrapper qw = new LambdaQueryWrapper<>();
qw.select(Topic::getId);
totalCount = topicDao.selectCount(qw);
long timeout = 2L;
redisUtils.setAsString(STRINGKP_TOPIC_COUNT, totalCount.toString(), timeout, TimeUnit.MINUTES);
return totalCount;
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/topic/impl/TopicWriteServiceImpl.java
================================================
package com.acimage.admin.service.topic.impl;
import com.acimage.admin.global.consts.ModuleConstants;
import com.acimage.admin.service.topic.TopicWriteService;
import com.acimage.common.global.exception.BusinessException;
import com.acimage.common.result.Result;
import com.acimage.feign.client.TopicClient;
import com.baomidou.dynamic.datasource.annotation.DS;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Slf4j
@Service
@DS(ModuleConstants.COMMUNITY)
public class TopicWriteServiceImpl implements TopicWriteService {
@Autowired
TopicClient topicClient;
@Override
public void remove(long topicId){
Result> result=topicClient.delete(topicId);
if(!result.isOk()){
log.error("话题删除失败 id:{}",topicId);
throw new BusinessException("话题删除失败");
}
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/user/UserQueryService.java
================================================
package com.acimage.admin.service.user;
import com.acimage.admin.model.request.UserQueryReq;
import com.acimage.common.model.domain.user.User;
import com.acimage.common.model.page.MyPage;
public interface UserQueryService {
MyPage listBy(UserQueryReq userQueryReq);
User getUser(long userId);
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/user/UserWriteService.java
================================================
package com.acimage.admin.service.user;
public interface UserWriteService {
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/user/impl/UserQueryServiceImpl.java
================================================
package com.acimage.admin.service.user.impl;
import com.acimage.admin.dao.user.UserDao;
import com.acimage.admin.global.consts.ModuleConstants;
import com.acimage.admin.model.request.UserQueryReq;
import com.acimage.admin.service.user.UserQueryService;
import com.acimage.admin.service.userrole.UserRoleQueryService;
import com.acimage.common.model.domain.user.User;
import com.acimage.common.model.page.MyPage;
import com.acimage.common.utils.common.ListUtils;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Service
@DS(ModuleConstants.USER)
public class UserQueryServiceImpl implements UserQueryService {
@Autowired
UserDao userDao;
@Autowired
UserRoleQueryService userRoleQueryService;
@Override
public MyPage listBy(UserQueryReq userQueryReq) {
IPage page = new Page<>(userQueryReq.getPageNo(), userQueryReq.getPageSize());
String like = userQueryReq.getKeyword();
IPage resultPage;
if (like != null && like.trim().length() > 0) {
LambdaQueryWrapper qw = new LambdaQueryWrapper<>();
qw.like(User::getUsername, userQueryReq.getKeyword());
page = userDao.selectPage(page, qw);
resultPage = userDao.selectPage(page, qw);
} else {
resultPage = userDao.selectPage(page, null);
}
List userList = resultPage.getRecords();
int totalCount = (int) resultPage.getTotal();
Map> map = userRoleQueryService.listUserIdWithRoleIds(ListUtils.extract(User::getId, userList));
for (User user : userList) {
List roleIds = map.get(user.getId());
if (roleIds == null) {
user.setRoleIds(new ArrayList<>());
} else {
user.setRoleIds(roleIds);
}
}
return new MyPage<>(totalCount, userList);
}
@Override
public User getUser(long userId){
return userDao.selectById(userId);
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/user/impl/UserWriteServiceImpl.java
================================================
package com.acimage.admin.service.user.impl;
import com.acimage.admin.global.consts.ModuleConstants;
import com.baomidou.dynamic.datasource.annotation.DS;
import org.springframework.stereotype.Service;
@Service
@DS(ModuleConstants.USER)
public class UserWriteServiceImpl {
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/userrole/UserRoleQueryService.java
================================================
package com.acimage.admin.service.userrole;
import com.acimage.common.model.domain.sys.UserRole;
import java.util.List;
import java.util.Map;
public interface UserRoleQueryService {
Map> listUserIdWithRoleIds(List userIds);
UserRole getUserRole(long userId, int roleId);
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/userrole/UserRoleWriteService.java
================================================
package com.acimage.admin.service.userrole;
import java.util.List;
import java.util.Map;
public interface UserRoleWriteService {
void save(long userId, int roleId);
void remove(long userId, int roleId);
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/userrole/impl/UserRoleQueryServiceImpl.java
================================================
package com.acimage.admin.service.userrole.impl;
import com.acimage.admin.dao.sys.UserRoleDao;
import com.acimage.admin.global.consts.ModuleConstants;
import com.acimage.admin.service.userrole.UserRoleQueryService;
import com.acimage.common.model.domain.sys.UserRole;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
@DS(ModuleConstants.SYS)
public class UserRoleQueryServiceImpl implements UserRoleQueryService {
@Autowired
UserRoleDao userRoleDao;
@Override
public Map> listUserIdWithRoleIds(List userIds) {
LambdaQueryWrapper qw = new LambdaQueryWrapper<>();
qw.in(UserRole::getUserId, userIds);
List userRoles = userRoleDao.selectList(qw);
//组装
Map> map = new HashMap<>();
for (UserRole userRole : userRoles) {
long userId = userRole.getUserId();
List roleIds = map.get(userId);
if (roleIds == null) {
roleIds = new ArrayList<>();
roleIds.add(userRole.getRoleId());
map.put(userId,roleIds);
}else{
roleIds.add(userRole.getRoleId());
}
}
return map;
}
@Override
public UserRole getUserRole(long userId, int roleId){
LambdaQueryWrapper qw=new LambdaQueryWrapper<>();
qw.eq(UserRole::getUserId,userId)
.eq(UserRole::getRoleId,roleId);
return userRoleDao.selectOne(qw);
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/userrole/impl/UserRoleWriteServiceImpl.java
================================================
package com.acimage.admin.service.userrole.impl;
import com.acimage.admin.dao.sys.UserRoleDao;
import com.acimage.admin.global.consts.ModuleConstants;
import com.acimage.admin.service.user.UserQueryService;
import com.acimage.admin.service.userrole.UserRoleQueryService;
import com.acimage.admin.service.userrole.UserRoleWriteService;
import com.acimage.common.global.exception.BusinessException;
import com.acimage.common.model.domain.sys.UserRole;
import com.acimage.common.utils.IdGenerator;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Date;
@DS(ModuleConstants.SYS)
@Service
public class UserRoleWriteServiceImpl implements UserRoleWriteService {
@Autowired
UserRoleDao userRoleDao;
@Autowired
UserRoleQueryService userRoleQueryService;
@Autowired
UserQueryService userQueryService;
@Override
public void save(long userId, int roleId) {
if (userRoleQueryService.getUserRole(userId, roleId) != null) {
throw new BusinessException("该用户已有该角色");
}
if (userQueryService.getUser(userId) == null) {
throw new BusinessException("该用户不存在");
}
long id = IdGenerator.getSnowflakeNextId();
UserRole userRole = new UserRole(id, userId, roleId, new Date());
userRoleDao.insert(userRole);
}
@Override
public void remove(long userId, int roleId) {
LambdaQueryWrapper qw=new LambdaQueryWrapper<>();
qw.eq(UserRole::getUserId,userId)
.eq(UserRole::getRoleId,roleId);
userRoleDao.delete(qw);
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/websitedata/WebsiteDataService.java
================================================
package com.acimage.admin.service.websitedata;
import com.acimage.admin.model.vo.WebsiteDataVo;
public interface WebsiteDataService {
WebsiteDataVo getWebsiteData();
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/service/websitedata/impl/WebsiteDataServiceImpl.java
================================================
package com.acimage.admin.service.websitedata.impl;
import com.acimage.admin.model.vo.WebsiteDataVo;
import com.acimage.admin.service.websitedata.WebsiteDataService;
import com.acimage.common.global.consts.SysKeyConstants;
import com.acimage.common.utils.redis.RedisUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class WebsiteDataServiceImpl implements WebsiteDataService {
@Autowired
RedisUtils redisUtils;
@Override
public WebsiteDataVo getWebsiteData() {
WebsiteDataVo websiteDataVo = new WebsiteDataVo();
Long pageViewLong = redisUtils.sizeForHyperLogLog(SysKeyConstants.LOGK_PAGE_VIEW);
Integer apiAccessCount = redisUtils.getForString(SysKeyConstants.STRINGK_INTERFACE_TOTAL, Integer.class);
if (pageViewLong != null) {
websiteDataVo.setPageView(pageViewLong.intValue());
}
websiteDataVo.setApiAccessCount(apiAccessCount);
return websiteDataVo;
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/web/controller/AdminLoginController.java
================================================
package com.acimage.admin.web.controller;
import com.acimage.admin.model.request.AdminLoginReq;
import com.acimage.admin.service.login.LoginService;
import com.acimage.admin.service.login.VerifyCodeService;
import com.acimage.common.redis.annotation.RequestLimit;
import com.acimage.common.redis.enums.LimitTarget;
import com.acimage.common.result.Result;
import com.acimage.common.utils.RsaUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@RestController
@Slf4j
@RequestMapping("/api/admin/logins")
@Validated
public class AdminLoginController {
@Autowired
LoginService loginService;
@Autowired
VerifyCodeService verifyCodeService;
@RequestLimit(limitTimes = {1}, durations = {2}, penaltyTimes = {-1}, targets = {LimitTarget.IP})
@PostMapping("/doLogin")
public Result doLogin(@Validated @RequestBody AdminLoginReq adminLoginReq, HttpServletRequest request) {
String code = adminLoginReq.getVerifyCode();
boolean verifyCorrect = verifyCodeService.verifyAndRemoveIfSuccess(request, code);
if (!verifyCorrect) {
return Result.fail("验证码错误,请重新验证");
}
return Result.ok(loginService.login(adminLoginReq));
}
@GetMapping("/publicKey")
public Result> getPublicKey() {
return Result.ok(RsaUtils.getPublicKey());
}
@GetMapping("/commonCode")
public Result> getCommonVerifyCode(HttpServletRequest request, HttpServletResponse response) {
verifyCodeService.writeCodeImageToResponseAndRecord(request,response);
return Result.ok();
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/web/controller/ApiOperateController.java
================================================
package com.acimage.admin.web.controller;
import com.acimage.admin.model.request.ApiAddReq;
import com.acimage.admin.model.request.ApiModifyReq;
import com.acimage.admin.service.api.ApiWriteService;
import com.acimage.common.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Positive;
@RestController
@Slf4j
@RequestMapping("/api/admin/apis/operate")
@Validated
public class ApiOperateController {
@Autowired
ApiWriteService apiWriteService;
@PostMapping
public Result> addApi(@Validated @RequestBody ApiAddReq apiAddreq){
String path=apiAddreq.getPath().trim();
if(path.length()<2){
return Result.fail("路径有效长度不少于2");
}
apiAddreq.setPath(path);
apiWriteService.save(apiAddreq);
return Result.ok();
}
@PutMapping
public Result> modifyApi(@Validated @RequestBody ApiModifyReq apiModifyReq){
String path=apiModifyReq.getPath().trim();
if(path.length()<2){
return Result.fail("路径有效长度不少于2");
}
apiModifyReq.setPath(path);
apiWriteService.update(apiModifyReq);
return Result.ok();
}
@DeleteMapping("/{id}")
public Result> deleteApi(@Positive @NotNull @PathVariable int id){
apiWriteService.delete(id);
return Result.ok();
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/web/controller/ApiQueryController.java
================================================
package com.acimage.admin.web.controller;
import com.acimage.admin.model.request.ApiQueryReq;
import com.acimage.admin.service.api.ApiQueryService;
import com.acimage.common.model.domain.sys.Api;
import com.acimage.common.model.page.MyPage;
import com.acimage.common.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@RestController
@Slf4j
@RequestMapping("/api/admin/apis/query")
@Validated
public class ApiQueryController {
@Autowired
ApiQueryService apiQueryService;
@GetMapping("/search")
public Result> queryApisBy(@Validated @ModelAttribute ApiQueryReq apiQueryReq){
return Result.ok(apiQueryService.pageBy(apiQueryReq));
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/web/controller/AuthorizeOperateController.java
================================================
package com.acimage.admin.web.controller;
import com.acimage.admin.service.authorize.AuthorizeWriteService;
import com.acimage.common.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.Positive;
@RestController
@Slf4j
@RequestMapping("/api/admin/authorizes")
@Validated
public class AuthorizeOperateController {
@Autowired
AuthorizeWriteService authorizeWriteService;
@PostMapping
public Result> addAuthorize(@RequestParam @Positive Integer roleId,
@RequestParam @Positive Integer permissionId){
authorizeWriteService.save(roleId,permissionId);
return Result.ok();
}
@DeleteMapping("/{roleId}/{permissionId}")
public Result> deleteAuthorize(@PathVariable @Positive Integer roleId,
@PathVariable @Positive Integer permissionId){
authorizeWriteService.remove(roleId,permissionId);
return Result.ok();
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/web/controller/AuthorizeQueryController.java
================================================
package com.acimage.admin.web.controller;
import com.acimage.admin.service.authorize.AuthorizeQueryService;
import com.acimage.common.model.domain.sys.Authorize;
import com.acimage.common.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.Positive;
import java.util.List;
@RestController
@Slf4j
@RequestMapping("/api/admin/authorizes")
@Validated
public class AuthorizeQueryController {
@Autowired
AuthorizeQueryService authorizeQueryService;
@GetMapping("/roleId/{roleId}")
public Result> queryRoleAuthorize(@PathVariable @Positive Integer roleId){
return Result.ok(authorizeQueryService.listAuthorizeByRoleId(roleId));
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/web/controller/CategoryController.java
================================================
package com.acimage.admin.web.controller;
import com.acimage.admin.service.category.CategoryQueryService;
import com.acimage.common.model.domain.community.Category;
import com.acimage.common.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@Slf4j
@RequestMapping("/api/admin/categories")
@Validated
public class CategoryController {
@Autowired
CategoryQueryService categoryQueryService;
@GetMapping("/all")
public Result> queryAll(){
return Result.ok(categoryQueryService.listAll()) ;
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/web/controller/CommentOperateController.java
================================================
package com.acimage.admin.web.controller;
import com.acimage.admin.model.request.CommentQueryReq;
import com.acimage.admin.service.comment.CommentQueryService;
import com.acimage.admin.service.comment.CommentWriteService;
import com.acimage.common.model.domain.community.Comment;
import com.acimage.common.model.page.MyPage;
import com.acimage.common.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.Positive;
@RestController
@Slf4j
@RequestMapping("/api/admin/comments/operate")
@Validated
public class CommentOperateController {
@Autowired
CommentWriteService commentWriteService;
@DeleteMapping("/{id}")
public Result> pageCommentsBy(@PathVariable @Positive Long id) {
commentWriteService.delete(id);
return Result.ok();
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/web/controller/CommentQueryController.java
================================================
package com.acimage.admin.web.controller;
import com.acimage.admin.model.request.CommentQueryReq;
import com.acimage.admin.model.request.TopicQueryReq;
import com.acimage.admin.service.comment.CommentQueryService;
import com.acimage.admin.service.topic.TopicQueryService;
import com.acimage.common.model.domain.community.Comment;
import com.acimage.common.model.domain.community.Topic;
import com.acimage.common.model.page.MyPage;
import com.acimage.common.result.Result;
import com.acimage.common.utils.LambdaUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@Slf4j
@RequestMapping("/api/admin/comments/query")
@Validated
public class CommentQueryController {
@Autowired
CommentQueryService commentQueryService;
@GetMapping("/by")
public Result> pageCommentsBy(@Validated @ModelAttribute CommentQueryReq queryReq) {
return Result.ok(commentQueryService.pageCommentsBy(queryReq));
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/web/controller/HomeCarouselController.java
================================================
package com.acimage.admin.web.controller;
import cn.hutool.core.util.StrUtil;
import com.acimage.admin.model.request.CarouselAddReq;
import com.acimage.admin.model.request.CarouselModifyReq;
import com.acimage.admin.service.homecarousel.HomeCarouselWriteService;
import com.acimage.admin.service.homecarousel.HomeCarouselQueryService;
import com.acimage.common.global.consts.FileFormatConstants;
import com.acimage.common.model.domain.community.HomeCarousel;
import com.acimage.common.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.validation.constraints.Positive;
import javax.validation.constraints.Size;
import java.util.List;
@RestController
@Slf4j
@RequestMapping("/api/admin/homeCarousels")
@Validated
public class HomeCarouselController {
@Autowired
HomeCarouselWriteService homeCarouselWriteService;
@Autowired
HomeCarouselQueryService homeCarouselQueryService;
@PostMapping
public Result> addImage(@RequestParam("image") MultipartFile imageFile,
@Validated @ModelAttribute CarouselAddReq carouselAddReq) {
String originName = imageFile.getOriginalFilename();
String format = StrUtil.subAfter(originName, '.', true);
if (!FileFormatConstants.ALLOWED_CAROUSEL_FORMAT.contains(format)) {
return Result.fail("图片格式需为"+FileFormatConstants.ALLOWED_CAROUSEL_FORMAT);
}
homeCarouselWriteService.saveHomeCarouselImage(imageFile, carouselAddReq);
return Result.ok();
}
@DeleteMapping("/{id}")
public Result> deleteImage(@PathVariable @Positive Long id) {
homeCarouselWriteService.deleteHomeCarouselImage(id);
return Result.ok();
}
@PutMapping("/descriptionAndLink")
public Result> modifyDescription(@Validated @ModelAttribute CarouselModifyReq carouselModifyReq) {
homeCarouselWriteService.updateHomeCarouselImage(carouselModifyReq);
return Result.ok();
}
@PostMapping("/cover")
public Result> coverImageFile(@RequestParam("id") @Positive Long id,
@RequestParam("image") MultipartFile imageFile) {
String originName = imageFile.getOriginalFilename();
String format = StrUtil.subAfter(originName, '.', true);
if (!FileFormatConstants.ALLOWED_CAROUSEL_FORMAT.contains(format)) {
return Result.fail("图片格式需为"+FileFormatConstants.ALLOWED_CAROUSEL_FORMAT);
}
homeCarouselWriteService.coverHomeCarouselImage(id, imageFile);
return Result.ok();
}
@GetMapping("/current")
public Result> queryCurrentHomeCarousel() {
return Result.ok(homeCarouselQueryService.listCurrent());
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/web/controller/PermissionOperateController.java
================================================
package com.acimage.admin.web.controller;
import cn.hutool.core.util.StrUtil;
import com.acimage.admin.model.request.PermissionAddReq;
import com.acimage.admin.model.request.PermissionModifyReq;
import com.acimage.admin.service.permission.PermissionWriteSercice;
import com.acimage.common.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.Positive;
@RestController
@Slf4j
@Validated
@RequestMapping("/api/admin/permissions")
public class PermissionOperateController {
@Autowired
PermissionWriteSercice permissionWriteSercice;
@PostMapping
public Result> add(@Validated @RequestBody PermissionAddReq permissionAddReq){
if(permissionAddReq.getCode()==null|| StrUtil.isBlank(permissionAddReq.getCode())){
permissionAddReq.setCode(null);
}
if(!permissionAddReq.getModule() &&permissionAddReq.getCode()==null){
return Result.fail("非模块的权限码不能为空");
}
permissionWriteSercice.save(permissionAddReq);
return Result.ok();
}
@PutMapping
public Result> modify(@Validated @RequestBody PermissionModifyReq permissionModifyReq){
permissionWriteSercice.update(permissionModifyReq);
return Result.ok();
}
@DeleteMapping("/{id}")
public Result> modify(@PathVariable @Positive Integer id){
permissionWriteSercice.remove(id);
return Result.ok();
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/web/controller/PermissionQueryController.java
================================================
package com.acimage.admin.web.controller;
import com.acimage.admin.service.permission.PermissionQueryService;
import com.acimage.common.model.domain.sys.Permission;
import com.acimage.common.model.page.MyPage;
import com.acimage.common.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.constraints.Max;
import javax.validation.constraints.Positive;
import java.util.List;
@RestController
@Slf4j
@Validated
@RequestMapping("/api/admin/permissions")
public class PermissionQueryController {
@Autowired
PermissionQueryService permissionQueryService;
@GetMapping("/tree")
public Result> queryPermissionTree(){
return Result.ok(permissionQueryService.getPermissionTree());
}
@GetMapping("/page/{pageNo}/{pageSize}")
public Result> pagePermissionsWithParent(@PathVariable @Positive Integer pageNo,
@PathVariable @Max(20) Integer pageSize){
return Result.ok(permissionQueryService.pagePermissionsWithParent(pageNo,pageSize));
}
@GetMapping("/modules")
public Result> queryModules(){
return Result.ok(permissionQueryService.listByModule(true));
}
@GetMapping("/nonModules")
public Result> queryNonModules(){
return Result.ok(permissionQueryService.listByModule(false));
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/web/controller/RoleController.java
================================================
package com.acimage.admin.web.controller;
import com.acimage.admin.model.request.RoleAddReq;
import com.acimage.admin.model.request.RoleModifyReq;
import com.acimage.admin.service.role.RoleQueryService;
import com.acimage.admin.service.role.RoleWriteService;
import com.acimage.common.model.domain.sys.Role;
import com.acimage.common.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.Positive;
import java.util.List;
@RestController
@Slf4j
@RequestMapping("/api/admin/roles")
@Validated
public class RoleController {
@Autowired
RoleQueryService roleQueryService;
@Autowired
RoleWriteService roleWriteService;
@GetMapping("/all")
public Result> queryAllRoles(){
return Result.ok(roleQueryService.listAll());
}
@PostMapping()
public Result> add(@Validated @RequestBody RoleAddReq roleAddReq){
roleWriteService.save(roleAddReq);
return Result.ok();
}
@DeleteMapping("/{id}")
public Result> delete(@PathVariable @Positive Integer id){
roleWriteService.remove(id);
return Result.ok();
}
@PutMapping()
public Result> modify(@Validated @RequestBody RoleModifyReq roleModifyReq){
roleWriteService.update(roleModifyReq);
return Result.ok();
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/web/controller/TopicOperateController.java
================================================
package com.acimage.admin.web.controller;
import com.acimage.admin.service.topic.TopicWriteService;
import com.acimage.common.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.constraints.Positive;
@RestController
@Slf4j
@RequestMapping("/api/admin/topics/operate")
@Validated
public class TopicOperateController {
@Autowired
TopicWriteService topicWriteService;
@DeleteMapping("/{topicId}")
public Result> delete(@PathVariable @Positive Long topicId){
topicWriteService.remove(topicId);
return Result.ok();
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/web/controller/TopicQueryController.java
================================================
package com.acimage.admin.web.controller;
import com.acimage.admin.model.request.TopicQueryReq;
import com.acimage.admin.service.topic.TopicQueryService;
import com.acimage.common.model.domain.community.Topic;
import com.acimage.common.result.Result;
import com.acimage.common.utils.LambdaUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@Slf4j
@RequestMapping("/api/admin/topics/query")
@Validated
public class TopicQueryController {
@Autowired
TopicQueryService topicQueryService;
@GetMapping("/orderBy")
public Result listOrderBy(@Validated @ModelAttribute TopicQueryReq topicQueryReq) {
List allowedColumns= LambdaUtils.columnsFrom(Topic::getUpdateTime,Topic::getCreateTime,Topic::getPageView,Topic::getStarCount,Topic::getCommentCount);
if(!allowedColumns.contains(topicQueryReq.getColumn())){
return Result.fail("非法查询字段");
}
return Result.ok(topicQueryService.listOrderByColumn(topicQueryReq));
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/web/controller/UserQueryController.java
================================================
package com.acimage.admin.web.controller;
import com.acimage.admin.model.request.UserQueryReq;
import com.acimage.admin.service.user.UserQueryService;
import com.acimage.common.model.domain.user.User;
import com.acimage.common.model.page.MyPage;
import com.acimage.common.result.Result;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Slf4j
@RequestMapping("/api/admin/users/query")
@Validated
public class UserQueryController {
@Autowired
UserQueryService userQueryService;
@GetMapping("/search")
public Result> queryUsersBy(@Validated @ModelAttribute UserQueryReq userQueryReq){
String keyword=userQueryReq.getKeyword();
if(keyword!=null){
if(keyword.trim().length()==0){
userQueryReq.setKeyword(null);
}else{
userQueryReq.setKeyword(keyword.trim());
}
}
return Result.ok(userQueryService.listBy(userQueryReq));
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/web/controller/UserRoleOperateController.java
================================================
package com.acimage.admin.web.controller;
import com.acimage.admin.model.request.UserQueryReq;
import com.acimage.admin.service.userrole.UserRoleWriteService;
import com.acimage.common.model.domain.user.User;
import com.acimage.common.model.page.MyPage;
import com.acimage.common.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Positive;
@RestController
@Slf4j
@RequestMapping("/api/admin/userRoles/operate")
@Validated
public class UserRoleOperateController {
@Autowired
UserRoleWriteService userRoleWriteService;
@PostMapping
public Result> addRoleForUser(@Positive @NotNull Long userId, @Positive @NotNull Integer roleId) {
userRoleWriteService.save(userId, roleId);
return Result.ok();
}
@DeleteMapping("/{userId}/{roleId}")
public Result> deleteRoleForUser(@PathVariable @Positive @NotNull Long userId,@PathVariable @Positive @NotNull Integer roleId) {
userRoleWriteService.remove(userId, roleId);
return Result.ok();
}
}
================================================
FILE: acimage_admin/src/main/java/com/acimage/admin/web/controller/WebsiteDataController.java
================================================
package com.acimage.admin.web.controller;
import com.acimage.admin.model.vo.WebsiteDataVo;
import com.acimage.admin.service.websitedata.WebsiteDataService;
import com.acimage.common.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Slf4j
@RequestMapping("/api/admin/websites")
@Validated
public class WebsiteDataController {
@Autowired
WebsiteDataService websiteDataService;
@GetMapping("/accessData")
public Result queryWebsiteData() {
return Result.ok(websiteDataService.getWebsiteData());
}
}
================================================
FILE: acimage_admin/src/main/resources/application-dev.yml
================================================
server:
port: 8060
spring:
config:
activate:
on-profile:
- dev
# datasource:
# community:
# type: com.alibaba.druid.pool.DruidDataSource
# driver-class-name: com.mysql.cj.jdbc.Driver
# jdbc-url: jdbc:mysql://localhost:3306/acimage_community?useSSl=false&allowMultiQueries=true&serverTimezone=UTC
# username: root
# password: mysql
# image:
# type: com.alibaba.druid.pool.DruidDataSource
# driver-class-name: com.mysql.cj.jdbc.Driver
# jdbc-url: jdbc:mysql://localhost:3306/acimage_image?useSSl=false&allowMultiQueries=true&serverTimezone=UTC
# username: root
# password: mysql
datasource:
dynamic:
primary: sys #设置默认的数据源或者数据源组,默认值即为master
strict: true #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
datasource:
sys:
url: jdbc:mysql://localhost:3306/acimage_sys?useSSl=false&allowMultiQueries=true&serverTimezone=UTC
username: root
password: mysql
driver-class-name: com.mysql.cj.jdbc.Driver # 3.2.0开始支持SPI可省略此配置
community:
url: jdbc:mysql://localhost:3306/acimage_community?useSSl=false&allowMultiQueries=true&serverTimezone=UTC
username: root
password: mysql
driver-class-name: com.mysql.cj.jdbc.Driver # 3.2.0开始支持SPI可省略此配置
image:
url: jdbc:mysql://localhost:3306/acimage_image?useSSl=false&allowMultiQueries=true&serverTimezone=UTC
username: root
password: mysql
driver-class-name: com.mysql.cj.jdbc.Driver # 3.2.0开始支持SPI可省略此配置
user:
url: jdbc:mysql://localhost:3306/acimage_user?useSSl=false&allowMultiQueries=true&serverTimezone=UTC
username: root
password: mysql
driver-class-name: com.mysql.cj.jdbc.Driver # 3.2.0开始支持SPI可省略此配置
redis:
host: 127.0.0.1
port: 6379
password: redis
lettuce:
pool:
max-active: 8
max-idle: 8 #最大空闲连接
min-idle: 0 #最小空闲连接
max-wait: 100ms #连接等待时间
cloud:
nacos:
server-addr: 43.136.68.91:8848 #nacos 服务地址
================================================
FILE: acimage_admin/src/main/resources/application.yml
================================================
spring:
profiles:
include: common,common-secret
active: dev2
application:
name: admin-service #服务名称
servlet:
multipart:
max-file-size: 10MB
max-request-size: 55MB
# rabbitmq:
# host: 192.168.130.128
# port: 5672
# username: acimage
# password: acimage
# virtual-host: /acimage
# listener:
# simple:
# auto-startup: false #消费者是否启动
# direct:
# auto-startup: false #生产者是否启动
mybatis-plus:
mapper-locations: classpath*:mapper/**/*.xml
type-aliases-package: com.acimage.common.model.domain
type-handlers-package: com.acimage.common.config.typehandler
global-config:
db-config:
table-prefix: tb_
feign:
okhttp:
enabled: true
httpclient:
max-connections: 20 # 最大的连接数
max-connections-per-route: 5 # 每个路径的最大连接数
================================================
FILE: acimage_admin/src/main/resources/logback-spring.xml
================================================
%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%20.20thread{20}] %40logger{40} : %msg%n
INFO
ACCEPT
DENY
${LOG_HOME}/${spring.application.name}/%d{yyyy-MM-dd}-info.%i.log
5MB
8
%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
WARN
ACCEPT
DENY
${LOG_HOME}/${spring.application.name}/%d{yyyy-MM-dd}-warn.%i.log
5MB
15
%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
ERROR
ACCEPT
DENY
${LOG_HOME}/${spring.application.name}/%d{yyyy-MM-dd}-error.%i.log
5MB
15
%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
================================================
FILE: acimage_admin/src/main/resources/mapper/community/TopicMapper.xml
================================================
================================================
FILE: acimage_admin/src/main/resources/mapper/image/HomeCarouselMapper.xml
================================================
================================================
FILE: acimage_admin/src/main/resources/mapper/sys/ApiMapper.xml
================================================
================================================
FILE: acimage_admin/src/main/resources/mapper/sys/PermissionMapper.xml
================================================
================================================
FILE: acimage_admin/src/main/resources/mapper/user/TopicMapper.xml
================================================
================================================
FILE: acimage_admin/src/test/java/com/acimage/admin/AdminApplicationTest.java
================================================
package com.acimage.admin;
import com.acimage.common.deprecated.QiniuUtils;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.io.File;
@SpringBootTest
class AdminApplicationTest {
@Autowired
QiniuUtils qiniuUtils;
@Test
void qiniuUtilsTest() {
File file = new File("F:\\MyImage\\素材\\bg2.png");
qiniuUtils.upload(file,"test/xlg.png");
}
}
================================================
FILE: acimage_admin/src/test/java/com/acimage/admin/dao/community/SpDaoTest.java
================================================
package com.acimage.admin.dao.community;
import com.acimage.common.model.domain.community.HomeCarousel;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.Date;
@SpringBootTest
public class SpDaoTest {
@Autowired
HomeCarouselDao homeCarouselDao;
@Test
public void deleteTest(){
long id=10086L;
homeCarouselDao.deleteById(id);
}
@Test
public void getMaxLocationOfHomeCarousel(){
System.out.println(homeCarouselDao.getMaxLocation());
}
@Test
public void testSelectAll(){
System.out.println(homeCarouselDao.selectList(null));
System.out.println(homeCarouselDao.count());
}
}
================================================
FILE: acimage_admin/src/test/java/com/acimage/admin/dao/community/TopicDaoTest.java
================================================
package com.acimage.admin.dao.community;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class TopicDaoTest {
@Autowired
TopicDao topicDao;
@Test
void testSelectAll(){
System.out.println(topicDao.selectList(null));
}
}
================================================
FILE: acimage_admin/src/test/java/com/acimage/admin/dao/sys/ApiDaoTest.java
================================================
package com.acimage.admin.dao.sys;
import com.acimage.common.global.enums.MatchRule;
import com.acimage.common.model.domain.sys.Api;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.HttpMethod;
@SpringBootTest
public class ApiDaoTest {
@Autowired
ApiDao apiDao;
@Test
void testSelect(){
System.out.println(apiDao.selectList(null));
}
}
================================================
FILE: acimage_admin/src/test/java/com/acimage/admin/service/HomeCarouselWriteServiceTest.java
================================================
package com.acimage.admin.service;
import com.acimage.admin.service.homecarousel.HomeCarouselWriteService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class HomeCarouselWriteServiceTest {
@Autowired
HomeCarouselWriteService homeCarouselWriteService;
}
================================================
FILE: acimage_common/.gitignore
================================================
/.idea
/src/main/resources/application-qiniu.yml
================================================
FILE: acimage_common/pom.xml
================================================
acimage
com.acimage
0.0.1-SNAPSHOT
4.0.0
acimage_common
jar
acimage_common
http://maven.apache.org
UTF-8
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-aop
com.baomidou
mybatis-plus-boot-starter
cn.hutool
hutool-all
org.springframework.boot
spring-boot-starter-data-redis
org.apache.commons
commons-pool2
org.springframework.boot
spring-boot-starter-amqp
true
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
org.springframework.cloud
spring-cloud-starter-netflix-ribbon
com.auth0
java-jwt
com.qiniu
qiniu-java-sdk
true
com.squareup.okhttp3
okhttp
3.14.2
compile
true
io.minio
minio
true
io.github.toolgood
toolgood-words
true
org.springframework.data
spring-data-elasticsearch
true
org.springframework.boot
spring-boot-starter-validation
net.coobird
thumbnailator
junit
junit
3.8.1
test
org.springframework.boot
spring-boot-maven-plugin
true
exec
true
org.apache.maven.plugins
maven-surefire-plugin
true
================================================
FILE: acimage_common/src/main/java/com/acimage/common/CommonMain.java
================================================
package com.acimage.common;
public class CommonMain {
public static void main(String[] args) {
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/config/EsConfig.java
================================================
package com.acimage.common.config;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import java.util.concurrent.TimeUnit;
@Profile(value = {"test","dev","dev2","server"})
@Configuration
@ConditionalOnClass(RestHighLevelClient.class)
public class EsConfig {
@Bean
public RestHighLevelClient devRestHighLevelClient(@Autowired RestClientBuilder restClientBuilder) {
return new RestHighLevelClient(restClientBuilder.setHttpClientConfigCallback(requestConfig -> {
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
return requestConfig.setDefaultCredentialsProvider(credentialsProvider);
}));
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/config/EsProdConfig.java
================================================
package com.acimage.common.config;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import java.util.concurrent.TimeUnit;
@Profile("prod")
@Configuration
@ConditionalOnClass(RestHighLevelClient.class)
public class EsProdConfig {
@Value("${spring.elasticsearch.username}")
private String username;
@Value("${spring.elasticsearch.password}")
private String password;
@Bean
public RestHighLevelClient prodRestHighLevelClient(@Autowired RestClientBuilder restClientBuilder) {
return new RestHighLevelClient(restClientBuilder.setHttpClientConfigCallback(requestConfig -> {
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));
requestConfig.setKeepAliveStrategy((response, context) -> TimeUnit.MINUTES.toMillis(3));
return requestConfig.setDefaultCredentialsProvider(credentialsProvider);
}));
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/config/FilterConfig.java
================================================
package com.acimage.common.config;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.filter.HiddenHttpMethodFilter;
@Configuration
public class FilterConfig {
/**
* 设置编码
* @return
*/
@Bean
public FilterRegistrationBean registerFilter1(){
FilterRegistrationBean registerFilter=new FilterRegistrationBean<>();
CharacterEncodingFilter encodeFilter=new CharacterEncodingFilter();
encodeFilter.setEncoding("UTF-8");
registerFilter.setFilter(encodeFilter);
registerFilter.addUrlPatterns("/*");
return registerFilter;
}
/**
* 设置HiddenHttpMethod,支持put、get、delete等请求
* @return
*/
@Bean
public FilterRegistrationBean registerFilter2(){
FilterRegistrationBean registerFilter=new FilterRegistrationBean<>();
HiddenHttpMethodFilter hiddenHttpMethodFilter=new HiddenHttpMethodFilter();
registerFilter.setFilter(hiddenHttpMethodFilter);
registerFilter.addUrlPatterns("/*");
return registerFilter;
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/config/JacksonConfig.java
================================================
package com.acimage.common.config;
import cn.hutool.core.date.DatePattern;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class JacksonConfig {
/**
* Jackson全局转化long类型为String,解决前端接受long类型缺失精度问题
* @return Jackson2ObjectMapperBuilderCustomizer 注入的对象
*/
@Bean
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder
.serializerByType(Long.class, ToStringSerializer.instance)
.serializerByType(Long.TYPE, ToStringSerializer.instance)
.simpleDateFormat(DatePattern.NORM_DATETIME_PATTERN);
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/config/PaginationConfig.java
================================================
package com.acimage.common.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class PaginationConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
paginationInnerInterceptor.setDbType(DbType.MYSQL);
//页数溢出时跳到第一页
paginationInnerInterceptor.setOverflow(true);
interceptor.addInnerInterceptor(paginationInnerInterceptor);
return interceptor;
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/config/RabbitmqConvertConfig.java
================================================
package com.acimage.common.config;
import org.springframework.amqp.core.AcknowledgeMode;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ConditionalOnClass(RabbitTemplate.class)
@Configuration
public class RabbitmqConvertConfig {
//发送方序列化
@Bean
public RabbitTemplate jacksonRabbitTemplate(ConnectionFactory connectionFactory) {
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
return rabbitTemplate;
}
//消费者序列化
@Bean
public RabbitListenerContainerFactory> rabbitListenerContainerFactory(ConnectionFactory connectionFactory){
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
factory.setMessageConverter(new Jackson2JsonMessageConverter());
factory.setAcknowledgeMode(AcknowledgeMode.MANUAL);
return factory;
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/deprecated/IpInterceptorBak.java
================================================
package com.acimage.common.deprecated;
import com.acimage.common.global.context.UserContext;
import com.acimage.common.utils.IpUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.concurrent.TimeUnit;
/**
* 获取请求的token状态
*/
@Slf4j
@Component
public class IpInterceptorBak implements HandlerInterceptor {
@Autowired
StringRedisTemplate stringRedisTemplate;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String KEY_IP="acimage:ip:";
String KEY_BLACK_IP="acimage:ip:black";
long EXPIRE_SECONDS=10L;
long limitTimes=300L;
String ip = IpUtils.getIp(request);
UserContext.setIp(ip);
String ipKey=KEY_IP+ip;
String blackIpKey=KEY_BLACK_IP+ip;
Boolean isBlackIp=stringRedisTemplate.opsForSet().isMember(blackIpKey,ip);
if(Boolean.TRUE.equals(isBlackIp)){
return false;
}
if (handler instanceof HandlerMethod) {
Long visitNum=stringRedisTemplate.opsForValue().increment(ipKey);
if(visitNum==null){
log.error("ip:{} 操作:ip访问计数 错误:redis中ip计数返回值为空",ip);
} else if (visitNum==1){
stringRedisTemplate.expire(ipKey,EXPIRE_SECONDS, TimeUnit.SECONDS);
} else if (visitNum>limitTimes) {
//加入黑名单
stringRedisTemplate.opsForSet().add(blackIpKey,ip);
response.setStatus(HttpStatus.FORBIDDEN.value());
return false;
}
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
UserContext.remove();
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/deprecated/JwtInterceptorBak.java
================================================
package com.acimage.common.deprecated;
import com.acimage.common.global.exception.NullTokenException;
import com.acimage.common.deprecated.annotation.utils.AuthenticationUtils;
import com.acimage.common.global.consts.HeaderKeyConstants;
import com.acimage.common.global.context.UserContext;
import com.acimage.common.global.enums.AuthenticationType;
import com.acimage.common.global.enums.TokenStatus;
import com.acimage.common.service.TokenService;
import com.acimage.common.utils.IpUtils;
import com.acimage.common.utils.JwtUtils;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 获取请求的token状态
*/
public class JwtInterceptorBak implements HandlerInterceptor {
@Autowired
TokenService tokenService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//设置ip
String ip = IpUtils.getIp(request);
UserContext.setIp(ip);
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod=(HandlerMethod) handler;
//获取该方法权限类型,优先注解顺序:方法、类
AuthenticationType authenticationType = AuthenticationUtils.getAuthenticationType(handlerMethod);
//无登录权限要求则放行
if (authenticationType == null || authenticationType == AuthenticationType.NONE) {
UserContext.setTokenStatus(TokenStatus.PASS_TOKEN_VERIFY);
return true;
}
}
//获取token
String token = request.getHeader(HeaderKeyConstants.AUTHORIZATION);
//验证token,验证不通过抛出异常
try {
JwtUtils.verifyToken(token);
} catch (NullTokenException e1) {
UserContext.setTokenStatus(TokenStatus.NULL);
return true;
} catch (TokenExpiredException e2) {
UserContext.setTokenStatus(TokenStatus.EXPIRE);
return true;
} catch (JWTVerificationException e3) {
UserContext.setTokenStatus(TokenStatus.INVALID);
return true;
}
if (!tokenService.hasRecorded(token)) {
UserContext.setTokenStatus(TokenStatus.MISMATCH_IP);
} else {
UserContext.setTokenStatus(TokenStatus.VALID);
}
UserContext.saveCurrentUserInfo(JwtUtils.getUserId(token), JwtUtils.getUsername(token), JwtUtils.getPhotoUrl(token));
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
UserContext.remove();
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/deprecated/PermissionInterceptorBak.java
================================================
package com.acimage.common.deprecated;
import com.acimage.common.deprecated.annotation.utils.AuthenticationUtils;
import com.acimage.common.global.context.UserContext;
import com.acimage.common.global.enums.AuthenticationType;
import com.acimage.common.global.enums.TokenStatus;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.ParameterizableViewController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 验证token状态和请求所需权限是否匹配
*/
@Slf4j
public class PermissionInterceptorBak implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String ip = UserContext.getIp();
log.info("access 用户:{} token状态:{} 访问:{} {} ip:{}",
UserContext.getUsername(), UserContext.getTokenStatus(), request.getRequestURI(), request.getMethod(), ip);
TokenStatus tokenStatus = UserContext.getTokenStatus();
if (tokenStatus == TokenStatus.PASS_TOKEN_VERIFY) {
return true;
}
//如果通过viewController访问页面
if (handler instanceof ParameterizableViewController) {
if (!(tokenStatus == TokenStatus.VALID||tokenStatus == TokenStatus.MISMATCH_IP)) {
response.sendRedirect("/");
return false;
}
}
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
//获取该方法权限类型,优先注解顺序:方法、类
AuthenticationType authenticationType = AuthenticationUtils.getAuthenticationType(handlerMethod);
//无登录权限要求则放行
if (authenticationType == null || authenticationType == AuthenticationType.NONE) {
return true;
} else if (authenticationType == AuthenticationType.TOKEN_REQUIRED) {
if (!(tokenStatus == TokenStatus.VALID||tokenStatus == TokenStatus.MISMATCH_IP)) {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
return false;
}
}
}
// ParameterizableViewController viewHandler=(ParameterizableViewController) handler;
// viewHandler.getViewName();
// String token= CookieUtils.getValueByName(request.getCookies(), JwtUtils.KEY_TOKEN);
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView
modelAndView) throws Exception {
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception
ex) throws Exception {
//移除用户信息,防止之后用该线程的信息误判(因为线程池)
UserContext.remove();
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/deprecated/QiniuUtils.java
================================================
package com.acimage.common.deprecated;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.http.HttpUtil;
import com.acimage.common.global.exception.BusinessException;
import com.acimage.common.utils.ExceptionUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qiniu.cdn.CdnManager;
import com.qiniu.cdn.CdnResult;
import com.qiniu.common.QiniuException;
import com.qiniu.http.Client;
import com.qiniu.http.Response;
import com.qiniu.storage.BucketManager;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.Region;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.BatchStatus;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.util.Auth;
import com.qiniu.util.StringMap;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Nullable;
import javax.annotation.PostConstruct;
import javax.validation.constraints.NotNull;
import java.io.*;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
@Deprecated
@Slf4j
@ConditionalOnClass(Auth.class)
@ConfigurationProperties(prefix = "qiniu")
public class QiniuUtils {
private String accessKey;
private String secretKey;
private String bucket;
private String domain;
private String uploadToken;
UploadManager uploadManager;
Auth auth;
Configuration cfg;
private static final ObjectMapper mapper = new ObjectMapper();
@PostConstruct
private void init() {
cfg = new Configuration(Region.huanan());
cfg.resumableUploadAPIVersion = Configuration.ResumableUploadAPIVersion.V2;// 指定分片上传版本
uploadManager = new UploadManager(cfg);
auth = Auth.create(accessKey, secretKey);
uploadToken = auth.uploadToken(bucket);
// System.out.println(accessKey);
// System.out.println(secretKey);
// System.out.println(bucket);
// System.out.println(domain);
}
public void setAccessKey(String accessKey) {
this.accessKey = accessKey;
}
public void setSecretKey(String secretKey) {
this.secretKey = secretKey;
}
public void setBucket(String bucket) {
this.bucket = bucket;
}
public void setDomain(String domain) {
this.domain = domain;
}
/**
* @param multipartFile 上传的图片
*/
public void upload(@NotNull MultipartFile multipartFile, String urlWithoutDomain) {
InputStream is;
try {
is = multipartFile.getInputStream();
} catch (IOException e) {
ExceptionUtils.printIfDev(e);
log.error("error: multipartFile.getInputStream()异常:{}", e.getMessage());
throw new RuntimeException(e);
}
putAndLog(is, urlWithoutDomain, uploadToken);
}
public void upload(@NotNull File file, String urlWithoutDomain) {
putAndLog(file, urlWithoutDomain, uploadToken);
}
public void cover(@NotNull MultipartFile multipartFile, String urlWithoutDomain) {
String coverToken = auth.uploadToken(bucket, urlWithoutDomain);
InputStream is;
try {
is = multipartFile.getInputStream();
} catch (IOException e) {
throw new RuntimeException(e);
}
putAndLog(is, urlWithoutDomain, coverToken);
new Thread(() -> {
refreshFile(urlWithoutDomain);
refreshQuery(urlWithoutDomain);
}).start();
}
public void refreshFile(String... urls) {
int urlAmountLimit = 100;
CdnManager c = new CdnManager(auth);
if (urls.length > urlAmountLimit) {
log.error("调用刷新的链接超过100个");
return;
}
//得到真实链接
for (int i = 0; i < urls.length; i++) {
urls[i] = getTrueUrl(urls[i]);
}
try {
//单次方法调用刷新的链接不可以超过100个
CdnResult.RefreshResult result = c.refreshUrls(urls);
//获取其他的回复内容
} catch (QiniuException e) {
log.error("刷新七牛云url失败 urls:{}", Arrays.asList(urls));
}
}
public void refreshQuery(String url) {
String trueUrl = getTrueUrl(url);
StringMap str = auth.authorization(trueUrl);
Client client = new Client();
try {
client.post(trueUrl, "", str);
} catch (QiniuException e) {
log.error("刷新查询oss url失败 url:{}", url);
ExceptionUtils.printIfDev(e);
}
}
public void deleteFile(String url) {
BucketManager bucketManager = new BucketManager(auth, cfg);
try {
bucketManager.delete(bucket, url);
} catch (QiniuException ex) {
//如果遇到异常,说明删除失败
log.error("云文件删除失败 url:{} 返回代码:{} 返回错误信息:{}", url, ex.code(), ex.response.toString());
}
}
public void batchDelete(List urlList) {
if (CollectionUtil.isEmpty(urlList)) {
return;
}
BucketManager bucketManager = new BucketManager(auth, cfg);
try {
//单次批量请求的文件数量不得超过1000
String[] urls = urlList.toArray(new String[0]);
BucketManager.BatchOperations batchOperations = new BucketManager.BatchOperations();
batchOperations.addDeleteOp(bucket, urls);
Response response = bucketManager.batch(batchOperations);
BatchStatus[] batchStatusList = response.jsonToObject(BatchStatus[].class);
for (int i = 0; i < urls.length; i++) {
BatchStatus status = batchStatusList[i];
String key = urls[i];
System.out.print(key + "\t");
if (status.code == 200) {
System.out.println("delete success");
} else {
System.out.println(status.data.error);
}
}
} catch (QiniuException ex) {
System.err.println(ex.response.toString());
}
}
public String generateUrl(String suffix, Date uploadTime, @Nullable String prefix) {
String formatPattern = "yyyy/MM/dd";
String newPrefix = prefix == null ? "" : prefix + "/";
SimpleDateFormat formatter = new SimpleDateFormat(formatPattern);
return newPrefix + formatter.format(uploadTime) + "/" + suffix;
}
public String getTrueUrl(String urlWithoutDomain) {
return domain + "/" + urlWithoutDomain;
}
public void download(String url, String toPath) {
String encodedUrl = null;
try {
encodedUrl = URLEncoder.encode(url, "utf-8").replace("+", "%20");
} catch (UnsupportedEncodingException e) {
ExceptionUtils.printIfDev(e);
log.error("url编码失败 error:{}", e.getLocalizedMessage());
}
String publicUrl = domain + "/" + encodedUrl;
HttpUtil.downloadFile(publicUrl, new File(toPath));//下载
}
private void putAndLog(Object inputStreamOrFile, String urlWithoutDomain, String token) {
Response response = null;
try {
if (inputStreamOrFile instanceof InputStream ) {
InputStream is=(InputStream) inputStreamOrFile;
response = uploadManager.put(is, urlWithoutDomain, token, null, null);
} else if (inputStreamOrFile instanceof File) {
File file=(File) inputStreamOrFile;
response = uploadManager.put(file, urlWithoutDomain, token);
} else {
throw new IllegalArgumentException(String.format("参数inputStreamOrFile类型错误:%s", inputStreamOrFile.getClass()));
}
if (response == null) {
return;
}
//解析上传成功的结果
DefaultPutRet putRet = mapper.readValue(response.bodyString(), DefaultPutRet.class);
log.info("文件上传七牛云成功 返回结果key:{} hash:{}", putRet.key, putRet.hash);
} catch (QiniuException ex) {
Response r = ex.response;
System.err.println(r.toString());
try {
String responseMsg = r.bodyString();
log.error(responseMsg);
throw new BusinessException("服务器上传文件失败");
} catch (QiniuException ex2) {
log.error("文件上传后返回信息读取失败 url:{}", urlWithoutDomain);
throw new BusinessException("上传文件出错了");
//ignore
}
} catch (JsonProcessingException e) {
log.error("json解析七牛云返回结果异常");
throw new BusinessException("上传文件出错了,服务器解析结果异常");
}
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/deprecated/QiniuUtilsBak.java
================================================
package com.acimage.common.deprecated;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.http.HttpUtil;
import com.acimage.common.global.exception.BusinessException;
import com.acimage.common.utils.ExceptionUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qiniu.cdn.CdnManager;
import com.qiniu.cdn.CdnResult;
import com.qiniu.common.QiniuException;
import com.qiniu.http.Client;
import com.qiniu.http.Response;
import com.qiniu.storage.BucketManager;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.Region;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.BatchStatus;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.util.Auth;
import com.qiniu.util.StringMap;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Nullable;
import javax.annotation.PostConstruct;
import javax.validation.constraints.NotNull;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
@Slf4j
@Component
@ConditionalOnClass(Auth.class)
@ConfigurationProperties(prefix = "qiniu")
@Deprecated
public class QiniuUtilsBak {
private String accessKey;
private String secretKey;
private String bucket;
private String domain;
private String uploadToken;
UploadManager uploadManager;
Auth auth;
Configuration cfg;
private static final ObjectMapper mapper = new ObjectMapper();
@PostConstruct
private void init() {
cfg = new Configuration(Region.huanan());
cfg.resumableUploadAPIVersion = Configuration.ResumableUploadAPIVersion.V2;// 指定分片上传版本
uploadManager = new UploadManager(cfg);
auth = Auth.create(accessKey, secretKey);
uploadToken = auth.uploadToken(bucket);
}
public void setAccessKey(String accessKey) {
this.accessKey = accessKey;
}
public void setSecretKey(String secretKey) {
this.secretKey = secretKey;
}
public void setBucket(String bucket) {
this.bucket = bucket;
}
public void setDomain(String domain) {
this.domain = domain;
}
/**
* @param multipartFile 上传的图片
*/
public void upload(@NotNull MultipartFile multipartFile, String urlWithoutDomain) {
InputStream is;
try {
is = multipartFile.getInputStream();
} catch (IOException e) {
ExceptionUtils.printIfDev(e);
log.error("error: multipartFile.getInputStream()异常:{}", e.getMessage());
throw new RuntimeException(e);
}
putAndLog(is, urlWithoutDomain, uploadToken);
}
public void upload(@NotNull File file, String urlWithoutDomain) {
putAndLog(file, urlWithoutDomain, uploadToken);
}
public void cover(@NotNull MultipartFile multipartFile, String urlWithoutDomain) {
String coverToken = auth.uploadToken(bucket, urlWithoutDomain);
InputStream is;
try {
is = multipartFile.getInputStream();
} catch (IOException e) {
throw new RuntimeException(e);
}
putAndLog(is, urlWithoutDomain, coverToken);
new Thread(() -> {
refreshFile(urlWithoutDomain);
refreshQuery(urlWithoutDomain);
}).start();
}
public void refreshFile(String... urls) {
int urlAmountLimit = 100;
CdnManager c = new CdnManager(auth);
if (urls.length > urlAmountLimit) {
log.error("调用刷新的链接超过100个");
return;
}
//得到真实链接
for (int i = 0; i < urls.length; i++) {
urls[i] = getTrueUrl(urls[i]);
}
try {
//单次方法调用刷新的链接不可以超过100个
CdnResult.RefreshResult result = c.refreshUrls(urls);
//获取其他的回复内容
} catch (QiniuException e) {
log.error("刷新七牛云url失败 urls:{}", Arrays.asList(urls));
}
}
public void refreshQuery(String url) {
String trueUrl = getTrueUrl(url);
StringMap str = auth.authorization(trueUrl);
Client client = new Client();
try {
client.post(trueUrl, "", str);
} catch (QiniuException e) {
log.error("刷新查询oss url失败 url:{} error:{}", url,e.getMessage());
ExceptionUtils.printIfDev(e);
}
}
public void deleteFile(String url) {
BucketManager bucketManager = new BucketManager(auth, cfg);
try {
bucketManager.delete(bucket, url);
} catch (QiniuException ex) {
//如果遇到异常,说明删除失败
log.error("云文件删除失败 url:{} 返回代码:{} 返回错误信息:{}", url, ex.code(), ex.response.toString());
}
}
public void batchDelete(List urlList) {
if (CollectionUtil.isEmpty(urlList)) {
return;
}
BucketManager bucketManager = new BucketManager(auth, cfg);
try {
//单次批量请求的文件数量不得超过1000
String[] urls = urlList.toArray(new String[0]);
BucketManager.BatchOperations batchOperations = new BucketManager.BatchOperations();
batchOperations.addDeleteOp(bucket, urls);
Response response = bucketManager.batch(batchOperations);
BatchStatus[] batchStatusList = response.jsonToObject(BatchStatus[].class);
for (int i = 0; i < urls.length; i++) {
BatchStatus status = batchStatusList[i];
String key = urls[i];
System.out.print(key + "\t");
if (status.code == 200) {
System.out.println("delete success");
} else {
System.out.println(status.data.error);
}
}
} catch (QiniuException ex) {
System.err.println(ex.response.toString());
}
}
public String generateUrl(String suffix, Date uploadTime, @Nullable String prefix) {
String formatPattern = "yyyy/MM/dd";
String newPrefix = prefix == null ? "" : prefix + "/";
SimpleDateFormat formatter = new SimpleDateFormat(formatPattern);
return newPrefix + formatter.format(uploadTime) + "/" + suffix;
}
public String getTrueUrl(String urlWithoutDomain) {
return domain + "/" + urlWithoutDomain;
}
public void download(String url, String toPath) {
String encodedUrl = null;
try {
encodedUrl = URLEncoder.encode(url, "utf-8").replace("+", "%20");
} catch (UnsupportedEncodingException e) {
ExceptionUtils.printIfDev(e);
log.error("url编码失败 error:{}", e.getMessage());
}
String publicUrl = domain + "/" + encodedUrl;
long expireInSeconds = 3600;//1小时,可以自定义链接过期时间
HttpUtil.downloadFile(publicUrl, new File(toPath));//下载
}
private void putAndLog(Object inputStreamOrFile, String urlWithoutDomain, String token) {
Response response = null;
try {
if (inputStreamOrFile instanceof InputStream) {
InputStream is = (InputStream) inputStreamOrFile;
response = uploadManager.put(is, urlWithoutDomain, token, null, null);
} else if (inputStreamOrFile instanceof File) {
File file = (File) inputStreamOrFile;
response = uploadManager.put(file, urlWithoutDomain, token);
} else {
throw new IllegalArgumentException(String.format("参数inputStreamOrFile类型错误:%s", inputStreamOrFile.getClass()));
}
if (response == null) {
return;
}
//解析上传成功的结果
DefaultPutRet putRet = mapper.readValue(response.bodyString(), DefaultPutRet.class);
log.info("文件上传七牛云成功 返回结果key:{} hash:{}", putRet.key, putRet.hash);
} catch (QiniuException ex) {
Response r = ex.response;
System.err.println(r.toString());
try {
String responseMsg = r.bodyString();
log.error(responseMsg);
throw new BusinessException("服务器上传文件失败");
} catch (QiniuException ex2) {
log.error("文件上传后返回信息读取失败 url:{}", urlWithoutDomain);
throw new BusinessException("上传文件出错了");
//ignore
}
} catch (JsonProcessingException e) {
log.error("json解析七牛云返回结果异常");
throw new BusinessException("上传文件出错了,服务器解析结果异常");
}
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/deprecated/UserCommunityStatistic.java
================================================
package com.acimage.common.deprecated;
import com.acimage.common.model.domain.community.CmtyUser;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Deprecated
public class UserCommunityStatistic {
@TableId
Long userId;
Integer topicCount;
Integer starCount;
@TableField(exist = false)
CmtyUser cmtyUser;
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/deprecated/annotation/Authentication.java
================================================
package com.acimage.common.deprecated.annotation;
import com.acimage.common.global.enums.AuthenticationType;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 注解上的类或方法表示不需要登录后才能访问
*/
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Authentication {
AuthenticationType type() default AuthenticationType.TOKEN_REQUIRED;
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/deprecated/annotation/utils/AuthenticationUtils.java
================================================
package com.acimage.common.deprecated.annotation.utils;
import com.acimage.common.deprecated.annotation.Authentication;
import com.acimage.common.global.enums.AuthenticationType;
import org.springframework.web.method.HandlerMethod;
public class AuthenticationUtils {
public static AuthenticationType getAuthenticationType(HandlerMethod handlerMethod){
if(handlerMethod==null){
return null;
}
//判断方法上是否有Authorization注解
Authentication methodAuthentication =handlerMethod.getMethod().getAnnotation(Authentication.class);
if(methodAuthentication !=null){
return methodAuthentication.type();
}
//获取类上的Authorization注解
Authentication classAuthentication =handlerMethod.getBeanType().getAnnotation(Authentication.class);
if(classAuthentication !=null){
return classAuthentication.type();
}
return null;
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/deprecated/typehandler/MatchRuleTypeHandler.java
================================================
package com.acimage.common.deprecated.typehandler;
import com.acimage.common.global.enums.MatchRule;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
//@MappedTypes(MatchRule.class)
public class MatchRuleTypeHandler extends BaseTypeHandler {
@Override
public void setNonNullParameter(PreparedStatement preparedStatement, int i, MatchRule matchRule, JdbcType jdbcType) throws SQLException {
preparedStatement.setInt(i, matchRule.getKey());
}
@Override
public MatchRule getNullableResult(ResultSet resultSet, String column) throws SQLException {
return MatchRule.from(resultSet.getInt(column));
}
@Override
public MatchRule getNullableResult(ResultSet resultSet, int i) throws SQLException {
return MatchRule.from(Integer.parseInt(resultSet.getString(i)));
}
@Override
public MatchRule getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
return MatchRule.from(Integer.parseInt(callableStatement.getString(i)));
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/global/aop/LogAdvice.java
================================================
package com.acimage.common.global.aop;
import com.acimage.common.utils.common.AopUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
@Aspect
@Component
@Slf4j
@Order(200)
public class LogAdvice {
private static final int MAX_RETURN_VALUE_LENGTH = 100;
// @Pointcut("execution(public * com.acimage..*.controller.*Controller.*(..))")
@Pointcut("execution(public * com.acimage..*.*Controller.*(..))")
public void controllerPointCut() {
}
@Pointcut("execution(public * com.acimage..*.*Provider.*(..))")
public void providerPointCut() {
}
/**
* 记录每个接口出异常时时的入参
*/
@Around("controllerPointCut() || providerPointCut()")
private Object logParametersAndReturnValue(ProceedingJoinPoint joinPoint) throws Throwable {
Method method = AopUtils.methodOf(joinPoint);
Object[] args = joinPoint.getArgs();
Parameter[] parameters = method.getParameters();
long startTime = System.currentTimeMillis();
//记录入参
StringBuilder argsString = new StringBuilder();
argsString.append(method.getName());
argsString.append(" 入参-->");
if (args != null) {
for (int i = 0; i < args.length; i++) {
if (i < parameters.length) {
argsString.append(parameters[i].getName());
argsString.append(": ");
}
argsString.append(args[i]);
argsString.append(" ");
}
}
Object obj;
try {
obj = joinPoint.proceed();
} catch (Throwable e) {
log.error("出异常: " + argsString);
throw e;
}
if (!method.isAnnotationPresent(GetMapping.class)) {
String returnValue = obj == null ? "" : obj.toString();
log.info(method.getName() + " 返回值-->" + returnValue);
}
String classMethod = method.getName() + " " + method.getDeclaringClass().getSimpleName();
long cost = System.currentTimeMillis() - startTime;
if (cost > 500) {
log.warn("{}耗时 {}ms", classMethod, cost);
} else {
log.debug("{}耗时 {}ms", classMethod, cost);
}
return obj;
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/global/consts/EsConstants.java
================================================
package com.acimage.common.global.consts;
public class EsConstants {
public static final String IK_SMART="ik_smart";
public static final String IK_MAX_WORD="ik_max_word";
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/global/consts/FileFormatConstants.java
================================================
package com.acimage.common.global.consts;
import java.util.Arrays;
import java.util.List;
public class FileFormatConstants {
public static List ALLOWED_IMAGE_FORMAT = Arrays.asList("jpeg", "jpg", "png");
public static List ALLOWED_CAROUSEL_FORMAT = Arrays.asList("jpeg", "jpg", "png","webp");
public static List ALLOWED_COVER_IMAGE_FORMAT = Arrays.asList("jpeg", "jpg", "png","webp");
public static final String WEBP="webp";
public static final String WEBP_CONTENT_TYPE="image/webp";
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/global/consts/HeaderKeyConstants.java
================================================
package com.acimage.common.global.consts;
public class HeaderKeyConstants {
public static final String AUTHORIZATION="authorization";
public static final String FEIGN_X_USER_IP ="x-origin-user-ip";
public static final String SEC_WEBSOCKET_PROTOCOL="Sec-WebSocket-Protocol";
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/global/consts/JwtConstants.java
================================================
package com.acimage.common.global.consts;
public class JwtConstants {
public static final int USER_EXPIRE_DAYS = 2;
public static final int ADMIN_EXPIRE_DAYS = 1;
public static final String KEY_USERNAME="username";
public static final String KEY_USER_ID="userId";
public static final String KEY_PHOTO_URL="photoUrl";
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/global/consts/MqConstants.java
================================================
package com.acimage.common.global.consts;
public class MqConstants {
public static final String HASH_IMAGE_QUEUE = "hash-image-queue";
public static final String HASH_IMAGE_ROUTE = "hash-image-route";
public static final String REMOVE_TOPIC_IMAGES_QUEUE = "remove-topic-images-queue";
public static final String REMOVE_TOPIC_IMAGE_ROUTE = "remove-topic-images-route";
public static final String SYNC_IMAGES_QUEUE="sync-images-queue";
public static final String SYNC_IMAGES_ROUTE="sync-images-route";
public static final String SYNC_ES_QUEUE = "sync-es-queue";
public static final String SYNC_ES_ROUTE = "sync-es-route";
public static final String SYNC_USER_QUEUE = "sync-user-queue";
public static final String SYNC_USER_ROUTE = "sync-user-route";
public static final String USER_MSG_QUEUE="user-msg-queue";
public static final String USER_MSG_ROUTE="user-msg-route";
public static final String TOPIC_IMAGES_EXCHANGE = "topic-images-exchange";
public static final String SYNC_ES_EXCHANGE = "sync-es-exchange";
public static final String COMMUNITY_USER_EXCHANGE="community-user-exchange";
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/global/consts/StorePrefixConstants.java
================================================
package com.acimage.common.global.consts;
public class StorePrefixConstants {
public final static String TOPIC_IMAGE="topicImage";
public final static String USER_PHOTO="userPhoto";
public final static String COVER_IMAGE="coverImage";
public final static String HOME_CAROUSEL="homeCarousel";
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/global/consts/SysKeyConstants.java
================================================
package com.acimage.common.global.consts;
public class SysKeyConstants {
/**
* 记录网站浏览量
*/
public static final String LOGK_PAGE_VIEW="acimage:admin:websiteData:pageView";
/**
* 记录接口访问次数
*/
public static final String STRINGK_INTERFACE_TOTAL="acimage:admin:websiteData:interface:total";
public static final String STRINGK_INTERFACE_SUCCESS="acimage:admin:websiteData:interface:success";
public static final String STRINGK_INTERFACE_FAILURE="acimage:admin:websiteData:interface:failure";
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/global/consts/TimeConstants.java
================================================
package com.acimage.common.global.consts;
public class TimeConstants {
public static final long DAY_SECONDS=24*60*60;
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/global/context/UserContext.java
================================================
package com.acimage.common.global.context;
import com.acimage.common.global.enums.TokenStatus;
public class UserContext {
private static final ThreadLocal userId = new ThreadLocal<>();
private static final ThreadLocal username = new ThreadLocal<>();
private static final ThreadLocal photoUrl = new ThreadLocal<>();
private static final ThreadLocal tokenStatus = new ThreadLocal<>();
private static final ThreadLocal ip = new ThreadLocal<>();
public static void saveCurrentUserInfo(Long userId, String username, String photoUrl) {
UserContext.userId.set(userId);
UserContext.username.set(username);
UserContext.photoUrl.set(photoUrl);
}
/**
* 移除登录用户信息,在拦截器方法afterCompletion中,应移除当前用户对象
*/
public static void remove() {
userId.remove();
username.remove();
photoUrl.remove();
tokenStatus.remove();
ip.remove();
}
public static void setTokenStatus(TokenStatus tokenStatus) {
UserContext.tokenStatus.set(tokenStatus);
}
public static void setUserId(Long userId){
UserContext.userId.set(userId);
}
public static void setUsername(String username){
UserContext.username.set(username);
}
public static void setIp(String ip) {
UserContext.ip.set(ip);
}
public static Long getUserId() {
return userId.get();
}
public static String getUsername() {
return username.get();
}
public static String getPhotoUrl() {
return photoUrl.get();
}
public static TokenStatus getTokenStatus() {
return tokenStatus.get();
}
public static String getIp() {
return ip.get();
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/global/enums/AuthenticationType.java
================================================
package com.acimage.common.global.enums;
public enum AuthenticationType {
NONE(0),
TOKEN_REQUIRED(1),
ADMIN(2);
private final int key;
AuthenticationType(int key) {
this.key = key;
}
public int getKey() {
return this.key;
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/global/enums/MatchRule.java
================================================
package com.acimage.common.global.enums;
/**
* interface表中匹配规则
*/
public enum MatchRule {
/**
* 精确匹配
*/
EXACT(1),
/**
* 匹配前缀
*/
PREFIX(2);
private final int key;
MatchRule(int key) {
this.key = key;
}
public int getKey() {
return this.key;
}
public static MatchRule from(int key){
for(MatchRule matchRule:MatchRule.values()){
if(matchRule.getKey()==key){
return matchRule;
}
}
return null;
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/global/enums/MyHttpMethod.java
================================================
package com.acimage.common.global.enums;
import org.springframework.http.HttpMethod;
public enum MyHttpMethod {
GET,
POST,
PUT,
DELETE,
ALL;
public static MyHttpMethod from(HttpMethod method) {
try {
return MyHttpMethod.valueOf(method.toString());
} catch (IllegalArgumentException e) {
return null;
}
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/global/enums/ServiceType.java
================================================
package com.acimage.common.global.enums;
public enum ServiceType {
ADD,
DELETE,
UPDATE
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/global/enums/TokenStatus.java
================================================
package com.acimage.common.global.enums;
public enum TokenStatus {
PASS_TOKEN_VERIFY(0),
NULL(1),
EXPIRE(2),
INVALID(3),
MISMATCH_IP(4),
VALID(5);
private final int key;
TokenStatus(int key) {
this.key = key;
}
public int getKey() {
return this.key;
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/global/exception/BaseException.java
================================================
package com.acimage.common.global.exception;
import com.acimage.common.result.Result;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public abstract class BaseException extends RuntimeException{
Integer code;
String msg;
public Result asResult(){
return new Result(code,null,msg);
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/global/exception/BusinessException.java
================================================
package com.acimage.common.global.exception;
import com.acimage.common.result.Code;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@AllArgsConstructor
public class BusinessException extends BaseException{
public BusinessException(String msg){
this.msg=msg;
this.code= Code.ERR;
}
public BusinessException(Integer code, String msg) {
super(code, msg);
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/global/exception/NullTokenException.java
================================================
package com.acimage.common.global.exception;
import com.auth0.jwt.exceptions.JWTVerificationException;
public class NullTokenException extends JWTVerificationException {
public NullTokenException(String message){super(message);}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/global/exception/SystemException.java
================================================
package com.acimage.common.global.exception;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@AllArgsConstructor
public class SystemException extends BaseException{
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/model/Index/TopicIndex.java
================================================
package com.acimage.common.model.Index;
import cn.hutool.core.date.DatePattern;
import com.acimage.common.global.consts.EsConstants;
import com.acimage.common.model.domain.community.CmtyUser;
import com.acimage.common.model.domain.community.Tag;
import com.acimage.common.model.domain.community.Topic;
import com.acimage.common.model.domain.user.User;
import com.acimage.common.model.page.MyPage;
import com.acimage.common.utils.common.BeanUtils;
import com.acimage.common.utils.common.ListUtils;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.*;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Data
@Document(indexName = "topic")
@Setting(replicas = 0)
public class TopicIndex {
@Id
private Long id;
@Field(type = FieldType.Text)
private String all;
@Field(type = FieldType.Keyword, store = true)
private Long userId;
@Field(type = FieldType.Text, analyzer = EsConstants.IK_MAX_WORD, store = true)
private String username;
@Field(type = FieldType.Keyword, index = false, store = true)
private String photoUrl;
@Field(type = FieldType.Text, analyzer = EsConstants.IK_MAX_WORD, store = true, copyTo = "all")
private String content;
@Field(type = FieldType.Text, analyzer = EsConstants.IK_MAX_WORD, store = true, copyTo = "all")
private String title;
@Field(type = FieldType.Integer, store = true)
private Integer starCount;
@Field(type = FieldType.Integer, store = true)
private Integer pageView;
@Field(type = FieldType.Integer, store = true)
private Integer commentCount;
@Field(store = true, index = false, type = FieldType.Keyword)
private String coverImageUrl;
@Field(type = FieldType.Date, pattern = DatePattern.NORM_DATETIME_PATTERN, store = true)
private Date createTime;
@Field(type = FieldType.Date, pattern = DatePattern.NORM_DATETIME_PATTERN, store = true)
private Date updateTime;
@Field(type = FieldType.Date, pattern = DatePattern.NORM_DATETIME_PATTERN, store = true)
private Date activityTime;
@Field(type = FieldType.Keyword, store = true)
List tagIds;
@Field(type = FieldType.Keyword, store = true)
Integer categoryId;
public static TopicIndex from(Topic topic) {
TopicIndex topicIndex = BeanUtils.copyPropertiesTo(topic, TopicIndex.class);
CmtyUser user = topic.getUser();
if (user != null) {
topicIndex.setUsername(user.getUsername());
topicIndex.setPhotoUrl(user.getPhotoUrl());
}
return topicIndex;
}
public static Topic toTopic(TopicIndex topicIndex) {
Topic topic = BeanUtils.copyPropertiesTo(topicIndex, Topic.class);
CmtyUser user = new CmtyUser();
user.setUsername(topicIndex.getUsername());
user.setPhotoUrl(topicIndex.getPhotoUrl());
topic.setUser(user);
return topic;
}
public static List toTopicList(List topicIndexList) {
return topicIndexList.stream()
.map(TopicIndex::toTopic)
.collect(Collectors.toList());
}
public static MyPage toTopicPage(MyPage topicPage) {
List topicList = toTopicList(topicPage.getDataList());
return new MyPage<>(topicPage.getTotalCount(),topicList);
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/model/domain/community/Category.java
================================================
package com.acimage.common.model.domain.community;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Category {
public static final int LABEL_MAX=50;
public static final int LABEL_MIN =2;
public static final String LABEL_VALIDATION_MSG ="角色名在"+ LABEL_MIN +"-"+LABEL_MAX+"之间";
@TableId(type = IdType.AUTO)
Integer id;
String label;
private Date createTime;
private Date updateTime;
@TableLogic(delval = "1")
boolean deleted;
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/model/domain/community/CmtyUser.java
================================================
package com.acimage.common.model.domain.community;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CmtyUser {
@TableId
Long id;
String username;
String photoUrl;
Integer topicCount;
Integer starCount;
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/model/domain/community/Comment.java
================================================
package com.acimage.common.model.domain.community;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@NoArgsConstructor
public class Comment {
public static final int CONTENT_MIN=2;
public static final int CONTENT_MAX=200;
public static final String CONTENT_VALIDATION_MSG="评论字数在"+CONTENT_MIN+"-"+CONTENT_MAX+"之间";
@TableId(type= IdType.INPUT)
private Long id;
private Long topicId;
private Long userId;
private String content;
@TableLogic
private boolean deleted;
private Date createTime;
private Date updateTime;
@TableField(exist = false)
Topic topic;
@TableField(exist = false)
CmtyUser user;
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/model/domain/community/HomeCarousel.java
================================================
package com.acimage.common.model.domain.community;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class HomeCarousel {
public static final int DESC_MIN = 2;
public static final int DESC_MAX = 30;
public static final String DESC_INVALID_MSG ="图片描述字数在"+ DESC_MIN +"-"+ DESC_MAX +"之间";
public static final int LINK_MAX = 100;
public static final String LINK_INVALID_MSG ="图片描述字数在"+ 0 +"-"+ LINK_MAX +"之间";
@TableId(type= IdType.AUTO)
private Integer id;
private String description;
private String url;
private String link;
private Integer location;
private Integer size;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date updateTime;
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/model/domain/community/Star.java
================================================
package com.acimage.common.model.domain.community;
import com.acimage.common.model.domain.community.Topic;
import com.baomidou.mybatisplus.annotation.TableField;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@NoArgsConstructor
public class Star {
private Long userId;
private Long topicId;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
@TableField(exist = false)
Topic topic;
public Star(Long userId, Long topicId) {
this.userId = userId;
this.topicId = topicId;
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/model/domain/community/Tag.java
================================================
package com.acimage.common.model.domain.community;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Tag {
@TableId(type = IdType.AUTO)
Integer id;
String label;
private Date createTime;
private Date updateTime;
@TableLogic(delval = "1")
boolean deleted;
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/model/domain/community/TagTopic.java
================================================
package com.acimage.common.model.domain.community;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class TagTopic {
@TableId(type = IdType.AUTO)
Long id;
Long topicId;
Integer tagId;
private Date createTime;
@TableLogic(delval = "1")
boolean deleted;
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/model/domain/community/Topic.java
================================================
package com.acimage.common.model.domain.community;
import com.acimage.common.model.domain.user.User;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
import java.util.List;
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Data
public class Topic {
public static final int CONTENT_MIN = 4;
public static final int CONTENT_MAX = 500;
public static final String CONTENT_VALIDATION_MSG= "内容长度在" + CONTENT_MIN + "-" + CONTENT_MAX + "之间";
public static final int TITLE_MIN = 4;
public static final int TITLE_MAX = 30;
public static final String TITLE_VALIDATION_MSG= "标题长度在"+TITLE_MIN+"-"+TITLE_MAX+"之间";
public static int IMAGES_AMOUNT_MAX=5;
public static int IMAGES_AMOUNT_MIN=1;
public static final String IMAGE_VALIDATION_MSG= "图片数量在"+IMAGES_AMOUNT_MIN+"-"+IMAGES_AMOUNT_MAX+"之间";
public static int TAG_MAX=3;
public static int TAG_MIN=1;
public static final String TAG_VALIDATION_MSG= "标签数量在"+TAG_MIN+"-"+TAG_MAX+"之间";
@TableId(type= IdType.INPUT)
private Long id;
private Long userId;
private String content;
private String title;
private Integer starCount;
private Integer pageView;
private Integer commentCount;
private String coverImageUrl;
private Integer categoryId;
private Date activityTime;
private Date createTime;
private Date updateTime;
@TableLogic(delval = "1")
boolean deleted;
@TableField(exist = false)
CmtyUser user;
@TableField(exist = false)
Category category;
@TableField(exist = false)
List tagIds;
// @TableField(exist = false)
// List images;
@TableField(exist = false)
List comments;
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/model/domain/community/TopicHtml.java
================================================
package com.acimage.common.model.domain.community;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@NoArgsConstructor
@Data
public class TopicHtml {
public static final int HTML_MIN = 4;
public static final int HTML_MAX = 4500;
public static final String HTML_VALIDATION_MSG = "html源码长度在" + HTML_MIN + "-" + HTML_MAX + "之间";
@TableId(type= IdType.INPUT)
private Long topicId;
String html;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date updateTime;
@TableLogic(delval = "1")
boolean deleted;
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/model/domain/image/Image.java
================================================
package com.acimage.common.model.domain.image;
import com.acimage.common.model.domain.community.Topic;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Data
public class Image {
public static final int DESCRIPTION_MIN = 2;
public static final int DESCRIPTION_MAX = 30;
public static final String DESCRIPTION_VALIDATION_MSG ="图片描述字数在"+DESCRIPTION_MIN+"-"+DESCRIPTION_MAX+"之间";
public static final int FILE_NAME_MIN = 3;
public static final int FILE_NAME_MAX = 80;
public static final String FILE_NAME_VALIDATION_MSG ="文件名在"+FILE_NAME_MIN+"-"+FILE_NAME_MAX+"之间";
@TableId(type= IdType.INPUT)
private Long id;
private Long topicId;
private Integer size;
private String fileName;
private String description;
private String url;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date updateTime;
@TableLogic
private boolean deleted;
@TableField(exist = false)
Topic topic;
public Image(Long id, Long topicId, Integer size, String description) {
this.id = id;
this.topicId = topicId;
this.size = size;
this.description = description;
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/model/domain/image/ImageHash.java
================================================
package com.acimage.common.model.domain.image;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ImageHash {
@TableId(type= IdType.INPUT)
Long imageId;
Long hashValue;
Integer hashSum;
Date createTime;
@TableField(exist = false)
Integer distance;
public ImageHash(Long imageId, Long hashValue, Integer hashSum) {
this.imageId = imageId;
this.hashValue = hashValue;
this.hashSum = hashSum;
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/model/domain/sys/Api.java
================================================
package com.acimage.common.model.domain.sys;
import com.acimage.common.global.enums.MatchRule;
import com.acimage.common.global.enums.MyHttpMethod;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.http.HttpMethod;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Positive;
import java.util.Date;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Api {
public static final int PATH_MIN = 2;
public static final int PATH_MAX = 200;
public static final int NOTE_MAX = 100;
public static final String PATH_PATTERN="(/([a-zA-Z0-9]+|(\\*){1,2}))+";
@TableId(type = IdType.AUTO)
Integer id;
String path;
MyHttpMethod method;
Integer permissionId;
String note;
boolean enable;
Date createTime;
Date updateTime;
@TableLogic(delval = "1")
boolean deleted;
@TableField(exist = false)
Permission permission;
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/model/domain/sys/Authorize.java
================================================
package com.acimage.common.model.domain.sys;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Authorize {
@TableId(type = IdType.AUTO)
Integer id;
Integer roleId;
Integer permissionId;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date createTime;
public Authorize(Integer roleId, Integer permissionId) {
this.roleId = roleId;
this.permissionId = permissionId;
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/model/domain/sys/Permission.java
================================================
package com.acimage.common.model.domain.sys;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
import java.util.List;
@Data
@NoArgsConstructor
public class Permission {
public static final int CODE_MAX=50;
public static final int NOTE_MAX=20;
public static final int LABEL_MAX=20;
public static final String CODE_VALIDATION_MSG="权限码字数小于"+CODE_MAX;
public static final String NOTE_VALIDATION_MSG="备注字数小于"+NOTE_MAX;
public static final String LABEL_VALIDATION_MSG="标识字数小于"+LABEL_MAX;
@TableId(type = IdType.AUTO)
Integer id;
Integer parentId;
String code;
String note;
String label;
boolean module;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date updateTime;
@TableField(exist = false)
List children;
@TableField(exist = false)
Permission parent;
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/model/domain/sys/Role.java
================================================
package com.acimage.common.model.domain.sys;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@NoArgsConstructor
public class Role {
public static final int ROLE_NAME_MAX=20;
public static final int ROLE_NAME_MIN =2;
public static final String ROLE_NAME_VALIDATION_MSG ="角色名在"+ ROLE_NAME_MIN +"-"+ROLE_NAME_MAX+"之间";
public static final int NOTE_MAX=20;
public static final String NOTE_VALIDATION_MSG ="备注小于"+ROLE_NAME_MAX+"字";
@TableId(type = IdType.AUTO)
Integer id;
String roleName;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date updateTime;
String note;
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/model/domain/sys/UserRole.java
================================================
package com.acimage.common.model.domain.sys;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserRole {
@TableId(type = IdType.INPUT)
private Long id;
private Long userId;
private Integer roleId;
private Date createTime;
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/model/domain/user/CommentMsg.java
================================================
package com.acimage.common.model.domain.user;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class CommentMsg {
@TableId(type = IdType.INPUT)
Long commentId;
String content;
Long fromUserId;
Long toUserId;
Long topicId;
String topicTitle;
Date createTime;
@TableField(exist = false)
User user;
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/model/domain/user/User.java
================================================
package com.acimage.common.model.domain.user;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
@TableId(type= IdType.INPUT)
private Long id;
private String username;
private String photoUrl;
@TableField(exist = false)
private Integer starCount;
@TableField(exist = false)
private Integer topicCount;
@TableField(exist = false)
List roleIds;
public User(Long id, String username) {
this.id = id;
this.username = username;
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/model/domain/user/UserMsg.java
================================================
package com.acimage.common.model.domain.user;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
import java.util.List;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserMsg {
@TableId(type= IdType.INPUT)
private Long userId;
private Integer commentMsgCount;
private Integer starMsgCount;
private Date readCommentTime;
private Date readStarTime;
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/model/domain/user/UserPrivacy.java
================================================
package com.acimage.common.model.domain.user;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@NoArgsConstructor
public class UserPrivacy {
@TableId(type = IdType.INPUT)
private Long userId;
private String pwd;
private String salt;
private String email;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date registerTime;
public UserPrivacy(Long userId, String pwd, String salt, String email) {
this.userId = userId;
this.pwd = pwd;
this.salt = salt;
this.email = email;
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/model/mq/dto/EsAddDto.java
================================================
package com.acimage.common.model.mq.dto;
import lombok.*;
@Getter
@Setter
@NoArgsConstructor
public class EsAddDto extends ObjectWithClass {
public EsAddDto(Object obj){
this.with(obj);
}
@Override
public String toString() {
return super.toString();
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/model/mq/dto/EsDeleteDto.java
================================================
package com.acimage.common.model.mq.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class EsDeleteDto {
String id;
Class> type;
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/model/mq/dto/EsUpdateByIdDto.java
================================================
package com.acimage.common.model.mq.dto;
import lombok.*;
import java.util.List;
@Getter
@Setter
@NoArgsConstructor
public class EsUpdateByIdDto extends ObjectWithClass {
List columns;
@Override
public String toString() {
return columns+super.toString();
}
// List> columns;
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/model/mq/dto/EsUpdateByTermDto.java
================================================
package com.acimage.common.model.mq.dto;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.util.List;
@Getter
@Setter
@NoArgsConstructor
public class EsUpdateByTermDto extends ObjectWithClass{
String termColumn;
List columns;
@Override
public String toString() {
return "EsUpdateByTermDto{" +
"termColumn='" + termColumn + '\'' +
", columns=" + columns +
'}'+super.toString();
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/model/mq/dto/ImageIdWithUrl.java
================================================
package com.acimage.common.model.mq.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ImageIdWithUrl {
private Long imageId;
private String url;
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/model/mq/dto/ObjectWithClass.java
================================================
package com.acimage.common.model.mq.dto;
import com.acimage.common.utils.common.JacksonUtils;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 用于序列化时候传输
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ObjectWithClass {
private String json;
private Class> type;
public void with(Object obj){
this.setJson(JacksonUtils.writeValueAsString(obj));
this.setType(obj.getClass());
}
/**
* 千万别写成getObject,否则会导致序列化出错
*/
public Object object(){
return JacksonUtils.convert(json,type);
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/model/mq/dto/SyncImagesUpdateDto.java
================================================
package com.acimage.common.model.mq.dto;
import com.acimage.common.global.enums.ServiceType;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class SyncImagesUpdateDto {
private Long topicId;
/**
* 话题内新增的图片链接
*/
private List addImageUrls;
/**
* 话题内移除的图片链接
*/
private List removeImageUrls;
private ServiceType serviceType;
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/model/mq/dto/UserIdWithPhotoUrl.java
================================================
package com.acimage.common.model.mq.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserIdWithPhotoUrl {
private Long userId;
private String photoUrl;
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/model/mq/dto/UserIdWithUsername.java
================================================
package com.acimage.common.model.mq.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserIdWithUsername {
private Long userId;
private String username;
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/model/page/MyPage.java
================================================
package com.acimage.common.model.page;
import com.baomidou.mybatisplus.core.metadata.IPage;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class MyPage {
int totalCount;
List dataList;
public static MyPage from(IPage page){
return new MyPage<>((int)page.getTotal(),page.getRecords());
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/redis/QueryRedisAdvice.java
================================================
package com.acimage.common.redis;
import com.acimage.common.redis.annotation.KeyParam;
import com.acimage.common.redis.annotation.QueryRedis;
import com.acimage.common.redis.enums.DataType;
import com.acimage.common.utils.common.*;
import com.acimage.common.utils.redis.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.annotation.Nullable;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@Aspect
@Component
@Order(100)
@Slf4j
public class QueryRedisAdvice {
private static final String POINT_CUT_PATTERN = "@annotation(com.acimage.common.redis.annotation.QueryRedis)";
@Autowired
RedisUtils redisUtils;
@Pointcut(POINT_CUT_PATTERN)
public void pointCut() {
}
@Around("pointCut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
Method method = AopUtils.methodOf(joinPoint);
QueryRedis queryRedis = AopUtils.annotationFrom(joinPoint, QueryRedis.class);
Class> returnType = method.getReturnType();
Class>[] generics = ReflectUtils.genericsOfReturnType(method);
//获取@QueryRedis的属性
String prefix = queryRedis.keyPrefix();
TimeUnit timeUnit = queryRedis.unit();
DataType dataType = queryRedis.dataType();
//获取被注解的形参和实参
List annotatedParams = AopUtils.paramAnnotationsFrom(joinPoint, KeyParam.class);
List annotatedArgs = AopUtils.annotatedArgsFrom(joinPoint, KeyParam.class, String.class);
//获取所有实参
List args = Arrays.stream(joinPoint.getArgs()).map(Object::toString).collect(Collectors.toList());
//合并出整体key
String suffix = StringUtils.concatForNotNull(":", args);
String overallKey = prefix + suffix;
//根据注解和实参信息得到起作用的expire
long expire = getActiveExpire(queryRedis.expire(), annotatedParams, annotatedArgs);
if (expire <= 0) {
return joinPoint.proceed();
}
if (dataType == DataType.STRING) {
return queryOrProceed(joinPoint, overallKey, expire, timeUnit, returnType, generics);
} else if (dataType == DataType.HASH) {
return queryOrProceedForHash(joinPoint, overallKey, expire, timeUnit, returnType);
} else {
throw new RuntimeException(this.getClass()+"到达不存在的分支");
}
}
/**
* 查询redis,有则返回,无则调用原方法被设置到redis并返回,针对返回值是list的类型
*/
private Object queryOrProceed(ProceedingJoinPoint joinPoint, String redisKey, long expire, TimeUnit timeUnit, Class> returnType, @Nullable Class>... generics) throws Throwable {
//从redis获取
Object obj;
Class>[] newGenerics = (generics == null) ? new Class>[]{} : generics;
obj = redisUtils.getFromString(redisKey, returnType, newGenerics);
if (obj != null) {
return obj;
}
Object result = joinPoint.proceed();
//设置到redis
if (result != null) {
redisUtils.setObjectJson(redisKey, result, expire, timeUnit);
}
return result;
}
private Object queryOrProceedForHash(ProceedingJoinPoint joinPoint, String redisKey, long expire, TimeUnit timeUnit, Class> returnType) throws Throwable {
//从redis获取
Object obj;
obj = redisUtils.getObjectForHash(redisKey, returnType);
if (obj != null) {
return obj;
}
Object result = joinPoint.proceed();
//设置到redis
if (result != null) {
redisUtils.setObjectForHash(redisKey, result,expire,timeUnit);
}
return result;
}
/**
* 若当前实参值和@KeyParam中的specials匹配,则返回该参数注解的expire,否则返回default expire
* @param annotatedArgs 被注解的实参值
*/
private long getActiveExpire(long defaultExpire, List keyParams, List annotatedArgs) {
assert keyParams.size() == annotatedArgs.size();
//先判断当前被注解实参值和它们的@KeyParam注解中的spValues参数是否符合
boolean isExpireChange = false;
long expire = defaultExpire;
for (int i = 0; i < keyParams.size(); i++) {
String[] specials = keyParams.get(i).specials();
long[] expires = keyParams.get(i).expires();
//未设置specials则不用考虑
if (specials.length == 0) {
continue;
}
Integer index = ArrayUtils.firstIndexOf(specials, annotatedArgs.get(i));
if (index == null) {
//当前实参和@KeyParam注解中specials不匹配
return defaultExpire;
} else {
if (expires.length <= index) {
log.error("@KeyParam注解使用错误:specials和expire长度不一致");
} else {
if (!isExpireChange) {
expire = expires[index];
isExpireChange = true;
}
}
}
}
return expire;
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/redis/RequestLimitAdvice.java
================================================
package com.acimage.common.redis;
import com.acimage.common.global.context.UserContext;
import com.acimage.common.redis.annotation.RequestLimit;
import com.acimage.common.redis.enums.LimitTarget;
import com.acimage.common.result.Result;
import com.acimage.common.utils.common.*;
import com.acimage.common.utils.redis.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@Aspect
@Component
@Slf4j
@Order(1)
public class RequestLimitAdvice {
private static final String POINT_CUT_PATTERN = "@annotation(com.acimage.common.redis.annotation.RequestLimit)";
private static final String STRINGKP_REQUEST_LIMIT = "acimage:request:limit:";
@Autowired
RedisUtils redisUtils;
@Pointcut(POINT_CUT_PATTERN)
public void pointCut() {
}
@Around("pointCut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
Method method = AopUtils.methodOf(joinPoint);
RequestLimit requestLimit = AopUtils.annotationFrom(joinPoint, RequestLimit.class);
String methodName = method.getName();
String className = method.getDeclaringClass().getName();
String predix = STRINGKP_REQUEST_LIMIT + String.format("%s:%s:", methodName, className);
LimitTarget[] targets = requestLimit.targets();
long[] limitTimes = requestLimit.limitTimes();
long[] durations = requestLimit.durations();
long[] penaltyTimes = requestLimit.penaltyTimes();
TimeUnit timeUnit = requestLimit.unit();
int len = targets.length;
if (limitTimes.length != len || durations.length != len || penaltyTimes.length != len) {
throw new IllegalArgumentException("注解参数长度不一致");
}
List keys = new ArrayList<>();
List limitList=new ArrayList<>();
List durationList=new ArrayList<>();
List penaltyList=new ArrayList<>();
List validTargetList=new ArrayList<>();
for (int i=0;i incrementResults = redisUtils.requestLimitScript(keys, limitList, durationList, penaltyList);
for (int i = 0; i < incrementResults.size(); i++) {
if (incrementResults.get(i) > limitList.get(i)) {
switch (validTargetList.get(i)) {
case IP:
case USER:
return Result.fail("请勿频繁操作");
case ALL:
return Result.fail("系统繁忙,请稍后重试");
}
}
}
return joinPoint.proceed();
}
private List toSecondsList(long[] times, TimeUnit unit) {
Long[] ts = new Long[times.length];
for (int i = 0; i < times.length; i++) {
ts[i] = times[i];
}
return Arrays.stream(ts).map(obj -> toSeconds(obj, unit)).collect(Collectors.toList());
}
private long toSeconds(long time, TimeUnit timeUnit) {
long res = time;
switch (timeUnit) {
case DAYS:
res = res * 24;
case HOURS:
res = res * 60;
case MINUTES:
res = res * 60;
case SECONDS:
return res;
}
throw new IllegalArgumentException("只支持timeUnit为day,hour,minute,second");
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/redis/annotation/KeyParam.java
================================================
package com.acimage.common.redis.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 和@QueryRedis配合使用,被注解的参数作为redis键的后缀,可以有多个
* 但只能有一个KeyParam设置spValues和expire
*/
@Target({ElementType.FIELD,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface KeyParam {
/**
* 后缀取这些值时,过期时间根据本身的expire设置
*/
String[] specials() default {};
/**
* 对应的过期时间
*/
long[] expires() default {};
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/redis/annotation/QueryRedis.java
================================================
package com.acimage.common.redis.annotation;
import com.acimage.common.redis.enums.DataType;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.concurrent.TimeUnit;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface QueryRedis {
String keyPrefix() ;
/**
* expire<=0并且参数中没有@KeyParam设置了expire时,不会设置到redis,
*/
long expire() default 1L;
TimeUnit unit() default TimeUnit.MINUTES;
DataType dataType() default DataType.STRING;
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/redis/annotation/RequestLimit.java
================================================
package com.acimage.common.redis.annotation;
import com.acimage.common.redis.enums.LimitTarget;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.concurrent.TimeUnit;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestLimit {
long[] limitTimes();
long[] durations();
long[] penaltyTimes();
LimitTarget[] targets();
TimeUnit unit() default TimeUnit.SECONDS;
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/redis/enums/DataType.java
================================================
package com.acimage.common.redis.enums;
public enum DataType {
STRING,
HASH;
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/redis/enums/LimitTarget.java
================================================
package com.acimage.common.redis.enums;
public enum LimitTarget {
USER,
IP,
ALL,
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/redis/utils/RedisAnnotationUtils.java
================================================
package com.acimage.common.redis.utils;
import com.acimage.common.redis.annotation.KeyParam;
import com.acimage.common.utils.common.AopUtils;
import com.acimage.common.utils.redis.RedisUtils;
import com.acimage.common.utils.common.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.concurrent.TimeUnit;
@Component
public class RedisAnnotationUtils {
@Autowired
RedisUtils redisUtils;
/**
* 查询redis,有则返回,无则调用原方法被设置到redis并返回
*/
private Object queryOrProceed(ProceedingJoinPoint joinPoint, String redisKey, Class> resultType, long expire, TimeUnit unit) throws Throwable {
//查redis
Object objectResult = redisUtils.getObjectFromString(redisKey, resultType);
if (objectResult != null) {
return objectResult;
}
Object result = joinPoint.proceed();
//设置到redis
redisUtils.setObjectJson(redisKey, result, expire, unit);
return result;
}
/**
* 查询redis,有则返回,无则调用原方法被设置到redis并返回,针对返回值是list的类型
*/
private Object queryOrProceedForList(ProceedingJoinPoint joinPoint, String redisKey, Class> resultType, long expire, TimeUnit timeUnit) throws Throwable {
//从redis获取
List> objectList = redisUtils.getListFromString(redisKey, resultType);
if (objectList != null) {
return objectList;
}
Object result = joinPoint.proceed();
//设置到redis
redisUtils.setObjectJson(redisKey,result,expire,timeUnit);
return result;
}
public static String overallKey(String prefix, ProceedingJoinPoint joinPoint){
//获取所有KeyParam注解
List keyParams = AopUtils.paramAnnotationsFrom(joinPoint, KeyParam.class);
//对应实参转String
List args = AopUtils.annotatedArgsFrom(joinPoint, KeyParam.class, String.class);
//合并出整体key
String suffix = StringUtils.concatForNotNull(":", args);
return (suffix == null) ? prefix : prefix + suffix;
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/result/Code.java
================================================
package com.acimage.common.result;
public class Code {
public static final Integer SAVE_ERR=20010;
public static final Integer OK=20000;
public static final Integer ERR=20001;
public static final Integer SYSTEM_ERR=50001;
public static final Integer BUSINESS_ERR=50002;
public static final Integer DATA_NOT_EXIST=20011;
public static final Integer PARAM_INVALID =40001;
public static final Integer TOKEN_ERR=40011;
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/result/Result.java
================================================
package com.acimage.common.result;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Result {
private Integer code;
private T data;
private String msg;
public static Result fail(String message){
return new Result(Code.ERR,null,message);
}
public static Result ok(){
return new Result(Code.OK,null,"");
}
public static Result ok(T data){
return new Result(Code.OK,data,"");
}
public static boolean isOk(Result> result){
return Code.OK.equals(result.getCode());
}
public Boolean isOk(){
return Code.OK.equals(code);
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/service/TokenService.java
================================================
package com.acimage.common.service;
public interface TokenService {
Boolean hasRecorded(String token);
String createAndRecordToken(long userId, String username, String photoUrl,int expireDays);
void record(String token, int expireDays);
void invalidate(String token);
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/service/impl/TokenServiceImpl.java
================================================
package com.acimage.common.service.impl;
import com.acimage.common.global.consts.JwtConstants;
import com.acimage.common.global.context.UserContext;
import com.acimage.common.service.TokenService;
import com.acimage.common.utils.JwtUtils;
import com.acimage.common.utils.redis.RedisUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
@Service
public class TokenServiceImpl implements TokenService {
public static final String STRINGKP_TOKEN ="acimage:tokens:token:";
@Autowired
RedisUtils redisUtils;
@Override
public String createAndRecordToken(long userId, String username, String photoUrl,int expireDays){
//生成token
String token = JwtUtils.createToken(userId, username,photoUrl,expireDays);
//记录token和ip的对应
record(token, expireDays);
return token;
}
@Override
public void record(String token,int expireDays){
redisUtils.setAsString(STRINGKP_TOKEN +token,Boolean.TRUE.toString(), expireDays, TimeUnit.DAYS);
}
@Override
public Boolean hasRecorded(String token){
return redisUtils.getForString(STRINGKP_TOKEN +token)!=null;
}
@Override
public void invalidate(String token) {
redisUtils.delete(STRINGKP_TOKEN +token);
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/utils/CookieUtils.java
================================================
package com.acimage.common.utils;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
public class CookieUtils {
public static String getValueByName(Cookie[] cookies,String name){
if(cookies==null){
return null;
}
for(int i=0;i< cookies.length;i++){
if(cookies[i].getName().equals(name)){
return cookies[i].getValue();
}
}
return null;
}
public static Cookie createCookie(String key,String value){
Cookie cookie = new Cookie(key,value);
cookie.setPath("/");
cookie.setMaxAge(-1);
return cookie;
}
public static Cookie createCookie(String key,String value,boolean httpOnly){
Cookie cookie = new Cookie(key,value);
cookie.setPath("/");
cookie.setMaxAge(-1);
cookie.setHttpOnly(httpOnly);
return cookie;
}
public static Cookie createCookie(String key,String value,String path,int expire){
Cookie cookie = new Cookie(key,value);
cookie.setPath(path);
cookie.setMaxAge(expire);
return cookie;
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/utils/EsUtils.java
================================================
package com.acimage.common.utils;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.acimage.common.model.Index.TopicIndex;
import com.acimage.common.model.domain.community.Topic;
import com.acimage.common.model.mq.dto.EsAddDto;
import com.acimage.common.model.mq.dto.EsDeleteDto;
import com.acimage.common.model.mq.dto.EsUpdateByIdDto;
import com.acimage.common.model.mq.dto.EsUpdateByTermDto;
import com.acimage.common.model.page.MyPage;
import com.acimage.common.utils.common.BeanUtils;
import com.acimage.common.utils.common.ReflectUtils;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.data.annotation.Id;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.*;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.*;
import org.springframework.stereotype.Component;
import reactor.util.annotation.Nullable;
import java.util.*;
import java.util.stream.Collectors;
@Component
@Slf4j
@ConditionalOnClass(ElasticsearchRestTemplate.class)
public class EsUtils {
@Autowired
ElasticsearchRestTemplate esTemplate;
public void createIndexIfNotExist(Class> entityType) {
IndexCoordinates indexCoordinates = indexCoordinatesOf(entityType);
IndexOperations indexOperations = esTemplate.indexOps(indexCoordinates);
if (!indexOperations.exists()) {
// 创建索引和映射
indexOperations.create();
indexOperations.refresh();
Document mapping = indexOperations.createMapping(entityType);
indexOperations.refresh();
indexOperations.putMapping(mapping);
indexOperations.refresh();
log.info("创建索引和映射关系成功 {}", entityType.getSimpleName());
}
}
public void updateById(EsUpdateByIdDto updateDto) {
Object entity = updateDto.object();
if (entity == null) {
return;
}
List columns = updateDto.getColumns();
if (CollectionUtil.isEmpty(columns)) {
return;
}
//获取id
Class> indexClass = entity.getClass();
String id = Objects.requireNonNull(ReflectUtils.getAnnotatedFiled(entity, Id.class)).toString();
IndexCoordinates indexCoordinates = indexCoordinatesOf(indexClass);
Document document = this.createDocument(entity, columns);
UpdateQuery updateQuery = UpdateQuery.builder(id)
.withDocument(document)
.build();
esTemplate.update(updateQuery, indexCoordinates);
}
public void UpdateByTerm(EsUpdateByTermDto updateDto) {
Object entity = updateDto.object();
if (entity == null) {
return;
}
List columns = updateDto.getColumns();
if (CollectionUtil.isEmpty(columns)) {
return;
}
//获取更新依据的term
Class> indexClass = entity.getClass();
String termColumn = updateDto.getTermColumn();
Object termValue = BeanUtil.getFieldValue(entity, termColumn);
QueryBuilder queryBuilder = QueryBuilders.termQuery(termColumn, termValue);
IndexCoordinates indexCoordinates = indexCoordinatesOf(indexClass);
//建立脚本和参数
Map params = new HashMap<>();
StringBuilder script = new StringBuilder();
for (String column : columns) {
Object value = BeanUtil.getFieldValue(entity, column);
script.append(String.format("ctx._source.%s=params.%s;", column, column));
params.put(column, value);
}
Query query = new NativeSearchQueryBuilder()
.withQuery(queryBuilder)
.build();
UpdateQuery updateQuery = UpdateQuery.builder(query)
.withParams(params)
.withScript(script.toString())
.withScriptType(ScriptType.INLINE)
.withAbortOnVersionConflict(false)
.build();
ByQueryResponse byQueryResponse = esTemplate.updateByQuery(updateQuery, indexCoordinates);
log.debug("更新了{}条", byQueryResponse.getUpdated());
}
public void batchUpdateById(List entityList, List columns) {
if (CollectionUtil.isEmpty(entityList)) {
return;
}
Class> clz = entityList.get(0).getClass();
List updateQueries = new ArrayList<>();
for (T entity : entityList) {
String id = Objects.requireNonNull(ReflectUtils.getAnnotatedFiled(entity, Id.class)).toString();
Document document = this.createDocument(entity, columns);
UpdateQuery updateQuery = UpdateQuery.builder(id)
.withDocument(document)
.build();
updateQueries.add(updateQuery);
}
esTemplate.bulkUpdate(updateQueries, clz);
}
public void save(EsAddDto esAddDto) {
Object obj = esAddDto.object();
esTemplate.save(obj);
}
public void remove(EsDeleteDto esDeleteDto) {
esTemplate.delete(esDeleteDto.getId(), esDeleteDto.getType());
}
public MyPage termQuery(String column, Object value, Class indexClass, int pageNo, int pageSize, @Nullable FieldSortBuilder sortBuilder) {
QueryBuilder queryBuilder = QueryBuilders.termQuery(column, value);
Pageable pageable = PageRequest.of(pageNo - 1, pageSize);
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder()
.withQuery(queryBuilder)
.withPageable(pageable);
if (sortBuilder != null) {
nativeSearchQueryBuilder.withSort(sortBuilder);
}
SearchHits search = esTemplate.search(nativeSearchQueryBuilder.build(), indexClass);
int totalCount = (int) search.getTotalHits();
List dateList = toList(search.getSearchHits());
return new MyPage<>(totalCount, dateList);
}
public List similarQuery(String id, Class index, List fields, int pageNo, int pageSize) {
MoreLikeThisQuery moreLikeThisQuery = new MoreLikeThisQuery();
moreLikeThisQuery.setId(id);
moreLikeThisQuery.addFields(fields.toArray(fields.toArray(new String[0])));
moreLikeThisQuery.setPageable(PageRequest.of(pageNo - 1, pageSize));
moreLikeThisQuery.setMinTermFreq(1);
moreLikeThisQuery.setMinDocFreq(2);
log.debug("{}", esTemplate.search(moreLikeThisQuery, index).getSearchHits());
return toList(esTemplate.search(moreLikeThisQuery, index).getSearchHits());
}
public List matchQuery(Class index, String field, Object value, int pageNo, int pageSize, float score) {
MatchQueryBuilder matchQuery = QueryBuilders.matchQuery(field, value);
Pageable pageable = PageRequest.of(pageNo - 1, pageSize);
NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
.withQuery(matchQuery)
.withPageable(pageable)
.withMinScore(score)
.build();
SearchHits search = esTemplate.search(nativeSearchQuery, index);
log.debug("{}", search.getSearchHits());
return toList(search.getSearchHits());
}
public MyPage queryBySort(Class indexClass, int pageNo, int pageSize, @Nullable FieldSortBuilder sortBuilder) {
Pageable pageable = PageRequest.of(pageNo - 1, pageSize);
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder()
.withPageable(pageable);
if (sortBuilder != null) {
nativeSearchQueryBuilder.withSort(sortBuilder);
}
SearchHits search = esTemplate.search(nativeSearchQueryBuilder.build(), indexClass);
int totalCount = (int) search.getTotalHits();
List dateList = toList(search.getSearchHits());
return new MyPage<>(totalCount, dateList);
}
public IndexCoordinates indexCoordinatesOf(Class> clz) {
String indexName = clz.getAnnotation(org.springframework.data.elasticsearch.annotations.Document.class)
.indexName();
return IndexCoordinates.of(indexName);
}
private List toList(List> searchHits) {
return searchHits.stream()
.map(SearchHit::getContent)
.collect(Collectors.toList());
}
private Document createDocument(Object entity, List columns) {
Document document = Document.create();
//根据要更新的字段创建对应map
for (String column : columns) {
Object value = BeanUtil.getFieldValue(entity, column);
document.put(column, value);
}
return document;
}
private String buildScript(Object entity, List columns) {
StringBuilder script = new StringBuilder();
for (String column : columns) {
Object value = BeanUtil.getFieldValue(entity, column);
script.append(String.format("ctx.source.%s=params.%s;", column, column));
}
return script.toString();
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/utils/ExceptionUtils.java
================================================
package com.acimage.common.utils;
public class ExceptionUtils {
public static void printIfDev(Throwable e){
if(SpringContextUtils.isDev()){
e.printStackTrace();
}
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/utils/HtmlUtils.java
================================================
package com.acimage.common.utils;
import com.acimage.common.utils.common.ListUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class HtmlUtils {
private static final Pattern imageSrcPattern;
static {
String regex = "
]*\\bsrc\\b\\s*=\\s*('|\")?(/[^'\"\n\r\f>]+(\\.jpg|\\.png\\.jpe|\\.jpeg|\\.webp))\\b[^>]*>";
imageSrcPattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
}
public static String html2Text(String strHtml) {
String content = strHtml.replaceAll("?[^>]+>", ""); //剔出的标签
content = content.replaceAll("(\\s|\t|\r|\n)+", " ");//去除字符串中的空格,回车,换行符,制表符
content = content.replaceAll("(&[a-z]{2,6}+;)+", " ");//替换掉如 之类的符号
return content;
}
/**
* 获取html中相对路径开头的图片,并对结果去重
*/
public static List getInnerImageUrls(String html) {
List imageSrcList = new ArrayList<>();
Matcher m = imageSrcPattern.matcher(html);
String src;
while (m.find()) {
String quote = m.group(1);
src = (quote == null || quote.trim().length() == 0) ? m.group(2).split("\\s+")[0] : m.group(2);
imageSrcList.add(src);
}
return ListUtils.removeRepeat(imageSrcList);
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/utils/IdGenerator.java
================================================
package com.acimage.common.utils;
import cn.hutool.core.util.IdUtil;
public class IdGenerator {
public static long getSnowflakeNextId(){
return IdUtil.getSnowflakeNextId();
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/utils/ImageUtils.java
================================================
package com.acimage.common.utils;
import com.acimage.common.global.exception.BusinessException;
import com.acimage.common.global.consts.FileFormatConstants;
import com.acimage.common.utils.common.FileUtils;
import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
@Slf4j
public class ImageUtils {
public static InputStream compressAsFixedWebpImage(MultipartFile multipartFile, int width, int height, int limitSize) {
try {
float qualify = 0.76f;
BufferedImage bufferedImage = Thumbnails.fromInputStreams(Collections.singletonList(multipartFile.getInputStream()))
.outputQuality(qualify)
.forceSize(width, height)
.outputFormat(FileFormatConstants.WEBP)
.asBufferedImage();
try (InputStream is = ImageUtils.bufferedImage2InputStream(bufferedImage, FileFormatConstants.WEBP)) {
if (is != null && is.available() > limitSize) {
log.warn("the image size after compressing exceed {} size:{}", limitSize, is.available());
throw new BusinessException("图片压缩后仍然较大,请尝试其它图片");
}
return is;
}
} catch (IOException e) {
log.error(e.getMessage());
throw new BusinessException("图片数据错误");
}
}
public static InputStream compressAsWebpImage(MultipartFile multipartFile, int limitSize, int limitLength) {
try {
float qualify = 0.76f;
BufferedImage image = ImageIO.read(multipartFile.getInputStream());
int width = image.getWidth();
int height = image.getHeight();
if (width > limitLength || height > limitLength) {
if (width > height) {
width = limitLength;
//等比例缩放
height = (int) (1.0 * height * limitLength / width);
} else {
height = limitLength;
width = (int) (1.0 * width * limitLength / height);
}
}
BufferedImage bufferedImage = Thumbnails.fromInputStreams(Collections.singletonList(multipartFile.getInputStream()))
.outputQuality(qualify)
.size(width, height)
.outputFormat(FileFormatConstants.WEBP)
.asBufferedImage();
try (InputStream is = ImageUtils.bufferedImage2InputStream(bufferedImage, FileFormatConstants.WEBP)) {
if (is != null && is.available() > limitSize) {
log.warn("the image size after compressing exceed {} size:{}", limitSize, is.available());
throw new BusinessException("图片压缩后仍然较大,请尝试其它图片");
}
return is;
}
} catch (IOException e) {
log.error(e.getMessage());
throw new BusinessException("图片数据错误");
}
}
public static InputStream compressBak(MultipartFile multipartFile, int limitSize) {
String format = FileUtils.formatOf(multipartFile);
try {
long size = multipartFile.getSize();
if (size < limitSize) {
return multipartFile.getInputStream();
}
// if (size < 240 * 1000) {
// return multipartFile.getInputStream();
// } else if (limitSize * 1.0 / size > 0.8f) {
// return multipartFile.getInputStream();
// }
// Thumbnails.fromInputStreams(Collections.singletonList(multipartFile.getInputStream()));
BufferedImage bufferedImage = ImageIO.read(multipartFile.getInputStream());
if (bufferedImage == null) {
log.error("bufferedImage为空");
throw new BusinessException("图像为空");
}
Thumbnails.Builder imageBuilder = Thumbnails.fromImages(Collections.singletonList(bufferedImage));
// BufferedImage bufferedImage = inputStreamBuilder.asBufferedImage();
int height = bufferedImage.getHeight();
int width = bufferedImage.getWidth();
//按边压缩比例,要开根号
double scale = Math.sqrt(limitSize * 1.0 / (width * height));
imageBuilder.scale(scale).outputQuality(1f);
// imageBuilder.size(270, 260).outputQuality(1f);
return ImageUtils.bufferedImage2InputStream(imageBuilder.asBufferedImage(), FileUtils.formatOf(multipartFile));
} catch (IOException e) {
log.error(e.getMessage());
throw new RuntimeException(e);
}
}
public static InputStream bufferedImage2InputStream(BufferedImage image, String format) {
ByteArrayOutputStream os = new ByteArrayOutputStream();
try {
ImageIO.write(image, format, os);
return new ByteArrayInputStream(os.toByteArray());
} catch (IOException e) {
log.error(e.getMessage());
}
return null;
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/utils/IpUtils.java
================================================
package com.acimage.common.utils;
import cn.hutool.core.util.StrUtil;
import com.acimage.common.global.consts.HeaderKeyConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.server.reactive.ServerHttpRequest;
import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Objects;
@Slf4j
public class IpUtils {
//获取请求客户端IP地址
public static String getClientIpAddr(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
if ("127.0.0.1".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip)) {
//根据网卡取本机配置的IP
InetAddress inet = null;
try {
inet = InetAddress.getLocalHost();
} catch (Exception e) {
ExceptionUtils.printIfDev(e);
}
assert inet != null;
ip = inet.getHostAddress();
}
}
// 多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
if (ip != null && ip.length() > 15) {
if (ip.indexOf(",") > 0) {
ip = ip.substring(0, ip.indexOf(","));
}
}
return ip;
}
private final static String IP_UTILS_FLAG = ",";
// 未知IP
private final static String UNKNOWN = "unknown";
// 本地 IP
private final static String LOCALHOST_IP = "0:0:0:0:0:0:0:1";
private final static String LOCALHOST_IP1 = "127.0.0.1";
public static String getUserIp(ServerHttpRequest request) {
// 多次反向代理后会有多个ip值 的分割符
// 根据 HttpHeaders 获取 请求 IP地址
String ip = request.getHeaders().getFirst("X-Forwarded-For");
// if (StrUtil.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
// ip = request.getHeaders().getFirst("x-forwarded-for");
// if (ip != null && ip.length() != 0 && !UNKNOWN.equalsIgnoreCase(ip)) {
// // 多次反向代理后会有多个ip值,第一个ip才是真实ip
// if (ip.contains(IP_UTILS_FLAG)) {
// ip = ip.split(IP_UTILS_FLAG)[0];
// }
// }
// }
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeaders().getFirst("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeaders().getFirst("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeaders().getFirst("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeaders().getFirst("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeaders().getFirst("X-Real-IP");
}
//兼容k8s集群获取ip
if (StrUtil.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = Objects.requireNonNull(request.getRemoteAddress()).getAddress().getHostAddress();
if (LOCALHOST_IP1.equalsIgnoreCase(ip) || LOCALHOST_IP.equalsIgnoreCase(ip)) {
//根据网卡取本机配置的IP
InetAddress iNet = null;
try {
iNet = InetAddress.getLocalHost();
ip = iNet.getHostAddress();
} catch (UnknownHostException e) {
log.error("getClientIp error:{}", e.getMessage());
}
}
}
return ip;
}
public static String getIp(HttpServletRequest request) {
String originUserIp = request.getHeader(HeaderKeyConstants.FEIGN_X_USER_IP);
if (!StrUtil.isEmpty(originUserIp)) {
return originUserIp;
} else {
return getClientIpAddr(request);
}
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/utils/JwtUtils.java
================================================
package com.acimage.common.utils;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.acimage.common.global.consts.JwtConstants;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.acimage.common.global.exception.NullTokenException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.Date;
@Component
public class JwtUtils {
@Value("${jwt.secret-key}")
public String secretKey;
private static String SECRET_KEY;
@PostConstruct
private void init(){
SECRET_KEY=this.secretKey;
}
public static String createToken(long userId, String username, String photoUrl, int expireDays) {
return JWT.create()
.withIssuedAt(new Date()) //发行时间
.withExpiresAt(DateUtil.offsetDay(new Date(), expireDays)) //有效截止时间
.withClaim(JwtConstants.KEY_USER_ID, userId) //载荷,存储不敏感的用户信息
.withClaim(JwtConstants.KEY_USERNAME, username)
.withClaim(JwtConstants.KEY_PHOTO_URL, photoUrl)
.sign(Algorithm.HMAC256(SECRET_KEY)); //加密(摘要)
}
public static void verifyToken(String token) throws JWTVerificationException {
if (StrUtil.isBlank(token)) {
throw new NullTokenException("token is null!");
}
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SECRET_KEY)).build();
verifier.verify(token);
}
public static Long getUserId(String token) throws JWTDecodeException {
return JWT.decode(token).getClaim(JwtConstants.KEY_USER_ID).asLong();
}
public static String getUsername(String token) throws JWTDecodeException {
return JWT.decode(token).getClaim(JwtConstants.KEY_USERNAME).asString();
}
public static String getPhotoUrl(String token) throws JWTDecodeException {
return JWT.decode(token).getClaim(JwtConstants.KEY_PHOTO_URL).asString();
}
public static Date getExpire(String token) throws JWTDecodeException {
return JWT.decode(token).getExpiresAt();
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/utils/LambdaUtils.java
================================================
package com.acimage.common.utils;
import cn.hutool.core.util.ReflectUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import lombok.extern.slf4j.Slf4j;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
@Slf4j
public class LambdaUtils {
public static final String TOKEN_GET="get";
public static final String TOKEN_IS="is";
public static final String WRITE_REPLACE="writeReplace";
public static String underlineColumnNameOf(SFunction getOrIs) {
return StringUtils.camelToUnderline(columnOf(getOrIs));
}
public static String columnOf(SFunction getOrIs) {
// 从function取出序列化方法
Method writeReplaceMethod = ReflectUtil.getMethodByName(getOrIs.getClass(), WRITE_REPLACE);
// 从序列化方法取出序列化的lambda信息
// boolean isAccessible = writeReplaceMethod.isAccessible();
/**
* 如果要通过isAccessible设置回去,一定要考虑并发问题
*/
writeReplaceMethod.setAccessible(true);
SerializedLambda serializedLambda;
try {
serializedLambda = (SerializedLambda) writeReplaceMethod.invoke(getOrIs);
} catch (IllegalAccessException | InvocationTargetException e) {
log.error(e.getMessage());
throw new RuntimeException(e);
}
//如果将访问属性设置回去,这里可能会出错
//writeReplaceMethod.setAccessible(isAccessible);
// 从lambda信息取出method等
String methodName = serializedLambda.getImplMethodName();
String capitalizeFieldName;
if (methodName.startsWith(TOKEN_IS)) {
capitalizeFieldName = methodName.substring(TOKEN_IS.length());
} else if (methodName.startsWith(TOKEN_GET)) {
capitalizeFieldName = methodName.substring(TOKEN_GET.length());
} else {
throw new IllegalArgumentException(methodName + "前缀非get或is");
}
return StringUtils.firstToLowerCase(capitalizeFieldName);
}
@SafeVarargs
public static List columnsFrom(SFunction... getOrIsFunctions) {
List columns=new ArrayList<>();
for(SFunction function:getOrIsFunctions){
columns.add(columnOf(function));
}
return columns;
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/utils/RsaUtils.java
================================================
package com.acimage.common.utils;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
public class RsaUtils {
private static final String privateKey;
private static final String publicKey;
static {
RSA rsa = new RSA();
privateKey=rsa.getPrivateKeyBase64();
publicKey =rsa.getPublicKeyBase64();
}
public static String decrypt(String privateKeyBase64,String encryptBase64){
RSA rsa=new RSA(privateKeyBase64,null);
return rsa.decryptStr(encryptBase64, KeyType.PrivateKey);
}
public static String getPrivateKey(){
return privateKey;
}
public static String getPublicKey(){
return publicKey;
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/utils/SensitiveWordUtils.java
================================================
package com.acimage.common.utils;
import cn.hutool.core.io.file.FileReader;
import cn.hutool.core.io.resource.ClassPathResource;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.stereotype.Component;
import toolgood.words.StringSearch;
import javax.annotation.PostConstruct;
import java.io.*;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
@Component
@ConditionalOnClass(StringSearch.class)
public class SensitiveWordUtils {
private static StringSearch search;
String sensitiveWordFileName="sensitive_word.txt";
@PostConstruct
private void init(){
//
ClassPathResource classPathResource = new ClassPathResource(sensitiveWordFileName);
InputStream inputStream = classPathResource.getStream();
List words = this.readLines(inputStream);
search = new StringSearch();
search.SetKeywords(words);
}
private List readLines(InputStream inputStream){
InputStreamReader isr = new InputStreamReader(inputStream);//传入InputStream in 键盘录入对象 in
List words=new ArrayList<>();
//为了提高效率,将字符串进行缓冲区技术高效操作.使用BufferedReader
BufferedReader bufr = new BufferedReader(isr);
String line = null;
try {
while ((line = bufr.readLine())!=null) {
words.add(line);
}
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
try {
bufr.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return words;
}
public static String filter(String str){
return search.Replace(str,'*');
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/utils/SpringContextUtils.java
================================================
package com.acimage.common.utils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class SpringContextUtils implements ApplicationContextAware {
/**
* spring的应用上下文
*/
private static ApplicationContext applicationContext;
/**
* 初始化时将应用上下文设置进applicationContext
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringContextUtils.applicationContext=applicationContext;
}
public static ApplicationContext getApplicationContext(){
return applicationContext;
}
public static Object getBean(String name) throws BeansException {
return applicationContext.getBean(name);
}
public static T getBean(Class beanClass) throws BeansException {
return applicationContext.getBean(beanClass);
}
/**
* 获取spring.profiles.active
* @return
*/
public static String getProfile(){
return getApplicationContext().getEnvironment().getActiveProfiles()[0];
}
public static boolean isDev(){
String[] profiles=getApplicationContext().getEnvironment().getActiveProfiles();
for(String profile:profiles){
if(profile.startsWith("dev")){
return true;
}
}
return false;
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/utils/common/AopUtils.java
================================================
package com.acimage.common.utils.common;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import com.acimage.common.utils.ExceptionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import javax.validation.constraints.NotNull;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.List;
@Slf4j
public class AopUtils {
public static Method methodOf(@NotNull JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method;
try {
method = joinPoint.getTarget()
.getClass()
.getMethod(signature.getMethod().getName(),
signature.getMethod().getParameterTypes());
} catch (NoSuchMethodException e) {
ExceptionUtils.printIfDev(e);
throw new RuntimeException(e);
}
return method;
}
public static boolean hasParameters(@NotNull JoinPoint joinPoint) {
Parameter[] parameters = methodOf(joinPoint).getParameters();
return parameters != null && parameters.length != 0;
}
public static T annotationFrom(JoinPoint joinPoint, Class annotation) {
Method method = methodOf(joinPoint);
return method.getAnnotation(annotation);
}
public static List paramAnnotationsFrom(JoinPoint joinPoint, Class annotation) {
Parameter[] parameters = methodOf(joinPoint).getParameters();
List annotationList=new ArrayList<>();
for(int i=0;i V annotatedArgOrArgFieldOf(@NotNull JoinPoint joinPoint, Class annotation, Class targetType) {
Parameter[] parameters = methodOf(joinPoint).getParameters();
Object[] args = joinPoint.getArgs();
Integer firstIndex = indexOfFirstAnnotatedParameter(parameters, annotation);
if (firstIndex != null) {
return Convert.convert(targetType, args[firstIndex]);
}
for(int i=0;i List annotatedArgsFrom(@NotNull JoinPoint joinPoint, Class annotation, Class targetType) {
Parameter[] parameters = methodOf(joinPoint).getParameters();
Object[] args = joinPoint.getArgs();
List annotatedObjectList=new ArrayList<>();
for (int i = 0; i < parameters.length; i++) {
if (parameters[i].isAnnotationPresent(annotation)) {
annotatedObjectList.add(Convert.convert(targetType, args[i]));
}
}
return annotatedObjectList;
}
private static Integer indexOfFirstAnnotatedParameter(Parameter[] parameters, Class annotation) {
for (int i = 0; i < parameters.length; i++) {
if (parameters[i].isAnnotationPresent(annotation)) {
return i;
}
}
return null;
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/utils/common/ArrayUtils.java
================================================
package com.acimage.common.utils.common;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
import java.util.List;
public class ArrayUtils {
public static Integer firstIndexOf(String[] strs, String targetStr){
for(int i=0;i beanToFieldJsonMap(Object javaBean) {
Map map = BeanUtil.beanToMap(javaBean, false, true);
Map fieldJsonMap = new HashMap<>();
Set keys = map.keySet();
for (String key : keys) {
Object obj = map.get(key);
String json = JacksonUtils.writeValueAsString(obj);
fieldJsonMap.put(key, json);
}
return fieldJsonMap;
}
public static T fieldJsonMapToBean(Map fieldJsonMap, Class clz) {
T instance=ReflectUtil.newInstance(clz);
List fieldName = ReflectUtils.getFieldNames(clz);
Set keys = fieldJsonMap.keySet();
for (String key : keys) {
if (fieldName.contains(key)) {
String json = fieldJsonMap.get(key);
//json转对象
Object obj = JacksonUtils.convert(json, ReflectUtil.getField(clz, key).getType());
//获取方法
String setMethodName = StringUtils.concatCapitalize(SET, key);
Method setMethod = ReflectUtil.getMethodByName(clz, setMethodName);
//调用方法,将属性set进去
ReflectUtil.invoke(instance, setMethod, obj);
}
}
return instance;
}
public static T copyPropertiesTo(Object source,Class targetType){
T target=ReflectUtil.newInstance(targetType);
BeanUtil.copyProperties(source,target,false);
return target;
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/utils/common/FileUtils.java
================================================
package com.acimage.common.utils.common;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
@Slf4j
public class FileUtils {
public static void packageFiles(File[] files, File zipFile) throws IOException {
byte[] buffer = new byte[4096];
ZipOutputStream out = new ZipOutputStream(Files.newOutputStream(zipFile.toPath()));
for (int i = 0; i < files.length; i++) {
FileInputStream fis = new FileInputStream(files[i]);
// FileInputStream fis = new FileInputStream(files[i].getPath());
out.putNextEntry(new ZipEntry(files[i].getName()));
int len;
// 读入需要下载的文件的内容,打包到zip文件
while ((len = fis.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
out.closeEntry();
fis.close();
}
out.close();
}
public static void downloadFileForClient(File file, HttpServletResponse response) throws IOException{
response.setCharacterEncoding("utf-8");
// response.setContentType("application/octet-stream");
// 以流的形式下载文件。
BufferedInputStream fis = new BufferedInputStream(Files.newInputStream(Paths.get(file.getPath())));
byte[] buffer = new byte[fis.available()];
fis.read(buffer);
fis.close();
// 清空response
response.reset();
OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment;filename=" + file.getName());
toClient.write(buffer);
toClient.flush();
toClient.close();
}
public static String formatOf(String fileName){
return StrUtil.subAfter(fileName,".",true);
}
public static String formatOf(MultipartFile multipartFile){
String fileName=multipartFile.getOriginalFilename();
return StrUtil.subAfter(fileName,".",true);
}
public static List formatsOf(MultipartFile[] multipartFiles){
if(multipartFiles==null){
return null;
}else if(multipartFiles.length==0){
return new ArrayList<>();
}else{
List formatList=new ArrayList<>();
for (MultipartFile multipartFile : multipartFiles) {
formatList.add(formatOf(multipartFile.getOriginalFilename()));
}
return formatList;
}
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/utils/common/JacksonUtils.java
================================================
package com.acimage.common.utils.common;
import com.acimage.common.utils.ExceptionUtils;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import javax.annotation.Nullable;
import java.util.List;
@Slf4j
public class JacksonUtils {
private static final ObjectMapper mapper = new ObjectMapper();
static {
//设置忽略空字段
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
}
public static String writeValueAsString(Object object) {
String json = null;
try {
json = mapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
ExceptionUtils.printIfDev(e);
log.error("对象序列化成json错误 对象[{}] error:{}", object,e.getMessage());
throw new RuntimeException(e);
}
return json;
}
public static List getList(@Nullable String json, Class ofType) {
if (json == null) {
return null;
}
JavaType javaType = mapper.getTypeFactory().constructParametricType(List.class, ofType);
try {
return mapper.readValue(json, javaType);
} catch (JsonProcessingException e) {
log.error("数据反序列化异常 json:{} type:{} error:{}", json,javaType,e.getMessage());
throw new RuntimeException(e);
}
}
public static T convert(@Nullable String json, Class targetType) {
if (json == null) {
return null;
}
try {
return mapper.readValue(json, targetType);
} catch (JsonProcessingException e) {
log.error("数据反序列化异常 json:{} type:{} error:{}", json,targetType,e.getMessage());
throw new RuntimeException(e);
}
}
}
================================================
FILE: acimage_common/src/main/java/com/acimage/common/utils/common/ListUtils.java
================================================
package com.acimage.common.utils.common;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Pair;
import org.springframework.data.redis.core.ZSetOperations;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
public class ListUtils {
public static List extract(Function attribute, List list) {
if (list == null) {
return null;
}
return list.stream().map(attribute).collect(Collectors.toList());
}
public static List extractKeyFrom(List> pairList) {
List keyList = new ArrayList<>();
for (Pair item : pairList) {
keyList.add(item.getKey());
}
return keyList;
}
public static List getListFrom(Set set) {
if (set == null) {
return null;
}
List list = new ArrayList<>(set.size());
return null;
}
public static List differenceSetOf(List list1, List list2) {
if (list2 == null || list2.size() == 0) {
return list1;
} else if (list1 == null || list1.size() == 0) {
return list1;
}
List list1Copy = new ArrayList<>(list1);
List list2Copy = new ArrayList<>(list2);
Comparator longComparator = Comparator.naturalOrder();
list1Copy.sort(longComparator);
list2Copy.sort(longComparator);
int ptr1 = 0, ptr2 = 0;
List differenceList = new ArrayList<>();
while (ptr1 < list1Copy.size() && ptr2 < list2Copy.size()) {
if (list1Copy.get(ptr1) < list2Copy.get(ptr2)) {
differenceList.add(list1Copy.get(ptr1));
ptr1++;
} else if (list1Copy.get(ptr1) > list2Copy.get(ptr2)) {
ptr2++;
} else if (list1Copy.get(ptr1).equals(list2Copy.get(ptr2))) {
ptr1++;
ptr2++;
}
}
if (ptr2 == list2Copy.size()) {
while (ptr1 < list1Copy.size()) {
differenceList.add(list1Copy.get(ptr1));
ptr1++;
}
}
return differenceList;
}
public static List differenceSetOfV2(List list1, List list2) {
if (list2 == null || list2.size() == 0) {
return list1;
} else if (list1 == null || list1.size() == 0) {
return list1;
}
List list1Copy = new ArrayList<>(list1);
List list2Copy = new ArrayList<>(list2);
Comparator stringComparator = Comparator.naturalOrder();
list1Copy.sort(stringComparator);
list2Copy.sort(stringComparator);
int ptr1 = 0, ptr2 = 0;
List differenceList = new ArrayList<>();
while (ptr1 < list1Copy.size() && ptr2 < list2Copy.size()) {
if (list1Copy.get(ptr1).compareTo(list2Copy.get(ptr2))<0 ) {
differenceList.add(list1Copy.get(ptr1));
ptr1++;
} else if (list1Copy.get(ptr1).compareTo(list2Copy.get(ptr2))>0 ) {
ptr2++;
} else if (list1Copy.get(ptr1).equals(list2Copy.get(ptr2))) {
ptr1++;
ptr2++;
}
}
if (ptr2 == list2Copy.size()) {
while (ptr1 < list1Copy.size()) {
differenceList.add(list1Copy.get(ptr1));
ptr1++;
}
}
return differenceList;
}
public static boolean isEmpty(List list) {
return list == null || list.size() == 0;
}
public static List