- 유연성
- maven
- MVC : DispatcherServlet지원
- DI : 의존성 주입 (@Controller)
- JDBC
참조 사이트 https://www.egovframe.go.kr/wiki/doku.php?id=egovframework:rte2:ptl:annotation-based_controller
DispatcherServlet의 의미
급파하다, 파견 등의 의미로, 해석해보면 받은 요청을 어딘가로 빨리빨리 보내는 서블릿이라는 뜻이다. 또한 프론트 컨트롤러라고 불리기도 한다.
그렇다면 과연 어디로 보낸다는 것일까? 프론트 컨트롤러라면 컨트롤러의 종류 중 하나인 것인가 ??
<!-- 서블릿1 등록 -->
<servlet>
<servlet-name>서블릿1</servlet-name>
...
</servlet>
<servlet-mapping>
<servlet-name>서블릿1</servlet-name>
...
</servlet-mapping>
<!-- 서블릿2 등록 -->
<servlet>
<servlet-name>서블릿2</servlet-name>
...
</servlet>
<servlet-mapping>
<servlet-name>서블릿2</servlet-name>
...
</servlet-mapping>
<!-- 서블릿3 등록 -->
<servlet>
<servlet-name>서블릿3</servlet-name>
...
</servlet>
<servlet-mapping>
<servlet-name>서블릿3</servlet-name>
...
</servlet-mapping>
하지만 웹사이트를 이용해봤다면 알겠지만, 우리가 접속하는 페이지(경로)는 한두개가 아니다.
메뉴 페이지, 로그인 페이지, 관리자 페이지 등 아무리 적게 잡아도 최소 10개이다.
게다가 컨트롤러와는 달리 서블릿 객체 하나는 하나의 경로만 담당한다.
이렇게되면 10개보다 더 늘어날 것이고, 프로젝트 문서는 온통 서블릿 객체로 넘쳐날 것이다.
Servlet 객체는 HttpServlet를 확장한 객체이다.
이렇게 되면 HttpServlet 기능을 필수로 Override 해야 하고, 더이상 일반 객체로 사용할 수 없다.
즉, 클래스끼리 값을 주고받기가 까다로워진다는 것!
모든 서블릿이 공통으로 처리하는 작업이나, 가장 우선시 되야하는 작업이 분명 있을 것이다.
이런 것을 서블릿 객체로 처리하기란 불가능하고, 매우 까다로울 것이다.
DispatcherServlet은 이러한 단점들을 모두 해소해주고, 간편하게 사용할 수 있다.
서블릿을 더이상 HttpServlet을 확장하지 않고, POJO를 사용한다.
@Controller 어노테이션을 붙여서 간편히 사용할 수 있으며, 의존성이 낮아져서 다른 객체들과 연계가 자유롭다.
* POJO란 ? Plain Old Java Object의 약자로 다른 클래스나 인터페이스를 상속/implements 받아 메서드가 추가된 클래스가 아닌 일반적으로 우리가 알고 있는 getter, setter 같이 기본적인 기능만 가진 자바 객체를 말한다.
/* Servlet 객체 */
@WebServlet("/user")
public class testServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// GET 작업 처리
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// POST 작업 처리
}
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 서블릿 동작 처리
}
}
이렇게 extends로 HttpServlet를 상속받아 사용하고 하나하나씩 get, post, service를 생성해주어야 했다.
@Controller
public class testController {
@PostMapping("/user")
public String userPage() {
// POST 처리
}
@GetMapping("/user")
public String userPage() {
// GET 처리
}
}
참조블로그
- spring에선 특정 클래스를 구현하거나 상속할 필요가 없다.
- 원하는 곳에 의존성을 주입해서 사용하면 된다.
View, controller
공부할 때 spring03_web 프로젝트 많이 참고할 것
어제 만들었던 프로젝트인 spring02_mvc에 있는 pom.xml 의존성을 긁어온다.
- front단에 필요한 파일을 여기에 넣는다.
정적인 문서들은 모두 resources에 파일을 생성한다.
※ application.properties 한글인코딩 필요
-> 우클릭 Properties -> Resource-> Text file encoding (Other: UTF-8)
------------------------------------------------------/src/main/resources/application.properties
#application.properties 환경 설정
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp
server.port=9095
server.servlet.jsp.init-parameters.development=true
-------------------------------------------------------------------
어제 만들었던 프로젝트 spring02에서 긁어오기
- war파일로 생성하면 ServletIniriallizer 를 자동으로 생성해준다.
→ 호스팅할 때 필요한 파일.
- pring03WebApplication.java는 서버 시작파일이다.
@Controller
URL에서 요청, 응답이 가능한 클래스 지정
내가 객체를 만들지 않아도 @Controller가 자동으로 객체를 생성해준다.
자동 객체 생성됨 (의존성 주입)
WEB-INF, views, bbs, loin 파일은
src/main에 아니고
test에 넣어서 에러남.
@Controller
를 어노테이션해주면 URL에서 요청과 응답이 가능한 클래스로 지정할 수 있다. @RequestMapping("/home.do")
요청이 왔을 때 어떤 컨트롤러가 호출이 되어야하는지 알려주는 지표같은 것. 예시)
@RequestMapping("/home.do")
이렇게 매핑을 하면 localhost:9095/home.do으로 url을 입력했을 경우에
이것에 해당하는 메서드가 실행된다.
/login.do가 들어오면, 클라이언트가 url에 요청을 하게되는데, @RequestMapping이 붙은 바로 밑에있는 메소드인 loginForm()에 URL요청을 맵핑해주게 되는 것이다.
@RequestMapping 은 다중요청도 가능하다!
예시)
@RequestMapping(value = {"/hello", "/hello-basic"})
이것처럼 다중 요청을 할 경우에는 둘 중 아무 url이나 입력해도 된다.
ModelAndView 객체
Model에 데이터를 저정 후 view에서 데이터에 접근이 가능하게 해준다, mav 객체를 생성해준다.setViewName("뷰의 경로")
frontend로 보여줄 view단의 페이지 이름을 작성해준다.addObject()
데이터를 보낼때는 addObject() 메소드를 이용한다.mav.addObject("변수 이름", "데이터 값");
클라이언트에서 서버로 어떤 리소스로부터 정보를 요청하기 위해 사용되는 메서드로 데이터를 읽거나, 검색할 때에 사용된다.
GET은 요청을 전송할 때 URL 주소 끝에 파라미터로 포함되어 전송된다.
URL에서 요청 명령어를 읽어서 실행해주는 클래스. 자동으로 객체를 생성해준다. (의존성 주입)
*이 부분 작성할 때
@RequestMapping (value="", method = Re)까지 작성 해준 후
1) public void add() {}를 먼저 작성 해주고
2) RequestMethod.GET)을 ctrl+space로 명령어를 불러올 수 있다.
- 링크 뒤에있는 값을 받는 것은 add()함수가 받는 것이다.
- 명령 요청이 들어왔을 때 처리를 해주는 함수.
- add()에 매개변수로 받으면 된다.
URL에서 요청한 명령어를 등록
@RequestMapping(value="", method=GET | POST)
생명주기에서 service() → doGet(), doPost() 이렇게 받아왔던 방식처럼, 사용자가 요청을 get 또는 post방식 어떤 것으로 지정했는지 ?를 등록
Model
(부모)
ModelAndView
(둘이 같은 족보임)
같은 족보기 때문에 둘다 사용해도 된다.
- view단의 calcResult.jsp를 만들어 이 view페이지로 이동하는 것이다.
- setViewName을 하게 되면 /WEB-INF/views/calcResult.jsp 이렇게 경로가 만들어진다.
- 2)에 선언한 변수들은 선언만 해주고 지정을 해주지 않았다.
- 이 변수를 세팅 setAttribute를 해주는 것이다.
- 값을 세팅하고 view단으로 넘겨주는 방식.
- 왼쪽이 부모, 오른쪽이 자식페이지로 넘겨주는 것.
[사용해볼 어노테이션]
@RequestParam
Controller 메소드의 파라미터와 웹요청 파라미터와 맵핑하기 위한 어노테이션
@ModelAttribute
Controller 메소드의 파라미터나 리턴값을 Model 객체와 바인딩하기 위한 어노테이션
@SessionAttributes
Model 객체를 세션에 저장하고 사용하기 위한 어노테이션
※ 원래 사용자에게 값을 가져온 방법
초록색 : 사용자에게 값을 가져와서
빨간색 : 형변환을 해주고
파란색 : 그것을 변수에 넣어주는 것
이게 보편적인 방식이었다.
※ 위와 똑같지만 다른 방법
→ @RequestParam
을 사용한다
@RequestParam을 사용한 두수 사이의 차이
view단에는 값만 넘겨주면 된다!
@RequestParam
도 줄여쓸 수 있는 방법이 있다사용자가 요청한 값을 매개변수로 직접 저장 가능하다.
- 이 명령어도 줄여쓸 수 있다.
- 사용자가 요청한 값을 매개변수로 직접 지정하는 방법이다.
→ 단, 요청요청변수명과 매개변수명이 동일해야 한다.
- 이렇게 줄여쓸 수 있다.
→ 단, 요청요청변수명과 매개변수명이 동일해야 한다.
- 링크의 매개변수명이 no1, no2인걸 확인할 수 있다.
- 따라서 max함수에도 int no1, int no2로 똑같은 변수명을 사용해주면 간단하게 쓸 수 있다.
private String wname;
private String subject;
private String content;
private String passwd;
package kr.co.itwill.bbs;
public class BbsDTO {
private String wname;
private String subject;
private String content;
private String passwd;
//기본생성자
public BbsDTO() {}
//getter, setter
public String getWname() {
return wname;
}
public void setWname(String wname) {
this.wname = wname;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getPasswd() {
return passwd;
}
public void setPasswd(String passwd) {
this.passwd = passwd;
}
//toString
@Override
public String toString() {
return "BbsDTO [wname=" + wname + ", subject=" + subject + ", content=" + content + ", passwd=" + passwd + "]";
}
}//BbsDTO end
- 객체 생성되었는지 확인하는 명령어 만든 후 서버 껐다 켜서 콘솔창에 객체 생성되었는지 확인하기.
- 저 링크 경로로 가면 bbsForm.jsp 화면이 나오도록 할 것이다.
◎ 단순히 페이지를 보여주고 싶다면 굳이 ModelAndView를 사용하진 않아도 된다.
◎ 하나의 명령어에 get방식과 post방식 두가지 모두 사용가능하다.
> 동일한 요청명령어를 GET | POST 방식으로 구분해서 호출 가능하다
여기에 값을 올려두었기 때문에 자식페이지에서도 사용이 가능한 것이다.
◎ MVC패턴 -> 백엔드단과 프로트단을 구분해서 코딩을 하는것.
bbsResult.jsp(view단)에 올려준다.
부모페이지인 BbsCont.java에 올려놨던 값을 자식페이지에 물려주면 view단에 출력할 수 있다.
> 서버 껐다 켠 후 http://localhost:9095/bbs/create.do URL에 접속해본다.
> 쓰기를 누르면 bbsResult.jsp페이지가 나온다.
한글 인코딩
<%request.setCharacterEncoding("UTF-8");%>
web.xml에 한글필터가 들어가있다.
매개변수(parameter)가 DTO 객체인 경우 (이걸 더 많이 사용)
myweb에서 했던 이 부분을 한번에 담을 수 있다.
@ModelAttribute
Controller 메소드의 파라미터나 리턴값을 Model 객체와 바인딩하기 위한 어노테이션
*DTO란 ? - getter setter가 있는 것
알아서 자신의 name값을 찾아서 넣어준다.
이 빨간색, 초록색이 있다는 전제 하에 파란색 박스 부분을 사용할 수 있는 것이다.
오른쪽 부분을 왼쪽 한 줄로 한번에 넣을 수 있다.
◎ getter, setter, toString을 한번에 작성해주는 라이브러리도 있다.
이걸 적용시켜주면 알아서 getter, setter가 있다고 알아서 인식한다.
많이 사용하는 문법 한번 리뷰하기
package kr.co.itwill.login;
public class LoginDTO {
private String id;
private String pw;
public LoginDTO() {}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPw() {
return pw;
}
public void setPw(String pw) {
this.pw = pw;
}
}//class end
로그인 페이지 화면 만들고, 서버 껐다켜서 확인하기
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>loninForm.jsp</title>
</head>
<body>
<h3>로그인</h3>
<form method="post" action="login.do">
<table border="1">
<tr>
<td colspan="2" align="center">* 로그인 *</td>
</tr>
<tr>
<td>아이디</td>
<td><input type="text" name="id" size="20"></td>
</tr>
<tr>
<td>비밀번호</td>
<td><input type="password" name="pw" size="20"></td>
</tr>
<tr>
<td colspan=2 align=center>
<input type="submit" value="확인">
<input type="reset" value="취소">
</td>
</tr>
</table>
</form>
</body>
</html>
1) LoginCont() 객체 생성 후 서버 켜서 생성되었는지 확인
2) URL 로그인 주소 get방식으로 지정 후
3) form전송을 위해 post방식으로 지정해줘서 LoginDTO를 가져온다.
if문 부분은 원래 데이터베이스가 연동되어 데이터를 가져와야하는 곳이고, 성공 실패여부를 따로 작성해줘야 한다.
package kr.co.itwill.login;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class LoginCont {
public LoginCont() {
System.out.println("-----LoginCont() 객체 생성됨 ");
}//end
//결과확인 http://localhost:9095/login.do
@RequestMapping(value = "/login.do", method = RequestMethod.GET)
public String loginForm() {
return"login/loginForm"; //WEB-INF/views/login/loginForm.jsp
}//loginForm() end
@RequestMapping(value = "/login.do", method = RequestMethod.POST)
public ModelAndView loginProc(@ModelAttribute LoginDTO dto, HttpServletRequest req, HttpServletResponse resp, HttpSession session) {
String id=dto.getId();
String pw=dto.getPw();
ModelAndView mav = new ModelAndView();
if(id.equals("itwill") && pw.equals("1234")) {
mav.setViewName("login/loginResult");
session.setAttribute("s_id", id);
session.setAttribute("s_pw", pw);
req.setAttribute("message", "<h3>로그인 성공</h3>");
//성공하면 이 성공 페이지로 보낼 것이고
}else {
mav.setViewName("login/msgView");
req.setAttribute("message", "<p>아이디와 비번이 일치하지 않습니다.</p>");
req.setAttribute("link", "<a href='javascript:history.back()'>[다시시도]</a>");
}//if end
mav.addObject("dto", dto);
return mav;
}//loginProc() end
}//class end