Notice
Recent Posts
Recent Comments
Link
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

Joon's Space

[Spring] 스프링 부트 스프링 빈과 의존 관계, 웹 MVC 개발 (4) 본문

Web/Spring

[Spring] 스프링 부트 스프링 빈과 의존 관계, 웹 MVC 개발 (4)

Happy Joon 2022. 1. 14. 21:33

스프링 빈 등록하기

- MemberController, MemberService, MemberRepository class에 각각 @Controller, @Service, @Repository를 붙여 주면, 자동으로 의존관계가 등록이 된다. (컴포넌트 스캔 방식) -> main app이 돌아가는 하위 패키지에서만 자동으로 찾아서 등록

 

DI에는 필드 주입, setter 주입, 생성자 주입 3가지가 있는데, 의존관계가 실행중에 동적으로 변하는 경우는 거의 없으므로 생성자 주입을 권장. 

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 // Controller에 Service를 연결
    public MemberController(MemberService memberService) {
        this.memberService = memberService;
    }
}
import hello.hellospring.domain.Member;
import hello.hellospring.repository.MemberRepository;
import hello.hellospring.repository.MemoryMemberRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

@Service
public class MemberService {

    private final MemberRepository memberRepository;

    @Autowired // Service를 Repository에 연결
    public MemberService(MemberRepository memberRepository) { // 직접 생성이 아닌 외부 memberRepository를 설정하여 저장한다.
        this.memberRepository = memberRepository;
    }

    // 회원 가입
    public Long join(Member member) {
        // 같은 이름이 있는 중복 회원 X
        validateDuplicateMember(member); // 중복 회원 검증 ctrl+t 단축키(extract method)
        memberRepository.save(member);
        return member.getId();
    }
...
package hello.hellospring.repository;

import hello.hellospring.domain.Member;
import org.springframework.stereotype.Repository;

import java.util.*;

@Repository
public class MemoryMemberRepository implements MemberRepository{

    private static Map<Long, Member> store = new HashMap<>();
    private static long sequence = 0L; // id key값을 생성할 때 필요한 변수
...

 

- 자바코드로 직접 스프링 빈 등록한다. 

 

hellopsring 패키지 밑에 SpringConfig class 생성 (controller는 그대로 유지, 직접 등록 x)

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

 

실무에서는 위 두 가지 방법 중 컴포넌트 스캔을 주로 사용한다. -> 컨트롤러, 서비스, 레포지토리 같은 코드는 정형화가 되어있기 때문

 

정형화되지 않거나, 상황에 따라 구현 클래스를 변경해야 할 때 설정을 통해 스프링 빈으로 등록한다. 

 

 

웹 MVC 개발

 

- 홈 화면 추가

controller에 HomeController 생성

package hello.hellospring.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class HomeController {

    @GetMapping("/")
    public String home() {
        return "home"; // template에 home.html로드
    }
}

 

resources/template/home.html

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<div class="container">
    <div>
        <h1>Hello Spring</h1>
        <p>회원 기능</p>
        <p>
            <a href="/members/new">회원 가입</a>
            <a href="/members">회원 목록</a>
        </p>
    </div>
</div> <!-- /container -->
</body>
</html>

 

다음 홈화면이 출력됨.

회원 가입 페이지

 

먼저 form데이터에서 데이터를 받아서 name을 받아 올 form class를 생성.

package hello.hellospring.controller;

public class MemberForm {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

 

MemberController에 회원가입 form을 로드하고, input 태그에 입력한 name값을 service의 join기능을 통해 등록하고, 다시 home 화면으로 redirect 한다. 

// MemberController.java

@GetMapping("/members/new")
public String createForm() {
    return "members/createMemberForm";
}

@PostMapping("/members/new") // html의 form action에서 받아온 name을 받아옴.
public String create(MemberForm form) {
    Member member = new Member();
    member.setName(form.getName());

    memberService.join(member); // service의 회원가입 메소드

    return "redirect:/"; // home 화면으로 돌아가기
}

 

회원가입 페이지 html 코드는 다음과 같이 입력

// resources/template/members/createMemberForm.html

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<div class="container">
    <form action="/members/new" method="post">
        <div class="form-group">
            <label for="name">이름</label>
            <input type="text" id="name" name="name" placeholder="이름을 입력하세요">
        </div>
        <button type="submit">등록</button>
    </form>
</div> <!-- /container -->
</body>
</html>

 

회원 목록 페이지

 

// MemberController.java

@GetMapping("/members")
public String list(Model model) {
    List<Member> members = memberService.findMembers();
    model.addAttribute("members", members); // members에 모든 member 정보를 넘겨줌.
    return "members/memberList";
}

회원 등록을 한 member들의 list를 받아 model의 members로 리스트 값을 넘겨준다. 그리고 나서 members/memberList.html 파일을 로드한다.

 

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<div class="container">
    <div>
        <table>
            <thead>
            <tr>
                <th>#</th>
                <th>이름</th>
            </tr>
            </thead>
            <tbody>
            <tr th:each="member : ${members}">
                <td th:text="${member.id}"></td>
                <td th:text="${member.name}"></td>
            </tr>
            </tbody>
        </table>
    </div>
</div> <!-- /container -->
</body>
</html>

여기서는 타임리프가 작동이 되는데, model에 넘겨준 members가 each를 통해 loop가 돌아 각 member의 값이 member에 넘어가 테이블의 열로 하나씩 추가된다. 

 

회원가입을 3개 등록한 후 회원 목록 페이지 화면

위 회원 데이터는 memory에 저장되어 있기 때문에, 서버를 다시 시작하면 모두 사라지게 되므로, 서버를 재시작해도 등록한 회원정보를 계속 로드할 수 있게 데이터 베이스가 필요하다. 

 

반응형