1. Mock

  • 일반적으로 사용하는 목업(Mock-up)의 의미와 비슷하며, 진짜인 것 처럼 보이도록 만드는 유사한 상황이나 물건, 물질 등을 의미한다
  • 테스트 계통에서의 Mock는 가짜 객체를 의미한다
  • 단위 테스트나 슬라이스 테스트 등에 Mock 객체를 사용하는 것을 Mocking 이라고 한다

2. Mock 객체를 사용하는 이유

  • 테스트의 단위는 적을수록 효율적이다
  • Mock 객체를 사용하지 않으면 Request는 서비스계층을 거쳐 데이터 액세스 계을과 데이터베이스까지 순회한 후 되돌아 온다
  • Mock 객체를 사용하면 Request가 원하는 응답을 상관없는 계층을 제외하고 결과값을 전송할 수 있다

3. Mockito

  • 여러 오픈 소스 라이브러리를 통해 Mock 객체를 생성하고 진짜처럼 동작하게 한다
  • Spring Framework 자체적으로도 지원하고 있는 Mocking 라이브러리가 Mockito이다
  • Mocking 기능을 이용하면 테스트하고자 하는 대상에서 다른 영역(다른 계층 또는 외부 통신이 필요한 서비스 등)을 단절시켜 테스트 대상에만 집중할 수 있다

4. Mockito 예제

 1) MemberController의 postMember() 테스트에 Mockito 적용

package com.codestates.slice.mock;

import com.codestates.member.dto.MemberDto;
import com.codestates.member.entity.Member;
import com.codestates.member.mapper.MemberMapper;
import com.codestates.member.service.MemberService;
import com.codestates.stamp.Stamp;
import com.google.gson.Gson;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.ResultActions;

import static org.mockito.BDDMockito.given;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@SpringBootTest
@AutoConfigureMockMvc
class MemberControllerMockTest {
    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private Gson gson;

    //@MockBean 애너테이션은 Application Context에 등록되어 있는 Bean에 대한 Mockito Mock 객체를 생성하고
    //주입해주는 역할을 한다
    //@MockBean 애너테이션을 필드에 추가하면 해당 필드의 Bean에 대한 Mock 객체를 생성한 후, 필드에 주입(DI)한다
    @MockBean
    //MemberService 빈에 대한 Mock 객체를 생성해서 memberService 필드에 주입한다
    private MemberService memberService;

    //MemberMapper를 DI 받는 이유는 MockMemberService(가칭)의 createMember()에서 리턴하는 Member 객체를
    //생성하기 위함이다
    @Autowired
    private MemberMapper mapper;

    @Test
    void postMemberTest() throws Exception {
        // given
        MemberDto.Post post = new MemberDto.Post("hgd@gmail.com",
                "홍길동", "010-1234-5678");

        //MemberMapper를 이용해 post(MemberDto.Post 타입) 변수를 Member 객체로 변환하고 있다
        //MemberMapper를 사용하지 않고 new Member() 와 같이 Member 객체를 생성해도 되지만
        //여기서는 post 변수를 재사용하기 위해 MemberMapper로 변환을 했다
        Member member = mapper.memberPostToMember(post);

        //실제 MemberService의 createMember()에서 회원 정보 등록 시, Stamp 정보도 등록되며,
        //createMember() 의 리턴 값(Member 객체)에 Stamp 정보가 포함된다
        //MockMemberService(가칭)의 createMember()에서도 리턴 값으로 Stamp 정보가 포함된 Member 객체를
        //리턴하도록 (4)와 같이 Stamp 객체를 추가해  준다
        member.setStamp(new Stamp());
        //Stamp 객체를 추가해주지 않으면 MemberResponseDto 클래스 객체가 JSON으로 변환되는 과정 중에
        //Stamp에 대한 정보가 없다는 예외가 발생한다


        //Mockito에서 지원하는 Stubbing 메서드이다
        given(memberService.createMember(Mockito.any(Member.class)))
        /*given()은 Mock 객체가 특정 값을 리턴하는 동작을 지정하는데 사용한다
          Mockito에서 지원하는 when()과 동일한 기능을 한다
          Mock 객체인 memberService 객체로 createMember() 메서드를 호출하도록 정의 하였다*/
        /*createMember()의 파라미터인 Mockito.any(Member.class) 는 Mockito에서 지원하는
          변수 타입 중 하나이다
          MockMemberService(가칭)가 아닌 실제 MemberService 클래스에서 createMember()의
          파라미터 타입이 Member이므로 Mockito.any()에 Member.class를 타입으로 지정해 준다*/

        //.willReturn(member)은 MockMemberService(가칭)의 createMember() 메서드가 리턴할
        //Stub 데이터이다
               .willReturn(member);

        String content = gson.toJson(post);

        // when
        ResultActions actions =
                mockMvc.perform(
                        post("/v11/members")
                                .accept(MediaType.APPLICATION_JSON)
                                .contentType(MediaType.APPLICATION_JSON)
                                .content(content)
                );

        // then
        MvcResult result = actions
                .andExpect(status().isCreated())
                .andExpect(jsonPath("$.data.email").value(post.getEmail()))
                .andExpect(jsonPath("$.data.name").value(post.getName()))
                .andExpect(jsonPath("$.data.phone").value(post.getPhone()))
                .andReturn();

//        System.out.println(result.getResponse().getContentAsString());
    }
}
  • 실행하면 아래와 같은 결과가 출력된다

  • 실행 결과에서 MockMemberService(가칭)의 createMember() 메서드가 호출되므로, 데이터 액세스 계층쪽의 로직은 실행이 되지 않는다
  • MockMemberService(가칭) 클래스는 테스트하고자 하는 Controller의 테스트에 집중할 수 있도록 다른 계층과의 연동을 끊어주는 역할을 한다
  • MemberService의 클래스 쪽의 createMember()가 호출되지 않고, Mockito가 생성한 MockMemberService(가칭)의 createMember()가 호출되는지 확인해 본다
    - MemberService의 createMember() 메서드 내에 디버깅 용 breakpoint를 추가해서 MemberControllerMockTest 클래스의 실행이 breakpoint에서 멈추는지 확인해 본다
    -  breakpoint 확인을 위한 실행은 Debug 실행으로 해야한다
    - 실행이 멈추지 않고 정상적으로 실행이 된다면 MockMemberService(가칭)쪽의 로직이 실행된다고 유추해 볼 수 있다
  • MemberController의 postMember() 핸들러 메서드 내에서  아래의 코드에 breakpoint를 추가해 본다
 @PostMapping
    public ResponseEntity postMember(@Valid @RequestBody MemberDto.Post requestBody) {
        Member member = mapper.memberPostToMember(requestBody);
        member.setStamp(new Stamp()); // homework solution 추가

  여기에 breakpoint ->     Member createdMember = memberService.createMember(member);

        return new ResponseEntity<>(
                new SingleResponseDto<>(mapper.memberToMemberResponse(createdMember)),
                HttpStatus.CREATED);
    }
  • 디버그 모드에서 MemberControllerMockTest 클래스를 실행해 본다

  • 위와 같이 breakpoint에서 실행이 일시 중지된다
    - IntelliJ IDE의 Debug 창을 확인해 보면 memberService 객체가 Mockito의 Mock 객체인 것을 확인할 수 있다
    - Mockito를 이용하면 의존하는 다른 메서드 호출이나 외부 서비스의 호출을 단절 시켜 원하는 테스트의 범위를 최대한 좁힐 수 있다

▶ IntelliJ debug : https://www.jetbrains.com/help/idea/debug-tool-window.html

 

Debug tool window | IntelliJ IDEA

 

www.jetbrains.com

 

 2) MemberService에 Mockito 적용

  • Mockito를 통해서 DB에서 회원 정보를 조회하지 않고 Member 객체를 제공할 수 있다는 것을 확인해 본다
package com.codestates.slice.mock;

import com.codestates.exception.BusinessLogicException;
import com.codestates.member.entity.Member;
import com.codestates.member.repository.MemberRepository;
import com.codestates.member.service.MemberService;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import java.util.Optional;

import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.BDDMockito.given;

//Spring을 사용하지 않고, Junit에서 Mockito의 기능을 사용하기 위해서는 
  @ExtendWith(MockitoExtension.class)를 추가해야 한다
@ExtendWith(MockitoExtension.class)
public class MemberServiceMockTest {

    //@Mock 애너테이션을 추가하면 해당 필드의 객체를 Mock 객체로 생성한다
    @Mock
    private MemberRepository memberRepository;

    //@InjectMocks 애너테이션을 추가한 필드에 MemberRepository Mock 객체를 주입해 준다
    //memberService 객체는 주입 받은 memberRepository Mock 객체를 포함하고 있다
    @InjectMocks
    private MemberService memberService;

    @Test
    public void createMemberTest() {
        // given
        Member member = new Member("hgd@gmail.com", "홍길동", "010-1111-1111");

        //memberRepository Mock 객체로 Stubbing을 하고 있다
        //memberRepository.findByEmail(member.getEmail())의 리턴 값으로 Optional.of(member)를
          지정했기 때문에 테스트 케이스를 실행하면 결과는 “passed”이다
        //Optional.of(member) 의 member 객체에 포함된 이메일 주소가
          memberRepository.findByEmail(member.getEmail()) 에서 파라미터로 전달한 이메일 주소와
          동일하기 때문에 검증 결과가 “passed”이다
        given(memberRepository.findByEmail(member.getEmail()))
                .willReturn(Optional.of(member)); // (5)

        // when / then (6)
        assertThrows(BusinessLogicException.class, () -> memberService.createMember(member));
    }
}

 

 

 

※ 참조 링크

▶ mockito : https://site.mockito.org/

 

Mockito framework site

Intro Why How More Who Links Training Why drink it? Mockito is a mocking framework that tastes really good. It lets you write beautiful tests with a clean & simple API. Mockito doesn’t give you hangover because the tests are very readable and they produc

site.mockito.org

 https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html

 

Mockito - mockito-core 4.6.1 javadoc

Latest version of org.mockito:mockito-core https://javadoc.io/doc/org.mockito/mockito-core Current version 4.6.1 https://javadoc.io/doc/org.mockito/mockito-core/4.6.1 package-list path (used for javadoc generation -link option) https://javadoc.io/doc/org.m

javadoc.io

 

1. GitHub

 1) 계정 생성

  • https://github.com/에 접속해서 계정을 생성한다
  • 계정 생성 후에는 토큰을 생성한다
  • 토큰 생성 후 윈도우의 자격증명관리자 메뉴로 가서 window자격증명에 등록한다
오른쪽 상단의 메뉴에서 settings 왼쪽 메뉴에서 Developer settings

 

 2) 저장소 생성

  • 메인 화면으로 돌아가서 New 버튼을 눌러 저장소를 생성한다

  • owner은 본인 계정을 선택하고 Repository name에는 프로젝트 명칭을 작성한다

  • Public는 전체에게 공개하는 범위이고 Private는 승인된 계정에만 공개하는 범위이다
    - Public으로 설정하여도 승인하지 않으면 변경을 할 수 없다

 2-1) 저장소 옵션 설정

  • README.md 파일을 자동으로 생성한다

  • Add .gitignore 설정
    - .gitignore 파일을 자동으로 생성한다
    - Java, Node.js 템플릿 중 선택하면 된다
    - Git에서 확인하지 않아야 하는 파일을 점차 추가한다

  • Choose a license 설정
    - 라이센스 파일을 생성해 준다
    - 상용 소프트웨어 개발의 경우는 private 리포지토리를 사용하며, 코드를 공개하지 않기 때문에 라이센스를 보통 작성하지 않는다
    - 오픈소스 소프트웨어 개발의 경우 보통 제약이 적은 MIT 라이센스나 Apache License를 적용한다

▶ 라이선스 종류 : https://www.bloter.net/newsView/blt201410100005 

 

GPL·AGPL·MPL…한눈에 보는 오픈소스SW 라이선스

부끄럽지만 용기내어 고백해볼게요. 크리에이티브 커먼즈 코리아 활동가로 지내면서 크리에이티브 커먼즈 라이선스(CCL)엔 어느정도 익숙하고 많은

www.bloter.net

 

 2-2) 저장소 사용

  • 저장소가 생성되면 Settings를 클릭한다

  • Collaborators에 들어가서 협업자의 GitHup 아이디 또는 이메일을 입력해 준다

 

 3) 파일 올리기 

  • Repository 의 Code 화면에서 해당하는 조건을 선택하여 주소를 복사한다

  • git 파일을 생성했고, 파일까지 commit 한 상황이라면 두번째 조건으로 파일을 올린다
    - 3줄의 문장을 차례로 복사/붙여넣기를 하면 자동으로 실행된다
    - git remote add origin 은 로컬의 Git저장소에 원격 저장소와의 연결을 추가한다는 의미이다
    - 원격 저장소 이름에는 일반적으로 origin을 사용한다
    - git branch -M main 은 원격 저장소의 기본브랜치명을 GitHub에서 권장하는 main으로 한다는 의미이다
    - git push -u origin main 은 로컬 저장소의 커밋된 내역들을 원격 저장소로 업로드 한다는 의미이다
    - 현재 브랜치와 명시된 원격 브랜치를 기본 연결할 경우 -u 또는 --set-upstream 을 사용한다
  • 저장소를 재실행하면 아래와 같이 파일이 업로드 되어 있다

  • git remote 와 git remote -v 를 사용하여 원격 저장소의 내역을 자세히 확인할 수 있다

 

 4) 파일 내려받기

  • Code 화면의 Code 메뉴로 들어가서 Http 주소를 복사한다
    - zip으로 내려받을 경우에는 파일에 .git 파일이 없으므로 Git이 관리를 하지 않는다

  • 탐색기를 열고 저장을 하려는 폴더의 우클릭 메뉴 중 gitbash를 오픈한다
  • 'git clone 원격저장소 주소' 를 사용하여 복사해 둔 Http 주소를 입력 후 파일을 내려받는다

 

 5) 파일 변경 후 업로드

  • Test6 파일을 새로 생성한 후 GitHub에 업로드 한다

  • GitHub의 원격 저장소를 새로고침하면 Test6가 추가된 것을 확인할 수 있다
  • 이미 git push -u origin main으로 원격 브랜치가 지정되어 있기 때문에 git push 만으로도 업로드가 가능하다

 

 7) 로컬 저장소에서 작업하기

  • Github 리포지토리를 생성한 후 해당 레포지토리를 로컬로 clone 받은 다음에 작업을 시작한다
git clone <git 주소>
cd <디렉터리명>
  • 로컬 리포지토리에 [README.md] 파일을 추가한다
    - README.md 파일에는 다음의 정보를 포함한다
     : 프로젝트 이름
     : 프로젝트 핵심 기능 소개
     : 팀원 소개
     : Wiki로 링크
touch README.md

 

README.md 파일은 아래 정보를 꼭 포함해야 합니다.

  • 프로젝트 이름
  • 프로젝트 핵심 기능 소개
  • 팀원 소개
  • Wiki로 링크
# My Todo App

OOOO을 위한 웹 애플리케이션입니다.

## Features

- 편리한 UI로 OOOO를 쉽게 생성하고 삭제할 수 있습니다.
- OOOO에 기한과 카테고리를 설정할 수 있습니다.
- create-react-app으로 간편한 번들링과 배포가 가능합니다.
- Spring Boot로 쉽게 서버 배포를 할 수 있습니다.

## Contributors

- FE: OOO, OOO
- BE: OOO, OOO

## Project Wiki

프로젝트 팀 정보, 기획, 아키텍쳐에 대한 자세한 안내입니다.
http://www.ooooooooo.com/ooo?/ooo

 

 8) 협업자 간의 변경 후 파일 업/다운

  • 로컬 저장소 내용과 원격 저장소의 내용이 모두 변경이 있을 경우에는 로컬에서 push를 할 경우 에러가 발생할 수 있다
  • 원격 저장소의 커밋 내용을 확인하고 변경이 있다면 다음과 같은 방법으로 진행할 수 있다
    - git pull --no-rebase 는 merge 방식으로 파일을 내려받는 방식이다
    - git pull --rebase 는 rebase 방식으로 파일을 내려받는 방식이다
    - pull 진행할 경우 rebase 방식이 협업시에는 용이하다
  •  git pull 을 진행한 후에 git push를 진행하면 충돌 에러가 해결된다
  • git pull --force 는 강제로 이전버전의 커밋으로 돌리는 명령어이며, 협업자와 합의가 없으면 사용하지 않는다

 

2. Git Repository

  • Github는 개발자의 SNS라고 불릴 정도로 다양한 종류의 오픈소스 프로젝트가 공유되어 있다

 1) 필수 파일

  • README.md
    - 오픈소스 프로젝트에 들어가면, 가장 먼저 확인할 수 있는 정보가 README.md 파일이다
    - 기본적인 마크다운 사용법을 알고 있으면 간단한 소개 페이지처럼 제작할 수 있다
    - README.md 파일을 적는 양식은 따로 존재하지 않는다
    - 일반적으로 해당 오픈소스의 활용에 대한 상세한 정보가 작성되어 있다
    - Pre-Project Github 리포지토리 README.md 파일은 아래 정보를 꼭 포함해야 한다
      : 프로젝트 이름
      : 프로젝트 핵심 기능 소개
      : 팀원 소개

 

  • .gitignore
    - gitignore dotfile은 git으로 관리하지 않는 파일의 모음이다
    - 주로 기록되는 파일은 다음과 같다
      : 개인이 따로 관리해야 하는 중요한 secret token
      : 다른 동료와 공유할 필요가 없는 설정 파일
      : 그 외 공유할 필요 없는 파일
    - gitignore에 기록한 파일은 git이 컨트롤 하지 않는다
    - push 할 경우에도 github 리포지토리에 push되지 않는다

 

  • LICENSE
    - 해당 코드의 라이센스를 표기한다
    - 깃허브에 public하게 공개된 리포지토리도 라이센스에 따라서 사용을 할 수도 있고, 하지 못 할 수도 있다
    - 회사에서 사용하는 코드는 private으로 관리하고, 외부에 공개하지 않아 라이센스 정보를 따로 표기하지 않기도 한다
    - 만약에 회사에서 작성하는 코드가 public으로 공개된다면, LICENSE를 명확하게 표기해야 한다

 

 2) 프로젝트 관리에 활용할 수 있는 Github 기능

▶ 이슈 및 풀 리퀘스트 템플릿 정보 : https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/about-issue-and-pull-request-templates 

 

About issue and pull request templates - GitHub Docs

After you create issue and pull request templates in your repository, contributors can use the templates to open issues or describe the proposed changes in their pull requests according to the repository's contributing guidelines. For more information abou

docs.github.com

  • Issue
    - 프로젝트에 새로운 기능을 제안하거나, 버그를 찾아 제보하는 등 프로젝트의 이슈를 의미한다
    - Pre-Project에서는 Issue를 하나의 칸반 티켓처럼 사용한다
    - 세부 설정 기능
     : Assigness : 해당 태스크를 맡은 사람을 지정할 수 있으며, assign yourself를 누르면 자신의 태스크로 만들 수 있다
     : Labels : 태스크 카드에 라벨링을 한다
     : Projects : Projects를 지정한다
     : Milestone : Milestone을 지정다.

 

  • Milestone
    - 이정표의 역할 및 태스크 카드(Issue)를 그룹화하는 데 사용한다
    - Milestone에 연결된 태스크 카드(Issue)가 종료되면 Milestone마다 진행 상황이 업데이트 된다
    - Milestone 기능을 통해 연관된 이슈의 추적과 진행 상황을 파악할 수 있다
    - Pre-Project에서는 Bare Minimum, Advanced Challenge, Nightmare를 표시하기 위해 사용한다

 

  • Pull Request
    - 자신이 작업한 내용을 중요 git branch에 합칠 수 있는지 확인하는 요청이다
    - Github에서는 Pull Request에서 커밋한 코드를 별도로 선택하여 해당 부분에 코멘트를 작성할 수 있다

 

  • Project
    - Github 내에서 업무 관리를 해줄 수 있도록 지원하는 기능이다
    - Pre-Project에서는 이 Project 기능을 이용하여 칸반 보드를 생성하고, 칸반으로 Pre-Project의 업무 흐름을 관리한다

 

3. 칸반

  • 팀과 조직이 작업을 시각화하고, 업무의 병목 현상과 리소스 낭비를 해결하는 업무 관리 방법이다

trello : https://trello.com/ 

 

Manage Your Team’s Projects From Anywhere | Trello

Trello cards are your portal to more organized work—where every single part of your task can be managed, tracked, and shared with teammates. Open any card to uncover an ecosystem of checklists, due dates, attachments, conversations, and more.

trello.com

monday.com : https://monday.com 

 

새로운 업무 방식 을 위한 플랫폼

monday.com work OS는 누구나 업무를 수행하는 데 필요한 툴을 만들 수 있는 개방형 플랫폼입니다.

monday.com

 Asana : https://asana.com/ko 

 

온라인에서 팀의 업무, 프로젝트, 작업 관리 • Asana

언제 어디서나 Asana로 작업하세요. Asana를 활용하여 근무하는 장소와 관계없이 팀과 조직 전체가 최종 목표, 프로젝트, 작업에 집중할 수 있습니다.

asana.com

▶ 작업 관리를 위한 10가지 최고의 온라인 칸반 보드 프로그램
 : https://gitmind.com/kr/kanban-board-online.html 

 

2022년 상위 10개 무료 칸반 보드 프로그램 및 프로젝트 관리 툴

이 게시물에서는 작업을 효과적으로 구성하는 데 도움이되는 최고의 무료 칸반 보드 프로그램에 대해 알아 봅니다.

gitmind.com

 

 1) 칸반 보드를 통한 시각화

  • 칸반 보드는 업무를 하나의 티켓으로 표현하고, 업무 단계를 하나의 열로 표현한다
  • 새로운 업무가 생기면 가장 왼쪽 열에 업무가 쌓이고, 업무가 잘 진행되면 가장 오른쪽으로 전달되어 쌓이는 방식이다
  • 어떤 업무가 현재 어느 업무 단계에 있는지 한눈에 파악할 수 있다

 

 2) Work In Progress(WIP)로 진행중인 업무 제한 및 흐름 관리

  • WIP는 현재 진행하고 있는 작업을 의미한다
  • 칸반에서는 각 업무 단계에 WIP 제한(WIP limit)을 둘 수 있다
  • WIP 제한이 2이면, 두 개 이상의 카드가 해당 열에 위치할 수 없게 됩니다. 아래 예시의 경우 하나의 업무를 추가할 수 있습니다.
  • 업무 흐름 관리
    - 업무가 과도하게 쌓이지 않는 원활한 업무 흐름을 위한 관리이다
    - 모든 팀원이 100%의 리소스를 사용하고 있는 상태에서 계속 새로운 업무가 쌓이게 되면, 업무가 과부하되어서 업무 효율이 나지 않게 된다
    - WIP 제한은 업무의 과부하를 조절해 주는 역할을 한다
  • 진행중인 업무 제한
    - 개발 프로젝트는 타 업무와 달리 맥락 전환(context switching)이 없이 집중할 수 있어야 업무 효율이 증가한다
    - 제조업 업무는 기계 가동률을 높이거나 일부 생산을 아웃소싱하면 짧은 기간 내에 산출물을 만들 수 있다
    - 개발 업무는 지식 업무에 해당하기 때문에 야근을 하거나 인원을 많이 투입한다고 좋은 퀄리티의 산출물이 빠른 시간 안에 나오지 않는다
    - 소통이 많이 필요한 개발 프로젝트의 경우 인원수가 늘어난다고 소요 기간이 확연하게 감소하지 않는다
    - 한 번에 처리하는 업무의 양을 최소화하여 팀원이 한 번에 여러 업무를 동시에 진행해서 생기는 맥락 전환의 문제를 방지한다
    - 업무 흐름을 적당하게 유지시켜 업무가 순차적으로 처리될 수 있도록 한다

 

 3) 명확한 팀 정책 설정

  • 칸반을 잘 활용하기 위해서는 정책을 설정한다
  • 칸반의 열을 정의, WIP limit, 회의 일정, 의사결정 방법 등에 대한 명확한 정책을 수립해야 한다
  • 정책 수립 시에는 팀원이 모두 모여서 합의를 하고, 합의한 정책은 향후 업무 진행 상황에 따라서 팀원이 모여 언제든지 조정할 수 있다
  • 프로젝트 시작하기 전에 정하면 도움이 되는 정책은 아래와 같다
    - 회의 시간 및 해당 회의에서 논의할 내용을 정한다
    - 팀원 간 소통 원칙을 정한다
    - 칸반 티켓을 언제, 어떻게, 누가 추가할 것인지를 정한다
    - WIP 제한을 정한다

 

 4) 회의와 리뷰를 통한 업무 개선

  • 칸반을 사용하는 경우에는 일반적으로 데일리 칸반 회의와 주간 보충 회의를 진행한다
  • 데일리 칸반 회의는 업무의 상태 및 흐름을 파악하고 확인한다
    - 구현하고자 하는 기능을 좀 더 빠르게 구현할 수 있는 방법을 협의한다
    - 업무가 끝난 인원이 다른 업무를 처리할 수 있는지 확인하고 진행한다
  • 주간 보충 회의는 칸반 보드에 추가할 업무가 있는지를 확인하고, 다음 주에 어떤 업무를 할 것인지 정한다
    - 프로젝트 진행 상황이 매우 원활하여, 추가로 구현하기로 했던 기능을 구현할 수 있게 된 경우에는 주간 보충 회의를 통해 해당 기능 구현 티켓을 칸반 보드에 추가할 수 있다
  • 추가로 격주, 혹은 월간으로 KPT 회고를 진행할 수도 있다
    - 지금까지의 진행 상황에 대해서 솔직하게 회고하고, 개선점을 찾을 수 있다

 

 5) 칸반 실천법

  • 칸반의 6가지 실천법을 정리하면 아래와 같다
    1. 업무 시각화
    2. 진행 중인 업무 제
    3. 흐름 관리
    4. 명확한 프로세스 정책
    5. 피드백 루프 구현
    6. 협력적인 개선, 실험적인 발전

 

4. 레포지토리 내에 프로젝트 생성

 1) 프로젝트 생성

  • 레포지토리 > Project > Add project 를 클릭한다
  • 기존에 프로젝트가 있으면 선택하고, 없응면 새로 생성을 클릭한다

  • Table 또는 Board 를 선택한다
    - 설정창이 뜨지 않으면 View1 옆의 아래 화살표를 클릭하면 보인다

  • 오늘쪽 상단의 '...'을 클리한 후 Setting를 클릭한다

  • 프로젝트의 이름과 설명을 작성하고 Save 버튼을 클릭한다

  • 설정 페이지 왼쪽 탭에 Manage access 를 클릭한다
    - Base Role을 필요에 따라 선택하여 변경한다
    - 함께할 팀원이 있다면 권한을 부여하고 초대한다

 

 2) 프로젝트에 Issue 연결

  • '+' 옆 칸에 '#'을 작성하여 해당 레포지토리를 찾아 선택한다
  • 레포지토리 선택 후 옆 칸을 클릭하면 issue나 PR을 선택할 수 있다

  • 리포지토리에 작성한 issue들이 project의 추가된 것을 확인할 수 있다
  • 각 이슈들의 상태를 설정할 수 있다
    - 기본적으로 Todo , In Progress , Done 세가지 상태가 있다
  • '+'를 클릭하여 Labels, PR, Reviewers, Repository, Milestone등 새로운 칼럼도 넣을 수 있다

  • 그룹으로 나눠서 볼 수도 있다
    - 그룹 아이콘을 클릭한다
    - Assignees, Status, Milestone, Repository 등으로 나눌 수 있다
  • Board를 선택하면 칸반보드로 볼 수 있다

 

'Git' 카테고리의 다른 글

GitHub - Git branch  (0) 2022.08.22
Git - 명령어 / HELP  (0) 2022.08.01
Git(global information tracker)  (0) 2022.07.10

ItsWard/GitHub-getting-started: 📝GitHub를 시작해보자

 

GitHub - ItsWard/GitHub-getting-started: 📝GitHub를 시작해보자

📝GitHub를 시작해보자. Contribute to ItsWard/GitHub-getting-started development by creating an account on GitHub.

github.com

1. Git(global information tracker)

  • 파일의 버젼관리를 용이하게 할 수 있는 프로그램이다
  • 개발자 혹은 동료들 간의 협업 시 파일의 수정, 보완이 용이한 프로그램이다
  • git download : Git - Downloading Package (git-scm.com)

 1) Git 장점

  • 분산형 버전 관리 시스템으로 소스코드를 효과적으로 관리하기 위해 개발되었다
  • 소스 코드가 변경된 이력을 쉽게 확인할 수 있다
  • 현재 소스 코드와 원하는 시점에 저장된 버전의 소스 코드를 비교하기가 용이하다
  • 특정 시점에 저장된 소스 코드로 되돌아갈 수도 있다
  • 협업자와 소스 코드 파일이  충돌할 경우에 경고 메시지를 출력한다
  •  백업용 복사본 파일을 생성할 필요가 없다

 

2. Git repository(저장소)

 1) 특성

  • Git repository는 파일이나 폴더를 저장하는 공간이다
  • 비슷한 파일의  내용이 일부라도 다르면 각각의 파일로 인식하고 저장한다
  • 파일의 변경 이력을 구분하여 저장한다
  • 일반적인 폴더를 Git에서는 작업트리(Work Tree)라고 한다

 2) 저장소 종류

  • 원격 저장소(Remote Repository)
    - 파일을 원격 저장소 전용 서버에서 관리한다
    - 여러 명이 협업을 하는 경우 파일을 공유하기에 적합하다
  • 로컬 저장소(Local Repository)
    - 내 PC에 파일을 저장하는 공간이다
  • 내 PC에서 작업한 파일을 로컬 저장소에 1차로 저장한 후 공개 시점에서 원격 저장소로 파일을 업로드한다
  • 협업자는 원격 저장소에 있는 파일을 본인의 로컬 저장소로 다운로드 할 수 있다

 

 3) 저장소 생성 방법

  • 원격 저장소를 새로 생성할 수 있다
  • 원격 저장소를 로컬 저장소로 복사할 수 있다

 

3. 커밋(Commit)

  • 파일이나 폴더의 추가 또는 변경 사항을 작업트리에서 원격저장소로 저장하기 위한 기능이다
  • 커밋을 할 경우 이전에 커밋한 상태부터 현재 상태까지의 변경 이력이 생성된다
  • 커밋은 최근 기록부터 순차적으로 저장되며, 저장된 기록을 시간까지 확인할 수 있다
  • 커밋된 파일에는 영문과 숫자로 이루어진 고유의 이름이 생성된다(40자)
  • 커밋을 할 경우에는 필히 나중에 확인할 수 있는 메시지를 입력해야 한다
    - ex) 'No : 변경 사항' 형식으로 작성하는 것이 좋다
  • 커밋은 작업트리 -> 인덱스 -> 원격 저장소 의 단계로 이루어 진다
  • 인덱스는 가상의 저장 공간을 의미한다

  • Git은 내부적으로 3가지 종류의 작업 영역으로 동작한다
     1) working directory
       - 작업을 하는 프로젝트 디렉토리를 의미한다
     2) staging area
       - git add를 한 파일들이 존재하는 영역이다
       - commit 을 하면 staging area에 있는 파일들만 commit 에 반영되고 대기한다
     3) repository
       - working directory의 변경 이력들이 저장되어 있는 영역이다
       - commit 된 파일들이 저장되는 영역이다

4. Git 설치

 1) 아래 사이트에서 Window용 Git을 다운로드 한다

 

Git for Windows

Git for Windows focuses on offering a lightweight, native set of tools that bring the full feature set of the Git SCM to Windows while providing appropriate user interfaces for experienced Git users and novices alike. Git BASH Git for Windows provides a BA

gitforwindows.org

  • 다운받은 파일을 실행하고 순차적으로 설치한다

 2) Git 설치 확인

  • git 설치 후 Git BASH를 실행하여 간단히 확인해 본다
  • 탐색기에서 파일명을 클릭한 후 마우스 우측버튼을 눌러 나오는 gitbash here를 실행하면 해당 파일 위치에서 작업을 시작할 수 있다

  • got --version 으로 git 설치 버젼을 확인해 본다

  • gitbash > 우클릭 > 메뉴 > option > Text 에서 설정을 Local변경하면 한글로 패치할 수 있다

 

 3) 최초 설정

  • Git 계정과는 별개로 Git 프로젝트에서 사용할 사용자 이름과 이메일 주소를 설정한다
  • commit 을 하기 전에 작성자의 이름과 email을 필히 설정해 주어야 한다
  • Git에 commit을 실행한 작성자를 기록하기 위한 설정이다
  • 설정을 통해 협업 시 누가 commit 한 파일인지 확인할 수 있다
  • 이름과 이메일은 각각의 프로젝트를 시작할 때 변경하여 적용할 수 있다

  • 설정이 되었는지 확인해 본다

  • 기본 브랜치를 main으로 변경하여 준다

  • 아래는 config 관련 명령어이다...참조

config 관련 명령어

 

4. Git 프로젝트 생성

 1) 로컬 저장소 생성

  • 생성하고져 하는 위치에 폴더를 만든다
  • 탐색기에서 우클릭하여 연관 프로그램으로 이동한다
     - GitBash / IntelliJ / VSCode 등등 

  • 해당 폴더 위치에서 시작하게 된다

 2) Git 관리하기

  • Git이 관리하도록 git init 명령을 입력하면 .git 이라는 폴더가 새로 생성되면서 관리가 시작된다
  • .git 폴더는 탐색기에서도 볼 수 있는데 혹시 안보이면 탐색기 옵션에서 숨긴폴더를 해제하면 볼 수 있다
  • .git 폴더에는 Git에서 관리한 내역이 저장된다
  • .git 폴더를 삭제하면 이전에 관리된 내역이 모두 삭제되고 현재 파일만 남게 된다

 

 3) 파일 테스트

아무 파일이나 2개 정도 만들어서 저장해 본다

git status 명령으로 저장된 내용을 확인하면 Git에서 관리되고 있는 파일의 목록이 나타난다

 

 

5. 특정파일/폴더 배제

  • Git 관리 목록에 포함할 필요가 없는 경우나 포함하지 말아야 할 경우에 사용한다
     - 자동 생성되는 파일
     - 보안에 민감한 파일
  • 폴더 안에 .gitignore 파일을 생성한다

  • .gitignore 파일에 숨기고져 하는 파일을 작성한다
    - .gitignore 파일에 작성된 파일은 Git의 관리 목록에서 제외된다 
    - '*' 전체, '이름/'이름 폴더 전체 숨김 표시가 가능하다 
숨기기 전 목록 secrets.yaml 파일 숨김
  • 일반 코드 프로그램에서는 파일 생성 시 .gitignore 파일을 자동으로 생성하고 제외 항목들을 포함하고 있다

 

6. Git 파일 관리

 1) git add

  • 업로드 할 파일을 지정한다
    - git add Test1.java

  • Test1.java 파일이 Changes to be committed 대기 중으로 변경된다
  • git add . 으로 전체를 지정할 수 있다

 

 2) git commit

  • git commit 를 입력 후 실행한다
  • VSCode 에디터가 열리면서 아래와 같은 화면이 출력된다
    - 1번 줄에 저장하고 싶은 메시지를 작성 후 저장하고 파일을 빠져 나온다

  • 위와 같은 에디터 표시를 없애고 빠르게 진행하기 위해서는 git add -m "메시지" 로 실행한다
  • 작성한 메시지가 표시되고 3개의 파일이 change 되었다고 표시된다

  • git.status를 입력해도 commit 대상이 없다고 확인된다

  • git.log 명령을 실행하면 메시지, commit 실행한 시간, commit 고유번호를 확인할 수 있다

 

 

※ 에디터가 지정되어 있지 않으면 아래와 같이 출력된다
- i 를 입력하면 맨 위 상단에 커서가 이동하면서 code 작성이 가능해 진다
- 저장할 메시지를 작성 후 ESC를 누른다
- :q(저장하지 않고 종료) , :q!(저장하지 않고 강제 종료) 를 하면 둘 다 저장하지 않고 나오게 된다
- 저장을 해야 commit가 진행되므로 :wq 를 작성 후 Enter 한다

 

 3) 파일 변경 후 commit

  • Test2 파일을 삭제하고 Test3 파일을 추가, Test1 파일은 내용 변경을 한 후 git.status로 확인해 본다

  • git diff 명령으로 변경 내역을 더 자세히 알아볼 수 있다
    - Test3은 신규 생성 파일이라서 변경 내역에는 나타나지 않는다

  • 변경 사항을 git add . 으로 업로드 할 파일을 지정한다

  • git commit -m "second file" 로 업로드를 준비한다

  • git log 로 확인해 보면 first, second 모두의 commit 정보를 확인할 수 있다

 

 4) 버젼 관리

  • 파일을 2개 더 추가한 후 commit까지 진행한다

과거의 시점으로 돌아가는 방법은 2가지가 있다
- 과거 시점으로 돌아간 후 이후에 실행되었던 파일들을 모두 삭제하는 경우에는 git reset --hard commit고유번호 를 사용한다
- 과거 시점으로 돌아가지만 이후에 행적은 그대로 두고 추가로 진행되는 경우에는 git revert commit고유번호 를 사용한다

협업 시에는 revert를 사용하는 것이 용이하다

 

 

7. 파일 푸쉬(push)

  • 로컬 저장소에 git 폴더를 만들고 파일을 commit하여 스테이징까지 진행하였다
  • 스테이징 한 파일을 원격 저장소로 업로드 하는 것을 푸쉬(push)라고 한다
  • 푸쉬를 하면 스테이징된 파일이 원격 저장소로 업로드 된다

 

8. 원격 저장소 복제

  • 원격 저장소의 파일을 복제하는 것을 클론(clone)이라고 한다
  • 복제를 하면 원격 저장소에 있는 파일 내용 전체를 다운로드 한다
  • 변경 이력도 함께 복제된다

 

9. 로컬 저장소 업데이트

  • 공유 작업자들이 push로 원격 저장소에 업로드 한 파일을 로컬 저장소로 업데이트 하는 것을 풀(pull)이라고 한다
  • 풀을 하면 변경된 파일 이력을 다운로드 한다

 

 

 

 

10. 레포지토리 만들기

 1) 컴퓨터에 프로젝트 디렉토리 생성하기

  • gitbash에서 'mkdir 디렉토리명'을 사용하여 프로젝트를 저장할 디렉토리를 생성한다
  • 디렉토리는 자신이 작업하고자 하는 드라이브의 위치로 경로 이동 후 생성한다
  • 'cd 디렉토리 경로' 를 사용하여 해당 디렉토리로 진입한다

 

 2) 프로젝트 디렉토리를 관리하기 위한 레포지토리 설정하기

  • 디렉토리의 버젼관리를 위한 설정을 git init 을 사용하여 실행 한다
    - 비어있는 .git 레포지토리를 설정할 수 있다
user@DESKTOP-MJ9EVF2 MINGW64 /d/Spring/be-homework-exception-main (main)
$ git init
Reinitialized existing Git repository in D:/Spring/be-homework-exception-main/.git/
  • ls -al 로 레포지토리 내용을 살펴 본다
    - drwxr-xr-x 1 user 197609     0 Jul  1 14:58 .git/ 이라는 레포지토리가 생성된 것을 볼 수 있다
user@DESKTOP-MJ9EVF2 MINGW64 /d/Spring/be-homework-exception-main (main)
$ ls -al

total 28
drwxr-xr-x 1 user 197609     0 Jun 30 21:48 ./
drwxr-xr-x 1 user 197609     0 Jun 29 15:06 ../
-rw-r--r-- 1 user 197609 12288 Jun 30 21:50 .CONTRIBUTING.md.swp
drwxr-xr-x 1 user 197609     0 Jul  1 14:58 .git/
  • cd .git 으로 경로 이동하여 레포지토리 내부의 디렉토리 내용을 살펴 본다
user@DESKTOP-MJ9EVF2 MINGW64 /d/Spring/be-homework-exception-main (main)
$ cd .git

user@DESKTOP-MJ9EVF2 MINGW64 /d/Spring/be-homework-exception-main/.git (GIT_DIR!)
$ ls -al
total 17
drwxr-xr-x 1 user 197609   0 Jul  1 14:58 ./
drwxr-xr-x 1 user 197609   0 Jun 30 21:48 ../
-rw-r--r-- 1 user 197609  19 Jun 30 22:35 COMMIT_EDITMSG
-rw-r--r-- 1 user 197609   0 Jun 30 19:30 FETCH_HEAD
-rw-r--r-- 1 user 197609  21 Jun 30 19:22 HEAD
-rw-r--r-- 1 user 197609 130 Jul  1 14:58 config              //프로젝트별 구성 옵션이 포함
-rw-r--r-- 1 user 197609  73 Jun 30 19:22 description
drwxr-xr-x 1 user 197609   0 Jun 30 19:22 hooks/
-rw-r--r-- 1 user 197609 249 Jun 30 22:35 index
drwxr-xr-x 1 user 197609   0 Jun 30 19:22 info/               //Git이 저장하는 위치
drwxr-xr-x 1 user 197609   0 Jun 30 19:58 logs/
drwxr-xr-x 1 user 197609   0 Jun 30 22:35 objects/            //데이터베이스의 모든 내용을 저장
drwxr-xr-x 1 user 197609   0 Jun 30 19:22 refs/ 
                  //refs : 해당 데이터(브랜치, 태그, 원격지 등)의 커밋 객체에 대한 포인터를 저장
  • 저장소를 백업하거나 복제하려는 경우 레포지토리를 다른 곳에 복사하면 필요한 거의 모든 것을 얻을 수 있다

 

11. 기존 파일 버전 제어

  • 기존 파일의 버전 제어(빈 디렉토리와 반대)를 시작하려면 해당 파일을 추적하고 초기 커밋을 수행해야 한다
$ git add *.c
$ git add LICENSE
$ git commit -m 'Initial project version'

12. 기존 리포지토리 복제

  • 기존 Git 리포지토리(예: 기여하려는 프로젝트)의 복사본을 얻으려는 경우 필요한 명령이다
  • libgit2 리포지토리의 모든 데이터를 풀다운하고 복사한다
  • 새로 생성된  libgit2 디렉터리로 이동하면 작업하거나 사용할 준비가 된 프로젝트 파일이 표시된다
//git clone <url>
//예를 들어 libgit2가능 라이브러리를 복제하려면 다음과 같이 하면 됩니다.
git clone https://github.com/libgit2/libgit2
  • 저장소를 다른 이름의 디렉토리에 복제하려면 libgit2새 디렉토리 이름을 추가 인수로 지정한다
//git clone <url> 디렉토리명
git clone https://github.com/libgit2/libgit2 mylibgit

 

13. 파일상태 확인

  • 어떤 파일이 어떤 상태에 있는지 확인하는 데 사용하는 기본 도구는 git status명령이다
  • 클론 직후에 이 명령을 실행하면 다음과 같이 표시된다
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working tree clean
  • 깨끗한 작업 디렉토리가 있음을 의미한다
  • 현재 있는 지점을 알려준다
  • 현재 지점은 항상 master가 기본값이다

 

14. 파일 커밋(commit)

  • commit 하기 전에 파일을 반영하는 git add 를 먼저 실행한다
    - 스테이징되지 않은 모든 파일, 즉 생성하거나 수정한 파일 중 편집한 이후에 git add를 실행하지 않은 파일은 이 커밋에 포함되지 않고 디스크에 수정된 파일로 남아 있게 된다
    - git add를 하지 않고 commit을 실행하면 'nothing added to comit but ubtrack files present'라는 문구가 나오면서 추적할 파일이 없음을 표시한다
git add 파일명.확장자

 

  • git commit 를 실행하면 편집기가 실행된다
  • 편집기는 보통 vim 또는 emacs에 의해 설정 되지만 git config --global core.editor 를 사용하여 EDITOR를 원하는 대로 구성할 수 있다
  • 편집기가 시작되면 다음과 같은 기본 문구가 표시된다
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# Your branch is up-to-date with 'origin/master'.
#
# Changes to be committed:
#	new file:   README
#	modified:   CONTRIBUTING.md
#
~
~
~
".git/COMMIT_EDITMSG" 9L, 283C
  • 기본 커밋 메시지에는 주석 처리된 명령의 출력과 맨 위에 빈 줄 하나가 포함되어 있다
  • 주석을 제거하고 커밋 메시지를 입력하여 커밋 내용을 기억하는 데 도움이 되도록 남겨둘 수 있다
  • 편집기를 종료하면 Git은 해당 커밋 메시지로 커밋을 생성한다
  • commit 뒤에 -m 을 사용하여 커밋 메시지를 입력할 수 있다
//git commit -m "메시지"
$ git commit -m "Story 182: fix benchmarks for speed"
[master 463dc4f] Story 182: fix benchmarks for speed
 2 files changed, 2 insertions(+)         //2개 파일, 2줄의 내용이 추가
 create mode 100644 README

 

15. branch 생성

  • branch는 프로젝트 수행 중에 추가적인 작업을 별개로 진행하고 싶을 때 생성하여 저장할 수 있는 별도의 저장 공간이다
  • git branch 브랜치명 으로 생성할 수 있다
  • git branch 로 브랜치 목록을 확인하면 main이 있고 브랜치 add-another가 있는 것을 확인할 수 있다

  • 브랜치로 위치를 이동할 경우에는 git switch 브랜치명 으로 이동한다
    - 오른쪽 끝에 위치가 main에서 브랜치명으로 변경되는 것을 확인할 수 있다

  • 브랜치를 생성과 동시에 위치도 이동할 경우에는 git switch -c 브랜치명 을 사용한다

  • commit 기록을 확인하면 각각의 브랜치 내역만 확인이 가능한다
  • 전체 commit 기록을 확인하기 위해서는 git log --all --decorate --oneline --grahp 명령어를 사용한다
  • 브랜치를 삭제할 경우에는 'git branch -d 브랜치명' 으로 삭제한다
  • 브랜치 이름을 변경할 경우에는 'git branch -m 브랜치명 변경브랜치명' 으로 변경한다

16. branch 병합

  • 브랜치를 유지하면서 개발 기록을 main에 병합할 경우에는 merge 를 사용한다
    - git branch main 으로 이동한다
    - git merge 병합브랜치명 으로 병합한다
    - merge도 하나의 커밋이기 때문에 reset을 사용하여 merge 하기 전 해당 브랜치의 마지막 시점으로 되돌리기가 가능하다
    - 병합 중에 충돌이 발생하면 Git에서 경고를 출력한다
    - 충돌 부분을 상황에 맞게 해결할 수 있다
    - 브랜치 병합을 중단하고져 할 경우에는 git merge --abort 를 사용한다
  • 브랜치를 삭제하면서 개발 기록을 main에 병합할 경우에는 rebase 를 사용한다 
    - git branch 병합브랜치명 으로 이동한다
    - git rebase main 으로 병합한다
    - 병합 전 시점의 main 뒤에 병합브랜치에 있던 커밋들이 이동하게 된다
    - 병합 후에도 main의 시점은 머물러 있기 때문에 git merge 병합브랜치명 으로 시점 이동을 시켜 준다
    - 병합 중에 충돌이 발생하면 Git에서 경고를 출력한다
    - 충돌 부분을 상황에 맞게 해결할 수 있지만 merge와 다르게 각 커밋한 부분마다 해결해 주어야 한다
    - 브랜치 병합을 중단하고져 할 경우에는 git rebase --abort 를 사용한다
    - 완료가 되면 git add . -> git rebase --continue 로 커밋을 진행한다

 

 

'Git' 카테고리의 다른 글

GitHub - Git branch  (0) 2022.08.22
Git - 명령어 / HELP  (0) 2022.08.01
GitHub  (0) 2022.07.10

1. DDD(Domain Driven Design)

  • 도메인 위주의 설계 기법을 의미한다

 1) 도메인(Domain)

  • 애플리케이션 개발에서 흔하게 사용하는 도메인이란 용어는 주로 비즈니스적인 어떤 업무 영역과 관련이 있다 
  • 애플리케이션 개발에서 필요한 업무 로직에 대한 지식을 도메인 지식(Domain Knowledge)이라고 한다
  • 도메인 지식이 많을수록 서비스 계층에서 비즈니스 로직으로 구현해야 하는 것들을 퀄리티가 높게 표현할 수 있다

 2) 애그리거트(Aggregate)

  • 비슷한 업무 도메인들의 묶음이다
  • 비슷한 범주의 연관된 업무들을 하나로 묶어 그룹화한 것이다

 3) 애그리거트 루트(Aggregate Root)

  • 하나의 애그리거트를 대표하는 도메인을 말한다
  • 애그리거트 루트(Aggregate Root)의 기본키 정보를 다른 도메인들이 외래키 형태로 가지고 있다

 4) 애그리거트 간의 관계

  • 하나의 애그리거트 루트는 N개의 애거리거트 루트와 관계를 가질 수 있다
  • N개의 도메인은 하나의 애거리거트 루트와 관계를 가질 수 있다
  • 애거리거트 간의 관계를 1:N , N:1 , 1:1로 구분할 수 있다

※ 데이터베이스 테이블 간의 관계는 외래키를 통해 맺어지지만

    클래스끼리 관계는 객체의 참조를 통해 맺어진다

 

※ 참조 링크

 https://martinfowler.com/bliki/DDD_Aggregate.html

 

bliki: DDD_Aggregate

A pattern from Domain-Driven Design describing a cluster of domain objects that can be treated as a single unit for persistant storage and transactions.

martinfowler.com

https://www.alibabacloud.com/blog/an-in-depth-understanding-of-aggregation-in-domain-driven-design_598034

 

An In-Depth Understanding of Aggregation in Domain-Driven Design

This article discusses the definition, value, and practices of aggregation in domain-driven design (DDD)

www.alibabacloud.com

 

1. Hello World 샘플 코드 구현

  • 클라이언트 쪽에서 “Hello, World” 문자열 데이터를 Request Body로 전송한다
  • Spring Data JDBC를 이용해서 전송받은  “Hello, World” 문자열을 H2 데이터베이스에 저장한다

 1) Package 생성

  • 기존 프로젝트 파일의 java > com.codestates > hello_world 패키지를 만든다
  • 아래의 클래스 또는 인터페이스를 생성한다

- MessageDto(DTO 클래스) - PostDto / ResponseDto

package com.codestates.hello_world;

import lombok.Getter;

import javax.validation.constraints.NotBlank;

//클라이언트가 Request Body로 전달하는 “Hello, World” 문자열을 바인딩하는 DTO 클래스
@Getter
public class MessagePostDto {
    @NotBlank
    private String message;
}
package com.codestates.hello_world;

import lombok.Getter;
import lombok.Setter;

//Response에 사용할 Dto
@Getter
@Setter
public class MessageResponseDto {
    private long messageId;
    private String message;
}

 

- MessageController

package com.codestates.hello_world.messageController;

import com.codestates.hello_world.messageMapper.MessageMapper;
import com.codestates.hello_world.messageService.MessageService;
import com.codestates.hello_world.message.Message;
import com.codestates.hello_world.messageDto.MessagePostDto;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;

//문자열을 전달받는 Controller
@RequestMapping("/v1/message")
@RestController
public class MessageController {
    private final MessageService messageService;
    private final MessageMapper mapper;

    public MessageController(MessageService messageService,
                             MessageMapper mapper){
        this.messageService = messageService;
        this.mapper = mapper;
    }

    @PostMapping
    public ResponseEntity postMessage(
            @Valid @RequestBody MessagePostDto messagePostDto){
        Message message =
                messageService.createMessage(mapper.messageDtoToMessage(messagePostDto));
        return ResponseEntity.ok(mapper.messageToMessageResponseDto(message));
        }
}

 

- MessageMapper

package com.codestates.hello_world.messageMapper;

import com.codestates.hello_world.message.Message;
import com.codestates.hello_world.messageDto.MessagePostDto;
import com.codestates.hello_world.messageDto.MessageResponseDto;
import org.mapstruct.Mapper;

//DTO 클래스와 엔티티(Entity) 클래스를 매핑해주는 Mapper 인터페이스
@Mapper(componentModel = "spring")
public interface MessageMapper {

    Message messageDtoToMessage(MessagePostDto messagePostDto);
    MessageResponseDto messageToMessageResponseDto(Message message);

}

 

- MessageService

package com.codestates.hello_world.messageService;

import com.codestates.hello_world.message.Message;
import com.codestates.hello_world.messageRepository.MessageRepository;
import org.springframework.stereotype.Service;

//MessageRepository 인터페이스를 DI를 통해 주입받는다
//데이터베이스에 데이터를 저장하고 데이터베이스에 저장된 데이터를 다시 리턴
@Service
public class MessageService {
    private MessageRepository messageRepositoty;
    public MessageService(MessageRepository messageRepositoty){
        this.messageRepositoty = messageRepositoty;
    }
    public Message createMessage(Message message){
        return messageRepositoty.save(message);
    }
}

  → MessageRepository가 상속받은 CrudRepository에 save() 메서드가 정의되어 있다

  → 개발자가 데이터의 생성, 조회, 수정, 삭제 작업을 위한 별도의 코드를 구현하지 않아도 CrudRepository가 작업을 대신해주는 역할을 한다


- Message(엔티티 클래스)

package com.codestates.hello_world.message;

import lombok.Getter;
import lombok.Setter;
import org.springframework.data.annotation.Id;

//Message 클래스명은 데이터베이스의 테이블명에 해당한다
//@Id 애너테이션을 추가한 멤버 변수는 해당 엔티티의 고유 식별자 역할을 한다
//식별자는 데이터베이스의 Primary key로 지정한 컬럼에 해당한다
@Getter
@Setter
public class Message {
    @Id
    private long messageId;
    private String message;
}


- MessageRepository

package com.codestates.hello_world;

import org.apache.logging.log4j.message.Message;
import org.springframework.data.repository.CrudRepository;

//데이터베이스와의 연동을 담당하는 Repository
public interface MessageRepository extends CrudRepository<Message, Long>{

}

  →  CrudRepository라는 인터페이스를 상속하고 있고, CrudRepository의 제너릭 타입이 <Message, Long>으로 선언되어 있다   

  → CrudRepository 는 데이터베이스에 CRUD(데이터 생성, 조회, 수정, 삭제) 작업을 진행하기 위해 Spring에서 지원해주는 인터페이스이다

  → CrudRepository<Message, Long> 와 같이 제너릭 타입을 지정해줌으로써 Message 엔티티 클래스 객체에 담긴 데이터를 데이터베이스 테이블에 생성 또는 수정하거나 데이터베이스에서 조회한 데이터를 Message 엔티티 클래스로 변환할 수 있다

  → <Message, Long>에서 LongMessage 엔티티 클래스의 멤버 변수 중에 식별자를 의미하는 @Id 라는 애너테이션이 붙어있는 멤버 변수의 데이터 타입이다

  ※ 짧은 문장이고 MessageRepository 인터페이스 내부에 아무런 코드도 없으나, MessageRepository 인터페이스를 서비스 계층에서 DI를 통해 주입받은 후 데이터베이스 작업을 위해 사용하게 된다

 

프로젝트를 실행시키고 error 발생 시 변수들의 경로에 유의하여 수정하도록 한다!!!

 

2) 프로젝트 실행

  • 실행 전에 property 설정을 추가한다
spring:
  h2:
    console:
      enabled: true
      path: /h2     # (1) Context path
  datasource:
    url: jdbc:h2:mem:test     # (2) JDBC URL
  sql:
    init:
      schema-locations: classpath*:db/h2/schema.sql      # 추가할 부분
      # 테이블 생성을 위한 SQL 문이 추가된 ‘schema’라는 파일명으로 .sql 파일의 경로를 지정
  • 추가 후 resource > db.h2 > schema.sql 파일을 보면 아래와 같이 테이블이 추가되어 있다
CREATE TABLE IF NOT EXISTS MESSAGE (
    MESSAGE_ID bigint NOT NULL AUTO_INCREMENT,
    MESSAGE varchar(100) NOT NULL,
    PRIMARY KEY (MESSAGE_ID)
);
  • postman에서 post : http://localhost:8080/v1/message 입력 후 전송하면 아래와 같이 응답한다

  • 요청 전송 시 Request Body에 messageId 값은 포함하지 않았지만 Response Body에는 messageId가 포함되어 출력된다
  • MESSAGE 테이블의 식별자(Primary key)인 ‘message_id’ 컬럼에 AUTO_INCREMENT 설정이 되어 있으므로 ‘message_id’ 컬럼에 값을 입력하지 않더라도 데이터가 저장이 될 때 마다 자동으로 포함이 된다
  • chrome 화면으로 가서 다시 출력한 후 'SELECT *FROM MESSAGE'를 입력하고 RUN SELECT를 실행한다
    - 1개의 데이터 (ID:1 , MESSAGE:Hello World)가 입력되어 있음을 확인할 수 있다

 

2. JDBC DATA 구현 순서

 

1. SQL 중심 기술

  • 애플리케이션에서 데이터베이스에 접근하기 위해 SQL 쿼리문을 애플리케이션 내부에 직접적으로 작성하는 것이 중심이 되는 기술이다
<select id="findMember" resultType="Member">
  SELECT * FROM MEMBER WHERE member_id = #{memberId}
</select>
  • mybatisSpring JDBC는 대표적인 SQL 중심 기술이다
  • mybatis은 SQL Mapper라는 설정 파일이 있고 SQL Mapper에서 SQL 쿼리문을 직접적으로 작성한다
    -
    작성된 SQL 쿼리문을 기반으로 데이터베이스의 특정 테이블에서 데이터를 조회하여 Java 객체로 변환해 준다
  • Spring JDBC의 경우에도 Java 코드에 SQL 쿼리문이 직접적으로 포함이 되어 있다
Member member = this.jdbcTemplate.queryForObject(
				"select * from member where member_id=?", 1, Member.class);

 

2. Object 중심 기술

  • 데이터를 SQL 쿼리문 중심으로 보는 것이 아니라 모든 데이터를 객체(Object) 관점으로 바라보는 기술이다
  • 애플리케이션 내부에서 Java 객체(Object)를 SQL 쿼리문으로 자동 변환 후에 데이터베이스의 테이블에 접근한다
  • 객체(Object) 중심의 데이터 액세스 기술을 ORM(Object-Relational Mapping)이라고 한다
  • Java에는 대표적인 ORM 기술로 JPA(Java Persistence API)가 있다

 

3. Spring Data JDBC

  • Spring Data JDBC를 사용하기 위하여 Spring Boot Starter를 추가한다
dependencies {
	...
	...
	implementation 'org.springframework.boot:spring-boot-starter-data-jdbc'
	runtimeOnly 'com.h2database:h2'
}
  • 데이터베이스에서 데이터를 관리할 것이므로 개발 환경에서 손쉽게 사용할 수 있는 인메모리(In-memory) DBH2를 의존 라이브러리 설정에 추가한다

※ In-memory DB

  • 메모리 안에 데이터를 저장하는 데이터베이스이다
  • 애플리케이션이 실행되는 동안에만 데이터를 저장하고 있다
  • 애플리케이션 실행을 중지했다가 다시 실행시키면 인메모리(In-memory) DB에 있던 데이터는 삭제된다
  • 로컬 개발 환경에서는 테스트를 진행하기 위하여 인메모리(In-memory) DB를 주로 사용한다

※ H2 활성화 설정

  • Spring Boot Initializr를 통해 샘플 프로젝트를 생성하면 기본적으로 ‘src/main/resources’ 디렉토리 하단에 application.properties 라는 비어 있는 파일이 있다
  • application.properties 또는 application.yml 파일을 통해 Spring에서 사용하는 다양한 설정 정보들을 입력할 수 있다
  • 웹 브라우저 H2 콘솔에서 H2 DB에 접속한 후, 데이터베이스를 관리할 수 있도록 설정한다
spring:
  h2:
    console:
      enabled: true
  • 프로젝트 실행 시 H2 console available at '/h2'. Database available at 'jdbc:h2:mem:test'와 같은 문구가 출력되면 정상적으로 연동되었음을 의미한다
  • 애플리케이션 연결
    - https://github.com/codestates-seb/be-reference-spring-data-jdbc 연결하여 fork 한 후 실행한다
    - chrome 브라우져에 http://local8080/h2 입력 후 출력한다
    - 원래는  http://local8080/h2-console 입력해야 하지만, 미리 URL을 추가 설정했으므로 h2까지만 입력한다

     - 프로젝트 실행에서 출력된 로그에서 주소를 확인한 후 'jdbc:h2:mem:test'을 JDBC URL에 입력한다

     - 정상적으로 H2 브라우저에 연결되면 아래와 같이 출력된다

  • H2 DB는 애플리케이션을 재시작 할때 마다 애플리케이션 로그에 출력되는 JDBC URL이 매번 랜덤하게 변경된다
  • application.yml 파일에 H2에 대한 추가 설정을 통해 JDBC URL을 다시 입력하는 불편을 해소한다
    - 예제 Git 파일은 사전에 입력되어 있으므로 추가 변경이 필요하지 않다
spring:
  h2:
    console:
      enabled: true
      path: /h2    
  datasource:
    url: jdbc:h2:mem:test
  • Spring Boot에서는 appliation.properties 또는 application.yml 파일을 통해 설정 정보를 추가할 수 있다

※ 참조 링크

▶ 인메모리(In-memory) DB

 : https://www.h2database.com/html/main.html

 

H2 Database Engine

H2 Database Engine Welcome to H2, the Java SQL database. The main features of H2 are: Very fast, open source, JDBC API Embedded and server modes; in-memory databases Browser based Console application Small footprint: around 2.5 MB jar file size     Supp

www.h2database.com

 : https://ko.wikipedia.org/wiki/%EC%9D%B8%EB%A9%94%EB%AA%A8%EB%A6%AC_%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4

 

인메모리 데이터베이스 - 위키백과, 우리 모두의 백과사전

 

ko.wikipedia.org

 

H2 Console : http://www.h2database.com/html/quickstart.html

 

Quickstart

Quickstart Embedding H2 in an Application The H2 Console Application Embedding H2 in an Application This database can be used in embedded mode, or in server mode. To use it in embedded mode, you need to: Add the h2*.jar to the classpath (H2 does not have a

www.h2database.com

 

Property 설정 : https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html

 

Common Application Properties

 

docs.spring.io

 

1. JDBC(Java Database Connectivity)

  • Java 기반 애플리케이션의 코드 레벨에서 사용하는 데이터를 데이터베이스에 저장 및 업데이트 하거나 반대로 데이터베이스에 저장된 데이터를 Java 코드 레벨에서 사용할 수 있도록 해주는 Java에서 제공하는 표준 API이다
  • Java 초창기(JDK 1.1) 버전부터 제공되는 데이터베이스 액세스 기능을 위한 API이다
  • JDBC API를 사용해서 Oracle, MS SQL, MySQL 등의 데이터베이스와 연동할 수 있다

Java Application → JDBC API → JDBC Driver → Database

  • JDBC Driver
    - 데이터베이스와의 통신을 담당하는 인터페이스이다
    - Oracle이나 MS SQL, MySQL 같은 다양한 벤더에서는 해당 벤더에 맞는 JDBC 드라이버를 구현해서 제공을 한다
    - JDBC 드라이버의 구현체를 이용해서 특정 벤더의 데이터베이스에 액세스 할 수 있다

2. Connection Pool

  • 데이터베이스 Connection을 보관하고 애플리케이션이 필요할 때 Connection을 제공해주는 Connection 관리자이다
  • 애플리케이션 로딩 시점에 Connection 객체를 미리 생성한다
  • 생성한 Connection 객체를 Connection Pool에 저장한다
  • 애플리케이션이 데이터베이스에 연결이 필요한 경우 미리 생성 보관 중인 Connection 객체를 사용한다
  • Spring Boot 2.0 이전 버전에는 Apache 재단의 오픈 소스인 Apache Commons DBCP(Database Connection Pool, DBCP)를 주로 사용했다
  • Spring Boot 2.0 부터는 HikariCP기본 DBCP로 채택하고 있다

 

※ 참조 링크

▶ JDBC : https://docs.oracle.com/javase/8/docs/technotes/guides/jdbc/

 

Java JDBC API

Java JDBC API The Java Database Connectivity (JDBC) API provides universal data access from the Java programming language. Using the JDBC API, you can access virtually any data source, from relational databases to spreadsheets and flat files. JDBC technolo

docs.oracle.com

https://docs.oracle.com/javase/tutorial/jdbc/basics/index.html

 

Lesson: JDBC Basics (The Java™ Tutorials > JDBC Database Access)

The Java Tutorials have been written for JDK 8. Examples and practices described in this page don't take advantage of improvements introduced in later releases and might use technology no longer available. See Java Language Changes for a summary of updated

docs.oracle.com

https://ko.wikipedia.org/wiki/JDBC

 

JDBC - 위키백과, 우리 모두의 백과사전

 

ko.wikipedia.org

https://techxyte.com/tutorials/hibernate/pros-and-cons-of-jdbc.php

 

Premium Bootstrap 5 HTML, Angular 11, VueJS, React & Laravel Admin Dashboard Themes

Metronic - #1 Selling Premium Bootstrap Admin Theme of All Time. Built with Twitter Bootstrap 5 HTML, Angular 11, VueJS, React and Laravel. Trusted By Tens of Thousands Users.

keenthemes.com

HikariCP : https://github.com/brettwooldridge/HikariCP

 

GitHub - brettwooldridge/HikariCP: 光 HikariCP・A solid, high-performance, JDBC connection pool at last.

光 HikariCP・A solid, high-performance, JDBC connection pool at last. - GitHub - brettwooldridge/HikariCP: 光 HikariCP・A solid, high-performance, JDBC connection pool at last.

github.com

 

1. @ExceptionHandler를 이용한 예외 처리

  • 위와 같이 postman의 GET에서 요청을 보냈을 경우 데이터를 찾지 못하여 에러가 발생하는 경우가 있다
  • 클라이언트가 전달 받는 Response Body는 애플리케이션에서 예외(Exception)가 발생했을 때, 내부적으로 Spring에서 전송해주는 에러 응답 메시지 중의 하나이다 (위에서는 '404 Not Found' 메시지를 전송하고 있다)

 1) Spring에서의 예외 처리

  • 애플리케이션의 문제가 발생하였을 경우 알려주어 처리를 유도한다
  • 유효성 검증에 실패하였을 경우 예외로 간주하고 처리를 유도한다
  • MemberController(v6)에 @ExceptionHandler 애너테이션을 이용해서 예외를 처리하도록 handleException() 메서드를 추가한다
  • handleException() 메서드에서 유효성 검사 실패에 대한 에러 메시지를 구체적으로 전송해 주는 역활을 한다
package com.codestates.member.controller;

import com.codestates.member.dto.MemberPatchDto;
import com.codestates.member.dto.MemberPostDto;
import com.codestates.member.dto.MemberResponseDto;
import com.codestates.member.entity.Member;
import com.codestates.member.mapper.MemberMapper;
import com.codestates.member.service.MemberService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import javax.validation.constraints.Positive;
import java.util.List;
import java.util.stream.Collectors;


/**
 * - DI 적용
 * - Mapstruct Mapper 적용
 */

@RestController
@RequestMapping("/v6/members")
@Validated
public class MemberController {
    private final MemberService memberService;
    private final MemberMapper mapper;

    public MemberController(MemberService memberService, MemberMapper mapper) {
        this.memberService = memberService;
        this.mapper = mapper;
    }

    @PostMapping
    public ResponseEntity postMember(@Valid @RequestBody MemberPostDto memberDto) {
        Member member = mapper.memberPostDtoToMember(memberDto);

        Member response = memberService.createMember(member);

        return new ResponseEntity<>(mapper.memberToMemberResponseDto(response),
                HttpStatus.CREATED);
    }

    @PatchMapping("/{member-id}")
    public ResponseEntity patchMember(
            @PathVariable("member-id") @Positive long memberId,
            @Valid @RequestBody MemberPatchDto memberPatchDto) {
        memberPatchDto.setMemberId(memberId);

        Member response =
                memberService.updateMember(mapper.memberPatchDtoToMember(memberPatchDto));

        return new ResponseEntity<>(mapper.memberToMemberResponseDto(response),
                HttpStatus.OK);
    }

    @GetMapping("/{member-id}")
    public ResponseEntity getMember(
            @PathVariable("member-id") @Positive long memberId) {
        Member response = memberService.findMember(memberId);
        return new ResponseEntity<>(mapper.memberToMemberResponseDto(response), HttpStatus.OK);
    }

    @GetMapping
    public ResponseEntity getMembers() {
        List<Member> members = memberService.findMembers();
        List<MemberResponseDto> response = mapper.membersToMemberResponseDtos(members);
        return new ResponseEntity<>(response, HttpStatus.OK);
    }

    @DeleteMapping("/{member-id}")
    public ResponseEntity deleteMember(
            @PathVariable("member-id") @Positive long memberId) {
        System.out.println("# delete member");
        memberService.deleteMember(memberId);

        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
    }

    @ExceptionHandler
    public ResponseEntity handleException(MethodArgumentNotValidException e) {
        //MethodArgumentNotValidException 객체에서
        //getBindingResult().getFieldErrors()를 통해 발생한 에러 정보를 확인할 수 있다
        final List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
        //getBindingResult().getFieldErrors()를 통해 확인한 에러 정보를
        //ResponseEntity를 통해 Response Body로 전달한다
        return new ResponseEntity<>(fieldErrors, HttpStatus.BAD_REQUEST);
    }
}
  • 위의 코드 흐름은 다음과 같이 진행된다
  1. 클라이언트 쪽에서 회원 등록을 위해 MemberController의 postMember() 핸들러 메서드에 요청을 전송한다
  2. RequestBody에 유효하지 않은 요청 데이터가 포함되어 있어 유효성 검증에 실패하고, MethodArgumentNotValidException이 발생한다
  3. MemberController에는 @ExceptionHandler 애너테이션이 추가된 예외 처리 메서드인 handleException()이 있기 때문에 유효성 검증 과정에서 내부적으로 던져진 MethodArgumentNotValidExceptionhandleException() 메서드가 전달 받는다
  4. postman으로 정확하지 않은 data를 json 형식으로 전송하면 아래와 같이 오류가 발생하고 상세한 오류 내역을 Response Body로 전송해 준다

  • 지금까지는 @ExceptionHandler 애너테이션과 handleException() 메서드를 통해 유효성 검사 결과를 그대로 전송받았다
  • 전송받은 데이터 중에는 불필요한 내용도 포함되어 있다

 

  • 필요한 내용들만 선택적으로 받을 수 있도록 코드를 수정한다
  • 별도의 ErrorResponse 클래스를 생성한다
    - DTO 클래스의 유효성 검증 실패 시, 실패한 필드(멤버 변수)에 대한 Error 정보만 담아서 응답으로 전송한다
  • MemberController(v6)에 @ExceptionHandler 애너테이션 적용 코드를 수정한다
package com.codestates.member.controller;

import lombok.AllArgsConstructor;
import lombok.Getter;

import java.util.List;

@Getter
@AllArgsConstructor

public class ErrorResponse {

    //한 개 이상의 유효성 검증에 실패한 필드의 에러 정보를 담기 위해서 List 객체를 이용한다
    private List<FieldError> fieldErrors;

    @Getter
    @AllArgsConstructor
    
    //한개의 필드 에러 정보는
    //FieldError 라는 별도의 static class를 ErrorResponse 클래스의 멤버 클래스로 정의한다
    public static class FieldError{
        private String field;
        private Object rejectedValue;
        private String reason;
    }
}
  • FieldError 클래스는 ErrorResponse 클래스 내부에 정의되어 있으나 내부(Inner) 클래스라고 부르기보다는 ErrorResponse 클래스의 static 멤버 클래스라고 부르는 것이 적절하다
  • 클래스가 멤버 변수와 멤버 메서드를 포함하듯이 static 멤버 클래스를 포함할 수 있다

 

  • MemberController(v6)에 @ExceptionHandler 애너테이션 적용 코드를 수정한다
@ExceptionHandler
    public ResponseEntity handleException(MethodArgumentNotValidException e) {
        //MethodArgumentNotValidException 객체에서
        //getBindingResult().getFieldErrors()를 통해 발생한 에러 정보를 확인할 수 있다
        final List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();

        //필요한 정보들만 선택하여 ErrorResponse.FieldError 클래스에서 List로 변환한다
        List<ErrorResponse.FieldError> errors =
                fieldErrors.stream()
                        .map(error->new ErrorResponse.FieldError(
                                error.getField(),
                                error.getRejectedValue(),
                                error.getDefaultMessage()
                        ))
                        .collect(Collectors.toList());

        //getBindingResult().getFieldErrors()를 통해 확인한 에러 정보를 List<ErrorResponse.FieldError>에 넣은 후
        //ResponseEntity를 통해 Response Body로 전달한다
        return new ResponseEntity<>(new ErrorResponse(errors), HttpStatus.BAD_REQUEST);
    }

 

  • post를 전송하면 아래와 같이 필요한 데이터만 응답받을 수 있다
    - email 주소가 오류인 경우

        - email 와 name 이 동시에 오류인 경우

 

2. @ExceptionHandler 의 단점

  • 각각의 Controller 클래스에서 @ExceptionHandler 애너테이션을 사용하여 Request Body에 대한 유효성 검증 실패에 대한 에러 처리를 해야되므로 각 Controller 클래스마다 코드 중복이 발생한다
  • Controller에서 처리해야 되는 예외(Exception)가 유효성 검증 실패에 대한 예외(MethodArgumentNotValidException)만 있는것이 아니기 때문에 하나의 Controller 클래스 내에서 @ExceptionHandler를 추가한 에러 처리 핸들러 메서드가 늘어날 수 있다

 

※ 참조 링크

Exceptions : https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-ann-exceptionhandler

 

Web on Servlet Stack

Spring Web MVC is the original web framework built on the Servlet API and has been included in the Spring Framework from the very beginning. The formal name, “Spring Web MVC,” comes from the name of its source module (spring-webmvc), but it is more com

docs.spring.io

BindingResult 클래스 : https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/validation/BindingResult.html

 

BindingResult (Spring Framework 5.3.21 API)

Record the given value for the specified field. To be used when a target object cannot be constructed, making the original field values available through Errors.getFieldValue(java.lang.String). In case of a registered error, the rejected value will be expo

docs.spring.io

 ConstraintViolation 인터페이스와 구현 클래스

 : https://docs.oracle.com/javaee/7/api/javax/validation/ConstraintViolation.html

 

ConstraintViolation (Java(TM) EE 7 Specification APIs)

Object getLeafBean() Returns: the bean instance the constraint is applied on if it is a bean constraint the bean instance hosting the property the constraint is applied on if it is a property constraint null when the ConstraintViolation is returned after c

docs.oracle.com

 : https://docs.jboss.org/hibernate/validator/5.3/api/org/hibernate/validator/internal/engine/ConstraintViolationImpl.html

 

ConstraintViolationImpl (Hibernate Validator 5.3.6.Final)

equals public boolean equals(Object o) IMPORTANT - some behaviour of Validator depends on the correct implementation of this equals method! (HF) expressionVariables and dynamicPayload are not taken into account for equality. These variables solely enric

docs.jboss.org

 

1. 서비스 계층 연동

  • 예제 코드를 활용하여 서비스 계층의 연동을 진행한다
  • API계층과 서비스계층의 연동은 API계층의 클래스가 서비스계층의 클래스와 메서드를 호출하여 상호 작용한다는 의미이다

 1) 예제 코드

 2) 학습 방향

  • Spring의 DI(Dependency Injection)를 이용해서 API 계층과 비즈니스 계층을 연동한다
  • API 계층에서 전달받은 DTO 객체를 비즈니스 계층의 도메인 엔티티(Entity) 객체로 변환해서 전달하는 방법을 알아본다
  • Controller에 많은 개선이 일어나기 때문에 Controller의 요청 URI가 “/v1/xxxx”에서 “/v2/xxxx”와 같이 지속적으로 API 버전이 바뀌는 점에 유의한다
  • 서비스 계층에서 샘플 응답 데이터를 클라이언트에 전송하는 로직을 확인할 수 있다

2. 서비스(Service)

  • 애플리케이션에서 Service는 도메인 업무 영역을 구현하는 비지니스 로직과 연관이 있다
  • 비지니스 로직을 처리하기 위한 서비스 계층은 도메인 모델을 포함하고 있다
  • 도메인 모델은 DDD(Domain Driven Design / 도메인 주도 설계)와 관련성이 높다
    - 빈약한 도메인 모델(anemic domain model) 과 풍부한 도메인 모델(roch domain model)로 구분된다

3. Service 클래스 작성

 1) Controller 클래스와 연동하는 Service 클래스의 틀을 작성한다

package com.codestates.member;

import java.lang.reflect.Member;
import java.util.List;

public class MemberService {

    //MemberController 클래스의 postMember
    public Member saveMember(Member member) {
        return null;
    }

    //MemberController 클래스의 patchMember
    public Member updateMember(Member member) {
        return null;
    }

    //MemberController 클래스의 getMember
    public Member findMember(Member member) {
        return null;
    }

    //MemberController 클래스의 getMembers
    public List<Member> findMember() {
        return null;
    }

    //MemberController 클래스의 deleteMember
    public void deleteMember(long memberId) {

    }
}
  • MemberController 클래스에는 핸들러 메서드가 5개 있다
    - postMember() , patchMember() , getMember() , getMembers() , deleteMember()
package com.codestates.member;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import javax.validation.constraints.Positive;


@RestController
@RequestMapping("/v1/members")
@Validated
public class MemberController {

	//postMember() : 1명의 회원 등록을 위한 요청을 전달 받는다.
    @PostMapping    
    public ResponseEntity postMember(@Valid @RequestBody MemberPostDto memberDto) {
        return new ResponseEntity<>(memberDto, HttpStatus.CREATED);
    }

	//patchMember() : 1명의 회원 수정을 위한 요청을 전달 받는다.
    @PatchMapping("/{member-id}")
    public ResponseEntity patchMember(@PathVariable("member-id") @Positive long memberId,
                                      @Valid @RequestBody MemberPatchDto memberPatchDto) {
        memberPatchDto.setMemberId(memberId);

        // No need Business logic

        return new ResponseEntity<>(memberPatchDto, HttpStatus.OK);
    }

	//getMember() : 1명의 회원 정보 조회를 위한 요청을 전달 받는다.
    @GetMapping("/{member-id}")
    public ResponseEntity getMember(@PathVariable("member-id") @Positive long memberId) {
        System.out.println("# memberId: " + memberId);

        // not implementation
        return new ResponseEntity<>(HttpStatus.OK);
    }

	//getMembers() : N명의 회원 정보 조회를 위한 요청을 전달 받는다.
    @GetMapping
    public ResponseEntity getMembers() {
        System.out.println("# get Members");

        // not implementation

        return new ResponseEntity<>(HttpStatus.OK);
    }

	//deleteMember() : 1명의 회원 정보 삭제를 위한 요청을 전달 받는다.
    @DeleteMapping("/{member-id}")
    public ResponseEntity deleteMember(@PathVariable("member-id") @Positive long memberId) {
        System.out.println("# deleted memberId: " + memberId);
        // No need business logic

        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
    }
  • MemberController의 핸들러 메서드에서 클라이언트의 요청 데이터(Request Body)를 전달 받을 때 MemberPostDtoMemberPatchDto 같은 DTO 클래스를 사용한다
    - DTO가 API 계층에서 클라이언트의 Request Body를 전달 받고 클라이언트에게 되돌려 줄 응답 데이터를 담는 역할을 한다
  • MemberService에서는 saveMember() 메서드와 updateMember() 메서드의 파라미터와 리턴값에 Member라는 타입을 사용했다
    - API 계층에서 전달 받은 요청 데이터를 기반으로 서비스 계층에서 비즈니스 로직을 처리하기 위해 필요한 데이터를 전달 받고, 비즈니스 로직을 처리한 후에는 결과 값을 다시 API 계층으로 리턴해주는 역할을 한다

 2) Member 클래스 구현

  • 아노테이션을 적용하면 자동으로 import 된다
package com.codestates.Member;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor

public class Member {
    private long memberId;
    private String email;
    private String name;
    private String phone;
}

 

 3) MemberService 클래스 세부 구현

package com.codestates.Member;

import java.lang.reflect.Member;
import java.util.List;

public class MemberService {

    //MemberController 클래스의 postMember
    public Member createMember(Member member) {
        // TODO should business logic

        // TODO member 객체는 나중에 DB에 저장 후, 되돌려 받는 것으로 변경 필요.
        Member createdMember = member;
        // DB 데이터가 없으므로 Member 객체를 그대로 리턴
        return createdMember;
    }

    //MemberController 클래스의 patchMember
    public Member updateMember(Member member) {
        // TODO should business logic

        // TODO member 객체는 나중에 DB에 저장 후, 되돌려 받는 것으로 변경 필요.
        Member updatedMember = member;
        // DB 데이터가 없으므로 Member 객체를 그대로 리턴
        return updatedMember;
    }

    //MemberController 클래스의 getMember
    public Member findMember(Member member) {
        // TODO should business logic

        // TODO member 객체는 나중에 DB에 저장 후, 되돌려 받는 것으로 변경 필요.
        // 현재는 stub 데이터로 사용
        Member member =
                new Member(memberId, "hgd@gmail.com", "홍길동", "010-1234-5678");
        return member;
    }

    //MemberController 클래스의 getMembers
    public List<Member> findMember() {
        // TODO should business logic

        // TODO member 객체는 나중에 DB에 저장 후, 되돌려 받는 것으로 변경 필요.
        List<Member> members = List.of(
                new Member(1, "hgd@gmail.com", "홍길동", "010-1234-5678"),
                new Member(2, "lml@gmail.com", "이몽룡", "010-1111-2222");
        );
        return members;
    }

    //MemberController 클래스의 deleteMember
    public void deleteMember(long memberId) {
        // TODO should business logic
    }
}

 

 4) DI(Dependency Injection)없이 비즈니스 계층과 API 계층 연동

  • 어떤 클래스가 다른 클래스의 기능을 사용하고자 한다면 객체를 새로 생성하여 다른 클래스의 메서드를 호출하면 된다
  • 객체의 생성은 new 키워드를 사용한다
  • MemberController에서 MemberService의 기능을 사용하도록 MemberController를 수정해 본다
package com.codestates.Member;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import javax.validation.constraints.Positive;

import java.util.List;

@RestController
@RequestMapping("/v2/members")
@Validated
public class MemberController {
    private final MemberService memberService;

    private class MemberService memberService;
    //에러로 인하여 생긴 class - 질문 요함...???

    public MemberController() {
        this.memberService = new MemberService();
        //MembeService 클래스를 사용하기 위하여 객체를 생성한다
    }

    //postMember() : 1명의 회원 등록을 위한 요청을 전달 받는다.
    @PostMapping
    public ResponseEntity postMember(
            @Valid @RequestBody MemberPostDto memberDto) {

        //클라이언트에서 전달 받은 DTO 클래스의 정보를
        // MemberService의 updateMember() 메서드의 파라미터로 전달하기 위해
        // MemberPostDto 클래스의 정보를 Member 클래스에 채워준다

        Member member = new Member();
        member.setEmail(memberDto.getEmail());
        member.setName(memberDto.getName());
        member.setPhone(memberDto.getPhone());

        //회원 정보 등록을 위해 MemberService 클래스의 createMember() 메서드를 호출한다
        Member response = memberService.createMember(member);

        return new ResponseEntity<>(memberDto, HttpStatus.CREATED);
    }

    //patchMember() : 1명의 회원 수정을 위한 요청을 전달 받는다.
    @PatchMapping("/{member-id}")
    public ResponseEntity patchMember(
            @PathVariable("member-id") @Positive long memberId,
            @Valid @RequestBody MemberPatchDto memberPatchDto) {
        memberPatchDto.setMemberId(memberId);

        //클라이언트에서 전달 받은 DTO 클래스의 정보를
        //MemberService의 createMember() 메서드의 파라미터로 전달하기 위해
        //MemberPatchDto 클래스의 정보를 Member 클래스에 채워준다
        Member member = new Member();
        member.setMemberId(memberPatchDto.getMemberId());
        member.setName(memberPatchDto.getName());
        member.setPhone(memberDto.getPhone());

        //회원 정보 수정을 위해 MemberService 클래스의 updateMember() 메서드를 호출한다
        Member response = memberService.updateMember(member);

        return new ResponseEntity<>(memberPatchDto, HttpStatus.OK);
    }

    //getMember() : 1명의 회원 정보 조회를 위한 요청을 전달 받는다.
    @GetMapping("/{member-id}")
    public ResponseEntity getMember(
            @PathVariable("member-id") @Positive long memberId) {

        //한 명의 회원 정보 조회를 위해 MemberService 클래스의 findMember() 메서드를 호출한다
        //특정 회원의 정보를 조회하는 기준인 memberId를 파라미터로 넘겨준다
        Member response = memberService.fineMember(memberId);

        System.out.println("# memberId: " + memberId);

        // not implementation
        return new ResponseEntity<>(HttpStatus.OK);
    }

    //getMembers() : N명의 회원 정보 조회를 위한 요청을 전달 받는다.
    @GetMapping
    public ResponseEntity getMembers() {

        //모든 회원의 정보를 조회하기 위해 MemberService 클래스의 findMembers() 메서드를 호출한다
        List<Member> response = memberService.fineMembers();

        System.out.println("# get Members");

        // not implementation

        return new ResponseEntity<>(HttpStatus.OK);
    }

    //deleteMember() : 1명의 회원 정보 삭제를 위한 요청을 전달 받는다.
    @DeleteMapping("/{member-id}")
    public ResponseEntity deleteMember(
            @PathVariable("member-id") @Positive long memberId) {
        System.out.println("# deleted memberId: " + memberId);

        //한 명의 회원 정보를 삭제하기 위해 MemberService 클래스의 deleteMember() 메서드를 호출한다
        //특정 회원의 정보를 삭제하는 기준인 memberId를 파라미터로 넘겨준다
        memberService.deleteMember(memberId);
        // No need business logic

        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
    }    
}

 

 5) DI를 적용한 비즈니스 계층과 API 계층 연동

  • MemberController v2 코드는 Spring에서 지원하는 DI 기능을 사용하지 않았기 때문에 MemberController와 MemberService가 강하게 결합(Tight Coupling)되어 있는 상태이다
  • Spring의 DI를 사용하면 클래스 간의 결합을 느슨한 결합(Loose Coupling)으로 만들 수 있다
  • Spring의 DI를 사용하도록 MemberController를 수정해 본다
 //DI를 적용하기 위한 코드 수정, 비어있던 (파라미터)에 객체를 추가한다
    public MemberController(MemberService memberService) {
        // Spring이 애플리케이션 로드시, ApplicationContext에 있는 MemberService 객체를 주입하여 준다
        this.memberService = memberService();
        //DI를 적용하여 MembeService 클래스를 사용하기 위하여 객체를 지정한다
    }
  • Spring에서 DI를 통해서 어떤 객체를 주입 받기 위해서는 주입을 받는 클래스와 주입 대상 클래스 모두 Spring Bean이어야 한다
  • MemberService 클래스에 @Service 애너테이션을 추가하여 MemberService 클래스를 Spring Bean으로 변경한다
@Service

public class MemberService {
  • 생성자가 하나 이상일 경우에는 DI를 적용하기 위해 생성자에 반드시 @Autowired 애너테이션을 붙여야 한다

 

 6) 현재까지 작성한 코드의 문제점

  1. Controller 핸들러 메서드의 책임과 역할에 관한 문제
    - 핸들러 메서드의 역할은 클라이언트로부터 전달 받은 요청 데이터를 Service 클래스로 전달하고, 응답 데이터를 클라이언트로 다시 전송해주는 단순한 역할만을 하는 것이 좋다
    - 현재의 MemberController에서는 핸들러 메서드가 DTO 클래스를 엔티티(Entity) 객체로 변환하는 작업까지 하고 있다
  2. Service 계층에서 사용되는 엔티티(Entity) 객체를 클라이언트의 응답으로 전송하고 있다
    - DTO 클래스는 API 계층에서만 데이터를 처리하는 역할을 하고 엔티티(Entity) 클래스는 서비스 계층에서만 데이터를 처리하는 역할을 해야 한다
    - 엔티티(Entity) 클래스의 객체를 클라이언트의 응답으로 전송함으로써 계층 간의 역할 분리가 되어있지 않다

 7) 적용한 아노테이션

  • @Valid
    - 필드에 사용된 모든 아노테이션에 대한 유효성을 검증할 때 사용한다
  • @REquestBody
    - @REquestBody를 사용하면 파라메터에 HTTP요청 본문이 그대로 전달된다
    - 일반적으로 GET/POST 요청 파라미터는 @REquestBody를 사용하지 않는다
    -  xml 또는 Json 파라미터를 요청할 경우에 @REquestBody를 사용한다
  • @ResponseBody
    - @ResponseBody를 사용하면 HTTP요청의 Body 내용으로 변환하여 전송한다
  • @Getter, @Setter
    - lombok 라이브러리에서 제공하는 애너테이션이다
    - DTO 클래스를 작성하면서 각 멤버 변수에 해당하는 getter/setter 메서드를 일일이 작성하지 않아도 된다
  • @AllArgsConstructor
    - 현재 Member 클래스에 추가된 모든 멤버 변수를 파라미터로 갖는 Member 생성자를 자동으로 생성해 준다
  • @NoArgsConstructor
    - 파라미터가 없는 기본 생성자를 자동으로 생성해 준다

@Getter, @Setter, @AllArgsConstructor, @NoArgsConstructor, @Data, @ToString

 

 

 

 

※ 참조 링크

▶ DDD : https://ko.wikipedia.org/wiki/%EB%8F%84%EB%A9%94%EC%9D%B8_%EC%A3%BC%EB%8F%84_%EC%84%A4%EA%B3%84

 

도메인 주도 설계 - 위키백과, 우리 모두의 백과사전

 

ko.wikipedia.org

https://ko.wikipedia.org/wiki/%EB%B9%88%EC%95%BD%ED%95%9C_%EB%8F%84%EB%A9%94%EC%9D%B8_%EB%AA%A8%EB%8D%B8

 

빈약한 도메인 모델 - 위키백과, 우리 모두의 백과사전

 

ko.wikipedia.org

https://martinfowler.com/eaaCatalog/domainModel.html

 

P of EAA: Domain Model

 

martinfowler.com

https://martinfowler.com/tags/domain%20driven%20design.html

 

domain driven design

When programming, I often find it's useful to represent things as a compound. A 2D coordinate consists of an x value and y value. An amount of money consists of a number and a currency. A date range consists of start and end dates, which themselves can be

martinfowler.com

Lombok : https://projectlombok.org/features/all

 

Stable

 

projectlombok.org

 

1. 아키텍쳐(Architecture)

  • 건축 분야에서 유래된 용어이다
  • 요구 사항을 만족하는 건축물을 만들기 위한 청사진과 같다
  • 컴퓨터 시스템에서의 아키텍처는 어떠한 시스템을 구축하는데 있어 해당 시스템의 비지니스적 요구 사항을 만족하는 전체 시스템 구조를 정의하는 것이다
  • 전체 시스템 구조를 상호간에 쉽게 이해할 수 있도록 일반적으로 이미지나 도형 등을 많이 사용한다
  • 아케텍쳐는 최대한 심플하고 간결해야 한다

2. 시스템 아키텍쳐(System Architecture)

  • 하드웨어와 소프트웨어를 모두 포함하는 어떤 시스템의 전체적인 구성을 큰그림으로 표현한 것이다
  • 해당 시스템이 어떤 하드웨어로 구성되고, 어떤 소프트웨어를 사용하는지를 대략적으로 알 수 있도록 한다
  • 시스템 구성 요소들 간의 상호작용과 시스템의 동작 원리 등을 시스템 아키텍처 안에 표현하면 이해하기가 쉽다

3. 소프트웨어 아키텍쳐(Software Architecture)

  • 하드웨어를 제외한 모든 소프트웨어의 구성을 큰 그림으로 표현한 것이다
  • Java 플랫폼 아키텍쳐가 대표적이다
  • Java의 기술지원, 기능 등을 그림을 통해 알 수 있다

  • Spring Framework 모듈 아키텍쳐를 보면 지원하는 모듈을 확인할 수 있다.
    - 모듈은 여러가지 기능들을 목적에 맞게 그룹화하여 묶어 놓은 것을 말한다
    - Spring에서 모듈은 Java의 패키지 단위로 묶여 있고, 패키지 안에는 클래스들이 포함되어 있다
    - 모듈은 재사용이 가능하도록 라이브러리 형태로 제공된다

 

4. 계층형 아키텍쳐(N-Tier)

 1) API 계층(API Layer)

  • 클라이언트의 요청을 받아들이는 계층이다
  • 표현 계층(Presentation Layer)이라고도 하지만 REST API를 제공하는 애플리케이션의 경우 API 계층이라고 표현한다

 2) 서비스 계층(Service Layer)

  • API 계층에서 전달 받은 요청을 업무 도메인의 요구 사항에 맞게 비즈니스적으로 처리하는 계층이다
  • 애플리케이션의 핵심 로직이 포함되어 있으며, 애플리케이션에 있어 핵심이 되는 계층이다

도메인(Domain)
 -
 애플리케이션 개발에서 흔하게 사용하는 도메인이란 용어는 주로 비즈니스적인 어떤 업무 영역과 관련이다
 - 애플리케이션 개발에서 필요한 업무 로직에 대한 지식을 도메인 지식(Domain Knowledge)이라고 한다

 - 도메인 지식이 많을수록 서비스 계층에서 비즈니스 로직으로 구현해야 하는 것들을 퀄리티가 높게 표현할 수 있다

 

 3) 데이터 엑세스 계층(Data Access Layer)

  • 비즈니스 계층에서 처리된 데이터를 데이터베이스 등의 데이터 저장소에 저장하기 위한 계층이다

 

※ 참조 링크

▶ Spring Framework : https://docs.spring.io/spring-framework/docs/5.0.0.M5/spring-framework-reference/html/overview.html

 

2. Introduction to the Spring Framework

The Spring Framework is a Java platform that provides comprehensive infrastructure support for developing Java applications. Spring handles the infrastructure so you can focus on your application. Spring enables you to build applications from "plain old Ja

docs.spring.io

 

'Spring Framework' 카테고리의 다른 글

Spring Framwork - PSA(Portable Service Abstraction)  (0) 2022.06.22
Spring Framework - AOP  (0) 2022.06.22
Spring Framework - DI - Spring Container  (0) 2022.06.19
Spring Framework - IoC / DI - 기초  (0) 2022.06.17
Spring Framework 특징  (0) 2022.06.15

1. PSA(Portable Service Abstraction)

 1) Pablo Picasso 의 추상화 기법

  • 파블로 피카소의 작품 'The Bull is a series of eleven lithographs created' 이다
  • 다국적 기업인 Apple의 업무 프로세스에 기본이 되는 그림이기도 하다
  • 황소의 특성을 살려 본질만을 남기려 한 작품이다

  • 객체지향 프로그램밍에서는 클래스의 본질적인 특성만을 추출해서 일반화하는 작업을 추상화(Abstraction)라고 한다
  • Java에서 추상화를 표현할 수 있는 방법에는 추상 클래스와 인터페이스가 있다

 2) 일반화(추상화)의 예

  • 어린 아이의 특성을 일반화하여 코드로 작성해 보면 아래와 같다

  • 위의 추상 클래스에 구체적인 메서드를 작성해 본다

  • Child 클래스를 실행시켜 본다

  • 클라이언트(ChildManageApplication 클래스의 main() 메서드)는
  • NewBornBaby, Infant, Toddler 를 사용할 때 구체화 클래스의 객체를 자신의 타입에 할당하지 않고, (1) ~ (3)과 같이 Child 클래스 변수에 할당을 해서 접근을 한다
  • 클라이언트는 Child라는 추상클래스만 찾아서 하위의 기능 클래스를 사용할 수 있다
  • 클라이언트가 추상황 된 상위클래스만을 일관되게 바라보며 하위 클래스의 기능을 사용할 수 있는 것이 일관된 서비스 추상화이며, PSA의 기본 개념이다

서버를 이용하는 클라이언트 외에 코드 내에서 어떤 클래스의 기능을 사용하는 측을 클라이언트라고 부른다

 

2. 서비스에 적용하는 일관된 서비스 추상화 (PSA)기법

  • 서비스 추상화는 추상화의 개념을 애플리케이션에 자용하는 서비스에 적용하는 기법이다

  • DbClient에서 어떤 JdbcConnector 구현체를 사용하더라도 Connection을 얻는 방식은 getConnection() 메서드를 사용해야 하기 때문에 동일하다
    - 일관된 방식으로 서비스의 기능을 사용할 수 있다
  • 애플리케이션에서 특정 서비스를 이용할 때, 서비스의 기능을 접근하는 방식 자체를 일관되게 유지하면서 기술 자체를 유연하게 사용할 수 있도록 하는 것을 PSA(일관된 서비스 추상화)라고 한다

 1) PSA(일관된 서비스 추상화) 코드 예제

  • DbClient 클래스의 (1)에서 SQLiteJdbcConnector 구현체의 객체를 생성해서 JdbcConnector 인터페이스 타입의 변수에 할당(업캐스팅)하고 있다
  • DbClient 클래스의 (2)에서 실제로 데이터를 데이터베이스에 저장하는 기능을 하는 DataProcessor 클래스의 생성자로 JdbcConnector 객체를 전달하고 있다(의존성 주입).

  • 상기와 같이 작성 후 실행을 시키면 error가 발생한다

  • JdbcConnector 메서드에 아래 코드를 삽입시켜 부면 해결된다
import java.sql.Connection;
  • 에러없이 실행된다

  • 다른 애플리케이션에서 SQLite 데이터베이스를 사용하는 것이 아니라 Oracle 데이터베이스를 사용해야 한다면, JdbcConnector 서비스 모듈을 그대로 가져와서 (1)의 new SQLiteJdbcConnector()를 new OracleJdbcConnector()로 바꿔서 사용하면 된다

3. PSA 필요성

  • 어떤 서비스를 이용하기 위한 접근 방식을 일관된 방식으로 유지하여 애플리케이션에서 사용하는 기술의 변경 시 최소 작업을 통해 변경 사항을 반영한다
  • PSA를 통해서 애플리케이션의 요구 사항 변경에 유연하게 대처할 수 있다
  • PSA는 트랜잭션 서비스, 메일 서비스, Spring Data 서비스 등에 적용된다

'Spring Framework' 카테고리의 다른 글

Spring Framework - Architecture  (0) 2022.06.26
Spring Framework - AOP  (0) 2022.06.22
Spring Framework - DI - Spring Container  (0) 2022.06.19
Spring Framework - IoC / DI - 기초  (0) 2022.06.17
Spring Framework 특징  (0) 2022.06.15

1. AOP(Aspect Oriented Programming)

  • 관심지향 프로그래밍으로 정의한다
  • 애플리케이션 핵심 업무 로직에서 공통 기능 로직을 분리하는 것이다

 1) 핵심 관심 사항 (Core concern)

  - 애플리케이션의 주 목적을 달성하기 위한 핵심 로직에 대한 관심사를 말한다

 

 2) 공통 관심 사항 (Cross-cutting concern)

  - 애플리케이션 전반에 걸쳐 공통적으로 사용되는 기능을 말한다

  - 로깅, 보안, 트랜젝션 등이 있다

 

2. AOP가 필요한 이유

  • 코드의 간결성을 유지
  • 객체 지향 설계 원칙에 적합한 코드 구현
  • 코드의 재사용

※ 트랜젝션(Tranjection) : 데이터를 처리하는 하나의 작업 단위를 말한다

  • 트랜젝션에는 커밋(commit) 과 롤백(rollback) 기능이 있다
    - 커밋은 모든 작업이 성공적으로 수행되었을 경우 수행한 작업을 데이터베이스에 반영하는 것이다
    - 롤백은 작업 중 하나라도 실패하면 이전에 성공한 작업들을 작업 수행 이전으로 되돌리는 것이다
  • 여러 작업을 하나의 트랜젝션으로 묶으면 코드는 간결해지고 재활용성은 높아진다

1. 스프링 컨테이너(Spring Container)

  • ApplicationContext 를 스프링 컨테이너라고 한다
  • 인터페이스로 구현되어 있고, 다형성이 적용된다
  • XML, 애너테이션 기반의 자바 설정 클래스로 만들 수 있다
  • 이전까지는 개발자가 xml을 통해 모두 설정하여야 했으나, Spring Boot를 사용하면서 설정하지 않는다
  • 빈의 인스턴스화, 구성, 전체 생명 주기 및 제거까지 처리한다
    - 컨테이너는 개발자가 정의한 Bean을 객체로 만들어 관리하며, 개발자가 필요로 할 때 제공한다
  • 스프링 컨테이너를 통해 원하는 만큼 객체를 가질 수 있다
  • 의존성 주입을 통해 애플리케이션의 컴포넌트를 관리한다
    - 스프링 컨테이너는 서로 다른 빈을 연결해 애플리케이션의 빈을 연결하는 역할을 한다
    - 개발자는 모듈 간에 의존 및 결합으로 인해 발생하는 문제로부터 자유로울 수 있다
    - 메서드가 언제, 어디서 호출되어야 하는지, 메서드를 호출하기 위해 필요한 매개 변수를 준비해서 전달하지 않는다

2. Spring Container 사용 목적

 

Spring Framework - IoC / DI - 기초 :: 상상코딩

 

coding-mid-life.tistory.com

  • 객체 간의 의존성을 낮추기 위하여 사용한다
  • 새로운 정책이 발생할 경우 변경 사항을 수작업으로 해야 한다
  • 코드의 양이 방대할 경우 수정 시간이 과도하게 소모된다
  • 스프링 컨테이너를 사용할 경우 인터페이스에만 의존하도록 설계할 수 있다

 

3. Spring Container 생성

  • 기존에는 xml방식으로 설정하였다 (ClassPathXmlApplicationContext)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">
        <-- <beans />에 필요한 값들을 설정합니다. -->
        
    <bean id="..." class="...">  
        <!-- id="..." Bean의 정의를 식별하는 문자열을 작성한다 -->
        <!-- class="..." Bean의 유형을 정의하고 클래스 이름은 작성한다 -->
    </bean>
         
    <bean id="..." class="...">         
   		 <!-- 추가적인 Bean을 작성한다 -->
    </bean>    
</beans>
  • 최근에는 주로 애너테이션 기반의 자바 설정 클래스로 Spring Container 을 만드는 것을 의미한다
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);


스프링 컨테이너를 만드는 다양한 방법은 ApplicationContext 인터페이스의 구현체이다
 - AppConfig.class 등의 구성 정보를 지정해줘서 스프링 컨테이너를 생성한다
 - AppConfig에 있는 구성 정보를 통해서 스프링 컨테이너는 필요한 객체들을 생성한다
 - 애플리케이션 클래스는 구성 메타데이터와 결합되어 ApplicationContext 생성 및 초기화된 후
   완전히 구성되고 실행 가능한 시스템 또는 애플리케이션을 갖게 된다
  • 스프링 컨테이너는 Configuration Metadata를 사용한다
  • 스프링 컨테이너는 파라미터로 넘어온 설정 클래스 정보를 사용해서 스프링 빈을 등록한다
  • new AnnotationConfigApplicationContext(구성정보.class)로 스프링에 있는 @Bean의 메서드를 등록한다
    ※  주석 기반 컨테이너 구성
       : https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-annotation-config
  • 스프링 빈 조회에서 상속관계가 있을 시 부모타입으로 조회하면 자식 타입도 함께 조회된다
    - 모든 자바 객체의 최고 부모인 object타입으로 조회하면 모든 스프링 빈을 조회한다

※ IntelliJ 에서 ApplicationContext 인터페이스를 확인하는 방법

  - ctrl + n >  class >  ApplicationContext 입력 검색

  -  ApplicationContext 인터페이스를 구현하기 위한 하위 클래스를 확인할 수 있다

 

 

4. Spring Container 종류

  • 파라미터로 넘어온 설정 클래스 정보를 참고해서 빈의 생성, 관계 설정 등의 제어작업을 총괄하는 컨테이너이다

 1) BeanFactory

  • 스프링 컨테이너의 최상위 인터페이스이다
  • BeanFactory는 bean을 등록, 생성, 조회, 반환 등... 빈을 관리하는 역할을 한다
  • getBean() 메소드를 통해 빈을 인스턴스화 할 수 있다
  • @Bean이 붙은 메서드의 이름을 스프링 빈의 이름으로 사용해 빈을 등록한다

 2) ApplicationContext

  • BeanFactory의 기능을 상속받아 제공한다
  • bean을 관리하고 검색하는 기능을 BeanFactory가 제공하고 그 외에 부가기능을 제공한다
  • 부가 기능은 아래와 같다
    - MessageSource: 메세지 다국화를 위한 인터페이스
    - EnvironmentCapable: 개발, 운영 등 환경변수 등으로 나눠 처리하고, 애플리케이션 구동 시 필요한 정보들을 관리하기 위한 인터페이스
    - ApplicationEventPublisher: 이벤트 관련 기능을 제공하는 인터페이스
    - ResourceLoader: 파일, 클래스 패스, 외부 등 리소스를 편리하게 조회

5. Container 인스턴스화

  • ApplicationContext 생성자에 제공된 위치 경로는 컨테이너가 로컬 파일 시스템, Java CLASSPATH 등과 같은 다양한 외부 리소스로부터 구성 메타데이터를 로드할 수 있도록 하는 리소스 문자열이다
// Annotation
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

// XML
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");

 

6. new 와 생성자 주입

  • new를 사용하는 대신 생성자를 통해 의존 객체가 주입되고, 느슨한 의존 관계가 이루어진다

  • userRepository와 discountInfo의 구현 클래스는 Bean 설정에 따라서 유연하게 변하게 된다
  • OrderServiceImpl 클래스는 생성자를 통해 어떤 구현 객체가 주입될지 알 수 없으며, 알 필요도 없다
  • 어떤 객체가 주입될지는 외부 AppConfig에서 결정된다
  • OrderServiceImpl 클래스는 실행에만 집중하게 된다

7. 빈(Bean)

  • 스프링 컨테이너에 의해 관리되는 재사용 소프트웨어 컴포넌트이다
    - 컴포넌트(component) : 여러 개의 객체를 하나로 묶어서 저장한 그룹
  • Spring 컨테이너가 관리하는 자바 객체를 의미하며, 하나 이상의 빈을 관리한다
  • Bean은 인스턴스화된 객체를 의미한다
  • 스프링 컨테이너에 등록된 객체를 Spring Bean 이라고 한다
  • @Bean이 적힌 메서드를 모두 호출해서 반환된 객체를 스프링 컨테이너에 등록한다
  • Bean은 클래스의 등록 정보와 getter/setter 메서드를 포함한다
  • Bean은 컨테이너에 사용되는 설정 메타데이터로 생성된다
  • 설정 메타데이터
    - XML, Java annotation, Java code 로 표현한다
    - 컨테이너의 명령, 인스턴스화, 설정, 조립할 객체 를 정의한다

 1) Bean 접근 방법

  • ApplicationContext 사용하여 bean 정의를 읽고 액세스할 수 있다
// bean을 생성하고 구성한다
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");

// getBean 메서드로 bean 인스턴스를 가져온다
PetStoreService service = context.getBean("cmarket", cmarketService.class);

// bean 인스턴스를 사용한다
List<String> userList = service.getUsernameList();
  • 응용 프로그램 코드에서는 getBean() 메서드로 호출하여 사용하면 안된다

 2) Bean의 정의(BeanDefinition)

  • 스프링은 다양한 설정 형식을 BeanDefinition이라는 추상화 덕분에 지원할 수 있다
  • Bean은 BeanDefinition에 의해 정의되며, BeanDefinition에 따라 활용하는 방법이 달라진다
  • BeanDefinition (빈 설정 메타정보)
    - 속성에 따라 컨테이너가 Bean을 어떻게 생성하고 관리할지를 결정한다
    - @Bean or <bean> 당 각 1개씩 메타 정보가 생성된다
    - Spring은 설정 메타정보를 BeanDefinition 인터페이스를 통해 관리하기 때문에 컨테이너 설정을 XML, Java로 할 수 있다
    - 스프링 컨테이너는 설정 형식이 XML인지 Java 코드인지에 상관없이 BeanDefinition만 알면 된다

※ BeanDefinition

 : https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/config/BeanDefinition.html

 

BeanDefinition (Spring Framework 5.3.21 API)

Return the current bean class name of this bean definition. Note that this does not have to be the actual class name used at runtime, in case of a child definition overriding/inheriting the class name from its parent. Also, this may just be the class that

docs.spring.io

 

참조 링크

▶ 컨테이너 : https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-basics

 

Core Technologies

In the preceding scenario, using @Autowired works well and provides the desired modularity, but determining exactly where the autowired bean definitions are declared is still somewhat ambiguous. For example, as a developer looking at ServiceConfig, how do

docs.spring.io

빈 : https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-definition

 

Core Technologies

In the preceding scenario, using @Autowired works well and provides the desired modularity, but determining exactly where the autowired bean definitions are declared is still somewhat ambiguous. For example, as a developer looking at ServiceConfig, how do

docs.spring.io

 XML 스키마 기반 구성 : https://docs.spring.io/spring-framework/docs/4.2.x/spring-framework-reference/html/xsd-configuration.html

 

40. XML Schema-based configuration

First up is coverage of the util tags. As the name implies, the util tags deal with common, utility configuration issues, such as configuring collections, referencing constants, and suchlike. To use the tags in the util schema, you need to have the followi

docs.spring.io

 config.xml 개요 : https://docs.oracle.com/cd/E13222_01/wls/docs81b/config_xml/overview.html

 

Overview of config.xml

 

docs.oracle.com

▶ XML 관련 문서 google 추천 검색어 : "beans xmlns meaning" 또는 "xml configuration"

'Spring Framework' 카테고리의 다른 글

Spring Framwork - PSA(Portable Service Abstraction)  (0) 2022.06.22
Spring Framework - AOP  (0) 2022.06.22
Spring Framework - IoC / DI - 기초  (0) 2022.06.17
Spring Framework 특징  (0) 2022.06.15
Spring Framework - 정의  (0) 2022.06.15

1. IoC(Inversion of Control) / DI(Dependency Injection)

 1) 반전 제어 (IoC)

  • Library는 애플리케이션 흐름의 주도권이 개발자... Framework은 애플리케이션 흐름의 주도권이 Framework
  • 애플리케이션 흐름의 주도권이 뒤바뀌는 기술
  • Java 콘솔 애플리케이션의 일반적인 제어권을 아래 코드에 따라 순서대로 진행하여 보면...
    - 프로세스의 진행을 위해서 main() 메서드가 있어야 한다
    - main() 메서드가 호출되면 System 클래스를 통해서 static 멤버 변수인 out의 println()을 호출한다
    - 일반적인 애플리케이션 제어 흐름은 개발자가 작성한 코드를 순차적으로 실행하는 것이다
public class Ioc {
    public static void main(String[] args) {
        System.out.println("Hello IoC!");
    }
}
  • Java 웹 애플리케이션에서 IoC가 적용되는 경우 (반전 제어)
    - 별도의 main( ) 메서드가 존재하지 않는다
    - main( ) 메서드와 같이 애플리케이션이 시작되는 지점을 엔트리 포인트(Entry point)라고 한다
    - main( ) 메서드 대신 서블릿 컨테이너 내의 서블릿 로직이 서블릿을 직접 실행 시킨다
    - 서블릿 로직은 service( )  메서드이다
    - 웹 애플리케이션은 서블릿 컨테이너가 서블릿을 제어하므로 제어 흐름은 서블릿 컨테이너에 있다

2. DI(Dependency Injection)

  • Dependency(의존하는, 종속되는) 와 Injection(주입) 의 합성 의미로 보면 의존성 주입의 의미이다
  • IoC 개념을 구체화시킨 내용이다
  • 아래 그림에서 A클래스는 B클래스의 기능을 사용하고 있다
    - A클래스는 B클래스에 의존한다
    - A클래스의 프로그래밍 로직의 완성을 위하여 B클래스에게 의지한다

  • 클래스 다이어그램 작성을 자주 해 보는 것이 도움이 된다

※ 클래스 다이어그램 도구 링크 : https://online.visual-paradigm.com/diagrams/features/

 

Online Drawing Software

Diagram Templates Templates of UML, Flowchart, BPMN, ER diagrams, DFD, Mind Map and more.

online.visual-paradigm.com

 1) 클래스 간 의존 관계 성립

  • 아래 그림을 참조

 2) 의존성 주입

  • 클래스 간 의존 관계에서는 new 키워드를 사용하여 객체를 직접 생성했다
  • 의존성 주입에서는 외부의 객체를 전달받아 생성자의 파라미터로 주입한다

!!! 클래스의 생성자로 객체를 전달 받는 코드가 있다면

▶ 객체를 외부에서 주입 받고 있으며, 의존성 주입이 이루어 지고 있다!!!

 

 3) 의존성 주입의 필요성

  • 일반적으로 Java에서 new 키워드를 사용해서 객체를 생성한다
  • Reflection이라는 기법을 이용해서 Runtime시에 객체를 동적으로 생성할 수 있는 방법도 있다
  • Stub과 같은 코드를 작성할 경우 new 키워드로 작성하면 내부에서 연동되어 작동하는 클래스명을 모두 고쳐야 한다
  • new 키워드를 사용하여 의존 객체를 생성하면 클래스 간의 결합이 강하다고 한다 (Tight Coupling)
  • 강한 결합이 있으면 향후 수정, 보완하기가 어렵다

 4) 의존성 주입의 방향성

  • 의존성 주입은 느슨한 결합이 좋다 (Loose Coupling)
  • 느슨한 결합의 대표적인 방법은 인터페이스(Interface)를 사용하는 것이다
  • A클래스가 B클래스에 의존하고 있을 경우 B클래스의 구현체가 어떻게 생성되었는지는 중요하지 않다
  • A클래스는 의존하고 목적의 결과만 확인할 수 있으면 된다

  • 아래 그림에서 CafeClient 클래스에는 new 키워드로 MenuServiceStub 객체를 생성하고 있다
    - MenuServiceStub 객체는 MenuService 인터페이스에 할당된다
    - 인터페이스 타입의 변수에 구현 객체를 할당하는 것을 업캐스팅(Upcasting)이라고 한다
  • 아래 그림은 업캐스팅에 의한 느슨한 결합을 보여준다

 5) Spring 기반 의존성 주입

  • 기존의 new 키워드를 사용하여 객체를 생성하는 코드를 Spring에서 변경하여 보자

 

※ 참조 링크

▶ 객체지향 설계 : https://ko.wikipedia.org/wiki/SOLID_(%EA%B0%9D%EC%B2%B4_%EC%A7%80%ED%96%A5_%EC%84%A4%EA%B3%84) 

 

SOLID (객체 지향 설계) - 위키백과, 우리 모두의 백과사전

 

ko.wikipedia.org

다이어그램 설계 : https://online.visual-paradigm.com/diagrams/templates/class-diagram/

 

Class Diagram Templates

Class Diagram Templates by Visual Paradigm A class diagram is one of the most widely used UML diagram types. As a type of static structure diagram, class diagram describes the structure of an object-oriented system by showing the system's classes, their at

online.visual-paradigm.com

 

'Spring Framework' 카테고리의 다른 글

Spring Framework - AOP  (0) 2022.06.22
Spring Framework - DI - Spring Container  (0) 2022.06.19
Spring Framework 특징  (0) 2022.06.15
Spring Framework - 정의  (0) 2022.06.15
Spring Framework - 환경 구성  (0) 2022.06.14

1. POJO(Plain Old Java Object)

  • POJO는 IoC/DI, AOP, PSA를 통해서 달성할 수 있다
  • Plain은 사전적 의미로 '있는 그대로'이며, Java로 생성하는 순수한 객체를 의미한다
  • 객체지향의 원리에 충실하게 설계된 오브젝트이다

2. POJO 프로그래밍

  • POJO를 이용해서 프로그래밍 코드를 작성하는 것을 의미한다
  • Spring은 POJO 프로그래밍을 지향하는 Framework이다
  • Spring은 최대한 다른 환경이나 기술에 종속적이지 않도록 하기 위한 POJO 프로그래밍 코드 작성을 위해 세가지 기술(IoC/DI , AOP , PSA)을 지원한다
  • POJO는 몇 가지 기본 규칙을 가지고 있다

   1) 특정 규약에 종속되지 않는다

     - Java 또는 Java spec에 정의되지 않은 기술이나 규약에 간섭받지 않는다

     - Java 언어 외에 필요하지 않은 API에 종속되지 않는다

     ex) EJB Architecture에서는 특정 클래스를 상속받아야 하는 규약이 있다

           - Java의 단일 상속 제한 원칙으로 인하여 해당 클래스에 더 이상의 상속이 불가능하다

           - 결과적으로 추가적인 객체지향적 설계를 적용할 수 없데 된다

           - 아래 코드에서 특정 클래스인 ActionForm 과 Action을 상속받고 있다

            → 상속 목적은 Status라는 기술을 사용하기 위해서이다

             향후 애플리케이션의 목적이나 요구사항이 변경될 경우 Status 기술을 사용하기 위해 상속받은 클래스를 전부

                변경하여야 하는 어려움이 발생한다

public class MessageForm extends ActionForm{ 
	String message;
	public String getMessage() {
		return message;
	}
	public void setMessage(String message) {
		this.message = message;
	}
}
public class MessageAction extends Action{ 
	public ActionForward execute(ActionMapping mapping, ActionForm form,
		HttpServletRequest request, HttpServletResponse response)
        throws Exception {
		MessageForm messageForm = (MessageForm) form;
		messageForm .setMessage("Hello World");
		return mapping.findForward("success");
	}
}

 2) 특정 환경에 종속되지 않는다
  - 특정한 프레임워크에서만 동작하면 안된다

  - 웹 기반의 환경정보나 웹 기술을 담고있는 클래스, 인터페이스를 사용하면 안된다
    웹 컨트롤러와 연결되어 사용할 경우라도 웹을 직접적으로 사용환경으로 제한하면 안된다

    ex) HTTPServletRequest, HTTPServletResponse 등... 

 

 3) 객체지향 원리를 따라야 한다

  - Java로 구현되었어도 객체지향적 설계가 적용되었다고 볼 수 없는 경우가 있다

  - 책임과 역활이 분명하게 구분되어야 한다 (단일책임의 원칙)

    하나의 클래스는 하나의 책임 또는 역활만 존재해야 한다

    상속, 다형성을 활용해서 설계할 수 있다

    조건문만을 활용하여 설계된 오브젝트는 POJO라고 할 수 없다

 

※ 참조 링크

▶ 객체지향 설계

https://ko.wikipedia.org/wiki/SOLID_(%EA%B0%9D%EC%B2%B4_%EC%A7%80%ED%96%A5_%EC%84%A4%EA%B3%84) 

 

SOLID (객체 지향 설계) - 위키백과, 우리 모두의 백과사전

 

ko.wikipedia.org

 

'Spring Framework' 카테고리의 다른 글

Spring Framework - AOP  (0) 2022.06.22
Spring Framework - DI - Spring Container  (0) 2022.06.19
Spring Framework - IoC / DI - 기초  (0) 2022.06.17
Spring Framework - 정의  (0) 2022.06.15
Spring Framework - 환경 구성  (0) 2022.06.14

1. Framework

  • Frame의 대표적인 의미는 ‘뼈대, ‘틀’, ‘구조’ 이다
  • 일상 생활에서 그림이나 액자. 자동차의 뼈대 등을 프레임이라고 부른다
  • Frame은 어던 대상의 큰 틀이나 외형적인 구조를 의미한다
  • 프로그래밍 분야에서의  Frame도 비슷한 의미를 가지고 있다

 2. 프로그램 종류별 Frame

 1) Web의 초기에는 HTML 문서를 구성하는 태그 중에서 frame이라는 태그가 존재했다

  • 아래 예를 보면 frameset과 frame 태그를 이용해서 HTML 문서의 틀만 구성하고 있는 것을 볼 수 있다
<frameset cols="33%,*,33%">
    <frame name="left" src="/left_menu"/>
    <frame name="center" src="/context"/>
    <frame name="right" src="/right_menu"/>
</frameset>

 2) Java에서 Frame과 유사한 의미를 가지는 Framework 가 있다

  • Java에서는 Collection Framework 가 있다
  • Java에서 자주 사용하는 Map이나 Set, List 등의 Collection들은 데이터를 저장하기 위해 널리 알려져 있는 자료구조를 바탕으로 비슷한 유형의 데이터들을 가공 및 처리하기 쉽도록 표준화 된 방법을 제공하는 클래스의 집합이다
  • Java 클래스 유형 중에서 기본적인 뼈대로만 구성되어 있는 것은 추상 메서드만 정의되어 있는 Interface 이다
  • Collection은 Map, Set, List 같은 인터페이스와 그 인터페이스들을 구현한 구현체들의 집합이다

3. 프로그램에서의 Framework 역활

  • 기본적으로 프로그래밍을 하기 위한 틀이나 구조를 제공하므로 생산성이 향상된다
  • 정해진 규약에 따라 작성하므로 애플리케이션을 체계적으로 관리가 가능하다
  • 코드의 재사용성이 높고, 확장성이 좋다
  • 서로 다른 애플리케이션 간의 통신, 데이터 저장소에 데이터를 저장 등... 다양한 기능들을 라이브러리 형태로 제공한다
  • 개발자에게 애플리케이션의 핵심 로직의 개발에 집중할 수 있도록 편의를 제공한다

4. Framework 와 Library

  • Framework 와 Library는 애플리케이션 구현을 위해 필요한 여러가지 기능들을 제공하는 의미에서는 유사하다
  • 애플리케이션에 대한 제어권에 따라 구분할 수 있다

Spring Frame 예) 

@SpringHelloApplication
@RestController
@RequestMapping(path = "/v1/message")
public class SampleApplication {
    @GetMapping
    public String getMessage() {  // (2)
        String message = "hello world";
        return StringUtils.upperCase(message);       
    }

    public static void main(String[] args) {
        SpringApplication.run(SampleApplication.class, args);
    }
}
  • Library
    - StringUtils 클래스는 Apache Commons Lang3 라이브러리의 유틸리티 클래스 중 하나이다
    - StringUtils 클래스의 upperCase() 메서드는 파라미터로 전달된 문자열(message 변수)을 대문자로 변환한다
    - 개발자가 작성한 코드 안에서 필요한 기능을 해당 라이브러리를 호출해서 사용하는 것이 Library 이다
    - 필요한 부분에 개발자가 직접 해당하는 라이브러리를 사용한다
    - Library는 애플리케이션의 주도권이 개발자에게 있다
  • Framework
    - 위의 예) 에서 사용한 애너테이션이나 main() 메서드 내의 SpringApplication.run() 메서드는 Spring Framework에서 지원하는 기능들이며, 라이브러리와는 다르게 코드 상에는 보이지 않는 상당히 많은 일을 한다
    - getMessage() 메서드 내부의 코드처럼 개발자가 메서드 내에 코드를 작성해 두면, Spring Framework에서 개발자가 작성한 코드를 사용해서 애플리케이션의 흐름을 만들어낸다
    - Framework 자체 규약이 있으며, 규약에 맞춰 코드를 작성해야 한다
    -  Framework는 애플리케이션의 주도권이 개발자에게 있다

 

5. Spring Boot

 1) Spring Boot 사용 목적

  • XML 기반의 복잡한 설계 방식을 지양한다
    - 기존에 사용하던 Spring의 복잡한 설정에서 탈피할 수 있다
  • 의존 라이브러리를 자동으로 관리한다
    - Spring Boot의 starter 모듈 자동구성 기능으로 라이브러리의 수동 설정의 불편함을 제거하였다
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-jdbc'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    implementation 'com.h2database:h2'
}

 

라이브러리 자동 설정

  • 애플리케이션 설정을 자동으로 구성한다
     - Spring Boot은 스타터(Starter) 모듈을 통해 설치되는 의존 라이브러리를 기반으로 애플리케이션의 설정을 자동으로 구성한다
implementation 'org.springframework.boot:spring-boot-starter-web'

       - 위와 같은 starter를 작성하면 Spring Boot은 애플리케이션이 웹 애플리케이션이라고 인식하고 웹 애플리케이션을 띄울 서블릿 컨테이너(디폴트: Tomcat) 설정을 자동으로 구성한다

implementation 'org.springframework.boot:spring-boot-starter-jdbc’

       - 위와 같은 starter를 작성하면 Spring Boot은 애플리케이션에 데이터베이스 연결이 필요하다고 인식하고 JDBC 설정을 자동으로 구성한다
       - Spring Boot에서 지원하는 자동 구성으로 인해 애플리케이션에 대한 설정을 직접해야하는 번거로움을 최소화할 수 있다
       - 자동 구성을 활성화 하기 위해서 아래와 같은 애너테이션을 코드에 추가해면 된다

@SpringBootApplication  // Spring Boot에서 자동 구성 설정을 활성화해 준다
public class SampleApplication {
    public static void main(String[] args) {
        SpringApplication.run(SampleApplication.class, args);
    }
}
  • 프로덕션급 애플리케이션의 빌드를 쉽게 할 수 있다
    - Spring Boot을 사용하면 개발한 애플리케이션 구현 코드를 손쉽게 빌드할 수 있다
    - build > bootJar(더블 클릭) 하면 libs > 파일명.jar 와 같이 애플리케이션 실행 파일이 생성된다
    - 직접 빌드 결과물을 War 파일 형태로 WAS(Web Application Server)에 올릴 필요가 없다

※ WAS(Web Application Server)

 - Java 기반의 웹 애플리케이션을 배포하는 일반적인 방식은 개발자가 구현한 애플리케이션 코드를 WAR(Web application ARchive) 파일 형태로 빌드한 후에 WAS(Java에서는 서블릿 컨테이너라고도 한다)라는 서버에 배포해서 해당 애플리케이션을 실행하는 것이다

 - Java에서 사용되는 대표적인 WAS에는 Tomcat이 있다

 - WAS는 구현된 코드를 빌드해서 나온 결과물을 실제 웹 애플리케이션으로 실행되게 해주는 서버이다

 

  • 내장된 WAS를 통해 배포를 쉽게 할 수 있다
     - Spring Boot은 Apache Tomcat이라는 WAS를 내장하고 있기때문에 별도의 WAS를 구축할 필요가 없다
     - Spring Boot을 통해 빌드된 jar 파일을 이용해서 아래와 같은 명령어를 cmd에서 입력 해주면 서비스 가능한 웹 애플리케이션을 실행 할 수 있다
java -jar sample-app.jar

 

 

 

 

※ 참조 링크

▶ 자바 서블릿 :https://ko.wikipedia.org/wiki/%EC%9E%90%EB%B0%94_%EC%84%9C%EB%B8%94%EB%A6%BF

 

자바 서블릿 - 위키백과, 우리 모두의 백과사전

서블릿은 여기로 연결됩니다. 다른 뜻에 대해서는 서블렛 문서를 참고하십시오. 자바 서블릿(Java Servlet)은 자바를 사용하여 웹페이지를 동적으로 생성하는 서버측 프로그램 혹은 그 사양을 말하

ko.wikipedia.org

서블릿 컨테이너 : https://ko.wikipedia.org/wiki/%EC%9B%B9_%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88

 

웹 컨테이너 - 위키백과, 우리 모두의 백과사전

웹 컨테이너(web container, 또는 서블릿 컨테이너)는 웹 서버의 컴포넌트 중 하나로 자바 서블릿과 상호작용한다. 웹 컨테이너는 서블릿의 생명주기를 관리하고, URL과 특정 서블릿을 맵핑하며 URL

ko.wikipedia.org

아파치 톰캣 : https://ko.wikipedia.org/wiki/%EC%95%84%ED%8C%8C%EC%B9%98_%ED%86%B0%EC%BA%A3

 

아파치 톰캣 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전.

ko.wikipedia.org

https://tomcat.apache.org/

 

Apache Tomcat® - Welcome!

The Apache Tomcat® software is an open source implementation of the Jakarta Servlet, Jakarta Server Pages, Jakarta Expression Language, Jakarta WebSocket, Jakarta Annotations and Jakarta Authentication specifications. These specifications are part of the

tomcat.apache.org

 

'Spring Framework' 카테고리의 다른 글

Spring Framework - AOP  (0) 2022.06.22
Spring Framework - DI - Spring Container  (0) 2022.06.19
Spring Framework - IoC / DI - 기초  (0) 2022.06.17
Spring Framework 특징  (0) 2022.06.15
Spring Framework - 환경 구성  (0) 2022.06.14

1. Spring Framework 실습환경 구성

  • JDK-11 설치되어 있어야 한다
  • JAVA_HOME 설정되어 있어야 한다
  • IntelliJ Community Edition이 설치되어 있어야 한다

2. Spring Boot 기반 샘플 프로젝트 생성

  • Spring Initializr 기능을 이용하여 IntelliJ Community Editiond에서 프로젝트 생성한다
  • https://start.spring.io/ 스프링 부트 기반의 프로젝트를 만들어 주는 사이트로 이동한다

  • 아래와 같이 설정한다
    - Project 항목은 최근에 Gradle 을 많이 사용한다
    메이븐(Maven)과 그래들(Gradle)의 개념 및 비교 — 슬기로운 개발생활😃 (tistory.com)
    - Spring Boot 항목은 자동 설정된 상태 그대로 사용한다
    - SNAPSHOT는 만들고 있는 버젼을 의미한다
    - 3.0.0(M3)는 기능 개발은 되었지만 출시 소프트웨어가 결정되지 않았음을 의미한다
    - Project Metadata 항목은 사용자에 맞게 변경해 준다
      → Group : 기업이나 도메인 명을 주로 작성한다
      → Artifact : 결과물의 이름을 작성한다(프로젝트명)
      → Name : Artifact 명으로 자동 작성된다
      → Description
      → Package name : Group + Artifact 결합으로 자동생성
      → Packaging
         : 일반적으로 Spring Boot 애플리케이션은 WAS를 내장하고
           있는 Jar 파일 형태로 배포해서 실행한다
         : 개발한 코드들을 빌드해서 하나의 빌드 결과물로 만들어
           낸다는 의미이다        
      → Java : 컴퓨터에 설치된 버젼을 선택한다

 

  •  우측의 ADD DEPRNDENCIES를 클릭하여 아래의 모듈을 선택한다
    - 어떤 스프링 기반의 라이브러리를 사용할 것인지를 결정한다
    - Lombok
     : @Getter, @Setter 등의 애노테이션을 통해 자주 사용하는 Java 코드를 자동으로 구성해주는 라이브러리이다
    - Spring Web
  • 하단의 GENERATE를 클릭하여 샘플 프로젝트를 다운한다

  • 별도의 project 폴더를 만들고 다운받은 파일을 압축해제 한다

 

3. 탬플릿 프로젝트 열기

  • IntelliJ를 열고 다운로드 한 폴더를 open 한다

  • 신뢰할 수 있는 파일인지 묻는다면 ok하고 진행한다
  • 템플릿 프로젝트를 오픈하면 Gradle 빌드 툴이 자동으로 빌드 작업을 한다

  • 빌드가 진행됨에 따라 External Libraries 하위에 의존 라이브러리들이 생성된다

  • External Libraries 하위에 의존 라이브러리들이 보이지 않을 경우 아래와 같이 진행하여 라이브러리를 생성한다
    - 우측의 메뉴에서 Gradle 탭을 눌러서 오픈한다

- 프로젝트 이름에서 마우스 오른쪽 버튼을 눌러 컨텍스트 메뉴를 오픈한다
- Reload Gradle Project를 클릭한다
- External Libraries 하위에 의존 라이브러리가 있는지 확인한다
- 그래도 나타나지 않으면 IntelliJ를 종료 후 다시 진행해 본다

 

 

 

 

 

 

 

4. Lombok 설정

  • IntelliJ 상단의 File 메뉴에서 Setting 을 오픈한다

  • [Build, Execution, Deployment] > [Compiler] > [Annotation Processors] 메뉴를 선택한다
  • [Enable annotation processing] 체크 박스에 체크한 후, [Apply] > [OK] 버튼을 차례로 클릭한다

  • [Enable annotation processing] 체크 박스에 체크를 해야 Lombok을 정상적으로 사용할 수 있다

 

5. Spring Boot Application 동작 확인

  • IntelliJ에서 Section2Week3Application.java 파일을 더블 클릭해서 오픈한다

  • 파일을 실행시킨다
  • 실행 라인에 .Section2Week3Application  : Started Section2Week3Application in 2.013 seconds (JVM running for 2.383) 문구가 출력되면 정상 실행된 것이다 

  • 죄측의 실행아이콘이 계속 돌고 있는 것은 애플리케이션 자체가 내장 WAS에서 실행이 되고 있음을 의미하는 지극히 정상적인 동작이다
  • 위 화면의 아래에서 4번째 줄에 출력된 port 번호를 확인한 후 Crome 창을 열고 localhost:8080 을 입력한다
    - 아래와 같이 에러가 뜨면 성공이다
    - 현재 아무것도 작성한 내용이 없으므로 에러가 뜨는 것이 정상이다

  • IntelliJ 에서 실행을 중단한 후 다시  localhost:8080 화면을 새로고침 한다
    - 아래와 같이 출력되면 정상이다
    - 스프링부트 파일을 실행 중단하였으므로 8080 port에 연결할 수 없는 것이다

  • 간단히 출력화면을 보고 싶다면 다음과 같이 작성 후 실행해 본다
    - [src] > [main] > [resources] > [static] > 마우스 우클릭 > 새로만들기 > HTML > 이름을 hello 로 입력 후 Enter
    - 아래와 같이 HTML 화면이 나오면 body에 아래와 같이 작성한다
<body>
    <h1>Hello SpringBoot World!!!</h1>
</body>

  • main > java 파일을 재실행 한 후 새로 작성한 HTML파일이 실행되도록 Crome에서 localhost:8080/hello.html 을 입력한다

실행 화면

'Spring Framework' 카테고리의 다른 글

Spring Framework - AOP  (0) 2022.06.22
Spring Framework - DI - Spring Container  (0) 2022.06.19
Spring Framework - IoC / DI - 기초  (0) 2022.06.17
Spring Framework 특징  (0) 2022.06.15
Spring Framework - 정의  (0) 2022.06.15

1. 웹 환경에서 쿼리문을 이용하여 ERD 제작하기

 1) 주어진 자료에 맞는 테이블을 쿼리문으로 구성하고

 2) 웹사이트를 통해 작성한 쿼리문을 ERD로 제작하기

 

2. ERD(Entity-Relationship Diagram)

  • 데이터의 "구조" 및 그에 수반한 제약 조건들은 다양한 기법에 의해 설계될 수 있는데 그 중 하나가 개체-관계 모델링(Entity-Relationship Modelling)이며, ERM이라고 한다.
  • ERM 프로세스의 산출물을 ERD(Entity-Relationship Diagram)라고 한다
  • ERD는 개념적 데이터 모델 혹은 시맨틱 데이터 모델의 한 타입이다

 

 

CREATE TABLE user (
  id INT PRIMARY KEY AUTO_INCREMENT,
  name varchar(255) NOT null,
  e_mail varchar(255) NOT null,
  role_id INT,
  FOREIGN KEY(role_id) REFERENCES role(id) ON DELETE CASCADE
);

CREATE TABLE content (
  id INT PRIMARY KEY AUTO_INCREMENT,
  title varchar(255) NOT null,
  body varchar(255) NOT null,
  created_at timestamp DEFAULT current_timestamp,
  user_id int,
  FOREIGN KEY(user_id) REFERENCES user(id) ON DELETE CASCADE
);

CREATE TABLE role (
  id INT PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(255) NOT null
);

CREATE TABLE catagory (
  id INT PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(255) NOT null
);

CREATE TABLE content_catagory (
  id INT PRIMARY KEY AUTO_INCREMENT,
  content_id INT NOT null,
  catagory_id INT NOT null,  
  FOREIGN KEY(content_id) REFERENCES content(id) ON DELETE CASCADE,
  FOREIGN KEY(catagory_id) REFERENCES catagory(id) ON DELETE CASCADE
);

 

※ 참조 링크

▶ ERD : 개체-관계 모델 - 위키백과, 우리 모두의 백과사전 (wikipedia.org)

 

개체-관계 모델 - 위키백과, 우리 모두의 백과사전

데이터 모델링 분야에서 개체-관계 모델이란 구조화된 데이터에 대한 일련의 표현이다. 서로 관계된 두 개의 엔티티 "구조"화된 데이터를 저장하기 위해 데이터베이스를 쓴다. 이 데이터의 "구

ko.wikipedia.org

 

1. 스키마(schema)

  • 데이터베이스에서 데이터가 구성되는 방식과 서로 다른 엔티티 간의 관계에 대한 설명이다
  • 데이터베이스의 청사진과 같다
  • 데이터베이스의 열의 집합체 = 테이블 이다
  • 데이터베이스의 행 = 레코드 이다
  • 행과 열의 필드 공간은 크기를 지정해야 한다

2. 관계형 데이터베이스(relation database)

  • 구조화된 데이터는 하나의 테이블로 표현할 수 있다
  • 사전에 정의된 테이블을 relation 이라고 한다
  • 테이블을 사용하는 데이터베이스를 관계형 데이터베이스(relation database)라고 한다

 1) 용어 정의

  • 데이터(data) : 각 항목에 저장되는 값이다
  • 테이블(table) : relation이라고도 하며, 사전에 정의된 열의 데이터 타입에 맞춰 데이터가 행으로 축적된다
  • 칼럼(column) : 테이블에 있는 한 개의 열을 말한다
  • 레코드(record) : tuple이라고도 하며, 테이블에 있는 한 개의 행을 말한다 
  • 키(key) : 테이블의 각 레코드를 구분할 수 있는 값이다
    - 각각의 레코드는 고유한 값을 가진다
    - 기본키(primary key)와 외래키(foreign key)가 있다
  • 기본키(primary key) : 테이블의 기본 값이며, 변하지않는 고유값이다
  • 외래키(foreign key) : 어떤 값을 참조하고 있는 값을 지칭한다

 2) 관계 종류

  • 1 : 1 관계 (One-to-one relationship)
    - 한 개의 레코드가 다른 테이블의 레코드 한 개와 연결된 관계이다
    - 1 : 1 관계는 직접 저장하는 것이 쉬울 수 있으므로 자주 사용하지 않는다

  • 1 : N 관계 (One-to-many relationship)
    - 한 개의 레코드가 다른 테이블의 여러 개의 레코드와 연결된 관계이다

 

  • N : N 관계 (many to manyrelationship)
    - 여러 개의 레코드가 다른 테이블의 여러 개의 레코드와 연결된 관계이다
    - 아래와 같은 테이블 구조에서는 관계를 표현하기가 복잡하다

     - N : N 관계를 쉽게 표현하기 위하여 JOIN 테이블을 삽입한다 
     - JOIN 테이블을 생성하더라도  JOIN 테이블의 기본KEY는 반드시 있어야 한다

  • 자기참조 관계(Self Referencing Relationship)
    - 한 개의 테이블 내에서 연결되는 레코드를 가지는 관계이다

 

※ 참조링크

▶ DBML : https://www.dbml.org/docs/#project-definition

 

DBML - Full Syntax Docs | DBML

DBML - Full Syntax Docs DBML (database markup language) is a simple, readable DSL language designed to define database structures. This page outlines the full syntax documentations of DBML. Take a look at an example below: Table users { id integer username

www.dbml.org

 

1. SQL문을 사용하기 위하여 RDBMS(relational database management system) 중에서 MySQL 설치한다

2. 설치 순서

 1) https://www.mysql.com/ 접속

 2) 상단의 DOWNLOADS 클릭

 3) 가장 아래에 MySQL Community (GPL) Downloads » 클릭

 4) MySQL Community Server 클릭

 5) Go to Download Page > 클릭

 6) 아래에 있는 439.6M Download 클릭

 7) 하단의 No thanks, just start my download. 클릭 (회원 가입 후 다운로드 진행해도 된다)

 8) 다운이 완료되면 파일이 실행된다

 9) 순서대로 설치한다 (프로그램 선택 화면이 사라지고 전체가 설치된다)...시간이 조금 걸린다...

 10) 로그인 암호를 입력하고 next 클릭

 11) Next 클릭

 12) Execute 클릭

 13) 구성을 확인 중....완료되면 Finish 클릭

 14) Next 클릭

 15) Finish 클릭

 16) Next 클릭

 17) 암호 입력 후 Check 클릭하면 Status가 Connection으로 변경된다...Next 클릭

 18) Excute 클릭

 19) 완료되면 Finish 클릭

 20) Next 클릭

 21) Finish 클릭하여 설치 종료

 22) MySQL이 실행된다

 

3. MySQL 접속

 1) MySQL을 실행한다

 2) 암호를 입력 후 Enter...로그인 되어 MySQL이 실행되었다

 

※ 참조 링크

▶ MySQL 홈페이지 : https://www.mysql.com/products/workbench/

 

MySQL :: MySQL Workbench

MySQL Workbench is a unified visual tool for database architects, developers, and DBAs. MySQL Workbench provides data modeling, SQL development, and comprehensive administration tools for server configuration, user administration, backup, and much more. My

www.mysql.com

▶ 테이블플러스 : https://tableplus.com/

 

TablePlus | Modern, Native Tool for Database Management.

Modern, native client with intuitive GUI tools to create, access, query & edit multiple relational databases: MySQL, PostgreSQL, SQLite, Microsoft SQL Server, Amazon Redshift, MariaDB, CockroachDB, Vertica, Cassandra, and Redis.

tableplus.com

 

▶ DBeaver : https://dbeaver.io/download/

 

Download | DBeaver Community

Download Tested and verified for MS Windows, Linux and Mac OS X. Install: Windows installer – run installer executable. It will automatically upgrade version (if needed). MacOS DMG – just run it and drag-n-drop DBeaver into Applications. Debian package

dbeaver.io

 

▶ DataGrip : https://www.jetbrains.com/datagrip/

 

DataGrip: The Cross-Platform IDE for Databases & SQL by JetBrains

A powerful IDE from JetBrains for SQL on macOS, Windows, and Linux.

www.jetbrains.com

 

1. 트랜잭션(Transaction)

  • 여러 개의 작업을 하나로 묶은 실행 유닛이다
  • 하나로 묶여 있는 작업 중 한 개라도 실패하면 유닛 전체가 실패한 것으로 판단한다
  • 트랜젝션은 '성공' 과 '실패' 두 개의 결과만 존재한다

2. ACID(Atomicity Consistency Isolation Durability)

  • 데이터베이스에서 트랜잭션이 발생할 경우 안정성을 보장할 수 있는 성질이다

 1) 원자성(Atomicity)

  • 하나의 트랜잭션에 속해있는 모든 작업이 전부 성공하거나 전부 실패해서 결과를 예측할 수 있어야 한다
  • 트랜젝션의 여러 작업이 부분적으로 실행된다면, 업데이트가 일어났지만 누가 업데이트했는지 모르거나, 업데이트 날짜가 누락되는 등 데이터가 오염될 수 있다
  • A의 작업은 성공했지만 B의 작업이 실패했다면 트랜잭션은 실패로 결론내어 데이터를 보호해야 한다

 2) 일관성(Consistency)

  • 데이터베이스의 상태가 일관되어야 한다는 성질이다
  • 하나의 트랜잭션 이전과 이후에 데이터베이스의 상태는 이전과 같이 유효해야 한다
  • 트랜잭션이 일어난 이후의 데이터베이스는 데이터베이스의 제약이나 규칙을 만족해야 한다
  • 데이터베이스의 제약조건을 만족하지 않으면 실패로 간주한다

 3) 고립성(Isolation), 격리성

  • 모든 트랜잭션은 다른 트랜잭션으로부터 독립되어야 한다
  • 동시에 여러 개의 트랜잭션들이 수행될 때, 각각의 트랜젝션은 고립되어 있어 연속으로 실행된 것과 동일한 결과를 나타낸다
  • 각각의 트랜잭션은 독립적으로 서로의 작업을 확인하거나 영향을 줄 수 없으며, 영향을 줄 경우 실패로 간주한다
  • 트랜잭션이 동시에 실행될 때와 연속으로 실행될 때의 데이터베이스 상태가 동일해야 한다

 4) 지속성(Durability)

  • 하나의 트랜잭션이 성공적으로 수행되었다면, 해당 트랜잭션에 대한 로그가 남아야 한다
  • 런타임 오류나 시스템 오류가 발생하더라도, 해당 기록은 영구적이어야 한다
  • 로그로 기록하기 전에 오류로 인하여 종료가 된다면 실패로 간주하여 작업 이전의 상태로 돌아가야 한다

1. SQL(Structured Query Language)

  • 구조화된 Query 언어이다
  • 데이터베이스를 위한 프로그래밍 언어이다
  • 데이터베이스에 query를 보내서 원하는 데이터를 가져오거나 삽입할 수 있다
  • MySQL, Oracle, SQLite, PostgreSQL 등 다양한 데이터베이스에서 SQL 구문을 사용할 수 있다
  • 데이터가 구조화된(structured) 테이블을 사용하는 고정된 데이터베이스 구조에서 활용할 수 있다

 1) Query

  • '질의하다'의 의미를 가진다
  • 검색창에 입력하는 검색어도 Query의 일종이다
  • 저장되어 있는 정보를 필터하기 위한 질의문이다
더보기

▶ In-memory
 - 프로그램을 종료하면 데이터가 사라진다
 - 예기치 못한 상황으로부터 데이터를 보호할 수 없다

 - 데이터의 수명이 프로그램의 수명에 의존하게 된다

 File I/O

 - 파일을 읽는 방식으로 작동하는 형태를 의미한다

 - 원하는 데이터를 가져오기 위하여 전체 데이터를 가져온 후 필터링을 해야 한다

 - 파일의 크기가 커질수록 비효율적이다

 - 여러개의 파일을 동시에 작업할 경우나 복잡하고 데이터 양이 많은 경우에는 작업이 어렵다

 

 Database

 - 필터링 기능 외에 File I/O로 구현하기 어려운 여러가지 관리 기능을 가지고 있는 데이터 특화 서버이다

 - 관계형 데이터베이스에서는 하나의 CSV 파일이나 엑셀 시트를 한 개의 테이블로 저장할 수 있다

 - 한번에 여러 개의 테이블을 가질 수 있기 때문에 SQL 을 활용해 데이터를 불러오기 쉽다

 

2. NoSQL(No Structured Query Language)

  • 데이터의 구조가 고정되어 있지 않은 데이터베이스 구조에서 활용할 수 있다
  • 테이블을 사용하지 않고 데이터를 다른 형태로 저장한다
  • MongoDB 와 같은 문서 지향 데이터베이스에 사용한다

3. 기본 Query 명령어

Select 데이터 테이블을 선택한다 // SELECT 테이블필드이름1, 테이블필드이름2
   FROM 테이블_이름;
Where    
And, Or, Not    
Order By    
Insert Into 데이터를 삽입한다  
Null Values    
Update 데이터를 변경, 수정 한다  
Delete    
Count    
Like    
Wildcards    
Aliases    
Joins Inner Join
Left Join
Right Join
 
Group By    

 

4. Database 관련 용어

  • SQL Create DB
  • SQL Drop DB
  • SQL Create Table
  • SQL Drop Table
  • SQL Alter Table
  • SQL Not Null
  • SQL Unique
  • SQL Primary Key
  • SQL Foreign Key
  • SQL Default
  • SQL Auto Increment
  • SQL Dates

5. Database 관련 명령어

  • 데이터베이스 생성
    // CREATE DATABASE 데이터베이스_이름 ;
  • 데이터베이스 사용 : 데이터베이스를 이용하여 테이블 생성, 수정, 삭제 등의 작업을 하기 전에 사용 명령을 전달한다
    // USE 데이터베이스_이름 ;
  • 테이블 생성
    // CREATE TABLE 테이블_이름
더보기
ex) 다음의 조건을 가지는 user 테이블 생성

 

필드 이름 필드 타입 그 외 속성
id 숫자 Primary key이면서 자동 증가되도록 설정
name 문자열(최대 255개 문자)  
email 문자열(최대 255개 문자)  

1 CREATE TABLE user (
2      id int PRIMARY KEY AUTO_INCREMENT,
3      name varchar(255),
4      email varchar(255),
5  );

  • 테이블 정보 확인
    // DESCRIBE 테이블명 ;
  • 데이터베이스 삭제
    // DROP DATABASE 데이터베이스_이름
  • 테이블 삭제
    // DROP TABLE 테이블_이름
  • 데이터베이스 전체 백업
    // BACKUP DATABASE 데이터베이스_이름
       TO DISK = 백업할 디렉토리_이름
  • 기존 테이블의 열 추가, 삭제, 수정
    더보기
    1) 테이블에 열 추가
    // ALTER TABLE 테이블_이름
       ADD 열_이름 데이터_형식

    2) 테이블에 열 삭제
    // ALTER TABLE 테이블_이름
       DROP COLUMN 열_이름 

    3) 테이블의 열 변경
    // ALTER TABLE 테이블_이름
       ALTER COLUMN 열_이름 데이터_형식
  • 테이블 데이터 삭제
    //TRUNCATE TABLE 테이블_이름

6. SQL 명령어

SELECT - 데이터베이스에서 데이터를 선택할 때 사용
// SELECT 'hello world'    : 일반 문자열
// SELECT 2                  : 숫자
// SELECT 10+5             : 일반 연산
// SELECT 테이블필드이름1, 테이블필드이름2
   FROM 테이블_이름
FROM - 테이블과 관련한 작업 시 반드시 입력해야 한다
- FROM 뒤에는 결과를 도출할 데이터베이스 테이블을 명시한다
1) 특정 특성을 테이블에서 사용
   // 1 SELECT 특성_1
      2 FROM 테이블_이름

2) 여러 개의 특성을 테이블에서 사용
   // 1 SELECT 특성_1, 특성_2
      2 FROM 테이블_이름

3) 테이블의 모든 특성을 사용
   (* 는 wildcard로 전체를 선택할 때 사용된다)

   // 1 SELECT *
      2 FROM 테이블_이름
WHERE - 필터 역활을 하는 쿼리문이다
- 선택적으로 사용할 수 있다
1) 특정 값과 동일한 데이터 찾기
   // 1 SELECT 특성_1, 특성_2
      2 FROM 테이블_이름
      3 WHERE 특성_1 = "특정 값"

2) 특정 값을 제외한 값을 찾기
   // 1 SELECT 특성_1, 특성_2
      2 FROM 테이블_이름
      3 WHERE 특성_2 < > "특정 값"

3) 특정 값보가 크거나 작은 값을 필터하는 경우
   // 1 SELECT 특성_1, 특성_2
      2 FROM 테이블_이름
      3 WHERE 특성_1 < "특정 값"

   // 1 SELECT 특성_1, 특성_2
      2 FROM 테이블_이름
      3 WHERE 특성_1 > "특정 값"

4) 특정 값을 포함하는 이상, 이하 값을 필터하는 경우
   // 1 SELECT 특성_1, 특성_2
      2 FROM 테이블_이름
      3 WHERE 특성_1 < = "특정 값"

   // 1 SELECT 특성_1, 특성_2
      2 FROM 테이블_이름
      3 WHERE 특성_1 > = "특정 값"

5) 리스트에 있는 값과 일치하는 데이터를 필터하는 경우
   // 1 SELECT 특성_1, 특성_2
      2 FROM 테이블_이름
      3 WHERE 특성_1 IN ("특정값_1", "특정값_2")

6) 리스트에 있는 값과 유사한 값을 필터하는 경우
   // 1 SELECT 특성_1, 특성_2
      2 FROM 테이블_이름
      3 WHERE 특성_1 LIKE "%특정 ANSWKDUF%"

7) 값이 없는 경우를 찾기
   // 1 SELECT *
      2 FROM 테이블_이름
      3 WHERE 특성_1 IS NULL

8) 값이 없는 경우를 제외하고 찾기
   // 1 SELECT *
      2 FROM 테이블_이름
      3 WHERE 특성_1 IS NOT NULL
ORDER BY - 돌려받는 데이터 결과의 정렬 기준을 결정한다
- 선택적으로 사용할 수 있다 
1) 오름차순 정렬
   // 1 SELECT *
      2 FROM 테이블_이름
      3 ORDER BY 특성_1

2) 내림차순 정렬
   // 1 SELECT *
      2 FROM 테이블_이름
      3 ORDER BY 특성_1 DESC
LIMIT - 결과로 출력할 데이터의 갯수를 지정한다
- 선택적으로 사용할 수 있다
- 쿼리문에서 사용할 경우 가장 마지막에 추가한다
// 1 SELECT *
   2 FROM 테이블_이름
   3 LIMIT 200
DISTINCT - 유니크한 값을 도출할 경우 사용한다
- SELECT와 함께 사용한다
1) 특성_1을 기준으로 유니크한 값을 선택
   // 1 SELECT DISTINCT 특성_1 
      2 FROM 테이블_이름

2) 특성_1, 특성_2, 특성_3의 유니크한 값을 조합하여 선택
   // 1 SELECT
      2     DISTINCT
      3          특성_1
      4          , 특성_2
      5          , 특성_3
      6     FROM 테이블_이름
INNER JOIN - INNER JOIN 또는 JOIN 으로 실행할 수 있다
- 두 개 이상의 테이블에서 일치하는 레코드 선택
SELECT column_name(s)
FROM table1
INNER JOIN table2
ON table1.column_name = table2.column_name;
OUTER JOIN - 모든 레코드 선택 : FULL JOIN

- 왼쪽 테이블의 모든 레코드와 일치하는 레코드 선택 : LEFT JOIN

-오른쪽 테이블의 모든 레코드와 일치하는 레코드 선택 : RIGHT JOIN
SELECT column_name(s)
FROM table1
FULL OUTER JOIN table2
ON table1.column_name = table2.column_name
WHERE condition;

SELECT
 column_name(s)
FROM table1
LEFT JOIN table2
ON table1.column_name = table2.column_name;

SELECT column_name(s)
FROM table1
RIGHT JOIN table2
ON table1.column_name = table2.column_name;
INSERT INTO - 테이블에 새 레코드를 삽입한다 // 1 INSERT INTO 테이블_이름(열1, 열2, 열3,...)
   2 VALUES (값1, 값2, 값3,...)
UPDATE - 테이블의 기존 레코드를 수정한다 // 1 UPDATE 테이블_이름
   2 SET 열1 = 값1, 열2 = 값2, 열3 = 값3,...
   3 WHERE 수정_대상명
DELETE - 테이블의 기존 레코드를 삭제한다 // 1 DELETE FROM 테이블_이름
   2 WHERE 수정_대상명
MIN( ) / MAX( ) - 선택한 열의 가장 작거나 큰 값을 반환한다 // 1 SELECT MIN(열_이름) AS 조건
   2 FROM 테이블_이름
   3 WHERE 수정_대상명
// 1 SELECT MAX(열_이름) AS 조건
   2 FROM 테이블_이름
   3 WHERE 수정_대상명
COUNT( ) - 지정된 기준과 일치하는 행 수를 반환한다 SELECT COUNT(column_name)
FROM table_name
WHERE condition;
AVG( ) 숫자 열의 평균 값을 반환한다 SELECT AVG(column_name)
FROM table_name
WHERE condition;
SUM( ) 숫자 열의 합계를 반환한다 SELECT SUM(column_name)
FROM table_name
WHERE condition;
LIKE - 열에서 지정된 패턴을 검색한다
- AND, OR 연산자와 사용하여 여러 조건을 결합할 수 있다 
- %, _ 를 사용하여 PATTEN을 조합할 수 있다
SELECT column1, column2, ...
FROM table_name
WHERE columnN LIKE pattern;
WILDCARD - 와일드카드 문자는 연산자와 결합하여 다양하게 사용된다



- LIKE 사용 예시


IN WHERE문에 여러 값을 지정할 수 있다 SELECT column_name(s)
FROM table_name
WHERE column_name IN (value1, value2, ...);
BETWEEN - 주어진 범위 내에서 값을 선택한다
- 시작과 종료 값이 포함된다
SELECT column_name(s)
FROM table_name
WHERE column_name BETWEEN value1 AND value2;
AS - 테이블이나 열에 임시 이름을 지정한다
- 임시 이름은 쿼리가 실행되는 동안에만 존재한다
1) 열
SELECT
 column_name AS alias_name
FROM table_name;

2) 테이블
SELECT column_name(s)
FROM table_name AS alias_name;
UNION - 두개 이상의 테이블에서 공통된 값을 선택한다
- 고유한 값만 반환된다
SELECT column_name(s) FROM table1
UNION
SELECT column_name(s) FROM table2;
UNION ALL - 두개 이상의 테이블에서 공통된 값을 선택한다
- 중복된 값을 포함하여 반환된다
SELECT column_name(s) FROM table1
UNION ALL
SELECT column_name(s) FROM table2;
GROUP BY 1) 각 Country의 CustomerID의 개수
SELECT
 COUNT(CustomerID), Country
FROM Customers
GROUP BY Country;

2) 정렬된 각 Country의 CustomerID의 개수
SELECT COUNT(CustomerID), Country
FROM Customers
GROUP BY Country
ORDER BY COUNT(CustomerID) DESC;

3) 주문 수를 나열
SELECT Shippers.ShipperName, COUNT(Orders.OrderID) AS NumberOfOrders FROM Orders
LEFT JOIN Shippers ON Orders.ShipperID = Shippers.ShipperID
GROUP BY ShipperName;
SELECT column_name(s)
FROM table_name
WHERE condition
GROUP BY column_name(s)
ORDER BY column_name(s);
HAVING GROUP BY로 조회한 결과를 필터링 한다  
  • ELECT 실행 순서
    - 데이터를 조회하는 SELECT 문은 정해진 순서대로 동작한다
    - FROM - WHERE - GROUP BY - HAVING - SELECT - ORDER BY
    - 예시로 확인해 본다
SELECT CustomerId, AVG(Total)
FROM invoices
WHERE CustomerId >= 10
GROUP BY CustomerId
HAVING SUM(Total) >= 30
ORDER BY 2

 

7. SQL 제약조건

  • NOT NULL - 컬럼이 NULL 값을 가질 수 없도록 보장
  • UNIQUE - 열의 모든 값이 서로 다른지 확인
  • PRIMARY KEY - NOT NULL와 의 조합 UNIQUE. 테이블의 각 행을 고유하게 식별
  • FOREIGN KEY - 테이블 간의 링크를 파괴하는 작업 방지
  • CHECK - 컬럼의 값이 특정 조건을 만족하는지 확인
  • DEFAULT - 값이 지정되지 않은 경우 열의 기본값을 설정합니다.
  • CREATE INDEX - 데이터베이스에서 데이터를 매우 빠르게 생성하고 검색하는 데 사용

 

※ 참조 링크

▶ SQL 명령어 : https://www.w3schools.com/sql/default.asp

 

SQL Tutorial

W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.

www.w3schools.com

SQL 연습문제 :  https://www.w3schools.com/sql/exercise.asp?filename=exercise_select1 

 

W3Schools SQL Exercise

I completed all the SQL exercises on w3schools.com

www.w3schools.com

 

1. HTTP(HyperText Transfer Protocol)

  • HTML과 같은 문서를 전송하기 위한 Application Layer 프로토콜이다
  • HTTP는 웹 브라우저와 웹 서버의 소통을 위해 디자인되었다
  • 전통적인 클라이언트-서버 모델에서 클라이언트가 HTTP messages 양식에 맞춰 요청을 보내면, 서버도 HTTP messages 양식에 맞춰 응답한다
  • HTTP는 특정 상태를 유지하지 않는 특징이 있다 (무상태성(Stateless))

 

2. HTTP message

 1) 개요

  • 클라이언트와 서버 사이에서 데이터가 교환되는 방식이다
  • HTTP messages에는 요청(Requests) 응답(Responses) 의 두 가지 유형이 있다
  • HTTP messages는 몇 줄의 텍스트 정보로 구성된다
  • 개발자가 직접 작성하지 않아도 구성 파일, API, 기타 인터페이스에서 HTTP messages를 자동으로 완성한다
  • HTTP 메시지의 시작 줄과 HTTP 헤더를 묶어서 요청 헤드(head)라고 한다
  • HTTP 메시지의 페이로드는 본문(body)이라고 한다

 2) 구성

  • start line
    - 요청이나 응답의 상태를 나타내며, 항상 첫 번째 줄에 위치한다
    - 응답에서는 status line이라고 한다
  • HTTP headers
    - 요청을 지정하거나, 메시지에 포함된 본문을 설명하는 헤더의 집합이다
  • empty line
    - 요청에 대한 모든 메타 정보가 전송되었음을 알리고, 헤더와 본문을 구분하는 빈 줄을 삽입한다
  • body
    - 요청과 관련된 데이터나 응답과 관련된 데이터 또는 문서를 포함하며, 요청과 응답의 유형에 따라 선택적으로 사용한다

 

3. 요청(Requests)

 1) Start line

  • 클라이언트가 서버에 보내는 메시지이다
  • 세가지 요소를 가지고 있다
  • 수행할 작업(GET, PUT, POST 등)이나 방식(HEAD or OPTIONS)을 설명하는 HTTP method를 나타낸다
    - GET method는 리소스를 받아 온다
    - POST method는 데이터를 서버로 전송한다
  • 요청 대상(일반적으로 URL이나 URI) 또는 프로토콜, 포트, 도메인의 절대 경로는 요청 컨텍스트(context)에 작성된다
  • 요청 형식은 HTTP method 마다 다르다
    - origin 형식
     : ?와 쿼리 문자열이 붙는 절대 경로이다
     : POST, GET, HEAD, OPTIONS 등의 method와 함께 사용한다
     : POST / HTTP 1.1GET /background.png HTTP/1.0HEAD /test.html?query=alibaba HTTP/1.1OPTIONS /anypage.html HTTP/1.0

    - absolute 형식
     : 완전한 URL 형식이다
     : 프록시에 연결하는 경우 대부분 GET method와 함께 사용한다
     : GET http://developer.mozilla.org/en-US/docs/Web/HTTP/Messages HTTP/1.1

    - authority 형식
     : 도메인 이름과 포트 번호로 이루어진 URL의 권한요소(authority component) 이다
     : HTTP 터널을 구축하는 경우, CONNECT와 함께 사용할 수 있다
     : CONNECT developer.mozilla.org:80 HTTP/1.1

    - asterisk 형식
     : OPTIONS 와 함께 별표'*' 하나로 서버 전체를 표현한다
     : OPTIONS * HTTP/1.1
  • HTTP 버전에 따라 HTTP message의 구조가 달라지므로 start line에 HTTP 버전을 함께 입력한다

 2) Headers

  • 헤더의 기본 구조는 헤더 이름(대소문자 구분이 없는 문자열), 콜론( : ), 값  으로 되어 있다
  • headers 는 여러 종류가 있으며, 아래의 그룹으로 나눌 수 있다
    - General headers
     : 메시지 전체에 적용되는 헤더이다
     : body를 통해 전송되는 데이터와는 관련이 없는 헤더입니다.

    - Request headers
     : fetch를 통해 가져올 리소스나 클라이언트 자체에 대한 자세한 정보를 포함하는 헤더이다
     : User-Agent, Accept-Type, Accept-Language과 같은 헤더는 요청을 보다 구체화한다
     : Referer처럼 컨텍스트를 제공하거나 If-None과 같이 조건에 따라 제약을 추가할 수 있다

    - Representation headers
     : Entity headers라고 부르기도 한다
     : Content-Length 와 같은 헤더는 요청 본문에 적용된다
     : body에 담긴 리소스의 정보(콘텐츠 길이, MIME 타입 등)를 포함하는 헤더이다
     : body가 없는 경우 전송되지 않는다

 

3) Body

  • 요청의 body는 HTTP messages 구조의 마지막에 위치한다
  • 모든 요청에 body가 필요하지는 않다
  • GET, HEAD, DELETE, OPTIONS처럼 서버에 리소스를 요청하는 경우에는 본문이 필요하지 않다
  • POST나 PUT과 같은 일부 요청은 데이터를 업데이트하기 위해 사용한다
  • body는 다음과 같이 두 종류로 나눌 수 있습니다.
    - Single-resource bodies(단일-리소스 본문)
     : 헤더 두 개(Content-Type 과 Content-Length)로 정의된 단일 파일로 구성된다

    - Multiple-resource bodies(다중-리소스 본문)
     : 여러 파트로 구성되며, 각 파트마다 다른 정보를 가진다
     : HTML form 과 관련이 있다

 

4. 응답(Responses)

 1) Status line

  • 응답의 첫 줄은 Status line이라고 한다
  • HTTP/1.1 404 Not Found. 처럼 구성된다
  • 다음의 정보를 포함한다
    - 현재 프로토콜의 버전
     : 보통 HTTP/1.1 이다

    - 상태 코드
     : 요청의 결과(성공여부)를 나타낸다
     : 200, 302, 404 등...

    - 상태 텍스트
     : 상태 코드에 대한 설명을 간결하게 나타낸다

 

 2) Headers

  • 응답의 HTTP headers는 요청 헤더와 동일한 구조를 가진다
  • 헤더 이름(대소문자 구분이 없는 문자열), 콜론( : ), 값 
  • 값은 헤더에 따라 다르다
  • 요청의 헤더처럼 그룹으로 나눌 수 있다
    - General headers
     : 메시지 전체에 적용되는 헤더이다
     : body를 통해 전송되는 데이터와는 관련이 없는 헤더이다

    - Response headers
     :위치 또는 서버 자체에 대한 정보(이름, 버전 등)와 같이 응답에 대한 부가적인 정보를 갖는 헤더이다
     : Vary, Accept-Ranges와 같이 상태 줄에 넣기에는 공간이 부족했던 추가 정보를 제공한다

    - Representation headers
     : Entity headers라고 부르기도 한다
     : body에 담긴 리소스의 정보(콘텐츠 길이, MIME 타입 등)를 포함하는 헤더이다

 

 3) Body

  • 응답의 body는 HTTP messages 구조의 마지막에 위치한다
  • 모든 응답에 body가 필요하지는 않다
  • 201, 204와 같은 상태 코드를 가지는 응답에는 body가 필요하지 않다
  • 응답의 body는 다음과 같이 두 종류로 나눌 수 있다
    - Single-resource bodies(단일-리소스 본문)
     : 길이가 알려진 단일-리소스 본문은 두 개의 헤더(Content-Type, Content-Length)로 정의한다
     :길이를 모르는 단일 파일로 구성된 단일-리소스 본문은 Transfer-Encoding이 chunked 로 설정되어 있으며, 파일은 chunk로 나뉘어 인코딩되어 있다

    - Multiple-resource bodies(다중-리소스 본문)
     : 서로 다른 정보를 담고 있는 body이다

 4) Stateless

  • 상태를 가지지 않는다는 의미이다
  • HTTP로 클라이언트와 서버가 통신을 주고받는 과정에서, HTTP가 클라이언트나 서버의 상태를 확인하지 않는다
  • 로그인, 로그아웃,상세 화면 이동, 카트 적재 등 클라이언트에서 발생한 모든 상태를 HTTP 통신이 추적하지 않는다
  • HTTP는 통신 규약일 뿐이므로, 상태를 저장하지 않는다
  • 상태 저장이 필요하면 쿠키-세션, API 등을 통해 상태를 확인할 수 있다
  • Stateless(무상태성)이 HTTP의 큰 특징이다

 

※ 참조

▶ HTTP 에러 코드

HTTP response status codes - HTTP | MDN (mozilla.org)

 

HTTP response status codes - HTTP | MDN

HTTP response status codes indicate whether a specific HTTP request has been successfully completed. Responses are grouped in five classes:

developer.mozilla.org

 

HTTP 정의

HTTP - 위키백과, 우리 모두의 백과사전 (wikipedia.org)

 

HTTP - 위키백과, 우리 모두의 백과사전

HTTP(HyperText Transfer Protocol, 문화어: 초본문전송규약, 하이퍼본문전송규약)는 W3 상에서 정보를 주고받을 수 있는 프로토콜이다. 주로 HTML 문서를 주고받는 데에 쓰인다. 주로 TCP를 사용하고 HTTP/3

ko.wikipedia.org

REST API

5 Basic REST API Design Guidelines (restcase.com)

 

5 Basic REST API Design Guidelines

As soon as we start working on an API, design issues arise. Robust and strong design is a key factor for API success. A poorly designed API will indeed lead to misuse or – even worse – no use at all by its intended clients: application developers. Crea

blog.restcase.com

 상태코드

https://docs.oracle.com/cd/E17802_01/products/products/servlet/2.3/javadoc/javax/servlet/http/HttpServletResponse.html

 

: Interface HttpServletResponse

 void setStatus(int sc, java.lang.String sm)           Deprecated. As of version 2.1, due to ambiguous meaning of the message parameter. To set a status code use setStatus(int), to send an error with a description use sendError(int, String).

docs.oracle.com

 

 

'Network' 카테고리의 다른 글

네트워크 - REST API  (0) 2022.08.16
네트워크 - 브라우져(Browser)  (0) 2022.06.08
네트워크 - 클라이언트(Client)  (0) 2022.06.07

1. URL(Uniform Resource Locator)

  • 네트워크 상에서 웹 페이지, 이미지, 동영상 등의 파일이 위치한 정보를 나타낸다
  • URL은 scheme, hosts, url-path로 구분할 수 있다
  • scheme은 통신 방식(프로토콜)을 결정하며, 일반적인 웹 브라우저에서는 http(s)를 사용한다
  • hosts는 웹 서버의 이름이나 도메인, IP를 사용하며 주소를 나타낸다
  • url-path는 웹 서버에서 지정한 루트 디렉토리부터 시작하여 웹 페이지, 이미지, 동영상 등이 위치한 경로와 파일명을 나타낸다
  • 브라우저로 파일을 찾아야 할 경우 'file://localhost/파일위치 디렉토리 주소' 를 사용하여 찾을 수 있다

 

2. URI(Uniform Resource Identifier)

  • URL의 기본 요소인 scheme, hosts, url-path에 query, bookmark를 추가한다
  • query는 웹 서버에 보내는 추가적인 질문이다
  • http://www.google.com:80/search?q=Java 를 브라우저의 검색창에 입력하면, 구글에서 Java를 검색한 결과가 나타난다
  • 브라우저의 검색창을 클릭하면 나타나는 주소가 URI이다
  • URI는 URL을 포함하는 상위개념으로 URL은 URI와 같을 수 있지만, URI는 URL과 같을 수 없다

http://www.google.com:80/search?q=Java 구분

file://
http://
https://
scheme 통신 프로토콜
127.0.0.1
www.google.com
hosts 파일이 위피한 웹 서버, 도메인, IP
:80
:443
:3000
port 웹 서버에 접속하기 위한 통로
/search
/user/username/Desktop
url-path 웹 서버의 루트 디렉토리로부터 파일까지 경로
q=Java quary 웹 서버에 전달하는 추가 질문

 

3. IP(Internet Protocol)

  • 인터넷상에서 사용하는 주소체계를 의미한다
  • 인터넷에 연결된 모든 PC는 IP 주소체계를 따라 네 개의 숫자 그룹으로 구분된다
  • 네 덩이의 숫자로 구분된 IP 주소체계를 IPv4라고 한다
  • IPv4(Internet Protocol version 4)는 IP 주소체계의 네 번째 버전을 나타낸다
  • IPv4의 각각의 숫자그룹은 0부터 255까지 사용 가능하다
  • 4개의 숫자그룹을 사용하면  2^(32)인 약 43억 개의 IP 주소를 가질 수 있다
더보기
▶ 터미널에서 'nslookup + 도메인주소' 명령어를 사용하여 도메인의 IP 주소를 확인할 수 있다

C:\Users\user>nslookup coding-mid-life.tistory.com

서버:    cns3.bora.net
Address:  203.248.252.2

권한 없는 응답:
이름:    wildcard-tistory-fz0x1pwf.kgslb.com
Address:  211.231.99.250
Aliases:  coding-mid-life.tistory.com
  • 용도가 정해져 있는 IP 주소도 있다
localhost

127.0.0.1
현재 사용 중인 로컬 PC의 주소
0.0.0.0

255.255.255.255
broadcast address로 로컬 네트워크에 접속된 모든 장치와 소통하는 주소이다

서버에서 접근 가능 IP 주소를 broadcast address 로 지정하면, 모든 기기에서 서버에 접근할 수 있다
  • 개인용 컴퓨터의 보급이 증가하여  IPv4의 주소가 고갈 단계에 도달하여 IPv6를 공식화 하였다
  •  IPv6은 128비트 주소를 사용하여 이론적으로 2^(128) 개 주소를 가질 수 있다
  • IPv6 주소는 각각 콜론으로 구분된 4개의 16진수로 구성된 8개의 그룹으로 표시된다
더보기

2001:0db8:0000:0000:0000:8a2e:0370:7334

단축 표현하여 2001:db8::8a2e:370:7334 로도 사용한다

 

4. PORT

  • IP 주소가 접속할 수 있는 통로를 의미한다
  • 포트 번호는 0~ 65,535 까지 사용할 수 있다
  • 0 ~ 1024번 까지의 포트 번호는 주요 통신을 위한 규약에 따라 이미 정해져 있다
  • 알아두어야 할 포트 번호

 

5. 도메인(Domain)

  • IP 주소에 특정한 이름을 부여한 것을 도메인이라 한다
  • 도메인은 일정 기간동안 대여하여 사용한다

 

6. DNS(Domain Name System)

  • 호스트의 도메인 이름을 IP 주소로 변환하거나 반대의 경우를 수행할 수 있도록 개발된 데이터베이스 시스템이다
  • 네트워크에는 DNS서버가 별도로 존재한다
  • 브라우저에 요청된 도메인을 검색하여 웹서버로 전달하여 주고 통신을 연결해 준다

7. 크롬(Chrome) 브라우저 에러 유형

  • Chrome 브라우저를 사용하다 보면 웹페이지를 제공하는 서버와 Chrome 브라우저가 소통하는 단계, 또는 기기와 네트워크의 연결, Chrome 브라우저가 해석할 수 없는 데이터를 전송받은 경우 에러가 발생한다
  • 에러 메시지를 만나면, 다음과 같은 문제가 발생할 수 있다

     - 웹페이지에 연결할 수 없습니다.

     - 웹페이지가 열리지 않습니다.

     - HTTPS가 적용된 웹페이지가 열리지 않습니다.

     - 사진이 로드되지 않습니다.

     - 새 탭이 로드되지 않습니다.

 

8. Chrome Network Tap 활용 방법

https://www.youtube.com/watch?v=e1gAyQuIFQo&t=482s 

 

 

※ 참조

https://en.wikipedia.org/wiki/IPv6

 

IPv6 - Wikipedia

From Wikipedia, the free encyclopedia Jump to navigation Jump to search Version 6 of the Internet Protocol Parts of this article (those related to RFC 8200 and RFC 8201) need to be updated. Please help update this article to reflect recent events or newly

en.wikipedia.org

 

'Network' 카테고리의 다른 글

네트워크 - REST API  (0) 2022.08.16
네트워크 - HTTP  (0) 2022.06.08
네트워크 - 클라이언트(Client)  (0) 2022.06.07

1. 클라이언트(Client) - 서버 아키텍쳐(Server Architecture)

  • 클라이언트 : 리소스를 사용하는 주체를 의미한다
  • 서버 : 리소스를 전달해 주는 역활을 한다
  • 데이터베이스 : 리소스를 저장하는 공간이다

※ 아키텍쳐(Architecture) : 컴퓨터 시스템의 구성을 의미한다

 

 1) 2-Tier 아키텍쳐

  • 클라이언트와 서버를 분리하여 리소스를 사용하는 방법이다
  • 클라이언트가 요청 후 서버가 리소스를 제공한다

 

 2) 3-Tier 아키텍쳐

  • 클라이언트 - 서버 - 데이터베이스 로 분리하여 리소스를 운영하는 방법이다

※  클라이언트 영역의 개발을 프론트엔드라고 한다

  서버와 데이터베이스 영역의 개발을 백엔드라고 한다

  데이터 동기화와 같은 서버와 서버 간의 통신을  inter-server commucation 이라고 한다

 

2. 클라이언트 - 서버 통신

 1) 프로토콜(Protocol)

  • 통신 시스템이 데이터를 교환하기 위해 사용하는 컴퓨터 간 통신의 규약이다
  • 클라이언트와 서버는 HTTP라는 프로토콜을 이용하여 정보를 주고 받는다
  • 호스트의 계층 사이에는 인터페이스(Interface)라는 규칙이 존재한다
  • 하위 계층이 상위 계층에 제공하는 인터페이스를 서비스(Service)라고 한다
더보기
■ OSI 7 Layer

 - 특징이 다른 여러 호스트를 서로 연결하여 통신하기 위하여 표준화한 연결 방식
 - 국제 표준화 단체(ISO, International Standard Organization)에서 제안
 - 네트워크에 연결된 호스트가 갖추어야 할 기능을 7개 계층으로 상세히 정의
 - 각 계층은 고유의 기능을 수행하며, 하위의 계층은 바로 위의 계층에 서비스를 제공한다
  • 호스트의 계층 사이에는 인터페이스(Interface)라는 규칙이 존재한다
  • 하위 계층이 상위 계층에 제공하는 인터페이스를 서비스(Service)라고 한다
    더보기
    ▶ OSI 7 Layer 계층별 기능

     - 응용 계층(Application Layer)
      ▷ 사용자의 다양한 네트워크 응용 환경을 지원한다
      ▷ 한정된 범위가 아닌 광범위 환경을 지원한다

      - 표현 계층(Presentation Layer)
      ▷ 전송되는 데이터의 의미(Semantic)를 올바르게 표현하는 방법(Sintax)을 제공한다
      ▷ 정보를 교환하는 시스템이 표준화된 방법으로 데이터를 인식할 수 있도록 한다
      ▷ 주요 기능은 압축(Compression)과 암호화(Encrypt)가 있다

        → 압축은 데이터의 양을 줄여 준다
        → 암호화는 외부의 침입에서 데이터를 보호한다

      - 세션 계층(Session Layer0
      ▷ 전송계층과 유사하지만 더 상위의 논리적 연결이다
      ▷ 응용 환경에서의 사용자 간의 대화(Dialog) 개념의 연결로 사용된다 
     
    - 전송 계층(Transport Layer)
      ▷ 송신 프로세스와 수신 프로세스 간의 연결(Connection) 기능을 제공한다
      ▷ 프로세스 간의 안전한 데이터 전송을 지원한다
      ▷ 4 Layer까지의 기능은 운영체제에서 시스템 콜(Syatem Call) 형태로 상위 계층에 제공한다
      ▷ 5~7 Layer의 기능은 사용자 프로그램으로 작성되어 상위 계층에 제공한다 

         프로세스(Processs)
        → 일이 처리되는 과정이나 공정
        → 주어진 일을 해결하기 위한 목적으로 수행되는 순서가 정해져 있는 절차
          
        → 컴퓨터에서 실행 중인 프로그램

     - 네트워크 계층(Network Layer)
      ▷ 송신 데이터가 수신 호스트까지 도착하는 과정에 올바른 경로를 선택하도록 지원한다
      ▷ 일반적으로 라우터(Router)가 수행한다
      ▷ 네트워크 부하가 증가하여 특정 지역에 혼잡(Congestion)이 발생할 경우에도 지원한다
          

     - 데이터링크 계층(Data Link Layer)
      ▷ 물리 계층으로 데이터를 전송하는 과정에서 잡음과 같은 외부 요인에 의해 오류가 발생할 수 있다
      ▷ 물리적 전송 오류를 감지하는 기능을 제공하여 송수신 호스트가 오류를 인지할 수 있게 한다
      ▷ 컴퓨터 네트워크에서 오류가 발생할 경우 원 데이터를 재전송(Retransmission)하는 방법으로 오류 제어(Error Control)를 한다 
        ※ 물리적 오류 종류
        → 데이터가 도착하지 못하는 데이터 분실의 물리적 오류
         데이터 내용이 깨져서 도착하는 데이터 분실의 물리적 오류

     - 물리 계층 (Physical Layer)
      ▷ 네트워크에서 호스트가 데이터를 정송하기 위해서는 반드시 전송 매체로 연결되어 있어야 한다
      ▷ 호스트를 전송 매체와 연결하기 위한 인터페이스 규칙과 전송 매체의 특성을 제공한다

 

 2) API(Application Programming Interface)

  • 클라이언트가 데이터에 편리하게 접근수 있도록 서버에서 정의한 규칙이다
  • 클라이언트 - 서버 - 데이터베이스를 연결해 주는 역활을 한다
  • 프로그램 내에서 실행을 위하여 특정 서브루틴에 연결을 제공하는 함수를 호출한다
  • 한 개의 API는 함수의 호출에 의해 요청되는 작업을 수행하기 위하여 연결되어야 하는 프로그램 모듈을 가지고 있다

 

 

 

'Network' 카테고리의 다른 글

네트워크 - REST API  (0) 2022.08.16
네트워크 - HTTP  (0) 2022.06.08
네트워크 - 브라우져(Browser)  (0) 2022.06.08

알고리즘 관련 유투브 영상을 보면서 시작해 보자

https://www.youtube.com/watch?v=cDA3_5982h8&t=3s 

위의 영상은 프로그램 코딩을 할 때 알고리즘의 중요성을 보여주고 있다.

절차와 방법이 빠지거나 순서가 달라지면 결과도 달라질 수 있다는 대표적인 예를 영상으로 표현한 내용이다

 

1. 수도 코드(Pseudocode)

  • 프로그램의 절차를 우리가 사용하는 일반적인 언어로 작성하는 방법이다
  • 컴퓨터가 실행할 수 있는 코드는 아니다
  • 프로그램을 코딩하기 전에 작동 순서와 같은 흐름을 파악할 수 있다

2. 수도코드 작성 순서

더보기

문제해석 -> 요구사항 분석 -> 문제 분해 -> 수도코드 작성 -> 코드 작성

 

1. 제어문(Control Flow Statements)

  • 조건문(a conditional statement)과 반복문(a repeating sentence)을 합해서 제어문이라 한다
  • 일반적인 코드의 흐름은 위에서 아래로 향하지만, 제어문을 사용하면 개발자가 원하는 방향으로 변경할 수 있다

2. 조건문(a conditional statement)

  • 조건문은 특정 조건에 부합하는 경우에 특정 코드의 실행 여부를 결정할 수 있다

 1) if문

  • 아래와 같은 형식으로 사용할 수 있다
  • 중괄호 { }를 사용하여 여러 문장을 하나로 묶을 수 있으며 '블록(block)'이라고 한다
더보기

if (조건식) { 실행 블록 };   //만약에 조건식이 true이면 실행블럭을 진행한다

 2) if ~else문

  • 조건식이 false일 경우에 조건문이나 실행블록을 추가하여 코드의 실행여부를 결정한다
  • else는 생략할 수 있다 
더보기

if(조건식1){실행블록1};                  //조건식1이 true이면 실행블록을 진행한다

      else if(조건식2){실행블록2};    //조건식1이 false이면 조건식2의 조건식을 검토하고 조건식2가 true이면 실행블록2를 진행한다

      else{실행블록3};                      //조건식1과 조건식2가 모두 false이면 실행블록3을 진행한다

import java.util.*;

public class Aaaa {
    public static void main(String[] args) {

        Scanner scanner = new Scanner(System.in);
        //int num = scanner.nextInt();
        String input = scanner.nextLine();
        //System.out.println(num);

        System.out.println("입력한 숫자는?");
        if (input.equals("1")) { 
            System.out.println("1번");
        } else if (input.equals("2")) {
            System.out.println("2번");
        } else if (input.equals("3")) {
            System.out.println("3번");
        } else if (input.equals("4")) {
            System.out.println("4번");
        } else if (input.equals("5")) {
            System.out.println("5번");
        } else if (input.equals("6")) {
            System.out.println("6번");
        } else {
            System.out.println("없는 숫자! " + input);
        }

    }
}

result
5  //입력 후 enter
입력한 숫자는?
5번

 3) switch문

  • if문은 조건식에 의해 실행블록이 결정되어 출력된다
  • switch문은 입력값에 따라 실행블록이 결정되어 출력된다
  • break 명령어로 true일 경우 실행블록을 탈출한다
  • defualt는 생략 가능하다
더보기

switch ( 입력변수 ) {              //switch문에서 입력받을 변수를 지정해 준다

        case "입력값" :              //입력변수 값과 대조할 값을 넣어준다

                 실행블록1 ;           //입력변수와 입력값이 일치했을 경우에 실행블록1을 진행한다

        break ;                           //입력변수 값과 입력값이 일치할 경우 실행블록1을 진행하고 멈춘다

        default:                          //입력변수 값과 입력값이 불일치 할 경우 실행블록2을 진행한다

                 실행블록2 ;

        break ;

import java.util.*;

public class Aaaa {
    public static void main(String[] args) {

        Scanner scanner = new Scanner(System.in);
        //int num = scanner.nextInt();
        String input = scanner.nextLine();
        //System.out.println(num);

        System.out.println("입력한 숫자는?");
        switch (input) {
            case "1":
                System.out.println("1번");
                break;
            case "2":
                System.out.println("2번");
                break;
            case "3":
                System.out.println("3번");
                break;
            case "4":
                System.out.println("4번");
                break;
            case "5":
                System.out.println("5번");
                break;
            default:
                System.out.println(input + " 번은 해당이 없는 숫자입니다");
                break;
        }
    }
}

result
6  //입력 후 enter
입력한 숫자는?
6 번은 해당이 없는 숫자입니다
  • 타입에 따라 문자열 입력도 가능하다
import java.util.*;

public class Aaaa {
    public static void main(String[] args) {

        Scanner scanner = new Scanner(System.in);
        //int num = scanner.nextInt();
        String input = scanner.nextLine();
        //System.out.println(num);

        System.out.println("입력한 사람은");
        switch (input) {
            case "kim":
                System.out.println("대한민국 국적입니다");
                break;
            case "smith":
                System.out.println("미국 국적입니다");
                break;
            case "jonadan":
                System.out.println("가나 국적입니다");
                break;
            default:
                System.out.println(input + " 번은 해당이 없는 숫자입니다");
                break;
        }
    }
}

result
smith
입력한 사람은
미국 국적입니다
  • JDK 14 이상 부터는 아래와 같은 형식으로 사용할 수 있다
import java.util.*;

public class Aaaa {
    public static void main(String[] args) {

        Scanner scanner = new Scanner(System.in);
        //int num = scanner.nextInt();
        String[] inputList = {"kim", "smith", "jonadan"};
        String input = scanner.nextLine();
        //System.out.println(num);

        System.out.println("입력한 사람은");
        switch (input) {
            case "kim" -> System.out.println("대한민국 국적입니다");
            case "smith", "jonadan" -> System.out.println("미국 또는 가나 국적입니다");

            default -> System.out.println(input + " 번은 해당이 없는 숫자입니다");
        }
    }
}

// : 대신 -> 의 사용으로 break 생략
// , 를 사용하여 여러 조건을 한번에 처리할 수 있다

 

3. 반복문(a repeating sentence)

  • 코드들이 반복적으로 실행되도록 하는 경우에 사용한다

 1) for문

  • for문은 조건식이 참(true)인 경우에 주어진 횟수만큼 실행문을 반복적으로 진행한다
  • 더보기
    sum = 0 ;
    for (초기화 , 조건식, 증감식  ) { 실행블록 ; }
    for (int i = 0, i < 10  , i++        ) { sum = sum + i ; } 
  • 변수 i는 임의의 변수명이므로 변경하여 사용해도 된다
  • 통상적으로 i 는 iterator(반복계수)를 의미하여 많이 사용한다
  • for문은 반복적으로 사용해야 할 조건을 조건식을 사용하여 단축시켜주므로 코드를 줄일 수 있다
  • 더보기
    ▷ 초기화 : for문을 시작할 때 한 번만 실행되며, 사용할 변수의 초기값을 지정해 준다
    조건식 : 반복 여부를 결정하는 조건으로 값이 true면 실행블록을 진행하고, false면 실행블록을 진행하지 않고 for문을 끝낸다
    증감식 : for문에서 지정한 변수의 값을 증감시켜 반복 횟수를 결정한다 (++ : 값을 1씩 증가시킨다)

public class Ffile {
    public static void main(String[] args) {
            int s=0;
            for(int i=0; i < 10; i++){
                s = s + i;
            }
        System.out.println(s);
    }
}

result
45
  • for문의 초기화 식은 생략 가능할 경우 생략할 수 있다
  • for문은 둘 이상의 초기화식과 조건식, 증감식을 사용할 수 있다
public class Ffile {
    public static void main(String[] args) {
            int s = 0;
            int s1 = 0;
            for(int i=0, j=100; i < 10 && j<200; i++, j++){
                s = s + i;
                s1= s1 + j;
            }
        System.out.println(s);
        System.out.println(s1);
    }
}

result
45
1045

 

 2) enhanced for문(향상된 for문)

  • 타입에 따른 값을 배열로 지정하여 주었을 때 for문의 초기화 변수를 지정하고 ':'을 사용하여 참조변수를 가져온다
  • 참조변수의 값이 존재하면 반복하여 실행문을 진행한다
public class Ffile {
    public static void main(String[] args) {
            String[] s = {"kim", "kang", "lee", "choi"};
            for(String name : s){
                System.out.println("나의 성은 " + name + " 입니다");
            }
    }
}

result
나의 성은 kim 입니다
나의 성은 kang 입니다
나의 성은 lee 입니다
나의 성은 choi 입니다

 

 3) while문

  • while문은 정해진 횟수가 없이 계속 반복한다
  • for문과 while문은 초기화, 증감식의 위치만 다르고 상호대체하여 사용이 가능하다
  • 더보기
    초기화 ;
    while (조건식) { 실행블록 ; 증감식 ; }
  • 초기화, 증감식이 불필요한 경우에는 생략할 수 있다
public class Wfile {
    public static void main(String[] args) {
        int n = 0, s = 0;
        while(n <= 9){
            s = s + n; //s += n 으로 작성할 수 있다
            n++;
        }
        System.out.println(s);
    }
}

result
45

//n이 9보다 작거나 같을때까지 반복하여 연산을 수행한다
  • 조건식에 true를 넣으면 while문은 무한반복을 한다
  • true를 사용할 경우 if문이나 break를 사용하여 중단할 수 있다

 4) do-while문

  • do-while문은 조건식이 우선이 아니라 실행문을 우선 진행하고 조건식으로 넘어간다
  • 조건식이 true이면 반복하고 false이면 중단한다
  • 더보기
    do { 실행블록 }
    while(조건식);
import java.util.Scanner;

public class Dfile {
    public static void main(String args[]){
        int input = 0, randomNum = 0;

        randomNum = (int)(Math.random() * 10) + 1; // 1 ~ 10 임의의 수를 생성
        Scanner scanner = new Scanner(System.in);

        do{
            System.out.println("1과 10 사이의 정수를 입력하세요");
            input = scanner.nextInt();

            if(input > randomNum) {
                System.out.println("더 작은 정수를 입력하세요");
            } else if (input < randomNum) {
                System.out.println("더 큰 정수를 입력하세요");
            }
        } while(input != randomNum);
        System.out.println(randomNum +" 정답입니다!");
    }
}

1과 10 사이의 정수를 입력하세요
9
더 작은 정수를 입력하세요
1과 10 사이의 정수를 입력하세요
5
더 작은 정수를 입력하세요
1과 10 사이의 정수를 입력하세요
3
더 큰 정수를 입력하세요
1과 10 사이의 정수를 입력하세요
4
4 정답입니다!

'JAVA' 카테고리의 다른 글

Java - 문자열 입력(Scanner, BufferReader)  (0) 2022.08.08
Java - 날짜(Date), 시간(Time)  (0) 2022.08.08
Java - 콘솔 입출력(I/O)  (0) 2022.06.02
Java - 연산자(Operator)  (0) 2022.06.02
자료구조 - 트리(Tree)  (0) 2022.05.30

1. 콘솔 출력(Console Output)

 1) 출력하기

  • System.out.print( )
  • ( ) 안의 내용을 단순히 출력한다
  • 줄바꿈은 하지 않는다

 2) 출력하고 줄 바꾸기

  • System.out.println( )  //ln 은 line 의 약자이다
  • ( ) 안의 내용을 단순히 출력한다
  • 출력 후 줄바꿈을 한다

 3) 형식대로 출력하기

  • System.out.printf( )   //f 은  formatted 의 약자이다
  • ( ) 안의 내용을 지시자에 의해 지정되는 형식으로 출력한다
  • 출력 후 줄바꿈을 하지 않는다
지시자 출력 형식 지시자 출력형식
%b 불리언 %c 문자
%d 10진수 %s 문자열
%o 8진수 %n 줄바꿈
%x, %X 16진수    

 

2. 콘솔 입력(Console Input)

 1) 스캐너(Scanner)

  • 화면으로부터 데이터를 입력받는 기능을 제공하는 클래스이다
  • 객체를 생성한 후 사용해야 한다
  • 더보기
    Scanner scanner = new Scanner(System.in);    //System.in : 화면입력 명령어
import java.util.*;

public class Aaaa {
    public static void main(String[] args) {

        Scanner scanner = new Scanner(System.in);
        //int num = scanner.nextInt();
        String input = scanner.nextLine();
        //System.out.println(num);
        System.out.println(input);
    }
}

result
kim //입력 후 enter
kim

 

'JAVA' 카테고리의 다른 글

Java - 날짜(Date), 시간(Time)  (0) 2022.08.08
Java - 제어문(Control Flow Statements)  (0) 2022.06.02
Java - 연산자(Operator)  (0) 2022.06.02
자료구조 - 트리(Tree)  (0) 2022.05.30
메서드 모음(method)  (0) 2022.05.29

1. 산술 연산자(Arithmetic operator)

  • 산술연산자는 사칙 연산자와 나머지 연산자를 말한다
  • 나머지 연산자는 모듈로(modulo) 연산자라고도 한다 
연산자 기능 예시 결과값
+ 두 항을 더한다 7 + 3 10
- 앞에 있는 항에서 뒤에 있는 항을 뺀다. 7 - 3 4
* 두 항을 곱한다 7 * 3 21
/ 앞에 있는 항에서 뒤에 있는 항을 나누어 몫을 구한다 7 / 3 2 (int 타입의 경우 정수로 반환)
% 앞에 있는 항에 뒤에 있는 항을 나누어 나머지를 구한다 7 % 3 1

 

2. 비교 연산자(Comparison operator)

 1) 대소 비교 연산자(Small-to-large comparison operator)

  • boolean을 제외한 나머지 기본 타입에 사용 가능하다
  • 항상 대소 비교연산자 <, > 를 우선 사용하여야 한다
  • 이항비교만 가능하기 때문에 논리 연산자 or(||), and(&&) 와 함께 사용한다
대소 비교연산자 결과값
5 > 3 true
5 <= 5 true
3 > 2 true
2 >= 3 false

 

 2) 등가 비교 연산자(Equivalent comparison operator)

  • 비교 대상의 값이 동등한지 여부를 판단할 때 사용한다
등가 비교연산자 결과
5 == 3 false
5 == 5 true
3 != 2 true
3 != 3 false

 

 3) 조건 연산자(Condition operator)

  • 삼항 연사자로 구성은 아래와 같다
더보기

조건식 ? 참일 경우 결과 : 거짓일 경우 결과;

int age = 20; 
int condition = age > 10 ? 20 : 10;
System.out.println(condition);
// age의 값이 10보다 크면 20이 conditione에 저장되어 20이 출력 
// age의 값이 10보다 작으면 10이 conditione에 저장되어 10이 출력

String condition; 
String name = "Kim";
condition = name.equals("Kim") ? "yes" : "no";
//name 변수의 값이 "Kim"과 같으면 "yes" 다르면 "no"가 저장
System.out.println(condition);
// "yes"가 출력

 

3. 논리연산자(logical operator)

  • boolean 타입을 반환하는 연산자이다
    AND OR NOT
    && || !
    피연산자 두 개의 값이
    모두
    true일 때 true를 반환한다
    하나라도
    true가 아니면 false를 반환
    피연산자 두 개의 값이
    모두
    false일 때 false를 반환한다
    하나라도 
    true면 true를 반환
    truefalse를 반대로 바꾼다

 

4. 연산자 우선순위

우선순위 연산자 내용
1 (),[] 괄호 / 대괄호
2 !, ~, ++, -- 부정/ 증감 연산자
3 *, /, % 곱셈 / 나눗셈 연산자
4 <, <=, >, >= 대소 비교 연산자
5 && AND 연산자
6 || OR 연산자
7 ? : 조건 연산자
8 =, +=, -=, /=, %= 대입/할당 연산자

 

'JAVA' 카테고리의 다른 글

Java - 제어문(Control Flow Statements)  (0) 2022.06.02
Java - 콘솔 입출력(I/O)  (0) 2022.06.02
자료구조 - 트리(Tree)  (0) 2022.05.30
메서드 모음(method)  (0) 2022.05.29
Java - 상수(Constant), 리터럴(Literal)  (0) 2022.05.29

1. 트리(Tree)

  • 자료 구조의 트리는 나무의 형태를 가진 단방향 그래프의 일종이다
  • 하나의 데이터 아래에 여러 개의 데이터가 존재하는 비선형 구조이다
  • 트리 구조는 계층적으로 표현된다
  • 트리 구조는 아래로만 뻗어 나가기 때문에 사이클이 존재하지 않는다

 1) 트리 구성

  • 데이터가 시작이 되는 꼭지점을 루트(Root) 라고 한다
  • 데이터를 연결하는 선을 간선(Edge)라고 한다
  • 각각의 개별 데이터를 노드(Node)라고 한다
  • 상위-하위 관계 데이터 중에서 루트노드로부터 가까운 데이터를 부모 노드(Parent Node) 라고 한다
  • 상위-하위 관계 데이터 중에서 루트노드로부터 먼 데이터를 자식 노드(Child Node)라고 한다
  • 부모와 자식 노드가 한쌍으로 연결되어 관계를 형성한다
  • 자식 노드가 없는 데이터를 리프 노드(Leaf Node)라고 하며, 트리구조의 끝 지점이다

 

Tree 구조

 

2. 트리 관계

 1) 깊이(Depth)

  • 루트부터 하위 특정 노드까지의 깊이를 표현할 수 있다
  • 루트값은 0부터 시작한다

 2) 레벨(Level)

  • 동일한 깊이를 가지고 있는 데이터들을 레벨로 묶을 수 있다
  • 같은 레벨의 데이터를 형제 노드(Sibling Node)라고 한다

 3) 높이(Height)

  • 깊이와 반대로 리프노드부터 상위 특정 노드까지의 높이를 표현할 수 있다
  • 리프노드 값은 0부터 시작한다
  • 부모노드는 자식노드의 높이 값 + 1 의 값을 높이로 가진다

 4) 서브 트리(Sub Tree)

  • 루트에서 뻗은 트리 구조 내에 트리구조를 가지는 작은 트리를 서브트리(Sub tree)라 한다

 

 

※ 트리구조 적용 사례

  • 컴퓨터 디렉토리 구조

'JAVA' 카테고리의 다른 글

Java - 콘솔 입출력(I/O)  (0) 2022.06.02
Java - 연산자(Operator)  (0) 2022.06.02
메서드 모음(method)  (0) 2022.05.29
Java - 상수(Constant), 리터럴(Literal)  (0) 2022.05.29
Java - 문자열 변환 후 저장(StringBuilder / StringBuffer)  (0) 2022.05.29

+ Recent posts