form validation error message doesn't show spring mvc thymeleaf - java

I have add user form doesn't display the error message with thymeleaf. I try to read other solutions and apply other solutions in this forum but still doesn't work.
**userform.html**
<form id="adduser" role="form" th:action="#{/adduser}" method="post" th:object="${user}">
<div class="form-group">
<label>First Name</label>
<input class="form-control" th:field="*{first_name}"/>
<p th:if="${#fields.hasErrors('first_name')}" th:errors="${user.first_name}">First name is mandatory</p>
</div>
<button type="submit" name="action" value="adduser" class="btn btn-default" onclick="myFunction()">Submit</button>
</form>
My spring MVC controller
UserformController.java
// Returns the view with model attached
#RequestMapping(value = "/userform", method = RequestMethod.GET)
public ModelAndView showuser(HttpServletRequest request, HttpServletResponse response) {
LOGGER.info("in get adduser");
ModelAndView mav = new ModelAndView();
mav.setViewName("userform");
mav.addObject("user", new User());
return mav;
}
//Save
#RequestMapping(value = "/adduser", method = RequestMethod.POST)
public ModelAndView adduser(#Valid #ModelAttribute("userForm") Userform user, BindingResult result, #RequestParam(value="action", required=true) String action) {
ModelAndView mav = new ModelAndView();
if (result.hasErrors()) {
mav.setViewName("redirect:userform");
mav.addObject("user", user);
return mav;
}
else {
utilService.insert(user);
mav.setViewName("redirect:userlist");
return mav;
}
}

Did you define any constraints in the User class? Please show the User class.
The errors would be based on the constraints in the properties of the User class, so there should be something like this
public class User {
#NotNull
private String first_name;
}

Related

How to get modelattribute from GET to POST method

I am making a Spring MVC project and i want to register new user.In my first page user sumbit his details like full name,address,mobilenumber etc when user enter the details i will send a OTP on his mobile and Store OTP in CacheLoader.Then i redirect the otp page and also use flashAttribute to use in OTPController GET method.I want when user enter OTP the full data comes to POST method and i will validate OTP then i save the full data in DB.
UserDetailsController.java
#RequestMapping(method = RequestMethod.POST)
public String addUser(#Valid #ModelAttribute("addUser") UserPojo userPojo, BindingResult bindingResult,
Model modelMap, final RedirectAttributes redirectAttributes) {
otpService.clearOTP(userPojo.getPhoneNumber());
boolean validate = adminUserService.uniqueUserName(userPojo.getUserName());
if (validate == false) {
int otp = otpService.generateOTP(userPojo.getPhoneNumber());
String response = smsService.sendOtp(otp, userPojo.getPhoneNumber());
if(response.equals("OK")) {
redirectAttributes.addFlashAttribute("addUser", userPojo);
logger.debug(addUserPojo.toString());
return "redirect:/userotp";
}
logger.debug("response is-OTP Failed");
redirectAttributes.addFlashAttribute("error", "Problem is Send OTP");
return "redirect:/admin/adduser";
}
redirectAttributes.addFlashAttribute("error", "UserName Must Be Unique");
return "redirect:/admin/adduser";
}
OtpController.java
#RequestMapping(value = "/userotp", method = RequestMethod.GET)
public String showAddUser(#ModelAttribute("addUser") UserPojo userPojo,
final BindingResult mapping1BindingResult, final Model model, ModelMap map,
final RedirectAttributes redirectAttributes) {
logger.debug("Enter in the Method" + this.getClass().getSimpleName());
logger.debug("Data is" + addUserPojo.toString());
return "userotp";
}
#RequestMapping(value = "/userotp", method = RequestMethod.POST)
public String validateUser(
final BindingResult mapping1BindingResult, Model model, final RedirectAttributes redirectAttributes,
HttpServletRequest request) {
logger.debug("Enter in the Method" + this.getClass().getSimpleName());
return "userotp";
}
userotp.html
<form:form method="post">
<div class="" role="document" style="padding: 0px 30%;">
<div class=" box">
<h5 class="">User Moblie No. Verify</h5>
<div class="">
<label>Moblie Number For Otp</label> <form:input type="number"
class="form-control" name="otp" placeholder="Enter OTP"/>
<br> <br>
<div class="float-right">
<button type="reset" class="btn btn-secondary">Reset</button>
<button type="submit" class="btn btn-primary">Verify</button>
</div>
</div>
</div>
</div>
</form:form>
I want to get data UserDetails in OtpController POST method.Can anyone help me.
I think you should use #SessionAttributes. To use #SessionAttributes we can store modelAttribute in Session and when there is no use of modelAttribute. We can remove it.
We can remove it like this:
#RequestMapping(value = "/userotp", method = RequestMethod.POST)
public String validate(#ModelAttribute User user, WebRequest request, SessionStatus status) {
// your business logic
status.setComplete();
request.removeAttribute("user", WebRequest.SCOPE_SESSION);
return "userotp";
}

Neither BindingResult nor plain target object for bean name when running application

index.jsp
<f:form action="emp_change.htm" method="POST" commandName="index">
<div id="login_box">
<div id="form_val">
<div class="label">Username:</div>
<div class="control"><f:input path="emailId" /></div>
<div style="clear:both;height:0px;"></div>
<div class="label">Password:</div>
<div class="control"><f:input path="password" type="password" /></div>
<div style="clear:both;height:0px;"></div>
<div id="msgbox"></div>
<div id="login_foot">
<input type="submit" name="action" id="login" value="Login" class="send_button" />
</div>
</div>
</div>
</f:form>
AdminInfoControl.java
#Controller
public class AdminInfoControl {
private AdminInfoService service;
#RequestMapping(value = "/emp_change", method = RequestMethod.POST)
public String doActions(#ModelAttribute JtAdminInfo emp, BindingResult result, #RequestParam String action, Map<String, Object> map) {
service = new AdminInfoService();
JtAdminInfo empResult = new JtAdminInfo();
switch (action.toLowerCase()) {
case "login":
JtAdminInfo search = service.getFindAdmin(emp.getEmailId());
empResult = search != null ? search : new JtAdminInfo();
break;
}
map.put("index", empResult);
map.put("empList", service.getAll());
return "index";
}
}
I'm getting following error :
Neither BindingResult nor plain target object for bean name 'emp_change' available as request attribute
Anyone please help me to correct this. Please let me know, if information is not sufficient.
Just answered on almost the same question.. You are obtaining emp_change as a model attribute in doActions method but you didn't set it as a model attribute previously. So, set your emp_change as a model attribute in some method that e.g. shows your index.jsp page. Something like this:
#RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView showIndex() {
ModelAndView mav = new ModelAndView("index");
mav.addObject("emp_change", new JtAdminInfo ());
return mav;
}
I have added following method in my controller and works fine.
#RequestMapping("/index")
public String setupForm(Map<String, Object> map) {
map.put("index", new JtAdminInfo());
return "index";
}

Spring Security using java config doesn't submit the login page

I am new to Java config feature of the spring. I am trying to use spring security using java config but my login page doesn't do anything when i submit the page. It looks like the request is not going anywhere. I am using Spring 4.0.6 RELEASE and Spring security 3.2.4.RELEASE. Please help. Thanks in advance.
1) Spring security Java Config class
#Configuration
#EnableWebSecurity
public class AppSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private CustomUserDetailsService customUserDetailsService;
#Override
protected void configure(AuthenticationManagerBuilder registry) throws Exception {
registry.userDetailsService(customUserDetailsService);
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/resources/**");
}
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/login","/login/form**","/register","/logout").permitAll() //any user can access a request if the URL starts with these URLs
.antMatchers("/admin","/admin/**").hasRole("ADMIN") //Any URL that starts with "/admin/" will be resticted to users who have the role "ROLE_ADMIN"
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login/form")
.loginProcessingUrl("/login")
.failureUrl("/login/form?error")
.permitAll();
}
}
2) Login page using tiles so this is just one of the body page
<%# page pageEncoding="UTF-8"%>
<p>
Locale is:
<%=request.getLocale()%></p>
<%-- this form-login-page form is also used as the
form-error-page to ask for a login again.
--%>
<c:if test="${not empty param.login_error}">
<font style="font-weight:bold;font-color:red"> Your login attempt was not successful, try
again.<br />
<br /> Reason: <c:out value="${SPRING_SECURITY_LAST_EXCEPTION.message}" />.
</font>
</c:if>
<br class="smaller" />
<!-- in spring security 3 the value is replaced to /login from j_spring_security_check -->
<form name="adminLogin" action="<c:url value='/login'/>"
method="POST">
<fieldset>
<legend>Login</legend>
<br />
<div class="largeFormEntry">
<label class="standardFormLabel" for="username">User Name:</label> <input
type='text' name='username'
value='<c:if test="${not empty param.login_error}"><c:out value="${SPRING_SECURITY_LAST_USERNAME}"/></c:if>' />
</div>
<div class="clear"></div>
<div class="largeFormEntry">
<label class="standardFormLabel" for="password">Password:</label> <input
type='password' name='password'>
</div>
<div class="largeFormEntry">
<input type="checkbox" name="_spring_security_remember_me">
<span>Don't ask for my password for two weeks</span>
</div>
<div class="clear"></div>
<!-- form footer -->
<br />
<div id="loginFooter">
<input class="buttons" type="button" value="Login" />
</div>
<!-- end of form footer -->
</fieldset>
<input type="hidden" name="${_csrf.parameterName}"
value="${_csrf.token}" />
<div class="clear"></div>
<div class="bodylink">
<br /> <a href="loginExample.jsp" title="Forgot User Name?">Forgot
User Name or Password?</a> <br /> <br /> <br /> If you
don't have an account, you can <a href="loginExample.jsp"
title="Create an account now">create an account now.</a>
</div>
</form>
3) Controllers
A) in this controller if the URL is .../admin/reports or admin/login...it displays the proper view but when I submit login, it doesn't do anything...
#Controller
#RequestMapping("/admin")
public class AdminLoginController {
#Autowired
SecurityRoleService securityRoleService;
/*
* #RequestMapping(value="{loginType}", method = RequestMethod.GET) public
* String getAdminLogin(#PathVariable String loginType, ModelMap model) {
*
* model.addAttribute("model", loginType); return "adminlogin";
*
* }
*/
// nothing is passed, show the login page
#RequestMapping(value = { "", "/login" }, method = RequestMethod.GET)
public ModelAndView adminLoginPage() {
// ModelAndView model = new ModelAndView();
Map<String, Object> model = new HashMap<String, Object>();
model.put("pageInstructionText", "Admin login");
// model.addObject("title",
// "Spring Security 3.2.3 Hello World Application");
// model.addObject("message", "Welcome Page !");
// model.setViewName("adminlogin",loginModel);
return new ModelAndView("adminlogin", model);
}
#RequestMapping(value = { "", "/login" }, method = RequestMethod.POST)
public ModelAndView handleLogin(BindingResult errors) {
Map<String, Object> model = new HashMap<String, Object>();
String view = "";
if (errors.hasErrors()) {
model.put("pageInstructionText", "Admin login");
view = "adminLogin";
} else {
view = "reports";
model.put("pageInstructionText", "List of Admin Reports");
}
return new ModelAndView(view, model);
}
#RequestMapping(value = { "/reports" }, method = RequestMethod.GET)
public ModelAndView adminReportsPage()
{
Map<String, Object> model = new HashMap<String, Object>();
model.put("pageInstructionText", "List of Admin Reports");
Date now = new Date();
SecurityRole securityRole = (SecurityRole.getBuilder("ROLE_ADMIN",
"Admin User", "Y", new Long(1), now, now)).build();
// securityRoleRepo.save(securityRole);
securityRoleService.save(securityRole);
System.out.println("SecurityRole inserted!");
return new ModelAndView("reports", model);
}
}
B)
#Controller
#RequestMapping("/")
public class AppController {
#RequestMapping(value = { "/helloworld**" ,"/welcome**","/home**"}, method = RequestMethod.GET)
public ModelAndView welcomePage() {
return getWelcomePage();
}
#RequestMapping(value = { "" }, method = RequestMethod.GET)
public ModelAndView getWelcomePage() {
ModelAndView model = new ModelAndView();
model.addObject("title",
"Spring Security 3.2.3 Hello World Application");
model.addObject("message", "Welcome Page !");
model.setViewName("helloworld");
return model;
}
#RequestMapping(value = "/protected**", method = RequestMethod.GET)
public ModelAndView protectedPage() {
ModelAndView model = new ModelAndView();
model.addObject("title", "Spring Security 3.2.3 Hello World");
model.addObject("pageInstructionText", "This is a protected page : Admin login");
model.setViewName("adminlogin");
return model;
}
#RequestMapping(value = "/confidential**", method = RequestMethod.GET)
public ModelAndView superAdminPage() {
ModelAndView model = new ModelAndView();
model.addObject("title", "Spring Security 3.2.3 Hello World");
model.addObject("message",
"This is confidential page - Need Super Admin Role !");
model.setViewName("protected");
return model;
}
#RequestMapping(value = { "/login" }, method = RequestMethod.POST)
public ModelAndView adminReportsPage() {
Map<String, Object> model = new HashMap<String, Object>();
model.put("pageInstructionText", "List of Admin Reports");
Date now = new Date();
//SecurityRole securityRole = (SecurityRole.getBuilder("ROLE_ADMIN",
// "Admin User", "Y", new Long(1), now, now)).build();
// securityRoleRepo.save(securityRole);
//securityRoleService.save(securityRole);
System.out.println("SecurityRole inserted!");
return new ModelAndView("reports", model);
}
}
You have to use
.formLogin()
.loginPage("/login")
if you want to submit the form to /login.
So replace
.formLogin()
.loginPage("/login/form")
.loginProcessingUrl("/login")
.failureUrl("/login/form?error")
.permitAll();
with
.formLogin()
.loginPage("/login")
.failureUrl("/login/form?error")
.permitAll();
The other option is to submit to /login/form and keep the current configuration.
Docs: http://docs.spring.io/spring-security/site/docs/3.2.5.RELEASE/reference/htmlsingle/See section 3.3 ava Configuration and Form Login.

Using #ModelAttribute and RedirectAttributes

I have a controller with the following methods:
#RequestMapping(value = "/register", method = RequestMethod.GET)
public String register(Model model) {
model.addAttribute("user", new User());
return "register";
}
#RequestMapping(value = "/registration", method = RequestMethod.POST)
public String registration(#ModelAttribute("user") User user, BindingResult bindingResult, RedirectAttributes redirectAttributes) {
UserValidator validator = new UserValidator();
validator.validate(user, bindingResult);
if (bindingResult.hasErrors()) {
redirectAttributes.addFlashAttribute(BindingResult.MODEL_KEY_PREFIX + "user", bindingResult);
redirectAttributes.addFlashAttribute("user", user);
return "redirect:/register";
}
...
}
My jsp:
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<form:form method="POST" modelAttribute="user" action="/registration">
<div>
<label>First Name</label>
<form:input path="firstName"/>
<form:errors path="firstName"/>
</div>
<div>
<label>Last Name</label>
<form:input path="lastName"/>
<form:errors path="lastName"/>
</div>
<div>
<label>E-mail</label>
<form:input path="email"/>
<form:errors path="email"/>
</div>
<div>
<label>Password</label>
<form:password path="password"/>
<form:errors path="password"/>
</div>
<input type="submit" value="Submit"/>
</form:form>
However, if there are errors they are not shown after the redirect because I create a new user every time the /register is called. Is there a way to fix this without storing the user in a session?
I can create another method just for this case so I can redirect to /register2 without losing the user:
#RequestMapping(value = "/register2", method = RequestMethod.GET)
public String register2() {
return "register";
}
It worked like I wanted, but it's a very bad approach.
How about checking first if a model named "user" exist before creating one on "/register" ?
if(!model.containsAttribute("user")) model.addAttribute("user", new User());
Also if I'm not wrong you can simply use #ModelAttribute on parameter and it will serve similar purpose
#RequestMapping(value = "/register", method = RequestMethod.GET)
public String register(#ModelAttribute("user") User user) {

Edit form validation with Spring MVC

I use Spring MVC and Spring form validation in my project.
There is class named Group in object model and I created form for editing it.
Form
<spring:url var="saveGroup" value="/teacher/groups/save"/>
<form:form action="${saveGroup}" method="post" modelAttribute="group">
<form:hidden path="id"/>
<div id="nameDiv" class="control-group">
<form:label path="title">Title:</form:label>
<form:input path="title"/>
<form:errors path="title"/>
</div>
<div id="specDiv" class="control-group">
<form:label path="title">Specialty:</form:label>
<form:select path="specialty">
<form:options items="${specialties}" itemValue="id" itemLabel="title"/>
</form:select>
</div>
<div class="center">
<spring:url var="groups" value="/teacher/groups"/>
<input class="btn btn-primary" type="submit" value="Save"/>
<a class="btn" href="${groups}"> Cancel </a>
</div>
</form:form>
Controller
#Controller
#RequestMapping("/teacher/groups")
public class GroupsController {
#Autowired
private GroupService groupService;
#Autowired
private SpecialtyService specialtyService;
#ModelAttribute("group")
public Group setGroup(Long id) {
if (id != null) {
return groupService.read(id);
} else {
return new Group();
}
}
#InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(Specialty.class, "specialty",
new SpecialtyEditor(specialtyService));
binder.setValidator(new GroupValidator());
}
#RequestMapping("")
public ModelAndView groups() {
return new ModelAndView("teacher/groups/list", "groups",
groupService.list());
}
#RequestMapping("/edit")
public ModelAndView editGroup() {
return new ModelAndView("teacher/groups/edit", "specialties",
specialtyService.list());
}
#RequestMapping(value = "/save", method = RequestMethod.POST)
public String saveGroup(#Valid Group group, BindingResult result) {
if (result.hasErrors()) {
return "forward:/teacher/groups/edit";
}
groupService.update(group);
return "redirect:/teacher/groups";
}
}
I want to set the adequate behavior of my form in the case of failed validation. I.e. it should save its state but only show validation error message (as when using javascript to validate).
I thought that "forward:/teacher/groups/edit" will again forward request to editGroup() with saved objects group and result. But when I failed validation form just reloads and show start state of edited group: no errors and no saved changes.
How can I do that correctly?
Thanks!
I solved problem by not forwarding request to other method but sending answer to user immediately. Now it works and looks like:
#RequestMapping(value = "/save", method = RequestMethod.POST)
public ModelAndView saveGroup(#Valid Group group, BindingResult result) {
if (result.hasErrors()) {
return new ModelAndView("/teacher/groups/edit", "specialties", specialtyService.list());
}
groupService.update(group);
return new ModelAndView("redirect:/teacher/groups");
}

Categories