Model attributes in Thymleaf and Spring boot - java

I'm wondering how I can receive the object from frontend(Thymeleaf) using #ModelAttribute. Main purpose of this is to edit object in the new view(html) where the fields are filled updated object therefore the invoice object is passed to model for further editing.
I tried to do that.
Model
public class Invoice {
private Long id;
private BigDecimal price;
#DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate date;
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
public LocalDate getDate() {
return date;
}
public void setDate(LocalDate date) {
this.date = date;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
#GetMapping("/edit")
public String editInvoice(Model model, #ModelAttribute Invoice invoice){
model.addAttribute("updatedInvoice", invoice);
return "edit";
}
<tr th:each="invoice:${allInvoices}">
<td th:text="${invoice.id}"></td>
<td th:text="${invoice.price}"></td>
<td th:text="${invoice.date}"></td>
<td th:text="${invoice.name}"></td>
<td><a th:href="#{/delete(id=${invoice.id})}" class="btn btn-danger">DELETE</a></td>
<td><a th:href="#{/edit(invoice=${invoice})}" class="btn btn-primary">EDIT</a></td>
</tr>
Finally I see that the invoice object has allocated memory but it is empty(I mean its variables)
When I printout the invoice object I get this: main.domain.model.Invoice#37567a3b it is not null but object has empty variables.
Thank you in advance for support and help.
Main purpose of this is to edit object in the new view(html) where the fields are filled updated object therefore the invoice object is passed to model for further editing.

Related

Add data to a related table Spring Hibernate [duplicate]

I have table employee and table employee_detail, I can add data to non related table(employee), controller work fine, everything is okey, but I cant implement code so I can store data to related table employee_detail
Employee:
#Entity
#Table(name="employee")
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "employeeId")
private int id;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
#Column(name = "email")
private String email;
#OneToOne(mappedBy = "employee")
private EmployeeDetail employeeDetail;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public EmployeeDetail getEmployeeDetail() {
return employeeDetail;
}
public void setEmployeeDetail(EmployeeDetail employeeDetail) {
this.employeeDetail = employeeDetail;
}
}
EmployeeDetail:
#Entity
#Table(name = "employee_detail")
public class EmployeeDetail {
#Id
#GeneratedValue(strategy= GenerationType.AUTO)
#Column(name="employee_detail_id")
private int id;
#Column(name="work_experience")
private int workExperience;
#Column(name="hobby")
private String hobby;
#Column(name="nationality")
private String nationality;
#OneToOne
#JoinColumn(name="employeeId")
private Employee employee;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getWorkExperience() {
return workExperience;
}
public void setWorkExperience(int workExperience) {
this.workExperience = workExperience;
}
public String getHobby() {
return hobby;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
public String getNationality() {
return nationality;
}
public void setNationality(String nationality) {
this.nationality = nationality;
}
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
}
This is how I store data to employee table:
`EmployeeController:`
#Controller
#RequestMapping("/employee")
public class EmployeeController {
#Autowired
private EmployeeService employeeService;
#GetMapping("/list")
public String listEmployee(Model theModel) {
// get customers from the service
List<Employee> theEmployee = employeeService.listEmployee();
// add the customers to the model
theModel.addAttribute("employees", theEmployee);
return "list-employee";
}
#GetMapping("/showFormForAdd")
public String showFormForAdd(Model theModel) {
// create model attribute to bind form data
Employee theEmployee = new Employee();
theModel.addAttribute("employee", theEmployee);
return "addNewEmployeeForm";
}
#PostMapping("/addNewEmployee")
public String addNewEmployee(#ModelAttribute("employee") Employee theEmployee) {
// save the customer using our service
employeeService.addNewEmployee(theEmployee);
return "redirect:/employee/list";
}
}
And form addNewEmployeeForm:
<form:form action="addNewEmployee" modelAttribute="employee" method="POST">
<table>
<tbody>
<tr>
<td><label>First name:</label></td>
<td><form:input path="firstName" /></td>
</tr>
<tr>
<td><label>Last name:</label></td>
<td><form:input path="lastName" /></td>
</tr>
<tr>
<td><label>Email:</label></td>
<td><form:input path="email" /></td>
</tr>
<tr>
<td><label></label></td>
<td><input type="submit" value="Save" class="save" /></td>
</tr>
</tbody>
</table>
How to store data into table from related table? What m I missing?
I tried like this but doesnt work:
#Controller
#RequestMapping("/employeeDetail")
public class EmployeeDetailController {
#Autowired
private EmployeeDetailService employeeDetailService;
#GetMapping("/listEmployeeDetail")
public String listEmployeeDetail(Model theModel) {
// get customers from the service
List<EmployeeDetail> theEmployeeDetail = employeeDetailService.listEmployeeDetail();
// add the customers to the model
theModel.addAttribute("employeeDetails", theEmployeeDetail);
return "list-employeeDetail";
}
#GetMapping("/showFormForAddEmployeeDetail")
public String showFormForAddEmployeeDetail(Model theModel) {
// create model attribute to bind form data
EmployeeDetail theEmployeeDetail = new EmployeeDetail();
theModel.addAttribute("employeeDetail", theEmployeeDetail);
return "addNewEmployeeDetailForm";
}
#PostMapping("/addNewEmployeeDetail")
public String addNewEmployeeDetail(#ModelAttribute("employeeDetail") EmployeeDetail theEmployeeDetail) {
// save the customer using our service
employeeDetailService.addNewEmployeeDetail(theEmployeeDetail);
return "redirect:/employeeDetail/listEmployeeDetail";
}
}
Requested code:
#Override
#Transactional
public void addNewEmployeeDetail(EmployeeDetail theEmployeeDetail) {
employeeDetailDAO.addNewEmployeeDetail(theEmployeeDetail);
}
Assuming your are not actively saving the EmployeeDetail entities on your own and only saving Employee, then configure cascade attribute on #OneToOne relationship on Employee side as follows:
#OneToOne(mappedBy = "employee", cascade = CascadeType.ALL)
private EmployeeDetail employeeDetail;
With this, you are telling your EntityManager to propagate (cascade) all operations (PERSIST, REMOVE, REFRESH, MERGE, DETACH) to the relating entities.
In addition to the change above, I would also recommend you moving to JPA instead of handling Hibernate Sessions on your own.
Include the Spring Boot JPA dependency in your pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
Create two repositories, one for each entity and inject them into the corresponding Service (just like you are doing with your DAOs):
public interface EmployeeDAO extends JpaRepository<Employee, Integer> {
}
public interface EmployeeDetailDAO extends JpaRepository<EmployeeDetail, Integer> {
}
Now in your Services, you can call a couple of default methods on these Repositories such as findAll() or save(). In your case you would do something like the following:
#Override
#Transactional
public void addNewEmployee(Employee theEmployee) {
employeeDAO.save(theEmployee);
}
You can check more details at https://www.baeldung.com/the-persistence-layer-with-spring-and-jpa and https://www.baeldung.com/spring-data-repositories.
Keep in mind that you will have a hard time saving EmployeeDetail directly as you receive it from your form. The reason being that you need to set Employee attribute, otherwise the foreign key in the column employeeId would be set and thus you will get a SQL error.

Passing mapped object through form:select tags

I keep getting 400 Bad Request error whenever im trying to pass an entire object through form:select.
HTTP Status 400 – Bad Request
Type Status Report
Description The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing).
This is my select form:
<html>
<head>
<title>Dodaj produkt do aukcji</title>
</head>
<body>
<form:form action="saveProduct${auction.id}" modelAttribute="newProduct" method="POST">
<label>Nazwa:</label> <form:input path="name"/><br>
<label>Cena:</label> <form:input path="price"/><br>
<label>Kategoria:</label>
<form:select path="productCategory">
<form:options items="${productCategories}" itemLabel="name"/>
</form:select><br>
<input type="submit" value="Dodaj" class="save"/><br>
</form:form>
</body>
</html>
Controller:
#GetMapping("/addProductPage")
public String addProductPage(#RequestParam("auctionId") int id,Model theModel) {
Collection <ProductCategory> pCategories = productCategoryService.getProductCategories();
Auction auction = auctionService.getAuction(id);
Product product = new Product();
ProductCategory pCategory = new ProductCategory();
theModel.addAttribute("auction", auction);
theModel.addAttribute("newProduct", product);
theModel.addAttribute("productCategories", pCategories);
return "add-product";
}
#PostMapping("/saveProduct{someId}")
public String saveProduct(#ModelAttribute("newProduct") Product product, #PathVariable(value="someId") String someId) {
Auction auction = auctionService.getAuction(Integer.parseInt(someId));
Collection<Product> products = auction.getProducts();
products.add(product);
auction.setProducts(products);
product.setAuction(auction);
auctionService.saveAuction(auction);
productService.saveProduct(product);
return "redirect:/showMyAuctions";
}
Product entity:
#Entity
#Table(name="product")
public class Product {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="product_id")
private int id;
#Column(name="name")
private String name;
#Column(name="price")
private float price;
#ManyToOne
#JoinColumn(name="category_id")
private ProductCategory productCategory;
#ManyToOne
#JoinColumn(name="auction_id")
private Auction auction;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
public ProductCategory getProductCategory() {
return productCategory;
}
public void setProductCategory(ProductCategory productCategory) {
this.productCategory = productCategory;
}
public Auction getAuction() {
return auction;
}
public void setAuction(Auction auction) {
this.auction = auction;
}
#Override
public String toString() {
return "Product [id=" + id + ", name=" + name + ", price=" + price + ", productCategory=" + productCategory
+ "]";
}
}
Product category entity:
#Entity
#Table(name="product_category")
public class ProductCategory {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="category_id")
private int id;
#Column(name="name")
private String name;
#OneToMany(mappedBy="productCategory", cascade=CascadeType.ALL, fetch=FetchType.EAGER)
Collection<Product> products;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Collection<Product> getProducts() {
return products;
}
public void setProducts(Collection<Product> products) {
this.products = products;
}
#Override
public String toString() {
return "ProductCategory [id=" + id + ", name=" + name + "]";
}
}
What i want is the chosen product category to be added to the product.
Spring expect productCategory to be an object but it's name of productCategory as specified in tag.
you need to try something like:
<form:select path="productCategory.name">
<form:options items="${productCategories}" itemLabel="name" itemValue= "name"/>
</form:select>

thymeleaf spring th attribute nested loop

This webapp is made with spring boot connected to MariaDB .I would like to view the items in each category, I can see the category attributes and can see the item in the view as such [Item [id=1, title=test, description=11, status=Used, zipcode=1231, price=111.0, category=Category [id=3, type=Services]]]
heres my controller
#RequestMapping(value="/item-by-category/{id}",method= RequestMethod.GET)
public String itemByCategory(#PathVariable("id") Long categoryid, Model model){
//model.addAttribute("items",irepository.findByCategory(categoryid));
model.addAttribute("categorys",crepository.findOne(categoryid));
//model.addAttribute("item",irepository.findByCategory(categoryid));
return "/item-by-category";
}
Im using CRUD repositories so I tried to use the itemRepository method to filter the items by category but I get an error on the type of attribute passed even if its of type Long as stated in the class initiation.
Repositories:
public interface ItemRepository extends CrudRepository<Item, Long> {
List<Item> findByTitle(String title);
List<Item> findByCategory(Long categoryid);
}
public interface CategoryRepository extends CrudRepository<Category, Long> {
//find by cat type
List<Category> findByType(String type);
//List<Category>findByItem(String item);
//Item findByCategory(String type);
//show the items in the categories
//List<Item>items(String type);
//List<Category>findByItem(String item);
}
classes :
#Entity
#Table(name="category")
public class Category {
//#id creates an ID column for the table
#Id
//Generates automatically a unique PK for every new entity object
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="categoryid")
private Long id;
#Column(name="type")
private String type;
// 1 Category can have * Items
#OneToMany(cascade = CascadeType.ALL, mappedBy = "category")
private List<Item> item;
//constructor
public Category() {}
public Category(String type) {
super();
this.type = type;
}
//getters n setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
//getters n setters for relationship
public List<Item> getItems() {
return item;
}
public void setItems(List<Item> item) {
this.item = item;
}
#Override
public String toString() {
return "Category [id=" + id + ", type=" + type + "]";
}
}
#Entity
#Table(name="item")
public class Item {
//generated ID column
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="itemid")
private Long id;
#Column(name="title")
private String title;
#Column(name="description")
private String description;
#Column(name="status")
private String status;
#Column(name="zipcode",length=5)
private Integer zipcode;
#Column(name="price")
private Double price;
//create relationship or * to 1 between items to user
/*
#ManyToOne
#JsonIgnore
#JoinColumn(name = "userid")
private User user;
*/
//Many items can have 1 category * to 1
#ManyToOne
/*entity relationship will
cause endless loop (First item is serialized and it contains
category which is then serialized which contains students which
are then serialized
*/
#JsonIgnore
#JoinColumn(name = "categoryid")
private Category category;
//working ^^
//JPA constructor
public Item(){
}
public Item(Long id, String title, String description, String status, Integer zipcode, Double price,
Category category) {
super();
this.id = id;
this.title = title;
this.description = description;
this.status = status;
this.zipcode = zipcode;
this.price = price;
this.category = category;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public Integer getZipcode() {
return zipcode;
}
public void setZipcode(Integer zipcode) {
this.zipcode = zipcode;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
#Override
public String toString() {
return "Item [id=" + id + ", title=" + title + ", description=" + description + ", status=" + status
+ ", zipcode=" + zipcode + ", price=" + price + ", category=" + category + "]";
}
}
so tried taking the category and got it working so far like this:
<table class="table table-striped">
<tr th:each ="category : ${categorys}">
<td th:text="${category.id}" ></td>
<td th:text="${category.items}" ></td>
//shows the size of the array
<td th:text="${category.items.size()}" ></td>
</tr>
<!-- this is what I want as the result, I would like to know how to loop with the TH attribute
<tr>
<td th:text="${category.items[0].title}"></td>
<td th:text="${category.items[0].category.type}"></td>
<td th:text="${category.items[0].description}"></td>
<td th:text="${category.items[0].status}"></td>
<td th:text="${category.items[0].zipcode}"></td>
<td th:text="${category.items[0].price}"></td>
</tr>
-->
This is my first web app using Spring mvc, at this point I am a bit stuck and would appreciate it if someone pointed me towards the right path thank you :D
To achieve a nested loop in Thymeleaf, simply do the following:
<th:block th:each="category : ${categorys}">
<tr th:each="item : ${category.items}">
<td th:text="${category.item.title}"></td>
<td th:text="${category.item.category.type}"></td>
<td th:text="${category.item.description}"></td>
<td th:text="${category.item.status}"></td>
<td th:text="${category.item.zipcode}"></td>
<td th:text="${category.item.price}"></td>
</tr>
</th:block>
I was able to achieve the result asked without the nested loops. by changing the parameter type to Category which is the attribute type in the entity class.
Repository:
List<Item> findByCategory(Category categoryid);
Controller :
#RequestMapping(value="/item-by-category/{id}",method= RequestMethod.GET)
public String itemByCategory(#PathVariable("id") Category categoryid, Model model){
model.addAttribute("items",irepository.findByCategory(categoryid));
return "/itemlist";
}

Hibernate selecting strings and not objects

I'm new to the Hibernate world, and I have a problem that I couldn't solve myself. And please be nice.
What I have :
Netbeans IDE 8.0.2
Mysql database (easyPHP) with some tables
What I want :
Select categories (table) which has 3 records with id,name, and description and show them (name and description) in jsp using EL.
My Category Class:
public class Category implements java.io.Serializable {
private Integer id;
private String name;
private String description;
public Category() {
}
public Category(String name, String description) {
this.name = name;
this.description = description;
}
public Category(String name, String description) {
this.name = name;
this.description = description;
}
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return this.description;
}
public void setDescription(String description) {
this.description = description;
}
}
My getCategories method :
public static List getAllCategories(){
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
Transaction tx = session.beginTransaction();
List results = session.createCriteria(Category.class, "category")
.list();
tx.commit();
return results;
}
My Controller:
List categories = CategoriesManagement.getAllCategories();
map.addAttribute("categories", categories);
My view (jsp):
<c:forEach var="cat" items="${categories} ">
${cat.name}
</c:forEach>
I'm getting nothing.
And when I show ${cat.class} it says :
java.lang.String
java.lang.String
java.lang.String
And when I show ${cat} it says :
com.company.Category#7136faa
com.company.Category#25636faa
com.company.Category#83baeaa
Update :
When I redefine toString() method in Category like this :
public toString(){
return "foo";
}
I get :
[foo
foo
foo]
Thanks in advance.
Use this: <c:out value="${cat.name}" />
I know it's wierd and after 9 hours I found that the space in
<c:forEach var="cat" items="${categories} "> was the error,
I should do as :
<c:forEach var="cat" items="${categories}">

javax.el.PropertyNotFoundException:

I am working on Spring. I am unable to display the list items in JSP. It says: Property not found on type java.lang.String.
I have a POJO class Student:
public class Student {
private Integer age;
private String name;
private Integer id;
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getId() {
return id;
}
}
In my controller class I fetch list of students and assign it to a List and add the list to the model attribute. Which is as follows.
#RequestMapping("/getstuds")
public String getstudents(#ModelAttribute Student student, ModelMap model){
StudentDAO studentDAO = (StudentJDBCTemplate)applicationContext.getBean("studentJDBCTemplate");
List<Student> students = studentDAO.listStudents();
model.addAttribute("studlist",students);
System.out.println(students.iterator().next().getName());
return "showstuds";
}
showstuds.jsp
<table>
<c:forEach var="stud" items="${studlist} }">
<tr><td>${stud.Name}</td></tr>
</c:forEach>
</table>
I get the following exception:
javax.el.PropertyNotFoundException: Property 'Name' not found on type com.spring.mvc.Student
your variable name is name not Name
<tr><td>${stud.name}</td></tr>
instead of
<tr><td>${stud.Name}</td></tr>
And also remove the brace
items="${studlist}"
instead of
items="${studlist} }"

Categories

Resources