CHAP06 - DDD-START/ONLINE-STUDY GitHub Wiki
- ์์ฉ์๋น์ค ๊ตฌํ
- ํํ ์์ญ์ ์ญํ
- ๊ฐ ๊ฒ์ฆ๊ณผ ๊ถํ ๊ฐ์ฌ
๋๋ฉ์ธ ์์ญ์ ์ ๊ตฌํํ๋ ๊ฒ์ด ์ค์ํ์ง๋ง ๋๋ฉ์ธ์ด ์ ๊ธฐ๋ฅ์ ํ๋ ค๋ฉด ์ฌ์ฉ์์ ๋๋ฉ์ธ์ ์ฐ๊ฒฐํด์ฃผ๋ ๋งค๊ฐ์ฒด(์์ฉ์์ญ)๊ฐ ํ์ํ๋ค.
- ํํ ์์ญ
- ์ฌ์ฉ์์ ์์ฒญ์ ํด์
- HTTP ์์ฒญ์ URL, ์์ฒญ ํ๋ผ๋ฏธํฐ, ์ฟ ํค, ํค๋ ๋ฑ์ผ๋ก ์๋ง๋ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ ์์ฉ ์๋น์ค ์คํ (์์ฉ ์๋น์ค๊ฐ ์๊ตฌํ๋ ํ์์ผ๋ก ์ฌ์ฉ์ ์์ฒญ์ ๋ณํ), ์คํ ๊ฒฐ๊ณผ ๋ฆฌํด
- ์์ฉ ์์ญ
- ์ฌ์ฉ์๊ฐ ์ํ๋ ๊ธฐ๋ฅ์ ์ ๊ณต
- ๊ธฐ๋ฅ์ ์คํํ๋ ๋ฐ ํ์ํ ์ ๋ ฅ๊ฐ์ ๋ฉ์๋ ํ๋ผ๋ฏธํฐ๋ก ์ ๋ฌ๋ฐ๊ณ ์คํ ๊ฒฐ๊ณผ๋ฅผ ๋ฆฌํด
public ModelAndView join(HttpServletRequest request) {
String email = request.getParameter("email");
String password = request.getParameter("password");
// ์ฌ์ฉ์ ์์ฒญ์ ์์ฉ ์๋น์ค์ ๋ง๊ฒ ๋ณํ
JoinRequest joinReq = new JoinRequest(email, password);
// ๋ณํํ ๊ฐ์ฒด(๋ฐ์ดํฐ)๋ฅผ ์ด์ฉํด์ ์์ฉ ์๋น์ค ์คํ
joinService.join(joinReq);
// ...
}
์น๋ธ๋ผ์ฐ์ > HTML ์๋ต
REST ํด๋ผ์ด์ธํธ > JSON ์ด๋ XML ํ์
์ฌ์ฉ์์์ ์ํธ ์์ฉ์ ํํ ์์ญ์ด ์ฒ๋ฆฌํ๊ธฐ ๋๋ฌธ์ ์์ฉ ์๋น์ค๋ ํํ ์์ญ์ ์์กดํ์ง ์๋๋ค
์์ฉ ์์ญ์ ์ฌ์ฉ์๊ฐ ์น ๋ธ๋ผ์ฐ์ ๋ฅผ ์ฌ์ฉํ๋ ์ง, Rest API ๋ฅผ ํธ์ถํ๋ ์ง, TCP ์์ผ์ ์ฌ์ฉํ๋ ์ง ์ ํ์๊ฐ ์๋ค.
์์ฉ ์๋น์ค๋ ์ฌ์ฉ์(ํด๋ผ์ด์ธํธ)๊ฐ ์์ฒญํ ๊ธฐ๋ฅ์ ์คํํ๊ณ , ์ฌ์ฉ์ ์์ฒญ์ ์ฒ๋ฆฌํ๊ธฐ ์ํด ๋ฆฌํฌ์งํฐ๋ฆฌ๋ก๋ถํฐ ๋๋ฉ์ธ ๊ฐ์ฒด๋ฅผ ๊ตฌํ๊ณ , ๋๋ฉ์ธ ๊ฐ์ฒด ์ฌ์ฉ (๋๋ฉ์ธ ์์ญ๊ณผ ํํ ์์ญ์ ์ฐ๊ฒฐํด์ฃผ๋ ์ฐฝ๊ตฌ์ธ ํผ์ฌ๋ ์ญํ)
๋๋ฉ์ธ ๊ธฐ๋ฅ์ ์คํํ๋ ์์ฉ ์๋น์ค
public Result doSomeFunc(SomeReq req) {
// 1. ๋ฆฌํฌ์งํฐ๋ฆฌ์์ ์ ๊ทธ๋ฆฌ๊ฑฐํธ๋ฅผ ๊ตฌํ๋ค.
SomeAgg agg = someAggRepository.findById(req.getId());
checkNull(agg);
// 2. ์ ๊ทธ๋ฆฌ๊ฑฐํธ์ ๋๋ฉ์ธ ๊ธฐ๋ฅ์ ์คํํ๋ค.
agg.doFunc(req.getValue());
// 3. ๊ฒฐ๊ณผ๋ฅผ ๋ฆฌํดํ๋ค.
return createSuccessResult(agg);
// ...
}
์๋ก์ด ์ ๊ทธ๋ฆฌ๊ฑฐํธ๋ฅผ ์์ฑํ๋ ์์ฉ ์๋น์ค
public Result doSomeCreation(CreateSomeReq req) {
// 1. ๋ฐ์ดํฐ ์ค๋ณต ๋ฑ ๋ฐ์ดํฐ๊ฐ ์ ํจํ์ง ๊ฒ์ฌํ๋ค.
checkValid(req);
// 2. ์ ๊ทธ๋ฆฌ๊ฑฐํธ๋ฅผ ์์ฑํ๋ค.
SomeAgg newAgg = createSome(req);
// 3. ๋ฆฌํฌ์งํฐ๋ฆฌ์ ์ ๊ทธ๋ฆฌ๊ฑฐํธ๋ฅผ ์ ์ฅํ๋ค.
someAggRepository.save(newAgg);
// 4. ๊ฒฐ๊ณผ๋ฅผ ๋ฆฌํดํ๋ค.
return createSuccessResult(newAgg);
// ...
}
์์ฉ ์๋น์ค์ ์ฃผ๋ ์ญํ
- ๋๋ฉ์ธ ๊ฐ์ฒด ๊ฐ์ ์คํ ํ๋ฆ ์ ์ด
- ํธ๋์ญ์ ์ฒ๋ฆฌ (์์ฉ ์๋น์ค๋ ๋๋ฉ์ธ์ ์ํ ๋ณ๊ฒฝ์ ํธ๋์ญ์ ์ผ๋ก ์ฒ๋ฆฌํด์ผ ํ๋ค.)
- ์ ๊ทผ์ ์ด
- ์ด๋ฒคํธ ์ฒ๋ฆฌ
๋๋ฉ์ธ ๋ก์ง์ ๋๋ฉ์ธ ์์ญ์ ์์นํ๊ณ ์์ฉ ์๋น์ค๋ ๋๋ฉ์ธ ๋ก์ง์ ๊ตฌํํ์ง ์๋๋ค.
์ ) ์ํธ ๋ณ๊ฒฝ ๊ธฐ๋ฅ์ ์ํ ์์ฉ ์๋น์ค๋ Member
์ ๊ทธ๋ฆฌ๊ฑฐํธ์ ๊ด๋ จ ๋ฆฌํฌ์งํฐ๋ฆฌ๋ฅผ ์ด์ฉํด์ ๋๋ฉ์ธ ๊ฐ์ฒด ๊ฐ์ ์คํ ํ๋ฆ์ ์ ์ดํ๋ค.
public class ChangePasswordService {
public void changePassword(String memberId, String oldPw, String newPw) {
Member member = memberRepository.findById(memberId);
checkMember(member);
member.changePassword(oldPw, newPw);
}
}
์ํธ๋ฅผ ๋ณ๊ฒฝํ๊ธฐ ์ํด ๊ฒ์ฆํ๋ ๋ก์ง์ Member
์ ๊ทธ๋ฆฌ๊ฑฐํธ์!
public class Member {
public void changePassword(String oldPw, String newPw) {
if (!matchPassword(oldPw)) {
throw new BadPasswordException();
}
setpassword(newPw);
}
// ํ์ฌ ์ํธ์ ์ผ์นํ๋์ง ๊ฒ์ฌํ๋ ๋๋ฉ์ธ ๋ก์ง
public boolean matchPassword(String pwd) {
return passwordEncoder.matches(pwd);
}
private void setPassword(String newpw) {
if (isEmpty(newPw)) {
throw new IllegalArgumentException("no new password");
}
this.password = newPw;
}
}
๋๋ฉ์ธ ๋ก์ง์ ๋๋ฉ์ธ ์์ญ๊ณผ ์์ฉ ์๋น์ค์ ๋ถ์ฐํด์ ๊ตฌํํ๋ฉด..
- ์ฝ๋์ ์์ง์ฑ์ด ๋จ์ด์ง๋ค.
- ๋๋ฉ์ธ ๋ฐ์ดํฐ์ ๊ทธ ๋ฐ์ดํฐ๋ฅผ ์กฐ์ํ๋ ๋๋ฉ์ธ ๋ก์ง์ด ํ ์์ญ์ ์์นํ์ง ์๊ณ , ์๋ก ๋ค๋ฅธ ์์ญ์ ์์นํ๊ฒ ๋จ
- ๋๋ฉ์ธ ๋ก์ง์ ํ์ ํ๊ธฐ ์ํด ์ฌ๋ฌ ์์ญ์ ๋ถ์ํด์ผ
- ์ฌ๋ฌ ์์ฉ ์๋น์ค์์ ๋์ผํ ๋ก์ง์ ์ด์ฉํ๊ณ ์ ํ ๊ฒฝ์ฐ ์ค๋ณต์ด ๋ฐ์ํ ์ ์๋ค.
- ๋ณ๊ฒฝ์ด ์ด๋ ค์์ง
์์ฉ ์๋น์ค > ํํ ์์ญ๊ณผ ๋๋ฉ์ธ ์์ญ์ ์ฐ๊ฒฐํ๋ ๋งค๊ฐ์ฒด ์ญํ . (๋์์ธํจํด์ ํผ์ฌ๋ ํจํด๊ณผ ๊ฐ์ ์ญํ )
์์ฉ ์๋น์ค ์์ฒด์ ๋ณต์กํ ๋ก์ง์ ์ํํ์ง ์๊ธฐ ๋๋ฌธ์ ์์ฉ ์๋น์ค์ ๊ตฌํ์ ์ด๋ ต์ง ์๋ค.
- ํ ์์ฉ ์๋น์ค ํด๋์ค์ ํ์ ๋๋ฉ์ธ์ ๋ชจ๋ ๊ธฐ๋ฅ ๊ตฌํํ๊ธฐ
- ๊ตฌ๋ถ๋๋ ๊ธฐ๋ฅ ๋ณ๋ก ์์ฉ ์๋น์ค ํด๋์ค๋ฅผ ๋ฐ๋ก ๊ตฌํํ๊ธฐ
ํด๋์ค์ ํฌํค๊ฐ ์ปค์ง vs ํด๋์ค ๊ฐ์ ์ฆ๊ฐ
- ๋ณ๋์ ํด๋์ค๋ก ๋ถ๋ฆฌํ์ฌ ๋ก์ง์ ๊ตฌํํ ๊ฒฝ์ฐ, ์ฌ๋ฌ ํด๋์ค์ ์ค๋ณตํด์ ๋์ผํ ์ฝ๋๋ฅผ ๊ตฌํํ์ง ์์๋ ๋์ด ์ฝ๋ ์ค๋ณต์ ๋ฐฉ์งํ ์ ์๋ค.
- ํ ํด๋์ค๊ฐ ์ฌ๋ฌ ์ญํ ์ ๊ฐ๋ ๊ฒ๋ณด๋ค ๊ฐ ํด๋์ค๋ง๋ค ๊ตฌ๋ถ๋๋ ์ญํ ์ ๊ฐ๋ ๊ฒ์ด ๋ ์ข๋ค.
์ธํฐํ์ด์ค๊ฐ ํ์ํ๊ฐ?
์ธํฐํ์ด์ค๊ฐ ํ์ํ ์ํฉ
- ๊ตฌํ ํด๋์ค๊ฐ ์ฌ๋ฌ ๊ฐ์ธ ๊ฒฝ์ฐ๋ ๋ฐํ์์ ๊ตฌํ ๊ฐ์ฒด๋ฅผ ๊ต์ฒดํด์ผํ๋ ๊ฒฝ์ฐ ( ๊ทธ๋ฌ๋ ์ด๋ฌํ ์ํฉ์ ๋งค์ฐ ๋๋ฌผ๋ค.)
๋ฐ์๊ฐ๋ฅํ ๋ฌธ์
- ์์ค ํ์ผ์ ์ฆ๊ฐ
- ๊ตฌํ ํด๋์ค์ ๋ํ ๊ฐ์ ์ฐธ์กฐ ์ฆ๊ฐ > ์ ์ฒด ๊ตฌ์กฐ๊ฐ ๋ณต์กํด ์ง
TDD๋ฅผ ์ฆ๊ฒจํ๊ณ ํํ ์์ญ๋ถํฐ ๊ฐ๋ฐ์ ์์ํ๋ค๋ฉด ๋ฏธ๋ฆฌ ์์ฉ ์๋น์ค๋ฅผ ๊ตฌํํ ์ ์์ด ์์ฉ ์๋น์ค์ ์ธํฐํ์ด์ค๋ถํฐ ์์ฑํ๊ฒ ๋ ํ ๋ฐ, TDD ๋ก ๋จผ์ ์ปจํธ๋กค๋ฌ๋ฅผ ๊ฐ๋ฐํ๋ค๋ฉด ์ปจํธ๋กค๋ฌ์์ ์ฌ์ฉํ ์์ฉ ์๋น์ค ํด๋์ค์ ๊ตฌํ์ ์กด์ฌํ์ง ์์ผ๋ฏ๋ก ์์ฉ ์๋น์ค์ ์ธํฐํ์ด์ค๋ฅผ ์ด์ฉํด์ ์ปจํธ๋กค๋ฌ์ ๊ตฌํ์ ์์ฑํด๋๊ฐ๊ฒ ๋๋ค
Mocjito ์ ๊ฐ์ ํ ์คํธ ๋๊ตฌ๋ ํด๋์ค์ ๋ํด์๋ ํ ์คํธ์ฉ ๊ฐ์ง ๊ฐ์ฒด๋ฅผ ๋ง๋ค ์ ์๊ธฐ ๋๋ฌธ์ ์์ฉ ์๋น์ค์ ๋ํ ์ธํฐํ์ด์ค๊ฐ ์์ด๋ ํํ์์ญ์ ํ ์คํธํ ์ ์๋ค.
๋ฐ๋ผ์, ์์ฉ ์๋น์ค์ ๋ํ ์ธํฐํ์ด์ค ํ์์ฑ X
์์ฉ ์๋น์ค๊ฐ ์ ๊ณตํ๋ ๋ฉ์๋๋ ๋๋ฉ์ธ์ ์ด์ฉํด์ ์ฌ์ฉ์๊ฐ ์๊ตฌํ ๊ธฐ๋ฅ์ ์คํํ๋ ๋ฐ ํ์ํ ๊ฐ์ ํ๋ผ๋ฏธํฐ๋ฅผ ํตํด ์ ๋ฌ๋ฐ๋๋ค.
- ํ์ํ ๊ฐ์ ๊ฐ๋ณ ํ๋ผ๋ฏธํฐ๋ก ๋ฐ๊ธฐ
- ๊ฐ์ฒด๋ก ์ ๋ฌ ๋ฐ๊ธฐ (ํ๋ผ๋ฏธํฐ๊ฐ ๋๊ฐ ์ด์ ์กด์ฌํ ๊ฒฝ์ฐ)
@Controller
@RequestMapping("/member/changePassword")
public class MemberPasswordController {
@Autowired
private ChangePasswordService changePasswordService;
// ์๋ฐ ํด๋์ค๋ฅผ ์ด์ฉํด์ ์์ฉ ์๋น์ค์ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ๋ฉด
// ํ๋ ์์ํฌ๊ฐ ์ ๊ณตํ๋ ๊ธฐ๋ฅ์ ํ์ฉํ๊ธฐ์ ์ข์
@RequestMapping(method = RequestMethod.POST)
public String submit(ChangePasswordRequest changePwdReq) {
Authentication auth = SecurityContext.getAuthentication();
changePwdReq.setMemberId(auth.getid());
try {
changePasswordService.changePassword(changePwdReq);
} catch (NoMemberException ex) {
// ์๋ง์ ์ต์
์
์ฒ๋ฆฌ ๋ฐ ์๋ต
}
}
}
ํํ ์์ญ์์ ์์ฉ ์๋น์ค์ ๊ฒฐ๊ณผ๊ฐ ํ์ํ๋ค๋ฉด ์์ฉ ์๋น์ค ๋ฉ์๋์ ๊ฒฐ๊ณผ๋ก ํ์ํ ๋ฐ์ดํฐ๋ฅผ ๋ฆฌํด.
์ ) ์ฃผ๋ฌธ > ์ฃผ๋ฌธ๋ฒํธ ๋ฆฌํด
public class OrderService {
@Transactional
public OrderNo placeOrder(OrderRequest orderRequest) {
OrderNo orderNo = orderRepository.nextId();
Order order = createOrder(orderNo, orderRequest);
orderRepository.save(order);
// ์์ฉ ์๋น์ค ์คํ ํ ํํ ์์ญ์์ ํ์ํ ๊ฐ ๋ฆฌํด
return orderNo;
}
}
์์ฉ ์๋น์ค์์ ์ ๊ทธ๋ฆฌ๊ฑฐํธ ์์ฒด๋ฅผ ์ ๋ฌํ๋ฉด ๋๋ฉ์ธ ๋ก์ง ์คํ์ ์๋น์ค์ ํํ ์์ญ ๋ ๊ณณ์์ -> ๋ก์ง์ ์์ฉ ์๋น์ค์ ํํ ์์ญ์ ๋ถ์ฐ -> ์ฝ๋์ ์์ง๋ ๋ฎ์์ง
์ ๊ทธ๋ฆฌ๊ฑฐํธ์ ์ํ๋ฅผ ๋ณ๊ฒฝํ๋ ์์ฉ ์๋น์ค๊ฐ ์ ๊ทธ๋ฆฌ๊ฑฐํธ๋ฅผ ๋ฆฌํดํ ๊ฒฝ์ฐ ํด๋น ์ ๊ทธ๋ฆฌ๊ฑฐํธ์ ๊ธฐ๋ฅ์ ์ปจํธ๋กค๋ฌ๋ ๋ทฐ ์ฝ๋์์ ์คํํ๋ฉด ์๋๋ค๋ ๊ท์น๋ณด๋ค๋ ์์ฉ ์๋น์ค๋ ํํ ์์ญ์์ ํ์ํ ๋ฐ์ดํฐ๋ง ๋ฆฌํดํ๋๋ก ํ์ฌ ๊ธฐ๋ฅ ์คํ ๋ก์ง์ ์์ง๋๋ฅผ ๋์ด์. ( ๋ ํ์คํ ๋ฐฉ๋ฒ ! )
์ ) HttpServletRequest
/ HttpSession
์ ์์ฉ ์๋น์ค์ ํ๋ผ๋ฏธํฐ๋ก ์ ๋ฌํ์ง ์๋๋ก
์์ฉ ์๋น์ค์์ ํํ ์์ญ์ ๋ํ ์์กด์ด ๋ฐ์ํ ๊ฒฝ์ฐ
- ์์ฉ์๋น์ค๋ง ๋จ๋ ์ผ๋ก ํ ์คํธํ๊ธฐ ์ด๋ ค์์ง
- ํํ ์์ญ์ ๊ตฌํ์ด ๋ณ๊ฒฝ๋๋ฉด ์์ฉ ์๋น์ค์ ๊ตฌํ๋ ๋ณ๊ฒฝ๋์ด์ผ ํจ ํํ ์์ญ์ ์์ง๋ ๊นจ์ง๊ฒ ๋์ด ์ฝ๋์ ์ ์ง๋ณด์ ๋น์ฉ ์ฆ๊ฐ.. -> ์๋น์ค ๋ฉ์๋์ ํ๋ผ๋ฏธํฐ์ ๋ฆฌํด ํ์ ์ผ๋ก ํํ ์์ญ์ ๊ตฌํ ๊ธฐ์ ์ ์ฌ์ฉํ์ง ์๋๋ก
์คํ๋ง์์ ์ ๊ณตํ๋ @Transactional
์ฌ์ฉํ๊ธฐ
Exception ๋ฐ์ํ๋ฉด, ๋กค๋ฐฑ / Exception ๋ฐ์ํ์ง ์์ผ๋ฉด, ์ปค๋ฐ
์์ฉ ์๋น์ค์์๋ ๋๋ฉ์ธ์์ ๋ฐ์์ํจ ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌํด์ผ ํ๋ค
์ด๋ฒคํธ : ๋๋ฉ์ธ์์ ๋ฐ์ํ ์ํ ๋ณ๊ฒฝ (์ ) '์ํธ ๋ณ๊ฒฝ๋จ' ์ด๋ฒคํธ, '์ฃผ๋ฌธ ์ทจ์ํจ' ์ด๋ฒคํธ)
public class Member {
private Password password;
public void initializePassword() {
String newPassword = generateRandomPassword();
this.password = new Password(newPassword);
// ๋๋ฉ์ธ ์ด๋ฒคํธ ๋ฐ์
Events.raise(new PasswordChangedEvent(this.id, password));
}
}
PasswordChangeEvent
๋ ์ํธ๋ฅผ ์ด๊ธฐํํ์์ ํํํ๋ ์ด๋ฒคํธ
๋๋ฉ์ธ์์ ์ด๋ฒคํธ๋ฅผ ๋ฐ์์ํค๋ฉด ๊ทธ ์ด๋ฒคํธ๋ฅผ ๋ฐ์ ์ฒ๋ฆฌํ๋ ์ญํ ์ ๋ด๋นํ๋ ๊ฒ์ด ๋ฐ๋ก ์์ฉ ์๋น์ค.
์์ฉ ์๋น์ค๋ ์ด๋ฒคํธ๋ฅผ ๋ฐ์์ ์ด๋ฒคํธ์ ์๋ง์ ํ์ฒ๋ฆฌ๋ฅผ ๋ด๋น
์ ) ์ํธ ์ด๊ธฐํ๋จ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ๋ฉด ๋ณ๊ฒฝํ ์ํธ๋ฅผ ์ด๋ฉ์ผ๋ก ๋ฐ์กํ๋ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ๋ฑ๋กํ๋ ๋ฑ
public class InitPasswordService {
@Transactional
public void initializePassword(String memberId) {
Events.handle((PasswordChangedEvent evt) -> {
// evt.getId()์ ํด๋นํ๋ ํ์์๊ฒ ์ด๋ฉ์ผ ๋ฐ์กํ๋ ๊ธฐ๋ฅ ๊ตฌํ
});
Member member = memberRepository.findById(memberId);
checkMemberExists(member);
member.initializePassword();
}
}
member.initializePassword()
-> PasswordChangedEvent()
์ด๋ฒคํธ ๋ฐ์ -> Events.handle()
์ ๋ฑ๋กํ ์ด๋ฒคํธ ํธ๋ค๋ฌ๊ฐ ์ด ์ด๋ฒคํธ๋ฅผ ๋ฐ์์ ๋ฉ์ผ์ ๋ฐ์ก.
ํํ ์์ญ์ ์ฑ ์
- ์ฌ์ฉ์๊ฐ ์์คํ
์ ์ฌ์ฉํ ์ ์๋ (ํ๋ฉด) ํ๋ฆ์ ์ ๊ณตํ๊ณ ์ ์ดํ๋ค.
์น ์ ํ๋ฆฌ์ผ์ด์ ์ ํผ ํ๋ฉด
์์ฒญ์ ๋ํ ์ฒ๋ฆฌ ํ ๊ฒฐ๊ณผ๋ฅผ ์๋ต์ผ๋ก ์ ์ก - ์ฌ์ฉ์์ ์์ฒญ์ ์๋ง์ ์์ฉ ์๋น์ค์ ์ ๋ฌํ๊ณ ๊ฒฐ๊ณผ๋ฅผ ์ฌ์ฉ์์๊ฒ ์ ๊ณตํ๋ค.
ํ๋ฉด์ ๋ณด์ฌ์ฃผ๋ ๋ฐ ํ์ํ ํ ์ดํฐ๋ฅผ ์ฝ๊ฑฐ๋ ๋๋ฉ์ธ์ ์ํ๋ฅผ ๋ณ๊ฒฝ
์ฌ์ฉ์์ ์์ฒญ ๋ฐ์ดํฐ๋ฅผ ์์ฉ ์๋น์ค๊ฐ ์๊ตฌํ๋ ํ์์ผ๋ก ๋ณํ
์์ฉ ์๋น์ค์ ๊ฒฐ๊ณผ๋ฅผ ์ฌ์ฉ์์๊ฒ ์๋ตํ ์ ์๋ ํ์์ผ๋ก ๋ณํ - ์ฌ์ฉ์์ ์ธ์ ์ ๊ด๋ฆฌํ๋ค.
- ์์ฉ ์๋น์ค ์์ญ์์ ์ฒ๋ฆฌ ํผ์ ์๋ฌ๋ฉ์์ง๋ฅผ ๋ณด์ฌ์ฃผ๊ธฐ ์ํด ์ฝ๋๊ฐ ๋ณต์กํด ์ง ๋ชจ๋ ์กฐ๊ฑด์ ๋ํ ๊ฒ์ฆ์ด ์ด๋ ค์ ( ์ฒซ๋ฒ์งธ ์๋ฌ ๋ฉ์์ง๋ง ํ์ธํ ์ ์์)
- ํํ ์์ญ์์ ์ฒ๋ฆฌ
์คํ๋ง์์ ์ ๊ณตํ๋
Validator
์ธํฐํ์ด์ค๋ฅผ ์ฌ์ฉํ๋ฉด ๊ฐ๋จํ๊ฒ ๊ฒ์ฆ ๊ฐ๋ฅ ํ์ ๊ฐ๊ณผ ๊ฐ์ ํ์์ ๊ฒ์ฌํ๋ฉด ์ค์ง์ ์ผ๋ก ์์ฉ ์๋น์ค๋ ๋ ผ๋ฆฌ์ ์ค๋ฅ๋ง ๊ฒ์ฌํ๋ฉด ๋๋ค. ์ฆ, ๊ฐ์ ๊ฐ ๊ฒ์ฌ๋ฅผ ํํ ์์ญ๊ณผ ์์ฉ ์๋น์ค์์ ์ค๋ณต์ผ๋ก ํ ํ์๊ฐ ์์ด์ง๋ ๊ฒ, ๋ฐ๋ผ์ ์์ฉ ์๋น์ค๋ฅผ ์ฌ์ฉํ๋ ํํ ์์ญ ์ฝ๋๊ฐ ํ ๊ณณ์ด๋ฉด ๊ตฌํ์ ํธ๋ฆฌํจ์ ์ํด ์ญํ ์ ๋๋์ด ๊ฒ์ฆ์ ์ํํ ์๋ ์๋ค. - ํํ์์ญ: ํ์ ๊ฐ, ๊ฐ์ ํ์, ๋ฒ์ ๋ฑ์ ๊ฒ์ฆ
- ์์ฉ ์๋น์ค: ๋ฐ์ดํฐ์ ์กด์ฌ ์ ๋ฌด์ ๊ฐ์ ๋ ผ๋ฆฌ์ ์ค๋ฅ๋ฅผ ๊ฒ์ฆ
@Controller
public class Controller {
@RequestMapping
public String join(JoinRequest joinRequest, Errors errors) {
new JoinRequestValidator().validate(joinRequest, errors);
if (errors.hasErrors()) return formView;
try {
joinService.join(joinRequest);
return successView;
} catch (DuplicateIdException ex) {
errors.rejectValue(ex.getPropertyName(), "duplicate");
return formView;
}
}
}
๊ฐ๋ : ์ฌ์ฉ์๊ฐ ๊ธฐ๋ฅ์ ์คํํ ์ ์๋์ง ํ์ธํ๋ ๊ฒ
๋จ์ํ ์์คํ ์ ์ธ์ฆ ์ฌ๋ถ๋ง ๊ฒ์ฌํ๋ฉด ๋์ง๋ง, ์ฌ์ฉ์๊ฐ ๊ด๋ฆฌ์์ธ์ง ์ฌ๋ถ์ ๋ฐ๋ผ ์คํ๊ฐ๋ฅํ ๊ธฐ๋ฅ์ด ๋ฌ๋ผ์ง ์ ์๋ค. (์คํ๋ง ์ํ๋ฆฌํฐ๋ ์ํ์น Shiro ๊ฐ์ ํ๋ ์์ํฌ๋ฅผ ์ด์ฉํ์ฌ ๊ถํ ๊ฒ์ฌ ๊ธฐ๋ฅ ๊ตฌํ ๊ฐ๋ฅ)
๊ถํ ๊ฒ์ฌ ์์ญ
- ํํ ์์ญ
- ์์ฉ์๋น์ค
- ๋๋ฉ์ธ
URL ๋ง์ผ๋ก ์ ๊ทผ ์ ์ด๋ฅผ ํ ์ ์๋ ๊ฒฝ์ฐ ๋ฉ์๋ ๋จ์๋ก ๊ถํ ๊ฒ์ฌ๋ฅผ ์ํํด์ผ -> ์ด๊ฒ์ด ๊ผญ ์์ฉ ์๋น์ค์ ์ฝ๋์์ ์ง์ ๊ถํ ๊ฒ์ฌ๋ฅผ ํด์ผ ํ๋ค๋ ๊ฒ์ ์๋ฏธํ๋ ๊ฑด ์๋๋ค. ์๋ฅผ ๋ค์ด ์คํ๋ง ์ํ๋ฆฌํฐ๋ AOP๋ฅผ ํ์ฉํด์ ์ ๋ ธํ ์ด์ ์ผ๋ก ์๋น์ค ๋ฉ์๋์ ๋ํ ๊ถํ ๊ฒ์ฌ๋ฅผ ํ ์ ์๋ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ค.
public class BlockMemberService {
private MemberRepository memberRepository;
@PreAuthorize("hasRole('ADMIN')")
public void block(String memberId) {
Member member = memberRepository.findById(memberId);
if (member == null) throw new NoMemberException();
member.block();
}
// ...
}
๊ฐ๋ณ ๋๋ฉ์ธ ๋จ์๋ก ๊ถํ ๊ฒ์ฌ๋ฅผ ํํ๋ ๊ฒฝ์ฐ๋ ๋ค์ ๊ตฌํ์ด ๋ณต์กํด์ง๋ค.
์๋ฅผ ๋ค์ด ๊ฒ์๊ธ์ ์ญ์ ๋ ๋ณธ์ธ ๋๋ ๊ด๋ฆฌ์ ์ญํ ์๊ฐ์ง ์ฌ์ฉ์๋ง ๊ฐ๋ฅํ ๊ฒฝ์ฐ, ๊ฒ์๊ธ ์์ฑ์๊ฐ ๋ณธ์ธ์ธ์ง ํ์ธํ๋ ค๋ฉด ๊ฒ์๊ธ ์ ๊ทธ๋ฆฌ๊ฑฐํธ๋ฅผ ๋จผ์ ๋ก๋ฉํด์ผ ํจ ์ฆ ์์ฉ ์๋น์ค์ ๋ฉ์๋ ์์ค์์ ๊ถํ ๊ฒ์ฌ๋ฅผ ํ ์ ์๊ธฐ ๋๋ฌธ์ ๋ค์๊ณผ ๊ฐ์ด ์ง์ ๊ถํ ๊ฒ์ฌ ๋ก์ง์ ๊ตฌํํด์ผ ํ๋ค.
public class DeleteArticleService {
public void delete(String userId, Long articleId) {
Article article = articleRepository.findById(articleId);
checkArticleExistence(article);
permissionService.checkDeletePermission(userId, article);
article.markDeleted();
// ...
}
}
permissionService.checkDeletePermission(์ฌ์ฉ์ ID, ๊ฒ์๊ธ)
: ์ฌ์ฉ์๊ฐ ํด๋น ๊ฒ์๋ฌผ ์ญ์ ๊ถํ์ ๊ฐ์ก๋์ง ๊ฒ์ฌ
์๋น์ค์์์ ์กฐํ ๊ธฐ๋ฅ : ๋จ์ ์กฐํ ์ ์ฉ ๊ธฐ๋ฅ ํธ์ถ
public class OrderListService {
public List<OrderView> getOrderList(String ordererId) {
return orderViewDao.selectByOrderer(ordererId);
}
// ...
}
์๋น์ค์์ ์ํํ๋ ์ถ๊ฐ์ ์ธ ๋ก์ง์ด ์์๋ฟ๋๋ฌ ์กฐํ ์ ์ฉ ๊ธฐ๋ฅ์ด์ด์ ํธ๋์ญ์ ์ด ํ์ํ์ง๋ ์๋ค. ์ด๋ฐ ๊ฒฝ์ฐ๋ผ๋ฉด ๊ตณ์ด ์๋น์ค๋ฅผ ๋ง๋ค ํ์ ์์ด ํํ ์์ญ์์ ๋ฐ๋ก ์กฐํ ์ ์ฉ ๊ธฐ๋ฅ์ ์ฌ์ฉํด๋ ๋๋ค.
public class OrderController {
private OrderViewDao orderViewDao;
@RequestMapping("/myorders")
public String list(ModelMap model) {
String ordererId = SecurityContext.getAuthentication().getid();
List<OrderView> orders = orderViewDao.selectByOrderer(ordererId);
model.addAttribute("orders", orders);
return "order/list";
}
// ...
}
์์ฉ ์๋น์ค๊ฐ ์กด์ฌํด์ผ ํ๋ค๋ ๊ฐ๋ฐ๊ด๋ ์ ๊ฐ์ง๋ฉด, ์ปจํธ๋กค๋ฌ์ ๊ฐ์ ํํ ์์ญ์์ ์์ฉ ์๋น์ค ์์ด ์กฐํ ์ ์ฉ ๊ธฐ๋ฅ์ด๋ ๋๋ฉ์ธ ๋ฆฌํฌ์งํฐ๋ฆฌ์ ์ ๊ทผํ๋ ๊ฒ์ด ์ฒ์์๋ ์ด์ํ๊ฒ ๋๊ปด์ง ์ ์๋ค. ํ์ง๋ง, ์์ฉ ์๋น์ค๊ฐ ์ฌ์ฉ์ ์์ฒญ ๊ธฐ๋ฅ์ ์คํํ๋ ๋ฐ ๋ณ๋ค๋ฅธ ๊ธฐ์ฌ๋ฅผ ํ์ง ๋ชปํ๋ค๋ฉด ๊ตณ์ด ์๋น์ค๋ฅผ ๋ง๋ค์ง ์์๋ ๋๋ค๊ณ ์๊ฐํ๋ค.