Home

0

Spring Boot 게시판 만들기 13 - jenkins를 이용해 build 하기

13. jenkins를 이용해 build하기jenkins를 로컬에 바로 설치해 사용해도 되지만 해당 프로젝트에서는 docker를 이용해 jenkins이미지를 불러와 빌드를 진행할 것이다. docker 설치하기도커는 https://docs.docker.com/get-docker/ 에서 본인 운영체제에 맞는 것을 선택해 다운로드 한다. 본인이 사용하는 프로젝트의 jdk 버전에 맞는 jenkins 파일 가져와야 build시에 jdk 버전 오류가 안생긴다. JDK11버전의 jenkins 이미지를 불러오도록 한다. docker images 명령어를 통해 이미지들을 확인할 수 있다. # lts버전의 jenkins 이미지docker pull jenkins/jenkins:lts# jdk11버전의 jenkins 이미지docker pull jenkins/jenkins:jdk11# 설치된 이미지들 확인docker images jenkins 이미지 실행하기

0

Spring Boot 게시판 만들기 12 - 타임리프 오류 해결하기

12. 타임리프 오류 해결하기null 오류게시물이 하나도 없을 때 Thymeleaf에서 null인 객체를 참조하여 오류가 발생하는 것을 확인할 수 있었다. 객체를 반환할 때 데이터가 null인 경우 비어있는 객체를 생성해 반환하도록 한다. @GetMapping("/")public String board(@PageableDefault Pageable pageable, Model model) { Page<Post> posts = postService.getPosts(pageable); if(posts == null){ posts = new PageImpl<Post>(new ArrayList<>()); } model.addAttribute("PostList", posts); return "board";} paging 오류데이터가 하나도 없는데 pagination 목록에서 1과 0이 떠있는 오류를 발견했다.

0

Spring Boot 게시판 만들기 11 - 페이징 처리하기

11. 페이징 처리하기메인 게시판을 접근하게 되면 한번에 너무 많은 게시글들이 쏟아져 나오게 돼 보기가 좋지 않고 서버도 많은 양의 데이터를 한번에 보내야 하기 때문에 성능에서도 좋지 않다.사용자에게 전체 데이터에서 적당한 양의 데이터만 보여줘 사용자 입장에서도 서버 입장에서도 부담이 없게 한다. Control 로직 수정하기Spring에서 제공하는 Pageable 인터페이스를 사용하면 쉽게 페이징 기능을 사용할 수 있다. BoardController.java @Controller@RequiredArgsConstructorpublic class BoardController { private final PostService postService;// @GetMapping("/")// public String board(Model model){// List<Post> posts = postService.getAllPosts();// model.addAttribute("PostList", posts);// return "board";// } @GetMapping("/") public String board(@PageableDefault Pageable pageable, Model model) { Page<Post> posts = postService.getPosts(pageable); model.addAttribute("PostList", posts); return "board"; }} 테스트 코드 로직 변경@Test@DisplayName("모든 Post를 가져온다.")public void board() throws Exception { List<Post> posts = new ArrayList<>(); posts.add(Post.builder() .id(1L) .title("test") .name("tester") .content("test") .writeTime(LocalDateTime.now()) .build() ); Page<Post> pagePosts = new PageImpl<>(posts); PageRequest pageRequest = PageRequest.of(1, 10); given(postService.getPosts(pageRequest)).willReturn(pagePosts); ResultActions resultActions = mockMvc.perform(get("/") .param("page", "1")// .flashAttr("PostList", new ArrayList<>()) ); resultActions .andExpect(status().isOk()) .andDo(print()); verify(postService).getPosts(pageRequest);} Servic 로직 추가

0

Spring Boot 게시판 만들기 10 - 포스트 삭제하기

10. 포스트 삭제하기PostController.java @PostMapping("/post/{postId}/delete")public String deletePost(@PathVariable("postId") Long id){ postService.deletePostById(id); return "redirect:/";} PostService.java @Transactionalpublic void deletePostById(Long id){ postRepository.deleteById(id);} Post.html <tbody class="text-center"><tr th:each="Post:${PostList}" th:id="*{Post.id}"> <td class="align-middle" th:text="${PostStat.index+1}"></td> <td class="align-middle"> <a th:href="@{/post/{id}(id=${Post.id})}" th:text="${Post.title}"></a> </td> <td class="align-middle" th:text="${Post.name}"></td> <td class="align-middle" th:text="${Post.writeTime}"></td> <td class="text-center align-middle"> <a class="btn btn-primary" th:href="@{/post/{id}/revise(id=${Post.id})}">수정</a> <a href="#" th:href="'javascript:deletePost('+${Post.id}+')'" class="btn btn-danger">삭제</a><!--<button id="delete-btn" type="submit" class="btn btn-danger" th:onclick="deletePost([[ ${Post.id} ]]);">삭제</button>--> </td></tr></tbody> function deletePost(id) { if(confirm(id + "번 게시글을 삭제하시겠습니까?")) { const action = "/post/" + id + "/delete" let form = document.createElement("form"); form.setAttribute("method", "post"); form.setAttribute("action", action); document.body.appendChild(form); form.submit(); }}// var table = document.getElementById('PostTable');//// async function deletePost(id) {// url = "http://localhost:8080/post/" + id + "/delete";// console.log(url);// const response = await fetch(url, {// method: 'post'// });// }

0

Spring Boot 게시판 만들기 9 - 페이지 수정하기

9. 페이지 수정하기데이터를 수정하기 위해서는 수정하고자 하는 데이터를 찾아야 하기 때문에 id값이 필요하다. input태그의 type속성을 hidden으로해 form을 작성한 후 나머지 데이터와 함께 id값을 넘겨주도록 한다. post.html <h2>게시글 작성</h2><div class="card" style="padding: 20px; border-radius: 15px; margin: 20px auto;"> <form class=" form-horizontal" method="post" th:action="@{/post}" th:object="${postDto}"> <input type="hidden" th:if="*{id != null and id > 0}" th:field="*{id}"/> <div class="form-group"> <label>제목</label> <div class="col-sm-12"> <input type="text" style="border-radius: 5px;" class="form-control" th:field="*{title}" placeholder="제목을 입력해 주세요."/> </div> </div> <div class="form-group"> <label>이름</label> <div class="col-sm-12"> <input type="text" style="border-radius: 5px;" class="form-control" th:field="*{name}"placeholder="이름을 입력해 주세요."/> </div> </div> <div class="form-group"> <label>내용</label> <div class="col-sm-12"> <textarea class="form-control" style="height: 300px; border-radius: 5px;" th:field="*{content}" placeholder="내용을 입력해 주세요."></textarea> </div> </div> <div class="btn_wrap text-center"> <a th:href="@{/}" class="btn btn-default waves-effect waves-light">뒤로가기</a> <button type="submit" class="btn btn-primary waves-effect waves-light">저장하기</button> </div> </form></div> 수정페이지로 이동하기데이터를 수정위해서 URL경로를 통해 수정할 데이터의 id값을 받아온 후 해당 id값을 이용해 데이터를 조회한 뒤 기존 데이터를 반환하도록 한다. 내부 로직은 상세페이지를 가져오는 것과 똑같고 반환하는 템플릿만 다르게 반환한다. PostController.java @GetMapping("/post/{postId}/revise")public String getPostDetailsToRevise(@PathVariable("postId") Long id, Model model) { Post post = postService.getPostById(id); PostDto postDto = PostDto.builder() .id(post.getId()) .name(post.getName()) .title(post.getTitle()) .content(post.getContent()) .writeTime(post.getWriteTime()) .build(); model.addAttribute("postDto", postDto); return "post";} PostControllerTest.java

0

Spring Boot 게시판 만들기 8 - 상세 페이지

<!DOCTYPE html><html xmlns:th="http://www.thymeleaf.org"><head th:replace="/fragments/head :: main-head"></head><body class="bg-light"><nav th:replace="/fragments/navbar :: main-nav"></nav><div class="container col-lg-6 "> <h2>상세 페이지</h2> <div class="card" style="padding: 20px; border-radius: 15px; margin: 20px auto;"> <form class=" form-horizontal" method="post" th:object="${postDto}"> <h1 th:text="*{title}">제목</h1> <span>작성자 : </span> <span th:text="*{name}">Tester </span> <hr> <p class="lead" style="height: 300px; border-radius: 5px;" th:text="*{content}"></p> <hr> <div class="text-right" style="padding-right: 10px;"> <span class="text-right">작성일 : </span> <span class="text-right" th:text="*{writeTime}">작성일 </span> </div> <hr> <div class="btn_wrap text-center"> <a href="#" class="btn btn-default waves-effect waves-light">뒤로가기</a> <button type="submit" class="btn btn-primary waves-effect waves-light">수정하기</button> <button type="submit" class="btn btn-danger waves-effect waves-light">삭제하기</button> </div> </form> </div></div></body></html>

0

Spring Boot 게시판 만들기 7 - 특정 페이지를 가져오기

7. 특정 포스트를 불러오기특정 포스트 불러오기 요청 처리하기 PostController @GetMapping("/post/{postId}")public String getPostDetails(@PathVariable("postId")Long id, Model model){ Post post = postService.getPostById(id); PostDto postDto = PostDto.builder() .id(post.getId()) .name(post.getName()) .title(post.getTitle()) .content(post.getContent()) .writeTime(post.getWriteTime()) .build(); model.addAttribute("postDto", postDto); return "details";} PostControllerTest.java @Test@DisplayName("상세 페이지를 가져온다.")public void getPostDetails() throws Exception{ Post mockPost = Post.builder() .id(1L) .name("tester") .title("test") .content("test") .writeTime(LocalDateTime.now()) .build(); given(postService.getPostById(any())).willReturn(mockPost); ResultActions resultActions = mockMvc.perform(get("/post/1")); resultActions .andExpect(status().isOk()); verify(postService).getPostById(any());} PostControllerTest.java @Test@DisplayName("상세 페이지를 못 가져온다.")public void getPostDetailsException() throws Exception{ given(postService.getPostById(any())).willThrow(new PostNotExistedException(1L)); ResultActions resultActions = mockMvc.perform(get("/post/1")); resultActions .andExpect(status().isNotFound()); verify(postService).getPostById(any());} 포스트가 없는 경우에 대한 예외처리하기

0

Spring Boot 게시판 만들기 6 - 게시판 페이지 만들기

게시판 페이지 템플릿게시판 페이지도 게시판 작성페이지와 똑같이 Bootstrap 과 BootWatch 를 이용해 만들었다. <!DOCTYPE html><html lang="ko"><head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <link rel="stylesheet" href="./css/bootstrap.css"> <link rel="stylesheet" href="./css/custom.min.css"> <title>게시글 작성 페이지</title></head><body class="bg-light"><nav class="navbar navbar-expand-lg navbar-dark bg-primary fixed-top"> <a class="navbar-brand" href="#">게시판</a></nav><div class="container col-lg-6 "> <form class="form-inline my-2 my-lg-0 float-right" style="padding-bottom : 16px;"> <input class="form-control mr-sm-2" type="text" placeholder="Search"> <button class="btn btn-secondary my-2 my-sm-0" type="submit">Search</button> </form> <div class="table-responsive clearfix"> <table class="table table-hover"> <thead> <tr> <th>번호</th> <th>제목</th> <th>작성자</th> <th>등록일</th> </tr> </thead> <tbody> <tr> </tr> </tbody> </table> <div class="btn_wrap text-right"> <a href="#" class="btn btn-primary waves-effect waves-light">Write</a> </div> <div class="text-center "> <ul class="pagination" style="justify-content: center;"> <li class="page-item disabled"> <a class="page-link" href="#">&laquo;</a> </li> <li class="page-item active"> <a class="page-link" href="#">1</a> </li> <li class="page-item"> <a class="page-link" href="#">2</a> </li> <li class="page-item"> <a class="page-link" href="#">3</a> </li> <li class="page-item"> <a class="page-link" href="#">4</a> </li> <li class="page-item"> <a class="page-link" href="#">5</a> </li> <li class="page-item"> <a class="page-link" href="#">&raquo;</a> </li> </ul> </div> </div></div></body></html> 타임리프 문법 적용하기<!DOCTYPE html><html lang="ko" xmlns:th="http://www.thymeleaf.org"><head th:replace="fragments/head :: main-head"/><body class="bg-light"><nav th:replace="fragments/navbar :: main-nav"/><div class="container col-lg-6 "> <form class="form-inline my-2 my-lg-0 float-right" style="padding-bottom : 16px;"> <input class="form-control mr-sm-2" type="text" placeholder="Search"> <button class="btn btn-secondary my-2 my-sm-0" type="submit">Search</button> </form> <div class="table-responsive clearfix"> <table class="table table-hover"> <thead class="text-center"> <tr> <th>번호</th> <th>제목</th> <th>작성자</th> <th>등록일</th> <th >수정/삭제</th> </tr> </thead> <tbody class="text-center"> <tr th:each="Post:${PostList}"> <td class="align-middle" th:text="${PostStat.index+1}"></td> <td class="align-middle"> <a th:text="${Post.title}"></a> </td> <td class="align-middle" th:text="${Post.name}"></td> <td class="align-middle" th:text="${Post.writeTime}"></td> <td class="text-center align-middle"> <button class="btn btn-primary">수정</button> <button class="btn btn-danger">삭제</button> </td> </tr> </tbody> </table> <div class="btn_wrap text-right"> <a href="#" class="btn btn-primary waves-effect waves-light">Write</a> </div> <div class="text-center "> <ul class="pagination" style="justify-content: center;"> <li class="page-item disabled"> <a class="page-link" href="#">&laquo;</a> </li> <li class="page-item active"> <a class="page-link" href="#">1</a> </li> <li class="page-item"> <a class="page-link" href="#">2</a> </li> <li class="page-item"> <a class="page-link" href="#">3</a> </li> <li class="page-item"> <a class="page-link" href="#">4</a> </li> <li class="page-item"> <a class="page-link" href="#">5</a> </li> <li class="page-item"> <a class="page-link" href="#">&raquo;</a> </li> </ul> </div> </div></div></body></html>

0

Spring Boot 게시판 만들기 5 - 모든 Post 가져오기

5. 모든 포스트 가져오기모든 포스트 가져오기 요청 처리하기BoardController.java @Controller@RequiredArgsConstructorpublic class BoardController { private final PostService postService; @GetMapping("/") public String board(Model model){ List<Post> posts = postService.getAllPost(); model.addAttribute("PostList", posts); return "board"; }} 모든 Post 가져오기 요청에 대한 테스트 코드 작성BoardControllerTest.java @WebMvcTestclass BoardControllerTest { @Autowired private MockMvc mockMvc; @MockBean private PostService postService; @Test @DisplayName("모든 Post를 가져온다.") public void board() throws Exception { List<Post> posts = new ArrayList<>(); posts.add(Post.builder() .id(1L) .title("test") .name("tester") .content("test") .writeTime(LocalDateTime.now()) .build() ); given(postService.getAllPost()).willReturn(posts); ResultActions resultActions = mockMvc.perform(get("/")); resultActions .andExpect(status().isOk()) .andDo(print()); verify(postService).getAllPost(); }} 데이터 조회@Service@RequiredArgsConstructorpublic class PostService { private final PostRepository postRepository; public Post addPost(Post newPost) { return postRepository.save(newPost); } public List<Post> getAllPost() { return postRepository.findAll(); }}

0

Spring Boot 게시판 만들기 4 - My SQL과 연동하기

4. My SQL과 연동의존성 추가My Sql과 연동하기 위해서는 Springboot프로젝트에 의존성을 추가해야 한다. build.gradle implementation 'mysql:mysql-connector-java' 데이터베이스 접속 설정하기application-mysql.yml spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/[DB]?serverTimezone=UTC&characterEncoding=UTF-8 username: [DB 접속 Id] password: [DB 접송 Password] 접속 설정 가져오기