Spring 공부 전 기초
학습목표 : Spring을 이해하기 위해 하드코딩으로 Spring처럼 만들어보기
- bean.properties 파일을 만들지 않아도 된다.
1. Annotation이란?
- 프로그램 실행 중 해당 변수에 대해 속성을 설정해주는 역할을 함.(Override, …)
- 주석에 대한 역할을 하면서 문법으로 체크함.
- @Override, @WebServlet(value=”.do”) …
1-1. Annotation만들기
1. New-> Annotation (원하는 패키지, 원하는 파일명 )
2. String value(); 메소드 선언
- @RequestMapping(value=”list.do”) // value()로 “list.do”를 추출할 수 있음
- String uri();를 선언하면 @RequestMapping(uri=”list.do”)가 됨
3. @Target(ElementType.)
- Annotation을 어디에 붙일지 설정할 수 있음
- 종류
@Target(ElementType.METHOD)
: 메소드 위에 붙일 수 있음@Target(ElementType.TYPE)
: 클래스위에 붙일 수 있음@Target(ElementType.FIELD)
: 멤버변수 위쪽에 붙일 수 있음
4. @Retention(RetentionPolicy.RUNTIME)
- Annotation 정보를 언제까지 유지시킬지 지정
RUNTIME
: 프로그램 실행되는동안까지
5. new Instance한 후, 메소드까지 실행하게 설정
- DispatcherServlet 에서
@WebServlet("*.do")
주석처리후 - web.xml설정
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>kr.ac.kopo.framework.DispatcherServlet</servlet-class>
<init-param>
<param-name>controllers</param-name>
<param-value>kr.ac.kopo.board.controller.BoardController
kr.ac.kopo.login.controller.LoginController</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
6. CtrlMethod
- list.do -> BoardController –> list()
- 어떤 컨트롤러인지 어떤메소드인지 받는 클래스 (get메소드만 필요)
import java.lang.reflect.Method;
public class CtrlAndMethod {
private Object target;
//어떤 메소드를 실행하는지 기억
private Method method;
public CtrlAndMethod(Object target, Method method) {
super();
this.target = target;
this.method = method;
}
/**
* @return the target
*/
public Object getTarget() {
return target;
}
/**
* @return the method
*/
public Method getMethod() {
return method;
}
}
7. HandlerMapping
- 어떤 uri가 들어왔을때 어떤 메소드가 실행될지
import java.lang.reflect.Method;
package kr.ac.kopo.framework;
import java.lang.reflect.Method;
import java.util.Map;
public class HandlerMapping {
private Map<String, CtrlAndMethod> mappings;
//uri
public HandlerMapping(String ctrlNames) throws Exception {
//ctrlName -> kr.ac.kopo.board.controller.BoardController | kr.ac.kopo.login.controller.LoginController
String[] ctrls = ctrlNames.split("\\|");
for(String c: ctrls) {
//System.out.println(c.trim()); | 뒤에 들여쓰기 공백있으니까 trim필요
Class<?> clz = Class.forName(c.trim());
//Object target = clz.newInstance(); // jdk 9부터 사용제한.
Object target = clz.getDeclaredConstructor().newInstance();
System.out.println(target);
Method[] methods = clz.getMethods(); //사용할 수 있는 메소드 출력 (public만 나온다.)
//Method[] methods = clz.getDeclaredMethods(); // 자신에 클래스에 선언한것 모두 나옴.(public, private ...)
for(Method method : methods) {
System.out.println(method);
}
System.out.println();
}
}
}
- DispatcherServlet
private HandlerMapping mappings; //밖에 선언
/**
* @see Servlet#init(ServletConfig)
*/
public void init(ServletConfig config) throws ServletException {
String ctrlNames = config.getInitParameter("controllers");
System.out.println(ctrlNames);
try {//init는 throws ServletException 이므로 에러남.그래서 try-catch필요
mappings = new HandlerMapping(ctrlNames);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
8. 원하는 메소드 찾기 invoke
@RequestMapping
어노테이션이 붙은것만 찾고싶다.- RequestMapping reqAnno = method.getAnnotation(RequestMapping.class);
invoke()
: Controller가 갖고있는 메소드 정보 동적으로 지정
// method.invoke(target, request, response);
try {
CtrlAndMethod cam = mappings.getCtrlAndMethod(uri);
/*
* System.out.println("ctrl : " + cam.getTarget());
* System.out.println("method : " + cam.getMethod());
*/
if(cam == null) {
throw new ServletException("해당 URI는 존재하지 않습니다.");
}
Object target = cam.getTarget();
Method method = cam.getMethod();
/*
* 누군가 /board/list.do 요청
target = new BoardController();
Method method = public String list ( ...req , ...res )....{}
String callPage = target.list(request,response);
target.method() 는 BoardController의 method()메소드를 사용하겠다는 의미임 우리가원하는것 아님.
*/
method.invoke(target, request, response);
}catch (Exception e) {
e.printStackTrace();
}
9. DispatcherServlet이 공유영역에 객체 등록하게 하기
- ModelAndView.java클래스 생성 : kr.ac.kopo.framwork패키지안
- Model : JSP에서 사용한 데이터 저장 객체(request공유영역에 등록한 객체)
- View : 응답화면(JSP) 정보를 저장.
package kr.ac.kopo.framework;
import java.util.HashMap;
import java.util.Map;
/*
* Model : JSP에서 사용한 데이터 저장 객체(request공유영역에 등록한 객체)
* View : 응답화면(JSP) 정보를 저장.
*/
public class ModelAndView {
private String view;
private Map<String, Object> model; // Object Generic은 안돼?
//request.setAttribute("key", value)
public ModelAndView() {
model = new HashMap<>();
}
/**
* @return the view
*/
public String getView() {
return view;
}
/**
* @param view the view to set
*/
public void setView(String view) {
this.view = view;
}
/**
* @return the model
*/
public Map<String, Object> getModel() {
return model;
}
/**
* @param model the model to set
*/
public void setModel(Map<String, Object> model) {
this.model = model;
}
public void addAttribute(String key, Object value) {
model.put(key,value);
}
}
2. Filter
- POST방식으로 파라미터 넘길경우 항상 인코딩해주어야함
- 번거롭기 때문에 Filter을 Servlet앞에 두어 어떤 게시물이 들어오든 request.setCharacter(“utf-8”);수행하도록 함.
-
필터클래스 생성 후, web.xml에 등록해야함
- 방법1
<filter>
<filter-name>encoding</filter-name>
<filter-class>kr.ac.kopo.filter.EncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>*</url-pattern>
</filter-mapping>
package kr.ac.kopo.filter;
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;
public class EncodingFilter implements Filter{
/* POST방식은 항상 인코딩해줘야한다 번거롭다
Servlet앞에 필터를 세워 request.setCharacterEncoding("utf-8");할지말지 판단.
*/
private String charset;
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("필터처리~");
request.setCharacterEncoding("utf-8");
chain.doFilter(request,response);
}
}
- 방법2
<filter>
<filter-name>encoding</filter-name>
<filter-class>kr.ac.kopo.filter.EncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
package kr.ac.kopo.filter;
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;
public class EncodingFilter implements Filter{
/* POST방식은 항상 인코딩해줘야한다 번거롭다
Servlet앞에 필터를 세워 request.setCharacterEncoding("utf-8");할지말지 판단.
*/
private String charset;
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("필터처리~");
request.setCharacterEncoding(charset);
chain.doFilter(request,response);
}
public void init(FilterConfig filterConfig) throws ServletException{
charset = filterConfig.getInitParameter("encoding");
}
}
3. Listener
- 리스너는 서버가 시작될 때 딱 한번 실행된다.
- close가 필요하다.
- 비즈니스 관련된 DAO와 서비스 등을 한번 실행해서 계속 재사용하고 싶을 때 사용
- Servlet끼리 값을 공유할 수 있는 영역 ( 객체 ) : servletContext
- ServletContextEvent sce를 통해 가져올 수 있음
- 만든 객체를 ServletContext 영역에 넣는다.
- 먼저 인스턴스객체를 모두 만들어놓고 개발자가 가져다 쓸 수 있다.
- Controller에서 ServletCOntext변수(sc)로 접근할 수 있다.
- ServletContext sc = request.getServletContext();
- service = (BoardService) sc.getAttribute(“boardService”);
- ServletContext sc = request.getServletContext();
- Client 요청이 들어오기전에 만들어져야함
- destroy가 존재하며, 자원관리를 한다.