

VO,DTO를 먼저 설계 => MyBatis의 result type설정하기 위해서는 VO,DTO의 설계가 먼저 필요하기 때문이다.
Mapper Interface 설계
인터페이스와 동일한 이름의 XML Mapper 설정
sql 먼저 테스트 해보기 (잘 되면 복사해서 5번으로)
XML Mapper에 4번의 sql을 반영한다.
테스트 코드 실행
package org.zerock.w1.vo;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class BoardVO {
private Long bno;
private String title;
private String content;
private String writer;
private LocalDateTime regDate;
private LocalDateTime modDate;
}
👉 VO이자 DTO의 역할을 함.
package org.zerock.w1.mappers;
import org.zerock.w1.vo.BoardVO;
import org.zerock.w1.vo.PageRequest;
public interface BoardMapper {
java.util.List<BoardVO> list(PageRequest pageRequest); // BoardMapper의 list메서드는 PageRequest객체를 인자값으로 받아 BoardVO를 return
Long insert(BoardVO vo); // dml이므로 몇건이 처리되었는지 알수있기 위해 Long
int delete(Long bno); // dml이므로 몇건이 처리되었는지 알수있기 위해 int
int update(BoardVO vo); // update가 몇건 되었는지 나오는것이므로 int로 하고 넣을 값이 여러개이므로 vo 객체
BoardVO select(Long bno);
}
👉 BoardMapper 인터페이스 내부의 list 메서드가 Page에 대한 객체를 매개변수로 받으면 return값으로 BoardVO를 준다.
👉 insert,delete,update는 dml이므로 몇건의 데이터가 처리되었는지 return되므로 int, Long으로 설정한다. 매개변수로는 vo객체 혹은 bno
<?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">
<mapper namespace="org.zerock.w1.mappers.BoardMapper">
<select id="list" resultType="BoardVO"> <!-- id값은 인터페이스에 정의한 메소드명, resultType은 행 하나하나가 boardVO 이므로 -->
select *
from tbl_board
order by bno desc
limit #{skip}, #{size}
</select>
<insert id="insert">
<selectKey order="AFTER" resultType="Long" keyProperty="bno"> <!-- selectKey를 통해 insert 이후에 마지막으로 입력된 last insert id값을 알수있음 -->
SELECT LAST_INSERT_ID()
</selectKey>
insert into tbl_board(title,content,writer)
values (#{title}, #{content}, #{writer}) <!-- #{}를 하게되면 알아서 Get title, Get content 등 찾아간다. -->
</insert>
<delete id="delete"> <!-- delete라 타입 필요 x -->
delete from tbl_board where bno = #{bno} <!-- 기본자료형 파라미터가 하나이면 파라미터값을 아무거나 줘도 상관없다 -->
</delete>
<update id="update"> <!-- 파라미터 값들은 #{}으로 작성 -->
update tbl_board
set title=#{title},
content=#{content},
modDate=now()
where bno = ${bno}
</update>
<select id="select" resultType="BoardVO"> <!-- select문은 resultType이 무조건 필요 -->
select * from tbl_board where bno = #{bno}
</select>
</mapper>
👉 select 혹은 페이징은 값을 db의 row단위로 가져와야하므로 resultType값을 설정해줘야하는데, 현재 vo값이 하나의 객체인 BoardVO로 되어있으므로 BoardVO로 설정해준다.
👉 기존의 jsp/servlet에서 sql을 사용할때는 ?(물음표)를 매개변수값으로 사용하였지만 해당 Spring에서는 #{}으로 사용한다.
👉 selectKey는 insert와 같이 sql문이 종료된 이후에 원하는 값을 얻기위해서 사용한다. 해당 예시로는 하나의 데이터를 추가했을때, 마지막으로 추가된 bno의 값을 알기 위해서 사용하였다.
package org.zerock.w1.mappers;
@ExtendWith(SpringExtension.class)
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml")
@Log4j2
public class BoardMapperTests {
@Autowired
private BoardMapper boardMapper;
@Test
public void test() {
PageRequest pg = new PageRequest();
log.info("---------------------");
log.info(boardMapper.list(pg)); //boardMapper의 list메서드를 호출해서
}
@Test
public void testInsert() {
BoardVO vo = BoardVO.builder()
.title("Sample Title")
.content("Sample Content")
.writer("user00")
.build();
Long count = boardMapper.insert(vo);
log.info("count: "+count);
log.info(vo.getBno());
}
@Test
public void testDelete() {
boardMapper.delete(10L); // LONG 타입이므로 뒤에 L을 붙혀줘야함 / 10번 삭제하기
}
@Test
public void testUpdate() {
BoardVO vo = BoardVO.builder()
.bno(13L)
.title("Sample Title13")
.content("Sample Content")
.build();
boardMapper.update(vo);
}
@Test
public void testSelect() {
boardMapper.select(13L);
}
}
👉 Autowired를 통해 BoardMapper를 주입
👉 Insert 테스트를 위해서 builder를 이용하여 vo객체를 쉽게 만들수있고, vo객체를 통해 만들어진 더미데이터를 boardMapper의 insert문에 매개변수로 넣어주게 되면 몇개의 데이터가 만들어졌는지에 대한 count값으로 만들수 있고, getBno를 통해 마지막에 등록된 Bno값을 알수있다.
👉 delete와 select문에서는 bno값을 인자값으로 넣어줘야해서 숫자를 넣지만, BoardVo에서 Long타입으로 선언했기 때문에 10L과 같이 뒤에 L을 넣어준다.
📌 기존의 이클립스에서 인텔리제이로 넘어가기 위해서 tomcat ver을 9버전을 사용해야한다.
tomcat.apache.org에서 9.0.93 ver으로 압축 다운로드하여 C드라이브에 풀어놓자.


gradle 설정
implementation 'org.springframework:spring-core:5.3.27'
implementation 'org.springframework:spring-context:5.3.27'
implementation 'org.springframework:spring-webmvc:5.3.27'
implementation 'org.springframework:spring-test:5.3.27'
implementation 'org.springframework:spring-jdbc:5.3.27'
implementation 'org.springframework:spring-tx:5.3.27'
4-1. gradle 수정
compileOnly('javax.servlet:javax.servlet-api:4.0.1')
compileOnly 'org.projectlombok:lombok:1.18.30'
testCompileOnly 'org.projectlombok:lombok:1.18.30'
annotationProcessor 'org.projectlombok:lombok:1.18.30'
testAnnotationProcessor 'org.projectlombok:lombok:1.18.30'
spring 폴더와 root-context , servlet-context 만들기
📌 new -> xml configration으로 생성하면 base세팅이 됨

org.zerock.w2 패키지 아래에, controller, mapper패키지 생성




implementation 'org.apache.logging.log4j:log4j-api:2.22.1'
implementation 'org.apache.logging.log4j:log4j-core:2.22.1'
implementation 'org.apache.logging.log4j:log4j-slf4j-impl:2.22.1'
10-1. log4j2.xml 파일을 resources아래에 생성하여 해당코드를 붙혀넣자
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<!-- Appender, Layout 설정 -->
<Appenders>
<Console name="console" target="SYSTEM_OUT">
<PatternLayout
pattern="%d{MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n" />
</Console>
</Appenders>
<!-- Logger 설정 -->
<Loggers>
<Logger name="com.zaxxer" level="INFO" additivity="false">
<AppenderRef ref="console"/>
</Logger>
<Logger name="org.springframework" level="INFO" additivity="false">
<AppenderRef ref="console"/>
</Logger>
<Logger name="org.zerock" level="INFO" additivity="false">
<AppenderRef ref="console"/>
</Logger>
<Root level="INFO">
<AppenderRef ref="console"/>
</Root>
</Loggers>
</Configuration>
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/spring/root-context.xml</param-value>
</context-param>
<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/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>
</web-app>
서버 접속해서 로그랑 WEB 잘 뜨는지 확인하기
JDBC 드라이버, hicariCP, MyBatis,jstl gradle 설정
implementation 'org.mariadb.jdbc:mariadb-java-client:3.1.4'
implementation 'com.zaxxer:HikariCP:5.0.0'
implementation 'org.mybatis:mybatis:3.5.7'
implementation 'org.mybatis:mybatis-spring:2.0.6'
implementation 'jstl:jstl:1.2'
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
<property name="driverClassName" value="org.mariadb.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mariadb://localhost:3306/bootdb2"/>
<property name="username" value="bootdb2user"/>
<property name="password" value="bootdb2user"/>
<property name="connectionTimeout" value="30000"/>
<property name="minimumIdle" value="2"/>
</bean>
<bean name="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
<constructor-arg ref="hikariConfig"/>
</bean>
</beans>
mapper의 현재시간 인터페이스 생성 및 mapper 폴더, xml생성 (TimeMapper인터페이스 내부 값은 이클립스에서 이전에 만들었던거 가져왔음)

root-context 코드 추가
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring.xsd">
<bean name="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
<property name="driverClassName" value="org.mariadb.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mariadb://localhost:3306/bootdb2"/>
<property name="username" value="bootdb2user"/>
<property name="password" value="bootdb2user"/>
<property name="connectionTimeout" value="30000"/>
<property name="minimumIdle" value="2"/>
</bean>
<bean name="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
<constructor-arg ref="hikariConfig"/>
</bean>
<bean class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
</bean>
<mybatis-spring:scan base-package="org.zerock.w2.mapper"></mybatis-spring:scan>
</beans>

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"></property>
<property name="suffix" value=".jsp"></property>
</bean>




<mvc:resources mapping="/resources/**" location="classpath:/static/"></mvc:resources>
<!--static한 자원을 세팅을 위해-->
<mvc:annotation-driven></mvc:annotation-driven>

5-1. service 패키지 생성 및 root-context.xml 파일 내부에 코드 추가

5-2. gradle 추가
implementation 'org.aspectj:aspectjweaver:1.9.22'
implementation 'org.aspectj:aspectjrt:1.9.22'
5-3. TimeSerive 클래스 추가

5-4. aop패키지, LogAdvice 클래스 추가

package org.zerock.w2.aop;
import lombok.extern.log4j.Log4j2;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect
@Component
@Log4j2
public class LogAdvice {
@Before("execution(* org.zerock.w2.service.*.*(..))")
public void logBefore(JoinPoint joinPoint) {
log.info("-------------------------");
log.info("-------------------------");
log.info("-------------------------");
log.info("-------------------------");
}
}
5-5. root-context 내부에 코드추가

5-6. timeController에서 getTime 메소드 호출해보기

5-7. db연결시간 확인가능 코드


👉 해당 사진처럼 log, transaction, security등을 aop로 다 해결할 수 있다. (log를 일일이 찍지 않아도)
6-1. timeService

6-2. TimeMapper.xml

6-3. mybatis-config.xml

6-4. 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"
xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean name="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
<property name="driverClassName" value="org.mariadb.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mariadb://localhost:3306/bootdb2"/>
<property name="username" value="bootdb2user"/>
<property name="password" value="bootdb2user"/>
<property name="connectionTimeout" value="30000"/>
<property name="minimumIdle" value="2"/>
</bean>
<bean name="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
<constructor-arg ref="hikariConfig"/>
</bean>
<bean class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:/mappers/*.xml"/>
</bean>
<mybatis-spring:scan base-package="org.example.wdemo.mapper"></mybatis-spring:scan>
<context:component-scan base-package="org.example.wdemo.service"></context:component-scan>
<context:component-scan base-package="org.example.wdemo.aop"></context:component-scan>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
6-5. servlet-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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!--static한 자원을 세팅을 위해-->
<context:component-scan base-package="org.example.wdemo.controller">
</context:component-scan>
<mvc:annotation-driven></mvc:annotation-driven>
</beans>
6-6. build.gradle
plugins {
id 'java'
id 'war'
}
group 'org.example'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
ext {
junitVersion = '5.9.2'
}
sourceCompatibility = '1.8'
targetCompatibility = '1.8'
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
dependencies {
compileOnly('javax.servlet:javax.servlet-api:4.0.1')
testImplementation("org.junit.jupiter:junit-jupiter-api:${junitVersion}")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${junitVersion}")
implementation 'org.springframework:spring-core:5.3.27'
implementation 'org.springframework:spring-context:5.3.27'
implementation 'org.springframework:spring-webmvc:5.3.27'
implementation 'org.springframework:spring-test:5.3.27'
implementation 'org.springframework:spring-jdbc:5.3.27'
implementation 'org.springframework:spring-tx:5.3.27'
compileOnly 'org.projectlombok:lombok:1.18.30'
testCompileOnly 'org.projectlombok:lombok:1.18.30'
annotationProcessor 'org.projectlombok:lombok:1.18.30'
testAnnotationProcessor 'org.projectlombok:lombok:1.18.30'
implementation 'org.apache.logging.log4j:log4j-api:2.22.1'
implementation 'org.apache.logging.log4j:log4j-core:2.22.1'
implementation 'org.apache.logging.log4j:log4j-slf4j-impl:2.22.1'
implementation 'org.mariadb.jdbc:mariadb-java-client:3.1.4'
implementation 'com.zaxxer:HikariCP:5.0.0'
implementation 'org.mybatis:mybatis:3.5.7'
implementation 'org.mybatis:mybatis-spring:2.0.6'
implementation 'jstl:jstl:1.2'
implementation 'org.aspectj:aspectjweaver:1.9.22'
implementation 'org.aspectj:aspectjrt:1.9.22'
}
test {
useJUnitPlatform()
}