본문 바로가기
카테고리 없음

1.17 (tiles-조회수,정렬,상세폼, 파일다운,수정폼호출,수정파일삭제)

by 쿠룽지 2024. 1. 18.
728x90
반응형

 

 

 

 

<복습>

 

 

 

검색 기능 넣기

 

1. 

boardMapper.xml에 sql태그 사용하여 where절 생성

 

2.

1에서 만든 sql태그를 총개수/검색개수, 목록/검색목록에 include

정렬도 똑같은 형태로 생성하면 됨 정렬하는 order절 만들고 include

 

 


 

 

 

 

<게시판에 정렬 버튼 만들기>

 

 

 

BoardController에 

정렬하기 위해 이미 @RequestParam(value="order", defaultValue="1")을 넣었음

 

 

 

 

정렬버튼 추가 + 유효성 체크 + 정렬 이벤트 삽입

views

board

boardList.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!-- 내용 시작 -->
<div class="page-main">
	<h2>게시판 목록</h2>
	<form action="list" id="search_form" method="get">
		<ul class="search">
			<li>
				<select name="keyfield" id="keyfield">
					<option value="1" <c:if test="${param.keyfield == 1}">selected</c:if>>제목</option>
					<option value="2" <c:if test="${param.keyfield == 2}">selected</c:if>>ID+별명</option>
					<option value="3" <c:if test="${param.keyfield == 3}">selected</c:if>>내용</option>
					<option value="4" <c:if test="${param.keyfield == 4}">selected</c:if>>제목+내용</option>
				</select>
			</li>
			<li>
				<input type="search" name="keyword" id="keyword" value="${param.keyword}">
			</li>
			<li>
				<input type="submit" value="찾기">
				<input type="button" value="목록" onclick="location.href='list'">
			</li>
		</ul>
		<div class="align-right">
			<select id="order" name="order">
				<option value="1" <c:if test="${param.order == 1}">selected</c:if>>최신순</option>
				<option value="2" <c:if test="${param.order == 2}">selected</c:if>>조회수</option>
				<option value="3" <c:if test="${param.order == 3}">selected</c:if>>좋아요</option>
				<option value="4" <c:if test="${param.order == 4}">selected</c:if>>댓글수</option>
			</select>
			<c:if test="${!empty user}">
			<input type="button" value="글쓰기" onclick="location.href='write'">
			</c:if>
		</div>
	</form>
	<c:if test="${count == 0}">
	<div class="result-display">표시할 게시물이 없습니다.</div>
	</c:if>
	<c:if test="${count > 0}">
	<table class="striped-table">
		<tr>
			<th>번호</th>
			<th width="400">제목</th>
			<th>작성자</th>
			<th>작성일</th>
			<th>조회수</th>
			<th>좋아요수</th>
		</tr>
		<c:forEach var="board" items="${list}">
		<tr>
			<td class="align-center">${board.board_num}</td>
			<td><a href="detail?board_num=${board.board_num}">${board.title}(${board.re_cnt})</a></td>
			<td class="align-center">
				<c:if test="${empty board.nick_name}">${board.id}</c:if>
				<c:if test="${!empty board.nick_name}">${board.nick_name}</c:if>
			</td>
			<td class="align-center">${board.reg_date}</td>
			<td class="align-center">${board.hit}</td>
			<td class="align-center">${board.fav_cnt}</td>
		</tr>
		</c:forEach>
	</table>
	<div class="align-center">${page}</div>
	</c:if>
</div>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-3.6.0.min.js"></script>
<script type="text/javascript">
$(function(){
	//검색 유효성 체크
	$('#search_form').submit(function(){
		if($('#keyword').val().trim()==''){
			alert('검색어를 입력하세요');
			$('#keyword').val('').focus();
			return false;
		}
	});//end of submit
	
	//정렬 선택
	$('#order').change(function(){
		location.href='list?keyfield='+$('#keyfield').val()+'&keyword='+$('#keyword').val()+'&order='+$('#order').val();
	});
});
</script>
<!-- 내용 끝 -->

1.

<option value="1" <c:if test="${param.order == 1}">selected</c:if>

전송된 value값이 화면에 남아있게끔 처리

 

2.

http://localhost:8000/board/list?keyfield=1&keyword=%EC%A3%BC%EC%8A%A4&order=1

실행 후 검색, 정렬을 선택 -> url을 보면 keyword/order 값이 get방식으로 전달된걸 알 수 있음

 

3.

정렬 필터는 jquery(ajax) 사용해서 해당 화면에서 움직이게함

파라미터네임 연결할 땐 ?
여러 개 명시할 땐 & 사용

아직 좋아요/ 댓글수는 넣지 않았기 때문에 정렬 1,2만 되는 상태

 

 

 

 

 

 

페이지 매핑 시 정렬+검색된 것에 대한 페이지 처리도 추가해야함

BoardController

//페이지 처리
PageUtil page = new PageUtil(keyfield, keyword, 
        currentPage, count, 20, 10, "list","&order="+order);

"&order="+order 추가

order도 연동 시키므로 인해 keyfield/keyword/order 가 동시에 작동할 수 있게 함

 

 

 


 

 

 

 

<상세페이지 구현/ 글쓴이 프로필 사진 표시 -db저장된 사진>

 

 

 

MemberController

//2. 프로필 사진 출력(회원번호 지정/ 게시판)
@RequestMapping("/member/viewProfile")
public String getProfileByMem_num(@RequestParam int mem_num,HttpServletRequest request, Model model) {
    MemberVO memberVO = memberService.selectMember(mem_num);

    viewProfile(memberVO, request, model); //3번 코드

    return "imageView";
}

2 추가

 

 

 

 

 

 

제목에 HTML태그 비허용, 글 상세 sql문 추가

BoardMapper.xml

<!-- 게시판 전체 목록/검색 목록 -->
	<select id="selectList" parameterType="map" resultType="boardVO">
		SELECT
		  *
		FROM (SELECT
				a.*,
				rownum rnum
			FROM (SELECT
					board_num,
					<![CDATA[
					REPLACE(REPLACE(title,'<','&lt;'),'>','&gt;') title,
					]]>
					hit,
					reg_date,
					mem_num,
					id,
					nick_name
				  FROM spboard JOIN spmember
				  USING(mem_num)
				  <include refid="boardSearch"></include>
				  <include refid="boardOrder"></include>)a)
		<![CDATA[
		WHERE rnum >= #{start} AND rnum <= #{end}
		]]>
	</select>
    
    
    <!-- 글 상세 -->
	<select id="selectBoard" parameterType="integer">
		SELECT
		  *
		FROM spboard
		JOIN spmember USING(mem_num)
		LEFT OUTER JOIN spmember_detail USING(mem_num)
		WHERE board_num=#{board_num}
	</select>

replace(replace(title, '<', '&lt;'), '>', '&gt;') title

<를 &lt; >를 &gt; 로 변경하여 html태그를 사용하지 못하게 함 (일반문자로 replace)

 

 

 

 

 

 

 

조회수 증가

BoardMapper.java

@Update("UPDATE spboard SET hit=hit+1 WHERE board_num=#{board_num}")
public void updateHit(int board_num);

 

 

 

 

 

메서드 묶어서 처리

BoardServiceImpl

@Override
public BoardVO selectBoard(int board_num) {
    return boardMapper.selectBoard(board_num);
}

@Override
public void updateHit(int board_num) {
    boardMapper.updateHit(board_num);
}

 

 

 

 

 

kr.spring.util에 mbox에 올려주신 StringUtil 파일 붙여넣기

 

BoardController

/*===========================
 * 게시판 글 상세
 * ==========================*/
@RequestMapping("/board/detail")
public ModelAndView process(@RequestParam int board_num) {
    log.debug("<<게시판 글 상세 board_num>> : " + board_num);

    //해당 글의 조회수 증가
    boardService.updateHit(board_num);

    BoardVO board = boardService.selectBoard(board_num);
    //제목에 태그를 허용하지 않음
    board.setTitle(StringUtil.useNoHtml(board.getTitle()));

    return new ModelAndView("boardView", "board", board); //tiles 설정명, 속성명, 속성값
}

 

 

 

 

 

설정파일에 글 상세 기재하기

tiles-def

board.xml

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE tiles-definitions PUBLIC
       "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
       "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">

<tiles-definitions>
    <definition name="boardList" extends="main">
    	<put-attribute name="title" value="게시판 목록"/>
    	<put-attribute name="body" value="/WEB-INF/views/board/boardList.jsp"/>
    </definition>
    <definition name="boardWrite" extends="main">
    	<put-attribute name="title" value="글쓰기"/>
    	<put-attribute name="body" value="/WEB-INF/views/board/boardWrite.jsp"/>
    </definition>
    <definition name="boardView" extends="main">
    	<put-attribute name="title" value="글 상세"/>
    	<put-attribute name="body" value="/WEB-INF/views/board/boardView.jsp"/>
    </definition>
   
</tiles-definitions>

 

 

 

 

 

 

상세폼 수정

views

board

boardView.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<!-- 내용 시작 -->
<div class="page-main">
	<h2>${board.title}</h2>
	<ul class="detail-info">
		<li>
			<img src="${pageContext.request.contextPath}/member/viewProfile?mem_num=${board.mem_num}" width="40" height="40" class="my-photo">
		</li>
		<li>
			<c:if test="${empty board.nick_name}">${board.id}</c:if>
			<c:if test="${!empty board.nick_name}">${board.nick_name}</c:if>
			<br>
			<c:if test="${!empty board.modify_date}">
			최근 수정일 : ${board.modify_date}
			</c:if>
			<c:if test="${empty board.modify_date}">
			작성일 : ${board.reg_date}
			</c:if>
			조회 : ${board.hit}
		</li>
	</ul>
	<c:if test="${!empty board.filename}">
	<ul>
		<li>첨부파일 : <a href="file?board_num=${board.board_num}">${board.filename}</a></li>
	</ul>
	</c:if>
	<hr size="1" width="100%">
	<c:if test="${fn:endsWith(board.filename, '.jpg') ||
				  fn:endsWith(board.filename, '.JPG') ||
				  fn:endsWith(board.filename, '.jpeg') ||
				  fn:endsWith(board.filename, '.JPEG') ||
				  fn:endsWith(board.filename, '.gif') ||
				  fn:endsWith(board.filename, '.GIF') ||
				  fn:endsWith(board.filename, '.png') ||
				  fn:endsWith(board.filename, '.PNG')}">
	<div class="align-center">
		<img src="${pageContext.request.contextPath}/upload/${board.filename}" class="detail-img">
	</div>
	</c:if>
	<div class="detail-content">
		${board.content}
	</div>
	<div>
		<%-- 좋아요 --%>
		<%-- 댓글수 --%>
	</div>
	<hr size="1" width="100%">
	<div class="align-right">
		<c:if test="${!empty user && user.mem_num == board.mem_num}">
			<input type="button" value="수정" onclick="location.href='update?board_num=${board.board_num}'">
			<input type="button" value="삭제" id="delete_btn">
			<script type="text/javascript">
				let delete_btn = document.getElementById('delete_btn');
				delete_btn.onclick=function(){
					let choice = confirm('삭제하시겠습니까?');
					if(choice){
						location.href='delete?board_num=${board.board_num}'
					}
				};
			</script>
		</c:if>
		<input type="button" value="목록" onclick="location.href='list'">
	</div>
	<hr size="1" width="100%">
	<%-- 댓글 작성 --%>
</div>
<!-- 내용 끝 -->

첨부파일 형태로 다운로드 받는 기능 + 만약 확장자가 jpeg,png 등 이미지라면 화면에 보여지는 (view) 형식도 추가
다운로드받는 downloadview는 선생님이 주신다 하심

화면에 이미지 출력하는 기능은 functions lib사용
endsWith=끝에 있는 글자 검색

fn:endsWith(board.filename, '.jpg')
board.filename의 끝 내용이 .jpg인것 찾기

=============================

제목 눌러서 글 상세 페이지 들어가면 사진, 글 모두 볼 수 있고 파일은 다운로드 링크도 생김 (아직 다운로드는 x)

 

 


 

 

 

 

 

<첨부파일 다운로드 기능 추가>

 

 

 

BoardController

/*===========================
 * 파일 다운로드
 * ==========================*/
@RequestMapping("/board/file")
public ModelAndView download(@RequestParam int board_num, HttpServletRequest request) {
    BoardVO board = boardService.selectBoard(board_num);

    //파일을 절대경로에서 읽어들여 byte[]로 변환
    byte[] downloadFile = FileUtil.getBytes(request.getServletContext().
    			getRealPath("/upload")+"/"+board.getFilename());

    //imageView->무조건view    download View->무조건download
    ModelAndView mav = new ModelAndView();
    mav.setViewName("downloadView");
    mav.addObject("downloadFile", downloadFile);
    mav.addObject("filename", board.getFilename());

    return mav;
}

imageView 는 view가 컨텐트타입
downloadView는 download가 컨텐트 타입

 

 

샘이 mbox에 공유해준 downloadView 받고 kr.spring.view에 넣기
byte[]로 변환한 downloadFile을 downloadView에서 받고 다운로드 받게 해줌

 

 

 


 

 

 

 

<수정 작업 시 파일만 삭제하기>

 

 

 

BoardMapper.java

@Update("UPDATE spboard SET filename='' WHERE board_num=#{board_num}")
public void deleteFile(int board_num);

사실상 delete가 아닌 ''로 update하는 것이기 때문에 filename='' 이라 코드를 작성

 

 

 

 

 

BoardService.java

public void deleteFile(int board_num);

 

 

BoardServiceImpl

@Override
public void deleteFile(int board_num) {
    boardMapper.deleteFile(board_num);
}

 

 

 

 

 

컨트롤러에서 호출

BoardController

/*===========================
 * 게시판 글 수정
 * ==========================*/
//수정폼 호출
@GetMapping("/board/update")
public String formUpdate(@RequestParam int board_num,Model model){
    BoardVO boardVO = boardService.selectBoard(board_num);

    model.addAttribute("boardVO", boardVO);

    return "boardModify"; //tiles설정
}

javascript로 jsp에서 삽입할거임

 

 

 

 

 

뷰 파일

views
board
boardModify.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!-- 내용 시작 -->
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-3.6.0.min.js"></script>
<div class="page-main">
	<h2>글 수정</h2>
	<form:form action="update" modelAttribute="boardVO" id="update_form" enctype="multipart/form-data">
		<form:hidden path="board_num"/>
		<form:errors element="div" cssClass="error-color"/>
		<ul>
			<li>
				<form:label path="title">제목</form:label>
				<form:input path="title"/>
				<form:errors path="title" cssClass="error-color"/>
			</li>
			<li>
				<form:label path="content">내용</form:label>
				<form:textarea path="content"/>
				<form:errors path="content" cssClass="error-color"/>
			</li>
			<li>
				<form:label path="upload">파일업로드</form:label>
				<input type="file" name="upload" id="upload">
				<c:if test="${!empty boardVO.filename}">
				<div id="file_detail">(${boardVO.filename})파일이 등록되어 있습니다.
					<input type="button" value="파일삭제" id="file_del">
				</div>
				<script type="text/javascript">
					$(function(){
						$('#file_del').click(function(){
							let choice = confirm('삭제하시겠습니까?');
							if(choice){
								$.ajax({
									url:'deleteFile',
									data:{board_num:${boardVO.board_num}}, //el로 data읽어옴 ()가 ajax
									type:'post',
									dataType:'json',
									success:function(param){
										if(param.result == 'logout'){
											alert('로그인 후 사용하세요');
										}else if(param.result == 'success'){
											$('#file_detail').hide();
										}else{
											alert('파일 삭제 오류 발생');
										}
									},
									error:function(){
										alert('네트워크 오류 발생');
									}
								});
							}
						});
					});
				</script>
				</c:if>
			</li>
		</ul>
		<div class="align-center">
			<form:button>전송</form:button>
			<input type="button" value="글 상세" onclick="location.href='detail?board_num=${boardVO.board_num}'">		
		</div>
	</form:form>
</div>
<!-- 내용 끝 -->

upload 파일업로드 구문 script 추가 (파일삭제 버튼 id=file_del)

#file_del.click 시 confirm('삭제하시겠습니까?');

if(choice) -> ajax로 처리 url=deleteFile / data={board_num:${boardVO.board_num}}

result=logout 시 로그인 후 사용

success시 file_detail을 hide (숨김처리) 그외 오류는 alert창 띄움

**

()=ajax

{}=el로 데이터 읽어옴

 

 

 

 

 

 

매핑

tiles-def

board.xml

<definition name="boardModify" extends="main">
    <put-attribute name="title" value="글 수정"/>
    <put-attribute name="body" value="/WEB-INF/views/board/boardModify.jsp"/>
</definition>

=============================

로그인 후 글수정 들어가면 폼 보임

 

 

 

 

 

 

ajax 통합관리하는 컨트롤에서 호출

src/main/java
kr.spring.board.controller
BoardAjaxController

package kr.spring.board.controller;

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

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import kr.spring.board.service.BoardService;
import kr.spring.board.vo.BoardVO;
import kr.spring.member.vo.MemberVO;
import kr.spring.util.FileUtil;
import lombok.extern.slf4j.Slf4j;

@Controller
@Slf4j
public class BoardAjaxController {
	@Autowired
	private BoardService boardService;
	
	/* ===========================
	 * 부모글 업로드 파일 삭제
	 * =========================== */
	@RequestMapping("/board/deleteFile")
	@ResponseBody
	public Map<String,String> processFile(int board_num,HttpSession session,HttpServletRequest request){
		Map<String,String> mapJson = new HashMap<String,String>();
		
		MemberVO user = (MemberVO)session.getAttribute("user");
		if(user==null) { //로그아웃
			mapJson.put("result", "logout");
		}else {
			BoardVO vo = boardService.selectBoard(board_num); //한건의 데이터 읽어오기
			
			boardService.deleteFile(board_num);//db에서 파일 삭제
			FileUtil.removeFile(request, vo.getFilename());//업로드 경로에서 파일 삭제
			
			mapJson.put("result", "success");
		}
		return mapJson;
	}
	
}

위 jsp에서 ajax에 설정한 url=deleteFile == RequestMapping

session으로부터 user정도 읽어온 후

user==null 일 시 result=logout

그외 상황인 경우

boardService.selectBoard (한건의 데이터 읽어와서 자바빈에 담기)

boardService.deleteFile (파일삭제)

FileUtil.removeFile(쓰레기파일 삭제)

result=success 순대로 처리

 

Map return

 

 

=============================

수정폼에서 파일삭제 누르면 폼에 저장되어 있던 파일이 안보이게 됨 (hide처리)
수정 기능은 아직 x

 

728x90
반응형