티스토리 뷰

1.    ViewResolver

-      MVC 패턴에서 Model 데이터를 이용하여, 최종 응답화면을 생성할 View 역할을 수행할 대상을 찾아낸다.

-      1 ) 접두사 : /WEB-INF/views/

-      2 ) 접미사 : .jsp

-      3 ) 최종 뷰의 이름 : 접두사 + 뷰 이름 + 접미사 = /WEB-INF/views/뷰 이름.jsp

 

2.    DataSource 설정

-      DBConnection을 맺고 끊는 작업은 리소스의 소모가 많은 작업이다.

-      그렇기에 Pooling이라는 기법을 통해서 객체를 미리 생성하고 빌려 쓰는 방식으로 이용해서 연결 시간을 단축시킨다.

 

3.    Servlet – context.xml파일과 root – context.xml파일의 차이점

-      같이 빈을 관리하지만, 웹과 관련된 빈은 Servlet-context.xml에 관리하고

-      웹과 관련이 없는 빈은 root – context.xml 파일에서 관리한다.


[ 1. servlet-context.xml 파일내 태그의 의미 ]

 


[ 2. web.xml 파일의 설명 ]

 

더보기

[ + 코드 보기 ]

<?xml version="1.0" encoding="UTF-8"?>

<web-app
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
  version="4.0">

  <display-name>chap02</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-list>

  
  <!-- ====================== -->
  <!-- 공통 JSP 설정          -->
  <!-- ====================== -->
  <jsp-config>
    <jsp-property-group>
      <url-pattern>*.jsp</url-pattern>
      <page-encoding>UTF-8</page-encoding>
      <include-prelude>/WEB-INF/views/include.jsp</include-prelude>
      <trim-directive-whitespaces>true</trim-directive-whitespaces>
      <default-content-type>text/html; charset=utf8</default-content-type>
    </jsp-property-group>
  </jsp-config>


  <!-- =============================== -->
  <!-- Web Application 예외처리방법#1  -->
  <!-- =============================== -->
  <error-page>
      <error-code>500</error-code>
      <location>/WEB-INF/views/errors/500.jsp</location>
  </error-page>

  <error-page>
      <error-code>404</error-code>
      <location>/WEB-INF/views/errors/404.jsp</location>
  </error-page>


  <!-- =============================== -->
  <!-- Web Application 예외처리방법#2  -->
  <!-- =============================== -->
  <error-page>
      <exception-type>java.lang.NullPointerException</exception-type>
      <location>/WEB-INF/views/errors/null.jsp</location>
  </error-page>


  <!-- =============================== -->
  <!-- Http Session 만료시간설정(in minutes) -->
  <!-- =============================== -->
  <session-config>
      <session-timeout>30</session-timeout>
  </session-config>

  <!-- =============================== -->
  <!-- 아래는 Spring Project 생성시 자동 생성되는 부분 -->
  <!-- =============================== -->
  
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/spring/root-context.xml</param-value>
  </context-param>

  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

  <!-- =============================== -->
  <!-- 프런트 컨트롤러 역할을 하는 Servlet : DispatcherServlet -->
  <!-- =============================== -->

  <servlet>
    <servlet-name>appServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

    <!-- servlet-context.xml는 웹과 관련이 없는 빈을 저장한다. -->

    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
    </init-param>
      
      <!-- 프런트 컨트롤러가 헨들러를 찾지 못하면 나오는 예외 -->
      <init-param>
         <param-name>throwExceptionIfNoHandlerFound</param-name>
         <param-value>true</param-value>
      </init-param>
    
    <!-- 요청을 받을시 로드되는 순서를 지정한다. -->
    <load-on-startup>1</load-on-startup>
  </servlet>

   <servlet-mapping>
     <servlet-name>appServlet</servlet-name>
     <url-pattern>/</url-pattern>
   </servlet-mapping>

  <!-- =============================== -->
  <!-- 자동생성되지 않는 부분 -->
  <!-- =============================== -->

   <filter>
      <filter-name>encodingFilter</filter-name>
      <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>

      <!-- 프론트 컨트롤러가 전송 파라미터를 깨지지 않고 잘 받을 수 있도록 설정 -->
      <init-param>
         <param-name>encoding</param-name>
         <param-value>utf8</param-value>
      </init-param>

      <init-param>
         <param-name>forceEncoding</param-name>
         <param-value>true</param-value>
      </init-param>
   </filter>

   <filter-mapping>
      <filter-name>encodingFilter</filter-name>
      <url-pattern>/*</url-pattern>
   </filter-mapping>


</web-app>

[ 3. root-cotext.xml 파일에서 빈을 수동으로 등록하는 방법 ] (**)

 

더보기

[ + 코드 보기 ]

<?xml version="1.0" encoding="UTF-8"?>

<beans 
	xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
	
	<!-- Root Context: defines shared resources visible to all other web components -->

	<!-- 여기 안에 속한 것은 모두 빈 타입으로 등록하겠다는 의미이다. -->
	<!-- <context:component-scan base-package="org.zerock.myapp.sample" /> -->

	<!-- 빈을 수동으로 등록하는 법 -->
	<!-- 빈의 이름은 name이 아니라 id값으로 나온다. (***) -->
	<bean id="hotel" name="myHotel" class="org.zerock.myapp.sample.Hotel" />
		
</beans>

[ 4. Servlet - context.xml파일에서 view-resolvers 설정 ] (***)

 

더보기

[ + 코드 보기 ]

<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
<!-- View로 어떤 JSP가 사용되어야 하는지 알려준다. -->
<!-- ViewResolver는 MVC 패턴에서 Model 데이터를 이용하여 최종 응답화면을 생성할 View 역할을 수행할 대상을 찾아낸다. -->
<!-- [ 예전 버전 ] -->
<!-- + 예전 버전은 빈으로 등록하는 방법을 사용했다. -->
<!-- <beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> -->
    <!-- beans:property는 setPrefix와 setSuffix를 value값으로 해주는것이다. -->
    <!-- <beans:property name="prefix" value="/WEB-INF/views/" /> -->
    <!-- <beans:property name="suffix" value=".jsp" /> -->
<!-- </beans:bean> -->

<!-- [ 현재 버전 ] -->
<view-resolvers>
    <jsp prefix="/WEB-INF/views/" suffix=".jsp" />
</view-resolvers>

[ 5. pom.xml파일에서 Hikari CP 추가하기 ] (**)

 

더보기

[ + 코드 보기 ]

<?xml version="1.0" encoding="UTF-8"?>
 <!-- 1~2칸 띄우기 -->

<project
   xmlns="http://maven.apache.org/POM/4.0.0"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">

   <modelVersion>4.0.0</modelVersion>

   <groupId>org.zerock</groupId>
   <artifactId>chap3</artifactId>
   <version>1.0.0-BUILD-SNAPSHOT</version>

   <!-- 웹에 패키징되는 건 war -->
   <packaging>war</packaging>

   <name>chap3</name>
   <url>http://springmvc.example.com</url>
   <description>Spring MVC project</description>


   <!-- 프로젝트 어디서든 가져다 쓸수 있도록 정의 -->
   <properties>
      
      <!-- 자바버전 -->
      <java-version>11</java-version>
      <!-- <java-home>${env.JAVA_HOME}</java-home> -->

      <!-- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      <maven.compiler.source>11</maven.compiler.source>
      <maven.compiler.target>11</maven.compiler.target> -->
      
      <!-- 스프링버전 -->
      <org.springframework-version>5.3.21</org.springframework-version>

      <org.aspectj-version>1.9.9.1</org.aspectj-version>
      <org.apache.logging.log4j-version>2.17.2</org.apache.logging.log4j-version>
   </properties>


   <dependencies>

        <!-- =============== Logging =============== -->

        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>${org.apache.logging.log4j-version}</version>
        </dependency>

        <!-- For Spring framework, HikariCP, DriverSpy logging -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j-impl</artifactId>
            <version>${org.apache.logging.log4j-version}</version>
        </dependency>


        <!-- ============= Servlet/JSP ============= -->
         
      <dependency>
         <groupId>javax.servlet</groupId>
         <artifactId>javax.servlet-api</artifactId>
         <version>4.0.1</version>
         <scope>provided</scope>
      </dependency>
   
      <dependency>
         <groupId>javax.servlet.jsp</groupId>
         <artifactId>javax.servlet.jsp-api</artifactId>
         <version>2.3.3</version>
         <scope>provided</scope>
      </dependency>

      <dependency>
         <groupId>javax.servlet</groupId>
         <artifactId>jstl</artifactId>
         <version>1.2</version>
      </dependency>


        <!-- =============== AspectJ (스프링할 때 rt, weaver 꼭)=============== -->
            
      <dependency>
         <groupId>org.aspectj</groupId>
         <artifactId>aspectjrt</artifactId> <!-- rt = runtime -->
         <version>${org.aspectj-version}</version>
      </dependency>

      <dependency>
         <groupId>org.aspectj</groupId>
         <artifactId>aspectjweaver</artifactId>
         <version>${org.aspectj-version}</version>
      </dependency>


        <!-- ================ Spring (밑의 2개는 최소한 꼭) =============== -->

      <!-- 스프링 빈즈 컨테이너 -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>

      <!-- 강제 -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>${org.springframework-version}</version>
			<scope>test</scope>
		</dependency>

      <!-- =============== data source =============== -->

      <!-- 히카리CP -->
      <dependency>
         <groupId>com.zaxxer</groupId>
         <artifactId>HikariCP</artifactId>
         <version>5.0.1</version>

         <exclusions>

            <!-- 충돌이 발생하기에 제외시켜줘야 한다. -->
            <exclusion>
               <groupId>org.slf4j</groupId>
               <artifactId>slf4j-api</artifactId>
            </exclusion>

         </exclusions>

      </dependency>

      <!-- =============== JDBC =============== -->

      <dependency>
         <groupId>org.bgee.log4jdbc-log4j2</groupId>
         <artifactId>log4jdbc-log4j2-jdbc4</artifactId>
         <version>1.16</version>
      </dependency>
        
      <dependency>
         <groupId>com.oracle.database.jdbc</groupId>
         <artifactId>ojdbc8-production</artifactId>
         <version>21.5.0.0</version>
      
         <type>pom</type>
      
         <exclusions>
            <exclusion>
               <groupId>com.oracle.database.ha</groupId>
               <artifactId>simplefan</artifactId>
            </exclusion>
      
            <exclusion>
               <groupId>com.oracle.database.ha</groupId>
               <artifactId>ons</artifactId>
            </exclusion>
      
            <exclusion>
               <groupId>com.oracle.database.jdbc</groupId>
               <artifactId>rsi</artifactId>
            </exclusion>
      
            <exclusion>
               <groupId>com.oracle.database.jdbc</groupId>
               <artifactId>ucp</artifactId>
            </exclusion>
      
            <exclusion>
               <groupId>com.oracle.database.xml</groupId>
               <artifactId>xdb</artifactId>
            </exclusion>
      
            <exclusion>
               <groupId>com.oracle.database.xml</groupId>
               <artifactId>xmlparserv2</artifactId>
            </exclusion>
         </exclusions>
      </dependency>


        <!-- =============== Testing (버전 4,5 둘다 쓸줄알아야함)=============== -->

      <dependency>
         <groupId>org.junit.jupiter</groupId>
         <artifactId>junit-jupiter-api</artifactId>
         <version>5.8.2</version>
         <scope>test</scope>
      </dependency>

    
        <!-- ================ Misc ================= -->

      <dependency>
         <groupId>javax.inject</groupId>
         <artifactId>javax.inject</artifactId>
         <version>1</version>
      </dependency>
   
      <dependency>
         <groupId>org.projectlombok</groupId>
         <artifactId>lombok</artifactId>
         <version>1.18.24</version>
         <scope>provided</scope>
      </dependency>
           
   </dependencies>


    <build>

      <finalName>/</finalName>

        <plugins>

            <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-war-plugin</artifactId>
            <version>3.3.2</version>
            </plugin>

            <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-eclipse-plugin</artifactId>
            <version>2.10</version>

                <configuration>
                    <downloadSources>true</downloadSources>
                    <downloadJavadocs>false</downloadJavadocs>
                </configuration>
            </plugin>

            <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
                <version>3.10.1</version>

            <configuration>
               <release>${java-version}</release>
            </configuration>
            </plugin>

        </plugins>

    </build>

</project>

[ 6. root-context.xml에서 HikariConfiguration과 hikariDataSource 빈 등록하기  ] (***)

 

더보기

[ + 코드 보기 ]

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:context="http://www.springframework.org/schema/context"
   xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
      http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
   
   <!-- Root Context: defines shared resources visible to all other web components -->
   
   <!-- Hikari Configuration -->
   <!-- primary는 같은 이름이 여러개 일때, 이것을 우선순위로 삼으라는 의미이다. -->
   <bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig" primary="true" >
      <description>HikariCP Configuration</description>

      <!-- 1. JDBC 연결정보 속성들에 값 설정 -->
      <property name="driverClassName" value="net.sf.log4jdbc.sql.jdbcapi.DriverSpy" />
      <property name="jdbcUrl" value="jdbc:log4jdbc:oracle:thin:@db0000000_high?TNS_ADMIN=C:/opt/OracleCloudWallet/ATP"/>
      <property name="username" value="HR"/>
      <property name="password" value="Oracle"/>

      <!-- 2. Connection Pool의 작동방식과 관련된 속성들에 값 설정 -->
      <property name="maximumPoolSize" value="10"/>
      <property name="minimumIdle" value="2"/>
      <property name="idleTimeout" value="10000"/>
      <property name="connectionTimeout" value="1000"/>
      <property name="connectionTestQuery" value="SELECT 1 FROM dual"/>
      <property name="dataSourceJNDI" value="jdbc/HikariCP"/>
      <property name="poolName" value="*** HikariDataSource ***"/>
   </bean>

   <bean 
      id="hikariDataSource" 
      class="com.zaxxer.hikari.HikariDataSource"
      destroy-method="close">
      <description>HikariCP DataSource</description>

      <!-- 생성자 매개변수가 2개 이상일 때 사용할 수 있는 속성 -->
      <!-- <constructor-arg name="" value="" ref="" index=""/> -->
      
      <constructor-arg ref="hikariConfig"/>
   </bean>
</beans>

[ 7. 히카리CP 활용하기  ] (****)

 

더보기

[ + 코드 보기 ]

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import javax.sql.DataSource;

import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.Timeout;
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 lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;

@Log4j2
@NoArgsConstructor

@ExtendWith(SpringExtension.class)
@ContextConfiguration(locations = { "file:src/main/webapp/WEB-INF/spring/**/*.xml" })

@TestInstance(Lifecycle.PER_CLASS)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class DataResourceTests {
	
	// 테스트하는데 필요한 빈을 주입해 주세요! 라고 시그널을 Beans Container에 전송함.
	// 그런데, 우리 테스트에 필요한 빈이 뭔가요!? => `HikariDataSource` Bean이 필요함!!!
	@Autowired
	private DataSource datasource;
	
	// =================================================================
	
	@BeforeAll
	void beforeAll() {
		log.trace("beforeAll() invokd.");
		Objects.nonNull(this.datasource);
		
		log.trace("\t + this.datasource : {}", this.datasource);
	} // beforeAll
	
	// =================================================================
	
	@Test
	@Order(1)
	@DisplayName("testHikariCP")
	@Timeout(value=1000, unit=TimeUnit.MILLISECONDS)
	void testHikariCP() throws SQLException {
		
		log.trace("testHikariCP() invoked.");
		
		Connection conn = datasource.getConnection();
		Statement stmt = conn.createStatement();
		ResultSet rs = stmt.executeQuery("SELECT * FROM employees");
		
		try ( conn; stmt; rs; ){
			
			log.info("\t + conn : {}", conn);
			log.info("\t + stmt : {}", stmt);
			log.info("\t + rs : {}", rs);
			
			while( rs.next() ) {
				
				String employee_id = rs.getString("EMPLOYEE_ID");
				String first_name = rs.getString("FIRST_NAME");
				String last_name = rs.getString("LAST_NAME");
				String email = rs.getString("EMAIL");
				String phone_number = rs.getString("PHONE_NUMBER");
				String hire_date = rs.getString("HIRE_DATE");
				String job_id = rs.getString("JOB_ID");
				String salary = rs.getString("SALARY");
				String commission_pct = rs.getString("COMMISSION_PCT");
				String department_id = rs.getString("DEPARTMENT_ID");
				
				String employee = String.format(
						"%S, %S, %S, %S, %S, %S, %S, %S, %S, %S",
						employee_id, first_name, last_name, email, phone_number, hire_date, job_id, salary, commission_pct, department_id);
				
				log.info(employee);
						
			} // while
			
		} // try - with - resources
		
	} // testHikariCP
	
	// =================================================================

} // end class

[ 8. 히카리CP 활용하기 2  ] (****)

 

더보기

[ + 코드 보기 ]

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

import java.sql.SQLException;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import javax.sql.DataSource;

import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.Timeout;
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 com.zaxxer.hikari.HikariConfig;

import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.extern.log4j.Log4j2;

@Log4j2
@NoArgsConstructor

@ExtendWith(SpringExtension.class)
@ContextConfiguration(locations = { "file:src/main/webapp/WEB-INF/spring/**/*.xml" })

@TestInstance(Lifecycle.PER_CLASS)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class DataResourceTests2 {
	
	// 테스트하는데 필요한 빈을 주입해 주세요! 라고 시그널을 Beans Container에 전송함.
	// 그런데, 우리 테스트에 필요한 빈이 뭔가요!? => `HikariDataSource` Bean이 필요함!!!
	@Autowired
	private DataSource datasource;
	
	
	// 테스트하는데 필요한 빈을 주입해 주세요!
	// 어느 빈 ? => HikariConfig빈이요!
	// 루트 컨텍스트에 등록한 HikariConfig빈을 얻은다.
	@Setter(onMethod_= {@Autowired})
	private HikariConfig config;
	
	// =================================================================
	
	@BeforeAll
	void beforeAll() {
		log.trace("beforeAll() invokd.");
		
		Objects.nonNull(this.datasource);
		log.trace("\t + this.datasource : {}", this.datasource);
		
		assertNotNull(this.config);
		log.trace("\t + this.config : {}", this.config);
		
	} // beforeAll
	
	// =================================================================
	
	@Test
	@Order(1)
	@DisplayName("testHikariConfig")
	@Timeout(value=1000, unit=TimeUnit.MILLISECONDS)
	void testHikariConfig() throws SQLException {
		
		log.trace("testHikariConfig() invoked.");
		
		// =================================================
		// 루트 컨텍스트에 등록한 HikariConfig의 속성을 활용
		// =================================================
		
		log.info("\t + 1. DriverClass : {}", this.config.getDriverClassName());
		// + 1. DriverClass : net.sf.log4jdbc.sql.jdbcapi.DriverSpy
		
		log.info("\t + 2. JdbcUrl : {}", this.config.getJdbcUrl() );
		// + 2. JdbcUrl : jdbc:log4jdbc:oracle:thin:@000_high?TNS_ADMIN=C:/opt/OracleCloudWallet/ATP
		
		log.info("\t + 3. Username : {}", this.config.getUsername() );
		// + 3. Username : HR
		
		log.info("\t + 4. IdleTimeout : {}", this.config.getIdleTimeout());
		// + 4. IdleTimeout : 10000
		
	} // testHikariConfig
	
	// =================================================================

} // end class
728x90
댓글
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
최근에 올라온 글
Total
Today
Yesterday
공지사항