Spring Boot, Html button which will add parameters to table in database - java

I want to make a link or another html element which will add parameters to table in MySQL database using JPA and Thymeleaf. I've made a link which have a good url (create a new parameters in table) but after click on this element firefox says : "The address wasn’t understood" but manually entered the same url works. I need that element in index.html which after click will insert into table values. Thank you.
Controller:
#Controller
public class UserController {
#RequestMapping("/")
public String home() {
return "index";
}
#Autowired
private UserDao userDao;
#RequestMapping("/create")
#ResponseBody
public String create(String email, String name) {
String userId="";
try {
User user = new User(email, name);
userDao.save(user);
userId = String.valueOf(user.getId());
}
catch (Exception exception) {
return "Error creating the user" + exception.toString();
}
return "User succesfully created with id = " + userId;
}
index.html :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>HomePage</title>
</head>
<body>
<div id="container">
<a href="localhost:8080/create/email=john10234#gmail.com&name=John">Click to
add: ([id], 'john10234#gmail.com', 'John')
</a>
</div>
</body>
</html>

you missed ? in url
your url will
a href="localhost:8080/create?email=john10234#gmail.com&name=John">
instead of a href="localhost:8080/create/email=john10234#gmail.com&name=John">
Also use #RequestParam
#RequestMapping("/create")
#ResponseBody
public String create(#RequestParam("email")String email, #RequestParam("name")String name)

Related

How to create a custom message/error message in Spring controller and display it in template?

I am trying to create a custom error message in my controller and then pass it into the HTML template if the email is already found in the database.
The controller method does work and it will redirect the user to "registration-form" if a duplicate email is used, but the error message is not displayed on the web page as I intend it to be.
I basically want the error message to appear on the screen when the user cannot register with that email.
In HTML form:
<p th:text="*{errorMessage}"></p>
In Controller:
#PostMapping("/process-register")
private String processRegistrationForm(Model model, WebUser webUser) {
String email = webUser.getEmail();
if(webUserRepo.findByEmail(email) == null) {
webUser.setRole("user");
WebUser savedWebuser = webUserRepo.save(webUser);
model.addAttribute("userID", savedWebuser.getUserID());
String userID = String.valueOf(savedWebuser.getUserID());
return "redirect:/welcome/" + userID;
}
else {
String errorMessage = "This email address is already registered, please login to your existing account.";
model.addAttribute(errorMessage);
return "registration-form";
}
}
}
When your original request is not cached (i.e. is a POST, DELETE, PUT, ... operation) you can respond with any MVC flow, simply be sure to not use the path for "weird" things (neither server nor client side).
Then, if the email exists put the message into the model and redirect to the remember password (or login ...).
So, you can prepare your RememberController to be called from others controllers decoupling internal state and logic:
#Controller
#RequestMapping("/remember")
public class RememberController {
#Getter
#Setter
#AllArgsConstructor
public static class RememberModel {
private String email;
}
// this method decouple the RememberController knowledge (i.e. merge, remove, get messages, ... needed by this view)
public String redirect(Model model, String email) {
model.addAttribute("form", new RememberModel(email));
return get(model);
}
#GetMapping
public String get(Model model) {
if (model.getAttribute("form") == null)
model.addAttribute("form", new RememberModel(""));
return "remember";
}
#PostMapping
public String post(#ModelAttribute(name = "form") RememberModel form, Model model) {
model.addAttribute("info", "password sent to " + form.getEmail() + "!");
return "remember";
}
}
Now, your RegisterController can redirect with any required information (i.e. the error message and the user email to not to rewrite twice):
#Controller
#RequestMapping("/register")
public class RegisterController {
#Getter
#Setter
#AllArgsConstructor
public static class RegisterModel {
private String email;
}
#Autowired
protected RememberController rememberController;
#GetMapping
public String get(Model model) {
if(model.getAttribute("form") == null)
model.addAttribute("form", new RegisterModel(""));
return "register";
}
#PostMapping
public String post(#ModelAttribute(name = "form") RegisterModel form, Model model) {
// ... when email exists ...
model.addAttribute("error", "e-mail `" + form.getEmail() + "` exists!");
return rememberController.redirect(model, form.getEmail());
}
}
Then, the user UI works as expected:
GET
POST and server redirecto to remember controller
Then user simply click:
The views are:
<!doctype html>
<html th:attr="lang=en" xmlns:th="http://www.w3.org/1999/xhtml">
<body>
<h1>REGISTER FORM</h1>
<div style="color: red" th:if="${error != null}" th:text="${error}"></div>
<div style="color: green" th:if="${info != null}" th:text="${info}"></div>
<form method="post" th:object="${form}">
<input th:field="*{email}" type="text"/>
<input type="submit" value="register"/>
</form>
</body>
</html>
and
<!doctype html>
<html th:attr="lang=en" xmlns:th="http://www.w3.org/1999/xhtml">
<body>
<h1>REMEMBER FORM</h1>
<div style="color: red" th:if="${error != null}" th:text="${error}"></div>
<div style="color: green" th:if="${info != null}" th:text="${info}"></div>
<form method="post" th:action="#{/remember}" th:object="${form}">
<input th:field="*{email}" type="text"/>
<input type="submit" value="remember"/>
</form>
</body>
</html>
NOTE: for a better user experience, you can change the url when the remember view is redirected on server using window.history.pushState or so.

How can I have a model attribute persist between redirects?

I am trying to write a password reset function for a website. I am running into an issue that I am using a couple of redirects to transition from postmappings to getmappings and they dont seem to be carrying the attributes they need to with them, namely the user object that I am trying to reset the password form, here is an example of one of my mappings:
#PostMapping("/user/forgot")
public String emailCheck (#RequestParam String email, Model model){
User user = userDao.findByEmail(email);
if (user==null){
model.addAttribute("wrongEmail", true);
return "redirect:/user/forgot";
}
else {
model.addAttribute("user", user);
return "redirect:/verifysecurity";
}
}
And here is the template where I then call the user attribute:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="en">
<head th:replace="fragments/header :: header('Security', '')"></head>
<body>
<div th:replace="fragments/navbar :: navbar"></div>
<h1 th:if="${wrongAnswer}">Answer does not match record on file, please try again</h1>
<h1>Please answer your security question: WHat is your best friends name?</h1>
<form id="passwordForm" th:action="#{/verifysecurity}" th:method="post">
<label for="answer">Answer</label>
<br/>
<input type="text" id="answer" name="answer"/>
<input type="hidden" name="user" id="user" th:value="${user}"/>
<input type="submit" class="btn btn-block btn-primary" value="Request"/>
</form>
</body>
</html>
Then on the next mapping afterwards I get a null pointer exception for the user:
#PostMapping("/verifysecurity")
public String verify (Model model, #RequestParam User user, #RequestParam String answer){
String security = user.getSecurity_question();
if (answer.equals(security)){
model.addAttribute("user", user);
return "redirect:/reset/password";
} else {
model.addAttribute("wrongAnswer", true);
model.addAttribute("user", user);
return "redirect:/verifysecurity";
}
}
How can I fix this, and if model attributes won't work what should I be doing instead?
Use spring RedirectAttributes.addFlashAttribute(), as name suggested it's stored in flashmap which internally uses user session to pass on this data to next redirect, and removes ones data is used.
Example from spring doc:
#RequestMapping(value = "/accounts", method = RequestMethod.POST)
public String handle(Account account, BindingResult result, RedirectAttributes redirectAttrs) {
// Save account ...
redirectAttrs.addFlashAttribute("message", "Account created!");
return "redirect:/accounts/{id}";
}

Thymeleaf with SpringBoot - how to loop model and delete?

I am using SpringBoot with Thymeleaf to build a trivial example to help me learn the two technologies.
I am basing my example on THIS GUIDE
The entity is a Greeting which has an Id and a Content.
I create the Greeting just fine, and I can list all the Greetings I've created.
I then wanted to add a delete option against each Greeting in the list page. When clicking delete, I want the object to be deleted and the list page served up again.
Alas, when I load the list page I get this error:
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'greeting' available as request attribute
Controller and respository objects
#Controller
public class GreetingController {
#Autowired
GreetingRepo gr;
#RequestMapping(value="/greeting/list", method=RequestMethod.GET)
public String greetingsForm(Model model) {
model.addAttribute("greetings", gr.findAll());
return "greeting/list";
}
#RequestMapping(value="/greeting/delete", method=RequestMethod.POST)
public String deleteGreeting(#ModelAttribute("greeting") Greeting greeting) {
gr.delete(greeting);
return "redirect:/greeting/list";
}
}
#RepositoryRestResource
interface GreetingRepo extends JpaRepository<Greeting, Long> {
}
List.html page:
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Getting Started: Handling Form Submission</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<h1>Result</h1>
<div th:each="greeting : ${greetings}">
<p th:text="'id: ' + ${greeting.id}" />
<p th:text="'content: ' + ${greeting.content}" />
<form action="#" th:action="#{/greeting/delete}" th:object="${greeting}" method="post">
<input type="hidden" th:field="*{id}"/>
<input type="hidden" th:field="*{content}"/>
<input type="Submit" value="Delete"/>
</form>
</div>
Add another
Show All
</body>
</html>
Would appreciate a push in the right direction here :-)
I think you miss this line .
model.addAttribute("greeting", new Greeting());
#RequestMapping(value="/greeting/list", method=RequestMethod.GET)
public String greetingsForm(Model model) {
model.addAttribute("greeting", new Greeting());
model.addAttribute("greetings", gr.findAll());
return "greeting/list";
}
you dont have to use a form to delete the greeting you can do it very easily with this approach. hide the id of the greeting within the url. so you dont need to use a form and hidden tags. and annotate the controller method with following approach, to accept incoming id of the greeting.
replace the current form with given html code and replace the delete method in the controller as well.
<a th:href="#{/greeting/{id}/delete(id=${greeting.id})}" th:text="delete"></a>
#RequestMapping(value="/greeting/{id}/delete",method=RequestMethod.GET)
public String deleteGreeting(#PathVariable int id) {
gr.delete(id);
return "redirect:/greeting/list";
}
edit:- since you need the object to be present within the controller
you can use findOne method to fetch the object from the given id.check out the following example.
<a th:href="#{/greeting/{id}/edit(id=${greeting.id})}" th:text="edit"></a>
#RequestMapping(value="/greeting/{id}/edit",method=RequestMethod.GET)
public String Edit(#PathVariable int id){
greeting greetingob = gr.findOne(id);
return "edit";
}

Sending HttpSession from one controller to another in spring mvc

I am redirecting my request from one controller to another, but while doing that I am loosing my session attributes. But I want to use the session only so that I can verify if user is logged in or not. Whole condition is explained below:
Login.jsp
This is the page in which user gives its username and password and the request goes to "LoginController" .
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Login</title>
</head>
<body>
${loginError }
<h1>Login Details</h1>
<form action="${pageContext.request.contextPath }/login" method="post">
<table>
<tr>
<td>Username</td>
<td><input type="text" name="userId" ></td>
</tr>
<tr>
<td>Password</td>
<td><input type="password" name="password" ></td>
</tr>
<tr>
<td><input type="submit" name="Submit" value="Submit"></td>
</tr>
</table>
</form>
</body>
</html>
LoginController.java
As the action was "login" using post method so the request maps to "verifyLogin()" method.
I have checked for the customer name it is coming after calling "loginCustomer()" method of "CustomerService" class.
But when I set it in session attributes and redirect it to url which match up to "HomeController" method I am losing that session attributes their.
#Controller
#RequestMapping(value="/login")
public class LoginController {
#Autowired
private CustomerService customerService;
#RequestMapping(method=RequestMethod.GET)
public String showLoginForm(){
return "login";
}
#RequestMapping(method=RequestMethod.POST)
public String verifyLogin(#RequestParam String userId, #RequestParam String password, HttpSession session, Model model){
Customer customer = customerService.loginCustomer(userId, password);
if(customer==null){
model.addAttribute("loginError", "Username or password is not correct");
return "login";
}
session.addAttribute("loggedInUser", customer);
return "redirect:/";
}
#RequestMapping(value="logout", method=RequestMethod.GET)
public String logoutUser(HttpSession session){
session.removeAttribute("loggedInUser");
return "login";
}
#ExceptionHandler(Exception.class)
public ModelAndView handleException(){
ModelAndView mav = new ModelAndView();
mav.addObject("loginError", "Usrname or password is not correct");
mav.setViewName("login");
return mav;
}
}
HomeController.java
The request mapped to "home()" method. This method is also called when application loads up, and when user logged in correctly then also it is called.
Here in this method I am loosing my session attribute, but I want it in the page were this method maps i.e. home.jsp the return value of this method.
As session attribute is not available in this method so its not available in the home.jsp page also.
Please help.
#Controller
public class HomeController {
#Autowired
private ProductService productService;
#Autowired
private CategoryService categoryService;
#RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Model model) {
List<Product> products = productService.getFeaturedProducts();
List<Category> categories = categoryService.getAllCategories();
model.addAttribute("featuredProduct", products);
model.addAttribute("categories",categories);
return "home";
}
}
I would suggest to go for RedirectAttributes.
redirectAttrs.addFlashAttribute("loggedInUser", customer);
Further reading: -Flash Attribute
My first guess would be that your session Id cookie might get lost between login and next page. (could be because the Web app is configured not to use cookies or the cookie is set for the wrong domain)
To verify check in your browser that:
After successful login the server sets the session cookie for the current host (chrome or Firefox Dev tools can help you here)
And also that your Browser sends the same cookie in the next request for the homepage.
If this does not help please also include the set cookie and the cookie headers in your reply
I've used session with the help plain old HttpServletRequest request and that seemed to serve the purpose for me.
#RequestMapping(method=RequestMethod.POST)
public String verifyLogin(#RequestParam String userId, #RequestParam String password, HttpServletRequest request, Model model){
Customer customer = customerService.loginCustomer(userId, password);
HttpSession session = request.getSession(false);
if (session == null) {
session = request.getSession();
}
if(customer==null){
model.addAttribute("loginError", "Username or password is not correct");
return "login";
}
session.addAttribute("loggedInUser", customer);
return "redirect:/";
}
By this way, you can access the session values through the request object in both your controller and jsp page.

How to display data of objects in JSP

I have stored some user details through a register form into db (hibernate and spring). I want to display the user details of all users in a separate JSP page.Could anyone please tell me how to do that?
Below is my code of controller
#Controller
public class RegisterController {
#Autowired
private UserDao userDao;
#RequestMapping(value = "/registerForm.htm", method = RequestMethod.GET)
public ModelAndView registerPage(ModelMap map) {
User user = new User();
map.addAttribute(user);
return new ModelAndView("registerForm", "command", user);
}
#RequestMapping(value = "/registerProcess.htm", method = RequestMethod.POST)
public ModelAndView registerUser(#ModelAttribute("user") User user, Model model) {
model.addAttribute("userName", user.getUserName());
model.addAttribute("password", user.getPassword());
model.addAttribute("emailId", user.getEmailId());
System.out.println("user is " + user);
System.out.println("userdao is" + userDao);
userDao.saveUser(user);
return new ModelAndView("registerProcess", "user", user);
}
}
code inside userdao
public void saveUser(User user) {
Session session=getSessionFactory().openSession();
Transaction tx;
tx=session.beginTransaction();
session.persist(user);
tx.commit();
}
You should obtain the elements you want to show to user in a GET request. This involves the following steps:
Have a proper URL mapping and view to process the GET.
Obtain the data in the method that will pre process your URL.
Store the data to display to users as request attribute.
Forward to the view (JSP).
In view, display the data from request attributes.
A very simple example based on your current code and assuming the existence of some methods:
#Controller
public class RegisterController {
#Autowired
private UserDao userDao;
#RequestMapping(value="/registerForm.htm",method=RequestMethod.GET)
public ModelAndView registerPage(ModelMap map){
User user=new User();
map.addAttribute(user);
return new ModelAndView("registerForm","command",user);
}
#RequestMapping(value="/registerProcess.htm",method=RequestMethod.POST)
public ModelAndView registerUser(#ModelAttribute("user") User user,Model model){
model.addAttribute("userName", user.getUserName());
model.addAttribute("password", user.getPassword());
model.addAttribute("emailId",user.getEmailId());
System.out.println("user is "+user);
System.out.println("userdao is"+userDao);
userDao.saveUser(user);
return new ModelAndView("registerProcess","user",user);
}
//this is the new method with proper mapping
#RequestMapping(value="/userList.htm", method=RequestMethod.GET)
public ModelAndView registerPage(ModelMap map) {
//this method should retrieve the data for all users
List<User> userList = userDao.getAllUsers();
map.addAttribute("userList", userList);
return new ModelAndView("userList", map);
}
}
Then, in userList.jsp:
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html lang="en">
<head>
<title>User List</title>
</head>
<body>
List of users:
<br />
<table>
<c:forEach items="${userList}" var="user">
<tr>
<td>${user.userName}</user>
</tr>
</c:forEach>
</table>
</body>
</html>
Note that this is a very basic example about how to do this. The code can be heavily improved.
More info:
How to pass parameter to jsp:include via c:set? What are the scopes of the variables in JSP?
How to avoid Java code in JSP files?
Write another method to get all the users and then store the list of retrieved users in your model object then use the JSTL forEach tag in your JSP to display the users, you can use this link to see how the data can be displayed on JSP using JSTL forEach loop: JSP Errors in ForEach Loop

Categories