Last Modified 2025.6.21
간단한 Spring MyBatis 예제
sqlplus scott/tiger
create table music ( no number, content varchar2(4000), constraint PK_MTV PRIMARY KEY(no) ); create sequence SEQ_MUSIC increment by 1 start with 1;
mybatismusic
├── pom.xml
└── src
    └── main
        ├── java
        │   └── net
        │       └── java_school
        │           ├── mybatis
        │           │   └── MusicVideoMapper.java
        │           └── mybatismusic
        │               ├── HomeController.java
        │               ├── MusicVideo.java
        │               ├── MusicVideoService.java
        │               └── MusicVideoServiceImpl.java
        ├── resources
        │   ├── commons-logging.properties
        │   ├── log4j2.xml
        │   └── net
        │       └── java_school
        │           └── mybatis
        │               ├── Configuration.xml
        │               └── MusicVideoMapper.xml
        └── webapp
            ├── WEB-INF
            │   ├── applicationContext.xml
            │   ├── mybatismusic-servlet.xml
            │   ├── views
            │   │   └── index.jsp
            │   └── web.xml
            └── resources
                └── js
                    └── jquery.js
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 
	http://maven.apache.org/xsd/maven-4.0.0.xsd">
	
<modelVersion>4.0.0</modelVersion>
<groupId>net.java_school</groupId>
<artifactId>mybatismusic</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>mybatismusic Maven Webapp</name>
<url>http://localhost:8080</url>
<properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <maven.compiler.source>21</maven.compiler.source>
  <maven.compiler.target>21</maven.compiler.target>
  <spring.version>6.2.8</spring.version>
</properties>
<dependencies>
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
    <scope>test</scope>
  </dependency>
  <!-- https://mvnrepository.com/artifact/jakarta.servlet/jakarta.servlet-api -->
  <dependency>
    <groupId>jakarta.servlet</groupId>
    <artifactId>jakarta.servlet-api</artifactId>
    <version>6.1.0</version>
    <scope>provided</scope>
  </dependency>       
  <!-- https://mvnrepository.com/artifact/jakarta.servlet.jsp.jstl/jakarta.servlet.jsp.jstl-api -->
  <dependency>
    <groupId>jakarta.servlet.jsp.jstl</groupId>
    <artifactId>jakarta.servlet.jsp.jstl-api</artifactId>
    <version>3.0.2</version>
  </dependency>
  <!-- https://mvnrepository.com/artifact/org.glassfish.web/jakarta.servlet.jsp.jstl -->
  <dependency>
    <groupId>org.glassfish.web</groupId>
    <artifactId>jakarta.servlet.jsp.jstl</artifactId>
    <version>3.0.1</version>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>${spring.version}</version>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>${spring.version}</version>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>${spring.version}</version>
  </dependency>
  <!-- https://mvnrepository.com/artifact/com.oracle.database.jdbc/ojdbc11 -->
  <dependency>
    <groupId>com.oracle.database.jdbc</groupId>
    <artifactId>ojdbc11</artifactId>
    <version>23.7.0.25.01</version>
  </dependency>
  <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
  <dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.19</version>
  </dependency>
  <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
  <dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>3.0.4</version>
  </dependency>
  <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-dbcp2 -->
  <dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-dbcp2</artifactId>
    <version>2.13.0</version>
  </dependency>
  <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-api -->
  <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.24.3</version>
  </dependency>
  <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
  <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.24.3</version>
  </dependency>
  <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-jcl -->
  <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-jcl</artifactId>
    <version>2.24.3</version>
  </dependency>
</dependencies>
<build>
  <finalName>mybatismusic</finalName>
  <pluginManagement>
    <plugins>
      <plugin>
        <artifactId>maven-clean-plugin</artifactId>
        <version>3.1.0</version>
        <configuration>
          <filesets>
             <fileset>
                <directory>src/main/webapp/WEB-INF/classes</directory>
             </fileset>
             <fileset>
                <directory>src/main/webapp/WEB-INF/lib</directory>
             </fileset>
          </filesets>
        </configuration>
      </plugin>
      <plugin>
        <artifactId>maven-resources-plugin</artifactId>
        <version>3.0.2</version>
      </plugin>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.0</version>
      </plugin>
      <plugin>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.22.1</version>
      </plugin>
      <plugin>
        <artifactId>maven-war-plugin</artifactId>
        <version>3.2.2</version>
      </plugin>
      <plugin>
        <artifactId>maven-install-plugin</artifactId>
        <version>2.5.2</version>
      </plugin>
      <plugin>
        <artifactId>maven-deploy-plugin</artifactId>
        <version>2.8.2</version>
      </plugin>
      <!-- https://mvnrepository.com/artifact/org.eclipse.jetty/jetty-maven-plugin -->
      <plugin>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-maven-plugin</artifactId>
        <version>11.0.25</version>
      </plugin>
    </plugins>
  </pluginManagement>
</build>
</project>
src/main/resources
commons-logging.properties
org.apache.commons.logging.Log = org.apache.commons.logging.impl.Log4JLogger
log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration>
<Configuration>
    <Appenders>
        <File name="MyBatisMusic" fileName="/var/log/tomcat9/MyBatisMusic.log" append="false">
            <PatternLayout pattern="%t %-5p %c{2} - %m%n" />
        </File>
        <Console name="STDOUT" target="SYSTEM_OUT">
            <PatternLayout pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n" />
        </Console>
    </Appenders>
    <Loggers>
        <Logger name="net.java_school" level="DEBUG">
            <AppenderRef ref="MyBatisMusic" />
        </Logger>
        <Root level="INFO">
            <AppenderRef ref="STDOUT" />
        </Root>
    </Loggers>
</Configuration>
src/main/resources/net/java_school/mybatis
Configuration.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <settings> <setting name="logImpl" value="LOG4J2"/> </settings> <typeAliases> <typeAlias type="net.java_school.mybatismusic.MusicVideo" alias="MusicVideo" /> </typeAliases> </configuration>
MusicVideoMapper.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">
<mapper namespace="net.java_school.mybatis.MusicVideoMapper">
    <select id="selectCountOfVideos" resultType="int">
        SELECT count(*) FROM music 
    </select>
    <select id="selectVideos" parameterType="hashmap" resultType="MusicVideo">
        SELECT content 
        FROM (
            SELECT rownum R,A.* 
            FROM (
                SELECT 
                    content
                FROM 
                    music
                ORDER BY no DESC
                 ) A
             )
        WHERE R BETWEEN #{start} AND #{end}
    </select>	
    <insert id="insert">
	    insert into music values (seq_music.nextval, #{content})
    </insert>
	
</mapper>
src/main/java/net/java_school/mybatis
MusicVideoMapper.java
package net.java_school.mybatis;
import java.util.HashMap;
import java.util.List;
import net.java_school.mybatismusic.MusicVideo;
import org.apache.ibatis.annotations.Param;
public interface MusicVideoMapper {
	public int selectCountOfVideos();
	public List<MusicVideo> selectVideos(HashMap<String, String> hashmap);
	public void insert(@Param("content") String content);
}
src/main/java/net/java_school/mybatismusic
MusicVideo.java
package net.java_school.mybatismusic;
public class MusicVideo {
	private int no;
	private String content;
	public MusicVideo() {}
	public MusicVideo(int no, String content) {
		this.no = no;
		this.content = content;
	}
	public int getNo() {
	       return no;
	}
	public void setNo(int no) {
		this.no = no;
	}
	public String getContent() {
		return content;
	}
	public void setContent(String content) {
		this.content = content;
	}
}	
MusicVideoService.java
package net.java_school.mybatismusic;
import java.util.List;
public interface MusicVideoService {
	
	public int getTotalRecords();
	public List<MusicVideo> getVideos(Integer startRecord, Integer endRecord);
	public void add(String content);
}
MusicVideoServiceImpl.java
package net.java_school.mybatismusic;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.HashMap;
import net.java_school.mybatis.MusicVideoMapper;
@Service
public class MusicVideoServiceImpl implements MusicVideoService {
	@Autowired
	private MusicVideoMapper musicVideoMapper;
	@Override
	public int getTotalRecords() {
		return musicVideoMapper.selectCountOfVideos();
	}
	@Override
	public List<MusicVideo> getVideos(Integer startRecord, Integer endRecord) {
		HashMap<String, String> hashmap = new HashMap<String, String>();
		hashmap.put("start", startRecord.toString());
		hashmap.put("end", endRecord.toString());
		return musicVideoMapper.selectVideos(hashmap);
	}
	@Override
	public void add(String content) {
		musicVideoMapper.insert(content);
	}
}
HomeController.java
package net.java_school.mybatismusic;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
@Controller
public class HomeController {
	@Autowired
	private MusicVideoService musicVideoService;
	private Map<String, Integer> getNumbersForPaging(int totalRecord, 
			int page, int numPerPage, int pagePerBlock) {
		Map<String, Integer> map = new HashMap<String, Integer>();
		int totalPage = totalRecord / numPerPage;
		if (totalRecord % numPerPage != 0) totalPage++;
		int totalBlock = totalPage / pagePerBlock;
		if (totalPage % pagePerBlock != 0) totalBlock++;
		int block = page / pagePerBlock;
		if (page % pagePerBlock != 0) block++;
		int firstPage = (block - 1) * pagePerBlock + 1;
		int lastPage = block * pagePerBlock;
		int prevPage = 0;
		if (block > 1) prevPage = firstPage - 1;
		int nextPage = 0;
		if (block < totalBlock) nextPage = lastPage + 1;
		if (block >= totalBlock) lastPage = totalPage;
		
		int listItemNo = totalRecord - (page - 1) * numPerPage;
		int startRecord = (page - 1) * numPerPage + 1;
		int endRecord = page * numPerPage;
		map.put("totalPage", totalPage);
		map.put("firstPage", firstPage);
		map.put("lastPage", lastPage);
		map.put("prevPage", prevPage);
		map.put("nextPage", nextPage);
		map.put("startRecord", startRecord);
		map.put("endRecord", endRecord);
		return map;
	}
	@GetMapping("/")
	public String index(@RequestParam(name="page", required=false) Integer page, Model model) {
		if (page == null) return "redirect:/?page=1";
		int numPerPage = 4;
		int pagePerBlock = 50;
		int totalRecord = musicVideoService.getTotalRecords();
		Map<String, Integer> map = getNumbersForPaging(totalRecord, page, numPerPage, pagePerBlock);
		Integer startRecord = map.get("startRecord");
		Integer endRecord = map.get("endRecord");
		List<MusicVideo> list = musicVideoService.getVideos(startRecord, endRecord);
		Integer prevPage = map.get("prevPage");
		Integer nextPage = map.get("nextPage");
		Integer firstPage = map.get("firstPage");
		Integer lastPage = map.get("lastPage");
		Integer totalPage = map.get("totalPage");
		model.addAttribute("list", list);
		model.addAttribute("prevPage", prevPage);
		model.addAttribute("nextPage", nextPage);
		model.addAttribute("firstPage", firstPage);
		model.addAttribute("lastPage", lastPage);
		model.addAttribute("totalPage", totalPage);
		return "index";
	}
	@PostMapping("/")
	@ResponseBody
	public void add(@RequestParam(name="content") String content) {
		musicVideoService.add(content);	
	}
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
                      https://jakarta.ee/xml/ns/jakartaee/web-app_6_1.xsd"
  version="6.1"
  metadata-complete="true">
<display-name>MyBatis Music</display-name>
<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<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>
<servlet>
	<servlet-name>mybatismusic</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
	<servlet-name>mybatismusic</servlet-name>
	<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
mybatismusic-servlet.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" xmlns:mybatis="http://mybatis.org/schema/mybatis-spring" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring.xsd"> <mvc:resources location="/resources/" mapping="/resources/**" /> <mvc:annotation-driven /> <context:component-scan base-package="net.java_school.mybatismusic" /> <mybatis:scan base-package="net.java_school.mybatis" /> <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" /> <property name="prefix" value="/WEB-INF/views/" /> <property name="suffix" value=".jsp" /> </bean> </beans>
applicationContext.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:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" /> <property name="url" value="jdbc:oracle:thin:@localhost:1521:XE" /> <property name="username" value="scott" /> <property name="password" value="tiger" /> <property name="maxTotal" value="100" /> <property name="maxWaitMillis" value="1000" /> <property name="poolPreparedStatements" value="true" /> <property name="defaultAutoCommit" value="true" /> <property name="validationQuery" value=" SELECT 1 FROM DUAL" /> </bean> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="configLocation" value="classpath:net/java_school/mybatis/Configuration.xml" /> </bean> </beans>
src/main/webapp/WEB-INF/views
index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>MyBatis Music</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="Keywords" content="MyBatis Music App Test" />
<meta name="Description" content="This is test web app for MyBatis Music Video" />
<style>
html, body {
	margin: 0;
	padding: 0;
	background-color: #FFF;
	font-family: "Liberation Sans", Helvetica, sans-serif;
}
#videos .iframe {
	float: left;
}
#paging {
	width: 640px;
	float: left;
	font-size: 1em;
}
form {
	display: flex;
}
textarea {
	display: inline-block;
	width: 85%;
	resize: none;
}
#submit {
	display: inline-block;
	width: 10%;
	margin-bottom: -10px;
}
</style>
<script src="resources/js/jquery.js"></script>
<script>
$(document).ready(function() {
	$("#addForm").submit(function (event) {
		event.preventDefault();
		var $form = $(this);
		var content = $('#addForm-ta').val();
		content = $.trim(content);
		if (content.length === 0) {
			$('#addForm-ta').val('');
			return false;
		}
		var dataToBeSent = $form.serialize();
		var url = $form.attr("action");
		var posting = $.post(url, dataToBeSent);
		posting.done(function () {
			$('#addForm-ta').val('');
		});
	});    
	var originWidth = $('#videos > iframe').width();
	var originHeight = $('#videos > iframe').height();
	var width = $('#paging').width();
	var height = originHeight * width / originWidth;
	$('#videos > iframe').attr('width', width);
	$('#videos > iframe').attr('height', height);
	$('#videos > iframe').attr('allowFullScreen', '');
});
</script>
</head>
<body>
	<div id="videos">
		<c:forEach var="video" items="${list }" varStatus="status">
		${video.content }
		</c:forEach>
	</div>
	<div id="paging">
		<c:if test="${prevPage > 0}">
		<a href="?page=1" title="1">[First]</a>
		<a href="?page=${prevPage }" title="${prevPage }">[Prev]</a>
		</c:if>
		<c:forEach var="i" begin="${firstPage }" end="${lastPage }" varStatus="status">
		<c:choose>
			<c:when test="${param.page == i}">
			<strong>${i }</strong>
			</c:when>
			<c:otherwise>
			<a href="?page=${i }" title="${i }">${i }</a>
			</c:otherwise>
		</c:choose>
		</c:forEach>
		<c:if test="${nextPage > 0 }">
		<a href="?page=${nextPage }" title="${nextPage }">[Next]</a>
		<a href="?page=${totalPage }" title="${totalPage }">[Last]</a>
		</c:if>
		<form id="addForm" action="./">
			<textarea id="addForm-ta" name="content" cols="30" rows="1"></textarea>
			<input id="submit" type="submit" value="Send" /> 
		</form>
	</div>
</body>
</html>
https://jquery.com/download/
src/main/webapp/resources/js/jquery.js
실행
mvn jetty:run
https://github.com/kimjonghoon/mybatismusic
