SpringBoot 項目模板:擺脫步步搭建

前言

在我的工作中倦春,我從零開始搭建了不少軟件項目户敬,其中包含了基礎(chǔ)代碼框架和持續(xù)集成基礎(chǔ)設(shè)施等,這些內(nèi)容在敏捷開發(fā)中通常被稱為“第0個迭代”要做的事情睁本。但是尿庐,當(dāng)項目運行了一段時間之后再來反觀,我總會發(fā)現(xiàn)一些不足的地方呢堰,要么測試分類沒有分好抄瑟,要么基本的編碼架子沒有考慮周全。

另外枉疼,我在工作中也會接觸到很多既有項目皮假,公司內(nèi)部和外部的都有鞋拟,多數(shù)項目的編碼實踐我都是不滿意的。比如惹资,我曾經(jīng)新加入一個項目的時候严卖,前前后后請教了3位同事才把該項目在本地運行起來;又比如在另一項目中布轿,我發(fā)現(xiàn)前端請求對應(yīng)的Java類命名規(guī)范不統(tǒng)一哮笆,有被后綴為Request的,也有被后綴為Command的汰扭。

再者稠肘,工作了這么多年之后,我越來越發(fā)現(xiàn)基礎(chǔ)知識以及系統(tǒng)性學(xué)習(xí)的重要性萝毛。誠然项阴,技術(shù)框架的發(fā)展使得我們可以快速地實現(xiàn)業(yè)務(wù)功能,但是當(dāng)軟件出了問題之后有時卻需要將各方面的知識融會貫通并在大腦里綜合反應(yīng)才能找到解決思路笆包。

基于以上环揽,我希望整理出一套公共性的項目模板出來,旨在盡量多地包含日常開發(fā)之所需庵佣,減少開發(fā)者的重復(fù)性工作以及提供一些最佳實踐歉胶。對于后端開發(fā)而言,我選擇了當(dāng)前被行業(yè)大量使用的Spring Boot巴粪,基于此整理出了一套公共的通今、基礎(chǔ)性的實踐方式,在結(jié)合了自己的經(jīng)驗以及其他項目的優(yōu)秀實踐之后肛根,總結(jié)出本文以饗開發(fā)者辫塌。

本文以一個簡單的電商訂單系統(tǒng)為例,源代碼請訪問:

git clone https://github.com/e-commerce-sample/order-backend
git checkout a443dace

所使用的技術(shù)棧主要包括:Spring Boot派哲、Gradle臼氨、MySQL、Junit 5芭届、Rest Assured储矩、Docker等。

從寫好README開始

一份好的README可以給人以項目全景概覽喉脖,可以使新人快速上手項目椰苟,可以降低溝通成本抑月。同時树叽,README應(yīng)該簡明扼要,條理清晰谦絮,建議包含以下方面:

  • 項目簡介:用一兩句話簡單描述該項目所實現(xiàn)的業(yè)務(wù)功能题诵;

  • 技術(shù)選型:列出項目的技術(shù)棧洁仗,包括語言、框架和中間件等性锭;

  • 本地構(gòu)建:列出本地開發(fā)過程中所用到的工具命令赠潦;

  • 領(lǐng)域模型:核心的領(lǐng)域概念,比如對于示例電商系統(tǒng)來說有Order草冈、Product等她奥;

  • 測試策略:自動化測試如何分類,哪些必須寫測試怎棱,哪些沒有必要寫測試哩俭;

  • 技術(shù)架構(gòu):技術(shù)架構(gòu)圖;

  • 部署架構(gòu):部署架構(gòu)圖拳恋;

  • 外部依賴:項目運行時所依賴的外部集成方凡资,比如訂單系統(tǒng)會依賴于會員系統(tǒng);

  • 環(huán)境信息:各個環(huán)境的訪問方式谬运,數(shù)據(jù)庫連接等隙赁;

  • 編碼實踐:統(tǒng)一的編碼實踐,比如異常處理原則梆暖、分頁封裝等伞访;

  • FAQ:開發(fā)過程中常見問題的解答。

需要注意的是轰驳,README中的信息可能隨著項目的演進(jìn)而改變(比如引入了新的技術(shù)椄琅ぃ或者加入了新的領(lǐng)域模型),因此也是需要持續(xù)更新的滑废。雖然我們知道蝗肪,軟件文檔的一個痛點便是無法與項目實際進(jìn)展保持同步,但是就README這點信息來講蠕趁,還是建議開發(fā)者們不要吝嗇那一點點敲鍵盤的時間薛闪。

此外,除了保持README的持續(xù)更新俺陋,一些重要的架構(gòu)決定可以通過示例代碼的形式記錄在代碼庫中豁延,新開發(fā)者可以通過直接閱讀這些示例代碼快速了解項目的通用實踐方式以及架構(gòu)選擇,請參考:

https://www.thoughtworks.com/radar/techniques/lightweight-architecture-decision-records

一鍵式本地構(gòu)建

為了避免諸如前文中所提到的“請教了3位同事才本地構(gòu)建成功”的尷尬腊状,為了減少“懶惰”的程序員們的手動操作诱咏,也為了為所有開發(fā)者提供一種一致的開發(fā)體驗,我們希望用一個命令就可以完成所有的事情缴挖。這里袋狞,對于不同的場景我總結(jié)出了以下命令:

  • 生成IDE工程:idea.sh,生成IntelliJ工程文件并自動打開IntelliJ

  • 本地運行:run.sh,本地啟動項目苟鸯,自動啟動本地數(shù)據(jù)庫同蜻,監(jiān)聽調(diào)試端口5005

  • 本地構(gòu)建:local-build.sh,只有本地構(gòu)建成功才能提交代碼

以上3個命令基本上可以完成日常開發(fā)之所需早处,此時湾蔓,對于新人的開發(fā)流程大致為:

  • 拉取代碼;

  • 運行idea.sh砌梆,自動打開IntelliJ默责;

  • 編寫代碼,包含業(yè)務(wù)代碼和自動化測試咸包;

  • 運行run.sh傻丝,進(jìn)行本地調(diào)試或必要的手動測試(本步驟不是必需);

  • 運行l(wèi)ocal-build.sh诉儒,完成本地構(gòu)建葡缰;

  • 再次拉取代碼,保證local-build.sh成功忱反,提交代碼泛释。

事實上,這些命令腳本的內(nèi)容非常簡單温算,比如run.sh文件內(nèi)容為:

#!/usr/bin/env bash

然而怜校,這種顯式化的命令卻可以減少新人的恐懼感,因為他們只需要知道運行這3個命令就可以搞開發(fā)了注竿。另外茄茁,一個小小的細(xì)節(jié):本地構(gòu)建的local-build.sh命令本來可以重命名為更簡單的build.sh,但是當(dāng)我們在命令行中使用Tab鍵自動補全的時候巩割,會發(fā)現(xiàn)自動補全到了build目錄裙顽,而不是build.sh命令,并不方便宣谈,因此命名為了local-build.sh愈犹。

細(xì)節(jié)雖小,但是卻體現(xiàn)了一個宗旨闻丑,即我們希望給開發(fā)者一種極簡的開發(fā)體驗漩怎,我把這些看似微不足道的東西稱作是對程序員的“人文關(guān)懷”。

目錄結(jié)構(gòu)

Maven所提倡的目錄結(jié)構(gòu)當(dāng)前已經(jīng)成為事實上的行業(yè)標(biāo)準(zhǔn)嗦嗡,Gradle在默認(rèn)情況下也采用了Maven的目錄結(jié)構(gòu)勋锤,這對于多數(shù)項目來說已經(jīng)足夠了。此外侥祭,除了Java代碼叁执,項目中還存在其他類型的文件茄厘,比如Gradle插件的配置、工具腳本和部署配置等徒恋。無論如何蚕断,項目目錄結(jié)構(gòu)的原則是簡單而有條理欢伏,不要隨意地增加多余的文件夾入挣,并且也需要及時重構(gòu)。

在示例項目中硝拧,頂層只有2個文件夾径筏,一個是用于放置Java源代碼和項目配置的src文件夾,另一個是用于放置所有Gradle配置的gradle文件夾障陶,此外滋恬,為了方便開發(fā)人員使用,將上文提到的3個常用腳本直接放到根目錄下:

└── order-backend

對于gradle而言抱究,我們刻意地將Gradle插件腳本與插件配置放到了一起恢氯,比如Checkstyle:

├── gradle

事實上,在默認(rèn)情況下Checkstyle插件會從項目根目錄下的config目錄查找checkstyle.xml配置文件鼓寺,但是這一方面增加了多余的文件夾勋拟,另一方面與該插件相關(guān)的設(shè)施分散在了不同的地方,違背了廣義上的內(nèi)聚原則妈候。

基于業(yè)務(wù)分包

早年的Java分包方式通常是基于技術(shù)的敢靡,比如與domain包平級的有controller包、service包和infrastructure包等苦银。這種方式當(dāng)前并不被行業(yè)所推崇啸胧,而是應(yīng)該首先基于業(yè)務(wù)分包。

比如幔虏,在訂單示例項目中纺念,有兩個重要的領(lǐng)域?qū)ο驩rder和Product(在DDD中稱為聚合根),所有的業(yè)務(wù)都圍繞它們展開想括,因此分別創(chuàng)建order包和product包柠辞,再分別在包下創(chuàng)建與之相關(guān)的各個子包。此時的order包如下:

├── order

可以看到主胧,在order包下我們直接放置了OrderController和OrderRepository等類叭首,而沒有必要再為這些類劃分單獨的子包。而對于領(lǐng)域模型Order來講踪栋,由于包含了多個對象焙格,因此基于內(nèi)聚性原則將它們歸到model包中。但是這并不是一個必須夷都,如果業(yè)務(wù)足夠簡單眷唉,我們甚至可以將所有類直接放到業(yè)務(wù)包下,product包便是如此:

└── product

在編碼實踐中,我們總是基于一個業(yè)務(wù)用例來實現(xiàn)代碼冬阳,在技術(shù)分包場景下蛤虐,我們需要在分散的各包中來回切換,增加了代碼導(dǎo)航的成本肝陪;另外驳庭,代碼提交的變更內(nèi)容也是散落的,在查看代碼提交歷史時氯窍,無法直觀的看出該次提交是關(guān)于什么業(yè)務(wù)功能的饲常。

在業(yè)務(wù)分包下,我們只需要在單個統(tǒng)一的包下修改代碼狼讨,減少了代碼導(dǎo)航成本贝淤;另外一個好處是,如果哪天我們需要將某個業(yè)務(wù)遷移到另外的項目(比如識別出了獨立的微服務(wù))政供,那么直接整體移動業(yè)務(wù)包即可播聪。

當(dāng)然,基于業(yè)務(wù)分包并不意味著所有的代碼都必須囿于業(yè)務(wù)包下布隔,這里的邏輯是:優(yōu)先進(jìn)行業(yè)務(wù)分包离陶,然后對于一些不隸屬于任何業(yè)務(wù)的代碼可以單獨分包,比如一些util類执泰、公共配置等枕磁。比如我們依然可以創(chuàng)建一個common包,下面放置了Spring公共配置术吝、異常處理框架和日志等子包:

└── common

自動化測試分類

在當(dāng)前的微服務(wù)和前后端分離的開發(fā)模式下计济,后端項目僅提供純粹的業(yè)務(wù)API,而不包含UI邏輯排苍,因此后端項目不會再包含諸如WebDriver的重量級端到端測試沦寂。同時,后端項目作為向外提供業(yè)務(wù)功能的獨立運行單元淘衙,在API級別也應(yīng)該有相應(yīng)的測試传藏。

此外,程序中有些框架性代碼彤守,要么是諸如Controller之類的技術(shù)性框架代碼毯侦,要么是基于某種架構(gòu)風(fēng)格的代碼(比如DDD實踐中的ApplicationService),這些代碼一方面并不包含業(yè)務(wù)邏輯具垫,一方面是很薄的一個抽象層(即實現(xiàn)相對簡單)侈离,用單元測試來覆蓋顯得沒有必要,因此筆者的觀點是可以不為此編寫單獨的單元測試筝蚕。歡迎關(guān)注公眾號"Java學(xué)習(xí)之道"卦碾,查看更多干貨铺坞!

再者,程序中有些重要的組件性代碼洲胖,比如訪問數(shù)據(jù)庫的Repository或者分布式鎖济榨,使用單元測試實際上“測不到點上”,而使用API測試又顯得在分類邏輯上不合理绿映,為此我們可以專門創(chuàng)建一種測試類型謂之組件測試擒滑。

基于以上,我們可以對自動化測試做個分類:

  • 單元測試:核心的領(lǐng)域模型绘梦,包括領(lǐng)域?qū)ο?比如Order類)橘忱,F(xiàn)actory類赴魁,領(lǐng)域服務(wù)類等卸奉;

  • 組件測試:不適合寫單元測試但是又必須測試的類,比如Repository類颖御,在有些項目中榄棵,這種類型測試也被稱為集成測試;

  • API測試:模擬客戶端測試各個API接口潘拱,需要啟動程序疹鳄。

Gradle在默認(rèn)情況下只提供src/test/java目錄用于測試,對于以上3種類型的測試芦岂,我們需要將它們分開以便于管理(也是職責(zé)分離的體現(xiàn))瘪弓。為此,可以通過Gradle提供的SourceSets對測試代碼進(jìn)行分類:

sourceSets {

到此禽最,3種類型的測試可以分別編寫在以下目錄:

  • 單元測試:src/test/java

  • 組件測試:src/componentTest/java

  • API測試:src/apiTest/java

需要注意的是腺怯,這里的API測試更多強調(diào)的是對業(yè)務(wù)功能的測試,有些項目中可能還會存在契約測試和安全測試等川无,雖然從技術(shù)上講都是對API的訪問呛占,但是這些測試都是單獨的關(guān)注點,因此建議分開對待懦趋。

值得一提的是晾虑,由于組件測試和API測試需要啟動程序,也即需要準(zhǔn)備好本地數(shù)據(jù)庫仅叫,我們采用了Gradle的docker-compose插件(或者jib插件)帜篇,該插件會在運行測試之前自動運行Docker容器(比如MySQL):

apply plugin: 'docker-compose'

更多的測試分類配置細(xì)節(jié),比如JaCoCo測試覆蓋率配置等诫咱,請參考本文的示例項目代碼笙隙。對Gradle不熟悉的讀者可以參考:

https://www.cnblogs.com/CloudTeng/p/3417762.html

日志處理

在日志處理中,除了完成基本配置外遂跟,還有2個需要考慮的點:

1逃沿、在日志中加入請求標(biāo)識婴渡,便于鏈路追蹤。在處理一個請求的過程中有時會輸出多條日志凯亮,如果每條日志都共享統(tǒng)一的請求ID边臼,那么在日志追蹤時會更加方便。此時假消,可以使用Logback原生提供的MDC(Mapped Diagnostic Context)功能柠并,創(chuàng)建一個RequestIdMdcFilter:

 protected void doFilterInternal(HttpServletRequest request,HttpServletResponse response,FilterChain filterChain)

2、集中式日志管理富拗,在多節(jié)點部署的場景下臼予,各個節(jié)點的日志是分散的,為此可以引入諸如ELK之類的工具將日志統(tǒng)一輸出到ElasticSearch中啃沪。本文的示例項目使用了RedisAppender將日志輸出到Logstash:

<appender name="REDIS" class="com.cwbase.logback.RedisAppender">

當(dāng)然粘拾,統(tǒng)一日志的方案還有很多,比如Splunk和Graylog等创千。

異常處理

在設(shè)計異常處理的框架時缰雇,需要考慮以下幾點:

  • 向客戶端提供格式統(tǒng)一的異常返回

  • 異常信息中應(yīng)該包含足夠多的上下文信息,最好是結(jié)構(gòu)化的數(shù)據(jù)以便于客戶端解析

  • 不同類型的異常應(yīng)該包含唯一標(biāo)識追驴,以便客戶端精確識別

異常處理通常有兩種形式械哟,一種是層級式的,即每種具體的異常都對應(yīng)了一個異常類殿雪,這些類最終繼承自某個父異常暇咆;另一種是單一式的,即整個程序中只有一個異常類丙曙,再以一個字段來區(qū)分不同的異常場景爸业。

層級式異常的好處是能夠顯式化異常含義,但是如果層級設(shè)計不好可能導(dǎo)致整個程序中充斥著大量的異常類河泳;單一式的好處是簡單沃呢,而其缺點在于表意性不夠。

本文的示例項目使用了層級式異常拆挥,所有異常都繼承自一個AppException:

public abstract class AppException extends RuntimeException {

這里薄霜,ErrorCode枚舉中包含了異常的唯一標(biāo)識、HTTP狀態(tài)碼以及錯誤信息纸兔;而data字段表示各個異常的上下文信息惰瓜。

在示例系統(tǒng)中,在沒有找到訂單時拋出異常:

public class OrderNotFoundException extends AppException {

在返回異常給客戶端時汉矿,通過一個ErrorDetail類來統(tǒng)一異常格式:

public final class ErrorDetail {

最終返回客戶端的數(shù)據(jù)為:

{

可以看到崎坊,ORDER_NOT_FOUND與data中的數(shù)據(jù)結(jié)構(gòu)是一一對應(yīng)的,也即對于客戶端來講洲拇,如果發(fā)現(xiàn)了ORDER_NOT_FOUND奈揍,那么便可確定data中一定存在orderId字段曲尸,進(jìn)而完成精確的結(jié)構(gòu)化解析。

后臺任務(wù)與分布式鎖

除了即時完成客戶端的請求外男翰,系統(tǒng)中通常會有一些定時性的例行任務(wù)另患,比如定期地向用戶發(fā)送郵件或者運行數(shù)據(jù)報表等;另外蛾绎,有時從設(shè)計上我們會對請求進(jìn)行異步化處理昆箕。此時,我們需要搭建后臺任務(wù)相關(guān)基礎(chǔ)設(shè)施租冠。Spring原生提供了任務(wù)處理(TaskExecutor)和任務(wù)計劃(TaskSchedulor)機制鹏倘;而在分布式場景下,還需要引入分布式鎖來解決并發(fā)沖突顽爹,為此我們引入一個輕量級的分布式鎖框架ShedLock纤泵。

啟用Spring任務(wù)配置如下:

@Configuration

然后配置Shedlock:

@Configuration

實現(xiàn)后臺任務(wù)處理:

 @Scheduled(cron = "0 0/1 * * * ?")

使用時在代碼中直接調(diào)用:

   public String doBusiness() {

本文的示例項目使用了基于JDBC的分布式鎖,事實上任何提供原子操作的機制都可用于分布式鎖话原,Shedlock還提供基于Redis夕吻、ZooKeeper和Hazelcast等的分布式鎖實現(xiàn)機制诲锹。

統(tǒng)一代碼風(fēng)格

除了Checkstyle統(tǒng)一代碼格式之外繁仁,項目中有些通用的公共的編碼實踐方式也需要在整個開發(fā)團隊中進(jìn)行統(tǒng)一,包括但不限于以下方面:

  • 客戶端的請求數(shù)據(jù)類統(tǒng)一使用相同后綴归园,比如Command

  • 返回給客戶端的數(shù)據(jù)統(tǒng)一使用相同后綴黄虱,比如Represetation

  • 統(tǒng)一對請求處理的流程框架,比如采用傳統(tǒng)的3層架構(gòu)或者DDD戰(zhàn)術(shù)模式

  • 提供一致的異常返回(請參考“異常處理”小節(jié))

  • 提供統(tǒng)一的分頁結(jié)構(gòu)類

  • 明確測試分類以及統(tǒng)一的測試基礎(chǔ)類(請參考“自動化測試分類”小節(jié))

靜態(tài)代碼檢查

靜態(tài)代碼檢查主要包含以下Gradle插件庸诱,具體配置請參考本文示例代碼:

  • Checkstyle:用于檢查代碼格式捻浦,規(guī)范編碼風(fēng)格

  • Spotbugs:Findbugs的繼承者

  • Dependency check:OWASP提供的Java類庫安全性檢查

  • Sonar:用于代碼持續(xù)改進(jìn)的跟蹤

健康檢查

健康檢查主要用于以下場景:

  • 我們希望初步檢查程序是否運行正常

  • 有些負(fù)載均衡軟件會通過一個健康檢查URL判斷節(jié)點的可達(dá)性

此時,可以實現(xiàn)一個簡單的API接口桥爽,該接口不受權(quán)限管控朱灿,可以公開訪問。如果該接口返回HTTP的200狀態(tài)碼钠四,便可初步認(rèn)為程序運行正常盗扒。此外,我們還可以在該API中加入一些額外的信息缀去,比如提交版本號侣灶、構(gòu)建時間曼月、部署時間等洛波。

啟動本文的示例項目:

./run.sh

然后訪問健康檢查API:http://localhost:8080/about疤孕,結(jié)果如下:

{

以上接口在示例項目中用了一個簡單的Controller實現(xiàn)尸折,事實上Spring Boot的Acuator框架也能夠提供相似的功能破喻。

API文檔

軟件文檔的難點不在于寫,而在于維護(hù)协屡。多少次宫蛆,當(dāng)我對照著項目文檔一步一步往下走時,總得不到正確的結(jié)果统倒,問了同事之后得到回復(fù)“哦斟湃,那個已經(jīng)過時了”。本文示例項目所采用的Swagger在一定程度上降低了API維護(hù)的成本檐薯,因為Swagger能自動識別代碼中的方法參數(shù)凝赛、返回對象和URL等信息,然后自動地實時地創(chuàng)建出API文檔坛缕。

配置Swagger如下:

@Configuration

啟動本地項目墓猎,訪問http://localhost:8080/swagger-ui.html

image

數(shù)據(jù)庫遷移

在傳統(tǒng)的開發(fā)模式中,數(shù)據(jù)庫由專門的運維團隊或者DBA來維護(hù)赚楚,要對數(shù)據(jù)庫進(jìn)行修改需要向DBA申請毙沾,告之遷移內(nèi)容,最后由DBA負(fù)責(zé)數(shù)據(jù)庫變更實施宠页。在持續(xù)交付和DevOps運動中左胞,這些工作逐步提前到開發(fā)過程,當(dāng)然并不是說不需要DBA了举户,而是這些工作可以由開發(fā)者和運維人員一同完成烤宙。

另外,在微服務(wù)場景下俭嘁,數(shù)據(jù)庫被包含在單個服務(wù)的邊界之內(nèi)躺枕,因此基于內(nèi)聚性原則(咦,這好像是本文第三次提到內(nèi)聚原則了供填,可見其在軟件開發(fā)中的重要性)拐云,數(shù)據(jù)庫的變更最好也與項目代碼一道維護(hù)在代碼庫中。

本文的示例項目采用了Flyway作為數(shù)據(jù)庫遷移工具近她,加入了Flyway依賴后叉瘩,在src/main/sources/db/migration目錄下創(chuàng)建遷移腳本文件即可:

resources/

遷移腳本的命名需要遵循一定的規(guī)則以保證腳本執(zhí)行順序,另外遷移文件生效之后不要任意修改粘捎,因為Flyway會檢查文件的checksum薇缅,如果checksum不一致將導(dǎo)致遷移失敗。

多環(huán)境構(gòu)建

在軟件的開發(fā)流程中晌端,我們需要將軟件部署到多個環(huán)境捅暴,經(jīng)過多輪驗證后才能最終上線。在不同的階段中咧纠,軟件的運行態(tài)可能是不一樣的蓬痒,比如本地開發(fā)時可能將所依賴的第三方系統(tǒng)stub掉;持續(xù)集成構(gòu)建時可能使用的是測試用的內(nèi)存數(shù)據(jù)庫等等漆羔。為此梧奢,本文的示例項目推薦采用以下環(huán)境:

  • local:用于開發(fā)者本地開發(fā)

  • ci:用于持續(xù)集成

  • dev:用于前端開發(fā)聯(lián)調(diào)

  • qa:用于測試人員

  • uat:類生產(chǎn)環(huán)境狱掂,用于功能驗收(有時也稱為staging環(huán)境)

  • prod:正式的生產(chǎn)環(huán)境

CORS

在前后端分離的系統(tǒng)中,前端單獨部署亲轨,有時連域名都和后端不同趋惨,此時需要進(jìn)行跨域處理。傳統(tǒng)的做法可以通過JSONP惦蚊,但這是一種比較“trick”的做法器虾,當(dāng)前更通用的實踐是采用CORS機制,在Spring Boot項目中蹦锋,啟用CORS配置如下:

@Configuration

對于使用Spring Security的項目兆沙,需要保證CORS工作于Spring Security的過濾器之前,為此Spring Security專門提供了相應(yīng)配置:

@EnableWebSecurity

常用第三方類庫:

這里列出一些比較常見的第三方庫莉掂,開發(fā)者們可以根據(jù)項目所需引入:

  • Guava:來自Google的常用類庫

  • Apache Commons:來自Apache的常用類庫

  • Mockito:主要用于單元測試的mock

  • DBUnit:測試中管理數(shù)據(jù)庫測試數(shù)據(jù)

  • Rest Assured:用于Rest API測試

  • Jackson 2:Json數(shù)據(jù)的序列化和反序列化

  • jjwt:Jwt token認(rèn)證

  • Lombok:自動生成常見Java代碼葛圃,比如equals()方法,getter和setter等憎妙;

  • Feign:聲明式Rest客戶端

  • Tika:用于準(zhǔn)確檢測文件類型

  • itext:生成Pdf文件等

  • zxing:生成二維碼

  • Xstream:比Jaxb更輕量級的XML處理庫

總結(jié)

本文通過一個示例項目談及到了項目之初開發(fā)者搭建后端工程的諸多方面库正,其中的絕大多數(shù)實踐均在筆者的項目中真實落地。讀完本文之后你可能會發(fā)現(xiàn)厘唾,文中的很多內(nèi)容都是很基礎(chǔ)很簡單的褥符。

沒錯,的確沒有什么難的東西阅嘶,但是要系統(tǒng)性地搭建好后端項目的基礎(chǔ)框架卻不見得是每個開發(fā)團隊都已經(jīng)做到的事情属瓣,而這恰恰是本文的目的。

最后讯柔,需要提醒的是,本文提到的實踐方式只是一個參考护昧,一方面依然存在考慮不周的地方魂迄,另一方面示例項目中用到的技術(shù)工具還存在其他替代方案,請根據(jù)自己項目的實際情況進(jìn)行取舍惋耙。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末捣炬,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子绽榛,更是在濱河造成了極大的恐慌湿酸,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件灭美,死亡現(xiàn)場離奇詭異推溃,居然都是意外死亡,警方通過查閱死者的電腦和手機届腐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進(jìn)店門铁坎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蜂奸,“玉大人,你說我怎么就攤上這事硬萍±┧” “怎么了?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵朴乖,是天一觀的道長祖屏。 經(jīng)常有香客問我,道長买羞,這世上最難降的妖魔是什么赐劣? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮哩都,結(jié)果婚禮上魁兼,老公的妹妹穿的比我還像新娘。我一直安慰自己漠嵌,他們只是感情好咐汞,可當(dāng)我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著儒鹿,像睡著了一般化撕。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上约炎,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天植阴,我揣著相機與錄音,去河邊找鬼圾浅。 笑死掠手,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的狸捕。 我是一名探鬼主播喷鸽,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼灸拍!你這毒婦竟也來了做祝?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤鸡岗,失蹤者是張志新(化名)和其女友劉穎混槐,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體轩性,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡声登,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片捌刮。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡碰煌,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出绅作,到底是詐尸還是另有隱情芦圾,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布俄认,位于F島的核電站个少,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏眯杏。R本人自食惡果不足惜夜焦,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望岂贩。 院中可真熱鬧茫经,春花似錦、人聲如沸萎津。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽锉屈。三九已至荤傲,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間颈渊,已是汗流浹背遂黍。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留俊嗽,地道東北人雾家。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像乌询,于是被迫代替她去往敵國和親榜贴。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容