build.gradle의 dependecies에 아래 코드 추가

    // JPA 설정
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    // MySQL
    implementation 'mysql:mysql-connector-java:8.0.28'

 

application.properties에 DB 정보 추가

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

spring.jpa.hibernate.ddl-auto=update

spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.use_sql_comments=true

 

Entity 클래스 작성

package com.sparta.memo.entity;

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

@Entity // JPA가 관리할 수 있는 Entity 클래스 지정
@Getter
@Setter
@Table(name = "memo") // 매핑할 테이블의 이름을 지정
@NoArgsConstructor
public class Memo {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column(name = "username", nullable = false)
    private String username;
    @Column(name = "contents", nullable = false, length = 500)
    private String contents;

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

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

 

레포지토리를 JpaRepository를 상속받는 인터페이스로 수정

package com.sparta.blog.repository;

import com.sparta.blog.entity.Post;
import org.springframework.data.jpa.repository.JpaRepository;


public interface PostRepository extends JpaRepository<Post, Long> {

}

 

 

컨트롤러 클래스 수정

package com.sparta.memo.controller;

import com.sparta.memo.dto.MemoRequestDto;
import com.sparta.memo.dto.MemoResponseDto;
import com.sparta.memo.service.MemoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

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

    private final MemoService memoService;

    @Autowired
    public MemoController(MemoService memoService) {
        this.memoService = memoService;
    }

    @PostMapping("/memos")
    public MemoResponseDto createMemo(@RequestBody MemoRequestDto requestDto) {
        return memoService.createMemo(requestDto);
    }

    @GetMapping("/memos")
    public List<MemoResponseDto> getMemos() {
        return memoService.getMemos();
    }

    @PutMapping("/memos/{id}")
    public Long updateMemo(@PathVariable Long id, @RequestBody MemoRequestDto requestDto) {
        return memoService.updateMemo(id, requestDto);
    }

    @DeleteMapping("/memos/{id}")
    public Long deleteMemo(@PathVariable Long id) {
        return memoService.deleteMemo(id);
    }

}

 

서비스 클래스 수정

package com.sparta.memo.service;

import com.sparta.memo.dto.MemoRequestDto;
import com.sparta.memo.dto.MemoResponseDto;
import com.sparta.memo.entity.Memo;
import com.sparta.memo.repository.MemoRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
public class MemoService {

    private final MemoRepository memoRepository;

    public MemoService(MemoRepository memoRepository) {
        this.memoRepository = memoRepository;
    }

    public MemoResponseDto createMemo(MemoRequestDto requestDto) {
        // RequestDto -> Entity
        Memo memo = new Memo(requestDto);

        // DB 저장
        Memo saveMemo = memoRepository.save(memo);

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

        return memoResponseDto;
    }

    public List<MemoResponseDto> getMemos() {
        // DB 조회
        return memoRepository.findAllByOrderByModifiedAtDesc().stream().map(MemoResponseDto::new).toList();
    }

    @Transactional
    public Long updateMemo(Long id, MemoRequestDto requestDto) {
        // 해당 메모가 DB에 존재하는지 확인
        Memo memo = findMemo(id);

        // memo 내용 수정
        memo.update(requestDto);

        return id;
    }

    public Long deleteMemo(Long id) {
        // 해당 메모가 DB에 존재하는지 확인
        Memo memo = findMemo(id);

        // memo 삭제
        memoRepository.delete(memo);

        return id;
    }

    private Memo findMemo(Long id) {
        return memoRepository.findById(id).orElseThrow(() ->
                new IllegalArgumentException("선택한 메모는 존재하지 않습니다.")
        );
    }
}

'TIL > WEEK5' 카테고리의 다른 글

IoC와 DI  (1) 2023.06.14
1주차 숙제  (0) 2023.06.13
Spring 입문 1주차  (0) 2023.06.12

IoC(Inversion of Control) 제어의 역전

개발자가 직접 객체의 생성과 소멸 객체간 관계같은 객체의 제어를 수행하는 것이 아니라, 여러 프레임워크, 컨테이너에서 제어를 수행하는 것

 

 

DI(Dependency Injection) 의존성 주입

객체를 직접 생성하지 않고 외부에서 미리 만든 객체를 주입하는 것 → 클래스 간 결합을 느슨하게 해서 어떤 클래스의 변경이 그 클래스를 이용하는 다른 클래스에 미치는 영향을 줄인다.

 

  • ⭐️⭐️⭐️생성자를 통한 주입(거의 이거 씀)

Consumer consumer = new Consumer(new Chicken()); 와 같이 생성자를 통해 주입

public class Consumer {

    Food food;

    public Consumer(Food food) {
        this.food = food;
    }

    void eat() {
        this.food.eat();
    }

    public static void main(String[] args) {
        Consumer consumer = new Consumer(new Chicken());
        consumer.eat();

        consumer = new Consumer(new Pizza());
        consumer.eat();
    }
}

interface Food {
    void eat();
}

class Chicken implements Food{
    @Override
    public void eat() {
        System.out.println("치킨을 먹는다.");
    }
}

class Pizza implements Food{
    @Override
    public void eat() {
        System.out.println("피자를 먹는다.");
    }
}

 

 

 

  • 메서드를 통한 주입

consumer.setFood(new Chicken()); 와 같이 setFood 메서드로 주입

public class Consumer {

    Food food;

    void eat() {
        this.food.eat();
    }

    public void setFood(Food food) {
        this.food = food;
    }

    public static void main(String[] args) {
        Consumer consumer = new Consumer();
        consumer.setFood(new Chicken());
        consumer.eat();

        consumer.setFood(new Pizza());
        consumer.eat();
    }
}

interface Food {
    void eat();
}

class Chicken implements Food{
    @Override
    public void eat() {
        System.out.println("치킨을 먹는다.");
    }
}

class Pizza implements Food{
    @Override
    public void eat() {
        System.out.println("피자를 먹는다.");
    }
}

 

 

  • 필드에 직접 주입(잘 안 씀)

consumer.food = new Chicken();

public class Consumer {

    Food food;

    void eat() {
        this.food.eat();
    }

    public static void main(String[] args) {
        Consumer consumer = new Consumer();
        consumer.food = new Chicken();
        consumer.eat();

        consumer.food = new Pizza();
        consumer.eat();
    }
}

interface Food {
    void eat();
}

class Chicken implements Food{
    @Override
    public void eat() {
        System.out.println("치킨을 먹는다.");
    }
}

class Pizza implements Food{
    @Override
    public void eat() {
        System.out.println("피자를 먹는다.");
    }
}

 

 

  • +) Lombok 사용

클래스 위에 @RequiredArgsConstructor를 달고 멤버 변수에 final을 달아준다.

@Component
@RequiredArgsConstructor // final로 선언된 멤버 변수를 파라미터로 사용하여 생성자를 자동으로 생성합니다.
public class MemoService {
    private final MemoRepository memoRepository;
}

 

 

 

 

IoC Container 

bean들을 모아둔 하나의 컨테이너

 

 

Bean

스프링이 관리하고 있는 객체, 이름은 클래스 명에서 첫 글자를 소문자로 바꾼 것으로 결정된다.

  • 클래스 위에 @Component를 달면 bean으로 등록된다.

3 Layer Annotation

Controller, Service, Repository의 역할로 구분된 클래스들은 @Component 대신 각각

  1. @Controller, @RestController
  2. @Service
  3. @Repository

를 달아주면 된다.

 

  • 객체의 의존성을 가지는 부분(객체를 주입 받는 부분)에 @Autowired를 달아준다. 생성자가 1개일 땐 생략 가능하다.
@RestController
@RequestMapping("/api")
public class MemoController {

    private final MemoService memoService;

    @Autowired
    public MemoController(MemoService memoService) {
        this.memoService = memoService;
    }
    
    ....
}

위 코드에서 생성자는 MemoController(MemoService memoService) 하나이므로 @Autowired를 생략해도 된다.

 

 

 

 

 

'TIL > WEEK5' 카테고리의 다른 글

SpringBoot의 JPA  (0) 2023.06.15
1주차 숙제  (0) 2023.06.13
Spring 입문 1주차  (0) 2023.06.12

CREATE TABLE IF NOT EXISTS MANAGER
(
    id bigint primary key,
    name varchar(100) not null,
    student_code varchar(100) not null,
    constraint manager_fk_student_code foreign key(student_code) references STUDENT(student_code)
);

 

문제 2

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

ALTER TABLE MANAGER MODIFY COLUMN id bigint NOT NULL AUTO_INCREMENT;

 

문제 3

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

AUTO_INCREMENT 기능을 활용하세요.

INSERT INTO MANAGER(name, student_code) VALUES ('managerA', 's1');
INSERT INTO MANAGER(name, student_code) VALUES ('managerA', 's2');
INSERT INTO MANAGER(name, student_code) VALUES ('managerA', 's3');
INSERT INTO MANAGER(name, student_code) VALUES ('managerA', 's4');
INSERT INTO MANAGER(name, student_code) VALUES ('managerA', 's5');

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

 

문제 4

JOIN을 사용하여 managerA가 관리하는 수강생들의 이름과 시험 주차 별 성적을 가져오세요.

SELECT s.name, e.exam_seq, e.score
FROM MANAGER m JOIN STUDENT S on S.student_code = m.student_code
JOIN EXAM E on S.student_code = E.student_code
WHERE m.name = 'managerA';

 

문제 5

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

  • ALTER, DROP, MODIFY, CASCADE 를 사용하여 EXAM, MANAGER 테이블을 수정합니다.
ALTER TABLE EXAM DROP CONSTRAINT 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 CONSTRAINT manager_fk_student_code;
ALTER TABLE MANAGER ADD CONSTRAINT manager_fk_student_code FOREIGN KEY(student_code) REFERENCES STUDENT(student_code) ON DELETE CASCADE;

DELETE FROM STUDENT WHERE student_code = 's1';

기존 제약조건을 지우고 ON DELETE CASCADE 옵션을 걸어 다시 설정해준다.

'TIL > WEEK5' 카테고리의 다른 글

SpringBoot의 JPA  (0) 2023.06.15
IoC와 DI  (1) 2023.06.14
Spring 입문 1주차  (0) 2023.06.12

Gradle

빌드 자동화 시스템

빌드란 소스코드를 실행 가능한 결과물로 만드는 일련의 과정

java 소스 코드 ➡️ jar 파일

 

 

Spring MVC

 

Model

  • 데이터와 비즈니스 로직을 담당
  • 데이터 베이스와 연동해 데이터를 불러오고 저장하는 작업을 수행

View

  • 사용자 인터페이스를 담당
  • 사용자가 보는 화면과 버튼, 폼 등을 디자인하고 구현 (html)

Controller

  • Model과 View 사이의 상호작용을 조정하고 제어
  • 사용자의 입력을 받아 Model에 전달하고, Model의 결과를 바탕으로 View를 업데이트

 

 

 

데이터를 Client에 반환하는 방법

  • JSON 데이터 반환하는 방법

템플릿 엔진이 적용된 SpringBoot에서는 Controller에서 문자열을 반환하면 templates 폴더에서 해당 문자열의 .html 파일을 찾아서 반환한다.

   @GetMapping("/html/templates")
    public String htmlTemplates() {
        return "hello";
    }

 

따라서 html 파일이 아닌 JSON 데이터를 브라우저에 반환하고 싶다면 해당 메서드에 @ResponseBody 애너테이션을 추가해줘야 한다.

@GetMapping("/response/json/string")
@ResponseBody
public String helloStringJson() {
    return "{\"name\":\"Robbie\",\"age\":95}";
}

+ "(큰 따옴표)는 그냥 쓰면 출력이 안되므로 앞에 \을 붙여준다.

 

Spring에서 자동으로 객체를 JSON으로 변환해 준다.

@GetMapping("/response/json/class")
@ResponseBody
public Star helloClassJson() {
    return new Star("Robbie", 95);
}

http://localhost:8080/response/json/class

  • @RestController

@RestController를 사용하면 해당 클래스의 모든 메서드에 @ResponseBody 애너테이션이 추가되는 효과를 부여할 수 있다.

@RestController = @Controller + @ResponseBody

 

 

 

Serialize(직렬화)

Object ➡️ JSON

@Test
@DisplayName("Object To JSON : get Method 필요")
void test1() throws JsonProcessingException {
    Star star = new Star("Robbie", 95);

    ObjectMapper objectMapper = new ObjectMapper(); // Jackson 라이브러리의 ObjectMapper
    String json = objectMapper.writeValueAsString(star);

    System.out.println("json = " + json);
}

Object를 JSON 타입의 String으로 변환하기 위해서는 해당 Object에 get Method가 필요하다.

 

Deserialize(역직렬화)

JSON ➡️ Object

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

JSON 타입의 String을 Object로 변환하기 위해서는 해당 Object에 기본 생성자get 혹은 set 메서드가 필요하다.

'TIL > WEEK5' 카테고리의 다른 글

SpringBoot의 JPA  (0) 2023.06.15
IoC와 DI  (1) 2023.06.14
1주차 숙제  (0) 2023.06.13

+ Recent posts