【问题标题】:Spring MVC variable resets for no reasonSpring MVC 变量无故重置
【发布时间】:2015-10-11 07:15:28
【问题描述】:

由于某种原因,当我对某个 URI 执行 GET 请求时,我需要在该方法中访问的变量会丢失其内存或指向 null。

我有一个表单,用户可以在其中更新他的个人信息。但是当他输入一个副本时,它会将他重定向到一个让他知道的页面

我有:private static volatile User currentUser;

当用户登录并且服务器对我自己编程的 REST API 执行 GET 请求并返回包含他的信息的用户时设置此字段。这按预期工作,用户信息显示在他的主屏幕上。

以上代码:

@RequestMapping(value = "/login", method = RequestMethod.POST)
    public String login(@ModelAttribute Credentials credentials,
            RedirectAttributes redirect) {

        RestTemplate restTemplate = new RestTemplate();
        RoleInfo roleInfo = restTemplate.postForObject(
                "http://localhost:9090/users/login", credentials,
                RoleInfo.class);

        if (roleInfo != null) {
            if (roleInfo.isAdmin()) {
                redirect.addFlashAttribute("credentials", credentials);
                return "redirect:/adminHome";
            } else {
                redirect.addFlashAttribute("credentials", credentials);
                return "redirect:/getBasicUser";
            }
        } else {
            return "login_fail";
        }
    }

@RequestMapping(value = "/getBasicUser", method = RequestMethod.GET)
    public <T> String getBasicUser(@ModelAttribute Credentials credentials,
            Model model, RedirectAttributes redirect) {

        RestTemplate restTemplate = new RestTemplate();
        String url = "http://localhost:9090/users/getBasicUser?username="
                + credentials.getUsername();
        ResponseEntity<User> responseEntity = restTemplate.exchange(
                url,
                HttpMethod.GET,
                new HttpEntity<T>(createHeaders(credentials.getUsername(),
                        credentials.getPassword())), User.class);
        User user;
        user = responseEntity.getBody();
        currentUser = user;
        System.out.println("current user: " + currentUser.getUsername());
        if (user != null) {
            userName = credentials.getUsername();
            passWord = credentials.getPassword();
            redirect.addFlashAttribute("credentials", credentials);
            redirect.addFlashAttribute("user", user);
            return "redirect:/basicHome";
        } else {
            return "register_fail";
        }
    }

所以他可以在“basicHome”上查看他的信息。该页面上还有一个表单链接,他可以在其中编辑信息:

@RequestMapping(value = "/edit", method = RequestMethod.GET)
    public String getEditProfilePage(Model model) {
        model.addAttribute("currentUser", currentUser);
        System.out.println("current use firstname: " + currentUser.getFirstname());
        model.addAttribute("user", new User());
        return "edit_profile";
    }

如果编辑成功,他将返回到他的主页,其中包含更新的信息。

当他输入无效信息时,问题就来了。他应该被重定向回“/edit” URI,currentUserfield 应该仍然保存他的信息,但实际上是空的。

这里是“/edit”PUT函数:

@RequestMapping(value = "/edit", method = RequestMethod.PUT)
    public <T> String editProfile(@ModelAttribute("user") User user,
            @ModelAttribute("credentials") Credentials credentials,
            RedirectAttributes redirect) {

        RestTemplate restTemplate = new RestTemplate();
        String url = "http://localhost:9090/users/update?username=" + userName;

        HttpHeaders headers = createHeaders(userName,
                passWord);

        @SuppressWarnings({ "unchecked", "rawtypes" })
        HttpEntity<T> entity = new HttpEntity(user, headers);

        ResponseEntity<User> responseEntity = restTemplate.exchange(url,
                HttpMethod.PUT, entity, User.class);

        User returnedUser = responseEntity.getBody();
        currentUser = returnedUser;

        if (returnedUser != null) {
            redirect.addFlashAttribute("user", returnedUser);
            redirect.addFlashAttribute("credentials", credentials);
            return "redirect:/basicHome";
        } else {
            return "redirect:/editFail";
        }
    }

【问题讨论】:

  • 你在用static volatile User做什么! - 摆脱类级变量
  • @6ton 没关系。我需要它来存储检索到的值,而不是使用 model.addAttribute("user", user);
  • 那么当 两个 用户尝试同时执行相同的操作时会发生什么?看起来问题在于您的高度非正统设计,而不是 Spring MVC “无缘无故”地做事。
  • @Kryger,这就是我使用 volatile 关键字的原因。我相信它可以防止数据竞争并进行同步,但是以不同的方式而不使用真正的锁。
  • 即使使用 volatile,两个并发用户仍会“争夺”同一个变量,您需要使用 ThreadLocal 来实现您的目标。请注意,它仍然是一个糟糕的解决方案,使得一开始就很难编写测试。

标签: spring spring-mvc spring-security


【解决方案1】:

我知道我必须做什么。我基本上将“用户”作为会话对象:@SessionAttributes("user")

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-27
    • 2013-05-16
    • 1970-01-01
    • 2017-08-08
    • 2011-05-20
    相关资源
    最近更新 更多