본문 바로가기
Spring

이미지 업로드 + 예외처리

by amoomar 2022. 4. 12.
반응형

 

목차는 아래와 같다.

1. 이미지 업로드
   1) V
   2) C
   3) M

2. 예외처리
   1) @활용
   2) xml활용

 

 

1. 이미지 업로드

각 파트별 수행할 행동으로 나누어 설명할 예정이다.

 

1) V

 

① form 생성

파일을 업로드할 수 있는 form을 생성하고, 이미지의 경우 인코딩설정이 필요하다. 이때 controller에서 해당 파일을 전달 받을 수 있도록 name설정이 반드시 필요하다. 예시코드는 아래와 같다.

<form action="insert.do" method="POST" enctype="multipart/form-data"><!-- 이미지 인코딩설정 -->
	<input type="file" name="img_tattoo"/>
</from

 

 


 

2) C

파일을 받는데에는 총 두가지의 방법이 있다. 포스팅의 경우 두 번째 방법으로 시행한다.
1) @requestParameter을 인자로 추가하기
2) vo내부에 그냥 받아올 수 있도록 쓰기

 

① VO추가

기존의 데이터들을 String 타입으로 관리하지만, 스프링 프레임 워크에서 제공하는 MultipartFile타입으로 인코딩 된 데이터를 관리해야한다. 임폴트가 필요하다.

package com.ham.app.vo;

import org.springframework.web.multipart.MultipartFile;

public class ArticleVO {

	// 멤버변수
	private MultipartFile uploadFile; //타투 이미지
	
	// getter & setter
	public MultipartFile getUploadFile() {
		return uploadFile;
	}
	public void setUploadFile(MultipartFile uploadFile) {
		this.uploadFile = uploadFile;
	}
	
	// to string
	@Override
	public String toString() {
		return "ArticleVO [uploadFile=" + uploadFile + "]";
	}
	
}

 


 

② 라이브러리 추가

MultipartFile타입의 등장으로 라이브러리가 필요하다. pom.xml에 추가될 코드는 아래와 같다.

	<!-- 파일업로드 -->
	<dependency>
		<groupId>commons-fileupload</groupId>
		<artifactId>commons-fileupload</artifactId>
		<version>1.3.1</version>
	</dependency>
    <!-- ============================================== -->

 

 

첨부된 이미지와 같이 라이브러리가 추가되었다면 설정 설공이다.

라이브러리

 

 


 

③ Resolver추가

MultipartFile타입을 다루기 위한 Resolver가 필요해진다. dispatcherServlet-servlet.xml파일에 추가된 설정 코드는 다음과 같다. 주석을 통해 내용 이해가 가능하다.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd">

	<context:component-scan base-package="com.ham.app.controller"/>

	<!-- 파일업로드 설정 --> <!-- id가 지정되어있기 때문에, 해당 id가 아니라면 설정 등록이 안될지 모른다. -->
	<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
		<property name="maxUploadSize" value="-1"/><!-- 무제한! : 디폴트 설정이라 작성하지 않아도 동일한 값을 부여한다. -->
	</bean>

</beans>

 

 


 

 

④ 로직 추가

transferTo메서드를 활용하여 지정한 위치에 파일을 생성해줄 수 있다. 

	@RequestMapping(value = "/insert.do")
	public String insert_article (ArticleVO vo, ArticleDAO dao) throws IllegalStateException, IOException {
		
		//파일 업로드 로직
		MultipartFile uploadFile=vo.getUploadFile();
		
		// 비어있지 않다면, 로직 수행
		if(!uploadFile.isEmpty()) {// !=null로도 체크 가능하지만, 해당 방법을 더 선호하기도 함
			//파일명
			String name=uploadFile.getOriginalFilename();
	       	 vo.setFilename(name);
			uploadFile.transferTo(new File("/Users/hamjeonghui/Desktop/java/workspace_2/tni/src/main/webapp/img_tattoo/"+name)); // 인자로 입력된 위치에 파일을 생성해주는 메서드이다.
		}
		
		boolean flag=dao.insert_article(vo);
		
		if(flag==true) { //성공
			return "redirect: main.do"; //해당 디테일 페이지로 이동
		}else { //실패
			return "redirect: main.do";
		}
	}

 

 

 


 

3) M

파일명을 가지고 다닐 칼럼을 추가한다. 이때, vo는 String타입으로 별도로 필요하게 되며 기존에 사용되던 dao의 sql문 등에 수정이 필요하다.

테이블

 

 

 

① VO

command객체 활용으로 파일 입출력을 용이하게 할 목적으로 생성한 MultipartFile타입의 멤버변수 외에 table로 가지고 다닐 String 타입의 멤버변수를 추가하여 생성한다. (해당 코드 외에 삭제)

package com.ham.app.vo;

import org.springframework.web.multipart.MultipartFile;

public class ArticleVO {

	// 멤버변수
	private MultipartFile uploadFile; //타투 이미지
	private String filename; //타투 이미지 파일 이름
	
	// getter & setter
	public MultipartFile getUploadFile() {
		return uploadFile;
	}
	public void setUploadFile(MultipartFile uploadFile) {
		this.uploadFile = uploadFile;
	}
	public String getFilename() {
		return filename;
	}
	public void setFilename(String filename) {
		this.filename = filename;
	}
	
	// to string
	@Override
	public String toString() {
		return "uploadFile=" + uploadFile + ", filename=" + filename + "]";
	}
	
}

 

 


 

 

② DAO

sql문의 insert부분과 update부분을 변경하고, select부분의 rs.getString을 추가한다.

package com.ham.app.dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;

import org.springframework.stereotype.Repository;

import com.ham.app.common.JDBCUtil;
import com.ham.app.vo.ArticleSet;
import com.ham.app.vo.ArticleVO;
import com.ham.app.vo.CommentVO;

@Repository("articleDAO")
// comment의 DAO도 함께 수행할 클래스
public class ArticleDAO {

	//트랜잭션: executeQuery,executeUpdate()등의 sql문 적용을 하나의 작업처리단위로  수행해야할때 사용
	// -> 하나의 dao비즈니스메서드() 안에서 여러번 sql문을 수행해야할때 사용
	
	private Connection conn=null;
	private PreparedStatement pstmt=null;
	private ResultSet rs= null;

	private final String ARTICLE_INSERT="insert into article (uid, uname, title, acontent, part, leadTime, addr, filename) values (?,?,?,?,?,?,?,?)";//댓글 등록

	// 게시글 등록
	public boolean insert_article(ArticleVO vo) {
		boolean flag = false;
		conn = JDBCUtil.connect();
		try {
			pstmt = conn.prepareStatement(ARTICLE_INSERT);
			pstmt.setString(1, vo.getUid());
			pstmt.setString(2, vo.getUname());
			pstmt.setString(3, vo.getTitle());
			pstmt.setString(4, vo.getAcontent());
			pstmt.setString(5, vo.getPart());
			pstmt.setString(6, vo.getLeadTime());
			pstmt.setString(7, vo.getAddr());
			pstmt.setString(8, vo.getFilename());
			// 등록이 성공하면,
			if(pstmt.executeUpdate()>0) {
				System.out.println("dao: 게시글 등록 성공"+vo.getFilename());
				flag = true;
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			JDBCUtil.disconnect(pstmt, conn);
		}
		return flag;
	}
}

 

package com.ham.app.dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;

import org.springframework.stereotype.Repository;

import com.ham.app.common.JDBCUtil;
import com.ham.app.vo.ArticleSet;
import com.ham.app.vo.ArticleVO;
import com.ham.app.vo.CommentVO;

@Repository("articleDAO")
// comment의 DAO도 함께 수행할 클래스
public class ArticleDAO {

	//트랜잭션: executeQuery,executeUpdate()등의 sql문 적용을 하나의 작업처리단위로  수행해야할때 사용
	// -> 하나의 dao비즈니스메서드() 안에서 여러번 sql문을 수행해야할때 사용
	
	private Connection conn=null;
	private PreparedStatement pstmt=null;
	private ResultSet rs= null;

	private final String ARTICLE_SELECTALL_FAV="select * from article where aid=? order by aid desc";//aid에 해당하는 게시글 목록

	// aid에 해당하는 게시글 목록 보기
	public ArticleVO get_article_fav(ArticleVO vo){
		System.out.println("해당하는 게시글");
		ArticleVO data = new ArticleVO();
		conn = JDBCUtil.connect();
		try {
			pstmt = conn.prepareStatement(ARTICLE_SELECTALL_FAV);
			pstmt.setInt(1, vo.getAid());
			rs = pstmt.executeQuery();

			if(rs.next()) {
				data.setAid(rs.getInt("aid"));
				data.setUid(rs.getString("uid"));
				data.setUname(rs.getString("uname"));
				data.setTitle(rs.getString("title"));
				data.setAcontent(rs.getString("acontent"));
				data.setPart(rs.getString("part"));
				data.setLeadTime(rs.getString("leadTime"));
				data.setAddr(rs.getString("addr"));
				data.setCnt(rs.getInt("cnt"));
				data.setFav(rs.getInt("fav"));
				data.setRcnt(rs.getInt("rcnt"));
				data.setAdate(rs.getString("adate"));
				data.setFilename(rs.getString("filename"));
				System.out.println("목록불러오는 중");
			}
			rs.close();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			JDBCUtil.disconnect(pstmt, conn);
		}
		System.out.println("목록 불러오기 완료");
		return data;
	}

}

 

 

설명 외 부분은 삭제하였다.

 

 

view에서는 알맞은 EL식을 통해 해당 이미지를 확인할 수 있다.

 

 


 

 

2. 예외처리

발생한 예외에 대하여 에러페이지로 이동할 수 있도록 하는데에 있어 방법은 @을 활용한 것과 xml을 활용한 것으로 총 두가지가 있다. 보편적으로 xml을 활용한 방법으로 사용되지만, @으로도 적용할 수 있는 방법도 함께 포스팅 하였다.

 

 

1) @활용

 

① 어노테이션 설정

viewResolver의 관여 아래에서 작업되기 때문에 DispatcherServlet-servlet.xml에서 예외 처리를 위한 어노테이션을 설정할 수 있도록 사전처리가 필요하다.

 

 

nameSpace에서 mvc를 선택하여 추가해준다.

nameSpace설정

 

 

 

주석을 통해 기존 코드외 추가 된 내용을 첨부하였다.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd">

<context:component-scan base-package="com.test.app.controller" />

<!-- 예외 처리 관련 어노테이션 사용을 위한 코드 -->
<mvc:annotation-driven></mvc:annotation-driven>

</beans>

 

 

 


 

 

② 에러페이지를 매핑하는 클래스 추가

어떤 예외에 대해 어떤 처리를 할 것인지를 묶어줄 목적으로 클래스를 생성하여, 해당 클래스의 메서드를 통해 처리가 될 수 있도록 한다. 일단 메서드 수행을 위해서는 아래 클래스가 초기화 되어있어야하므로, 어노테이션을 활용하여 초기화를 진행한다. 이때 @Componenet로도 물론 초기화가 가능하지만, @Component를 상속받아 예외와 관련된 설정을 더 효율적으로 수행할 수 있는 @ControllerAdvice를 사용할 수 있다. 다음 순서로 메서드를 작성해주는데, output을 String으로 하여 예외페이지의 경로만 반환해주어도 되지만, 예외에 대한 내용또한 반환해줄 목적이라면 내용도 함께 전달해주어야하므로 output을 ModelAndView로 대체하여 설정해줄 수 있다. 이때 사용되는 @ExceptionHandler를 메서드 상단에 작성해줌으로써 어떤 예외에 대해 어떤 메서드를 수행할 것인지를 지정해줄 수 있다.

package com.test.app.common;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;

@ControllerAdvice("com.test.app") // 메서드 수행을 위해 객체화 되어있어야하므로, 어노테이션으로 객체화 진행
public class ExceptionHandlerCommon {
// 어떤 예외에 대해 어떤 처리를 할 것인지를 작성
	
	@ExceptionHandler(IllegalArgumentException.class)//requestMapping과 유사한 역할을 한다.
	public ModelAndView a(Exception e) {
		// 어떤 페이지로 전달해줄것인지를 작성
		ModelAndView mav=new ModelAndView(); //어떤 예외인지를 전달하고자 mav를 사용 -> String으로 경로만 전달하긴 어렵기 때문이다.
		mav.addObject("excep", e);
		mav.setViewName("/error/error.jsp");
		return mav;
	}
	
	@ExceptionHandler(Exception.class)//requestMapping과 유사한 역할을 한다.
	public ModelAndView b(Exception e) {
		// 어떤 페이지로 전달해줄것인지를 작성
		ModelAndView mav=new ModelAndView(); //어떤 예외인지를 전달하고자 mav를 사용 -> String으로 경로만 전달하긴 어렵기 때문이다.
		mav.addObject("excep", e);
		mav.setViewName("/error/error.jsp");
		return mav;
	}
	
}

 

 

 


 

③ 에러페이지

에러페이지의 경우 이 페이지가 에러페이지인지를 명시해주기 위해 페이지 지시어를 활용하여 설정이 가능하다. 또한 .message메서드를 통해 해당 예외에 대한 문구를 확인할 수 있다.

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" isErrorPage="true"%> <!-- 에러페이지임을 알려주기 -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>에러페이지</title>
</head>
<body>

<!-- 예외페이지들은 모두 .message라는 메서드를 통해 예외에 대한 내용을 확인해볼 수 있다. -->
<h1>${excep.message}</h1>

</body>
</html>

 

 


 

 

2) xml활용

DispatcherServlet-servlet.xml파일에서 모든 설정을 끝낼 수 있다. 주석을 통해 내용을 이해할 수 있으며, error.jsp페이지에 대한 설정은 위와 동일하다.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd">

<context:component-scan base-package="com.test.app.controller" />

<!-- 예외 관리를 위한 Spring지원 클래스 -->
<bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
  	<!-- 기본 설정! 어떤 예외에 대해 어떤 페이지를 매핑할 것인지를 설정함 -->
   <property name="exceptionMappings">
   	<props>
   		<prop key="java.lang.IllegalArgumentException">
   			error/error.jsp
   		</prop>
   	</props>
   </property>
   <!-- 디폴트 값 생성 -->
   <property name="defaultErrorView" value="error/error2.jsp" />
</bean>

</beans>

 

 

단, ModelAndView와 같은 별도 설정이 없으므로 view에서 에러에 대한 메세지를 확인하고 싶다면 아래와 같은 EL식을 사용할 수 있다.

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" isErrorPage="true"%> <!-- 에러페이지임을 알려주기 -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>에러페이지</title>
</head>
<body>

<!-- 예외페이지들은 모두 .message라는 메서드를 통해 예외에 대한 내용을 확인해볼 수 있다. -->
<h1>${exception.message}</h1>

</body>
</html>

 

 


 

반응형

'Spring' 카테고리의 다른 글

[Mybatis] Mybatis설치 및 개요_DAO3  (0) 2022.04.18
다국어 처리 : 국제화  (0) 2022.04.13
[레이어] 비즈니스 컴포넌트  (0) 2022.04.11
[AOP] 트랜잭션 관리자  (2) 2022.04.08
[AOP] 다양한 어노테이션 : Controller_3  (0) 2022.04.07