**Hi everyone. I ran into a problem while developing a web application. The saveEmployee method does not work properly and throws the corresponding error. In the project I use Spring-boot + Thymeleaf. I think there is an error in these two files or a problem in the configuration. But so far I haven't found anything.
**
myRestController.java
#Controller
#RequestMapping("/shop")
public class myRestController {
#Autowired
private EmployeeService employeeService;
#GetMapping("/allEmployees")
public String allEmployees(Model model) {
List<Employee> employees = employeeService.getAllEmployees();
model.addAttribute("employeesList", employees);
return "allEmployees";
}
#GetMapping("/allEmployees/{name}")
public String getEmployeeByName(#PathVariable String name, Model model) {
List<Employee> employees = employeeService.findAllByName(name);
model.addAttribute("employeesList", employees);
return "allEmployees";
}
#GetMapping("/newEmployee")
public String addEmployee(Model model) {
Employee employee = new Employee();
model.addAttribute("employee", employee);
return "addNewEmployee";
}
#RequestMapping()
public String saveEmployee(#ModelAttribute("employee") Employee employee){
employeeService.saveEmployee(employee);
return "index";
}
addNewEmployee.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>Add Employee</h1>
<form th:method="POST" th:action="#{shop/allEmployees}" th:object="${employee}">
<label for="name">Enter name:</label>
<input type="text" th:field="*{name}" id="name"/>
<br/>
<label for="surname">Enter surname:</label>
<input type="text" th:field="*{surname}" id="surname"/>
<br/>
<label for="department">Enter department:</label>
<input type="text" th:field="*{department}" id="department"/>
<br/>
<label for="salary">Enter salary:</label>
<input type="text" th:field="*{salary}" id="salary"/>
<br/>
<input type="submit" value="Create!">
</form>
<br><br>
</body>
</html>
In your myRestController.java, I am not seeing any #PostMapping defined. In addNewEmployee.html, it appears you are attempting to call shop/allEmployees with a POST rather than the GET method. If your intention is to pass a body or form to the shop/allEmployees endpoint, you may want to consider either changing your #GetMapping to a #PostMapping that accepts a #RequestBody or creating an entirely new #PostMapping that accepts a #RequestBody.
Related
I'm new to thymeleaf and couldn't found a way to pass two th:objects in a single HTML form. how can I pass two different entity objects.in this case, my entities are Patient and Doctor. My form is given below.
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="ISO-8859-1">
<link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<title>LOG IN PAGE</title>
</head>
<body>
<div class="container">
<form th:action="#{/loggedProfile}" th:object="${patient,doctor}"
method="get">
<div class="form-group">
<label for="patientEmail">Email address</label> <input type="email"
class="form-control" placeholder="Enter Your email"
th:field="*{eMail}"> <small id="emailHelp"
class="form-text text-muted">We'll never share your email
with anyone else.</small>
</div>
<div class="form-group">
<label for="patientPassword">Password</label> <input type="password"
class="form-control" placeholder="Enter Your Password"
th:field="*{password}">
</div>
<button type="submit" class="btn btn-primary">Login</button>
</form>
</div>
</body>
<div th:insert="Header-Footer/common_header_footer"></div>
</html>
Here is my controller, its raw.
#GetMapping("/logIn")
public String logIn(Model model) {
Patient patient = new Patient();
model.addAttribute("patient", patient);
Doctor doctor = new Doctor();
model.addAttribute("doctor", doctor);
return "UI-Pages/LogIn_Page";
}
#GetMapping("/loggedProfile")
public String loggedProfile(#ModelAttribute Doctor doctor,#ModelAttribute Patient patient,Model model) {
doctor = docRep.findByeMailAndPassword(doctor.geteMail(), doctor.getPassword());
patient = patRep.findByeMailAndPassword(patient.geteMail(), patient.getPassword());
model.addAttribute("doctor", doctor);
model.addAttribute("patient", patient);
return "Profile-Pages/Patient_Profile";
}
Thanks.
You create a new object that contains a Patient and a Doctor.
public class LoginForm {
private Patient patient;
private Doctor doctor;
// getters and setters
}
Then access the fields like this:
<form th:action="#{/loggedProfile}" th:object="${form}"
th:field="*{patient.eMail}"
....
th:field="*{doctor.password}"
</form>
Etc...
It is probably better to use a dedicated Data Transfer Object that maps to the fields in the form data:
public class LoginFormData {
private String email;
private String password;
}
Then transform from the Patient or Doctor entity into LoginFormData and back in your controller.
Side note:
Use th:method="post" in the form with a #PostMapping in the controller if it is the intention to use the form to change data
Having a method findByeMailAndPassword is not something that you should have. Passwords should be in the database in plain text, and it would be strange to try to find a certain user with its plain text password.
I am working on a usecase to upload student details along with his image in spring boot. The entity class looks like
below.
public class Student{
private int rollNo;
private String name;
// few more fields
#Lob
private byte[] picture;
// getters setters
}
JSP file
<!DOCTYPE html>
<html>
<head>
<title>Student Registration</title>
</head>
<body>
<form action="save" method="post" enctype="multipart/form-data">
<input type="text" name="rollNo"/>
<input type="text" name="name"/>
<!-- some more fields -->
<input type="file" name="picture"/>
<input type="submit" value="Registration">
</form>
</body>
</html>
How should i handle the form data in my controller method? In a nutshell how to write controller method to handle both form data and image?
the very basic idea could be as follows
#RestController
public class ImageUploadController {
#RequestMapping(value="/upload", method=RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<Object> uploadFile(#RequestParam(required=true, value="picture") MultipartFile file, #RequestParam(name = "rollNo") String rollNo, #RequestParam(name = "name") String name) {
}
}
How to send data from jsp to controller in spring using form ?
<form:form action="${searchUrl}" method="post">
<div class="form-group">
<label class="control-label"> search by ID </label>
<br>
<input type="text" id="ticketId" placeholder=" Enter ticket ID ">
</div>
</form:form>
Could not able to get ticketId using this method
You need to declare name attribute (name="ticketId") and access the same on the controller. Like below.
JSP:
<input type="text" name="ticketId" id="ticketId" placeholder=" Enter ticket ID">
Controller:
#RequestParam(value = "ticketId", required = false) String ticketId
I hope it is helpful to you, for me it is working fine.
If you want to use spring forms, make sure to follow the below steps :
Step:1.In the spring controller, you should return the bean object like below to respected JSP.
Class User {
private String ticketId;
// setter & getter
}
#RequestMapping(value = "/test", method = RequestMethod.GET)
public String init(Model model) {
model.addAttribute("msg", "Please Enter Your Login Details");
model.addAttribute("loginBean", new User());
return "login";
}
Step:2 add a model attribute and add taglib in the JSP page.
<%#taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<form:form action="${searchUrl}" method="post"
modelAttribute="loginBean">
<div class="form-group">
<label class="control-label"> search by ID </label>
<br>
<form:input type="text" id="ticketId" path = "ticketId"
placeholder=" Enter ticket ID " />
</div>
</form:form>
Step : 3
#RequestMapping(value = "/test", method = RequestMethod.Post)
public String init(Model model,
#ModelAttribute("user") User user,BindingResult
result) {
sout("user"+user);
return "home";
}
My application is not able to bind a form value from an Thymeleaf + HTML based UI to a Spring Boot controller.
I am getting that value as null when I do a System.out.println into the controller.
index.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Getting Started: Serving Web Content</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<body>
<p>Get your greeting here</p>
<form action="/publishMessage" method="post">
<table>
<tr>
<th>CHARGE</th>
</tr>
<tr>
<td>
<textarea th:field="*{messageBody}" name="" cols="90" rows="40">
{
"firstname": "Jose",
"lastname": "Long"
}
</textarea>
</td>
</tr>
<tr>
<td><input type="submit" name="btnSubmit" value="Publish CHARGE message"></td>
</tr>
</table>
</form>
</body>
</html>
PublishMessageController.java
#Controller
public class PublishMessageController {
#PostMapping("/publishMessage")
public String publishMessage(Message message, BindingResult bindingResult, Model model) {
System.out.println("into the publishMessage method..........");
String messageBody = message.getMessageBody();
System.out.println("messageBody: " + messageBody);
return "result";
}
}
Message.java
import lombok.*;
#Data
#Getter
#Setter
#NoArgsConstructor
public class Message {
private String messageBody;
}
Output:
into the publishMessage method..........
messageBody: null
Your message never gets put into the model, so you can't use it as variable in your controller.
Spring model attributes
Handling the command object
BTW: The method shouldn't return "result" but the String of the message body.
Put your messageBody to model where you show your form:
#RequestMapping(value = "/showForm", method=RequestMethod.GET)
public String showForm(Model model) {
...
String messageBody = ...
model.addAttribute("messageBody", messageBody);
...
}
To use this in your view, add th:action and th:object to your form:
<form action="#" th:action="#{/publishMessage}" th:object="${messageBody}" method="post">
...
</form>
Now you're able to use it in your controller method via annotation in the parameters:
#PostMapping("/publishMessage")
public String publishMessage(#ModelAttribute(value="messageBody") String messageBody, BindingResult bindingResult, Model model) {
...
return messageBody;
}
You could do this with the whole message instead of the body, of course.
Based on the above input from SHEIX made some changes and it worked.
ShowFormController.java
#Controller
public class ShowFormController {
#RequestMapping(value = "/showForm", method = RequestMethod.GET)
public String showForm(Model model) {
model.addAttribute("message", new Message());
return "show";
}
}
show.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Getting Started: Serving Web Content</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<h3>
Go Back
</h3>
<form action="#" th:action="#{/publishMessage}" th:object="${message}" method="post">
<table>
<tr>
<th>CHARGE</th>
</tr>
<tr>
<td>
<textarea th:field="*{messageBody}" name="" cols="90" rows="40" style="background-color: beige">
</textarea>
</td>
</tr>
<tr>
<td><input type="submit" name="btnSubmit" value="Publish CHARGE message"></td>
</tr>
</table>
</form>
</body>
</html>
Message.java
import lombok.*;
#Data
#Getter
#Setter
#NoArgsConstructor
public class Message {
private String messageBody = "{\n" +
"\t\t\t\t\t\t\"name\": \"John\"\n" +
" }";
}
PublishMessageController.java
#PostMapping("/publishMessage")
public String publishMessage(#ModelAttribute(value = "messageBody") String messageBody, BindingResult bindingResult, Model model) {
System.out.println("into the publishMessage method..........");
System.out.println("messageBody: " + messageBody);
return "result";
result.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Getting Started: Serving Web Content</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<h3>
Thanks !!!
Go Back
</h3>
</body>
</html>
I am new to Spring and yesterday I created a simple app. I type book's title, author and genre and it saves it to List<Book>. Book.java contains private fields (title, author, genre).
So creating books and saving them to list works fine. Also I can view all books I have added. So it works fine. But now I want to create and delete them. So I have BookService.java that can add and delete books.
BookService.java
private List<Book> allBooks = new ArrayList<>();
public List<Book> getAllBooks() {
return allBooks;
}
public void addBook(String title, String author, String genre) {
allBooks.add(new Book(title, author, genre));
}
public void deleteBook(Book book) {
allBooks.remove(book);
}
This is stuff in my controller to delete books
#GetMapping("/books/delete")
public String deleteBook(Model model) {
model.addAttribute("BookList", bookService.getAllBooks()); // Works fine
return "delete";
}
#PostMapping("/books/delete")
public String deletedBook(#ModelAttribute Book book, Model model) {
System.out.println(book.getTitle()); // null
bookService.deleteBook(book); // can't delete null so nothing happens to the list
model.addAttribute("deletedBook", book);
return "deletedBookResult";
}
delete.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>Title</title>
</head>
<body>
<h2>Delete page</h2>
<div th:each="bookObj : ${BookList}"> <!-- BookList - all books I add using submit form -->
<form action="#" th:action="#{/books/delete}" th:object="${bookObj}" method="post"> <!-- I SEND bookObj -->
<input type="submit" th:value="${bookObj.title}"/> <!-- WORKS. I GET BOOK'S NAME ON THIS BUTTON-->
</form>
</div>
</body>
</html>
I use th:each="bookObj : ${BookList}". So bookObj is every book I add. That's why I use th:object=${bookObj}. There is a form for each book I added later. And it display's it's title on the button. But when I press it, I get null to IDEA's console and on webpage. Why?
Thank you in advance.
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>Title</title>
</head>
<body>
<h2 th:text=" 'You have just deleted' + ${deletedBook.title}"></h2>
<!-- You have just deleted null -->
</body>
</html>
You are not sending anything in your form. Add some hidden fields:
<div th:each="bookObj : ${BookList}">
<form action="#" th:action="#{/books/delete}" method="post">
<input type="hidden" th:name="genre" th:value="${bookObj.genre}"/>
<input type="hidden" th:name="author" th:value="${bookObj.author}"/>
<input type="hidden" th:name="title" th:value="${bookObj.title}"/>
<input type="submit" th:value="${bookObj.title}"/>
</form>
</div>
Or if you don't want to expose your data in html, you can try to use some sort of session objects instead (Probably an overkill, but sometimes can be useful):
#GetMapping("/books/delete")
public String deleteBook(Model model, HttpSession session) {
session.setAttribute("BookList", new Book[]{
new Book("Title", "Tom","genre"),
new Book("Title 2", "Jerry","genre2")}
);
return "delete";
}
#PostMapping("/books/delete")
public String deletedBook(HttpSession session, Integer id, Model model) {
Book[] books = (Book[]) session.getAttribute("BookList");
Book book = books[id];
System.out.println(book);
model.addAttribute("deletedBook", book);
return "deletedBookResult";
}
And use it like:
<div th:each="bookObj, iter : ${session.BookList}">
<form action="#" th:action="#{/books/delete}" method="post">
<input type="hidden" th:name="id" th:value="${iter.index}"/>
<input type="submit" th:value="${bookObj.title}"/>
</form>
</div>