Entitiy와 Table 설계 원칙 
- 컬렉션과 스칼라가 아닌 모든 것들은 테이블로 쪼갠다.
- 1-N 관계에서는 N 쪽에 외래키를 넣는다.
- 외래키에 제약조건을 넣지 않는 것이 좋다. → 외래키 제약조건이 데이터의 삭제나 변경 시에 제한을 걸 수 있기 때문이다.
jpa에서 기본키 자동생성 어노테이션
@GeneratedValue(strategy = GenerationType.IDENTITY) // 기본키 자동생성
// IDENTITY : AUTO_INCREMENT
// SEQUENCE : Oracle 과 같은 시퀀스를 지원하는 데이터 베이스에서 사용
GeneratedValue타입사진

폴링키에 제약조건을 않넣는게 좋다.
나중에 걸려있는 애를 삭제하려 할 때 문제가 생김
게시판
화면에 보이지 않더라도 아이디는 들고 와야 된다.
작성자가 누군지 알아야 되기 때문에
mustache 문법
오브젝트면 if문 boolen타입의 if문

결과
@RequestParam(defaultValue = "0") 기본 값이 0으로 되도록 한다. 기입하면 다른 값이 나온다.
컬렉션일 때만 for문으로 바뀐다.
{{#boardList}} {{/boardList}}


쿼리스트링을 쓰는 이유는 구체적으로 조회하기 위해서 이다.
@GetMapping({"/", "/board"})
public String index(HttpServletRequest request, @RequestParam(defaultValue = "0") int page) {
System.out.println("페이지 : " + page);
List<Board> boardList = boardRepository.findAll();
request.setAttribute("boardList", boardList); // 가방(리퀘스트)에 담는 것 MVC 패턴
return "index";
}
DAO=REPASITORY
@RequestParam
name
: 요청 파라미터의 이름을 지정합니다.
required
: 해당 파라미터가 필수인지 아닌지를 지정합니다. 기본값은 true
입니다. false
로 설정하면, 파라미터가 없어도 요청이 처리됩니다.
defaultValue
: 파라미터가 없을 경우 사용할 기본값을 지정합니다.jsp와 mustache의 차이
jsp는 꺽쇠로 자바 코드로 표현 할 수 있어서 자유도가 높다.
mustache는 자바 코드를 못 적는다. 중괄호 두 개로 표현 할 수 있다. 그러나 강제성을 줘서 frontController를 거쳐서 지나가게 끔 만들 수 있다.(의존성 주입)
페이징
currentPage
: 현재 페이지를 나타냄.
totalCount
: 전체 게시물의 수를 나타내는 변수입니다. 실제로는 데이터베이스에서 조회한 총 게시물의 수를 사용해야 합니다. 현재 코드에서는 임시로 4로 설정되어 있습니다.
paging
: 한 페이지에 표시할 게시물의 수를 나타내는 변수입니다. 한 페이지당 보여줄 게시물 수를 설정하는 값으로, 현재 코드에서는 3으로 설정되어 있습니다.
"disabled"
는 일반적으로 사용자 인터페이스에서 요소(element)나 컨트롤(control)에 대해 비활성화(disabled) 상태를 나타내는 속성(attribute)입니다. 비활성화된 요소는 사용자가 상호작용할 수 없으며, 일반적으로 회색 또는 투명한 모습으로 표시됩니다.
밑 코드에서 시작 페이지를알려줄 때랑 마지막 페이지에를 알려줄때 사용했다.{{> layout/header}}
<div class="container p-5">
{{#boardList}}
<div class="card mb-3">
<div class="card-body">
<h4 class="card-title mb-3">{{title}}</h4>
<a href="/board/{{id}}" class="btn btn-primary">상세보기</a>
</div>
</div>
{{/boardList}}
<ul class="pagination d-flex justify-content-center">
<li class="page-item {{#first}}disabled{{/first}}">
<a class="page-link" href="?page={{prevPage}}">Previous</a>
</li>
<li class="page-item {{#last}}disabled{{/last}}">
<a class="page-link" href="?page={{nextPage}}">Next</a>
</li>
</ul>
</div>
{{> layout/footer}}
package shop.mtcoding.blog.board;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;
import shop.mtcoding.blog._core.Constant;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.util.List;
@RequiredArgsConstructor
@Repository
public class BoardRepository {
private final EntityManager em;
public List<Board> findAll(int page) {
int value = page * Constant.PAGING_COUNT;
Query query = em.createNativeQuery("select * from board_tb order by id desc limit ?, ?", Board.class);
query.setParameter(1, value);
query.setParameter(2, Constant.PAGING_COUNT);
List<Board> boardList = query.getResultList(); // 여러건이니
return boardList;
}
public int count() {
Query query = em.createNativeQuery("select count(*) from board_tb");
Number count = (Number) query.getSingleResult();
return count.intValue();
}
}
package shop.mtcoding.blog.board;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import shop.mtcoding.blog._core.PagingUtil;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
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); // 가방(리퀘스트)에 담는 것 MVC 패턴
int currentPage = page; // 현재 페이지
int nextPage = currentPage + 1;
int prevPage = currentPage - 1; // 뷰에 자바 코드가 최소화 된다.
request.setAttribute("nextPage", nextPage);
request.setAttribute("prevPage", prevPage); // 가져와서 넣기!
boolean first = PagingUtil.isFirst(currentPage);
boolean last = PagingUtil.isLast(currentPage, 4);
// t = 4, c = 0, last = false
// t = 4, c = 1, last = true
request.setAttribute("first", first);
request.setAttribute("last", last);
// disabled 도 편하게 수정하기 // {{#first}}disabled{{/first}} 이걸 {{disabled}}만 넣어서 해결 가능
String disabled = currentPage == 0 ? "disabled" : "";
request.setAttribute("disabled", disabled);
return "index";
}
@GetMapping("/board/saveForm")
public String saveForm() {
return "board/saveForm";
}
@GetMapping("/board/1")
public String detail() {
return "board/detail";
}
}
package shop.mtcoding.blog._core;
public class PagingUtil {
public static boolean isFirst(int currentPage) {
return currentPage == 0 ? true : false;
}
// 책임 : 마지막 페이지인지 여부
public static boolean isLast(int currentPage, int totalCount) {
int totalPageCount = getTotalPageCount(totalCount);
return currentPage + 1 == totalPageCount ? true : false;
}
// 책임 : 전체 페이지 개수 리턴
public static int getTotalPageCount(int totalCount) {
// 1. 나머지 여부 확인
int remainCount = totalCount % Constant.PAGING_COUNT;
int totalPageCount = totalCount / Constant.PAGING_COUNT;
// 2. 나머지가 있다면?
if (remainCount > 0) {
totalPageCount = totalPageCount + 1;
}
return totalPageCount;
}
}
참고코드
@GetMapping({"/", "/board"})
public String index(HttpServletRequest request, @RequestParam(defaultValue = "0")int 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);
boolean first = (currentPage == 0 ?true : false);
int totalCount = boardRepository.count();
int paging = 5;
int totalPage = totalCount/paging;
if (totalCount % paging != 0) {
totalPage = 1 + (totalCount / paging);
}
ArrayList pageIndex = new ArrayList<>();
for (int i =0; i< totalPage; i++) {
pageIndex.add(i);
}
request.setAttribute("pageIndex",pageIndex);
boolean last = currentPage ==(totalPage -1) ?true : false;
request.setAttribute("first",first);
request.setAttribute("last",last);
return "index";
}
package shop.mtcoding.blog.board;
import jakarta.persistence.EntityManager;
import jakarta.persistence.Query;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@RequiredArgsConstructor
@Repository // 데이터 베이스 연동, ioc컨테이너 등록
public class BoardRepository { //dao
private final EntityManager em;
public List<Board> findAll(int page){
final int count =5;
int value = page * 5;
//value는 페이지 번호에 따라 가져올 데이터의 시작 인덱스를 계산하는 방식
Query query = em.createNativeQuery("select * from board_tb order by no desc limit ?,?", Board.class);
query.setParameter(1,value);
query.setParameter(2,count);
List<Board> boardList = query.getResultList();
return boardList;
}
public int count() {
Query query = em.createNativeQuery("select count(*) from board_tb");
Long count = (Long) query.getSingleResult(); //integer를 넣을 경우 터짐 그래서 Long을 사용함
return count.intValue();//Long 타입을 int 타입으로 형변환 해주는 메서드
}
{{#pageIndex}}
<li class="page-item"><a class="page-link" href="?page={{.}}">{{.}}</a></li>
{{/pageIndex}}
컨텍스트:템플릿에서 사용하고 있는 변수의 또 다른 명칭 또는 데이터, 객체의 집합.
플레이스 홀더:예시로 {{.}}로
값이 들어갈 자리를 나타내는 표시
머스테치 문법에서 {{.}}은 현재 컨텍스트에 있는 값을 나타낸다.
Share article