Concept of Two-Way data binding in Spring MVC - spring

This is my login.jsp file.
<form:form method="POST" action="checklogin" modelAttribute="log">
<form:label path="username">UserName: </form:label>
<form:input path="username" id="username" /><br /><br />
<br />
<form:label path="pswd">Password: </form:label>
<form:password path="pswd" id="password" /><br /> <br />
<br />
<input type="submit" id="btnLogin" value=login class="login" />
</form:form>
This is my controller
#RequestMapping(value = "/checklogin", method=RequestMethod.POST)
public String chklogin(#ModelAttribute Login login, Model mod) {
if (login.getUsername().equals("subro") && login.getpswd().equals("ss")) {
mod.addAttribute("log",login);
return "Home";
}
else {
return "Login";
}
}
Still I am getting the error as
Neither BindingResult nor plain target object for bean name 'log' available as request attribute

Change
#ModelAttribute Login login
To
#ModelAttribute Login log

Two way data binding in spring allows user inputs to be dynamically bound to the beans. It is two-way in a sense that it can get the inputs from the beans and it can post the user inputs to the beans using GET and POST api.
Using the #ModelAttribute annotation you can bind the user inputs with the beans.
#RequestMapping(value = "/login", method=RequestMethod.GET)
public String login(#ModelAttribute Login log){ //one-way binding
return "Login";
}
#RequestMapping(value = "/checklogin", method=RequestMethod.POST)
public String chklogin(#ModelAttribute Login log, Model mod) { //two-way binding
if (login.getUsername().equals("subro") && login.getpswd().equals("ss")) {
mod.addAttribute("log",login);
return "Home";
}
else return "Error";
}
Earlier I haven't written the login method which is mapped with the url /login.
When you are getting an error as "Neither BindingResult nor plain target object for bean name 'log' available as request attribute", it means that the beans ('log' in my case) is not able to bind with the view page.

Related

How do I access a variable in the request scope in JSP from a Spring MVC controller?

I have the following in my controller
#GetMapping("/login")
public String login(#RequestParam(name="userId", required=true) String userId) {
if (userId.matches("^\\d+$")) {
return "login";
And I have the following in my login.jsp
User: <input type="text" name="userId" value="${userId}"><br>
However for the URL https://localhost:8443/login?userId=751061, the browser returns
User: <input type="text" name="userId" value=""><br>
How can I access the userId from the request? I tried ${requestScope.userId} also.
I've rebuilt the app with mvn spring-boot:run.
I had to add
public String login(#RequestParam(name="userId", required=true) String userId,
HttpServletRequest request) {
...
request.setAttribute("userId", userId);
Then it was accessible. Rails really spoils you.
https://memorynotfound.com/servlet-attributes-example/

Request method 'GET' not supported Spring Booth with Thymeleaf

I am building a very simple crud app using Spring boot, Jpa and Thymeleaf, but I am stuck at a "Request method 'GET' not supported" problem. I get this error whenever I want to access the /add page through which I can add a new student. The snippets associated with this error are as below:
Thymeleaf form:
<h1>Form</h1>
<form action="#" th:action="#{/add}" th:object="${addStudent}"
method="post">
<p>Full name: <input type="text" th:field="*{fname}" /></p>
<p>Major: <input type="text" th:field="*{major}" /></p>
<p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
</form>
Controller addNewStudentMethod
#PostMapping("/add")
public String addNewStudent( #ModelAttribute StudentEntity studentEntity, Model model) {
model.addAttribute("addStudent",studentRepository.save(studentEntity) );
return "/allstudents";
}
The error I get:
There was an unexpected error (type=Method Not Allowed, status=405).
Request method 'GET' not supported
Thanks,
In your controller you only have a method which has mapped to POST request "/add". You have to have a GET request mapped to a different method OR change the #PostMapping("/add") to #RequestMapping("/add").
Please note:
#PostMapping is for mapping POST request only.
#GetMapping is for mapping GET request only.
#RequestMapping maps all request types
You have some issues with how you have it set up. What you may want is:
#GetMapping("/add")
public String addNewStudent(Model model) {
model.addAttribute("studentEntity", new StudentEntity()); //create a new bean so that your form can bind the input fields to it
return "add"; //let's say add.html this is the name of your form
}
#PostMapping("/add")
public String addNewStudent( #ModelAttribute StudentEntity studentEntity, Model model) {
//call any service methods to do any processing here
studentRepository.save(studentEntity);
return "redirect:/allstudents"; //this would be your confirmation page
}
Your add.html form would have something like:
<form th:object="${studentEntity}" th:action="#{/add}" method="post" action="allstudents.html">
<!-- input fields here --->
</form>
Note that the th:object is what you added to the model in the #GetMapping method.
change your Controller methods's #PostMapping("/any-url") to either #GetMapping("/any-url") or #RequestMapping("/any-url")
In simple words, change your above controller's method to
#RequestMapping("/add")
public String addNewStudent( #ModelAttribute StudentEntity studentEntity, Model model) {
model.addAttribute("addStudent",studentRepository.save(studentEntity) );
return "/allstudents";
}

#ModelAttribute("") annotation is still working with the wrong parameter in spring mvc

I am trying to learn spring mvc. I have trouble understanding how #ModelAttribute works. Below is my controller
#RequestMapping("/showForm")
public String showForm(Model theModel){
Student student = new Student();
theModel.addAttribute("testName",student);
return "student-form";
}
#RequestMapping("/processForm")
public String showForm(#ModelAttribute("hello") Student student){
return "student-confirmation";
}
When i go to student-form page i create a student object and add it to the model with attribute name "testName". Then i submit to form to "processForm" method. Using below form
<form:form action="processForm" modelAttribute="testName">
First Name: <form:input path="firstName" />
Second Name: <form:input path="lastName" />
<input type="submit" value="submit" />
</form:form>
Here is what i don`t understand the attribute names do not match at where i put the object to model and where i retrive it. But the result is shown correctly..
theModel.addAttribute("testName",student); //Here it is testName
#ModelAttribute("hello") Student student //Here it is hello
student-confirmation.jsp
First Name : ${hello.firstName}
Last Name : ${hello.lastName}
The Student model is populated automatically after submit the form because you have set testName as the model attribute:
theModel.addAttribute("testName",student);
JSP:
<form:form action="processForm" modelAttribute="testName">
<form:input path="firstName" />
So Spring matches Student field firstName with form text input with path: path="firstName" .
After submit:
#RequestMapping("/processForm")
public String showForm(#ModelAttribute("hello") Student student){
#ModelAttribute("hello") is not required, Student is matched
automatically.
You just change the reference name of the model. And then you can get values from the model using ${hello.firstName} at your JSP.
More info about #ModelAttribute you can read #ModelAttribute Annotation As a Method Argument
Hope it helps.

How to made Spring Security to redirect to specified path after Authentation

Its my first attempt to Spring Security, so the final solution for my question may be easy. So...
I have an index page, which has only sign in form:
<form name="loginForm" action="login.html" method="post">
<table>
<tr>
<td><#spring.message "form.email" /></td>
<td><input type="text" name="email" /></td>
</tr>
<tr>
<td><#spring.message "form.password" /></td>
<td><input type="password" name="password" /></td
</tr>
</table>
<input type="submit" value="${signIn}" />
</form>
<form name="" action="createAccount.html">
<input type="submit" value="${register}" />
</form>
when im POST request, it is handled by controller. In My Controller I retrieve UserAccount data from DB and pass it to another page called "account.html".
This controller method is posted below:
#RequestMapping(value = "/login", method = RequestMethod.POST)
public String logUserAccount(#RequestParam(value = "email", required = false) String email,
#RequestParam(value = "password", required = false) String password, RedirectAttributes redirect) {
try {
UserAccount userAccount = userAccountService.signIn(email, password);
redirect.addFlashAttribute("userAccount", userAccount);
return "redirect:account.html";
} catch (InvalidCreditnailsException e) {
return RedirectController.REDIRECT_TO_INDEX_VIEW;
}
}
And Next controller method, which put user account data to model and render account.html page:
#RequestMapping(value = "/account", method = RequestMethod.GET)
public String accountWindow(#ModelAttribute("userAccount") UserAccount userAccount, Model model){
model.addAttribute("userAccount", userAccount);
return "account";
}
Now, I want to secure account.html page, preventing non authorized users to go directly to /account.html page. But my configuration of Spring Security is not correct. It looks like this:
<security:http>
<security:intercept-url pattern="/account**" access="ROLE_USER" />
<security:form-login
login-page="/index.html"
login-processing-url="/login.html"
default-target-url="/account.html"
username-parameter="email"
password-parameter="password"
/>
<security:logout />
</security:http>
<security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<security:user name="test#gmail.com" password="qwerty" authorities="ROLE_USER"/>
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
What it does actually? When Im trying to access /account.html directly it redirect me to index.html where I have sign In form. Thats fine. But when Im log in Spring Security redirect me directly to /account.html page, Instead of sending /login.html request to my login controller for retrieve user data.
How to set up this> Any Ideas? Maybe my approach is not correct? I want only index and register page to be available for all guests. Rest of the page only for logged users.
Thank you for your help.
Sounds like you need to get your user account from the current context because you are already logged in. For example: You log in, close the browser, open a new browser window, and navigation to /account.html. You should still be able to reach /account.html because you have an active session on the server.
You may want to consider doing the following in your AccountController:
Retrieve the authenticated user:
Authentication auth = SecurityContextHolder().getContext().getAuthentication();
Get the user's username:
String username = auth.getName();
Get the user's account object:
UserAccount userAccount = userService.getAccount(username);
Alternatively, you can add a Principal argument to your AccountController to automatically inject the Principal.
#RequestMapping(value = "/account", method = RequestMethod.GET)
public String accountWindow(Model model, Principal principal){
UserAccount userAccount = userService.getAccount(principal.getName());
model.addAttribute("userAccount", userAccount);
return "account";
}

#NumberFormat Annotation not working

Trying to show the currency symbol in JSP but I don't see it. Did my research and I just don`t know what more should I add to get it working. This is what I have.
<mvc:annotation-driven />
Controller
#NumberFormat(style = Style.CURRENCY)
private Double value = 50.00;
#ModelAttribute("value")
#NumberFormat(style = Style.CURRENCY)
public Double getValue() {
return value;
}
#RequestMapping(method = RequestMethod.GET)
public ModelAndView loadForm(#ModelAttribute("user") User user) {
ModelAndView instance
modelAndView.addObject("value", 100.00);
return modelAndView;
}
JSP
<spring:bind path="value">
<input type="text" name="${value}" value="${value}"/>
</spring:bind>
<spring:bind path="value">
${value}
</spring:bind>
Output
<input type="text" name="value" value="100.0"/>
100.0
Try using the string literal value for the name attribute instead of resolving it with EL
<spring:bind path="value">
<input type="text" name="value" value="${value}"/>
</spring:bind>
Also, move the field value into a new object. Currently I do not believe the code is using the field in the controller or the getter in the controller.
public class MyForm(){
#NumberFormat(style = Style.CURRENCY)
private Double value = 50.00;
#ModelAttribute("value")
#NumberFormat(style = Style.CURRENCY)
public Double getValue() {
return value;
}
}
Then add the object to the model in the controller:
#RequestMapping(method = RequestMethod.GET)
public ModelAndView loadForm(#ModelAttribute("user") User user) {
ModelAndView instance
modelAndView.addObject("myForm", new MyForm());
return modelAndView;
}
Then access via the jsp:
<spring:bind path="myForm.value">
<input type="text" name="${status.expression}" value="${status.value}"/>
</spring:bind>
<spring:bind path="myForm.value">
${status.value}
</spring:bind>
The major issue at the moment with the code is that it is not using the field/accessor, it is simply placing a value in the model, which does not use any of the annotated fields/methods.
References:
http://www.captaindebug.com/2011/08/using-spring-3-numberformat-annotation.html#.UOAO_3fghvA
How is the Spring MVC spring:bind tag working and what are the meanings of status.expression and status.value?

Resources