SpringMVC Framework를 사용하여 웹프로그램 작성 방법

woom·2023년 2월 27일
0

Framework

목록 보기
15/20
post-thumbnail

🌼 웹프로그램 작성 순서

  • SpringMVC Framework를 사용하여 웹프로그램을 작성하는 방법

  • 테이블 → DTO 클래스 → DAO 클래스(Mybatis) → Service 클래스 → Controller 클래스 → 테스트 프로그램(JUint) → 단위 프로그램(모듈) 테스트 → HTML 문서를 JSP 문서로 변환 → 브라우저를 이용한 통합 프로그램 테스트


📌 빌드 처리 (pom.xml)

  • JDBC 기능을 제공하기 위한 OracleDriver 관련 라이브러리

  • Spring DAO 관련 기능을 제공하는 라이브러리 (Spring DataSource 관련 클래스 포함)

  • Mybatis Framework 관련 라이브러리

  • Spring Framework에 Mybatis Framework 기능을 제공하기 위한 라이브러리



		<!-- https://mvnrepository.com/artifact/com.oracle.database.jdbc/ojdbc11 -->
		<!-- => JDBC 기능을 제공하기 위한 OracleDriver 관련 라이브러리 -->
		<dependency>
		    <groupId>com.oracle.database.jdbc</groupId>
		    <artifactId>ojdbc11</artifactId>
		    <version>21.9.0.0</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
		<!-- => Spring DAO 관련 기능을 제공하는 라이브러리 - Spring DataSource 관련 클래스 포함 -->
		<!-- => 라이브러리 의존관계에 의해 spring-tx 라이브러리(트렌젝션 관리)도 빌드 처리 -->
		<dependency>
		    <groupId>org.springframework</groupId>
		    <artifactId>spring-jdbc</artifactId>
		    <version>${org.springframework-version}</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
		<!-- => Mybatis Framework 관련 라이브러리 -->
		<dependency>
		    <groupId>org.mybatis</groupId>
		    <artifactId>mybatis</artifactId>
		    <version>3.5.11</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
		<!-- => Spring Framework에 Mybatis Framework 기능을 제공하기 위한 라이브러리 -->
		<dependency>
		    <groupId>org.mybatis</groupId>
		    <artifactId>mybatis-spring</artifactId>
		    <version>3.0.1</version>
		</dependency>





📌 mybatis-config.xml

  • Mybatis Framework의 환경설정파일 작성 (생략 가능)

    • src/main/webapp 폴더에 작성해야만 스프링 컨테이너(WebApplicationContenxt 객체)가 Mybatis Framework의 환경설정파일에 접근 가능
    • 환경설정에 따라 src/main/java 또는 src/main/resources 폴더에 작성 가능
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
	<settings>
		<setting name="mapUnderscoreToCamelCase" value="true"/>
		<setting name="jdbcTypeForNull" value="NULL"/>
		<setting name="callSettersOnNulls" value="true"/>
	</settings>
</configuration>





📕 root-context.xml

  • root-context.xml : 모든 Front Controller 역할의 객체에서 공통적으로 사용될 클래스를 Spring Bean으로 등록하기 위한 Spring Bean Configuration File

    • DAO 클래스 작성에 필요한 클래스를 Spring Bean으로 등록
    • DataSource, SqlSessionFactory, SqlSession, TransactionManager 등
  • DataSource 관련 클래스를 Spring Bean으로 등록 - DBCP(DataBase Connection Pool)
    • <bean class="org.springframework.jdbc.datasource.DriverManagerDataSource" id="dataSource">
    • DataSource 객체 필드에 Connection 객체 생성에 필요한 값을 인젝션 처리
    • driverClassName, url, username, password
  • SqlSessionFactory 관련 클래스를 Spring Bean으로 등록
    • SqlSessionFactoryBean 객체 필드에 객체 생성에 필요한 값을 인젝션 처리
  • configLocation 필드에 Mybatis Framework의 환경설정파일에 경로가 저장되도록 설정
    • SpringMVC Framework에서 사용하는 스프링 컨테이너(WebApplicationContext 객체)는 [src/main/webapp] 폴더를 웹자원의 최상위 폴더로 처리하여 환경설정파일의 경로를 제공
    • <property name="configLocation" value="/WEB-INF/spring/mybatis-config.xml"/>
    • [src/main/java] 폴더 또는 [src/main/resources] 폴더에 환경설정파일이 있는 경우 classpath 접두사를 사용하면 스프링 컨테이너로 접근 가능 (폴더의 패키지에 작성된 환경설정파일 파일 시스템 경로 표현하여 접근 가능)
    • <property name="configLocation" value="classpath:mybatis-config.xml"/>
  • dataSource 필드에 DataSource 관련 클래스의 Spring Bean이 저장되도록 설정 (DI)
    • Mybatis 환경설정파일에서 environment 엘리먼트와 유사한 기능 제공
  • typeAliasesPackage 필드에 DTO 클래스를 작성한 패키지가 저장되도록 설정
    • XML 기반의 매퍼파일(MapperFile)에서 Java 자료형 대신 사용할 별칭을 제공하기 위한 기능
    • Mybatis 환경설정파일에서 typeAliases 엘리먼트의 package 엘리먼트와 유사한 기능 제공
  • mapperLocations 필드에 List 객체를 생성하여 저장되도록 설정
    • List 객체에는 XML 기반의 매퍼 파일의 경로가 요소값으로 저장되도록 추가 (매퍼 등록)
    • [src/main/java] 폴더의 패키지에 매퍼 파일을 작성하기 위한 classpath 접두사 사용
    • <value>classpath:xyz/itwill10/mapper/*.xml</value>
  • SqlSession 관련 클래스를 Spring Bean으로 등록
    • SqlSessionTemplate 클래스로 객체를 생성하기 위한 생성자 매개변수에 SqlSessionFactoryBean 객체를 전달하여 필드 초기화 처리 (DI)
    • destroy-method 속성을 사용하여 Spring Bean 소멸전 clearCache 메소드가 자동 호출되도록 설정
    • clearCache 메소드는 SqlSessionTemplate 객체 소멸전 SqlSessionTemplate 객체에 의해 사용된 JDBC 관련 객체를 정리하는 메소드
    • DAO 클래스의 메소드에서 SqlSession 객체 사용후 close() 메소드를 호출하지 않도록 설정
    • <bean class="org.mybatis.spring.SqlSessionTemplate" id="sqlSession" destroy-method="clearCache">


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
	
	<!-- Root Context: defines shared resources visible to all other web components -->
	<!-- root-context.xml : 모든 Front Controller에서 객체로 사용될 클래스를 Spring Bean으로
	등록하기 위한 Spring Bean Configuration File -->
	<!-- => DAO 클래스 작성에 필요한 클래스를 Spring Bean으로 등록 -->
	<!-- => DataSource, SqlSessionFactory, SqlSession, TransactionManager 등 -->
		
	<!-- DataSource 관련 클래스를 Spring Bean으로 등록 - DBCP(DataBase Connection Pool) -->
	<!-- => DataSource 객체 필드에 Connection 객체 생성에 필요한 값을 인젝션 처리 -->	
	<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource" id="dataSource">
		<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
		<property name="url" value="jdbc:oracle:thin:@localhost:1521:xe"/>
		<property name="username" value="scott"/>
		<property name="password" value="tiger"/>
	</bean>
	
	<!-- SqlSessionFactory 관련 클래스를 Spring Bean으로 등록 -->
	<!-- => SqlSessionFactoryBean 객체 필드에 객체 생성에 필요한 값을 인젝션 처리 -->
	<bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactoryBean">
		<!-- configLocation 필드에 Mybatis Framework의 환경설정파일의 경로가 저장되도록 인젝션 처리 -->
		<!-- => SpringMVC Framework에서 사용하는 스프링 컨테이너(WebApplicationContext 객체)는
		[src/main/webapp] 폴더를 웹자원의 최상위 폴더로 처리하여 환경설정파일의 경로를 제공 -->
		<!-- <property name="configLocation" value="/WEB-INF/spring/mybatis-config.xml"/> -->
		<!-- [src/main/java] 폴더 또는 [src/main/resources] 폴더에 환경설정파일을 작성한 경우
		classpath 접두사를 사용하면 스프링 컨테이너(WebApplicationContext 객체)로 접근 가능 -->
		<!-- => 폴더의 패키지에 작성된 환경설정파일은 파일 시스템 형식으로 경로를 표현하여 접근 가능 -->
		<!-- <property name="configLocation" value="classpath:xyz/itwill/config/mybatis-config.xml"/> -->
		<property name="configLocation" value="classpath:mybatis-config.xml"/>
		
		<!-- dataSource 필드에 DataSource 관련 클래스의 Spring Bean이 저장되도록 인젝션 처리 - DI -->
		<!-- => Mybatis 환경설정파일에서 environment 엘리먼트와 유사한 기능 제공 -->
		<property name="dataSource" ref="dataSource"/>
		
		<!-- typeAliasesPackage 필드에 DTO 클래스를 작성한 패키지가 저장되도록 인젝션 처리 -->
		<!-- => XML 기반의 매퍼파일(MapperFile)에서 Java 자료형 대신 사용할 별칭을 제공하기 위한 기능 -->
		<!-- => Mybatis 환경설정파일에서 typeAliases 엘리먼트의 package 엘리먼트와 유사한 기능 제공 -->
		<property name="typeAliasesPackage" value="xyz.itwill10.dto"/>
		
		<!-- mapperLocations 필드에 List 객체를 생성하여 저장되도록 인젝션 처리 -->
		<!-- => List 객체에는 XML 기반의 매퍼 파일의 경로가 요소값으로 저장되도록 추가 - 매퍼 등록 -->
		<!-- => Mybatis 환경설정파일에서 mappers 엘리먼트의 package 엘리먼트와 유사한 기능 제공 -->
		<property name="mapperLocations">
			<list>
				<!-- [src/main/java] 폴더의 패키지에 매퍼 파일을 작성하기 위한 classpath 접두사 사용  -->
				<value>classpath:xyz/itwill10/mapper/*.xml</value>
			</list>
		</property>				
	</bean>
	
	<!-- SqlSession 관련 클래스를 Spring Bean으로 등록 -->
	<!-- => SqlSessionTemplate 클래스로 객체를 생성하기 위한 생성자 매개변수에 SqlSessionFactoryBean
	객체를 전달하여 필드 초기화 처리 - DI -->
	<!-- destroy-method 속성을 사용하여 Spring Bean 소멸전 clearCache 메소드가 자동 호출되도록 설정  -->
	<!-- => clearCache 메소드는 SqlSessionTemplate 객체 소멸전 SqlSessionTemplate 객체에 의해
	사용된 JDBC 관련 객체를 정리하는 메소드 -->
	<!-- => DAO 클래스의 메소드에서 SqlSession 객체 사용후 close() 메소드를 호출하지 않도록 설정 -->
	<bean class="org.mybatis.spring.SqlSessionTemplate" id="sqlSession" destroy-method="clearCache">
		<constructor-arg ref="sqlSessionFactoryBean"/>
	</bean>
</beans>






📕 servlet-context.xml

  • component-scan : 스프링 컨테이너가 스프링 어노테이션을 검색하여 처리하기 위한 엘리먼트

    • base-package 속성 : 스프링 어노테이션을 검색하기 위해 어노테이션을 사용한 클래스의 패키지를 속성값으로 설정
    • controller 패키지에 요청 처리 클래스(Model)를 작성하고, dao 패키지에 DAO 클래스를 작성하고, service 패키지에 service 클래스를 작성한 후 스프링 어노테이션을 이용하여 Spring Bean으로 등록
    • <context:component-scan base-package="xyz.itwill10.service" />


<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:beans="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
		http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

	<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
	<!-- servlet-context.xml : appServlet 이름의 Front Controller에서 객체로 사용될 클래스를 
	Spring Bean으로 등록하기 위한 Spring Bean Configuration File -->
	
	<!-- Enables the Spring MVC @Controller programming model -->
	<!-- annotation-driven : @Controller 어노테이션을 사용하여 요청 처리 클래스를 Spring Bean으로
	등록하고 @RequestMapping 어노테이션을 사용하여 작성된 메소드를 요청 처리 메소드로 등록하여
	클라이언트 요청에 의해 요청 처리 클래스의 메소드가 호출되어 처리되도록 설정하는 엘리먼트 -->
	<!-- => HandlerMapping 객체를 사용하지 않아도 요청 처리 클래스의 요청 처리 메소드가 
	클라이언트의 요청에 의해 호출되도록 자동으로 매핑 처리 -->
	<annotation-driven />

	<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
	<!-- resources : 클라이언트 요청을 Front Controller가 직접 응답 처리되도록 설정하는 엘리먼트 -->
	<!-- => 클라이언트의 리소스 파일 요청에 대한 응답 처리를 위해 사용하는 엘리먼트 -->
	<!-- mapping 속성 : 클라이언트에 의해 요청되는 리소스 파일의 요청 URL 주소 패턴을 속성값으로 설정 -->
	<!-- => [**] 패턴문자를 속성값으로 사용한 경우 현재 폴더 및 하위 폴더의 리소스 파일 요청 가능 -->
	<!-- location 속성 : 클라이언트 요청에 의해 리소스 파일을 검색하기 위한 폴더를 속성값으로 설정 -->
	<!-- <resources mapping="/resources/**" location="/resources/" /> -->
	<resources mapping="/images/**" location="/resources/images/" />
	<resources mapping="/css/**" location="/resources/css/" />
	<resources mapping="/js/**" location="/resources/js/" />

	<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
	<!-- InternalResourceViewResolver 클래스를 Spring Bean으로 등록 -->
	<!-- InternalResourceViewResolver 객체 : 클라이언트 요청에 의해 호출되는 요청 처리 메소드의
	반환값(ViewName)을 제공받아 응답 가능한 JSP 문서로 변환하여 반환하는 객체 -->
	<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<beans:property name="prefix" value="/WEB-INF/views/" />
		<beans:property name="suffix" value=".jsp" />
		<beans:property name="order" value="3"/>
	</beans:bean>

	<!-- UrlBasedViewResolver 클래스를 Spring Bean으로 등록 -->
	<!-- UrlBasedViewResolver 객체 : 클라이언트 요청에 의해 호출되는 요청 처리 메소드의
	반환값(ViewName)을 제공받아 Spring Framework가 제공하는 ViewResolver 객체가 아닌
	외부의 뷰프로그램의 이용하여 응답 처리하는 객체 -->
	<!-- => 뷰이름으로 응답하기 위한 뷰를 커스터마이징 할 때 사용하는 객체 -->
	<beans:bean class="org.springframework.web.servlet.view.UrlBasedViewResolver">
		<!-- viewClass 필드에 뷰프로그램을 구현한 클래스를 인젝션 처리 -->
		<beans:property name="viewClass" value="org.springframework.web.servlet.view.tiles3.TilesView"/>
		<!-- order 필드에 ViewResolver 객체의 우선순위 관련 정수값을 인젝션 처리  -->
		<!-- => 다수의 ViewResolver 객체를 이용할 경우 모든 ViewResolver 객체는 반드시 우선순위 설정 -->
		<!-- => 필드의 저장된 정수값이 적을수록 우선순위가 높게 설정 -->
		<beans:property name="order" value="2"/>
	</beans:bean>

	<!-- TilesConfigurer 클래스를 Spring Bean으로 등록 -->
	<!-- TilesConfigurer 객체 : TilesView 프로그램의 응답관련 정보를 저장한 Tiles 환경설정파일을 제공하기 위한 객체 -->
	<beans:bean class="org.springframework.web.servlet.view.tiles3.TilesConfigurer">
		<!-- definitions 필드에 List 객체를 생성하여 인젝션 처리 -->
		<!-- => List 객체의 요소로 Tiles 환경설정파일(XML)의 경로를 추가하여 제공 -->
		<beans:property name="definitions">
			<beans:list>
				<beans:value>/WEB-INF/spring/appServlet/tiles.xml</beans:value>
			</beans:list>
		</beans:property>
	</beans:bean>

	<!-- component-scan : 스프링 컨테이너가 스프링 어노테이션을 검색하여 처리하기 위한 엘리먼트 -->
	<!-- base-package 속성 : 스프링 어노테이션을 검색하기 위해 어노테이션을 사용한 클래스의 패키지를 속성값으로 설정 -->	
	<!-- <context:component-scan base-package="xyz.itwill.controller" /> -->
	<!-- xyz.itwill10.controller 패키지에 요청 처리 클래스(Model)를 작성하고 스프링 어노테이션을 이용하여 Spring Bean으로 등록 -->
	<context:component-scan base-package="xyz.itwill10.controller" />
	<!-- xyz.itwill10.dao 패키지에 DAO 클래스를 작성하고 스프링 어노테이션을 이용하여 Spring Bean으로 등록 -->
	<context:component-scan base-package="xyz.itwill10.dao" />
	<context:component-scan base-package="xyz.itwill10.service" />
</beans:beans>





🐣 VO class (Student)

package xyz.itwill10.dto;

import lombok.Data;

@Data
public class Student {
	private int no;
	private String name;
	private String phone;
	private String address;
	private String birthday;
}






🌸 Mapper (interface)

package xyz.itwill10.mapper;

import java.util.List;

import xyz.itwill10.dto.Student;

public interface StudentMapper {
	int insertStudent(Student student);
	List<Student> selectStudentList();
}





📙 Mapper (interface상속)

  • Interface Mapper 파일과 바인딩 하기 위한 namespace 속성값으로 Interface Mapper 파일의 경로 설정
    • <mapper namespace="xyz.itwill10.mapper.StudentMapper">
    • Interface Mapper 파일과 바인딩할 경우 parameterType 속성 생략 가능
    • 검색행의 컬럼명과 DTO 클래스의 필드명이 같은 경우 resultType 속성을 사용하여 자동 매핑 처리

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- Interface Mapper 파일과 바인딩 하기 위한 namespace 속성값으로 Interface Mapper 파일의 경로 설정 -->
<mapper namespace="xyz.itwill10.mapper.StudentMapper">
	<!-- Interface Mapper 파일과 바인딩할 경우 parameterType 속성 생략 가능 -->
	<insert id="insertStudent">
		insert into student values(#{no},#{name},#{phone},#{address},#{birthday})
	</insert>
	
	<!-- 검색행의 컬럼명과 DTO 클래스의 필드명이 같은 경우 resultType 속성을 사용하여 자동 매핑 처리 -->
	<select id="selectStudentList" resultType="Student">
		select * from student order by no	
	</select>
</mapper>





🌸 DAO (interface)

package xyz.itwill10.dao;

import java.util.List;

import xyz.itwill10.dto.Student;

public interface StudentDAO {
	int insertStudent(Student student);
	List<Student> selectStudentList();
}





📒 DAOImpl (interface상속)

  • SpringMVC Framework에 Mybatis Framework를 사용하여 DAO 클래스를 작성하는 방법
  1. DataSource 관련 라이브러리와 Mybatis 관련 라이브러리를 프로젝트에 빌드 처리 (메이븐 : pom.xml)

    • ojdbc, spring-jdbc(spring-tx), mybatis, mybatis-spring
  2. Mybatis Framework의 환경설정파일 작성 (생략 가능)

    • src/main/webapp 폴더에 작성해야만 스프링 컨테이너(WebApplicationContenxt 객체)가 Mybatis Framework의 환경설정파일에 접근 가능
    • 환경설정에 따라 src/main/java 또는 src/main/resources 폴더에 작성 가능
  3. DataSource 관련 클래스, SqlSessionFactroy 관련 클래스, SqlSession 관련 클래스를 Spring Bean으로 등록

    • SpringMVC Framework의 스프링 컨테이너를 초기화 처리하기 위한 Spring Bean Configuration File에서 bean 엘리먼트로 해당 클래스를 Spring Bean으로 등록 → root-context.xml 또는 servlet-context.xml
  4. 테이블 생성 >> DTO 클래스 작성 >> 매퍼 파일 작성 >> DAO 클래스 작성 → 반복

  • DAO 클래스 : 저장매체에게 행에 대한 삽입, 변경, 삭제, 검색 기능을 제공하는 객체를 생성하기 위한 클래스
    • DAO 클래스의 메소드에서는 DBMS 서버에 SQL 명령을 전달하여 실행하고 실행결과를 제공받아 Java 객체(원시값)으로 변환하여 반환되도록 작성
    • DAO 클래스가 변경돼도 의존관계로 설정된 Service 클래스에 영향을 최소화 하기 위해 인터페이스를 상속받아 작성
  • DAO 클래스는 Service 클래스에서 객체로 제공받아 사용되도록 반드시 Spring Bean으로 등록
    • DAO 클래스는 @Repository 어노테이션을 사용하여 Spring Bean으로 등록되도록 처리
    • @Repository 어노테이션을 사용하면 SQL 명령으로 발생되는 예외를 Spring 관련 예외로 제공되도록 처리
    • @Repository 어노테이션를 스프링 컨테이너가 처리하기 위해서는 반드시 클래스를 작성한 패키지를 Spring Bean Configuration File(servlet-context.xml)의 component-scan 엘리먼트로 검색되도록 설정
  • Mybatis Framework로 DAO 클래스를 작성할 경우 매퍼에 등록된 SQL 명령을 전달하여 실행하고 결과를 Java 객체(원시값)로 반환받기 위해 SqlSession 객체가 반드시 필요
    • SqlSession 객체를 저장하기 위한 필드를 선언하고 스프링 컨테이너에 의해 관리되는 Spring Bean에서 SqlSession 관련 객체를 제공받아 필드에 인젝션 처리 (DI)
    • 필드를 초기화하는 생성자를 생성하여 @Autowired 어노테이션을 사용하여 의존성 주입 (순환참조 방지)
    • @RequiredArgsConstructor : final 필드만 초기화 설정하는 생성자를 만들어 주는 어노테이션
    • 생성자가 하나만 작성된 경우 @Autowired 어노테이션 생략 가능


package xyz.itwill10.dao;

@Repository
//final 필드만 초기화 설정하는 생성자를 만들어 주는 어노테이션
// => 생성자가 하나만 작성된 경우 @Autowired 어노테이션 생략 가능
@RequiredArgsConstructor
public class StudentDAOImpl implements StudentDAO {
	//Mybatis Framework로 DAO 클래스를 작성할 경우 매퍼에 등록된 SQL 명령을 전달하여 실행하고
	//결과를 Java 객체(원시값)로 반환받기 위해 SqlSession 객체가 반드시 필요
	// => SqlSession 객체를 저장하기 위한 필드를 선언하고 스프링 컨테이너에 의해 관리되는 
	//Spring Bean에서 SqlSession 관련 객체를 제공받아 필드에 인젝션 처리 - DI
	// => 필드를 초기화하는 생성자를 생성하여 @Autowired 어노테이션을 사용하여 의존성 주입 - 순환참조 방지
	private final SqlSession sqlSession;
	
	@Override
	public int insertStudent(Student student) {
		return sqlSession.getMapper(StudentMapper.class).insertStudent(student);
	}

	@Override
	public List<Student> selectStudentList() {
		return sqlSession.getMapper(StudentMapper.class).selectStudentList();
	}
}





🌸 Service (interface)

package xyz.itwill10.service;

import java.util.List;

import xyz.itwill10.dto.Student;

public interface StudentService {
	void addStudent(Student student);
	List<Student> getStudentList();
}





📗 ServiceImpl (interface상속)

  • Service 클래스 : 요청 처리 메소드에서 데이타 처리 관련 기능을 모듈화하여 제공하는 객체를 생성하기 위한 클래스

    • Service 클래스의 메소드에서는 데이타 처리에 필요한 다수의 DAO 클래스의 메소드를 호출하여 프로그램이 필요한 데이타 처리 기능을 모듈화하여 제공하도록 작성
    • Service 클래스가 변경돼도 의존관계로 설정된 Controller 클래스에 영향을 최소화 하기 위해 인터페이스를 상속받아 작성
  • Service 클래스는 Controller 클래스의 객체로 제공받아 사용되도록 반드시 Spring Bean으로 등록

    • Service 클래스는 @Service 어노테이션을 사용하여 Spring Bean으로 등록되도록 처리
    • @Service 어노테이션을 사용하여 TansactionManager 객체에 의해 트렌젝션 관리 가능
    • @Service 어노테이션를 스프링 컨테이너가 처리하기 위해서는 반드시 클래스를 작성한 패키지를 Spring Bean Configuration File(servlet-context.xml)의 component-scan 엘리먼트로 검색되도록 설정
  • Service 클래스의 메소드에서 사용될 DAO 객체를 저장하기 위한 필드 선언

    • @Autowired 어노테이션을 사용한 생성자로 필드의 인젝션 처리


package xyz.itwill10.service;

@Service
@RequiredArgsConstructor
public class StudentServiceImpl implements StudentService {
	//Service 클래스의 메소드에서 사용될 DAO 객체를 저장하기 위한 필드 선언
	// => @Autowired 어노테이션을 사용한 생성자로 필드의 인젝션 처리
	private final StudentDAO studentDAO;
	
	@Override
	public void addStudent(Student student) {
		studentDAO.insertStudent(student);
	}

	@Override
	public List<Student> getStudentList() {
		return studentDAO.selectStudentList();
	}
}





📘 Model (controller class)

  • Controller 클래스 : 클라이언트 요청을 처리하기 위한 기능의 객체를 생성하기 위한 클래스
    • Controller 클래스는 Front Controller(DispatcherServlet 객체)의 객체로 제공받아 사용되도록 반드시 Spring Bean으로 등록
    • @Controller 클래스는 @Controller 어노테이션을 사용하여 Spring Bean으로 등록되도록 처리
    • @Controller 어노테이션을 사용하면 클라이언트 요청에 의해 호출될 요청 처리 메소드 작성
    • @Controller 어노테이션를 스프링 컨테이너가 처리하기 위해서는 반드시 클래스를 작성한 패키지를 Spring Bean Configuration File(servlet-context.xml)의 component-scan 엘리먼트로 검색되도록 설정
  • @RequestMapping 어노테이션을 클래스에 선언하면 Controller 클래스의 모든 요청 처리 메소드의 요청 URL 주소 앞부분에 공통적으로 포함될 URL 주소를 제공
    • @RequestMapping("/student")
  • Controller 클래스의 요청 처리 메소드에서 사용될 Service 객체를 저장하기 위한 필드 선언
    • @Autowired 어노테이션을 사용한 생성자로 필드의 인젝션 처리 (@RequiredArgsConstructor)
    • private final StudentService studentService;
  1. 학생정보를 입력받기 위한 JSP 문서 관련 뷰이름을 반환하는 요청 처리 메소드

  2. 학생정보를 전달받아 STUDENT 테이블에 삽입하고 회원목록 출력페이지를 요청할 수 있는 URL 주소를 클라이언트에게 전달하는 요청 처리 메소드

    • STUDENT 테이블에 학생정보 삽입시 PK 제약조건에 의해 예외 발생 가능 (예외처리필요)
  3. STUDENT 테이블에 저장된 모든 학생정보를 검색하여 속성값으로 저장하고 학생목록을 출력하는 JSP 문서 관련 뷰이름을 반환하는 요청 처리 메소드



package xyz.itwill10.controller;

@Controller
//@RequestMapping 어노테이션을 클래스에 선언하면 Controller 클래스의 모든 요청 처리 메소드에
//요청 URL 주소 앞부분에 공통적으로 포함될 URL 주소를 제공
@RequestMapping("/student")
@RequiredArgsConstructor
public class StudentController {
	//Controller 클래스의 요청 처리 메소드에서 사용될 Service 객체를 저장하기 위한 필드 선언
	// => @Autowired 어노테이션을 사용한 생성자로 필드의 인젝션 처리
	private final StudentService studentService;
	
	//학생정보를 입력받기 위한 JSP 문서 관련 뷰이름을 반환하는 요청 처리 메소드
	//@RequestMapping(value = "/student/add", method = RequestMethod.GET)
	@RequestMapping(value = "/add", method = RequestMethod.GET)
	public String add() {
		return "student/student_add";
	}
	
	//학생정보를 전달받아 STUDENT 테이블에 삽입하고 회원목록 출력페이지를 요청할 수 있는
	//URL 주소를 클라이언트에게 전달하는 요청 처리 메소드
	//@RequestMapping(value = "/student/add", method = RequestMethod.POST)
	@RequestMapping(value = "/add", method = RequestMethod.POST)
	public String add(@ModelAttribute Student student,Model model) {
		try {
			//STUDENT 테이블에 학생정보 삽입시 PK 제약조건에 의해 예외 발생 가능
			studentService.addStudent(student);
		} catch (Exception e) {
			model.addAttribute("message", "이미 사용중인 학번을 입력 하였습니다.");
			return "student/student_add";
		}
		return "redirect:/student/display";//리다이렉트 이동
	}
	
	//STUDENT 테이블에 저장된 모든 학생정보를 검색하여 속성값으로 저장하고 학생목록을 출력하는
	//JSP 문서 관련 뷰이름을 반환하는 요청 처리 메소드
	//@RequestMapping("/student/display")
	@RequestMapping("/display")
	public String display(Model model) {
		model.addAttribute("studentList",studentService.getStudentList());
		return "student/student_display";
	}
}





🐣 앱실행 (학생정보입력)



<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>SPRING</title>
</head>
<body>
	<h1 align="center">학생정보 입력</h1>
	<hr>
	<form name="studentForm" method="post">
	<table align="center" border="1" cellpadding="1" cellspacing="0" width="300">
		<tr height="40">
			<th bgcolor="yellow" width="100">학생번호</th>
			<td width="200" align="center">
				<input type="text" name="no" value="${student.no }">
			</td>
		</tr>
		<tr height="40">
			<th bgcolor="yellow" width="100">이름</th>
			<td width="200" align="center">
				<input type="text" name="name" value="${student.name }">
			</td>
		</tr>
		<tr height="40">
			<th bgcolor="yellow" width="100">전화번호</th>
			<td width="200" align="center">
				<input type="text" name="phone" value="${student.phone }">
			</td>
		</tr>
		<tr height="40">
			<th bgcolor="yellow" width="100">주소</th>
			<td width="200" align="center">
				<input type="text" name="address" value="${student.address }">
			</td>
		</tr>
		<tr height="40">
			<th bgcolor="yellow" width="100">생년월일</th>
			<td width="200" align="center">
				<input type="text" name="birthday" value="${student.birthday}">
			</td>
		</tr>
		<tr height="40">
			<td width="200" colspan="2" align="center">
				<input type="button" value="학생추가" onclick="submitCheck();">
				<input type="reset" value="초기화">
				<input type="button" value="학생목록" onclick="location.href='${pageContext.request.contextPath}/student/display';">
			</td>
		</tr>
	</table>
	</form>
	
	<p align="center" style="color: red;">${message }</p>
	
	<script type="text/javascript">
	studentForm.no.focus();
	function submitCheck() {
		if(studentForm.no.value=="") {
			alert("학생번호를 입력해 주세요.");
			studentForm.no.focus();
			return;
		}
		
		var noReg=/\d{4}/g;
		if(!noReg.test(studentForm.no.value)) {
			alert("학생번호는 정수 4자리로 입력해주세요.");
			studentForm.no.focus();
			return;
		}
		
		if(studentForm.name.value=="") {
			alert("이름을 입력해 주세요.");
			studentForm.name.focus();
			return;
		}
		if(studentForm.phone.value=="") {
			alert("전화번호을 입력해 주세요.");
			studentForm.phone.focus();
			return;
		}
		var phoneReg=/(01[016789])-\d{3,4}-\d{4}/g;
		if(!phoneReg.test(studentForm.phone.value)) {
			alert("전화번호를 형식에 맞게 입력해주세요.");
			studentForm.phone.focus();
			return;
		}
		
		if(studentForm.address.value=="") {
			alert("주소을 입력해 주세요.");
			studentForm.address.focus();
			return;
		}
		if(studentForm.birthday.value=="") {
			alert("생년월일을 입력해 주세요.");
			studentForm.birthday.focus();
			return;
		}
		
		var birthdayReg=/(18|19|20)\d{2}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])/g;
		if(!birthdayReg.test(studentForm.birthday.value)) {
			alert("생년월일을 형식에 맞게 입력해주세요.");
			studentForm.birthday.focus();
			return;
		}
		studentForm.submit();
	} 
	</script>
</body>
</html>





🐣 앱실행 (학생목록출력)



<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>    
<%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>    
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>SPRING</title>
</head>
<body>
	<h1 align="center">학생목록</h1>
	<table align="center" cellspacing="0" cellpadding="1" width="700">
		<tr align="right">
			<td>
				<%-- <input type="button" value="학생추가" onclick="location.href='add';"> --%>
				<input type="button" value="학생추가" onclick="location.href='${pageContext.request.contextPath}/student/add';">
			</td>
		</tr>
	</table>
	<table align="center" border="1" cellspacing="0" cellpadding="1" width="700">
		<tr bgcolor="yellow">
			<th width="100">학생번호</th>
			<th width="100">이름</th>
			<th width="150">전화번호</th>
			<th width="250">주소</th>
			<th width="100">생년월일</th>
		</tr>
		<c:choose>
			<c:when test="${empty(studentList)}">
				<tr align="center">
					<td colspan="5">검색된 학생정보가 없습니다.</td>
				</tr>		
			</c:when>
			<c:otherwise>
				<c:forEach var="student" items="${studentList }">
					<tr align="center">
						<td width="100">${student.no }</td>				
						<td width="100">${student.name }</td>				
						<td width="150">${student.phone }</td>				
						<td width="250">${student.address }</td>				
						<td width="100">${fn:substring(student.birthday,0,10) }</td>				
					</tr>
				</c:forEach>
			</c:otherwise>
		</c:choose>	
	</table>
</body>
</html>





🌼 Spring 로그 구현체 실행

  • Mybatis Framework의 로그 팩토리에 의해 생성된 로그 이벤트를 Spring Framework의 로그 구현체에게 전달하여 기록하는 방법
  1. log4jdbc-log4j2-jdbc4 라이브러리를 프로젝트에 빌드 처리 (메이븐 : pom.xml)

  2. DataSource 관련 클래스를 Spring Bean으로 등록한 Spring Bean Configuration File의 bean 엘리먼트에서 driverClassName 필드값과 url 필드값 변경 → root-context.xml

  3. [src/main/resources] 폴더에 [log4jdbc.log4j2.properties] 파일 작성

    • Mybatis Framework의 로그 이벤트를 Spring Framework에게 전달하기 위한 SpyLogDelegator 클래스를 지정하기 위한 파일
  4. SpyLogDelegator 객체에 의해 발생된 로그 이벤트를 SpyLogDelegator의 로그 구현체에 의해 기록되도록 환경설정파일 변경 → log4j.xml : logger 엘리먼트 추가


📌 빌드 처리 (pom.xml)

  • 퍼시스턴스 프레임워크(Persistence Framework)에 의해 발생되는 로그 이벤트를 Spring Framework의 로그 구현체로 기록하기 위한 기능을 제공하는 라이브러리


		<!-- https://mvnrepository.com/artifact/org.bgee.log4jdbc-log4j2/log4jdbc-log4j2-jdbc4 -->
		<dependency>
		    <groupId>org.bgee.log4jdbc-log4j2</groupId>
		    <artifactId>log4jdbc-log4j2-jdbc4</artifactId>
		    <version>1.16</version>
		</dependency>





📕 root-context.xml

  • 퍼시스턴스 프레임워크(Persistence Framework)에서 발생되는 로그 이벤트를 전달받아 Spring Framework에서 처리하기 위해 driverClassName 필드값과 url 필드값을 log4jdbc-log4j2-jdbc4 라이브러리에서 제공하는 값으로 변경


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
	
	<!-- DataSource 관련 클래스를 Spring Bean으로 등록 - DBCP(DataBase Connection Pool) -->
	<!-- => DataSource 객체 필드에 Connection 객체 생성에 필요한 값을 인젝션 처리 -->
	<!--  	
	<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource" id="dataSource">
		<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
		<property name="url" value="jdbc:oracle:thin:@localhost:1521:xe"/>
		<property name="username" value="scott"/>
		<property name="password" value="tiger"/>
	</bean>
	-->
	<!-- 퍼시스턴스 프레임워크(Persistence Framework)에서 발생되는 로그 이벤트를 전달받아
	Spring Framework에서 처리하기 위해 driverClassName 필드값과 url 필드값을 log4jdbc-log4j2-jdbc4
	라이브러리에서 제공하는 값으로 변경 -->
	<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource" id="dataSource">
		<property name="driverClassName" value="net.sf.log4jdbc.sql.jdbcapi.DriverSpy"/>
		<property name="url" value="jdbc:log4jdbc:oracle:thin:@localhost:1521:xe"/>
		<property name="username" value="scott"/>
		<property name="password" value="tiger"/>
	</bean>
</beans>





📌 log4jdbc.log4j2.properties


log4jdbc.spylogdelegator.name = net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator




📕 log4j.xml (로그 구현체)

  • log4.xml : 로그 구현체에 대한 환경설정 파일

  • SpyLogDelegator 객체에 의해 전달된 로그 이벤트를 기록하기 위한 logger 엘리먼트

    • jdbc.sqlonly : 완성된 SQL 명령 기록
    • jdbc.sqltiming : SQL 명령의 실행시간(ms) 기록
    • jdbc.audit : ResultSet 관련 매핑 정보를 제외한 모든 JDBC 관련 정보 기록
    • jdbc.resultset : ResultSet 관련 매핑 정보를 포함한 모든 JDBC 관련 정보 기록 (너무 많은 기록 발생 → 생략 권장)
    • jdbc.resultsettable : ResultSet 관련 매핑 정보를 표(Table)형식으로 기록
    • jdbc.connection : Connection 객체 관련 정보 기록 (Open 또는 Close)


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/xml/doc-files/log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">

	<!-- SpyLogDelegator 객체에 의해 전달된 로그 이벤트를 기록하기 위한 logger 엘리먼트 -->
	<!-- jdbc.sqlonly : 완성된 SQL 명령 기록 -->
	<logger name="jdbc.sqlonly">
		<level value="info" />
	</logger>
	
	<!-- jdbc.sqltiming : SQL 명령의 실행시간(ms) 기록 -->
	<logger name="jdbc.sqltiming">
		<level value="info" />
	</logger>
	
	<!-- jdbc.audit : ResultSet 관련 매핑 정보를 제외한 모든 JDBC 관련 정보 기록 -->
	<logger name="jdbc.audit">
		<level value="info" />
	</logger>
	
	<!-- jdbc.resultset : ResultSet 관련 매핑 정보를 포함한 모든 JDBC 관련 정보 기록 -->
	<!--  
	<logger name="jdbc.resultset">
		<level value="info" />
	</logger>
	-->
	
	<!-- jdbc.resultsettable : ResultSet 관련 매핑 정보를 표(Table)형식으로 기록 -->
	<logger name="jdbc.resultsettable">
		<level value="info" />
	</logger>
	
	<!-- jdbc.connection : Connection 객체 관련 정보 기록 - Open 또는 Close -->
	<logger name="jdbc.connection">
		<level value="info" />
	</logger>

</log4j:configuration>





🐣 앱실행 (학생목록출력)


profile
Study Log 📂

0개의 댓글