포스트

Day94 java프로그래밍 기초(Spring web MVC)

1.페이지 컨트롤러 만드는 방법

1)RequestMapping

  • Dispatcher Servlet(프론트 컨트롤러)가 페이지 컨트롤러를 찾기위해 붙이는 에노테이션이다.
  • 컨트롤러에 URL을 매핑하여 설정한다.
  • URL당 한개의 핸들러에만 연결할 수 있다.
  • 한개의 request handler에 여러개의 URL을 매핑 할 수 있다.
  • requestMapping이 붙은 메서드를 요청핸들러 라고한다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    
    @Controller
    @RequestMapping("/c01_3") // 핸들러에 적용될 기본 URL을 지정한다.
    public class Controller01_3 {
      
      @RequestMapping("h1") // 기본 URL에 뒤에 붙는 상세 URL. 예) /c01_3/h1
      @ResponseBody
      public String handler() {
        return "h1";
      }
      
      @RequestMapping("/h2") // 앞에 /를 붙여도 되고 생략해도 된다. 예) /c01_3/h2
      @ResponseBody
      public String handler2() {
        return "h2";
      }
      
      @RequestMapping("h3") //
      @ResponseBody
      public String handler3() {
        return "h3";
      }
      
      @RequestMapping("h4")
      @ResponseBody
      public String handler4() {
        return "h4";
      }
      
      @RequestMapping({"h5", "h6", "h7"})
      @ResponseBody
      public String handler5() {
        return "h5,h6,h7";
      }
    }
    

2. RequestMapping 구분하기

  • 프론트 컨트롤에서서 요청이 들어오면 RequestMapping에 따라 요청핸들러가 결정되며, 요청매핑의 설정에 따라 결정된다.
  • RequestMapping : 모든 HTTP 요청에 대해 요청핸들러를 호출한다.
  • GetMapping : 요청메서드가 GET요청일때 요청핸들러를 호출한다.
  • PostMapping : 요청매서드가 POST요청일때 요청핸들러를 호출한다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    
    @Controller
    @RequestMapping("/c02_2")
    public class Controller02_2 {
      
      // 테스트 방법:
      // => http://localhost:9999/eomcs-spring-webmvc/html/app1/c02_2.html
      
      @GetMapping // GET 요청일 때만 호출된다.
      @ResponseBody
      public String handler1() {
        return "get";
      }
      
      @PostMapping // POST 요청일 때만 호출된다.
      @ResponseBody
      public String handler2() {
        return "post";
      }
      
      @RequestMapping({RequestMethod.GET, RequestMethod.HEAD}) // GET과 HEAD요청일 때만 호출된다.
      @ResponseBody
      public String handler1() {
        System.out.println("handler1() 호출됨!");
        return "get";
      }
    }
    

3. 요청핸들러를 구분하는 방법

1)params

  • GET요청에서 QueryString에 담긴 parmeter정보를 통해 매핑을 할 수 있다.
  • Params의 항목으로 중복되어 Mapping을 하는 경우 에러가 발생한다.
    • url?name=kim&age=20으로 들어왓는데 mapping이 mapping(name),mapping(age)로 된경우 요청핸들러 호출이 모호해진다.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    
    @Controller
    @RequestMapping("/c03_1")
    public class Controller03_1 {
      @GetMapping(params = "name")
      @ResponseBody
      public String handler1() {
        return "handler1";
      }
        
      @GetMapping(params = "age")
      @ResponseBody
      public String handler2() {
        return "handler2";
      }
        
      // => 만약 이 요청 핸들러가 없다면, queryString에 name과 age가 동시에 들어오는 경우 에러발생
      @GetMapping(params = {"age", "name"})
      @ResponseBody
      public String handler3() {
        return "handler3";
      }
        
      @GetMapping
      @ResponseBody
      public String handler4() {
        return "handler4";
      }
    }
      
    

2)headers

  • 요청헤더 중에서 특정 이름을 갖는 헤더가 있을 때, 요청핸들러를 지정할수 있다.
  • JS같은 프로그래밍으로 임의의 HTTP요청을 할때 헤더를 추가할 수 있다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    
      @Controller
      @RequestMapping("/c03_2")
      public class Controller03_2 {
        // @GetMapping(headers = "name")
        @RequestMapping(method = RequestMethod.GET, headers = "name")
        @ResponseBody
        public String handler1() {
          return "handler1";
        }
        
        // @GetMapping(headers="age")
        @RequestMapping(method = RequestMethod.GET, headers = "age")
        @ResponseBody
        public String handler2() {
          return "handler2";
        }
        
        @GetMapping(headers = {"age", "name"})
        @ResponseBody
        public String handler3() {
          return "handler3";
        }
        
        @GetMapping
        @ResponseBody
        public String handler4() {
          return "handler4";
        }
      }
    

3)produces

  • Accept헤더 : client에서 서버에 요청할때 받고자 하는 콘텐트의 타입을 알려주는 헤더
  • produces설정을 통해 제공 받는 콘텐트 타입의 종류를 설정할 수 있다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    
    @Controller
    @RequestMapping("/c03_3")
    public class Controller03_3 {
     
      @GetMapping(produces = "text/plain")
      @ResponseBody
      public String handler1() {
        return "handler1";
      }
      
      @GetMapping(produces = "text/html")
      @ResponseBody
      public String handler2() {
        return "handler2";
      }
      
      @GetMapping(produces = "application/json")
      @ResponseBody
      public String handler3() {
        return "handler3";
      }
      
      @GetMapping
      @ResponseBody
      public String handler4() {
        return "handler4";
      }
    }
    

4)consumes

  • Content-Type : 클라이언트가 서버에 보내는 데이터 타입니다.
  • consumes 설정을 통해 서버가 받는 타입에 따라 매핑 설정이 가능하다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    
    @Controller
    @RequestMapping("/c03_4")
    public class Controller03_4 {
      // 다음 메서드는 application/x-www-form-urlencoded 형식의 데이터를 소비한다.
      // => 즉 클라이언트의 HTTP 요청에서 Content-Type 헤더의 값이 위와 같을 때
      //    이 메서드를 호출하라는 의미다.
      @PostMapping(consumes = "application/x-www-form-urlencoded")
      @ResponseBody
      public String handler1() {
        return "handler1";
      }
      
      // 다음 메서드는 multipart/form-data 형식의 데이터를 소비한다.
      @PostMapping(consumes = "multipart/form-data")
      @ResponseBody
      public String handler2() {
        return "handler2";
      }
      
      // 다음 메서드는 text/csv 형식의 데이터를 소비한다.
      @PostMapping(consumes = "text/csv")
      @ResponseBody
      public String handler3() {
        return "handler3";
      }
      
      // 다음 메서드는 application/json 형식의 데이터를 소비한다.
      @PostMapping(consumes = "application/json")
      @ResponseBody
      public String handler4() {
        return "handler4";
      }
      
      // 다음 메서드는 Content-Type 헤더가 없을 때 호출된다.
      @RequestMapping
      @ResponseBody
      public String handler5() {
        return "handler5";
      }
    }
    

4. 요청핸들러의 아규먼트

1) 프로트 컨트롤러에서 받는 아규먼트

  • 프론트컨트롤러에서 기본적으로 받을 수 있는 아규먼트는 다음과 같다.
    • ServletRequest, ServletResponse
    • HttpServletRequest, HttpServletResponse, HttpSession
    • Map, Model
    • PrintWriter
  • ServletContext는 의존 객체로 주입 받아야 한다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    
    @Controller
    @RequestMapping("/c04_1")
    public class Controller04_1 {
      // ServletContext는 의존 객체로 주입 받아야 한다.
      // 요청 핸들러에서 파라미터로 받을 수 없다.
      @Autowired
      ServletContext sc;
      
      // 요청 핸들러에서 받을 수 있는 타입의 아규먼트를 선언해 보자!
      @GetMapping("h1")
      @ResponseBody
      public void handler1(
          // ServletContext sc,
          // ServletContext는 파라미터로 받을 수 없다. 예외 발생!
          // 의존 객체로 주입 받아야 한다.
          ServletRequest request,
          ServletResponse response,
          HttpServletRequest request2,
          HttpServletResponse response2,
          HttpSession session,
          Map<String, Object> map, // JSP에 전달할 값을 담는 임시 보관소
          Model model, // Map과 같다. 둘 중 한 개만 받으면 된다.
          PrintWriter out // 클라이언트에게 콘텐트를 보낼 때 사용할 출력 스트림
          ) {
      }
    }
    

2) RequestParam

  • 클라이언트가 보낸 파라미터를 아규먼트로 사용 할 수 있다.
  • GET요청에서는 quertyString에서 param을 받는다.
  • POST요청에서는 URL 쿼리 스트링 또는 application/x-www-form-urlencoded 형식으로 전송되어야 한다.
  • 요청 파라미터 이름과 메서드 파라미터(아규먼트)의 이름이 같다면 애노테이션을 생략해도 된다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    
    @Controller
    @RequestMapping("/c04_2")
    public class Controller04_2 {
      @GetMapping("h1")
      @ResponseBody
      public void handler1(
          PrintWriter out,
          ServletRequest request,
          @RequestParam(value = "name") String name1,
          @RequestParam(name = "name") String name2, // value와 name은 같은 일을 한다.
          @RequestParam("name") String name3, // value 이름을 생략할 수 있다.
          /* @RequestParam("name") */ String name // 생략가능
          ) {
      }
      
      @GetMapping("h2")
      @ResponseBody
      public void handler2(
          PrintWriter out,
          @RequestParam("name1") String name1, // 애노테이션을 붙이면 필수 항목으로 간주한다.
          // 따라서 파라미터 값이 없으면 예외가 발생한다.
      
          String name2, // 애노테이션을 붙이지 않으면 선택 항목으로 간주한다.
          // 따라서 파라미터 값이 없으면 null을 받는다.
      
          @RequestParam(value = "name3", required = false) String name3,
          // required 프로퍼티를 false로 설정하면 선택 항목으로 간주한다.
      
          @RequestParam(value = "name4", defaultValue = "ohora") String name4
          // 기본 값을 지정하면 파라미터 값이 없어도 된다.
          ) {
      }
    }
    

3) 도메인 객체로 요청 파라미터 값 받기

  • 클라이언트가 보낸 요청 파라미터 값을 값 객체에 받을 수 있다.
  • 프론트 컨트롤러는 매서드를 호출 할 때 객체의 인스턴스를 생성한후, 요청 파라미터와 일치하는 프로퍼티에 대해 값을 저장한다.
  • 값 객체 안에 또 값 객체가 있을 때는 OGNL(ex. 내부객체클래스.프로퍼티명) 방식으로 요청 파라미터 값을 지정한다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    
    @Controller
    @RequestMapping("/c04_3")
    public class Controller04_3 {
      @GetMapping(value = "h1", produces = "text/plain;charset=UTF-8")
      @ResponseBody
      public String handler1(
          String model, String maker,
          @RequestParam(defaultValue = "100") int capacity, // 프론트 컨트롤러가 String 값을 int로 변환해 준다.
          // 단 변환할 수 없을 경우 예외가 발생한다.
          
          boolean auto,
          // 프론트 컨트롤러가 String 값을 boolean으로 변환해 준다.
          // 단 변환할 수 없을 경우 예외가 발생한다.
          // "true", "false"는 대소문자 구분없이 true, false로 변환해 준다.
          // 1 ==> true, 0 ==> false 로 변환해 준다. 그 외 숫자는 예외 발생!
      
          Car car
      ) {
        return String.format("model=%s\n", model) + String.format("maker=%s\n", maker)
            + String.format("capacity=%s\n", capacity) + String.format("auto=%s\n", auto)
            + String.format("car=%s\n", car);
      }
    }
    

4) 프로퍼티 에디터 추가하기

  • primitive type의 아규먼트는 자동으로 형변환을 해주지만, 그렇지 않은 경우는 에디터를 추가 해야한다.
  • @InitBinder : 에디터는 Request Handler를 호출하기 전에 에디터를 설정해야하기 때문에 이 애노테이션을 통해 프론트컨트롤에 알려준다.
  • 에디터 등록 : WebDataBinder.registerCustomEditor(class, new PropertyEditor())을 통해 등록한다.
  • PropertyEditor : 객체는 PropertyEditorSupport를 상속받아 setAsText메서드를 통해 커스텀한다.
  • request handler의 아규먼트 개수 만큼 이 메서드를 호출한다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    
    @Controller
    @RequestMapping("/c04_4")
    public class Controller04_4 {
      @GetMapping("h1")
      @ResponseBody
      public void handler1(
          PrintWriter out, String model,
          @RequestParam(defaultValue = "5") int capacity,
          boolean auto,
          Date createdDate // 프로퍼티 에디터를 설정하지 않으면 변환 오류 발생
        ) {    }
        
      @GetMapping("h2")
      @ResponseBody
      public void handler2(PrintWriter out,
          // 콤마(,)로 구분된 문자열을 Car 객체로 변환하기?
          // => String ===> Car 프로퍼티 에디터를 등록하면 된다.
          @RequestParam("car") Car car
        ) {    }
    
      @InitBinder
      public void initBinder(WebDataBinder binder) {
        System.out.println("Controller04_4.initBinder()...");
        binder.registerCustomEditor(java.util.Date.class ,new DatePropertyEditor());
        binder.registerCustomEditor(Car.class, new CarPropertyEditor());
      }
        
      class DatePropertyEditor extends PropertyEditorSupport {
        @Override
        public void setAsText(String text) throws IllegalArgumentException {
          try {
            setValue(java.sql.Date.valueOf(text));
          } catch (Exception e) {
            throw new IllegalArgumentException(e);
          }
        }
      }
    
      class CarPropertyEditor extends PropertyEditorSupport {
        @Override
        public void setAsText(String text) throws IllegalArgumentException {
          String[] values = text.split(",");
      
          Car car = new Car();
          car.setModel(values[0]);
          car.setCapacity(Integer.parseInt(values[1]));
          car.setAuto(Boolean.parseBoolean(values[2]));
          car.setCreatedDate(java.sql.Date.valueOf(values[3]));
      
          setValue(car);
        }
      }
    }
    

5) 글로벌 프로퍼티 에디터 추가하기

  • InitBinder를 별도의 클래스에서 관리하며 모든 페이지 컨트롤러에 에디터를 사용한다.
  • @ControllerAdvice 에노테이션을 사용한다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    
    @ControllerAdvice
    public class GlobalControllerAdvice {
      @InitBinder
      public void initBinder(WebDataBinder binder) {
        binder.registerCustomEditor(class, new PropertyEditor());
      }
      
      class PropertyEditor extends PropertyEditorSupport {
        @Override
        public void setAsText(String text) throws IllegalArgumentException {
          try {
           //커스텀 
            setValue(/*커스텀 내용*/text);
          } catch (Exception e) {
            throw new IllegalArgumentException(e);
          }
        }
      }
    }
    

6) 요청핸들러의 아규먼트

  • 클라이언트의 HTTP 요청 헤더를 받고 싶으면request handler의 아규먼트 앞에 @RequestHeader(헤더명) 애노테이션을 붙이면 된다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    
    @Controller
    @RequestMapping("/c04_6")
    public class Controller04_6 {
      @GetMapping("h1")
      @ResponseBody
      public void handler1(
          PrintWriter out,
          @RequestHeader("Accept") String accept,
          @RequestHeader("User-Agent") String userAgent) {
      
        out.printf("Accept=%s\n", accept);
        out.printf("User-Agent=%s\n", userAgent);
      
        if (userAgent.matches(".*Edg.*")) {
          out.println("Edge");
        } else if (userAgent.matches(".*Chrome.*")) {
          out.println("chrome");
        } else if (userAgent.matches(".*Safari.*")) {
          out.println("safari");
        } else if (userAgent.matches(".*Firefox.*")) {
          out.println("firefox");
        } else {
          out.println("etc");
        }
      }
    }
    

7) 요청핸들러의 쿠키

  • @CookieValue(쿠키명) 애노테이션을 request handler의 아규먼트 앞에 붙인다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    
    @Controller
    @RequestMapping("/c04_7")
    public class Controller04_7 {
      @GetMapping("h1")
      @ResponseBody
      public void handler1(PrintWriter out, HttpServletResponse response) {
        // 이 메서드에서 쿠키를 클라이언트로 보낸다.
        try {
          // 쿠키의 값이 ASCII가 아니라면 URL 인코딩 해야만 데이터가 깨지지 않는다.
          // URL 인코딩을 하지 않으면 ? 문자로 변환된다.
          response.addCookie(new Cookie("name1", "AB가각"));
          response.addCookie(new Cookie("name2", URLEncoder.encode("AB가각", "UTF-8")));
          response.addCookie(new Cookie("name3", "HongKildong"));
          response.addCookie(new Cookie("age", "30"));
        } catch (Exception e) {
          e.printStackTrace();
        }
        out.println("send cookie!");
      }
      @GetMapping(value = "h2", produces = "text/plain;charset=UTF-8")
      @ResponseBody
      public String handler2(@CookieValue(value = "name1", required = false) String name1,
          @CookieValue(value = "name2", defaultValue = "") String name2,
          @CookieValue(value = "name3", defaultValue = "홍길동") String name3,
          @CookieValue(value = "age", defaultValue = "0") int age // String ===> int 자동 변환
      ) throws Exception {
        String namex = new String(originBytes, "UTF-8");
        return String.format(//
            "name1=%s\n name2=%s\n name2=%s\n name3=%s\n age=%d\n", //
            name1, name2, namex, name3, age);
      }
    }
    

5. 요청핸들러의 리턴값

1) ResponseBody

  • 리턴 값이 클라이언트에게 보내는 콘텐트라면 메서드 선언부에 @ResponseBody를 붙인다.
  • 리턴되는 콘텐트의 MIME 타입과 charset을 지정하고 싶다면 애노테이션의 produces 프로퍼티에 설정하라.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    
    @Controller
    @RequestMapping("/c05_1")
    public class Controller05_1 {
      @GetMapping("h1")
      @ResponseBody
      public String handler1() {
        return "<html><body><h1>abc가각간</h1></body></html>";
      }
        
      @GetMapping(value = "h2", produces = "text/html;charset=UTF-8")
      @ResponseBody
      public String handler2() {
        return "<html><body><h1>abc가각간<h1></body></html>";
      }
        
      @GetMapping("h3")
      @ResponseBody
      public String handler3(HttpServletResponse response) {
      
        // HttpServletResponse에 대해 다음과 같이 콘텐트 타입을 설정해봐야 소용없다.
        response.setContentType("text/html;charset=UTF-8");
        return "<html><body><h1>abc가각간<h1></body></html>";
      }
      
      @GetMapping("h4")
      public HttpEntity<String> handler4(HttpServletResponse response) {
        // HttpEntity 객체에 콘텐트를 담아 리턴할 수 있다.
        // 이 경우에는 리턴 타입으로 콘텐트임을 알 수 있기 때문에
        // @ResponseBody 애노테이션을 붙이지 않아도 된다.
      
        HttpEntity<String> entity = new HttpEntity<>(
            "<html><body><h1>abc가각간<h1></body></html>");
        return entity;
      }
      
      @GetMapping(value = "h5", produces = "text/html;charset=UTF-8")
      public HttpEntity<String> handler5(HttpServletResponse response) {
        // 한글을 제대로 출력하고 싶으면 위 애노테이션의 produces 속성에 콘텐트 타입을 지정한다.
        HttpEntity<String> entity = new HttpEntity<>(
            "<html><body><h1>abc가각간<h1></body></html>");
      
        return entity;
      }
        
      @GetMapping("h6")
      public HttpEntity<String> handler6(HttpServletResponse response) {
        // 한글을 제대로 출력하고 싶으면,
        // 응답 헤더에 직접 Content-Type을 설정할 수 있다.
      
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Type", "text/html;charset=UTF-8");
        HttpEntity<String> entity = new HttpEntity<>(
            "<html><body><h1>abc가각간<h1></body></html>",
            headers);
        return entity;
      }
        
      @GetMapping("h7")
      public ResponseEntity<String> handler7(HttpServletResponse response) {
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Type", "text/html;charset=UTF-8");
        headers.add("BIT-OK", "ohora");
      
        ResponseEntity<String> entity = new ResponseEntity<>(
            "<html><body><h1>abc가각간<h1></body></html>",
            headers,
            HttpStatus.OK // 응답 상태 코드를 설정할 수 있다.
            );
      
        return entity;
      }
    }
    

2) view 컴포넌트(JSP) 쪽에 데이터 전달하기

  • JSP가 꺼내 쓸 수 있도록 ServletRequest 객체에 직접 담는다.
  • 맵 객체에 값을 담아 놓으면 프론트 컨트롤러가 JSP를 실행하기 전에 ServletRequest로 복사한다.
  • 아규먼트에 Model 타입의 변수를 선언하면 프론트 컨트롤러는 모델 객체를 만들어 넘겨준다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    
    @Controller
    @RequestMapping("/c05_3")
    public class Controller05_3 {
      @GetMapping("h1")
      public String handler1(ServletRequest request) {
      
        request.setAttribute("name", "홍길동");
        request.setAttribute("age", 20); // auto-boxing: int ===> Integer 객체
        request.setAttribute("working", true); // auto-boxing: boolean ===> Boolean 객체
      
        return "/WEB-INF/jsp/c05_3.jsp";
      }
        
      @GetMapping("h2")
      public String handler2(Map<String,Object> map) {
      
        map.put("name", "홍길동");
        map.put("age", 20); // auto-boxing
        map.put("working", true); // auto-boxing
      
        return "/WEB-INF/jsp/c05_3.jsp";
      }
        
      @GetMapping("h3")
      public String handler3(Model model) {
          
        model.addAttribute("name", "홍길동");
        model.addAttribute("age", 20); // auto-boxing
        model.addAttribute("working", true); // auto-boxing
      
        return "/WEB-INF/jsp/c05_3.jsp";
      }
        
      @GetMapping("h4")
      public ModelAndView handler4() {
          
        ModelAndView mv = new ModelAndView();
          
        mv.addObject("name", "홍길동");
        mv.addObject("age", 20); // auto-boxing
        mv.addObject("working", true); // auto-boxing
      
        mv.setViewName("/WEB-INF/jsp/c05_3.jsp");
      
        return mv;
      }
    }
    
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.