ㅁ 마이바티스 ~ 스프링의 AOP 특징도 알아본다.
ㅁ 새로운 스프링 레거시 프로젝트 생성
- project name은 "04_Spring_MyBatis_AOP"
- "Spring MVC Project" 템플릿 선택
- 베이스 패키지는 "com.br.sbatis"
- src/main/java에 있는 베이스 패키지의 HomeController.java, src/main/webapp/WEB-INF/views의 home.jsp 삭제
ㅁ DB 연동할거라 DB 생성
- 관리자 계정에서 "create user sbatis identified by sbatis;", "grant connect, resource to sbatis;"으로 계정을 생성한다.
- sbatis 계정으로 접속한다.
- 내가 직접 ~했다면 commit;으로 트랜잭션 처리를 해야 함.
그래야 다른 데서 보인다.
ㅁ pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<modelVersion>4.0.0</modelVersion>
<groupId>com.br</groupId>
<artifactId>sbatis</artifactId>
<name>04_Spring_MyBatis_AOP</name>
<packaging>war</packaging>
<version>1.0.0-BUILD-SNAPSHOT</version>
<properties>
<java-version>11</java-version>
<org.springframework-version>5.3.27</org.springframework-version>
<org.aspectj-version>1.9.19</org.aspectj-version>
<org.slf4j-version>2.0.7</org.slf4j-version>
</properties>
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework-version}</version>
<exclusions>
<!-- Exclude Commons Logging in favor of SLF4j -->
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<!-- AspectJ -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${org.aspectj-version}</version>
</dependency>
<!-- Logging (logback) -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.14</version>
<!-- <scope>test</scope> 이건 지워야 함 -->
</dependency>
<dependency> <!-- 기존 dependency 중 이것만 남기고 다 지운다.-->
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${org.slf4j-version}</version>
</dependency>
<!-- @Inject -->
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
<!-- Servlet -->
<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>
<!-- Test -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<!-- Lombok 라이브러리 추가 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
<!-- Jackson 라이브러리 추가 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.14.2</version>
</dependency>
<!-- db관련 라이브러리 -->
<!-- (1) ojdbc8 -->
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
<version>23.2.0.0</version>
</dependency>
<!-- (2) spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<!-- (3) mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.14</version>
</dependency>
<!-- (4) mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<!-- (5) commons-dbcp -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.9.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.9</version>
<configuration>
<additionalProjectnatures>
<projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
</additionalProjectnatures>
<additionalBuildcommands>
<buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
</additionalBuildcommands>
<downloadSources>true</downloadSources>
<downloadJavadocs>true</downloadJavadocs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${java-version}</source>
<target>${java-version}</target>
<compilerArgument>-Xlint:all</compilerArgument>
<showWarnings>true</showWarnings>
<showDeprecation>true</showDeprecation>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<configuration>
<mainClass>org.test.int1.Main</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
- 맨 위 6줄 프로젝트 정보는 건들지 말고, properties와 dependencies 수정한다.
- 3번째 프로젝트의 pom.xml에서 properties부터 완전 끝까지(/project) 복사.
- 추가로 db연동하고 마이바티스 프레임워크를 사용한다.
기존에 다이너믹 웹 프로젝트할 때도 마이바티스 라이브러리를 추가했었다.
그것만 있으면 되는게 아니고 스프링에서 마이바티스를 쓸 수 있게 라이브러리를 더 추가해야 한다.
db관련 라이브러리도 추가한다. ojdbc 라이브러리 등.
- ojdbc6버전을 썼었는데 ojdbc6은 외부저장소를 연결해야 한다해서 ojdbc8을 쓴다.
- 첫번째꺼. com.oracle.database.jdbc
- 스프링이 나온 23년과 비슷한 23.2.0.0버전 사용.
- ojdbc 먼저 추가했다.
- 여기서 보이는 버전은 스프링 버전이다. 스프링의 모듈 중 하나다.
- 5.3.27버전을 쓰고 있으니 거기서 가져온다.
- <version>5.3.27</version>을 <version>${org.springframework-version}</version>으로 수정한다.
이러면 properties 태그만 바꿔도 된다.
- 첫번째에서 3.5.14버전.
- 두번째가 스프링과 마이바티스 다리역할이다. 2.0.6버전 사용.
- DBCP가 database connection pool이다. 2.9.0 사용.
- 기본적으로 이렇게 5개가 필요하다. 오라클 관련한거, 마이바티스 관련한거, 커넥션풀 관련한거.
ㅁ 자바 버전은 그대로다
- 프로젝트 우클릭 - maven - update project
ㅁ 패키지와 클래스 생성
com.br.sbatis.controller.NoticeController
com.br.sbatis.dto.NoticeDto
com.br.sbatis.dao.NoticeDao
com.br.sbatis.service.Service 인터페이스
com.br.sbatis.service.ServiceImpl 클래스
ㅁ NoticeDto
package com.br.sbatis.dto;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
@NoArgsConstructor
// @AllArgsConstructor 매개변수 생성자는 dto엔 사용할 일이 없다.
@Getter
@Setter
@ToString
public class NoticeDto {
private int no;
private String title;
private String content;
}
ㅁ NoticeService
package com.br.sbatis.service;
import java.util.List;
import com.br.sbatis.dto.NoticeDto;
public interface NoticeService {
// 전체목록조회
List<NoticeDto> selectNoticeList();
// 번호로 공지사항 한 개 조회
NoticeDto selectNoticeByNo(int noticeNo);
// 공지사항 등록
int insertNotice(NoticeDto n);
// 공지사항 수정
int updateNotice(NoticeDto n);
// 다수의 번호들 가지고 공지사항 일괄삭제
int deleteNotice(String[] deleteNo);
}
ㅁ NoticeServiceImpl
package com.br.sbatis.service;
import java.util.List;
import org.springframework.stereotype.Service;
import com.br.sbatis.dao.NoticeDao;
import com.br.sbatis.dto.NoticeDto;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@Service
public class NoticeServiceImpl implements NoticeService {
private final NoticeDao noticeDao;
@Override
public List<NoticeDto> selectNoticeList() {
return null;
}
@Override
public NoticeDto selectNoticeByNo(int noticeNo) {
return null;
}
@Override
public int insertNotice(NoticeDto n) {
return 0;
}
@Override
public int updateNotice(NoticeDto n) {
return 0;
}
@Override
public int deleteNotice(String[] deleteNo) {
return 0;
}
}
ㅁ NoticeDao
package com.br.sbatis.dao;
import org.springframework.stereotype.Repository;
@Repository
public class NoticeDao {
}
ㅁ 컨트롤러에서는 서비스 객체가, 서비스에서는 dao 객체가 필요하다.
여기까지가 mvc의 기본세팅이다.
ㅁ 추가로 마이바티스 쓴다.
- src/main/resources에 config, mappers 폴더 생성.
ㅁ mapper 파일에 xml 파일 만들기
- 기존에는 dtd 3줄을 홈페이지에서 복붙했다.
- 처음 만들때부터 붙여서 만들 수 있다.
- preferences - xml - xml catalog - ~
- new xml file에서 finish말고 next한다.
- finish하면 기본 템플릿대로 만들어진다.
- 2->1
- 1 -> 2
- user specified entries 보면 내가 만든 2개~. 직므은 mapper파일이니까 mapper 누른다.
- finish한다.
- <cache-ref> 태그는 자동완성시 만들어지는데 반드시 지워줘야 한다.
- 이런식으로 mapper 파일을 많이 만들 예정이다.
- 이때 각각의 mapper 파일을 각각의 어쩌구~
mapper 파일의 ~ namespace
- 초반에 mapper 파일 만들 때 반드시 namespace까지도 써놔라.
namespace를 안쓰고 등록하면 서버 구동이 안된다.
ㅁ config 폴더에 mybatis-config.xml 생성
- 얘도 finish로 바로 만들지 않고 위처럼 똑같이 한다.
- user specified entries만 config를 선택한다.
- 근데 조금 이상하다. 마이바티스때 홈페이지에서 가져왔던 코드는 세번째가 url 주소였다.
- 이 상태로는 유효성 검사가 제대로 반영이 안 될 수 있다.
- 미리 설정하고 가져다 쓰고 있는데
- config, mapper 둘 다 https를 http로 바꾼다.
- https면 url로 인식이 잘 안됬던 이슈가 있었다. ~
- config, mapper 둘 다 삭제하고 다시 만들었다. 세번째가 url 주소로 잘 되어있다.
ㅁ mybatis-config.xml
- 주로 dto에 별칭을 붙인다.
그런데 실제 클래스가 존재하고 별칭을 붙여야 한다.
서버 시작할 때 이제 웬만한 xml 파일을 다 읽어들인다. 없으면 서버 시작할 때부터 오류난다.
- mapper 파일도 존재하지 않는 mapper 파일을 쓰면 오류난다.
뿐만 아니라 mapper파일은 namespace까지도 다 지정되어 있어야 한다.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
<configuration>
<settings>
<setting name="jdbcTypeForNull" value="NULL" />
</settings>
<typeAliases>
<typeAlias type="com.br.sbatis.dto.NoticeDto" alias="NoticeDto" />
</typeAliases>
<!-- 연결 db 정보는 mybatis 관련한 SqlSession[Template] 빈으로 등록하는 곳에서 작성한다. -->
<mappers>
<mapper resource="mappers/notice-mapper.xml" />
</mappers>
</configuration>
- 그런데 이전 마이바티스의 mybatis-config.xml에서 environments ~
- 연결 db 정보는 mybatis 관련한 SqlSession[Template] 빈으로 등록하는 곳에서 작성한다.
- settings, typeAliases, mappers 태그만 작성했다.
- ~ 거기에 연결 db정보를 작성한다.
ㅁ SqlSession 객체 빈 등록
- 빈 등록 방법은 3가지. xml 방식, 자바 방식, 어노테이션 방식. 내가 만든 클래스면 상단에 어노테이션.
- 이번에 등록해야 하는 빈은 내가 만든 클래스가 아니고 마이바티스가 제공하는 클래스다.
- src/main/webapp/WEB-INF/spring의 root-context.xml
서버가 실행될 때 root-context.xml을 읽어들인다.
ㅁ root-context.xml
- 서버 스타트와 동시에 web.xml 파일에 기술된 ContextLoaderListener에 의해 pre-loading(제일 먼저 읽혀짐)되는 문서.
- Spring Bean Configuration File이다. 빈을 등록하는 파일이다. 아이콘도 콩과 S 모양이 있다.
- 서버 구동과 동시에 등록하고자 하는 빈들이 있다면 해당 파일에 작성하면 된다.
- 주로 db 관련 빈 객체, 트랜잭션 처리, 내외부 모듈 연동 등 스프링에서 제공하는 서비스들에 대한 설정 정보들에 대해 작성한다.
- SqlSession은 마이바티스가 제공하는 객체다.
~ 우리가 필요한 건 SqlSession 객체가 아니라 ~서 제공하는 SqlSessionTemplate 객체가 필요하다.
- 그런데 SqlSessionTemplate 객체를 만드려면 SqlSessionFactoryBean이라는 객체가 필요하다.
SqlSessionFactoryBean 객체도 빈으로 등록되어야 한다.
- 작성 순서 중요하다. SqlSessionFactoryBean이 먼저 생성되어야 한다.
- 그런데 SqlSessionFactoryBean 객체를 만드려면 BasicDataSource 객체가 필요하다.
BasicDataSource 객체에 setter 메소드로 value값을 각 필드에 담았다.
(1) BasicDataSource
- destroy-method="close"는 해당 빈이 소멸될 때 close() 메서드가 호출된다는 의미다.
SqlSessionFactoryBean의 경우, 세션을 닫고 연결을 정리하는 자원 해제 작업을 close() 메서드를 통해 수행
(2) SqlSessionFactoryBean
- SqlSessionFactoryBean 객체를 생성하면서 mybatis-config.xml을 읽어들인다.
- classpath:: 리소스 파일이 클래스패스에 위치하고 있음을 나타냅니다. 클래스패스는 주로 src/main/resources에 해당하며, 이 경로에 있는 파일을 참조할 수 있습니다.
- config/mybatis-config.xml: 클래스패스 내에서 config 폴더 안에 있는 mybatis-config.xml 파일을 참조하겠다는 의미입니다.
- dataSource 필드에 위에서 빈으로 등록한 dataSource 객체를 참조한다.
이 객체를 만들기 위해서는 위의 객체가 필요해서 먼저 빈으로 등록했다.
(3) SqlSessionTemplate
- 이 빈의 아이디로 "sqlSession"을 준다.
- 빈이름이 바로 위에서 만든 "sqlSessionFactory"인 객체를 주입한다.
- 위의 3개 다 내가 만든 클래스가 아니어서 어노테이션 방식이 불가능하다.
- 자바에서 객체 생성하고 setter 메소드로 담는 구문이 내부적으로 실행된다.
value 속성이 아니고 ref 속성이면 문자열로 담기는게 아니고 참조 변수가 그대로 담긴다.
- constructor-arg는 setter메소드가 아니라 생성할 때 생성자의 매개변수로 전달한다는 뜻이다.
- 최종적으로 필요한 객체는 SqlSessionTemplate 타입의 sqlSession 객체다.
- 스프링을 쓰지 않던 마이바티스 프로젝트에서는 별도로 Template 클래스를 만들어서 SqlSession 객체를 생성해서 반환하는 static 메소드를 만들었었다.
여기서도 sqlSession 객체를 만들 때 mybatis-config.xml을 읽어들이는 InputStream과 sqlSeesionFactoryBuilder ~
ㅁ 서버에 add and remove로 4번째 프로젝트만 올리고 서버 스타트한다.
ㅁ 로그백
- log4.xml은 지운다.
3번재 프로젝트에서 logback.xml을 복사해서 src/main/resources에 붙여넣는다.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender class="ch.qos.logback.core.ConsoleAppender" name="consoleLog">
<encoder>
<pattern>%-5level: [%date{yyyy-MM-dd HH:mm:ss}] [%logger:%line] - %msg%n</pattern>
</encoder>
</appender>
<logger name="org.springframework" level="INFO" />
<logger name="com.br.sbatis" level="DEBUG" />
<root level="WARN">
<appender-ref ref="consoleLog" />
</root>
</configuration>
- <logger name="com.br.ajax" level="DEBUG" />에서 ajax를 sbatis로 바꿨다.
ㅁ 서버 구동해보고 오류나는지 확인한다.
===============================================================
ㅁ NoticeDao 수정
package com.br.sbatis.dao;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.stereotype.Repository;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@Repository
public class NoticeDao {
private final SqlSessionTemplate sqlSession;
}
ㅁ src/main/webapp/WEB-INF/views에 main.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<c:set var="contextPath" value="${pageContext.request.contextPath}" />
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h2>메인페이지</h2>
<a href="">공지사항 목록페이지로 이동</a>
</body>
</html>
ㅁ controller에 MvcController 생성
package com.br.sbatis.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class MvcController {
@GetMapping("/")
public String mainPage() {
return "main";
}
}
- 단순히 메인페이지 이동용이다.
- @Contoller 어노테이션 붙인다.
ㅁ 서버 리스타트 후 메인페이지가 잘 뜨는지 확인한다.