-----------------------------------------------------------------------------
오늘의 교훈 : 프로젝트는 와이어 프레임 짜고 생각하자...!
-----------------------------------------------------------------------------
Util.java
// 2024-02-21 psd
public HttpServletRequest req() { // 리퀘스트를 받아주는
ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
HttpServletRequest request = sra.getRequest();
return request;
}
}
더 짧게 쓰기 위해서 util에서 받아오도록 getSession() 생성
public HttpSession getSession() { 세션을 주는 -> 코드가 중복되므로 중복을 없애보자
ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
HttpServletRequest request = sra.getRequest();
HttpSession session = request.getSession();
return session;
}
}
-> 위의 코드를 이렇게 중복 제거
public HttpServletRequest req() { // 리퀘스트를 받아주는
ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
HttpServletRequest request = sra.getRequest();
return request;
}
public HttpSession getSession() { // 세션을 주는 -> 윗 부분과 코드가 중복되므로 중복을 없애보자
HttpSession session = req().getSession();
return session;
}
-> BoardService에서 util을 이용해 중복을 줄였으니 컨트롤러에서도 삭제해줘야함.
BoardController.java
@PostMapping("/write")에서 if문 수정
result의 write 변수에서 request삭제, dto만 남김.
// 2024-02-16 글쓰기 + 02-20
@PostMapping("/write") // 내용,제목 -> DB에 저장 -> 게시판으로
public String write(WriteDTO dto, HttpServletRequest request) {
if(util.getSession().getAttribute("mid") != null) {
int result = boardService.write(dto); // dto, request
if(result == 1) {
return "redirect:/detail?no="+dto.getBoard_no();
} else {
return "redirect:/error";
}
} else {
return "redirect:/login";
}
@PostMapping("/commentWrite")
public String commentWrite(CommentDTO comment) {
int result = boardService.commentWrite(comment); // boardService 실행 시 dto를 가지고 날아감
return "redirect:/detail?no="+comment.getNo(); // 글 번호를 받아서 글 번호로 페이지 이동
}
BoardService.java
public int write(WriteDTO dto) {
HttpServletRequest request = util.req();
HttpSession session = request.getSession();
dto.setMid((String) session.getAttribute("mid"));
return boardDAO.write(dto);
}
-> 짧게 줄여 중복을 없애보자 wirte, commentWrite
util.getSession().getAttribute("mid"));
public int write(WriteDTO dto) {
dto.setMid((String) util.getSession().getAttribute("mid"));
return boardDAO.write(dto);
}
public int commentWrite(CommentDTO comment) {
comment.setMid((String) util.getSession().getAttribute("mid"));
return boardDAO.commentWrite(comment); // DAO에게 일 시키기
}
-> 중복을 줄인 부분은 컨트롤러에서도 수정해줘야 함.
BoardService.java
BoardService 의 comment부분 코드 줄여주기
public int commentWrite(CommentDTO comment) {
// 가져오는 것 : 댓글 내용, 글 번호 + mid
comment.setMid((String) util.getSession().getAttribute("mid"));
return boardDAO.commentWrite(comment); // DAO에게 일 시키기
}
-> mapper 내용 수정해야함.
board-mapper.xml
- board_no의 변수명 수정 #{board_no}
- AND mno=() 쿼리문 추가
CDATA는 Character Data의 약어로, XML 또는 HTML 문서에서 문자 데이터를 포함하는 데 사용됩니다. CDATA 섹션은 특별한 문자나 태그로부터 내용을 보호하고, 해당 내용이 파서에 의해 해석되지 않도록 합니다.
<update id="postDel" parameterType="WriteDTO">
<![CDATA[
UPDATE board SET board_del='0' WHERE board_no=#{board_no}
AND mno=(SELECT mno FROM member WHERE mid=#{mid}))
]]>
</update>
BoardDTO.java
DTO에서 board_write를 mname으로 변경하기 -> 그에 따라 다른 파일들에서도 변경해줘야 한다.
// 게시판, 톺아보기, 글 삭제 등.. 변경해야함
// board-mapper의 boardList에서 변경 : board_write as mname
// detail 부분에 m.mname as board_write를 m.mname으로 변경 / m.mid 추가
// board.jsp : board_write를 mname으로 변경<td>${row.mname }</td>
import lombok.Data;
@Data
public class BoardDTO {
private int board_no, board_count, comment;
private String board_title, board_content, mname, mid, board_date, board_ip;
}
detail.jsp
+ 댓글 출력창에 수정, 삭제 아이콘 이미지 추가하기
<c:if test="${detail.mid eq sessionScope.mid }">
<img alt="edit" src="./assets/img/pencil.png">
<img alt="delete" src="./assets/img/deletey.png" title="글 삭제" onclick="deletePost(${detail.board_no})">
</c:if>
-> 게시판 디테일에 같은 아이디인지 확인하기
${detail.mname }
<c:if test="${detail.mid eq sessionScope.mid }">
같은 아이디입니다.
</c:if>
// 게시글 디테일 부분 코드
<h2 class="section-heading text-uppercase">게시글 디테일(톺아보기)</h2>
</div>
<div class="card mb-4" style="min-height: 500px;">
<div class="card-body">
<div class="h2">${detail.board_title }</div>
<div class="row p-2 bg-secondary">
<div class="col align-middle text-start">
${detail.mname }
<c:if test="${detail.mid eq sessionScope.mid }">
<img alt="edit" src="./assets/img/pencil.png">
<img alt="delete" src="./assets/img/deletey.png" title="글 삭제" onclick="deletePost(${detail.board_no})">
</c:if>
</div>
<div class="col align-middle text-end">${detail.board_date }</div>
</div>
<div class="mt-4 vh -75">${detail.board_content }</div>
</div>
</div>
<button class="btn btn-warning" onclick="history.back()">게시판으로</button>
<button class="btn btn-warning" onclick="history.go(-1)">게시판으로</button>
-> 댓글 출력창도 로그인한 아이디와 같은지 확인 코드
<c:if test="${c.mid eq sessionScope.mid }">
<img alt="edit" src="./assets/img/pencil.png">
<img alt="delete" src="./assets/img/deletey.png" title="댓글 삭제" onclick="deleteComment(${c.no })">
</c:if>
<!-- 댓글 출력창 20240219 -->
<div class="mt-2">
<c:forEach items="${commentsList}" var="c">
<div class="card mb-3">
<div
class="card-header bg-success text-white d-flex justify-content-between align-items-center">
<!-- 댓글 헤더 좌측 -->
<div>
${c.mname } / ${c.mid }
<c:if test="${c.mid eq sessionScope.mid }">
<img alt="edit" src="./assets/img/pencil.png">
<img alt="delete" src="./assets/img/deletey.png" title="댓글 삭제" onclick="deleteComment(${c.no })">
</c:if>
</div>
<!-- 댓글 정보 우측 -->
<div class="text-end">
<div>${c.cip } | ${c.cdate } | ${c.clike }</div>
</div>
</div>
<div class="card-body">
<p class="card-text">${c.comment}</p>
</div>
</div>
</c:forEach>
</div>
<!-- 댓글 끝 -->
detail.jsp
2024-02-21 댓글 삭제 버튼 jQuery function으로 추가
function deleteComment(no){
// Swal.fire("댓글 삭제", no+"번 댓글을 삭제합니다.","warning");
if(confirm("댓글을 삭제할까요?")){
location.href="./deleteComment?no=${board.board_no}&cno="+no; // get방식
}
}
</script>
댓글 삭제가 안되는 상태?
해결방법 :
${board.board_no} 를 ${detail.board_no}로 변경.
board아니라 detail임
// 2024-02-21 댓글 삭제 버튼
function deleteComment(no){
if(confirm("댓글을 삭제할까요?")){
location.href="./deleteComment?no=${detail.board_no}&cno="+no;
}
}
BoardController.java
deleteComment()
@GetMapping("/deleteComment")
public String deleteComment(@RequestParam("no") int no, @RequestParam("cno") int cno) {
System.out.println("no : " + no);
System.out.println("cno : " + cno);
return "redirect:/detail?no="+no; // 댓글 삭제 후에 원래의 게시물 페이지로 다시 돌아가기 위함
}
-> CommentDTO에 담아서
BoardService.java
// 2024-02-21
public int deleteComment(int no, int cno) {
CommentDTO dto = new CommentDTO();
dto.setNo(cno);
dto.setBoard_no(no);
dto.setMid((String) util.getSession().getAttribute("mid"));
return boardDAO.deleteComment(dto);
}
-> BoardDAO에 deleteComment 생성
BaordDAO.java
public int deleteComment(CommentDTO dto) {
return sqlSession.update("board.deleteComment", dto);
}
-> board-mapper에 추가
board-mapper.xml
<!-- 2024-02-21 본인 글만 삭제하도록 -->
<update id="deleteComment" parameterType="commetDTO">
UPDATE comment SET cdel='0'
WHERE cno=#{no} AND board_no=#{board_no} AND mno=(SELECT mno FROM member WHERE mid=#{mid})
</update>
Util.java
util에 ip 추가
// ip
public String getIP() { // 유효객체 만들어서 사용
HttpServletRequest request = req();
String ip = request.getHeader("X-FORWARDED-FOR");
if(ip == null) {
ip = request.getHeader("Proxy-Client-IP");
}
if(ip == null) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if(ip == null) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if(ip == null) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if(ip == null) {
ip = request.getRemoteAddr();
}
return ip;
}
BoardDTO.java
boardDTO와 writeDTO에 String 타입으로 ip 추가
- BoardDTO : board_ip
- WriteDTO : ip
@Data
public class BoardDTO {
private int board_no, board_count, comment;
private String board_title, board_content, mname, mid, board_date, board_ip;
}
@Data
public class WriteDTO {
private int board_no;
private String title, content, mid, ip;
}
BoardService.java
public int write(WriteDTO dto) {
dto.setMid((String) util.getSession().getAttribute("mid"));
dto.setIp(util.getIP()); // 아까 util에서 생성한 ip 부분
return boardDAO.write(dto);
}
board-mapper.xml
write의 sql 문 : board_ip와 #{ip} 추가하기
<insert id="write" parameterType="writeDTO">
INSERT INTO board (board_title, board_content, mno, board_ip)
VALUES (#{title}, #{content}, (SELECT mno FROM member WHERE mid=#{mid}), #{ip})
<selectKey resultType="Integer" keyProperty="board_no" order="AFTER">
SELECT LAST_INSERT_ID() <!-- 작성 후 내가 쓴 글로 돌아가기 -->
</selectKey>
</insert>
BoardService.java
댓글에 ip 추가하기 : commentWrite()
comment.setCip(util.getIP());
public int commentWrite(CommentDTO comment) {
comment.setMid((String) util.getSession().getAttribute("mid"));
comment.setCip(util.getIP());
return boardDAO.commentWrite(comment); // DAO에게 일 시키기
}
board-mapper.xml
commentWrite에 cip와 #{cip} 추가
<insert id="commentWrite" parameterType="commentDTO">
INSERT INTO comment (board_no, ccomment, mno, cip)
VALUES (#{no}, #{comment}, (SELECT mno FROM member WHERE mid=#{mid}), #{cip})
</insert>
BoardService.java
write에 엔터키 처리 코드 추가하기
public int write(WriteDTO dto) {
// 엔터키 처리
dto.setContent(dto.getContent().replaceAll("(\r\n|\r|\n|\n\r)", "<br>"));
dto.setMid((String) util.getSession().getAttribute("mid"));
dto.setIp(util.getIP());
return boardDAO.write(dto);
}
board.jsp
글쓰기 버튼 : 로그인한 사용자들만 보도록 (modal에 있는 글쓰기 버튼이 로그인 해야 보임)
<c:if test="${sessionScope.mid ne null }">
<button type="submit" class="btn btn-dark">글 등록하기</button>
</c:if>
글쓰기 모달 만드는 부분 전체코드
<!-- 글쓰기 모달 만들기 -->
<div class="modal" id="write">
<div class="modal-dialog modal-xl">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title">글쓰기 창입니다.</h3>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<div class="mt-2">
<form action="./write" method="post" onsubmit="return writeCheck()" name="frm">
<input type="text" id="title" name="title" class="form-control mb-2" required="required" placeholder="제목을 입력하세요">
<textarea id="summernote" name="content" class="form-control mb-2 vh-500" required="required"></textarea>
<!-- 글쓰기 버튼 (로그인 한 사람만 보이도록) -->
<c:if test="${sessionScope.mid ne null }">
<button type="submit" class="btn btn-dark">글 등록하기</button>
</c:if>
</form>
</div>
</div>
<div class="modal-footer">로그인 한 사용자만 글을 쓸 수 있어요!</div>
</div>
</div>
</div>
BoardController.java
로그인 여부 검사 코드 util.getSession().getAttribute("mid") != null
@PostMapping("/write")
// mid가 세션에 존재하면 boardService.write(dto)를 호출해서 게시글 작성하도록 함.
// 작성이 성공하면 해당 게시물의 상세페이지로 이동
// 작성이 실패하면 /error 페이지로 리다이렉트
// mid가 세션에 존재하지 않는다면 /login 페이지로 리다이렉트
// 로그인하지 않은 사용자가 write페이지에 접근하려 할 때 생기는 오류
@GetMapping("/write")
public String write() {
return "redirect:/login?error=2077";
}
@PostMapping("/write") // 내용,제목 -> DB에 저장 -> 게시판으로
public String write(WriteDTO dto, HttpServletRequest request) {
if(util.getSession().getAttribute("mid") != null) {
int result = boardService.write(dto);
if(result == 1) {
return "redirect:/detail?no="+dto.getBoard_no();
} else {
return "redirect:/error";
}
} else {
return "redirect:/login";
}
}
// 로그인 확인
@PostMapping("/commentWrite")
public String commentWrite(CommentDTO comment) {
if(util.getSession().getAttribute("mid") != null) {
int result = boardService.commentWrite(comment);
return "redirect:/detail?no="+comment.getNo();
} else {
return "redirect:/login";
}
}
login.jsp
Swal 스크립트 추가
<!-- Swal alert -->
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<!-- jQuery -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js" integrity="sha512-v2CJ7UaYy4JwqLDIrZUI/4hqeoQieOmAZNXBeQyjo21dadnwR+8ZaIJVT8EE2iyI61OV8e6M8PP2/4hpQINQ/g=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<!-- 2024-02-21 파라미터로 오는 error가 있다면 에러 화면에 출력하기 -->
<c:if test="${param.error ne null}">
<script type="text/javascript">
Swal.fire("ERROR HERE", "잘못된 접근입니다!", "warning");
</script>
</c:if>
<c:if test="${param.login ne null }">
<script type="text/javascript">
Swal.fire("로그인 불가", "올바른 아이디와 비번을 입력해주세요.", "warning");
</script>
</c:if>
</body>
</html>
LoginController.java
// loginService.login(loginDTO) = 사용자 로그인 정보 확인
// 1이면 로그인 성공 -> 세션 생성 후 세션에 아이디, 이름 저장 -> index로 이동
// 로그인 실패 -> 로그인 페이지로 이동 후 오류 메세지 팝업
return 코드 추가
LoginDTO login = loginService.login(loginDTO);
if(login.getCount() == 1) {
// 세션 만들기
HttpSession session = request.getSession();
session.setAttribute("mid", id);
session.setAttribute("mname", login.getMname());
return "redirect:/index";
} else {
return "redirect:login?login=2000";
}
}
LoginController.java
잘못된 로그인은 로그인 창으로 이동하기 = 5번 시도하면 잠그기
-> DB에서 member 테이블에 mcount 생성하기 (모두 1로 변경)
// loginService.login(loginDTO) = 사용자 로그인 정보 확인
// 로그인 성공하면 세션에 아이디, 이름 저장
// loginService.mcountUp(loginDTO);를 통해 시도 횟수 0으로 초기화
// 로그인 실패하면 loginService.mcountUp(loginDTO);을 통해 시도 횟수 증가시킴
@PostMapping("/login")
public String login(HttpServletRequest request) {
String id = request.getParameter("id");
String pw = request.getParameter("pw");
LoginDTO loginDTO = new LoginDTO();
loginDTO.setId(id);
loginDTO.setPw(pw);
LoginDTO login = loginService.login(loginDTO);
if(login.getCount() == 1) {
// 세션 만들기
HttpSession session = request.getSession();
session.setAttribute("mid", id);
session.setAttribute("mname", login.getMname()); // mname은 DTO에 있으니까
// 해당 id의 mcount를 0으로 만들기
return "redirect:/index";
} else {
// 잘못된 로그인은 로그인 창으로 이동하기 = 5번 시도하면 잠그기.
// 해당 id의 mcount를 +1
loginService.mcountUp(loginDTO); // 로그인DTO에 다 있으니까
return "redirect:/login?login=2000"; // 로그인 성공,실패 어떤 상황이어도 인덱스로 넘어감
}
}
-> mcountUp 메소드 생성해주기 (서비스, DAO)
LoginService.java
return이 없음
public void mcountUp(LoginDTO loginDTO) {
loginDAO.mcountUp(loginDTO);
}
}
LoginDAO.java
return이 없음
public void mcountUp(LoginDTO loginDTO) {
sqlSession.update("login.mcountUp", loginDTO);
}
login-mapper.xml
login에 mcount 추가
: UPDATE member SET mcount=mcount+1 WHERE mid=#{id}
<select id="login" parameterType="loginDTO" resultType="loginDTO">
<![CDATA[
SELECT COUNT(*) as count, mname, mcount, mpw as pw
FROM member
WHERE mid=#{id} AND mgrade > 4
]]>
</select>
<!-- 2024-02-21 로그인마다 +1씩 -->
<update id="mcountUp" parameterType="loginDTO">
UPDATE member SET mcount=mcount+1 WHERE mid=#{id}
</update>
LoginController.java
@PostMapping("/login")
public String login(HttpServletRequest request) {
String id = request.getParameter("id");
String pw = request.getParameter("pw");
// System.out.println("id: "+id+" / pw : "+pw);
LoginDTO loginDTO = new LoginDTO();
loginDTO.setId(id);
loginDTO.setPw(pw);
LoginDTO login = loginService.login(loginDTO);
if(login.getCount() == 1 && login.getMcount() < 5) { // 로그인 성공 & 시도가 5번보다 작을 때
if(login.getPw().equals(loginDTO.getPw())) { // 비번 비교하기
// 세션 만들기
HttpSession session = request.getSession();
session.setAttribute("mid", id);
session.setAttribute("mname", login.getMname()); // mname은 DTO에 있으니까
// 해당 id의 mcount를 0으로 만들기
loginService.mcountReset(loginDTO);
return "redirect:/index";
} else {
// mcountUp
loginService.mcountUp(loginDTO);
return "redirect:/login?count="+login.getMcount();
}
} else {
// 잘못된 로그인은 로그인 창으로 이동하기 = 5번 시도하면 잠그기.
// 해당 id의 mcount를 +1
loginService.mcountUp(loginDTO); // 로그인DTO에 다 있으니까
return "redirect:/login?login=1004"; // 로그인 성공,실패 어떤 상황이어도 인덱스로 넘어감
}
}
-> mcountReset 생성 (서비스, DAO)
LoginService.java
public void mcountReset(LoginDTO loginDTO) {
loginDAO.mcountReset(loginDTO);
}
LoginDAO
public void mcountReset(LoginDTO loginDTO) {
sqlSession.update("login.mcountReset", loginDTO);
}
login.jsp
<body> 섹션 아래에
<c:if test="${param.count ne null }">
<script type="text/javascript">
let count = ${param.count};
if(count < 5){
Swal.fire("다시 생각해보자.", count+"번 시도했다!", "warning");
} else {
Swal.fire("로그인 여러번 시도 감지", "ID 잠금처리 실시", "warning");
}
</script>
</c:if>
login-mapper.xml
<update id="mcountReset" parameterType="loginDTO">
UPDATE member SET mcount=1 WHERE mid=#{id}
</update>
'개발 공부 Today I Learned' 카테고리의 다른 글
[국비 63일차 TIL] spring 조회수, 좋아요 버튼, myinfo, 이메일 인증 (0) | 2024.02.22 |
---|---|
[국비 62 xxxxxxx] 로그인 확인, 횟수 제한 (0) | 2024.02.22 |
[국비 61일차 TIL_2] 필수 파일의 대략적인 기본 로직 정리 (0) | 2024.02.20 |
[국비 61일차 TIL] spring 글 삭제, 페이징, 로그인 (1) | 2024.02.20 |
[국비 60일차 TIL] spring 글쓰기, 디테일, 댓글 modal (0) | 2024.02.19 |
댓글