http์ ์์ฒญ๊ณผ ์๋ต
ํ๋กํ ์ฝ(Protocol)
์๋ก๊ฐ์ ํต์ ์ ์ํ ์ฝ์ ๋๋ ๊ท์น. ์ฃผ๊ณ ๋ฐ์ ๋ฐ์ดํฐ์ ๋ํ ํ์์ ์ ์ํ ๊ฒ.
๋ณ๋ค๋ฅธ ์ค๋ช ์์ด๋ ๊ท์น์ ์ ํด๋๊ณ ์ฃผ๊ณ ๋ฐ์ ๋ ์ด๋ค ๊ฒ์ ์๋ฏธํ๋์ง ์์๋ค์ ์ ์๋๋ก ํจ.
HTTP(Hyper Text Transfer Protocal)
ํ ์คํธ ๊ธฐ๋ฐ์ ํ๋กํ ์ฝ. ์ํ๋ฅผ ์ ์งํ์ง ์๋๋ค.(๋ฌด์ํ. stateless) ํด๋ผ์ด์ธํธ๋ฅผ ๊ตฌ๋ถํ ์ ์๋ค.(๊ฐ์ ํด๋ผ์ด์ธํธ๊ฐ ์์ฒญ์ ๋ณด๋ด๋ ์ ๋ณด๋ฅผ ์ ์ฅํ์ง ์๊ธฐ ๋๋ฌธ์ ํด๋ผ์ด์ธํธ๋ฅผ ๊ตฌ๋ถํ ์ ์์. ์ด๋ฅผ ๋ณด์ํ๊ธฐ ์ํด ์ฟ ํค์ ์ธ์ ์ ์ฌ์ฉํ๋ค.) ํ์ฅ์ด ๊ฐ๋ฅํ๋ค. (์ปค์คํ ํค๋๋ฅผ ์ถ๊ฐํ ์ ์๋ค. ์๋ฒ์ ํด๋ผ์ด์ธํธ๊ฐ ์ฝ์๋ง ๋๋ค๋ฉด ํค๋๋ฅผ ์ถ๊ฐํ ์ ์๋ค.)
์์ฒญ
์์ฒญ ๋ฌธ์๋ ํค๋์ ๋ฐ๋๋ก ๊ตฌ์ฑ๋์ด์๋ค. ํค๋์๋ ๋ณธ๋ฌธ์ ๋ํ ์ค๋ช ์ด ์์ฑ๋์ด ์๊ณ , ๋ฐ๋์๋ ์ค์ ๋ด์ฉ์ด ์์ฑ๋์ด ์๋ค. url์ ์ ๋ ฅํ๋ฉด, ํค๋์ ๋ฐ๋๋ก ์์ฑ๋ http ์์ฒญ ๋ฌธ์๋ฅผ ์์ฑํ์ฌ ์๋ฒ์๊ฒ ๋ณด๋ธ๋ค. ์๋ฒ๋ ํด๋น http ๋ฌธ์๋ฅผ ๋ฐ์ ์ฒ๋ฆฌ ํ http ์๋ต ๋ฌธ์๋ฅผ ๋ณด๋ธ๋ค.
์๋ต
์๋ต ๋ฌธ์๋ ์ํ ๋ผ์ธ, ํค๋, ๋ฐ๋๋ก ๊ตฌ์ฑ๋์ด ์๋ค. ํค๋๋ ์ค๋ฐ๊ฟ์ผ๋ก ๊ตฌ๋ถ๋๋ฉฐ ํค๋์ ๋ฐ๋๋ ๋น ์ค๋ก ๊ตฌ๋ถ๋๋ค. (๋น ์ค์ด ๋์ค๋ฉด ํค๋๊ฐ ๋๋ฌ์์ ์๋ฏธํ๋ค.)
์ฝ๋(์ํ๋ผ์ธ)
100 information (ํด๋ผ์ด์ธํธ-์๋ฒ ๊ฐ์ ์ ๋ณด ๊ตํ)
200 success
300 redirect (๋ค๋ฅธ url๋ก ์ฌ ์์ฒญํ๋ผ)
400 client error (๊ฒฝ๋ก ๋ฑ์ ์๋ชป ์ ๋ ฅํจ. ex) 404 Not Found)
500 server error (ํด๋ผ์ด์ธํธ๋ ์์ฒญ์ ์ ๋๋ก ํ์ผ๋ ์๋ฒ์์ ์์ฒญ ์ฒ๋ฆฌ ์ค ํ๋ก๊ทธ๋จ์ ์๋ฌ๊ฐ ๋ฐ์ํจ)
http ์์ฒญ ๋ฐฉ์ - Get, Post
get
๊ฒ์ ์์ง์์ ๊ฒ์ ๋จ์ด ์ ์ก ๋ฑ์ ์ฌ์ฉ๋๋ ๋ฐฉ์. ์๋ฒ์์ ์ ๋ณด๋ฅผ ์ป์ด์ด(read only). ์๋ฒ์์ ๋ฆฌ์์ค๋ฅผ ๊ฐ์ ธ์ค๊ธฐ ์ํด ์ค๊ณํ๋ค. url์ ์ฟผ๋ฆฌ ์คํธ๋ง(Query String)์ผ๋ก ๋ด์ฉ์ ์ ์ด์ ๋ฐ์ดํฐ๋ฅผ ๋ณด๋ผ ์ ์์(์์ฉ๋). ๋ฐ๋๊ฐ ์์. url์ ๋ฐ์ดํฐ๊ฐ ๋ ธ์ถ๋๋ฏ๋ก ๋ณด์์ ์ทจ์ฝํ๋ค. ๋ฐ์ดํฐ ๊ณต์ ์ ์ ๋ฆฌํ๋ค.
post
๊ธ์ฐ๊ธฐ, ๋ก๊ทธ์ธ, ํ์๊ฐ์ , ํ์ผ ์ฒจ๋ถ ๋ฑ์ ์ฌ์ฉ๋๋ ๋ฐฉ์. ์๋ฒ์ ๋ฐ์ดํฐ๋ฅผ ์ฌ๋ฆฌ๊ธฐ ์ํด ์ค๊ณ. ๋ฐ์ดํฐ๋ฅผ ์์ฒญ ๋ฉ์์ง์ ๋ฐ๋์ ๋ด์ ์ ์กํ๊ธฐ ๋๋ฌธ์ ์ ์ก ๋ฐ์ดํฐ ํฌ๊ธฐ์ ์ ํ์ด ์์(๋์ฉ๋). ๋ณด์์ ์ ๋ฆฌํ๊ณ ๊ณต์ ์ ๋ถ๋ฆฌํ๋ค.
get ๋ฐฉ์
post ๋ฐฉ์. ๋ฐ์ดํฐ๊ฐ url ๋ค์ ๋ถ์ง ์๊ณ ๋ฐ๋์ ๋ถ๋๋ค.
MIME(Multipurpose Internet Mail Extension)
ํ ์คํธ ๊ธฐ๋ฐ ํ๋กํ ์ฝ์ ๋ฐ์ด๋๋ฆฌ ๋ฐ์ดํฐ๋ฅผ ์ ์กํ๊ธฐ ์ํด ๊ณ ์๋จ. HTTP์ ํค๋์ ์ฌ์ฉ. ๋ฐ์ดํฐ์ ํ์ ์ ๋ช ์ํ๋ค.
`text` `image` `audio` `video` `application` ๋ฑ์ด ์์.
MVC ํจํด - ๊ด์ฌ์ฌ์ ๋ถ๋ฆฌ(Separation of Concerns)
"ํด์ผํ ์์ "์ ๋ถ๋ฆฌ. SRP(Single Responsibility Priciple): ํ๋์ ํด๋์ค๋ ํ๋์ ์ฑ ์๋ง์ ๊ฐ์ ธ์ผํ๋ค. ๋ฉ์๋๋ ๋ง์ฐฌ๊ฐ์ง๋ค. ํ๋์ ๋ฉ์๋๋ ํ๋์ ์ฑ ์๋ง์ ๊ฐ์ ธ์ผ ํ๋ค. 1. ๊ด์ฌ์ฌ 2. ๋ณํ๋ ๊ฒ 3. ์ค๋ณต ์ฝ๋ ์ด ์ ์ ์ ๋ถ๋ฆฌํ์ฌ ์ฝ๋๋ฅผ ์์ฑํ๋ฉด ๊ฐ์ฒด ์งํฅ์ ์ ์งํค๋ ์ค๊ณ๋ฅผ ํ ์ ์๋ค. ๋๋ฌด ์์น๋ง์ ์๊ฐํ์ง ์๋๋ค. ์ผ๋จ ์ฝ๋๋ฅผ ์์ฑํ๊ณ ์์น์ ์๊ฐํ๋ฉฐ ์์ ํ๋ ๋ฐฉ๋ฒ์ผ๋ก ์ฝ๋๋ฅผ ๊ฐ์ ํด ๋๊ฐ๋ค.
Contoller : ์ฒ๋ฆฌ
Modal : ์ ๋ณด๋ฅผ ๋ด์ ๊ฐ์ฒด
View : ์ถ๋ ฅ
@Controller์ @RequestMapping ์ ๋ํ ์ด์ ์ ๊ฐ์ง ๋ฉ์๋๋ Model ๊ฐ์ฒด๋ฅผ ๋งค๊ฐ๋ณ์๋ก ๋ฐ์ ๊ฐ์ ์ฒ๋ฆฌํ๊ณ Model ๊ฐ์ฒด์ ์์ ๊ฒฐ๊ณผ๋ฅผ ์ ์ฅํ ๋ค(model ๊ฐ์ฒด๋ ์ด๋ฏธ dispatcher๊ฐ ๊ฐ์ง๊ณ ์์ผ๋ฏ๋ก model ๊ฐ์ฒด๋ฅผ ๋ฐํํ ํ์๊ฐ ์์. ๊ฐ๋ง ์์ ํด์ฃผ๋ฉด ๋๋ค.) ๋ณด๋ด์ค ์์ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์ฌ์ค view์ ์ด๋ฆ์ String์ผ๋ก ๋ฐํํ๋ค.
// ๋
์ ์ผ์ ์
๋ ฅํ๋ฉด ์์ผ์ ์๋ ค์ฃผ๋ ํ๋ก๊ทธ๋จ
@Controller
public class YoilTellerMVC {
@RequestMapping("/getYoilMVC")
public String getYoilMVC(int year, int month, int day, Model model) throws IOException {
if (!isValid(year, month, day)) {
return "yoilError";
}
char yoil = getYoil(year, month, day);
model.addAttribute("year", year);
model.addAttribute("month", month);
model.addAttribute("day", day);
model.addAttribute("yoil", yoil);
return "yoil";
}
private boolean isValid(int year, int month, int day) {
// TODO Auto-generated method stub
return true;
}
private char getYoil(int year, int month, int day) {
Calendar cal = Calendar.getInstance();
cal.set(year, month - 1, day);
int dayOfweek = cal.get(Calendar.DAY_OF_WEEK); // 1= ์ผ์์ผ 2=์์์ผ...
return " ์ผ์ํ์๋ชฉ๊ธํ ".charAt(dayOfweek);
}
}
// yoil.jsp
<%@ page contentType="text/html;charset=utf-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
<title>Yoil</title>
</head>
<body>
<P> ${year}๋
${month}์ ${day}์ผ์ ${yoil}์์ผ์
๋๋ค.</P>
</body>
</html>
`Class` ํด๋์ค์ `forName()` ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ฉด ํด๋น ํด๋์ค์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ฌ ์ ์๋ค.
`getDeclareMethod()` ๋ฉ์๋๋ ํด๋น ํด๋์ค์์ ์ ์๋ ๋ฉ์๋๋ฅผ `Method`ํ์ ์ ๋ฐฐ์ด๋ก ๋ฐํํ๋ค. `getParameters()`๋ ํด๋น ํด๋์ค์์ ์ ์๋ ํ๋ผ๋ฏธํฐ(๋งค๊ฐ๋ณ์)๋ฅผ `Parameter` ํ์ ์ ๋ฐฐ์ด๋ก ๋ฐํํ๋ค. ์ ์ฝ๋๋ ํด๋์ค ๋ด ์ ์๋ ๋ฉ์๋์ ๋งค๊ฐ๋ณ์๋ฅผ ์ถ๋ ฅํ ์ ์๋๋ก ์์ฑ๋์๋ค.
์๋ ์ปดํ์ผ๋ฌ๋ ๋งค๊ฐ๋ณ์์ ์ด๋ฆ์ ๋ณ๋ก ์ค์ํ๊ฒ ์๊ฐํ์ง ์๊ธฐ ๋๋ฌธ์ ์ ์ฅํ์ง ์๋๋ค. ๋งค๊ฐ๋ณ์ ์ด๋ฆ์ ์ ์ฅํ๋ ค๋ฉด ์ปดํ์ผ ์ต์ ์์ `-parameters` ๋ผ๋ ์ต์ ์ ์ค์ผํ๋ค.(JDK 1.8๋ถํฐ ๊ฐ๋ฅ) STS์์๋ windows - preferences(setting) - compiler - classfile generation ์์ store information about method parameters(usable via reflection)์ ์ฒดํฌํ๋ฉด ๋งค๊ฐ๋ณ์ ์ด๋ฆ์ ์ ์ฅํ๋๋ก ์ค์ ์ ๋ณ๊ฒฝํ ์ ์๋ค.
package com.fastcampus.ch2;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Set;
class ModelController {
public String main(HashMap map) {
// ์์
๊ฒฐ๊ณผ๋ฅผ map์ ์ ์ฅ
map.put("id", "asdf");
map.put("pwd", "1111");
// ๋ทฐ ์ด๋ฆ์ ๋ฐํ
return "txtView2";
}
}
public class MethodCall {
public static void main(String[] args) throws Exception{
HashMap<String, String> map = new HashMap<>();
System.out.println("before:"+map);
ModelController mc = new ModelController();
String viewName = mc.main(map);
System.out.println("after :"+map);
render(map, viewName);
}
static void render(HashMap<String, String> map, String viewName) throws IOException {
String result = "";
// 1. ๋ทฐ์ ๋ด์ฉ์ ํ์ค์ฉ ์ฝ์ด์ ํ๋์ ๋ฌธ์์ด๋ก ๋ง๋ ๋ค.
Scanner sc = new Scanner(new File(viewName+".txt"));
while(sc.hasNextLine())
result += sc.nextLine()+ System.lineSeparator();
// 2. map์ ๋ด๊ธด key๋ฅผ ํ๋์ฉ ์ฝ์ด์ template์ ${key}๋ฅผ value๋ฐ๊พผ๋ค.
Iterator<String> it = map.keySet().iterator();
while(it.hasNext()) {
String key = (String)it.next();
// 3. replace()๋ก key๋ฅผ value ์นํํ๋ค.
result = result.replace("${"+key+"}", (String)map.get(key));
}
// 4.๋ ๋๋ง ๊ฒฐ๊ณผ๋ฅผ ์ถ๋ ฅํ๋ค.
System.out.println(result);
}
}
์ ์ฝ๋์์ `ModelController` ํด๋์ค๋ ๋งค๊ฐ๋ณ์๋ก `map`์ ๋ฐ์์์ `map`์ ์ ๋ณด๋ฅผ ์ถ๊ฐํ๊ธฐ๋ง ํ ๋ฟ map์ ๋ฐํํ์ง๋ ์๋๋ค.(๊ทธ๋ฅ ๋ณด์ฌ์ค view ์ด๋ฆ๋ง String์ผ๋ก ๋ฐํํ๋ค.) ์๋ํ๋ฉด `MethodCall` ํด๋์ค์ ๋ฉ์ธ ๋ฉ์๋์์ `map`์ ์์ฑํ์ฌ ๋๊ฒผ๊ธฐ ๋๋ฌธ์ ๋ฉ์ธ ๋ฉ์๋์๋ ์ด๋ฏธ `map`์ด ์กด์ฌํ๋ฏ๋ก ๋๊ธธ ํ์๊ฐ ์๊ธฐ ๋๋ฌธ์ด๋ค. ์ฐธ์กฐ๋ณ์๋ฅผ ๋งค๊ฐ๋ณ์๋ก ๋๊ธฐ๋ฉด, ๊ฐ์ฒด์ ์ฃผ์๋ฅผ ๋๊ธฐ๋ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ ๊ฐ์ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ๋ค. ๋ฐ๋ผ์ `ModelController`์์ ๊ฐ์ ๋ฃ์ผ๋ฉด ๋ฉ์ธ ๋ฉ์๋์ `map`์ ๊ฐ์ด ์ถ๊ฐ๋๋ ๊ฒ์ด๋ค.
// String viewName = obj.main(2024, 1, 1, model);
// Reflection API๋ฅผ ์ด์ฉํ ํธ์ถ
String viewName = (String)main.invoke(obj, new Object[] { 2024, 1, 1, model });
// String viewName = obj.main(2024, 1, 1, model);
// Reflection API๋ฅผ ์ด์ฉํ ํธ์ถ
// String viewName = (String)main.invoke(obj, new Object[] { 2024, 1, 1, model });
// ํ๋์ฝ๋ฉX ๋์ ํธ์ถ
Method main = clazz.getDeclaredMethod("main", int.class, int.class, int.class, Model.class);
Parameter[] paramArr = main.getParameters();
Object[] argArr = new Object[main.getParameterCount()];
for(int i=0;i<paramArr.length;i++) {
String paramName = paramArr[i].getName();
Class paramType = paramArr[i].getType();
Object value = map.get(paramName); // map์์ ๋ชป์ฐพ์ผ๋ฉด value๋ null
// paramType์ค์ Model์ด ์์ผ๋ฉด, ์์ฑ & ์ ์ฅ
if(paramType==Model.class) {
argArr[i] = model = new BindingAwareModelMap();
} else if(value != null) { // map์ paramName์ด ์์ผ๋ฉด,
// value์ parameter์ ํ์
์ ๋น๊ตํด์, ๋ค๋ฅด๋ฉด ๋ณํํด์ ์ ์ฅ
argArr[i] = convertTo(value, paramType);
}
}
`Model`์ ์ธํฐํ์ด์ค๋ผ์ ๊ฐ์ฒด๋ฅผ ์์ฑํ ์ ์๋ค. model์ ์ค์ฒด ๊ตฌํ ๊ฐ์ฒด๋ `BindingAwareModelMap`์ด๋ค.
JSP์ ์๋ธ๋ฆฟ์ ๊ฑฐ์ ์ ์ฌํ๋ค. ์๋ธ๋ฆฟ์ ๋ฐ์ ์ํจ ๊ฒ์ด Spring์ด๋ค.
1. servlet์ ๋ฐ๋์ ๋ฉ์๋์ ์ด๋ฆ์ด `service()`์ด๋ค. (์ค๋ฒ๋ผ์ด๋ฉ)
2. `HttpServlet`์ ์์๋ฐ์์ผ ํ๋ค.
3. ๋งค๊ฐ๋ณ์๋ก `HttpServletRequest`์ `HttpServletResponse`๋ฅผ ์ ์ธํด์ผ ํ๋ค.
4. ํด๋์ค ๋งคํ๋ง ๊ฐ๋ฅํ๊ธฐ ๋๋ฌธ์ ํด๋์ค ์์ `@WebServlet` ์ ํฐ๋ค์ด์ ์ ์ฌ์ฉํ๋ค.
์๋ธ๋ฆฟ ์๋ช ์ฃผ๊ธฐ
Servlet Context์๋ children์ด๋ ๋งต์ด ์กด์ฌํ๋ค. ์์ฒญ์ ๋ฐ์์ ๋ childeren์ ํด๋น ์๋ธ๋ฆฟ ์ธ์คํด์ค๊ฐ ์กด์ฌํ์ง ์์ผ๋ฉด `init()` ๋ฉ์๋๋ฅผ ํธ์ถํด ์๋ธ๋ฆฟ ํด๋์ค๋ฅผ ๋ก๋ฉํ๊ณ ์ธ์คํด์ค๋ฅผ ์์ฑํ๋ค. ๊ทธ๋ฆฌ๊ณ `service()` ๋ฉ์๋ ํธ์ถํด ์ฒ๋ฆฌํ๊ณ ์๋ตํ๋ค. ์๋ธ๋ฆฟ์ด ๋์ด์ ์ฌ์ฉ๋์ง ์์ผ๋ฉด ๋ฉ๋ชจ๋ฆฌ์์ ์ ๊ฑฐ๋๋๋ฐ, ์ด๋ ์๋ธ๋ฆฟ ์ปจํ ์ด๋์ ์ํด `destroy()` ๋ฉ์๋๊ฐ ํธ์ถ๋๋ค. ๋ ๋ค๋ฅธ ์์ฒญ์ด ๋ค์ด์์ ๋ ์ด๋ฏธ ์๋ธ๋ฆฟ ์ธ์คํด์ค๊ฐ ์กด์ฌํ๋ค๋ฉด `init()`์ ํธ์ถํ์ง ์๊ณ ๋ฐ๋ก `service()`๋ฅผ ํธ์ถํ์ฌ ์์ ์ ์งํํ๋ค.
์๋ธ๋ฆฟ์ ์ฑ๊ธํค์ด๋ค. ์์ฒญ์ด ์ฌ ๋๋ง๋ค ์๋ธ๋ฆฟ ๊ฐ์ฒด๋ฅผ ๊ณ์ ๋ง๋๋ ๊ฒ์ด ์๋๋ผ ํ ๊ฐ์ ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด์ ์์ฒญ์ด ์ฌ ๋๋ง๋ค ๊ณ์ ์ฌํ์ฉํ๋ค. ์คํ๋ง๋ ๋ง์ฐฌ๊ฐ์ง!
์๋ธ๋ฆฟ์ ์ง์ฐ๋ ์ด๊ธฐํ๋ฅผ ํ๋ค.(lazy init) ์์ฒญ์ด ๋ค์ด์ค๋ฉด ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ค. -๋ฏธ๋ฆฌ ์ด๊ธฐํ ํ๋ ๋ฐฉ๋ฒ๋ ์ ๊ณตํ๊ธด ํจ.
์คํ๋ง์ ์ด๋ฅธ ์ด๊ธฐํ๋ฅผ ํ๋ค.(early init) ์์ฒญ์ด ๋ค์ด์ค์ง ์์๋ ๊ฐ์ฒด๋ฅผ ์์ฑํด๋๋ค.
URL ํจํด
`@WebServlet`์ผ๋ก url์ ๋งตํํ ๋ ์ฌ์ฉ. ์ฐ์ ์์๊ฐ ์กด์ฌํจ. ์ฐ์ ์์๊ฐ ๋์ ๊ฒ์์ ๋งค์นญ์ด ๋์ง ์์ผ๋ฉด ๋ค์ ์ฐ์ ์์๋ก ๋์ด๊ฐ๊ณ ๋ชจ๋ ๋งค์นญ๋์ง ์๋ ๊ฒฝ์ฐ ๋ํดํธ ๋งคํํจ. Servlet Context์๋ servletMapping์ด๋ผ๋ ๋งต์ด ์กด์ฌํ๋ค. ์์ฒญ์ ๋ฐ์ผ๋ฉด ๋งคํ์ด ์กด์ฌํ๋์ง ํ์ธํ๋ค.
* spring์์๋ seveltMapping์ ์ฌ์ฉํ์ง ์๊ณ ๋ฐ๋ก `DispatcherServlet`์ด ๋ฐ์์ ๋ด๋ถ์์ ๋งคํ์ ์ฒ๋ฆฌํ๋ค(RequestMapping)
EL(Expression Laguage)
<% ... &> ๋์ ์ ${...} ํํ๋ก ์ฌ์ฉํ ์ ์๊ฒ ๋จ
'Java > Spring' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[SpringBoot] Querydsl ์ค์ ์ ์ค๋ฅ (0) | 2024.03.11 |
---|---|
[Spring] summernote ์๋ํฐ๋ก ์ด๋ฏธ์ง๊ฐ ํฌํจ๋ ๊ธ ์ ๋ก๋ํ๊ธฐ (0) | 2024.02.22 |
[Spring] ์คํ๋ง์ ์ ์ (2) - ์์ฒญ๊ณผ ์๋ต (0) | 2023.12.31 |
[Spring] ์คํ๋ง์ ์ ์ (1) ์ด๊ธฐ ์ค์ (0) | 2023.12.30 |
[Spring] ์คํ๋ง ํต์ฌ ์๋ฆฌ ๊ธฐ๋ณธํธ (3) (0) | 2023.12.28 |