如何将@RequestBody值传递给转发控制器Spring MVC

时间:2015-04-30 10:58:31

标签: java json spring spring-mvc

我必须使用@RequestBody的值来转发控制器。当我将JSON作为请求主体传递时,从一个控制器传递给另一个控制器。但它提供了第二个控制器java.io.IOException

MyController.java

@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实现此方案。

4 个答案:

答案 0 :(得分:1)

您正在获取异常,因为@RequestBody注释会读取基础servlet输入流并使用它,因此您无法读取它两次。

如果仔细观察堆栈跟踪,可以注意原点

  

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

您正在尝试(重新)从已关闭的流中读取数据。

如果你想保留现在的第一个控制器你必须改变第二个控制器,你可以选择例如重定向到第二个控制器并将对象放入会话或从第二个执行业务的控制器中提取方法逻辑并从第一个控制器调用它。

如果你可以将json放在http调用的参数(authorize)中,你可以避免这个问题,但是(授权)它不再是一个REST ednpoint,而是像" simple&# 34; http集成。

答案 1 :(得分:1)

在这种情况下你不应该转发,而只是调用其他方法:

@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/是真实网址,那么这只会有意义,如果没有,并且方法loginloginError只能从{{1}调用方法,它们应该只是控制器中的私有方法。

当然,如果它涉及业务规则,它应该进入服务层。

答案 2 :(得分:0)

我不认为你的方法是理想的。我只有一次调用控制器,然后开始将不同的任务委托给不同的服务。

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

答案 3 :(得分:0)

接受的答案是正确的,没有适当的解决方案。

但是,这是一种对我有用的解决方法。我想构建一个接受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;
    }
}