如何将对象从一个控制器传递到另一个控制器

时间:2017-12-07 15:10:10

标签: java spring-mvc controller

我希望将对象(放置在第一个控制器中的函数模型中)传递给第二个控制器的函数,并将接收到的对象放在函数模型中。

我理解HTTP是无状态的,但有没有办法在不使用Spring MVC中的会话的情况下将对象从一个控制器传递到另一个控制器?感谢。

请参阅我在下面提供的示例代码。

FirstController.java

@RequestMapping(value="search-user",method=RequestMethod.POST)
public ModelAndView searchUser (HttpServletRequest request) {
    //Retrieve the search query by request.getParameter
    String searchQuery = request.getParameter("searchQuery");

    //Search for the user (this is the object that I want to pass)
    User user = userDao.searchUser(searchQuery);

    ModelAndView mav = new ModelAndView(new RedirectView("display-searched-user"));
    mav.addObject("user",user);

    return mav;
}

SecondController.java

@RequestMapping(value="display-searched-user",method={RequestMethod.GET,RequestMethod.POST})
public ModelAndView displayResultUser (HttpServletRequest request) {
    ModelAndView mav = new ModelAndView();
    mav.setViewName("result");

    //I want to receive the object from the FirstController and set that object in this function's model.

    return mav;
}

2 个答案:

答案 0 :(得分:2)

您需要从客户端发送2个电话并发送"用户"到第二个控制器(你应该修改它以接受用户)。所以第一次打电话给" / search-user"返回包含用户的对象。客户端提取用户并将其发送到" / display-searching-user"。

另一种方法可能是,第二个控制器中的请求也接受参数" searchQuery"。在这种情况下,只需将第二个控制器修改为:

@RequestMapping(value="display-searched-user",method={RequestMethod.GET,RequestMethod.POST})
public ModelAndView displayResultUser (HttpServletRequest request) {
    ModelAndView mav = new ModelAndView();
    mav.setViewName("result");

    FirstController fc = new FirstController();
    return fc.searchUser(request);
}

编辑:

我刚刚阅读了CrazySabbath关于创建交通运输类的建议。假设两个控制器都可以访问它,我就像这样实现运输类:

public class UserTransporter {

    private static boolean userAvailable = false;
    private static User user;

    public static boolean isUserAvailable() {
        return userAvailable;
    }

    public static void setUser(User user) {
        UserTransporter.user = user;
        userAvailable = true;
    }

    public static User getUser() {
        userAvailable = false;
        return user;
    }
}

为了清楚起见:我添加了布尔变量,因为我希望无法获得null或获取用户,这已经是之前通过调用获得的。如果您不想检查,只需删除布尔值以及我使用它的任何行。

第一个控制器需要更改为:

@RequestMapping(value="search-user",method=RequestMethod.POST)
public ModelAndView searchUser (HttpServletRequest request) {
    //Retrieve the search query by request.getParameter
    String searchQuery = request.getParameter("searchQuery");

    //Search for the user (this is the object that I want to pass)
    User user = userDao.searchUser(searchQuery);

    ModelAndView mav = new ModelAndView(new RedirectView("display-searched-user"));
    mav.addObject("user",user);

    UserTransporter.setUser(user);

    return mav;
}

第二个控制器需要更改为:

@RequestMapping(value="display-searched-user",method={RequestMethod.GET,RequestMethod.POST})
public ModelAndView displayResultUser (HttpServletRequest request) {
    ModelAndView mav = new ModelAndView();
    mav.setViewName("result");

    User user;
    if(UserTransporter.isUserAvailable()) user = UserTransporter.getUser();
    else return "ERROR, no user available to display";

    //do something with the obtained user object

    return mav;
}

答案 1 :(得分:1)

您可以使用RedirectAttributesModelAttribute实现此目的。

通常情况下,我只是说使用flash属性,但由于这些属性存储在会话中,并且您希望在没有会话的情况下执行此操作,因此您必须使用常规属性执行此操作。

实际上,在再次阅读您的代码后,我认为您真正想要做的是使用会话和Flash属性。不使用一个安全性较低(信任客户端携带用户对象)和/或容易出错。

重定向属性的工作原理是在重定向网址上添加重定向属性作为参数,并发送比简单字符串,整数,双精度等更复杂的内容。我们需要先将其序列化。在这里,我将对象转换为JSON,然后对其进行Base64编码。

这是一个完整的,有效的例子:

@Controller
@SpringBootApplication
public class RedirectController {

    @Autowired
    private ObjectMapper objectMapper;

    // Bean for converting from TestThing to base64 encoded string
    @Bean
    public Converter<TestThing, String> testThingToStringConverter() {
        return new Converter<TestThing, String>() {
            public String convert(TestThing thing) {
                try {
                    return Base64.getUrlEncoder().encodeToString(
                            objectMapper.writeValueAsString(thing)
                                    .getBytes(StandardCharsets.UTF_8));
                } catch (IOException e){
                    throw new RuntimeException(e);
                }
            }
        };
    }

    // Bean for converting from base64 encoded string to TestThing
    @Bean
    public Converter<String, TestThing> stringToTestThingConverter() {
        return new Converter<String, TestThing>() {
            public TestThing convert(String thing) {
                try {
                    return objectMapper.readValue(Base64.getUrlDecoder().decode(thing), TestThing.class);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        };
    }

    public static class TestThing implements Serializable {

        private String firstString;
        private String secondString;

        public String getFirstString() {
            return firstString;
        }

        public void setFirstString(String firstString) {
            this.firstString = firstString;
        }

        public String getSecondString() {
            return secondString;
        }

        public void setSecondString(String secondString) {
            this.secondString = secondString;
        }
    }


    @GetMapping("/test")
    public String testValidation(@RequestParam String firstString,
                                 @RequestParam String secondString,
                                 RedirectAttributes redirectAttributes) {
        TestThing redirectObject = new TestThing();
        redirectObject.firstString = firstString;
        redirectObject.secondString = secondString;

        redirectAttributes.addAttribute("redirectObject", redirectObject);

        return "redirect:/redirected";
    }

    @ResponseBody
    @GetMapping("/redirected")
    public TestThing redirected(@ModelAttribute("redirectObject") TestThing thing) {
        return thing;
    }
    public static void main(String[] args) {
        SpringApplication.run(RedirectController.class, args);
    }
}

如果我们使用Curl与我们的控制器交谈,我们可以看到它有效:

# -L follows redirects
$ curl -L "localhost:8080/test?firstString=first&secondString=second
{"firstString":"first","secondString":"second"}% 

# Now let's do it manually
curl -v "localhost:8080/test?firstString=first&secondString=second"
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> GET /test?firstString=first&secondString=second HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.57.0
> Accept: */*
> 
< HTTP/1.1 302 
< Location: http://localhost:8080/redirected?redirectObject=eyJmaXJzdFN0cmluZyI6ImZpcnN0Iiwic2Vjb25kU3RyaW5nIjoic2Vjb25kIn0%3D
< Content-Language: en-GB
< Content-Length: 0
< Date: Thu, 07 Dec 2017 15:38:02 GMT
< 
* Connection #0 to host localhost left intact

$ curl http://localhost:8080/redirected\?redirectObject\=eyJmaXJzdFN0cmluZyI6ImZpcnN0Iiwic2Vjb25kU3RyaW5nIjoic2Vjb25kIn0%3D
{"firstString":"first","secondString":"second"}

如果您使用Flash属性,示例相同,但您不需要两个Converter,而是使用addFlashAttribute代替addAttribute