I want to show validation error in my jsp page.
My object is:
public class MyObjectDTO{ #valid private TextDTO text1; #valid private TextDTO text2 }
public class TextDTO{ #NotBlank private String code;#NotBlank private String label;}
My controller:
#RequestMapping(value = "/create", method = RequestMethod.POST)
public String creationProjet(#Valid #ModelAttribute MyObjectDTO obj, BindingResult result,
Model model) {
if (result.hasErrors()) {
model.addAttribute("hasErrors", true);
return "create";
} else {
....
return "redirect:/list";
}
}
my jsp
<div class="col-md-6 form-group ${requestScope['org.springframework.validation.BindingResult.obj'].hasFieldErrors('text1') ? 'has-error' : ''}">
<label class="col-lg-3 control-label">my label</label>
<div class="col-lg-5">
<form:select class="form-control" name="type" path="text1.code" id="selectType">
<option value="">---------</option>
<c:forEach items="${types }" var="type">
<form:option value="${type.id }">
<c:out value=" ${type.code}"></c:out>
</form:option>
</c:forEach>
</form:select>
<form:errors path="text1.code" class="has-error error"></form:errors>
</div>
</div>
My controller redirects to the page create but the errors are not showing. In debug mode there is one error that indicates text1.code cannot be a blank.
In your Jsp page add following line
<div class="col-md-6 form-group ${requestScope['org.springframework.validation.BindingResult.obj'].hasFieldErrors('text1') ? 'hasErrors' : ''}">
or use hasFieldErrors() instead
<div class="col-md-6 form-group ${requestScope['org.springframework.validation.BindingResult.obj'].hasFieldErrors()}">
And About addAttributes("hasErrors",true), use addFlashAttribute() which is store in flashmap and Object (In your case Error Message will be alive when you navigate to create page or redirect between two controller.) Look at this for more
In your controller Add RedirectAttributes Object like this
#RequestMapping(value = "/create", method = RequestMethod.POST)
public String creationProjet(#Valid #ModelAttribute MyObjectDTO obj,
BindingResult result,
RedirectAttributes redirectAtt,
Model model) {
if (result.hasErrors()) {
redirectAtt.addFlashAttribute("hasErrors","ur message");//instead of true you can write your own message
return "create";
} else {
....
}
return "redirect:/list";
}
}
If you write your own message instead of true
<c:if test="${not empty hasErrors">
<p>${hasErrors}</p>
</c:if>
only you missing is put part to model map.You are putting only flag. But you need to put result.
if(result.hasErrors()){
mm.addAttribute("errors", result);
return "create";
}
Related
I am having a small issue with Spring Boot forms displaying the information of the path value instead of the placeholder once you get to the editProfile.jsp. I want the input field to look like this;
Edit Profile Page instead of this Wrong Edit Profile. I do not want my users to have to click, select and delete the auto completed value. I want it to show the placeholder only and allow them to overwrite what is shown with ease.
This is the editProfile.jsp
<%--#elvariable id="editProfile" type=""--%>
<form:form method="POST" modelAttribute="editProfile">
<div class="MyForm form-group">
<h1>Edit Profile</h1>
<form:input type="email" class="MyInput" id="email" path="email" placeholder="${editProfile.email}" />
<form:button type="submit" class="from-control">Submit</form:button>
</div>
<div>
<img src="images/reg1.png" alt="picture">
</div>
</form:form>
</body>
</html>
This is the code specified in the Controller
#RequestMapping(value = "edit/{email}", method = RequestMethod.GET)
public String getEditUserData(#PathVariable("email") String email, Model model) {
AccountEntity accountInstance = accountRepo.findByEmail(email);
model.addAttribute("editProfile", accountInstance);
return "editProfile";
}
#RequestMapping(value = "edit/{email}", method = RequestMethod.POST)
public String enterEditUserData(#ModelAttribute("login") AccountEntity accountForm, #PathVariable("email") String email, Model model ) {
AccountEntity accountInstance = accountRepo.findByEmail(email);
accountInstance.setEmail(accountForm.getEmail());
accountRepo.save(accountInstance);
return "redirect:/login";
}
I have figured it out; You have to add a model of a new Entity, so the path variable does not fill in with the instance of the specific path value. Here is the new code, and compare it to the one I sent above.
#RequestMapping(value = "edit/{email}", method = RequestMethod.GET)
public String getEditUserData(#PathVariable("email") String email, Model model) {
AccountEntity accountInstance = accountRepo.findByEmail(email);
model.addAttribute("editProfile2", new AccountEntity());
model.addAttribute("editProfile1", accountInstance);
return "editProfile";
}
<%--#elvariable id="editProfile" type=""--%>
<%--#elvariable id="editProfile2" type=""--%>
<form:form method="POST" modelAttribute="editProfile2">
<div class="grid form-group">
<h1>Edit Profile</h1>
<form:input type="email" class="MyInput" id="email" path="email" placeholder='${editProfile1.email}' />
<form:button type="submit" class="from-control">Submit</form:button>
</div>
I had written a code for the passing the parameter but in the login page it is not displaying the parameter can anyone help me?My home page code as shown below
<h1>
<form:form action="./loginPage" method="GET" >
<input type ="text" value="abc" id="name">
<input type ="submit" value ="Login">
</form:form>
</h1>
my controller page:
#RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Model model) {
return "home";
}
#RequestMapping(value = "/loginPage", method = RequestMethod.GET)
public String redirect(#ModelAttribute("name")String name,BindingResult result,Model model) {
model.addAttribute(name);
if(result.hasErrors()){
return "home";
}else{
model.addAttribute("name",name);
return "loginPage";
}
}
My login page to display the parameter:
<h1>
Welcome to login Page
</h1>
<p>The value is:${name}</p>
When collecting input, there are a couple of ways to go, I'll go over two options here:
You can use a command object and bind that as an attribute in which case you would have something like this:
public class LoginForm {
#NotNull(message="Name is required")
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
In your controller you would:
#RequestMapping(value="/login", method= { RequestMethod.POST } )
public String redirect(#ModelAttribute("LoginForm") #Valid LoginForm loginForm, BindingResult bindingResult, Model model) {
if(bindingResult.hasErrors()){
return "home";
}
model.addAttribute("name", loginForm.getName());
return "loginPage";
}
In your JSP (with bootstrap classes) something like this, where you bind the form object to the form element which allows you to then bind the attribute "name" to the input field.
<form:form method="post"
commandName="loginForm"
action="/login"
role="form">
<form:errors path="name" id="name-errors" element="div" cssClass="alert alert-danger" />
<form:input path="name" cssClass="form-control" placeholder="Your name" />
<input type="submit" value="Submit" class="btn btn-primary" />
</form:form>
You can use request parameter binding to just pluck a field from a query string or form. However the downside is you can't use build in form validation and you want to redraw a form after an error you'll need to pass all the parameters back to repopulate it manually.I
#RequestMapping(value = "/loginPage", method = RequestMethod.GET)
public String redirect(#RequestParam(value="name", required=false) String name, Model model) {
if(name == null || name.length() == 0) {
return "home";
}
model.addAttribute("name",name);
return "loginPage";
}
For what it looks like your trying to do I'd recommend you use the command object binding approach. Also if you are using spring MVC for authentication, you should take a look at spring security. While the configuration can be a little frustrating it does provide a standard way to handle authentication and authorization.
http://docs.spring.io/autorepo/docs/spring-security/3.2.x/guides/hellomvc.html
I think that Model is request scoped. You will have to use Sessions
I have been dealing with the following issue:
I have a simple model class called User.
public class User{
private Long id;
private String name;
...}
And this is my the controller code:
#RequestMapping ( value = "/users", params = { "id" } )
public String showEditForm( final Model model, final HttpServletRequest req )
{
User edit = this.userRepository.findOne( Long.valueOf( req.getParameter( "id" ) ) );
model.addAttribute( "user", edit );
return "edit-user";
}
#RequestMapping ( value = "/users", method = RequestMethod.POST, params = {"edit"
})
public String editUser( #Valid #ModelAttribute ( "user" ) final User user,
final BindingResult bindingResult, final Model model )
{
if ( bindingResult.hasErrors() )
{
return "edit-user";
}
return "redirect:/users";
}
The following is the code snippet to displaying all the users:
<div class="userlist" th:unless="${#lists.isEmpty(users)}">
<h2 th:text="#{list.user.title}"></h2>
<table>
<thead>
<tr>
<th th:text="#{name}" />
<th th:text="#{details}" />
</tr>
</thead>
<tbody>
<tr th:each="u : ${users}">
<td th:text="${u.name}" />
<td><a th:href="#{/users(id=${tc.id})}" th:text="#{edit}"></a></td>
</tr>
</tbody>
</table>
</div>
And eventually the submit form:
<form action="#" th:action="#{/users}" th:object="${user}"
method="post">
<fieldset>
<ul th:if="${#fields.hasErrors('*')}" class="errorlist">
<li th:each="err : ${#fields.errors('*')}" th:text="${err}"></li>
</ul>
<div>
<input type="text" th:field="*{id}"/>
</div>
<div>
<label for="name"> <span th:text="#{name}"></span>
</label> <input type="text" th:field="*{name}"
th:class=" ${#fields.hasErrors('name')}? 'fieldError'" />
</div>
<div class="submit">
<button type="submit" th:text="#{update}" name="edit"></button>
</div>
</fieldset>
</form>
And now the problem description:
As long as the 'id'-field is present within the submit form, everything works fine. If I remove the 'id'-field from the submit form though, because the id property isn't meant to be modified, the workflow doesn't work anymore. In fact, the id is null in the editUser() method. I assume that Thymeleaf does set the value of the id property to null if it is not present within the submit form. But I'm not sure about this. And I think there must be some solution to this problem other than having to let the id-property reside in the submit form.
I hope anyone can help here out.
Thanks.
Edmond
That has nothing to do with Thymeleaf, but how binding works. Spring will only bind attributes to the model object which are present as parameter in the request. If you remove id that isn't present and as such cannot be bound (what should it be bound to?).
A solution to this is to either specify the id as a hidden form, so that it is present. Or in between requests store your object in the session (using #SessionAttributes on the controller) that way the earlier retrieved object is going to be used for binding.
#Controller
#SessionAttributes("user")
public class UserController {
#ModelAttribute("user")
public User initUser(#RequestParam("id") Long id) {
return this.userRepository.findOne(id);
}
RequestMapping ( value = "/users", params = { "id" } )
public String showEditForm() {
return "edit-user";
}
#RequestMapping ( value = "/users", method = RequestMethod.POST, params = {"edit"})
public String editUser( #Valid #ModelAttribute ( "user" ) final User user, final BindingResult bindingResult, SessionStatus status;) {
if ( bindingResult.hasErrors() ) {
return "edit-user";
}
status.setComplete(); // Indicate we are done,so #SessionAttributes can be cleaned up
return "redirect:/users";
}
Something like that should preserve the User between sessions, and the SessionStatus can then be used to trigger the cleanup of the session attributes.
Id field should be present in form otherwise how controller would know which user should be updated.
If this field is meaningless for client (that is it's some generated unique id) it should be done hidden. If it may be of some interest for client this field can be done read-only.
I need to show the fetched values from database which are stored in an arraylist using spring form:input tag. However i found that the 'value' attribute isn't supported. Please help!
I guess you are expecting something like this.
//Assumes you have the following in your class
public class Students{
private String name;
private List<String> Departments;
/* getters/setters */
}
In the HTML would be.
<form:input path="departments[0]" />
<form:input path="departments[1]" />
For more details about click http://www.javacodegeeks.com/2013/07/spring-mvc-form-handling-vol-5-select-option-options-tags.html
Please first retrieve the list from the datebase and set the list on the model attribute in the controller see the example set the
#Controller
public class UserController {
#RequestMapping(method = RequestMethod.GET)
public String userHome(Model model, EventBean event, UserService userService,ImageBean image)
{
List<Event> events = userService.viewNews(); //retrieve the list from datebase
model.addAttribute("event", event); //add bean object
model.addAttribute("events", events); //add list in model attribute
return "home";
}
}
your jsp page
<form:form modelAttribute="event"> <!--set the model attribute here -->
<form:input path="news" value="${events.get(0).news}" />
</form:form>
This is my code,please have a look and say what i might be doing wrong,
JAVA
public ModelAndView userEditProfile(#ModelAttribute("userDetails") UserFormbean registration,BindingResult result,HttpServletRequest request){
ModelAndView mav=null;
HttpSession httpSession=null;
List userProfileList=new ArrayList();
httpSession=request.getSession();
if (httpSession != null) {
UserFormbean formbean=(UserFormbean)httpSession.getAttribute("UserRegistrationFormBean");
userProfileList= userRegistrationService.getUserProfileInfo(formbean);
mav=new ModelAndView("EditProfile");
mav.addObject("userProfileInfoList", userProfileList);
}
return mav;
}
JSP::
-----
<c:if test="${not empty userProfileInfoList}">
<c:forEach var="temp" items="${userProfileInfoList}">
<div>
<form:label path="userRegistration.email"><spring:message code="label.email"/></form:label>
<form:input path ="userRegistration.email" value="${temp.get(0).UserRegistration.email}"/>
<form:errors path="userRegistration.email"/>
</div>
<div>
<form:label path="userRegistration.firstName"><spring:message code="label.firstname"/></form:label>
<form:input path ="userRegistration.firstName" value="${temp.get(0).UserRegistration.firstName}"/>
<form:errors path="userRegistration.firstName"/>
</div>
<div>
<form:label path="userRegistration.lastName"><spring:message code="label.lastname"/></form:label>
<form:input path ="userRegistration.lastName" value="${temp.get(0).UserRegistration.lastName}"/>
<form:errors path="userRegistration.lastName"/>
</div>
</c:forEach>
</c:if>
I've got a Groovy project using Spring framework and its validators doing sanity-checking on my forms' input values. I would like to have Spring populate error messages next to my input form fields via the built-in ${status.errorMessage}; however, I can only get it to populate "errorMessages" in my Model object (from the controller.) So let's take a look at some code.
login.jsp:
<form method="post" action="<c:url value="/login" />">
<spring:bind path="request.username">
<label for="username"><fmt:message key="login.username"/>:
<input type="text" id="username" size="20" maxlength="50" name="username" value="${request.username}"/>
</label>
<%-- This part does NOT display the validation errors. --%>
<c:if test="${status.error}"><span class="error">${status.errorMessage}</span></c:if>
</spring:bind>
<spring:bind path="request.password">
<label for="password"><fmt:message key="login.password"/>:
<input type="password" id="password" size="20" maxlength="30" name="password" />
</label>
<%-- This part does NOT display the validation errors. --%>
<c:if test="${status.error}"><span class="error">${status.errorMessage}</span></c:if>
</spring:bind>
<input id="login" type="submit" value="Login"/>
</form>
<%-- This part does display the validation errors. --%>
<c:if test="${ec > 0}">
<p>
<c:forEach items="${errorCodes}" var="error">
<span class="error"><fmt:message key="${error.defaultMessage}"/></span><br/>
</c:forEach>
</p>
</c:if>
LoginController.groovy:
#RequestMapping(method = RequestMethod.GET, value = '/')
ModelAndView defaultView() {
ModelMap model = new ModelMap()
model.addAttribute('request', new LoginRequest())
new ModelAndView('login', model)
}
#RequestMapping(method = RequestMethod.POST, value = '/login')
ModelAndView login(
LoginRequest loginRequest, HttpServletResponse response,
HttpSession session, BindingResult br, ModelMap model
) {
validator.validate(loginRequest, br)
if (br.hasErrors()) {
model.addAttribute('request', loginRequest)
return returnWithError(br, model, 'login')
}
...
}
private ModelAndView returnWithError(BindingResult br, ModelMap model, String redirectTo) {
br.allErrors.each {error ->
log.error(error.toString())
}
def objectErrors = br.allErrors.findAll {e -> e instanceof ObjectError}
model.addAttribute('ec', br.errorCount)
model.addAttribute('errorCodes', objectErrors)
new ModelAndView(redirectTo, model)
}
LoginRequestValidator.groovy:
#Override
void validate(Object o, Errors errors) {
ValidationUtils.rejectIfEmpty(errors, 'username', 'username.empty', 'username.empty')
ValidationUtils.rejectIfEmpty(errors, 'password', 'password.empty', 'password.empty')
}
Which part of the Spring Magic [TM] am I missing?
I think your BindingResult object should be the argument immediately following your LoginRequest object. See http://static.springsource.org/spring/docs/3.0.x/reference/mvc.html#mvc-ann-requestmapping and specifically Example 15.1. Invalid ordering of BindingResult and #ModelAttribute
Review the Javadoc on #RequestMapping as I find it the best on the subject:
http://static.springsource.org/spring/docs/3.0.x/api/org/springframework/web/bind/annotation/RequestMapping.html
Try the following:
ModelAndView login(
#Valid LoginRequest loginRequest, HttpServletResponse response,
HttpSession session, BindingResult br, ModelMap model
) {}
See What does the #Valid annotation indicate in Spring?
If that doesn't work you should try translating some of your code to plain Java and running the debugger to see whats happening (I know its not an answer but just an idea).
Maybe you will find these post from kgiannakakis very usefull.
It explains the purpose of these functionnality and how to deal with is explained in Spring 3.1 documentation.
Adding something like that will probably do the trick, isn't it ?
#Controller
public class MyController {
#InitBinder
protected void initBinder(WebDataBinder binder) {
binder.setValidator(new FooValidator());
}
#RequestMapping("/foo", method=RequestMethod.POST)
public void processFoo(#Valid Foo foo) { ... }
}
Take a look at SpringSource blog and especially these post about new features around data binding. It could add some new look about your validation process.