
자바 스크립트를 사용하지 않고 HTTP 1.0을 가지고 블로그 제작하기
- GET, POST만 지원
POST → INSERT, DELETE, UPDATE
- HTML5 (form 태그 : get, post) (a태그 : get 요청)
1. 삭제가 가능한 페이지 찾기 → 상세페이지(detail)
- 로그인을 해야 삭제가 가능함
- 삭제 버튼을 누르면 삭제되고 목록에 반영되야 함

{{> layout/header}}
<div class="container p-5">
{{#pageOwner}}
<!-- 수정삭제버튼 -->
<div class="d-flex justify-content-end">
<button class="btn btn-warning me-1">수정</button>
<button class="btn btn-danger">삭제</button>
</div>
{{/pageOwner}}
<div class="d-flex justify-content-end">
<b>작성자</b> : {{board.username}}
</div>
<!-- 게시글내용 -->
<div>
<h2><b>{{board.title}}</b></h2>
<hr />
<div class="m-4 p-2">
{{board.content}}
</div>
</div>
<!-- 댓글 -->
<div class="card mt-3">
<!-- 댓글등록 -->
<div class="card-body">
<form action="/reply/save" method="post">
<textarea class="form-control" rows="2" name="comment"></textarea>
<div class="d-flex justify-content-end">
<button type="submit" class="btn btn-outline-primary mt-1">댓글등록</button>
</div>
</form>
</div>
<!-- 댓글목록 -->
<div class="card-footer">
<b>댓글리스트</b>
</div>
<div class="list-group">
<!-- 댓글아이템 -->
<div class="list-group-item d-flex justify-content-between align-items-center">
<div class="d-flex">
<div class="px-1 me-1 bg-primary text-white rounded">cos</div>
<div>댓글 내용입니다</div>
</div>
<form action="/reply/1/delete" method="post">
<button class="btn">🗑</button>
</form>
</div>
<!-- 댓글아이템 -->
<div class="list-group-item d-flex justify-content-between align-items-center">
<div class="d-flex">
<div class="px-1 me-1 bg-primary text-white rounded">ssar</div>
<div>댓글 내용입니다</div>
</div>
<form action="/reply/1/delete" method="post">
<button class="btn">🗑</button>
</form>
</div>
</div>
</div>
</div>
{{> layout/footer}}
2. detail에 <form>삭제</form>로 감싸기
- "/board/{{board.id/delete}} 추가하기
- 요청 방법은 post
- <form>태그 안에 button의 기본 디폴트는 submit


{{> layout/header}}
<div class="container p-5">
{{#pageOwner}}
<!-- 수정삭제버튼 -->
<div class="d-flex justify-content-end">
<button class="btn btn-warning me-1">수정</button>
<form action="/board/{{board.id}}/delete" method="post">
<button class="btn btn-danger">삭제</button>
</form>
</div>
{{/pageOwner}}
<div class="d-flex justify-content-end">
<b>작성자</b> : {{board.username}}
</div>
<!-- 게시글내용 -->
<div>
<h2><b>{{board.title}}</b></h2>
<hr />
<div class="m-4 p-2">
{{board.content}}
</div>
</div>
<!-- 댓글 -->
<div class="card mt-3">
<!-- 댓글등록 -->
<div class="card-body">
<form action="/reply/save" method="post">
<textarea class="form-control" rows="2" name="comment"></textarea>
<div class="d-flex justify-content-end">
<button type="submit" class="btn btn-outline-primary mt-1">댓글등록</button>
</div>
</form>
</div>
<!-- 댓글목록 -->
<div class="card-footer">
<b>댓글리스트</b>
</div>
<div class="list-group">
<!-- 댓글아이템 -->
<div class="list-group-item d-flex justify-content-between align-items-center">
<div class="d-flex">
<div class="px-1 me-1 bg-primary text-white rounded">cos</div>
<div>댓글 내용입니다</div>
</div>
<form action="/reply/1/delete" method="post">
<button class="btn">🗑</button>
</form>
</div>
<!-- 댓글아이템 -->
<div class="list-group-item d-flex justify-content-between align-items-center">
<div class="d-flex">
<div class="px-1 me-1 bg-primary text-white rounded">ssar</div>
<div>댓글 내용입니다</div>
</div>
<form action="/reply/1/delete" method="post">
<button class="btn">🗑</button>
</form>
</div>
</div>
</div>
</div>
{{> layout/footer}}
3. 인증, 권한 체크하기
- 기존에 findById의 이름을 findByIdWithUser로 변경하기 / 헷갈릴 수 있음
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.PostMapping;
import shop.mtcoding.blog.user.User;
import java.util.List;
@RequiredArgsConstructor
@Controller
public class BoardController {
// HttpSession 객체를 참조
private final HttpSession session;
private final BoardRepository boardRepository; // DI
@GetMapping({"/", "/board"})
public String index(HttpServletRequest request) {
User sessionUser = (User) session.getAttribute("sessionUser");
if (sessionUser == null) {
System.out.println("로그인 안된 상태입니다");
} else {
System.out.println("로그인 된 상태입니다");
}
List<Board> boardList = boardRepository.findAll();
request.setAttribute("boardList", boardList); // ("key", value)
return "index";
}
@GetMapping("/board/saveForm")
public String saveForm() { // session 영역에 접근하기 위한
// 1. session 영역에 sessionUser 키 값에 user 객체가 있는지 체크하기
User sessionUser = (User) session.getAttribute("sessionUser");
// 2. 값이 null이면 로그인 페이지로 리다이렉션
if (sessionUser == null) {
return "redirect:/loginForm";
}
// 3. null이 아니면 /board/saveForm으로 이동
return "board/saveForm";
}
@PostMapping("board/save") //save 주소 만들기
public String save(BoardRequest.SaveDTO requestDTO, HttpServletRequest request) {
// 1. 인증 체크
User sessionUser = (User) session.getAttribute("sessionUser");
System.out.println("sessionUser:" + sessionUser);
if (sessionUser == null) {
return "redirect:/loginForm";
}
// 2. 바디 데이터 확인 및 유효성 검사
System.out.println(requestDTO);
if (requestDTO.getTitle().length() > 30) {
request.setAttribute("status", 400);
request.setAttribute("msg", "title의 길이가 30자를 초과해서는 안되요");
return "error/40x"; // BadRequest
}
// 3. 모델 위임
// insert into board_tb(title, content, user_id, created_at) values(?,?,?, now());
boardRepository.save(requestDTO, sessionUser.getId());
return "redirect:/";
}
// select b.id, b.title, b.content, b.user_id, u.username from board_tb b inner join user_tb u on b.user_id = u.id where b.id = ?
@GetMapping("/board/{id}")
public String detail(@PathVariable int id, HttpServletRequest request) {
System.out.println("id : " + id);
// 1. 바로 모델 진입 -> 상세보기 데이터 가져오기
// body 데이터가 없으면 유효성 검사할 필요 없음
BoardResponse.DetailDTO reponseDTO = boardRepository.findByIdWithUser(id); //메서드 이름 변경
// user 객체를 가져와서 session 값 받기 : object라 다운 캐스팅 해야함
User sessionUser = (User) session.getAttribute("sessionUser");
//System.out.println("sessionUser: " + sessionUser);
// 2. 페이지 주인 여부 체크(board의 userId와 sessionId의 값 비교)
boolean pageOwner = false;
if (reponseDTO.getUserId() == sessionUser.getId()) {
//System.out.println("getUserId:" + reponseDTO.getUserId());
pageOwner = true;
}
request.setAttribute("board", reponseDTO);
request.setAttribute("pageOwner", pageOwner); // 이 값을 mustache에게 줘야함!
return "board/detail";
}
}
- BoardRepository 작성하기
findById → findByIdWithUser 이름 변경
- findById() 구현하기
삭제할 데이터가 있는지 없는지 확인한 후에 삭제하는 것이 더 좋음!
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
public class BoardRepository {
private final EntityManager em;
public List<Board> findAll() {
Query query = em.createNativeQuery("select * from board_tb order by id desc", Board.class);
return query.getResultList();
}
public Board findById(int id) {
Query query = em.createNativeQuery("select * from board_tb where id = ?", Board.class);
query.setParameter(1, id);
Board board = (Board) query.getSingleResult();
return board;
}
public BoardResponse.DetailDTO findByIdWithUser(int idx) {
Query query = em.createNativeQuery("select b.id, b.title, b.content, b.user_id, u.username from board_tb b inner join user_tb u on b.user_id = u.id where b.id = ?");
query.setParameter(1, idx);
Object[] row = (Object[]) query.getSingleResult();
Integer id = (Integer) row[0];
String title = (String) row[1];
String content = (String) row[2];
int userId = (Integer) row[3];
String username = (String) row[4];
System.out.println("id : " + id);
System.out.println("title : " + title);
System.out.println("content : " + content);
System.out.println("userId : " + userId);
System.out.println("username : " + username);
BoardResponse.DetailDTO responseDTO = new BoardResponse.DetailDTO();
responseDTO.setId(id);
responseDTO.setTitle(title);
responseDTO.setContent(content);
responseDTO.setUserId(userId);
responseDTO.setUsername(username);
return responseDTO;
}
@Transactional
public void save(BoardRequest.SaveDTO requestDTO, int userId) {
Query query = em.createNativeQuery("insert into board_tb(title, content, user_id, created_at) values(?,?,?, now())");
query.setParameter(1, requestDTO.getTitle());
query.setParameter(2, requestDTO.getContent());
query.setParameter(3, userId);
query.executeUpdate();
}
}
4. 삭제하기
- deleteById() 구현하기
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
public class BoardRepository {
private final EntityManager em;
public List<Board> findAll() {
Query query = em.createNativeQuery("select * from board_tb order by id desc", Board.class);
return query.getResultList();
}
public Board findById(int id) {
Query query = em.createNativeQuery("select * from board_tb where id = ?", Board.class);
query.setParameter(1, id);
Board board = (Board) query.getSingleResult();
return board;
}
public BoardResponse.DetailDTO findByIdWithUser(int idx) {
Query query = em.createNativeQuery("select b.id, b.title, b.content, b.user_id, u.username from board_tb b inner join user_tb u on b.user_id = u.id where b.id = ?");
query.setParameter(1, idx);
Object[] row = (Object[]) query.getSingleResult();
Integer id = (Integer) row[0];
String title = (String) row[1];
String content = (String) row[2];
int userId = (Integer) row[3];
String username = (String) row[4];
System.out.println("id : " + id);
System.out.println("title : " + title);
System.out.println("content : " + content);
System.out.println("userId : " + userId);
System.out.println("username : " + username);
BoardResponse.DetailDTO responseDTO = new BoardResponse.DetailDTO();
responseDTO.setId(id);
responseDTO.setTitle(title);
responseDTO.setContent(content);
responseDTO.setUserId(userId);
responseDTO.setUsername(username);
return responseDTO;
}
@Transactional
public void save(BoardRequest.SaveDTO requestDTO, int userId) {
Query query = em.createNativeQuery("insert into board_tb(title, content, user_id, created_at) values(?,?,?, now())");
query.setParameter(1, requestDTO.getTitle());
query.setParameter(2, requestDTO.getContent());
query.setParameter(3, userId);
query.executeUpdate();
}
@Transactional
public void deleteById(int id) {
Query query = em.createNativeQuery("delete from board_tb where id = ?");
query.setParameter(1, id);
query.executeUpdate();
}
}
- BoardController에서 deleteById() 호출하기
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.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import shop.mtcoding.blog.user.User;
import java.util.List;
@RequiredArgsConstructor
@Controller
public class BoardController {
private final HttpSession session; // DI
private final BoardRepository boardRepository; // DI
@PostMapping("/board/{id}/delete") // body데이터가 없어서 유효성 검사 안해도 됨
public String delete(@PathVariable int id, HttpServletRequest request) {
// 1. 인증 검사하기
User sessionUser = (User) session.getAttribute("sessionUser");
if(sessionUser == null) {
return "redirect:/loginForm";
}
// 2. 권한 검사하기
Board board = boardRepository.findById(id);
if(board.getUserId() != sessionUser.getId()){
request.setAttribute("status", 403);
request.setAttribute("msg", "게시글을 삭제할 권한이 없습니다");
return "error/40x"; // 리다이렉트 하면 데이터 사라지니까 하면 안됨
}
boardRepository.deleteById(id);
return "redirect:/";
}
@PostMapping("/board/save")
public String save(BoardRequest.SaveDTO requestDTO, HttpServletRequest request) {
// 1. 인증 체크
User sessionUser = (User) session.getAttribute("sessionUser");
System.out.println("sessionUser:" + sessionUser);
if (sessionUser == null) {
return "redirect:/loginForm";
}
// 2. 바디 데이터 확인 및 유효성 검사
System.out.println(requestDTO);
if (requestDTO.getTitle().length() > 30) {
request.setAttribute("status", 400);
request.setAttribute("msg", "title의 길이가 30자를 초과해서는 안되요");
return "error/40x"; // BadRequest // 리다이렉션하면 데이터가 삭제되서 하면 안됨
}
// 3. 모델 위임
// insert into board_tb(title, content, user_id, created_at) values(?,?,?, now());
boardRepository.save(requestDTO, sessionUser.getId());
return "redirect:/";
}
// http://localhost:8080?page=0
@GetMapping({"/", "/board"})
public String index(HttpServletRequest request) {
List<Board> boardList = boardRepository.findAll();
request.setAttribute("boardList", boardList);
return "index";
}
@GetMapping("/board/saveForm") // /board/saveForm Get요청이 옴
public String saveForm() { // session 영역에 접근하기 위한
// 1. session 영역에 sessionUser 키 값에 user 객체가 있는지 체크하기
User sessionUser = (User) session.getAttribute("sessionUser");
// 2. 값이 null이면 로그인 페이지로 리다이렉션
if (sessionUser == null) {
return "redirect:/loginForm";
}
// 3. null이 아니면 /board/saveForm으로 이동
return "board/saveForm";
}
// 상세보기시 호출
@GetMapping("/board/{id}") // 1이 프라이머리키 -> 뭐든 넣어도 실행시키려면 변수화시켜서 {}
public String detail(@PathVariable int id, HttpServletRequest request) {
System.out.println("id : " + id);
// 1. 바로 모델 진입 -> 상세보기 데이터 가져오기
// body 데이터가 없으면 유효성 검사할 필요 없음
BoardResponse.DetailDTO reponseDTO = boardRepository.findByIdWithUser(id); //메서드 이름 변경
// user 객체를 가져와서 session 값 받기 : object라 다운 캐스팅 해야함
User sessionUser = (User) session.getAttribute("sessionUser");
//System.out.println("sessionUser: " + sessionUser);
// 2. 페이지 주인 여부 체크(board의 userId와 sessionId의 값 비교)
boolean pageOwner = false;
if (reponseDTO.getUserId() == sessionUser.getId()) {
//System.out.println("getUserId:" + reponseDTO.getUserId());
pageOwner = true;
}
request.setAttribute("board", reponseDTO);
request.setAttribute("pageOwner", pageOwner); // 이 값을 mustache에게 줘야함!
return "board/detail";
}
}

Share article