100일 챌린지/빅데이터기반 인공지능 융합 서비스 개발자

Day 53 - Spring 5.x guest file upload/download 프로그램 만들기 -

ksyke 2024. 10. 11. 12:49

1. H2 table 만들기

create table guest(
num int primary key auto_increment,
name varchar(10),
file varchar(255),
path varchar(255)
);
insert into guest (name,file,path) values ('test1',null,null);
insert into guest (name,file,path) values ('test2',null,null);
insert into guest (name,file,path) values ('test3',null,null);
commit;

2. spring legacy project

3. pom.xml 업데이트

3-1. java version up

    <properties>
        <java-version>1.8</java-version>
        <org.springframework-version>5.3.39</org.springframework-version>
        <org.aspectj-version>1.6.10</org.aspectj-version>
        <org.slf4j-version>1.6.6</org.slf4j-version>
    </properties>

    <build>
                <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.5.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <compilerArgument>-Xlint:all</compilerArgument>
                    <showWarnings>true</showWarnings>
                    <showDeprecation>true</showDeprecation>
                </configuration>
            </plugin>
    </buid>

3-2. spring 5.3.39 version up

<org.springframework-version>5.3.39</org.springframework-version>

3-3. spring jdbc 추가

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${org.springframework-version}</version>
        </dependency>

3-5. junit 4.13으로 버전업

        <!-- Test -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
            <scope>test</scope>
        </dependency>

3-6. lombok 추가

        <!-- lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.34</version>
            <scope>provided</scope>
        </dependency>

3-7. mybatis spring, mybatis 추가

        <!-- mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.6</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.16</version>
        </dependency>

3-9. h2 engine 추가 (scope 삭제)

        <!-- h2 -->
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.4.200</version>
        </dependency>

3-10. file upload

<!-- commons-fileupload -->
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.5</version>
</dependency>

4. servlet-context (beans, context, mvc)추가

    <context:component-scan base-package="com.gimhae.day53" />

    <beans:bean id="multipartResolver"
        class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <beans:property name="maxUploadSize" value="5242880"/>        
    </beans:bean>

5. web.xml

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

6. root-context (beans, mybatis-spring, p)추가

    <bean id="dataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource"
        p:driverClassName="org.h2.Driver"
        p:url=""
        p:username=""
        p:password=""
    />
    <bean id="sqlSessionFactory"
        class="org.mybatis.spring.SqlSessionFactoryBean"
        p:dataSource-ref="dataSource"
    />

    <mybatis-spring:scan base-package="com.gimhae.day53.model"/>

7. Model 만들기

GuestVo

package com.gimhae.day53.model;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class GuestVo {
    int num;
    String name,file,path;
}

GuestDao(Interface)

package com.gimhae.day53.model;

@Mapper
public interface GuestDao {
    @Select("select * from guest")
    List<GuestVo> list();
}

8. HomeController

package com.gimhae.day53;

@Controller
public class HomeController {
	@Autowired
	GuestDao guestDao;
	
	@RequestMapping(value = "/", method = RequestMethod.GET)
	public String home(Model model) {
		model.addAttribute("list", guestDao.list());
		return "index";
	}
	
	@GetMapping("/add")
	public void add() {}
	
	@PostMapping("/")
	public String add(String name,MultipartFile file,HttpServletRequest req) {
		String origin=file.getOriginalFilename();
		String newName=System.currentTimeMillis()+origin;
		GuestVo bean=GuestVo.builder()
							.name(name)
							.file(origin)
							.path(newName)
							.build();
		try {
			File upload=new File(req.getRealPath("./resources")+"/"+newName);
			System.out.println(upload.getCanonicalPath());
			file.transferTo(upload);
		} catch (IllegalStateException | IOException e) {
			e.printStackTrace();
		}
//		try (
//				FileOutputStream os=new FileOutputStream(upload+"/"+newName);
//				InputStream is=file.getInputStream();
//				){
//			int cnt=-1;
//			while((cnt=is.read())!=-1) {
//				os.write(cnt);
//			}
//		} catch (IOException e) {
//			e.printStackTrace();
//		}
		guestDao.add(bean);
		return "redirect:./";
	}
	
	@GetMapping("/login")
	public String login(HttpSession session) {
		session.setAttribute("user", "root");
		return "redirect:./";
	}
	@GetMapping("/logout")
	public String logout(HttpSession session) {
		session.invalidate();
		return "redirect:./";
	}
	@GetMapping(value = "/download")
	public void download2(HttpSession session,HttpServletRequest req,HttpServletResponse resp
			,@RequestParam("o") String origin,@RequestParam("f") String newName) {
		if(session.getAttribute("user")==null || !session.getAttribute("user").equals("root")) {
			try {
				resp.sendRedirect("./");
			} catch (IOException e) {
				e.printStackTrace();
			}
			return;
		}
		resp.setContentType("application/octet-stream");
		resp.setHeader("Content-Disposition", "attachment; filename=\""+origin+".jsp\"");
		File upload=new File(req.getRealPath("./resources")+"/"+newName);
		try (
				InputStream is=new FileInputStream(upload);
				OutputStream os=resp.getOutputStream();
				){
			int cnt=-1;
			while((cnt=is.read())!=-1) {
				os.write(cnt);
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e1) {
			e1.printStackTrace();
		}
	}
	
	@GetMapping("/{origin}/{newName:.+}")
	public void download3(HttpSession session,HttpServletRequest req,HttpServletResponse resp
			,@PathVariable String origin
			,@PathVariable String newName) {
		if(session.getAttribute("user")==null || !session.getAttribute("user").equals("root")) {
			try {
				resp.sendRedirect("../");
			} catch (IOException e) {
				e.printStackTrace();
			}
			return;
		}
		resp.setContentType("application/octet-stream");
		resp.setHeader("Content-Disposition", "attachment; filename=\""+origin+".jsp\"");
		File upload=new File(req.getRealPath("./resources")+"/"+newName);
		try (
				InputStream is=new FileInputStream(upload);
				OutputStream os=resp.getOutputStream();
				){
			int cnt=-1;
			while((cnt=is.read())!=-1) {
				os.write(cnt);
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e1) {
			e1.printStackTrace();
		}
	}
	@GetMapping("/add2")
	public void add2() {}
	@PostMapping("/add2")
	public void add2(MultipartFile[] files) {
		for(MultipartFile file: files) {
			System.out.println(file.getOriginalFilename());
		}
	}
}

9. index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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>Insert title here</title>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
</head>
<body>
<nav>
	<a href="/">list</a>
	<a href="./add">add</a>
	<a href="./login">login</a>
	<a href="./logout">logout(${sessionScope.user})</a>
</nav>
<table>
	<thead>
		<tr>
			<th>글번호</th>
			<th>이름</th>
			<th>download1</th>
			<th>download2</th>
			<th>download3</th>
		</tr>
	</thead>
	<tbody>
		<c:forEach items="${list }" var="bean">
			<tr>
				<td>${bean.num }</td>
				<td>${bean.name }</td>
				<td>
					<c:if test="${bean.file ne null}">
						<a href="resources/${bean.path }">${bean.file}</a>
					</c:if>
				</td>
				<td>
					<c:if test="${bean.file ne null}">
						<a href="download?o=${bean.file }&f=${bean.path}">download</a>
					</c:if>
				</td>
				<td>
					<c:if test="${bean.file ne null}">
						<a href="${bean.file }/${bean.path}">download</a>
					</c:if>
				</td>
			</tr>
		</c:forEach>
	</tbody>
</table>
<a href="add">입력</a>
</body>
</html>

10. add.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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>Insert title here</title>
</head>
<body>
<h2>add page</h2>
<form action="./" method="post" enctype="multipart/form-data">
	<div>
		<input name="name" placeholder="name"/>
	</div>
	<div>
		<input name="file" type="file"/>
	</div>
	<div>
		<button>입력</button>
	</div>
</form>
</html>

11. add2.jsp

<head>
<script src="https://code.jquery.com/jquery-1.12.4.min.js" integrity="sha384-nvAa0+6Qg9clwYCGGPpDQLVpLNn0fRaROjHqs13t4Ggj3Ez50XnGQqc/r8MhnRDZ" crossorigin="anonymous"></script>
<script type="text/javascript">
$(function(){
	var file=$('form #file');
	file.find('button').click(e=>{
		file.append('<br/><input type="file" name="files"/>');
	});
});
</script>
</head>
<body>
<h2>add page</h2>
<form action="./add2" method="post" enctype="multipart/form-data">
	<div>
		<input name="name" placeholder="name"/>
	</div>
	<div id="file">
		<button type="button">추가</button>
		<input name="files" type="file"/>
	</div>
	<div>
		<button>입력</button>
	</div>
</form>
</html>

 

11-1. Log Aop

package com.gimhae.day49.aop;

//@Slf4j
@Component
@Aspect
public class LogAop {

    @Before("execution(* com.gimhae.day49..*Impl.*(..))")
    public void before(JoinPoint join) {
        System.out.println("param:"+Arrays.toString(join.getArgs()));
    }

    @AfterReturning(
            returning = "obj",
            pointcut = "execution(* com.gimhae.day49..*Impl.*(..))")
    public void afterSuccess(Object obj) {
//        log.debug("after");
        System.out.println("return:"+obj);
    }
}

12. 서비스 만들기

12-1. Service

package com.gimhae.day49.dept.service;

@Service
public class DeptService {
    @Autowired
    SqlSession sqlSession;
    final String success="{\"result\":}";

    public List<?> list(){
        DeptDao deptDao=sqlSession.getMapper(DeptDao.class);
        return deptDao.pullList();
    }

    public DeptVo getOne(int deptno){
        DeptDao deptDao=sqlSession.getMapper(DeptDao.class);
        return deptDao.getList(deptno);
    }

    public String add(DeptVo bean){
        DeptDao deptDao=sqlSession.getMapper(DeptDao.class);
        return "{\"result\":" + deptDao.addList(bean) + "}";
    }

    public String edit(DeptVo bean){
        DeptDao deptDao=sqlSession.getMapper(DeptDao.class);
        return "{\"result\":" + deptDao.setList(bean) + "}";
    }

    public String delete(int deptno){
        DeptDao deptDao=sqlSession.getMapper(DeptDao.class);
        return "{\"result\":" + deptDao.rmList(deptno) + "}";
    }
}

12-2. Controller

package com.gimhae.day49.api;

@RestController
@RequestMapping("/api/dept/")
@RequiredArgsConstructor
public class DeptController {
    private final DeptService deptService;

    @GetMapping("")
    public List<?> list(){
        return deptService.list();
    }

    @GetMapping("/{deptno}")
    public DeptVo detail(@PathVariable int deptno) {
        return deptService.getOne(deptno);
    }

    @PostMapping(value = "",produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String add(@ModelAttribute DeptVo bean) {
        return deptService.add(bean);
    }

    @PutMapping(value = "{deptno}",produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String edit(@RequestBody DeptVo bean) {
        return deptService.edit(bean);
    }

    @DeleteMapping(value = "{deptno}",produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String delete(@PathVariable int deptno) {
        return deptService.delete(deptno);
    }
}

13. web project 만들기

13-1. pom.xml

서블릿 업데이트

        <!-- Servlet -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>2.3.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>

13-2. web.xml

- schema 수정

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

- encoding filter 달아주기

    <filter>
        <filter-name>encoding</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>utf-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encoding</filter-name>
        <url-pattern>/api/*</url-pattern>
    </filter-mapping>

13-3. maven update

13-4. .setting의 .xml 파일 버전 변경 (1.8/3.1)

13-5. maven update

14. API 테스트 하기

https://www.postman.com/downloads/

[Download Postman | Get Started for Free

Try Postman for free! Join 30 million developers who rely on Postman, the collaboration platform for API development. Create better APIs—faster.

www.postman.com](https://www.postman.com/downloads/)

14-1. pom.xml

jacksonbind 추가

        <!-- jackson-databind -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.15.2</version>
        </dependency>

api 서비스 테스트 하기

15. Rest Template 만들기