Dev/Struts

Struts1/iBatis - 파일 업로드 기능 구현

창문닦이 2019. 3. 21. 11:48

네 가지 기능을 구현할 수 있으면 기본적인 개념은 잡힌 것

① 게시판 만들기 (JSP > Servlet > Struts1 > iBatis )

② Struts1 을 사용한 파일 업로드

③ 이미지게시판

④ 로그인 처리


Struts1 + iBatis 을 사용한 파일 업로드

기존에는 OriginalfileName 과 SaveFileName을 동일하게 생성했음. 기존 디렉토리에 동일한 이름이 있으면 뒤에 숫자를 붙여서 구분하였음. 클라우드서비스를 이용하면 서버측에서는 모두 열람이 가능함. 이번에는 파일의 이름을 업로드할 때 (무슨 성격을 띄는지 모르게) 일정규칙을 생성하여 파일을 업로드하고자 함.

1. DATABASE에 TABLE 생성

CREATE TABLE FILETEST

(NUM NUMBER(7) PRIMARY KEY,

SUBJECT VARCHAR2(50) NOT NULL,

SAVEFILENAME VARCHAR2(50),

ORIGINALFILENAME VARCHAR2(50))


2. WebContent에 fileTest 폴더 및 View 생성 

파일 업로드 JSP 페이지 write.jsp

파일이 올라간 리스트 조회 JSP페이지 list.jsp

View - write.jsp

<%@ page contentType="text/html; charset=UTF-8"%>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<%

request.setCharacterEncoding("UTF-8");

String cp = request.getContextPath();

%>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>파일 업로드</title>

</head>

<body>

<form action="<%=cp%>/fileTest.do" method="post" enctype="multipart/form-data">

제목: <input type="text" name="subject"/><br>

파일: <input type="file" name="upload"/><br>

<input type="hidden" name="method" value="write_ok"/>

<input type="submit" value="파일 올리기"/>&nbsp;

<input type="button" value="리스트"

onclick="javascript:location.href='<%=cp%>/fileTest.do?method=list';"/><br>

<!-- button은 onclick 사용, submit은 action찾아가는 것 기억  -->

</form>

</body>

</html>

3. Model - DTO 클래스(FileTestForm Class) 

package com.fileTest;

import org.apache.struts.action.ActionForm;

import org.apache.struts.upload.FormFile;

public class FileTestForm extends ActionForm{

private static final long serialVersionUID = 1L;

private int num;

private String subject;

private String saveFileName;

private String originalFileName;

//FormFile은 아파치에서 제공하는 파일 업로드시 사용하는 클래스

//jsp페이지에서의 input 데이터의 name과 반드시 일치해야 한다.

//파일을 2개 이상 올릴 경우 배열로 처리해서 진행하면 된다.

private FormFile upload;

//일렬번호 재정렬. 중간에 있는 파일이 삭제되더라도 일련번호가 정렬되도록

private int listNum;

//파일의 다운로드 경로

private String urlFile;

getter, setter 생성

}

4. Controller - Struts1의 환경설정

struts-config_fileTest.xml 생성 및 forward 경로 등록

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE struts-config PUBLIC

"-//Apache Software Foundation//DTD Struts Configuration 1.3//EN"

"http://struts.apache.org/dtds/struts-config_1_3.dtd">

       

<struts-config>

<form-beans>

<form-bean name="fileTestForm" type="com.fileTest.FileTestForm"/>

</form-beans>

<action-mappings>

<action path="/fileTest" type="com.fileTest.FileTestAction"

name="fileTestForm" scope="request" parameter="method">

<forward name="write" path="/fileTest/write.jsp"/>

<forward name="write_ok" redirect="true" path="/fileTest.do?method=list"/>

<forward name="list" path="/fileTest/list.jsp"/>

<forward name="delete" redirect="true" path="/fileTest.do?method=list"/>

</action>

</action-mappings>

</struts-config>         


web-xml 등록

<servlet>

<servlet-name>action</servlet-name>

<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>

<init-param>

<param-name>config</param-name>

<param-value>

/WEB-INF/struts-config.xml,

/WEB-INF/struts-config_test.xml,

/WEB-INF/struts-config_board.xml,

/WEB-INF/struts-config_boardTest.xml,

/WEB-INF/struts-config_fileTest.xml

</param-value>

</init-param>

<load-on-startup>2</load-on-startup>

</servlet>

 <servlet-mapping>

<servlet-name>action</servlet-name>

<url-pattern>*.do</url-pattern>

</servlet-mapping>


5. iBatis 셋팅

sqlMap 파일 생성


config 파일 등록 (sqlMapConfig.xml에 등록)

<sqlMap resource="com/util/sqlMap/fileTest_sqlMap.xml"/>


sqlMap(mapper) 작성 (fileTest_sqlMap.xml에 등록)

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE sqlMap

PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"

"http://ibatis.apache.org/dtd/sql-map-2.dtd">

<!-- Mapper -->

<sqlMap namespace="fileTest">

<select id="maxNum" resultClass="Integer">

select nvl(max(num),0) from fileTest

</select>

<!-- 컬럼명이 데이터베이스에 있는 컬럼명과 dto 클래스에 있는 변수명과 상이할 경우

parameterMap="" 속성을 사용한다. 실제로는 많이 사용하지 않음 -->

<insert id="insertData" parameterClass="com.fileTest.FileTestForm" >

insert into fileTest (num,subject,saveFileName,originalFileName)

values (#num#,#subject#,#saveFileName#,#originalFileName#)

</insert>

</sqlMap>

6. Model - DAO 클래스 (FileTestAction Class)

package com.fileTest;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.ActionForm;

import org.apache.struts.action.ActionForward;

import org.apache.struts.action.ActionMapping;

import org.apache.struts.actions.DispatchAction;

public class FileTestAction extends DispatchAction{

//파일 업로드 페이지 호출

public ActionForward write(ActionMapping mapping, ActionForm form,

HttpServletRequest request, HttpServletResponse response) throws Exception {

return mapping.findForward("write");

}

//파일 업로드 등록

public ActionForward write_ok(ActionMapping mapping, ActionForm form,

HttpServletRequest request, HttpServletResponse response) throws Exception {

return mapping.findForward("write_ok");

}

//파일 리스트

public ActionForward list(ActionMapping mapping, ActionForm form,

HttpServletRequest request, HttpServletResponse response) throws Exception {

return mapping.findForward("list");

}

//파일 삭제

public ActionForward delete(ActionMapping mapping, ActionForm form,

HttpServletRequest request, HttpServletResponse response) throws Exception {

return mapping.findForward("delete");

}

//파일 다운로드

public ActionForward download(ActionMapping mapping, ActionForm form,

HttpServletRequest request, HttpServletResponse response) throws Exception {

//다운로드 후 페이지 변동이 없으므로 반환값을 null로 줌

return mapping.findForward(null);

}

}

7. com.util 공용 패키지에 FileManager 클래스 생성

package com.util;

import java.io.File;

import java.io.FileOutputStream;

import java.util.Calendar;

import org.apache.struts.upload.FormFile;

public class FileManager {

//upload

//path : 파일을 저장할 경로

//return : 서버에 저장할 새로운 파일 이름(saveFileName이 됨)

public static String doFileUpload(FormFile uploadFile, String path) throws Exception{

//매개변수로 받는 uploadFile은 originalFileName

String newFileName = null;

if(uploadFile==null){

return null;

}

//클라이언트가 업로드한 파일이름

String originalFileName = uploadFile.getFileName();

//업로드파일 없을경우 반환값도 null

if(originalFileName.equals("")){

return null;

}

//확장자 분리

//abc.txt 일 경우 substring를 통해서 .이후의 확장자에 해당하는 텍스트를 분리해옴

String fileExt = originalFileName.substring(originalFileName.lastIndexOf("."));

//확장자 없을경우 반환값도 null

if(fileExt==null||fileExt.equals("")){

return null;

}

//서버에 저장할 파일명 생성

//매개변수가 원래 %의 갯수만큼 있어야 하는데 1$는 한번만 써도됨

//Y년 m월 d일 H시 M분 S초

newFileName = String.format("%1$tY%1$tm%1$td%1$tH%1$tM%1$tS", Calendar.getInstance());

newFileName += System.nanoTime(); //동일한 파일명이 생성되지 않도록 나노시간까지 반영 10의 -9승

newFileName += fileExt; //확장자 재반영

File f = new File(path);

//디렉토리 없을 경우 생성

if(!f.exists())

f.mkdirs();

String fullFilePath = path + File.separator + newFileName;

//파일 업로드(이 네줄만 있으면 formFile에서 알아서 올려준다.)

byte[] fileData = uploadFile.getFileData();

FileOutputStream fos = new FileOutputStream(fullFilePath);

fos.write(fileData);

fos.close();

return newFileName;

}

}

8. FileTestAction의 write_ok method 수정

//파일 업로드 등록

public ActionForward write_ok(ActionMapping mapping, ActionForm form,

HttpServletRequest request, HttpServletResponse response) throws Exception {

CommonDAO dao = CommonDAOImpl.getInstance();

HttpSession session = request.getSession();

String root = session.getServletContext().getRealPath("/");

String savePath = root + File.separator + "pds" +  File.separator + "saveFile";

FileTestForm f = (FileTestForm)form;

//파일 업로드

String newFileName = FileManager.doFileUpload(f.getUpload(), savePath);

//파일에 대한 정보 추출후 DB반영

if(newFileName!=null){

int maxNum = dao.getIntValue("fileTest.maxNum");

f.setNum(maxNum+1);

f.setSaveFileName(newFileName);

f.setOriginalFileName(f.getUpload().getFileName());

//파일크기 //f.getUpload().getFileSize();

dao.insertData("fileTest.insertData", f);

}

return mapping.findForward("write_ok");

}



리스트 기능 구현, 페이징 처리

1. 리스트 조회 페이지 DAO 작성

fileTest_sqlMap.xml

<!-- 페이징 작업을 위해 where조건 반영 -->

<select id="listData" resultClass="com.fileTest.FileTestForm" parameterClass="map">

<![CDATA[

select * from(

select rownum rnum, data.* from(

select num,subject,saveFileName,originalFileName

from fileTest order by num desc) data)

where rnum>=#start# and rnum<=#end#

]]>

</select>


<!-- 다운로드시 -->

<select id="readData" resultClass="com.fileTest.FileTestForm" parameterClass="int">

select num,subject,saveFileName,originalFileName

from fileTest where num=#num#

</select>

2. list.jsp (view 생성)

<%@ page contentType="text/html; charset=UTF-8"%>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<%

request.setCharacterEncoding("UTF-8");

String cp = request.getContextPath();

%>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>파일 리스트</title>

</head>

<body>

<br/><br/>

<table width="500" align="center">

<tr height="30">

<td align="right">

<input type="button" value="파일올리기"

onclick="javascript:location.href='<%=cp%>/fileTest.do?method=write';"/>

</td>

</tr>

</table>

<table width="500" align="center" border="1" style="font-size: 10pt;">

<tr height="30" align="center">

<td width="50">번호</td>

<td width="200">제목</td>

<td width="200">파일</td>

<td width="50">삭제</td>

</tr>

<c:forEach var="dto" items="${lists}">

<tr height="30" onmouseover="this.style.backgroundColor='#e4e4e4'"

onmouseout="this.style.backgroundColor=''" bgcolor="#ffffff">

<td width="50" align="center">${dto.num}</td>

<td width="200" align="left">${dto.subject}</td>

<td width="200" align="left">

<a href="${dto.urlFile }">${dto.originalFileName}</a>

</td>

<td width="50" align="center">

<a href="<%=cp%>/fileTest.do?method=delete&num=${dto.num}">삭제</a>

</td>

</tr>

</c:forEach>


<c:if test="${totalDataCount==0 }">

<tr bgcolor="#ffffff">

<td align="center" colspan="4">등록된 자료가 없습니다.</td>

</tr>

</c:if>

</table>

<c:if test="${totalDataCount!=0 }">

<table width="600" border="0" cellpadding="3" cellspacing="0" align="center">

<tr align="center">

<td align="center" height="30">${pageIndexList}</td>

</tr>

</table>

</c:if>

</body>

</html>

3. FileTestAction list메소드 작성

//파일 리스트

public ActionForward list(ActionMapping mapping, ActionForm form,

HttpServletRequest request, HttpServletResponse response) throws Exception {

CommonDAO dao = CommonDAOImpl.getInstance();

MyUtil myUtil = new MyUtil();

String cp = request.getContextPath();

int numPerPage = 5;

int totalPage = 0;

int totalDataCount = 0;

String pageNum = request.getParameter("pageNum");

int currentPage = 1;

if(pageNum!=null&&!pageNum.equals("")){

currentPage = Integer.parseInt(pageNum);

}

totalDataCount = dao.getIntValue("fileTest.dataCount");

if(totalDataCount!=0)

totalPage = myUtil.getPageCount(numPerPage, totalDataCount);

if(currentPage>totalPage)

currentPage = totalPage;

Map<String, Object> hMap = new HashMap<String,Object>();

int start = (currentPage-1)*numPerPage+1;

int end = currentPage*numPerPage;

hMap.put("start", start);

hMap.put("end", end);

List<Object> lists = (List<Object>)dao.getListData("fileTest.listData",hMap);

//번호 재정렬 작업

Iterator<Object> it = lists.iterator();

int listNum,n=0;

String str;

while(it.hasNext()){

//전체 데이터 갯수 6개일 때

//리스트번호가 10 8 6 (start=1)/ 5 4 3(start=4) 라 가정

// 1 2 3 / 4 5 6

FileTestForm dto = (FileTestForm)it.next();

listNum = totalDataCount - (start + n - 1) ;

dto.setListNum(listNum);

n++;

//파일 다운로드 경로

str = cp + "/fileTest.do?method=download&num="+dto.getNum();

dto.setUrlFile(str);

}

String urlList = cp + "/fileTest.do?method=list";

request.setAttribute("lists", lists);

request.setAttribute("pageNum", pageNum);

request.setAttribute("totalPage", totalPage);

request.setAttribute("totalDataCount", totalDataCount);

request.setAttribute("pageIndexList", myUtil.pageIndexList(currentPage, totalPage, urlList));

return mapping.findForward("list");

}

일렬번호(listNum) : 단, 한 페이지에 3개의 게시글이 페이징된다는 가정사항

NUM

번호 재정렬

(listNum)

listNum = totalDataCount - (start + n - 1) ;

start

10

6

6 - (1 + 0 - 1)


start = 1

8

5

6 - (1 + 1 - 1)

6

4

6 - (1 + 2 - 1)

5

3

6 - (4 + 0 - 1)


start = 4

4

2

6 - (4 + 1 - 1)

3

1

6 - (4 + 2 - 1)

${dto.num}

${dto.listNum}



파일 삭제 기능 구현

1. sqlMap 수정

<!-- 게시물 카운팅 -->

<select id="dataCount" resultClass="int">

select nvl(count(num),0) from fileTest

</select>


<!-- 삭제 -->

<delete id="deleteData" parameterClass="int">

delete fileTest where num=#num#

</delete>

2. FileManager 클래스에 파일을 삭제하는 메소드 생성

//파일 삭제

public static void doFileDelete(String fileName, String path){

//파일 경로 받기

String fullFilePath = path +  File.separator + fileName;

File f = new File(fullFilePath);

//파일삭제

if(f.exists())

f.delete();

}

3. FileTestAction클래스에 delete 메소드 

//파일 삭제

public ActionForward delete(ActionMapping mapping, ActionForm form,

HttpServletRequest request, HttpServletResponse response) throws Exception {

//DB연결 및 세션가져오기

CommonDAO dao = CommonDAOImpl.getInstance();

HttpSession session = request.getSession();

String root = session.getServletContext().getRealPath("/");

String savePath = root + File.separator + "pds" +  File.separator + "saveFile";

int num = Integer.parseInt(request.getParameter("num"));

//삭제해야하는 데이터 값 읽어오기

FileTestForm dto = (FileTestForm)dao.getReadData("fileTest.readData", num);

String saveFileName = dto.getSaveFileName();

//파일삭제

FileManager.doFileDelete(saveFileName, savePath);

//DB삭제

dao.deleteData("fileTest.deleteData",num);

return mapping.findForward("delete");

}



파일 다운로드 기능 구현

1. FileManager 클래스에 파일을 다운로드하는 메소드 생성

//파일 다운로드

//saveFileName : 서버에 저장된 파일명

//originalFileName : 클라이언트가 업로드한 파일명

//path : 서버에 저장된 경로

public static boolean doFileDownload(String saveFileName,

String originalFileName, String path, HttpServletResponse response){

String fullFilePath = path + File.separator + saveFileName;

try {

if(originalFileName==null||originalFileName.equals("")){

originalFileName = saveFileName;

}

//파일이름이 한글일경우를 위해 작성

//ISO-8859-1 에서 ISO를 생략하게되면 8859_1로 기재

originalFileName = new String(originalFileName.getBytes("euc-kr"),"8859_1");

} catch (Exception e) {

System.out.println(e.toString());

}

try {

File f = new File(fullFilePath);

if(f.exists()){

byte readByte[] = new byte[4096];

//octet-stream은 8비트로된 일련의 데이터. 배열

response.setContentType("application/octet-stream");

response.setHeader("Content-disposition", "attachement;fileName="+ originalFileName);

BufferedInputStream fis = new BufferedInputStream(new FileInputStream(f));

OutputStream os = response.getOutputStream();

int read;

while((read=fis.read(readByte,0,4096))!=-1){

//더이상 읽을 데이터가 없을때까지

os.write(readByte,0,read);

}

os.flush();

os.close();

fis.close();

return true;

}

} catch (Exception e) {

System.out.println(e.toString());

}

return false;

}

2. FileTestAction클래스에 download 메소드  

//파일 다운로드

public ActionForward download(ActionMapping mapping, ActionForm form,

HttpServletRequest request, HttpServletResponse response) throws Exception {

//DB연결 및 세션가져오기

CommonDAO dao = CommonDAOImpl.getInstance();

HttpSession session = request.getSession();

String root = session.getServletContext().getRealPath("/");

String savePath = root + File.separator + "pds" +  File.separator + "saveFile";

int num = Integer.parseInt(request.getParameter("num"));

//다운로드 받을 데이터값 읽어오기

FileTestForm dto = (FileTestForm)dao.getReadData("fileTest.readData", num);

   if(dto==null){

return mapping.findForward("list");

}

//다운로드 진행

boolean flag = FileManager.doFileDownload(dto.getSaveFileName(),

dto.getOriginalFileName(), savePath, response);

if(!flag){

//다운로드 받지 못했을 시 실행

response.setContentType("text/html;charset=UTF-8");

PrintWriter out = response.getWriter();

out.print("<script type='text/javascript'>");

out.print("alert('다운로드 에러!!!')");

out.print("history.back()");

out.print("</script>");

}

//다운로드 후 페이지 변동이 없으므로 반환값을 null로 줌

return mapping.findForward(null);

}

3. list.jsp 페이지에서의 경로 



'Dev > Struts' 카테고리의 다른 글

Struts2 - 입출력 기능 구현, Struts1과2 비교  (0) 2019.03.22
Struts2 세팅  (0) 2019.03.21
Struts1/iBatis - 게시판 만들기  (2) 2019.03.20
iBatis(2.0) 및 log4j 세팅  (0) 2019.03.20
Struts1/JDBC - 게시판 만들기  (2) 2019.03.19