HttpHeader, body
https://developer.mozilla.org/ko/docs/Web/HTTP/Messages
HttpStatus, Status 참조용
https://developer.mozilla.org/en-US/docs/Web/HTTP/Status
produces : 클라이언트에게 반환하는 HTTP Header의 형식을 지정하는 파라미터 (클라이언트에 데이터를 전달할 때, 서버의 입장에서 데이터를 생산할 때)
consumes : 클라이언트에서 들어오는 HTTP Header의 형식을 지정하는 파라미터 (클라이언트로부터 데이터를 얻을 때, 서버의 입장에서 데이터를 소비할 때)
@ResponseBody : 자바 객체를 json 기반의 HTTP Body로 변환
@RequestBody : json 기반의 HTTP Body를 자바 객체로 변환
@CrossOrigin : CORS 요청 처리 방식 명시
@ExceptionHandler : 하나의 컨트롤러에 대해 예외 처리
동기 (Synchronous) : 요청 결과 응답 후, 다른 동작이 실행되는 방식
비동기 (Asynchronous) : 요청 결과 응답과는 별개로 다음 동작이 실행되는 방식
@RestController : 요청에 대한 응답을 지정한 content type으로 리턴하는 컨트롤러 (화면에 대한 전환이 없음)
RestController의 기본 리턴 타입 : ResponseEntity<Resource>
콜백 함수 : 다른 함수의 파라미터로 넘겨주는 함수
function func() {
console.log(1);
setTimeout(() => console.log(2), 0);
console.log(3);
// 1 3 2 순으로 출력
}
콜백 지옥을 해결하기 위해 Promise를 사용
// 생산자
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {resolve('data1');}, 2000);
});
// 소비자
promise1.then(v => console.log(v));
XMLHttpRequest : 웹 브라우저와 서버 간에 메소드가 데이터를 전송하는 객체 형태의 API
JSON (JavaScript Object Notation) : 데이터를 문자열의 형태로 주고 받도록 만들어진 내장객체
function ajaxTest() {
// step01 : 비동기 요청 객체 생성
var xhr = new XMLHttpRequest();
// step03 : 데이터 응답
xhr.onreadystatechange = function() {
if(this.readyState == 4 && this.status == 200) {
document.write(this.responseText);}
}
// step02 : 서버로 데이터를 비동기로 요청
xhr.open("GET", "https://jsonplaceholder.typicode.com/users");
xhr.send();
}
ajaxTest();
fetch : 비동기 통신을 제공하는 JS 내장 함수
기본 요청은 GET, 이외 POST, PUT, DELETE가 있음
fetch('url')
.then(response => response.json())
.then(data => console.log(data));
axios : 비동기 통신을 위한 프로미스 기반의 라이브러리
요청 방식은 fetch와 같음, 기본적으로 json 객체 반환
axios.get(url)
.then(response => response.data)
.then(users => console.log(users[7]))
@RestController : 요청에 대한 응답을 지정한 컨텐트 타입으로 리턴하는 컨트롤러 (화면에 대한 전환이 없음)
객체를 json 형식으로 전달하려면 converter가 필요함 (Jackson 라이브러리)
POSTMAN 이용함
@RestController
public class DeptRestController {
// GET 요청
// 객체를 Json으로 전달하려면 converter가 필요함 (Jackson)
// Jackson으로 컨버팅을 하지만 서버에서 어느 데이터 타입을 생산하는지 알리기 위해 명시함
@CrossOrigin(origins = {"*"}) // 모든 요청을 허용
@RequestMapping(value = "/getTest2",
method = RequestMethod.GET,
produces = {MediaType.APPLICATION_JSON_VALUE})
// @ResponseBody // RestController 를 사용하면 생략 가능
public Dept getTest2() {
Dept dept = new Dept(50, "DEV", "IT");
return dept;
}
// POST 요청1, MediaType JSON, 여러 개의 타입으로 받을 수 있음
@RequestMapping(value = "/getTest3",
method = RequestMethod.POST,
consumes = {MediaType.APPLICATION_JSON_VALUE})
@ResponseBody
public String getTest3(@RequestBody Dept newDept) {
return "success";
}
// POST 요청2 MediaType URLENCODED_VALUE
@RequestMapping(value = "/getTest3",
method = RequestMethod.POST,
consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE})
@ResponseBody
public String getTest3ForForm(Dept newDept) {
return "success";
}
// HTTP 통신
@CrossOrigin(origins = {"*"})
@RequestMapping(value = "/api/dept/{deptno}",
method = RequestMethod.POST,
produces = {MediaType.APPLICATION_JSON_VALUE})
public Dept getDeptByDeptno(@PathVariable int deptno) {
Dept dept = null;
if(dept == null) {
throw new NullPointerException("해당 부서가 존재하지 않습니다.");
}
return dept;
}
// RestController 임시 예외 처리
@ExceptionHandler(value = {NullPointerException.class})
public ResponseEntity<String> handleNullPointerException(Exception e) {
return new ResponseEntity<String>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
blur가 된다면 DB의 deptno 여부에 따라 중복 여부 체크
<span style="font-size:12pt;">
<input id="deptno" type="text" name="deptno" size="30">
</span>
<br/>
<span id="deptnoMsg" style="font-size:8pt"></span>
<script type="text/javascript">
const inputDeptno = document.getElementById('deptno');
const deptMsg = document.getElementById('deptnoMsg');
inputDeptno.addEventListener('blur', () => {
axios.get('http://localhost:8082/api/dept/' + inputDeptno.value)
.then(response => {
if(response.data == '') {
deptMsg.innerHTML = '새로운 부서 번호로 사용할 수 있습니다.';
}
})
.catch(error => {
deptMsg.innerHTML = error.response.data;
})
});
</script>
@RestController
@RequiredArgsConstructor // 생성자 주입 방식, 안정성이 높음
public class DeptAPIController {
final DeptService deptService; // 생성자 주입 방식, 안정성이 높음
// deptno 검증
@RequestMapping(value = "/api/dept/{deptno}",
method = RequestMethod.GET)
@ResponseBody
public Dept getAPIDeptByDeptno (@PathVariable int deptno) throws Exception {
Dept dept = deptService.getDeptByDeptno(deptno);
if(dept != null) {
throw new Exception("이미 존재하는 부서번호 입니다.");
}
return dept;
}
// 리턴 타입 ResponseEntity<?>
@ExceptionHandler(value = {Exception.class})
public ResponseEntity<String> handleNullPointerException(Exception e) {
return new ResponseEntity<String>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
ERROR 415 : MediaType이 매치되지 않을 경우 발생 (json, urlEncoded, form-data)
CORS ERROR : 동일한 http://ip주소:포트 번호까지 동일해야만 요청한 결과값을 돌려주는 정책
이 정책을 모두 다 허용하기 위해서 backend 요청 메소드에 @CrossOrigin(origin = {"*"}) 을 추가
xml에서 javascript를 사용할 떄 자동완성이 되지 않아 문법적인 실수가 정말 많았음, 자동 완성에 너무 의존하면 안될 것 같음
이제 정말 프론트에서 서버, 데이터베이스까지 연결할 수 있게되서 정말 기뻤다.
throw를 사용해서 중복값을 예외로 만들어 처리하는 것과
예외 처리를 왜 @ControllerAdvice, @ExceptionHandler 에서 해줘야하는 이유도 점차 알아가고 있다.
이제 정말 미니프로젝트에 대한 기본 지식은 갖춘 것 같다.