簡體   English   中英

如何將@RequestBody 值傳遞給轉發控制器 Spring MVC

[英]How to pass @RequestBody value to forwarded controller Spring MVC

我必須將@RequestBody值消耗到轉發控制器。 當我將 JSON 作為請求主體傳遞時,它將從一個控制器轉發到另一個控制器。 但是它的第二個控制器給出了java.io.IOException

我的控制器

@Controller
public class MyController {

/* 
Request JSON like  
{"personeId":"123789","personName":"Fitz"}
*/
@RequestMapping(value = "/myapp/first/", method = RequestMethod.POST, 
        consumes = { "application/json" })
public String authorize(@RequestBody Person person) {
    //Looking good
    if(Validator.validatePerson(perosn)) {
        return "forward:/myapp/second/";
    } else {
        return "forward:/myapp/secondError/";
    }
}

@RequestMapping(value = "/myapp/second/", method = RequestMethod.POST, 
        consumes = { "application/json" })
public @ResponseBody String login(@RequestBody Person person) {
    // Not able to get Person object here.
    // Getting java.io.IOException: Stream closed :( 
    System.out.println("---> "+person.getPersonName());
    return "success";
}

@RequestMapping(value = "/myapp/secondError/", method = RequestMethod.POST,
        consumes = { "application/json" })
public @ResponseBody String loginError() {
    return "error";
}
}

堆棧跟蹤

org.apache.catalina.core.ApplicationDispatcher invoke
SEVERE: Servlet.service() for servlet dispatcher threw exception
java.io.IOException: Stream closed
    at org.apache.catalina.connector.InputBuffer.readByte(InputBuffer.java:339)
    at org.apache.catalina.connector.CoyoteInputStream.read(CoyoteInputStream.java:94)
    at java.io.FilterInputStream.read(FilterInputStream.java:83)
    at java.io.PushbackInputStream.read(PushbackInputStream.java:139)
    at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.readWithMessageConverters(RequestResponseBodyMethodProcessor.java:168)
    at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:105)
    at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:77)
    at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:162)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:129)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:777)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:706)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:644)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:301)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:721)
    at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:466)
    at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:391)
    at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:318)
    at org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:168)
    at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:303)
    at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1228)
    at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1011)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:955)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:644)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:301)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:503)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:136)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:74)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:516)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1015)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:652)
    at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1575)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1533)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:745)

所以有什么辦法可以用Spring MVC來實現這個場景。

您收到異常是因為@RequestBody注釋讀取底層 servlet 輸入流並使用它,因此您無法讀取它兩次。

如果您仔細查看堆棧跟蹤,您可以注意到原點

org.apache.catalina.connector.InputBuffer.readByte(InputBuffer.java:339)

您正在嘗試(重新)從關閉的流中讀取數據。

如果要保留第一個控制器,現在必須更改第二個控制器,例如,您可以選擇重定向到第二個控制器並將對象放入會話中,或者從第二個控制器中提取執行業務邏輯並調用的方法它來自第一個控制器。

如果您可以將 json 放在 http 調用(授權)的參數中,您可以避免這個問題,但是(授權)它不再是 REST ednpoint,而是類似於“簡單”http 集成的東西。

在這種情況下,您不應轉發,而只需調用其他方法:

@RequestMapping(value = "/myapp/first/", method = RequestMethod.POST, 
        consumes = { "application/json" })
public String authorize(@RequestBody Person person) {
    //Looking good
    if(Validator.validatePerson(perosn)) {
        return login(person);
    } else {
        return loginError();
    }
}

這只有在/myapp/second//myapp/secondError/是真實 URL /myapp/secondError/ ,如果不是,並且如果方法loginloginError應該只從authorize方法調用,它們應該只是控制器中的私有方法。

當然,如果涉及到業務規則,就應該進入服務層。

我不認為你的方法是理想的。 我只會對控制器進行一次調用,然后開始將不同的任務委派給不同的服務。

if(Validator.validatePerson(perosn)) {
    return loginService.login(person);
} else {
    return "error";
}

接受的答案是正確的,沒有適當的解決方案。

但是,這里有一個對我有用的解決方法。 我想構建一個接收 json 並根據command字段在內部轉發請求的調度程序:

@Controller
public class StackoverflowExampleController {

    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    @PostMapping("/post")
    public ModelAndView post(@RequestBody String body) {
        JsonNode tree = OBJECT_MAPPER.readTree(body);
        String command = tree.get("command").asText();
        return new ModelAndView("forward:/" + command + "?json=" + URLEncoder.encode(body)); 
    }
    
    @PostMapping("/test")
    @ResponseBody
    public String test(@RequestParam String json) {
        return json;
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM