@GeneratedValue(strategy = GenerationType.IDENTITY)로 지정을 해줘야 auto-increment 속성이 테이블 별로 지정이된다.
@GeneratedValue(strategy = GenerationType.AUTO)로 지정 시 모든 테이블의 auto-increment 값이 공유되기 때문에 관리가 어려움
파일경로 지정시 templates, static 등 프로젝트 생성시 기본 생성 되는 폴더들은 경로 지정시 생략가능
언뜻 보면 eager속성이 한번에 가져오니까 좋아보이지만 수많은 테이블이 존재 할 때는 필요하지 않은 데이터까지 불러오게 되므로 리소스를 많이 차지 하게 됨으로써 많은 문제가 발생하므로
LAZY속성을 이용하도록 하자.
// project
@OneToMany(mappedBy = "project") // 1 : n의 관계, 상호연관관계일 때 사용, ManyToOne의 변수명, Project 테이블에 맵핑
// Cascade는 수정, 삭제 시 연관데이터 조작여부체크, Fetch는 lazy일 때 연관 테이블 데이터를 천천히
private List<Employee> employees;
// employee
@ManyToOne(cascade = {CascadeType.DETACH, CascadeType.MERGE,
CascadeType.PERSIST, CascadeType.REFRESH},
fetch = FetchType.LAZY) // n : 1 관계, 여러명의 직원 : 하나의 프로젝트
// Cascade는 수정, 삭제 시 연관데이터 조작여부체크, Fetch는 lazy일 때 연관 테이블 데이터를 천천히
@JoinColumn(name = "project_id") // 테이블에 "project_id" column 넣기, 외래키 열
private Project project;
// project
@ManyToMany(cascade = { CascadeType.DETACH, CascadeType.MERGE,
CascadeType.REFRESH }, fetch = FetchType.LAZY) // n : 1 관계, 여러명의 직원 : 하나의 프로젝트
// Cascade는 수정, 삭제 시 연관데이터 조작여부체크, Fetch는 lazy일 때 연관 테이블 데이터를 천천히
@JoinTable(name = "project_employee", joinColumns = @JoinColumn(name = "project_id"),
inverseJoinColumns = @JoinColumn(name = "employee_id"))
// n : n 관계에서는 테이블을 만들고 생성한 테이블에 id를 넣고 다른 테이블의 id도 입력
private List<Employee> employees;
// employee
@ManyToMany(cascade = {CascadeType.DETACH, CascadeType.MERGE,
CascadeType.REFRESH},
fetch = FetchType.LAZY)// n : 1 관계, 여러명의 직원 : 하나의 프로젝트
// Cascade는 수정, 삭제 시 연관데이터 조작여부체크, Fetch는 lazy일 때 연관 테이블 데이터를 천천히
@JoinTable(name = "project_employee", joinColumns = @JoinColumn(name = "employee_id"),
inverseJoinColumns = @JoinColumn(name = "project_id"))
// n : n 관계에서는 테이블을 만들고 생성한 테이블에 id를 넣고 다른 테이블의 id도 입력
private List<Project> projects;
package com.myapp.pma;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import com.myapp.pma.dao.EmployeeRepository;
import com.myapp.pma.dao.ProjectRepository;
import com.myapp.pma.entities.Employee;
import com.myapp.pma.entities.Project;
@SpringBootApplication
public class PmaApplication {
@Autowired
private EmployeeRepository empRepo;
@Autowired
private ProjectRepository proRepo;
public static void main(String[] args) {
SpringApplication.run(PmaApplication.class, args);
}
// 프로그램 실행시 자동으로 DB에 입력하는 코드
@Bean
CommandLineRunner runner() {
return args -> {
// 프로그램 실행시 코드
Employee emp1 = new Employee("길동", "홍", "hong@gmail.com");
Employee emp2 = new Employee("라니", "고", "go@gmail.com");
Employee emp3 = new Employee("스티븐", "킹", "king@gmail.com");
Employee emp4 = new Employee("날두", "호", "ho@gmail.com");
Employee emp5 = new Employee("펭수", "김", "kim@gmail.com");
Employee emp6 = new Employee("피터", "팬", "pen@gmail.com");
Employee emp7 = new Employee("순신", "이", "lee@gmail.com");
Employee emp8 = new Employee("감찬", "강", "kang@gmail.com");
Employee emp9 = new Employee("유신", "김", "yousin@gmail.com");
Project pro1 = new Project("대형 프로젝트", "시작전", "할일이 많음");
Project pro2 = new Project("새 직원 인사", "완료", "필요한 부서의 새 직원 고용");
Project pro3 = new Project("오피스 리모델링", "진행중", "오래된 오피스 환경을 새것처럼 리모델링");
Project pro4 = new Project("회사 보안 강화", "진행중", "출 입문 인증 지문센서 추가");
// project 에 직원들을 추가하고 , employee 객체에 프로젝트들을 추가한다.
// project에 새 메서드 작성
pro1.addEmployee(emp1);
pro1.addEmployee(emp2);
pro2.addEmployee(emp3);
pro3.addEmployee(emp1);
pro4.addEmployee(emp1);
pro4.addEmployee(emp3);
empRepo.save(emp1);
empRepo.save(emp2);
empRepo.save(emp3);
empRepo.save(emp4);
empRepo.save(emp5);
empRepo.save(emp6);
empRepo.save(emp7);
empRepo.save(emp8);
empRepo.save(emp9);
proRepo.save(pro1);
proRepo.save(pro2);
proRepo.save(pro3);
proRepo.save(pro4);
};
}
}
// project.java
// 프로젝트 객체에서 직원을 추가하는 메소드
public void addEmployee(Employee emp) {
if (employees == null) {
employees = new ArrayList<>();
}
employees.add(emp);
}
spring.jpa.defer-datasource-initialization=true
<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head th:replace="layouts::헤드"> </head>
<body>
<nav th:replace="layouts:: 네브바"></nav>
<div class="container">
<h3>프로젝트 진행 상황</h3>
<div class="row">
<div class="col-md-7">
<table class="table table-hover">
<thead class="table-dark">
<tr>
<th>프로젝트 이름</th>
<th>현재 진행상태</th>
</tr>
</thead>
<tbody>
<!-- thymeleaf의 반복문-->
<tr th:each="project : ${projectList}">
<td th:text="${project.name}"></td>
<td class="stage" th:text="${project.stage}"></td>
</tr>
</tbody>
</table>
</div>
<div class="col-md-3 ms-5">
<canvas id="myChart"></canvas>
</div>
</div>
</div>
<div class="container">
<h1>직원 현황</h1>
<table class="table table-hover">
<thead class="table-dark">
<tr class="fw-bold">
<th>성</th>
<th>이름</th>
<th>이메일</th>
</tr>
</thead>
<tbody>
<tr th:each="employee : ${employeeList}">
<td th:text="${employee.lastName}"></td>
<td th:text="${employee.firstName}"></td>
<td th:text="${employee.email}"></td>
</tr>
</tbody>
</table>
</div>
<footer th:replace="layouts::푸터"></footer>
<!-- 홈페이지에만 필요한 차트 만들기-->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script th:src="@{/js/chart.js}"></script>
</body>
</html>
const stages = document.querySelectorAll('.stage');
let s1 = 0;
let s2 = 0;
let s3 = 0;
stages.forEach((stage) => {
if (stage.textContent === '시작전') s1++;
else if (stage.textContent === '진행중') s2++;
else if (stage.textContent === '완료') s3++;
});
const data = {
labels: ['시작전', '진행중', '완료'],
datasets: [
{
label: 'My First Dataset',
data: [s1, s2, s3],
backgroundColor: ['rgb(255, 99, 132)', 'rgb(54, 162, 235)', 'rgb(255, 205, 86)'],
hoverOffset: 4,
},
],
};
const config = {
type: 'pie',
data: data,
};
const myChart = new Chart(document.getElementById('myChart'), config);