Is it possible to run #Validated after the #RequestMapping method has started? The reason is that I need to modify the #ModelAttribute before actually validating it.
Ideally something like this.
#RequestMapping(value = "/doSomething",
method = RequestMethod.POST)
public final String DoSomething(
#ModelAttribute(value = "myobject") final MyObject myobject) {
//.... do some processing on myobject
//.... now validate
BindingResult bindingResult = validate(myobject);
//...
And a method like this
private final BindingResult validate(
#Validated(value = {Group1.class, Group2.class}) MyObject myobject) {
return bindingResult //somehow return a BindingResult
}
Use your own custom Validator
http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/validation.html#validation-binder
Related
#RequestMapping(value = "/testmap", method = RequestMethod.GET)
public ModelAndView testmap(ModelAndView model) {
ModelMap map=new ModelMap();
String greetings = "Greetings, Spring MVC! testinggg";
model.setViewName("welcome");
map.addAttribute("message", greetings);
return model;
}
I had
${message}
on welcome.jsp. But it does not prints the greetings.
Can you tell me the reason?
Model is an Interface. It defines a holder for model attributes and is primarily designed for adding attributes to the model. It contains four addAttribute (Overloaded) and one mergeAttributes and one containsAttribute method.
Example:
#GetMapping("/showViewPage")
public String passParametersWithModel(Model model) {
Map<String, String> map = new HashMap<>();
map.put("spring", "mvc");
model.addAttribute("message", "Baeldung");
model.mergeAttributes(map);
return "viewPage";
}
ModelAndView is a class which allows us to pass all the information required by Spring MVC (Model and View) in one return.
Example :
#GetMapping("/goToViewPage")
public ModelAndView passParametersWithModelAndView() {
ModelAndView modelAndView = new ModelAndView("viewPage");
modelAndView.addObject("message", "Baeldung");
return modelAndView;
}
Hope you get some clarity from this.
Is it possible to call the Controller if the executed URL contains the word mentioned in the #RequestMapping of the respective Controller?
Here is my code
#Controller
#RequestMapping({"/employee","/nonemployee","/temp"})
public class EmployeeController {
#Autowired
EmployeeService service;
#RequestMapping("/add")
public ModelAndView employee() {
ModelAndView modelAndView = new ModelAndView("emp/add", "command", new Employee());
return modelAndView;
}
#RequestMapping("/employees")
public ModelAndView getEmployeeList() {
ModelAndView modelAndView = new ModelAndView("/emp/employees", "list", service.getEmployeeList());
return modelAndView;
}
#RequestMapping(value = "/create")
public String createEmployee(#ModelAttribute Employee employee, ModelMap model) {
service.newEmployee(employee);
model.addAttribute("name", employee.getName());
model.addAttribute("age", employee.getAge());
model.addAttribute("id", employee.getId());
return "/emp/create";
}
}
Using the above code with #RequestMapping({"/employee","/nonemployee","/temp"}) and #RequestMapping("/employees"), we can call the following urls, to list values:
http://localhost:8080/Spring/employee/employees
http://localhost:8080/Spring/nonemployee/employees
http://localhost:8080/Spring/temp/employees
On observing closely, we can see the matching word emp within all the three words/values passed to the RequestMapping. So, what I am looking for is the way using which the execution of Controller is occurred, if the URL contains the word emp.
On execution of the following URLs, list of values must be returned by the same method (getEmployeeList()), but without passing multiple or all the values to RequestMapping Annotation:
http://localhost:8080/Spring/employee/employees
http://localhost:8080/Spring/nonemployee/employees
http://localhost:8080/Spring/temp/employees
http://localhost:8080/Spring/exempt/employees
http://localhost:8080/Spring/attempt/employees
Change you Request Mapping to -
#RequestMapping("/*emp*")
This should work for what you want to do.
I have startController and start view. In this view I input number and amount and validate it. If validation was successful, I want pass this parameters(number and amount) to another controller, and after that make some operations with it, in this controller. I see two way:
make this operations in first controller, in another methods and use second view for it. But my controller will very big and all logic will be this.
create second controller and second view and pass parameters to this controller.
I make this:
#Controller
#RequestMapping("/")
public class StartController {
#Autowired
private ValidateService validateService;
#RequestMapping(method = RequestMethod.GET)
public ModelAndView printWelcome() {
ModelAndView modelAndView = new ModelAndView("start");
return modelAndView;
}
#RequestMapping(value = "process", method = RequestMethod.POST)
public ModelAndView process(HttpServletRequest request) {
ModelAndView modelAndView;
String phoneNumber = request.getParameter("phone_number");
int amount = Integer.parseInt(request.getParameter("amount"));
String result = validateService.validate(phoneNumber, amount);
if (!result.equals("OK")) {
modelAndView = new ModelAndView("start");
modelAndView.addObject("result",result);
}else {
modelAndView = new ModelAndView("redirect:/check/process");
modelAndView.addObject("phone_number", phoneNumber);
modelAndView.addObject("amount",amount);
}
return modelAndView;
}
and if result != OK I redirect to new controller
#Controller
#RequestMapping("/check")
public class CheckController {
#RequestMapping(value = "process", method = RequestMethod.GET)
public ModelAndView process(HttpServletRequest request) {
ModelAndView modelAndView = new ModelAndView("check");
String phoneNumber = request.getParameter("phone_number");
int amount = Integer.parseInt(request.getParameter("amount"));
return modelAndView;
}
}
But I need pass parameters with RequestMethod.POST and it will not work. How do it?
You can return a ModelAndView with parameters as follow:
return new ModelAndView("redirect:/check/process?phone_number="+yourPhoneNumber+"&amount="+amount)
You can use forward to go to a new controller right?
"forward:/test2?param1=foo¶m2=bar";
Please see below link for more details.
Spring forward with added parameters?
My usecase: a single html-form can triggered as a save or an update event. Depending on the event the validation is is performed by a different validator. This works so far with the following code. The only problem I have, that I want the field-errors to be mapped in all cases to "saveDto", so I can map them in my form.
Any hints welcome.
#Inject
private SaveValidator saveValidator;
#Inject
private UpdateValidator updateValidator;
#RequestMapping(value = EVENT_SAVE, method = RequestMethod.POST)
protected String doSave(#Valid #ModelAttribute("saveDto") final SaveDto saveDto,
final BindingResult bindingResult, final Model model, final HttpServletRequest request)
{
if (bindingResult.hasErrors())
{
// ...
}
}
#RequestMapping(value = EVENT_UPDATE, method = RequestMethod.POST)
protected String doUpdate(#Valid #ModelAttribute("updateDto") final SaveDto saveDto,
final BindingResult bindingResult, final Model model, final HttpServletRequest request)
{
if (bindingResult.hasErrors())
{
// ...
}
}
#InitBinder("saveDto")
protected void initSaveValidator(final WebDataBinder binder)
{
binder.addValidators(saveValidator);
}
#InitBinder("updateDto")
protected void initUpdateValidator(final WebDataBinder binder)
{
binder.addValidators(updateValidator);
}
Try the hibernate validation group feature along with #Validated annotation
I have the following function in my abstract controller
public abstract class GenericController<T extends PersistentObject> {
...
...
...
#RequestMapping(value = "/validation.json", method = RequestMethod.POST)
#ResponseBody
public ValidationResponse ajaxValidation(#Valid T t, BindingResult result) {
ValidationResponse res = new ValidationResponse();
if (!result.hasErrors()) {
res.setStatus("SUCCESS");
} else {
res.setStatus("FAIL");
List<FieldError> allErrors = result.getFieldErrors();
List<ErrorMessage> errorMesages = new ArrayList<ErrorMessage>();
for (FieldError objectError : allErrors) {
errorMesages.add(new ErrorMessage(objectError.getField(),
objectError.getDefaultMessage()));
}
res.setErrorMessageList(errorMesages);
}
return res;
}
At most cases the validation is sufficient for different kind of entities. Now I would like to customize the validation on my concrete controller as
#Controller
#RequestMapping("user")
public class UserController extends GenericController<User> {
#RequestMapping(value = "/validation.json", method = RequestMethod.POST)
#ResponseBody
public ValidationResponse ajaxValidation(#Valid User user,
BindingResult result, Locale locale) {
ValidationResponse res = super.ajaxValidation(user, result);
if (!user.getPassword().equals(user.getConfirmPassword())) {
res.setStatus("FAIL");
res.getErrorMessageList().add(
new ErrorMessage("confirmPassword", messageSource
.getMessage("password.mismatch", null, locale)));
}
return res;
}
}
With this I get the following error java.lang.IllegalStateException: Ambiguous mapping found. Cannot map 'userController' bean method. How can I solve this issue ? Is there a better approach ?
The problem here is that after extending your generic controller you have two different methods
public ValidationResponse ajaxValidation(#Valid T t, BindingResult result)
and
public ValidationResponse ajaxValidation(#Valid User user,
BindingResult result, Locale locale)
with the exact same mapping
user/validation.json
An ugly solution would be to add the Locale locale param to your abstract controller method (even if you don't use it) and add the #Overwrite annotation to the UserController method (you'll get a compilation error otherwise). This way the two methods become one.
The generic controller is extended by other classes ? Then you will have two identical requestmappings.
Are you sure the UserController is correctly getting user prepend request mapping applied ? As this works :
#RequestMapping("test")
public class ExampleController extends AbstractController {
#RequestMapping(value = "/Home", method = RequestMethod.GET)
public String getHome(Model model) {
return "home";
}
with the same mapping in AbstractController
#RequestMapping(value = "/Home", method = RequestMethod.GET)
public String getHome(Model model) {
return "home";
}