目的
作为开发人员,我们应该写出符合规范的代码,而不是写完代码后,通过不断修改让代码符合规范。
代码规范问题发现的时间越靠后,修改的成本越高,我们可以通过IDEA各种各样的工具和提示,来强制代码符合规范,并在实施的过程中养成良好的代码习惯。
说明
本文档中的配置分为两个级别:
强制: 希望每个开发人员都必须使用的配置
建议: 建议开发人员尽量使用的配置
配置
[强制]引入koca代码格式
Step1. 打开Code Style设置
Mac OS: IntelliJ IDEA → Preferences → Editor → Code Style → Java
Windows: File → Settings → Editor → Code Style → Java
Step2. 引入KOCA Code Style文件
创建ProjectJavaCodeStyle.xml文件,文件内容在帖子最下面
选择ProjectJavaCodeStyle.xml
选择刚刚引入的Schema
Step3. 修改刚刚导入的格式文件,最大空白行数全部设置为1
Step4. 通过快捷键或Code → Reformat Code命令格式化代码
MacOS:⌘ + ⌥ + L
Windows:Ctrl + Alt + L
[强制]打开自动整理imports
Step1. 打开自动导入配置
Mac OS: IntelliJ IDEA → Preferences → Editor → General → Auto Import
Windows: File → Settings → Editor → General → Auto Import
Step2. 勾选Optimize imports on the fly (for current project)
注意该配置只对当前项目生效,如果切换项目或者删除项目重新导入,需要再次设置
Step3. 没有使用的导入会在文件保存时自动被删除,并且import顺序会根据Code
Style设置自动整理
[强制]安装Alibaba Java Coding Guidelines
Step1. 安装IDEA插件
插件名称:Alibaba Java Coding Guidelines
Step2. 打开实时规约扫描
Step3. 未满足规范的代码会在IDEA中自动提示
不同级别的规范会有不同的提示方式,比如红色波浪线、灰色波浪线、灰色背景等,鼠标hover会有具体提示
[强制]安装SonarLint插件
Step1. 安装SonarLint插件
在线安装时间可能较久,可以到官网下载后离线安装
Step2. 配置SonarLint
Mac OS: IntelliJ IDEA → Preferences → Other Settings → SonarLint General Settings
Windows: File → Settings → Other Settings → SonarLint General Settings
用户名密码:kocamgr1/D3WTCL7gs0@
SonarLint会自动从服务器拉取规则
Step3. 和Alibaba Java Guidelines一样,会根据规则级别不一样给出不同的提示
[强制]安装CheckStyle插件
Step1. 安装CheckStyle插件
Step2. 配置CheckStyle
Mac OS: IntelliJ IDEA → Preferences → Tools → Checkstyle
Windows: File → Settings → Tools → Checkstyle
注意:CheckStyle也是项目级配置,切换项目需重新配置
创建checkstyle.xml文件,文件内容在帖子最下面
参数填入checkstyle-header.txt和checkstyle-suppressions.xml即可
Step3. 使用checkstyle检查代码规范
[建议]提交代码时自动格式化并整理导入
注意:勾选的越多,检查时间越长
[建议]修改IDEA所有提示
红色代码:编译错误
红色波浪线:致命错误/编译错误
黄色背景:主要错误
黄色波浪线:主要错误
灰色代码:无用代码
绿色/灰色波浪线:拼写错误
配置文件
ProjectJavaCodeStyle.xml
<code_scheme name="Project" version="173">
<option name="LINE_SEPARATOR" value="
" />
<option name="WRAP_WHEN_TYPING_REACHES_RIGHT_MARGIN" value="true" />
<option name="FORMATTER_TAGS_ENABLED" value="true" />
<JavaCodeStyleSettings>
<option name="TEST_NAME_SUFFIX" value="Tests" />
<option name="ANNOTATION_PARAMETER_WRAP" value="1" />
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="20" />
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="20" />
<option name="IMPORT_LAYOUT_TABLE">
<value>
<package name="java" withSubpackages="true" static="false" />
<emptyLine />
<package name="javax" withSubpackages="true" static="false" />
<emptyLine />
<package name="" withSubpackages="true" static="false" />
<emptyLine />
<package name="com.szkingdom" withSubpackages="true" static="false" />
<emptyLine />
<package name="" withSubpackages="true" static="true" />
</value>
</option>
<option name="ENABLE_JAVADOC_FORMATTING" value="false" />
</JavaCodeStyleSettings>
<codeStyleSettings language="JAVA">
<option name="RIGHT_MARGIN" value="120" />
<option name="KEEP_LINE_BREAKS" value="false" />
<option name="KEEP_FIRST_COLUMN_COMMENT" value="false" />
<option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" />
<option name="BLANK_LINES_BEFORE_PACKAGE" value="1" />
<option name="BLANK_LINES_AROUND_FIELD" value="1" />
<option name="BLANK_LINES_AROUND_FIELD_IN_INTERFACE" value="1" />
<option name="BLANK_LINES_AFTER_CLASS_HEADER" value="1" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="CALL_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_WRAP" value="1" />
<option name="RESOURCE_LIST_WRAP" value="1" />
<option name="EXTENDS_LIST_WRAP" value="1" />
<option name="THROWS_LIST_WRAP" value="1" />
<option name="EXTENDS_KEYWORD_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="FOR_STATEMENT_WRAP" value="1" />
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
<option name="ASSIGNMENT_WRAP" value="1" />
<option name="ASSERT_STATEMENT_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="WRAP_LONG_LINES" value="true" />
<option name="PARAMETER_ANNOTATION_WRAP" value="1" />
<option name="VARIABLE_ANNOTATION_WRAP" value="2" />
<option name="ENUM_CONSTANTS_WRAP" value="2" />
<option name="WRAP_ON_TYPING" value="0" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
</codeStyleSettings>
</code_scheme>
checkstyle.xml
<!DOCTYPE module PUBLIC "-//Checkstyle//DTD Check Configuration 1.3//EN" "https://checkstyle.org/dtds/configuration_1_3.dtd">
<!--
This configuration file was written by the eclipse-cs plugin configuration editor
-->
<!--
Checkstyle-Configuration: KOCA-CS
Description: none
-->
<module name="Checker">
<property name="severity" value="warning"/>
<module name="TreeWalker">
<module name="AnnotationUseStyle">
<property name="elementStyle" value="compact"/>
</module>
<module name="MissingOverride"/>
<module name="PackageAnnotation"/>
<module name="AnnotationLocation">
<property name="allowSamelineSingleParameterlessAnnotation" value="false"/>
</module>
<module name="EmptyBlock">
<property name="option" value="text"/>
</module>
<module name="LeftCurly"/>
<module name="RightCurly"/>
<module name="NeedBraces"/>
<module name="AvoidNestedBlocks"/>
<module name="FinalClass"/>
<module name="InterfaceIsType"/>
<module name="HideUtilityClassConstructor"/>
<module name="MutableException"/>
<module name="InnerTypeLast"/>
<module name="OneTopLevelClass"/>
<module name="VisibilityModifier"/>
<module name="CovariantEquals"/>
<module name="DeclarationOrder"/>
<module name="DefaultComesLast"/>
<module name="EmptyStatement"/>
<module name="EqualsAvoidNull"/>
<module name="EqualsHashCode"/>
<module name="IllegalToken"/>
<module name="InnerAssignment"/>
<module name="MissingSwitchDefault"/>
<module name="ModifiedControlVariable">
<property name="skipEnhancedForLoopVariable" value="true"/>
</module>
<module name="MultipleVariableDeclarations"/>
<module name="NestedForDepth">
<property name="max" value="3"/>
</module>
<module name="NestedIfDepth">
<property name="max" value="3"/>
</module>
<module name="NestedTryDepth">
<property name="max" value="3"/>
</module>
<module name="NoFinalizer"/>
<module name="OneStatementPerLine"/>
<module name="PackageDeclaration"/>
<module name="RequireThis">
<property name="checkFields" value="false"/>
</module>
<module name="SimplifyBooleanExpression"/>
<module name="SimplifyBooleanReturn"/>
<module name="StringLiteralEquality"/>
<module name="AvoidStarImport"/>
<module name="AvoidStaticImport">
<property name="excludes" value="org.assertj.core.api.Assertions.*, org.junit.Assert.*, org.junit.Assume.*, org.junit.internal.matchers.ThrowableMessageMatcher.*, org.hamcrest.CoreMatchers.*, org.hamcrest.Matchers.*, org.springframework.boot.configurationprocessor.ConfigurationMetadataMatchers.*, org.springframework.boot.configurationprocessor.TestCompiler.*, org.springframework.boot.test.autoconfigure.AutoConfigurationImportedCondition.*, org.mockito.Mockito.*, org.mockito.BDDMockito.*, org.mockito.Matchers.*, org.mockito.ArgumentMatchers.*, org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.*, org.springframework.restdocs.hypermedia.HypermediaDocumentation.*, org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*, org.springframework.test.web.servlet.result.MockMvcResultMatchers.*, org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.*, org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*, org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.*, org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo, org.springframework.test.web.client.match.MockRestRequestMatchers.*, org.springframework.test.web.client.response.MockRestResponseCreators.*, org.springframework.web.reactive.function.server.RequestPredicates.*, org.springframework.web.reactive.function.server.RouterFunctions.*, org.springframework.test.web.servlet.setup.MockMvcBuilders.*"/>
</module>
<module name="IllegalImport"/>
<module name="ImportOrder">
<property name="option" value="bottom"/>
<property name="groups" value="java,/^javax?\./,*,com.szkingdom"/>
<property name="separated" value="true"/>
<property name="sortStaticImportsAlphabetically" value="true"/>
</module>
<module name="RedundantImport"/>
<module name="UnusedImports"/>
<module name="AtclauseOrder">
<property name="target" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF"/>
<property name="tagOrder" value="@param, @author, @since, @see, @version, @serial, @deprecated"/>
</module>
<module name="AtclauseOrder">
<property name="target" value="METHOD_DEF, CTOR_DEF, VARIABLE_DEF"/>
<property name="tagOrder" value="@param, @return, @throws, @since, @deprecated, @see"/>
</module>
<module name="JavadocMethod"/>
<module name="JavadocStyle">
<property name="checkEmptyJavadoc" value="true"/>
<property name="endOfSentenceFormat" value="([\s\S]$)"/>
</module>
<module name="JavadocTagContinuationIndentation">
<property name="offset" value="0"/>
</module>
<module name="JavadocType">
<property name="scope" value="package"/>
<property name="authorFormat" value=".+"/>
</module>
<module name="JavadocVariable">
<property name="scope" value="public"/>
</module>
<module name="NonEmptyAtclauseDescription"/>
<module name="ArrayTypeStyle"/>
<module name="CommentsIndentation">
<property name="tokens" value="BLOCK_COMMENT_BEGIN"/>
</module>
<module name="OuterTypeFilename"/>
<module name="UpperEll"/>
<module name="RedundantModifier"/>
<module name="RegexpSinglelineJava">
<property name="format" value="org\.mockito\.Mockito\.(when|doThrow|doAnswer)"/>
<property name="message" value="Please use BDDMockito "/>
<property name="ignoreComments" value="true"/>
</module>
<module name="RegexpSinglelineJava">
<property name="format" value="org\.junit\.Assert\.assert"/>
<property name="message" value="Please use AssertJ "/>
<property name="ignoreComments" value="true"/>
</module>
<module name="RegexpSinglelineJava">
<property name="format" value="System\.[out|err]\.print(ln)?\("/>
<property name="ignoreComments" value="true"/>
</module>
<module name="RegexpSinglelineJava">
<property name="format" value="[e|ex]\.printStackTrace\(\)"/>
<property name="ignoreComments" value="true"/>
</module>
<module name="LineLength">
<property name="ignorePattern" value="^ \* +.*$"/>
<property name="max" value="120"/>
</module>
<module name="EmptyLineSeparator">
<property name="allowNoEmptyLineBetweenFields" value="true"/>
<property name="allowMultipleEmptyLines" value="false"/>
<property name="allowMultipleEmptyLinesInsideClassMembers" value="false"/>
</module>
<module name="GenericWhitespace"/>
<module name="MethodParamPad"/>
<module name="NoWhitespaceAfter">
<property name="tokens" value="BNOT, DEC, DOT, INC, LNOT, UNARY_MINUS, UNARY_PLUS, ARRAY_DECLARATOR"/>
</module>
<module name="NoWhitespaceBefore"/>
<module name="ParenPad"/>
<module name="TypecastParenPad"/>
<module name="WhitespaceAfter"/>
<module name="WhitespaceAround"/>
<module name="SuppressionCommentFilter"/>
</module>
<module name="RegexpHeader">
<property name="headerFile" value="${checkstyle.header.file}"/>
<property name="fileExtensions" value="java"/>
</module>
<module name="NewlineAtEndOfFile">
<property name="lineSeparator" value="lf"/>
</module>
<module name="FileTabCharacter">
<property name="eachLine" value="true"/>
</module>
<module name="SuppressionFilter">
<property name="file" value="${checkstyle.suppression.filter}"/>
</module>
</module>
checkstyle-suppressions.xml
<?xml version="1.0"?>
<!DOCTYPE suppressions PUBLIC
"-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN"
"https://checkstyle.org/dtds/suppressions_1_2.dtd">
<suppressions>
<suppress files="[\\/]src[\\/]test[\\/]" checks=".*"/>
<suppress files="[\\/]target[\\/]" checks=".*"/>
<suppress files="[/\\]\..+" checks=".*"/>
<suppress files="generated-sources" checks="[a-zA-Z0-9]*"/>
<suppress files=".*Application\.java$" checks=".*"/>
<suppress files=".+\.(?:txt|xml|csv|sh|thrift|html|sql|eot|ttf|woff|css|png|yml|properties)$" checks=".*"/>
</suppressions>
checkstyle-header.txt
^/\*$
^ \* <p>文件名称: [\w-]*\.java</p>$
^ \* <p>项目描述: KOCA 金证云原生平台 [\w\W.]*</p>$
^ \* <p>公司名称: 深圳市金证科技股份有限公司</p>$
^ \* <p>版权所有: \(C\) (20\d\d-)?20\d\d</p>$
^ \*/$