├── docs ├── imgs │ ├── 1.png │ ├── 2.png │ ├── 3.png │ ├── 4.png │ ├── pdm.png │ ├── swagger.png │ ├── nice-fish.png │ ├── maven-modules.png │ └── front-end-back-end.png ├── 画图用的PPT.pptx └── elastic-mysql-jdbc.conf ├── nicefish-cms ├── src │ └── main │ │ ├── resources │ │ ├── META-INF │ │ │ └── MANIFEST.MF │ │ ├── banner.txt │ │ ├── application-druid.yml │ │ └── application.yml │ │ └── java │ │ └── com │ │ └── nicefish │ │ ├── cms │ │ ├── service │ │ │ ├── ISysParamService.java │ │ │ ├── IFileUploadService.java │ │ │ ├── ICommentService.java │ │ │ ├── IUserFollowService.java │ │ │ ├── IPostService.java │ │ │ ├── impl │ │ │ │ ├── SysParamServiceImpl.java │ │ │ │ ├── CommentServiceImpl.java │ │ │ │ ├── UserFollowServiceImpl.java │ │ │ │ ├── UserPostRelationServiceImpl.java │ │ │ │ └── PostServiceImpl.java │ │ │ └── IUserPostRelationService.java │ │ ├── jpa │ │ │ ├── repository │ │ │ │ ├── IFileUploadRepository.java │ │ │ │ ├── ISysParamRepository.java │ │ │ │ ├── IPostFileUploadRepository.java │ │ │ │ ├── IPostRepository.java │ │ │ │ ├── ICommentRepository.java │ │ │ │ ├── IUserFollowRepository.java │ │ │ │ └── IUserPostRelationRepository.java │ │ │ └── entity │ │ │ │ ├── PostFileUploadEntity.java │ │ │ │ ├── SysParamEntity.java │ │ │ │ ├── UserFollowEntity.java │ │ │ │ ├── UserPostRelationEntity.java │ │ │ │ ├── CommentEntity.java │ │ │ │ └── FileUploadEntity.java │ │ ├── util │ │ │ ├── ResponsePageImpl.java │ │ │ └── HashUtils.java │ │ ├── config │ │ │ ├── DruidConfig.java │ │ │ └── DruidProperties.java │ │ └── controller │ │ │ ├── SysParamController.java │ │ │ ├── FileUploadController.java │ │ │ ├── UserFollowController.java │ │ │ ├── CommentController.java │ │ │ ├── PostController.java │ │ │ └── UserPostRelationController.java │ │ └── NiceFishCMSApplication.java └── pom.xml ├── .vscode └── settings.json ├── nicefish-elastic-search ├── src │ └── main │ │ ├── resources │ │ ├── META-INF │ │ │ └── MANIFEST.MF │ │ └── application.yml │ │ └── java │ │ └── com │ │ └── nicefish │ │ └── search │ │ ├── service │ │ ├── IPostSearchService.java │ │ ├── IUserSearchService.java │ │ └── impl │ │ │ ├── PostSearchServiceImpl.java │ │ │ └── UserSearchServiceImpl.java │ │ ├── repository │ │ ├── PostSearchRepository.java │ │ └── UserSearchRepository.java │ │ ├── NiceFishSearchApplication.java │ │ ├── controller │ │ ├── UserSearchController.java │ │ └── PostSearchController.java │ │ └── entity │ │ ├── PostSearchEntity.java │ │ └── UserSearchEntity.java └── pom.xml ├── nicefish-shiro-rbac ├── src │ └── main │ │ ├── java │ │ └── com │ │ │ └── nicefish │ │ │ └── rbac │ │ │ ├── exception │ │ │ ├── EmailDuplicateException.java │ │ │ ├── CellphoneDuplicateException.java │ │ │ ├── UserNotExistsException.java │ │ │ └── UserNameDuplicateException.java │ │ │ ├── config │ │ │ ├── JpaConfig.java │ │ │ ├── I18nConfig.java │ │ │ └── CaptchaConfig.java │ │ │ ├── service │ │ │ ├── INiceFishSessionService.java │ │ │ ├── IRoleService.java │ │ │ ├── IApiPermissionService.java │ │ │ ├── IComponentPermissionService.java │ │ │ ├── IUserService.java │ │ │ └── impl │ │ │ │ ├── NiceFishSessionServiceImpl.java │ │ │ │ ├── ApiPermissionServiceImpl.java │ │ │ │ └── ComponentPermissionServiceImpl.java │ │ │ ├── jpa │ │ │ ├── repository │ │ │ │ ├── IRoleComponentRepository.java │ │ │ │ ├── IComponentPermissionRepository.java │ │ │ │ ├── IApiPermissionRepository.java │ │ │ │ ├── INiceFishSessionRepository.java │ │ │ │ ├── IUserRoleRepository.java │ │ │ │ ├── IRoleRepository.java │ │ │ │ ├── IRoleApiRepository.java │ │ │ │ └── IUserRepository.java │ │ │ └── entity │ │ │ │ ├── UserRoleEntity.java │ │ │ │ ├── RoleComponentEntity.java │ │ │ │ ├── RoleApiEntity.java │ │ │ │ ├── RoleEntity.java │ │ │ │ ├── ApiPermissionEntity.java │ │ │ │ ├── UserEntity.java │ │ │ │ ├── NiceFishSessionEntity.java │ │ │ │ └── ComponentPermissionEntity.java │ │ │ ├── jpautils │ │ │ ├── RoleListDeserializer.java │ │ │ └── RoleListSerializer.java │ │ │ ├── constant │ │ │ └── AuthConstants.java │ │ │ ├── shiro │ │ │ ├── session │ │ │ │ └── NiceFishSessionFactory.java │ │ │ ├── util │ │ │ │ └── NiceFishSecurityUtils.java │ │ │ ├── realm │ │ │ │ └── NiceFishMySQLRealm.java │ │ │ └── filter │ │ │ │ └── NiceFishCaptchaValidateFilter.java │ │ │ ├── util │ │ │ └── KaptchaTextCreator.java │ │ │ └── controller │ │ │ ├── ApiPermissionController.java │ │ │ ├── ComponentPermissionController.java │ │ │ ├── CaptchaController.java │ │ │ ├── ShiroAuthController.java │ │ │ └── UserController.java │ │ └── resources │ │ ├── i18n │ │ ├── messages.properties │ │ └── messages_en.properties │ │ └── ehcache-shiro.xml └── pom.xml ├── nicefish-core ├── src │ └── main │ │ └── java │ │ └── com │ │ └── nicefish │ │ └── core │ │ ├── i18n │ │ ├── LocalizationUtils.java │ │ ├── I18nService.java │ │ └── I18nUtil.java │ │ ├── exception │ │ └── NiceFishBaseException.java │ │ └── utils │ │ ├── AjaxResult.java │ │ └── IPUtil.java └── pom.xml ├── .gitignore ├── LICENSE └── NiceFish.sh /docs/imgs/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/damoqiongqiu/nicefish-spring-boot/HEAD/docs/imgs/1.png -------------------------------------------------------------------------------- /docs/imgs/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/damoqiongqiu/nicefish-spring-boot/HEAD/docs/imgs/2.png -------------------------------------------------------------------------------- /docs/imgs/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/damoqiongqiu/nicefish-spring-boot/HEAD/docs/imgs/3.png -------------------------------------------------------------------------------- /docs/imgs/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/damoqiongqiu/nicefish-spring-boot/HEAD/docs/imgs/4.png -------------------------------------------------------------------------------- /docs/imgs/pdm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/damoqiongqiu/nicefish-spring-boot/HEAD/docs/imgs/pdm.png -------------------------------------------------------------------------------- /docs/画图用的PPT.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/damoqiongqiu/nicefish-spring-boot/HEAD/docs/画图用的PPT.pptx -------------------------------------------------------------------------------- /docs/imgs/swagger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/damoqiongqiu/nicefish-spring-boot/HEAD/docs/imgs/swagger.png -------------------------------------------------------------------------------- /docs/imgs/nice-fish.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/damoqiongqiu/nicefish-spring-boot/HEAD/docs/imgs/nice-fish.png -------------------------------------------------------------------------------- /docs/imgs/maven-modules.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/damoqiongqiu/nicefish-spring-boot/HEAD/docs/imgs/maven-modules.png -------------------------------------------------------------------------------- /docs/imgs/front-end-back-end.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/damoqiongqiu/nicefish-spring-boot/HEAD/docs/imgs/front-end-back-end.png -------------------------------------------------------------------------------- /nicefish-cms/src/main/resources/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Main-Class: com.nicefish.NiceFishCMSApplication 3 | 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "java.compile.nullAnalysis.mode": "automatic", 3 | "java.configuration.updateBuildConfiguration": "disabled" 4 | } -------------------------------------------------------------------------------- /nicefish-elastic-search/src/main/resources/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Main-Class: com.nicefish.search.NiceFishSearchApplication 3 | 4 | -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/exception/EmailDuplicateException.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.exception; 2 | 3 | import com.nicefish.core.exception.NiceFishBaseException; 4 | 5 | public class EmailDuplicateException extends NiceFishBaseException { 6 | private static final long serialVersionUID = 1L; 7 | } 8 | -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/exception/CellphoneDuplicateException.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.exception; 2 | 3 | import com.nicefish.core.exception.NiceFishBaseException; 4 | 5 | public class CellphoneDuplicateException extends NiceFishBaseException { 6 | private static final long serialVersionUID = 1L; 7 | } 8 | -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/exception/UserNotExistsException.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.exception; 2 | 3 | import com.nicefish.core.exception.NiceFishBaseException; 4 | 5 | /** 6 | * 用户不存在异常类 7 | * 8 | * @author 大漠穷秋 9 | */ 10 | public class UserNotExistsException extends NiceFishBaseException { 11 | private static final long serialVersionUID = 1L; 12 | } 13 | -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/exception/UserNameDuplicateException.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.exception; 2 | 3 | import com.nicefish.core.exception.NiceFishBaseException; 4 | 5 | /** 6 | * 用户不存在异常类 7 | * 8 | * @author 大漠穷秋 9 | */ 10 | public class UserNameDuplicateException extends NiceFishBaseException { 11 | private static final long serialVersionUID = 1L; 12 | } 13 | -------------------------------------------------------------------------------- /nicefish-elastic-search/src/main/java/com/nicefish/search/service/IPostSearchService.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.search.service; 2 | 3 | import org.springframework.data.domain.Page; 4 | import com.nicefish.search.entity.PostSearchEntity; 5 | 6 | public interface IPostSearchService { 7 | Iterable getAll(); 8 | 9 | Page searchSimilar(PostSearchEntity entity, int page, int size); 10 | } -------------------------------------------------------------------------------- /nicefish-elastic-search/src/main/java/com/nicefish/search/service/IUserSearchService.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.search.service; 2 | 3 | import com.nicefish.search.entity.UserSearchEntity; 4 | import org.springframework.data.domain.Page; 5 | 6 | public interface IUserSearchService { 7 | Iterable getAll(); 8 | 9 | Page searchSimilar(UserSearchEntity entity, int page, int size); 10 | } -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/resources/i18n/messages.properties: -------------------------------------------------------------------------------- 1 | # 通用提示 2 | common.del.success=删除成功 3 | 4 | #各个模块提示 5 | #用户 6 | user.del.failure=删除失败,内置用户或者正在使用中。 7 | #带参数的示例 8 | user.del.arg.failure=删除失败,内置用户或者用户 {0} 正在使用中。 9 | user.del.success=删除成功。 10 | user.update.not.exists=用户不存在。 11 | 12 | #角色 13 | role.del.failure=删除失败,系统内置角色或者正在使用中。 14 | 15 | #认证授权 16 | auth.register.user.mail.failure=用户名或者邮箱已存在 17 | auth.register.mail.failure=相同的邮箱已存在 18 | auth.register.phone.failure=相同的手机号已存在 -------------------------------------------------------------------------------- /nicefish-cms/src/main/java/com/nicefish/cms/service/ISysParamService.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.cms.service; 2 | 3 | import com.nicefish.cms.jpa.entity.SysParamEntity; 4 | import org.springframework.data.domain.Page; 5 | import org.springframework.data.domain.Pageable; 6 | 7 | import java.util.Map; 8 | 9 | /** 10 | * @author 大漠穷秋 11 | */ 12 | public interface ISysParamService { 13 | Page getParamPaging(Pageable pageable); 14 | 15 | Map getAllParamJSON(); 16 | } 17 | -------------------------------------------------------------------------------- /nicefish-core/src/main/java/com/nicefish/core/i18n/LocalizationUtils.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.core.i18n; 2 | 3 | import org.springframework.context.i18n.LocaleContextHolder; 4 | 5 | import java.util.Locale; 6 | 7 | /** 8 | * 9 | * 返回与当前线程关联的区域设置(如果有),否则返回系统默认区域设置 10 | * @author nanke 11 | */ 12 | public class LocalizationUtils { 13 | 14 | private LocalizationUtils() { 15 | } 16 | 17 | public static Locale getCurrentLocale() { 18 | return LocaleContextHolder.getLocale(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /nicefish-cms/src/main/java/com/nicefish/cms/jpa/repository/IFileUploadRepository.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.cms.jpa.repository; 2 | 3 | import com.nicefish.cms.jpa.entity.FileUploadEntity; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.data.repository.PagingAndSortingRepository; 6 | import org.springframework.stereotype.Repository; 7 | 8 | @Repository 9 | public interface IFileUploadRepository extends PagingAndSortingRepository, JpaRepository { 10 | FileUploadEntity findDistinctById(Integer id); 11 | } 12 | -------------------------------------------------------------------------------- /nicefish-cms/src/main/java/com/nicefish/cms/service/IFileUploadService.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.cms.service; 2 | 3 | import com.nicefish.cms.jpa.entity.FileUploadEntity; 4 | import com.nicefish.core.utils.AjaxResult; 5 | import jakarta.servlet.http.HttpServletResponse; 6 | import org.springframework.web.multipart.MultipartFile; 7 | 8 | import java.util.List; 9 | 10 | 11 | public interface IFileUploadService { 12 | List upload(MultipartFile[] files); 13 | 14 | FileUploadEntity getFileById(Integer id); 15 | 16 | AjaxResult download(Integer id, HttpServletResponse response); 17 | } 18 | -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/config/JpaConfig.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.config; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.data.jpa.repository.config.EnableJpaRepositories; 5 | import org.springframework.transaction.annotation.EnableTransactionManagement; 6 | 7 | /** 8 | * @see JPA DOC 9 | * @author 大漠穷秋 10 | */ 11 | 12 | @Configuration 13 | @EnableJpaRepositories 14 | @EnableTransactionManagement 15 | public class JpaConfig { 16 | 17 | } 18 | -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/resources/i18n/messages_en.properties: -------------------------------------------------------------------------------- 1 | #common tips 2 | common.del.success=successfully deleted 3 | 4 | #user msg 5 | user.del.failure=deletion failed, built-in user or is in use. 6 | user.del.arg.failure=deletion failed, built-in user or {0} is in use. 7 | user.update.not.exists=user not exists 8 | 9 | #role msg 10 | role.del.failure=deletion failed, the system built-in or the role is in use. 11 | 12 | #auth 13 | auth.register.user.mail.failure=username or email already exists 14 | auth.register.mail.failure=same email already exists 15 | auth.register.phone.failure=phone number already exists -------------------------------------------------------------------------------- /nicefish-cms/src/main/java/com/nicefish/cms/jpa/repository/ISysParamRepository.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.cms.jpa.repository; 2 | 3 | import com.nicefish.cms.jpa.entity.SysParamEntity; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.data.repository.PagingAndSortingRepository; 6 | import org.springframework.stereotype.Repository; 7 | 8 | /** 9 | * @author 大漠穷秋 10 | * @version 创建时间:2018-12-30 20:31 11 | */ 12 | @Repository 13 | public interface ISysParamRepository extends PagingAndSortingRepository, JpaRepository { 14 | 15 | } 16 | -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/service/INiceFishSessionService.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.service; 2 | 3 | import com.nicefish.rbac.jpa.entity.NiceFishSessionEntity; 4 | import org.springframework.data.domain.Page; 5 | import org.springframework.data.domain.Pageable; 6 | 7 | public interface INiceFishSessionService { 8 | NiceFishSessionEntity findDistinctBySessionId(String sessionId); 9 | 10 | Page findNiceFishSessionEntitiesByUserId(Integer userId, Pageable pageable); 11 | 12 | int deleteDistinctBySessionId(String sessionId); 13 | 14 | NiceFishSessionEntity saveSession(NiceFishSessionEntity session); 15 | } 16 | -------------------------------------------------------------------------------- /nicefish-core/src/main/java/com/nicefish/core/i18n/I18nService.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.core.i18n; 2 | 3 | import org.springframework.context.MessageSource; 4 | 5 | public class I18nService { 6 | 7 | private final MessageSource messageSource; 8 | 9 | public I18nService(MessageSource messageSource) { 10 | this.messageSource = messageSource; 11 | } 12 | 13 | public String getMessage(String code, Object[] args) { 14 | return messageSource.getMessage(code, args, LocalizationUtils.getCurrentLocale()); 15 | } 16 | 17 | public String getMessage(String code) { 18 | return messageSource.getMessage(code, null, LocalizationUtils.getCurrentLocale()); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /nicefish-cms/src/main/java/com/nicefish/cms/service/ICommentService.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.cms.service; 2 | 3 | import com.nicefish.cms.jpa.entity.CommentEntity; 4 | import org.springframework.data.domain.Page; 5 | import org.springframework.data.domain.Pageable; 6 | 7 | public interface ICommentService { 8 | Page findByPostId(Integer postId, Pageable pageable); 9 | CommentEntity saveComment(CommentEntity commentEntity); 10 | Page findAllByUserIdAndPaging(Integer userId,Pageable pageable); 11 | Integer countByUserId(Integer userId); 12 | void deleteById(Integer commentId); 13 | Integer deletetByPostId(Integer postId); 14 | Integer deleteByUserId(Integer userId); 15 | } -------------------------------------------------------------------------------- /nicefish-cms/src/main/java/com/nicefish/cms/service/IUserFollowService.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.cms.service; 2 | 3 | import com.nicefish.cms.jpa.entity.UserFollowEntity; 4 | import com.nicefish.rbac.jpa.entity.UserEntity; 5 | 6 | import java.util.List; 7 | 8 | public interface IUserFollowService { 9 | 10 | List findFollowersByUserId(Integer userId); 11 | 12 | Long countFollowersByUserId(Integer userId); 13 | 14 | Long countFollowingByUserId(Integer userId); 15 | 16 | UserFollowEntity createFollowRelation(UserFollowEntity userFollowEntity); 17 | 18 | void deleteFollowRelation(UserFollowEntity userFollowEntity); 19 | 20 | boolean existsFollow(UserFollowEntity userFollowEntity); 21 | } -------------------------------------------------------------------------------- /nicefish-cms/src/main/resources/banner.txt: -------------------------------------------------------------------------------- 1 | >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 2 | 3 | ## ## #### ###### ######## ######## #### ###### ## ## 4 | ### ## ## ## ## ## ## ## ## ## ## ## 5 | #### ## ## ## ## ## ## ## ## ## 6 | ## ## ## ## ## ###### ###### ## ###### ######### 7 | ## #### ## ## ## ## ## ## ## ## 8 | ## ### ## ## ## ## ## ## ## ## ## ## 9 | ## ## #### ###### ######## ## #### ###### ## ## 10 | 11 | Application Name: ${nicefish.name} 12 | Application Version: ${nicefish.version} 13 | Spring Boot Version: ${spring-boot.version} 14 | 15 | >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/service/IRoleService.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.service; 2 | 3 | import com.nicefish.rbac.jpa.entity.RoleEntity; 4 | import org.springframework.data.domain.Page; 5 | import org.springframework.data.domain.Pageable; 6 | 7 | /** 8 | * @author 大漠穷秋 9 | */ 10 | public interface IRoleService { 11 | RoleEntity createRole(RoleEntity roleEntity); 12 | 13 | int deleteRole(Integer roleId); 14 | 15 | RoleEntity updateRole(RoleEntity newRoleEntity); 16 | 17 | Page getRoleListPaging(RoleEntity roleEntity, Pageable pageable); 18 | 19 | RoleEntity getRoleById(Integer roleId); 20 | 21 | int deleteAuthUsers(Integer roleId, Integer[] userIds); 22 | 23 | int addAuthUsers(Integer roleId, Integer[] userIds); 24 | } 25 | -------------------------------------------------------------------------------- /nicefish-cms/src/main/java/com/nicefish/cms/jpa/repository/IPostFileUploadRepository.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.cms.jpa.repository; 2 | 3 | import com.nicefish.cms.jpa.entity.PostFileUploadEntity; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor; 6 | import org.springframework.data.repository.PagingAndSortingRepository; 7 | import org.springframework.stereotype.Repository; 8 | import org.springframework.transaction.annotation.Transactional; 9 | 10 | @Repository 11 | public interface IPostFileUploadRepository extends PagingAndSortingRepository, JpaSpecificationExecutor, JpaRepository { 12 | @Transactional 13 | int deleteAllByPostId(Integer postId); 14 | } 15 | -------------------------------------------------------------------------------- /nicefish-elastic-search/src/main/java/com/nicefish/search/repository/PostSearchRepository.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.search.repository; 2 | 3 | import com.nicefish.search.entity.PostSearchEntity; 4 | import org.springframework.data.domain.Page; 5 | import org.springframework.data.domain.Pageable; 6 | import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; 7 | import org.springframework.stereotype.Repository; 8 | 9 | @Repository 10 | public interface PostSearchRepository extends ElasticsearchRepository { 11 | //TODO:重构这里的代码 12 | Page findByTitleLikeIgnoreCaseOrContentLikeIgnoreCaseOrSummaryLikeIgnoreCase( 13 | String title, 14 | String content, 15 | String summary, 16 | Pageable pageable 17 | ); 18 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ###################################################################### 2 | # Build Tools 3 | 4 | .gradle 5 | /build/ 6 | !gradle/wrapper/gradle-wrapper.jar 7 | 8 | target/ 9 | !.mvn/wrapper/maven-wrapper.jar 10 | 11 | ###################################################################### 12 | # IDE 13 | 14 | ### STS ### 15 | .apt_generated 16 | .classpath 17 | .factorypath 18 | .project 19 | .settings 20 | .springBeans 21 | 22 | ### IntelliJ IDEA ### 23 | .idea 24 | *.iws 25 | *.iml 26 | *.ipr 27 | 28 | ### NetBeans ### 29 | nbproject/private/ 30 | build/* 31 | nbbuild/ 32 | dist/ 33 | nbdist/ 34 | .nb-gradle/ 35 | 36 | ###################################################################### 37 | # Others 38 | *.log 39 | *.xml.versionsBackup 40 | 41 | !*/build/*.java 42 | !*/build/*.html 43 | !*/build/*.xml 44 | 45 | *.pdb -------------------------------------------------------------------------------- /nicefish-cms/src/main/java/com/nicefish/cms/service/IPostService.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.cms.service; 2 | 3 | import com.nicefish.cms.jpa.entity.PostEntity; 4 | import org.springframework.data.domain.Page; 5 | import org.springframework.data.domain.Pageable; 6 | 7 | public interface IPostService { 8 | /** 9 | * 查找内容列表,不区分用户 10 | * @param pageable 11 | * @return 12 | */ 13 | Page getPostsPaging(Pageable pageable); 14 | 15 | PostEntity getOne(Integer id); 16 | 17 | PostEntity savePost(PostEntity postEntity); 18 | 19 | Integer delPost(Integer id); 20 | 21 | /** 22 | * 根据 userId 查找此用户发表的内容列表,带分页 23 | * @param userId 24 | * @param pageable 25 | * @return 26 | */ 27 | Page getPostsByUserIdAndPaging(Integer userId,Pageable pageable); 28 | } 29 | -------------------------------------------------------------------------------- /nicefish-elastic-search/src/main/java/com/nicefish/search/NiceFishSearchApplication.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.search; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; 6 | import org.springframework.context.annotation.ComponentScan; 7 | 8 | @ComponentScan("com.nicefish.search.*") 9 | @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) 10 | public class NiceFishSearchApplication { 11 | public static void main(String[] args) { 12 | System.setProperty("spring.devtools.restart.enabled", "true"); 13 | SpringApplication.run(NiceFishSearchApplication.class, args); 14 | System.out.println(">>>>>>>>>>> NiceFish Search started >>>>>>>>>>>"); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /nicefish-elastic-search/src/main/java/com/nicefish/search/repository/UserSearchRepository.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.search.repository; 2 | 3 | import com.nicefish.search.entity.PostSearchEntity; 4 | import com.nicefish.search.entity.UserSearchEntity; 5 | import org.springframework.data.domain.Page; 6 | import org.springframework.data.domain.Pageable; 7 | import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; 8 | import org.springframework.stereotype.Repository; 9 | 10 | @Repository 11 | public interface UserSearchRepository extends ElasticsearchRepository { 12 | //TODO:重构这里的代码 13 | Page findByUserNameLikeIgnoreCaseOrNickNameLikeIgnoreCaseOrEmailLikeIgnoreCase( 14 | String userName, 15 | String nickName, 16 | String email, 17 | Pageable pageable 18 | ); 19 | } -------------------------------------------------------------------------------- /nicefish-cms/src/main/java/com/nicefish/cms/util/ResponsePageImpl.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.cms.util; 2 | 3 | import org.springframework.data.domain.PageImpl; 4 | import org.springframework.data.domain.Pageable; 5 | 6 | import java.io.Serializable; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | /** 11 | * PageImpl没有默认的无参构造,会导致Jackson反序列化失败,继承一个空的子类来支持Jackson的反序列化 12 | * ref:https://jira.spring.io/browse/DATACMNS-1061 13 | * @param 14 | */ 15 | public class ResponsePageImpl extends PageImpl implements Serializable { 16 | 17 | public ResponsePageImpl () { 18 | super (new ArrayList<>()); 19 | } 20 | 21 | public ResponsePageImpl (List content) { 22 | super (content); 23 | } 24 | 25 | public ResponsePageImpl (List content, Pageable pageable, long total) { 26 | super (content, pageable, total); 27 | } 28 | } -------------------------------------------------------------------------------- /nicefish-elastic-search/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8899 3 | servlet: 4 | context-path: / 5 | tomcat: 6 | uri-encoding: UTF-8 7 | max-threads: 800 8 | min-spare-threads: 30 9 | 10 | logging: 11 | level: 12 | com.nicefish: DEBUG 13 | org.springframework: DEBUG 14 | org.hibernate.SQL: DEBUG 15 | org.hibernate.type.descriptor.sql: TRACE 16 | org.hibernate.engine.QueryParameters: DEBUG 17 | org.hibernate.engine.query.HQLQueryPlan: DEBUG 18 | org.hibernate.type.descriptor.sql.BasicBinder: TRACE 19 | org.springframework.data.elasticsearch.client: DEBUG 20 | org.elasticsearch.root: DEBUG 21 | 22 | spring: 23 | elasticsearch: 24 | uris: 192.168.23.130:9200 25 | 26 | xss: 27 | enabled: true 28 | excludes: /system/notice/* 29 | urlPatterns: /system/*,/monitor/*,/tool/* -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/jpa/repository/IRoleComponentRepository.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.jpa.repository; 2 | 3 | import com.nicefish.rbac.jpa.entity.RoleComponentEntity; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor; 6 | import org.springframework.data.repository.PagingAndSortingRepository; 7 | import org.springframework.transaction.annotation.Transactional; 8 | 9 | /** 10 | * @author 大漠穷秋 11 | */ 12 | public interface IRoleComponentRepository extends PagingAndSortingRepository, JpaSpecificationExecutor, JpaRepository { 13 | int deleteByRoleIdAndCompPermId(Integer roleId,Integer compPermId); 14 | int deleteByRoleIdAndCompPermIdIsIn(Integer roleId,Integer[] componentIds); 15 | 16 | @Transactional 17 | int deleteAllByRoleId(Integer roleId); 18 | } 19 | -------------------------------------------------------------------------------- /nicefish-cms/src/main/java/com/nicefish/cms/jpa/repository/IPostRepository.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.cms.jpa.repository; 2 | 3 | import com.nicefish.cms.jpa.entity.PostEntity; 4 | import org.springframework.data.domain.Page; 5 | import org.springframework.data.domain.Pageable; 6 | import org.springframework.data.jpa.repository.JpaRepository; 7 | import org.springframework.data.repository.PagingAndSortingRepository; 8 | import org.springframework.stereotype.Repository; 9 | 10 | /** 11 | * @author 大漠穷秋 12 | * @version 创建时间:2018-12-30 20:31 13 | */ 14 | @Repository 15 | public interface IPostRepository extends PagingAndSortingRepository, JpaRepository { 16 | 17 | Page findAllByUserId(Integer userId, Pageable pageable); 18 | 19 | Integer countByUserId(Integer userId); 20 | 21 | PostEntity findDistinctByPostId(Integer postId); 22 | 23 | Integer deleteByPostId(Integer postId); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /nicefish-cms/src/main/java/com/nicefish/cms/jpa/repository/ICommentRepository.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.cms.jpa.repository; 2 | 3 | import com.nicefish.cms.jpa.entity.CommentEntity; 4 | import org.springframework.data.domain.Page; 5 | import org.springframework.data.domain.Pageable; 6 | import org.springframework.data.jpa.repository.JpaRepository; 7 | import org.springframework.stereotype.Repository; 8 | 9 | /** 10 | * @author 大漠穷秋 11 | * @version 创建时间:2018-12-30 20:31 12 | */ 13 | @Repository 14 | public interface ICommentRepository extends JpaRepository { 15 | 16 | Page findAllByPostId(Integer postId, Pageable pageable); 17 | 18 | Page findAllByUserId(Integer userId,Pageable pageable); 19 | 20 | Integer countByUserId(Integer userId); 21 | 22 | void deleteById(Integer commentId); 23 | 24 | Integer deleteByPostId(Integer postId); 25 | 26 | Integer deleteByUserId(Integer userId); 27 | } -------------------------------------------------------------------------------- /nicefish-core/src/main/java/com/nicefish/core/i18n/I18nUtil.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.core.i18n; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.stereotype.Component; 5 | 6 | import jakarta.annotation.PostConstruct; 7 | 8 | /** 9 | * 在静态工具类Util封装一下 i18nService,省去在要使用I18n对应方法时,每次都要在类中声明 I18nService 类型的 成员变量 10 | */ 11 | @Component 12 | public class I18nUtil { 13 | 14 | @Autowired 15 | private I18nService i18nService; 16 | 17 | private static I18nUtil i18nUtil; 18 | 19 | @PostConstruct 20 | public void init() { 21 | i18nUtil = this; 22 | i18nUtil.i18nService = this.i18nService; 23 | } 24 | 25 | public static String getMessage(String code, Object[] args) { 26 | return i18nUtil.i18nService.getMessage(code, args); 27 | } 28 | public static String getMessage(String code) { 29 | return i18nUtil.i18nService.getMessage(code); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /nicefish-core/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | nicefish-spring-boot 7 | com.nicefish 8 | 1.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | nicefish-core 13 | nicefish-core 14 | 1.1-SNAPSHOT 15 | 16 | NiceFish 核心工具包,提供一些全局通用的工具和逻辑。 17 | 18 | 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter-web 23 | 24 | 25 | -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/jpa/entity/UserRoleEntity.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.jpa.entity; 2 | 3 | import org.hibernate.annotations.DynamicInsert; 4 | import org.hibernate.annotations.DynamicUpdate; 5 | 6 | import jakarta.persistence.*; 7 | import java.io.Serializable; 8 | 9 | @Entity 10 | @DynamicInsert 11 | @DynamicUpdate 12 | @IdClass(UserRoleEntity.class) 13 | @Table(name = "nicefish_rbac_user_role") 14 | public class UserRoleEntity implements Serializable { 15 | @Id 16 | @Column(name="user_id") 17 | private Integer userId; 18 | 19 | @Id 20 | @Column(name="role_id") 21 | private Integer roleId; 22 | 23 | public Integer getUserId() { 24 | return userId; 25 | } 26 | 27 | public void setUserId(Integer userId) { 28 | this.userId = userId; 29 | } 30 | 31 | public Integer getRoleId() { 32 | return roleId; 33 | } 34 | 35 | public void setRoleId(Integer roleId) { 36 | this.roleId = roleId; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/service/IApiPermissionService.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.service; 2 | 3 | import com.nicefish.rbac.jpa.entity.ApiPermissionEntity; 4 | import com.nicefish.rbac.jpa.entity.RoleEntity; 5 | import org.springframework.data.domain.Page; 6 | import org.springframework.data.domain.Pageable; 7 | 8 | /** 9 | * 10 | * @author 大漠穷秋 11 | */ 12 | public interface IApiPermissionService { 13 | Page getPermListPaging(ApiPermissionEntity apiPermissionEntity, Pageable pageable); 14 | Iterable getPermListAll(ApiPermissionEntity apiPermissionEntity); 15 | Iterable getPermListAllByRole(RoleEntity roleEntity); 16 | ApiPermissionEntity createApiPermission(ApiPermissionEntity apiPermissionEntity); 17 | ApiPermissionEntity updatePermission(ApiPermissionEntity apiPermissionEntity); 18 | ApiPermissionEntity getApiPermissionById(Integer apiPermissionEntity); 19 | int deleteByApiId(Integer apiPermissionId); 20 | } 21 | -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/jpa/repository/IComponentPermissionRepository.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.jpa.repository; 2 | 3 | import com.nicefish.rbac.jpa.entity.ComponentPermissionEntity; 4 | import com.nicefish.rbac.jpa.entity.RoleEntity; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor; 7 | import org.springframework.data.repository.PagingAndSortingRepository; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * @author 大漠穷秋 13 | */ 14 | public interface IComponentPermissionRepository extends PagingAndSortingRepository, JpaSpecificationExecutor, JpaRepository { 15 | ComponentPermissionEntity findDistinctByCompPermId(Integer compPermId); 16 | 17 | Iterable findAllByRoleEntitiesIn(List roleEntityList); 18 | 19 | Iterable findDistinctByRoleEntitiesIn(List roleEntityList); 20 | } 21 | -------------------------------------------------------------------------------- /nicefish-cms/src/main/java/com/nicefish/cms/jpa/entity/PostFileUploadEntity.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.cms.jpa.entity; 2 | 3 | import org.hibernate.annotations.DynamicInsert; 4 | import org.hibernate.annotations.DynamicUpdate; 5 | 6 | import jakarta.persistence.*; 7 | import java.io.Serializable; 8 | 9 | /** 10 | * 文章与上传的图片,视频之间的关联表 11 | */ 12 | @Entity 13 | @DynamicInsert 14 | @DynamicUpdate 15 | @IdClass(PostFileUploadEntity.class) 16 | @Table(name = "nicefish_cms_post_file_upload") 17 | public class PostFileUploadEntity implements Serializable { 18 | @Id 19 | @Column(name="post_id") 20 | private Integer postId; 21 | 22 | @Id 23 | @Column(name="up_id") 24 | private Integer upId; 25 | 26 | public Integer getPostId() { 27 | return postId; 28 | } 29 | 30 | public void setPostId(Integer postId) { 31 | this.postId = postId; 32 | } 33 | 34 | public Integer getUpId() { 35 | return upId; 36 | } 37 | 38 | public void setUpId(Integer upId) { 39 | this.upId = upId; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/jpa/entity/RoleComponentEntity.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.jpa.entity; 2 | 3 | import org.hibernate.annotations.DynamicInsert; 4 | import org.hibernate.annotations.DynamicUpdate; 5 | 6 | import jakarta.persistence.*; 7 | import java.io.Serializable; 8 | 9 | @Entity 10 | @DynamicInsert 11 | @DynamicUpdate 12 | @IdClass(RoleComponentEntity.class) 13 | @Table(name = "nicefish_rbac_role_component") 14 | public class RoleComponentEntity implements Serializable { 15 | @Id 16 | @Column(name="role_id") 17 | private Integer roleId; 18 | 19 | @Id 20 | @Column(name="component_id") 21 | private Integer compPermId; 22 | 23 | public Integer getRoleId() { 24 | return roleId; 25 | } 26 | 27 | public void setRoleId(Integer roleId) { 28 | this.roleId = roleId; 29 | } 30 | 31 | public Integer getComponentId() { 32 | return compPermId; 33 | } 34 | 35 | public void setComponentId(Integer compPermId) { 36 | this.compPermId = compPermId; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/jpa/repository/IApiPermissionRepository.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.jpa.repository; 2 | 3 | import com.nicefish.rbac.jpa.entity.ApiPermissionEntity; 4 | import com.nicefish.rbac.jpa.entity.RoleEntity; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor; 7 | import org.springframework.data.repository.PagingAndSortingRepository; 8 | import org.springframework.transaction.annotation.Transactional; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * @author 大漠穷秋 14 | */ 15 | public interface IApiPermissionRepository extends PagingAndSortingRepository, JpaSpecificationExecutor, JpaRepository { 16 | ApiPermissionEntity findDistinctByApiPermissionId(Integer apiPermissionId); 17 | 18 | Iterable findAllByRoleEntitiesIn(List roleEntityList); 19 | 20 | @Transactional 21 | int deleteByApiPermissionId(Integer apiPermissionId); 22 | } 23 | -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/jpa/entity/RoleApiEntity.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.jpa.entity; 2 | 3 | import org.hibernate.annotations.DynamicInsert; 4 | import org.hibernate.annotations.DynamicUpdate; 5 | 6 | import jakarta.persistence.*; 7 | import java.io.Serializable; 8 | 9 | @Entity 10 | @DynamicInsert 11 | @DynamicUpdate 12 | @IdClass(RoleApiEntity.class) 13 | @Table(name = "nicefish_rbac_role_api") 14 | public class RoleApiEntity implements Serializable { 15 | @Id 16 | @Column(name="role_id") 17 | private Integer roleId; 18 | 19 | @Id 20 | @Column(name="api_id") 21 | private Integer apiPermissionId; 22 | 23 | public Integer getRoleId() { 24 | return roleId; 25 | } 26 | 27 | public void setRoleId(Integer roleId) { 28 | this.roleId = roleId; 29 | } 30 | 31 | public Integer getApiPermissionId() { 32 | return apiPermissionId; 33 | } 34 | 35 | public void setApiPermissionId(Integer apiPermissionId) { 36 | this.apiPermissionId = apiPermissionId; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/jpa/repository/INiceFishSessionRepository.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.jpa.repository; 2 | 3 | import com.nicefish.rbac.jpa.entity.NiceFishSessionEntity; 4 | import org.springframework.data.domain.Page; 5 | import org.springframework.data.domain.Pageable; 6 | import org.springframework.data.jpa.repository.JpaRepository; 7 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor; 8 | import org.springframework.data.repository.PagingAndSortingRepository; 9 | import org.springframework.transaction.annotation.Transactional; 10 | 11 | /** 12 | * @author 大漠穷秋 13 | */ 14 | public interface INiceFishSessionRepository extends PagingAndSortingRepository, JpaSpecificationExecutor, JpaRepository { 15 | NiceFishSessionEntity findDistinctBySessionId(String sessionId); 16 | 17 | Page findNiceFishSessionEntitiesByUserId(Integer userId, Pageable pageable); 18 | 19 | @Transactional 20 | int deleteDistinctBySessionId(String sessionId); 21 | } 22 | -------------------------------------------------------------------------------- /nicefish-cms/src/main/java/com/nicefish/NiceFishCMSApplication.java: -------------------------------------------------------------------------------- 1 | package com.nicefish; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; 6 | import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; 7 | import org.springframework.context.annotation.ComponentScan; 8 | import org.springframework.data.jpa.repository.config.EnableJpaRepositories; 9 | 10 | /** 11 | * @author 大漠穷秋 12 | */ 13 | @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) 14 | @ComponentScan("com.nicefish.*") 15 | @EnableJpaRepositories("com.nicefish.*") 16 | public class NiceFishCMSApplication extends SpringBootServletInitializer { 17 | public static void main(String[] args) { 18 | System.setProperty("spring.devtools.restart.enabled", "true"); 19 | SpringApplication.run(NiceFishCMSApplication.class, args); 20 | System.out.println("====== NiceFish CMS started ======"); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 NiceFish 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/jpa/repository/IUserRoleRepository.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.jpa.repository; 2 | 3 | import com.nicefish.rbac.jpa.entity.UserRoleEntity; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor; 6 | import org.springframework.data.repository.PagingAndSortingRepository; 7 | import org.springframework.transaction.annotation.Transactional; 8 | 9 | /** 10 | * @author 大漠穷秋 11 | */ 12 | public interface IUserRoleRepository extends PagingAndSortingRepository, JpaSpecificationExecutor, JpaRepository { 13 | @Transactional 14 | void deleteByRoleIdAndUserIdIsIn(Integer roleId,Integer[] userIds); 15 | 16 | /** 17 | * 根据 roleId 删除 user-role 之间的关联关系 18 | * @param roleId 19 | * @return 20 | */ 21 | @Transactional 22 | void deleteAllByRoleId(Integer roleId); 23 | 24 | /** 25 | * 根据 userId 删除 user-role 之间的关联关系 26 | * @param userId 27 | * @return 28 | */ 29 | @Transactional 30 | int deleteByUserId(Integer userId); 31 | } 32 | -------------------------------------------------------------------------------- /nicefish-cms/src/main/java/com/nicefish/cms/jpa/entity/SysParamEntity.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.cms.jpa.entity; 2 | 3 | import jakarta.persistence.*; 4 | import java.io.Serializable; 5 | 6 | /** 7 | * @author 大漠穷秋 8 | * @version 创建时间:2018-12-31 17:00 9 | */ 10 | @Entity 11 | @Table(name="nicefish_cms_sys_params") 12 | public class SysParamEntity implements Serializable { 13 | @Id 14 | @Column(name = "param_key") 15 | private String paramKey; 16 | @Column(name = "param_value") 17 | private String paramValue; 18 | @Column(name = "param_desc") 19 | private String paramDesc; 20 | 21 | public String getParamKey() { 22 | return paramKey; 23 | } 24 | 25 | public void setParamKey(String paramKey) { 26 | this.paramKey = paramKey; 27 | } 28 | 29 | public String getParamValue() { 30 | return paramValue; 31 | } 32 | 33 | public void setParamValue(String paramValue) { 34 | this.paramValue = paramValue; 35 | } 36 | 37 | public String getParamDesc() { 38 | return paramDesc; 39 | } 40 | 41 | public void setParamDesc(String paramDesc) { 42 | this.paramDesc = paramDesc; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /nicefish-cms/src/main/java/com/nicefish/cms/util/HashUtils.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.cms.util; 2 | 3 | 4 | import java.security.MessageDigest; 5 | import java.security.NoSuchAlgorithmException; 6 | import java.security.SecureRandom; 7 | 8 | public class HashUtils { 9 | 10 | /** 11 | * 生成随机盐值并对其进行 SHA-256 哈希 12 | * 13 | * @return 哈希后的字符串 14 | */ 15 | public static String generateSaltedSha256() { 16 | try { 17 | SecureRandom random = new SecureRandom(); 18 | byte[] salt = new byte[16]; 19 | random.nextBytes(salt); 20 | MessageDigest digest = MessageDigest.getInstance("SHA-256"); 21 | digest.update(salt); 22 | byte[] hash = digest.digest(); 23 | StringBuilder hexString = new StringBuilder(); 24 | for (byte b : hash) { 25 | String hex = Integer.toHexString(0xff & b); 26 | if (hex.length() == 1) hexString.append('0'); 27 | hexString.append(hex); 28 | } 29 | return hexString.toString(); 30 | } catch (NoSuchAlgorithmException e) { 31 | throw new RuntimeException(e); 32 | } 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/service/IComponentPermissionService.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.service; 2 | 3 | import com.nicefish.rbac.jpa.entity.ComponentPermissionEntity; 4 | import com.nicefish.rbac.jpa.entity.RoleEntity; 5 | import org.springframework.data.domain.Page; 6 | import org.springframework.data.domain.Pageable; 7 | 8 | 9 | /** 10 | * 11 | * @author 大漠穷秋 12 | */ 13 | public interface IComponentPermissionService { 14 | /** 15 | * 此方法从根节点开始,包含所有层级上的子节点,带分页 16 | */ 17 | Page getComponentPermissionTree(ComponentPermissionEntity componentPermissionEntity, Pageable pageable); 18 | 19 | Iterable getPermListAllByRole(RoleEntity roleEntity); 20 | 21 | ComponentPermissionEntity getComponentPermissionDetail(Integer compPermId); 22 | 23 | ComponentPermissionEntity createComponentPermission(ComponentPermissionEntity componentPermissionEntity); 24 | 25 | ComponentPermissionEntity updateComponentPermission(ComponentPermissionEntity componentPermissionEntity); 26 | 27 | int deleteComponentPermission(Integer compPermId); 28 | 29 | Iterable getComponentPermissionsByUserId(Integer userId); 30 | } 31 | -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/jpa/repository/IRoleRepository.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.jpa.repository; 2 | 3 | import com.nicefish.rbac.jpa.entity.RoleEntity; 4 | import com.nicefish.rbac.jpa.entity.UserEntity; 5 | import org.springframework.data.domain.Page; 6 | import org.springframework.data.domain.Pageable; 7 | import org.springframework.data.jpa.repository.JpaRepository; 8 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor; 9 | import org.springframework.data.repository.PagingAndSortingRepository; 10 | import org.springframework.transaction.annotation.Transactional; 11 | 12 | /** 13 | * @author 大漠穷秋 14 | */ 15 | public interface IRoleRepository extends PagingAndSortingRepository, JpaSpecificationExecutor, JpaRepository { 16 | Iterable findAllByRoleId(Integer roleId); 17 | 18 | Page findUserEntitiesByRoleId(Integer roleId, Pageable pageable); 19 | 20 | RoleEntity findDistinctByRoleName(String roleName); 21 | 22 | RoleEntity findDistinctByRoleId(Integer roleId); 23 | 24 | @Transactional 25 | void deleteAllByRoleIdIn(Integer[] roleIds); 26 | 27 | @Transactional 28 | int deleteByRoleId(Integer roleId); 29 | } 30 | -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/jpautils/RoleListDeserializer.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.jpautils; 2 | 3 | import com.fasterxml.jackson.core.JsonParser; 4 | import com.fasterxml.jackson.core.JsonProcessingException; 5 | import com.fasterxml.jackson.databind.DeserializationContext; 6 | import com.fasterxml.jackson.databind.deser.std.StdDeserializer; 7 | import com.nicefish.rbac.jpa.entity.RoleEntity; 8 | 9 | import java.io.IOException; 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | /** 14 | * TODO:看起来不需要这个反序列化器? 15 | * @author: 大漠穷秋 16 | */ 17 | public class RoleListDeserializer extends StdDeserializer> { 18 | public RoleListDeserializer() { 19 | this(null); 20 | } 21 | 22 | protected RoleListDeserializer(Class> vc) { 23 | super(vc); 24 | } 25 | 26 | @Override 27 | public List deserialize(JsonParser parser, DeserializationContext context) throws IOException, JsonProcessingException { 28 | System.out.println("=========================="); 29 | System.out.println("RoleListDeserializer.................."); 30 | System.out.println("=========================="); 31 | return new ArrayList<>(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/jpa/repository/IRoleApiRepository.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.jpa.repository; 2 | 3 | import com.nicefish.rbac.jpa.entity.NiceFishSessionEntity; 4 | import com.nicefish.rbac.jpa.entity.RoleApiEntity; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor; 7 | import org.springframework.data.repository.PagingAndSortingRepository; 8 | import org.springframework.transaction.annotation.Transactional; 9 | 10 | /** 11 | * @author 大漠穷秋 12 | */ 13 | public interface IRoleApiRepository extends PagingAndSortingRepository, JpaSpecificationExecutor, JpaRepository { 14 | @Transactional 15 | int deleteByRoleIdAndApiPermissionId(Integer roleId,Integer apiPermissionId); 16 | 17 | @Transactional 18 | int deleteByRoleIdAndApiPermissionIdIsIn(Integer roleId,Integer[] apiIds); 19 | 20 | @Transactional 21 | int deleteAllByRoleId(Integer roleId); 22 | 23 | int deleteByApiPermissionId(Integer apiPermissionId); 24 | 25 | Iterable findAllByRoleId(Integer roleId);//TODO:分页? 26 | 27 | Iterable findAllByApiPermissionId(Integer apiPermissionId);//TODO:分页? 28 | } 29 | -------------------------------------------------------------------------------- /nicefish-elastic-search/src/main/java/com/nicefish/search/service/impl/PostSearchServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.search.service.impl; 2 | 3 | import org.springframework.data.domain.Page; 4 | import com.nicefish.search.entity.PostSearchEntity; 5 | import com.nicefish.search.repository.PostSearchRepository; 6 | import com.nicefish.search.service.IPostSearchService; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.data.domain.PageRequest; 9 | import org.springframework.data.domain.Pageable; 10 | import org.springframework.stereotype.Service; 11 | 12 | @Service 13 | public class PostSearchServiceImpl implements IPostSearchService { 14 | 15 | @Autowired 16 | private PostSearchRepository postSearchRepository; 17 | 18 | @Override 19 | public Iterable getAll() { 20 | return postSearchRepository.findAll(); 21 | } 22 | 23 | @Override 24 | public Page searchSimilar(PostSearchEntity entity, int page, int size) { 25 | Pageable pageable = PageRequest.of(page, size); 26 | return postSearchRepository.findByTitleLikeIgnoreCaseOrContentLikeIgnoreCaseOrSummaryLikeIgnoreCase( 27 | entity.getTitle(), 28 | entity.getContent(), 29 | entity.getSummary(), 30 | pageable 31 | ); 32 | } 33 | } -------------------------------------------------------------------------------- /nicefish-cms/src/main/java/com/nicefish/cms/config/DruidConfig.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.cms.config; 2 | 3 | import com.alibaba.druid.pool.DruidDataSource; 4 | import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder; 5 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 6 | import org.springframework.boot.context.properties.ConfigurationProperties; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | 10 | import javax.sql.DataSource; 11 | 12 | /** 13 | * 14 | * @author 大漠穷秋 15 | */ 16 | @Configuration 17 | public class DruidConfig { 18 | @Bean 19 | @ConfigurationProperties("spring.datasource.druid.master") 20 | public DataSource masterDataSource(DruidProperties druidProperties) { 21 | DruidDataSource dataSource = DruidDataSourceBuilder.create().build(); 22 | return druidProperties.dataSource(dataSource); 23 | } 24 | 25 | @Bean 26 | @ConfigurationProperties("spring.datasource.druid.slave") 27 | @ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true") 28 | public DataSource slaveDataSource(DruidProperties druidProperties) { 29 | DruidDataSource dataSource = DruidDataSourceBuilder.create().build(); 30 | return druidProperties.dataSource(dataSource); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /nicefish-cms/src/main/java/com/nicefish/cms/jpa/entity/UserFollowEntity.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.cms.jpa.entity; 2 | 3 | import jakarta.persistence.*; 4 | import java.io.Serializable; 5 | import java.util.Date; 6 | 7 | @Entity 8 | @Table(name = "nicefish_cms_user_follow") 9 | public class UserFollowEntity implements Serializable { 10 | 11 | @Id 12 | @GeneratedValue(strategy = GenerationType.IDENTITY) 13 | @Column(name = "id") 14 | private Integer id; 15 | 16 | @Column(name = "from_id") 17 | private Integer fromId; 18 | 19 | @Column(name = "to_id") 20 | private Integer toId; 21 | 22 | @Column(name = "follow_time") 23 | private Date followTime=new Date(); 24 | 25 | public Integer getId() { 26 | return id; 27 | } 28 | 29 | public void setId(Integer id) { 30 | this.id = id; 31 | } 32 | 33 | public Integer getFromId() { 34 | return fromId; 35 | } 36 | 37 | public void setFromId(Integer fromId) { 38 | this.fromId = fromId; 39 | } 40 | 41 | public Integer getToId() { 42 | return toId; 43 | } 44 | 45 | public void setToId(Integer toId) { 46 | this.toId = toId; 47 | } 48 | 49 | public Date getFollowTime() { 50 | return followTime; 51 | } 52 | 53 | public void setFollowTime(Date followTime) { 54 | this.followTime = followTime; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /nicefish-elastic-search/src/main/java/com/nicefish/search/service/impl/UserSearchServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.search.service.impl; 2 | 3 | import com.nicefish.search.entity.PostSearchEntity; 4 | import com.nicefish.search.entity.UserSearchEntity; 5 | import com.nicefish.search.repository.UserSearchRepository; 6 | import com.nicefish.search.service.IUserSearchService; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.data.domain.Page; 9 | import org.springframework.data.domain.PageRequest; 10 | import org.springframework.data.domain.Pageable; 11 | import org.springframework.stereotype.Service; 12 | 13 | @Service 14 | public class UserSearchServiceImpl implements IUserSearchService { 15 | 16 | @Autowired 17 | private UserSearchRepository userSearchRepository; 18 | 19 | @Override 20 | public Iterable getAll() { 21 | return userSearchRepository.findAll(); 22 | } 23 | 24 | public Page searchSimilar(UserSearchEntity entity, int page, int size) { 25 | Pageable pageable = PageRequest.of(page, size); 26 | return userSearchRepository.findByUserNameLikeIgnoreCaseOrNickNameLikeIgnoreCaseOrEmailLikeIgnoreCase( 27 | entity.getUserName(), 28 | entity.getNickName(), 29 | entity.getEmail(), 30 | pageable 31 | ); 32 | } 33 | } -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/config/I18nConfig.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.config; 2 | 3 | import com.nicefish.core.i18n.I18nService; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.context.support.ResourceBundleMessageSource; 7 | 8 | import java.nio.charset.StandardCharsets; 9 | import java.util.Locale; 10 | 11 | /** 12 | * Spring 默认实现了 I18n,这里在配置类里简单配置一下。当然您可以在 application 配置文件里进行配置。 13 | * 切换国际化需要在请求头添加 Accept-Language,举例 Accept-Language=zh 14 | */ 15 | @Configuration 16 | public class I18nConfig { 17 | 18 | /** 19 | * RESOURCE_BUNDLE 资源包名称 20 | * 包下资源文件,您可以自行添加,注意格式 21 | * 举例: 22 | * messages_en.properties 23 | * messages.properties 24 | */ 25 | private static final String RESOURCE_BUNDLE = "i18n/messages"; 26 | 27 | @Bean 28 | public I18nService i18nService() { 29 | return new I18nService(messageSource()); 30 | } 31 | 32 | @Bean 33 | public ResourceBundleMessageSource messageSource() { 34 | Locale.setDefault(Locale.SIMPLIFIED_CHINESE); 35 | ResourceBundleMessageSource source = new ResourceBundleMessageSource(); 36 | source.setBasenames(RESOURCE_BUNDLE); 37 | source.setUseCodeAsDefaultMessage(true); 38 | source.setDefaultEncoding(StandardCharsets.UTF_8.name()); 39 | return source; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /nicefish-core/src/main/java/com/nicefish/core/exception/NiceFishBaseException.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.core.exception; 2 | 3 | /** 4 | * NiceFish 的基础异常类,所有业务异常都应该继承此类。 5 | * NiceFish 的日志分析工具可以针对此异常类的格式进行日志分析和审计。 6 | * @author 大漠穷秋 7 | */ 8 | public class NiceFishBaseException extends RuntimeException { 9 | //异常所属的业务模块 10 | private String module; 11 | 12 | //异常代码 13 | private String code; 14 | 15 | //异常消息 16 | private String message; 17 | 18 | public NiceFishBaseException() { 19 | super(); 20 | } 21 | 22 | public NiceFishBaseException(Throwable cause) { 23 | super(cause); 24 | } 25 | 26 | public NiceFishBaseException(String message, Throwable cause) { 27 | super(message, cause); 28 | } 29 | 30 | public NiceFishBaseException(String module, String code, String message) { 31 | this.module = module; 32 | this.code = code; 33 | this.message = message; 34 | } 35 | 36 | public NiceFishBaseException(String message) { 37 | this(null, null, message); 38 | } 39 | 40 | public NiceFishBaseException(String module, String code) { 41 | this(module, code, null); 42 | } 43 | 44 | public String getModule() { 45 | return module; 46 | } 47 | 48 | public String getCode() { 49 | return code; 50 | } 51 | 52 | @Override 53 | public String getMessage() { 54 | return message; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /nicefish-elastic-search/src/main/java/com/nicefish/search/controller/UserSearchController.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.search.controller; 2 | 3 | import com.nicefish.search.entity.PostSearchEntity; 4 | import com.nicefish.search.entity.UserSearchEntity; 5 | import com.nicefish.search.service.IUserSearchService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.data.domain.Page; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.PathVariable; 10 | import org.springframework.web.bind.annotation.RequestMapping; 11 | import org.springframework.web.bind.annotation.RestController; 12 | 13 | @RestController 14 | @RequestMapping("/nicefish/search/user") 15 | public class UserSearchController { 16 | 17 | @Autowired 18 | private IUserSearchService userSearchService; 19 | 20 | @RequestMapping("/get-all") 21 | public Iterable getAll() { 22 | return userSearchService.getAll(); 23 | } 24 | 25 | @GetMapping("/q/{page}/{size}/{keyword}") 26 | public Page searchSimilar(@PathVariable String keyword, @PathVariable int page, @PathVariable int size) { 27 | UserSearchEntity entity = new UserSearchEntity(); 28 | entity.setUserName(keyword); 29 | entity.setNickName(keyword); 30 | entity.setEmail(keyword); 31 | return userSearchService.searchSimilar(entity,page-1,size); 32 | } 33 | } -------------------------------------------------------------------------------- /nicefish-elastic-search/src/main/java/com/nicefish/search/controller/PostSearchController.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.search.controller; 2 | 3 | import com.fasterxml.jackson.databind.util.JSONPObject; 4 | import com.nicefish.search.entity.PostSearchEntity; 5 | import com.nicefish.search.service.IPostSearchService; 6 | import jakarta.json.Json; 7 | import org.apache.tomcat.util.json.JSONParser; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.boot.jackson.JsonObjectSerializer; 12 | import org.springframework.data.domain.Page; 13 | import org.springframework.web.bind.annotation.*; 14 | 15 | @RestController 16 | @RequestMapping("/nicefish/search/post") 17 | public class PostSearchController { 18 | private static final Logger logger = LoggerFactory.getLogger(PostSearchController.class); 19 | 20 | @Autowired 21 | private IPostSearchService postSearchService; 22 | 23 | @RequestMapping("/get-all") 24 | public Iterable getAll() { 25 | return postSearchService.getAll(); 26 | } 27 | 28 | @GetMapping("/q/{page}/{size}/{keyword}") 29 | public Page searchSimilar(@PathVariable String keyword, @PathVariable int page, @PathVariable int size) { 30 | PostSearchEntity entity = new PostSearchEntity(); 31 | entity.setTitle(keyword); 32 | entity.setContent(keyword); 33 | entity.setSummary(keyword); 34 | return postSearchService.searchSimilar(entity,page-1,size); 35 | } 36 | } -------------------------------------------------------------------------------- /nicefish-cms/src/main/java/com/nicefish/cms/jpa/repository/IUserFollowRepository.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.cms.jpa.repository; 2 | 3 | import com.nicefish.cms.jpa.entity.UserFollowEntity; 4 | import com.nicefish.rbac.jpa.entity.UserEntity; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | import org.springframework.data.jpa.repository.Query; 7 | import org.springframework.data.repository.query.Param; 8 | import org.springframework.stereotype.Repository; 9 | 10 | import java.util.List; 11 | 12 | @Repository 13 | public interface IUserFollowRepository extends JpaRepository { 14 | @Query("SELECT u FROM UserFollowEntity uf JOIN UserEntity u ON uf.fromId = u.userId WHERE uf.toId = :userId") 15 | List findFollowersByUserId(@Param("userId") Integer userId); 16 | 17 | @Query("SELECT COUNT(uf) FROM UserFollowEntity uf WHERE uf.toId = :userId") 18 | Long countFollowersByUserId(@Param("userId") Integer userId); 19 | 20 | @Query("SELECT COUNT(uf) FROM UserFollowEntity uf WHERE uf.fromId = :userId") 21 | Long countFollowingByUserId(@Param("userId") Integer userId); 22 | 23 | /** 24 | * 根据 fromId 和 toId 查找 25 | * @param fromId 26 | * @param toId 27 | * @return 28 | */ 29 | UserFollowEntity findByFromIdAndToId(@Param("fromId")Integer fromId,@Param("toId")Integer toId); 30 | 31 | /** 32 | * 是否存在关注关系 33 | * @param fromId 34 | * @param toId 35 | * @return 36 | */ 37 | boolean existsByFromIdAndToId(@Param("fromId")Integer fromId,@Param("toId")Integer toId); 38 | } -------------------------------------------------------------------------------- /nicefish-cms/src/main/java/com/nicefish/cms/controller/SysParamController.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.cms.controller; 2 | 3 | import com.nicefish.cms.jpa.entity.SysParamEntity; 4 | import com.nicefish.cms.service.ISysParamService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.data.domain.Page; 7 | import org.springframework.data.domain.PageRequest; 8 | import org.springframework.data.domain.Pageable; 9 | import org.springframework.data.domain.Sort; 10 | import org.springframework.web.bind.annotation.PathVariable; 11 | import org.springframework.web.bind.annotation.RequestMapping; 12 | import org.springframework.web.bind.annotation.RequestMethod; 13 | import org.springframework.web.bind.annotation.RestController; 14 | 15 | import java.util.Map; 16 | 17 | /** 18 | * @author 大漠穷秋 19 | */ 20 | @RestController 21 | @RequestMapping("/nicefish/cms/param") 22 | public class SysParamController { 23 | @Autowired 24 | private ISysParamService sysParamService; 25 | 26 | //TODO:每页显示的条数改为系统配置项 27 | @RequestMapping(value = "/list/{page}", method = RequestMethod.GET) 28 | public Page getParamList(@PathVariable(value="page",required = false) Integer page) { 29 | Pageable pageable= PageRequest.of(page-1,10, Sort.by(Sort.Direction.DESC,"paramKey")); 30 | return this.sysParamService.getParamPaging(pageable); 31 | } 32 | 33 | @RequestMapping(value = "/all", method = RequestMethod.GET) 34 | public Map getParamAll() { 35 | return this.sysParamService.getAllParamJSON(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /nicefish-cms/src/main/java/com/nicefish/cms/controller/FileUploadController.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.cms.controller; 2 | 3 | import com.nicefish.cms.service.IFileUploadService; 4 | import com.nicefish.core.utils.AjaxResult; 5 | import jakarta.servlet.http.HttpServletResponse; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.web.bind.annotation.*; 10 | import org.springframework.web.multipart.MultipartFile; 11 | 12 | import java.io.UnsupportedEncodingException; 13 | 14 | //TODO:加权限控制,没有登录的用户不能上传 15 | @RestController 16 | @RequestMapping("/nicefish/cms/file") 17 | public class FileUploadController { 18 | private static final Logger logger = LoggerFactory.getLogger(FileUploadController.class); 19 | 20 | @Autowired 21 | private IFileUploadService fileUploadService; 22 | 23 | /** 24 | * 文件上传 25 | * 26 | * @param files 27 | * @return 28 | */ 29 | @PostMapping(value = "/upload") 30 | public AjaxResult upLoad(MultipartFile[] files) { 31 | return AjaxResult.success(this.fileUploadService.upload(files)); 32 | } 33 | 34 | /** 35 | * 文件下载 36 | * 37 | * @param id 38 | * @param response 39 | * @return 40 | * @throws UnsupportedEncodingException 41 | */ 42 | @GetMapping(value = "/download/{id}") 43 | public AjaxResult download(@PathVariable("id") Integer id, HttpServletResponse response) throws UnsupportedEncodingException { 44 | return this.fileUploadService.download(id, response); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/jpautils/RoleListSerializer.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.jpautils; 2 | 3 | import com.fasterxml.jackson.core.JsonGenerator; 4 | import com.fasterxml.jackson.databind.SerializerProvider; 5 | import com.fasterxml.jackson.databind.ser.std.StdSerializer; 6 | import com.nicefish.rbac.jpa.entity.RoleEntity; 7 | 8 | import java.io.IOException; 9 | import java.util.ArrayList; 10 | import java.util.HashMap; 11 | import java.util.List; 12 | import java.util.Map; 13 | 14 | /** 15 | * 由于 RoleEntity 与多个实体之间存在多对多的关系,所以在序列化时,需要自定义序列化器,否则 Jackson 会因为循环引用而抛出异常。 16 | * 本序列化器将 RoleEntity 序列化为一个 Map 对象,包含 roleId、roleName、status、remark 四个属性,而不包含与其他实体的关联关系。 17 | * @author 大漠穷秋 18 | */ 19 | public class RoleListSerializer extends StdSerializer> { 20 | public RoleListSerializer() { 21 | this(null); 22 | } 23 | 24 | protected RoleListSerializer(Class> t) { 25 | super(t); 26 | } 27 | 28 | @Override 29 | public void serialize(List roleEntities, JsonGenerator generator, SerializerProvider provider) throws IOException { 30 | List list = new ArrayList<>(); 31 | for (RoleEntity roleEntity : roleEntities) { 32 | HashMap obj=new HashMap(); 33 | obj.put("roleId",roleEntity.getRoleId()); 34 | obj.put("roleName",roleEntity.getRoleName()); 35 | obj.put("status",roleEntity.getStatus()); 36 | obj.put("remark",roleEntity.getRemark()); 37 | list.add(obj); 38 | } 39 | generator.writeObject(list); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /nicefish-cms/src/main/resources/application-druid.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | type: com.alibaba.druid.pool.DruidDataSource 4 | driverClassName: com.mysql.cj.jdbc.Driver 5 | druid: 6 | master: 7 | url: jdbc:mysql://localhost:3307/nicefish-spring-boot-test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 8 | username: root 9 | password: root 10 | slave: 11 | enabled: false 12 | url: 13 | username: 14 | password: 15 | initialSize: 5 16 | minIdle: 10 17 | maxActive: 20 18 | maxWait: 60000 19 | timeBetweenEvictionRunsMillis: 60000 20 | minEvictableIdleTimeMillis: 300000 21 | maxEvictableIdleTimeMillis: 900000 22 | validationQuery: SELECT 1 FROM DUAL 23 | testWhileIdle: true 24 | testOnBorrow: false 25 | testOnReturn: false 26 | webStatFilter: 27 | enabled: true 28 | statViewServlet: 29 | enabled: true 30 | allow: 31 | url-pattern: /druid/* 32 | login-username: 33 | login-password: 34 | filter: 35 | stat: 36 | enabled: true 37 | log-slow-sql: true 38 | slow-sql-millis: 1000 39 | merge-sql: true 40 | wall: 41 | config: 42 | multi-statement-allow: true -------------------------------------------------------------------------------- /nicefish-cms/src/main/java/com/nicefish/cms/jpa/entity/UserPostRelationEntity.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.cms.jpa.entity; 2 | 3 | import jakarta.persistence.*; 4 | import java.io.Serializable; 5 | import java.util.Date; 6 | 7 | @Entity 8 | @Table(name = "nicefish_cms_user_post_relation") 9 | public class UserPostRelationEntity implements Serializable { 10 | @Id 11 | @GeneratedValue(strategy = GenerationType.IDENTITY) 12 | private Integer id; 13 | 14 | @Column(name = "user_id", nullable = false) 15 | private Integer userId; 16 | 17 | @Column(name = "post_id", nullable = false) 18 | private Integer postId; 19 | 20 | @Column(name = "relation_type", nullable = false) 21 | private Integer relationType; 22 | 23 | @Column(name = "time", nullable = false) 24 | private Date time=new Date(); 25 | 26 | public Integer getId() { 27 | return id; 28 | } 29 | 30 | public void setId(Integer id) { 31 | this.id = id; 32 | } 33 | 34 | public Integer getUserId() { 35 | return userId; 36 | } 37 | 38 | public void setUserId(Integer userId) { 39 | this.userId = userId; 40 | } 41 | 42 | public Integer getPostId() { 43 | return postId; 44 | } 45 | 46 | public void setPostId(Integer postId) { 47 | this.postId = postId; 48 | } 49 | 50 | public Date getTime() { 51 | return time; 52 | } 53 | 54 | public void setTime(Date time) { 55 | this.time = time; 56 | } 57 | 58 | public Integer getRelationType() { 59 | return relationType; 60 | } 61 | 62 | public void setRelationType(Integer relationType) { 63 | this.relationType = relationType; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/constant/AuthConstants.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.constant; 2 | 3 | /** 4 | * 5 | * @author 大漠穷秋 6 | */ 7 | public interface AuthConstants { 8 | int USERNAME_MIN_LENGTH = 2; 9 | int USERNAME_MAX_LENGTH = 20; 10 | int PASSWORD_MIN_LENGTH = 5; 11 | int PASSWORD_MAX_LENGTH = 20; 12 | String MOBILE_PHONE_NUMBER_PATTERN = "^0{0,1}(13[0-9]|15[0-9]|14[0-9]|18[0-9])[0-9]{8}$"; 13 | String EMAIL_PATTERN = "^((([a-z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+(\\.([a-z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+)*)|((\\x22)((((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(([\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(\\\\([\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]))))*(((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(\\x22)))@((([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.)+(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.?"; 14 | String CURRENT_CAPTCHA = "captcha"; 15 | String CURRENT_ENABLED = "captchaEnabled"; 16 | String CURRENT_TYPE = "captchaType"; 17 | String CURRENT_VALIDATECODE = "validateCode"; 18 | String CAPTCHA_ERROR = "captchaError"; 19 | } 20 | -------------------------------------------------------------------------------- /nicefish-cms/src/main/java/com/nicefish/cms/service/impl/SysParamServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.cms.service.impl; 2 | 3 | import com.nicefish.cms.jpa.entity.SysParamEntity; 4 | import com.nicefish.cms.jpa.repository.ISysParamRepository; 5 | import com.nicefish.cms.service.ISysParamService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.cache.annotation.Cacheable; 8 | import org.springframework.data.domain.Page; 9 | import org.springframework.data.domain.Pageable; 10 | import org.springframework.stereotype.Service; 11 | import org.springframework.util.ObjectUtils; 12 | 13 | import jakarta.transaction.Transactional; 14 | import java.util.HashMap; 15 | import java.util.Map; 16 | 17 | /** 18 | * @author 大漠穷秋 19 | */ 20 | @Transactional 21 | @Service 22 | public class SysParamServiceImpl implements ISysParamService { 23 | 24 | @Autowired 25 | private ISysParamRepository sysParamRepository; 26 | 27 | @Override 28 | @Cacheable(value="params",key ="T(String).valueOf(#pageable.pageNumber).concat('-').concat(#pageable.pageSize)", unless="#result==null") 29 | public Page getParamPaging(Pageable pageable) { 30 | return this.sysParamRepository.findAll(pageable); 31 | } 32 | 33 | @Override 34 | public Map getAllParamJSON() { 35 | Map result=new HashMap<>(); 36 | Iterable iterable=this.sysParamRepository.findAll(); 37 | if(ObjectUtils.isEmpty(iterable)){ 38 | return result; 39 | } 40 | for (SysParamEntity sysParamEntity : iterable) { 41 | result.put(sysParamEntity.getParamKey(),sysParamEntity.getParamValue()); 42 | } 43 | return result; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /nicefish-cms/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | nicefish-spring-boot 7 | com.nicefish 8 | 1.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | nicefish-cms 13 | nicefish-cms 14 | 1.1-SNAPSHOT 15 | CMS 相关的功能 16 | 17 | 18 | 19 | com.nicefish 20 | nicefish-core 21 | ${nicefish.version} 22 | 23 | 24 | com.nicefish 25 | nicefish-shiro-rbac 26 | ${nicefish.version} 27 | 28 | 29 | 30 | 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-maven-plugin 35 | 3.0.10 36 | 37 | 38 | 39 | repackage 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/jpa/repository/IUserRepository.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.jpa.repository; 2 | 3 | import com.nicefish.rbac.jpa.entity.UserEntity; 4 | import org.springframework.data.domain.Page; 5 | import org.springframework.data.domain.Pageable; 6 | import org.springframework.data.jpa.repository.JpaRepository; 7 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor; 8 | import org.springframework.data.repository.PagingAndSortingRepository; 9 | import org.springframework.transaction.annotation.Transactional; 10 | 11 | /** 12 | * @see JPA DOC 13 | * @author 大漠穷秋 14 | */ 15 | public interface IUserRepository extends PagingAndSortingRepository, JpaSpecificationExecutor, JpaRepository { 16 | 17 | UserEntity findDistinctByUserId(Integer userId); 18 | 19 | UserEntity findDistinctByUserName(String userName); 20 | 21 | UserEntity findDistinctByEmail(String email); 22 | 23 | UserEntity findDistinctTopByCellphone(String cellphone); 24 | 25 | UserEntity findDistinctByUserNameOrEmailOrCellphone(String userName,String email,String cellphone); 26 | 27 | Page findAllByNickName(String nickName,Pageable pageable); 28 | 29 | Page findAllByUserNameOrNickNameOrEmailOrCellphone(String userName,String nickName,String email,String cellphone, Pageable pageable); 30 | 31 | Page findAll(Pageable pageable); 32 | 33 | @Transactional 34 | int deleteByUserId(Integer userId); 35 | 36 | @Transactional 37 | int deleteByUserIdIn(Integer[] userIds); 38 | 39 | @Transactional 40 | int deleteAllByUserId(Integer[] ids); 41 | } -------------------------------------------------------------------------------- /nicefish-elastic-search/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | com.nicefish 7 | nicefish-spring-boot 8 | 1.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | nicefish-elastic-search 13 | nicefish-elastic-search 14 | 1.1-SNAPSHOT 15 | 搜索相关的功能 16 | 17 | 18 | 19 | com.nicefish 20 | nicefish-core 21 | ${nicefish.version} 22 | 23 | 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-starter-data-elasticsearch 28 | 29 | 30 | 31 | 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-maven-plugin 36 | 3.0.10 37 | 38 | 39 | 40 | repackage 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /nicefish-core/src/main/java/com/nicefish/core/utils/AjaxResult.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.core.utils; 2 | 3 | import java.util.HashMap; 4 | 5 | /** 6 | * 7 | * @author 大漠穷秋 8 | */ 9 | public class AjaxResult extends HashMap { 10 | public AjaxResult(){ 11 | super.put("success",true); 12 | super.put("msg",""); 13 | super.put("data",null); 14 | } 15 | 16 | public AjaxResult(boolean success){ 17 | super.put("success",success); 18 | } 19 | 20 | public AjaxResult(String msg){ 21 | super.put("msg",msg); 22 | } 23 | 24 | public AjaxResult(Object data){ 25 | super.put("data",data); 26 | } 27 | 28 | public AjaxResult(boolean success, String msg){ 29 | super.put("success",success); 30 | super.put("msg",msg); 31 | } 32 | 33 | public AjaxResult(boolean success, Object data){ 34 | super.put("success",success); 35 | super.put("data",data); 36 | } 37 | 38 | public AjaxResult(boolean success, String msg, Object data){ 39 | super.put("success",success); 40 | super.put("msg",msg); 41 | super.put("data",data); 42 | } 43 | 44 | public static AjaxResult success(){ 45 | return new AjaxResult(true); 46 | } 47 | 48 | public static AjaxResult success(String msg){ 49 | return new AjaxResult(true,msg); 50 | } 51 | 52 | public static AjaxResult success(Object data){ 53 | return new AjaxResult(true,data); 54 | } 55 | 56 | public static AjaxResult failure(){ 57 | return new AjaxResult(false); 58 | } 59 | 60 | public static AjaxResult failure(String msg){ 61 | return new AjaxResult(false,msg); 62 | } 63 | 64 | public static AjaxResult failure(Object msg){ 65 | return new AjaxResult(false,msg); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/resources/ehcache-shiro.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 16 | 17 | 18 | 25 | 26 | 27 | 28 | 35 | 36 | 37 | 38 | 47 | 52 | 53 | -------------------------------------------------------------------------------- /NiceFish.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | AppName=nicefish-spring-boot.jar 4 | 5 | #JVM参数 6 | JVM_OPTS="-Dname=$AppName -Duser.timezone=Asia/Shanghai -Xms512M -Xmx512M -XX:PermSize=256M -XX:MaxPermSize=512M -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:NewRatio=1 -XX:SurvivorRatio=30 -XX:+UseParallelGC -XX:+UseParallelOldGC" 7 | APP_HOME=`pwd` 8 | LOG_PATH=$APP_HOME/logs/$AppName.log 9 | 10 | if [ "$1" = "" ]; 11 | then 12 | echo -e "\033[0;31m 未输入操作名 \033[0m \033[0;34m {start|stop|restart|status} \033[0m" 13 | exit 1 14 | fi 15 | 16 | if [ "$AppName" = "" ]; 17 | then 18 | echo -e "\033[0;31m 未输入应用名 \033[0m" 19 | exit 1 20 | fi 21 | 22 | function start() 23 | { 24 | PID=`ps -ef |grep java|grep $AppName|grep -v grep|awk '{print $2}'` 25 | 26 | if [ x"$PID" != x"" ]; then 27 | echo "$AppName is running..." 28 | else 29 | nohup java -jar $JVM_OPTS target/$AppName > /dev/null 2>&1 & 30 | echo "Start $AppName success..." 31 | fi 32 | } 33 | 34 | function stop() 35 | { 36 | echo "Stop $AppName" 37 | 38 | PID="" 39 | query(){ 40 | PID=`ps -ef |grep java|grep $AppName|grep -v grep|awk '{print $2}'` 41 | } 42 | 43 | query 44 | if [ x"$PID" != x"" ]; then 45 | kill -TERM $PID 46 | echo "$AppName (pid:$PID) exiting..." 47 | while [ x"$PID" != x"" ] 48 | do 49 | sleep 1 50 | query 51 | done 52 | echo "$AppName exited." 53 | else 54 | echo "$AppName already stopped." 55 | fi 56 | } 57 | 58 | function restart() 59 | { 60 | stop 61 | sleep 2 62 | start 63 | } 64 | 65 | function status() 66 | { 67 | PID=`ps -ef |grep java|grep $AppName|grep -v grep|wc -l` 68 | if [ $PID != 0 ];then 69 | echo "$AppName is running..." 70 | else 71 | echo "$AppName is not running..." 72 | fi 73 | } 74 | 75 | case $1 in 76 | start) 77 | start;; 78 | stop) 79 | stop;; 80 | restart) 81 | restart;; 82 | status) 83 | status;; 84 | *) 85 | 86 | esac 87 | -------------------------------------------------------------------------------- /nicefish-cms/src/main/java/com/nicefish/cms/service/IUserPostRelationService.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.cms.service; 2 | 3 | import com.nicefish.cms.jpa.entity.PostEntity; 4 | import com.nicefish.cms.jpa.entity.UserPostRelationEntity; 5 | 6 | import java.util.List; 7 | 8 | public interface IUserPostRelationService { 9 | /** 10 | * 根据用户ID和帖子ID查找关系记录 11 | * @param userId 12 | * @param postId 13 | * @return 14 | */ 15 | UserPostRelationEntity findByUserIdAndPostId(Integer userId, Integer postId); 16 | 17 | /** 18 | * 根据用户ID查找所有关系记录 19 | * @param userId 20 | * @return 21 | */ 22 | List findAllByUserId(Integer userId); 23 | 24 | /** 25 | * 根据 userId 查找此用户收藏或者点赞的所有帖子 26 | * TODO:分页 27 | * @param userId 28 | * @param relationType 29 | * @return 30 | */ 31 | List findUserRelatedPosts(Integer userId,Integer relationType); 32 | 33 | /** 34 | * 根据帖子ID查找所有关系记录 35 | * @param postId 36 | * @return 37 | */ 38 | List findAllByPostId(Integer postId); 39 | 40 | /** 41 | * 根据帖子ID和关系类型统计数量 42 | * @param postId 43 | * @param relationType 44 | * @return 45 | */ 46 | int countByPostIdAndRelationType(Integer postId, Integer relationType); 47 | 48 | /** 49 | * 统计用户内容的获赞总数 50 | * @param userId 51 | * @return 52 | */ 53 | int countLikesForUserPosts(Integer userId); 54 | 55 | /** 56 | * 判断用户与帖子之间是否存在点赞与收藏关系 57 | * @param userPostRelationEntity 58 | * @return 59 | */ 60 | boolean existsRelation(UserPostRelationEntity userPostRelationEntity); 61 | 62 | /** 63 | * 保存用户与帖子之间的关系 64 | * @param userPostRelation 65 | */ 66 | void saveUserPostRelation(UserPostRelationEntity userPostRelation); 67 | 68 | /** 69 | * 删除用户与帖子之间的关系 70 | * @param userPostRelation 71 | */ 72 | void deleteUserPostRelation(UserPostRelationEntity userPostRelation); 73 | } -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/service/IUserService.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.service; 2 | 3 | import com.nicefish.rbac.jpa.entity.RoleEntity; 4 | import com.nicefish.rbac.jpa.entity.UserEntity; 5 | import org.springframework.data.domain.Page; 6 | import org.springframework.data.domain.Pageable; 7 | 8 | import java.util.Set; 9 | 10 | /** 11 | * 12 | * @author 大漠穷秋 13 | */ 14 | public interface IUserService { 15 | 16 | UserEntity createUser(UserEntity userEntity); 17 | 18 | int resetPwd(Integer userId); 19 | 20 | UserEntity resetPwd(UserEntity userEntity); 21 | 22 | UserEntity setUserStatus(UserEntity userEntity); 23 | 24 | UserEntity updateUser(UserEntity userEntity); 25 | 26 | UserEntity updateUserRoleRelation(UserEntity userEntity); 27 | 28 | Page getUserList(UserEntity userEntity, Pageable pageable); 29 | 30 | Page getAllocatedList(RoleEntity roleEntity, UserEntity userEntity, Pageable pageable); 31 | 32 | Page getUnallocatedList(RoleEntity roleEntity, UserEntity userEntity, Pageable pageable); 33 | 34 | UserEntity getUserByUserName(String userName); 35 | 36 | UserEntity getUserByCellphone(String cellphone); 37 | 38 | UserEntity getUserByEmail(String email); 39 | 40 | UserEntity getUserByUserId(Integer userId); 41 | 42 | int deleteByUserId(Integer userId); 43 | 44 | int deleteByIds(Integer[] ids); 45 | 46 | UserEntity saveUser(UserEntity userEntity); 47 | 48 | 49 | boolean isUserNameUnique(String userName); 50 | 51 | boolean isPhoneUnique(String cellphone); 52 | 53 | boolean isEmailUnique(String email); 54 | 55 | String getRoleList(Integer userId); 56 | 57 | boolean matches(UserEntity userEntity, String newPassword); 58 | 59 | String encryptPassword(String username, String password, String salt); 60 | 61 | UserEntity checkUser(String userName, String password); 62 | 63 | /** 64 | * 根据 userId 获取此用户持有的所有权限字符串列表 65 | * @param userId 66 | * @return 67 | */ 68 | Set getPermStringsByUserId(Integer userId); 69 | } 70 | -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/shiro/session/NiceFishSessionFactory.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.shiro.session; 2 | 3 | import com.nicefish.core.utils.IPUtil; 4 | import eu.bitwalker.useragentutils.UserAgent; 5 | import org.apache.shiro.session.Session; 6 | import org.apache.shiro.session.mgt.SessionContext; 7 | import org.apache.shiro.session.mgt.SimpleSessionFactory; 8 | import org.apache.shiro.web.session.mgt.WebSessionContext; 9 | 10 | import jakarta.servlet.ServletRequest; 11 | import jakarta.servlet.http.HttpServletRequest; 12 | 13 | /** 14 | * NiceFish 自定义的 Session 工厂类,扩展 SimpleSessionFactory ,把一些额外的属性设置到 Session 实例的 attributes 里面。 15 | * Shiro 在运行时会使用此类来创建 Session 实例,配置项在 ShiroConfig.java 中。 16 | * @author 大漠穷秋 17 | */ 18 | public class NiceFishSessionFactory extends SimpleSessionFactory { 19 | @Override 20 | public Session createSession(SessionContext sessionContext) { 21 | Session session=super.createSession(sessionContext); 22 | if (sessionContext instanceof WebSessionContext) { 23 | WebSessionContext webSessionContext = (WebSessionContext) sessionContext; 24 | HttpServletRequest request = (HttpServletRequest) webSessionContext.getServletRequest(); 25 | String ip= IPUtil.getIpAddr(request); 26 | session.setAttribute("host",ip); 27 | 28 | ServletRequest servletRequest=webSessionContext.getServletRequest(); 29 | if(servletRequest instanceof HttpServletRequest){ 30 | String userAgentString=((HttpServletRequest)servletRequest).getHeader("User-Agent"); 31 | session.setAttribute("userAgent",userAgentString); 32 | 33 | UserAgent userAgent = UserAgent.parseUserAgentString(userAgentString); 34 | String os = userAgent.getOperatingSystem().getName(); 35 | String browser = userAgent.getBrowser().getName(); 36 | session.setAttribute("os",os); 37 | session.setAttribute("browser",browser); 38 | } 39 | } 40 | return session; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /nicefish-cms/src/main/java/com/nicefish/cms/service/impl/CommentServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.cms.service.impl; 2 | 3 | import com.nicefish.cms.jpa.entity.CommentEntity; 4 | import com.nicefish.cms.jpa.repository.ICommentRepository; 5 | import com.nicefish.cms.service.ICommentService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.cache.annotation.CacheEvict; 8 | import org.springframework.cache.annotation.Cacheable; 9 | import org.springframework.data.domain.Page; 10 | import org.springframework.data.domain.Pageable; 11 | import org.springframework.stereotype.Service; 12 | 13 | import jakarta.transaction.Transactional; 14 | 15 | @Transactional 16 | @Service 17 | public class CommentServiceImpl implements ICommentService { 18 | @Autowired 19 | private ICommentRepository commentRepository; 20 | 21 | @Override 22 | @Cacheable(value = "comments",key = "#postId.toString().concat('-comments')") 23 | public Page findByPostId(Integer postId, Pageable pageable) { 24 | return commentRepository.findAllByPostId(postId,pageable); 25 | } 26 | 27 | @Override 28 | @CacheEvict(value = "comments",allEntries = true) 29 | public CommentEntity saveComment(CommentEntity commentEntity) { 30 | return commentRepository.save(commentEntity); 31 | } 32 | 33 | @Override 34 | public Page findAllByUserIdAndPaging(Integer userId, Pageable pageable) { 35 | return commentRepository.findAllByUserId(userId,pageable); 36 | } 37 | 38 | @Override 39 | public Integer countByUserId(Integer userId) { 40 | return this.commentRepository.countByUserId(userId); 41 | } 42 | 43 | @Override 44 | @CacheEvict(value = "comments",allEntries = true) 45 | public void deleteById(Integer commentId) { 46 | this.commentRepository.deleteById(commentId); 47 | } 48 | 49 | @Override 50 | public Integer deletetByPostId(Integer postId) { 51 | return this.commentRepository.deleteByPostId(postId); 52 | } 53 | 54 | @Override 55 | public Integer deleteByUserId(Integer userId) { 56 | return this.commentRepository.deleteByUserId(userId); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /nicefish-cms/src/main/java/com/nicefish/cms/config/DruidProperties.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.cms.config; 2 | 3 | import com.alibaba.druid.pool.DruidDataSource; 4 | import org.springframework.beans.factory.annotation.Value; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | @Configuration 8 | public class DruidProperties { 9 | @Value("${spring.datasource.druid.initialSize}") 10 | private int initialSize; 11 | 12 | @Value("${spring.datasource.druid.minIdle}") 13 | private int minIdle; 14 | 15 | @Value("${spring.datasource.druid.maxActive}") 16 | private int maxActive; 17 | 18 | @Value("${spring.datasource.druid.maxWait}") 19 | private int maxWait; 20 | 21 | @Value("${spring.datasource.druid.timeBetweenEvictionRunsMillis}") 22 | private int timeBetweenEvictionRunsMillis; 23 | 24 | @Value("${spring.datasource.druid.minEvictableIdleTimeMillis}") 25 | private int minEvictableIdleTimeMillis; 26 | 27 | @Value("${spring.datasource.druid.maxEvictableIdleTimeMillis}") 28 | private int maxEvictableIdleTimeMillis; 29 | 30 | @Value("${spring.datasource.druid.validationQuery}") 31 | private String validationQuery; 32 | 33 | @Value("${spring.datasource.druid.testWhileIdle}") 34 | private boolean testWhileIdle; 35 | 36 | @Value("${spring.datasource.druid.testOnBorrow}") 37 | private boolean testOnBorrow; 38 | 39 | @Value("${spring.datasource.druid.testOnReturn}") 40 | private boolean testOnReturn; 41 | 42 | public DruidDataSource dataSource(DruidDataSource datasource) { 43 | datasource.setInitialSize(initialSize); 44 | datasource.setMaxActive(maxActive); 45 | datasource.setMinIdle(minIdle); 46 | datasource.setMaxWait(maxWait); 47 | datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis); 48 | datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis); 49 | datasource.setMaxEvictableIdleTimeMillis(maxEvictableIdleTimeMillis); 50 | datasource.setValidationQuery(validationQuery); 51 | datasource.setTestWhileIdle(testWhileIdle); 52 | datasource.setTestOnBorrow(testOnBorrow); 53 | datasource.setTestOnReturn(testOnReturn); 54 | return datasource; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/util/KaptchaTextCreator.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.util; 2 | 3 | import com.google.code.kaptcha.text.impl.DefaultTextCreator; 4 | 5 | import java.security.SecureRandom; 6 | import java.util.Random; 7 | 8 | /** 9 | * 验证码文本生成器 10 | * 11 | * @author 大漠穷秋 12 | */ 13 | public class KaptchaTextCreator extends DefaultTextCreator { 14 | private static final String[] CNUMBERS = "0,1,2,3,4,5,6,7,8,9,10".split(","); 15 | 16 | @Override 17 | public String getText() { 18 | Integer result = 0; 19 | Random random = new SecureRandom(); 20 | int x = random.nextInt(10); 21 | int y = random.nextInt(10); 22 | StringBuilder suChinese = new StringBuilder(); 23 | int randomoperands = (int) Math.round(Math.random() * 2); 24 | if (randomoperands == 0) { 25 | result = x * y; 26 | suChinese.append(CNUMBERS[x]); 27 | suChinese.append("*"); 28 | suChinese.append(CNUMBERS[y]); 29 | } else if (randomoperands == 1) { 30 | if (!(x == 0) && y % x == 0) { 31 | result = y / x; 32 | suChinese.append(CNUMBERS[y]); 33 | suChinese.append("/"); 34 | suChinese.append(CNUMBERS[x]); 35 | } else { 36 | result = x + y; 37 | suChinese.append(CNUMBERS[x]); 38 | suChinese.append("+"); 39 | suChinese.append(CNUMBERS[y]); 40 | } 41 | } else if (randomoperands == 2) { 42 | if (x >= y) { 43 | result = x - y; 44 | suChinese.append(CNUMBERS[x]); 45 | suChinese.append("-"); 46 | suChinese.append(CNUMBERS[y]); 47 | } else { 48 | result = y - x; 49 | suChinese.append(CNUMBERS[y]); 50 | suChinese.append("-"); 51 | suChinese.append(CNUMBERS[x]); 52 | } 53 | } else { 54 | result = x + y; 55 | suChinese.append(CNUMBERS[x]); 56 | suChinese.append("+"); 57 | suChinese.append(CNUMBERS[y]); 58 | } 59 | suChinese.append("=?@" + result); 60 | return suChinese.toString(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/shiro/util/NiceFishSecurityUtils.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.shiro.util; 2 | 3 | import com.nicefish.rbac.jpa.entity.UserEntity; 4 | import org.apache.shiro.SecurityUtils; 5 | import org.apache.shiro.crypto.SecureRandomNumberGenerator; 6 | import org.apache.shiro.session.Session; 7 | import org.apache.shiro.subject.PrincipalCollection; 8 | import org.apache.shiro.subject.SimplePrincipalCollection; 9 | import org.apache.shiro.subject.Subject; 10 | import org.springframework.beans.BeanUtils; 11 | import org.springframework.util.ObjectUtils; 12 | 13 | /** 14 | * 静态工具类,扩展 Shiro 内置的 SecurityUtils 工具类,加上 NiceFish 需要的一些工具方法,这些方法用来简化上层的业务代码。 15 | * @author 大漠穷秋 16 | */ 17 | public class NiceFishSecurityUtils extends SecurityUtils{ 18 | public static UserEntity getUserEntity() { 19 | UserEntity userEntity = null; 20 | Object obj = SecurityUtils.getSubject().getPrincipal(); 21 | if (!ObjectUtils.isEmpty(obj)) { 22 | userEntity = new UserEntity(); 23 | BeanUtils.copyProperties(obj, userEntity); 24 | } 25 | return userEntity; 26 | } 27 | 28 | public static void setUserEntity(UserEntity userEntity) { 29 | Subject subject = SecurityUtils.getSubject(); 30 | PrincipalCollection principalCollection = subject.getPrincipals(); 31 | String realmName = principalCollection.getRealmNames().iterator().next(); 32 | PrincipalCollection newPrincipalCollection = new SimplePrincipalCollection(userEntity, realmName); 33 | subject.runAs(newPrincipalCollection); 34 | } 35 | 36 | public static Session getSession(){ 37 | return SecurityUtils.getSubject().getSession(); 38 | } 39 | 40 | public static Integer getUserId() { 41 | return getUserEntity().getUserId(); 42 | } 43 | 44 | public static String getUserName() { 45 | return getUserEntity().getUserName(); 46 | } 47 | 48 | public static String getIp() { 49 | return SecurityUtils.getSubject().getSession().getHost(); 50 | } 51 | 52 | public static String getSessionId() { 53 | return String.valueOf(SecurityUtils.getSubject().getSession().getId()); 54 | } 55 | 56 | public static String randomSalt() { 57 | return new SecureRandomNumberGenerator().nextBytes(3).toHex(); 58 | } 59 | } -------------------------------------------------------------------------------- /nicefish-cms/src/main/java/com/nicefish/cms/service/impl/UserFollowServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.cms.service.impl; 2 | 3 | import com.nicefish.cms.jpa.entity.UserFollowEntity; 4 | import com.nicefish.cms.jpa.repository.IUserFollowRepository; 5 | import com.nicefish.cms.service.IUserFollowService; 6 | import com.nicefish.rbac.jpa.entity.UserEntity; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Service; 9 | import org.springframework.transaction.annotation.Transactional; 10 | 11 | import java.util.List; 12 | 13 | @Service 14 | public class UserFollowServiceImpl implements IUserFollowService { 15 | 16 | private final IUserFollowRepository userFollowRepository; 17 | 18 | @Autowired 19 | public UserFollowServiceImpl(IUserFollowRepository userFollowRepository) { 20 | this.userFollowRepository = userFollowRepository; 21 | } 22 | 23 | @Override 24 | public List findFollowersByUserId(Integer userId) { 25 | return userFollowRepository.findFollowersByUserId(userId); 26 | } 27 | 28 | @Override 29 | public Long countFollowersByUserId(Integer userId) { 30 | return userFollowRepository.countFollowersByUserId(userId); 31 | } 32 | 33 | @Override 34 | public Long countFollowingByUserId(Integer userId) { 35 | return userFollowRepository.countFollowingByUserId(userId); 36 | } 37 | 38 | @Override 39 | @Transactional 40 | public UserFollowEntity createFollowRelation(UserFollowEntity userFollowEntity) { 41 | //TODO:这里的删除有 bug,没有删除成功 42 | userFollowRepository.delete(userFollowEntity); 43 | return userFollowRepository.save(userFollowEntity); 44 | } 45 | 46 | @Override 47 | @Transactional 48 | public void deleteFollowRelation(UserFollowEntity userFollowEntity) { 49 | UserFollowEntity temp = userFollowRepository.findByFromIdAndToId( 50 | userFollowEntity.getFromId(), 51 | userFollowEntity.getToId() 52 | ); 53 | 54 | if (temp != null) { 55 | userFollowRepository.delete(temp); 56 | } 57 | } 58 | 59 | @Override 60 | public boolean existsFollow(UserFollowEntity userFollowEntity) { 61 | return userFollowRepository.existsByFromIdAndToId( 62 | userFollowEntity.getFromId(), 63 | userFollowEntity.getToId() 64 | ); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /docs/elastic-mysql-jdbc.conf: -------------------------------------------------------------------------------- 1 | input { 2 | jdbc { 3 | type => "nicefish_cms_post" 4 | jdbc_connection_string => "jdbc:mysql://192.168.23.1:3307/nicefish-spring-boot-test?characterEncoding=UTF-8&autoReconnect=true" 5 | jdbc_user => "root" 6 | jdbc_password => "root" 7 | jdbc_driver_library => "/usr/share/logstash/mysql/mysql-connector-j-8.1.0.jar" 8 | jdbc_driver_class => "com.mysql.cj.jdbc.Driver" 9 | statement => "SELECT * FROM nicefish_cms_post" 10 | connection_retry_attempts => 3 11 | jdbc_validate_connection => true 12 | jdbc_validation_timeout => 3600 13 | jdbc_paging_enabled => true 14 | jdbc_page_size => 500 15 | lowercase_column_names => false 16 | sql_log_level => "info" 17 | record_last_run => true 18 | use_column_value => true 19 | tracking_column => "update_time" 20 | tracking_column_type => "timestamp" 21 | clean_run => false 22 | schedule => "* * * * *" 23 | } 24 | jdbc { 25 | type => "nicefish_rbac_user" 26 | jdbc_connection_string => "jdbc:mysql://192.168.23.1:3307/nicefish-spring-boot-test?characterEncoding=UTF-8&autoReconnect=true" 27 | jdbc_user => "root" 28 | jdbc_password => "root" 29 | jdbc_driver_library => "/usr/share/logstash/mysql/mysql-connector-j-8.1.0.jar" 30 | jdbc_driver_class => "com.mysql.cj.jdbc.Driver" 31 | statement => "SELECT user_id, user_name, nick_name, email, cellphone, gender, city, education, avatar_url, create_time, status, remark FROM nicefish_rbac_user" 32 | connection_retry_attempts => 3 33 | jdbc_validate_connection => true 34 | jdbc_validation_timeout => 3600 35 | jdbc_paging_enabled => true 36 | jdbc_page_size => 500 37 | lowercase_column_names => false 38 | sql_log_level => "info" 39 | record_last_run => true 40 | use_column_value => true 41 | tracking_column => "create_time" 42 | tracking_column_type => "timestamp" 43 | clean_run => false 44 | schedule => "* * * * *" 45 | } 46 | } 47 | 48 | filter { 49 | json { 50 | source => "message" 51 | remove_field => ["message"] 52 | } 53 | } 54 | 55 | output { 56 | elasticsearch { 57 | hosts => [ "localhost:9200" ] 58 | index => "nicefish_cms_post" 59 | document_id => "%{post_id}" 60 | } 61 | elasticsearch { 62 | hosts => [ "localhost:9200" ] 63 | index => "nicefish_rbac_user" 64 | document_id => "%{user_id}" 65 | } 66 | stdout { 67 | codec => json_lines 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /nicefish-cms/src/main/java/com/nicefish/cms/controller/UserFollowController.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.cms.controller; 2 | 3 | import com.nicefish.cms.jpa.entity.UserFollowEntity; 4 | import com.nicefish.cms.service.IUserFollowService; 5 | import com.nicefish.core.utils.AjaxResult; 6 | import com.nicefish.rbac.jpa.entity.UserEntity; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.util.ObjectUtils; 9 | import org.springframework.web.bind.annotation.*; 10 | 11 | import java.util.List; 12 | 13 | @RestController 14 | @RequestMapping("/nicefish/cms/user-follow") 15 | public class UserFollowController { 16 | @Autowired 17 | private IUserFollowService userFollowService; 18 | 19 | /** 20 | * 获取用户粉丝列表 21 | */ 22 | @GetMapping("/followers/{userId}") 23 | public List getFollowersByUserId(@PathVariable Integer userId) { 24 | return userFollowService.findFollowersByUserId(userId); 25 | } 26 | 27 | /** 28 | * 获取用户粉丝数量 29 | */ 30 | @RequestMapping(value = "/follower-count/{userId}",method = RequestMethod.GET) 31 | public Long countFollowersByUserId(@PathVariable(value="userId",required = true) Integer userId) { 32 | return userFollowService.countFollowersByUserId(userId); 33 | } 34 | 35 | /** 36 | * 获取用户关注的人数量 37 | */ 38 | @RequestMapping(value = "/following-count/{userId}",method = RequestMethod.GET) 39 | public Long countFollowingByUserId(@PathVariable(value="userId",required = true) Integer userId) { 40 | return userFollowService.countFollowingByUserId(userId); 41 | } 42 | 43 | /** 44 | * 创建关注关系 45 | */ 46 | @PostMapping("/follow") 47 | public AjaxResult createFollowRelation(@RequestBody UserFollowEntity userFollowEntity) { 48 | UserFollowEntity result=userFollowService.createFollowRelation(userFollowEntity); 49 | return ObjectUtils.isEmpty(result)?AjaxResult.failure():AjaxResult.success(); 50 | } 51 | 52 | /** 53 | * 删除关注关系 54 | */ 55 | @DeleteMapping("/unfollow") 56 | public void deleteFollowRelation(@RequestBody UserFollowEntity userFollowEntity) { 57 | userFollowService.deleteFollowRelation(userFollowEntity); 58 | } 59 | 60 | @PostMapping("/exists-follow") 61 | public boolean existsFollow(@RequestBody UserFollowEntity userFollowEntity) { 62 | return userFollowService.existsFollow(userFollowEntity); 63 | } 64 | } -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/service/impl/NiceFishSessionServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.service.impl; 2 | 3 | import com.nicefish.rbac.jpa.entity.NiceFishSessionEntity; 4 | import com.nicefish.rbac.jpa.repository.INiceFishSessionRepository; 5 | import com.nicefish.rbac.service.INiceFishSessionService; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.data.domain.Page; 10 | import org.springframework.data.domain.Pageable; 11 | import org.springframework.data.jpa.domain.Specification; 12 | import org.springframework.stereotype.Service; 13 | 14 | import jakarta.persistence.criteria.CriteriaBuilder; 15 | import jakarta.persistence.criteria.CriteriaQuery; 16 | import jakarta.persistence.criteria.Predicate; 17 | import jakarta.persistence.criteria.Root; 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | 21 | /** 22 | * @author 大漠穷秋 23 | */ 24 | @Service 25 | public class NiceFishSessionServiceImpl implements INiceFishSessionService { 26 | private static final Logger logger = LoggerFactory.getLogger(NiceFishSessionServiceImpl.class); 27 | 28 | @Autowired 29 | private INiceFishSessionRepository sessionRepository; 30 | 31 | @Override 32 | public NiceFishSessionEntity findDistinctBySessionId(String sessionId) { 33 | return this.sessionRepository.findDistinctBySessionId(sessionId); 34 | } 35 | 36 | @Override 37 | public Page findNiceFishSessionEntitiesByUserId(Integer userId, Pageable pageable) { 38 | return this.sessionRepository.findAll(new Specification() { 39 | @Override 40 | public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) { 41 | List predicates=new ArrayList<>(); 42 | predicates.add(criteriaBuilder.equal(root.get("userId"),userId)); 43 | return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()])); 44 | } 45 | },pageable); 46 | } 47 | 48 | @Override 49 | public int deleteDistinctBySessionId(String sessionId) { 50 | return this.sessionRepository.deleteDistinctBySessionId(sessionId); 51 | } 52 | 53 | @Override 54 | public NiceFishSessionEntity saveSession(NiceFishSessionEntity session) { 55 | return this.sessionRepository.save(session); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /nicefish-cms/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | nicefish: 2 | name: nicefish 3 | version: 1.1.0 4 | copyrightYear: 2019 5 | demoEnabled: true 6 | # 文件上传目录,请根据自己服务器情况配置 7 | uploadPath: C:/nicefish/upload 8 | #uploadPath: /Users/nanke/workSpace/uploadDir 9 | addressEnabled: true 10 | 11 | server: 12 | port: 8080 13 | max-http-request-header-size: 65535 14 | servlet: 15 | context-path: / 16 | forward-headers-strategy: NATIVE 17 | tomcat: 18 | uri-encoding: UTF-8 19 | max-threads: 800 20 | min-spare-threads: 30 21 | 22 | logging: 23 | level: 24 | com.nicefish: TRACE 25 | org.springframework: TRACE 26 | org.hibernate.SQL: TRACE 27 | org.hibernate.type.descriptor.sql: TRACE 28 | org.hibernate.engine.QueryParameters: TRACE 29 | org.hibernate.engine.query.HQLQueryPlan: TRACE 30 | org.hibernate.type.descriptor.sql.BasicBinder: TRACE 31 | 32 | user: 33 | password: 34 | maxRetryCount: 5 35 | 36 | spring: 37 | messages: 38 | basename: static/i18n/messages 39 | jackson: 40 | time-zone: GMT+8 41 | date-format: yyyy-MM-dd HH:mm:ss 42 | profiles: 43 | active: druid 44 | servlet: 45 | multipart: 46 | # 单个文件上传大小限制 47 | max-file-size: 100MB 48 | max-request-size: 500MB 49 | devtools: 50 | restart: 51 | enabled: true 52 | additional-paths: src/main/java 53 | jpa: 54 | properties: 55 | hibernate: 56 | dialect: org.hibernate.dialect.MySQL8Dialect 57 | order_inserts: true 58 | order_updates: true 59 | format_sql: true 60 | hbm2ddl: 61 | auto: validate 62 | jdbc: 63 | batch_size: 500 64 | batch_versioned_data: true 65 | show-sql: true 66 | 67 | pagehelper: 68 | helperDialect: mysql 69 | reasonable: true 70 | supportMethodsArguments: true 71 | params: count=countSql 72 | 73 | # Shiro 相关的配置, ShiroConfig.java 配置类会读取这些配置项。 74 | shiro: 75 | user: 76 | loginUrl: /nicefish/auth/shiro/login 77 | unauthorizedUrl: /nicefish/auth/shiro/unauth 78 | indexUrl: /index 79 | captchaEnabled: true 80 | captchaType: math 81 | cookie: 82 | domain: 83 | path: / 84 | httpOnly: false 85 | maxAge: 259200000 #ms 86 | secure: false 87 | session: 88 | timeout: 259200000 #ms 89 | dbSyncPeriod: 1 90 | validationInterval: 10000 #ms 91 | maxSession: -1 92 | kickoutAfter: false 93 | 94 | xss: 95 | enabled: true 96 | excludes: /system/notice/* 97 | urlPatterns: /system/*,/monitor/*,/tool/* 98 | -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/shiro/realm/NiceFishMySQLRealm.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.shiro.realm; 2 | 3 | import com.nicefish.rbac.jpa.entity.UserEntity; 4 | import com.nicefish.rbac.service.IUserService; 5 | import com.nicefish.rbac.shiro.util.NiceFishSecurityUtils; 6 | import org.apache.shiro.authc.*; 7 | import org.apache.shiro.authz.AuthorizationInfo; 8 | import org.apache.shiro.authz.SimpleAuthorizationInfo; 9 | import org.apache.shiro.realm.AuthorizingRealm; 10 | import org.apache.shiro.subject.PrincipalCollection; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | 15 | import java.util.Set; 16 | 17 | /** 18 | * NiceFish 操作 MySQL 的 Realm 。 19 | * @author 大漠穷秋 20 | */ 21 | public class NiceFishMySQLRealm extends AuthorizingRealm { 22 | private static final Logger logger = LoggerFactory.getLogger(NiceFishMySQLRealm.class); 23 | 24 | @Autowired 25 | private IUserService userService; 26 | 27 | /** 28 | * 认证 29 | * TODO:这里仅实现了简单的用户名+密码的验证方式,需要扩展其它认证方式,例如:扫描二维码、第三方认证。 30 | */ 31 | @Override 32 | protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { 33 | UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token; 34 | String username = usernamePasswordToken.getUsername(); 35 | String password = usernamePasswordToken.getPassword()!=null?new String(usernamePasswordToken.getPassword()):""; 36 | 37 | UserEntity userEntity; 38 | try { 39 | userEntity = userService.checkUser(username, password); 40 | logger.debug("UserName>"+username); 41 | logger.debug("Password>"+password); 42 | }catch (Exception e) { 43 | logger.error(username + "登录失败{}", e.getMessage()); 44 | throw new AuthenticationException(e.getMessage(), e); 45 | } 46 | 47 | //用户认证成功,返回验证信息实例。 48 | SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(userEntity, password, getName()); 49 | return info; 50 | } 51 | 52 | /** 53 | * 授权 54 | * NiceFish 采用 Shiro 字符串形式的权限定义,权限不实现成 Java 类。 55 | * Shiro 权限字符串的匹配模式定义参考 https://shiro.apache.org/java-authorization-guide.html 56 | */ 57 | @Override 58 | protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { 59 | Integer userId= NiceFishSecurityUtils.getUserId(); 60 | 61 | //TODO:首先尝试从 Session 中获取角色和权限数据,加快授权操作的速度。 62 | //同时需要自己扩展 SessionListener 来同步 Session 数据。 63 | 64 | Set permStrs=this.userService.getPermStringsByUserId(userId); 65 | logger.debug(permStrs.toString()); 66 | 67 | SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); 68 | info.setStringPermissions(permStrs); 69 | return info; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/jpa/entity/RoleEntity.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.jpa.entity; 2 | 3 | import com.fasterxml.jackson.annotation.*; 4 | import org.hibernate.annotations.DynamicInsert; 5 | import org.hibernate.annotations.DynamicUpdate; 6 | 7 | import jakarta.persistence.*; 8 | import java.io.Serializable; 9 | import java.util.List; 10 | 11 | @Entity 12 | @DynamicInsert 13 | @DynamicUpdate 14 | @Table(name = "nicefish_rbac_role") 15 | public class RoleEntity implements Serializable { 16 | @Id 17 | @GeneratedValue(strategy = GenerationType.IDENTITY) 18 | @Column(name="role_id") 19 | private Integer roleId; 20 | 21 | @Column(name="role_name") 22 | private String roleName; 23 | 24 | @Column(name="status",columnDefinition = "int default 0",nullable = false) 25 | private Integer status; 26 | 27 | @Column(name="remark") 28 | private String remark; 29 | 30 | @ManyToMany(mappedBy = "roleEntities",fetch = FetchType.LAZY) 31 | private List userEntities; 32 | 33 | @ManyToMany(mappedBy = "roleEntities",fetch = FetchType.LAZY) 34 | private List apiEntities; 35 | 36 | @ManyToMany(mappedBy = "roleEntities",fetch = FetchType.LAZY) 37 | private List componentEntities; 38 | 39 | //每个角色都可能被大量用户关联,因此 JSON 序列化时忽略 userEntities 40 | //TODO:用户数量很大时查询会有问题???需要用测试数据 check 41 | @JsonIgnore 42 | public List getUserEntities() { 43 | return userEntities; 44 | } 45 | 46 | public void setUserEntities(List userEntities) { 47 | this.userEntities = userEntities; 48 | } 49 | 50 | public List getApiEntities() { 51 | return apiEntities; 52 | } 53 | 54 | public void setApiEntities(List apiEntities) { 55 | this.apiEntities = apiEntities; 56 | } 57 | 58 | public List getComponentEntities() { 59 | return componentEntities; 60 | } 61 | 62 | public void setComponentEntities(List componentEntities) { 63 | this.componentEntities = componentEntities; 64 | } 65 | 66 | public Integer getRoleId() { 67 | return roleId; 68 | } 69 | 70 | public void setRoleId(Integer roleId) { 71 | this.roleId = roleId; 72 | } 73 | 74 | public String getRoleName() { 75 | return roleName; 76 | } 77 | 78 | public void setRoleName(String roleName) { 79 | this.roleName = roleName; 80 | } 81 | 82 | public Integer getStatus() { 83 | return status; 84 | } 85 | 86 | public void setStatus(Integer status) { 87 | this.status = status; 88 | } 89 | 90 | public String getRemark() { 91 | return remark; 92 | } 93 | 94 | public void setRemark(String remark) { 95 | this.remark = remark; 96 | } 97 | 98 | } -------------------------------------------------------------------------------- /nicefish-cms/src/main/java/com/nicefish/cms/jpa/repository/IUserPostRelationRepository.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.cms.jpa.repository; 2 | 3 | import com.nicefish.cms.jpa.entity.PostEntity; 4 | import com.nicefish.cms.jpa.entity.UserPostRelationEntity; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | import org.springframework.data.jpa.repository.Query; 7 | import org.springframework.data.repository.query.Param; 8 | import org.springframework.stereotype.Repository; 9 | 10 | import java.util.List; 11 | 12 | @Repository 13 | public interface IUserPostRelationRepository extends JpaRepository { 14 | /** 15 | * 根据用户ID和帖子ID查找关系记录 16 | * @param userId 17 | * @param postId 18 | * @return 19 | */ 20 | UserPostRelationEntity findByUserIdAndPostId(Integer userId, Integer postId); 21 | 22 | /** 23 | * 判断用户与帖子之间是否存在点赞与收藏关系 24 | * @param userId 25 | * @param postId 26 | * @param relationType 27 | * @return 28 | */ 29 | boolean existsByUserIdAndPostIdAndRelationType(@Param("userId") Integer userId, @Param("postId") Integer postId, @Param("relationType") Integer relationType); 30 | 31 | /** 32 | * 根据 userId, postId, relationType 查找关系记录 33 | * @param userId 34 | * @param postId 35 | * @param relationType 36 | * @return 37 | */ 38 | UserPostRelationEntity findByUserIdAndPostIdAndRelationType(Integer userId, Integer postId, Integer relationType); 39 | 40 | /** 41 | * 根据用户ID查找所有关系记录 42 | * @param userId 43 | * @return 44 | */ 45 | List findAllByUserId(Integer userId); 46 | 47 | /** 48 | * 根据帖子ID查找所有关系记录 49 | * @param postId 50 | * @return 51 | */ 52 | List findAllByPostId(Integer postId); 53 | 54 | /** 55 | * 根据帖子ID和关系类型统计数量 56 | * @param postId 57 | * @param relationType 58 | * @return 59 | */ 60 | int countByPostIdAndRelationType(Integer postId, Integer relationType); 61 | 62 | /** 63 | * 根据用户ID查询该用户的帖子被点赞的总数(使用原生SQL) 64 | * @param userId 65 | * @return 66 | */ 67 | @Query(value = 68 | "SELECT COUNT(*) AS COUNT FROM nicefish_cms_user_post_relation r " + 69 | "LEFT OUTER JOIN nicefish_cms_post p ON r.post_id = p.post_id " + 70 | "WHERE r.relation_type=1 AND p.user_id = :userId", nativeQuery = true) 71 | int countLikesForUserPosts(@Param("userId") Integer userId); 72 | 73 | /** 74 | * 根据 userId 查找此用户收藏或者点赞的所有帖子 75 | * TODO:分页 76 | * @param userId 77 | * @param relationType 78 | * @return 79 | */ 80 | @Query("SELECT p FROM UserPostRelationEntity upr JOIN PostEntity p ON upr.postId = p.postId WHERE upr.userId = :userId AND upr.relationType = :relationType") 81 | List findUserRelatedPosts(@Param("userId") Integer userId, @Param("relationType") Integer relationType); 82 | } -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/config/CaptchaConfig.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.config; 2 | 3 | import com.google.code.kaptcha.impl.DefaultKaptcha; 4 | import com.google.code.kaptcha.util.Config; 5 | import com.google.code.kaptcha.impl.NoNoise; 6 | import com.google.code.kaptcha.impl.ShadowGimpy; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | 10 | import java.util.Properties; 11 | import com.nicefish.rbac.util.KaptchaTextCreator; 12 | 13 | import static com.google.code.kaptcha.Constants.*; 14 | 15 | /** 16 | * @author 大漠穷秋 17 | */ 18 | @Configuration 19 | public class CaptchaConfig { 20 | @Bean(name = "captchaProducer") 21 | public DefaultKaptcha getKaptchaBean() { 22 | DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); 23 | Properties properties = new Properties(); 24 | properties.setProperty(KAPTCHA_BORDER, "yes"); 25 | properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black"); 26 | properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160"); 27 | properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60"); 28 | properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "38"); 29 | properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCode"); 30 | properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4"); 31 | properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier"); 32 | properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, ShadowGimpy.class.getName()); 33 | Config config = new Config(properties); 34 | defaultKaptcha.setConfig(config); 35 | return defaultKaptcha; 36 | } 37 | 38 | @Bean(name = "captchaProducerMath") 39 | public DefaultKaptcha getKaptchaBeanMath() { 40 | DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); 41 | Properties properties = new Properties(); 42 | properties.setProperty(KAPTCHA_BORDER, "yes"); 43 | properties.setProperty(KAPTCHA_BORDER_COLOR, "105,179,90"); 44 | properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue"); 45 | properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160"); 46 | properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60"); 47 | properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "35"); 48 | properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCodeMath"); 49 | properties.setProperty(KAPTCHA_TEXTPRODUCER_IMPL, KaptchaTextCreator.class.getName()); 50 | properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "3"); 51 | properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "6"); 52 | properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier"); 53 | properties.setProperty(KAPTCHA_NOISE_COLOR, "white"); 54 | properties.setProperty(KAPTCHA_NOISE_IMPL, NoNoise.class.getName()); 55 | properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, ShadowGimpy.class.getName()); 56 | Config config = new Config(properties); 57 | defaultKaptcha.setConfig(config); 58 | return defaultKaptcha; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /nicefish-cms/src/main/java/com/nicefish/cms/service/impl/UserPostRelationServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.cms.service.impl; 2 | 3 | import com.nicefish.cms.jpa.entity.PostEntity; 4 | import com.nicefish.cms.jpa.entity.UserPostRelationEntity; 5 | import com.nicefish.cms.jpa.repository.IUserPostRelationRepository; 6 | import com.nicefish.cms.service.IUserPostRelationService; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Service; 9 | 10 | import java.util.List; 11 | 12 | @Service 13 | public class UserPostRelationServiceImpl implements IUserPostRelationService { 14 | 15 | private final IUserPostRelationRepository userPostRelationRepository; 16 | 17 | @Autowired 18 | public UserPostRelationServiceImpl(IUserPostRelationRepository userPostRelationRepository) { 19 | this.userPostRelationRepository = userPostRelationRepository; 20 | } 21 | 22 | @Override 23 | public void saveUserPostRelation(UserPostRelationEntity userPostRelation) { 24 | userPostRelationRepository.save(userPostRelation); 25 | } 26 | 27 | @Override 28 | public UserPostRelationEntity findByUserIdAndPostId(Integer userId, Integer postId) { 29 | return userPostRelationRepository.findByUserIdAndPostId(userId, postId); 30 | } 31 | 32 | @Override 33 | public List findAllByUserId(Integer userId) { 34 | return userPostRelationRepository.findAllByUserId(userId); 35 | } 36 | 37 | /** 38 | * 根据 userId 查找此用户收藏或者点赞的所有帖子 39 | * TODO:分页 40 | * 41 | * @param userId 42 | * @param relationType 43 | * 44 | * @return 45 | */ 46 | @Override 47 | public List findUserRelatedPosts(Integer userId, Integer relationType) { 48 | return userPostRelationRepository.findUserRelatedPosts(userId,relationType); 49 | } 50 | 51 | @Override 52 | public List findAllByPostId(Integer postId) { 53 | return userPostRelationRepository.findAllByPostId(postId); 54 | } 55 | 56 | @Override 57 | public int countByPostIdAndRelationType(Integer postId, Integer relationType) { 58 | return userPostRelationRepository.countByPostIdAndRelationType(postId, relationType); 59 | } 60 | 61 | @Override 62 | public int countLikesForUserPosts(Integer userId) { 63 | return userPostRelationRepository.countLikesForUserPosts(userId); 64 | } 65 | 66 | @Override 67 | public boolean existsRelation(UserPostRelationEntity userPostRelationEntity) { 68 | return userPostRelationRepository.existsByUserIdAndPostIdAndRelationType( 69 | userPostRelationEntity.getUserId(), 70 | userPostRelationEntity.getPostId(), 71 | userPostRelationEntity.getRelationType() 72 | ); 73 | } 74 | 75 | @Override 76 | public void deleteUserPostRelation(UserPostRelationEntity userPostRelation) { 77 | UserPostRelationEntity temp = userPostRelationRepository.findByUserIdAndPostIdAndRelationType( 78 | userPostRelation.getUserId(), 79 | userPostRelation.getPostId(), 80 | userPostRelation.getRelationType() 81 | ); 82 | 83 | if (temp != null) { 84 | userPostRelationRepository.delete(temp); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /nicefish-cms/src/main/java/com/nicefish/cms/controller/CommentController.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.cms.controller; 2 | 3 | import com.nicefish.cms.jpa.entity.CommentEntity; 4 | import com.nicefish.cms.service.ICommentService; 5 | import com.nicefish.core.utils.AjaxResult; 6 | import com.nicefish.rbac.jpa.entity.UserEntity; 7 | import com.nicefish.rbac.shiro.util.NiceFishSecurityUtils; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.data.domain.Page; 10 | import org.springframework.data.domain.PageRequest; 11 | import org.springframework.data.domain.Pageable; 12 | import org.springframework.data.domain.Sort; 13 | import org.springframework.web.bind.annotation.*; 14 | 15 | /** 16 | * @author 大漠穷秋 17 | */ 18 | @RestController 19 | @RequestMapping("/nicefish/cms/comment") 20 | public class CommentController { 21 | @Autowired 22 | private ICommentService commentService; 23 | 24 | //TODO:每页显示的条数改为系统配置项 25 | @RequestMapping(value = "/post-id/{postId}/page/{page}", method = RequestMethod.GET) 26 | public Page getCommentList(@PathVariable(value="postId",required = true) Integer postId, @PathVariable(value="page",required = true) Integer page) { 27 | PageRequest pageRequest= PageRequest.of(page-1,10, Sort.by(Sort.Direction.DESC,"id")); 28 | return commentService.findByPostId(postId,pageRequest); 29 | } 30 | 31 | @RequestMapping(value="/write-comment",method = RequestMethod.POST) 32 | public AjaxResult writeComment(@RequestBody CommentEntity commentEntity){ 33 | UserEntity user= NiceFishSecurityUtils.getUserEntity(); 34 | commentEntity.setUserId(user.getUserId()); 35 | commentEntity.setUserName(user.getUserName()); 36 | commentEntity.setNickName(user.getNickName()); 37 | commentEntity=commentService.saveComment(commentEntity); 38 | return AjaxResult.success(commentEntity); 39 | } 40 | 41 | //TODO:管理员用户不过滤ID,获取全部文章并分页 42 | @RequestMapping(value = "/manage/comment-table/{page}", method = RequestMethod.GET) 43 | public Page getCommentListByUserId(@PathVariable(value="page",required = true) Integer page) { 44 | Pageable pageable= PageRequest.of(page-1,10); 45 | Integer userId= NiceFishSecurityUtils.getUserId(); 46 | return this.commentService.findAllByUserIdAndPaging(userId,pageable); 47 | } 48 | 49 | @RequestMapping(value = "/manage/delete/{commentId}",method = RequestMethod.DELETE) 50 | public AjaxResult deleteByCommentId(@PathVariable(value="commentId",required = true) Integer commentId){ 51 | commentService.deleteById(commentId); 52 | return AjaxResult.success(); 53 | } 54 | 55 | @RequestMapping(value = "/manage/delete-by-post-id/{postId}",method = RequestMethod.DELETE) 56 | public AjaxResult deletetByPostId(@PathVariable(value="postId",required = true) Integer postId){ 57 | Integer affected=commentService.deletetByPostId(postId); 58 | return AjaxResult.success(affected); 59 | } 60 | 61 | @RequestMapping(value = "/manage/delete-by-user-id/{userId}",method = RequestMethod.DELETE) 62 | public AjaxResult deletetByUserId(@PathVariable(value="userId",required = true) Integer userId){ 63 | Integer affected=commentService.deleteByUserId(userId); 64 | return AjaxResult.success(affected); 65 | } 66 | } -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/shiro/filter/NiceFishCaptchaValidateFilter.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.shiro.filter; 2 | 3 | import com.google.code.kaptcha.Constants; 4 | import com.nicefish.rbac.constant.AuthConstants; 5 | import com.nicefish.rbac.shiro.util.NiceFishSecurityUtils; 6 | import org.apache.shiro.web.filter.AccessControlFilter; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import jakarta.servlet.ServletRequest; 11 | import jakarta.servlet.ServletResponse; 12 | import jakarta.servlet.http.HttpServletRequest; 13 | 14 | /** 15 | * 验证码 16 | * @author 大漠穷秋 17 | */ 18 | public class NiceFishCaptchaValidateFilter extends AccessControlFilter { 19 | private static final Logger logger = LoggerFactory.getLogger(NiceFishCaptchaValidateFilter.class); 20 | 21 | private boolean captchaEnabled = true; 22 | 23 | private String captchaType = "math"; 24 | 25 | @Override 26 | public boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception { 27 | request.setAttribute(AuthConstants.CURRENT_ENABLED, captchaEnabled); 28 | request.setAttribute(AuthConstants.CURRENT_TYPE, captchaType); 29 | return super.onPreHandle(request, response, mappedValue); 30 | } 31 | 32 | @Override 33 | protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) { 34 | if (!this.captchaEnabled) return true; 35 | HttpServletRequest httpReq = (HttpServletRequest) request; 36 | String code = (String)NiceFishSecurityUtils.getSession().getAttribute(Constants.KAPTCHA_SESSION_KEY); 37 | String validateCode=httpReq.getParameter(AuthConstants.CURRENT_VALIDATECODE); 38 | 39 | //TODO:这里需要 fix 一下,处理 post 请求里面的 captcha 参数,否则会影响前端传递参数的方式。 40 | // try{ 41 | // if("GET".equals(httpReq.getMethod())){ 42 | // validateCode=httpReq.getParameter(AuthConstants.CURRENT_VALIDATECODE); 43 | // }else if("POST".equals(httpReq.getMethod())){ 44 | // String jsonParams=httpReq.getReader().lines().collect(Collectors.joining(System.lineSeparator())); 45 | // ObjectMapper mapper = new ObjectMapper(); 46 | // JsonNode actualObj = mapper.readTree(jsonParams); 47 | // code= String.valueOf(actualObj.get("captcha")); 48 | // } 49 | // }catch (Exception e){ 50 | // logger.error(e.getMessage()); 51 | // } 52 | 53 | if (!code.equalsIgnoreCase(validateCode)) { 54 | return false; 55 | } 56 | return true; 57 | } 58 | 59 | @Override 60 | protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { 61 | request.setAttribute(AuthConstants.CURRENT_CAPTCHA, AuthConstants.CAPTCHA_ERROR); 62 | return true; 63 | } 64 | 65 | public boolean isCaptchaEnabled() { 66 | return captchaEnabled; 67 | } 68 | 69 | public void setCaptchaEnabled(boolean captchaEnabled) { 70 | this.captchaEnabled = captchaEnabled; 71 | } 72 | 73 | public String getCaptchaType() { 74 | return captchaType; 75 | } 76 | 77 | public void setCaptchaType(String captchaType) { 78 | this.captchaType = captchaType; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /nicefish-elastic-search/src/main/java/com/nicefish/search/entity/PostSearchEntity.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.search.entity; 2 | 3 | import org.springframework.data.annotation.Id; 4 | import org.springframework.data.elasticsearch.annotations.Document; 5 | import org.springframework.data.elasticsearch.annotations.Field; 6 | import org.springframework.data.elasticsearch.annotations.FieldType; 7 | 8 | import java.io.Serializable; 9 | 10 | /** 11 | * 这里的 nicefish_cms_post 是索引名称,与库表同名。 12 | * @author 大漠穷秋 13 | */ 14 | @Document(indexName = "nicefish_cms_post") 15 | public class PostSearchEntity implements Serializable { 16 | @Id 17 | @Field(name = "post_id") 18 | private String postId; 19 | 20 | @Field(name = "thumb_img_url") 21 | private String thumbImgUrl; 22 | 23 | @Field(name = "header_img_url") 24 | private String headerImgUrl; 25 | 26 | //TODO:需要在 ES 中配置 IK 分词器来支持中文分词 27 | @Field(name="post_title",type = FieldType.Text, analyzer = "ik_max_word") 28 | private String title; 29 | 30 | //TODO:需要在 ES 中配置 IK 分词器来支持中文分词 31 | @Field(name="post_content",type = FieldType.Text, analyzer = "ik_max_word") 32 | private String content; 33 | 34 | //TODO:需要在 ES 中配置 IK 分词器来支持中文分词 35 | @Field(name="post_summary",type = FieldType.Text, analyzer = "ik_max_word") 36 | private String summary; 37 | 38 | @Field(name="user_id") 39 | private Integer userId; 40 | 41 | @Field(name="email",type = FieldType.Text, analyzer = "ik_max_word") 42 | private String email; 43 | 44 | @Field(name="nick_name",type = FieldType.Text, analyzer = "ik_max_word") 45 | private String nickName; 46 | 47 | public String getPostId() { 48 | return postId; 49 | } 50 | 51 | public void setPostId(String postId) { 52 | this.postId = postId; 53 | } 54 | 55 | public String getThumbImgUrl() { 56 | return thumbImgUrl; 57 | } 58 | 59 | public void setThumbImgUrl(String thumbImgUrl) { 60 | this.thumbImgUrl = thumbImgUrl; 61 | } 62 | 63 | public String getHeaderImgUrl() { 64 | return headerImgUrl; 65 | } 66 | 67 | public void setHeaderImgUrl(String headerImgUrl) { 68 | this.headerImgUrl = headerImgUrl; 69 | } 70 | 71 | public String getTitle() { 72 | return title; 73 | } 74 | 75 | public void setTitle(String title) { 76 | this.title = title; 77 | } 78 | 79 | public String getContent() { 80 | return content; 81 | } 82 | 83 | public void setContent(String content) { 84 | this.content = content; 85 | } 86 | 87 | public String getSummary() { 88 | return summary; 89 | } 90 | 91 | public void setSummary(String summary) { 92 | this.summary = summary; 93 | } 94 | 95 | public Integer getUserId() { 96 | return userId; 97 | } 98 | 99 | public void setUserId(Integer userId) { 100 | this.userId = userId; 101 | } 102 | 103 | public String getEmail() { 104 | return email; 105 | } 106 | 107 | public void setEmail(String email) { 108 | this.email = email; 109 | } 110 | 111 | public String getNickName() { 112 | return nickName; 113 | } 114 | 115 | public void setNickName(String nickName) { 116 | this.nickName = nickName; 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /nicefish-elastic-search/src/main/java/com/nicefish/search/entity/UserSearchEntity.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.search.entity; 2 | 3 | import org.springframework.data.annotation.Id; 4 | import org.springframework.data.elasticsearch.annotations.Document; 5 | import org.springframework.data.elasticsearch.annotations.Field; 6 | 7 | import java.io.Serializable; 8 | 9 | /** 10 | * 这里的 nicefish_rbac_user 是索引名称,与库表同名。 11 | * @author 大漠穷秋 12 | */ 13 | @Document(indexName = "nicefish_rbac_user") 14 | public class UserSearchEntity implements Serializable { 15 | @Id 16 | @Field("user_id") 17 | private Integer userId; 18 | 19 | @Field("user_name") 20 | private String userName; 21 | 22 | @Field("nick_name") 23 | private String nickName; 24 | 25 | @Field(name="email") 26 | private String email; 27 | 28 | @Field(name="cellphone") 29 | private String cellphone; 30 | 31 | @Field(name="gender") 32 | private Integer gender=0; 33 | 34 | @Field(name="city") 35 | private String city; 36 | 37 | @Field(name="education") 38 | private String education; 39 | 40 | @Field(name="avatar_url") 41 | private String avatarURL; 42 | 43 | @Field(name="status") 44 | private Integer status=0; 45 | 46 | @Field(name="remark") 47 | private String remark; 48 | 49 | public Integer getUserId() { 50 | return userId; 51 | } 52 | 53 | public void setUserId(Integer userId) { 54 | this.userId = userId; 55 | } 56 | 57 | public String getUserName() { 58 | return userName; 59 | } 60 | 61 | public void setUserName(String userName) { 62 | this.userName = userName; 63 | } 64 | 65 | public String getNickName() { 66 | return nickName; 67 | } 68 | 69 | public void setNickName(String nickName) { 70 | this.nickName = nickName; 71 | } 72 | 73 | public String getEmail() { 74 | return email; 75 | } 76 | 77 | public void setEmail(String email) { 78 | this.email = email; 79 | } 80 | 81 | public String getCellphone() { 82 | return cellphone; 83 | } 84 | 85 | public void setCellphone(String cellphone) { 86 | this.cellphone = cellphone; 87 | } 88 | 89 | public Integer getGender() { 90 | return gender; 91 | } 92 | 93 | public void setGender(Integer gender) { 94 | this.gender = gender; 95 | } 96 | 97 | public String getCity() { 98 | return city; 99 | } 100 | 101 | public void setCity(String city) { 102 | this.city = city; 103 | } 104 | 105 | public String getEducation() { 106 | return education; 107 | } 108 | 109 | public void setEducation(String education) { 110 | this.education = education; 111 | } 112 | 113 | public String getAvatarURL() { 114 | return avatarURL; 115 | } 116 | 117 | public void setAvatarURL(String avatarURL) { 118 | this.avatarURL = avatarURL; 119 | } 120 | 121 | public Integer getStatus() { 122 | return status; 123 | } 124 | 125 | public void setStatus(Integer status) { 126 | this.status = status; 127 | } 128 | 129 | public String getRemark() { 130 | return remark; 131 | } 132 | 133 | public void setRemark(String remark) { 134 | this.remark = remark; 135 | } 136 | } -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/controller/ApiPermissionController.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.controller; 2 | 3 | import com.nicefish.core.utils.AjaxResult; 4 | import com.nicefish.rbac.jpa.entity.ApiPermissionEntity; 5 | import com.nicefish.rbac.jpa.entity.RoleEntity; 6 | import com.nicefish.rbac.service.IApiPermissionService; 7 | import org.apache.shiro.authz.annotation.RequiresPermissions; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.data.domain.Page; 12 | import org.springframework.data.domain.PageRequest; 13 | import org.springframework.data.domain.Pageable; 14 | import org.springframework.web.bind.annotation.*; 15 | 16 | /** 17 | * 服务端 API 权限管理 18 | * @author 大漠穷秋 19 | */ 20 | @RestController 21 | @RequestMapping("/nicefish/auth/api-permission") 22 | @RequiresPermissions("sys:manage:api-permission") 23 | public class ApiPermissionController { 24 | private static final Logger logger = LoggerFactory.getLogger(ApiPermissionController.class); 25 | 26 | @Autowired 27 | protected IApiPermissionService apiPermService; 28 | 29 | @PostMapping(value = "/list/{page}") 30 | @ResponseBody 31 | public Page getPermissionList(@RequestBody ApiPermissionEntity apiPermissionEntity, @PathVariable(value="page",required = true) int page) { 32 | Pageable pageable= PageRequest.of(page-1,10); 33 | Page permList = apiPermService.getPermListPaging(apiPermissionEntity,pageable); 34 | return permList; 35 | } 36 | 37 | @PostMapping(value = "/list-all") 38 | @ResponseBody 39 | public Iterable getPermissionListAll(@RequestBody ApiPermissionEntity apiPermissionEntity) { 40 | return apiPermService.getPermListAll(apiPermissionEntity); 41 | } 42 | 43 | @PostMapping(value = "/list-all-by-role") 44 | @ResponseBody 45 | public Iterable getPermissionListByRole(@RequestBody RoleEntity roleEntity) { 46 | return apiPermService.getPermListAllByRole(roleEntity); 47 | } 48 | 49 | @GetMapping(value = "/detail/{apiPermissionId}") 50 | @ResponseBody 51 | public AjaxResult getApiPermissionDetail(@PathVariable(value = "apiPermissionId",required = true) Integer apiPermissionId){ 52 | return AjaxResult.success(this.apiPermService.getApiPermissionById(apiPermissionId)); 53 | } 54 | 55 | @PostMapping(value = "/create") 56 | @ResponseBody 57 | public AjaxResult createApiPermission(@RequestBody ApiPermissionEntity apiPermissionEntity){ 58 | apiPermissionEntity=this.apiPermService.createApiPermission(apiPermissionEntity); 59 | return AjaxResult.success(apiPermissionEntity); 60 | } 61 | 62 | @PostMapping(value = "/update") 63 | @ResponseBody 64 | public AjaxResult updatePermission(@RequestBody ApiPermissionEntity apiPermissionEntity){ 65 | apiPermissionEntity=this.apiPermService.updatePermission(apiPermissionEntity); 66 | return AjaxResult.success(apiPermissionEntity); 67 | } 68 | 69 | @DeleteMapping(value = "/delete/{apiPermissionId}") 70 | @ResponseBody 71 | public AjaxResult deleteByApiId(@PathVariable(value="apiPermissionId",required = true)Integer apiPermissionId){ 72 | //TODO:数据校验,数据关联性测试 73 | this.apiPermService.deleteByApiId(apiPermissionId); 74 | return AjaxResult.success(); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /nicefish-cms/src/main/java/com/nicefish/cms/jpa/entity/CommentEntity.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.cms.jpa.entity; 2 | 3 | import com.fasterxml.jackson.annotation.JsonFormat; 4 | 5 | import jakarta.persistence.*; 6 | import java.io.Serializable; 7 | import java.util.Date; 8 | 9 | /** 10 | * @author 大漠穷秋 11 | * @version 创建时间:2018-12-31 17:00 12 | */ 13 | @Entity 14 | @Table(name="nicefish_cms_comment") 15 | public class CommentEntity implements Serializable { 16 | @Id 17 | @Column(name="comment_id") 18 | @GeneratedValue(strategy = GenerationType.IDENTITY) 19 | private Integer id; 20 | 21 | @Column(name="post_id") 22 | private Integer postId; 23 | 24 | @Lob 25 | @Column(name = "content",columnDefinition="text") 26 | private String content; 27 | 28 | @Temporal(TemporalType.TIMESTAMP) 29 | @Column(name = "comment_time") 30 | @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") 31 | private Date time=new Date(); 32 | 33 | @Column(name="comment_ip") 34 | private String ip; 35 | 36 | @Column(name="p_id") 37 | private Integer pId; 38 | 39 | @Column(name = "user_id") 40 | private Integer userId; 41 | 42 | @Column(name = "user_name") 43 | private String userName; 44 | 45 | @Column(name = "nick_name") 46 | private String nickName; 47 | 48 | @Column(name = "email") 49 | private String email; 50 | 51 | @Column(name = "status") 52 | private Integer status; 53 | 54 | public String getContent() { 55 | return content; 56 | } 57 | 58 | public void setContent(String content) { 59 | this.content = content; 60 | } 61 | 62 | public Date getTime() { 63 | return time; 64 | } 65 | 66 | public void setTime(Date time) { 67 | this.time = time; 68 | } 69 | 70 | public String getIp() { 71 | return ip; 72 | } 73 | 74 | public void setIp(String ip) { 75 | this.ip = ip; 76 | } 77 | 78 | public String getUserName() { 79 | return userName; 80 | } 81 | 82 | public void setUserName(String userName) { 83 | this.userName = userName; 84 | } 85 | 86 | public String getNickName() { 87 | return nickName; 88 | } 89 | 90 | public void setNickName(String nickName) { 91 | this.nickName = nickName; 92 | } 93 | 94 | public String getEmail() { 95 | return email; 96 | } 97 | 98 | public void setEmail(String email) { 99 | this.email = email; 100 | } 101 | 102 | public Integer getStatus() { 103 | return status; 104 | } 105 | 106 | public void setStatus(Integer status) { 107 | this.status = status; 108 | } 109 | 110 | public Integer getId() { 111 | return id; 112 | } 113 | 114 | public void setId(Integer id) { 115 | this.id = id; 116 | } 117 | 118 | public Integer getPostId() { 119 | return postId; 120 | } 121 | 122 | public void setPostId(Integer postId) { 123 | this.postId = postId; 124 | } 125 | 126 | public Integer getpId() { 127 | return pId; 128 | } 129 | 130 | public void setpId(Integer pId) { 131 | this.pId = pId; 132 | } 133 | 134 | public Integer getUserId() { 135 | return userId; 136 | } 137 | 138 | public void setUserId(Integer userId) { 139 | this.userId = userId; 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/controller/ComponentPermissionController.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.controller; 2 | 3 | import com.nicefish.core.utils.AjaxResult; 4 | import com.nicefish.rbac.jpa.entity.ComponentPermissionEntity; 5 | import com.nicefish.rbac.jpa.entity.RoleEntity; 6 | import com.nicefish.rbac.service.IComponentPermissionService; 7 | import org.apache.shiro.authz.annotation.RequiresPermissions; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.data.domain.Page; 12 | import org.springframework.data.domain.PageRequest; 13 | import org.springframework.data.domain.Pageable; 14 | import org.springframework.data.domain.Sort; 15 | import org.springframework.web.bind.annotation.*; 16 | 17 | /** 18 | * 前端页面组件权限管理 19 | * @author 大漠穷秋 20 | */ 21 | @RestController 22 | @RequestMapping("/nicefish/auth/component-permission") 23 | @RequiresPermissions("sys:manage:component-permission") 24 | public class ComponentPermissionController { 25 | private static final Logger logger = LoggerFactory.getLogger(ComponentPermissionController.class); 26 | 27 | @Autowired 28 | private IComponentPermissionService componentService; 29 | 30 | @PostMapping(value = "/list/{page}") 31 | @ResponseBody 32 | public Page getPermissionList(@RequestBody ComponentPermissionEntity componentPermissionEntity, @PathVariable(value="page",required = true) int page) { 33 | Pageable pageable= PageRequest.of(page-1,10,Sort.by(Sort.Direction.ASC,"displayOrder")); 34 | Page compoPermList = componentService.getComponentPermissionTree(componentPermissionEntity,pageable); 35 | logger.debug(compoPermList.toString()); 36 | return compoPermList; 37 | } 38 | 39 | @PostMapping(value = "/list-all-by-role") 40 | @ResponseBody 41 | public Iterable getPermissionListByRole(@RequestBody RoleEntity roleEntity) { 42 | return this.componentService.getPermListAllByRole(roleEntity); 43 | } 44 | 45 | @GetMapping(value = "/detail/{compPermId}") 46 | @ResponseBody 47 | public ComponentPermissionEntity getCompPermDetail(@PathVariable(value = "compPermId",required = true) Integer compPermId){ 48 | return this.componentService.getComponentPermissionDetail(compPermId); 49 | } 50 | 51 | @DeleteMapping(value = "/delete/{compPermId}") 52 | @ResponseBody 53 | public AjaxResult deleteComponentPermission(@PathVariable(value="compPermId",required = true)Integer compPermId){ 54 | int result=this.componentService.deleteComponentPermission(compPermId); 55 | if(result==0){ 56 | return AjaxResult.success(); 57 | }else{ 58 | return AjaxResult.failure(); 59 | } 60 | } 61 | 62 | @PostMapping(value = "/create") 63 | @ResponseBody 64 | public AjaxResult createComponentPermission(@RequestBody ComponentPermissionEntity componentPermission){ 65 | componentPermission=this.componentService.createComponentPermission(componentPermission); 66 | return AjaxResult.success(componentPermission); 67 | } 68 | 69 | @PostMapping(value = "/update") 70 | @ResponseBody 71 | public AjaxResult updateComponentPermission(@RequestBody ComponentPermissionEntity componentPermission){ 72 | componentPermission=this.componentService.updateComponentPermission(componentPermission); 73 | return AjaxResult.success(componentPermission); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /nicefish-cms/src/main/java/com/nicefish/cms/service/impl/PostServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.cms.service.impl; 2 | 3 | import com.nicefish.cms.jpa.entity.FileUploadEntity; 4 | import com.nicefish.cms.jpa.entity.PostEntity; 5 | import com.nicefish.cms.jpa.entity.PostFileUploadEntity; 6 | import com.nicefish.cms.jpa.repository.IPostFileUploadRepository; 7 | import com.nicefish.cms.jpa.repository.IPostRepository; 8 | import com.nicefish.cms.service.IPostService; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.cache.annotation.CacheEvict; 13 | import org.springframework.cache.annotation.Cacheable; 14 | import org.springframework.data.domain.Page; 15 | import org.springframework.data.domain.Pageable; 16 | import org.springframework.stereotype.Service; 17 | import org.springframework.util.ObjectUtils; 18 | 19 | import jakarta.transaction.Transactional; 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | 23 | 24 | @Transactional 25 | @Service 26 | public class PostServiceImpl implements IPostService { 27 | private static final Logger logger = LoggerFactory.getLogger(PostServiceImpl.class); 28 | 29 | @Autowired 30 | private IPostRepository postRepository; 31 | 32 | @Autowired 33 | private IPostFileUploadRepository postFileUploadRepository; 34 | 35 | @Override 36 | @Cacheable(value="posts",key ="T(String).valueOf(#pageable.pageNumber).concat('-').concat(#pageable.pageSize)", unless="#result==null") 37 | public Page getPostsPaging(Pageable pageable) { 38 | return postRepository.findAll(pageable); 39 | } 40 | 41 | @Override 42 | @Cacheable(value = "post-detail",key = "T(String).valueOf(#id)", unless="#result==null") 43 | public PostEntity getOne(Integer postId){ 44 | return this.postRepository.findDistinctByPostId(postId); 45 | } 46 | 47 | @Override 48 | @CacheEvict(value = "posts",allEntries = true) 49 | public PostEntity savePost(PostEntity postEntity) { 50 | //先尝试保存文章自身的内容 51 | PostEntity newPostEntity=postRepository.save(postEntity); 52 | 53 | //处理文章和图片,视频之间的关联关系,先删掉当前的关联关系,再插入新的关联关系。 54 | //NOTE:手动操作,不要自动级联,防止错误删除附件。 55 | postFileUploadRepository.deleteAllByPostId(newPostEntity.getPostId()); 56 | 57 | //取客户端传过来的文件列表 58 | List newFileUploadEntities=postEntity.getFileUploadEntities(); 59 | if(!ObjectUtils.isEmpty(newFileUploadEntities)){ 60 | List newPostFileUploadList=new ArrayList<>(); 61 | newFileUploadEntities.forEach(entity->{ 62 | PostFileUploadEntity newPf=new PostFileUploadEntity(); 63 | newPf.setPostId(newPostEntity.getPostId()); 64 | newPf.setUpId(entity.getId()); 65 | newPostFileUploadList.add(newPf); 66 | }); 67 | 68 | this.postFileUploadRepository.saveAll(newPostFileUploadList); 69 | logger.debug(newPostFileUploadList.toString()); 70 | newPostEntity.setFileUploadEntities(newFileUploadEntities); 71 | } 72 | return newPostEntity; 73 | } 74 | 75 | @Override 76 | @CacheEvict(value = "posts",allEntries = true) 77 | public Integer delPost(Integer postId) { 78 | return this.postRepository.deleteByPostId(postId); 79 | } 80 | 81 | /** 82 | * 根据 userId 查找此用户发表的内容列表,带分页 83 | * @param userId 84 | * @param pageable 85 | * @return 86 | */ 87 | @Override 88 | public Page getPostsByUserIdAndPaging(Integer userId,Pageable pageable) { 89 | return postRepository.findAllByUserId(userId,pageable); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /nicefish-cms/src/main/java/com/nicefish/cms/controller/PostController.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.cms.controller; 2 | 3 | import com.nicefish.cms.jpa.entity.PostEntity; 4 | import com.nicefish.cms.service.IPostService; 5 | import com.nicefish.core.utils.AjaxResult; 6 | import com.nicefish.rbac.shiro.util.NiceFishSecurityUtils; 7 | import jakarta.servlet.http.HttpServletRequest; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.data.domain.Page; 10 | import org.springframework.data.domain.PageRequest; 11 | import org.springframework.data.domain.Pageable; 12 | import org.springframework.data.domain.Sort; 13 | import org.springframework.web.bind.annotation.*; 14 | 15 | 16 | /** 17 | * @author 大漠穷秋 18 | */ 19 | @RestController 20 | @RequestMapping("/nicefish/cms/post") 21 | public class PostController { 22 | @Autowired 23 | private IPostService postService; 24 | 25 | //TODO:每页显示的条数改为系统配置项 26 | @RequestMapping(value = "/post-list/{page}/{rows}", method = RequestMethod.GET) 27 | public Page getPostList( 28 | @PathVariable(value="page",required = false) Integer page, 29 | @PathVariable(value="rows",required = false) Integer rows, 30 | HttpServletRequest request 31 | ) { 32 | //测试 request 的真实类型 33 | System.out.print(request); 34 | Pageable pageable= PageRequest.of(page-1,rows, Sort.by(Sort.Direction.DESC,"postId")); 35 | return postService.getPostsPaging(pageable); 36 | } 37 | 38 | @RequestMapping(value = "/post-detail/{postId}",method = RequestMethod.GET) 39 | public PostEntity getPostDetail(@PathVariable(value = "postId",required = true) Integer postId){ 40 | return postService.getOne(postId); 41 | } 42 | 43 | private PostEntity setUserInfoToPostEntity(PostEntity postEntity){ 44 | Integer userId= NiceFishSecurityUtils.getUserEntity().getUserId(); 45 | String nickName= NiceFishSecurityUtils.getUserEntity().getNickName(); 46 | String email= NiceFishSecurityUtils.getUserEntity().getEmail(); 47 | 48 | postEntity.setUserId(userId); 49 | postEntity.setNickName(nickName); 50 | postEntity.setEmail(email); 51 | return postEntity; 52 | } 53 | 54 | @RequestMapping(value = "/write-post",method = RequestMethod.POST) 55 | public PostEntity writePost(@RequestBody PostEntity postEntity){ 56 | this.setUserInfoToPostEntity(postEntity); 57 | return postService.savePost(postEntity); 58 | } 59 | 60 | @RequestMapping(value = "/update-post",method = RequestMethod.POST) 61 | public PostEntity updatePost(@RequestBody PostEntity postEntity){ 62 | this.setUserInfoToPostEntity(postEntity); 63 | return postService.savePost(postEntity); 64 | } 65 | 66 | /** 67 | * 根据 userId 查找此用户发表的内容列表,带分页 68 | * TODO:管理员用户不过滤ID,获取全部文章并分页 69 | * @return 70 | */ 71 | @RequestMapping(value = "/manage/post-table/{userId}/{page}", method = RequestMethod.GET) 72 | public Page getPostTableByUserId( 73 | @PathVariable(value="userId",required = true) Integer userId, 74 | @PathVariable(value="page",required = true) Integer page 75 | ) { 76 | Pageable pageable= PageRequest.of(page-1,10); 77 | return this.postService.getPostsByUserIdAndPaging(userId,pageable); 78 | } 79 | 80 | @RequestMapping(value = "/manage/del-post/{postId}",method = RequestMethod.DELETE) 81 | public AjaxResult delPostById(@PathVariable(value="postId",required = true) Integer postId){ 82 | Integer affected=postService.delPost(postId); 83 | return AjaxResult.success(affected); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/controller/CaptchaController.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.controller; 2 | 3 | import com.google.code.kaptcha.Constants; 4 | import com.google.code.kaptcha.Producer; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.stereotype.Controller; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | import org.springframework.web.servlet.ModelAndView; 11 | 12 | import jakarta.annotation.Resource; 13 | import javax.imageio.ImageIO; 14 | import jakarta.servlet.ServletOutputStream; 15 | import jakarta.servlet.http.HttpServletRequest; 16 | import jakarta.servlet.http.HttpServletResponse; 17 | import jakarta.servlet.http.HttpSession; 18 | import java.awt.image.BufferedImage; 19 | import java.io.IOException; 20 | 21 | /** 22 | * 验证码 23 | * TODO:这款验证码组件有点老,需要换一个更新一点的。 24 | * @author 大漠穷秋 25 | */ 26 | @Controller 27 | @RequestMapping("/nicefish/auth/captcha") 28 | public class CaptchaController { 29 | private static final Logger logger = LoggerFactory.getLogger(CaptchaController.class); 30 | 31 | //文本型验证码 32 | @Resource(name = "captchaProducer") 33 | private Producer captchaProducer; 34 | 35 | //数学计算型验证码 36 | @Resource(name = "captchaProducerMath") 37 | private Producer captchaProducerMath; 38 | 39 | /** 40 | * 获取验证码,有两种类型:math 或者 char 。 41 | * 获取验证码的请求默认开启 Session ,这个会话用来存储验证码结果,以便与用户输入的内容进行比对, 42 | * 后续的 /login 和其它操作都会复用这个 HttpSession 。 43 | * 在与 Shiro 整合时,这里获得的 Session 实例是被 Shiro 包装过的 ShiroHttpSession 类型。 44 | * @param request 45 | * @param response 46 | * @return 47 | */ 48 | @GetMapping(value = "/captchaImage") 49 | public ModelAndView getKaptchaImage(HttpServletRequest request, HttpServletResponse response) { 50 | ServletOutputStream out = null; 51 | try { 52 | HttpSession session = request.getSession(); 53 | response.setDateHeader("Expires", 0); 54 | response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate"); 55 | response.addHeader("Cache-Control", "post-check=0, pre-check=0"); 56 | response.setHeader("Pragma", "no-cache"); 57 | response.setContentType("image/jpeg"); 58 | 59 | String capStr = null; //验证码 60 | String capResult = null;//结果,会被存在 session 中 61 | BufferedImage bufferedImg = null; 62 | String type = request.getParameter("type"); 63 | if ("math".equals(type)) { 64 | String capText = captchaProducerMath.createText(); 65 | capStr = capText.substring(0, capText.lastIndexOf("@")); 66 | capResult = capText.substring(capText.lastIndexOf("@") + 1); 67 | bufferedImg = captchaProducerMath.createImage(capStr); 68 | } else if ("char".equals(type)) { 69 | capStr = capResult = captchaProducer.createText(); 70 | bufferedImg = captchaProducer.createImage(capStr); 71 | } 72 | 73 | session.setAttribute(Constants.KAPTCHA_SESSION_KEY, capResult); 74 | out = response.getOutputStream(); 75 | ImageIO.write(bufferedImg, "jpg", out); 76 | out.flush(); 77 | } catch (Exception e) { 78 | logger.debug(e.getMessage(),e); 79 | } finally { 80 | try { 81 | if (out != null) { 82 | out.close(); 83 | } 84 | } catch (IOException e) { 85 | logger.debug(e.getMessage(),e); 86 | } 87 | } 88 | return null; 89 | } 90 | } -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/service/impl/ApiPermissionServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.service.impl; 2 | 3 | 4 | import com.nicefish.rbac.jpa.entity.ApiPermissionEntity; 5 | import com.nicefish.rbac.jpa.entity.RoleEntity; 6 | import com.nicefish.rbac.jpa.repository.IApiPermissionRepository; 7 | import com.nicefish.rbac.service.IApiPermissionService; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | import org.springframework.beans.BeanUtils; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.data.domain.Page; 13 | import org.springframework.data.domain.Pageable; 14 | import org.springframework.data.domain.Sort; 15 | import org.springframework.data.jpa.domain.Specification; 16 | import org.springframework.stereotype.Service; 17 | import org.springframework.transaction.annotation.Transactional; 18 | import org.springframework.util.StringUtils; 19 | 20 | import jakarta.persistence.criteria.CriteriaBuilder; 21 | import jakarta.persistence.criteria.CriteriaQuery; 22 | import jakarta.persistence.criteria.Predicate; 23 | import jakarta.persistence.criteria.Root; 24 | import java.util.ArrayList; 25 | import java.util.List; 26 | 27 | /** 28 | * @author 大漠穷秋 29 | */ 30 | @Service 31 | public class ApiPermissionServiceImpl implements IApiPermissionService { 32 | private static final Logger logger = LoggerFactory.getLogger(ApiPermissionServiceImpl.class); 33 | 34 | @Autowired 35 | private IApiPermissionRepository apiPermRepository; 36 | 37 | @Override 38 | public Page getPermListPaging(ApiPermissionEntity permEntity, Pageable pageable) { 39 | return this.apiPermRepository.findAll(new Specification() { 40 | @Override 41 | public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) { 42 | List predicates=new ArrayList<>(); 43 | if(!StringUtils.isEmpty(permEntity.getApiName())){ 44 | predicates.add(criteriaBuilder.like(root.get("apiName"),"%"+permEntity.getApiName()+"%")); 45 | } 46 | return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()])); 47 | } 48 | },pageable); 49 | } 50 | 51 | @Override 52 | public Iterable getPermListAll(ApiPermissionEntity apiPermissionEntity) { 53 | return this.apiPermRepository.findAll(); 54 | } 55 | 56 | @Override 57 | public Iterable getPermListAllByRole(RoleEntity roleEntity) { 58 | List list=new ArrayList<>(); 59 | list.add(roleEntity); 60 | Iterable apiPermissionEntities=this.apiPermRepository.findAllByRoleEntitiesIn(list); 61 | return apiPermissionEntities; 62 | } 63 | 64 | @Override 65 | public ApiPermissionEntity createApiPermission(ApiPermissionEntity permEntity) { 66 | return this.apiPermRepository.save(permEntity); 67 | } 68 | 69 | @Override 70 | public ApiPermissionEntity updatePermission(ApiPermissionEntity permEntity) { 71 | //TODO:数据校验 72 | ApiPermissionEntity permEntityDB=this.apiPermRepository.findDistinctByApiPermissionId(permEntity.getApiPermissionId()); 73 | BeanUtils.copyProperties(permEntity,permEntityDB); 74 | this.apiPermRepository.save(permEntity); 75 | return permEntity; 76 | } 77 | 78 | @Override 79 | public ApiPermissionEntity getApiPermissionById(Integer apiPermissionId) { 80 | return this.apiPermRepository.findDistinctByApiPermissionId(apiPermissionId); 81 | } 82 | 83 | @Override 84 | @Transactional 85 | public int deleteByApiId(Integer apiPermissionId) { 86 | return this.apiPermRepository.deleteByApiPermissionId(apiPermissionId); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /nicefish-cms/src/main/java/com/nicefish/cms/controller/UserPostRelationController.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.cms.controller; 2 | 3 | import com.nicefish.cms.jpa.entity.PostEntity; 4 | import com.nicefish.cms.jpa.entity.UserPostRelationEntity; 5 | import com.nicefish.cms.service.IUserPostRelationService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.web.bind.annotation.*; 8 | 9 | import java.util.List; 10 | 11 | @RestController 12 | @RequestMapping("/nicefish/cms/user-post-relation") 13 | public class UserPostRelationController { 14 | 15 | private final IUserPostRelationService userPostRelationService; 16 | 17 | @Autowired 18 | public UserPostRelationController(IUserPostRelationService userPostRelationService) { 19 | this.userPostRelationService = userPostRelationService; 20 | } 21 | 22 | /** 23 | * 根据用户ID和帖子ID查找关系记录 24 | */ 25 | @GetMapping("/find-by-user-id-and-post-id/{userId}/{postId}") 26 | public UserPostRelationEntity findByUserIdAndPostId(@PathVariable Integer userId, @PathVariable Integer postId) { 27 | return userPostRelationService.findByUserIdAndPostId(userId, postId); 28 | } 29 | 30 | /** 31 | * 根据用户ID查找所有关系记录 32 | */ 33 | @GetMapping("/find-all-by-user-id/{userId}") 34 | public List findAllByUserId(@PathVariable Integer userId) { 35 | return userPostRelationService.findAllByUserId(userId); 36 | } 37 | 38 | /** 39 | * 根据帖子ID查找所有关系记录 40 | */ 41 | @GetMapping("/find-all-by-post-id/{postId}") 42 | public List findAllByPostId(@PathVariable Integer postId) { 43 | return userPostRelationService.findAllByPostId(postId); 44 | } 45 | 46 | /** 47 | * 根据帖子ID统计点赞数量 48 | */ 49 | @GetMapping("/count-likes/{postId}") 50 | public int countLikesByPostId(@PathVariable Integer postId) { 51 | return userPostRelationService.countByPostIdAndRelationType(postId, 1); // 1 表示喜欢 52 | } 53 | 54 | /** 55 | * 根据帖子ID统计收藏数量 56 | */ 57 | @GetMapping("/count-favorites/{postId}") 58 | public int countFavoritesByPostId(@PathVariable Integer postId) { 59 | return userPostRelationService.countByPostIdAndRelationType(postId, 2); // 2 表示收藏 60 | } 61 | 62 | /** 63 | * 根据用户ID查询该用户的帖子被点赞的总数 64 | */ 65 | @GetMapping("/count-likes-for-user-posts/{userId}") 66 | public int countLikesForUserPosts(@PathVariable Integer userId) { 67 | return userPostRelationService.countLikesForUserPosts(userId); 68 | } 69 | 70 | /** 71 | * 判断用户与内容之间是否存在喜欢、收藏关系 72 | * @param userPostRelationEntity 73 | * @return 74 | */ 75 | @PostMapping("/exists-relation") 76 | public boolean existsRelation(@RequestBody UserPostRelationEntity userPostRelationEntity){ 77 | return userPostRelationService.existsRelation(userPostRelationEntity); 78 | } 79 | 80 | /** 81 | * 保存用户与帖子之间的关系 82 | */ 83 | @PostMapping("/save-relation") 84 | public void saveUserPostRelation(@RequestBody UserPostRelationEntity userPostRelation) { 85 | userPostRelationService.saveUserPostRelation(userPostRelation); 86 | } 87 | 88 | /** 89 | * 删除用户与帖子之间的关系 90 | */ 91 | @DeleteMapping("/delete-relation") 92 | public void deleteUserPostRelation(@RequestBody UserPostRelationEntity userPostRelation) { 93 | userPostRelationService.deleteUserPostRelation(userPostRelation); 94 | } 95 | 96 | /** 97 | * 根据用户ID查询该用户点赞或者收藏的帖子列表 98 | */ 99 | @PostMapping("/find-user-related-posts") 100 | public List findUserRelatedPosts(@RequestBody UserPostRelationEntity userPostRelation) { 101 | return userPostRelationService.findUserRelatedPosts(userPostRelation.getUserId(),userPostRelation.getRelationType()); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/jpa/entity/ApiPermissionEntity.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.jpa.entity; 2 | 3 | import com.fasterxml.jackson.annotation.JsonFormat; 4 | import com.fasterxml.jackson.databind.annotation.JsonSerialize; 5 | import com.nicefish.rbac.jpautils.RoleListSerializer; 6 | import org.hibernate.annotations.DynamicInsert; 7 | import org.hibernate.annotations.DynamicUpdate; 8 | 9 | import jakarta.persistence.*; 10 | import java.io.Serializable; 11 | import java.util.Date; 12 | import java.util.List; 13 | 14 | /** 15 | * 在 NiceFish 中,权限控制整体上分2个层次:前端权限和后端权限。 16 | * - 前端权限是指在前端页面上的权限控制,比如菜单、按钮、甚至可以细致到一个 HTML 元素。 17 | * - 后端权限是指在后端 API 接口上的权限控制,比如一个 API 接口是否需要登录才能访问,是否需要某个角色才能访问,是否需要某个权限才能访问等。 18 | * 19 | * ApiPermissionEntity 用来定义服务端 API 接口的权限,对应数据库中的 nicefish_rbac_api 表。 20 | * 需要被保护的服务端 API 接口使用此 Entity 进行权限定义,不需要保护的接口由业务代码自行处理。 21 | * 22 | * @see ComponentPermissionEntity 23 | * @author 大漠穷秋 24 | */ 25 | @Entity 26 | @DynamicInsert 27 | @DynamicUpdate 28 | @Table(name = "nicefish_rbac_api") 29 | public class ApiPermissionEntity implements Serializable { 30 | @Id 31 | @GeneratedValue(strategy = GenerationType.IDENTITY) 32 | @Column(name="api_id") 33 | private Integer apiPermissionId; 34 | 35 | @Column(name="api_name") 36 | private String apiName; 37 | 38 | @Column(name="url") 39 | private String url; 40 | 41 | @Column(name="permission") 42 | private String permission; 43 | 44 | @Temporal(TemporalType.TIMESTAMP) 45 | @Column(name="create_time",updatable = false) 46 | @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") 47 | private Date createTime=new Date(); 48 | 49 | @Temporal(TemporalType.TIMESTAMP) 50 | @Column(name="update_time") 51 | @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") 52 | private Date updateTime=new Date(); 53 | 54 | @Column(name="remark") 55 | private String remark; 56 | 57 | @JoinTable( 58 | name="nicefish_rbac_role_api", 59 | joinColumns={@JoinColumn(name="api_id",referencedColumnName="api_id")}, 60 | inverseJoinColumns={@JoinColumn(name="role_id",referencedColumnName="role_id")} 61 | ) 62 | @ManyToMany(fetch = FetchType.LAZY) 63 | @JsonSerialize(using = RoleListSerializer.class) 64 | private List roleEntities; 65 | 66 | public List getRoleEntities() { 67 | return roleEntities; 68 | } 69 | 70 | public void setRoleEntities(List roleEntities) { 71 | this.roleEntities = roleEntities; 72 | } 73 | 74 | public Integer getApiPermissionId() { 75 | return apiPermissionId; 76 | } 77 | 78 | public void setApiPermissionId(Integer apiPermissionId) { 79 | this.apiPermissionId = apiPermissionId; 80 | } 81 | 82 | public String getApiName() { 83 | return apiName; 84 | } 85 | 86 | public void setApiName(String apiName) { 87 | this.apiName = apiName; 88 | } 89 | 90 | public String getUrl() { 91 | return url; 92 | } 93 | 94 | public void setUrl(String url) { 95 | this.url = url; 96 | } 97 | 98 | public String getPermission() { 99 | return permission; 100 | } 101 | 102 | public void setPermission(String permission) { 103 | this.permission = permission; 104 | } 105 | 106 | public Date getCreateTime() { 107 | return createTime; 108 | } 109 | 110 | public void setCreateTime(Date createTime) { 111 | this.createTime = createTime; 112 | } 113 | 114 | public Date getUpdateTime() { 115 | return updateTime; 116 | } 117 | 118 | public void setUpdateTime(Date updateTime) { 119 | this.updateTime = updateTime; 120 | } 121 | 122 | public String getRemark() { 123 | return remark; 124 | } 125 | 126 | public void setRemark(String remark) { 127 | this.remark = remark; 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /nicefish-cms/src/main/java/com/nicefish/cms/jpa/entity/FileUploadEntity.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.cms.jpa.entity; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | 5 | import jakarta.persistence.*; 6 | import java.io.Serializable; 7 | import java.util.Date; 8 | 9 | @Entity 10 | @Table(name = "nicefish_cms_file_upload") 11 | public class FileUploadEntity implements Serializable { 12 | @Id 13 | @Column(name="id") 14 | @GeneratedValue(strategy = GenerationType.IDENTITY) 15 | private Integer id; 16 | 17 | //实际存储用的文件名,一般是哈希字符串 18 | @Column(name = "file_name") 19 | private String fileName; 20 | 21 | //显示给用户的名称 22 | @Column(name = "display_name") 23 | private String displayName; 24 | 25 | //文件后缀 26 | @Column(name = "fileSuffix") 27 | private String fileSuffix; 28 | 29 | //文件的大小 30 | @Column(name = "file_size") 31 | private Long fileSize; 32 | 33 | //文件的存储路径,可以是本地磁盘上的路径,也可以是网络上的存储路径 34 | @Column(name = "path") 35 | private String path; 36 | 37 | @Column(name = "url") 38 | private String url; 39 | 40 | @Column(name = "file_desc") 41 | private String fileDesc; 42 | 43 | @Column(name = "display_order",columnDefinition = "int default 1") 44 | private Integer displayOrder=1; 45 | 46 | @Column(name = "up_time") 47 | private Date upTime=new Date(); 48 | 49 | //上传此文件的用户 id ,用户必须登录才能上传文件 50 | @Column(name = "user_id") 51 | private Integer userId; 52 | 53 | @JoinTable( 54 | name="nicefish_cms_post_file_upload", 55 | joinColumns={@JoinColumn(name="up_id",referencedColumnName="id")}, 56 | inverseJoinColumns={@JoinColumn(name="post_id",referencedColumnName="post_id")} 57 | ) 58 | @ManyToOne(fetch = FetchType.LAZY) 59 | @JsonIgnore //防止 Jackson 因为循环依赖导致转 JSON 字符串时 stackoverflow 60 | private PostEntity postEntity; 61 | 62 | public Integer getId() { 63 | return id; 64 | } 65 | 66 | public void setId(Integer id) { 67 | this.id = id; 68 | } 69 | 70 | public String getFileName() { 71 | return fileName; 72 | } 73 | 74 | public void setFileName(String fileName) { 75 | this.fileName = fileName; 76 | } 77 | 78 | public String getDisplayName() { 79 | return displayName; 80 | } 81 | 82 | public void setDisplayName(String displayName) { 83 | this.displayName = displayName; 84 | } 85 | 86 | public String getFileSuffix() { 87 | return fileSuffix; 88 | } 89 | 90 | public void setFileSuffix(String fileSuffix) { 91 | this.fileSuffix = fileSuffix; 92 | } 93 | 94 | public Long getFileSize() { 95 | return fileSize; 96 | } 97 | 98 | public void setFileSize(Long fileSize) { 99 | this.fileSize = fileSize; 100 | } 101 | 102 | public String getPath() { 103 | return path; 104 | } 105 | 106 | public void setPath(String path) { 107 | this.path = path; 108 | } 109 | 110 | public String getUrl() { 111 | return url; 112 | } 113 | 114 | public void setUrl(String url) { 115 | this.url = url; 116 | } 117 | 118 | public String getFileDesc() { 119 | return fileDesc; 120 | } 121 | 122 | public void setFileDesc(String fileDesc) { 123 | this.fileDesc = fileDesc; 124 | } 125 | 126 | public Date getUpTime() { 127 | return upTime; 128 | } 129 | 130 | public Integer getDisplayOrder() { 131 | return displayOrder; 132 | } 133 | 134 | public void setDisplayOrder(Integer displayOrder) { 135 | this.displayOrder = displayOrder; 136 | } 137 | 138 | public void setUpTime(Date upTime) { 139 | this.upTime = upTime; 140 | } 141 | 142 | public Integer getUserId() { 143 | return userId; 144 | } 145 | 146 | public void setUserId(Integer userId) { 147 | this.userId = userId; 148 | } 149 | 150 | public PostEntity getPostEntity() { 151 | return postEntity; 152 | } 153 | 154 | public void setPostEntity(PostEntity postEntity) { 155 | this.postEntity = postEntity; 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /nicefish-shiro-rbac/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | nicefish-spring-boot 5 | com.nicefish 6 | 1.1-SNAPSHOT 7 | 8 | 4.0.0 9 | 10 | nicefish-shiro-rbac 11 | nicefish-shiro-rbac 12 | 1.1-SNAPSHOT 13 | 基于 Apache Shiro 的 RBAC 权限管理模块 14 | 15 | 16 | 17 | com.nicefish 18 | nicefish-core 19 | ${nicefish.version} 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-web 25 | 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-data-jpa 30 | 31 | 32 | 33 | com.github.penggle 34 | kaptcha 35 | 36 | 37 | javax.servlet 38 | javax.servlet-api 39 | 40 | 41 | 42 | 43 | 44 | eu.bitwalker 45 | UserAgentUtils 46 | 47 | 48 | 49 | org.apache.commons 50 | commons-lang3 51 | 52 | 53 | 54 | com.fasterxml.jackson.core 55 | jackson-databind 56 | 57 | 58 | 59 | commons-fileupload 60 | commons-fileupload 61 | 62 | 63 | 64 | mysql 65 | mysql-connector-java 66 | 67 | 68 | 69 | com.alibaba 70 | druid-spring-boot-starter 71 | 72 | 73 | 74 | 75 | org.apache.shiro 76 | shiro-spring 77 | jakarta 78 | ${shiro.version} 79 | 80 | 81 | org.apache.shiro 82 | shiro-core 83 | 84 | 85 | org.apache.shiro 86 | shiro-web 87 | 88 | 89 | 90 | 91 | org.apache.shiro 92 | shiro-core 93 | jakarta 94 | ${shiro.version} 95 | 96 | 97 | org.apache.shiro 98 | shiro-web 99 | jakarta 100 | ${shiro.version} 101 | 102 | 103 | org.apache.shiro 104 | shiro-core 105 | 106 | 107 | 108 | 109 | org.apache.shiro 110 | shiro-ehcache 111 | ${shiro.version} 112 | 113 | 118 | 119 | org.terracotta 120 | ehcache-probe 121 | 1.0.2 122 | 123 | 124 | -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/controller/ShiroAuthController.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.controller; 2 | 3 | import com.nicefish.core.i18n.I18nUtil; 4 | import com.nicefish.core.utils.AjaxResult; 5 | import com.nicefish.rbac.exception.CellphoneDuplicateException; 6 | import com.nicefish.rbac.exception.EmailDuplicateException; 7 | import com.nicefish.rbac.exception.UserNameDuplicateException; 8 | import com.nicefish.rbac.jpa.entity.ComponentPermissionEntity; 9 | import com.nicefish.rbac.jpa.entity.UserEntity; 10 | import com.nicefish.rbac.service.IComponentPermissionService; 11 | import com.nicefish.rbac.service.IUserService; 12 | import com.nicefish.rbac.shiro.util.NiceFishSecurityUtils; 13 | import org.apache.shiro.authc.AuthenticationException; 14 | import org.apache.shiro.authc.UsernamePasswordToken; 15 | import org.slf4j.Logger; 16 | import org.slf4j.LoggerFactory; 17 | import org.springframework.beans.factory.annotation.Autowired; 18 | import org.springframework.stereotype.Controller; 19 | import org.springframework.util.ObjectUtils; 20 | import org.springframework.web.bind.annotation.*; 21 | 22 | import jakarta.servlet.http.Cookie; 23 | import jakarta.servlet.http.HttpServletRequest; 24 | import jakarta.servlet.http.HttpServletResponse; 25 | 26 | /** 27 | * Shiro 认证和授权相关的 API 。 28 | * @author 大漠穷秋 29 | */ 30 | @Controller 31 | @RequestMapping("/nicefish/auth/shiro") 32 | public class ShiroAuthController { 33 | private static final Logger logger = LoggerFactory.getLogger(ShiroAuthController.class); 34 | 35 | @Autowired 36 | protected IUserService userService; 37 | 38 | @Autowired 39 | protected IComponentPermissionService componentPermissionService; 40 | 41 | @PostMapping("/register") 42 | @ResponseBody 43 | public AjaxResult register(@RequestBody UserEntity userEntity) { 44 | //TODO:与前端代码对接,让前端先加密一次传输过来 45 | userEntity.setSalt(NiceFishSecurityUtils.randomSalt()); 46 | userEntity.setPassword(userService.encryptPassword(userEntity.getUserName(), userEntity.getPassword(), userEntity.getSalt())); 47 | 48 | try { 49 | userService.createUser(userEntity); 50 | }catch (UserNameDuplicateException e){ 51 | logger.debug(e.toString()); 52 | return AjaxResult.failure(I18nUtil.getMessage("auth.register.user.mail.failure")); 53 | }catch (EmailDuplicateException e){ 54 | logger.debug(e.toString()); 55 | return AjaxResult.failure(I18nUtil.getMessage("auth.register.mail.failure")); 56 | }catch (CellphoneDuplicateException e){ 57 | logger.debug(e.toString()); 58 | return AjaxResult.failure(I18nUtil.getMessage("auth.register.phone.failure")); 59 | } 60 | 61 | return AjaxResult.success(userEntity); 62 | } 63 | 64 | /** 65 | * 调用 Shiro 的 API 尝试登录,Shiro 会在内部调用 NiceFishMySQLRealm.doGetAuthenticationInfo 进行验证。 66 | * 关键调用轨迹:ShiroAuthController.login->NiceFishMySQLRealm.doGetAuthenticationInfo->UserServiceImpl.checkUser 67 | * TODO:要求前端代码对 password 先进行一次加密再调用此接口登录。 68 | * @param userName 用户名 69 | * @param password 密码 70 | * @param rememberMe 记住我 71 | * @return 72 | */ 73 | @PostMapping("/login") 74 | @ResponseBody 75 | public AjaxResult login(String userName, String password, Boolean rememberMe) { 76 | try { 77 | UsernamePasswordToken token = new UsernamePasswordToken(userName, password, rememberMe); 78 | NiceFishSecurityUtils.getSubject().login(token); 79 | UserEntity userEntity=NiceFishSecurityUtils.getUserEntity(); 80 | return AjaxResult.success(userEntity); 81 | } catch (AuthenticationException e) { 82 | return AjaxResult.failure(e.getMessage()); 83 | } 84 | } 85 | 86 | @GetMapping("/logout") 87 | @ResponseBody 88 | public AjaxResult logout(HttpServletRequest request, HttpServletResponse response) { 89 | try { 90 | NiceFishSecurityUtils.getSubject().logout(); 91 | 92 | //把请求端的所有 cookie 全部标记成失效 93 | Cookie[] cookies=request.getCookies(); 94 | if(!ObjectUtils.isEmpty(cookies)){ 95 | for(Cookie cookie:cookies){ 96 | cookie.setMaxAge(0); 97 | response.addCookie(cookie); 98 | } 99 | } 100 | 101 | return AjaxResult.success(); 102 | } catch (AuthenticationException e) { 103 | return AjaxResult.failure(e.getMessage()); 104 | } 105 | } 106 | 107 | @GetMapping(value = "/menu/{userId}") 108 | @ResponseBody 109 | public AjaxResult getMenus(@PathVariable(value = "userId",required = true) Integer userId){ 110 | Iterable list = this.componentPermissionService.getComponentPermissionsByUserId(userId); 111 | return AjaxResult.success(list); 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/jpa/entity/UserEntity.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.jpa.entity; 2 | 3 | import com.fasterxml.jackson.annotation.JsonFormat; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import org.hibernate.annotations.DynamicInsert; 6 | import org.hibernate.annotations.DynamicUpdate; 7 | 8 | import jakarta.persistence.*; 9 | import java.io.Serializable; 10 | import java.util.Date; 11 | import java.util.List; 12 | 13 | @Entity 14 | @DynamicInsert 15 | @DynamicUpdate 16 | @Table(name = "nicefish_rbac_user") 17 | public class UserEntity implements Serializable { 18 | @Id 19 | @GeneratedValue(strategy = GenerationType.IDENTITY) 20 | @Column(name="user_id", updatable = false) 21 | private Integer userId; 22 | 23 | @Column(name="user_name",nullable = false,updatable = false) 24 | private String userName; 25 | 26 | @Column(name="nick_name",nullable = false) 27 | private String nickName; 28 | 29 | @Column(name="password",nullable = false) 30 | private String password; 31 | 32 | @Column(name="email") 33 | private String email; 34 | 35 | @Column(name="cellphone") 36 | private String cellphone; 37 | 38 | @Column(name="gender",columnDefinition = "int default 0") 39 | private Integer gender=0; 40 | 41 | @Column(name="city") 42 | private String city; 43 | 44 | @Column(name="education") 45 | private String education; 46 | 47 | @Temporal(TemporalType.TIMESTAMP) 48 | @Column(name="create_time",updatable = false) 49 | @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") 50 | private Date createTime; 51 | 52 | @Column(name="avatar_url") 53 | private String avatarURL; 54 | 55 | @Column(name="salt") 56 | private String salt; 57 | 58 | @Column(name="status",columnDefinition = "int default 0") 59 | private Integer status=0; 60 | 61 | @Column(name="remark") 62 | private String remark; 63 | 64 | @JoinTable( 65 | name="nicefish_rbac_user_role", 66 | joinColumns={@JoinColumn(name="user_id",referencedColumnName="user_id")}, 67 | inverseJoinColumns={@JoinColumn(name="role_id",referencedColumnName="role_id")} 68 | ) 69 | @ManyToMany(fetch = FetchType.LAZY) 70 | private List roleEntities; 71 | 72 | public List getRoleEntities() { 73 | return roleEntities; 74 | } 75 | 76 | @JsonProperty 77 | public void setRoleEntities(List roleEntities) { 78 | this.roleEntities = roleEntities; 79 | } 80 | 81 | public Integer getUserId() { 82 | return userId; 83 | } 84 | 85 | public void setUserId(Integer userId) { 86 | this.userId = userId; 87 | } 88 | 89 | public String getUserName() { 90 | return userName; 91 | } 92 | 93 | public void setUserName(String userName) { 94 | this.userName = userName; 95 | } 96 | 97 | public String getNickName() { 98 | return nickName; 99 | } 100 | 101 | public void setNickName(String nickName) { 102 | this.nickName = nickName; 103 | } 104 | 105 | public String getPassword() { 106 | return password; 107 | } 108 | 109 | public void setPassword(String password) { 110 | this.password = password; 111 | } 112 | 113 | public String getEmail() { 114 | return email; 115 | } 116 | 117 | public void setEmail(String email) { 118 | this.email = email; 119 | } 120 | 121 | public String getCellphone() { 122 | return cellphone; 123 | } 124 | 125 | public void setCellphone(String cellphone) { 126 | this.cellphone = cellphone; 127 | } 128 | 129 | public Integer getGender() { 130 | return gender; 131 | } 132 | 133 | public void setGender(Integer gender) { 134 | this.gender = gender; 135 | } 136 | 137 | public String getAvatarURL() { 138 | return avatarURL; 139 | } 140 | 141 | public void setAvatarURL(String avatarURL) { 142 | this.avatarURL = avatarURL; 143 | } 144 | 145 | public String getSalt() { 146 | return salt; 147 | } 148 | 149 | public void setSalt(String salt) { 150 | this.salt = salt; 151 | } 152 | 153 | public Integer getStatus() { 154 | return status; 155 | } 156 | 157 | public void setStatus(Integer status) { 158 | this.status = status; 159 | } 160 | 161 | public String getRemark() { 162 | return remark; 163 | } 164 | 165 | public void setRemark(String remark) { 166 | this.remark = remark; 167 | } 168 | 169 | public Date getCreateTime() { 170 | return createTime; 171 | } 172 | 173 | public void setCreateTime(Date createTime) { 174 | this.createTime = createTime; 175 | } 176 | 177 | public String getCity() { 178 | return city; 179 | } 180 | 181 | public void setCity(String city) { 182 | this.city = city; 183 | } 184 | 185 | public String getEducation() { 186 | return education; 187 | } 188 | 189 | public void setEducation(String education) { 190 | this.education = education; 191 | } 192 | } -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.controller; 2 | 3 | import com.nicefish.core.i18n.I18nUtil; 4 | import com.nicefish.core.utils.AjaxResult; 5 | import com.nicefish.rbac.jpa.entity.UserEntity; 6 | import com.nicefish.rbac.service.IUserService; 7 | import com.nicefish.rbac.shiro.util.NiceFishSecurityUtils; 8 | import org.apache.shiro.authz.annotation.RequiresPermissions; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.data.domain.Page; 13 | import org.springframework.data.domain.PageRequest; 14 | import org.springframework.data.domain.Pageable; 15 | import org.springframework.web.bind.annotation.*; 16 | 17 | /** 18 | * 用户管理 19 | * @author 大漠穷秋 20 | */ 21 | @RestController 22 | @RequestMapping("/nicefish/auth/user") 23 | public class UserController { 24 | private static final Logger logger = LoggerFactory.getLogger(UserController.class); 25 | 26 | @Autowired 27 | protected IUserService userService; 28 | 29 | /** 30 | * 获取Session中的用户实例。 31 | * 在前后端分离的模式下,前端可以通过此接口来测试Session中是否还存在已登录的用户。 32 | * @return 33 | */ 34 | @GetMapping("/get-session-user") 35 | @ResponseBody 36 | public UserEntity getSessionUser(){ 37 | return NiceFishSecurityUtils.getUserEntity(); 38 | } 39 | 40 | @PostMapping("/update") 41 | @ResponseBody 42 | public AjaxResult updateUser(@RequestBody UserEntity userEntity) { 43 | logger.debug(userEntity.toString()); 44 | 45 | //TODO:与前端代码对接,让前端先加密一次传输过来 46 | userEntity.setSalt(NiceFishSecurityUtils.randomSalt()); 47 | userEntity.setPassword(userService.encryptPassword(userEntity.getUserName(), userEntity.getPassword(), userEntity.getSalt())); 48 | 49 | //TODO:数据合法性校验 50 | return AjaxResult.success(userService.saveUser(userEntity)); 51 | } 52 | 53 | @PostMapping(value = "/update-user-role-relation") 54 | @ResponseBody 55 | @RequiresPermissions("sys:manage:user") 56 | public AjaxResult updateUserRoleRelation(@RequestBody UserEntity userEntity){ 57 | userEntity=this.userService.updateUserRoleRelation(userEntity); 58 | return AjaxResult.success(userEntity); 59 | } 60 | 61 | @PostMapping(value = "/list/{page}") 62 | @ResponseBody 63 | @RequiresPermissions("sys:manage:user") 64 | public Page getUserList(@RequestBody UserEntity userEntity, @PathVariable(value="page",required = true) int page) { 65 | Pageable pageable= PageRequest.of(page-1,10); 66 | Page userList = userService.getUserList(userEntity,pageable); 67 | return userList; 68 | } 69 | 70 | @DeleteMapping(value = "/delete/{userId}") 71 | @ResponseBody 72 | @RequiresPermissions("sys:manage:user") 73 | public AjaxResult deleteUser(@PathVariable(value="userId",required = true)Integer userId){ 74 | //TODO:合法性校验,关联表操作校验,业务逻辑校验 75 | int affected=userService.deleteByUserId(userId); 76 | if(affected==0){ 77 | return new AjaxResult(false, I18nUtil.getMessage("user.del.failure")); 78 | }else{ 79 | return new AjaxResult(true,"common.del.success"); 80 | } 81 | } 82 | 83 | @GetMapping(value = "/detail/{userId}") 84 | @ResponseBody 85 | public AjaxResult getUserDetail(@PathVariable(value = "userId",required = true) Integer userId){ 86 | UserEntity userEntity=userService.getUserByUserId(userId); 87 | AjaxResult ajaxResult =new AjaxResult(true,userEntity); 88 | return ajaxResult; 89 | } 90 | 91 | //TODO:重新定义权限,管理员可以重置任意密码,用户自己只能重置自己的密码 92 | @PostMapping("/reset-pwd") 93 | @ResponseBody 94 | public AjaxResult resetPwd(UserEntity userEntity) { 95 | userEntity.setSalt(NiceFishSecurityUtils.randomSalt()); 96 | userEntity.setPassword(userService.encryptPassword(userEntity.getUserName(), userEntity.getPassword(), userEntity.getSalt())); 97 | userService.resetPwd(userEntity); 98 | return AjaxResult.failure(); 99 | } 100 | 101 | @PostMapping("/remove") 102 | @ResponseBody 103 | @RequiresPermissions("sys:manage:user") 104 | public AjaxResult delUser(Integer[] ids) { 105 | try { 106 | return AjaxResult.success(userService.deleteByIds(ids)); 107 | } catch (Exception e) { 108 | return AjaxResult.failure(e.getMessage()); 109 | } 110 | } 111 | 112 | @PostMapping("/change-status") 113 | @ResponseBody 114 | @RequiresPermissions("sys:manage:user") 115 | public AjaxResult changeStatus(UserEntity userEntity) { 116 | return AjaxResult.success(userService.setUserStatus(userEntity)); 117 | } 118 | 119 | @PostMapping("/is-user-name-unique") 120 | @ResponseBody 121 | public String isUserNameUnique(UserEntity userEntity) { 122 | return userService.isUserNameUnique(userEntity.getUserName())?"0":"1"; 123 | } 124 | 125 | @PostMapping("/is-phone-unique") 126 | @ResponseBody 127 | public String isPhoneUnique(UserEntity userEntity) { 128 | return userService.isPhoneUnique(userEntity.getCellphone())?"0":"1"; 129 | } 130 | 131 | @PostMapping("/is-email-unique") 132 | @ResponseBody 133 | public String isEmailUnique(UserEntity userEntity) { 134 | return userService.isEmailUnique(userEntity.getEmail())?"0":"1"; 135 | } 136 | } -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/jpa/entity/NiceFishSessionEntity.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.jpa.entity; 2 | 3 | import com.fasterxml.jackson.annotation.JsonFormat; 4 | import jakarta.persistence.*; 5 | import org.hibernate.annotations.DynamicInsert; 6 | import org.hibernate.annotations.DynamicUpdate; 7 | 8 | import java.io.Serializable; 9 | import java.util.Date; 10 | 11 | /** 12 | * 此实体类用于持久化 Session 到数据库。 13 | */ 14 | @Entity 15 | @DynamicInsert 16 | @DynamicUpdate 17 | @Table(name = "nicefish_rbac_session") 18 | public class NiceFishSessionEntity implements Serializable { 19 | @Id 20 | @Column(name = "session_id") 21 | private String sessionId; 22 | 23 | @Column(name="app_name") 24 | private String appName; 25 | 26 | @Column(name="user_id") 27 | private Integer userId; 28 | 29 | @Column(name="user_name") 30 | private String userName; 31 | 32 | @Temporal(TemporalType.TIMESTAMP) 33 | @Column(name="creation_time") 34 | @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") 35 | private Date creationTime; 36 | 37 | @Temporal(TemporalType.TIMESTAMP) 38 | @Column(name="expiry_time") 39 | @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") 40 | private Date expiryTime; 41 | 42 | @Temporal(TemporalType.TIMESTAMP) 43 | @Column(name="last_access_time") 44 | @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") 45 | private Date lastAccessTime; 46 | 47 | @Column(name="max_inactive_interval") 48 | private Integer maxInactiveInteval; 49 | 50 | //Session 有效时间,单位 ms 51 | @Column(name="timeout") 52 | private Long timeout; 53 | 54 | @Column(name="expired") 55 | private Boolean expired=false; 56 | 57 | @Column(name="host") 58 | private String host; 59 | 60 | @Column(name="os") 61 | private String os; 62 | 63 | @Column(name="browser") 64 | private String browser; 65 | 66 | @Column(name="userAgent") 67 | private String userAgent; 68 | 69 | /** 70 | * Session 中的所有 K-V 都序列化在这个 JSON 字符串中。 71 | * 为了跨项目场景下反序列化失败,此 JSON 字符串中的数据只包含 Java 基本类型,不处理自定义的类。 72 | */ 73 | @Lob 74 | @Column(name="session_data",columnDefinition="text") 75 | private String sessionData; 76 | 77 | public String getSessionId() { 78 | return sessionId; 79 | } 80 | 81 | public void setSessionId(String sessionId) { 82 | this.sessionId = sessionId; 83 | } 84 | 85 | public Integer getUserId() { 86 | return userId; 87 | } 88 | 89 | public void setUserId(Integer userId) { 90 | this.userId = userId; 91 | } 92 | 93 | public String getUserName() { 94 | return userName; 95 | } 96 | 97 | public void setUserName(String userName) { 98 | this.userName = userName; 99 | } 100 | 101 | public String getAppName() { 102 | return appName; 103 | } 104 | 105 | public void setAppName(String appName) { 106 | this.appName = appName; 107 | } 108 | 109 | public Date getCreationTime() { 110 | return creationTime; 111 | } 112 | 113 | public void setCreationTime(Date creationTime) { 114 | this.creationTime = creationTime; 115 | } 116 | 117 | public Date getExpiryTime() { 118 | return expiryTime; 119 | } 120 | 121 | public void setExpiryTime(Date expiryTime) { 122 | this.expiryTime = expiryTime; 123 | } 124 | 125 | public Date getLastAccessTime() { 126 | return lastAccessTime; 127 | } 128 | 129 | public void setLastAccessTime(Date lastAccessTime) { 130 | this.lastAccessTime = lastAccessTime; 131 | } 132 | 133 | public Long getTimeout() { 134 | return timeout; 135 | } 136 | 137 | public void setTimeout(Long timeout) { 138 | this.timeout = timeout; 139 | } 140 | 141 | public boolean isExpired() { 142 | return expired; 143 | } 144 | 145 | public void setExpired(boolean expired) { 146 | this.expired = expired; 147 | } 148 | 149 | public String getHost() { 150 | return host; 151 | } 152 | 153 | public void setHost(String host) { 154 | this.host = host; 155 | } 156 | 157 | public String getOs() { 158 | return os; 159 | } 160 | 161 | public void setOs(String os) { 162 | this.os = os; 163 | } 164 | 165 | public String getBrowser() { 166 | return browser; 167 | } 168 | 169 | public void setBrowser(String browser) { 170 | this.browser = browser; 171 | } 172 | 173 | public String getUserAgent() { 174 | return userAgent; 175 | } 176 | 177 | public void setUserAgent(String userAgent) { 178 | this.userAgent = userAgent; 179 | } 180 | 181 | public String getSessionData() { 182 | return sessionData; 183 | } 184 | 185 | public void setSessionData(String sessionData) { 186 | this.sessionData = sessionData; 187 | } 188 | 189 | public Integer getMaxInactiveInteval() { 190 | return maxInactiveInteval; 191 | } 192 | 193 | public void setMaxInactiveInteval(Integer maxInactiveInteval) { 194 | this.maxInactiveInteval = maxInactiveInteval; 195 | } 196 | } -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/service/impl/ComponentPermissionServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.service.impl; 2 | 3 | 4 | import com.nicefish.rbac.jpa.entity.ComponentPermissionEntity; 5 | import com.nicefish.rbac.jpa.entity.RoleEntity; 6 | import com.nicefish.rbac.jpa.entity.UserEntity; 7 | import com.nicefish.rbac.jpa.repository.IComponentPermissionRepository; 8 | import com.nicefish.rbac.jpa.repository.IUserRepository; 9 | import com.nicefish.rbac.service.IComponentPermissionService; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.data.domain.Page; 14 | import org.springframework.data.domain.Pageable; 15 | import org.springframework.data.jpa.domain.Specification; 16 | import org.springframework.stereotype.Service; 17 | import org.springframework.util.ObjectUtils; 18 | 19 | import jakarta.persistence.criteria.CriteriaBuilder; 20 | import jakarta.persistence.criteria.CriteriaQuery; 21 | import jakarta.persistence.criteria.Predicate; 22 | import jakarta.persistence.criteria.Root; 23 | import java.util.ArrayList; 24 | import java.util.List; 25 | 26 | /** 27 | * @author 大漠穷秋 28 | */ 29 | @Service 30 | public class ComponentPermissionServiceImpl implements IComponentPermissionService { 31 | private static final Logger logger = LoggerFactory.getLogger(ComponentPermissionServiceImpl.class); 32 | 33 | @Autowired 34 | private IComponentPermissionRepository componentPermissionRepository; 35 | 36 | @Autowired 37 | private IUserRepository userRepository; 38 | 39 | /** 40 | * 此方法从根节点开始,包含所有层级上的子节点,带分页 41 | */ 42 | @Override 43 | public Page getComponentPermissionTree(ComponentPermissionEntity componentPermissionEntity,Pageable pageable) { 44 | Page page= this.componentPermissionRepository.findAll(new Specification() { 45 | @Override 46 | public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) { 47 | List predicates=new ArrayList<>(); 48 | predicates.add(criteriaBuilder.isNull(root.get("parentEntity"))); 49 | return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()])); 50 | } 51 | },pageable); 52 | return page; 53 | } 54 | 55 | @Override 56 | public Iterable getPermListAllByRole(RoleEntity roleEntity) { 57 | List list=new ArrayList<>(); 58 | list.add(roleEntity); 59 | Iterable compPermList=this.componentPermissionRepository.findAllByRoleEntitiesIn(list); 60 | return compPermList; 61 | } 62 | 63 | @Override 64 | public ComponentPermissionEntity getComponentPermissionDetail(Integer compPermId) { 65 | return this.componentPermissionRepository.findDistinctByCompPermId(compPermId); 66 | } 67 | 68 | /** 69 | * 创建组件权限,创建时可以带有父层节点的 id 作为参数,但是不处理子节点,即使传递 children 参数,也会被忽略。 70 | * @param componentPermissionEntity 71 | * @return 72 | */ 73 | @Override 74 | public ComponentPermissionEntity createComponentPermission(ComponentPermissionEntity componentPermissionEntity) { 75 | if(!ObjectUtils.isEmpty(componentPermissionEntity.getParentEntity())){ 76 | Integer pId=componentPermissionEntity.getParentEntity().getCompPermId(); 77 | ComponentPermissionEntity parentEntity=this.componentPermissionRepository.findDistinctByCompPermId(pId); 78 | componentPermissionEntity.setParentEntity(parentEntity); 79 | } 80 | componentPermissionEntity.setChildren(new ArrayList<>()); 81 | componentPermissionEntity=this.componentPermissionRepository.save(componentPermissionEntity); 82 | return componentPermissionEntity; 83 | } 84 | 85 | /** 86 | * 编辑组件权限,编辑时只修改当前组件节点上的属性,父层和子层都不修改。 87 | * 即使接收到了 parentEntity 和 children 参数 ,也全部忽略,仍然使用原来的值。 88 | * @param componentPermissionEntity 89 | * @return 90 | */ 91 | @Override 92 | public ComponentPermissionEntity updateComponentPermission(ComponentPermissionEntity componentPermissionEntity) { 93 | //TODO:数据校验 94 | ComponentPermissionEntity oldEntity=this.componentPermissionRepository.findDistinctByCompPermId(componentPermissionEntity.getCompPermId()); 95 | if(!ObjectUtils.isEmpty(oldEntity)){ 96 | componentPermissionEntity.setParentEntity(oldEntity.getParentEntity()); 97 | componentPermissionEntity.setChildren(oldEntity.getChildren()); 98 | componentPermissionEntity.setRoleEntities(oldEntity.getRoleEntities()); 99 | } 100 | this.componentPermissionRepository.save(componentPermissionEntity); 101 | return componentPermissionEntity; 102 | } 103 | 104 | @Override 105 | public int deleteComponentPermission(Integer compPermId) { 106 | this.componentPermissionRepository.deleteById(compPermId); 107 | return 0; 108 | } 109 | 110 | @Override 111 | public Iterable getComponentPermissionsByUserId(Integer userId) { 112 | UserEntity userEntity=this.userRepository.findDistinctByUserId(userId); 113 | List roleEntities=userEntity.getRoleEntities(); 114 | Iterable componentPermissionEntities=this.componentPermissionRepository.findDistinctByRoleEntitiesIn(roleEntities); 115 | return componentPermissionEntities; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /nicefish-core/src/main/java/com/nicefish/core/utils/IPUtil.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.core.utils; 2 | 3 | import org.springframework.util.StringUtils; 4 | 5 | import jakarta.servlet.http.HttpServletRequest; 6 | import java.net.InetAddress; 7 | import java.net.UnknownHostException; 8 | 9 | public class IPUtil { 10 | public static String getIpAddr(HttpServletRequest request) { 11 | if (request == null) { 12 | return "unknown"; 13 | } 14 | String ip = request.getHeader("x-forwarded-for"); 15 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 16 | ip = request.getHeader("Proxy-Client-IP"); 17 | } 18 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 19 | ip = request.getHeader("X-Forwarded-For"); 20 | } 21 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 22 | ip = request.getHeader("WL-Proxy-Client-IP"); 23 | } 24 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 25 | ip = request.getHeader("X-Real-IP"); 26 | } 27 | 28 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 29 | ip = request.getRemoteAddr(); 30 | } 31 | return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip; 32 | } 33 | 34 | public static boolean internalIp(String ip) { 35 | byte[] addr = textToNumericFormatV4(ip); 36 | return internalIp(addr) || "127.0.0.1".equals(ip); 37 | } 38 | 39 | private static boolean internalIp(byte[] addr) { 40 | if (StringUtils.isEmpty(addr) || addr.length < 2) { 41 | return true; 42 | } 43 | final byte b0 = addr[0]; 44 | final byte b1 = addr[1]; 45 | // 10.x.x.x/8 46 | final byte SECTION_1 = 0x0A; 47 | // 172.16.x.x/12 48 | final byte SECTION_2 = (byte) 0xAC; 49 | final byte SECTION_3 = (byte) 0x10; 50 | final byte SECTION_4 = (byte) 0x1F; 51 | // 192.168.x.x/16 52 | final byte SECTION_5 = (byte) 0xC0; 53 | final byte SECTION_6 = (byte) 0xA8; 54 | switch (b0) { 55 | case SECTION_1: 56 | return true; 57 | case SECTION_2: 58 | if (b1 >= SECTION_3 && b1 <= SECTION_4) { 59 | return true; 60 | } 61 | case SECTION_5: 62 | switch (b1) { 63 | case SECTION_6: 64 | return true; 65 | } 66 | default: 67 | return false; 68 | } 69 | } 70 | 71 | public static byte[] textToNumericFormatV4(String text) { 72 | if(StringUtils.isEmpty(text)){ 73 | return null; 74 | } 75 | 76 | byte[] bytes = new byte[4]; 77 | String[] elements = text.split("\\.", -1); 78 | try { 79 | long l; 80 | int i; 81 | switch (elements.length) { 82 | case 1: 83 | l = Long.parseLong(elements[0]); 84 | if ((l < 0L) || (l > 4294967295L)) 85 | return null; 86 | bytes[0] = (byte) (int) (l >> 24 & 0xFF); 87 | bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF); 88 | bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF); 89 | bytes[3] = (byte) (int) (l & 0xFF); 90 | break; 91 | case 2: 92 | l = Integer.parseInt(elements[0]); 93 | if ((l < 0L) || (l > 255L)) 94 | return null; 95 | bytes[0] = (byte) (int) (l & 0xFF); 96 | l = Integer.parseInt(elements[1]); 97 | if ((l < 0L) || (l > 16777215L)) 98 | return null; 99 | bytes[1] = (byte) (int) (l >> 16 & 0xFF); 100 | bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF); 101 | bytes[3] = (byte) (int) (l & 0xFF); 102 | break; 103 | case 3: 104 | for (i = 0; i < 2; ++i) { 105 | l = Integer.parseInt(elements[i]); 106 | if ((l < 0L) || (l > 255L)) 107 | return null; 108 | bytes[i] = (byte) (int) (l & 0xFF); 109 | } 110 | l = Integer.parseInt(elements[2]); 111 | if ((l < 0L) || (l > 65535L)) 112 | return null; 113 | bytes[2] = (byte) (int) (l >> 8 & 0xFF); 114 | bytes[3] = (byte) (int) (l & 0xFF); 115 | break; 116 | case 4: 117 | for (i = 0; i < 4; ++i) { 118 | l = Integer.parseInt(elements[i]); 119 | if ((l < 0L) || (l > 255L)) 120 | return null; 121 | bytes[i] = (byte) (int) (l & 0xFF); 122 | } 123 | break; 124 | default: 125 | return null; 126 | } 127 | } catch (NumberFormatException e) { 128 | return null; 129 | } 130 | return bytes; 131 | } 132 | 133 | public static String getHostIp() { 134 | try { 135 | return InetAddress.getLocalHost().getHostAddress(); 136 | } catch (UnknownHostException e) { 137 | } 138 | return "127.0.0.1"; 139 | } 140 | 141 | public static String getHostName() { 142 | try { 143 | return InetAddress.getLocalHost().getHostName(); 144 | } catch (UnknownHostException e) { 145 | } 146 | return "unknown"; 147 | } 148 | } -------------------------------------------------------------------------------- /nicefish-shiro-rbac/src/main/java/com/nicefish/rbac/jpa/entity/ComponentPermissionEntity.java: -------------------------------------------------------------------------------- 1 | package com.nicefish.rbac.jpa.entity; 2 | 3 | import com.fasterxml.jackson.annotation.JsonFormat; 4 | import com.fasterxml.jackson.annotation.JsonIdentityInfo; 5 | import com.fasterxml.jackson.annotation.ObjectIdGenerators; 6 | import com.fasterxml.jackson.databind.annotation.JsonSerialize; 7 | import com.nicefish.rbac.jpautils.RoleListSerializer; 8 | import org.hibernate.annotations.DynamicInsert; 9 | import org.hibernate.annotations.DynamicUpdate; 10 | 11 | import jakarta.persistence.*; 12 | import java.io.Serializable; 13 | import java.util.ArrayList; 14 | import java.util.Date; 15 | import java.util.List; 16 | 17 | /** 18 | * 在 NiceFish 中,权限控制整体上分2个层次:前端权限和后端权限。 19 | * - 前端权限是指在前端页面上的权限控制,比如菜单、按钮、甚至可以细致到一个 HTML 元素。 20 | * - 后端权限是指在后端 API 接口上的权限控制,比如一个 API 接口是否需要登录才能访问,是否需要某个角色才能访问,是否需要某个权限才能访问等。 21 | * 22 | * ComponentPermissionEntity 用来定义前端页面的权限,对应数据库中的 nicefish_rbac_component 表。 23 | * 需要被保护的前端组件使用此 Entity 进行权限定义,不需要保护的组件由前端自行管理。 24 | * 25 | * @see ApiPermissionEntity 26 | * @author: 大漠穷秋 27 | */ 28 | @Entity 29 | @DynamicInsert 30 | @DynamicUpdate 31 | @Table(name = "nicefish_rbac_component") 32 | public class ComponentPermissionEntity implements Serializable { 33 | @Id 34 | @GeneratedValue(strategy = GenerationType.IDENTITY) 35 | @Column(name="component_id") 36 | private Integer compPermId; 37 | 38 | @Column(name="component_name") 39 | private String componentName; 40 | 41 | @Column(name="icon") 42 | private String icon; 43 | 44 | @Column(name="url") 45 | private String url; 46 | 47 | @Column(name="display_order ") 48 | private Integer displayOrder; 49 | 50 | @Column(name="permission") 51 | private String permission; 52 | 53 | @Temporal(TemporalType.TIMESTAMP) 54 | @Column(name="create_time",updatable = false) 55 | @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") 56 | private Date createTime; 57 | 58 | @Temporal(TemporalType.TIMESTAMP) 59 | @Column(name="update_time") 60 | @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") 61 | private Date updateTime; 62 | 63 | @Column(name="visiable") 64 | private Integer visiable=1; 65 | 66 | @Column(name="remark") 67 | private String remark; 68 | 69 | @JsonIdentityInfo(generator= ObjectIdGenerators.PropertyGenerator.class, property="compPermId") 70 | @ManyToOne 71 | @JoinColumn(name="p_id") 72 | private ComponentPermissionEntity parentEntity; 73 | 74 | @OneToMany(cascade = {CascadeType.REMOVE,CascadeType.MERGE,CascadeType.PERSIST,CascadeType.REFRESH}) 75 | @JoinColumn(name="p_id") 76 | @OrderBy("displayOrder asc ") 77 | private List children=new ArrayList<>(); 78 | 79 | @JoinTable( 80 | name="nicefish_rbac_role_component", 81 | joinColumns={@JoinColumn(name="component_id",referencedColumnName="component_id")}, 82 | inverseJoinColumns={@JoinColumn(name="role_id",referencedColumnName="role_id")} 83 | ) 84 | @ManyToMany 85 | @JsonSerialize(using = RoleListSerializer.class) 86 | private List roleEntities; 87 | 88 | public List getRoleEntities() { 89 | return roleEntities; 90 | } 91 | 92 | public void setRoleEntities(List roleEntities) { 93 | this.roleEntities = roleEntities; 94 | } 95 | 96 | public Integer getCompPermId() { 97 | return compPermId; 98 | } 99 | 100 | public void setCompPermId(Integer compPermId) { 101 | this.compPermId = compPermId; 102 | } 103 | 104 | public String getComponentName() { 105 | return componentName; 106 | } 107 | 108 | public void setComponentName(String componentName) { 109 | this.componentName = componentName; 110 | } 111 | 112 | public String getIcon() { 113 | return icon; 114 | } 115 | 116 | public void setIcon(String icon) { 117 | this.icon = icon; 118 | } 119 | 120 | public String getUrl() { 121 | return url; 122 | } 123 | 124 | public void setUrl(String url) { 125 | this.url = url; 126 | } 127 | 128 | public Integer getDisplayOrder() { 129 | return displayOrder; 130 | } 131 | 132 | public void setDisplayOrder(Integer displayOrder) { 133 | this.displayOrder = displayOrder; 134 | } 135 | 136 | public String getPermission() { 137 | return permission; 138 | } 139 | 140 | public void setPermission(String permission) { 141 | this.permission = permission; 142 | } 143 | 144 | public Date getCreateTime() { 145 | return createTime; 146 | } 147 | 148 | public void setCreateTime(Date createTime) { 149 | this.createTime = createTime; 150 | } 151 | 152 | public Date getUpdateTime() { 153 | return updateTime; 154 | } 155 | 156 | public void setUpdateTime(Date updateTime) { 157 | this.updateTime = updateTime; 158 | } 159 | 160 | public Integer getVisiable() { 161 | return visiable; 162 | } 163 | 164 | public void setVisiable(Integer visiable) { 165 | this.visiable = visiable; 166 | } 167 | 168 | public String getRemark() { 169 | return remark; 170 | } 171 | 172 | public void setRemark(String remark) { 173 | this.remark = remark; 174 | } 175 | 176 | public List getChildren() { 177 | return children; 178 | } 179 | 180 | public void setChildren(List children) { 181 | this.children = children; 182 | } 183 | 184 | public ComponentPermissionEntity getParentEntity() { 185 | return parentEntity; 186 | } 187 | 188 | public void setParentEntity(ComponentPermissionEntity parentEntity) { 189 | this.parentEntity = parentEntity; 190 | } 191 | } --------------------------------------------------------------------------------