์ธํ๋ฐ ์คํ๋ง ์ ๋ฌธ ์น์ 1 ~ ์น์ 4 ๊ฐ์ ๋ด์ฉ ์ ๋ฆฌ
โ ํ๋ก์ ํธ ์์ฑ
ํํ์ด์ง์์ ํ๋ก์ ํธ ์ค์ ํ generate
zip ํ์ผ ์์ถ ํ๊ณ ์ธํ ๋ฆฌ์ ์ด์์ import (์์ถ์ ํผ ํด๋์์ build.gradleํ์ผ์ ์ ํํด์ open)
File > Settings > Build, execution, ... > Build Tools > Gradle ์์ Build and run using, Run tests using ์ IntelliJ๋ก ๋ฐ๊ฟ์ค
โ ์๋์ฐ ๋จ์ถํค ์ฌ์ฉ
์ธํ ๋ฆฌ์ ์ด ๋จ์ถํค ๊ฒ์ ๋ฐฉ๋ฒ
โช File -> Settings -> Keymap -> ๋จ์ถํค ์ด๋ฆ ๊ฒ์
ex) Ctrl + Alt + Shift + T : Refactor This
โ Welcome Page
- Thymleaf (ํ ํ๋ฆฟ ์์ง) Thymeleaf
ํ์ผ๊ฒฝ๋ก src-main-resources-static-index.html ์์ฑ
//java/hello.hellospring/controller/HelloController
@Controller
public class HelloController {
@GetMapping("hello")
public String hello(Model model) {
model.addAttribute("data", "hello!!");
return "hello";
}
}
//resources/templates/hello.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Hello</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p th:text="'์๋
ํ์ธ์. ' + ${data}" >์๋
ํ์ธ์. ์๋</p>
</body>
</html>
์น ๋ธ๋ผ์ฐ์ ์ localhost:8080/hello์ ์ ๋ ฅ -> getMapping -> ๋ด์ฅ ํฐ์ผ ์๋ฒ -> @Getmapping์ด hello๋ก ๋์ด์๋ ์ปจํธ๋กค๋ฌ๋ฅผ ์ฐพ์ ๋ฉ์๋ ์คํ -> ๋ฉ์๋๋ model์ addAttribute๋ก key๊ฐ data์ธ hello!! ์ธ value๋ฅผ ๋ด๊ณ hello๋ฅผ ๋ฆฌํด -> viewResolver๊ฐ ๋ฆฌํด๋ ๋ฌธ์์ ๋์ํ๋ html ํ์ผ์ ์ฐพ์ -> html ํ์ผ์ด ์น๋ธ๋ผ์ฐ์ ๊ฐ ๋์์ง
โ ์ ์ ์ปจํ ์ธ
- html ํ์ผ์ ๊ทธ๋๋ก ์น ๋ธ๋ผ์ฐ์ ์ ๋ณด์ฌ์ค , ์คํ๋ง ๋ถํธ๋ ์ ์ ์ปจํ ์ธ ๊ธฐ๋ฅ์ ์๋์ผ๋ก ์ ๊ณต
์น ๋ธ๋ผ์ฐ์ ์์ url ์์ฒญ -> ๋ด์ฅ ํฐ์ผ ์๋ฒ๊ฐ ์์ฒญ์ ๋ฐ๊ณ ์คํ๋ง์ผ๋ก ๋๊ฒจ์ค -> ์ปจํธ๋กค๋ฌ์์ hello-static์ ์ฐพ๊ณ ์์ผ๋ฉด resources/static ์์ hello-static.html์ ์ฐพ์ -> ์น ๋ธ๋ผ์ฐ์ ์ ๋ฐํํ๊ณ ์ถ๋ ฅํจ
โ MVC
- Model, View, Controller๋ก ๋ถ๋ฆฌํ์ฌ ๊ฐ๋ฐ
์น ๋ธ๋ผ์ฐ์ ์์ url ์์ฒญ -> ๋ด์ฅ ํฐ์ผ ์๋ฒ -> hello-mvc ์ปจํธ๋กค๋ฌ๋ฅผ ์ฐพ์ -> ์ปจํธ๋กค๋ฌ๊ฐ Model ์ ๊ฐ์ด spring์ธ key name์ ๋ด๊ณ hello-template์ return -> viewResolver๊ฐ resources/templates ์์ hello-template.html ํ์ผ์ ์ฐพ๊ณ ํ ํ๋ฆฟ ์์ง์ ์ฐ๊ฒฐ -> Thymeleaf ํ ํ๋ฆฟ ์์ง์ ๋ ๋๋ง ํ ์น ๋ธ๋ผ์ฐ์ ์ ๋๊น
โ API
- ์๋ฒ๊ฐ JSON์ด๋ผ๋ ๋ฐ์ดํฐ ๊ตฌ์กฐ ํฌ๋งท์ผ๋ก ํด๋ผ์ด์ธํธ์๊ฒ ๋ฐ์ดํฐ ์ ๋ฌ
* JSON : key-value ์์ผ๋ก ์ด๋ฃจ์ด์ง ๊ตฌ์กฐ
@Controller
public class HelloController {
@GetMapping("hello-string")
@ResponseBody
public String helloString(@RequestParam("name") String name) {
return "hello " + name;
}
}
@ResponseBody๋ฅผ ์ฌ์ฉํ๋ฉด viewResolver๋ฅผ ์ฌ์ฉํ์ง์์ -> HttpMessageConverter๊ฐ ๋์
- ๊ธฐ๋ณธ ๋ฌธ์์ฒ๋ฆฌ : StringHttpMessageConverter
- ๊ธฐ๋ณธ ๊ฐ์ฒด์ฒ๋ฆฌ : MappingJackson2HttpMessageConverter
@ResponseBody๋ฅผ ์ฌ์ฉํ๊ณ , ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ฉด ๊ฐ์ฒด๊ฐ JSON์ผ๋ก ๋ฐํ๋จ
โ ํ์ ๊ด๋ฆฌ ์์ - ํ ์คํธ ์ผ์ด์ค ์์ฑ
test/java/ํ๋ก์ ํธ๋ช ์๋์ repository ํด๋๋ฅผ ์์ฑํ๊ณ MemoryMemberRepositoryTest(๊ตฌํ์ฒด ์ด๋ฆ+Test) ํ์ผ์ ์์ฑ
package hello.hellospring.repository;
import hello.hellospring.domain.Member;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.junit.jupiter.api.Assertions.*;
class MemoryMemberRepositoryTest {
MemoryMemberRepository repository = new MemoryMemberRepository();
// @Test : ํ
์คํธ ์ ๋ ์์ฑ (๋ฉ๋ชจ๋ฆฌ ๊ตฌํ์ฒด์ธ MemoryMemberRepository ๊ฐ์ฒด๋ฅผ repository๋ก ์์ฑ)
@Test
public void save(){ //save ํจ์์ ๋์์ ํ
์คํธ
//given
Member member = new Member(); //Member ๊ฐ์ฒด ์์ฑ
member.setName("spring"); //name spring์ผ๋ก ์ธํ
//when
repository.save(member); // repository์ ์์ฑ๋ ๋ฉค๋ฒ ๊ฐ์ฒด๋ฅผ save ํจ์์ ์ ์ฅ
//then
Member result = repository.findById(member.getId()).get();
//member์ ์ ์ฅ๋ id๋ก findByIdํจ์๋ฅผ ํตํด repository์ ์ ์ฅ๋ Member๊ฐ์ฒด๋ฅผ ๊บผ๋ด๊ณ (get()), ๊บผ๋ธ Member ๊ฐ์ฒด(result)๊ฐ save๋ฅผ ํตํด ์ ์ฅํ๋ member์ ๋์ผํ ๊ฐ์ฒด์ธ์ง ํ์ธ
assertThat(member).isEqualTo(result); //์คํํ๋ฉด ์ ์์ ์ผ๋ก ํ
์คํธ ์งํ
}
@Test
public void findByName(){
//given
Member member1 = new Member();
member1.setName("spring1");
repository.save(member1);
Member member2 = new Member();
member2.setName("spring2");
repository.save(member2);
//when
Member result = repository.findByName("spring1").get();
//then
assertThat(result).isEqualTo(member1);
}
@Test
public void findAll(){
//given
Member member1 = new Member();
member1.setName("spring1");
repository.save(member1);
Member member2 = new Member();
member2.setName("spring2");
repository.save(member2);
//when
List<Member> result = repository.findAll();
//then
assertThat(result.size()).isEqualTo(2);
}
}
๐ธ ํ ์คํธ ์ ๋์ ํ๋ฒ์ ํ ์คํธํ๋ฉด error ๋ฐ์ ๊ฐ๋ฅ
๐ธ ๋ฉ๋ชจ๋ฆฌ DB์ ์ด์ ํ ์คํธ ๊ฒฐ๊ณผ๊ฐ ๋จ๊ธฐ ๋๋ฌธ์ ๋ค๋ฅธ ํ ์คํธ ์ผ์ด์ค์ ์ํฅ์ด ๊ฐ์ง ์๊ฒ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ง์์ผํจ
๐ธ ํ ์คํธ๋ ๊ฐ๊ฐ ๋ ๋ฆฝ์ ์ผ๋ก ์คํ๋์ด์ผ ํ๋ฉฐ, ํ ์คํธ์ ์์์ ์์กด๊ด๊ณ๊ฐ ์๋ ํ ์คํธ๋ ์ข์ ํ ์คํธ๊ฐ ์๋
import org.junit.jupiter.api.AfterEach;
class MemoryMemberRepositoryTest {
@AfterEach
public void afterEach(){
repository.clearStore();
}
}
@AfterEach : ํ ์คํธ ์ผ์ด์ค๊ฐ ์คํ๋๊ณ ๋์ ๋ฌด์กฐ๊ฑด ์คํ
@BeforeEach : ํ ์คํธ ๋ฉ์๋ ์คํ ์ ์ ํธ์ถ, ํ ์คํธ๊ฐ ์๋ก ์ํฅ์ด ์๋๋ก ํญ์ ์๋ก์ด ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ์์กด๊ด๊ณ๋ฅผ ์๋ก ๋งบ์ด์ค
โ ์คํ๋ง ๋น
์คํ๋ง ์ปจํ
์ด๋๊ฐ ๊ด๋ฆฌํ๋ ์๋ฐ ๊ฐ์ฒด๋ฅผ ๋น(Bean)
์๋ฐ์์ new๋ฅผ ํตํด ์์ฑ๋๋ ๊ฐ์ฒด๋ฅผ ์๋ฏธํ๋ ๊ฒ์ด ์๋๋ผ ์ปจํ
์ด๋์์ ์์ฑํ๊ณ ๊ด๋ฆฌํ๋ ๊ฐ์ฒด
โ ์ปดํฌ๋ํธ ์ค์บ๊ณผ ์๋ ์์กด ๊ด๊ณ ์ค์
package hello.hellospring.controller;
import hello.hellospring.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class MemberController {
private final MemberService memberService;
// ํ์ ์๋น์ค๋ ํ ๋ฒ๋ง ์์ฑ๋์ด ์์ฑ๋ ํ๋์ ํ์ ์๋น์ค ์ธ์คํด์ค๋ฅผ ๊ฐ๊ฐ์ ์ปจํธ๋กค๋ฌ๋ค์ด ๊ณต์
@Autowired
public MemberController(MemberService memberService) {
this.memberService = memberService;
}
}
@Controller๋ฅผ ์ฌ์ฉํด MemberController๋ผ๋ ์ปจํธ๋กค๋ฌ๋ฅผ ์์ฑ
@Autowired : ์์ฑ์์ @Autowired ๊ฐ ์๋ค๋ฉด ์คํ๋ง์ด ์ฐ๊ด๋ ๊ฐ์ฒด๋ฅผ ์คํ๋ง ์ปจํ ์ด๋์์ ์ฐพ์์ ๋ฃ์ด์ค
- ๊ฐ์ฒด ์์กด๊ด๊ณ๋ฅผ ์ธ๋ถ์์ ๋ฃ์ด์ฃผ๋ ๊ฒ์ DI, ์์กด์ฑ ์ฃผ์ ์ด๋ผ๊ณ ํจ
์คํ๋ง ๋น์ผ๋ก ์๋ ๋ฑ๋กํ๋ ๋ฐฉ๋ฒ
@Controller
@Service
@Repository // ์ ๋ค @Component๋ก ๋์ฒด ๊ฐ๋ฅ
@Service
public class MemberService {
private final MemberRepository memberRepository;
@Autowired
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
}
@Repository
public class MemoryMemberRepository implements MemberRepository {}
@SpringBootApplication์ ์คํํ๋ฉด ์ํด์๋ ํจํค์ง ๋ด์ @Controller, @Service, @Repository๋ฅผ ํตํด ๊ฐ๊ฐ์ด ์ปจํ ์ด๋์ ๋ฑ๋ก๋๊ณ , @Autowired๋ฅผ ํตํด ์์กด๊ด๊ณ๋ฅผ ๊ฐ์ง
์คํ๋ง์ ์คํ๋ง ์ปจํ ์ด๋์ ์คํ๋ง ๋น ๋ฑ๋ก ์ ์ค๋ณต๋์ง ์๊ฒ ์ ์ผํ๊ฒ ํ๋์ ๊ฐ์ฒด๋ง ์ฑ๊ธํค์ผ๋ก ๋ฑ๋ก
โ ์๋ฐ ์ฝ๋๋ก ์ง์ ์คํ๋ง ๋น ๋ฑ๋กํ๊ธฐ
@Service, @Repository, @Autowired ์ ๋ ธํ ์ด์ ์ ์ ๊ฑฐํ๊ณ ์งํ
MemberController๋ ์ด๋ ธํ ์ด์ ์ ์ ๊ฑฐํ์ง ์๋๋ค. spring container์ ์ ์ฅํ๊ณ Controller๋ก ๊ด๋ฆฌํด์ผ ํ๊ธฐ ๋๋ฌธ
package hello.hellospring;
import hello.hellospring.repository.MemberRepository;
import hello.hellospring.repository.MemoryMemberRepository;
import hello.hellospring.service.MemberService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration //ํด๋์ค๋ช
์์ @Configuration์ ๋ฑ๋กํ๋ฉด ์คํ๋ง์ด ์ค์ ํ์ผ์์ ์ธ์, ์ปจํ
์ด๋์ ์คํ๋ง ๋น์ ๋ฑ๋กํ ์ค๋น
public class SpringConfig {
//@Bean์ ์ฌ์ฉํ๋ ํด๋์ค์ ๊ฒฝ์ฐ ๋ฐ๋์ @Configuration์ ๊ฐ์ด ์ฌ์ฉ
@Bean //์๋์ผ๋ก Bean ๊ฐ์ฒด ์์ฑ
public MemberService memberService(){
return new MemberService(memberRepository());
}
@Bean
public MemberRepository memberRepository(){
return new MemoryMemberRepository();
}
}
โ DI์ 3๊ฐ์ง ๋ฐฉ๋ฒ
โช Field ์ฃผ์
@Autowired private MemberService memberService;
๋ฉค๋ฒ ๋ณ์ ์์ @Autowired ์ด๋ ธํ ์ด์ ์ ๋ถ์
โช Setter ์ฃผ์
@Controller
public class MemberController {
private MemberService memberService;
@Autowired
public void setMemberService(MemberService memberService) {
this.memberService = memberService;
}
}
setter๊ฐ public์ผ๋ก ์ค์ ๋์ด์์ด ๋ฌธ์ ๊ฐ ์๊ธธ ๊ฐ๋ฅ์ฑ์ด ์์
โช ์์ฑ์ ์ฃผ์
@Controller
public class MemberController {
private final MemberService memberService;
@Autowired
public MemberController(MemberService memberService) {
this.memberService = memberService;
}
}
์กฐ๋ฆฝ(์์ฑ์ ํธ์ถ) ์์ ์ ์์ฑ์๋ฅผ ํ ๋ฒ๋ง ํธ์ถํ์ฌ ์ปจํ ์ด๋์ ์คํ๋ง ๋น์ ๋ฑ๋กํ๊ณ , ์ดํ์๋ ์์กด๊ด๊ณ๊ฐ ๋์ ์ผ๋ก ๋ณ๊ฒฝ๋๋ ๊ฒฝ์ฐ๊ฐ ๊ฑฐ์ ์๊ธฐ ๋๋ฌธ์ ์์ฑ์ ์ฃผ์ ๊ถ์ฅ