본문 바로가기

JAVA

Java & SpringBoot로 시작하는 웹 프로그래밍 : 자바 인강 - 6주차

  • 관심사의 분리와 MVC패턴 - 원리
  • 서블릿과 JSP
  • @RequestParam과 @ModelAttribute

 

Spring이 내부적으로 어떤 일을 하길래 매개변수로 적어주기만 하면 알아서 처리해주는지의 원리를 단계별로 알아보기

 

 

1) MethodInfo.java 실습

MethodInfo.java

package com.fastcampus.ch2;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.StringJoiner;

public class MethodInfo {
	public static void main(String[] args) throws Exception{

		Class clazz = Class.forName("com.fastcampus.ch2.YoilTeller");
		Object obj = clazz.newInstance();
		
		Method[] methodArr = clazz.getDeclaredMethods();
		
		for(Method m : methodArr) {
			String name = m.getName();
			Parameter[] paramArr = m.getParameters();
//			Class[] paramTypeArr = m.getParameterTypes();
			Class returnType = m.getReturnType();
			
			StringJoiner paramList = new StringJoiner(", ", "(", ")");
			
			for(Parameter param : paramArr) {
				String paramName = param.getName();
				Class  paramType = param.getType();
				
				paramList.add(paramType.getName() + " " + paramName);
			}
			
			System.out.printf("%s %s%s%n", returnType.getName(), name, paramList);
		}
	} // main
}

yoilTeller라는 클래스의 객체를 만들고 

 

결과

매개변수 이름이 arg0, arg1 인 모습

원래 request, response인데 바껴있는 이유는 이 YoilTeller클래스를 컴파일할 때 매개변수 이름은

별로 중요한 정보가 아니여서 저장하지 않는다.

매개변수 이름을 저장하고 싶은 경우 컴파일 옵션에 javac -parameters를 줘야한다.

-parameters : 매개변수 이름 저장 옵션

 

-parameters 설정 방법

preferences - compiler - Store information about method parameters 체크 (자바 1.8 부터 지원)

 

그래도 지금 1.6으로 돌아가는 상태라 매개변수 이름이 안나올 때

targer - pom.xml 더블클릭



 

핑크색 부분 바꾸기

 

버전을 바꾼 후에는 업데이트 프로젝트를 해줘야한다 !

우리가 사용하는 MVC 프로젝트는 Maven을 이용해서 관리한다.

pom.xml 파일은 Maven 설정 파일 

 

다시 결과

매개변수 이름 request, response 로 잘 나온 모습

 

 

 

매개변수 이름을 Spring에 얻는 방법

1. Reflection API를 이용 : -parameters 옵션을 넣고 컴파일 (Java8, Jdk 1.8 부터 가능)

2. Class 파일을 직접 읽기 

현재 쓰는 Package Explorer은 소스파일 중심이라 클래스 파일 보기 힘들어 새로운 View 열어보기

Window - Show View - Others - navi 검색

Open 누르기

소스 파일과 클래스 파일이 전부 나온다.

src 소스 파일에는 *.java 파일들이 있고

target 타겟 파일에는 *.class 파일들이 있다.

 

클래스 파일의 내용을 해석해서 보여준다.

class 파일 우클릭 - Open With - Class File Viewer 로 보여 준 것이다.

 

맨 아래 Local Variable table에 request, response 매개변수 이름이 있는 모습을 볼 수 있다.

이거를 읽어서 알아내는 방법도 있다.

 

 

다른 클래스의 메소드 출력해보기 - YoilTellerMVC가 가지고 있는 메소드 목록 출력해보기

MethodInfo.java에서 YoilTellerMVC로 바꾸기

 

메소드가 3개인 모습을 볼 수 있다.

 

 

2) MethodCall.java 실습

MethodCall.java

package com.fastcampus.ch2;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Set;

class ModelController {
	public String main(HashMap map) {
		// 작업 결과를 맵에 저장
		map.put("id", "asdf");
		map.put("pwd", "1111");
		
		return "txtView2"; // 뷰 이름을 반환
	}
}

public class MethodCall {
	public static void main(String[] args) throws Exception{
		HashMap map = new HashMap();
		System.out.println("before:"+map);

		ModelController mc = new ModelController();
		String viewName = mc.main(map);
		
		System.out.println("after :"+map);
		
		render(map, viewName);
	}
	
	static void render(HashMap map, String viewName) throws IOException {
		String result = "";
		
		// 1. 뷰의 내용을 한줄씩 읽어서 하나의 문자열로 만든다.
		Scanner sc = new Scanner(new File(viewName+".txt"));
		
		while(sc.hasNextLine())
			result += sc.nextLine()+ System.lineSeparator();
		
		// 2. map에 담긴 key를 하나씩 읽어서 template의 ${key}를 value바꾼다.
		Iterator it = map.keySet().iterator();
		
		while(it.hasNext()) {
			String key = (String)it.next();

			// 3. replace()로 key를 value 치환한다.
			result = result.replace("${"+key+"}", (String)map.get(key));
		}
		
		// 4.렌더링 결과를 출력한다.
		System.out.println(result);
	}
}

이 코드에서 ModelController 클래스는 진짜 Controller은 아닌데 Controller처럼 행동

맵을 선언하면 메인메소드에서 맵을 생성하여 넘겨줌

그 맵은 결과에 저장하고 뷰이름을 반환

 

txtView1.txt 파일 만들기 - ch2 우클릭 - New - File - txtView1.txt 입력 후 

id:${id}

pwd:${pwd} 붙여넣기

- txtView1.txt 파일 복사해서 txtView2.txt 파일 붙여넣고

id=${id}, pwd=${pwd} 로 수정

 

실행시

before은 맵을 생성하자마자는 비어있는데

ModelController의 main메소드 호출 후 맵을 출력하니 맵의 값이 채워졌다.

그 후 render 메소드 호출하니 맵에 있는 데이터를 viewName에 결과를 뿌려 콘솔에 출력함

 

jsp도 마찬가지로 View를 여러개 만들어 놓고 View 이름을 다르게 반환하면 

그 View에 맞게 값을 채워서 결과를 보여준다.

 

 


 

서블릿과 JSP

1. 서블릿과 컨트롤러의 비교

JSP ≒ 서블릿 거의 유사 → Spring (서블릿을 발전시킨 것)

 

TowDice @Controller을 TwoDiceServlet으로 바꾼 것

main 메소드를 service 메소드로 바꾼 것, 안의 내용은 똑같다.

 

@WebServlet = @Controller + @RequestMapping

 

service 메소드는 고정으로 매개변수로 response, request가 들어가야한다.

Controller가 여러가지 면에서 발전된 모습 (상속 안받기, 매개변수 필요한거만 적기,

하나의 클래스안에 새로운 클래스만 만들면 매핑 가능 등등)

 

 

2. 서블릿의 생명 주기

서블릿은 기본적으로 3개의 메소드

  • init 메소드 : 처음에 서블릿이 생성될 때 서블릿 초기화를 위해 쓰임
  • service 메소드 : 실제 작업 처리를 위해 쓰임
  • destroy 메소드 : 서블릿이 메모리에서 제거될 때 호출되는 메소드

 

오버라이드 하는 방법 : Source - Override/Implement Methods..

3개 체크하기

 

HelloServlet.java 코드 

package com.fastcampus.ch2;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/hello")
public class HelloServlet extends HttpServlet{

	@Override
	public void init() throws ServletException {
		// 서블릿이 초기화될 때 자동으로 호출되는 메소드
		// 1. 서블릿의 초기화 작업 담당
		System.out.println("[HelloServlet] init() is called."); // 언제 호출되는지 보기
	}
	
	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// 1. 입력
		// 2. 처리
		// 3. 출력
		System.out.println("[HelloServlet] service() is called.");
	}

	@Override
	public void destroy() {
		// 3. 뒷정리 - 서블릿이 메모리에서 제거될 때 서블릿 컨테이너에 의해서 자동 호출
		System.out.println("[HelloServlet] destroy() is called.");
	}
}

 

http://localhost:8080/ch2/hello 입력시 결과

init(), service() 메소드가 잘 호출된 모습

 

브라우저 새로고침으로 여러번 호출해보기

init 메소드는 더이상 호출되지 않고 service메소드만 계속 호출되는 모습

 

 

서블릿 : Singleton 싱글톤

한 개의 객체(인스턴스)만 만들어진다.

서블릿이나 스프링이나 하나의 객체만 만들어 요청을 처리

요청이 올 때마다 인스턴스 객체를 새로 만드는 것이 아니라 1개의 인스턴스만 만들어 계속 재활용

인스턴스가 존재하는지 확인하고 있으면 그것만 쓰는 것

이유 : 요청할 때마다 처리해야될 작업들이 대부분 똑같다.

 

 

3. JSP(Java Server Pages)란?

HTML 안에 자바 코드가 있는 것

JSP ≒ 서블릿 

JSP로 작성하면 JSP가 자동으로 서블릿으로 변환된다.

twoDice.jsp 페이지가 있을 때 <%   %> 안에 자바 코드를 넣고

<% 값 %>에 값 넣어 출력하면

html 부분은 자동으로 out. 으로 변하고

자바 코드service 메소드 안으로 자동으로 들어감

<%  %> 부분은 service 메소드가 아니라 클래스 안으로 들어간다.

 

JSP 페이지는 

src / main / webapp / twoDice.jsp 에 만들면 된다.

 

twoDice.jsp 코드

<%@ page contentType="text/html;charset=utf-8"%>
<%@ page import="java.util.Random" %>
<%-- <%! 클래스 영역 %> --%>
<%!  
	int getRandomInt(int range){
		return new Random().nextInt(range)+1;
	}
%>
<%-- <%  메서드 영역 - service()의 내부 %> --%>
<%
	int idx1 = getRandomInt(6);
	int idx2 = getRandomInt(6);
%>
<html>
<head>
	<title>twoDice.jsp</title>
</head>
<body>
	<img src='resources/img/dice<%=idx1%>.jpg'>
	<img src='resources/img/dice<%=idx2%>.jpg'>
</body>
</html>

 

결과

 

5. JSP의 호출 과정

JSP 파일이 언제 서블릿으로 변환되는지 보기

 

서블릿, Spring 둘 다 싱글톤 (하나의 객체를 가지고 반복해서 재사용)

초기화에서 차이가 있다

  • 서블릿 : lazy - init (늦은 초기화) : 요청이 올 때 객체를 만들고 초기화
  • Spring : early - init (빠른 초기화) : 요청이 오지않아도 미리 객체를 만들어놓음

 

7. JSP의 기본 객체

: 생성 없이 사용할 수 있는 객체

 

- service 메소드의 lv(지역 변수)로 선언되어 있는 것들

request : 요청 정보가 담겨있는 객체

response : 요청에 응답을 작성할 때 사용

session : HTTP session을 구현한 객체, 세션 정보 저장에 사용

pageContext : JSP 페이지의 context 정보 제공

application : Web Application 전체에서 공유하는 객체

config : JSP 페이지에 대한 설정 정보가 담긴 객체

out : 응답에 포함될 내용을 출력할 때 사용

page : JSP 객체 자신

exception : 예외 발생시 생성되는 예외 객체

 

 

8. 유효 범위 (scope)와 속성(attribute)

 

HTTP 프로토콜의 특징

: 상태 정보를 저장하지 않는다 (stateless) <=> stateful (상태 정보 저장)

 

HTTP 특징이 상태 정보를 저장하지 않기 때문에 저장소가 필요

이 저장소를 유효 범위에 따라 4개의 저장소를 제공

접근 범위, 생존 기간이 다른 4개의 저장소를 가지고 있다.

 

Key Value
속성1 속성값
속성2 속성값
... ...

저장소마다 Map을 하나씩 가지고있고 여기에 원하는 데이터를 저장하면 된다.

void setAttribute(String name, Object value) : 저장소에 쓰기 저장할 때 쓰는 메소드 

Object getAttribute(String name) : 저장소에 읽기 저장할 때 쓰는 메소드

void removeAttribute(String name): session 객체 부담 커서 잠깐 썼다 삭제할 때 쓰는 메소드

Enumeration getAttributeNames() : 저장된 모든 속성을 반환하여 보고 싶을 때 쓰는 메소드

 

 

 

저장소 종류

(1) pageContext 저장소

  • 같은 페이지 내에서만 접근 가능
  • 요청할 때마다 새로 초기화

 

(2) application 저장소

  • 접근 범위가 WebApp 전체에서 접근 가능
  • 전체에 딱 1개만 존재 <공통 저장소>
  • pageContext 코드에서 다 접근 가능

 

id, pwd 같은 경우 application 저장소에 저장하는 경우

전체에서 접근 가능하기 때문에 적절하지 않다.

그래서 제공되는 것이 session

 

 

(3) session 저장소

  • <개별 저장소>
  • 클라이언트 마다 1개씩 있다
  • session 객체가 어떤 사람건지 연결하는 것은 쿠키가 한다
  • 로그인 할 때 개별 저장소를 생성했다 로그아웃하면 제거
  • id, 장바구니 등 사용자만 사용할 수 있는 개별 정보를 담기 용이

사용자마다 1개씩 갖는 개별 저장소이기 때문에 

session은 사용자 개수 만큼 session 객체가 생기기 때문에 서버 부담이 제일 크다.

session에는 최소한의 데이터만 저장해야한다.

 

웹 프로그래밍이라는 것이 페이지들간의 이동과 데이터 전달인데

페이지들간의 데이터를 전달할 때 제일 쉬운게 session 저장소

하지만 메모리 부담이 큰 문제 그래서 request를 쓰는 것이 가장 좋다.

 

 

(4) request 저장소

  • request 객체가 맵을 가지고 있는 것
  • 요청할 때마다 하나씩 생기며 독립적이다. 

 

보통 요청이 하나의 JSP페이지가 담당하는데 request가 전달되면

페이지 안에서 request 객체를 사용할 수 있고 여기에 데이터도 저장 가능

 

요청, 응답이 한 JSP에서 끝나지 않고 

요청을 첫번째 JSP가 받았다가 응답을 안한 채로 

다른 JSP한테 request 객체를 넘겨줄 수가 있다.

 

forward : 첫번째 JSP가 다른 JSP 한테 request 객체 넘겨주는 것

 

정리

기본 객체 유효 범위 설명
pageContext JSP 페이지당 1개 EL ${} 때문에 쓰는거지 별 다른건 없음
request JSP 페이지당 1개인데 forward로 1개 이상 가능 foward를 통해 다른 페이지로 넘겨줄 수 있다
session 클라이언트마다 1개라 JSP페이지당 n개 데이터 전달은 편리하지만 사용자마자 1개씩 가져 서버 부담이 크다
application context 전체 (context 마다 1개) Web Application 시작부터 종료까지 존재, 어디서든 접근 가능

 

 

 

9. URL 패턴

URL패턴 : @WebServlet으로 서블릿을 URL에 맵핑할 때 사용

(@WebServlet은 서블릿에서 쓰는 애너테이션, 스프링에서는 @RequestMapping)

 

@WebServlet(urlPatterns={"/hello", "/hello/*"}, loadOnStartup = 1)

: URL 패턴은 배열로 여러개 등록해서 쓸 수 있다.

loadOnStartup 서블릿이 lazy init 늦은 초기화이기 때문에 미리 초기화를 하는 것

즉, 서블릿 초기화 전에 미리 만들어두기, 번호는 미리 초기화하는 서블릿 중에서 우선순위(곂쳐져도 됨)

@WebServlet("/hello") : URL 패턴이 한 개인 경우

 

 종류 (번호는 우선순위) URL pattern 설명
1. exact mapping /login/hello.do 정확히 일치하는 매칭되는 패턴이 URL 패턴, 우선순위 가장 높다
(ex) 매칭 URL : http://localhost/ch2/login/hello.do)
2. path mapping /login/* 경로 맵핑, /login/으로 시작하는 경로로 들어오면 이 URL 패턴이 등록된 서블릿이 처리
(ex) 매칭 URL : http://localhost/ch2/login/)
3. extension mapping *.do 확장자 맵핑, .do 라는 URL 패턴이 맵핑되어있는 서블릿이 처리
(ex) 매칭 URL : http://localhost/ch2/hi.do)
4. default mapping / 디폴트 맵핑, 모든 주소와 맵핑된다, 앞에서 매칭이 안될때만 맵핑
(ex) 매칭 URL : http://localhost/ch2/)

 

 

개별 설정 web.xml

Spring은 서버로 오는 모든 요청을 default에 연결되어 있는 DispatcherServlet이 받게 되어있다.

 

 

 

10. EL (Expression Language)

<%=값%> 대신 ${ 값 }을 쓰려고 사용

 

실습

webapp - new - other - JSP file

 

el.jsp

<%@ page contentType="text/html;charset=utf-8"%>
<%@ taglib prefix="c"   uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ page import="com.fastcampus.ch2.*" %>
<%
	Person person = new Person();
	request.setAttribute("person", person);
	request.setAttribute("name", "남궁성");   
	request.setAttribute("list", new java.util.ArrayList());	
%>
<html>  
<head>   
	<title>EL</title>   
</head>  
<body>   
person.getCar().getColor()=<%=person.getCar().getColor()%> <br>
person.getCar().getColor()=${person.getCar().getColor()} <br>
person.getCar().getColor()=${person.car.color} <br>    
name=<%=request.getAttribute("name")%> <br>   
name=${requestScope.name} <br>
name=${name} <br>
id=<%=request.getParameter("id")%> <br>
id=${pageContext.request.getParameter("id")} <br>
id=${param.id} <br>
"1"+1 = ${"1"+1} <br>
"1"+="1" = ${"1"+="1"} <br>
"2">1 = ${"2">1} <br>   
null = ${null}<br>
null+1 = ${null+1} <br>
null+null = ${null+null} <br>
"" + null = ${""+null} <br>   
""-1 = ${""-1} <br> 
empty null=${empty null} <br>
empty list=${empty list} <br>
null==0 = ${null==0} <br>
null eq 0 = ${null eq 0} <br>
name == "남궁성"=${name=="남궁성"} <br>
name != "남궁성"=${name!="남궁성"} <br>
name eq "남궁성"=${name eq "남궁성"} <br>  
name ne "남궁성"=${name ne "남궁성"} <br>  
name.equals("남궁성")=${name.equals("남궁성")} <br>   
</body>
</html>

Person.java

package com.fastcampus.ch2;

public class Person { 
	private Car car = new Car(); 
	public  Car getCar() { return car; }
}

Car.java

package com.fastcampus.ch2;

public class Car    { 
	private String color = "red"; 
	public String getColor() { return color; }
}

 

http://localhost:8080/ch2/el.jsp 입력 결과

EL에서는 lv 못쓰고 꼭 pageContext를 붙여줘야한다.

null = 인 이유는 EL은 null을 출력하지 않는다.

null이 계산할 때는 0으로 바뀐다.

EL은 "1"이 자동으로 숫자로 바뀐다.

그래서 11을 원할 때는 "1"+="1"으로 써야한다.

empty는 null인지 빈 컬렉션 배열인지 확인하고 맞다면 참

 

 

 

11. JSTL (JSP Standard Tag Library)

 

접두사 <c: JSTL의 core library를 쓰는 것

fmt는 형식화 출력할 때 쓰는 라이브러리

코드 추가해줘야함

<%@ taglib prefix = "c" uri="http:java.sun.com/jsp/jstl/core"%>

<%@ taglib prefix = "fmt" uri="http:java.sun.com/jsp/jstl/fmt"%>

 

jstl.jsp

<%@ page contentType="text/html;charset=utf-8"%>
<%@ taglib prefix="c"   uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<html>
<head>
	<title>JSTL</title>
</head>
<body>
<c:set var="to"   value="10"/>
<c:set var="arr"  value="10,20,30,40,50,60,70"/> 
<c:forEach var="i" begin="1" end="${to}">
	${i}
</c:forEach>
<br>
<c:if test="${not empty arr}">
	<c:forEach var="elem" items="${arr}" varStatus="status">
		${status.count}. arr[${status.index}]=${elem}<BR>
	</c:forEach>
</c:if>	
<c:if test="${param.msg != null}">
	msg=${param.msg} 
	msg=<c:out value="${param.msg}"/>
</c:if>
<br>
<c:if test="${param.msg == null}">메시지가 없습니다.<br></c:if>
<c:set var="age" value="${param.age}"/>
<c:choose>
	<c:when test="${age >= 19}">성인입니다.</c:when>
	<c:when test="${0 <= age && age < 19}">성인이 아닙니다.</c:when>
	<c:otherwise>값이 유효하지 않습니다.</c:otherwise>
</c:choose>
<br>
<c:set var="now" value="<%=new java.util.Date() %>"/>
Server time is <fmt:formatDate value="${now}" type="both" pattern="yyyy/MM/dd HH:mm:ss"/>	
</body>
</html>

 

 

http://localhost:8080/ch2/jstl.jsp 입력시 결과

EL은 lv 사용 불가능→ 저장소에 "to" 10을 key, value로 저장

item 배열에 있는 값을 하나씩 elem 배열에 넣는 것

"status"는 count(1~)와 Index(0~)를 가지고 있다

param.msg에 값을 넣지 않아 메세지가 없다고 떴음

<p> </p>가 태그인데 out을 사용하는 경우 태그로 해석하지 않음

 

 

 

12. Filter

Filter : 서블릿이 시작하기 전에 1.전처리, 2.후처리 코드가 중복적으로 들어가는데 중복 코드를 분리할 때 쓰는 것

로딩, 인코딩 변환시 사용

즉, 공통적인 요청 전처리와 응답 후처리에 사용

Filter는 보통 한 개인데 여러 개일 수도 있다.

 

AOP 개념과도 유사

 

PerformanceFilter

: Filter가 수행하는 시간을 측정하려고 만든 Filter

시작 시간을 측정 후 서블릭 호출한 다음

현재 시간 - 시작 시간으로 소요시간 알 수 있다.

 

 

Filter 수행 시간 측정해보는 실습

PerformanceFilter.java

package com.fastcampus.ch2;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;

// 필터를 적용할 요청의 패턴 지정 - 모든 요청에 필터를 적용.
@WebFilter(urlPatterns="/*")
public class PerformanceFilter implements Filter {
	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		// 초기화 작업
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		// 1. 전처리 작업
		long startTime = System.currentTimeMillis();

		// 2. 서블릿 또는 다음 필터를 호출
		chain.doFilter(request, response); 
		
		// 3. 후처리 작업
		System.out.print("["+((HttpServletRequest)request).getRequestURI()+"]");
		System.out.println(" 소요시간="+(System.currentTimeMillis()-startTime)+"ms");
	}

	@Override
	public void destroy() {
		// 정리 작업
	}

}

// 1. 전처리 작업 // 3. 후처리 작업 중 하나만 있어도 된다.

@WebFilter 애너테이션은 WebFilter을 등록하는 것

PerformanceFilter라는 클래스를 Filter로 등록하고

이 Filter을 적용할 대상을 (urlPatterns="/*")로 지정해줘야한다.

"/*"은 모든 요청에 대해서 Filter을 적용해라는 의미

 

 

http://localhost:8080/ch2/el.jsp 입력 후 여러번 새로고침 하고 로그를 본 결과

 

모든 요청에 대한 실행 시간이 출력된 모습

처음엔 jsp에 적용되느라 시간이 좀 걸렸지만 그 후는 시간이 짧아진 모습

 

 

 

@RequestParam과 @ModelAttribute

1. @RequestParam

요청할 때 넘어온 파라미터를 매개변수에 연결할 때 쓰는 애너테이션

 

public String main2(@RequestParam{name="year", required=false}String year) {

에서 @RequestParam{name="year", required=false} 부분 생략 가능!

 

public String main2(@RequestParam{name="year", required=false} String year) {

public String main2(@RequestParam String year) {

 

"year"은 파라미터 이름, required = false는 필수 여부

 

http://localhost/ch2/requestParam2 로 요청시 year을 적지 않아 year = null, 400번 클라이언트 에러 발생 (500은 서버 에러)

http://localhost/ch2/requestParam2?year 로 요청시 year = ""  빈 문자열이 입력됨

 

 

public String main8(@RequestParam(required=false) int year) {

의 경우 필수 입력이 아님요

http://localhost/ch2/requestParam2 로 year값을 안주면 500번 서버 에러 발생 

http://localhost/ch2/requestParam2?year 로 요청시

아무 것도 넣지 않으면 year에 Null 이 들어오고 int로 변환할 수 없음 그러면 400번 클라이언트 에러

 

int는 string과 달리 값을 변환 까지 해야하기 때문에 에러가 다른 것 

 

필수 입력이 아닐때는 @RequestParam(required=false, defaultValue="1")로 기본값을 줘야함

기본값을 준 경우

http://localhost/ch2/requestParam11 로 year값을 주지 않아도 year=1이 대입된다.

문자열1은 숫자로 변환 가능

필수입력이 아니라고 적은 경우 거기에는 반드시 기본값이 있어야한다.

아니면 required를 true로 주기