INTELLIJ H2 데이터베이스 설치

https://www.h2database.com/html/main.html - All Platforms 다운 - 압축 풀기 - 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

INTELLIJ 홈 화면 추가

* welcome페이지를 만들었다고 해도, controller에 이미 같은경로가 만들어져 있으면, 우선순위에 밀린다

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";
    }
}
<!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>

 

실행 결과 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

INTELLIJ 등록

package hello.hellospring.controller;

import hello.hellospring.domain.Member;
import hello.hellospring.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

@Controller
public class MemberController {

    private final MemberService memberService;

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

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

    @PostMapping("/members/new")
    public String create(MemberForm form) {
        Member member = new Member();
        member.setName(form.getName());

        memberService.join(member);

        return "redirect:/";
    }
}
package hello.hellospring.controller;

public class MemberForm {
    private String name;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
<!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>

 

실행 결과

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

INTELLIJ 조회

package hello.hellospring.controller;

import hello.hellospring.domain.Member;
import hello.hellospring.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

import java.util.List;

@Controller
public class MemberController {

    private final MemberService memberService;

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

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

    @PostMapping("/members/new")
    public String create(MemberForm form) {
        Member member = new Member();
        member.setName(form.getName());

        memberService.join(member);

        return "redirect:/";
    }

    @GetMapping("/members")
    public String list(Model model){
        List<Member> members = memberService.findMembers();
        model.addAttribute("members", members);
        return "members/memberList";
    }
}
<!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>

 

실행 결과

 

 

 

 

 

 

 

 

INTELLIJ 스프링 빈을 등록하는 방법 (컴포넌트 스캔과 자동 의존관계 설정)

* @Autowired를 한 객체는 @Service든 @Repository 등을 해줘야 한다

 

컴포넌트 스캔과 자동 의존관계 설정

: @Controller나 @Service등을 쓰는 방식 (해당하는 것들이 모두 컴포넌트이다, 싱글톤 형식)

*@Controller랑 @Service를 @Autowired로 연결해주는 형식

* 컴포넌트는 main메서드에 해당하는 패키지의 하위 패키지에서만 설정 가능

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

INTELLIJ 스프링 빈을 등록하는 방법 ( 자바 코드로 직접 스프링 빈 등록하기 )

자바 코드로 직접 등록

SpringConfig 클래스 생성 - @Configuration 작성 - @Bean 작성(SpringBean을 등록하겠다는 의미)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

INTELLIJ DI

1. 생성자 주입(가장 좋다)

 

2. 필드 주입(세팅할 때, 변경이 힘들어 좋지 않다.)

 

3. Setter 주입(중간에 변경할 필요가 없지만, public으로 설정해야 한다)

(alt + insert) - setter - 생성 - 생성된 메소드에 @Autowried 작성

 

* 정형화된 것은 컴포넌트 스캔 사용, 정형화되지 않거나 구현 클래스를 변경해야 하면 스프링 빈 등록

 

 

 

 

 

 

 

 

 

INTELLIJ 비지니스 요구사항 정리

데이터 : 회원ID, 이름

기능 : 회원 등록, 조회

아직 데이터 저장소가 선정되지 않음

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

INTELLIJ 회원 도메인과 리포지토리 만들기

Optional : null일수도, 아닐수도 있는 객체를 감싸는 래퍼 클래스

Optional.ofNullable(객체명) : null인지 아닌지 모를 때 사용

 

store.values().stream()

.filter(member -> member.getName().equals(name))

.findAny();

: store의 values값을 반복문처럼 돌려서, 만약 .filter뒤쪽에 해당하는 값이 true일때만 필터링이 적용

finAny()는 하나라도 찾는것, 만약 찾으면 반환, 못찾으면 null값 반환

package hello.hellospring.domain;

public class Member {
    private Long id;
    private String name;

    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
}
package hello.hellospring.repository;

import hello.hellospring.domain.Member;

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

public interface MemberRepository {
    Member save(Member member);
    Optional<Member> findById(Long id);
    Optional<Member> findByName(String name);
    List<Member> findAll();
}
package hello.hellospring.repository;

import hello.hellospring.domain.Member;

import java.util.*;

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

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

INTELLIJ 회원 리포지토리 테스트 케이스 

* main메서드를 통해서 실행하면,  오래 걸리고 한번에 실행하기 어렵다

따라서, JUNIT을 통해 테스트를 한다

@Test : test실행이 가능하다

 

Assertions.assertThat(member).isEqualTo(result) : 만약 둘의 값이 같다면 ↓

 

값이 다르다면 ↓

 

* .get() : 해당 객체를 가져온다

 

* 아래와 같이 선택(alt + enter)하면, 

Assertions.assertThat(member).isEqualTo(result)를 assertThat(member).isEqualTo(result)으로 사용 가능

 

* test를 각 메소드에서 실행 시킬수도 있지만, 클래스에서 실행하면 전체 다 실행 가능하다.

* 테스트 순서는 보장되어 있지 않다

 

@AfterEach : 각 메소드의 테스트가 끝나면, @AfterEach 메소드를 호출한다.

해당하는 저장소를 clear하는 메소드를 만든후, @AfterEach에 해당하는 메소드에서 호출한다

* ↓아래에 해당하는 코드가, store를 clear하는 명령어 및 메소드이다.

 

package hello.hellospring.repository;

import hello.hellospring.domain.Member;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;

import java.util.List;

import static org.assertj.core.api.Assertions.*;

public class MemoryMemberRepositoryTest {

    MemoryMemberRepository repository = new MemoryMemberRepository();

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

    @Test
    public void save(){
        Member member = new Member();
        member.setName("spring");

        repository.save(member);
        Member result = repository.findById(member.getId()).get();

        assertThat(member).isEqualTo(result);
        //Assertions.assertEquals(member, 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);
    }
}

 

실행 결과

정상적으로 test 실행

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

INTELLIJ 회원 서비스 개발

변수명.ifPresent(함수) : 변수의 값이 null이 아니면 함수 실행 (해당 변수가 Optional이여서 가능)

* (ctrl + t)를 통해 해당 기능 함수를 하나의 메소드로 묶어서 호출하는 형식으로 변환 가능

throw new IlligalStateException("어쩌고") : 해당 함수가 예외가 발생하였을 때, "어쩌고" 전송

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

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

INTELLIJ 회원 서비스 테스트

 

(ctrl + shift + t) : 해당하는 클래스의 테스트 클래스를 자동으로 만들어주는 역할

 

* 왼쪽의 MemberService에서  (ctrl + shift + t)설정을 마치면 오른쪽에 클래스(MemberServieTest)클래스가 생성된다

* 테스트 클래스의 메소드 명을 한글로 써도 무관하다

 

* ctrl + alt + v : 해당하는 객체의 타입을 만들어서 지정해준다

왼쪽에서 오른쪽으로 변함

 

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;

    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);
    }
}
package hello.hellospring.service;

import hello.hellospring.domain.Member;
import hello.hellospring.repository.MemoryMemberRepository;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.util.Optional;

import static org.assertj.core.api.Assertions.*;
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 회원가입() {
        //given
        Member member = new Member();
        member.setName("spring");

        //when
        Long saveId = memberService.join(member);

        //then
        Member findMember = memberService.findOne(saveId).get(); //asdfasdfasd
        assertThat(member.getName()).isEqualTo(findMember.getName());
    }

    @Test
    public void 중복_회원_예외(){
        Member member1 = new Member();
        member1.setName("sping");

        Member member2 = new Member();
        member2.setName("sping");

        memberService.join(member1);
        IllegalStateException e = assertThrows(IllegalStateException.class, () -> memberService.join(member2));
        assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다");
//        try {
//            memberService.join(member2);
//            fail();
//        }catch (IllegalStateException e){
//            assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다");
//        }

    }

    @Test
    void findMembers() {
    }

    @Test
    void findOne() {
    }
}

 

 

 

 

 

 

 

 

 

INTELLIJ 정적 컨텐츠

정적 컨텐츠 : 웹브라우저에 그냥 내려주는 서비스, 변환하지 않고 넘겨준다

정적 컨텐츠 생성 위치 : src/main/resources/static/파일명(hello-static).html

해당 파일 경로 : localhost:8080/파일명(hello-static) .html

* 동작 원리 : 웹 브라우저에서 (hello-static).html의 경로를 요청 받으면, 먼저 컨트롤러에서 찾는다. 

해당 경로가 컨트롤러에 없으면,  src/main/resources/static/에서 찾는다.

<!DOCTYPE HTML>
<html>
<head>
    <title>static content</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
정적 컨텐츠 입니다.
</body>
</html>

 

실행 결과 

경로 확인

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

INTELLIJ mvc & 템플릿 엔진

mvc, 템플릿 엔진 : 서버에서 html을 동적으로 바꿔서 내보내는 것, 변환 후 넘겨준다

* @RequestParam("아이디명") 타입 변수명 : req값을 넒겨 받는 용도

package hello.hellospring.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class HelloController {

    @GetMapping("hello")
    public String hello(Model model){
        model.addAttribute("data", "hello!!");
        return "hello";
    }

    @GetMapping("hello-mvc")
    public String helloMvc(@RequestParam("name") String name, Model model){
        model.addAttribute("name", name);
        return "hello-template";
    }
}

 

실행 결과

경로 확인

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

INTELLIJ api

api : json 구조로 클라이언트에게 전달하는 방식

@ResponseBody : HTTP body부분에 직접 넣겠다는 의미

따라서, 해당 페이지 페이지 소스를 보게 되면 보통 아래와 같이 html태그들이 보인다

 

하지만, @ResponseBody를 추가하게 되면 아래와 같이 html태그가 없다

 

 

json이란? key, value로 이루어진 구조

json형식 만드는법 : return 값을 html파일로 명시하지 않고, 보내고 싶은 데이터를 지정

위와 같이, 받아온 name을 getter setter를 통해 저장한 후 해당 객체를 보내준다.

 

실행 결과

json 형식 !!!

 

@Responsebody가 붙어있지 않으면, return을 통해  templates/html파일로 전달한다 (viewResolver 동작)

@ResponseBody 가 있으면, return값이 문자인 경우 문자 내용을 그대로 반환 (StringConverter 동작)

return값이 객체인 경우, default값으로 json형식으로 반환 (JsonConverter 동작)

 

 

 

 

 

 

 

 

INTELLIJ 기본 설정 및 실행

* gradle : 버전 설정, 라이브러리 땡겨옴

* 만약 실행(run)이 안될 경우, .idea를 삭제하고 다시 실행시켜본다.

해당 main이 실행이 되면

localhost:8080 검색 - 

위와 같이 뜨면 정상적으로 작동중.

 

* File - Settings - gradle 검색 - (Build and run using, Run tests using) intellij로 변경

이유 : gradle을 거치지 않아, 속도가 더 빠르다

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

INTELLIJ 라이브러리

gradle 관련 라이브러리 등 확인 가능

* 실무에서는 system.out 대신 log를 사용한다

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

INTELLIJ view 환경 설정

* welcome 페이지 = domain(localhost:8080)만 입력했을 때 나오는 화면

* welcome 페이지 명 : html명은 반드시 index.html으로 설정해야 한다

* welcome 페이지 위치 : src/main/resources/static/index.html

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

INTELLIJ controller

 

controller 설정 위치 : src/main/java/파일명(hello.hello-sping)/패키지(controller) 생성

해당 패키지 안에 클래스(HelloController) 생성

@Controller 및 @GetMapping 추가

 

해당하는 @GetMapping한 메소드 return한 내용은 src/main/resources/templates/파일명.html로 이동

* Thymeleaf는 템플릿 엔진으로, 동적으로 HTML파일을 처리하는데 사용

* 따라서 controller에서 받은 데이터를 처리해야 하므로 Thymeleaf를 사용

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

INTELLIJ 빌드 및 실행

 

* 빌드를 실행하기 전에는, 서버를 끄고 실행한다

빌드 실행 방법 : terminal창 이동 - 해당 프로젝트 위치로 이동(cd사용)

해당 프로젝트 위치에서 (./gradlew build) 명령어 실행

해당 브로젝트 위치/build 이동 - 해당 브로젝트 위치/build/libs 이동

ls를 통해 directoryf를 확인 - 마지막에 SNAPSHOT.jar가 포함된 Name 복사

해당 위치에서 (java -jav 붙여넣기) 명령어 실행 - 아래와 같이 화면 출력

- 해당 페이지가 뜨면, 서버도 정상적으로 실행 

* 만약 실행이 잘 안 될 경우, ./gradlew build 대신 ./gradlew clean build 실행

 

 

 

 

 

 

intellij 설치

https://www.jetbrains.com/ko-kr/idea/download/ - Intellij IDEA Community Edition 설치 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

intellij 프로젝트 생성

https://start.spring.io/ - Gradle - 3.2.5 - java버전 설정(17) - Dependencies - Spring Web, Thymeleaf 추가 - GENERATE

open folder - (설치한 폴더 - build.gradle)선택 - Open as Project

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

intellij 설정

terminal - ./gradlew clean  을 통해 gradle 초기화

File - Project Structure - SDK - 17버전 설정

시스템 환경 변수 편집 - 환경 변수 - 시스템 변수 - 새로 만들기

- (변수이름 : JAVA_HOME, 변수 값 : jdk-17경로)

시스템 환경 변수 편집 - 환경 변수 - 시스템 변수 - Path - 새로 만들기

- jdk-17\bin경로 추가

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

+ Recent posts