Spring boot
스프링부트 블로그 만들기 테스트
H_u
2024. 8. 22. 12:04
728x90
반응형
SMALL
요구사항
- 게시판을 구현하시오
- 익명 게시판 사이트입니다. 로그인이 없습니다.
- 제목과 내용은 20자를 넘어갈 수 없습니다.
- 글쓰기, 글목록보기, 글수정하기, 글삭제하기
- JSP,Mustache 선택 가능
- JPA, 마이바티스 선택 가능
심화1
위 요구사항을 만족하였다면 아래 1가지를 해보시오.
- 글목록보기를 5개씩 페이징하세요. prev, next 버튼 구현
심화2
위 요구사항을 만족하였다면 아래 1가지를 해보시오.
- 전체 글 개수가 21개라면, prev [0][1][2][3][4] next
- 예시) 3번을 클릭하면 ?page=3 페이지로 이동되면 됩니다.
- 예시) 글 개수가 21개이기 때문에 0~4 까지 번호가 만들어집니다.
기술스택
- Springboot 3.2.x
- JDK 21, 17 선택
- h2, MySQL 선택
의존성
- Lombok
- DevTools
- Spring WEB
- JPA
- h2
- Mustache
footer.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<div class="bg-light p-5 text-center">
<h4>Created by Metacoding</h4>
<h5>☎ 010-2222-7777</h5>
<button class="btn btn-outline-primary">고객센터</button>
<button class="btn btn-outline-primary">오시는길</button>
</div>
</body>
</html>
header.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<title>Blog</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<nav class="navbar navbar-expand-sm bg-dark navbar-dark">
<div class="container-fluid">
<a class="navbar-brand" href="/">Metacoding</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#collapsibleNavbar">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="collapsibleNavbar">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" href="/board/saveForm">글쓰기</a>
</li>
</ul>
</div>
</div>
</nav>
list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!-- heafer.jsp -->
<%@ include file="/WEB-INF/views/layout/header.jsp"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<div class="container p-5">
<c:choose>
<c:when test="${posts != null && !empty posts}">
<table class="table table-striped">
<thead>
<tr>
<th>번호</th>
<th>제목</th>
<th>내용</th>
<th>작성자</th>
<th></th>
</tr>
</thead>
<tbody>
<c:forEach var="post" items="${posts}">
<tr>
<td>${post.id}</td>
<td>${post.title}</td>
<td>${post.content}</td>
<td>${post.username}</td>
<td>
<div class="d-flex">
<form action="/board/delete/${post.id}" method="post">
<button class="btn btn-danger">삭제</button>
</form>
<form action="/board/update" method="get">
<input type="hidden" id="id" name="id" value="${post.id}">
<button class="btn btn-warning">수정</button>
</form>
</div>
</td>
</tr>
</c:forEach>
</tbody>
</table>
<div class="d-flex justify-content-center" >
<ul class="pagination">
<li class="page-item <c:if test='${currentPage == 1}'>disabled</c:if>">
<a class="page-link" href="?type=${type}&page=${currentPage - 1}&size=${size}" >Previous</a>
</li>
<c:forEach begin="1" end="${totalPages}" var="page" >
<li class="page-item <c:if test='${page == currentPage}'>active </c:if>">
<a class="page-link" href="?type=${type}&page=${page}&size=${size}" >${page}</a>
</li>
</c:forEach>
<li class="page-item <c:if test='${currentPage == totalPages}'>disabled</c:if>" >
<a class="page-link" href="?type=${type}&page=${currentPage + 1}&size=${size}" >Next</a>
</li>
</ul>
</div>
</c:when>
<c:otherwise>
<div>
<h5>아직 게시글이 없습니다</h5>
</div>
</c:otherwise>
</c:choose>
</div>
<!-- foofer.jsp -->
<%@ include file="/WEB-INF/views/layout/footer.jsp"%>
saveForm.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!-- header.jsp -->
<%@ include file="/WEB-INF/views/layout/header.jsp" %>
<div class="container p-5">
<div class="card">
<div class="card-header"><b>익명 글쓰기 화면입니다</b></div>
<div class="card-body">
<form action="/board/save" method="post">
<div class="mb-3">
<label for="username">작성자:</label>
<input type="text" id="username" name="username" required>
</div>
<div class="mb-3">
<label for="title">제목:</label>
<input type="text" class="form-control" id="title" placeholder="Enter title" name="title">
</div>
<div class="mb-3">
<label for="content">내용:</label>
<textarea class="form-control" rows="5" id="content" name="content"></textarea>
</div>
<button type="submit" class="btn btn-primary form-control">글쓰기완료</button>
</form>
</div>
</div>
</div>
<!-- footer.jsp -->
<%@ include file="/WEB-INF/views/layout/footer.jsp" %>
updateForm.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!-- header.jsp -->
<%@ include file="/WEB-INF/views/layout/header.jsp"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<div class="container p-5">
<div class="card">
<div class="card-header">
<b>글수정 화면입니다</b>
</div>
<div class="card-body">
<form action="/board/update" method="post">
<input type="hidden" name="id" value="${post.id}">
<label for="title">제목:</label>
<input type="text" id="title" name="title" value="${post.title}" required>
<br>
<label for="content">내용:</label>
<textarea id="content" name="content" required>${post.content}</textarea>
<br>
<label for="username">작성자:</label>
<input type="text" id="username" name="username" value="${post.username}" required>
<br>
<button type="submit">수정</button>
</form>
</div>
</div>
</div>
<!-- footer.jsp -->
<%@ include file="/WEB-INF/views/layout/footer.jsp"%>
PostService.java
package com.tenco.main.util;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.tenco.main.model.PostList;
import com.tenco.main.repository.PostRepository;
@Service
public class PostService {
@Autowired
private PostRepository postRepository;
public List<PostList> getAllPosts(int page, int size) {
int offset = (page - 1) * size;
return postRepository.findAll(offset, size);
}
public void savePost(PostList post) {
postRepository.insert(post);
}
public PostList getPostById(Long id) {
return postRepository.findById(id);
}
public void updatePost(PostList post) {
postRepository.update(post);
}
public void deletePost(Long id) {
postRepository.delete(id);
}
public int getTotalCount() {
return postRepository.count();
}
}
PostRepository.java
package com.tenco.main.repository;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import com.tenco.main.model.PostList;
@Mapper
public interface PostRepository {
void insert(PostList post);
List<PostList> findAll(@Param("offset") int offset, @Param("limit") int limit);
PostList findById(Long id);
void update(PostList post);
void delete(Long id);
int count();
}
PostList.java
package com.tenco.main.model;
import java.sql.Timestamp;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ToString
public class PostList {
private Long id;
private String title;
private String content;
private String username;
private Timestamp createdAt;
}
BoardController
package com.tenco.main.board;
import java.sql.Timestamp;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
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.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.tenco.main.model.PostList;
import com.tenco.main.util.PostService;
import lombok.RequiredArgsConstructor;
@Controller
@RequestMapping("/board")
@RequiredArgsConstructor
public class BoardController {
@Autowired
private final PostService postService;
@GetMapping("/")
public String index() {
return "index";
}
@GetMapping("/saveForm")
public String saveForm() {
return "board/saveForm";
}
@PostMapping("/save")
public String save(@RequestParam ("username") String username,
@RequestParam ("title") String title,
@RequestParam ("content") String content) {
PostList post = PostList.builder()
.username(username)
.title(title)
.content(content)
.createdAt(new Timestamp(System.currentTimeMillis()))
.build();
postService.savePost(post);
return "redirect:/board/list";
}
@GetMapping("/update")
public String updateForm(@RequestParam(name = "id")Long id, Model model) {
model.addAttribute("id", id);
PostList post = postService.getPostById(id);
model.addAttribute("post", post);
return "board/updateForm";
}
@PostMapping("/update")
public String update(@RequestParam("id") Long id,
@RequestParam("title") String title,
@RequestParam("content") String content,
@RequestParam("username") String username) {
System.out.println("업데이트");
PostList post = PostList.builder()
.id(id)
.title(title)
.content(content)
.username(username)
.build();
postService.updatePost(post);
return "redirect:/board/list";
}
@PostMapping("/delete/{id}")
public String delete(@PathVariable("id") Long id) {
postService.deletePost(id);
return "redirect:/board/list";
}
@GetMapping("/list")
public String list(@RequestParam(name = "page", defaultValue = "1") int page,
@RequestParam(name = "size", defaultValue = "5") int size,
Model model) {
List<PostList> posts = postService.getAllPosts(page, size);
int totalCount = postService.getTotalCount();
int totalPages = (int) Math.ceil((double) totalCount / size);
model.addAttribute("posts", posts);
model.addAttribute("currentPage", page);
model.addAttribute("totalPages", totalPages);
model.addAttribute("totalItems", totalCount);
return "board/list";
}
}
728x90
반응형
SMALL