Java – can spring MVC with JPA be used to update a subset of attributes on an entity?

I am using spring Roo, spring MVC and JPA to save MySQL database I'm new to spring MVC and Java, but I work with cake, PHP and rails

In addition to my password, I have a user entity that contains personal data Things like this (not including many roo generated functions in additional. AJ files):

public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "ID")
    private Long id;

    @Column(name = "PASSWORD",length = 32)
    private String password;

    @Column(name = "FIRST_NAME",length = 25)
    private String firstName;

    @Column(name = "LAST_NAME",length = 25)
    private String lastName;

    @Column(name = "ADDRESS",length = 255)
    private String address;

    // The appropriate getters and setters
    ...
}

Then there is an editing operation in my user controller. I created the following conventions for the scaffold automatically generated by roo:

@RequestMapping(value="/edit",method = RequestMethod.GET)
public String editForm(Model uiModel) {
    String username = (String) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    uiModel.addAttribute("user",User.findUserByUsername(username).getSingleResult());
    return "account/edit";
}

There is also a jspx view rendering form, which follows roo's convention again:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<div xmlns:field="urn:jsptagdir:/WEB-INF/tags/form/fields" xmlns:form="urn:jsptagdir:/WEB-INF/tags/form" xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0">
    <jsp:directive.page contentType="text/html;charset=UTF-8"/>
    <jsp:output omit-xml-declaration="yes"/>
    <form:update id="" label="Personal Details" modelattribute="user" path="/account" versionField="none">
        <field:input id="" field="firstName" label="First Name" />
        <field:input id="" field="lastName" label="Last Name" />
        <field:textarea id="" field="address" label="Street Address" />
    </form:update>
</div>

I don't want the form to update the password, just provide the fields (first name, last name and address)

Update the action and follow the roo convention again:

@RequestMapping(method = RequestMethod.PUT,produces = "text/html")
public String edit(@Valid User user,BindingResult bindingResult,Model uiModel,HttpServletRequest httpServletRequest) {
    if (bindingResult.hasErrors()) {
        uiModel.addAttribute("user",user);
        return "account/edit";
    }
    uiModel.asMap().clear();
    user.merge();
    return "redirect:/account";
}

The user object is a perfect update, but the problem is that its override password field is empty because it is not provided as input in the form, so it is set to null in the user object passed to the form submit request handler This problem does not occur on roo generated scaffolds because they provide form input for all columns So I can add it as a hidden field, but that doesn't sound like a good idea And I think there's a better way to do

TL; How does Dr update only the entity properties provided in the form without overwriting other properties?

In other words, how do I make spring / JPA generate SQL

UPDATE user SET firstname=?,lastname=?,address=?

replace

UPDATE user SET firstname=?,address=?,password=?

The code example will be great because I'm the new feature of all this:)

thank you!

Update: I can use yglodt's suggestions to make it work and add the following methods to my user model:

@Transactional
public void mergeWithExistingAndUpdate() {
    final User existingUser = User.findUser(this.getId());

    existingUser.setFirstName(this.getFirstName());
    existingUser.setLastName(this.getLastName());
    existingUser.setAddress(this.getAddress());

    existingUser.flush();
}

And act from my controller instead of user Merge() to call it:

user.mergeWithExistingAndUpdate();

Solution

I usually solve this problem at the service level

You can read the entity to be updated from the DB and overwrite the properties obtained from the form

In this way, you only need to change the required properties

Code example:

@Service
@Transactional
public class UserService {

    @Resource(name = "sessionFactory")
    private SessionFactory  sessionFactory;

    public void mergeWithExistingAndUpdate(final Person personFromPost) {

        Session session = sessionFactory.getCurrentSession();

        Person existingPerson = (Person) session.get(Person.class,personFromPost.getId());

        // set here explicitly what must/can be overwritten by the html form POST
        existingPerson.setName(personFromPost.getName());
        existingPerson.setEmail(personFromPost.getEmail());
        existingPerson.setDateModified(new Date());
        existingPerson.setUserModified(Utils.getCurrentUser());

        session.update(existingPerson);
    }

}

Edit 1

In fact, there is a spring way to solve this problem. Use @ sessionattributes to see this:

https://stackoverflow.com/a/3675919/272180

I haven't tested it yet, but it looks promising

Edit 2

Finally I tested it and how it works

There's one thing you can shoot at your feet:

If you open several tabs with the same format, the opening of the last tab overrides the session properties of the other tabs and may corrupt the data when submitting This blog post has a solution: http://marty-java-dev.blogspot.com/2010/09/spring-3-session-level-model-attributes.html

But finally, if you don't open multiple tabs for editing, you won't have any problems

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>