티스토리 뷰
※ 수업 코드로 클론코딩해보기 ※
✔ 현재 상태 : 프로젝트 실행했을 때, home도 연결이 안 됨....
→ 스프링프로젝트는 프로젝트 내의 모든 오류를 검사. 하나라도 오류가 있다면 전체 실행 불가.
1. 프로젝트 생성
-Srping Legacy Project : boardSystem02
-top level package name : com.wsy.boardsystem02
2. 환경설정
(2-1) pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cm.wsy</groupId>
<artifactId>boardSystem02</artifactId>
<name>boardSystem02</name>
<packaging>war</packaging>
<version>1.0.0-BUILD-SNAPSHOT</version>
<properties>
<!-- Java, SrpingFramwork 버전 변경 -->
<java-version>11</java-version>
<org.springframework-version>5.2.19.RELEASE</org.springframework-version>
<org.aspectj-version>1.6.10</org.aspectj-version>
<org.slf4j-version>1.6.6</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 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${org.slf4j-version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${org.slf4j-version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${org.slf4j-version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.15</version>
<exclusions>
<exclusion>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
</exclusion>
<exclusion>
<groupId>javax.jms</groupId>
<artifactId>jms</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jdmk</groupId>
<artifactId>jmxtools</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jmx</groupId>
<artifactId>jmxri</artifactId>
</exclusion>
</exclusions>
<scope>runtime</scope>
</dependency>
<!-- @Inject -->
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
<!-- Servlet -->
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</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</version>
<scope>test</scope>
</dependency>
<!-- ★★★ 추가한 것들 -->
<!-- 스프링 관련된 것은 스프링프레임워크 버전이랑 동일. 5.2.19 RELEASE -->
<!-- spring-test -->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.19.RELEASE</version>
<scope>test</scope>
</dependency>
<!-- Spring JDBC -->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.19.RELEASE</version>
</dependency>
<!-- spring tx -->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-tx -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.2.19.RELEASE</version>
</dependency>
<!-- hikariCP :최신버즌 -->
<!-- https://mvnrepository.com/artifact/com.zaxxer/HikariCP -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>5.0.1</version>
</dependency>
<!-- mybatis3.5.5 미리 넣어둘 것. -->
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>
<!-- MyBatis Spring -->
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.7</version>
</dependency>
<!-- Log4Jdbc Log4j2 JDBC 4 1 : 1.16 -->
<!-- https://mvnrepository.com/artifact/org.bgee.log4jdbc-log4j2/log4jdbc-log4j2-jdbc4.1 -->
<dependency>
<groupId>org.bgee.log4jdbc-log4j2</groupId>
<artifactId>log4jdbc-log4j2-jdbc4.1</artifactId>
<version>1.16</version>
</dependency>
<!-- lombok -->
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
<scope>provided</scope>
</dependency>
<!-- End -->
</dependencies>
<build>
<plugins>
<plugin>
<!-- 설치한 버전 Eclipse Enterprise Java and Web Developer Tools 3.24-->
<artifactId>maven-eclipse-plugin</artifactId>
<version>3.24</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>
<!-- maven compiler version 변경 -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.5.1</version>
<configuration>
<source>11</source>
<target>11</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>
(2-2) 설치 확인_pom.xml 입력뿐만 아니라 별도 설치가 필요한 것들
-Spring Tools 4 for Eclipse : 스프링프레임워크 사용을 위해 필요한 프로그램
(레거시 생성 : Spring Tools 3 Add-One for Spring Tools4 3.9.21. RELEASE)
(JSP 생성 : Eclipse Enterprise Java and Web Edveloper Tools 3.24
(exception initialize 오류 / Convert 오류는 [ https://exploreryun.tistory.com/302?category=1004603 ] 참조)
-Java 11 버전
-톰캣 9.0.59 버전
-lombok 1.18.22 버전 설치 후 인스톨
(2-3) ojdbc8 설정
-프로젝트 우클릭 >> Java Build Path & Deployment Assembly >> ojdbc8 추가
(Add External Jars / Archives from file system)
3. 디비(DB) 연결 및 테스트
(3-1) VO 생성
-패키지명 : com.wsy.boardsystem02.domain
-클래스 이름 : BoardVO
package com.wsy.boardsystem00.domain;
import java.util.Date;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data //getter, setter 자동 생성
@NoArgsConstructor // 기본생성자
@AllArgsConstructor // 모든 필드를 매개변수로 가지는 생성자
public class BoardVO {
private int bno;
private String title;
private String content;
private String writer;
private Date regdate;
private Date updatedate;
}
(3-2) MySQL 접속
-MySQL 설치되어 있다는 전제 (*설치하는 방법은 https://exploreryun.tistory.com/301 참고)
-MySQL 설치(집) >> user name : root / pw : 1234
-MySQL Workbench 실행 >> root 접속 >> users and privileges >> Add Account >> limit to Hosts Matching : %(외부에서 접근 가능) >> 비밀번호 : 1234 >> Administrative role : DBA 체크
>> HOME >> my SQL connection (+) 클릭해 접속 계정 추가
>> 생성 계정 접속(이름 바꾸고, 비밀번호 입력, 테스트 성공 후 접속)
(3-3) MySQL 데이터 생성
[ new schemas(드럼통 아이콘) ] >> [ name : springdb / charset : utf8 ] >> [ apply ]
>> 생성한 스키마 더블클릭 >> 테이블 우클릭 : 테이블 생성 >> 이름 : board_tbl
>> column name 입력하고 필요한 거 체크
| CHECK | Default | ||
| bno | INT | PK / NN / AI | |
| title | VARCHAR2(200) | NN | |
| content | VARCHAR2(1000) | NN | |
| writer | VARCHAR2(450) | NN | |
| regdate | DATETIME | now() | |
| updatedate | DATETIME | now() |
(*생성한 테이블에 마우스커서 올리면 수정할 수 있음. 스패너(설정 변경), 테이블(데이터 입력))

└테이블 생성할 때, 열 이름(columns)과 기본 설정해줘야 함. ← 이게 안 보일 때, 겹쳐진 아래 화살표 누르면 나온다.
└더미 데이터 입력
(3-4) MySQL 준비시키기
-maven repository 코드 pom.xml에 입력
mySQL 버전 확인 : programfile(x86) >> mySQL : 버전 8.0.28
(학원에서 설치한 것은 8.0.15로 maven이 그 버전에 맞춰 코드 입력되어 있을 건데...)
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
(3-5) MySQL 연결 - root-context.xml
-폴더 : src / main / webapp / 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 -->
<!-- MySQL -->
<!-- Tip : 일반 클래스에서 자동완성 기능 사용. import의 경로? 가져오면 됨. -->
<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/springdb?useSSL=false&serverTimezone=Asia/Seoul&characterEncoding=UTF-8"/>
<!--스키마 이름-->
<property name="username" value="wsy"/>
<property name="password" value="1234"/>
</bean>
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
<constructor-arg ref="hikariConfig"/>
</bean>
</beans>
(3-6) JDBCTest.java
-패키지 폴더 : com.wsy.boardSystem00.test
MySQL 연결이 됐는지, MySQL에서 입력한 데이터를 제대로 가져오는지 확인
package com.wsy.boardSystem00.test;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.wsy.boardsystem00.domain.BoardVO;
import lombok.extern.log4j.Log4j;
@Log4j //annotation해줘야 junit할 수 있음
@RunWith(SpringJUnit4ClassRunner.class) //자동입력 가능 // 단위 테스트 하겠다.
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml")
public class JDBCTest {
String sql = "SELECT * FROM board_tbl"; //MySQL의 테이블 이름
@Autowired
private DataSource dataSource;
@Test //이거 안 붙여서 junit 에러났던 거임...
public void testMySQLDataSource() {
try {
Connection conn = dataSource.getConnection();
PreparedStatement ps = conn.prepareStatement(sql);
ResultSet rs = ps.executeQuery();
while(rs.next()) {
BoardVO vo = new BoardVO();
vo.setBno(rs.getInt("bno"));
vo.setTitle(rs.getString("title"));
vo.setContent(rs.getNString("content"));
vo.setWriter(rs.getString("writer"));
vo.setRegdate(rs.getDate("regdate"));
vo.setUpdatedate(rs.getDate("updatedate"));
log.info(vo);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
>> junuit 테스트 결과
(src/test/java >> com.wsy.boardsystem00 >> JDBCTest.java >> testMySQLDataSource() 우클릭 junit)
| INFO : org.springframework.test.context.support.DefaultTestContextBootstrapper - Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener, org.springframework.test.context.event.EventPublishingTestExecutionListener] INFO : org.springframework.test.context.support.DefaultTestContextBootstrapper - Using TestExecutionListeners: [org.springframework.test.context.web.ServletTestExecutionListener@26b3fd41, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener@7494f96a, org.springframework.test.context.support.DependencyInjectionTestExecutionListener@561b6512, org.springframework.test.context.support.DirtiesContextTestExecutionListener@2e377400, org.springframework.test.context.transaction.TransactionalTestExecutionListener@1757cd72, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener@445b295b, org.springframework.test.context.event.EventPublishingTestExecutionListener@49e5f737] INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting... INFO : com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@344561e0 INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed. INFO : com.wsy.boardSystem00.JDBCTest - BoardVO(bno=1, title=title01, content=content01, writer=writer01, regdate=2022-03-07, updatedate=2022-03-07) INFO : com.wsy.boardSystem00.JDBCTest - BoardVO(bno=2, title=title02, content=content02, writer=writer02, regdate=2022-03-07, updatedate=2022-03-07) INFO : com.wsy.boardSystem00.JDBCTest - BoardVO(bno=3, title=title03, content=content03, writer=writer03, regdate=2022-03-07, updatedate=2022-03-07) INFO : com.wsy.boardSystem00.JDBCTest - BoardVO(bno=4, title=title04, content=content04, writer=writer04, regdate=2022-03-07, updatedate=2022-03-07) INFO : com.wsy.boardSystem00.JDBCTest - BoardVO(bno=5, title=title05, content=content05, writer=writer05, regdate=2022-03-07, updatedate=2022-03-07) INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown initiated... INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown completed. |
4. MyBatis
쿼리만 입력했을 때, 모든 작업이 되도록 하는 것. testMySQLDataSource의 과정을 축약하는 것.
(기존의 작업은 데이터를 받아와서 ArrayList에 데이터를 담아 리턴하는 번거로운 과정인데 MyBatis를 이용하면 쿼리만 입력했을 때, 모든 작업이 되도록 한다)
(3-1) root-context.xml (src / main / webapp / WEB-INF / spring)
root-context.xml > namespaces > maBatis-spring 체크
<!-- myBatis 사용하기 위해 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
</bean>
<mybatis-spring:scan base-package="com.wsy.boardsystem00.mapper"/>
>> 인터페이스 생성 - mapper
-패키지 : com.wsy.boardsystem00.mapper
-이름 : BoardMapper
쿼리문 작성.
package com.wsy.boardsystem00.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import com.wsy.boardsystem00.domain.BoardVO;
@Mapper
public interface BoardMapper {
@Select("select * from board_tbl where bno > 0")
public List<BoardVO> getList();
}
>> 클래스 생성 - MapperTest
-패키지 폴더 : src/test/java > com.wsy.boardsystem00.test
-이름 : MapperTest
package com.wsy.boardsystem00.test;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.log;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.wsy.boardsystem00.domain.BoardVO;
import com.wsy.boardsystem00.mapper.BoardMapper;
import lombok.extern.log4j.Log4j;
@Log4j
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml")
public class MapperTest {
@Autowired
private BoardMapper mapper;
@Test
public void testGetList() {
List<BoardVO> list = mapper.getList();
for(BoardVO vo : list) {
log.info(vo);
}
}
}
>> junit Run As
| INFO : org.springframework.test.context.support.DefaultTestContextBootstrapper - Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener, org.springframework.test.context.event.EventPublishingTestExecutionListener] INFO : org.springframework.test.context.support.DefaultTestContextBootstrapper - Using TestExecutionListeners: [org.springframework.test.context.web.ServletTestExecutionListener@1190200a, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener@6a2f6f80, org.springframework.test.context.support.DependencyInjectionTestExecutionListener@45b4c3a9, org.springframework.test.context.support.DirtiesContextTestExecutionListener@399c4be1, org.springframework.test.context.transaction.TransactionalTestExecutionListener@291caca8, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener@385e9564, org.springframework.test.context.event.EventPublishingTestExecutionListener@5b94b04d] INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting... INFO : com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@1e53135d INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed. INFO : com.wsy.boardsystem00.MapperTest - BoardVO(bno=1, title=title01, content=content01, writer=writer01, regdate=Mon Mar 07 21:23:00 KST 2022, updatedate=Mon Mar 07 21:23:00 KST 2022) INFO : com.wsy.boardsystem00.MapperTest - BoardVO(bno=2, title=title02, content=content02, writer=writer02, regdate=Mon Mar 07 21:23:00 KST 2022, updatedate=Mon Mar 07 21:23:00 KST 2022) INFO : com.wsy.boardsystem00.MapperTest - BoardVO(bno=3, title=title03, content=content03, writer=writer03, regdate=Mon Mar 07 21:23:00 KST 2022, updatedate=Mon Mar 07 21:23:00 KST 2022) INFO : com.wsy.boardsystem00.MapperTest - BoardVO(bno=4, title=title04, content=content04, writer=writer04, regdate=Mon Mar 07 21:23:00 KST 2022, updatedate=Mon Mar 07 21:23:00 KST 2022) INFO : com.wsy.boardsystem00.MapperTest - BoardVO(bno=5, title=title05, content=content05, writer=writer05, regdate=Mon Mar 07 21:23:00 KST 2022, updatedate=Mon Mar 07 21:23:00 KST 2022) INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown initiated... INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown completed. |
앞으로 계속 함수를 만들어 나갈 건데,
여러 쿼리에서 조건(where) 등을 사용하면 쿼리가 무거워진다. → 쿼리 전문 xml 만들어서 사용
package com.wsy.boardsystem00.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import com.wsy.boardsystem00.domain.BoardVO;
@Mapper
public interface BoardMapper {
@Select("select * from board_tbl where bno > 0")
public List<BoardVO> getList();
//위 함수를 부르면, 위의 쿼리를 가지고 sqlSessionFactory 데이터 접근
//root-context 이동 >> sqlSessionFactory가 dataSource 만듦.
//스캔해서 mapper 자동 만듦.
//데이터 연결 정보 // 디비 접근
//앞으로 만들어야 할 함수 목록
public void insert(BoardVO vo);
public BoardVO getBoard(int bno);
public void update(BoardVO vo);
public void delete(BoardVO vo);
}
<?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"
xsi:schemaLocation="http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!-- Root Context: defines shared resources visible to all other web components -->
<!-- MySQL -->
<!-- Tip : 일반 클래스에서 자동완성 기능 사용. import의 경로? 가져오면 됨. -->
<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/springdb?useSSL=false&serverTimezone=Asia/Seoul&characterEncoding=UTF-8"/>
<property name="username" value="wsy"/>
<property name="password" value="1234"/>
</bean>
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
<constructor-arg ref="hikariConfig"/>
</bean>
<!-- myBatis 사용하기 위해 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
</bean> <!-- sql 자체로 빈들 만들어서 작업하겠다. -->
<!-- sqlSessionFactory는 여기(아래) 경로에 있다. -->
<mybatis-spring:scan base-package="com.wsy.boardsystem00.mapper"/>
<context:component-scan base-package="com.wsy.boardsystem00"/>
</beans>
└코드 간략하게 설명한 것.
(3-2) BoardMapper.xml 파일 생성
-인터페이스 이름과 동일하게
-패키지 위치 : src/main/resources >> (BoardMapper.java 파일에서 패키지 경로 복사) com.wsy.boardsystem00.mapper
-이름 : BoardMapper.xml
-소스 코드 구글링 : mapper.xml >> mybatis >> configuration XML >> (중간보다 살짝 아래에 위치하고 있음)
-인터페이스 BoardMapper.java에서 구현하던 쿼리문을 xml에서 대신. 인터페이스의 쿼리문 비활성(또는 삭제)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- BoardMapper.java에서 경로 복붙 -->
<mapper namespace="com.wsy.boardsystem00.mapper.BoardMapper">
<select id="getList" resultType="com.wsy.boardsystem00.domain.BoardVO">
select * from board_tbl where bno > 0
<!-- BoardMapper.java에서 쿼리문 비활성화 -->
</select>
</mapper>
└(getList) 결과를 resultType에 실음. 데이터가 여러 개 일 때, 자동으로 ArrayList로 넣음.
>> interface BoardMapper.java
package com.wsy.boardsystem00.mapper;
...
@Mapper
public interface BoardMapper {
// @Select("select * from board_tbl where bno > 0")
public List<BoardVO> getList();
//앞으로 계속 함수를 만들어 나갈 건데(아래와 같은 함수들), 쿼리가 무거워질 것. 그래서 쿼리 전용 xml 생성
public void insert(BoardVO vo);
public BoardVO getBoard(int bno);
public void update(BoardVO vo);
public void delete(BoardVO vo);
}
└함수 getList()를 호출하면 리스트 형식으로 받아옴. 받아온 걸 보여주는 게 Service
>> junit Test
(쿼리문을 xml에서 대신하도록 변경. 이때도 디비에 제대로 연결되고 데이터를 제대로 가져오는지 확인)
| INFO : org.springframework.test.context.support.DefaultTestContextBootstrapper - Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener, org.springframework.test.context.event.EventPublishingTestExecutionListener] INFO : org.springframework.test.context.support.DefaultTestContextBootstrapper - Using TestExecutionListeners: [org.springframework.test.context.web.ServletTestExecutionListener@1190200a, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener@6a2f6f80, org.springframework.test.context.support.DependencyInjectionTestExecutionListener@45b4c3a9, org.springframework.test.context.support.DirtiesContextTestExecutionListener@399c4be1, org.springframework.test.context.transaction.TransactionalTestExecutionListener@291caca8, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener@385e9564, org.springframework.test.context.event.EventPublishingTestExecutionListener@5b94b04d] INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting... INFO : com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@610db97e INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed. INFO : com.wsy.boardsystem00.MapperTest - BoardVO(bno=1, title=title01, content=content01, writer=writer01, regdate=Mon Mar 07 21:23:00 KST 2022, updatedate=Mon Mar 07 21:23:00 KST 2022) INFO : com.wsy.boardsystem00.MapperTest - BoardVO(bno=2, title=title02, content=content02, writer=writer02, regdate=Mon Mar 07 21:23:00 KST 2022, updatedate=Mon Mar 07 21:23:00 KST 2022) INFO : com.wsy.boardsystem00.MapperTest - BoardVO(bno=3, title=title03, content=content03, writer=writer03, regdate=Mon Mar 07 21:23:00 KST 2022, updatedate=Mon Mar 07 21:23:00 KST 2022) INFO : com.wsy.boardsystem00.MapperTest - BoardVO(bno=4, title=title04, content=content04, writer=writer04, regdate=Mon Mar 07 21:23:00 KST 2022, updatedate=Mon Mar 07 21:23:00 KST 2022) INFO : com.wsy.boardsystem00.MapperTest - BoardVO(bno=5, title=title05, content=content05, writer=writer05, regdate=Mon Mar 07 21:23:00 KST 2022, updatedate=Mon Mar 07 21:23:00 KST 2022) INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown initiated... INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown completed. |
└데이터 제대로 가져옴
5. CRUD - Create/Read/Update/Delete
(5-1) 게시물 등록 인터페이스/xml 생성 및 테스트
>> 인터페이스 ( com.wsy.boardsystem00.mapper ) BoardMapper.java 함수 수정(또는 구현해야할 것 확인)
package com.wsy.boardsystem00.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import com.wsy.boardsystem00.domain.BoardVO;
@Mapper
public interface BoardMapper {
// @Select("select * from board_tbl where bno > 0")
public List<BoardVO> getList();
//구현해야 할 함수
public void insert(BoardVO vo); //★ turn ★
public BoardVO getBoard(int bno);
public void update(BoardVO vo);
public void delete(BoardVO vo);
}
>> BoardMapper.xml
-패키지 폴더 : src/main/resources > com > wsy > boardsystem00 > mapper : BoardMapper.xml
-insert 쿼리문 입력
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- BoardMapper.java에서 경로 복붙 -->
<mapper namespace="com.wsy.boardsystem00.mapper.BoardMapper">
<select id="getList" resultType="com.wsy.boardsystem00.domain.BoardVO">
select * from board_tbl where bno > 0
<!-- BoardMapper.java에서 쿼리문 비활성화 -->
</select>
<insert id="insert"><!-- 함수 이름 -->
insert into board_tbl(title, content, writer)
values(#{title}, #{content}, #{writer})
<!-- bno 자동 증가, regdate/updatedate는 자동입력 -->
</insert>
</mapper>
>> MapperTest.java
STS에서 입력한 것이 제대로 반영되는지 junit 테스트
package com.wsy.boardsystem00;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.log;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.wsy.boardsystem00.domain.BoardVO;
import com.wsy.boardsystem00.mapper.BoardMapper;
import lombok.extern.log4j.Log4j;
@Log4j
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml")
public class MapperTest {
@Autowired
private BoardMapper mapper;
@Test
public void testGetList() {
List<BoardVO> list = mapper.getList();
for(BoardVO vo : list) {
log.info(vo);
}
}
@Test
public void testInsert() {
//setter
BoardVO vo = new BoardVO();
vo.setTitle("STS_Title_01");
vo.setContent("STS_Content_01");
vo.setWriter("STS_Writer_01");
mapper.insert(vo);
}
}
>> junit Test : testInsert → testGetList
| INFO : org.springframework.test.context.support.DefaultTestContextBootstrapper - Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener, org.springframework.test.context.event.EventPublishingTestExecutionListener] INFO : org.springframework.test.context.support.DefaultTestContextBootstrapper - Using TestExecutionListeners: [org.springframework.test.context.web.ServletTestExecutionListener@1190200a, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener@6a2f6f80, org.springframework.test.context.support.DependencyInjectionTestExecutionListener@45b4c3a9, org.springframework.test.context.support.DirtiesContextTestExecutionListener@399c4be1, org.springframework.test.context.transaction.TransactionalTestExecutionListener@291caca8, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener@385e9564, org.springframework.test.context.event.EventPublishingTestExecutionListener@5b94b04d] INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting... INFO : com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@610db97e INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed. INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown initiated... INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown completed. |
| INFO : org.springframework.test.context.support.DefaultTestContextBootstrapper - Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener, org.springframework.test.context.event.EventPublishingTestExecutionListener] INFO : org.springframework.test.context.support.DefaultTestContextBootstrapper - Using TestExecutionListeners: [org.springframework.test.context.web.ServletTestExecutionListener@1190200a, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener@6a2f6f80, org.springframework.test.context.support.DependencyInjectionTestExecutionListener@45b4c3a9, org.springframework.test.context.support.DirtiesContextTestExecutionListener@399c4be1, org.springframework.test.context.transaction.TransactionalTestExecutionListener@291caca8, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener@385e9564, org.springframework.test.context.event.EventPublishingTestExecutionListener@5b94b04d] INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting... INFO : com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@57a4d5ee INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed. INFO : com.wsy.boardsystem00.MapperTest - BoardVO(bno=1, title=title01, content=content01, writer=writer01, regdate=Mon Mar 07 21:23:00 KST 2022, updatedate=Mon Mar 07 21:23:00 KST 2022) INFO : com.wsy.boardsystem00.MapperTest - BoardVO(bno=2, title=title02, content=content02, writer=writer02, regdate=Mon Mar 07 21:23:00 KST 2022, updatedate=Mon Mar 07 21:23:00 KST 2022) INFO : com.wsy.boardsystem00.MapperTest - BoardVO(bno=3, title=title03, content=content03, writer=writer03, regdate=Mon Mar 07 21:23:00 KST 2022, updatedate=Mon Mar 07 21:23:00 KST 2022) INFO : com.wsy.boardsystem00.MapperTest - BoardVO(bno=4, title=title04, content=content04, writer=writer04, regdate=Mon Mar 07 21:23:00 KST 2022, updatedate=Mon Mar 07 21:23:00 KST 2022) INFO : com.wsy.boardsystem00.MapperTest - BoardVO(bno=5, title=title05, content=content05, writer=writer05, regdate=Mon Mar 07 21:23:00 KST 2022, updatedate=Mon Mar 07 21:23:00 KST 2022) INFO : com.wsy.boardsystem00.MapperTest - BoardVO(bno=6, title=STS_Title_01, content=STS_Content_01, writer=STS_Writer_01, regdate=Mon Mar 07 23:46:23 KST 2022, updatedate=Mon Mar 07 23:46:23 KST 2022) INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown initiated... INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown completed. |
└ STS에서 insert한 것이 제대로 입력되었음을 확인
함수 getList()를 호출하면 리스트 형식으로 데이터를 받아오는데,
데이터는 BoardMapper.xml에서 처리. DB로부터 데이터를 가져와 실어보냄.
가져온 데이터를 보여주는 것이 서비스(Service)
이때, 뒤에서 수정한 것으로 앞의 것이 수정되지 않도록 하는 게 중요한데
그를 위해서 '인터페이스(interface)' 생성해둔다.
(5-2) Service 구현
>> 인터페이스 생성
-위치 : com.wsy.boardsystem00.service
-이름 : BoardSerivce
package com.wsy.boardsystem00.service;
import java.util.List;
import com.wsy.boardsystem00.domain.BoardVO;
public interface BoardSerivce {
List<BoardVO> getList();
}
>> 인터페이스 구현 : 클래스 생성
-위치 : com.wsy.boardsystem00.service
-이름 : BoardSerivceImpl
package com.wsy.boardsystem00.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.wsy.boardsystem00.domain.BoardVO;
import com.wsy.boardsystem00.mapper.BoardMapper;
@Service
public class BoardSerivceImpl implements BoardService {
//root-context.xml에 component 자동 스캔하라고 설정
//<context:component-scan base-package="com.wsy.boardsystem00"/>
@Autowired
BoardMapper boardMapper;
@Override
public List<BoardVO> getList() {
return boardMapper.getList();
}
}
(5-3) Controller 생성
-위치 : com.wsy.boardsystem00.controller
-이름 : BoardController.java
package com.wsy.boardsystem00.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import com.wsy.boardsystem00.domain.BoardVO;
import com.wsy.boardsystem00.service.BoardService;
@Controller //controller임을 명시 //얘때문에 객체 생성됨
@RequestMapping("board/**") //공통 부분 간소화하기 위해
public class BoardController {
//서비스 만드는 법
@Autowired //default 생성자를 통해서 세팅
BoardService boardService; //서비스는 BoardServiceImpl에서 생성됨
//controller class 역할하는 함수
@GetMapping("list") //board 폴더 아래 list.jsp 연결한다는 뜻.
public String list(Model model) {
List<BoardVO> list = boardService.getList();
model.addAttribute("list", list);
return "board/list"; //리턴 타입이 String일 때 사용.
//servlet-context.xml의 viewresolve의 prefix와 suffix에서 경로, 확장자 설정
}
}
(5-4) JSP 페이지 만들기
-위치 : src/main/webapp/WEB-INF / views / board 폴더 생성
-이름 : list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title> List Page </title>
</head>
<body>
<table>
<tr>
<td>번호</td>
<td>제목</td>
<td>작성자</td>
<td>등록일</td>
<td>수정일</td>
</tr>
<!-- items은 model.addAttribute("list", list);의 쌍따옴표의 이름 -->
<c:forEach items="${list }" var="board"> <!-- 가져온 것(list)를 board에 넣음 -->
<tr>
<td>${board.bno }</td>
<!--boardController의 read mapping 이름이 같아야 함. detail -->
<td><a href="/board/detail?bno=${board.bno }">${board.title }</a></td>
<td>${board.writer }</td>
<td>${board.regdate }</td>
<td>${board.updatedate }</td>
</tr>
</c:forEach>
</table>
</body>
</html>
>> list.jsp 제대로 뜨는지 확인하기 위해 실행(Run As)했는데 404 에러
home 화면도 안 뜸....이게 안 뜰 수는 없잖아? 건드린게 없는데?
-BoardMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- BoardMapper.java에서 경로 복붙 -->
<mapper namespace="com.wsy.boardsystem00.mapper.BoardMapper">
<select id="getList" resultType="com.wsy.boardsystem00.domain.BoardVO">
select * from board_tbl where bno > 0
<!-- BoardMapper.java에서 쿼리문 비활성화 -->
</select>
<insert id="insert"><!-- 함수 이름 -->
insert into board_tbl(title, content, writer)
values(#{title}, #{content}, #{writer})
<!-- bno 자동 증가, regdate/updatedate는 자동입력 -->
</insert>
<select id="read" resultType="com.wsy.boardsystem00.domain.BoardVO"> <!--★-->
select * from board_tbl where bno = #{bno}
</select>
<update id="update">
update board_tbl set title = #{title}, content = #{content}, writer = #{writer}, updatedate = #{update}
where bno = #{bno}
</update>
<delete id="delete">
delete from board_tbl where bno = #{bno}
</delete>
</mapper>
└이거 입력해주니까 홈화면이랑 list 전부 제대로 뜸.
(+) 한글 깨짐 처리_home.jsp
web.xml에 코드 복붙
<!--★ 한글 깨짐 방지 처리-->
<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>
<init-param>
<param-name>forceEncoding</param-name> <!--강제로 해라 -->
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping> <!--한글 필터 어디까지 적용할 것인가? -->
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern> <!--루트 아래 전부 -->
</filter-mapping>
6. 부트스트랩 서식 설정
list.jsp 페이지 기준
(6-1) 공통영역 만들기
-샘플 자료의 소스 코드 이용
-header.jsp, footer.jsp 생성 : WEB-INF > views > includes 폴더 생성
<!--header.jsp-->
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<!--부트스트랩 링크-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
<title> HEADER </title>
</head>
<body>
<div class="jumbotron" style="margin-bottom: 0">
<h1>MyBoard</h1>
</div>
<nav class="navbar navbar-expand-sm bg-dark navbar-dark mb-3">
<!-- Brand/logo -->
<a class="navbar-brand" href="/index">HOME</a>
<!-- Links -->
<ul class="navbar-nav mr-auto">
<li class="nav-item"><a class="nav-link" href="/board/list">Board</a></li>
<li class="nav-item"><a class="nav-link" href="#"> FILE</a></li>
<li class="nav-item"><a class="nav-link" href="#"> FILEBOARD</a></li>
</ul>
<ul class="navbar-nav">
<li class="nav-item"><a class="nav-link" href="#">로그인</a></li>
<li class="nav-item"><a class="nav-link" href="#">회원가입</a></li>
</ul>
</nav>
</body>
</html>
<!--footer.jsp-->
(6-2) list.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="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ include file="../includes/header.jsp" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title> List Page </title>
</head>
<body>
<h2>BoardList(10)</h2>
<div class="form-group text-right">
<button type="button" class="btn btn-secondary btn-sm" id="btnWrite">글쓰기</button>
</div>
<table class="table table-hover">
<thead>
<tr>
<th>번호</th>
<th>작성자</th>
<th>제목</th>
<th>작성일시</th>
<th>조회수</th>
</tr>
</thead>
<tbody>
<!-- items은 model.addAttribute("list", list);의 쌍따옴표의 이름 -->
<c:forEach items="${list }" var="board">
<!-- 가져온 것(list)를 board에 넣음 -->
<tr>
<td>${board.bno }</td>
<!--boardController의 read mapping 이름이 같아야 함. detail -->
<td><a href="/board/detail?bno=${board.bno }">${board.title }</a></td>
<td>${board.writer }</td>
<td><fmt:formatDate value="${board.regdate }"/></td>
<td>${board.updatedate }</td>
</tr>
</c:forEach>
</tbody>
</table>
<div class="d-flex justify-content-between mt-3">
<ul class="pagination">
<!-- 이전 -->
<li class="page-item"><a class="page-link" href="#">Previous</a></li>
<!--페이지 리스트-->
<li class="page-item"><a class="page-link" href="#">1</a></li>
<li class="page-item"><a class="page-link" href="#">2</a></li>
<li class="page-item"><a class="page-link" href="#">3</a></li>
<li class="page-item"><a class="page-link" href="#">4</a></li>
<li class="page-item"><a class="page-link" href="#">5</a></li>
<li class="page-item"><a class="page-link" href="#">6</a></li>
<li class="page-item"><a class="page-link" href="#">7</a></li>
<li class="page-item"><a class="page-link" href="#">8</a></li>
<li class="page-item"><a class="page-link" href="#">9</a></li>
<li class="page-item"><a class="page-link" href="#">10</a></li>
<!-- 다음 -->
<li class="page-item"><a class="page-link" href="#">Next</a></li>
</ul>
<form class="form-inline" action="#" id="searchFrm">
<select name="field" class="form-control mb-2 mr-sm-2">
<option value="writer">작성자</option>
<option value="title">제목</option>
</select> <input type="text" class="form-control mb-2 mr-sm-2"
placeholder="Enter Search" name="word">
<button type="submit" class="btn btn-secondary mb-2 btn-sm">Search</button>
</form>
</div>
</body>
</html>
<%@ include file="../includes/footer.jsp" %>
(6-3) detail.jsp 수정
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file="../includes/header.jsp" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title> Read page </title>
</head>
<body>
<div class="container">
<h2>user00 글보기</h2>
<div class="form-group">
<label for="num">글번호</label>
<input type="text" class="form-control" id="num" name="bno" value="${board.bno }" readonly="readonly">
</div>
<div class="form-group">
<label for="title">제목</label>
<input type="text" class="form-control" id="title" name="title" value="${board.title }" readonly="readonly">
</div>
<div class="form-group">
<label for="writer">등록일</label>
<input type="text" class="form-control" id="writer"name="regdate" value="${board.regdate }" readonly="readonly">
</div>
<div class="form-group">
<label for="writer">수정일</label>
<input type="text" class="form-control" id="writer"name="updatedate" value="${board.updatedate }" readonly="readonly">
</div>
<div class="form-group">
<label for="writer">조회수</label>
<input type="text" class="form-control" id="writer"name="readCount" value="user00" readonly="readonly">
</div>
<div class="form-group">
<label for="content">내용</label>
<textarea class="form-control" rows="5" id="content" name="content" readonly="readonly">${board.content }</textarea>
</div>
<div class="form-group text-right">
<button type="button" class="btn btn-secondary btn-sm" id="btnUpdate">수정하기</button>
<button type="button" class="btn btn-secondary btn-sm" id="btnDelete">삭제하기</button>
</div>
<div class="container mt-5">
<div class="form-group">
<label for="comment">Comment:</label>
<textarea class="form-control" rows="5" id="msg" name="text"></textarea>
</div>
<button type="button" class="btn btn-success" id="commentBtn">Comment Write</button>
</div>
<div id="replyResult">댓글 리스트 영역 </div>
</div>
</body>
</html>
<%@ include file="../includes/footer.jsp" %>
>> 프로젝트 실행했을 때,
board/list 입력했을때 제대로 화면이 출력되는지 확인
글을 눌렀을 때, 상세보기로 이동하는지 확인
→ OK
7. index 페이지 만들기
(7-1) index.jsp 만들기
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file="includes/header.jsp" %> <!-- 인덱스 위치 경로 주의 -->
<div class="container">
<!-- Carousel -->
<div id="carouselExampleControls" class="carousel slide container mt-4" data-ride="carousel">
<div class="carousel-inner">
<div class="carousel-item active">
<img src="resources/images/image1.jpg" width="400" height="500" class="d-block w-100">
</div>
<div class="carousel-item">
<img src="resources/images/image2.jpg" width="400" height="500" class="d-block w-100">
</div>
<div class="carousel-item">
<img src="resources/images/image3.jpg" width="400" height="500" class="d-block w-100">
</div>
<div class="carousel-item">
<img src="resources/images/image4.jpg"width="400" height="500" class="d-block w-100">
</div>
</div>
<a class="carousel-control-prev" href="#carouselExampleControls" role="button" data-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="sr-only">Previous</span>
</a>
<a class="carousel-control-next" href="#carouselExampleControls" role="button" data-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="sr-only">Next</span>
</a>
</div>
<!-- end of Carousel -->
<div class="container text-center mt-5">
<div class="row">
<div class="col-lg-4">
<img src="resources/images/image1.jpg" width="140" height="140" class="rounded-circle">
<h2>Heading</h2>
<p>Some representative placeholder content for the three columns of text below the carousel. This is the first column.</p>
<p><a class="btn btn-secondary" href="#">View details »</a></p>
</div><!-- /.col-lg-4 -->
<div class="col-lg-4">
<img src="resources/images/image2.jpg" width="140" height="140" class="rounded-circle">
<h2>Heading</h2>
<p>Another exciting bit of representative placeholder content. This time, we've moved on to the second column.</p>
<p><a class="btn btn-secondary" href="#">View details »</a></p>
</div><!-- /.col-lg-4 -->
<div class="col-lg-4">
<img src="resources/images/image3.jpg" width="140" height="140" class="rounded-circle">
<h2>Heading</h2>
<p>And lastly this, the third column of representative placeholder content.</p>
<p><a class="btn btn-secondary" href="#">View details »</a></p>
</div><!-- /.col-lg-4 -->
</div><!-- /.row -->
</div>
<div class="container mt-5">
<!-- Card Deck -->
<div class="card-deck">
<div class="card">
<img src="resources/images/image1.jpg" class="card-img-top">
<div class="card-body">
<h5 class="card-title">Card title</h5>
<p class="card-text">This is a longer card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.</p>
<p class="card-text"><small class="text-muted">Last updated 3 mins ago</small></p>
</div>
</div>
<div class="card">
<img src="resources/images/image2.jpg" class="card-img-top">
<div class="card-body">
<h5 class="card-title">Card title</h5>
<p class="card-text">This card has supporting text below as a natural lead-in to additional content.</p>
<p class="card-text"><small class="text-muted">Last updated 3 mins ago</small></p>
</div>
</div>
<div class="card">
<img src="resources/images/image3.jpg" class="card-img-top">
<div class="card-body">
<h5 class="card-title">Card title</h5>
<p class="card-text">This is a wider card with supporting text below as a natural lead-in to additional content. This card has even longer content than the first to show that equal height action.</p>
<p class="card-text"><small class="text-muted">Last updated 3 mins ago</small></p>
</div>
</div>
</div>
<!-- end of Card Deck -->
</div>
<!-- Jumbotron -->
<div class="jumbotron container mt-5">
<h1 class="image-4">Hello, world!</h1>
<p class="lead">This is a simple hero unit, a simple jumbotron-style component for calling extra attention to featured content or information.</p>
<hr class="my-4">
<p>It uses utility classes for typography and spacing to space content out within the larger container.</p>
<a class="btn btn-primary btn-lg" href="#" role="button">Learn more</a>
</div>
<!-- end of Jumbotron -->
</div>
<%@ include file="includes/footer.jsp" %><!-- 인덱스 위치 경로 주의 -->
(7-2) index 연결 수정
-위치 : com.wsy.boardsystem00 > HomeContoller.java
((하는 중))
8. 글 등록
(8-1) BoardController.jsp 수정
package com.wsy.boardsystem00.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.wsy.boardsystem00.domain.BoardVO;
import com.wsy.boardsystem00.service.BoardService;
@Controller //controller임을 명시 //얘때문에 객체 생성됨
@RequestMapping("/board/**") //공통 부분 간소화하기 위해
public class BoardController {
//서비스 만드는 법
@Autowired //default 생성자를 통해서 세팅
BoardService boardService; //서비스는 BoardServiceImpl에서 생성됨
//controller class 역할하는 함수
@GetMapping("list")
public String list(Model model) {
List<BoardVO> list = boardService.getList();
model.addAttribute("list", list);
return "board/list"; //리턴 타입이 String일 때 사용.
//servlet-context.xml의 viewresolve의 prefix와 suffix에서 경로, 확장자 설정
}
@GetMapping("detail")
public String read(@RequestParam("bno") int bno, Model model) {
model.addAttribute("board", boardService.read(bno));
return "board/detail";
}
//글 등록 ★★
@GetMapping("register") //board 폴더 밑에 register.jsp가 있어야 함.
public void register() {
}
}
(8-2) register.jsp 생성
샘플 코드에서 복붙하고 내용 일부 수정
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file="../includes/header.jsp"%>
<!-- controller -->
<div class="container">
<h2>글쓰기</h2>
<form action="insert" method="post">
<div class="form-group">
<label for="title">제목:</label>
<input type="text" class="form-control" id="title" placeholder="Enter title" name="title">
</div>
<div class="form-group">
<label for="writer">작성자:</label>
<input type="text" class="form-control" id="writer" name="writer">
</div>
<div class="form-group">
<label for="content">내용:</label>
<textarea class="form-control" rows="5" id="content" name="content"></textarea>
</div>
<button type="submit" class="btn btn-primary btn-sm">Submit</button>
</form>
</div>
<%@ include file="../includes/footer.jsp"%>
8. 링크 연결 수정
글 입력 / 리스트 / 상세 보기 한 사이클이 제대로 도는지 확인
(5-2) 만들어야 할 함수와 쿼리 미리 작성
>> 인터페이스 BoardMapper.java_앞선 것과 수정된 것 없지만..적어둠
package com.wsy.boardsystem00.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import com.wsy.boardsystem00.domain.BoardVO;
@Mapper
public interface BoardMapper {
// @Select("select * from board_tbl where bno > 0")
public List<BoardVO> getList();
//앞으로 계속 함수를 만들어 나갈 건데(아래와 같은 함수들), 쿼리가 무거워질 것. 그래서 쿼리 전용 xml 생성
public void insert(BoardVO vo);
public BoardVO getBoard(int bno);
public void update(BoardVO vo);
public void delete(BoardVO vo);
//나중에 할 것
// public void insertSelectKey(BoardVO vo);
}
└게시물 저장할 때, 앞의 것보다 증가해서 게시물 번호 설정하는데 게시물 번호를 미리 땡겨서 써야할 때.
>> XML BoardMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- BoardMapper.java에서 경로 복붙 -->
<mapper namespace="com.wsy.boardsystem00.mapper.BoardMapper">
<select id="getList" resultType="com.wsy.boardsystem00.domain.BoardVO">
select * from board_tbl where bno > 0
<!-- BoardMapper.java에서 쿼리문 비활성화 -->
</select>
<insert id="insert"><!-- 함수 이름 -->
insert into board_tbl(title, content, writer)
values(#{title}, #{content}, #{writer})
<!-- bno 자동 증가, regdate/updatedate는 자동입력 -->
</insert>
<select id="read" resultType="">
select * from board_tbl where bno = #{bno}
</select>
<update id="update">
update board_tbl set title = #{title}, content = #{content}, writer = #{writer}, updatedate = #{update}
where bno = #{bno}
</update>
<delete id="delete">
delete from board_tbl where bno = #{bno}
</delete>
</mapper>
END
- 2022.03.08 -
resultType=""이걸 안 채워줘서 오류로 인식하고
Home 자체가 뜨지 않았던 것!
→ 수정 후 완료
home jsp가 404에러뜨는 건 왜지?
건드린 게 없는데??
'수업 > └Spring Framework' 카테고리의 다른 글
| [06]AOP와 트랜잭션(수정)+게시판 댓글 트랜잭션 (0) | 2022.03.11 |
|---|---|
| [05]REST & Ajax_개념 (0) | 2022.03.10 |
| [04]웹 게시판(CRUD)_1차 (0) | 2022.03.04 |
| [03_2]Spring MVC - Legacy Project (0) | 2022.03.03 |
| [03_1]Spring MVC - Maven Project_실습 (0) | 2022.03.03 |
- Total
- Today
- Yesterday
- A%B
- input type 종류
- text formatting
- 기본선택자
- empty-cell
- scanner
- Java
- CascadingStyleSheet
- html pre
- html atrribute
- html a tag
- 외부구성요소
- html base tag
- ScriptTag
- selcetor
- html input type
- initialized
- 입력양식
- caption-side
- html layout
- JavaScript
- typeof
- 미디어 태그
- html
- css
- 스크립태그
- BAEKJOON
- improt
- 변수
- border-spacing
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | ||||
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| 18 | 19 | 20 | 21 | 22 | 23 | 24 |
| 25 | 26 | 27 | 28 | 29 | 30 | 31 |