
- ์ปจํธ๋กค๋ฌ: ์น MVC์ ์ปจํธ๋กค๋ฌ ์ญํ
- ์๋น์ค: ํต์ฌ ๋น์ฆ๋์ค ๋ก์ง ๊ตฌํ
- ๋ฆฌํฌ์งํ ๋ฆฌ: ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ๊ทผ, ๋๋ฉ์ธ ๊ฐ์ฒด๋ฅผ DB์ ์ ์ฅํ๊ณ ๊ด๋ฆฌ
- ๋๋ฉ์ธ: ๋น์ฆ๋์ค ๋๋ฉ์ธ ๊ฐ์ฒด ex) ํ์, ์ฃผ๋ฌธ, ์ฟ ํฐ ๋ฑ๋ฑ ์ฃผ๋ก ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅํ๊ณ ๊ด๋ฆฌ
@Entity
- ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ
์ด๋ธ๊ณผ ๋งคํ๋๋ ์๋ฐ ํด๋์ค
- DTO ํด๋์ค์ด๋ฆ๊ณผ ํ ์ด๋ธ๋ช ๋งคํ
- DTO ํ๋๋ช ์ ํ ์ด๋ธ์ ์นผ๋ผ๋ช ๊ณผ ๋งคํ
import java.time.LocalDateTime;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Entity
public class Question {
@Id //primary key๋ก ์ง์
@GeneratedValue(strategy = GenerationType.IDENTITY) //๋ฐ์ดํฐ๋ฅผ 1์ฉ ์ฆ๊ฐํ๋ฉฐ ์ ์ฅ
//IDENTITY : ๋
๋ฆฝ์ ์ธ ์ํ์ค๋ฅผ ์์ฑํ๋ฉฐ ๊ณ ์ ๋ฒํธ๋ฅผ ๊ฐ์ง
private Integer id;
@Column(length = 200) //์ปฌ๋ผ ์์ฑ ์ ์, 200์ ๊น์ง
private String subject;
@Column(columnDefinition = "TEXT") //๊ธ์์ ์ ํ ์์ด ์ฌ์ฉ
private String content;
private LocalDateTime createdAt;
@OneToMany(mappedBy = "question", cascade = CascadeType.REMOVE)
//mappedBy="์ฐธ์กฐ ์ํฐํฐ์ ์์ฑ๋ช
"
//cascade=์ง๋ฌธ์ ์ญ์ ํ๋ฉด ๊ทธ์ ๋ฌ๋ฆฐ ๋ต๋ณ๋ค๋ ๋ชจ๋ ํจ๊ป ์ญ์
private List<Answer> answerList;
}
package com.mysite.board;
import java.time.LocalDateTime;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Entity
public class Answer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(columnDefinition = "TEXT")
private String content;
private LocalDateTime createdAt;
@ManyToOne
//foreign key : ๋ถ๋ชจํ
์ด๋ธ์ pk, uk ๊ฐ์ ์ฐธ์กฐํด์ ํ ๋น
//answer ์ํฐํฐ์ question ์์ฑ๊ณผ Question ์ํฐํฐ๊ฐ ์ฐ๊ฒฐ
private Question question; //๋ถ๋ชจํ
์ด๋ธ์ด Questionํ
์ด๋ธ์ Primary Key๋ฅผ ์ฐธ์กฐ(id)
}
@Controller
- Controller๋ MVC(Model View Controller)์์ ์ฌ์ฉ์์ ์์ฒญ์ ์ฒ๋ฆฌ ํ ํ ์ง์ ๋ ๋ทฐ์ ๋ชจ๋ธ ๊ฐ์ฒด๋ฅผ ๋๊ฒจ์ฃผ๋ ์ญํ ์ ํจ
- @Controller ์ด๋ ธํ ์ด์ ์ด ์์ด์ผ ์คํ๋ง๋ถํธ ํ๋ ์์ํฌ๊ฐ ์ปจํธ๋กค๋ฌ๋ก ์ธ์ํจ
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller //Springboot Framework์ HelloController ๋น ๋ฑ๋ก
public class HelloController {
@GetMapping("/Hello")
//get๋ฐฉ์ URL์์ฒญ, ์์ฒญ๋ URL ๊ณผ์ ๋งคํ์ ๋ด๋น
//์๋ฒ์ ์์ฒญ์ด ๋ฐ์ํ๋ฉด ์์ฒญ ํ์ด์ง์ ๋งคํ๋๋ ๋ฉ์๋๋ฅผ ํด๋์ค์์ ์ฐพ์ ์คํ
@ResponseBody
//์๋ต ๊ฒฐ๊ณผ๊ฐ ๋ฌธ์์ด ๊ทธ ์์ฒด์์ ๋ํ๋
//URL ์์ฒญ์ ๋ํ ์๋ต์ผ๋ก ๋ฌธ์์ด์ ๋ฆฌํด
public String Hello() {
return "Hello World";
}
}
| ๋ฉ์๋ | ์ค๋ช |
|---|---|
| @RequestMapping | HTTP ์์ฒญ์ ๋งคํ, ๊ณตํต์ ์ฌ์ฉ |
| @GetMapping | HTTP ์์ฒญ ์ค GET ๋ฉ์๋๋ก ์ค๋ ์์ฒญ์ ๋งคํ |
| @PostMapping | HTTP ์์ฒญ ์ค POST ๋ฉ์๋๋ก ์ค๋ ์์ฒญ์ ๋งคํ |
| @RequestBody | HTTP ์์ฒญ์์ BODY์ ์๋ ๋ฐ์ดํฐ ํฌ๋งท์ ์ฝ์ด ํด๋น ๋งค๊ฐ๋ณ์์ ๋งคํ |
DTO, Data Transfer Object
๋ ์ด์ด ๊ฐ ๋ฐ์ดํฐ ๊ตํ์ ์ํด ์ฌ์ฉ๋๋ ๊ฐ์ฒด
|View|โ DTO โ|DB| |โ|โ|โ|
์ฐธ๊ณ ) Value Object(VO) : ๊ฐ ๊ทธ ์์ฒด๋ฅผ ํํํ๋ ๊ฐ์ฒด
DTO ์์ฑ ๋ฐฉ๋ฒ
- DB ํ
์ด๋ธ๊ณผ ๋์ผํ ์๋ฃํ, ๋ณ์
private์นผ๋ผ - ๊ธฐ๋ณธ ์์ฑ์, getter, setter ์์ฑ
- toString ์ฌ์ ์ : ๊ฐ์ฒด ์์ฒด๋ฅผ ํ๋ฆฐํธ ํ์ ๋ ๊ฐ์ฒด์ ํ๋ ๋ด์ฉ์ ํ์ธ
@Repository
- ์ํฐํฐ์ ์ํด ์์ฑ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ ์ด๋ธ์ ์ ๊ทผํ๋ ๋ฉ์๋๋ค์ ์ฌ์ฉํ๊ธฐ ์ํ ์ธํฐํ์ด์ค
- ์๋ฐ ํด๋์ค์ JPA ๋ฉ์๋๋ฅผ ์ฌ์ฉํด์ SQL์์ CRUD
- CRUD ๋ฅผ ์ด๋ป๊ฒ ์ฒ๋ฆฌํ ์ง ์ ์ํ๋ ๊ณ์ธต
package com.mysite.board;
import org.springframework.data.jpa.repository.JpaRepository;
public interface QuestionRepository extends JpaRepository<Question, Integer> {
Question findBySubject(String subject);
}
package com.mysite.board;
import org.springframework.data.jpa.repository.JpaRepository;
public interface AnswerRepository extends JpaRepository<Answer, Integer> {
}
@Service
- ๋น์ฆ๋์ค ๋ก์ง์ ์ฒ๋ฆฌํ๋ ํด๋์ค
- ๊ท๋ชจ๊ฐ ํฐ ์ฌ์ดํธ์์ ๋น์ฆ๋์ค ๋ก์ง์ ๊ฐ๋ตํ๊ฒ ์ฒ๋ฆฌํ ์ ์๋ค
- ์ ์ง๋ณด์๊ฐ ๋น๋ฒํ ๊ฒฝ์ฐ ์ ์ง๋ณด์๋ฅผ ์ฝ๊ฒ ๊ตฌํํ ์ ์๋ค
- ๋ณด์์ ๊ฐํํ ์ ์๋ค
@RequredArgsConstrouctor
@Service
public class QuestionService{
private final QuestionRepository questionRepository;
public List<Question>
@Test
๋ฐ์ดํฐ ์ ์ฅ
package com.mysite.board;
import java.time.LocalDateTime;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class SbbApplicationTests {
// ํ
์คํธ ์ฝ๋ ์์ฑ์ ์์ฑ์๋ฅผ ํตํ ๊ฐ์ฒด์ ์์กด์ฑ ์ฃผ์
์ด ๋ถ๊ฐ๋ฅํ๋ฏ๋ก @Autowired ์ฌ์ฉ
@Autowired
private QuestionRepository questionRepository;
//JUnit์ ์คํํ๋ฉด @Test ์ ๋ํ
์ด์
์ด ๋ถ์ ๋ฉ์๋๊ฐ ์คํ๋จ
@Test
void testJpa() {
Question q1 = new Question();
q1.setSubject("sbj1");
q1.setContent("cnt1");
q1.setCreateDate(LocalDateTime.now());
this.questionRepository.save(q1); // ์ฒซ๋ฒ์งธ ์ง๋ฌธ ์ ์ฅ
Question q2 = new Question();
q2.setSubject("sbj2");
q2.setContent("cnt2");
q2.setCreateDate(LocalDateTime.now());
this.questionRepository.save(q2); // ๋๋ฒ์งธ ์ง๋ฌธ ์ ์ฅ
}
}
๋ฐ์ดํฐ ์กฐํ
findAll
- question ํ ์ด๋ธ์ ์ ์ฅ๋ ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ์กฐํ
package com.mysite.board;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.List;import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class SbbApplicationTests {
@Autowired
private QuestionRepository questionRepository;
@Test
void testJpa() {
List<Question> all = this.questionRepository.findAll();
assertEquals(2, all.size());
Question q = all.get(0);
assertEquals("sbj2", q.getSubject());
}
}
assertEquals(๊ธฐ๋๊ฐ, ์ค์ ๊ฐ) ๋ฐ์ดํฐ ์ฌ์ด์ฆ๊ฐ ๊ธฐ๋๊ฐ๊ณผ ์ค์ ๊ฐ์ด ๋์ผํ์ง ํ์ธ
findById (id ๊ฐ์ ๋ฐ๋ผ ์กฐํ)
@SpringBootTest
class SbbApplicationTests {
@Autowired
private QuestionRepository questionRepository;
@Test
void testJpa() {
Optional<Question> oq = this.questionRepository.findById(1);
if(oq.isPresent()) {
Question q = oq.get();
assertEquals("sbb ๊ฐ ๋ฌด์์ธ๊ฐ์?", q.getSubject());
}
}
}
๋ฆฌํดํ์
optional null ์ฒ๋ฆฌ๋ฅผ ์ ์ฐํ๊ฒ ์ฒ๋ฆฌํ๊ธฐ ์ํด ์ฌ์ฉํ๋ ํด๋์ค
-> isPresent ๋ก null ์ด ์๋์ง๋ฅผ ํ์ธํ ํ์ get ์ผ๋ก ์ค์ Question ๊ฐ์ฒด ๊ฐ์ ์ป์
findBySubject (id ๊ฐ์ ๋ฐ๋ผ ์กฐํ)
@SpringBootTest
class SbbApplicationTests {
@Autowired
private QuestionRepository questionRepository;
@Test
void testJpa() {
Question q = this.questionRepository.findBySubject("sbj1");
assertEquals(1, q.getId());
}
}
| ํญ๋ชฉ | ์์ | ์ค๋ช |
|---|---|---|
| And | findBySubjectAndContent(String subject, String content) | ์ฌ๋ฌ ์ปฌ๋ผ์ and ๋ก ๊ฒ์ |
| Or | findBySubjectOrContent(String subject, String content) | ์ฌ๋ฌ ์ปฌ๋ผ์ or ๋ก ๊ฒ์ |
| Between | findByCreateDateBetween(LocalDateTime fromDate, LocalDateTime toDate) | ์ปฌ๋ผ์ between์ผ๋ก ๊ฒ์ |
| LessThan | findByIdLessThan(Integer id) | ์์ ํญ๋ชฉ ๊ฒ์ |
| GreaterThanEqual | findByIdGraterThanEqual(Integer id) | ํฌ๊ฑฐ๋ ๊ฐ์ ํญ๋ชฉ ๊ฒ์ |
| Like | findBySubjectLike(String subject) - ๋ฌธ์์ด% : ์ฐพ๋ ๋ฌธ์์ด๋ก ์์ํ๋ ๋ฐ์ดํฐ - %๋ฌธ์์ด : ์ฐพ๋ ๋ฌธ์์ด๋ก ๋๋๋ ๋ฐ์ดํฐ - %๋ฌธ์์ด% : ์ฐพ๋ ๋ฌธ์์ด์ ํฌํจํ๋ ๋ฐ์ดํฐ |
like ๊ฒ์(ํน์ ๋ฌธ์์ด ํฌํจ) |
| In | findBySubjectIn(String[] subjects) | ์ฌ๋ฌ ๊ฐ์ค์ ํ๋์ธ ํญ๋ชฉ ๊ฒ์ |
| OrderBy | findBySubjectOrderByCreateDateAsc(String subject) | ๊ฒ์ ๊ฒฐ๊ณผ๋ฅผ ์ ๋ ฌํ์ฌ ์ ๋ฌ |
๋ฐ์ดํฐ ์ญ์
@SpringBootTest
class SbbApplicationTests {
@Autowired
private QuestionRepository questionRepository;
@Test
void testJpa() {
assertEquals(2, this.questionRepository.count());
Optional<Question> oq = this.questionRepository.findById(1);
assertTrue(oq.isPresent());
Question q = oq.get();
this.questionRepository.delete(q); //์ญ์
assertEquals(1, this.questionRepository.count()); //์ด ๋ฐ์ดํฐ ๊ฑด์ ๋ฆฌํด
}
}