[Servlet, JSP] 231212/ 405번 발동 이유, WAS

이슬기·2023년 12월 12일

servlet

목록 보기
5/8

최종 목표

<화면 출력 부분 관련>

  • ViewResolver (최종. 1-3)
  • 1-1에서 설계했던 ActionForward -> String(1-2)으로 변경
    • ActionForward : for문 안 if문, if문이 계속 오는 형태 : 좋지 않다. 모든 조건을 따져야 한다. 직관적이지 않다. 유지보수에 불리
    • String : 문자열, 바이너리, JSON, html 출력
      • JSP, Servlet 중 JSP는 굳이 사용할 필요 없다. Servlet으로도 문자열, 바이너리, JSON을 출력할 수 있다.

👇1-1 NoticeController.java : ActionForward

public ActionForward execute(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {}

👇1-2 BoardController.java : String

public String execute(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {}
  • 텍스트와 바이너리
    • 바이너리 : 문자와 숫자
    • 텍스트 : 문자만
      • 텍스트는 숫자도 문자로 바꾸려 한다. 따라서 메모장에서 이미지를 열었을 때 깨진다.

p.273

  • PrintWriter는 JS의 document라고 생각하면 됨
    : 브라우저의 태그들을 기록함
    : 단, PrintWriter 처리 주체는 톰캣(서버에서 이미 만들어져 내려옴). 따라서 document보다 빠름. 서버시점.
    : document의 처리 주체는 브라우저. 브라우저에서 랜더링 될 때 출력됨. 클라이언트 시점.

  • 8-9)
    url은 first. 출력하는 건 second


    <3가지 경우 나눠서 처리해보기>

  • redirect

  • forward

  • WEB-INF

    • : 있으면 redirect, forward. 없으면 WEB-INF
return "redirect:/notice/noticeList.jsp"; //webapp
return "forward:/notice/noticeList.jsp"; //webapp - 요청이 유지되는 것으로 판단해서 서블릿이 쥐고 있는 값을 jsp에서도 사용할 수 있다.
return "/notice/noticeList"; //WEB-INF/jsp/notice 아래

p. 276

  • redirect : first -> second
  • 확장자명 .jsp은 중요하지 않다. 중요한 건 mime type. mime type으로 브라우저가 판단한다.
    [" ", / ]
  • 0번 방 : 콜론 - redirect(sendRedirect)와 forward(forward)를 나눔. redirect, forward이면 " " 0번 방에 넣겠다.
  • 1번 방 : / 슬래쉬로 나눔. 슬래쉬를 기준으로 리턴을 Array로 받겠다. workname. 예) notice, board...
  • 2번 방 : 메소드 이름이면서 페이지 이름이다. viewName

MIME TYPE

MIME

Multipurpose Internet Mail Extensions의 약자로 파일 변환을 의미. 현재는 웹을 통해 여러 형태의 파일을 전달하는데 사용하고 있지만 이 용어가 생길 땐 이메일과 함께 동봉할 파일을 텍스트 문자로 전환해서 이메일 시스템을 통해 전달하기 위해 개발되어 Internet Mail Extensions라고 불리기 시작했다.

MIME 사용 이유

예전에는 텍스트 파일을 주고 받는데에 ASCII로 공통된 표준에 따르기만 하면 문제가 없었으나 네트워크를 통해 ASCII가 아닌 바이너리 파일을 보내는 경우가 생기게 되었다. 음악파일, 무비파일, 워드파일 등등 ASCII만으로는 전송이 안되기 때문에 기존 시스템에서 문제 없이 전달하기 위해서는 텍스트로의 변환이 필요했다.

텍스트 파일로 변환하는 것을 인코딩(Encoding), 텍스트 파일을 바이너리 파일로 변환하는 것을 디코딩(Decoding)이라고 한다.

MIME으로 인코딩한 파일은 Content-type정보를 앞부분에 담게되며 Content-type은 여러가지 타입이 있다.

웹 브라우저에서 서버에 접속하여 html 문서를 요청하면서 html문서에 있는 이미지 파일의 경로를 불러올 수 있다. 이러한 과정에서 이미지의 경로에 있는 파일이 웹브라우저에서 지원되는 MIME-Type이라면 웹브라우저를 이용하여 열어볼 수 있다.

바이너리파일(음악 파일, 무비 파일, 워드 파일 등) 또한 마찬가지 이다. 주로 쓰고 있는 대부분의 포맷인 .gif .jpg .mov 등등의 파일들은 웹 브라우저에서 무리없이 열리게 되는데 브라우저에서 지원하지 못하는 유형은 따로 지정해줘야 한다.

Content Type 종류

  1. Multipart Related MIME 타입
  • Content-Type : Multipart/Related (기본형태)
  • Content-Type : Application/X-FixedRecord
  1. XML Media 타입
  • Content-Type : text/xml
  • Content-Type : Application/xml
  • Content-Type : Application/xml-external-parsed-entity
  • Content-Type : Application/xml-dtd
  • Content-Type : Application/mathtml+xml
  • Content-Type : Application/xslt+xml
  1. Application의 타입
  • Servlet - JSON : (application/json)
  1. 오디오 타입

  2. Multipart 타입

  3. TEXT 타입

  • Servlet - jsp : (text/html)
  • Servlet - text : (text/plain)
  1. file 타입
  • Servlet - jsp : (text/html)
  • Servlet - text : (text/plain)

유지의 문제

Spring 버전이 높아지면서 달라진 점 : 의존관계에 대한 자동화

  • Spring 2.0 ~ 4.0 : 유지에 대한 클래스 ModelAndView
  • ModelAndView : 스코프는 String으로. 즉 select일 때 사용하겠다.
    <Redirect이거나 forward일 때 배포 위치>
    • webapp : 한 건을 수정하고 처리할 때. Redirect, forward 배포는 여기. select 쓸 때, 스코프는 request - setAttribute 사용(p.276)
    • WEB-INF : ModelAndView 배포는 여기.
return "redirect:/notice/noticeList.jsp"; //webapp
return "forward:/notice/noticeList.jsp"; //webapp - 요청이 유지되는 것으로 판단해서 서블릿이 쥐고 있는 값을 jsp에서도 사용할 수 있다.
return "/notice/noticeList"; //WEB-INF/jsp/notice 아래
  • 스코프 종류
    • pageContext
    • request
    • session
    • application
    p. 278
  • second 자체가 서블릿. p. 281
    리액트로 받을 때 JSON형식으로 변경해서 받아야 하는데 JSON으로 내보내려면 application/JSON 형식으로 해야한다.
    이렇게 되면 forward를 사용할 필요없다.

JSP로 내보낼 필요가 없을 때는 html을 사용하지 않는다.

  • html페이지로 select한 결과를 내보낼 때만 필요한 부분이다.
  • json으로 바로 내보낼 때는 굳이 forward 처리할 필요 없다.
    • getRequestDispatcher 할 필요없다.
    • setContentType( / )으로 바로 처리
    else if("jsonNoticeList2".equals(upmu[1])) {//select
    		logger.info("jsonNoticeList");
    		List<Map<String ,Object>> nList = null;
    		hmb.bind(pMap);
    		nList = nLogic.noticeList(pMap);
    		Gson g = new Gson();
    		String temp = g.toJson(nList);
    		res.setCharacterEncoding("utf-8");
    		res.setContentType("application/json");
    		PrintWriter out = res.getWriter();
    		out.print(temp);//[{"deptno":10, "dname":"영업무"}]
    		int end = path.toString().length();// -> notice/
    		path.delete(0, end);
    		path.append(temp);//url이 전달되는게 아니라 json형식 즉 문자열이 전달됨

관심사의 분리(Separation of Concerns)

  • 이론서만 너무 보면 코딩이 안됨
  • 구현을 해 놓고 개선하면서 분리를 연습할 것.
  • OOP(객체 지향 프로그래밍) 5대 설계 원칙 - SOLID

    • SRP : 단일 책임의 원칙
      하나의 메소드는 하나의 책임(관심사로 읽음)만 진다
      모듈이 변경되는 이유가 한 가지여야 함. 즉, 해당 모듈이 여러 대상 또는 액터들에 대해 책임을 가져서는 안 되고, 오직 하나의 액터에 대해서만 책임을 져야 한다.
    • OCP : 개방 폐쇄 원칙
    • ISP : 인터페이스 분리 원칙
    • DIP : 의존 역적 원칙
    • LSP : 리스코프 치환 원칙
  • 분리
    1) 관심사 (입력 - 처리 - 출력)
    2) 변하는 것, 변하지 않는 것 분리해 본다.
    3) 공통(중복) 코드 분리

유효범위

  1. pageContext - 현재 페이지에서만 사용이 가능하다
    : EL사용을 위해서만 사용될 뿐 사용되지 않는다
    : 주소창이 바뀐다

  2. request - 요청이 유지되는 동안에...
    : 요청할 때 마다 생기고 서로 독립적이다. - 세션보다는 제한적
    : 요청마다 1개씩 갖는다
    : forward시에 사용이 가능함 - 주소창이 안바뀌는데 페이지는 바뀐다.

  3. session - 사용자마다 1개씩 생기는 개별저장소 - 사용자 만명이면 만개가 생긴다.
    : 그래서 서버 부담이 대단히 높다. 사용하기는 제일 편하다
    : 로그인하면 생겼다가 로그아웃하면 사라진다.
    : 메모리 부담이 제일 높다
    : 잠깐 저장했다가 지우는 방법도 가능은 하다
    : 주소창이 바뀌어서 기존에 요청이 끊어져도 유지된다 - 시간

  4. application - 공통저장소이다. - 이부분이 세션과 다르다
    : context마다 1개라서 어디서나 접근이 가능함
    : 모든 클라이언트가 공유가능함 - 하나다
    : Web Application의 시작부터 종료까지 계속 유지된다. - 독이다

  • 사용방법은? - 저장소
    저장할 때 -> setAttribute(이름,값);
    읽어올 때 -> getAttribute(이름-String):값- Object;
    지울 때 -> removeAttribute(이름);, 세션 session.invalidate();세션값 모두 삭제

  • 2번과 3번은 스프링에서도 지원하기 때문에 주의 깊에 봐야한다. 1번과 4번은 별로...

Today

  1. XXXController : 서블릿 아니어도 괜찮아
    : Controller 추가해 본다
    : 누가 서블릿이지? - ActionServlet.java 추가 - FrontController(전처리 지원 : 관여) -> DispatcherServlet과 동급

  2. doGet, doPost, doPut, doDelete : Restful API 지원하는 메소드를 오버라이딩 함
    : 405번 발동하면 이 메소드 이름이 틀렸을 경우임

  • 화면 없이도 post방식을 테스트할 수 있다 - postman
    • body 옵션 선택함
      • upmu[0] = workname, upmu[1] = 메소드 이름 뿐 + 디폴트 뷰 이름으로 사용해본다.
      • form - data -> <form method="post" action="/notice/noticeInsert.gd"> -> BoardController로 갈지, QnAController로 갈지, MemberController로 갈지 결정해야 함
      • workname - upmu[0]으로 어떤 컨트롤러 클래스를 주입받을 건지 결정한다.
      • methodname, viewname - upmu[1]
  • Servlet과 만나는 부분 / mime type
    • Servlet - jsp : (text/html)
    • Servlet - text : (text/plain)
    • Servlet - null : 첨부파일 : X
    • Servlet - JSON : (application/json)
      • 텍스트 : 문자 -> 문자, 숫자 -> 문자
      • 바이너리 : 문자 -> 문자 , 숫자->숫자 - 형전환이 일어나지 않기 때문에 텍스트보다 빠름
    • postman에서 GET방식 일때는 body에 어떤 값을 넣어도 넘어가지 않는다. Params에서 해야한다.

Tomcat에서 한글깨짐이 발생했을 때

왜 한글이 깨지는 걸까?
Tomcat은 인코딩 타입이 8859_1 디폴트이다.

  • get방식 한글처리
    • server.xml : 포트번호 8000번인 <connector URIEncoding=utf-8 -> URI한글포함될 때>
  • post방식 한글처리
    • web.xml에 filter 옵션을 추가하여 한글 처리 할 수 있다.
<!-- EncodingFilter 정의하기 	 
	  아래 filter가 post방식에 대한 한글처리를 지원하는가? - 네
	  web.xml문서는 deployment descriptor - DD파일, 배포서술자(번역어)
	  -> @annotation으로 변경됨
	  -->
	  <filter>
	  	<filter-name>CharacterEncoding</filter-name>
	  	<filter-class>org.apache.catalina.filters.SetCharacterEncodingFilter</filter-class>
	  <init-param>
	  	<param-name>encoding</param-name>
	  	<param-value>utf-8</param-value>
	  </init-param>
	  </filter>
	  <filter-mapping>
	  	<filter-name>CharacterEncoding</filter-name>
	  	<url-pattern>/*</url-pattern>
	  </filter-mapping>
  • 텍스트 VS 바이너리
    : Base64(64진법 - 26*2) VS 아스키코드(128bit)
    • 바이너리 타입 : 문자+숫자
    • 텍스트 에디터 : 문자+문자 - 사람이 눈으로 볼 수 있는 정보
      숫자 -> 문자로 전환처리 시 ) 12를 "1""2"로 나눠서 저장한다.
      • 메모장에서 숫자가 문자로 변환되어 깨지면 텍스트 에디터

WAS(Web Application Server)

웹 서버와 웹 컨테이너의 기능을 모두 수행하는 프로그램(S/W)

  • 웹 서버와 웹 컨테이너의 차이점 (둘을 분리해서 자세하게 알아둘 것)
    옛날 ) Apache서버(웹서버 - 정적처리)와 Tomcat(웹서버 포함하는 컨테이너 - 동적처리) 분리 돼 있었음

    • 웹 컨테이너 : servlet - api.jar, jsp - api.jar
      자바기반엔진이다.
    • IIS서버에서 서블릿 또는 스프링 지원하는가? 라고 묻는다면
      : IIS서버에서 서블릿 컨테이너가 지원되나요? 라고 되물을 것
  • 엔터프라이즈 서버 : JBOSS, JEUS, 웹스피어 -AWS-

    • 원격에 있는 클래스를 호출해서 사용 가능한 서버, 로그, 보안강점, 모니터링 시스템 - 로그파일 출력해서 기술면접 시험 봄

웹 서버 VS 웹 컨테이너

  • 웹 서버
    응답(Response)하는 쪽인 서버.
    클라이언트의 요청에 응답(데이터)을 보내는 컴퓨터 프로그램.
    데이터는 HTML문서, 컴퓨터에 저장된 리소스(자원)이다.

    • 가장 많이 사용되는 웹 서버 프로그램은 Apache, Nginx, Microsoft IIS 등이다.
  • 웹 컨테이너
    클라이언트의 요청에 따른 데이터를 데이터베이스에서 전달받아 웹 서버로 전달하는 프로그램.
    예) 패밀리 레스토랑에서 주문을 받아 주방에서 만든 음식을 서빙하는 종업원에게 전달하는 주방 보조웹 컨테이너, 음식을 서빙하는 종업원웹 서버

    • 기본 기능
      • 프로그램 실행 환경과 데이터베이스 접속 기능 제공
      • 여러 개의 트랜잭션 관리
      • 업무 처리를 위한 비즈니스 로직 수행
      • Web Service 플랫폼의 역할 수행
    • 웹 컨테이너는 jsp, php 등의 개발 언어를 읽고 포털 검색 결과와 같은 콘텐츠, 다소 복잡한 웹 응용 프로그램 등을 처리한다. <-> 웹 서버가 한 번 다운로드 되면 내용이 변하지 않는 HTML 문서와 같은 정적 컨텐츠 처리
    • 웹 서버 측에서 클라이언트의 요청을 받아 응답할 때, 요청에 필요한 데이터를 처리하거나 웹 서버에 전달하는 역할을 한다.
      • 따라서 데이터베이스 서버와 같이 작업을 수행하는 경우가 많다.
      • 일종의 중간 관리자로 웹 서버를 지원하는 역할(미들웨어)
  • WAS 서버는 원래 웹 컨테이너 프로그램을 이르는 말이었으나 요즘은 웹 컨테이너 + 웹 서버 기능까지 내장하고 있다.

  • 서버 규모가 커질 경우)

    • 웹 서버와 웹 컨테이너를 분리한다. 자원 이용의 효율성, 배포 및 유지보수의 편의성에 더 유리하기 때문이다.

어제 - eclipse

.classpath, .project : 로컬환경정보 - 이클립스가 생성해주는 파일
: workspace_jsp 배포 했을 때 -> nae2Gym 꺼내서 처리하면 에러가 뜨지 않음
: buildpath - 트러블 슈팅
: zulu11로 설치한 노트북 이슈

Today 2

JDBC API -> myBatis(ORM 매핑오픈소스 - if문 지원함, 동적쿼리를 지원함 - SQL문 그대로 사용) -> Hibernate(ORM 프레임워크 - SQL문 없다. 그런데 조회됨)
JPA(DB연동 마지막 목표) : 좋다 나쁘다 문제 아님. 장단점이 분명하다. 단점) 튜닝 안 됨. 복잡한 계산식은 SQL문 사용이 유리함.

Lombok

Lombok 이란?

Lombok(롬복)은 Java 라이브러리로 반복되는 getter, setter, toString 등의 메서드 작성 코드를 줄여주는 코드 다이어트 라이브러리이다. 보통 Model 클래스나 Entity 같은 도메인 클래스 등에는 수많은 멤버변수가 있고 이에 대응되는 getter와 setter 그리고 toString() 메서드 그리고 때에 따라서는 멤버변수에 따른 여러개의 생성자를 만들어주게 되는데, 거의 대부분 이클립스같은 IDE의 힘만으로 생성한다고 하지만 이 역시도 번거로운 작업이 될 수 있다. 뿐만 아니라 코드 자체가 반복되는 메서드로 인해 매우 복잡해지게 된다.

Lombok은 여러가지 어노테이션을 제공하고 이를 기반으로 코드를 컴파일과정에서 생성해 주는 방식으로 동작하는 라이브러리이다. 즉 코딩 과정에서는 롬복과 관련된 어노테이션만 보이고 getter와 setter 메서드 등은 보이지 않지만 실제로 컴파일된 결과물(.class)에는 코드가 생성되어 있다는 뜻.

왜 롬복을 사용하지?

getter/setter메소드를 추가하지 않아도 괜찮다
전변을 private으로 선언하였다 : 캡슐레이션(고유한 정보들을 외부에서 직접 수정하는 걸 막는다)

  • Lombok에서 제공하는 @Builder를 사용하면 파라미터 갯수나 타입을 일일이 맞추지 않고도 자유롭게 사용 가능하다
    • 사용이란 생성자의 파라미터 값을 통한 전역변수들의 초기화 작업

@Builder

  • Lombok에서 제공하는 @Builder를 사용하면 파라미터 갯수나 타입을 일일이 맞추지 않고도 자유롭게 사용 가능하다
    • 사용이란 생성자의 파라미터 값을 통한 전역변수들의 초기화 작업

👇BoardVO

package com.vo;
//JDBC API -> myBatis(ORM 매핑오픈소스 - if문 지원함, 동적쿼리를 지원함 - SQL문 그대로 사용) -> Hibernate(ORM 프레임워크 - SQL문 없다. 그런데 조회됨)
//JPA(DB연동 마지막 목표) : 좋다 나쁘다 문제 아님. 장단점이 분명하다. 단점) 튜닝 안 됨. 복잡한 계산식은 SQL문 사용이 유리함.
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
//왜 롬복을 사용하지?
//getter/setter메소드를 추가하지 않아도 괜찮다
//전변을 private으로 선언하였다 : 캡슐레이션(고유한 정보들을 외부에서 직접 수정하는 걸 막는다)

@Data //@Setter, @Getter
@NoArgsConstructor
public class BoardVO {
	private int b_no      =0;//     
	private String b_title   =null;//     
	private String b_writer  =null;//     
	private String b_content =null;//     
	private int b_hit    =0;//     
	private String b_date    =null;//     
	private String b_file    =null;//     
	//Lombok에서 제공하는 @Builder를 사용하면 파라미터 갯수나 타입을 일일이 맞추지 않고도 자유롭게 사용 가능하다
	//사용이란 생성자의 파라미터 값을 통한 전역변수들의 초기화 작업
	@Builder
	public BoardVO(int b_no, String b_title, String b_writer, String b_content, int b_hit, String b_date, String b_file) {
		super(); //디폴트 생성자 호출 : 왜냐하면 파라미터 갖는 생성자가 하나라도 있으면 디폴트 생성자를 제공하지 않음
		this.b_no = b_no;
		this.b_title = b_title;
		this.b_writer = b_writer;
		this.b_content = b_content;
		this.b_hit = b_hit;
		this.b_date = b_date;
		this.b_file = b_file;
	}
}

👇BoardVOTest

public class BoardVOTest {

	public static void main(String[] args) {
		//lombok 적용의 좋은 점을 알아보자.
		//lombok 적용되지 않은 경우) lombok 없으면 순서 지키지 않았을 때 에러 뜸.
		EmpVO evo = new EmpVO("나잘난"); //public EmpVO(int empno) //lombok 없으면 순서 지키지 않았을 때 에러 뜸.
		System.out.println("ename : "+evo.getEname());//나잘난
		//lombok 적용된 경우) 순서, 개수 맞추지 않고 자유롭게 사용 가능
		//BoardVO bvo = new BoardVO(5);
		BoardVO bvo3 = new BoardVO();
		bvo3.setB_title("제목333");
		String title = bvo3.getB_title();
		System.out.println(title);//제목333
		BoardVO bvo = BoardVO.builder().b_no(3).build();
		System.out.println(bvo.getB_no());//3
		System.out.println(bvo.getB_title());//null or ""
		BoardVO bvo2 = BoardVO.builder().b_no(30).b_title("제목1").build();		
		System.out.println(bvo.getB_no());//30
		System.out.println(bvo.getB_title());//제목1
	}

}
  • EmpVO는 파라미터로 "나잘난"을 받는 생성자를 사용하여 객체를 생성한다. Lombok을 적용하지 않은 경우, 순서나 개수를 지키지 않으면 에러가 발생한다. 그 후, getEname() 메서드를 통해 이름을 가져와 출력한다.

  • BoardVO는 Lombok의 @Builder 어노테이션을 사용하여 객체를 생성한다. 이를 통해 객체를 빌더 패턴을 사용하여 생성할 수 있다. 그 예로 bvo3는 b_title 속성만 설정하고, bvo는 b_no만 설정하며, bvo2는 b_no와 b_title을 설정한다.

  • 각 객체의 값을 출력하여, Lombok이 적용된 경우 빌더 패턴을 사용하여 특정 필드만 설정하거나, 순서를 신경쓰지 않고도 객체를 생성할 수 있다. 이를 통해 Lombok을 사용하면 코드가 더 간결해지고 유연성이 증가한다는 것을 확인할 수 있다.

XXXVO

  • VO(Value Object or DTO(Data Transfer Object) - 레거시 시스템에서 사용하는 이름)패턴은 객체와 테이블 사이의 매핑을 위해 시작된 클래스 설계이다.
  • 자바에서는 String인데 오라클에서는 Char, Varchar2 - 타입이 다르다. 실제 값은 동일한 타입이다

배포 위치에 대한 기준

/webapp/board

  • noticeList.jsp

/WEB-INF/jsp/board

  • url을 통해 접근이 불가한 경우 : 컨테이너를 경유해야만 접근 가능하다

ActionForward를 String으로 변경한다

ActionForward를 Object로 변경한다

  • ActionServlet(FrontController) BoardController
    • 너는 서블릿이지만 나는 아니다
    • 서블릿이 아니면 요청도 응답도 못 하는데 어떡하지?
      : Controller 인터페이스의 메소드 오버라이딩으로 이 문제를 해결한다(req, res 포함됨).
    • 나는 어디에서 인스턴스화가 진행되나요?
      : ActionServlet에서 한다.
    • Controller의 구현체 클래스는 누구인가?
      : XXXController이다. 즉, 여기서는 BoardController이다.
      : Controller controller = new BoardController();
      • 다형성 (fly( ) 호출했는데 어떤 경우는 날고 어떤 경우는 날지 못한다)
      • controller.execute(req, res); // 원본을 넘긴다 - 싱글톤
        이 장면에서 BoardController는 서블릿이 아니지만 요청객체와 응답객체를 누릴 수 있다 - 구조 설계 - 인터페이스와 클래스 설계하였다.

매핑 URL 패턴

@WebServlet으로 서블릿을 URL에 매핑할 때 사용 - 클래스 앞에

서블릿은 늦은 초기화를 사용한다
스프링은 이른 초기화를 사용한다. - 스프링은 서블릿을 발전시킨 것이다.
@WebServlet(urlPatterns={"/hello", "/hello/*"}, loadOnStartup=1)
미리 초기화를 해두고 싶은 서블릿에 붙일 수 있는 옵션임 - loadOnStartup

매핑 패턴 소개 - React Router사용하는 컨셉
아래 번호는 순번을 의미하므로 1번을 따져서 없으면 2번이 또 없으면 3번이 적용됨

  1. exact mapping - /basic/hello.do -> http://localhost/basic/hello.do

  2. path mapping - /basic/* ->
    -> http://localhost/basic/hello.do
    -> http://localhost/basic/hello
    -> http://localhost/basic/
    -> http://localhost/basic/test

  3. extension mapping - .do, .gd
    :확장자가 do로 끝나기만 한다면 내가 가로챌께
    -> http://localhost/basic/hello.do
    -> http://localhost/basic/login.do
    -> http://localhost/basic/logout.do

  4. default mapping - / - spring legacy 기본
    :위에서 부터 따져보다가 어디에도 해당되지 않으면 디폴트가 적용됨
    -> http://localhost/basic/hello.do
    -> http://localhost/basic/hello
    -> http://localhost/basic/
    -> http://localhost/basic/test

스프링에서는 @RequestMapping이 제공된다 - 메소드 앞에온다

@Controller - 컨트롤계층의 역할을 맡게됨 - 어노테이션(@) - annotation
:자바에서는 Reflection API를 지원하고 있음
-> 힙 영역에 로드되어 있는 클래스 타입의 객체를 통해서 필드/메소드/생성자를
접근제어자와 상관없이 사용할 수 있도록 지원하는 API
-> 컴파일 시점이 아닌 런타임 시점에 동적으로 특정 클래스의 정보를
추출해 주는 프로그래밍 기법을 지원
-> 주로 프레임워크 또는 라이브러리 개발시 사용됨
예) Spring DI(dependency Injection), Test프레임워크(JUnit), JSON 라이브러리

ActionServlet.java

package com.example.demo.pojo2;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;

import lombok.extern.slf4j.Slf4j;
//Restful API란 무엇인가?
//전송방식 : 바이너리 - UI솔루션이 지원하는 모드 중 한 가지
@SuppressWarnings("serial")
//@Slf4j : Logger를 쓰지 않고도 사용할 수 있다
public class ActionServlet extends HttpServlet {
	Logger logger = Logger.getLogger(ActionServlet.class);
	
	protected void doService(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		Controller controller = new BoardController();
	}
	@Override
	protected void doDelete(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doService(req, res);
	}
	//쿼리스트링, ?, 링크, header, 제한적임
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doService(req, res);
	}
	//body, 서버인터셉트 안 당함, 무조건 서버전달, 제한이 없음 - 바이너리 타입(첨부파일)
	//POST 방식 : enctype="multipart/form-data" - 바이너리 전달 - 문자+숫자 - 
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doService(req, res);
	}

	@Override
	protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// TODO Auto-generated method stub
		super.doPut(req, resp);
	}

}

BoardController.java

package com.example.demo.pojo2;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;

import com.example.demo.pojo1.ActionForward;

import com.example.demo.pojo1.NoticeController;
import com.example.demo.pojo1.NoticeLogic;
/*
 * upmu[] : 내려갈 때 -> ActionServlet -> BoardController로 연결될 때
 * -> 개선점(1-3버전) -> spring -> XXXHandlerMapping -> BoardController 클래스에서부터 메소드를 쪼갤 수는 없나?(현재는 if문으로 되어 있어 가독성, 재사용성 떨어짐)
 * pageMove[] : 올라올 때
 */
//@Controller : 스프링에서는 클래스 사이의 결합도를 낮추기 위해 상속(결합도가 높아지니까)을 포기하였다
//@RequestMapping(/notice/*) : 2번째 URL 매핑 방법
public class BoardController implements Controller {
	Logger logger = Logger.getLogger(BoardController.class);
	BoardLogic nLogic = new BoardLogic();//이른
	//@GetMapping("noticeList.gd") : 객체 주입 받으려면 ApplicationContext로부터 빈 관리를 받을 때만 사용 가능함 - req, res 주입해주기 때문에
	//public String noticeList(HttpServletRequest req, HttpServletResponse res) {}
	@Override
	public String execute(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		String upmu[] = (String[])req.getAttribute("upmu");
		String path = null;
		/*
		//전체조회일 때 : select / n건 - List<Map | VO> - list.jsp
		//상세보기와 응답페이지 이름이 달라서 메소드를 분리한다
		// 1) 배포위치가 WEB-INF 일 때 : /WEB-INF/jsp/(workname)/메소드이름 or upmu[1].jsp
		// 2) 배포위치가 webapp 일 때
		if(true) {
			return path = "1";
		}
		
		//상세조회일 때 : select / 1건 - Map or VO - read.jsp
		else if("boardDetail".equals("boardDetail")) {
			path = "redirect:2";//redirect
		}
		//공통분모 : 반환값이 int이다. commit과 rollback 대상이다
		//입력 | 수정 | 삭제인 경우 모두 1이라면 어느 페이지로 이동할까? - 목록(select: /board/boardList.gd2 - 이 뒤에서 forward 처리해야 함)을 보여주세요
		//등록일 때 : post 방식 - insert : 1(수정성공) or 0(수정 안 됨)
		else if("boardInsert".equals("boardInsert")) {
			path = "redirect:3";
		}
		
		//수정일 때 : get, put 방식(모든 방식을 doService로 묶었기 때문에 큰 의미는 없다) - Restful 상징성을 표현함 - update : 1(수정성공) or 0(수정 안 됨)
		else if(true) {
			path = "redirect:4";
		}
		
		//삭제일 때 : delete 방식 - 스프링 수업 땐 분리해서 할 것임 - delete : 1(수정성공) or 0(수정 안 됨)
		else if(true) {
			path = "redirect:/board/boardDetail";
		}
		*/
		return path;
		//return "redirect:/notice/noticeList.jsp"; //webapp
		//return "forward:/notice/noticeList.jsp"; //webapp - 요청이 유지되는 것으로 판단해서 서블릿이 쥐고 있는 값을 jsp에서도 사용할 수 있다.
		//return "/notice/noticeList"; //WEB-INF/jsp/notice 아래
	}

}

BoardLogic.java

package com.example.demo.pojo2;

import org.apache.log4j.Logger;

//나는 Controller라는 인터페이스를 implements 하지 않아서 어떤 제약조건(추상 메소드(execute(req, res) - Tomcat이 제공해 줌. 
//		단, 서블릿이어야 한다 - 그런데 서블릿 아니어도 스프링은 지원해줌)도 해당 안 됨
//나는 순수한 자바 클래스이다(순수성 - 원자성 : 다른 이종간의 결합에서 사용 가능한 상태라는 것이 장점).
public class BoardLogic {
	Logger logger = Logger.getLogger(BoardLogic.class);
} 

정리

  • forward : select인 경우에 해당 - 어떤 서버가 쥐고 있는 정보를 유지해야한다

    • url은 바뀌지 않는다. 화면은 바뀜.
    • 기존 요청이 단절되지 않은 상태. a.jsp에서 쥐고 있는 값(list, map...)을 b.jsp에서도 유지, 접근 할 수 있다
  • redirect

    • url 바뀜. 화면도 바뀜
    • 기존 요청 단절된 상태. a.jsp 값을 b.jsp에서 접근할 수 없다.
      • 새로운 요청이 시작됐다.
  • upmu[] : 내려갈 때
    pageMove : 올라올 때

  • 전체 문자열 -> "redirect:/workname-컨트롤클래스이름결정/메소드이름(if문 조건문)
    pageMove[]
    pageMove[0] = "redirect" or "forward"
    pageMove[1] = "/notice/noticeList.jsp" or "/board/boardList.jsp"
    루트 태그 떼어내고 확장자를 떼어내면 notice/noticeList가 남음 -> split, splice를 통해 둘도 구분할 것

0개의 댓글