浏览代码

1.网站后台

slambb 1 年之前
当前提交
c111e7c2e7
共有 100 个文件被更改,包括 5919 次插入0 次删除
  1. 138 0
      MovieWebsiteServer.iml
  2. 10 0
      deploy.sh
  3. 310 0
      mvnw
  4. 182 0
      mvnw.cmd
  5. 136 0
      pom.xml
  6. 二进制
      src/.DS_Store
  7. 二进制
      src/main/.DS_Store
  8. 59 0
      src/main/java/com/dapp/moviewebsite/MovieWebsiteApplication.java
  9. 21 0
      src/main/java/com/dapp/moviewebsite/annotation/Between.java
  10. 12 0
      src/main/java/com/dapp/moviewebsite/annotation/Decrypt.java
  11. 12 0
      src/main/java/com/dapp/moviewebsite/annotation/Encrypt.java
  12. 16 0
      src/main/java/com/dapp/moviewebsite/annotation/In.java
  13. 13 0
      src/main/java/com/dapp/moviewebsite/annotation/Like.java
  14. 26 0
      src/main/java/com/dapp/moviewebsite/annotation/RedisUpdate.java
  15. 128 0
      src/main/java/com/dapp/moviewebsite/app/appFavorite/controller/AppFavoriteController.java
  16. 36 0
      src/main/java/com/dapp/moviewebsite/app/appFavorite/pojo/AppFavorite.java
  17. 16 0
      src/main/java/com/dapp/moviewebsite/app/appFavorite/repository/AppFavoriteRepository.java
  18. 28 0
      src/main/java/com/dapp/moviewebsite/app/appFavorite/service/AppFavoriteService.java
  19. 117 0
      src/main/java/com/dapp/moviewebsite/app/appFavorite/service/AppFavoriteServiceImpl.java
  20. 31 0
      src/main/java/com/dapp/moviewebsite/app/appFavorite/vo/AppFavoriteSimpleVo.java
  21. 31 0
      src/main/java/com/dapp/moviewebsite/app/appFavorite/vo/AppFavoriteVo.java
  22. 15 0
      src/main/java/com/dapp/moviewebsite/app/appUser/controller/AppUserController.java
  23. 35 0
      src/main/java/com/dapp/moviewebsite/app/appUser/pojo/AppUser.java
  24. 9 0
      src/main/java/com/dapp/moviewebsite/app/appUser/repository/AppUserRepository.java
  25. 9 0
      src/main/java/com/dapp/moviewebsite/app/appUser/service/AppUserService.java
  26. 21 0
      src/main/java/com/dapp/moviewebsite/app/appUser/service/AppUserServiceImpl.java
  27. 31 0
      src/main/java/com/dapp/moviewebsite/app/appUser/vo/AppUserSimpleVo.java
  28. 31 0
      src/main/java/com/dapp/moviewebsite/app/appUser/vo/AppUserVo.java
  29. 57 0
      src/main/java/com/dapp/moviewebsite/app/appUserMember/controller/AppUserMemberController.java
  30. 9 0
      src/main/java/com/dapp/moviewebsite/app/appUserMember/enums/MemberType.java
  31. 34 0
      src/main/java/com/dapp/moviewebsite/app/appUserMember/pojo/AppUserMember.java
  32. 12 0
      src/main/java/com/dapp/moviewebsite/app/appUserMember/repository/AppUserMemberRepository.java
  33. 12 0
      src/main/java/com/dapp/moviewebsite/app/appUserMember/service/AppUserMemberService.java
  34. 93 0
      src/main/java/com/dapp/moviewebsite/app/appUserMember/service/AppUserMemberServiceImpl.java
  35. 29 0
      src/main/java/com/dapp/moviewebsite/app/appUserMember/vo/AppUserMemberSimpleVo.java
  36. 29 0
      src/main/java/com/dapp/moviewebsite/app/appUserMember/vo/AppUserMemberVo.java
  37. 44 0
      src/main/java/com/dapp/moviewebsite/app/appUserTran/controller/AppUserTranController.java
  38. 9 0
      src/main/java/com/dapp/moviewebsite/app/appUserTran/enums/TranType.java
  39. 49 0
      src/main/java/com/dapp/moviewebsite/app/appUserTran/pojo/AppUserTran.java
  40. 9 0
      src/main/java/com/dapp/moviewebsite/app/appUserTran/repository/AppUserTranRepository.java
  41. 9 0
      src/main/java/com/dapp/moviewebsite/app/appUserTran/service/AppUserTranService.java
  42. 52 0
      src/main/java/com/dapp/moviewebsite/app/appUserTran/service/AppUserTranServiceImpl.java
  43. 45 0
      src/main/java/com/dapp/moviewebsite/app/appUserTran/vo/AppUserTranSimpleVo.java
  44. 45 0
      src/main/java/com/dapp/moviewebsite/app/appUserTran/vo/AppUserTranVo.java
  45. 56 0
      src/main/java/com/dapp/moviewebsite/app/appVideos/controller/AppVideosController.java
  46. 36 0
      src/main/java/com/dapp/moviewebsite/app/appVideos/pojo/AppVideos.java
  47. 13 0
      src/main/java/com/dapp/moviewebsite/app/appVideos/repository/AppVideosRepository.java
  48. 25 0
      src/main/java/com/dapp/moviewebsite/app/appVideos/service/AppVideosService.java
  49. 86 0
      src/main/java/com/dapp/moviewebsite/app/appVideos/service/AppVideosServiceImpl.java
  50. 36 0
      src/main/java/com/dapp/moviewebsite/app/appVideos/vo/AppVideosOtherVo.java
  51. 31 0
      src/main/java/com/dapp/moviewebsite/app/appVideos/vo/AppVideosSimpleVo.java
  52. 31 0
      src/main/java/com/dapp/moviewebsite/app/appVideos/vo/AppVideosVo.java
  53. 134 0
      src/main/java/com/dapp/moviewebsite/app/appViewingRecords/controller/AppViewingRecordsController.java
  54. 29 0
      src/main/java/com/dapp/moviewebsite/app/appViewingRecords/dto/ViewingRecordsDto.java
  55. 38 0
      src/main/java/com/dapp/moviewebsite/app/appViewingRecords/pojo/AppViewingRecords.java
  56. 16 0
      src/main/java/com/dapp/moviewebsite/app/appViewingRecords/repository/AppViewingRecordsRepository.java
  57. 20 0
      src/main/java/com/dapp/moviewebsite/app/appViewingRecords/service/AppViewingRecordsService.java
  58. 72 0
      src/main/java/com/dapp/moviewebsite/app/appViewingRecords/service/AppViewingRecordsServiceImpl.java
  59. 33 0
      src/main/java/com/dapp/moviewebsite/app/appViewingRecords/vo/AppViewingRecordsSimpleVo.java
  60. 33 0
      src/main/java/com/dapp/moviewebsite/app/appViewingRecords/vo/AppViewingRecordsVo.java
  61. 98 0
      src/main/java/com/dapp/moviewebsite/app/controller/LoginController.java
  62. 10 0
      src/main/java/com/dapp/moviewebsite/app/enums/FavoriteType.java
  63. 10 0
      src/main/java/com/dapp/moviewebsite/app/enums/OperationType.java
  64. 17 0
      src/main/java/com/dapp/moviewebsite/common/VO/ResultVO.java
  65. 82 0
      src/main/java/com/dapp/moviewebsite/common/controller/CommonController.java
  66. 9 0
      src/main/java/com/dapp/moviewebsite/common/enums/CodeEnum.java
  67. 47 0
      src/main/java/com/dapp/moviewebsite/common/enums/ResultEnum.java
  68. 28 0
      src/main/java/com/dapp/moviewebsite/common/enums/UserEnum.java
  69. 107 0
      src/main/java/com/dapp/moviewebsite/common/exception/MyExceptionHandler.java
  70. 24 0
      src/main/java/com/dapp/moviewebsite/common/exception/UserException.java
  71. 22 0
      src/main/java/com/dapp/moviewebsite/common/pojo/IpVo.java
  72. 31 0
      src/main/java/com/dapp/moviewebsite/common/pojo/MonitorVo.java
  73. 39 0
      src/main/java/com/dapp/moviewebsite/common/pojo/PageCondition.java
  74. 83 0
      src/main/java/com/dapp/moviewebsite/common/pojo/PageInfo.java
  75. 42 0
      src/main/java/com/dapp/moviewebsite/common/pojo/ParameterRequestWrapper.java
  76. 79 0
      src/main/java/com/dapp/moviewebsite/common/pojo/Result.java
  77. 16 0
      src/main/java/com/dapp/moviewebsite/common/repository/CommonRepository.java
  78. 60 0
      src/main/java/com/dapp/moviewebsite/common/service/CommonService.java
  79. 313 0
      src/main/java/com/dapp/moviewebsite/common/service/CommonServiceImpl.java
  80. 166 0
      src/main/java/com/dapp/moviewebsite/common/utils/CacheUtils.java
  81. 561 0
      src/main/java/com/dapp/moviewebsite/common/utils/CodeDOM.java
  82. 141 0
      src/main/java/com/dapp/moviewebsite/common/utils/CopyUtil.java
  83. 123 0
      src/main/java/com/dapp/moviewebsite/common/utils/DoubleUtil.java
  84. 31 0
      src/main/java/com/dapp/moviewebsite/common/utils/ErrorUtil.java
  85. 29 0
      src/main/java/com/dapp/moviewebsite/common/utils/JsonUtils.java
  86. 43 0
      src/main/java/com/dapp/moviewebsite/common/utils/ResultVOUtil.java
  87. 16 0
      src/main/java/com/dapp/moviewebsite/common/utils/UUIDUtil.java
  88. 111 0
      src/main/java/com/dapp/moviewebsite/config/filter/JwtTokenUtil.java
  89. 165 0
      src/main/java/com/dapp/moviewebsite/config/filter/MovieWebsiteAppFilter.java
  90. 31 0
      src/main/java/com/dapp/moviewebsite/config/filter/RedisConfig.java
  91. 62 0
      src/main/java/com/dapp/moviewebsite/config/filter/TokenRequestWrapper.java
  92. 39 0
      src/main/java/com/dapp/moviewebsite/config/global/GlobalSecuritySetting.java
  93. 46 0
      src/main/java/com/dapp/moviewebsite/config/security/MovieWebsiteApplicationConfig.java
  94. 79 0
      src/main/java/com/dapp/moviewebsite/config/security/SecurityConfig.java
  95. 147 0
      src/main/java/com/dapp/moviewebsite/config/utils/IpUtil.java
  96. 21 0
      src/main/java/com/dapp/moviewebsite/config/utils/RedisConstant.java
  97. 165 0
      src/main/java/com/dapp/moviewebsite/config/utils/RedisSettingMap.java
  98. 14 0
      src/main/java/com/dapp/moviewebsite/config/utils/RedisType.java
  99. 68 0
      src/main/java/com/dapp/moviewebsite/demos/web/BasicController.java
  100. 45 0
      src/main/java/com/dapp/moviewebsite/demos/web/PathVariableController.java

+ 138 - 0
MovieWebsiteServer.iml

@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
+  <component name="FacetManager">
+    <facet type="Spring" name="Spring">
+      <configuration />
+    </facet>
+    <facet type="web" name="Web">
+      <configuration>
+        <webroots />
+      </configuration>
+    </facet>
+  </component>
+  <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
+    <output url="file://$MODULE_DIR$/target/classes" />
+    <output-test url="file://$MODULE_DIR$/target/test-classes" />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
+      <excludeFolder url="file://$MODULE_DIR$/target" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-data-jpa:2.6.4" level="project" />
+    <orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-aop:2.6.4" level="project" />
+    <orderEntry type="library" name="Maven: org.aspectj:aspectjweaver:1.9.7" level="project" />
+    <orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-jdbc:2.6.4" level="project" />
+    <orderEntry type="library" name="Maven: com.zaxxer:HikariCP:4.0.3" level="project" />
+    <orderEntry type="library" name="Maven: org.springframework:spring-jdbc:5.3.16" level="project" />
+    <orderEntry type="library" name="Maven: jakarta.transaction:jakarta.transaction-api:1.3.3" level="project" />
+    <orderEntry type="library" name="Maven: jakarta.persistence:jakarta.persistence-api:2.2.3" level="project" />
+    <orderEntry type="library" name="Maven: org.hibernate:hibernate-core:5.6.5.Final" level="project" />
+    <orderEntry type="library" name="Maven: net.bytebuddy:byte-buddy:1.11.22" level="project" />
+    <orderEntry type="library" name="Maven: antlr:antlr:2.7.7" level="project" />
+    <orderEntry type="library" name="Maven: org.jboss:jandex:2.4.2.Final" level="project" />
+    <orderEntry type="library" name="Maven: org.hibernate.common:hibernate-commons-annotations:5.1.2.Final" level="project" />
+    <orderEntry type="library" name="Maven: org.glassfish.jaxb:jaxb-runtime:2.3.6" level="project" />
+    <orderEntry type="library" name="Maven: org.glassfish.jaxb:txw2:2.3.6" level="project" />
+    <orderEntry type="library" name="Maven: com.sun.istack:istack-commons-runtime:3.0.12" level="project" />
+    <orderEntry type="library" scope="RUNTIME" name="Maven: com.sun.activation:jakarta.activation:1.2.2" level="project" />
+    <orderEntry type="library" name="Maven: org.springframework.data:spring-data-jpa:2.6.2" level="project" />
+    <orderEntry type="library" name="Maven: org.springframework.data:spring-data-commons:2.6.2" level="project" />
+    <orderEntry type="library" name="Maven: org.springframework:spring-orm:5.3.16" level="project" />
+    <orderEntry type="library" name="Maven: org.springframework:spring-context:5.3.16" level="project" />
+    <orderEntry type="library" name="Maven: org.springframework:spring-tx:5.3.16" level="project" />
+    <orderEntry type="library" name="Maven: org.springframework:spring-beans:5.3.16" level="project" />
+    <orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.36" level="project" />
+    <orderEntry type="library" name="Maven: org.springframework:spring-aspects:5.3.16" level="project" />
+    <orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-security:2.6.4" level="project" />
+    <orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter:2.6.4" level="project" />
+    <orderEntry type="library" name="Maven: org.springframework.boot:spring-boot:2.6.4" level="project" />
+    <orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-autoconfigure:2.6.4" level="project" />
+    <orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-logging:2.6.4" level="project" />
+    <orderEntry type="library" name="Maven: ch.qos.logback:logback-classic:1.2.10" level="project" />
+    <orderEntry type="library" name="Maven: ch.qos.logback:logback-core:1.2.10" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-to-slf4j:2.17.1" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-api:2.17.1" level="project" />
+    <orderEntry type="library" name="Maven: org.slf4j:jul-to-slf4j:1.7.36" level="project" />
+    <orderEntry type="library" name="Maven: jakarta.annotation:jakarta.annotation-api:1.3.5" level="project" />
+    <orderEntry type="library" name="Maven: org.yaml:snakeyaml:1.29" level="project" />
+    <orderEntry type="library" name="Maven: org.springframework:spring-aop:5.3.16" level="project" />
+    <orderEntry type="library" name="Maven: org.springframework.security:spring-security-config:5.6.2" level="project" />
+    <orderEntry type="library" name="Maven: org.springframework.security:spring-security-core:5.6.2" level="project" />
+    <orderEntry type="library" name="Maven: org.springframework.security:spring-security-crypto:5.6.2" level="project" />
+    <orderEntry type="library" name="Maven: org.springframework.security:spring-security-web:5.6.2" level="project" />
+    <orderEntry type="library" name="Maven: org.springframework:spring-expression:5.3.16" level="project" />
+    <orderEntry type="library" name="Maven: io.jsonwebtoken:jjwt:0.9.1" level="project" />
+    <orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.13.1" level="project" />
+    <orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.13.1" level="project" />
+    <orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-core:2.13.1" level="project" />
+    <orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-web:2.6.4" level="project" />
+    <orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-json:2.6.4" level="project" />
+    <orderEntry type="library" name="Maven: com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.13.1" level="project" />
+    <orderEntry type="library" name="Maven: com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.1" level="project" />
+    <orderEntry type="library" name="Maven: com.fasterxml.jackson.module:jackson-module-parameter-names:2.13.1" level="project" />
+    <orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-tomcat:2.6.4" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-core:9.0.58" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-el:9.0.58" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-websocket:9.0.58" level="project" />
+    <orderEntry type="library" name="Maven: org.springframework:spring-web:5.3.16" level="project" />
+    <orderEntry type="library" name="Maven: org.springframework:spring-webmvc:5.3.16" level="project" />
+    <orderEntry type="library" name="Maven: org.hibernate.validator:hibernate-validator:6.2.2.Final" level="project" />
+    <orderEntry type="library" name="Maven: jakarta.validation:jakarta.validation-api:2.0.2" level="project" />
+    <orderEntry type="library" name="Maven: org.jboss.logging:jboss-logging:3.4.3.Final" level="project" />
+    <orderEntry type="library" name="Maven: com.fasterxml:classmate:1.5.1" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-starter-test:2.6.4" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-test:2.6.4" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-test-autoconfigure:2.6.4" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: com.jayway.jsonpath:json-path:2.6.0" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: net.minidev:json-smart:2.4.8" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: net.minidev:accessors-smart:2.4.8" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: org.ow2.asm:asm:9.1" level="project" />
+    <orderEntry type="library" name="Maven: jakarta.xml.bind:jakarta.xml.bind-api:2.3.3" level="project" />
+    <orderEntry type="library" name="Maven: jakarta.activation:jakarta.activation-api:1.2.2" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: org.assertj:assertj-core:3.21.0" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest:2.2" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter:5.8.2" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter-api:5.8.2" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: org.opentest4j:opentest4j:1.2.0" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: org.junit.platform:junit-platform-commons:1.8.2" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: org.apiguardian:apiguardian-api:1.1.2" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter-params:5.8.2" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter-engine:5.8.2" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: org.junit.platform:junit-platform-engine:1.8.2" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: org.mockito:mockito-core:4.0.0" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: net.bytebuddy:byte-buddy-agent:1.11.22" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: org.objenesis:objenesis:3.2" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: org.mockito:mockito-junit-jupiter:4.0.0" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: org.skyscreamer:jsonassert:1.5.0" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: com.vaadin.external.google:android-json:0.0.20131108.vaadin1" level="project" />
+    <orderEntry type="library" name="Maven: org.springframework:spring-core:5.3.16" level="project" />
+    <orderEntry type="library" name="Maven: org.springframework:spring-jcl:5.3.16" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: org.springframework:spring-test:5.3.16" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: org.xmlunit:xmlunit-core:2.8.4" level="project" />
+    <orderEntry type="library" scope="RUNTIME" name="Maven: mysql:mysql-connector-java:8.0.28" level="project" />
+    <orderEntry type="library" name="Maven: org.projectlombok:lombok:1.18.22" level="project" />
+    <orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-data-redis:2.6.4" level="project" />
+    <orderEntry type="library" name="Maven: org.springframework.data:spring-data-redis:2.6.2" level="project" />
+    <orderEntry type="library" name="Maven: org.springframework.data:spring-data-keyvalue:2.6.2" level="project" />
+    <orderEntry type="library" name="Maven: org.springframework:spring-oxm:5.3.16" level="project" />
+    <orderEntry type="library" name="Maven: org.springframework:spring-context-support:5.3.16" level="project" />
+    <orderEntry type="library" name="Maven: io.lettuce:lettuce-core:6.1.6.RELEASE" level="project" />
+    <orderEntry type="library" name="Maven: io.netty:netty-common:4.1.74.Final" level="project" />
+    <orderEntry type="library" name="Maven: io.netty:netty-handler:4.1.74.Final" level="project" />
+    <orderEntry type="library" name="Maven: io.netty:netty-resolver:4.1.74.Final" level="project" />
+    <orderEntry type="library" name="Maven: io.netty:netty-buffer:4.1.74.Final" level="project" />
+    <orderEntry type="library" name="Maven: io.netty:netty-codec:4.1.74.Final" level="project" />
+    <orderEntry type="library" name="Maven: io.netty:netty-tcnative-classes:2.0.48.Final" level="project" />
+    <orderEntry type="library" name="Maven: io.netty:netty-transport:4.1.74.Final" level="project" />
+    <orderEntry type="library" name="Maven: io.projectreactor:reactor-core:3.4.15" level="project" />
+    <orderEntry type="library" name="Maven: org.reactivestreams:reactive-streams:1.0.3" level="project" />
+    <orderEntry type="library" name="Maven: commons-beanutils:commons-beanutils:1.8.0" level="project" />
+    <orderEntry type="library" name="Maven: commons-logging:commons-logging:1.1.1" level="project" />
+    <orderEntry type="library" name="Maven: commons-collections:commons-collections:3.2.2" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.9" level="project" />
+    <orderEntry type="library" name="Maven: cn.hutool:hutool-all:5.7.22" level="project" />
+    <orderEntry type="library" name="Maven: javax.validation:validation-api:2.0.1.Final" level="project" />
+  </component>
+</module>

+ 10 - 0
deploy.sh

@@ -0,0 +1,10 @@
+name="MovieWebsiteServer"
+port=30001
+pid=`lsof -i:$port | grep LISTEN | awk '{print $2}'`
+if [ $pid ]
+then
+kill -15 $pid
+echo stop $name
+fi
+nohup java -jar $name.jar > $name.txt 2>&1 &
+echo run $name

+ 310 - 0
mvnw

@@ -0,0 +1,310 @@
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#    https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+# Maven2 Start Up Batch script
+#
+# Required ENV vars:
+# ------------------
+#   JAVA_HOME - location of a JDK home dir
+#
+# Optional ENV vars
+# -----------------
+#   M2_HOME - location of maven2's installed home dir
+#   MAVEN_OPTS - parameters passed to the Java VM when running Maven
+#     e.g. to debug Maven itself, use
+#       set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+#   MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+# ----------------------------------------------------------------------------
+
+if [ -z "$MAVEN_SKIP_RC" ] ; then
+
+  if [ -f /etc/mavenrc ] ; then
+    . /etc/mavenrc
+  fi
+
+  if [ -f "$HOME/.mavenrc" ] ; then
+    . "$HOME/.mavenrc"
+  fi
+
+fi
+
+# OS specific support.  $var _must_ be set to either true or false.
+cygwin=false;
+darwin=false;
+mingw=false
+case "`uname`" in
+  CYGWIN*) cygwin=true ;;
+  MINGW*) mingw=true;;
+  Darwin*) darwin=true
+    # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
+    # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
+    if [ -z "$JAVA_HOME" ]; then
+      if [ -x "/usr/libexec/java_home" ]; then
+        export JAVA_HOME="`/usr/libexec/java_home`"
+      else
+        export JAVA_HOME="/Library/Java/Home"
+      fi
+    fi
+    ;;
+esac
+
+if [ -z "$JAVA_HOME" ] ; then
+  if [ -r /etc/gentoo-release ] ; then
+    JAVA_HOME=`java-config --jre-home`
+  fi
+fi
+
+if [ -z "$M2_HOME" ] ; then
+  ## resolve links - $0 may be a link to maven's home
+  PRG="$0"
+
+  # need this for relative symlinks
+  while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+      PRG="$link"
+    else
+      PRG="`dirname "$PRG"`/$link"
+    fi
+  done
+
+  saveddir=`pwd`
+
+  M2_HOME=`dirname "$PRG"`/..
+
+  # make it fully qualified
+  M2_HOME=`cd "$M2_HOME" && pwd`
+
+  cd "$saveddir"
+  # echo Using m2 at $M2_HOME
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin ; then
+  [ -n "$M2_HOME" ] &&
+    M2_HOME=`cygpath --unix "$M2_HOME"`
+  [ -n "$JAVA_HOME" ] &&
+    JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+  [ -n "$CLASSPATH" ] &&
+    CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
+fi
+
+# For Mingw, ensure paths are in UNIX format before anything is touched
+if $mingw ; then
+  [ -n "$M2_HOME" ] &&
+    M2_HOME="`(cd "$M2_HOME"; pwd)`"
+  [ -n "$JAVA_HOME" ] &&
+    JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
+fi
+
+if [ -z "$JAVA_HOME" ]; then
+  javaExecutable="`which javac`"
+  if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
+    # readlink(1) is not available as standard on Solaris 10.
+    readLink=`which readlink`
+    if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
+      if $darwin ; then
+        javaHome="`dirname \"$javaExecutable\"`"
+        javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
+      else
+        javaExecutable="`readlink -f \"$javaExecutable\"`"
+      fi
+      javaHome="`dirname \"$javaExecutable\"`"
+      javaHome=`expr "$javaHome" : '\(.*\)/bin'`
+      JAVA_HOME="$javaHome"
+      export JAVA_HOME
+    fi
+  fi
+fi
+
+if [ -z "$JAVACMD" ] ; then
+  if [ -n "$JAVA_HOME"  ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+      # IBM's JDK on AIX uses strange locations for the executables
+      JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+      JAVACMD="$JAVA_HOME/bin/java"
+    fi
+  else
+    JAVACMD="`which java`"
+  fi
+fi
+
+if [ ! -x "$JAVACMD" ] ; then
+  echo "Error: JAVA_HOME is not defined correctly." >&2
+  echo "  We cannot execute $JAVACMD" >&2
+  exit 1
+fi
+
+if [ -z "$JAVA_HOME" ] ; then
+  echo "Warning: JAVA_HOME environment variable is not set."
+fi
+
+CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
+
+# traverses directory structure from process work directory to filesystem root
+# first directory with .mvn subdirectory is considered project base directory
+find_maven_basedir() {
+
+  if [ -z "$1" ]
+  then
+    echo "Path not specified to find_maven_basedir"
+    return 1
+  fi
+
+  basedir="$1"
+  wdir="$1"
+  while [ "$wdir" != '/' ] ; do
+    if [ -d "$wdir"/.mvn ] ; then
+      basedir=$wdir
+      break
+    fi
+    # workaround for JBEAP-8937 (on Solaris 10/Sparc)
+    if [ -d "${wdir}" ]; then
+      wdir=`cd "$wdir/.."; pwd`
+    fi
+    # end of workaround
+  done
+  echo "${basedir}"
+}
+
+# concatenates all lines of a file
+concat_lines() {
+  if [ -f "$1" ]; then
+    echo "$(tr -s '\n' ' ' < "$1")"
+  fi
+}
+
+BASE_DIR=`find_maven_basedir "$(pwd)"`
+if [ -z "$BASE_DIR" ]; then
+  exit 1;
+fi
+
+##########################################################################################
+# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+# This allows using the maven wrapper in projects that prohibit checking in binary data.
+##########################################################################################
+if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
+    if [ "$MVNW_VERBOSE" = true ]; then
+      echo "Found .mvn/wrapper/maven-wrapper.jar"
+    fi
+else
+    if [ "$MVNW_VERBOSE" = true ]; then
+      echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
+    fi
+    if [ -n "$MVNW_REPOURL" ]; then
+      jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
+    else
+      jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
+    fi
+    while IFS="=" read key value; do
+      case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
+      esac
+    done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
+    if [ "$MVNW_VERBOSE" = true ]; then
+      echo "Downloading from: $jarUrl"
+    fi
+    wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
+    if $cygwin; then
+      wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
+    fi
+
+    if command -v wget > /dev/null; then
+        if [ "$MVNW_VERBOSE" = true ]; then
+          echo "Found wget ... using wget"
+        fi
+        if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+            wget "$jarUrl" -O "$wrapperJarPath"
+        else
+            wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
+        fi
+    elif command -v curl > /dev/null; then
+        if [ "$MVNW_VERBOSE" = true ]; then
+          echo "Found curl ... using curl"
+        fi
+        if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+            curl -o "$wrapperJarPath" "$jarUrl" -f
+        else
+            curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
+        fi
+        
+    else
+        if [ "$MVNW_VERBOSE" = true ]; then
+          echo "Falling back to using Java to download"
+        fi
+        javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
+        # For Cygwin, switch paths to Windows format before running javac
+        if $cygwin; then
+          javaClass=`cygpath --path --windows "$javaClass"`
+        fi
+        if [ -e "$javaClass" ]; then
+            if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+                if [ "$MVNW_VERBOSE" = true ]; then
+                  echo " - Compiling MavenWrapperDownloader.java ..."
+                fi
+                # Compiling the Java class
+                ("$JAVA_HOME/bin/javac" "$javaClass")
+            fi
+            if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+                # Running the downloader
+                if [ "$MVNW_VERBOSE" = true ]; then
+                  echo " - Running MavenWrapperDownloader.java ..."
+                fi
+                ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
+            fi
+        fi
+    fi
+fi
+##########################################################################################
+# End of extension
+##########################################################################################
+
+export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
+if [ "$MVNW_VERBOSE" = true ]; then
+  echo $MAVEN_PROJECTBASEDIR
+fi
+MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+  [ -n "$M2_HOME" ] &&
+    M2_HOME=`cygpath --path --windows "$M2_HOME"`
+  [ -n "$JAVA_HOME" ] &&
+    JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
+  [ -n "$CLASSPATH" ] &&
+    CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
+  [ -n "$MAVEN_PROJECTBASEDIR" ] &&
+    MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
+fi
+
+# Provide a "standardized" way to retrieve the CLI args that will
+# work with both Windows and non-Windows executions.
+MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
+export MAVEN_CMD_LINE_ARGS
+
+WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+exec "$JAVACMD" \
+  $MAVEN_OPTS \
+  -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
+  "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
+  ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"

+ 182 - 0
mvnw.cmd

@@ -0,0 +1,182 @@
+@REM ----------------------------------------------------------------------------
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements.  See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership.  The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License.  You may obtain a copy of the License at
+@REM
+@REM    https://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied.  See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM ----------------------------------------------------------------------------
+
+@REM ----------------------------------------------------------------------------
+@REM Maven2 Start Up Batch script
+@REM
+@REM Required ENV vars:
+@REM JAVA_HOME - location of a JDK home dir
+@REM
+@REM Optional ENV vars
+@REM M2_HOME - location of maven2's installed home dir
+@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
+@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
+@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
+@REM     e.g. to debug Maven itself, use
+@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+@REM ----------------------------------------------------------------------------
+
+@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
+@echo off
+@REM set title of command window
+title %0
+@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
+@if "%MAVEN_BATCH_ECHO%" == "on"  echo %MAVEN_BATCH_ECHO%
+
+@REM set %HOME% to equivalent of $HOME
+if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
+
+@REM Execute a user defined script before this one
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
+@REM check for pre script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
+if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
+:skipRcPre
+
+@setlocal
+
+set ERROR_CODE=0
+
+@REM To isolate internal variables from possible post scripts, we use another setlocal
+@setlocal
+
+@REM ==== START VALIDATION ====
+if not "%JAVA_HOME%" == "" goto OkJHome
+
+echo.
+echo Error: JAVA_HOME not found in your environment. >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+:OkJHome
+if exist "%JAVA_HOME%\bin\java.exe" goto init
+
+echo.
+echo Error: JAVA_HOME is set to an invalid directory. >&2
+echo JAVA_HOME = "%JAVA_HOME%" >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+@REM ==== END VALIDATION ====
+
+:init
+
+@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
+@REM Fallback to current working directory if not found.
+
+set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
+IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
+
+set EXEC_DIR=%CD%
+set WDIR=%EXEC_DIR%
+:findBaseDir
+IF EXIST "%WDIR%"\.mvn goto baseDirFound
+cd ..
+IF "%WDIR%"=="%CD%" goto baseDirNotFound
+set WDIR=%CD%
+goto findBaseDir
+
+:baseDirFound
+set MAVEN_PROJECTBASEDIR=%WDIR%
+cd "%EXEC_DIR%"
+goto endDetectBaseDir
+
+:baseDirNotFound
+set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
+cd "%EXEC_DIR%"
+
+:endDetectBaseDir
+
+IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
+
+@setlocal EnableExtensions EnableDelayedExpansion
+for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
+@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
+
+:endReadAdditionalConfig
+
+SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
+set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
+set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
+
+FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
+    IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
+)
+
+@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
+if exist %WRAPPER_JAR% (
+    if "%MVNW_VERBOSE%" == "true" (
+        echo Found %WRAPPER_JAR%
+    )
+) else (
+    if not "%MVNW_REPOURL%" == "" (
+        SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
+    )
+    if "%MVNW_VERBOSE%" == "true" (
+        echo Couldn't find %WRAPPER_JAR%, downloading it ...
+        echo Downloading from: %DOWNLOAD_URL%
+    )
+
+    powershell -Command "&{"^
+		"$webclient = new-object System.Net.WebClient;"^
+		"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
+		"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
+		"}"^
+		"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
+		"}"
+    if "%MVNW_VERBOSE%" == "true" (
+        echo Finished downloading %WRAPPER_JAR%
+    )
+)
+@REM End of extension
+
+@REM Provide a "standardized" way to retrieve the CLI args that will
+@REM work with both Windows and non-Windows executions.
+set MAVEN_CMD_LINE_ARGS=%*
+
+%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
+if ERRORLEVEL 1 goto error
+goto end
+
+:error
+set ERROR_CODE=1
+
+:end
+@endlocal & set ERROR_CODE=%ERROR_CODE%
+
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
+@REM check for post script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
+if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
+:skipRcPost
+
+@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
+if "%MAVEN_BATCH_PAUSE%" == "on" pause
+
+if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
+
+exit /B %ERROR_CODE%

+ 136 - 0
pom.xml

@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>2.6.4</version>
+        <relativePath/> <!-- lookup parent from repository -->
+    </parent>
+    <groupId>com.dapp</groupId>
+    <artifactId>moviewebsite</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <name>MovieWebsite</name>
+    <description>MovieWebsite project for Spring Boot</description>
+
+    <properties>
+        <java.version>1.8</java.version>
+    </properties>
+
+    <dependencies>
+           <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-jpa</artifactId>
+        </dependency>
+        <!--<dependency>-->
+        <!--    <groupId>org.springframework.boot</groupId>-->
+        <!--    <artifactId>spring-boot-starter-oauth2-client</artifactId>-->
+        <!--</dependency>-->
+        <!--<dependency>-->
+        <!--    <groupId>org.springframework.boot</groupId>-->
+        <!--    <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>-->
+        <!--</dependency>-->
+        <!-- Spring Security -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-security</artifactId>
+        </dependency>
+        <!-- Spring Security OAuth2 -->
+        <!--<dependency>-->
+        <!--    <groupId>org.springframework.security.oauth</groupId>-->
+        <!--    <artifactId>spring-security-oauth2</artifactId>-->
+        <!--    <version>2.3.6.RELEASE</version>-->
+        <!--</dependency>-->
+        <!-- JWT -->
+        <dependency>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt</artifactId>
+            <version>0.9.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+
+        <!-- 使用 body 校验注解时候需要添加-->
+        <dependency>
+            <groupId>org.hibernate.validator</groupId>
+            <artifactId>hibernate-validator</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <!--<dependency>-->
+        <!--    <groupId>org.springframework.security</groupId>-->
+        <!--    <artifactId>spring-security-test</artifactId>-->
+        <!--    <scope>test</scope>-->
+        <!--</dependency>-->
+
+        <!--mysql-->
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+            <scope>runtime</scope>
+        </dependency>
+
+        <!--添加lombok工具,需要在plugin下载-->
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+
+        <!--缓存服务-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+        </dependency>
+        <!-- CopyUtil需要用到 -->
+        <dependency>
+            <groupId>commons-beanutils</groupId>
+            <artifactId>commons-beanutils</artifactId>
+            <version>1.8.0</version>
+        </dependency>
+        <dependency>
+            <groupId>commons-collections</groupId>
+            <artifactId>commons-collections</artifactId>
+            <version>3.2.2</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.9</version>
+        </dependency>
+
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+            <version>5.7.22</version>
+        </dependency>
+
+        <dependency>
+            <groupId>javax.validation</groupId>
+            <artifactId>validation-api</artifactId>
+            <version>2.0.1.Final</version>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <finalName>MovieWebsiteServer</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <!--  启动修改之后实时生效   -->
+                <configuration>
+                    <!--<fork>true</fork>-->
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

二进制
src/.DS_Store


二进制
src/main/.DS_Store


+ 59 - 0
src/main/java/com/dapp/moviewebsite/MovieWebsiteApplication.java

@@ -0,0 +1,59 @@
+package com.dapp.moviewebsite;
+
+import com.dapp.moviewebsite.config.global.GlobalSecuritySetting;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.web.servlet.ServletComponentScan;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+@SpringBootApplication
+@EnableCaching//开启基于注解缓存
+//@ServletComponentScan(basePackages = "com.dapp.moviewebsite")
+public class MovieWebsiteApplication {
+
+    public static void main(String[] args) {
+        GlobalSecuritySetting.init();
+        SpringApplication.run(MovieWebsiteApplication.class, args);
+    }
+
+}
+
+@Slf4j
+@Controller
+@RequestMapping("/")
+@Configuration
+class IndexController {
+    @Value("${server.servlet.context-path:}")
+    private String contextPath;
+    /**
+     * 端口
+     */
+    @Value("${server.port}")
+    private String port;
+    /**
+     * 启动成功
+     */
+    @Bean
+    public ApplicationRunner applicationRunner() {
+        return applicationArguments -> {
+            try {
+                //获取本机内网IP
+                log.info("启动成功:" + "http://" + InetAddress.getLocalHost().getHostAddress() + ":" + port + contextPath);
+            } catch (UnknownHostException e) {
+                //输出到日志文件中
+                log.error(e.getMessage());
+            }
+        };
+    }
+
+}

+ 21 - 0
src/main/java/com/dapp/moviewebsite/annotation/Between.java

@@ -0,0 +1,21 @@
+package com.dapp.moviewebsite.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Between {
+
+    /**
+     * 最小值的实体属性名
+     */
+    String min();
+
+    /**
+     * 最大值的实体属性名
+     */
+    String max();
+}

+ 12 - 0
src/main/java/com/dapp/moviewebsite/annotation/Decrypt.java

@@ -0,0 +1,12 @@
+package com.dapp.moviewebsite.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Decrypt {
+
+}

+ 12 - 0
src/main/java/com/dapp/moviewebsite/annotation/Encrypt.java

@@ -0,0 +1,12 @@
+package com.dapp.moviewebsite.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Encrypt {
+
+}

+ 16 - 0
src/main/java/com/dapp/moviewebsite/annotation/In.java

@@ -0,0 +1,16 @@
+package com.dapp.moviewebsite.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface In {
+
+    /**
+     * in的具体集合的属性名
+     */
+    String values();
+}

+ 13 - 0
src/main/java/com/dapp/moviewebsite/annotation/Like.java

@@ -0,0 +1,13 @@
+package com.dapp.moviewebsite.annotation;
+
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Like {
+
+}

+ 26 - 0
src/main/java/com/dapp/moviewebsite/annotation/RedisUpdate.java

@@ -0,0 +1,26 @@
+package com.dapp.moviewebsite.annotation;
+
+import com.dapp.moviewebsite.config.utils.RedisType;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface RedisUpdate {
+
+    /**
+     * key值,对应redis里面的key
+     * @return
+     */
+    String key() default "";
+
+    /**
+     * 当前枚举策略
+     * @return
+     */
+    RedisType strategy() default RedisType.NULL;
+
+}

+ 128 - 0
src/main/java/com/dapp/moviewebsite/app/appFavorite/controller/AppFavoriteController.java

@@ -0,0 +1,128 @@
+package com.dapp.moviewebsite.app.appFavorite.controller;
+
+import com.dapp.moviewebsite.app.appFavorite.vo.AppFavoriteSimpleVo;
+import com.dapp.moviewebsite.app.appVideos.service.AppVideosService;
+import com.dapp.moviewebsite.app.appVideos.vo.AppVideosVo;
+import com.dapp.moviewebsite.common.VO.ResultVO;
+import com.dapp.moviewebsite.common.controller.*;
+import com.dapp.moviewebsite.app.appFavorite.pojo.AppFavorite;
+import com.dapp.moviewebsite.app.appFavorite.vo.AppFavoriteVo;
+import com.dapp.moviewebsite.app.appFavorite.service.AppFavoriteService;
+import com.dapp.moviewebsite.common.enums.ResultEnum;
+import com.dapp.moviewebsite.common.exception.UserException;
+import com.dapp.moviewebsite.common.pojo.PageInfo;
+import com.dapp.moviewebsite.common.pojo.Result;
+import com.dapp.moviewebsite.common.utils.CopyUtil;
+import com.dapp.moviewebsite.common.utils.ResultVOUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotBlank;
+import java.util.List;
+
+@Slf4j
+@Validated
+@RestController
+@RequestMapping("/favorite/")
+public class AppFavoriteController extends CommonController<AppFavoriteVo, AppFavorite, Integer> {
+
+    @Autowired
+    private AppFavoriteService appFavoriteService;
+
+    @Autowired
+    private AppVideosService appVideosService;
+
+    /**
+     * 使用url操作收藏视频
+     * @param userId
+     * @param videoUrl
+     * @return
+     */
+    @GetMapping("/add")
+    public ResultVO addByUrl(@RequestParam("userId") String userId,
+                             @RequestParam("videoUrl") @NotBlank(message = "videoUrl 字符串不能为空且不能只包含空白字符") String videoUrl
+    ) {
+        AppVideosVo appVideosVo = appVideosService.findByUrl(videoUrl);
+        if(appVideosVo == null){
+            //先判断是否存在视频
+            return ResultVOUtil.error(ResultEnum.VIEWING_RECORDS_CANCEL_ERROR);
+        }
+        //查询收藏表
+        AppFavoriteVo appFavoriteVo = appFavoriteService.addAppFavoriteVo(userId, appVideosVo.getId(),appVideosVo.getUrl());
+        appFavoriteVo.setVideoName(appVideosVo.getVideoName());
+        appFavoriteVo.setUrl(appVideosVo.getUrl());
+        appFavoriteVo.setVideoPoster(appVideosVo.getVideoPoster());
+        AppFavoriteSimpleVo  appFavoriteSimpleVo = CopyUtil.copy(appFavoriteVo,AppFavoriteSimpleVo.class);
+        return ResultVOUtil.success(appFavoriteSimpleVo);
+    }
+    /**
+     * 取消收藏
+     * @param userId
+     * @param videoUrl
+     * @return
+     */
+    @GetMapping("/cancel")
+    public ResultVO cancel(@RequestParam("userId") String userId,
+                        @RequestParam("videoUrl") @NotBlank(message = "videoUrl 字符串不能为空且不能只包含空白字符") String videoUrl
+    ) {
+        AppVideosVo appVideosVo = appVideosService.findByUrl(videoUrl);
+        if(appVideosVo == null){
+            //先判断是否存在视频
+            return ResultVOUtil.error(ResultEnum.VIEWING_RECORDS_CANCEL_ERROR);
+        }
+        AppFavorite appFavorite = appFavoriteService.findByUserIdAndVideoId(userId,appVideosVo.getId());
+        if(appFavorite != null){
+            appFavoriteService.delete(appFavorite.getId());
+            ResultVO resultVO = new ResultVO();
+            resultVO.setCode(0);
+            resultVO.setMsg(ResultEnum.FAVORITE_CANCEL_SUCCESS.getMessage());
+            return resultVO;
+        } else {
+            return ResultVOUtil.error(ResultEnum.FAVORITE_CANCEL_ERROR);
+        }
+
+    }
+
+    /**
+     * 分页查询视频
+     * @param userId
+     * @param page
+     * @param size
+     * @return
+     */
+    @GetMapping("/page")
+    public ResultVO page(@RequestParam("userId") String userId,
+                         @RequestParam(value = "page",defaultValue = "1") @Min(value = 1, message = "page必须大于等于1")  Integer page,
+                         @RequestParam(value = "size",defaultValue = "10") @Min(value = 1, message = "size必须大于等于1") Integer size) {
+        try {
+            AppFavoriteVo appFavoriteVo = new AppFavoriteVo();
+            appFavoriteVo.setUserId(userId);
+            appFavoriteVo.setPage(page);
+            appFavoriteVo.setRows(size);
+            appFavoriteVo.setSidx("DESC");
+            appFavoriteVo.setSord("updateTime");
+
+            //处理视频信息
+            PageInfo pageInfo = appFavoriteService.pageByClass(appFavoriteVo,AppFavoriteSimpleVo.class);
+            List<AppFavoriteSimpleVo> list = pageInfo.getRows();
+            for (AppFavoriteSimpleVo vo :list){
+                AppVideosVo _appVideosVo = appVideosService.getVo(vo.getVideoId());
+                if(_appVideosVo !=null){
+                    vo.setUrl(_appVideosVo.getUrl());
+                    vo.setVideoName(_appVideosVo.getVideoName());
+                    vo.setVideoPoster(_appVideosVo.getVideoPoster());
+                }
+            }
+            pageInfo.setRows(list);
+            return ResultVOUtil.success(pageInfo);
+        } catch (UserException e) {
+            return ResultVOUtil.error(e.getCode(), e.getMessage());
+        }
+
+    }
+
+
+}

+ 36 - 0
src/main/java/com/dapp/moviewebsite/app/appFavorite/pojo/AppFavorite.java

@@ -0,0 +1,36 @@
+package com.dapp.moviewebsite.app.appFavorite.pojo;
+
+import lombok.Data;
+import javax.persistence.*;
+import java.io.Serializable;
+import java.util.Date;
+
+@Entity
+@Table(name = "app_favorite")
+@Data
+public class AppFavorite implements Serializable {
+    @Id
+    @GeneratedValue(strategy= GenerationType.IDENTITY)
+    private Integer id;//
+
+    private String userId;//后台自己的用户id
+
+    private Integer videoId;
+
+    private Integer type;//收藏类型:0:other,1:视频
+
+    private String videoName;//视频名字
+
+    private String url;//视频路径
+
+    private Integer duration;//视频时长
+
+    private Integer currentSet;//当前集数
+
+    private String videoPoster;//视频海报
+
+    private Date createTime;//
+
+    private Date updateTime;//
+
+}

+ 16 - 0
src/main/java/com/dapp/moviewebsite/app/appFavorite/repository/AppFavoriteRepository.java

@@ -0,0 +1,16 @@
+package com.dapp.moviewebsite.app.appFavorite.repository;
+
+import com.dapp.moviewebsite.common.repository.*;
+import com.dapp.moviewebsite.app.appFavorite.pojo.AppFavorite;
+import org.springframework.stereotype.Repository;
+
+import java.util.Optional;
+
+@Repository
+public interface AppFavoriteRepository extends CommonRepository<AppFavorite, Integer> {
+
+    //根据用户id和视频url查找
+    Optional<AppFavorite> findByUserIdAndUrl(String userId,String Url);
+
+    Optional<AppFavorite> findByUserIdAndVideoId(String userId,Integer videoId);
+}

+ 28 - 0
src/main/java/com/dapp/moviewebsite/app/appFavorite/service/AppFavoriteService.java

@@ -0,0 +1,28 @@
+package com.dapp.moviewebsite.app.appFavorite.service;
+
+import com.dapp.moviewebsite.app.appFavorite.repository.AppFavoriteRepository;
+import com.dapp.moviewebsite.app.appFavorite.vo.AppFavoriteSimpleVo;
+import com.dapp.moviewebsite.common.service.*;
+import com.dapp.moviewebsite.app.appFavorite.pojo.AppFavorite;
+import com.dapp.moviewebsite.app.appFavorite.vo.AppFavoriteVo;
+import org.springframework.beans.factory.annotation.Autowired;
+
+public interface AppFavoriteService extends CommonService<AppFavoriteVo, AppFavorite, Integer> {
+    AppFavorite findByUserIdAndUrl(String userId , String url);
+
+    AppFavorite findByUserIdAndVideoId(String userId ,Integer videoId);
+
+    //添加收藏操作
+    AppFavoriteVo addAppFavoriteVo( String userId,
+                                    String videoUrl,
+                                    String name,
+                                    Integer duration,
+                                    Integer currentSet,
+                                    String poster );
+
+    //添加收藏操作
+    AppFavoriteVo addAppFavoriteVoByUrl( String userId, String videoUrl);
+
+
+    AppFavoriteVo addAppFavoriteVo( String userId, Integer videoId, String videoUrl);
+}

+ 117 - 0
src/main/java/com/dapp/moviewebsite/app/appFavorite/service/AppFavoriteServiceImpl.java

@@ -0,0 +1,117 @@
+package com.dapp.moviewebsite.app.appFavorite.service;
+
+import cn.hutool.core.date.DateUtil;
+import com.dapp.moviewebsite.app.appFavorite.vo.AppFavoriteSimpleVo;
+import com.dapp.moviewebsite.app.appVideos.service.AppVideosService;
+import com.dapp.moviewebsite.app.appVideos.vo.AppVideosVo;
+import com.dapp.moviewebsite.app.enums.FavoriteType;
+import com.dapp.moviewebsite.common.service.*;
+import com.dapp.moviewebsite.app.appFavorite.pojo.AppFavorite;
+import com.dapp.moviewebsite.app.appFavorite.vo.AppFavoriteVo;
+import com.dapp.moviewebsite.app.appFavorite.repository.AppFavoriteRepository;
+import com.dapp.moviewebsite.common.utils.CopyUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+
+@Service
+@Transactional
+public class AppFavoriteServiceImpl extends CommonServiceImpl<AppFavoriteVo, AppFavorite, Integer> implements AppFavoriteService{
+
+    @PersistenceContext
+    private EntityManager em;
+    @Autowired
+    private AppFavoriteRepository appFavoriteRepository;
+
+
+    @Autowired
+    private AppVideosService appVideosService;
+
+
+    @Override
+    public AppFavorite findByUserIdAndUrl(String userId, String url) {
+        return appFavoriteRepository.findByUserIdAndUrl(userId,url).orElse(null);
+    }
+
+    @Override
+    public AppFavorite findByUserIdAndVideoId(String userId,Integer videoId) {
+        return appFavoriteRepository.findByUserIdAndVideoId(userId,videoId).orElse(null);
+    }
+
+    /**
+     * 添加一个收藏视频
+     * @param videoUrl
+     * @param name
+     * @param duration
+     * @param currentSet
+     * @param poster
+     * @return
+     */
+    @Override
+    @Transactional
+    public AppFavoriteVo addAppFavoriteVo( String userId,
+                                           String videoUrl,
+                                           String name,
+                                           Integer duration,
+                                           Integer currentSet,
+                                           String poster) {
+
+        AppFavorite appFavorite = findByUserIdAndUrl(userId,videoUrl);
+        if(appFavorite == null){
+            AppFavoriteVo appFavoriteVo = new AppFavoriteVo();
+            appFavoriteVo.setUserId(userId);
+            appFavoriteVo.setUrl(videoUrl);
+            appFavoriteVo.setVideoName(name);
+            appFavoriteVo.setDuration(duration);
+            appFavoriteVo.setCurrentSet(currentSet);
+            appFavoriteVo.setVideoPoster(poster);
+            appFavoriteVo.setType(FavoriteType.video.ordinal());
+            appFavoriteVo.setCreateTime(DateUtil.date());
+            appFavoriteVo.setUpdateTime(DateUtil.date());
+            appFavoriteVo = saveReturnVo(appFavoriteVo);
+            return appFavoriteVo;
+        } else {
+            return CopyUtil.copy(appFavorite,AppFavoriteVo.class);
+        }
+
+    }
+
+    @Override
+    public AppFavoriteVo addAppFavoriteVoByUrl(String userId, String videoUrl) {
+        AppFavorite appFavorite = findByUserIdAndUrl(userId,videoUrl);
+        if(appFavorite == null){
+            AppFavoriteVo appFavoriteVo = new AppFavoriteVo();
+            appFavoriteVo.setUserId(userId);
+            appFavoriteVo.setUrl(videoUrl);
+            appFavoriteVo.setType(FavoriteType.video.ordinal());
+            appFavoriteVo.setCreateTime(DateUtil.date());
+            appFavoriteVo.setUpdateTime(DateUtil.date());
+            appFavoriteVo = saveReturnVo(appFavoriteVo);
+            return appFavoriteVo;
+        } else {
+            return CopyUtil.copy(appFavorite,AppFavoriteVo.class);
+        }
+    }
+
+    @Override
+    @Transactional
+    public AppFavoriteVo addAppFavoriteVo(String userId, Integer videoId , String videoUrl) {
+        AppFavorite appFavorite = findByUserIdAndVideoId(userId,videoId);
+        if(appFavorite == null){
+            AppFavoriteVo appFavoriteVo = new AppFavoriteVo();
+            appFavoriteVo.setUserId(userId);
+            appFavoriteVo.setVideoId(videoId);
+            //appFavoriteVo.setUrl(videoUrl);
+            appFavoriteVo.setType(FavoriteType.video.ordinal());
+            appFavoriteVo.setCreateTime(DateUtil.date());
+            appFavoriteVo.setUpdateTime(DateUtil.date());
+            appFavoriteVo = saveReturnVo(appFavoriteVo);
+            return appFavoriteVo;
+        } else {
+            return CopyUtil.copy(appFavorite,AppFavoriteVo.class);
+        }
+    }
+
+}

+ 31 - 0
src/main/java/com/dapp/moviewebsite/app/appFavorite/vo/AppFavoriteSimpleVo.java

@@ -0,0 +1,31 @@
+package com.dapp.moviewebsite.app.appFavorite.vo;
+
+import lombok.Data;
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+public class AppFavoriteSimpleVo implements Serializable {
+    //private Integer id;//
+
+    //private String userId;//后台自己的用户id
+
+    private Integer type;//收藏类型:0:other,1:视频
+
+    private Integer videoId;
+
+    private String videoName;//视频名字
+
+    private String url;//视频路径
+
+    //private Integer duration;//视频时长
+
+    //private Integer currentSet;//当前集数
+
+    private String videoPoster;//视频海报
+
+    private Date createTime;//
+
+    private Date updateTime;//
+
+}

+ 31 - 0
src/main/java/com/dapp/moviewebsite/app/appFavorite/vo/AppFavoriteVo.java

@@ -0,0 +1,31 @@
+package com.dapp.moviewebsite.app.appFavorite.vo;
+
+import com.dapp.moviewebsite. common.pojo.PageCondition;import lombok.Data;
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+public class AppFavoriteVo extends PageCondition implements Serializable {
+    private Integer id;//
+
+    private String userId;//后台自己的用户id
+
+    private Integer videoId;
+
+    private Integer type;//收藏类型:0:other,1:视频
+
+    private String videoName;//视频名字
+
+    private String url;//视频路径
+
+    private Integer duration;//视频时长
+
+    private Integer currentSet;//当前集数
+
+    private String videoPoster;//视频海报
+
+    private Date createTime;//
+
+    private Date updateTime;//
+
+}

+ 15 - 0
src/main/java/com/dapp/moviewebsite/app/appUser/controller/AppUserController.java

@@ -0,0 +1,15 @@
+package com.dapp.moviewebsite.app.appUser.controller;
+
+import com.dapp.moviewebsite.common.controller.*;
+import com.dapp.moviewebsite.app.appUser.pojo.AppUser;
+import com.dapp.moviewebsite.app.appUser.vo.AppUserVo;
+import com.dapp.moviewebsite.app.appUser.service.AppUserService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequestMapping("/User/")
+public class AppUserController extends CommonController<AppUserVo, AppUser, String> {
+    @Autowired
+    private AppUserService appUserService;
+}

+ 35 - 0
src/main/java/com/dapp/moviewebsite/app/appUser/pojo/AppUser.java

@@ -0,0 +1,35 @@
+package com.dapp.moviewebsite.app.appUser.pojo;
+
+import lombok.Data;
+import javax.persistence.*;
+import java.io.Serializable;
+import java.util.Date;
+
+@Entity
+@Table(name = "app_user")
+@Data
+public class AppUser implements Serializable {
+    @Id
+    private String userId;//用户id
+
+    private String loginName;//登录名
+
+    private String userName;//用户名称
+
+    private String password;//登录密码
+
+    private Integer valid;//软删除标识,1/0
+
+    private String limitedIp;//限制允许登录的IP集合
+
+    private Date expiredTime;//账号失效时间,超过时间将不能登录系统
+
+    private Date lastChangePwdTime;//最近修改密码时间,超出时间间隔,提示用户修改密码
+
+    private Integer limitMultiLogin;//是否允许账号同一个时刻多人在线,1/0
+
+    private Date createTime;//创建时间
+
+    private Date updateTime;//修改时间
+
+}

+ 9 - 0
src/main/java/com/dapp/moviewebsite/app/appUser/repository/AppUserRepository.java

@@ -0,0 +1,9 @@
+package com.dapp.moviewebsite.app.appUser.repository;
+
+import com.dapp.moviewebsite.common.repository.*;
+import com.dapp.moviewebsite.app.appUser.pojo.AppUser;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface AppUserRepository extends CommonRepository<AppUser, String> {
+}

+ 9 - 0
src/main/java/com/dapp/moviewebsite/app/appUser/service/AppUserService.java

@@ -0,0 +1,9 @@
+package com.dapp.moviewebsite.app.appUser.service;
+
+import com.dapp.moviewebsite.common.service.*;
+import com.dapp.moviewebsite.app.appUser.pojo.AppUser;
+import com.dapp.moviewebsite.app.appUser.vo.AppUserVo;
+
+public interface AppUserService extends CommonService<AppUserVo, AppUser, String> {
+
+}

+ 21 - 0
src/main/java/com/dapp/moviewebsite/app/appUser/service/AppUserServiceImpl.java

@@ -0,0 +1,21 @@
+package com.dapp.moviewebsite.app.appUser.service;
+
+import com.dapp.moviewebsite.common.service.*;
+import com.dapp.moviewebsite.app.appUser.pojo.AppUser;
+import com.dapp.moviewebsite.app.appUser.vo.AppUserVo;
+import com.dapp.moviewebsite.app.appUser.repository.AppUserRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+
+@Service
+@Transactional
+public class AppUserServiceImpl extends CommonServiceImpl<AppUserVo, AppUser, String> implements AppUserService{
+
+    @PersistenceContext
+    private EntityManager em;
+    @Autowired
+    private AppUserRepository appUserRepository;
+}

+ 31 - 0
src/main/java/com/dapp/moviewebsite/app/appUser/vo/AppUserSimpleVo.java

@@ -0,0 +1,31 @@
+package com.dapp.moviewebsite.app.appUser.vo;
+
+import lombok.Data;
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+public class AppUserSimpleVo implements Serializable {
+    private String userId;//用户id
+
+    private String loginName;//登录名
+
+    private String userName;//用户名称
+
+    private String password;//登录密码
+
+    private Integer valid;//软删除标识,1/0
+
+    private String limitedIp;//限制允许登录的IP集合
+
+    private Date expiredTime;//账号失效时间,超过时间将不能登录系统
+
+    private Date lastChangePwdTime;//最近修改密码时间,超出时间间隔,提示用户修改密码
+
+    private Integer limitMultiLogin;//是否允许账号同一个时刻多人在线,1/0
+
+    private Date createTime;//创建时间
+
+    private Date updateTime;//修改时间
+
+}

+ 31 - 0
src/main/java/com/dapp/moviewebsite/app/appUser/vo/AppUserVo.java

@@ -0,0 +1,31 @@
+package com.dapp.moviewebsite.app.appUser.vo;
+
+import com.dapp.moviewebsite. common.pojo.PageCondition;import lombok.Data;
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+public class AppUserVo extends PageCondition implements Serializable {
+    private String userId;//用户id
+
+    private String loginName;//登录名
+
+    private String userName;//用户名称
+
+    private String password;//登录密码
+
+    private Integer valid;//软删除标识,1/0
+
+    private String limitedIp;//限制允许登录的IP集合
+
+    private Date expiredTime;//账号失效时间,超过时间将不能登录系统
+
+    private Date lastChangePwdTime;//最近修改密码时间,超出时间间隔,提示用户修改密码
+
+    private Integer limitMultiLogin;//是否允许账号同一个时刻多人在线,1/0
+
+    private Date createTime;//创建时间
+
+    private Date updateTime;//修改时间
+
+}

+ 57 - 0
src/main/java/com/dapp/moviewebsite/app/appUserMember/controller/AppUserMemberController.java

@@ -0,0 +1,57 @@
+package com.dapp.moviewebsite.app.appUserMember.controller;
+
+import com.dapp.moviewebsite.app.appUserMember.vo.AppUserMemberSimpleVo;
+import com.dapp.moviewebsite.common.VO.ResultVO;
+import com.dapp.moviewebsite.common.controller.*;
+import com.dapp.moviewebsite.app.appUserMember.pojo.AppUserMember;
+import com.dapp.moviewebsite.app.appUserMember.vo.AppUserMemberVo;
+import com.dapp.moviewebsite.app.appUserMember.service.AppUserMemberService;
+import com.dapp.moviewebsite.common.enums.ResultEnum;
+import com.dapp.moviewebsite.common.utils.CopyUtil;
+import com.dapp.moviewebsite.common.utils.ResultVOUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.constraints.DecimalMin;
+import javax.validation.constraints.Min;
+
+@Validated
+@RestController
+@RequestMapping("/appUserMember/")
+public class AppUserMemberController extends CommonController<AppUserMemberVo, AppUserMember, Integer> {
+    @Autowired
+    private AppUserMemberService appUserMemberService;
+
+    @GetMapping("/add")
+    public ResultVO add(@RequestParam("userId") String userId,
+                        @RequestParam(value = "tox" ) @DecimalMin(value = "0.01",message = "tox 必须大于等于0.01") Double tox,
+                        @RequestParam(value = "purchaseQuantity") @Min(value = 1,message = "purchaseQuantity 必须大于等于1") Integer purchaseQuantity
+
+    ) {
+      AppUserMemberVo appUserMemberVo = appUserMemberService.addNormalMember(userId, tox, purchaseQuantity);
+      AppUserMemberSimpleVo appUserMemberSimpleVo = CopyUtil.copy(appUserMemberVo,AppUserMemberSimpleVo.class);
+      return ResultVOUtil.success(appUserMemberSimpleVo);
+    }
+
+    @GetMapping("/delete")
+    public ResultVO delete(@RequestParam("userId") String userId) {
+        Boolean bSuccess = appUserMemberService.deleteNormalMember(userId);
+        if(bSuccess){
+            return ResultVOUtil.success();
+        }else {
+            return ResultVOUtil.error(ResultEnum.MEMBER_GET_ERROR);
+        }
+    }
+
+    @GetMapping("/get")
+    public ResultVO get(@RequestParam("userId") String userId) {
+        AppUserMemberVo appUserMemberVo = appUserMemberService.getNormalMember(userId);
+        if(appUserMemberVo != null){
+            return ResultVOUtil.success(CopyUtil.copy(appUserMemberVo,AppUserMemberSimpleVo.class));
+        }else{
+
+            return ResultVOUtil.success(ResultEnum.MEMBER_GET_ERROR);
+        }
+    }
+}

+ 9 - 0
src/main/java/com/dapp/moviewebsite/app/appUserMember/enums/MemberType.java

@@ -0,0 +1,9 @@
+package com.dapp.moviewebsite.app.appUserMember.enums;
+
+/**
+ * @author:slambb
+ * @date:2024/4/25
+ */
+public enum MemberType {
+    Normal
+}

+ 34 - 0
src/main/java/com/dapp/moviewebsite/app/appUserMember/pojo/AppUserMember.java

@@ -0,0 +1,34 @@
+package com.dapp.moviewebsite.app.appUserMember.pojo;
+
+import lombok.Data;
+import javax.persistence.*;
+import java.io.Serializable;
+import java.util.Date;
+
+@Entity
+@Table(name = "app_user_member")
+@Data
+public class AppUserMember implements Serializable {
+    @Id
+    @GeneratedValue(strategy= GenerationType.IDENTITY)
+    private Integer id;//
+
+    private String userId;//用户id
+
+    private String mName;//会员名字
+
+    private String mDescribe;//
+
+    private Integer type;//会员类型,。0 :普通会员...
+
+    private String limitedIp;//限制允许登录的IP集合
+
+    private Date expiredTime;//会员失效时间,超过时间将不能使用会员
+
+    private Date lastChangeTime;//最近续费时间
+
+    private Date createTime;//创建时间
+
+    private Date updateTime;//修改时间
+
+}

+ 12 - 0
src/main/java/com/dapp/moviewebsite/app/appUserMember/repository/AppUserMemberRepository.java

@@ -0,0 +1,12 @@
+package com.dapp.moviewebsite.app.appUserMember.repository;
+
+import com.dapp.moviewebsite.common.repository.*;
+import com.dapp.moviewebsite.app.appUserMember.pojo.AppUserMember;
+import org.springframework.stereotype.Repository;
+
+import java.util.Optional;
+
+@Repository
+public interface AppUserMemberRepository extends CommonRepository<AppUserMember, Integer> {
+    Optional<AppUserMember> findByUserIdAndType(String userId,Integer type);
+}

+ 12 - 0
src/main/java/com/dapp/moviewebsite/app/appUserMember/service/AppUserMemberService.java

@@ -0,0 +1,12 @@
+package com.dapp.moviewebsite.app.appUserMember.service;
+
+import com.dapp.moviewebsite.common.service.*;
+import com.dapp.moviewebsite.app.appUserMember.pojo.AppUserMember;
+import com.dapp.moviewebsite.app.appUserMember.vo.AppUserMemberVo;
+
+public interface AppUserMemberService extends CommonService<AppUserMemberVo, AppUserMember, Integer> {
+
+    AppUserMemberVo addNormalMember(String userId,Double tox,Integer purchaseQuantity);
+    Boolean deleteNormalMember(String userId);
+    AppUserMemberVo getNormalMember(String userId);
+}

+ 93 - 0
src/main/java/com/dapp/moviewebsite/app/appUserMember/service/AppUserMemberServiceImpl.java

@@ -0,0 +1,93 @@
+package com.dapp.moviewebsite.app.appUserMember.service;
+
+import cn.hutool.core.date.DateField;
+import cn.hutool.core.date.DateUtil;
+import com.dapp.moviewebsite.app.appUserMember.enums.MemberType;
+import com.dapp.moviewebsite.app.appUserTran.pojo.AppUserTran;
+import com.dapp.moviewebsite.app.appUserTran.service.AppUserTranService;
+import com.dapp.moviewebsite.common.service.*;
+import com.dapp.moviewebsite.app.appUserMember.pojo.AppUserMember;
+import com.dapp.moviewebsite.app.appUserMember.vo.AppUserMemberVo;
+import com.dapp.moviewebsite.app.appUserMember.repository.AppUserMemberRepository;
+import com.dapp.moviewebsite.common.utils.CopyUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import java.util.Date;
+
+@Service
+@Transactional
+public class AppUserMemberServiceImpl extends CommonServiceImpl<AppUserMemberVo, AppUserMember, Integer> implements AppUserMemberService{
+
+    @PersistenceContext
+    private EntityManager em;
+    @Autowired
+    private AppUserMemberRepository appUserMemberRepository;
+
+    @Autowired
+    private AppUserTranService appUserTranService;
+
+    /**
+     * 购买会员
+     * @param userId
+     * @param tox
+     * @param purchaseQuantity
+     * @return
+     */
+    @Override
+    @Transactional
+    public AppUserMemberVo addNormalMember(String userId, Double tox, Integer purchaseQuantity) {
+
+        AppUserMember  appUserMember = appUserMemberRepository.findByUserIdAndType(userId, MemberType.Normal.ordinal()).orElse(null);
+        AppUserMemberVo appUserMemberVo;
+        if(appUserMember == null){
+            //添加新会员数据
+            appUserMemberVo = new AppUserMemberVo();
+            appUserMemberVo.setUserId(userId);
+            appUserMemberVo.setMName("普通会员");
+            appUserMemberVo.setMDescribe("使用tox购买了普通会员!");
+            appUserMemberVo.setType(MemberType.Normal.ordinal());
+            //购买会员增加一年时间
+            Date nextYear = DateUtil.offset(DateUtil.date(), DateField.YEAR,1);
+            appUserMemberVo.setExpiredTime(nextYear);
+            appUserMemberVo.setLastChangeTime(DateUtil.date());
+            appUserMemberVo.setCreateTime(DateUtil.date());
+            appUserMemberVo.setUpdateTime(DateUtil.date());
+            //保存一次数据
+            appUserMemberVo = saveReturnVo(appUserMemberVo);
+
+
+        }else{
+            //再购买一次,叠加上去
+            Date nextYear = DateUtil.offset(appUserMember.getExpiredTime(), DateField.YEAR,1);
+            //复制对象后
+            appUserMemberVo = CopyUtil.copy(appUserMember,AppUserMemberVo.class);
+            appUserMemberVo.setExpiredTime(nextYear);
+            appUserMemberVo.setLastChangeTime(DateUtil.date());
+            appUserMemberVo.setUpdateTime(DateUtil.date());
+            //保存一次数据
+            appUserMemberVo = saveReturnVo(appUserMemberVo);
+        }
+        //记录一次购买数据
+        appUserTranService.addAppUserTranInfo(userId, tox, purchaseQuantity);
+        return appUserMemberVo;
+    }
+
+    @Override
+    public Boolean deleteNormalMember(String userId) {
+       AppUserMember appUserMember = appUserMemberRepository.findByUserIdAndType(userId,MemberType.Normal.ordinal()).orElse(null);
+       if(appUserMember != null){
+           delete(appUserMember.getId());
+           return true;// "删除会员信息成功!";
+       }
+       return false;// "不存在会员信息!";
+    }
+
+    @Override
+    public AppUserMemberVo getNormalMember(String userId) {
+        AppUserMember appUserMember = appUserMemberRepository.findByUserIdAndType(userId,MemberType.Normal.ordinal()).orElse(null);
+        return appUserMember == null?null:CopyUtil.copy(appUserMember,AppUserMemberVo.class);
+    }
+}

+ 29 - 0
src/main/java/com/dapp/moviewebsite/app/appUserMember/vo/AppUserMemberSimpleVo.java

@@ -0,0 +1,29 @@
+package com.dapp.moviewebsite.app.appUserMember.vo;
+
+import lombok.Data;
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+public class AppUserMemberSimpleVo implements Serializable {
+    //private Integer id;//
+
+    //private String userId;//用户id
+
+    private String mName;//会员名字
+
+    private String mDescribe;//
+
+    private Integer type;//会员类型,。0 :普通会员...
+
+    private String limitedIp;//限制允许登录的IP集合
+
+    private Date expiredTime;//会员失效时间,超过时间将不能使用会员
+
+    private Date lastChangeTime;//最近续费时间
+
+    private Date createTime;//创建时间
+
+    private Date updateTime;//修改时间
+
+}

+ 29 - 0
src/main/java/com/dapp/moviewebsite/app/appUserMember/vo/AppUserMemberVo.java

@@ -0,0 +1,29 @@
+package com.dapp.moviewebsite.app.appUserMember.vo;
+
+import com.dapp.moviewebsite. common.pojo.PageCondition;import lombok.Data;
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+public class AppUserMemberVo extends PageCondition implements Serializable {
+    private Integer id;//
+
+    private String userId;//用户id
+
+    private String mName;//会员名字
+
+    private String mDescribe;//
+
+    private Integer type;//会员类型,。0 :普通会员...
+
+    private String limitedIp;//限制允许登录的IP集合
+
+    private Date expiredTime;//会员失效时间,超过时间将不能使用会员
+
+    private Date lastChangeTime;//最近续费时间
+
+    private Date createTime;//创建时间
+
+    private Date updateTime;//修改时间
+
+}

+ 44 - 0
src/main/java/com/dapp/moviewebsite/app/appUserTran/controller/AppUserTranController.java

@@ -0,0 +1,44 @@
+package com.dapp.moviewebsite.app.appUserTran.controller;
+
+
+import com.dapp.moviewebsite.app.appUserTran.vo.AppUserTranSimpleVo;
+import com.dapp.moviewebsite.common.VO.ResultVO;
+import com.dapp.moviewebsite.common.controller.*;
+import com.dapp.moviewebsite.app.appUserTran.pojo.AppUserTran;
+import com.dapp.moviewebsite.app.appUserTran.vo.AppUserTranVo;
+import com.dapp.moviewebsite.app.appUserTran.service.AppUserTranService;
+import com.dapp.moviewebsite.common.exception.UserException;
+import com.dapp.moviewebsite.common.pojo.PageInfo;
+import com.dapp.moviewebsite.common.utils.ResultVOUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.constraints.Min;
+
+@Validated
+@RestController
+@RequestMapping("/appUserTran/")
+public class AppUserTranController extends CommonController<AppUserTranVo, AppUserTran, String> {
+    @Autowired
+    private AppUserTranService appUserTranService;
+
+    @GetMapping("/page")
+    public ResultVO page(@RequestParam("userId") String userId,
+                         @RequestParam(value = "page",defaultValue = "1") @Min(value = 1, message = "page必须大于等于1")  Integer page,
+                         @RequestParam(value = "size",defaultValue = "10") @Min(value = 1, message = "size必须大于等于1") Integer size) {
+        try {
+            AppUserTranVo appUserTranVo = new AppUserTranVo();
+            appUserTranVo.setUserId(userId);
+            appUserTranVo.setPage(page);
+            appUserTranVo.setRows(size);
+            appUserTranVo.setSidx("DESC");
+            appUserTranVo.setSord("updateTime");
+            PageInfo pageInfo = appUserTranService.pageByClass(appUserTranVo, AppUserTranSimpleVo.class);
+            return ResultVOUtil.success(pageInfo);
+        } catch (UserException e) {
+            return ResultVOUtil.error(e.getCode(), e.getMessage());
+        }
+
+    }
+}

+ 9 - 0
src/main/java/com/dapp/moviewebsite/app/appUserTran/enums/TranType.java

@@ -0,0 +1,9 @@
+package com.dapp.moviewebsite.app.appUserTran.enums;
+
+/**
+ * @author:slambb
+ * @date:2024/4/25
+ */
+public enum TranType {
+    Normal
+}

+ 49 - 0
src/main/java/com/dapp/moviewebsite/app/appUserTran/pojo/AppUserTran.java

@@ -0,0 +1,49 @@
+package com.dapp.moviewebsite.app.appUserTran.pojo;
+
+import lombok.Data;
+import javax.persistence.*;
+import java.io.Serializable;
+import java.util.Date;
+
+@Entity
+@Table(name = "app_user_tran")
+@Data
+public class AppUserTran implements Serializable {
+    @Id
+    private String id;//
+
+    private String userId;//操作用户的id
+
+    private String tranId;//操作对象的id,不唯一
+
+    private String tranName;//交易的类型名字
+
+    private Integer tranType;//交易类型,区分是什么交易。0:购买会员
+
+    private Integer tranAmount;//交易数量,上限10个int长度
+
+    private Double tranAmountPart;//交易的部分数据
+
+    private Integer tranPrice;//物品的交易价格,单价
+
+    private String tranDescribe;//交易描述
+
+    private Integer isAdd;//交易是增加还是减少,0:减少,1:是增加
+
+    private Integer beforeTox;//交易之前的tox
+
+    private Integer tranTox;//交易的tox
+
+    private Integer afterTox;//交易完成后的tox
+
+    private Double beforeToxPart;//
+
+    private Double tranToxPart;//
+
+    private Double afterToxPart;//
+
+    private Date createTime;//
+
+    private Date updateTime;//
+
+}

+ 9 - 0
src/main/java/com/dapp/moviewebsite/app/appUserTran/repository/AppUserTranRepository.java

@@ -0,0 +1,9 @@
+package com.dapp.moviewebsite.app.appUserTran.repository;
+
+import com.dapp.moviewebsite.common.repository.*;
+import com.dapp.moviewebsite.app.appUserTran.pojo.AppUserTran;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface AppUserTranRepository extends CommonRepository<AppUserTran, String> {
+}

+ 9 - 0
src/main/java/com/dapp/moviewebsite/app/appUserTran/service/AppUserTranService.java

@@ -0,0 +1,9 @@
+package com.dapp.moviewebsite.app.appUserTran.service;
+
+import com.dapp.moviewebsite.common.service.*;
+import com.dapp.moviewebsite.app.appUserTran.pojo.AppUserTran;
+import com.dapp.moviewebsite.app.appUserTran.vo.AppUserTranVo;
+
+public interface AppUserTranService extends CommonService<AppUserTranVo, AppUserTran, String> {
+    AppUserTranVo addAppUserTranInfo(String userId,Double tox,Integer purchaseQuantity);
+}

+ 52 - 0
src/main/java/com/dapp/moviewebsite/app/appUserTran/service/AppUserTranServiceImpl.java

@@ -0,0 +1,52 @@
+package com.dapp.moviewebsite.app.appUserTran.service;
+
+import cn.hutool.core.date.DateUtil;
+import com.dapp.moviewebsite.app.appUserTran.enums.TranType;
+import com.dapp.moviewebsite.app.enums.OperationType;
+import com.dapp.moviewebsite.common.service.*;
+import com.dapp.moviewebsite.app.appUserTran.pojo.AppUserTran;
+import com.dapp.moviewebsite.app.appUserTran.vo.AppUserTranVo;
+import com.dapp.moviewebsite.app.appUserTran.repository.AppUserTranRepository;
+import com.dapp.moviewebsite.common.utils.DoubleUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+
+@Service
+@Transactional
+public class AppUserTranServiceImpl extends CommonServiceImpl<AppUserTranVo, AppUserTran, String> implements AppUserTranService{
+
+    @PersistenceContext
+    private EntityManager em;
+    @Autowired
+    private AppUserTranRepository appUserTranRepository;
+
+
+    @Override
+    @Transactional
+    public AppUserTranVo addAppUserTranInfo(String userId,Double tox,Integer purchaseQuantity) {
+
+        //交易部分转换计算
+        Integer _tranTox = (int)Math.floor(tox);
+        Double _tranToxPart = DoubleUtil.sub(tox, Math.floor(tox));
+
+        AppUserTranVo appUserTranVo = new AppUserTranVo();
+        appUserTranVo.setUserId(userId);
+        //appUserTranVo.setTranId(); //交易对象的id,比如后续会员记录的id
+        appUserTranVo.setTranName("会员");
+        appUserTranVo.setTranType(TranType.Normal.ordinal());
+        appUserTranVo.setTranAmount(purchaseQuantity);
+        appUserTranVo.setTranAmountPart(0d);
+        //appUserTranVo.setTranPrice(tox);
+        appUserTranVo.setTranTox(_tranTox);
+        appUserTranVo.setTranToxPart(_tranToxPart);
+        //用户减少了对应的tox
+        appUserTranVo.setIsAdd(OperationType.Decrease.ordinal());
+        appUserTranVo.setCreateTime(DateUtil.date());
+        appUserTranVo.setUpdateTime(DateUtil.date());
+        appUserTranVo = saveReturnVo(appUserTranVo);
+        return appUserTranVo;
+    }
+}

+ 45 - 0
src/main/java/com/dapp/moviewebsite/app/appUserTran/vo/AppUserTranSimpleVo.java

@@ -0,0 +1,45 @@
+package com.dapp.moviewebsite.app.appUserTran.vo;
+
+import lombok.Data;
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+public class AppUserTranSimpleVo implements Serializable {
+    //private String id;//
+
+   // private String userId;//操作用户的id
+
+    private String tranId;//操作对象的id,不唯一
+
+    private String tranName;//交易的类型名字
+
+    private Integer tranType;//交易类型,区分是什么交易。0:购买会员
+
+    private Integer tranAmount;//交易数量,上限10个int长度
+
+    private Double tranAmountPart;//交易的部分数据
+
+    private Integer tranPrice;//物品的交易价格,单价
+
+    private String tranDescribe;//交易描述
+
+    private Integer isAdd;//交易是增加还是减少,0:减少,1:是增加
+
+    private Integer beforeTox;//交易之前的tox
+
+    private Integer tranTox;//交易的tox
+
+    private Integer afterTox;//交易完成后的tox
+
+    private Double beforeToxPart;//
+
+    private Double tranToxPart;//
+
+    private Double afterToxPart;//
+
+    private Date createTime;//
+
+    private Date updateTime;//
+
+}

+ 45 - 0
src/main/java/com/dapp/moviewebsite/app/appUserTran/vo/AppUserTranVo.java

@@ -0,0 +1,45 @@
+package com.dapp.moviewebsite.app.appUserTran.vo;
+
+import com.dapp.moviewebsite. common.pojo.PageCondition;import lombok.Data;
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+public class AppUserTranVo extends PageCondition implements Serializable {
+    private String id;//
+
+    private String userId;//操作用户的id
+
+    private String tranId;//操作对象的id,不唯一
+
+    private String tranName;//交易的类型名字
+
+    private Integer tranType;//交易类型,区分是什么交易。0:购买会员
+
+    private Integer tranAmount;//交易数量,上限10个int长度
+
+    private Double tranAmountPart;//交易的部分数据
+
+    private Integer tranPrice;//物品的交易价格,单价
+
+    private String tranDescribe;//交易描述
+
+    private Integer isAdd;//交易是增加还是减少,0:减少,1:是增加
+
+    private Integer beforeTox;//交易之前的tox
+
+    private Integer tranTox;//交易的tox
+
+    private Integer afterTox;//交易完成后的tox
+
+    private Double beforeToxPart;//
+
+    private Double tranToxPart;//
+
+    private Double afterToxPart;//
+
+    private Date createTime;//
+
+    private Date updateTime;//
+
+}

+ 56 - 0
src/main/java/com/dapp/moviewebsite/app/appVideos/controller/AppVideosController.java

@@ -0,0 +1,56 @@
+package com.dapp.moviewebsite.app.appVideos.controller;
+
+import com.dapp.moviewebsite.app.appFavorite.pojo.AppFavorite;
+import com.dapp.moviewebsite.app.appFavorite.service.AppFavoriteService;
+import com.dapp.moviewebsite.app.appFavorite.vo.AppFavoriteVo;
+import com.dapp.moviewebsite.app.appVideos.vo.AppVideosOtherVo;
+import com.dapp.moviewebsite.app.appViewingRecords.pojo.AppViewingRecords;
+import com.dapp.moviewebsite.app.appViewingRecords.service.AppViewingRecordsService;
+import com.dapp.moviewebsite.app.appViewingRecords.vo.AppViewingRecordsSimpleVo;
+import com.dapp.moviewebsite.common.VO.ResultVO;
+import com.dapp.moviewebsite.common.controller.*;
+import com.dapp.moviewebsite.app.appVideos.pojo.AppVideos;
+import com.dapp.moviewebsite.app.appVideos.vo.AppVideosVo;
+import com.dapp.moviewebsite.app.appVideos.service.AppVideosService;
+import com.dapp.moviewebsite.common.enums.ResultEnum;
+import com.dapp.moviewebsite.common.utils.CopyUtil;
+import com.dapp.moviewebsite.common.utils.ResultVOUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.constraints.NotBlank;
+
+@Validated
+@RestController
+@RequestMapping("/appVideos/")
+public class AppVideosController extends CommonController<AppVideosVo, AppVideos, Integer> {
+    @Autowired
+    private AppVideosService appVideosService;
+
+    @Autowired
+    private AppFavoriteService appFavoriteService;
+
+    @Autowired
+    private AppViewingRecordsService appViewingRecordsService;
+
+    @GetMapping("/get")
+    public ResultVO add(@RequestParam("userId") String userId,
+                        @RequestParam("videoUrl") @NotBlank(message = "videoUrl 字符串不能为空且不能只包含空白字符") String videoUrl
+    ) {
+        //找出电影信息
+        AppVideosVo appVideosVo = appVideosService.findByUrl(videoUrl);
+        if(appVideosVo != null){
+            AppVideosOtherVo appVideosOtherVo = CopyUtil.copy(appVideosVo, AppVideosOtherVo.class);
+            //是否收藏
+            AppFavorite appFavorite = appFavoriteService.findByUserIdAndVideoId(userId, appVideosVo.getId());
+            appVideosOtherVo.setIsFavorite(appFavorite == null?false:true);
+            //播放次数
+            AppViewingRecords appViewingRecords = appViewingRecordsService.findByUserIdAndVideoId(userId, appVideosVo.getId());
+            appVideosOtherVo.setPlayerCount(appViewingRecords == null?0:appViewingRecords.getPlayCount());
+            return ResultVOUtil.success(appVideosOtherVo);
+        }else{
+            return ResultVOUtil.error(ResultEnum.VIEWING_RECORDS_CANCEL_ERROR);
+        }
+    }
+}

+ 36 - 0
src/main/java/com/dapp/moviewebsite/app/appVideos/pojo/AppVideos.java

@@ -0,0 +1,36 @@
+package com.dapp.moviewebsite.app.appVideos.pojo;
+
+import lombok.Data;
+import javax.persistence.*;
+import java.io.Serializable;
+import java.util.Date;
+
+@Entity
+@Table(name = "app_videos")
+@Data
+public class AppVideos implements Serializable {
+    @Id
+    @GeneratedValue(strategy= GenerationType.IDENTITY)
+    private Integer id;//电影列表id
+
+    private Integer type;//收藏类型:0:other,1:视频
+
+    private String url;//视频路径
+
+    private String videoName;//视频名字
+
+    private Integer duration;//视频时长
+
+    private Integer durationMax;//最大时长
+
+    private Integer currentSet;//当前集数
+
+    private Integer currentSetMax;//当前最大视频集数
+
+    private String videoPoster;//视频海报
+
+    private Date createTime;//
+
+    private Date updateTime;//
+
+}

+ 13 - 0
src/main/java/com/dapp/moviewebsite/app/appVideos/repository/AppVideosRepository.java

@@ -0,0 +1,13 @@
+package com.dapp.moviewebsite.app.appVideos.repository;
+
+import com.dapp.moviewebsite.common.repository.*;
+import com.dapp.moviewebsite.app.appVideos.pojo.AppVideos;
+import org.springframework.stereotype.Repository;
+
+import java.util.Optional;
+
+@Repository
+public interface AppVideosRepository extends CommonRepository<AppVideos, Integer> {
+
+    Optional<AppVideos> findByUrl(String url);
+}

+ 25 - 0
src/main/java/com/dapp/moviewebsite/app/appVideos/service/AppVideosService.java

@@ -0,0 +1,25 @@
+package com.dapp.moviewebsite.app.appVideos.service;
+
+import com.dapp.moviewebsite.app.appFavorite.pojo.AppFavorite;
+import com.dapp.moviewebsite.common.service.*;
+import com.dapp.moviewebsite.app.appVideos.pojo.AppVideos;
+import com.dapp.moviewebsite.app.appVideos.vo.AppVideosVo;
+
+public interface AppVideosService extends CommonService<AppVideosVo, AppVideos, Integer> {
+
+    AppVideosVo findByUrl( String videoUrl);
+
+    AppVideosVo findByUrlAndName( String videoUrl,String name);
+
+    AppVideosVo createAppVideos(  String videoUrl,
+                                  String name,
+                                  Integer duration,
+                                  Integer currentSet,
+                                  String poster );
+
+    AppVideosVo getAndUpdateAppVideos( String videoUrl,
+                                 String name,
+                                 Integer duration,
+                                 Integer currentSet,
+                                 String poster);
+}

+ 86 - 0
src/main/java/com/dapp/moviewebsite/app/appVideos/service/AppVideosServiceImpl.java

@@ -0,0 +1,86 @@
+package com.dapp.moviewebsite.app.appVideos.service;
+
+import cn.hutool.core.date.DateUtil;
+import com.dapp.moviewebsite.app.enums.FavoriteType;
+import com.dapp.moviewebsite.common.service.*;
+import com.dapp.moviewebsite.app.appVideos.pojo.AppVideos;
+import com.dapp.moviewebsite.app.appVideos.vo.AppVideosVo;
+import com.dapp.moviewebsite.app.appVideos.repository.AppVideosRepository;
+import com.dapp.moviewebsite.common.utils.CopyUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+
+@Service
+@Transactional
+public class AppVideosServiceImpl extends CommonServiceImpl<AppVideosVo, AppVideos, Integer> implements AppVideosService{
+
+    @PersistenceContext
+    private EntityManager em;
+    @Autowired
+    private AppVideosRepository appVideosRepository;
+
+    @Override
+    public AppVideosVo findByUrl(String videoUrl) {
+        AppVideos appVideos = appVideosRepository.findByUrl(videoUrl).orElse(null);
+        return appVideos == null? null: CopyUtil.copy(appVideos,AppVideosVo.class);
+    }
+
+    @Override
+    public AppVideosVo findByUrlAndName(String videoUrl, String name) {
+        return null;
+    }
+
+    @Override
+    public AppVideosVo createAppVideos(  String videoUrl,
+                                         String name,
+                                         Integer duration,
+                                         Integer currentSet,
+                                         String poster ) {
+        AppVideosVo  appVideosVo = new AppVideosVo();
+        appVideosVo.setUrl(videoUrl);
+        appVideosVo.setVideoName(name);
+        appVideosVo.setDuration(duration);
+        appVideosVo.setDurationMax(duration);
+        appVideosVo.setCurrentSet(currentSet);
+        appVideosVo.setCurrentSetMax(currentSet);
+        appVideosVo.setVideoPoster(poster);
+        appVideosVo.setType(FavoriteType.video.ordinal());
+        appVideosVo.setCreateTime(DateUtil.date());
+        appVideosVo.setUpdateTime(DateUtil.date());
+        appVideosVo = saveReturnVo(appVideosVo);
+        return appVideosVo;
+    }
+
+
+    @Override
+    public AppVideosVo getAndUpdateAppVideos( String videoUrl,
+                                        String name,
+                                        Integer duration,
+                                        Integer currentSet,
+                                        String poster ) {
+
+        AppVideosVo appVideosVo = findByUrl(videoUrl);
+        if(appVideosVo == null){
+            appVideosVo =  createAppVideos(videoUrl, name, duration, currentSet, poster);
+        }else{
+            appVideosVo.setVideoName(name);
+            if(appVideosVo.getDurationMax() == null || duration > appVideosVo.getDurationMax()){
+                appVideosVo.setDurationMax(duration);
+            }
+            appVideosVo.setDuration(duration);
+
+            if(appVideosVo.getCurrentSetMax() == null || currentSet > appVideosVo.getCurrentSetMax()){
+                appVideosVo.setCurrentSetMax(currentSet);
+            }
+            appVideosVo.setCurrentSet(currentSet);
+            appVideosVo.setVideoPoster(poster);
+            appVideosVo = saveReturnVo(appVideosVo);
+        }
+        return appVideosVo;
+    }
+}

+ 36 - 0
src/main/java/com/dapp/moviewebsite/app/appVideos/vo/AppVideosOtherVo.java

@@ -0,0 +1,36 @@
+package com.dapp.moviewebsite.app.appVideos.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+public class AppVideosOtherVo implements Serializable {
+    private Integer id;//电影列表id
+
+    private Integer type;//收藏类型:0:other,1:视频
+
+    private String url;//视频路径
+
+    private String videoName;//视频名字
+
+    private Integer duration;//视频时长
+
+    private Integer durationMax;//最大时长
+
+    private Integer currentSet;//当前集数
+
+    private Integer currentSetMax;//当前最大视频集数
+
+    private String videoPoster;//视频海报
+
+    private Integer playerCount; //播放次数
+
+    private Boolean isFavorite;//是否收藏
+
+    private Date createTime;//
+
+    private Date updateTime;//
+
+}

+ 31 - 0
src/main/java/com/dapp/moviewebsite/app/appVideos/vo/AppVideosSimpleVo.java

@@ -0,0 +1,31 @@
+package com.dapp.moviewebsite.app.appVideos.vo;
+
+import lombok.Data;
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+public class AppVideosSimpleVo implements Serializable {
+    private Integer id;//电影列表id
+
+    private Integer type;//收藏类型:0:other,1:视频
+
+    private String url;//视频路径
+
+    private String videoName;//视频名字
+
+    private Integer duration;//视频时长
+
+    private Integer durationMax;//最大时长
+
+    private Integer currentSet;//当前集数
+
+    private Integer currentSetMax;//当前最大视频集数
+
+    private String videoPoster;//视频海报
+
+    private Date createTime;//
+
+    private Date updateTime;//
+
+}

+ 31 - 0
src/main/java/com/dapp/moviewebsite/app/appVideos/vo/AppVideosVo.java

@@ -0,0 +1,31 @@
+package com.dapp.moviewebsite.app.appVideos.vo;
+
+import com.dapp.moviewebsite. common.pojo.PageCondition;import lombok.Data;
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+public class AppVideosVo extends PageCondition implements Serializable {
+    private Integer id;//电影列表id
+
+    private Integer type;//收藏类型:0:other,1:视频
+
+    private String url;//视频路径
+
+    private String videoName;//视频名字
+
+    private Integer duration;//视频时长
+
+    private Integer durationMax;//最大时长
+
+    private Integer currentSet;//当前集数
+
+    private Integer currentSetMax;//当前最大视频集数
+
+    private String videoPoster;//视频海报
+
+    private Date createTime;//
+
+    private Date updateTime;//
+
+}

+ 134 - 0
src/main/java/com/dapp/moviewebsite/app/appViewingRecords/controller/AppViewingRecordsController.java

@@ -0,0 +1,134 @@
+package com.dapp.moviewebsite.app.appViewingRecords.controller;
+
+import com.dapp.moviewebsite.app.appFavorite.vo.AppFavoriteSimpleVo;
+import com.dapp.moviewebsite.app.appVideos.pojo.AppVideos;
+import com.dapp.moviewebsite.app.appVideos.service.AppVideosService;
+import com.dapp.moviewebsite.app.appVideos.vo.AppVideosVo;
+import com.dapp.moviewebsite.app.appViewingRecords.dto.ViewingRecordsDto;
+import com.dapp.moviewebsite.app.appViewingRecords.vo.AppViewingRecordsSimpleVo;
+import com.dapp.moviewebsite.app.enums.FavoriteType;
+import com.dapp.moviewebsite.common.VO.ResultVO;
+import com.dapp.moviewebsite.common.controller.*;
+import com.dapp.moviewebsite.app.appViewingRecords.pojo.AppViewingRecords;
+import com.dapp.moviewebsite.app.appViewingRecords.vo.AppViewingRecordsVo;
+import com.dapp.moviewebsite.app.appViewingRecords.service.AppViewingRecordsService;
+import com.dapp.moviewebsite.common.enums.ResultEnum;
+import com.dapp.moviewebsite.common.exception.UserException;
+import com.dapp.moviewebsite.common.pojo.PageInfo;
+import com.dapp.moviewebsite.common.utils.CopyUtil;
+import com.dapp.moviewebsite.common.utils.ResultVOUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.StringUtils;
+import org.springframework.validation.BindingResult;
+import org.springframework.validation.ObjectError;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+
+import javax.validation.Valid;
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Size;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+@Validated
+@RestController
+@RequestMapping("/viewingRecords/")
+public class AppViewingRecordsController extends CommonController<AppViewingRecordsVo, AppViewingRecords, Integer> {
+    @Autowired
+    private AppViewingRecordsService appViewingRecordsService;
+
+    @Autowired
+    private AppVideosService appVideosService;
+    /**
+     * 更新和添加观看视频信息
+     */
+    @PostMapping("/add")
+    public ResultVO add(@RequestParam("userId") String userId,@Valid @RequestBody ViewingRecordsDto vDto) {
+        //log.info(vDto.toString());
+        AppVideosVo appVideosVo = appVideosService.getAndUpdateAppVideos(vDto.getVideoUrl(), vDto.getName(), vDto.getDuration(), vDto.getCurrentSet(), vDto.getPoster());
+        //更新观看操作
+        AppViewingRecordsVo appViewingRecordsVo = appViewingRecordsService.addAppViewingRecordsVo(userId,appVideosVo.getId(),
+                appVideosVo.getUrl(), appVideosVo.getVideoName(), appVideosVo.getDuration(), appVideosVo.getCurrentSet(), appVideosVo.getVideoPoster());
+        AppViewingRecordsSimpleVo  appViewingRecordsSimpleVo = CopyUtil.copy(appViewingRecordsVo,AppViewingRecordsSimpleVo.class);
+        //把剩余空白的信息填上
+        BeanUtils.copyProperties(appVideosVo,appViewingRecordsSimpleVo);
+        return ResultVOUtil.success(appViewingRecordsSimpleVo);
+    }
+
+    /**
+     * 获取观看视频信息
+     * @param userId
+     * @param videoUrl
+     * @return
+     */
+    @GetMapping("/get")
+    public ResultVO add(@RequestParam("userId") String userId,
+                        @RequestParam("videoUrl") @NotBlank(message = "videoUrl 字符串不能为空且不能只包含空白字符") String videoUrl
+    ) {
+        AppVideosVo appVideosVo = appVideosService.findByUrl(videoUrl);
+        if(appVideosVo == null){
+            return ResultVOUtil.error(ResultEnum.VIEWING_RECORDS_CANCEL_ERROR);
+        }
+        AppViewingRecords appViewingRecords = appViewingRecordsService.findByUserIdAndVideoId(userId,appVideosVo.getId());
+        if(appViewingRecords != null){
+            AppViewingRecordsSimpleVo  appViewingRecordsSimpleVo = CopyUtil.copy(appViewingRecords,AppViewingRecordsSimpleVo.class);
+            //把剩余空白的信息填上
+            BeanUtils.copyProperties(appVideosVo,appViewingRecordsSimpleVo);
+            return ResultVOUtil.success(appViewingRecordsSimpleVo);
+        }else{
+            return ResultVOUtil.error(ResultEnum.VIEWING_RECORDS_CANCEL_ERROR);
+        }
+    }
+
+    /**
+     * 分页获取视频
+     * @param userId
+     * @param videoName 如果输入了则按 video name 过滤
+     * @param page
+     * @param size
+     * @return
+     */
+    @GetMapping("/page")
+    public ResultVO page(@RequestParam("userId") String userId,
+                         @RequestParam(value = "videoName" , required = false) String videoName,
+                         @RequestParam(value = "page",defaultValue = "1") @Min(value = 1,message = "page必须大于等于1")   Integer page,
+                         @RequestParam(value = "size",defaultValue = "10")  @Min(value = 1, message = "size必须大于等于1") Integer size) {
+
+        try {
+            AppViewingRecordsVo appViewingRecordsVo = new AppViewingRecordsVo();
+            appViewingRecordsVo.setUserId(userId);
+            //如果有名字添加名字过滤
+            if(StringUtils.hasText(videoName)){
+                appViewingRecordsVo.setVideoName(videoName);
+            }
+            appViewingRecordsVo.setPage(page);
+            appViewingRecordsVo.setRows(size);
+            appViewingRecordsVo.setSidx("DESC");
+            appViewingRecordsVo.setSord("updateTime");
+
+            PageInfo pageInfo = appViewingRecordsService.pageByClass(appViewingRecordsVo,AppViewingRecordsSimpleVo.class);
+            List<AppViewingRecordsSimpleVo> list = pageInfo.getRows();
+            for (AppViewingRecordsSimpleVo vo :list){
+                AppVideosVo _appVideosVo = appVideosService.getVo(vo.getVideoId());
+                if(_appVideosVo !=null){
+                    vo.setUrl(_appVideosVo.getUrl());
+                    vo.setVideoName(_appVideosVo.getVideoName());
+                    vo.setVideoPoster(_appVideosVo.getVideoPoster());
+                }
+            }
+            pageInfo.setRows(list);
+
+            return ResultVOUtil.success(pageInfo);
+        } catch (UserException e) {
+            return ResultVOUtil.error(e.getCode(), e.getMessage());
+        }
+
+    }
+}

+ 29 - 0
src/main/java/com/dapp/moviewebsite/app/appViewingRecords/dto/ViewingRecordsDto.java

@@ -0,0 +1,29 @@
+package com.dapp.moviewebsite.app.appViewingRecords.dto;
+
+import lombok.Data;
+
+import javax.validation.Valid;
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+/**
+ * @author:slambb
+ * @date:2024/4/26
+ */
+@Data
+public class ViewingRecordsDto {
+    @NotBlank(message = "videoUrl 字符串不能为空且不能只包含空白字符")
+    String videoUrl;
+    @NotBlank(message = "name 字符串不能为空且不能只包含空白字符")
+    String name;
+
+    @NotNull(message = "duration 不能为空")
+    @Min(value = 0, message = "数字必须大于或等于0")
+    Integer duration;
+    @Min(value = 0, message = "数字必须大于或等于0")
+    @NotNull(message = "currentSet 不能为空")
+    Integer currentSet;
+    @NotBlank(message = "poster 字符串不能为空且不能只包含空白字符")
+    String poster;
+}

+ 38 - 0
src/main/java/com/dapp/moviewebsite/app/appViewingRecords/pojo/AppViewingRecords.java

@@ -0,0 +1,38 @@
+package com.dapp.moviewebsite.app.appViewingRecords.pojo;
+
+import lombok.Data;
+import javax.persistence.*;
+import java.io.Serializable;
+import java.util.Date;
+
+@Entity
+@Table(name = "app_viewing_records")
+@Data
+public class AppViewingRecords implements Serializable {
+    @Id
+    @GeneratedValue(strategy= GenerationType.IDENTITY)
+    private Integer id;//
+
+    private String userId;//后台自己的用户id
+
+    private Integer videoId;
+
+    private Integer type;//收藏类型:0:other,1:视频
+
+    private String url;//视频路径
+
+    private String videoName;//视频名字
+
+    private Integer duration;//视频时长
+
+    private Integer currentSet;//当前集数
+
+    private String videoPoster;//视频海报
+
+    private Integer playCount;//播放次数
+
+    private Date createTime;//
+
+    private Date updateTime;//
+
+}

+ 16 - 0
src/main/java/com/dapp/moviewebsite/app/appViewingRecords/repository/AppViewingRecordsRepository.java

@@ -0,0 +1,16 @@
+package com.dapp.moviewebsite.app.appViewingRecords.repository;
+
+import com.dapp.moviewebsite.common.repository.*;
+import com.dapp.moviewebsite.app.appViewingRecords.pojo.AppViewingRecords;
+import org.springframework.stereotype.Repository;
+
+import java.util.Optional;
+
+@Repository
+public interface AppViewingRecordsRepository extends CommonRepository<AppViewingRecords, Integer> {
+    //根据用户id和视频url查找
+    Optional<AppViewingRecords> findByUserIdAndUrl(String userId, String Url);
+    //根据videoId查找
+    Optional<AppViewingRecords> findByUserIdAndVideoId(String userId,Integer videoId);
+
+}

+ 20 - 0
src/main/java/com/dapp/moviewebsite/app/appViewingRecords/service/AppViewingRecordsService.java

@@ -0,0 +1,20 @@
+package com.dapp.moviewebsite.app.appViewingRecords.service;
+
+import com.dapp.moviewebsite.app.appFavorite.pojo.AppFavorite;
+import com.dapp.moviewebsite.app.appFavorite.vo.AppFavoriteVo;
+import com.dapp.moviewebsite.common.service.*;
+import com.dapp.moviewebsite.app.appViewingRecords.pojo.AppViewingRecords;
+import com.dapp.moviewebsite.app.appViewingRecords.vo.AppViewingRecordsVo;
+
+public interface AppViewingRecordsService extends CommonService<AppViewingRecordsVo, AppViewingRecords, Integer> {
+    AppViewingRecords findByUserIdAndUrl(String userId , String url);
+    AppViewingRecords findByUserIdAndVideoId(String userId ,Integer videoId);
+    //添加收藏操作
+    AppViewingRecordsVo addAppViewingRecordsVo(String userId,
+                                               Integer videoId,
+                                   String videoUrl,
+                                   String name,
+                                   Integer duration,
+                                   Integer currentSet,
+                                   String poster );
+}

+ 72 - 0
src/main/java/com/dapp/moviewebsite/app/appViewingRecords/service/AppViewingRecordsServiceImpl.java

@@ -0,0 +1,72 @@
+package com.dapp.moviewebsite.app.appViewingRecords.service;
+
+import cn.hutool.core.date.DateUtil;
+import com.dapp.moviewebsite.app.appFavorite.pojo.AppFavorite;
+import com.dapp.moviewebsite.app.appViewingRecords.vo.AppViewingRecordsSimpleVo;
+import com.dapp.moviewebsite.app.enums.FavoriteType;
+import com.dapp.moviewebsite.common.service.*;
+import com.dapp.moviewebsite.app.appViewingRecords.pojo.AppViewingRecords;
+import com.dapp.moviewebsite.app.appViewingRecords.vo.AppViewingRecordsVo;
+import com.dapp.moviewebsite.app.appViewingRecords.repository.AppViewingRecordsRepository;
+import com.dapp.moviewebsite.common.utils.CopyUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+
+@Service
+@Transactional
+public class AppViewingRecordsServiceImpl extends CommonServiceImpl<AppViewingRecordsVo, AppViewingRecords, Integer> implements AppViewingRecordsService{
+
+    @PersistenceContext
+    private EntityManager em;
+    @Autowired
+    private AppViewingRecordsRepository appViewingRecordsRepository;
+
+
+
+    @Override
+    public AppViewingRecords findByUserIdAndUrl(String userId, String url) {
+        return appViewingRecordsRepository.findByUserIdAndUrl(userId,url).orElse(null);
+    }
+
+    @Override
+    public AppViewingRecords findByUserIdAndVideoId(String userId,Integer videoId) {
+        return appViewingRecordsRepository.findByUserIdAndVideoId(userId,videoId).orElse(null);
+    }
+
+    @Override
+    @Transactional
+    public AppViewingRecordsVo addAppViewingRecordsVo(String userId, Integer videoId, String videoUrl, String name, Integer duration, Integer currentSet, String poster) {
+        //当前用户信息
+        AppViewingRecords appViewingRecords = findByUserIdAndVideoId(userId,videoId); //findByUserIdAndUrl(userId,videoUrl);
+        if(appViewingRecords == null){
+            AppViewingRecordsVo appViewingRecordsVo = new AppViewingRecordsVo();
+            appViewingRecordsVo.setUserId(userId);
+            appViewingRecordsVo.setVideoId(videoId);
+            //appViewingRecordsVo.setUrl(videoUrl);
+            //appViewingRecordsVo.setVideoName(name);
+            appViewingRecordsVo.setDuration(duration);
+            appViewingRecordsVo.setCurrentSet(currentSet);
+            //appViewingRecordsVo.setVideoPoster(poster);
+            //appViewingRecordsVo.setType(FavoriteType.video.ordinal());
+            appViewingRecordsVo.setPlayCount(0);
+            appViewingRecordsVo.setCreateTime(DateUtil.date());
+            appViewingRecordsVo.setUpdateTime(DateUtil.date());
+            appViewingRecordsVo = saveReturnVo(appViewingRecordsVo);
+            return appViewingRecordsVo;
+        }else {
+            //更新时长
+            AppViewingRecordsVo appViewingRecordsVo= CopyUtil.copy(appViewingRecords,AppViewingRecordsVo.class);
+            appViewingRecordsVo.setDuration(duration);
+            appViewingRecordsVo.setCurrentSet(currentSet);
+            //appViewingRecordsVo.setVideoPoster(poster);
+            appViewingRecordsVo.setPlayCount(appViewingRecords.getPlayCount() + 1); //添加一次播放次数
+            appViewingRecordsVo.setUpdateTime(DateUtil.date());
+            appViewingRecordsVo = saveReturnVo(appViewingRecordsVo);
+            return appViewingRecordsVo;
+        }
+
+    }
+}

+ 33 - 0
src/main/java/com/dapp/moviewebsite/app/appViewingRecords/vo/AppViewingRecordsSimpleVo.java

@@ -0,0 +1,33 @@
+package com.dapp.moviewebsite.app.appViewingRecords.vo;
+
+import lombok.Data;
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+public class AppViewingRecordsSimpleVo implements Serializable {
+    //private Integer id;//
+
+    //private String userId;//后台自己的用户id
+
+    private Integer type;//收藏类型:0:other,1:视频
+
+    private Integer videoId;
+
+    private String url;//视频路径
+
+    private String videoName;//视频名字
+
+    private Integer duration;//视频时长
+
+    private Integer currentSet;//当前集数
+
+    private String videoPoster;//视频海报
+
+    private Integer playCount;//播放次数
+
+    private Date createTime;//
+
+    private Date updateTime;//
+
+}

+ 33 - 0
src/main/java/com/dapp/moviewebsite/app/appViewingRecords/vo/AppViewingRecordsVo.java

@@ -0,0 +1,33 @@
+package com.dapp.moviewebsite.app.appViewingRecords.vo;
+
+import com.dapp.moviewebsite. common.pojo.PageCondition;import lombok.Data;
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+public class AppViewingRecordsVo extends PageCondition implements Serializable {
+    private Integer id;//
+
+    private String userId;//后台自己的用户id
+
+    private Integer videoId;
+
+    private Integer type;//收藏类型:0:other,1:视频
+
+    private String url;//视频路径
+
+    private String videoName;//视频名字
+
+    private Integer duration;//视频时长
+
+    private Integer currentSet;//当前集数
+
+    private String videoPoster;//视频海报
+
+    private Integer playCount;//播放次数
+
+    private Date createTime;//
+
+    private Date updateTime;//
+
+}

+ 98 - 0
src/main/java/com/dapp/moviewebsite/app/controller/LoginController.java

@@ -0,0 +1,98 @@
+package com.dapp.moviewebsite.app.controller;
+
+import cn.hutool.core.date.DateUtil;
+import com.dapp.moviewebsite.app.appUser.service.AppUserService;
+import com.dapp.moviewebsite.app.appUser.vo.AppUserVo;
+import com.dapp.moviewebsite.common.VO.ResultVO;
+import com.dapp.moviewebsite.config.utils.RedisConstant;
+import com.dapp.moviewebsite.config.utils.RedisSettingMap;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.validation.constraints.NotBlank;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * 统一管理登录接口
+ * @author:slambb
+ * @date:2024/4/23
+ */
+@Validated
+@RestController
+@RequestMapping("/program")
+@Slf4j
+public class LoginController {
+    @Autowired
+    private RedisSettingMap redisSettingMap;
+
+    @Autowired
+    private AppUserService appUserService;
+    /**
+     *
+     * @param address
+     * @return
+     */
+    @GetMapping("/getTestToken")
+    public ResultVO getTestToken(@RequestParam("address") @NotBlank(message = "address 字符串不能为空且不能只包含空白字符") String address) {
+
+        log.info("getTestToken address={}", address);
+        String token = UUID.randomUUID().toString();
+        Integer expire = RedisConstant.EXPIRE;//过期时间
+        Map<String, String> tokenMap = new HashMap<>();
+        //拿到用户userid
+        tokenMap.put("userId", address);
+
+        //2.设置token 到redis
+        redisSettingMap.putToken(token, tokenMap);
+        //3.设置token到cookie
+        //CookieUtil.set(response, CookieConstant.TOKEN, token, expire);
+
+        //简单是否存在数据库。不存在创建
+        AppUserVo appUserVo = appUserService.getVo(address);
+        if(appUserVo == null) {
+            appUserVo = new AppUserVo();
+            appUserVo.setUserId(address);
+            appUserVo.setLoginName("TestLogin1");
+            appUserVo.setUserName("TestUser1");
+            appUserVo.setPassword("TestUser1");
+            appUserVo.setValid(1);
+            appUserVo.setLastChangePwdTime(DateUtil.date());
+            appUserVo.setLimitMultiLogin(1);
+            appUserVo.setCreateTime(DateUtil.date());
+            appUserVo.setUpdateTime(DateUtil.date());
+            appUserService.save(appUserVo);
+        }
+
+        ResultVO resultVO = new ResultVO();
+        resultVO.setCode(0);
+        resultVO.setMsg("成功");
+        resultVO.setData(token);
+        return resultVO;
+
+    }
+
+
+    @GetMapping("/analysisToken")
+    public ResultVO analysisToken(@RequestParam("userId") String userId) {
+
+        log.info("getTestToken address={}", userId);
+        Map<String, String> tokenMap = new HashMap<>();
+        //拿到用户userid
+        tokenMap.put("userId", userId);
+
+        ResultVO resultVO = new ResultVO();
+        resultVO.setCode(0);
+        resultVO.setMsg("成功");
+        resultVO.setData(tokenMap);
+
+        return resultVO;
+
+    }
+}

+ 10 - 0
src/main/java/com/dapp/moviewebsite/app/enums/FavoriteType.java

@@ -0,0 +1,10 @@
+package com.dapp.moviewebsite.app.enums;
+
+/**
+ * @author:slambb
+ * @date:2024/4/23
+ */
+public enum FavoriteType {
+    other,//0
+    video,//1
+}

+ 10 - 0
src/main/java/com/dapp/moviewebsite/app/enums/OperationType.java

@@ -0,0 +1,10 @@
+package com.dapp.moviewebsite.app.enums;
+
+/**
+ * @author:slambb
+ * @date:2024/4/25
+ */
+public enum OperationType {
+    Decrease,//0:减少
+    Increase //1:增加
+}

+ 17 - 0
src/main/java/com/dapp/moviewebsite/common/VO/ResultVO.java

@@ -0,0 +1,17 @@
+package com.dapp.moviewebsite.common.VO;
+
+import lombok.Data;
+
+/**
+ * @author:slambb
+ * @date:2024/4/23
+ */
+@Data
+public class ResultVO<T> {
+    //错误码
+    private Integer code;
+    //请求返回信息
+    private String msg;
+    //请求返回数据
+    private T data;
+}

+ 82 - 0
src/main/java/com/dapp/moviewebsite/common/controller/CommonController.java

@@ -0,0 +1,82 @@
+package com.dapp.moviewebsite.common.controller;
+
+import com.dapp.moviewebsite.annotation.Decrypt;
+import com.dapp.moviewebsite.annotation.Encrypt;
+import com.dapp.moviewebsite.common.pojo.PageInfo;
+import com.dapp.moviewebsite.common.pojo.Result;
+import com.dapp.moviewebsite.common.service.CommonService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+
+import java.util.List;
+
+/**
+ * 通用Controller
+ *
+ * @param <V> 实体类Vo
+ * @param <E> 实体类
+ * @param <T> id主键类型
+ */
+public class CommonController<V, E, T> {
+
+    @Autowired
+    private CommonService<V, E, T> commonService;
+
+    /*
+        CRUD、分页、排序测试
+     */
+    @PostMapping("page")
+    @Decrypt
+    @Encrypt
+    public Result<PageInfo<V>> page(V entityVo) {
+        return commonService.page(entityVo);
+    }
+
+    @PostMapping("list")
+    @Decrypt
+    @Encrypt
+    public Result<List<V>> list(V entityVo) {
+        return commonService.list(entityVo);
+    }
+
+    @GetMapping("get/{id}")
+    public Result<V> get(@PathVariable("id") T id) {
+        return commonService.get(id);
+    }
+
+    /**
+     * 保存对应vo数据
+     * @param entityVo
+     * @return
+     */
+    @PostMapping("save")
+    @Decrypt
+    @Encrypt
+    public Result<V> save(V entityVo) {
+        return commonService.save(entityVo);
+    }
+
+    @DeleteMapping("delete/{id}")
+    public Result<T> delete( @PathVariable("id") T id) {
+        /*
+        批量删除
+        @DeleteMapping("deleteBatch")
+        public Result<T> deleteBatch(@RequestBody List<String> ids){}
+        前端调用:
+        $.ajax({
+            url: ctx + "deleteBatch",
+            type: "DELETE",
+            data: JSON.stringify([id1,id2]),
+            dataType: "JSON",
+            contentType: 'application/json',
+            success: function (data) {
+
+            }
+        });
+         */
+        return commonService.delete(id);
+    }
+}

+ 9 - 0
src/main/java/com/dapp/moviewebsite/common/enums/CodeEnum.java

@@ -0,0 +1,9 @@
+package com.dapp.moviewebsite.common.enums;
+
+/**
+ * @author:slambb
+ * @date:2024/4/23
+ */
+public interface CodeEnum {
+    Integer getCode();
+}

+ 47 - 0
src/main/java/com/dapp/moviewebsite/common/enums/ResultEnum.java

@@ -0,0 +1,47 @@
+package com.dapp.moviewebsite.common.enums;
+
+import lombok.Getter;
+
+/**
+ * @author:slambb
+ * @date:2024/4/23
+ */
+@Getter
+public enum ResultEnum {
+
+    SUCCESS(0,"成功"),
+
+    TOKEN_IS_ILLEGAL(3001,"用户授权认证没有通过!客户端请求参数TOKEN信息无效"),
+    TOKEN_DOES_NOT_EXIST(3002,"用户授权认证没有通过!客户端请求参数中无TOKEN信息"),
+    TOKEN_DOES_NOT_HAVE_USER_ID(3003,"用户授权认证没有通过!TOKEN不存在用户id"),
+    TOKEN_FILTER_ERROR(3004,"登录信息异常!"),
+    //
+    VALID_EXCEPTION(3005,"入参信息异常!"),
+
+
+    //redis部分
+    REDIS_IS_LOCK(3107,"操作过于频繁,稍后再试!"),
+    REDIS_IS_LOCK_ERROR(3108,"操作失败,稍后再试!"),
+    //特定接口访问部分限制
+    LOGIN_IP_IS_ERROR(3209,"IP异常?!"),
+
+    //收藏相关
+    FAVORITE_ADD_SUCCESS(3300,"添加收藏!"),
+    FAVORITE_CANCEL_SUCCESS(3301,"取消收藏!"),
+    FAVORITE_CANCEL_ERROR(3302,"不存在收藏视频!"),
+
+    //观看视频相关
+    VIEWING_RECORDS_CANCEL_ERROR(3402,"不存在视频信息!"),
+
+    //会员相关
+    MEMBER_GET_ERROR(3501,"不存在会员信息!");
+    ;
+    private Integer code;
+
+    private String message;
+
+    ResultEnum(Integer code, String message) {
+        this.code = code;
+        this.message = message;
+    }
+}

+ 28 - 0
src/main/java/com/dapp/moviewebsite/common/enums/UserEnum.java

@@ -0,0 +1,28 @@
+package com.dapp.moviewebsite.common.enums;
+
+import lombok.Getter;
+
+/**
+ * @author:slambb
+ * @date:2024/4/23
+ */
+@Getter
+public enum UserEnum implements CodeEnum {
+
+    USER_ADD(0, "添加用户成功"),
+    USER_UPDATE(2000, "更新用户数据成功"),
+    USER_NOT_EXIST(2001, "请求参数userId为null"),
+    RECENTLY_ADD_ERROR(2010,"最近数据保存错误"),
+    USER_DEFAULT_NULL(2011,"默认头像为null"),
+    //用户修改密码
+    USER_INFO_NULL(2020,"用户数据异常")
+    ;
+    private Integer code;
+
+    private String message;
+
+    UserEnum(Integer code, String message) {
+        this.code = code;
+        this.message = message;
+    }
+}

+ 107 - 0
src/main/java/com/dapp/moviewebsite/common/exception/MyExceptionHandler.java

@@ -0,0 +1,107 @@
+package com.dapp.moviewebsite.common.exception;
+
+import com.dapp.moviewebsite.common.VO.ResultVO;
+import com.dapp.moviewebsite.common.enums.ResultEnum;
+import com.dapp.moviewebsite.common.pojo.Result;
+import com.dapp.moviewebsite.common.utils.ResultVOUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.validation.BindException;
+import org.springframework.validation.BindingResult;
+import org.springframework.validation.ObjectError;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.MissingServletRequestParameterException;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.method.HandlerMethod;
+
+import javax.validation.ConstraintViolationException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * @author:slambb
+ * @date:2024/4/30
+ */
+@ControllerAdvice
+@Slf4j
+public class MyExceptionHandler {
+
+//    //拦截登录异常
+//    @ExceptionHandler(value = AuthorizeException.class)
+//    @ResponseBody
+//    public ResultVO handlerAuthorizeException(AuthorizeException e){
+//        log.info("捕获信息异常{},{}",e.getCode(),e.getMessage());
+//        return ResultVOUtil.error(e.getCode(),e.getMessage());
+//    }
+//
+//    //用户信息异常
+//    @ExceptionHandler(value = UserException.class)
+//    @ResponseBody
+//    public ResultVO handlerUserException(UserException e){
+//
+//        return ResultVOUtil.error(e.getCode(),e.getMessage());
+//    }
+//
+//    //表单错误
+//    @ExceptionHandler(value = BindException.class)
+//    @ResponseBody
+//    public ResultVO handlerBindException(BindException e){
+//        return  ResultVOUtil.error(ResultEnum.VALID_EXCEPTION.getCode(),e.getMessage());
+//    }
+//
+//
+//    //捕获设置了形参,但是在访问该方法时,没有传参的异常
+//    @ExceptionHandler(value = MissingServletRequestParameterException.class)
+//    @ResponseBody
+//    public ResultVO handlerServletRequestParameterException(MissingServletRequestParameterException e){
+//        return ResultVOUtil.error(ResultEnum.VALID_EXCEPTION.getCode(),e.getMessage());
+//    }
+
+    //捕获设置了形参,但是在访问该方法时,没有传参的异常
+    @ExceptionHandler(value = IllegalArgumentException.class)
+    @ResponseBody
+    public ResultVO handlerServletRequestParameterException(IllegalArgumentException e){
+        return  ResultVOUtil.error(ResultEnum.VALID_EXCEPTION.getCode(),e.getMessage());
+    }
+
+    @ResponseBody
+    @ExceptionHandler(MethodArgumentNotValidException.class)
+    public ResultVO handleValidException(MethodArgumentNotValidException e) {
+        //日志记录错误信息
+        //log.error(Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage());
+        BindingResult bindingResult= e.getBindingResult();
+        if (bindingResult != null) {
+            if (bindingResult.hasErrors()) {
+                List<ObjectError> errorList = bindingResult.getAllErrors();
+                List<String> resultList = new ArrayList<>();
+                for (ObjectError error : errorList) {
+                    resultList.add(error.getDefaultMessage());
+                }
+                return ResultVOUtil.error(ResultEnum.VALID_EXCEPTION.getCode(),String.join(",", resultList));
+            }
+        }
+
+        return  ResultVOUtil.error(ResultEnum.VALID_EXCEPTION);
+    }
+
+    /**
+     * 参数校验异常:直接参数校验。
+     * <p>
+     * 此校验适用的接口,需要满足如下条件:
+     * 1. 需要校验的参数“直接”作为接口方法的参数;
+     * 2. Controller上添加 @Validated 注解;
+     * 3. 参数前添加了校验规则注解(比如 @Pattern)。
+     * <p>
+     * 示例:删除用户接口
+     */
+    @ExceptionHandler(value = ConstraintViolationException.class)
+    @ResponseBody
+    public ResultVO handleConstraintViolationException(ConstraintViolationException e) {
+         return  ResultVOUtil.error(ResultEnum.VALID_EXCEPTION.getCode(),e.getMessage());
+    }
+
+}

+ 24 - 0
src/main/java/com/dapp/moviewebsite/common/exception/UserException.java

@@ -0,0 +1,24 @@
+package com.dapp.moviewebsite.common.exception;
+
+import com.dapp.moviewebsite.common.enums.UserEnum;
+import lombok.Getter;
+
+/**
+ * @author:slambb
+ * @date:2024/4/23
+ */
+@Getter
+public class UserException extends RuntimeException{
+    private Integer code;
+
+    public UserException(UserEnum userEnum) {
+        super(userEnum.getMessage());
+
+        this.code = userEnum.getCode();
+    }
+
+    public UserException(Integer code, String message) {
+        super(message);
+        this.code = code;
+    }
+}

+ 22 - 0
src/main/java/com/dapp/moviewebsite/common/pojo/IpVo.java

@@ -0,0 +1,22 @@
+package com.dapp.moviewebsite.common.pojo;
+
+import lombok.Data;
+
+/**
+ * ip
+ */
+@Data
+public class IpVo {
+    private String ip;//IP地址
+    private String pro;//省
+    private String proCode;//省编码
+    private String city;//城市
+    private String cityCode;//城市编码
+    private String region;//区
+    private String regionCode;//区编码
+    private String addr;//详细地址 + 运营商
+
+    //主要用于接参,无实际意义
+    private String regionNames;
+    private String err;
+}

+ 31 - 0
src/main/java/com/dapp/moviewebsite/common/pojo/MonitorVo.java

@@ -0,0 +1,31 @@
+package com.dapp.moviewebsite.common.pojo;
+
+import lombok.Data;
+
+/**
+ * 系统监控信息Vo
+ */
+@Data
+public class MonitorVo {
+    private String os;//操作系统
+    private String runTime;//程序启动时间
+    private String jvmJavaVersion;//java版本
+
+    //jvm
+    private String jvmHeapInit;//jvm内存的初始大小
+    private String jvmHeapMax;//jvm最大可用内存量
+    private String jvmHeapUsed;//jvm已使用的内存量
+    private String jvmHeapCommitted;//jvm已申请的内存量
+    private String jvmNonHeapInit;//jvm内存的初始大小
+    private String jvmNonHeapMax;//jvm最大可用内存量
+    private String jvmNonHeapUsed;//jvm已使用的内存量
+    private String jvmNonHeapCommitted;//jvm已申请的内存量
+
+    //硬件信息
+    private String cpuInfo;//CPU信息
+    private String cpuUseRate;//CPU使用率
+    private String ramTotal;//系统内存总量
+    private String ramUsed;//已使用的系统内存量
+    private String diskTotal;//系统磁盘总量
+    private String diskUsed;//已使用的系统磁盘量
+}

+ 39 - 0
src/main/java/com/dapp/moviewebsite/common/pojo/PageCondition.java

@@ -0,0 +1,39 @@
+package com.dapp.moviewebsite.common.pojo;
+
+import lombok.Data;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.domain.Sort.Direction;
+import org.springframework.util.StringUtils;
+
+/**
+ * 分页条件(参考JqGrid插件)
+ */
+@Data
+public class PageCondition {
+    private int page = 1;//当前页码
+    private int rows = 10;//页面大小
+    private String sidx;//排序字段
+    private String sord;//排序方式
+
+    /**
+     * 获取JPA的分页查询对象
+     */
+    public Pageable getPageable() {
+        //处理非法页码
+        if (page < 0) {
+            page = 1;
+        }
+        //处理非法页面大小
+        if (rows < 0) {
+            rows = 10;
+        }
+        //处理排序
+        if(StringUtils.hasText(sidx) && StringUtils.hasText(sord)){
+            Direction direction = "desc".equals(sidx.toLowerCase()) ? Direction.DESC : Direction.ASC;
+            return PageRequest.of(page - 1, rows, Sort.by(direction, sord));
+        }
+        return PageRequest.of(page - 1, rows);
+    }
+}

+ 83 - 0
src/main/java/com/dapp/moviewebsite/common/pojo/PageInfo.java

@@ -0,0 +1,83 @@
+package com.dapp.moviewebsite.common.pojo;
+
+import com.dapp.moviewebsite.common.utils.CopyUtil;
+import lombok.Data;
+import org.hibernate.query.internal.NativeQueryImpl;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.repository.support.PageableExecutionUtils;
+
+import javax.persistence.EntityManager;
+import javax.persistence.Query;
+import java.util.List;
+
+/**
+ * 分页对象(参考JqGrid插件)
+ */
+@Data
+public class PageInfo<M> {
+    private int page;//当前页码
+    private int pageSize;//页面大小
+    private String sidx;//排序字段
+    private String sord;//排序方式
+
+    private List<M> rows;//分页结果
+    private int records;//总记录数
+    private int total;//总页数
+
+    /**
+     * 获取统一分页结果
+     */
+    public static <M> PageInfo<M> of(Page page, Class<M> entityModelClass) {
+        int records = (int) page.getTotalElements();
+        int pageSize = page.getSize();
+        int total = records % pageSize == 0 ? records / pageSize : records / pageSize + 1;
+
+        PageInfo<M> pageInfo = new PageInfo<>();
+        pageInfo.setPage(page.getNumber() + 1);//页码
+        pageInfo.setPageSize(pageSize);//页面大小
+        pageInfo.setRows(CopyUtil.copyList(page.getContent(), entityModelClass));//分页结果
+        pageInfo.setRecords(records);//总记录数
+        pageInfo.setTotal(total);//总页数
+        return pageInfo;
+    }
+
+    /**
+     * 设置当前页面的content
+     * @param page
+     * @param content
+     * @param <M>
+     * @return
+     */
+    public static <M> PageInfo<M> customContent(Page page, List<M> content) {
+        int records = (int) page.getTotalElements();
+        int pageSize = page.getSize();
+        int total = records % pageSize == 0 ? records / pageSize : records / pageSize + 1;
+
+        PageInfo<M> pageInfo = new PageInfo<>();
+        pageInfo.setPage(page.getNumber() + 1);//页码
+        pageInfo.setPageSize(pageSize);//页面大小
+        pageInfo.setRows(content);//分页结果
+        pageInfo.setRecords(records);//总记录数
+        pageInfo.setTotal(total);//总页数
+        return pageInfo;
+    }
+
+    /**
+     * 获取JPA的分页对象
+     */
+    public static Page getJPAPage(Query query, PageRequest pageRequest, EntityManager em) {
+        query.setFirstResult((int) pageRequest.getOffset());
+        query.setMaxResults(pageRequest.getPageSize());
+
+        //获取分页结果
+        return PageableExecutionUtils.getPage(query.getResultList(), pageRequest, () -> {
+            //设置countQuerySQL语句
+            Query countQuery = em.createNativeQuery("select count(*) from ( " + ((NativeQueryImpl) query).getQueryString() + " ) count_table");
+            //设置countQuerySQL参数
+            query.getParameters().forEach(parameter -> countQuery.setParameter(parameter.getName(), query.getParameterValue(parameter.getName())));
+            //返回一个总数
+            return Long.valueOf(countQuery.getResultList().get(0).toString());
+        });
+    }
+}

+ 42 - 0
src/main/java/com/dapp/moviewebsite/common/pojo/ParameterRequestWrapper.java

@@ -0,0 +1,42 @@
+package com.dapp.moviewebsite.common.pojo;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 重写一个RequestWrapper,实现可修改Parameter的值
+ */
+public class ParameterRequestWrapper extends HttpServletRequestWrapper {
+
+    private Map<String , String[]> params = new HashMap<String, String[]>();
+
+    public ParameterRequestWrapper(HttpServletRequest request) {
+        super(request);
+        this.params.putAll(request.getParameterMap());
+    }
+
+    //重写getParameter,从当前类中的map获取(查看UsernamePasswordAuthenticationFilter可知)
+    @Override
+    public String getParameter(String name) {
+        String[]values = params.get(name);
+        if(values == null || values.length == 0) {
+            return null;
+        }
+        return values[0];
+    }
+
+    //增加参数
+    public void addParameter(String name, Object value) {
+        if(value != null) {
+            if(value instanceof String[]) {
+                params.put(name , (String[])value);
+            }else if(value instanceof String) {
+                params.put(name , new String[] {(String)value});
+            }else {
+                params.put(name , new String[] {String.valueOf(value)});
+            }
+        }
+    }
+}

+ 79 - 0
src/main/java/com/dapp/moviewebsite/common/pojo/Result.java

@@ -0,0 +1,79 @@
+package com.dapp.moviewebsite.common.pojo;
+
+import com.dapp.moviewebsite.common.enums.ResultEnum;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 统一返回对象
+ */
+
+@Data
+public class Result<T> implements Serializable {
+    /**
+     * 通信数据
+     */
+    private T data;
+    /**
+     * 通信状态
+     */
+    private boolean flag = true;
+    /**
+     * 通信描述
+     */
+    private String msg = "操作成功";
+
+    /**
+     * 通信code
+     */
+    private Integer code = 0;
+
+    /**
+     * 通过静态方法获取实例
+     */
+    public static <T> Result<T> of(T data) {
+        return new Result<>(data);
+    }
+
+    public static <T> Result<T> of(T data, boolean flag) {
+        return new Result<>(data, flag);
+    }
+
+    public static <T> Result<T> of(T data, boolean flag, String msg) {
+        return new Result<>(data, flag, msg);
+    }
+    public static <T> Result<T> of(T data, boolean flag, String msg,Integer code) {
+        return new Result<>(data, flag, msg,code);
+    }
+
+    public static <T> Result<T> of(T data, boolean flag, ResultEnum resultEnum) {
+        return new Result<>(data, flag, resultEnum.getMessage(),resultEnum.getCode());
+    }
+    @Deprecated
+    public Result() {
+
+    }
+
+    private Result(T data) {
+        this.data = data;
+    }
+
+    private Result(T data, boolean flag) {
+        this.data = data;
+        this.flag = flag;
+    }
+
+    private Result(T data, boolean flag, String msg) {
+        this.data = data;
+        this.flag = flag;
+        this.msg = msg;
+    }
+
+    private Result(T data, boolean flag, String msg ,Integer code) {
+        this.data = data;
+        this.flag = flag;
+        this.msg = msg;
+        this.code = code;
+    }
+}

+ 16 - 0
src/main/java/com/dapp/moviewebsite/common/repository/CommonRepository.java

@@ -0,0 +1,16 @@
+package com.dapp.moviewebsite.common.repository;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.repository.NoRepositoryBean;
+
+/**
+ * 通用Repository
+ *
+ * @param <E> 实体类
+ * @param <T> id主键类型
+ */
+@NoRepositoryBean
+public interface CommonRepository<E,T> extends JpaRepository<E,T>, JpaSpecificationExecutor<E> {
+
+}

+ 60 - 0
src/main/java/com/dapp/moviewebsite/common/service/CommonService.java

@@ -0,0 +1,60 @@
+package com.dapp.moviewebsite.common.service;
+
+
+import com.dapp.moviewebsite.common.pojo.PageInfo;
+import com.dapp.moviewebsite.common.pojo.Result;
+
+import java.util.List;
+
+/**
+ * 通用Service
+ *
+ * @param <V> 实体类Vo
+ * @param <E> 实体类
+ * @param <T> id主键类型
+ */
+public interface CommonService<V, E,T> {
+
+    Result<PageInfo<V>> page(V entityVo);
+
+    PageInfo<V> pageByClass(V entityVo, Class entityModelClass);
+
+    Result<List<V>> list(V entityVo);
+
+    List<V> listVo(V entityVo);
+
+    Result<V> get(T id);
+
+    V getVo(T id);
+
+    Result<V> save(V entityVo);
+
+    V saveReturnVo(V entityVo);
+
+    Result<T> delete(T id);
+
+    //更新当前列表数据到缓存
+    List<E> updateListToCache(String key);
+    //添加缓存列表操作
+    List<E> getListFromCache(String key);
+
+    //注解操作
+
+    /**
+     * 获取对应的列表缓存
+     * @return
+     */
+    List<E> getListFromCache();
+
+    /**
+     * 更新对应的列表缓存
+     * @return
+     */
+    List<E> updateListToCache();
+
+
+    V saveAndCache(V entityVo);
+
+    T deleteAndCache(T id);
+
+}

+ 313 - 0
src/main/java/com/dapp/moviewebsite/common/service/CommonServiceImpl.java

@@ -0,0 +1,313 @@
+package com.dapp.moviewebsite.common.service;
+
+import cn.hutool.json.JSONUtil;
+import com.dapp.moviewebsite.common.pojo.PageCondition;
+import com.dapp.moviewebsite.common.pojo.PageInfo;
+import com.dapp.moviewebsite.common.pojo.Result;
+import com.dapp.moviewebsite.common.repository.CommonRepository;
+import com.dapp.moviewebsite.common.utils.CopyUtil;
+import com.dapp.moviewebsite.common.utils.ErrorUtil;
+import com.dapp.moviewebsite.common.utils.UUIDUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.hibernate.annotations.NotFound;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cache.annotation.CacheConfig;
+import org.springframework.cache.annotation.CachePut;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.data.domain.Example;
+import org.springframework.data.domain.Page;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.util.StringUtils;
+
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import java.lang.reflect.Field;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * 通用Service实现类
+ *
+ * @param <V> 实体类Vo
+ * @param <E> 实体类
+ * @param <T> id主键类型
+ */
+@Slf4j
+@CacheConfig(cacheNames = "com",keyGenerator = "keyGenerator")
+public class CommonServiceImpl<V, E, T> implements CommonService<V, E, T> {
+
+    private Class<V> entityVoClass;//实体类Vo
+
+    private Class<E> entityClass;//实体类
+
+
+    @Autowired
+    private CommonRepository<E, T> commonRepository;//注入实体类仓库
+
+    @Autowired
+    private StringRedisTemplate redisTemplate; //注入缓存机制
+
+    @Value("${spring.application.name}")
+    private String applicationName;
+    //key 的前缀
+    private String keyPrefixStr = "com:";
+
+
+    public CommonServiceImpl() {
+        Type[] types = ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments();
+        this.entityVoClass = (Class<V>) types[0];
+        this.entityClass = (Class<E>) types[1];
+    }
+
+    @Override
+    public Result<PageInfo<V>> page(V entityVo) {
+        //实体类缺失分页信息
+        if (!(entityVo instanceof PageCondition)) {
+            throw new RuntimeException("实体类" + entityVoClass.getName() + "未继承PageCondition。");
+        }
+        PageCondition pageCondition = (PageCondition) entityVo;
+        Page<E> page = commonRepository.findAll(Example.of(CopyUtil.copy(entityVo, entityClass)), pageCondition.getPageable());
+        return Result.of(PageInfo.of(page, entityVoClass));
+    }
+
+    @Override
+    public PageInfo<V> pageByClass(V entityVo, Class entityModelClass) {
+        //实体类缺失分页信息
+        if (!(entityVo instanceof PageCondition)) {
+            throw new RuntimeException("实体类" + entityVoClass.getName() + "未继承PageCondition。");
+        }
+        PageCondition pageCondition = (PageCondition) entityVo;
+        Page<E> page = commonRepository.findAll(Example.of(CopyUtil.copy(entityVo, entityClass)), pageCondition.getPageable());
+        return PageInfo.of(page, entityModelClass);
+    }
+
+    @Override
+    public Result<List<V>> list(V entityVo) {
+        List<E> entityList = commonRepository.findAll(Example.of(CopyUtil.copy(entityVo, entityClass)));
+        List<V> entityModelList = CopyUtil.copyList(entityList, entityVoClass);
+        return Result.of(entityModelList);
+    }
+
+    @Override
+    public List<V> listVo(V entityVo) {
+        List<E> entityList = commonRepository.findAll(Example.of(CopyUtil.copy(entityVo, entityClass)));
+        List<V> entityModelList = CopyUtil.copyList(entityList, entityVoClass);
+        return entityModelList;
+    }
+
+    @Override
+    public Result<V> get(T id) {
+        Optional<E> optionalE = commonRepository.findById(id);
+        if (!optionalE.isPresent()) {
+            return Result.of(null, false, "ID不存在!");
+        }
+        return Result.of(CopyUtil.copy(optionalE.get(), entityVoClass));
+    }
+
+    @Override
+    public V getVo(T id) {
+        Optional<E> optionalE = commonRepository.findById(id);
+        return !optionalE.isPresent() ? null : CopyUtil.copy(optionalE.get(), entityVoClass);
+    }
+
+    @Override
+    public Result<V> save(V entityVo) {
+        E e = this.saveEntityVo(entityVo);
+        return Result.of(CopyUtil.copy(e, entityVoClass));
+    }
+
+    @Override
+    public V saveReturnVo(V entityVo) {
+        E e = this.saveEntityVo(entityVo);
+        return CopyUtil.copy(e, entityVoClass);
+    }
+
+    @Override
+    public Result<T> delete(T id) {
+        commonRepository.deleteById(id);
+        return Result.of(id);
+    }
+
+
+    /**
+     * 更新当前列表数据到缓存
+     *
+     * @param key
+     */
+    public List<E> updateListToCache(String key) {
+        key = keyPrefixStr.concat(key);
+        List<E> entityList = commonRepository.findAll();
+        redisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(entityList));
+        return entityList;
+    }
+
+
+    /**
+     * 从缓存中获取列表,没有缓存更新一次数据库数据到缓存
+     *
+     * @param key
+     * @return
+     */
+    @Override
+    public List<E> getListFromCache(String key) {
+        key = keyPrefixStr.concat(key);
+        List<E> entityList;
+        String s = redisTemplate.opsForValue().get(key);
+        if (StringUtils.hasText(s)) {
+            entityList = JSONUtil.toList(s, entityClass);
+        } else {
+            entityList = commonRepository.findAll();
+            redisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(entityList));
+        }
+        return entityList;
+    }
+
+
+    /**
+     * 检测是否有对应的缓存,没有则写入缓存
+     * 注意:如果缓存有数据,不会再更新缓存
+     * @return
+     */
+    @Override
+    @Cacheable(key = "targetClass+'_findAll'")
+    public List<E> getListFromCache() {
+        List<E> entityList = commonRepository.findAll();
+        return entityList;
+    }
+
+    /**
+     * 更新数据后重新获取全部数据到缓存
+     * @return
+     */
+    @Override
+    @CachePut(key = "targetClass+'_findAll'")
+    public List<E> updateListToCache() {
+        List<E> entityList = commonRepository.findAll();
+        return entityList;
+    }
+
+
+    @Override
+    public V saveAndCache(V entityVo) {
+        E e = this.saveEntityVo(entityVo);
+        //更新当前缓存
+        this.updateListToCache();
+        return CopyUtil.copy(e, entityVoClass);
+    }
+
+    @Override
+    public T deleteAndCache(T id) {
+        commonRepository.deleteById(id);
+        //更新当前缓存
+        this.updateListToCache();
+        return id;
+    }
+
+    /**
+     * 保存操作
+     * @param entityVo
+     * @return
+     */
+    private E saveEntityVo(V entityVo) {
+        //传进来的对象(属性可能残缺)
+        E entity = CopyUtil.copy(entityVo, entityClass);
+
+        //最终要保存的对象
+        E entityFull = entity;
+
+        //为空的属性值,忽略属性,BeanUtils复制的时候用到
+        List<String> ignoreProperties = new ArrayList<String>();
+
+        //获取最新数据,解决部分更新时jpa其他字段设置null问题
+        try {
+            //新增 true,更新 false,要求实体类的Id属性排在第一位,因为for循环读取是按照顺序的
+            boolean isInsert = false;
+
+            //反射获取Class的属性(Field表示类中的成员变量)
+            for (Field field : entity.getClass().getDeclaredFields()) {
+                //获取授权
+                field.setAccessible(true);
+                //属性名称
+                String fieldName = field.getName();
+                //属性的值
+                Object fieldValue = field.get(entity);
+
+                //找出Id主键,自增的不设置
+                if (field.isAnnotationPresent(Id.class)) {
+                    if (!field.isAnnotationPresent(GeneratedValue.class)) {
+                        //UUID 部分
+                        if (!StringUtils.isEmpty(fieldValue)) {
+                            //如果Id主键不为空,则为更新
+                            Optional<E> one = commonRepository.findById((T) fieldValue);
+                            if (one.isPresent()) {
+                                entityFull = one.get();
+                            }
+                        } else {
+                            //如果Id主键为空,则为新增
+                            fieldValue = UUIDUtil.getUUID();
+                            //set方法,第一个参数是对象
+                            field.set(entity, fieldValue);
+                            isInsert = true;
+                        }
+                    } else {
+                        //自增id处理数据
+                        if (!StringUtils.isEmpty(fieldValue)) {
+                            //如果Id主键不为空,则为更新
+                            Optional<E> one = commonRepository.findById((T) fieldValue);
+                            if (one.isPresent()) {
+                                entityFull = one.get();
+                            }
+                        } else {
+                            //如果Id主键为空,则为新增
+                            //单纯插入数据,id自增
+                            isInsert = true;
+                        }
+                    }
+
+                }
+                //Boolean is = "createTime".equals(fieldName);
+                //if(is){
+                //    log.info(isInsert +" == "+ is+" == "+StringUtils.isEmpty(fieldValue));
+                //}
+                //如果前端不传这两个值,后台来维护创建时间、更新时间
+                if (isInsert && "createTime".equals(fieldName) && StringUtils.isEmpty(fieldValue)) {
+                    //先赋值给fieldValue,以免后续进行copy对象判断属性是否为忽略属性是出错
+                    fieldValue = new Date();
+
+                    //set方法,第一个参数是对象
+                    field.set(entity, fieldValue);
+                }
+                if ("updateTime".equals(fieldName) && StringUtils.isEmpty(fieldValue)) {
+                    //先赋值给fieldValue,以免后续进行copy对象判断属性是否为忽略属性是出错
+                    fieldValue = new Date();
+
+                    //set方法,第一个参数是对象
+                    field.set(entity, fieldValue);
+                }
+
+                //找出值为空的属性,值为空则为忽略属性,或者被NotFound标注,我们复制的时候不进行赋值
+                if (null == fieldValue || field.isAnnotationPresent(NotFound.class)) {
+                    ignoreProperties.add(fieldName);
+                }
+            }
+            /*
+                org.springframework.beans BeanUtils.copyProperties(A,B); 是A中的值付给B
+                org.apache.commons.beanutils; BeanUtils.copyProperties(A,B);是B中的值付给A
+                把entity的值赋给entityFull,第三个参数是忽略属性,表示不进行赋值
+             */
+            BeanUtils.copyProperties(entity, entityFull, ignoreProperties.toArray(new String[0]));
+        } catch (IllegalAccessException e) {
+            //输出到日志文件中
+            log.error(ErrorUtil.errorInfoToString(e));
+        }
+
+        E e = commonRepository.save(entityFull);
+        return e;
+    }
+}

+ 166 - 0
src/main/java/com/dapp/moviewebsite/common/utils/CacheUtils.java

@@ -0,0 +1,166 @@
+package com.dapp.moviewebsite.common.utils;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cache.CacheManager;
+import org.springframework.cache.interceptor.SimpleKeyGenerator;
+import org.springframework.cache.support.NullValue;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.cache.RedisCacheConfiguration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
+import org.springframework.cache.interceptor.KeyGenerator;
+import org.springframework.data.redis.cache.RedisCacheManager;
+import org.springframework.data.redis.serializer.RedisSerializationContext;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+import java.io.IOException;
+import java.time.Duration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author:slambb
+ * @date:2024/4/23
+ */
+@Configuration
+public class CacheUtils {
+    @Value("${spring.application.name}")
+    private String applicationName;
+
+    // ${cache} 获取配置文件的配置信息   #{}是spring表达式,获取Bean对象的属性
+    @Value("#{${cache}}")
+    private Map<String, Long> ttlParams;
+
+    /**
+     * @param redisConnectionFactory
+     * @功能描述 redis作为缓存时配置缓存管理器CacheManager,主要配置序列化方式、自定义
+     * <p>
+     * 注意:配置缓存管理器CacheManager有两种方式:
+     * 方式1:通过RedisCacheConfiguration.defaultCacheConfig()获取到默认的RedisCacheConfiguration对象,
+     * 修改RedisCacheConfiguration对象的序列化方式等参数【这里就采用的这种方式】
+     * 方式2:通过继承CachingConfigurerSupport类自定义缓存管理器,覆写各方法,参考:
+     * https://blog.csdn.net/echizao1839/article/details/102660649
+     * <p>
+     * 切记:在缓存配置类中配置以后,yaml配置文件中关于缓存的redis配置就不会生效,如果需要相关配置需要通过@value去读取
+     */
+    @Bean
+    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
+        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
+        redisCacheConfiguration = redisCacheConfiguration
+                // 设置key采用String的序列化方式
+                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(StringRedisSerializer.UTF_8))
+                //设置value序列化方式采用jackson方式序列化
+                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer()))
+                //当value为null时不进行缓存
+                .disableCachingNullValues()
+                // 配置缓存空间名称的前缀
+                .prefixCacheNameWith(applicationName.concat(":"))
+                //全局配置缓存过期时间【可以不配置】
+                .entryTtl(Duration.ofMinutes(30L));
+        //专门指定某些缓存空间的配置,如果过期时间【主要这里的key为缓存空间名称】
+        Map<String, RedisCacheConfiguration> map = new HashMap<>();
+        Set<Map.Entry<String, Long>> entries = ttlParams.entrySet();
+        for (Map.Entry<String, Long> entry : entries) {
+            //指定特定缓存空间对应的过期时间
+            map.put("user", redisCacheConfiguration.entryTtl(Duration.ofSeconds(40)));
+            map.put(entry.getKey(), redisCacheConfiguration.entryTtl(Duration.ofSeconds(entry.getValue())));
+        }
+        return RedisCacheManager
+                .builder(redisConnectionFactory)
+                .cacheDefaults(redisCacheConfiguration)  //默认配置
+                .withInitialCacheConfigurations(map)  //某些缓存空间的特定配置
+                .build();
+    }
+
+
+    /**
+     * 自定义缓存的redis的KeyGenerator【key生成策略】
+     * 注意: 该方法只是声明了key的生成策略,需在@Cacheable注解中通过keyGenerator属性指定具体的key生成策略
+     * 可以根据业务情况,配置多个生成策略
+     * 如: @Cacheable(value = "key", keyGenerator = "cacheKeyGenerator")
+     */
+    @Bean
+    public KeyGenerator keyGenerator() {
+        /**
+         * target: 类
+         * method: 方法
+         * params: 方法参数
+         */
+        return (target, method, params) -> {
+            //获取代理对象的最终目标对象
+            StringBuilder sb = new StringBuilder();
+            sb.append(target.getClass().getSimpleName()).append(":");
+            sb.append(method.getName()).append(":");
+            //调用SimpleKey的key生成器
+            Object key = SimpleKeyGenerator.generateKey(params);
+            return sb.append(key);
+        };
+    }
+
+
+    /**
+     * @param redisConnectionFactory:配置不同的客户端,这里注入的redis连接工厂不同: JedisConnectionFactory、LettuceConnectionFactory
+     * @功能描述 :配置Redis序列化,原因如下:
+     * (1) StringRedisTemplate的序列化方式为字符串序列化,
+     * RedisTemplate的序列化方式默为jdk序列化(实现Serializable接口)
+     * (2) RedisTemplate的jdk序列化方式在Redis的客户端中为乱码,不方便查看,
+     * 因此一般修改RedisTemplate的序列化为方式为JSON方式【建议使用GenericJackson2JsonRedisSerializer】
+     */
+    @Bean
+    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
+        GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = serializer();
+        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
+        // key采用String的序列化方式
+        redisTemplate.setKeySerializer(StringRedisSerializer.UTF_8);
+        // value序列化方式采用jackson
+        redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer);
+        // hash的key也采用String的序列化方式
+        redisTemplate.setHashKeySerializer(StringRedisSerializer.UTF_8);
+        //hash的value序列化方式采用jackson
+        redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer);
+        redisTemplate.setConnectionFactory(redisConnectionFactory);
+        return redisTemplate;
+    }
+
+    /**
+     * 此方法不能用@Ben注解,避免替换Spring容器中的同类型对象
+     */
+    public GenericJackson2JsonRedisSerializer serializer() {
+        ObjectMapper om = new ObjectMapper();
+        om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+        om.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
+        om.registerModule(new JavaTimeModule());
+        om.registerModule((new SimpleModule())
+                .addSerializer(new NullValueSerializer()));
+        //om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
+        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
+        return new GenericJackson2JsonRedisSerializer(om);
+    }
+
+
+    protected class NullValueSerializer extends StdSerializer<NullValue> {
+        private static final long serialVersionUID = 1999052150548658807L;
+        private final String classIdentifier="@class";
+        NullValueSerializer() {
+            super(NullValue.class);
+        }
+        public void serialize(NullValue value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
+            jgen.writeStartObject();
+            jgen.writeStringField(this.classIdentifier, NullValue.class.getName());
+            jgen.writeEndObject();
+        }
+    }
+}
+

+ 561 - 0
src/main/java/com/dapp/moviewebsite/common/utils/CodeDOM.java

@@ -0,0 +1,561 @@
+package com.dapp.moviewebsite.common.utils;
+
+import com.dapp.moviewebsite.common.utils.ErrorUtil;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.PrintWriter;
+import java.sql.*;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 自动生成代码
+ */
+@Slf4j
+public class CodeDOM {
+
+    /**
+     * 构造参数,出入表名
+     */
+    private CodeDOM(String tableName) {
+        this.tableName = tableName;
+        basePackage_ = "com\\dapp\\moviewebsite\\app\\";
+        package_ = basePackage_ + StringUtil.camelCaseName(tableName) + "\\";
+        //System.getProperty("user.dir") 获取的是项目所在路径,如果我们是子项目,则需要添加一层路径
+        basePath = System.getProperty("user.dir") + "\\src\\main\\java\\" + package_;
+        basePackage_ = "com\\dapp\\moviewebsite\\";
+    }
+
+    /**
+     * 数据连接相关
+     */
+    private static final String URL = "jdbc:mysql://42.192.165.168:3306/dapp_ms?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&useSSL=false&serverTimezone=GMT%2b8";
+    private static final String USERNAME = "root";
+    private static final String PASSWORD = "9ab8fad748dead93";
+    private static final String DRIVER_CLASSNAME = "com.mysql.jdbc.Driver";
+    /**
+     * 表名
+     */
+    private String tableName;
+
+    /**
+     * 基础路径
+     */
+    private String basePackage_;
+    private String package_;
+    private String basePath;
+
+    /**
+     * 创建pojo实体类
+     */
+    private void createPojo(List<TableInfo> tableInfos) {
+        File file = FileUtil.createFile(basePath + "pojo\\" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + ".java");
+        StringBuffer stringBuffer = new StringBuffer();
+        stringBuffer.append(
+                "package " + package_.replaceAll("\\\\", ".") + "pojo;\n" +
+                        "\n" +
+                        "import lombok.Data;\n" +
+                        "import javax.persistence.*;\n" +
+                        "import java.io.Serializable;\n" +
+                        "import java.util.Date;\n" +
+                        "\n" +
+                        "@Entity\n" +
+                        "@Table(name = \"" + tableName + "\")\n" +
+                        "@Data\n" +
+                        "public class " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + " implements Serializable {\n"
+        );
+        //遍历设置属性
+        for (TableInfo tableInfo : tableInfos) {
+            //主键
+            if ("PRI".equals(tableInfo.getColumnKey())) {
+                stringBuffer.append("    @Id\n");
+            }
+            //自增
+            if ("auto_increment".equals(tableInfo.getExtra())) {
+                stringBuffer.append("    @GeneratedValue(strategy= GenerationType.IDENTITY)\n");
+            }
+            stringBuffer.append("    private " + StringUtil.typeMapping(tableInfo.getDataType()) + " " + StringUtil.camelCaseName(tableInfo.getColumnName()) + ";//" + tableInfo.getColumnComment() + "\n\n");
+        }
+        stringBuffer.append("}");
+        FileUtil.fileWriter(file, stringBuffer);
+    }
+
+    /**
+     * 创建vo类
+     */
+    private void createVo(List<TableInfo> tableInfos) {
+        File file = FileUtil.createFile(basePath + "vo\\" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Vo.java");
+        StringBuffer stringBuffer = new StringBuffer();
+        stringBuffer.append(
+                "package " + package_.replaceAll("\\\\", ".") + "vo;\n" +
+                        "\n" +
+                        "import "+ basePackage_.replaceAll("\\\\", ".") +" common.pojo.PageCondition;"+
+                        "import lombok.Data;\n" +
+                        "import java.io.Serializable;\n" +
+                        "import java.util.Date;\n" +
+                        "\n" +
+                        "@Data\n" +
+                        "public class " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Vo extends PageCondition implements Serializable {\n"
+        );
+        //遍历设置属性
+        for (TableInfo tableInfo : tableInfos) {
+            stringBuffer.append("    private " + StringUtil.typeMapping(tableInfo.getDataType()) + " " + StringUtil.camelCaseName(tableInfo.getColumnName()) + ";//" + tableInfo.getColumnComment() + "\n\n");
+        }
+        stringBuffer.append("}");
+        FileUtil.fileWriter(file, stringBuffer);
+
+
+
+        File fileSimple = FileUtil.createFile(basePath + "vo\\" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "SimpleVo.java");
+        StringBuffer stringBufferSimple = new StringBuffer();
+        stringBufferSimple.append(
+                "package " + package_.replaceAll("\\\\", ".") + "vo;\n" +
+                        "\n" +
+                        "import lombok.Data;\n" +
+                        "import java.io.Serializable;\n" +
+                        "import java.util.Date;\n" +
+                        "\n" +
+                        "@Data\n" +
+                        "public class " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "SimpleVo implements Serializable {\n"
+        );
+        //遍历设置属性
+        for (TableInfo tableInfo : tableInfos) {
+            stringBufferSimple.append("    private " + StringUtil.typeMapping(tableInfo.getDataType()) + " " + StringUtil.camelCaseName(tableInfo.getColumnName()) + ";//" + tableInfo.getColumnComment() + "\n\n");
+        }
+        stringBufferSimple.append("}");
+        FileUtil.fileWriter(fileSimple, stringBufferSimple);
+    }
+
+    /**
+     * 创建repository类
+     */
+    private void createRepository(List<TableInfo> tableInfos) {
+        File file = FileUtil.createFile(basePath + "repository\\" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Repository.java");
+        StringBuffer stringBuffer = new StringBuffer();
+        String t = "String";
+        //遍历属性
+        for (TableInfo tableInfo : tableInfos) {
+            //主键
+            if ("PRI".equals(tableInfo.getColumnKey())) {
+                t = StringUtil.typeMapping(tableInfo.getDataType());
+            }
+        }
+        stringBuffer.append(
+                "package " + package_.replaceAll("\\\\", ".") + "repository;\n" +
+                        "\n" +
+                        "import " + basePackage_.replaceAll("\\\\", ".") + "common.repository.*;\n" +
+                        "import " + package_.replaceAll("\\\\", ".") + "pojo." + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + ";\n" +
+                        "import org.springframework.stereotype.Repository;\n" +
+                        "\n" +
+                        "@Repository\n" +
+                        "public interface " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Repository extends CommonRepository<" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + ", " + t + "> {"
+        );
+        stringBuffer.append("\n");
+        stringBuffer.append("}");
+        FileUtil.fileWriter(file, stringBuffer);
+    }
+
+    /**
+     * 创建service类
+     */
+    private void createService(List<TableInfo> tableInfos) {
+        File file = FileUtil.createFile(basePath + "service\\" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Service.java");
+        StringBuffer stringBuffer = new StringBuffer();
+        String t = "String";
+        //遍历属性
+        for (TableInfo tableInfo : tableInfos) {
+            //主键
+            if ("PRI".equals(tableInfo.getColumnKey())) {
+                t = StringUtil.typeMapping(tableInfo.getDataType());
+            }
+        }
+        stringBuffer.append(
+                "package " + package_.replaceAll("\\\\", ".") + "service;\n" +
+                        "\n" +
+                        "import " + basePackage_.replaceAll("\\\\", ".") + "common.service.*;\n" +
+                        "import " + package_.replaceAll("\\\\", ".") + "pojo." + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + ";\n" +
+                        "import " + package_.replaceAll("\\\\", ".") + "vo." + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Vo;\n" +
+                        "\n" +
+                        "public interface " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Service extends CommonService<" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Vo, " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + ", " + t + "> {"
+        );
+        stringBuffer.append("\n");
+        stringBuffer.append("}");
+        FileUtil.fileWriter(file, stringBuffer);
+
+        //Impl
+        File file1 = FileUtil.createFile(basePath + "service\\" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "ServiceImpl.java");
+        StringBuffer stringBuffer1 = new StringBuffer();
+        stringBuffer1.append(
+                "package " + package_.replaceAll("\\\\", ".") + "service;\n" +
+                        "\n" +
+                        "import " + basePackage_.replaceAll("\\\\", ".") + "common.service.*;\n" +
+                        "import " + package_.replaceAll("\\\\", ".") + "pojo." + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + ";\n" +
+                        "import " + package_.replaceAll("\\\\", ".") + "vo." + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Vo;\n" +
+                        "import " + package_.replaceAll("\\\\", ".") + "repository." + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Repository;\n" +
+                        "import org.springframework.beans.factory.annotation.Autowired;\n" +
+                        "import org.springframework.stereotype.Service;\n" +
+                        "import org.springframework.transaction.annotation.Transactional;\n" +
+                        "import javax.persistence.EntityManager;\n" +
+                        "import javax.persistence.PersistenceContext;\n" +
+                        "\n" +
+                        "@Service\n" +
+                        "@Transactional\n" +
+                        "public class " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "ServiceImpl extends CommonServiceImpl<" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Vo, " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + ", " + t + "> implements " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Service{"
+        );
+        stringBuffer1.append("\n\n");
+        stringBuffer1.append(
+                "    @PersistenceContext\n" +
+                        "    private EntityManager em;\n");
+
+        stringBuffer1.append("" +
+                "    @Autowired\n" +
+                "    private " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Repository " + StringUtil.camelCaseName(tableName) + "Repository;\n");
+        stringBuffer1.append("}");
+        FileUtil.fileWriter(file1, stringBuffer1);
+    }
+
+    /**
+     * 创建controller类
+     */
+    private void createController(List<TableInfo> tableInfos) {
+        File file = FileUtil.createFile(basePath + "controller\\" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Controller.java");
+        StringBuffer stringBuffer = new StringBuffer();
+        String t = "String";
+        //遍历属性
+        for (TableInfo tableInfo : tableInfos) {
+            //主键
+            if ("PRI".equals(tableInfo.getColumnKey())) {
+                t = StringUtil.typeMapping(tableInfo.getDataType());
+            }
+        }
+        stringBuffer.append(
+                "package " + package_.replaceAll("\\\\", ".") + "controller;\n" +
+                        "\n" +
+                        "import " + basePackage_.replaceAll("\\\\", ".") + "common.controller.*;\n" +
+                        "import " + package_.replaceAll("\\\\", ".") + "pojo." + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + ";\n" +
+                        "import " + package_.replaceAll("\\\\", ".") + "vo." + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Vo;\n" +
+                        "import " + package_.replaceAll("\\\\", ".") + "service." + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Service;\n" +
+                        "import org.springframework.beans.factory.annotation.Autowired;\n" +
+                        "import org.springframework.web.bind.annotation.*;\n" +
+                        "\n" +
+                        "@RestController\n" +
+                        "@RequestMapping(\"/" + StringUtil.camelCaseName(tableName) + "/\")\n" +
+                        "public class " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Controller extends CommonController<" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Vo, " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + ", " + t + "> {"
+        );
+        stringBuffer.append("\n");
+        stringBuffer.append("" +
+                "    @Autowired\n" +
+                "    private " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Service " + StringUtil.camelCaseName(tableName) + "Service;\n");
+        stringBuffer.append("}");
+        FileUtil.fileWriter(file, stringBuffer);
+    }
+
+    /**
+     * 获取表结构信息
+     */
+    private List<TableInfo> getTableInfo() {
+        Connection conn = null;
+        PreparedStatement ps = null;
+        ResultSet rs = null;
+        ArrayList<TableInfo> list = new ArrayList<>();
+        try {
+            conn = DBConnectionUtil.getConnection();
+            String sql = "select column_name,data_type,column_comment,column_key,extra from information_schema.columns where table_schema = (select database()) and table_name=?";
+            ps = conn.prepareStatement(sql);
+            ps.setString(1, tableName);
+            rs = ps.executeQuery();
+            while (rs.next()) {
+                TableInfo tableInfo = new TableInfo();
+                //列名,全部转为小写
+                tableInfo.setColumnName(rs.getString("column_name").toLowerCase());
+                //列类型
+                tableInfo.setDataType(rs.getString("data_type"));
+                //列注释
+                tableInfo.setColumnComment(rs.getString("column_comment"));
+                //主键
+                tableInfo.setColumnKey(rs.getString("column_key"));
+                //主键类型
+                tableInfo.setExtra(rs.getString("extra"));
+                list.add(tableInfo);
+            }
+        } catch (SQLException e) {
+            //输出到日志文件中
+            log.error(ErrorUtil.errorInfoToString(e));
+        } finally {
+            assert rs != null;
+            DBConnectionUtil.close(conn, ps, rs);
+        }
+        return list;
+    }
+
+    /**
+     * file工具类
+     */
+    private static class FileUtil {
+        /**
+         * 创建文件
+         *
+         * @param pathNameAndFileName 路径跟文件名
+         * @return File对象
+         */
+        private static File createFile(String pathNameAndFileName) {
+            File file = new File(pathNameAndFileName);
+            try {
+                //获取父目录
+                File fileParent = file.getParentFile();
+                if (!fileParent.exists()) {
+                    fileParent.mkdirs();
+                }
+                //创建文件
+                if (!file.exists()) {
+                    file.createNewFile();
+                }
+            } catch (Exception e) {
+                file = null;
+                System.err.println("新建文件操作出错");
+                //输出到日志文件中
+                log.error(ErrorUtil.errorInfoToString(e));
+            }
+            return file;
+        }
+
+        /**
+         * 字符流写入文件
+         *
+         * @param file         file对象
+         * @param stringBuffer 要写入的数据
+         */
+        private static void fileWriter(File file, StringBuffer stringBuffer) {
+            //字符流
+            try {
+                FileWriter resultFile = new FileWriter(file, false);//true,则追加写入 false,则覆盖写入
+                PrintWriter myFile = new PrintWriter(resultFile);
+                //写入
+                myFile.println(stringBuffer.toString());
+
+                myFile.close();
+                resultFile.close();
+            } catch (Exception e) {
+                System.err.println("写入操作出错");
+                //输出到日志文件中
+                log.error(ErrorUtil.errorInfoToString(e));
+            }
+        }
+    }
+
+    /**
+     * 字符串处理工具类
+     */
+    private static class StringUtil {
+        /**
+         * 数据库类型->JAVA类型
+         *
+         * @param dbType 数据库类型
+         * @return JAVA类型
+         */
+        private static String typeMapping(String dbType) {
+            String javaType;
+            if ("int|integer|tinyint".contains(dbType)) {
+                javaType = "Integer";
+            } else if ("float|double|decimal|real".contains(dbType)) {
+                javaType = "Double";
+            } else if ("date|time|datetime|timestamp".contains(dbType)) {
+                javaType = "Date";
+            } else {
+                javaType = "String";
+            }
+            return javaType;
+        }
+
+        /**
+         * 驼峰转换为下划线
+         */
+        public static String underscoreName(String camelCaseName) {
+            StringBuilder result = new StringBuilder();
+            if (camelCaseName != null && camelCaseName.length() > 0) {
+                result.append(camelCaseName.substring(0, 1).toLowerCase());
+                for (int i = 1; i < camelCaseName.length(); i++) {
+                    char ch = camelCaseName.charAt(i);
+                    if (Character.isUpperCase(ch)) {
+                        result.append("_");
+                        result.append(Character.toLowerCase(ch));
+                    } else {
+                        result.append(ch);
+                    }
+                }
+            }
+            return result.toString();
+        }
+
+        /**
+         * 首字母大写
+         */
+        static String captureName(String name) {
+            char[] cs = name.toCharArray();
+            cs[0] -= 32;
+            return String.valueOf(cs);
+
+        }
+
+        /**
+         * 下划线转换为驼峰
+         */
+        static String camelCaseName(String underscoreName) {
+            StringBuilder result = new StringBuilder();
+            if (underscoreName != null && underscoreName.length() > 0) {
+                boolean flag = false;
+                for (int i = 0; i < underscoreName.length(); i++) {
+                    char ch = underscoreName.charAt(i);
+                    if ("_".charAt(0) == ch) {
+                        flag = true;
+                    } else {
+                        if (flag) {
+                            result.append(Character.toUpperCase(ch));
+                            flag = false;
+                        } else {
+                            result.append(ch);
+                        }
+                    }
+                }
+            }
+            return result.toString();
+        }
+    }
+
+    /**
+     * JDBC连接数据库工具类
+     */
+    private static class DBConnectionUtil {
+
+        static {
+            // 1、加载驱动
+            try {
+                Class.forName(DRIVER_CLASSNAME);
+            } catch (ClassNotFoundException e) {
+                //输出到日志文件中
+                log.error(ErrorUtil.errorInfoToString(e));
+            }
+        }
+
+        /**
+         * 返回一个Connection连接
+         */
+        static Connection getConnection() {
+            Connection conn = null;
+            // 2、连接数据库
+            try {
+                conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
+            } catch (SQLException e) {
+                //输出到日志文件中
+                log.error(ErrorUtil.errorInfoToString(e));
+            }
+            return conn;
+        }
+
+        /**
+         * 关闭Connection,Statement连接
+         */
+        public static void close(Connection conn, Statement stmt) {
+            try {
+                conn.close();
+                stmt.close();
+            } catch (SQLException e) {
+                //输出到日志文件中
+                log.error(ErrorUtil.errorInfoToString(e));
+            }
+        }
+
+        /**
+         * 关闭Connection,Statement,ResultSet连接
+         */
+        public static void close(Connection conn, Statement stmt, ResultSet rs) {
+            try {
+                close(conn, stmt);
+                rs.close();
+            } catch (SQLException e) {
+                //输出到日志文件中
+                log.error(ErrorUtil.errorInfoToString(e));
+            }
+        }
+
+    }
+
+    /**
+     * 表结构行信息实体类
+     */
+    private class TableInfo {
+        private String columnName;
+        private String dataType;
+        private String columnComment;
+        private String columnKey;
+        private String extra;
+
+        TableInfo() {
+        }
+
+        String getColumnName() {
+            return columnName;
+        }
+
+        void setColumnName(String columnName) {
+            this.columnName = columnName;
+        }
+
+        String getDataType() {
+            return dataType;
+        }
+
+        void setDataType(String dataType) {
+            this.dataType = dataType;
+        }
+
+        String getColumnComment() {
+            return columnComment;
+        }
+
+        void setColumnComment(String columnComment) {
+            this.columnComment = columnComment;
+        }
+
+        String getColumnKey() {
+            return columnKey;
+        }
+
+        void setColumnKey(String columnKey) {
+            this.columnKey = columnKey;
+        }
+
+        String getExtra() {
+            return extra;
+        }
+
+        void setExtra(String extra) {
+            this.extra = extra;
+        }
+    }
+
+    /**
+     * 快速创建,供外部调用,调用之前先设置一下项目的基础路径
+     */
+    private String create() {
+        List<TableInfo> tableInfo = getTableInfo();
+        createPojo(tableInfo);
+        createVo(tableInfo);
+        createRepository(tableInfo);
+        createService(tableInfo);
+        createController(tableInfo);
+        System.out.println("生成路径位置:" + basePath);
+        return tableName + " 后台代码生成完毕!";
+    }
+
+    //public static void main(String[] args) {
+    //    //"app_user","app_favorite","app_viewing_records","app_videos","app_user_member","app_user_tran"
+    //    String[] tables = {};
+    //    for (String table : tables) {
+    //        String msg = new CodeDOM(table).create();
+    //        System.out.println(msg);
+    //    }
+    //}
+}

+ 141 - 0
src/main/java/com/dapp/moviewebsite/common/utils/CopyUtil.java

@@ -0,0 +1,141 @@
+package com.dapp.moviewebsite.common.utils;
+
+/**
+ * @author:slambb
+ * @date:2024/4/23
+ */
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.beanutils.BeanMap;
+import org.springframework.beans.BeanWrapper;
+import org.springframework.beans.BeanWrapperImpl;
+
+import java.lang.reflect.Field;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 实体转换工具
+ */
+@Slf4j
+public class CopyUtil {
+
+    /**
+     * 类型转换:实体Vo <->实体  例如:UserVo <-> User
+     * 默认支持1层复杂对象复制
+     */
+    public static <T> T copy(Object src, Class<T> targetType) {
+        return CopyUtil.copy(src,targetType,1);
+    }
+
+    /**
+     * 同上,支持count多层复杂对象复制
+     */
+    public static <T> T copy(Object src, Class<T> targetType,Integer count) {
+        //执行一层,自减1
+        count--;
+
+        T target = null;
+        try {
+            //创建一个空目标对象,并获取一个BeanWrapper代理器,用于属性填充,BeanWrapperImpl在内部使用Spring的BeanUtils工具类对Bean进行反射操作,设置属性。
+            target = targetType.newInstance();
+            BeanWrapper targetBean = new BeanWrapperImpl(target);
+
+            //获取源对象的BeanMap,属性和属性值直接转换为Map的key-value 形式
+            BeanMap srcBean = new BeanMap(src);
+            for (Object key : srcBean.keySet()) {
+                //源对象属性名称
+                String srcPropertyName = key + "";
+                //源对象属性值
+                Object srcPropertyVal = srcBean.get(key);
+                //源对象属性类型
+                Class srcPropertyType = srcBean.getType(srcPropertyName);
+                //目标对象属性类型
+                Class targetPropertyType = targetBean.getPropertyType(srcPropertyName);
+
+                //源对象属性值非空判断、目标对象属性类型非空判断,如果为空跳出,继续操作下一个属性
+                if ("class".equals(srcPropertyName) || targetPropertyType == null) {
+                    continue;
+                }
+
+                //类型相等,可直接设置值,比如:String与String 或者 User与User
+                if (srcPropertyType == targetPropertyType) {
+                    targetBean.setPropertyValue(srcPropertyName, srcPropertyVal);
+                }
+                //类型不相等,比如:User与UserVo
+                else {
+                    //满足条件,跳出递归
+                    if(count <= -1){
+                        return target;
+                    }
+
+                    //如果源复杂对象为null,直接跳过,不需要复制
+                    if(srcPropertyVal == null){
+                        continue;
+                    }
+
+                    //设置目标对象属性值
+                    targetBean.setPropertyValue(srcPropertyName, CopyUtil.copy(srcPropertyVal, targetPropertyType, count));
+                }
+            }
+        } catch (Exception e) {
+            //输出到日志文件中
+            log.error(ErrorUtil.errorInfoToString(e));
+        }
+        return target;
+    }
+
+    /**
+     * 类型转换:实体Vo <->实体  例如:List<UserVo> <-> List<User>
+     */
+    public static <T> List<T> copyList(List srcList, Class<T> targetType) {
+        List<T> newList = new ArrayList<>();
+        for (Object src : srcList) {
+            newList.add(CopyUtil.copy(src, targetType));
+        }
+        return newList;
+    }
+
+    /**
+     * 类型转换:Object[]转Vo
+     * 当使用自定义SQL查询,查询字段跟实体对应不上时,可以使用Object[]接值
+     * em.createNativeQuery(sql.toString()),第二个参数不传时,默认就是用Object[]来接值
+     * 因为是Object[]转Vo,是按顺序来取值、设置,所有要求两边的字段、属性顺序要一一对应
+     */
+    public static <T> T copyByObject(Object[] src, Class<T> targetType){
+        T targetVo = null;
+        try {
+            //遍历Object[]转换为Field[]
+            targetVo  = targetType.newInstance();
+            Field[] fields = targetType.getDeclaredFields();
+            int length = src.length < fields.length ? src.length : fields.length;
+            for (int i = 0; i < length; i++) {
+                Field field = fields[i];
+                Object fieldVal = src[i];
+                if (fieldVal instanceof Character || fieldVal instanceof BigDecimal) {
+                    fieldVal = String.valueOf(fieldVal);
+                }
+
+                field.setAccessible(true);//获取授权
+                field.set(targetVo, fieldVal);//赋值
+            }
+        } catch (InstantiationException | IllegalAccessException e) {
+            ErrorUtil.errorInfoToString(e);
+        }
+        return targetVo;
+    }
+
+    /**
+     * 类型转换:List<Object[]>转List<Vo>
+     */
+    public static <T> List<T> copyListByObject(List<Object[]> srcList, Class<T> targetType) {
+        List<T> newList = new ArrayList<>();
+        if (srcList != null) {
+            for (Object[] src : srcList) {
+                newList.add(CopyUtil.copyByObject(src,targetType));
+            }
+        }
+        return newList;
+    }
+}

+ 123 - 0
src/main/java/com/dapp/moviewebsite/common/utils/DoubleUtil.java

@@ -0,0 +1,123 @@
+package com.dapp.moviewebsite.common.utils;
+
+/**
+ * @author:slambb
+ * @date:2024/4/25
+ */
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+
+/**
+ * double的计算不精确,会有类似0.0000000000000002的误差,正确的方法是使用BigDecimal或者用整型
+ * 整型地方法适合于货币精度已知的情况,比如12.11+1.10转成1211+110计算,最后再/100即可
+ * 以下是摘抄的BigDecimal方法:
+ */
+public class DoubleUtil implements Serializable {
+    private static final long serialVersionUID = -3345205828566485102L;
+    // 默认除法运算精度
+    private static final Integer DEF_DIV_SCALE = 2;
+    /**
+     * 提供精确的加法运算。
+     *
+     * @param value1 被加数
+     * @param value2 加数
+     * @return 两个参数的和
+     */
+    public static Double add(Double value1, Double value2) {
+        BigDecimal b1 = new BigDecimal(Double.toString(value1));
+        BigDecimal b2 = new BigDecimal(Double.toString(value2));
+        return b1.add(b2).doubleValue();
+    }
+    /**
+     * 提供精确的减法运算。
+     *
+     * @param value1 被减数
+     * @param value2 减数
+     * @return 两个参数的差
+     */
+    public static double sub(Double value1, Double value2) {
+        BigDecimal b1 = new BigDecimal(Double.toString(value1));
+        BigDecimal b2 = new BigDecimal(Double.toString(value2));
+        return b1.subtract(b2).doubleValue();
+    }
+    /**
+     * 提供精确的乘法运算。
+     *
+     * @param value1 被乘数
+     * @param value2 乘数
+     * @return 两个参数的积
+     */
+    public static Double mul(Double value1, Double value2) {
+        BigDecimal b1 = new BigDecimal(Double.toString(value1));
+        BigDecimal b2 = new BigDecimal(Double.toString(value2));
+        return b1.multiply(b2).doubleValue();
+    }
+    /**
+     * 提供(相对)精确的除法运算,当发生除不尽的情况时, 精确到小数点以后10位,以后的数字四舍五入。
+     *
+     * @param dividend 被除数
+     * @param divisor 除数
+     * @return 两个参数的商
+     */
+    public static Double divide(Double dividend, Double divisor) {
+        return divide(dividend, divisor, DEF_DIV_SCALE);
+    }
+    /**
+     * 提供(相对)精确的除法运算。 当发生除不尽的情况时,由scale参数指定精度,以后的数字四舍五入。
+     *
+     * @param dividend 被除数
+     * @param divisor 除数
+     * @param scale  表示表示需要精确到小数点以后几位。
+     * @return 两个参数的商
+     */
+    public static Double divide(Double dividend, Double divisor, Integer scale) {
+        if (scale < 0) {
+            throw new IllegalArgumentException("The scale must be a positive integer or zero");
+        }
+        BigDecimal b1 = new BigDecimal(Double.toString(dividend));
+        BigDecimal b2 = new BigDecimal(Double.toString(divisor));
+        return b1.divide(b2, scale, RoundingMode.HALF_UP).doubleValue();
+    }
+    /**
+     * 提供指定数值的(精确)小数位四舍五入处理。
+     *
+     * @param value 需要四舍五入的数字
+     * @param scale 小数点后保留几位
+     * @return 四舍五入后的结果
+     */
+    public static double round(double value,int scale){
+        if(scale<0){
+            throw new IllegalArgumentException("The scale must be a positive integer or zero");
+        }
+        BigDecimal b = new BigDecimal(Double.toString(value));
+        BigDecimal one = new BigDecimal("1");
+        return b.divide(one,scale, RoundingMode.HALF_UP).doubleValue();
+    }
+
+
+    /**
+     * 提供精确的判断大小。
+     *
+     * @param value1
+     * @param value2
+     * @return 两个参数比较大小
+     */
+    public static Integer compare(Double value1, Double value2) {
+        BigDecimal b1 = new BigDecimal(Double.toString(value1));
+        BigDecimal b2 = new BigDecimal(Double.toString(value2));
+
+        Integer result = 0;
+        if (b1.compareTo(b2) == 0) {
+            result = 0;
+        }else if (b1.compareTo(b2) < 0){
+            result = -1;
+        }else if (b1.compareTo(b2) > 0) {
+            result = 1;
+        }else{
+            throw new IllegalArgumentException("The compare is error!");
+        }
+        return result;
+    }
+}

+ 31 - 0
src/main/java/com/dapp/moviewebsite/common/utils/ErrorUtil.java

@@ -0,0 +1,31 @@
+package com.dapp.moviewebsite.common.utils;
+
+/**
+ * @author:slambb
+ * @date:2024/4/23
+ */
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+/**
+ * 捕获报错日志处理工具类
+ */
+public class ErrorUtil {
+
+    /**
+     * Exception出错的栈信息转成字符串
+     * 用于打印到日志中
+     */
+    public static String errorInfoToString(Throwable e) {
+        //try-with-resource语法糖 处理机制
+        try(StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw)){
+            e.printStackTrace(pw);
+            pw.flush();
+            sw.flush();
+            return sw.toString();
+        }catch (Exception ignored){
+            throw new RuntimeException(ignored.getMessage(),ignored);
+        }
+    }
+}

+ 29 - 0
src/main/java/com/dapp/moviewebsite/common/utils/JsonUtils.java

@@ -0,0 +1,29 @@
+package com.dapp.moviewebsite.common.utils;
+
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+
+/**
+ * @author:slambb
+ * @date:2024/4/23
+ */
+public class JsonUtils {
+    private static final ObjectMapper JSON = new ObjectMapper();
+
+    static {
+        JSON.setSerializationInclusion(Include.NON_NULL);
+        JSON.configure(SerializationFeature.INDENT_OUTPUT, Boolean.TRUE);
+    }
+
+    public static String toJson(Object obj) {
+        try {
+            return JSON.writeValueAsString(obj);
+        } catch (JsonProcessingException e) {
+            e.printStackTrace();
+        }
+
+        return null;
+    }
+}

+ 43 - 0
src/main/java/com/dapp/moviewebsite/common/utils/ResultVOUtil.java

@@ -0,0 +1,43 @@
+package com.dapp.moviewebsite.common.utils;
+
+import com.dapp.moviewebsite.common.VO.ResultVO;
+import com.dapp.moviewebsite.common.enums.ResultEnum;
+
+/**
+ * @author:slambb
+ * @date:2024/4/23
+ */
+public class ResultVOUtil {
+    public static ResultVO success(Object object){
+        ResultVO resultVO = new ResultVO();
+        resultVO.setData(object);
+        resultVO.setCode(0);
+        resultVO.setMsg("成功");
+        return resultVO;
+    }
+    public static ResultVO success() {
+        return success(null);
+    }
+
+    public static ResultVO error(Integer code, String msg) {
+        ResultVO resultVO = new ResultVO();
+        resultVO.setCode(code);
+        resultVO.setMsg(msg);
+        return resultVO;
+    }
+
+    public static ResultVO error(ResultEnum resultEnum) {
+        ResultVO resultVO = new ResultVO();
+        resultVO.setCode(resultEnum.getCode());
+        resultVO.setMsg(resultEnum.getMessage());
+        return resultVO;
+    }
+
+    public static ResultVO error(Integer code, String msg,Object object) {
+        ResultVO resultVO = new ResultVO();
+        resultVO.setCode(code);
+        resultVO.setMsg(msg);
+        resultVO.setData(object);
+        return resultVO;
+    }
+}

+ 16 - 0
src/main/java/com/dapp/moviewebsite/common/utils/UUIDUtil.java

@@ -0,0 +1,16 @@
+package com.dapp.moviewebsite.common.utils;
+
+import java.util.UUID;
+
+/**
+ * @author:slambb
+ * @date:2024/4/23
+ */
+public class UUIDUtil {
+    /**
+     * 生成32位UUID编码
+     */
+    public static String getUUID(){
+        return UUID.randomUUID().toString().trim().replaceAll("-", "");
+    }
+}

+ 111 - 0
src/main/java/com/dapp/moviewebsite/config/filter/JwtTokenUtil.java

@@ -0,0 +1,111 @@
+package com.dapp.moviewebsite.config.filter;
+
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.Clock;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.SignatureAlgorithm;
+import io.jsonwebtoken.impl.DefaultClock;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cglib.core.internal.Function;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.stereotype.Component;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author:slambb
+ * @date:2024/4/23
+ */
+@Component
+public class JwtTokenUtil implements Serializable {
+    private static final long serialVersionUID = -3301605591108950415L;
+
+    @Value("${jwt.secret}")
+    private  String secret;
+
+    @Value("${jwt.expiration}")
+    private Long expiration;
+
+    @Value("${jwt.token}")
+    private String tokenHeader;
+
+    private Clock clock = DefaultClock.INSTANCE;
+
+    public String generateToken(UserDetails userDetails) {
+        Map<String, Object> claims = new HashMap<>();
+        return doGenerateToken(claims, userDetails.getUsername());
+    }
+
+    //根据字符串生成token
+    public String generateToken(String tokenId) {
+        Map<String, Object> claims = new HashMap<>();
+        return doGenerateToken(claims, tokenId);
+    }
+
+    private String doGenerateToken(Map<String, Object> claims, String subject) {
+        final Date createdDate = clock.now();
+        final Date expirationDate = calculateExpirationDate(createdDate);
+
+        return Jwts.builder()
+                .setClaims(claims)
+                .setSubject(subject)
+                .setIssuedAt(createdDate)
+                .setExpiration(expirationDate)
+                .signWith(SignatureAlgorithm.HS512, secret)
+                .compact();
+    }
+
+    private Date calculateExpirationDate(Date createdDate) {
+        return new Date(createdDate.getTime() + expiration);
+    }
+
+    public Boolean validateToken(String token, UserDetails userDetails) {
+//        SecurityUserDetails user = (SecurityUserDetails) userDetails;
+        final String username = getUsernameFromToken(token);
+//        user.getUsername()
+        return (username.equals("11")
+                && !isTokenExpired(token)
+        );
+    }
+    //根据userId字符串校验
+    public Boolean validateToken(String token, String userId) {
+        final String id = getUserIdFromToken(token);
+        return (id.equals(userId)
+                && !isTokenExpired(token)
+        );
+    }
+    public String getUserIdFromToken(String token) {
+        return getClaimFromToken(token, Claims::getSubject);
+    }
+
+    public String getUsernameFromToken(String token) {
+        return getClaimFromToken(token, Claims::getSubject);
+    }
+
+    public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
+        final Claims claims = getAllClaimsFromToken(token);
+        return claimsResolver.apply(claims);
+    }
+
+    private Claims getAllClaimsFromToken(String token) {
+        return Jwts.parser()
+                .setSigningKey(secret)
+                .parseClaimsJws(token)
+                .getBody();
+    }
+
+
+    private Boolean isTokenExpired(String token) {
+        final Date expiration = getExpirationDateFromToken(token);
+        return expiration.before(clock.now());
+    }
+
+    public Date getExpirationDateFromToken(String token) {
+        return getClaimFromToken(token, Claims::getExpiration);
+    }
+
+
+}

+ 165 - 0
src/main/java/com/dapp/moviewebsite/config/filter/MovieWebsiteAppFilter.java

@@ -0,0 +1,165 @@
+package com.dapp.moviewebsite.config.filter;
+
+import cn.hutool.core.convert.Convert;
+import com.dapp.moviewebsite.common.VO.ResultVO;
+import com.dapp.moviewebsite.common.enums.ResultEnum;
+import com.dapp.moviewebsite.common.pojo.Result;
+import com.dapp.moviewebsite.common.utils.JsonUtils;
+import com.dapp.moviewebsite.common.utils.ResultVOUtil;
+import com.dapp.moviewebsite.config.utils.IpUtil;
+import com.dapp.moviewebsite.config.utils.RedisSettingMap;
+import com.dapp.moviewebsite.config.utils.RedisType;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.util.StringUtils;
+
+import javax.servlet.*;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 用于APP过滤
+ * @author:slambb
+ * @date:2024/4/23
+ */
+@Slf4j
+public class MovieWebsiteAppFilter implements Filter {
+
+    @Value("${jwt.token}")
+    private String tokenHeader;
+
+    @Value("${server.servlet.context-path:}")
+    private String contextPath;
+
+    @Autowired
+    private JwtTokenUtil jwtTokenUtil;
+
+    //添加redis 防止恶意请求
+    @Autowired
+    private StringRedisTemplate redisTemplate;
+
+    @Autowired
+    RedisSettingMap redisSettingMap;
+
+    @Override
+    public void init(FilterConfig filterConfig) throws ServletException {
+    }
+
+    @Override
+    public void destroy() {
+    }
+
+    @Override
+    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
+        //处理跨域请求
+        HttpServletResponse response = (HttpServletResponse) servletResponse;
+        response.setHeader("Access-Control-Allow-Origin", "*");
+        response.setHeader("Access-Control-Allow-Credentials", "true");
+        response.setHeader("Access-Control-Allow-Methods", "POST, GET, PATCH, DELETE, PUT");
+        response.setHeader("Access-Control-Max-Age", "3600");
+        response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept , Authorization");
+
+        log.info("********进入MovieWebsiteAppFilter过滤器********");
+        HttpServletRequest req = (HttpServletRequest) servletRequest;
+        //登陆IP不在白名单
+        String ipAddr = IpUtil.getIpAddr(req);
+        String token = req.getHeader(tokenHeader);
+        Integer platform = req.getIntHeader("platform"); //登录的平台
+
+        String path = req.getServletPath();
+
+        /**
+         * game接口都需要限制访问
+         */
+        //设置5秒内可以访问5次,同一个接口
+        String redisKey = "limit-req:".concat(req.getRequestURL().toString()).concat(":").concat(ipAddr);
+        int _limitTime = 5, _limitCount = 40;
+        if (!redisTemplate.hasKey(redisKey)) {
+            redisTemplate.opsForValue().set(redisKey, String.valueOf(1), _limitTime, TimeUnit.SECONDS);
+        } else {
+            int increment = Convert.toInt(redisTemplate.opsForValue().get(redisKey));
+            if (increment > _limitCount) {
+                response.setCharacterEncoding("UTF-8");
+                response.setContentType("application/json; charset=utf-8");
+                PrintWriter out = response.getWriter();
+                out.print(JsonUtils.toJson(Result.of(null, false, ResultEnum.REDIS_IS_LOCK.getMessage(), ResultEnum.REDIS_IS_LOCK.getCode())));
+                out.flush();
+                out.close();
+                return;
+            } else {
+                redisTemplate.opsForValue().set(redisKey, String.valueOf(++increment), _limitTime, TimeUnit.SECONDS);
+            }
+        }
+
+        //不用登录的接口
+        if (  path.indexOf("analysisToken") == -1 &&
+                path.indexOf("program") > -1
+        ) {
+            //登录情况直接放行
+            filterChain.doFilter(servletRequest, response);
+            return;
+        }
+
+        log.info("token:" + token);
+        if (null == token || token.isEmpty()) {
+            //没有token信息
+            ResultVO resultVO = ResultVOUtil.error(ResultEnum.TOKEN_DOES_NOT_EXIST);
+            response.setCharacterEncoding("utf-8");
+            response.getWriter().print(JsonUtils.toJson(resultVO));
+            return;
+        } else {
+            //String authToken = token.substring(7);
+            try {
+                /**
+                 * token使用redis管理,实时控制登录,下线等操作
+                 */
+//                String.format(RedisConstant.TOKEN_PREFIX, token)
+                String userId = redisSettingMap.getValue(RedisType.TOKEN, token);
+                //String userId = jwtTokenUtil.getUserIdFromToken(authToken);
+                //if (!jwtTokenUtil.validateToken(authToken, userId)) {
+                //    log.info("secret 不可靠,validateToken:{}", jwtTokenUtil.validateToken(authToken, userId));
+                //}
+                if (StringUtils.hasText(userId)) {
+                    //传入userId和platform
+                    filterChain.doFilter(new TokenRequestWrapper((HttpServletRequest) servletRequest, userId, platform), response);
+                } else {
+                    //不存在用户信息
+                    ResultVO resultVO = ResultVOUtil.error(ResultEnum.TOKEN_DOES_NOT_HAVE_USER_ID);
+                    response.setCharacterEncoding("utf-8");
+                    response.getWriter().print(JsonUtils.toJson(resultVO));
+
+                }
+            } catch (Exception e) {
+                ResultVO resultVO = ResultVOUtil.error(ResultEnum.TOKEN_FILTER_ERROR);
+                response.setCharacterEncoding("utf-8");
+                response.getWriter().print(JsonUtils.toJson(resultVO));
+            }
+            //catch (ExpiredJwtException e) {
+            //    //token过期
+            //    response.setCharacterEncoding("UTF-8");
+            //    response.setContentType("application/json; charset=utf-8");
+            //    PrintWriter out = response.getWriter();
+            //    out.print(JsonUtils.toJson(Result.of(null, false, ResultEnum.TOKEN_OUT_OF_DATE.getMessage(), ResultEnum.TOKEN_OUT_OF_DATE.getCode())));
+            //    out.flush();
+            //    out.close();
+            //}
+            //catch (SignatureException e) {
+            //    //secret校验密钥不对
+            //    response.setCharacterEncoding("UTF-8");
+            //    response.setContentType("application/json; charset=utf-8");
+            //    PrintWriter out = response.getWriter();
+            //    out.print(JsonUtils.toJson(Result.of(authToken, false, ResultEnum.TOKEN_IS_ILLEGAL.getMessage(), ResultEnum.TOKEN_IS_ILLEGAL.getCode())));
+            //    out.flush();
+            //    out.close();
+            //}
+
+        }
+
+    }
+
+}

+ 31 - 0
src/main/java/com/dapp/moviewebsite/config/filter/RedisConfig.java

@@ -0,0 +1,31 @@
+package com.dapp.moviewebsite.config.filter;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+
+/**
+ * @author:slambb
+ * @date:2024/4/23
+ */
+
+@Configuration
+public class RedisConfig {
+
+
+    //@Bean
+    //public JedisConnectionFactory redisConnectionFactory() {
+    //    return new JedisConnectionFactory();
+    //}
+    //
+    //
+    //@Bean
+    //public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
+    //    RedisTemplate<String, Object> template = new RedisTemplate<>();
+    //    template.setConnectionFactory(redisConnectionFactory);
+    //    return template;
+    //}
+
+}

+ 62 - 0
src/main/java/com/dapp/moviewebsite/config/filter/TokenRequestWrapper.java

@@ -0,0 +1,62 @@
+package com.dapp.moviewebsite.config.filter;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+
+/**
+ * @author:slambb
+ * @date:2024/4/23
+ */
+@Slf4j
+public class TokenRequestWrapper extends HttpServletRequestWrapper {
+
+    private String paramsUserId;
+    private Integer paramsPlatform;
+
+    public TokenRequestWrapper(HttpServletRequest request, String userId, Integer platform) {
+        super(request);
+        paramsUserId = userId;
+        paramsPlatform = platform;
+    }
+
+    /**
+     * 修改此方法主要是因为当RequestMapper中的参数为pojo类型时,
+     * 会通过此方法获取所有的请求参数并进行遍历,对pojo属性赋值
+     *
+     * @return
+     */
+    @Override
+    public Enumeration<String> getParameterNames() {
+        Enumeration<String> enumeration = super.getParameterNames();
+        ArrayList<String> list = Collections.list(enumeration);
+        String token = super.getHeader("token");
+        Integer platform = super.getIntHeader("platform");
+        list.add("platform");
+        log.info("getParameterNames token=="+token);
+        //当有token字段时动态的添加uid字段
+        if (StringUtils.isNotBlank(token)) {
+            list.add("userId");
+            return Collections.enumeration(list);
+        } else {
+            return super.getParameterNames();
+        }
+    }
+
+    @Override
+    public String[] getParameterValues(String name) {
+        if ("userId".equals(name)) {
+            return new String[]{paramsUserId};
+        }
+        if ("platform".equals(name)) {
+            return new String[]{paramsPlatform.toString()};
+        }
+        return super.getParameterValues(name);
+    }
+
+}

+ 39 - 0
src/main/java/com/dapp/moviewebsite/config/global/GlobalSecuritySetting.java

@@ -0,0 +1,39 @@
+package com.dapp.moviewebsite.config.global;
+
+import java.util.Arrays;
+
+/**
+ * @author:slambb
+ * @date:2024/4/25
+ */
+public class GlobalSecuritySetting {
+    public static String[] base = {"test",
+            "program",
+            "favorite",
+            "user",
+            "viewingRecords",
+            "appVideos",
+            "app",
+            "appUserMember",
+            "appUserTran"
+    };
+    //web 拦截过滤 "/app/**"
+    public static String[] web_antPatterns;
+    //api 拦截过滤 "/app/*"
+    public static String[] filter_urlPatterns;
+
+    public static void init()
+    {
+        web_antPatterns = new String[base.length];
+        filter_urlPatterns = new String[base.length];
+
+        for (int i = 0; i < base.length; i++) {
+            //例如 "/app/**"
+            web_antPatterns[i] = "/" + base[i] + "/**";
+            //例如 "/app/*"
+            filter_urlPatterns[i] = "/" + base[i] + "/*";
+        }
+        System.out.println("web_antPatterns:"+Arrays.toString(web_antPatterns));
+        System.out.println("filter_urlPatterns:"+Arrays.toString(filter_urlPatterns));
+    }
+}

+ 46 - 0
src/main/java/com/dapp/moviewebsite/config/security/MovieWebsiteApplicationConfig.java

@@ -0,0 +1,46 @@
+package com.dapp.moviewebsite.config.security;
+
+import com.dapp.moviewebsite.config.filter.MovieWebsiteAppFilter;
+import com.dapp.moviewebsite.config.global.GlobalSecuritySetting;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.filter.DelegatingFilterProxy;
+
+import javax.servlet.Filter;
+
+/**
+ * 拦截处理通过 SecurityConfig 放行的接口
+ * 前端API访问配置部分
+ * @author:slambb
+ * @date:2024/4/23
+ */
+@Configuration
+public class MovieWebsiteApplicationConfig {
+    @Bean
+    public Filter MovieWebsiteAppFilter() {
+        return new MovieWebsiteAppFilter();
+    }
+
+
+    @Bean
+    public FilterRegistrationBean authorizeFilterRegistration() {
+
+        FilterRegistrationBean registration = new FilterRegistrationBean();
+        registration.setFilter(new DelegatingFilterProxy("MovieWebsiteAppFilter"));
+        //拦截SecurityConfig放行的接口,使其进入MovieWebsiteAppFilter处理
+        /**
+         "/test/*",
+         "/program/*",
+         "/favorite/*",
+         "/user/*",
+         "/viewingRecords/*",
+         "/appVideos/*",
+         "/app/*"
+         */
+        registration.addUrlPatterns(GlobalSecuritySetting.filter_urlPatterns);
+        registration.setName("MovieWebsiteAppFilter");
+        registration.setOrder(1);
+        return registration;
+    }
+}

+ 79 - 0
src/main/java/com/dapp/moviewebsite/config/security/SecurityConfig.java

@@ -0,0 +1,79 @@
+package com.dapp.moviewebsite.config.security;
+
+import com.dapp.moviewebsite.config.global.GlobalSecuritySetting;
+import org.apache.catalina.startup.UserConfig;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.security.access.AccessDecisionVoter;
+import org.springframework.security.access.vote.RoleVoter;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.builders.WebSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
+import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
+import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
+
+import javax.sql.DataSource;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 处理引入的spring security
+ * @author:slambb
+ * @date:2024/4/23
+ */
+@EnableWebSecurity
+public class SecurityConfig extends WebSecurityConfigurerAdapter {
+
+    @Autowired
+    private DataSource dataSource;
+
+    @Override
+    public void configure(WebSecurity web) throws Exception {
+        /**
+         *
+         "/test/**",
+         "/program/**",
+         "/favorite/**",
+         "/user/**",
+         "/viewingRecords/**",
+         "/appVideos/**",
+         "/app/**"
+         */
+        // 放行,使其走MovieWebsiteApplicationConfig验证流程
+        //web.ignoring().antMatchers(GlobalSecuritySetting.web_antPatterns);
+    }
+
+    @Override
+    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+
+    }
+
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+        http
+                // 关闭csrf防护
+                .csrf().disable()
+                .headers().frameOptions().disable()
+                .and();
+
+        http
+                .authorizeRequests()
+                //其他接口需要登录后才能访问
+                .antMatchers(GlobalSecuritySetting.web_antPatterns).permitAll()    //解决静态资源被拦截的问题(新,写在这里)
+                .anyRequest().authenticated()
+                .and();
+    }
+
+    @Bean
+    public PersistentTokenRepository persistentTokenRepository() {
+        JdbcTokenRepositoryImpl persistentTokenRepository = new JdbcTokenRepositoryImpl();
+        persistentTokenRepository.setDataSource(dataSource);
+        return persistentTokenRepository;
+    }
+
+}
+

+ 147 - 0
src/main/java/com/dapp/moviewebsite/config/utils/IpUtil.java

@@ -0,0 +1,147 @@
+package com.dapp.moviewebsite.config.utils;
+
+import com.dapp.moviewebsite.common.pojo.IpVo;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.util.StringUtils;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.text.SimpleDateFormat;
+
+/**
+ * @author:slambb
+ * @date:2024/4/23
+ */
+@Slf4j
+public class IpUtil {
+    /**
+     * 获取访问者的ip地址
+     * 注:要外网访问才能获取到外网地址,如果你在局域网甚至本机上访问,获得的是内网或者本机的ip
+     */
+    public static String getIpAddr(HttpServletRequest request) {
+        String ipAddress = null;
+        try {
+            //X-Forwarded-For:Squid 服务代理
+            String ipAddresses = request.getHeader("X-Forwarded-For");
+
+            if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
+                //Proxy-Client-IP:apache 服务代理
+                ipAddresses = request.getHeader("Proxy-Client-IP");
+            }
+
+            if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
+                //WL-Proxy-Client-IP:weblogic 服务代理
+                ipAddresses = request.getHeader("WL-Proxy-Client-IP");
+            }
+
+            if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
+                //HTTP_CLIENT_IP:有些代理服务器
+                ipAddresses = request.getHeader("HTTP_CLIENT_IP");
+            }
+
+            if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
+                //X-Real-IP:nginx服务代理
+                ipAddresses = request.getHeader("X-Real-IP");
+            }
+
+            //有些网络通过多层代理,那么获取到的ip就会有多个,一般都是通过逗号(,)分割开来,并且第一个ip为客户端的真实IP
+            if (ipAddresses != null && ipAddresses.length() != 0) {
+                ipAddress = ipAddresses.split(",")[0];
+            }
+
+            //还是不能获取到,最后再通过request.getRemoteAddr();获取
+            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
+                ipAddress = request.getRemoteAddr();
+            }
+        } catch (Exception e) {
+            ipAddress = "";
+        }
+        return ipAddress;
+    }
+
+    /**
+     * 调用太平洋网络IP地址查询Web接口(http://whois.pconline.com.cn/),返回ip、地理位置
+     */
+    public static IpVo getIpVo(String ip){
+        //查本机
+        String url = "http://whois.pconline.com.cn/ipJson.jsp?json=true";
+
+        //查指定ip
+        if(!StringUtils.isEmpty(ip)){
+            url = "http://whois.pconline.com.cn/ipJson.jsp?json=true&ip=" + ip;
+        }
+
+        StringBuilder inputLine = new StringBuilder();
+        String read;
+        try {
+            HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection();
+            urlConnection.setRequestProperty("Charset", "GBK");
+            BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), "GBK"));
+            while ((read = in.readLine()) != null) {
+                inputLine.append(read);
+            }
+            in.close();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        //返回格式
+        /*
+        {
+            ip: "58.63.47.115",
+            pro: "广东省",
+            proCode: "440000",
+            city: "广州市",
+            cityCode: "440100",
+            region: "天河区",
+            regionCode: "440106",
+            addr: "广东省广州市天河区 电信",
+            regionNames: "",
+            err: ""
+        }
+         */
+
+        IpVo ipVo = null;
+        try {
+            ObjectMapper mapper = new ObjectMapper();
+            //当属性的值为空(null或者"")时,不进行序列化,可以减少数据传输
+            mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
+            //设置日期格式
+            mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
+            //转换成IpVo
+            ipVo = mapper.readValue(new String(inputLine.toString().getBytes("GBK"), "GBK"), IpVo.class);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return ipVo;
+    }
+
+    /**
+     * 直接根据访问者的Request,返回ip、地理位置
+     */
+    public static IpVo getIpVoByRequest(HttpServletRequest request){
+        return IpUtil.getIpVo(IpUtil.getIpAddr(request));
+    }
+
+    /*
+        终极大法:java获取不了,就用js来获取
+        <!-- js获取客户ip -->
+        <script src="http://whois.pconline.com.cn/ipJson.jsp"></script>
+     */
+
+    /*//测试
+    public static void main(String[] args) {
+        //获取本机ip
+        System.out.println(getIpVo(null));
+
+        //获取指定ip
+        System.out.println(getIpVo("115.48.58.106"));
+    }*/
+}
+

+ 21 - 0
src/main/java/com/dapp/moviewebsite/config/utils/RedisConstant.java

@@ -0,0 +1,21 @@
+package com.dapp.moviewebsite.config.utils;
+
+/**
+ * @author:slambb
+ * @date:2024/4/23
+ */
+public interface RedisConstant {
+    String TOKEN_PREFIX = "token:%s";
+    //设置1个月
+    Integer EXPIRE = 60*60*24*30;//7200;//2小时
+
+    //短信信息
+    String SMS_PREFIX = "code:%s";
+
+    Integer  CODE_EXPIRE = 300;//5分钟
+
+
+    //keyword
+    String KEYWORD_PREFIX ="keyword:%s";
+}
+

+ 165 - 0
src/main/java/com/dapp/moviewebsite/config/utils/RedisSettingMap.java

@@ -0,0 +1,165 @@
+package com.dapp.moviewebsite.config.utils;
+
+import cn.hutool.crypto.asymmetric.RSA;
+import cn.hutool.json.JSON;
+import cn.hutool.json.JSONUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author:slambb
+ * @date:2024/4/23
+ */
+
+@Component
+public class RedisSettingMap {
+    @Value("${spring.application.name}")
+    private String applicationName;
+
+    @Autowired
+    private StringRedisTemplate redisTemplate;
+
+
+    //动态设置一个RSA key保存
+    private String rsaPublicKey = ":rsa:public";
+    private String rsaPrivateKey = ":rsa:private";
+    //update 一次rsa数据
+    public void updateRSAMap(){
+        RSA rsa = new RSA();
+        String privateKeyBase64 = rsa.getPrivateKeyBase64();
+        String publicKeyBase64 = rsa.getPublicKeyBase64();
+        redisTemplate.opsForValue().set(applicationName.concat(rsaPublicKey), JSONUtil.toJsonStr(publicKeyBase64));
+        redisTemplate.opsForValue().set(applicationName.concat(rsaPrivateKey), JSONUtil.toJsonStr(privateKeyBase64));
+    }
+    //从redis 获取系统设置 rsa 设置
+    public String getRSAPublicKeyBase64(){
+        if (redisTemplate.hasKey(applicationName.concat(rsaPublicKey))) {
+            return  redisTemplate.opsForValue().get(applicationName.concat(rsaPublicKey));
+        } else {
+            RSA rsa = new RSA();
+            String privateKeyBase64 = rsa.getPrivateKeyBase64();
+            String publicKeyBase64 = rsa.getPublicKeyBase64();
+            redisTemplate.opsForValue().set(applicationName.concat(rsaPublicKey), JSONUtil.toJsonStr(publicKeyBase64));
+            redisTemplate.opsForValue().set(applicationName.concat(rsaPrivateKey), JSONUtil.toJsonStr(privateKeyBase64));
+            return publicKeyBase64;
+        }
+    }
+    public String getRSAPrivateKeyBase64(){
+        if (redisTemplate.hasKey(applicationName.concat(rsaPrivateKey))) {
+            return  redisTemplate.opsForValue().get(applicationName.concat(rsaPrivateKey));
+        } else {
+            RSA rsa = new RSA();
+            String privateKeyBase64 = rsa.getPrivateKeyBase64();
+            String publicKeyBase64 = rsa.getPublicKeyBase64();
+            redisTemplate.opsForValue().set(applicationName.concat(rsaPublicKey), JSONUtil.toJsonStr(publicKeyBase64));
+            redisTemplate.opsForValue().set(applicationName.concat(rsaPrivateKey), JSONUtil.toJsonStr(privateKeyBase64));
+            return privateKeyBase64;
+        }
+    }
+
+    /**
+     * token相关操作
+     */
+    /**
+     * 根据token生成对应的key
+     * @param token
+     * @return
+     */
+    public String getTokenKey(String token){
+        return applicationName.concat(":").concat(String.format(RedisConstant.TOKEN_PREFIX, token));
+    }
+    /**
+     * 对应token存放 map 信息
+     * @param token
+     * @param tokenMap
+     */
+    public void putToken(String token, Map<String, String> tokenMap){
+        Integer expire = RedisConstant.EXPIRE;//过期时间
+        redisTemplate.opsForHash().putAll(getTokenKey(token), tokenMap);
+        redisTemplate.expire(getTokenKey(token), expire, TimeUnit.SECONDS);
+    }
+
+
+    /**
+     * SMS相关操作
+     */
+    /**
+     * 短信key
+     * @param key
+     * @return
+     */
+    public String getSMSKey(String key){
+        return applicationName.concat(":").concat(String.format(RedisConstant.SMS_PREFIX, key));
+    }
+
+    /**
+     * 设置短信缓存
+     * @param key
+     * @param code
+     */
+    public void setSMS(String key,String code){
+        Integer expire = RedisConstant.CODE_EXPIRE;//过期时间
+        redisTemplate.opsForValue().set(getSMSKey(key), code, expire, TimeUnit.SECONDS);
+    }
+
+
+    /**
+     * 根据类型获取缓存值
+     * @param redisType
+     * @param key
+     * @return
+     */
+    public String getValue(RedisType redisType,String key){
+        switch (redisType){
+            case SMS:
+                /**
+                 * 获取短信key对应的值
+                 */
+                return redisTemplate.opsForValue().get(getSMSKey(key));
+            case TOKEN:
+                /**
+                 * 获取token的key对应userId
+                 */
+                return redisTemplate.opsForHash().get(getTokenKey(key), "userId").toString();
+            default: return null;
+        }
+    }
+
+    /**
+     * 根据类型删除缓存值
+     * @param redisType
+     * @param key
+     * @return
+     */
+    public Boolean deleteValue(RedisType redisType,String key){
+        switch (redisType){
+            case SMS:
+                /**
+                 * 删除短信key的值
+                 */
+                return redisTemplate.delete(getSMSKey(key));
+            case TOKEN:
+                /**
+                 * 删除token的值
+                 */
+                return redisTemplate.delete(getTokenKey(key));
+            default: return null;
+        }
+    }
+
+
+    /**
+     * 记录keyword的redis前缀
+     * @return
+     */
+
+    public String getKeywordPrefix(){
+        return applicationName.concat(":").concat("keyword");
+    }
+
+}

+ 14 - 0
src/main/java/com/dapp/moviewebsite/config/utils/RedisType.java

@@ -0,0 +1,14 @@
+package com.dapp.moviewebsite.config.utils;
+
+/**
+ * @author:slambb
+ * @date:2024/4/23
+ */
+public enum RedisType {
+    NULL,
+    BLE_KEY,
+    SMS,
+    TOKEN,
+    RANKING_CITY,
+    RANKING_CHINA
+}

+ 68 - 0
src/main/java/com/dapp/moviewebsite/demos/web/BasicController.java

@@ -0,0 +1,68 @@
+/*
+ * Copyright 2013-2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dapp.moviewebsite.demos.web;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+/**
+ * @author <a href="mailto:chenxilzx1@gmail.com">theonefx</a>
+ */
+@Controller
+@RequestMapping("/test")
+public class BasicController {
+
+    // http://127.0.0.1:30001/ms_dev/test/hello?name=lisi
+    @RequestMapping("/hello")
+    @ResponseBody
+    public String hello(@RequestParam(name = "name", defaultValue = "unknown user") String name) {
+        return "Hello " + name;
+    }
+
+    // http://127.0.0.1:30001/ms_dev/test/user
+    @RequestMapping("/user")
+    @ResponseBody
+    public User user() {
+        User user = new User();
+        user.setName("theonefx");
+        user.setAge(666);
+        return user;
+    }
+
+    // http://127.0.0.1:30001/ms_dev/save_user?name=newName&age=11
+    @RequestMapping("/save_user")
+    @ResponseBody
+    public String saveUser(User u) {
+        return "user will save: name=" + u.getName() + ", age=" + u.getAge();
+    }
+
+    // http://127.0.0.1:30001/html
+    @RequestMapping("/html")
+    public String html(){
+        return "index.html";
+    }
+
+    @ModelAttribute
+    public void parseUser(@RequestParam(name = "name", defaultValue = "unknown user") String name
+            , @RequestParam(name = "age", defaultValue = "12") Integer age, User user) {
+        user.setName("zhangsan");
+        user.setAge(18);
+    }
+}

+ 45 - 0
src/main/java/com/dapp/moviewebsite/demos/web/PathVariableController.java

@@ -0,0 +1,45 @@
+/*
+ * Copyright 2013-2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dapp.moviewebsite.demos.web;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+/**
+ * @author <a href="mailto:chenxilzx1@gmail.com">theonefx</a>
+ */
+@Controller
+@RequestMapping("/app")
+public class PathVariableController {
+
+    // http://127.0.0.1:30001/ms_dev/app/user/123/roles/222
+    @RequestMapping(value = "/user/{userId}/roles/{roleId}", method = RequestMethod.GET)
+    @ResponseBody
+    public String getLogin(@PathVariable("userId") String userId, @PathVariable("roleId") String roleId) {
+        return "User Id : " + userId + " Role Id : " + roleId;
+    }
+
+    // http://127.0.0.1:30001/ms_dev/javabeat/somewords
+    @RequestMapping(value = "/javabeat/{regexp1:[a-z-]+}", method = RequestMethod.GET)
+    @ResponseBody
+    public String getRegExp(@PathVariable("regexp1") String regexp1) {
+        return "URI Part : " + regexp1;
+    }
+}

部分文件因为文件数量过多而无法显示