9장 (javastudy 22_Jdbc_Ex 리메이크. dao,dto,sql 가져옴)

@Component // JdbcConnection 객체(Bean)를 Spring Container에 저장해 둔다.
public class JdbcConnection {
/*
* 일반 버전
* Class.forName("oracle.jdbc.OracleDriver");
* url = "jdbc:oracle:thin:@localhost:1521:xe"
*
* 쿼리 출력 버전(log4jdbc 디펜던시)
* Class.forName("net.sf.log4jdbc.sql.jdbcapi.DriverSpy");
* url = "jdbc:log4jdbc:oracle:thin:@localhost:1521:xe"
*/
public Connection getConnection() {
Connection con = null;
try {
Class.forName("net.sf.log4jdbc.sql.jdbcapi.DriverSpy"); // oracle jdbc 로드
con = DriverManager.getConnection("jdbc:log4jdbc:oracle:thin:@localhost:1521:xe", "GD", "1111");
} catch (Exception e) {
e.printStackTrace();
}
return con;
}
public void close(Connection con, PreparedStatement ps, ResultSet rs) {
try {
if(rs != null) rs.close();
if(ps != null) ps.close();
if(con != null) con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
1) <bean> 태그 : @ContextConfiguration(locations="file:src/main/webapp/WEB-INF/spring/root-context.xml")
2) @Bean : @ContextConfiguration(classes=AppConfig.class)
3) @Component : @ContextConfiguration(locations="file:src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml")
// JUnit4를 이용한다.
@RunWith(SpringJUnit4ClassRunner.class)
// ContactDao Bean 생성 방법을 알려준다.
@ContextConfiguration(locations="file:src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml")
// 테스트 메소드의 이름 오름차순(알파벳순)으로 테스트를 수행한다.
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class ContactUnitTest {
@Autowired // Spring Container에서 ContactDao 객체(Bean)를 가져온다.
private ContactDao contactDao;
@Test // 테스트를 수행한다.
public void test01_삽입테스트() {
ContactDto contactDto = new ContactDto(0, "이름", "연락처", "이메일", "주소", "");
int insertResult = contactDao.insert(contactDto);
assertEquals(1, insertResult); // insertResult가 1이면 테스트 성공이다.
}
@Test // 테스트를 수행한다.
public void test02_조회테스트() {
int contact_no = 1;
ContactDto contactDto = contactDao.selectContactByNo(contact_no);
assertNotNull(contactDto); // contactDto가 not null이면 테스트 성공이다.
}
@Test // 테스트를 수행한다.
public void test03_삭제테스트() {
int contact_no = 1;
int deleteResult = contactDao.delete(contact_no);
assertEquals(1, deleteResult); // deleteResult가 1이면 테스트 성공이다.
// assertNull(contactDao.selectContactByNo(contact_no)); select 결과가 null이면 테스트 성공이다.
}
}
각종 정보를 콘솔에서 info 레벨로 찍어주는 애가 있다.
Appender : 로그를 찍어주는 놈

name : 어팬더 이름 (console)
콘솔어팬더 = 콘솔에 찍어주는 놈
value값 = 찍는 방식 지정

하단부 Root logger를 보면

어팬더 사용할 때 console로 이름 지정해준 것을 사용하라고 명시해둔 상태

name으로 지정해준 패키지의 로그는 level value로 지정한 수준으로 찍으라고 적어준 것. 여기선 전부 인포레벨
여기까지 전부 스프링 프로젝트의 기본로그들. 간단히 알고만 있으면 된다.
logger import -> slf4j(로깅 인터페이스)로

출력 결과




개발자는 slf4j 인터페이스에 맞춰 로그 작업을 하고 slf4j는 실제로 동작할 로깅 프레임워크(log4j, logback 등)을 연결한다. (다양한 로깅 프레임워크가 있지만 사용법을 통일하기 위해 slf4j 인터페이스를 사용한다. 개발자는 slf4j와만 작업하기 때문에 그 뒷단 하나하나 문법은 신경안써도 된다)

<configuration>
<!-- Appenders : 로그를 출력하는 Appender 모음 -->
<!--
%d{날짜시간패턴} : 로그기록시간 (SimpleDateFormat과 같은 날짜시간패턴)
%level : 로그 레벨 (OFF > ERROR > WARN > INFO > DEBUG > TRACE)
%logger : 로그를 찍는 클래스 (어떤 클래스가 동작할 때 로그가 남겨지는가?)
%msg : 로그 메시지
%n : 줄 바꿈
-->
<!-- Console에 로그를 찍는 Appender -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>[%d{HH:mm:ss, Asia/Seoul}] %-5level:%logger - %msg%n</pattern>
</encoder>
</appender>
<!-- File에 로그를 찍는 Appender -->
<appender name="file" class="ch.qos.logback.core.FileAppender">
<file>/log/app09_log.log</file>
<append>true</append>
<immediateFlush>true</immediateFlush>
<encoder>
<pattern>[%d{HH:mm:ss, Asia/Seoul}] %-5level:%logger - %msg%n</pattern>
</encoder>
</appender>
<!-- 매일 새로운 로그 파일을 만드는 RollingFileAppender -->
<appender name="rolling" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>/log/app09.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxFileSize>100MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>3GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>[%d{HH:mm:ss, Asia/Seoul}] %-5level:%logger - %msg%n</pattern>
</encoder>
</appender>
<!-- Application Loggers -->
<logger name="com.gdu.app09" level="info" />
<!-- 3rdparty Loggers -->
<logger name="org.springframework" level="info" />
<logger name="log4jdbc" level="info" />
<logger name="jdbc.sqlonly" level="info" /> <!-- 쿼리문 출력하기 -->
<logger name="jdbc.sqltiming" level="off" /> <!-- 쿼리문 + 실행시간 출력하기 -->
<logger name="jdbc.resultsettable" level="info" /> <!-- SELECT 결과를 테이블 형식으로 출력하기 -->
<logger name="jdbc.connection" level="off" /> <!-- Connection 연결/종료 정보 출력하기 -->
<logger name="jdbc.audit" level="off" /> <!-- ResultSet을 제외한 jdbc 호출 정보 출력하기 -->
<logger name="jdbc.resultset" level="off" /> <!-- ResultSet을 포함한 jdbc 호출 정보 출력하기 -->
<!-- Root Logger -->
<root>
<priority value="warn" />
<appender-ref ref="console" />
<appender-ref ref="rolling" />
</root>
</configuration>

// ContactController를 실행할 때 org.slf4j.Logger가 동작한다.
--> @slf4j 어노테이션으로 대체
@Slf4j // private static final Logger log = LoggerFactory.getLogger(ContactController.class);
@RequiredArgsConstructor // private final ContactService contactService;에 @Autowired를 하기 위한 코드이다.
@Controller
public class ContactController {
// ContactController를 실행할 때 org.slf4j.Logger가 동작한다.
// private static final Logger log = LoggerFactory.getLogger(ContactController.class);
private final ContactService contactService;
@RequestMapping(value="/contact/list.do", method=RequestMethod.GET)
public String list(Model model) {
List<ContactDto> contactList = contactService.getContactList();
model.addAttribute("contactList", contactList);
return "contact/list";
}
}

msg 자리에 출력됨
6교시에 작업한 것 실행 결과
목록보기(연락처관리 클릭)하면 자동으로 찍힘
콘솔 로그

파일 로그

정해준 위치에 파일로 생성돼서 잘 찍혔다
RollingFileAppender 로그

지정한 형식대로 날짜 찍혀서 생성
이후에 쿼리로그했음 8교시까지
쿼리로그
작업하기 위해 필요한 디펜더시 : log4jdbc
작업하기 위해 필요한 파일 : log4jdbc.log4j2.properties
커넥션 연결하려면 dirverName, url이 달라진다
