@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "mydept")
public class DeptEntity {
@Id
@GeneratedValue
@Column(name = "deptNo")
private Long id;
private String name;
private String mgr;
//양방향관계에서는 항상 기준이 되는 엔티티는 외래키 테이블을 표현한 엔티티
//현테이블과 매핑되는 테이블이 엔티티에서 어떤 컬럼명으로 명시되어 있는지 정의
//양방향에서는 mappedBy 속성을 이용해서 내가 뭐에 의해서 매핑이 됐는지 명시
//상대엔티티에서 현 엔티티를 매핑하고 있는 변수명을 정의
//mappedBy가 정의되어있는 엔티티에서는 조회만 가능하도록 처리
@OneToMany(mappedBy = "dept")
//양방향참조에서 toString을 호출하면 순환참조오류가 발생한다.
//dept에서 emp의 toString을 호출하고 emp에서 dept의 toString을 호출한다.
//직접호출하지않아도 JSON객체를 만들때 내부에서 toString을 호출하는 상황이 만들어진다.
@ToString.Exclude //toString메소드에 해당컬럼을 포함하지 않겠다는 의미
private List<EmpEntity> emplist = new ArrayList<>();
public DeptEntity(String name, String mgr) {
this.name = name;
this.mgr = mgr;
}
}
//단방향으로 작업
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "myemp")
public class EmpEntity extends PublicInfoEntity {
@Id
private String userId;
private String name;
private String addr;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "userPrivateId")
private PrivateInfoEntity infoEntity;
public EmpEntity(String userId, String name, String addr, PrivateInfoEntity infoEntity) {
this.userId = userId;
this.name = name;
this.addr = addr;
this.infoEntity = infoEntity;
}
//경력사항은 한 사람이 여러 개 가질 수 있다.
@OneToMany(mappedBy = "emp", cascade = CascadeType.ALL)
// @JoinColumn(name = "userKey")
private List<HistoryEntity> historylist = new ArrayList<>();
@ManyToOne
@JoinColumn(name = "deptId")
private DeptEntity dept;
//양방향관계에서 주데이터 이외의 새로 추가된 데이터가 반영된다.
public void changeVal(HistoryEntity history){
historylist.add(history);
history.setEmp(this);
}
//모든정보를 Emp에 저장하기
//양방향관계에서 기본객체가 아닌 객체도 데이터가 반영될 수 있도록 처리하기
public static EmpEntity buildEmpEntity(String userId, String name, String addr,
PrivateInfoEntity infoEntity, List<HistoryEntity> historylist, DeptEntity dept){
EmpEntity entity = new EmpEntity(userId,name,addr,infoEntity,dept);
//historylist에서 history를 꺼내서 emp를 셋팅
for (HistoryEntity history:historylist){
entity.changeVal(history);
}
return entity;
}
public EmpEntity(String userId, String name, String addr, PrivateInfoEntity infoEntity, List<HistoryEntity> historylist) {
this.userId = userId;
this.name = name;
this.addr = addr;
this.infoEntity = infoEntity;
this.historylist = historylist;
}
public EmpEntity(String userId, String name, String addr, PrivateInfoEntity infoEntity, DeptEntity dept) {
this.userId = userId;
this.name = name;
this.addr = addr;
this.infoEntity = infoEntity;
this.dept = dept;
}
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "myhistory")
public class HistoryEntity {
@Id
@GeneratedValue
private Long historyId;
private String company;
private String content;
@ManyToOne
@JoinColumn(name = "id")
private EmpEntity emp;
public HistoryEntity(String company, String content) {
this.company = company;
this.content = content;
}
}
@SpringBootTest
@Transactional
@Rollback(value = false)
class JPAWayTest {
@PersistenceContext
EntityManager entityManager;
@Test
public void test1() {
//초기데이터 저장하기
DeptEntity dept1 = new DeptEntity("전산실", "RM");
DeptEntity dept2 = new DeptEntity("인사팀", "슈가");
DeptEntity dept3 = new DeptEntity("기획실", "뷔");
entityManager.persist(dept1);
entityManager.persist(dept2);
entityManager.persist(dept3);
//사원을 등록할 때 경력 사항을 같이 등록하기
//파라미터로 전달 받은 부서 코드를 이용해서 부서 정보 조회
PrivateInfoEntity privateInfo1 =
new PrivateInfoEntity("bts1", "태양과 듀엣", "솔로");
PrivateInfoEntity privateInfo2 =
new PrivateInfoEntity("bts2", "Seven", "올림픽곡");
PrivateInfoEntity privateInfo3 =
new PrivateInfoEntity("bts3", "춤모야", "조교");
PrivateInfoEntity privateInfo4 =
new PrivateInfoEntity("bts4", "제대했다", "너무해");
PrivateInfoEntity privateInfo5 =
new PrivateInfoEntity("kbr", "싱어송라이터", "바람바람바람");
//경력사항 3개
List<HistoryEntity> historyEntityList = new ArrayList<>();
historyEntityList.add(new HistoryEntity("A사", "front개발"));
historyEntityList.add(new HistoryEntity("B사", "Entity개발"));
historyEntityList.add(new HistoryEntity("C사", "보안"));
EmpEntity emp1 = new EmpEntity("bts1", "지민", "광주"
, privateInfo1, historyEntityList, dept1);
EmpEntity emp2 = new EmpEntity("bts2", "정국", "부산", privateInfo2, dept1);
EmpEntity emp3 = new EmpEntity("bts3", "제이홉", "광주", privateInfo3, dept2);
EmpEntity emp4 = new EmpEntity("bts4", "석진", "천안", privateInfo4, dept2);
EmpEntity emp5 = new EmpEntity("kbr", "범룡", "청주", privateInfo5, dept3);
entityManager.persist(emp1);
entityManager.persist(emp2);
entityManager.persist(emp3);
entityManager.persist(emp4);
entityManager.persist(emp5);
}
@Test
public void test2() {
//dept데이터 조회하기 : Dept -> Emp
//ctrl+alt+L
//1번부서
DeptEntity deptEntity = entityManager.find(DeptEntity.class, 1L);
System.out.println(deptEntity);
//양방향은 양쪽의 모든 엔티티에서 각자방향으로 객체를 접근할 수 있다.
List<EmpEntity> emplist = deptEntity.getEmplist();
for (EmpEntity emp : emplist) {
System.out.println(emp + "=>" + emp.getDept());
}
}
@Test
public void test3() {
//emp조회 : Emp -> Dept
EmpEntity empEntity = entityManager.find(EmpEntity.class, "bts1");
System.out.println(empEntity);
System.out.println(empEntity.getDept().getName());
}
@Test
public void test4() {
//새로운 사원을 등록
DeptEntity dept = entityManager.find(DeptEntity.class, "2");
System.out.println(dept);
List<HistoryEntity> historyEntityList = new ArrayList<>();
historyEntityList.add(new HistoryEntity("D사", "front react개발"));
historyEntityList.add(new HistoryEntity("E사", "Entity개발"));
historyEntityList.add(new HistoryEntity("A사", "보안개발"));
EmpEntity emp = new EmpEntity("bts7", " 슈가", "대구",
new PrivateInfoEntity("bts7", "화양연화", "래퍼"),
historyEntityList, dept);
entityManager.persist(emp);
}
@Test
public void test5() {
//새로 삽입된 데이터를 조회하기 - Emp기준
EmpEntity empEntity = entityManager.find(EmpEntity.class, "bts7");
System.out.println("bts7의 부서정보=>"+empEntity.getDept());
}
@Test
public void test6() {
//새로 삽입된 데이터를 조회하기 - Dept 기준
DeptEntity deptEntity = entityManager.find(DeptEntity.class, 2L);
System.out.println(deptEntity);
//양방향은 양쪽의 모든 엔티티에서 각자방향으로 객체를 접근할 수 있다.
List<EmpEntity> emplist = deptEntity.getEmplist();
for (EmpEntity emp : emplist) {
System.out.println(emp.getUserId());
}
}
@Test
public void test7() {
//양방향으로 매핑되어있는 객체는
//방향시 연관관계에서 주인이 아닌 역방향에 관계를 설정해서 코드를 넣지 않는다.
// - mapped by 가 정의되어있는 엔티티는 조회만한다.
//주체가 아닌 것을 이용해서 insert를 했기 때문에 dept가 셋팅되지 않는다.
EmpEntity emp = new EmpEntity("bts5", " 뷔", "서울",
new PrivateInfoEntity("bts5", "화랑", "서진이네"));
entityManager.persist(emp);
DeptEntity dept = new DeptEntity("TF팀","kbr");
dept.getEmplist().add(emp);
entityManager.persist(dept);
}
@Test
public void test8() {
DeptEntity dept = new DeptEntity("서비스팀","장동건");
entityManager.persist(dept);
EmpEntity emp = new EmpEntity("bts7", "슈가", "대구",
new PrivateInfoEntity("bts7", "화양연화", "래퍼"),dept);
entityManager.persist(emp);
}
@Test
public void test9() {
DeptEntity dept = entityManager.find(DeptEntity.class, "2");
System.out.println(dept);
List<HistoryEntity> historyEntityList = new ArrayList<>();
historyEntityList.add(new HistoryEntity("D사", "front react개발"));
historyEntityList.add(new HistoryEntity("E사", "Entity개발"));
historyEntityList.add(new HistoryEntity("A사", "보안개발"));
//주객체와 양방향매핑되는 객체에 변경된 내용을 반영시키기
EmpEntity emp = EmpEntity.buildEmpEntity("lee2", "이민호", "서울",
new PrivateInfoEntity("lee2", "신의", "푸른바다의전설"),
historyEntityList, dept);
entityManager.persist(emp);
}
}

//view를 랜더링하는 컨트롤러
@Controller
@RequestMapping("/category")
@RequiredArgsConstructor
public class CategoryController {
private final CategoryService service;
//page보기
@GetMapping("write")
public String categoryRegisterPage(){
return "manage/product/category";
}
@PostMapping("write")
public String categoryRegister(CategoryRequestDTO inputdto){
System.out.println(inputdto);
service.write(inputdto);
return "manage/product/category";
}
}

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{layout/mainLayout}">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<div class="container-fluid" layout:fragment="content">
<h1>카테고리 등록</h1>
<hr/>
<form class="form-horizontal" action="/erp/category/write" method="POST" name="myform">
<fieldset>
<div class="form-group">
<!-- 카테고리명-->
<div><a href="/erp/catgory/list">카테고리목록</a></div>
</div>
<div class="form-group">
<!-- 카테고리명-->
<label class="control-label col-sm-2" for="categoryName">카테고리명</label>
<div class="col-sm-3">
<input type="text" id="categoryName" name="categoryName"
placeholder="카테고리명"
class="form-control" >
</div>
</div>
<div class="form-group">
<!-- 비고-->
<label class="control-label col-sm-2" for="info">비고</label>
<div class="col-sm-3">
<input type="text" id="info" name="info"
placeholder="비고"
class="form-control" >
</div>
</div>
<div class="form-group">
<!-- Button -->
<div class="col-sm-3 col-sm-offset-2">
<input type="submit" value="등록하기" class="btn btn-success"/>
</div>
</div>
</fieldset>
</form>
</div>
</body>
</html>
@Repository
@RequiredArgsConstructor
public class CategoryDAOImpl implements CategoryDAO{
//스프링프레임워크가 CategoryRepository의 구현체를 만들어서 autowired한다.
private final CategoryRepository repository;
@Override
public void write(CategoryEntity category) {
//create
repository.save(category);
}
@Override
public List<CategoryEntity> findAll() {
//List
return repository.findAll();
}
@Override
public List<CategoryEntity> pagingFindAll() {
return List.of();
}
@Override
public CategoryEntity findById(long categoryId) {
//read
return repository.findById(categoryId).get();
}
}
@Service
@RequiredArgsConstructor
public class CategoryServiceImpl implements CategoryService{
private final CategoryDAO dao;
@Override
public void write(CategoryRequestDTO category) {
//컨트롤러에서 넘겨받은 CategoryRequestDTO를 entity로 변환해서 넘기기
//step01 - 생성자를 이용해서 직접 변경
CategoryEntity entity = new CategoryEntity(category.getCategoryName(),
category.getInfo());
dao.write(entity);
}
@Override
public List<CategoryResponseDTO> findAll() {
return List.of();
}
@Override
public List<CategoryResponseDTO> pagingFindAll() {
return List.of();
}
@Override
public CategoryResponseDTO findById(long categoryId) {
//Entity를 DTO로 변환해서 넘기기
//step2 builder를 활용해서 작업하기
CategoryEntity entity = dao.findById(categoryId);
return CategoryResponseDTO.builder()
.categoryId(entity.getCategoryId())
.categoryName(entity.getCategoryName())
.info(entity.getInfo())
.build();
}
}
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
public class CategoryResponseDTO {
private Long categoryId;
private String categoryName;
private String info;
}
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
public class CategoryRequestDTO {
private String categoryName;
private String info;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "category")
public class CategoryEntity {
@Id
@GeneratedValue
private Long categoryId;
private String categoryName;
private String info;
public CategoryEntity(String categoryName, String info) {
this.categoryName = categoryName;
this.info = info;
}
}
//api패키지의 모든 컨트롤러는 RestController
//JSON을 리턴하는 메소드
@RestController
@RequiredArgsConstructor
@RequestMapping("/api")
//로그기록
@Slf4j
public class CategoryAPIController {
private final CategoryService categoryService;
//카테고리를 추가하기 위한 데이터를 JSON으로 입력받고 싶은 경우
//JSON으로 입력데이터를 만들어서 요청하면 스프링이 DTO로 변환
//작업이 완료되면 성공완료됐는지만 넘기기
//@RequestBody ---> json데이터 -> DTO로 변환해서 매개변수에 전달
//@RequestBody ---> 자바객체 -> json데이터로 변환해서 응답
@PostMapping("/category/insert")
public ResponseEntity<?> insert(@RequestBody CategoryRequestDTO inputdata){
System.out.println(inputdata);
categoryService.write(inputdata);
//ResponseEntity는 상태코드와 응답데이터의 본문을 설정
//성공응답을 200 응답을 생성하고 별도의 본문없이 응답을 반환 - ok메시지
// return ResponseEntity.ok().build(); ->원래 이렇게하면됨 밑은 ok사인 찍고싶어서하는것
return ResponseEntity.ok(HttpStatus.OK);
}
@GetMapping("/category/{categoryId}")
public CategoryResponseDTO read(@PathVariable("categoryId") String catrgoryId){
return categoryService.findById(Long.parseLong(catrgoryId));
}
}


본 포스팅은 멀티캠퍼스의 멀티잇 백엔드 개발(Java)의 교육을 수강하고 작성되었습니다.