數據庫的簡單建模
654
2025-04-04
5、分環境配置
類型
dev
test
uat
prod
環境定義:
public class EnvConstant { public static final String ENV_DEV = "dev"; public static final String ENV_TEST = "test"; public static final String ENV_UAT = "uat"; // similar to staging public static final String ENV_PROD = "prod"; }
環境配置:
// environment related configuration @Data @Builder public class EnvConfig { private String name; private boolean debug; private String externalApex; private String internalApex; private String scheme; @Getter(AccessLevel.NONE) @Setter(AccessLevel.NONE) private static Map
開發測試環境禁用 Sentry 異常日志:
@Aspect @Slf4j public class SentryClientAspect { @Autowired EnvConfig envConfig; @Around("execution(* io.sentry.SentryClient.send*(..))") public void around(ProceedingJoinPoint joinPoint) throws Throwable { // no sentry logging in debug mode if (envConfig.isDebug()) { log.debug("no sentry logging in debug mode"); return; } joinPoint.proceed(); } }
Sentry 是統一的異常管理平臺,支持異常事件的收集、展示、告警等功能。
6、異步調用處理
ThreadPoolTaskExecutor:
AsyncExecutor 配置:
Configuration @EnableAsync @Import(value = {StaffjoyRestConfig.class}) @SuppressWarnings(value = "Duplicates") public class AppConfig { public static final String ASYNC_EXECUTOR_NAME = "asyncExecutor"; @Bean(name=ASYNC_EXECUTOR_NAME) public Executor asyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setTaskDecorator(new ContextCopyingDecorator()); executor.setCorePoolSize(3); executor.setMaxPoolSize(5); executor.setQueueCapacity(100); executor.setWaitForTasksToCompleteOnShutdown(true); executor.setThreadNamePrefix("AsyncThread-"); executor.initialize(); return executor; } }
Async 標注:
@Async(AppConfig.ASYNC_EXECUTOR_NAME) public void trackEventAsync(String userId, String eventName) { if (envConfig.isDebug()) { logger.debug("intercom disabled in dev & test environment"); return; } Event event = new Event() .setUserID(userId) .setEventName("v2_" + eventName) .setCreatedAt(Instant.now().toEpochMilli()); try { Event.create(event); } catch (Exception ex) { String errMsg = "fail to create event on Intercom"; handleException(logger, ex, errMsg); throw new ServiceException(errMsg, ex); } logger.debug("updated intercom"); }
線程上下文拷貝:
// https://stackoverflow.com/questions/23732089/how-to-enable-request-scope-in-async-task-executor public class ContextCopyingDecorator implements TaskDecorator { @Override public Runnable decorate(Runnable runnable) { RequestAttributes context = RequestContextHolder.currentRequestAttributes(); return () -> { try { RequestContextHolder.setRequestAttributes(context); runnable.run(); } finally { RequestContextHolder.resetRequestAttributes(); } }; } }
@Configuration @EnableAsync @Import(value = {StaffjoyRestConfig.class}) @SuppressWarnings(value = "Duplicates") public class AppConfig { public static final String ASYNC_EXECUTOR_NAME = "asyncExecutor"; @Bean(name=ASYNC_EXECUTOR_NAME) public Executor asyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); // for passing in request scope context executor.setTaskDecorator(new ContextCopyingDecorator()); executor.setCorePoolSize(3); executor.setMaxPoolSize(5); executor.setQueueCapacity(100); executor.setWaitForTasksToCompleteOnShutdown(true); executor.setThreadNamePrefix("AsyncThread-"); executor.initialize(); return executor; } }
7、Swagger 配置
@Configuration @EnableSwagger2 public class SwaggerConfig { @Bean public Docket api() { return new Docket(DocumentationType.SWAGGER_2) .select() //為當前包下controller生成API文檔 .apis(RequestHandlerSelectors.basePackage("com.7d.PmsBrand.controller")) .paths(PathSelectors.any()) .build() .apiInfo(apiEndPointsInfo()) .useDefaultResponseMessages(false); } private ApiInfo apiEndPointsInfo() { return new ApiInfoBuilder().title("PmsBrand REST API") .description("7d Account REST API") .contact(new Contact("7d", "https://zuozewei.blog.csdn.net", "zuozewei@hotmail.com")) .license("The MIT License") .licenseUrl("https://opensource.org/licenses/MIT") .version("V2") .build(); } }
給 Controller 添加 Swagger 注解:
/** * 品牌管理Controller */ @Api(tags = "PmsBrandController", description = "商品品牌管理") @Controller @RequestMapping("/brand") public class PmsBrandController { @Autowired private PmsBrandService brandService; private static final Logger LOGGER = LoggerFactory.getLogger(PmsBrandController.class); @ApiOperation("獲取所有品牌列表") @RequestMapping(value = "listAll", method = RequestMethod.GET) @ResponseBody public CommonResult> getBrandList() { return CommonResult.success(brandService.listAllBrand()); } @ApiOperation("添加品牌") @RequestMapping(value = "/create", method = RequestMethod.POST) @ResponseBody public CommonResult createBrand(@RequestBody PmsBrand pmsBrand) { CommonResult commonResult; int count = brandService.createBrand(pmsBrand); if (count == 1) { commonResult = CommonResult.success(pmsBrand); LOGGER.debug("createBrand success:{}", pmsBrand); } else { commonResult = CommonResult.failed("操作失敗"); LOGGER.debug("createBrand failed:{}", pmsBrand); } return commonResult; } @ApiOperation("更新指定id品牌信息") @RequestMapping(value = "/update/{id}", method = RequestMethod.POST) @ResponseBody public CommonResult updateBrand(@PathVariable("id") Long id, @RequestBody PmsBrand pmsBrandDto, BindingResult result) { CommonResult commonResult; int count = brandService.updateBrand(id, pmsBrandDto); if (count == 1) { commonResult = CommonResult.success(pmsBrandDto); LOGGER.debug("updateBrand success:{}", pmsBrandDto); } else { commonResult = CommonResult.failed("操作失敗"); LOGGER.debug("updateBrand failed:{}", pmsBrandDto); } return commonResult; } @ApiOperation("刪除指定id的品牌") @RequestMapping(value = "/delete/{id}", method = RequestMethod.GET) @ResponseBody public CommonResult deleteBrand(@PathVariable("id") Long id) { int count = brandService.deleteBrand(id); if (count == 1) { LOGGER.debug("deleteBrand success :id={}", id); return CommonResult.success(null); } else { LOGGER.debug("deleteBrand failed :id={}", id); return CommonResult.failed("操作失敗"); } } @ApiOperation("分頁查詢品牌列表") @RequestMapping(value = "/list", method = RequestMethod.GET) @ResponseBody public CommonResult
修改 MyBatis Generator 注釋的生成規則:
CommentGenerator為MyBatis Generator的自定義注釋生成器,修改addFieldComment方法使其生成Swagger的@ApiModelProperty注解來取代原來的方法注釋,添加addJavaFileComment方法,使其能在import中導入@ApiModelProperty,否則需要手動導入該類,在需要生成大量實體類時,是一件非常麻煩的事。
/** * 自定義注釋生成器 */ public class CommentGenerator extends DefaultCommentGenerator { private boolean addRemarkComments = false; private static final String EXAMPLE_SUFFIX="Example"; private static final String API_MODEL_PROPERTY_FULL_CLASS_NAME="io.swagger.annotations.ApiModelProperty"; /** * 設置用戶配置的參數 */ @Override public void addConfigurationProperties(Properties properties) { super.addConfigurationProperties(properties); this.addRemarkComments = StringUtility.isTrue(properties.getProperty("addRemarkComments")); } /** * 給字段添加注釋 */ @Override public void addFieldComment(Field field, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn) { String remarks = introspectedColumn.getRemarks(); //根據參數和備注信息判斷是否添加備注信息 if(addRemarkComments&&StringUtility.stringHasValue(remarks)){ // addFieldJavaDoc(field, remarks); //數據庫中特殊字符需要轉義 if(remarks.contains("\"")){ remarks = remarks.replace("\"","'"); } //給model的字段添加swagger注解 field.addJavaDocLine("@ApiModelProperty(value = \""+remarks+"\")"); } } /** * 給model的字段添加注釋 */ private void addFieldJavaDoc(Field field, String remarks) { //文檔注釋開始 field.addJavaDocLine("/**"); //獲取數據庫字段的備注信息 String[] remarkLines = remarks.split(System.getProperty("line.separator")); for(String remarkLine:remarkLines){ field.addJavaDocLine(" * "+remarkLine); } addJavadocTag(field, false); field.addJavaDocLine(" */"); } @Override public void addJavaFileComment(CompilationUnit compilationUnit) { super.addJavaFileComment(compilationUnit); //只在model中添加swagger注解類的導入 if(!compilationUnit.isJavaInterface()&&!compilationUnit.getType().getFullyQualifiedName().contains(EXAMPLE_SUFFIX)){ compilationUnit.addImportedType(new FullyQualifiedJavaType(API_MODEL_PROPERTY_FULL_CLASS_NAME)); } } }
運行代碼生成器重新生成 mbg 包中的代碼:
運行com.7d.mall.tiny.mbg.Generator 的 main方法,重新生成 mbg 中的代碼,可以看到 PmsBrand 類中已經自動根據數據庫注釋添加了@ApiModelProperty注解
8、前后端分離跨域
CORS全稱Cross-Origin Resource Sharing,意為跨域資源共享。當一個資源去訪問另一個不同域名或者同域名不同端口的資源時,就會發出跨域請求。如果此時另一個資源不允許其進行跨域資源訪問,那么訪問的那個資源就會遇到跨域問題。
覆蓋默認的CorsFilter
添加GlobalCorsConfig配置文件來允許跨域訪問。
設置 SpringSecurity 允許 OPTIONS 請求訪問
在SecurityConfig類的configure(HttpSecurity httpSecurity) 方法中添加如下代碼。
.antMatchers(HttpMethod.OPTIONS)//跨域請求會先進行一次options請求 .permitAll()
9、統一訪問日志記錄
AOP 通過在 controller 層建一個切面來實現接口訪問的統一日志記錄。
添加日志信息封裝類 WebLog
用于封裝需要記錄的日志信息,包括操作的描述、時間、消耗時間、url、請求參數和返回結果等信息。
/** * Controller層的日志封裝類 */ public class WebLog { /** * 操作描述 */ private String description; /** * 操作用戶 */ private String username; /** * 操作時間 */ private Long startTime; /** * 消耗時間 */ private Integer spendTime; /** * 根路徑 */ private String basePath; /** * URI */ private String uri; /** * URL */ private String url; /** * 請求類型 */ private String method; /** * IP地址 */ private String ip; /** * 請求參數 */ private Object parameter; /** * 請求返回的結果 */ private Object result; //省略了getter,setter方法 }
添加切面類 WebLogAspect:
定義了一個日志切面,在環繞通知中獲取日志需要的信息,并應用到controller層中所有的public方法中去。
/** * 統一日志處理切面 */ @Aspect @Component @Order(1) public class WebLogAspect { private static final Logger LOGGER = LoggerFactory.getLogger(WebLogAspect.class); @Pointcut("execution(public * com.dunsan.mall.tiny.controller.*.*(..))") public void webLog() { } @Before("webLog()") public void doBefore(JoinPoint joinPoint) throws Throwable { } @AfterReturning(value = "webLog()", returning = "ret") public void doAfterReturning(Object ret) throws Throwable { } @Around("webLog()") public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable { long startTime = System.currentTimeMillis(); //獲取當前請求對象 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); //記錄請求信息 WebLog webLog = new WebLog(); Object result = joinPoint.proceed(); Signature signature = joinPoint.getSignature(); MethodSignature methodSignature = (MethodSignature) signature; Method method = methodSignature.getMethod(); if (method.isAnnotationPresent(ApiOperation.class)) { ApiOperation apiOperation = method.getAnnotation(ApiOperation.class); webLog.setDescription(apiOperation.value()); } long endTime = System.currentTimeMillis(); String urlStr = request.getRequestURL().toString(); webLog.setBasePath(StrUtil.removeSuffix(urlStr, URLUtil.url(urlStr).getPath())); webLog.setIp(request.getRemoteUser()); webLog.setMethod(request.getMethod()); webLog.setParameter(getParameter(method, joinPoint.getArgs())); webLog.setResult(result); webLog.setSpendTime((int) (endTime - startTime)); webLog.setStartTime(startTime); webLog.setUri(request.getRequestURI()); webLog.setUrl(request.getRequestURL().toString()); LOGGER.info("{}", JSONUtil.parse(webLog)); return result; } /** * 根據方法和傳入的參數獲取請求參數 */ private Object getParameter(Method method, Object[] args) { List
10、打包方式
jar
docker
服務配置文件處理方式:
對于各個項目分環境部署,最麻煩的就是配置文件的問題,不同的環境需要加載不同的配置,好在 Spring Boot 框架加載配置是非常方便的,我們可以針對不同的環境分別配置不同的配置文件,這里有兩個地方要注意一下:
構建鏡像的時候,盡量實現一個鏡像支持所有環境(即所有配置都打到一個鏡像里面去),在容器啟動時指定加載哪個環境配置即可,例如:在部署容器時指定 args: ["–spring.profiles.active=prod"] 參數啟動。
盡量不要每個環境打出來一個鏡像版本,傳統方式在構建的時候指定 -D prod 配置 Profile 來指定加載哪個配置,來生成不同的產物 jar,容器化部署后不需要這樣,那樣后期控制各鏡像版本發布會比較麻煩。
鏡像可以分為基礎鏡像和應用鏡像:
基礎鏡像要求體積盡量小,方便拉取,同時安裝一些必要的軟件,方便后期進入容器內排查問題,我們需要準備好服務運行的底層系統鏡像,比如 Centos、Ubuntu 等常見 Linux 操作系統,然后基于該系統鏡像,構建服務運行需要的環境鏡像,比如一些常見組合:Centos + Jdk、Centos + Jdk + Tomcat、Centos + nginx 等,由于不同的服務運行依賴的環境版本不一定一致,所以還需要制作不同版本的環境鏡像,例如如下基礎鏡像版本。
Centos6.5 + Jdk1.8: registry.docker.com/baseimg/centos-jdk:6.5_1.8
Centos7.5 + Jdk1.8: registry.docker.com/baseimg/centos-jdk:7.5_1.8
Centos7.5 + Jdk1.7: registry.docker.com/baseimg/centos-jdk:7.5_1.7
Centos7 + Tomcat8 + Jdk1.8: registry.docker.com/baseimg/centos-tomcat-jdk:7.5_8.5_1.8
Centos7 + Nginx: registry.docker.com/baseimg/centos-tomcat-jdk:7.5_1.10.2
…
這樣,就可以標識該基礎鏡像的系統版本及軟件版本,方便后邊選擇對應的基礎鏡像來構建應用鏡像
有了上邊的基礎鏡像后,就很容易構建出對應的應用鏡像了,例如一個簡單的應用鏡像 Dockerfile 如下:
FROM registry.docker.com/baseimg/centos-jdk:7.5_1.8 COPY app-name.jar /opt/project/app.jar EXPOSE 8080 ENTRYPOINT ["/java", "-jar", "/opt/project/app.jar"]
當然,這里我建議使用另一種方式來啟動服務,將啟動命令放在統一 shell 啟動腳本執行,例如如下Dockerfile 示例:
FROM registry.docker.com/baseimg/centos-jdk:7.5_1.8 COPY app-name.jar /opt/project/app.jar COPY entrypoint.sh /opt/project/entrypoint.sh EXPOSE 8080 ENTRYPOINT ["/bin/sh", "/opt/project/entrypoint.sh"]
將服務啟動命令配置到 entrypoint.sh,這樣我們可以擴展做很多事情,比如啟動服務前做一些初始化操作等,還可以向容器傳遞參數到腳本執行一些特殊操作,而且這里變成腳本來啟動,這樣后續構建鏡像基本不需要改 Dockerfile 了。
#!/bin/bash # do other things here java -jar $JAVA_OPTS /opt/project/app.jar > /dev/null 2>&1
上邊示例中,我們就注入 $JAVA_OPTS 環境變量,來優化 JVM 參數,還可以傳遞一個變量,這個變量大家應該就猜到了,就是服務啟動加載哪個配置文件參數,例如:–spring.profiles.active=prod
十、技術選型(參考)
1、代碼生成工具
MyBatis Generator
MyBatis Generator是 MyBatis 的代碼生成器,支持為 MyBatis 的所有版本生成代碼。非常容易及快速生成 Mybatis 的Java POJO文件及數據庫 Mapping 文件。
2、核心框架
SpringBoot 2.x
SpringBoot 它使用“習慣優于配置”(項目中存在大量的配置,此外還內置一個習慣性的配置,讓你無須手動進行配置)的理念讓 Java 項目快速運行起來。使用 SpringBoot 很容易創建一個獨立運行(運行 Jar ,內嵌 Servlet 容器)、準生產級別的基于 Spring 的框架項目,使用 SpringBoot 你可以不用或者只需要很少的 Spring 配置。
用白話來理解,就是 SpringBoot 其實不是什么新框架,它默認配置了很多框架的使用方式,就像 Maven 整合了所有的 Jar 包,SpringBoot 整合了幾乎所有的框架。
官網:https://spring.io/projects/spring-boot
3、日志框架
Logback
LogBack 是 Log4j 的改良版本,比 Log4j 擁有更多的特性,同時也帶來很大性能提升,同時天然支持SLF4J。
LogBack 官方建議配合 Slf4j 使用,這樣可以靈活地替換底層日志框架。
官網:http://logback.qos.ch/
4、持久層框架
Mybatis 3
MyBatis 是一款優秀的持久層框架,它支持定制化 SQL、存儲過程以及高級映射。MyBatis 避免了幾乎所有的 JDBC 代碼和手動設置參數以及獲取結果集。MyBatis 可以使用簡單的 XML 或注解來配置和映射原生類型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 對象)為數據庫中的記錄。
5、連接池
阿里 druid
Druid 是一個關系型數據庫連接池,它是阿里巴巴的一個開源項目。Druid 支持所有 JDBC 兼容數據庫,包括了Oracle、MySQL、PostgreSQL、SQL Server、H2等。
Druid 在監控、可擴展性、穩定性和性能方面具有明顯的優勢。通過 Druid 提供的監控功能,可以實時觀察數據庫連接池和SQL查詢的工作情況。使用 Druid 連接池在一定程度上可以提高數據訪問效率。
官網:https://druid.apache.org/
6、SQL攔截工具
P6Spy
p6spy 是一個開源項目,通常使用它來跟蹤數據庫操作,查看程序運行過程中執行的sql語句。
官網:https://github.com/p6spy/p6spy
7、多數據源啟動器
dynamic-datasource-spring-boot-starter
dynamic-datasource-spring-boot-starter 是一個基于 springboot 的快速集成多數據源的啟動器。
其支持 Jdk 1.7+, SpringBoot 1.4.x、1.5.x、 2.0.x。
官網:https://github.com/baomidou/dynamic-datasource-spring-boot-starter
8、分頁插件
MyBatis PageHelper
MyBatis PageHelper 實現了通用的分頁查詢,其支持的數據有,mysql、Oracle、DB2、PostgreSQL等主流的數據庫。
github: https://github.com/pagehelper/Mybatis-PageHelper
PageHelper.startPage(pageNum, pageSize); //之后進行查詢操作將自動進行分頁 List
9、API文檔
swagger2.0
Swagger是一款Restful 接口的文檔在線自動生成、功能測試框架。一個規范和完整的框架,用于生成、描述、調用和可視化Restful 風格的Web服務,加上Swagger-UI,可以有很好的呈現。
十一、開發環境(推薦)
1、開發插件
Lombok
Lombok 項目是一個 Java 庫,它會自動插入您的編輯器和構建工具中,從而使您的Java更加生動有趣。
永遠不要再寫另一個 getter 或 equals 方法,帶有一個注釋的您的類有一個功能全面的生成器,自動化您的日志記錄變量等等。
官網:https://projectlombok.org/
Hutool
Hutool 是一個小而全的Java工具類庫,它幫助我們簡化每一行代碼,避免重復造輪子。如果你有需要用到某些工具類的時候,不妨在 Hutool 里面找找。
官網:https://www.hutool.cn/
2、JDK
SUN JDK1.8及以上
3、構建工具
Maven 3.5.4及以上
Maven 作為一個構建工具,不僅能幫我們自動化構建,還能夠抽象構建過程,提供構建任務實現;它跨平臺,對外提供了一致的操作接口,這一切足以使它成為優秀的、流行的構建工具。
Maven 不僅是構建工具,還是一個依賴管理工具和項目管理工具,它提供了中央倉庫,能幫助我們自動下載構件。
官網:https://maven.apache.org/
4、Git 不限
5、數據庫
MySQL 5.7及以上
Navicat Premium 11.2.7及以上
MySQL是一個關系型數據庫管理系統,由瑞典 MySQL AB 公司開發,目前屬于 Oracle 旗下產品。MySQL 是最流行的關系型數據庫管理系統之一,在 WEB 應用方面,MySQL是最好的 RDBMS (Relational Database Management System,關系數據庫管理系統) 應用軟件之一。
MySQL是一種關系數據庫管理系統,關系數據庫將數據保存在不同的表中,而不是將所有數據放在一個大倉庫內,這樣就增加了速度并提高了靈活性。
MySQL所使用的 SQL 語言是用于訪問數據庫的最常用標準化語言。MySQL 軟件采用了雙授權政策,分為社區版和商業版,由于其體積小、速度快、總體擁有成本低,尤其是開放源碼這一特點,一般中小型網站的開發都選擇 MySQL 作為網站數據庫。
----- 摘抄自百度百科
官網:https://www.mysql.com/
6、IDE
IntelliJ IDEA 2020.1
推薦插件:
Free MyBatis plugin:對MyBatis的xml具有強大的提示功能,同時可以關聯mapper接口和mapper.xml中的sql實現。
Lombok plugin:Lombok為Java語言添加了非常有趣的附加功能,你可以不用再為實體類手寫getter,setter等方法,通過一個注解即可擁有。
MyBatis Log Plugin:把Mybatis輸出的SQL日志還原成完整的SQL語句。
RestfulToolkit:一套Restful服務開發輔助工具集,提供了項目中的接口概覽信息,可以根據URL跳轉到對應的接口方法中去,內置了HTTP請求工具,對請求方法做了一些增強功能。
GsonFormat:這款插件可以把JSON格式的字符串轉化為實體類,當我們要根據JSON字符串來創建實體類的時候用起來很方便。
Grep Console:一款幫你分析控制臺日志的插件,可以對不同級別的日志進行不同顏色的高亮顯示,還可以用來按關鍵字搜索日志內容。
Alibaba Java Coding Guidelines:阿里巴巴《Java 開發手冊》配套插件,可以實時檢測代碼中不符合手冊規約的地方,助你碼出高效,碼出質量。
Maven Helper:解決Maven依賴沖突的好幫手,可以快速查找項目中的依賴沖突,并予以解決
Statistic:一款代碼統計工具,可以用來統計當前項目中代碼的行數和大小。
Vue.js:Vue.js支持插件,可以根據模板創建.vue文件,也可以對Vue相關代碼進行智能提示。
element:Element-UI支持插件,可以對Element-UI中的標簽進行智能提示,有了它就不用盲寫相關代碼了!
7、其他工具
Postman:API接口調試工具。
https://www.postman.com/
PowerDesigner:數據庫設計工具,平時用來設計數據庫表,設計完成之后可以直接導出數據庫表
RedisDesktop:Redis可視化工具,平時用來查看和管理Redis緩存中的數據,有時候需要清空緩存的時候就用到它了。
https://rdm.dev/
Robomongo:MongoDB可視化工具,平時用來查看和管理MongoDB中的數據。
https://robomongo.org/download
X-shell:一款強大的安全終端模擬軟件,可以用來連接和管理遠程linux服務器。-
https://www.netsarang.com/zh/all-downloads/
ProcessOn:作圖工具,可以用來制作思維導圖和流程圖。
processon.com
Snipaste:一款好用的截屏工具。
www.snipaste.com
十二、代碼提交規范
1、基本原則
Git 代碼完整提交正確姿勢,建議先 Commit,再 Pull,最后 Push;
代碼提交前,保證本地編譯通過;
代碼提交時,保證代碼、文件完整提交,不要把本地測試代碼、配置提交上去了;
代碼每次獨立的功能、模塊修改,都 Commit 到本地(不急每次都 Push);
創建本地開發分支,完成后合并到特性分支,特性分支不可 push。
2、提交注釋規則
格式:[type: description] #[相關任務編號]
2.1、type
fix: 修復bug
add: 新功能
update: 更新
style : 代碼格式改變
test: 增加測試代碼
revert: 撤銷上一次的commit
build: 構建工具或構建過程等的變動,如:gulp 換成了 webpack,webpack 升級等
2.2、description
description 是對本次提交的簡短描述;
不超過50個字符;
推薦以動詞開頭,如: 設置、修改、增加、刪減、撤銷等。
3、示例
fix:修復登錄正確提示不準確缺陷 #demo-1243 add:添加登錄攔截校驗功能 #demo-1240 update:刪除登陸彈出框提示 #demo-1241 test:增加控制接口測試用例 #demo-1242
關聯任務單/缺陷單編號,例如:“demo-124”;
《java開發手冊》v1.7.0 嵩山版:
https://github.com/zuozewei/blog-example/blob/master/Java-api-test/12-Alibaba Java Coding Guidelines/《java開發手冊》v1.7.0 嵩山版.pdf
參考資料:
[1]:《java開發手冊》v1.7.0 嵩山版》
[2]:《Spring Boot & Kubernetes 云原生微服務實踐》
Java
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。