※ Keep in mind
본 내용은 웹개발과정의 강의 중 내용을 복습을 위해서 메모한 것에 불과한 것입니다. 이러한 연유로 강의내용을 오인한 나머지 오기재 및 불기재가 있을 수 있으니 '참고'만 해주시길 바랍니다. 저의 경우에도 본 내용을 단순하 읽은 것이 결코 저의 것이라고 생각하지 않습니다. 본 내용은 복습를 위한 초기 내지 중간 과정에 불과한 것이고, 이후에 내용을 보충 후 인출 및 설명하기 과정이 있어야 비로소 복습의 단추가 어느정도 마무리 되어간다고 볼 수 있습니다.
따라서 당초에 본 내용은 비공개였습니다. 그럼에도 불구하고 본 내용을 공개한 점은 함께 공부하는 동료들과 나눔을 바탕으로 배움과 성장의 공진화라는 소기의 목적을 달성에 어느정도 도움이 될수 있기 때문이라고 생각합니다.
I. RESTfulAPI
1. API
(1) 들어가며
1)
postman 는 JS없이도 test할 수 있게 해주는거야!
요청을 할때는 URL을 써야해 localhost쓰면 데스크탑버전 따로 설치해야해
2)
이전에는 HTML의 메소드를 이용했어! 그런데 GPPD요청은 HTTP 메소드야
이제부터 GPPD 요청은 HTML페이지가 아니라 JS가 요청하는 API야
HTML 에서 요청하는 방법 없어, 왜냐 get post put delete(GPPD) 는 HTML에 없어 오로지 JS로만 요청이 가능해
JS요청하려면 미리 JS로 작성해야해
다만 그 이전에 backend가 완성돼야 client가 의미있어
3)
@GetMapping("{id}")
public String get(
@PathVariable("id") int id){
Menu menu = service.getById(id);
return "menu " + id;
};
먼저 @PathVariable(id) 은 url의 {id}에서 받아온다.
이후 받아온 값을 int id 에 대입한다
(2) JSON, XML로 전달하기
1)
restful 에서 menu 등의 객체는 원래 전달하지못해
이를 전달하기 위해서는 문자열로 바꾸거나 JSON, XML등의 표현식을 써야해 이 경우 변환이 번거로운데, 부트는 수월해
2)
그냥 반환타입을 menu 로 하면 나머지는 boot가 해줘
public List<Menu> getList() {
List <Menu> list = service.getList();
// return "menu List";
return list ;
};
@GetMapping("/menus/{id}")
public Menu get(
@PathVariable("id") int id){
Menu menu = service.getById(id);
// return "menu " + id;
return menu;
//객체를 못전달해 이를 다 표현하기 위해 문자열로 바꾸거나,바꾸는 표현식을 써야해!
//요새 트렌드는 JSON과 XML을 써야
};
JSON형식으로 반환이 되었어
3)
다시말하지만 고객은 HTML이 아니야 JS만 얘들(HTTP메소드) 부를 수있어!
page에서 스크립트 블럭이 얘들 호출 할수있게해야해
4)
중복된거 줄이자
@RestController("apiMenuController")
@RequestMapping("menus")
public class MenuController {
@Autowired
private MenuService service;
//rest 가 아니면 문서에 대한 url이 돼
//사용자에게 갈 데이터 구조야!
//사용자는 restConroller 에 요청하면 사용자가 받는건 데이터
//나중에 메소드가 아니라 공통분모에 몰아주자!
@GetMapping
public List<Menu> getList() {
List <Menu> list = service.getList();
// return "menu List";
return list ;
};
@GetMapping("{id}")
public Menu get(
@PathVariable("id") int id){
Menu menu = service.getById(id);
// return "menu " + id;
return menu;
//객체를 못전달해 이를 다 표현하기 위해 문자열로 바꾸거나,바꾸는 표현식을 써야해!
//요새 트렌드는 JSON과 XML을 써야
};
@PutMapping("{id}")
public String edit(
@PathVariable("id") int id){
return "menu edit:" + id ;
};
@DeleteMapping("{id}")
public String delete(
@PathVariable("id") int id){
return "menu del:" + id ;
};
@PostMapping
public String insert() {
return "menu insert";
};
}
menus만 있으면 지워도 돼!
@PutMapping
public String edit(
@PathVariable("id") int id){
return "menu edit:" + id ;
};
사실 edit 은 통채로 해주기 때문에
("{id}") 를 지워줘도 돼!
왜냐하면 put 은 리소스 전부를 수정하는거이기 때문에 별도로 특정할필요가없어
만약 리소스 일부를 특정해서 수정하고자 하면 PATCH를 쓰자
5)
쿼리스트링을 하는 방법을 보자
@GetMapping
public List<MenuView> getList(
@RequestParam(name = "p", defaultValue = "1") int page,
@RequestParam(name = "c", required = false) Integer categoryId,
@RequestParam(name = "q", required = false) String query ) {
// List <Menu> list = service.getList();
List <MenuView> list = service.getViewList(page, categoryId, query);
// return "menu List";
return list ;
};
쿼리스트링을 위한 틀을 만든다
세개의 인자에 대해서 각자 파라미터 별칭을 지어준다.
(3) JS 로 전달해주기
1)
list2 detail2 를 만들어서 Controller에서 return 을 바꿔주자
<예>
return "menu/list2";
}
@RequestMapping("detail") //주소와 같게 해주면
public String detail(
long id, Model model) {
Menu menu = service.getById(id);
String categoryName = categoryservice.getNameById(menu.getCategoryId());
List<RcmdMenuView> rcmdMenuServices = rcmdMenuService.getViewListMenuId((int) id);
model.addAttribute("categoryName", categoryName);
model.addAttribute("menu", menu);
model.addAttribute("rcmdMenuServices",rcmdMenuServices);
return "menu/detail2";
}
list2 에다가 스크립트를 추가하자! 스크립트 파일은 타임리프fragment 때문에 <main 태그 안 에서하자>
<main layout:fragment="main">
<script src="/js/menu/list.js" defer="defer" ></script>
<section>
defer 옵션이 뭘까? 이 옵션이 없으면 태그 읽기전 실행되버려서 비효율적이야
다운로드는 다했는데 실행하려고하는데 태그가 로드가 안되어있어
윈도우 이벤트 온로드될 때 까지 기다리는거야! 차라리 스크립트 코드 가장아래에 두는게 나을수도있어
위에도 두었지만 defer 옵션을 주면아래에 둔 것 같은 효과를 줘!
스크립트를 아래에 두면 준비물을 안둔것 같은 느낌주고 한곳에 놓지를 못해
현재 JS가있는데, 파일이 현재 어디에 있을까? static에 있어야해
2)
우리는 이전방식은 링크를 누르고, 서버에 다시 page요청하는 등으로 하는데
문서에 조금달라졌다고, 전체를 다시주는건 문제가 있어 그래서 AJAX활용하는 형식을 이용하자
AJAX 는 비동기적으로 JS이용해서 XML을 요청하다
XML은 데이터의 상징적인 요청이야 서버에 데이터만 요청하는거야
처음에 페이지를 요청해 이후에는 data만 요청해서 data만 달라고 해
처음에는 메뉴목록을 받아서 페이지 요청을 해 카테고리 다른것을 눌러도 페이지가 아니라 카테고리 데이터만 요청해서 가져올거야!
그래서 준비하는 Controller가 있어 이후가 RESTController야
3)
카테고리 클릭할 때 데이터를 요청하게 하자!
url 은 아무런변화가 없을거야! 이 버튼을 누르면 실행하게 하자
4)
클릭하기 위한 기본구조를 만들자
window.addEventListener("load",function(){
let ul = document.querySelector(".menu-category>ul");
ul.onclick = function(e){
// addeventList 이거는 누적할 때 쓰는거야!
// 람다 쓰는게 아냐 왜냐하면 지역화를 못해
//일부로 지역변수 쓰고싶지않을 때쓴다
let tagName = e.target.tagname;
if(tagName != 'LI') //li 가 아니면 return;
return;
};
})
HTML 태그 등이 다 로드 됐을 때를 의미한다.
우선 클릭을 테스트 해야해 let ul은 ul태그를 지정하는것인데,
ul태그가 클릭이벤트에실행하는 함수이다
그 함수의 실행은 이벤트가 있을 때 인데 눌러져있어
tagName으로 태그이름을 가져올 수있어' 이 경우 조건에서 대문자인 이유가 대문자로 반환하기 때문이야
만약 LI태그가 아니면 return 으로 return 아래의 것들이 실행되지 않을것이다.
window.addEventListener("load",function(){
let ul = document.querySelector(".menu-category>ul");
ul.onclick = function(e){
e.preventDefault();
// addeventList 이거는 누적할 때 쓰는거야!
// 람다 쓰는게 아냐 왜냐하면 지역화를 못해
//일부로 지역변수 쓰고싶지않을 때쓴다
let tagName = e.target.tagName;
console.log(tagName);
// if(!(tagName == 'LI' || tagName == 'A'))
if(tagName != 'LI' && tagName != 'A') //li 가 아니면 return;
return; //두가지 조건 만족시 본 함수에서 나가게해서 못쓰게 해
console.log("clicked"); //return 안되면 본 내용 이해하게끔
};
})
조건문에서 LI 태그부분과 A태그 부분 둘 중 하나라도 안눌리면 return 이 되어서 log에 clicked 이 발생하지 않게된다
즉 박스와 박스내 텍스트 중 하나만 누르면 클릭이벤트가 발생하는것이다.
(4) API 데이터 요청
1) 비동기적 데이터 요청에 두가지 방식
XHR, FetchAPI 두가지 방식이있어
비동기 처리시 XHR은 콜백함수 방식이고, fetch는 promise 방식이야
방식에 따라서 둘중 하나를 선택하는거야! 보기에는 XHR이 양이 더 많아보여
2)
web에서는 외부에다가 데이터 요청하는게 없어
script는 특성상 문서 내에 포함된 프로그래밍 요소야 의도치 않게 링크 클릭해서 다른 문서요청하게 되고
악의적 코드가 있어서 내 시스템이 꼬이거나 다른 곳에다가 내 정보를 보내거나를 허용하지 않게 해야해
그래서 script 언어가 개발자가 다루는게 아니었어
언어가 매력적이려면 언어의 기능을 떠나서 생각한것을 발현하거나 출력해주지 않으면
생각의 결과물을 적용하기가 어렵다
- (activeX 의 과거 명 : com(common) component ) active X는 어떤 언어도 형식만 맞추면 쓸 수있어
JS에다가 해보니까 되었어! 외부 데이터를 가져오거나 보내거나 가능해! JS는 못했는데 이거 덕분에 가능했어
- 구글에서는 이거는 윈도우에만 쓸수있는건데(비쥬얼베이직에 페치된거 전제) 이거를 써버렸어
두가지 문제가있어 윈도우즈 기능을 사용했기 때문에 아닌곳에서는 쓸수 없어 그래서 다른 곳에서 같은 기능을 브라우저에 심었어
3) 동기적 방식
우선 동기형 방식이야 이제는 윈도우가 아니라 브라우저 내재 기능을 쓰면돼
(var request = new ActiveXObject(...) 윈도우것)
false부분은 동기 비동기 여부이다 false는 동기야! 동기로해도 되는데 큰 문제가있어!
이 경우 비동기가 아니기 때문에 (동기적)
if(tagName != 'LI' && tagName != 'A') //li 가 아니면 return;
return; //두가지 조건 만족시 본 함수에서 나가게해서 못쓰게 해
console.log("clicked"); //return 안되면 본 내용 이해하게끔
const request = new XMLHttpRequest();
request.open("GET", "http://localhost:8080/menus",false); //브라우저에서 url을 입력하는것과 같은 요
request.send(); //
console.log(request.responseText);
};
})
open() 메소드는 pstman에서 주소를 입력하는 부분이고
send() 는 postman 우측에 send버튼이야
다만 대전제는 조건문 때문에 clicked 일때! 객체가 생성되게끔한다. 이 경우 동기이기 때문에 콜백 함수 등을 쓸 필요가없다.
4) 동기형의 문제점
방금 방식은 postman으로 하는 것과 비슷해 동기형 요청은 send인데 postman이랑 비슷해
오래걸리면 계속 기다려야해
@GetMapping
public List<MenuView> getList(
@RequestParam(name = "p", defaultValue = "1") int page,
@RequestParam(name = "c", required = false) Integer categoryId,
@RequestParam(name = "q", required = false) String query ) {
// List <Menu> list = service.getList();
List <MenuView> list = service.getViewList(page, categoryId, query);
try {
Thread.sleep(10000);
}
catch (Exception e) {
e.printStackTrace();
}
// return "menu List";
return list ;
};
sleep(10000) 을 넣어 10초동안 대기를 시킨다.
log에 나올 때 까지 기다리게 되고, 화면이 다운되어버려! 이러한 점이 동기형의 문제점이야!
5)
JS는 비동기문제 해결하기 위해서 callBack함수를 써
onclick 할 때 실행하게끔 위임하는 함수! 콜백 즉 추후에 다시 전화주는 느낌이야
이따 전화해 호출해줘
const request = new XMLHttpRequest();
request.open("GET", "http://localhost:8080/menus?p=1&c=1&q=아메리",true); //브라우저에서 url을 입력하는것과 같은 요
request.send(); //
console.log(request.responseText);
true로 하면 비동기형이 돼
다만 문제가 있어 비동기로 빠져있는데, log는 실행도 안했는데 출력해버려
log에 10초뒤(즉 데이터 로드 완료 후) 에 나오게끔 해줘야해
이따 콜해줘 부탁하려면 지금안되고 함수에 담아서 줘야해
const request = new XMLHttpRequest();
request.onload = function(){
console.log(request.responseText);
}
request.open("GET", "http://localhost:8080/menus?p=1&c=1&q=아메리",true); //브라우저에서 url을 입력하는것과 같은 요
request.send(); //
비동기 하는 방법이 있는데 수단으로 callback과 promise야
그래서 log가 다 onload 되고 나서 입력되게 해!
10초 되기 전에 클릭이 가능한 상황이다.
6)
비동기는 JS가 아니라 JS가 쓰는 플랫폼에서 기능이 있어
비동기로 처리하는 대신 완료된 시점을 알수가없으니까 비동기처리하는곳에 위임하는 방법을 쓸 밖에없어
나중에 호출한다고 해서 콜백함수야!
그런데 이렇게 하는것을 사람들이 안좋아해 콜백이 콜백이 콜백이 부르는 방식 때문에 나온게 promise야!
화면갱신하는 방법부터 먼저하고 promise는 곧 있다가 배우자!
json 문자열로 되어있는데 json parser를 이용하자!
if(tagName != 'LI' && tagName != 'A') //li 가 아니면 return;
return; //두가지 조건 만족시 본 함수에서 나가게해서 못쓰게 해
console.log("clicked"); //return 안되면 본 내용 이해하게끔
const request = new XMLHttpRequest();
request.onload = function(){
//json parser
let menus = JSON.parse(request.responseText)
console.log(menus[0]);
}
request.open("GET", "http://localhost:8080/menus?p=1&c=1&q=아메리",true); //브라우저에서 url을 입력하는것과 같은 요
request.send(); //
무분별한 문자열을 JSON형식으로 변환시켰다.
7)
if(tagName != 'LI' && tagName != 'A') //li 가 아니면 return;
return; //두가지 조건 만족시 본 함수에서 나가게해서 못쓰게 해
// let queryString = "";
// console.log("clicked"); //return 안되면 본 내용 이해하게끔
let categoryId = 1;
const request = new XMLHttpRequest();
request.onload = function(){
let menus = JSON.parse(request.responseText)
console.log(menus[0]);
}
request.open("GET", `http://localhost:8080/menus?c=${categoryId}`,true); //브라우저에서 url을 입력하는것과 같은 요
request.send(); //
};
데이터를 꽂아넣기 위해서 backtick을 쓴다. ${categoryId}
클릭할 때 특정 데이터(categoryId)에 대해서 수집을 하고 심어야해
이 데이터를 li 태그 에다가만 심고 싶어
<li th:attr="data-cid=${c.id}"
th:class="${#strings.equals(param.c, c.id)}? 'menu-selected'"
th:each="c : ${categoryList}" >
타임리프의 th:attr 을이용해서 카테고리 아이디들을 각 li태그에다가 심어준다.
각 태그에 c.id가 심어졌다.
11)
시블링을 다음시간에 보자
1. 보충
2. 회고
1) 날이 갈수록 프론엔드에 대해서 궁금해진다
'배움 __IL > TIL 1기' 카테고리의 다른 글
TIL : 78번째- 230328 [3-4-화] (1) | 2023.03.28 |
---|---|
TIL : 77번째- 230327 [3-4-월] (0) | 2023.03.27 |
TIL : 75번째- 230323 [3-3-목] (0) | 2023.03.23 |
TIL : 74번째- 230322 [3-3-수] (0) | 2023.03.22 |
TIL : 73번째- 230321 [3-3-화] (0) | 2023.03.21 |