JAN's History
스프링과 JPA를 이용한 웹개발 프로젝트_데이터 연동(MySQL), 컨트롤러 본문
엔티티를 작성했으니 데이터베이스를 MySQL과 연동해봅시다.👍
Helper 메소드 정의하기!
정의하기에 앞서, Helper 메소드가 무엇인지 알아볼까요?
- Helper 메소드는 양방향 연관관계에서 사용되는 방법인데요. 두 엔티티 간의 관계를 설정하고 데이터를 전달하는 코드를 캡슐화하여 코드를 더 간결하고 읽기 쉽게 만들어주는 도구랍니다.
- Helper 메소드를 통해 양방향 연관관계를 설정하고 유지하는 로직을 한 곳에 집중시킬 수 있어 코드의 복잡성이 감소된다는 장점이 있습니다.
- 즉, Helper 메소드는 양방향 연관관계에서 한 엔티티가 수정되었을 때 다른 엔티티의 정보를 동기화하기 위해 사용됩니다!
➡️ 따라서 양방향 관계에서는 Helper 메서드를 사용하여 관계를 설정하고 유지하는 것이 일반적으로 권장되는 방법입니다.
SeedStarter 엔티티
public class SeedStarter {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "SEED_STARTER_ID")
private Long id;
..
..
//---여기서부터 helper method
public void setFeature(Feature feature){
this.features.add(feature);
feature.setSeedStarter(this);
}
public void setDetail(Detail detail){
this.details.add(detail);
detail.setSeedStarter(this);
}
}
SeedStarter 의 양방향인 Feature와 Detail 엔티티에게 한 엔티티가 수정되었을 때 동기화할 수 있도록 helper 메소드를 정의해주도록 합니다.
Helper 메소드 설명 : SeedStarter Feature엔티티의 정보가 UPDATE되면 SeedStarter 엔티티 속 this.feature에게도 업데이트 해주고, Feature 객체 속 SeedStrater 객체에게도 UPDATE 해준다는 뜻입니다.
➡️약간.. 어떤 느낌이냐면요.새로운 feature 값이 들어오면 내 엔티티에 일단 그 값을 업데이트하고, 업데이트 된 최신버전 내 엔티티를 (this)로 받아서 상대편 엔티티에도 넣어주는 느낌이랍니다
➕feature의 타입이 List이기 때문에 this.feature = feature가 아니라 .add(feature)를 사용한 것입니다.
Feature 엔티티
public void setSeedStarter(SeedStarter seedStarter){
this.seedStarter = seedStarter;
seedStarter.getFeatures().add(this);
}
Helper 메소드 설명 : SeedStarter메소드가 UPDATE되면 그 Feature엔티티에 SeedStarter 값을 UPDATE하고, SeedStarter 엔티티에 Feature값도 업데이트 하겠다는 뜻입니다.
Detail 엔티티
public void setSeedStarter(SeedStarter seedStarter){
this.seedStarter = seedStarter;
seedStarter.getDetails().add(this);
}
SeedStarter 전체
public class SeedStarter {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "SEED_STARTER_ID")
private Long id;
private LocalDateTime datePlanted;
private boolean covered;
@Enumerated(EnumType.STRING)
private Type type;
@OneToMany(mappedBy = "seedStarter", cascade = CascadeType.PERSIST ,orphanRemoval = true)
private List<Feature> features = new ArrayList<>();
@OneToMany(mappedBy = "seedStarter", cascade = CascadeType.PERSIST, orphanRemoval = true)
private List<Detail> details = new ArrayList<>();
public void setFeature(Feature feature){
this.features.add(feature);
feature.setSeedStarter(this);
}
public void setDetail(Detail detail){
this.details.add(detail);
detail.setSeedStarter(this);
}
}
public enum Type {
PLASTIC, WOOD
}
Feature 전체
public class Feature {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "FEATURE_ID")
private Long id;
@Enumerated(EnumType.STRING)
private FeatureType name;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "SEED_STARTER_ID")
private SeedStarter seedStarter = new SeedStarter();
public void setSeedStarter(SeedStarter seedStarter){
this.seedStarter = seedStarter;
seedStarter.getFeatures().add(this);
}
}
public enum FeatureType {
SUBSTRATE, FERTILIZER, PH_CORRECTOR
}
Detail 전체
public class Detail {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "DETAIL_ID")
private Long id;
private int rowNum;
private int seedPerCell;
private String variety;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "SEED_STARTER_ID")
private SeedStarter seedStarter;
public void setSeedStarter(SeedStarter seedStarter){
this.seedStarter = seedStarter;
seedStarter.getDetails().add(this);
}
}
중간 정리
Entity를 설계하고 양방향 연관관계까지 설정하고, 동기화를 위한 Helper 메소드까지 선언해주었습니다!
데이터베이스 준비
application.yml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/jpa_playground?serverTimezone=Asia/Seoul
username: root
password: 1234
jpa:
database-platform: org.hibernate.dialect.MySQL8Dialect
hibernate:
ddl-auto: create
show-sql: true
properties:
hibernate.format_sql: true
1. url에 jpa_playground 부분에는 자신이 만든 파일 명을 적어주면 됩니다.
2. username와 password는 MySQL에서 자신이 설정한 파일에 맞게 적어주시면 됩니다.
스프링 부트 어플리케이션을 실행하여 테이블 생성 확인
이렇게 실행되면 데이터베이스가 잘 연동된 것입니다!
데이터베이스 준비
INSERT INTO SEED_STARTER(covered,date_planted,type) VALUES(0,'2002-04-05 10:10:10','PLASTIC');
INSERT INTO SEED_STARTER(covered,date_planted,type) VALUES(0,'2001-04-05 10:10:10','WOOD');
INSERT INTO SEED_STARTER(covered,date_planted,type) VALUES(1,'2003-04-05 10:10:10', 'WOOD');
INSERT INTO FEATURE(name,SEED_STARTER_ID) VALUES('SUBSTRATE',1);
INSERT INTO FEATURE(name,SEED_STARTER_ID) VALUES('PH_CORRECTOR',1);
INSERT INTO FEATURE(name,SEED_STARTER_ID) VALUES('FERTILIZER',2);
INSERT INTO FEATURE(name,SEED_STARTER_ID) VALUES('PH_CORRECTOR',3);
INSERT INTO DETAIL(ROW_NUM,SEED_PER_CELL, VARIETY, SEED_STARTER_ID) VALUES(1,10,'Thymus vularis',1);
INSERT INTO DETAIL(ROW_NUM,SEED_PER_CELL, VARIETY, SEED_STARTER_ID) VALUES(2,15,'Thymus pseudolaginosus',1);
INSERT INTO DETAIL(ROW_NUM,SEED_PER_CELL, VARIETY, SEED_STARTER_ID) VALUES(3,20,'x citriodorus',1);
INSERT INTO DETAIL(ROW_NUM,SEED_PER_CELL, VARIETY, SEED_STARTER_ID) VALUES(1,5,'Thymus herba-barona',2);
INSERT INTO DETAIL(ROW_NUM,SEED_PER_CELL, VARIETY, SEED_STARTER_ID) VALUES(2,5,'Thymus serpyllum',2);
INSERT INTO DETAIL(ROW_NUM,SEED_PER_CELL, VARIETY, SEED_STARTER_ID) VALUES(1,20,'New Variety',3);
데이블 확인
SEED_STARTER와 Feature의 정합성 확인
SeedStarter의 PK와 Feature의 FK의 연관관계가 잘 되어있는지 확인하기 위해 JOIN을 통해 잘 가져와지는지 확인하기 위함입니다!
SELECT *
FROM SEED_STARTER AS s
NATURAL JOIN FEATURE AS f;
➡️FeatureType은 SUBSTRATE, FERTILIZER, PH_CORRECTOR로 총 3가지입니다.
SEED_STARTER와 DETAIL 정합성 확인
SELECT *
FROM SEED_STARTER AS s
NATURAL JOIN DETAIL AS d;
전체 데이터 정합성 확인
SELECT *
FROM SEED_STARTER AS s
NATURAL JOIN FEATURE AS f
NATURAL JOIN DETAIL AS d;
➡️전체적인 그림을 이렇게 생각하면 됩니다
MySQL과 데이터베이스를 연동했으니 이제 그 데이터를 화면에 뿌려줄 컨트롤러를 만들어볼까요?
@Autowired를 활용한 컨트롤러 코드
@Controller
public class SeedStarterMngController {
private SeedStarterService seedStarterService;
@Autowired
public SeedStarterMngController(SeedStarterService seedStarterService) {
this.seedStarterService = seedStarterService;
}
@RequestMapping({"/","/seedstartermng"})
public String showSeedstarters(final SeedStarter seedStarter, Model model) {
List<SeedStarter> all = seedStarterService.findAll();
model.addAttribute("allSeedStarters", all);
return "seedstartermng";
}
➕@Autowired이 뭐더라 ..?
- @Autowired는 클래스 간의 의존성을 주입할 때 사용되는 어노테이션인데요. 이를 통해 Spring 컨테이너는 프로그램에서 필요로 하는 빈(Bean)을 자동으로 찾아서 해당 클래스나 필드에 주입해줍니다!
- Bean을 모르신다면 스프링 컨테이너를 공부하고 오시기를 추천드려요
어찌됐든, @Autowired를 사용하면 SeedStarterService를 사용하는 생성자를 주입해주는 코드를 직접 만들고 난 후에, 생성자 위에 어노테이션을 붙여줘야합니다.
그러나 많은 코드를 작성할 때에는 코드의 복잡성이 생깁니다
@RequiredArgsConstructor를 사용한 컨트롤러 코드
@Controller
@RequiredArgsConstructor
public class SeedStarterMngController {
private final SeedStarterService seedStarterService;
...
그러나 !
lombok에 @RequiredArgsConstructor를 사용하면 생성자 인젝션을 통해 의존성을 주입할 수 있습니다. 이는 코드를 간결하게 만들어줍니다. 따라서 생성자를 별도로 선언할 필요 없이 클래스의 의존성을 바로 주입할 수 있습니다.
그리고 @RequiredArgsConstructor를 사용하면 final 키워드가 지정된 필드에 대한 생성자가 자동으로 생성되어 final을 사용할 수 있습니다 .
'스프링' 카테고리의 다른 글
스프링과 JPA를 이용한 웹개발 프로젝트_View 구현 1 (0) | 2024.04.11 |
---|---|
스프링과 JPA를 이용한 웹개발 프로젝트_Repository구현 (0) | 2024.04.08 |
스프링과 JPA를 이용한 웹개발 프로젝트_엔티티 설계 (0) | 2024.04.06 |
스프링과 JPA를 이용한 웹개발_Spring Data JPA 2 (0) | 2024.04.06 |
jsp, tomcat 간단하게 그림으로 이해하기! (0) | 2024.04.05 |