오늘은 학원에서는 싱글톤 개념에 대해서 다양하게 배우고 있다.
일단 오늘은 싱글톤을 이용한 파일입출력에 대하여 기록해 보도록 하겠다.
일단 파일업로드를 하기 위해서는 http://www.servlets.com/cos/ 이 사이트에서 cos.jar이라는 파일을
프로젝트의 lib폴더에 넣어줘야 한다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="ex01.*" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:set var="cpath" value="${pageContext.request.contextPath }" />
<c:set var="dao" value="${UploadDAO.getInstance() }" />
<c:set var="util" value="${FileUtil.getInstance(pageContext.request) }" />
<% request.setCharacterEncoding("UTF-8"); %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<nav>
<ul>
<li><a href="${cpath }/list.jsp">목록</a></li>
<li><a href="${cpath }/add.jsp">추가</a></li>
</ul>
</nav>
----------------------------------------------------- header.jsp -----------------------------------------------------------------
우선 header파일이다. 여기서는 jstl을 사용하기 위해서 taglib를 설정하고
cpath, dao의 싱글톤 인스턴스, 파일을 유지하기 위해서 FileUtil이라는 싱글톤 인스턴스를 만들어주고 불러와준다.
여기서 cpath를 사용하는 이유는 cpath를 a태그에 넣어주면 현재 가지고 있는 값도 같이 해당 페이지로 보낼 수 있기 때문이다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ include file = "header.jsp" %>
<div id = "root">
<c:set var="list" value="${dao.selectAll() }" />
<c:forEach var="dto" items="${list }" >
<div class="item">
<div class="title">${dto.title }</div>
<div class="image"><img src="${cpath}/image/${dto.uploadFile}" /></div>
</div>
</c:forEach>
</div>
</body>
</html>
----------------------------------------------------- list.jsp -----------------------------------------------------------------
list에서는 dao의 함수로 불러온 db값들을 불러오는 페이지이다.
일단 c:set으로 함수를 불러와주고
forEach로 모든 사진들의 좌표를 불러와준다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ include file = "header.jsp" %>
<c:if test="${pageContext.request.method == 'GET'}" >
<form method="POST" enctype="multipart/form-data">
<p><input type="text" name="title" placeholder="제목" required autofocus /></p>
<p><input type="file" name="upload" required /></p>
<p><input type="submit" /></p>
</form>
</c:if>
<c:if test="${pageContext.request.method == 'POST'}">
<c:set var="dto" value="${util.getUploadDTO(pageContext.request) }" />
<c:set var="row" value="${dao.insert(dto) }" />
<h3>${row != 0 ? "추가성공" : "추가실패" }</h3>
<a href="${cpath }/list.jsp"><button>목록으로</button></a>
</c:if>
</body>
</html>
----------------------------------------------------- add.jsp ----------------------------------------------------------------------
add는 pageContext.request의 타입이 GET이면 아래 객체를 보낸다.
여기서 중요한 점은 파일은 통째로 보내는 것이 아니라는 것이다. 당연한 얘기지만 파일을 쪼개서
개발자가 정한 한계치의 용량의 파일만 올릴 수 있다.
파일을 쪼개는 기능을 제공하는 것이 multipart/form-data라고 적혀있는 부분에서 불러오는 것이다.
util.getUploadDTO라고 적혀있는 부분은 header.jsp에서 <c:set>으로 util이라는 객체를 만들든 다음 FileUtil.getInstance(싱글톤)를 불러온 것으로 이렇게 하면 이 java클래스의 모든 메서드를 불러올 수 있다.
package ex01;
import java.io.File;
import java.io.IOException;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import com.oreilly.servlet.MultipartRequest;
import com.oreilly.servlet.multipart.DefaultFileRenamePolicy;
import com.oreilly.servlet.multipart.FileRenamePolicy;
public class FileUtil {
private static FileUtil instance;
private String saveDirectory;
private int maxPostSize = 20 * 1024 * 1024;
private String encoding = "UTF-8";
private FileRenamePolicy policy = new DefaultFileRenamePolicy();
private FileUtil(HttpServletRequest request) {
ServletContext application = request.getServletContext();
saveDirectory = application.getRealPath("image");
}
public static FileUtil getInstance(HttpServletRequest request) {
if(instance == null) {
instance = new FileUtil(request);
}
return instance;
}
public UploadDTO getUploadDTO(HttpServletRequest request) throws IOException {
UploadDTO dto = null;
File dir = new File(saveDirectory);
if(dir.exists()==false) {
dir.mkdir();
}
MultipartRequest req = new MultipartRequest(request, saveDirectory, maxPostSize,encoding ,policy );
String title = req.getParameter("title");
File f = req.getFile("upload");
dto = new UploadDTO();
dto.setTitle(title);
dto.setUploadFile(f.getName());
return dto;
}
}
----------------------------------------------------- FileUtil.java ----------------------------------------------------------------------
여기서 싱글톤의 개념을 알아야 한다.
우선 보통 DAO를 만들 때 DTO객체는 각각의 메서드에 만들 것이다.
그것이 의미하는 의미는 함수를 실행할 때마다 DTO의 값을 불러왔다가 함수가 종료되면
불러왔던 값도 사라진다는 뜻이다.
그것을 방지하기 위해서 DTO의 객체를 멤버필드의 instance타입으로 만들어 값을 유지시키기 위해
사용하는 것이 싱글톤이다.
제일 위에 보면 FileUtil타입의 instance객체를 만들고
getInstance함수의 instance에 객체속성을 넣어주고
instance를 반환한다.
private FileUtil(HttpServletRequest request) {
ServletContext application = request.getServletContext();
saveDirectory = application.getRealPath("image");
}
위 부분은 HttpServletRequest는 웹 애플리케이션에서 클라이언트의 HTTP요청에 대한 정보를 제공하는 객체이다.
request를 사용하여 ServletContext를 얻습니다.
saveDirectory는 저장경로를 지정하는 구문이다.
이제 파일을 업로드하는 함수이다.
public UploadDTO getUploadDTO(HttpServletRequest request) throws IOException {
UploadDTO dto = null;
File dir = new File(saveDirectory);
if(dir.exists()==false) {
dir.mkdir();
}
DTO객체를 생성하고 초기화 후
File타입의 객체에 저장경로 변수를 넣어준다.
그 변수(경로에) 파일이 없다면 파일을 생성한다.
MultipartRequest req = new MultipartRequest(request, saveDirectory, maxPostSize, encoding , policy );
String title = req.getParameter("title");
File f = req.getFile("upload");
dto = new UploadDTO();
dto.setTitle(title);
dto.setUploadFile(f.getName());
return dto;
MultipartRequest 이것은 add에서도 설명했었지만 파일은 통째로 올라가는 것이 아니라 쪼개져서 올라간다.
그 기능을 할 수 있는 것이 MultipartRequest이다.
add.jsp에서 값을 보내면 title변수에 MultipartRequest로 파라미터를 받고
파일에 MultipartRequest의 기능을 적용시킨다.
그다음 dto로 값을 보낸다.
package ex01;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import java.sql.Connection;
public class UploadDAO {
private static UploadDAO instance = new UploadDAO();
private Connection conn;
private PreparedStatement pstmt;
private ResultSet rs;
private Context init;
private DataSource ds;
private UploadDAO() {
try {
init = new InitialContext();
ds = (DataSource) init.lookup("java:comp/env/jdbc/oracle");
}catch(NamingException e) {
e.printStackTrace();
}
}
public static UploadDAO getInstance() {
return instance;
}
private void close() {
try { if (rs != null) rs.close();} catch (Exception e) {}
try { if (pstmt != null) pstmt.close();} catch (Exception e) {}
try { if (conn != null) conn.close();} catch (Exception e) {}
}
public List<UploadDTO> selectAll() {
ArrayList<UploadDTO> list = new ArrayList<UploadDTO>();
String sql = "select * from upload1 order by idx";
try {
conn = ds.getConnection();
pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery();
while(rs.next()) {
UploadDTO dto = new UploadDTO();
dto.setIdx(rs.getInt("idx"));
dto.setTitle(rs.getString("title"));
dto.setUploadFile(rs.getString("uploadfile"));
dto.setUploadDate(rs.getDate("uploaddate"));
list.add(dto);
}
}catch(SQLException e) {
e.printStackTrace();
}finally {
close();
}
return list;
}
public int insert(UploadDTO dto) {
int row = 0;
String sql = "insert into upload1 (title, uploadFile) values (?, ?)";
try {
conn = ds.getConnection();
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, dto.getTitle());
pstmt.setString(2, dto.getUploadFile());
row = pstmt.executeUpdate();
}catch(SQLException e) {
e.printStackTrace();
}finally {
close();
}
return row;
}
public int delete(UploadDTO dto) {
int row = 0;
String sql = "delete upload1 where idx = ?";
try {
conn = ds.getConnection();
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, dto.getIdx());
row = pstmt.executeUpdate();
}catch(SQLException e) {
e.printStackTrace();
}finally {
close();
}
return row;
}
}
----------------------------------------------------- UploadDAO.java ----------------------------------------------------------------------
FileUtil.java에서 DTO로 보낸 값들을 DAO에서 받아서 db로 올리는 것으로 끝이다.
여기서 중요한 점은 dto를 만약 각 객체에서 생성했다면 함수가 실행되고 나면 값이 사라졌을 것이다.
하지만 그것을 싱글톤으로 instance에 위치시켜 놨기 때문에 dto객체에 계속 유지될 수 있었던 것이다.
DAO는 단순한 내용이라 생략하도록 하겠다.
내용이 점점 어려워 지고 있지만 그만큼 혼자 만들수 있는 범위가 늘어나는 점은 즐겁게 느끼고있다.
앞으로 국비교육이 끝날때까지 3개월밖에 남지않았다.
조만간 Spring까지 들어가면 국비의 커리큘럼은 끝날것이다.
얼마 남지않았다고 조급해 하지말고 현재 배운 내용으로 만들수 있는 것을 만들어보고
꾸준히 프로그래머스를 풀면서 나만의 페이스로 끝까지 갈 생각이다.
그럼 오늘은 여기서 마치도록 하겠다.
'JSP' 카테고리의 다른 글
JSP 파라미터의 이동 - 심화내용 (0) | 2023.05.29 |
---|---|
JSP JSTL - 파라미터의 흐름 (0) | 2023.05.23 |
JSP기초 - 자바코드 페이지 출력방법 (0) | 2023.05.17 |