java spring mvc many to many - spring

I'm trying to make a many-to-many example app with spring mvc and hibernate.
I have 2 classes, book and author. I've mapped these 2 class created all relations, but the problem is I can't add values to my join table.
Where's the problem?
CREATE TABLE author
(
author_id serial NOT NULL,
author_name character(100),
CONSTRAINT author_pkey PRIMARY KEY (author_id)
)
CREATE TABLE book
(
book_id serial NOT NULL,
book_name character(50) NOT NULL,
price integer NOT NULL,
CONSTRAINT book_pkey PRIMARY KEY (book_id)
)
CREATE TABLE book_author
(
book_id integer NOT NULL,
author_id integer NOT NULL,
CONSTRAINT book_author_pkey PRIMARY KEY (book_id, author_id),
CONSTRAINT book_author_author_id_fkey FOREIGN KEY (author_id)
REFERENCES author (author_id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION,
CONSTRAINT book_author_book_id_fkey FOREIGN KEY (book_id)
REFERENCES book (book_id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
)
and my java files
#Entity
#Table(name = "book")
public class Book {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int book_id;
#Column
private String book_name;
#Column
private int price;
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(
name = "book_author",
joinColumns = { #JoinColumn(name = "book_id")},
inverseJoinColumns = { #JoinColumn(name = "author_id") }
)
private Set<Author> authors = new HashSet<Author>();
//geters and setters
}
Author.java
#Entity
#Table(name="author")
public class Author {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="author_id")
private int author_id;
#Column
private String author_name;
#ManyToMany(mappedBy = "authors")
private Set<Book> books = new HashSet<Book>();
//getters and setters
}
BookDAOImpl.java
#Repository
public class BookDAOImpl implements BookDAO{
#Autowired
private SessionFactory sessionFactory;
public void addBook(Book book) {
sessionFactory.getCurrentSession().saveOrUpdate(book);
}
}
BookServiceImpl.java
#Service
#Transactional
public class BookServiceImpl implements BookService{
#Autowired
private BookDAO bookDAO;
#Override
public void addBook(Book book) {
bookDAO.addBook(book);
}
}
BookController.java
#Controller
#SessionAttributes("authors")
public class BookController {
#Autowired
private BookService bookService;
#Autowired
private AuthorService authorService;
#RequestMapping(value = "/newBook", method = RequestMethod.GET)
public ModelAndView newBook(ModelAndView model) {
Book book = new Book();
model.addObject("book", book);
model.setViewName("bookForm");
return model;
}
#RequestMapping(value = "/saveBook", method = RequestMethod.POST)
public ModelAndView saveBook(#ModelAttribute Book book,BindingResult result)
{
if (book.getBook_id() == 0) {
// if employee id is 0 then creating the
// employee other updating the employee
bookService.addBook(book);
} else {
bookService.updateBook(book);
}
return new ModelAndView("redirect:/newBook");
}
#ModelAttribute("authors")
public List<Author> getAuthors(){
return authorService.getAuthors();
}
}
and finally here is bookForm.jsp file
<body>
<div align="center">
<h1>New/Edit Book</h1>
<form:form action="saveBook" method="post" modelAttribute="book">
<table>
<form:input type="hidden" path="book_id"/>
<tr>
<td>Name:</td>
<td><form:input path="book_name" /></td>
</tr>
<tr>
<td>Price:</td>
<td><form:input path="price" /></td>
</tr>
<tr>
<td>Author:</td>
<td><form:select path="authors" items="${authors}" itemValue="author_id" itemLabel="author_name"/></td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" value="Save"></td>
</tr>
</table>
</form:form>
</div>
</body>
After the page opens, I enter some book name and price and choose an author and click the Save button. It saves book but not saves the join table book_author.
As you can see I can send author_id from uipng
And I can insert book object to database

Related

Couldn't join two tables on Spring boot

I am a beginner of spring boot application. I want to join the course table and the student table together. What I tried so far I attached code below. I didn't get any errors. When the student page is loaded I show course id only I need to display the name instead of the id. I attached the screenshot image below.
Above screenshot image only displayed the course id I need to display the course name.
Student Controller
#RequestMapping(value = "/student", method = RequestMethod.GET)
public String viewStudentPage(Model model) {
List<Student> liststudent = services.listAll();
model.addAttribute("liststudent", liststudent);
System.out.print("Get / ");
return "Student";
}
I made the relation the below. What I tried so far now.
Course.java
#Entity
public class Course {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private Long id;
private String coursename;
private int duration;
#ManyToOne
private Student student;
public Course()
{
}
public Course(Long id, String coursename, int duration) {
this.id = id;
this.coursename = coursename;
this.duration = duration;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getCoursename() {
return coursename;
}
public void setCoursename(String coursename) {
this.coursename = coursename;
}
public int getDuration() {
return duration;
}
public void setDuration(int duration) {
this.duration = duration;
}
#Override
public String toString() {
return "Course [id=" + id + ", coursename=" + coursename + ", duration=" + duration + "]";
}
}
Student.java
#Entity
#Table(name="student")
public class Student {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private Long id;
private String stname;
private int course;
private int fee;
#OneToMany(mappedBy = "course")
private List<Student> student;
public Student() {
}
public Student(Long id, String stname, int course, int fee) {
this.id = id;
this.stname = stname;
this.course = course;
this.fee = fee;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getStname() {
return stname;
}
public void setStname(String stname) {
this.stname = stname;
}
public int getCourse() {
return course;
}
public void setCourse(int course) {
this.course = course;
}
public int getFee() {
return fee;
}
public void setFee(int fee) {
this.fee = fee;
}
#Override
public String toString() {
return "Student [id=" + id + ", stname=" + stname + ", course=" + course + ", fee=" + fee + "]";
}
}
StudentRepository
#Repository
public interface StudentRepository extends JpaRepository<Student, Long>{ }
Student.html
<table class="table">
<thead class="thead-dark">
<tr>
<th>Student ID</th>
<th>Student Name</th>
<th>Course Name</th>
<th>Fee</th>
<th>edit</th>
<th>delete</th>
</tr>
</thead>
<tbody>
<tr th:each="student : ${liststudent}">
<td th:text="${student.id}">Student ID</td>
<td th:text="${student.stname}">Student Name</td>
<td th:text="${student.course}">Course</td>
<td th:text="${student.fee}">Fee</td>
<td>
<a th:href="#{'/Student/edit/' + ${student.id}}">Edit</a>
</td>
<td>
<a th:href="#{'/Student/delete/' + ${student.id}}">Delete</a>
</td>
</tr>
</tbody>
</table>
Custom Code i wrote it to Join
#Repository
public interface StudentRepository extends JpaRepository<Student, Long>{
#Query(value="select student.id, student.stname, course.coursename from student Inner JOIN course ON student.course= course.id", nativeQuery=true)
List<Object[]> findStudent();
}
You have to add a custom query to get the course name. Your listAll() return all student object without course, the payload doesn't have any variable like name and you have course id in your entity that's why ID appearing in your UI.
Your student object have course objects also you can get like below.
you have the wrong relationship on your entity correct as below.
It should come under ManyToMany relationship because one user have many courses and one course belong to many student anyway you started as oneToMany then follow as below.
within Student Entity.
#OneToMany(fetch = FetchType.LAZY,
cascade = CascadeType.ALL,mappedBy = "student")
private List<Course> course;
within Course entity
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "id", nullable = false)
private Student student;
then try you access the course object as below.
th:field="*{student.course.name}"
if you want to try a custom query then try to as below.
#Query(value="select s.id, s.name, c.name from Student s left JOIN Course c on student.course_id= c.id", nativeQuery=true)
List<Object[]> findStudent();

Cannot show mysql data using jpa and thymeleaf

I'm very new to Spring. I'm trying to build an user management web app.
Here is the controller
#Controller
#RequestMapping("/index")
public class UserManagementController {
#Autowired
private UserManagementRepository userManagementRepository;
#RequestMapping(method= RequestMethod.GET)
public ModelAndView index(Model model){
ArrayList<Staff> staffList = (ArrayList<Staff>) userManagementRepository.findAll();
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("index");
modelAndView.addObject("staffList", staffList);
return modelAndView;
}
}
The model
#Entity
#Table(name="staff")
#Data
public class Staff {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String name;
private int age;
private String department;
private String sex;
private String status;
}
html file
<tbody>
<tr th:each="staff, state : ${staffList}">
<td th.text="${staff.id}"></td>
<td th.text="${staff.name}"></td>
<td th.text="${staff.age}"></td>
<td th.text="${staff.department}"></td>
<td th.text="${staff.department}"></td>
<td th.text="${staff.status}"></td>
</tr>
and finally the application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/user_management
spring.datasource.username=root
spring.datasource.password=
When i run the project, the table only shows the header and the body is totally blank.
I am not 100% sure but can you try to make all attributes in model public or generate getters and then change your code like:
<td th.text="${staff.getId()}"></td>
Do this:
<tr th:each="staff : ${staffList}">
That will solve your problem If not then comment below and tell whats the problem.
This should work :
<tr th:each="staff : ${staffList}">
<td th:text="${staff.id}"></td>
...
</tr>
If it doesn't, look with a debugger if the value staffList in your controller is not empty or null. If it is, then you have an issue with your database connection or request.

Haw can i show the details of each with using many to many relationship using spring and thymeleaf

I want to display the details of each user here is my class entity
#Entity
#Table(name="user")
public class User implements Serializable{
#Id #GeneratedValue
private Long id;
private String nom ;
#ManyToMany(cascade = {CascadeType.ALL})
#JoinTable(name="user_user_detail",joinColumns={
#JoinColumn(name="id")},
inverseJoinColumns={#JoinColumn(name="UserId")})
private Collection<UserDetail>userDetail ;
classe user detail
#Entity
#Table(name="userDetail")
public class UserDetail implements Serializable{
#Id #GeneratedValue
private Long UserId;
private String adresse ;
My controller
#RequestMapping(name="/vue", method = RequestMethod.GET)
public String vue(Model model){
User u=new User();
List<User>p=new ArrayList<User>();
p.add(u);
p=ur.findAll();
model.addAttribute("us",p);
return "user" ;
}
My view thymeleaf
<table border="1">
<tr>
<td>Nom</td>
<td>adresse</td>
</tr>
<tr th:each="t:${us}">
<td th:text="${t.Id}"></td>
<td th:text="${t.nom}"></td>
<td th:text="${t.getUserDetail()}"></td>
</tr>
</table>
i would to show the userdetail with
${t.getUserDetail()}">
but the result of details like this [org.sid.entity.UserDetail#1469f77e, org.sid.entity.UserDetail#78a81727]
please answer me quickly
thank's in advance

Spring MVC, load objects attributes in a jsp

I got an issue when trying to load an object attribute in a jsp file.
The model contains a list of objects of type "Evaluation", for each element in the list, all the attributes are correctly loaded except the ones that it has to fetch from another table.
The .jsp file :
<div class="container">
<h1>Liste des Evaluations pour ${etudiant.username}</h1>
<table class="tbl">
<thead>
<th>Module</th>
<th>Note</th>
<th>Remarque</th>
</thead>
<tbody>
<c:forEach items="model.evaluations" var="ev">
<tr>
<td>${ev.examen.module.code}</td> --> Error occurs here
<td>${ev.note}</td>
<td>${ev.remarque}</td>
</tr>.
</c:forEach>
</tbody>
</table>
The Controller :
#RequestMapping(value="/{username}", method=RequestMethod.GET)
public String etudiantEvaluations(
#PathVariable String username, Model model) {
List<Evaluation> evaluations = evalDAO.findAllByEtudiant(username);
Etudiant etudiant = etDAO.findByUsername(username);
model.addAttribute("evaluations", evaluations);
model.addAttribute("etudiant", etudiant);
return "etudiants/listEvaluations";
}
The Evaluation entity :
#Data
#NoArgsConstructor
#EqualsAndHashCode
#Immutable #Entity(name="TEVALUATION")
public class Evaluation {
private enum evaldeliberation {
REUSSITE,
AJOURNEMENT,
REFUS,
ABANDON
}
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
protected Long id;
#NotNull
#Min(0) #Max(100)
#Column(updatable = true)
private Double note;
#Column(name="deliberation")
private evaldeliberation delib;
#Column(name="remarque")
private String remarque;
#Column(name="module_code")
private String moduleCode;
private Long examenId;
private String etudiantUsername;
#ManyToOne(fetch=FetchType.EAGER)
#JoinColumn(name = "FKExamen",
insertable = false,
updatable = false)
protected Examen examen;
#ManyToOne
#JoinColumn(name = "FKEtudiant",
insertable = false,
updatable = false)
protected Etudiant etudiant;
#OneToMany(mappedBy="evaluation")
protected List<EvalComp> evalComps = new ArrayList<>();
public Evaluation(Double note, Examen examen, Etudiant etudiant) {
super();
this.examen = examen;
this.etudiant = etudiant;
examen.getEvaluations().add(this);
etudiant.getEvaluations().add(this);
}
}
Examen:
#Data
#EqualsAndHashCode
#NoArgsConstructor
#Entity(name="TEXAMEN")
public class Examen {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#OneToMany(mappedBy = "examen")
private Set<Evaluation> evaluations = new HashSet<>();
#NotNull
#OneToOne(cascade=CascadeType.PERSIST)
#JoinColumn(name="FKmodule")
protected Module module;
public Examen(Module module) {
this.module = module;
}
}
The Query:
#Query("SELECT ev FROM TEVALUATION ev JOIN FETCH ev.examen ex JOIN FETCH ex.module m WHERE ev.etudiant=?1")
List<Evaluation> findAllByEtudiantId(String username);
The getters and setters are generated by Lombok(also tried without it).
Any idea how can I load the attributes ?
Thanks in advance.

Hibernate OneToOne using Spring and JSP

I have a question to ask:
I have to tables user and user_login joined OneToOne by user.id -> user_login.user_id.
The issue is when I do .updateObject(user) I get 2 queries executed:
Hibernate: insert into User (created, modified, email, first_name,
last_name) values (?, ?, ?, ?, ?) Hibernate: insert into user_login
(created, modified, password, user_id) values (?, ?, ?, ?) [2012-08-15
12:15:04,192] [ERROR] [http-bio-8080-exec-1] SqlExceptionHelper [144]:
Column 'user_id' cannot be null
and looks like there is no reference between 2 objects. If into the Entity User, method setUserLogin I add line
userLogin.setUser(this); its working but I dont find this way elegant honestly. Is there anything I missed in entity configuration
maybe that does not do that automatically ?
Thank you
Here are my Entities
#Entity
#NamedQueries({ #NamedQuery(name = "user.list", query = "select u from User u") })
public class User implements java.io.Serializable {
#Column(name = "first_name", nullable = true)
private String firstName;
#OneToOne(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name="user_id", nullable=false)
private UserLogin userLogin;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public UserLogin getUserLogin() {
return userLogin;
}
public void setUserLogin(UserLogin userLogin) {
this.userLogin = userLogin;
//userLogin.setUser(this); THIS IS THE LINE THAT FIXES IT, BUT I DONT FIND THIS WAY ELEGANT
}
}
#Entity
#Table(name="user_login")
public class UserLogin implements java.io.Serializable {
#Column(name = "password", nullable = false)
private String password;
#OneToOne(optional = false, fetch = FetchType.LAZY)
private User user;
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
JSP File:
<%# taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%# taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
<html>
<head>
<title>Registration Page</title>
</head>
<body>
<form:form action="/test" commandName="user">
<tr>
<td>User Name :</td>
<td><form:input path="firstName" /></td>
</tr>
<tr>
<td>Password :</td>
<td><form:input path="userLogin.password" /></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="Register"></td>
</tr>
</table>
</form:form>
</body>
</html>
Spring Controller:
#Controller(value = "/")
public class Test {
#Autowired
UserServiceImpl userServiceImpl;
#RequestMapping(method = RequestMethod.GET, value = "/test")
public void test(ModelMap model) {
model.addAttribute("user", new User());
}
#RequestMapping(method = RequestMethod.POST, value = "/test")
public void test(User user) {
userServiceImpl.update(user);
}
}
As usual, bidirectional relationships do have owning side. Owning side of relationship is attribute that is referenced by mappedBy. In your case attribute user in UserLogin entity is the owning side.
When relationship is persisted to the database, only owning side is consulted. This means, that you have to set value for user attribute to be able to persist. To keep also entity graph in memory consistent both sides of the relationship should be set.
In JPA 2.0 specification this is told with following words:
Bidirectional relationships between managed entities will be persisted
based on references held by the owning side of the relationship. It is
the developer’s responsibility to keep the in-memory references held
on the owning side and those held on the inverse side consistent with
each other when they change.

Resources