[๊ฐ์] ์คํ๋ง ์ ๋ฌธ - ์ฝ๋๋ก ๋ฐฐ์ฐ๋ ์คํ๋ง ๋ถํธ, ์น MVC, DB์ ๊ทผ ๊ธฐ์ 2
[๋ฌด๋ฃ] ์คํ๋ง ์ ๋ฌธ - ์ฝ๋๋ก ๋ฐฐ์ฐ๋ ์คํ๋ง ๋ถํธ, ์น MVC, DB ์ ๊ทผ ๊ธฐ์ - ์ธํ๋ฐ | ๊ฐ์
์คํ๋ง ์ ๋ฌธ์๊ฐ ์์ ๋ฅผ ๋ง๋ค์ด๊ฐ๋ฉด์ ์คํ๋ง ์น ์ ํ๋ฆฌ์ผ์ด์ ๊ฐ๋ฐ ์ ๋ฐ์ ๋น ๋ฅด๊ฒ ํ์ตํ ์ ์์ต๋๋ค., ์คํ๋ง ํ์ต ์ฒซ ๊ธธ์ก์ด! ๊ฐ๋ฐ ๊ณต๋ถ์ ๊ธธ์ ์์ง ์๋๋ก ๋์๋๋ฆฝ๋๋ค. ๐ฃ ํ์ธํด์ฃผ์ธ
www.inflearn.com
๋ฌด๋ฃ๋ถ๋ถ๋ง ์ฌ๋ฆฌ๊ฒ ์
์ถ์ฒ : inf.run/reCZ ๊ฐ์
3. ํ์ ๊ด๋ฆฌ ์์ - ๋ฐฑ์๋ ๊ฐ๋ฐ
- ๋น์ฆ๋์ค ์๊ตฌ์ฌํญ ์ ๋ฆฌ
๋ฐ์ดํฐ ์ ์ฅ์๊ฐ ์ ์ ๋์ง ์์์ ๊ฐ์
์ปจํธ๋กค๋ฌ → ์๋น์ค → ๋ฆฌํฌ์งํ ๋ฆฌ → DB
โ ↓ โ
๋๋ฉ์ธ
์๋น์ค : ํ์ ์ค๋ณต ๊ฐ์ ์ด ์๋๋ค ๊ฐ์ ๋น์ฆ๋์ค ๋ก์ง
๋น์ฆ๋์ค ๋๋ฉ์ธ ๊ฐ์ฒด๋ฅผ ๊ฐ์ง๊ณ ํต์ฌ ๋น์ฆ๋์ค ๋ก์ง์ด ๋์๊ฐ๋๋ก ๊ตฌํํ ๊ฐ์ฒด
๋ฆฌํฌ์งํ ๋ฆฌ : ๋ฐ์ดํฐ ๋ฒ ์ด์ค์ ์ ๊ทผํ๊ณ
๋๋ฉ์ธ : ๋ฐ์ดํฐ ๋ฒ ์ด์ค์ ์ ์ฅ๋๊ณ ๊ด๋ฆฌ๋๋ ๋น์ฆ๋์ค ๋๋ฉ์ธ ๊ฐ์ฒด
๋ฉ๋ชจ๋ฆฌ๋ฅผ ๊ตฌํ์ฒด๋ก ๋ง๋ค์ด์ ๋์ค์ ๋ฐ์ดํฐ ์ ์ฅ์ ์ ์ ํ ๊ตฌํ ํด๋์ค๋ฅผ ๋ณ๊ฒฝํ ์ ์๋๋ก ์ค๊ณ
- ํ์ ๋๋ฉ์ธ๊ณผ ๋ฆฌํฌ์งํ ๋ฆฌ ๋ง๋ค๊ธฐ
//Member.java - member ํด๋์ค ๋ง๋ค๊ธฐ
public class Member {
private Long id;//id ์๋ณ์, ์์คํ
์ด ์๋ ์ ์ฅ
private String name;//์ด๋ฆ
public Long getId() {
return id;
}
public String getName() {
return name;
}
public void setId(Long id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
}
//MemberRepository.java
public interface MemberRepository {
Member save(Member member);
Optional<Member> findById(Long id); //id๋ก ํ์ ์ฐพ๊ธฐ
Optional<Member> findByName(String name); //์ด๋ฆ์ผ๋ก ํ์ ์ฐพ๊ธฐ
//Optional -> null๋ก ๋ฐํ๋๋ ๊ฑฐ ๋ฐฉ์ง
List<Member> findAll();
}
//MemoryMemberRepository.java
public class MemoryMemberRepository implements MemberRepository {
private static Map<Long, Member> store = new HashMap<Long, Member>();
private static long sequence = 0L; //key๊ฐ ์์ฑ
@Override
public Member save(Member member) {
member.setId(++sequence);//id ๋ ์์คํ
์ด ์ ํด์ค๋ค.
store.put(member.getId(), member);
return member;
}
@Override
public Optional<Member> findById(Long id) {
return Optional.ofNullable(store.get(id));
}
@Override
public Optional<Member> findByName(String name) {
return store.values().stream()
.filter(member -> member.getName().equals(name))
.findAny(); // map์ ์ด๋ฆ์ด ํ๋๋ผ๋ ์์ผ๋ฉด ๋ฐํ. ์์ผ๋ฉด null์ด ํฌํจ๋์ ๋ฐํ
}
@Override
public List<Member> findAll() {
return new ArrayList<>(store.values());
}
}
- ํ์ ๋ฆฌํฌ์งํ ๋ฆฌ ํ ์คํธ ์ผ์ด์ค ์์ฑ
JUnit์ด๋ผ๋ ํ๋ ์์ํฌ๋ก ํ ์คํธ ์คํ
//MemoryMemberRepositoryTest.java
public class MemoryMemberRepositoryTest {
MemoryMemberRepository repository = new MemoryMemberRepository();
@AfterEach //๋งค๋ฒ ๋๋ ๋๋ง๋ค ์คํํ๊ฒ ํ๋ ์ฝ๋ฐฑ ๋ฉ์๋
public void afterEach(){
repository.clearStore();
}
@Test
public void save(){
Member member = new Member();
member.setName("spring");
repository.save(member);//๋ฉค๋ฒ ์ ์ฅ
Member result = repository.findById(member.getId()).get(); //์ ์ฅํ ๋ฉค๋ฒ ์ฐพ๊ธฐ
//optional์์๋ get์ผ๋ก ๋ฐ๋ก ๊บผ๋ผ ์ ์์(์ข์ ๋ฐฉ๋ฒ x)
//1)System.out.println("Result = " + (result == member));
//2)Assertions.assertEquals(member, null);
//3)
assertThat(member).isEqualTo(result);
}
@Test
public void findByName(){
Member member1 = new Member();
member1.setName("spring1");
repository.save(member1);
Member member2 = new Member();
member2.setName("spring2");
repository.save(member2);
Member result = repository.findByName("spring1").get();
assertThat(result).isEqualTo(member1);
}
@Test
public void findAll(){
Member member1 = new Member();
member1.setName("spring1");
repository.save(member1);
Member member2 = new Member();
member2.setName("spring2");
repository.save(member2);
List<Member> result = repository.findAll();
assertThat(result.size()).isEqualTo(2);
}
//์์๋ ๋ณด์ฅ ํ ์ ์๋ค. ์์์ ํ
์คํธ ํ๋ฒ์ด ๋๋๊ณ ๋๋ฉด clear๊ฐ ํ์ํ๋ค.
//-> ์์๊ฐ ์๊ด ์๊ฒ ๋ง๋ค์
}
- ํ์ ์๋น์ค ๊ฐ๋ฐ
//MemberService.java
public class MemberService {
private final MemberRepository memberRepository = new MemoryMemberRepository();
//ํ์๊ฐ์
public Long join(Member member){
//๊ฐ์ ์ด๋ฆ ์ค๋ณตํ์ x
validateDuplicateMember(member);
memberRepository.save(member);
return member.getId();
}
private void validateDuplicateMember(Member member){
memberRepository.findByName(member.getName())
.ifPresent(m->{
throw new IllegalStateException("์ด๋ฏธ ์กด์ฌํ๋ ํ์์
๋๋ค.");
});
}
//์ ์ฒด ํ์ ์กฐํ
public List<Member> findMembers(){
return memberRepository.findAll();
}
//id๋ก ์ฌ๋ ์ฐพ๊ธฐ
public Optional<Member> findOne(Long memberID){
return memberRepository.findById(memberID);
}
}
- ํ์ ์๋น์ค ํ ์คํธ
<<๋จ์ถํค>>
ctrl+shift+t -> test class ๋ง๋ค์ด์ค๋ค
ctrl+alt+v -> Optional๋ก ๊ฐ์ธ๊ธฐ/reCZ
shift+F10 -> ์คํ
//MemberServiceTest.java
class MemberServiceTest {
MemberService memberService;
MemoryMemberRepository memberRepository;
@BeforeEach
public void beforeEach(){
memberRepository = new MemoryMemberRepository();
memberService = new MemberService(memberRepository);
} // -> DI
@AfterEach
public void afterEach(){
memberRepository.clearStore();
}
@Test
void ํ์๊ฐ์
() { //ํ๊ธ๋ก ํด๋ ๋๋ค!
//given ์ํฉ์ด ์ฃผ์ด์ง
Member member = new Member();
member.setName("spring");
//when ์ด๊ฑธ๋ก ์คํํจ
Long saveId = memberService.join(member);
//then ์ด๋ฐ ๊ฒฐ๊ณผ๊ฐ ๋์ด
Member findMember = memberService.findOne(saveId).get();
assertThat(member.getName()).isEqualTo(findMember.getName());
}
@Test
public void ์ค๋ณต_ํ์_์์ธ(){
//given
Member member1 = new Member();
member1.setName("spring");
Member member2 = new Member();
member1.setName("spring");
//when
memberService.join(member1);
/*1)
try {
memberService.join(member2);
fail(); //fail์์ ๊ณ์ ์ค๋ฅ๋จ ์ด์ ์์๋ผ ๊ฒ
}catch(IllegalStateException e){
assertThat(e.getMessage()).isEqualTo("์ด๋ฏธ ์กด์ฌํ๋ ํ์์
๋๋ค.");
}*/
//2)
IllegalStateException e = assertThrows(IllegalStateException.class,
() -> memberService.join(member1));
//then
}
@Test
void findMembers() {
}
@Test
void findOne() {
}
}
๋ ์ด๋ ต๋ค... ๋ค์ ๊ณต๋ถํด์ผํ ๋ฏ
4. ์คํ๋ง ๋น๊ณผ ์์กด ๊ด๊ณ
- ์ปดํฌ๋ํธ ์ค์บ๊ณผ ์๋ ์์กด๊ด๊ณ ์ค์
์คํ๋ง ๋น ๋ฑ๋ก
1) ์ปดํฌ๋ํธ ์ค์บ, ์๋ ์์กด ๊ด๊ณ ์ค์ (@Component๋ฅผ ํฌํจํ๋ ์ ๋ ธํ ์ด์ )
์คํ๋ง์ ์ปดํฌ๋ํธ ์ ๋ ธํ ์ด์ (@)์ผ๋ก ๊ฐ์ฒด๋ฅผ ์คํ๋ง ์ปจํ ์ด๋์ ๋ฑ๋กํ๋ค.
@AutoWired๋ ์๋ค๋ฅผ ์ฐ๊ฒฐํ๋ ์ ๊ฐ์ ๋๋
๋๋ถ๋ถ์ ๊ฒฝ์ฐ ํ๋์ฉ๋ง ๋ฑ๋กํด ์ฌ์ฉํ๋ค.(์ฑ๊ธํค) ์ค์ ๊ฐ๋ฅ ํ๊ธด ํ์ง๋ง ์ฌ๋งํ๋ฉด ์ฑ๊ธํค
DI์๋ ํ๋ ์ฃผ์ , setter ์ฃผ์ , ์์ฑ์ ์ฃผ์ 3๊ฐ์ง ๋ฐฉ๋ฒ -> ์์ฑ์ ์ฃผ์ ๊ถ์ฅ
MemberController -> MemberService -> MemberRepository
//MemberController.java
@Controller
public class MemberController {
private final MemberService memberService; //= new MemberService(); ์ฌ๋ฌ๊ฐ ์ฐ๋ ๊ฑด ์๋ฏธ๊ฐ ์์
@Autowired
public MemberController(MemberService memberService) {
this.memberService = memberService;
}
}
2) ์๋ฐ ์ฝ๋๋ก ์ง์ ์คํ๋ง ๋น ๋ฑ๋ก
๋ค์์ ๋์ด
- ์๋ฐ ์ฝ๋๋ก ์ง์ ์คํ๋ง ๋น ๋ฑ๋กํ๊ธฐ
@Configuration
public class SpringConfig {
@Bean
public MemberService memberService() {
return new MemberService(memberRepository());
}
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
}
5. ํ์ ๊ด๋ฆฌ ์์ - ์น MVC ๊ฐ๋ฐ
- ํ์ ์น ๊ธฐ๋ฅ - ํ ํ๋ฉด ์ถ๊ฐ
//HomeController
@Controller
public class HomeController {
@GetMapping("/") //์ฐ์ ํธ์ถ๋๊ธฐ ๋๋ฌธ์ index.html ๋ฌด์
public String home(){
return "home";
}
}
- ํ์ ์น ๊ธฐ๋ฅ - ๋ฑ๋ก
//MemberForm.java
public class MemberForm {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
//MemberController.java
@Controller
public class MemberController {
private final MemberService memberService; //= new MemberService(); ์ฌ๋ฌ๊ฐ ์ฐ๋ ๊ฑด ์๋ฏธ๊ฐ ์์
@Autowired
public MemberController(MemberService memberService) {
this.memberService = memberService;
}
@GetMapping("/members/new")
public String createForm(){
return "members/createMemberForm";
}
@PostMapping("/members/new")
public String create(MemberForm form){
Member member = new Member();
member.setName(form.getName());
memberService.join(member);
System.out.println(member.getName());
return "redirect:/";
}
}
- ํ์ ์น ๊ธฐ๋ฅ - ์กฐํ
//MemberController.java ์ ์ผ๋ถ
@GetMapping(value = "/members")
public String list(Model model) {
List<Member> members = memberService.findMembers();
model.addAttribute("members", members);
return "members/memberList";
}