Spring Hibernate - Saving Joke with existing Category - java

I've been dealing with a problem which I require your help.
#Controller
public class JokeController {
#Autowired
JokeRepository jokeRepository;
CategoryRepository categoryRepository;
public Category dark_humor = new Category("Dark Humor");
public Category sports_and_athletes = new Category("Sports And Athletes");
#GetMapping("/new")
public String jokeForm(Model model) {
model.addAttribute("joke", new Joke());
return "jokeForm"; // jokeForm.html
}
#PostMapping("/new")
public String jokeSubmit(#ModelAttribute Joke joke) {
//joke.setCategory(dark_humor);
jokeRepository.save(joke);
return "redirect:/new";
//return "resultJoke"; // resultCategory.html
}
}
My entities:
Relationship is that Category can have many Jokes, but Joke can only belong to one Category.
Category
#Entity
public class Category {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
#Column(name = "name")
private String name;
public Category() {
}
public Category(String name) {
this.name = name;
}
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;
}
#Override
public String toString() {
return "Category{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
Joke
#Entity
public class Joke {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int joke_id;
#Column(name = "likes")
#Value("${some.key:0}")
private int likes;
#Column(name = "dislikes")
#Value("${some.key:0}")
private int dislikes;
#Column(name = "content")
#NotNull
private String content;
#ManyToOne(fetch = FetchType.EAGER, cascade=CascadeType.ALL)
#NotNull
#JoinColumn(name = "category_id")
private Category category;
public Joke() {
}
public Joke(#NotNull String content, #NotNull Category category) {
this.content = content;
this.category = category;
}
public int getJoke_id() {
return joke_id;
}
public void setJoke_id(int joke_id) {
this.joke_id = joke_id;
}
public int getLikes() {
return likes;
}
public void setLikes(int likes) {
this.likes = likes;
}
public int getDislikes() {
return dislikes;
}
public void setDislikes(int dislikes) {
this.dislikes = dislikes;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
#Override
public String toString() {
return "Joke{" +
"joke_id=" + joke_id +
", likes=" + likes +
", dislikes=" + dislikes +
", content='" + content + '\'' +
", category=" + category +
'}';
}
}
My thymeleaf:
<!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>Form</h1>
<form action="#" th:action="#{/new}" th:object="${joke}" method="post">
<p>Content: <input type="text" th:field="*{content}" /></p>
<p>Category: <input type="text" th:field="*{category}" /></p>
<p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
</form>
</body>
</html>
*Specifically in this section:*
#PostMapping("/new")
public String jokeSubmit(#ModelAttribute Joke joke) {
//joke.setCategory(dark_humor);
jokeRepository.save(joke);
return "redirect:/new";
//return "resultJoke"; // resultCategory.html
}
I would like Hibernate to save new Joke with existing category. But I am not sure how I can in my form load all the existing categories and how to use it in my Post method to send the joke with category that I have picked explicitly in my form. I think I am missing some important aspect that I haven't picked up upon yet.

The first step is to hard code setting the category in the controller to ensure that it saves correctly. I would also reduce your cascade, in the joke class, as I would not have thought saving a joke should be able to modify properties of the category.
Once you are confidant that you can save a joke with a hard coded category, we can look to select the category in the ui. Now you won't easily be able to set the category straight into the joke object, you will find it much easier to pass a value to the controller and use that to select the category on the back end.
If you try something along the lines of
<p>Category: <input type="text" name="categoryid" /></p>
And
jokeSubmit(#ModelAttribute Joke joke, #Requestparam("categoryid") String categoryid) {
Now this should work, although could be cleaner, you are implementing one of my little frustrations: you are using your db objects in your ui layer, ideally ORM objects should not be used as form objects, although that is it of scope for the question I would happily discuss separation of code concepts with you.

Related

Unknown column when trying to add data to a database

I am working on a simple CRUD project using Spring, Hibernate & JPA.
It's a basic coupon system, Coupon object has parameters, one of them is Coupon Type. When typing in the vales in the jsp which is bound to the server:
<h1> Create Coupon </h1>
<form:form action="company/create" method="POST" modelAttribute="theCoupon">
<input name="title"/>
<input name="startDate"/>
<input name="endDate"/>
<input name="amount"/>
<input name="message"/>
<input name="price"/>
<input name="image"/>
<select name="couponType">
<option>SPORTS</option>
<option>GAMING</option>
</select>
<input type="submit" value="submit">
</form:form>
this is the controller :
#PostMapping("/add")
public String newCoupon(Model theModel) {
List<CouponType> couponType = new ArrayList<CouponType>( Arrays.asList(CouponType.values()));
System.out.println(couponType);
theModel.addAttribute("couponType", couponType);
theModel.addAttribute("theCoupon", new Coupon());
return "add";
}
#RequestMapping("/create")
public String add(#ModelAttribute("theCoupon") Coupon theCoupon) {
theCoupon.setId(0);
System.out.println(theCoupon);
couponService.save(theCoupon);
return "savedCoupon";
}
I am getting this error:
java.sql.SQLSyntaxErrorException: Unknown column 'coupon0_.coupon_type' in 'field list'
Here is a screenshot of the database structure, the names are the same I have no idea whats the problem.
Also, here is the Coupon pojo:
#Entity
#Table(name = "coupon")
public class Coupon {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private long id;
#Column(name = "title")
private String title;
#Column(name = "startDate")
private String startDate;
#Column(name = "endDate")
private String endDate;
#Column(name = "amount")
private int amount; // decrease amount on every customer purchase
#Column(name = "couponType")
private String couponType;
#Column(name = "message")
private String message;
#Column(name = "price")
private double price;
#Column(name = "image")
private String image;
public Coupon(long id, String title, String startDate, String endDate, int amount, String couponType,
String message, double price, String image) {
super();
this.id = id;
this.title = title;
this.startDate = startDate;
this.endDate = endDate;
this.amount = amount;
this.couponType = couponType;
this.message = message;
this.price = price;
this.image = image;
}
public Coupon() {
super();
}
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 getStartDate() {
return startDate;
}
public void setStartDate(String startDate) {
this.startDate = startDate;
}
public String getEndDate() {
return endDate;
}
public void setEndDate(String endDate) {
this.endDate = endDate;
}
public int getAmount() {
return amount;
}
public void setAmount(int amount) {
this.amount = amount;
}
public String getCouponType() {
return couponType;
}
public void setCouponType(String couponType) {
this.couponType = couponType;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public String getImage() {
return image;
}
public void setImage(String image) {
this.image = image;
}
#Override
public String toString() {
return "Coupon [id=" + id + ", title=" + title + ", startDate=" + startDate + ", endDate=" + endDate
+ ", amount=" + amount + ", couponType=" + couponType + ", message=" + message + ", price=" + price
+ ", image=" + image + "]";
}
}
Hope anyone of you could spot the problem, any help would be appreciated!
[SOLVED]
The problem was that I was using two words in my var, like couponType, would be coupon_type on the data base.
changed it to type only, the pojo & the database & now it works fine!
hope this helps to anyone that had this problem.

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>

How to send an object from a thymeleaf form to MVC spring boot controller

I have two classes (Employee and Project) that have many to many relationship. I am trying to send the contents of the thymeleaf form with the (project) as the class object and a drop down list that contains the employee list. I can retrieve the employee list in my form but when I submit it to the controller to save it, non of the employees in the list saved. I should be able to save one employee each time I submit the form.
This is Employee class:
#Entity
#Table(name = "EMPLOYEE")
public class Employee {
#Id
#Column(name = "EMPLOYEE_ID")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "FIRST_NAME")
private String firstName;
#Column(name = "LAST_NAME")
private String lastName;
#Column(name = "DOB")
#DateTimeFormat(pattern = "yyyy-MM-dd")
private Date dob;
#Column(name = "HIRING_DATE")
#DateTimeFormat(pattern = "yyyy-MM-dd")
private Date hiringDate;
#Column(name = "TERMINATION_DATE")
#DateTimeFormat(pattern = "yyyy-MM-dd")
private Date terminationDate;
#Column(name = "TELEPHONE")
private String telephone;
#Column(name = "EMAIL")
private String email;
#Column(name = "JOB_TITLE")
private String jobTitle;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "MANAGER_ID")
private Employee manager;
#OneToOne(cascade=CascadeType.ALL)
private EmployeeInfo empInfo;
#ManyToMany(cascade = { CascadeType.ALL }, fetch = FetchType.EAGER)
#JoinTable(name = "EMPLOYEE_PROJECT", joinColumns = { #JoinColumn(name = "EMPLOYEE_ID") }, inverseJoinColumns = {
#JoinColumn(name = "PROJECT_ID") })
Set<Project> projects;
public Employee() {
super();
}
public Employee(Long id, String firstName, String lastName, String telephone, String email, String jobTitle) {
super();
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.telephone = telephone;
this.email = email;
this.jobTitle = jobTitle;
}
public Long getId() {
return id;
}
public void setId(Long 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 Date getDob() {
return dob;
}
public void setDob(Date dob) {
this.dob = dob;
}
public Date getHiringDate() {
return hiringDate;
}
public void setHiringDate(Date hiringDate) {
this.hiringDate = hiringDate;
}
public Date getTerminationDate() {
return terminationDate;
}
public void setTerminationDate(Date terminationDate) {
this.terminationDate = terminationDate;
}
public String getTelephone() {
return telephone;
}
public void setTelephone(String telephone) {
this.telephone = telephone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getJobTitle() {
return jobTitle;
}
public void setJobTitle(String jobTitle) {
this.jobTitle = jobTitle;
}
public Set<Project> getProjects() {
return projects;
}
public void setProjects(Set<Project> projects) {
this.projects = projects;
}
public Employee getManager() {
return manager;
}
public void setManager(Employee manager) {
this.manager = manager;
}
public EmployeeInfo getEmpInfo() {
return empInfo;
}
public void setEmpInfo(EmployeeInfo empInfo) {
this.empInfo = empInfo;
}
}
This is Project class:
#Entity
#Table(name = "PROJECT")
public class Project {
#Id
#Column(name = "ID")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "PROJECT_TYPE")
private String projectType;
#Column(name = "PROJECT_NAME")
private String name;
#Column(name = "DESCRIPTION")
private String description;
#Column(name = "START_DATE")
#DateTimeFormat(pattern = "yyyy-MM-dd")
private Date startDate;
#Column(name = "END_DATE")
#DateTimeFormat(pattern = "yyyy-MM-dd")
private Date endDate;
#Column(name = "COST")
private Float cost;
#ManyToMany(mappedBy = "projects", fetch = FetchType.EAGER)
private Set<Employee> employees;
public Project() {
super();
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getProjectType() {
return projectType;
}
public void setProjectType(String projectType) {
this.projectType = projectType;
}
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 Date getStartDate() {
return startDate;
}
public void setStartDate(Date startDate) {
this.startDate = startDate;
}
public Date getEndDate() {
return endDate;
}
public void setEndDate(Date endDate) {
this.endDate = endDate;
}
public Float getCost() {
return cost;
}
public void setCost(Float cost) {
this.cost = cost;
}
public Set<Employee> getEmployees() {
return employees;
}
public void setEmployees(Set<Employee> employees) {
this.employees = employees;
}
}
This is the main projects page:
<!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" />
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script
src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
<h2>Projects List</h2>
<a href="#" th:href="#{/projects/new}" class="btn btn-primary"
role="button">Add New Project</a> <br> <br>
<table class="table table-striped">
<tr>
<th>Name</th>
<th>Cost</th>
<th>Start Date</th>
<th>End Date</th>
<th>Project Type</th>
<th></th>
<th></th>
</tr>
<tr th:each="project : ${projects}">
<td th:text="${project.name}"></td>
<td th:text="${project.cost}"></td>
<td th:text="${project.startDate}"></td>
<td th:text="${project.endDate}"></td>
<td th:text="${project.projectType}"></td>
<td><a th:href="#{'/project/' + ${project.id} + '/update'}">Update</a></td>
<td><a th:href="#{'/project/' + ${project.id} + '/addTeam'}">Add Team</a></td>
</tr>
</table>
</div>
</body>
</html>
This is the thymeleaf view:
<!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" />
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script
src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
<body>
<div class="container">
<h1>
<span th:text="${project.name }" th:remove="tag">title</span>
</h1>
<h3>
<span th:text="${project.id }" th:remove="tag">title</span>
</h3>
<br>
<h2>Add Project Team</h2>
<br>
<form class="form-group" th:object="${project}"
th:action="#{/projects/saveProject}" method="post">
<input th:type="hidden" name="id" th:field="${project.id}" />
<div class="form-group">
<label for="employees">Add Team:</label>
<select name="employees"
id="employees">
<option th:each="data:${employeesList}" th:value="${data.id}"
th:text="${data.firstName}" >Options</option>
</select>
</div>
<button type="submit" class="btn btn-primary">Save</button>
<a href="#" th:href="#{/projects}" class="btn btn-danger"
role="button">Cancel</a>
</form>
</div>
</body>
</html>
and this is the controller:
#RequestMapping("project/{id}/addTeam")
public String addProjectTeam(#PathVariable String id, Model model) {
model.addAttribute("project", projectService.findById(Long.valueOf(id)));
model.addAttribute("employeesList", this.employeeService.getEmployees());
return "addTeam";
}
#PostMapping("/projects/saveProject")
public String saveOrUpdate(Model model, #RequestParam("project") Project project,
#RequestParam("employees") Set<Long> employeesIds)
{
Set<Employee> employees = new LinkedHashSet<Employee>();
if (project.getEmployees() != null && project.getEmployees().size() > 0) {
for (Employee emp : project.getEmployees()) {
employeesIds.add(emp.getId());
}
for (Long eId : employeesIds) {
Employee e = this.employeeService.findById(eId);
employees.add(e);
}
project.setEmployees(employees);
this.projectService.saveProject(project);
}
model.addAttribute("projects", projectService.getProjects());
return "redirect:/projects/";enter image description here
}
I appreciate your help to solve the problem.
So apparently you want to send the 'Employee' object from HTML-Drop-down to your Controller , which you're not able to get.!!
If thats the case here , as per your code - You haven't set 'Employee' object in your thymeleaf code, Also I'd like to tell you that you wont be able to get all the values like dob,job_title,address from your 'Employee' class on the drop down because a HTML drop-down contains name and its value only. Something like this
<select name="Employee">
<option value="Id">David</option>
<option value="Id">Peter</option>
</select>
In order to solve this problem , send your 'Employee-Id' & 'employee-name' from controller to thymeleaf and then further after getting the 'Employee-Id' object on your controller , execute a 'select query' to get the details of the employee from DB.
For that:---
1.) From your controller where you're sending the Employee & Project's Object use Model Attribute like this :--
#RequestMapping("/getProjectAndEmployee")
public String getProjectAndEmployee(Model model) {
List<YourEmployeeEntityClass> employees = //your code to get the employee
List<YourProjectEntityClass> project = //your code to get project
model.addAttribute("employees",employees);
model.addAttribute("project",project);
}
2.) (Now this part is important) Get the Employee ID and Employee name on your Thyemleaf Code along with project :---
<select>
<option th:each="data:${employees}" th:value="${data.employee_id}" th:text="${data.employee_name}"> </option>
</select>
3.) Get the list of selected Employee_id & Project_details on your controller like this :--
#PostMapping("/projects/saveProject")
public String saveOrUpdate(Model model, #RequestParam("project") Project project,
#RequestParam("employee_id")String employee_id ) {
//here you've employee_id , get the employee's details on the basis of this id from your DB
}

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";
}

Thymeleaf and spring select box containing list of objects not able to post

I'm creating a web app with spring, hibernate and thyme leaf.
I have a page where I can manage users, on this page you should be able to place users in groups.
I am doing this with 2 multiple select boxes.
I added a jquery script what handles the movement of users from the one select box to the other one.
But when i submit my Group.users object list is empty.
Does anyone has some advice?
Thanks in advance.
Thyme leaf / edit.html:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="//code.jquery.com/jquery-migrate-1.2.1.min.js"></script>
<div th:replace="template :: css"></div>
<title>Edit group</title>
</head>
<body>
<script>
$(document).ready(function() {
$(".clickable").click(function() {
if ($(this).hasClass("selected")) {
$(this).removeClass("selected").addClass("unselected");
$('#userGroupContainer').append(this);
$("option:selected").css("background-color", "red");
} else {
$(this).removeClass("unselected").addClass("selected");
$('#userGroupContainerSelected').append(this);
$("option:selected").css("background-color", "green");
}
});
});
</script>
<div id="bodyWrap">
<div th:replace="template :: logo">Logo</div>
<div th:replace="template :: nav">Nav</div>
<div th:replace="template :: messages">Header</div>
<div id="backGround">
<div id="contentWrap">
<form action="#{edit}"
th:action="#{${#httpServletRequest.servletPath}}"
th:object="${group}" th:method="post">
<h1 th:unless="${group.id}">Add group</h1>
<h1 th:if="${group.id}">Edit group</h1>
<hr />
<div th:replace="template :: messages">Header</div>
<div class="newFile">
<input type="hidden" th:field="*{id}" />
<table class="newFile">
<tr>
<th>Name:</th>
<td><input type="text" size="50" th:field="${group.name}" /></td>
</tr>
<tr>
<th>Description:</th>
<td><textarea th:field="${group.description}"></textarea></td>
</tr>
<tr>
<td> </td>
</tr>
</table>
<br /> users <br />
<select multiple="multiple" id="userGroupContainer">
<option th:each="u : ${userNotInGroup}" th:text="${u.displayName}" class="clickable unselected" th:value="${u}" ></option>
</select>
<!-- It's all about the select box under this comment -->
<select multiple="multiple" id="userGroupContainerSelected" th:field="*{users}">
<option th:each="ug, rowStat : ${group.users}" th:text="${ug.displayName}" th:value="${ug}" class="clickable selected">Selected</option>
</select>
<div class="form-actions">
<button th:unless="${group.id}" type="submit">Add</button>
<button th:if="${group.id}" type="submit">Update</button>
</div>
</div>
</form>
</div>
</div>
</div>
</body>
</html>
example of the 2 multiple select boxes:
$(document).ready(function() {
$(".clickable").click(function() {
if ($(this).hasClass("selected")) {
$(this).removeClass("selected").addClass("unselected");
$('#userGroupContainer').append(this);
$("option:selected").css("background-color", "red");
} else {
$(this).removeClass("unselected").addClass("selected");
$('#userGroupContainerSelected').append(this);
$("option:selected").css("background-color", "green");
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.1/jquery.min.js"></script>
<select multiple="multiple" id="userGroupContainer">
<option class="clickable unselected" >Example</option>
</select>
<select multiple="multiple" id="userGroupContainerSelected" th:field="*{users}">
<option class="clickable selected">Selected</option>
</select>
Servlet / controller:
#RequestMapping(value = "/management/edit/{groupId}", method = RequestMethod.GET)
public String editGroup(ModelMap model, Principal principal, #PathVariable("groupId") Long groupId) {
Group group = groupService.findGroupById(groupId);
User user = new User();
List<User> userNotInGroup = userService.findUsersNotInGroup(group);
model.addAttribute("userNotInGroup", userNotInGroup);
model.addAttribute("group", group);
return "management/groups/edit";
}
#RequestMapping(value = "/management/edit/{groupId}", method = RequestMethod.POST)
public String editGroup(#Valid Group group, BindingResult result, Model model, #PathVariable("groupId") Long groupId) {
model.addAttribute("group", group);
System.out.println("USERS: " + group.getUsers());
groupService.saveGroup(group);
return "redirect:/management/list";
}
Group entity:
#Entity
#Table(name = "GROUPS")
public class Group extends DomainObject {
private static final long serialVersionUID = ;
#Id
#GeneratedValue(generator = "GROUPS_SEQ", strategy = GenerationType.SEQUENCE)
#SequenceGenerator(name = "GROUPS_SEQ", sequenceName = "GROUPS_SEQ")
private Long id;
#Column(name = "NAME")
private String name;
#Column(name = "DESCRIPTION")
private String description;
#JoinTable(name = "USERS_GROUPS")
#ManyToMany(fetch = FetchType.EAGER)
private Collection<User> users;
#JoinTable(name = "GROUPS_ROLES")
#ManyToMany
private Collection<Role> roles;
public Collection<User> getUsers() {
return users;
}
public void setUsers(Collection<User> users) {
this.users = users;
}
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;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Collection<Role> getRoles() {
return roles;
}
public void setRoles(Collection<Role> roles) {
this.roles = roles;
}
}
User entity:
#Entity
#Table(name = "USERS")
public class User extends DomainObject implements UserDetails {
private static final long serialVersionUID = ;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#NotNull
private Long ID;
#Column(name = "DISPLAY_NAME")
#NotNull
private String displayName;
#Column(name = "EMAIL_ADDRESS")
#NotNull
private String emailAddress;
#Column(name = "PASSWORD")
private String password;
#Column(name = "USERNAME")
#NotNull
private String username;
#Column(name = "LAST_LOGIN")
private Date lastLogin;
#Column(name = "MODIFIED_DATE")
private Date modifiedDate;
#Column(name = "MODIFIED_BY")
private String modifiedBy;
#Transient
private Collection<? extends GrantedAuthority> authorities;
private boolean admin;
#Nullable
#JoinTable(name = "USERS_GROUPS")
#ManyToMany
private Collection<Group> groups;
public Date getLastLogin() {
return lastLogin;
}
public void setLastLogin(Date lastLogin) {
this.lastLogin = lastLogin;
}
public Collection<Group> getGroups() {
return groups;
}
public void setGroups(Collection<Group> groups) {
this.groups = groups;
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
#Override
public String getPassword() {
return password;
}
#Override
public String getUsername() {
return username;
}
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return true;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return true;
}
public String getEmailAddress() {
return emailAddress;
}
public void setEmailAddress(String emailAddress) {
this.emailAddress = emailAddress;
}
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
public void setAuthorities(Collection<? extends GrantedAuthority> authorities) {
this.authorities = authorities;
}
public void setPassword(String password) {
this.password = password;
}
public void setUsername(String username) {
this.username = username;
}
public boolean isAdmin() {
return admin;
}
public void setAdmin(boolean admin) {
this.admin = admin;
}
#Override
public Long getId() {
return ID;
}
#Override
public void setId(Long id) {
this.ID = id;
}
}

Categories

Resources