Back-end/Spring Boot

[Spring Boot] Model에서 Rest API로 변환

Bay Im 2024. 4. 6. 12:52
개념 정리 

 

이전까지는 @RequestParam으로 사용자 입력 값을 가져오고, Model을 사용하여 addAtribute로 데이터를 보내서 출력했다.

하지만 REST API를 사용한다면 JSON 형식의 데이터를 주고 받는다.

@RequestBody로 사용자 입력 값을 가져오고 @ResponseBody로 데이터를 보내준다.

 

그리고 View만 출력하는 ViewController와 REST API 메서드만 모여있는 ApiController를 구분해서 구현한다.

ApiController 클래스는 @RestController 어노테이션을 준다. (@RestController = @Controller + @ResponseBody)

RestController의 주요 메소드는 GET, POST(create), DELETE, PUT(update)이다.

ApiController 메서드의 return 값은 DTO 클래스를 생성하여 DTO에 담아서 보낸다. 또한 Map, List도 담아서 보낼 수 있다. 

 

 

Rest API 구현 순서
  1. ViewController와 ApiController는 따로 나눠서 생성한다.
  2. ViewController를 생성한다.
    • 클래스에 @Controller 어노테이션을 준다.
    • main이나 Form 출력같이 로직과 전달 값 없고, 오로지 View만 출력하는 메소드로만 구성한다.
    • 해당 메소드의 return 값은 이동할 html 파일명을 주는 @Getmapping 메소드이다.
    • 예시
      • public class ViewController {
            // 메인 출력
            @GetMapping("/")
            public String main() {
                return "login";
            }
        
            // 회원가입 폼 출력
            @GetMapping("/join")
            public String viewJoin() {
                return "join";
            }
        }
  3. RequestDTO/ResponseDTO를 생성한다.
    • ApiController 메소드에서 Request할 값이나, Reponse할 값이 있다면 그 값을 담아서 넘겨줄 DTO를 생성한다.
    • DTO는 @Data 어노테이션을 주입한다.
    • REST API를 구성할 때 return 값 데이터 형태는 DTO, Map, List 형태 모두 가능하다.
      • 하지만 나는 왠만해서 DTO를 만들어서 사용하려고 했다.
      • 그런데 넘겨줄 값이 한 개이면 그냥 Map으로 선언하여 넘겨주었다! (고민: 값 1개를 넘겨줘도 DTO를 만들어서 사용하는게 나을지?)
    • 예시
      • // ApiController의 join 메소드 사용 
        @Data
        public class JoinReqDTO {
            private String inputName;
            private String inputEmail;
            private String inputPw;
        }
        -------------------------------------
        // ApiController의 login 메소드 사용
        @Data
        public class LoginReqDTO {
            private String inputName;
            private String inputPw;
        }
  4. ApiController를 생성한다.
    • 클래스에 @RestController 어노테이션을 준다.
      • 아직 전체 메소드를 RESTFUL하게 만들지 못하였다면 먼저 @Controller 어노테이션을 주입하고 REST 메소드에 @ResponseBody를 붙여서 점점 만들어 나간다.
        • 예시
          •     // 회원가입
                @PostMapping("/join")
                @ResponseBody
                public List<Member> join(@RequestBody JoinReqDTO joinReqDTO) {
                    Member member = Member.builder()
                            .username(joinReqDTO.getInputName())
                            .email(joinReqDTO.getInputEmail())
                            .password(joinReqDTO.getInputPw())
                            .joindate(LocalDate.now())
                            .build();
            
                    memberList.add(member);
                    return memberList;
                }
    • REST API 메소드를 생성한다.
      • 매개변수에서 받아올 값은 @RequestBody와 위에서 만든 RequestDTO를 사용하여 JSON 형태로 값을 받아온다.
        • 예시
          • join(@RequestBody JoinReqDTO joinReqDTO)
      • 엔티티에 저장할 값(POST)이 있다면 builder()를 사용하여 값을 넣어준다.
        • 해당 엔티티 클래스에는 @Builder 어노테이션이 붙여진 상태여야 한다.
        • 예시
          • Member member = Member.builder()
                    .username(joinReqDTO.getInputName())
                    .email(joinReqDTO.getInputEmail())
                    .password(joinReqDTO.getInputPw())
                    .joindate(LocalDate.now())
                    .build();
      • 보낼 값(Reponse)의 데이터 타입은 위에서 생성한 DTO나 Map, List 형태 모두 가능하다.
        • 메소드에 @ResponseBody 어노테이션을 붙여주거나, @RestController가 붙은 컨트롤러 클래스라면 자동으로 3가지의 데이터를 모두 JSON으로 자동변환하여 넘겨주기 때문이다.
      • 예시
        •     // Map 형태 
              @PostMapping("/")
              public Map<String, String> login(@RequestBody LoginReqDTO loginReqDTO) {
                  String message = "로그인 실패!";
                  String inputName = loginReqDTO.getInputName();
                  String inputPw = loginReqDTO.getInputPw();
          
                  for(Member member: memberList) {
                      if(member.getUsername().equals(inputName) &&
                              member.getPassword().equals(inputPw)) {
                          message = "로그인 성공!";
                          break;
                      }
                  }
          
                  Map<String, String> loginResMap = new HashMap<>();
                  loginResMap.put("message", message);
          
                  return loginResMap;
              }
          
          	// List 형태 
              // 회원가입
              @PostMapping("/join")
              public List<Member> join(@RequestBody JoinReqDTO joinReqDTO) {
                  Member member = Member.builder()
                          .username(joinReqDTO.getInputName())
                          .email(joinReqDTO.getInputEmail())
                          .password(joinReqDTO.getInputPw())
                          .joindate(LocalDate.now())
                          .build();
          
                  memberList.add(member);
                  return memberList;
              }
  5. html에서 fetch()를 사용하여 스크립트 함수를 작성한다.
    • Request만 있고 Response 값이 없을 때 예시
      •     const join = () => {
                const inputName = document.getElementById("inputName").value;
                const inputEmail = document.getElementById("inputEmail").value;
                const inputPw = document.getElementById("inputPw").value;
        
                fetch("/join", {
                    method: "POST",
                    headers: {
                        "Content-Type": "application/json"
                    },
                    body: JSON.stringify({
                        inputName: inputName,
                        inputPw: inputPw,
                        inputEmail: inputEmail
                    })
                })
                    .then(response => {
                        if (response.ok) {
                            window.location.href = "/";
                        } else {
                            console.error("회원가입 실패");
                        }
                    })
                    .catch(error => {
                        console.error("오류 발생: ", error);
                    })
            }​
        • 값을 보낼 때 input 태그에 있던 id의 값을 document.getElementById(”id값").value; 을 변수에 담는다.
        • 이후 위의 변수를 body에서 JSON 형태로 보낸다. {변수명: 변수명, ….}
        • 실행 후 경로 이동이 있다면 window.location.href = "경로"; 의 형태로 작성한다.
    • Request와 Response 값이 모두 있을 때 예시
      •     const login = () => {
                const inputName = document.getElementById("inputName").value;
                const inputPw = document.getElementById("inputPw").value;
        
                fetch("/", {
                    method: "POST",
                    headers: {
                        "Content-Type": "application/json"
                    },
                    body: JSON.stringify({
                        inputName: inputName,
                        inputPw: inputPw
                    })
                })
                    .then(response => response.json())
                    .then(data => {
                        document.getElementById("alert").innerText = data.message;
                    })
                    .catch(error => {
                        console.error('Error:', error);
                    });
            }
      • Request는 위의 방법과 같고, Reponse 값은 .then() 안에서 data(json)를 가져온 후, data.키이름 형식으로 값을 가져온다.
        • 예시
          • .then(data => {document.getElementById("alert").innerText = data.message;})
      • div 태그의 값을 Reponse한 값으로 변경하려면 document.getElementById("id명").innerText 로 변경한다.
728x90