欧美三级电影完整|亚洲一二三四久久|性爱视频精品一区二区免费在线观看|国产精品啪啪视频|婷婷六月综合操人妻视频网站|99爱免费视频在线观看|美女一级片在线观看|北京熟女88av|免费看黄色A级电影|欧美黄色毛片儿

hi和hello兩個請求引發(fā)的@RequestBody思考

2023-04-12


hi和hello兩個請求引發(fā)的@RequestBody思考

  • 描述
  • 思考
  • DispatcherServlet
  • AbstractHandlerMethodAdapter
  • RequestMappingHandlerAdapter
  • ServletInvocableHandlerMethod
  • InvocableHandlerMethod
  • HandlerMethodArgumentResolverComposite
  • RequestResponseBodyMethodProcessor
  • 結論
  • 驗證
  • 設置日志打印級別
  • 啟動時關鍵日志
  • hi請求日志
  • hello請求日志
  • 心得

描述


每天多思考一點,不斷豐富自己的知識體系。有hi和hello兩個get請求,他們倆有啥區(qū)別呢?


@GetMapping("/hi")
    public String hi(User user) {
        System.out.println("hi");
        System.out.println(user.toString());
        return "hi";
    }

    @GetMapping("/hello")
    public String hello(@RequestBody User user) {
        System.out.println("hello");
        System.out.println(user.toString());
        return "hello";
    }

使用Apifox發(fā)送如下兩個請求:


  1. http://127.0.0.1:8080/hi
  2. http://127.0.0.1:8080/hello hi請求正常返回“hi”,hello請求則返回如下“400”錯誤。
{
    "timestamp": "2022-04-15T02:00:42.580+00:00",
    "status": 400,
    "error": "Bad Request",
    "path": "/hello"
}

hello請求的后臺錯誤信息如下:


Resolved [org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing: public java.lang.String com.example.web.test.TestController.hello(com.example.web.test.User)]

然后將hello請求參數(shù)改為json格式,如下所示:




然后正常返回字符串“hello”。


思考


首先從寫法看來,hello請求多一個@RequestBody注解,并且這個注解是寫在參數(shù)里的。可以朝著數(shù)據(jù)綁定的方向去思考。@RequestBody源碼如下:


@Target({ElementType.PARAMETER})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface RequestBody {
        boolean required() default true;
    }

然后我們梳理一下一個請求的完整的處理過程。根據(jù)SpringMvc核心架構圖說明,從用戶發(fā)送一個請求到應答信息返回,主要有以下幾個步驟:



  1. 發(fā)送請求到控制器
  2. 控制器進行分發(fā)
  3. 處理器進行數(shù)據(jù)校驗和業(yè)務邏輯調用
  4. service層業(yè)務處理
  5. 邏輯處理完成
  6. 封裝數(shù)據(jù)模型并返回ModelAndView
  7. 控制器調用視圖解析
  8. ViewResolver進行視圖解析
  9. 控制器調用視圖渲染
  10. View進行視圖渲染
  11. 視圖渲染完成,并返回應答信息到用戶
  12. 請求完成

通過跟蹤斷點,發(fā)現(xiàn)以下時間軸方法。



DispatcherServlet

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
	    ……
        // 確定當前請求的 handler adapter
	    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
	    ……
	    // 實際的handler處理
	    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
	    ……
    }

AbstractHandlerMethodAdapter

@Override
	@Nullable
	public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {

		return handleInternal(request, response, (HandlerMethod) handler);
	}

RequestMappingHandlerAdapter

@Override
	protected ModelAndView handleInternal(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
		……
	    // No synchronization on session demanded at all...
		mav = invokeHandlerMethod(request, response, handlerMethod);
		……		
	}

    @Nullable
	protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
		……
		invocableMethod.invokeAndHandle(webRequest, mavContainer);
		……
	}

ServletInvocableHandlerMethod

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {
		Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
	}

InvocableHandlerMethod

@Nullable
    public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
        Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs);
        ……
    }
    protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
      ……
      args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
      ……
    }

HandlerMethodArgumentResolverComposite

@Nullable
    public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
        HandlerMethodArgumentResolver resolver = this.getArgumentResolver(parameter);
        ……
        return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
    }

RequestResponseBodyMethodProcessor

@Override
	public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
	    ……
		Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
		……
	}
	
    @Override
	protected  Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter,
			Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
		……
		Object arg = readWithMessageConverters(inputMessage, parameter, paramType);
		……
	}



圖中部分找到了系統(tǒng)后臺報異常的代碼。


結論


使用@RequestBody注解的接口前置條件如下:


  • 請求頭Content-Type必須設置為application/json
  • 請求體不能為空

驗證


設置日志打印級別

logging.level.root: debug

啟動時關鍵日志

_.s.web.servlet.HandlerMapping.Mappings  : 
	c.e.w.t.TestController:
	{GET [/hi]}: hi(User)
	{GET [/hello]}: hello(User)

hi請求日志

Received [GET /hi HTTP/1.1
User-Agent: apifox/2.1.7 (https://www.apifox.cn)
Accept: */*
Host: 127.0.0.1:8080
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 17

username=xiaoming]

正常響應。


hello請求日志

Received [GET /hello HTTP/1.1
User-Agent: apifox/2.1.7 (https://www.apifox.cn)
Content-Type: application/json
Accept: */*
Host: 127.0.0.1:8080
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Length: 32

{
    "username": "xiaoming"
}]

正常響應。


心得


雖然結論很簡單,但是收獲的是思考的過程。
身為一個程序員,但求勤勤勉勉、兢兢業(yè)業(yè),每天有所得、每事有所得。




本文僅代表作者觀點,版權歸原創(chuàng)者所有,如需轉載請在文中注明來源及作者名字。

免責聲明:本文系轉載編輯文章,僅作分享之用。如分享內容、圖片侵犯到您的版權或非授權發(fā)布,請及時與我們聯(lián)系進行審核處理或刪除,您可以發(fā)送材料至郵箱:service@tojoy.com