是否還記得SpringMVC中的@MatrixVariable注解?
環(huán)境:SpringBoot3.0.5
1. 簡(jiǎn)介
RFC 3986【https://datatracker.ietf.org/doc/html/rfc3986#section-3.3】討論了路徑段中的name-value對(duì)。在Spring MVC中,我們將它們稱為“矩陣變量”,但它們也可以稱為URI路徑參數(shù)。
矩陣變量可以出現(xiàn)在任何路徑段中,每個(gè)變量用分號(hào)分隔,多個(gè)值用逗號(hào)分隔(例如/cars;color=red,green;year=2012)。還可以通過重復(fù)的變量名指定多個(gè)值(例如,color=red;color=green;color=blue)。
如果期望URL包含矩陣變量,則控制器方法的請(qǐng)求映射必須使用URI變量來屏蔽變量?jī)?nèi)容,并確保請(qǐng)求可以成功匹配,而不依賴于矩陣變量的順序和存在。下面的例子使用了一個(gè)矩陣變量:
// GET /pets/42;q=11;r=22
@GetMapping("/pets/{petId}")
public void findPet(@PathVariable String petId, @MatrixVariable int q) {
// petId == 42
// q == 11
}
@MatrixVariable應(yīng)用場(chǎng)景
- 主要適用于需要在URI路徑中傳遞多個(gè)與路徑段相關(guān)的參數(shù),并且希望保持URI清晰、語義化的情況下。
- 一個(gè)資源需要通過多維度資源定位時(shí),一個(gè)URI可能需要同時(shí)標(biāo)識(shí)多個(gè)維度的信息。比如在一個(gè)圖片處理服務(wù)中,可能會(huì)通過顏色模式、分辨率等參數(shù)來定位特定版本的圖片資源。
/images/pic1.png;colors=rgb;resolution=high
2. 實(shí)戰(zhàn)案例
2.1 案例1
@GetMapping("/m1/{id}")
public Object matrix1(@PathVariable("id") Long id, @MatrixVariable Integer q, @MatrixVariable String p) {
return String.format("input, id: %d, q: %d, p: %s", id, q, p) ;
}
請(qǐng)求
圖片
2.2 案例2
多個(gè)矩陣變量,在不同的路徑變量中定義
@GetMapping("/m2/{cateId}/a2/{artId}")
public Object matrix2(
@PathVariable("cateId") Long cateId,
@MatrixVariable(pathVar = "cateId", name = "q") Integer q1,
@PathVariable("artId") Long artId,
@MatrixVariable(pathVar = "artId", name = "q") Integer q2) {
return String.format("input, cateId: %d, q: %d, artId: %d, q: %s%n",
cateId, q1, artId, q2) ;
}
請(qǐng)求
圖片
2.3 案例3
使用Map接收矩陣值
@GetMapping("/m3/{cateId}/a2/{artId}")
public Object matrix3(
@PathVariable("cateId") Long cateId,
@MatrixVariable MultiValueMap<String, String> cateMap,
@PathVariable("artId") Long artId,
@MatrixVariable(pathVar = "artId") MultiValueMap<String, String> artMap) {
return Map.of("cate", cateMap, "art", artMap) ;
}
請(qǐng)求
圖片
注意:這里的a=1,2有多個(gè)值可以使用','分割。
2.4 案例4
當(dāng)變量路徑之后沒有添加矩陣參數(shù)時(shí),會(huì)報(bào)錯(cuò)。
圖片
我們可以通過配置,指定非必須活著設(shè)定默認(rèn)值。
@GetMapping("/m2/{cateId}/a2/{artId}")
public Object matrix2(
...,
// 設(shè)置默認(rèn)值
@MatrixVariable(pathVar = "artId", name = "q", required = false, defaultValue = "999") Integer q2) {
return String.format("input, cateId: %d, q: %d, artId: %d, q: %s%n",
cateId, q1, artId, q2) ;
}
3. 實(shí)現(xiàn)原理
這里以上面的 案例2 講解。
3.1 路徑匹配存儲(chǔ)矩陣變量
public abstract class AbstractHandlerMethodMapping {
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
}
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) {
handleMatch(bestMatch.mapping, lookupPath, request);
}
}
beastMatch.mapping
圖片
lookupPath
圖片
public abstract class RequestMappingInfoHandlerMapping {
protected void handleMatch(RequestMappingInfo info, String lookupPath, HttpServletRequest request) {
extractMatchDetails(pprc, lookupPath, request);
}
private void extractMatchDetails(...) {
// 將矩陣編碼存入到request對(duì)象中
request.setAttribute(MATRIX_VARIABLES_ATTRIBUTE, result.getMatrixVariables());
}
}
3.2 解析@MatrixVariable注解的參數(shù)
public class MatrixVariableMethodArgumentResolver {
protected Object resolveName(...) throws Exception {
// 從request中取出上一步存入的map集合
Map<String, MultiValueMap<String, String>> pathParameters = (Map<String, MultiValueMap<String, String>>)
request.getAttribute(HandlerMapping.MATRIX_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST);
MatrixVariable ann = parameter.getParameterAnnotation(MatrixVariable.class);
// 獲取注解配置的pathVar值
String pathVar = ann.pathVar();
if (!pathVar.equals(ValueConstants.DEFAULT_NONE)) {
if (pathParameters.containsKey(pathVar)) {
// 取出值
paramValues = pathParameters.get(pathVar).get(name);
}
}
// 返回?cái)?shù)據(jù)
return paramValues.get(0);
}
}
以上本篇文章的全部?jī)?nèi)容,希望對(duì)你有所幫助。
完畢?。?!