简体   繁体   中英

Spring MVC 3 Controller annotation for onBind() - how to?

I am upgrading from Spring 2.5 to Spring 3.2. I have a MVC Controller that previously extended CancellableFormController . It declared,separately, initBinder() and onBind() methods. I have refactored the Controller to use @Controller annotation, and switched the overridden initBinder() method to use Spring MVC 3 annotation @initBinder .

My specific question is, in Spring MVC 3, upgrading from Spring 2.5, how to refactor the overridden onBind() method to use an annotation equivalent? The signature of the existing method is:

@Override
protected void onBind(HttpServletRequest request, Object command, BindException errors)  throws Exception {
    MyCommand cmd = (MyCommand) command;
    ....
}

I thought about using @initBinder() and put the code previously in onBind() inside this annotated method. But my confusion here is:

  1. Doing this, would the code be called at the same time in the overall framework process as before?
  2. How to get a handle on the Command object from @initBinder annotated method.

Can I just declare it as another parameter in the signature of the method and Spring MVC framework will ensure I get a copy? It seems that in the old onBind() method the Command object has already been created (by formBackingObject method). Can I safely assume that this is also the case when using @initBinder method?

Thank you anyone for some insights. I am trying to get up to speed with the Spring MVC process flow!

My existing @initBinder method signature is something like:

@InitBinder
protected void initBinder(WebDataBinder binder) {
    // register custom editor here.. etc
}

I am hoping I can do something like:

@InitBinder
protected void initBinder(WebDataBinder binder, MyCommand cmd) {
   // register custom editor here.. etc
}

Is this the standard best practice approach for upgrading cancellableformcontroller onBind() method using annotations?

Attempt based on answer marked correct, still not working:

@InitBinder("myCommand")
protected void onBind(WebDataBinder binder) throws Exception {
    MyCommand cmd = (MyCommand) binder.getTarget();
    .... // do whatever was required here...
}

Work around

Please see my comments below to zeroflag. Create a private method with same logic as contained in onBind(), and then after validation of command object in onSubmit() annotated method (POST / GET) make a callout to the now defunct onBind() method passing your Command object in as a parameter. Something like the following:

@RequestMapping(method=RequestMethod.POST) 
public ModelAndView onSubmit(@ModelAttribute("myCommand") MyCommand cmd, BindingResult result, <any other params> {

        new MyCommandValidator().validate(cmd, result);
        if (result.hasErrors()) {
            return new ModelAndView("context");
        }
        onBind(cmd, <any other params>);

        ... // do business stuff

}

It appears to be an ugly workaround that was ok for my particular case.

You can access the command object with binder.getTarget() . @InitBinder is called for every model parameter of the controller method. Let's assume the following code

@RequestMapping("/somePath")
public String myMethod(@ModelAttribute("user") User user,
                       @ModelAttribute("info") Info info) {

Then your initBinder method is called at least twice: For the User object and for the Info object. To have it called only for a specific object add the model name:

@InitBinder("user")

That way it will only be called for the User object. Be aware, though, that the method might still be called more than once, the first time even with the target object being null.

If you want to ensure that some fields are not set automatically, then you can use setDisallowedFields() in your initBinder method.

If you want to do some validation then let JSR 303 (Bean Validation) do that job.

Depending on what you want to do an @ModelAttribute method in your controller could be a solution:

@ModelAttribute("user")
public User createUser(HttpServletRequest request /*or whatever*/) {
  User user = new User();
  //check some parameters and set some attributes
  return user;
}

Creates a user object before binding happens.

One last solution can be a message or type converter for your command object, that creates an object from the request. That's actually similar to the example above, but independent of the controller and there is no binding for an object created with a converter.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM