容易出现Invalid bound statement (not found) :com.xxx错误,该错误是由于spring没有找到mapper.xml文件引起的,请检查如下方面:
1、 接口中方法名称如findAll()与Mapper.xml文件中 id="findAll"是否一致
2、 Mapper.xml文件中的 namespace的属性值与接口文件路径一致,比如有接口为xxx.xxx.UserMapper,则 namespace="xxx.xxx.UserMapper"
3、Mapper.xml文件名称要与接口名称一致,比如UserMapper.xml,则接口名称为UserMapper。
4、项目配置文件application.properties中的mapper.xml的位置配置是否正确(写错一个字符都不行),正确配置的例子如下:
mybatis.typeAliasesPackage=com.entity
mybatis.mapper-locations=classpath:/mapper/*Mapper.xml
切记不要错误配置为:
spring.mybatis.typeAliasesPackage=com.entity
spring.mybatis.mapper-locations=classpath:/mapper/*Mapper.xml
mybatis、spring、server是application.properties中三大并列的配置范畴,不是主从关系不要搞混了。
另外需要注意的地方是:
5、如果在接口上配置了@Mapper注解,则没有必要在启动程序的类public class DemoApplication{ ....main()....}的前添加MapperScan,比如@MapperScan("com.example.demo.dao")。
6、项目启动程序public class DemoApplication{ ....main()....}的包如果是 com.example.demo,则项目中新建的包中有组件(bean),则要求在com.example.demo基础上进行添加,比如添加com.example.demo.dao;com.example.demo.controller等;
如果新建包不在com.example.demo下面建立,则要用如下方式指定组件的包位置:@ComponentScan({"com.xx","com.xx2"})。由于不需要依赖注入实体类的包不需要遵循这个结构,比如我们可以在com.entity下面创建实体类。
7、下面给出一个正确的案例,该例实现了spring boot整合mybatis的xml配置和注解配置两种方式:
步骤1 在http://maven.apache.org/download.cgi下载maven。先配置maven的下载依赖包的镜像网站,在settings.xml里面找到<mirrors>中的内容,用下面替换:
<mirror>
<id>nexus</id>
<mirrorOf>*</mirrorOf>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
</mirror>
步骤2 在eclipse的Windowd/Preferences/Maven/User Settings的Global settings和User settings中导入settings.xml文件
步骤3 在start.spring.io上下载demo模板,并导入该maven项目
步骤4 进入项目设计,具体如下:
项目结构:
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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.8.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demoJDBC</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.properties
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false
#spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
#spring.datasource.type=com.zaxxer.hikari.HikariDataSource
#不需要配置如上alibaba等数据库pool,系统已经有新的hikari数据库pool
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.maximum-pool-size=15
spring.datasource.username=root
spring.datasource.password=root
#下面这句也没必要了:The jdbc driver is automatically registered via the SPI
#spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.thymeleaf.prefix=classpath:/pages/
spring.thymeleaf.suffix=.html
spring.thymeleaf.mode=HTML
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.cache=false
#启动aop
spring.aop.auto=true
mybatis.typeAliasesPackage=com.entity
#如果接口和Mapper.xml放在同一个包里面,则下面这句不需要。
mybatis.mapper-locations=classpath:/mapper/*Mapper.xml
server.port= 8080
package com.demo;
@SpringBootApplication
//@MapperScan("com.demo.dao")
//@ComponentScan("com.demo") //如果项目结构按照标准组织,此语句可以不要,具体还是根据项目来设计。
public class DemoWebApplication {
public static void main(String[] args) {
SpringApplication.run(DemoMyBatisWebApplication.class, args);
}
}
User.java。 User实体类,新建包com.entity在下面建立。
package com.entity;
public class User {
int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
String name;
int age;
}
相应的user表的sql脚本文件如下:
# Host: localhost (Version: 5.5.53)
# Generator: MySQL-Front 5.3 (Build 4.234)
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=95 DEFAULT CHARSET=utf8;
#
# Data for table "user"
#
/*!40000 ALTER TABLE `user` DISABLE KEYS */;
INSERT INTO `user` VALUES (4,'zhangsan',29),(5,'lishi',22);
/*!40000 ALTER TABLE `user` ENABLE KEYS */;
Mybatis注解方式
package com.demo.dao;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import com.entity.User;
@Mapper
public interface UserDaoMybatis { //注解方式实现
@Select("select * from user where id=#{id}")
User GetUserbyId(@Param("id") Integer id);
@Select("select * from user")
List<User> GetUsers();
}
Mybatis的xml实现
UserMapper接口
package com.demo.dao;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import com.entity.User;
@Mapper //此处注解表面是Mapper接口不是必须的,如果没有@Mapper注解需要在主程序配置@MapperSan指定
//Mapper接口的包位置
public interface UserMapper {
List<User> queryAllUser();
}
UserMapper.xml。在项目的src/main/resources下新建mapper文件夹将UserMapper.xml放置里面(也可以将UserMapper.xml和UserMapper接口 放在同一个包里面,但是不要忘记了要删除application.properties 中的mybatis.mapper-locations=classpath:/mapper/*Mapper.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.demo.dao.UserMapper">
<!--在配置文件中有mybatis.typeAliasesPackage=com.entity 所以resultType
中的User不需要写前面的包名
-->
<select id="queryAllUser" resultType="User">
select * from user
</select>
</mapper>
Controller测试(也可以在src/test/java下面的测试类中进行测试)。注意在queryAll方法中给出了不同的调用方式,这里提倡以注入接口方式调用,而不提倡用SqlSessin方式调用。
package com.demo.controller;
import java.util.List;
//..................
@Controller
@RequestMapping("user")
public class UserController {
@Autowired //注入sqlSession
SqlSession sqlSession;
@Autowired //注入dao对象,xml方式
private UserMapper userMapper;
@Autowired //注入dao对象,注解方式
private UserDaoMybatis userDaoMybatis;
@GetMapping("/showall")
public String queryAll(Model model,HttpSession session){
// 接口调用 xml配置
List<User> list = userMapper.queryAllUser();
// sqlSession直接调方法,不需要接口(不提倡),xml配置
// List<User> list=sqlSession.selectList("com.demo.dao.UserMapper.queryAllUser");
// sqlSession获得mapper对象后调用(不提倡),注解配置
// UserDaoMybatis mapper = sqlSession.getMapper(UserDaoMybatis.class);
//User user = (User) mapper.GetUserbyId(1);
// 接口调用
User user = userDaoMybatis.GetUserbyId(1);
if user==null{
user=new User();//防止user为空时页面模板解析错误
}
session.setAttribute("ssUser", user);
System.out.println(user);
model.addAttribute("userlist", list);
return "userlist";
}
@RequestMapping("/showallanno")
public String getuser(Model model) { // sqlSession直接调用方法
List<User> user=sqlSession.selectList("com.demo.dao.UserDaoMybatis.GetUsers");
//System.out.println(accountlist);
model.addAttribute("userlist",user);
return "userlist";
}
@RequestMapping("/showone")
public String getuserone(Model model) { // sqlSession获取mapper对象后调用方法
UserDaoMybatis mapper = sqlSession.getMapper(UserDaoMybatis.class);
User result = (User) mapper.GetUserbyId(1);
model.addAttribute("user",result);
return "oneuser";
}
}
前台页面 userlist.html 。这里我用了thymeleaf模板(也可以用jsp模板)
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:layout="http://www.ultraq.net.nz/web/thymeleaf/layout"
>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<table border="1" cellspacing="0">
<tr>
<th>姓名</th>
<th>年龄</th>
</tr>
<tr th:each="user : ${userlist}" >
<td th:text="${user.name}"></td>
<td th:text="${user.age}"></td>
</tr>
</table>
<br/>
<span>th:text不能够写出 th: text 中间不能用空格</span>
<div th:object="${session.ssUser}">
<p>姓名: <span th:text="*{name}" >Sebastian</span>. </p>
<p>年龄: <span th:text="*{age}" >Pepper</span>. </p>
</div>
<!-- <p>姓名: <span th:text="${session.ssUser.name}" ></span>. </p> -->
</div>
</body>
</html>
输出结果
姓名 | 年龄 |
---|---|
zhangsan | 29 |
lisi | 22 |
th:text不能够写出 th: text 中间不能用空格
姓名: zhangsan.
年龄: 29.