2012-02-08 47 views
0

目前,我有我的控制器下面的映射:只有一個上發佈添加/編輯方法

@RequestMapping(value = "/add.html", method = RequestMethod.GET) 
    public String showAddForm(Map<String, Object> map) 
    { 
    map.put("person", new Person()); 
    return "form"; 
    } 

    @RequestMapping(value = "/add.html", method = RequestMethod.POST) 
    public String processAddForm(@ModelAttribute("person") @Valid Person person, BindingResult result, Map<String, Object> map) 
    { 
    if (service.findByName(person.getName()) != null) 
    { 
     result.addError(new FieldError("person", "name", "Person already exists")); 
    } 

    if (result.hasErrors()) 
    { 
     return "form"; 
    } 

    service.save(person); 
    return "redirect:/index.html"; 
    } 

    @RequestMapping(value = "/{id}/edit.html", method = RequestMethod.GET) 
    public String showEditForm(@PathVariable("id") int id, Map<String, Object> map) 
    { 
    map.put("person", service.load(id)); 
    return "form"; 
    } 

    @RequestMapping(value = "/{id}/edit.html", method = RequestMethod.POST) 
    public String processEditForm(@PathVariable("id") int id, @ModelAttribute("person") @Valid Person person, BindingResult result) 
    { 
    Person p; 
    if ((p = service.findByName(person.getName())) != null && person.getId() != id) 
    { 
     result.addError(new FieldError("person", "name", "Person already exists")); 
    } 

    if (result.hasErrors()) 
    { 
     return "form"; 
    } 

    person.setId(id); 
    service.save(person); 
    return "redirect:/index.html"; 
    } 

這怎麼可能,以減少冗餘代碼? 也許通過設置形式的行動,以/save.html並結合processAddForm和processEditForm到

@RequestMapping(value = "/save.html", method = RequestMethod.POST) 

但代碼應該看起來怎麼樣呢? 我只是嘗試,並得到一些例外,因爲已經有人物#在會話實例...

編輯 在這裏,我給它一個嘗試...

控制器的方法:

@RequestMapping(value = "/save.html", method = RequestMethod.POST) 
    public String onSubmit(@ModelAttribute("person") @Valid Person person, BindingResult result, Map<String, Object> map) 
    { 
    Person p; 
    if ((p = service.findByName(person.getName())) != null) 
    { 
     if (person.getId() != p.getId()) 
     { 
     result.addError(new FieldError("person", "name", "Person already exists")); 
     } 
    } 

    if (result.hasErrors()) 
    { 
     return "form"; 
    } 

    service.save(person); 
    return "redirect:/index.html"; 
    } 

形式:

<c:url value="/save.html" var="formAction" /> 
<form:form modelAttribute="person" action="${formAction}" method="post"> 
    <form:errors path="*" cssClass="error" element="div" /> 
    <form:hidden path="id" /> 
    <form:label path="name">Name:</form:label> 
    <form:input path="name" /> 
    <input type="submit" value="Submit" /> 
</form:form> 

添加的作品,但編輯給出以下Excep重刑:

org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [com.example.entities.Person#7] 
    org.hibernate.engine.StatefulPersistenceContext.checkUniqueness(StatefulPersistenceContext.java:637) 
    org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.java:305) 
    org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsDetached(DefaultSaveOrUpdateEventListener.java:246) 
    org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:112) 
    org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93) 
    org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:677) 
    org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:669) 
    org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:665) 
    com.example.dao.PersonDaoImpl.save(PersonDaoImpl.java:30) 
    com.example.dao.PersonDaoImpl.save(PersonDaoImpl.java:1) 
    com.example.services.PersonServiceImpl.save(PersonServiceImpl.java:29) 
    com.example.services.PersonServiceImpl.save(PersonServiceImpl.java:1) 
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    java.lang.reflect.Method.invoke(Method.java:616) 
    org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:318) 
    org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183) 
    org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150) 
    org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110) 
    org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 
    org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202) 
    $Proxy44.save(Unknown Source) 
    com.example.controller.PersonController.onSubmit(PersonController.java:65) 
    com.example.controller.PersonController$$FastClassByCGLIB$$9c2dc698.invoke(<generated>) 
    net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) 
    org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:689) 
    org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150) 
    org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:61) 
    org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 
    org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:622) 
    com.example.controller.PersonController$$EnhancerByCGLIB$$a0aff0d2.onSubmit(<generated>) 
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    java.lang.reflect.Method.invoke(Method.java:616) 
    org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:212) 
    org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:126) 
    org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:96) 
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:617) 
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:578) 
    org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80) 
    org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:900) 
    org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:827) 
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882) 
    org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:789) 
    javax.servlet.http.HttpServlet.service(HttpServlet.java:637) 
    javax.servlet.http.HttpServlet.service(HttpServlet.java:717) 
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:311) 
    org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:116) 
    org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83) 
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323) 
    org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113) 
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323) 
    org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:101) 
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323) 
    org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113) 
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323) 
    org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:54) 
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323) 
    org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45) 
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323) 
    org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter(BasicAuthenticationFilter.java:201) 
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323) 
    org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87) 
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323) 
    org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:173) 
    org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346) 
    org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259) 
    org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:198) 
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76) 

EDIT2: PersonServiceImpl:

@Override 
    @Transactional 
    public void save(Person person) 
    { 
    dao.save(person); 
    } 

PersonDaoImpl:

@Override 
    public void save(Person person) 
    { 
    try 
    { 
     sessionFactory.getCurrentSession().saveOrUpdate(person); 
    } 
    catch(NonUniqueObjectException e) 
    { 
     sessionFactory.getCurrentSession().merge(person); 
    } 
    } 

這是正確的方法是什麼?也許更好的解決方案?

EDIT3

@Override 
    public void save(Person person) 
    { 
    if (load(person.getId()) != null) 
    { 
     sessionFactory.getCurrentSession().merge(person); 
    } 
    else 
    { 
     sessionFactory.getCurrentSession().save(person); 
    } 
    } 

    @Override 
    public Person load(int id) 
    { 
    return (Person) sessionFactory.getCurrentSession().load(Person.class, id); 
    } 

這是一個更好的解決辦法?

+0

因此,這實際上是一個Hibernate異常,並且與Spring MVC無關。閱讀堆棧跟蹤的其餘部分(我無法讀取它,你沒有按照問題發佈),併發布代碼,如果你不明白它的話。 – 2012-02-08 15:48:23

回答

2

它看起來像你試圖保存一個對象具有相同的ID,該對象沒有連接到休眠會話。

您可能編輯了Person的名字並試圖保存它。沒有找到具有該名稱的人,但具有相同ID的人存在於數據庫中,因此出錯。

要麼使用merge()要麼在您的服務中首先獲取人員(使其連接到休眠的會話),更新必要的字段並將其保存到數據庫。

更好地說明:

@RequestMapping(value = "/save.html", method = RequestMethod.POST) 
    public String onSubmit(@ModelAttribute("person") @Valid Person person, BindingResult result, Map<String, Object> map) 
    { 
    Person p; 
    // You changed the name so it doesn't find anything here and proceeds without errors 
    if ((p = service.findByName(person.getName())) != null) 
    { 
     if (person.getId() != p.getId()) 
     { 
     result.addError(new FieldError("person", "name", "Person already exists")); 
     } 
    } 

    if (result.hasErrors()) 
    { 
     return "form"; 
    } 

//the code breaks here, person is not attached to hibernate session and you're trying to save it. Modify your service code to use merge() or to fetch the person from database before saving it. 
    service.save(person); 
    return "redirect:/index.html"; 
    } 

編輯

如果使用merge()那麼你沒有測試任何東西。 Hibernate足夠聰明,可以知道是否保存新實例或將更改保存到已保存的實例。另一種方法是在您的控制器中測試是否設置了person.id,並在您的服務中調用適當的方法(service.saveservice.update)。這實際上取決於你想依賴於hibernate的聰明程度。

+0

所以我只需要調用'merge'而不是save/saveOrUpdate? – dtrunk 2012-02-08 16:50:36

+1

@dtrunk是的,只是'merge' – soulcheck 2012-02-08 16:53:49

1

爲此,在Spring 3.0中有效使用URI模板。

@RequestMapping(value = "/save.html{mode}", method = RequestMethod.POST) 
public EditAndSave(@PAthVariable String mode,...){ 
if(mode.equals("Edit")){ 
    //write code for edit here 
} 

if(mode.equals("Add")){ 
    //write code for add here 
} 

}