본문 바로가기
JSP/Java Script

2024_07_24_수

by 알케니브 2024. 7. 24.

오늘의 코딩순서

1.프로젝트 배포 방법

2. (폴더: och16)

jquery.zip
0.08MB

 

Board 익스포트.sql
0.01MB

  • och10폴더의 자카르타 파일 4개, context.xml를 lib 폴더에 복붙함
    ↳ context.xml은 DBCP를 위해 걸어두는 것!
  • webapp 폴더에 images, sub2 폴더 만듬
  • Board.sql을 메모장으로 열어서 내용 복사하고 Oracle에 넣어 커밋해서 BOARD TBL 만들기

 

메인 페이지 ↓↓↓

http://localhost:8181/och16/list.do

 

( 줌 강의 4:55~5:03, 5:08~5:16, 5:47~)

  • (dao 패키지)Board.class + BoardDao.class (현장 HW)
  • (service 패키지) CommandProcess.class + (control 패키지) Controller.servlet + web.xml
    + (lib 폴더) command.properties.file + (service 패키지) ListAction.class
  • list.jsp (타이핑 조금만 함)

오늘의 코딩 포인트

(폴더: och16)

  • Board.class 
package och16.dao;

import java.util.Date;

public class Board {
	private int num;
	private String writer;
	private String subject;
	private String content;
	private String email;
	private int readcount;
	private String passwd;
	private int ref;
	private int re_step;
	private int re_level;
	private String ip;
	private Date reg_date;
	public int getNum() {
		return num;
	}
	public void setNum(int num) {
		this.num = num;
	}
	public String getWriter() {
		return writer;
	}
	public void setWriter(String writer) {
		this.writer = writer;
	}
	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 getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
	public int getReadcount() {
		return readcount;
	}
	public void setReadcount(int readcount) {
		this.readcount = readcount;
	}
	public String getPasswd() {
		return passwd;
	}
	public void setPasswd(String passwd) {
		this.passwd = passwd;
	}
	public int getRef() {
		return ref;
	}
	public void setRef(int ref) {
		this.ref = ref;
	}
	public int getRe_step() {
		return re_step;
	}
	public void setRe_step(int re_step) {
		this.re_step = re_step;
	}
	public int getRe_level() {
		return re_level;
	}
	public void setRe_level(int re_level) {
		this.re_level = re_level;
	}
	public String getIp() {
		return ip;
	}
	public void setIp(String ip) {
		this.ip = ip;
	}
	public Date getReg_date() {
		return reg_date;
	}
	public void setReg_date(Date reg_date) {
		this.reg_date = reg_date;
	}
	
	
	
}

※ 아래 코딩은 코딩한 순서가 아닌, 로직이 작동하는 순서에 가깝게 작성함!

1. 크롬 같은 웹에서 요청(Request)이 들어오면 가장 먼저 실행됨

  • web.xml ==>  여기까지는 단순한  String에 지나지 않음
    • <servlet-class>control.Controller</servlet-class>에서 '.' 앞은 서블렛의 패키지명, 뒤는 서블렛의 클래스명
      즉 서블렛을 Controller로 만들어주겠다, Controller의 실체
    • <servlet-name>Controller</servlet-name>으로 controller 지정하여, servlet 프로그램의 서버라고 선언
    • <param-name>config</param-name>으로 초기값을 config라는 파라미터 명으로 지정
      config의 값(value)은 /WEB-INF/command.properties로 지정
    • <param-value>/WEB-INF/command.properties</param-value>는 congig의 변수,
      config 파라미터를 command.propertiesinit해서 넘김

      Tip)
      • https에서 s 없애야 오류 없어지는 경우가 많음 => ∵최신 버전을 아직 못받아들여서
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="https://jakarta.ee/xml/ns/jakartaee" xsi:schemaLocation="http://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd" id="WebApp_ID" version="6.0">
  <display-name>och16</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.jsp</welcome-file>
    <welcome-file>default.htm</welcome-file>
  </welcome-file-list>
  <servlet>
    <description></description>
    <display-name>Controller</display-name>
    <servlet-name>Controller</servlet-name>
    <servlet-class>control.Controller</servlet-class>
    <init-param>
    	<param-name>config</param-name>
    	<param-value>/WEB-INF/command.properties</param-value>
    </init-param>
  </servlet>
  <servlet-mapping>
    <servlet-name>Controller</servlet-name>
    <url-pattern>*.do</url-pattern>
  </servlet-mapping>
</web-app>

 

2. web.xml을 통해 요청(Request)를 받아들인다

    • Controller.servlet⭐⭐⭐⭐⭐ ==> 정확히는 Controller 역할을 하는 Servlet임

1) web.xml에서 init된 파라미터 config를 해주었기 때문에 servlet에서 끌어당겨 Controller에서 쓸 수 있음

2) init: servlet에서 작성한 controller 작동 script

1. init String props=> /WEB-INF/command.properties

  • /WEB-INF/command.properties라는 파라미터 값은 config, 다음으로 props에 들어감
	public void init(ServletConfig config) throws ServletException {
		 // web.xml에서 propertyConfig에 해당하는 init-param 의 값을 읽어옴
		String props = config.getInitParameter("config");
		// /WEB-INF/command.properties
		System.out.println("1. init String props=> "+ props);	// /ch16/com
		Properties		pr = new Properties();
		FileInputStream	f = null;

 

2. init String configFilePath=> C:\jsp\jspSrc17\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\och16\WEB-INF\command.properties

  • getRealPath를 통해 c:\jsp\jsp17\.metadata/.plugins/org.eclipse.wtpwebapps\och16\WEB-INF\command/properties를 받아옴
    => 받아오는 이유는 웹으로 배포를 할 때 사용자의 드라이브에는 이클립스도, 파일도 없으니 메타데이터를 따라가는 배포데이터를 만들어줌 => 이때 만들어진 데이터가 configFilePath
  • 윗부분 까지는 String에 지나지 않았다면, 이제 메모리에 업로드를 해야함
    f = new FileInputStream(configFilePath);을 통해 configFilePath를 파일로 바꿔준 뒤,
    properties의 값을 받은 pr.load(f);를 통해 파일명을 주며 메모리에 업로드함
    이후 try-catch 문을 지나 close를 거쳐 업로드가 완료됨
try	{
			String configFilePath = config.getServletContext().getRealPath(props);
			System.out.println("2. init String configFilePath=> "+ configFilePath);	// /och16/com
			f = new FileInputStream(configFilePath);
			// Memory upload
			pr.load(f);		
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (f != null)
				try {
					f.close();
				} catch(IOException ex) {
					System.out.println("IOException ex.getMessage()->"+ex.getMessage());
				}
		}

3. init command => /list.do

  • 메모리에 올라간 pr(properties)에는 Map 방식을 통해 command.properties.file에 있는 key값(여기서는 /list.do)을 받아옴 ++(String)부분 설명 추가하기
//		list.do		/content.do
		//		/list.do = service.ListAction		
		//		/content.do = service.contentAction
		Iterator keyIter = pr.keySet().iterator();

 

4. init className=> service.ListAction

  • 가져온 key값을  keyIter에 넣고, hasNext (rs.next()와 비슷한 기능을 함)를 거치면 향상형 for문처럼 하나씩 통과함
    ↳ hasNext(): 
  • key 값을 command에 넣고 => command가 getProperty를 가져와 value값의 이름, 즉 serviceListAction을 ClassName에 넣음
while (keyIter.hasNext())	{
			String command = (String) keyIter.next();
			String className = pr.getProperty(command);
			System.out.println("3. init command => "+ command); // /och16/com
			System.out.println("4. init className=> "+ className);

3. 요청(Request)한 url 주소를 따라 뒤의 value값이 Service에서 수행되도록, Controller에 짜인 로직에 따라 value값이 인스턴스화 되어서 CommandProcess로 넘어간다

3) try문 거치기 

  • ClassName에 넣은 값을 commandClass를 통해 Class명으로 만들어줌
  • getDeclaredConstructor을 통해 CommandProcess를 인스턴스화 해줌
    이때 CommandProcess를 인스턴스화 해주는 이유는 CommandProcess 가 서비스에 있기 때문이며, 상속받은 클래스들(ListAction, ContentAction 등)을 대신해서 While문을 다 받아줄 수 있기 때문
    이는 ListAction la = new ListAction();과 같은 성능을 지니지만 효율은 더 좋음⭐
  • commandMap에 저장되는데 괄호 안의 앞의 값인 command에는 String의 /list.do가 들어가고, 뒤의 값인 commandInstance에는 CommandProcess의 자식인  service.ListAction를 인스턴스화 한 값이 들어가고, 메모리에 값들이 올라감
    try	{
            //	ListAction la = new ListAction();
            //소멸 Class
        //	Class	commandClass = Class.forName(className);
        //	Object	commandInstance = commandClass.newInstance();
            //new Class  ==> 제네릭의 요점은 클래스 유형을 모른다

            Class<?> commandClass = Class.forName(className);	//해당 문자열을 클래스로 만든다
            CommandProcess commandInstance =
                    (CommandProcess)commandClass.getDeclaredConstructor().newInstance();

            //			list.do		service.ListAction
            //			contend.do	service.ContentAction
            commandMap.put(command, commandInstance);

        } catch (Exception e)	{
            e.printStackTrace();
        }

3. init command => /list.do (한 번 더 돌려서 위의 3번과 같은 sysout이 나온것)
4. init className=> service.ListAction (한 번 더 돌려서 위의 4번과 같은 sysout이 나온것)

  • 위의 작업을 전부 거치고 나서 while문을 한 번 더 돌림 ∵ 이후 추가한 /content.do 때문
    => 즉, 추가할 때마다 한 번씩 더 돌아감
  • 이렇게 긴 처리가 된 Servlet은 Map방식을 통해서 private Map<String, Object> commandMap = new HashMap<String, Object>(); String에는 key 값, Object에는 value값이 들어가 Object에 들어간 주소를 발동시킴
    이렇게 하면 위의 Map 커맨드에 어떤 커맨드가 들어와도 큰 수정 없이 발동시킬 수 있음
    즉, new보다 효율적임
public class Controller extends HttpServlet {
	private static final long serialVersionUID = 1L;
	private Map<String, Object> commandMap = new HashMap<String, Object>();

4. Controller 에서 추가된 Object들은 CommandProcess.class를 통해 Service와 정보(request, response)를 주고받는다

  • CommandProcess.class ==> Service에 있음
    Tip)
    • requestpro: 여기에 비즈니스 로직이 들어감
      design pattern관련하여 역할 써두기
package och16.service;

import java.io.IOException;

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

public interface CommandProcess {
	public String requestPro(HttpServletRequest  request, 
							 HttpServletResponse response)
							 throws ServletException, IOException;

}

5. Controller와 Service는 Get방식이나 Post방식을 통해 request와 response 값을 주고받는다

4) doGet, doPost

1-1. requestServletPro URI command=> /och16/list.do
1-2. requestServletPro URL command3=> http://localhost:8181/och16/list.do

  • URI 자원에 대한 통합 자원 식별자, URL은 자원의 위치(주소)와 식별자를 동시에 보여줌
  • init처리가 된 후 doGet, doPost를 만나면 requestServletPro가 호출되어 실행됨
  •  requestServletPro가 실행되고 나면 getRequestURI가 실행되는데, 이때 URI는 /och16/list.do를 뜻하고, URL은 http://localhost:8181/och16/list.do을 뜻함
    이들을 각각 command, command3 객체에 넣어줌

2. requestServletPro command substring=> /list.do

  • 저장된 /och16/list.do 에서 list.do만 사용하고 싶으므로 subString을 사용하여 contextPath만큼 잘라냄
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		//위의 request와 response가 아래에 입력됨
		requestServletPro(request, response);	
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		requestServletPro(request, response);
	}

	protected void requestServletPro(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String			view = null;
		CommandProcess	com = null;
		String command = request.getRequestURI();
		StringBuffer command3 = request.getRequestURL();
		System.out.println("1-1. requestServletPro URI command=> "+ command);	// /och16/list.do
		System.out.println("1-2. requestServletPro URL command3=> "+ command3);	// /och16/list.do
		command = command.substring(request.getContextPath().length());
		System.out.println("2. requestServletPro command substring=> "+command);	// /och16/

 

5) try문 거치기

  • command.properties.file
    Tip) 
    • 프로젝트를 분할할 수 있음 => 0729 9시 리뷰 참고해서 더 추가하기
    • Map 방식에 따라, '='의 왼쪽이 key가 되고 오른쪽이 value값이 됨
    •  properties
    • Map 방식: key와 value
/list.do=service.ListAction
/content.do=service.ContentAction

3. requestServletPro command=> /list.do
4. requestServletPro com=> service.ListAction@4114cf1e

  • list.do는 command.properties.file의 key값, commandMap에 key값을 넣으면 value값인 service.ListAction이 불려와서 인스턴스인 com에 저장됨
    com이 인스턴스인 증거는 콘솔창을 보면 @와 숫자로 이루어진 로직이 보임, 이는 hash코드를 의미하며 이는 인스턴스 객체를 가리킴
  • 'service.ListAction@숫자'가 들어간 com이 requestpro에 들어감
    => requestpro를 하는 이유
    public String requestPro(HttpServletRequest  request, 
     HttpServletResponse response)
     throws ServletException, IOException;

    이 때문에 ListAction.class, 즉 Service 모델이 실행됨 
try	{
			//service.ListAction Instance
			com = (CommandProcess) commandMap.get(command);
			System.out.println("3. requestServletPro command=> "+ command);		// /och16/
			System.out.println("4. requestServletPro com=> "+ com);		// /och16/
			//		com --> service.ListAction@32a22787
			view = com.requestPro(request, response);
			System.out.println("5. requestServletPro view=> "+ view);	// /och16/		
			
		} catch (Exception e)	{
			throw new ServletException(e);
		}

6. Service 모델은 DAO를 호출하여 로직을 작동시킨다

ListAction Service start...

  • requestPro로 인해 Service 모델이 작동되고, 인스턴스화 된 value값이 넘어와 commandProcess를 상속받음
    이로 인해 어떤 Service들이던 밑에 써넣으면, DAO와 값을 주고 받을 수 있게 됨
    따라서 아래 DAO logic이 작동되면 BoardDao가 호출되고 연결되어 로직이 작업됨
    로직의 결과값을 받아서 관련된 파라미터 값들을 전부 request.setAttribute에 저장함

7. 작동된 DAO 로직과 연결되어 DML작업을 통해 DB와 연결한 뒤 데이터를 주고 받는다.

  • BoardDao.class >>  데이터베이스와의 연결을 관리하는 싱글턴 패턴의 DAO 클래스
    Tip)
    • private static BoardDao instance;
      • private: 접근 제어자를 사용하여 외부에서 직접 접근하거나 수정하지 못하도록 함
      • BoardDao: 클래스의 유일한 인스턴스를 저장하는 static 변수
    • private BoardDao()
      • BoardDao 클래스의 생성자
      • private 접근 제어자를 사용하여 외부에서 이 클래스를 직접 인스턴스화 하지 못하게 함
        이는 Singleton 패턴을 유지하기 위한 중요한 부분
    • public static BoardDao getInstance()
      • BoardDao 클래스의 인스턴스를 반환하는 static 메서드
      • public 접근 제어자를 사용하여 외부에서 이 메서드를 통해 유일한 인스턴스를 얻을 수 있게 함
      • 인스턴스가 아직 생성되지 않았다면, new BoardDao()를 통해 생성함
    • private Connection getConnection()
      • 데이터베이스와 연결을 설정하고 Connection 객체를 반환하는 메서드
      • private 접근 제어자를 사용하여 외부에서 직접 호출할 수 없도록 함
      • 이 메서드는 주로 BoardDao 클래스 내부에서 데이터베이스와의 연결이 필요할 때 사용됨
package dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;

//(0724)현장 HW1. Singleton + DBCP
public class BoardDao {
	private static BoardDao instance;
	private BoardDao() {
	}

	public static BoardDao getInstance() {
		if (instance == null) {	
			instance = new BoardDao();		
		}
		return instance;
	}
	
	private Connection getConnection() {
		Connection conn = null;
		try {
			Context ctx = new InitialContext();
			DataSource ds = (DataSource)
				ctx.lookup("java:comp/env/jdbc/OracleDB");
			conn = ds.getConnection();
		}catch(Exception e) { 
			System.out.println(e.getMessage());	
		}
		return conn;

	}

 

8. DAO와 DB가 주고받은 결과값(result 값)이 Controller에 return되어 Service(

##.jsp)모델이 실행되면 result 값인 ##.jsp를 Controller에 전달한다

↳ 이때 View가 정해지는데 사실 Controller에 전해지기 전, Service(예시_ ListAction.class )에서 정해진거나 다름없다

==> ListAction.class의 return 값이 "list.jsp"였기 때문

9. Service에서 Controller으로 이동할 때 작동하는 메서드는 RequestDispatcher.
페이지로 이동시킨뒤 forward 시켜주면 view로 이동이 완료된다.

5. requestServletPro view=> list.jsp

		RequestDispatcher dispatcher = request.getRequestDispatcher(view);
		dispatcher.forward(request, response);

 

Tip)

  • 왜 이렇게 힘들게 코딩하느냐?
    => ListAction la = new ListAction(); 처럼 선언하고 짜고나면 controller의 값을 전부 수정해야 한다
  • init
  • getInitParameter
  • properties⭐⭐⭐: Map방식에서 쓰이는 클래스,  key와 value의 쌍으로 이루어진 데이터의 집합
  • getRealPath

 

 

    •  

 

'JSP > Java Script' 카테고리의 다른 글

2024_07_26_금  (0) 2024.07.26
2024_07_25_목  (0) 2024.07.26
2024_07_23_화~ 07_24_수  (0) 2024.07.23
2024_07_22_월  (0) 2024.07.22
2024_07_19_금 ⭐⭐⭐  (0) 2024.07.19