Spring framework relationship mapping - java

My class Categorie needs to have multiple Products, i need to show the products when you click on a category in the jsp... I tried it like this:
#Entity
public class Categorie {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int categorieId;
private String categorieName;
#OneToMany()
#JoinColumn(name = "CategorieNr")
private Set<Product> products;
My Product class:
#Entity
#Table(name = "CentricProduct")
public class Product implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int productId;
private int calories, productRow;
private String description;
private double price;
#Override
public boolean equals(Object object) {
if (!(object instanceof Product)) {
return false;
}
Product other = (Product) object;
return description.equals(other.description);
}
#Override
public int hashCode() {
return description.hashCode();
}
This is the repository i use to get the categorys with their products:
#Repository
public class CategoryRepository implements ICategoryRepository
{
#PersistenceContext
private EntityManager em;
public CategoryRepository() {
}
public CategoryRepository(EntityManager em)
{
this.em = em;
}
public void setEntityManager(EntityManager e)
{
this.em = e;
}
#Transactional(readOnly = true)
#Override
public List<Categorie> findAll()
{
CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
cq.select(cq.from(Categorie.class));
return em.createQuery(cq).getResultList();
}
in my jsp:
<h1 class="listtitle">Productenlijst</h1>
<div id="leftlist" class="list" >
<c:forEach items="${products}" var="item" >
<form:form method="POST" action="shoppinglist.htm" modelAttribute="products">
<input type="submit" value= "${item.categorieName}" class="productlistbtn" alt="Submit" input path="${item}" >
</form:form>
</c:forEach>
</div>

your class Product needs to be declared as #Entity. (you can't embed a one-to-many relationship, especially because you're Productcontains it's own ID)

Related

How to map Form Parameter with Hibernate Entity Class in Spring-MVC Controller [duplicate]

This question already has an answer here:
Binding child object on submit spring mvc
(1 answer)
Closed 5 years ago.
I am new at Hibernate/JPA and I am trying to get form parameter with hibernate entity class. There was no problem with it until when I tried to get parameter with Entity class that has relationship with other class. For example;
Controller:
#RequestMapping(value = "/addProduct", method = RequestMethod.POST)
public String addProduct(Model model, Product product) {
databaseService.insert(product);
return "redirect:/products";
}
Entity class:
#Entity
#Table(name = "products")
public class Product implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private String id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "category_id")
private Category category;
#Column(name = "name")
private String name;
#Column(name = "price")
private String price;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
}
Category class :
#Entity
#Table(name = "categories")
public class Category implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private String id;
#Column(name = "name")
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
The program cannot set 'category'. Because category is not type like int, string.. I am realize the problem. But I cannot find solution to mapping parameters with Entity class. Is there any way to solve this. Or should I use #RequestParam to get parameters one-by-one instead of mapping parameters with entity class.
UPDATE
I just change category to category.id in my .jsp page and it solved my problem.
old code
<form>
...
<select class="form-control" name="category">
<c:if test="${not empty categoryList}">
<c:forEach var="item" items="${categoryList}">
<option value="${item.getId()}">${item.getName()}</option>
</c:forEach>
</c:if>
</select>
</form>
new code
<form>
...
<select class="form-control" name="category.id">
<c:if test="${not empty categoryList}">
<c:forEach var="item" items="${categoryList}">
<option value="${item.getId()}">${item.getName()}</option>
</c:forEach>
</c:if>
</select>
</form>
Please show us your form mapping,
Till then can could try with, change path in <form:select>/<form:input> tag to category.id and category.name
have a look at my another answer
I will suggest don't expose your Entity in the View, try to get form data in DTO, then convert to entity..
One way to do that is by creating a custom Spring Converter. So lets say you will be passing your entity's Id as a path variable, and your converter implementation would get that product object for you.
In your Controller you will need to do the following:
#RequestMapping(value = "/addProduct/{id}", method = RequestMethod.POST)
public String addProduct(Model model, #PathVariable("id") Product product) {
databaseService.insert(product);
return "redirect:/products";
}
Your Converter would look something like this:
import org.springframework.core.convert.converter.Converter;
public class StringToProductConverter implements Converter<String, Product> {
...
#Override
public Product convert(String id) {
Product product = databaseService.getProduct(id);
...
return product;
}
And don't forget to register your Converter either programmatically or by XML depending on your Spring version you're working on.

How to check if given atributte is already set in jsp

I'm creating Pet Clinic. If the user wants to add new pet he has to input Owner Id. How to check if this Id already exists. If no I want to use the redirect to the new form where the user can add new Owner.
<tr>
<td><label>Owner: </label></td>
<td><form:input path="ownerId"/></td>
</tr>
Edit:
I want to check if exists in the database. I have two tables in MySQL. Owner and Pet. Owner can have many Pets, Pet can have just one Owner.
Part of Pet Class:
#Entity
#Table(name="pet")
public class Pet {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="id")
private int id;
#Column(name="type")
private String type;
#Column(name="name")
private String name;
#Column(name="sickness")
private String sickness;
#Column(name="owner_id")
private String ownerId;
...
}
Owner class:
#Entity
#Repository
public class Owner {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="id")
private int id;
#Column(name="first_name")
private String firstName;
#Column(name="last_name")
private String lastName;
#Column(name="phone_number")
private String phoneNumber;
...
}
Controller
#Controller
#RequestMapping("/pet")
public class PetController {
#Autowired
private PetService petService;
#GetMapping("/list")
public String listPets(Model theModel){
List<Pet> thePets = petService.getPets();
theModel.addAttribute("pets", thePets);
return "list-pets";
}
...
#PostMapping("/savePet")
public String savePet(#ModelAttribute("pet") Pet thePet){
petService.savePet(thePet);
return "redirect:/pet/list";
}
}
Serive
#Service
public class PetServiceImpl implements PetService{
#Autowired
private PetDAO petDAO;
#Transactional
public List<Pet> getPets() {
return petDAO.getPets();
}
#Transactional
#Override
public void savePet(Pet thePet) {
petDAO.savePet(thePet);
}
}
DAO
#Repository
public class PetDAOImpl implements PetDAO {
#Autowired
private SessionFactory sessionFactory;
public List<Pet> getPets() {
Session currentSession = sessionFactory.getCurrentSession();
Query<Pet> theQuery = currentSession.createQuery("from Pet", Pet.class);
List<Pet> thePets = theQuery.getResultList();
return thePets;
}
#Override
public void savePet(Pet thePet) {
Session currentSession = sessionFactory.getCurrentSession();
currentSession.saveOrUpdate(thePet);
}
}
In JSP you can check if object has value with JSTL core lib:
<c:if test="${not empty pet.ownerId}">...</c:if>
where pet is your model object (passed to form).

Only the first commandLink in dataTable is clickable

I am new to JPA, and I'm trying to make a datatable form that allows you to press "Remove" to remove a User from a Course. The problem is that only the first (uppermost) from the datatable is clickable, and removes the course from that user. (When it's removed, the next on the list is now the uppermost and working. )
The problem is that the other links (everyone but the uppermost) are refreshing the site without URL parameters (resetting session?), and doesn't invoke the removeUserFromCourse(..) method. If anyone knows why this is happeing, please feel free to answer and point out my mistakes.
Controller (shortened) :
#Model
public class UserController{
private UserDAO persister;
private User user;
// 103 is just a default value
private int selectedID = 103;
#Inject
public UserController(UserDAO persister) {
this.persister = persister;
}
#PostConstruct
public void init() {
this.user = new User();
}
public int getSelectedID() {
return selectedID;
}
public void setSelectedID(int selectedID) {
this.selectedID = selectedID;
}
public void removeUserFromCourse(int courseID){
persister.removeFromCourse(selectedID, courseID);
user = persister.getUser(selectedID);
}
}
Form in edit-user.xhtml:
<h:form>
<h:dataTable id="mdtb" value="#{userController.getUserCourses()}" var="course"
styleClass=" col-lg-6">
<h:column>
<h:outputText value="#{course.name} (#{course.id})" styleClass="col-lg-6"/>
<h:commandLink update="mdtb" value="Remove"
action="#{userController.removeUserFromCourse(course.id)}">
<f:param name="id" value="#{userController.selectedID}"/>
</h:commandLink>
</h:column>
</h:dataTable>
</h:form>
User JPA (shortened):
#Stateless
public class JPAUserDao implements UserDAO {
EntityManagerFactory entityManagerFactory;
#PersistenceContext(name = "Egentreningprosjekt")
EntityManager entityManager;
public JPAUserDao() {
}
public JPAUserDao(EntityManager entityManager){
this.entityManager = entityManager;
}
#Override
public User update(User user) {
System.out.println("updating user " + user);
entityManager.merge(user);
return user;
}
#Override
public void removeFromCourse(int userID, int courseID) {
User user = getUser(userID);
List<Course> courses = user.getCourses();
Course courseToBeDeleted = null;
for(Course course : courses){
if(course.getId() == courseID){
courseToBeDeleted = course;
}
}
if(courseToBeDeleted != null){
courses.remove(courseToBeDeleted);
courseToBeDeleted.getUsers().remove(user);
}
user.setCourses(courses);
update(user);
entityManager.merge(courseToBeDeleted);
}
User.java (shortened):
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
#Min(value = 0, message = "ID cannot be negative")
private int id;
#NotNull
#Pattern(regexp = "^([A-Z|a-z|0-9](\\.|_){0,1})+[A-Z|a-z|0-9]\\#([A-Z|a-z|0-9])+((\\.){0,1}[A-Z|a-z|0-9]){2}\\.[a-z]{2,3}$")
private String email;
#ManyToMany(mappedBy = "users", cascade = {CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.EAGER)
private List<Course> courses;
// getters/setters
}
Answering this now 4 years later. This was due to 103 being hardcoded, as the comments hinted to.

how to databind list selected checkbox in spring mvc

Hi I am new to Spring Mvc i have 3 tables first is role,resources,roleresource tables respectively. I have a created a jsp in which a list of resources are shown along with check boxes and also rolename where user enters,my prob is i need to insert rolename to role table and generated roleid to roleresource table with selected resources ids. problem here is i am not able to bind selected checkbox values here is my controller
package com.steadyground.controller;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.steadyground.constants.URLConstants;
import com.steadyground.entity.Organization;
import com.steadyground.entity.Resources;
import com.steadyground.form.RoleResourceForm;
import com.steadyground.service.ResourcesService;
#Controller
public class RoleResoucesMappingController {
#Autowired
private ResourcesService resourcesService;
#RequestMapping(value = URLConstants.ROLERESOURCEMAPPING_PAGE, method = RequestMethod.GET)
public String landRoleResourceMapping(ModelMap map)
{
map.addAttribute("roleResourceForm",new RoleResourceForm());
return "roleResourcesMapping";
}
#RequestMapping(value = URLConstants.ROLERESOURCEMAPPING_ADD, method = RequestMethod.POST)
public String createRoleResourceMapping(#ModelAttribute(value="roleResourceForm") RoleResourceForm roleResourceForm, BindingResult result, ModelMap map)
{
System.out.println(roleResourceForm.getResources());
System.out.println(roleResourceForm.getResources().size());
//System.out.println(roleResourceForm.getRole().getRoleResources());
return "roleResourcesMapping";
}
#ModelAttribute("resources")
public List<Resources> getAllResources() {
List<Resources> listResources = new ArrayList<Resources>();
listResources = resourcesService.getAllResources();
return listResources;
}
}
here is my role.java file
#Entity
#Table(name = "role", catalog = "steadyground")
public class Role implements java.io.Serializable {
private Integer roleId;
private String roleName;
private Set<RoleResource> roleResources = new HashSet<RoleResource>(0);
public Role() {
}
public Role(String roleName) {
this.roleName = roleName;
}
public Role(String roleName, String applicationName,
Set<RoleResource> roleResources) {
this.roleName = roleName;
this.roleResources = roleResources;
}
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "role_id", unique = true, nullable = false)
public Integer getRoleId() {
return this.roleId;
}
public void setRoleId(Integer roleId) {
this.roleId = roleId;
}
#Column(name = "role_name", nullable = false, length = 100)
public String getRoleName() {
return this.roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "role")
public Set<RoleResource> getRoleResources() {
return this.roleResources;
}
public void setRoleResources(Set<RoleResource> roleResources) {
this.roleResources = roleResources;
}
}
here is my resources.java
#Entity
#Table(name = "resources", catalog = "steadyground")
public class Resources implements java.io.Serializable {
private Integer resourceId;
private String url;
private String urlName;
public Resources() {
}
public Resources(String url, String urlName) {
this.url = url;
this.urlName = urlName;
}
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "resource_id", unique = true, nullable = false)
public Integer getResourceId() {
return this.resourceId;
}
public void setResourceId(Integer resourceId) {
this.resourceId = resourceId;
}
#Column(name = "url", length = 100)
public String getUrl() {
return this.url;
}
public void setUrl(String url) {
this.url = url;
}
#Column(name = "url_name", length = 200)
public String getUrlName() {
return this.urlName;
}
public void setUrlName(String urlName) {
this.urlName = urlName;
}
}
here is my roleresource.java
#Entity
#Table(name="role_resource"
,catalog="steadyground"
)
public class RoleResource implements java.io.Serializable {
private Integer roleResourceId;
private Role role;
private Integer resourceId;
public RoleResource() {
}
public RoleResource(Role role, Integer resourceId) {
this.role = role;
this.resourceId = resourceId;
}
#Id #GeneratedValue(strategy=IDENTITY)
#Column(name="role_resource_id", unique=true, nullable=false)
public Integer getRoleResourceId() {
return this.roleResourceId;
}
public void setRoleResourceId(Integer roleResourceId) {
this.roleResourceId = roleResourceId;
}
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="role_id")
public Role getRole() {
return this.role;
}
public void setRole(Role role) {
this.role = role;
}
#Column(name="resource_id")
public Integer getResourceId() {
return this.resourceId;
}
public void setResourceId(Integer resourceId) {
this.resourceId = resourceId;
}
}
and my jsp page
<springform:form method="post" action="createRoleResourcesMapping" class="form-horizontal" commandName="roleResourceForm" >
<div class="span12">
<div class="center">
<div class="control-group span6">
<label class="control-label" for="Role_Id">Role Id</label>
<div class="control-group span6">
<label class="control-label" for="url_Name">Role Name</label>
<div class="controls">
<div class="span12">
<springform:input path="role.roleName"/>
</div>
</div>
</div>
<div class="page-header position-relative"></div>
<table id="sample-table-2" class="table table-striped table-bordered table-hover">
<thead>
<tr>
<th>Resources</th>
</tr>
</thead>
<tbody>
<tr>
<td><springform:checkboxes path="resources" items="${resources}" itemLabel="urlName" itemValue="resourceId"/>
</td></tr></tbody>
</table>
<div class="controls">
<div class="span12">
<input type="submit" class="btn btn-primary" value="Submit">
<input type="button" class="btn " value="Cancel">
</div>
</div>
</div>
</div>
</springform:form>
could someone help me in how to receive the data and save it in two tables
<springform:checkboxes path="resources" items="${resources}" itemLabel="urlName" itemValue="resourceId"/>
From your code, what I've understood, the RoleResourcesForm is more like a wrapper of the 2 entities Resource & Role with another object resources.
I think, to use form:checkboxes you better give it an object List in the path.
And what's this variable resources?
If it's really an List object in the RoleResourcesForm wrapper, in the items, you should use
items="${roleResourceForm.resources}"
When you commit it, it will send the form model attribute with only checked checkbox values.

Binding objects from spring multiple <form:select>

Have to beans:
#Entity
#Table(name="book")
public class Book {
#Id
#Column(name="id_book")
#GeneratedValue(generator="increment")
#GenericGenerator(name="increment", strategy="increment")
private int id;
#Column
#Size(min=1,max=100)
private String title;
#Column
#Size(min=1,max=400)
private String description;
#Column
private Integer year=0;
#ManyToMany(cascade={CascadeType.ALL},fetch = FetchType.EAGER)
#Fetch (FetchMode.SELECT)
#JoinTable(name="book_author",
joinColumns={#JoinColumn(name="book_id_book")},
inverseJoinColumns= {#JoinColumn(name="author_id_author")})
private List<Author> author=new ArrayList<Author>();
//getters/setters
}
and:
#Entity
#Table(name="author")
public class Author {
#Id
#Column(name="id_author")
#GeneratedValue
private Integer id;
#Column
private String name;
#Column
private String surname;
#ManyToMany(mappedBy="author")
private Set<Book> book=new HashSet<Book>();
//getters/setters
}
In my jsp I'm have form for enter data about book, and multiple list for select author(s) from DB, problem only in select authors, therefore give only this code:
<sf:select multiple="true" path="author" items="${authors}" size="7" >
</sf:select>
Where ${authors} - List with objects Author from DB. Use POST request.
In my controller for this page have this (I know it's not correct):
#RequestMapping(value="/addbook", method=RequestMethod.POST)
public String addBook(Book book){
hibarnateService.saveBook(book);
return "redirect:/books";
}
When I'm create book without select authors, but enter another information, all fine, book save in DB. When select some authors get this - The request sent by the client was syntactically incorrect.
Problem solved by add in controller:
#InitBinder
protected void initBinder(WebDataBinder binder){
binder.registerCustomEditor(Author.class, new Editor(hibarnateService));
}
and create class:
public class Editor extends PropertyEditorSupport {
private final Dao hibernateService;
public Editor(Dao hibernateService){
this.hibernateService=hibernateService;
}
#Override
public void setAsText(String text) throws IllegalArgumentException{
Author author=hibernateService.getAuthor(Integer.parseInt(text));
setValue(author);
}
}
P.S. What wrong with me? I can't find the right answer myself until I ask here)
You will need to implement initBinder in your controller, below can be tentative code (not tested)
#InitBinder
protected void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(List.class, "authors ", new CustomCollectionEditor(List.class)
{
#Override
protected Object convertElement(Object element)
{
Long id = null;
if(element instanceof Long) {
//From the database 'element' will be a Long
id = (Long) element;
}
return id != null ? authorService.loadAuthorById(id) : null;
}
});
}

Categories

Resources