본문 바로가기

programming/Java [notion 정리본 업로드]

JSP/SERVLET 프로젝트 생성 시 Dependencies

 


  • LogForJ (?) ⇒ 로그 남기는 라이브러리 (설정을 .xml 파일로 함 ⇒ resources 내에 넣을 것)
  • 내부 폴더 구조 /test/ 는 단위 테스트를 위한

프로젝트 전체 폴더 구조


라이브러리 설치

  • 간단한 블로그 프로젝트
  • 사용할 라이브러리들 다운 받을 것

프로젝트 디펜던시 설정하기 Logging 관련

Library Description

log4j-core The Apache Log4j Implementation
log4j-api The Apache Log4j API
log4j-slf4j2-impl The Apache Log4j SLF4J 2.0 API binding to Log4j 2 Core
slf4j-api The slf4j API
  1. Maven Central Repository - Sonatype 페이지에서 log4j-core 검색
  2. Maven Central Repository - Sonatype 페이지에서 log4j-api 검색
  3. Maven Central Repository - Sonatype 페이지에서 log4j-slf4j2-impl 검색
  4. Maven Central Repository - Sonatype 페이지에서 slf4j-api 검색
    • The slf4j API
    • 다운 페이지
    • slf4j-api의 2.대 버전은, log4j의 2.21 버전과 호환이 되지 않기 때문에(컴파일 자체 실패) 1.7.36 사용
      • : pom.xml에 버전 명을 1.7.36으로 변경
  • log4j 는 아파치에서 만들었고, slf4j 같이 log4j 관련 의존성들은 slf4j에서 만들어서 그룹명이 상이함
  • Log4j2 홈페이지 가기 - Apache log4j2 > configuration > logging 속성들 설정할 수 있음
    • Status Messages https://logging.apache.org/log4j/2.x/manual/configuration.html#status-messages
    • /src/main/resources/log4j2.xml 파일
      • %d, %date : 로그가 발생한 날짜와 시간
      • %p, %level : 로그 레벨. all < debug < info < warn < error < fatal < off
      • %c, %logger : 로그를 쓰는 로거(logger)의 이름
      • %m, %msg, %message : 로그 메세지
      • %n : 줄바
      • %L, %line : 로그가 발생한 소스의 라인 번호
    • <?xml version="1.0" encoding="UTF-8" standalone="no"?> <Configuration> <Appenders> <Console name="console" target="SYSTEM_OUT"> <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5p [%-40.40logger] %m%n"/> </Console> </Appenders> <Loggers> <Root level="debug" additivity="false"> <AppenderRef ref="console"/> <!-- Console 태그 내에 정의한 이름을 ref해주어야 함. --> </Root> </Loggers> </Configuration>

프로젝트 디펜던시 설정하기 Junit 관련

  1. Junit-jupiter-engine
  2. Jupiter-api
  • assertionNull, assertionNotNull 같은 개발자가 예측한 결과와 동일한 결과를 보이고 있는지를 확인할 수 있다.

프로젝트 디펜던시 설정하기 OJDBC 관련

  1. Oracle jdbc lib
  2. HikariCP

JUnitTest

  • select 의 결과가 ArrayList로 만들어지느냐만 하고 싶은데 FE 까지 모두 봐야 된다고…? ⇒
<dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>5.10.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>5.10.1</version>
            <scope>test</scope>
        </dependency>
  • scope 에 test를 설정해주면 /test 경로 내에 있는 파일만 사용 가능하다.
  • JUnit 테스트(자바 단위 테스트)를 하기 위한 클래스 작성
  • main 메세지를 작성하지 않음
  • @Test 에너테이션을 사용한 메서드를 작성
  • Run AS → JUnit Test를 실행하면, junit-jupiter-engine에서 테스트 메서드를 실행
  • Test 메서드 작성:
    • @Test 에너테이션을 사용
    • public void로 선언
4.0.0

com.itwill
lb_contacts
1.0-SNAPSHOT
lb_contacts
war

UTF-8
11
11
5.9.2
    
jakarta.servlet.jsp.jstl
jakarta.servlet.jsp.jstl-api
3.0.0
        
org.junit.jupiter
junit-jupiter-api
5.10.1

org.junit.jupiter
junit-jupiter-engine
5.10.1        
        
org.glassfish.web
jakarta.servlet.jsp.jstl
3.0.1
                
org.apache.logging.log4j
log4j-core
2.21.1
        
org.apache.logging.log4j
log4j-api
2.21.1
        
org.apache.logging.log4j
log4j-slf4j2-impl
2.21.1
        
org.slf4j
slf4j-api
2.0.9
        
com.oracle.database.jdbc
ojdbc11
23.2.0.0
            
org.apache.maven.plugins
maven-war-plugin
3.3.2
CREATE TABLE POSTS (
    ID NUMBER(10),
    TITLE VARCHAR2(100 CHAR) NOT NULL,
    CONTENT VARCHAR2( 4000 CHAR) NOT NULL,
    AUTHOR VARCHAR2(30 BYTE) NOT NULL,
    CREATED_TIME TIMESTAMP DEFAULT SYSTIMESTAMP,
    MODIFIED_TIME TIMESTAMP DEFAULT SYSTIMESTAMP,
    CONSTRAINT POSTS_PK PRIMARY KEY (ID)
);

INSERT INTO POSTS (TITLE, CONTENT, AUTHOR) VALUES ('test', 'Servlet/Jsp Connection Pool', 'admin' );
rollback;
commit;
<%@ page language="java" contentType="text/html; charset=${encoding}"
    pageEncoding="${encoding}" trimDirectiveWhitespaces="true" %>

${cursor}

Mac

  • 위 버전 : Jakarta EE 10버전 ⇒ Tomcat 버전인것임
  • Servlet ⇒ 웹 버전 어떻게 할 거냐고 물어봤던…

DTO (Data Transfer Object)

계층 간 데이터 전달 할 때 사용하는 객체를 사용해도 되고,

  • Post Model Class를 따로 사용해도 되지만, DTO를 따로 사용할 것
  • Controller, Service, Dao 간 전달할 때 사용한다고

💡 주요 차이 : DB의 테이블과 완전 똑같은 형태로 만들어야 한다. VS

 

PRG 패턴

Post → redirect → Get

<aside> 💡 리팩터링을 합니다!

  • (repository 폴더 내) dao의 메서드들은 DB와의 연결 시 Connection, Stateement, ResultSet(nullable)을 사용한다,
  • 사용한 위 3가지 리소스들은 finally 구문에서 모두 해제해주어야 하는데, try {} catch{} finaaly{} 구문 내에 다시 try-catch 구문이 등장하므로 매우 복잡해짐
Connection conn = null;
        PreparedStatement stmt = null;
        ResultSet rs = null;

        try {
            conn = ds.getConnection();
            stmt = conn.prepareStatement(SQL_SELECT);
            rs = stmt.executeQuery();

            while (rs.next()) {
                list.add(makePostInstance(rs));
            }

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                rs.close();
                stmt.close();
                conn.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }

        }

리소스 해제 메서드 만들기

private void closeResources(Connection conn, Statement stmt) {
        closeResources(conn, stmt, null);
    }

    private void closeResources(Connection conn, Statement stmt, ResultSet rs) {
        try {
            if (rs != null) {
                rs.close();
            }
            if (stmt != null) {
                stmt.close();
            }
            if (conn != null) {
                conn.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
  • 오버로딩 사용

</aside>

<aside> ♻️ input box

<form style="display:inline" action="${postDeleteUrl}" method="post">
            <input type="hidden" name="id" value="${post.id}"/>
            <input type="submit" value="삭제하기"/>
</form>
  • input type=”hidden” 의 경우, display:none과 동일한 효과 </aside>

시나리오

HTML에서 textarea

textarea의 innerHtml 과 value는 다름

innerHtml ⇒

value ⇒

로그인 로그아웃

  • 로그인 기능은 상당히 까다로운 작업
  • 로그인하고 나면 로그인 한 상태로 지속되고 해당 유저에게 맞는 페이지를 보여줌
  • 로그인을 하게되면 보던 페이지로 다시 되돌아가야됨.
  • **FILTER** 인터페이스 : 클라이언트의 상태에 따라 각 요청들의 권한 유무를 체크할 수 있음
  • 로그인 시 쿼리 스트링으로 로그인 버튼을 누른 해당 페이지의 요청 주소를 쿼리 스트링으로 보낸다.

FILTER

package com.itwill.jsp1.filter;

import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpFilter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebFilter(filterName = "filter", urlPatterns = {"/*"})
public class filterEx1 extends HttpFilter {

    public filterEx1() {
        System.out.println("생성자 FilterEx1");
    }

    @Override
    public void destroy() {
        System.out.println("FilterEx1::destroy() 호출");
    }

    @Override
    protected void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain chain)
        throws IOException, ServletException {
        System.out.println("------- FilterEx1: doFilter() 호출 전");
        System.out.println(req.getRequestURI());
//      pass the request along the filter chain
        chain.doFilter(req, res); // ------ (1)

        System.out.println("------- FilterEx2: doFilter() 호출 후");
    }

    @Override
    public void init(FilterConfig config) throws ServletException {
        System.out.println("------- filterEx1::init() 호출");
        super.init(config);
    }
}
  1. annotation을 사용하면 필터 순서를 지정하지 못하기 때문에, web.xml에 작성하여 순서를 지정해주는 것이 좋다.

[🐔] Cookie And Session

<aside> 💡

쿠키

  • 웹 브라우저가 저장하는 데이터
  • 동작방식
    • 웹 브라우저의 최초 요청 시 웹 서버는 쿠키를 생성해서 브라우저로 전송
    • 웹 브라우저는 쿠키를 저장
    • 웹 브라우저가 같은 서버에 접속할 때는 저장된 쿠키를 요청에 실어서 보냄
  • 쿠키의 구성 요소
    • 이름 : 각각의 쿠키를 구별하는데 사용되는 이름
    • 값 : 쿠키의 이름에 저장할 값
    • 유효 시간 : 쿠키 유지 시간
    • 도메인 : 쿠키를 전송할 도메인
    • 경로 : 쿠키를 전송할 요청 경로
  • 쿠키 생성 및 전송 : new Cookie(”name”, ”value”);
    • 쿠키에 필요한 설정 : setValue(String), setMaxAge(int), setDomain(String), setPath(String), setSecure(boolean), ….
    • 응답에 쿠키를 포함시켜서 클라이언트에게 전송 : response.addCookie()
  • 웹 브라우저가 보낸 쿠키의 사용
    • 요청에서 쿠키를 가져옴 : req.getCookie
    • 배열을 리턴
    • 이름.값의 쌍으로 이루어진 쿠키들의 배열에서 정보 추출
      • Cookie.getName(), Cookie.getValue()

세션

  • 클라이언트와의 상태를 유지하기 위해 웹 서버에서 웹 컨테이너에 저장하는 정보
    • 웹 브라우저마다 1개씩 생성되어 웹 컨테이너에 저장
    • 웹 브라우저와 웹 서버의 상태 유지가 훨씬 안정적
    • 쿠키가 가지고 있는 보안상의 문제를 해결
  • 웹 서버는 각각의 웹 브라우저로부터 발생한 요청에 대해 특정한 식별자를 부여
    • 예 : JSESSIONID
    • 이 식별자를 사용해서 세션을 구분하고 유지 및 사용할 수 있음
      • 식별자를 알아서 구분하고, 해당 식별자들에 관한 정보들을 각각 </aside>

로그아웃

  1. 세션에 저장된 로그인 관련 정보 삭제
  2. 세션 객체 무효화

url의 queryString에 url이 포함될 경우,

Query parameter가 포함되었을 때, parameter로 들어가는 url에 인코딩하여 보내야 한다. 그렇지 앟을 경우, 쿼리 스트링의 구분자인 ? 가 중복으로 나타나여 문제가 생길 수 있다.


Servlet 으로 프론트(JSP)와 소통하기

  • 오해 : Servlet은 본래 JSP로 프론트 서버를 만들기 위해 사용하는 프로그램이다.
    • 추가1+ : PrintWriter out = resp.getWriter()**;**는 화면을 그릴 수 있게 해주는 메서드이다.
  • 서블릿에서 out의 print 메서드에 들어가는 값은, 프론트로 보내는 데이터를 보낼 뿐이지 화면에 그려주는 목적의 메서드가 아님.
    • 화면에 그려지는 기능은, 데이터를 받은 브라우저가 단순 문자열을 받았을 때 데이터를 해결하는 방법일 뿐.

'programming > Java [notion 정리본 업로드]' 카테고리의 다른 글

중첩 클래스와 람다  (0) 2024.04.15
입출력 스트림  (0) 2024.04.15
Collection  (0) 2024.04.13
예외처리 (Exception)  (0) 2024.04.13
추상클래스와 인터페이스  (0) 2024.04.13