Merge branch 'master' into add-license-scan-badge

This commit is contained in:
ronger 2022-10-23 14:35:35 +08:00 committed by GitHub
commit f4b813c30a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
229 changed files with 3143 additions and 3779 deletions

156
.onedev-buildspec.yml Normal file
View File

@ -0,0 +1,156 @@
version: 18
jobs:
- name: maven ci
steps:
- !CheckoutStep
name: checkout
cloneCredential: !DefaultCredential {}
withLfs: false
withSubmodules: false
condition: ALL_PREVIOUS_STEPS_WERE_SUCCESSFUL
- !CommandStep
name: detect build version
runInContainer: true
image: '@script:builtin:maven:determine-docker-image@'
interpreter: !DefaultInterpreter
commands:
- echo "Detecting project version (may require some time while downloading maven
dependencies)..."
- echo $(mvn org.apache.maven.plugins:maven-help-plugin:3.1.0:evaluate -Dexpression=project.version
-q -DforceStdout) > buildVersion
useTTY: false
condition: ALL_PREVIOUS_STEPS_WERE_SUCCESSFUL
- !SetBuildVersionStep
name: set build version
buildVersion: '@file:buildVersion@'
condition: ALL_PREVIOUS_STEPS_WERE_SUCCESSFUL
- !CommandStep
name: run unit tests
runInContainer: true
image: '@script:builtin:maven:determine-docker-image@'
interpreter: !DefaultInterpreter
commands:
- mvn clean test -P dev
useTTY: false
condition: ALL_PREVIOUS_STEPS_WERE_SUCCESSFUL
triggers:
- !BranchUpdateTrigger {}
retryCondition: never
maxRetries: 3
retryDelay: 30
cpuRequirement: 250
memoryRequirement: 256
caches:
- key: maven-cache
path: /root/.m2/repository
timeout: 3600
- name: package
steps:
- !CheckoutStep
name: Checkout Code
cloneCredential: !DefaultCredential {}
withLfs: false
withSubmodules: false
condition: ALL_PREVIOUS_STEPS_WERE_SUCCESSFUL
- !CommandStep
name: delete build version
runInContainer: true
image: '@script:builtin:maven:determine-docker-image@'
interpreter: !DefaultInterpreter
commands:
- echo "Detecting project version (may require some time while downloading maven
dependencies)..."
- echo $(mvn org.apache.maven.plugins:maven-help-plugin:3.1.0:evaluate -Dexpression=project.version
-q -DforceStdout) > buildVersion
useTTY: false
condition: ALL_PREVIOUS_STEPS_WERE_SUCCESSFUL
- !SetBuildVersionStep
name: Set Build Version
buildVersion: '@file:buildVersion@'
condition: ALL_PREVIOUS_STEPS_WERE_SUCCESSFUL
- !CommandStep
name: run maven package
runInContainer: true
image: '@script:builtin:maven:determine-docker-image@'
interpreter: !DefaultInterpreter
commands:
- mvn package
useTTY: false
condition: ALL_PREVIOUS_STEPS_WERE_SUCCESSFUL
- !PublishArtifactStep
name: Publish Artifacts
artifacts: '**'
condition: ALL_PREVIOUS_STEPS_WERE_SUCCESSFUL
jobExecutor: internal
retryCondition: never
maxRetries: 3
retryDelay: 30
cpuRequirement: 250
memoryRequirement: 256
caches:
- key: maven-cache
path: /root/.m2/repository
timeout: 3600
- name: Build Docker Image
steps:
- !SetBuildVersionStep
name: Set Build Version
buildVersion: '@file:buildVersion@'
condition: ALL_PREVIOUS_STEPS_WERE_SUCCESSFUL
- !BuildImageStep
name: Build Docker Image
tags: rymcu/forest:@build_version@
publish: false
condition: ALL_PREVIOUS_STEPS_WERE_SUCCESSFUL
jobDependencies:
- jobName: package
requireSuccessful: true
artifacts: '**'
retryCondition: never
maxRetries: 3
retryDelay: 30
cpuRequirement: 250
memoryRequirement: 256
timeout: 3600
- name: Pull from Github
steps:
- !PullRepository
name: Pull from GitHub
remoteUrl: https://github.com/ronger-x/forest
syncToChildProject: false
passwordSecret: access_token
refs: refs/heads/* refs/tags/*
withLfs: false
force: false
condition: ALL_PREVIOUS_STEPS_WERE_SUCCESSFUL
triggers:
- !ScheduleTrigger
cronExpression: 0 0 1 * * ?
retryCondition: never
maxRetries: 3
retryDelay: 30
cpuRequirement: 250
memoryRequirement: 256
timeout: 3600
- name: Push to GitHub
steps:
- !PushRepository
name: Push to GitHub
remoteUrl: https://github.com/ronger-x/forest
passwordSecret: access_token
withLfs: false
force: false
condition: ALL_PREVIOUS_STEPS_WERE_SUCCESSFUL
triggers:
- !BranchUpdateTrigger
branches: master
projects: forest
- !TagCreateTrigger
branches: master
projects: forest
retryCondition: never
maxRetries: 3
retryDelay: 30
cpuRequirement: 250
memoryRequirement: 256
timeout: 3600

13
Dockerfile Normal file
View File

@ -0,0 +1,13 @@
FROM rymcu/java-container:1.0.0
MAINTAINER rymcu.com
COPY target/forest.war /usr/local/tomcat/webapps/
ENV JAVA_HOME=/usr/lib/jvm/jdk1.8.0_202
ENV PATH=$JAVA_HOME/bin:$PATH
CMD ["/usr/local/tomcat/bin/catalina.sh", "run"]
EXPOSE 8080

View File

@ -13,7 +13,7 @@ forest[ˈfôrəst]n.森林)是一款现代化的知识社区项目,使
## ⚡ 动机
在 2019 年的某一天,受到 [Hugh](https://rymcu.com/user/Hugh) 的邀请, 构建一个开源嵌入式知识学习交流平台。因此就有了 forest 这个项目。 forest
在 2019 年的某一天,受到 [Hugh](https://rymcu.com/user/RYMCU-J) 的邀请, 构建一个开源嵌入式知识学习交流平台。因此就有了 forest 这个项目。 forest
在很多方面受到了 [Symphony](https://github.com/88250/symphony) 的启发,并尝试着在 [Symphony](https://github.com/88250/symphony)
和 [B3log 思想](https://ld246.com/article/1546941897596) 的基础上进一步探索。
@ -99,6 +99,11 @@ forest[ˈfôrəst]n.森林)是一款现代化的知识社区项目,使
- 感谢 `JetBrains` 对本项目的帮助,为作者提供了开源许可版 `JetBrains` 全家桶
![JetBrains](src/main/resources/static/jetbrains.png)
## ⭐ Star 历史
[![Stargazers over time](https://starchart.cc/rymcu/forest.svg)](https://starchart.cc/rymcu/forest)
## License
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Frymcu%2Fforest.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Frymcu%2Fforest?ref=badge_large)
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Frymcu%2Fforest.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Frymcu%2Fforest?ref=badge_large)

179
forest.iml Normal file
View File

@ -0,0 +1,179 @@
<?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>
<root url="file://$MODULE_DIR$/src/main/webapp" relative="/" />
</webroots>
<sourceRoots>
<root url="file://$MODULE_DIR$/src/main/java" />
<root url="file://$MODULE_DIR$/src/main/resources" />
</sourceRoots>
</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/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-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-redis:2.7.2" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter:2.7.2" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot:2.7.2" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-logging:2.7.2" level="project" />
<orderEntry type="library" name="Maven: ch.qos.logback:logback-classic:1.2.11" level="project" />
<orderEntry type="library" name="Maven: ch.qos.logback:logback-core:1.2.11" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:jul-to-slf4j:1.7.36" level="project" />
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-redis:2.7.2" level="project" />
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-keyvalue:2.7.2" level="project" />
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-commons:2.7.2" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-tx:5.3.22" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-oxm:5.3.22" level="project" />
<orderEntry type="library" name="Maven: io.lettuce:lettuce-core:6.1.9.RELEASE" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-common:4.1.79.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-handler:4.1.79.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-resolver:4.1.79.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-buffer:4.1.79.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-transport-native-unix-common:4.1.79.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-codec:4.1.79.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-transport:4.1.79.Final" level="project" />
<orderEntry type="library" name="Maven: io.projectreactor:reactor-core:3.4.21" level="project" />
<orderEntry type="library" name="Maven: org.reactivestreams:reactive-streams:1.0.4" level="project" />
<orderEntry type="library" name="Maven: org.yaml:snakeyaml:1.32" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-mail:2.7.2" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-context-support:5.3.22" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-beans:5.3.22" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-context:5.3.22" level="project" />
<orderEntry type="library" name="Maven: com.sun.mail:jakarta.mail:1.6.7" level="project" />
<orderEntry type="library" name="Maven: com.sun.activation:jakarta.activation:1.2.2" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-web:2.7.2" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-json:2.7.2" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.13.3" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.3" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.module:jackson-module-parameter-names:2.13.3" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-web:5.3.22" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-webmvc:5.3.22" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-expression:5.3.22" level="project" />
<orderEntry type="library" name="Maven: org.mybatis.spring.boot:mybatis-spring-boot-starter:2.2.2" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-jdbc:2.7.2" 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.22" level="project" />
<orderEntry type="library" name="Maven: org.mybatis.spring.boot:mybatis-spring-boot-autoconfigure:2.2.2" level="project" />
<orderEntry type="library" name="Maven: org.mybatis:mybatis:3.5.9" level="project" />
<orderEntry type="library" name="Maven: org.mybatis:mybatis-spring:2.0.7" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: mysql:mysql-connector-java:8.0.30" level="project" />
<orderEntry type="library" name="Maven: org.projectlombok:lombok:1.18.24" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: org.springframework.boot:spring-boot-starter-tomcat:2.7.2" level="project" />
<orderEntry type="library" name="Maven: jakarta.annotation:jakarta.annotation-api:1.3.5" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: org.apache.tomcat.embed:tomcat-embed-core:9.0.65" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: org.apache.tomcat.embed:tomcat-embed-el:9.0.65" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: org.apache.tomcat.embed:tomcat-embed-websocket:9.0.65" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-starter-test:2.7.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-test:2.7.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-test-autoconfigure:2.7.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: com.jayway.jsonpath:json-path:2.7.0" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: jakarta.xml.bind:jakarta.xml.bind-api:2.3.3" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: jakarta.activation:jakarta.activation-api:1.2.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.assertj:assertj-core:3.22.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.5.1" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: net.bytebuddy:byte-buddy:1.12.12" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: net.bytebuddy:byte-buddy-agent:1.12.12" 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.5.1" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.skyscreamer:jsonassert:1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-core:5.3.22" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-jcl:5.3.22" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.springframework:spring-test:5.3.22" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.xmlunit:xmlunit-core:2.9.0" level="project" />
<orderEntry type="library" name="Maven: net.minidev:json-smart:2.4.8" level="project" />
<orderEntry type="library" name="Maven: net.minidev:accessors-smart:2.4.8" level="project" />
<orderEntry type="library" name="Maven: org.ow2.asm:asm:9.1" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-aop:2.7.2" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-aop:5.3.22" level="project" />
<orderEntry type="library" name="Maven: org.aspectj:aspectjweaver:1.9.7" level="project" />
<orderEntry type="library" name="Maven: tk.mybatis:mapper:4.2.1" level="project" />
<orderEntry type="library" name="Maven: javax.persistence:persistence-api:1.0" level="project" />
<orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper:5.3.2" level="project" />
<orderEntry type="library" name="Maven: com.github.jsqlparser:jsqlparser:4.5" level="project" />
<orderEntry type="library" name="Maven: com.alibaba:fastjson:2.0.14" level="project" />
<orderEntry type="library" name="Maven: com.alibaba.fastjson2:fastjson2-extension:2.0.14" level="project" />
<orderEntry type="library" name="Maven: com.alibaba.fastjson2:fastjson2:2.0.14" level="project" />
<orderEntry type="library" name="Maven: org.apache.shiro:shiro-spring:1.9.1" level="project" />
<orderEntry type="library" name="Maven: org.apache.shiro:shiro-core:1.9.1" level="project" />
<orderEntry type="library" name="Maven: org.apache.shiro:shiro-lang:1.9.1" level="project" />
<orderEntry type="library" name="Maven: org.apache.shiro:shiro-cache:1.9.1" level="project" />
<orderEntry type="library" name="Maven: org.apache.shiro:shiro-crypto-hash:1.9.1" level="project" />
<orderEntry type="library" name="Maven: org.apache.shiro:shiro-crypto-core:1.9.1" level="project" />
<orderEntry type="library" name="Maven: org.apache.shiro:shiro-crypto-cipher:1.9.1" level="project" />
<orderEntry type="library" name="Maven: org.apache.shiro:shiro-config-core:1.9.1" level="project" />
<orderEntry type="library" name="Maven: org.apache.shiro:shiro-config-ogdl:1.9.1" level="project" />
<orderEntry type="library" name="Maven: commons-beanutils:commons-beanutils:1.9.4" level="project" />
<orderEntry type="library" name="Maven: org.apache.shiro:shiro-event:1.9.1" level="project" />
<orderEntry type="library" name="Maven: org.apache.shiro:shiro-web:1.9.1" level="project" />
<orderEntry type="library" name="Maven: org.owasp.encoder:encoder:1.2.2" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-collections4:4.4" level="project" />
<orderEntry type="library" name="Maven: commons-lang:commons-lang:2.6" level="project" />
<orderEntry type="library" name="Maven: commons-io:commons-io:2.11.0" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-text:1.9" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.12.0" level="project" />
<orderEntry type="library" name="Maven: commons-codec:commons-codec:1.15" 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.3" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.13.3" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-core:2.13.3" level="project" />
<orderEntry type="library" name="Maven: com.alibaba:druid-spring-boot-starter:1.2.13-SNSAPSHOT" level="project" />
<orderEntry type="library" name="Maven: com.alibaba:druid:1.2.13-SNSAPSHOT" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.36" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-autoconfigure:2.7.2" level="project" />
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-to-slf4j:2.19.0" level="project" />
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-api:2.19.0" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-configuration-processor:2.7.2" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-thymeleaf:2.7.2" level="project" />
<orderEntry type="library" name="Maven: org.thymeleaf:thymeleaf-spring5:3.0.15.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.thymeleaf:thymeleaf:3.0.15.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.attoparser:attoparser:2.0.5.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.unbescape:unbescape:1.1.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.thymeleaf.extras:thymeleaf-extras-java8time:3.0.4.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-websocket:2.7.2" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-messaging:5.3.22" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-websocket:5.3.22" level="project" />
<orderEntry type="library" name="Maven: org.jodd:jodd-http:6.3.0" level="project" />
<orderEntry type="library" name="Maven: org.jodd:jodd-util:6.1.0" level="project" />
<orderEntry type="library" name="Maven: com.github.jedis-lock:jedis-lock:1.0.0" level="project" />
<orderEntry type="library" name="Maven: redis.clients:jedis:3.8.0" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-pool2:2.11.1" level="project" />
<orderEntry type="library" name="Maven: org.apache.lucene:lucene-queryparser:8.11.2" level="project" />
<orderEntry type="library" name="Maven: org.apache.lucene:lucene-core:8.11.2" level="project" />
<orderEntry type="library" name="Maven: org.apache.lucene:lucene-queries:8.11.2" level="project" />
<orderEntry type="library" name="Maven: org.apache.lucene:lucene-sandbox:8.11.2" level="project" />
<orderEntry type="library" name="Maven: org.apache.lucene:lucene-analyzers-common:8.11.2" level="project" />
<orderEntry type="library" name="Maven: org.apache.lucene:lucene-highlighter:8.11.2" level="project" />
<orderEntry type="library" name="Maven: org.apache.lucene:lucene-memory:8.11.2" level="project" />
<orderEntry type="library" name="Maven: org.apache.lucene:lucene-suggest:8.11.2" level="project" />
<orderEntry type="library" name="Maven: cn.hutool:hutool-core:5.8.7" level="project" />
<orderEntry type="library" name="Maven: cn.hutool:hutool-http:5.8.7" level="project" />
<orderEntry type="library" name="Maven: com.warrenstrange:googleauth:1.5.0" level="project" />
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpclient:4.5.13" level="project" />
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpcore:4.4.15" level="project" />
</component>
</module>

193
pom.xml
View File

@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.5.RELEASE</version>
<version>2.7.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.rymcu</groupId>
@ -17,7 +17,7 @@
<properties>
<java.version>1.8</java.version>
<lucene.version>8.11.1</lucene.version>
<lucene.version>8.11.2</lucene.version>
</properties>
<dependencies>
@ -31,6 +31,11 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.33</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
@ -40,6 +45,7 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
@ -49,6 +55,7 @@
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
<scope>runtime</scope>
</dependency>
<dependency>
@ -74,8 +81,19 @@
<groupId>com.vaadin.external.google</groupId>
<artifactId>android-json</artifactId>
</exclusion>
<exclusion>
<groupId>net.minidev</groupId>
<artifactId>json-smart</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- https://mvnrepository.com/artifact/net.minidev/json-smart -->
<dependency>
<groupId>net.minidev</groupId>
<artifactId>json-smart</artifactId>
<version>2.4.8</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
@ -84,43 +102,37 @@
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper</artifactId>
<version>4.1.5</version>
</dependency>
<dependency>
<groupId>net.sourceforge.jtds</groupId>
<artifactId>jtds</artifactId>
<version>1.3.1</version>
<version>4.2.1</version>
</dependency>
<!-- pagehelper -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.3.0</version>
<version>5.3.2</version>
</dependency>
<!-- fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
<version>2.0.14</version>
</dependency>
<!-- shiro权限控制框架 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.7.1</version>
</dependency>
<!-- shiro-redis -->
<dependency>
<groupId>org.crazycake</groupId>
<artifactId>shiro-redis</artifactId>
<version>3.2.3</version>
<version>1.9.1</version>
<exclusions>
<exclusion>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.4</version>
</dependency>
<!--apache相关依赖-->
<dependency>
<groupId>commons-lang</groupId>
@ -151,7 +163,7 @@
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.8</version>
<version>1.2.13-SNSAPSHOT</version>
<exclusions>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
@ -163,7 +175,7 @@
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
<version>2.17.1</version>
<version>2.19.0</version>
<exclusions>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
@ -174,7 +186,7 @@
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.17.1</version>
<version>2.19.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
@ -185,11 +197,6 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
<version>1.9.22</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
@ -197,52 +204,13 @@
<dependency>
<groupId>org.jodd</groupId>
<artifactId>jodd-http</artifactId>
<version>6.2.1</version>
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-open</artifactId>
<version>4.2.5.B</version>
<exclusions>
<exclusion>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</exclusion>
<exclusion>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</exclusion>
<exclusion>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.19</version>
<version>6.3.0</version>
</dependency>
<dependency>
<groupId>com.github.jedis-lock</groupId>
<artifactId>jedis-lock</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>com.baidu.aip</groupId>
<artifactId>java-sdk</artifactId>
<version>4.16.5</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
</exclusion>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- lucene -->
<dependency>
@ -273,12 +241,12 @@
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
<version>5.7.20</version>
<version>5.8.8</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-http</artifactId>
<version>5.7.20</version>
<version>5.8.8</version>
</dependency>
<dependency>
@ -292,8 +260,6 @@
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
@ -306,15 +272,98 @@
<include>**/**/*.xml</include>
</includes>
</resource>
<!-- 资源文件配置 -->
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
<includes>
<include>**/**</include>
</includes>
</resource>
<!-- 过滤配置文件到config目录 -->
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<targetPath>config</targetPath>
<includes>
<include>application.yml</include>
<include>application-${profileActive}.yml</include>
<include>banner.txt</include>
<include>logback.xml</include>
<include>*.properties</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.3.5.RELEASE</version>
<configuration>
<fork>true</fork>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<nonFilteredFileExtensions>
<nonFilteredFileExtension>woff</nonFilteredFileExtension>
<nonFilteredFileExtension>woff2</nonFilteredFileExtension>
<nonFilteredFileExtension>eot</nonFilteredFileExtension>
<nonFilteredFileExtension>ttf</nonFilteredFileExtension>
<nonFilteredFileExtension>svg</nonFilteredFileExtension>
</nonFilteredFileExtensions>
</configuration>
</plugin>
</plugins>
<finalName>forest</finalName>
</build>
</build><!--MAVEN打包选择运行环境-->
<!-- 1:dev:开发环境 2:prod:生产环境 -->
<profiles>
<profile>
<id>dev</id>
<properties>
<profileActive>dev</profileActive>
</properties>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
</profile>
<profile>
<id>prod</id>
<properties>
<profileActive>prod</profileActive>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
</profiles>
<repositories>
<repository>
<id>public</id>
<name>aliyun nexus</name>
<url>https://maven.aliyun.com/nexus/content/groups/public/</url>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>public</id>
<name>aliyun nexus</name>
<url>https://maven.aliyun.com/nexus/content/groups/public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>

View File

@ -2,10 +2,12 @@ package com.rymcu.forest;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
/**
* @author ronger
*/
@EnableAsync
@SpringBootApplication
public class ForestApplication {

View File

@ -1,6 +1,7 @@
package com.rymcu.forest.config;
import com.alibaba.fastjson.support.spring.FastJsonJsonView;
import com.rymcu.forest.core.exception.BusinessException;
import com.rymcu.forest.core.exception.ServiceException;
import com.rymcu.forest.core.exception.TransactionException;
import com.rymcu.forest.core.result.GlobalResult;
@ -62,6 +63,9 @@ public class BaseExceptionHandler {
} else if (ex instanceof ServletException) {
result.setCode(ResultCode.FAIL.getCode());
result.setMessage(ex.getMessage());
} else if (ex instanceof BusinessException) {
result.setCode(ResultCode.FAIL.getCode());
result.setMessage(ex.getMessage());
} else if (ex instanceof TransactionException) {
result.setCode(TransactionCode.InsufficientBalance.getCode());
result.setMessage(ex.getMessage());
@ -108,6 +112,9 @@ public class BaseExceptionHandler {
} else if (ex instanceof ServletException) {
attributes.put("code", ResultCode.FAIL.getCode());
attributes.put("message", ex.getMessage());
} else if (ex instanceof BusinessException) {
attributes.put("code", ResultCode.FAIL.getCode());
attributes.put("message", ex.getMessage());
} else if (ex instanceof TransactionException) {
attributes.put("code", TransactionCode.InsufficientBalance.getCode());
attributes.put("message", ex.getMessage());

View File

@ -1,5 +1,6 @@
package com.rymcu.forest.config;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.rymcu.forest.core.constant.ShiroConstants;
import com.rymcu.forest.core.exception.CaptchaException;
import com.rymcu.forest.entity.Permission;
@ -106,7 +107,8 @@ public class BaseShiroRealm extends AuthorizingRealm {
private static final long serialVersionUID = 1L;
private Integer id; // 编号
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long id; // 编号
private String account; // 登录名
private String name; // 姓名
private boolean mobileLogin; // 是否手机登录
@ -120,7 +122,7 @@ public class BaseShiroRealm extends AuthorizingRealm {
this.mobileLogin = mobileLogin;
}
public Integer getId() {
public Long getId() {
return id;
}

View File

@ -40,12 +40,11 @@ public class MybatisConfigurer {
pageHelper.setProperties(properties);
//添加插件
factory.setPlugins(new Interceptor[]{pageHelper});
factory.setPlugins(pageHelper);
//添加XML目录
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
factory.setMapperLocations(resolver.getResources("classpath:mapper/**/*.xml"));
// factory.setTypeHandlersPackage("com.rymcu.forest.util.handlers");
return factory.getObject();
}

View File

@ -3,14 +3,12 @@ package com.rymcu.forest.config;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.session.mgt.eis.MemorySessionDAO;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.EnvironmentAware;
@ -116,62 +114,12 @@ public class ShiroConfig implements EnvironmentAware {
@Bean
public SessionManager sessionManager() {
BaseSessionManager sessionManager = new BaseSessionManager();
sessionManager.setSessionDAO(redisSessionDAO());
sessionManager.setSessionDAO(new MemorySessionDAO());
sessionManager.setSessionIdUrlRewritingEnabled(false);
sessionManager.setGlobalSessionTimeout(21600000L);
return sessionManager;
}
/**
* 配置shiro redisManager
* <p>
* 使用的是shiro-redis开源插件
*
* @return
*/
public RedisManager redisManager() {
StringBuffer host = new StringBuffer(env.getProperty("spring.redis.host"));
host.append(":").append(env.getProperty("spring.redis.port"));
// 设置redis配置信息
RedisManager redisManager = new RedisManager();
redisManager.setHost(host.toString());
redisManager.setPassword(env.getProperty("spring.redis.password"));
return redisManager;
}
/**
* cacheManager 缓存 redis实现
* <p>
* 使用的是shiro-redis开源插件
*
* @return
*/
@Bean
public RedisCacheManager cacheManager() {
RedisCacheManager redisCacheManager = new RedisCacheManager();
redisCacheManager.setRedisManager(redisManager());
return redisCacheManager;
}
/**
* RedisSessionDAO shiro sessionDao层的实现 通过redis
* <p>
* 使用的是shiro-redis开源插件
*/
@Bean
public RedisSessionDAO redisSessionDAO() {
RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
redisSessionDAO.setRedisManager(redisManager());
redisSessionDAO.setExpire(21600);
return redisSessionDAO;
}
/**
* 开启shiro aop注解支持.
* 使用代理方式;所以需要开启代码支持;

View File

@ -12,6 +12,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.util.ResourceUtils;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
@ -54,7 +55,7 @@ public class WebMvcConfigurer extends WebMvcConfigurationSupport {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedOriginPatterns(CorsConfiguration.ALL)
.allowCredentials(true)
.allowedMethods("GET", "POST", "DELETE", "PUT", "PATCH");
}

View File

@ -0,0 +1,28 @@
package com.rymcu.forest.core.exception;
import org.apache.shiro.authc.AccountException;
/**
* Created on 2022/8/25 19:27.
*
* @author ronger
* @email ronger-x@outlook.com
*/
public class AccountExistsException extends AccountException {
private static final long serialVersionUID = 3206734387536223284L;
public AccountExistsException() {
}
public AccountExistsException(String message) {
super(message);
}
public AccountExistsException(String message, Throwable cause) {
super(message, cause);
}
public AccountExistsException(Throwable cause) {
super(cause);
}
}

View File

@ -0,0 +1,28 @@
package com.rymcu.forest.core.exception;
/**
* @author KKould
*/
public class BusinessException extends RuntimeException {
private static final long serialVersionUID = 3206744387536223284L;
public BusinessException() {
}
public BusinessException(String message) {
super(message);
}
public BusinessException(String message, Throwable cause) {
super(message, cause);
}
public BusinessException(Throwable cause) {
super(cause);
}
public BusinessException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}

View File

@ -0,0 +1,27 @@
package com.rymcu.forest.core.exception;
/**
* @author KKould
*/
public class ContentNotExistException extends BusinessException {
private static final long serialVersionUID = 3206734387536223284L;
public ContentNotExistException() {
}
public ContentNotExistException(String message) {
super(message);
}
public ContentNotExistException(String message, Throwable cause) {
super(message, cause);
}
public ContentNotExistException(Throwable cause) {
super(cause);
}
public ContentNotExistException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}

View File

@ -0,0 +1,32 @@
package com.rymcu.forest.core.exception;
/**
* Created on 2022/8/25 19:11.
*
* @author ronger
* @email ronger-x@outlook.com
*/
public class NicknameOccupyException extends BusinessException {
private static final long serialVersionUID = 3206744387536223284L;
public NicknameOccupyException() {
}
public NicknameOccupyException(String message) {
super(message);
}
public NicknameOccupyException(String message, Throwable cause) {
super(message, cause);
}
public NicknameOccupyException(Throwable cause) {
super(cause);
}
public NicknameOccupyException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}

View File

@ -5,7 +5,7 @@ import com.rymcu.forest.enumerate.TransactionCode;
/**
* @author ronger
*/
public class TransactionException extends Exception {
public class TransactionException extends BusinessException {
private int code;

View File

@ -0,0 +1,29 @@
package com.rymcu.forest.core.exception;
/**
* @author KKould
*/
public class UltraViresException extends BusinessException {
private static final long serialVersionUID = 3206744387536228284L;
public UltraViresException() {
super();
}
public UltraViresException(String message) {
super(message);
}
public UltraViresException(String message, Throwable cause) {
super(message, cause);
}
public UltraViresException(Throwable cause) {
super(cause);
}
protected UltraViresException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}

View File

@ -90,7 +90,7 @@ public class VisitAspect {
if (StringUtils.isBlank(param) || "undefined".equals(param) || "null".equals(param)) {
break;
}
Integer id = Integer.parseInt(param);
Long id = Long.parseLong(param);
articleService.incrementArticleViewCount(id);
break;
default:

View File

@ -76,7 +76,7 @@ public class AuthorshipAspect {
}
HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
String idArticle;
Integer idAuthor = 0;
Long idAuthor = 0l;
if (isAjax(request)) {
Object[] objects = joinPoint.getArgs();
JSONObject jsonObject;

View File

@ -1,7 +1,11 @@
package com.rymcu.forest.dto;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
import java.util.List;
@ -10,14 +14,19 @@ import java.util.List;
* @author ronger
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ArticleDTO {
private Integer idArticle;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idArticle;
/** 文章标题 */
private String articleTitle;
/** 文章缩略图 */
private String articleThumbnailUrl;
/** 文章作者id */
private Integer articleAuthorId;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long articleAuthorId;
/** 文章作者 */
private String articleAuthorName;
/** 文章作者头像 */

View File

@ -1,18 +1,26 @@
package com.rymcu.forest.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author ronger
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ArticleTagDTO {
private Integer idArticleTag;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idArticleTag;
private Integer idTag;
private Integer idArticle;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idArticle;
private String tagTitle;
@ -22,5 +30,6 @@ public class ArticleTagDTO {
private String tagIconPath;
private Integer tagAuthorId;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long tagAuthorId;
}

View File

@ -1,14 +1,22 @@
package com.rymcu.forest.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author ronger
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Author {
private Integer idUser;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idUser;
private String userNickname;

View File

@ -1,5 +1,6 @@
package com.rymcu.forest.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
/**
@ -8,7 +9,8 @@ import lombok.Data;
@Data
public class ChangeEmailDTO {
private Integer idUser;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idUser;
private String email;

View File

@ -1,5 +1,6 @@
package com.rymcu.forest.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.rymcu.forest.entity.Notification;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ -11,7 +12,8 @@ import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = false)
public class NotificationDTO extends Notification {
private Integer idNotification;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idNotification;
private String dataTitle;

View File

@ -1,5 +1,6 @@
package com.rymcu.forest.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.util.List;
@ -10,11 +11,14 @@ import java.util.List;
@Data
public class PortfolioArticleDTO {
private Integer id;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long id;
private Integer idPortfolio;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idPortfolio;
private Integer idArticle;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idArticle;
private String headImgUrl;

View File

@ -1,5 +1,6 @@
package com.rymcu.forest.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.util.Date;
@ -10,11 +11,13 @@ import java.util.Date;
@Data
public class PortfolioDTO {
private Integer idPortfolio;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idPortfolio;
/** 作品集头像 */
private String headImgUrl;
/** 作品集作者 */
private Integer portfolioAuthorId;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long portfolioAuthorId;
/** 作品集作者 */
private String portfolioAuthorName;
/** 作品集作者头像 */

View File

@ -0,0 +1,23 @@
package com.rymcu.forest.dto;
import com.rymcu.forest.entity.Product;
import lombok.Data;
/**
* Created on 2022/6/21 9:38.
*
* @author ronger
* @email ronger-x@outlook.com
* @packageName com.rymcu.forest.dto
*/
@Data
public class ProductDTO extends Product {
/**
* 文章内容
*/
private String productContent;
/**
* 文章内容html
*/
private String productContentHtml;
}

View File

@ -1,5 +1,6 @@
package com.rymcu.forest.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
/**
@ -8,7 +9,8 @@ import lombok.Data;
@Data
public class TokenUser {
private Integer idUser;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idUser;
private String account;

View File

@ -1,5 +1,6 @@
package com.rymcu.forest.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
/**
@ -8,7 +9,8 @@ import lombok.Data;
@Data
public class UpdatePasswordDTO {
private Integer idUser;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idUser;
private String password;

View File

@ -1,5 +1,6 @@
package com.rymcu.forest.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
/**
@ -8,7 +9,8 @@ import lombok.Data;
@Data
public class UserDTO {
private Integer idUser;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idUser;
private String account;
@ -19,4 +21,6 @@ public class UserDTO {
private String nickname;
private String signature;
private String bgImgUrl;
}

View File

@ -1,6 +1,7 @@
package com.rymcu.forest.dto;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import javax.persistence.Column;
@ -13,7 +14,8 @@ import java.util.Date;
@Data
public class UserInfoDTO implements Serializable {
private Integer idUser;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idUser;
private String account;
@ -46,4 +48,6 @@ public class UserInfoDTO implements Serializable {
private Integer onlineStatus;
private String bgImgUrl;
}

View File

@ -1,5 +1,6 @@
package com.rymcu.forest.dto.admin;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
/**
@ -8,7 +9,9 @@ import lombok.Data;
@Data
public class TopicTagDTO {
private Integer idTopic;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idTopic;
private Integer idTag;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idTag;
}

View File

@ -1,5 +1,6 @@
package com.rymcu.forest.dto.admin;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
/**
@ -7,7 +8,10 @@ import lombok.Data;
*/
@Data
public class UserRoleDTO {
private Integer idUser;
private Integer idRole;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idUser;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idRole;
}

View File

@ -1,5 +1,6 @@
package com.rymcu.forest.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import javax.persistence.Column;
@ -19,13 +20,15 @@ public class Article implements Serializable,Cloneable {
@Id
@GeneratedValue(generator = "JDBC")
@Column(name = "id")
private Integer idArticle;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idArticle;
/** 文章标题 */
private String articleTitle;
/** 文章缩略图 */
private String articleThumbnailUrl;
/** 文章作者id */
private Integer articleAuthorId;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long articleAuthorId;
/** 文章类型 */
private String articleType;
/** 文章标签 */

View File

@ -1,5 +1,6 @@
package com.rymcu.forest.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import javax.persistence.Column;
@ -18,7 +19,8 @@ public class ArticleContent {
@Id
@Column(name = "id")
@GeneratedValue(generator = "JDBC")
private Integer idArticle;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idArticle;
private String articleContent;

View File

@ -1,5 +1,6 @@
package com.rymcu.forest.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import javax.persistence.Column;
@ -21,15 +22,18 @@ public class ArticleThumbsUp implements Serializable, Cloneable {
@Id
@Column(name = "id")
@GeneratedValue(generator = "JDBC")
private Integer idArticleThumbsUp;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idArticleThumbsUp;
/**
* 文章表主键
*/
private Integer idArticle;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idArticle;
/**
* 用户表主键
*/
private Integer idUser;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idUser;
/**
* 点赞时间
*/

View File

@ -1,6 +1,7 @@
package com.rymcu.forest.entity;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import javax.persistence.Column;
@ -21,15 +22,17 @@ public class Bank {
@Id
@Column(name = "id")
@GeneratedValue(generator = "JDBC")
private Integer idBank;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idBank;
/** 银行名称 */
private String bankName;
/** 银行负责人 */
private Integer bankOwner;
private Long bankOwner;
/** 银行描述 */
private String bankDescription;
/** 创建人 */
private Integer createdBy;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long createdBy;
/** 创建时间 */
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private Date createdTime;

View File

@ -1,6 +1,7 @@
package com.rymcu.forest.entity;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import javax.persistence.Column;
@ -21,15 +22,18 @@ public class BankAccount {
@Id
@Column(name = "id")
@GeneratedValue(generator = "JDBC")
private Integer idBankAccount;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idBankAccount;
/** 所属银行 */
private Integer idBank;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idBank;
/** 银行账户 */
private String bankAccount;
/** 账户余额 */
private BigDecimal accountBalance;
/** 账户所有者 */
private Integer accountOwner;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long accountOwner;
/** 创建时间 */
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private Date createdTime;

View File

@ -1,5 +1,6 @@
package com.rymcu.forest.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import javax.persistence.Column;
@ -19,22 +20,26 @@ public class Comment implements Serializable,Cloneable {
@Id
@GeneratedValue(generator = "JDBC")
@Column(name = "id")
private Integer idComment;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idComment;
/** 评论内容 */
@Column(name = "comment_content")
private String commentContent;
/** 作者 id */
@Column(name = "comment_author_id")
private Integer commentAuthorId;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long commentAuthorId;
/** 文章 id */
@Column(name = "comment_article_id")
private Integer commentArticleId;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long commentArticleId;
/** 锚点 url */
@Column(name = "comment_sharp_url")
private String commentSharpUrl;
/** 父评论 id */
@Column(name = "comment_original_comment_id")
private Integer commentOriginalCommentId;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long commentOriginalCommentId;
/** 状态 */
@Column(name = "comment_status")
private String commentStatus;

View File

@ -1,5 +1,6 @@
package com.rymcu.forest.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import javax.persistence.GeneratedValue;
@ -18,11 +19,13 @@ public class CurrencyIssue {
/** 主键 */
@Id
@GeneratedValue(generator = "JDBC")
private Integer id;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long id;
/** 发行数额 */
private BigDecimal issueValue;
/** 发行人 */
private Integer createdBy;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long createdBy;
/** 发行时间 */
private Date createdTime;

View File

@ -1,5 +1,6 @@
package com.rymcu.forest.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import javax.persistence.Column;
@ -21,7 +22,8 @@ public class CurrencyRule implements Serializable, Cloneable {
@Id
@GeneratedValue(generator = "JDBC")
@Column(name = "id")
private Integer idCurrencyRule;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idCurrencyRule;
/**
* 规则名称
*/

View File

@ -1,5 +1,6 @@
package com.rymcu.forest.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import javax.persistence.Column;
@ -18,13 +19,16 @@ public class Follow implements Serializable,Cloneable {
@Id
@GeneratedValue(generator = "JDBC")
@Column(name = "id")
private Integer idFollow;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idFollow;
/** 关注者 id */
@Column(name = "follower_id")
private Integer followerId;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long followerId;
/** 关注数据 id */
@Column(name = "following_id")
private Integer followingId;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long followingId;
/** 0用户1标签2帖子收藏3帖子关注 */
@Column(name = "following_type")
private String followingType;

View File

@ -1,5 +1,6 @@
package com.rymcu.forest.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import javax.persistence.Column;
@ -21,13 +22,15 @@ public class ForestFile {
@Id
@GeneratedValue(generator = "JDBC")
@Column(name = "id")
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long id;
/**
* 文件大小
*/
@Column(name = "file_size")
private long fileSize;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long fileSize;
/**
* 文件类型-文件后缀
@ -68,7 +71,8 @@ public class ForestFile {
* 创建人
*/
@Column(name = "created_by")
private long createdBy;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long createdBy;
}

View File

@ -1,6 +1,7 @@
package com.rymcu.forest.entity;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import javax.persistence.Column;
@ -22,7 +23,8 @@ public class LoginRecord implements Serializable,Cloneable {
@Id
@GeneratedValue(generator = "JDBC")
@Column(name = "id")
private Integer id;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long id;
/** IP */
@Column(name = "login_ip")
private String loginIp;
@ -43,7 +45,8 @@ public class LoginRecord implements Serializable,Cloneable {
private String loginBrowser;
/** 用户 id */
@Column(name = "id_user")
private Integer idUser;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idUser;
/** 创建时间 */
@Column(name = "created_time")
@JSONField(format = "yyyy-MM-dd HH:mm:ss")

View File

@ -1,6 +1,7 @@
package com.rymcu.forest.entity;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import javax.persistence.Column;
@ -23,12 +24,14 @@ public class Notification implements Serializable,Cloneable {
@Id
@GeneratedValue(generator = "JDBC")
@Column(name = "id")
private Integer idNotification;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idNotification;
/**
* 用户id
*/
@Column(name = "id_user")
private Integer idUser;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idUser;
/**
* 数据类型
*/
@ -38,7 +41,8 @@ public class Notification implements Serializable,Cloneable {
* 数据id
*/
@Column(name = "data_id")
private Integer dataId;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long dataId;
/**
* 数据摘要
*/

View File

@ -1,5 +1,6 @@
package com.rymcu.forest.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import tk.mybatis.mapper.annotation.ColumnType;
@ -19,7 +20,8 @@ public class Permission implements Serializable,Cloneable {
@Id
@Column(name = "id")
@GeneratedValue(generator = "JDBC")
private Integer idPermission;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idPermission;
/**
* 权限标识

View File

@ -1,5 +1,6 @@
package com.rymcu.forest.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import javax.persistence.*;
@ -15,14 +16,16 @@ public class Portfolio {
@Id
@GeneratedValue(generator = "JDBC")
@Column(name = "id")
private Integer idPortfolio;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idPortfolio;
/** 作品集头像 */
@Column(name = "portfolio_head_img_url")
private String headImgUrl;
/** 作品集名称 */
private String portfolioTitle;
/** 作品集作者 */
private Integer portfolioAuthorId;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long portfolioAuthorId;
/** 作品集介绍 */
private String portfolioDescription;
/** 作品集介绍 Html */

View File

@ -0,0 +1,62 @@
package com.rymcu.forest.entity;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import java.io.Serializable;
import java.util.Date;
/**
* Created on 2022/6/13 21:42.
*
* @author ronger
* @email ronger-x@outlook.com
* @desc : 产品表
*/
@Data
@Table(name = "forest_product")
public class Product implements Serializable, Cloneable {
/**
* 主键
*/
@Id
@GeneratedValue(generator = "JDBC")
@Column(name = "id")
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idProduct;
/**
* 产品名
*/
private String productTitle;
/**
* 单价(单位:)
*/
private Integer productPrice;
/**
* 产品主图
*/
private String productImgUrl;
/**
* 产品描述
*/
private String productDescription;
/**
* 权重;数值越小权限越大;0:无权限
*/
private Integer weights;
/**
* 创建时间
*/
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private Date createdTime;
/**
* 更新时间
*/
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private Date updatedTime;
}

View File

@ -0,0 +1,44 @@
package com.rymcu.forest.entity;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import javax.persistence.Table;
import java.io.Serializable;
import java.util.Date;
/**
* Created on 2022/6/13 21:51.
*
* @author ronger
* @email ronger-x@outlook.com
* @desc : 产品详情表
*/
@Data
@Table(name = "forest_product_content")
public class ProductContent implements Serializable, Cloneable {
/**
* 产品表主键
*/
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idProduct;
/**
* 产品详情原文
*/
private String productContent;
/**
* 产品详情;Html
*/
private String productContentHtml;
/**
* 创建时间
*/
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private Date createdTime;
/**
* 更新时间
*/
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private Date updatedTime;
}

View File

@ -1,6 +1,7 @@
package com.rymcu.forest.entity;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import javax.persistence.Column;
@ -19,7 +20,8 @@ public class Role implements Serializable,Cloneable {
@Id
@Column(name = "id")
@GeneratedValue(generator = "JDBC")
private Integer idRole;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idRole;
/**
* 角色名称

View File

@ -1,5 +1,6 @@
package com.rymcu.forest.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import javax.persistence.Column;
@ -19,7 +20,8 @@ public class SpecialDay implements Serializable,Cloneable{
@Id
@Column(name = "id")
@GeneratedValue(generator = "JDBC")
private Integer idSpecialDay;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idSpecialDay;
/** 名称 */
private String specialDayName;
/** 权重/优先级,小数优秀 */

View File

@ -1,5 +1,6 @@
package com.rymcu.forest.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import javax.persistence.GeneratedValue;
@ -20,7 +21,8 @@ public class Sponsor implements Serializable, Cloneable {
*/
@Id
@GeneratedValue(generator = "JDBC")
private Integer id;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long id;
/**
* 数据类型
*/
@ -28,11 +30,13 @@ public class Sponsor implements Serializable, Cloneable {
/**
* 数据主键
*/
private Integer dataId;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long dataId;
/**
* 赞赏人
*/
private Integer sponsor;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long sponsor;
/**
* 赞赏日期
*/

View File

@ -1,5 +1,6 @@
package com.rymcu.forest.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import javax.persistence.Column;
@ -19,7 +20,8 @@ public class Tag implements Serializable,Cloneable {
@Id
@Column(name = "id")
@GeneratedValue(generator = "JDBC")
private Integer idTag;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idTag;
/** 标签名 */
private String tagTitle;
/** 标签图标 */

View File

@ -1,5 +1,6 @@
package com.rymcu.forest.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import javax.persistence.Column;
@ -19,7 +20,8 @@ public class Topic {
@Id
@Column(name = "id")
@GeneratedValue(generator = "JDBC")
private Integer idTopic;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idTopic;
/** 专题标题 */
private String topicTitle;
/** 专题路径 */

View File

@ -1,5 +1,6 @@
package com.rymcu.forest.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import javax.persistence.Column;
@ -20,7 +21,8 @@ public class TransactionRecord {
@Id
@Column(name = "id")
@GeneratedValue(generator = "JDBC")
private Integer idTransactionRecord;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idTransactionRecord;
/** 交易流水号 */
private String transactionNo;
/** 款项 */

View File

@ -1,6 +1,7 @@
package com.rymcu.forest.entity;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.apache.ibatis.type.JdbcType;
import tk.mybatis.mapper.annotation.ColumnType;
@ -21,7 +22,8 @@ public class User implements Serializable,Cloneable {
@Id
@Column(name = "id")
@GeneratedValue(generator = "JDBC")
private Integer idUser;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idUser;
/**
* 登录账号
@ -120,4 +122,10 @@ public class User implements Serializable,Cloneable {
@Column(name = "last_online_time")
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private Date lastOnlineTime;
/**
* 个人中心背景图片
* */
@Column(name = "bg_img_url")
private String bgImgUrl;
}

View File

@ -1,5 +1,6 @@
package com.rymcu.forest.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import javax.persistence.Id;
@ -13,7 +14,8 @@ import javax.persistence.Table;
public class UserExtend {
@Id
private Integer idUser;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idUser;
private String github;

View File

@ -1,6 +1,7 @@
package com.rymcu.forest.entity;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import javax.persistence.Column;
@ -22,7 +23,8 @@ public class Visit implements Serializable,Cloneable {
@Id
@GeneratedValue(generator = "JDBC")
@Column(name = "id")
private Integer id;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long id;
/** 浏览链接 */
@Column(name = "visit_url")
private String visitUrl;
@ -40,7 +42,8 @@ public class Visit implements Serializable,Cloneable {
private String visitDeviceId;
/** 浏览者 id */
@Column(name = "visit_user_id")
private Integer visitUserId;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long visitUserId;
/** 上游链接 */
@Column(name = "visit_referer_url")
private String visitRefererUrl;

View File

@ -1,5 +1,6 @@
package com.rymcu.forest.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import javax.persistence.Column;
@ -17,7 +18,8 @@ public class WxUser {
@Id
@Column(name = "id")
@GeneratedValue(generator = "JDBC")
private Integer idWxUser;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idWxUser;
private Boolean subscribe;

View File

@ -0,0 +1,26 @@
package com.rymcu.forest.handler;
import com.rymcu.forest.handler.event.AccountEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
/**
* Created on 2022/8/24 14:44.
*
* @author ronger
* @email ronger-x@outlook.com
* @packageName com.rymcu.forest.handler
*/
@Slf4j
@Component
public class AccountHandler {
@Async
@EventListener
public void processAccountLastLoginEvent(AccountEvent accountEvent) {
}
}

View File

@ -0,0 +1,66 @@
package com.rymcu.forest.handler;
import com.alibaba.fastjson.JSON;
import com.rymcu.forest.core.constant.NotificationConstant;
import com.rymcu.forest.handler.event.ArticleDeleteEvent;
import com.rymcu.forest.handler.event.ArticleEvent;
import com.rymcu.forest.lucene.service.LuceneService;
import com.rymcu.forest.util.NotificationUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* Created on 2022/8/16 20:42.
*
* @author ronger
* @email ronger-x@outlook.com
*/
@Slf4j
@Component
public class ArticleHandler {
@Resource
private LuceneService luceneService;
@EventListener
@Async
public void processArticlePostEvent(ArticleEvent articleEvent) throws InterruptedException {
Thread.sleep(1000);
log.info(String.format("执行文章发布相关事件:[%s]", JSON.toJSONString(articleEvent)));
// 发送系统通知
if (articleEvent.getNotification()) {
NotificationUtils.sendAnnouncement(articleEvent.getIdArticle(), NotificationConstant.Article, articleEvent.getArticleTitle());
} else {
// 发送关注通知
StringBuilder dataSummary = new StringBuilder();
if (articleEvent.getIsUpdate()) {
dataSummary.append(articleEvent.getNickname()).append("更新了文章: ").append(articleEvent.getArticleTitle());
NotificationUtils.sendArticlePush(articleEvent.getIdArticle(), NotificationConstant.UpdateArticle, dataSummary.toString(), articleEvent.getArticleAuthorId());
} else {
dataSummary.append(articleEvent.getNickname()).append("发布了文章: ").append(articleEvent.getArticleTitle());
NotificationUtils.sendArticlePush(articleEvent.getIdArticle(), NotificationConstant.PostArticle, dataSummary.toString(), articleEvent.getArticleAuthorId());
}
}
// 草稿不更新索引
if (articleEvent.getIsUpdate()) {
log.info("更新文章索引id={}", articleEvent.getIdArticle());
luceneService.updateArticle(articleEvent.getIdArticle());
} else {
log.info("写入文章索引id={}", articleEvent.getIdArticle());
luceneService.writeArticle(articleEvent.getIdArticle());
}
log.info("执行完成文章发布相关事件...id={}", articleEvent.getIdArticle());
}
@EventListener
@Async
public void processArticleDeleteEvent(ArticleDeleteEvent articleDeleteEvent) throws InterruptedException {
Thread.sleep(1000);
log.info(String.format("执行文章删除相关事件:[%s]", JSON.toJSONString(articleDeleteEvent)));
luceneService.deleteArticle(articleDeleteEvent.getIdArticle());
log.info("执行完成文章删除相关事件...id={}", articleDeleteEvent.getIdArticle());
}
}

View File

@ -0,0 +1,57 @@
package com.rymcu.forest.handler;
import com.alibaba.fastjson.JSON;
import com.rymcu.forest.core.constant.NotificationConstant;
import com.rymcu.forest.entity.Comment;
import com.rymcu.forest.handler.event.CommentEvent;
import com.rymcu.forest.mapper.CommentMapper;
import com.rymcu.forest.util.Html2TextUtil;
import com.rymcu.forest.util.NotificationUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* Created on 2022/8/17 7:38.
*
* @author ronger
* @email ronger-x@outlook.com
* @packageName com.rymcu.forest.handler
*/
@Slf4j
@Component
public class CommentHandler {
private static final int MAX_PREVIEW = 200;
@Resource
private CommentMapper commentMapper;
@Async
@EventListener
public void processCommentCreatedEvent(CommentEvent commentEvent) throws InterruptedException {
log.info(String.format("开始执行评论发布事件:[%s]", JSON.toJSONString(commentEvent)));
String commentContent = commentEvent.getContent();
Integer length = commentContent.length();
if (length > MAX_PREVIEW) {
length = 200;
}
String commentPreviewContent = commentContent.substring(0, length);
commentContent = Html2TextUtil.getContent(commentPreviewContent);
// 判断是否是回复消息
if (commentEvent.getCommentOriginalCommentId() != null && commentEvent.getCommentOriginalCommentId() != 0) {
Comment originalComment = commentMapper.selectByPrimaryKey(commentEvent.getCommentOriginalCommentId());
// 回复消息时,评论者不是上级评论作者则进行消息通知
if (!commentEvent.getCommentAuthorId().equals(originalComment.getCommentAuthorId())) {
NotificationUtils.saveNotification(originalComment.getCommentAuthorId(), commentEvent.getIdComment(), NotificationConstant.Comment, commentContent);
}
} else {
// 评论者不是作者本人则进行消息通知
if (!commentEvent.getCommentAuthorId().equals(commentEvent.getArticleAuthorId())) {
NotificationUtils.saveNotification(commentEvent.getArticleAuthorId(), commentEvent.getIdComment(), NotificationConstant.Comment, commentContent);
}
}
}
}

View File

@ -0,0 +1,19 @@
package com.rymcu.forest.handler.event;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* Created on 2022/8/24 14:45.
*
* @author ronger
* @email ronger-x@outlook.com
* @packageName com.rymcu.forest.handler.event
*/
@Data
@AllArgsConstructor
public class AccountEvent {
private String account;
}

View File

@ -0,0 +1,18 @@
package com.rymcu.forest.handler.event;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* Created on 2022/8/20 18:51.
*
* @author ronger
* @email ronger-x@outlook.com
*/
@Data
@AllArgsConstructor
public class ArticleDeleteEvent {
private Long idArticle;
}

View File

@ -0,0 +1,27 @@
package com.rymcu.forest.handler.event;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* Created on 2022/8/16 20:56.
*
* @author ronger
* @email ronger-x@outlook.com
*/
@Data
@AllArgsConstructor
public class ArticleEvent {
private Long idArticle;
private String articleTitle;
private Boolean isUpdate;
private Boolean notification;
private String nickname;
private Long articleAuthorId;
}

View File

@ -0,0 +1,26 @@
package com.rymcu.forest.handler.event;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* Created on 2022/8/17 7:43.
*
* @author ronger
* @email ronger-x@outlook.com
* @packageName com.rymcu.forest.handler.event
*/
@Data
@AllArgsConstructor
public class CommentEvent {
private Long idComment;
private Long articleAuthorId;
private Long commentAuthorId;
private String content;
private Long commentOriginalCommentId;
}

View File

@ -1,13 +1,14 @@
package com.rymcu.forest.jwt.service;
import com.rymcu.forest.handler.event.AccountEvent;
import com.rymcu.forest.jwt.def.JwtConstants;
import com.rymcu.forest.jwt.model.TokenModel;
import com.rymcu.forest.service.UserService;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
@ -27,7 +28,7 @@ public class RedisTokenManager implements TokenManager {
@Autowired
private StringRedisTemplate redisTemplate;
@Resource
private UserService userService;
private ApplicationEventPublisher applicationEventPublisher;
/**
* 生成TOKEN
@ -62,7 +63,7 @@ public class RedisTokenManager implements TokenManager {
String result = redisTemplate.boundValueOps(key.toString()).get();
if (StringUtils.isBlank(result)) {
// 更新最后在线时间
userService.updateLastOnlineTimeByEmail(model.getUsername());
applicationEventPublisher.publishEvent(new AccountEvent(model.getUsername()));
redisTemplate.boundValueOps(key.toString()).set(LocalDateTime.now().toString(), JwtConstants.LAST_ONLINE_EXPIRES_MINUTE, TimeUnit.MINUTES);
}
return true;

View File

@ -99,7 +99,7 @@ public class LuceneSearchController {
int endIndex = Math.min(startIndex + rows, total);
// 分割子列表
List<ArticleLucene> subList = resList.subList(startIndex, endIndex);
String[] ids = subList.stream().map(ArticleLucene::getIdArticle).toArray(String[]::new);
Long[] ids = subList.stream().map(ArticleLucene::getIdArticle).toArray(Long[]::new);
List<ArticleDTO> articleDTOList = luceneService.getArticlesByIds(ids);
ArticleDTO temp;
// 写入文章关键词信息
@ -114,7 +114,7 @@ public class LuceneSearchController {
}
articles.addAll(articleDTOList);
PageInfo<ArticleDTO> pageInfo = new PageInfo<>(articles);
return GlobalResultGenerator.genSuccessResult(Utils.getArticlesGlobalResult(pageInfo));
return GlobalResultGenerator.genSuccessResult(pageInfo);
}
/**
@ -141,7 +141,7 @@ public class LuceneSearchController {
int endIndex = Math.min(startIndex + rows, total);
// 分割子列表
List<UserLucene> subList = resList.subList(startIndex, endIndex);
Integer[] ids = subList.stream().map(UserLucene::getIdUser).toArray(Integer[]::new);
Long[] ids = subList.stream().map(UserLucene::getIdUser).toArray(Long[]::new);
List<UserDTO> userDTOList = userLuceneService.getUsersByIds(ids);
UserDTO temp;
// 写入文章关键词信息
@ -156,7 +156,7 @@ public class LuceneSearchController {
}
users.addAll(userDTOList);
PageInfo<UserDTO> pageInfo = new PageInfo<>(users);
return GlobalResultGenerator.genSuccessResult(Utils.getUserGlobalResult(pageInfo));
return GlobalResultGenerator.genSuccessResult(pageInfo);
}
/**
@ -183,7 +183,7 @@ public class LuceneSearchController {
int endIndex = Math.min(startIndex + rows, total);
// 分割子列表
List<PortfolioLucene> subList = resList.subList(startIndex, endIndex);
String[] ids = subList.stream().map(PortfolioLucene::getIdPortfolio).toArray(String[]::new);
Long[] ids = subList.stream().map(PortfolioLucene::getIdPortfolio).toArray(Long[]::new);
List<PortfolioDTO> portfolioDTOList = portfolioLuceneService.getPortfoliosByIds(ids);
PortfolioDTO temp;
// 写入文章关键词信息
@ -198,6 +198,6 @@ public class LuceneSearchController {
}
portfolios.addAll(portfolioDTOList);
PageInfo<PortfolioDTO> pageInfo = new PageInfo<>(portfolios);
return GlobalResultGenerator.genSuccessResult(Utils.getPortfolioGlobalResult(pageInfo));
return GlobalResultGenerator.genSuccessResult(pageInfo);
}
}

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

0
src/main/java/com/rymcu/forest/lucene/core/Lexeme.java Executable file → Normal file
View File

View File

View File

View File

View File

0
src/main/java/com/rymcu/forest/lucene/dic/Hit.java Executable file → Normal file
View File

View File

View File

View File

@ -29,7 +29,7 @@ public interface ArticleLuceneMapper {
* @param ids 文章id(半角逗号分隔)
* @return
*/
List<ArticleDTO> getArticlesByIds(@Param("ids") String[] ids);
List<ArticleDTO> getArticlesByIds(@Param("ids") Long[] ids);
/**
@ -38,6 +38,6 @@ public interface ArticleLuceneMapper {
* @param id 文章id
* @return
*/
ArticleLucene getById(@Param("id") String id);
ArticleLucene getById(@Param("id") Long id);
}

View File

@ -32,7 +32,7 @@ public interface PortfolioLuceneMapper {
* @param ids 作品集id(半角逗号分隔)
* @return
*/
List<PortfolioDTO> getPortfoliosByIds(@Param("ids") String[] ids);
List<PortfolioDTO> getPortfoliosByIds(@Param("ids") Long[] ids);
/**
* 加载作品集
@ -40,5 +40,5 @@ public interface PortfolioLuceneMapper {
* @param id 用户id
* @return
*/
PortfolioLucene getById(@Param("id") String id);
PortfolioLucene getById(@Param("id") Long id);
}

View File

View File

@ -29,7 +29,7 @@ public interface UserLuceneMapper {
* @param ids 用户id(半角逗号分隔)
* @return
*/
List<UserDTO> getUsersByIds(@Param("ids") Integer[] ids);
List<UserDTO> getUsersByIds(@Param("ids") Long[] ids);
/**
* 加载 UserLucene

View File

@ -1,5 +1,6 @@
package com.rymcu.forest.lucene.model;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@ -20,7 +21,8 @@ import javax.persistence.Id;
public class ArticleLucene {
/** 文章编号 */
private String idArticle;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idArticle;
/** 文章标题 */
private String articleTitle;

View File

@ -1,5 +1,6 @@
package com.rymcu.forest.lucene.model;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@ -18,7 +19,8 @@ import lombok.NoArgsConstructor;
public class PortfolioLucene {
/** 作品集编号 */
private String idPortfolio;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idPortfolio;
/** 作品集名称 */
private String portfolioTitle;

View File

@ -1,5 +1,6 @@
package com.rymcu.forest.lucene.model;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@ -22,7 +23,8 @@ import javax.persistence.Column;
public class UserLucene {
/** 用户编号 */
private Integer idUser;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long idUser;
/** 昵称 */
private String nickname;

View File

@ -25,7 +25,7 @@ public interface LuceneService {
*
* @param id
*/
void writeArticle(String id);
void writeArticle(Long id);
/**
@ -40,14 +40,14 @@ public interface LuceneService {
*
* @param id
*/
void updateArticle(String id);
void updateArticle(Long id);
/**
* 删除单个文章索引
*
* @param id
*/
void deleteArticle(String id);
void deleteArticle(Long id);
/**
* 关键词搜索
@ -71,5 +71,5 @@ public interface LuceneService {
* @param ids 文章id(半角逗号分隔)
* @return
*/
List<ArticleDTO> getArticlesByIds(String[] ids);
List<ArticleDTO> getArticlesByIds(Long[] ids);
}

View File

@ -25,7 +25,7 @@ public interface PortfolioLuceneService {
*
* @param id
*/
void writePortfolio(String id);
void writePortfolio(Long id);
/**
* 写入单个作品集索引
@ -39,14 +39,14 @@ public interface PortfolioLuceneService {
*
* @param id
*/
void updatePortfolio(String id);
void updatePortfolio(Long id);
/**
* 删除单个作品集索引
*
* @param id
*/
void deletePortfolio(String id);
void deletePortfolio(Long id);
/**
* 关键词搜索
@ -70,5 +70,5 @@ public interface PortfolioLuceneService {
* @param ids 作品集id(半角逗号分隔)
* @return
*/
List<PortfolioDTO> getPortfoliosByIds(String[] ids);
List<PortfolioDTO> getPortfoliosByIds(Long[] ids);
}

View File

@ -70,5 +70,5 @@ public interface UserLuceneService {
* @param ids 用户id(半角逗号分隔)
* @return
*/
List<UserDTO> getUsersByIds(Integer[] ids);
List<UserDTO> getUsersByIds(Long[] ids);
}

View File

@ -3,8 +3,6 @@ package com.rymcu.forest.lucene.service.impl;
import com.rymcu.forest.dto.ArticleDTO;
import com.rymcu.forest.dto.ArticleTagDTO;
import com.rymcu.forest.dto.Author;
import com.rymcu.forest.dto.PortfolioArticleDTO;
import com.rymcu.forest.entity.ArticleContent;
import com.rymcu.forest.entity.User;
import com.rymcu.forest.lucene.lucene.ArticleBeanIndex;
import com.rymcu.forest.lucene.lucene.IKAnalyzer;
@ -67,6 +65,7 @@ public class LuceneServiceImpl implements LuceneService {
try {
int totalCount = list.size();
int perThreadCount = 3000;
// 加1避免线程池的参数为0
int threadCount = totalCount / perThreadCount + (totalCount % perThreadCount == 0 ? 0 : 1);
ExecutorService pool = Executors.newFixedThreadPool(threadCount);
CountDownLatch countDownLatch1 = new CountDownLatch(1);
@ -96,7 +95,7 @@ public class LuceneServiceImpl implements LuceneService {
}
@Override
public void writeArticle(String id) {
public void writeArticle(Long id) {
writeArticle(luceneMapper.getById(id));
}
@ -106,12 +105,12 @@ public class LuceneServiceImpl implements LuceneService {
}
@Override
public void updateArticle(String id) {
public void updateArticle(Long id) {
ArticleIndexUtil.updateIndex(luceneMapper.getById(id));
}
@Override
public void deleteArticle(String id) {
public void deleteArticle(Long id) {
ArticleIndexUtil.deleteIndex(id);
}
@ -156,12 +155,11 @@ public class LuceneServiceImpl implements LuceneService {
float score = hit.score;
Document hitDoc = searcher.doc(hit.doc);
// 获取到summary
String name = hitDoc.get("summary");
String summary = hitDoc.get("summary");
// 将查询的词和搜索词匹配匹配到添加前缀和后缀
TokenStream tokenStream =
TokenSources.getAnyTokenStream(searcher.getIndexReader(), id, "summary", analyzer);
TokenStream tokenStream = TokenSources.getTokenStream("summary", searcher.getIndexReader().getTermVectors(id), summary, analyzer, -1);
// 传入的第二个参数是查询的值
TextFragment[] frag = highlighter.getBestTextFragments(tokenStream, name, false, 10);
TextFragment[] frag = highlighter.getBestTextFragments(tokenStream, summary, false, 10);
StringBuilder baikeValue = new StringBuilder();
for (TextFragment textFragment : frag) {
if ((textFragment != null) && (textFragment.getScore() > 0)) {
@ -173,8 +171,7 @@ public class LuceneServiceImpl implements LuceneService {
// 获取到title
String title = hitDoc.get("title");
TokenStream titleTokenStream =
TokenSources.getAnyTokenStream(searcher.getIndexReader(), id, "title", analyzer);
TokenStream titleTokenStream = TokenSources.getTokenStream("title", searcher.getIndexReader().getTermVectors(id), title, analyzer, -1);
TextFragment[] titleFrag =
highlighter.getBestTextFragments(titleTokenStream, title, false, 10);
StringBuilder titleValue = new StringBuilder();
@ -185,7 +182,7 @@ public class LuceneServiceImpl implements LuceneService {
}
resList.add(
ArticleLucene.builder()
.idArticle(hitDoc.get("id"))
.idArticle(Long.valueOf(hitDoc.get("id")))
.articleTitle(titleValue.toString())
.articleContent(baikeValue.toString())
.score(String.valueOf(score))
@ -209,9 +206,9 @@ public class LuceneServiceImpl implements LuceneService {
}
@Override
public List<ArticleDTO> getArticlesByIds(String[] ids) {
public List<ArticleDTO> getArticlesByIds(Long[] ids) {
List<ArticleDTO> list = luceneMapper.getArticlesByIds(ids);
list.forEach(articleDTO -> genArticle(articleDTO));
list.forEach(this::genArticle);
return list;
}

View File

@ -41,150 +41,150 @@ import java.util.concurrent.Executors;
@Service
public class PortfolioLuceneServiceImpl implements PortfolioLuceneService {
@Resource private PortfolioLuceneMapper portfolioLuceneMapper;
@Resource
private PortfolioLuceneMapper portfolioLuceneMapper;
/**
* 将文章的数据解析为一个个关键字词存储到索引文件中
*
* @param list
*/
@Override
public void writePortfolio(List<PortfolioLucene> list) {
try {
int totalCount = list.size();
int perThreadCount = 3000;
int threadCount = totalCount / perThreadCount + (totalCount % perThreadCount == 0 ? 0 : 1);
ExecutorService pool = Executors.newFixedThreadPool(threadCount);
CountDownLatch countDownLatch1 = new CountDownLatch(1);
CountDownLatch countDownLatch2 = new CountDownLatch(threadCount);
/**
* 将文章的数据解析为一个个关键字词存储到索引文件中
*
* @param list
*/
@Override
public void writePortfolio(List<PortfolioLucene> list) {
try {
int totalCount = list.size();
int perThreadCount = 3000;
// 加1避免线程池的参数为0
int threadCount = totalCount / perThreadCount + (totalCount % perThreadCount == 0 ? 0 : 1);
ExecutorService pool = Executors.newFixedThreadPool(threadCount);
CountDownLatch countDownLatch1 = new CountDownLatch(1);
CountDownLatch countDownLatch2 = new CountDownLatch(threadCount);
for (int i = 0; i < threadCount; i++) {
int start = i * perThreadCount;
int end = Math.min((i + 1) * perThreadCount, totalCount);
List<PortfolioLucene> subList = list.subList(start, end);
Runnable runnable =
new PortfolioBeanIndex(LucenePath.PORTFOLIO_PATH, i, countDownLatch1, countDownLatch2, subList);
// 子线程交给线程池管理
pool.execute(runnable);
}
countDownLatch1.countDown();
System.out.println("开始创建索引");
// 等待所有线程都完成
countDownLatch2.await();
// 线程全部完成工作
System.out.println("所有线程都创建索引完毕");
// 释放线程池资源
pool.shutdown();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void writePortfolio(String id) {
writePortfolio(portfolioLuceneMapper.getById(id));
}
@Override
public void writePortfolio(PortfolioLucene portfolioLucene) {
PortfolioIndexUtil.addIndex(portfolioLucene);
}
@Override
public void updatePortfolio(String id) {
PortfolioIndexUtil.updateIndex(portfolioLuceneMapper.getById(id));
}
@Override
public void deletePortfolio(String id) {
PortfolioIndexUtil.deleteIndex(id);
}
@Override
public List<PortfolioLucene> getAllPortfolioLucene() {
return portfolioLuceneMapper.getAllPortfolioLucene();
}
@Override
public List<PortfolioDTO> getPortfoliosByIds(String[] ids) {
return portfolioLuceneMapper.getPortfoliosByIds(ids);
}
@Override
public List<PortfolioLucene> searchPortfolio(String value) {
List<PortfolioLucene> resList = new ArrayList<>();
ExecutorService service = Executors.newCachedThreadPool();
// 定义分词器
Analyzer analyzer = new IKAnalyzer();
try {
IndexSearcher searcher = SearchUtil.getIndexSearcherByParentPath(LucenePath.PORTFOLIO_PATH, service);
String[] fields = {"title", "summary"};
// 构造Query对象
MultiFieldQueryParser parser = new MultiFieldQueryParser(fields, analyzer);
BufferedReader in =
new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8));
String line = value != null ? value : in.readLine();
Query query = parser.parse(line);
// 最终被分词后添加的前缀和后缀处理器默认是粗体<B></B>
SimpleHTMLFormatter htmlFormatter =
new SimpleHTMLFormatter("<font color=" + "\"" + "red" + "\"" + ">", "</font>");
// 高亮搜索的词添加到高亮处理器中
Highlighter highlighter = new Highlighter(htmlFormatter, new QueryScorer(query));
// 获取搜索的结果指定返回document返回的个数
// TODO 默认搜索结果为显示第一页1000 可以优化
TopDocs results = SearchUtil.getScoreDocsByPerPage(1, 100, searcher, query);
ScoreDoc[] hits = results.scoreDocs;
// 遍历输出
for (ScoreDoc hit : hits) {
int id = hit.doc;
float score = hit.score;
Document hitDoc = searcher.doc(hit.doc);
// 获取到summary
String summary = hitDoc.get("summary");
// 将查询的词和搜索词匹配匹配到添加前缀和后缀
TokenStream tokenStream =
TokenSources.getAnyTokenStream(searcher.getIndexReader(), id, "summary", analyzer);
// 传入的第二个参数是查询的值
TextFragment[] frag = highlighter.getBestTextFragments(tokenStream, summary, false, 10);
StringBuilder sb = new StringBuilder();
for (TextFragment textFragment : frag) {
if ((textFragment != null) && (textFragment.getScore() > 0)) {
// if ((frag[j] != null)) {
// 获取 summary 的值
sb.append(textFragment.toString());
}
for (int i = 0; i < threadCount; i++) {
int start = i * perThreadCount;
int end = Math.min((i + 1) * perThreadCount, totalCount);
List<PortfolioLucene> subList = list.subList(start, end);
Runnable runnable =
new PortfolioBeanIndex(LucenePath.PORTFOLIO_PATH, i, countDownLatch1, countDownLatch2, subList);
// 子线程交给线程池管理
pool.execute(runnable);
}
countDownLatch1.countDown();
System.out.println("开始创建索引");
// 等待所有线程都完成
countDownLatch2.await();
// 线程全部完成工作
System.out.println("所有线程都创建索引完毕");
// 释放线程池资源
pool.shutdown();
} catch (Exception e) {
e.printStackTrace();
}
// 获取到title
String title = hitDoc.get("title");
TokenStream titleTokenStream =
TokenSources.getAnyTokenStream(searcher.getIndexReader(), id, "title", analyzer);
TextFragment[] titleFrag =
highlighter.getBestTextFragments(titleTokenStream, title, false, 10);
StringBuilder titleValue = new StringBuilder();
for (int j = 0; j < titleFrag.length; j++) {
if ((frag[j] != null)) {
titleValue.append(titleFrag[j].toString());
}
}
resList.add(
PortfolioLucene.builder()
.idPortfolio(hitDoc.get("id"))
.portfolioTitle(titleValue.toString())
.portfolioDescription(sb.toString())
.score(String.valueOf(score))
.build());
}
} catch (IOException | ParseException | InvalidTokenOffsetsException e) {
System.out.println(e.getMessage());
e.printStackTrace();
} finally {
service.shutdownNow();
}
return resList;
}
@Override
public void writePortfolio(Long id) {
writePortfolio(portfolioLuceneMapper.getById(id));
}
@Override
public void writePortfolio(PortfolioLucene portfolioLucene) {
PortfolioIndexUtil.addIndex(portfolioLucene);
}
@Override
public void updatePortfolio(Long id) {
PortfolioIndexUtil.updateIndex(portfolioLuceneMapper.getById(id));
}
@Override
public void deletePortfolio(Long id) {
PortfolioIndexUtil.deleteIndex(id);
}
@Override
public List<PortfolioLucene> getAllPortfolioLucene() {
return portfolioLuceneMapper.getAllPortfolioLucene();
}
@Override
public List<PortfolioDTO> getPortfoliosByIds(Long[] ids) {
return portfolioLuceneMapper.getPortfoliosByIds(ids);
}
@Override
public List<PortfolioLucene> searchPortfolio(String value) {
List<PortfolioLucene> resList = new ArrayList<>();
ExecutorService service = Executors.newCachedThreadPool();
// 定义分词器
Analyzer analyzer = new IKAnalyzer();
try {
IndexSearcher searcher = SearchUtil.getIndexSearcherByParentPath(LucenePath.PORTFOLIO_PATH, service);
String[] fields = {"title", "summary"};
// 构造Query对象
MultiFieldQueryParser parser = new MultiFieldQueryParser(fields, analyzer);
BufferedReader in =
new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8));
String line = value != null ? value : in.readLine();
Query query = parser.parse(line);
// 最终被分词后添加的前缀和后缀处理器默认是粗体<B></B>
SimpleHTMLFormatter htmlFormatter =
new SimpleHTMLFormatter("<font color=" + "\"" + "red" + "\"" + ">", "</font>");
// 高亮搜索的词添加到高亮处理器中
Highlighter highlighter = new Highlighter(htmlFormatter, new QueryScorer(query));
// 获取搜索的结果指定返回document返回的个数
// TODO 默认搜索结果为显示第一页1000 可以优化
TopDocs results = SearchUtil.getScoreDocsByPerPage(1, 100, searcher, query);
ScoreDoc[] hits = results.scoreDocs;
// 遍历输出
for (ScoreDoc hit : hits) {
int id = hit.doc;
float score = hit.score;
Document hitDoc = searcher.doc(hit.doc);
// 获取到summary
String summary = hitDoc.get("summary");
// 将查询的词和搜索词匹配匹配到添加前缀和后缀
TokenStream tokenStream = TokenSources.getTokenStream("summary", searcher.getIndexReader().getTermVectors(id), summary, analyzer, -1);
// 传入的第二个参数是查询的值
TextFragment[] frag = highlighter.getBestTextFragments(tokenStream, summary, false, 10);
StringBuilder sb = new StringBuilder();
for (TextFragment textFragment : frag) {
if ((textFragment != null) && (textFragment.getScore() > 0)) {
// if ((frag[j] != null)) {
// 获取 summary 的值
sb.append(textFragment);
}
}
// 获取到title
String title = hitDoc.get("title");
TokenStream titleTokenStream = TokenSources.getTokenStream("title", searcher.getIndexReader().getTermVectors(id), title, analyzer, -1);
TextFragment[] titleFrag =
highlighter.getBestTextFragments(titleTokenStream, title, false, 10);
StringBuilder titleValue = new StringBuilder();
for (int j = 0; j < titleFrag.length; j++) {
if ((frag[j] != null)) {
titleValue.append(titleFrag[j].toString());
}
}
resList.add(
PortfolioLucene.builder()
.idPortfolio(Long.valueOf(hitDoc.get("id")))
.portfolioTitle(titleValue.toString())
.portfolioDescription(sb.toString())
.score(String.valueOf(score))
.build());
}
} catch (IOException | ParseException | InvalidTokenOffsetsException e) {
System.out.println(e.getMessage());
e.printStackTrace();
} finally {
service.shutdownNow();
}
return resList;
}
}

View File

@ -133,13 +133,13 @@ public class UserLuceneServiceImpl implements UserLuceneService {
int id = hit.doc;
float score = hit.score;
Document hitDoc = searcher.doc(hit.doc);
// 获取到summary
String name = hitDoc.get("signature");
// 获取到 signature
String signature = hitDoc.get("signature");
// 将查询的词和搜索词匹配匹配到添加前缀和后缀
TokenStream tokenStream =
TokenSources.getAnyTokenStream(searcher.getIndexReader(), id, "signature", analyzer);
TokenStream tokenStream = TokenSources.getTokenStream("signature", searcher.getIndexReader().getTermVectors(id), signature, analyzer, -1);
// 传入的第二个参数是查询的值
TextFragment[] frag = highlighter.getBestTextFragments(tokenStream, name, false, 10);
TextFragment[] frag = highlighter.getBestTextFragments(tokenStream, signature, false, 10);
StringBuilder baikeValue = new StringBuilder();
for (TextFragment textFragment : frag) {
if ((textFragment != null) && (textFragment.getScore() > 0)) {
@ -148,12 +148,11 @@ public class UserLuceneServiceImpl implements UserLuceneService {
baikeValue.append(textFragment.toString());
}
}
// 获取到title
String title = hitDoc.get("nickname");
TokenStream titleTokenStream =
TokenSources.getAnyTokenStream(searcher.getIndexReader(), id, "nickname", analyzer);
// 获取到 nickname
String nickname = hitDoc.get("nickname");
TokenStream titleTokenStream = TokenSources.getTokenStream("nickname", searcher.getIndexReader().getTermVectors(id), nickname, analyzer, -1);
TextFragment[] titleFrag =
highlighter.getBestTextFragments(titleTokenStream, title, false, 10);
highlighter.getBestTextFragments(titleTokenStream, nickname, false, 10);
StringBuilder titleValue = new StringBuilder();
for (int j = 0; j < titleFrag.length; j++) {
if ((frag[j] != null)) {
@ -162,7 +161,7 @@ public class UserLuceneServiceImpl implements UserLuceneService {
}
resList.add(
UserLucene.builder()
.idUser(Integer.valueOf(hitDoc.get("id")))
.idUser(Long.valueOf(hitDoc.get("id")))
.nickname(titleValue.toString())
.signature(baikeValue.toString())
.score(String.valueOf(score))
@ -183,7 +182,7 @@ public class UserLuceneServiceImpl implements UserLuceneService {
}
@Override
public List<UserDTO> getUsersByIds(Integer[] ids) {
public List<UserDTO> getUsersByIds(Long[] ids) {
return userLuceneMapper.getUsersByIds(ids);
}
}

Some files were not shown because too many files have changed in this diff Show More