spring RequestMapping not working without ModelAttribute - spring

I have controller class with following request mapping method.
appStart() method is responsible for redirecting user to login.html and
logout() is responsible for invalidating session and redirecting user
back to login.jsp
if I remove #ModelAttribute from their parameter then these two methods are throwing exception, is there any hack to get these methods working without modelattribute?
controller methods.
#RequestMapping(value="/",method=RequestMethod.GET)
public String appStart(#ModelAttribute("tempAdmin") Admin tempAdmin) {
return "login.jsp";
}
#RequestMapping(method = RequestMethod.POST,name="doLogin")
public ModelAndView doLogin(#ModelAttribute("tempAdmin") Admin tempAdmin, HttpServletRequest request) {
ModelAndView mvc = new ModelAndView();
/*
Buisness logic
*/
mvc.setViewName("home.jsp");
return mvc;
}
#RequestMapping("doLogout")
public String logout(HttpServletRequest request) {
HttpSession session = request.getSession(false);
if(session != null){
session.invalidate();
}
return "login.jsp";
}
login.jsp
<form:form action="doLogin" modelAttribute="tempAdmin" cssClass="form-horizontal">
<div class="form-group">
<label for="username" class="col-sm-2 control-label">Username</label>
<div class="col-sm-10">
<form:input cssClass="form-control" path="adminId" placeholder="username" />
</div>
</div>
<div class="form-group">
<label for="passwd" class="col-sm-2 control-label">Password</label>
<div class="col-sm-10">
<form:password path="password" cssClass="form-control" id="passwd" placeholder="password" />
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default">Sign in</button>
</div>
</div>
</form:form>
stacktrace.
Caused by: java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'tempAdmin' available as request attribute
at org.springframework.web.servlet.support.BindStatus.<init>(BindStatus.java:144)
at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getBindStatus(AbstractDataBoundFormElementTag.java:168)
at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getPropertyPath(AbstractDataBoundFormElementTag.java:188)

I will tell you how to change your controller, to avoid binding result problem. Try this :
#RequestMapping(method = RequestMethod.POST,name="doLogin")
public String doLogin(#ModelAttribute("tempAdmin") Admin tempAdmin, HttpServletRequest request,Model model) {
model.addAttribute("tempadmin",new Admin());
// business logic
return "home";
}
Try this out, and if you have any other classes, then add the model.addAttribute for that as well. Can you post your JSP too?

Related

Thymleaf controller request mapping binging issue

I am new to thymleaf and at first i used simple requestmapping and thymleaf th:action and th:object to bind controller methods. But after adding class level requestmapping i cannot view my html.
below is my controller class code where i redirect to login page.
#Controller
#RequestMapping("/project")
public class MyController {
#RequestMapping(value = {"/"}, method = RequestMethod.GET)
public String login(Model model) {
model.addAttribute("mylogin", new Credentials());
return "login";
}
}
below is my html page.
<form class="user" th:action="#{/project/login}" th:object="${mylogin}" method="POST">
<div class="form-group">
<input type="email" id="user_name" name="username"
class="form-control form-control-user"
placeholder="Enter Email Address..." />
</div>
<div class="form-group">
<input type="password" id="password" name="password"
class="form-control form-control-user"
placeholder="Password" />
</div>
<button class="btn btn-primary btn-user btn-block"
name="Submit" value="Login" type="Submit" th:text="Login"></button>
</form>
after adding #RequestMapping("/project") in class i cannot fetch html. If i remove this #RequestMapping("/project") and change th:action="#{/project/login}" to th:action="#{/login}" my code works.
What can be the problem for such issue?
Change This Request mapping this way /login with class level requestmapping and try again:
#RequestMapping(value = {"/login"}, method = RequestMethod.GET)
public String login(Model model) {
model.addAttribute("mylogin", new Credentials());
return "login";
}
OR
#GetMapping("/login")
public String login(Model model) {
model.addAttribute("mylogin", new Credentials());
return "login";
}

Spring Request method 'POST' not supported with th:field in select

I have strange problem with post method from form to method in controller.
Every mapping is ok but when i put th:field in 'select' I receive an error 405.
I tried remove this (th:field=*{code}) and then it's working but i dont have value of this.
So, in my controller in GET method i put to the model list of Code objects and new Position of object (for form)
Then in form html in "select" i display every single Code object.
In short, i would like to post data from select to the post method in my controller
Thats my code in controller:
#GetMapping("/add-shop-position")
public ModelAndView addShopPositionForm(){
ModelAndView modelAndView = new ModelAndView("admin/addShopPosition");
List<Code> codes = codeService.getAllCodes();
modelAndView.addObject("codes", codes);
modelAndView.addObject("position", new Position());
return modelAndView;
}
#PostMapping("/add-shop-position")
public ModelAndView addShopPositionSubmit(#ModelAttribute Position position){
ModelAndView modelAndView = new ModelAndView("admin/addShopPosition");
if(positionService.addPosition(position)){
//I will do something here in future
}else{
//I will do something here in future
}
return modelAndView;
}
And of course my controller has RequestMapping:
#Controller
#RequestMapping(value = "/admin")
public class AdminController {}
And thats my form, html view in Thymeleaf:
<form action="#" th:action="#{/admin/add-shop-position}" th:object="${position}" method="POST"
style="margin: 0 auto; width: 50%">
<div class="form-group">
<input class="form-control" type="text" th:field="*{title}" th:placeholder="Title">
</div>
<div class="form-group">
<input class="form-control" type="text" th:field="*{description}" th:placeholder="Description">
</div>
<div class="form-group">
<select class="form-control" th:field="*{code}">
<option th:each="code : ${codes}"
th:value="${code}"
th:text="${code.getCode()}"></option>
</select>
</div>
<div class="form-group">
<button class="btn btn-primary btn-block" type="submit" value="Submit">Create</button>
</div>
</form>

JSP doesn't display validation errors

<spring:bind path="aDepartment">
<div class="form-group ${status.error ? 'has-error' : ''}">
<label class="col-lg-4 control-label">Department *</label>
<div class="col-lg-8">
<form:input class="form-control" path="aDepartment" required="true"
placeholder="Department" />
<form:errors path="aDepartment" class="control-label" />
</div>
</div>
</spring:bind>
PATH is the path of the current page.
When I violate validation rules (on purpose) , errors are not bound to the model and the jsp doesn't display the errors.
Should I bind the errors manually to the model ? If so how can I do it ?
#RequestMapping(value = "/admin/adepartement/add", method = RequestMethod.POST)
public String add(
#ModelAttribute(value = "addadepartment") #Valid ADepartment pADepartment,
final BindingResult pBindingResult, final ModelMap pModel) {
if (!pBindingResult.hasErrors()) {
///
}
}else{
return PATH;
}
}
It should work just fine !
Make sure that "aDepartment" in the path refers to an attribute called "aDepartment" in your "ADepartment" Class.

form:error not showing error

When validating object controller just refreshes the page, instead showing errors via form:errors, can you tell me where is the problem. I guest it needs to get error from binding result and insert it into the page, instead controller is just refreshing page
Controller :
#PreAuthorize("hasRole('ROLE_ADMIN')")
#RequestMapping(value = "/create", method = RequestMethod.POST)
public String createProduct(MultipartFile image, Model model,#ModelAttribute #Valid ProductDto product, BindingResult bindingResult) throws IOException {
productValidator.validate(product,bindingResult);
if (bindingResult.hasErrors()){
return "admin/create";
} else {
return "index";
}
}
#PreAuthorize("hasRole('ROLE_ADMIN')")
#RequestMapping(value = "/create", method = RequestMethod.GET)
public String createProduct(Model model) {
model.addAttribute("product", new ProductDto());
model.addAttribute("categories", categoryService.findAll());
return "admin/create";
}
Validator :
#Override
public boolean supports(Class<?> aClass) {
return ProductDto.class.equals(aClass);
}
#Override
public void validate(Object o, Errors errors) {
ProductDto product = (ProductDto) o;
if (product.getTitle().isEmpty() || product.getTitle() == null) {
errors.rejectValue("title", "product.title", "Product title cant be empty");
}
if (product.getDescription().isEmpty() || product.getDescription() == null) {
errors.rejectValue("description", "product.description", "Product description cant be empty");
}
if (product.getPrice() == null || product.getPrice()<=0) {
errors.rejectValue("price", "product.price", "Product price is not valid");
}
if (product.getCategoryId()==null) {
errors.rejectValue("category", "product.category", "Product category is not valid");
}
}
jstl page :
<spring:url value="/product/create" var="formUrl"/>
<form:form modelAttribute="product" action="${formUrl }" method="post" enctype="multipart/form-data">
<div class="form-group">
<label>Title</label>
<form:input id="title"
cssClass="form-control" path="title"/>
<form:errors path="title"/>
</div>
<div class="form-group">
<label>Description</label>
<form:textarea id="description" rows="10"
cssClass="form-control" path="description"/>
</div>
<div class="form-group">
<label>Price</label>
<form:input id="price" type="number"
cssClass="form-control" path="price"/>
<form:errors path="description"/>
</div>
<div class="form-group">
<label for="sel1">Select category</label>
<form:select id="sel1" cssClass="form-control" path="categoryId">
<form:options items="${categories}" itemValue="id" itemLabel="title"/>
</form:select>
</div>
<label class="btn btn-default btn-file">
Image <input type="file" multiple accept='image/*' ng-file-select="onFileSelect($files)" name="image" style="display: block;">
</label>
<br><br>
<div class="text-center">
<button type="submit" class="btn btn-lg btn-success text-center"><span
class="fa fa-check"></span> Submit
</button>
<a href="/" class="btn btn-danger btn-lg text-center"><span
class="fa fa-times"></span> Cancel
</a>
</div>
</form:form>
I think your product model attribute has different name in your POST-handling method.
According to documentation:
The default model attribute name is inferred from the declared
attribute type (i.e. the method parameter type or method return type),
based on the non-qualified class name: e.g. "orderAddress" for class
"mypackage.OrderAddress", or "orderAddressList" for
"List<mypackage.OrderAddress>".
So your ProductDto product attribute will have name productDto in resulting model. But you referring the product in your template.
Try to explicitly set the name attribute of #ModelAttribute annotation
public String createProduct(MultipartFile image, Model model, #ModelAttribute(name = "product") #Valid ProductDto product, BindingResult bindingResult)
And to make sure that bidning and validation actually works, try to log it:
if (bindingResult.hasErrors()) {
System.err.println("Form has errors!");
}

Spring validator - The request sent by the client was syntactically incorrect

My friend helped me up set my first spring/hibernate project and now I am trying to implement a custom validator. I already have a RegistrationForm model that uses anotations to validate. However, now I need to implement a password validator - to check if the password and confirmPassword are equal.
Problem: when I POST, if the passwords match, the data is saved. If they dont match, then at the validators following line, I get the error from the title.
errors.rejectValue("confirmPassword", "valid.passwordConfDiff");
The request sent by the client was syntactically incorrect.
Tutorial I followed:
http://examples.javacodegeeks.com/enterprise-java/spring/mvc/spring-mvc-password-example/
This is what I have:
Controller:
#Controller
#RequestMapping("/")
//#SessionAttributes(value = {"registerForm"})
#ComponentScan("ba.codecentric.movienight")
public class FrontController {
#Autowired
private UserService userService;
#Autowired
#Qualifier("passwordValidator")
private PasswordValidator validator;
#InitBinder("password")
private void initBinder(WebDataBinder binder) {
binder.setValidator(validator);
}
#RequestMapping(method = RequestMethod.GET)
public String initIndex(Model model){
model.addAttribute("registerForm", new RegisterForm());
Password password = new Password();
model.addAttribute("password", password);
return "index";
}
#RequestMapping(value="/register", method=RequestMethod.POST)
public String addNewUser(#Valid #ModelAttribute("registerForm") RegisterForm registerForm,
BindingResult result, Model model, HttpServletRequest request, #Validated Password password){
if(result.hasErrors()){
model.addAttribute("error", true);
model.addAttribute("userIsRegistering", "<script>$('#loginbox').hide(); $('#signupbox').show();</script>");
System.out.println("ERROR");
return "index";
}
User user = new User();
user.setUserName(registerForm.getUserName());
user.setPassword(registerForm.getPassword());
userService.addNewUser(user);
return "index";
}
}
Password validator:
public class PasswordValidator implements Validator{
public boolean supports(Class<?> paramClass) {
return Password.class.equals(paramClass);
}
public void validate(Object obj, Errors errors) {
Password password = (Password) obj;
if (!password.getPassword().equals(password.getConfirmPassword())) {
errors.rejectValue("confirmPassword", "valid.passwordConfDiff");
}
}
}
RegistrationForm:
public class RegisterForm {
#NotBlank
#NotEmpty
private String userName;
#NotBlank
#NotEmpty
#Size(min=7,max=16,message="Password range error")
private String password;
#NotBlank
#NotEmpty
private String confirmPassword;
//getters setters
}
Registration form jsp:
<form:form id="signupform" class="form-horizontal" role="form" commandName="registerForm" action="${pageContext.request.contextPath}/register" method="post">
<form:errors path="*" cssClass="errorblock" element="div" class="alert alert-danger" role="alert" />
<div class="form-group">
<label for="userName" class="col-md-3 control-label">User Name</label>
<div class="col-md-9">
<form:input type="text" path="userName" class="form-control" name="userName" placeholder="User Name" />
</div>
</div>
<form:errors path="userName" element="div" class="alert alert-danger" role="alert" />
<div class="form-group">
<label for="password" class="col-md-3 control-label">Password</label>
<div class="col-md-9">
<form:password path="password" class="form-control" name="password" placeholder="Password"/>
</div>
</div>
<form:errors path="password" element="div" class="alert alert-danger" role="alert" />
<div class="form-group">
<label for="confirmPassword" class="col-md-3 control-label">Confirm Password</label>
<div class="col-md-9">
<form:password path="confirmPassword" class="form-control" name="confirmPassword" placeholder="Confirm Password"/>
</div>
</div>
<form:errors path="confirmPassword" class="alert alert-danger" role="alert" />
<div class="form-group">
<!-- Button -->
<div class="col-md-offset-3 col-md-9">
<form:button id="btn-signup" type="submit" class="btn btn-info"><i class="icon-hand-right"></i> &nbsp Sign Up</form:button>
</div>
</div>
</form:form>
I have also faced the same problem.
#RequestMapping(method = RequestMethod.POST)
public String processForm(
#Valid #ModelAttribute("student") Student student, Model model,
BindingResult result) {
if (result.hasErrors()) {
return "registration";
}
return "success";
}
When the object student has invalid attribute(s), then this code gives the error: The request sent by the client was syntactically incorrect.
However, if the order of arguments student and model is changed, then this method works as expected.
E.g.,
public String processForm(Model model, #Valid #ModelAttribute("student") Student student, BindingResult result)
and
public String processForm( #Valid #ModelAttribute("student") Student student, BindingResult result, Model model)
both work as expected.
Please, let me know what is the science behind this.

Resources