Spring day 05

유요한·2022년 11월 29일
1

Spring

목록 보기
7/15
post-thumbnail

스프링 MVC Controller의 특징

HttpServletRequest, HttpServletResponse를 거의 사용할 필요가 없이 기능 구현 다양한 타입의 파라미터 처리, 다양한 타입의 리턴 타입 사용 가능 Get방식, Post 방식 등 전송 방식에 대한 처리를 어노테이션으로 처리 가능 상속/인터페이스 방식 대신 어노테이션으로 간단하게 설정 가능


POSTMAN

postman은 이클립스에서 Spring을 만들 때 사용한다. 인텔리제이에서는 .http라는 방법이 있다.

API 개발을 보다 빠르고 쉽게 구현할 수 있도록 도와주는 테스트 결과를 공유하며 API개발의 생산성을 높여주는 플랫폼이고 여러 방식의 요청을 외부에서 보낼 수 있도록 도와주는 개발 툴이다. 만들면서 테스트하는 용도로 사용한다. 예를 들어, 스프링으로 ajax나 axios로 기능을 구현하고 그것이 제대로 돌아가는지 테스트하기 위해서 사용한다.

GET, POST 외에도 PUT, DELETE 등의 요청도 가능하다.

  • REST API 설계 개발, 테스팅을 할 수 있는 GUI툴로 개발 생산성을 높여주는 프로그램

  • 팀원들 간의 공유 가능

  • Query String이 포함된 GET방식 호출

  • JSON이 사용된 POST 방식 호출

  • Authorization을 이요한 oauth 요청

  • 계정 별로 API 사용에 대한 내용과 기록을 저장할 수 있습니다.

  • 테스트한 API의 입력 정보를 기록하고 저장할 수 있습니다. Save As... 클릭하기

  • 개발 중인 앱에 회원가입, 로그인, 로그아웃, 포스트 등을 구현하고 테스트 하기 위해서는 클라이언트가 필요합니다.

  • 클라이언트에서 특정 주소로 보내준 정보와 요청을 토대로 서버에 구현한 로직을 처리하기 위해서입니다. 예를 들어 회원가입이라면 localhost::PORT/api/user/register라는 라우터로 이메일, 비밀번호 등의 정보를 보냅니다.

  • 서버는 이 정보를 받아서 회원을 만들어 데이터베이스에 저장해야 합니다. 하지만 특정 주소로 정보를 보내줄 클라이언트(프론트 엔드)가 아직 개발되지 않았다면 포스트맨이라는 프로그램으로 쉽게 테스트 할 수 있습니다.

postman이 나온 이유

post의 경우 html 클라이언트에서 form, 버튼, 이벤트, 이벤트 등록, 등등등... 백엔드를 구현하기 전 우선 만들어져야 하는 것들이 있다. 그럼 백엔드가 프론트엔드가 구현되기를 기다려야하는 상황이 발생한다. => 이러한 불편함을 개선하기 위해 postman 탄생

POSTMAN 사용하면 좋은 점

  • postman은 가벼운 툴이다.

  • Rest API를 표현할 수 있다.

  • 협업할 때 팀원이 만든 url을 확인할 때 편리하다.

  • 인터페이스를 구축해 놓은 툴인 Postman 을 사용하게 되면 변수 및 환경, Request, 테스트 등 자유롭게 가능하고 테스트한 환경, 요청한 Request History 등 이 그대로 저장되어 시간과 장소에 구애받지 않고 나의 작업환경을 다시 쉽게 가져올 수 있다.

설치

https://www.postman.com/downloads/

사용법






Model이라는 데이터 전달자

Controller의 메서드를 작성할 때는 특별하게 Model이라는 타입을 파라미터로 지정할 수 있습니다. Model 객체는 JSP 컨트롤러에서 생성된 데이터를 담아서 전달하는 역할을 하는 존재입니다. 이를 이용해서 View로 전달해야 하는 데이터를 담아서 보낼 수 있습니다. 메서의 파라미터에 Model 타입이 지정된 경우에는 스프링은 특별하게 Model 타입의 객체를 만들어서 메서드에 주입하게 됩니다.

웹페이지 구조는 Request에 전달된 데이터를 가지고 필요하다면 추가적인 데이터를 생성해서 화면으로 전달하는 방식으로 동작합니다. Model의 경우는 파라미터로 전달된 데이터는 존재하지 않지만 화면에서 필요한 데이터를 전달하기 위해서 사용합니다.

스프링 MVC의 Controller는 기본적으로 Java Beans 규칙에 맞는 객체는 다시 화면으로 객체를 전달합니다. 좁은 의미에서 Java Beans의 규칙은 단순히 생성자가 없거나 빈 생성자를 가져야 하며, getter/setter를 가진 클래스의 객체들을 의미합니다.

SampleDTO

package com.example.domain;

import lombok.Data;

@Data
public class SampleDTO {
    private String name;
    private int age;
}

SampleDTO의 경우는 Java Bean 규칙에 맞기 때문에 자동으로 다시 화면까지 전달합니다. 전달될 때에는 클래스명의 앞글자는 소문자로 처리합니다. 반면에 기본 자료형의 경우는 파라미터로 선언하더라도 기본적으로 화면까지 전달되지는 않습니다.

SampleController

@GetMapping("/ex07")
    public String ex07(SampleDTO dto, int page) {
        log.info("dto : " + dto);
        log.info(("page : " + page));
        return "/sample/ex07";
    }

ex07.jsp

<%--
  Created by IntelliJ IDEA.
  User: user
  Date: 2022-12-21
  Time: 오후 4:57
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h2>SAMPLEDTO ${sampleDTO}</h2>
    <h2>page ${page}</h2>
</body>
</html>

서버를 실행하고 브라우저를 통해 localhost:10000/sample/ex07?name=aaa&age=11&page=9 같이 호출하면 화면에 SampleDTO만 전달된다.
int 타입으로 선언된 page는 전달되지 않습니다.

여기서 int를 화면에 보여주는 방법은 2개가 있습니다. 첫 번째는 Model model를 매개변수로 받아서 model.addAttribute("키", "값")로 model에 넣어줘서 보여주는 방법입니다.

package com.example.controller;

import org.springframework.stereotype.Component;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.example.domain.SampleDTO;

import lombok.extern.log4j.Log4j;

@Component
@RequestMapping("/sample/*")
@Log4j
public class SampleController {
//	@RequestMapping("")
//	public String basic() {
//		log.info("==========basic==========");
//		return "a";
//	}

	// 메소드명으로 찾는 것이 아니라
	// RequestMapping() 여기 가로 안에 써준 것을 찾는 것이다.
	@RequestMapping("basic1")
	public void basic2(int age) {
		log.info("=============basic1===========");
		log.info(age);
	}

	@GetMapping("basic")
	public void basicGet() {
		log.info("============Get방식으로 요청===========");
	}

	@PostMapping("basic")
	public void basicPost(int age) {
		log.info("=============Post방식으로 요청==========");
		log.info(age);
	}

	@RequestMapping(value = "basic2", method = {RequestMethod.GET, RequestMethod.POST})
	public void basic2() {
		log.info("===========get, post 방식으로 요청=================");
	}
	
	// Controller 파라미터 수집 방법
	
	// DTO 객체로 수집하기
	@GetMapping("ex01")
	public String ex01(SampleDTO dto, Model model) {
		log.info(dto);
		model.addAttribute("dto", dto);
		// WEB-INF/views/sample/ex01.jsp
		return "/sample/ex01";
	}
    	// 파라미터 명과 담을 변수명이 다른 경우 수집 방법
	@GetMapping("ex02")
	public String ex02(@RequestParam("data1")String name, @RequestParam("data2")int age, Model model) {
		model.addAttribute("name",name);
		model.addAttribute("age",age);
		return "sample/ex02";
	}
	
	// 파라미터가 같은 이름으로 여러개 날라오는 경우(ex : checkbox) 수집방법
	@GetMapping("ex03")
	public void ex03(@RequestParam("data")String[] datas, Model model) {
		model.addAttribute("datas", datas);
	}
	@GetMapping("ex04")
	public void ex04(@RequestParam("data")ArrayList<Integer> datas, Model model) {
		int sum = 0;
		for(int data : datas) {
			sum += data;
		}
		model.addAttribute("datas", datas);
		model.addAttribute("sum" , sum);
	}
}

여기서 @GetMapping("basic")은 파라미터로 받는 거라서 뒤에 /baisc만 붙으면 class에 붙은 어노테이션인 @RequestMapping("/sample/*)을 만나서 sample 뒤에 basic이 오는거면 이쪽으로 와진다. postman에서는 아래와 같이 해주면 된다.

@PostMapping 은 requestBody에 담겨서 보내지는 것이다. postman에서는 아래와 같은 창에서 해줘야한다.

@RequestMapping(value = "basic2", method = {RequestMethod.GET, RequestMethod.POST})은 GET, POST 모두 포함되는 것이다.

DTO 객체로 수집하기에서 처리한 것은 @GetMapping("ex01")에서 GET방식으로 되어 있는 ex01로 된 것을 받아오고 그것을 SampleDTO 만들어준것에 담는다. 하나하나 일일히 담으면 효율적이지 못하기 때문에 DTO에 포장에서 담는 것이다.


main/java에 com.example.controller패키지안에 SampleDTO를 만들어준다.

SampleDTO

package com.example.domain;

import lombok.Data;

@Data
public class SampleDTO {
    private String name;
    private int age;
}

이곳에 담아주는 것이다. 그러면 Model model은 무엇일까?
Model은 HashMap 형태를 갖고 있으며 key, value 값을 가지고 있습니다. 또한 addAttribute()와 같은 기능을 통해 모델에 원하는 속성과 그것에 대한 값을 주어 전달할 뷰에 데이터를 전달할 수 있습니다.

Spring에서 Controller의 메서드를 작성할때는 특별하게 Model이라는 타입을 파라미터로 지정할 수 있습니다. Model 객체는 JSP에 컨트롤러에서 생성된 데이터를 담아서 전달하는 역할을 하는 존재입니다. JSP와 같은 view로 전달해야하는 데이터를 담아서 보낼 수 있습니다. 메서드의 파라미터에 Model 타입이 지정된 경우에는 스프링은 특별하게 Model 타입의 객체를 만들어서 메서드에 주입하게 됩니다.

여기서는 Model을 사용하기 위해서 model이라는 매개변수를 받게 만들어주고 view에 데이터를 담아서 보내주기 위해서 model.addAttribute("dto", dto)를 써서 위에서 GET으로 받아온 파라미터를 담아준 dto를 model의 key에 담아줘서 return "/sample/ex01"로 view로 보내주는 것이다. 앞에 WEB-INF/views는 servlet-context에 prefix로 담겨져 있고 jsp는 servlet-context에 suffix로 담겨져 있기 때문에 또 써줄 필요가없다.

ex01

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>ex01</title>
</head>
<body>
    <h1>ex01</h1>
    <p>
        Model<br />
        name : ${dto.name } / age : ${dto.age}
    </p>
</body>
</html>

여기까지 해줬으면 GET방식으로 name과 age를 쓴다면 위에서 설명한 순서대로 데이터를 담아줘서 ex01.jsp에서 보여줄 것이다.


이런식으로 보내 주면 된다.

postman으로 테스트 해보면 이렇게 나온다.

하지만 각각 따로 해줘서 이름을 다르게 주는 경우도 있을 것이다. 그럴때는 아래와 같이 @RequestParam()으로 줘야한다.

@GetMapping("ex02")
    public String ex02(@RequestParam("data1") String name, @RequestParam("data2") int age, Model model) {
        model.addAttribute("name", name);
        model.addAttribute("age", age);
        return "sample/ex02";
    }

ex02

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>ex02</title>
</head>
<body>
	<h1>ex02</h1>
	<p>
		Model <br/>
		name : ${name} / age : ${age}
	</p>
</body>
</html>

배열로 파라미터를 받아오는 방법이다.

 @GetMapping("ex03")
    public void ex03(@RequestParam("data")String[] datas, Model model) {
        model.addAttribute("datas", datas);
    }

ex03

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>ex03</title>
</head>
<body>
	 <h1>ex03</h1>
      <p>
		<c:forEach items="${datas}" var="data">
			${data }<br/>
		</c:forEach>	
      </p>
</body>
</html>

이번에는 list로 받아오는 방법이다.

 @GetMapping("ex04")
    public void  ex04(@RequestParam("data")ArrayList<Integer> datas, Model model) {
        int sum = 0;
        for (int data : datas) {
            sum += data;
        }
        model.addAttribute("datas", datas);
        model.addAttribute("sum", sum);
    }

ex04

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>ex04</title>
</head>
<body>
	<h1>ex04</h1>
	<p>
		<c:forEach items="${datas }" var="data">
			${data } <br/>
		</c:forEach>
		총합 : ${sum}
	</p>
	
</body>
</html>

여기서 Controller에서 @RequsetMapping()에서 메소드 타입이 voidString으로 되어 있는게 있는데 차이점을 알아보고자 한다.

1. void
void와 같은경우는 mapping에 작성해놓은 주소의 view를 리턴한다.
위에서 mapping에 ex03, ex04가 되어 있으니 ex03, ex04가 리턴을 한것이다.

2. String
String은 mapping에 작성해놓은 주소와 상관없이 return에 작성된 주소의 view를 리턴한다.

메서드의 파라미터를 Model 타입으로 선언하게 되면 자동으로 스프링 MVC에서 Model 타입의 객체를 만들어 주기 때문에 개발자의 입장에서는 필요한 데이터를 담아주는 작업만으로 모든 작업이 완료됩니다. Model을 사용해야하는 경우는 주로 Controller에 전달된 데이터를 이용해서 추가적인 데이터를 가져와야 하는 상황입니다.

예를 들어 다음과 같은 경우들을 생각해 볼 수 있습니다.

  • 리스트 페이지 번호를 파라미터로 전달받고 실제 데이터를 View로 전달해야 하는 경우

  • 파라미터들에 대한 처리 후 결과를 전달해야 하는 경우


@ModelAttribute

두번째 방법입니다. @ModelAttribute는 강제로 전달받은 파라미터를 Model에 담아서 전달하도록 할 때 필요한 어노테이션입니다. @ModelAttribute가 걸린 파라미터는 타입에 관계없이 무조건 Model에 담아서 전달되므로, 파라미터로 전달된 데이터를 다시 화면에서 사용해야 할 경우 유용하게 사용합니다.

 @GetMapping("/ex09")
    public String ex09(SampleDTO dto, @ModelAttribute("page") int page) {
        log.info("dto : " +dto);
        log.info("page : " + page);
        return "/sample/ex09";
    }
profile
발전하기 위한 공부

0개의 댓글