관리 메뉴

거니의 velog

231201_SPRING 2 (8-1) 본문

대덕인재개발원/대덕인재개발원_웹기반 애플리케이션

231201_SPRING 2 (8-1)

Unlimited00 2023. 12. 1. 08:31

* 파일 업로드

package kr.or.ddit.controller.file.item01;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Controller
@RequestMapping("/item")
public class FIleUploadController01 {

	/*
	 * [ 13장. 파일 업로드 ]
	 * 
	 * 		1. 파일 업로드 설명
	 * 
	 * 			- 서블릿 3.0에서 지원하는 파일 업로드 기능과 스프링 웹에서 제공하는 컴포넌트를 사용하여 파일을 업로드 한다.
	 * 
	 * 			# 파일 업로드 설정
	 * 
	 * 				1) 서블릿 3.0 이상 지원
	 * 				2) 서블릿 표준 파일 업로드 기능을 활성화
	 * 				3) 스프링 MVC와 연계
	 * 				4) 업로드 된 파일 저장 위치 설정
	 * 
	 * 			# 환경 설정
	 * 
	 * 				1) 의존 관계 정의
	 * 				- 파일을 처리하기 위해서 의존 라이브러리를 추가한다.
	 * 					> pom.xml commons-io 추가
	 * 
	 * 				2) 웹 컨테이너 설정
	 * 					> web.xml 서블릿 표준 버전 3.1로 설정
	 * 					> multipart-config 활성화 (web.xml의 servlet 태그 내 설정)
	 * 
	 * 				3) 스프링 웹 설정
	 * 					> servlet-context.xml
	 * 					> multipartResolver Bean 등록 (id는 multipartResolver로 설정)
	 * 
	 * 					[파일 업로드 설정]
	 * 					파일 업로드를 설정하는 방식은 2가지가 있다.
	 * 
	 * 					- StandardServletMultipartResolver 사용 시 설정.
	 * 						> servlet 3.0의 Part를 이용한 MultipartFile 데이터 처리
	 * 						> servlet-context.xml 에 설정
	 * 							> StandardServletMultipartResolver bean 등록
	 * 						> web.xml에 설정
	 * 							> multipart-config (servlet 태그 안에 설정)
	 * 
	 * 					- CommonsMultipartResolver 사용 시 설정. ( 우리가 사용할 방식 )
	 * 						> Commons Fileupload API를 이용한 MultipartFile 데이터 처리
	 * 						> bean 속성으로 maxUploadSize, maxInMemorySize 및 defaultEncoding 설정을 제공
	 * 						> 기본값 및 허용되는 값에 대한 자세한 내용은 각 DiskFileUpload 속성을 참조
	 * 						> pom.xml 설정
	 * 							> commons-fileupload 추가
	 * 						> root-context.xml에 설정
	 * 							> CommonsMultipartResolver bean 등록
	 * 
	 * 					- root-context.xml 에 설정
	 * 						> uploadPath bean 등록
	 * 
	 * 					- multipartFilter 필터 등록
	 * 						> web.xml
	 * 
	 * 		# 데이터베이스 준비
	 * 
	 * 			- item 테이블 생성 (item, item2, item3, item3_attach)
	 * 
	 * 		2. 이미지 업로드
	 * 
	 * 			- 한 개의 이미지를 업로드 하는 기본 파일 업로드 기능을 구현한다.
	 * 
	 * 			# 파일 업로드 구현 설명
	 * 
	 * 				- 파일 업로드 등록 화면 컨트롤러 만들기 (FileUploadController01)
	 * 				- 파일 업로드 등록 화면 컨트롤러 메소드 만들기 (itemRegisterForm:get)
	 * 				- 파일 업로드 등록 화면 만들기 (item/register.jsp)
	 * 				- 여기까지 확인
	 * 
	 * 				- 파일 업로드 등록 기능 컨트롤러 메소드 만들기 (itemRegister:post)
	 * 				- 파일 업로드 등록 기능 서비스 인터페이스 메소드 만들기
	 * 				- 파일 업로드 등록 기능 서비스 클래스 메소드 만들기
	 * 				- 파일 업로드 등록 기능 Mapper 인터페이스 메소드 만들기
	 * 				- 파일 업로드 등록 기능 Mapper xml 쿼리 만들기
	 * 				- 파일 업로드 등록 완료 페이지 만들기
	 * 				- 여기까지 확인
	 * 
	 * 				- 파일 업로드 목록 화면 컨트롤러 메소드 만들기 (itemList:get)
	 * 				- 파일 업로드 목록 화면 서비스 인터페이스 메소드 만들기
	 * 				- 파일 업로드 목록 화면 서비스 클래스 메소드 만들기
	 * 				- 파일 업로드 목록 화면 Mapper 인터페이스 메소드 만들기
	 * 				- 파일 업로드 목록 화면 Mapper xml 쿼리 만들기
	 * 				- 파일 업로드 목록 화면 만들기 (item/list.jsp)
	 * 				- 여기까지 확인
	 * 
	 * 				- 파일 업로드 수정 화면 컨트롤러 메소드 만들기 (itemModifyForm:get)
	 * 				- 파일 업로드 수정 화면 서비스 인터페이스 메소드 만들기
	 * 				- 파일 업로드 수정 화면 서비스 클래스 메소드 만들기
	 * 				- 파일 업로드 수정 화면 Mapper 인터페이스 메소드 만들기
	 * 				- 파일 업로드 수정 화면 Mapper xml 쿼리 만들기
	 * 				- 파일 업로드 수정 화면 만들기 (item/modify.jsp)
	 *				- 여기까지 확인
	 *
	 *				- 파일 업로드 수정 기능 컨트롤러 메소드 만들기 (itemModify:post)
	 *				- 파일 업로드 수정 기능 서비스 인터페이스 메소드 만들기
	 * 				- 파일 업로드 수정 기능 서비스 클래스 메소드 만들기
	 * 				- 파일 업로드 수정 기능 Mapper 인터페이스 메소드 만들기
	 * 				- 파일 업로드 수정 기능 Mapper xml 쿼리 만들기
	 *				- 여기까지 확인
	 *
	 *				- 파일 업로드 삭제 화면 컨트롤러 메소드 만들기 (itemRemoveForm:get)
	 *				- 파일 업로드 삭제 화면 서비스 인터페이스 메소드 만들기
	 * 				- 파일 업로드 삭제 화면 서비스 클래스 메소드 만들기
	 * 				- 파일 업로드 삭제 화면 Mapper 인터페이스 메소드 만들기
	 * 				- 파일 업로드 삭제 화면 Mapper xml 쿼리 만들기
	 * 				- 파일 업로드 삭제 화면 만들기 (item/remove.jsp)
	 *				- 여기까지 확인
	 *
	 *				- 파일 업로드 삭제 기능 컨트롤러 메소드 만들기 (itemRemove:post)
	 *				- 파일 업로드 삭제 기능 서비스 인터페이스 메소드 만들기
	 * 				- 파일 업로드 삭제 기능 서비스 클래스 메소드 만들기
	 * 				- 파일 업로드 삭제 기능 Mapper 인터페이스 메소드 만들기
	 * 				- 파일 업로드 삭제 기능 Mapper xml 쿼리 만들기
	 * 				- 여기까지 확인
	 */
	
}

[pom.xml]

		<!--  
			파일을 처리하기 위한 라이브러리 의존 관계 정의
		-->
		<dependency>
			<groupId>commons-io</groupId>
			<artifactId>commons-io</artifactId>
			<version>2.6</version>
		</dependency>
		
		<!--  
			파일 업로드를 처리하기 위한 라이브러리 의존 관계 정의
		-->
		<dependency>
			<groupId>commons-fileupload</groupId>
			<artifactId>commons-fileupload</artifactId>
			<version>1.3.2</version>
		</dependency>

[servlet-context.xml]

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

	<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
	
	<!-- Enables the Spring MVC @Controller programming model -->
	<annotation-driven />

	<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
	<resources mapping="/resources/**" location="/resources/" />

	<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
	<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<beans:property name="prefix" value="/WEB-INF/views/" />
		<beans:property name="suffix" value=".jsp" />
		<beans:property name="order" value="2" />
	</beans:bean>
	
	<!-- Tiles 설정을 위한 Bean 등록 시작 -->
	<beans:bean id="tilesViewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
		<beans:property name="viewClass" value="org.springframework.web.servlet.view.tiles3.TilesView" />
		<beans:property name="order" value="1" />
	</beans:bean>
	
	<beans:bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles3.TilesConfigurer">
		<beans:property name="definitions">
			<beans:list>
				<beans:value>/WEB-INF/spring/tiles-config.xml</beans:value>
			</beans:list>
		</beans:property>
	</beans:bean>
	<!-- Tiles 설정을 위한 Bean 등록 끝 -->
	
	<context:component-scan base-package="kr.or.ddit" />
	
	<!--  
		서블릿 표준용 MultipartResolver 를 스프링 빈으로 정의
		- StandardServletMultipartResolver 사용 시 설정
			> Servlet 3.0의 Part를 이용한 MultipartFile 데이터 처리
	-->
<!-- 	<beans:bean id="multipartResolver" class="org.springframework.web.multipart.support.StandardServletMultipartResolver">
		
	</beans:bean> -->
	
	
	
</beans:beans>

[web.xml]

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_3_1.xsd">

	<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/spring/root-context.xml</param-value>
	</context-param>
	
	<!-- Creates the Spring Container shared by all Servlets and Filters -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

	<!-- Processes application requests -->
	<servlet>
		<servlet-name>appServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
		
		<!--  
			web.xml의 설정은 WAS(Tomcat) 자체 설정일 뿐이다.
			multipart-config : 메모리 사이즈, 업로드 파일 저장 위치, 최대 크기 설정
			- location : 저장될 디렉토리(필수)
			- max-file-size : 업로드 파일 최대 크기(기본값 : -1L, 제한이 없다)
			- max-request-size : 한번 요청 시 업로드 파일 최대 크기
			- file-size-threshold : 설정 크기가 넘는 경우 임시 디렉토리에 저장(기본값 0, 설정하지 않는 한 무조건 저장)
			
			web.xml에서 설정하지 않을 때는 @MultipartConfig 어노테이션으로 설정이 가능하다.
			- 요청을 받는 컨트롤러에 설정이 가능하다. (메소드 라인이 아니라 컨트롤러인 클래스 라인에 설정한다)
			- @MultipartConfig(
				  location = "D:/upload",
				  maxFileSize = "24683394",
				  maxRequestSize = "478212294",
				  fileSizeThreshold = "154985741"
			  )
			  
			  임시 파일이 저장되는 경로는 다음과 같다.
			 - C:\Users\개인PC이름\AppData\Local\Temp=
		-->
<!-- 		<multipart-config>
			<location>C:\\upload</location>
			<max-file-size>24683394</max-file-size>
			<max-request-size>478212294</max-request-size>
			<file-size-threshold>154985741</file-size-threshold>
		</multipart-config> -->
	</servlet>

[root-context.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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
	
	<!-- Root Context: defines shared resources visible to all other web components -->
	
	<!--  
		root-context.xml : 스프링 설정을 위한 파일
		
		스프링 설정이란?
		- view와 관련되지 않은 객체를 정의
		- service(비즈니스 기능), DAO(repository: 저장소), DB 등 비즈니스 로직과 관련된 설정
		- BasicDataSource dataSource = new BasicDataSource();
		  dataSource.setDriverClassName("oracle.jdbc.driver.OracleDriver");
	-->
	
	<!-- dataSource : 데이터베이스와 관련된 정보를 설정한다. -->
	<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
		<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
		<property name="url" value="jdbc:oracle:thin:@localhost:1521:xe" />
		<property name="username" value="spring2" />
		<property name="password" value="java" />
	</bean>
	
	<!--  
		데이터베이스와 연결을 맺고 끊어질 때까지의 라이프 사이클을 관리해주는 SqlSessionTemplate 객체를 생성한다.
		1) dataSource
		2) Mapper xml 위치 지정
		3) 마이바티스 설정 위치 지정
	-->
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<property name="mapperLocations" value="classpath:/sqlmap/**/*_SQL.xml" />
		<property name="configLocation" value="/WEB-INF/mybatisAlias/mybatisAlias.xml" />
	</bean>
	
	<!--  
		데이터베이스에 쿼리를 실행시키는 객체
		이 객체를 통해서 query를 실행한다.
	-->
	<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
		<constructor-arg name="sqlSessionFactory" index="0" ref="sqlSessionFactory" />
	</bean>
	
	<!--  
		Mapper 인터페이스 설정
		개발자가 직접 DAO를 설정하지 않아도 자동으로 Mapper 인터페이스를 활용하는 객체를 생성하게 된다.
	-->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="basePackage" value="kr.or.ddit.mapper" />
	</bean>
	
	<!--  
		MultipartFile CommonsMultipartResolver 설정 시
	-->
	<bean id="MultipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
		<!-- 하나의 요청당 파일 업로드 용량(3145728) -->
		<property name="maxUploadSize" value="3145728" />
		<!-- 메모리에 저장되는 최대 용량 -->
		<property name="maxInMemorySize" value="3145728" />
		<property name="defaultEncoding" value="UTF-8" />
	</bean>
	
	<!-- 파일 업로드 디렉토리 설정 -->
	<bean id="uploadPath" class="java.lang.String">
		<constructor-arg value="D:\A_TeachingMaterial\07_JSP_Spring\workspace\workspace_spring2\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\Spring2Project\resources\upload" />
	</bean>
		
</beans>

[web.xml]

	<!--  
		MultipartFilter 적용 : 파일 업로드를 위한 필터 적용
		- MultipartFilter의 역할은 들어온 요청이 multipart/form-data 유형의 요청인지를 확인하여 multipart 형태의 요청이면
		MultipartResolver를 통해 multipart 요청을 확인한다.
		그리고 해당 요청이 적절한 요청이면 MultipartHttpServletRequest로 랩핑한다.
		- MultipartFilter의 기본 빈 이름은 'filterMultipartResolver'이다.
	-->
	<filter>
		<filter-name>MultipartFilter</filter-name>
		<filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>MultipartFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

-- 파일 업로드
-- item table 생성
create table item(
    item_id number(10) not null,
    item_name VARCHAR2(150) null,
    price number(10) null,
    description VARCHAR2(500) null,
    picture_url VARCHAR2(400) null,
    CONSTRAINT pk_item PRIMARY KEY(item_id)
);

-- item sequence 생성
create sequence seq_item increment by 1 start with 1 nocache;

-- item2 table 생성
create table item2(
    item_id number(10) not null,
    item_name VARCHAR2(150) null,
    price number(10) null,
    description VARCHAR2(500) null,
    picture_url VARCHAR2(400) null,
    picture_url2 VARCHAR2(400) null,
    CONSTRAINT pk_item2 PRIMARY KEY(item_id)
);

-- item sequence 생성
create sequence seq_item2 increment by 1 start with 1 nocache;

-- item3 table 생성
create table item3(
    item_id number(10) not null,
    item_name VARCHAR2(150) null,
    price number(10) null,
    description VARCHAR2(500) null,
    CONSTRAINT pk_item3 PRIMARY KEY(item_id)
);

-- item sequence 생성
create sequence seq_item3 increment by 1 start with 1 nocache;

-- item3_attach table 생성
create table item3_attach(
    fullname VARCHAR2(400) not null,
    item_id number(10) not null,
    regdate date not null,
    CONSTRAINT pk_item3_attach PRIMARY KEY(fullname),
    CONSTRAINT fk_item3_attach_item_no foreign key(item_id) references item3(item_id)
);

commit;


package kr.or.ddit.controller.file.item01;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Controller
@RequestMapping("/item")
public class FIleUploadController01 {
	
	//@GetMapping("/register")
	@RequestMapping(value = "/register", method = RequestMethod.GET)
	//@PostMapping("/register")
	public String itemRegisterForm(Model model) {
		// 스프링 form 태그를 이용한다면, modelAttribute 속성에 연결된 item 자바 객체와의 연결을 위함
		// 스프링 form 태그를 활용한다면 아래와 같이 순환체계를 연결하기 위해서 model에 데이터를 담아 클라이언트로 보낸다.
//		model.addAttribute("item", new Item());
		return "item/register";
	}
	
}

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>ITEM</title>
	</head>
	<body>
		<h2>REGISTER</h2>
		<form action="/item/register" method="post" enctype="multipart/form-data">
			<table border="1">
				<tr>
					<td>상품명</td>
					<td><input type="text" name="itemName" id="itemName" /></td>
				</tr>
				<tr>
					<td>가격</td>
					<td><input type="text" name="price" id="price" /></td>
				</tr>
				<tr>
					<td>파일</td>
					<td><input type="file" name="picture" id="picture" /></td>
				</tr>
				<tr>
					<td>개요</td>
					<td><textarea rows="10" cols="30" wrap="soft" name="description" id="description"></textarea></td>
				</tr>
			</table>
			<div>
				<button type="submit" id="registerBtn">Register</button>
				<button type="button" id="listBtn" onclick="javascript:location.href='/item/list'">List</button>
			</div>
		</form>
	</body>
</html>

- http://localhost/item/register


package kr.or.ddit.vo;

import org.springframework.web.multipart.MultipartFile;

import lombok.Data;

@Data
public class Item {

	private int itemId;
	private String itemName;
	private int price;
	private String description;
	private MultipartFile picture;
	private String pictureUrl;
	
}
package kr.or.ddit.controller.file.item01;

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

import javax.annotation.Resource;
import javax.inject.Inject;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.multipart.MultipartFile;

import kr.or.ddit.service.IItemService;
import kr.or.ddit.vo.Item;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Controller
@RequestMapping("/item")
public class FIleUploadController01 {
	
	// root-context.xml에서 설정한 uploadPath 빈등록 path 경로를 사용한다.
	@Resource(name = "uploadPath")
	private String resourcePath;
	
	@Inject
	private IItemService itemService;
	
	//@GetMapping("/register")
	@RequestMapping(value = "/register", method = RequestMethod.GET)
	//@PostMapping("/register")
	public String itemRegisterForm(Model model) {
		// 스프링 form 태그를 이용한다면, modelAttribute 속성에 연결된 item 자바 객체와의 연결을 위함
		// 스프링 form 태그를 활용한다면 아래와 같이 순환체계를 연결하기 위해서 model에 데이터를 담아 클라이언트로 보낸다.
//		model.addAttribute("item", new Item());
		return "item/register";
	}
	
	@RequestMapping(value = "/register", method = RequestMethod.POST)
	public String itemRegister(Item item, Model model) throws IOException {
		MultipartFile file = item.getPicture();
		
		log.info("originalName : " + file.getOriginalFilename());
		log.info("size : " + file.getSize());
		log.info("contentType : " + file.getContentType());
		
		// 넘겨 받은 파일을 이용하여 파일 업로드(복사)를 진행한다.
		// return : UUID + "_" + 원본 파일명
		String createdFileName = uploadFile(file.getOriginalFilename(), file.getBytes());
		
		item.setPictureUrl(createdFileName);
		itemService.register(item);
		model.addAttribute("msg", "등록이 완료되었습니다.");
		return "item/success";
	}
	
	
	private String uploadFile(String originalName, byte[] fileData) throws IOException {
		UUID uuid = UUID.randomUUID(); // UUID로 파일명 생성
		// UUID + "_" + 원본 파일명
		String createdFileName = uuid.toString() + "_" + originalName;
		
		File file = new File(resourcePath);
		if(!file.exists()) {
			file.mkdirs();
		}
		
		File target = new File(resourcePath, createdFileName); // 파일 업로드 준비
		FileCopyUtils.copy(fileData, target); // 파일 복사 진행
		return createdFileName;
	}
	
}

package kr.or.ddit.service;

import kr.or.ddit.vo.Item;

public interface IItemService {

	public void register(Item item);

}

package kr.or.ddit.service.impl;

import javax.inject.Inject;

import org.springframework.stereotype.Service;

import kr.or.ddit.mapper.IItemMapper;
import kr.or.ddit.service.IItemService;
import kr.or.ddit.vo.Item;

@Service
public class ItemServiceImpl implements IItemService {

	@Inject
	private IItemMapper mapper;
	
	@Override
	public void register(Item item) {
		mapper.create(item);
	}

}

package kr.or.ddit.mapper;

import kr.or.ddit.vo.Item;

public interface IItemMapper {

	public void create(Item item);

}

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="kr.or.ddit.mapper.IItemMapper">
	
	<insert id="create" parameterType="item">
		insert into item (
			item_id, item_name, price, description, picture_url
		) values (
			seq_item.nextval, #{itemName}, #{price}, #{description}, #{pictureUrl}
		)
	</insert>
	
</mapper>

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>SUCCESS</title>
	</head>
	<body>
		<h2>${msg }</h2>
		<a href="/item/list">List</a>
	</body>
</html>

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
	
	<!--  
		[마이바티스] 스프링에서 "_"를 사용한 컬럼명 사용 시(BOOK 테이블의 BOOK_ID와 같은 컬럼)
		카멜케이스로 읽어주는 역할(bookId와 같이)
		
		ex) 테이블 컬럼명이 member_id인 경우 jsp 화면 단에서 이 값을 사용시 memberId로 사용할 수 있다.
	-->
	<settings>
		<setting name="mapUnderscoreToCamelCase" value="true"/>
	</settings>
	
	<typeAliases>
		<typeAlias type="kr.or.ddit.vo.Board" alias="board"/>
		<typeAlias type="kr.or.ddit.vo.crud.CrudMember" alias="crudMember"/>
		<typeAlias type="kr.or.ddit.vo.crud.CrudMemberAuth" alias="crudMemberAuth"/>
		<typeAlias type="kr.or.ddit.vo.Item" alias="item"/>
		
		<typeAlias type="kr.or.ddit.vo.crud.PaginationInfoVO" alias="pagingVO"/>
		<typeAlias type="kr.or.ddit.vo.crud.NoticeVO" alias="noticeVO"/>
		<typeAlias type="kr.or.ddit.vo.crud.NoticeFileVO" alias="noticefileVO"/>
	</typeAliases>
	
</configuration>

- http://localhost/item/register


	@RequestMapping(value = "/list", method = RequestMethod.GET)
	public String itemList(Model model) {
		List<Item> itemList = itemService.list();
		model.addAttribute("itemList", itemList);
		return "item/list";
	}
package kr.or.ddit.service;

import java.util.List;

import kr.or.ddit.vo.Item;

public interface IItemService {

	public void register(Item item);
	public List<Item> list();

}
package kr.or.ddit.service.impl;

import java.util.List;

import javax.inject.Inject;

import org.springframework.stereotype.Service;

import kr.or.ddit.mapper.IItemMapper;
import kr.or.ddit.service.IItemService;
import kr.or.ddit.vo.Item;

@Service
public class ItemServiceImpl implements IItemService {

	@Inject
	private IItemMapper mapper;
	
	@Override
	public void register(Item item) {
		mapper.create(item);
	}

	@Override
	public List<Item> list() {
		return mapper.list();
	}

}
package kr.or.ddit.mapper;

import java.util.List;

import kr.or.ddit.vo.Item;

public interface IItemMapper {

	public void create(Item item);
	public List<Item> list();

}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="kr.or.ddit.mapper.IItemMapper">
	
	<insert id="create" parameterType="item">
		insert into item (
			item_id, item_name, price, description, picture_url
		) values (
			seq_item.nextval, #{itemName}, #{price}, #{description}, #{pictureUrl}
		)
	</insert>
	
	<select id="list" resultType="item">
		select 
			item_id, item_name, price, description, picture_url 
		from item 
		order by item_id desc
	</select>
	
</mapper>

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>ITEM</title>
	</head>
	<body>
		<h2>LIST</h2>
		<a href="/item/register">상품 등록</a>
		<hr />
		<table border="1">
			<tr>
				<th width="80">상품 ID</th>
				<th width="320">상품명</th>
				<th width="100">가격</th>
				<th width="80">편집</th>
				<th width="80">제거</th>
			</tr>
			<c:choose>
				<c:when test="${empty itemList }">
					<tr>
						<td colspan="5">조회하신 게시글이 존재하지 않습니다.</td>
					</tr>
				</c:when>
				<c:otherwise>
					<c:forEach items="${itemList }" var="item">
						<tr>
							<td align="center">${item.itemId }</td>
							<td align="left">${item.itemName }</td>
							<td align="right">${item.price }원</td>
							<td align="center">
								<a href="/item/modify?itemId=${item.itemId }">상품편집</a>
							</td>
							<td align="center">
								<a href="/item/remove?itemId=${item.itemId }">상품제거</a>
							</td>
						</tr>
					</c:forEach>
				</c:otherwise>
			</c:choose>
		</table>
	</body>
</html>

- http://localhost/item/list


	@RequestMapping(value = "/modify", method = RequestMethod.GET)
	public String itemModifyForm(int itemId, Model model) {
		Item item = itemService.read(itemId);
		model.addAttribute("item", item);
		return "item/modify";
	}
package kr.or.ddit.service;

import java.util.List;

import kr.or.ddit.vo.Item;

public interface IItemService {

	public void register(Item item);
	public List<Item> list();
	public Item read(int itemId);

}
package kr.or.ddit.service.impl;

import java.util.List;

import javax.inject.Inject;

import org.springframework.stereotype.Service;

import kr.or.ddit.mapper.IItemMapper;
import kr.or.ddit.service.IItemService;
import kr.or.ddit.vo.Item;

@Service
public class ItemServiceImpl implements IItemService {

	@Inject
	private IItemMapper mapper;
	
	@Override
	public void register(Item item) {
		mapper.create(item);
	}

	@Override
	public List<Item> list() {
		return mapper.list();
	}

	@Override
	public Item read(int itemId) {
		return mapper.read(itemId);
	}

}
package kr.or.ddit.mapper;

import java.util.List;

import kr.or.ddit.vo.Item;

public interface IItemMapper {

	public void create(Item item);
	public List<Item> list();
	public Item read(int itemId);

}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="kr.or.ddit.mapper.IItemMapper">
	
	<insert id="create" parameterType="item">
		insert into item (
			item_id, item_name, price, description, picture_url
		) values (
			seq_item.nextval, #{itemName}, #{price}, #{description}, #{pictureUrl}
		)
	</insert>
	
	<select id="list" resultType="item">
		select 
			item_id, item_name, price, description, picture_url 
		from item 
		order by item_id desc
	</select>
	
	<select id="read" parameterType="int" resultType="item">
		select 
			item_id, item_name, price, description, picture_url 
		from item 
		where item_id = #{itemId}
	</select>
	
</mapper>

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>ITEM</title>
	</head>
	<body>
		<h2>MODIFY</h2>
		<form action="/item/modify" method="post" enctype="multipart/form-data">
			<input type="hidden" name="itemId" value="${item.itemId }" />
			<input type="hidden" name="pictureUrl" value="${item.pictureUrl }" />
			<table border="1">
				<tr>
					<td>상품명</td>
					<td><input type="text" name="itemName" id="itemName" value="${item.itemName }" /></td>
				</tr>
				<tr>
					<td>가격</td>
					<td><input type="text" name="price" id="price" value="${item.price }" /></td>
				</tr>
				<tr>
					<td>파일</td>
					<td>
						<img alt="파일 이미지" src="/item/display?itemId=${item.itemId }" width="210", height="240">
					</td>
				</tr>
				<tr>
					<td>파일</td>
					<td><input type="file" name="picture" id="picture" /></td>
				</tr>
				<tr>
					<td>개요</td>
					<td><textarea rows="10" cols="30" wrap="soft" name="description" id="description">${item.description }</textarea></td>
				</tr>
			</table>
			<div>
				<button type="submit" id="modifyBtn">Modify</button>
				<button type="button" id="listBtn" onclick="javascript:location.href='/item/list'">List</button>
			</div>
		</form>
	</body>
</html>
	@ResponseBody
	@RequestMapping(value = "/display")
	public ResponseEntity<byte[]> displayFile(int itemId) {
		InputStream in = null;
		ResponseEntity<byte[]> entity = null;
		
		// itemId에 해당하는 이미지 파일명을 얻어온다.
		String fileName = itemService.getPicture(itemId);
		log.info("fileName : " + fileName);
		try {
			String formatName = fileName.substring(fileName.lastIndexOf(".") + 1); // 확장자 추출
			MediaType mType = getMediaType(formatName);
			HttpHeaders headers = new HttpHeaders();
			
			in = new FileInputStream(resourcePath + File.separator + fileName);
			if(mType != null) {
				headers.setContentType(mType);
			}
			entity = new ResponseEntity<byte[]>(IOUtils.toByteArray(in), headers, HttpStatus.CREATED);
		} catch (Exception e) {
			e.printStackTrace();
			entity = new ResponseEntity<byte[]>(HttpStatus.BAD_REQUEST);
		} finally {
			try {
				in.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return entity;
	}
	
	// 추출된 확장자를 통한 Mime 타입 결정
	private MediaType getMediaType(String formatName) {
		if(formatName != null) {
			if(formatName.toUpperCase().equals("JPG")) {
				return MediaType.IMAGE_JPEG;
			}
			if(formatName.toUpperCase().equals("GIF")) {
				return MediaType.IMAGE_GIF;
			}
			if(formatName.toUpperCase().equals("PNG")) {
				return MediaType.IMAGE_PNG;
			}
		}
		return null;
	}
package kr.or.ddit.service;

import java.util.List;

import kr.or.ddit.vo.Item;

public interface IItemService {

	public void register(Item item);
	public List<Item> list();
	public Item read(int itemId);
	public String getPicture(int itemId);

}
package kr.or.ddit.service.impl;

import java.util.List;

import javax.inject.Inject;

import org.springframework.stereotype.Service;

import kr.or.ddit.mapper.IItemMapper;
import kr.or.ddit.service.IItemService;
import kr.or.ddit.vo.Item;

@Service
public class ItemServiceImpl implements IItemService {

	@Inject
	private IItemMapper mapper;
	
	@Override
	public void register(Item item) {
		mapper.create(item);
	}

	@Override
	public List<Item> list() {
		return mapper.list();
	}

	@Override
	public Item read(int itemId) {
		return mapper.read(itemId);
	}

	@Override
	public String getPicture(int itemId) {
		return mapper.getPicture(itemId);
	}

}
package kr.or.ddit.mapper;

import java.util.List;

import kr.or.ddit.vo.Item;

public interface IItemMapper {

	public void create(Item item);
	public List<Item> list();
	public Item read(int itemId);
	public String getPicture(int itemId);

}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="kr.or.ddit.mapper.IItemMapper">
	
	<insert id="create" parameterType="item">
		insert into item (
			item_id, item_name, price, description, picture_url
		) values (
			seq_item.nextval, #{itemName}, #{price}, #{description}, #{pictureUrl}
		)
	</insert>
	
	<select id="list" resultType="item">
		select 
			item_id, item_name, price, description, picture_url 
		from item 
		order by item_id desc
	</select>
	
	<select id="read" parameterType="int" resultType="item">
		select 
			item_id, item_name, price, description, picture_url 
		from item 
		where item_id = #{itemId}
	</select>
	
	<select id="getPicture" parameterType="int" resultType="string">
		select picture_url 
		from item 
		where item_id = #{itemId}
	</select>
	
</mapper>

- http://localhost/item/modify?itemId=2


	@RequestMapping(value = "/modify", method = RequestMethod.POST)
	public String itemModify(Item item, Model model) throws Exception {
		MultipartFile file = item.getPicture();
		
		if(file != null && file.getSize() > 0) {
			log.info("originalName : " + file.getOriginalFilename());
			log.info("size : " + file.getSize());
			log.info("contentType : " + file.getContentType());
			
			String createdFileName = uploadFile(file.getOriginalFilename(), file.getBytes());
			
			item.setPictureUrl(createdFileName);
		}
		
		itemService.modify(item);
		model.addAttribute("msg", "수정이 완료되었습니다.");
		return "item/success";
	}
package kr.or.ddit.service;

import java.util.List;

import kr.or.ddit.vo.Item;

public interface IItemService {

	public void register(Item item);
	public List<Item> list();
	public Item read(int itemId);
	public String getPicture(int itemId);
	public void modify(Item item);

}
package kr.or.ddit.service.impl;

import java.util.List;

import javax.inject.Inject;

import org.springframework.stereotype.Service;

import kr.or.ddit.mapper.IItemMapper;
import kr.or.ddit.service.IItemService;
import kr.or.ddit.vo.Item;

@Service
public class ItemServiceImpl implements IItemService {

	@Inject
	private IItemMapper mapper;
	
	@Override
	public void register(Item item) {
		mapper.create(item);
	}

	@Override
	public List<Item> list() {
		return mapper.list();
	}

	@Override
	public Item read(int itemId) {
		return mapper.read(itemId);
	}

	@Override
	public String getPicture(int itemId) {
		return mapper.getPicture(itemId);
	}

	@Override
	public void modify(Item item) {
		mapper.update(item);
	}

}
package kr.or.ddit.mapper;

import java.util.List;

import kr.or.ddit.vo.Item;

public interface IItemMapper {

	public void create(Item item);
	public List<Item> list();
	public Item read(int itemId);
	public String getPicture(int itemId);
	public void update(Item item);

}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="kr.or.ddit.mapper.IItemMapper">
	
	<insert id="create" parameterType="item">
		insert into item (
			item_id, item_name, price, description, picture_url
		) values (
			seq_item.nextval, #{itemName}, #{price}, #{description}, #{pictureUrl}
		)
	</insert>
	
	<select id="list" resultType="item">
		select 
			item_id, item_name, price, description, picture_url 
		from item 
		order by item_id desc
	</select>
	
	<select id="read" parameterType="int" resultType="item">
		select 
			item_id, item_name, price, description, picture_url 
		from item 
		where item_id = #{itemId}
	</select>
	
	<select id="getPicture" parameterType="int" resultType="string">
		select picture_url 
		from item 
		where item_id = #{itemId}
	</select>
	
	<update id="update" parameterType="item">
		update item 
		set 
			item_name = #{itemName},
			price = #{price},
			description = #{description},
			picture_url = #{pictureUrl} 
		where item_id = #{itemId}
	</update>
	
</mapper>

- http://localhost/item/modify?itemId=3


이미지 업로드 없이 텍스트만으로도 잘 수정된다.


	@RequestMapping(value = "/remove", method = RequestMethod.GET)
	public String itemRemoveForm(int itemId, Model model) {
		Item item = itemService.read(itemId);
		model.addAttribute("item", item);
		return "item/remove";
	}

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>ITEM</title>
	</head>
	<body>
		<h2>REMOVE</h2>
		<form action="/item/remove" method="post">
			<input type="hidden" name="itemId" value="${item.itemId }" />
			<table border="1">
				<tr>
					<td>상품명</td>
					<td><input type="text" name="itemName" id="itemName" value="${item.itemName }" disabled="disabled" /></td>
				</tr>
				<tr>
					<td>가격</td>
					<td><input type="text" name="price" id="price" value="${item.price }" disabled="disabled" /></td>
				</tr>
				<tr>
					<td>파일</td>
					<td>
						<img alt="파일 이미지" src="/item/display?itemId=${item.itemId }" width="210", height="240">
					</td>
				</tr>
				<tr>
					<td>개요</td>
					<td><textarea rows="10" cols="30" wrap="soft" name="description" id="description" disabled="disabled">${item.description }</textarea></td>
				</tr>
			</table>
			<div>
				<button type="submit" id="removeBtn">Remove</button>
				<button type="button" id="listBtn" onclick="javascript:location.href='/item/list'">List</button>
			</div>
		</form>
	</body>
</html>

- http://localhost/item/remove?itemId=3


	@RequestMapping(value = "/remove", method = RequestMethod.POST)
	public String itemRemove(int itemId, Model model) {
		itemService.remove(itemId);
		model.addAttribute("msg", "삭제가 완료되었습니다.");
		return "item/success";
	}
package kr.or.ddit.service;

import java.util.List;

import kr.or.ddit.vo.Item;

public interface IItemService {

	public void register(Item item);
	public List<Item> list();
	public Item read(int itemId);
	public String getPicture(int itemId);
	public void modify(Item item);
	public void remove(int itemId);

}
package kr.or.ddit.service.impl;

import java.util.List;

import javax.inject.Inject;

import org.springframework.stereotype.Service;

import kr.or.ddit.mapper.IItemMapper;
import kr.or.ddit.service.IItemService;
import kr.or.ddit.vo.Item;

@Service
public class ItemServiceImpl implements IItemService {

	@Inject
	private IItemMapper mapper;
	
	@Override
	public void register(Item item) {
		mapper.create(item);
	}

	@Override
	public List<Item> list() {
		return mapper.list();
	}

	@Override
	public Item read(int itemId) {
		return mapper.read(itemId);
	}

	@Override
	public String getPicture(int itemId) {
		return mapper.getPicture(itemId);
	}

	@Override
	public void modify(Item item) {
		mapper.update(item);
	}

	@Override
	public void remove(int itemId) {
		mapper.delete(itemId);
	}

}
package kr.or.ddit.mapper;

import java.util.List;

import kr.or.ddit.vo.Item;

public interface IItemMapper {

	public void create(Item item);
	public List<Item> list();
	public Item read(int itemId);
	public String getPicture(int itemId);
	public void update(Item item);
	public void delete(int itemId);

}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="kr.or.ddit.mapper.IItemMapper">
	
	<insert id="create" parameterType="item">
		insert into item (
			item_id, item_name, price, description, picture_url
		) values (
			seq_item.nextval, #{itemName}, #{price}, #{description}, #{pictureUrl}
		)
	</insert>
	
	<select id="list" resultType="item">
		select 
			item_id, item_name, price, description, picture_url 
		from item 
		order by item_id desc
	</select>
	
	<select id="read" parameterType="int" resultType="item">
		select 
			item_id, item_name, price, description, picture_url 
		from item 
		where item_id = #{itemId}
	</select>
	
	<select id="getPicture" parameterType="int" resultType="string">
		select picture_url 
		from item 
		where item_id = #{itemId}
	</select>
	
	<update id="update" parameterType="item">
		update item 
		set 
			item_name = #{itemName},
			price = #{price},
			description = #{description},
			picture_url = #{pictureUrl} 
		where item_id = #{itemId}
	</update>
	
	<delete id="delete" parameterType="int">
		delete from item 
		where item_id = #{itemId}
	</delete>
	
</mapper>

- http://localhost/item/remove?itemId=3


 

'대덕인재개발원 > 대덕인재개발원_웹기반 애플리케이션' 카테고리의 다른 글

231201_SPRING 2 (과제 1)  (0) 2023.12.01
231201_SPRING 2 (8-2)  (0) 2023.12.01
231130_SPRING 2 (7-3)  (0) 2023.11.30
231130_SPRING 2 (7-2)  (0) 2023.11.30
231130_SPRING 2 (7-1)  (1) 2023.11.30