✅ 정적 리소스
src/main/resources
-> 리소스를 보관하는 곳, 클래스 패스의 시작 경로
다음 디렉토리에 리소스를 넣어두면 스프링부트가 정적 리소스로 서비스를 제공
src/main/resources/static
src/main/resources/static/basic/hello.form.html
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
@GetMapping("/hello")
@ResponseBody
public String sayHello() {
return "Hello, World!"; // 응답 본문: "Hello, World!"
}
ResponseEntity
응답 본문
뿐만 아니라 HTTP 상태 코드
, 헤더
등을 명시적으로 설정 @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) 패턴
방법이 가장 많이 사용하는 방법으로 작동 방식
@PostMapping("/productRegistEnd")
public String productRegistEnd(@ModelAttribute Product product, HttpSession session) {
// 상품 등록 로직 수행
productService.saveProduct(product);
// 리다이렉트하여 중복 등록 방지
return "redirect:/user/productList"; // 상품 목록 페이지로 이동
}