[Spring] 03. @RequestParam과 @ModelAttribute/@GetMapping, @PostMapping/redirect와 forward

Hyeongmin Jung·2023년 5월 2일

Spring

목록 보기
3/17

🐥 @RequestParam과 @ModelAttribute

  • 컨트롤러 매개변수
    ✅ @RequestParam: 타입이 기본형(int, char 등0), String일 때 생략가능
    ✅ @ModelAttribute: 타입이 참조형일 때는 생략가능

@RequestParam

요청의 파라미터를 연결할 매개변수에 붙이는 애너테이션
✔️ @RequestParam(name="year", required=false) 생략가능
✔️ name="파라미터 이름", required=필수여부(t/f)
✔️ defaultValue="기본값"

@RequestMapping("/requestParam2")
//public String main2(@RequestParam(name="year", required=false) String year) {   // 아래와 동일 
public String main2(String year) {   

✅ @RequestParam(name="year", required=false) String year:
http://localhost/ch2/requestParam2 ---->> year=null
http://localhost/ch2/requestParam2?year=
http://localhost/ch2/requestParam2?year ---->> year="" (빈문자열, null != "")

✅ @RequestParam(name="year", required=true) String year: year을 필수입력, 빈문자열은 에러X
🐦 필수입력의 경우 예외처리

@ExceptionHandler(Exception.class)
	public String catcher(Exception ex) {
 	    ex.printStackTrace(); // 에러 출력
		return "yoilError";
	}

✔️ year=null | [400 Bad Request java.lang.NumberFormatException] required=true이기 때문

✅ @RequestParam(name="year", required=false) int year: null이나 ""를 int로 변환할 수 없음
🐦 필수 입력이 아닐때는 defaultValue="기본값"
✔️ year=null | 서버 에러 [500 java.lang.IllegalStateException]
✔️ year="" | 클라이언트 에러 [400 Bad Request]

✅ @RequestParam(name="year", required=true) int year:
✔️ year=null | [400 Bad Request]
✔️ year="" | [400 Bad Request]

@ModelAttribute

: 적용 대상을 Model의 속성으로 자동추가(자동저장)해주는 애너테이션
✔️ 반환 타입 또는 컨트롤러 메서드의 매개변수에 적용 가능

✔️ @ModelAttribute("키")와 같이 키를 적어주어야하지만 생략할 시 첫번째 타입의 앞글자를 소문자로 한 key 자동생성
✔️ 컨트롤러 매개변수 생략가능
ex. @ModelAttribute("mydate") Mydate date
    @ModelAttribute Mydate date
    Mydate date
    ㄴ Mydate date -> mydate

  • @RequestParam : 기본형, String
    | 모델저장 필요없음 ${param.파라미터 이름}으로 참조가능
  • @ModelAttribute : 참조형

* 매개변수에 적용

@RequestMapping("/getYoilMVC5") 
//  public String main(@ModelAttribute("myDate") MyDate date, Model m) { // 아래와 동일
//  public String main(MyDate date, Model m) {
public String main(@ModelAttribute MyDate date, Model m) { // @ModelAttribute사용, 반환 타입은 String  
System.out.println("myDate="+date);

	// 1. 유효성 검사 
	if(!isValid(date))
		return "yoilError";
    	
	// 2. 처리
// char yoil = getYoil(date);

	// 3. Model에 작업한 결과를 저장 
	// @ModelAttribute 덕분에 MyDate를 저장안해도 됨. View로 자동 전달됨.
//  m.addAttribute("myDate", date);     	
//  m.addAttribute("yoil", yoil);        
        
    // 4. 작업 결과를 보여줄 뷰의 이름을 반환  
    return "yoil";
}

* 반환타입에 적용: 호출결과(return값)을 key에 대응되는 value에 저장

private @ModelAttribute("yoil") char getYoil(MyDate date) { 
	return getYoil(date.getYear(), date.getMonth(),date.getDay());
}

WebDataBinder

타입변환, 데이터검증 -> 결과&에러 BindingResult에 저장
데이터 오류 시 : org.springframework.validation.BindException
✔️ BindingResult는 바인딩할 개체 바로 뒤에 작성해야 함
ex. public String main(@ModelAttribute MyDate date, BindingResult result)

result=org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors
code=typeMismatch
field=day
msg=Failed to convert property value of type 'java.lang.String' to required type 'int' for property 'day'; nested exception is java.lang.NumberFormatException: For input string: "a"

@ExceptionHandler(Exception.class)
public String catcher(Exception ex, BindingResult result) {
	System.out.println("result="+result);
		
	FieldError error = result.getFieldError();
		
	System.out.println("code="+error.getCode());
	System.out.println("field="+error.getField());
	System.out.println("msg="+error.getDefaultMessage());
		
	return "yoilError";
}

🐤 회원가입 화면 작성

✅ placeholder : 입력필드 입력 전 기본값 출력
✅ autofocus: 페이지 로드 시 자동으로 input요소로 focus(커서)
✅ onsubmit: form 전송 전에 입력된 데이터의 유효성 체크 이벤트, true 전송/false 전송X
✅ element.select(): element 선택
✅ <c:url>: Context root 자동추가, Session id 자동추가
/ch2/register/save (=) <c:url value="/register/save"/>

✅ GET/POST: < form action="/ch2/registerInfo.jsp" method="GET/POST">

<!-- registerInfo.jsp -->
<h1>id=${param.id}</h1>
<h1>pwd=${param.pwd}</h1>
<h1>name=${param.name}</h1>
<h1>email=${param.email}</h1>
<h1>birth=${param.birth}</h1>
<!-- checkbox string 배열로 받아와서 출력 -->
<h1>sns=${paramValues.sns[0]} ${paramValues.sns[1]} ${paramValues.sns[2]}</h1>

form action="/ch2/registerInfo.jsp" method="POST"

<form action="<c:url value="/register/save"/>" method="post">

function formCheck(frm) {
	var msg ='';

	if(frm.id.value.length<3) {
		setMessage('id의 길이는 3이상이어야 합니다.', frm.id);
        return false;
    }
    return true;
}

function setMessage(msg, element){
    document.getElementById("msg").innerHTML = `<i class="fa fa-exclamation-circle"> ${msg}</i>`;
  
    /* 잘못 입력한 값 선택 */
    if(element) {
         element.select();
    }
}

🐥 @GetMapping, @PostMapping

✅ spring 4.3부터 사용 가능, Maven 업데이트
✅ url이 같으면 충돌나지만 method가 다르면 같아도 충돌X
✅ 매핑할 url 공통부분을 @requestMapping으로 클래스에 적용

// 매핑할 url 공통부분을 @requestMapping으로 클래스에 적용
// register/add  or register/save
@RequestMapping("register")  
public class RegisterController {
    // @RequestMapping("/add") 
	@GetMapping("/add") 
	public String register() {}
    
    // @RequestMapping(value="/save", method=RequestMethod.POST) 
	@PostMapping("/save")
    public String save(@ModelAttribute("user") User user, Model m) throws Exception {}
}

@GetMapping

@RequestMapping(value="/register/add", method={RequestMethod.GET, RequestMethod.POST})
// method 안쓰면 GET, POST 둘다 허용
( = ) @RequestMapping("/add")
( = ) @GetMapping("/register/add")

@GetMapping("/register/add")
public String register() { 
	return"registerForm"; // WEB-INF/views/registerForm.jsp
}
  • 메서드가 다른 기능없이 registerForm로 연결하여 신규회원가입 화면 보여주므로 registerController의GetMapping을 없애고 view-controller로 변경
    // @GetMapping("/add") String register()
    // public String register() {
    // return "registerForm"; }
    src > main > webapp > WEB-INF > spring > appServlet > servlet-context.xml

    <mvc:view-controller path="/register/add" view-name="registerForm">

@PostMapping

@RequestMapping(value="/register/save", method=RequestMethod.POST)
@PostMapping("/register/save")

// <div id="msg" class="msg"> ${URLDecoder.decode(param.msg, "utf-8")}</div> 
@PostMapping("/save")
public String save(@ModelAttribute("user") User user, Model m) throws Exception {
		
	if(!isValid(user)) {
		String msg = URLEncoder.encode("id를 잘못입력하셨습니다.","utf-8");
			 
		m.addAttribute("msg", msg);
		return "redirect:/register/add";
//		return "redirect:/register/add?msg="+msg; //url재작성(rewriting)
	}
		 
	return "registerInfo";
}	

private boolean isValid(User user) {
	return false;

@RequestMapping의 URL패턴

  • URL 패턴 : @WebServlet(서블릿) / @RequestMapping(스프링)

?는 한글자, *는 여러글자, **는 하위경로 포함 | 배열로 여러패턴 지정
exact mapping -> path mapping -> extension mapping

URL인코딩 - 퍼센트 인코딩

✔️ URL에 포함된 non-ASCII문자를 문자코드(16진수) ↔ 문자열 변환
✔️ ≠Base64(바이너리→text 변환)


🐣 redirect와 forward

redirect

✔️ 300 Redirect: 다른 URL로 재요청
✔️ 요청이 2번이며 각 요청은 서로 다른 객체, 응답 2번
✔️ 첫번째 요청은 수동 GET/POST, 두번째 요청은 자동 GET
✔️ 재요청하므로 주소가 자동으로 변경

forward

✔️ 클라이언트가 보낸 요청을 다음 jsp로 그대로 전달, 두번 request할 필요 없음
✔️ 재요청하지 않으므로 주소가 변경되지 않음

RedirectView

✔️ redirect로 응답할 때 RedirectView를 통해 응답헤더 생성
💻client --(/ch/register/save 요청)--> 📃DispatcherServlet
---> 🕹️Controller --(redirect:/register/add)--> 📃DispatcherServlet
---> 📑RedirectView 응답헤더생성 --(응답)-->💻client

JstlView

✔️ jsp 뷰 처리
✔️ InternalResourcViewResolver는 뷰 이름을 해석하여 jsp주소로 넘겨줌
💻client --(/ch/register/add 요청)--> 📃DispatcherServlet ---> 🕹️Controller
--(registerForm_뷰이름)--> 📃DispatcherServlet
--(registerForm)--> 📜InternalResourceViewResolver
--(/WEB-INF/views/registerForm.jsp)--> 📃DispatcherServlet
--(/WEB-INF/views/registerForm.jsp)--> 📑JstlView
--(데이터를 모델로 전달)--> registerForm.jsp --(응답)--> 💻client

InternalResourceView

✔️ 내부적 forwarding
💻client --(/ch/register/save 요청)--> 📃DispatcherServlet ---> 🕹️Controller
--(forward:/register/add)--> 📃DispatcherServlet
--(/register/add)--> InternalResourceView
--(registerForm)--> 📃DispatcherServlet

--(registerForm)--> 📜InternalResourceViewResolver
--(/WEB-INF/views/registerForm.jsp)--> 📃DispatcherServlet
--(/WEB-INF/views/registerForm.jsp)--> 📑JstlView
---> registerForm.jsp --(응답)--> 💻client

실습


참고) 자바의 정석 | 남궁성과 끝까지 간다

0개의 댓글