-
스프링부트 프로젝트 게시판Programming/JAVA 2023. 5. 27. 23:06
인텔리제이 (IDE) 설치 -> MariaDB 설치 -> MYSQL workbench 설치
1 프로젝트 생성1. start.spring.io 접속
타임리프 템플릿 등 dependencies (의존) 추가한 뒤
Generate 통해 생성
압축풀기 -> 파일 내가 미리 만들어둔 폴더 ( 그냥 원하는 폴더인데 나는 강의에서처럼 C:\study 로 만듬 ) 안에 복붙2. 인텔리제이에서 OPEN 폴더 board 열기
3. main > java > com.study.board > BoardApplication ( class ) 에서 코드 실행 : 오류
오류 해결 : Settings > Gradle > Bild and run using, Run tests using 을 Gradle -> IntelliJ IDEA 로 바꿔준다.
DB 연결 안돼있어 오류 :
JPA 사용하려면 기본적으로 DB에 연결이 되어있어야 한다.
resources 디렉토리 -> application.properties 에서 코드 작성server.port=8080 spring.datasource.driver-class-name=org.mariadb.jdbc.Driver spring.datasource.username=root spring.datasource.password=000000 spring.datasource.url=jdbc:mariadb://localhost:3306
spring.datasource.url=jdbc:mariadb://localhost:3306/ "스키마 이름"스키마 생성 안해줬기 때문에
3. mysql 돌아가서 스키마 만들어주기상단 저 버튼을 통해 스키마 만들어준다
Name은 board 작성 후 우측 하단 Apply 버튼 -> Apply -> Finish그 후 application.properties 에서 스키마 이름 부분에 board를 입력해주고
spring.datasource.url=jdbc:mariadb://localhost:3306/board
실행 Run -> 크롬창에서 localhost:8080 접속
오류가 뜨면 제대로 작동한 것
4. project 레포지토리에서
main > java > com.study.board -> 오른쪽마우스 new package : 이름은 controller -> 오른쪽마우스 new class : BoardController@Controller //spring이 이게 controller 라는 것을 알 수 있게 쓰는 어노테이션 public class BoardController { @GetMapping("/") // 매핑 @ResponseBody //아래 글자 띄어주는 어노테이션 public String main(){ return "Hello World"; } }
다시 코드 실행 시킨 후 다시 localhost:8080 재접속해서 아래 화면이 뜨면 성공 !
2 DB에 테이블 생성
게시물 작성하면 DB에 보관이 되어야 함. 따라 스키마에 게시물을 보관할 테이블 생성해야 한다.
1. workbench -> maria db 접속
접속해 화면 왼쪽에 Navigator 에서 SCHEMAS -> board -> Tables 마우스 오른쪽 버튼 Create Tabel
Name board.
Column Name 아래 더블 클릭하면 입력할 수 있게 창이 뜬다.
아래와 같이 작성 할 것 작성하고 오른쪽하단 Apply - Apply - FinishAI : Auto Incremental
PK : Primary Key : 기본키
NN : Not NullNavigator 에서 board 의 두번째 버튼 누르면 다시 볼 수 있다.
버튼은 board위에 올려두면 ( mouse over 하면 ) 버튼들이 뜬다.3 게시글 작성폼 생성
BoardController.java 에서
BoardController 클래스 안의 내용 삭제1. resources 레포지토리 - templete 마우스 오른쪽 New HTML File
boardwrite.html 생성class 는 대문자로 html 은 소문자로
boardwrite.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>게시물 작성 폼</title> </head> <body> <div class="layout"> <input type="text"> <textarea></textarea> <button>작성</button> </div> </body> </html>
BoardController.class 에서 boardwrite.html 페이지로 이동하는 주소 필요하기 때문에 controller가서 아래와 같이 작성
package com.study.board.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller //spring이 이게 controller 라는 것을 알 수 있게 쓰는 어노테이션 public class BoardController { @GetMapping("/board/write") //localhost:8080/board/write public String boardWriteForm(){ return "boardwrite"; } }
Run : 실행
localhost:8080/board/write 접속2. css 로 조금 깔끔하게 정리해보기
boardwrite.html
head 태그와 body 태그 사이 아래와 같이 style 태그 작성<style> .layout { width:500px; margin : 0 auto; margin-top : 40px; } .layout input, textarea{ width: 100%; box-sizing : border-box; margin-top:10px; } .layout textarea { min-height: 300px; } </style>
4 게시글 작성 처리
1. input 태그와 textarea 태그 button 태그 까지 form 태그로 감싸주기
세줄을 드래그해서 ctrl shift 위아래 방향키 통해 한번에 이동 가능
form actioon 속성 : data들을 어디로 보내줄 것이냐
action = "/board/writedo"
method 속성 : 어떤 방식으로 넘겨 줄 것인지
method="post"2. input 태그와 textarea 태그에 이름부여 : name 이라는 속성 통해 부여 ( title, content )
3. button 태그에 type 속성 지정 : submit
<!--글 작성 처리 --> <body> <div class="layout"> <form action="/board/writepro" method="post"> <input name="title" type="text"> <textarea name="content"></textarea> <button type="submit">작성</button> </form> </div> </body> </html>
4. RUN : 실행
localhost:8080/board/write 에서
title과 content 입력후 작성 버튼 누르면 아래와 같은 에러 페이지가 뜬다.404 에러 : 페이지가 없다.
현재 /board/writedo 라는 페이지를 만들어주지 않았기 때문에
에러 해결 :5. 게시글 작성 처리 전 데이터 넘어오는 것 먼저 확인
BoardController.java에
boardWriteFrome 아래와 같이 추가 작성 후@PostMapping("/board/writepro") //html의 form 의 action에서 여기로 넘어오는 것 : 일치 public String boardWritePro(String title, String content){ System.out.println("제목 : " + title); System.out.println("내용 : " + content); return ""; }
run- 페이지 접속 - title , content 작성 - 인텔리제이 편집창 아래 터미널? 에서 확인 가능
* sout + tqb을 누르면 System.out.println() 을 자동완성 해준다.그런데 이 title, content 를 DB에 저장하기 위해서는 레포지토리 필요
6. 패키지 몇 개 만들기
main > java > com.study.board 마우스 오른쪽 new : package : repository와 entity 생성
entity 아래 board class 생성어노테이션으로 @Entity
자바 영속성 JPA에서 어노테이션은
: 이 클래스가 DB에 있는 테이블 의미한다7. Board.java 필드 아래와 같이 작성
package com.study.board.entiry; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; @Entity public class Board { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; private String title; private String content; }
어노테이션으로 ID : primary key 의미
GeneratedValue ( strategy = ) : 전략을 어떻게 할 것이냐8. BoardController.java 에서
html 의 input 과 textarea 의 이름인 title, content로 BoardController.java에서 받아와 사용하고 있었는데이게 많아지다 보면 받아주기 복잡해지기 때문에
만들어준 Board 클래스이자 엔터티 형식으로 받아서 Board boardboard.getTitle로 받아오고자 하지만, 사용할 수 없음 : 이때 쓰는 것이 Lombok
Board.java에서
@Entity 아래 @Data 어노테이션 추가 해주면
BoardController.java에서 getTitle과 같이 받아올 수 있음.빨간 줄일 때 해당 클래스 클릭 후 Alt + Enter 눌러주면 해결
아래와 같이 작성후 run -입력-전송-하면 전과 같이 인텔리제이 터미널에서 정보를 잘 받고 있음을 확인할 수 있다@PostMapping("/board/writepro") //html의 form 의 action에서 여기로 넘어오는 것 : 일치 public String boardWritePro(Board board){ System.out.println(board.getTitle()); return ""; }
9. repository 에 BoardRepository 인터페이스를 만들어준다
어노테이션으로 @Repository 지정 해주고
이 인터페이스를 extends JpaRepository<>
extends : 상속
Generic으로 타입 지정해준다. <> 안에서 쉼표 사이에 두고 < 엔터티, 프라이머리키의 타입 >extends JpaRepository< Board, Integer >
package com.study.board.repository; import com.study.board.entiry.Board; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository public interface BoardRepository extends JpaRepository<Board,Integer> { }
10. service 패키지 만들어주기
com.study.board에 service 패키지 만들어주기
여기에 BoardService 클래스 생성@Repository @Controller 처럼 똑같이
@Service 어노테이션 넣어주고
클래스 안에 아래와 같이 작성
@Autowired 하면
private BoardRepository boardRepository = new BoardRepository; 할 것을 뒷부분 삭제 해준다boardRepository.save() 통해 entity 넣어준다.
BoardService.java
package com.study.board.service; import com.study.board.entiry.Board; import com.study.board.repository.BoardRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class BoardService { @Autowired private BoardRepository boardRepository; public void boardwrite(Board board){ boardRepository.save(board); } }
11. BoardController.java에서 위에서 만든 Service 이용
boardWritePro에서
sout 없애고 그 자리에
boardService.boardwrite(board); 작성그리고 클래스의 상단에 boardService 주입 (사용하기위해)
@Autowired
private BoardService boardService;run
화면 자체는 view가 없기 때문에 타임리프 템플릿 ( view가 없는 것 ) 오류가 나고 다른 오류는 없을 것
이렇게 작성하고 mariaDB 들어가서
board의 세번째 버튼 클릭해서 내용확인하면작성한 것이 DB로 잘 들어옴을 확인할 수 있다.
5 게시글 리스트 페이지 생성
https://developer-rooney.tistory.com/153?category=496529 에서
테스트 데이터 프로시저 복사DB 들어가서 복붙
각 줄에서 ctrl + enter 하면 실행된다
table 을 확인해보면 글들이 들어갔음을 알 수 있다그리고 인텔리제이에서
BoardController.javaboardWritePro 아래에 추가
@GetMapping("/board/list") public String boardList() { return"boardlist"; }
boardlist.html 을 templetes에 생성 및 아래와 같이 작성<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>게시글 리스트 페이지</title> </head> <style> .layout { width:500px; margin : 0 auto; margin-top : 40px; } </style> <body> <div class="layout"> <table> <thead> <tr> <th>글번호</th> <th>제목</th> </tr> </thead> <tbody> <tr> <td>1</td> <td>제목입니다</td> </tr> </tbody> </table> </div> </body> </html>
아래와 같은 결과 볼수 있다.
다음 글 불러올 메소드가 필요하니
Service에서 아래 코드 추가public List<Board> boardList(){ return boardRepository.findAll(); //Board 리스트 반환해줌 }
Controller 에서 아래 코드 추가
@GetMapping("/board/list") public String boardList(Model model) { model.addAttribute("list", boardService.boardList()); return"boardlist"; }
그리고 boardlist.html 에서
받아온 데이터들 일일이 처리 : 타임리프 템플릿 사용 html 태그 안에다가
xmlns:th="http://www.thymeleaf.org"<tbody> <tr th:each="board :${list}"> <td>1</td> <td>제목입니다</td> </tr> </tbody> </table>
boardController에서 list로 담아서 넘긴 것, 근데 그 리스트에는 board 가 들어있는것
<tbody> <tr th:each="board :${list}"> <td th:text="${board.id}">1</td> <td th:text="${board.title}">제목입니다</td> </tr> </tbody>
//each는 반복 list에서 board가 없어질 때까지 여기서는 121번까지
run하고 접속해주면잘 나온 것을 볼 수 있다.
6 게시글 상세 페이지 생성
1. boardview.html 생성
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>게시글 상세 페이지</title> </head> <body> <h1>제목입니다.</h1> <p>내용이 들어갈 부분입니다.</p> </body> </html>
BoardController.java에 GetMapping 추가
@GetMapping("/board/view") public String boardView(){ return "boardview"; }
하고 실행
잘 뜬다.
이제 목록별로 들어오도록 한다.2. BoardService.java 에서
// 특정 게시글 불러오기 public Board boardView(Integer id){ return boardRepository.findById(id).get(); }
BoardController.java 에서
@GetMapping("/board/view") public String boardView(Model model, Integer id){ model.addAttribute("board", boardService.boardView(id); return "boardview"; }
localhost:8080/board/view?id=1하면 이 1이 아래의 id로 들어간다. (Get 방식)
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>게시글 상세 페이지</title> </head> <body> <h1 th:text="${board.title}">제목입니다.</h1> <p th:text="${board.content}">내용이 들어갈 부분입니다.</p> </body> </html>
3. 이제 list에서 제목을 눌렀을 때 view로 들어가도록 처리
boardlist.html에서
<td th:text="${board.title}" > <a th:href="@{/board/view(id=${board.id})}">제목입니다</a> </td>
이렇게 수정했더니 적용안됨
<td > <a th:text="${board.title}" th:href="@{/board/view(id=${board.id})}"></a> </td>
이렇게 수정했더니 적용완료 th 둘다 a로 내려야하는 것7 게시글 삭제 버튼 생성 및 삭제 처리
<a href="#">글삭제</a>
boardview.html 에 이렇게 아래 추가 작성하고
// 특정 게시글 삭제 public void boardDelete(Integer id){ boardRepository.deleteById(id); }
BoardService.java에서 service작성
//게시글 삭제 @GetMapping("/board/delete") public String boardDelete(Integer id){ boardService.boardDelete(id); return "redirect:/board/list"; }
BoardController.java에서 위와같이 작성
<a th:href="@{/board/delete(id=${board.id})}">글삭제</a>
그리고 boardview.html 버튼에서도 작동하도록 위와 같이 작성
8 게시글 수정 버튼 생성 및 수정 처리
1. 수정 버튼 생성 및 boardview.html 페이지에 아래와 같이 추가
<a th:href="@{/board/modify/{id}(id=${board.id})}"> 수정 </a>
BoardController.java에 다음과 같이 추가
// 게시글 수정 @GetMapping("/board/modify/{id}") public String boardModify(@PathVariable("id") Integer id){ return "boardmodify"; }
@PathVariable 어노테이션은@GetMapping통해서 url이 들어왔을 때 슬래쉬 뒷편에 있는 id가 인식이 돼서 Integer 형태의 id로 들어온다는 것 , Get 과 달리 슬래쉬 다음 바로 숫자가 온다.
그리고 boardmodify.html 생성 및 boardwrite.html의 내용 우선 그대로 가져오기
-> 성공적
2. 제목, 내용 넘기기
BoardController 가서 아래와 같이 작성
// 게시글 수정 @GetMapping("/board/modify/{id}") public String boardModify(@PathVariable("id") Integer id , Model model){ model.addAttribute("board", boardService.boardView(id)); return "boardmodify"; }
그리고 modify.html 파일에서 input 태그에 다음과 같이 수정
html 태그에 thymeleaf도 추가해줘야한다 <html lang="en" xmlns:th="http://www.thymeleaf.org"><form action="/board/writepro" method="post"> <input name="title" type="text" th:value="${board.title}" > <textarea name="content" th:text="${board.content}"></textarea> <button type="submit">수정</button> </form>
잘 나오는 것을 볼 수 있다. 아래와 같이 추가수정하고
<form th:action="@{/board/update/{id}(id=${board.id})}" method="post">
그리고 아래와 같이 추가
@PostMapping("/board/update/{id}") public String boardUpdate(@PathVariable("id") Integer id, Board board){ Board boardtemp =boardService.boardView(id); boardtemp.setTitle(board.getTitle()); boardtemp.setContent(board.getContent()); return "redirect:/board/list"; }
하면 계속해서 수정을 해도 내용이 변경되지 않고 리스트로 돌아옴. 이 문제 때문에 3시간 넘게 강의를 돌리고 오타를 찾다가
처음부터 강의를 2번째 돌리고 있던중@PostMapping("/board/update/{id}") public String boardUpdate(@PathVariable("id") Integer id, Board board){ Board boardtemp =boardService.boardView(id); boardtemp.setTitle(board.getTitle()); boardtemp.setContent(board.getContent()); boardService.boardwrite(boardtemp); return "redirect:/board/list"; }
위와 같은 코드를 추가하니 드디어 성공..
boardService.boardwrite(boardtemp);
이 한 줄 추가로 모든 것이 해결되었다.
9. 게시글 등록, 수정 시에 처리 메세지 출력
기존에 실행하면 바로 리스트로 가는데, 등록하면 메시지로 완료되었습니다를 보여주고 넘어가는 것
templetes에 message.html 생성
thymeleaf 넣어주고
head태그와 body 태그 사이에 script 태그 생성
script 태그에 타임리프 사용해주기 위해서
script th:inline="javascript" 입력컨트롤러에서 받아온 변수 여기에 적용시켜줘야한다.
>>/*<![CDATA[*/
var message = [ [ ${message} ] ]; // 컨트롤러에서 여기로 메세지 전달 , 그리고 alert로 메세지 창 띄워준다.
alert(message);location.replace([[${searchUrl}]]); // 페이지 이동시켜주는 것.
/*]]>*/
Controller.java
기존에는 wirtepro 에서 return으로 redirect로 바로 보내줬었는데, 이제 "message"로 보내준다.
매개변수 Model model 추가해주고,
아래와 같이 수정@PostMapping("/board/writepro") //html의 form 의 action에서 여기로 넘어오는 것 : 일치 public String boardWritePro(Board board, Model model){ boardService.boardwrite(board); model.addAttribute("message","글 작성이 완료되었습니다."); model.addAttribute("searchUrl","/board/list"); return "message"; }
잘 작동함을 볼 수 있다.
7. 게시글 파일 업로드
이미지 파일 업로드 후 뷰에서 어떻게 보여지는 지에 대해 학습
파일에 저장된 경로, 파일 이름저장하기 위한 컬럼 위해 mariadb에서 컬럼수정1. filename , filepath라는 컬럼 board DB에 추가
2. 컬럼을 바꿔주면 인텔리제이에서 엔터티도 바꿔줘야한다.
entity > board.java에
아래와 같이 수정정package com.study.board.entiry; import lombok.Data; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; @Entity @Data public class Board { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; private String title; private String content; private String filename; private String filepath; }
3. 이제 파일을 저장할 boardwrite.html 에서
파일 추가해주기 위해서는 form태그에 enctype을 추가해주어야한다.<form action="/board/writepro" method="post" enctype="multipart/form-data"> <input name="title" type="text"> <textarea name="content"></textarea> <input type="file"> <button type="submit">작성</button> </form>
4. 작성해도 안넘어가기 때문에 코드 추가 해준다.
파일 저장할 디렉토리 추가 resources> static 에 오른쪽마우스 "files"라는 이름의 directory 추가
5. BoardService.java에서 글 작성처리에서 MultiparttFile file 로 매개변수 추가 ( 현재는 오류 뜰 수 있지만 컨트롤러 수정 할 예정이니 괜찮다 )
// 게시글 작성 처리 public void boardwrite(Board board, MultipartFile file){ String projectPath = System.getProperty("user.dir") + "//src//main//resources//static//files"; // 저장할 경로 지정 UUID uuid = UUID.randomUUID(); // 랜덤으로 식별자 이름만들어준다. String fileName = uuid + "-" + file.getOriginalFilename(); //랜덤식별자 + 언더바 + 파일이름 File saveFile = new File(projectPath, fileName); //File 이라는 클래스 이용해 빈 껍데기 생성, 경로 및 이름지정 file.transferTo(saveFile); // boardRepository.save(board); }
file.transferTo(saveFile)에 exception 대비하라는 경고창이 아래와 같이 뜬다.
이런경우에는 아래와 같이 추가 작성해준다.
public void boardwrite(Board board, MultipartFile file) throws Exception
그리고 BoardController.java에서 아래와 같이 수정
@PostMapping("/board/writepro") //html의 form 의 action에서 여기로 넘어오는 것 : 일치 public String boardWritePro(Board board, Model model, MultipartFile file) throws Exception{ boardService.boardwrite(board,file); model.addAttribute("message","글 작성이 완료되었습니다."); model.addAttribute("searchUrl","/board/list"); return "message"; }
수정에서도 아래와 같이 수정
@PostMapping("/board/update/{id}") public String boardUpdate(@PathVariable("id") Integer id, Board board, Model model, MultipartFile file) throws Exception{ Board boardtemp =boardService.boardView(id); boardtemp.setTitle(board.getTitle()); boardtemp.setContent(board.getContent()); boardService.boardwrite(boardtemp , file); model.addAttribute("message","글 수정이 완료되었습니다."); model.addAttribute("searchUrl","/board/list"); return "message"; }
그리고 실행하면 오류 : null point exception 이 발생했다.
String fileName = uuid + "-" + file.getOriginalFilename(); 에서 나타난 것.숫자 옆에 저기 부분을 클릭하면 브레이크포인트를 걸어서 디버깅을 할 수있다.
file이 안담겼다는 것 . boardwrite.html에서 input type file, 그리고 name="file"이라고 설정해줬어야 한다. Controller에서
public String boardUpdate(@PathVariable("id") Integer id, Board board, Model model, MultipartFile file)
여기의 제일 끝의 file과 일치시켜주어야한다. 한 뒤 디버깅 하고
F9로 디버깅 끝내고 오면 리스트에 잘 들어가있고
인텔리제이에서 보면 static.files에 잘 들어가있음을 볼 수 있다.6. 이제 mariaDB에도 데이터를 넣어준다.
BoardService.java에서 글 작성 처리에서
board.setFilename();// 게시글 작성 처리 public void boardwrite(Board board, MultipartFile file) throws Exception{ String projectPath = System.getProperty("user.dir") + "\\src\\main\\resources\\static\\files"; // 저장할 경로 지정 UUID uuid = UUID.randomUUID(); // 랜덤으로 식별자 이름만들어준다. String fileName = uuid + "-" + file.getOriginalFilename(); //랜덤식별자 + 언더바 + 파일이름 File saveFile = new File(projectPath, fileName); //File 이라는 클래스 이용해 빈 껍데기 생성, 경로 및 이름지정 file.transferTo(saveFile); // board.setFilename(fileName); board.setFilepath("/files"+fileName); //경로 boardRepository.save(board); }
그리고 boardview.html 에서 추가 a 태그, 다운받기 하나 만들어주고
후 새로 이미지 업로드를 write페이지에서 해보면
이름과 경로가 잘들어갔음을 확인할 수 있다.
7. 이제 업로드된 이미지를 보는 방법
boardwview.html 에서
<body> <h1 th:text="${board.title}">제목입니다.</h1> <p th:text="${board.content}">내용이 들어갈 부분입니다.</p> <a th:href="@{${board.filepath}}">다운받기</a> <a th:href="@{/board/delete(id=${board.id})}"> 삭제</a> <a th:href="@{/board/modify/{id}(id=${board.id})}"> 수정 </a> </body>
th:href -> a 태그에 경로를 걸 때 사용
th:text -> 태그에 문자열을 출력할 때 사용그대로 해도 계속 404에러가 떠서 BoardService.java에서 url부분들을 아래와 같이 하드코딩 해주었다.
public void boardwrite(Board board, MultipartFile file) throws Exception{ String projectPath = System.getProperty("user.dir") + "\\board\\src\\main\\resources\\static\\files"; // 저장할 경로 지정 UUID uuid = UUID.randomUUID(); // 랜덤으로 식별자 이름만들어준다. String fileName = uuid + "-" + file.getOriginalFilename(); //랜덤식별자 + 언더바 + 파일이름 File saveFile = new File(projectPath, fileName); //File 이라는 클래스 이용해 빈 껍데기 생성, 경로 및 이름지정 file.transferTo(saveFile); // board.setFilename(fileName); board.setFilepath("board/src/main/resources/static/files/"+fileName); //경로 boardRepository.save(board); }
8. 게시판 페이징 처리
백엔드 처리 - > 페이징 블럭 만들기 순서
JPA 이용해 페이징 처리, 페이지 번호와 사이즈를 넘겨주면 페이징 처리 하게 된다.
localhost:8080/board/list?page=1&size=100페이지가 1페이지, 사이즈는 한 페이지에서 보여줄 게시글 수
1. 먼저 최근 작성글이 제일 위에 오도록 처리
BoardController.java에서 boardList 에서 Pageable pageable 매개변수 추가 : 여기서 Pageable은 끝이 domain 인 것으로
괄호에서 ctrl + space 누르면 괄호 안에 들어갈 수 있는 것들 목록이 아래로 쫙 보인다@GetMapping("/board/list") public String boardList(Model model, @PageableDefault(page = 0, size=10, sort="id", direction = Sort.Direction.DESC) Pageable pageable) { model.addAttribute("list", boardService.boardList(pageable));
위와 같이 수정 한 뒤
BaordService.java에서
// 게시글 리스트 처리 public Page<Board> boardList(Pageable pageable){ return boardRepository.findAll(pageable); //Board 리스트 반환해줌 }
boardList의 매개변수로 받아준다.
매개변수가 없는 경우에는 List<Board>로 받아주는데, 여기서는 Page라는 클래스로 리턴
위와 같이 잘 나타나고, page=1의 부분을 바꾸고 &size=20 등을 통해서 더 조작해줄 수 있다.
원래 페이징 처리할 때 쿼리문도 적어주어야하고 페이지 처리할 클래스도 따로 생성을 해주어야하는데, JPA 를 이용해서
JPA 의 findAll이라는 메소드 사용할 때 pageable 이라는 클래스를 넘겨주게 되면 어려운 처리를 간단하게 해준다.이것이 편하게 페이징해줄 수 있는 방법 !
findAll이라는 메소드 활용해 DB의 내용을 가져오게 되면, 말 그대로 DB에 보관하고 있는 모든 정보를 가져오게 되지만
pageable이라는 클래스를 넘겨주게 되면 안에 몇페이지인지 개수가 몇개인지 담아서 보내줄 수 있다. url에 페이지정보, 사이즈 넘겨주고
어노테이션 페이저블 디폴트 통해서 기본 설정 해줄 수 있따.2. 페이지버튼을 누르면 넘어가도록 처리
필요한 변수
nowPage -> 현재 페이지
startPage -> 블럭에서 보여줄 시작 페이지
endPage -> 블럭에서 보여줄 마지막 페이지타임리프 문법
th:text -> 태그 안에 데이터 출력
th:each-> 반복문
th:each="${number:#number(시작 번호, 끝번호)}"
-> 시작번호에서 끝번호까지 반복3. BoardController.java에서
model.addAttribute("list", boardService.boardList(pageable));
위에서 넣어줄 페이지를 직접넣지 않고 빼준다.
int nowPage = list.getPageable().getPageNumber();//1번 int nowPage = pageable.getPageNumber(); //2번 이렇게 써도 똑같음 하지만 통일성을 위해 1번으로
@GetMapping("/board/list") public String boardList(Model model, @PageableDefault(page = 0, size=10, sort="id", direction = Sort.Direction.DESC) Pageable pageable) { Page<Board> list= boardService.boardList(pageable); int nowPage = list.getPageable().getPageNumber() +1 ;// 페이지 0 시작이기 때문에 +1 int startPage = Math.max(nowPage-4,1); //두 개 비교해 더 높은값 반환 int endPage = Math.min(nowPage+5,list.getTotalPages()); model.addAttribute("list", list); //위의 변수들 넘겨주기 model.addAttribute("nowPage",nowPage); model.addAttribute("startPage",startPage); model.addAttribute("endPage",endPage); return"boardlist"; }
그리고 타임리프 써주기
boardlist.html 에서 table 태그 아래 다음과 같이 추가
<th:block th:each="page : ${#numbers.sequence(startPage, endPage)}"> <a th:if="${page!=nowPage}" th:href="@{/board/list(page=${page-1})}" th:text="${page}"></a> <strong th:if="${page==nowPage}" th:text="${page}" style="color:blue"></strong> </th:block>
9. 게시판 검색 기능
JPA Repository
findBy(컬럼 이름) -> 컬럼에서 키워드를 넣어서 찾겠다.
findBy(컬럼 이름)Containing -> 컬럼에서 키워드가 포함된 것을 찾겠다.1. BoardRepository.java ( 전에 만들어 둔 인터페이스 )
@Repository public interface BoardRepository extends JpaRepository<Board,Integer> { Page<Board> findBytTitleContaining(String searchKeyword, Pageable pageable); }
BoardService.java 수정 //게시글 리스트 처리 아래
public Page<Board> boardSearchList(String searchKeyword, Pageable pageable){//검색한 내용도 페이징처리 해주기 위해 pageable 추가 return boardRepository.findBytTitleContaining(searchKeyword, pageable); }
그 전에는 전부 모든 데이터를 가져왔지만, 검색했을때와 검색하지 않았을 때의 구분을 해주어야한다.
BoardController.java 수정 .. 사이트에 연결할 수 없다고 에러가 뜬다. 왜지? 다시 처음부터 타이핑 했더니 해결됐다
하지만, 2페이지를 누르면 searchKeyword가 사라진 것을 볼 수있다.
따라서, &page=1을 주소창에 함께 입력하면 유지된채 검색되는 것을 볼 수 있다.2. 타임리프 부분 바꿔준다.
<th:block th:each="page : ${#numbers.sequence(startPage, endPage)}"> <a th:if="${page!=nowPage}" th:href="@{/board/list(page=${page-1}, searchKeyword=${param.searchKeyword})}" th:text="${page}"></a> <strong th:if="${page==nowPage}" th:text="${page}" style="color:blue"></strong> </th:block>
param.searchKeyword를 가지고왔는데 param이라는 것이 쿼리스트링 중에 특정 키워드를 넣어서 넘겨준다. 그래서 페이지 넘어갈 때 물고 가기 때문에 그대로 가는 것.
boardlist.html 에서 위와 같이 작성하면 검색했을 때, 유지된 채 다음으로 넘어가는 것을 볼 수 있다.
3. 그리고 아래에 다음과 같이 검색창을 만들어준다.
<form th:action="@{/board/list}" method="get"> <input type="text" name="searchKeyword"> <button type="submit">검색</button> </form>
그리고 아주 잘 작동하는 것을 볼 수 있다.
한코딩 님의 유튜브를 공부하고 정리한 내용입니다.
https://youtube.com/playlist?list=PLZzruF3-_clsWF2aULPsUPomgolJ-idGJ
'Programming > JAVA' 카테고리의 다른 글
스프링부트 3 백엔드 개발자 되기 : 시작하는 과정 (2) (0) 2023.08.17 [ JavaSpring ]Whitelabel Error Page 해결방법 (0) 2023.04.28 [ JavaSpring ] Hello world 출력 (0) 2023.04.28 JAVA (0) 2022.09.13 JSP 게시판 만들기 강좌 -6강 (0) 2022.09.13