WEB

[강의기록] 스프링 입문 - 코드로 배우는 스프링 부트 [完]

공멍 2025. 1. 18. 01:07

스프링 입문 - 코드로 배우는 스프링 부트

상태: 완료
참고자료: https://www.inflearn.com/course/스프링-입문-스프링부트 
날짜: 2025년 1월 11일 → 2025년 1월 16일

 

[지금 무료]스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술 강의 | 김영한 - 인프런

김영한 | 스프링 입문자가 예제를 만들어가면서 스프링 웹 애플리케이션 개발 전반을 빠르게 학습할 수 있습니다., 스프링 학습 첫 길잡이! 개발 공부의 길을 잃지 않도록 도와드립니다. 📣 확

www.inflearn.com

https://start.spring.io

 

 

→스프링 부트 기반으로 프로젝트 만들어주는 사이트

 

https://spring.io/projects/spring-boot

 

Spring Boot

 

spring.io

 

→ 여기서 찾아가면서 개발할 수 있음

 

gradlew.bat build

→ build 폴더 생성 및 jar 파일 만들어짐

→ 이거 서버에서 실행하면 돌아가는 것

  1. 정적(static) 컨텐츠

⇒ 그냥 HTML 그대로 인쇄 — JAVA X

  1. MVC & 템플릿
  2. @Controller @GetMapping

⇒ Controller가 템플릿(HTML)에 값을 전달해줌

  1. API
  2. @GetMapping @ResponseBody

⇒ JAVA가 그대로 값 전달— 객체를 전달하면 JSON 형태로 옴


3강 회원관리 예제 - 백엔드 개발

비즈니스 요구사항 정리

인터페이스 만들기 — why? 아직 데이터 저장소 고민중이라서 메모리 기반으로 사용

+) 실무에서는 동시성 문제를 고려해서 Map 사용 안하고 ConcurrentHashMap, AtomicLong 사용함

**TEST 과정은 매우 중요함

JUnit 에서 test의 순서는 고려되지 않기 때문에 각각 독립적으로 동작해야함.

테스트 순서에 의존관계가 있는 것은 좋은 테스트가 아니다

@AfterEach : 한번에 여러 테스트 실행하면 메모리 DB에 직전 테스트 결과 남으므로 이 이노테이션 사용해서 각 테스트가 독립적으로 동작하도록 유도

Test와 실제 코드 객체 통일화—

@BeforeEach : 각 테스트 실행전에 호출, 테스트가 서로 영향이 없도록 항상 새로운 객체를 생성하고, 의존관계도 새로 맺어줌.

@Service @Repository @Controller

@Component 의 특수 케이스

이걸 달고 @Autowired 를 사용하면 객체 생성 시점에 스프링 컨테이너에서 해당 스프링 빈을 찾아서 의존성을 주입함!

OR — 자바 코드로 스프링 빈 직접 등록 가능

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();
    }
 }

⇒ 차후에 변경 사항이 있을 때에는 이렇게 설정하는 것이 더 유리할듯.


5. 회원 관리 예제 - 웹 MVC 개발

** 컨트롤러가 정적파일보다 우선순위가 높아서, Controller로 설정해두면 index.html 무시됨.

thymeleaf — 사용하면 html 템플릿으로 for each 문법 사용할 수 있음.

      <tr th:each="member : ${members}">
        <td th:text="${member.id}"></td>
        <td th:text="${member.name}"></td>
      </tr>

6. Spring DB 접근 기술

H2 연결

spring.datasource.url = jdbc:h2:tcp://localhost/~/test
spring.datasource.username=sa
spring.datasource.password=

Repository 바뀌어도, JdbcMemberRepository 클래스 생성하고

// SpringConfig 파일
@Configuration
public class SpringConfig {
    private DataSource dataSource;

    @Autowired
    public SpringConfig(DataSource dataSource){
        this.dataSource = dataSource;
    }

    @Bean
    public MemberService memberService() {
        return new MemberService(memberRepository());
    }

    @Bean
    public MemberRepository memberRepository() {
        //return new MemoryMemberRepository();
        return new JdbcMemberRepository(dataSource);
    }
}

@Transactional : 테스트 케이스에 이 애노테이션이 있으면, 테스트 시작 전에 트랜잭션을 시작하고, 테스트 완료 후에 항상 롤백함

@SpringBootTest : 스프링 컨테이너와 테스트를 함께 실행한다. ← 상대적으로 느리고, 단위 테스트가 아니기 때문에 자제하는 것이 좋음. (통합 테스트도 필요하지만, 단위 개념으로 테스트하는 것이 좋은 테스트)

Jdbc & Jdbc Template 까지는 쿼리문을 직접 작성해야함.

JPA — SQL도 JPA가 직접 만들어서 실행, 객체로 Select 가능!

public Optional <Member>  findById(Long id){
    Member member = em.find(Member.class, id);
    return Optional.ofNullable(member);
} // item 하나만 뽑는건 간단히 가능 But 여러개 뽑는 건 불가능

public List<Member> findAll(){
    return em.createQuery("select m from Member m", Member.class)
                    .getResultList();
}

public Optional<Member> findByName(String name){
    List<Member> result = em.createQuery("select m from Member m where m.name = :name", Member.class)
    .setParameter("name", name)
    .getResultList();
    return result.stream().findAny();
}

7장 AOP

package hello.hello_spring.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class TimeTraceAop {
    @Around("execution(* hello.hello_spring..*(..))")
    public Object execute(ProceedingJoinPoint joinPoint) throws Throwable{
        long start = System.currentTimeMillis();
        System.out.println("START: " + joinPoint.toString());
        try{
            return joinPoint.proceed();
        } finally{
            long finish = System.currentTimeMillis();
            long timeMs = finish - start;
            System.out.println("END: " + joinPoint.toString() + " " + timeMs + "ms");
        }
    }
}

 

 


노션으로 작성한 걸 Markdown으로 옮겨온 거라 보기에 어색한 부분 있을 수도 있음

https://github.com/Yevin-WIN/hello-spring 

 

GitHub - Yevin-WIN/hello-spring

Contribute to Yevin-WIN/hello-spring development by creating an account on GitHub.

github.com

 

강의보고 그대로 따라한 github