2022-03-30(์)
์ธ์
์ ์ฌ์ฉํ๋ request handler
ํด๋ผ์ด์ธํธ๊ฐ ๋ณด๋ธ ์ธ์
ID๋ก ์ด์ ์ ์์ฑํ ์ธ์
๊ฐ์ฒด๋ฅผ ์ฐพ๋๋ค.
๋ฌดํจํ ์ธ์ ์ด๋ฉด ์๋ก ์ธ์ ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด์ ๋๊ฒจ์ค๋ค
์๋ฒ์์ ์์ฑํ ์ธ์ ID
์ธ์ ID๋ ์น๋ธ๋ผ์ฐ์ ์์ ์์ฑํ๋ ๊ฒ ์๋๋ผ ์๋ฒ์์ ์์ฑํ๋ ๊ฑฐ
์ธ์ ์ ์๋ก ๋ง๋ ๊ฒ ์๋๋ฉด ์๋ตํ ๋ ์ธ์ ID๋ฅผ ๋ฆฌํดํ ํ์๊ฐ ์๋ค
์๋ก ๋ง๋ค์์ ๋๋ง ์๋ต ํค๋์ ํฌํจ๋๋ค
์ด๋ฆ(๊ฐ๋
)
๊ตฌ์กฐ๋
ํ๋ฆ(๊ณผ์ )
์์ง ๊ตฌ์ฒด์ ์ผ๋ก ๋จธ๋ฆฌ๋ก ๊ทธ๋ ค์ง์ง ์์ผ๋๊น ๋จธ๋ฆฌ์ 20~30%๋ง ๋จ์
์ธ์
ID๋ ์น๋ธ๋ผ์ฐ์ ์์ ์์ฑํ๋ ๊ฒ ์๋๋ผ ์๋ฒ์์ ์์ฑํ๋ ๊ฑฐ
fetch("/member/signup", { // ๋น๋๊ธฐ ๋ฐฉ์์ผ๋ก ์๋ฒ์ ์์ฒญ์ ๋ณด๋ธ๋ค.
method: "POST",
body: new URLSearchParams(fd)
})
http://localhost:8080/member/form.html
// MemberController
@RequestMapping("/member/signin")
public Object signin(String email, String password) {
return memberService.get(email, password);
}
public interface MemberService {
int add(Member member);
Member get(String email, String password);
}
@Override
public Member get(String email, String password) {
return memberDao.findByEmailAndPassword(email, password);
}
@Param์ ์ฌ์ฉํ์ฌ SQL Mapper์์ ์ฌ์ฉํ ์ด๋ฆ ์ง์
๋ณดํต์ ๊ฐ๊ฒ ํ๋ค
public interface MemberDao {
int insert(Member member);
Member findByEmailAndPassword(@Param("email") String email, @Param("password") String password);
<select id="findByEmailAndPassword" resultMap="memberMap">
select
no,
name,
email
from
ml_member
where
email=#{email} and password=password(#{password})
</select>
<resultMap type="member" id="memberMap">
<id column="no" property="no"/>
<result column="name" property="name"/>
<result column="email" property="email"/>
<result column="regist_date" property="registDate"/>
</resultMap>
http://localhost:8080/member/signin.html
http://localhost:8080/member/signin?email=user1@test.com&password=abc123
json์ผ๋ก ๋ฐ๊พธ๊ธฐ
fetch("/member/signin", { // ๋น๋๊ธฐ ๋ฐฉ์์ผ๋ก ์๋ฒ์ ์์ฒญ์ ๋ณด๋ธ๋ค.
method: "POST",
body: new URLSearchParams(fd)
})
.then(function(response) {
return response.json();
})
.then(function(obj) {
console.log(obj);
window.alert("๋ก๊ทธ์ธ ์ฑ๊ณต");
});
fetch("/member/signin", { // ๋น๋๊ธฐ ๋ฐฉ์์ผ๋ก ์๋ฒ์ ์์ฒญ์ ๋ณด๋ธ๋ค.
method: "POST",
body: new URLSearchParams(fd)
})
.then(function(response) {
return response.json();
})
.then(function(obj) {
if (obj == "") {
window.alert("๋ก๊ทธ์ธ ์คํจ!");
} else {
window.alert(obj.name + "๋ ํ์ํฉ๋๋ค!");
}
});
@RequestMapping("/member/signin")
public Object signin(String email, String password) {
Member loginUser = memberService.get(email, password);
if (loginUser == null) {
return "";
} else {
return loginUser;
}
}
json์ ์ผ๋ฐ ๋ฌธ์์ด๋ก ๋ณด๋ด๋ฉด ์ ๋๋ค... null์ ๋ณด๋ด๋ ์ ๋๋ค
@RequestMapping("/member/signin")
public Object signin(String email, String password) {
Member loginUser = memberService.get(email, password);
if (loginUser == null) {
return "fail";
} else {
return "success";
}
}
fetch("/member/signin", { // ๋น๋๊ธฐ ๋ฐฉ์์ผ๋ก ์๋ฒ์ ์์ฒญ์ ๋ณด๋ธ๋ค.
method: "POST",
body: new URLSearchParams(fd)
})
.then(function(response) {
return response.text();
})
.then(function(text) {
if (text == "success") {
location.href = "../index.html";
} else {
window.alert("๋ก๊ทธ์ธ ์คํจ!");
}
});
๋ก๊ทธ์ธ ์ฑ๊ณตํ๋ฉด index.html๋ก ์ด
@RequestMapping("/member/signin")
public Object signin(String email, String password, HttpSession session) {
Member loginUser = memberService.get(email, password);
if (loginUser == null) {
return "fail";
}
// ๋ก๊ทธ์ธ์ด ์ฑ๊ณตํ๋ฉด,
// ๋ค๋ฅธ ์์ฒญ์ ์ฒ๋ฆฌํ ๋ ๋ก๊ทธ์ธ ํ์์ ์ ๋ณด๋ฅผ ์ฌ์ฉํ ์ ์๋๋ก ์ธ์
์ ๋ณด๊ดํ๋ค.
session.setAttribute("loginUser", loginUser);
return "success";
}
DAO ๊ตฌํ์ฒด๊ฐ ์ฌ์ฉํ SQL Mapper ํ์ผ์ ์์น๋ ์ธํฐํ์ด์ค์ ํจํค์ง ๊ฒฝ๋ก ๋ฐ ์ด๋ฆ๊ณผ ์ผ์นํด์ผ ํ๋ค.
SQL Mapper ํ์ผ ์ด๋ฆ์ด๋ ์ธํฐํ์ด์ค ์ด๋ฆํ๊ณ ๋๊ฐ์์ผ ํจ (MemberDao.xml)
http://localhost:8080/member/signin.html
<form name="form1">
์ด๋ฉ์ผ: <input name="email" type="email"><br>
์ํธ: <input name="password" type="password"><br>
<div>
<button id="x-add-btn">๋ก๊ทธ์ธ</button>
<button id="x-cancel-btn" type="button">์ทจ์</button>
</div>
<div>
<a href="form.html">ํ์๊ฐ์
</a>
</div>
</form>
@RequestMapping("/member/signup")
public Object signup(Member member) {
if (memberService.add(member) == 1) {
return "success";
} else {
return "fail";
}
}
// form.html
fetch("/member/signup", { // ๋น๋๊ธฐ ๋ฐฉ์์ผ๋ก ์๋ฒ์ ์์ฒญ์ ๋ณด๋ธ๋ค.
method: "POST",
body: new URLSearchParams(fd)
})
.then(function(response) {
return response.text();
})
.then(function(text) {
if (text == "success") {
location.href = "signin.html";
} else {
window.alert("ํ์๊ฐ์
์คํจ!");
}
});
return false;
};
document.querySelector("#x-cancel-btn").onclick = function() {
window.location.href = "../index.html";
};
์๋จ ๋ฉ๋ด๋ฐ๋ฅผ ์ถ๊ฐํ๋ค.
// index.html
<style>
#header {
background-color: navy;
color: white;
height: 50px;
display: flex;
align-items: center;
}
</style>
</head>
<body>
<div id="header">
MyList
<button id="login-btn" type="button">๋ก๊ทธ์ธ</button>
<button id="logout-btn" type="button">๋ก๊ทธ์์</button>
</div>
package com.eomcs.mylist.controller;
import lombok.Data;
@Data
public class ResultMap {
final String status;
final Object data;
}
final ๋ถ์ด๋ฉด ์์ฑ์
package com.eomcs.mylist.controller;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
@Data
@NoArgsConstructor(force = true) // ๊ธฐ๋ณธ ์์ฑ์๋ฅผ ๋ฌด์กฐ๊ฑด ๋ง๋ค๊ฒ ํ๋ค.
@RequiredArgsConstructor // final์ด ๋ถ์ ํ๋์ ๊ฐ์ ํ๋ผ๋ฏธํฐ๋ก ๋ฐ๋ ์์ฑ์๋ฅผ ๋ง๋ค๊ฒ ํ๋ค.
public class ResultMap {
final String status;
final Object data;
}
@RequestMapping("/member/getLoginUser")
public Object getLoginUser(HttpSession session) {
Object data = session.getAttribute("loginUser");
if (data != null) {
return new ResultMap("success", data);
} else {
return new ResultMap("fail", "๋ก๊ทธ์ธ ํ์ง ์์์ต๋๋ค.");
}
}
8๋จ๊ณ - ๋ก๊ทธ์ธ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ์กฐํํ๋ค.
โข controller.ResultMap ํด๋์ค ์ถ๊ฐ
JSON ํ์์ ๋ฐ์ดํฐ๋ฅผ ๋ฆฌํดํ ๋ ์ฌ์ฉํ ํด๋์ค
์์
์ฑ๊ณต ์ ๋ฌด์ ๊ฒฐ๊ณผ๋ฅผ ์ ์ฅํ๋ค.
โข MemberController ํด๋์ค ๋ณ๊ฒฝ
getLoginUser() ๋ฉ์๋ ์ถ๊ฐ
final, ์ ๋ ธํ ์ด์ ์ง์ฐ๊ธฐ
package com.eomcs.mylist.controller;
import lombok.Data;
@Data
public class ResultMap {
String status;
Object data;
}
lombok setter return this ๊ฒ์
์ธํฐ ๊ฒํฐ ๋ฉ์๋ ์ด๋ฆ์ด ํ๋ ์ด๋ฆ๊ณผ ๊ฐ์
์ธํฐ์ ๋ฆฌํด ํ์
๋ ResultMap
์ ๋์ด(get/set)๋ฅผ ๋ถ์ด๋ ๊ฒฝ์ฐ๋ ์๊ณ ์๋ ๊ฒฝ์ฐ๋ ์์
@Accessors(fluent = true) ํ๋ฉด ํ๋ ์ด๋ฆ๊ณผ ๊ฐ๊ฒ ๋ง๋ค์ด์ง๋ค
์ธํฐ๋ฅผ ํตํด์๋ง ์ ๊ทผํ ์ ์
package com.eomcs.mylist.controller;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(fluent = true)
public class ResultMap {
private String status;
private Object data;
}
ํ ๋์ ์์๋ณด๊ธฐ๊ฐ ์ฝ๋ค. ๊ทธ๋์ ์ด ๋ฐฉ๋ฒ์ ์ฐ๋ ๊ฑฐ
@RequestMapping("/member/getLoginUser")
public Object getLoginUser(HttpSession session) {
Object member = session.getAttribute("loginUser");
if (member != null) {
return new ResultMap().status("success").data(member);
} else {
return new ResultMap().status("fail").data("๋ก๊ทธ์ธ ํ์ง ์์์ต๋๋ค.");
}
}
์๋ฌ ๋จ
json ์ถฉ๋ ์ผ์ด๋จ
get, set์ผ๋ก ์์ํ๋
json ๋ฐ์ดํฐ๋ก ๋ฐ๊พธ
@Accessors(chain = true) ๋ก ๋ณ๊ฒฝํ๊ธฐ
@RequestMapping("/member/getLoginUser")
public Object getLoginUser(HttpSession session) {
Object member = session.getAttribute("loginUser");
if (member != null) {
return new ResultMap()
.setStatus("success")
.setData(member);
} else {
return new ResultMap()
.setStatus("fail")
.setData("๋ก๊ทธ์ธ ํ์ง ์์์ต๋๋ค.");
}
}
success ์
๋ ฅํ๋ค ๋ณด๋ฉด ์คํ ๋ ์๋ ์์
์คํ ๋ฐฉ์ง
์์๋ก ์ ์ํด๋๊ธฐ
package com.eomcs.mylist.controller;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class ResultMap {
public static final String SUCCESS = "success";
public static final String FAIL = "fail";
private String status;
private Object data;
}
@RequestMapping("/member/getLoginUser")
public Object getLoginUser(HttpSession session) {
Object member = session.getAttribute("loginUser");
if (member != null) {
return new ResultMap()
.setStatus(ResultMap.SUCCESS)
.setData(member);
} else {
return new ResultMap()
.setStatus(ResultMap.FAIL)
.setData("๋ก๊ทธ์ธ ํ์ง ์์์ต๋๋ค.");
}
}
์์ import ํ๊ธฐ
@RequestMapping("/member/getLoginUser")
public Object getLoginUser(HttpSession session) {
Object member = session.getAttribute("loginUser");
if (member != null) {
return new ResultMap()
.setStatus(SUCCESS)
.setData(member);
} else {
return new ResultMap()
.setStatus(FAIL)
.setData("๋ก๊ทธ์ธ ํ์ง ์์์ต๋๋ค.");
}
}
<div id="header">
<span id="app-title">MyList</span>
<span id="user-name"></span>
<button id="login-btn" type="button">๋ก๊ทธ์ธ</button>
<button id="logout-btn" type="button">๋ก๊ทธ์์</button>
</div>
<script type="text/javascript">
fetch("/member/getLoginUser").then(function(response) {
return response.json();
}).then(function(result) {
document.querySelector("#user-name").innerHTML = result.data.name;
});
</script>
var el = document.querySelectorAll(".login");
for (var e of el) {
e.style.display = "none"
}
function css(selector, name, value) {
var el = document.querySelectorAll(selector);
for (var e of el) {
e.style[name] = value;
}
}
jQuery ์ฌ์ฉํ๋ ์ด์
์ฝ๋๊ฐ ๊ฐ๊ฒฐํด์ง๋ค.
๋ธ๋ผ์ฐ์ ์ ๋ง์ถฐ์ ํด๋น๋๋ ๊ธฐ๋ฅ์ด ๋์ํ๋๋ก ์ฝ๋ฉ๋์ด ์๋ค.
ํฌ๋ก์ค ๋ธ๋ผ์ฐ์ง ์ง์
9๋จ๊ณ - ๋ก๊ทธ์์ ๊ธฐ๋ฅ์ ์ถ๊ฐํ๋ค.
๋ก๊ทธ์์์ Controller๋ง ๋ฐ๊พธ๋ฉด ๋จ
@RequestMapping("/member/signout")
public Object signout(HttpSession session) {
session.invalidate();
return new ResultMap().setStatus("success");
}
document.querySelector("#logout-btn").onclick = function() {
fetch("/member/signout").then(function(response) {
location.href = "/index.html"
});
}
18.2 ์ธ์ ๊ณผ ์ฟ ํค์ ํ์ฉ: ์ธ์ ํ์ฉํ๊ธฐ
๋ก๊ทธ์ธ๊ณผ ์ธ์ ์ ํ์ฉํ์ฌ ์ฌ์ฉ์๋ณ๋ก ๋ฐ์ดํฐ ์ฒ๋ฆฌํ๊ธฐ
alter table ml_board
add column writer int not null,
add constraint ml_board_fk foreign key (writer) references ml_member(no);
๊ธฐ์กด ๋ฐ์ดํฐ๊ฐ ์์ผ๋ฉด not null ์ปฌ๋ผ์ ๋์ค์ ์ถ๊ฐ ๋ถ๊ฐ
๋จผ์ ๊ธฐ์กด ๋ฐ์ดํฐ ๋ค ์ง์ฐ๊ธฐ
delete from ml_board;
3๋จ๊ณ์ ๊ฑฐ์ณ์ ํ๋ ๋ฐฉ๋ฒ๋ ์์
null ํ์ฉํ๊ณ ๊ฐ ๋ฃ๊ณ ๋ค์ not null๋ก ๋ฐ๊พธ๋ ๊ฑด ๊ฐ๋ฅ
2๋จ๊ณ - ๊ฒ์๊ธ์ ๋ค๋ฃจ๋ ๋๋ฉ์ธ ํด๋์ค์ ํ์ ๋ฒํธ๋ฅผ ๋ด๋ ํ๋๋ฅผ ์ถ๊ฐํ๋ค.
Board ํด๋์ค ๋ณ๊ฒฝํ๊ธฐ
@Data
public class Board {
int no;
String title;
String content;
int viewCount;
java.sql.Date createdDate;
int writer;
}
๊ฒ์๊ธ ์ ๋ ฅ ์ ์์ฑ์ ๋ฒํธ๋ฅผ ์ ๋ ฅํ๋๋ก SQL Mapper ํ์ผ์ ๋ณ๊ฒฝํ๋ค
๊ฒ์๊ธ ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃฐ ๋ ์์ฑ์ ๋ฒํธ๋ ํจ๊ป ๋ค๋ฃฌ๋ค
@RequestMapping("/board/add")
public Object add(Board board, HttpSession session) {
Member member = (Member) session.getAttribute("loginUser");
if (member == null) {
return new ResultMap().setStatus(FAIL).setData("๋ก๊ทธ์ธ ํ์ง ์์์ต๋๋ค.");
}
board.setWriter(member.getNo());
boardService.add(board);
return new ResultMap().setStatus(SUCCESS);
}
์๊ธฐ๊ฐ ์ด ๊ธ๋ง ๊ฐ๋ฅ
and writer=#{writer}
<update id="update" parameterType="Board">
update ml_board set
title=#{title},
content=#{content}
where
board_no=#{no} and writer=#{writer}
</update>
parameterType="board"๋ก ๋ณ๊ฒฝํ๊ธฐ
<delete id="delete" parameterType="board">
delete from ml_board
where board_no=#{no} and writer=#{writer}
</delete>
5๋จ๊ณ - ๊ฒ์๊ธ ์กฐํํ ๋ ๋ก๊ทธ์ธ ์ฌ์ฉ์์ ์ด๋ฆ์ ํจ๊ป ์กฐํํ๋ค.
<resultMap>
์ Member ๊ฐ์ฒด๋ฅผ ๊ฐ์ ธ์ค๋ ์ฝ๋๋ฅผ ์ถ๊ฐ
https://mybatis.org/mybatis-3/sqlmap-xml.html
<association>
โ 1:1 ๊ด๊ณ์ ํ
์ด๋ธ์ join ํ ๋ ์ฌ์ฉ
<!-- ํ
์ด๋ธ์ ์ปฌ๋ผ๊ณผ ๊ฐ์ฒด ํ๋๋ฅผ ์ฐ๊ฒฐํ๋ค. -->
<resultMap type="board" id="boardMap">
<id column="board_no" property="no"/>
<result column="title" property="title"/>
<result column="content" property="content"/>
<result column="created_date" property="createdDate"/>
<result column="view_count" property="viewCount"/>
<association property="writer" javaType="member">
<id column="no" property="no"/>
<result column="name" property="name"/>
</association>
</resultMap>
โ name ์ปฌ๋ผ ๊ฐ์ member ๊ฐ์ฒด์ name ์ด๋ผ๋ ํ๋์ ์ ์ฅํด๋ผ
<result column="name" property="name"/>
์ ๋ฒ ์๊ฐ์๋ ContactDao.xml์์ <collection>
์ ์จ์ ์ฐ๋ฝ์ฒ ํ
์ด๋ธ๊ณผ ์ ํ๋ฒํธ ํ
์ด๋ธ์ join ํ์๋ค
<collection>
โ 1:M ๊ด๊ณ์ ํ
์ด๋ธ์ join ํ ๋ ์ฌ์ฉ
findAll
, findByNo
SQL๋ฌธ ๋ณ๊ฒฝ: ml_member
ํ
์ด๋ธ๊ณผ ์กฐ์ธํ๋ค.
<select id="findAll" resultMap="boardMap">
select
b.board_no,
b.title,
b.created_date,
b.view_count,
m.no,
m.name
from
ml_board b
inner join ml_member m on (b.writer = m.no)
order by
b.board_no desc
</select>
๊ทธ๋๋ก ๋ณต์ฌํด์ sql๋ฌธ์ด ์ฌ๋ฐ๋ฅธ์ง ํ์ธํ๋ค.
select
b.board_no,
b.title,
b.created_date,
b.view_count,
m.no,
m.name
from
ml_board b
inner join ml_member m on (b.writer = m.no)
order by
b.board_no desc;
์ ๋์จ๋ค
๊ฒ์๊ธ๊ณผ ์์ฑ์
90-MyListํ๋ก์ ํธ2 / 67 ํ์ด์ง
๐น ํ
์ด๋ธ ๊ด๊ณ (ER-Diagram)
ml_board
ml_member
ํ ๋ช
์ ๋ฉค๋ฒ๋ 0๊ฐ ์ด์์ ๊ฒ์๊ธ์ ์ธ ์ ์๋ค.
๐น ์๋ฐ ๊ฐ์ฒด (UML Class Diagram) (๊ฐ์ฒด ๊ด๊ณ)
Board ๊ฐ์ฒด
Member ํด๋์ค
Board ๊ฐ์ฒด๋ writer๋ผ๋ ์ด๋ฆ์ผ๋ก Member ๊ฐ์ฒด 1๊ฐ๋ฅผ ํฌํจํ๋ค.
Class Diagram์ ๋ฐ๋ผ ์์ค์ฝ๋๋ฅผ ํํํ ๊ฒ โ
Board ์์ Member๋ฅผ ํฌํจํ๊ณ ์๋ค
Board ์์ Member๋ฅผ ํฌํจํ๊ณ ์๋ค
<select id="findByNo" resultMap="boardMap" parameterType="int">
select
b.board_no,
b.title,
b.content,
b.created_date,
b.view_count,
m.no,
m.name
from
ml_board b
inner join ml_member m on (b.writer = m.no)
where
b.board_no=#{no}
</select>
์ด์ writer๋ int๊ฐ ์๋. (Member๋ก ๋ฐ๊ฟจ์)
Board ๊ฐ์ฒด ์์ ๋ค์ด ์๋ writer ๊ฐ์ฒด์ no (writer.no)
writer โ writer.no
<insert>
, <update>
, <delete>
SQL๋ฌธ ๋ณ๊ฒฝ: writer ํ๋์ ํ์
์ด int์์ Member ๋ณ๊ฒฝ๋ ๊ฒ์ ์ ์ฉํ๋ค.
BoardController ํด๋์ค ๋ณ๊ฒฝ
add(), update(), delete() ๋ฉ์๋ ๋ณ๊ฒฝ
๋ฒํธ๊ฐ ์๋๋ผ Member ๊ฐ์ฒด๋ฅผ ๋ด๋๋ค
member.getNo()
โ member
localhost:8080/board/list
board ๊ฐ์ฒด ์์ writer ๊ฐ์ฒด๊ฐ ๋ค์ด ์๋ค
http://localhost:8080/board/get?no=12
${board.writer}
โ ${board.writer.name}
board ๊ฐ์ฒด์ writer ๋ผ๋ ํ๋๊ฐ Member ๊ฐ์ฒด์ด๋ค
writer ๊ฐ์ฒด์ name ํ๋
ํ์ด์ง ์ปจํธ๋กค๋ฌ์์ ๊ฒฐ๊ณผ๋ฅผ ๋ฆฌํดํ ๋ ์์ ์ฒ๋ผ ํ
์คํธ๋ก ๋ฆฌํดํ์ง ์๊ณ
ํญ์ ResultMap์ ๋ด์์ ์ฑ๊ณต ์คํจ ์ฌ๋ถ๋ฅผ ๋ฆฌํดํ์
Author And Source
์ด ๋ฌธ์ ์ ๊ดํ์ฌ(2022-03-30(์)), ์ฐ๋ฆฌ๋ ์ด๊ณณ์์ ๋ ๋ง์ ์๋ฃ๋ฅผ ๋ฐ๊ฒฌํ๊ณ ๋งํฌ๋ฅผ ํด๋ฆญํ์ฌ ๋ณด์๋ค https://velog.io/@banana/2022-03-30์์ ์ ๊ท์: ์์์ ์ ๋ณด๊ฐ ์์์ URL์ ํฌํจ๋์ด ์์ผ๋ฉฐ ์ ์๊ถ์ ์์์ ์์ ์ ๋๋ค.
์ฐ์ํ ๊ฐ๋ฐ์ ์ฝํ
์ธ ๋ฐ๊ฒฌ์ ์ ๋
(Collection and Share based on the CC Protocol.)
์ข์ ์นํ์ด์ง ์ฆ๊ฒจ์ฐพ๊ธฐ
๊ฐ๋ฐ์ ์ฐ์ ์ฌ์ดํธ ์์ง
๊ฐ๋ฐ์๊ฐ ์์์ผ ํ ํ์ ์ฌ์ดํธ 100์ ์ถ์ฒ ์ฐ๋ฆฌ๋ ๋น์ ์ ์ํด 100๊ฐ์ ์์ฃผ ์ฌ์ฉํ๋ ๊ฐ๋ฐ์ ํ์ต ์ฌ์ดํธ๋ฅผ ์ ๋ฆฌํ์ต๋๋ค