실제 개발을 하면 요청 파라미터를 받아서 필요한 객체를 만들고 그 객체에 값을 넣어주어야 한다.

@RequestParam String username;
@RequestParam int age;

HelloData data = new HelloData();
data.setUsername(username);
data.setAge(age);

스프링은 이 과정을 완전히 자동화해주는 @ModelAttribute 기능을 제공한다.

먼저 요청 파라미터를 바인딩 받을 객체를 만들자.

 

HelloData

package hello.springmvc.basic;
import lombok.Data;

@Data
public class HelloData {
 	private String username;
 	private int age;
}

롬복 @Data

@Getter, @Setter, @ToString, @EqualsAndHashCode, @RequiredArgsConstructor를 자동으로 적용해준다.

 

  @ResponseBody
    @RequestMapping("/model-attribute-v1")
    public String modelAttributeV(@ModelAttribute HelloData helloData){
        log.info("username={}, age={}",helloData.getUsername(),helloData.getAge());

        return "ok";
    }

객체가 생성되고, 요청 파라미터의 값도 모두 들어가 있다.

 

스프링MVC는  @ModelAttribute가 있으면 다음을 실행한다.

- HelloData 객체를 생성한다.

- 요청 파라미터의 이름으로 HelloData 객체의 프로퍼티를 찾는다. 그리고 해당 프로퍼티의 setter를 호출해서 파라미터의

   값을 바인딩 한다.

    예) 파라미터 이름이 username이면 setUsername() 메서드를 찾아서 호출하면서 값을 입력한다.

 

프로퍼티

객체의 getUsername(), setUsername() 메서드가 있으면 ,이 객체는 username이라는 프로퍼티를 가지고 있다.

username 프로퍼티의 값을 변경하면 setUsername()이 호출되고, 조회하면 getUsername()이 호출된다.

class HelloData {
 getUsername();
 setUsername();
}

 

바인딩 오류

age=abc 처럼 숫자가 들어가야 할 곳에 문자를 넣으면 BindException이 발생한다. 이런 바인딩 오류를

처리하는 방법은 검증에서 공부할 예정이다.

 

@ModelAttribute 또한 생략 가능하다.

@RequestParam도 생략할 수 있으니 혼란이 발생할 수 있다.

 

스프링은 해당 생략시 다음과 같은 규칙을 적용한다.

String, int, Integer같은 단순 타입 -> @RequestParam

나머지 -> @ModelAttribute(argument resolver로 지정해둔 타입 외)

 

스프링이 제공하는 @RequestParam을 사용하면 요청 파라미터를 매우 편리하게 사용할 수 있다.

 

 @ResponseBody
    @RequestMapping("/request-param-v2")
    public String requestParamV2(
        @RequestParam("username") String memberName,
        @RequestParam("age") int memberAge){

        log.info("username={}, age={}",memberName,memberAge);
        return"ok";
    }

@RequestParam : 파라미터 이름으로 바인딩

@ResponseBody : View조회를 무시하고, HTTP message body에 직접 해당 내용 입력

 

@RequestParam의 name(value) 속성이 파라미터 이름으로 사용

@RequestParma("username") String memberName

 -> request.getParameter("username")

@ResponseBody
    @RequestMapping("/request-param-v3")
    public String requestParamV3(
            @RequestParam String username,
            @RequestParam int age){

        log.info("username={}, age={}",username ,age);
        return"ok";
    }

    @ResponseBody
    @RequestMapping("/request-param-v4")
    public String requestParamV4(String username, int age){
        log.info("username={}, age={}",username ,age);
        return"ok";
    }

위의 코드에서 더 간편하게 하기위한 과정이다.

v3에서는 HTTP 파라미터 이름이 변수 이름과 같으면 @RequestParam(name="")생략이 가능하다.

v4에서는 String,int ,Integer등의 단순 타입이면 @RequestParam도 생략가능하다.

 

@RequestParam 애노테이션을 생략하면 스프링MVC는 내부에서 required=false를 적용한다.

 

이렇게 애노테이션을 완전히 생략해도 되는데, 너무 없는 것도 과할 수 있다.

@RequestParam이 있으면 명확하게 요청 파라미터에서 데이터를 읽는다는 것을 알 수 있다.

    @ResponseBody
    @RequestMapping("/request-param-required")
    public String requestParamRequired(
            @RequestParam(required = false) String username,
            @RequestParam(required = false)  Integer age){
        log.info("username={}, age={}",username ,age);
        return"ok";
    }

@RequestParam.required

파라미터 필수 여부

기본값이 파라미터 필수(true)이다.

 

/request-param 요청

username이 없으므로 400 예외가 발생한다.

 

주의! - 파라미터 이름만 사용

/request-param?username=

파라미터 이름만 있고 값이 없는 경우 -> 빈문자로 통과

 

주의! - 기본형에 null 입력

/request-param 요청

@RequestParam( required = false) int age

 

null을 int에 입력하는 것은 불가능(500예외 발생)

따라서 null을 받을 수 있는 Integer로 변경하거나, 또는 defaultValue 사용

 

@ResponseBody
    @RequestMapping("/request-param-default")
    public String requestParamDefault(
            @RequestParam(required = true, defaultValue = "guest") String username,
            @RequestParam(required = false, defaultValue = "-1")  int age){
        log.info("username={}, age={}",username ,age);
        return"ok";
    }

파라미터에 값이 없는 경우 defaultValue 를 사용하면 기본 값을 적용할 수 있다.

이미 기본 값이 있기 때문에 required 는 의미가 없다.

 

defaultValue 는 빈 문자의 경우에도 설정한 기본 값이 적용된다.

/request-param?username=

 

 @ResponseBody
    @RequestMapping("/request-param-map")
    public String requestParamMap(@RequestParam Map<String, Object> paramMap){
        log.info("username={}, age={}",paramMap.get("username"),paramMap.get("age"));
        return"ok";
    }

파리미터를 Map, MultiValueMap으로 조회할 수 있다.

 

@RequestParam Map

  Map(key = value)

 

@RequestParam MultiValueMap

  MultiValueMap(key=[value1, value2, ...] ex) {key=uesrIds, value=[id1, id2])

 

파라미터의 값이 1개가 확실하다면 Map을 사용해도 되지만, 그렇지 않다면 MultiValueMap을 사용하자

서블릿에서 공부했던 HTTP 요청 데이터를 조회하는 방법을 다시 떠올려 보았다.

그리고 서블릿으로 공부했던 내용을 스프링이 얼마나 편하게 바꿔주는지 알아보았다.

 

HTTP 요청 메시지를 통해 클라이언트에서 서버로 데이터를 전달하는 방법을 알아보았다.

 

클라이언트에서 서버로 요청 데이터를 전달할 때는 주로 3가지 방법을 사용한다.

 

GET - 쿼리 파라미터

  /url?uesrname=hello&age=20

  메시지 바디 없이, URL의 쿼리 파라미터에 데이터를 포함해서 전달

  예) 검색, 필터, 페이징 등에서 사용되는 방식

 

POST - HTML Form

  content-type : application/x-www-form-urlencoded

  메시지 바디에 쿼리 파라미터 형식으로 전달 username=hello&age=20

  예)회원 가입, 상품 주문, HTML Form 사용

 

HTTP message body에 데이터를 직접 담아서 요청

  HTTP API에서 주로 사용, JSON, XML, TEXT

  데이터 형식은 주로 JSON 사용

  POST, PUT, PATCH

 

요청 파라미터 - 쿼리 파라미터, HTML Form

HttpServletRequest의 request.getParameter()를 사용하면 두가지 요청 파라미터를 조회할 수 있다.

 

GET, 쿼리 파라미터 전송

예 ) http://localhost:8080/request-param?username=hello&age=20

 

POST, HTML Form 전송

예 )

POST /request-param ...
content-type: application/x-www-form-urlencoded

username=hello&age=20

GET 쿼리 파라미터 전송 방식이든, POST HTML Form 전송 방식이든 둘다 형식이 같으므로 구분없이

조회할 수 있다.

이것을 간단히 요청 파라미터(request parameter)조회라 한다.

package hello.springmvc.basic.request;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Slf4j
@Controller
public class RequestParamController {

    @RequestMapping("/request-param-v1")
    public void requestParamV1(HttpServletRequest request, HttpServletResponse response)throws IOException {
        String username = request.getParameter("username");
        int age = Integer.parseInt(request.getParameter("age"));

        log.info("username={}, age={}", username, age);
        response.getWriter().write("ok");
    }
}

단순히 서블릿과 같은 방식으로 조회했다.

<!DOCTYPE html>
<html>
<head>
 <meta charset="UTF-8">
 <title>Title</title>
</head>
<body>
 <form action="/request-param-v1" method="post">
 username: <input type="text" name="username" />
 age: <input type="text" name="age" />
 <button type="submit">전송</button>
 </form>
</body>
</html>

 HTML을 작성해서 POST방식으로도 테스트 해보았다.

이전 과는다르게 Jar를 사용하여 webapp경로를 사용할 수 없다. 이제부터 정적 리소스도 클래스 경로에 함께

포함해야 한다.

애노테이션 기반의 스프링 컨트롤러는 다양한 파라미터를 지원한다.

 

 

HttpServletRequest

HttpServletResponse

HttpMethod : HTTP 메서드를 조회한다.

Locale : Locale 정보를 조회한다.

 

@RequestHeader("host") String host

  특정 HTTP 헤더를 조회한다.

  속성

    필수 값 여부 : require

    기본 값 속성 : defaultValue

 

@CookieValue(value = "myCookie", require = false) String cookie

  특정 쿠키를 조회한다.

  속성

    필수 값 여부 : require

    기본 값 : defalutValue

 

MultiValueMap

MAP과 유사한데 , 하나의 키에 여러 값을 받을 수 있다.

HTTP header, HTTP 쿼리 파라미터와 같이 하나의 키에 여러 값을 받을 때 사용한다.

  KeyA = value1 & KeyA= value2

MultiValueMap<String, String> map = new LinkedMultiValueMap();
map.add("keyA", "value1");
map.add("keyA", "value2");
//[value1,value2]
List<String> values = map.get("keyA")

 

@Slf4j

다음 코드를 자동으로 생성해서 로그를 선언해준다.  개발자는 편리하게 log라고 사용하면 된다.

private static final org.slf4j.Logger log =
org.slf4j.LoggerFactory.getLogger(RequestHeaderController.class);

 

회원 관리를 HTTP API로 만든다 생각하고 매핑을 어떻게 하는지 알아보았다.

 

회원 관리API

회원 목록 조회 : GET /users

회원 등록 : POST /users

회원 조회 : GET /uesrs/{userID}

회원 수정 : PATCH /users/{userID}
회원 삭제 : DELETE /users/{userID}

 

package hello.springmvc.basic.requestmapping;

import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/mapping/users")
public class MappingClassController {

    @GetMapping
    public String users(){
        return "get users";
    }

    @PostMapping
    public String addUser(){
        return "post user";
    }

    @GetMapping("/{userId}")
    public String findUser(@PathVariable String userId){
        return "get userID";
    }

    @PatchMapping("/{userId}")
    public String updateUser(@PathVariable String userId){
        return "update userId=" + userId;
    }

    @DeleteMapping("/{userId}")
    public String deleteUser(@PathVariable String userId){
        return "delete userId=" +userId;
    }
}

깔끔하게 API만 설계 해보았다.

 

요청 매핑부분을 자세히 공부하였다.

 

package hello.springmvc.basic.requestmapping;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MappingController {

    private Logger log = LoggerFactory.getLogger(getClass());

    @RequestMapping("/hello-basic")
    public String helloBasic(){
        log.info("helloBasic");
        return "ok";
    }

}

 

매핑 정보

@RestController

  @Controller는 반환 값이 String이면 뷰 이름으로 인식된다. 그래서 뷰를 찾고 뷰가 랜더링 된다.

  @RestController는 반환 값으로 뷰를 찾는 것이 아니라, HTTP 메시지 바디에 바로 입력한다.

   따라서 실행 결과로 OK메시지를 받을 수 있다. @ResponseBody와 관련이 있다.

 

@RequestMapping("/hello-basic")

  /hello-basic  URL 호출이 오면 이 메서드가 실행되도록 매핑한다.

  대부분의 속성을 배열로 제공하므로 다중 설정이 가능하다.{"/hello-basic" , "/hello-go"}

 

Postman으로 테스트 해보았다.

 

둘다 허용

다음 두가지 요청은 다른 URL이지만, 스프링은 다음 요청들을 같은 요청으로 매핑한다.

매핑 : /hello-basic

URL 요청 : /hello-basic, /hello-basic/

 

HTTP 메서드

@RequestMapping에 method 속성으로 HTTP 메서드를 지정하지 않으면 HTTP 메서드와 무관하게 호출된다.

모두허용 GET, HEAD, POST, PUT, PATCH, DELETE

package hello.springmvc.basic.requestmapping;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MappingController {

    private Logger log = LoggerFactory.getLogger(getClass());

    @RequestMapping(value = "/hello-basic", method = RequestMethod.GET)
    public String helloBasic(){
        log.info("helloBasic");
        return "ok";
    }

}

Post로 보내면 오류(405)가 발생한다.

 

다음 코드를 보면

HTTP 메서드를 축약한 애노테이션을 사용하는 것이 더 직관적이라는 것을 알 수 있다.

@GetMapping(value = "/mapping-get-v2")
    public String mappingGetV2() {
        log.info("mapping-get-v2");
        return "ok";
    }

 

PathVariable(경로 변수) 사용

  @GetMapping("/mapping/{userId}")
    public String mappingPath(@PathVariable("userId") String data){
        log.info("mappingPath userId={}", data);
        return "ok";
    }

최근 HTTP API는 다음과 같이 리소스 경로에 식별자를 넣는 스타일을 선호한다.

/mapping/userA

/user/1

 

@RequestMapping은 URL 경로를 템플릿화 할 수 있는데, @PathVariable을 사용하면 매칭 되는 부분을 

편리하게 조회할 수 있다.

 

@PathVariable의 이름과 파라미터 이름이 같으면 생략할 수 있다.

 

    @GetMapping("/mapping/users/{userId}/orders/{orderId}")
    public String mappingPath(@PathVariable String userId, @PathVariable Long
            orderId) {
        log.info("mappingPath userId={}, orderId={}", userId, orderId);
        return "ok";
    }

이런식으로 설계하는 것이 요즘 많이 쓰는 방식이라고 한다.

 

	@GetMapping(value = "/mapping-param", params = "mode=debug")
		public String mappingParam() {
 			log.info("mappingParam");
 			return "ok";
}

파라미터에 조건을 거는 방식 또한 있다.

파라미터로 mode=debug라는 것이 있어야 호출이 된다.

 

@GetMapping(value = "/mapping-header", headers = "mode=debug")
public String mappingHeader() {
 log.info("mappingHeader");
 return "ok";
}

헤더에 또한 조건을 줄 수 있다.

 

@PostMapping(value = "/mapping-consume", consumes = "application/json")
public String mappingConsumes() {
 log.info("mappingConsumes");
 return "ok";
}

미디어 타입 역시 조건을 걸 수 있다. content-type기반

 

@PostMapping(value = "/mapping-produce", produces = "text/html")
public String mappingProduces() {
 log.info("mappingProduces");
 return "ok";
}

컨트롤러가 생산해내는 컨텐트 타입을 조건을 걸 수 도있다.

클라이언트의 요청 정보에 받아들일 수 있는 타입을 보고(Accept 헤더)를 기반으로 매핑한다.

로그에 대해서 간단히 알아보았다.

 

운영 시스템에서는 System.out.println()같은 시스템 콘솔을 사용해서 필요한 정보를 출력하지 않고,

별도의 로깅 라이브러리를 사용해서 로그를 출력한다.

그렇기에 최소한의 사용방법을 숙지하기 위해 공부하였다.

 

로깅 라이브러리

스프링 부트 라이브러리를 사용하면 스프링 부트 로깅 라이브러리가 함께 포함된다.

스프링 부트 로깅 라이브러리는 기본으로 다음 로깅 라이브러리를 사용한다.

SLF4J - www.slf4j.org  

 

SLF4J

Simple Logging Facade for Java (SLF4J) The Simple Logging Facade for Java (SLF4J) serves as a simple facade or abstraction for various logging frameworks (e.g. java.util.logging, logback, log4j) allowing the end user to plug in the desired logging framewor

www.slf4j.org

Logback - http://logback.qos.ch 

 

Logback Home

Logback Project Logback is intended as a successor to the popular log4j project, picking up where log4j 1.x leaves off. Logback's architecture is quite generic so as to apply under different circumstances. At present time, logback is divided into three mod

logback.qos.ch

 

로그 라이브러리는 Logbak, Log4J, Log4J2 등등 수 많은 라이브러리가 있는데, 그것을 통합해서

인터페이스로 제공하는 것이 바로 SLF4J 라이브러리다.

쉽게 이야기해서 SLF4J는 인터페이스이고, 그 구현체로 Logback 같은 로그 라이브러리를 선택하면 된다.

실무에서는 스프링 부트가 기본으로 제공하는 Logback을 대부분 사용한다.

 

로그 선언 

private Logger log = LoggerFactory.getLogger(getClass());

private static final Logger log = LoggerFactory.getLogger(Xxx.class)

@Slf4j : 롬복 사용 가능

 

로그 호출

log.info("hello")

System.out.pritnln("hello")

시스템 콘솔로 직접 출력하는 것 보다 로그를 사용하면 다음과 같은 장점이 있다. 실무에서는 항상 로그를 사용해야 한다.

 

package hello.springmvc.basic;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class LogTestController {

    private final Logger log = LoggerFactory.getLogger(getClass());

    @RequestMapping("/log-test")
    public String logTest(){
        String name = "Spring";

        log.trace("trace log={}", name);
        log.debug("debug log={}", name);
        log.info("info log = {}",name);
        log.warn("warn log={}",name);
        log.error("error log={}",name);

        return "ok";
    }
}

 

매핑 정보

@RestController

  @Controller는 반환 값이 String이면 뷰 이름으로 인식된다. 그래서 뷰를 찾고 뷰가 랜더링 된다.

  @RestController는 반환 값으로 뷰를 찾는 것이 아니라, HTTP 메시지 바디에 바로 입력한다.

  따라서 실행 결과로 ok메시지를 받을 수 있다. @ResponseBody와 관련이 있는데, 뒤에서 더 자세히 설명한다.

 

테스트

로그가 출력되는 포맷 확인

  시간, 로그 레벨, 프로세스  ID, 쓰레드 명, 클래스명, 로그 메시지

 

로그 레벨 설정을 변경해서 출력 결과를 보자

  LEVEL :  TRACE > DEBUG > INFO > WARN > ERROR

  개발 서버는 debug 출력

  운영 서버는 info 출력

 

@slf4j로 변경

#전체 로그 레벨 설정(기본 info)
logging.level.root=info
#hello.springmvc 패키지와 그 하위 로그 레벨 설정
logging.level.hello.springmvc=debug

 

올바른 로그 사용법

 

log.debug("data="+data) (사용 X)

  로그 출력 레벨을 info로 설정해도 해당 코드에 있는 "data="+data가 실제 실행이 되어 버린다.

  결과적으로 문자 더하기 연산이 발생한다.

 

log.debug("data={}", data) (사용 O)

  로그 출력 레벨을 info로 설정하면 아무일도 발생하지 않는다. 따라서 앞과 같은 의미없는 연산이 발생하지 않는다.

 

로그 사용시 장점

쓰레드 정보, 클래스 이름 같은 부가 정보를 함께 볼 수 있고, 출력 모양을 조정할 수 있다.

로그 레벨에 따라 개발 서버에서는 모든 로그를 출력하고, 운영서버에서는 출력하지 않는 등 로그를 상황에 맞게 조절할 수 있다.

시스템 아웃 콘솔에서만 출력하는 것이 아니라, 파일이나 네트워크 등, 로그를 별도의 위치에 남길 수 있다.

  특히 파일로 남길때는 일별, 특정 용량에 따라 로그를 분할하는 것도 가능하다.

성능도 일반 System.out보다 좋다. 그래서 실무에서는 꼭 로그를 사용해야 한다.

 

'웹프로그래밍 > 스프링 MVC' 카테고리의 다른 글

40. 요청 매핑 - API 예시  (0) 2022.04.03
39. 요청 매핑  (0) 2022.04.03
37. 프로젝트 생성  (0) 2022.04.02
36. 스프링 MVC - 실용적인 방식  (0) 2022.04.01
35 스프링 MVC - 컨트롤러 통합  (0) 2022.04.01

지금부터 본격적으로 스프링MVC가 제공하는 기본기능을 자세히 공부할 예정이다.

 

start.spring.io

에 접속하여 java11 - jar - gradle project

dependencies : Spring Web, Thymeleaf, Lombok

을 기본설정으로하여 새로운 프로젝트를 생성하였다.

 

이전에는 War로 했었는데 JSP를 사용하지않을 예정이기 때문에 Jar를 선택했다.

항상 내장서버를 사용하고, webapp 경로도 사용하지 않고 내장 서버 사용에

최적화 되어 있는 기능이기때문에 최근에는 주로 이 방식을 선택한다고 한다.

'웹프로그래밍 > 스프링 MVC' 카테고리의 다른 글

39. 요청 매핑  (0) 2022.04.03
38. 로깅 간단히 알아보기  (0) 2022.04.02
36. 스프링 MVC - 실용적인 방식  (0) 2022.04.01
35 스프링 MVC - 컨트롤러 통합  (0) 2022.04.01
34. 스프링 MVC - 시작하기  (0) 2022.04.01

 MVC 프레임워크를 만들때  ModelView를 개발자가 직접 생성해서 반환했기 때문에

v4를 만들어 실용적으로 개선했었다.

 

스프링 MVC는 개발자가 편리하게 개발할 수 있도록 수 많은 편의 기능을 제공한다.

실무에서 주로 쓰는 방식을 공부하였다.

package hello.servlet.web.springmvc.v3;

import hello.servlet.domain.member.Member;
import hello.servlet.domain.member.MemberRepository;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@Controller
@RequestMapping("springmvc/v3/members")
public class SpringMemberControllerV3 {

    private MemberRepository memberRepository = MemberRepository.getInstance();

    @GetMapping("/new-form")
    public String newForm(){
        return "new-form";
    }

    @GetMapping
    public String members(Model model) {
        List<Member> members = memberRepository.findAll();
        model.addAttribute("members",members);

        return "members";
    }

    @PostMapping("/save")
    public String save(
            @RequestParam("username") String username,
            @RequestParam("age")int age,
            Model model) {

        Member member = new Member(username,age);
        memberRepository.save(member);

        model.addAttribute("member",member);
        return "save-result";
    }
}

어마어마한 놀라움을 겪었다..

 

Model 파라미터

save(), members()를 보면 Model을 파라미터로 받는 것을 확인할 수 있다.

스프링 MVC도 이런 편의 기능을 제공한다.

 

ViewName 직접 반환

뷰의 논리 이름을 반환할 수 있다.

 

@RequestParam 사용

스프링은 HTTP 요청 파라미터를 @RequestParam으로 받을 수 있다.

@RequestParam("uesrname)은 request.getParameter("username)와 같은 코드라고 생각하면 된다.

물론 GET 쿼리 파라미터, POST Form방식을 모두 지원한다.

 

@RequestMapping -> @GetMapping , @PostMapping

@RequestMapping 은 URL만 매칭하는 것이 아니라, HTTP Method도 함께 구분할 수 있다. 예를 들어서 URL이 /new-form 이고, HTTP Method가 GET인 경우를 모두 만족하는 매핑을 하려면 다음과 같이 처리하면 된다.

@RequestMapping(value = "/new-form", method = RequestMethod.GET)

이것을 @GetMapping , @PostMapping 으로 더 편리하게 사용할 수 있다.

 

 

 

'웹프로그래밍 > 스프링 MVC' 카테고리의 다른 글

38. 로깅 간단히 알아보기  (0) 2022.04.02
37. 프로젝트 생성  (0) 2022.04.02
35 스프링 MVC - 컨트롤러 통합  (0) 2022.04.01
34. 스프링 MVC - 시작하기  (0) 2022.04.01
33. 뷰 리졸버  (0) 2022.03.31

@RequestMapping을 잘 보면 클래스 단위가 아니라 메서드 단위에 적용된 것을 확인할 수 있다.

따라서 컨트롤러 클래스를 유연하게 하나로 통합할 수 있다. 

 

package hello.servlet.web.springmvc.v2;

import hello.servlet.domain.member.Member;
import hello.servlet.domain.member.MemberRepository;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;

@Controller
public class SpringMemberControllerV2 {

    private MemberRepository memberRepository = MemberRepository.getInstance();

    @RequestMapping("/springmvc/v2/members/new-form")
    public ModelAndView newForm(){
        return new ModelAndView("new-form");
    }

    @RequestMapping("/springmvc/v2/members")
    public ModelAndView members() {
        List<Member> members = memberRepository.findAll();
        ModelAndView mv = new ModelAndView("members");
        mv.addObject("members",members);

        return mv;
    }

    @RequestMapping("/springmvc/v2/members/save")
    public ModelAndView save(HttpServletRequest request, HttpServletResponse response) {
        String username = request.getParameter("username");
        int age = Integer.parseInt(request.getParameter("age"));

        Member member = new Member(username,age);
        memberRepository.save(member);

        ModelAndView mv = new ModelAndView("save-result");
        mv.addObject("member",member);
        return mv;
    }
}

기존에 3개로 나눠졌던 클래스를 하나로 통합했다.

@RequestMapping은 메서드 단위에 적용하기 때문에 가능하다.

package hello.servlet.web.springmvc.v2;

import hello.servlet.domain.member.Member;
import hello.servlet.domain.member.MemberRepository;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;

@Controller
@RequestMapping("springmvc/v2/members")
public class SpringMemberControllerV2 {

    private MemberRepository memberRepository = MemberRepository.getInstance();

    @RequestMapping("/new-form")
    public ModelAndView newForm(){
        return new ModelAndView("new-form");
    }

    @RequestMapping
    public ModelAndView members() {
        List<Member> members = memberRepository.findAll();
        ModelAndView mv = new ModelAndView("members");
        mv.addObject("members",members);

        return mv;
    }

    @RequestMapping("/save")
    public ModelAndView save(HttpServletRequest request, HttpServletResponse response) {
        String username = request.getParameter("username");
        int age = Integer.parseInt(request.getParameter("age"));

        Member member = new Member(username,age);
        memberRepository.save(member);

        ModelAndView mv = new ModelAndView("save-result");
        mv.addObject("member",member);
        return mv;
    }
}

메서드 3개 모두 @RequestMapping에 중복되는 부분이 있었다.

이것을 클래스 레벨의 @RequestMapping에 입력하면 

클래스 + 메서드의 조합이 가능하게 된다.

'웹프로그래밍 > 스프링 MVC' 카테고리의 다른 글

37. 프로젝트 생성  (0) 2022.04.02
36. 스프링 MVC - 실용적인 방식  (0) 2022.04.01
34. 스프링 MVC - 시작하기  (0) 2022.04.01
33. 뷰 리졸버  (0) 2022.03.31
32. 핸들러 매핑과 핸들러 어댑터  (0) 2022.03.31

+ Recent posts