Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring MVC CRUD controller best pactice

Tags:

spring-mvc

I am trying to find a best practice approach for a Spring MVC simple CRUD controller. There are a lot of examples of CRUD controllers both on the web and on this forum, but most of them suffer from one of two problems:

  1. After saving/ or updating or deleting they show the message that save and update took place, but the URL they are hitting still has "/update/{id}" or "/delete/{id}" on it. This is "wrong", because the content shown usually is a list of objects.

or

  1. The controller redirects to the "showAll" view, but then the is no message that an action took place, which is not user friendly.

Does anyone have an example of crud controller that does not have these two problems?

Thank you,

Henry

@Controller
@RequestMapping(value="/role")
public class RoleController {
    private static final Logger log = Logger.getLogger(RoleController.class);

    @Autowired
    private RoleValidator validator = null;
    @Autowired
    private RoleService service = null;


    public void setService(RoleService  service) {
        this.service = service;
    }

    public void setValidator(RoleValidator validator) {
        this.validator = validator;
    }


    @RequestMapping(method=RequestMethod.GET)
    public String showForm(ModelMap model){
        List<Role> domainObjectList = service.getRoles();
        model.addAttribute("domainObjectList", domainObjectList);
        return "role";
    }

    @RequestMapping(value="/add", method=RequestMethod.GET)
    public String preAdd(ModelMap model){
        Role domainObject = new Role();
        model.addAttribute("domainObject", domainObject);
        addConstrainedFields(model);
        return "roleEdit";
    }

    @RequestMapping(value="/add", method=RequestMethod.POST)
    public ModelAndView add(@ModelAttribute(value="domainObject") Role domainObject, BindingResult result) {
        validator.validate(domainObject, result);
        ModelAndView mv = new ModelAndView("role");
        if(result.hasErrors()){
            mv = new ModelAndView("roleEdit");
            mv.addObject("domainObject", domainObject);
            return mv;
        }
        service.insertRole( domainObject );
        mv.addObject("domainObjectList", service.getRoles());
        mv.addObject("messageKey","label.form.item.added");
        //PROBLEM: the URL will remain "/add", but the content will be one of showing all roles + message that role was added. 
        return mv;
    }

    @RequestMapping(value="/update/{id}")
    public String preUpdate(@PathVariable Integer id, ModelMap model) {
        Role domainObject = service.getRole( id );
        model.addAttribute("domainObject", domainObject);
        return "roleEdit";
    }


    @RequestMapping(value="/update", method=RequestMethod.POST)
    public String update(@ModelAttribute(value="domainObject") Role domainObject, ModelMap model, BindingResult result){
        validator.validate(domainObject, result);
        ModelAndView mv = new ModelAndView("role");
        if(result.hasErrors()){        
            model.addAttribute("domainObject", domainObject);
            return "roleEdit";
        }
        service.insertRole(domainObject);
        model.addAttribute("messageKey","label.form.item.added");
        model.addAttribute("domainObjectList", service.getRoles());
        //PROBLEM: the message that the object was updated will be lost, but the URL will be /role and we will show all roles.
        return "redirect:/role";
    }

    @RequestMapping(value="/delete/{id}")
    public String delete(@PathVariable Integer id, ModelMap model) {
        Role domainObject = service.getRole( id );
        if (domainObject == null) {
            model.addAttribute("messageKey","label.form.item.notfound");
            return showForm(model);
        }
        service.deleteRole(domainObject);
        model.addAttribute("messageKey","label.form.item.deleted");
        return showForm(model);
    }

    @RequestMapping(value="/delete", method=RequestMethod.POST)
    public ModelAndView delete(@ModelAttribute(value="domainObject") Role domainObject, BindingResult result){
        validator.validate(domainObject, result);
        ModelAndView mv = new ModelAndView("role");
        if(!result.hasErrors()){
            service.deleteRole(domainObject);
            mv.addObject("messageKey","label.form.item.deleted");
            domainObject = new Role();
            mv.addObject("domainObject", domainObject);
        }
        mv.addObject("domainObjectList", service.getRoles());
        return mv;
    }

}
like image 516
Henry N. Avatar asked Jul 29 '13 15:07

Henry N.


1 Answers

  1. You should use RESTful URL design, and use gEt to rEad, posT to creaTe, pUt to Update, and Delete to Delete. Use the HiddenHttpMethodFilter for user agents that don't PUT or DELETE.

  2. Use the Post-Redirect-Get pattern to avoid re-POSTs.

  3. Use Flash Attributes to show Success/Failure messages on subsequent pages.

like image 170
Neil McGuigan Avatar answered Nov 19 '22 07:11

Neil McGuigan