[Sparta] Spring 입문 1주차

Dyong_Song·2024년 2월 20일

📕Spring 입문

1주차

📌학습 기초 지식

1. Gradle이란?

빌드 자동화 시스템 : 자바 코드를 설정에 맞도록 자동 빌드(작성한 소스코드를 실행 가능한 jar 파일로 변경
build시, build/libs/프로젝트명.jar 생성

build.gradle이란?

  • gradle 기반의 build script = 소스코드를 빌드하거나, 라이브러리의 의존성을 쉽게 관리-
  • groovy 혹은 kotlin 언어로 작성
  • dependencies에 필요한 라이브러리를 작성 -> maven.repository 사이트를 통해 다운
  • 라이브러리 의존성을 자동으로 관리해주므로, 라이브러리 충동 가능성이 적음

2. Server란?

네트워크

여러 대의 컴퓨터 또는 장비(라우터, 스위치 등등)가 서로 연결되어 정보를 주고 받을 수 있는 기술

  • 정보를 주고 받기 위해서는 IP주소, 서브넷 마스크, 게이트웨이 등의 정보를 설정하고, 네트워크 프로토콜을 이용하여 통신

네트워크를 알아야 하는 이유?

  • 사용자의 요청에 따라 응답을 수행하는 프로그램(서버)을 개발하기 위해서
  • 네트워크의 흐름을 파악 => 서버 개발에 도움

Client와 Server

  • 사용자는 브라우저(url)를 이용하여 서버에 정보를 요청 -> 요청을 보낼 서버의 정보(IP)필요
  • IP: 컴퓨터를 식별하기 위한 위치 주소
  • Port: 컴퓨터 내의 받는 사람과 동일

Web Server란?

  • 인터넷을 통해 HTTP를 이용하여 웺상의 클라이언트의 요청을 응답해주는 통신을 하는 일종의 컴퓨터
  • 웹 서버의 기본 동작 원리
  1. 브라우저를 통해 HTTP Request로 웹사이트를 웹서버에 요청
  2. 웹서버는 요청을 승인하고, HTTP Response를 통해 웹사이트 데이터를 브라우저에 전송
  3. 브라우저는 서버에서 받아온 데이터를 이용해 브라우저에 출력 (보통 Get Method로 요청)

API 란?

application programming interface : 다른 소프트웨어 시스템과 통신하기 위해 따라야 하는 규칙
일종의 약속, 컨벤션 -> 서로 약속한 방식으로 API요청을 보내면, 그에 맞는 응답을 보내주는 형식

RESTful API란?

  • Representational State Trasfer(REST)는 API 동작 방식에 대한 조건을 부과하는 소프트웨어 아키텍처
  • REST 아키텍처 스타일을 따르는 API를 통칭 REST API
  • REST 아키텍처를 구현하는 웹 서비스를 RESTful 웹 서비스
  • 즉, http를 준수하며 잘 설계된 것을 RESTful 하다고 표현
  • HTTP(Hypertext Transfer Protocol)의 메소드
    - GET / POST / PUT / DELETE 등등 ...

WebServer와 WebApplicationServer(WAS)

  • Web Server: 브라우저에서 URL을 입력하여, 페이지 요청 -> HTTP의 요청을 받아 HTML 문서와 같은 정적 컨텐츠를 사용자에게 전달해주는 역할 ex) Apache, Nginx
    -> WAS는 로그인, 회원가입, 게시물 조회, 정렬 등 다양한 로직을 수행하는 프로그램 동작 가능

Apache Tomcat이란?

Tomcat은 동적인 처리를 할 수 있는 웹서버를 만들기 위한 웹 컨테이너

Apache Tomcat이란? Apache와 Tomcat이 합쳐진 형태로 정적인 데이터 처리와 동적인 데이터 처리를 효율적으로 진행

Spring과 SpringBoot

  • Spring Framework: 2004년 1.0 버전 출시 / POJO(순수 자바 객체)를 Ioc/DI, AOP, PSA를 통해 달성 => 이러한 편의성을 위해서는 xml파일, 다양한 설정을 해야한다. => 이를 개선한 SpringBoot
    • IoC/DI : 제어의 역전 / 의존성 주입
    • AOP : 프록시 패턴
    • PSA : Portable Service Abstraction - 편의성 서비스의 추상화 / 추상화 계층을 사용하여 어떤 기술을 내부에 숨기고 개발자에게 편의성을 제공하는 것
  • Spring Boot
    • 기존 Spring FrameWork의 xml 설정 대신, 자바의 어노테이션 기능을 통해 설정가능
    • 자주 사용하는 설정을 default값으로 설정하여, 따로 설정할 필요가 없음
    • 라이브러리의 의존성을 모두 가져올 수 있음
    • 내장 ApacheTomcat 포함

3. HTTP란?

HTTP(HyperTextTransfer Protocol)

  • 데이터를 주고 받는 양식을 정의한 "통신 규약" 중 하나
  • 세계에서 가장 널리 쓰이는 통신 규약
  • 통신 규약: 컴퓨터 간의 데이터 전송 시의 약속
  • 모든 브라우저는 HTTP 프로토콜을 기본으로 지원

데이터를 주고 받는 방법

  • Request와 Response를 통한 통신
  1. 브라우저는 서버에 원하는 페이지(URL)를 요청(Request)
  2. 서버는 브라우저가 원하는 페이지 확인 후, 응답(Response)
  • 개발자 도구를 통한 확인 : 네트워크 탭의 Header / Response / Request 등을 통해 확인
  • Header: 요청과 응답 데이터를 담는 필드
  • Payload: 실제 데이터, 서버가 응답을 보낼 때 사용 (GET메서드 제외 모두 사용 가능)

4. 테스트 코드

개발에서 발생할 수 있는 버그를 찾아내기 위한 코드

방법

  1. 블랙박스 테스팅 : 소프트웨어 내부 구조, 동작원리를 몰라도 가능한 테스트 (사용자 입장)
    • 누구나 테스트 가능
    • 기능 증가에 따른 테스트 범위 증가
  2. 개발자 테스트 : 본인이 작성한 코드를 검증하기 위한 테스트 코드
    • 빠르고 정확한 테스트 가능 + 테스트 자동화 가능 + 리팩토링 용이
    • 개발 시간 증가 + 테스트 코드 유지보수 비용 발생

5. Lombok과 application.properties

Lombok

Lombok은 자바 프로젝트에 필수적인 메서드/생성자 등을 자동 생성해줌으로써 코드를 절약하도록 도와주는 라이브러리
@Getter / @Setter / @AllArgsConstructor / @NoArgsConstructor / @RequiredArgsConstructor (final이 붙은 필드)

application.properties

  • Spring 관련 설정을 하는 파일
  • DB 연결 시 DB의 정보를 제공
  • application.yml: properties보다 계층 구조 확인 용이, 가독성 UP

📌Spring MVC

6. Spring MVC란?

MVC 디자인 패턴

  • MVC: Model - View - Controller의 약자, 소프트웨어 디자인 패턴 중 하나
  • Model: 데이터와 비즈니스 로직 담당, DB와 연동하여 데이터 저장 및 불러오기 작업
  • View: 사용자 인터페이스 담당, 화면-버튼-폼 등을 디자인하고 구현
  • Controller: Model과 View 사이의 상호작용을 조정하고 제어, 사용자의 입력을 Model에 전달하고 Model의 결과를 바탕으로 View를 업데이트
  • MVC: Model - View - Controller의 약자, 소프트웨어 디자인 패턴 중 하나
  • Model: 데이터와 비즈니스 로직 담당, DB와 연동하여 데이터 저장 및 불러오기 작업
  • View: 사용자 인터페이스 담당, 화면-버튼-폼 등을 디자인하고 구현
  • Controller: Model과 View 사이의 상호작용을 조정하고 제어, 사용자의 입력을 Model에 전달하고 Model의 결과를 바탕으로 View를 업데이트

    MVC 패턴은 소프트웨어를 구성하는 요소들을 분리함으로써, 코드의 재사용성과 유지보수성을 높이고, 개발자 간의 협업을 용이하게 한다. 따라서, MVC 패턴을 적용하여 구조를 잘 설계하는 것이 중요하다.

Spring MVC

Spring Web MVC는 Servlet API를 기반으로 구축된 웹 프레임워크. 중앙에 있는 DispatcherServlet이 요청을 처리하기 위한 공유 알고리즘을 제공하는 Front Controller 패턴을 중심으로 설계

Servlet(서블릿)은 자바를 사용하여 웹 페이지를 동적으로 생성하는 서버 측 프로그램 혹은 그 사양을 의미
1. 사용자가 브라우저를 통해 서버에 HTTP Request(API)를 요청
2. 요청을 받은 Servlet 컨테이너는 Request와 Response 객체를 생성
3. 설정된 정보를 통해 어떤 Servlet에 대한 요청인지 확인
4. 해당 Servlet에서 service 메서드를 호출한 뒤, 브라우저의 요청 Method에 따라 doGet 혹은 doPost 등의 메서드를 호출
5. 호출한 메서드들의 결과를 그대로 반환하거나 동적 페이지를 생성한 뒤, Response 객체에 응답을 담아 브라우저에 반환
6. 응답 완료 후, Servlet 소멸

  • 모든 API 요청을 서블릿 동작 방식에 맞춰 구현한다면, 수많은 Servlet 클래스 필요
  • Spring은 DispatcherServlet을 사용하여, Front Controller 패턴 방식으로 API 요청을 효율적으로 처리
  • Front Controller 패턴
  1. 브라우저에서 HTTP 요청이 들어오면 DispatcherServlet 객체가 요청 분석
  2. Handler mapping을 통해 Controller를 찾아 요청 전달
@RestController
public class HelloController {
    @GetMapping("/api/hello")    // Handler mapping 
    public String hello() {
        return "Hello World!";
    }
}
// API path와 Controller 메서드가 매핑된 것을 의미
// @Controller 어노테이션이 있는 클래스를 생성한 뒤, 메서드를 구현하여 요청에 해당하는 로직 처리
// return 값을 DispatcherServlet 전달
  1. Controller -> DispatcherServlet으로 처리에 대한 결과 즉, 데이터(Model)과 View 정보 전달
  2. DispatcherServlet -> Client : ViewResolver를 통해 View에 Model을 적용하여 View를 Client에게 응답으로 전달

<정리>
Dispatcher(배달부)Servlet은 요청과 응답 객체를 가진 채, 매핑된 정보에 따라 Controller로 이동, 해당 로직을 수행하고, ViewResolver에 등록된 정보에 따라 로직의 return 값을 View로 전환하여 Client로 전달

7. Controller

@ResponseBody // View로 보내지 않고, 순수 데이터를 전송할 경우 사용
  • Mapping 시, 경로는 중복될 수 있으나, Method는 중복되어서는 안된다.
  • 한 Controller가 같은 endpoint를 반복할 경우, 클래스 어노테이션으로 @RequestMapping 사용
  • @GET, @POST, @PUT, @DELETE : 메서드 정하기

8. 정적 페이지와 동적 페이지

9. 데이터를 Client에 반환하기

서버단에서 모든 데이터를 처리하고, html/css/js 파일을 반환하는 방식도 존재.
But! 최근에는 프론트와 백이 나뉘면서, 느슨한 결합 방식을 채택
요청에 맞는 특정 데이터만 반환 (JSON형태의 데이터 반환 多)
기본적인 html 파일 요청을 제외하고는, JSON 데이터를 요청하는 API를 통해 브라우저에서 html을 조작하여 반영하는 방식 사용

데이터 보내기

  • 템플릿 엔진(Thymleaf)이 적용된 Controller에서, 문자열을 반환하면 temlplates 폴더의 해당 문자열의 .html 파일을 반환
  • html 파일이 아닌, JSON 데이터를 보내기 위해서는 @ResponseBody 어노테이션 必
  • @ResponseBody가 모두 붙은 Controller = @RestController
  • 예시
@RestController
@RequestMapping("/response/rest")
public class ResponseRestController {
    // [Response header]
    //   Content-Type: text/html
    // [Response body]
    //   {"name":"Robbie","age":95}
    @GetMapping("/json/string")
    public String helloStringJson() {
        return "{\"name\":\"Robbie\",\"age\":95}";
    }

    // [Response header]
    //   Content-Type: application/json
    // [Response body]
    //   {"name":"Robbie","age":95}
    @GetMapping("/json/class")
    public Star helloClassJson() {
        return new Star("Robbie", 95);
    }

}

10. Jackson

JSON 데이터 구조를 처리해주는 라이브러리.

  • 자바의 객체를 Json으로, Json타입의 String 값을 Object로 전환 가능
  • Spring 3.0 버전 이후로, Jackson 라이브러리 지원
  • 객체를 return하면, 라이브러리에 의해 자동으로 변환되지만 직접 변환도 가능
    @Test
    @DisplayName("Object To JSON : get Method Need")
    void test1() throws JsonProcessingException {
        Star star = new Star("Robbie", 95);
        ObjectMapper objectMapper = new ObjectMapper(); // Jackson 라이브러리의 ObjectMapper
        String json = objectMapper.writeValueAsString(star);    // 변환시 Getter 반드시 필요!
        System.out.println("json = " + json);
    }

    @Test
    @DisplayName("JSON To Object : 기본 생성자 & (get OR set) Method 필요")
    void test2() throws JsonProcessingException {
        String json = "{\"name\":\"Robbie\",\"age\":95}"; // JSON 타입의 String
        ObjectMapper objectMapper = new ObjectMapper(); // Jackson 라이브러리의 ObjectMapper
        Star star = objectMapper.readValue(json, Star.class); // 변환할 객체 명시 
        System.out.println("star.getName() = " + star.getName());
    }

11. Path Variable과 Request Param

브라우저에서 서버로 HTTP 요청을 보낼 때, 데이터를 함께 보낼 수 있다.

@Controller
@RequestMapping("/hello/request")
public class RequestController {
    @GetMapping("/form/html")
    public String helloForm() {
        return "hello-request-form";
    }
    // [Request sample]
    // GET http://localhost:8080/hello/request/star/Robbie/age/95
    @GetMapping("/star/{name}/age/{age}")
    @ResponseBody
    public String helloRequestPath(@PathVariable String name, @PathVariable int age)
    {
        return String.format("Hello, @PathVariable.<br> name = %s, age = %d", name, age);
    }
    // [Request sample]
    // GET http://localhost:8080/hello/request/form/param?name=Robbie&age=95
    // @RequestParam 생략 가능 / 단, 값을 담지 않은 채 데이터를 넘길 경우 BadRequest 400
    // 안 넘어올 경우에는 required = false로 설정 -> 단, 값이 null로 초기화된다.
    @GetMapping("/form/param")
    @ResponseBody
    public String helloGetRequestParam(@RequestParam(required = false) String name, int age) {
        return String.format("Hello, @RequestParam.<br> name = %s, age = %d", name, age);
    }
    // [Request sample]
    // POST http://localhost:8080/hello/request/form/param
    // Header
    //  Content type: application/x-www-form-urlencoded
    // Body
    //  name=Robbie&age=95
    @PostMapping("/form/param")
    @ResponseBody
    public String helloPostRequestParam(@RequestParam String name, @RequestParam int age) {
        return String.format("Hello, @RequestParam.<br> name = %s, age = %d", name, age);
    }
}
  1. Path Variable : HTTP 요청을 보낼 때, URL에 함께 전송
    • GetMapping()을 통해 endPoint를 지정할 때, parameter에 해당하는 값을 {data} 지정
    • 예제 상, 해당 URL로 전송하는 메서드는 front 단에서 관리
  2. Request Param : 서버에 보내려는 데이터를 URL 경로 마지막에 ?&를 사용해 추가
    - GET방식: header에 값 전송
    - POST방식: HTTP body에 담겨서 전송

12. HTTP 데이터를 객체로 처리하기

@Controller
@RequestMapping("/hello/request")
public class RequestController {
    @GetMapping("/form/html")
    public String helloForm() {
        return "hello-request-form";
    }
    @GetMapping("/star/{name}/age/{age}")
    @ResponseBody
    public String helloRequestPath(@PathVariable String name, @PathVariable int age)
    {
        return String.format("Hello, @PathVariable.<br> name = %s, age = %d", name, age);
    }
    // @RequestParam 생략 가능 / 단, 값을 담지 않은 채 데이터를 넘길 경우 BadRequest 400
    // 안 넘어올 경우에는 required = false로 설정 -> 단, 값이 null로 초기화된다.
    @GetMapping("/form/param")
    @ResponseBody
    public String helloGetRequestParam(@RequestParam(required = false) String name, int age) {
        return String.format("Hello, @RequestParam.<br> name = %s, age = %d", name, age);
    }
    @PostMapping("/form/param")
    @ResponseBody
    public String helloPostRequestParam(@RequestParam String name, @RequestParam int age) {
        return String.format("Hello, @RequestParam.<br> name = %s, age = %d", name, age);
    }
    // HTML에 설정된 name과 일치해지 않으면 null값이 들어오므로 주의
    @PostMapping("/form/model")
    @ResponseBody
    public String helloRequestBodyForm(@ModelAttribute Star star) {
        return String.format("Hello, @ModelAttribute.<br> (name = %s, age = %d) ", star.name, star.age);
    }
    // 데이터가 넘어오는 갯수와 양이 많다면, 하나의 객체(클래스)로 만들어서 받는 편이
    // 유지보수 측면에서 유리하다.
    // 또한, 객체를 매개변수로 받는 경우에는 반드시 생성자를 통해 값들을 넣어주어야 한다.
    // Lombok을 통해 Setter를 설정해주면, 생성자가 기본이어도 가능
    // @ModelAttribute는 생략 가능
    // 생략시 Spring이 알아볼 수 있는 이유.
    // simpleValueType의 경우, RequestParam이 생략됐다고 판단
    // 객체를 받는 경우, ModelAttribute가 생략됐다고 판단
    @GetMapping("/form/param/model")
    @ResponseBody
    public String helloRequestParam(@ModelAttribute Star star) {
        return String.format("Hello, @ModelAttribute.<br> (name = %s, age = %d) ", star.name, star.age);
    }
    // HTTP body 부분에 JSON 형식으로 데이터가 넘어오는 경우,
    // 매개변수 앞에 @RequestBody를 반드시 붙여주어야 한다.
    @PostMapping("/form/json")
    @ResponseBody
    public String helloPostRequestJson(@RequestBody Star star) {
        return String.format("Hello, @RequestBody.<br> (name = %s, age = %d) ", star.name, star.age);
    }
}

📌메모장 프로젝트

13. 메모장 프로젝트 설계

메모장 기능

  1. 접속 하자마자 메모 전체 목록 조회하기
    1. GET API 사용해서 메모 목록 불러오기
  2. 메모 생성하기
    1. POST API 사용해서 메모 신규 생성하기
    2. 생성된 메모 반환
  3. 메모 변경하기
    1. PUT API 사용해서 메모 내용 변경하기
    2. 사용자가 클릭한 메모가 DB에 존재하는지 확인하기
    3. 해당 메모 내용 변경
  4. 메모 삭제하기
    1. DELETE API 사용해서 메모 삭제하기
    2. 사용자가 삭제하려는 메모가 DB에 존재하는지 확인하기
    3. DB에서 해당 메모 삭제

API 테이블

14. Create / Read

DTO란?

Data Transfer Object: 데이터 전송 및 이동을 위해 생성되는 객체 의미

  • 클라이언트에서 보내오는 데이터를 객체로 처리할 때 사용
  • 서버의 계층 간의 이동에서 사용
  • DB와의 소통을 담당하는 Java 클래스를 DTO로 변환한 후에 반환할 때도 사용
@RestController
@RequestMapping("/api")
public class MemoController {
    // DB 대신 일단 사용
    private final Map<Long, Memo> memoList = new HashMap<>();
    @PostMapping("/memos")
    public MemoResponseDto createMemo(@RequestBody MemoRequestDto requestDto) {
        // RequestDto -> Entity
        Memo memo = new Memo(requestDto);
        // Memo Max ID Check
        Long maxId = memoList.size() > 0 ? Collections.max(memoList.keySet()) + 1 : 1;
        memo.setId(maxId);
        // DB 저장
        memoList.put(memo.getId(), memo);
        // Entity -> ResponseDto
        MemoResponseDto memoResponseDto = new MemoResponseDto(memo);
        return memoResponseDto;
    }
    @GetMapping("/memos")
    public List<MemoResponseDto> getMemos(){
        // Map to List
        List<MemoResponseDto> responseList = memoList.values().stream()
                .map(MemoResponseDto::new).toList();
        return responseList;
    }
}

15. Update / Delete

    @PutMapping("/memos/{id}")
    public Long updateMemo(@PathVariable Long id, @RequestBody MemoRequestDto requestDto){
        // 해당 메모가 DB에 존재하는지 확인
        if(memoList.containsKey(id)){
            // id에 해당하는 메모 가져오기
            Memo memo = memoList.get(id);
            memo.update(requestDto);
            return memo.getId();
        } else {
            throw new IllegalArgumentException("선택한 메모는 존재하지 않습니다!");
        }
    }
    @DeleteMapping("/memos/{id}")
    public Long deleteMemo(@PathVariable Long id){
        // 해당 메모가 Db에 존재하는지 확인
        if(memoList.containsKey(id)){
            memoList.remove(id);
            return id;
        } else{
            throw new IllegalArgumentException("선택한 메모는 존재하지 않습니다!");
        }
    }

Database와 SQL

16. Database

데이터의 집합, 정보를 저장하고 관리하는 역할
DBMS : DataBase Management System, 데이터 베이스를 관리하고 운영하는 소프트웨어
RDBMS: Relational DBMS, 관계형 데이터베이스 -> 테이블 간의 Key값을 통해 서로 관계를 맺는 DB -> 테이블 간의 결합을 통해 데이터 조작이 용이하다.

17. SQL

Structured Query Language, RDBMS에서 사용되는 언어
국제 표준화 기구에서 SQL에 대한 표준을 정의하여 발표. 각 회사, 제품마다 약간의 차이가 존재

  • DDL: Data Definition Language, 테이블이나 관계의 구조를 생성 (Create / Alter / Drop / Truncate)
  • DCL: Data Control Language, 데이터 사용 권한 관리 (Grant / Revoke)
  • DML: Data Manipulation Language, 데이터 검색, 수정, 삭제, 삽입 (Insert / Select / Update / Delete)

18. JDBC

JDBC 등장 배경

  1. DB에 연결하기 위한 커넥션을 연결
  2. SQL을 작성한 후, 커넥션을 통해 SQL 요청
  3. 요청한 SQL 결과 응답받기
  • But! DB 서버를 변경한다면, 사용 방법이 다르기 때문에 로직을 전부 수정해야한다.

  • 이를 해결한 JDBC 표준 인터페이스

  • JDBC = Java Database Connectivity, Java에서 제공하는 DB 접근 API

  • DB 회사들은 자신들의 DB에 맞도록 JDBC 인터페이스를 구현한 후, 라이브러리로 제공 (JDBC 드라이버)

Jdbc Templates

  • JDBC로 DB 교체는 간단해졌지만, DB에 연결하기 위한 여러 로직을 직접 작성하는 불편함 有
  • 커넥션 연결 / statement 준비 및 실행 / 커넥션 종료 등의 반복 작업을 대신 처리해주는 JDBC templates 등장
  • 사용법
  1. application.properties에 DB 접근을 위한 정보 작성
  2. build.gradle에 jdbc 라이브러리와 MySQL 등록하기
  3. DB 연결이 필요한 곳에서 JdbcTemplate을 주입받아 사용
profile
꾸준한 개발자가 되자! Do steady yong

0개의 댓글