댓글id추가

 

 

내용을 추가해주었으니 댓글을 새로 작성할 때에도 내용을 추가해야한다

replyWrite(boardId, userId)

 

지우기 버튼도 추가

 

 

자바스크립트에서 replyDelete 함수 만들기

 

 

ReplyDeleteProcAction

 

 

ReplyRepository

 

 

결과

'Web > Jsp' 카테고리의 다른 글

이클립스 eclipse sts툴 java / html / javascript / jsp 자동완성  (2) 2020.06.16
product 페이지 예제 만들기  (0) 2020.06.15
get / post 방식  (0) 2020.06.12
블로그 댓글쓰기  (0) 2020.06.12
블로그 댓글보기  (0) 2020.06.12

 

전달 가능 방식

get방식 - key:value

post, put, delete방식 - key:value + 텍스트 + json + 영상 이미지 등 byte + 등등등

--------------------------

get방식은 getParameter로 값을 받을 수 있고 버퍼로 받지 못한다

post방식처럼 body에 값을 넣어서 전달하는 경우
getParameter로 값을 받을 수 있고 버퍼로도 받을 수 있다

------------------------------

 

'Web > Jsp' 카테고리의 다른 글

product 페이지 예제 만들기  (0) 2020.06.15
블로그 댓글 지우기  (0) 2020.06.15
블로그 댓글쓰기  (0) 2020.06.12
블로그 댓글보기  (0) 2020.06.12
사진 업로드  (0) 2020.06.11

 

detail.jsp

더보기
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<%@include file="../include/nav.jsp"%>

<div class="container">

	<button type="button" class="btn btn-light" onclick="back(${param.page})">뒤로가기</button>

	<c:if test="${sessionScope.principal.id == detailDto.boardDto.board.userId}">

		<a href="/blog/board?cmd=update&id=${detailDto.boardDto.board.id}" class="btn btn-warning">수정</a>
		<!-- 하이퍼링크는 get방식만 사용 -->
		<button type="button" class="btn btn-danger" onclick="deleteById(${detailDto.boardDto.board.id})">삭제</button>

	</c:if>


	<br /> <br />


	<h6>
		작성자 : <i>${detailDto.boardDto.username}</i> 조회수 : <i>${detailDto.boardDto.board.readCount}</i>
	</h6>

	<br />

	<h3>${detailDto.boardDto.board.title}</h3>

	<div class="container p-3 my-3 border">${detailDto.boardDto.board.content}</div>

	<hr />
	<!-- 댓글 박스 -->
	<div class="row bootstrap snippets">
		<div class="col-md-12">
			<div class="comment-wrapper">
				<div class="panel panel-info">
					<div class="panel-heading m-2">
						<b>Comment</b>
					</div>
					<div class="panel-body">
						<textarea id="reply__write__form" class="form-control" placeholder="write a comment..." rows="3"></textarea>
						<br>
						<button onclick="replyWrite(${detailDto.boardDto.board.id}, ${sessionScope.principal.id})" type="button" class="btn btn-primary pull-right">댓글쓰기</button>
						<div class="clearfix"></div>
						<hr />
						<!-- 댓글 리스트 시작-->
						<ul id="reply__list" class="media-list">

							<c:forEach var="replyDto" items="${detailDto.replyDtos}">
								<!-- 댓글 아이템 -->
								<li class="media"><img onerror="this.src='/blog/image/userProfile.png'" src="${replyDto.userProfile}" alt="" class="img-circle">
									<div class="media-body">
										<strong class="text-primary">${replyDto.username}</strong>
										<p>
											${replyDto.reply.content} <br /> <br />
										</p>
									</div></li>
							</c:forEach>
						</ul>
						<!-- 댓글 리스트 끝-->
					</div>
				</div>
			</div>

		</div>
	</div>
	<!-- 댓글 박스 끝 -->

</div>

<script>

	function replyWrite(boardId, userId) {
		var data = {
			boardId : boardId,  // 키값은 변수가 안 들어가서 문제 없다
			userId : userId,
			content : $("#reply__write__form").val()
		}
		
		$.ajax({
			
			type: "post",
			url: "/blog/reply?cmd=writeProc",
			data : JSON.stringify(data),
			contentType : "application/json; charset=utf-8",
			dataType: "json"
			
		}).done(function (result) {
			
			$("#reply__list").empty();
			
			// 정상 응답
			// 1. reply__list를 찾아서 내부를 비우기
			// 2. ajax 재호출 findAll()
			// 3. reply__list를 찾아서 내부에 채워주기

			for (var replyDto of result) {
				
				var string = "<li class=\"media\"><img onerror=\"this.src='/blog/image/userProfile.png'\" src=\""+replyDto.userProfile+"\" alt=\"\" class=\"img-circle\">\r\n" + 
				"					<div class=\"media-body\">\r\n" + 
				"					<strong class=\"text-primary\">"+replyDto.username+"</strong>\r\n" + 
				"					<p>\r\n" + 
				"						"+replyDto.reply.content+" <br /> <br />\r\n" + 
				"					</p>\r\n" + 
				"				</div></li>";
				  
				$('#reply__list').append(string);
			
			}
			
// 		    result.forEach(replyDto => {
	    	
//				var string = "<li class=\"media\"><img onerror=\"this.src='/blog/image/userProfile.png'\" src=\""+replyDto.userProfile+"\" alt=\"\" class=\"img-circle\">\r\n" + 
//				"					<div class=\"media-body\">\r\n" + 
//				"					<strong class=\"text-primary\">"+replyDto.username+"</strong>\r\n" + 
//				"					<p>\r\n" + 
//				"						"+replyDto.reply.content+" <br /> <br />\r\n" + 
//				"					</p>\r\n" + 
//				"				</div></li>";
			  
//			$('#reply__list').append(string);
	        
//		    });
			
		}).fail(function (result) {
			
		});
		
		
// 		$.ajax({
// 			type: "post",
// 			url: "/~~/~",
// 			success: function name() {}, 
// 			error : function name() {}
// 		});
		
	}
</script>

<script src="/blog/js/detail.js"></script>

<%@include file="../include/footer.jsp"%>


 

자바스크립트에 replyWrite함수를 만들어 준다

 

boardId와 userId를 매개변수로 받아서 ajax로 통신하여 값(댓글배열)을 받아온다.

결과가 정상이면 댓글들을 모두 지우고

댓글배열을 통해 다시 댓글들을 생성해준다.

 

 

ReplyController

더보기
package com.cos.blog.controller;

import java.io.IOException;

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 com.cos.blog.action.Action;
import com.cos.blog.action.reply.ReplyWriteProcAction;


@WebServlet("/reply")
public class ReplyController extends HttpServlet {
	private final static String TAG = "ReplyController : ";
	private static final long serialVersionUID = 1L;
       
    public ReplyController() {
        super();
    }
    

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doProcess(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doProcess(request, response);
	}
	
	protected void doProcess(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// http://localhost:8000/blog/user?cmd=join
		String cmd = request.getParameter("cmd");
		System.out.println(TAG+"router : "+cmd);
		Action action = router(cmd);
		action.execute(request, response);
	}
	
	public Action router(String cmd) {
		if(cmd.equals("writeProc")) {
			return new ReplyWriteProcAction();
		}
		return null;
	}
	

}

 

 

 

ReplyWriteProcAction

더보기
package com.cos.blog.action.reply;

import java.io.BufferedReader;
import java.io.IOException;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.cos.blog.action.Action;
import com.cos.blog.dto.ReplyResponseDto;
import com.cos.blog.model.Reply;
import com.cos.blog.repository.ReplyRepository;
import com.cos.blog.util.Script;
import com.google.gson.Gson;

public class ReplyWriteProcAction implements Action{

	@Override
	public void execute(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		BufferedReader br = request.getReader();
		StringBuffer sb = new StringBuffer();
		String input = null;
		
		while ((input = br.readLine()) != null) {
			sb.append(input);
		}
		
		System.out.println(sb.toString());
		
		Gson gson = new Gson();
		Reply reply = gson.fromJson(sb.toString(), Reply.class);
		
		ReplyRepository replyRepository = ReplyRepository.getInstance();
		
		int result = replyRepository.save(reply);
		
//		Script.outText(Integer.toString(result), response);
		if(result == 1) {
			List<ReplyResponseDto> replyDtos = replyRepository.findAll(reply.getBoardId());
			
			Script.outJson(gson.toJson(replyDtos), response);
			
		} else {
			Script.back("댓글 달기에 실패하였습니다", response);
		}
		
		// ReplyRepository 연결 - save(reply)
		// save 성공하면 1, 실패하면 0, -1
		// Script.outText() 응답
		
	}

}

 

스트링빌더나 스트링버퍼를 사용하여 ajax에서 온 데이터를 조합한다

 

gson으로 json데이터를 자바객체로 만든다

 

데이터베이스에 댓글을 저장하고 결과값을 리턴받는다

 

결과값이 성공이면 댓글들을 새로받아와서 json으로 만든 뒤 ajax에게 돌려보내준다

 

 

ReplyRepository.java

더보기
package com.cos.blog.repository;

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 com.cos.blog.db.DBConn;
import com.cos.blog.dto.ReplyResponseDto;
import com.cos.blog.model.Board;
import com.cos.blog.model.Reply;
import com.cos.blog.model.Users;

public class ReplyRepository {
	private static final String TAG = "ReplyRepository : "; // TAG 생성 (오류 발견시 용이)
	private static ReplyRepository instance = new ReplyRepository();

	private ReplyRepository() {
	}

	public static ReplyRepository getInstance() {
		return instance;
	}

	private Connection conn = null;
	private PreparedStatement pstmt = null;
	private ResultSet rs = null;

	// 글쓰기
	public int save(Reply reply) { // object 받기(안에 내용 다 받아야 하니까)
		final String SQL = "INSERT INTO reply(id, userid, boardid, content, createDate) "
				+ "VALUES(REPLY_SEQ.nextval,?,?,?,sysdate)";
		try {
			conn = DBConn.getConnection(); // DB에 연결
			pstmt = conn.prepareStatement(SQL);
			pstmt.setInt(1, reply.getUserId());
			pstmt.setInt(2, reply.getBoardId());
			pstmt.setString(3, reply.getContent());
			// 물음표 완성하기
			return pstmt.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
			System.out.println(TAG + "save : " + e.getMessage());
		} finally {
			DBConn.close(conn, pstmt, rs);
		}
		return -1; // 실패시
	}

	// 회원정보 수정
	public int update(Board board) { // object 받기(안에 내용 다 받아야 하니까)
		final String SQL = "";
		try {
			conn = DBConn.getConnection(); // DB에 연결
			pstmt = conn.prepareStatement(SQL);
			// 물음표 완성하기
			return pstmt.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
			System.out.println(TAG + "Update : " + e.getMessage());
		} finally {
			DBConn.close(conn, pstmt, rs);
		}
		return -1; // 실패시
	}

	
	// 회원정보 삭제
	public int deleteById(int id) { // object 받기(안에 내용 다 받아야 하니까)
		final String SQL = "";
		try {
			conn = DBConn.getConnection(); // DB에 연결
			pstmt = conn.prepareStatement(SQL);
			// 물음표 완성하기
			return pstmt.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
			System.out.println(TAG + "Delete : " + e.getMessage());
		} finally {
			DBConn.close(conn, pstmt, rs);
		}
		return -1; // 실패시
	}

	
	public List<ReplyResponseDto> findAll(int boardId) {

		StringBuffer sb = new StringBuffer();
		sb.append("SELECT r.id, r.userid, r.boardId, r.content, r.createDate, u.username, u.userProfile ");
		sb.append("FROM reply r INNER JOIN users u ");
		sb.append("ON r.userid = u.id ");
		sb.append("WHERE boardId = ? ");
		sb.append("ORDER BY r.id DESC ");

		final String SQL = sb.toString();
		List<ReplyResponseDto> replyDtos = new ArrayList<>();

		try {
			conn = DBConn.getConnection();
			pstmt = conn.prepareStatement(SQL);
			pstmt.setInt(1, boardId);
			rs = pstmt.executeQuery();

			while (rs.next()) {

				Reply reply = Reply.builder()
						.id(rs.getInt(1))
						.userId(rs.getInt(2))
						.boardId(rs.getInt(3))
						.content(rs.getString(4))
						.createDate(rs.getTimestamp(5))
						.build();

				ReplyResponseDto replyDto = ReplyResponseDto.builder().reply(reply).username(rs.getString(6))
						.userProfile(rs.getString(7)).build();

				replyDtos.add(replyDto);

			}

			return replyDtos;
		} catch (SQLException e) {
			e.printStackTrace();
			System.out.println(TAG + "findAll(boardId) : " + e.getMessage());
		} finally {
			DBConn.close(conn, pstmt, rs);
		}
		return null; // 실패시
	}
	

	// 회원정보 다 찾기
	public List<Reply> findAll() { // object 받기(안에 내용 다 받아야 하니까)
		final String SQL = "";
		List<Reply> replys = new ArrayList<>();
		try {
			conn = DBConn.getConnection(); // DB에 연결
			pstmt = conn.prepareStatement(SQL);
			// 물음표 완성하기

			// while 돌려서 rs -> java오브젝트에 집어넣기
			return replys;
		} catch (SQLException e) {
			e.printStackTrace();
			System.out.println(TAG + "findAll : " + e.getMessage());
		} finally {
			DBConn.close(conn, pstmt, rs);
		}
		return null; // 실패시
	}

	// 회원정보 한 건 찾기
	public Reply findById(int id) { // object 받기(안에 내용 다 받아야 하니까)
		final String SQL = "";
		Reply reply = new Reply();
		try {
			conn = DBConn.getConnection(); // DB에 연결
			pstmt = conn.prepareStatement(SQL);
			// 물음표 완성하기

			// if 돌려서 rs -> java오브젝트에 집어넣기
			return reply;
		} catch (SQLException e) {
			e.printStackTrace();
			System.out.println(TAG + "findById : " + e.getMessage());
		} finally {
			DBConn.close(conn, pstmt, rs);
		}
		return null; // 실패시
	}

}

 

댓글 저장

 

 

댓글 xss 공격 막기

 

 

결과

-

'Web > Jsp' 카테고리의 다른 글

블로그 댓글 지우기  (0) 2020.06.15
get / post 방식  (0) 2020.06.12
블로그 댓글보기  (0) 2020.06.12
사진 업로드  (0) 2020.06.11
자바스크립트 on 이벤트  (0) 2020.06.11

 

BoardResponseDto

DetailResponseDto를 Board로 바꾼다.( 재사용하기위해서 )

 

BoardRepository

더보기
	public BoardResponseDto findById(int id) { // object 받기(안에 내용 다 받아야 하니까)
		
		StringBuilder sb = new StringBuilder();
		sb.append("SELECT b.id, b.userid, b.title, b.content, b.readcount, b.createdate, u.username ");
		sb.append("FROM board b INNER JOIN users u ");
		sb.append("ON b.userId = u.id ");
		sb.append("AND b.id = ?");
		
		final String SQL = sb.toString();
		BoardResponseDto boardDto = null;
		
		try {
			conn = DBConn.getConnection(); // DB에 연결
			pstmt = conn.prepareStatement(SQL);
			// 물음표 완성하기
			pstmt.setInt(1, id);
			
			rs = pstmt.executeQuery();
			
			// if 돌려서 rs -> java오브젝트에 집어넣기
			if(rs.next()) {
				
				boardDto = new BoardResponseDto();	
				Board board = Board.builder()
						.id(rs.getInt(1))
						.userId(rs.getInt(2))
						.title(rs.getString(3))
						.content(rs.getString(4))
						.readCount(rs.getInt(5))
						.createDate(rs.getTimestamp(6))
						.build();
				boardDto.setBoard(board);
				boardDto.setUsername(rs.getString(7));
				
			}
			
			return boardDto;
			
		} catch (SQLException e) {
			
			e.printStackTrace();
			System.out.println(TAG + "findById : " + e.getMessage());
			
		} finally {
			DBConn.close(conn, pstmt, rs);
		}
		
		return null; // 실패시
		
	}

 

BoardResponseDto로 바꾸었기 때문에 리포지토리의 리턴값도 바꾸어야한다.

 

 

ReplyResponseDto

댓글DTO생성

 

 

DetailResponseDto

board와 reply를 합쳐서 detail

 

 

데이터베이스

데이터베이스에서 쿼리문을 테스트해본다.

 

 

ReplyRepository

더보기
	public List<ReplyResponseDto> findAll(int boardId) {

		StringBuffer sb = new StringBuffer();
		sb.append("SELECT r.id, r.userid, r.boardId, r.content, r.createDate, u.username, u.userProfile ");
		sb.append("FROM reply r INNER JOIN users u ");
		sb.append("ON r.userid = u.id ");
		sb.append("WHERE boardId = ? ");
		sb.append("ORDER BY r.id DESC ");

		final String SQL = sb.toString();
		List<ReplyResponseDto> replyDtos = new ArrayList<>();

		try {
			conn = DBConn.getConnection();
			pstmt = conn.prepareStatement(SQL);
			pstmt.setInt(1, boardId);
			rs = pstmt.executeQuery();

			while (rs.next()) {

				Reply reply = Reply.builder()
						.id(rs.getInt(1))
						.userId(rs.getInt(2))
						.boardId(rs.getInt(3))
						.content(rs.getString(4))
						.createDate(rs.getTimestamp(5))
						.build();

				ReplyResponseDto replyDto = ReplyResponseDto.builder().reply(reply).username(rs.getString(6))
						.userProfile(rs.getString(7)).build();

				replyDtos.add(replyDto);

			}

			return replyDtos;
		} catch (SQLException e) {
			e.printStackTrace();
			System.out.println(TAG + "findAll(boardId) : " + e.getMessage());
		} finally {
			DBConn.close(conn, pstmt, rs);
		}
		return null; // 실패시
	}

 

findAll을 오버로딩하고, 스트링버퍼

 

 

BoardDetailAction

더보기
package com.cos.blog.action.board;

import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Vector;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.websocket.Session;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import com.cos.blog.action.Action;
import com.cos.blog.dto.BoardResponseDto;
import com.cos.blog.dto.DetailResponseDto;
import com.cos.blog.dto.ReplyResponseDto;
import com.cos.blog.model.Board;
import com.cos.blog.repository.BoardRepository;
import com.cos.blog.repository.ReplyRepository;
import com.cos.blog.util.HtmlParser;
import com.cos.blog.util.Script;

public class BoardDetailAction implements Action {

	@Override
	public void execute(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

		if (request.getParameter("id") == null || request.getParameter("id").equals("")) {
			Script.back("잘못된 접근입니다.", response);
			return;
		}
		

		int boardId = Integer.parseInt(request.getParameter("id"));

		BoardRepository boardRepository = BoardRepository.getInstance();
		
		ReplyRepository replyRepository = ReplyRepository.getInstance();
		
		int result = 0;
		
		Cookie[] cookies = request.getCookies();
		int visitor = 0;
		
		
		
		for (Cookie cookie : cookies) {
			System.out.println(cookie.getName());
			if(cookie.getName().equals("visit")) {
				
				visitor = 1;
				
				
				if(cookie.getValue().contains(request.getParameter("id"))) {
					
					result = 1;
					
				} else {
					
					cookie.setValue(cookie.getValue()+ "_" + request.getParameter("id"));
					
					response.addCookie(cookie);
					
					result = boardRepository.readCountUp(boardId);
					
				} 
			}
		}
		
		if(visitor == 0) {
			Cookie cookie1 = new Cookie("visit", request.getParameter("id"));
			response.addCookie(cookie1);
			
			result = boardRepository.readCountUp(boardId);
		}
		
		
		
//		if(result != 1) {
//			Script.back("서버오류", response);
//			return;
//		}
		
		
//		Cookie cookie =
		
//		HttpSession session = request.getSession();
//		if(session.getAttribute("sameUser") == null || !session.getAttribute("sameUser").equals(request.getParameter("id"))) {
//			result = boardRepository.readCountUp(id);
//			session.setAttribute("sameUser", request.getParameter("id"));
//		}
		
		
		if(result == 1) {
			System.out.println("리절트1 ");
			BoardResponseDto boardDto = boardRepository.findById(boardId);
			List<ReplyResponseDto> replyDtos = replyRepository.findAll(boardId);
			
			
			DetailResponseDto detailDto = DetailResponseDto.builder()
					.boardDto(boardDto)
					.replyDtos(replyDtos)
					.build();
			
			if (detailDto != null) {
				
				String content = detailDto.getBoardDto().getBoard().getContent(); // DTO에서 컨텐츠 가져오기
				
				String doc = HtmlParser.youtubeParser(content); // 유튜브 링크가 있다면 아래에 영상 프레임 넣기
				
				detailDto.getBoardDto().getBoard().setContent(doc); // 바뀐 내용을 콘텐츠에 바꿔넣기
				
				request.setAttribute("detailDto", detailDto);

				RequestDispatcher dis = request.getRequestDispatcher("board/detail.jsp");
				dis.forward(request, response);
				
			} else {
				Script.back("잘못된 접근입니다.", response);
			}
		} else {
			Script.back("상세보기를 할 수 없습니다.", response);
		}
		
	}

}

 

리포지토리를 소환

 

데이터를 가져와서 객체에 저장

 

detailDto에 두 객체를 저장

 

기존의 dto를 detailDto로 모두 바꿔준다

 

 

detail.jsp

기존의 dto를 detailDto로 모두 바꿔준다

 

데이터베이스에 댓글을 임의로 넣고 테스트

 

결과

-

'Web > Jsp' 카테고리의 다른 글

get / post 방식  (0) 2020.06.12
블로그 댓글쓰기  (0) 2020.06.12
사진 업로드  (0) 2020.06.11
자바스크립트 on 이벤트  (0) 2020.06.11
multipart/form-data // HTML 파일업로드 MIME타입  (0) 2020.06.11

 

아이콘을 클릭하면 프로필사진 수정페이지가 뜨게 하려고 한다.

 

 

nav.jsp

더보기
<%@page import="com.cos.blog.model.Users"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<%
	// 	Users principal = (Users) session.getAttribute("principal");
%>

<!DOCTYPE html>
<html lang="en">
<head>
<title>blog</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="/blog/css/styles.css" rel="stylesheet">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"></script>

<link href="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote-bs4.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote-bs4.min.js"></script>

</head>
<body>
	<nav class="navbar navbar-expand-md bg-dark navbar-dark">
		<a class="navbar-brand" href="/blog/index.jsp">Blog</a>
		<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#collapsibleNavbar">
			<span class="navbar-toggler-icon"></span>
		</button>

		<div class="justify-content-between collapse navbar-collapse" id="collapsibleNavbar">
			<ul class="navbar-nav">

				<c:choose>
					<c:when test="${empty sessionScope.principal}">

						<li class="nav-item"><a class="nav-link" href="/blog/user?cmd=login">로그인</a></li>
						<li class="nav-item"><a class="nav-link" href="/blog/user?cmd=join">회원가입</a></li>

					</c:when>

					<c:otherwise>

						<li class="nav-item"><a class="nav-link" href="/blog/board?cmd=write">글쓰기</a></li>
						<li class="nav-item"><a class="nav-link" href="/blog/user?cmd=update">회원정보</a></li>
						<li class="nav-item"><a class="nav-link" href="/blog/user?cmd=logout">로그아웃</a></li>

					</c:otherwise>
					
				</c:choose>

			</ul>

			<ul class="navbar-nav">

				<c:if test="${not empty sessionScope.principal}">
					<li class="nav-item">
					
						<a href="/blog/user?cmd=profileUpload"> 
						
							<img style="border-radius: 20px" onerror="this.src='/blog/image/userProfile.png'"
								src="${sessionScope.principal.userProfile}" width="40px" height="40px" />
						</a>
					</li>
				</c:if>

			</ul>

		</div>
	</nav>
	<br>

 

이미지를 클릭하면 이동하는 경로를 지정해준다.

 

UsersController.java

더보기
package com.cos.blog.controller;

import java.io.IOException;

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 com.cos.blog.action.Action;
import com.cos.blog.action.user.UsersJoinAction;
import com.cos.blog.action.user.UsersJoinProcAction;
import com.cos.blog.action.user.UsersLoginAction;
import com.cos.blog.action.user.UsersLoginProcAction;
import com.cos.blog.action.user.UsersLogoutAction;
import com.cos.blog.action.user.UsersProfileUploadAction;
import com.cos.blog.action.user.UsersProfileUploadProcAction;
import com.cos.blog.action.user.UsersUpdateAction;
import com.cos.blog.action.user.UsersUpdateProcAction;
import com.cos.blog.action.user.UsersUsernameCheckAction;

// http://localhost:8000/blog/user
@WebServlet("/user")
public class UsersController extends HttpServlet {
	private final static String TAG = "UsersController : ";
	private static final long serialVersionUID = 1L;

	public UsersController() {
		super();
	}

	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doProcess(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doProcess(request, response);
	}

	protected void doProcess(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// http://localhost:8000/blog/user?cmd=join
		String cmd = request.getParameter("cmd");
		System.out.println(TAG + "router : " + cmd);
		Action action = router(cmd);
		action.execute(request, response);
	}

	public Action router(String cmd) {
		if (cmd.equals("join")) {
			// 회원가입 페이지로 이동
			return new UsersJoinAction();
		} else if (cmd.equals("joinProc")) {
			// 회원가입을 진행 한 후 -> index.jsp로 이동
			return new UsersJoinProcAction();
		} else if (cmd.equals("update")) {
			// 회원 수정 페이지로 이동 (세션에 User 오브젝트를 가지고 있을 예정)
			return new UsersUpdateAction();
		} else if (cmd.equals("updateProc")) {
			// 회원 수정을 진행 한 후 -> index.jsp로 이동
			return new UsersUpdateProcAction();
		} else if (cmd.equals("delete")) {
			// 회원 삭제를 진행 한 후 -> 로그아웃을 하고 -> index.jsp로 이동
		} else if (cmd.equals("login")) {
			// 회원 로그인 페이지로 이동
			return new UsersLoginAction();
		} else if (cmd.equals("loginProc")) {
			// 회원 로그인을 수행한 후 -> 세션에 등록을 하고 -> index.jsp로 이동
			return new UsersLoginProcAction();
		} else if (cmd.equals("logout")) {
			// 회원 로그인을 수행한 후 -> 세션에 등록을 하고 -> index.jsp로 이동
			return new UsersLogoutAction();
		} else if (cmd.equals("usernameCheck")) {
			return new UsersUsernameCheckAction();
		} else if (cmd.equals("usernameCheck")) {
			return new UsersUsernameCheckAction();
		} else if (cmd.equals("profileUpload")) {
			return new UsersProfileUploadAction();
		} else if (cmd.equals("profileUploadProc")) {
			return new UsersProfileUploadProcAction();
		}

		return null;
	}

}

 

라우터에서 UsersProfileUploadAction 을 리턴한다

 

 

UsersUpdateAction.java

더보기
package com.cos.blog.action.user;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.cos.blog.action.Action;

public class UsersUpdateAction implements Action{

	@Override
	public void execute(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		RequestDispatcher dis = request.getRequestDispatcher("user/update.jsp");
		dis.forward(request, response);
		
	}
	
}

페이지이동

 

 

profileUpload.jsp

더보기
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<%@include file="../include/nav.jsp"%>



<div class="container">
	<div class="d-flex justify-content-center">
		<form action="/blog/user?cmd=profileUploadProc" method="post" enctype="multipart/form-data">

			<div class="form-group">
				<img id="img__wrap" onerror="this.src='/blog/image/userProfile.png'" src="${sessionScope.principal.userProfile}" width="350px" height="300px" />
			</div>
			<div class="form-group">
				<input type="file" name="userProfile" id="img__preview" />
				<!-- 단어를 이을 때 자바는 카멜 , html은 언더바를 주로 사용한다, 아이디쓸 때 언더바 두개 쓰기 -->
			</div>
				<input type="hidden" name="id" value="${sessionScope.principal.id}">
			<div class="form-group">
			
				<button class="btn btn-primary w-100">사진전송</button>
			
			</div>

		</form>
	</div>
</div>

<script src="/blog/js/imgPreview.js"></script>

<%@include file="../include/footer.jsp"%>

 

src를 세션의 principal에서 가져오고 만약에 null이거나 빈값이라면 onerror주소의 이미지를 가져온다

 

 

기본상태의 모습

 

 

파일을 선택 했을 때의 모습

 

 

imgPreview.js

더보기
$("#img__preview").on("change", (e) => {
	var f = e.target.files[0];
	
	console.log(f);

	if(!f.type.match("image*")){
		alert("이미지만 첨부 가능합니다.");
		$("#img__preview").val(""); // 이미지 파일이 아닐 경우 선택된 파일 없음 유지
		return;
	}

	if(f.size > 1024*1024*2){
		alert("용량을 초과 하였습니다.");
		$("#img__preview").val(""); // 이미지 파일이 아닐 경우 선택된 파일 없음 유지
		return;
	}
	
	var reader = new FileReader();
	
	// readAsDataURL(f)보다 위에 설정

	reader.onload = function (e) { // readAsDataURL(f)보다 아래에 있으면 타이밍이 안맞을 수 있음.
		$("#img__wrap").attr("src", e.target.result);			
	}
	
	reader.readAsDataURL(f); // 비동기 실행

	// reader.readAsDataURL(f); 가 실행이 끝나면 e.target(이벤트객체)에 result라는 객체를 하나
	// 생성하고 안에 이미지를 넣어준다.
	// $("#img__wrap").attr("src", e.target.result); // reader가 다읽으면 result가
	// 생성된다.(비동기이기때문에 작동안될 것)

});

 

이미지가 아니거나 용량을 초과 했을 경우 처리

 

이미지가 아닌 것을 올렸을 경우 메시지

 

 

reader객체를 선언하여 파일을 읽어오려고한다.

reader.readAsDataURL(f)를 이용하여 데이터를 먼저 받아오지 않고,

reader.onload를 먼저 선언해줘야한다.

reader.readAsDataURL(f)를 이용하여 데이터를 받아오면 자동으로 reader.onload()가 실행되는데,

너무 빨리 받아오면 onload함수를 선언하기도 전에 onload가 실행되기 때문에

미리 onload를 선언하고 데이터를 받아오게 한다.

데이터를 받아오면 target안에 result가 생성되고 result값을 이미지 미리보기의 주소값으로 바꾼다.

 

 

UsersProfileUploadProcAction.java

더보기
package com.cos.blog.action.user;

import java.io.BufferedReader;
import java.io.IOException;

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

import com.cos.blog.action.Action;
import com.cos.blog.model.Users;
import com.cos.blog.repository.UsersRepository;
import com.cos.blog.util.Script;
import com.oreilly.servlet.MultipartRequest;
import com.oreilly.servlet.multipart.DefaultFileRenamePolicy;

public class UsersProfileUploadProcAction implements Action {

	@Override
	public void execute(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		// getServletContext()는 프로젝트가 여러개일 때 무조건 넣어줘야함
		String realPath = request.getServletContext().getRealPath("image");
		int id;
		String fileName = null;
		String contextPath = request.getServletContext().getContextPath();
		String userProfile = null; // DB에 들어갈 변수 : 위치
		
		
		System.out.println("real " + realPath);
		System.out.println("context " + contextPath);
		
		try {
			MultipartRequest multi = new MultipartRequest(request, realPath, 1024*1024*2, "utf-8", new DefaultFileRenamePolicy());
			
			fileName = multi.getFilesystemName("userProfile");
			
			System.out.println("fileName " + fileName);
			
			id = Integer.parseInt(multi.getParameter("id"));
			
			userProfile = contextPath + "/image/" + fileName;
			
			UsersRepository usersRepository = UsersRepository.getInstance();
			
			int result = usersRepository.update(id, userProfile);
			
			if(result == 1) {
				
				HttpSession session = request.getSession();
				Users principal = usersRepository.findById(id);
				session.setAttribute("principal", principal);
				
				Script.href("사진변경 완료", "/blog/index.jsp", response);
			} else {
				Script.back("사진 변경 실패", response);
			}
			
		} catch (Exception e) {
			e.getStackTrace();
		}
		
		
		
		
		
		
//		BufferedReader br = request.getReader();
//		StringBuilder sb = new StringBuilder();
//		
//		String input = null;
//		
//		while ((input = br.readLine()) != null) {
//			sb.append(input);
//		}
//		
//		System.out.println("사진받았음");
//		System.out.println(sb.toString());
//		Script.outText("테스트 중", response);
		
	}

}

 

realPath는 톰캣이 운영하는 진짜 주소를 말한다.

 

 

multipart/form-data타입으로 전송할경우 request로는 파일을 가져올 수 없다.

MultipartRequest클래스를 이용하여

request와 실제 저장할 경로, 최대 받을 용량, 캐릭터셋, 파일이름이 중복될 경우 사용할 정책을 설정한다.

 

유저 프로필 주소를 context주소를 기준으로 폴더 + 파일명을 붙여준다.

 

유저프로필 주소를 업데이트 한다.

 

쿼리 결과값이 1이면 세션을 다시 세팅해준다.

 

UsersRepository.java

더보기
package com.cos.blog.repository;

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 com.cos.blog.db.DBConn;
import com.cos.blog.model.Users;

public class UsersRepository {
	private static final String TAG = "UserRepository : "; // TAG 생성 (오류 발견시 용이)
	private static UsersRepository instance = new UsersRepository();

	private UsersRepository() {
	}

	public static UsersRepository getInstance() {
		return instance;
	}

	private Connection conn = null;
	private PreparedStatement pstmt = null;
	private ResultSet rs = null;

	public int findByUsername(String username) {
		final String SQL = "SELECT count(*) " + "FROM users WHERE username=?";
		Users user = null;
		try {
			conn = DBConn.getConnection(); // DB에 연결
			pstmt = conn.prepareStatement(SQL);

			// 물음표 완성하기
			pstmt.setString(1, username);

			// if 돌려서 rs -> java오브젝트에 집어넣기
			rs = pstmt.executeQuery();

			if (rs.next()) {
				return rs.getInt(1);
			}

		} catch (SQLException e) {
			e.printStackTrace();
			System.out.println(TAG + "findByUsername : " + e.getMessage());
		} finally {
			DBConn.close(conn, pstmt, rs);
		}

		return -1; // 실패시
	}
	

	public Users findByUsernameAndPassword(String username, String password) {
		final String SQL = "SELECT id, username, email, address, userProfile, userRole, createDate "
				+ "FROM users WHERE username=? AND password=?";
		Users user = null;
		try {
			conn = DBConn.getConnection(); // DB에 연결
			pstmt = conn.prepareStatement(SQL);

			// 물음표 완성하기
			pstmt.setString(1, username);
			pstmt.setString(2, password);

			// if 돌려서 rs -> java오브젝트에 집어넣기
			rs = pstmt.executeQuery();
			if (rs.next()) {
				user = new Users(); // 무조건 null이 아니라는 의미
				user.setId(rs.getInt("id"));
				user.setUsername(rs.getString("username"));
				user.setEmail(rs.getString("email"));
				user.setAddress(rs.getString("address"));
				user.setUserProfile(rs.getString("userProfile"));
				user.setUserRole(rs.getString("userRole"));
				user.setCreateDate(rs.getTimestamp("createDate"));
			}
			return user;
		} catch (SQLException e) {
			e.printStackTrace();
			System.out.println(TAG + "findByUsernameAndPassword : " + e.getMessage());
		} finally {
			DBConn.close(conn, pstmt, rs);
		}
		return null; // 실패시
	}

	// 회원가입
	public int save(Users user) { // object 받기(안에 내용 다 받아야 하니까) // insert하고 싶으면 save
		final String SQL = "INSERT INTO users(id, username, password, email, address, userRole, createDate) "
				+ "VALUES(USERS_SEQ.nextval,?,?,?,?,?,sysdate)"; // userProfile은 나중에 update
		try {
			conn = DBConn.getConnection(); // DB에 연결
			pstmt = conn.prepareStatement(SQL);
			// 물음표 완성하기

			pstmt.setString(1, user.getUsername());
			pstmt.setString(2, user.getPassword());
			pstmt.setString(3, user.getEmail());
			pstmt.setString(4, user.getAddress());
			pstmt.setString(5, user.getUserRole()); // user권한 (종류는 user, admin)

			return pstmt.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
			System.out.println(TAG + "save : " + e.getMessage());
		} finally {
			DBConn.close(conn, pstmt, rs);
		}
		return -1; // 실패시
	}

	// 회원정보 수정
	public int update(Users user) { // object 받기(안에 내용 다 받아야 하니까)
		final String SQL = "UPDATE users SET password = ?, email = ?, address = ? WHERE id = ? ";
		try {
			conn = DBConn.getConnection(); // DB에 연결
			pstmt = conn.prepareStatement(SQL);
			// 물음표 완성하기
		
			pstmt.setString(1, user.getPassword());
			pstmt.setString(2, user.getEmail());
			pstmt.setString(3, user.getAddress());
			pstmt.setInt(4, user.getId());
			
			return pstmt.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
			System.out.println(TAG + "update : " + e.getMessage());
		} finally {
			DBConn.close(conn, pstmt, rs);
		}
		return -1; // 실패시
	}
	
	// 회원정보 수정
	public int update(int id, String userProfile) {
		final String SQL = "UPDATE users SET userProfile = ? WHERE id = ? ";
		try {
			conn = DBConn.getConnection(); // DB에 연결
			pstmt = conn.prepareStatement(SQL);
			// 물음표 완성하기
		
			pstmt.setString(1, userProfile);
			pstmt.setInt(2, id);
			
			return pstmt.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
			System.out.println(TAG + "update : " + e.getMessage());
		} finally {
			DBConn.close(conn, pstmt, rs);
		}
		return -1; // 실패시
	}

	// 회원정보 삭제
	public int deleteById(int id) { // object 받기(안에 내용 다 받아야 하니까)
		final String SQL = "";
		try {
			conn = DBConn.getConnection(); // DB에 연결
			pstmt = conn.prepareStatement(SQL);
			// 물음표 완성하기
			return pstmt.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
			System.out.println(TAG + "Delete : " + e.getMessage());
		} finally {
			DBConn.close(conn, pstmt, rs);
		}
		return -1; // 실패시
	}

	// 회원정보 다 찾기
	public List<Users> findAll() { // object 받기(안에 내용 다 받아야 하니까)
		final String SQL = "";
		List<Users> users = new ArrayList<>();
		try {
			conn = DBConn.getConnection(); // DB에 연결
			pstmt = conn.prepareStatement(SQL);
			// 물음표 완성하기

			// while 돌려서 rs -> java오브젝트에 집어넣기
			return users;
		} catch (SQLException e) {
			e.printStackTrace();
			System.out.println(TAG + "findAll : " + e.getMessage());
		} finally {
			DBConn.close(conn, pstmt, rs);
		}
		return null; // 실패시
	}

	// 회원정보 한 건 찾기
	public Users findById(int id) { // object 받기(안에 내용 다 받아야 하니까)
		final String SQL = "SELECT id, username, email, address, userProfile, userRole, createDate "
				+ "FROM users WHERE id = ?";
		Users user = new Users();
		try {
			conn = DBConn.getConnection(); // DB에 연결
			pstmt = conn.prepareStatement(SQL);
			
			// 물음표 완성하기
			pstmt.setInt(1, id);
			
			rs = pstmt.executeQuery();
			

			// if 돌려서 rs -> java오브젝트에 집어넣기
			if(rs.next()) {
				
				user = new Users(); // 무조건 null이 아니라는 의미
				user.setId(rs.getInt("id"));
				user.setUsername(rs.getString("username"));
				user.setEmail(rs.getString("email"));
				user.setAddress(rs.getString("address"));
				user.setUserProfile(rs.getString("userProfile"));
				user.setUserRole(rs.getString("userRole"));
				user.setCreateDate(rs.getTimestamp("createDate"));
				
			}
			
			return user;
		} catch (SQLException e) {
			e.printStackTrace();
			System.out.println(TAG + "findById : " + e.getMessage());
		} finally {
			DBConn.close(conn, pstmt, rs);
		}
		return null; // 실패시
	}
}

 

기존의 update를 오버로딩하여 프로필만 업데이트 하는 쿼리를 실행한다.

 

결과

사진이 업로드 된 모습

'Web > Jsp' 카테고리의 다른 글

블로그 댓글쓰기  (0) 2020.06.12
블로그 댓글보기  (0) 2020.06.12
자바스크립트 on 이벤트  (0) 2020.06.11
multipart/form-data // HTML 파일업로드 MIME타입  (0) 2020.06.11
자바 UUID 생성  (0) 2020.06.11

'Web > Jsp' 카테고리의 다른 글

블로그 댓글보기  (0) 2020.06.12
사진 업로드  (0) 2020.06.11
multipart/form-data // HTML 파일업로드 MIME타입  (0) 2020.06.11
자바 UUID 생성  (0) 2020.06.11
네비게이션 바에 사진 넣기  (0) 2020.06.11

 

profileUpload.jsp 코드

더보기
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<%@include file="../include/nav.jsp"%>



<div class="container">
	<div class="d-flex justify-content-center">
		<form action="/blog/user?cmd=profileUploadProc" method="post" enctype="multipart/form-data">

			<div class="form-group">
				<img id="img__wrap" onerror="this.src='/blog/image/userProfile.png'" src="${sessionScope.principal.userProfile}" width="350px" height="300px" />
			</div>
			<div class="form-group">
				<input type="file" name="userProfile" id="img__preview" />
				<!-- 단어를 이을 때 자바는 카멜 , html은 언더바를 주로 사용한다, 아이디쓸 때 언더바 두개 쓰기 -->
			</div>
				<input type="hidden" name="id" value="${sessionScope.principal.id}">
			<div class="form-group">
			
				<button class="btn btn-primary w-100">사진전송</button>
			
			</div>

		</form>
	</div>
</div>

<script src="/blog/js/imgPreview.js"></script>

<%@include file="../include/footer.jsp"%>

 

enctype="multipart/form-data"

enc타입을 위와 같이 설정해줘야 파일을 업로드 할 수 있다.

'Web > Jsp' 카테고리의 다른 글

사진 업로드  (0) 2020.06.11
자바스크립트 on 이벤트  (0) 2020.06.11
자바 UUID 생성  (0) 2020.06.11
네비게이션 바에 사진 넣기  (0) 2020.06.11
cos라이브러리를 이용하여 파일 업로드 및 다운로드  (0) 2020.06.11

uuid
완벽하게 고유하지는 않지만 실제 사용에서 중복될 가능성이 낮아서 자주 사용함

UUID.randomUUID()

자바 유틸에 내장된 uuid생성기를 이용하여 uuid를 생성할 수 있다.

+ Recent posts