Spring-Day08

JUNHO YEOM·2023년 3월 2일
0

Spring

목록 보기
13/14

RequestMapping에 대해서 알아봐요

@RequestMapping(value="URL", option, option)

consumes: Client에게 request를 제한하는 용도로 사용해요
Client의 header정보(Content-Type)를 토대로 제한하게 됩니다.

Data를 보내는 방식
GET 방식: url뒤에 query string으로 실어 보내는 방식
POST 방식: request body안에 들어가요

consumes를 사용하면 GET방식은 사용할 수 없어요.
Get방식은 header에 query-string으로 data가 전달되기 때문에 header의 Content-Type이 없어요
Content-type은 data가 body에 담길경우에 설정할 수 있는 header이기 때문이에요


POST를 통해서 request를 보내줬어요
기본적인 Content-type은
application/x-www-form-urlencoded였어요
내가 허락해줄 Content-type은 application/json타입 뿐이었으니까 415 error를 response했어요

이렇게 request를 제한하는 comsumes는 어떨 때 사용할까?

RESTful 방식으로 서버를 설계하기 위해서 사용해요
Content-type: application/json등으로 Content type을 제한해서 Ajax요청으로 request를 받을 수 있게 할수 있으니까 좋아요


Request는 원래...

보통의 request는 특별한 경우가 아닌 이상 요청을 제한하는 경우가 거의 없어요.
요청을 제한하는 경우보다 요청을 처리한 다음 서버에서 데이터를 전달할 때 해당 data가 일반적인 html, json, xml인지를 정해주는 경우가 많아요.
response의 header에 data type을 정해서 알려줘요


MIME Type

data 형식에 따라 정해져 있는 데이터의 형식을 문자로 표현한 문자열


produces

클라이언트에게 반환(return)하는 data의 Content type을 지정하는 역할을 합니다.
브라우저는 Data가 어떤 형식이 올지 모르니까 결과에 대한 Data형식을 파악하고 이 형식으로 Data를 적절히 처리하는 일이 필요합니다.

return 하는 data의 Content type을 지정하는(알려주는) 것이지 명시한 Data의 형식으로 data를 변환해주는 역할을 하지는 않아요!


외부 라이브러리를 Bean으로 등록하는 방법(수동)

Gson을 사용하면서 받아왔는데 이건 외부 Library이고, Stateless하니까 Bean으로 등록해서 사용해 줄꺼에요

package를 생성해 줍니다.

common

class를 생성해 줍니다.

LibraryComponent.java

Application Context가 스캔할 수 있도록 인식시켜줘야 해요
@Configuration을 사용해줘요

// 수동으로 Bean을 Application Context에 등록하려면. 
// @Bean이라는 Annotation을 이용해야 해요
@Configuration // @Component의 하위 속성이에요
public class LibraryComponent {

}

등록하려는 Library(Gson)을 Bean으로 등록해줘요

// 수동으로 Bean을 Application Context에 등록하려면. 
// @Bean이라는 Annotation을 이용해야 해요
@Configuration // @Component의 하위 속성이에요
public class LibraryComponent {
	
	@Bean
	public Gson getGson() {
		return new Gson();
	}
}
// 메서드의 이름 getGson이 Bean id로 등록 됩니다.

RequestMapingProducesController

@Controller
public class RequestMapingProducesController {

	Logger log = LogManager.getLogger("case3");
	
	@Autowired
	private Gson gson;
	@RequestMapping(value = "testProduces4", produces = "application/json; charset=UTF-8")
	public void method04(HttpServletResponse response) {
		try {
			response.setContentType("application/json; charset=UTF-8");
			PrintWriter out = response.getWriter();

			// 데이터를 만들어요
			Map<String, String> map = new HashMap<String, String>();
			map.put("userName","홍길동");
			map.put("userAge","20");
			map.put("userAddr","서울");
			
			// 이 데이터를 JSON 문자열로 변형해야 해요
			String str = gson.toJson(map);
			
			// 그리고 나서 Stream을 통해 client에게 보내주면 됩니다.
			out.println(str);
			out.close();
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}
	

Bean을 수동으로 등록해주었습니다.

Bean을 수동으로 등록해 주었을 때의 장점

  1. 외부 Library(Gson같은)를 Bean으로 등록해서 효율적으로 사용이 가능
  2. program의 크기가 커지고 자주 기능이 변경되는 경우
    interface를 기반으로 구현클래스를 수동으로 등록해서 전략패턴을 활용할 수 있습니다.

Autowired를 사용하지 않고 Application Context를 직접 사용하는 방법

Autowired를 사용하지 않는 방법이에용
Spring에서 우리에게 interface를 제공 해줘요
ApplicationContextAware
구현한 구현체를 Bean으로 등록해야 해요

class를 만들어 줄꺼에요

ApplicationContextProvider.java

@Component
public class ApplicationContextProvider implements ApplicationContextAware {

	private static ApplicationContext ctx;
	
	public static ApplicationContext getApplicationContext() {
		return ctx;
	}
	
	// Spring이 관리하는 ApplicationContext가 인자로 들어오는것을 볼 수 있어요
	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		this.ctx = applicationContext;
	}
}

등록한 부분을 사용해주는 부분

@RequestMapping(value = "testProduces4_1", produces = "application/json; charset=UTF-8")
	public void method04_1(HttpServletResponse response) {
		try {
			response.setContentType("application/json; charset=UTF-8");
			PrintWriter out = response.getWriter();

			// 데이터를 만들어요
			Map<String, String> map = new HashMap<String, String>();
			map.put("userName","홍길동");
			map.put("userAge","20");
			map.put("userAddr","서울");
			
			// 이 데이터를 JSON 문자열로 변형해야 해요
//			String str = gson.toJson(map);
			ApplicationContext ctx = ApplicationContextProvider.getApplicationContext();
			Gson gson = ctx.getBean("getGson", Gson.class);
			String str = gson.toJson(map);
			// 그리고 나서 Stream을 통해 client에게 보내주면 됩니다.
			out.println(str);
			out.close();
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}

Produces 어떤 의미가 있나요?

@RequestBody와 결합해서 사용해요

Http의 기본 통신 방식
request를 보내고 Response를 받는 아주 단순한 구조에요

HttpRequest
1. Start Line: 어떤 Method를 사용하는지 알려줘요
방식: POST
URL: /springweb/aka
Http version: Http/1.1

  1. Headers: data의 형식 등의 정보를 알려줘요

  2. Body(Request Body): 실제 전송하는 data

HttpResponse
1. Status Line :
상태 코드: 어떤 상태로 요청이 처리되었는지 응답하는 코드 값
2. headers
3. body(Response Body)

Spring은 Request Body, Response Body를 구현합니다.
저기에 Data를 어떻게 넣을 것인지 컨트롤 해 줄 수 있어요

Request Body

Request Body를 이용하면 Spring에서 Client가 Request를 보낼때 Post 방식으로 Json을 줘요.
Json방식의 Request Body를 통해서 Vo로 바로 변환할 수 있어요.(제약사항이 있어서 많이 사용되지는 않아요)

Response Body

Response에 대한 정보를 내가 직접 만들어서 넣어줄 수 있어서 많이 사용되어요.
XML, Json data를 넣어서 보낼 수 있어요
Ajax구현할 때 이렇게 사용해요!
Body부분에 내가 직접 데이터를 넣을 때는 어떤 데이터를 넣는지 내가 직접 명시를 해야해요 그래서 Produces가 필요한거에용!!!


이제는 Controller가 2가지로 나뉘어요
Rest 기반의 API : 결과 Data만 보내주는 방식
기존 방식: JSP를 보내주는 방식

일반적인 경우(JSP 파일 이용)

request를 Dispatcher Servlet이 받아서 처리해요
Dispatcher Servlet(Front Controller)

Dispacther Servlet-> Handler Mapping -> Controller


Internet 물리적 platform 뒤에 www(web)이라는 Service를 활용

  1. SOAP 기반의 web Service
    (Simple Object Access Protocol)
    이 프로토콜을 이용하면 보안, 데이터 무결성의 장점이 있어요
    protocol 자체가 복잡한 단점이 있어요
    Web의 CS구조와 잘 맞지 않아요
    일반적인 Enterprise Application에 사용되어요

  2. HTTP 기반의 Web Service
    web의 구조와 잘 맞아서 지금도 사용되고 있습니다.
    HTTP protocol의 개발자중의 한명이 protocol을 잘 사용할 수 있는 방식의 Guide를 제시하였습니다.
    Architecture => REST


REST(Representational State Transfer)

HTTP, Web을 조금 더 잘 사용하기 위한 Architecture

구성요소

  1. Resource(자원) : 서버에 존재하는 사용 가능한 것들(file, image, 문서, program) "ID가 부여"되어요
    /springweb/counter -> URI
    /springweb/resources/sample07/index.html -> URI(Uniform Resource Identifier)

URI(Uniform Resource Identifier): 식별자
URL(Uniform Resource Locater): 위치를 식별하기 위한것

  1. 행위(HTTP의 Method로 행위를 표현) : HTTP 메서드에 의미가 부여 됩니다.
  • GET : 자원의 조회
  • POST : 자원의 생성
  • PUT : 자원의 수정
  • DELETE : 자원의 삭제
  1. 표현(Representation)
    서버가 처리를 끝내면 적절한 응답을 보내요
  • plain/text
  • plain/html
  • application/json
  • application/xml
    여러 형태로 응답을 보낼 수 있어요

REST API 디자인 가이드

  1. URI는 Resources를 표현하는 수단이어야 합니다.
    예시 - 멤버 삭제
    GET /member/delete/3 - 이건 잘못된 형태에요(동작을 지칭하면 안됩니다)
    DELETE /member/3 - 이런식으로 하나의 리소스를 지칭해야 해요

  2. URI의 마지막은 '/'로 끝나지 않아요

  • /member/3/ ( X )
  • /member/3 ( O )
  1. 특수문자는 URI에 사용하면 안됩니다.
    /member/student_score ( X ) 언더바는 사용하지 않습니다
    /member/student-score ( O ) '-'을 사용합니다.

  2. 소문자로 URI를 작성합니다.

  3. 확장자는 URI에 포함하지 않습니다.
    /member/flower.gif ( X ) 확장자 Accept-hader에 명시


REST의 응답

REST 원칙에 따라 서버는 Client에게 상태정보를 보내야 해요
(ex: 200, 201, 404)

REST의 인증

  1. HTTP 인증 -> 데이터 암호화 시켜서 base64 혹은 128비트로 암호화
  2. key-base -> 서버가 Client에게 key 발급, request 마다 key 포함
  3. OAuth 인증 -> 복잡한 인증 Process

@RestController
@RequestMapping(value = "/rest/user")
public class MyRestController {
	
	Logger log = LogManager.getLogger("case3");
	
	@GetMapping
	public ResponseEntity<?> method01(String id, String name){
		log.debug("GET 방식으로 호출 되었어요 ");
		log.debug("id={}",id);
		log.debug("name={}",name);
		// 값이 제대로 들어와요
		return null;
	}
	
	@DeleteMapping
	public ResponseEntity<?> method02(String id, String name){
		log.debug("DELETE 방식으로 호출 되었어요 ");
		log.debug("id={}",id);
		log.debug("name={}",name);
		// null 이에요
		// Data가 Body안에 들어간채로 들어와요
		// Body안에 있는 Data를 꺼내는 것을 파싱이라고 하는데 파싱을 톰켓이 알아서 해줘요
		// POST는 TOMCAT이 파싱을 잘해주는데
		// DELETE, PUT은 TOMCAT이 파싱을 안해줘요
		return null;
	}
	// 해결방법
	// 1. 톰캣 설정 바꾸기
	// 2. 
	
}

Server-> Tomcat -> server.xml

64번째줄

<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>

변환하기

<Connector connectionTimeout="20000" port="8080"
    	parseBodyMethods="POST, PUT, DELETE" protocol="HTTP/1.1" redirectPort="8443"/>

parseBodyMethods="POST, PUT, DELETE"추가된 부분

0개의 댓글