eajni IT ์ดˆ๋ณด์‚ฌ์ „ ๐Ÿ’ฆ๐Ÿ’ฆ

[SpringBoot] Springboot board project 01

2022-12-15

  • ์ปจํŠธ๋กค๋Ÿฌ: ์›น 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());  //์ด ๋ฐ์ดํ„ฐ ๊ฑด์ˆ˜ ๋ฆฌํ„ด
	}
}

Comments

Content