쌍용교육(JAVA)/Spring

쌍용교육 -JSP수업 82일차 - ch09_SpringJDBC(2)

구 승 2024. 6. 20. 17:45

버전 일부 수정

 

appServlet => servlet-context.xml 내용추가

<!-- 정적 파일을 요청할 때 /resources/** 패턴의 모든 요청을
		location에 지정한 경로 /resources/에 있는 파일에 매핑 -->
	<resources location="/resources/" mapping="/resources/**"/>

servlet-context.xml을 추가하기 전 화면
추가하고 나니까 css가 적용된 것을 볼 수 있다.

BoardVO 내용추가 

package kr.spring.board.vo;

import java.sql.Date;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;

/*
 * @NotNull : null만 허용하지 않음
 * @NotBlank : null, ""(빈문자열)," "(공백)을 모두 허용하지않음
 * @NotEmpty : null, ""(빈문자열)을 허용하지 않음
 */
public class BoardVO {
	private int num;
	@NotBlank
	private String writer;
	@NotBlank
	private String title;
	@NotBlank
	private String passwd;
	@NotEmpty
	private String content;
	private Date reg_date;
	public int getNum() {
		return num;
	}
	public void setNum(int num) {
		this.num = num;
	}
	public String getWriter() {
		return writer;
	}
	public void setWriter(String writer) {
		this.writer = writer;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getPasswd() {
		return passwd;
	}
	public void setPasswd(String passwd) {
		this.passwd = passwd;
	}
	public String getContent() {
		return content;
	}
	public void setContent(String content) {
		this.content = content;
	}
	public Date getReg_date() {
		return reg_date;
	}
	public void setReg_date(Date reg_date) {
		this.reg_date = reg_date;
	}
	@Override
	public String toString() {
		return "BoardVO [num=" + num + ", writer=" + writer + ", title=" + title + ", passwd=" + passwd + ", content="
				+ content + ", reg_date=" + reg_date + "]";
	}
	
}

pom.xml 내용추가

VO에 @Blank 같은 것들이 작동이 되지않는 부분을 dependency로 해결

<dependency>
		    <groupId>org.hibernate</groupId>
		    <artifactId>hibernate-validator</artifactId>
		    <version>6.0.18.Final</version>
		</dependency>

src/main/resources => messages 폴더 => validation.properties 파일

NotBlank.writer=작성자는 필수 항목
NotBlank.title=제목은 필수 항목
NotBlank.passwd=비밀번호는 필수 항목
NotEmpty.content=내용은 필수 항목
invalidPassword=비밀번호 불일치

 servlet-context.xml 내용추가

<!-- 리소스 번들 지정 -->
	<beans:bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
		<beans:property name="basenames">
			<beans:list>
				<beans:value>messages.validation</beans:value>
			</beans:list>
		</beans:property>
	</beans:bean>

BoardController 내용추가

package kr.spring.board.controller;

import javax.validation.Valid;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;


import kr.spring.board.vo.BoardVO;

@Controller
public class BoardController {
	//로그 처리 (로그 대상 지정)
	private static final Logger log = LoggerFactory.getLogger(BoardController.class);
	/*
	 * 로그 레벨
	 * FATAL : 가장 심각한 오류
	 * ERROR : 일반적인 오류
	 * WARN  : 주의를 요하는 경우(경고, 에러는 아님)
	 * INFO  : 런타임시 관심있는 경우
	 * DEBUG : 시스템 흐름과 관련된 상세 상태
	 * TRACE : 가장 상세한 정보
	 */
	//유효성 체크를 위한 폼 초기화
	@ModelAttribute
	public BoardVO initCommand() {
		
		return new BoardVO();
	}
	
	//폼 호출
	@GetMapping("/insert.do")
	public String form() {
		
		return "insertForm";
	}
	//전송된 데이터 처리
	@PostMapping("/insert.do")
	public String submit(@Valid BoardVO vo, BindingResult result) {
		
		log.debug("<<BoardVO>> : "+vo);
		
		//유효성 체크 결과 오류가 있으면 폼을 호출
		if(result.hasErrors()) { //출력을 했을 떄 출력이 되지않은 것들을 확인하기 위해서 (즉 바로위에서 디버그하고 남은것들을 보여줌)
			return form();
		}
		
		return "redirect:/list.do";
	}
	
	@RequestMapping("/list.do")
	public ModelAndView process() {
		
		ModelAndView mav = new ModelAndView();
		mav.setViewName("selectList"); //중간 경로가 없음.
		
		return mav;
	}
}

log4j.xml 에 이 내용이 있어야지 디버그 모드가 적용되기 때문에 없으면 필히 넣어야됨.

kr.spring의 하위레벨은 디버그 모드이다. 라는 내용

<!-- Application Loggers -->
	<logger name="kr.spring">
		<level value="debug" />
	</logger>

 

DEBUG: kr.spring.board.controller.BoardController - <<BoardVO>> : BoardVO [num=0, writer=, title=, passwd=, content=, reg_date=null]

resources/css => style.css 내용추가

.error-color{
	color:red;
}

src/main/resources => config => jdbc.properties

jdbc.driverClassName=oracle.jdbc.OracleDriver
jdbc.url=jdbc:oracle:thin:@localhost:1521:xe
jdbc.username=user01
jdbc.password=1234

이 파일을 root-context.xml에 연결되도록한다.

root-context.xml 내용추가

<context>태그가 인식되도록

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context" 
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">

beans xmlns를 수정한다

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context" 
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">
	<!-- 빈 자동 스캔 -servlet-context.xml에서 Controller를 자동 스캔 설정해서 아래 설정에서는 Controller 자동 스캔 제외 시키기-->
	<context:component-scan base-package="kr.spring.board">
														<!-- org.springframework.stereotype.Controller를 자동스캔에서 빼겠다라는 뜻 -->
		<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
	</context:component-scan>
	
	<context:property-placeholder location="classpath:config/jdbc.properties"/>
	
	<!-- 커넥션풀을 이용한 DataSource 설정 -->
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
		<property name="driverClassName" value="${jdbc.driverClassName}"/> <!-- ${}안에 값이 키값이고 호출할 때 이 값을 사용 -->
		<property name="url" value="${jdbc.url}"/>
		<property name="username" value="${jdbc.username}"/>
		<property name="password" value="${jdbc.password}"/>
		<!-- 최대 커넥션 개수 -->
		<property name="maxActive" value="50"/>
		<!-- 접속이 없을 경우 최대 유지 커넥션 개수 -->
		<property name="maxIdle" value="30"/>
		<!-- 접속이 없을 경우 최소 유지 커넥션 개수  -->
		<property name="minIdle" value="20"/>
		<!-- 최대 대기시간(초) : 초과시 연결 실패 오류 발생하게함-->
		<property name="maxWait" value="5"/><!-- 5초동안 연결시 에러발생 -->
	</bean>
	
	<!-- JdbcTemplate 객체 생성 -->
	<bean name="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource"/>
	</bean>
	
	<!-- JDBC 기반 트랜잭션 관리자 설정 -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
		p:dataSource-ref="dataSource"/>
	
	<!-- 어노테이션 방식으로 처리할 때  -->
	<tx:annotation-driven transaction-manager="transactionManager"/> <!-- 이 태그를 쓰면 어노테이션 방식으로 처리할 수 있다. -->
	
</beans>

kr.spring.board.dao =>BoardDAO (클래스가 아닌 인터페이스)

package kr.spring.board.dao;

import java.util.List;

import kr.spring.board.vo.BoardVO;

public interface BoardDAO {
	public void insertBoard(BoardVO board);
	public int getBoardCount();
	public List<BoardVO> getBoardList(int startRow,int endRow);
	public BoardVO getBoard(int num);
	public void updateBoard(BoardVO board);
	public void deleteBoard(int num);
}

kr.spring.board.dao => BoardDAOImpl(클래스)

package kr.spring.board.dao;

import java.util.List;

import kr.spring.board.vo.BoardVO;

public class BoardDAOImpl implements BoardDAO{

	@Override
	public void insertBoard(BoardVO board) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public int getBoardCount() {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public List<BoardVO> getBoardList(int startRow, int endRow) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public BoardVO getBoard(int num) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void updateBoard(BoardVO board) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void deleteBoard(int num) {
		// TODO Auto-generated method stub
		
	}

}

데이터 베이스 연동

BoardDAOImpl

@Repository //@DAO라고 생각하면 이해가 쉽다. Repository는 저장소라는 뜻으로, 데이터베이스 역시 저장소임.
public class BoardDAOImpl implements BoardDAO{
	
	//SQL문을 정의하는 것
	private static final String INSERT_SQL = "INSERT INTO aboard(num,writer,title,passwd,content,reg_date) VALUES(aboard_seq.nextval,?,?,?,?,SYSDATE)"; 
	
	@Autowired // 연동은 주입을 받아서 처리해야됨으로 주입한다.
	private JdbcTemplate jdbcTemplate;
	
	@Override
	public void insertBoard(BoardVO board) {
		//INSERT를하든 DELETE를 하든 전부 .update 라고씀		
										//INSERT_SQL뒤에 오는 값들은 ?값들
		jdbcTemplate.update(INSERT_SQL,new Object[] {board.getWriter(),board.getTitle(),board.getPasswd(),board.getContent()}); 
		
	}
    .
    .
    .
    (생략)

kr.spring.board.service => BoardService (인터페이스)

BoardDAO와 같은 내용

package kr.spring.board.service;

import java.util.List;

import kr.spring.board.vo.BoardVO;

public interface BoardService {
	public void insertBoard(BoardVO board);
	public int getBoardCount();
	public List<BoardVO> getBoardList(int startRow,int endRow);
	public BoardVO getBoard(int num);
	public void updateBoard(BoardVO board);
	public void deleteBoard(int num);
}

kr.spring.board.service =>BoardServiceImpl

package kr.spring.board.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import kr.spring.board.dao.BoardDAO;
import kr.spring.board.vo.BoardVO;

@Service  //@Component와 같다고 생각하면됨
@Transactional  //하위 메소드의 자동으로 transcation을 적용시킬 때 
public class BoardServiceImpl implements BoardService{
	
	@Autowired
	private BoardDAO boardDAO;
	
	@Override
	public void insertBoard(BoardVO board) {
		boardDAO.insertBoard(board);
		
	}

	@Override
	public int getBoardCount() {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public List<BoardVO> getBoardList(int startRow, int endRow) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public BoardVO getBoard(int num) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void updateBoard(BoardVO board) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void deleteBoard(int num) {
		// TODO Auto-generated method stub
		
	}

}

BoardController 내용추가

	@Autowired
	private BoardService boardService;
//글 등록
boardService.insertBoard(vo);

 

에러 수정 후 재등록이기 때문에 내용이 조금 다름

 

BoardDAOImpl

페이지처리

private static final String SELECT_COUNT_SQL = "SELECT COUNT(*) FROM aboard";
@Override
	public int getBoardCount() {
		return jdbcTemplate.queryForObject(SELECT_COUNT_SQL, Integer.class);
		
	}

목록작업

private static final String SELECT_LIST_SQL = 
			"SELECT * FROM (SELECT a.*, rownum rnum FROM("
			+ "SELECT * FROM aboard ORDER BY reg_date DESC)a) "
			+ "WHERE rnum>=? AND rnum<=?";
            
 //하나의 레코드의 데이터를 자바빈에 매핑(목록처리를 할 때 사용)
	private RowMapper<BoardVO> rowMapper = new RowMapper<BoardVO>() {
		public BoardVO mapRow(ResultSet rs, int rowNum) throws SQLException{
			
			BoardVO board = new BoardVO();
			board.setNum(rs.getInt("num"));
			board.setWriter(rs.getString("writer"));
			board.setTitle(rs.getString("title"));
			board.setPasswd(rs.getString("passwd"));
			board.setContent(rs.getString("content"));
			board.setReg_date(rs.getDate("reg_date"));
			
			return board;
		}
	};
@Override
	public List<BoardVO> getBoardList(int startRow, int endRow) {
		List<BoardVO> list = jdbcTemplate.query(SELECT_LIST_SQL,new Object[] {startRow,endRow},rowMapper);
		
		return list;
	}

BoardServiceImpl

페이지처리와 목록처리를 전달

@Override
	public int getBoardCount() {
		
		return boardDAO.getBoardCount();
	}

	@Override
	public List<BoardVO> getBoardList(int startRow, int endRow) {
		
		return boardDAO.getBoardList(startRow, endRow);
	}

kr.spring.util => PagingUtil.java (이전 프로젝트에서 가져옴)

페이지 처리를 위해서 가져옴

BoardServiceImpl에서 작성이 완료되면

BoardController 로 전달된다.

BoardController 내용추가

	@RequestMapping("/list.do")
	public ModelAndView process(@RequestParam(value="pageNum",defaultValue="1")int currentPage) {
		
		int count = boardService.getBoardCount();
		
		log.debug("<<count>> : "+count);
		
		//페이지 처리
		PagingUtil page = new PagingUtil(currentPage,count,20,10,"list.do");
		
		//목록 호출
		List<BoardVO> list = null;
		if(count > 0 ) {
			list = boardService.getBoardList(page.getStartRow(),page.getEndRow());
		}
		
		ModelAndView mav = new ModelAndView();
		mav.setViewName("selectList"); //중간 경로가 없음.
		
		mav.addObject("count",count);
		mav.addObject("list",list);
		mav.addObject("page",page.getPage());
		return mav;
	}

@RequestParam(value="pageNum",defaultValue="1")intcurrentPage 를 추가 

이 코드 설명

즉 currentPage 값에 pageNum 값이 들어간다.

 

 

views/selectList.jsp 내용추가

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>게시판 목록</title>
<link rel="stylesheet" href="${pageContext.request.contextPath}/resources/css/style.css" type="text/css">
</head>
<body>
<div class="page-main">
	<h2>게시판 목록</h2>
	<div class="align-right">
		<input type="button" value="글쓰기" onclick="location.href='insert.do'">
	</div>
	<c:if test="${count ==0}">
	<div class="result-display">표시할 내용이 없습니다.</div>
	</c:if>
	<c:if test="${count >0}">
	<table>
		<tr>
			<th>번호</th>
			<th>제목</th>
			<th>작성자</th>
			<th>작성일</th>
		</tr>
		<c:forEach var="board" items="${list}">
		<tr>
			<td>${board.num}</td>
			<td><a href="detail.do?num=${board.num}">${board.title}</a></td>
			<td>${board.writer}</td>
			<td>${board.reg_date}</td>
		</tr>
		</c:forEach>
	</table>
	<div class="align-center">${page}</div>
	</c:if>
</div>
</body>
</html>

 

DEBUG: kr.spring.board.controller.BoardController - <<count>> : 1
WARN : org.springframework.web.servlet.PageNotFound - No mapping for GET /JDBC/detail.do

BoardDAOImpl 내용추가

detail 내용 추가

private static final String SELECT_DETAIL_SQL = "SELECT * FROM aboard WHERE num=?";
@Override
	public BoardVO getBoard(int num) {
		
		return jdbcTemplate.queryForObject(SELECT_DETAIL_SQL,new Object[] {num},rowMapper);
	}

BoardServiceImpl 내용추가

	@Override
	public BoardVO getBoard(int num) {
		
		return boardDAO.getBoard(num);
	}

BoardController 내용추가

//글상세
	@RequestMapping("/detail.do")
	public ModelAndView detail(int num) {
		log.debug("<<num>> : "+num);
		
		BoardVO board = boardService.getBoard(num);
								//뷰이름		,    속성명 , 속성값
		return new ModelAndView("selectDetail","board",board); 
	}
}

views => selectDetail.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>글상세</title>
<link rel="stylesheet" href="${pageContext.request.contextPath}/resources/css/style.css" type="text/css">
</head>
<body>
<div class="page-main">
	<h2>${board.title}</h2>
	<p>
		글번호 : ${board.num}<br>
		작성자 : ${board.writer}<br>
		작성일 : ${board.reg_date}<br>
	</p>
	<hr width="90%" size="1" noshade="noshade">
	<p>
		${board.content}
	</p>
	<div class="align-center">
		<input type="button" value="수정" onclick="location.href='update.do?num=${board.num}'">
		<input type="button" value="삭제" onclick="location.href='delete.do?num=${board.num}'">
		<input type="button" value="목록" onclick="location.href='list.do'">
	</div>
</div>
</body>
</html>

수정폼 만들기

BoardController 내용추가

//수정 폼
	@GetMapping("/update.do")
	public String formUpdate(int num,Model model) { //ModelAndView는 반환을 해줘야하지만 Model은 반환을 할 필요가없고 전달만 하면 된다.
		model.addAttribute("boardVO",boardService.getBoard(num));
		
		return "updateForm";

views => updateForm.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>글수정</title>
<link rel="stylesheet" href="${pageContext.request.contextPath}/resources/css/style.css" type="text/css">
</head>
<body>
<div class="page_main">
	<h2>글수정</h2>
	<form:form action="update.do" modelAttribute="boardVO">
		<form:hidden path="num"/>
		<ul>
			<li>
				<form:label path="writer">작성자</form:label>
				<form:input path="writer"/>
				<form:errors path="writer" cssClass="error-color"/>
			</li>
			<li>
				<form:label path="title">제목</form:label>
				<form:input path="title"/>
				<form:errors path="title" cssClass="error-color"/>
			</li>
			<li>
				<form:label path="passwd">비밀번호</form:label>
				<form:password path="passwd"/>
				<form:errors path="passwd" cssClass="error-color"/>
			</li>
			<li>
				<form:label path="content">내용</form:label>
				<form:textarea path="content"/>
				<form:errors path="content" cssClass="error-color"/>
			</li>
		</ul>
		<div class="align-center">
			<form:button>수정</form:button>
			<input type="button" value="목록" onclick="location.href='list.do'">
		</div>
	</form:form>
</div>
</body>
</html>

BoardController 의 model.addAttribute("boardVO",boardService.getBoard(num));

여기에있는 boardVO와

updateForm.jsp 의 <form:form action="update.do" modelAttribute="boardVO">

여기에 있는 boardVO가 일치해야 결과가 올바르게 나온다.

 

추가로 <form:hidden path="num"/> 을 쓰지않으면 num값이 전달되지않아 수정이 되질않음

수정

BoardDAOImpl 내용추가

private static final String UPDATE_SQL = "UPDATE aboard SET writer=?,title=?,content=? WHERE num=?";
@Override
	public void updateBoard(BoardVO board) {
		jdbcTemplate.update(UPDATE_SQL,new Object[] {board.getWriter(),board.getTitle(),board.getContent(),board.getNum()});
		
	}

BoardServiceImpl 내용추가

@Override
	public void updateBoard(BoardVO board) {
		boardDAO.updateBoard(board);
		
	}

BoardController 내용추가

@PostMapping("/update.do") //이걸 명시하지않으면 Post로 전달하지못해서 에러가난다.
	//전송된 데이터 처리
	public String submitUpdate(@Valid BoardVO vo, BindingResult result ) {
		log.debug("<<BoardVO>> : " +vo);
		
		//유효성 체크 결과 오류가 있으면 폼을 호출
		if(result.hasErrors()) {
			return "updateForm"; //formUpdate 메서드를 리턴하지 않은이유는 num값과 model값을 같이 보내야되고 그게 코드가 더 길어지기 때문에 쓰지않음
		}
		
		//DB에 저장된 비밀번호 구하기(비밀번호 일치여부 확인을 위해)
		BoardVO db_board = boardService.getBoard(vo.getNum());
		
		//비밀번호 일치 여부 체크
		//비밀번호가 일치하지 않을 떄
		if(!db_board.getPasswd().equals(vo.getPasswd())) {
							//   필드  		에러코드
			result.rejectValue("passwd","invalidPassword");
			return "updateForm";
		}
		//비밀번호가 일치할 때
		//글수정
		boardService.updateBoard(vo);
		
		return "redirect:/list.do";
	}

비밀번호가 틀렸을 시
비밀번호 일치시 수정완료

삭제

BoardDAOImpl 내용추가 

private static final String DELETE_SQL = "DELETE FROM aboard WHERE num=?";
@Override
	public void deleteBoard(int num) {
		jdbcTemplate.update(DELETE_SQL,new Object[] {num});
		
	}

BoardServiceImpl 내용추가

@Override
	public void deleteBoard(int num) {
		boardDAO.deleteBoard(num);
		
	}

BoardController 내용추가

//삭제 폼 호출
	@GetMapping("/delete.do")
	public String formDelete(BoardVO vo) {
		
		return "deleteForm";
	}

view=>deleteForm.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>게시판</title>
<link rel="stylesheet" href="${pageContext.request.contextPath}/resources/css/style.css" type="text/css">
</head>
<body>
<div class="page-main">
	<h2>글 삭제</h2>
	<form:form action="delete.do" modelAttribute="boardVO">
		<form:hidden path="num"/>
		<ul>
			<li>
				<form:label path="passwd">비밀번호</form:label>
				<form:password path="passwd"/>
				<form:errors path="passwd" cssClass="error-color"/>
			<li>
		</ul>
		<div class="align-center">
			<input type="submit" value="삭제">
			<input type="button" value="목록" onclick="location.href='list.do'">
		</div>
	</form:form>
</div>
</body>
</html>

BoardController 내용추가

//전송된 데이터 처리
	@PostMapping("/delete.do")
	public String submitDelete(@Valid BoardVO vo, BindingResult result) {
		
		log.debug("<<BoardVO>> : "+ vo);
		
		//BoardVO에는 비밀번호 말고도 title같은 것들이 @NotBlank로 쓰여져있는데 비밀번호만 쓰게하려함(이 방법을 안쓰면 VO를 따로 만들어야되는 번거로움이생김)
		//비밀번호만 유효성 체크 결과 오류가 있으면 폼 호출
		if(result.hasFieldErrors("passwd")) {//hasFieldErrors(): 괄호안에 값만 에러가 있는지 체크하는 함수
			return "deleteForm";
		}
		
		//DB에 저장된 비밀번호 구하기
		BoardVO db_board = boardService.getBoard(vo.getNum());
		
		//비밀번호 일치 여부 체크
		//비밀번호가 틀렸을 시
		if(!db_board.getPasswd().equals(vo.getPasswd())) {
			result.rejectValue("passwd","invalidPassword");
			return "deleteForm";
		}
		
		boardService.deleteBoard(vo.getNum());
		
		return "redirect:/list.do";
	}

삭제시 게시판 목록으로 이