20230705 _[23일차]_01. 게시판 만들기 이어서
jul03/src/main/webapp/board.jsp
[board.jsp]
<div id = "tableDiv">
<table>
<tr>
<th>번호</th>
<th>제목</th>
<th>글쓴이</th>
<th>조회수</th>
<th>쓴날짜</th>
</tr>
<%
for (int i = 0; i < list.size(); i++) {
%>
<tr>
<td class="td1"><%=list.get(i).getBno() %></td>
<td class="title">
<a href="./detail?bno=<%=list.get(i).getBno() %>"><%=list.get(i).getBtitle()%></a>
</td>
<td class="td1"><%=list.get(i).getBwrite() %></td>
<td class="td1"><%=list.get(i).getBlike() %></td>
<td class="td2"><%=list.get(i).getBdate() %></td>
</tr>
<%
}
%>
</table>
</div>
위 테이블에 대해 hover 스타일 적용
(순서대로)
a 링크 => 글자색_검정 적용
a 링크 => (마우스 올리면) 배경_회색 & 글자색_흰색 적용
tr (한줄) => 배경_회색 & 글자색_흰색 적용
(겹치는 스타일은 콤마(,)로 한번에 적용가능)
=> hover 스타일을 tr & a 링크 둘다 적용시키기 위해
tr에 a태그가 포함되어 있지만 태그마다 적용 가능한 스타일이 다르기 때문에 별도로 지정해줘야 함
tr은 영역을 나타내는 거라 color 스타일 적용이 불가능한 것처럼
a태그에 적용이 가능한 스타일을 따로 지정해줘야함.
적용가능/불가능한 스타일을 알려주거나 잡아내는건 따로 없는듯 ㅠㅠ
.title a : hover {~~} : title클래스의 a태그에 호버스타일 적용
tr:hover, tr:hover a {~~} : tr에 호버스타일 적용 + tr 내부의 a태그에도 적용.
http://localhost:8080/jul03/board.jsp
위의 주소( ~~board.jsp )로 들어가면 오류* (리스트가 없어서!_서블릿 통해서 jsp에 접근해야함)
mariadb-java-client-3.1.4.jar 자료파일 => src/webapp/WEB-INF/lib 폴더에 넣기
이제 디비랑 연결해주자
(패키지 & 클래스 생성)
package com.poseidon.db
[ DBconnection ]
package com.poseidon.db;
import java.sql.Connection;
// static 싱글턴
public class DBconnection {
// getConn
public Connection getconConnection() {
Connection conn = null;
// "jdbc:mariadb://localhost:3306/choongang"
// "jdbc:mariadb://172.30.1.19:3306/choongang"
String url = "jdbc:mariadb://127.0.0.1:3306/choongang";
String id = "PHYHO";
String pw = "0228";
return conn;
}
}
getconConnection() => get~~ 가져오겠다는 의미, Connection을 가져오겠다
String url = "jdbc:mariadb://localhost";
localhost 또는 '내 ip주소' => 내컴퓨터에 접속
package com.poseidon.db;
import java.sql.Connection;
import java.sql.DriverManager;
// static 싱글턴
public class DBconnection {
// getConn
public Connection getconConnection() {
Connection conn = null;
// "jdbc:mariadb://localhost:3306/choongang"
// "jdbc:mariadb://172.30.1.19:3306/choongang"
String url = "jdbc:mariadb://127.0.0.1:3306/choongang";
String id = "PHYHO";
String pw = "0228";
try {
Class.forName("org.mariadb.jdbc.Driver"); // 아까 넣은 파일 가져옴
conn = DriverManager.getConnection(url, id, pw); // get~ 으로 가져오겠다
} catch (Exception e) {
e.printStackTrace();
}
return conn;
}
}
(싱글턴 생성자 & 반환메소드 생성)
DBconnection dbConn 반환
package com.poseidon.db;
import java.sql.Connection;
import java.sql.DriverManager;
// static 싱글턴
public class DBconnection {
private static DBconnection dbConn = null;
// 생성자
private DBconnection() {}
// 싱글턴 인스턴스를 반환하는 메소드
public synchronized static DBconnection getInstance() {
if(dbConn == null) {
dbConn = new DBconnection();
}
return dbConn;
}
// getConn
public Connection getconConnection() {
Connection conn = null;
// "jdbc:mariadb://localhost:3306/choongang"
// "jdbc:mariadb://172.30.1.19:3306/choongang"
String url = "jdbc:mariadb://127.0.0.1:3306/choongang";
String id = "PHYHO";
String pw = "0228";
try {
Class.forName("org.mariadb.jdbc.Driver");
conn = DriverManager.getConnection(url, id, pw);
} catch (Exception e) {
e.printStackTrace();
}
return conn;
}
}
(dao 패키지 & 클래스 생성) _ 게시판의 글읽기, 쓰기, 지우기, 수정하기를 담당
package com.poseidon.dao
[ BoardDAO ]
package com.poseidon.dao;
// 게시판의 글읽기, 쓰기, 지우기, 수정하기를 담당하는 DAO
// MVC패턴
public class BoardDAO {
// 게시판 글 읽어오는 메소드
}
* MVC ( Model-View-Controller )
https://cocoon1787.tistory.com/733
[개발상식] MVC 패턴이란? (Model-View-Controller)
🚀 이번 포스팅은 개발자 면접에서 자주 나오는 질문 중의 하나인 "MVC패턴"에 대한 내용입니다. MVC패턴의 의미와 사용해야 하는 이유, 사용 예시 등등에 대해 알아보겠습니다. 💡 MVC 패턴이란?
cocoon1787.tistory.com
AQueryTool
AQueryTool은 웹 기반 ERD 툴 + SQL 자동 생성 프로그램입니다.
aquerytool.com
( 테이블만들기 )
* bdate의 데이터타입은 DATETIME or DATE
* Null 허용여부는 다 해제
테이블이름 지정해줘야 생성가능
( 테이블 생성 & 코드복사 )
코드 복사해서 HeidiSQL에 쿼리창에 붙여넣기
코드만큼만 블럭처리 ** 해서 실행한 후에 새로고침 하면 board 생성
(테스트 데이터 생성) _ 100개 생성
( 생성된 데이터 _100개)
복사해서 HeidiSQL로 가져가서 쿼리창에 붙여넣기
*******블럭처리해서 부분실행**********
새로고침하면 board 내부에 데이터 들어간거 확인가능
( board 내부 데이터 갯수 확인 )
package com.poseidon.dto;
[ BoardDTO.java ] 에 이미 변수선언 해뒀으니
private int bno, blike;
private String btitle, bwrite, bdate;
[ BoardDAO ] 에 List (boardList) 생성 _ 여기에 담아서 불러올거
package com.poseidon.dao;
import java.util.List;
import com.poseidon.dto.BoardDTO;
public class BoardDAO {
// 게시판 글 읽어오는 메소드
public List<BoardDTO> boardList(){
return ;
}
}
( 필요한 인스턴스 및 변수들 생성 )
package com.poseidon.dao;
// 게시판의 글읽기, 쓰기, 지우기, 수정하기를 담당하는 DAO
// MVC패턴
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import com.poseidon.dto.BoardDTO;
public class BoardDAO {
// 게시판 글 읽어오는 메소드
public List<BoardDTO> boardList(){
List<BoardDTO> list = new ArrayList<BoardDTO>();
String sql = "";
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
return ;
}
}
conn = DBconnection.getInstance().getconConnection();
인스턴스 꺼내오기 => 가져와서 getcon~ 하겠다
package com.poseidon.dao;
// 게시판의 글읽기, 쓰기, 지우기, 수정하기를 담당하는 DAO
// MVC패턴
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import com.poseidon.db.DBconnection;
import com.poseidon.dto.BoardDTO;
public class BoardDAO {
// 게시판 글 읽어오는 메소드
public List<BoardDTO> boardList(){
List<BoardDTO> list = new ArrayList<BoardDTO>();
String sql = "SELECT * FROM board";
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
conn = DBconnection.getInstance().getconConnection();
try {
stmt = conn.createStatement();
rs = stmt.executeQuery(sql); // *
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
}
* execute = 실행 = 참/거짓
* executeUpdate = 실행 = 영향받은 행 1, 2, 0
* executeQuery = select = 결과 반환
명령문 실행해서 가져온 결과들을 list에 담으려면
=> while 내부에 dto ( BoardDTO ) 생성
=> dto에 데이터 값들 넣어주기 (getter/setter 이용해서 값 가져와 넣어줌)
conn = DBconnection.getInstance().getconConnection();
try {
stmt = conn.createStatement();
rs = stmt.executeQuery(sql);
while(rs.next()) {
BoardDTO dto = new BoardDTO();
dto.setBno(rs.getInt("bno"));
dto.setBtitle(rs.getString("btitle"));
dto.setBwrite(rs.getString("bwrite"));
dto.setBdate(rs.getString("bdate"));
dto.setBlike(rs.getInt("blike"));
list.add(dto); // 리스트에 추가
}
} catch (SQLException e) {
e.printStackTrace();
}
while( rs.next () ) { ~~ } => rs 내부에 가져올 값이 있으면 참 / 없으면 거짓
finally 로 닫아줄건데!!!!
..........
catch (SQLException e) {
e.printStackTrace();
} finally {
try {
rs.close();
stmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
좀 더 확실하게 하려면 데이터 다 가져왔을 때 닫아주기
..........
catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if(rs != null) {rs.close();}
if(stmt != null) {stmt.close();}
if(conn != null) {conn.close();}
} catch (SQLException e) {
e.printStackTrace();
}
}
(최종본)
package com.poseidon.dao;
// 게시판의 글읽기, 쓰기, 지우기, 수정하기를 담당하는 DAO
// MVC패턴
import java.awt.Taskbar.State;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import com.poseidon.db.DBconnection;
import com.poseidon.dto.BoardDTO;
public class BoardDAO {
// 게시판 글 읽어오는 메소드
public List<BoardDTO> boardList(){
List<BoardDTO> list = new ArrayList<BoardDTO>();
String sql = "SELECT * FROM boardview";
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
conn = DBconnection.getInstance().getconConnection();
try {
stmt = conn.createStatement();
rs = stmt.executeQuery(sql);
while(rs.next()) {
BoardDTO dto = new BoardDTO();
dto.setBno(rs.getInt("bno"));
dto.setBtitle(rs.getString("btitle"));
dto.setBwrite(rs.getString("bwrite"));
dto.setBdate(rs.getString("bdate"));
dto.setBlike(rs.getInt("blike"));
list.add(dto); // 리스트에 추가
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if(rs != null) {rs.close();}
if(stmt != null) {stmt.close();}
if(conn != null) {conn.close();}
} catch (SQLException e) {
e.printStackTrace();
}
}
return list;
}
}
[ Board.java ] 에서 요만큼 삭제
요만큼은 추가
package com.poseidon.board;
[ Board.java ]
package com.poseidon.board;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.poseidon.dao.BoardDAO;
import com.poseidon.dto.BoardDTO;
@WebServlet("/board")
public class Board extends HttpServlet {
private static final long serialVersionUID = 1L;
public Board() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
BoardDAO dao = new BoardDAO();
List<BoardDTO> list = dao.boardList();
RequestDispatcher rd = request.getRequestDispatcher("board.jsp");
request.setAttribute("Sdata","전달합니다.");
request.setAttribute("list", list); // *
rd.forward(request, response);
}
}
* 삭제한 부분인 (boardList 빼고 list로 바꿔줘야함)
request.setAttribute("list", list);
실행하면
[BoardDAO.java] 에서 쿼리 명령문 바꿔주면
String sql = "SELECT * FROM board ORDER BY bno DESC LIMIT 10";
=> bno 기준으로 역순 방향, 10개의 데이터만 선택
package com.poseidon.board;
[ Detail.java ]
package com.poseidon.board;
import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.poseidon.dao.BoardDAO;
import com.poseidon.dto.BoardDTO;
@WebServlet("/detail")
public class Detail extends HttpServlet {
private static final long serialVersionUID = 1L;
public Detail() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//http://localhost:8080/jul03/detail?bno=1
System.out.println(request.getParameter("bno")); // *
int bno = Integer.parseInt(request.getParameter("bno")); // **
// DAO만들고
BoardDAO dao = new BoardDAO();
// DAO속 detail을 실행시켜서 DTO받기
BoardDTO detail = dao.detail(bno); // datail 만들자~
}
}
* System.out.println(request.getParameter("bno"));
=> bno를 파라미터로 받아오면 주소창에 아래처럼 표시됨
http://localhost:8080/jul03/detail?bno=1
** getParameter() 는 무조건 String타입으로만 가능. => int bno 로 받아오려면
int bno = Integer.parseInt(request.getParameter("bno"));
BoardDTO detail = dao.detail(bno); => 만들러 가자!!
[ BoardDAO.java ] 에 BoardDTO를 타입으로 가지는 detail() 메소드 생성
public BoardDTO detail(int bno) {
BoardDTO dto = new BoardDTO();
return dto;
}
( 변수들생성 & db연결 )
public BoardDTO detail(int bno) {
BoardDTO dto = new BoardDTO();
Connection conn = null;
String sql = "";
Statement stmt = null;
ResultSet rs = null;
// DB연결
conn = DBconnection.getInstance().getconConnection();
stmt = conn.createStatement(); // * try/catch 필요
return dto;
}
* stmt 에는 try/catch 필요
( 쿼리 명령문 넣어주고 실행 )*
public BoardDTO detail(int bno) {
BoardDTO dto = new BoardDTO();
Connection conn = null;
String sql = "SELECT * FROM board WHERE bno=" + bno; // *
Statement stmt = null;
ResultSet rs = null;
// DB연결
conn = DBconnection.getInstance().getconConnection();
try {
stmt = conn.createStatement();
rs = stmt.executeQuery(sql) // *
} catch (SQLException e) {
e.printStackTrace();
}
return dto;
}
( 실행값 가져오기 )
public BoardDTO detail(int bno) {
BoardDTO dto = new BoardDTO();
Connection conn = null;
String sql = "SELECT * FROM board WHERE bno=" + bno;
Statement stmt = null;
ResultSet rs = null;
// DB연결
conn = DBconnection.getInstance().getconConnection();
try {
stmt = conn.createStatement();
rs = stmt.executeQuery(sql);
if(rs.next()) {
dto.setBno(rs.getInt("bno"));
dto.setBtitle(rs.getString("btitle"));
dto.setBwrite(rs.getString("bwrite"));
dto.setBdate(rs.getString("bdate"));
dto.setBlike(rs.getInt("blike")); }
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if(rs != null) {rs.close();}
if(stmt != null) {stmt.close();}
if(conn != null) {conn.close();}
} catch (SQLException e) {
e.printStackTrace();
}
}
return dto;
}
[ Detail.java ] _ 디스패쳐로 보내기 (detail.jsp)
package com.poseidon.board;
import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.poseidon.dao.BoardDAO;
import com.poseidon.dto.BoardDTO;
@WebServlet("/detail")
public class Detail extends HttpServlet {
private static final long serialVersionUID = 1L;
public Detail() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//http://localhost:8080/jul03/detail?bno=1
System.out.println(request.getParameter("bno"));
int bno = Integer.parseInt(request.getParameter("bno"));
// DAO만들고
BoardDAO dao = new BoardDAO();
// DAO속 detail을 실행시켜서 DTO받기
BoardDTO detail = dao.detail(bno);
//System.out.println(detail.getBno()); // 확인용으로 찍어본거
//System.out.println(detail.getBtitle());
//System.out.println(detail.getBwrite());
// 디스패쳐로 보내기 (detail.jsp)
RequestDispatcher rd = request.getRequestDispatcher("detail.jsp");
request.setAttribute("detail", detail);
rd.forward(request, response);
}
}
src/webapp
[ detail.jsp ] _ jsp파일 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>톺아보기</title>
</head>
<body>
<h1>톺아보기</h1>
${detail.bno }<br>
${detail.btitle }<br>
${detail.bdate }<br>
${detail.bwrite }<br>
${detail.blike }<br>
</body>
</html>
게시판에서 100번 게시글 누르면 짠
( becontent 생성) _ 데이터유형은 text & Null 값 해제
저장*****
데이터 탭에서 becontent 생성확인!
ALTER TABLE `board`
ADD COLUMN `bcontent` TEXT NOT NULL AFTER `btitle`;
내용칸 채우려면
UPDATE board SET bcontent = '내용' WHERE 'bcontent'= null ; => 안됐었음......왜지?
UPDATE board SET bcontent = '내용'; => 내용칸 채우기
UPDATE board SET bwrite = '홍길동';
[ BoardDAO ]
String sql = "SELECT * FROM board ORDER BY bno DESC LIMIT 10";
String sql = "SELECT bno, btitle, bwrite, bdate, blike FROM board ORDER BY bno DESC LIMIT 10"; 로 변경
너무 명령문이 길고 복잡
=> view를 만들어줄거
CREATE VIEW boardview AS
SELECT bno, btitle, bwrite, bdate, blike
FROM board ORDER BY bno DESC LIMIT 10
=> SELECT~ 이후의 것들로 가상테이블(VIEW )을 만들겠다
10개만 보여줌
SELECT * FROM boardview; => 명령문 실행하면
[ BoardDAO ] 에서 명령문
String sql = "SELECT * FROM boardview"; 로 변경해주기
*view는 읽어오기만 하는거라 변경될 위험이 없음*
* 100번 글 지워보기 *
DELETE FROM board WHERE bno=100;
content 항목 추가해주기
[ BoardDTO.java ]
public String getBcontent() {
return bcontent;
}
public void setBcontent(String bcontent) {
this.bcontent = bcontent;
}
* getter/setter 해주기
(지금처럼 하나가 아닌, 여러개 추가하는 경우에는 그냥 전체에 대한 getter/setter 다시 걸어주는게 나음!)
[ BoardDAO.java ] 에도 추가
위에는 지워주고 아래부분에만 추가? 왜져 ㅠㅠ
dto.setBcontent(rs.getString("bcontent"));
[ detail.jsp ] 에도 추가
${detail.bcontent}<br>

테스트용도는 지워주고
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>톺아보기</title>
<link rel="stylesheet" type="text/css" href="./detail.css"> // *
</head>
<body>
<h1>톺아보기</h1>
</body>
</html>
* <link rel="stylesheet" type="text/css" href="./css/detail.css">
이제 css 파일을 따로 만들어서 여기에서 스타일 지정 코드 작성할거
( webapp 에 새로운 css폴더 생성 )

( css 파일 생성 )

( 이전에 css코드 작성해줬던 파일인 menu.jsp 연결해주기 )

[ detail.jsp ]
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>톺아보기</title>
<link rel="stylesheet" type="text/css" href="./css/detail.css">
</head>
<body>
<jsp:include page="./menu.jsp"/>
<h1>톺아보기</h1>
<div class="content">
<div class="title">
${detail.btitle }
</div>
<div class="write">
<div class="bwrite">
${detail.bwrite }
</div>
<div class="blike">
${detail.blike }
</div>
</div>
<div class="date">
${detail.bdate }
</div>
<div class="bcontent">
${detail.bcontent }
</div>
</div>
</body>
</html>
css로 꾸며주기 위해 class 설정해준듯???????
** 오타로 인한 오류주의 **
css 꾸미쟝
[ detail.css ]

(btitle 글자 가운데로)

밖으로 밀린 선 처리하려면!

.title 에 box-sizing: border-box; 추가

<div class="write">
<div class="bwrite">
${detail.bwrite }
</div>
<div class="blike">
${detail.blike }
</div>
</div>
( 위의 클래스들에 스타일 지정 )
@charset "UTF-8";
.content{
margin: 0 auto;
width: 900px;
height: auto;
background-color: gray;
}
.title{
width: 100%;
height: 100px;
line-height: 100px;
font-size: x-large;
border-bottom: 2px solid black;
padding-left: 20px;
box-sizing: border-box;
}
.write{
width: 100%;
height: 50px;
line-height: 50px;
background-color: lime;
}

.blike{
text-align: right;
}
.date{
width: 100%;
height: 30px;
line-height: 30px;
background-color: #c0c0c0;
}

.bcontent{
width: 100%;
height: auto;
min-height: 300px; /*높이는 자동(auto)지만 최소 300px까지*/
}
높이가 auto 면 내용부분에 따라서 늘어남!!!
그래도 최소 300px부터 시작하도록 설정해준거

각각 끝자락에 패딩을 주고 싶다면!??

체크 부분에 해당하는 class에다가 padding(right / left) 적용시키면 되는데
width 가 퍼센트로 설정되어 있어서 패딩값을 넣어주면 패딩값을 포함한 넓이의 퍼센트로 계산이 되어 뒤쪽 것들이 밀리게됨!
아래처럼
box-sizing: border-box;
같이 넣어주면 전체 넓이에 영향을 주지 않음!!!!


아니면

내용 추가!
결과화면은 요렇게!

최종 css코드!!
@charset "UTF-8";
.content{
margin: 0 auto;
width: 900px;
height: auto;
background-color: #B0C4DE;
padding: 10px;
}
.title{
width: 100%;
height: 100px;
line-height: 100px;
font-size: x-large;
border-bottom: 2px solid black;
padding-left: 20px;
box-sizing: border-box;
}
.write{
width: 100%;
height: 50px;
line-height: 50px;
background-color: #B0E0E6;
padding-left: 20px;
box-sizing: border-box;
}
.bwrite, .blike{
width: 50%;
height: 50px;
float: left;
}
.blike{
text-align: right;
padding-right: 20px;
box-sizing: border-box;
}
.date{
width: 100%;
height: 30px;
line-height: 30px;
background-color: #B0E0E6;
padding-left: 20px;
box-sizing: border-box;
}
.bcontent{
width: 100%;
height: auto;
min-height: 300px; /*높이는 자동(auto)지만 최소 300px까지*/
padding: 10px 0 10px 20px;
box-sizing: border-box;
background-color: #E0FFFF;
}
