728x90
반응형
참고 강의 : (인프런) 스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
@ResponseBody 객체 반환
@GetMapping("hello-string")
@ResponseBody //http 바디에 직접 넣어주겠다. -> html 파일이 따로 필요없이 return 값이 걍 그 페이지 자체가 됨
public String helloString(@RequestParam("name") String name){ // 링크에 ? 로 name 의 키값 입력해주는건 동일
return "hello "+name; // 이거 그대로가 /hello-string 페이지에 보여짐
}
@GetMapping("hello-api")
@ResponseBody //viewResolver가 아닌 httpMessageConverter로 동작하고, 객체면 jsonConverter로 동작
public Hello helloApi(@RequestParam("name") String name){
Hello hello = new Hello();
hello.setName(name); //json 방식으로 반환 => "name": "sprindfsd"
return hello;
}
static class Hello{
private String name;
//getter setter 자동 생성성
// java bin 표준 방식
//property 접근 방식
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@ResponseBody 를 사용하고, 객체를 반환하면 객체가 JSON으로 변환됨
실행
http://localhost:8080/hello-api?name=spring
@ResponseBody 사용 원리
- @ResponseBody 를 사용
- HTTP의 BODY에 문자 내용을 직접 반환
viewResolver 대신에 HttpMessageConverter 가 동작
기본 문자처리: StringHttpMessageConverter
기본 객체처리: MappingJackson2HttpMessageConverter
byte 처리 등등 기타 여러 HttpMessageConverter가 기본으로 등록되어 있음
참고: 클라이언트의 HTTP Accept 해더와 서버의 컨트롤러 반환 타입 정보 둘을 조합해서
HttpMessageConverter 가 선택된다. 더 자세한 내용은 스프링 MVC 강의에서 설명하겠다
Test 케이스 작성
test 내 MemoryMemberRepositoryTest 클래스 만들고 작성
package hello.hellospring.repository;
import hello.hellospring.domain.Member;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.assertj.core.api.Assertions.*;
class MemoryMemberRepositoryTest {
MemoryMemberRepository repository = new MemoryMemberRepository();
//Test 할때마다 레포를 깔끔히 지워줘야함
@AfterEach
public void afterEach(){
repository.clearStore();
}
@Test
public void save(){
Member member = new Member();
member.setName("hehesun");
repository.save(member);
Member result = repository.findById(member.getId()).get();
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);
}
}
main > repository > MemoryMemberRepository
에서 clearStore 메서드 추가
public void clearStore(){
store.clear();
}
회원 서비스 개발
package hello.hellospring.service;
import hello.hellospring.domain.Member;
import hello.hellospring.repository.MemberRepository;
import hello.hellospring.repository.MemoryMemberRepository;
import java.util.List;
import java.util.Optional;
public class MemberService {
private final MemberRepository memberRepository = new MemoryMemberRepository();
/**
* 회원가입
*/
public Long join(Member member){
validateDuplicateMember(member); //중복 회원 검증
memberRepository.save(member);
return member.getId();
}
private void validateDuplicateMember(Member member) {
//동명이인 안됨
//null 일 가능성이 있으면 optional로 한번 감싸서 진행 => 자동으로 감싸짐
memberRepository.findByName(member.getName())
.ifPresent(m -> {
throw new IllegalStateException("이미 존재하는 회원입니다.");
});
}
/**
* 전체 회원 조회
*/
public List<Member> findMembers() {
return memberRepository.findAll();
}
public Optional<Member> findOne(Long memberId) {
return memberRepository.findById(memberId);
}
}
회원 서비스 테스트
ctrl + shift + t ⇒ test case 자동 작성
given when then 문법
- given : 주어진 상황
- when : 이걸로 실행되었을때
- then : 이렇게 결과가 나와야함 (검증부)
기존에는 회원 서비스가 메모리 회원 리포지토리를 직접 생성하게 했다
public class MemberService {
private final MemberRepository memberRepository = new MemoryMemberRepository();
}
회원 리포지토리의 코드가
회원 서비스 코드를 DI 가능하게 변경한다.
public class MemberService {
private final MemberRepository memberRepository;
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository; //외부에서 넣어주도록 바꾸기
}
회원 서비스 테스트
package hello.hellospring.service;
import hello.hellospring.domain.Member;
import hello.hellospring.repository.MemoryMemberRepository;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.junit.jupiter.api.Assertions.*;
class MemberServiceTest {
MemberService memberService;
MemoryMemberRepository memberRepository;
@BeforeEach
public void beforeEach() {
//테스트가 독립적으로 실행되야기 때문에 각각 객체 생성
memberRepository = new MemoryMemberRepository();
memberService = new MemberService(memberRepository);
}
@AfterEach
public void afterEach() {
memberRepository.clearStore();
}
@Test
void join() {
//회원가임
//Given
Member member = new Member();
member.setName("spring");
//When
Long saveId = memberService.join(member);
//Then
Member findMember = memberService.findOne(saveId).get();
assertEquals(member.getName(), findMember.getName());
}
@Test
public void 중복_회원_예외() {
//Given
Member member1 = new Member();
member1.setName("spring");
Member member2 = new Member();
member2.setName("spring");
//When
memberService.join(member1);
IllegalStateException e = assertThrows(IllegalStateException.class,
() -> memberService.join(member2));//예외가 발생해야 한다.
assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다.");
}
@Test
void findMembers() {
}
@Test
void findOne() {
}
}
- @BeforeEach : 각 테스트 실행 전에 호출된다. 테스트가 서로 영향이 없도록 항상 새로운 객체를 생성하고, 의존관계도 새로 맺어준다.
스프링 빈을 등록하는 2가지 방법
- 컴포넌트 스캔과 자동 의존관계 설정
- 자바 코드로 직접 스프링 빈 등록하기
1. 컴포넌트 스캔과 자동 의존관계 설정
컴포넌트 스캔 원리
- @Component 애노테이션이 있으면 스프링 빈으로 자동 등록된다.
- @Controller 컨트롤러가 스프링 빈으로 자동 등록된 이유도 컴포넌트 스캔 때문이다.
- @Component 를 포함하는 다음 애노테이션도 스프링 빈으로 자동 등록된다.
- @Controller
- @Service
- @Repository
2. 자바 코드로 직접 스프링 빈 등록하기
원 서비스와 회원 리포지토리의 @Service, @Repository, @Autowired 애노테이션을 제거하고
진행한다. (Controller에 @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
public class SpringConfig {
@Bean
public MemberService memberService() {
return new MemberService(memberRepository());
}
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
}
스프링 IoC 컨테이너와 빈
https://www.youtube.com/watch?v=L-0UvbFUXrk (백기선님 강의 일부)
Inversion of Control : 의존성 관계 주입 (Dependency Injection) 이라고도 함. 어떤 객체가 사용하는 의존 객체를 직접 만들어 사용하는 것이 아니라, 주입 받아 사용하는 방법.
스프링 IoC 컨테이너
- 빈들이 모여있음 (코드로 모아놔야함)
- 애플레케이션 컴포넌트의 중앙 저장소
- 빈 설정 소스로 부터 빈 정의를 읽어들이고, 빈을 구성하고 제공한다
빈
- 스프링 IoC 컨테이너가 관리하는 객체.
- 의존성 주입을 받으려면 빈으로 들어가 있어야함
- 기본적으로 싱글톤 스코프로 관리된다.
어노테이션 Service, Repository, Autowired 를 통해 빈으로 주입할 수 있다.
728x90
반응형
'웹' 카테고리의 다른 글
[Spring] 스프링 입문 3 : 스프링 데이터 JPA 와 AOP (0) | 2022.07.22 |
---|---|
[Spring] 스프링 입문 2 (0) | 2022.07.21 |
[Vue.js] 데이터 전달 방법2 : vuex - state, mutations 개념과 활용 (0) | 2022.04.01 |
[Vue.js] 데이터 전달 방법1 : props, emit 개념과 활용 (0) | 2022.03.31 |
[Vue.js] Router 설정하기 : params, query 자세한 사용법 (0) | 2022.03.30 |