[내배캠 Java 6기] Spring 1주차 주특기 입문 (16 ~ 24)

ekkkyo_j·2024년 8월 14일

[내배캠 Java 6기] TIL

목록 보기
19/38

스탠다드 실습반 OT

📌 IoC 제어 역전
프로그램 제어 흐름의 주도권을 외부로 넘겨주는 것

📌 DI 의존성 주입
객체가 필요한 종속성을 외부에서 주입해주는 것을 “의존성 주입”

=> IOC는 느슨한 결합을 만들기 위한 틀이고, 그 과정으로 DI를 사용한다.

16. 메모장 프로젝트

메모 생성(Create), 메모 조회(Read), 메모 수정(Update), 메모 삭제(Delete)를 구현한다.

17. Create, Read 구현하기

entity pacakge -> Memo.java

package com.sparta.memo.entity;

import com.sparta.memo.dto.MemoRequestDto;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
public class Memo {
    private Long id;
    private String username;
    private String contents;

    public Memo(MemoRequestDto requestDto) {
        this.username = requestDto.getUsername();
        this.contents = requestDto.getContents();
    }
}

dto pacakge -> MemoRequestDto.java

package com.sparta.memo.dto;

import lombok.Getter;

@Getter
public class MemoRequestDto {
    private String username;
    private String contents;
}

dto pacakge -> MemoResponseDto.java

package com.sparta.memo.dto;

import com.sparta.memo.entity.Memo;
import lombok.Getter;

@Getter
public class MemoResponseDto {
    private Long id;
    private String username;
    private String contents;

    public MemoResponseDto(Memo memo) {
        this.id = memo.getId();
        this.username = memo.getUsername();
        this.contents = memo.getContents();
    }
}

controller package -> MemoController.java

package com.sparta.memo.controller;

import com.sparta.memo.dto.MemoRequestDto;
import com.sparta.memo.dto.MemoResponseDto;
import com.sparta.memo.entity.Memo;
import org.springframework.web.bind.annotation.*;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/api")
public class MemoController {

    private final Map<Long, Memo> memoList=  new HashMap<>();
    @PostMapping("/memos")
    public MemoResponseDto create(@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;
    }
}

18. Update, Delete 구현하기

controller package -> MemoController.java

    @PutMapping("/memos/{id}")
    public Long updateMemo(@PathVariable Long id, @RequestBody MemoRequestDto requestDto) {
        // 해당 메모가 DB에 존재하는지 확인
        if(memoList.containsKey(id)) {
            // 해당 메모 가져오기
            Memo memo = memoList.get(id);

            // memo 수정
            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("선택한 메모는 존재하지 않습니다.");
        }
    }

19. JdbcTemplate 적용

application.properties 설정

spring.application.name=memo
spring.datasource.url=jdbc:mysql://localhost:3306/memo
spring.datasource.username=root
spring.datasource.password={비밀번호}
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

controller package -> MemoController.java

package com.sparta.memo.controller;

import com.sparta.memo.dto.MemoRequestDto;
import com.sparta.memo.dto.MemoResponseDto;
import com.sparta.memo.entity.Memo;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.web.bind.annotation.*;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;

@RestController
@RequestMapping("/api")
public class MemoController {

    // JDBC DB 생성
    private final JdbcTemplate jdbcTemplate;

    // JDBC DB 초기화 <-final 이므로
    public MemoController(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    @PostMapping("/memos")
    public MemoResponseDto createMemo(@RequestBody MemoRequestDto requestDto) {
        // RequestDto -> Entity
        Memo memo = new Memo(requestDto);

        // DB 저장
        KeyHolder keyHolder = new GeneratedKeyHolder(); // 기본 키를 반환받기 위한 객체

        String sql = "INSERT INTO memo (username, contents) VALUES (?, ?)"; // 값은 동적이므로 ?, ?
        jdbcTemplate.update( con -> {
                    PreparedStatement preparedStatement = con.prepareStatement(sql,
                            Statement.RETURN_GENERATED_KEYS);

                    preparedStatement.setString(1, memo.getUsername());
                    preparedStatement.setString(2, memo.getContents());
                    return preparedStatement;
                },
                keyHolder);

        // DB Insert 후 받아온 기본키 확인
        Long id = keyHolder.getKey().longValue();
        memo.setId(id);

        // Entity -> ResponseDto
        MemoResponseDto memoResponseDto = new MemoResponseDto(memo);

        return memoResponseDto;
    }

    @GetMapping("/memos")
    public List<MemoResponseDto> getMemos() {
        // DB 조회
        String sql = "SELECT * FROM memo";

        return jdbcTemplate.query(sql, new RowMapper<MemoResponseDto>() {
            @Override
            public MemoResponseDto mapRow(ResultSet rs, int rowNum) throws SQLException {
                // SQL 의 결과로 받아온 Memo 데이터들을 MemoResponseDto 타입으로 변환해줄 메서드
                Long id = rs.getLong("id");
                String username = rs.getString("username");
                String contents = rs.getString("contents");
                return new MemoResponseDto(id, username, contents);
            }
        });
    }

    @PutMapping("/memos/{id}")
    public Long updateMemo(@PathVariable Long id, @RequestBody MemoRequestDto requestDto) {
        // 해당 메모가 DB에 존재하는지 확인
        Memo memo = findById(id);
        if(memo != null) {
            // memo 내용 수정
            String sql = "UPDATE memo SET username = ?, contents = ? WHERE id = ?";
            jdbcTemplate.update(sql, requestDto.getUsername(), requestDto.getContents(), id);

            return id;
        } else {
            throw new IllegalArgumentException("선택한 메모는 존재하지 않습니다.");
        }
    }

    @DeleteMapping("/memos/{id}")
    public Long deleteMemo(@PathVariable Long id) {
        // 해당 메모가 DB에 존재하는지 확인
        Memo memo = findById(id);
        if(memo != null) {
            // memo 삭제
            String sql = "DELETE FROM memo WHERE id = ?";
            jdbcTemplate.update(sql, id);

            return id;
        } else {
            throw new IllegalArgumentException("선택한 메모는 존재하지 않습니다.");
        }
    }

    private Memo findById(Long id) {
        // DB 조회
        String sql = "SELECT * FROM memo WHERE id = ?";

        return jdbcTemplate.query(sql, resultSet -> {
            if(resultSet.next()) {
                Memo memo = new Memo();
                memo.setUsername(resultSet.getString("username"));
                memo.setContents(resultSet.getString("contents"));
                return memo;
            } else {
                return null;
            }
        }, id);
    }
}

dto pacakge -> MemoResponseDto.java

package com.sparta.memo.dto;

import com.sparta.memo.entity.Memo;
import lombok.Getter;

@Getter
public class MemoResponseDto {
    private Long id;
    private String username;
    private String contents;

    public MemoResponseDto(Memo memo) {
        this.id = memo.getId();
        this.username = memo.getUsername();
        this.contents = memo.getContents();
    }

    public MemoResponseDto(Long id, String username, String contents) {
        this.id = id;
        this.username = username;
        this.contents = contents; 
    }
}

20 ~ 24 SQL

숙제
1번 수강생을 관리하는 MANAGER 테이블을 만들어보세요.

  • 컬럼은 총 id, name, student_code 입니다.
  • id는 bigint 타입이며 PK입니다.
  • name은 최소 2자 이상, varchar 타입, not null 입니다.
  • student_code는 STUDENT 테이블을 참조하는 FK이며 not null 입니다.
  • FK는 CONSTRAINT 이름을 ‘manager_fk_student_code’ 로 지정해야합니다.
/* 1 번 답안 */
CREATE TABLE if not exists MANAGER
(
    id bigint primary key comment '관리자 ID',
    name varchar(2) not null comment '관리자 이름',
    student_code varchar(100) not null comment '수강생 코드',
    CONSTRAINT manager_fk_student_code FOREIGN KEY(student_code) REFERENCES STUDENT(student_code)
);


2번 ALTER, MODIFY를 이용하여 MANAGER 테이블의 id 컬럼에 AUTO_INCREMENT 기능을 부여하세요.
/* 2 번 답안 */

ALTER TABLE MANAGER MODIFY COLUMN id bigint AUTO_INCREMENT;

3번 INSERT를 이용하여 수강생 s1, s2, s3, s4, s5를 관리하는 managerA와 s6, s7, s8, s9를 관리하는 managerB를 추가하세요.

  • AUTO_INCREMENT 기능을 활용하세요
/* 3 번 답안 */
INSERT INTO MANAGER (name, student_code) VALUES('mA', 's1');
INSERT INTO MANAGER (name, student_code) VALUES('mA', 's2');
INSERT INTO MANAGER (name, student_code) VALUES('mA', 's3');
INSERT INTO MANAGER (name, student_code) VALUES('mA', 's4');
INSERT INTO MANAGER (name, student_code) VALUES('mA', 's5');

INSERT INTO MANAGER (name, student_code) VALUES('mB', 's6');
INSERT INTO MANAGER (name, student_code) VALUES('mB', 's7');
INSERT INTO MANAGER (name, student_code) VALUES('mB', 's8');
INSERT INTO MANAGER (name, student_code) VALUES('mB', 's9');


4번 JOIN을 사용하여 managerA가 관리하는 수강생들의 이름과 시험 주차 별 성적을 가져오세요.
/* 4번 답안 */
/* mA 관리를 받는 학생들의 이름과, 주차별 시험점수 */
/* DISTINCT: 중복 값 삭제 */
SELECT DISTINCT
    s.name AS student_name,
    e.exam_seq AS exam_sequence,
    e.score AS exam_score
FROM
    MANAGER m
JOIN
    STUDENT s ON m.student_code = s.student_code
JOIN
    Exam e ON s.student_code = e.student_code
WHERE
    m.name = 'mA';

5번. STUDENT 테이블에서 s1 수강생을 삭제했을 때 EXAM에 있는 s1수강생의 시험성적과 MANAGER의 managerA가 관리하는 수강생 목록에 자동으로 삭제될 수 있도록 하세요.

  • ALTER, DROP, MODIFY, CASCADE 를 사용하여 EXAM, MANAGER 테이블을 수정합니다.
/* 5번 답안 */
ALTER TABLE EXAM DROP FOREIGN KEY exam_fk_student_code;
ALTER TABLE EXAM ADD CONSTRAINT exam_fk_student_code
    FOREIGN KEY (student_code) REFERENCES STUDENT(student_code)
        ON DELETE CASCADE;


ALTER TABLE MANAGER DROP FOREIGN KEY manager_fk_student_code;
ALTER TABLE MANAGER ADD CONSTRAINT manager_fk_student_code
    FOREIGN KEY (student_code) REFERENCES STUDENT(student_code)
        ON DELETE CASCADE;
profile
게으르지만 성실히 공부하기^_^

0개의 댓글