伙伴匹配系統(移動端 H5 網站(APP 風格)基于Spring Boot 后端 + Vue3 - 02
伙伴匹配系統(移動端 H5 網站(APP 風格)基于Spring Boot 后端 + Vue3 - 02

項目地址:
@
后端整合 Swagger + Knife4j 接口文檔
什么是接口文檔,寫接口信息的文檔。
每個接口的信息包括:
- 請求參數
- 響應參數:
- 錯誤碼
- 接口地址
- 接口名稱
- 請求類型
- 請求格式
- 備注
誰用接口文檔?
答:一般是后端或者負責人來提供,后端和前端都要使用
為什么需要接口文檔?
- 有一個書面內容(背書或者歸檔),便于大家參考和查閱,便于沉淀和維護,拒絕口口相傳。
- 接口文檔便于前端和后端開發對接,前后端聯調的介質,后端 => 接口文檔 <= 前端。
- 好的接口文檔支持在線調試,在線測試,可以作為工具提高我們的開發測試效率。
怎么做接口文檔?
- 手寫:比如騰訊文檔、Markdown筆記
- 自動化接口文檔生成:自動根據項目代碼生成完整的文檔或在線調試的網頁。Swagger、Postman(側重接口管理)(國外);apifox、apipost、eolink(國產)
使用 Swagger
- 引l入依賴(Swagger或Knife4j:https://doc.xiaominfo.com/knife4j/documentation/get_start.html))
- 自定義Swagger配置類
- 定義需要生成接口文檔的代碼位置(Controller)
- 千萬注意:線上環境不要把接口暴露出去!!!可以通過在SwaggerConfig配置文件開頭加上@Profile({"dev","test"})限定配置僅在部分環境開啟
- 啟動即可
- 可以通過在controller方法上添加[@Api、@ApilmplicitParam(name]VApi、@ApilmplicitParam(name)="name",value="姓名",required=true)[@ApiOperation(value]/ApiOperation(value)=“向客人問好")等注解來自定義生成的接口描述信息
使用 swagger 日志
swagger 官網地址:https://swagger.io/

導入相關的依賴
<!-- swagger -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>3.0.0</version>
</dependency>
在配置文件config目錄下,添加swagger 的配置文件 SwaggerConfig.java

package com.yupi.yupao.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;
/**
* 自定義 Swagger 接口文檔的配置
*
* @author <a >Raibnowsea</a>
*/
@Configuration
//@EnableSwagger2WebMvc
@EnableSwagger2
@Profile({"dev", "test"}) // 表示該項目在什么樣的開發環境下,對外開發接口文檔
public class SwaggerConfig {
@Bean(value = "defaultApi2") //
public Docket defaultApi2() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
// 這里一定要標注你控制器的位置
.apis(RequestHandlerSelectors.basePackage("com.rainbowsea.yupao.controller"))
.paths(PathSelectors.any())
.build();
}
/**
* api 信息
*
* @return
*/
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("魚皮用戶中心")
.description("魚皮用戶中心接口文檔")
.termsOfServiceUrl("https://github.com/rainbowsea")
.contact(new Contact("yupi", "https://github.com/rainbowsea", "xxx@qq.com"))
.version("1.0")
.build();
}
}

apis(RequestHandler)

如果 Spring Boot Verision >= 2.6 ,需要添加如下配置
spring:
mvc:
pathmatch:
matching-strategy: ANT_PATH_MATCHER

訪問路徑:你的項目名映射路徑+/doc.html ;比如: localhost:8080/api/doc.html

網頁內容抓取-存量用戶信息導入及同步
看上了網頁信息,怎么抓到的
-
分析原網站是怎么獲取這些數據的?哪個接口? F12,刷新——>觸發請求
-
用程序去調用接口
-
處理(清洗)一下數據,之后就可以寫到數據庫里。
流程:
- 從 Excel 中導入全量用戶數據,判重。
- 抓取寫了自我介紹的同學信息,提取出用戶昵稱,用戶唯一 id,自我介紹信息。
- 從自我介紹中提取信息,
Easy Excel 讀取 Excel 當中的信息
Easy Excel 官網地址:https://alibaba-easyexcel.github.io/index.html

Easy Excel 官方文檔:https://easyexcel.opensource.alibaba.com/docs/current/
兩種讀 Excel 的方式:
- 確定表頭:建立對象;和表頭形成映射
- 不確定表頭:每一行數據映射為 Map<String.Object>
兩種讀取模式:
- 監聽器:先創建監聽器,再讀取文件時綁定監聽器。單獨抽離處理邏輯,代碼清晰易于維護;一條一條處理,適用于數據量大的場景。
- 同步讀:無需創建監聽器,一次性獲取完整數據。方便簡單,但是數據量大時會有等待時常,也可能內存溢出。
導入 Easy Excel 依賴
<!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.1.1</version>
</dependency>
這里我們創建一個:最簡單的讀的對象。用于存放我們讀取到的 Excel 信息將其映射為一個對象。
- 確定表頭:建立對象;和表頭形成映射
- 不確定表頭:每一行數據映射為 Map<String.Object>
package com.rainbowsea.yupao.one;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
@Data
public class DemoExcelData {
//@ExcelProperty(index = 1) 可以用列表匹配
/**
* id
* 強制讀取第幾個,這里不建議用 index 和 name 同時使用,
* 要么一個對象只用 index ,要么一個對象只用 name 去匹配
*/
@ExcelProperty("成員編號")
private String planeCode;
/**
* 用戶昵稱
*/
@ExcelProperty("成員昵稱")
private String username;
}

讀取方式一:監聽器:先創建監聽器,再讀取文件時綁定監聽器。單獨抽離處理邏輯,代碼清晰易于維護;一條一條處理,適用于數據量大的場景。

package com.rainbowsea.yupao.one;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import lombok.extern.slf4j.Slf4j;
/**
* Excel 讀取監聽
*
*/
@Slf4j
public class TableListener implements ReadListener<DemoExcelData> {
/**
* 這個每一條數據解析都會來調用
*
* @param data one row value. Is is same as {@link AnalysisContext#readRowHolder()}
* @param context
*/
@Override
public void invoke(DemoExcelData data, AnalysisContext context) {
System.out.println(data);
}
/**
* 所有數據解析完成了 都會來調用
*
* @param context
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
System.out.println("已解析完成");
}
}

package com.rainbowsea.yupao.one;
import com.alibaba.excel.EasyExcel;
import java.util.List;
/**
* 導入 Excel
*
*/
public class ImportExcel {
/**
* 讀取數據
*/
public static void main(String[] args) {
// todo 記得改為自己的測試文件
String fileName = "E:\\Java\\project\\魚皮星球項目\\伙伴匹配系統\\yupao\\yupao-backend\\src\\main\\resources\\testExcel.xlsx";
readByListener(fileName);
}
/**
* 監聽器讀取
* @param fileName
*/
public static void readByListener(String fileName) {
EasyExcel.read(fileName, DemoExcelData.class, new TableListener()).sheet().doRead();
}
}

讀取方式二:同步讀:無需創建監聽器,一次性獲取完整數據。方便簡單,但是數據量大時會有等待時常,也可能內存溢出。

package com.rainbowsea.yupao.one;
import com.alibaba.excel.EasyExcel;
import java.util.List;
/**
* 導入 Excel
*
*/
public class ImportExcel {
/**
* 讀取數據
*/
public static void main(String[] args) {
// todo 記得改為自己的測試文件
String fileName = "E:\\Java\\project\\魚皮星球項目\\伙伴匹配系統\\yupao\\yupao-backend\\src\\main\\resources\\testExcel.xlsx";
synchronousRead(fileName);
}
/**
* 同步讀
*
* @param fileName
*/
public static void synchronousRead(String fileName) {
// 這里 需要指定讀用哪個class去讀,然后讀取第一個sheet 同步讀取會自動finish
List<DemoExcelData> totalDataList =
EasyExcel.read(fileName).head(DemoExcelData.class).sheet().doReadSync();
for (DemoExcelData xingQiuTableUserInfo : totalDataList) {
System.out.println(xingQiuTableUserInfo);
}
}
}

技巧:讀取 Excel 當前的數據,進行一個過濾,提交操作
package com.yupi.yupao.once.importuser;
import com.alibaba.excel.EasyExcel;
import org.apache.commons.lang3.StringUtils;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 導入星球用戶到數據庫
*
* @author <a >程序員魚皮</a>
* @from <a >編程導航知識星球</a>
*/
public class ImportXingQiuUser {
public static void main(String[] args) {
// todo 記得改為自己的測試文件
String fileName = "E:\\星球項目\\yupao-backend\\src\\main\\resources\\prodExcel.xlsx";
// 這里 需要指定讀用哪個class去讀,然后讀取第一個sheet 同步讀取會自動finish
List<XingQiuTableUserInfo> userInfoList =
EasyExcel.read(fileName).head(XingQiuTableUserInfo.class).sheet().doReadSync();
System.out.println("總數 = " + userInfoList.size());
Map<String, List<XingQiuTableUserInfo>> listMap =
userInfoList.stream()
.filter(userInfo -> StringUtils.isNotEmpty(userInfo.getUsername()))
.collect(Collectors.groupingBy(XingQiuTableUserInfo::getUsername));
for (Map.Entry<String, List<XingQiuTableUserInfo>> stringListEntry : listMap.entrySet()) {
if (stringListEntry.getValue().size() > 1) {
System.out.println("username = " + stringListEntry.getKey());
System.out.println("1");
}
}
System.out.println("不重復昵稱數 = " + listMap.keySet().size());
}
}
關于 Easy Excel 的寫入到 Excel 的操作,大家可以參考官方文檔:https://easyexcel.opensource.alibaba.com/docs/current/quickstart/write
前端頁面跳轉傳值
- query => url serachParams ,url 后附加參數,傳遞的值長度有限。
- vuex(全局狀態管理),eg:搜索頁將關鍵詞塞到狀態中,搜索結果頁從狀態取值。

banner.txt 廣告位
只需要在 resource根目錄下創建一個: banner.txt 文件即可
文件當中輸入/填寫你所想要讓你的項目啟動的時候的一些提示信息即可。
這樣其他人沿用了你的項目,啟動該項目的時候,則會看到你的這個廣告信息。
用戶中心——> RainbowSea CSDN 博客地址: rainbowsea.blog.csdn.net


后端接受前端值時出現的問題:


問題:我們需要將前端的傳值的格式修改一下,修改為一個可以被后端識別為一個字符串的值。
**這里使用 **axios-js**的一個前端庫,進行解決 **
axios-js 官網地址:https://www.axios-http.cn/docs/intro


yarn add axios




@CrossOrigin 后端跨域,允許任何請求都同意
一般都是后端處理跨域問題的,更加靈活。后端統一防守。只能防前端,不能防止后端
@CrossOrigin(origins="localhost:8080")

改造用戶中心,把單機登錄改為分布式 Session 登錄
還有一種方式就是:使用 Tociket 。但是 Tociket 過期時間不是那么容易簡單控制的(需要額外配置,但是更加靈活)
Session 共享
種 Session 的時候注意范圍:cookie.domain
比如兩個域名:
- aaa.yupi.com
- bbb.yupi.com
如果要共享 cookie,可以種一個更高層的公共域名,比如:yupi.com 。
為什么服務器 A 登錄后,請求發送到服務器 B,不認識該用戶?
思考:為什么服務器 A 登錄后,請求發到服務器 B,不認識該用戶?
原因如下:
- 用戶在 A 登錄,所以 Session(用戶登錄信息)存在了 A 上
- 結果請求 B 時,B 沒有用戶信息,所以不認識
如圖:

解決方案:共享存儲,而不是把數據放到單臺服務器的內存中。

Redis 基于內存的 K/V 數據庫 ,此處選擇 Redis,因為用戶信息讀取?(是否登錄的判斷極其頻繁),Redis 基于內存,讀寫性能很高,簡單的數據單機 qps 5w-10w
通過將打包的項目,使用java -jar .\yupao-backend-0.0.1-SNAPSHOT.jar --server.port=8081定義 8081 作為該項目的新的端口,從而啟動一個新的項目上的作為一個新的服務器啟動一個項目——》到達分布式服務器的一種方式。
E:\Java\project\魚皮星球項目\伙伴匹配系統\yupao\yupao-backend\target>java -jar .\yupao-backend-0.0.1-SNAPSHOT.jar --server.port=8081



Redis Windows 安裝
- 安裝 Windows 版本的 Redis


在 application.yaml 文件配置 Redis 的相關配置:
spring:
# Redis 配置
redis:
port: 6379
host: localhost
database: 0

- 引入 redis. 能夠操作 redis:盡量和你的 Spring Boot 的版本一一對應上。
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.6.4</version>
</dependency>

- 引入 spring-session 和 Redis 的整合,使得自動將 session 存儲到 Redis 當中。同樣:盡量和你的 Spring Boot 的版本一一對應上。
<!-- https://mvnrepository.com/artifact/org.springframework.session/spring-session-data-redis -->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
<version>2.6.4</version>
</dependency>

- 修改 spring-session 存儲配置,默認是在
spring.session.store-type默認是 none ,表示存儲在單臺服務器。
store-type:redis表示從 redis 讀寫兩個都從 Redis 來 session 。

spring:
session:
timeout: 86400
store-type: redis

server:
port: 8080
servlet:
context-path: /api
spring:
profiles:
active: dev
application:
name: yupao-backend
mvc:
pathmatch:
matching-strategy: ant_path_matcher
# DataSource Config
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/usercenter
username: root
password: MySQL123
# session 失效時間
session:
timeout: 86400
store-type: redis
# Redis 配置
redis:
port: 6379
host: localhost
database: 0
mybatis-plus:
global-config:
db-config:
logic-delete-field: isDelete # 全局邏輯刪除字段名,所以項目表當中所有邏輯刪除,都用這個字段名,保證全局性
logic-delete-value: 1 # 邏輯已刪除值(默認值為 1)
logic-not-delete-value: 0 # 邏輯未刪除值(默認值為 0)
configuration:
# 取消數據庫駝峰映射
map-underscore-to-camel-case: false
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

重新啟動兩個項目,模擬分布式,測試



最后:
“在這個最后的篇章中,我要表達我對每一位讀者的感激之情。你們的關注和回復是我創作的動力源泉,我從你們身上吸取了無盡的靈感與勇氣。我會將你們的鼓勵留在心底,繼續在其他的領域奮斗。感謝你們,我們總會在某個時刻再次相遇。”


浙公網安備 33010602011771號