답글 게시판이란 아래 그림과 같이 댓글이 달리는 것을 의미한다.

기본 이론 정리

[답변형게시판]
num : auto
writer
pass
subject
content
photo
readcount
(답변형 댓글 3가지 더 필요)
①regroup : 새글+예전글
②restep : 출력
③relevel :들여쓰기
writeday

regroup은 a글에 해당하는 답글들을 묶어줄 groupdyd column이다.
restep은 최종적으로 출력되는 순서를 나타낸다.
relevel은 댓글에 대해 들여쓰기를 표현한다.

restep과 relevel에 대한 설명이다.(네이버 댓글과는 순번이 약간 다르다)

  • num 1 원글 a면 regroup 1 restep 0 relevel 0
  • num 2 a의 답글1 regroup 1 restep 1 relevel 1
  • num 3 a의 답글2 regroup 1 restep 1 relevel 1 -> num 2의 restep은 2로 변경됨
  • num 4 num2(a의 답글1)의 답글1 regroup 1 restep 3 relevel 2 -> num2를 기준으로 restep 2+1 relevel은 답글의 답글이니까 1칸 들여쓰기해서 2가 되어야함
  • num 5 a의 답글3 regroup 1 restep 1 relvel 1 -> num1을 기준으로 num5의 regroup이 +1되고 num 234의 regroup +1씩 해서 번호 밀려남
  • num 6 num2(a의 답글1)의 답글2 regroup 1 restep 4 relevel 1
    -> num2를 기준 현재 num 2의 regroup은 3이니까 num 6의 regroup은 +1 해서 4
    -> num2를 기준으로 num 2의 relevel은 1이니까 num 6의 relevel은 +1 해서 2

boardMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 
<mapper namespace="board">
	<select id="getTotalCountOfReboard" resultType="int">
		select count(*) from reboard
	</select>
	
	<!-- num의 max값, null일 0 -->
	<select id="maxNumOfReboard" resultType="int">
		select ifnull(max(num),0) from reboard
	</select>
	
	<!-- 같은 그룹중에서 step보다 큰 데이터는 모두 +1 -->
	<update id="updateStepOfReboard" parameterType="HashMap">
		update reboard set restep=restep+1 where regroup=#{regroup} and restep>#{restep}
	</update>
	
	<!-- insert: 새글,답글 모두 해당 -->
	<insert id="insertOfReboard" parameterType="bdto">
		insert into reboard (writer,pass,subject,content,photo,regroup,restep,relevel,writeday) values (#{writer},#{pass},#{subject},#{content},#{photo},#{regroup},#{restep},#{relevel},now())
	</insert>
	
	<!-- 페이징 처리 전체 리스트 -->
	<select id="selectPagingOfReboard" resultType="bdto" parameterType="HashMap">
		select * from reboard order by regroup desc, restep asc limit #{start},#{perpage}
	</select>
	
	<!-- 하나의 dto값 얻기 -->
	<select id="getDataOfReboard" parameterType="int" resultType="bdto">
		select * from reboard where num=#{num}
	</select>
	
	<!-- readCount 증가 --> <!-- mapper에서는 무조건 sql 기준으로 값을 주고 받는다. -->
	<update id="plusReadCountOfReboard" parameterType="int">
		update reboard set readcount=readcount+1 where num=#{num}
	</update>
	
	<select id="checkPassEqualOfReboard" parameterType="HashMap" resultType="int">
		select count(*) from reboard where num=#{num} and pass=#{pass}
	</select>
	
	<delete id="deleteOfReboard" parameterType="int">
		delete from reboard where num=#{num}
	</delete>
	
	<update id="updateOfReboard" parameterType="bdto">
		update reboard set subject=#{subject},content=#{content}
		<if test="photo!='no'">
			,photo=#{photo}
		</if>
		 where num=#{num}
	</update>
	
</mapper>

BoardDto.java

package spring.mvc.reboard;

import java.sql.Timestamp;

public class BoardDto {

	private int num;
	private String writer;
	private String pass; 
	private String subject;
	private String content;
	private String photo;
	private int readCount;
	private int regroup;
	private int restep;
	private int relevel;
	private Timestamp writeday;
	private int acount;
	
	public int getAcount() {
		return acount;
	}
	public void setAcount(int acount) {
		this.acount = acount;
	}
	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 getPass() {
		return pass;
	}
	public void setPass(String pass) {
		this.pass = pass;
	}
	public String getSubject() {
		return subject;
	}
	public void setSubject(String subject) {
		this.subject = subject;
	}
	public String getContent() {
		return content;
	}
	public void setContent(String content) {
		this.content = content;
	}
	public String getPhoto() {
		return photo;
	}
	public void setPhoto(String photo) {
		this.photo = photo;
	}
	public int getRegroup() {
		return regroup;
	}
	public void setRegroup(int regroup) {
		this.regroup = regroup;
	}
	public int getRestep() {
		return restep;
	}
	public void setRestep(int restep) {
		this.restep = restep;
	}
	public int getRelevel() {
		return relevel;
	}
	public void setRelevel(int relevel) {
		this.relevel = relevel;
	}
	public Timestamp getWriteday() {
		return writeday;
	}
	public void setWriteday(Timestamp writeday) {
		this.writeday = writeday;
	}
	public int getReadCount() {
		return readCount;
	}
	public void setReadCount(int readCount) {
		this.readCount = readCount;
	}
}

BoardDaoInter.java

public interface BoardDaoInter {

	public int getTotalCount();
	public int getMaxNum();
	public void updateRestep(int regroup,int restep);
	public void insertReboard(BoardDto bdto);
	public List<BoardDto> getPagingList(int start,int perpage);
	public BoardDto getData(int num);
	public void updateReadCount(int num);
	public int getCheckPass(int num,int pass);
	public void deleteReboard(int num);
	public void updateReboard(BoardDto bdto);

BoardDao.java

package spring.mvc.reboard;

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

import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

@Repository // bean에 등록
public class BoardDao implements BoardDaoInter {
	
	@Autowired
	private SqlSession session;
	
	@Override
	public int getTotalCount() {
		// TODO Auto-generated method stub
		return session.selectOne("getTotalCountOfReboard");
	}
	
	@Override
	public int getMaxNum() {
		// TODO Auto-generated method stub
		return session.selectOne("maxNumOfReboard");
	}
	
	@Override
	public void updateRestep(int regroup, int restep) {
		// TODO Auto-generated method stub
		HashMap<String, Integer> map=new HashMap<String, Integer>();
		// int를 integer(ref class)로 써야 합니다.
		map.put("regroup", regroup);
		map.put("restep", restep);
		session.update("updateStepOfReboard", map);
	}
	
	@Override
	public void insertReboard(BoardDto bdto) {
		// TODO Auto-generated method stub
		int num=bdto.getNum();
		int regroup=bdto.getRegroup();
		int restep=bdto.getRestep();
		int relevel=bdto.getRelevel();
			
		if(num==0) { // 새글
			regroup=getMaxNum()+1;
			restep=0;
			relevel=0;
		} else { // 답글
			// 같은 그룹중 전달받은 restep보다 큰 글들은 모두 +1 해준다.
			this.updateRestep(regroup, restep);
			
			// 전달받은 step과 level 모두 +1
			restep++;
			relevel++;
		}
		
		// 바뀐 값들을 다시 dto에 담아줘야 합니다.
		bdto.setRegroup(regroup);
		bdto.setRestep(restep);
		bdto.setRelevel(relevel);
		
		// insert
		session.insert("insertOfReboard", bdto);
		
	}
	
	@Override
	public List<BoardDto> getPagingList(int start, int perpage) {
		
		HashMap<String, Integer>map=new HashMap<String, Integer>();
		map.put("start", start);
		map.put("perpage", perpage);
		
		return session.selectList("selectPagingOfReboard", map);
	}
	
	
	@Override
	public BoardDto getData(int num) {
		// TODO Auto-generated method stub
		return session.selectOne("getDataOfReboard", num);
	}
	
	@Override
	public void updateReadCount(int num) {
		
		session.update("plusReadCountOfReboard", num);
	}
	
	@Override
	public int getCheckPass(int num, int pass) {
		// TODO Auto-generated method stub
		HashMap<String, Integer>map=new HashMap<String, Integer>();
		map.put("num", num);
		map.put("pass", pass);
		
		return session.selectOne("checkPassEqualOfReboard", map);
	}
	
	@Override
	public void deleteReboard(int num) {
		// TODO Auto-generated method stub
		session.delete("deleteOfReboard", num);
	}
	
	@Override
	public void updateReboard(BoardDto bdto) {
		// TODO Auto-generated method stub
		session.update("updateOfReboard", bdto);
	}
}

답글

Controller

BoardListController.java

  • 간만에 보는 paging처리
package board.data.controller;

@Controller
public class BoardListController {

	@Autowired
	BoardDao bdao;
	
	@Autowired
	AnswerDao adao;
	
	@GetMapping("/board/list")
	public ModelAndView list(@RequestParam(value = "currentPage",defaultValue = "1") int currentPage) {
		
		ModelAndView mview=new ModelAndView();
		
        
		// 페이징 처리에 필요한 변수선언
		int totalCount=bdao.getTotalCount(); //전체객수
		int totalPage; //총 페이지수
		int startPage; //각블럭에서 보여질 시작페이지
		int endPage; //각블럭에서 보여질 끝페이지
		int startNum; //db에서 가져올 글의 시작번호(mysql은 첫글이 0,오라클은 1)
		int perPage=10; //한페이지당 보여질 글의 갯수
		int perBlock=3; //한블럭당 보여질 페이지 개수
		int no; //각페이지당 출력할 시작번호   
		     
		//총페이지수 구하기
		//총글의 갯수/한페이지당 보여질 개수로 나눔(7/5=1)
		//나머지가 1이라도 있으면 무조건 1페이지 추가(1+1=2페이지가 필요)
		  	totalPage=totalCount/perPage+(totalCount%perPage==0?0:1);
		 
		//각블럭당 보여야할 시작페이지
		//perBlock=5일경우는 현재페이지 1~5 시작:1 끝:5
		//현재페이지 13  시작:11  끝:15
		  	startPage=(currentPage-1)/perBlock*perBlock+1;
		     
		  	endPage=startPage+perBlock-1;
		    
		 // 총페이지가 23일경우 마지막블럭은 25가아니라 23이다   
		      if(endPage>totalPage)
		        	endPage=totalPage;
		     
			//각페이지에서 보여질 시작번호
			//1페이지: 0,2페이지:5 3페이지:10....
			startNum=(currentPage-1)*perPage;
			
			//각페이지당 출력할 시작번호 구하기 no
			//총글개수가 23이면 1페이지 23,2페이지는 18,3페이지 13.....
			//출력시 1씩 감소하며 출력
			no=totalCount-(currentPage-1)*perPage;
		
			// 각 페이지에서 필요한 게시글 가져오기
			List<BoardDto> list=bdao.getPagingList(startNum, perPage);
			
			// list의 각글에 댓글 갯수 표시하기
			for(BoardDto d:list) {
				d.setAcount(adao.getAnswerList(d.getNum()).size());
			}
			
		mview.addObject("totalCount", totalCount);
		mview.addObject("list", list);
		mview.addObject("startPage", startPage);
		mview.addObject("endPage", endPage);
		mview.addObject("totalPage", totalPage);
		mview.addObject("no", no);
		mview.addObject("currentPage", currentPage);
		
		
		mview.setViewName("reboard/boardlist");
		
		return mview;
	}
}

BoardContentController.java

package board.data.controller;

@Controller
public class BoardContentController {

	@Autowired // 자동 주입
	BoardDaoInter inter;
	
	@Autowired // 댓글용 자동주입
	AnswerDaoInter ainter;
	
	@GetMapping("/board/content") // list에서 a태그 href에 있는 'content?' 라고 넘겨서 mapping 주소도 content이다.
	public ModelAndView content(@RequestParam int num, @RequestParam String currentPage) { // boardlist 에서 보내준 2개의 값 다 받아줘야 한다.
		
		ModelAndView mview=new ModelAndView();
		
		// 조회수 증가
		inter.updateReadCount(num);
		
		// 넘어온 num에 대한 값들을 다시 dto에 넣어주기 
		BoardDto bdto=inter.getData(num);
		
		// num에 해당하는 댓글을 DB에서 가져와서 보낸다.
		List<AnswerDto> alist=ainter.getAnswerList(num);
		
		mview.addObject("bdto", bdto);
		mview.addObject("currentPage", currentPage);
		
		// 댓글이 있을때에만 넘겨야 하므로..	
		mview.addObject("acount", alist.size());
		mview.addObject("alist", alist);
		
		mview.setViewName("reboard/content");
		
		return mview;
	}	
}

BoardWriteController.java

package board.data.controller;

@Controller
public class BoardWriteController {
	
	@Autowired
	BoardDao bdao;

	
	@GetMapping("/board/writeform")
	public ModelAndView form(@RequestParam Map<String, String>map) {
		ModelAndView mview=new ModelAndView();
		
		// 아래 5개는 답글일 경우에만 넘어온다. 새글일 경우에는 안넘어온다.
		String currentPage=map.get("currentPage");
		String num=map.get("num");
		String regroup=map.get("regroup");
		String restep=map.get("restep");
		String relevel=map.get("relevel");
		
		System.out.println(currentPage+","+num);
		
		// 입력폼에 hidden으로 넣어줘야함.. 답글일때 대비
		mview.addObject("currentPage", currentPage==null?"1":currentPage); // 얘는 default 값을 1로 설정해줬음.
		mview.addObject("num", num==null?"0":num);
		mview.addObject("regroup", regroup==null?"0":regroup);
		mview.addObject("restep", restep==null?"0":restep);
		mview.addObject("relevel", relevel==null?"0":relevel);
		
		// 0으로 넣어야 dao에서 새글로 인식
		// 폼이 답글,새글 공용이므로..	
		
		mview.setViewName("reboard/writeform");
		return mview;
	}
	
	@PostMapping("/board/insert")
	public String insert(@ModelAttribute BoardDto bdto,@RequestParam ArrayList<MultipartFile>uimage,HttpSession session,
			@RequestParam String currentPage) {
		
		// 실제경로 구하기
		String path=session.getServletContext().getRealPath("/WEB-INF/photo");
		SimpleDateFormat sdf=new SimpleDateFormat("yyyyMMddHHmmss");
		System.out.println(currentPage);
		String photo="";
		
		if(uimage.get(0).getOriginalFilename().equals("")) {
			photo="no";
		} else {
			for(MultipartFile f:uimage) {
				String fName=sdf.format(new Date())+"_"+f.getOriginalFilename();
				photo+=fName+",";
				
				try {
					f.transferTo(new File(path+"/"+fName));
				} catch (IllegalStateException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			} 
			// photo에서 마지막 컴마 제거하기 
			photo=photo.substring(0, photo.length()-1);
		}
		// dto의 Photo에 넣기
		bdto.setPhoto(photo);
		
		// insert
		bdao.insertReboard(bdto);		
		
		// insert되는 순간 생성된 content의 num값이 가장 큰 값이다. insert 된 파일을 바로 열기 위해 maxNum을 활용한다.
		int maxNum=bdao.getMaxNum();
		
		return "redirect:content?num="+maxNum+"&currentPage="+currentPage;
	}	
}

BoardUpdateController.java

package board.data.controller;

@Controller
public class BoardUpdateController {

	@Autowired
	BoardDaoInter inter;
	
	
	@GetMapping("/board/updatepassform")
	public ModelAndView upassform(@RequestParam int num,@RequestParam int currentPage) {
		ModelAndView mview=new ModelAndView();
		
		mview.addObject("num", num);
		mview.addObject("currentPage", currentPage);
		
		mview.setViewName("reboard/updatepassform");
		
		return mview;
	}
	
	@PostMapping("/board/updatepass")
	public ModelAndView updatepass(@RequestParam int num,@RequestParam int pass,@RequestParam int currentPage) {
				 
		ModelAndView mview=new ModelAndView();
		System.out.println(currentPage);
		
		// 비밀번호가 맞으면 수정폼으로, 틀리면 passfail로 이동
		
		int check=inter.getCheckPass(num, pass);
		
		if(check==0) {
			mview.setViewName("reboard/passfail");
		} else {
			BoardDto bdto=inter.getData(num);
			
			mview.addObject("bdto", bdto);
			mview.addObject("currentPage", currentPage);
			
			mview.setViewName("reboard/updateform");
		}
		
		return mview;
	}
	
	@PostMapping("/board/update")
	public String update(@ModelAttribute BoardDto bdto,
			@RequestParam String currentPage,
			@RequestParam ArrayList<MultipartFile>uimage,
			HttpSession session) {
		String path=session.getServletContext().getRealPath("WEB-INF/photo");
		System.out.println(path);
		System.out.println(currentPage);
		
		SimpleDateFormat sdf=new SimpleDateFormat("yyyyMMddHHmmss");
		
		String photo="";
		
		if(uimage.get(0).getOriginalFilename().equals("")) {
			photo="no";
		} else {
			// 수정전에 이전사진 지우기
			String pre_photo=inter.getData(bdto.getNum()).getPhoto();
			
			String []pre_fName=pre_photo.split(",");
			for(String f:pre_fName) {
				File file=new File(path+"/"+f);
				file.delete();
			}
			
			for(MultipartFile f:uimage) {
				String fName=sdf.format(new Date())+"_"+f.getOriginalFilename();
				photo+=fName+",";
				
				try {
					f.transferTo(new File(path+"/"+fName));
				} catch (IllegalStateException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			} 
			// photo에서 마지막 컴마 제거하기 
			photo=photo.substring(0, photo.length()-1);
		}
		// dto의 Photo에 넣기
		bdto.setPhoto(photo);
		
		// update
		inter.updateReboard(bdto);
		
		// 내용 수정 후 원래 페이지로 이동
		return "redirect:content?num="+bdto.getNum()+"&currentPage="+currentPage;
	}
}

BoardDeleteController.java

package board.data.controller;

@Controller
public class BoardDeleteController {

	@Autowired
	BoardDaoInter inter;
	
	@GetMapping("/board/deletepassform")
	public ModelAndView dpassform(@RequestParam String num,@RequestParam String currentPage) {
		
		ModelAndView mview=new ModelAndView();
		
		mview.addObject("num", num);
		mview.addObject("currentPage", currentPage);
		
		mview.setViewName("reboard/delpassform");
		
		return mview;
	}
	
	@PostMapping("/board/deletepass")
	public ModelAndView deletepass(@RequestParam int num,@RequestParam int pass,
			@RequestParam int currentPage,HttpSession session) {
		
		ModelAndView mview=new ModelAndView();
		
		// 비밀번호가 맞으면 삭제하고, 틀리면 passfail로 이동
		
		int check=inter.getCheckPass(num, pass);
		
		if(check==0) {
			mview.setViewName("reboard/passfail"); 
		} else {
			
			String photo=inter.getData(num).getPhoto();
			if(!photo.equals("no")) {
				String [] fName=photo.split(",");
				String path=session.getServletContext().getRealPath("/WEB-INF/photo");
				
				for(String f:fName) {
					File file=new File(path+"/"+f);
					file.delete();
				}
			}
			inter.deleteReboard(num);
			mview.setViewName("redirect:list");
		}
		return mview;
	}
}


댓글

answerMapper.xml

<mapper namespace="answer">
	<insert id="insertOfReanswer" parameterType="adto">
		insert into reanswer (num,nickname,pass,contents,writeday) values(#{num},#{nickname},#{pass},#{contents},now()) 
	</insert>
		
	<select id="selectNumOfReanswer" parameterType="int" resultType="adto">
		select * from reanswer where num=#{num} order by idx asc 
	</select>
	
	<!-- 비밀번호 check -->
	<select id="checkEqulPassOfReanswer" parameterType="HashMap" resultType="int">
		select count(*) from reanswer where idx=#{idx} and pass=#{pass}
	</select>
	
	<!-- 삭제 -->
	<delete id="deleteOfReanswer" parameterType="int">
		delete from reanswer where idx=#{idx}
	</delete>
</mapper>

AnswerDto.java

package answer.data;

import java.sql.Timestamp;

public class AnswerDto {

	private int idx;
	private int num;
	private String nickname;
	private String pass;
	private String contents;
	private Timestamp writeday;
	
	public int getIdx() {
		return idx;
	}
	public void setIdx(int idx) {
		this.idx = idx;
	}
	public int getNum() {
		return num;
	}
	public void setNum(int num) {
		this.num = num;
	}
	public String getNickname() {
		return nickname;
	}
	public void setNickname(String nickname) {
		this.nickname = nickname;
	}
	public String getPass() {
		return pass;
	}
	public void setPass(String pass) {
		this.pass = pass;
	}
	public String getContents() {
		return contents;
	}
	public void setContents(String contents) {
		this.contents = contents;
	}
	public Timestamp getWriteday() {
		return writeday;
	}
	public void setWriteday(Timestamp writeday) {
		this.writeday = writeday;
	}
}

AnswerDaoInter.java

public interface AnswerDaoInter {

	public void insertAnswer(AnswerDto adto);
	public List<AnswerDto> getAnswerList(int num);
	public int checkPassAnswer(int idx,String pass);
	public void deleteAnswer(int idx);

AnswerDao.java

package answer.data;

@Repository 
public class AnswerDao implements AnswerDaoInter {

	@Autowired
	private SqlSession session;
	
	@Override
	public void insertAnswer(AnswerDto adto) {
		// TODO Auto-generated method stub
		session.insert("insertOfReanswer", adto);
	}
	
	@Override
	public List<AnswerDto> getAnswerList(int num) {
		// TODO Auto-generated method stub
		return session.selectList("selectNumOfReanswer", num);
	}
	
	@Override
	public int checkPassAnswer(int idx, String pass) {
		// TODO Auto-generated method stub
		HashMap<String, Object> map=new HashMap<String, Object>();
		map.put("idx", idx);
		map.put("pass", pass);
		
		return session.selectOne("checkEqulPassOfReanswer", map);
	}
	
	@Override
	public void deleteAnswer(int idx) {
		// TODO Auto-generated method stub
		session.delete("deleteOfReanswer", idx);
	}
}

AnswerController.java

package answer.data;

@Controller
public class AnswerController {

	@Autowired
	AnswerDaoInter ainter;
	
	@PostMapping("/board/ainsert")
	public String answerinsert(@ModelAttribute AnswerDto adto,@RequestParam String currentPage) {
		
		//DB에 추가
		ainter.insertAnswer(adto);
		
		return "redirect:content?num="+adto.getNum()+"&currentPage="+currentPage; 
	}
	
	@GetMapping("/board/adelete")
	@ResponseBody
	public HashMap<String, Integer> answerDelete(@RequestParam int idx,@RequestParam String pass){ // {"idx":1}
		
		int check=ainter.checkPassAnswer(idx, pass);
		
		if(check==1) {
			ainter.deleteAnswer(idx);
		} 
		HashMap<String, Integer>map=new HashMap<String, Integer>();
		map.put("check", check); // {"check":1}
		
		return map;
	}
}


출력jsp

boardlist.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link href="https://fonts.googleapis.com/css2?family=Bagel+Fat+One&family=Dongle:wght@300&family=East+Sea+Dokdo&family=Gamja+Flower&family=Gowun+Dodum&family=Nanum+Gothic+Coding&family=Nanum+Pen+Script&family=Orbit&display=swap" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css">
<script src="https://code.jquery.com/jquery-3.7.0.js"></script>
<title>Insert title here</title>
</head>
<body>
<div style="margin: 50px 50px;">
	<table class="table table-bordered" style="width: 800px;">
		<caption align="top">
			<b>스프링 답변형 게시판</b>
				<span style="float: right;">
					<button type="button" class="btn btn-outline-info" onclick="location.href='writeform?currentPage=${currentPage}'">글쓰기</button>
				</span>
		</caption>
		
		<tr>
			<th width="60">번호</th>
			<th width="300">제목</th>
			<th width="220">작성자</th>
			<th width="250">작성일</th>
			<th width="60">조회</th>
		</tr>
		
		<c:if test="${totalCount==0 }">
			<tr>
				<td colspan="5" align="center">
					<b>등록된 게시글이 없습니다.</b>
				</td>
			</tr>	
		</c:if>
		<c:if test="${totalCount>0 }">
			<c:forEach var="bdto" items="${list }" >
				<tr>
					<td align="center">${no }</td>
					<c:set var="no" value="${no-1 }"></c:set> <!-- 출력 후 감소시키는것. 증감연산자 사용이 불가하기 때문이다. -->
					<td> <!-- 제목 -->
						<!-- relevel만큼 앞에 공백이 와야한다. -->
						<c:forEach var="s" begin="1" end="${bdto.relevel }">
							&nbsp;&nbsp;
						</c:forEach>
						
						<!-- 답글인 경우에만 re.png이미지 출력 -->
						<c:if test="${bdto.relevel>0 }">
							<img alt="" src="../upload/re.png">
						</c:if>
						
						<!-- 제목.. 여기 누르면 내용 보기로 갈꺼다! -->
						<a href="content?num=${bdto.num }&currentPage=${currentPage}">${bdto.subject }</a>
						
						<!-- 댓글개수 표시하기 -->
						<c:if test="${bdto.acount>0 }">
							<a style="color: red;" href="content?num=${bdto.num }&currentPage=${currentPage}#answer">[${bdto.acount }]</a>
						</c:if>
						
						<!-- 사진이 있을경우 아이콘 표시 -->
						<c:if test="${bdto.photo!='no' }">
							<i class="bi bi-image"></i>
						</c:if>
					</td>
					<td align="center"> ${bdto.writer }</td>
					<td><fmt:formatDate value="${bdto.writeday }" pattern="yyyy-MM-dd"/></td>
					<td align="center">${bdto.readCount }</td>
				</tr>
			</c:forEach>
		</c:if>
	</table>	

<!-- 페이지번호 출력 -->

	<c:if test="${totalCount>0 }">
		<div style="width: 800px; text-align: center;">
			<ul class="pagination justify-content-center">
				<!-- 이전 -->
				<c:if test="${startPage>1 }">
					<li class="page-item">
						<a href="list?currentPage=${startPage-1 }">이전</a>
					</li>
				</c:if>
				
				<!-- 가운데 숫자들.. -->
				<c:forEach var="pp" begin="${startPage }" end="${endPage }">
					<c:if test="${currentPage==pp }">
						<li class="page-item active">
							<a href="list?currentPage=${pp }" class="page-link">${pp }</a>
						</li>
					</c:if>
					<c:if test="${currentPage!=pp }">
						<li class="page-item">
							<a href="list?currentPage=${pp }" class="page-link">${pp }</a>
						</li>
					</c:if>
				</c:forEach>
			
				<!-- 다음 -->
				<c:if test="${endPage<totalPage }">
					<li class="page-item">
						<a href="list?currentPage=${endPage+1 }">다음</a>
					</li>
				</c:if>
			</ul>
		</div>			
	</c:if>
</div>
</body>
</html>

content.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link href="https://fonts.googleapis.com/css2?family=Bagel+Fat+One&family=Dongle:wght@300&family=East+Sea+Dokdo&family=Gamja+Flower&family=Gowun+Dodum&family=Nanum+Gothic+Coding&family=Nanum+Pen+Script&family=Orbit&display=swap" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css">
<script src="https://code.jquery.com/jquery-3.7.0.js"></script>
<title>Insert title here</title>
</head>
<body>
<div style="margin: 100px 100px;">
	<table class="table table-bordered" style="width: 600px;">
		<caption align="top"><b>내용보기</b></caption>
		<tr>
			<td>
				<h2><b>${bdto.subject }</b></h2>
				<span style="float: right; margin-right: 20px;">
					조회: ${bdto.readCount } &nbsp;&nbsp;&nbsp;
					<fmt:formatDate value="${bdto.writeday }" pattern="yyyy-MM-dd HH:mm"/>
				</span>
				<br>
				<h5><b>작성자: ${bdto.writer }</b></h5>
			</td>
		</tr>
		
		<tr>
			<td>
				<pre>${bdto.content }</pre>
				<br><br>
				<!-- 이미지가 있을때만 출력 -->
				<c:if test="${bdto.photo!='no' }"> <!-- null이 아니다. DB 확인할 것!! -->
					<c:forTokens var="pho" items="${bdto.photo }" delims=","> <!-- 사진 여러개의 경우 끊어서 사진 넣기 -->
						<a href="../upload/${pho }"> <!-- 사진 클릭 시 원본사진 나오게 하기 -->
							<img alt="" src="../upload/${pho }" width="150" style="border: 1px solid gray; border-radius: 10px;">
						</a>
					</c:forTokens>
				</c:if>
			</td>
		</tr>
		
		<!-- 댓글 -->
		
		<tr>
			<td>
				<div id="answer">
					<b>댓글: ${acount }</b><br><br>
					<c:forEach var="a" items="${alist }">
						${a.nickname }: ${a.contents } 
						<span style="color: gray;font-size: 0.8em;">
							<fmt:formatDate value="${a.writeday }" pattern="yyyy-MM-dd HH:mm"/>
						</span>
						&nbsp;
						<i class="adel bi bi-eraser" style="color: red; cursor: pointer;" idx="${a.idx }"></i>
						<br>
					</c:forEach>
				</div>
				<form action="ainsert" method="post">
					<input type="hidden" name="num" value="${bdto.num }">
					<input type="hidden" name="currentPage" value="${currentPage }"> 
					<div class="d-inline-flex">
						<b>닉네임: </b>
						<input type="text" name="nickname" class="form-control" style="width: 120px;" required="required">
						&nbsp;&nbsp;<b>비밀번호: </b>
						<input type="password" name="pass" class="form-control" style="width: 120px;" required="required">
					</div>
					<br><br>
					<div class="d-inline-flex">
						<input type="text" name="contents" class="form-control" style="width: 500px;" placeholder="댓글내용을 입력하세요">
						<button type="submit" class="btn btn-outline-info">확인</button>
					</div>
				</form>
			</td>
		</tr>
		
		<tr>
			<td align="right">
				<button type="button" class="btn btn-info" onclick="location.href='writeform'" style="width: 100px;">글쓰기</button>
				<button type="button" class="btn btn-success" onclick="location.href='writeform?num=${bdto.num}&regroup=${bdto.regroup }&restep=${bdto.restep }&relevel=${bdto.relevel }&currentPage=${currentPage }'" style="width: 100px;">답글쓰기</button>
				<button type="button" class="btn btn-warning" onclick="location.href='updatepassform?num=${bdto.num}&currentPage=${currentPage }'" style="width: 100px;">수정</button>
				<button type="button" class="btn btn-danger" onclick="location.href='deletepassform?num=${bdto.num}&currentPage=${currentPage }'" style="width: 100px;">삭제</button>
				<button type="button" class="btn btn-primary" onclick="location.href='list?currentPage=${currentPage}'" style="width: 100px;">목록</button>
			</td>
		</tr>
	</table>
</div>
	
<script type="text/javascript">
	
	$("i.adel").click(function(){
		var idx=$(this).attr("idx");
		var pass=prompt("비밀번호를 입력하세요","비밀번호");
		if(pass==null){
			return;
		}
 		// alert(idx);
		// alert(pass);
  		$.ajax({
			type:"get",
			dataType:"json",
			url:"adelete",
			data:{"pass":pass,"idx":idx},
			success:function(res){
				
				if(res.check==0){
					alert("비밀번호가 맞지 않습니다.")
				} else {
					alert("댓글을 삭제합니다.");
					location.reload();
				}	
			}
		}); 
	});
</script>
</body>
</html>

delpassform.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link href="https://fonts.googleapis.com/css2?family=Bagel+Fat+One&family=Dongle:wght@300&family=East+Sea+Dokdo&family=Gamja+Flower&family=Gowun+Dodum&family=Nanum+Gothic+Coding&family=Nanum+Pen+Script&family=Orbit&display=swap" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css">
<script src="https://code.jquery.com/jquery-3.7.0.js"></script>
<title>Insert title here</title>
</head>
<body>
	<div style="margin: 200px 200px;">
		<form action="deletepass" method="post">
			<input type="hidden" name="num" value="${num }">
			<input type="hidden" name="currentPage" value="${currentPage }">
			
			<div class="alert alert-danger" style="width: 300px; font-size: 1.3em;">
				<b>비밀번호를 입력해 주세요</b>
			</div>
			<div class="d-inline-flex">
				<input type="password" name="pass" class="form-control" style="width: 120px;" required="required">
				<button type="submit" class="btn btn-outline-danger">삭제하기</button>
				<button type="button" class="btn btn-outline-success" onclick="history.back()">이전으로</button>
			</div> 
		</form>
	</div>
</body>
</html>

passfail.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link href="https://fonts.googleapis.com/css2?family=Bagel+Fat+One&family=Dongle:wght@300&family=East+Sea+Dokdo&family=Gamja+Flower&family=Gowun+Dodum&family=Nanum+Gothic+Coding&family=Nanum+Pen+Script&family=Orbit&display=swap" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css">
<script src="https://code.jquery.com/jquery-3.7.0.js"></script>
<title>Insert title here</title>
</head>
<body>
	<script type="text/javascript">
		alert("비밀번호가 맞지 않습니다.");
		history.back();	
	</script>
</body>
</html>

updateform.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link href="https://fonts.googleapis.com/css2?family=Bagel+Fat+One&family=Dongle:wght@300&family=East+Sea+Dokdo&family=Gamja+Flower&family=Gowun+Dodum&family=Nanum+Gothic+Coding&family=Nanum+Pen+Script&family=Orbit&display=swap" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css">
<script src="https://code.jquery.com/jquery-3.7.0.js"></script>
<title>Insert title here</title>
</head>
<body>
	<div style="margin: 50px 100px;">
		<form action="update" method="post" enctype="multipart/form-data">
			<!-- hidden 2개 넣어주기 -->
			<input type="hidden" name="num" value="${bdto.num }">
			<input type="hidden" name="currentPage" value="${currentPage }">

			<table class="table table-bordered" style="width: 500px;">
				<tr>
					<th>작성자</th>
					<td>
						<input type="text" name="writer" class="form-control" required="required" style="width: 100px;" value="${bdto.writer }">
					</td>
				</tr>
				<tr>
					<th>제목</th>
					<td>
						<input type="text" name="subject" class="form-control" required="required" style="width: 300px;" value="${bdto.subject }">
					</td>
				</tr>
				<tr>
					<th>사진</th>
					<td>
						<input type="file" name="uimage" class="form-control" style="width: 220px;" multiple="multiple">
					</td>
				</tr>
				<tr>
					<td colspan="2">
						<textarea style="width: 480px; height: 150px;" name="content" required="required" class="form-control">${bdto.content }</textarea>
					</td>
				</tr>
				<tr>
					<td colspan="2" align="center">
						<button type="submit" class="btn btn-info" style="width: 100px;">수정하기</button>
						<button type="button" class="btn btn-success" onclick="location.href='list'" style="width: 100px;">목록</button>
					</td>
				</tr>
			</table>
		</form>
	</div>
</body>
</html>

updatepassform.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link href="https://fonts.googleapis.com/css2?family=Bagel+Fat+One&family=Dongle:wght@300&family=East+Sea+Dokdo&family=Gamja+Flower&family=Gowun+Dodum&family=Nanum+Gothic+Coding&family=Nanum+Pen+Script&family=Orbit&display=swap" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css">
<script src="https://code.jquery.com/jquery-3.7.0.js"></script>
<title>Insert title here</title>
</head>
<body>
<h2>${currentPage }</h2>
	<div style="margin: 200px 200px;">
		<form action="updatepass" method="post">
			<input type="hidden" name="num" value="${num }">
			<input type="hidden" name="currentPage" value="${currentPage }">
			
			<div class="alert alert-warning" style="width: 300px; font-size: 1.3em;">
				<b>비밀번호를 입력해 주세요</b>
			</div>
			<div class="d-inline-flex">
				<input type="password" name="pass" class="form-control" style="width: 120px;" required="required">
				<button type="submit" class="btn btn-outline-warning">수정하기</button>
				<button type="button" class="btn btn-outline-success" onclick="history.back()">이전으로</button>
			</div> 
		</form>
	</div>
</body>
</html>

writeform.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link href="https://fonts.googleapis.com/css2?family=Bagel+Fat+One&family=Dongle:wght@300&family=East+Sea+Dokdo&family=Gamja+Flower&family=Gowun+Dodum&family=Nanum+Gothic+Coding&family=Nanum+Pen+Script&family=Orbit&display=swap" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css">
<script src="https://code.jquery.com/jquery-3.7.0.js"></script>
<title>Insert title here</title>
</head>
<body>
	<div style="margin: 50px 100px;">
		<form action="insert" method="post" enctype="multipart/form-data">
			<!-- hidden 5개 넣어주기 -->
			<input type="hidden" name="num" value="${num }">
			<input type="hidden" name="currentPage" value="${currentPage }">
			<input type="hidden" name="regroup" value="${regroup }">
			<input type="hidden" name="restep" value="${restep }">
			<input type="hidden" name="relevel" value="${relevel }">
			 
			<table class="table table-bordered" style="width: 500px;">
				<caption align="top"><b>
					<c:if test="${num==0 }">새글쓰기</c:if>	
					<c:if test="${num!=0 }">답글쓰기</c:if>
				</b></caption>
				
				<tr>
					<th>작성자</th>
					<td>
						<input type="text" name="writer" class="form-control" required="required" style="width: 100px;">
					</td>
				</tr>
				<tr>
					<th>비밀번호</th>
					<td>
						<input type="password" name="pass" class="form-control" required="required" style="width: 130px;">
					</td>
				</tr>
				<tr>
					<th>제목</th>
					<td>
						<input type="text" name="subject" class="form-control" required="required" style="width: 300px;">
					</td>
				</tr>
				<tr>
					<th>사진</th>
					<td>
						<input type="file" name="uimage" class="form-control" style="width: 220px;" multiple="multiple">
					</td>
				</tr>
				<tr>
					<td colspan="2">
						<textarea style="width: 480px; height: 150px;" name="content" required="required" class="form-control"></textarea>
					</td>
				</tr>
				<tr>
					<td colspan="2" align="center">
						<button type="submit" class="btn btn-info" style="width: 100px;">저장하기</button>
						<button type="button" class="btn btn-success" onclick="location.href='list'" style="width: 100px;">목록</button>
					</td>
				</tr>
			</table>
		</form>
	</div>
</body>
</html>
profile
java를 잡아...... 하... 이게 맞나...

0개의 댓글

Powered by GraphCDN, the GraphQL CDN