前言:使用Spring boot搭建的项目开发人员可以使用大量的注解替代了繁琐的xml配置,在我的上一篇文章使用Spring Boot + Spring DataJpa 开发RestFul Api时,采用了Spring Data Jpa作为持久层框架,省略了大部分sql语句。但是采用Spring DataJpa作为持久层框架,Dao层直接继承CrudRepository或JpaRepository接口,对于不是深入理解底层映射原理的开发人员一时半会很难实现复杂的sql语句,包括一些动态sql语句。而在以前开发过的Spring MVC + MyBatis项目中我们更多的是使用xml标签语句完成sql语句,xml标签化的sql语句支持动态sql语句和存储过程等复查的查询SQL语句块。我本人之前在公司的项目开发中也一直采用xml标签化的sql语句完一些复杂的数据库操作业务逻辑。那么下面就来分享一下自己的这个项目吧,包括实现分页查询和批量操作的API接口。所所接口均通过post测试调用成功。
本项目使用的环境:
1. 搭建项目
1.1 进入站点https://start.spring.io/ 快速搭建一个Spring Boot 整合Mybatis的demo项目, 选择Spring Boot版本号(目前的稳定版本是2.1.1,本人在搭建这一项目时当时用的是2.1.0版本,但是发现启动时连接数据源一直报错,查了很多博客还是解决不了,于是换成了2.0.5版本就没报错了)在Group和Group下面的输入框中包名和项目名,添加Web、JDBC、Mysql、Mybatis等依赖, 然后点击生成项目按钮生成.zip的项目文件,会自动下载到本地,解压导入到IDEA工具中即可
本人当时创建的项目groupId 为com.example, artifactId为mybatis, 在pom.xml文件中将spring boot的版本号改成了
2.0.5.RELEASE
1.2 项目目录结构及pom.xml文件
项目代码结构图
1.3 pom.xml文件代码,手工引入了alibaba德鲁伊数据源连接池druid、jackson-core、jackson-databind、pagehelper等依赖
4.0.0
com.example
mybatis
0.0.1-SNAPSHOT
jar
mybatis
Demo project for Spring Boot
org.springframework.boot
spring-boot-starter-parent
2.0.5.RELEASE
UTF-8
UTF-8
1.8
org.springframework.boot
spring-boot-starter-web
org.mybatis.spring.boot
mybatis-spring-boot-starter
1.3.2
mysql
mysql-connector-java
runtime
org.springframework.boot
spring-boot-starter-test
test
com.alibaba
druid
1.0.5
com.fasterxml.jackson.core
jackson-core
com.fasterxml.jackson.core
jackson-databind
com.fasterxml.jackson.module
jackson-module-parameter-names
com.github.pagehelper
pagehelper
4.1.3
org.springframework.boot
spring-boot-starter-thymeleaf
org.springframework.boot
spring-boot-maven-plugin
2. 配置文件application.yml及启动类MybatisApplication.java
2.1 数据库建表,创建用户并授权
使用mysql-workbench客户端root账号登录成功后建表userinfo, 新建用户robbot并授权, 依次执行下面两部分sql脚本
建表userinfo,创建新用户robbot并授权
新建部门表dept,并插入4条记录
2.2 application.yml代码
2.2 MybatisApplication.java源代码
@MapperScan注解的basePackags属性开启扫描dao接口类所在的包,多个包可用逗号分隔;没有这个注解的话项目启动时会报异常
@SpringBootApplication也可以用@EnableAutoConfiguration和@ComponentScan(basePackages={"com.xxx.xxx"})代替
@SpringBootApplication是@EnableAutoConfiguration和@ComponentScan两个注解的合并,默认扫描启动类所在的包
package com.example.mybatis;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
//@EnableAutoConfiguration
//@ComponentScan(basePackages = {"com.example.mybatis"})
@MapperScan(basePackages={"com.example.mybatis.dao"})
public class MybatisApplication{
public static void main(String[] args) {
SpringApplication.run(MybatisApplication.class, args);
}
}
3. 接口开发
3.1 实体类
3.1.1 对应userinfo表的UserTO实体类
package com.example.mybatis.model;
import java.io.Serializable;
public class UserTO implements Serializable {
private int id;
private int deptNo;
private String deptName;
private String userAccount;
private String password;
private String nickName;
private String emailAddress;
private String birthDay;
private Long phoneNum;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getDeptNo() {
return deptNo;
}
public void setDeptNo(int deptNo) {
this.deptNo = deptNo;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
public String getUserAccount() {
return userAccount;
}
public void setUserAccount(String userAccount) {
this.userAccount = userAccount;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
public String getEmailAddress() {
return emailAddress;
}
public void setEmailAddress(String emailAddress) {
this.emailAddress = emailAddress;
}
public String getBirthDay() {
return birthDay;
}
public void setBirthDay(String birthDay) {
this.birthDay = birthDay;
}
public Long getPhoneNum() {
return phoneNum;
}
public void setPhoneNum(Long phoneNum) {
this.phoneNum = phoneNum;
}
}
3.1.2 接口响应实体类ServiceResponse
package com.example.mybatis.model;
import java.io.Serializable;
public class ServiceResponse implements Serializable {
private int status;
private String message;
private String serviceId;
private T data;
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getServiceId() {
return serviceId;
}
public void setServiceId(String serviceId) {
this.serviceId = serviceId;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
3.1.3 分页查询实体类PageInfo
package com.example.mybatis.model;
import java.io.Serializable;
import java.util.List;
public class PageInfo implements Serializable {
int pageNum;
int pageSize;
int startIndex;
int endIndex;
int totalRows;
List dataList;
public int getPageNum() {
return pageNum;
}
public void setPageNum(int pageNum) {
this.pageNum = pageNum;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public int getStartIndex() {
return startIndex;
}
public void setStartIndex(int startIndex) {
this.startIndex = startIndex;
}
public int getEndIndex() {
return endIndex;
}
public void setEndIndex(int endIndex) {
this.endIndex = endIndex;
}
public List getDataList() {
return dataList;
}
public void setDataList(List dataList) {
this.dataList = dataList;
}
public int getTotalRows() {
return totalRows;
}
public void setTotalRows(int totalRows) {
this.totalRows = totalRows;
}
}
3.1.4 分层开发接口代码结构
分层开发接口代码结构
3.2 四层架构模式完成接口代码
3.2.1 Controller层代码(注意Post接口请求体数据参数前必须加@RequestBody注解)
package com.example.mybatis.controller;
import com.example.mybatis.model.PageInfo;
import com.example.mybatis.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import com.example.mybatis.model.UserTO;
import com.example.mybatis.model.ServiceResponse;
import java.util.List;
/**
* spring-boot 整合mybatis的 controller
*/
@RestController
@RequestMapping(value="/user")
public class MybatisController {
@Autowired
private IUserService userService;
/**
* 根据用户账号查询单个用户信息
* @param userAccout
* @return
*/
@RequestMapping(value= "/userinfo",method = RequestMethod.GET,produces = {"application/json;charset=UTF-8"},consumes = {"application/json"})
public ServiceResponse getUserInfoByAccount(@RequestParam("userAccount") String userAccout){
return userService.queryUserInfoByAccount(userAccout);
}
/**
* 添加单个用户信息
* @param userTO
* @return
*/
@RequestMapping(value="add/userinfo",method=RequestMethod.POST,produces = {"application/json;charset=UTF-8"},consumes = {"application/json"})
public ServiceResponse addUserInfo(@RequestBody UserTO userTO){
return userService.addUserTO(userTO);
}
/**
* 修改单个用户信息
* @param userTO
* @return
*/
@RequestMapping(value="/update/userinfo",method = RequestMethod.POST)
public ServiceResponse updateUserInfo(@RequestBody UserTO userTO){
return userService.updateUserTO(userTO);
}
/**
* 批量添加用户信息
* @param userTOs
* @return
*/
@RequestMapping(value="/batchadd/userinfo",method=RequestMethod.POST)
public ServiceResponse batchAddUserInfo(@RequestBody List userTOs){
return userService.batchAddUserTO(userTOs);
}
/**
* 分页查询用户信息
* @param pageNum
* @param pageSize
* @return
*/
@RequestMapping(value="alluser/page",method=RequestMethod.GET)
public ServiceResponse queryAllUser(@RequestParam(value="pageNum") int pageNum,
@RequestParam(value="pageSize") int pageSize){
return userService.selectAllUser(pageNum,pageSize);
}
/**
* 批量修改用户信息
* @param userItems
* @return
*/
@RequestMapping(value="/batch/update",method = RequestMethod.POST)
public ServiceResponse batchUpdateUserInfo(@RequestBody List userItems){
return userService.batchAddUserTO(userItems);
}
/**
* 根据用户名删除单个用户信息
* @param userAccount
* @return
*/
@RequestMapping(value="/delete/userinfo",method=RequestMethod.DELETE)
public ServiceResponse deleteUserInfo(@RequestParam("userAccount") String userAccount){
return userService.deleteUserInfo(userAccount);
}
/**
* 批量删除用户信息
* @param userAccounts
* @return
*/
@RequestMapping(value="/delete/batch",method = RequestMethod.POST)
public ServiceResponse batchDeleteUserInfo(@RequestBody List userAccounts){
return userService.batchDeleteUserInfo(userAccounts);
}
}
3.2.2 Service层代码
Service层接口类代码
package com.example.mybatis.service;
import com.example.mybatis.model.ServiceResponse;
import com.example.mybatis.model.UserTO;
import java.util.List;
import com.example.mybatis.model.PageInfo;
public interface IUserService {
ServiceResponse queryUserInfoByAccount(String userAccount);
ServiceResponse addUserTO(UserTO userTO);
ServiceResponse updateUserTO(UserTO userTO);
ServiceResponse batchAddUserTO(List userTOs);
ServiceResponse selectAllUser(int pageNum,int pageSize);
ServiceResponse batchUpdateUserInfo(List userItems);
ServiceResponse deleteUserInfo(String userAccount);
ServiceResponse batchDeleteUserInfo(List userAccounts);
}
Service层实现类代码
package com.example.mybatis.service.impl;
import com.example.mybatis.business.IUserBusiness;
import com.example.mybatis.model.PageInfo;
import com.example.mybatis.model.ServiceResponse;
import com.example.mybatis.model.UserTO;
import com.example.mybatis.service.IUserService;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
import java.util.List;
@Service
public class UserService implements IUserService {
@Autowired
private IUserBusiness userBusiness;
private static final Logger logger = LoggerFactory.getLogger(UserService.class);
@Override
public ServiceResponse queryUserInfoByAccount(String userAccount) {
ServiceResponse response = new ServiceResponse<>();
UserTO userTO = userBusiness.queryUsersByAccount(userAccount);
response.setStatus(200);
response.setMessage("ok");
response.setData(userTO);
return response;
}
@Override
public ServiceResponse addUserTO(UserTO userTO) {
ServiceResponse response = new ServiceResponse<>();
try{
userBusiness.addUserInfo(userTO);
response.setMessage("ok");
response.setStatus(200);
response.setData("success");
}catch (Exception ex){
response.setMessage("inner service error:"+ex.getMessage());
response.setStatus(500);
response.setData("error");
logger.error(ex.getMessage(),ex);
}
return response;
}
@Override
public ServiceResponse updateUserTO(UserTO userTO) {
ServiceResponse response = new ServiceResponse<>();
try{
userBusiness.updateUserInfo(userTO);
response.setMessage("ok");
response.setStatus(200);
response.setData("success");
}catch (Exception ex){
response.setMessage("inner service error:"+ex.getMessage());
response.setStatus(500);
response.setData("error");
logger.error(ex.getMessage(),ex);
}
return response;
}
@Override
public ServiceResponse batchAddUserTO(List userTOs) {
ServiceResponse response = new ServiceResponse<>();
try{
userBusiness.batchInsertUserInfo(userTOs);
response.setStatus(200);
response.setMessage("ok");
response.setData("success");
}catch (Exception ex){
response.setMessage("inner service error:"+ex.getMessage());
response.setStatus(500);
response.setData("error");
logger.error(ex.getMessage(),ex);
}
return response;
}
@Override
public ServiceResponse selectAllUser(int pageNum, int pageSize) {
ServiceResponse response = new ServiceResponse<>();
PageInfo pageInfo = new PageInfo();
pageInfo.setPageNum(pageNum);
pageInfo.setPageSize(pageSize);
int startIndex = (pageNum-1)*pageSize+1;
int endIndex = pageNum*pageSize;
pageInfo.setStartIndex(startIndex);
int totalRows = userBusiness.queryTotalRows("userinfo");
if(totalRows resultList = userBusiness.selectAllUser(startIndex,pageSize-1);
pageInfo.setDataList(resultList);
response.setStatus(200);
response.setMessage("ok");
response.setData(pageInfo);
return response;
}
@Override
public ServiceResponse batchUpdateUserInfo(List userItems) {
ServiceResponse response = new ServiceResponse<>();
try{
userBusiness.batchUpdateUserInfo(userItems);
response.setStatus(200);
response.setMessage("ok");
response.setData("success!");
}catch(Exception ex){
response.setStatus(500);
response.setMessage("inner service error:"+ex.getMessage());
response.setData("error");
logger.error(ex.getMessage(),ex);
}
return response;
}
@Override
public ServiceResponse deleteUserInfo(String userAccount) {
ServiceResponse response = new ServiceResponse<>();
try{
userBusiness.deleteUserInfo(userAccount);
response.setStatus(200);
response.setMessage("ok");
response.setData("success!");
}catch(Exception ex){
response.setStatus(500);
response.setMessage("inner service error:"+ex.getMessage());
response.setData("error");
logger.error(ex.getMessage(),ex);
}
return response;
}
@Override
public ServiceResponse batchDeleteUserInfo(List userAccounts) {
ServiceResponse response = new ServiceResponse<>();
try{
userBusiness.batchDeleteUserInfo(userAccounts);
response.setStatus(200);
response.setMessage("ok");
response.setData("success!");
}catch(Exception ex){
response.setStatus(500);
response.setMessage("inner service error:"+ex.getMessage());
response.setData("error");
logger.error(ex.getMessage(),ex);
}
return response;
}
}
3.2.3 Busines层代码
Busines层接口类代码
package com.example.mybatis.business;
import com.example.mybatis.model.UserTO;
import java.util.List;
public interface IUserBusiness {
UserTO queryUsersByAccount(String userAccount);
void addUserInfo(UserTO userTO)throws Exception;
void updateUserInfo(UserTO userTO)throws Exception;
void batchInsertUserInfo(List items) throws Exception;
List selectAllUser(int startIndex,int pageSize);
int queryTotalRows(String dbName);
void batchUpdateUserInfo(List items) throws Exception;
void deleteUserInfo(String userAccount) throws Exception;
void batchDeleteUserInfo(List userAccounts) throws Exception;
}
Business层实现类代码(注意实现类必须加@Component或@Named注解暴露接口,dao类的增删改操作要添加加事物注解@Transactional)
package com.example.mybatis.business.impl;
import com.example.mybatis.business.IUserBusiness;
import com.example.mybatis.dao.IUserDao;
import com.example.mybatis.model.UserTO;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Component
public class UserBusiness implements IUserBusiness {
@Autowired
private IUserDao userDao;
@Override
public UserTO queryUsersByAccount(String userAccount){
return userDao.queryUsersByAccount(userAccount);
}
@Override
@Transactional(rollbackFor = {Exception.class},readOnly = false)
public void addUserInfo(UserTO userTO) throws Exception {
userDao.addUserInfo(userTO);
}
@Override
@Transactional(rollbackFor = {Exception.class},readOnly = false)
public void updateUserInfo(UserTO userTO) throws Exception {
userDao.updateUserInfo(userTO);
}
@Override
@Transactional(rollbackFor = {Exception.class},readOnly = false)
public void batchInsertUserInfo(List items) throws Exception {
userDao.batchAddUserInfo(items);
}
@Override
public List selectAllUser(int startIndex,int pageSize) {
//将分页参数传给PageHelper类的startPage(int pageNum,int pageSize)静态方法即可实现分页效果,非常简单
// PageHelper.startPage(pageNum,pageSize);
return userDao.selectAllUser(startIndex,pageSize);
}
@Override
public int queryTotalRows(String dbName) {
return userDao.queryTotalRows(dbName);
}
@Override
@Transactional(rollbackFor = {Exception.class},readOnly = false)
public void batchUpdateUserInfo(List items) throws Exception {
userDao.batchUpdateUserInfo(items);
}
@Override
@Transactional(rollbackFor = {Exception.class},readOnly = false)
public void deleteUserInfo(String userAccount) throws Exception {
userDao.deleteUserInfo(userAccount);
}
@Override
@Transactional(rollbackFor = {Exception.class},readOnly = false)
public void batchDeleteUserInfo(List userAccounts) throws Exception {
userDao.batchDeleteUserInfo(userAccounts);
}
}
3.2.4 Dao层代码
dao接口类代码(有多个入参时可使用ibatis的参数绑定注解@Param)
package com.example.mybatis.dao;
import com.example.mybatis.model.UserTO;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
//import java.util.List;
//@Repository
public interface IUserDao {
UserTO queryUsersByAccount(@Param("userAccount")String userAccount);
List selectAllUser(@Param("startIndex") int startIndex,@Param("pageSize") int pageSize);
void addUserInfo(UserTO userTO);
void updateUserInfo(UserTO userTO);
void batchAddUserInfo(List userItems);
int queryTotalRows(@Param("dbName") String dbName);
void batchUpdateUserInfo(List userItems);
void deleteUserInfo(String userAccount);
void batchDeleteUserInfo(List userAccounts);
}
dao接口实现类IUser.xml代码(注意该文件必须在resource目录下Spring容器才能在类路径classpath下找到)
insert into userinfo
(user_account,
password,
phone_num,
dept_no,
birth_day,
nick_name,
email_address)
values(
#{userAccount,jdbcType=VARCHAR},
#{password,jdbcType=VARCHAR},
#{phoneNum,jdbcType=NUMERIC},
#{deptNo,jdbcType=NUMERIC},
#{birthDay,jdbcType=VARCHAR},
#{nickName,jdbcType=VARCHAR},
#{emailAddress,jdbcType=VARCHAR})
insert into userinfo(
user_account,
password,
phone_num,
dept_no,
birth_day,
nick_name,
email_address
)
select
#{item.userAccount,jdbcType=VARCHAR},
#{item.password,jdbcType=VARCHAR},
#{item.phoneNum,jdbcType=NUMERIC},
#{item.deptNo,jdbcType=NUMERIC},
#{item.birthDay,jdbcType=VARCHAR},
#{item.nickName,jdbcType=VARCHAR},
#{item.emailAddress,jdbcType=VARCHAR}
from dual
update userinfo
password=#{password,jdbcType=VARCHAR},
phone_num=#{phoneNum,jdbcType=NUMERIC},
dept_no=#{deptNo,jdbcType=NUMERIC},
birth_day=#{birthDay,jdbcType=VARCHAR},
nick_name=#{nickName,jdbcType=VACHAR},
email_address=#{emailAddress,jdbcType=VARCHAR}
where user_account=#{userAccount,jdbcType=VARCHAR}
update userinfo
password=#{item.password,jdbcType=VARCHAR},
phone_num=#{item.phoneNum,jdbcType=NUMERIC},
dept_no=#{item.deptNo,jdbcType=NUMERIC},
birth_day=#{item.birthDay,jdbcType=VARCHAR},
nick_name=#{item.nickName,jdbcType=VACHAR},
email_address=#{item.emailAddress,jdbcType=VARCHAR}
where user_account=#{item.userAccount,jdbcType=VARCHAR}
delete from userinfo where user_account=#{param1,jdbcType=VARCHAR}
delete from userinfo where user_account in
#{item,jdbcType=VARCHAR}
3.3 接口测试
启动项目后利用postman对接口进行测试
3.3.1 首先测试添加单个用户信息接口(Headers里设置Content-type: application/json, Body选择raw):
postman测试添加单个用户信息接口
接口响应信息截图如下,status:200 代表接口调用成功
添加单个用户信息接口响应信息
在mysql-workbench客户端query窗口中执行sql脚本:select * from userinfo, 发现数据库多了一个记录
数据库userinfo表查询结果
3.3.2 测试批量添加用户信息接口
postman测试批量添加用户信息接口
返回响应信息status:200代表接口调用成功
3.3.3 测试根据用户名查询用户信息接口
postman测试测试根据用户名查询用户信息接口
3.3.4 测试分页查询接口
先利用批量插入接口添加20条左右数据,然后使用postman调用分页查询接口
其他接口可使用postman一一测试,本博客不再一一截图。开发过程中,如遇到报异常,可查看具体异常信息,并通过debug模式断点调试查看具体原因,然后进行解决
参考文档
Spring boot Mybatis 整合(完整版):https://blog.csdn.net/winter_chen001/article/details/77249029
Mybatis v3.4.6开发指南
请尊重原创作品付出的汗水,转载请注明出处!参考本片博客开发demo项目遇到难以解决的问题,欢迎给本人发邮件交流,
本人邮箱:[email protected]