웹개발 수업/Server
[Day +78 / Server]웹사이트(공지사항)
Chole Woo
2021. 10. 14. 20:12
211014 목
1. lib(라이브러리)에 jstl-1.2.jar 파일 넣어주기
why? jstl을 이 프로젝트에서도 쓰고 싶어서

2. menubar.jsp : 카테고리의 공지사항 클릭시 출력 용도
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" import="member.model.vo.Member"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
// session 객체에 담긴 loginUser 정보를 변수에 담아두기
Member loginUser = (Member)session.getAttribute("loginUser");
// *임포트 처리해줘야 위의 빨간줄 사라짐
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>menubar</title>
<!-- 구글 웹폰트 -->
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@700&display=swap" rel="stylesheet">
<!-- 외부 스타일 시트 -->
<link href="<%= request.getContextPath() %>/resources/css/menubar-style.css" rel="stylesheet">
<%-- session에 담긴 message 있을 경우 alert하는 script --%>
<% if(session.getAttribute("message") != null) {%>
<script>
alert(' <%= session.getAttribute("message") %>');
</script>
<%
session.removeAttribute("message");
} %>
</head>
<body>
<!-- page의 application의 contextPath -->
<c:set var="contextPath" value="${ pageContext.servletContext.contextPath }"
scope="application"/>
<!-- pageContext라고하는 내장객체로 부터.. contextPath값 요청 = getContextPath와 같음
application : 어느 페이지에서든 쓸 수 있음-->
<div class="wrapper">
<header id="header">
<!-- 로고 이미지를 클릭하면 첫 화면으로 -->
<a href="<%= request.getContextPath() %>">
<%-- request.getContextPath() => jsp --%>
<img class="logo" src="<%= request.getContextPath() %>/resources/images/logo.jpg">
</a>
<div class="btnArea">
<!-- 로긴 했을 떄와 안했을때의 차이를 두기 위한 조건식 세우기 -->
<% if(loginUser == null) { %>
<a href="<%= request.getContextPath() %>/memberJoin">회원가입</a>|
<a href="<%= request.getContextPath() %>/login">로그인</a>
<% } else { %>
<a href ="<%= request.getContextPath()%>/memberModify">정보수정</a>
<a href ="<%= request.getContextPath()%>/logout">로그아웃</a>
<!-- href방식은 무조건 get방식 -->
<% } %>
</div>
</header>
<nav id="nav">
<ul>
<li><a href="<%= request.getContextPath() %>">HOME</a></li>
<li><a href="${ contextPath }/notice/list">공지사항</a></li>
<li><a href="#">게시판</a></li>
<li><a href="#">사진게시판</a></li>
</ul>
</nav>
</div>
</body>
</html>

<ul> <li><a href="<%= request.getContextPath() %>">HOME</a></li> <li><a href="${ contextPath }/notice/list">공지사항</a></li> <li><a href="#">게시판</a></li> <li><a href="#">사진게시판</a></li> </ul> |
1) 경로 작성 방법 변경됨 jstl 사용 전에는 <%= request.getContextPath() %>">HOME 이런 식으로 경로를 써줬으나, jstl 사용 후에는 "${ contextPath }/notice/list"만 써줘도 됨 2) /notice/list로 NoticeServlet.java와 매핑 |
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> |
=> 상단에 어떤 접두사를 쓸건지와 그 접두사에 맞는 uri를 넣어줘야 실행됨 |
3. loginCheckFilter.java
package filter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import member.model.vo.Member;
/**
* Servlet Filter implementation class LoginCheckFilter
*/
@WebFilter("/*")
public class LoginCheckFilter implements Filter {
private List<String> permitList;
// 로그인이 안되어 있어도 볼 수 있는 리스트
private List<String> resourceList;
// css 하위..
// => init 메소드 안에 저 값들 초기화 하기
/**
* Default constructor.
*/
public LoginCheckFilter() {
// TODO Auto-generated constructor stub
}
/**
* @see Filter#destroy()
*/
public void destroy() {
// TODO Auto-generated method stub
}
/**
* @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest)request;
String uri = req.getRequestURI();
// 요청한 주소가 뭔지
// System.out.println(uri);
/* 로그인 없이 요청이 허가된 요청 값 리스트에 현재 요청이 포함되지 않았을 때 */
if(!permitList.contains(uri)) {
boolean isResourceFile = false;
/* 요청 안에 "/resources/" 라는 문자열을 포함하고 있는지 확인 */
for(String str : resourceList) {
if(uri.contains(str)) {
isResourceFile = true;
break;
}
}
/* 허가 리스트에도 없는 요청이면서 리소스 파일도 아닌 경우 ex) /jsp/memberModify*/
if(!isResourceFile) {
/*로그인 상태 확인*/
Member loginUser = (Member)req.getSession().getAttribute("loginUser");
if(loginUser == null) {
req.setAttribute("message", "올바르지 않은 요청입니다.");
req.getRequestDispatcher("/WEB-INF/views/common/errorpage.jsp").forward(request, response);
return;
}
}
}
// pass the request along the filter chain
chain.doFilter(request, response);
}
/**
* @see Filter#init(FilterConfig)
*/
public void init(FilterConfig fConfig) throws ServletException {
permitList = new ArrayList<String>();
permitList.add("/jsp/");
permitList.add("/jsp/login");
permitList.add("/jsp/memberJoin");
permitList.add("/jsp/notice/list");
resourceList = new ArrayList<String>();
resourceList.add("/resources/");
}
}
public void init(FilterConfig fConfig) throws ServletException { permitList = new ArrayList<String>(); permitList.add("/jsp/"); permitList.add("/jsp/login"); permitList.add("/jsp/memberJoin"); permitList.add("/jsp/notice/list"); resourceList = new ArrayList<String>(); resourceList.add("/resources/"); } |
-비회원 상태에서도 접근가능한 사이트 목록에 notice/list 추가해주기 |
4. NoticeListServlet.java
package notice.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 notice.model.vo.Notice;
import notice.model.service.NoticeService;
/**
* Servlet implementation class NoticeListServlet
*/
@WebServlet("/notice/list")
public class NoticeListServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public NoticeListServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 공지사항 목록 조회 요청(넘어온 데이터 없으므로 추출할 값 없는 상태)
List<Notice> noticeList = new NoticeService().selectList();
System.out.println(noticeList);
request.setAttribute("noticeList", noticeList);
request.getRequestDispatcher("/WEB-INF/views/notice/noticeListView.jsp").forward(request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
@WebServlet("/notice/list") |
-menubar.jsp와 연결 |
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 공지사항 목록 조회 요청(넘어온 데이터 없으므로 추출할 값 없는 상태) List<Notice> noticeList = new NoticeService().selectList(); System.out.println(noticeList); request.setAttribute("noticeList", noticeList); request.getRequestDispatcher("/WEB-INF/views/notice/noticeListView.jsp").forward(request, response); } |
1) href로 연결하면 보통 바로 doGet과 연결됨 2) List<Notice> noticeList = new NoticeService().selectList(); 만들어서 NoticeService와 연결 |
5. NoticeService.java
package notice.model.service;
import java.sql.Connection;
import java.util.List;
import static common.JDBCTemplate.*;
import notice.model.dao.NoticeDao;
import notice.model.vo.Notice;
public class NoticeService {
private NoticeDao noticeDao = new NoticeDao();
public List<Notice> selectList() {
Connection conn = getConnection();
List<Notice> noticeList = noticeDao.selectList(conn);
close(conn);
return noticeList;
}
}
public List<Notice> selectList() { Connection conn = getConnection(); List<Notice> noticeList = noticeDao.selectList(conn); close(conn); return noticeList; } |
-Servlet과 연결되는 List selectList()만들기 |
Connection conn = getConnection(); |
-이미 JDBCTemplate에 만들어 놓은 Conn객체 불러오기 ![]() *Connection의 역할 : DB와의 연결 |
private NoticeDao noticeDao = new NoticeDao(); |
-NoticeDao와 연결 |
List<Notice> noticeList = noticeDao.selectList(conn); |
-noticeList를 Dao와 연결해서 쿼리 정보 불러오기 |
6. NoticeDao.java
package notice.model.dao;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
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.InvalidPropertiesFormatException;
import java.util.List;
import java.util.Properties;
import static common.JDBCTemplate.close;
import notice.model.vo.Notice;
public class NoticeDao {
private Properties noticeQuery = new Properties();
// Properties : 맵 타입의 일종, 키와 밸류가 하나의 엔트리가 되..
// 키와 밸류가 모두 String 타입이다.
public NoticeDao() {
String fileName = NoticeDao.class.getResource("/sql/notice/notice-query.xml").getPath();
try {
noticeQuery.loadFromXML(new FileInputStream(fileName));
} catch (IOException e) {
e.printStackTrace();
}
// IO는 항상 exception이 발생할 위험이 있으므로 try/catch로 감싸준다
}
public List<Notice> selectList(Connection conn) {
PreparedStatement pstmt=null;
ResultSet rset = null;
List<Notice> noticeList = new ArrayList<>();
String sql= noticeQuery.getProperty("selectList");
try {
pstmt = conn.prepareStatement(sql);
rset = pstmt.executeQuery();
// return 값은 resultset..
while(rset.next()) {
noticeList.add(new Notice(rset.getInt("nno")
, rset.getString("ntitle")
, rset.getString("ncontent")
, rset.getString("nwriter")
, rset.getInt("ncount")
, rset.getDate("ndate")
, rset.getString("status")));
}
} catch (SQLException e) {
e.printStackTrace();
} finally{
close(rset);
close(pstmt);
} // 임포트로 close 오류 없애기
return noticeList;
}
}
String fileName = NoticeDao.class.getResource("/sql/notice/notice-query.xml").getPath(); |
-notice.query.xml에서 경로 얻어오기 |
7. notice-query.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM
"http://java.sun.com/dtd/properties.dtd">
<properties>
<entry key="selectList">
SELECT
NNO
, NTITLE
, NCONTENT
, NWRITER
, NCOUNT
, NDATE
, STATUS
FROM NOTICE
WHERE STATUS = 'Y'
ORDER BY NNO DESC
</entry>
</properties>
WHERE STATUS = 'Y' ORDER BY NNO DESC |
1) STATUS = 'Y' : 로그인이 되어있을 경우라는 의미 2) NNO DESC : NO를 내림차순으로 불러오겠다는 의미 |
8. NoticeDao.java
public List<Notice> selectList(Connection conn) { PreparedStatement pstmt=null; ResultSet rset = null; List<Notice> noticeList = new ArrayList<>(); String sql= noticeQuery.getProperty("selectList"); try { pstmt = conn.prepareStatement(sql); rset = pstmt.executeQuery(); // return 값은 resultset.. while(rset.next()) { noticeList.add(new Notice(rset.getInt("nno") , rset.getString("ntitle") , rset.getString("ncontent") , rset.getString("nwriter") , rset.getInt("ncount") , rset.getDate("ndate") , rset.getString("status"))); } } catch (SQLException e) { e.printStackTrace(); } finally{ close(rset); close(pstmt); } // 임포트로 close 오류 없애기 return noticeList; } |
-이 부분 잘 모르겠음 -결국 noticeList를 NoticeService로 반환 |
9. NoticeService.java
List<Notice> noticeList = noticeDao.selectList(conn); close(conn); return noticeList; |
-쓴 conn객체 닫아주기 -Dao에서 반환받은 noticeService를 NoticeListServlet으로 돌려줌 |
10. NoticeListServlet.java
System.out.println(noticeList); |
-돌려받은 noticeList값 출력해보기 [Notice [nno=1, ntitle=첫번째 공지사항입니다., ncontent=환영합니다., nwriter=admin, ncount=0, ndate=2021-10-06, status=Y]] |
request.setAttribute("noticeList", noticeList); request.getRequestDispatcher("/WEB-INF/views/notice/noticeListView.jsp").forward(request, response); |
-noticeList 위임해서 noticeListView에 보여주기 |
11. NoticeListView.jsp
<%@ 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>
<style>
.outer {
width: 800px;
margin: auto;
}
.wrap {
width: 780px;
margin: 100px auto;
}
ul, li {
margin: 0;
padding: 0;
}
.notice_title {
border-bottom: 1px solid #282A35;
}
.notice_list {
margin: 20px 30px;
min-height: 540px;
}
.notice_list>ul {
border-bottom: 1px solid #f3f5f7;
height: 50px;
line-height: 50px;
display: flex;
justify-content: space-around;
list-style: none;
}
.notice_list>ul.last {
border: 0;
}
.notice_list>ul>li {
text-align: center;
}
.notice_list .no {
width: 100px;
}
.notice_list .title {
width: 520px;
text-align: left;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.notice_list .date {
width: 100px;
}
.onmouseover {
background: #f3f5f7;
cursor: pointer;
}
.search_area {
text-align: center;
padding: 30px;
}
.search_area select {
width: 150px;
height: 30px;
border: 0px;
}
.input_area {
border: solid 1px #dadada;
padding: 10px 10px 14px 10px;
margin-right: 20px;
background: white;
}
.input_area input {
width: 250px;
height: 30px;
border: 0px;
}
.input_area input:focus, .search_area select:focus {
outline: none;
}
.search_area button {
width: 100px;
height: 35px;
border: 0px;
color: white;
background: #282A35;
margin: 5px;
cursor : pointer;
}
</style>
</head>
<body>
<jsp:include page="/WEB-INF/views/common/menubar.jsp" />
<div class="outer">
<div class="wrap">
<div class="notice_area">
<div class="notice_title">
<h1>공지사항</h1>
</div>
<!-- 출력 영역 -->
<div class="notice_list">
<c:forEach var="notice" items="${ noticeList }">
<ul class="notice_ul">
<li class="no">${ notice.nno }</li>
<li class="title">${ notice.ntitle }</li>
<li class="date">${ notice.ndate }</li>
</ul>
</c:forEach>
</div>
</div>
<div class="search_area">
<form method="get">
<select id="searchCondition" name="searchCondition">
<option value="title">제목</option>
<option value="content">내용</option>
</select> <span class="input_area"> <input type="search"
name="searchValue">
</span>
<button type="submit">검색하기</button>
</form>
</div>
</div>
</div>
</body>
</html>
<div class="notice_list"> <c:forEach var="notice" items="${ noticeList }"> <ul class="notice_ul"> <li class="no">${ notice.nno }</li> <li class="title">${ notice.ntitle }</li> <li class="date">${ notice.ndate }</li> </ul> </c:forEach> |
-noticeList로 받아온 정보값 출력하기 |
