Notice
Recent Posts
Recent Comments
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 |
Tags
- JAVA객체지향
- OPP개념
- 시스템 환경 변수 편집
- java변수
- for문
- 집합관계
- IntelliJ IDEA
- Java
- this예약어
- Java데이터 타입
- 자바 멀티스레딩
- 반복문
- 컴파일
- Thread
- While
- 생성자
- JAVA기초
- 연관관계
- 접근제어지시자
- continue문
- 메서드
- 인텔리제이 기초 설정
- 인텔리제이 한글 깨짐 해결법
- multi-threading
- 형 변환
- break문
- 상수
- function
- 메서드 오버로딩
- 포함관계
Archives
- Today
- Total
최원종의 개발 블로그
V2(PersistentContext)-패키지 구조 변경 본문
기존 패키지 구조
V1: 계층 중심 패키지 구조
com.tenco.blog
├── controller/ # 계층별 분리
│ ├── BoardController
│ └── UserController
├── model/ # 모든 엔티티가 한 곳에
│ ├── Board
│ └── User
├── service/ # 모든 서비스 클래스가 한 곳에
│ ├── BoardService
├── repository/ # 모든 리포지토리가 한 곳에
│ ├── BoardNativeRepository
│ └── UserRepository
├── dto/ # 모든 DTO가 한 곳에
│ ├── BoardRequest
│ └── UserRequest
└── util/
└── MyDateUtil
// 문제점: Board 관련 파일들이 여러 패키지에 흩어져 있음
// BoardController ← controller 패키지
// Board ← model 패키지
// BoardRepository ← repository 패키지
// BoardRequest ← dto 패키지
도메인 중심 구조로 전환
도메인이란?
도메인(Domain)은 소프트웨어가 해결하려는 문제 영역이나 비즈니스 영역을 의미
블로그 시스템의 도메인
Board (게시글) 도메인
- 게시글 작성, 수정, 삭제, 조회
- 조회수 증가, 인기글 선정
- 게시글 상태 관리 (공개/비공개/임시저장)
User (사용자) 도메인
- 회원가입, 로그인, 프로필 관리
- 권한 관리, 활동 이력
Comment (댓글) 도메인
- 댓글 작성, 수정, 삭제
- 대댓글, 댓글 좋아요
Category (카테고리) 도메인
- 카테고리 생성, 관리
- 게시글 분류
변경할 프로젝트 형태
com.tenco.blog
├── board/ # Board 도메인의 모든 것이 한 곳에
│ ├── Board # 엔티티
│ ├── BoardController # 컨트롤러
│ ├── BoardPersistRepository # 리포지토리
│ └── BoardRequest # DTO
├── user/ # User 도메인의 모든 것이 한 곳에
│ ├── User
│ ├── UserController
│ ├── UserRepository
│ └── UserRequest
└── utils/ # 공통 기능
└── MyDateUtil
// 장점: Board 관련된 모든 클래스가 board 패키지에 응집
- board/Board.java 코드
package com.tenco.blog.board;
import com.tenco.blog.util.MyDateUtil;
import jakarta.persistence.*;
import lombok.Data;
import java.sql.Timestamp;
@Data // get,set, toString ..
// @Entity - JPA가 이 클래스를 데이터베이스 테이블과 매핑하는 객체로 인식하게 설정
// 즉, 이 어노테이션이 있어야 JPA가 관리 함
@Entity
@Table(name = "board_tb")
public class Board {
// @id : 이 필드가 기본키임을 설정 함
@Id
// IDENTITY 전략: 데이터베이스게 기본 AUTO_INCREMENT 기능 사용
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String username;
private String title;
private String content;
private Timestamp createdAt;
// createdAt -> 포멧 하는 메서드 만들어 보기
public String getTime() {
return MyDateUtil.timestampFormat(createdAt);
}
}
중요 정리
// @Entity - JPA가 이 클래스를 데이터베이스 테이블과 매핑하는 객체로 인식하게 설정
// 즉, 이 어노테이션이 있어야 JPA가 관리 함
// @id : 이 필드가 기본키임을 설정 함
// IDENTITY 전략: 데이터베이스게 기본 AUTO_INCREMENT 기능 사용
board/BoardController.java 코드
package com.tenco.blog.board;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
@Slf4j
@Controller // IoC
@RequiredArgsConstructor // DI
public class BoardController {
// DI
private final BoardNativeRepository boardNativeRepository;
/**
* 게시글 작성 화면 요청
* @return 페이지 반환
* 주소설계 : http://localhost:8080/board/save-form
*/
@GetMapping("/board/save-form")
public String saveForm() {
return "board/save-form";
}
/**
* 게시글 작성 기능 요청
* @return 페이지 반환
* 주소설계 : http://localhost:8080/board/save-form
*/
@PostMapping("/board/save")
public String saveProc(
@RequestParam("username") String username,
@RequestParam("title") String title,
@RequestParam("content") String content) {
log.info("username : " + username);
log.info("title : " + title);
log.info("content : " + content);
// insert + 트랜잭션 처리
boardNativeRepository.save(title, content, username);
// redirect <-- 다시 URL 요청 해 !
//return "redirect:/";
return "redirect:/";
}
/**
* 게시글 목록 화면 요청
* 주소설계 : http://localhost:8080/
*/
@GetMapping({"/", "index"})
public String list(Model model) {
List<Board> boardList = boardNativeRepository.findAll();
model.addAttribute("boardList", boardList);
return "board/list";
}
// 게시글 상세보기 화면 요청
// http://localhost:8080/board/1
@GetMapping("/board/{id}")
public String detailPage(@PathVariable(name = "id") Integer id, Model model) {
// 유효성 검사 , 인증 검사
Board board = boardNativeRepository.findById(id);
model.addAttribute("board", board);
return "board/detail";
}
// /board/{{board.id}}/delete
@PostMapping("/board/{id}/delete")
public String deleteProc(@PathVariable(name = "id") Integer id) {
boardNativeRepository.deleteById(id);
// PRG 패턴( Post-> Redirect -> Get) 적용
return "redirect:/";
}
// http://localhost:8080/board/1/update-form
@GetMapping("/board/{id}/update-form")
public String updateFormPage(@PathVariable(name = "id") Integer id, Model model) {
// 사용자 에게 해당 게시물 내용을 보여 줘야 한다.
// 조회 기능 - 게시글 id로
Board board = boardNativeRepository.findById(id);
model.addAttribute("board", board);
return "board/update-form";
}
// /board/{id}/update
@PostMapping("/board/{id}/update")
public String updateProc(@PathVariable(name = "id") Integer id,
@RequestParam(name = "username") String username,
@RequestParam(name = "title") String title,
@RequestParam(name = "content") String content) {
log.info("username : " + username);
log.info("title : " + title);
log.info("content : " + content);
log.info("id : " + id);
boardNativeRepository.updateById(username, title, content, id);
// 게시글 수정 완료 ---> 게시글 목록, 게시글 상세보기 화면
// 리다이렉트는 뷰 리졸브 동작이 아닌 (내부 파일 찾는 것이 아니고)
// 그냥 새로은 HTTP Get 요청이다.
return "redirect:/board/" + id;
}
}
중요 정리
@Controller // IoC (Inversion of Control): 제어의 역전
//주도권을 내가 아닌 프레임워크(Spring)가 갖는 것
@RequiredArgsConstructor // DI(Dependency Injection): 의존성 주입
// 필요한 부품을 외부에서 끼워주는 것
// PRG 패턴( Post-> Redirect -> Get) 적용
board/BoardNativeRepository.java코드
package com.tenco.blog.board;
import jakarta.persistence.EntityManager;
import jakarta.persistence.Query;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository // Ioc + DI
@RequiredArgsConstructor
public class BoardNativeRepository {
// EntityManager: JPA 핵심 인터페이스
// 데이터베이스와 모든 작업을 담당
private final EntityManager em;
// 트랜잭션 처리
@Transactional
public void save(String title, String content, String username) {
Query query = em.createNativeQuery("insert " +
"into board_tb(title, content, username, created_at) values (?, ?, ?, now())");
query.setParameter(1, title);
query.setParameter(2, content);
query.setParameter(3, username);
query.executeUpdate();
}
// 게시글 목록 조회 메서드
public List<Board> findAll() {
String sql = """
select * from board_tb order by id desc
""";
// while(rs.next) { Board board = new Board(); board.setTile(rs.getString("title)))}
Query query = em.createNativeQuery(sql, Board.class);
return query.getResultList();
}
// 게시글 상세 보기 (특정 ID로 조회)
public Board findById(Integer id) {
String strQuery = """
select * from board_tb where id = ?
""";
try {
Query query = em.createNativeQuery(strQuery, Board.class);
query.setParameter(1, id);
return (Board) query.getSingleResult();
} catch (Exception e) {
return null;
}
}
// 게시글 삭제 하기
@Transactional
public void deleteById(Integer id) {
Query query = em.createNativeQuery("delete from board_tb where id = ?");
query.setParameter(1, id);
query.executeUpdate();
}
// 게시글 수정하기
@Transactional
public boolean updateById(String username, String title, String content, Integer id) {
String queryStr = """
update board_tb set username = ?, title = ?, content = ? where id = ?
""";
Query query = em.createNativeQuery(queryStr);
query.setParameter(1, username);
query.setParameter(2, title);
query.setParameter(3, content);
query.setParameter(4, id);
int rows = query.executeUpdate();
if(rows > 0) {
return true;
} else {
return false;
}
}
}
중요정리
@Repository // Ioc + DI
// EntityManager: JPA 핵심 인터페이스
// 데이터베이스와 모든 작업을 담당
private final EntityManager em;'Spring boot 입문' 카테고리의 다른 글
| V2(PersistentContext) 게시글 목록 보기 - Persistence Context와 JPQL 활용 (0) | 2026.05.07 |
|---|---|
| V2(PersistentContext) 게시글 작성 - PersistenceContext 활용 (0) | 2026.05.07 |
| V2(PersistentContext)- 영속성 컨텍스트 개념 정리 (0) | 2026.04.30 |
| V1(익명블로그)-게시글 수정하기 (0) | 2026.04.30 |
| V1(익명블로그)-게시글 삭제하기 (0) | 2026.04.30 |
