요청의 파라미터를 연결할 매개변수에 붙이는 애너테이션
✔️ @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]
: 적용 대상을 Model의 속성으로 자동추가(자동저장)해주는 애너테이션
✔️ 반환 타입 또는 컨트롤러 메서드의 매개변수에 적용 가능
✔️ @ModelAttribute("키")와 같이 키를 적어주어야하지만 생략할 시 첫번째 타입의 앞글자를 소문자로 한 key 자동생성
ex. Mydate date -> mydate
@RequestMapping("/getYoilMVC5")
// public String main(@ModelAttribute("myDate") 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";
}
private @ModelAttribute("yoil") char getYoil(MyDate date) {
return getYoil(date.getYear(), date.getMonth(),date.getDay());
}
타입변환, 데이터검증 -> 결과&에러 BindingResult에 저장
✔️ 컨트롤러 메서드 바로 뒤에 작성해야 함
✅ autofocus: 페이지 로드 시 자동으로 input요소로 focus(커서)
✅ onsubmit: form 전송 전에 입력된 데이터의 유효성 체크 이벤트, true 전송/false 전송X
✅ <c:url>: Context root 자동추가, Seesion id 자동추가
/ch2/register/save (=) <c:url value="/register/save"/>
✅ GET/POST: < form action="/ch2/registerInfo.jsp" method="GET/POST">
GET(default)
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>
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();
}
}
✅ spring 4.3부터 사용 가능, Maven 업데이트
✅ url이 같으면 충돌나지만 method가 다르면 같아도 충돌X
✅ 매핑할 url 공통부분을 @requestMapping으로 클래스에 적용
// 매핑할 url 공통부분을 @requestMapping으로 클래스에 적용
// register/add or register/save
@RequestMapping("register")
public class RegisterController {
@GetMapping("/add")
public String register() {}
@PostMapping("/save")
public String save(@ModelAttribute("user") User user, Model m) throws Exception {}
}
@RequestMapping(value="/register/add", method={RequestMethod.GET, RequestMethod.POST})
@GetMapping("/register/add")
@GetMapping("/register/add")
public String register() {
return"registerForm"; // WEB-INF/views/registerForm.jsp
}
<mvc:view-controller path="/register/add" view-name="registerForm">
@RequestMapping(value="/register/save", method=RequestMethod.POST)
@PostMapping("/register/save")
@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";
}
✔️ URL에 포함된 non-ASCII문자를 문자코드(16진수) ↔ 문자열 변환
✔️ ≠Base64(바이너리→text 변환)
✔️ 300 Redirect: 다른 URL로 재요청
✔️ 요청이 2번이며 각 요청은 서로 다른 객체, 응답 2번
✔️ 첫번째 요청은 수동 GET/POST, 두번째 요청은 자동 GET
✔️ 재요청하므로 주소가 자동으로 변경
✔️ 클라이언트가 보낸 요청을 다음 jsp로 그대로 전달, 두번 request할 필요 없음
✔️ 재요청하지 않으므로 주소가 변경되지 않음
✔️ redirect로 응답할 때 RedirectView를 통해 응답헤더 생성
💻client --(/ch/register/save 요청)--> 📃DispatcherServlet
---> 🕹️Controller --(redirect:/register/add)--> 📃DispatcherServlet
---> 📑RedirectView 응답헤더생성 --(응답)-->💻client
✔️ 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
✔️ 내부적 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
참고) 자바의 정석 | 남궁성과 끝까지 간다