我面临春天的问题,如下:
在SessionAttributes中,我有一个对象人,其属性地址是一个列表。每当通过控制器更新人员时,之前的条目仍然存在。因此,例如,如果我有亲自地址:旧地址1,旧地址2,旧地址3和我通过表单更新人只有一个新地址,地址列表变为:新地址1,旧地址2,旧地址3而预期的行为是只有“新地址1”。我似乎找不到解决这个问题的方法。我使用的是Spring 3.0.X。
请在下面找到显示手头问题的所有相关代码。
Person.java:
package com.convert.dashboard.web.test;
import java.util.List;
public class Person {
private String name;
private Integer age;
private List<String> addresses;
public Person(List<String> addresses) {
this.addresses = addresses;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public List<String> getAddresses() {
return addresses;
}
public void setAddresses(List<String> addresses) {
this.addresses = addresses;
}
}
TestController.java
package com.convert.dashboard.web.test;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.servlet.ModelAndView;
@Controller
@RequestMapping("/test")
@SessionAttributes("person")
public class TestController {
@RequestMapping(value = "/")
public ModelAndView xyz() {
ModelAndView mav = new ModelAndView();
List<String> abc = new ArrayList<String>();
abc.add("old address1");
abc.add("old address2");
abc.add("old address3");
Person person = new Person(abc);
mav.addObject("person", person);
mav.setViewName("cForm");
return mav;
}
@RequestMapping("/save")
public @ResponseBody
String process(@ModelAttribute("person") Person person) {
return "<body>" + " Name:" + person.getName() + " Age: " + person.getAge() + " Addresses: " + person.getAddresses();
}
}
cForm.jsp:
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>populate form</title>
</head>
<body>
<form:form modelAttribute="person" action="/dashboard/test/save">
<form:hidden path="name" value="X" />
<form:hidden path="age" value="20" />
<form:hidden path="addresses[0]" value="New address" />
<input type="Submit" value="Submit" />
</form:form>
</body>
</html>
答案 0 :(得分:2)
我想解决一些设计问题。
您正在为表单绑定和域数据使用单个对象。这往往会产生与您在此遇到的问题完全相同的问题。问题不在于表单无法“清除”会话对象的地址;问题是会话对象将其数据结构泄露到表单,这会导致绑定问题。
表单了解Person
对象的内容。具体来说,表单要求person.getAddresses()
列表中有三个地址。与上面的(1)一样,问题是域结构泄漏到视图层中。
我建议您创建两个不同的“人”类:一个用于表示域数据(会话对象),另一个用于完全镜像表单结构(表单绑定对象)。您的表单将包含直接映射到PersonForm
类中的属性的字段,而在TestController
中,您可以从PersonForm
获取数据并相应地更新会话Person
。然后,表单输入不需要设计为处理Person.addresses
列表的不同状态。
这种方法确实需要更多的代码,但不是非常多,并且形式复杂性和表单/域解耦的节省非常值得。
答案 1 :(得分:0)
所以解决方案如下:
通过在客户端附加删除AJAX调用并将以下代码添加到控制器。
@RequestMapping("/remeveAddress")
public @ResponseBody String removeElement(@ModelAttribute("person") Person person, @RequestParam Integer addressId, Model model){
person.getAddresses().remove(addressId);
model.addAttribute("person", person);
return "{}";
}
答案 2 :(得分:0)
我遇到了同样的问题,并通过向控制器引入init绑定器来解决它。 init绑定器重置会话属性的地址列表。 根据要求,它可以做一些更复杂的工作。
@InitBinder
public void initBinder(HttpSession session) {
Person person = (Person)session.getAttribute("person");
person.getAddresses().clear();
}
希望可以帮助别人:)
答案 3 :(得分:0)
最近我遇到了同样的问题,而且我找到了一个非常简单的解决方案。 因此,您只需为列表添加隐藏字段即可。 Spring转换服务将从此隐藏字段的空字符串值中设置空列表:)
您可以看到以下解决方案:
<input type='hidden' name='addresses' value='' />
然后把你的其他代码:
<form:input path="addresses[0]" />
<form:input path="addresses[n]" />
注意: 如果您需要将字符串转换为 YourClass列表,并且您还没有拥有转换器或编辑器。 因此,请确保至少ObjectToObjectConverter可以执行此操作,YourClass必须具有 String arg的构造函数或静态方法 valueOf(String)。
答案 4 :(得分:-1)
另一种可能的解决方案是使用处理程序拦截器,如下所示。
servlet.xml中:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/test/**" />
<bean class="com.convert.dashboard.web.test.PersonInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
PersonInterceptor.java:
public class PersonInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
Person person = (Person)request.getSession().getAttribute("person");
if (person != null)
person.getAddresses().clear();
return super.preHandle(request, response, handler);
}
}