스프링의 정석 : 남궁성과 끝까지 간다 스프링MVC
스프링MVC
Spring MVC
1. 들어가며
[Servlet -> JSP -> Spring] -> SpringBoot
Spring : STS3 , 인텔리제이(유료에서 지원 -> 웹,db지원)
SpringBoot : STS4, 인텔리제이(무료지원)
2. Http의 요청과 응답
http1.1 : Connection 하나당 하나의 요청
http2 : Connection 하나당 여러개 요청 가능, 응답은 Stream으로 주고 받음
3. web.xml 과 server.xml
web.xml => 애너테이션
server.xml => 포트, DB, 웹리소스참조경로, 이벤트리스너 설정
4. GET/ POST 요청 : GET은 공유에 유리(소용량) , POST는 보안에 유리(대용량)
5. MVC 패턴 => 관심사의 분리
M(데이터) View(출력) Controller(처리)
스프링MVC 구조 DispatcherServlet <=> InternalResoureView
JstlView
6. 서블릿과 JSP
7. @RequestParam과 @ModelAttribute
8. @RequestMapping
@Controller
public class YoilTellerMVC6 {
@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());
ex.printStackTrace();
return "yoilError";
}
@RequestMapping("/getYoilMVC6") // http://localhost/ch2/getYoilMVC6
// public String main(@ModelAttribute("myDate") MyDate date, Model model) { // 아래와 동일
public String main(MyDate date, BindingResult result) {
System.out.println("result="+result);
// 1. 유효성 검사
if(!isValid(date))
return "yoilError"; // 유효하지 않으면, /WEB-INF/views/yoilError.jsp로 이동
// 2. 처리
// char yoil = getYoil(date);
// 3. Model에 작업 결과 저장
// model.addAttribute("myDate", date);
// model.addAttribute("yoil", yoil);
// 4. 작업 결과를 보여줄 View의 이름을 반환
return "yoil"; // /WEB-INF/views/yoil.jsp
}
private boolean isValid(MyDate date) {
return isValid(date.getYear(), date.getMonth(), date.getDay());
}
private @ModelAttribute("yoil") char getYoil(MyDate date) {
return getYoil(date.getYear(), date.getMonth(), date.getDay());
}
private char getYoil(int year, int month, int day) {
Calendar cal = Calendar.getInstance();
cal.set(year, month - 1, day);
int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
return " 일월화수목금토".charAt(dayOfWeek);
}
private boolean isValid(int year, int month, int day) {
if(year==-1 || month==-1 || day==-1)
return false;
return (1<=month && month<=12) && (1<=day && day<=31); // 간단히 체크
}
}
10. @GetMapping, @PostMapping
@RequestMapping(value="/add", method={RequestMethod.GET, RequestMethod.POST})
// @GetMapping("/add")
public String register() {
return "registerForm"; // WEB-INF/views/registerForm.jsp
}
@PostMapping("/save") // 4.3부터
public String save(User user, Model m) throws Exception {
// 1. 유효성 검사
if(!isValid(user)) {
String msg = URLEncoder.encode("id를 잘못입력하셨습니다.", "utf-8");
m.addAttribute("msg", msg);
return "forward:/register/add";
// return "redirect:/register/add?msg="+msg; // URL재작성(rewriting)
}
// 2. DB에 신규회원 정보를 저장
return "registerInfo";
}
private boolean isValid(User user) {
return false;
}
11. redirect 와 forward
@PostMapping("/save") // 4.3부터
public String save(User user, Model m) throws Exception {
// 1. 유효성 검사
if(!isValid(user)) {
String msg = URLEncoder.encode("id를 잘못입력하셨습니다.", "utf-8");
m.addAttribute("msg", msg);
return "forward:/register/add";
// return "redirect:/register/add?msg="+msg; // URL재작성(rewriting)
}
// 2. DB에 신규회원 정보를 저장
return "registerInfo";
}
12. 쿠키(Cookie)란?
@PostMapping("/login")
public String login(String id, String pwd, String toURL, boolean rememberId, HttpServletRequest request, HttpServletResponse response) throws Exception {
// 1. id와 pwd를 확인
if (!loginCheck(id, pwd)) {
// 2-1 일치하지 않으면, loginForm으로 이동
String msg = URLEncoder.encode("id 또는 pwd가 일치하지 않습니다.", StandardCharsets.UTF_8);
return "redirect:/login/login?msg=" + msg;
}
// 2-2. id와 pwd가 일치하면,
// 세션 객체를 얻어오기
HttpSession session = request.getSession();
// 세션 객체에 id를 저장
session.setAttribute("id", id);
if (rememberId) {
// 1. 쿠키를 생성
Cookie cookie = new Cookie("id", id); // ctrl+shift+o 자동 import
// 2. 응답에 저장
response.addCookie(cookie);
} else {
// 1. 쿠키를 삭제
Cookie cookie = new Cookie("id", id); // ctrl+shift+o 자동 import
cookie.setMaxAge(0); // 쿠키를 삭제
// 2. 응답에 저장
response.addCookie(cookie);
}
// 3. 홈으로 이동
toURL = toURL == null || toURL.equals("") ? "/" : toURL;
return "redirect:" + toURL;
}
13. 세션 이론
// 1. 원격 호출 가능한 프로그램으로 등록
@Controller
@RequestMapping("/login")
public class LoginController {
@GetMapping("/login")
public String loginForm() {
return "loginForm";
}
@GetMapping("/logout")
public String logout(HttpSession session) {
// 1. 세션을 종료
session.invalidate();
// 2. 홈으로 이동
return "redirect:/";
}
@PostMapping("/login")
public String login(String id, String pwd, String toURL, boolean rememberId, HttpServletRequest request, HttpServletResponse response) throws Exception {
// 1. id와 pwd를 확인
if (!loginCheck(id, pwd)) {
// 2-1 일치하지 않으면, loginForm으로 이동
String msg = URLEncoder.encode("id 또는 pwd가 일치하지 않습니다.", StandardCharsets.UTF_8);
return "redirect:/login/login?msg=" + msg;
}
// 2-2. id와 pwd가 일치하면,
// 세션 객체를 얻어오기
HttpSession session = request.getSession();
// 세션 객체에 id를 저장
session.setAttribute("id", id);
if (rememberId) {
// 1. 쿠키를 생성
Cookie cookie = new Cookie("id", id); // ctrl+shift+o 자동 import
// 2. 응답에 저장
response.addCookie(cookie);
} else {
// 1. 쿠키를 삭제
Cookie cookie = new Cookie("id", id); // ctrl+shift+o 자동 import
cookie.setMaxAge(0); // 쿠키를 삭제
// 2. 응답에 저장
response.addCookie(cookie);
}
// 3. 홈으로 이동
toURL = toURL == null || toURL.equals("") ? "/" : toURL;
return "redirect:" + toURL;
}
private boolean loginCheck(String id, String pwd) {
return "asdf".equals(id) && "1234".equals(pwd);
}
}
14. 예외처리
// 예외 처리
@Controller
public class ExceptionController {
// catcher2 ( 널 , 파일 낫파운드)
@ExceptionHandler({NullPointerException.class, FileNotFoundException.class})
public String catcher2(Exception ex, Model m) {
m.addAttribute("ex", ex);
return "error";
}
// catcher (서버 에러러
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) // 200 -> 500
public String catcher(Exception ex, Model m) {
System.out.println("catcher() in ExceptionController");
System.out.println("m="+m);
// m.addAttribute("ex", ex);
return "error";
}
@RequestMapping("/ex")
public String main(Model m) throws Exception {
m.addAttribute("msg", "message from ExceptionController.main()");
throw new Exception("예외가 발생했습니다.");
}
@RequestMapping("/ex2")
public String main2() throws Exception {
throw new NullPointerException("예외가 발생했습니다.");
}
}
// 예외 처리
@ControllerAdvice("com.fastcampus.ch3") // 지정된 패키지에서 발생한 예외만 처리
// @ControllerAdvice // 모든 패키지에 적용
public class GlobalCatcher {
// catcher2 ( 널 , 파일 낫파운드)
@ExceptionHandler({NullPointerException.class, FileNotFoundException.class})
public String catcher2(Exception ex, Model m) {
m.addAttribute("ex", ex);
return "error";
}
// catcher (서버 에러러
@ExceptionHandler(Exception.class)
public String catcher(Exception ex, Model m) {
m.addAttribute("ex", ex);
return "error";
}
}
15. DispatcherServlet 파헤치기
16. 데이터의 변환과 검증
public class GlobalValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return User.class.isAssignableFrom(clazz);
}
@Override
public void validate(Object target, Errors errors) {
System.out.println("GlobalValidator.validate() called");
User user = (User) target;
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "id", "required");
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "pwd", "required");
if(user.getId() == null || user.getId().trim().isEmpty() || user.getId().length() < 4 || user.getId().length() > 10 ) {
errors.rejectValue("id", "invalidLength", new String[]{"","4","12"}, null );
}
}
}
<beans:bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<beans:property name="basenames">
<beans:list>
<beans:value>error_message</beans:value> <!-- /src/main/resources/error_message.properties -->
</beans:list>
</beans:property>
<beans:property name="defaultEncoding" value="UTF-8"/>
</beans:bean>
'4차산업혁명의 일꾼 > Java&Spring웹개발과 서버 컴퓨터' 카테고리의 다른 글
자바의 버전 변천사를 통한 자바 이해 (0) | 2023.03.14 |
---|---|
자바개발자의 툴 이클립스에서 인텔리제이 비교 (0) | 2023.03.14 |
Interpreter Pattern - 디자인패턴(인터프리터 패턴) (0) | 2023.03.12 |
디자인패턴 - Command Pattern (0) | 2023.03.12 |
디자인 패턴 with 자바 - 낭비를 없애기(Flyweight, Proxy) (0) | 2023.03.09 |