배움 __IL/TIL 1기

TIL : 55번째- 230221 [2-3-화]

Mo_bi!e 2023. 2. 21. 18:34

I. 들어가며

모든 것은 컨트롤러가 있고 다 작성가능해

컨트롤러는 분리하면 이제 POJO컨트롤러가 돼! 서블릿흔적프론트컨트롤러가 돼!

 

5가지 (쿼리스트링, : get, post), page, cookie, session

Session 사용목적?은 사용자가 요청결과들을 유지하고싶을 떄 써!

이 저장소를 쿠키가 대신할수있어

 

그런데 세션장점은? 사용자 특성을 타지않아!! 사용자가 쿠키설정해서 했기때문이야

사용자의 동의가 필요한 상태뿐만아니라, 저장소는 클라이언트야 사용자 특성을

쿠키 장점은? 원하는 경로, 원하는 기간을 정할수있다.

 

 

II. 웹개발

1.  쿠키

(1) 쿠키값 보기

 

list3 실행 후 list2를 실행하면 다음과 같은 결과가 나온다

첫번째 줄 : session 의 value

두번째 줄: Cookie Array

세번째 줄 : Cookie 의 value

 

다음과 같이 하면 출력이 된다

<ListController2.java>

    Cookie [] cookies = req.getCookies();
    System.out.println(cookies);

그냥 이렇게 하면 위 두번째 줄 처럼처럼 나온다.

    Cookie [] cookies = req.getCookies();
    for(Cookie cookie : cookies)
        if(cookie.getName().equals("haha22")) {
            System.out.println(cookie.getValue());
            break;
        }

이렇게 하면 위 이미지 3번째 줄처럼 hoho111 이 나온다!!

그런데,  쿠키 값 하나 꺼내는데 반복하고, 조건하는등 너무 불편해!! 이런것은 결국 Spring으로 손쉽게 해결할 수있다

 

 

2. 프론트 컨트롤러 

(1) 실습

우선 DispatcherServlet 이란 frontController 을 의미한다

1)

<JSPDispatcherServlet.java>

@WebServlet("/*")
public class JSPDispatcherServlet extends HttpServlet{

	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp)
    	throws ServletException, IOException {

		PrintWriter out = resp.getWriter();
		
		out.write("hello frontBell");
		
	}
}

별도의 파일을 만들어준다

이 경우에 어노테이션 방식을 루트에서 * 넣어주면 어디를 접속해도 프론트컨트롤러와 조우하게된다.

 

2)

기존 컨트롤러에서 다 떼낸다.

서블릿어노테이션, 상속(HtppServlet), doGet(or Service) 모두 없앤다.

 

위 아래 같음

좌측이 FrontController, 우측이 서블릿이 없는 컨트롤러(POJO) 두개이다.

향후 좌측의 역할은 Spring 프레임웍이 대신한다.

 

3)

앞서 말한것 처럼 FrontController가 다 먹어버린다

 

*을 써야 모든 접속이 프론트컨트롤러로 오게된다. 하지않는다면 menu 등의 url 은 놓치게된다 왜냐하면 놓치면 안되기 때문이다

한편 이경우 다른 서블릿, url 맵핑 등을 하면안된다

 

// menu/list 요청이 오면 ListPojoController의 requestHandler()호출

// menu/detail 요청이 오면 DetailPOJOController의 requestHandler()호출

@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

    PrintWriter out = resp.getWriter();

    String uri = req.getRequestURI();
    String url = req.getRequestURL().toString();

    out.printf("uri : %s \n", uri);
    out.printf("url : %s \n", url);

 

uri 와 url 은 다르다

uri 는 물리경로가 나오고

url 은 localhost 부터 다 표현해준다

 

4)

<JSPDispatcherServlet.java>

@WebServlet("/*")
public class JSPDispatcherServlet extends HttpServlet{

	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

		PrintWriter out = resp.getWriter();
		
		String uri = req.getRequestURI();
		String url = req.getRequestURL().toString();
		
		out.printf("uri : %s \n", uri);
		out.printf("url : %s \n", url);
		
// menu/list 요청이 오면 ListPojoController의 requestHandler()호출
// menu/detail 요청이 오면 DetailPOJOController의 requestHandler()호출
        
		if(uri.equals("/menu/list"))
			viewSrc = new ListPOJOController4().requestHandler();
		
		if(uri.equals("/menu/detail"))
			viewSrc = new DetailPOJOController().requestHandler();
		
		out.write("hello frontBell");

uri 값이 menu/list or detail 인지 여부에 따라서 함수호출이 달라진다.

 

<POJO Controller> 2개

public class DetailPOJOController {
	
	private MenuService service;
	//메뉴 서비스에 대한 멤버 변수를 선언해준다.
	
	public DetailPOJOController() {
		// TODO Auto-generated constructor stub
		service = new DefaultMenuService();
		//생성자에다가 인터페이스를 구현한것을 이용할 수있게끔 해준다
	}
	
	public String requestHandler() {
		return "/WEB-INF/view/menu/detail.jsp" ;
	}
}
public class ListPOJOController4 {
	
	private MenuService service;
	//메뉴 서비스에 대한 멤버 변수를 선언해준다.
	
	public ListPOJOController4() {
		// TODO Auto-generated constructor stub
		service = new DefaultMenuService();
		//생성자에다가 인터페이스를 구현한것을 이용할 수있게끔 해준다
	}
	
	public String requestHandler() {
		
		return "/WEB-INF/view/menu/list.jsp" ;
	}
}

1. 최초에 기본값notfound.jsp 로 해준다

2. 그리고 uri 의 값이 (물리주소로 해야함 즉 앞에 / 필수!) 조건문에 따라서 다른 컨트롤러를 호출한다

3. 호출한 컨트롤러의 반환값을 viewsrc에 넣는다

4. viewsrc를 포워딩한다 (그러고 이제 디스패처 기능도 프론트가 가져간다.)

 

 

5)

이렇게 frontController는 내가 매번 만들어야할까?

이런것들은 라이브러리로 만드는것이 좋고, 이러한 소스코드 없을 수있다

장착만 하면쓸수있게끔 할 수있다

라이브러리가 있으면 이렇게 연달아서 만들 필요가 없다 (or SpringFrameWork)

 

 

이렇게 프론트 컨트롤러를 통해서 POJO를 호출하는 코드를 작성하는 방법은 2가지가 있다.

====방법 1: 내가 반복하는 코드

앞서 한것이다

 

====방법 2: 컴퓨터가 반복하는 코드

 

캐스팅 관련 requestHandler를 가지는 공통형식?

공통형식을 만들어보자~

 

예전에는 implements 이지만 이제는 reflextion 이다.

리플렉션 방법은 쉽지는 않다

 

(2) 리플렉션

1)

클래스 정보얻기를 리플렉션이라고한다

 

클래스 정보를 얻는 방법은 3가지가 있다

//개체명(문자열)에서 클래스 정보 얻기
Class clsInfo = 
		Class.forName("com.newlecture.web.controller.menu.DetailPOJOController");


// 개체(class)에서 클래스 정보 얻기
Class clsInfo1 = 
		ListPOJOController4.class; //이렇게 해서 정보를 얻음


// 객체에서 클래스 정보 얻기 

    //객체생성 
Object controller = Class.forName
        ("com.newlecture.web.controller.menu.ListPOJOController4")
        .getDeclaredConstructor()
        .newInstance();

    //객체로 정보 얻음
Class clsInfo2 = controller.getClass();

이렇게 하나의 정보를 얻어준다

 

이후 이 방법을 기초로

Field[] fields =  clsInfo.getDeclaredFields();
Method[] methods = clsInfo.getDeclaredMethods();

for(Method m : methods) {
    System.out.println(m.getName());
}
System.out.println("====");

for(Field f : fields) {
    System.out.println(f.getName());
}

다음과 같이 DetailPOJOController 메소드 멤버변수가 무엇인지 출력이 가능하다

\

2)

이렇게 정보를 얻어 낼 때에는 메소드나, 변수private 인지 여부 상관없이 다 나온다.

Method method = null; 
    for(Method m : methods) {
        System.out.println(m.getName());

        if(m.getName().equals("add"))
            method = m;
    }

    int result = (int) method.invoke(controller, 3, 4);
    System.out.printf("result : %d \n", result);

어떤 클래스는 정보를 얻을수있다면 그 정보를 꺼내서 해당 클래스 메소드호출이 가능하다.

 

즉 add 메소드 정보를 받아와서 그 메소드에 대해서 invoke 를 할 때 객체를 넣어주면서 인수 3,4를 넣으면 된다

이 경우 (int)로 캐스팅해주어야한다 (왜냐하면 object 형식이기 때문이다.)

한편 기존 add메소드는 정보를 조회할때와 달리 private이기 때문에 public으로 수정해주어야한다

 

3)

비단 메소드, 멤버변수 명 외에도 매개변수도 파악할수 있다

//매개 변수 갯수 출력 
int count = method.getParameterCount();
System.out.println(count);


//매개변수 타입 출력 
Parameter[] parmas = method.getParameters();
for(Parameter p : parmas)
    System.out.printf("param : %s \n", p.getType().toString());



int result = (int) method.invoke(controller, 3, 4);
System.out.printf("result : %d \n", result);

 

 

 

4)

이후 프론트 컨트롤러에 리플렉션 옮기기

 

 

 

 

 

 

 


1. 보충

(1) 자바 for 확장문

What (정의) : 기존 for문과 마찬가지로 반복문이다. 

Why (존재이유) :

- 기존 for문과 차이는 반복문에서 index가 불요한 경우이다

- 또한 배열모든 값을 반복한다.

 

 

(2) URI URL 차이 (https://www.elancer.co.kr/blog/view?seq=74)

두개의 차이는 무엇이고, POJO 컨트롤러 호출 시 왜 URI를 이용해서 조건문을 작성하는가?

1) URI (Uniform Resource Identifier) : 통합자원식별자

What (정의) : 

- Uniform : 자원 식별을 위한 통합적 방식이다

- Resource : URI 로 식별가능한 모든 자원

- Identifier : 다른 자원와 구별

: 이런 말을 통합해 보면 자원식별하기 위한 문자열 시퀀스 이다.

 

Why (존재이유) : 웹페이지의 자원을 식별하기 위한 것이다.

How (방법) :

e.g. (예) :

 

 

2) URL

What (정의) : 

UR : 상동

Location : 위치

 

: 통합하면 URI 의 위치를 나타내는 규약이다

즉 이는 주소(URI) 뿐만 아니라 프로토콜(HTTPS, FTP 등) 을 나타낸다.

 

Why (존재이유) : 외부에서 특정 웹페이지에 접속하기 위해서

 

3) 차이점

- URL 은 URI 의 일부이다.

위 정의에 비추어보면 

- URI : mdlg.tistory.com / URL : https://mdlg.tistory.com 

차이이다. 즉 URL 은 프로토콜(HTTPS)과 결합된 형태이다.

 

 

 

 

4) 왜 URI 로 조건문 작성?

생각컨데 URL 은 외부기준으로 접속하기 위해 필요한 것이지만

디스패처 서블릿에서 컨트롤러간에 관계는 내부적인것이기 떄문에 식별자를 주고받는 것이 바람직 할수도 있다.

 

+ 추가로 현재는 URL 이 localHost이지만 도메인이나, 서브측 주소가 바뀔경우 하나씩 바꿔주어야하는 문제가 발생한다

이러한 점을 연유로 URI 로 작성하는것이 바람직하다

 

(3) Reflection ( https://steady-coding.tistory.com/609 ) (https://dublin-java.tistory.com/53 )

What (정의) :

- 우선 new 를 이용해서 만드는 객체와 다른 것이다

- Heap 영역에 load 된 Class타입의 객체를 이용해서, 특정 클래스의 인스턴스를 생성할 수 있게끔한다

- 또한 인스턴스의 메소드나, 멤버변수를 접근제어자(private 등) 와 무방하게 이용이 가능하다 [캡슐화??!!!]

 

 

 

Why (존재이유) : 리플렉션은 캡슐화를 저해하기 때문에 문제가 있다. 그럼에도 불구하고 사용하는 이유는 소규모 프로젝트의 경우 객체와 의존관계 파악이 용이하다. 그러나 SpringFramework 를 이용하는 대규모 프로젝트의 경우 동적으로 클래스를 만들어서 의존관계를 맺어줄 수있다.

 

How (방법) :

 

  • 클래스.class 로 가져오기
  • 인스턴스.getClass() 로 가져오기
  • Class.forName("클래스명") 으로 가져오기

+ Spring BeanFactory 가 무엇일까?

 

 

(3 - 1) invoke

What (정의) : 단어 그자체의 의미는 "부르다" 이다 예측컨데 메소드를 호출한다는 의미로 먼저 이해하면 수월하다고 생각한다.

Why (존재이유) : 리플렉션에서 함수를 호출하기 위한 방법이다 (동적실행)

 

How (방법) :

보통의 JAVA : S(주어 : Object) + V(동사 : method) + O(목적어 : argument) 순서이다

reflection : V(메소드).invoke(S(주어) , O(목적어)) 이다.

 

 

e.g. (예) :

 

 

(3 - 2) reflection 과 SpringFramework 과의 관계

 

- reflection 을 이용해서 DI 프레임웍 구현이 가능함

- reflection 존재이유로 갈음 

 

 

 

2. 회고 

 

1) 프론트 컨트롤러가 향후에 스프링프레임웍이 대신한다는 점이 흥미롭다

 

2) 리플렉션의 느낌은 알았는데 무언가 어떻게 연결되는지는 의문이다.

 

'배움 __IL > TIL 1기' 카테고리의 다른 글

TIL : 57번째- 230223 [2-3-목]  (0) 2023.02.23
TIL : 56번째- 230222 [2-3-수]  (0) 2023.02.22
TIL : 54번째- 230220 [2-3-월]  (0) 2023.02.20
TIL : 53번째- 230217 [2-2-금]  (0) 2023.02.17
TIL : 52번째- 230216 [2-2-목]  (0) 2023.02.16