본문 바로가기
  • Welcome J-Kyu Tstory
PROJECT/게시판 프로젝트

게시판프로젝트[KyuBoard_ver_2.0]

by regularity 2022. 2. 20.
728x90

 

게시판프로젝트 제작영상

 

 

게시판프로젝트 파일 GitHub QR코드

게시판 프로젝트 GitHub 주소

 


 

1.

 

2.

3.

4.

5.

6.

7.

8.

9.

10.

11.

12.

13.

14.

15.

16.

17.

18.

19.

20.

21.

22.

[에러 추가 내용]

23.

24.

 

 


 

홈 화면

 

 

게시글 목록

 

 

게시글 조회

 

게시글 작성 

KyuBoard_ver2.0.zip
0.08MB

 

표지 이미지


홈 HTML 코드

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<html>
<head>
<title>KyuBoard</title>
</head>


<script>
	function loginCheck() {

		if (document.loginForm.userId.value == '') {
			alert('아이디를 입력하세요!!!');
			document.loginForm.userId.focus(); //로그인 폼의 id 이름을 가진 곳에 포커스를 맞춘다
			return false;
		}

		var Passwd = document.getElementById('userPass').value;
		if (Passwd == '') {
			alert('비밀번호를 입력하세요!!!');
			document.loginForm.userPass.focus();
			return false;
		}
		document.loginForm.action = '/member/login';
		document.loginForm.submit();

	}

	function press() {

		if (event.keyCode == 13) {
			loginCheck();
		}

	}
</script>



<Style>
/*@import url('http://fonts.googleapis.com/earlyaccess/nanumgothic.css');*/
@import
	url('https://cdn.pixabay.com/photo/2017/08/01/01/17/beach-2562563_960_720.jpg')
	;

@font-face {
	font-family: 'Noto Sans KR';
	font-style: normal;
	font-weight: 100;
	src: url(//fonts.gstatic.com/ea/notosanskr/v2/NotoSansKR-Thin.woff2)
		format('woff2'),
		url(//fonts.gstatic.com/ea/notosanskr/v2/NotoSansKR-Thin.woff)
		format('woff'),
		url(//fonts.gstatic.com/ea/notosanskr/v2/NotoSansKR-Thin.otf)
		format('opentype');
}

@font-face {
	font-family: 'Noto Sans KR';
	font-style: normal;
	font-weight: 300;
	src: url(//fonts.gstatic.com/ea/notosanskr/v2/NotoSansKR-Light.woff2)
		format('woff2'),
		url(//fonts.gstatic.com/ea/notosanskr/v2/NotoSansKR-Light.woff)
		format('woff'),
		url(//fonts.gstatic.com/ea/notosanskr/v2/NotoSansKR-Light.otf)
		format('opentype');
}

@font-face {
	font-family: 'Noto Sans KR';
	font-style: normal;
	font-weight: 400;
	src: url(//fonts.gstatic.com/ea/notosanskr/v2/NotoSansKR-Regular.woff2)
		format('woff2'),
		url(//fonts.gstatic.com/ea/notosanskr/v2/NotoSansKR-Regular.woff)
		format('woff'),
		url(//fonts.gstatic.com/ea/notosanskr/v2/NotoSansKR-Regular.otf)
		format('opentype');
}

@font-face {
	font-family: 'Noto Sans KR';
	font-style: normal;
	font-weight: 500;
	src: url(//fonts.gstatic.com/ea/notosanskr/v2/NotoSansKR-Medium.woff2)
		format('woff2'),
		url(//fonts.gstatic.com/ea/notosanskr/v2/NotoSansKR-Medium.woff)
		format('woff'),
		url(//fonts.gstatic.com/ea/notosanskr/v2/NotoSansKR-Medium.otf)
		format('opentype');
}

@font-face {
	font-family: 'Noto Sans KR';
	font-style: normal;
	font-weight: 700;
	src: url(//fonts.gstatic.com/ea/notosanskr/v2/NotoSansKR-Bold.woff2)
		format('woff2'),
		url(//fonts.gstatic.com/ea/notosanskr/v2/NotoSansKR-Bold.woff)
		format('woff'),
		url(//fonts.gstatic.com/ea/notosanskr/v2/NotoSansKR-Bold.otf)
		format('opentype');
}

@font-face {
	font-family: 'Noto Sans KR';
	font-style: normal;
	font-weight: 900;
	src: url(//fonts.gstatic.com/ea/notosanskr/v2/NotoSansKR-Black.woff2)
		format('woff2'),
		url(//fonts.gstatic.com/ea/notosanskr/v2/NotoSansKR-Black.woff)
		format('woff'),
		url(//fonts.gstatic.com/ea/notosanskr/v2/NotoSansKR-Black.otf)
		format('opentype');
}

body {
	margin: 0 auto;

	/* body, table, div, p, span{font-family:'Nanum Gothic';}*/
	body
	,
	table,
	div,
	p,
	span{font-family
	:
	'Noto Sans KR';
}

a {
	text-decoration: none;
	color: #333;
}

}
#con {
	width: 40%;
	height: 100vh;
	background-color: #4B4453;
	background-image:
		url('https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKyJ08%2FbtruokJIFda%2F8yF55aKLZid8roQuaHuHx1%2Fimg.png');
	/*url('https://cdn.pixabay.com/photo/2022/01/31/15/18/coffee-6984075_960_720.jpg');	*/
	background-position: left left; 1
	background-repeat: no-repeat;
	background-size: cover;
	margin: 0px 0px;
	padding: 0;
}

#login {
	border-radius: 60px;
	padding: 100px;
	text-align: center;
	position: absolute;
	top: 50%;
	left: 50%;
	transform: translate(-50%, -50%);
	opacity: 0.9;
}

#login_form {
	width: 150%;
	border-radius: 10px;
	padding: 30px;
	background: #fff;
	text-align: center;
	position: absolute;
	top: 50%;
	left: 50%;
	transform: translate(-50%, -50%);
}

#id {
	text-align: center;
	font-weight: 100px;
	font-size: 20px;
	color: #666
}

#pass {
	text-align: center;
	font-weight: 100px;
	font-size: 20px;
	color: #666
}

#userId {
	width: 300px;
	height: 30px;
	padding-left: 10px;
	background-color: #f4f4f4;
	border: none;
	border-radius: 1px;
	font-style: italic;
}

#userPass {
	width: 300px;
	height: 30px;
	padding-left: 10px;
	background-color: #f4f4f4;
	border: none;
	border-radius: 1px;
	font-style: italic;
}

.size {
	width: 300px;
	height: 30px;
	padding-left: 10px;
	background-color: #fff;
}

.btn {
	width: 310px;
	height: 40px;
	font-size: 15px;
	background-color: #0073C2;
	color: #fff;
	border: none;
	cursor: pointer;
	font-family: Noto Sans KR;
}

.join {
	width: 610px;
	height: 40px;
	font-size: 15px;
	background-color: none;
	border: none;
	cursor: pointer;
	font-family: Noto Sans KR;
}
</Style>


<body>
	<div id="con">
		<div id="login">
			<div id="login_form">


				<h1>Sign into KyuBoard</h1>
				<!--<hr>
				<P>The time on the server is ${serverTime}.</P>
			 
				<p>
					<a href="board/list">게시물 목록</a>
				</p>

				<p>
					<a href="board/write">게시물 작성</a>
				</p>  -->

				<!-- 내용 추가 (로그인) -->
				<c:if test="${member == null}">
					<form name="loginForm" method="post" class="loginForm"
						onsubmit="loginCheck()">
						<!-- 원본 <form role="form" method="post" autocomplete="off" action="/member/login">  -->
						<!-- 아이디 -->
						<p style="text-align: left; font-size: 15px; color: #666">
							<label for="userId" id="id">User ID</label>
						</p>
						<input type="text" placeholder="아이디 입력" id="userId" name="userId" />

						<!-- 비밀번호 -->
						<p style="text-align: left; font-size: 15px; color: #666">
							<label for="userPass" id="pass">Password</label>
						</p>
						<input type="password" placeholder="비밀번호 입력" id="userPass"
							name="userPass" />
						<p>
							<button type="submit" class="btn">로그인</button>
						</p>
						<hr>
						<p>
							<a href="/member/register" class="join"> 회원가입</a>
						</p>

					</form>
				</c:if>

				<c:if test="${msg == false}">
					<p style="color: #f00;">
						로그인에 실패했습니다. <br>아이디 또는 패스워드를 다시 <br>입력해주십시오.
					</p>
				</c:if>

				<c:if test="${member != null}">
					<p>${member.userName}님!환영합니다!</p>

					<p>
						<a href="/board/listPageSearch?num=1">게시물 목록</a>
					</p>

					<p>
						<a href="board/write">게시물 작성</a>
					</p>

					<a href="main/">메인페이지 이동</a>

					<a href="member/modify">회원정보 수정</a>, <a href="member/withdrawal">회원탈퇴</a>
					<br />
					<a href="member/logout">로그아웃</a>
				</c:if>


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


</body>
</html>

 

Controller 코드

package com.kyuboard.controller;

import java.util.List;

import javax.inject.Inject;
import javax.servlet.http.HttpSession;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import com.kyuboard.domain.KyuBoardVO;
import com.kyuboard.domain.KyuReplyVO;
import com.kyuboard.domain.Page;
import com.kyuboard.service.KyuBoardService;
import com.kyuboard.service.KyuReplyService;

@Controller
@RequestMapping("/board/*")
public class KyuBoardController {
private static final Logger logger  = LoggerFactory.getLogger(KyuBoardController.class);

	@Inject
	private KyuBoardService service;
	
	@Inject
	private KyuReplyService replyService;
	
	//게시물 목록
	@RequestMapping(value="/list", method=RequestMethod.GET)
	public void getList(Model model) throws Exception {
		
		List<KyuBoardVO> list = null;
		list = service.list();
		
		model.addAttribute("listJsp", list);
	}
	
	//게시물 작성(GET)
	@RequestMapping(value = "/write", method = RequestMethod.GET)
	public void getWrite(HttpSession session, Model model) throws Exception {
		logger.info("get write");
			
		
		Object loginInfo = session.getAttribute("member");
		
		if(loginInfo == null) {
			model.addAttribute("msg", false);
		}
		
	}
	
	//게시물 작성(POST)
	@RequestMapping(value = "/write", method = RequestMethod.POST)
	public String postWrite(KyuBoardVO vo) throws Exception {
		logger.info("post write");
		service.write(vo);
		
		return "redirect:/board/list";
	}
	
	//게시물 조회
	@RequestMapping(value = "/view", method = RequestMethod.GET)
	public void getView(@RequestParam("bno") int bno, Model model) throws Exception {
		
		KyuBoardVO vo = service.view(bno); 
		
		model.addAttribute("view", vo);
		
		
	//댓글 조회
	List<KyuReplyVO> reply = null;
	reply = replyService.list(bno);
	model.addAttribute("reply", reply);
		
	}
	
	//게시물 수정(GET)
	@RequestMapping(value = "/modify", method = RequestMethod.GET)
	public void getModify(@RequestParam("bno") int bno, Model model) throws Exception {
		
		KyuBoardVO vo = service.view(bno); 
		
		model.addAttribute("view", vo);
	}
	
	//게시물 수정(POST)
	@RequestMapping(value = "/modify", method = RequestMethod.POST)
	public String postModify(KyuBoardVO vo) throws Exception {
		
		service.modify(vo);
		
		return "redirect:/board/view?bno=" + vo.getBno();
	
	}
	
	//게시물 삭제
	@RequestMapping(value = "/delete", method = RequestMethod.GET)
	public String getDelete(@RequestParam("bno")int bno) throws Exception {
		
		service.delete(bno);
		
		return "redirect:/board/list";
		
	}
	
	
	//게시물 목록 + 페이징 추가
	@RequestMapping(value="/listPage", method=RequestMethod.GET)
	public void getListPage(Model model, @RequestParam("num") int num) throws Exception {
		
		Page page = new Page();
		
		page.setNum(num);
		page.setCount(service.count());
		
		List<KyuBoardVO> list = null;
		list = service.listPage(page.getDisplayPost(), page.getPostNum());
		
		model.addAttribute("list", list);
		/*
		model.addAttribute("pageNum", page.getPageNum());
		
		model.addAttribute("startPageNum", page.getStartPageNum());
		model.addAttribute("endPageNum", page.getEndPageNum());
		
		model.addAttribute("prev", page.getPrev());
		model.addAttribute("next", page.getPrev());
		 */
		
		model.addAttribute("page", page);
		model.addAttribute("select", num);
		
		
		/*
		//게시물 총 갯수
		int count = service.count();
		
		//한페이지에 출력할 게시물 갯수
		int postNum = 10;
		
		//하단 페이징 번호 ([게시물 총 갯수 / 한 페이지에 출력할 갯수]의 올림)
		int pageNum = (int)Math.ceil((double)count/postNum);
		
		//출력할 게시물
		int displayPost = (num - 1) * postNum;
		
		
		//한번에 표시할 페이징 번호의 갯수
		int pageNum_cnt = 10;
		
		//표시되는 페이지 번호 중 마지막 번호
		int endPageNum = (int)(Math.ceil((double)num / (double)pageNum_cnt) * pageNum_cnt);
		
		//표시되는 페이지 번호 중 첫번쨰 번호
		int startPageNum = endPageNum - (pageNum_cnt - 1);
		
		//마지막 번호 재계산   (why?->[ ((올림)(11 / 10)) * 10 => (올림)1.1 * 10 => 2 * 10 = 20 ] 이 됨 즉, 13 ~ 20까지 없어야할 페이지 번호가 출력
		int endPageNum_tmp = (int)(Math.ceil((double)count / (double)pageNum_cnt));		//count ->게시물 총 갯수
		
		if(endPageNum > endPageNum_tmp) {
			endPageNum = endPageNum_tmp;
		}
		
		boolean prev = startPageNum == 1 ? false : true;
		boolean next = endPageNum * pageNum_cnt >= count ? false : true;
		
		List<KyuBoardVO> list = null;
		list = service.listPage(displayPost, postNum);
		model.addAttribute("list", list);
		model.addAttribute("pageNum", pageNum);
		
		//시작 및 끝 번호
		model.addAttribute("startPageNum", startPageNum);
		model.addAttribute("endPageNum", endPageNum);
		
		// 이전 및 다음
		model.addAttribute("prev", prev);
		model.addAttribute("next", next);
		
		//현재 페이지
		model.addAttribute("select", num);
		*/
		
		//memo
		// 매개변수로 num 은 페이지 번호
		//1. 게시물의 총 갯수를 구하고
		//한 페이지당 출력할 게시물 갯수를 정하고(10개)
		//하단에 표시할 페이징 번호의 갯수를 구하고(소수점은 올림)
		//현재 페이지를 기준으로 10개의 데이터를 출력
		
	}
	
	// 게시물 목록 + 페이징 추가 + 검색
	@RequestMapping(value = "/listPageSearch", method = RequestMethod.GET)
	public void getListPageSearch(Model model, @RequestParam("num") int num, 
			@RequestParam(value = "searchType", required = false, defaultValue = "title") String searchType,
			@RequestParam(value = "keyword", required = false, defaultValue = "") String keyword
			) throws Exception {
		
		
		Page page = new Page();
		
		page.setNum(num);
		//page.setCount(service.count());  
		page.setCount(service.searchCount(searchType, keyword));
		
		//검색 타입과 검색어
		//page.setSearchTypeKeyword(searchType, keyword);
		page.setSearchType(searchType);
		page.setKeyword(keyword);
		
		List<KyuBoardVO> list = null; 
		//list = service.listPage(page.getDisplayPost(), page.getPostNum());
		list = service.listPageSearch(page.getDisplayPost(), page.getPostNum(), searchType, keyword);
		
		model.addAttribute("list", list);
		model.addAttribute("page", page);
		model.addAttribute("select", num);
		
		//model.addAttribute("searchType", searchType);
		//model.addAttribute("keyword", keyword);
	}
	
}

 

 

Mapper 코드

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.KyuBoard.mappers.board">

	<!-- 게시물 목록 -->
	<select id="list" resultType="com.kyuboard.domain.KyuBoardVO">
		 select
		 	 bno, title, content, writer, regDate, viewCnt
		 from tbl_board
	</select>

	<!-- 게시물 작성 -->
	<insert id="write" parameterType="com.kyuboard.domain.KyuBoardVO">
		 insert into
		 	tbl_board(title, content, writer)
		 		value(#{title}, #{content}, #{writer})
	</insert>

	<!-- 게시물 조회 -->
	<select id="view" parameterType="int" resultType="com.kyuboard.domain.KyuBoardVO">
		select
			bno, title, content, writer, regDate, viewCnt
		from
			tbl_board
		where
			bno = #{bno}
	</select>

	<!-- 게시물 수정 -->
	<update id="modify" parameterType="com.kyuboard.domain.KyuBoardVO">
		update tbl_board
			set
				title = #{title},
				content = #{content},
				writer = #{writer}
			where bno = #{bno}
 				
	</update>
	
	<!-- 게시물 삭제 -->
	<delete id="delete" parameterType="int">
		delete 
			from tbl_board
		where bno = #{bno}
		
	</delete>
	
	<!-- 게시물 총 갯수 -->
	<select id="count" resultType="int">
		select count(bno) from tbl_board
	</select>
	
	<!-- 게시물 목록 + 페이징-->
	<select id="listPage" parameterType="hashMap" resultType="com.kyuboard.domain.KyuBoardVO">
			select
				bno, title, writer, regDate, viewCnt
			from tbl_board
			
			
			order by bno desc
			limit #{displayPost}, #{postNum}
	</select>
	
	<!-- 게시물 목록 + 페이징 + 검색 -->
		<select id="listPageSearch" parameterType="hashMap" resultType="com.kyuboard.domain.KyuBoardVO">
		 select
		  bno, title, writer, regDate, viewCnt
		 from tbl_board
		 
		 <if test='searchType.equals("title")'>
		  WHERE title LIKE concat('%', #{keyword}, '%')
		 </if>
		 
		 <if test='searchType.equals("content")'>
		  WHERE content LIKE concat('%', #{keyword}, '%')
		 </if>
		 
		 <if test='searchType.equals("title_content")'>
		  WHERE title LIKE concat('%', #{keyword}, '%') 
		   or content LIKE concat('%', #{keyword}, '%')
		 </if>
		 
		 <if test='searchType.equals("writer")'>
		  WHERE writer LIKE concat('%', #{keyword}, '%')
		 </if>
		 
		 order by bno desc
		  limit #{displayPost}, #{postNum}
		</select> 
	
		<!-- 게시물 총 갯수 + 검색적용-->
		<select id="searchCount" parameterType="hashMap" resultType="int">
		SELECT COUNT(bno) FROM tbl_board
		
		 <if test='searchType.equals("title")'>
		  WHERE title LIKE concat('%', #{keyword}, '%')
		 </if>
		 
		 <if test='searchType.equals("content")'>
		  WHERE content LIKE concat('%', #{keyword}, '%')
		 </if>
		 
		 <if test='searchType.equals("title_content")'>
		  WHERE title LIKE concat('%', #{keyword}, '%') 
		   or content LIKE concat('%', #{keyword}, '%')
		 </if>
		 
		 <if test='searchType.equals("writer")'>
		  WHERE writer LIKE concat('%', #{keyword}, '%')
		 </if>
		
		
		</select>
		
		
</mapper>
728x90

댓글