文章目錄
- 1 云嵐家政項目概述
- 1.1 簡介
- 1.2 項目業務流程
- 1.3 項目業務模塊
- 1.4 項目架構及技術棧
- 1.5 學習后掌握能力
- 2 熟悉項目
- 2.1 熟悉需求
- 2.2 熟悉設計
- 2.2.1 表結構
- 2.2.2 熟悉工程結構
- 2.2.3 jzo2o-foundations
- 2.2.3.1 工程結構
- 2.2.3.2 接口測試
- 3 開發區域服務模塊
- 3.1 流程分析
- 3.2 查詢區域服務
- 3.2.1 梳理接口
- 3.2.2 接口設計
- 3.2.2.1 接口文檔
- 3.2.2.2 HTTP請求方法
- 3.2.2.3 接口路徑
- 3.2.2.4 請求參數類型
- 3.2.2.5 請求參數內容
- 3.2.2.6 響應結果類型
- 3.2.2.7 響應結果狀態碼
- 3.2.2.8 響應結果內容
- 3.2.3 接口定義
- 3.2.3.1 編寫controller
- 3.2.3.1.1 基礎注釋
- 3.2.3.1.2 分頁controller中實現
- 3.2.3.2 編寫mapper
- 3.2.3.2.1 mapper代碼生成工具
- 3.2.3.2.2 分頁mapper開發
- 3.2.3.2.3 針對mapper的單元測試
- 3.2.3.2.4 @Resource 和 @Autowired有什么區別?
- 3.2.3.3 編寫service
- 3.2.3.3.1 單元測試
- 3.2.3.3.2 PageHelper原理
- 3.2.3.4 controller測試
- 3.2.3.5 前后端聯調
1 云嵐家政項目概述
1.1 簡介
云嵐到家項目是一個家政服務o2o平臺,互聯網+家政是繼打車、外賣后的又一個風口,創業者眾多,比如:58到家,天鵝到家等,o2o(Online To Offline)是將線下商務的機會與互聯網的技術結合在一起,讓互聯網成為線下交易的前臺,同時起到推廣和成交的作用。
C2B2C:
在家政 O2O(Online to Offline,線上到線下)領域中,“Consumer to Business to Consumer”(C2B2C)描述了一個商業模式,消費者不僅可以通過平臺獲取家政服務,還有機會成為服務提供者。在這個背景下,C2B2C 模式通常指的是:
- 消費者(Consumer):
- 最終的家庭用戶,他們需要家政服務,例如清潔、保姆、維修等。
- 企業(Business):
- 在家政 O2O 中,企業通常是在線平臺,提供家政服務的中介。這些平臺通過在線渠道為消費者提供了查找、預訂、支付等服務,同時也可能為家政服務提供者提供了工作機會。
- 消費者(家政服務提供者):
- 在 C2B2C 模式中,一些消費者也可以成為服務的提供者。這些個體可能是獨立的家政服務專業人員,他們可以在家政 O2O 平臺上注冊,提供自己的服務,并被其他需要服務的消費者雇傭。
B2B2C:
代表著"Business to Business to Consumer",即企業到企業到消費者的模式。家政服務平臺作為中間商,通過與各種家政服務提供商(家政服務公司)合作,為消費者提供多樣化的家政服務選擇。
B2B2C與C2B2C的區別是:B2B2C中服務提供者是家政服務中介公司,在C2B2C中是服務提供者是擁有服務技能的服務人員(散戶)。
本項目結合了C2B2C和B2B2C模式,個人和家政服務中介都可以通過平臺提供家政服務,如下圖:
項目包括四個端:用戶端(小程序)、服務端(app)、機構端(PC)、運營管理端(PC),四個端對應四類用戶角色:
家政需求方:通過用戶端小程序完成在線預約下單、支付、評價、投訴、退款等操作。
家政服務人員:通過服務端APP完成在線接單、結算等操作。
家政服務公司:通過機構端完成在線接單、派單、投訴處理、結算等操作。
平臺方:通過管理端完成服務人員管理、機構管理、訂單管理、財務管理等操作,一筆完成的訂單,結算時按照分成比例平臺進行抽成。
1.2 項目業務流程
核心流程:
- 運營端在運營區域上架家政服務
比如:在北京上架 日常保潔、空調維修。
-
用戶端通過定位區域獲取當前區域的服務項目,選擇家政服務,下單、支付
-
家政服務人員及家政服務公司(機構)通過平臺搶單
-
家政服務人員現場服務,平臺跟蹤管理整個服務過程。
-
服務完成,用戶評價、售后服務等。
1.3 項目業務模塊
我們根據業務流程去分析各個模塊的功能:
服務管理:對家政服務項目進行管理,最后在指定區域上架服務后用戶可在當前區域購買。
下單支付:用戶通過小程序完成下單支付,進入小程序首頁查詢服務,用戶選擇服務,下單并支付
搶單:服務人員和機構進行搶單。首先服務人員和機構設置接單范圍、服務技能、開啟搶單開關,然后進入搶單界面進行搶單。
派單調度:平臺根據撮合匹配算法通過任務調度將訂單和服務人員進行撮合匹配,促進成交。
訂單管理:對訂單的生命周期進行管理,包括創建訂單、取消訂單、刪除訂單、歷史訂單等。
服務人員管理:對服務人員的信息、認證等進行管理。
企業管理:對機構的信息、認證進行管理。
客戶管理:對c端用戶的信息、用戶的狀態等信息進行管理。
營銷管理:對優惠券活動進行管理。
1.4 項目架構及技術棧
項目是基于Spring Cloud Alibaba框架構建的微服務項目,采用前后端分離模式進行開發,系統架構圖如下
-
用戶層:
包括四個端:運營端(PC)、服務端(APP)、機構端(PC)、用戶端(小程序)
-
負載層:
反向代理、負載均衡。
-
服務層:包括網關、業務微服務、基礎服務。
業務微服務:包括運營基礎服務、客戶管理服務、訂單管理服務、搶單服務、派單服務、支付服務等。
基礎服務:Nacos(服務注冊、配置中心)、XXL-JOB(任務調度)、RabbitMQ(消息隊列)、Elasticsearch(全文檢索)、Canal(數據同步)、Sentinel(熔斷降級、限流)等。
-
數據層:
MySQL數據庫存儲:服務信息、區域信息、客戶信息、訂單信息、支付信息、搶單池、派單池、結算信息等。
分庫分表:使用ShardingShphere進行分庫分表。
TiDB分布式數據庫存儲:歷史訂單信息。
消息隊列:存儲數據同步消息、各類異步消息等。
索引:服務信息、服務提供者信息、訂單信息等。
緩存:服務信息、訂單信息、服務單信息等。
項目核心交互流程如下圖:
1.5 學習后掌握能力
掌握項目需求分析能力
掌握系統分析與設計的能力
掌握Spring Cloud 在項目中的開發與調優能力
掌握Redis在項目中的應用能力
掌握緩存技術方案的分析與設計能力
掌握Canal+MQ異構數據同步的開發調試能力
掌握Elasticsearch全文檢索與地理搜索的開發能力
掌握ShardingSphere分庫分表的方案設計與開發能力
掌握Seata分布式事務控制的開發能力
掌握數據冷熱分離技術方案的設計與開發能力
掌握XXL-JOB+線程池任務調度方案的設計與開發能力
掌握系統調優與線上故障處理的能力
掌握狀態機組件的設計與開發能力
掌握門戶業務的設計與開發能力
掌握訂單支付業務的系統設計與開發能力
掌握優惠券&活動管理業務的系統設計與開發能力
掌握秒殺搶購業務的常見設計方案與開發能力
掌握派單調度類業務的系統設計與開發能力
掌握客戶管理業務的系統設計與開發能力
掌握活動管理業務的系統設計與開發能力
掌握搜索附近業務的系統設計與開發能力
掌握服務管理&商品管理業務的系統計與開發能力
掌握統計分析與看板業務的系統設計與開發能力
2 熟悉項目
2.1 熟悉需求
目標:閱讀需求文檔,理解基本概念和業務流程。
1-4已經開發的差不多了,模擬實際公司的業務環節,我們需要新開發5,添加對區域服務管理的開發。
2.2 熟悉設計
理解運營基本管理模塊的表結構,熟悉工程結構,能夠對接口進行斷點調試。
2.2.1 表結構
根據需求熟悉本模塊的核心表,如下圖:
serve_type:服務類型表(家電清洗)
serve_item: 服務項表,存儲了本平臺的家政服務項目(家電清洗的具體項目,如洗衣機清洗,空調清洗等等)
每個服務項都有一個服務類型,一個服務類型下有多個服務項,服務類型與服務項是一對多關系。
region:區域表,存儲運營地區信息,一般情況區域表行政級別是市。
serve: 服務表,存儲了各個區域運營的服務及相關信息。(直接與用戶/運營相關)
注意:這里不要把serve表簡單理解為只是區域表和服務項表的中間關系表,因為如果是簡單的關聯關系表只需記錄區域表和服務項表各自的主鍵Id即可,serve記錄的是平臺運營服務的信息,凡是與運營相關的信息都要記錄在serve表,比如:運營價格。后期也可能會增加其它運營相關的字段。
注意:
-
region與serve_item是什么關系?
一個區域下可以設置多個服務項,一個服務項可以被多個區域設置,region與serve_item是多對多關系。
2.2.2 熟悉工程結構
2.2.3 jzo2o-foundations
2.2.3.1 工程結構
首先熟悉jzo2o-foundations運營基礎服務工程的結構,jzo2o-foundations工程結構如下圖:
依賴:
<dependencies><!--Nacos服務發現--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><!--Nacos服務管理配置--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId></dependency><!--開啟Bootstrap配置文件的支持--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bootstrap</artifactId></dependency><!--jzo2o-mvc在jzo2o-framework下,針對web開發的依賴--><dependency><groupId>com.jzo2o</groupId><artifactId>jzo2o-mvc</artifactId></dependency><!--knife4j用于生成swagger文檔--><dependency><groupId>com.jzo2o</groupId><artifactId>jzo2o-knife4j-web</artifactId></dependency><!-- <dependency>-->
<!-- <groupId>com.jzo2o</groupId>-->
<!-- <artifactId>jzo2o-es</artifactId>-->
<!-- </dependency>--><!--單元測試--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--api接口,定義了服務之間的遠程調用接口--><dependency><groupId>com.jzo2o</groupId><artifactId>jzo2o-api</artifactId></dependency><!--序列化工具庫--><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId></dependency><!--jzo2o-redis定義在jzo2o-framework工程,定義了持久層相關的依賴--><dependency><groupId>com.jzo2o</groupId><artifactId>jzo2o-redis</artifactId></dependency>
<!-- <dependency>-->
<!-- <groupId>com.jzo2o</groupId>-->
<!-- <artifactId>jzo2o-canal-sync</artifactId>-->
<!-- </dependency>--><!--jzo2o-mysql定義在jzo2o-framework工程,定義了持久層相關的依賴--><dependency><groupId>com.jzo2o</groupId><artifactId>jzo2o-mysql</artifactId></dependency>
<!-- <dependency>-->
<!-- <groupId>com.jzo2o</groupId>-->
<!-- <artifactId>jzo2o-xxl-job</artifactId>-->
<!-- </dependency>--></dependencies>
持久層:MySQL數據庫,mybatis-plus框架,com.github.pagehelper分頁組件
中間件:Redis、Elasticsearch、xxl-job
服務層:通過Spring進行事務控制,redisson分布式鎖、Spring Cache緩存框架
web層: SpringMVC框架(基于SpringBoot開發)
web容器:undertow(Undertow 是一個采用 Java 開發的靈活的高性能 Web 服務器,紅帽公司的開源產品)
高并發場景下undertow的性能更好。
2.2.3.2 接口測試
啟動jzo2o-foundations工程。啟動docker中的redis,mysql,nacos。
通過swagger接口文檔去熟悉模塊的接口,通過測試接口去理解接口的整個交互流程。
打開接口文檔:http://localhost:11509/foundations/doc.html
通過左側菜單找到“運營端-服務類型相關接口”,如下圖:
點擊“服務類型分頁查詢”打開接口文檔,如下圖:
找到接口地址:/foundations/operation/serve-type/page
/foundations:微服務的content-path路徑
/operation:表示給運營端使用的接口
/serve-type/page:具體的接口地址
在jzo2o-foundations工程搜索“/serve-type”關鍵字
繼續在ServeTypeController.java類中找/page接口,如下圖:
@GetMapping("/page")
@ApiOperation("服務類型分頁查詢")
public PageResult<ServeTypeResDTO> page(ServeTypePageQueryReqDTO serveTypePageQueryReqDTO) {return serveTypeService.page(serveTypePageQueryReqDTO);
}
下邊debug運行工程,跟蹤接口執行的流程:
首先打上斷點,如下圖:
debug運行jzo2o-foundations工程。下邊通過swagger接口文檔測試該接口,進入“調試”窗口,點擊“發送”
跟蹤請求參數:
放行繼續執行,測試結束,觀察響應結果
觀察idea控制臺輸出的SQL執行語句
3 開發區域服務模塊
3.1 流程分析
我們的開發流程肯定是先點區域,然后在區域中設置服務,所以我們應當先開發查詢區域再查詢服務列表的流程。
3.2 查詢區域服務
3.2.1 梳理接口
在定義接口前先梳理本模塊涉及哪些接口,根據梳理出的接口制定工作計劃。
通常對于前后端交互的接口根據界面原型、需求文檔去梳理。
通過閱讀需求文檔在區域服務模塊包括以下接口:
-
區域服務分頁查詢接口
-
區域服務新增接口
-
區域服務刪除接口
-
區域服務價格修改接口
-
區域服務設置熱門接口
-
區域服務取消熱門接口
-
區域服務上架接口
-
區域服務下架接口
3.2.2 接口設計
下邊設計區域服務分頁查詢接口,企業中前后分離開發通常由java程序員設計接口,設計完成提供接口文檔給前端工程師。
如何設計一個接口?
我們根據最終提供的接口文檔看看需要設計哪些內容。
3.2.2.1 接口文檔
接口設計信息如下:
接口路徑:GET/foundations/operation/serve/page
請求數據類型 application/x-www-form-urlencoded
響應參數:
首先明確該接口是一個前后端交互接口,該接口由前端通過HTTP協議進行調用,前端去調用接口需要知道以下內容:
-
HTTP請求方法
-
接口路徑
-
請求參數類型
-
請求參數內容
-
響應結果類型
-
響應結果狀態碼
-
響應結果內容
所以我們設計接口需要設計這些內容。
3.2.2.2 HTTP請求方法
根據RESTful規范:
查詢方法用GET,請求參數比較多可用POST
新增方法用POST
修改方法用PUT
刪除方法用DELETE
本接口是一個分頁查詢接口,查詢條件我們用GET。
具體的代碼實現可以找一些現有的類參考,比如:ServeTypeController類
3.2.2.3 接口路徑
定義為RESTful風格的路徑。
接口路徑為:/foundations/operation/serve/page
因為我們在bootstrap.yml文件中已經定義了項目根路徑 server.servlet.context-path: /foundations
server:port: 11509undertow:accesslog:enabled: truepattern: "%t %a "%r" %s (%D ms)"dir: /data/logs/undertow/${spring.application.name}/access-logs/servlet:context-path: /foundations
可以在類上邊使用@RequestMapping指定該類中接口的路徑的基礎路徑。
在方法中指定具體的路徑。
3.2.2.4 請求參數類型
常用的有:
-
json格式:
application/json,傳遞json格式字符串,當傳遞的參數是屬于一個對象的屬性時可用此格式,比如:新增、修改時通常傳遞的數據是某個對象的信息就可以使用此格式。
-
表單格式:
application/x-www-form-urlencoded,傳遞key/value串,就是在url后通過?和&進行拼接的參數,比如:
/foundations/operation/serve/page?pageNo=1&pageSize=10
當傳遞的參數比較雜且不屬于某個特定的對象時使用此格式,本接口使用application/x-www-form-urlencoded格式。
3.2.2.5 請求參數內容
請求參數的內容根據需求文檔和界面原型去識別。
分頁式查詢首先有當前頁碼和每頁顯示記錄數。
對于查詢類的接口還有常用的參數有:排序方式、排序字段。
再根據需求的梳理,查詢某個區域下的服務需要傳遞一個區域id。
請求參數如下:
3.2.2.6 響應結果類型
常見的類型有:text/html、text/plain、application/json等。
本項目統一使用application/json
3.2.2.7 響應結果狀態碼
HTTP狀態碼是服務器返回給客戶端的數字代碼(三位數字),共分為五類:
1xx: 表示服務器接收到了客戶端請求并正在處理
2xx: 表示成功狀態碼
3xx:表示重向定狀態碼
4xx:表示客戶端錯誤狀態碼
5xx: 表示服務端錯誤狀態碼
當服務端處理成功返回200,其它表示失敗。
3.2.2.8 響應結果內容
分頁查詢通用的響應內容有:數據列表、總頁數、總記錄數
數據列表中需要分析具體的屬性,根據界面原型進行分析:
屬性包括:
制定分頁查詢通用的響應內容如下:
msg、code、 data、total、pages是固定的。
data中List數據的內容對于不同的分頁查詢會不一樣。
響應示例
{"msg": "OK","code": 200,"data": {"list": [{"serveTypeId": 0,"serveItemName": "","updateTime": "","saleStatus": 0,"serveItemId": 0,"referencePrice": 0,"createTime": "","regionId": 0,"price": 0,"id": 0,"isHot": 0,"serveTypeName": ""}],"total": 0,"pages": 0}
}
3.2.3 接口定義
3.2.3.1 編寫controller
3.2.3.1.1 基礎注釋
根據接口設計的內容編寫controller方法,最后通過swagger生成接口文檔。
缺少請求路徑的/foundations/operation/serve/page
的serve的controller,所以在com.jzo2o.foundations.controller.operation中創建ServeController
注意 @RestController
注入到Spring容器中的名字,采用包名+類名,來避免重復
@RestController("operationServeController")
注意@RequestMapping
路徑,因為我們在bootstrap.yml文件中已經定義了項目根路徑 server.servlet.context-path: /foundations
,所以路徑應該是
@RequestMapping("/operation/serve")
注意是否要添加@Validated
,可以對id等字段進行校驗,@NotNull(message = "id不能為空")
public void update(@NotNull(message = "id不能為空") @PathVariable("id") Long id,@RequestParam("managerName") String managerName,@RequestParam("managerPhone") String managerPhone) {regionService.update(id, managerName, managerPhone);
}
注意我們使用的swagger接口文檔編寫,所以要添加@Api
@Api(tags = "運營端 - 區域服務管理相關接口")
3.2.3.1.2 分頁controller中實現
請求參數用com.jzo2o.foundations.model.dto.request.ServePageQueryReqDTO封裝起來,進行請求
@Data
@ApiModel("服務分頁查詢類")
public class ServePageQueryReqDTO extends PageQueryDTO {@ApiModelProperty(value = "區域id", required = true)private Long regionId;
}
返回參數用com.jzo2o.foundations.model.dto.response.ServeResDTO封裝到List列表中,再和total和pages組成data返回。
@RestController("operationServeController")
@RequestMapping("/operation/serve")
@Api(tags = "運營端 - 區域服務管理相關接口")
public class ServeController {@GetMapping("/page")@ApiOperation("分頁查詢區域服務列表")public PageResult<ServeResDTO> page(ServePageQueryReqDTO servePageQueryReqDTO) {return null;}
}
初步構建完畢,重新啟動后,查看swagger文檔,成功查詢到
3.2.3.2 編寫mapper
3.2.3.2.1 mapper代碼生成工具
代碼生成工具
通常一個接口需求明確后從持久層開始開發。
對于一個新模塊需要使用工具生成模型類、mapper接口、mapper映射文件等,下邊介紹一個工具用于自動生成代碼。
使用MybatisPlus插件自動生成代碼
1、安裝插件
2.重啟IDEA,連接mysql
配置連接的數據庫
輸入連接字符串:jdbc:mysql://192.168.101.68:3306/jzo2o-foundations?useSSL=false&serverTimezone=UTC
賬號和密碼跟我們day00設置一樣,賬號root,密碼mysql
3、配置代碼生成規則
1)選擇表:上圖選擇serve_type表。
2)設置生成代碼的根目錄:上圖設置generator
3)設置包路徑:上圖設置為com.jzo2o.foundations
4)主鍵生成策略:根據表中主鍵的生成策略進行選擇,支持的主鍵生成策略如下圖:
本項目使用的MyBatisPlus版本支持前5個,對應MyBatisPlus源碼如下:
public enum IdType {AUTO(0),NONE(1),INPUT(2),ASSIGN_ID(3),ASSIGN_UUID(4);
- AUTO:基于數據庫的自增主鍵
- NONE: 不設置id生成策略
- INPUT:用戶手工輸入id
- ASSIGN_ID:雪花算法生成id(可兼容數值型與字符串型)
- ASSIGN_UUID:以UUID生成算法作為id生成策略
本項目使用ASSIGN_ID方式,即分配ID。
5)勾選要生成的類及包路徑(Entity、Mapper、Controller、Service、ServiceImpl)。
6)勾選是否生成lombok注解、restController注解、swagger注解等。
點擊“check field”選擇表中的字段。
點擊“code generatro”生成代碼。
生成成功在項目工程根目錄有一個generator目錄,里邊為生成的代碼,如下圖:
對生成的代碼根據自己的需求稍加修改,修改后拷貝到工程相應的包下即可。
3.2.3.2.2 分頁mapper開發
因為我們最后獲取的響應里由服務名稱,但是serve表中并沒有服務名稱
所以就涉及多表查詢,而MybatisPlus生成的代碼只適合單表查詢。
查看響應參數,保證返回值與響應一致,駝峰為返回值,下劃線為數據庫查詢出來的參數
先查詢一個北京區域的服務,region_id為1686303222843662337
SELECTst.id serve_type_id,si.name serve_item_name,s.update_time update_time,s.sale_status sale_status,si.id serve_item_id,si.reference_price reference_price,s.create_time create_time,s.region_id region_id,s.price price,s.id id,s.is_hot is_hot,st.name serve_type_name
FROMserve sINNER JOIN serve_item si ON s.serve_item_id = si.idINNER JOIN serve_type st ON si.serve_type_id = st.id
WHEREregion_id = 1686303222843662337
持久層基礎代碼生成完畢下邊開發mapper接口,對于通用的CRUD接口由MybatisPlus提供。
對于需要自定義mapper接口的需求則需要自定義mapper接口及mapper映射文件,根據需求本接口要返回的數據包括多張表的數據,而MybatisPlus提供的CRUD是針對單表的,下邊定義mapper實現多表關聯查詢。
先定義mapper接口:
mapper接口講究通用性,根據數據處理最底層的需求去定義接口,本需求是根據區域查詢服務列表,參數為區域id,方法返回值為服務列表。
生成com.jzo2o.foundations.mapper.ServeMapper
public interface ServeMapper extends BaseMapper<Serve> {List<ServeResDTO> queryServeListByRegionId(@Param("regionId") Long regionId);
}
@Param("regionId")
是我們待會在mapper的xml文件中需要使用的。
因為我們的查詢方法是新生成的,自然在mapper的xml無法找到,所以alt+enter在src/main/resources/mapper/ServeMapper.xml中自動生成
復制我們剛剛的sql語句,修改where語句為 region_id = #{regionId}
,現在都是使用#{}
:占位符號,#{ }
和 ${ }
會有不同的表現。#{ }
:解析為一個 JDBC 預編譯語句(prepared statement)的參數標記符。而${ }
僅僅為一個純碎的 string 替換,在動態 SQL 解析階段將會進行變量替換。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jzo2o.foundations.mapper.ServeMapper"><select id="queryServeListByRegionId" resultType="com.jzo2o.foundations.model.dto.response.ServeResDTO">SELECTst.id serve_type_id,si.NAME serve_item_name,s.update_time update_time,s.sale_status sale_status,si.id serve_item_id,si.reference_price reference_price,s.create_time create_time,s.region_id region_id,s.price price,s.id id,s.is_hot is_hot,st.NAME serve_type_nameFROMserve sINNER JOIN serve_item si ON s.serve_item_id = si.idINNER JOIN serve_type st ON si.serve_type_id = st.idWHEREregion_id = 1686303222843662337</select>
</mapper>
3.2.3.2.3 針對mapper的單元測試
大廠都嚴格要求對mapper進行單元測試,創建com.jzo2o.foundations.service.ServeMapperTest
@SpringBootTest
@Slf4j
public class ServeMapperTest {@Resourceprivate ServeMapper serveMapper;@Testpublic void testQueryServeListByRegionId() {List<ServeResDTO> serveResDTOS = serveMapper.queryServeListByRegionId(1686303222843662337L);Assert.notEmpty(serveResDTOS, "查詢結果為空");}
}
@SpringBootTest
spring測試類注釋@Slf4j
日志記錄@Test
測試方法注解@Resource
自動注入
運行我們的單元測試
成功查詢到,說明我們的單元測試通過。
3.2.3.2.4 @Resource 和 @Autowired有什么區別?
- 來源不同
@Resource 是 Java EE(Java Platform, Enterprise Edition)規范定義的注解,位于 javax.annotation 包中,不僅可以用于 Spring 環境,還可以用于其他 Java EE 容器。
@Autowired 是 Spring 框架定義的注解,位于 org.springframework.beans.factory.annotation 包中,主要用于 Spring 環境中。
- 注入方式不同
@Resource默認按名稱注入,如果在spring容器找不到對應名稱的 Bean,則按照 byType 進行注入。
@Autowired默認按照 byType 的方式進行注入。如果有多個類型相同的 Bean,可以結合 @Qualifier 使用指定具體的 Bean 名稱
// 使用 @Resource
@Resource(name = "myBean")
private MyBean myBean;// 使用 @Autowired
@Autowired
@Qualifier("myBean")
private MyBean myBean;
3.2.3.3 編寫service
用我們針對serve生成的代碼進行修改
復制到相應的位置,他生成的是針對單表查詢的mybatisplus。所以我們單表查詢的時候可以直接使用。
在controller中注入service
@RestController("operationServeController")
@RequestMapping("/operation/serve")
@Api(tags = "運營端 - 區域服務管理相關接口")
public class ServeController {@Resourceprivate IServeService serveService;@GetMapping("/page")@ApiOperation("分頁查詢區域服務列表")public PageResult<ServeResDTO> page(ServePageQueryReqDTO servePageQueryReqDTO) {return serveService.page(servePageQueryReqDTO);}
}
service接口
public interface IServeService extends IService<Serve> {PageResult<ServeResDTO> page(ServePageQueryReqDTO servePageQueryReqDTO);}
實現層,分頁有兩種思路,一種是mybatisplus的分頁,但是不能自定義查詢語句,也就是只能單表查詢,另一種是用pagehelper插件,可以自定義,我們的語句是自定義的,因此我們采用pagehelper。
未來工作中有很多別人的代碼,我們要學習觀察和替換,把參數和方法改成我們自己的。
@Service
public class ServeServiceImpl extends ServiceImpl<ServeMapper, Serve> implements IServeService {@Overridepublic PageResult<ServeResDTO> page(ServePageQueryReqDTO servePageQueryReqDTO) {PageResult<ServeResDTO> serveResDTOPageResult = PageHelperUtils.selectPage(servePageQueryReqDTO,() -> baseMapper.queryServeListByRegionId(servePageQueryReqDTO.getRegionId()));return serveResDTOPageResult;}
}
3.2.3.3.1 單元測試
@SpringBootTest
@Slf4j
class IServeServiceTest {@Resourceprivate IServeService serveService;//分頁測試@Testpublic void test_page(){ServePageQueryReqDTO servePageQueryReqDTO = new ServePageQueryReqDTO();servePageQueryReqDTO.setRegionId(1677152267410149378L);servePageQueryReqDTO.setPageNo(1L);servePageQueryReqDTO.setPageSize(3L);PageResult<ServeResDTO> page = serveService.page(servePageQueryReqDTO);log.info("page : {}", page);Assert.notEmpty(page.getList(),"列表為空");}
}
成功輸出五條共兩頁。
3.2.3.3.2 PageHelper原理
使用com.github.pagehelper分頁插件實現分頁功能,下邊介紹它的執行原理。
PageHelperUtils是項目封裝的一個工具類,進入selectPage方法,調用PageHelper.startPage方法設置分頁參數,通過一層一層進入源碼,最終將分頁參數設置到ThreadLocal<Page>LOCAL_PAGE=newThreadLocal();
中。
通過PageInterceptor攔截器攔截 MyBatis的Executor 的 query() 方法得到原始的sql語句,首先得到count總數,然后從newThreadLocal中取出分頁參數,在原始sql語句中添加分頁參數查詢分頁數據。
部分源碼截圖如下:
我們的分頁參數在ThreadLocal中存儲,最后拼合在一起
如果查詢第二頁,會自動進行計算拼接(page-1)*size
3.2.3.4 controller測試
重啟服務,通過接口文檔工具進行測試。
遇到問題在controller、service中打斷點進行調試。
測試時注意請求參數填寫是否正確,下邊是測試結果
返回
3.2.3.5 前后端聯調
啟動foundations服務和gateway服務。
通過cmd進入project-xzb-pc-admin-vue3-java目錄啟動前端項目
運行命令,啟動前端工程
npm run dev
根據業務操作流程進行測試。
點擊服務管理中區域服務,對北京市進行設置服務
成功查詢到五條服務項目