BASHA TECH

스프링으로 news 카테고리 만들어보기 본문

Computer/JSP

스프링으로 news 카테고리 만들어보기

Basha 2022. 9. 8. 17:56
728x90

src/main/java

> com.big15.news.controller (패키지)

>NewsWebController (클래스)

package com.big15.news.controller;

import java.io.File;
import java.io.IOException;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

import com.big15.news.dto.NewsDto;
import com.big15.news.model.NewsDao;

@Controller
@RequestMapping("/news")
public class NewsWebController {
	private final Logger logger = LoggerFactory.getLogger(this.getClass());
	
	final NewsDao dao;
	
	@Autowired // DI => spring container control => IoC
	public NewsWebController(NewsDao dao) {
		this.dao = dao; // final 한 애를 생성자에서 초기화 할 수 있다.
	}
	
//	파일 업로드 처리 => 디렉토리 설정
	@Value("${news.imgdir}") // spring container에게 파일 속성값을 가져와서 fileDir에 넣어라는 명령어
	String fileDir;  
	
//	뉴스 등록
	@PostMapping("/add")
	public String addNews(@ModelAttribute NewsDto newsDto
			, Model model, @RequestParam("file") MultipartFile file) {
		logger.info("뉴스 등록 : " + newsDto);
//		저장 위치만 지정
		File dest = new File(fileDir + "/" + file.getOriginalFilename()); 
		logger.info("파일 저장 위치 : " + dest);
//		파일 저장
		try {
			file.transferTo(dest); // File에 unload
			newsDto.setImg(dest.getName());
			dao.insert(newsDto); // DB에 insert 처리
		} catch (Exception e) {
			e.printStackTrace();
			logger.info("뉴스 추가 과정에서 문제 발생");
			model.addAttribute("error", "뉴스가 정상적으로 등록되지 않았습니다.");
		}
		// 스프링이 문자열 안에 redirect:/ 로 되어있으면 sendRedirect 처리한다.
		return "redirect:/news/list"; 
	}
	
//	뉴스 삭제
	@GetMapping("/delete/{newsid}")
	public String deleteNews(@PathVariable int newsid, Model model) {
		dao.delete(newsid);
		return "redirect:/news/list";
	}
	
	
//	뉴스 목록
	@GetMapping("/list")
	public String listNews(Model model) {
		List<NewsDto> list;
		
		try {
			list = dao.select();
			model.addAttribute("listNews", list); // request에서 add한다음 forward한다.
		} catch (Exception e) {
			e.printStackTrace();
		} // DB에서 select한 것을 담고 (bean 처리)
		
		return "news/listNews"; //return은 jsp가 받음 forwarding 해야함
	}
	
//	@GetMapping("/list")
//	public String listNews(Model model) {
//		List<NewsDto> list;
//		
//		list = dao.select(); // DB에서 select한 것을 담고 (bean 처리)
//		
//		model.addAttribute("listNews", list); // request에서 add한다음 forward한다.
//		return "news/listNews"; //return은 jsp가 받음 forwarding 해야함
//	}
	
//	뉴스 상세 => /news/{newsid}
	@GetMapping("/{newsid}")
	public String getNews(@PathVariable int newsid, Model model) {
		NewsDto newsDto = dao.select(newsid); // DB에서 Select한것
		
		model.addAttribute("newsDto", newsDto);
		return "news/newsView"; // forward 한 것
	}
}

com.big15.news.dto (패키지)

> NewsDto (클래스)

package com.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 + "]";
	}
	
	
}

com.big15.news.model (패키지)

> NewsDao (클래스)

package com.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 org.springframework.stereotype.Component;

//import javax.naming.spi.DirStateFactory.Result;

import com.big15.news.dto.NewsDto;

@Component
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랑 뭐가 다른 걸까? ? ? result 닫는 것
	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 insert(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(newsid)+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("	  , a.img												   ");
		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, update, del은 int값으로 나오는 데 결과 값이 0이다. => 삭제된 것이 없다
				System.out.println("삭제된 뉴스가 없다.");
			}

		} catch (SQLException e) {
			e.printStackTrace();
		}
				
	}
}

src/main/resources

> application.properties

spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp
server.port=62000
# 이미지 업로드 디렉토리 설정
news.imgdir=D:/big15/sts-dev/workspace/news/src/main/resources/static/img
# 파일 크기 설정
spring.servlet.multipart.max-file-size=1024MB
spring.servlet.multipart.max-request-size=1024MB
# static resource
#spring.mvc.static-path-pattern=/static/**
#spring.resources.static-locations=classpath:/static/
#spring.resources.add-mappings=true

src/main/resources

/static

/css, img, jsp 폴더 생성

 

src/main/resources

/templates

/html 폴더 생성


src

/main

/webapp

/WEB-INF 폴더 생성

/views 폴더 생성

/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/${news.newsid }" class="text=decoration-none">
					[${status.count}] [${news.title}] [${news.regdate}]
				</a> <!-- 상세 -->
				<a href="/news/delete/${news.newsid }">
					<span class="badge bg-secondary">&times;</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="/news/add" 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"> <!-- multipart방식이여야하고 method가 반드시 post여야함 -->
			<label class="form-label">기사 내용</label>
				<textarea rows="5" cols="50" class="form-control" name="content"></textarea>
			<button type="submit" class="btn btn-success mt-3">저장</button>
			</form>
		</div>
	</div>
	 
	<!-- 뉴스 등록 끝 -->
	
	</div>
</body>
</html>

> newsView.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>${newsDto.title}</h2>
		<hr>
		<!-- 카드 박싱 -->
		<div class="card w-75 mx-auto">
			<img class="card-img-top" src="/img/${newsDto.img }">
			<div class="card-body">
				<h4 class="card-title">${newsDto.regdate}</h4>
				<p class="card-text">${newsDto.content}</p>
			</div>
		</div>
		<a href = "javascript:history.back();" class="btn btn-primary"> Back </a>
	</div>
	
</body>
</html>
728x90
반응형

'Computer > JSP' 카테고리의 다른 글

Decorator Pattern  (0) 2022.09.07
프록시 패턴(Proxy Pattern)  (0) 2022.09.07
AOP & Filter & Listener  (0) 2022.09.05
this.getclass().getmethod  (0) 2022.09.01
Redirect  (0) 2022.09.01
Comments