관리 메뉴

거니의 velog

231201_SPRING 2 (과제 1) 본문

대덕인재개발원/대덕인재개발원_웹기반 애플리케이션

231201_SPRING 2 (과제 1)

Unlimited00 2023. 12. 1. 14:00

* CRUD 연습

- http://localhost/board/tag/list.do

- http://localhost/board/tag/detail.do

- http://localhost/board/tag/form.do


-- TagVO를 활용한 Board CRUD 연습
-- 게시판 테이블 작성
create table tagboard(                                             
	bo_no number(8) not null,                                       
	bo_title varchar2(300) not null,                                
	bo_content varchar2(4000) not null,                             
	bo_writer varchar2(300) not null,                               
	bo_date date not null,                                          
	bo_hit number(8) not null,                                      
	constraint pk_tagboard primary key(bo_no)                      
);                                                                  
                                                                     
create sequence seq_tagboard increment by 1 start with 1 nocache;  

-- 태그 테이블 작성
create table tag(
	bo_no number(8) not null,
	tag varchar2(300) not null,
	constraint fk_tagboard_bo_no foreign key(bo_no) references tagboard(bo_no)
);


[TagBoardVO.java]

package kr.or.ddit.vo.test;

import java.util.List;

import lombok.Data;

@Data
public class TagBoardVO {
	private int boNo;
	private String boTitle;
	private String boContent;
	private String boWriter;
	private String boDate;
	private int boHit;
	private List<TagVO> tagList;
	private String tag;
	
	private String searchType;
	private String searchWord;
}

[TagVO.java]

package kr.or.ddit.vo.test;

import lombok.Data;

@Data
public class TagVO {
	private int boNo;
	private String tagName;
}

[TagBoardController.java]

package kr.or.ddit.controller.test.web;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.inject.Inject;

import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import kr.or.ddit.ServiceResult;
import kr.or.ddit.controller.test.ITestService;
import kr.or.ddit.vo.test.TagBoardVO;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Controller
@RequestMapping("/board/tag")
public class TagBoardController {

	@Inject
	private ITestService service;
	
	// 태그 게시판 목록 
	@RequestMapping(value="/list.do", method = RequestMethod.GET)
	public String tagList(
			@RequestParam(required = false, defaultValue = "title") String searchType, 
			@RequestParam(required = false) String searchWord, 
			Model model
			) {
		
		// 검색 기능
		// 검색을 했을 때의 조건은 키워드(searchWord)가 넘어왔을 때 정확하게 검색을 진행한 것이므로
		// 이 때, 검색을 진행하기 위한 타입과 키워드를 TagBoardVO에 셋팅하고 목록을 조회해야 함.
		TagBoardVO tagboard = new TagBoardVO();
		if(StringUtils.isNotBlank(searchWord)) {
			tagboard.setSearchType(searchType);
			tagboard.setSearchWord(searchWord);
		}
		
		List<TagBoardVO> tagboardList = service.list(tagboard);
		model.addAttribute("tagboardList", tagboardList);
		model.addAttribute("tagboard", tagboard);
		return "test/list";
	}
	
	// 태그 게시판 등록
	@RequestMapping(value="/form.do", method = RequestMethod.GET)
	public String tagRegisterForm() {
		return "test/form";
	}
	
	@RequestMapping(value="/form.do", method = RequestMethod.POST)
	public String tagRegister(
			TagBoardVO tagboard, 
			Model model, 
			RedirectAttributes ra
			) {
		String goPage = "";
		
		Map<String, String> errors = new HashMap<String, String>();
		if(StringUtils.isBlank(tagboard.getBoTitle())) {
			errors.put("boTitle", "제목을 입력해주세요.");
		}
		if(StringUtils.isBlank(tagboard.getBoContent())) {
			errors.put("boContent", "내용을 입력해주세요.");
		}
		
		if(errors.size() > 0) {
			model.addAttribute("errors", errors);
			model.addAttribute("tagboard", tagboard);
			goPage = "test/form";
		} else {
			tagboard.setBoWriter("a001");
			ServiceResult result = service.register(tagboard);
			if(result.equals(ServiceResult.OK)) {
				goPage = "redirect:/board/tag/list.do";
				ra.addFlashAttribute("message", "게시글 등록이 완료되었습니다.");
			}else {
				model.addAttribute("tagboard", tagboard);
				model.addAttribute("message", "서버 에러, 다시 시도해 주세요!");
				goPage = "test/form";
			}
		}
		
		return goPage;
	}
	
	// 태그 게시판 상세 화면
	@RequestMapping(value="/detail.do", method = RequestMethod.GET)
	public String tagDetail(int boNo, Model model) {
		service.incrementHit(boNo); // 게시글 조회수 증가
		TagBoardVO tagboard = service.read(boNo); // 게시글 정보에 해당하는 게시글 정보 가져오기
		model.addAttribute("tagboard", tagboard);
		return "test/detail";
	}
	
	// 태그 게시판 수정
	@RequestMapping(value="/modify.do", method = RequestMethod.GET)
	public String tagModifyForm(int boNo, Model model) {
		TagBoardVO tagboard = service.read(boNo);
		model.addAttribute("tagboard", tagboard);
		model.addAttribute("status", "u"); // '수정입니다' flag
		return "test/form";
	}
	
	@RequestMapping(value="/modify.do", method = RequestMethod.POST)
	public String tagModify(
			TagBoardVO tagboard, 
			Model model, 
			RedirectAttributes ra
			) {
		log.info("수정 기능 메서드에 진입했습니다.");
		
		String goPage = "";
		
		ServiceResult result = service.modify(tagboard);
		if(result.equals(ServiceResult.OK)) { // 수정 성공
			goPage = "redirect:/board/tag/detail.do?boNo=" + tagboard.getBoNo();
			ra.addFlashAttribute("message", "게시글 수정이 완료되었습니다!");
		}else {  // 수정 실패
			model.addAttribute("tagboard", tagboard);
			model.addAttribute("message", "수정에 실패했습니다!");
			model.addAttribute("status", "u");
			goPage = "test/form";
		}
		
		return goPage;
	}
	
	// 태그 게시판 삭제
	@RequestMapping(value = "/delete.do", method = RequestMethod.POST)
	public String tagDelete(int boNo, Model model, RedirectAttributes ra) {
		String goPage = "";
		
		ServiceResult result = service.delete(boNo);
		if(result.equals(ServiceResult.OK)) { // 삭제 성공
			goPage = "redirect:/board/tag/list.do";
			ra.addFlashAttribute("message", "게시글 삭제가 완료되었습니다!");
		}else { // 삭제 실패
			goPage = "redirect:/board/tag/detail.do?boNo=" + boNo;
			ra.addFlashAttribute("message", "게시글 삭제에 실패했습니다!");
		}
		
		return goPage;
	}
	
}

[ITestService.java]

package kr.or.ddit.controller.test;

import java.util.List;

import kr.or.ddit.ServiceResult;
import kr.or.ddit.vo.test.TagBoardVO;

public interface ITestService {

	public ServiceResult register(TagBoardVO tagboard);
	public List<TagBoardVO> list(TagBoardVO tagboard);
	public void incrementHit(int boNo);
	public TagBoardVO read(int boNo);
	public ServiceResult modify(TagBoardVO tagboard);
	public ServiceResult delete(int boNo);

}

[TestServiceImpl.java]

package kr.or.ddit.controller.test.service;

import java.util.List;

import javax.inject.Inject;

import org.springframework.stereotype.Service;

import kr.or.ddit.ServiceResult;
import kr.or.ddit.controller.test.ITestService;
import kr.or.ddit.mapper.ITestMapper;
import kr.or.ddit.vo.test.TagBoardVO;
import kr.or.ddit.vo.test.TagVO;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class TestServiceImpl implements ITestService {

	@Inject
	private ITestMapper mapper;
	
	@Override
	public ServiceResult register(TagBoardVO tagboard) {
		ServiceResult result = null;
		
		// 게시글 1개를 등록
		int status = mapper.create(tagboard);
		
		// 여러 개의 태그를 등록
		String tag = tagboard.getTag();
		String[] tagList = tag.split(" ");
		for(int i = 0; i < tagList.length; i++) {
			TagVO tagVO = new TagVO();
			String tagVal = tagList[i];
			log.info("tagVal : " + tagVal);
			tagVO.setBoNo(tagboard.getBoNo());
			tagVO.setTagName(tagVal);
			mapper.createTag(tagVO);
		}
		
		if(status > 0) {
			result = ServiceResult.OK;
		}else {
			result = ServiceResult.FAILED;
		}
		
		return result;
	}

	@Override
	public List<TagBoardVO> list(TagBoardVO tagboard) {
		return mapper.list(tagboard);
	}
	
	@Override
	public void incrementHit(int boNo) {
		mapper.incrementHit(boNo);
	}

	@Override
	public TagBoardVO read(int boNo) {
		return mapper.read(boNo);
	}

	@Override
	public ServiceResult modify(TagBoardVO tagboard) {
		ServiceResult result = null;
		
		// 1) 게시판 글 수정
		int status = mapper.modify(tagboard);
		
		// 2) 태그를 수정
		//		-> 게시판 번호에 대한 태그를 모두 삭제
		int boNo = tagboard.getBoNo();
		mapper.deleteTag(boNo);
		
		//		-> 새롭게 수정될 태그들을 insert
		String tag = tagboard.getTag();
		String[] tagList = tag.split(" ");
		for(int i = 0; i < tagList.length; i++) {
			TagVO tagVO = new TagVO();
			String tagVal = tagList[i];
			tagVO.setBoNo(tagboard.getBoNo());
			tagVO.setTagName(tagVal);
			mapper.createTag(tagVO);
		}
		
		if(status > 0) {
			result = ServiceResult.OK;
		}else {
			result = ServiceResult.FAILED;
		}
		
		return result;
	}

	@Override
	public ServiceResult delete(int boNo) {
		ServiceResult result = null;
		
		mapper.deleteTag(boNo); // 태그를 먼저 삭제
		
		int status = mapper.delete(boNo); // 게시글을 삭제
		if(status > 0) {
			result = ServiceResult.OK;
		}else {
			result = ServiceResult.FAILED;
		}
		
		return result;
	}

}

[ITestMapper.java]

package kr.or.ddit.mapper;

import java.util.List;

import kr.or.ddit.vo.test.TagBoardVO;
import kr.or.ddit.vo.test.TagVO;

public interface ITestMapper {

	public int create(TagBoardVO tagboard);
	public void createTag(TagVO tagVO);
	public List<TagBoardVO> list(TagBoardVO tagboard);
	public void incrementHit(int boNo);
	public TagBoardVO read(int boNo);
	public int modify(TagBoardVO tagboard);
	public void deleteTag(int boNo);
	public int delete(int boNo);

}

[tagMapper_SQL.xml]

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="kr.or.ddit.mapper.ITestMapper">
	
	<resultMap type="tagboardVO" id="tagboardMap">
		<id property="boNo" column="bo_no" />
		<result property="boNo" column="bo_no" />
		<result property="boTitle" column="bo_title" />
		<result property="boContent" column="bo_content" />
		<result property="boWriter" column="bo_writer" />
		<result property="boDate" column="bo_date" />
		<result property="boHit" column="bo_hit" />
		<collection property="tagList" resultMap="tagMap" />
	</resultMap>
	
	<resultMap type="tagVO" id="tagMap">
		<result property="boNo" column="bo_no" />
		<result property="tagName" column="tag" />
	</resultMap>
	
	<sql id="tagSearch">
		<if test="searchType != null and searchType == 'title'">
			and (bo_title like '%' || #{searchWord} || '%')
		</if>
		<if test="searchType != null and searchType == 'writer'">
			and (bo_writer like '%' || #{searchWord} || '%')
		</if>
		<if test="searchType != null and searchType == 'both'">
			and (bo_title like '%' || #{searchWord} || '%')
			and (bo_writer like '%' || #{searchWord} || '%')
		</if>
	</sql>
	
	<insert id="create" parameterType="tagboardVO" useGeneratedKeys="true">
		<selectKey keyProperty="boNo" resultType="int" order="BEFORE">
			select seq_tagboard.nextval from dual
		</selectKey>
		insert into tagboard (
			bo_no, bo_title, bo_content, bo_writer, bo_date, bo_hit
		) values (
			#{boNo}, #{boTitle}, #{boContent}, #{boWriter}, sysdate, 0
		)
	</insert>
	
	<insert id="createTag" parameterType="tagVO">
		insert into tag (
			bo_no, tag
		) values (
			#{boNo}, #{tagName}
		)
	</insert>
	
	<select id="list" resultType="tagboardVO">
		select 
			bo_no, bo_title, bo_content, bo_writer, bo_date, bo_hit
		from tagboard 
		where 1=1
		<include refid="tagSearch" />
		order by bo_no desc 
	</select>
	
	<select id="read" parameterType="int" resultMap="tagboardMap">
		select 
			tb.bo_no, bo_title, bo_content, bo_writer, bo_date, bo_hit, 
			tag
		from tagboard tb left outer join tag ta on(tb.bo_no = ta.bo_no) 
		where tb.bo_no = #{boNo}
	</select>
	
	<update id="modify" parameterType="tagboardVO">
		update tagboard 
		set 
			bo_title = #{boTitle},
			bo_content = #{boContent},
			bo_date = sysdate 
		where bo_no = #{boNo}
	</update>
	
	<delete id="deleteTag" parameterType="int">
		delete from tag 
		where bo_no = #{boNo}
	</delete>
	
	<delete id="delete" parameterType="int">
		delete from tagboard 
		where bo_no = #{boNo}
	</delete>
	
	<update id="incrementHit" parameterType="int">
		update tagboard 
		set 
			bo_hit = bo_hit + 1 
		where bo_no = #{boNo}
	</update>
	
</mapper>

[list.jsp]

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!doctype html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="">
    <meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap contributors">
    <meta name="generator" content="Hugo 0.108.0">
    <title>DDIT BOARD LIST</title>
    <link rel="canonical" href="https://getbootstrap.com/docs/5.3/examples/album/">
    <link href="${pageContext.request.contextPath }/resources/assets/dist/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
    <style>
        .bd-placeholder-img {
            font-size: 1.125rem;
            text-anchor: middle;
            -webkit-user-select: none;
            -moz-user-select: none;
            user-select: none;
        }

        @media (min-width : 768px) {
            .bd-placeholder-img-lg {
                font-size: 3.5rem;
            }
        }

        .b-example-divider {
            height: 3rem;
            background-color: rgba(0, 0, 0, .1);
            border: solid rgba(0, 0, 0, .15);
            border-width: 1px 0;
            box-shadow: inset 0 .5em 1.5em rgba(0, 0, 0, .1), inset 0 .125em .5em rgba(0, 0, 0, .15);
        }

        .b-example-vr {
            flex-shrink: 0;
            width: 1.5rem;
            height: 100vh;
        }

        .bi {
            vertical-align: -.125em;
            fill: currentColor;
        }

        .nav-scroller {
            position: relative;
            z-index: 2;
            height: 2.75rem;
            overflow-y: hidden;
        }

        .nav-scroller .nav {
            display: flex;
            flex-wrap: nowrap;
            padding-bottom: 1rem;
            margin-top: -1px;
            overflow-x: auto;
            text-align: center;
            white-space: nowrap;
            -webkit-overflow-scrolling: touch;
        }
    </style>
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.0/jquery.min.js"></script>
</head>

<body>

	<c:if test="${not empty message }">
		<script type="text/javascript">
			alert("${message}");
			<c:remove var="message" scope="request"/>
			<c:remove var="message" scope="session"/>
		</script>
	</c:if>

    <header>
        <div class="collapse bg-dark" id="navbarHeader">
        </div>
        <div class="navbar navbar-dark bg-dark shadow-sm">
            <div class="container"></div>
        </div>
    </header>
    <main>
        <section class="py-1 text-center container">
            <div class="row py-lg-4">
                <div class="col-lg-6 col-md-8 mx-auto">
                    <h1 class="fw-light">DDIT 목록</h1>
                </div>
            </div>
        </section>
        <section class="py-1 container">
            <div class="row">
                <div class="col-md-12">
                    <form class="row g-3 mb-3">
                        <div class="row">
                            <div class="col-md-6"></div>
                            <div class="col-md-6" align="right">
                                <div class="row">
                                	<form method="post" id="searchForm" name="searchForm">
	                                    <div class="col-md-4">
	                                        <select class="form-select" id="searchType" name="searchType">
	                                            <option value="title" <c:if test="${tagboard.searchType eq 'title' }">selected</c:if>>제목</option>
	                                            <option value="writer" <c:if test="${tagboard.searchType eq 'writer' }">selected</c:if>>작성자</option>
	                                            <option value="both" <c:if test="${tagboard.searchType eq 'both' }">selected</c:if>>제목+작성자</option>
	                                        </select>
	                                    </div>
	                                    <div class="col-md-5">
	                                        <label for="inputPassword2" class="visually-hidden">키워드</label>
	                                        <input type="text" class="form-control" id="searchWord" name="searchWord" placeholder="검색 키워드" value="${tagboard.searchWord }">
	                                    </div>
	                                    <div class="col-md-3">
	                                        <button type="submit" class="btn btn-dark">검색하기</button>
	                                    </div>
                                	</form>
                                </div>
                            </div>
                        </div>
                    </form>
                    <table class="table">
                        <thead class="table-dark">
                            <tr>
                                <th scope="col" width="8%">번호</th>
                                <th scope="col">제목</th>
                                <th scope="col" width="14%">작성자</th>
                                <th scope="col" width="16%">작성일</th>
                                <th scope="col" width="8%">조회수</th>
                            </tr>
                        </thead>
                        <tbody>
                        	<c:choose>
                        		<c:when test="${empty tagboardList }">
		                            <tr>
		                                <td colspan="5">조회하신 게시글이 존재하지 않습니다.</td>
		                            </tr>
                        		</c:when>
                        		<c:otherwise>
                        			<c:forEach items="${tagboardList }" var="tagboard">
			                            <tr>
			                                <td>${tagboard.boNo }</td>
			                                <td>
			                                <a href="/board/tag/detail.do?boNo=${tagboard.boNo }">
			                                	${tagboard.boTitle }
			                                </a>
			                                </td>
			                                <td>${tagboard.boWriter }</td>
			                                <td>${tagboard.boDate }</td>
			                                <td>${tagboard.boHit }</td>
			                            </tr>
                        			</c:forEach>
                        		</c:otherwise>
                        	</c:choose>
                        </tbody>
                    </table>
                    <button type="button" class="btn btn-primary" id="registerBtn">등록</button>
                </div>
            </div>
        </section>
    </main>
    <script src="${pageContext.request.contextPath }/resources/assets/dist/js/bootstrap.bundle.min.js"></script>
</body>
<script type="text/javascript">
	$(function(){
		var registerBtn = $("#registerBtn");
		
		registerBtn.on("click", function(){
			location.href = "/board/tag/form.do";
		});
	});
</script>
</html>

[form.jsp]

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!doctype html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="">
    <meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap contributors">
    <meta name="generator" content="Hugo 0.108.0">
    <title>DDIT BOARD LIST</title>
    <link rel="canonical" href="https://getbootstrap.com/docs/5.3/examples/album/">
    <link href="${pageContext.request.contextPath }/resources/assets/dist/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
    <style>
        .bd-placeholder-img {
            font-size: 1.125rem;
            text-anchor: middle;
            -webkit-user-select: none;
            -moz-user-select: none;
            user-select: none;
        }

        @media (min-width : 768px) {
            .bd-placeholder-img-lg {
                font-size: 3.5rem;
            }
        }

        .b-example-divider {
            height: 3rem;
            background-color: rgba(0, 0, 0, .1);
            border: solid rgba(0, 0, 0, .15);
            border-width: 1px 0;
            box-shadow: inset 0 .5em 1.5em rgba(0, 0, 0, .1), inset 0 .125em .5em rgba(0, 0, 0, .15);
        }

        .b-example-vr {
            flex-shrink: 0;
            width: 1.5rem;
            height: 100vh;
        }

        .bi {
            vertical-align: -.125em;
            fill: currentColor;
        }

        .nav-scroller {
            position: relative;
            z-index: 2;
            height: 2.75rem;
            overflow-y: hidden;
        }

        .nav-scroller .nav {
            display: flex;
            flex-wrap: nowrap;
            padding-bottom: 1rem;
            margin-top: -1px;
            overflow-x: auto;
            text-align: center;
            white-space: nowrap;
            -webkit-overflow-scrolling: touch;
        }
    </style>
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.0/jquery.min.js"></script>
</head>

<body>

	<c:if test="${not empty message }">
		<script type="text/javascript">
			alert("${message}");
			<c:remove var="message" scope="request"/>
			<c:remove var="message" scope="session"/>
		</script>
	</c:if>
	
	<c:set value="등록" var="name" />
	<c:if test="${status eq 'u' }">
		<c:set value="수정" var="name" />
	</c:if>

    <header>
        <div class="collapse bg-dark" id="navbarHeader">
        </div>
        <div class="navbar navbar-dark bg-dark shadow-sm">
            <div class="container"></div>
        </div>
    </header>
    <main>
        <section class="py-1 text-center container">
            <div class="row py-lg-4">
                <div class="col-lg-6 col-md-8 mx-auto">
                    <h1 class="fw-light">DDIT ${name }</h1>
                </div>
            </div>
        </section>
        <section class="py-1 text-center container">
            <form class="album py-1 bg-light" action="/board/tag/form.do" method="post" id="dditboard" name="dditboard">
            
            	<c:if test="${status eq 'u' }">
               		<input type="hidden" name="boNo" value="${tagboard.boNo }" />
               	</c:if>
            
                <div class="">
                    <div class="container">
                        <div class="card-body">
                            <div class="input-group input-group-lg">
                                <span class="input-group-text" id="inputGroup-sizing-lg">제목</span>
                                <input type="text" class="form-control" id="boTitle" name="boTitle" value="${tagboard.boTitle }" />
                            </div>
                            <div class="input-group input-group-lg">
                                <span class="input-group-text" id="inputGroup-sizing-lg">내용</span>
                                <textarea class="form-control" aria-label="With textarea" rows="12" id="boContent" name="boContent" style="white-space: pre-wrap;">${tagboard.boContent }</textarea>
                            </div>
                            <div class="input-group input-group-lg">
                                <span class="input-group-text" id="inputGroup-sizing-lg">태그</span>
                                <input type="text" class="form-control" id="tag" name="tag" value="" />
                            </div>
                        </div>
                        <div class="card-footer" align="right">
                            <button type="button" class="btn btn-primary" id="registerBtn">${name }</button>
                            <c:if test="${status ne 'u' }">
                            	<button type="button" class="btn btn-info" id="listBtn">목록</button>
                            </c:if>
                            <c:if test="${status eq 'u' }">
                            	<button type="button" class="btn btn-info" id="cancelBtn">취소</button>
                            </c:if>
                        </div>
                    </div>
                </div>
            </form>
        </section>
    </main>
    <script src="${pageContext.request.contextPath }/resources/assets/dist/js/bootstrap.bundle.min.js"></script>
</body>
<script type="text/javascript">
	$(function(){
		var dditboard = $("#dditboard"); // form
		var registerBtn = $("#registerBtn");
		var listBtn = $("#listBtn");
		var cancelBtn = $("#cancelBtn");
		
		registerBtn.on("click", function(){
			var boTitle = $("#boTitle").val();
			var boContent = $("#boContent").val();
			var tag = $("#tag").val();
			
			if(!boTitle){
				alert("제목을 입력해 주세요!");
				$("#boTitle").focus();
				return false;
			}
			
			if(!boContent){
				alert("내용을 입력해 주세요!");
				$("#boContent").focus();
				return false;
			}
			
			if(!tag){
				alert("태그을 입력해 주세요!");
				$("#tag").focus();
				return false;
			}
			
			if($(this).text() == "수정") {
				dditboard.attr("action", "/board/tag/modify.do");
			}
			
			dditboard.submit();
		});
		
		listBtn.on("click", function(){
			location.href = "/board/tag/list.do";
		});
		
		cancelBtn.on("click", function(){
			location.href = "/board/tag/detail.do?boNo=${tagboard.boNo }";
		});
	});
</script>
</html>

[detail.jsp]

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!doctype html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="">
    <meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap contributors">
    <meta name="generator" content="Hugo 0.108.0">
    <title>DDIT BOARD LIST</title>
    <link rel="canonical" href="https://getbootstrap.com/docs/5.3/examples/album/">
    <link href="${pageContext.request.contextPath }/resources/assets/dist/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
    <style>
        .bd-placeholder-img {
            font-size: 1.125rem;
            text-anchor: middle;
            -webkit-user-select: none;
            -moz-user-select: none;
            user-select: none;
        }

        @media (min-width : 768px) {
            .bd-placeholder-img-lg {
                font-size: 3.5rem;
            }
        }

        .b-example-divider {
            height: 3rem;
            background-color: rgba(0, 0, 0, .1);
            border: solid rgba(0, 0, 0, .15);
            border-width: 1px 0;
            box-shadow: inset 0 .5em 1.5em rgba(0, 0, 0, .1), inset 0 .125em .5em rgba(0, 0, 0, .15);
        }

        .b-example-vr {
            flex-shrink: 0;
            width: 1.5rem;
            height: 100vh;
        }

        .bi {
            vertical-align: -.125em;
            fill: currentColor;
        }

        .nav-scroller {
            position: relative;
            z-index: 2;
            height: 2.75rem;
            overflow-y: hidden;
        }

        .nav-scroller .nav {
            display: flex;
            flex-wrap: nowrap;
            padding-bottom: 1rem;
            margin-top: -1px;
            overflow-x: auto;
            text-align: center;
            white-space: nowrap;
            -webkit-overflow-scrolling: touch;
        }
    </style>
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.0/jquery.min.js"></script>
</head>

<body>

	<c:if test="${not empty message }">
		<script type="text/javascript">
			alert("${message}");
			<c:remove var="message" scope="request"/>
			<c:remove var="message" scope="session"/>
		</script>
	</c:if>

    <header>
        <div class="collapse bg-dark" id="navbarHeader">
        </div>
        <div class="navbar navbar-dark bg-dark shadow-sm">
            <div class="container"></div>
        </div>
    </header>
    <main>
        <section class="py-1 text-center container">
            <div class="row py-lg-4">
                <div class="col-lg-6 col-md-8 mx-auto">
                    <h1 class="fw-light">DDIT 상세보기</h1>
                </div>
            </div>
        </section>
        <section class="py-1 container">
            <div class="row">
                <div class="col-md-12">
                    <div class="card">
                        <div class="card-header">${tagboard.boTitle }</div>
                        <div class="card-body">${tagboard.boWriter } ${tagboard.boDate } ${tagboard.boHit }</div>
                        <div class="card-body">
                        	<p style="white-space: pre-wrap;">${tagboard.boContent }</p>
                        </div>
                        <div class="card-body">
                        	<c:forEach items="${tagboard.tagList }" var="tag">
                        		<span class="badge bg-success">${tag.tagName }</span>
                        	</c:forEach>
                        <%-- ${tagboard.tagList[0].tagName } --%>
                        </div>
                        <form action="/board/tag/delete.do" id="delForm" name="delForm" method="post">
							<input type="hidden" name="boNo" value="${tagboard.boNo }" />
						</form>
                        <div class="card-footer">
                            <button type="button" class="btn btn-warning" id="modifyBtn">수정</button>
                            <button type="button" class="btn btn-danger" id="delBtn">삭제</button>
                            <button type="button" class="btn btn-info" id="listBtn">목록</button>
                        </div>
                    </div>
                </div>
            </div>
        </section>
    </main>
    <script src="${pageContext.request.contextPath }/resources/assets/dist/js/bootstrap.bundle.min.js"></script>
</body>
<script type="text/javascript">
	$(function(){
		var delForm = $("#delForm");
		var modifyBtn = $("#modifyBtn");
		var delBtn = $("#delBtn");
		var listBtn = $("#listBtn");
		
		modifyBtn.on("click", function(){
			delForm.attr("action", "/board/tag/modify.do");
			delForm.attr("method", "get");
			delForm.submit();
		});
		
		delBtn.on("click", function(){
			if(confirm("정말로 삭제하시겠습니까?")) {
				delForm.submit();
			}
		});
		
		listBtn.on("click", function(){
			location.href = "/board/tag/list.do";
		});
	});
</script>
</html>

- http://localhost/board/tag/list.do

- http://localhost/board/tag/form.do

- http://localhost/board/tag/detail.do?boNo=20


- http://localhost/board/tag/detail.do?boNo=24

- http://localhost/board/tag/modify.do?boNo=24

- http://localhost/board/tag/detail.do?boNo=24


- http://localhost/board/tag/detail.do?boNo=20

20번 글이 없어졌다.


제목 검색
작성자 검색
제목+작성자 검색


* 데이터 정합성도 잘 유지하고 있다...

'대덕인재개발원 > 대덕인재개발원_웹기반 애플리케이션' 카테고리의 다른 글

231204_SPRING 2 (9-2)  (0) 2023.12.04
231204_SPRING 2 (9-1)  (0) 2023.12.04
231201_SPRING 2 (8-2)  (0) 2023.12.01
231201_SPRING 2 (8-1)  (0) 2023.12.01
231130_SPRING 2 (7-3)  (0) 2023.11.30