[Spring] 스프링 입문

호호빵·2022년 6월 13일
0

Spring

목록 보기
4/24

환경설정

  • 스프링부트 스타터
  • Gradle 설정
  • intelliJ 단축키 보는 법(Settings - keymap)
  • thymeleaf 템플릿 엔진
  • 빌드하고 실행하기
    .gradlew build
     cd build/libs
     java -jar hello-spring-0.0.1-SNAPSHORT.jar


스프링 웹 개발 기초

정적컨텐츠
- resources/static/hello-static.html 등록 후 localhost 실행

MVC와 템플릿 엔진

  • model, view, controller
  • 템플릿 엔진 : 템플릿 양식과 특정 데이터 모델에 따른 입력 자료를 합성하여 결과 문서를 출력하는 소프트웨어(또는 소프트웨어 컴포넌트)
@Controller
public class HelloController {
   
   @GetMapping("hello-mvc")
   public String helloMvc(@RequestParam("name") String name, Model model) {
     model.addAttribute("name", name);
   	 return "hello-template";
   }
}
# View
# resources/static/hello-static.html

<html xmlns:th="http://www.thymeleaf.org">
<body>
<p th:text="'hello ' + ${name}">hello! empty</p>
</body>
</html>

-> localhost:8080/hello-mvc?name=spring 확인

API

나중에!!!!



회원관리 예제(백엔드)

웹 계층 구조

  • 컨트롤러 : 웹 MVC의 컨트롤러 역할
  • 서비스 : 핵심 비즈니스 로직 구현
  • 레포지토리 : DB에 접근, 도메인 객체를 DB에 저장하고 관리
  • 도메인 : 비즈니스 도메인 객체
src
main
ㄴ resources 
		ㄴ static
            ㄴ index.html
		ㄴ templates
        	ㄴ hello.html
            ㄴ hello-template.html
        ㄴ application.properties
ㄴ java 
	ㄴ hello.hellospring
                ㄴ controller
                        ㄴ HelloController
                ㄴ domain 
                        ㄴ Member
                ㄴ repository
                        ㄴ MemberRepository (i)
                        ㄴ MemoryMemberRepository

멤버 객체, 멤버 레포지토리, 멤버 레포지토리 구현 객체

# domain.Member.java
package hello.hellospring.domain;

public class Member {
	private Long id;
    private String name;
    
    // Getter and Setter
}

# MemberRepository - 인터페이스
public interface MemberRepository {
    Member save(Member member);
    Optional<Member> findById(Long id);
    Optional<Member> findByName(String name);
    List<Member> findAll();
}

# 멤버레포지토리 메모리 구현체
public class MemoryMemberRepository implements MemberRepository {

    private static Map<Long, Member> store = new HashMap<>();
    private static long sequence = 0L;


    @Override
    public Member save(Member member) {
        member.setId(++sequence);
        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();
    }

    @Override
    public List<Member> findAll() {
        return new ArrayList<>(store.values());
    }

    public void clearStore() {
        store.clear();
    }
}


서비스 개발

@Service
public class MemberService {
    private final MemberRepository memberRepository;

    @Autowired
    public MemberService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

    public Long join(Member member) {
        // 같은 이름이 있는지 찾아봄
        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();
    }

    public Optional<Member> findOne(Long memberId) {
        return memberRepository.findById(memberId);
    }

}

멤버 레포지토리 테스트 케이스 작성

  • JUnit 이라는 프레임워크로 테스트 실행
  • test/java/ 안에 test 만들어서 실행
class MemoryMemberRepositoryTest {

    MemoryMemberRepository repository = new MemoryMemberRepository();

    @AfterEach
    public void afterEach() {
        repository.clearStore();
    }

    @Test
    public void save() {
    	//given  이러한 상황에서
        Member member = new Member();
        member.setName("spring");
		
        //when  이걸 실행하면
        repository.save(member);

		//then 이렇게 됨
        Member result = repository.findById(member.getId()).get();
        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);

    }
}

서비스 테스트

public class MemberService {
  // private final MemberRepository memberRepository = 
    							// new MemoryMemberRepository();
  // 기존에는 서비스가 메모리 리포지토리를 직접 생성하게 함
  
  private final MemberRepository memberRepository;
  
  public MemberService(MemberRepository memberRepository) {
 	this.memberRepository = memberRepository;
 }
 
 // 서비스 코드를 DI 가능하게 변경
 .
...


# 각 테스트가 종료될 때마다 기능 실행(메모리 DB에 저장된 데이터 삭제
	@AfterEach
    public void afterEach() {
        memberRepository.clearStore();	// clear 처리 해줌
    }
    
# test 하는 것이 new 객체가 아닌 바로 그 객체를 사용하기 위해 
# test 전에 만들어줌 (D.I)
    @BeforeEach
    public void beforeEach() {
        memberRepository = new MemoryMemberRepository();
        memberService = new MemberService(memberRepository);
    }

# @Autowired 
스프링이 연관된 객체를 스프링 컨테이너에서 찾아서 넣어줌
    
@Test 껍데기 자동으로 만들기 
클래스 네임 - cmd+sh+t

null 오류 발생 위험이 있으면 Optional로 감싸기

스프링 빈, D.I

스트링 빈 등록 방법

1. 컴포넌트 스캔, 자동 의존관계

DI(Dependency Injection) : 객체 의존관계를 외부에서 넣어주는 것


@Controller
public class MemberController {

    private final MemberService memberService;   
    // 객체를 생성할 필요없이 하나를 공용으로 사용하면 됨

    @Autowired
    public MemberController(MemberService memberService) {
        this.memberService = memberService;
    }
}

@Autowired로 memberService를 자동 주입
-> 스프링 빈으로 등록되어 있지 않아서 오류남
-> @Component 로 컴포너트 스캔하면 자동 등록 됨
   (@Controller, @Service, @Repository)
  
# 생성자에 @Autowired 사용하면 객체 생성 시점에 
  스프링 컨테이너에서 해당 스프링 빈을 찾아 주입

# 스프링 빈을 등록할 때 기본으로 싱글톤으로 등록

2. 자바 코드로 직접 스프링 빈 등록

  • SpringConfig 파일 생성
@Configuration
public class SpringConfig {
	@Bean
    public MemberService memberService() {
    	return new MemberService(memberService());
    }
    
    @Bean
    public MemberRepository memberRepository() {
    	return new MemoryMemberRepository();
    }
}
  • 주로 정형화된 컨트롤러, 서비스, 리포지토리 같은 코드는 컴포넌트 스캔 사용
  • 정형화되지 않거나 상황에따라 구현 클래스를 변경한다면 설정을 통해 스프링 빈 등록
  • @Autowired를 통한 DI는 helloContorller, memberService 등과 같이 스프링이 관리하는 객체에서만 동작(내가 직접 생성한 객체 x)

회원관리

controller(GetMapping) -> return creat.html -> 뷰 리졸버가 creat.html 선택 - thymeleaf 템플릿 엔진이 렌더링

H2 연결

# build.gradle
dependencies 에 추가
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
	runtimeOnly 'com.h2database:h2'
    
# 스프링부트 DB연결 설정 추가
spring.datasource.url=jdbc:h2:tcp://localhost/~/test
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa

스프링부트 테스트

@SpringBootTest : 스프링 컨테이너와 테스트를 함께 실행
@Transactinal : 테스트 시작 전 시작하고 테스트 완료 후 항상 롤백(DB에 데이터가 넘어가지 않으므로 다음 테스트에 영향 x) 
profile
하루에 한 개념씩

0개의 댓글