如何在两个控制器之间传递对象

3
我希望将一个放置在第一个控制器模型中的对象传递给第二个控制器的函数,并将接收到的对象放置在该函数的模型中。我知道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;
}

为什么不创建一个类来为您传输该对象? - CrazySabbath
CrazySabbath,你能提供一个传输对象的类的示例代码吗?谢谢。 - Devsharan Shupta
Naeramarth的答案能够解决我的问题,但如果还有其他方法或解决方案,请在这里发布。谢谢。 - Devsharan Shupta
你为什么要避免使用会话(session)? - Raniz
我认为您会在这里找到一个很好的答案: (https://dev59.com/-6fja4cB1Zd3GeqPuVl4#47698398) - L.G
2个回答

2
你需要从客户端发送两个调用,并将“User”发送到第二个控制器(你需要修改以接受用户)。因此,第一个调用“/search-user”返回一个包含用户的对象。客户端提取用户并将其发送到“/display-searched-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;
}

请澄清一下,FirstController里面没有问题吗?我的意思是,我不需要在FirstController上做任何更改吗? - Devsharan Shupta
1
我刚刚添加了一个运输类的示例,就像CrazySabbath建议的那样。回答您的问题:我不认为会有问题。除非FirstController包含任何@Autowired注释,这可能会引起问题。但是,由于我没有看到您在全局实例化任何变量,因此我认为只需按照我展示的方式使用您的FirstController即可。 - Naeramarth
1
Raniz,我看不到创建一个交通工具类的其他方法,除非你想将其传递给客户端,否则这将与直接将用户传递给客户端相同。 - Naeramarth
Naeramarth你的解决方案能够帮助我解决问题。谢谢。 - Devsharan Shupta
1
你采用了哪种解决方案?是从 SecondController 调用 FirstController 吗? - Naeramarth
显示剩余4条评论

1
您可以使用RedirectAttributesModelAttribute来实现此目的。
通常我会建议使用flash属性,但由于这些属性存储在会话中,而您想要在没有会话的情况下完成此操作,因此您必须使用常规属性。
实际上,在再次阅读您的代码后,我认为您真正想要做的是使用会话和flash属性。不使用会话较不安全(信任客户端携带用户对象)和/或容易出错。
重定向属性通过将重定向属性添加为重定向URL上的参数来工作,并且要发送比简单字符串、int、double等更复杂的内容,我们需要首先对其进行序列化。在此示例中,我通过将对象转换为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"}

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接