9:15 경 학원 도착
<9:30 1교시>
get 방식으로 서버에 요청한 꼴.
페이지 전환이 일어나지 않는 똑같은 기능을 jquery의 기능을 이용해서 한 적도 있다.
빨강 화살표 : 페이지 로딩 시점에 실행 -> 그 결과 함수 두 개가 만들어짐
파랑 화살표 : 버튼을 눌렀을 때 실행 -> 그 결과 ~함수를 이용해서 요청했습니다가 콘솔창에 출력
초록 화살표 : 함수가 실행되었을 때 실행 -> 그 결과 object 를 콘솔창에 출력함
ajax는 비동기 방식으로 서버에 요청한다.
자바는 동기 처리를 하는데 새로운 스레드를 만들어서 여러 작업을 처리한다.
ajax 요청은 내가 컨텐츠를 요청한 서버에서만 요청을 받아들여서 응답하지, 다른 서버에서 그 요청을 응답해주지 않음.
동일 출처 정책 위반이라고, 이 정책이 어긋나면 CORS 위반이라고 언급됨.
CORS 푸는 방법
프로젝트 우클릭 > Java EE Tools > DeploymentDescriptor:Step07Final 누르면
WEB-INF에 web.xml이 생기는데, 여기에 쌤이 전달해준 내용을 복사 붙여넣기 했더니 쌤 컴퓨터에 대해 요청이 가능해짐.
<filter>
<filter-name>CorsFilter</filter-name>
<filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
<init-param>
<param-name>cors.allowed.origins</param-name>
<param-value>*</param-value> <!-- 모든 도메인 허용 -->
</init-param>
<init-param>
<param-name>cors.allowed.methods</param-name>
<param-value>GET,POST,PUT,DELETE,OPTIONS</param-value>
</init-param>
<init-param>
<param-name>cors.allowed.headers</param-name>
<param-value>*</param-value> <!-- 모든 헤더 허용 -->
</init-param>
<init-param>
<param-name>cors.exposed.headers</param-name>
<param-value>*</param-value>
</init-param>
<init-param>
<param-name>cors.support.credentials</param-name>
<param-value>false</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CorsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
그리고 이거 말고도 우리가 VS Code 에서 작성한 ajax.html에 대해서도 서버가 member.jsp 응답을 해줌.
<10:30 2교시>
member.jsp 스레드를 3초 지연시키고 나서 이 기능을 확인하기 위해 console.log를 추가 함
다시 post.jsp로 돌아옴.
검색기능이 추가되어 있고, 글을 눌렀을 때 이전글 다음글을 선택할 수 있는 기능이 추가됨.
이전글 다음글을 선택하는 기작.
lead 앞선것 lag 뒤쳐진것을 계산하여 select 할 수 있는 oracle의 함수가 있다.
SELECT empno, ename, sal,
LAG(ename, 1, '없음') OVER (ORDER BY empno ASC),
LEAD(ename, 1, '없음') OVER (ORDER BY empno ASC)
FROM emp
ORDER BY empno ASC;
이런식으로 작성하는데,
lag(ename, 1, '없음')은 ename이 1칸 뒤쳐진 것이고, 디폴트 값은 '없음'이란 의미.
lead(ename,1, '없음')은 ename이 1칸 앞선 것이고, 디폴트 값은 '없음'이란 의미.
동적 쿼리문(다이나믹하게 반응하는 DB 셀렉트문)의 필요성을 인지하고
일단은 어떻게 하드 코딩했는지 확인해보기 : StringBuilder를 사용해서 동적 쿼리문을 코딩.
<11:30 3교시>
새로운 PostDto, PostDao
PostDto
package test.post.dto;
public class PostDto {
private long num;
private String writer;
private String title;
private String content;
private int viewCount;
private String createdAt;
private String updatedAt;
//페이징 처리할 때 필요한 필드
private int startRowNum;
private int endRowNum;
private String condition;//검색 조건
private String keyword;//검색 키워드 : writer 또는 title, 또는 title+content
private long prevNum;//이전글 글번호
private long nextNum;//다음글 글번호
public long getNum() {
return num;
}
public void setNum(long num) {
this.num = num;
}
public String getWriter() {
return writer;
}
public void setWriter(String writer) {
this.writer = writer;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public int getViewCount() {
return viewCount;
}
public void setViewCount(int viewCount) {
this.viewCount = viewCount;
}
public String getCreatedAt() {
return createdAt;
}
public void setCreatedAt(String createdAt) {
this.createdAt = createdAt;
}
public String getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(String updatedAt) {
this.updatedAt = updatedAt;
}
public int getStartRowNum() {
return startRowNum;
}
public void setStartRowNum(int startRowNum) {
this.startRowNum = startRowNum;
}
public int getEndRowNum() {
return endRowNum;
}
public void setEndRowNum(int endRowNum) {
this.endRowNum = endRowNum;
}
public String getCondition() {
return condition;
}
public void setCondition(String condition) {
this.condition = condition;
}
public String getKeyword() {
return keyword;
}
public void setKeyword(String keyword) {
this.keyword = keyword;
}
public long getPrevNum() {
return prevNum;
}
public void setPrevNum(long prevNum) {
this.prevNum = prevNum;
}
public long getNextNum() {
return nextNum;
}
public void setNextNum(long nextNum) {
this.nextNum = nextNum;
}
}
PostDao(이건 오류 조금 있다고 하심)
package test.post.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import test.post.dto.PostDto;
import test.util.DbcpBean;
public class PostDao {
private static PostDao dao;
static {
dao = new PostDao();
}
private PostDao() {}
public static PostDao getInstance() {
return dao;
}
//글의 갯수를 리턴하는 메소드
public int getCount(PostDto dto) {
int count = 0;
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = new DbcpBean().getConn();
StringBuilder sql = new StringBuilder();
sql.append("SELECT COUNT(*) AS count FROM posts ");
// 검색 조건 추가
if (dto.getCondition() != null && dto.getKeyword() != null && !dto.getKeyword().isEmpty()) {
if (dto.getCondition().equals("title+content")) {
sql.append("WHERE title LIKE ? OR content LIKE ? ");
} else {
sql.append("WHERE ").append(dto.getCondition()).append(" LIKE ? ");
}
}
pstmt = conn.prepareStatement(sql.toString());
int paramIndex = 1;
if (dto.getCondition() != null && dto.getKeyword() != null && !dto.getKeyword().isEmpty()) {
if (dto.getCondition().equals("title+content")) {
pstmt.setString(paramIndex++, "%" + dto.getKeyword() + "%");
pstmt.setString(paramIndex++, "%" + dto.getKeyword() + "%");
} else {
pstmt.setString(paramIndex++, "%" + dto.getKeyword() + "%");
}
}
rs = pstmt.executeQuery();
if (rs.next()) {
count = rs.getInt("count");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (rs != null) rs.close();
if (pstmt != null) pstmt.close();
if (conn != null) conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return count;
}
//삭제한 글에 대한 참조를 삭제하는 메소드
public boolean deleteRef(int num) {
Connection conn = null;
PreparedStatement pstmt = null;
int rowCount = 0;
try {
conn = new DbcpBean().getConn();
//실행할 sql 문
String sql = """
DELETE FROM readed_data
WHERE num=?
""";
pstmt = conn.prepareStatement(sql);
//? 에 바인딩 할 내용이 있으면 바인딩
pstmt.setInt(1, num);
rowCount = pstmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (pstmt != null)
pstmt.close();
if (conn != null)
conn.close();
} catch (Exception e) {
}
}
return rowCount>0;
}
//글을 읽었다고 표시해주는 메소드
public boolean insertReaded(int num, String id) {
Connection conn = null;
PreparedStatement pstmt = null;
int rowCount = 0;
try {
conn = new DbcpBean().getConn();
//실행할 sql 문
String sql = """
INSERT INTO readed_data
(num, session_id)
VALUES(?, ?)
""";
pstmt = conn.prepareStatement(sql);
//? 에 바인딩 할 내용이 있으면 바인딩
pstmt.setInt(1, num);
pstmt.setString(2, id);
rowCount = pstmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (pstmt != null)
pstmt.close();
if (conn != null)
conn.close();
} catch (Exception e) {
}
}
return rowCount>0;
}
//이미 글을 읽었는지 여부를 리턴해주는 메소드
public boolean isReaded(int num, String id) {
boolean isReaded=false;
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = new DbcpBean().getConn();
//실행할 sql 문
String sql = """
SELECT *
FROM readed_data
WHERE num=? AND session_id=?
""";
pstmt = conn.prepareStatement(sql);
//? 에 바인딩할 내용이 있으면 여기서 한다.
pstmt.setInt(1, num);
pstmt.setString(2, id);
//query 문 수행하고 결과(ResultSet) 얻어내기
rs = pstmt.executeQuery();
//만일 select 된 row 가 존재 한다면 이미 읽은것이다
if (rs.next()) {
isReaded=true;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (rs != null)
rs.close();
if (pstmt != null)
pstmt.close();
if (conn != null)
conn.close(); //Connection 객체의 close() 메소드를 호출하면 Pool 에 반납된다.
} catch (Exception e) {
}
}
return isReaded;
}
//글 조회수를 증가 시키는 메소드
public boolean addViewCount(int num) {
Connection conn = null;
PreparedStatement pstmt = null;
int rowCount = 0;
try {
conn = new DbcpBean().getConn();
//실행할 sql 문
String sql = """
UPDATE posts
SET viewCount=viewCount+1
WHERE num=?
""";
pstmt = conn.prepareStatement(sql);
//? 에 바인딩 할 내용이 있으면 바인딩
pstmt.setInt(1, num);
rowCount = pstmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (pstmt != null)
pstmt.close();
if (conn != null)
conn.close();
} catch (Exception e) {
}
}
return rowCount>0;
}
public PostDto getData(PostDto dto) {
PostDto data = null;
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = new DbcpBean().getConn();
StringBuilder sql = new StringBuilder();
sql.append("SELECT * FROM ");
sql.append("(SELECT num, writer, title, content, viewCount, ");
sql.append("TO_CHAR(createdAt, 'YYYY.MM.DD HH24:MI') AS createdAt, ");
sql.append("LAG(num, 1, 0) OVER (ORDER BY num DESC) AS prevNum, ");
sql.append("LEAD(num, 1, 0) OVER (ORDER BY num DESC) AS nextNum ");
sql.append("FROM posts ");
// 검색 조건 및 키워드 추가
if (dto.getCondition() != null && dto.getKeyword() != null && !dto.getKeyword().isEmpty()) {
if (dto.getCondition().equals("title+content")) {
sql.append("WHERE title LIKE ? OR content LIKE ? ");
} else {
sql.append("WHERE ").append(dto.getCondition()).append(" LIKE ? ");
}
}
sql.append(") WHERE num = ?");
pstmt = conn.prepareStatement(sql.toString());
int paramIndex = 1;
if (dto.getCondition() != null && dto.getKeyword() != null && !dto.getKeyword().isEmpty()) {
if (dto.getCondition().equals("title+content")) {
pstmt.setString(paramIndex++, "%" + dto.getKeyword() + "%");
pstmt.setString(paramIndex++, "%" + dto.getKeyword() + "%");
} else {
pstmt.setString(paramIndex++, "%" + dto.getKeyword() + "%");
}
}
pstmt.setLong(paramIndex, dto.getNum());
rs = pstmt.executeQuery();
if (rs.next()) {
data = new PostDto();
data.setNum(rs.getInt("num"));
data.setWriter(rs.getString("writer"));
data.setTitle(rs.getString("title"));
data.setContent(rs.getString("content"));
data.setViewCount(rs.getInt("viewCount"));
data.setCreatedAt(rs.getString("createdAt"));
data.setPrevNum(rs.getInt("prevNum"));
data.setNextNum(rs.getInt("nextNum"));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (rs != null) rs.close();
if (pstmt != null) pstmt.close();
if (conn != null) conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return data;
}
public PostDto getData(long num) {
PostDto dto = null;
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = new DbcpBean().getConn();
String sql = """
SELECT writer, title, content, viewCount, createdAt, updatedAt
FROM posts
WHERE num=?
""";
pstmt = conn.prepareStatement(sql);
pstmt.setLong(1, num);
rs = pstmt.executeQuery();
if (rs.next()) {
dto = new PostDto();
dto.setNum(num);
dto.setWriter(rs.getString("writer"));
dto.setTitle(rs.getString("title"));
dto.setContent(rs.getString("content"));
dto.setViewCount(rs.getInt("viewCount"));
dto.setCreatedAt(rs.getString("createdAt"));
dto.setUpdatedAt(rs.getString("updatedAt"));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (rs != null) rs.close();
if (pstmt != null) pstmt.close();
if (conn != null) conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return dto;
}
public boolean insert(PostDto dto) {
Connection conn = null;
PreparedStatement pstmt = null;
int rowCount = 0;
try {
conn = new DbcpBean().getConn();
String sql = """
INSERT INTO posts (num, writer, title, content)
VALUES (posts_seq.NEXTVAL, ?, ?, ?)
""";
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, dto.getWriter());
pstmt.setString(2, dto.getTitle());
pstmt.setString(3, dto.getContent());
rowCount = pstmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (pstmt != null) pstmt.close();
if (conn != null) conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return rowCount > 0;
}
public boolean update(PostDto dto) {
Connection conn = null;
PreparedStatement pstmt = null;
int rowCount = 0;
try {
conn = new DbcpBean().getConn();
String sql = """
UPDATE posts
SET title=?, content=?, updatedAt=SYSDATE
WHERE num=?
""";
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, dto.getTitle());
pstmt.setString(2, dto.getContent());
pstmt.setLong(3, dto.getNum());
rowCount = pstmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (pstmt != null) pstmt.close();
if (conn != null) conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return rowCount > 0;
}
public boolean delete(long num) {
Connection conn = null;
PreparedStatement pstmt = null;
int rowCount = 0;
try {
conn = new DbcpBean().getConn();
String sql = """
DELETE FROM posts
WHERE num=?
""";
pstmt = conn.prepareStatement(sql);
pstmt.setLong(1, num);
rowCount = pstmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (pstmt != null) pstmt.close();
if (conn != null) conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return rowCount > 0;
}
public List<PostDto> getList(PostDto dto) {
List<PostDto> list = new ArrayList<>();
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = new DbcpBean().getConn();
StringBuilder sql = new StringBuilder();
sql.append("SELECT * FROM ");
sql.append("(SELECT result1.*, ROWNUM AS rnum FROM ");
sql.append("(SELECT num, writer, title, viewCount, TO_CHAR(createdAt, 'YYYY.MM.DD HH24:MI') AS createdAt FROM posts ");
if (dto.getCondition() != null && dto.getKeyword() != null && !dto.getKeyword().isEmpty()) {
if (dto.getCondition().equals("title+content")) {
sql.append("WHERE title LIKE ? OR content LIKE ? ");
} else {
sql.append("WHERE ").append(dto.getCondition()).append(" LIKE ? ");
}
}
sql.append("ORDER BY num DESC) result1) WHERE rnum BETWEEN ? AND ?");
pstmt = conn.prepareStatement(sql.toString());
int paramIndex = 1;
if (dto.getCondition() != null && dto.getKeyword() != null && !dto.getKeyword().isEmpty()) {
if (dto.getCondition().equals("title+content")) {
pstmt.setString(paramIndex++, "%" + dto.getKeyword() + "%");
pstmt.setString(paramIndex++, "%" + dto.getKeyword() + "%");
} else {
pstmt.setString(paramIndex++, "%" + dto.getKeyword() + "%");
}
}
pstmt.setInt(paramIndex++, dto.getStartRowNum());
pstmt.setInt(paramIndex, dto.getEndRowNum());
rs = pstmt.executeQuery();
while (rs.next()) {
PostDto tmp = new PostDto();
tmp.setNum(rs.getInt("num"));
tmp.setWriter(rs.getString("writer"));
tmp.setTitle(rs.getString("title"));
tmp.setViewCount(rs.getInt("viewCount"));
tmp.setCreatedAt(rs.getString("createdAt"));
list.add(tmp);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (rs != null) rs.close();
if (pstmt != null) pstmt.close();
if (conn != null) conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return list;
}
public List<PostDto> selectAll() {
List<PostDto> list = new ArrayList<>();
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = new DbcpBean().getConn();
String sql = """
SELECT num, writer, title, content, viewCount, createdAt, updatedAt
FROM posts
ORDER BY num DESC
""";
pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery();
while (rs.next()) {
PostDto dto = new PostDto();
dto.setNum(rs.getLong("num"));
dto.setWriter(rs.getString("writer"));
dto.setTitle(rs.getString("title"));
dto.setContent(rs.getString("content"));
dto.setViewCount(rs.getInt("viewCount"));
dto.setCreatedAt(rs.getString("createdAt"));
dto.setUpdatedAt(rs.getString("updatedAt"));
list.add(dto);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (rs != null) rs.close();
if (pstmt != null) pstmt.close();
if (conn != null) conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return list;
}
}
list.jsp도 다시 받음
<%@page import="java.util.List"%>
<%@page import="test.post.dto.PostDto"%>
<%@page import="test.post.dao.PostDao"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%
//검색조건이 있는지 읽어와 본다.
String condition=request.getParameter("condition");
String keyword=request.getParameter("keyword");
String findQuery=null;
//있다면 dto 에 해당 정보를 담는다.
PostDto dto=new PostDto();
if(condition != null){
dto.setCondition(condition);
dto.setKeyword(keyword);
findQuery="&condition="+condition+"&keyword="+keyword;
}
//한 페이지에 몇개씩 표시할 것인지
final int PAGE_ROW_COUNT=5;
//하단 페이지를 몇개씩 표시할 것인지
final int PAGE_DISPLAY_COUNT=5;
//보여줄 페이지의 번호를 일단 1이라고 초기값 지정
int pageNum=1;
//페이지 번호가 파라미터로 전달되는지 읽어와 본다.
String strPageNum=request.getParameter("pageNum");
//만일 페이지 번호가 파라미터로 넘어 온다면
if(strPageNum != null){
//숫자로 바꿔서 보여줄 페이지 번호로 지정한다.
pageNum=Integer.parseInt(strPageNum);
}
//보여줄 페이지의 시작 ROWNUM
int startRowNum=1+(pageNum-1)*PAGE_ROW_COUNT;
//보여줄 페이지의 끝 ROWNUM
int endRowNum=pageNum*PAGE_ROW_COUNT;
//하단 시작 페이지 번호
int startPageNum = 1 + ((pageNum-1)/PAGE_DISPLAY_COUNT)*PAGE_DISPLAY_COUNT;
//하단 끝 페이지 번호
int endPageNum=startPageNum+PAGE_DISPLAY_COUNT-1;
//전체 글의 갯수
int totalRow=PostDao.getInstance().getCount(dto);
//전체 페이지의 갯수 구하기
int totalPageCount=(int)Math.ceil(totalRow/(double)PAGE_ROW_COUNT);
//끝 페이지 번호가 이미 전체 페이지 갯수보다 크게 계산되었다면 잘못된 값이다.
if(endPageNum > totalPageCount){
endPageNum=totalPageCount; //보정해 준다.
}
// startRowNum 과 endRowNum 을 PostDto 객체에 담아서
dto.setStartRowNum(startRowNum);
dto.setEndRowNum(endRowNum);
//보여줄 페이지에 해당하는 글 목록을 얻어온다.
List<PostDto> list=PostDao.getInstance().getList(dto);
request.setAttribute("list", list);
request.setAttribute("startPageNum", startPageNum);
request.setAttribute("endPageNum", endPageNum);
request.setAttribute("totalPageCount", totalPageCount);
request.setAttribute("pageNum", pageNum);
request.setAttribute("totalRow", totalRow);
request.setAttribute("dto", dto);
request.setAttribute("findQuery", findQuery);
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>/post/list.jsp</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
</head>
<body>
<div class="container">
<a href="${pageContext.request.contextPath }/post/protected/new.jsp">새글 작성</a>
<h1>게시글 목록 입니다</h1>
<table class="table table-striped">
<thead class="table-dark">
<tr>
<th>번호</th>
<th>작성자</th>
<th>제목</th>
<th>조회수</th>
<th>등록일</th>
</tr>
</thead>
<tbody>
<c:forEach var="post" items="${list}">
<tr>
<td>${post.num}</td>
<td>${post.writer}</td>
<td>
<a href="view.jsp?num=${post.num}${findQuery}">${post.title}</a>
</td>
<td>${post.viewCount}</td>
<td>${post.createdAt}</td>
</tr>
</c:forEach>
</tbody>
</table>
<nav>
<ul class="pagination">
<!-- Prev 버튼 -->
<c:if test="${startPageNum ne 1}">
<li class="page-item">
<a class="page-link" href="list.jsp?pageNum=${startPageNum - 1}${findQuery}">Prev</a>
</li>
</c:if>
<!-- 페이지 번호 -->
<c:forEach begin="${startPageNum}" end="${endPageNum}" var="i">
<li class="page-item ${i == pageNum ? 'active' : ''}">
<a class="page-link" href="list.jsp?pageNum=${i}${findQuery}">${i}</a>
</li>
</c:forEach>
<!-- Next 버튼 -->
<c:if test="${endPageNum < totalPageCount}">
<li class="page-item">
<a class="page-link" href="list.jsp?pageNum=${endPageNum + 1}${findQuery}">Next</a>
</li>
</c:if>
</ul>
</nav>
<form action="${pageContext.request.contextPath }/post/list.jsp" method="get">
<label for="condition">검색조건</label>
<select name="condition" id="condition">
<option value="title+content" ${dto.condition eq 'title+content' ? 'selected' : ''}>제목 + 내용</option>
<option value="title" ${dto.condition eq 'title' ? 'selected' : ''}>제목</option>
<option value="writer" ${dto.condition eq 'writer' ? 'selected' : ''}>작성자</option>
</select>
<input type="text" name="keyword" placeholder="검색어..." value="${dto.keyword }"/>
<button class="btn btn-primary btn-sm" type="submit">검색</button>
<a class="btn btn-success btn-sm" href="${pageContext.request.contextPath }/post/list.jsp">새로고침</a>
</form>
<c:if test="${not empty dto.keyword }">
<p>
<strong>${totalRow }</strong> 개의 자료가 검색 되었습니다.
</p>
</c:if>
</div>
</body>
</html>
view.jsp도 다시 받음
<%@page import="test.user.dto.SessionDto"%>
<%@page import="test.post.dao.PostDao"%>
<%@page import="test.post.dto.PostDto"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%
//검색조건이 있는지 읽어와 본다.
String condition=request.getParameter("condition");
String keyword=request.getParameter("keyword");
String findQuery=null;
//있다면 dto 에 해당 정보를 담는다.
PostDto findDto=new PostDto();
if(condition != null){
//findDto=new PostDto();
findDto.setCondition(condition);
findDto.setKeyword(keyword);
findQuery="&condition="+condition+"&keyword="+keyword;
}
//자세히 보여줄 글의 번호를 읽어온다.
int num=Integer.parseInt(request.getParameter("num"));
findDto.setNum(num);
//DB 에서 해당 글의 정보를 얻어와서
PostDto dto=PostDao.getInstance().getData(findDto);
//세션 아이디를 읽어와서
String sessionId=session.getId();
//이미 읽었는지 여부를 얻어낸다
boolean isReaded=PostDao.getInstance().isReaded(num, sessionId);
if(!isReaded){
//글 조회수도 1 증가 시킨다
PostDao.getInstance().addViewCount(num);
//이미 읽었다고 표시한다.
PostDao.getInstance().insertReaded(num, sessionId);
}
request.setAttribute("dto", dto);
request.setAttribute("findDto", findDto);
request.setAttribute("findQuery", findQuery);
//응답한다
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>/post/view.jsp</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<style>
#contents {
margin-top: 20px;
padding: 20px;
background-color: #fefefe;
border-radius: 10px;
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
border: 1px solid #ddd;
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
#contents:hover {
transform: translateY(-5px);
box-shadow: 0 15px 30px rgba(0, 0, 0, 0.3);
}
#content{
width: 100%;
height: 300px;
}
</style>
</head>
<body>
<div class="container">
<c:if test="${dto.prevNum ne 0}">
<a href="view.jsp?num=${dto.prevNum}${findQuery}">이전글</a>
</c:if>
<c:if test="${dto.nextNum ne 0}">
<a href="view.jsp?num=${dto.nextNum}${findQuery}">다음글</a>
</c:if>
<c:if test="${not empty findDto.condition}">
<p>
<strong>${findDto.condition }</strong> 조건
<strong>${findDto.keyword }</strong>검색어로 검색된 내용 자세히보기
</p>
</c:if>
<h3>글 상세 보기</h3>
<table class="table table-bordered">
<tr>
<th>글번호</th>
<td>${dto.num }</td>
</tr>
<tr>
<th>작성자</th>
<td>${dto.writer }</td>
</tr>
<tr>
<th>제목</th>
<td>${dto.title }</td>
</tr>
<tr>
<th>조회수</th>
<td>${dto.viewCount }</td>
</tr>
<tr>
<th>작성일</th>
<td>${dto.createdAt }</td>
</tr>
<tr>
<th>수정일</th>
<td>${dto.updatedAt }</td>
</tr>
<tr>
<td colspan="2">
<div id="contents">${dto.content }</div>
</td>
</tr>
</table>
<%-- 만일 글 작성자가 로그인된 아이디와 같다면 수정, 삭제 링크를 제공한다. --%>
<c:if test="${dto.writer eq sessionDto.userName }">
<a class="btn btn-outline-success btn-sm" href="${pageContext.request.contextPath }/post/protected/edit.jsp?num=${dto.num }">수정</a>
<a class="btn btn-outline-danger btn-sm" href="javascript:" onclick="deleteConfirm()">삭제</a>
<script>
function deleteConfirm(){
const isDelete=confirm("이 글을 삭제 하겠습니까?");
if(isDelete){
//javascript 를 이용해서 페이지 이동 시키기
location.href="${pageContext.request.contextPath }/post/protected/delete.jsp?num=${dto.num}";
}
}
</script>
</c:if>
</div>
</body>
</html>
내페이지에서도 잘 입력됨.
수정된 Dao
package test.post.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import test.post.dto.PostDto;
import test.util.DbcpBean;
public class PostDao {
private static PostDao dao;
static {
dao = new PostDao();
}
private PostDao() {}
public static PostDao getInstance() {
return dao;
}
//글의 갯수를 리턴하는 메소드
public int getCount(PostDto dto) {
int count = 0;
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = new DbcpBean().getConn();
StringBuilder sql = new StringBuilder();
sql.append("SELECT COUNT(*) AS count FROM posts ");
// 검색 조건 추가
if (dto.getCondition() != null && dto.getKeyword() != null && !dto.getKeyword().isEmpty()) {
if (dto.getCondition().equals("title_content")) {
sql.append("WHERE title LIKE ? OR content LIKE ? ");
} else {
sql.append("WHERE ").append(dto.getCondition()).append(" LIKE ? ");
}
}
pstmt = conn.prepareStatement(sql.toString());
int paramIndex = 1;
if (dto.getCondition() != null && dto.getKeyword() != null && !dto.getKeyword().isEmpty()) {
if (dto.getCondition().equals("title_content")) {
pstmt.setString(paramIndex++, "%" + dto.getKeyword() + "%");
pstmt.setString(paramIndex++, "%" + dto.getKeyword() + "%");
} else {
pstmt.setString(paramIndex++, "%" + dto.getKeyword() + "%");
}
}
rs = pstmt.executeQuery();
if (rs.next()) {
count = rs.getInt("count");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (rs != null) rs.close();
if (pstmt != null) pstmt.close();
if (conn != null) conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return count;
}
//삭제한 글에 대한 참조를 삭제하는 메소드
public boolean deleteRef(int num) {
Connection conn = null;
PreparedStatement pstmt = null;
int rowCount = 0;
try {
conn = new DbcpBean().getConn();
//실행할 sql 문
String sql = """
DELETE FROM readed_data
WHERE num=?
""";
pstmt = conn.prepareStatement(sql);
//? 에 바인딩 할 내용이 있으면 바인딩
pstmt.setInt(1, num);
rowCount = pstmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (pstmt != null)
pstmt.close();
if (conn != null)
conn.close();
} catch (Exception e) {
}
}
return rowCount>0;
}
//글을 읽었다고 표시해주는 메소드
public boolean insertReaded(int num, String id) {
Connection conn = null;
PreparedStatement pstmt = null;
int rowCount = 0;
try {
conn = new DbcpBean().getConn();
//실행할 sql 문
String sql = """
INSERT INTO readed_data
(num, session_id)
VALUES(?, ?)
""";
pstmt = conn.prepareStatement(sql);
//? 에 바인딩 할 내용이 있으면 바인딩
pstmt.setInt(1, num);
pstmt.setString(2, id);
rowCount = pstmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (pstmt != null)
pstmt.close();
if (conn != null)
conn.close();
} catch (Exception e) {
}
}
return rowCount>0;
}
//이미 글을 읽었는지 여부를 리턴해주는 메소드
public boolean isReaded(int num, String id) {
boolean isReaded=false;
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = new DbcpBean().getConn();
//실행할 sql 문
String sql = """
SELECT *
FROM readed_data
WHERE num=? AND session_id=?
""";
pstmt = conn.prepareStatement(sql);
//? 에 바인딩할 내용이 있으면 여기서 한다.
pstmt.setInt(1, num);
pstmt.setString(2, id);
//query 문 수행하고 결과(ResultSet) 얻어내기
rs = pstmt.executeQuery();
//만일 select 된 row 가 존재 한다면 이미 읽은것이다
if (rs.next()) {
isReaded=true;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (rs != null)
rs.close();
if (pstmt != null)
pstmt.close();
if (conn != null)
conn.close(); //Connection 객체의 close() 메소드를 호출하면 Pool 에 반납된다.
} catch (Exception e) {
}
}
return isReaded;
}
//글 조회수를 증가 시키는 메소드
public boolean addViewCount(int num) {
Connection conn = null;
PreparedStatement pstmt = null;
int rowCount = 0;
try {
conn = new DbcpBean().getConn();
//실행할 sql 문
String sql = """
UPDATE posts
SET viewCount=viewCount+1
WHERE num=?
""";
pstmt = conn.prepareStatement(sql);
//? 에 바인딩 할 내용이 있으면 바인딩
pstmt.setInt(1, num);
rowCount = pstmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (pstmt != null)
pstmt.close();
if (conn != null)
conn.close();
} catch (Exception e) {
}
}
return rowCount>0;
}
public PostDto getData(PostDto dto) {
PostDto data = null;
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = new DbcpBean().getConn();
StringBuilder sql = new StringBuilder();
sql.append("SELECT * FROM ");
sql.append("(SELECT num, writer, title, content, viewCount, ");
sql.append("TO_CHAR(createdAt, 'YYYY.MM.DD HH24:MI') AS createdAt, ");
sql.append("LAG(num, 1, 0) OVER (ORDER BY num DESC) AS prevNum, ");
sql.append("LEAD(num, 1, 0) OVER (ORDER BY num DESC) AS nextNum ");
sql.append("FROM posts ");
// 검색 조건 및 키워드 추가
if (dto.getCondition() != null && dto.getKeyword() != null && !dto.getKeyword().isEmpty()) {
if (dto.getCondition().equals("title_content")) {
sql.append("WHERE title LIKE ? OR content LIKE ? ");
} else {
sql.append("WHERE ").append(dto.getCondition()).append(" LIKE ? ");
}
}
sql.append(") WHERE num = ?");
pstmt = conn.prepareStatement(sql.toString());
int paramIndex = 1;
if (dto.getCondition() != null && dto.getKeyword() != null && !dto.getKeyword().isEmpty()) {
if (dto.getCondition().equals("title_content")) {
pstmt.setString(paramIndex++, "%" + dto.getKeyword() + "%");
pstmt.setString(paramIndex++, "%" + dto.getKeyword() + "%");
} else {
pstmt.setString(paramIndex++, "%" + dto.getKeyword() + "%");
}
}
pstmt.setLong(paramIndex, dto.getNum());
rs = pstmt.executeQuery();
if (rs.next()) {
data = new PostDto();
data.setNum(rs.getInt("num"));
data.setWriter(rs.getString("writer"));
data.setTitle(rs.getString("title"));
data.setContent(rs.getString("content"));
data.setViewCount(rs.getInt("viewCount"));
data.setCreatedAt(rs.getString("createdAt"));
data.setPrevNum(rs.getInt("prevNum"));
data.setNextNum(rs.getInt("nextNum"));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (rs != null) rs.close();
if (pstmt != null) pstmt.close();
if (conn != null) conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return data;
}
public PostDto getData(long num) {
PostDto dto = null;
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = new DbcpBean().getConn();
String sql = """
SELECT writer, title, content, viewCount, createdAt, updatedAt
FROM posts
WHERE num=?
""";
pstmt = conn.prepareStatement(sql);
pstmt.setLong(1, num);
rs = pstmt.executeQuery();
if (rs.next()) {
dto = new PostDto();
dto.setNum(num);
dto.setWriter(rs.getString("writer"));
dto.setTitle(rs.getString("title"));
dto.setContent(rs.getString("content"));
dto.setViewCount(rs.getInt("viewCount"));
dto.setCreatedAt(rs.getString("createdAt"));
dto.setUpdatedAt(rs.getString("updatedAt"));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (rs != null) rs.close();
if (pstmt != null) pstmt.close();
if (conn != null) conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return dto;
}
public boolean insert(PostDto dto) {
Connection conn = null;
PreparedStatement pstmt = null;
int rowCount = 0;
try {
conn = new DbcpBean().getConn();
String sql = """
INSERT INTO posts (num, writer, title, content)
VALUES (posts_seq.NEXTVAL, ?, ?, ?)
""";
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, dto.getWriter());
pstmt.setString(2, dto.getTitle());
pstmt.setString(3, dto.getContent());
rowCount = pstmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (pstmt != null) pstmt.close();
if (conn != null) conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return rowCount > 0;
}
public boolean update(PostDto dto) {
Connection conn = null;
PreparedStatement pstmt = null;
int rowCount = 0;
try {
conn = new DbcpBean().getConn();
String sql = """
UPDATE posts
SET title=?, content=?, updatedAt=SYSDATE
WHERE num=?
""";
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, dto.getTitle());
pstmt.setString(2, dto.getContent());
pstmt.setLong(3, dto.getNum());
rowCount = pstmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (pstmt != null) pstmt.close();
if (conn != null) conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return rowCount > 0;
}
public boolean delete(long num) {
Connection conn = null;
PreparedStatement pstmt = null;
int rowCount = 0;
try {
conn = new DbcpBean().getConn();
String sql = """
DELETE FROM posts
WHERE num=?
""";
pstmt = conn.prepareStatement(sql);
pstmt.setLong(1, num);
rowCount = pstmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (pstmt != null) pstmt.close();
if (conn != null) conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return rowCount > 0;
}
public List<PostDto> getList(PostDto dto) {
List<PostDto> list = new ArrayList<>();
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = new DbcpBean().getConn();
StringBuilder sql = new StringBuilder();
sql.append("SELECT * FROM ");
sql.append("(SELECT result1.*, ROWNUM AS rnum FROM ");
sql.append("(SELECT num, writer, title, viewCount, TO_CHAR(createdAt, 'YYYY.MM.DD HH24:MI') AS createdAt FROM posts ");
if (dto.getCondition() != null && dto.getKeyword() != null && !dto.getKeyword().isEmpty()) {
if (dto.getCondition().equals("title_content")) {
sql.append("WHERE title LIKE ? OR content LIKE ? ");
} else {
sql.append("WHERE ").append(dto.getCondition()).append(" LIKE ? ");
}
}
sql.append("ORDER BY num DESC) result1) WHERE rnum BETWEEN ? AND ?");
pstmt = conn.prepareStatement(sql.toString());
int paramIndex = 1;
if (dto.getCondition() != null && dto.getKeyword() != null && !dto.getKeyword().isEmpty()) {
if (dto.getCondition().equals("title_content")) {
pstmt.setString(paramIndex++, "%" + dto.getKeyword() + "%");
pstmt.setString(paramIndex++, "%" + dto.getKeyword() + "%");
} else {
pstmt.setString(paramIndex++, "%" + dto.getKeyword() + "%");
}
}
pstmt.setInt(paramIndex++, dto.getStartRowNum());
pstmt.setInt(paramIndex, dto.getEndRowNum());
rs = pstmt.executeQuery();
while (rs.next()) {
PostDto tmp = new PostDto();
tmp.setNum(rs.getInt("num"));
tmp.setWriter(rs.getString("writer"));
tmp.setTitle(rs.getString("title"));
tmp.setViewCount(rs.getInt("viewCount"));
tmp.setCreatedAt(rs.getString("createdAt"));
list.add(tmp);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (rs != null) rs.close();
if (pstmt != null) pstmt.close();
if (conn != null) conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return list;
}
public List<PostDto> selectAll() {
List<PostDto> list = new ArrayList<>();
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = new DbcpBean().getConn();
String sql = """
SELECT num, writer, title, content, viewCount, createdAt, updatedAt
FROM posts
ORDER BY num DESC
""";
pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery();
while (rs.next()) {
PostDto dto = new PostDto();
dto.setNum(rs.getLong("num"));
dto.setWriter(rs.getString("writer"));
dto.setTitle(rs.getString("title"));
dto.setContent(rs.getString("content"));
dto.setViewCount(rs.getInt("viewCount"));
dto.setCreatedAt(rs.getString("createdAt"));
dto.setUpdatedAt(rs.getString("updatedAt"));
list.add(dto);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (rs != null) rs.close();
if (pstmt != null) pstmt.close();
if (conn != null) conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return list;
}
}
수정된 list.jsp
<%@page import="java.util.List"%>
<%@page import="test.post.dto.PostDto"%>
<%@page import="test.post.dao.PostDao"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%
//검색조건이 있는지 읽어와 본다.
String condition=request.getParameter("condition");
String keyword=request.getParameter("keyword");
String findQuery=null;
//있다면 dto 에 해당 정보를 담는다.
PostDto dto=new PostDto();
if(condition != null){
dto.setCondition(condition);
dto.setKeyword(keyword);
findQuery="&condition="+condition+"&keyword="+keyword;
}
//한 페이지에 몇개씩 표시할 것인지
final int PAGE_ROW_COUNT=5;
//하단 페이지를 몇개씩 표시할 것인지
final int PAGE_DISPLAY_COUNT=5;
//보여줄 페이지의 번호를 일단 1이라고 초기값 지정
int pageNum=1;
//페이지 번호가 파라미터로 전달되는지 읽어와 본다.
String strPageNum=request.getParameter("pageNum");
//만일 페이지 번호가 파라미터로 넘어 온다면
if(strPageNum != null){
//숫자로 바꿔서 보여줄 페이지 번호로 지정한다.
pageNum=Integer.parseInt(strPageNum);
}
//보여줄 페이지의 시작 ROWNUM
int startRowNum=1+(pageNum-1)*PAGE_ROW_COUNT;
//보여줄 페이지의 끝 ROWNUM
int endRowNum=pageNum*PAGE_ROW_COUNT;
//하단 시작 페이지 번호
int startPageNum = 1 + ((pageNum-1)/PAGE_DISPLAY_COUNT)*PAGE_DISPLAY_COUNT;
//하단 끝 페이지 번호
int endPageNum=startPageNum+PAGE_DISPLAY_COUNT-1;
//전체 글의 갯수
int totalRow=PostDao.getInstance().getCount(dto);
//전체 페이지의 갯수 구하기
int totalPageCount=(int)Math.ceil(totalRow/(double)PAGE_ROW_COUNT);
//끝 페이지 번호가 이미 전체 페이지 갯수보다 크게 계산되었다면 잘못된 값이다.
if(endPageNum > totalPageCount){
endPageNum=totalPageCount; //보정해 준다.
}
// startRowNum 과 endRowNum 을 PostDto 객체에 담아서
dto.setStartRowNum(startRowNum);
dto.setEndRowNum(endRowNum);
//보여줄 페이지에 해당하는 글 목록을 얻어온다.
List<PostDto> list=PostDao.getInstance().getList(dto);
request.setAttribute("list", list);
request.setAttribute("startPageNum", startPageNum);
request.setAttribute("endPageNum", endPageNum);
request.setAttribute("totalPageCount", totalPageCount);
request.setAttribute("pageNum", pageNum);
request.setAttribute("totalRow", totalRow);
request.setAttribute("dto", dto);
request.setAttribute("findQuery", findQuery);
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>/post/list.jsp</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
</head>
<body>
<div class="container">
<a href="${pageContext.request.contextPath }/post/protected/new.jsp">새글 작성</a>
<h1>게시글 목록 입니다</h1>
<table class="table table-striped">
<thead class="table-dark">
<tr>
<th>번호</th>
<th>작성자</th>
<th>제목</th>
<th>조회수</th>
<th>등록일</th>
</tr>
</thead>
<tbody>
<c:forEach var="post" items="${list}">
<tr>
<td>${post.num}</td>
<td>${post.writer}</td>
<td>
<a href="view.jsp?num=${post.num}${findQuery}">${post.title}</a>
</td>
<td>${post.viewCount}</td>
<td>${post.createdAt}</td>
</tr>
</c:forEach>
</tbody>
</table>
<nav>
<ul class="pagination">
<!-- Prev 버튼 -->
<c:if test="${startPageNum ne 1}">
<li class="page-item">
<a class="page-link" href="list.jsp?pageNum=${startPageNum - 1}${findQuery}">Prev</a>
</li>
</c:if>
<!-- 페이지 번호 -->
<c:forEach begin="${startPageNum}" end="${endPageNum}" var="i">
<li class="page-item ${i == pageNum ? 'active' : ''}">
<a class="page-link" href="list.jsp?pageNum=${i}${findQuery}">${i}</a>
</li>
</c:forEach>
<!-- Next 버튼 -->
<c:if test="${endPageNum < totalPageCount}">
<li class="page-item">
<a class="page-link" href="list.jsp?pageNum=${endPageNum + 1}${findQuery}">Next</a>
</li>
</c:if>
</ul>
</nav>
<form action="${pageContext.request.contextPath }/post/list.jsp" method="get">
<label for="condition">검색조건</label>
<select name="condition" id="condition">
<option value="title_content" ${dto.condition eq 'title_content' ? 'selected' : ''}>제목 + 내용</option>
<option value="title" ${dto.condition eq 'title' ? 'selected' : ''}>제목</option>
<option value="writer" ${dto.condition eq 'writer' ? 'selected' : ''}>작성자</option>
</select>
<input type="text" name="keyword" placeholder="검색어..." value="${dto.keyword }"/>
<button class="btn btn-primary btn-sm" type="submit">검색</button>
<a class="btn btn-success btn-sm" href="${pageContext.request.contextPath }/post/list.jsp">새로고침</a>
</form>
<c:if test="${not empty dto.keyword }">
<p>
<strong>${totalRow }</strong> 개의 자료가 검색 되었습니다.
</p>
</c:if>
</div>
</body>
</html>
<12:30 4교시>
검색 기능 익히기
오전에 한 내용 복습, 내일 퀴즈 준비, 프로젝트 페이지 업데이트
<14:30~ 5교시~8교시> 프로젝트 회의 및 준비
연휴 동안에 작업하고 프로젝트 깃허브 올렸던거 조금 수정해서 다시 커밋했는데, 일단 수정한걸로 백업하기.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<jsp:include page="/include/resource.jsp"></jsp:include>
<style>
.container {
text-align: center;
}
button {
width: 500px; /* 버튼의 고정된 너비 */
height: 80px; /* 버튼의 고정된 높이 */
font-size: 30px; /* 글자 크기 */
padding: 20px; /* 버튼 내부 여백 */
margin: 5px; /* 버튼 사이 간격 */
cursor: pointer; /* 마우스 커서 변경 */
border: none; /* 기본 버튼 테두리 없애기 */
background-color: grey; /* 버튼 배경 색 */
color: white; /* 버튼 텍스트 색 */
border-radius: 5px; /* 버튼 모서리 둥글게 */
transition: background-color 0.3s; /* 버튼 색 변경에 대한 애니메이션 */
}
button:hover {
background-color:black; /* 호버 시 색상 변화 */
}
</style>
</head>
<body>
<jsp:include page="/include/navbar.jsp"></jsp:include>
<div class="container">
<p>님 접속 중</p>
<p> 회사 이름: 관리자 이름 : 사원번호: </p>
</div>
<div class="container">
<p>
<button>
<a href="${pageContext.request.contextPath}/ceo_seong/myinfo_ceo.jsp" style="text-decoration: none; color: inherit;">나의 정보 보기</a>
</button>
</p>
</div>
<div class="container">
<p>
<button>
<a href="" style="text-decoration: none; color: inherit;">가입 승인</a>
</button>
</p>
</div>
<div class="container">
<p>
<button>
<a href="${pageContext.request.contextPath}/ceo_seong/employee/employeemanage.jsp" style="text-decoration: none; color: inherit;">직원 관리</a>
</button>
</p>
</div>
<div class="container">
<p>
<button>
<a href="" style="text-decoration: none; color: inherit;">퇴사자 관리</a>
</button>
</p>
</div>
<div class="container">
<p>
<button>
<a href="${pageContext.request.contextPath}/ceo_seong/sales/salesmanage.jsp" style="text-decoration: none; color: inherit;">매출 관리</a>
</button>
</p>
</div>
<jsp:include page="/include/footer.jsp" />
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%--
//session 영역에서 SessionDto 객체를 얻어낸다.
SessionDto sessionDto=(SessionDto)session.getAttribute("sessionDto");
//회원 번호를 이용해서 UserDto 정보 얻어내기
UserDto dto=UserDao.getInstance().getData(sessionDto.getNum());
//el 에서 dto 를 사용가능하게 request 영역에 담는다.
request.setAttribute("dto", dto);
//아래에서 가입정보를 응답한다
--%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>/ceo/myinfo_ceo.jsp</title>
<jsp:include page="/include/resource.jsp"></jsp:include>
<style>
table {
width: 100%; /* 화면 너비에 맞게 설정 */
border-spacing: 0;
border-collapse: collapse; /* 테이블의 경계를 합칩니다 */
margin-bottom: 50px;
}
th, td {
padding: 20px; /* 셀 안의 여백을 일정하게 */
text-align: left; /* 텍스트를 왼쪽 정렬 */
border-bottom: 1px solid #ddd; /* 셀에 테두리 추가 */
}
th {
background-color: #f4f4f4; /* 헤더 셀 배경색 */
text-align: right; /* 텍스트를 오른쪽 정렬 */
width: 25%; /* 각 열의 넓이를 고정 비율로 설정 */
}
td {
width: 75%; /* 데이터 셀의 넓이를 고정 비율로 설정 */
}
/* 페이지에 맞게 조정된 폰트 크기 */
h1 {
margin-bottom: 30px;
}
/* 링크 스타일 수정 */
a {
color: #007bff;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
</style>
</head>
<body>
<jsp:include page="/include/navbar.jsp"></jsp:include>
<div class="container">
<h1>개인정보</h1>
<table>
<tr>
<th>회사</th>
<td></td>
</tr>
<tr>
<th>관리자 사원번호</th>
<td></td>
</tr>
<tr>
<th>관리자 이름</th>
<td></td>
</tr>
<tr>
<th>직급</th>
<td></td>
</tr>
<tr>
<th>연락처</th>
<td>
<div class="accordion" id="accordionPanelStayOpenExample">
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button" type="button"
data-bs-toggle="collapse" data-bs-target="#panelsStayOpen-collapseOne"
aria-expanded="false" aria-controls="panelsStayOpen-collapseOne">
연락처 수정하기</button>
</h2>
<div id="panelsStayOpen-collapseOne" class="accordion-collapse collapse ">
<div class="accordion-body">
<form action="call-update.jsp" method="post">
<div class="mb-3">
<label for="call" class="form-label">새 연락처</label>
<input type="text" class="form-control" id="call" name="call" placeholder="새 연락처를 입력하세요" required>
</div>
<button type="submit" class="btn btn-primary">연락처 수정</button>
</form>
</div>
</div>
</div>
</div>
</td>
</tr>
<tr>
<th>비밀번호</th>
<td>
<div class="accordion" id="accordionPanelStayOpenExample">
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#panelsStayOpen-collapseTwo" aria-expanded="false" aria-controls="panelsStayOpen-collapseTwo">
비밀번호 수정하기</button>
</h2>
<div id="panelsStayOpen-collapseTwo" class="accordion-collapse collapse">
<div class="accordion-body">
<form action="pwd-update.jsp" method="post">
<div class="mb-3">
<label for="pwd" class="form-label">새 비밀번호</label>
<input type="password" class="form-control" id="pwd" name="pwd" placeholder="새 비밀번호를 입력하세요" required>
</div>
<div class="mb-3">
<label for="pwd" class="form-label">새 비밀번호 확인</label>
<input type="password" class="form-control" id="pwd2" name="pwd2" placeholder="새 비밀번호 확인" required>
</div>
<button type="submit" class="btn btn-primary">비밀번호 수정</button>
</form>
</div>
</div>
</div>
</div>
</td>
</tr>
</table>
</div>
<jsp:include page="/include/footer.jsp" />
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<jsp:include page="/include/resource.jsp"></jsp:include>
<style>
.sidebar-item {
text-align: center;
padding: 10px;
cursor: pointer;
}
.sidebar-item:hover {
background-color: lightgrey; /* 배경색 변경 */
color: white; /* 텍스트 색상 변경 */
}
/* 테이블 헤더 고정 */
th {
position: sticky;
top: 0;
background-color: #f1f1f1; /* 배경색 고정 */
z-index: 1; /* 헤더가 다른 콘텐츠 위에 오도록 설정 */
}
/* 테이블 스타일 */
table {
width: 100%;
border-collapse: collapse;
border: 1px solid #ccc;
}
th, td {
padding: 8px;
border: 1px solid #ddd;
}
</style>
</head>
<body>
<jsp:include page="/include/navbar.jsp"></jsp:include>
<div style="padding: 10px; text-align: center;">
<div>관리자 전용 네비바:
<a href="#">내 정보 보기</a> |
<a href="#">계정 승인</a> |
<a href="#">직원 현황</a> |
<a href="#">매출 관리</a> |
<a href="#">퇴사 관리</a>
</div>
<h1>관리자 메뉴</h1>
<br />
<h3>매출 현황</h3>
</div>
<div style="display: flex;">
<!-- 왼쪽 사이드바 -->
<div
style="height: 450px; width: 200px; padding: 10px; display: flex; flex-direction: column; gap: 10px; overflow-y: auto;">
<h3>지점 선택</h3>
<div class="sidebar-item">1호점</div>
<div class="sidebar-item">2호점</div>
<div class="sidebar-item">3호점</div>
<div class="sidebar-item">4호점</div>
<div class="sidebar-item">5호점</div>
</div>
<!-- 오른쪽 콘텐츠 영역 -->
<div
style="height: 450px; flex-grow: 1; padding: 10px; overflow-y: auto;">
<!-- 오른쪽 콘텐츠 영역에 기간 선택 UI 추가 -->
<div style="padding: 10px;">
<h3 style="display: inline-block; margin-right: 10px;">기간 선택</h3>
<form action="your_server_endpoint" method="get"
style="display: inline-block;">
<label for="startDate">시작 날짜:</label> <input type="date"
id="startDate" name="startDate" required> ~ <label
for="endDate">종료 날짜:</label> <input type="date" id="endDate"
name="endDate" required> <label for="today"
style="margin-right: 10px;"> <input type="checkbox"
id="today" onclick="setEndDate('today')">당일
</label> <label for="week" style="margin-right: 10px;"> <input
type="checkbox" id="week" onclick="setEndDate('week')">일주일
</label> <label for="month"> <input type="checkbox" id="month"
onclick="setEndDate('month')">1개월
</label>
<button type="submit">조회</button>
</form>
</div>
<table
style="width: 100%; border-collapse: collapse; border: 1px solid #ccc;">
<thead>
<tr>
<th style="padding: 8px; border: 1px solid #ddd;">매장</th>
<th style="padding: 8px; border: 1px solid #ddd;">점장</th>
<th style="padding: 8px; border: 1px solid #ddd;">연월일시</th>
<th style="padding: 8px; border: 1px solid #ddd;">원가</th>
<th style="padding: 8px; border: 1px solid #ddd;">가격</th>
<th style="padding: 8px; border: 1px solid #ddd;">수익</th>
</tr>
</thead>
<tbody>
<tr>
<td>1호점</td>
<td>홍길동</td>
<td>2025-01-01 10:00</td>
<td>50000</td>
<td>100000</td>
<td>50000</td>
</tr>
<tr>
<td>2호점</td>
<td>김철수</td>
<td>2025-01-01 11:00</td>
<td>60000</td>
<td>120000</td>
<td>60000</td>
</tr>
<tr>
<td>3호점</td>
<td>이영희</td>
<td>2025-01-02 09:30</td>
<td>40000</td>
<td>80000</td>
<td>40000</td>
</tr>
<tr>
<td>4호점</td>
<td>박민수</td>
<td>2025-01-02 10:45</td>
<td>70000</td>
<td>140000</td>
<td>70000</td>
</tr>
<tr>
<td>5호점</td>
<td>최지훈</td>
<td>2025-01-03 14:30</td>
<td>55000</td>
<td>110000</td>
<td>55000</td>
</tr>
<tr>
<td>1호점</td>
<td>홍길동</td>
<td>2025-01-03 15:00</td>
<td>45000</td>
<td>90000</td>
<td>45000</td>
</tr>
<tr>
<td>2호점</td>
<td>김철수</td>
<td>2025-01-04 10:15</td>
<td>50000</td>
<td>100000</td>
<td>50000</td>
</tr>
<tr>
<td>3호점</td>
<td>이영희</td>
<td>2025-01-04 11:30</td>
<td>62000</td>
<td>124000</td>
<td>62000</td>
</tr>
<tr>
<td>4호점</td>
<td>박민수</td>
<td>2025-01-05 09:00</td>
<td>50000</td>
<td>100000</td>
<td>50000</td>
</tr>
<tr>
<td>5호점</td>
<td>최지훈</td>
<td>2025-01-05 13:45</td>
<td>57000</td>
<td>114000</td>
<td>57000</td>
</tr>
<tr>
<td>1호점</td>
<td>홍길동</td>
<td>2025-01-06 08:30</td>
<td>48000</td>
<td>96000</td>
<td>48000</td>
</tr>
<tr>
<td>2호점</td>
<td>김철수</td>
<td>2025-01-06 12:00</td>
<td>59000</td>
<td>118000</td>
<td>59000</td>
</tr>
<tr>
<td>3호점</td>
<td>이영희</td>
<td>2025-01-07 16:30</td>
<td>51000</td>
<td>102000</td>
<td>51000</td>
</tr>
<tr>
<td></td>
</tr>
<!-- 추가적인 직원 목록을 여기에 삽입 -->
</tbody>
</table>
</div>
</div>
<jsp:include page="/include/footer.jsp" />
<script>
// 시작 날짜와 종료 날짜를 계산하는 함수
function updateEndDate() {
const startDate = document.getElementById("startDate").value;
const endDateInput = document.getElementById("endDate");
if (!startDate) return;
const start = new Date(startDate);
// 종료 날짜를 오늘로 기본 설정
let endDate = new Date(start);
// 종료 날짜 초기화
endDateInput.value = "";
// 자동으로 계산된 종료 날짜를 갱신
document.getElementById("today").checked = false;
document.getElementById("week").checked = false;
document.getElementById("month").checked = false;
}
// 체크박스를 클릭했을 때 종료 날짜를 설정하는 함수
function setEndDate(period) {
const startDate = document.getElementById("startDate").value;
const endDateInput = document.getElementById("endDate");
if (!startDate) return;
const start = new Date(startDate);
let endDate;
switch (period) {
case 'today':
// 당일은 시작 날짜와 동일
endDate = new Date(start);
break;
case 'week':
// 일주일 후 종료 날짜
endDate = new Date(start);
endDate.setDate(start.getDate() + 7);
break;
case 'month':
// 한 달 후 종료 날짜
endDate = new Date(start);
endDate.setMonth(start.getMonth() + 1);
break;
default:
return;
}
// 종료 날짜를 해당 날짜로 설정
endDateInput.value = endDate.toISOString().split('T')[0];
// 체크박스 상태 갱신
document.getElementById("today").checked = (period === 'today');
document.getElementById("week").checked = (period === 'week');
document.getElementById("month").checked = (period === 'month');
}
</script>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<jsp:include page="/include/resource.jsp"></jsp:include>
<style>
.sidebar-item {
text-align: center;
padding: 10px;
cursor: pointer;
}
.sidebar-item:hover {
background-color: lightgrey; /* 배경색 변경 */
color: white; /* 텍스트 색상 변경 */
}
/* 테이블 헤더 고정 */
th {
position: sticky;
top: 0;
background-color: #f1f1f1; /* 배경색 고정 */
z-index: 1; /* 헤더가 다른 콘텐츠 위에 오도록 설정 */
}
/* 테이블 스타일 */
table {
width: 100%;
border-collapse: collapse;
border: 1px solid #ccc;
}
th, td {
padding: 8px;
border: 1px solid #ddd;
}
</style>
</head>
<body>
<jsp:include page="/include/navbar.jsp"></jsp:include>
<div style="padding: 10px; text-align: center;">
<div>관리자 전용 네비바:
<a href="#">내 정보 보기</a> |
<a href="#">계정 승인</a> |
<a href="#">직원 현황</a> |
<a href="#">매출 관리</a> |
<a href="#">퇴사 관리</a>
</div>
<h1>관리자 메뉴</h1>
<br />
<h3>직원 현황</h3>
</div>
<div style="display: flex;">
<!-- 왼쪽 사이드바 -->
<div
style="height: 450px; width: 200px; padding: 10px; display: flex; flex-direction: column; gap: 10px; overflow-y: auto;">
<h3>지점 선택</h3>
<div class="sidebar-item">1호점</div>
<div class="sidebar-item">2호점</div>
<div class="sidebar-item">3호점</div>
<div class="sidebar-item">4호점</div>
<div class="sidebar-item">5호점</div>
<div class="sidebar-item add-store">추가하기</div>
</div>
<!-- 오른쪽 콘텐츠 영역 -->
<div
style="height: 450px; flex-grow: 1; padding: 10px; overflow-y: auto;">
<table
style="width: 100%; border-collapse: collapse; border: 1px solid #ccc;">
<thead>
<tr>
<th style="padding: 8px; border: 1px solid #ddd;">직원이름</th>
<th style="padding: 8px; border: 1px solid #ddd;">직급</th>
<th style="padding: 8px; border: 1px solid #ddd;">입사일자</th>
<th style="padding: 8px; border: 1px solid #ddd;">연락처</th>
<th style="padding: 8px; border: 1px solid #ddd;">이메일</th>
</tr>
</thead>
<tbody>
<tr>
<td>이영희</td>
<td>주임</td>
<td>2021-12-15</td>
<td>010-2345-6789</td>
<td>lee@example.com</td>
</tr>
<tr>
<td>박민수</td>
<td>사원</td>
<td>2020-08-22</td>
<td>010-3456-7890</td>
<td>park@example.com</td>
</tr>
<tr>
<tr>
<td>이영희</td>
<td>주임</td>
<td>2021-12-15</td>
<td>010-2345-6789</td>
<td>lee@example.com</td>
</tr>
<tr>
<td>박민수</td>
<td>사원</td>
<td>2020-08-22</td>
<td>010-3456-7890</td>
<td>park@example.com</td>
</tr>
<tr>
<tr>
<td>이영희</td>
<td>주임</td>
<td>2021-12-15</td>
<td>010-2345-6789</td>
<td>lee@example.com</td>
</tr>
<tr>
<td>박민수</td>
<td>사원</td>
<td>2020-08-22</td>
<td>010-3456-7890</td>
<td>park@example.com</td>
</tr>
<tr>
<tr>
<td>이영희</td>
<td>주임</td>
<td>2021-12-15</td>
<td>010-2345-6789</td>
<td>lee@example.com</td>
</tr>
<tr>
<td>박민수</td>
<td>사원</td>
<td>2020-08-22</td>
<td>010-3456-7890</td>
<td>park@example.com</td>
</tr>
<tr>
<tr>
<td>이영희</td>
<td>주임</td>
<td>2021-12-15</td>
<td>010-2345-6789</td>
<td>lee@example.com</td>
</tr>
<tr>
<td>박민수</td>
<td>사원</td>
<td>2020-08-22</td>
<td>010-3456-7890</td>
<td>park@example.com</td>
</tr>
<tr>
<td></td>
</tr>
<!-- 추가적인 직원 목록을 여기에 삽입 -->
</tbody>
</table>
</div>
</div>
<jsp:include page="/include/footer.jsp" />
</body>
</html>
기능 추가하기 시작
금요일(+주말)까지 기능 추가해서 다음주 월요일에는 프로토타입 버그잡기 시작하기로 함. 오늘 내가 한 코드 정리
Com1QuitDto.java
package test.dto;
public class Com1QuitDto {
private int comId;
private int storeNum;
private int empNo;
private String eName;
private String role;
private String eCall;
private String email;
private String hiredate;
private String contract;
private String quitdate;
private int startRowNum;
private int endRowNum;
private String condition;
private String keyword;
public int getStartRowNum() {
return startRowNum;
}
public void setStartRowNum(int startRowNum) {
this.startRowNum = startRowNum;
}
public int getEndRowNum() {
return endRowNum;
}
public void setEndRowNum(int endRowNum) {
this.endRowNum = endRowNum;
}
public String getCondition() {
return condition;
}
public void setCondition(String condition) {
this.condition = condition;
}
public String getKeyword() {
return keyword;
}
public void setKeyword(String keyword) {
this.keyword = keyword;
}
public int getComId() {
return comId;
}
public void setComId(int comId) {
this.comId = comId;
}
public int getStoreNum() {
return storeNum;
}
public void setStoreNum(int storeNum) {
this.storeNum = storeNum;
}
public int getEmpNo() {
return empNo;
}
public void setEmpNo(int empNo) {
this.empNo = empNo;
}
public String geteName() {
return eName;
}
public void seteName(String eName) {
this.eName = eName;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public String geteCall() {
return eCall;
}
public void seteCall(String eCall) {
this.eCall = eCall;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getHiredate() {
return hiredate;
}
public void setHiredate(String hiredate) {
this.hiredate = hiredate;
}
public String getContract() {
return contract;
}
public void setContract(String contract) {
this.contract = contract;
}
public String getQuitdate() {
return quitdate;
}
public void setQuitdate(String quitdate) {
this.quitdate = quitdate;
}
}
ceomain.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<jsp:include page="/include/resource.jsp"></jsp:include>
<style>
.container {
text-align: center;
}
button {
width: 500px; /* 버튼의 고정된 너비 */
height: 80px; /* 버튼의 고정된 높이 */
font-size: 30px; /* 글자 크기 */
padding: 20px; /* 버튼 내부 여백 */
margin: 5px; /* 버튼 사이 간격 */
cursor: pointer; /* 마우스 커서 변경 */
border: none; /* 기본 버튼 테두리 없애기 */
background-color: grey; /* 버튼 배경 색 */
color: white; /* 버튼 텍스트 색 */
border-radius: 5px; /* 버튼 모서리 둥글게 */
transition: background-color 0.3s; /* 버튼 색 변경에 대한 애니메이션 */
}
button:hover {
background-color:black; /* 호버 시 색상 변화 */
}
</style>
</head>
<body>
<jsp:include page="/include/navbar.jsp"></jsp:include>
<div class="container">
<p>님 접속 중</p>
<p> 회사 이름: 관리자 이름 : 사원번호: </p>
</div>
<div class="container">
<p>
<button>
<a href="${pageContext.request.contextPath}/ceo_seong/myinfo_ceo.jsp" style="text-decoration: none; color: inherit;">나의 정보 보기</a>
</button>
</p>
</div>
<div class="container">
<p>
<button>
<a href="${pageContext.request.contextPath }/ceo_eugene/accept-form.jsp" style="text-decoration: none; color: inherit;">가입 승인</a>
</button>
</p>
</div>
<div class="container">
<p>
<button>
<a href="${pageContext.request.contextPath}/ceo_seong/employee/employeemanage.jsp" style="text-decoration: none; color: inherit;">직원 관리</a>
</button>
</p>
</div>
<div class="container">
<p>
<button>
<a href="${pageContext.request.contextPath }/ceo_eugene/quit-form.jsp" style="text-decoration: none; color: inherit;">퇴사자 관리</a>
</button>
</p>
</div>
<div class="container">
<p>
<button>
<a href="${pageContext.request.contextPath}/ceo_seong/sales/salesmanage.jsp" style="text-decoration: none; color: inherit;">매출 관리</a>
</button>
</p>
</div>
<jsp:include page="/include/footer.jsp" />
</body>
</html>
myinf_ceo.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%--
//session 영역에서 SessionDto 객체를 얻어낸다.
SessionDto sessionDto=(SessionDto)session.getAttribute("sessionDto");
//회원 번호를 이용해서 UserDto 정보 얻어내기
UserDto dto=UserDao.getInstance().getData(sessionDto.getNum());
//el 에서 dto 를 사용가능하게 request 영역에 담는다.
request.setAttribute("dto", dto);
//아래에서 가입정보를 응답한다
--%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>/ceo/myinfo_ceo.jsp</title>
<jsp:include page="/include/resource.jsp"></jsp:include>
<style>
table {
width: 100%; /* 화면 너비에 맞게 설정 */
border-spacing: 0;
border-collapse: collapse; /* 테이블의 경계를 합칩니다 */
margin-bottom: 50px;
}
th, td {
padding: 20px; /* 셀 안의 여백을 일정하게 */
text-align: left; /* 텍스트를 왼쪽 정렬 */
border-bottom: 1px solid #ddd; /* 셀에 테두리 추가 */
}
th {
background-color: #f4f4f4; /* 헤더 셀 배경색 */
text-align: right; /* 텍스트를 오른쪽 정렬 */
width: 25%; /* 각 열의 넓이를 고정 비율로 설정 */
}
td {
width: 75%; /* 데이터 셀의 넓이를 고정 비율로 설정 */
}
/* 페이지에 맞게 조정된 폰트 크기 */
h1 {
margin-bottom: 30px;
}
/* 링크 스타일 수정 */
a {
color: #007bff;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
</style>
</head>
<body>
<jsp:include page="/include/navbar.jsp"></jsp:include>
<div class="container">
<h1>개인정보</h1>
<table>
<tr>
<th>회사</th>
<td></td>
</tr>
<tr>
<th>관리자 사원번호</th>
<td></td>
</tr>
<tr>
<th>관리자 이름</th>
<td></td>
</tr>
<tr>
<th>직급</th>
<td></td>
</tr>
<tr>
<th>연락처</th>
<td>
<div class="accordion" id="accordionPanelStayOpenExample">
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button" type="button"
data-bs-toggle="collapse" data-bs-target="#panelsStayOpen-collapseOne"
aria-expanded="false" aria-controls="panelsStayOpen-collapseOne">
연락처 수정하기</button>
</h2>
<div id="panelsStayOpen-collapseOne" class="accordion-collapse collapse ">
<div class="accordion-body">
<form action="call-update.jsp" method="post">
<div class="mb-3">
<label for="call" class="form-label">새 연락처</label>
<input type="text" class="form-control" id="call" name="call" placeholder="새 연락처를 입력하세요" required>
</div>
<button type="submit" class="btn btn-primary">연락처 수정</button>
</form>
</div>
</div>
</div>
</div>
</td>
</tr>
<tr>
<th>비밀번호</th>
<td>
<div class="accordion" id="accordionPanelStayOpenExample">
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#panelsStayOpen-collapseTwo" aria-expanded="false" aria-controls="panelsStayOpen-collapseTwo">
비밀번호 수정하기</button>
</h2>
<div id="panelsStayOpen-collapseTwo" class="accordion-collapse collapse">
<div class="accordion-body">
<form action="pwd-update.jsp" method="post">
<div class="mb-2">
<label class="form-label" for="password">기존 비밀번호</label>
<input class="form-control"
@input="onPwdInput"
:class="{'is-invalid': !isPwdValid && isPwdDirty, 'is-valid':isPwdValid}" type="password" name="password" id="password"/>
<div class="invalid-feedback">반드시 입력하세요</div>
</div>
<div class="mb-2">
<label class="form-label" for="newPwd">새 비밀번호</label>
<input class="form-control" type="password" name="newPassword" id="newPassword"
@input="onNewPwdInput"
v-model="newPassword"
:class="{'is-invalid': !isNewPwdValid && isNewPwdDirty, 'is-valid':isNewPwdValid}"/>
<small class="form-text">반드시 입력하고 아래의 확인란과 동일해야 합니다</small>
<div class="invalid-feedback">새 비밀번호를 확인하세요</div>
</div>
<div class="mb-2">
<label class="form-label" for="newPassword2">새 비밀번호 확인</label>
<input class="form-control" type="password" id="newPassword2"
@input="onNewPwdInput" v-model="newPassword2"/>
</div>
<button type="submit" class="btn btn-primary" :disabled="!isPwdValid || !isNewPwdValid">비밀번호 수정</button>
</form>
</div>
</div>
</div>
</div>
</td>
</tr>
</table>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
new Vue({
el:"#app",
data:{
isCallValid:false,
isCallDirty:false,
isPwdValid:false,
isNewPwdValid:false,
newPassword:"",
newPassword2:"",
isPwdDirty:false, //비밀번호 입력란에 한번이라도 입력했는지 여부
isNewPwdDirty:false //새비밀번호 입력한에 한번이라도 입력했는지 여부
},
methods:{
onCallInput(e){
//현재까지 입력한 비밀번호
const Call=e.target.value;
//공백이 아닌 한글자가 한번이상 반복 되어야 통과 되는 정규표현식
const reg_call=/^01([0|1|6|7|8|9])-?()[0-9]{3,4})-?([0-9]{4})$/;
if(reg_call.test(pwd)){
this.isCallValid=true;
}else{
this.isCallValid=false;
}
this.isCallDirty=true;
}
onPwdInput(e){
//현재까지 입력한 비밀번호
const password=e.target.value;
//공백이 아닌 한글자가 한번이상 반복 되어야 통과 되는 정규표현식
const reg_pwd=/[\S]+/;
if(reg_pwd.test(password)){
this.isPwdValid=true;
}else{
this.isPwdValid=false;
}
this.isPwdDirty=true;
},
onNewPwdInput(){
//공백이 아닌 글자를 하나이상 입력했는지 확인할 정규 표현식
const reg_pwd=/[\S]+/;
//만일 정규표현식도 통과하고 그리고 두개의 비밀번호가 같다면
if(reg_pwd.test(this.newPassword) && (this.newPassword === this.newPassword2)){
//새 비밀번호 유효성 여부를 true 로 변경
this.isNewPwdValid = true;
}else{//그렇지 않다면
//새 비밀번호 유효성 여부를 false 로 변경
this.isNewPwdValid = false;
}
this.isNewPwdDirty=true;
}
}
});
</script>
<jsp:include page="/include/footer.jsp" />
</body>
</html>
employeemanage.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<jsp:include page="/include/resource.jsp"></jsp:include>
<style>
.sidebar-item, .sidebar-item-add-store {
text-align: center;
padding: 10px;
cursor: pointer;
}
.sidebar-item:hover {
background-color: lightgrey; /* 배경색 변경 */
color: white; /* 텍스트 색상 변경 */
}
/* 테이블 헤더 고정 */
th {
position: sticky;
top: 0;
background-color: #f1f1f1; /* 배경색 고정 */
z-index: 1; /* 헤더가 다른 콘텐츠 위에 오도록 설정 */
}
/* 테이블 스타일 */
table {
width: 100%;
border-collapse: collapse;
border: 1px solid #ccc;
}
th, td {
padding: 8px;
border: 1px solid #ddd;
}
</style>
</head>
<body>
<jsp:include page="/include/navbar.jsp"></jsp:include>
<div style="padding: 10px; text-align: center;">
<div>관리자 전용 네비바:
<a href="#">내 정보 보기</a> |
<a href="#">계정 승인</a> |
<a href="#">직원 현황</a> |
<a href="#">매출 관리</a> |
<a href="#">퇴사 관리</a>
</div>
<h1>관리자 메뉴</h1>
<br />
<h3>직원 현황</h3>
</div>
<div style="display: flex;">
<!-- 왼쪽 사이드바 -->
<div style="height: 450px; width: 200px; padding: 10px; display: flex; flex-direction: column; gap: 10px; overflow-y: auto;">
<h3>지점 선택</h3>
<div class="sidebar-item-container">
<div id="sidebar-item">
</div>
<!-- "추가하기" 버튼 -->
<div class="sidebar-item-add-store">
<button class="btn btn-success btn-sm" onclick="addStore()">추가하기</button>
</div>
</div>
</div>
<!-- 오른쪽 콘텐츠 영역 -->
<div
style="height: 450px; flex-grow: 1; padding: 10px; overflow-y: auto;">
<table
style="width: 100%; border-collapse: collapse; border: 1px solid #ccc;">
<thead>
<tr>
<th style="padding: 8px; border: 1px solid #ddd;">직원이름</th>
<th style="padding: 8px; border: 1px solid #ddd;">직급</th>
<th style="padding: 8px; border: 1px solid #ddd;">입사일자</th>
<th style="padding: 8px; border: 1px solid #ddd;">연락처</th>
<th style="padding: 8px; border: 1px solid #ddd;">이메일</th>
</tr>
</thead>
<tbody>
<tr>
<td>이영희</td>
<td>주임</td>
<td>2021-12-15</td>
<td>010-2345-6789</td>
<td>lee@example.com</td>
</tr>
<tr>
<td>박민수</td>
<td>사원</td>
<td>2020-08-22</td>
<td>010-3456-7890</td>
<td>park@example.com</td>
</tr>
<tr>
<tr>
<td>이영희</td>
<td>주임</td>
<td>2021-12-15</td>
<td>010-2345-6789</td>
<td>lee@example.com</td>
</tr>
<tr>
<td></td>
</tr>
<!-- 추가적인 직원 목록을 여기에 삽입 -->
</tbody>
</table>
</div>
</div>
<jsp:include page="/include/footer.jsp" />
<script>
function addStore() {
// 새 지점 생성
let storeCount = document.querySelectorAll(".sidebar-item").length; // 현재 지점 갯수
let newStoreId = "store"+(storeCount+1); // 새 지점 ID (ex: store6)
// 새로운 지점 항목을 만들기 위한 HTML
let newStoreHTML = `
<div class="sidebar-item" id= " \${newStoreId} " >
\${newStoreId}호점
<button class="btn btn-danger btn-sm" onclick="deleteStore(\${newStoreId})">삭제</button>
</div>
`;
// 사이드바에 새 지점 추가
document.querySelector("#sidebar-item").insertAdjacentHTML("beforeend", newStoreHTML)
}
function deleteStore(storeName) {
// 사용자에게 삭제 확인을 요청
if (confirm(storeName + "을 삭제하시겠습니까?")) {
// 해당 지점 삭제 처리 (여기서는 단순히 화면에서 지점 항목을 삭제)
var storeElement = document.getElementById(storeName);
storeElement.remove();
}
}
</script>
</body>
</html>
salesmanage.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<jsp:include page="/include/resource.jsp"></jsp:include>
<style>
.container {
text-align: center;
}
button {
width: 500px; /* 버튼의 고정된 너비 */
height: 80px; /* 버튼의 고정된 높이 */
font-size: 30px; /* 글자 크기 */
padding: 20px; /* 버튼 내부 여백 */
margin: 5px; /* 버튼 사이 간격 */
cursor: pointer; /* 마우스 커서 변경 */
border: none; /* 기본 버튼 테두리 없애기 */
background-color: grey; /* 버튼 배경 색 */
color: white; /* 버튼 텍스트 색 */
border-radius: 5px; /* 버튼 모서리 둥글게 */
transition: background-color 0.3s; /* 버튼 색 변경에 대한 애니메이션 */
}
button:hover {
background-color:black; /* 호버 시 색상 변화 */
}
</style>
</head>
<body>
<jsp:include page="/include/navbar.jsp"></jsp:include>
<div class="container">
<p>님 접속 중</p>
<p> 회사 이름: 관리자 이름 : 사원번호: </p>
</div>
<div class="container">
<p>
<button>
<a href="${pageContext.request.contextPath}/ceo_seong/myinfo_ceo.jsp" style="text-decoration: none; color: inherit;">나의 정보 보기</a>
</button>
</p>
</div>
<div class="container">
<p>
<button>
<a href="${pageContext.request.contextPath }/ceo_eugene/accept-form.jsp" style="text-decoration: none; color: inherit;">가입 승인</a>
</button>
</p>
</div>
<div class="container">
<p>
<button>
<a href="${pageContext.request.contextPath}/ceo_seong/employee/employeemanage.jsp" style="text-decoration: none; color: inherit;">직원 관리</a>
</button>
</p>
</div>
<div class="container">
<p>
<button>
<a href="${pageContext.request.contextPath }/ceo_eugene/quit-form.jsp" style="text-decoration: none; color: inherit;">퇴사자 관리</a>
</button>
</p>
</div>
<div class="container">
<p>
<button>
<a href="${pageContext.request.contextPath}/ceo_seong/sales/salesmanage.jsp" style="text-decoration: none; color: inherit;">매출 관리</a>
</button>
</p>
</div>
<jsp:include page="/include/footer.jsp" />
</body>
</html>
'자바풀스택 과정 > 자바 풀 스택 : 수업내용정리' 카테고리의 다른 글
자바 풀 스택 2/5 하루 기록 048 (2) | 2025.02.05 |
---|---|
자바 풀 스택 2/4 하루 기록 047 (1) | 2025.02.04 |
자바 풀 스택 1/23 오후 기록 044-2 (1) | 2025.01.23 |
자바 풀 스택 1/23 오전 기록 044-1 (0) | 2025.01.23 |
자바 풀 스택 1/22 오후 기록 043-2 (1) | 2025.01.22 |