inblog logo
|
vosw1
    Spring

    게시판 만들기 - 실습

    Feb 02, 2024
    게시판 만들기 - 실습

    1. 로그인을 안하면 안 보여주기

    • owner 세션이 있으면 로그인이 된 것
    게시물 아이디랑 내 세션 정보의 아이디가 동일해야 함
    notion image
     
    • 세션에 접근하는 방법 session.getAttribute();
     
    • 로그인 안되도 들어갈 수 있는 것도 잡아야 함
    권한 체크하기
    package shop.mtcoding.blog.board; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpSession; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestParam; import shop.mtcoding.blog._core.PagingUtil; import shop.mtcoding.blog.user.User; import java.util.List; @RequiredArgsConstructor @Controller public class BoardController { private final HttpSession session; private final BoardRepository boardRepository; // http://localhost:8080?page=0 @GetMapping({"/", "/board"}) public String index(HttpServletRequest request, @RequestParam(defaultValue = "0") int page) { //System.out.println("페이지: "+page); List<Board> boardList = boardRepository.findAll(page); request.setAttribute("boardList", boardList); // 가방에 담음 int currentPage = page; int nextPage = currentPage + 1; int prevPage = currentPage - 1; request.setAttribute("nextPage", nextPage); request.setAttribute("prevPage", prevPage); // 이것만 담으면 disable 못함 // 현재 페이지가 퍼스트인지 라스트인지 만든다. boolean first = PagingUtil.isFirst(currentPage); boolean last = PagingUtil.isLast(currentPage, 4); request.setAttribute("first", first); request.setAttribute("last", last); return "index"; } @GetMapping("/board/saveForm") public String saveForm() { return "board/saveForm"; } // 상세보기시 호출 @GetMapping("/board/{id}") // 1이 프라이머리키 -> 뭐든 넣어도 실행시키려면 변수화시켜서 {} public String detail(@PathVariable int id, HttpServletRequest request) { // 파싱하게 치환해서 알려줌 BoardResponse.DetailDTO reponseDTO = boardRepository.findById(id); request.setAttribute("board", reponseDTO); // 키를 통해 값을 찾음 // 1. 해당 페이지의 주인 여부 boolean owner = false; // 목적 // 2. 작성자 userId 확인하기 int boardUserId = reponseDTO.getUserId(); // 3. 로그인 여부 체크 User sessionUser = (User) session.getAttribute("sessionUser"); if (sessionUser != null) { // 로그인 했고 if (boardUserId == sessionUser.getId()) { owner = true; } } request.setAttribute("owner", owner); return "board/detail"; } }
    notion image
     

    2. 보드 상세보기할 때

    • 보드만 조회 하는게 아니라 유저를 같이 조회해야 되서 데이터를 못 담았음
    항아리가 아이디는 담을 수 있으나 유저를 못 담아서 새로운 항아리 DTO 만들기
     

    3. ORM(Object-Relational Mapping)

    • 객체와 관계형 데이터베이스 간의 매핑을 자동화하는 기술이나 프레임워크
    • 원래 설계 순서 : 테이블 설계 > 자바코드 작성
    • DB랑 JAVA의 데이터 타입이 다름
    테이블 : 모든 타입을 스칼라만 담을 수 있음
    스칼라는 하나의 데이터
    → 테이블이 여러 데이터를 담고 싶으면 테이블을 만들어야 함
    자바 : 하나의 클래스에 여러가지의 타입을 담을 수 있음
    ⇒ OOP 세상과 테이블 세상은 데이터 타입의 구조조차 다름 불일치
    • 불일치 해결
    DB의 테이블 + 자바의 데이터 → 모델링해서 테이블이랑 타입을 똑같이 만들었음
    package shop.mtcoding.blog.board; import jakarta.persistence.*; import lombok.Data; import org.hibernate.annotations.CreationTimestamp; import shop.mtcoding.blog.user.User; import java.time.LocalDateTime; @Data @Entity @Table(name = "board_tb") public class Board { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; private String title; private String content; @ManyToOne // 매니는 보드 원은 유저 : 1대 N -> 오류 사라짐 private User user; // 컬럼에 테이블로 만들어지지는 않음 @CreationTimestamp private LocalDateTime createdAt; }
    • 나는 객체를 적었는데 테이블을 만들 때는 외래키로 만들어줌
    버전 1과 방식은 다르지만 똑같은 테이블이 생성됨
     
    • JPA: Hibernate와 orm이 담겨있음
    Hibernate: 데이터베이스 타입의 데이터를 자바 Object로 변환해 줌=파싱해 줌
    ORM : 자바는 자바의 타입으로 DB의는 데이터베이스 타입으로 만들어 줌
    → 불일치를 해결해주는 것
     
    @ManyToOne // 매니는 보드 원은 유저 : 1대 N -> 오류 사라짐 private User user; // 컬럼에 테이블로 만ㄴ들어지지는 않음
    • 나중에 조회할 때 보드를 남으면 USER가 남김
    • 조인해서 담을 항아리가 있기 때문에 DTO를 만들 필요가 없음
     

    4. Select

    Query String = JPQL(Java Persistence Query Language)
    : 쿼리를 객체지향 쿼리로 작성할 수 있게 해주는 문법
    → 쿼리를 작성하면 실제 쿼리는 아니나 실제 쿼리로 발동됨 / 객체가 뜸
    select b from Board b select * from board_tb
    • 보드가 유저를 들고 있기에 DTO 필요 없음
    notion image
     
    @DataJpaTest // 스프링의 메인이 실행되지 않고 EntityManager랑 DB에 관련된 애들을 메모리에 다 띄워줌
    package shop.mtcoding.blog.Board; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.context.annotation.Import; import shop.mtcoding.blog.board.BoardRepository; @Import(BoardRepository.class) // 내가 만든 파일 임포트 @DataJpaTest // 엔티티 메니저랑 데이터베이스에 관련된 애들을 메모리에 다 띄워줌 public class BoardRepositoryTest { @Autowired private BoardRepository boardRepository; @Test public void findById(){ } }
     
    @ResponseBody // 데이터를 리턴 // HTTP 응답의 본문(body)을 직접 생성하여 반환 // 소드의 반환 값을 HTTP 응답으로 직접 전송
     
    • Board가 user 객체를 들고 있음
    notion image
     
    • 서로 매칭 됨 : 서로 일치해야 함
    notion image
     
    • 객체 리턴 시 스프링이 JSON으로 변환
    package shop.mtcoding.blog.board; import jakarta.persistence.EntityManager; import jakarta.persistence.Query; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Repository; @RequiredArgsConstructor @Repository public class BoardRepository { private final EntityManager em; public Board findById(int id) { Query query = em.createQuery("select b from Board b join fetch b.user u where b.id = :id", Board.class); query.setParameter("id", id); Board board = (Board) query.getSingleResult(); return board; } }
    insert into user_tb(username, password, email, created_at) values('ssar', '1234', 'ssar@nate.com', now()); insert into user_tb(username, password, email, created_at) values('cos', '1234', 'cos@nate.com', now()); insert into board_tb(title, content, user_id, created_at) values('제목1', '내용1', 1, now()); insert into board_tb(title, content, user_id, created_at) values('제목2', '내용2', 1, now()); insert into board_tb(title, content, user_id, created_at) values('제목3', '내용3', 1, now()); insert into board_tb(title, content, user_id, created_at) values('제목4', '내용4', 2, now());
    package shop.mtcoding.blog.board; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpSession; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.ResponseBody; @RequiredArgsConstructor @Controller public class BoardController { private final HttpSession session; private final BoardRepository boardRepository; // 데이터 리턴 시 (RestController or ResponseBody) - 객체를 리턴하면 스프링이 JSON으로 변환 @GetMapping("/api/board/{id}") public @ResponseBody Board apiBoard(@PathVariable int id) { // @ResponseBody : 데이터를 리턴 return boardRepository.findById(id); } // http://localhost:8080?page=0 @GetMapping({"/", "/board"}) public String index() { return "index"; } @GetMapping("/board/saveForm") public String saveForm() { return "board/saveForm"; } // 상세보기시 호출 @GetMapping("/board/{id}") // 1이 프라이머리키 -> 뭐든 넣어도 실행시키려면 변수화시켜서 {} public String detail(@PathVariable int id, HttpServletRequest request) { // 파싱하게 치환해서 알려줌 return "board/detail"; } }
    notion image
     

    오늘의 정리

    • 레파지토리를 만들어서 함수를 만들어서 JPQL를 만들었음
    예전처럼 네이티브 쿼리를 저적어도 됨
    핵심은 ORM 보드로 받을 수 있음
    제일 중요한건 테이블을 만들어낼때 원래는 INT USERID라고 적어야되는데 객체로 적었음
    디비에서는 USER_ID로 만들어줌
    USER라고 적으면 PK에 ?를 찾아서 만들어줌
    • 내가 이름을 만들고 싶을때
    @JOINCUZJAFOTJ → NAME__ID하면 됨
    객체로 적어서 테이블의 컬럼(INT)을 만들어냄
    이렇게 만든 목적이 바로 ORM임
    내가 조인해서 들고오면 JPA가 객체에USER에 담아줌
    못 담아주면 DTO를 만들어서 담아야함
    • DTA DTO 만들때 비교를 하면
    ?같은 라인에 있으니까?
    jpql 안 쓰고 내가 Object로 하나씩 담으면 담을 수 있음 → 그냥 orm이 해주는 것
     
    플랫하고 일자로 해주는 것(Flat and Straight)
    : 주로 객체와 DB간에 일관성 있고 간단한 매핑
    굴곡있게 나와오는 것(Complex and Nesting)
    : 객체의 계층 구조가 복잡하거나 중첩된 경우
    → 보기도 좋고 일할 때 좋음 데이터 찾기도 좋음
     
    Share article

    vosw1

    RSS·Powered by Inblog