Spring MVC + Hibernate Cannot get item property - spring

I,m stuck. I have a problem with output of data. I try to make some kind of order-product project. My Entities are following:
#Entity
#Table(name = "sales")
public class Sale implements Serializable {
public Sale() {
}
#Id
#Column
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Column(insertable = false, updatable = false)
private Timestamp date;
#OneToMany(fetch = FetchType.EAGER, mappedBy = "sale")
private List<OrderItem> items = new ArrayList<OrderItem>();
#Column
private double cost;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Timestamp getDate() {
return date;
}
public void setDate(Timestamp date) {
this.date = date;
}
public List<OrderItem> getItems() {
return items;
}
public void setItems(List<OrderItem> items) {
this.items = items;
}
public double getCost() {
return cost;
}
public void setCost(double cost) {
for(OrderItem item : items)
cost += item.getProduct().getPrice() * item.getQuantity();
this.cost = cost;
}
}
#Entity
#Table(name = "products")
public class Product implements Serializable {
public Product() {
}
#Id
#Column
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Column
private String name;
#Column
private double price;
#OneToMany(fetch = FetchType.EAGER, mappedBy = "product")
private Set<OrderItem> items = new HashSet<OrderItem>();
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 double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public Set<OrderItem> getItems() {
return items;
}
public void setItems(Set<OrderItem> items) {
this.items = items;
}
public boolean isNew() {
return this.id == 0;
}
}
#Entity
#Table(name = "order_items")
public class OrderItem implements Serializable {
#Id
#GeneratedValue
#Column(name = "id")
private Long id;
#Column
private int quantity;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "product_id")
private Product product;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "sale_id")
private Sale sale;
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
}
SQL tables create like this:
CREATE TABLE products (
id SERIAL PRIMARY KEY NOT NULL,
name CHARACTER(50) NOT NULL,
price REAL NOT NULL
)
WITH ( OIDS = FALSE );
CREATE TABLE sales (
id SERIAL PRIMARY KEY NOT NULL,
cost REAL NOT NULL,
date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
)
WITH ( OIDS = FALSE );
CREATE TABLE order_items (
id SERIAL NOT NULL,
sale_id INTEGER NOT NULL,
product_id INTEGER,
quantity INTEGER NOT NULL,
primary key (sale_id, id)
)
WITH ( OIDS = FALSE );
ALTER TABLE order_items
ADD CONSTRAINT order_itemsFK0 FOREIGN KEY (product_id) REFERENCES products(id);
ALTER TABLE order_items
ADD CONSTRAINT order_itemsFK1 FOREIGN KEY (sale_id) REFERENCES sales(id);
My sale form:
<form:hidden path="id" />
<spring:bind path="items">
<div class="form-group ${status.error ? 'has-error' : ''}">
<label class="col-sm-2 control-label">Product</label>
<div class="col-sm-5">
<form:select path="items" class="form-control">
<form:options items="${productMap}" />
</form:select>
<form:errors path="items" class="control-label" />
</div>
<div class="col-sm-5"></div>
</div>
</spring:bind>
<spring:bind path="items">
<div class="form-group ${status.error ? 'has-error' : ''}">
<label class="col-sm-2 control-label">Quantity</label>
<div class="col-sm-10">
<form:radiobuttons path="items" items="${numberList}" element="label class='radio-inline'" />
<br />
<form:errors path="items" class="control-label" />
</div>
</div>
</spring:bind>
<spring:bind path="cost">
<div class="form-group ${status.error ? 'has-error' : ''}">
<label class="col-sm-2 control-label">Cost</label>
<div class="col-sm-10">
<form:input path="cost" type="text" class="form-control" id="cost"
placeholder="Cost" />
<form:errors path="cost" class="control-label" />
</div>
</div>
</spring:bind>
And i have problems on form where I try to add sale. Items is incorrect, doesn`t save. i write jsp code wrong but i have no idea how to get it right. Need help, please!

Do you have some log? make sure that your post is arriving to the server side.

Solved. I remade some stuff in the project, in jsp part. Add additive page and everything works good.

Related

Thymeleaf access object in outerloop from innerloop

i am looping through a list of "roles" , inside each one i loop through a list of "notifications" ( a role can have many notifications )
<div class="row justify-content-center">
<div class="col-sm-3" th:each="role : ${roles}">
<div class="card">
<div class="card-body">
<h5 class="card-title" th:text="${role.name}"></h5>
Notifications :
<div class="input-group mb-3">
<th:block th:each="notif : ${notif_list}">
<div class="custom-control custom-control-inline">
<input type="checkbox" class="custom-control-input"
th:id="${notif.id_notif_type}"
th:value="${notif.id_notif_type}" th:field="${role.notifs}">
<label class="custom-control-label" th:text="${notif.type}"
th:for="${notif.id_notif_type}"></label>
</div>
</th:block>
</div>
</div>
</div>
</div>
</div>
i want access an object "role" inside the notification loop by using th:field="${role.notifs}
here is my Role class :
#Entity
#Table(name = "roles")
#Transactional
public class Role implements Serializable{
public Role() {
}
public Role(Integer id, String name) {
super();
this.id = id;
this.name = name;
}
#Id
#Column(name = "role_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
#ManyToMany(cascade = CascadeType.MERGE, fetch = FetchType.EAGER)
#JoinTable(name = "roles_notifs", joinColumns = #JoinColumn(name = "role_id"), inverseJoinColumns = #JoinColumn(name = "notif_id"))
private Set<NotifType> notifs = new HashSet<>();
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<NotifType> getNotifs() {
return notifs;
}
public void setNotifs(Set<NotifType> notifs) {
this.notifs = notifs;
}
public void addNotif(NotifType notif) {
notifs.add(notif);
}
public void removeNotif(NotifType notif) {
notifs.remove(notif);
}
#Override
public String toString() {
return name;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Role other = (Role) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
i got an error on ${role.notifs} , so how can i access the outer object "role" from the inner loop.
i got this error Neither BindingResult nor plain target object for bean name 'role' available as request attribute

How to save the image file associated with user in springboot, thymeleaf

I am trying to save the image file and the item details to mysql database, However i got an
error.
I am using thymeleaf for the front end.
Here is my item upload form:
#GetMapping("/itemUploadForm")
public String itemUploadForm(Model theModel) {
Item theItem = new Item();
theModel.addAttribute("item", theItem);
return "fileUploadForm";
}
This part is to process the image and the item details once taken from the user.
#PostMapping("/itemUploadProcess")
public String itemUploadProcess(#ModelAttribute("item") Item theItem,#RequestParam("imagefile") MultipartFile imageFile) throws Exception {
String folder = "/photos";
byte[] bytes = imageFile.getBytes();
Path path = Paths.get(folder + imageFile.getOriginalFilename());
Files.write(path, bytes);
itemService.save(theItem);
return "redirect:/";
}
This is a class item.
I dont know if the problem is in this properties or in mysql.
I have mysql column for file set as imagefile blob not null;
package com.rentyou.projectdemo.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.Table;
import org.springframework.web.multipart.MultipartFile;
#Entity
#Table(name = "item")
public class Item {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
public int id;
#Column(name = "name")
public String name;
#Column(name = "description")
public String description;
#Column(name = "conditiontype")
public String type;
#Column(name = "price")
public String price;
#Column(name = "contact")
public String contact;
#Column(name = "itemimage")
public MultipartFile itemImage;
public Item() {
}
public Item(String name, String description, String type, String price, String contact, MultipartFile itemImage) {
this.name = name;
this.description = description;
this.type = type;
this.price = price;
this.contact = contact;
this.itemImage = itemImage;
}
public Item(int id, String name, String description, String type, String price, String contact,
MultipartFile itemImage) {
this.id = id;
this.name = name;
this.description = description;
this.type = type;
this.price = price;
this.contact = contact;
this.itemImage = itemImage;
}
public MultipartFile getItemImage() {
return itemImage;
}
public void setItemImage(MultipartFile itemImage) {
this.itemImage = itemImage;
}
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 String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
public String getContact() {
return contact;
}
public void setContact(String contact) {
this.contact = contact;
}
}
This part is the form to take image file and the item details:
<form th:action="#{/itemUploadProcess}"
th:object="${item}" method="POST" enctype="multipart/form-data">
<input type="text" th:field="*{name}"
class="form-control mb-4 col-4" placeholder="Name">
<input type="text" th:field="*{description}"
class="form-control mb-4 col-4" placeholder="Description">
<input type="text" th:field="*{type}"
class="form-control mb-4 col-4" placeholder="Condition">
<input type="text" th:field="*{price}"
class="form-control mb-4 col-4" placeholder="Price">
<input type="text" th:field="*{contact}"
class="form-control mb-4 col-4" placeholder="Contact">
<input type="file" th:field="*{itemImage}" class="form-control mb-4 col-4" placeholder="Contact" name="imagefile">
<button type="submit" class="btn btns-info col-2">Save</button>
</form>
Remove that attribute name="imagefile" from your form. Its giving the file the wrong name. The th:field attribute will supply the correct name attribute.

When update Employee table then why new row inserted in Address table. I want simple update Address table also

Note: When update Employee why new row inserted in Address table. I want to update Employee and want to update Address table also rather than new row inserted.
After execute following:
session=sessionFactory.getCurrentSession();
session.update(employee);
Result:
Hibernate: insert into Address (address, employee_empId, mobile, pincode) values (?, ?, ?, ?)
Hibernate: update Employee set addId=?, empName=?, empProfile=? where empId=?
#Entity
#Table(name = "Address")
public class Address {
#Id
#Column(name = "addId", unique = true, nullable = false)
#GeneratedValue(strategy = GenerationType.IDENTITY)
int addId;
#Column(name = "pincode", unique = false, nullable = false, length = 100)
int pincode;
#Column(name = "address", unique = false, nullable = false, length = 100)
String address;
#Column(name = "mobile", unique = false, nullable = false, length = 100)
String mobile;
#OneToOne
private Employee employee;
public int getAddId() {
return addId;
}
public void setAddId(int addId) {
this.addId = addId;
}
public int getPincode() {
return pincode;
}
public void setPincode(int pincode) {
this.pincode = pincode;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
}
#Entity
#Table(name = "Employee")
public class Employee {
#Id
#Column(name = "empId", unique = true, nullable = false)
#GeneratedValue(strategy = GenerationType.IDENTITY)
int empId;
#Column(name = "empName", unique = false, nullable = false, length = 100)
String empName;
#Column(name = "empProfile", unique = false, nullable = false, length = 100)
String empProfile;
#OneToOne(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
#JoinColumn(name="addId")
Address address;
public int getEmpId() {
return empId;
}
public void setEmpId(int empId) {
this.empId = empId;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public String getEmpProfile() {
return empProfile;
}
public void setEmpProfile(String empProfile) {
this.empProfile = empProfile;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
<form:form cssClass="form-horizontal" method="POST" action="${pageContext.request.contextPath}/editEmployee" modelAttribute="employee">
<input type="hidden" value="${employeeDetail.empId}" name="empId">
<div class="form-group">
<label for="email">Employee Name:</label>
<input type="text" class="form-control" name="empName" value="${employeeDetail.empName}">
</div>
<div class="form-group">
<label for="pwd">Profile:</label>
<textarea rows="5" class="form-control" name="empProfile">${employeeDetail.empProfile}</textarea>
</div>
<div class="form-group">
<label for="pwd">Pincode:</label>
<input type="text" class="form-control" name="address.pincode" value="${employeeDetail.address.pincode}">
</div>
<div class="form-group">
<label for="pwd">Address:</label>
<textarea rows="5" class="form-control" name="address.address">${employeeDetail.address.address}</textarea>
</div>
<div class="form-group">
<label for="pwd">Mobile No:</label>
<input type="text" class="form-control" name="address.mobile" value="${employeeDetail.address.mobile}">
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">Update</button>
</div>
</form:form>
After execute following:
session=sessionFactory.getCurrentSession();
session.update(employee);
Result:
Hibernate: insert into Address (address, employee_empId, mobile, pincode) values (?, ?, ?, ?)
Hibernate: update Employee set addId=?, empName=?, empProfile=? where empId=?
Note: When update Employee why new row inserted in Address table. I want to update Employee and want to update Address table also rather than new row inserted.

Thymeleaf #sets.contains() always returning false despite usage according to documentation

Preface
I have a spring boot application with a User entity with a set of Role.
On the edit user template, I am displaying the user's roles with a <select>multiple. When rending the view of a existing User with its set of Role, I am trying to only mark as selected the roles within the set.
Thymeleaf provides two tools for this:
th:selected: Which expects a boolean value (true being selected)
#sets: Which provides a handful of useful methods similar to java.util.Set, the one being used in this case is contains().
The problem
When adding to the model a found User and all the possibles Role in the form of a HashSet, using #sets.contains() always return false when using the found user's roles and all the roles as parameters, therefore not selecting the user's roles when loading the form.
If I use the notation th:selected="${{user.roles}}" notation all the options are selected (even those the user does not posses).
The Code
User
public class User
{
private Long id;
private String username;
private String password;
private String passwordConfirm;
private Set<Role> roles;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public Long getId()
{
return id;
}
public void setId(Long id)
{
this.id = id;
}
public String getUsername()
{
return username;
}
public void setUsername(String username)
{
this.username = username;
}
public String getPassword()
{
return password;
}
public void setPassword(String password)
{
this.password = password;
}
#Transient
public String getPasswordConfirm()
{
return passwordConfirm;
}
public void setPasswordConfirm(String passwordConfirm)
{
this.passwordConfirm = passwordConfirm;
}
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "users_role", joinColumns = #JoinColumn(name = "users_id"), inverseJoinColumns = #JoinColumn(name = "role_id"))
public Set<Role> getRoles()
{
return roles;
}
public void setRoles(Set<Role> roles)
{
this.roles = roles;
}
}
Role
public class Role
{
private Long id;
private String name;
private Set<User> users;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public Long getId()
{
return id;
}
public void setId(Long id)
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
#ManyToMany(mappedBy = "roles")
public Set<User> getUsers()
{
return users;
}
public void setUsers(Set<User> users)
{
this.users = users;
}
}
Controller
#Controller
#RequestMapping("/admin")
public class AdminController
{
#Autowired
UserService userService;
#Autowired
RoleService roleService;
#RequestMapping("/user/edit/{id}")
public String editUser(Model model, #PathVariable("id") long id)
{
User user = userService.findByUserId(id);
HashSet<Role> foundRoles = roleService.getAllRoles();
model.addAttribute("user", user);
model.addAttribute("userRoles", foundRoles);
return "admin/adminUserDetail";
}
}
The form
<form role="form" th:action="#{/registration}" method="POST"
th:object="${user}">
<div th:if="${#fields.hasErrors('*')}">
<div class="alert alert-danger" role="alert">
<h3 class="alert-heading">It seems we have a couple problems with your input</h3>
<li th:each="err : ${#fields.errors('*')}" th:text="${err}"></li>
</div>
</div>
<div class="form-group">
<label>Username: </label> <input class="form-control" type="text" th:field="${user.username}"
placeholder="Username" name="username"/>
<label>Password: </label> <input class="form-control" type="password" th:field="${user.password}"
placeholder="Password" name="password"/>
<label>Password Confirm: </label> <input type="password"
th:field="${user.passwordConfirm}" class="form-control"
placeholder="Password Confirm"/>
<select class="form-control" multiple="multiple">
<option th:each="role : ${userRoles}"
th:value="${role.id}"
th:selected="${#sets.contains(user.roles, role)}"
th:text="${role.name}">Role name
</option>
</select>
<button type="submit" class="btn btn-success">Update</button>
</div>
</form>
When using a Set the object in there must implement both hashCode and equals as that is used to determine if an object is already in the Set. Unless it is a SortedSet which uses either a Comparator or the natural order expressed through your object implementing Comparable.
As you don't do either of those using contains will simply always return false even for a seemingly same Role instance. Because according to the contract they aren't.
To fix implement the equals and hashCode method in your User and Role object.
public class Role {
public int hashCode() {
return Objects.hash(this.name);
}
public boolean equals(Object o) {
if (o == this) { return true; }
if (o == null || !(o instanceof Role) ) { return false; }
return Objects.equals(this.name, ((Role) o).name);
}
}
Something along those lines should do the trick.

Get list within a list using Thymeleaf

I have two tables one names "State" another named "City"
My city model
#Entity
#Table(name = "city")
public class City implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String city;
#ManyToOne
private State state;
public City() {
}
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
public String getCity() {
return this.city;
}
public void setCity(String city) {
this.city = city;
}
public State getState() {
return this.state;
}
public void setState(State state) {
this.state = state;
}
}
my state model
#Entity
#Table(name = "state")
public class State implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String state;
#OneToMany(mappedBy = "state")
private List<City> cities;
public State() {
}
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
public String getState() {
return this.state;
}
public void setState(String state) {
this.state = state;
}
public List<City> getCities() {
return this.cities;
}
public void setCities(List<City> cities) {
this.cities = cities;
}
public City addCity(City city) {
getCities().add(city);
city.setState(this);
return city;
}
public City removeCity(City city) {
getCities().remove(city);
city.setState(null);
return city;
}
}
my CityRepository
public interface CityRepository extends CrudRepository<City, Long> {
List<City> findByState(String city);
}
my StateRepository
public interface StateRepository extends CrudRepository<State, Long> {
List<State> findByState(String state);
}
my controller
#Controller
public class IndexController {
#Autowired
StateRepository stateRepository;
#Autowired
CityRepository cityRepository;
#RequestMapping(value = "/", method = RequestMethod.GET)
public String index(Model model) {
model.addAttribute("title", "");
Iterable<State> stateIterable = stateRepository.findAll();
for (State state : stateIterable) {
System.out.println(state.getState());
}
model.addAttribute("stateIterable", stateIterable);
return "index";
}
}
and the relevant code for Theymeleaf
<div class="col-md-4">
<div class="panel-group" id="panel-790692">
<th:block th:each="state : ${stateIterable}">
<div class="panel panel-default">
<div class="panel-heading">
<a class="panel-title" data-toggle="collapse"
data-parent="#panel-790692"
th:href="|#panel-element-${#strings.replace(state,' ','-')}|"
th:text="${state.state}">State Name</a>
</div>
<th:block th:each="city : ${state.getCities}">
<div th:id="|panel-element-${#strings.replace(state,' ','-')}|"
class="panel-collapse collapse in">
<div class="panel-body" th:text="city.city"></div>
</div>
</th:block>
</div>
</th:block>
</div>
</div>
Right now I am getting this error
"Property or field 'getCities' cannot be found on object"
Is it possible to get the cities and loop through the cities using Themeleaf? If so how can it be done?
Try with replacing ${state.getCities} with ${state.cities}
<th:block th:each="city : ${state.cities}">
<div th:id="|panel-element-${#strings.replace(state,' ','-')}|"
class="panel-collapse collapse in">
<div class="panel-body" th:text="city.city"></div>
</div>
</th:block>

Resources