2

This is a question about a Spring Boot MVC application with Hibernate and PostgreSQL.

I have a web page that allows a user to set administrative / configuration data for an application, and I want to store this data in a single database record. I have a POJO to contain the data. I have coded up a Spring MVC app that persists this data.

The trouble is that each time the user saves the data (by doing a POST from the web page) the Spring application creates a new record in the database.

I'm using a Repository, and I was under the impression that each time I did a Repository.save() on the object it would update the existing record if there is one, otherwise create a new one and that it would identify the record based upon the primary key. I could not find an "update" method.

I have tried several ways around this issue but they either still make extra records, fail with a duplicate key error or just plain don't work.

Also, it seems that each time I start the web page or the application all the data in the database is removed.

So what's the trick? Thanks very much...

Here is my code:

AdminFormController.java

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.beans.factory.annotation.Autowired;


@Controller
public class Admin_FormController 
{

    @Autowired
    private AdminDataRepository rep;

    @RequestMapping(value="/admin", method=RequestMethod.GET)
    public String adminForm(Model model) 
    {
        AdminData ad = new AdminData();
        model.addAttribute("adminForm", ad);

        ad = rep.findById(1L);

        if(ad != null)
            ad.setId(1L);

        return "adminForm";
    }

    @RequestMapping(value="/admin", method=RequestMethod.POST)
    public String adminSubmit(@ModelAttribute AdminData ad, Model model) 
    {

        // ad.setId(1L);;

        rep.save(ad);

        model.addAttribute("adminForm", ad);

        return "adminForm";
    }
}

AdminDataRepository.java

import org.springframework.data.repository.CrudRepository;

public interface AdminDataRepository extends CrudRepository<AdminData, String> 
{
    AdminData findById(Long Id);
}

AdminData.java

import java.util.logging.Logger;
import javax.persistence.*;

@Entity
public class AdminData 
{
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)   
    private Long id;

    private String useDates;

    private String startDate;
    private String endDate;

    public String getUseDates()
    {
        return useDates;
    }


    public String getStartDate() 
    {
        return startDate;
    }

    public String getEndDate() 
    {
        return endDate;
    }

    public void setUseDates(String s)
    {
        Logger.getGlobal().info(() -> "UseDates: " + s);
        useDates = s;
    }

    public void setStartDate(String s) 
    {
        Logger.getGlobal().info(() -> "Start Date: " + s);
        startDate = s;
    }

    public void setEndDate(String s) 
    {
        Logger.getGlobal().info(() -> "End Date: " + s);
        endDate = s;
    }

}
Jim Archer
  • 1,337
  • 5
  • 30
  • 43

1 Answers1

1

You need to store the object somewhere between requests. Your options:

  1. Using hidden form fields
  2. Re-read it from the database (in your POST method)
  3. Use session

1 is inconvenient, and not secure. 2 Doesn't support concurrency control. 3 is secure and correct.

To implement #3, add @SessionAttributes("yourAttributeName") just before your controller. Add a SessionStatus parameter to your POST method, and call sessionStatus.setComplete() when you're done with it.

Example here.

Community
  • 1
  • 1
Neil McGuigan
  • 46,580
  • 12
  • 123
  • 152
  • Wow, that was really easy, thank you! My intention is to leave the user on this page after they click "SAVE" so they can keep working on changes. There is really no upper level menu or page they got here from. So there is no opportunity to call the sessionStatus.setComplete() method. Will this cause a problem? – Jim Archer Jul 15 '15 at 21:27
  • @JimArcher you'll end up using a little more server memory if you don't call setComplete, at least until the user's session is over. You might have to run a periodic process to clean up sessionAttributes, or live with a little extra memory usage – Neil McGuigan Jul 16 '15 at 20:39