欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

spring mvc中@RequestBody注解的作用說(shuō)明

 更新時(shí)間:2022年08月18日 17:12:12   作者:健康平安的活著  
這篇文章主要介紹了spring mvc中@RequestBody注解的作用說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

@RequestBody的作用

@RequestBody主要用來(lái)接收前端傳遞給后端的json字符串中的數(shù)據(jù)的(請(qǐng)求體中的數(shù)據(jù)的),所以只能發(fā)送POST請(qǐng)求。

GET方式無(wú)請(qǐng)求體,所以使用@RequestBody接收數(shù)據(jù)時(shí),前端不能使用GET方式提交數(shù)據(jù),而是用POST方式進(jìn)行提交。

在后端的同一個(gè)接收方法里,@RequestBody與@RequestParam()可以同時(shí)使用,@RequestBody最多只能有一個(gè),而@RequestParam()可以有多個(gè)。

注:一個(gè)請(qǐng)求,只有一個(gè)RequestBody;一個(gè)請(qǐng)求,可以有多個(gè)RequestParam。

jQuery中,$.ajax()默認(rèn)發(fā)送的參數(shù)類型及編碼為:application/x-www-form-urlcoded,而@RequestBody處理的參數(shù)類型及編碼為:aplication/json或者是application/xml,通過(guò)contentType屬性來(lái)指定

在傳遞之前,對(duì)JSON對(duì)象要使用JSON.stringify(),JSON.stringify() 方法將一個(gè) JavaScript 值(對(duì)象或者數(shù)組)轉(zhuǎn)換為一個(gè) JSON 字符串

后端@RequestBody注解對(duì)應(yīng)的類在將HTTP的輸入流(含請(qǐng)求體)裝配到目標(biāo)類(即:@RequestBody后面的類)時(shí),會(huì)根據(jù)json字符串中的key來(lái)匹配對(duì)應(yīng)實(shí)體類的屬性,如果匹配一致且json中的該key對(duì)應(yīng)的值符合(或可轉(zhuǎn)換為)實(shí)體類的對(duì)應(yīng)屬性的類型要求時(shí),會(huì)調(diào)用實(shí)體類的setter方法將值賦給該屬性。

注:當(dāng)同時(shí)使用@RequestParam()和@RequestBody時(shí),@RequestParam()指定的參數(shù)可以是普通元素、數(shù)組、集合、對(duì)象等等

(即:當(dāng),@RequestBody 與@RequestParam()可以同時(shí)使用時(shí),原SpringMVC接收參數(shù)的機(jī)制不變,只不過(guò)RequestBody 接收的是請(qǐng)求體里面的數(shù)據(jù);而RequestParam接收的是key-value里面的參數(shù),所以它會(huì)被切面進(jìn)行處理從而可以用普通元素、數(shù)組、集合、對(duì)象等接收)

實(shí)現(xiàn)案例

1. jsp頁(yè)面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <script src="${pageContext.request.contextPath}/js/jquery.min.js"></script>
    <script>
        var userList=new Array();
        userList.push({userName:"beijing",age:34});
        userList.push({userName:"shanghai",age:89});
        $.ajax({
            type:"post",
            url:"${pageContext.request.contextPath}/bike7",
            data:JSON.stringify(userList),
            contentType:"application/json;charset=utf-8",
            success:function(result){
                alert(result);
            }
        })
    </script>
</head>
<body>
 
</body>
</html>

2. controller

  /**
     * @author liujianfu
     * @description      controller中業(yè)務(wù)方法的集合參數(shù)獲取,要將集合參數(shù)封裝到一個(gè)pojo中才可以
     * 參數(shù)屬性名與請(qǐng)求參數(shù)名稱一致,參數(shù)值會(huì)自動(dòng)映射匹配
     * @date 2021/1/10 22:14
     * @param
     * @return
     */
    @RequestMapping("/bike6")
    public String bike6(){
      System.out.println("controller6:");
        return "ajax";
    }
    /**
     * @author liujianfu
     * @description      controller中業(yè)務(wù)方法的集合參數(shù)獲取,要將集合參數(shù)封裝到一個(gè)pojo中才可以
     * 參數(shù)屬性名與請(qǐng)求參數(shù)名稱一致,參數(shù)值會(huì)自動(dòng)映射匹配
     * @date 2021/1/10 22:14
     * @param
     * @return
     */
    @RequestMapping("/bike7")
    @ResponseBody
    public String bike7(@RequestBody List<User> userList){
        for(User u:userList){
            System.out.println("user:"+u.getUserName());
        }
        return "ok";
    }

3. spring-mvc 配置文件

4. 頁(yè)面訪問(wèn)

@RequestBody原理

通過(guò)Http傳遞參數(shù)一般有兩種方式,一種是通過(guò)url解析參數(shù),一種是通過(guò)body來(lái)解決,那么我們本次說(shuō)的RequestBody就是去解析請(qǐng)求體然后映射到我們的參數(shù),那它該如何解析body呢?這就是本篇博客誕生的目的。

這個(gè)其實(shí)是SpringMVC中做的一個(gè)處理機(jī)制,在整個(gè)SpringMVC的處理流程中,會(huì)通過(guò)HandlerMethod來(lái)代理每個(gè)Map后的controller和method,在通過(guò)反射invoke method的過(guò)程中,會(huì)解析request來(lái)獲得arguments,而@RequestBody就是在解析參數(shù)的這個(gè)過(guò)程中起作用的

1. 執(zhí)行流程

在InvocableHandlerMethod#getMethodArgumentValues中,它會(huì)遍歷當(dāng)前HandlerMethod的參數(shù),對(duì)于每一個(gè)參數(shù),它都會(huì)通過(guò)HandlerMethodArgumentResolverComposite#supportsParameter來(lái)判斷是否可以被解析器解析,如果可以被解析,則通過(guò)HandlerMethodArgumentResolverComposite#resolveArguement進(jìn)行解析

對(duì)于@RequestBody來(lái)說(shuō),它對(duì)應(yīng)的解析器是RequestResponseBodyMethodProcessor,那么,我們就深入到它的源碼中來(lái)一探究竟:

public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {
	// 是否可以解析當(dāng)前參數(shù)
	@Override
	public boolean supportsParameter(MethodParameter parameter) {
		return parameter.hasParameterAnnotation(RequestBody.class);
	}
    // 是否可以解析當(dāng)前返回值
	@Override
	public boolean supportsReturnType(MethodParameter returnType) {
		return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
				returnType.hasMethodAnnotation(ResponseBody.class));
	}
	
	@Override
	public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
		parameter = parameter.nestedIfOptional();
        // 解析handlerMethod中的參數(shù)
		Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
        // 獲取變量名
		String name = Conventions.getVariableNameForParameter(parameter);
		if (binderFactory != null) {
			WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
			if (arg != null) {
                // 通過(guò)binder校驗(yàn)@Validated注解的字段
				validateIfApplicable(binder, parameter);
				if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
					throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
				}
			}
			if (mavContainer != null) {
				mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
			}
		}
        // 如果方法是Optional參數(shù),則代理
		return adaptArgumentIfNecessary(arg, parameter);
	}
	@Override
	protected <T> Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter,
			Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
		HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
		Assert.state(servletRequest != null, "No HttpServletRequest");
		ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(servletRequest);
        // 解析http請(qǐng)求中的body并映射到對(duì)應(yīng)的parameter上
		Object arg = readWithMessageConverters(inputMessage, parameter, paramType);
		if (arg == null && checkRequired(parameter)) {
			throw new HttpMessageNotReadableException("Required request body is missing: " +
					parameter.getExecutable().toGenericString());
		}
		return arg;
	}
	protected boolean checkRequired(MethodParameter parameter) {
		RequestBody requestBody = parameter.getParameterAnnotation(RequestBody.class);
		return (requestBody != null && requestBody.required() && !parameter.isOptional());
	}
}

2. 注冊(cè)流程

那么RequestResponseBodyMethodProcessor是如何被注冊(cè)到resolver中呢?主要是在RequestMappingHandlerAdapter中:

  • RequestMappingHandlerAdapter實(shí)現(xiàn)了HandlerAdapter這個(gè)接口,這個(gè)接口是MVC框架的SPI,DispatcherServlet通過(guò)此接口訪問(wèn)所有已安裝的處理程序。
  • HandlerAdapter主要是路由之后方法的適配器,DispatcherServlet在路由之后通過(guò)HandlerAdapter來(lái)執(zhí)行真實(shí)的操作(handlerAdapter是通過(guò)HandlerMethod來(lái)執(zhí)行的)

對(duì)于RequestResponseBodyMethodProcessor來(lái)說(shuō),它實(shí)現(xiàn)了InitializingBean,在bean初始化之后會(huì)添加參數(shù)處理器和返回值處理器,對(duì)于參數(shù)處理器來(lái)說(shuō),內(nèi)容如下:

從圖中我們可以看到,RequestMappingHandlerAdapter在初始化的時(shí)候會(huì)把系統(tǒng)給定的,自定義的參數(shù)解析器加載到內(nèi)存中。

加入說(shuō),我們要自定義一個(gè)參數(shù)解析器,系統(tǒng)會(huì)在什么時(shí)候加載進(jìn)入內(nèi)存呢?

我們發(fā)現(xiàn)RequestMappingHandlerAdapter#setCustomArgumentResolvers這個(gè)方法就是要去設(shè)置自定義參數(shù)解析器的,那么我們只需要找到它的調(diào)用方即可。

我們只需要實(shí)現(xiàn)WebMvcConfigurer即可(這點(diǎn)關(guān)系到Spring的自動(dòng)裝配,暫時(shí)沒(méi)有看到,先鴿一下)

3. 設(shè)計(jì)優(yōu)點(diǎn)

設(shè)計(jì)模式

采用策略模式+工廠模式 + 組合模式:

對(duì)于HandlerMethod的參數(shù)和返回值處理來(lái)說(shuō),對(duì)應(yīng)著不同的處理方式,即對(duì)應(yīng)著不同的策略,所以此處用的策略模式來(lái)處理的。至于HandlerMethodArgumentResolverComposite它則對(duì)應(yīng)著策略工廠,同時(shí),因?yàn)檫@個(gè)類實(shí)現(xiàn)了HandlerMethodArgumentResolver,所以它也是組合模式的變形,具體的策略類是HandlerMethodArgumentResolver

類圖如下:

緩存處理

在參數(shù)解析工廠中,剛開(kāi)始的參數(shù)解析器是在剛啟動(dòng)時(shí)注冊(cè)到list中,但是如果之后被使用的時(shí)候就會(huì)存放到map中,可以直接獲得(key是MethodParam),提高路由效率

附:常見(jiàn)的MVC參數(shù)注解

對(duì)于url解析參數(shù)來(lái)說(shuō),有兩個(gè)注解,分別是pathVariable(指一種占位符)和requestParam,對(duì)于body來(lái)說(shuō),有requestBody。不加注解,也可以直接把url轉(zhuǎn)為對(duì)應(yīng)參數(shù)或者實(shí)體類

1.@PathVariable: www.666.com/web/6

@GetMapping("/web/{node}")
public ReturnType listEmployeeInNode(@PathVariable String node) throws BusinessException {
}

2.@ReqeustParam: www.666.com/web?user=1

@GetMapping("/web")
public ReturnType listEmployeeInNode(@RequestParam("user") String node) throws BusinessException {
}

3.@RequestBody: www.666.com/web body中是json

@GetMapping("/web")
public ReturnType listEmployeeInNode(@RequestBody UserDTO userDto) throws BusinessException {
}

4.無(wú)注解:www.666.com/web?userId=1&pwd=2

@PostMapping("/web")
public ReturnType listEmployeeInNode(UserDTO userDto) throws BusinessException {
}

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java深入淺出說(shuō)流的使用

    Java深入淺出說(shuō)流的使用

    這篇文章主要介紹了Java深入淺出說(shuō)流的使用,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-09-09
  • SpringMVC參數(shù)傳遞之基本數(shù)據(jù)類型和復(fù)雜對(duì)象說(shuō)明

    SpringMVC參數(shù)傳遞之基本數(shù)據(jù)類型和復(fù)雜對(duì)象說(shuō)明

    這篇文章主要介紹了SpringMVC參數(shù)傳遞之基本數(shù)據(jù)類型和復(fù)雜對(duì)象說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • Java基礎(chǔ)教程之?dāng)?shù)組的定義與使用

    Java基礎(chǔ)教程之?dāng)?shù)組的定義與使用

    Java語(yǔ)言的數(shù)組是一個(gè)由固定長(zhǎng)度的特定類型元素組成的集合,它們的數(shù)據(jù)類型必須相同,聲明變量的時(shí)候,必須要指定參數(shù)類型,這篇文章主要給大家介紹了關(guān)于Java基礎(chǔ)教程之?dāng)?shù)組的定義與使用的相關(guān)資料,需要的朋友可以參考下
    2021-09-09
  • 深入聊一聊JDK中的Map和Set

    深入聊一聊JDK中的Map和Set

    這篇文章主要給大家介紹了關(guān)于JDK中Map和Set的相關(guān)資料,文中通過(guò)示例代碼以及圖文介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用jdk具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2022-12-12
  • Java使用Statement接口執(zhí)行SQL語(yǔ)句操作實(shí)例分析

    Java使用Statement接口執(zhí)行SQL語(yǔ)句操作實(shí)例分析

    這篇文章主要介紹了Java使用Statement接口執(zhí)行SQL語(yǔ)句操作,結(jié)合實(shí)例形式詳細(xì)分析了Java使用Statement接口針對(duì)mysql數(shù)據(jù)庫(kù)進(jìn)行連接與執(zhí)行SQL語(yǔ)句增刪改查等相關(guān)操作技巧與注意事項(xiàng),需要的朋友可以參考下
    2018-07-07
  • IDEA導(dǎo)入Springboot項(xiàng)目,注解和pom文件不識(shí)別的解決

    IDEA導(dǎo)入Springboot項(xiàng)目,注解和pom文件不識(shí)別的解決

    這篇文章主要介紹了IDEA導(dǎo)入Springboot項(xiàng)目,注解和pom文件不識(shí)別的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • java如何遍歷對(duì)象中的所有屬性(字段)和類型

    java如何遍歷對(duì)象中的所有屬性(字段)和類型

    這篇文章主要介紹了java如何遍歷對(duì)象中的所有屬性(字段)和類型問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • Spring 源碼解析CommonAnnotationBeanPostProcessor

    Spring 源碼解析CommonAnnotationBeanPostProcessor

    這篇文章主要為大家介紹了Spring 源碼解析CommonAnnotationBeanPostProcessor示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • JAVA簡(jiǎn)單工廠模式(從現(xiàn)實(shí)生活角度理解代碼原理)

    JAVA簡(jiǎn)單工廠模式(從現(xiàn)實(shí)生活角度理解代碼原理)

    本文主要介紹了JAVA簡(jiǎn)單工廠模式(從現(xiàn)實(shí)生活角度理解代碼原理)的相關(guān)知識(shí)。具有很好的參考價(jià)值。下面跟著小編一起來(lái)看下吧
    2017-03-03
  • Java編程實(shí)現(xiàn)打地鼠文字游戲?qū)嵗a

    Java編程實(shí)現(xiàn)打地鼠文字游戲?qū)嵗a

    這篇文章主要介紹了Java編程實(shí)現(xiàn)打地鼠文字游戲?qū)嵗a,具有一定借鑒價(jià)值,需要的朋友可以參考下。
    2017-11-11

最新評(píng)論