ㅁ 5번째 프로젝트
- 다 써볼 예정. + 파일 업로드
ㅁ sql develoer
- sbatis 계정으로 테이블 2개, 시퀀스 2개를 더 만든다.
- 총 테이블 3개(NOTICE, BOARD, ATTACHMENT)와 시퀀스 3개(seq_notice, seq_bno, weq_fno)가 있다.
create table board ( board_no number primary key , board_title varchar2(100) not null , board_content varchar2(4000) ); create table attachment ( file_no number primary key , file_path varchar2(200) , original_name varchar2(200) , filesystem_name varchar2(100) , ref_board_no number references board ); create sequence seq_bno; create sequence seq_fno;
ㅁ 안쓰는 프로젝트 닫기
- 버벅이니까 안쓰는 프로젝트는 우클릭 - close project로 닫는다.
- 그냥 닫히는것 뿐이고 더블클릭하면 다시 오픈된다.
ㅁ Spring Legacy Project 생성
- 프로젝트명을 입력하고, Spring MVC Project 선택하고, next를 누른다.
- 베이스 패키지는 com.br.file로 한다. 이러면 컨텍스트 패스는 /file이 된다.
ㅁ 베이스 패키지의 Homecontroller랑 views의 home.jsp 삭제
ㅁ 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 (AOP를 위한 라이브러리)-->
< dependency > <!-- 원래 있던 것. 이게 있어야 "Advice 동작 시점"의 어노테이션들을 사용할 수 있다. -->
< groupId > org.aspectj </ groupId >
< artifactId > aspectjrt </ artifactId >
< version > ${org.aspectj-version} </ version >
</ dependency >
<!-- 위빙 : Advice(공통로직)를 PointCut(핵심로직)에 로딩되도록 함 -->
< dependency >
< groupId > org.aspectj </ groupId >
< artifactId > aspectjweaver </ artifactId >
< version > ${org.aspectj-version} </ version >
< scope > runtime </ scope >
</ dependency >
<!-- Logging (logback) -->
< dependency >
< groupId > ch.qos.logback </ groupId >
< artifactId > logback-classic </ artifactId >
< version > 1.4.14 </ version >
<!-- <scope>test</scope> 이건 지워야 함 -->
</ dependency >
<!-- (2) slf4j -->
< dependency > <!-- 기존 dependency 중 이것만 남기고 다 지운다.-->
< groupId > org.slf4j </ groupId >
< artifactId > slf4j-api </ artifactId >
< version > ${org.slf4j-version} </ version >
</ dependency >
<!-- (3) log4jdbc -->
< dependency >
< groupId > org.bgee.log4jdbc-log4j2 </ groupId >
< artifactId > log4jdbc-log4j2-jdbc4.1 </ artifactId >
< version > 1.16 </ 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 >
- 기존 4번째 프로젝트의 pom.xml에서 전부 가져오지 않고, <properties> 태그부터 끝까지를 복사해서
5번째 프로젝트의 pom.xml에 붙여넣는다.
- 라이브러리가 계속 추가되고 있는데 결국에는 다 쓸 예정이다.
- 라이브러리들 설명.
- 저장한다. 자바 버전은 바로 바뀌지 않는다. 프로젝트 우클릭 - Maven - update project한다.
ㅁ web.xml
<? xml version = "1.0" encoding = "UTF-8" ?>
<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
< context-param >
< param-name > contextConfigLocation </ param-name >
< param-value > /WEB-INF/spring/root-context.xml </ param-value >
</ context-param >
<!-- Creates the Spring Container shared by all Servlets and Filters -->
< listener >
< listener-class > org.springframework.web.context.ContextLoaderListener </ listener-class >
</ listener >
<!-- Processes application requests -->
< servlet >
< servlet-name > appServlet </ servlet-name >
< servlet-class > org.springframework.web.servlet.DispatcherServlet </ servlet-class >
< init-param >
< param-name > contextConfigLocation </ param-name >
< param-value > /WEB-INF/spring/appServlet/servlet-context.xml </ 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 > UTF-8 </ param-value >
</ init-param >
</ filter >
< filter-mapping >
< filter-name > encodingFilter </ filter-name >
< url-pattern > /* </ url-pattern >
</ filter-mapping >
</ web-app >
- 4번째 프로젝트의 web.xml에서 인코딩 필터 등록 부분의 <filter>, <filter-mapping> 태그를 복사해서
5번째 프로젝트의web.xml에 붙여넣는다.
ㅁ src/main/resources
- log4j.xml 삭제
- 4번째 프로젝트에서 log4jdbc.log4j2.properties과 logback.xml을 파일을 그대로 복사해서 가져온다.
ㅁ logback.xml 수정
<? 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.file" level = "DEBUG" />
< logger name = "jdbc.sqlonly" level = "off" /> <!-- 쿼리문만 -->
< logger name = "jdbc.sqltiming" level = "INFO" /> <!-- 쿼리문 + 실행시간 -->
< logger name = "jdbc.audit" level = "off" /> <!-- JDBC 호출 정보 -->
< logger name = "jdbc.resultset" level = "off" /> <!-- ResultSet 호출 정보 -->
< logger name = "jdbc.resultsettable" level = "off" /> <!-- ResultSet 결과 (조회결과 테이블) -->
< logger name = "jdbc.conntection" level = "off" /> <!-- Connection 호출 정보 -->
< root level = "WARN" >
< appender-ref ref = "consoleLog" />
</ root >
</ configuration >
- com.br.sbatis를 com.br.file로 바꾼다.
- sqltiming을 INFO로 바꾼다.
ㅁ 패키지 생성
- com.br.file.controller
- com.br.file.service
- com.br.file.dao
- com.br.file.dto
- com.br.file.util
- 서비스가 좀 많다면 도메인형 구조가 좋지만 이런 계층형 구조로도 해본다.
계층형 구조로 패키지를 두는 회사도 많다.
- 패키지를 만들었다면 dto 클래스부터 생성한다.
ㅁ com.br.file.dto 패키지에 BoardDto 클래스 생성
package com.br.file.dto ;
import lombok.AllArgsConstructor ;
import lombok.Builder ;
import lombok.Getter ;
import lombok.NoArgsConstructor ;
import lombok.Setter ;
import lombok.ToString ;
@ NoArgsConstructor
@ AllArgsConstructor
@ Getter
@ Setter
@ ToString
@ Builder
public class BoardDto {
private int boardNo ;
private String boardTitle ;
private String boardContent ;
}
- db를 참고해서 필드를 만든다.
- 이제부터 필드명은 소문자 하나 + 대문자로 노노. 최소 소문자 2개 다음에 대문자가 오게끔 필드명을 작성한다.
- 저 어노테이션들을 이제 기본으로 다 깔고간다.
- import할 때 Getter와 Setter는 lombok 패키지 걸로 고른다.
ㅁ com.br.file.dto 패키지에 AttachDto 클래스 생성
package com . br . file . dto ;
import lombok . AllArgsConstructor ;
import lombok . Builder ;
import lombok . Getter ;
import lombok . NoArgsConstructor ;
import lombok . Setter ;
import lombok . ToString ;
@ NoArgsConstructor
@ AllArgsConstructor
@ Getter
@ Setter
@ ToString
@ Builder
public class AttachDto {
private int fileNo ;
private String filePath ;
private String originalName ;
private String filesystemName ;
private int refBoardNo ;
}
ㅁ 클래스 생성
- com.br.file.controller
- com.br.file.service
- com.br.file.dao
- com.br.file.dto
ㅁ src/main/resources
- config, mappers 일반 폴더 생성
- mappers 폴더 우클릭 - new - xml file - board-mapper.xml 입력후 finish 말고 next -
- User Specified Entries에서 저걸 선택하고 next, 그 다음창에서 아무것도 안건들고 바로 finish.
<? xml version = "1.0" encoding = "UTF-8" ?>
< mapper namespace = "boardMapper" >
</ mapper >
- <cache-ref> 태그는 반드시 지워야 한다.
- <mapper> 태그에 namespace 속성을 준다.
- config 우클릭 - new - xml file - mybatis-config.xml 입력후 finish 말고 next - 위와 똑같이 한다.
<? xml version = "1.0" encoding = "UTF-8" ?>
< configuration >
< settings >
< setting name = "jdbcTypeForNull" value = "NULL" />
</ settings >
< typeAliases >
< typeAlias type = "com.br.file.dto.BoardDto" alias = "BoardDto" />
< typeAlias type = "com.br.file.dto.AttachDto" alias = "AttachDto" />
</ typeAliases >
< mappers >
< mapper resource = "mappers/board-mapper.xml" />
</ mappers >
</ configuration >
- 지금 이 문서들은 서버 구동과 동시에 읽혀져서 오류가 있으면 안된다.
- 클래스도 실제로 존재해야 한다. dto 클래스도 먼저 만들고 등록을 해야 한다.
- 매퍼 파일들도 실제로 존재해야 한다. 또 매퍼 파일들 마다 별칭도 있어야 한다. 매퍼 파일을 먼저 만들고 별칭도 namespace로 부여하고 등록한다.
ㅁ root-context.xml
<? xml version = "1.0" encoding = "UTF-8" ?>
<!-- mybatis 사용을 위한 빈 3개 -->
< bean class = "org.apache.commons.dbcp2.BasicDataSource" id = "dataSource" destroy-method = "close" >
<!-- <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:@localhost:1521:xe" /> -->
< 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 = "sbatis" />
< property name = "password" value = "sbatis" />
</ bean >
< bean class = "org.mybatis.spring.SqlSessionFactoryBean" id = "sqlSessionFactory" >
< property name = "configLocation" value = "classpath:config/mybatis-config.xml" />
< property name = "dataSource" ref = "dataSource" />
</ bean >
< bean class = "org.mybatis.spring.SqlSessionTemplate" id = "sqlSession" >
< constructor-arg ref = "sqlSessionFactory" />
</ bean >
<!-- 트랜잭션 처리용 aop를 위한 구문 3개 -->
<!-- AOP를 이용한 트랜잭션 처리 -->
<!-- 1) 트랜잭션 매니저 빈으로 등록 (dataSource 객체 필요함) -->
< bean class = "org.springframework.jdbc.datasource.DataSourceTransactionManager" id = "txManager" >
< property name = "dataSource" ref = "dataSource" />
</ bean >
<!-- 2) 트랜잭션 Advice 등록 -->
< tx:advice transaction-manager = "txManager" id = "txAdvice" >
< tx:attributes >
< tx:method name = "*" /> <!-- pointcut의 모든 메소드에서 실행하겠다. (삽입, 수정, 삭제, 목록조회, 상세조회 등의 메소드가 있음) -->
< tx:method name = "select*" read-only = "true" /> <!-- 단, select로 시작하는 메소드는 실행하지 않는다. (삽입, 수정, 삭제 메소드만 실행됨) -->
</ tx:attributes >
</ tx:advice >
<!-- 3) AOP 등록 -->
< aop:config >
< aop:pointcut expression = "execution(* com.br.sbatis.file.*Impl.*(..))" id = "txPointcut" />
< aop:advisor advice-ref = "txAdvice" pointcut-ref = "txPointcut" />
</ aop:config >
</ beans >
- 4번째 프로젝트의 root-context.xml에서 <beans>~</beans> 부분에서 <breans>와 </beans> 태그는 빼고 그 안의 내용을 다 복사해서 5번째 프로젝트의 root-context.xml에 붙여넣는다.
- xml에 주석은 최대한 없는게 좋다. 오류를 많이 발생시킨다. 태그 안에 주석도 안주는게 좋다.
- namespace탭에서 aop와 tx를 선택한다.
- 위가 4번째 프로젝트의 root-context.xml이고, 아래가 지금 만드는 5번째 프로젝트의 root-context.xml이다.
- 'file'로 수정한다.
수정하지 않으면 오류가 발생하진 않는데 트랜잭션 처리가 안된다.
ㅁ BoardDao
package com . br . file . dao ;
import org . mybatis . spring . SqlSessionTemplate ;
import org . springframework . stereotype . Repository ;
import lombok . RequiredArgsConstructor ;
@ RequiredArgsConstructor
@ Repository
public class BoardDao {
private final SqlSessionTemplate sqlSession ;
}
- Service에서 dao 객체를 필요로 한다. 그러려면 dao가 빈으로 등록되어 있어야 한다.
- @Repository 어노테이션을 붙인다. 롬복이 아닌 스프링에서 제공한다.
ㅁ BoardService
package com . br . file . service ;
public interface BoardService {
}
- 확인 필요
ㅁ BoardServiceImpl
package com . br . file . service ;
import org . springframework . stereotype . Service ;
import com . br . file . dao . BoardDao ;
import lombok . RequiredArgsConstructor ;
@ RequiredArgsConstructor
@ Service
public class BoardServiceImpl implements BoardService {
private final BoardDao boardDao ;
}
- 컨트롤러에서 서비스 객체를 필요로 한다. 그러려면 빈으로 등록되어 있어야 한다. @Service 어노테이션을 붙인다.
ㅁ BoardController
package com . br . file . controller ;
import org . springframework . stereotype . Controller ;
import org . springframework . web . bind . annotation . RequestMapping ;
import com . br . file . service . BoardService ;
import lombok . RequiredArgsConstructor ;
@ RequestMapping ( "/board" )
@ RequiredArgsConstructor
@ Controller
public class BoardController {
private final BoardService boardService ;
}
- @Controller 어노테이션을 붙인다.
- @RequestMapping을 붙인다.
ㅁ 여기가 기본적인 세팅 끝이다.
- 서버에 add and remove로 현재 프로젝트를 올린다.
- 서버를 스타트해서 오류가 없는지 확인한다.
ㅁ 프로젝트 생성 후 세팅
0. 버전 및 라이브러리 등록 : pom.xml
1. 인코딩필터 등록 : web.xml 2. 로그관련 문서 세팅 1) logback.xml 복사 후 base package 수정 2) log4jdbc properties 복사 3. 계층형 패키지 생성 4. Dto 클래스 먼저 만들기 5. mybatis 관련 문서 세팅 1) mappers 폴더 만들어서 *-mapper.xml 파일 만들기 (반드시 namespace 까지 지정해둘것) 2) config 폴더 만들어서 mybatis-config.xml 파일 만들기 ㄴ setting 태그 작성 ㄴ typeAlias로 Dto 클래스들 alias 등록해두기 ㄴ mapper파일들 등록해두기 6. DB관련 빈 등록, 트랜잭션 관련 구문 작성 : root-context.xml 1) mybatis 사용을 위한 빈 3개 등록 2) 트랜잭션 처리를 위한 aop 등록 (base package 수정)
3) 첨부파일 업로드를 위한 빈 등록 7. MVC 패턴의 클래스 만들기 1) controller, service<I>, serviceImpl, dao 만들기 2) controller, serviceImpl, dao 에 어노테이션 붙여서 빈등록하기 3) 각 클래스마다 필요한 필드 추가해서 DI 진행시키기 8. Server Start 해보기 (오류안나야됨)
===============================================================================
ㅁ 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 >
메인페이지
</ body >
</ html >
ㅁ controller에 MvcController 생성
package com . br . file . controller ;
import org . springframework . stereotype . Controller ;
import org . springframework . web . bind . annotation . GetMapping ;
@ Controller
public class MvcController {
@ GetMapping ( "/" )
public String mainPage () {
return "main" ;
}
}
- MvcController에는 항상 메인 페이지를 응답하는 메소드만 둔다.
- @Controller 어노테이션을 붙여서 빈으로 등록한다.
ㅁ 서버 스타트 후 메인페이지 접속
- http://localhost:8888/file를 입력하면 메인페이지가 응답된다.