简单示例
这一节中,我们不再从头编写 MyBatis 的方法,直接使用第2、3、4、6章中已经开发好的 simple 项目。如果没有按照前面章节中的介绍实现书中提到的所有方法,可以直接下载 simple 项目,然后使用 Maven 命令(mvn install)打包到本地仓库或将该项目引入到当前的工作空间即可。simple 项目的下载地址是 http://mybatis.tk/book/simple-all.zip 。
引入simple依赖
做好 simple 项目准备后,在 pom.xml 中添加 simple 项目依赖,代码如下。
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>simple</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
引入新的依赖后,还需要配置 MyBatis,让 MyBatis 可以扫描到这个依赖下面的 Mapper 接口。上一节的例子中使用的是 @Mapper 注解,但是对于已经存在的 simple 来说,一个个去添加注解并不合适,因此要换一种新的方式来扫描 Mapper 接口。
修改 Application 类,添加 @MapperScan 注解,代码如下。
@SpringBootApplication
@MapperScan(basePackages = {"cn.liaozh.mybatis2.ch10.boot.mapper", "cn.liaozh.mybatis2.ch2.xml.mapper"}, nameGenerator = MapperNameGenerator.class)
public class BootApplication implements CommandLineRunner {
// 省略
}
修改 Application 类后就会通过这种方式去扫描 Mapper 接口,还需要修改 application.properties,让映射文件也可以被扫描到。
mybatis.mapper-locations=classpath:mapper/.xml,classpath:tk/mybatis/*/mapper/.xml
修改好这两处配置后,在当前项目中就可以直接使用已经写好的 Mapper 接口了。但是此时如果执行 Application 类就会报错,错误信息如下。
这是因为在刚刚引入的依赖中,存在 tk.mybatis.simple.mapper.CountryMapper 接口,和上一节添加的例子 tk.mybatis.springboot.mapper.CountryMapper 的接口名完全相同。因为 MyBatis 扫描接口时会默认用首字母小写的类名作为 Spring 中 bean 的名字,使得 CountryMapper 对应的 countryMapper 相同,因此会报错。
就当前项目来说,解决这个问题有两种方式。第一种就是去掉上一节添加的这个接口,毕竟只是测试用的,去掉也无所谓。但是当项目的依赖有很多时,很有可能会出现不能删除的情况,这样就只能考虑另一种方式,即从 bean 的名字入手,修改默认的名字生成规则,让它们生成的名字不再重复。
在 tk.mybatis.springboot 包下新建 MapperNameGenerator 类,代码如下。
package cn.liaozh.mybatis2.ch10.boot;
import java.beans.Introspector;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.util.ClassUtils;
/**
* Mapper 名字生成器
**/
public class MapperNameGenerator implements BeanNameGenerator {
Map<String, Integer> nameMap = new HashMap<String, Integer>();
@Override
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
//获取类的名字,如 CountryMapper
String shortClassName = ClassUtils.getShortName(definition.getBeanClassName());
//将类名转换为规范的变量名,如 countryMapper
String beanName = Introspector.decapitalize(shortClassName);
//判断名字是否已经存在,如果存在,则在名字后面增加序号
if (nameMap.containsKey(beanName)) {
int index = nameMap.get(beanName) + 1;
nameMap.put(beanName, index);
//增加序号
beanName += index;
} else {
nameMap.put(beanName, 1);
}
return beanName;
}
}
该类的说明见代码注释,创建好名字生成器后,修改 Application 中的 @MapperScan 注解。
@MapperScan(value={
"tk.mybatis.springboot.mapper",
"tk.mybatis.simple.mapper"
},
nameGenerator = MapperNameGenerator.class
)
指定 nameGenerator 属性为 MapperNameGenerator.class 即可,这样在扫描所有的 Mapper 接口时,如果出现重复,就会通过增加序号的方式避免这个问题。
名字重复的问题解决了,但是代码使用 @Resource 注解注入时,可能会由于 beanName 和类型不匹配导致注入失败。
举个例子,假设 tk.mybatis.simple.mapper.CountryMapper 生成的名字为 countryMapper,tk.mybatis.springboot.mapper.CountryMapper 生成的名字为 countryMapper2。当存在如下注解代码时,通过名字注入会使用 countryMapper 对应的 tk.mybatis.simple.mapper.CountryMapper,这样就会因为类型不匹配而出错。
@Resource
private tk.mybatis.springboot.mapper.CountryMapper countryMapper;
因此在注入 Mapper 接口时,建议使用 @Autowired 注解,根据类型注入时一定不会有错。
开发业务(service)层
新建 tk.mybatis.springboot.service 包,然后在该包下面创建 UserService 接口,代码如下。
public interface UserService {
/**
* 通过 id 查询用户
*
* @param id ID
* @return 用户信息
*/
SysUser findById(Long id);
/**
* 查询全部用户
*
* @return 用户集合
*/
List<SysUser> findAll();
}
再创建 tk.mybatis.springboot.service.impl 包,在该包下创建 UserServiceImpl 实现类,代码如下。
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public SysUser findById(Long id) {
return userMapper.selectById(id);
}
@Override
public List<SysUser> findAll() {
return userMapper.selectAll();
}
}
在该类中注入 simple 项目的 UserMapper 接口。因为前面已经配置好,所以这里可以直接注入。
开发控制(Controller)层
在 tk.mybatis.springboot.controller 包下创建 UserController 类,代码如下。
@RestController
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("users/{id}")
SysUser user(@PathVariable("id") Long id) {
return userService.findById(id);
}
@RequestMapping("users")
List<SysUser> users() {
return userService.findAll();
}
}
UserController 中提供了两个方法:通过 id 获取具体的用户信息的方法以及获取全部用户信息的方法。
运行应用查看效果
重新运行 Application 类,然后在浏览器地址栏输入 http://localhost:8080/users ,此时会显示出系统中所有的用户信息,显示内容如下。
如果想要查看 id 为 1001 的用户的信息,可以在浏览器地址栏输入 http://localhost:8080/users/1001 ,此时会显示出用户 1001 的个人信息。
大家可以自行添加 simple 项目中的其他方法进行尝试,关于 Spring Boot 的详细用法可以通过本章开头提到的官方文档进行了解。