기존의 Student 테이블 사용
📃Student.java
※ xyz.itwill10.dto 패키지에 Student.java 클래스 생성
package xyz.itwill10.dto; /* 이름 널? 유형 -------- -------- ------------- NO NOT NULL NUMBER(4) NAME VARCHAR2(50) PHONE VARCHAR2(20) ADDRESS VARCHAR2(100) BIRTHDAY DATE */ import lombok.Data; // @Data public class Student { private int no; private String name; private String phone; private String address; private String birthday; }
📃StudentMapper.java(인터페이스)
※ src/main/java 폴더에 xyz.itwill10.mapper 패키지 생성
※ xyz.itwill10.mapper 패키지에 StudentMapper.java 인터페이스 파일 생성package xyz.itwll10.mapper; // import java.util.List; import xyz.itwill10.dto.Student; // public interface StudentMapper { int insertStudent(Student student); List<Student> selectStudentList(); }
📃StudentMapper.xml
※ src/main/java 폴더에 xyz.itwill10.mapper 패키지 생성
※ xyz.itwill10.mapper 패키지에 StudentMapper.xml 파일 생성<?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>
📃StudentDAO(인터페이스)
※ src/main/java 폴더에 xyz.itwill10.dao 패키지 생성
※ xyz.itwill10.dao 패키지에 StudentDAO 인터페이스 생성package xyz.itwill10.dao; // import java.util.List; import xyz.itwill10.dto.Student; //결합도를 느슨하게 하기 위해서 인터페이스 생성 public interface StudentDAO { int insertStudent(Student student); List<Student> selectStudentList(); }
📃StudentDAOImpl
※ xyz.itwill10.dao 패키지에 StudentDAOImpl 클래스 생성
package xyz.itwill10.dao; // import java.util.List; import org.apache.ibatis.session.SqlSession; import org.springframework.stereotype.Repository; import lombok.RequiredArgsConstructor; import xyz.itwill10.dto.Student; import xyz.itwill10.mapper.StudentMapper; // //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 관련 클래스, SqlSessionFactory 관련 클래스, SqlSession 관련 클래스를 Spring Bean으로 등록 //→ SpringMVC Framework의 스프링 컨테이너를 초기화 처리하기 위한 Spring Bean Configuration File에서 bean 엘리먼트로 해당 클래스를 Spring Bean으로 등록 //→ root-context.xml 또는 servlet-context.xml //4. 테이블 생성 >> DTO 클래스 작성 >> 매퍼 파일 작성 >> DAO 클래스 작성 - 반복 // //Mybatis Framework의 로그 팩토리에 의해 생성된 로그 이벤트를 Spring Framework의 로그 구현체를 사용하여 기록하는 방법 //1. log4jdbc-log4j2-jdbc4 라이브러리를 프로젝트에 빌드 처리 //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 객체에 의해 발생된 로그 이벤트를 로그 구현체에 의해 기록되도록 환경설정파일 변경 - log4j.xml : logger 엘리먼트 추가 // //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 엘리먼트로 검색되도록 설정 @Repository //final 필드만 초기화 설정하는 생성자를 만들어 주는 어노테이션 //→ 생성자만 하나만 작성된 경우 @Autowired 어노테이션 생략 가능 @RequiredArgsConstructor//final이 꼭 있어야함 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(); } }
📃servlet-context.xml
※ WEB-INF/spring/appServlet 폴더의 servlet-context.xml 수정
<!-- xyz.itwill10.dao 패키지에 DAO 클래스를 작성하고 스프링 어노테이션을 이용하여 Spring Bean으로 등록 --> <context:component-scan base-package="xyz.itwill10.dao" />
① 빌드 처리
📃pom.xml
<!-- 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>2.1.0</version> </dependency>
② Mybatis Framework의 환경설정파일 작성
📃mybatis-config.xml
※ WEB-INF/spring 폴더에 mybatis-config.xml 파일 생성
<?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>
③ 클래스를 Spring Bean으로 등록
📃root-context.xml
※ WEB-INF/spring 폴더에 root-context.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" 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 접두사를 사용하여 스프링 컨데이너로 접근 --> <!-- → 폴더의 패키지에 작성된 환경설정파일은 파일 시스템 경로 표현하여 접근 가능 --> <!-- <property name="configLocation" value="classpath:xyz/itwill/config/mybatis-config.xml"/> --> <property name="configLocation" value="classpath:mybatis-config.xml"/> <!-- --> <!-- dataSource 필드에 DataSource 관련 클래스의 Spring Bean이 저장되도록 설정 - DI --> <!-- --> <property name="dataSource" ref="dataSource"/> <!-- --> <!-- typeAliasesPackage 필드에 DTO 클래스를 작성한 패키지를 저장하도록 설정 --> <!-- → XML 기반의 매퍼파일(MapperFile)에서 Java 자료형 대신 사용할 별칭을 제공하기 위해 Mybatis 환경설정파일의 typeAliases 엘리먼트 package 엘리먼트와 유사한 기능 제공 --> <property name="typeAliasesPackage" value="xyz.itwill10.dto"/> <!-- --> <!-- mapperLocations 필드에 List 객체를 생성하여 저장되도록 설정 --> <!-- → List 객체의 요소에는 XML 기반의 매퍼 파일의 경로가 요소값으로 저장되도록 추가 - 매퍼 등록 --> <property name="mapperLocations"> <list> <!-- [src/main/java] 폴더의 패키지에 매퍼 파일을 작성하기 위한 classpath 접두사 사용 --> <value>classpath:xyz/itwill10/mapper/*.xml</value> </list> </property> </bean> <!-- ========================================================================================= --> <!-- SqlSession 관련 클래스를 Spring Bean으로 등록 --> <!-- → SqlSessionTemplate 클래스로 객체를 생성하기 위한 생성자 매개변수에 SqlSessionFactory 객체를 전달하여 필드 초기화 처리 - 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>
📃StudentService.java(인터페이스)
※ src/main/java 폴더에 xyz.itwill10.service 패키지 생성
※ xyz.itwill10.service 패키지에 StudentService.java 인터페이스 파일 생성package xyz.itwill10.service; // import java.util.List; import xyz.itwill10.dto.Student; // public interface StudentService { void addStudent(Student student); List<Student> getStudentList(); }
📃StudentServiceImpl.java
※ xyz.itwill10.service 패키지에 StudentServiceImpl.java 클래스 생성
package xyz.itwill10.service; // import java.util.List; import org.springframework.stereotype.Service; import lombok.RequiredArgsConstructor; import xyz.itwill10.dao.StudentDAO; import xyz.itwill10.dto.Student; // //Service 클래스 : 요청 처리 메소드에서 데이터 처리 관련 기능을 모듈화하여 기능을 제공하는 객체를 생성하기 위한 클래스 //→ Service 클래스의 메소드에서는 데이터 차리에 필요한 다수의 DAO 클래스의 메소드를 호출하여 프로그램이 필요한 데이터 처리 기능을 모듈화하여 제공하도록 작성 //→ Service 클래스가 변경돼도 의존관계로 설정된 Controller 클래스에 영향을 최소화 하기 위한 인터페이스를 상속받아 작성 // //Service 클래스는 Controller 클래스의 객체로 제공받아 사용되도록 반드시 Spring Bean으로 등록 //→ Service 클래스는 @Service 어노테이션을 사용하여 Spring Bean으로 등록되도록 처리 //→ @Service 어노테이션을 사용하여 TransactionManager 객체에 의해 트렌젝션 관리 가능 //→ @Service 어노테이션을 스프링 컨테이너가 처리하기 위해서는 반드시 클래스를 작성한 패키지를 // Spring Bean Configuration File(servlet-context.xml)의 component-scan 엘리먼트로 검색되도록 설정 @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(); } }
📃servlet-context.xml
※ WEB-INF/spring/appServlet 폴더의 servlet-context.xml 수정
<context:component-scan base-package="xyz.itwill10.service" />
📃StudentController.java 클래스 생성
※ xyz.itwill10.controller 패키지에 StudentController.java 클래스 생성
package xyz.itwill10.controller; // import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import lombok.RequiredArgsConstructor; import xyz.itwill10.dto.Student; import xyz.itwill10.service.StudentService; // //SpringMVC Framework를 사용하여 웹프로그램을 작성하는 방법 //→ 테이블 >> DTO 클래스(Mybatis) >> Service 클래스 >> Controller 클래스 //>> 테스트 프로그램(JUit)- 단위 프로그램(모듈) 테스트 >> HTML 문서를 JSP 문서로 변환 >> 토합 프로그램 테스트 - 브라우저 이용 // //Controller 클래스 : 클라이언트 요청을 처리하기 위한 기능의 객체를 생성하기 위한 클래스 // //Controller 클래스는 Front Controller(DispatcherServlet 객체)의 객체로 제공받아 사용되도록 반드시 Spring Bean으로 등록 //→ @Controller 클래스는 @Controlle 어노테이션을 사용하여 Spring Bean으로 등록되도록 처리 //→ @Controller 어노테이션을 사용하면 클라이언트 요청에 의해 호출될 요청 처리 메소드 작성 //→ @Controller 어노테이션를 스프링 컨테이너가 처리하기 위해서는 반드시 클래스를 작성한 패키지를 // Spring Bean Configuration File(servlet-context.xml)의 component-scan 엘리먼트로 검색되도록 설정 // @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) public String add() { return "student/student_add"; } // //학생정보를 전달받아 STUDENT 테이블에 삽입하고 회원목록 출력페이지를 요청할 수 있는 URL 주소를 클라이언트에게 전달하는 요청 처리 메소드 @RequestMapping(value = "/student/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") public String display(Model model) { model.addAttribute("studentList",studentService.getStudentList()); return "student/student_display"; } }
※ 테스트 프로그램은 아래 폴더에 만들어서 작성
📃DataSourceTest.java
※ src/test/java 폴더 → xyz.itiwll.controller 패키지에 DataSourceTest.java 클래스 생성
package xyz.itwill.controller; // import java.sql.Connection; import java.sql.SQLException; import javax.sql.DataSource; import org.junit.Test; import org.junit.runner.RunWith; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; // //Spring Framework를 사용하여 테스트 프로그램을 작성하여 단위 프로그램(모듈)을 테스트 하는 방법 //→ SpringMvc에서의 모듈 : DAO 클래스, Service 클래스, Controller 클래스의 메소드 //1. junit 라이브러리와 spring-test 라이브러리를 프로젝트에 빌드 처리 - 메이븐 : pom.xml //2. 테스트 프로그램에서 사용될 로그 구현체의 환경설정파일 변경 - log4j.xml //→ [src/test/resources] 폴더의 log4j.xml 파일의 내용 수정 //3. [src/test/java] 폴더에 테스트 프로그램에 대한 클래스 작성 //→ junit 라이브러리와 spring-test 라이브러리에서 scope 속성을 주석 처리해야 테스트 프로그램 관련 클래스 작성 가능 - 테스트 프로그램 실행 후 주석 제거 //4. 테스트 프로그램 실행 - 모듈 클래스 // //@RunWith : 테스트 프로그램의 클래스를 객체로 생성하여 테스트 메소드를 호출하기 위한 클래스를 설정하는 어노테이션 //→ 테스트 클래스를 실행하기 위한 클래스 설정 //value 속성 : 테스트 클래스를 실행하기 위한 클래스(Class 객체)를 속성값으로 설정 //→ 다른 속성이 없는 경우 속성값만 설정 가능 //SpringJUnit4ClassRunner 클래스를 사용하여 테스트 클래스를 실행할 경우 ApplicatrionContext 객체(Spring Container)가 생성되어 제공 @RunWith(SpringJUnit4ClassRunner.class) //@ContextConfiguration : 테스트 클래스에서 사용할 수 있는 Spring Bean을 제공하기 위한 Spring Bean Configuration File을 설정하는 어노테이션 //→ 스프링 컨테이너에 객체에 의해 관리하기 위한 객체 //locations 속성 : Spring Bean Configuration File의 경로를 요소로 저장한 배열을 속성값으로 설정 @ContextConfiguration(locations = {"file:src/main/webapp/WEB-INF/spring/root-context.xml"}) public class DataSourceTest { private static final Logger logger=LoggerFactory.getLogger(DataSourceTest.class); // //테스트 클래스의 메소드에서 사용할 객체를 저장하기 위한 필드 선언 // => @AutoWired 어노테이션을 필드에 사용하여 의존성 주입 - 생성자를 이용한 의존성 주입 불가능 @Autowired private DataSource dataSource; // //@Test : 테스트 메소드를 설정하는 어노테이션 // => SpringJUnit4ClassRunner에 의해 호출되어 모듈 테스트를 실행할 메소드 @Test public void testDataSource() throws SQLException { logger.info("DataSource = "+dataSource); Connection connection=dataSource.getConnection(); logger.info("Connection = "+connection); connection.close(); } }
① 빌드 처리
📃pom.xml
<!-- Test --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.2</version> <!-- <scope>test</scope> --> </dependency><!-- https://mvnrepository.com/artifact/org.springframework/spring-test --> <!-- => Spring Framework를 이용하여 테스트 프로그램 작성에 필요한 기능을 제공하는 라이브러리 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${org.springframework-version}</version> <!-- <scope>test</scope> --> </dependency>
📃StudentServiceTest.java
※ xyz.itiwll.controller 패키지에 StudentServiceTest.java 클래스 생성
package xyz.itwill.controller; // import java.util.List; import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.MethodSorters; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; import xyz.itwill10.dto.Student; import xyz.itwill10.service.StudentService; // //테스트 클래스의 메소드에서는 일반적으로 Service 클래스의 메소드 또는 Controller 클래스의 메소드를 호출하여 메소드가 정상적으로 동작되는지 검사할 목적으로 작성 // @RunWith(SpringJUnit4ClassRunner.class) //@WebAppConfiguration : ApplicationContext 객체가 아닌 WebApplicationContext 객체로 스프링 컨테이너 역할을 제공하도록 설정하기 위한 어노테이션 @WebAppConfiguration @ContextConfiguration(locations = {"file:src/main/webapp/WEB-INF/spring/root-context.xml" ,"file:src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml"}) //@FixMethodOrder : 테스트 메소드 호출순서을 설정하기 위한 어노테이션 //value 속성 : MethodSorters 자료형(Enum)의 상수 중 하나를 속성값으로 설정 //→ MethodSorters.DEFAULT : JUnit 프로그램의 내부 규칙에 의해 정렬되어 메소드 호출 - 테스트마다 동일한 순서로 메소드 호출 //→ MethodSorters.JVM : JVM에 의해 정렬되어 메소드 호출 - 테스트마다 변경된 순서로 메소드 호출 //→ MethodSorters.NAME_ASCENDING : 테스트 메소드의 이름을 오름차순 정렬하여 메소드 호출 @FixMethodOrder(value = MethodSorters.NAME_ASCENDING) public class StudentServiceTest { private static final Logger logger=LoggerFactory.getLogger(StudentServiceTest.class); // @Autowired private StudentService studentService; // @Test public void testAddStudent() { Student student=new Student(); student.setNo(6000); student.setName("홍경래"); student.setPhone("010-6781-4311"); student.setAddress("서울시 중랑구"); student.setBirthday("2000-09-10"); // studentService.addStudent(student); } // @Test public void testStudentList() { List<Student> studentList=studentService.getStudentList(); // for(Student student:studentList) { //DTO 클래스의 toString() 메소드 호출 - 모든 필드값을 문자열로 변환하여 반환 logger.info(student.toString()); } } }
📃StudentControllerTset.java
※ xyz.itiwll.controller 패키지에 StudentControllerTset.java 클래스 생성
package xyz.itwill.controller; // import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; // @RunWith(SpringJUnit4ClassRunner.class) @WebAppConfiguration //[*] 패턴문자를 사용하여 Spring Bean Configuration File 설정 가능 //→ [**] 형식으로 0개 이상의 하위 폴더를 표현 가능 @ContextConfiguration(locations = {"file:src/main/webapp/WEB-INF/spring/**/*.xml"}) public class StudentControllerTset { private static final Logger logger=LoggerFactory.getLogger(StudentControllerTset.class); // //WebApplicationContext 객체를 저장하기 위한 필드 선언 - DI //→ WebApplicationContext 객체 : SpringMVC 프로그램에서 스프링 컨테이너 역할을 제공하기 위한 객체 @Autowired private WebApplicationContext context; // //MockMvc 객체르 저장하기 위한 필드 선언 //→ MockMvc 객체 : private MockMvc mvc; // //@Before : 테스트 메소드 호출 전 실행될 명령을 작성한 메소드를 설정하는 어노테이션 - 초기화 작업 @Before public void setup() { //MockMvcBuilders.webAppContextSetup(WebApplicationContext context) //→ MockMvcBuilder 객체를 생성하여 반환하기 위한 메소드 //MockMvcBuilder.build() : MockMvc 객체를 생성하여 반환하기 위한 메소드 mvc=MockMvcBuilders.webAppContextSetup(context).build(); logger.info("MockMvc 객체 생성"); } // @Test public void testStudentDisplay() throws Exception { //MockMvc.perform(Builder requestBulider) : 가상으로 페이지를 요청하는 메소드 //→ Controller 클래스에서 해당 페이지의 요청 처리 메소드 호출 //→ 요청에 대한 처리결과가 저장된 ResultActions 객체 반환 //MockMvcRequestBuilders.get(String url) : URL 주소를 전달받아 GET 방식으로 요청하는 메소드 //→ 페이지에 대한 URL 주소의 요청 관련 정보(리퀘스트 메세지)가 저장된 Builder 객체 반환 //ResultActions.andReturn() : 요청 처리 메소드의 실행 결과를 MvcResult 객체로 반환하는 메소드 MvcResult result=mvc.perform(MockMvcRequestBuilders.get("/student/display")).andReturn(); // logger.info(result.getModelAndView().getViewName()); logger.info(result.getModelAndView().getModel().toString()); } }
📃 student_add.jsp
※ WEB-INF/views/student 폴더에 student_add.jsp 생성
<%@ 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>
📃 student_display.jsp
※ WEB-INF/views/student 폴더에 student_display.jsp 생성
<%@ 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>
📢Mybatis Framework의 로그 팩토리에 의해 생성된 로그 이벤트를 Spring Framework의 로그 구현체를 사용하여 기록하는 방법
1. log4jdbc-log4j2-jdbc4 라이브러리를 프로젝트에 빌드 처리
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 객체에 의해 발생된 로그 이벤트를 로그 구현체에 의해 기록되도록 환경설정파일 변경 - log4j.xml : logger 엘리먼트 추가
①빌드 처리
📃pom.xml
<!-- https://mvnrepository.com/artifact/org.bgee.log4jdbc-log4j2/log4jdbc-log4j2-jdbc4 --> <!-- => 퍼시스턴스 프레임워크(Persistence Framework)에 의해 발생되는 로그 이벤트를 Spring Framework의 로그 구현체로 기록하기 위한 기능을 제공하는 라이브러리 --> <dependency> <groupId>org.bgee.log4jdbc-log4j2</groupId> <artifactId>log4jdbc-log4j2-jdbc4</artifactId> <version>1.16</version> </dependency>
②필드값 변경
📃root-context.xml
※ WEB-INF/spring 폴더에 root-context.xml 파일 수정
<!-- <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>
③파일 작성
📃log4jdbc.log4j2.properties
※ src/main/resources 폴더에 log4jdbc.log4j2.properties 파일 생성
log4jdbc.spylogdelegator.name = net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator
④환경설정파일 변경
📃log4j.xml
※ src/main/resources 폴더에 log4j.xml 파일 수정
<!-- Slf4jSpyLogDelegator 객체에 의해 전달된 로그 이벤트를 기록하기 위한 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>