1) ์ํ์ ๋ณด๋?
์น์์์ ์ํ ์ ์ง ๊ธฐ์
-
HTTPํ๋กํ ์ฝ์ ์ํ ์ ์ง๊ฐ ์๋๋ ํ๋กํ ์ฝ์ ๋๋ค.
- ์ด์ ์ ๋ฌด์์ ํ๊ณ , ์ง๊ธ ๋ฌด์์ ํ๋์ง์ ๋ํ ์ ๋ณด๋ฅผ ๊ฐ๊ณ ์์ง ์์ต๋๋ค.
- ์น ๋ธ๋ผ์ฐ์ (ํด๋ผ์ด์ธํธ)์ ์์ฒญ์ ๋ํ ์๋ต์ ํ๊ณ ๋๋ฉด ํด๋น ํด๋ผ์ด์ธํธ์์ ์ฐ๊ฒฐ์ ์ง์ํ์ง ์์ต๋๋ค. -
์ํ ์ ์ง๋ฅผ ์ํด Cookie์ Session๊ธฐ์ ์ด ๋ฑ์ฅํฉ๋๋ค.
์ฟ ํค(Cookie)์ ์ธ์ (Session)
-
์ฟ ํค
- ์ฌ์ฉ์ ์ปดํจํฐ์ ์ ์ฅ
- ์ ์ฅ๋ ์ ๋ณด๋ฅผ ๋ค๋ฅธ ์ฌ๋ ๋๋ ์์คํ ์ด ๋ณผ ์ ์๋ ๋จ์
- ์ ํจ์๊ฐ์ด ์ง๋๋ฉด ์ฌ๋ผ์ง -
์ธ์
- ์๋ฒ์ ์ ์ฅ
- ์๋ฒ๊ฐ ์ข ๋ฃ๋๊ฑฐ๋ ์ ํจ์๊ฐ์ด ์ง๋๋ฉด ์ฌ๋ผ์ง๋๋ค.
์ฟ ํค(Cookie) ๋์ ์ดํด
์ธ์ ์ ๋์ ์ดํด
HttpSession์ด๋ผ๋ ๊ฐ์ฒด: ์ธ์ ์ ์ ๋ณด๋ฅผ ๋ด๊ธฐ ์ํด ์์ฑ๋๋ ๊ฐ์ฒด
2) ์ฟ ํค๋?
์ฟ ํค ์ ์
-
ํด๋ผ์ด์ธํธ ๋จ์ ์ ์ฅ๋๋ ์์ ์ ๋ณด์ ๋จ์์ ๋๋ค. (์ฟ ํคํ๋: key-value ํ๋์ฉ)
-
ํด๋ผ์ด์ธํธ์์ ์์ฑํ๊ณ ์ ์ฅ๋ ์ ์๊ณ , ์๋ฒ ๋จ์์ ์ ์กํ ์ฟ ํค๊ฐ ํด๋ผ์ด์ธํธ์ ์ ์ฅ๋ ์ ์์ต๋๋ค.
์ด์ฉ ๋ฐฉ๋ฒ
javax.servlet.http.Cookie
์๋ฒ์์ ์ฟ ํค ์์ฑ, Reponse์ addCookie๋ฉ์๋๋ฅผ ์ด์ฉํด ํด๋ผ์ด์ธํธ์๊ฒ ์ ์ก
Cookie cookie = new Cookie(์ด๋ฆ, ๊ฐ);
response.addCookie(cookie);
-
์๋ฒ์์ ํด๋ผ์ด์ธํธ์ ๋ธ๋ผ์ฐ์ ๋ก ์ ์ก๋์ด ์ฌ์ฉ์์ ์ปดํจํฐ์ ์ ์ฅํฉ๋๋ค.
-
์ ์ฅ๋ ์ฟ ํค๋ ๋ค์ ํด๋นํ๋ ์น ํ์ด์ง์ ์ ์ํ ๋, ๋ธ๋ผ์ฐ์ ์์ ์๋ฒ๋ก ์ฟ ํค๋ฅผ ์ ์กํฉ๋๋ค.
-
์ฟ ํค๋ ์ด๋ฆ(name)๊ณผ ๊ฐ(value) ์์ผ๋ก ์ ๋ณด๋ฅผ ์ ์ฅํฉ๋๋ค.
- ์ด๋ฆ-๊ฐ ์ ์ธ์๋ ๋๋ฉ์ธ(Domain), ๊ฒฝ๋ก(Path), ์ ํจ๊ธฐ๊ฐ(Max-Age, Expires), ๋ณด์(Secure), HttpOnly ์์ฑ์ ์ ์ฅํ ์ ์์ต๋๋ค. -
์ฟ ํค๋ ๊ทธ ์์ ํฌ๊ธฐ์ ์ ํ
-
๋ธ๋ผ์ฐ์ ๋ณ๋ก ์ ํ ๊ฐ์ ๋ค๋ฅด๊ฒ ๊ฐ์ ธ๊ฐ๊ณ ์์ต๋๋ค.
-
์ฟ ํค๋ (์ด๋ฆ, ๊ฐ)์ ์ ์ ๋ณด๋ฅผ ์ ๋ ฅํ์ฌ ์์ฑํฉ๋๋ค.
-
์ฟ ํค์ ์ด๋ฆ์ ์ผ๋ฐ์ ์ผ๋ก ์ํ๋ฒณ๊ณผ ์ซ์, ์ธ๋๋ฐ๋ก ๊ตฌ์ฑํฉ๋๋ค. ์ ํํ ์ ์๋ฅผ ์๊ณ ์ถ๋ค๋ฉด RFC 6265(https://tools.ietf.org/html/rfc6265)) ๋ฌธ์ [4.1.1 Syntax] ํญ๋ชฉ์ ์ฐธ์กฐํ์ธ์.
ํด๋ผ์ด์ธํธ๊ฐ ๋ณด๋ธ ์ฟ ํค ์ ๋ณด ์ฝ๊ธฐ
Cookie[] cookies = request.getCookies();
-
์ฟ ํค ๊ฐ์ด ์์ผ๋ฉด null์ด ๋ฐํ๋ฉ๋๋ค.
-
Cookie๊ฐ ๊ฐ์ง๊ณ ์๋ getName()๊ณผ getValue()๋ฉ์๋๋ฅผ ์ด์ฉํด์ ์ํ๋ ์ฟ ํค์ ๋ณด๋ฅผ ์ฐพ์ ์ฌ์ฉํฉ๋๋ค.
ํด๋ผ์ด์ธํธ์๊ฒ ์ฟ ํค ์ญ์ ์์ฒญ
- ์ฟ ํค๋ฅผ ์ญ์ ํ๋ ๋ช ๋ น์ ์๊ณ , maxAge๊ฐ 0์ธ ๊ฐ์ ์ด๋ฆ์ ์ฟ ํค๋ฅผ ์ ์กํฉ๋๋ค.
Cookie cookie = new Cookie("์ด๋ฆ", null);
cookie.setMaxAge(0); ๋ป: ์ ์ง์๊ฐ 0
response.addCookie(cookie);
์ฟ ํค์ ์ ํจ๊ธฐ๊ฐ ์ค์
-
๋ฉ์๋ setMaxAge()
- ์ธ์๋ ์ ํจ๊ธฐ๊ฐ์ ๋ํ๋ด๋ ์ด ๋จ์์ ์ ์ํ
- ๋ง์ผ ์ ํจ๊ธฐ๊ฐ์ 0์ผ๋ก ์ง์ ํ๋ฉด ์ฟ ํค์ ์ญ์
- ์์๋ฅผ ์ง์ ํ๋ฉด ๋ธ๋ผ์ฐ์ ๊ฐ ์ข ๋ฃ๋ ๋ ์ฟ ํค๊ฐ ์ญ์ -
์ ํจ๊ธฐ๊ฐ์ 10๋ถ์ผ๋ก ์ง์ ํ๋ ค๋ฉด
- cookie.setMaxAge(10 * 60); //์ด ๋จ์ : 10๋ถ
- 1์ฃผ์ผ๋ก ์ง์ ํ๋ ค๋ฉด (7*24*60*60)๋ก ์ค์ ํฉ๋๋ค.
Spring MVC์์์ Cookie ์ฌ์ฉ
-
@CookieValue ์ ๋ ธํ ์ด์ ์ฌ์ฉ
- ์ปจํธ๋กค๋ฌ ๋ฉ์๋์ ํ๋ผ๋ฏธํฐ์์ CookieValue์ ๋ ธํ ์ด์ ์ ์ฌ์ฉํจ์ผ๋ก์จ ์ํ๋ ์ฟ ํค์ ๋ณด๋ฅผ ํ๋ผ๋ฏธํฐ ๋ณ์์ ๋ด์ ์ฌ์ฉํ ์ ์ต๋๋ค. -
์ปจํธ๋กค๋ฌ๋ฉ์๋(@CookieValue(value="์ฟ ํค์ด๋ฆ", required=false, defaultValue="๊ธฐ๋ณธ๊ฐ") String ๋ณ์๋ช )
3) ์ฟ ํค๋ฅผ ์ด์ฉํ ์ํ์ ๋ณด ์ ์งํ๊ธฐ
package kr.or.connect.guestbook.controller;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import kr.or.connect.guestbook.dto.Guestbook;
import kr.or.connect.guestbook.service.GuestbookService;
@Controller
public class GuestbookController {
@Autowired
GuestbookService guestbookService;
@GetMapping(path="/list")
public String list(@RequestParam(name="start", required=false, defaultValue="0") int start, ModelMap model, HttpServletRequest request, HttpServletResponse response) {
String value = null;
boolean find = false; // ๋ด๊ฐ ์ํ๋ ์ฟ ํค๋ฅผ ๊ฐ์ง๊ณ ์์ด?
Cookie\[\] cookies = request.getCookies();
if(cookies != null) {
for(Cookie cookie : cookies) {
if("count".equals(cookie.getName())) {
find = true;
value = cookie.getValue();
break;
}
}
}
if(!find) {
value = "1";
}else { // ์ฟ ํค๋ฅผ ์ฐพ์๋ค๋ฉด.
try {
int i = Integer.parseInt(value);
value = Integer.toString(++i);
}catch(Exception ex) {
value = "1";
}
}
// ์ฟ ํค ์์ฑ
Cookie cookie = new Cookie("count", value);
cookie.setMaxAge(60 \* 60 \* 24 \* 365); // 1๋
๋์ ์ ์ง.
cookie.setPath("/"); // / ๊ฒฝ๋ก ์ดํ์ ๋ชจ๋ ์ฟ ํค ์ ์ฉ.
response.addCookie(cookie); // ๋ณ๊ฒฝ๋ ์ฟ ํค๋ฅผ ํด๋ผ์ด์ธํธ์ ๋ณด๋ด์ค์ผ์ง. ๊ทธ๋์ผ ์ฟ ํค ๊ต์ฒด.
List<Guestbook> list = guestbookService.getGuestbooks(start);
int count = guestbookService.getCount();
int pageCount = count / GuestbookService.LIMIT;
if(count % GuestbookService.LIMIT > 0)
pageCount++;
List pageStartList = new ArrayList<>();
for(int i = 0; i < pageCount; i++) {
pageStartList.add(i \* GuestbookService.LIMIT);
}
model.addAttribute("list", list);
model.addAttribute("count", count);
model.addAttribute("pageStartList", pageStartList);
model.addAttribute("cookieCount", value); // jsp์๊ฒ ์ ๋ฌํ๊ธฐ ์ํด์ ์ฟ ํค ๊ฐ์ model์ ๋ด์ ์ ์กํ๋ค.
return "list";
}
@PostMapping(path="/write")
public String write(@ModelAttribute Guestbook guestbook, HttpServletRequest request) {
String clientIp = request.getRemoteAddr();
System.out.println("clientIp : " + clientIp);
guestbookService.addGuestbook(guestbook, clientIp);
return "redirect:list";
}
}
4) Session์ด๋?
์ธ์ ์ ์
- ํด๋ผ์ด์ธํธ ๋ณ๋ก ์๋ฒ์ ์ ์ฅ๋๋ ์ ๋ณด์ ๋๋ค.
์ด์ฉ ๋ฐฉ๋ฒ
-
์น ํด๋ผ์ด์ธํธ๊ฐ ์๋ฒ์ธก์ ์์ฒญ์ ๋ณด๋ด๊ฒ ๋๋ฉด ์๋ฒ๋ ํด๋ผ์ด์ธํธ๋ฅผ ์๋ณํ๋ session id๋ฅผ ์์ฑํฉ๋๋ค.
-
์๋ฒ๋ session id๋ฅผ ์ด์ฉํด์ key์ value๋ฅผ ์ด์ฉํ ์ ์ฅ์์ธ HttpSession์ ์์ฑํฉ๋๋ค.
-
์๋ฒ๋ session id๋ฅผ ์ ์ฅํ๊ณ ์๋ ์ฟ ํค๋ฅผ ์์ฑํ์ฌ ํด๋ผ์ด์ธํธ์ ์ ์กํฉ๋๋ค.
-
ํด๋ผ์ด์ธํธ๋ ์๋ฒ์ธก์ ์์ฒญ์ ๋ณด๋ผ๋ session id๋ฅผ ๊ฐ์ง๊ณ ์๋ ์ฟ ํค๋ฅผ ์ ์กํฉ๋๋ค.
-
์๋ฒ๋ ์ฟ ํค์ ์๋ session id๋ฅผ ์ด์ฉํด์ ๊ทธ ์ ์์ฒญ์์ ์์ฑํ HttpSession์ ์ฐพ๊ณ ์ฌ์ฉํฉ๋๋ค.
์ธ์ ์์ฑ ๋ฐ ์ป๊ธฐ
HttpSession session = request.getSession();
HttpSession session = request.getSession(true);
// ๋ชจ๋ ๋์ ๊ฐ์
-
request์ getSession()๋ฉ์๋๋ ์๋ฒ์ ์์ฑ๋ ์ธ์ ์ด ์๋ค๋ฉด ์ธ์ ์ ๋ฐํํ๊ณ ์๋ค๋ฉด ์๋กญ๊ฒ ์ธ์ ์ ์์ฑํ์ฌ ๋ฐํํฉ๋๋ค.
-
์๋กญ๊ฒ ์์ฑ๋ ์ธ์ ์ธ์ง๋ HttpSession์ด ๊ฐ์ง๊ณ ์๋ isNew()๋ฉ์๋๋ฅผ ํตํด ์ ์ ์์ต๋๋ค.
HttpSession session = request.getSession(false);
- request์ getSession()๋ฉ์๋์ ํ๋ผ๋ฏธํฐ๋ก false๋ฅผ ์ ๋ฌํ๋ฉด, ์ด๋ฏธ ์์ฑ๋ ์ธ์ ์ด ์๋ค๋ฉด ๋ฐํํ๊ณ ์์ผ๋ฉด null์ ๋ฐํํฉ๋๋ค.
์ธ์ ์ ๊ฐ ์ ์ฅ
setAttribute(String name, Object value)
session.setAttribute(์ด๋ฆ, ๊ฐ)
-
name๊ณผ value์ ์์ผ๋ก ๊ฐ์ฒด Object๋ฅผ ์ ์ฅํ๋ ๋ฉ์๋์ ๋๋ค.
-
์ธ์ ์ด ์ ์ง๋๋ ๋์ ์ ์ฅํ ์๋ฃ๋ฅผ ์ ์ฅํฉ๋๋ค.
์ธ์ ์ ๊ฐ ์กฐํ
getAttribute(String name) ๋ฉ์๋
String value = (String) session.getAttribute("id");
-
์ธ์ ์ ์ ์ฅ๋ ์๋ฃ๋ ๋ค์ getAttribute(String name) ๋ฉ์๋๋ฅผ ์ด์ฉํด ์กฐํํฉ๋๋ค.
-
๋ฐํ ๊ฐ์ Object ์ ํ์ด๋ฏ๋ก ์ ์ฅ๋ ๊ฐ์ฒด๋ก ์๋ฃ์ ํ ๋ณํ์ด ํ์ํฉ๋๋ค.
-
๋ฉ์๋ setAttribute()์ ์ด์ฉํ name์ธ “id”๋ฅผ ์๊ณ ์๋ค๋ฉด ๋ฐ๋ก ๋ค์๊ณผ ๊ฐ์ด ๋ฐ๋ก ์กฐํํฉ๋๋ค.
์ธ์ ์ ๊ฐ ์ญ์
removeAttribute(String name) ๋ฉ์๋
-
name๊ฐ์ ํด๋นํ๋ ์ธ์ ์ ๋ณด๋ฅผ ์ญ์ ํฉ๋๋ค.
-
invalidate() ๋ฉ์๋: ๋ชจ๋ ์ธ์ ์ ๋ณด๋ฅผ ์ญ์ ํฉ๋๋ค.
์ธ์ ์ ํด๋ผ์ด์ธํธ๊ฐ ์๋ฒ์ ์ ์ํ๋ ์๊ฐ ์์ฑ
-
ํน๋ณํ ์ง์ ํ์ง ์์ผ๋ฉด ์ธ์ ์ ์ ์ง ์๊ฐ์ ๊ธฐ๋ณธ ๊ฐ์ผ๋ก 30๋ถ ์ค์ ํฉ๋๋ค.
-
์ธ์ ์ ์ ์ง ์๊ฐ์ด๋ ์๋ฒ์ ์ ์ํ ํ ์๋ฒ์ ์์ฒญ์ ํ์ง ์๋ ์ต๋ ์๊ฐ์ ๋๋ค.
-
30๋ถ ์ด์ ์๋ฒ์ ์ ํ ๋ฐ์์ ๋ณด์ด์ง ์์ผ๋ฉด ์ธ์ ์ด ์๋์ผ๋ก ๋์ด์ง๋๋ค.
-
์ด ์ธ์ ์ ์ง ์๊ฐ์ web.xmlํ์ผ์์ ์ค์ ๊ฐ๋ฅํฉ๋๋ค.
<session-config>
<session-timeout>30</session-timeout>
</session-config>
5) Session์ ์ด์ฉํ ์ํ์ ๋ณด ์ ์งํ๊ธฐ
์ค์ต์ฝ๋
-
/guess๋ก ์์ฒญ์ ํ๋ฉด ์ปดํจํฐ๊ฐ 1๋ถํฐ 100 ์ฌ์ด์ ์์์ ๊ฐ ์ค์ ํ๋๋ฅผ ๋ง์ถฐ๋ณด๋ผ๋ ๋ฉ์์ง๊ฐ ์ถ๋ ฅํฉ๋๋ค.
-
ํด๋น ๊ฐ์ ์ธ์ ์ ์ ์ฅํฉ๋๋ค.
-
์ฌ์ฉ์๋ 1๋ถํฐ 100 ์ฌ์ด์ ๊ฐ์ ์ ๋ ฅํฉ๋๋ค.
-
์ ๋ ฅํ ๊ฐ์ด ์ธ์ ๊ฐ๋ณด๋ค ์์ผ๋ฉด, ์ ๋ ฅํ ๊ฐ์ด ์๋ค๊ณ ์ถ๋ ฅํฉ๋๋ค.
-
์ ๋ ฅํ ๊ฐ์ด ์ธ์ ๊ฐ๋ณด๋ค ํฌ๋ฉด, ์ ๋ ฅํ ๊ฐ์ด ํฌ๋ค๊ณ ์ถ๋ ฅํฉ๋๋ค.
-
์ ๋ ฅํ ๊ฐ์ด ์ธ์ ๊ฐ๊ณผ ๊ฐ๋ค๋ฉด ๋ช ๋ฒ์งธ์ ๋ง์ท๋ค๊ณ ์ถ๋ ฅํฉ๋๋ค.
GuessNumberController.java
package kr.or.connect.guestbook.controller;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class GuessNumberController {
@GetMapping("/guess")
public String guess(@RequestParam(name="number", required=false) Integer number,
HttpSession session,
ModelMap model) {
String message = null;
// get๋ฐฉ์์ผ๋ก /guess ๋ฅผ ์์ฒญํ๋๋ฐ ํ๋ผ๋ฏธํฐ number๊ฐ ์์ ๊ฒฝ์ฐ์๋ session์ count๋ฅผ 0์ผ๋ก randomNumber์ 1๋ถํฐ 100์ฌ์ด์ ๊ฐ์ ์ ์ฅํฉ๋๋ค.
if(number == null) {
session.setAttribute("count", 0);
session.setAttribute("randomNumber", (int)(Math.random() * 100) + 1); // 1 ~ 100์ฌ์ด์ random๊ฐ
message = "๋ด๊ฐ ์๊ฐํ ์ซ์๋ฅผ ๋ง์ถฐ๋ณด์ธ์.";
}else {
// numberํ๋ผ๋ฏธํฐ๊ฐ ์์ ๊ฒฝ์ฐ ์ธ์
์์ ๊ฐ์ ์ฝ์ด๋ค์ธ ํ, number์ ์ธ์
์ ์ ์ฅ๋ ๊ฐ์ ๋น๊ตํฉ๋๋ค.
// ๊ฐ์ ๋น๊ตํด์ ์๊ฑฐ๋ ํฌ๋ค๋ฉด ์นด์ดํธ๋ฅผ 1์ฆ๊ฐ์์ผ์ฃผ๊ณ
// ๊ฐ์ด ๊ฐ๋ค๋ฉด ์ธ์
์ ๋ณด๋ฅผ ์ญ์ ํฉ๋๋ค.
// ๊ฐ ์ํฉ์ ๋ง๋ ๋ฉ์์ง๋ฅผ message๋ณ์์ ์ ์ฅ์ ํ ํ jsp์๊ฒ ์ ๋ฌํ๊ธฐ ์ํด์ ModelMap์ addAttribute๋ฉ์๋๋ฅผ ํตํด ์ ๋ฌํ๊ฒ ๋ฉ๋๋ค.
int count = (Integer)session.getAttribute("count");
int randomNumber = (Integer)session.getAttribute("randomNumber");
if(number < randomNumber) {
message = "์
๋ ฅํ ๊ฐ์ ๋ด๊ฐ ์๊ฐํ๊ณ ์๋ ์ซ์๋ณด๋ค ์์ต๋๋ค.";
session.setAttribute("count", ++count);
}else if(number > randomNumber) {
message = "์
๋ ฅํ ๊ฐ์ ๋ด๊ฐ ์๊ฐํ๊ณ ์๋ ์ซ์๋ณด๋ค ํฝ๋๋ค.";
session.setAttribute("count", ++count);
}else {
message = "OK " + ++count + " ๋ฒ์งธ ๋ง์ท์ต๋๋ค. ๋ด๊ฐ ์๊ฐํ ์ซ์๋ " + number + " ์
๋๋ค.";
session.removeAttribute("count");
session.removeAttribute("randomNumber");
}
}
model.addAttribute("message", message);
return "guess";
}
}
guess.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!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>์ซ์ ๋ง์ถ๊ธฐ ๊ฒ์</title>
</head>
<body>
<h1> ์ซ์ ๋ง์ถ๊ธฐ ๊ฒ์.</h1>
<hr>
<h3>${message }</h3>
<c:if test="${sessionScope.count != null}">
<form method="get" action="guess">
1๋ถํฐ 100์ฌ์ด์ ์ซ์๋ก ๋ง์ถฐ์ฃผ์ธ์.<br>
<input type="text" name="number"><br>
<input type="submit" value="ํ์ธ">
</form>
</c:if>
<a href="guess">๊ฒ์ ๋ค์ ์์ํ๊ธฐ.</a>
</body>
</html>
'Spring > Boost Course Web' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
4.5 Swagger (0) | 2020.11.19 |
---|---|
4.4 Controller (0) | 2020.11.19 |
4.3 WEB API (0) | 2020.11.19 |
4.2 Layered Architecture (0) | 2020.11.19 |
4.1 Spring MVC (0) | 2020.11.19 |
3.3 Spring JDBC (0) | 2020.11.19 |