[Day +84 / Server]사진 게시판 만들기1 // 내용추가하세요
211022 금
1. 사진 게시판 썸네일 형식으로 만들기
1) SQL Developer
Board 테이블에 사진 게시판 가데이터 5행 삽입
BEGIN FOR I IN 1..5 LOOP INSERT INTO BOARD VALUES(SEQ_BID.NEXTVAL, 2, 10, '사진 제목' || I, '사진 내용' || I, 2, DEFAULT, SYSDATE, SYSDATE, DEFAULT); -SEQ_BID.NEXTVAL : 215~219 / 사진 제목 || I : 사진 제목 1~5 / DEFAULT : 0 (조회수) / DEFATLT : Y(STATUS) ![]() INSERT INTO ATTACHMENT VALUES(SEQ_FID.NEXTVAL, SEQ_BID.CURRVAL, 'origin.png', 'change.png', 'resources/uploadFiles/', SYSDATE, 0, DEFAULT, DEFAULT); ![]() END LOOP; END; / COMMIT; |
*PL/SQL 구조 -선언부(DECLARE SECTION) : DECLARE로 시작, 변수나 상수를 선언하는 부분 -실행부(EXCUTABLE SECTION) : BEGIN으로 시작, 제어문, 반복문, 함수 등의 로직을 기술 -예외처리부(EXCEPTION SECTION) : EXCEPTION으로 시작, 예외 상황 발생 시 해결하기 위한 문장 기술 ![]() ![]() *SEQ. : 시퀀스 : 자동 번호 발생기 역할을 하는 객체 -순차적으로 정수 값을 자동으로 생성해줌 -UNIQUE한 값을 컬럼에 입력할 수 있음 / 일반적으로 PRIMARY KEY 값을 생성하기 위해 사용 *CURRVAL, NEXTVAL 시퀀스명.CURRVAL : 현재 생성된 시퀀스 값 시퀀스명.NEXTVAL : 시퀀스 값을 증가 시킴. 기본 시퀀스 값에서 증가치만큼 증가한 값. 출처 : 본인 블로그 [Day +45 / SQL]SYNONYM, PL_SQL 참조 *|| : sql에서 텍스트 합치기 연결자 출처 : https://lcs1245.tistory.com/entry/SQL-%EB%AC%B8%EC%9E%90-%ED%95%A9%EC%B9%98%EA%B8%B0-%EC%8C%8D%ED%8C%8C%EC%9D%B4%ED%94%84-CONCAT |
2) uploadFiles -> change.png 넣기
3) menubar.jsp
생략 <nav id="nav"> <ul> <li><a href="<%= request.getContextPath() %>">HOME</a></li> <li><a href="${ contextPath }/notice/list">공지사항</a></li> <li><a href="${ contextPath }/board/list">게시판</a></li> <li><a href="${ contextPath }/gallery/list">사진게시판</a></li> ![]() -client가 게시판 클릭시 galleryListServlet(/gallery/list)과 매핑 </ul> </nav> </div> </body> </html> |
4) GalleryLIstServlet 생성
5) Attachment 생성자 만들기
package board.model.vo; import java.sql.Date; public class Attachment { private int fid; // 첨부파일 pk private int bid; // 참조 게시글 아이디 private String originName; // 파일 업로드 시의 원본 파일명 private String changeName; // 서버 저장시의 변경 파일명 private String filePath; // 파일 저장 경로 private Date uploadDate; // 업로드된 시간 private int fileLevel; // 대표 사진0, 내용 사진1 private int downloadCount; // 다운로드 횟수 private String status; // 삭제 여부 ![]() -SQLDeveloper에서 만든 Attachment 테이블의 컬럼명들을 생성자로 만들었음 public Attachment() {} public Attachment(int fid, int bid, String originName, String changeName, String filePath, Date uploadDate, int fileLevel, int downloadCount, String status) { super(); this.fid = fid; this.bid = bid; this.originName = originName; this.changeName = changeName; this.filePath = filePath; this.uploadDate = uploadDate; this.fileLevel = fileLevel; this.downloadCount = downloadCount; this.status = status; } public int getFid() { return fid; } public void setFid(int fid) { this.fid = fid; } public int getBid() { return bid; } public void setBid(int bid) { this.bid = bid; } public String getOriginName() { return originName; } public void setOriginName(String originName) { this.originName = originName; } public String getChangeName() { return changeName; } public void setChangeName(String changeName) { this.changeName = changeName; } public String getFilePath() { return filePath; } public void setFilePath(String filePath) { this.filePath = filePath; } public Date getUploadDate() { return uploadDate; } public void setUploadDate(Date uploadDate) { this.uploadDate = uploadDate; } public int getFileLevel() { return fileLevel; } public void setFileLevel(int fileLevel) { this.fileLevel = fileLevel; } public int getDownloadCount() { return downloadCount; } public void setDownloadCount(int downloadCount) { this.downloadCount = downloadCount; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } @Override public String toString() { return "Attachment [fid=" + fid + ", bid=" + bid + ", originName=" + originName + ", changeName=" + changeName + ", filePath=" + filePath + ", fileLevel=" + fileLevel + ", downloadCount=" + downloadCount + ", status=" + status + "]"; } } |
6) Board에 <list>타입의 photoList추가
-private list<Attachment> photoList;
-관련된 getter, setter, tostring 등 모두 바꾸기
package board.model.vo; import java.util.Date; import java.util.List; public class Board { private int bid; // 게시글 고유 번호 private int btype; // 게시글 타입(1. 일반게시판, 2. 사진 게시판) private int cid; // 게시글 카테고리 id private String cname; // 게시글 카테고리명(category 테이블 조인 결과 값 : id와 명칭을 같이 조인해서 가져옴) private String btitle; // 게시글 제목 private String bcontent; // 게시글 내용 private int bwriter; // 게시글 작성자(user_no 참조 값) private String userName; // 게시글 작성자명(Member 테이블 조인 결과 값) private int bcount; // 게시글 조회수 private Date createDate; // 게시글 작성일 : sql Date 연월일 포맷되어서 2021-10-19 시분초 데이터 날라감 private Date modifyDate; // 게시글 수정일 : util Date를 사용해야 시분초 안날라감 대신 포맷팅이 안되어서 옴 private String status; // 게시글 상태(Y, N) private List<Attachment> photoList; // 사진 게시판 첨부 파일 (게시글 하나에 여러 첨부 파일을 가질 수 있음) /*BID NUMBER BTYPE NUMBER CID NUMBER BTITLE VARCHAR2(100 BYTE) BCONTENT VARCHAR2(4000 BYTE) BWRITER NUMBER BCOUNT NUMBER CREATE_DATE DATE MODIFY_DATE DATE STATUS VARCHAR2(1 BYTE)*/ public Board() {} public Board(int bid, int btype, int cid, String cname, String btitle, String bcontent, int bwriter, String userName, int bcount, Date createDate, Date modifyDate, String status) { super(); this.bid = bid; this.btype = btype; this.cid = cid; this.cname = cname; this.btitle = btitle; this.bcontent = bcontent; this.bwriter = bwriter; this.userName = userName; this.bcount = bcount; this.createDate = createDate; this.modifyDate = modifyDate; this.status = status; } public Board(int bid, int btype, int cid, String cname, String btitle, String bcontent, int bwriter, String userName, int bcount, Date createDate, Date modifyDate, String status, List<Attachment> photoList) { super(); this.bid = bid; this.btype = btype; this.cid = cid; this.cname = cname; this.btitle = btitle; this.bcontent = bcontent; this.bwriter = bwriter; this.userName = userName; this.bcount = bcount; this.createDate = createDate; this.modifyDate = modifyDate; this.status = status; this.photoList = photoList; } public int getBid() { return bid; } public void setBid(int bid) { this.bid = bid; } public int getBtype() { return btype; } public void setBtype(int btype) { this.btype = btype; } public int getCid() { return cid; } public void setCid(int cid) { this.cid = cid; } public String getCname() { return cname; } public void setCname(String cname) { this.cname = cname; } public String getBtitle() { return btitle; } public void setBtitle(String btitle) { this.btitle = btitle; } public String getBcontent() { return bcontent; } public void setBcontent(String bcontent) { this.bcontent = bcontent; } public int getBwriter() { return bwriter; } public void setBwriter(int bwriter) { this.bwriter = bwriter; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public int getBcount() { return bcount; } public void setBcount(int bcount) { this.bcount = bcount; } public Date getCreateDate() { return createDate; } public void setCreateDate(Date createDate) { this.createDate = createDate; } public Date getModifyDate() { return modifyDate; } public void setModifyDate(Date modifyDate) { this.modifyDate = modifyDate; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } public List<Attachment> getPhotoList() { return photoList; } public void setPhotoList(List<Attachment> photoList) { this.photoList = photoList; } @Override public String toString() { return "Board [bid=" + bid + ", btype=" + btype + ", cid=" + cid + ", cname=" + cname + ", btitle=" + btitle + ", bcontent=" + bcontent + ", bwriter=" + bwriter + ", userName=" + userName + ", bcount=" + bcount + ", createDate=" + createDate + ", modifyDate=" + modifyDate + ", status=" + status + ", photoList=" + photoList + "]"; } } |
Q. photoList를 Board에 추가해준 이유가 뭘까? |
7) GalleryListServlet
List<Board> boardList = new BoardService().selectGalleryList(); / 3번의 menubar와 매핑
생략 /** * Servlet implementation class GalleryListServlet */ @WebServlet("/gallery/list") public class GalleryListServlet extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public GalleryListServlet() { super(); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { List<Board> boardList = new BoardService().selectGalleryList(); -<board>클래스에 List타입의 boardList객체를 만들겠다. 그 값은 BoardService의 selectGalleryList에서 불러오겠다.(아직 만들어주지 않았음) // System.out.println(boardList); request.setAttribute("boardList", boardList); request.getRequestDispatcher("/WEB-INF/views/gallery/galleryListView.jsp").forward(request, response); } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); } } |
8) BoardService
package board.model.service; import java.sql.Connection; import java.util.HashMap; import java.util.List; import java.util.Map; import board.model.dao.BoardDao; import board.model.vo.Board; import board.model.vo.PageInfo; import board.model.vo.Search; import notice.model.vo.Notice; import static common.JDBCTemplate.*; public class BoardService { private BoardDao boardDao = new BoardDao(); public Map<String, Object> selectList(int page, Search search) { // JDBCTemplate 임포트 필요 Connection conn = getConnection(); // 1. 게시글 총 개수 구하기 int listCount = boardDao.getListCount(conn, search); // System.out.println(listCount); // 2. PageInfo 객체 만들기 PageInfo pi = new PageInfo(page, listCount, 10, 10); // 3. 페이징 처리된 게시글 목록 조회 List<Board> boardList = boardDao.selectList(conn, pi, search); Map<String, Object> returnMap = new HashMap<>(); // System.out.println(listCount); //갯수 출력됨 // System.out.println(pi); // System.out.println(boardList); returnMap.put("pi", pi); returnMap.put("boardList", boardList); return returnMap; } 생략 public List<Board> selectGalleryList() { Connection conn = getConnection(); -Connection객체를 쓰겠다. How? JDBCTemplate에 저장해놨음 List<Board> boardList = boardDao.selectGalleryList(conn); -BoardDao에서 selectGalleryList메소드를 통해 conn과 연결해서 본격적으로 사용하겠다. -> Dao로 감 close(conn); -boardDao에서 돌아온 후 다 쓴 conn객체는 그만 쓰겠다. return boardList; -boardDao까지 탐색해서 알아낸 boardList 값을 servlet으로 보내겠다. } } |
9) board-query
select문 작성
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> <properties> 생략 <entry key="selectGalleryList"> SELECT BID , CNAME , BTITLE , USER_NAME , BCOUNT , FILE_PATH , CHANGE_NAME FROM BOARD B JOIN CATEGORY USING(CID) JOIN MEMBER ON(BWRITER=USER_NO) JOIN ATTACHMENT USING(BID) WHERE BTYPE = 2 AND B.STATUS = 'Y' AND FILE_LEVEL = 0 ORDER BY BID DESC </entry> </properties> |
10) dao
PreparedStatement pstmt = null;
ResultSet rset = null;
List<Board> boardList = new ArrayList<>();
String sql = boardQuery.getProperty("selectGalleryList");
return boardList;
package board.model.dao; import java.io.FileInputStream; import java.io.IOException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.Properties; import board.model.vo.Attachment; import board.model.vo.Board; import board.model.vo.PageInfo; import board.model.vo.Search; import static common.JDBCTemplate.close; public class BoardDao { 생략 public List<Board> selectGalleryList(Connection conn) { PreparedStatement pstmt = null; -이제부터 PreparedStatment를 쓸 것이다. 준비해라(초기화해라) *PreparedStatement : sql에서 실행부분 담당 ResultSet rset = null; List<Board> boardList = new ArrayList<>(); Q. 이게 무슨 뜻일까 String sql = boardQuery.getProperty("selectGalleryList"); -board-query의 entry키가 selectGalleryList와 연결하겠다. Q. 이름이 똑같지 않은데 board-Query.xml인지 어떻게 알았지? A. 위쪽에 연결하는 코드 써줬음 이미 try { pstmt = conn.prepareStatement(sql); -PreparedStatement 생성 후 실행할 쿼리 정보를 등록한다 rset = pstmt.executeQuery(); -rset에 쿼리에서 불러온 결과 값 담기 while(rset.next()) { -row를 다음으로 이동시킨다. 리턴값은 true와 false Board board = new Board(); board.setBid(rset.getInt("bid")); -rset(=sql)에서 얻어온 bid값을 board의 Bid에 넣는다. (int냐 String이냐 타입 맞춰줘야 함) board.setCname(rset.getString("cname")); board.setBtitle(rset.getString("btitle")); board.setUserName(rset.getString("user_name")); board.setBcount(rset.getInt("bcount")); Q. 여기 이름들은 어디서 가져온 이름일까?sql? jsp? 생성자? List<Attachment> photoList = new ArrayList<>(); Attachment photo = new Attachment(); photo.setFilePath(rset.getString("file_path")); photo.setChangeName(rset.getString("change_name")); photoList.add(photo); board.setPhotoList(photoList); boardList.add(board); } } catch (SQLException e) { e.printStackTrace(); } finally { close(rset); close(pstmt); } return boardList; } } |
*PreparedStatment와 ResultSet을 사용하는 이유 1) PreparedStatement (1) 쿼리와 값(파라메터)을 따로 보낸다. (2) 쿼리의 실행계획을 한번만 세우게 된다. 2) ResultSet (1) 쿼리한 테이블을 결과값을 반환함. (2) 커서(cursor)가 위치함 -next(): 다음 위치를 가르키고, 데이터가 존재하면 true, 없다면 false 반환 -getxxx(): 데이터를 추출하기, (컬럼명 or 인덱스) Ex) getInt("ID"); getString(2); ..... 출처 : https://blog.kuby.co.kr/39 *PreparedStatement의 리턴값 (1) PreparedStatement.executeQuery()의 경우 ResultSet을 반환(=결과값이라는 뜻 ex. 3(3행) (2) PreparedStatement.executeUpdate()의 경우 INSERT문, UPDATE문, DELETE문을 실행한다 *Properties -키와 값을 String타입으로 제한한 Map컬렉션 -주로 Properties는 프로퍼티(*.properties)파일을 읽어 들일 때 주로 사용 *while 원리 ( )안이 true가 되면 while문은 무한정 반복한다. while문은 무한 루프에서 자주 사용된다. 끝나는 부분을 작성하지 않으면 while문은 무한히 반복한다는 뜻이다. 따라서 break;와 같은 명령문으로 종료시켜줘야 한다. |
리턴값 1) pstmt : oracle.jdbc.driver.OraclePreparedStatementWrapper@3a90b977 2) rset : oracle.jdbc.driver.OracleResultSetImpl@60f5056d 3) boardList(전체 출력) [Board [bid=219, btype=0, cid=0, cname=공통, btitle=사진 제목5, bcontent=null, bwriter=0, userName=홍길동, bcount=0, createDate=null, modifyDate=null, status=null, photoList=[Attachment [fid=0, bid=0, originName=null, changeName=change.png, filePath=/resources/uploadFiles/, fileLevel=0, downloadCount=0, status=null]]], Board [bid=218, btype=0, cid=0, cname=공통, btitle=사진 제목4, bcontent=null, bwriter=0, userName=홍길동, bcount=0, createDate=null, modifyDate=null, status=null, photoList=[Attachment [fid=0, bid=0, originName=null, changeName=change.png, filePath=/resources/uploadFiles/, fileLevel=0, downloadCount=0, status=null]]], Board [bid=217, btype=0, cid=0, cname=공통, btitle=사진 제목3, bcontent=null, bwriter=0, userName=홍길동, bcount=0, createDate=null, modifyDate=null, status=null, photoList=[Attachment [fid=0, bid=0, originName=null, changeName=change.png, filePath=/resources/uploadFiles/, fileLevel=0, downloadCount=0, status=null]]], Board [bid=216, btype=0, cid=0, cname=공통, btitle=사진 제목2, bcontent=null, bwriter=0, userName=홍길동, bcount=0, createDate=null, modifyDate=null, status=null, photoList=[Attachment [fid=0, bid=0, originName=null, changeName=change.png, filePath=/resources/uploadFiles/, fileLevel=0, downloadCount=0, status=null]]], Board [bid=215, btype=0, cid=0, cname=공통, btitle=사진 제목1, bcontent=null, bwriter=0, userName=홍길동, bcount=0, createDate=null, modifyDate=null, status=null, photoList=[Attachment [fid=0, bid=0, originName=null, changeName=change.png, filePath=/resources/uploadFiles/, fileLevel=0, downloadCount=0, status=null]]]] 4) board Board [bid=219, btype=0, cid=0, cname=공통, btitle=사진 제목5, bcontent=null, bwriter=0, userName=홍길동, bcount=0, createDate=null, modifyDate=null, status=null, photoList=[Attachment [fid=0, bid=0, originName=null, changeName=change.png, filePath=/resources/uploadFiles/, fileLevel=0, downloadCount=0, status=null]]] 5) photoList [Attachment [fid=0, bid=0, originName=null, changeName=change.png, filePath=/resources/uploadFiles/, fileLevel=0, downloadCount=0, status=null]] 6) photo Attachment [fid=0, bid=0, originName=null, changeName=change.png, filePath=/resources/uploadFiles/, fileLevel=0, downloadCount=0, status=null] |
11) servlet
-출력
-request.setAttribute("boardList", boardList);
request.getRequestDispatcher("/WEB-INF/views/gallery/galleryListView.jsp").forward(request, response);
package board.controller; import java.io.IOException; import java.util.List; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import board.model.service.BoardService; import board.model.vo.Board; /** * Servlet implementation class GalleryListServlet */ @WebServlet("/gallery/list") public class GalleryListServlet extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public GalleryListServlet() { super(); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { List<Board> boardList = new BoardService().selectGalleryList(); // System.out.println(boardList); request.setAttribute("boardList", boardList); request.getRequestDispatcher("/WEB-INF/views/gallery/galleryListView.jsp").forward(request, response); } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); } } |
*setAttribute 사용법 setAttribute(String name, Object value) |
12) galleryListView.jsp
-<ul class="board_list">여기부터
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>사진 게시판</title> 생략 </head> <body> <jsp:include page="/WEB-INF/views/common/menubar.jsp" /> <div class="outer"> <div class="wrap"> <div class="board_area"> <div class="board_title"> <h1>사진 게시판</h1> </div> <div class="list_div"> <ul class="board_list"> <c:forEach var="board" items="${ boardList }"> <li> <div class="box"> <img src="${ contextPath }${ board.photoList.get(0).filePath }${ board.photoList.get(0).changeName }"> <p class="category">[ ${ board.cname } ]</p> <p class="title">${ board.btitle }</p> <p class="writer">${ board.userName } | 조회수 : ${ board.bcount }</p> </div> </c:forEach> </ul> </div> <c:if test="${ !empty loginUser }"> <div class="btn_area"> <button onclick="location.href='${contextPath }/gallery/insert'">작성하기</button> </div> </c:if> </div> </div> </div> </body> </html> |
*<img src="${ contextPath }${ board.photoList.get(0).filePath }${ board.photoList.get(0).changeName }"> 의미 http://localhost:8801/jsp/resources/uploadFiles/change.png(url) 1) jsp = contextPath 2) /resources/uploadFiles/ = ${ board.photoList.get(0).filePath } 3) /change.png = ${ board.photoList.get(0).changeName } |
결과)
2. 작성하기
16. galleryListview
<c:if test="${ !empty loginUser }">
<div class="btn_area">
<button onclick="loction.href='${contextPath}/gallery/insert'">작성하기</button>
</div>
17.GalleryInsertSevlet
foward
18. galleryinserview
imagePreview 만들기
galleryInsertview
<form method="post" action="${ contextPath }/gallery/insert"
enctype="multipart/form-data">
<div class="content">
3. 작성하기 페이지에 사진 첨부할 때 리네임해서 DB에 저장하기