Backend
home

2024. 8. 7

프로젝트 실습 - 뉴스 기사 관리 서비스

뉴스 기사 제공 웹 서비스 제작
부트스트랩을 활용한 화면 구현
DB 연동 (뉴스 DataBase에 새로운 기사를 등록, 조회, 삭제가 가능)
이미지 파일 첨부 포함
프로젝트 구조
-- news_db 생성 DROP DATABASE IF EXISTS `news_db`; CREATE DATABASE news_db DEFAULT CHARACTER SET = 'utf8mb4' COLLATE = utf8mb4_0900_ai_ci; -- 생성된 DB 선택 USE news_db; -- news 테이블 생성 CREATE TABLE news ( id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, title VARCHAR(255) NOT NULL, img VARCHAR(255) NOT NULL, date DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, content VARCHAR(255) NOT NULL );
SQL
복사
설정 파일 경로 확인
~/Desktop/test/java/webjsp/news (main)$ ls mvnw mvnw.cmd pom.xml src target ~/Desktop/test/java/webjsp/news (main)$ cd src ~/Desktop/test/java/webjsp/news/src (main)$ ls main test ~/Desktop/test/java/webjsp/news/src (main)$ cd main ~/Desktop/test/java/webjsp/news/src/main (main)$ ls java resources webapp ~/Desktop/test/java/webjsp/news/src/main (main)$ ls java resources webapp ~/Desktop/test/java/webjsp/news/src/main (main)$ cd webapp ~/Desktop/test/java/webjsp/news/src/main/webapp (main)$ ls WEB-INF lib style.css ~/Desktop/test/java/webjsp/news/src/main/webapp (main)$ cd WEB-INF ~/Desktop/test/java/webjsp/news/src/main/webapp/WEB-INF (main)$ ls views ~/Desktop/test/java/webjsp/news/src/main/webapp/WEB-INF (main)$ cd ls cd: no such file or directory: ls ~/Desktop/test/java/webjsp/news/src/main/webapp/WEB-INF (main)$ ls lib views ~/Desktop/test/java/webjsp/news/src/main/webapp/WEB-INF (main)$ cd views ~/Desktop/test/java/webjsp/news/src/main/webapp/WEB-INF/views (main)$ ls NewsList.jsp NewsView.jsp ~/Desktop/test/java/webjsp/news/src/main/webapp/WEB-INF/views (main)$
SQL
복사
폴더 구조
├── mvnw ├── mvnw.cmd ├── pom.xml ├── src │ ├── main │ │ ├── java │ │ │ └── com │ │ │ └── news │ │ │ ├── controller │ │ │ │ └── NewsController.java │ │ │ ├── dao │ │ │ │ └── NewsDAO.java │ │ │ ├── model │ │ │ │ └── News.java │ │ │ ├── service │ │ │ │ └── NewsService.java │ │ │ └── util │ │ │ └── ConnectionPool.java │ │ ├── resources │ │ └── webapp │ │ ├── WEB-INF │ │ │ ├── lib │ │ │ │ ├── jstl-1.2.jar │ │ │ │ └── mysql-connector-j-8.3.0.jar │ │ │ └── views │ │ │ ├── NewsList.jsp │ │ │ └── NewsView.jsp │ │ └── style.css │ └── test │ ├── java │ └── resources └── target ├── classes │ └── com │ └── news │ └── HelloServlet.class ├── generated-sources │ └── annotations └── news-1.0-SNAPSHOT ├── META-INF │ └── MANIFEST.MF ├── WEB-INF │ ├── classes │ │ └── com │ │ └── news │ │ └── HelloServlet.class │ └── web.xml ├── index.jsp └── lib └── mysql-connector-j-8.3.0.jar
HTML
복사
bootstrap 링크 적용 - css, js 적용
<!-- CSS --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script> <!-- JS --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
HTML
복사
model 패키지 News 클래스 작성
package com.news.model; import lombok.AllArgsConstructor; import lombok.Data; @Data @AllArgsConstructor public class News { private int id; private String title; private String img; private String date; private String content; }
Java
복사
NewsDAO
package com.news.dao; import com.news.model.News; import java.util.List; public interface NewsDAO { // 뉴스 기사 추가 void addNews(News news) throws Exception; // 뉴스 기사 전체 보기 List<News> getAll() throws Exception; // 뉴스 기사 보기 News getNews(int id) throws Exception; // 뉴스 기사 삭제 void deleteNews(int id) throws Exception; }
Java
복사
ListController
package com.news.controller; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class ListController implements NewsController { @Override public void process(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { String view = "/WEB-INF/views/NewsList.jsp"; req.getRequestDispatcher(view).forward(req, res); } }
Java
복사
ViewController
package com.news.controller; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class ViewController implements NewsController { @Override public void process(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { String view = "/WEB-INF/views/NewsView.jsp"; req.getRequestDispatcher(view).forward(req, res); } }
Java
복사
NewsController
package com.news.controller; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public interface NewsController { void process(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException; }
Java
복사
NewsServlet
package com.news.controller; 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 java.io.IOException; import java.util.HashMap; import java.util.Map; @WebServlet("/news/*") public class NewsServlet extends HttpServlet { private static final long serialVersionUID = 1L; private Map<String, NewsController> controllerMap = new HashMap<>(); // 페이지 추가시 여기에 추가해준다 public NewsServlet() { controllerMap.put("/news/newsList", new ListController()); controllerMap.put("/news/newsView", new ViewController()); } @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String requestURI = req.getRequestURI(); NewsController controller = controllerMap.get(requestURI); if (controller == null) { // controller = controllerMap.get("/news/newsList"); // resp.setStatus(HttpServletResponse.SC_NOT_FOUND); // return; } controller.process(req, resp); } }
Java
복사
View 꾸미기
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous"> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script> <title>뉴스 목록</title> </head> <body> <div class="container w-75 mt-5 mx-auto"> <h2 class="text-center mb-4">뉴스 목록</h2> <hr/> <ul class="list-group mb-4"> <li class="list-group-item list-group-item-action d-flex justify-content-between align-items-center"> <a>[1] 안세영 배드민턴 협회 은퇴 예고</a> <span>2024-08-07</span> <a><span class="badge bg-secondary"> &times; </span></a> </li> <li class="list-group-item list-group-item-action d-flex justify-content-between align-items-center"> <a>[2] 오늘 파리올림픽 남자 클라이밍 리드 이도현 출전 17시</a> <span>2024-08-07</span> <a><span class="badge bg-secondary"> &times; </span></a> </li> </ul> </div> </body> </html>
HTML
복사
NewsList.jsp
<%-- Created by IntelliJ IDEA. User: haminsung Date: 8/7/24 Time: 9:35 AM To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous"> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script> <title>뉴스 목록</title> </head> <body> <div class="container w-75 mt-5 mx-auto"> <h2 class="text-center mb-4">뉴스 목록</h2> <hr/> <ul class="list-group mb-4"> <li class="list-group-item list-group-item-action d-flex justify-content-between align-items-center"> <a>[1] 안세영 배드민턴 협회 은퇴 예고</a> <div> <span>2024-08-07</span> <a><span class="badge bg-secondary"> &times; </span></a> </div> </li> <li class="list-group-item list-group-item-action d-flex justify-content-between align-items-center"> <a>[2] 오늘 파리올림픽 남자 클라이밍 리드 이도현 출전 17시</a> <div> <span>2024-08-07</span> <a><span class="badge bg-secondary"> &times; </span></a> </div> </li> </ul> <div class="alert alert-danger alert-dismissible fade show mt-3" role="alert"> 에러 발생 : 에러 메시지~~~ <button class="btn-close" data-bs-dismiss="alert"></button> </div> <button class="btn btn-outline-success collapse-button" data-bs-toggle="collapse" data-bs-target="#addForm" aria-expanded="false" aria-controls="addForm"> 기사 등록 </button> <div class="collapse" id="addForm"> <div class="card card-body"> <form> <label for="title" class="form-label">제목</label> <input id="title" name="title" class="form-control" required /> <label for="img" class="form-label">이미지</label> <input id="img" type="file" name="img" class="form-control" required /> <label for="content" class="form-label">기사 내용</label> <textarea id="content" rows="5" cols="50" name="content" class="form-control" required></textarea> <button class="btn btn-success mt-3">저장</button> </form> </div> </div> </div> </body> </html>
HTML
복사