스프링부트 HTTP 응답

WAS·2024년 2월 7일
0

✅ 정적 리소스
src/main/resources -> 리소스를 보관하는 곳, 클래스 패스의 시작 경로
다음 디렉토리에 리소스를 넣어두면 스프링부트가 정적 리소스로 서비스를 제공

  • 스프링부트의 정적 리소스 경로 -> src/main/resources/static
    다음 경로로 파일이 들어오면 ex) src/main/resources/static/basic/hello.form.html
    웹 브라우저에서는 다음과 같이 실행하면 됨 ex) http://loaclhost:8080/basic/hello-form.html

✅ 뷰 템플릿

  • 일반적으로 HTML을 동적으로 생성하는 용도로 사용됨

  • 스프링 부트의 뷰 템플릿 경로 -> src/main/resources/templates
    위 경로에서 하위에다 패키지 or html 파일을 만들면 됨

  • @ResponseBody 있으면
    뷰 템플릿을 사용하는 것이 아니라, HTTP 메시지 바디에 직접 응답하여 데이터 출력

  • @ResponseBody 없으면
    뷰 리졸버가 해당 매핑 주소를 찾고 렌더링 한다

@Controller
public class ResponseViewController {

    @RequestMapping("/response-view-v1") // @ResponseBody 가 없으므로 뷰 리졸버가 해당 "resonse/hello"를 찾고 렌더링 한다
    public ModelAndView responseViewV1(){
        ModelAndView mav = new ModelAndView("response/hello").addObject("data","hello!");
        return mav; // ModelAndView 객체에 뷰와 데이터 둘다 저장해서 이 객체 자체를 리턴
    }

    @RequestMapping("/response-view-v2")
    public String responseViewV2(Model model){  // Model 객체를 이용해서 데이터를 넣고 뷰는 문자열로 반환
        model.addAttribute("data","hello!");
        return "response/hello";
    }
}


✅ HTTP API, 메시지 바디에 직접 입력
@RestController = Controller + ResponseBody
-> 컨트롤러에 모두 @ResponseBody 효과가 적용됨
-> 뷰 템플릿을 사용하는 것이 아니라, HTTP 메시지 바디에 직접 데이터를 입력한다
-> Rest API (HTTP API)를 만들 때 사용하는 컨트롤러임

@Slf4j
@Controller
public class ResponseBodyController {
    @GetMapping("/response-body-string-v1") // HttpServlet 객체를 사용하여 문자열 형태(바디메시지)로 반환하는 방법
    public void responseBodyV1(HttpServletResponse response) throws IOException{
        response.getWriter().write("ok");
    }

    @GetMapping("/response-body-string-v2") // ResponseEntity 객체를 사용하여 문자열 형태(바디메시지)로 반환하는 방법
    public ResponseEntity<String> responseBodyV2() {
        return new ResponseEntity<>("OK", HttpStatus.OK);
    }

    @ResponseBody
    @GetMapping("/response-body-string-v3") // ResponseBody 어노테이션을 사용해서 문자열 형태(바디메시지)로 반환하는 방법
    public String responseBodyV3() {
        return "ok";
    }

    @GetMapping("/response-body-json-v1") // ResponseEntity 객체로 json형태로 반환하는 방법
    public ResponseEntity<HelloData> responseBodyJsonV1(){
        HelloData helloData = new HelloData();
        helloData.setUsername("userA");
        helloData.setAge(20);
        return new ResponseEntity<>(helloData,HttpStatus.OK);
    }

    @ResponseStatus(HttpStatus.OK)  // Http 상태코드 정하기
    @ResponseBody
    @GetMapping("/response-body-json-v2") // ResponseBody 어노테이션을 사용하여 json형태로 반환하는 방법
    public HelloData responseBodyJsonV2(){
        HelloData helloData = new HelloData();
        helloData.setUsername("userA");
        helloData.setAge(20);
        return helloData;
    }

@ResponseBody vs ResponseEntity

@ResponseBody

  • 메서드의 반환 값을 HTTP 응답 본문에 직접 넣어 클라이언트에게 전달
  • 주로 JSON, XML, 문자열 등의 데이터를 반환할 때 사용
  • HTTP 상태 코드나 헤더를 직접 설정할 수 없으며, 기본적으로 Spring이 자동으로 처리
@GetMapping("/hello")
@ResponseBody
public String sayHello() {
  return "Hello, World!"; // 응답 본문: "Hello, World!"
}

ResponseEntity

  • HTTP 응답 전체를 제어할 수 있는 클래스
  • 응답 본문 뿐만 아니라 HTTP 상태 코드 , 헤더 등을 명시적으로 설정
  • HTTP 상태 코드 설정 (예: 200 OK, 404 NOT FOUND, 등)
  @GetMapping("/hello")
  public ResponseEntity<String> sayHello() {
      return ResponseEntity.ok("Hello, World!"); 
      // 응답 본문: "Hello, World!", 상태 코드: 200 OK
  }

  @GetMapping("/product")
  public ResponseEntity<Product> getProduct() {
      Product product = new Product("상품명", 10000);
      return ResponseEntity.status(200).body(product);
      // 응답 본문: {"name":"상품명","price":10000}, , 상태 코드: 200 OK
  }

그러면 @RestController@ResponseBody 를 각각 언제 사용해야할까?

한 컨트롤러에 모두 API 용으로 사용된다면? @RestController 를 사용하면 된다
-> @RestController@ResponseBody 포함되어 있기 때문에
-> 즉 이 클래스는 화면용(view) 가 아닌, 순수하게 json 또는 문자열 응답을 위한 API 컨트롤러

그러면 @RestController 는 한 컨트롤러에서 일부 메서드는 뷰를 반환, 일부 메소드는 데이터를(API 용) 반환할 때 직접적으로 사용한다.
이럴 경우 @RestController 를 명시하지 않고, @Controller 를 명시해야한다


✅ INSERT 중복 등록 방지 방법

  • POST-Redirect-GET (PRG) 패턴
  • 클라이언트 리다이렉트 location.replace()
  • CSRF 토큰 또는 세션 검증

POST-Redirect-GET (PRG) 패턴 방법이 가장 많이 사용하는 방법으로 작동 방식

  1. 사용자가 상품 등록 폼을 제출하면 서버에서 데이터를 저장합니다
  2. 서버는 클라이언트에게 리다이렉트를 응답합니다 (redirect:)
  3. 클라이언트는 리다이렉트된 URL로 GET 요청을 보냅니다
  4. 브라우저 히스토리에 기록되는 것은 리다이렉트된 URL(GET 요청)이고, POST 요청은 기록되지 않습니다
  5. 뒤로가기를 누르면 다시 상품등록 폼 페이지로 이동되는 단점이 있다
@PostMapping("/productRegistEnd")
public String productRegistEnd(@ModelAttribute Product product, HttpSession session) {
    // 상품 등록 로직 수행
    productService.saveProduct(product);

    // 리다이렉트하여 중복 등록 방지
    return "redirect:/user/productList"; // 상품 목록 페이지로 이동
}
profile
우측 상단 햇님모양 클릭하셔서 무조건 야간모드로 봐주세요!!

0개의 댓글