[12.03] 내일배움캠프[Spring] TIL-25
1. 스프링 입문
DB SQL 을 이해하기 위해 기본 쿼리문 배워보기
CREATE TABLE IF NOT EXISTS MAJOR
(
major_code varchar(100) primary key comment '주특기코드',
major_name varchar(100) not null comment '주특기명',
tutor_name varchar(100) not null comment '튜터'
)
CREATE TABLE IF NOT EXISTS STUDENT
(
student_code varchar(100) primary key comment '수강생코드',
name varchar(100) not null comment '이름',
birth varchar(8) null comment '생년월일',
gender varchar(1) not null comment '성별',
phone varchar(11) null comment '전화번호',
major_code varchar(100) not null comment '주특기코드',
foreign key(major_code) references major(major_code)
)
CREATE TABLE IF NOT EXISTS EXAM
(
student_code varchar(100) not null comment '수강생코드',
exam_seq int not null comment '시험주차',
score decimal(10,2) not null comment '시험점수',
result varchar(1) not null comment '합불'
)
CREATE TABLE MANAGER(
id bigint PRIMARY KEY comment '관리테이블 키',
name varchar(3) not null comment '회원 이름',
student_code varchar(100) not null comment '회원 코드',
CONSTRAINT manager_fk_student_code foreign key(student_code) references STUDENT(STUDENT_CODE)
)
- Diagram

ALTER TABLE MANAGER ALTER COLUMN id bigint 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');
SELECT s.name, e.exam_seq, e.score
FROM MANAGER m JOIN STUDENT S on m.student_code = s.student_code
JOIN EXAM e on m.student_code = e.student_code WHERE m.name = 'managerA';
LTER 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;
- 중간에 AUTO_INCREMENT 값이 1부터 시작하지 않아서 다시 속성 바꾸고 싶었을 떄 사용했던 것
ALTER TABLE [TABLE명] AUTO_INCREMENT = [시작할 값];
2. Spring 써보기
- 전반적인 구조 파악하기


1) 요청이 들어온다.( URL , GET? POST? PUT? DELETE? PARAM? )
2) 들어온 요청을 바탕으로 DispatcherServlet
이 Handlermapping
에 적절한 Controller
를 찾음
3) 해당 URL을 바탕으로 호출해야 할 함수 로직을 시행 한 후 Model
에 파싱할 Data, 호출해야 할 View
를 DispatcherServlet
를 넘겨주고, ViewResoler
를 거쳐 해당 View
로 랜더링 됨.
- 주로 사용했던 라이브러리 정리
1) Spring Web
2) Lombok
-> @Getter
,Setter
,@RequiedArgsConstructor
등 제공.
3) Dev Tool
-> 소스 수정시 자동 컴파일 다시 재 기동 할 필요성 없어짐.
4) H2
-> DB
- 프로젝트는
Repository
,DTO
,Entity
,Service
,Controller
로 구성
- Controller/MemoController
package com.sparta.hanghaememo.controller;
import com.sparta.hanghaememo.dto.MemoRequestDTO;
import com.sparta.hanghaememo.entity.Memo;
import com.sparta.hanghaememo.service.MemoService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import java.util.List;
@RestController
@RequiredArgsConstructor
public class MemoController {
private final MemoService memoService;
@GetMapping("/")
public ModelAndView home() {
return new ModelAndView("index");
}
@PostMapping("/api/memos")
public Memo createMemo(@RequestBody MemoRequestDTO requestDto){
return memoService.createMemo(requestDto);
}
@GetMapping("/api/memos")
public List<Memo> getMemos(){
return memoService.getMemos();
}
@PutMapping("/api/memos/{id}")
public Long updateMemo(@PathVariable Long id,@RequestBody MemoRequestDTO requestDto){
return memoService.update(id,requestDto);
}
@DeleteMapping("/api/memos/{id}")
public Long deleteMemo(@PathVariable Long id){
return memoService.deleteMemo(id);
}
package com.sparta.hanghaememo.dto;
import lombok.Getter;
@Getter
public class MemoRequestDTO {
private String username;
private String contents;
}
package com.sparta.hanghaememo.entity;
import com.sparta.hanghaememo.dto.MemoRequestDTO;
import com.sparta.hanghaememo.repository.MemoRepository;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter
@Entity
@NoArgsConstructor
public class Memo extends Timestamped {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(nullable = false)
private String username;
@Column(nullable = false)
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();
}
}
- 의문: Update쿼리 사용시, Repository에 접근하지 않고, Entity에서 직접 작업한 점
👉 아마 Remote Data 가 아닌 in - Memory구조의 H2를 사용하고 있어서, 여기가 DB역할을 하는 것 같다..!
- entity/TimeStamped
👉 DB추가시 생성날짜를 자동으로 기록하기 위한 class
package com.sparta.hanghaememo.entity;
import jakarta.persistence.EntityListeners;
import jakarta.persistence.MappedSuperclass;
import lombok.Getter;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import java.time.LocalDateTime;
@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public class Timestamped {
@CreatedDate
private LocalDateTime createdAt;
@LastModifiedDate
private LocalDateTime modifiedAt;
}
- repository/MemoRepository
package com.sparta.hanghaememo.repository;
import com.sparta.hanghaememo.entity.Memo;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface MemoRepository extends JpaRepository<Memo, Long> {
List<Memo> findAllByOrderByModifiedAtDesc();
}
package com.sparta.hanghaememo.service;
import com.sparta.hanghaememo.dto.MemoRequestDTO;
import com.sparta.hanghaememo.entity.Memo;
import com.sparta.hanghaememo.repository.MemoRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
@RequiredArgsConstructor
public class MemoService {
private final MemoRepository memoRepository;
@Transactional
public Memo createMemo(MemoRequestDTO requestDto) {
Memo memo = new Memo(requestDto);
memoRepository.save(memo);
return memo;
}
@Transactional(readOnly = true)
public List<Memo> getMemos() {
return memoRepository.findAllByOrderByModifiedAtDesc();
}
@Transactional
public Long update(Long id, MemoRequestDTO requestDto) {
Memo memo = memoRepository.findById(id).orElseThrow(
() -> new IllegalArgumentException("아이디가 존재하지 않습니다!")
);
memo.update(requestDto);
return memo.getId();
}
@Transactional
public Long deleteMemo(Long id) {
memoRepository.deleteById(id);
return id;
}
}
package com.sparta.hanghaememo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
@SpringBootApplication
@EnableJpaAuditing
public class HanghaememoApplication {
public static void main(String[] args) {
SpringApplication.run(HanghaememoApplication.class, args);
}
}