亚洲欧美日韩熟女|做爱高潮视频网址|国产一区二区三级片|国产Av中文字幕www.性色av|亚洲婷婷永久免费|国产高清中文字幕|欧美变态网站久re视频精品|人妻AV鲁丝第一页|天堂AV一区二区在线观看|综合 91在线精品

hi和hello兩個(gè)請(qǐng)求引發(fā)的@RequestBody思考

2023-04-12


hi和hello兩個(gè)請(qǐng)求引發(fā)的@RequestBody思考

  • 描述
  • 思考
  • DispatcherServlet
  • AbstractHandlerMethodAdapter
  • RequestMappingHandlerAdapter
  • ServletInvocableHandlerMethod
  • InvocableHandlerMethod
  • HandlerMethodArgumentResolverComposite
  • RequestResponseBodyMethodProcessor
  • 結(jié)論
  • 驗(yàn)證
  • 設(shè)置日志打印級(jí)別
  • 啟動(dòng)時(shí)關(guān)鍵日志
  • hi請(qǐng)求日志
  • hello請(qǐng)求日志
  • 心得

描述


每天多思考一點(diǎn),不斷豐富自己的知識(shí)體系。有hi和hello兩個(gè)get請(qǐng)求,他們倆有啥區(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ā)送如下兩個(gè)請(qǐng)求:


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

hello請(qǐng)求的后臺(tái)錯(cuò)誤信息如下:


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請(qǐng)求參數(shù)改為json格式,如下所示:




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


思考


首先從寫法看來(lái),hello請(qǐng)求多一個(gè)@RequestBody注解,并且這個(gè)注解是寫在參數(shù)里的??梢猿鴶?shù)據(jù)綁定的方向去思考。@RequestBody源碼如下:


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

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



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

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



DispatcherServlet

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
	    ……
        // 確定當(dāng)前請(qǐng)求的 handler adapter
	    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
	    ……
	    // 實(shí)際的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)后臺(tái)報(bào)異常的代碼。


結(jié)論


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


  • 請(qǐng)求頭Content-Type必須設(shè)置為application/json
  • 請(qǐng)求體不能為空

驗(yàn)證


設(shè)置日志打印級(jí)別

logging.level.root: debug

啟動(dòng)時(shí)關(guān)鍵日志

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

hi請(qǐng)求日志

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]

正常響應(yīng)。


hello請(qǐng)求日志

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īng)。


心得


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




本文僅代表作者觀點(diǎn),版權(quán)歸原創(chuàng)者所有,如需轉(zhuǎn)載請(qǐng)?jiān)谖闹凶⒚鱽?lái)源及作者名字。

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