Restful Service(Representational State Transfer)
- 클라이언트와 서버 요소를 엄격하게 구분함
- 하나의 서버로 다양한 플랫폼의 클라이언트 대응 가능
- url 형태로 요청을 명료화할 수 있음
- URI : ex) /detail/java/15
- 상황이나 요청 데이터에 따라 요청방식을 선택
- Restful 서비스의 반환 값은 일반적으로 XML과 JSON을 활용(JSON이 가장 대중적)
json 형태의 문자열을 HashMap으로 변환(jackson-databind 필요)
- pom.xml
- jackson-databind 추가(버전 상관 없음 - boot에서 알아서 적용해줌)
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
- index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-3.6.3.min.js"></script>
</head>
<body>
<h3>@RestController : @ResponseBody를 사용하지 않아도 됨</h3>
<ul>
<li>/rest/list.ajax<button onclick="sendAjax('list.ajax')">list 호출</button></li>
<li>/rest/map.ajax<button onclick="sendAjax('map.ajax')">map 호출</button></li>
<li>/rest/object.ajax<button onclick="sendAjax('object.ajax')">object 호출</button></li>
</ul>
<h3>복잡한 JSON 전송</h3>
<p>복잡한 json 형태의 전송은 기존과 다른 방식<button onclick="complex()">복잡한 JSON</button></p>
<h3>서버에서 문자열을 json 형태로 변환할 수 있음</h3>
<p>hashmap 형태 : <button onclick="sendAjax('strMap.ajax')">map</button></p>
<p>UserInfo 형태 : <button onclick="sendAjax('strObject.ajax')">UserInfo</button></p>
</body>
<script>
function complex(){
var arr = [1,2,3,4,5];
var obj = {};
obj.name="json";
obj.num = arr;
var params = {"values":obj};
console.log(params);
$.ajax({
url : 'rest/complex.ajax',
type:'POST', // post 방식이어야 함
data:JSON.stringify(params), // json을 문자열화 해야함
dataType:'json',
contentType:'application/json; charset=utf-8;', // contentType이 json이라고 명시해줘야함
success:function(data){
console.log(data);
},error:function(e){
console.log(e);
}
});
}
function sendAjax(uri){
$.ajax({
type:'get',
url:'rest/'+uri,
dataType:'json',
success:function(data){
console.log(data);
},
error:function(e){
console.log(e);
}
});
}
</script>
</html>
- ApiController
- restful에서는 기본적으로 아래 method를 사용
- GET : 특정 데이터 조회 요청할 때 사용
- POST : 특정 데이터의 입력을 요청할 때 사용
- DELETE : 특정 데이터의 삭제를 요청할 때 사용
- PUT : 특정 데이터의 수정을 요청할 때 사용
- PATCH : 특정 데이터의 수정(일부)를 요청할 때 사용
- 사용방법
- @xxxMapping(value="/")
- @RequestMapping(value="/" method={RequestMethod.xxx}) : 여러가지 방식을 받을 경우
package kr.co.gudi.controller;
import java.util.ArrayList;
import java.util.HashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import kr.co.gudi.dto.UserInfo;
// restController는 앞에 /rest가 붙은 요청만 받기로 함(규칙)
@RestController
@RequestMapping(value = "/rest")
public class ApiController {
Logger logger = LoggerFactory.getLogger(getClass());
@RequestMapping(value = "/list.ajax")
public ArrayList<String> list(){
logger.info("list 형태로 반환");
ArrayList<String> list = new ArrayList<String>();
list.add("하나");
list.add("둘");
list.add("셋");
return list;
}
@GetMapping(value="/map.ajax")
public HashMap<String, Object> map(){
logger.info("map 형태로 반환");
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("msg", "hello");
map.put("age", 33);
map.put("married", false);
return map;
}
@GetMapping(value = "/object.ajax")
public UserInfo object() {
logger.info("UserInfo 형태로 반환");
UserInfo info = new UserInfo();
info.setId("tester");
info.setAge(55);
info.setName("Lee");
info.setPromotion(true);
return info;
}
@PostMapping(value = "/complex.ajax")
public HashMap<String, Object> complex(@RequestBody HashMap<String, Object> params){
logger.info("params : {}",params);
// params : {values={name=json, num=[1, 2, 3, 4, 5]}}
HashMap<String, Object> vmap = (HashMap<String, Object>) params.get("values");
logger.info("vmap : "+vmap);
String name = (String) vmap.get("name");
logger.info("name : "+name);
ArrayList<Integer> list = (ArrayList<Integer>) vmap.get("num");
logger.info("list : "+list);
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("success", true);
return map;
}
@GetMapping(value = "strMap.ajax")
public HashMap<String, Object> strMap() throws Exception{
// json 형태의 문자열을 HashMap으로 변환(jackson-databind 필요)
// json 형태로 입력할 때는 "" 사용
String json = "{\"no\":1, \"msg\":\"HashMap 변환 완료\", \"name\":\"홍길동\"}";
ObjectMapper mapper = new ObjectMapper();
// 여기 있는 데이터를, 이 형태로 만들어줘
// 타입체크가 강력함(다만 사용하기 귀찮음)
// HashMap<String, Object> map = mapper.readValue(json, new TypeReference<HashMap<String, Object>>() {});
// 사용 자체가 편리한 방법
HashMap<String, Object> map = mapper.readValue(json, HashMap.class);
return map;
}
@GetMapping(value = "/strObject.ajax")
public UserInfo strObject() throws Exception {
String json = "{\"id\":\"json ID\", \"name\":\"홍길동\", \"age\":44,\"promotion\":false}";
ObjectMapper mapper = new ObjectMapper();
UserInfo info = mapper.readValue(json, UserInfo.class);
return info;
}
}
- UserInfo(dto)
package kr.co.gudi.dto;
public class UserInfo {
private String id;
private String name;
private int age;
private boolean promotion;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public boolean isPromotion() {
return promotion;
}
public void setPromotion(boolean promotion) {
this.promotion = promotion;
}
}
실시간 데이터 변경/조회
- Restful은 url 경로를 활용하여 데이터를 가져오는 방식이므로 url 경로 자체를 파라메터처럼 변수화 시킬 수 있음
- index.html
- TeamCotroller
- 필드 주입 : @Autowired TeamService service; (사용지양됨)
- 순환참조를 조기에 발견할 수 없음(순환참조 : 서로를 참조하는 것으로 작동되지 않을 수 있음)
- Controller -> Service -> DAO 와 같이 일방향 구조는 순환참조가 발생하지 않아 사용 가능
- 서비스끼리 서로 참조하는 경우 문제가 발생할 수 있음(MemberService와 MyPageService가 서로를 호출할 경우)
- 서비스 실행 후 실제 문제 발생(stack over flow) 시 까지 알 수 없음
- 생성자 주입
- final을 쓸 수 있으므로 불변성 보장
- 객체 간 순환참조 방지
- 순환참조 발생 시 빌드 전에 미리 알 수 있음(컴파일 에러 발생 - 순수자바이기 때문에 컴파일 시 확인 가능)
- 필드 주입 : @Autowired TeamService service; (사용지양됨)
private final TeamService service;
public TeamCotroller(TeamService service) { //생성자 주입
this.service = service;
}
- TeamService
- TeamDAO
- team_mapper
'코딩도전기 > Spring Boot' 카테고리의 다른 글
Spring Boot - Properties / AOP(Interceptor) (0) | 2023.06.02 |
---|---|
Spring Boot - REST API (0) | 2023.05.31 |
Spring Boot - Transaction / Connection Pool / CSS 일괄적용 (0) | 2023.05.26 |
Spring Boot - 쿼리문 로고 찍기 / 동적쿼리 (0) | 2023.05.25 |
Spring Boot (0) | 2023.05.24 |