中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

spring?mvc中@RequestBody注解的作用是什么

發布時間:2022-08-26 14:37:05 來源:億速云 閱讀:188 作者:iii 欄目:開發技術

這篇文章主要介紹“spring mvc中@RequestBody注解的作用是什么”,在日常操作中,相信很多人在spring mvc中@RequestBody注解的作用是什么問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”spring mvc中@RequestBody注解的作用是什么”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

@RequestBody的作用

@RequestBody主要用來接收前端傳遞給后端的json字符串中的數據的(請求體中的數據的),所以只能發送POST請求。

GET方式無請求體,所以使用@RequestBody接收數據時,前端不能使用GET方式提交數據,而是用POST方式進行提交。

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

注:一個請求,只有一個RequestBody;一個請求,可以有多個RequestParam。

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

在傳遞之前,對JSON對象要使用JSON.stringify(),JSON.stringify() 方法將一個 JavaScript 值(對象或者數組)轉換為一個 JSON 字符串

后端@RequestBody注解對應的類在將HTTP的輸入流(含請求體)裝配到目標類(即:@RequestBody后面的類)時,會根據json字符串中的key來匹配對應實體類的屬性,如果匹配一致且json中的該key對應的值符合(或可轉換為)實體類的對應屬性的類型要求時,會調用實體類的setter方法將值賦給該屬性。

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

(即:當,@RequestBody 與@RequestParam()可以同時使用時,原SpringMVC接收參數的機制不變,只不過RequestBody 接收的是請求體里面的數據;而RequestParam接收的是key-value里面的參數,所以它會被切面進行處理從而可以用普通元素、數組、集合、對象等接收)

實現案例

1. jsp頁面

<%@ 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中業務方法的集合參數獲取,要將集合參數封裝到一個pojo中才可以
     * 參數屬性名與請求參數名稱一致,參數值會自動映射匹配
     * @date 2021/1/10 22:14
     * @param
     * @return
     */
    @RequestMapping("/bike6")
    public String bike6(){
      System.out.println("controller6:");
        return "ajax";
    }
    /**
     * @author liujianfu
     * @description      controller中業務方法的集合參數獲取,要將集合參數封裝到一個pojo中才可以
     * 參數屬性名與請求參數名稱一致,參數值會自動映射匹配
     * @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 配置文件

spring?mvc中@RequestBody注解的作用是什么

4. 頁面訪問

spring?mvc中@RequestBody注解的作用是什么

spring?mvc中@RequestBody注解的作用是什么

@RequestBody原理

通過Http傳遞參數一般有兩種方式,一種是通過url解析參數,一種是通過body來解決,那么我們本次說的RequestBody就是去解析請求體然后映射到我們的參數,那它該如何解析body呢?這就是本篇博客誕生的目的。

這個其實是SpringMVC中做的一個處理機制,在整個SpringMVC的處理流程中,會通過HandlerMethod來代理每個Map后的controller和method,在通過反射invoke method的過程中,會解析request來獲得arguments,而@RequestBody就是在解析參數的這個過程中起作用的

spring?mvc中@RequestBody注解的作用是什么

1. 執行流程

在InvocableHandlerMethod#getMethodArgumentValues中,它會遍歷當前HandlerMethod的參數,對于每一個參數,它都會通過HandlerMethodArgumentResolverComposite#supportsParameter來判斷是否可以被解析器解析,如果可以被解析,則通過HandlerMethodArgumentResolverComposite#resolveArguement進行解析

spring?mvc中@RequestBody注解的作用是什么

對于@RequestBody來說,它對應的解析器是RequestResponseBodyMethodProcessor,那么,我們就深入到它的源碼中來一探究竟:

public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {
	// 是否可以解析當前參數
	@Override
	public boolean supportsParameter(MethodParameter parameter) {
		return parameter.hasParameterAnnotation(RequestBody.class);
	}
    // 是否可以解析當前返回值
	@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中的參數
		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) {
                // 通過binder校驗@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參數,則代理
		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請求中的body并映射到對應的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. 注冊流程

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

  • RequestMappingHandlerAdapter實現了HandlerAdapter這個接口,這個接口是MVC框架的SPI,DispatcherServlet通過此接口訪問所有已安裝的處理程序。

  • HandlerAdapter主要是路由之后方法的適配器,DispatcherServlet在路由之后通過HandlerAdapter來執行真實的操作(handlerAdapter是通過HandlerMethod來執行的)

對于RequestResponseBodyMethodProcessor來說,它實現了InitializingBean,在bean初始化之后會添加參數處理器和返回值處理器,對于參數處理器來說,內容如下:

spring?mvc中@RequestBody注解的作用是什么

從圖中我們可以看到,RequestMappingHandlerAdapter在初始化的時候會把系統給定的,自定義的參數解析器加載到內存中。

加入說,我們要自定義一個參數解析器,系統會在什么時候加載進入內存呢?

我們發現RequestMappingHandlerAdapter#setCustomArgumentResolvers這個方法就是要去設置自定義參數解析器的,那么我們只需要找到它的調用方即可。

我們只需要實現WebMvcConfigurer即可(這點關系到Spring的自動裝配,暫時沒有看到,先鴿一下)

3. 設計優點

設計模式

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

對于HandlerMethod的參數和返回值處理來說,對應著不同的處理方式,即對應著不同的策略,所以此處用的策略模式來處理的。至于HandlerMethodArgumentResolverComposite它則對應著策略工廠,同時,因為這個類實現了HandlerMethodArgumentResolver,所以它也是組合模式的變形,具體的策略類是HandlerMethodArgumentResolver

類圖如下:

spring?mvc中@RequestBody注解的作用是什么

緩存處理

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

附:常見的MVC參數注解

對于url解析參數來說,有兩個注解,分別是pathVariable(指一種占位符)和requestParam,對于body來說,有requestBody。不加注解,也可以直接把url轉為對應參數或者實體類

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.無注解:www.666.com/web?userId=1&pwd=2

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

到此,關于“spring mvc中@RequestBody注解的作用是什么”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

柳州市| 石城县| 漳州市| 阿拉善右旗| 敦化市| 沿河| 田阳县| 乐业县| 乌审旗| 宜宾市| 永泰县| 大姚县| 福建省| 理塘县| 和田县| 抚顺市| 清水河县| 舞阳县| 青州市| 安岳县| 清徐县| 庆元县| 高邮市| 罗源县| 淮南市| 新乡县| 岱山县| 历史| 太谷县| 黄大仙区| 海原县| 玉门市| 高安市| 贡山| 醴陵市| 涿鹿县| 兴业县| 葫芦岛市| 漯河市| 湟中县| 友谊县|