style: 代码格式化

This commit is contained in:
xiongxiaoyang 2022-06-30 21:34:54 +08:00
parent 6d2fa74237
commit 9b93d90270
67 changed files with 1293 additions and 620 deletions

6
doc/sql/README.md Normal file
View File

@ -0,0 +1,6 @@
1. 初始状态下MySQL 只需要执行 `novel.sql` 文件即可正常运行本系统
2. 代码更新后再执行以日期命名的增量 SQL 文件
3. 只有开启 XXL-JOB 的功能,才需要执行 `xxl-job.sql` 和以 xxl-job 开头日期结尾的增量 SQL 文件
4. 只有开启 ShardingSphere-JDBC 的功能,才需要执行 `shardingsphere-jdbc.sql` 和以 shardingsphere-jdbc 开头日期结尾的增量 SQL
文件

View File

@ -1,5 +0,0 @@
1. 初始状态下MYSQL 只需要执行 novel.sql 文件即可正常运行本系统
2. 代码更新后再执行以日期命名的增量 SQL 文件
3. 只有开启 XXL-JOB 的功能,才需要执行 xxl-job.sql 和以 xxl-job 开头日期结尾的增量 SQL 文件
4. 只有开启 ShardingSphere-JDBC 的功能,才需要执行 shardingsphere-jdbc.sql 和以 shardingsphere-jdbc 开头日期结尾的增量 SQL 文件

3
doc/style/README.md Normal file
View File

@ -0,0 +1,3 @@
IntelliJ IDEA 中导入 `intellij-java-google-style.xml` 文件:
`Preferences` => `Editor` => `Code Style` => `Java` => `Schema` => `Import Schema`

View File

@ -0,0 +1,598 @@
<?xml version="1.0" encoding="UTF-8"?>
<code_scheme name="GoogleStyle">
<option name="OTHER_INDENT_OPTIONS">
<value>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="2" />
<option name="USE_TAB_CHARACTER" value="false" />
<option name="SMART_TABS" value="false" />
<option name="LABEL_INDENT_SIZE" value="0" />
<option name="LABEL_INDENT_ABSOLUTE" value="false" />
<option name="USE_RELATIVE_INDENTS" value="false" />
</value>
</option>
<option name="INSERT_INNER_CLASS_IMPORTS" value="true" />
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="999" />
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="999" />
<option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
<value />
</option>
<option name="IMPORT_LAYOUT_TABLE">
<value>
<package name="" withSubpackages="true" static="true" />
<emptyLine />
<package name="" withSubpackages="true" static="false" />
</value>
</option>
<option name="RIGHT_MARGIN" value="100" />
<option name="JD_ALIGN_PARAM_COMMENTS" value="false" />
<option name="JD_ALIGN_EXCEPTION_COMMENTS" value="false" />
<option name="JD_P_AT_EMPTY_LINES" value="false" />
<option name="JD_KEEP_EMPTY_PARAMETER" value="false" />
<option name="JD_KEEP_EMPTY_EXCEPTION" value="false" />
<option name="JD_KEEP_EMPTY_RETURN" value="false" />
<option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" />
<option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="0" />
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
<option name="BLANK_LINES_AFTER_CLASS_HEADER" value="0" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="ALIGN_MULTILINE_FOR" value="false" />
<option name="CALL_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_WRAP" value="1" />
<option name="EXTENDS_LIST_WRAP" value="1" />
<option name="THROWS_KEYWORD_WRAP" value="1" />
<option name="METHOD_CALL_CHAIN_WRAP" value="1" />
<option name="BINARY_OPERATION_WRAP" value="1" />
<option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
<option name="TERNARY_OPERATION_WRAP" value="1" />
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
<option name="FOR_STATEMENT_WRAP" value="1" />
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
<option name="WRAP_COMMENTS" value="true" />
<option name="IF_BRACE_FORCE" value="3" />
<option name="DOWHILE_BRACE_FORCE" value="3" />
<option name="WHILE_BRACE_FORCE" value="3" />
<option name="FOR_BRACE_FORCE" value="3" />
<option name="SPACE_BEFORE_ARRAY_INITIALIZER_LBRACE" value="true" />
<AndroidXmlCodeStyleSettings>
<option name="USE_CUSTOM_SETTINGS" value="true" />
<option name="LAYOUT_SETTINGS">
<value>
<option name="INSERT_BLANK_LINE_BEFORE_TAG" value="false" />
</value>
</option>
</AndroidXmlCodeStyleSettings>
<JSCodeStyleSettings>
<option name="INDENT_CHAINED_CALLS" value="false" />
</JSCodeStyleSettings>
<Python>
<option name="USE_CONTINUATION_INDENT_FOR_ARGUMENTS" value="true" />
</Python>
<TypeScriptCodeStyleSettings>
<option name="INDENT_CHAINED_CALLS" value="false" />
</TypeScriptCodeStyleSettings>
<XML>
<option name="XML_ALIGN_ATTRIBUTES" value="false" />
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
</XML>
<codeStyleSettings language="CSS">
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="ECMA Script Level 4">
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="ALIGN_MULTILINE_FOR" value="false" />
<option name="CALL_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_WRAP" value="1" />
<option name="EXTENDS_LIST_WRAP" value="1" />
<option name="BINARY_OPERATION_WRAP" value="1" />
<option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
<option name="TERNARY_OPERATION_WRAP" value="1" />
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
<option name="FOR_STATEMENT_WRAP" value="1" />
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
<option name="IF_BRACE_FORCE" value="3" />
<option name="DOWHILE_BRACE_FORCE" value="3" />
<option name="WHILE_BRACE_FORCE" value="3" />
<option name="FOR_BRACE_FORCE" value="3" />
<option name="PARENT_SETTINGS_INSTALLED" value="true" />
</codeStyleSettings>
<codeStyleSettings language="HTML">
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="JAVA">
<option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" />
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
<option name="BLANK_LINES_AFTER_CLASS_HEADER" value="1" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="ALIGN_MULTILINE_RESOURCES" value="false" />
<option name="ALIGN_MULTILINE_FOR" value="false" />
<option name="CALL_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_WRAP" value="1" />
<option name="EXTENDS_LIST_WRAP" value="1" />
<option name="THROWS_KEYWORD_WRAP" value="1" />
<option name="METHOD_CALL_CHAIN_WRAP" value="1" />
<option name="BINARY_OPERATION_WRAP" value="1" />
<option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
<option name="TERNARY_OPERATION_WRAP" value="1" />
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
<option name="FOR_STATEMENT_WRAP" value="1" />
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
<option name="WRAP_COMMENTS" value="true" />
<option name="IF_BRACE_FORCE" value="3" />
<option name="DOWHILE_BRACE_FORCE" value="3" />
<option name="WHILE_BRACE_FORCE" value="3" />
<option name="FOR_BRACE_FORCE" value="3" />
<option name="PARENT_SETTINGS_INSTALLED" value="true" />
<indentOptions>
<option name="INDENT_SIZE" value="4" />
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="4" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="JSON">
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="JavaScript">
<option name="RIGHT_MARGIN" value="80" />
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="ALIGN_MULTILINE_FOR" value="false" />
<option name="CALL_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_WRAP" value="1" />
<option name="BINARY_OPERATION_WRAP" value="1" />
<option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
<option name="TERNARY_OPERATION_WRAP" value="1" />
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
<option name="FOR_STATEMENT_WRAP" value="1" />
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
<option name="IF_BRACE_FORCE" value="3" />
<option name="DOWHILE_BRACE_FORCE" value="3" />
<option name="WHILE_BRACE_FORCE" value="3" />
<option name="FOR_BRACE_FORCE" value="3" />
<option name="PARENT_SETTINGS_INSTALLED" value="true" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="PROTO">
<option name="RIGHT_MARGIN" value="80" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="protobuf">
<option name="RIGHT_MARGIN" value="80" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="Python">
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
<option name="RIGHT_MARGIN" value="80" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="PARENT_SETTINGS_INSTALLED" value="true" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="SASS">
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="SCSS">
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="TypeScript">
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="XML">
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
<arrangement>
<rules>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:id</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>style</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:.*Style</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_width</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_height</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_weight</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_margin</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_marginTop</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_marginBottom</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_marginStart</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_marginEnd</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_marginLeft</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_marginRight</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:padding</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:paddingTop</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:paddingBottom</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:paddingStart</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:paddingEnd</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:paddingLeft</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:paddingRight</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res-auto</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>http://schemas.android.com/tools</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
<Objective-C>
<option name="INDENT_NAMESPACE_MEMBERS" value="0" />
<option name="INDENT_C_STRUCT_MEMBERS" value="2" />
<option name="INDENT_CLASS_MEMBERS" value="2" />
<option name="INDENT_VISIBILITY_KEYWORDS" value="1" />
<option name="INDENT_INSIDE_CODE_BLOCK" value="2" />
<option name="KEEP_STRUCTURES_IN_ONE_LINE" value="true" />
<option name="FUNCTION_PARAMETERS_WRAP" value="5" />
<option name="FUNCTION_CALL_ARGUMENTS_WRAP" value="5" />
<option name="TEMPLATE_CALL_ARGUMENTS_WRAP" value="5" />
<option name="TEMPLATE_CALL_ARGUMENTS_ALIGN_MULTILINE" value="true" />
<option name="ALIGN_INIT_LIST_IN_COLUMNS" value="false" />
<option name="SPACE_BEFORE_SUPERCLASS_COLON" value="false" />
</Objective-C>
<Objective-C-extensions>
<option name="GENERATE_INSTANCE_VARIABLES_FOR_PROPERTIES" value="ASK" />
<option name="RELEASE_STYLE" value="IVAR" />
<option name="TYPE_QUALIFIERS_PLACEMENT" value="BEFORE" />
<file>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
</file>
<class>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
</class>
<extensions>
<pair source="cc" header="h" />
<pair source="c" header="h" />
</extensions>
</Objective-C-extensions>
<codeStyleSettings language="ObjectiveC">
<option name="RIGHT_MARGIN" value="80" />
<option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="1" />
<option name="BLANK_LINES_BEFORE_IMPORTS" value="0" />
<option name="BLANK_LINES_AFTER_IMPORTS" value="0" />
<option name="BLANK_LINES_AROUND_CLASS" value="0" />
<option name="BLANK_LINES_AROUND_METHOD" value="0" />
<option name="BLANK_LINES_AROUND_METHOD_IN_INTERFACE" value="0" />
<option name="ALIGN_MULTILINE_BINARY_OPERATION" value="false" />
<option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
<option name="FOR_STATEMENT_WRAP" value="1" />
<option name="ASSIGNMENT_WRAP" value="1" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
</codeStyleSettings>
</code_scheme>

View File

@ -7,6 +7,7 @@ import io.swagger.v3.oas.annotations.enums.SecuritySchemeType;
import io.swagger.v3.oas.annotations.info.Info; import io.swagger.v3.oas.annotations.info.Info;
import io.swagger.v3.oas.annotations.info.License; import io.swagger.v3.oas.annotations.info.License;
import io.swagger.v3.oas.annotations.security.SecurityScheme; import io.swagger.v3.oas.annotations.security.SecurityScheme;
import java.util.Map;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.annotation.MapperScan; import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.CommandLineRunner; import org.springframework.boot.CommandLineRunner;
@ -21,8 +22,6 @@ import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.SecurityFilterChain;
import java.util.Map;
@OpenAPIDefinition(info = @Info(title = "novel 项目接口文档", version = "v3.2.0", license = @License(name = "Apache 2.0", url = "https://www.apache.org/licenses/LICENSE-2.0"))) @OpenAPIDefinition(info = @Info(title = "novel 项目接口文档", version = "v3.2.0", license = @License(name = "Apache 2.0", url = "https://www.apache.org/licenses/LICENSE-2.0")))
@SecurityScheme(type = SecuritySchemeType.APIKEY, in = SecuritySchemeIn.HEADER, name = SystemConfigConsts.HTTP_AUTH_HEADER_NAME, description = "登录 token") @SecurityScheme(type = SecuritySchemeType.APIKEY, in = SecuritySchemeIn.HEADER, name = SystemConfigConsts.HTTP_AUTH_HEADER_NAME, description = "登录 token")
@SpringBootApplication @SpringBootApplication

View File

@ -20,7 +20,12 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springdoc.core.annotations.ParameterObject; import org.springdoc.core.annotations.ParameterObject;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/** /**
* 作家后台-作家模块 API 控制器 * 作家后台-作家模块 API 控制器
@ -81,7 +86,9 @@ public class AuthorController {
*/ */
@Operation(summary = "小说章节发布接口") @Operation(summary = "小说章节发布接口")
@PostMapping("book/chapter/{bookId}") @PostMapping("book/chapter/{bookId}")
public RestResp<Void> publishBookChapter(@Parameter(description = "小说ID") @PathVariable("bookId") Long bookId, @Valid @RequestBody ChapterAddReqDto dto) { public RestResp<Void> publishBookChapter(
@Parameter(description = "小说ID") @PathVariable("bookId") Long bookId,
@Valid @RequestBody ChapterAddReqDto dto) {
dto.setBookId(bookId); dto.setBookId(bookId);
return bookService.saveBookChapter(dto); return bookService.saveBookChapter(dto);
} }
@ -91,7 +98,9 @@ public class AuthorController {
*/ */
@Operation(summary = "小说章节发布列表查询接口") @Operation(summary = "小说章节发布列表查询接口")
@GetMapping("book/chapters/{bookId}") @GetMapping("book/chapters/{bookId}")
public RestResp<PageRespDto<BookChapterRespDto>> listBookChapters(@Parameter(description = "小说ID") @PathVariable("bookId") Long bookId,@ParameterObject PageReqDto dto) { public RestResp<PageRespDto<BookChapterRespDto>> listBookChapters(
@Parameter(description = "小说ID") @PathVariable("bookId") Long bookId,
@ParameterObject PageReqDto dto) {
return bookService.listBookChapters(bookId, dto); return bookService.listBookChapters(bookId, dto);
} }

View File

@ -2,16 +2,25 @@ package io.github.xxyopen.novel.controller.front;
import io.github.xxyopen.novel.core.common.resp.RestResp; import io.github.xxyopen.novel.core.common.resp.RestResp;
import io.github.xxyopen.novel.core.constant.ApiRouterConsts; import io.github.xxyopen.novel.core.constant.ApiRouterConsts;
import io.github.xxyopen.novel.dto.resp.*; import io.github.xxyopen.novel.dto.resp.BookCategoryRespDto;
import io.github.xxyopen.novel.dto.resp.BookChapterAboutRespDto;
import io.github.xxyopen.novel.dto.resp.BookChapterRespDto;
import io.github.xxyopen.novel.dto.resp.BookCommentRespDto;
import io.github.xxyopen.novel.dto.resp.BookContentAboutRespDto;
import io.github.xxyopen.novel.dto.resp.BookInfoRespDto;
import io.github.xxyopen.novel.dto.resp.BookRankRespDto;
import io.github.xxyopen.novel.service.BookService; import io.github.xxyopen.novel.service.BookService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.List; import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/** /**
* 前台门户-小说模块 API 控制器 * 前台门户-小说模块 API 控制器
@ -32,7 +41,8 @@ public class BookController {
*/ */
@Operation(summary = "小说分类列表查询接口") @Operation(summary = "小说分类列表查询接口")
@GetMapping("category/list") @GetMapping("category/list")
public RestResp<List<BookCategoryRespDto>> listCategory(@Parameter(description = "作品方向",required = true) Integer workDirection) { public RestResp<List<BookCategoryRespDto>> listCategory(
@Parameter(description = "作品方向", required = true) Integer workDirection) {
return bookService.listCategory(workDirection); return bookService.listCategory(workDirection);
} }
@ -41,7 +51,8 @@ public class BookController {
*/ */
@Operation(summary = "小说信息查询接口") @Operation(summary = "小说信息查询接口")
@GetMapping("{id}") @GetMapping("{id}")
public RestResp<BookInfoRespDto> getBookById(@Parameter(description = "小说 ID") @PathVariable("id") Long bookId) { public RestResp<BookInfoRespDto> getBookById(
@Parameter(description = "小说 ID") @PathVariable("id") Long bookId) {
return bookService.getBookById(bookId); return bookService.getBookById(bookId);
} }
@ -59,7 +70,8 @@ public class BookController {
*/ */
@Operation(summary = "小说最新章节相关信息查询接口") @Operation(summary = "小说最新章节相关信息查询接口")
@GetMapping("last_chapter/about") @GetMapping("last_chapter/about")
public RestResp<BookChapterAboutRespDto> getLastChapterAbout(@Parameter(description = "小说ID") Long bookId) { public RestResp<BookChapterAboutRespDto> getLastChapterAbout(
@Parameter(description = "小说ID") Long bookId) {
return bookService.getLastChapterAbout(bookId); return bookService.getLastChapterAbout(bookId);
} }
@ -68,7 +80,8 @@ public class BookController {
*/ */
@Operation(summary = "小说推荐列表查询接口") @Operation(summary = "小说推荐列表查询接口")
@GetMapping("rec_list") @GetMapping("rec_list")
public RestResp<List<BookInfoRespDto>> listRecBooks(@Parameter(description = "小说ID") Long bookId) throws NoSuchAlgorithmException { public RestResp<List<BookInfoRespDto>> listRecBooks(
@Parameter(description = "小说ID") Long bookId) throws NoSuchAlgorithmException {
return bookService.listRecBooks(bookId); return bookService.listRecBooks(bookId);
} }
@ -77,7 +90,8 @@ public class BookController {
*/ */
@Operation(summary = "小说章节列表查询接口") @Operation(summary = "小说章节列表查询接口")
@GetMapping("chapter/list") @GetMapping("chapter/list")
public RestResp<List<BookChapterRespDto>> listChapters(@Parameter(description = "小说ID") Long bookId) { public RestResp<List<BookChapterRespDto>> listChapters(
@Parameter(description = "小说ID") Long bookId) {
return bookService.listChapters(bookId); return bookService.listChapters(bookId);
} }
@ -86,7 +100,8 @@ public class BookController {
*/ */
@Operation(summary = "小说内容相关信息查询接口") @Operation(summary = "小说内容相关信息查询接口")
@GetMapping("content/{chapterId}") @GetMapping("content/{chapterId}")
public RestResp<BookContentAboutRespDto> getBookContentAbout(@Parameter(description = "章节ID") @PathVariable("chapterId") Long chapterId) { public RestResp<BookContentAboutRespDto> getBookContentAbout(
@Parameter(description = "章节ID") @PathVariable("chapterId") Long chapterId) {
return bookService.getBookContentAbout(chapterId); return bookService.getBookContentAbout(chapterId);
} }
@ -95,7 +110,8 @@ public class BookController {
*/ */
@Operation(summary = "获取上一章节ID接口") @Operation(summary = "获取上一章节ID接口")
@GetMapping("pre_chapter_id/{chapterId}") @GetMapping("pre_chapter_id/{chapterId}")
public RestResp<Long> getPreChapterId(@Parameter(description = "章节ID") @PathVariable("chapterId") Long chapterId) { public RestResp<Long> getPreChapterId(
@Parameter(description = "章节ID") @PathVariable("chapterId") Long chapterId) {
return bookService.getPreChapterId(chapterId); return bookService.getPreChapterId(chapterId);
} }
@ -104,7 +120,8 @@ public class BookController {
*/ */
@Operation(summary = "获取下一章节ID接口") @Operation(summary = "获取下一章节ID接口")
@GetMapping("next_chapter_id/{chapterId}") @GetMapping("next_chapter_id/{chapterId}")
public RestResp<Long> getNextChapterId(@Parameter(description = "章节ID") @PathVariable("chapterId") Long chapterId) { public RestResp<Long> getNextChapterId(
@Parameter(description = "章节ID") @PathVariable("chapterId") Long chapterId) {
return bookService.getNextChapterId(chapterId); return bookService.getNextChapterId(chapterId);
} }
@ -140,7 +157,8 @@ public class BookController {
*/ */
@Operation(summary = "小说最新评论查询接口") @Operation(summary = "小说最新评论查询接口")
@GetMapping("comment/newest_list") @GetMapping("comment/newest_list")
public RestResp<BookCommentRespDto> listNewestComments(@Parameter(description = "小说ID") Long bookId) { public RestResp<BookCommentRespDto> listNewestComments(
@Parameter(description = "小说ID") Long bookId) {
return bookService.listNewestComments(bookId); return bookService.listNewestComments(bookId);
} }

View File

@ -1,20 +1,19 @@
package io.github.xxyopen.novel.controller.front; package io.github.xxyopen.novel.controller.front;
import io.github.xxyopen.novel.core.constant.ApiRouterConsts;
import io.github.xxyopen.novel.core.common.resp.RestResp; import io.github.xxyopen.novel.core.common.resp.RestResp;
import io.github.xxyopen.novel.core.constant.ApiRouterConsts;
import io.github.xxyopen.novel.dto.resp.NewsInfoRespDto; import io.github.xxyopen.novel.dto.resp.NewsInfoRespDto;
import io.github.xxyopen.novel.service.NewsService; import io.github.xxyopen.novel.service.NewsService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/** /**
* 前台门户-新闻模块 API 控制器 * 前台门户-新闻模块 API 控制器
* *
@ -43,7 +42,8 @@ public class NewsController {
*/ */
@Operation(summary = "新闻信息查询接口") @Operation(summary = "新闻信息查询接口")
@GetMapping("{id}") @GetMapping("{id}")
public RestResp<NewsInfoRespDto> getNews(@Parameter(description = "新闻ID") @PathVariable Long id) { public RestResp<NewsInfoRespDto> getNews(
@Parameter(description = "新闻ID") @PathVariable Long id) {
return newsService.getNews(id); return newsService.getNews(id);
} }
} }

View File

@ -7,11 +7,14 @@ import io.github.xxyopen.novel.service.ResourceService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException; import java.io.IOException;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
/** /**
* 前台门户-资源(图片/视频/文档)模块 API 控制器 * 前台门户-资源(图片/视频/文档)模块 API 控制器
@ -38,10 +41,11 @@ public class ResourceController {
/** /**
* 图片上传接口 * 图片上传接口
* */ */
@Operation(summary = "图片上传接口") @Operation(summary = "图片上传接口")
@PostMapping("/image") @PostMapping("/image")
RestResp<String> uploadImage(@Parameter(description = "上传文件") @RequestParam("file") MultipartFile file) { RestResp<String> uploadImage(
@Parameter(description = "上传文件") @RequestParam("file") MultipartFile file) {
return resourceService.uploadImage(file); return resourceService.uploadImage(file);
} }

View File

@ -33,7 +33,8 @@ public class SearchController {
*/ */
@Operation(summary = "小说搜索接口") @Operation(summary = "小说搜索接口")
@GetMapping("books") @GetMapping("books")
public RestResp<PageRespDto<BookInfoRespDto>> searchBooks(@ParameterObject BookSearchReqDto condition) { public RestResp<PageRespDto<BookInfoRespDto>> searchBooks(
@ParameterObject BookSearchReqDto condition) {
return searchService.searchBooks(condition); return searchService.searchBooks(condition);
} }

View File

@ -19,7 +19,14 @@ import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/** /**
* 前台门户-会员模块 API 控制器 * 前台门户-会员模块 API 控制器
@ -108,7 +115,8 @@ public class UserController {
*/ */
@Operation(summary = "修改评论接口") @Operation(summary = "修改评论接口")
@PutMapping("comment/{id}") @PutMapping("comment/{id}")
public RestResp<Void> updateComment(@Parameter(description = "评论ID") @PathVariable Long id, String content) { public RestResp<Void> updateComment(@Parameter(description = "评论ID") @PathVariable Long id,
String content) {
return bookService.updateComment(UserHolder.getUserId(), id, content); return bookService.updateComment(UserHolder.getUserId(), id, content);
} }
@ -122,9 +130,7 @@ public class UserController {
} }
/** /**
* 查询书架状态接口 * 查询书架状态接口 0-不在书架 1-已在书架
* 0-不在书架
* 1-已在书架
*/ */
@Operation(summary = "查询书架状态接口") @Operation(summary = "查询书架状态接口")
@GetMapping("bookshelf_status") @GetMapping("bookshelf_status")

View File

@ -1,12 +1,12 @@
package io.github.xxyopen.novel.core.annotation; package io.github.xxyopen.novel.core.annotation;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Documented; import java.lang.annotation.Documented;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/** /**
* 分布式锁-Key 注解 * 分布式锁-Key 注解
* *
@ -17,5 +17,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Retention(RUNTIME) @Retention(RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER}) @Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
public @interface Key { public @interface Key {
String expr() default ""; String expr() default "";
} }

View File

@ -3,6 +3,9 @@ package io.github.xxyopen.novel.core.aspect;
import io.github.xxyopen.novel.core.annotation.Key; import io.github.xxyopen.novel.core.annotation.Key;
import io.github.xxyopen.novel.core.annotation.Lock; import io.github.xxyopen.novel.core.annotation.Lock;
import io.github.xxyopen.novel.core.common.exception.BusinessException; import io.github.xxyopen.novel.core.common.exception.BusinessException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.concurrent.TimeUnit;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Around;
@ -17,10 +20,6 @@ import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.concurrent.TimeUnit;
/** /**
* 分布式锁 切面 * 分布式锁 切面
* *

View File

@ -6,9 +6,8 @@ import io.github.xxyopen.novel.core.constant.SystemConfigConsts;
import io.github.xxyopen.novel.core.util.JwtUtils; import io.github.xxyopen.novel.core.util.JwtUtils;
import io.github.xxyopen.novel.dto.UserInfoDto; import io.github.xxyopen.novel.dto.UserInfoDto;
import io.github.xxyopen.novel.manager.cache.UserInfoCacheManager; import io.github.xxyopen.novel.manager.cache.UserInfoCacheManager;
import org.springframework.util.StringUtils;
import java.util.Objects; import java.util.Objects;
import org.springframework.util.StringUtils;
/** /**
* 策略模式实现用户认证授权功能 * 策略模式实现用户认证授权功能
@ -35,7 +34,8 @@ public interface AuthStrategy {
* @param token token 登录 token * @param token token 登录 token
* @return 用户ID * @return 用户ID
*/ */
default Long authSSO(JwtUtils jwtUtils, UserInfoCacheManager userInfoCacheManager, String token) { default Long authSSO(JwtUtils jwtUtils, UserInfoCacheManager userInfoCacheManager,
String token) {
if (!StringUtils.hasText(token)) { if (!StringUtils.hasText(token)) {
// token 为空 // token 为空
throw new BusinessException(ErrorCodeEnum.USER_LOGIN_EXPIRED); throw new BusinessException(ErrorCodeEnum.USER_LOGIN_EXPIRED);

View File

@ -7,11 +7,10 @@ import io.github.xxyopen.novel.core.util.JwtUtils;
import io.github.xxyopen.novel.dto.AuthorInfoDto; import io.github.xxyopen.novel.dto.AuthorInfoDto;
import io.github.xxyopen.novel.manager.cache.AuthorInfoCacheManager; import io.github.xxyopen.novel.manager.cache.AuthorInfoCacheManager;
import io.github.xxyopen.novel.manager.cache.UserInfoCacheManager; import io.github.xxyopen.novel.manager.cache.UserInfoCacheManager;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
/** /**
* 作家后台管理系统 认证策略 * 作家后台管理系统 认证策略
@ -31,17 +30,17 @@ public class AuthorAuthStrategy implements AuthStrategy {
/** /**
* 不需要进行作家权限认证的 URI * 不需要进行作家权限认证的 URI
* */ */
private static final List<String> EXCLUDE_URI = List.of( private static final List<String> EXCLUDE_URI = List.of(
ApiRouterConsts.API_AUTHOR_URL_PREFIX + "/register", ApiRouterConsts.API_AUTHOR_URL_PREFIX + "/register",
ApiRouterConsts.API_AUTHOR_URL_PREFIX +"/status" ApiRouterConsts.API_AUTHOR_URL_PREFIX + "/status"
); );
@Override @Override
public void auth(String token, String requestUri) throws BusinessException { public void auth(String token, String requestUri) throws BusinessException {
// 统一账号认证 // 统一账号认证
Long userId = authSSO(jwtUtils, userInfoCacheManager, token); Long userId = authSSO(jwtUtils, userInfoCacheManager, token);
if(EXCLUDE_URI.contains(requestUri)){ if (EXCLUDE_URI.contains(requestUri)) {
// 该请求不需要进行作家权限认证 // 该请求不需要进行作家权限认证
return; return;
} }

View File

@ -23,6 +23,6 @@ public class FrontAuthStrategy implements AuthStrategy {
@Override @Override
public void auth(String token, String requestUri) throws BusinessException { public void auth(String token, String requestUri) throws BusinessException {
// 统一账号认证 // 统一账号认证
authSSO(jwtUtils,userInfoCacheManager,token); authSSO(jwtUtils, userInfoCacheManager, token);
} }
} }

View File

@ -13,12 +13,12 @@ public class UserHolder {
/** /**
* 当前线程用户ID * 当前线程用户ID
* */ */
private static final ThreadLocal<Long> userIdTL = new ThreadLocal<>(); private static final ThreadLocal<Long> userIdTL = new ThreadLocal<>();
/** /**
* 当前线程作家ID * 当前线程作家ID
* */ */
private static final ThreadLocal<Long> authorIdTL = new ThreadLocal<>(); private static final ThreadLocal<Long> authorIdTL = new ThreadLocal<>();
public void setUserId(Long userId) { public void setUserId(Long userId) {
@ -37,7 +37,7 @@ public class UserHolder {
return authorIdTL.get(); return authorIdTL.get();
} }
public void clear(){ public void clear() {
userIdTL.remove(); userIdTL.remove();
authorIdTL.remove(); authorIdTL.remove();
} }

View File

@ -11,33 +11,33 @@ public class CommonConsts {
/** /**
* *
* */ */
public static final Integer YES = 1; public static final Integer YES = 1;
public static final String TRUE = "true"; public static final String TRUE = "true";
/** /**
* *
* */ */
public static final Integer NO = 0; public static final Integer NO = 0;
public static final String FALSE = "false"; public static final String FALSE = "false";
/** /**
* 性别常量 * 性别常量
* */ */
public enum SexEnum{ public enum SexEnum {
/** /**
* *
* */ */
MALE(0,""), MALE(0, ""),
/** /**
* *
* */ */
FEMALE(1,""); FEMALE(1, "");
SexEnum(int code,String desc){ SexEnum(int code, String desc) {
this.code = code; this.code = code;
this.desc = desc; this.desc = desc;
} }

View File

@ -5,15 +5,12 @@ import lombok.Getter;
/** /**
* 错误码枚举类 * 错误码枚举类
* * <p>
* 错误码为字符串类型 5 分成两个部分错误产生来源+四位数字编号 * 错误码为字符串类型 5 分成两个部分错误产生来源+四位数字编号 错误产生来源分为 A/B/C A 表示错误来源于用户比如参数错误用户安装版本过低用户支付 超时等问题 B
* 错误产生来源分为 A/B/C A 表示错误来源于用户比如参数错误用户安装版本过低用户支付 * 表示错误来源于当前系统往往是业务逻辑出错或程序健壮性差等问题 C 表示错误来源 于第三方服务比如 CDN 服务出错消息投递超时等问题四位数字编号从 0001 9999大类之间的
* 超时等问题 B 表示错误来源于当前系统往往是业务逻辑出错或程序健壮性差等问题 C 表示错误来源
* 于第三方服务比如 CDN 服务出错消息投递超时等问题四位数字编号从 0001 9999大类之间的
* 步长间距预留 100 * 步长间距预留 100
* * <p>
* 错误码分为一级宏观错误码二级宏观错误码三级宏观错误码 * 错误码分为一级宏观错误码二级宏观错误码三级宏观错误码 在无法更加具体确定的错误场景中可以直接使用一级宏观错误码
* 在无法更加具体确定的错误场景中可以直接使用一级宏观错误码
* *
* @author xiongxiaoyang * @author xiongxiaoyang
* @date 2022/5/11 * @date 2022/5/11
@ -24,134 +21,132 @@ public enum ErrorCodeEnum {
/** /**
* 正确执行后的返回 * 正确执行后的返回
* */ */
OK("00000","一切 ok"), OK("00000", "一切 ok"),
/** /**
* 一级宏观错误码用户端错误 * 一级宏观错误码用户端错误
* */ */
USER_ERROR("A0001","用户端错误"), USER_ERROR("A0001", "用户端错误"),
/** /**
* 二级宏观错误码用户注册错误 * 二级宏观错误码用户注册错误
* */ */
USER_REGISTER_ERROR("A0100","用户注册错误"), USER_REGISTER_ERROR("A0100", "用户注册错误"),
/** /**
* 用户未同意隐私协议 * 用户未同意隐私协议
* */ */
USER_NO_AGREE_PRIVATE_ERROR("A0101","用户未同意隐私协议"), USER_NO_AGREE_PRIVATE_ERROR("A0101", "用户未同意隐私协议"),
/** /**
* 注册国家或地区受限 * 注册国家或地区受限
* */ */
USER_REGISTER_AREA_LIMIT_ERROR("A0102","注册国家或地区受限"), USER_REGISTER_AREA_LIMIT_ERROR("A0102", "注册国家或地区受限"),
/** /**
* 用户验证码错误 * 用户验证码错误
* */ */
USER_VERIFY_CODE_ERROR("A0240","用户验证码错误"), USER_VERIFY_CODE_ERROR("A0240", "用户验证码错误"),
/** /**
* 用户名已存在 * 用户名已存在
* */ */
USER_NAME_EXIST("A0111","用户名已存在"), USER_NAME_EXIST("A0111", "用户名已存在"),
/** /**
* 用户账号不存在 * 用户账号不存在
* */ */
USER_ACCOUNT_NOT_EXIST("A0201","用户账号不存在"), USER_ACCOUNT_NOT_EXIST("A0201", "用户账号不存在"),
/** /**
* 用户密码错误 * 用户密码错误
* */ */
USER_PASSWORD_ERROR("A0210","用户密码错误"), USER_PASSWORD_ERROR("A0210", "用户密码错误"),
/** /**
* 二级宏观错误码用户请求参数错误 * 二级宏观错误码用户请求参数错误
* */ */
USER_REQUEST_PARAM_ERROR("A0400","用户请求参数错误"), USER_REQUEST_PARAM_ERROR("A0400", "用户请求参数错误"),
/** /**
* 用户登录已过期 * 用户登录已过期
* */ */
USER_LOGIN_EXPIRED("A0230","用户登录已过期"), USER_LOGIN_EXPIRED("A0230", "用户登录已过期"),
/** /**
* 访问未授权 * 访问未授权
* */ */
USER_UN_AUTH("A0301","访问未授权"), USER_UN_AUTH("A0301", "访问未授权"),
/** /**
* 用户请求服务异常 * 用户请求服务异常
* */ */
USER_REQ_EXCEPTION("A0500","用户请求服务异常"), USER_REQ_EXCEPTION("A0500", "用户请求服务异常"),
/** /**
* 请求超出限制 * 请求超出限制
* */ */
USER_REQ_MANY("A0501","请求超出限制"), USER_REQ_MANY("A0501", "请求超出限制"),
/** /**
* 用户评论异常 * 用户评论异常
* */ */
USER_COMMENT("A2000","用户评论异常"), USER_COMMENT("A2000", "用户评论异常"),
/** /**
* 用户评论异常 * 用户评论异常
* */ */
USER_COMMENTED("A2001","用户已发表评论"), USER_COMMENTED("A2001", "用户已发表评论"),
/** /**
* 作家发布异常 * 作家发布异常
* */ */
AUTHOR_PUBLISH("A3000","作家发布异常"), AUTHOR_PUBLISH("A3000", "作家发布异常"),
/** /**
* 小说名已存在 * 小说名已存在
* */ */
AUTHOR_BOOK_NAME_EXIST("A3001","小说名已存在"), AUTHOR_BOOK_NAME_EXIST("A3001", "小说名已存在"),
/** /**
* 用户上传文件异常 * 用户上传文件异常
* */ */
USER_UPLOAD_FILE_ERROR("A0700","用户上传文件异常"), USER_UPLOAD_FILE_ERROR("A0700", "用户上传文件异常"),
/** /**
* 用户上传文件类型不匹配 * 用户上传文件类型不匹配
* */ */
USER_UPLOAD_FILE_TYPE_NOT_MATCH("A0701","用户上传文件类型不匹配"), USER_UPLOAD_FILE_TYPE_NOT_MATCH("A0701", "用户上传文件类型不匹配"),
/** /**
* 一级宏观错误码系统执行出错 * 一级宏观错误码系统执行出错
* */ */
SYSTEM_ERROR("B0001","系统执行出错"), SYSTEM_ERROR("B0001", "系统执行出错"),
/** /**
* 二级宏观错误码系统执行超时 * 二级宏观错误码系统执行超时
* */ */
SYSTEM_TIMEOUT_ERROR("B0100","系统执行超时"), SYSTEM_TIMEOUT_ERROR("B0100", "系统执行超时"),
/** /**
* 一级宏观错误码调用第三方服务出错 * 一级宏观错误码调用第三方服务出错
* */ */
THIRD_SERVICE_ERROR("C0001","调用第三方服务出错"), THIRD_SERVICE_ERROR("C0001", "调用第三方服务出错"),
/** /**
* 一级宏观错误码中间件服务出错 * 一级宏观错误码中间件服务出错
* */ */
MIDDLEWARE_SERVICE_ERROR("C0100","中间件服务出错") MIDDLEWARE_SERVICE_ERROR("C0100", "中间件服务出错");
;
/** /**
* 错误码 * 错误码
* */ */
private final String code; private final String code;
/** /**
* 中文描述 * 中文描述
* */ */
private final String message; private final String message;
} }

View File

@ -19,28 +19,28 @@ public class CommonExceptionHandler {
/** /**
* 处理数据校验异常 * 处理数据校验异常
* */ */
@ExceptionHandler(BindException.class) @ExceptionHandler(BindException.class)
public RestResp<Void> handlerBindException(BindException e){ public RestResp<Void> handlerBindException(BindException e) {
log.error(e.getMessage(),e); log.error(e.getMessage(), e);
return RestResp.fail(ErrorCodeEnum.USER_REQUEST_PARAM_ERROR); return RestResp.fail(ErrorCodeEnum.USER_REQUEST_PARAM_ERROR);
} }
/** /**
* 处理业务异常 * 处理业务异常
* */ */
@ExceptionHandler(BusinessException.class) @ExceptionHandler(BusinessException.class)
public RestResp<Void> handlerBusinessException(BusinessException e){ public RestResp<Void> handlerBusinessException(BusinessException e) {
log.error(e.getMessage(),e); log.error(e.getMessage(), e);
return RestResp.fail(e.getErrorCodeEnum()); return RestResp.fail(e.getErrorCodeEnum());
} }
/** /**
* 处理系统异常 * 处理系统异常
* */ */
@ExceptionHandler(Exception.class) @ExceptionHandler(Exception.class)
public RestResp<Void> handlerException(Exception e){ public RestResp<Void> handlerException(Exception e) {
log.error(e.getMessage(),e); log.error(e.getMessage(), e);
return RestResp.error(); return RestResp.error();
} }

View File

@ -14,20 +14,19 @@ public class PageReqDto {
/** /**
* 请求页码默认第 1 * 请求页码默认第 1
* */ */
@Parameter(description = "请求页码,默认第 1 页") @Parameter(description = "请求页码,默认第 1 页")
private int pageNum = 1; private int pageNum = 1;
/** /**
* 每页大小默认每页 10 * 每页大小默认每页 10
* */ */
@Parameter(description = "每页大小,默认每页 10 条") @Parameter(description = "每页大小,默认每页 10 条")
private int pageSize = 10; private int pageSize = 10;
/** /**
* 是否查询所有默认不查所有 * 是否查询所有默认不查所有 true pageNum pageSize 无效
* true pageNum pageSize 无效 */
* */
@Parameter(hidden = true) @Parameter(hidden = true)
private boolean fetchAll = false; private boolean fetchAll = false;

View File

@ -1,8 +1,7 @@
package io.github.xxyopen.novel.core.common.resp; package io.github.xxyopen.novel.core.common.resp;
import lombok.Getter;
import java.util.List; import java.util.List;
import lombok.Getter;
/** /**
* 分页响应数据格式封装 * 分页响应数据格式封装
@ -34,8 +33,7 @@ public class PageRespDto<T> {
private final List<? extends T> list; private final List<? extends T> list;
/** /**
* 该构造函数用于通用分页查询的场景 * 该构造函数用于通用分页查询的场景 接收普通分页数据和普通集合
* 接收普通分页数据和普通集合
*/ */
public PageRespDto(long pageNum, long pageSize, long total, List<T> list) { public PageRespDto(long pageNum, long pageSize, long total, List<T> list) {
this.pageNum = pageNum; this.pageNum = pageNum;
@ -50,7 +48,7 @@ public class PageRespDto<T> {
/** /**
* 获取分页数 * 获取分页数
* */ */
public long getPages() { public long getPages() {
if (this.pageSize == 0L) { if (this.pageSize == 0L) {
return 0L; return 0L;
@ -59,7 +57,6 @@ public class PageRespDto<T> {
if (this.total % this.pageSize != 0L) { if (this.total % this.pageSize != 0L) {
++pages; ++pages;
} }
return pages; return pages;
} }
} }

View File

@ -1,14 +1,15 @@
package io.github.xxyopen.novel.core.common.util; package io.github.xxyopen.novel.core.common.util;
import lombok.experimental.UtilityClass; import java.awt.Color;
import java.awt.Font;
import javax.imageio.ImageIO; import java.awt.Graphics;
import java.awt.*;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.Base64; import java.util.Base64;
import java.util.Random; import java.util.Random;
import javax.imageio.ImageIO;
import lombok.experimental.UtilityClass;
/** /**
* 图片验证码工具类 * 图片验证码工具类

View File

@ -16,6 +16,7 @@ public class IpUtils {
/** /**
* 获取真实IP * 获取真实IP
*
* @return 真实IP * @return 真实IP
*/ */
public String getRealIp(HttpServletRequest request) { public String getRealIp(HttpServletRequest request) {

View File

@ -2,6 +2,11 @@ package io.github.xxyopen.novel.core.config;
import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.Caffeine;
import io.github.xxyopen.novel.core.constant.CacheConsts; import io.github.xxyopen.novel.core.constant.CacheConsts;
import java.time.Duration;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.springframework.cache.CacheManager; import org.springframework.cache.CacheManager;
import org.springframework.cache.caffeine.CaffeineCache; import org.springframework.cache.caffeine.CaffeineCache;
import org.springframework.cache.support.SimpleCacheManager; import org.springframework.cache.support.SimpleCacheManager;
@ -13,12 +18,6 @@ import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter; import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.RedisConnectionFactory;
import java.time.Duration;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/** /**
* 缓存配置类 * 缓存配置类
* *
@ -40,7 +39,8 @@ public class CacheConfig {
// 类型推断 var 非常适合 for 循环JDK 10 引入JDK 11 改进 // 类型推断 var 非常适合 for 循环JDK 10 引入JDK 11 改进
for (var c : CacheConsts.CacheEnum.values()) { for (var c : CacheConsts.CacheEnum.values()) {
if (c.isLocal()) { if (c.isLocal()) {
Caffeine<Object, Object> caffeine = Caffeine.newBuilder().recordStats().maximumSize(c.getMaxSize()); Caffeine<Object, Object> caffeine = Caffeine.newBuilder().recordStats()
.maximumSize(c.getMaxSize());
if (c.getTtl() > 0) { if (c.getTtl() > 0) {
caffeine.expireAfterWrite(Duration.ofSeconds(c.getTtl())); caffeine.expireAfterWrite(Duration.ofSeconds(c.getTtl()));
} }
@ -57,26 +57,32 @@ public class CacheConfig {
*/ */
@Bean @Bean
public CacheManager redisCacheManager(RedisConnectionFactory connectionFactory) { public CacheManager redisCacheManager(RedisConnectionFactory connectionFactory) {
RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory); RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(
connectionFactory);
RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig() RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig()
.disableCachingNullValues().prefixCacheNameWith(CacheConsts.REDIS_CACHE_PREFIX); .disableCachingNullValues().prefixCacheNameWith(CacheConsts.REDIS_CACHE_PREFIX);
Map<String, RedisCacheConfiguration> cacheMap = new LinkedHashMap<>(CacheConsts.CacheEnum.values().length); Map<String, RedisCacheConfiguration> cacheMap = new LinkedHashMap<>(
CacheConsts.CacheEnum.values().length);
// 类型推断 var 非常适合 for 循环JDK 10 引入JDK 11 改进 // 类型推断 var 非常适合 for 循环JDK 10 引入JDK 11 改进
for (var c : CacheConsts.CacheEnum.values()) { for (var c : CacheConsts.CacheEnum.values()) {
if (c.isRemote()) { if (c.isRemote()) {
if (c.getTtl() > 0) { if (c.getTtl() > 0) {
cacheMap.put(c.getName(), RedisCacheConfiguration.defaultCacheConfig().disableCachingNullValues() cacheMap.put(c.getName(),
.prefixCacheNameWith(CacheConsts.REDIS_CACHE_PREFIX).entryTtl(Duration.ofSeconds(c.getTtl()))); RedisCacheConfiguration.defaultCacheConfig().disableCachingNullValues()
.prefixCacheNameWith(CacheConsts.REDIS_CACHE_PREFIX)
.entryTtl(Duration.ofSeconds(c.getTtl())));
} else { } else {
cacheMap.put(c.getName(), RedisCacheConfiguration.defaultCacheConfig().disableCachingNullValues() cacheMap.put(c.getName(),
RedisCacheConfiguration.defaultCacheConfig().disableCachingNullValues()
.prefixCacheNameWith(CacheConsts.REDIS_CACHE_PREFIX)); .prefixCacheNameWith(CacheConsts.REDIS_CACHE_PREFIX));
} }
} }
} }
RedisCacheManager redisCacheManager = new RedisCacheManager(redisCacheWriter, defaultCacheConfig, cacheMap); RedisCacheManager redisCacheManager = new RedisCacheManager(redisCacheWriter,
defaultCacheConfig, cacheMap);
redisCacheManager.setTransactionAware(true); redisCacheManager.setTransactionAware(true);
redisCacheManager.initializeCaches(); redisCacheManager.initializeCaches();
return redisCacheManager; return redisCacheManager;

View File

@ -37,7 +37,7 @@ public class CorsConfig {
UrlBasedCorsConfigurationSource configurationSource = new UrlBasedCorsConfigurationSource(); UrlBasedCorsConfigurationSource configurationSource = new UrlBasedCorsConfigurationSource();
// 添加映射路径拦截一切请求 // 添加映射路径拦截一切请求
configurationSource.registerCorsConfiguration("/**",config); configurationSource.registerCorsConfiguration("/**", config);
return new CorsFilter(configurationSource); return new CorsFilter(configurationSource);
} }

View File

@ -18,7 +18,7 @@ public class RedissonConfig {
@Bean @Bean
@SneakyThrows @SneakyThrows
public RedissonClient redissonClient(){ public RedissonClient redissonClient() {
Config config = Config.fromYAML(getClass().getResource("/redisson.yml")); Config config = Config.fromYAML(getClass().getResource("/redisson.yml"));
return Redisson.create(config); return Redisson.create(config);
} }

View File

@ -12,9 +12,8 @@ import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/** /**
* Spring Web Mvc 相关配置 * Spring Web Mvc 相关配置不要加 @EnableWebMvc 注解否则会导致 jackson 的全局配置失效因为 @EnableWebMvc 注解会导致
* 不要加 @EnableWebMvc 注解否则会导致 jackson 的全局配置失效 * WebMvcAutoConfiguration 自动配置失效
* 类上添加 @EnableWebMvc 会导致 WebMvcAutoConfiguration 中的自动配置全部失效
* *
* @author xiongxiaoyang * @author xiongxiaoyang
* @date 2022/5/18 * @date 2022/5/18

View File

@ -1,8 +1,7 @@
package io.github.xxyopen.novel.core.config; package io.github.xxyopen.novel.core.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.List; import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
/** /**
* Xss 过滤配置属性 * Xss 过滤配置属性
@ -11,6 +10,6 @@ import java.util.List;
* @date 2022/5/17 * @date 2022/5/17
*/ */
@ConfigurationProperties(prefix = "novel.xss") @ConfigurationProperties(prefix = "novel.xss")
public record XssProperties(Boolean enabled,List<String> excludes) { public record XssProperties(Boolean enabled, List<String> excludes) {
} }

View File

@ -10,22 +10,22 @@ public class AmqpConsts {
/** /**
* 小说信息改变 MQ * 小说信息改变 MQ
* */ */
public static class BookChangeMq{ public static class BookChangeMq {
/** /**
* 小说信息改变交换机 * 小说信息改变交换机
* */ */
public static final String EXCHANGE_NAME = "EXCHANGE-BOOK-CHANGE"; public static final String EXCHANGE_NAME = "EXCHANGE-BOOK-CHANGE";
/** /**
* Elasticsearch book 索引更新的队列 * Elasticsearch book 索引更新的队列
* */ */
public static final String QUEUE_ES_UPDATE = "QUEUE-ES-BOOK-UPDATE"; public static final String QUEUE_ES_UPDATE = "QUEUE-ES-BOOK-UPDATE";
/** /**
* Redis book 缓存更新的队列 * Redis book 缓存更新的队列
* */ */
public static final String QUEUE_REDIS_UPDATE = "QUEUE-REDIS-BOOK-UPDATE"; public static final String QUEUE_REDIS_UPDATE = "QUEUE-REDIS-BOOK-UPDATE";
} }

View File

@ -34,32 +34,32 @@ public class ApiRouterConsts {
/** /**
* 首页模块请求路径前缀 * 首页模块请求路径前缀
* */ */
public static final String HOME_URL_PREFIX = "/home"; public static final String HOME_URL_PREFIX = "/home";
/** /**
* 首页模块请求路径前缀 * 首页模块请求路径前缀
* */ */
public static final String NEWS_URL_PREFIX = "/news"; public static final String NEWS_URL_PREFIX = "/news";
/** /**
* 小说模块请求路径前缀 * 小说模块请求路径前缀
* */ */
public static final String BOOK_URL_PREFIX = "/book"; public static final String BOOK_URL_PREFIX = "/book";
/** /**
* 会员模块请求路径前缀 * 会员模块请求路径前缀
* */ */
public static final String USER_URL_PREFIX = "/user"; public static final String USER_URL_PREFIX = "/user";
/** /**
* 资源图片/视频/文档模块请求路径前缀 * 资源图片/视频/文档模块请求路径前缀
* */ */
public static final String RESOURCE_URL_PREFIX = "/resource"; public static final String RESOURCE_URL_PREFIX = "/resource";
/** /**
* 搜索模块请求路径前缀 * 搜索模块请求路径前缀
* */ */
public static final String SEARCH_URL_PREFIX = "/search"; public static final String SEARCH_URL_PREFIX = "/search";
/** /**
@ -85,11 +85,13 @@ public class ApiRouterConsts {
/** /**
* 前台门户资源图片/视频/文档相关API请求路径前缀 * 前台门户资源图片/视频/文档相关API请求路径前缀
*/ */
public static final String API_FRONT_RESOURCE_URL_PREFIX = API_FRONT_URL_PREFIX + RESOURCE_URL_PREFIX; public static final String API_FRONT_RESOURCE_URL_PREFIX =
API_FRONT_URL_PREFIX + RESOURCE_URL_PREFIX;
/** /**
* 前台门户搜索相关API请求路径前缀 * 前台门户搜索相关API请求路径前缀
* */ */
public static final String API_FRONT_SEARCH_URL_PREFIX = API_FRONT_URL_PREFIX + SEARCH_URL_PREFIX; public static final String API_FRONT_SEARCH_URL_PREFIX =
API_FRONT_URL_PREFIX + SEARCH_URL_PREFIX;
} }

View File

@ -56,7 +56,7 @@ public class CacheConsts {
/** /**
* 小说分类列表缓存 * 小说分类列表缓存
* */ */
public static final String BOOK_CATEGORY_LIST_CACHE_NAME = "bookCategoryListCache"; public static final String BOOK_CATEGORY_LIST_CACHE_NAME = "bookCategoryListCache";
/** /**
@ -76,13 +76,14 @@ public class CacheConsts {
/** /**
* 最近更新小说ID列表缓存 * 最近更新小说ID列表缓存
* */ */
public static final String LAST_UPDATE_BOOK_ID_LIST_CACHE_NAME = "lastUpdateBookIdListCache"; public static final String LAST_UPDATE_BOOK_ID_LIST_CACHE_NAME = "lastUpdateBookIdListCache";
/** /**
* 图片验证码缓存 KEY * 图片验证码缓存 KEY
* */ */
public static final String IMG_VERIFY_CODE_CACHE_KEY = REDIS_CACHE_PREFIX + "imgVerifyCodeCache::"; public static final String IMG_VERIFY_CODE_CACHE_KEY =
REDIS_CACHE_PREFIX + "imgVerifyCodeCache::";
/** /**
* 用户信息缓存 * 用户信息缓存
@ -111,19 +112,19 @@ public class CacheConsts {
HOME_FRIEND_LINK_CACHE(2, HOME_FRIEND_LINK_CACHE_NAME, 0, 1), HOME_FRIEND_LINK_CACHE(2, HOME_FRIEND_LINK_CACHE_NAME, 0, 1),
BOOK_CATEGORY_LIST_CACHE(0,BOOK_CATEGORY_LIST_CACHE_NAME,0,2), BOOK_CATEGORY_LIST_CACHE(0, BOOK_CATEGORY_LIST_CACHE_NAME, 0, 2),
BOOK_INFO_CACHE(0, BOOK_INFO_CACHE_NAME, 60 * 60 * 18, 500), BOOK_INFO_CACHE(0, BOOK_INFO_CACHE_NAME, 60 * 60 * 18, 500),
BOOK_CHAPTER_CACHE(0,BOOK_CHAPTER_CACHE_NAME,60 * 60 * 6,5000), BOOK_CHAPTER_CACHE(0, BOOK_CHAPTER_CACHE_NAME, 60 * 60 * 6, 5000),
BOOK_CONTENT_CACHE(2, BOOK_CONTENT_CACHE_NAME, 60 * 60 * 12, 3000), BOOK_CONTENT_CACHE(2, BOOK_CONTENT_CACHE_NAME, 60 * 60 * 12, 3000),
LAST_UPDATE_BOOK_ID_LIST_CACHE(0,LAST_UPDATE_BOOK_ID_LIST_CACHE_NAME,60 * 60, 10), LAST_UPDATE_BOOK_ID_LIST_CACHE(0, LAST_UPDATE_BOOK_ID_LIST_CACHE_NAME, 60 * 60, 10),
USER_INFO_CACHE(2,USER_INFO_CACHE_NAME,60 * 60 * 24, 10000), USER_INFO_CACHE(2, USER_INFO_CACHE_NAME, 60 * 60 * 24, 10000),
AUTHOR_INFO_CACHE(2,AUTHOR_INFO_CACHE_NAME,60 * 60 * 48, 1000); AUTHOR_INFO_CACHE(2, AUTHOR_INFO_CACHE_NAME, 60 * 60 * 48, 1000);
/** /**
* 缓存类型 0-本地 1-本地和远程 2-远程 * 缓存类型 0-本地 1-本地和远程 2-远程

View File

@ -10,7 +10,6 @@ import lombok.Getter;
*/ */
public class DatabaseConsts { public class DatabaseConsts {
/** /**
* 用户信息表 * 用户信息表
*/ */

View File

@ -14,8 +14,8 @@ public class EsConsts {
/** /**
* 小说索引 * 小说索引
* */ */
public static class BookIndex{ public static class BookIndex {
private BookIndex() { private BookIndex() {
throw new IllegalStateException(SystemConfigConsts.CONST_INSTANCE_EXCEPTION_MSG); throw new IllegalStateException(SystemConfigConsts.CONST_INSTANCE_EXCEPTION_MSG);
@ -23,7 +23,7 @@ public class EsConsts {
/** /**
* 索引名 * 索引名
* */ */
public static final String INDEX_NAME = "book"; public static final String INDEX_NAME = "book";
/** /**

View File

@ -14,32 +14,32 @@ public class SystemConfigConsts {
/** /**
* Http 请求认证 Header * Http 请求认证 Header
* */ */
public static final String HTTP_AUTH_HEADER_NAME = "Authorization"; public static final String HTTP_AUTH_HEADER_NAME = "Authorization";
/** /**
* 前台门户系统标识 * 前台门户系统标识
* */ */
public static final String NOVEL_FRONT_KEY = "front"; public static final String NOVEL_FRONT_KEY = "front";
/** /**
* 作家管理系统标识 * 作家管理系统标识
* */ */
public static final String NOVEL_AUTHOR_KEY = "author"; public static final String NOVEL_AUTHOR_KEY = "author";
/** /**
* 后台管理系统标识 * 后台管理系统标识
* */ */
public static final String NOVEL_ADMIN_KEY = "admin"; public static final String NOVEL_ADMIN_KEY = "admin";
/** /**
* 图片上传目录 * 图片上传目录
* */ */
public static final String IMAGE_UPLOAD_DIRECTORY = "/image/"; public static final String IMAGE_UPLOAD_DIRECTORY = "/image/";
/** /**
* 常量类实例化异常信息 * 常量类实例化异常信息
* */ */
public static final String CONST_INSTANCE_EXCEPTION_MSG = "Constant class"; public static final String CONST_INSTANCE_EXCEPTION_MSG = "Constant class";
} }

View File

@ -3,18 +3,22 @@ package io.github.xxyopen.novel.core.filter;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import io.github.xxyopen.novel.core.config.XssProperties; import io.github.xxyopen.novel.core.config.XssProperties;
import io.github.xxyopen.novel.core.wrapper.XssHttpServletRequestWrapper; import io.github.xxyopen.novel.core.wrapper.XssHttpServletRequestWrapper;
import jakarta.servlet.*; import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.annotation.WebFilter; import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/** /**
* 防止 XSS 攻击的过滤器 * 防止 XSS 攻击的过滤器
* *
@ -22,13 +26,12 @@ import java.util.regex.Pattern;
* @date 2022/5/17 * @date 2022/5/17
*/ */
@Component @Component
@ConditionalOnProperty(value = "novel.xss.enabled",havingValue = "true") @ConditionalOnProperty(value = "novel.xss.enabled", havingValue = "true")
@WebFilter(urlPatterns = "/*", filterName = "xssFilter") @WebFilter(urlPatterns = "/*", filterName = "xssFilter")
@EnableConfigurationProperties(value = {XssProperties.class}) @EnableConfigurationProperties(value = {XssProperties.class})
@RequiredArgsConstructor @RequiredArgsConstructor
public class XssFilter implements Filter { public class XssFilter implements Filter {
private final XssProperties xssProperties; private final XssProperties xssProperties;
@Override @Override
@ -37,13 +40,15 @@ public class XssFilter implements Filter {
} }
@Override @Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest; HttpServletRequest req = (HttpServletRequest) servletRequest;
if (handleExcludeUrl(req)) { if (handleExcludeUrl(req)) {
filterChain.doFilter(servletRequest, servletResponse); filterChain.doFilter(servletRequest, servletResponse);
return; return;
} }
XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) servletRequest); XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper(
(HttpServletRequest) servletRequest);
filterChain.doFilter(xssRequest, servletResponse); filterChain.doFilter(xssRequest, servletResponse);
} }

View File

@ -9,18 +9,16 @@ import io.github.xxyopen.novel.core.constant.ApiRouterConsts;
import io.github.xxyopen.novel.core.constant.SystemConfigConsts; import io.github.xxyopen.novel.core.constant.SystemConfigConsts;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.ModelAndView;
import java.nio.charset.StandardCharsets;
import java.util.Map;
/** /**
* 认证 拦截器 * 认证 拦截器为了注入其它的 Spring beans需要通过 @Component 注解将该拦截器注册到 Spring 上下文
* 为了注入其它的 Spring beans需要通过 @Component 注解将该拦截器注册到 Spring 上下文
* *
* @author xiongxiaoyang * @author xiongxiaoyang
* @date 2022/5/18 * @date 2022/5/18
@ -29,13 +27,14 @@ import java.util.Map;
@RequiredArgsConstructor @RequiredArgsConstructor
public class AuthInterceptor implements HandlerInterceptor { public class AuthInterceptor implements HandlerInterceptor {
private final Map<String,AuthStrategy> authStrategy; private final Map<String, AuthStrategy> authStrategy;
private final ObjectMapper objectMapper; private final ObjectMapper objectMapper;
@SuppressWarnings("NullableProblems") @SuppressWarnings("NullableProblems")
@Override @Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
// 获取登录 JWT // 获取登录 JWT
String token = request.getHeader(SystemConfigConsts.HTTP_AUTH_HEADER_NAME); String token = request.getHeader(SystemConfigConsts.HTTP_AUTH_HEADER_NAME);
@ -44,25 +43,27 @@ public class AuthInterceptor implements HandlerInterceptor {
// 根据请求的 URI 得到认证策略 // 根据请求的 URI 得到认证策略
String subUri = requestUri.substring(ApiRouterConsts.API_URL_PREFIX.length() + 1); String subUri = requestUri.substring(ApiRouterConsts.API_URL_PREFIX.length() + 1);
String systemName = subUri.substring(0,subUri.indexOf("/")); String systemName = subUri.substring(0, subUri.indexOf("/"));
String authStrategyName = String.format("%sAuthStrategy",systemName); String authStrategyName = String.format("%sAuthStrategy", systemName);
// 开始认证 // 开始认证
try { try {
authStrategy.get(authStrategyName).auth(token,requestUri); authStrategy.get(authStrategyName).auth(token, requestUri);
return HandlerInterceptor.super.preHandle(request, response, handler); return HandlerInterceptor.super.preHandle(request, response, handler);
}catch (BusinessException exception){ } catch (BusinessException exception) {
// 认证失败 // 认证失败
response.setCharacterEncoding(StandardCharsets.UTF_8.name()); response.setCharacterEncoding(StandardCharsets.UTF_8.name());
response.setContentType(MediaType.APPLICATION_JSON_VALUE); response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.getWriter().write(objectMapper.writeValueAsString(RestResp.fail(exception.getErrorCodeEnum()))); response.getWriter().write(
objectMapper.writeValueAsString(RestResp.fail(exception.getErrorCodeEnum())));
return false; return false;
} }
} }
@SuppressWarnings("NullableProblems") @SuppressWarnings("NullableProblems")
@Override @Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// 清理当前线程保存的用户数据 // 清理当前线程保存的用户数据
UserHolder.clear(); UserHolder.clear();
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView); HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);

View File

@ -2,15 +2,14 @@ package io.github.xxyopen.novel.core.interceptor;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.HandlerInterceptor;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
/** /**
* 文件 拦截器 * 文件 拦截器
* *
@ -26,12 +25,14 @@ public class FileInterceptor implements HandlerInterceptor {
@SuppressWarnings("NullableProblems") @SuppressWarnings("NullableProblems")
@Override @Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
// 获取请求的 URI // 获取请求的 URI
String requestUri = request.getRequestURI(); String requestUri = request.getRequestURI();
// 缓存10天 // 缓存10天
response.setDateHeader("expires", System.currentTimeMillis() + 60 * 60 * 24 * 10 * 1000); response.setDateHeader("expires", System.currentTimeMillis() + 60 * 60 * 24 * 10 * 1000);
try (OutputStream out = response.getOutputStream(); InputStream input = new FileInputStream(fileUploadPath + requestUri)) { try (OutputStream out = response.getOutputStream(); InputStream input = new FileInputStream(
fileUploadPath + requestUri)) {
byte[] b = new byte[4096]; byte[] b = new byte[4096];
for (int n; (n = input.read(b)) != -1; ) { for (int n; (n = input.read(b)) != -1; ) {
out.write(b, 0, n); out.write(b, 0, n);

View File

@ -15,20 +15,18 @@ import io.github.xxyopen.novel.core.common.resp.RestResp;
import io.github.xxyopen.novel.core.common.util.IpUtils; import io.github.xxyopen.novel.core.common.util.IpUtils;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.HandlerInterceptor;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/** /**
* 流量限制 拦截器 * 流量限制 拦截器实现接口防刷和限流
* 实现接口防刷和限流
* *
* @author xiongxiaoyang * @author xiongxiaoyang
* @date 2022/6/1 * @date 2022/6/1
@ -70,7 +68,8 @@ public class FlowLimitInterceptor implements HandlerInterceptor {
} }
@Override @Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
String ip = IpUtils.getRealIp(request); String ip = IpUtils.getRealIp(request);
Entry entry = null; Entry entry = null;
try { try {
@ -85,7 +84,8 @@ public class FlowLimitInterceptor implements HandlerInterceptor {
log.info("IP:{}被限流了!", ip); log.info("IP:{}被限流了!", ip);
response.setCharacterEncoding(StandardCharsets.UTF_8.name()); response.setCharacterEncoding(StandardCharsets.UTF_8.name());
response.setContentType(MediaType.APPLICATION_JSON_VALUE); response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.getWriter().write(objectMapper.writeValueAsString(RestResp.fail(ErrorCodeEnum.USER_REQ_MANY))); response.getWriter()
.write(objectMapper.writeValueAsString(RestResp.fail(ErrorCodeEnum.USER_REQ_MANY)));
} finally { } finally {
// 注意exit 的时候也一定要带上对应的参数否则可能会有统计错误 // 注意exit 的时候也一定要带上对应的参数否则可能会有统计错误
if (entry != null) { if (entry != null) {

View File

@ -24,7 +24,8 @@ public class TokenParseInterceptor implements HandlerInterceptor {
private final JwtUtils jwtUtils; private final JwtUtils jwtUtils;
@Override @Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
// 获取登录 JWT // 获取登录 JWT
String token = request.getHeader(SystemConfigConsts.HTTP_AUTH_HEADER_NAME); String token = request.getHeader(SystemConfigConsts.HTTP_AUTH_HEADER_NAME);
if (StringUtils.hasText(token)) { if (StringUtils.hasText(token)) {
@ -35,7 +36,8 @@ public class TokenParseInterceptor implements HandlerInterceptor {
} }
@Override @Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// 清理当前线程保存的用户数据 // 清理当前线程保存的用户数据
UserHolder.clear(); UserHolder.clear();
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView); HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);

View File

@ -3,9 +3,8 @@ package io.github.xxyopen.novel.core.json.deserializer;
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonDeserializer;
import org.springframework.boot.jackson.JsonComponent;
import java.io.IOException; import java.io.IOException;
import org.springframework.boot.jackson.JsonComponent;
/** /**
@ -18,13 +17,13 @@ import java.io.IOException;
public class GlobalJsonDeserializer { public class GlobalJsonDeserializer {
/** /**
* 字符串反序列化器 * 字符串反序列化器过滤特殊字符解决 XSS 攻击
* 过滤特殊字符解决 XSS 攻击
*/ */
public static class StringDeserializer extends JsonDeserializer<String> { public static class StringDeserializer extends JsonDeserializer<String> {
@Override @Override
public String deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { public String deserialize(JsonParser jsonParser,
DeserializationContext deserializationContext) throws IOException {
return jsonParser.getValueAsString() return jsonParser.getValueAsString()
.replace("<", "&lt;") .replace("<", "&lt;")
.replace(">", "&gt;"); .replace(">", "&gt;");

View File

@ -3,7 +3,6 @@ package io.github.xxyopen.novel.core.json.serializer;
import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException; import java.io.IOException;
/** /**
@ -15,8 +14,9 @@ import java.io.IOException;
public class UsernameSerializer extends JsonSerializer<String> { public class UsernameSerializer extends JsonSerializer<String> {
@Override @Override
public void serialize(String s, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { public void serialize(String s, JsonGenerator jsonGenerator,
jsonGenerator.writeString(s.substring(0,4) + "****" + s.substring(8)); SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeString(s.substring(0, 4) + "****" + s.substring(8));
} }
} }

View File

@ -21,7 +21,8 @@ import org.springframework.stereotype.Component;
* @date 2022/5/25 * @date 2022/5/25
*/ */
@Component @Component
@ConditionalOnProperty(prefix = "spring", name = {"elasticsearch.enable","amqp.enable"}, havingValue = "true") @ConditionalOnProperty(prefix = "spring", name = {"elasticsearch.enable",
"amqp.enable"}, havingValue = "true")
@RequiredArgsConstructor @RequiredArgsConstructor
@Slf4j @Slf4j
public class RabbitQueueListener { public class RabbitQueueListener {
@ -32,7 +33,7 @@ public class RabbitQueueListener {
/** /**
* 监听小说信息改变的 ES 更新队列更新最新小说信息到 ES * 监听小说信息改变的 ES 更新队列更新最新小说信息到 ES
* */ */
@RabbitListener(queues = AmqpConsts.BookChangeMq.QUEUE_ES_UPDATE) @RabbitListener(queues = AmqpConsts.BookChangeMq.QUEUE_ES_UPDATE)
@SneakyThrows @SneakyThrows
public void updateEsBook(Long bookId) { public void updateEsBook(Long bookId) {

View File

@ -13,14 +13,13 @@ import io.github.xxyopen.novel.core.constant.EsConsts;
import io.github.xxyopen.novel.dao.entity.BookInfo; import io.github.xxyopen.novel.dao.entity.BookInfo;
import io.github.xxyopen.novel.dao.mapper.BookInfoMapper; import io.github.xxyopen.novel.dao.mapper.BookInfoMapper;
import io.github.xxyopen.novel.dto.es.EsBookDto; import io.github.xxyopen.novel.dto.es.EsBookDto;
import java.util.List;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.List;
/** /**
* 小说数据同步到 elasticsearch 任务 * 小说数据同步到 elasticsearch 任务
* *

View File

@ -5,14 +5,13 @@ import io.jsonwebtoken.Jws;
import io.jsonwebtoken.JwtException; import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts; import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys; import io.jsonwebtoken.security.Keys;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
/** /**
* JWT 工具类 * JWT 工具类
* *
@ -37,6 +36,7 @@ public class JwtUtils {
/** /**
* 根据用户ID生成JWT * 根据用户ID生成JWT
*
* @param uid 用户ID * @param uid 用户ID
* @param systemKey 系统标识 * @param systemKey 系统标识
* @return JWT * @return JWT
@ -51,6 +51,7 @@ public class JwtUtils {
/** /**
* 解析JWT返回用户ID * 解析JWT返回用户ID
*
* @param token JWT * @param token JWT
* @param systemKey 系统标识 * @param systemKey 系统标识
* @return 用户ID * @return 用户ID

View File

@ -2,7 +2,6 @@ package io.github.xxyopen.novel.core.wrapper;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper; import jakarta.servlet.http.HttpServletRequestWrapper;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -14,7 +13,7 @@ import java.util.Map;
*/ */
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
private static final Map<String,String> REPLACE_RULE = new HashMap<>(); private static final Map<String, String> REPLACE_RULE = new HashMap<>();
static { static {
REPLACE_RULE.put("<", "&lt;"); REPLACE_RULE.put("<", "&lt;");
@ -34,7 +33,8 @@ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
escapeValues[i] = values[i]; escapeValues[i] = values[i];
int index = i; int index = i;
REPLACE_RULE.forEach((k, v)-> escapeValues[index] = escapeValues[index].replaceAll(k, v)); REPLACE_RULE.forEach(
(k, v) -> escapeValues[index] = escapeValues[index].replaceAll(k, v));
} }
return escapeValues; return escapeValues;
} }

View File

@ -6,13 +6,12 @@ import io.github.xxyopen.novel.core.constant.DatabaseConsts;
import io.github.xxyopen.novel.dao.entity.AuthorInfo; import io.github.xxyopen.novel.dao.entity.AuthorInfo;
import io.github.xxyopen.novel.dao.mapper.AuthorInfoMapper; import io.github.xxyopen.novel.dao.mapper.AuthorInfoMapper;
import io.github.xxyopen.novel.dto.AuthorInfoDto; import io.github.xxyopen.novel.dto.AuthorInfoDto;
import java.util.Objects;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.Objects;
/** /**
* 作家信息 缓存管理类 * 作家信息 缓存管理类
* *

View File

@ -6,12 +6,11 @@ import io.github.xxyopen.novel.core.constant.DatabaseConsts;
import io.github.xxyopen.novel.dao.entity.BookCategory; import io.github.xxyopen.novel.dao.entity.BookCategory;
import io.github.xxyopen.novel.dao.mapper.BookCategoryMapper; import io.github.xxyopen.novel.dao.mapper.BookCategoryMapper;
import io.github.xxyopen.novel.dto.resp.BookCategoryRespDto; import io.github.xxyopen.novel.dto.resp.BookCategoryRespDto;
import java.util.List;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.List;
/** /**
* 小说分类 缓存管理类 * 小说分类 缓存管理类
* *

View File

@ -8,14 +8,13 @@ import io.github.xxyopen.novel.dao.entity.BookInfo;
import io.github.xxyopen.novel.dao.mapper.BookChapterMapper; import io.github.xxyopen.novel.dao.mapper.BookChapterMapper;
import io.github.xxyopen.novel.dao.mapper.BookInfoMapper; import io.github.xxyopen.novel.dao.mapper.BookInfoMapper;
import io.github.xxyopen.novel.dto.resp.BookInfoRespDto; import io.github.xxyopen.novel.dto.resp.BookInfoRespDto;
import java.util.List;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.List;
/** /**
* 小说信息 缓存管理类 * 小说信息 缓存管理类
* *
@ -33,7 +32,8 @@ public class BookInfoCacheManager {
/** /**
* 从缓存中查询小说信息先判断缓存中是否已存在存在则直接从缓存中取否则执行方法体中的逻辑后缓存结果 * 从缓存中查询小说信息先判断缓存中是否已存在存在则直接从缓存中取否则执行方法体中的逻辑后缓存结果
*/ */
@Cacheable(cacheManager = CacheConsts.CAFFEINE_CACHE_MANAGER, @Cacheable(
cacheManager = CacheConsts.CAFFEINE_CACHE_MANAGER,
value = CacheConsts.BOOK_INFO_CACHE_NAME) value = CacheConsts.BOOK_INFO_CACHE_NAME)
public BookInfoRespDto getBookInfo(Long id) { public BookInfoRespDto getBookInfo(Long id) {
return cachePutBookInfo(id); return cachePutBookInfo(id);
@ -42,7 +42,8 @@ public class BookInfoCacheManager {
/** /**
* 缓存小说信息不管缓存中是否存在都执行方法体中的逻辑然后缓存起来 * 缓存小说信息不管缓存中是否存在都执行方法体中的逻辑然后缓存起来
*/ */
@CachePut(cacheManager = CacheConsts.CAFFEINE_CACHE_MANAGER, @CachePut(
cacheManager = CacheConsts.CAFFEINE_CACHE_MANAGER,
value = CacheConsts.BOOK_INFO_CACHE_NAME) value = CacheConsts.BOOK_INFO_CACHE_NAME)
public BookInfoRespDto cachePutBookInfo(Long id) { public BookInfoRespDto cachePutBookInfo(Long id) {
// 查询基础信息 // 查询基础信息
@ -73,7 +74,8 @@ public class BookInfoCacheManager {
.build(); .build();
} }
@CacheEvict(cacheManager = CacheConsts.CAFFEINE_CACHE_MANAGER, @CacheEvict(
cacheManager = CacheConsts.CAFFEINE_CACHE_MANAGER,
value = CacheConsts.BOOK_INFO_CACHE_NAME) value = CacheConsts.BOOK_INFO_CACHE_NAME)
public void evictBookInfoCache(Long ignoredId) { public void evictBookInfoCache(Long ignoredId) {
// 调用此方法自动清除小说信息的缓存 // 调用此方法自动清除小说信息的缓存
@ -82,15 +84,16 @@ public class BookInfoCacheManager {
/** /**
* 查询每个类别下最新更新的 500 个小说ID列表并放入缓存中 1 个小时 * 查询每个类别下最新更新的 500 个小说ID列表并放入缓存中 1 个小时
*/ */
@Cacheable(cacheManager = CacheConsts.CAFFEINE_CACHE_MANAGER, @Cacheable(
cacheManager = CacheConsts.CAFFEINE_CACHE_MANAGER,
value = CacheConsts.LAST_UPDATE_BOOK_ID_LIST_CACHE_NAME) value = CacheConsts.LAST_UPDATE_BOOK_ID_LIST_CACHE_NAME)
public List<Long> getLastUpdateIdList(Long categoryId) { public List<Long> getLastUpdateIdList(Long categoryId) {
QueryWrapper<BookInfo> queryWrapper = new QueryWrapper<>(); QueryWrapper<BookInfo> queryWrapper = new QueryWrapper<>();
queryWrapper.eq(DatabaseConsts.BookTable.COLUMN_CATEGORY_ID, categoryId) queryWrapper
.gt(DatabaseConsts.BookTable.COLUMN_WORD_COUNT,0) .eq(DatabaseConsts.BookTable.COLUMN_CATEGORY_ID, categoryId)
.gt(DatabaseConsts.BookTable.COLUMN_WORD_COUNT, 0)
.orderByDesc(DatabaseConsts.BookTable.COLUMN_LAST_CHAPTER_UPDATE_TIME) .orderByDesc(DatabaseConsts.BookTable.COLUMN_LAST_CHAPTER_UPDATE_TIME)
.last(DatabaseConsts.SqlEnum.LIMIT_500.getSql()); .last(DatabaseConsts.SqlEnum.LIMIT_500.getSql());
return bookInfoMapper.selectList(queryWrapper).stream().map(BookInfo::getId).toList(); return bookInfoMapper.selectList(queryWrapper).stream().map(BookInfo::getId).toList();
} }
} }

View File

@ -6,12 +6,11 @@ import io.github.xxyopen.novel.core.constant.DatabaseConsts;
import io.github.xxyopen.novel.dao.entity.BookInfo; import io.github.xxyopen.novel.dao.entity.BookInfo;
import io.github.xxyopen.novel.dao.mapper.BookInfoMapper; import io.github.xxyopen.novel.dao.mapper.BookInfoMapper;
import io.github.xxyopen.novel.dto.resp.BookRankRespDto; import io.github.xxyopen.novel.dto.resp.BookRankRespDto;
import java.util.List;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.List;
/** /**
* 小说排行榜 缓存管理类 * 小说排行榜 缓存管理类
* *
@ -43,7 +42,7 @@ public class BookRankCacheManager {
public List<BookRankRespDto> listNewestRankBooks() { public List<BookRankRespDto> listNewestRankBooks() {
QueryWrapper<BookInfo> bookInfoQueryWrapper = new QueryWrapper<>(); QueryWrapper<BookInfo> bookInfoQueryWrapper = new QueryWrapper<>();
bookInfoQueryWrapper bookInfoQueryWrapper
.gt(DatabaseConsts.BookTable.COLUMN_WORD_COUNT,0) .gt(DatabaseConsts.BookTable.COLUMN_WORD_COUNT, 0)
.orderByDesc(DatabaseConsts.CommonColumnEnum.CREATE_TIME.getName()); .orderByDesc(DatabaseConsts.CommonColumnEnum.CREATE_TIME.getName());
return listRankBooks(bookInfoQueryWrapper); return listRankBooks(bookInfoQueryWrapper);
} }
@ -56,14 +55,14 @@ public class BookRankCacheManager {
public List<BookRankRespDto> listUpdateRankBooks() { public List<BookRankRespDto> listUpdateRankBooks() {
QueryWrapper<BookInfo> bookInfoQueryWrapper = new QueryWrapper<>(); QueryWrapper<BookInfo> bookInfoQueryWrapper = new QueryWrapper<>();
bookInfoQueryWrapper bookInfoQueryWrapper
.gt(DatabaseConsts.BookTable.COLUMN_WORD_COUNT,0) .gt(DatabaseConsts.BookTable.COLUMN_WORD_COUNT, 0)
.orderByDesc(DatabaseConsts.CommonColumnEnum.UPDATE_TIME.getName()); .orderByDesc(DatabaseConsts.CommonColumnEnum.UPDATE_TIME.getName());
return listRankBooks(bookInfoQueryWrapper); return listRankBooks(bookInfoQueryWrapper);
} }
private List<BookRankRespDto> listRankBooks(QueryWrapper<BookInfo> bookInfoQueryWrapper) { private List<BookRankRespDto> listRankBooks(QueryWrapper<BookInfo> bookInfoQueryWrapper) {
bookInfoQueryWrapper bookInfoQueryWrapper
.gt(DatabaseConsts.BookTable.COLUMN_WORD_COUNT,0) .gt(DatabaseConsts.BookTable.COLUMN_WORD_COUNT, 0)
.last(DatabaseConsts.SqlEnum.LIMIT_30.getSql()); .last(DatabaseConsts.SqlEnum.LIMIT_30.getSql());
return bookInfoMapper.selectList(bookInfoQueryWrapper).stream().map(v -> { return bookInfoMapper.selectList(bookInfoQueryWrapper).stream().map(v -> {
BookRankRespDto respDto = new BookRankRespDto(); BookRankRespDto respDto = new BookRankRespDto();

View File

@ -6,12 +6,11 @@ import io.github.xxyopen.novel.core.constant.DatabaseConsts;
import io.github.xxyopen.novel.dao.entity.HomeFriendLink; import io.github.xxyopen.novel.dao.entity.HomeFriendLink;
import io.github.xxyopen.novel.dao.mapper.HomeFriendLinkMapper; import io.github.xxyopen.novel.dao.mapper.HomeFriendLinkMapper;
import io.github.xxyopen.novel.dto.resp.HomeFriendLinkRespDto; import io.github.xxyopen.novel.dto.resp.HomeFriendLinkRespDto;
import java.util.List;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.List;
/** /**
* 友情链接 缓存管理类 * 友情链接 缓存管理类
* *

View File

@ -8,16 +8,15 @@ import io.github.xxyopen.novel.dao.entity.HomeBook;
import io.github.xxyopen.novel.dao.mapper.BookInfoMapper; import io.github.xxyopen.novel.dao.mapper.BookInfoMapper;
import io.github.xxyopen.novel.dao.mapper.HomeBookMapper; import io.github.xxyopen.novel.dao.mapper.HomeBookMapper;
import io.github.xxyopen.novel.dto.resp.HomeBookRespDto; import io.github.xxyopen.novel.dto.resp.HomeBookRespDto;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
/** /**
* 首页推荐小说 缓存管理类 * 首页推荐小说 缓存管理类
@ -56,7 +55,7 @@ public class HomeBookCacheManager {
List<BookInfo> bookInfos = bookInfoMapper.selectList(bookInfoQueryWrapper); List<BookInfo> bookInfos = bookInfoMapper.selectList(bookInfoQueryWrapper);
// 组装 HomeBookRespDto 列表数据并返回 // 组装 HomeBookRespDto 列表数据并返回
if(!CollectionUtils.isEmpty(bookInfos)){ if (!CollectionUtils.isEmpty(bookInfos)) {
Map<Long, BookInfo> bookInfoMap = bookInfos.stream() Map<Long, BookInfo> bookInfoMap = bookInfos.stream()
.collect(Collectors.toMap(BookInfo::getId, Function.identity())); .collect(Collectors.toMap(BookInfo::getId, Function.identity()));
return homeBooks.stream().map(v -> { return homeBooks.stream().map(v -> {

View File

@ -6,12 +6,11 @@ import io.github.xxyopen.novel.core.constant.DatabaseConsts;
import io.github.xxyopen.novel.dao.entity.NewsInfo; import io.github.xxyopen.novel.dao.entity.NewsInfo;
import io.github.xxyopen.novel.dao.mapper.NewsInfoMapper; import io.github.xxyopen.novel.dao.mapper.NewsInfoMapper;
import io.github.xxyopen.novel.dto.resp.NewsInfoRespDto; import io.github.xxyopen.novel.dto.resp.NewsInfoRespDto;
import java.util.List;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.List;
/** /**
* 新闻 缓存管理类 * 新闻 缓存管理类
* *

View File

@ -4,12 +4,11 @@ import io.github.xxyopen.novel.core.constant.CacheConsts;
import io.github.xxyopen.novel.dao.entity.UserInfo; import io.github.xxyopen.novel.dao.entity.UserInfo;
import io.github.xxyopen.novel.dao.mapper.UserInfoMapper; import io.github.xxyopen.novel.dao.mapper.UserInfoMapper;
import io.github.xxyopen.novel.dto.UserInfoDto; import io.github.xxyopen.novel.dto.UserInfoDto;
import java.util.Objects;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.Objects;
/** /**
* 用户信息 缓存管理类 * 用户信息 缓存管理类
* *

View File

@ -4,13 +4,13 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.github.xxyopen.novel.core.constant.DatabaseConsts; import io.github.xxyopen.novel.core.constant.DatabaseConsts;
import io.github.xxyopen.novel.dao.entity.UserInfo; import io.github.xxyopen.novel.dao.entity.UserInfo;
import io.github.xxyopen.novel.dao.mapper.UserInfoMapper; import io.github.xxyopen.novel.dao.mapper.UserInfoMapper;
import java.util.List;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.List;
/** /**
* 用户模块 DAO管理类 * 用户模块 DAO管理类
*
* @author xiongxiaoyang * @author xiongxiaoyang
* @date 2022/5/20 * @date 2022/5/20
*/ */
@ -22,12 +22,13 @@ public class UserDaoManager {
/** /**
* 根据用户ID集合批量查询用户信息列表 * 根据用户ID集合批量查询用户信息列表
*
* @param userIds 需要查询的用户ID集合 * @param userIds 需要查询的用户ID集合
* @return 满足条件的用户信息列表 * @return 满足条件的用户信息列表
* */ */
public List<UserInfo> listUsers(List<Long> userIds){ public List<UserInfo> listUsers(List<Long> userIds) {
QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>(); QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
queryWrapper.in(DatabaseConsts.CommonColumnEnum.ID.getName(),userIds); queryWrapper.in(DatabaseConsts.CommonColumnEnum.ID.getName(), userIds);
return userInfoMapper.selectList(queryWrapper); return userInfoMapper.selectList(queryWrapper);
} }

View File

@ -2,6 +2,7 @@ package io.github.xxyopen.novel.manager.mq;
import io.github.xxyopen.novel.core.common.constant.CommonConsts; import io.github.xxyopen.novel.core.common.constant.CommonConsts;
import io.github.xxyopen.novel.core.constant.AmqpConsts; import io.github.xxyopen.novel.core.constant.AmqpConsts;
import java.util.Objects;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.amqp.core.AmqpTemplate; import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
@ -9,8 +10,6 @@ import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionSynchronization; import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager; import org.springframework.transaction.support.TransactionSynchronizationManager;
import java.util.Objects;
/** /**
* AMQP 消息管理类 * AMQP 消息管理类
* *
@ -35,10 +34,12 @@ public class AmqpMsgManager {
} }
} }
private void sendAmqpMessage(AmqpTemplate amqpTemplate, String exchange, String routingKey, Object message) { private void sendAmqpMessage(AmqpTemplate amqpTemplate, String exchange, String routingKey,
Object message) {
// 如果在事务中则在事务执行完成后再发送否则可以直接发送 // 如果在事务中则在事务执行完成后再发送否则可以直接发送
if (TransactionSynchronizationManager.isActualTransactionActive()) { if (TransactionSynchronizationManager.isActualTransactionActive()) {
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { TransactionSynchronizationManager.registerSynchronization(
new TransactionSynchronization() {
@Override @Override
public void afterCommit() { public void afterCommit() {
amqpTemplate.convertAndSend(exchange, routingKey, message); amqpTemplate.convertAndSend(exchange, routingKey, message);

View File

@ -2,15 +2,14 @@ package io.github.xxyopen.novel.manager.redis;
import io.github.xxyopen.novel.core.common.util.ImgVerifyCodeUtils; import io.github.xxyopen.novel.core.common.util.ImgVerifyCodeUtils;
import io.github.xxyopen.novel.core.constant.CacheConsts; import io.github.xxyopen.novel.core.constant.CacheConsts;
import java.io.IOException;
import java.time.Duration;
import java.util.Objects;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.io.IOException;
import java.time.Duration;
import java.util.Objects;
/** /**
* 验证码 管理类 * 验证码 管理类
* *
@ -39,7 +38,8 @@ public class VerifyCodeManager {
* 校验图形验证码 * 校验图形验证码
*/ */
public boolean imgVerifyCodeOk(String sessionId, String verifyCode) { public boolean imgVerifyCodeOk(String sessionId, String verifyCode) {
return Objects.equals(stringRedisTemplate.opsForValue().get(CacheConsts.IMG_VERIFY_CODE_CACHE_KEY + sessionId), verifyCode); return Objects.equals(stringRedisTemplate.opsForValue()
.get(CacheConsts.IMG_VERIFY_CODE_CACHE_KEY + sessionId), verifyCode);
} }
/** /**

View File

@ -21,8 +21,9 @@ public interface AuthorService {
/** /**
* 查询作家状态 * 查询作家状态
*
* @param userId 用户ID * @param userId 用户ID
* @return 作家状态 * @return 作家状态
* */ */
RestResp<Integer> getStatus(Long userId); RestResp<Integer> getStatus(Long userId);
} }

View File

@ -11,7 +11,11 @@ import io.github.xxyopen.novel.core.common.req.PageReqDto;
import io.github.xxyopen.novel.core.common.resp.PageRespDto; import io.github.xxyopen.novel.core.common.resp.PageRespDto;
import io.github.xxyopen.novel.core.common.resp.RestResp; import io.github.xxyopen.novel.core.common.resp.RestResp;
import io.github.xxyopen.novel.core.constant.DatabaseConsts; import io.github.xxyopen.novel.core.constant.DatabaseConsts;
import io.github.xxyopen.novel.dao.entity.*; import io.github.xxyopen.novel.dao.entity.BookChapter;
import io.github.xxyopen.novel.dao.entity.BookComment;
import io.github.xxyopen.novel.dao.entity.BookContent;
import io.github.xxyopen.novel.dao.entity.BookInfo;
import io.github.xxyopen.novel.dao.entity.UserInfo;
import io.github.xxyopen.novel.dao.mapper.BookChapterMapper; import io.github.xxyopen.novel.dao.mapper.BookChapterMapper;
import io.github.xxyopen.novel.dao.mapper.BookCommentMapper; import io.github.xxyopen.novel.dao.mapper.BookCommentMapper;
import io.github.xxyopen.novel.dao.mapper.BookContentMapper; import io.github.xxyopen.novel.dao.mapper.BookContentMapper;
@ -20,23 +24,39 @@ import io.github.xxyopen.novel.dto.AuthorInfoDto;
import io.github.xxyopen.novel.dto.req.BookAddReqDto; import io.github.xxyopen.novel.dto.req.BookAddReqDto;
import io.github.xxyopen.novel.dto.req.ChapterAddReqDto; import io.github.xxyopen.novel.dto.req.ChapterAddReqDto;
import io.github.xxyopen.novel.dto.req.UserCommentReqDto; import io.github.xxyopen.novel.dto.req.UserCommentReqDto;
import io.github.xxyopen.novel.dto.resp.*; import io.github.xxyopen.novel.dto.resp.BookCategoryRespDto;
import io.github.xxyopen.novel.manager.cache.*; import io.github.xxyopen.novel.dto.resp.BookChapterAboutRespDto;
import io.github.xxyopen.novel.dto.resp.BookChapterRespDto;
import io.github.xxyopen.novel.dto.resp.BookCommentRespDto;
import io.github.xxyopen.novel.dto.resp.BookContentAboutRespDto;
import io.github.xxyopen.novel.dto.resp.BookInfoRespDto;
import io.github.xxyopen.novel.dto.resp.BookRankRespDto;
import io.github.xxyopen.novel.manager.cache.AuthorInfoCacheManager;
import io.github.xxyopen.novel.manager.cache.BookCategoryCacheManager;
import io.github.xxyopen.novel.manager.cache.BookChapterCacheManager;
import io.github.xxyopen.novel.manager.cache.BookContentCacheManager;
import io.github.xxyopen.novel.manager.cache.BookInfoCacheManager;
import io.github.xxyopen.novel.manager.cache.BookRankCacheManager;
import io.github.xxyopen.novel.manager.dao.UserDaoManager; import io.github.xxyopen.novel.manager.dao.UserDaoManager;
import io.github.xxyopen.novel.manager.mq.AmqpMsgManager; import io.github.xxyopen.novel.manager.mq.AmqpMsgManager;
import io.github.xxyopen.novel.service.BookService; import io.github.xxyopen.novel.service.BookService;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Random;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
/** /**
* 小说模块 服务实现类 * 小说模块 服务实现类
* *
@ -100,7 +120,8 @@ public class BookServiceImpl implements BookService {
BookInfoRespDto bookInfo = bookInfoCacheManager.getBookInfo(bookId); BookInfoRespDto bookInfo = bookInfoCacheManager.getBookInfo(bookId);
// 查询最新章节信息 // 查询最新章节信息
BookChapterRespDto bookChapter = bookChapterCacheManager.getChapter(bookInfo.getLastChapterId()); BookChapterRespDto bookChapter = bookChapterCacheManager.getChapter(
bookInfo.getLastChapterId());
// 查询章节内容 // 查询章节内容
String content = bookContentCacheManager.getBookContent(bookInfo.getLastChapterId()); String content = bookContentCacheManager.getBookContent(bookInfo.getLastChapterId());
@ -119,7 +140,8 @@ public class BookServiceImpl implements BookService {
} }
@Override @Override
public RestResp<List<BookInfoRespDto>> listRecBooks(Long bookId) throws NoSuchAlgorithmException { public RestResp<List<BookInfoRespDto>> listRecBooks(Long bookId)
throws NoSuchAlgorithmException {
Long categoryId = bookInfoCacheManager.getBookInfo(bookId).getCategoryId(); Long categoryId = bookInfoCacheManager.getBookInfo(bookId).getCategoryId();
List<Long> lastUpdateIdList = bookInfoCacheManager.getLastUpdateIdList(categoryId); List<Long> lastUpdateIdList = bookInfoCacheManager.getLastUpdateIdList(categoryId);
List<BookInfoRespDto> respDtoList = new ArrayList<>(); List<BookInfoRespDto> respDtoList = new ArrayList<>();
@ -190,7 +212,8 @@ public class BookServiceImpl implements BookService {
QueryWrapper<BookChapter> queryWrapper = new QueryWrapper<>(); QueryWrapper<BookChapter> queryWrapper = new QueryWrapper<>();
queryWrapper.eq(DatabaseConsts.BookChapterTable.COLUMN_BOOK_ID, bookId) queryWrapper.eq(DatabaseConsts.BookChapterTable.COLUMN_BOOK_ID, bookId)
.orderByAsc(DatabaseConsts.BookChapterTable.COLUMN_CHAPTER_NUM); .orderByAsc(DatabaseConsts.BookChapterTable.COLUMN_CHAPTER_NUM);
return RestResp.ok(bookChapterMapper.selectList(queryWrapper).stream().map(v -> BookChapterRespDto.builder() return RestResp.ok(bookChapterMapper.selectList(queryWrapper).stream()
.map(v -> BookChapterRespDto.builder()
.id(v.getId()) .id(v.getId())
.chapterName(v.getChapterName()) .chapterName(v.getChapterName())
.isVip(v.getIsVip()) .isVip(v.getIsVip())
@ -204,7 +227,8 @@ public class BookServiceImpl implements BookService {
@Lock(prefix = "userComment") @Lock(prefix = "userComment")
@Override @Override
public RestResp<Void> saveComment(@Key(expr = "#{userId + '::' + bookId}") UserCommentReqDto dto) { public RestResp<Void> saveComment(
@Key(expr = "#{userId + '::' + bookId}") UserCommentReqDto dto) {
// 校验用户是否已发表评论 // 校验用户是否已发表评论
QueryWrapper<BookComment> queryWrapper = new QueryWrapper<>(); QueryWrapper<BookComment> queryWrapper = new QueryWrapper<>();
queryWrapper.eq(DatabaseConsts.BookCommentTable.COLUMN_USER_ID, dto.getUserId()) queryWrapper.eq(DatabaseConsts.BookCommentTable.COLUMN_USER_ID, dto.getUserId())
@ -229,7 +253,8 @@ public class BookServiceImpl implements BookService {
QueryWrapper<BookComment> commentCountQueryWrapper = new QueryWrapper<>(); QueryWrapper<BookComment> commentCountQueryWrapper = new QueryWrapper<>();
commentCountQueryWrapper.eq(DatabaseConsts.BookCommentTable.COLUMN_BOOK_ID, bookId); commentCountQueryWrapper.eq(DatabaseConsts.BookCommentTable.COLUMN_BOOK_ID, bookId);
Long commentTotal = bookCommentMapper.selectCount(commentCountQueryWrapper); Long commentTotal = bookCommentMapper.selectCount(commentCountQueryWrapper);
BookCommentRespDto bookCommentRespDto = BookCommentRespDto.builder().commentTotal(commentTotal).build(); BookCommentRespDto bookCommentRespDto = BookCommentRespDto.builder()
.commentTotal(commentTotal).build();
if (commentTotal > 0) { if (commentTotal > 0) {
// 查询最新的评论列表 // 查询最新的评论列表
@ -242,7 +267,8 @@ public class BookServiceImpl implements BookService {
// 查询评论用户信息并设置需要返回的评论用户名 // 查询评论用户信息并设置需要返回的评论用户名
List<Long> userIds = bookComments.stream().map(BookComment::getUserId).toList(); List<Long> userIds = bookComments.stream().map(BookComment::getUserId).toList();
List<UserInfo> userInfos = userDaoManager.listUsers(userIds); List<UserInfo> userInfos = userDaoManager.listUsers(userIds);
Map<Long, UserInfo> userInfoMap = userInfos.stream().collect(Collectors.toMap(UserInfo::getId, Function.identity())); Map<Long, UserInfo> userInfoMap = userInfos.stream()
.collect(Collectors.toMap(UserInfo::getId, Function.identity()));
List<BookCommentRespDto.CommentInfo> commentInfos = bookComments.stream() List<BookCommentRespDto.CommentInfo> commentInfos = bookComments.stream()
.map(v -> BookCommentRespDto.CommentInfo.builder() .map(v -> BookCommentRespDto.CommentInfo.builder()
.id(v.getId()) .id(v.getId())

View File

@ -8,13 +8,12 @@ import io.github.xxyopen.novel.dao.mapper.BookInfoMapper;
import io.github.xxyopen.novel.dto.req.BookSearchReqDto; import io.github.xxyopen.novel.dto.req.BookSearchReqDto;
import io.github.xxyopen.novel.dto.resp.BookInfoRespDto; import io.github.xxyopen.novel.dto.resp.BookInfoRespDto;
import io.github.xxyopen.novel.service.SearchService; import io.github.xxyopen.novel.service.SearchService;
import java.util.List;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.List;
/** /**
* 数据库搜索 服务实现类 * 数据库搜索 服务实现类
* *
@ -35,7 +34,8 @@ public class DbSearchServiceImpl implements SearchService {
page.setCurrent(condition.getPageNum()); page.setCurrent(condition.getPageNum());
page.setSize(condition.getPageSize()); page.setSize(condition.getPageSize());
List<BookInfo> bookInfos = bookInfoMapper.searchBooks(page, condition); List<BookInfo> bookInfos = bookInfoMapper.searchBooks(page, condition);
return RestResp.ok(PageRespDto.of(condition.getPageNum(), condition.getPageSize(), page.getTotal(), return RestResp.ok(
PageRespDto.of(condition.getPageNum(), condition.getPageSize(), page.getTotal(),
bookInfos.stream().map(v -> BookInfoRespDto.builder() bookInfos.stream().map(v -> BookInfoRespDto.builder()
.id(v.getId()) .id(v.getId())
.bookName(v.getBookName()) .bookName(v.getBookName())

View File

@ -19,16 +19,15 @@ import io.github.xxyopen.novel.dto.es.EsBookDto;
import io.github.xxyopen.novel.dto.req.BookSearchReqDto; import io.github.xxyopen.novel.dto.req.BookSearchReqDto;
import io.github.xxyopen.novel.dto.resp.BookInfoRespDto; import io.github.xxyopen.novel.dto.resp.BookInfoRespDto;
import io.github.xxyopen.novel.service.SearchService; import io.github.xxyopen.novel.service.SearchService;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/** /**
* Elasticsearch 搜索 服务实现类 * Elasticsearch 搜索 服务实现类
* *
@ -84,8 +83,10 @@ public class EsSearchServiceImpl implements SearchService {
if (!CollectionUtils.isEmpty(hit.highlight().get(EsConsts.BookIndex.FIELD_BOOK_NAME))) { if (!CollectionUtils.isEmpty(hit.highlight().get(EsConsts.BookIndex.FIELD_BOOK_NAME))) {
book.setBookName(hit.highlight().get(EsConsts.BookIndex.FIELD_BOOK_NAME).get(0)); book.setBookName(hit.highlight().get(EsConsts.BookIndex.FIELD_BOOK_NAME).get(0));
} }
if (!CollectionUtils.isEmpty(hit.highlight().get(EsConsts.BookIndex.FIELD_AUTHOR_NAME))) { if (!CollectionUtils.isEmpty(
book.setAuthorName(hit.highlight().get(EsConsts.BookIndex.FIELD_AUTHOR_NAME).get(0)); hit.highlight().get(EsConsts.BookIndex.FIELD_AUTHOR_NAME))) {
book.setAuthorName(
hit.highlight().get(EsConsts.BookIndex.FIELD_AUTHOR_NAME).get(0));
} }
list.add(BookInfoRespDto.builder() list.add(BookInfoRespDto.builder()
.id(book.getId()) .id(book.getId())
@ -99,14 +100,16 @@ public class EsSearchServiceImpl implements SearchService {
.build()); .build());
} }
assert total != null; assert total != null;
return RestResp.ok(PageRespDto.of(condition.getPageNum(), condition.getPageSize(), total.value(), list)); return RestResp.ok(
PageRespDto.of(condition.getPageNum(), condition.getPageSize(), total.value(), list));
} }
/** /**
* 构建检索条件 * 构建检索条件
*/ */
private void buildSearchCondition(BookSearchReqDto condition, SearchRequest.Builder searchBuilder) { private void buildSearchCondition(BookSearchReqDto condition,
SearchRequest.Builder searchBuilder) {
BoolQuery boolQuery = BoolQuery.of(b -> { BoolQuery boolQuery = BoolQuery.of(b -> {

View File

@ -10,11 +10,10 @@ import io.github.xxyopen.novel.dao.mapper.NewsInfoMapper;
import io.github.xxyopen.novel.dto.resp.NewsInfoRespDto; import io.github.xxyopen.novel.dto.resp.NewsInfoRespDto;
import io.github.xxyopen.novel.manager.cache.NewsCacheManager; import io.github.xxyopen.novel.manager.cache.NewsCacheManager;
import io.github.xxyopen.novel.service.NewsService; import io.github.xxyopen.novel.service.NewsService;
import java.util.List;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.List;
/** /**
* 新闻模块 服务实现类 * 新闻模块 服务实现类
* *

View File

@ -8,20 +8,19 @@ import io.github.xxyopen.novel.core.constant.SystemConfigConsts;
import io.github.xxyopen.novel.dto.resp.ImgVerifyCodeRespDto; import io.github.xxyopen.novel.dto.resp.ImgVerifyCodeRespDto;
import io.github.xxyopen.novel.manager.redis.VerifyCodeManager; import io.github.xxyopen.novel.manager.redis.VerifyCodeManager;
import io.github.xxyopen.novel.service.ResourceService; import io.github.xxyopen.novel.service.ResourceService;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.Objects; import java.util.Objects;
import javax.imageio.ImageIO;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
/** /**
* 资源图片/视频/文档相关服务实现类 * 资源图片/视频/文档相关服务实现类

View File

@ -22,13 +22,12 @@ import io.github.xxyopen.novel.dto.resp.UserLoginRespDto;
import io.github.xxyopen.novel.dto.resp.UserRegisterRespDto; import io.github.xxyopen.novel.dto.resp.UserRegisterRespDto;
import io.github.xxyopen.novel.manager.redis.VerifyCodeManager; import io.github.xxyopen.novel.manager.redis.VerifyCodeManager;
import io.github.xxyopen.novel.service.UserService; import io.github.xxyopen.novel.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Objects; import java.util.Objects;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
/** /**
* 会员模块 服务实现类 * 会员模块 服务实现类
@ -69,7 +68,8 @@ public class UserServiceImpl implements UserService {
// 注册成功保存用户信息 // 注册成功保存用户信息
UserInfo userInfo = new UserInfo(); UserInfo userInfo = new UserInfo();
userInfo.setPassword(DigestUtils.md5DigestAsHex(dto.getPassword().getBytes(StandardCharsets.UTF_8))); userInfo.setPassword(
DigestUtils.md5DigestAsHex(dto.getPassword().getBytes(StandardCharsets.UTF_8)));
userInfo.setUsername(dto.getUsername()); userInfo.setUsername(dto.getUsername());
userInfo.setNickName(dto.getUsername()); userInfo.setNickName(dto.getUsername());
userInfo.setCreateTime(LocalDateTime.now()); userInfo.setCreateTime(LocalDateTime.now());