# 第四章 自媒體素材管理
目標
- 能掌握什么是fastdfs
- 能掌握fastdfs的流程架構
- 能夠掌握分布式文件系統fastdfs的基本使用
- 能夠搭建dfs微服務實現素材管理功能
- 能夠完成自媒體文章列表查詢功能
1 admin網關對接用戶微服務
上一章網關地址對接(如果已經對接配置過了則不用對接)
在admin網關的yml文件中進行配置如下:

- id: user
uri: lb://leadnews-user
predicates:
- Path=/user/**
filters:
- StripPrefix= 1
注意格式配置
2 FastDFS
2.1 FastDFS介紹
FastDFS是一個開源的輕量級分布式文件系統,它對文件進行管理,功能包括:文件存儲、文件同步、文件訪問(文件上傳、文件下載)等,解決了大容量存儲和負載均衡的問題。特別適合以文件為載體的在線服務,如相冊網站、視頻網站等等。
FastDFS為互聯網量身定制,充分考慮了冗余備份、負載均衡、線性擴容等機制,并注重高可用、高性能等指標,使用FastDFS很容易搭建一套高性能的文件服務器集群提供文件上傳、下載等服務。
FastDFS 架構包括 Tracker server 和 Storage server。客戶端請求 Tracker server 進行文件上傳、下載,通過Tracker server 調度最終由 Storage server 完成文件上傳和下載。
Tracker server 作用是負載均衡和調度,通過 Tracker server 在文件上傳時可以根據一些策略找到Storage server 提供文件上傳服務。可以將 tracker 稱為追蹤服務器或調度服務器。Storage server 作用是文件存儲,客戶端上傳的文件最終存儲在 Storage 服務器上,Storageserver 沒有實現自己的文件系統而是利用操作系統的文件系統來管理文件。可以將storage稱為存儲服務器。

架構流程圖如下(可參考講義中攜帶的具體流程圖):

3.2 文件上傳流程

客戶端上傳文件后存儲服務器將文件 ID 返回給客戶端,此文件 ID 用于以后訪問該文件的索引信息。文件索引信息包括:組名,虛擬磁盤路徑,數據兩級目錄,文件名。

組名:文件上傳后所在的 storage 組名稱,在文件上傳成功后有storage 服務器返回,需要客戶端自行保存。
虛擬磁盤路徑:storage 配置的虛擬路徑,與磁盤選項store_path*對應。如果配置了
store_path0 則是 M00,如果配置了 store_path1 則是 M01,以此類推。
數據兩級目錄:storage 服務器在每個虛擬磁盤路徑下創建的兩級目錄,用于存儲數據文件。
文件名:與文件上傳時不同。是由存儲服務器根據特定信息生成,文件名包含:源存儲
服務器 IP 地址、文件創建時間戳、文件大小、隨機數和文件拓展名等信息。
3.3 FastDFS服務端搭建
注意:該操作步驟已經完成,虛擬機已經搭建完成了,不需要大家再去搭建
(1)虛擬機中拉取鏡像
docker pull morunchang/fastdfs
(2)運行tracker
docker run -d --name tracker --net=host morunchang/fastdfs sh tracker.sh
(3)運行storage
docker run -d --name storage --net=host -e TRACKER_IP=192.168.211.136:22122 -e GROUP_NAME=group1 morunchang/fastdfs sh storage.sh
說明:
使用的網絡模式是–net=host, 192.168.211.136是宿主機的IP
group1是組名,即storage的組
如果想要增加新的storage服務器,再次運行該命令,注意更換 新組名
設置開啟自啟動(可以不做):
docker update --restart=always tracker
docker update --restart=always storage
(4)修改nginx
Nginx在這里主要提供對FastDFS圖片訪問的支持,Docker容器中已經集成了Nginx,我們需要修改nginx的配置,進入storage的容器內部,修改nginx.conf
(4.1)進入容器
docker exec -it storage /bin/bash
(4.2)修改配置
vi /etc/nginx/conf/nginx.conf
修改訪問端口為如下:

3.4 文件操作
3.4.1 環境搭建
(1)新建項目:leadnews-fastdfs-demo 用作測試

(2)pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.itheima</groupId>
<artifactId>leadnews-fastdfs-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.8.RELEASE</version>
</parent>
<dependencies>
<!--fastdfs-->
<dependency>
<groupId>com.github.tobato</groupId>
<artifactId>fastdfs-client</artifactId>
<version>1.26.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>
(3)編寫啟動類
package com.itheima;
import com.github.tobato.fastdfs.FdfsClientConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Import;
/**
* @author ljh
* @version 1.0
* @date 2020/11/27 15:40
* @description 標題
* @package com.itheima
*/
@SpringBootApplication
@Import(FdfsClientConfig.class)
public class FastdfsApplication {
public static void main(String[] args) {
SpringApplication.run(FastdfsApplication.class,args);
}
}
(5)yml中
fdfs:
so-timeout: 1501
connect-timeout: 601
thumb-image: #縮略圖生成參數
width: 150
height: 150
tracker-list: #TrackerList參數,支持多個
- 192.168.211.136:22122
3.4.2 編寫測試實現文件的基本操作
編寫測試類test下創建如下類 com.itheima.FastadfsTest:
package com.itheima;
import com.github.tobato.fastdfs.domain.fdfs.StorePath;
import com.github.tobato.fastdfs.domain.proto.storage.DownloadCallback;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import org.apache.commons.io.IOUtils;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.util.StringUtils;
import java.io.*;
/**
* @author ljh
* @version 1.0
* @date 2020/11/27 15:43
* @description 標題
* @package com.itheima
*/
@SpringBootTest
public class FastadfsTest {
@Autowired
private FastFileStorageClient storageClient;
//上傳圖片
@Test
public void uploadFile() throws IOException {
//創建流對象
File file = new File("C:\\Users\\admin\\Pictures\\45.png");
FileInputStream inputStream = new FileInputStream(file);
long length = file.length();
//獲取文件的擴展名不帶點
String extName = StringUtils.getFilenameExtension(file.getName());
//上傳圖片
StorePath storePath = storageClient.uploadFile(
inputStream,
length,
extName,
null);
System.out.println(storePath);
System.out.println(storePath.getFullPath());
}
//刪除圖片
//
@Test
public void deleteFile() {
//group + path
storageClient.deleteFile("group1/M00/00/00/wKjTiF_BIUqAMwDrAAAl8vdCW2Y127.png");
}
//下載圖片
@Test
public void download() throws Exception{
byte[] group1s = storageClient.downloadFile("group1", "M00/00/00/wKjTiF_BIrCAAn9IAAAl8vdCW2Y205.png", new DownloadCallback<byte[]>() {
@Override
public byte[] recv(InputStream ins) throws IOException {
//獲取字節數組
byte[] bytes = IOUtils.toByteArray(ins);
return bytes;
}
});
//下載
FileOutputStream fileOutputStream = new FileOutputStream(new File("e:/abc.png"));
fileOutputStream.write(group1s);
fileOutputStream.close();
}
}
3.5 黑馬頭條的圖片處理解決方案

由于很多個微服務都需要用到圖片相關的存儲 刪除 獲取等 所以為了方便擴展維護,利于升級,我們獨立出一個獨立的文件存儲微服務 用于對存儲的圖片 文件 視頻進行管理,而其他的微服務通過feign進行調用 實現相關的操作。
圖片上傳 則直接可以訪問文件存儲微服務即可。
3.6 文件微服務
3.6.1 文件微服務搭建
步驟如下:
(1)創建itheima-leadnews-service-dfs工程微服務
(2)添加依賴
(3)創建啟動類
(4)配置yml
(5)實現圖片上傳
(1)創建itheima-leadnews-service-dfs工程微服務

(2)添加依賴
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>itheima-leadnews-service</artifactId>
<groupId>com.itheima</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>itheima-leadnews-service-dfs</artifactId>
<description>文件存儲微服務</description>
<dependencies>
<!--fastdfs-->
<dependency>
<groupId>com.github.tobato</groupId>
<artifactId>fastdfs-client</artifactId>
<version>1.26.5</version>
</dependency>
<dependency>
<groupId>com.itheima</groupId>
<artifactId>itheima-leadnews-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
(3)創建啟動類
package com.itheima;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* @author ljh
* @version 1.0
* @date 2021/2/26 17:04
* @description 標題
* @package com.itheima
*/
@SpringBootApplication
@EnableDiscoveryClient
public class DfsApplication {
public static void main(String[] args) {
SpringApplication.run(DfsApplication.class, args);
}
}
(4)配置yml
spring:
profiles:
active: dev
---
server:
port: 9005
spring:
application:
name: leadnews-dfs
profiles: dev
cloud:
nacos:
server-addr: 192.168.211.136:8848
discovery:
server-addr: ${spring.cloud.nacos.server-addr}
servlet:
multipart:
max-file-size: 10MB
max-request-size: 10MB
# fastdfs的配置
fdfs:
so-timeout: 1501
connect-timeout: 601
thumb-image: #縮略圖生成參數
width: 150
height: 150
tracker-list:
- 192.168.211.136:22122 #TrackerList參數,支持多個
web-server-url: http://192.168.211.136/ # 設置前綴路徑
logging:
level.com: debug
---
server:
port: 9005
spring:
application:
name: leadnews-dfs
profiles: pro
cloud:
nacos:
server-addr: 192.168.211.136:8848
discovery:
server-addr: ${spring.cloud.nacos.server-addr}
servlet:
multipart:
max-file-size: 10MB
max-request-size: 10MB
# fastdfs的配置
fdfs:
so-timeout: 1501
connect-timeout: 601
thumb-image: #縮略圖生成參數
width: 150
height: 150
tracker-list:
- 192.168.211.136:22122 #TrackerList參數,支持多個
web-server-url: http://192.168.211.136/ # 設置前綴路徑
---
server:
port: 9005
spring:
application:
name: leadnews-dfs
profiles: test
cloud:
nacos:
server-addr: 192.168.211.136:8848
discovery:
server-addr: ${spring.cloud.nacos.server-addr}
servlet:
multipart:
max-file-size: 10MB
max-request-size: 10MB
# fastdfs的配置
fdfs:
so-timeout: 1501
connect-timeout: 601
thumb-image: #縮略圖生成參數
width: 150
height: 150
tracker-list:
- 192.168.211.136:22122 #TrackerList參數,支持多個
web-server-url: http://192.168.211.136/ # 設置前綴路徑
3.6.2 實現圖片上傳功能
分析:
1 頁面上,選擇上傳的圖片,并點擊上傳圖片按鈕
2 后臺文件微服務接收到請求并獲取到上傳文件數據 封裝到MultipartFile 對象中
3 后臺將文件對象獲取之后 上傳給fastdfs中
4 返回前端上傳成功之后的路徑即可
功能實現:
創建controller 實現功能:
package com.itheima.dfs;
import com.github.tobato.fastdfs.domain.conn.FdfsWebServer;
import com.github.tobato.fastdfs.domain.fdfs.StorePath;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import com.itheima.common.pojo.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.util.HashMap;
import java.util.Map;
/**
* @author ljh
* @version 1.0
* @date 2021/2/26 17:07
* @description 標題
* @package com.itheima.dfs
*/
@RestController
@RequestMapping("/dfs")
public class FileController {
@Autowired
private FastFileStorageClient fastFileStorageClient;
@Autowired
private FdfsWebServer fdfsWebServer;
/**
* 上傳文件
* @param file
* @return
*/
@PostMapping("/upload")
public Result<Map<String,String>> upload(MultipartFile file) throws Exception{
StorePath storePath = fastFileStorageClient.uploadFile(
file.getInputStream(),
file.getSize(),
StringUtils.getFilenameExtension(file.getOriginalFilename()),
null
);
String fullPath = storePath.getFullPath();
String realUrl = fdfsWebServer.getWebServerUrl()+fullPath;
Map<String,String> map = new HashMap<String,String>();
map.put("url",realUrl);
//設置返回圖片的路徑
return Result.ok(map);
}
}

測試:


4 素材管理
4.1 添加素材
4.1.1 需求分析

點擊如上傳圖片彈出如下:

提交到的數據存儲到如下表中:

4.1.2 實現思路分析
分析:
應該有兩個大步驟:
1. 需要先上傳圖片成功并回顯在頁面上
2. 選擇類型 并最終點擊【提交】按鈕 將上傳之后的圖片地址和選擇的文件類型數據 傳遞給后臺 添加數據到后臺表中
1.步驟已經在上一節中實現,只需要前端發送一個請求到文件微服務上上傳圖片即可,前端拿到鏈接地址進行回顯
2.我們只需要實現第二步驟就好了
4.1.3 功能實現
(1)重寫controller
package com.itheima.media.controller;
import com.itheima.common.pojo.Result;
import com.itheima.core.controller.AbstractCoreController;
import com.itheima.media.pojo.WmMaterial;
import com.itheima.media.service.WmMaterialService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
/**
* <p>
* 自媒體圖文素材信息表 控制器</p>
* @author ljh
* @since 2021-02-25
*/
@RestController
@RequestMapping("/wmMaterial")
public class WmMaterialController extends AbstractCoreController<WmMaterial> {
private WmMaterialService wmMaterialService;
//注入
@Autowired
public WmMaterialController(WmMaterialService wmMaterialService) {
super(wmMaterialService);
this.wmMaterialService=wmMaterialService;
}
/**
* 重寫父類方法 實現添加素材
* @param record
* @return
*/
@PostMapping
@Override
public Result insert(@RequestBody WmMaterial record) {
//1.設置補充屬性
//todo 先硬編碼 設置為該素材所屬的自媒體賬號ID
record.setUserId(1000);
//未收藏
record.setIsCollection(0);
//圖片
record.setType(0);
//創建時間
record.setCreatedTime(LocalDateTime.now());
//2.保存到數據庫中
wmMaterialService.save(record);
return Result.ok(record);
}
}

測試注意:這userId的數據需要更改
4.2 自媒體端網關
4.2.1 自媒體網關說明
上一次創建的admin平臺管理的網關,自媒體端也有自己的網關,后邊還需要創建app端的網關,自媒體網關與admin端網關幾乎是一樣的,可以參考admin端網關。

訪問可以按照如圖的方式進行 先經過網關再路由到不同的微服務 以實現相關的權限的控制。
4.2.2 搭建自媒體網關
自媒體網關可以參考admin網關進行搭建。
(1)創建工程

(2)pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>itheima-leadnews-gateway</artifactId>
<groupId>com.itheima</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>itheima-leadnews-gateway-media</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.itheima</groupId>
<artifactId>itheima-leadnews-common</artifactId>
<version>1.0-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>
(3)創建啟動類
package com.itheima;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* @author ljh
* @version 1.0
* @date 2021/2/26 19:44
* @description 標題
* @package com.itheima
*/
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayMediaApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayMediaApplication.class,args);
}
}
(4)yaml
spring:
profiles:
active: dev
---
server:
port: 6002
spring:
application:
name: leadnews-media-gateway
profiles: dev
cloud:
nacos:
server-addr: 192.168.211.136:8848
discovery:
server-addr: ${spring.cloud.nacos.server-addr}
gateway:
globalcors:
cors-configurations:
'[/**]': # 匹配所有請求
allowedOrigins: "*" #跨域處理 允許所有的域
allowedHeaders: "*"
allowedMethods: # 支持的方法
- GET
- POST
- PUT
- DELETE
routes:
# 平臺管理
- id: media
uri: lb://leadnews-wemedia
predicates:
- Path=/media/**
filters:
- StripPrefix= 1
- id: dfs
uri: lb://leadnews-dfs
predicates:
- Path=/dfs/**
filters:
- StripPrefix= 1
---
server:
port: 6002
spring:
application:
name: leadnews-media-gateway
profiles: test
cloud:
nacos:
server-addr: 192.168.211.136:8848
discovery:
server-addr: ${spring.cloud.nacos.server-addr}
gateway:
globalcors:
cors-configurations:
'[/**]': # 匹配所有請求
allowedOrigins: "*" #跨域處理 允許所有的域
allowedHeaders: "*"
allowedMethods: # 支持的方法
- GET
- POST
- PUT
- DELETE
routes:
# 平臺管理
- id: media
uri: lb://leadnews-wemedia
predicates:
- Path=/media/**
filters:
- StripPrefix= 1
- id: dfs
uri: lb://leadnews-dfs
predicates:
- Path=/dfs/**
filters:
- StripPrefix= 1
---
server:
port: 6002
spring:
application:
name: leadnews-media-gateway
profiles: pro
cloud:
nacos:
server-addr: 192.168.211.136:8848
discovery:
server-addr: ${spring.cloud.nacos.server-addr}
gateway:
globalcors:
cors-configurations:
'[/**]': # 匹配所有請求
allowedOrigins: "*" #跨域處理 允許所有的域
allowedHeaders: "*"
allowedMethods: # 支持的方法
- GET
- POST
- PUT
- DELETE
routes:
# 平臺管理
- id: media
uri: lb://leadnews-wemedia
predicates:
- Path=/media/**
filters:
- StripPrefix= 1
- id: dfs
uri: lb://leadnews-dfs
predicates:
- Path=/dfs/**
filters:
- StripPrefix= 1
4.2.3 實現自媒體用戶登錄功能
(1)controller
//登錄功能的方法
@PostMapping("/login")
public Result<Map<String,Object>> login(@RequestBody WmUser wmUser) throws LeadNewsException {
Map<String,Object> info = wmUserService.login(wmUser);
return Result.ok(info);
}

(2)service
@Service
public class WmUserServiceImpl extends ServiceImpl<WmUserMapper, WmUser> implements WmUserService {
@Autowired
private WmUserMapper wmUserMapper;
@Override
public Map<String, Object> login(WmUser wmUser) throws LeadNewsException{
//1.獲取頁面傳遞過來的用戶名
String name = wmUser.getName();
String password = wmUser.getPassword();
//2.校驗用戶名不能為空 (密碼不能Wie空)
if(StringUtils.isEmpty(name) || StringUtils.isEmpty(password)){
throw new LeadNewsException("兄弟用戶名和密碼不能為空");
}
//3.從數據庫中獲取 (根據用戶名) 一行數據 判斷 如果沒有 返回
QueryWrapper<WmUser> quweryWrapper = new QueryWrapper<>();
quweryWrapper.eq("name",name);
WmUser wmUserFromDb = wmUserMapper.selectOne(quweryWrapper);
if(wmUserFromDb==null){
throw new LeadNewsException("用戶名或者密碼錯誤");
}
//4.0對比(獲取頁面傳遞過來的密碼 明文 ---》通過獲取到數據庫中的鹽值 ---》md5加密 --》得出密文)
String passwordFromweb = DigestUtils.md5DigestAsHex((password+wmUserFromDb.getSalt()).getBytes());
//4.1 獲取數據庫中的密碼 判斷 頁面來的密文 和數據庫中密文是否一致 如果不一致 返回錯誤
String passwordfromDb = wmUserFromDb.getPassword();
if(!passwordfromDb.equals(passwordFromweb)){
throw new LeadNewsException("用戶名或者密碼錯誤");
}
//5. 生成令牌
String token = AppJwtUtil.createToken(Long.valueOf(wmUserFromDb.getId()));
Map<String,Object> map = new HashMap<>();
map.put("token",token);
//看需求 todo
map.put("userheadpic",wmUserFromDb.getImage());
map.put("nickname",wmUserFromDb.getNickname());
return map;
}
}

4.2.4 實現自媒體網關校驗解析token
這個完全可以參考admin端網關。
package com.itheima.gatewaymedia.filter;
import com.itheima.common.constants.SystemConstants;
import com.itheima.common.util.AppJwtUtil;
import io.jsonwebtoken.Claims;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Component
public class MeidaAuthorizeFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//1.獲取請求對象和響應對象
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
//2.判斷當前的請求是否為登錄,如果是,直接放行 當然也可以使用另外一種方式來判斷
if(path.endsWith("/media/wmUser/login") || path.endsWith("/v2/api-docs")){
return chain.filter(exchange);
}
//3.獲取當前用戶的請求頭jwt信息
//請求頭的名稱為token
String jwtToken = request.getHeaders().getFirst("token");
//4.判斷當前令牌是否存在
if(StringUtils.isEmpty(jwtToken)){
//如果不存在,向客戶端返回錯誤提示信息
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
try {
//5.如果令牌存在,解析jwt令牌,判斷該令牌是否合法,如果不合法,則向客戶端返回錯誤信息
int result = AppJwtUtil.verifyToken(jwtToken);
if(result== SystemConstants.JWT_OK){
//解析數據
Claims claimsBody = AppJwtUtil.getClaimsBody(jwtToken);
//設置登錄的用戶的ID 頭名為userId中并下發到下游微服務
//exchange.getRequest().mutate().header("userId",claimsBody.get("id").toString());
exchange.getRequest().mutate().header(SystemConstants.USER_HEADER_NAME,claimsBody.get("id").toString());
}else {
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
}catch (Exception e){
e.printStackTrace();
//想客戶端返回錯誤提示信息
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
//6.放行
return chain.filter(exchange);
}
/**
* 優先級設置
* 值越小,優先級越高
* @return
*/
@Override
public int getOrder() {
return 0;
}
}
常量類中添加數據如下圖

/**
* 請求頭名
*/
public static final String USER_HEADER_NAME="userId";
思考一個問題?
為什么要向下游微服務傳遞頭信息?目的是什么?
4.2.5 實現微服務獲取登錄用戶信息
4.2.5.1 需求
自媒體添加素材的時候 用戶的ID 設置為了硬編碼如下所示,這個是需要修改的

如何獲取呢?
4.2.5.2 實現思路

網關解析到了token之后,向下游傳遞用戶信息,有很多種方式:常用2種
1.下游微服務通過攔截器 可以獲取到請求頭中的用戶的ID 值,并返回給controller中進行使用即可。
2.編寫一個工具類 直接使用springmvc為我們提供的請求的線程副本 RequestContextHolder中的方法獲取(本質使用ThreadLocal來實現)
第一種方式相對麻煩一些,還需要進行攔截器創建和配置,并進行綁定(大家有興趣可以自己實現下)。這里我采用第二種。
4.2.5.3 實現功能
public class RequestContextUtil {
/**
* 獲取登錄的用戶的ID 可以是自媒體賬號 也可以是 平臺賬號 也可以是app賬號
* @return
*/
public static String getUserInfo(){
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
//獲取路由轉發的頭信息
String headerValue = request.getHeader(SystemConstants.USER_HEADER_NAME);
return headerValue;
}
}
(2)修改素材添加功能
@PostMapping
@Override
public Result insert(@RequestBody WmMaterial record) {
//1.設置補充屬性
//todo 先硬編碼 設置為該素材所屬的自媒體賬號ID
String userId = RequestContextUtil.getUserInfo();
record.setUserId(Integer.valueOf(userId));
//未收藏
record.setIsCollection(0);
//圖片
record.setType(0);
//創建時間
record.setCreatedTime(LocalDateTime.now());
//2.保存到數據庫中
wmMaterialService.save(record);
return Result.ok(record);
}
浙公網安備 33010602011771號