Spring mvc 没有冗余代码的Spring MVC更新?

Spring mvc 没有冗余代码的Spring MVC更新?,spring-mvc,crud,spring-form,Spring Mvc,Crud,Spring Form,我正在使用SpringMVC控制器和视图来实现名为Partner的简单对象的CRUD操作。更新操作让我很烦恼。似乎我需要手动编写几行代码,我希望SpringMVC能够自动处理这些代码。这里有没有我错过的最佳实践 以下是我的看法: <%@ include file="include.jsp"%> <form:form commandName="partner"> <input type="hidden" name="_method" value="PUT"

我正在使用SpringMVC控制器和视图来实现名为Partner的简单对象的CRUD操作。更新操作让我很烦恼。似乎我需要手动编写几行代码,我希望SpringMVC能够自动处理这些代码。这里有没有我错过的最佳实践

以下是我的看法:

<%@ include file="include.jsp"%>

<form:form commandName="partner">
    <input type="hidden" name="_method" value="PUT" />
    <table>
        <tr>
            <td>Id:</td>
            <td><form:input path="id" disabled="true" /></td>
        </tr>
        <tr>
            <td>Name:</td>
            <td><form:input path="name" /></td>
        </tr>
        <tr>
            <td>Logo:</td>
            <td><form:input path="logo" /></td>
        </tr>
        <tr>
            <td>On-screen text:</td>
            <td><form:textarea path="onScreenText" /></td>
        </tr>
        <tr>
            <td colspan="2"><input type="submit" value="Save Changes" /></td>
        </tr>
    </table>
    </form:form>
困扰我的代码行有:

Partner partnerToUpdate = entityManager.find(Partner.class, partnerId);
partnerToUpdate.setId(partnerId);
partnerToUpdate.setName(partner.getName());
partnerToUpdate.setLogo(partner.getLogo());
partnerToUpdate.setOnScreenText(partner.getOnScreenText());
我真的需要在数据库中查找现有的合作伙伴并显式更新该对象的每个字段吗?我已经有了一个具有所有正确值的Partner对象。是否无法将该对象直接存储到数据库


我已经看过了,但这并没有完全回答我的问题。

作为一个可能的建议,您可以在模型创建过程中查找现有的
合作伙伴
对象,以便此模型实例支持表单,Spring将字段直接绑定到表单。实现这一点的一种方法是在负责创建模型的控制器中创建一个显式方法

例如:

@ModelAttribute("partner")
public Partner createModel(@PathVariable int partnerId) {
    Partner partner = entityManager.find(Partner.class, partnerId);
    return partner;
}
然后可以从
updatePartner
方法中删除复制,因为Spring已经将表单字段直接绑定到加载的
Partner
对象

@RequestMapping(value="/partner/{partnerId}", method=RequestMethod.PUT)
public ModelAndView updatePartner(@ModelAttribute("partner") Partner partner) {
    EntityManager entityManager = DatabaseHelper.getEntityManager();
    try {
        entityManager.getTransaction().begin();
        entityManager.persist(partner);
        entityManager.getTransaction().commit();
    }
    finally {
        entityManager.close();
    }
    return new ModelAndView("redirect:/partner");
}
一个警告-因为
createModel
方法将被调用用于控制器的每个请求(不仅仅是
updatePartnerner
),所以
partnerId
路径变量将需要出现在所有请求中

有一篇文章讨论了该问题的解决方案。

您可以使用它来更新所需的值,例如:

    @RequestMapping(value="/partner/{partnerId}", method=RequestMethod.PUT)
    public ModelAndView updatePartner(@ModelAttribute Partner partner, @PathVariable int partnerId) {
        EntityManager entityManager = DatabaseHelper.getEntityManager();
        try {
            entityManager.getTransaction().begin();
            partner.setId(partnerId);
            entityManager.merge(partner);
            entityManager.getTransaction().commit();
        }
        finally {
            entityManager.close();
        }
        return new ModelAndView("redirect:/partner");
    }

另外,我建议您将和Spring事务支持与
@Transactional
@Repository

一起使用,您可以尝试使用
partner.setId(partnerToUpdate.getId());entityManager.merge(合作伙伴)
但只有当
合作伙伴
是一个完整的实体时,它才起作用。@AVolpe,您使用合并的建议起作用了。然后我将添加一个答案。您确实应该有一个服务/存储库来隐藏
EntityManager
的使用。控制器不是启动/停止事务的地方。您可能希望使用springs声明性tx管理,这样您就不必自己处理这些问题。@M.Deinum-同意。我从OP中提取代码来说明我的答案。将持久性细节与控制器分离并隐藏EntityManager肯定是明智的。谢谢。我能够遵循AVolpe的建议,并且不需要创建一个用ModelAttribute注释的单独方法。我将按照M.Deinum和@Will Keeling的建议创建一个单独的服务/存储库。
    @RequestMapping(value="/partner/{partnerId}", method=RequestMethod.PUT)
    public ModelAndView updatePartner(@ModelAttribute Partner partner, @PathVariable int partnerId) {
        EntityManager entityManager = DatabaseHelper.getEntityManager();
        try {
            entityManager.getTransaction().begin();
            partner.setId(partnerId);
            entityManager.merge(partner);
            entityManager.getTransaction().commit();
        }
        finally {
            entityManager.close();
        }
        return new ModelAndView("redirect:/partner");
    }