Post

๐Ÿฅœ [Spring] File ์—…๋กœ๋“œ, ์ €์žฅ & AOP

Component๋Š” ์ธํ„ฐํŽ˜์ด์Šค ๊ธฐ๋ฐ˜์˜ ์—ฌ๋Ÿฌ ๊ธฐ๋Šฅ๋“ค์ด ์žˆ๋Š” ๊ฒƒ์„ ๋งํ•œ๋‹ค.

DI ์ปจํ…Œ์ด๋„ˆ๋Š” Component(bean)์„ Singletone ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋งŒ๋“ ๋‹ค.

ํšŒ์›๊ฐ€์ž…์„ ํ• ๋•Œ ์ค‘๋ณต๋œ ์•„์ด๋””๊ฑฐ๋‚˜ 4~8 ์ž ๊ฐ€ ์•„๋‹ˆ๋ฉด ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ฉ”์‹œ์ง€๋ฅผ ์ฃผ๋Š” ๊ธฐ๋Šฅ์„ ๋„ฃ์–ด์ฃผ๋ ค๋ฉด

๋จผ์ € pom.xml ์— Ajax๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” <dependency> ๋ฅผ ๋„ฃ์–ด์•ผ ํ•œ๋‹ค

1
2
3
4
5
6
<!-- 8. Ajax Json -->
 <dependency>
        	<groupId>com.fasterxml.jackson.core</groupId>
        	<artifactId>jackson-databind</artifactId>
        	<version>2.5.1</version>
 </dependency>

์ด์ œ register.jsp์— ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ์ฝ”๋“œ๋ฅผ ๋„ฃ์–ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">  
<meta name="viewport" content="width=device-width, initial-scale=1">
 <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css">
 <!-- jquery cdn ::  cloudflare, google, ms, jquery -->
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
 
 <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
 <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.bundle.min.js"></script>
<title>Insert title here</title>
<style type="text/css">
form{
	width: 300px;
	margin: 0 auto;
}
</style>
<script>
	/* 
		KEY ์ด๋ฒคํŠธ ๊ด€๋ จ ํ•จ์ˆ˜
		keypress() ๋ˆŒ๋ €์„ ๋•Œ
		keydown() ๋ฒ„ํŠผ์„ ๊พน๋ˆ„๋ฅผ๋•Œ
		keyup() ๋ฒ„ํŠผ์„ ๋•” ๋•Œ
	
	*/
	$(function(){
		$('#id').keyup(function(){
			var id =$(this).val();
			//id๊ฐ’์ด 4์ž ์ด์ƒ 8์ž ์ดํ•˜์ผ ๋•Œ๋งŒ id๊ฐ’์„ ๋ฐ›์•„๋“ค์ด๊ฒŸ๋‹ค.
			if(id.length >= 4 & id.length <=8){
				//์ด ๋•Œ๋งŒ ๋น„๋™๊ธฐ ์š”์ฒญ
				$.ajax({
					type:'post',
					url:'idExist.do',
					data:'id='+id,
					
					success:function(data){ //callback
						//์ด๋ฏธ ์‚ฌ์šฉ์ค‘์ธ ์•„์ด๋””......idcheck ์˜์—ญ์— ์ถœ๋ ฅ
						//์‚ฌ์šฉ๊ฐ€๋Šฅ ์•„์ด๋””...idcheck ์˜์—ญ์— ์ถœ๋ ฅ
					     var jsonData=JSON.parse(data); //[object:object]๋กœ ๋‚˜์˜ค๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€
						if(jsonData.check ==true){
							$('#idcheck').html("<h3><font color=tomato>์ค‘๋ณต๋œ ์•„์ด๋””</font></h3>");
							$('#submit_btn').attr('disabled', true);
						}
						else{
							$('#idcheck').html("<h3><font color=blue>์‚ฌ์šฉ๊ฐ€๋Šฅ  ์•„์ด๋””</font></h3>");
							$('#submit_btn').attr('disabled', false);
						}
					}
				});//ajax
			}
			else{ //๋ฉ”์„ธ์ง€ ์ถœ๋ ฅ
				$('#idcheck').html('4์ž ์ด์ƒ, 8์ž ์ดํ•˜๋งŒ ๊ฐ€๋Šฅ!!').css('color', 'orange');
				$('#submit_btn').attr('disabled', true); //๋น„ํ™œ์„ฑํ™”
			}
		});
	});
</script>
</head>
<body>
<div class="container">
	<div class="jumbotron" align="center">
		<h2>REGISTER MEMBER FORM</h2>
	</div>
</div>
<hr>
<div class="container">	
	 <form action="register.do" method="post">	
    <div class="form-group">
      <label for="id">ID:</label>
      <input type="text" class="form-control" id="id" placeholder="Enter Id" name="id">
      <span id="idcheck" style="margin-left:15px"></span>  ์ถ”๊ฐ€!!!!!!!!!!!!
    </div>
    <div class="form-group">
      <label for="pwd">Password:</label>
      <input type="password" class="form-control" id="pwd" placeholder="Enter password" name="password">
    </div>
        <div class="form-group">
      <label for="name">Name:</label>
      <input type="text" class="form-control" id="name" placeholder="Enter Name" name="name">
    </div>
        <div class="form-group">
      <label for="address">Address:</label>
      <input type="text" class="form-control" id="address" placeholder="Enter Address" name="address">
    </div>
 
    <button type="submit" class="btn btn-primary" id="submit_btn">Submit</button>
  </form>
</div>
</body>
</html>

<script> ์— ๋‹ค๊ฐ€ Ajax์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ์—ˆ๋‹ค.

Ajax์˜ ์š”์ฒญ์ด idExist.do๋กœ ๋“ค์–ด๊ฐ„๋‹ค.

๋”ฐ๋ผ์„œ Controller๋กœ ๊ฐ€์„œ idExist.do์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•ด์ค€๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
//์ถ”๊ฐ€...๋น„๋™๊ธฐ ์š”์ฒญ
	@RequestMapping("idExist.do")
	public String idExist(String id, Model model)throws Exception{
		boolean check=false;
		String rid = memberDAO.idExist(id); //id๊ฐ€ ์žˆ๋Š”์ง€ ์—†๋Š”์ง€ true, false๊ฐ€ Stirngํ˜•ํƒœ๋กœ return๋จ
		//true์ด๋ฉด ์ค‘๋ณต๋œ ์•„์ด๋””, false์ด๋ฉด ์‚ฌ์šฉ๊ฐ€๋Šฅํ•œ ์•„์ด๋””

		if(rid!=null)check = true;//์ค‘๋ณต๋œ ์•„์ด๋””
		
		model.addAttribute("check", check);
		
		return "JsonView";
	}

๋น„๋™๊ธฐ ์š”์ฒญ์—์„œ data์— ๋‹ค๊ฐ€ id๋ฅผ ๋‹ด์•„์™”๋‹ค.

idExist() ์˜ ๊ฒฐ๊ณผ๊ฐ’์ด null์ด ์•„๋‹ˆ๋ฉด ํ•ด๋‹น id๊ฐ€ ์ด๋ฏธ ์กด์žฌํ•˜๋Š” ๊ฒƒ์ด๋ฏ€๋กœ check ๋ณ€์ˆ˜์— true๋ฅผ ํ• ๋‹นํ•ด ์ค€๋‹ค.

์ด์— ๋Œ€ํ•œ return๊ฐ’์€ JsonView ๋กœ ๊ฐ„๋‹ค.

๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” PresentationBean.xml ์„ ์ˆ˜์ •ํ•ด์ค˜์•ผ ํ•œ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?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.0.xsd">

	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/views/" />
		<property name="suffix" value=".jsp" />	
		<property name="order" value="1" />
	</bean>
	
	<bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
		<property name="order" value="0" />
	</bean>
	
	<!--  Ajax๋ฅผ ์œ„ํ•œ ๋นˆ์„ ๋“ฑ๋ก -->
	<bean id="JsonView" class="org.springframework.web.servlet.view.json.MappingJackson2JsonView" >
	    <property name="contentType" value="text/html;charset=utf-8" />
	</bean>
	
	<!--  3. Business Logic Layer Bean :: Service + Persistence Layer-->
	<context:component-scan base-package="com.service.spring.controller" />
</beans>

์ „์— ๋ณธ๊ฒƒ๊ณผ ๊ฐ™์ด BeanNameViewResolver ๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

๊ทธ๋ฆฌ๊ณ  id๊ฐ’์ด JsonView์ธ AJax๋ฅผ ์œ„ํ•œ ๋นˆ์„ ๋“ฑ๋กํ•œ๋‹ค.

image-39 (์ •์ƒ์ž‘๋™ํ•˜๋Š” ๋ชจ์Šต)

Spring ์—์„œ ํŒŒ์ผ ์—…๋กœ๋“œ ํ•˜๋Š” ๋ฒ•

์‚ฌ์šฉ์ž๊ฐ€ ์˜ฌ๋ฆฐ ํŒŒ์ผ์€ ์–ด๋””๋‹ค ์ €์žฅ์„ ํ• ๊นŒ?

image-40

Tomcat_Home โ†’ webapps โ†’ sq15_FileUpload โ†’ ์šฐ๋ฆฌ๊ฐ€ ์˜ฌ๋ฆฐ ํŒŒ์ผ๋“ค์€ ์ •์ ์ธ ํŒŒ์ผ์ด๊ธฐ ๋•Œ๋ฌธ์— WEB-INF ์ƒ์œ„์— ๋“ค์–ด๊ฐ„๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>Insert title here</title>
</head>
<body>
<h2 align="center">File Upload Form</h2>
<form action="fileupload.do" method="post" enctype="multipart/form-data">
	์‚ฌ์šฉ์ž๋ช…<input type="text" name="userName"> <!-- name์œผ๋กœ ํ•„๋“œ๊ฐ’ ์ง€์ • -->
	<input type="file" name="uploadFile"> <!--name์œผ๋กœ ํ•„๋“œ๊ฐ’ ์ง€์ •  -->
	<input type="submit" value="ํŒŒ์ผ ์—…๋กœ๋“œ">

</form>
</body>
</html>

โ€‹

ํŒŒ์ผ ์—…๋กœ๋“œ ๊ธฐ์ˆ  ์‚ฌ์šฉ์‹œ ์ฃผ์˜ํ•  ์ 

  1. form ํƒœ๊ทธ ์•ˆ์— input type=โ€fileโ€๋กœ ํผ์„ ๋งŒ๋“ ๋‹ค
  2. method=post ๋งŒ ๊ฐ€๋Šฅํ•˜๋‹ค.
  3. enctype=โ€multipart/form-dataโ€
  4. poem.xml์— fileupload dependency ์ถ”๊ฐ€
  5. ํŒŒ์ผ์—…๋กœ๋“œํ•œ ์ •๋ณด๋ฅผ ์ €์žฅํ•˜๋Š” vo๋ฅผ ๋จผ์ € ๋งŒ๋“ค๊ณ  ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•œ๋‹ค.(RequestMappping)
1
2
3
4
5
6
<!-- 9. FileUpload -->
<dependency>
        	<groupId>commons-fileupload</groupId>
        	<artifactId>commons-fileupload</artifactId>
        	<version>1.3.3</version>
</dependency>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.service.spring.domain;

import org.springframework.web.multipart.MultipartFile;

/*
 * ํŒŒ์ผ ํƒ์ƒ‰์ฐฝ์—์„œ ์„ ํƒํ•œ ํŒŒ์ผ์˜ ์ •๋ณด๋ฅผ ์ €์žฅํ•˜๋Š”  VO  ํด๋ž˜์Šค..
 */
public class UploadDataVO {
	private String userName; // ์‚ฌ์šฉ์ž๋ช… ์ €์žฅ
	private MultipartFile uploadFile;// ์—…๋กœ๋“œ ํŒŒ์ผ ์ •๋ณด ์ €์žฅ
	//MultipartFile์€ ์‚ฌ์šฉ์ž๊ฐ€ ํŒŒ์ผ์„ ์—…๋กœ๋“œ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ณด์—ฌ์ง€๋Š” ํŒŒ์ผ ํƒ์ƒ‰์ฐฝ

	public String getUserName() {
		return userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

	public MultipartFile getUploadFile() {
		return uploadFile;
	}

	public void setUploadFile(MultipartFile uploadFile) {
		this.uploadFile = uploadFile;
	}
}

ํ•„๋“œ๊ฐ’์˜ userName๊ณผ uploadFile์€ ์•„๋ž˜์˜ name๊ณผ ๋™์ผํ•ด์•ผ ํ•œ๋‹ค.

1
2
์‚ฌ์šฉ์ž๋ช…<input type="text" name="userName"> <!-- name์œผ๋กœ ํ•„๋“œ๊ฐ’ ์ง€์ • -->
<input type="file" name="uploadFile"> <!--name์œผ๋กœ ํ•„๋“œ๊ฐ’ ์ง€์ •  -->

์ด์ œ fileupload.do๋กœ ๋“ค์–ด์˜ค๋Š” ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด Controller๋ฅผ ๋งŒ๋“ ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@Controller
public class FileUploadController {
	
	@RequestMapping("fileupload.do")
	public String upload(UploadDataVO vo, Model model, HttpSession session)throws Exception{
		
		MultipartFile mFile = vo.getUploadFile(); //์‚ฌ์šฉ์ž๊ฐ€ ์„ ํƒํ•œ ํŒŒ์ผ ๋ฐ›์•„์˜ด
		System.out.println("MultipartFile..."+mFile);
		
		//.1 MultipartFile์˜ ์ฃผ์š”๊ธฐ๋Šฅ... ์—…๋กœ๋“œํ•œ ํŒŒ์ผ ์ด๋ฆ„
		if(mFile.isEmpty()==false) { //์—…๋กœ๋“œ๋œ ํŒŒ์ผ์ด ์žˆ๋‹ค๋ฉด
			System.out.println("ํŒŒ์ผ์˜ ์‚ฌ์ด์ฆˆ : "+ mFile.getSize());
			System.out.println("์—…๋กœ๋“œํ•œ ํŒŒ์ผ์˜ ์ด๋ฆ„ : "+ mFile.getOriginalFilename());
			System.out.println("mFile.getName() : "+mFile.getName());
		}
		//2. ์—…๋กœ๋“œํ•œ ํŒŒ์ผ์„ Tomcat ์„œ๋ฒ„๋กœ ๋ฐฐํฌ(์ €์žฅ)
		//HtteRequest ์จ๋„ ๋จ
		String root =session.getServletContext().getRealPath("/");
		System.out.println("root   :"+root);//context path ๊ฒฝ๋กœ ํ™•๋ณด
		
		String path=root+"upload\\";
		System.out.println("path   :"+path);
		
		//3. ์—…๋กœ๋“œํ•œ ํŒŒ์ผ์˜ ์นดํ”ผ๋ณธ์„ ํ•ด๋‹น ๊ฒฝ๋กœ /upload์— ์ €์žฅ
		File copyFile = new File(path + mFile.getOriginalFilename());
		mFile.transferTo(copyFile);
		
		model.addAttribute("uploadfile", mFile.getOriginalFilename());
		
		return "upload_result";
	}
}


image-41 (ํŒŒ์ผ์ด ์ •์ƒ์ ์œผ๋กœ ์ง€์ •๋˜์—ˆ๋‹ค)

path ๊ฒฝ๋กœ๋กœ ์—…๋กœ๋“œํ•œ ํŒŒ์ผ์ด ์ €์žฅ๋œ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<b>Upload File OK~~~~</b>
	<ul>
		<li>File download&nbsp;&nbsp;&nbsp;&nbsp;<a href="filedown.do?filename=${uploadfile}">${uploadfile}</a></li>
	</ul>
</body>
</html>

File download ๋ฅผ ๋ˆ„๋ฅด๋ฉด ์š”์ฒญ์ด filedown.do๋กœ ๊ฐ„๋‹ค.

๋˜ํ•œ get์š”์ฒญ์œผ๋กœ uploadfile์ด ๊ฐ™์ด ๋“ค์–ด๊ฐ„๋‹ค.

uploadfile์€ Controller์—์„œ

Model.addAttribute("uploadfile", mFile.getOriginalFileName() ๋กœ ์ €์žฅ๋˜์žˆ๋‹ค.

๋”ฐ๋ผ์„œ filedown.do์— ํ•ด๋‹นํ•˜๋Š” Controller๋ฅผ ๋งŒ๋“ค์–ด ์ค˜์•ผ ํ•œ๋‹ค.


1
2
3
4
5
6
7
8
9
10
11
12
13
@RequestMapping("filedown.do")
	public String down(String filename, Model model, HttpSession session)throws Exception{
		
		String root =session.getServletContext().getRealPath("/");
		String path=root+"upload\\";
		
		//๋‹ค์šด๋กœ๋“œ ์ฝ”๋“œ ์ถ”๊ฐ€
		
		model.addAttribute("path", path);
		
		//ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ๋„ ๊ฒฐ๊ณผํŽ˜์ด์ง€๊ฐ€ ์—†๋‹ค
		return "downloadView";
	}

Controller ์—์„œ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๊ณ  downloadView ๋กœ ์ด๋™ํ•œ๋‹ค.

๋‹ค์šด๋กœ๋“œ ์™„๋ฃŒ ๋ผ๋Š” ํŽ˜์ด์ง€๋Š” ํ•„์š”์—†๊ธฐ ๋•Œ๋ฌธ์—

๋”ฐ๋ผ์„œ ๋น„๋™๊ธฐ์ฒ˜๋ฆฌ ์ฒ˜๋Ÿผ ๊ฒฐ๊ณผํŽ˜์ด์ง€๊ฐ€ ์—†๋‹ค.

๊ฒฐ๊ตญ bean ์„ ๋งŒ๋“ค์–ด ์ค˜์•ผ ํ•œ๋‹ค. โ‡’ BeanNameViewResolver ์‚ฌ์šฉํ•ด์•ผ ํ•จ

servlet-context.xml ๋กœ ๊ฐ„๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<?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">

	<!-- 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="1" />
	</beans:bean>
	
	<beans:bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
		<beans:property name="order" value="0" />
	</beans:bean>
	
	<!-- ๋‹ค์šด๋กœ๋“œ ๋นˆ ์ถ”๊ฐ€ -->
	<beans:bean name="downloadView" class="util.DownloadView"/>
	
	
	<!-- FileUpload์‹œ ๋ฐ˜๋“œ์‹œ ๋นˆ ์„ค์ • ์ถ”๊ฐ€ :: MultipartFile -->
	<beans:bean id="multipartResolver"
		class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
		<beans:property name="defaultEncoding" value="utf-8" /> <!--ํ•œ๊ธ€์ฒ˜๋ฆฌ -->
		<beans:property name="maxUploadSize" value="-1" /> <!--ํŒŒ์ผ ์—…๋กœ๋“œ ํ•  ์ˆ˜ ์žˆ๋Š” ์ตœ๋Œ€ ์‚ฌ์ด์ฆˆ(๋™์˜์ƒ๋„ ๊ฐ€๋Šฅ)  -->
	</beans:bean>
	
	<context:component-scan base-package="com.service.spring.controller" />

</beans:beans>

์ž˜๋ณด๋ฉด <!โ€” ๋‹ค์šด๋กœ๋“œ ๋นˆ ์ถ”๊ฐ€ โ€”> ๋ถ€๋ถ„์—์„œ downloadView ๋ผ๋Š” bean ์ด ์ƒ์„ฑ๋˜๊ณ 

class=util.DownloadView ์ด๋‹ค. class ์— ํ•ด๋‹นํ•˜๋Š” ์œ„์น˜์— ์กด์žฌํ•˜๋Š” ํด๋ž˜์Šค๋ฅผ bean ์œผ๋กœ ๋งŒ๋“ ๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package util;

public class DownloadView extends AbstractView {
    // ๋‹ค์šด๋กœ๋“œ ํŒŒ์ผ์˜ ์ปจํ…ํŠธ ํƒ€์ž…์„ ์ง€์ • 
    @Override
    public String getContentType() {
        // 8๋น„ํŠธ๋กœ ๋œ ์ผ๋ จ์˜ ๋ฐ์ดํ„ฐ..application์˜ ๋ฐ์ดํƒ€ ํ˜•์‹์„ ๊ตณ์ด ์ง€์ •ํ•˜์ง€ ์•Š์„๋–„ ์‚ฌ์šฉํ•จ.
        return "application/octet-stream";
    }

    @Override
    protected void renderMergedOutputModel(Map<String, Object> map,
                                           HttpServletRequest request, HttpServletResponse response) throws Exception {

        System.out.println("downloadView ์‹คํ–‰~~~" + map.get("path"));
        String path = (String) map.get("path");
        String fileName = request.getParameter("filename");
        //์—…๋กœ๋“œ ๊ฒฝ๋กœ๊ฐ€ ์ €์žฅ๋œ ํŒŒ์ผ ๊ฐ์ฒด
        File file = new File(path + fileName);

        // ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ 
        response.setContentType(this.getContentType());
        response.setContentLength((int) file.length());//ํŒŒ์ผ ํฌ๊ธฐ ์„ค์ • 
        // ๋‹ค์šด๋กœ๋“œ ํŒŒ์ผ์— ๋Œ€ํ•œ ์„ค์ • 
        response.setHeader("Content-Disposition",
                "attachment; fileName="
                        + new String(file.getName().getBytes("UTF-8"), "8859_1"));
        //๋ฐ์ดํ„ฐ ์ธ์ฝ”๋”ฉ์ด ๋ฐ”์ด๋„ˆ๋ฆฌ ํŒŒ์ผ์ž„์„ ๋ช…์‹œ
        response.setHeader("Content-Transfer-encoding", "binary");
        // ์‹ค์ œ ์—…๋กœ๋“œ ํŒŒ์ผ์„ inputStream ์œผ๋กœ ์ฝ์–ด์„œ 
        // response ์— ์—ฐ๊ฒฐ๋œ OutputStream์œผ๋กœ ์ „์†กํ•˜๊ฒ ๋‹ค. 
        OutputStream os = response.getOutputStream();
        FileInputStream fis = new FileInputStream(file);
        FileCopyUtils.copy(fis, os);
        System.out.println("๋‹ค์šด๋กœ๋“œ.." + file.getName());
    }
}



AOP (Aspect Oriented Programming)

AOP๊ฐ€ ์ ์šฉ๋˜๋Š” ๋ถ€๋ถ„์€ Service Layer์— ๊ฐ€๊น๋‹ค.

AOP๊ฐ€ ์ค‘์š”ํ•œ ์ด์œ 

AOP ๋Š” ๋‹ค๋ฅธ Service Layer์˜ ๋ฉ”์†Œ๋“œ๋ฅผ ๋นจ๋Œ€ ๊ฝ‚์•„ ๊ฐ€์ ธ์™€์„œ ์ž์‹ ๋งŒ์˜ ์ƒˆ๋กœ์šด ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ

ํŽธ์ง‘ํ•ด ์ž์‹ ๋งŒ์˜ ๊ฒƒ์œผ๋กœ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด๋‹ค.

OOP ๋Š” ์—ฌ๋Ÿฌ ์š”์†Œ๋“ค์ด ๋ชจ๋“ˆํ™”๋˜์–ด์ ธ์žˆ์–ด์„œ ๋…๋ฆฝํ™” โ†’ ์žฌ์‚ฌ์šฉ์„ฑ์ด ๋†’์•„์ง

AOP ๋Š” ๋ชจ๋“ˆํ™” ๋˜์–ด์žˆ๋Š” ๊ฒƒ์„ ๋ถ„ํ•ด์‹œํ‚จ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ๊ณ„์ขŒ์ด์ฒด๋ฅผ ํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ๋ณด์ž

1
2
3
4
5
6
transfer(){ //๊ณ„์ขŒ ์ด์ฒด
	log(); //๋ถ€์ˆ˜์ ์ธ ๊ด€์‹ฌ์‚ฌ(Cross Cutting Concern)
	dao.login(); //ํ•ต์‹ฌ๊ธฐ๋Šฅ(Core Concern)
	security(); //Cross Cutting concern
	log(); //Cross Cutting concern
}

image-42

Target์—๋Š” Core Concern์— ๋‘”๋‹ค.

Advice์—๋Š” Cross Cutting Concern์— ๋‘”๋‹ค.

์ด๋ ‡๊ฒŒ ๋ถ„๋ฆฌ ํ•˜๋Š” ๊ฒƒ์ด AOP ๋ผ๊ณ  ํ•œ๋‹ค.

Aspect๋Š” Core Concern ๊ณผ Cross Cutting Concern ์ด๋‹ค.

๋ถ„๋ฆฌ์‹œ์ผœ๋†“๊ณ  Target ๊ธฐ๋Šฅ์ด ์‹คํ–‰๋  ๋•Œ ๋‚ด๊ฐ€ ์›ํ•˜๋Š”๋Œ€๋กœ Advice ๋ถ€๋ถ„์ด ๋‚ด๋ ค ๊ฝ‚ํ˜€์„œ

์‹คํ–‰๋˜๋Š” ๊ฒƒ์ด Weaving์ด๋ผ๊ณ  ํ•œ๋‹ค.

๋‚ด๋ ค ๊ฝ‚ํ˜€์ง€๋Š” ๊ณณ์ด Join Point ๋ผ๊ณ  ํ•œ๋‹ค.

ํ”„๋กœ๊ทธ๋žจ์˜ ๊ฒฐ๊ณผ๋Š” ๋˜‘๊ฐ™๋‹ค. ํ•˜์ง€๋งŒ

๊ฒฐ๊ณผ์ ์œผ๋กœ ๋ณด๋ฉด OOP ์˜ ๋ํŒ์™•์ด๋ผ๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

AOP ๊ฐ€ ์–ด๋–ค ์ƒํ™ฉ์—์„œ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋Š”์ง€๊ฐ€ ์ค‘์š”ํ•˜๋‹ค.

๋จผ์ € AOP ๋ฅผ ์ ์šฉํ•˜์ง€ ์•Š์€ ์ƒํƒœ๋ฅผ ๋ณด๊ฒ ๋‹ค.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package spring.aop.prob;

public class MemberService {
	
	private Log log = LogFactory.getLog(getClass());
	
	public void register(String name) {
		log.info(name+" :: ๋‹˜ ํšŒ์›๋“ฑ๋ก ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค."); //cross cutting
		System.out.println("register....logic...ํšŒ์› ๋“ฑ๋ก ์„ฑ๊ณต"); //core 
		log.info(name+" :: ๋‹˜ ํšŒ์›๋“ฑ๋ก ์‹œ๋„ ์„ฑ๊ณตํ•˜์…จ์Šต๋‹ˆ๋‹ค.");//cross cutting

	}
	
	public void findMember(String id) {
		System.out.println("findMember...logic....ํšŒ์›๊ฒ€์ƒ‰ ์„ฑ๊ณต");
	}
}

์œ„ ์ฝ”๋“œ๋Š” Business Logic ์„ ํ˜ธ์ถœํ•˜๊ณ  ์žˆ๋Š” ์„œ๋น„์Šค ํด๋ž˜์Šค์ด๋‹ค.

ํ•ต์‹ฌ์ ์ธ ๋กœ์ง(Core Concern) ์‚ฌ์ด์‚ฌ์ด์— ๋ถ€์ˆ˜์ ์ธ ๋กœ์ง(Cross Cutting Concern)์ด ์‚ฐ๋ฐœ์ ์œผ๋กœ ํ˜ผ์žฌ๋˜์–ด

์žˆ๋‹ค.

๊ฒฐ๊ณผ์ ์œผ๋กœ OOP ์˜ ๋ณธ์งˆ์„ ํ๋ฆฌ๊ณ  ์žˆ๋‹ค.

์œ„ ์ฝ”๋“œ์—์„œ๋Š” Cross Cutting Concern์— ํ•ด๋‹นํ•˜๋Š” ๋กœ์ง์„ log ํŒŒ์ผ ์ถœ๋ ฅ์œผ๋กœ ์ •ํ•ด์„œ ์ž‘์„ฑํ•˜์˜€๋‹ค.

๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋น„์Šทํ•œ ์œ ํ˜•์ธ ProductService class ๋ฅผ ๋งŒ๋“ค์–ด ์ฃผ์—ˆ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
package spring.aop.prob;

public class ProductService {
	private Log log = LogFactory.getLog(getClass());

    public String deleteProduct(String id) {
        System.out.println(id+" :: deleteProduct..logic..์‚ญ์ œ ์„ฑ๊ณต");
        log.info(id+" :: deleteProduct info...");

        return "์‚ญ์ œ๋œ ์ƒํ’ˆ ID :"+id;
    }
}

์ด์ œ DI๋ฅผ ์ ์šฉํ•˜๊ธฐ ์œ„ํ•ด bean์„ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค.

1
2
3
4
5
6
7
8
9
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean id="member" class="spring.aop.prob.MemberService"/>
<bean id="product" class="spring.aop.prob.ProductService"/>

</beans>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package aop.test;

public class AopAppTest1 {

	public static void main(String[] args) {
		ApplicationContext factory = 
				new ClassPathXmlApplicationContext("beans/prob.xml");
		
		System.out.println("===prob.xml์„ ์ฝ์–ด์„œ ๋นˆ์„ ์ƒ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.====");
		
		MemberService member = (MemberService)factory.getBean("member");
		ProductService product = (ProductService)factory.getBean("product");
		member.register("kbstar");
		member.findMember("kbstar");
		
		System.out.println("\n****************************\n");
		product.deleteProduct("aaa");
	}
}

image-43 (์ด์™€ ๊ฐ™์€ ์ถœ๋ ฅ์ด ๋‚˜์˜จ๋‹ค)

log ๊ฐ€ ๊ฐ™์ด ๋‚˜์˜จ๋‹ค.

์ด์ œ AOP ๋ฅผ ์ ์šฉํ•ด๋ณด์ž

MemberService ์—์„œ Core Concern ๋งŒ ๋นผ๊ณ  ๋ชจ๋‘ ์ œ๊ฑฐํ–ˆ๋‹ค. ์ฆ‰ Target ์ด๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
package spring.aop.solv;

//Target Class..
public class MemberService {
		
	public void register(String name) {
		System.out.println("register....logic...ํšŒ์› ๋“ฑ๋ก ์„ฑ๊ณต"); //core 
	}
	
	public void findMember(String id) {
		System.out.println("findMember...logic....ํšŒ์›๊ฒ€์ƒ‰ ์„ฑ๊ณต");
	}
}

ProductService ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ Core Concern๋งŒ ๋‚จ๊ธฐ๊ณ  ๋ชจ๋‘ ์ œ๊ฑฐํ–ˆ๋‹ค. ์ฆ‰, Target ์ด๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
package spring.aop.solv;

//ํ•ต์‹ฌ ๊ด€์‹ฌ์‚ฌ๋งŒ ๋“ค์–ด์žˆ๋Š” ํด๋ž˜์Šค
//Target Class
public class ProductService {

    public String deleteProduct(String id) {
        System.out.println(id+" :: deleteProduct..logic..์‚ญ์ œ ์„ฑ๊ณต");
        return "์‚ญ์ œ๋œ ์ƒํ’ˆ ID :"+id;
    }
}

์ด์ œ ์ œ๊ฑฐ๋œ Cross Cutting Concern ๋”ฐ๋กœ ๋ชจ์•„์ค„ Advice ๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package spring.aop.solv;

/*
 * ๋ถ€์ˆ˜์ ์ธ ๊ด€์‹ฌ์‚ฌ๋งŒ ๋ชจ์•„ ๋†“์€ ํด๋ž˜์Šค...
 * Advice Class
 */
public class LoggingAdvice {
	private Log log = LogFactory.getLog(getClass());
	
	public void logPush(ProceedingJoinPoint pjp) throws Throwable{
        log.info("\ncheck...before logging...");

        Object ret=pjp.proceed();//target์œผ๋กœ ์œ„๋น™๋˜๋Š” ์‹œ์ 
        System.out.println("target method return..."+ret);
	}
}

๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋˜ bean์„ ์„ค์ •ํ•ด์ค€๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?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:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">

<!-- Target 2๊ฐœ (member, product),  Advice 1๊ฐœ (logging)  -->
<bean id="member" class="spring.aop.solv.MemberService"/>
<bean id="product" class="spring.aop.solv.ProductService"/>
<bean id="logging" class="spring.aop.solv.LoggingAdvice"/>

<!-- Advice์˜ ์–ด๋–ค ๋ฉ”์†Œ๋“œ๊ฐ€ Target์— ์–ด๋””๋กœ weaving ๋˜๋Š”์ง€๋ฅผ ์ง€์ •ํ•ด์ค˜์•ผ ํ•œ๋‹ค. => <aop:config> -->
<aop:config>
	<aop:aspect id="loggingAspect" ref="logging">
		<aop:pointcut expression="execution(* spring.aop..*(..))" id="pc"/> <!--Target์˜ ํ™•์žฅ์ž๋Š” ์ƒ๊ด€์—†๊ณ , spring.aop ๋ฐ‘์— ์•„๋ฌด๊ฑฐ๋‚˜ ์ƒ๊ด€์—†์ด  -->
		<aop:around method="logPush" pointcut-ref="pc"/>
	</aop:aspect>
</aop:config>

</beans>

image-44

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package aop.test;

public class AopAppTest2 {

	public static void main(String[] args) {
		ApplicationContext factory = 
				new ClassPathXmlApplicationContext("beans/solv.xml");
		
		System.out.println("===solv.xml์„ ์ฝ์–ด์„œ ๋นˆ์„ ์ƒ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.====");
		
		MemberService member = (MemberService)factory.getBean("member");
		ProductService product = (ProductService)factory.getBean("product");
		member.register("kbstar");
		member.findMember("kbstar");
		
		System.out.println("\n****************************\n");
		product.deleteProduct("aaa");
		
	}
}

image-45

์œ„์™€ ๊ฐ™์ด ์ถœ๋ ฅ๋œ๋‹ค.

๊ฒฐ๊ตญ AOP ๋ฅผ ์‚ฌ์šฉํ•˜๋“  ์•ˆํ•˜๋“  ๊ฒฐ๊ณผ๊ฐ’์€ ๋˜‘๊ฐ™๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

ํ•˜์ง€๋งŒ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ๋Š” AOP๋ฅผ ์‚ฌ์šฉํ•จ์œผ๋กœ์จ

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๊ณตํ†ต์˜ ๊ธฐ๋Šฅ์„ ๊ฐ€์ง„ ๋ถ€๋ถ„(์˜ˆ๋ฅผ ๋“ค์–ด, ๋กœ๊น…, ๋ณด์•ˆ, ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ ๋“ฑ)์„

๋ณ„๋„์˜ ๊ด€์ (aspect)์œผ๋กœ ๋ถ„๋ฆฌํ•˜์—ฌ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ๋‹ค.

  1. ์ค‘๋ณต ์ฝ”๋“œ ๊ฐ์†Œ
  2. ๋ชจ๋“ˆ์„ฑ ํ–ฅ์ƒ
  3. ์œ ์ง€๋ณด์ˆ˜ ์šฉ์ด์„ฑ
  4. ์žฌ์‚ฌ์šฉ์„ฑ ์ฆ๊ฐ€
  5. ํšก๋‹จ ๊ด€์‹ฌ์‚ฌ(Cross-cutting Concerns)์˜ ํšจ์œจ์  ๊ด€๋ฆฌ
This post is licensed under CC BY 4.0 by the author.