views:

56

answers:

1

Hello,

I want to implement something like this:

@Controller
@SessionAttributes("promotion")
class PromotionController {
    @RequestMapping("showPromo")
    void showPromotionInfo(
        @RequestParam("promId") String promotionId,
        @ModelAttribute Promotion promotion, Errors errors
    ) {
        promotion = Promotions.get(promotionId);
        if (promotion == null || promotion.validates() == false) {
            errors.reject("promotion.invalid");
        }
        return "prom";
    }    
}

The code is invalid, wont work and has some bad errors, but I don't know how to write it better.

When user comes to an URL "showPromo?promId=15", controller should validate if the promotion is valid (outdated/non-existent/etc.). If it is valid - it should show it's information and save the promotion to model and session. If it's not - it should show some error about promotion being invalid.

Problem is, I need to save the promotion in the session (for several requests) and don't want to use direct session management. Is it currently possible with Spring? Or am I doing something wrong?

Could you please provide the optimal solution to my problem using Spring 3?

Thanks in advance.

Added:

Ok, I think I'll write down the problematic points:

  1. When there is no object in session, it can't be bound with @ModelAttribute throwing an error like "no object found in session". And there is no "optional" parameter anywhere.
  2. I can't have @ModelAttribute in the parameters, as I'm overwriting that promotion object. Proper way should be model.addAttribute("promotion", promotion). But I also need to have a way to provide errors, and I see no way to provide them using model.addAttribute.
+1  A: 

In addition to skaffman's answer: you can associate BindingResults with manually added model attributes using BindingResult.MODEL_KEY_PREFIX.

Promotion promotion = .... 
modelMap.addAttribute("promotion", promotion); 
if (!promotion.validate()) {
    BindingResult errors = new BeanPropertyBindingResult(promotion, "promotion");
    errors.reject("promotion.invalid");
    model.put(BindingResult.MODEL_KEY_PREFIX + "promotion", errors);
}

Note, however, that you can't associate BindingResult with null object, therefore you can't use errors.reject when promotion was not found (if you don't add some kind of empty promotion into model in that case).

axtavt
Thanks a lot. This was exactly what I wanted to know. However, this code looks pretty depressing (I mean the string-based attribute name)... Could there be some better (prettier) way to do it?
Max