Continuing from 1016
<body>
<div>
<table>
<caption align="top"><b>내용보기</b></caption>
<tr>
<td>
<h2><b>${dto.subject }</b></h2>
<span style="float: right;margin-right: 20px">
조회: ${dto.viewcount }
<fmt:formatDate value="${dto.writeday }" pattern="yyyy-MM-dd HH:mm"/>
</span><br>
<h5><b>작성자: ${dto.writer }</b></h5>
</td>
</tr>
<tr>
<td>
<pre>${dto.content }</pre><br>
<!-- 이미지가 있을때만 출력 -->
<c:if test="${dto.photo!='no' }">
<c:forTokens var="p" items="${dto.photo }" delims=",">
<a href="../upload/${p }"><img src="../upload/${p }" style="width: 150px;height: 150px"></a>
</c:forTokens>
</c:if>
</td>
</tr>
<tr>
<td align="right">
<button type="button" class="btn btn-outline-success" onclick="location.href='writeForm'">글쓰기</button>
<button type="button" class="btn btn-outline-info" onclick="location.href='writeForm?num=${dto.num}®roup=${dto.regroup}&restep=${dto.restep}&relevel=${dto.relevel}¤tPage=${currentPage}'">답글</button>
<button type="button" class="btn btn-outline-warning" onclick="location.href='updatePassForm?num=${dto.num}¤tPage=${currentPage }'">수정</button>
<button type="button" class="btn btn-outline-danger" onclick="location.href='deletePassForm?num=${dto.num}¤tPage=${currentPage }'">삭제</button>
<button type="button" class="btn btn-outline-success" onclick="location.href='list?currentPage=${currentPage}'">목록</button>
</td>
</tr>
</table>
</div>
</body>
<mapper>
<update id="updateViewcount" parameterType="int">
update reboard set viewcount=viewcount+1 where num=#{num}
</update>
</mapper>
<mapper>
<!-- 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>
</mapper>
@Repository
public class BoardDao implements BoardDaoInter {
@Autowired
private SqlSession session;
@Override
public void insertReboard(BoardDto dto) {
int num=dto.getNum(); //String이면 null이냐 아니냐,int면 0이냐 아니냐
int regroup=dto.getRegroup();
int restep=dto.getRestep();
int relevel=dto.getRelevel();
if(num==0) {
regroup=getMaxNum()+1;
restep=0;
relevel=0;
}
else {
//같은 그룹중 잔달받은 restep보다 큰글들은 모두 +1
this.updateRestep(regroup, restep);
//전달받은 step과 level 모두 +1
restep++;
relevel++;
}
//바뀐값들을 다시 dto에 담는다
dto.setRegroup(regroup);
dto.setRestep(restep);
dto.setRelevel(relevel);
session.insert("insertOfReboard", dto);
}
}
@Controller
public class BoardWriteController {
@Autowired
BoardDaoInter dao;
@GetMapping("/board/writeForm")
public String writeform(Model model,@RequestParam Map<String, String> map) {
//요 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으로 넣어줘야함..답글일때 대비
model.addAttribute("currentPage", currentPage==null?"1":currentPage);
model.addAttribute("num", num==null?"0":num);
model.addAttribute("regroup", regroup==null?"0":regroup);
model.addAttribute("restep", restep==null?"0":restep);
model.addAttribute("relevel", relevel==null?"0":relevel);
//0으로 넣어야 dao에서 새글로 인식
//폼이 답글,새글 공용이므로
return "reboard/writeForm";
}
}
<body>
<div>
<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"></td>
</tr>
<tr>
<th>비밀번호</th>
<td><input type="password" name="pass" class="form-control" required="required"></td>
</tr>
<tr>
<th>제목</th>
<td><input type="text" name="subject" class="form-control" required="required"></td>
</tr>
<tr>
<th>사진</th>
<td><input type="file" name="uimage" class="form-control" style="width: 250px" multiple="multiple"></td>
</tr>
<tr>
<td colspan="2">
<textarea name="content" required="required" class="form-control"></textarea>
</td>
</tr>
<tr>
<td colspan="2" align="center">
<button type="submit">저장</button>
<button type="button" onclick="location.href='list'">목록</button>
</td>
</tr>
</table>
</form>
</div>
</body>
@Controller
public class BoardWriteController {
@Autowired
BoardDaoInter dao;
@PostMapping("/board/insert")
public String insert(@ModelAttribute BoardDto dto,
@RequestParam ArrayList<MultipartFile> uimage, //업로드 파일 여러개라서
HttpSession session,
@RequestParam int currentPage) {
String path=session.getServletContext().getRealPath("/WEB-INF/photo");
System.out.println(path);
SimpleDateFormat sdf=new SimpleDateFormat("yyyyMMddHHmmss");
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) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//photo에서 마지막 컴마 제거
photo=photo.substring(0, photo.length()-1);
}
//dto의 photo에 넣기
dto.setPhoto(photo);
//insert
dao.insertReboard(dto);
int num=dao.getMaxNum();
return "redirect:content?num="+num+"¤tPage="+currentPage;
}
}
<body>
<script type="text/javascript">
alert("비밀번호가 맞지 않습니다");
hitory.back();
</script>
</body>
<?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="board">
<select id="authentification" parameterType="HashMap" resultType="int">
select count(*) from reboard where num=#{num} and pass=#{pass}
</select>
</mapper>
@Repository
public class BoardDao implements BoardDaoInter {
@Autowired
private SqlSession session;
@Override
public int authentification(int num, int pass) {
HashMap<String, Integer> map=new HashMap<String, Integer>();
map.put("num", num);
map.put("pass", pass);
return session.selectOne("board.authentification", map);
}
}
//생략..추후 설명
@Controller
public class BoardDeleteController {
@Autowired
BoardDaoInter dao;
@PostMapping("/board/deletePass")
public String dpass(Model model,int num,int pass,HttpSession session) {
int flag=dao.authentification(num, pass);
String mapping="";
//비번이 맞으면 수정폼으로,틀리면 passFail로
mapping=(flag==0?"reboard/passFail":"redirect:list");
//다른 삭제 기능은 생략..추후 설명
return mapping;
}
}
<body>
<div style="margin: 200px">
<form action="deletePass" method="post">
<input type="hidden" name="num" value="${num }">
<input type="hidden" name="currentPage" value="${currentPage }">
<div>
<b>비밀번호를 입력해 주세요</b>
</div>
<div class="d-inline-flex">
<input type="password" name="pass" class="form-control" 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>
@Controller
public class BoardUpdateController {
@Autowired
BoardDaoInter dao;
@GetMapping("/board/updatePassForm")
public ModelAndView upassform(@RequestParam String num,@RequestParam String currentPage) {
ModelAndView mv=new ModelAndView();
mv.setViewName("reboard/updatePassForm");
mv.addObject("num", num);
mv.addObject("currentPage", currentPage);
return mv;
}
@Controller
public class BoardUpdateController {
@Autowired
BoardDaoInter dao;
@PostMapping("/board/updatePass")
public String upass(Model model,@RequestParam int num,int pass,int currentPage) {
int flag=dao.authentification(num, pass);
String mapping="";
//비번이 맞으면 수정폼으로,틀리면 passFail로
mapping=(flag==0?"reboard/passFail":"reboard/updateForm");
BoardDto dto=dao.getData(num);
model.addAttribute("dto", dto);
model.addAttribute("currentPage", currentPage);
return mapping;
}
<body>
<div style="margin: 50px 100px">
<form action="update" method="post" enctype="multipart/form-data">
<!-- hidden 5개 -->
<input type="hidden" name="num" value="${dto.num }">
<input type="hidden" name="currentPage" value="${currentPage }">
<input type="hidden" name="regroup" value="${dto.regroup }">
<input type="hidden" name="restep" value="${dto.restep }">
<input type="hidden" name="relevel" value="${dto.relevel }">
<table>
<caption align="top"><b>
<c:if test="${dto.num==0 }">새글쓰기</c:if>
<c:if test="${dto.num!=0 }">답글쓰기</c:if>
</b></caption>
<tr>
<th>작성자</th>
<td><input type="text" name="writer" class="form-control" value="${dto.writer }" readonly="readonly"></td>
</tr>
<tr>
<th>비밀번호</th>
<td><input type="password" name="pass" class="form-control" required="required" value="${dto.pass }"></td>
</tr>
<tr>
<th>제목</th>
<td><input type="text" name="subject" class="form-control" required="required" value="${dto.subject }"></td>
</tr>
<tr>
<th>사진</th>
<td><input type="file" name="modimage" class="form-control" multiple="multiple"></td>
</tr>
<tr>
<td colspan="2">
<textarea name="content" required="required" class="form-control">${dto.content }</textarea>
</td>
</tr>
<tr>
<td colspan="2" align="center">
<button type="submit" class="btn btn-outline-info">
<c:if test="${dto.relevel==0 }">원글 수정</c:if>
<c:if test="${dto.relevel==1 }">답글 수정</c:if>
<c:if test="${dto.relevel>1 }">답답글 수정</c:if>
</button>
<button type="button" onclick="location.href='list'">목록</button>
</td>
</tr>
</table>
</form>
</div>
</body>
<mapper>
<update id="updateOfReboard" parameterType="bdto">
update reboard set pass=#{pass},subject=#{subject},content=#{content}
<if test="photo!='no'">
,photo=#{photo}
</if>
where num=#{num}
</update>
</mapper>
@Controller
public class BoardUpdateController {
@Autowired
BoardDaoInter dao;
@PostMapping("/board/update")
public String update(Model model,@ModelAttribute BoardDto dto,@RequestParam int currentPage,
@RequestParam List<MultipartFile> modimage,
HttpSession session) {
String newphoto="";
if(modimage.get(0).getOriginalFilename().equals(""))
newphoto="no";
else {
String oldphoto=dao.getData(dto.getNum()).getPhoto();
String [] oldphotoes=oldphoto.split(",");
String path=session.getServletContext().getRealPath("/WEB-INF/photo");
for(String o:oldphotoes) {
File file=new File(path+"\\"+o);
file.delete();
}
for(MultipartFile f:modimage) {
SimpleDateFormat sdf=new SimpleDateFormat("yyyyMMddHHmmss");
String fName=sdf.format(new Date())+"_"+f.getOriginalFilename();
newphoto+=fName+",";
try {
f.transferTo(new File(path+"\\"+fName));
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
newphoto=newphoto.substring(0, newphoto.length()-1);
}
dto.setPhoto(newphoto);
dao.updateData(dto);
model.addAttribute("currentPage", currentPage);
model.addAttribute("dto", dto);
return "redirect:content?num="+dto.getNum()+"¤tPage="+currentPage;
}
}
<delete id="deleteWithChildren" parameterType="HashMap">
delete from reboard where restep
<if test="pointValue==-1">
>=#{restep}
</if>
<if test="pointValue!=-1">
between #{restep} and #{pointValue}
</if>
and relevel>=#{relevel} and regroup=#{regroup}
</delete>
게시물 삭제 시 해당 게시물에 첨부된 하위 게시물 전부 삭제 (g-s-l 이용)
g = g (같은 그룹의 게시물에만 적용)
l ≥ l (해당 게시물의 level보다 하위 level의 게시물까지 지정)
s 값은 조건(pointValue 존재 여부)에 따라 제어 방식 변경
<select id="nextRestep" parameterType="bdto" resultType="int">
select ifnull(min(restep),0) from reboard where regroup=#{regroup} and restep>#{restep} and relevel=#{relevel}
</select>
pointValue는 같은 level의, 해당 s 값보다 큰 s 값 중 최소값 → 즉 삭제 대상 게시물의 하위에 속하지 가장 가까운 이후의 게시물의 s 값
Delete Cascade 아닌 해당 게시물만을 삭제하고자 할 경우 아래의 Mapper 사용
<delete id="deleteOfReboard" parameterType="int">
delete from reboard where num=#{num}
</delete>
@Repository
public class BoardDao implements BoardDaoInter {
@Autowired
private SqlSession session;
@Override
public void deleteCascade(BoardDto dto) {
Map<String, Integer> map=new HashMap<String, Integer>();
int pointValue=(getNextRestep(dto)==0?0:getNextRestep(dto));
map.put("pointValue", getNextRestep(dto)-1);
map.put("restep", dto.getRestep());
map.put("relevel", dto.getRelevel());
map.put("regroup", dto.getRegroup());
session.delete("deleteChildren", map);
}
}
@Controller
public class BoardDeleteController {
@Autowired
BoardDaoInter dao;
@GetMapping("/board/deletePassForm")
public ModelAndView dpassform(@RequestParam String num,@RequestParam String currentPage) {
ModelAndView mv=new ModelAndView();
mv.setViewName("reboard/deletePassForm");
mv.addObject("num", num);
mv.addObject("currentPage", currentPage);
return mv;
}
@PostMapping("/board/deletePass")
public String dpass(Model model,int num,int pass,HttpSession session) {
int flag=dao.authentification(num, pass);
String path=session.getServletContext().getRealPath("/WEB-INF/photo");
BoardDto dto=dao.getData(num);
String mapping="";
//비번이 맞으면 수정폼으로,틀리면 passFail로
mapping=(flag==0?"reboard/passFail":"redirect:list");
if(mapping.equals("redirect:list")) {
if(!dao.getData(num).getPhoto().equals("no")) {
String [] oldphotoes=dao.getData(num).getPhoto().split(",");
for(String o:oldphotoes) {
File file=new File(path+"\\"+o);
file.delete();
}
}
dao.deleteCascade(dto);
}
model.addAttribute("dto", dto);
return mapping;
}
}