๐ฅ [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๋ฅผ ์ํ ๋น์ ๋ฑ๋กํ๋ค.
Spring ์์ ํ์ผ ์ ๋ก๋ ํ๋ ๋ฒ
์ฌ์ฉ์๊ฐ ์ฌ๋ฆฐ ํ์ผ์ ์ด๋๋ค ์ ์ฅ์ ํ ๊น?
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>
โ
ํ์ผ ์ ๋ก๋ ๊ธฐ์ ์ฌ์ฉ์ ์ฃผ์ํ ์
- form ํ๊ทธ ์์ input type=โfileโ๋ก ํผ์ ๋ง๋ ๋ค
- method=post ๋ง ๊ฐ๋ฅํ๋ค.
- enctype=โmultipart/form-dataโ
- poem.xml์ fileupload dependency ์ถ๊ฐ
- ํ์ผ์ ๋ก๋ํ ์ ๋ณด๋ฅผ ์ ์ฅํ๋ 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";
}
}
(ํ์ผ์ด ์ ์์ ์ผ๋ก ์ง์ ๋์๋ค)
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 <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
}
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");
}
}
(์ด์ ๊ฐ์ ์ถ๋ ฅ์ด ๋์จ๋ค)
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>
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");
}
}
์์ ๊ฐ์ด ์ถ๋ ฅ๋๋ค.
๊ฒฐ๊ตญ AOP
๋ฅผ ์ฌ์ฉํ๋ ์ํ๋ ๊ฒฐ๊ณผ๊ฐ์ ๋๊ฐ๋ค๋ ๊ฒ์ ์ ์ ์๋ค.
ํ์ง๋ง ์ฌ์ฉํ๋ ์ด์ ๋ AOP๋ฅผ ์ฌ์ฉํจ์ผ๋ก์จ
์ ํ๋ฆฌ์ผ์ด์ ์์ ๊ณตํต์ ๊ธฐ๋ฅ์ ๊ฐ์ง ๋ถ๋ถ(์๋ฅผ ๋ค์ด, ๋ก๊น , ๋ณด์, ํธ๋์ญ์ ๊ด๋ฆฌ ๋ฑ)์
๋ณ๋์ ๊ด์ (aspect
)์ผ๋ก ๋ถ๋ฆฌํ์ฌ ๊ด๋ฆฌํ ์ ์๋ค๋ ์ฅ์ ์ด ์๋ค.
- ์ค๋ณต ์ฝ๋ ๊ฐ์
- ๋ชจ๋์ฑ ํฅ์
- ์ ์ง๋ณด์ ์ฉ์ด์ฑ
- ์ฌ์ฌ์ฉ์ฑ ์ฆ๊ฐ
- ํก๋จ ๊ด์ฌ์ฌ(Cross-cutting Concerns)์ ํจ์จ์ ๊ด๋ฆฌ