В настоящее время у меня есть следующее сопоставление в моем контроллере:
@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 )
Но как тогда должен выглядеть код?Я просто попробовал это и получил некоторые исключения, потому что уже был экземпляр Person # в сеансе ...
EDIT Здесь я дал ему попытку ...
Метод контроллера:
@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>
Добавление работает, но редактирование дает следующее исключение:
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 );
}
Это лучшее решение?