我们将通过几个实例来学习 MyBatis 的用法,提供的例子中不仅仅只有MyBatis 部分的代码,还包含Service、Controller、JSP 的代码。
这一节会通过一整套的代码来演示MyBatis在项目开发中的基本用法。按照自下而上的顺序进行开发,从Mapper开始,依次开发 Service 层、Controller 层、JSP 前端页面。在实际开发过程中,可能会根据每一层的需求对各层接口进行调整。
基本准备
在开始之前需要先准备数据库、表和数据,配置的数据源连接的仍是本地的 mybatis数据库,这一节会新增一个字典表,然后针对这个字典表进行增、删、改、查4类操作。字典表的建表语句和基础数据的SQL如下。
drop table if exists n_sysdict;
create table n_sysdict(
id int not null auto_increment,
code varchar(64) not null comment '类型',
name varchar(64) not null comment '字典名',
value varchar(64) not null comment '字典值',
primary key(id)
) comment '字典表';
insert into n_sysdict values (1,'性别','男','女');
insert into n_sysdict values (2,'性别','女','女');
insert into n_sysdict values (3,'季度','第一季度','1');
insert into n_sysdict values (4,'季度','第二季度','2');
insert into n_sysdict values (5,'季度','第三季度','3');
insert into n_sysdict values (6,'季度','第四季度','4');
项目情况截图
导入依赖
<?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>com.shrimpking</groupId>
<artifactId>mybatis-04</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 清单管理 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>4.3.10.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- spring上下文,核心 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<!-- jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<!-- spring事务 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<!-- spring面向切面 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</dependency>
<!-- aop依赖 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.5</version>
</dependency>
<!-- spring web 核心 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<!-- spring mvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
<!-- spring mvc-json依赖 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.4</version>
</dependency>
<!-- -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.1</version>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!-- jstl模板 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
</dependencies>
</project>
实体类
在src/main/java中新建tcom.shrimpking.pojo包,然后新建SysDict实体类。
SysDict.java
package com.shrimpking.pojo;
import java.io.Serializable;
/**
* Created by IntelliJ IDEA.
*
* @Author : Shrimpking
* @create 2023/6/12 15:32
*/
public class SysDict implements Serializable
{
/**
* 可序列化
*/
private static final long serialVersionUID=1L;
private Integer id;
private String code;
private String name;
private String value;
public SysDict()
{
}
public SysDict(Integer id, String code, String name, String value)
{
this.id = id;
this.code = code;
this.name = name;
this.value = value;
}
public Integer getId()
{
return id;
}
public void setId(Integer id)
{
this.id = id;
}
public String getCode()
{
return code;
}
public void setCode(String code)
{
this.code = code;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getValue()
{
return value;
}
public void setValue(String value)
{
this.value = value;
}
@Override
public String toString()
{
return "SysDict{" + "id=" + id + ", code='" + code + '\'' + ", name='" + name + '\'' + ", value='" + value + '\'' + '}';
}
}
开发Mapper层(Dao层)
Mapper层也就是常说的数据访问层(Dao 层)。使用Mapper接口和XML映射文件结合的方式进行开发,集成 MyBatis 的配置中,自动扫描接口的包名为 com.shrimpking.mapper,因此在创建Mapper接口所在的包时也要参照这个命名规则。
在src/main/java中新建com.shrimpking.mapper包,然后新建SysDictMapper接口。
SysDictMapper.java
package com.shrimpking.mapper;
import com.shrimpking.pojo.SysDict;
import org.apache.ibatis.session.RowBounds;
import java.util.List;
/**
* Created by IntelliJ IDEA.
*
* @Author : Shrimpking
* @create 2023/6/12 15:37
*/
public interface SysDictMapper
{
/**
* 通过id查询
* @param id
* @return
*/
SysDict selectById(Integer id);
/**
* 通过条件查询多个
* @param sysDict
* @return
*/
List<SysDict> selectList(SysDict sysDict, RowBounds rowBounds);
/**
* 新增
* @param sysDict
* @return
*/
int insert(SysDict sysDict);
/**
* 修改
* @param sysDict
* @return
*/
int updateById(SysDict sysDict);
/**
* 删除
* @param id
* @return
*/
int deleteById(Integer id);
}
同时,SqlSessionFactoryBean 中也配置了扫描 XML 映射文件的目录。
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:context="http://www.springframework.org/schema/context"
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">
<context:component-scan base-package="com.shrimpking.service.impl"/>
<bean id="dataSource" class="org.apache.ibatis.datasource.pooled.PooledDataSource">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimeZone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="mysql123"/>
</bean>
<import resource="mybatis-servlet.xml"/>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="dataSource" ref="dataSource"/>
<property name="mapperLocations">
<array>
<value>classpath:com/shrimpking/mapper/*.xml</value>
</array>
</property>
<property name="typeAliasesPackage" value="com.shrimpking.pojo"/>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.shrimpking.mapper"/>
</bean>
</beans>
在src/main/resources中新建com/shrimpking/mapper/目录,然后新建SysDictMapper.xml文件。
首先,当需要查看或修改某个具体的字典信息时,要有一个通过主键获取字典信息的方法,在Mapper接口和对应的XML中分别添加如下代码。
SqlSessionFactoryBean 时,将 typeAliasesPackage 配置为com.shrimpking.pojo,所以这里设置resultType时可以直接使用类名,省略包名。
以下代码依次是根据字典参数和分页参数查询字典信息的方法,新增、更新、删除字典的接口的方法。
SysDictMapper.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="com.shrimpking.mapper.SysDictMapper">
<!-- 通过id查询 -->
<select id="selectById" resultType="sysDict">
select id,code,name,value from n_sysdict where id=#{id}
</select>
<!-- 通过条件查询多个 -->
<select id="selectList" resultType="sysDict">
select id,code,name,value from n_sysdict
<where>
<if test="id != null">
and id = #{id}
</if>
<if test="code != null and code != ''">
and code = #{code}
</if>
</where>
order by code,value
</select>
<!-- 新增 -->
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
insert into n_sysdict(code,name,value)
values (#{code},#{name},#{value})
</insert>
<!-- 修改 -->
<update id="updateById">
update n_sysdict set
code = #{code},
name = #{name},
value = #{value}
where id = #{id}
</update>
<!-- 删除 -->
<delete id="deleteById">
delete from n_sysdict where id = #{id}
</delete>
</mapper>
这5个方法都是很基础的方法,通过这5个方法就可以实现字典表的基本操作。
下面将在这5个接口的基础上,继续编写Service层的代码。
开发业务层(Service层)
虽然针对接口编程对小的项目来说并不重要,但是这里为了形式上的需要仍然提供了Service接口。在src/main/java中新建com.shrimpking.service包,然后添加SysDictService接口,代码如下。
SysDictService.java
package com.shrimpking.service;
import com.shrimpking.pojo.SysDict;
import java.util.List;
/**
* Created by IntelliJ IDEA.
*
* @Author : Shrimpking
* @create 2023/6/12 15:54
*/
public interface SysDictService
{
/**
* 通过id查询
* @param id
* @return
*/
SysDict getById(Integer id);
/**
* 通过条件查询多个
* @param sysDict
* @param offset
* @param limit
* @return
*/
List<SysDict> getList(SysDict sysDict, Integer offset,Integer limit);
/**
* 新增或修改
* @param sysDict
* @return
*/
boolean saveOrUpdate(SysDict sysDict);
/**
* 删除
* @param id
* @return
*/
boolean deleteById(Integer id);
}
Service层的saveOrUpdate方法对应Mapper中的insert和updateById方法,其他3 个方法和 Mapper 层方法一 一 对应。在 com.shrimpking.service 包下创建 impl 包,然后新建SysDictService接口的实现类SysDictServiceImpl,代码如下。
SysDictServiceImpl.java
package com.shrimpking.service.impl;
import com.shrimpking.mapper.SysDictMapper;
import com.shrimpking.pojo.SysDict;
import com.shrimpking.service.SysDictService;
import com.sun.istack.internal.NotNull;
import org.apache.ibatis.session.RowBounds;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* Created by IntelliJ IDEA.
*
* @Author : Shrimpking
* @create 2023/6/12 15:57
*/
@Service
public class SysDictServiceImpl implements SysDictService
{
@Autowired
private SysDictMapper sysDictMapper;
/**
* 通过id查询
* @param id
* @return
*/
@Override
public SysDict getById(@NotNull Integer id)
{
return sysDictMapper.selectById(id);
}
/**
* 通过条件查询多个,可以分页,mysql方式
* @param sysDict
* @param offset
* @param limit
* @return
*/
@Override
public List<SysDict> getList(SysDict sysDict, Integer offset, Integer limit)
{
RowBounds rowBounds = RowBounds.DEFAULT;
if(offset != null && limit != null)
{
rowBounds = new RowBounds(offset,limit);
}
return sysDictMapper.selectList(sysDict,rowBounds);
}
/**
* 新增或修改
* @param sysDict
* @return
*/
@Override
public boolean saveOrUpdate(SysDict sysDict)
{
if (sysDict.getId() == null)
{
//新增
return sysDictMapper.insert(sysDict) == 1;
}
else
{
//修改
return sysDictMapper.updateById(sysDict) == 1;
}
}
/**
* 删除
* @param id
* @return
*/
@Override
public boolean deleteById(Integer id)
{
return sysDictMapper.deleteById(id) == 1;
}
}
Service的实现类中需要添加@Service注解,集成Spring时配置过自动扫描包,包名是 com.shrimpking.service.impl,SysDictServiceImpl 实现类所在的包就是符合这个包名规则的,加上注解后,Spring在初始化时就会扫描到这个类,然后由Spring管理这个类。因为配置了自动扫描Mapper接口,所以在Service 层可以直接通过以下代码注入Mapper。
其他配置文件
mybatis-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:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--启用controller注解支持-->
<mvc:annotation-driven/>
<!-- 映射静态资源 -->
<mvc:resources mapping="/static/**" location="classpath:static/"/>
<!-- 包扫描 -->
<context:component-scan base-package="com.shrimpking.controller"/>
<!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/view/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
mybatis-config.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="STDOUT_LOGGING"/>
<setting name="cacheEnabled" value="true"/>
<setting name="mapUnderscoreToCamelCase" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
</configuration>
web.xml
<?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">
<!--spring 配置文件在哪里-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>mybtis</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:mybatis-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mybtis</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<filter>
<filter-name>springEncoding</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>springEncoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
开发控制层(Controller层)
在com.shrimpking.controller包下,新建SysDictController类,代码如下。
package com.shrimpking.controller;
import com.shrimpking.pojo.SysDict;
import com.shrimpking.service.SysDictService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import java.util.List;
/**
* Created by IntelliJ IDEA.
*
* @Author : Shrimpking
* @create 2023/6/12 16:07
*/
@Controller
@RequestMapping("/dicts")
public class SysDictController
{
@Autowired
private SysDictService sysDictService;
/**
* 查询
* http://localhost:8089/dicts?offset=0&limit=6
* @param sysDict
* @param offset
* @param limit
* @return
*/
@RequestMapping
public ModelAndView dicts(SysDict sysDict,Integer offset,Integer limit)
{
ModelAndView modelAndView = new ModelAndView();
List<SysDict> sysDictList = sysDictService.getList(sysDict, offset, limit);
modelAndView.addObject("dicts",sysDictList);
modelAndView.setViewName("dicts");
return modelAndView;
}
/**
* 跳转新增
* @param id
* @return
*/
@RequestMapping(value = "/toAdd",method = RequestMethod.GET)
public ModelAndView add(Integer id)
{
ModelAndView modelAndView = new ModelAndView();
SysDict sysDict;
if(id == null)
{
//如果id不存在,就是新增,创建一个空对象;
sysDict = new SysDict();
}
else
{
//修改
sysDict = sysDictService.getById(id);
}
modelAndView.addObject("model",sysDict);
modelAndView.setViewName("dict_add");
return modelAndView;
}
/**
* 新增保存
* @param sysDict
* @return
*/
@RequestMapping(value = "/add",method = RequestMethod.POST)
public ModelAndView save(SysDict sysDict)
{
ModelAndView modelAndView = new ModelAndView();
try
{
sysDictService.saveOrUpdate(sysDict);
modelAndView.setViewName("redirect:/dicts");
}
catch (Exception e)
{
modelAndView.setViewName("dict_add");
modelAndView.addObject("msg",e.getMessage());
modelAndView.addObject("model",sysDict);
}
return modelAndView;
}
@RequestMapping(value = "/delete",method = RequestMethod.POST)
@ResponseBody
public ModelMap delete(@RequestParam Integer id)
{
ModelMap modelMap = new ModelMap();
try
{
boolean success = sysDictService.deleteById(id);
modelMap.put("success",success);
}
catch (Exception e)
{
modelMap.put("success",false);
modelMap.put("msg",e.getMessage());
}
return modelMap;
}
}
开发视图层(View层)
按照视图配置,需要在web下面的WEB-INF中创建view目录,然后在view中创建dicts.jsp和dict_add.jsp,dicts.jsp代码如下。
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<c:set var="path" value="${pageContext.request.contextPath}"/>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>字典信息</title>
<script src="${path}/static/jQuery-3.4.1.js"></script>
</head>
<body>
<table style="border: 1px solid black;width: 50%;border-collapse: collapse;padding: 10px;text-align: center;">
<tr>
<th colspan="4">字典管理</th>
</tr>
<tr>
<th>类别名</th>
<th>字典名</th>
<th>字典值</th>
<th>操作[<a href="${path}/dicts/toAdd">新增</a>]</th>
</tr>
<c:forEach items="${dicts}" var="dict">
<tr id="dict-${dict.id}">
<td>${dict.code}</td>
<td>${dict.name}</td>
<td>${dict.value}</td>
<td>
[<a href="${path}/dicts/toAdd?id=${dict.id}">编辑</a>]
[<a href="javascript:;" onclick="deleteById(${dict.id},'${dict.name}')">删除</a>]
</td>
</tr>
</c:forEach>
</table>
<script>
function deleteById(id, label) {
var result = confirm('确定要删除<' + label + '>吗');
if(result)
{
$.ajax({
url:'${path}/dicts/delete',
data:{
id:id
},
dataType:'json',
type:'POST',
success:function (data) {
if(data.success)
{
$('#dict-' + id).remove();
}
else
{
alert(data.msg);
}
}
})
}
}
</script>
</body>
</html>
dict_add.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<c:set var="path" value="${pageContext.request.contextPath}"/>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>字典维护</title>
</head>
<body>
<form action="${path}/dicts/add" method="post">
<input type="hidden" name="id" value="${model.id}">
<table>
<c:if test="${msg != null}">
<tr>
<th colspan="2" style="color: red;max-width: 400px;">${msg}</th>
</tr>
</c:if>
<tr>
<th colspan="2">字典维护</th>
</tr>
<tr>
<th>类别名</th>
<td><input type="text" name="code" value="${model.code}"></td>
</tr>
<tr>
<th>字典名</th>
<td><input type="text" name="name" value="${model.name}"></td>
</tr>
<tr>
<th>字典值</th>
<td><input type="text" name="value" value="${model.value}"></td>
</tr>
<tr>
<th colspan="2">
<input type="submit" value="保存">
<input type="button" value="取消" onclick="backToList()">
</th>
</tr>
</table>
</form>
<script>
function backToList() {
location.href = '${path}/dicts';
}
</script>
</body>
</html>
dicts.jsp 代码中使用了 jquery-3.4.1.js,然后放在resources/static/目录下面。
部署和运行应用
将项目部署到 Tomcat 下,然后启动服务。服务器启动完成后,在浏览器中输入http://localhost:8089/dicts 并访问,简单的字典管理操作界面便实现了,如图