日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
手把手教你在SpringBoot中自定義參數(shù)解析器

放在地址欄中,我們可以通過如下方式獲取參數(shù):

十多年的蒲縣網(wǎng)站建設(shè)經(jīng)驗(yàn),針對設(shè)計(jì)、前端、開發(fā)、售后、文案、推廣等六對一服務(wù),響應(yīng)快,48小時(shí)及時(shí)工作處理。全網(wǎng)整合營銷推廣的優(yōu)勢是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動(dòng)調(diào)整蒲縣建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計(jì),從而大程度地提升瀏覽體驗(yàn)。成都創(chuàng)新互聯(lián)公司從事“蒲縣網(wǎng)站設(shè)計(jì)”,“蒲縣網(wǎng)站推廣”以來,每個(gè)客戶項(xiàng)目都認(rèn)真落實(shí)執(zhí)行。

String javaboy = request.getParameter("name ");

放在請求體中,如果是 key/value 形式,我們可以通過如下方式獲取參數(shù):

String javaboy = request.getParameter("name ");

如果是 JSON 形式,我們則通過如果如下方式獲取到輸入流,然后解析成 JSON 字符串,再通過 JSON 工具轉(zhuǎn)為對象:

BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream()));
String json = reader.readLine();
reader.close();
User user = new ObjectMapper().readValue(json, User.class);

如果參數(shù)放在請求頭中,我們可以通過如下方式獲?。?/p>

String javaboy = request.getHeader("name");

如果你用的是 Jsp/Servlet 那一套技術(shù)棧,那么參數(shù)獲取無外乎這幾種方式。

如果用了 SpringMVC 框架,有的小伙伴們可能會(huì)覺得參數(shù)獲取方式太豐富了,各種注解如 @RequestParam、@RequestBody、@RequestHeader、@PathVariable,參數(shù)可以是 key/value 形式,也可以是 JSON 形式,非常豐富!但是,無論多么豐富,最底層獲取參數(shù)的方式無外乎上面幾種。

那有小伙伴要問了,SpringMVC 到底是怎么樣從 request 中把參數(shù)提取出來直接給我們用的呢?例如下面這個(gè)接口:

@RestController
public class HelloController {
@GetMapping("/hello")
public String hello(String name) {
return "hello "+name;
}
}

我們都知道 name 參數(shù)是從 HttpServletRequest 中提取出來的,到底是怎么提取出來的?這就是松哥今天要和大家分享的話題。

1.自定義參數(shù)解析器

為了搞清楚這個(gè)問題,我們先來自定義一個(gè)參數(shù)解析器看看。

自定義參數(shù)解析器需要實(shí)現(xiàn) HandlerMethodArgumentResolver 接口,我們先來看看該接口:

public interface HandlerMethodArgumentResolver {
boolean supportsParameter(MethodParameter parameter);
@Nullable
Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;

}

這個(gè)接口中就兩個(gè)方法:

  • supportsParameter:該方法表示是否啟用這個(gè)參數(shù)解析器,返回 true 表示啟用,返回 false 表示不啟用。
  • resolveArgument:這是具體的解析過程,就是從 request 中取出參數(shù)的過程,方法的返回值就對應(yīng)了接口中參數(shù)的值。

自定義參數(shù)解析器只需要實(shí)現(xiàn)該接口即可。

假設(shè)我現(xiàn)在有這樣一個(gè)需求(實(shí)際上在 Spring Security 中獲取當(dāng)前登錄用戶名非常方便,這里只是為了該案例而做,勿抬杠):

假設(shè)我現(xiàn)在系統(tǒng)安全框架使用了 Spring Security(對 Spring Security 不熟悉的小伙伴,可以在公眾號(hào)江南一點(diǎn)雨后臺(tái)回復(fù) ss,有教程),如果我在接口的參數(shù)上添加了 @CurrentUserName 注解,那么該參數(shù)的值就是當(dāng)前登錄的用戶名,像下面這樣:

@RestController
public class HelloController {
@GetMapping("/hello")
public String hello(@CurrentUserName String name) {
return "hello "+name;
}
}

要實(shí)現(xiàn)這個(gè)功能,非常 easy,首先我們自定義一個(gè) @CurrentUserName 注解,如下:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface CurrentUserName {
}

這個(gè)注解沒啥好解釋的。

接下來我們自定義參數(shù)解析器 CurrentUserNameHandlerMethodArgumentResolver,如下:

public class CurrentUserNameHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterType().isAssignableFrom(String.class)&¶meter.hasParameterAnnotation(CurrentUserName.class);
}

@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
return user.getUsername();
}
}
  • supportsParameter:如果參數(shù)類型是 String,并且參數(shù)上有 @CurrentUserName 注解,則使用該參數(shù)解析器。
  • resolveArgument:該方法的返回值就是參數(shù)的具體值,當(dāng)前登錄用戶名從 SecurityContextHolder 中獲取即可。

最后,我們再將自定義的參數(shù)解析器配置到 HandlerAdapter 中,配置方式如下:

@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addArgumentResolvers(List resolvers) {
resolvers.add(new CurrentUserNameHandlerMethodArgumentResolver());
}
}

至此,就算配置完成了。

接下來啟動(dòng)項(xiàng)目,用戶登錄成功后,訪問 /hello 接口,就可以看到返回當(dāng)前登錄用戶數(shù)據(jù)了。

這就是我們自定義的一個(gè)參數(shù)類型解析器。可以看到,非常 Easy。

在 SpringMVC 中,默認(rèn)也有很多 HandlerMethodArgumentResolver 的實(shí)現(xiàn)類,他們處理的問題也都類似,松哥再給大家舉個(gè)例子。

2.PrincipalMethodArgumentResolver

如果我們在項(xiàng)目中使用了 Spring Security,我們可以通過如下方式獲取當(dāng)前登錄用戶信息:

@GetMapping("/hello2")
public String hello2(Principal principal) {
return "hello " + principal.getName();
}

即直接在當(dāng)前接口的參數(shù)中添加 Principal 類型的參數(shù)即可,該參數(shù)描述了當(dāng)前登錄用戶信息,這個(gè)用過 Spring Security 的小伙伴應(yīng)該都知道。

那么這個(gè)功能是怎么實(shí)現(xiàn)的呢?當(dāng)然就是 PrincipalMethodArgumentResolver 在起作用了!

我們一起來看下這個(gè)參數(shù)解析器:

public class PrincipalMethodArgumentResolver implements HandlerMethodArgumentResolver {

@Override
public boolean supportsParameter(MethodParameter parameter) {
return Principal.class.isAssignableFrom(parameter.getParameterType());
}

@Override
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
if (request == null) {
throw new IllegalStateException("Current request is not of type HttpServletRequest: " + webRequest);
}

Principal principal = request.getUserPrincipal();
if (principal != null && !parameter.getParameterType().isInstance(principal)) {
throw new IllegalStateException("Current user principal is not of type [" +
parameter.getParameterType().getName() + "]: " + principal);
}

return principal;
}

}
  • supportsParameter:這個(gè)方法主要是判斷參數(shù)類型是不是 Principal,如果參數(shù)類型是 Principal,就支持。
  • resolveArgument:這個(gè)方法的邏輯很簡單,首先獲取原生的請求,再從請求中獲取 Principal 對象返回即可。

是不是很簡單,有了這個(gè),我們就可以隨時(shí)加載到當(dāng)前登錄用戶信息了。

3.RequestParamMapMethodArgumentResolver

松哥再給大家舉個(gè)例子:

@RestController
public class HelloController {
@PostMapping("/hello")
public void hello(@RequestParam MultiValueMap map) throws IOException {
//省略...
}
}

這個(gè)接口很多小伙伴可能都寫過,使用 Map 去接收前端傳來的參數(shù),那么這里用到的參數(shù)解析器就是 RequestParamMapMethodArgumentResolver。

public class RequestParamMapMethodArgumentResolver implements HandlerMethodArgumentResolver {

@Override
public boolean supportsParameter(MethodParameter parameter) {
RequestParam requestParam = parameter.getParameterAnnotation(RequestParam.class);
return (requestParam != null && Map.class.isAssignableFrom(parameter.getParameterType()) &&
!StringUtils.hasText(requestParam.name()));
}

@Override
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

ResolvableType resolvableType = ResolvableType.forMethodParameter(parameter);

if (MultiValueMap.class.isAssignableFrom(parameter.getParameterType())) {
// MultiValueMap
Class valueType = resolvableType.as(MultiValueMap.class).getGeneric(1).resolve();
if (valueType == MultipartFile.class) {
MultipartRequest multipartRequest = MultipartResolutionDelegate.resolveMultipartRequest(webRequest);
return (multipartRequest != null ? multipartRequest.getMultiFileMap() : new LinkedMultiValueMap<>(0));
}
else if (valueType == Part.class) {
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
if (servletRequest != null && MultipartResolutionDelegate.isMultipartRequest(servletRequest)) {
Collection parts = servletRequest.getParts();
LinkedMultiValueMap result = new LinkedMultiValueMap<>(parts.size());
for (Part part : parts) {
result.add(part.getName(), part);
}
return result;
}
return new LinkedMultiValueMap<>(0);
}
else {
Map parameterMap = webRequest.getParameterMap();
MultiValueMap result = new LinkedMultiValueMap<>(parameterMap.size());
parameterMap.forEach((key, values) -> {
for (String value : values) {
result.add(key, value);
}
});
return result;
}
}

else {
// Regular Map
Class valueType = resolvableType.asMap().getGeneric(1).resolve();
if (valueType == MultipartFile.class) {
MultipartRequest multipartRequest = MultipartResolutionDelegate.resolveMultipartRequest(webRequest);
return (multipartRequest != null ? multipartRequest.getFileMap() : new LinkedHashMap<>(0));
}
else if (valueType == Part.class) {
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
if (servletRequest != null && MultipartResolutionDelegate.isMultipartRequest(servletRequest)) {
Collection parts = servletRequest.getParts();
LinkedHashMap result = CollectionUtils.newLinkedHashMap(parts.size());
for (Part part : parts) {
if (!result.containsKey(part.getName())) {
result.put(part.getName(), part);
}
}
return result;
}
return new LinkedHashMap<>(0);
}
else {
Map parameterMap = webRequest.getParameterMap();
Map result = CollectionUtils.newLinkedHashMap(parameterMap.size());
parameterMap.forEach((key, values) -> {
if (values.length > 0) {
result.put(key, values[0]);
}
});
return result;
}
}
}

}

supportsParameter:參數(shù)類型是 Map,并且使用了 @RequestParam 注解,并且 @RequestParam 注解中沒有配置 name 屬性,就可以使用該參數(shù)解析器。

resolveArgument:具體解析分為兩種情況:MultiValueMap 和其他 Map,前者中又分三種情況:MultipartFile、Part 或者其他普通請求,前兩者可以處理文件上傳,第三個(gè)就是普通參數(shù)。如果是普通 Map,則直接獲取到原始請求參數(shù)放到一個(gè) Map 集合中返回即可。


網(wǎng)頁題目:手把手教你在SpringBoot中自定義參數(shù)解析器
標(biāo)題路徑:http://www.dlmjj.cn/article/djhphdg.html