【发布时间】: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