Hibernate One to Many Mapping trong Spring Web MVC và cơ sở dữ liệu Oracle
Đăng lúc: 08:01 PM - 26/10/2023 bởi Charles Chung - 906Trong bài viết này tôi sẽ hướng dẫn các bạn cách tạo quan hệ One to Many Mapping cho các Entity trong Hibernate, demo sử dụng Spring Web MVC và cơ sở dữ liệu Oracle, ngoài ra còn sử dụng thư viện xử lý upload ảnh kèm dữ liệu.
1. Kiến thức cần có
- Căn bản về Oracle database, cách cài đặt cơ sở dữ liệu Oracle, công cụng SQL Developer, tạo database xem ở đây
- Lập trình Java Core
- HTML - CSS - JavaScript
- JSP và Servlet
2. Các bước tạo ứng dụng Spring Hibernate và thực hiện các thao tác CRUD
Bước 1: Mở SQL Developer tạo bảng và nhập dữ liệu ( xem file db.sql đính kèm trong source code)
Bước 2: Tạo Dynamic Web Project
- Khởi động Eclispe IDE -> vào menu File -> New -> Dynamic Web Project -> Nhập tên project "MappingJoinSpringHibernateOracle"
- Tiếp tục kích vào Next -> Next -> Chọn Generate web.xml deyployment desciptor và kích Finish
Bước 3: Convert sang Maven Project
- Kích chuột phải vào Project vừa tạo -> Configure -> Convert to Maven Project -> Finish
Bước 4: Khai báo các Maven Dependencies cần thiết
- Mở file pom.xml và cấu hình các Maven Dependencies gồm: spring web, web mvc, spring-orm, hibernate, jdbc oracle, servlet api, jstl (xem bài trước), bổ sung thêm upload file dependency vào nhé
<!--https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.13.0</version>
</dependency>
Bước 5: Cấu hình ứng dụng Spring Web Mvc
- Trong thư mục WEB-INF tạo thư mục views và tệp tin spring-servlet.xml (xem bài trước), bổ sung thêm đoạn cấu hình sau
<!-- Cấu hình đường dẫn tài nguyên được phép truy cập trong thư mục gốc -->
<mvc:resources mapping="/**" location="/" />
<!-- Tạo bean xác định dữ liệu multipart khi upload file -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" />
- Mở tệp web.xml và cấu hình vào bên trong thẻ <web-app> (xem bài trước)
Bước 6: Tạo các tệp tin theo cấu trúc mô tả sau
Bước 7: Code cho các tệp theo gợi ý sau
- Tệp entities/Emloyee.java
package entities;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.springframework.format.annotation.DateTimeFormat;
@Entity
@Table(name="employees")
public class Employee implements Serializable {
@Id
@Column(name="employeeid")
private String employeeId;
@Column(name="fullname")
private String fullName;
@Column(name="birthday")
@Temporal(value = TemporalType.DATE)
@DateTimeFormat(pattern = "dd/MM/yyyy")
private Date birthDay;
@Column(name="picture")
private String picture;
@Column(name="gender")
private int gender;
@Column(name="address")
private String address;
@Column(name="phone")
private String phone;
@Column(name="email")
private String email;
@Column(name="departmentid")
private int departmentId;
@Column(name="active")
private int active;
@ManyToOne(fetch = FetchType.LAZY) // khi nào cần thì load phòng ban theo nhân viên
@JoinColumn(name="departmentId",insertable = false, updatable = false)
private Department department;
public Employee() {
// TODO Auto-generated constructor stub
}
public String getEmployeeId() {
return employeeId;
}
public void setEmployeeId(String employeeId) {
this.employeeId = employeeId;
}
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
public Date getBirthDay() {
return birthDay;
}
public void setBirthDay(Date birthDay) {
this.birthDay = birthDay;
}
public String getPicture() {
return picture;
}
public void setPicture(String picture) {
this.picture = picture;
}
public int getGender() {
return gender;
}
public void setGender(int gender) {
this.gender = gender;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public int getDepartmentId() {
return departmentId;
}
public void setDepartmentId(int departmentId) {
this.departmentId = departmentId;
}
public int getActive() {
return active;
}
public void setActive(int active) {
this.active = active;
}
public Department getDepartment() {
return department;
}
public void setDepartment(Department department) {
this.department = department;
}
}
- Tệp entities/Department.java
package entities;
import java.io.Serializable;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Entity
@Table(name="departments")
public class Department implements Serializable {
@Id
@Column(name="departmentid")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int departmentId;
@Column(name="departmentname")
private String departmentName;
@Column(name="active")
private int active;
// tạo quan hệ với employee thông qua trường department, lazy: khi nào cần thì load nhân viên, all: sử dụng mọi cascade
@OneToMany(mappedBy = "department",fetch = FetchType.LAZY)
private List<Employee> employees;
public Department() {
// TODO Auto-generated constructor stub
}
public int getDepartmentId() {
return departmentId;
}
public void setDepartmentId(int departmentId) {
this.departmentId = departmentId;
}
public String getDepartmentName() {
return departmentName;
}
public void setDepartmentName(String departmentName) {
this.departmentName = departmentName;
}
public int getActive() {
return active;
}
public void setActive(int active) {
this.active = active;
}
public List<Employee> getEmployees() {
return employees;
}
public void setEmployees(List<Employee> employees) {
this.employees = employees;
}
}
- Tệp dao/GenericDAO.java
package dao;
import java.util.List;
public interface GenericDAO<T,K> {
public List<T> getAll();
public T find(K key);
public void add(T obj);
public void update(T obj);
public void delete(K key);
public List<T> search(String name);
}
- Tệp dao/DepartmentDAO.java
package dao;
import java.util.List;
import entities.Department;
public interface DepartmentDAO extends GenericDAO<Department, Integer> {
}
- Tệp dao/DepartmentImpl.java
package dao;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import entities.Department;
@Repository
public class DepartmentImpl implements DepartmentDAO {
@Autowired
private SessionFactory sessionFactory;
public List<Department> getAll()
{
Session session=sessionFactory.openSession();
session.beginTransaction();
List result=session.createQuery("from Department").list();
session.getTransaction().commit();
return result;
}
@Override
public Department find(Integer key) {
Session session=sessionFactory.getCurrentSession();
session.beginTransaction();
Department dep= session.find(Department.class, key);
session.getTransaction().commit();
return dep;
}
@Override
public void add(Department obj) {
Session session=sessionFactory.getCurrentSession();
session.beginTransaction();
session.save(obj);
session.getTransaction().commit();
}
@Override
public void update(Department obj) {
Session session=sessionFactory.getCurrentSession();
session.beginTransaction();
session.update(obj);
session.getTransaction().commit();
}
@Override
public void delete(Integer key) {
Session session=sessionFactory.getCurrentSession();
session.beginTransaction();
Department dep= session.find(Department.class, key);
session.remove(dep);
session.getTransaction().commit();
}
@Override
public List<Department> search(String name) {
Session session=sessionFactory.openSession();
session.beginTransaction();
List result=session.createQuery("from Department where departmentName like :name").setParameter("name", "%"+name+"%").list();
session.getTransaction().commit();
return result;
}
}
- Tệp dao/EmployeeDAO.java
package dao;
import java.util.List;
import entities.Employee;
public interface EmployeeDAO extends GenericDAO<Employee, String> {
public List<Employee> paging(int page, int pagesize);
public List<Employee> findByDepartment(int key);
}
- Tệp dao/EmployeeImpl.java
package dao;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import entities.Department;
import entities.Employee;
@Repository
public class EmployeeImpl implements EmployeeDAO {
@Autowired
private SessionFactory sessionFactory;
@Override
public List<Employee> getAll() {
Session session=sessionFactory.openSession();
session.beginTransaction();
List result=session.createQuery("from Employee").list();
session.getTransaction().commit();
return result;
}
@Override
public Employee find(String key) {
Session session=sessionFactory.getCurrentSession();
session.beginTransaction();
Employee emp= session.find(Employee.class, key);
session.getTransaction().commit();
return emp;
}
@Override
public void add(Employee obj) {
Session session=sessionFactory.getCurrentSession();
session.beginTransaction();
session.save(obj);
session.getTransaction().commit();
}
@Override
public void update(Employee obj) {
Session session=sessionFactory.getCurrentSession();
session.beginTransaction();
session.update(obj);
session.getTransaction().commit();
}
@Override
public void delete(String key) {
Session session=sessionFactory.getCurrentSession();
session.beginTransaction();
Employee dep= session.find(Employee.class, key);
session.remove(dep);
session.getTransaction().commit();
}
@Override
public List<Employee> search(String name) {
Session session=sessionFactory.openSession();
session.beginTransaction();
List result=session.createQuery("from Employee where fullName like :name").setParameter("name", "%"+name+"%").list();
session.getTransaction().commit();
return result;
}
@Override
public List<Employee> paging(int page, int pagesize) {
Session session=sessionFactory.openSession();
session.beginTransaction();
List result=session.createQuery("from Employee").setFirstResult((page-1)*pagesize).setMaxResults(pagesize).list();
session.getTransaction().commit();
return result;
}
@Override
public List<Employee> findByDepartment(int key) {
Session session=sessionFactory.openSession();
session.beginTransaction();
List result=session.createQuery("from Employee where departmentId like :depid").setParameter("depid", key).list();
session.getTransaction().commit();
return result;
}
}
- Tệp controllers/HomeController.java
package controllers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import dao.DepartmentImpl;
import dao.EmployeeImpl;
import entities.Employee;
@Controller
public class HomeController {
@Autowired
private DepartmentImpl departmentImpl;
@Autowired
private EmployeeImpl employeeImpl;
public HomeController() {
// TODO Auto-generated constructor stub
}
@RequestMapping(value= {"/","danh-muc.htm"},method = RequestMethod.GET)
public String index(Model model) {
model.addAttribute("departments", departmentImpl.getAll());
return "index";
}
@RequestMapping(value= "them-nhan-vien.htm",method = RequestMethod.GET)
public String addEmployee(Model model) {
model.addAttribute("departments", departmentImpl.getAll());
model.addAttribute("employee",new Employee());
return "createEmployee";
}
@RequestMapping(value= "luu-nhan-vien.htm",method = RequestMethod.POST)
public String saveEmployee(@ModelAttribute("employee")Employee employee,@RequestParam(value="files")MultipartFile[] files,Model model, HttpServletRequest req) {
//upload 1 ảnh
if(files.length>0) {
String uploadRootPath = req.getServletContext().getRealPath("images");
System.out.println(uploadRootPath+"/"+files[0].getOriginalFilename());
File destination = new File(uploadRootPath+"/"+files[0].getOriginalFilename());
try {
files[0].transferTo(destination);
} catch (IllegalStateException | IOException e) {
e.printStackTrace();
}
employee.setPicture("images/"+files[0].getOriginalFilename());
}
employeeImpl.add(employee);
return "redirect:danh-muc.htm";
}
@RequestMapping(value= "xoa-nhan-vien.htm",method = RequestMethod.GET)
public String delete(@RequestParam(value="id")String id) {
employeeImpl.delete(id);
return "redirect:danh-muc.htm";
}
}
- Tệp views/index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Danh sách phòng ban - nhân viên</title>
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<h1>DANH SÁCH PHÒNG BAN</h1>
<p>
<a class="btn btn-success" href="them-nhan-vien.htm">Thêm nhân viên</a>
</p>
<div class="accordion" id="accordionExample">
<c:forEach var="d" items="${departments}">
<div class="card">
<div class="card-header" id="headingOne">
<h2 class="mb-0">
<button class="btn btn-block text-left" type="button"
data-toggle="collapse" data-target="#D${d.departmentId}"
aria-expanded="true" aria-controls="collapseOne">
${d.departmentName}</button>
</h2>
</div>
<div id="D${d.departmentId}" class="collapse"
aria-labelledby="headingOne" data-parent="#accordionExample">
<div class="card-body">
<h4>Danh sách nhân viên</h4>
<table class="table table-bordered">
<tr>
<th>Mã</th>
<th>Tên</th>
<th>Ảnh</th>
<th>Tình trạng</th>
<th></th>
</tr>
<c:forEach var="e" items="${d.employees}">
<tr>
<td>${e.employeeId}</td>
<td>${e.fullName}</td>
<td><img src="${e.picture}" width="100" /></td>
<td>
<c:choose>
<c:when test="${e.active==1}">Đang làm</c:when>
<c:otherwise>Đã nghỉ</c:otherwise>
</c:choose>
</td>
<td><a class="btn btn-danger"
onclick="return confirm('Bạn có muốn xóa không?')"
href="xoa-nhan-vien.htm?id=${e.employeeId}">Xóa</a></td>
</tr>
</c:forEach>
</table>
</div>
</div>
</div>
</c:forEach>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.min.js"></script>
</body>
</html>
- Tệp views/createEmployee.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="f" uri="http://www.springframework.org/tags/form"%>
<!DOCTYPE html>
<html>
<head>
<title>Thêm mới nhân viên</title>
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<h1>Thêm mới nhân viên</h1>
<f:form action="luu-nhan-vien.htm" modelAttribute="employee"
method="post" enctype="multipart/form-data">
<table class="table">
<tr>
<td>Mã số</td>
<td><f:input path="employeeId" /></td>
</tr>
<tr>
<td>Tên nhân viên</td>
<td><f:input path="fullName" /></td>
</tr>
<tr>
<td>Ngày sinh</td>
<td><f:input path="birthDay" /></td>
</tr>
<tr>
<td>Giới tính</td>
<td>
<select name="gender" id="gender">
<option value="1">Nam</option>
<option value="0">Nữ</option>
</select>
</td>
</tr>
<tr>
<td>Địa chỉ</td>
<td><f:input path="address" /></td>
</tr>
<tr>
<td>Điện thoại</td>
<td><f:input path="phone" /></td>
</tr>
<tr>
<td>Email</td>
<td><f:input type="email" path="email" /></td>
</tr>
<tr>
<td>Phòng ban</td>
<td>
<f:select path="departmentId" items="${departments}" itemLabel="departmentName" itemValue="departmentId"></f:select>
</td>
</tr>
<tr>
<td>Ảnh</td>
<td><input type="file" id="files" name="files"
multiple="multiple" accept="image/*" />
</tr>
<tr>
<td>Tình trạng</td>
<td>
<select name="active" id="active">
<option value="1">Đang làm</option>
<option value="0">Đã nghỉ</option>
</select>
</td>
</tr>
<tr>
<td colspan="2"><button>Lưu</button></td>
</tr>
</table>
</f:form>
</div>
</body>
</html>
Bước 8: Run application
- Kích chuột phải vào project chọn Run As -> Run on Server -> Tomcat v9.0
Kích để tải source code bài Hibernate One to Many Mapping trong Spring Web MVC và cơ sở dữ liệu Oracle
Kích để tải dource code phiên bản làm việc với cơ sở dữ liệu SQL Server
Training online liên hệ: Charles Chung
Video
thay lời cảm ơn!
Các bài cũ hơn
- CRUD trong ứng dụng Spring Web MVC với Hibernate-Oracle Database (11:02 AM - 25/10/2023)
- Các cách gửi nhận dữ liệu trong Spring MVC (11:27 AM - 24/10/2023)
- Tạo và cấu hình ứng dụng Spring Web Mvc với Maven Dependencies sử dụng Eclipse IDE (09:27 PM - 22/10/2023)
- Một số Maven Dependencies dùng trong các dự án Java (09:56 AM - 18/10/2023)
- Tạo ER Diagram trong SQL Developer Oracle (11:03 AM - 13/10/2023)