繁体   English   中英

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

[英]How to pass an object from one controller to another 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个呼叫并将“用户”发送到第二个控制器(您应该修改它以接受用户)。 因此,对“/ 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;
}

您可以使用RedirectAttributesModelAttribute实现此目的

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

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

重定向属性通过在重定向URL上添加重定向属性作为参数来工作,并发送比简单字符串,整数,双精度等更复杂的任何内容。我们需要先将其序列化。 在这里,我通过将对象转换为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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM