1.  MyBatis 

스프링 프레임워크의 중요한 특징 중 하나는 다른 프레임워크들을 쉽게 결합해서 사용할 수 있다는 점이다. 이것은 스프링 프레임워크가 웹이나 데이터베이스와 같이 특정한 영역을 구애받지 않고 시스템의 객체지향 구조를 만드는데 이용된다는 성격 때문.

 

데이터베이스와 관련해서 스프링 프레임워크는 자체적으로 'spring-jdbc'와 같은 라이브러리를 이용해서구현할 수도 있고, MyBatisJPA 프레임워크를 이용하는 방식도 존재


💫  MyBatis는 'Sql Mapping Framework'라고 표현

  • 'Sql Mapping'이라는 단어가 의미하는 바는 SQL의 실행 결과를 객체지향으로 '매핑'해 준다는 뜻
  •  MyBatis를 이용하면 기존의 SQL을 그대로 사용할 수 있고 다음과 같은 점들이 편리해짐
  PreparedStatement / ResultSet의 처리 : 기존에 프로그램을 작성해서 하나씩 처리해야 하는 파라미터나 ResultSet의 getXXX()를 MyBatis가 알아서 처리해 주기 때문에 기존에 비해서 많은 양의 코드를 줄일 수 있음
  Connection / PreparedStatement / ResultSet의 close() 처리 : MyBatis와 스프링을 연동해서 사용하는 방식을 이용하면 자동으로 close() 처리할 수 있음
  SQL의 분리 : MyBatis를 이용하면 별도의 파일이나 어노테이션 등을 이용해서 SQL을 선언함. 파일을 이용하는 경우에는 SQL을 별도의 파일로 분리해서 운영이 가능  ➡️ 자바 코드에 쿼리문을 넣지 않아도 됨

 

1)  MyBatis와 스프링의 연동 방식


👻  MyBatis는 단독으로도 실행이 가능한 완전히 독립적인 프레임워크이지만, 스프링 프레임워크는 MyBatis와 연동을 쉽게 처리할 수 있는 라이브러리와 API들을 제공
👻  스프링에서 제공하는 라이브러리를 이용하는지 여부에 따라서 다음과 같은 방식 중에 하나로 개발이 가능

  • MyBatis를 단독으로 개발하고 스프링에서 DAO를 작성해서 처리하는 방식
    ➡️  기존의 DAO에서 SQL의 처리를 MyBatis를 이용하는 구조로써 완전히 MyBatis와 스프링 프레임워크를 독립적인 존재로 바라보고 개발하는 방식
  • MyBatis와 스프링을 연동하고 Mapper 인터페이스만 이용하는 방식
    ➡️  스프링과 MyBatis 사이에 'mybatis-spring'이라는 라이브러리를 이용해서 스프링이 데이터베이스 전체에 대한 처리를 하고
    MyBatis는 일부 기능 개발에 활용하는 방식. 개발 시에는 Mapper 인터페이스라는 방식을 이용해서 인터페이스만으로 모든 개발이 가능

 

2) MyBatis를 위한 라이브러리들


👻  MyBatis를 이용하려면 다음과 같은 라이브러리들이 필요

스프링 관련 : spring-jdbc, spring-tx
MyBatis 관련 : mybatis, mybatis-spring
  ➡️  다른 스프링 관련 라이브러리들과 버전이 같도록 통일해서 추가


    📌  MyBatis 관련 라이브러리는 검색을 이용해서 추가. MyBatis 버젼과 mybatis-spring 라이브러리의 버전은 일치하지 않으므로 주의해서 사용

 



3) MyBatis를 위한 스프링 설정 - SqlSessionFactory


👻  MyBatis를 이용하기 위해서는 스프링에 설정해둔 HikariDataSource를 이용해서 SqlSessionFactory라는 빈을 설정
👻  root-context.xml에 'mybatis-spring' 라이브러리에 있는 클래스를 이용해서 <bean>을 등록

 

 


2. Mapper 인터페이스 활용하기

MyBatis는 SQL 파일을 별도로 처리할 수 있지만 인터페이스와 어노테이션으로도 처리가 가능

 

📌  프로젝트에 mapper라는 이름의 패키지를 구성하고 현재 시간을 처리하는 TimeMapper 인터페이스를 선언

 


🎃  TimeMapper는 데이터베이스의 현재 시각을 문자열로 처리하도록 구성

🎃  MyBatis에는 @Select 어노테이션을 이용해서 쿼리를 작성할 수 있는데, JDBC와 마찬가지로 ";"을 이용하지 않으므로 주의

 

 

 

🎃  작성된 인터페이스를 매퍼(Mapper) 인터페이스라고 하는데 마지막으로 어떠한 매퍼 인터페이스를 설정했는지 root-context.xml에 등록해 주어야 함
🎃 root-context.xml에는 <mybatis:scan> 태그를 이용해서 매퍼 인터페이스의 설정을 추가
🎃  root-context.xml 파일 상단의 xmlns, xsi 설정에 mybatis-spring 관련 설정이 추가 되어야 함.




 

1)  테스트 코드를 통한 확인


👾  test 폴더에 mapper 패키지와 TimeMapperTests 테스트 클래스를 작성해서 확인

import lombok.extern.log4j.Log4j2;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;

import static org.junit.jupiter.api.Assertions.*;

@Log4j2
@ExtendWith(SpringExtension.class)
@ContextConfiguration(locations = "file:src/main/webapp/WEB-INF/root-context.xml")
class TimeMapperTest {
    @Autowired(required = false)
    private TimeMapper timeMapper;

    @Test
    public void testGetTimer() {
        log.info(timeMapper.getTime());
    }

}


  📍  테스트 코드에서는 @Autowired 내에 required 속성을 지정
      ✓  @Autowired(required = false)로 지정하면 해당 객체를 주입 받지 못하도라도 예외가 발생하지 않는데 인텔리제이의 경우@Service, @Repository 와 같이 직접 스프링의 빈으로 등록된 경우가 아니라면 경고가 발생하므로 이를 방지하기 위해서 사용

 


3.  XML로 SQL 분리하기

👩🏻‍💻  MyBatis를 이용할 때 SQL은 @Select와 같은 어노테이션을 이용해서 사용하기도 하지만 대부분은 SQL을 별도의 파일로 분리하는 것을 권장
👩🏻‍💻  XML을 이용하는 이유는 SQL이 길어지면 이를 어노테이션으로 처리하기가 복잡해지고, 어노테이션이 나중에 변경되면 프로젝트 전체를 다시 빌드하는 작업이 필요하기 때문에 단순 파일로 사용하는 것이 편리

 

XML과 매퍼 인터페이스를 같이 결합할 때는 다음과 같은 과정으로 작성
  1. 매퍼 인터페이스를 정의하고 메소드를 선언
  2. 해당 XML 파일을 작성 (파일 이름과 매퍼 인터페이스 이름을 같게)하고 <select>와 같은 태그를 이용해서 SQL을 작성
  3. <select>, <insert> 등의 태그에 id 속성 값을 매퍼 인터페이스의 메소드 이름과 같게 작성



🎃  TimeMapper2 매퍼 인터페이스를 정의
🎃  어노테이션이 없는 getNow() 메서드만을 작성

 

 

 

🎃  main/resources 폴더에 mapper 폴더를 추가

 

🎃  TimeMapper2.xml을 다음과 같이 작성 (매퍼 인터페이스와 같은 이름으로 대소문자 주의)
  ➡️ 스프링 버전이 업그레이드 되면서 인터페이스와 xml의 이름을 똑같이 하지 않아도 됨

  ➡️ 하지만 관리상의 목적으로 매퍼 인터페이스와 xml의 이름을 같게 하기도 함
🎃  <mapper> 태그의 namespace 속성에서 매퍼 인터페이스를 맞게 지정하면 됨
  ➡️ <mapper> 태그의 namespace 속성을 반드시 매퍼 인터페이스의 이름과 동일하게 지정

 

  🎃  <select> 태그는 반드시 resultType이나 resultMap이라는 속성을 지정
         ➡️  resultType은 말 그대로 select 문의 결과를 어떤 타입으로 처리할지에 대한 설정으로 java.lang.String과 같이 전체 이름을 써야 하지만 자주 사용하는 타입은 string과 같이 사용할 수 있음

 


🎃  마지막으로 root-context.xml에 있는 MyBatis 설정에 XML 파일들을 인식하도록 설정을 추가

 

  🎃  추가된 mapperLocations는 말 그대로 'XML 매퍼 파일들의 위치'를 의미
  🎃  resources의 경우 'classpath:' 접두어를 이용해서 인식되는 경로이고 mapper 폴더 밑에 폴더가 있어도 관계없도록 '**'와 모든 '.xml'을 의미라는 '*.xml'을 지정

 

 

📌  XML 설정이 정상적인지 테스트를 통해서 확인. 기존에 만들어진 TimeMapperTests를 이용.



 

 

 

[ 내용 참고 : IT 학원 강의 ]

 

 


1.  스프링의 시작 

스프링 프레임워크는 웹이라는 제한적 용도로만 쓰이는 것이 아니라 객체지향의 의존성 주입 dependency injection 기법을 적용할 수 있는 객체지향 프레임워크

 

  •   스프링 프레임워크는 로드 존슨이 2002년도에 집필했던 'J2EE 설계 및 개발 wrox'이라는 책의 예제 코드에서 시작되었는데 말 그대로 효과적이고 가볍게 J2EE를 이용할 수 있다는 것을 증명하면서 예제의 코드를 발전시킨 것
  • 2000년 당시 자바 진영에서 JavaEE의 여러가지 스펙을 정의하고 비대해지는 동안 스프링 프레임워크는 반대로 '경량 light weight 프레임워크'를 목표로 만들어짐
  • 스프링이 등장할 때 여러 종류의 프레임워크들이 비슷한 사상(경량화, 단순화)으로 등장했지만 다른 프레임워크들과 달리 스프링 프레임워크는 개발과 설계 전반에 관련된 문제들을 같이 다루었기 때문에 결론적으로 가장 성공한 프레임워크로 기록
  • 스프링 프레임워크는 가장 중요한 '코어core' 역할을 하는 라이브러리와  여러 개의 추가적인 라이브러리를 결합하는 형태로 프로젝트를 구성. 가장 대표적으로 웹 MVC구현을 쉽게 할 수 있는 'Spring Web MVC'나 JDBC 처리를 쉽게 할 수 있는 'MyBatis'를 연동하는 'mybatis-spring'과 같은 라이브러리가 그러한 예. 

2.  의존성 주입 

스프링이 객체지향 구조를 설계할 때 받아들인 개념은 '의존성 주입 dependency injection'이라는 사상.

    ✓ 의존성 주입은 어떻게 하면 '객체와 객체 간의 관계를 더 유연하게 유지할 것인가?'에 대한 고민에서 나옴

    ✓ 즉 의존성이란 하나의 객체가 자신이 해야 하는 일을 하기 위해서 다른 객체의 도움이 필수적인 관계를 의미

    ✓ 스프링 프레임워크는 바로 이런 점을 프레임워크 자체에서 지원. 다양한 방식으로 필요한 객체를 찾아서 사용할 수 있도록 XML 설정이나 자바 설정 등을 이용

 


3.  ApplicationContext 와 빈 Bean

👻  서블릿이 존재하는 공간을 서블릿 콘텍스트 ServletContext라고 했던 것 처럼, 스프링에서는 빈 Bean 이라고 부르는 객체들을 관리하기 위해서 ApplicationContext 라는 존재를 활용

코드의 경우 ApplicationContext는 root-context.xml을 이용해서 스프링이 실행

ApplicationContext 객체가 생성

root-context.xml을 읽으면 SampleService와 SampleDAO가 해당 클래스의 객체를 생성해서 관리

테스트를 실행하면 @Autowired가 처리된 부분에 맞는 타입의 빈 Bean 이 존재하는지를 확인

이를 테스트 코드 실행 시에 주입

멤버변수에 직접 @Autowired를 선언하는 방식을 '필드 주입 Field Injection' 방식

 


4.  SampleDAO 주입하기 

 

@Autowired를 이용하면 필요한 타입을 주입받을 수 있다는 사실을 이용해서 SampleService를 다음과 같이 변경

 

 

 

📌  Lombok의 @ToString을 적용한 부분과 SampleDAO의 변수로 선언하고 @Autowired를 적용

📌  테스트 코드를 실행하면 SampleService 객체 안에 SampleDAO 객체가 주입된 것을 확인

 

 

 

 

 

👾  스프링을 이용할 때는 클래스를 작성하거나 객체를 직접 생성하지 않음

👾 이 역할은 스프링 내부에서 이루어지며 ApplicationContext가 생성된 객체들을 관리

  • 서블릿의 url 매핑의 경우 web.xml에 <servlet>이라는 태그를 이용해서 서블릿 클래스의 이름과 경로를 전부 기록해야 했지만, 최근에는 @WebServlet 어노테이션이 이를 대신하는 것처럼, 스프링도 비슷한 방식으로 발전, 초기 스프링 버전에서는 XML 파일에 <bean>이라는 것을 이용해서 설정하는 방식이 2.5버전 이후에 어노테이션 형태로 변화되면서 예전에 비해 편리하게 설정이 가능

5.  @Repository, @Service 

👩🏻‍💻  서블릿에서도 @WebServlet이나 @WebFilter와 같이 다양한 어노테이션이 존재하듯이 스프링 프레임워크는 애플리케이션 전체를 커버하기 때문에 다양한 종류의 어노테이션을 사용하도록 작성 

 

@Controller      : MVC의 컨트롤러를 위한 어노테이션
@Service           : 서비스 계층의 객체를 위한 어노테이션
@Repository    : DAO와 같은 객체를 위한 어노테이션
@Component   : 일반 객체나 유틸리티 객체를 위한 어노테이션

 

💡  DAO(Data Access Object)   "실제로 DB의 데이터에 접근하는 객체"
  •  DAO는 Service와 DB를 연결하는 역할을 하며, 실제로 DB에 접근하여 data를 삽입, 삭제, 조회, 수정 등 CRUD 기능을 수행

💡 DTO(Data Transfer Object)   "계층 간 데이터 교환을 위한 객체"

  • 로직을 가지지 않고 getter/setter 메소드만 가진 순수한 데이터 객체 클래스(Java Beans)로 DB에서 데이터를 얻어 Service나 Controller 등으로 보낼 때 사용

💡 VO(Value Object)   "변경 불가능하며 오직 읽기만 가능 (Read-Only)"

  • DTO는 setter를 가지고 있어 값을 변경할 수 있지만, VO는 getter만을 가지기 때문에 읽기만 가능하고 수정은 불가능

 

출처: https://hstory0208.tistory.com/entry/Spring-DAO-DTO-VO란-각각의-개념에-대해-알아보자 

 

 

👩🏻‍💻  스프링이 사용하는 어노테이션의 경우 웹 영역뿐만 아니라 애플리케이션 전체에 사용할 수 있는 객체들을 포함

👩🏻‍💻  어노테이션을 이용하게 되면 스프링 설정은 <bean>이 아니라 '해당 패키지를 조사해서 어노테이션들을 이용'하는 설정으로 변경

 

설정 변경 전과 후

 

📌  기존 설정과 비교해 보면 XML 위쪽의 xmlns 네임 스페이스가 추가되고 schemaLocation이 변경

📌  내용에는 component-scan이 추가되었는데 속성값으로는 패키지를 지정 

📌  'component-scan'은 해당 패키지를 스캔해서 스프링의 어노테이션들을 인식

 


 

 

 

🎃  SampleDAO는 해당 클래스의 객체가 스프링에서 빈 Bean으로 관리될 수 있도록 @Repository 라는 어노테이션을 추가

 

 

 

 

 

 

 

 

 

🎃  SampleService에는 @Service 어노테이션을 추가

 

 

 

 

 

 

 


 

생성자 주입 방식 

 

👾  초기 스프링에서는 @Autowired를 멤버 변수에 할당하거나, Setter를 작성하는 방식을 많이 이용해 왔지만, 스프링 3 이후에는 생성자 주입이라고 부르는 방식을 더 많이 활용.

👾  생성자 주입 방식은 객체를 생성할 때 문제가 발생하는 지를 미리 확인할 수 있기 때문에 필드 주입이나 Setter 주입 방식 보다 선호되는 방식 

👾  Lombok에서는 생성자 주입을 보다 간단하게 작성할 수 있는데 @RequiredArgsConstructor를 이용해서  필요한 생성자 함수를 자동으로 작성할 수 있음

 

 

 

 

 

💫  생성자 주입 방식은 다음과 같은 규칙으로 작성

   

    - 주입 받아야 하는 객체의 변수는 final로 작성

     - 생성자를 이용해서 해당 변수를 생성자의 파라미터로 지정

 

 

 

 

 

 

 


6.  인터페이스를 이용한 느슨한 결합 

스프링이 의존성 주입을 가능하게 하지만  '좀 더 근본적으로 유연한 프로그램을 설계하기 위해서는 인터페이스를 이용'해서 나중에 다른 클래스의 객체로 쉽게 변경할 수 있도록 하는 것이 좋음.

    ⚡️  예를 들어 코드에서 SampleDAO를 다른 객체로 변경하려면 결론적으로 SampleService 코드 역시 수정해야 함. 추상화된 타입을 이용하면 이러한 문제를 피할 수 있는데 가장 대표적인 것이 인터페이스. 인터페이스를 이용하면 실제 객체를 모르고 타입만을 이용해서 코드를 작성하는 일이 가능해 짐. 

 

1)  SampleDAO를 인터페이스로 변경하기  

 

 

 

🎃  클래스로 작성된 SampleDAO을 인터페이스로 수정. @Repository 삭제

🎃  SampleService는 SampleDAO라는 인터페이스를 보게 되었지만 코드상의 변경은 필요하지 않음

 

 

 

 

 

 

 

 

🎃 SampleDAO 인터페이스는 구현 코드가 없기 때문에 구현한 클래스를 SampleDAOImpl 이라는 이름으로 선언

🎃 SampleDAOImpl에는 @Repository를 이용해서 해당 클래스의 객체를 스프링의 빈 Bean으로 처리되도록 구성

 

 

 

 

 

SampleService의 입장에서는 인터페이스만 바라보고 있기 때문에 실제 객체가 SampleDAOImpl의 인스턴스인지 알수 없지만, 코드를 작성하는 데에는 아무런 문제가 없음. 이처럼 객체와 객체의 의존 관계의 실제 객체를 몰라도 가능하게 하는 방식을 '느슨한 결합 Loose coupling'이라고 함. 느슨한 결합을 이용하면 나중에 SampleDAO 타입의 객체를 다른 객체로 변경하더라도 SampleService 타입을 이용하는 코드를 수정할 일이 없기 때문에 보다 유연한 구조가 됨. 


2) 다른 SampleDAO 객체로 변경해 보기 

 

 

🎃  예를 들어 특정한 기간에만 SampleDAO를 다른 객체로 변경해야 되는 경우 EventSampleDAOImpl이라는 클래스를 작성

 

 

 

 

 

 

 

 

이렇게 되면 SampleService에 필요한 SampleDAO 타입의 빈 Bean이 두 개 SampleDAOImpl, EventSampleDAOImpl 가 되기 때문에 스프링 입장에서는 어떤 것을 주입해야 하는지 알 수 없음테스트 코드를 실행하면 어떤 클래스의 객체를 사용해야 하는지 알 수 없으므로 다음과 같은 에러가 발생

 

Error creating bean with name 'sampleService' defined in file [E:\work\dev\projects\projects-spring intellij\springex\build\classes\java\main\com\nomadlab\springex\sample\SampleService.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.nomadlab.springex.sample.SampleDAO' available: expected single matching bean but found 2: eventSampleDAOImpl,sampleDAOImpl 

 

 

스프링이 기대하는 것은 SampleDAO 타입의 객체가 하나 single 이길 기대했지만 2개가 발견. 

이를 해결하는 가장 간단한 방법은 두 클래스 중에 하나를 @Primary라는 어노테이션으로 지정해 주는 것

 


 

3) @Qualifier 이용하기 

 

👾  @Primary를 이용하는 방식 외에도 @Qualifier를 이용하는 방식도 있음

👾  @Qualifier는 이름을 지정해서 특정한 이름의 객체를 주입받는 방식

 

  📌  Lombok과 @Qualifier를 같이 이용하기 위해서는 src/main/java 폴더에 lombok.config 파일을 생성

 

 

 

 

🎃  동작을 확인하기 위해서 SampleDAOImpl과 EventSampleDAOImpl 에는 @Qualifier를 적용. 

🎃  SampleDAOImpl 에는 normal 이라는 이름을 지정 

 

 

 

 

 

 

 

🎃  EventSampleDAOImpl에는 event 라는 이름을 지정 

 

 

 

 

 

 

 

 

 

 

 

🎃  SampleService에는 특정한 이름의 객체를 사용하도록 수정

 

 

 

 

 

 

 

    🎃  normal 이름을 가진 SampleDAOImpl이 주입되는 것을 확인

 


4)  스프링의 빈 Bean 으로 지정되는 객체들 

 

👾  스프링 프레임워크를 이용해서 객체를 생성하고 의존성 주입을 이용할 수 있다는 사실을 알았지만 작성되는 모든 클래스의 객체가 스프링의 빈 Bean으로 처리되는 것은 아님

👾  스프링의 빈 Bean으로  등록되는  객체들은 쉽게 말해서 '핵심 배역'을 하는 객체들로 오랜 시간 동안 프로그램 내에 상주하면서 중요한 역할을 하는 '역할' 중심의 객체들

👾  반대로 DTO나 VO와 같이 '역할' 보다는 '데이터'에 중심을 두고 설계된 객체들은 스프링의 빈 Bean을 등록하지 않음

      특히 DTO의 경우 생명주기가 굉장히 짧고, 데이터 보관이 주된 역할이기 때문에 스프링에서 빈 Bean으로 처리하지 않음


5) XML이나 어노테이션으로 처리하는 객체 

 

👾  빈 Bean 으로 처리할 때 XML 설정을 이용할 수도 있고, 어노테이션을 처리할 수도 있지만, 이에 대한 기준은 '코드를 수정할 수 있는가'로 판단

👾  예를 들어 jar 파일로 추가되는 클래스의 객체를 스프링의 빈Bean으로 처리해야 한다면 해당 코드가 존재하지 않기 때문에 어노테이션을 추가할 수가 없다는 문제가 생김. 이러한 객체들은 XML에서 <bean>을 이용해서 처리하고, 직접 처리되는 클래스는 어노테이션을 이용하는 것이 좋음. 


7.   웹 프로젝트를 위한 스프링 준비 

💡  스프링의 구조를 보면 ApplicatonContext라는 객체가 존재하고 빈으로 등록된 객체들은  ApplicatonContext 내에 생성되어 관리되는 구조.

    ⚡️  이렇게 만들어진 ApplicatonContext가 웹 애플리케이션에 동작하려면 웹 애플리케이션이 실행될 때  스프링을 로딩해서 해당 웹 애플리케이션 내부에 스프링의 ApplicatonContext를 생성하는 작업이 필요하게 되는데 이를 위해서 web.xml을 이용해서 리스너를 설정

    ⚡️  스프링 프레임워크의 웹과 관련된 작업은 'spring-webmvc'라이브러리를 추가해야만 설정이 가능

 

 

 

 

▶️  build.gradle파일에 spring-mvc 라이브러리를 추가

 

 

 

 

▶️  WEB-INF 폴더 아래 web.xml에  <listener>설정과 <listener>에 필요한 <context-param>을 추가

 

 

 

 

💫  설정이 추가된 후에 톰캣을 실행하면 스프링과 관련된 로그가 기록되면서 실행 


8.  DataSource 구성하기 

톰캣과 스프링이 연동되는 구조를 완성했다면 데이터베이스 관련 설정을 추가

 

  📌  build.gradle에 MySQL과 HikariCP 관련 라이브러리를 추가

    // https://mvnrepository.com/artifact/mysql/mysql-connector-java
    implementation 'mysql:mysql-connector-java:8.0.33'

    // https://mvnrepository.com/artifact/com.zaxxer/HikariCP
    implementation 'com.zaxxer:HikariCP:5.0.1'

 

 

   📌  root-context.xml에 HikariCP 설정하기 

    <context:component-scan base-package="com.example.sping_class.sample" />

    <bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/sample" />
        <property name="username" value="root"/>
        <property name="password" value="비밀번호"/>
        <property name="dataSourceProperties">
            <props>
                <prop key="cachePrepStmts">true</prop>
                <prop key="prepStmtCacheSize">250</prop>
                <prop key="prepStmtCacheSqlLimit">2048</prop>
            </props>
        </property>
    </bean>

    <bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
        <constructor-arg ref="hikariConfig" />
    </bean>

 

  • HikariCP를 사용하기 위해서는 HikariConfig 객체와 HikariDataSource를 초기화해야함
  • root-context.xml을 이용해서 HikariConfig 객체와 HikariDataSource 객체를 설정
  • hikariConfig에는 id 속성이 적용되어 있고 HikariDataSource는 <constructor-arg ref="hikariConfig" />로 id 값을 참조해서 사용
  • HikariDataSource는 javax.sql의 DataSource 인터페이스의 구현체이므로 테스트 코드를 통해서 설정에 문제가 없는지 확인

 

 

 

🎃  root-context.xml에 선언된 HikariCP를 주입받기 위해서 DataSource타입의 변수를 선언하고 @Autowired를 이용해서 주입 되도록 구성

 

 

 

 

 

 

 

 

 

 

 

 

 

 

👩🏻‍💻  스프링은 필요한 객체를 스프링에서 주입해 주기 때문에 개별적으로 클래스를 작성해서 빈으로 등록해 두기만 하면 원하는 곳에서 쉽게 다른 객체를 사용할 수 있음. 이런 특징으로 인해 스프링 프레임워크는 웹이나 데이터베이스 같은 특정한 영역이 아닌 전체 애플리케이션의 구조를 설계할 때 사용

 

 

 

 

[ 내용 참고 : IT 학원 강의 ]

 


1. 쿠키와 세션의 차이

출처 :&nbsp;https://cyberchimps.com/blog/session-cookies/

 

출처 :&nbsp;https://twitter.com/sahnlam/status/1759829449284231214

 

쿠키와 세션 응답 헤더

 

  📌  쿠키를 사용했을 때는 아이디와 비밀번호가 노출됨  ▶️  보안이 되지 않음


2.  쿠키  Cookie

html 파일

 

<body>
    <form action="cookie01_process.jsp" method="post">
          <p>아 이 디 : <input type="text" name="id"></p>
          <p>비밀번호 : <input type="text" name="passwd"></p>
          <p><input type="submit" value="전송"></p>
    </form>
</body>

 

jsp 파일

 

    📍 쿠키 생성하기
         1) 전송된 아이디와 비밀번호가 일치하면, 쿠키 이름 userId, userPw에 값을 설정하도록 Cookie 객체를 생성

<body>

    <%
      String userId = request.getParameter("id");
      String userPw = request.getParameter("passwd");

      if (userId.equals("admin") && userPw.equals("1234")) { // 로그인 정보가 맞으면
        Cookie cookieId = new Cookie("userId", userId); // 쿠키 생성. Cookie 클래스를 이용해서 쿠키 객체 생성.
        Cookie cookiePw = new Cookie("userPw", userPw);
        response.addCookie(cookieId); // response 할 때 쿠키도 같이 보낼 것
        response.addCookie(cookiePw);

        out.println("쿠키 생성이 성공했습니다<br>");
        out.println(userId + "님 환영합니다");
      } else {
        out.println("쿠키 생성이 실패했습니다");
      }
    %>

</body>

 

    📍 쿠키 객체에 저장된 모든 쿠키 값 가져와 출력
        1) 쿠키 정보를 얻어오도록 request 내장 객체의 getCookies() 메서드 작성
        2) 얻어온 쿠키 정보의 개수를 출력하도록 Cookie 객체의 length를 작성
        3) 얻어온 쿠키 정보에서 쿠키 이름과 값을 하나씩 출력하도록 Cookie 객체의 getName(), getValue() 메소드 작성

<body>

    <%
      boolean isLogin = false;
      String userId = "";
      Cookie[] cookies = request.getCookies(); // request에서 쿠키를 얻어옴.
      out.println("현재 설정된 쿠키의 개수 => " + cookies.length + "<br>");
      out.println("====================================<br>");
      for (int i = 0; i < cookies.length; i++) {
        out.println("설정된 쿠키의 속성 이름 [ " + i + " ] : " + cookies[i].getName() + "<br>");
        out.println("설정된 쿠키의 속성 값 [ " + i + " ] : " + cookies[i].getValue() + "<br>");
        out.println("--------------------------------------------<br>");

        if (cookies[i].getName().equals("userId") && cookies[i].getValue() != null) {
          // userId라는 쿠키이름이 있고 value가 null이 아니면 로그인 한 것으로 간주
          isLogin = true;
          userId = cookies[i].getValue();
        }
      }

      if (isLogin) {
        out.print(userId + "님이 로그인 중입니다.");
      } else {
        out.print("로그인 상태가 아닙니다.");
      }
    %>

</body>


    📍 쿠키 객체에 저장된 모든 쿠키 삭제하기
        1) 쿠키 정보를 얻어오도록 request 내장 객체의 getCookies() 메소드 작성
        2) 얻어온 모든 쿠키를 삭제하도록 Cookie 객체의 setMaxAge() 메소드에 유효 기간을 0으로 설정
        3) 웹 페이지 cookie02.jsp로 이동하도록 response 내장 객체의 sendRedirect() 메소드를 작성

<body>
    
    <%
        Cookie[] cookies = request.getCookies();

        for (int i = 0; i < cookies.length; i++) {
            cookies[i].setMaxAge(0);
            response.addCookie(cookies[i]);
        }
        response.sendRedirect("04.jsp");
    %>

</body>


3.  세션  Session

html 파일
<body>
    <form action="session01_process.jsp" method="post">
      <p> 아이디 : <input type="text" name="id"></p>
      <p> 비밀번호 : <input type="text" name="passwd"></p>
      <p><input type="submit" value="전송"></p>
    </form>
</body>

 

jsp 파일

 

     📍  세션 설정하기
         1)  전송된 아이디 비번이 일치하면 세션 속성 이름이 userID, userPW에 값을 설정하도록 session 내장 객체의 setAttribute() 메소드 작성
        2) 일치하지 않으면 실패 메시지를 출력

 

      💫  쿠키와는 다르게 response 객체에 세션을 담는 과정은 없음 ▶️ 서버에 저장하기 때문

<body>
    <%
      String userId = request.getParameter("id");
      String userPw = request.getParameter("passwd");

      if (userId.equals("admin") && userPw.equals("1234")) {
        session.setAttribute("userId", userId);
        session.setAttribute("userPw", userPw);
        out.println("세션 설정이 성공했습니다<br>");
        out.println(userId + "님 환영합니다");
      } else {
        out.println("세션 설정이 실패했습니다");
      }
    %>
</body>

 

    📍 세션에 저장된 속성 값 가져와 출력
        - 세션에 저장된 세션 속성 이름 userID, userPW의 속성 값을 가져오도록 session 내장 객체의 getAttribute() 메소드를 작성

<body>
    <%
        String userId = (String) session.getAttribute("userId"); // 세션의 속성값은 Object라서 다운캐스팅을 해야함.
        String userPw = (String) session.getAttribute("userPw");

        out.println("설정된 세션의 속성 값 [1] : " + userId + "<br>");
        out.println("설정된 세션의 속성 값 [2] : " + userPw);
    %>
</body>

    

    📍  세션에 저장된 세션 속성 삭제
       -  세션에 저장된 세션 속성 이름  userID를 삭제하도록 session 내장 객체의 removeAttribute() 메서드를 작성

<body>
    <p><h4>------ 세션을 삭제하기 전 ------</h4></p>
    <%
        String userId = (String) session.getAttribute("userId");
        String userPw = (String) session.getAttribute("userPw");
        out.println("설정된 세션 userId : " + userId + "<br>");
        out.println("설정된 세션 userPw : " + userPw + "<br>");

        session.removeAttribute("userId");
        session.removeAttribute("userPw");
    %>
    
    <p><h4>------ 세션을 삭제한 후 ------</h4></p>
    <%
        userId = (String) session.getAttribute("userId");
        userPw = (String) session.getAttribute("userPw");
        out.println("설정된 세션 userId : " + userId + "<br>");
        out.println("설정된 세션 userPw : " + userPw + "<br>");
    %>
</body>

    📍 세션에 저장된 모든 세션 속성 삭제
        1) 요청에 포함된 클라이언트의 세션이 유효하면 유효한 메시지를 출력하고, 그렇지 않으면 유효하지 않은 메시지를 출력
        2) 세션에 저장된 모든 세션 속성을 삭제하도록 session 내장 객체의 invalidate() 메서드를 작성

 

     👾  request.isRequestSessionIdValue() : request에 포함된 SessionId가 유효한지 검사. 반환형은 boolean

<body>
    <p><h4>------ 세션을 삭제하기 전 ------</h4></p>
    <%
        String userId = (String) session.getAttribute("userId");
        String userPw = (String) session.getAttribute("userPw");
        out.println("설정된 세션 userId : " + userId + "<br>");
        out.println("설정된 세션 userPw : " + userPw + "<br>");

        if (request.isRequestedSessionIdValid() == true) {
          out.print("세션이 유효합니다.");
        } else {
          out.print("세션이 유효하지 않습니다.");
        }

        session.invalidate();
     %>
     
    <p><h4>------ 세션을 삭제한 후 ------</h4></p>
    <%
      if (request.isRequestedSessionIdValid() == true) {
        out.print("세션이 유효합니다.");
      } else {
        out.print("세션이 유효하지 않습니다.");
      }
    %>
</body>

    

    📍 세션 아이디와 웹 사이트에서 유지한 시간 출력


        1) 고유한 세션 내장 객체의 아이디를 가져오도록 session 내장 객체의 getId() 메서드를 작성
        2) 세션에 마지막으로 접근한 시간을 가져오도록 session 내장 객체의 getLastAccessedTime() 메서드를 작성
        3) 세션이 생성된 시간을 가져오도록 session 내장 객체의 getCreationTime() 메서드를 작성
        4) 웹 사이트에 머문 시간을 계산하도록 작성

<body>
    <%
      String sessinId = session.getId();
      // 세션에 마지막으로 접근한 시간
      long lastTime = session.getLastAccessedTime();  // 단위가 1/1,000초
      // 세션이 생성된 시간
      long startTime = session.getCreationTime();  // 단위가 1/1,000초

      long usedTime = (lastTime - startTime) / 1000;

      out.println("세션 아이디 : " + sessinId + "<br>");
      out.println("요청 시작 시간  : " + startTime + "<br>");
      out.println("요청 마지막 시간  : " +  lastTime + "<br>");
      out.println("웹 사이트에서 경과 시간  : " + usedTime + "초<br>");
    %>
</body>

    📍 세션 유효 시간을 가져와 출력


        1) 세션에 설정된 유효 시간을 가져오도록 session 내장 객체의 getMaxInactiveInterval() 메서드를 작성하고, 유효시간을 출력
        2) 세션 유효 시간을 60 * 60 초로 설정하도록 session 내장 객체의 setMaxInactiveInterval() 메서드를 작성
        3) 세션에 설정된 유효 시간을 가져오도록 session 내장 객체의 getMaxInactiveInterval() 메서드를 작성하고, 유효시간을 출력

<body>
    <p><h4>------ 세션 유효시간 변경 전 ------</h4></p>
    <%
        int time = session.getMaxInactiveInterval() / 60;

        out.println("세션 유효 시간 : " + time + "분<br>");
    %>
    <p><h4>------ 세션 유효시간 변경 후 ------</h4></p>
    <%
        session.setMaxInactiveInterval(60 * 60);
        time = session.getMaxInactiveInterval() / 60;

        out.println("세션 유효 시간 : " + time + "분<br>");
    %>
</body>

 

 

 

 

 

 

 

 

 

[ 내용 참고 : IT학원 강의 ]


1.  회원가입 양식

html 코드
    <h3>회원가입</h3>
    <form action="form01_process.jsp" name="member" method="post">
        <p> 아이디 : <input type="text" name="id"> <input type="button" value="아이디 중복검사"></p>
        <p> 비밀번호 : <input type="password" name="passwd"></p>
        <p> 이름 : <input type="text" name="name"></p>
        <p> 연락처 : <select name="phone1">
            <option value="010">010</option>
            <option value="011">011</option>
            <option value="016">016</option>
            <option value="017">017</option>
            <option value="019">019</option>
        </select> - <input type="text" maxlength="4" size="4" name="phone2"> -
            <input type="text" maxlength="4" size="4" name="phone3"></p>
        <p> 성별 : <input type="radio" name="sex" value="남성" checked>남성
            <input type="radio" name="sex" value="여성">여성</p>
        <p> 취미 : 독서 <input type="checkbox" name="hobby" value="독서" checked>
            운동<input type="checkbox" name="hobby" value="운동">
            영화<input type="checkbox" name="hobby" value="영화"></p>

        <p> 주소 : <input name="zipcode" id="zipcode" size="10" maxlength="7" readonly>
            <input type="button" value="우편번호 검색" id="address"><br />
            <input name="address01" id="address01" size="70" maxlength="70" readonly>
            <input name="address02" id="address02" size="70" maxlength="70"> </p>

        <p> <textarea name="comment" cols="30" rows="3" placeholder="가입인사를 입력해주세요"></textarea></p>
        <p> <input type="submit" value="가입하기">
            <input type="reset" value="다시쓰기"></p>
    </form>

 

자바스크립트 코드
       /*
        카카오 우편번호 검색 가이드 페이지 :  https://postcode.map.daum.net/guide
        getElementById() : html 에서 매개변수로 받은 id 값이 있는 요소를 반환.
        */
        function execDaumPostcode() {
            new daum.Postcode({
                oncomplete: function(data) {
                    // 팝업에서 검색결과 항목을 클릭했을때 실행할 코드를 작성하는 부분.

                    // 각 주소의 노출 규칙에 따라 주소를 조합한다.
                    // 내려오는 변수가 값이 없는 경우엔 공백('')값을 가지므로, 이를 참고하여 분기 한다.
                    var fullAddr = ''; // 최종 주소 변수
                    var extraAddr = ''; // 조합형 주소 변수

                    // 사용자가 선택한 주소 타입에 따라 해당 주소 값을 가져온다.
                    if (data.userSelectedType === 'R') { // 사용자가 도로명 주소를 선택했을 경우
                        fullAddr = data.roadAddress;
                    }
                    else { // 사용자가 지번 주소를 선택했을 경우(J)
                        fullAddr = data.jibunAddress;
                    }

                    // 사용자가 선택한 주소가 도로명 타입일때 조합한다.
                    if(data.userSelectedType === 'R'){
                        //법정동명이 있을 경우 추가한다.
                        if(data.bname !== ''){
                            extraAddr += data.bname;
                        }
                        // 건물명이 있을 경우 추가한다.
                        if(data.buildingName !== ''){
                            extraAddr += (extraAddr !== '' ? ', ' + data.buildingName : data.buildingName);
                        }
                        // 조합형주소의 유무에 따라 양쪽에 괄호를 추가하여 최종 주소를 만든다.
                        fullAddr += (extraAddr !== '' ? ' ('+ extraAddr +')' : '');
                    }

                    // 우편번호와 주소 정보를 해당 필드에 넣는다.
                    document.querySelector('input[name=zipcode]').value = data.zonecode; //5자리 새우편번호 사용
                    document.querySelector('input[name=address01]').value = fullAddr;

                    // 커서를 상세주소 필드로 이동한다.
                    document.querySelector('input[name=address02]').focus();
                }
            }).open();
        }

        document.addEventListener("DOMContentLoaded", function () {
            const addrBtn = document.querySelector('input[id=address]');
            addrBtn.addEventListener('click', execDaumPostcode);
        });

 

JSP 코드
    <%
        request.setCharacterEncoding("utf-8");
        String userid = request.getParameter("id");
        String password = request.getParameter("passwd");
        String name = request.getParameter("name");
        String phone = request.getParameter("phone1");
        String sex = request.getParameter("sex");
        String[] hobby = request.getParameterValues("hobby");
        String comment = request.getParameter("comment");
    %>
    <p> 아이디 : <%=userid%>
    <p> 비밀번호 : <%=password%>
    <p> 이름 : <%=name%>
    <p> 연락처 : <%=phone%>
    <p> 성별 : <%=sex%>
    <p> 취미 : <%
        if (hobby != null) {
            for(String s: hobby) {
                out.println(" " + s);
            }
        }
        %>
    <p> 가입인사 : <%=comment%>

 


2.  유효성 검사

회원가입시 아이디와 비밀번호를 입력하지 않을 시 + 비밀번호에 아이디가 포함된 경우 경고창 띄우기

html 코드
<body>
    <h3>회원가입</h3>
    <form action="validation_process.jsp" name="member" method="post">
        <p> 아이디 : <input type="text" name="id"> <input type="button" value="아이디 중복검사"></p>
        <p> 비밀번호 : <input type="password" name="passwd"></p>

        <p> <input type="submit" value="가입하기"> </p>
    </form>
</body>

 

javascript 코드
<script>
    document.addEventListener("DOMContentLoaded", function() {
       const id = document.querySelector("input[name=id]");
       const pwd = document.querySelector("input[name=passwd]");
       const submitBtn = document.querySelector('input[value="가입하기"]');

       submitBtn.addEventListener('click', function(event) {
           if (id.value.trim() === "") {
               alert('아이디를 입력해 주세요.');
               event.preventDefault(); // Prevent form submission
               id.focus();
           } else if (pwd.value.trim() === "") {
               alert('비밀번호를 입력해 주세요.');
               event.preventDefault(); // Prevent form submission
               pwd.focus();
           } else if (pwd.value.indexOf(id.value) !== -1) {
               alert('비밀번호는 아이디를 포함할 수 없습니다.');
               event.preventDefault(); // Prevent form submission
               pwd.focus();
           }
       });

    });
</script>

 

JSP 코드
<body>
    <%
        request.setCharacterEncoding("utf-8");
        String userid = request.getParameter("id");
        String password = request.getParameter("passwd");
    %>
       <p> 아이디 : <%=userid%>
       <p> 비밀번호 : <%=password%>

</body>

 

 

 

 

[ 내용 참고 : IT 학원 강의 ]

'JSP' 카테고리의 다른 글

[JSP] 쿠키 Cookie 와 세션 Session  (0) 2024.04.20
[JSP] 내장객체 - response, out  (0) 2024.04.17
[JSP] 내장 객체 - request  (0) 2024.04.17
[JSP] 디렉티브 태그 - include, taglib  (0) 2024.04.16
[JSP] 디렉티브 태그 - page tag  (0) 2024.04.16


1.  프로퍼티와 메서드의 재정의 : 오버라이드

👩🏻‍💻  상속받은 부모 클래스의 프로퍼티와 메서드 중에 자식 클래스에서는 다른 용도로 사용해야 하는 경우가 있음
👩🏻‍💻  동일한 이름의 메서드나 프로퍼티를 사용할 필요가 있을 경우에 override 키워드를 사용해서 재정의 할 수 있음
👩🏻‍💻  오버라이드 할 때는 프로퍼티나 메서드도 클래스 처럼 앞에 open을 붙여서 상속할 준비가 되어 있어야 함

 

메서드 오버라이드


    📍 상속할 메서드 앞에 open 키워드를 붙이면 오버라이드 할 수 있지만, open 키워드가 없는 메서드는 오버라이드 할 수 없음

    open class BaseClass {
        open fun opened() {

        }
        fun notOpened() {

        }
    }

    class ChildClass : BaseClass() {
        override fun opened() {
            super.opened()
        }
    }

 

 

프로퍼티 오버라이드


    📍 메서드 오버라이드처럼 프로퍼티 역시 open으로 열려 있어야만 오버라이드를 할 수 있음

    open class BaseClass2 {
        open var opened: String = "I am"
    }
    class ChildClass2: BaseClass2() {
        override var opened: String = "You are"
    }

 


2.  추상 클래스

🚀  추상 클래스는 그 자체로는 객체를 만들 수 없는 클래스로, 일반적으로 추상 메소드가 포함된 클래스를 말함
        ➡️  추상 메소드란 아직 구현되지 않고 추상적으로만 존재하는 메소드
🚀  추상 클래스와 추상 메소드 앞에는 abstract 키워드를 붙임
🚀  상속받는 자식 클래스에 특정 메소드 구현을 강제하고 싶을 때 사용
🚀  추상 클래스 자체로는 직접 객체를 만들 수 없고 자식 클래스에서 추상 메소드를 구현한 다음, 자식 클래스의 객체를 생성하면 됨.

abstract class Game {

    fun startGame() {
        println("게임을 시작했습니다.")
    }
    // 추상 메소드
    abstract fun printName()
}

class OverWatch: Game() {
    override fun printName() { // 추상 메소드 구현
        println("오버워치입니다.")
    }
}

fun main() {
    val overWatch = OverWatch()
    overWatch.startGame() // 게임을 시작했습니다.
    overWatch.printName() // 오버워치입니다.
}

 

 

 

[ 내용 참고 : IT 학원 강의 ]


1.  response 내장 객체의 기능과 사용법

response 내장 객체는 사용자의 요청을 처리한 결과를 서버에서 웹 브라우저로 전달하는 정보를 저장

  ➡️  즉 서버는 응답 헤더와 요청 처리 결과 데이터를 웹 브라우저로 보냄
  ➡️  JSP 컨테이너는 서버에서 웹 브라우저로 응답하는 정보를 처리하기 위해  javax.servlet.http.HttpServletResponse 객체 타입의 response 내장 객체를 사용하여 사용자의 요청에 응답

 


 

1) 페이지 이동 관련 메소드


사용자가 새로운 페이지를 요청할 때와 같이 페이지를 강제로 이동하는 것을 리다이렉션(redirection)
서버는 웹 브라우저에 다른 페이지로 강제 이동하도록 response 내장 객체의 리다이렉션 메소드를 제공
페이지 이동 시에는 문자 인코딩을 알맞게 설정 해야 함

페이지 이동 방법


  📍 포워드(forward) 방식

<jsp:forward page="이동할 페이지"/>

 

  ✓ 현재 JSP 페이지에서 이동할 URL로 요청 정보를 그대로 전달하므로 사용자가 최초로 요청한 정보가 이동된 URL에서도 유효. 그러나 이동된 URL이 웹 브라우저의 주소 창에 나타나지 않고 처음 요청한 URL이 나타나기 때문에 이동 여부를 사용자가 알 수 없음

  📍 리다이렉트(redirect)방식

response.sendRedirect("이동할 페이지")

 

  ✓ 처음 요청받은 현재 JSP 페이지로부터 이동할 URL을 웹 브라우저로 반환. 이때 웹 브라우저에서는 새로운 요청을 생성하여 이동할 URL에 다시 요청을 전송하므로 처음 보낸 요청 정보가 이동된 URL에서는 유효하지 않음. 즉 클라이언트가 새로 페이지를 요청한 것과 같은 방식으로 페이지가 이동. 따라서 이동된 URL이 웹 브라우저의 주소 창에 보임.

페이지 이동 관련 메소드 반환유형 설명
sendRedirect(String url) void 설정한 URL 페이지로 강제 이동

 

<body>
    <%
      response.setHeader("Refresh", "5");
      Calendar calendar = Calendar.getInstance();
      String am_pm;
      int hour = calendar.get(Calendar.HOUR_OF_DAY);
      int minute = calendar.get(Calendar.MINUTE);
      int second = calendar.get(Calendar.SECOND);

      if (hour < 12)
        am_pm = " AM";
      else {
        am_pm = " PM";
        hour = (hour != 12) ? hour - 12 : hour;
      }

      String currentTime = hour + ":" + minute + ":" + second + am_pm;
    %>
    <p>현재 시간은 <b><%=currentTime %></b></p>
    <p><a href="response_data.jsp">구글 홈페이지로 이동하기</a></p>
</body>
// response_data.jsp 파일
<body>
    <%
        response.sendRedirect("https://www.google.com");
    %>
</body>

 


내장 객체로 페이지 이동하기 ▶️  아이디와 비밀번호가 일치하면 성공 페이지로, 그렇지 않으면 로그인 페이지로 이동

 

    1)  폼 문으로 전송받은 아이디와 비밀번호가 일치하면 response01_success.jsp 페이지로 이동.

    2) 일치하지 않으면 response01_failed.jsp 페이지로 이동하도록 response 내장 객체의 sendRedirect() 메서드를 작성

// form 태그 작성
<body>
    <form action="response01_process.jsp" method="post">
      <p> 아 이 디 : <input type="text" name="id">
      <p> 비밀번호 : <input type="text" name="passwd">
      <p> <input type="submit" value="전송">
    </form>
</body>
// response01_process.jsp 파일
<body>

    <%
      request.setCharacterEncoding("utf-8");
      String userid = request.getParameter("id");
      String password = request.getParameter("passwd");

      if (userid.equals("관리자") && password.equals("1234")) {
          out.println("로그인을 성공했습니다!!");
          response.sendRedirect("response01_success.jsp");
      } else {
          out.println("로그인을 실패했습니다.");
          response.sendRedirect("response01_failed.jsp");
      }
    %>

</body>
// response01_success.jsp 파일
<body>
    로그인을 성공했습니다!!
</body>
// response01_failed.jsp 파일
<body>
    <p> 로그인을 실패했습니다.</p>
    <p><a href="./04.jsp"> 로그인가기</a></p>
</body>


 

2) 응답 HTTP 헤더 관련 메소드


응답 HTTP 헤더 관련 메소드는 서버가 웹 브라우저에 응답하는 정보에 헤더를 추가하는 기능을 제공
 ➡️ 헤더 정보에는 주로 서버에 대한 정보가 저장되어 있음

 

메소드 종류
메소드 반환 유형 설명
addCookie(Cookie cookie) void 쿠키를 추가
addDateHeader(String name, long date) void 설정한 헤더 이름 name에 날짜/시간을 추가
addHeader(String name, String value) void 설정한 헤더 이름 name에 value를 추가
addIntHeader(String name, int value) void 설정한 헤더 이름 name에 정수 값 value를 추가
setDateHeader(String name, long date) void 설정한 헤더 이름 name에 날짜/시간을 설정
setHeader(String name, String value) void 설정한 헤더 이름 name에 문자열 값 value를 설정
setIntHeader(String name, int value) void 설정한 헤더 이름 name에 정수 값 value를 설정
containsHeader(String name) boolean 설정한 헤더 이름 name이 HTTP 헤더에 포함되었는지 여부를 확인
getHeader(String name) String 설정한 헤더 이름 name 값을 가져옴

 

response 내장 객체로 5초마다 JSP 페이지 갱신하기 

 

   1) 5초마다 JSP 페이지가 갱신되도록 response 내장 객체의 setIntHeader() 메서드를 작성

   2) 5초마다 JSP 페이지가 갱신된 시간을 출력하도록 표현문 태그 작성

<body>
    <p>이 페이지는 5초마다 새로고침 됩니다.</p>

    <%
      response.setIntHeader("Refresh", 5);
    %>
    <p> <%=(new java.util.Date())%> </p>
</body>


3) 응답 콘텐츠 관련 메소드

 

response 내장 객체는 웹 브라우저로 응답하기 위해 MIME 유형, 문자 인코딩, 오류 메시지, 상태 코드 등을 설정하고 가져오는 응답 콘텐츠 관련 메소드를 제공

메소드 반환 유형 설명
setContentType(String type) void 웹 브라우저에 응답할 MIME 유형을 설정
getContentType() String 웹 브라우저에 응답할 MIME 유형을 가져옴
setCharacterEncoding(String charset) void 웹 브라우저에 응답할 문자 인코딩을 설정
getCharacterEncoding() String 웹 브라우저에 응답할 문자 인코딩을 가져옴
sendError(int status_code, String message) void 웹 브라우저에 응답할 오류(코드 및 오류 메시지)를 설정
setStatus(int statuscode) void 웹 브라우저에 응답할 HTTP 코드를 설정

 


2.  out 내장 객체의 기능과 사용법 

👩🏻‍💻  out 내장 객체는 웹 브라우저에 데이터를 전송하는 출력 스트림 객체

👩🏻‍💻  JSP 컨테이너는 JSP 페이지에 사용되는 모든 표현문 태그와 HTML 일반 텍스트 등을 out 내장 객체를 통해 웹 브라우저에 그대로 전달 

👩🏻‍💻  스크립틀릿 태그에 사용하여 단순히 값을 출력 하는 표현문 태그(<%= ...%>)와 같은 결과를 얻을 수 있음

 

메소드 반환 유형 설명
print(String str) void 설정된 str 값을 웹 브라우저에 출력
println(String str) void 설정된 str 값을 웹 브라우저에 출력. 이 때 줄 바꿈이 적용되지 않음.
newLine() void 줄바꿈을 출력
getBufferSize() int 현재 출력 버퍼의 크기를 가져옴
getRemaining() int 현재 남아 있는 출력 버퍼의 크기를 가져옴
clear() void 현재 출력 버퍼에 저장되어 있는 내용을 웹 브라우저에 전송하지 않고 비움. 만약 버퍼가 이미 플러시 되었다면 IOException이 발생.
clearBuffer() void 현재 출력 버퍼에 저장되어 있는 내용을 웹 브라우저에 전송하지 않고 비움. 만약 버퍼가 이미 플러시 되었다면 IOException이 발생하지 않음
flush() void 현재 출력 퍼버에 저장되어 있는 내용을 웹 브라우저에 전송하고 비움
isAutoFlush() boolean 출력 버퍼가 채워졌을 때의 처리를 결정. 자동으로 플러시 하는 경우 true를 반환하고, 그렇지 않은 경우 false를 반환

 

 

 

 

[ 내용 참고 : IT 학원 강의 ]

+ Recent posts