BASHA TECH
ch10 본문
728x90
sql
CREATE TABLE news (
newsid NUMBER PRIMARY KEY
, title VARCHAR2(100) NOT NULL
, img VARCHAR2(300)
, regdate DATE DEFAULT SYSDATE -- news 등록일
, content VARCHAR2(2000) NOT NULL
);
DROP TABLE news;
INSERT INTO news(newsid, title, img, content)
VALUES( (SELECT NVL(MAX(newsid)+1,1) FROM news)
, 'test'
, 'test'
, 'test'
);
SELECT newsid
, title
, TO_CHAR(regdate, 'YYYY-MM-DD HH24:mm:ss') AS regdate
FROM news;
-- 상세
SELECT a.NEWSID
, a.TITLE
, TO_CHAR(a.regdate, 'YYYY-MM-DD HH24:mm:ss') AS regdate
, a.CONTENT
FROM NEWS a
WHERE a.NEWSID =: newid -- =: 가변 데이터 입력할 때 사용 db에서 테스트할 때 사용함
;
참고:
> Java단
jwbook/main/java/kr.co.big15/news/controller/NewsController.java
package kr.co.big15.news.controller;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.List;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import kr.co.big15.news.dto.NewsDto;
import kr.co.big15.news.model.NewsDao;
//annotation이 자바 코드로 바뀜.
@WebServlet("/news.nhn")
@MultipartConfig(maxFileSize = 1024*1024 * 2, location = "c:/Temp/img" ) //@MultipartConfig: 파일 업로드 처리하는 애
public class NewsController extends HttpServlet {
private static final long serialVersionUID = 1L;
private NewsDao dao;
private ServletContext ctx; //ServletContext: 요청 들어온 걸 다 받아줌. 서블릿 컨테이너임.
// 웹 리소스 기본 경로 지정
private final String START_PAGE = "news.nhn?action=listNews";
//init을 쓰는 이유 생성자 호출이 안됨.
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config); //super는 HTTPServlet임 여기를 초기화 하겠다는 것
dao = new NewsDao();
ctx = super.getServletContext(); //Httpt서블릿안에 있음 그래서 상속 받을 수 있다. => overriding
}
// 얘도 실행은 서블릿 컨테이너가 함
@Override
protected void service(HttpServletRequest req
, HttpServletResponse resp) throws ServletException, IOException {
// request의 한글 처리 = > utf-8 : 첫째 줄에 있어야함
req.setCharacterEncoding("utf-8");
String action = req.getParameter("action");
// dao = new NewsDao(); 필요 없다. 위에 선언되어잇음 중복됨
Method method;
String view = "null";
if(action == null) {
action = "listNews"; //listNews가 메소드 이름이 됨
}
try {
method = this.getClass().getMethod(action, HttpServletRequest.class); //NewsController class를 가져오는 코드임 => 코드양이 많이 주는 좋은 코드다
// m.invoke => 해당 메소드 실행
view = (String)method.invoke(this, req); //this가 들어간다는 것 멤버 변수 접근을 가능하게 한다.
} catch (Exception e) { //NoSuchException : 네가 부른 메소드가 없다
// e.printStackTrace();
req.setAttribute("error", "action 파라미터가 잘못 되었습니다.");
view = START_PAGE;
}
// Post 요청에서는 리디렉션 방법으로 이동하도록 분기
// redirect:/view => view만 남기고 얘 가지고만 redirect 처리 하겠다는 얘기
if(view.startsWith("redirect:/")) {//시작하는 문자열
String rview = view.substring("redirect:/".length()); //redirect의 length부터 가져와라 index는 0부터 length는 1부터
resp.sendRedirect(rview); //양식 다시 제출 확인이라는 창이 뜨게 함. 핵심 redirect해야한다는 것. url을 알아야함. 그럴려면
//url에 redirect가 추가되면서 view가 들어와서 다시 제출하라는 요청이 뜨게 함. = > 이때 다시 제출하면 안되니까 억지로 view로 redirect하라는 뜻
//안되면 forwarding 해야함
} else {
RequestDispatcher disp = req.getRequestDispatcher(view);
disp.forward(req, resp);
}
}
// 뉴스 목록 처리 메소드
public String listNews(HttpServletRequest request) {
List<NewsDto> list = null; //alt+shift+o
try {
list = dao.select();
request.setAttribute("listNews", list);
} catch (Exception e) {
e.printStackTrace(); // 에러 추적해서 출력해주는 것. 개발 시 적용했다가 실제 운용시에는 제거해야함
request.setAttribute("error", "뉴스 목록이 정상적으로 처리되지 않았습니다.");
}
return "news/listNews.jsp"; //이건 웹상 경로임
}
}
jwbook/main/java/kr.co.big15/news/dto>NewsDto.java
package kr.co.big15.news.dto;
public class NewsDto {
private int newsid;
private String title;
private String img;
private String regdate;
private String content;
public int getNewsid() {
return newsid;
}
public void setNewsid(int newsid) {
this.newsid = newsid;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getImg() {
return img;
}
public void setImg(String img) {
this.img = img;
}
public String getRegdate() {
return regdate;
}
public void setRegdate(String regdate) {
this.regdate = regdate;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
//alt+ s+s+s
@Override
public String toString() {
return "NewsDto [newsid=" + newsid + ", title=" + title + ", img=" + img + ", regdate=" + regdate + ", content="
+ content + "]";
}
}
jwbook/main/java/kr.co.big15/news/model/NewDao.java
package kr.co.big15.news.model;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
//import javax.naming.spi.DirStateFactory.Result;
import kr.co.big15.news.dto.NewsDto;
public class NewsDao {
public static Connection getConnection() {
Connection conn = null;
String driver = "oracle.jdbc.driver.OracleDriver";
String url = "jdbc:oracle:thin:@localhost:1521:xe";
String userid = "ora_user";
String userpassword = "hong";
try {
Class.forName(driver);
conn = DriverManager.getConnection(url, userid, userpassword);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
public static void close(Connection conn, PreparedStatement pstmt) {
try {
pstmt.close();
conn.close();
}catch(SQLException e) {
e.printStackTrace();
}
}
// 위에 있는 close랑 뭐가 다른 걸까? ? ?
public static void close(Connection conn, PreparedStatement pstmt, ResultSet rs) {
try {
conn.close();
rs.close();
pstmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
// 뉴스 추가 => insert => int
public void addNews(NewsDto newsDto) { //throws Exception=> 안에서 에러나면 던진다는 것. 컨트롤러에서 에러를 해결을 해야함.
// 따라서 에러난 곳에서 해결하는 것이 좋다.
Connection conn = getConnection();
PreparedStatement pstmt = null; //웬만하면 connection뒤에 선언을 해주는 것이 맞다
StringBuilder sql = new StringBuilder();
sql.append("insert into news(newsid, title, img, content)");
sql.append("values((select nvl(max()+1,1) from news), ");
sql.append("?,?,?) ");
try {
pstmt = conn.prepareStatement(sql.toString()); //conn.preparedStatement~부터 처리 한다. 예외일 땐, catch로 빠져나감. 따라서 pstmt 자체가 아예 선언이 되지 않을 수 있다. //따라서 pstmt부터 선언을 밖에서 해줘야함.
pstmt.setString(1, newsDto.getTitle());
pstmt.setString(2, newsDto.getImg());
pstmt.setString(3, newsDto.getContent());
pstmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
close(conn, pstmt);
}
}
// 뉴스 전체 목록 추출 => select all
public ArrayList<NewsDto> select() throws Exception {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
ArrayList<NewsDto> newsArr = new ArrayList<>();
// 처리 코드
StringBuilder sql = new StringBuilder();
sql.append("SELECT newsid ");
sql.append(" , title ");
sql.append(" , TO_CHAR(regdate, 'YYYY-MM-DD HH24:mm:ss') AS regdate");
sql.append(" FROM news ");
// try(conn;pstmt;rs){ //이렇게 쓰면 안에서 정상적인 처리가 끝나면 } finally {close(conn, pstmt);}를 안 쳐도 자동으로 종료 됨
try {
conn = getConnection();
pstmt = conn.prepareStatement(sql.toString());
rs = pstmt.executeQuery();
while(rs.next()) {
NewsDto n = new NewsDto();
n.setNewsid(rs.getInt("newsid"));
n.setTitle(rs.getString("title"));
n.setRegdate(rs.getString("regdate"));
newsArr.add(n);
}
} catch (Exception e) {
}
return newsArr;
}
// 뉴스 상세 추출 = > select where newsid =?
public NewsDto select(int newsid) {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
NewsDto newsDto = new NewsDto();
// 처리 코드
StringBuilder sql = new StringBuilder();
sql.append("SELECT a.NEWSID ");
sql.append(" , a.TITLE ");
sql.append(" , TO_CHAR(a.regdate, 'YYYY-MM-DD HH24:mm:ss') AS regdate");
sql.append(" , a.CONTENT ");
sql.append(" FROM NEWS a ");
sql.append(" WHERE a.NEWSID = ? ");
try {
conn = getConnection();
pstmt = conn.prepareStatement(sql.toString());
pstmt.setInt(1, newsid);
rs = pstmt.executeQuery();
if(rs.next()) {
newsDto.setNewsid(rs.getInt("newsid"));
newsDto.setTitle(rs.getString("title"));
newsDto.setImg(rs.getString("img"));
newsDto.setRegdate(rs.getString("regdate"));
newsDto.setContent(rs.getString("content"));
} else {
System.out.println("해당 뉴스가 없다!!!");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
close(conn, pstmt, rs);
}
return newsDto;
}
//
// 뉴스 제목 검색 추출 = > select where 검색 제목
public ArrayList<NewsDto> select(String title) {
ArrayList<NewsDto> newsArr = new ArrayList<>();
// ****** 처리 코드
return newsArr;
}
// 뉴스 삭제 = > delete where newsid = ?
public void delete(int newsid) {
Connection conn = null;
PreparedStatement pstmt = null;
String sql = "delete news where newsid = ?";
try {
conn = getConnection();
pstmt = conn.prepareStatement(sql.toString());
pstmt.setInt(1, newsid);
if(pstmt.executeUpdate() == 0) {
//insert, updat, del은 int값으로 나오는 데 결과 값이 0이다. => 삭제된 것이 없다
System.out.println("삭제된 뉴스가 없다.");
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
jwbook/main/java/kr.co.big15/news/service
여기서는 안 만들었지만 현장 가면 만들 가능성 ↑
> web단
jwbook/main/webapp/news/listNews.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>
<!--https://www.w3schools.com/bootstrap5/bootstrap_get_started.php 여기 MaxCDN 복붙 -->
<!-- Latest compiled and minified CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- Latest compiled JavaScript -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<div class="container w-75 mt-5 mx-auto">
<h2>뉴스 목록</h2>
<hr>
<ul class="list-group">
<c:forEach items="${listNews }" var="news" varStatus="status">
<li class="list-group-item list-group-item-action d-flex justify-content-between align-items-center">
<a href="news_nhn?action=getNews&newsid=${news.newsid } class="text=decoration-none">
[${status.count}] [${news.title}] [${news.regdate}]
</a>
<a href="news.nhn?action=deleteNews&newsid=${news.newsid }">
<span class="badge bg-secondary">×</span>
</a>
</li>
</c:forEach>
</ul>
<hr>
<c:if test="${error != null }">
<div class="alert alert-danger alert-dismissible fade show mt-3">
에러 발생 : ${error}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
</c:if>
<!-- 에러 처리 끝 -->
<!-- 뉴스 등록 시작 -->
<button class="btn btn-outline-info mb-3" type="button" data-bs-toggle="collapse"
data-bs-target="#addForm" aria-controls="addForm" aria-expanded="false">
뉴스 등록
</button>
<!--<input type="button" value="뉴스 등록">-->
<div class = "collapse" id="addForm">
<div class="card card-body">
<form action="/jwbook/news.nhn?action=addNews" method="post" enctype="multipart/form-data">
<label class="form-label">제목</label>
<input type = "text" name="title" class="form-control">
<label class="form-label">이미지</label>
< input type = "file" name="file" class="form-control">
<label class="form-label">기사 내용</label>
<textarea rows="5" cols="50" class="form-control"></textarea>
<button type="sumit" class="btn btn-success mt-3">저장</button>
</form>
</div>
</div>
<!-- 뉴스 등록 끝 -->
</div>
</body>
</html>
728x90
반응형
'Computer > JSP' 카테고리의 다른 글
startsWith/endsWith 특정 문자로 시작하거나 끝나는지 체크 (0) | 2022.09.01 |
---|---|
annotation이 java코드로 바뀌는 원리 (0) | 2022.09.01 |
ch09 (0) | 2022.08.31 |
JSP 목차 (0) | 2022.08.30 |
ch08 (0) | 2022.08.30 |
Comments