Mybatis逆向工程(代码生成器)及其简单使用——及其报错处理
Mybatis逆向工程(代码生成器)及其简单使用——及其报错处理
Mybatis逆向工程仅仅针对单表操作
一、测试用数据库表
drop table if exists t_student;
create table t_student
(
id int(10) not null auto_increment,
name varchar(20) null,
age int(10) null,
constraint PK_T_STUDENT primary key clustered (id)
);
insert into t_student(name,age) values("zhangsan",25);
insert into t_student(name,age) values("lisi",28);
insert into t_student(name,age) values("wangwu",23);
insert into t_student(name,age) values("Tom",21);
insert into t_student(name,age) values("Jck",55);
insert into t_student(name,age) values("Lucy",27);
insert into t_student(name,age) values("zhaoliu",75);
二、逆向工程配置文件(代码生成器)
GeneratorMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<!--
Mybatis逆向工程配置文件
-->
<generatorConfiguration>
<!--
指定连接数据库的 JDBC 驱动包所在位置(必须存在),
指定到你本机的完整路径
注意:此驱动包和pom文件中引入的mysql连接依赖必须兼容,最好同一个版本
-->
<classPathEntry location="D:IDEA_ProjectSpringBootspringboot11mysql-connector-java-8.0.26.jar"/>
<!-- 配置 table 表信息内容体,targetRuntime 指定采用 MyBatis3 的版本 -->
<context id="tables" targetRuntime="MyBatis3">
<!--
用于生成model实体类中生成toString方法
plugin标签必须放在context标签下开始地方,放在后边会报错
-->
<plugin type="org.mybatis.generator.plugins.ToStringPlugin" />
<!--
当我们生成实体类以后,发现默认是没有toString和序列化,
但是很多时候需要序列化对象,从而方便在网络上传输
-->
<plugin type="org.mybatis.generator.plugins.SerializablePlugin" />
<!-- 抑制生成注释,由于生成的注释都是英文的,可以不让它生成 -->
<commentGenerator>
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<!-- 配置数据库连接信息 -->
<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/springboot"
userId="root"
password="admin">
</jdbcConnection>
<!--
生成 model 类,
targetPackage 指定 model 类的包名,
targetProject 指定生成的 model 放在 eclipse 的哪个工程下面
-->
<javaModelGenerator targetPackage="com.example.springboot13.model"
targetProject="src/main/java">
<property name="enableSubPackages" value="false"/>
<property name="trimStrings" value="false"/>
</javaModelGenerator>
<!--
生成 MyBatis 的 Mapper.xml 文件,
targetPackage 指定 mapper.xml 文件的包名,
targetProject 指定生成的 mapper.xml 放在 eclipse 的哪个工程下面
-->
<sqlMapGenerator targetPackage="com.example.springboot13.mapper"
targetProject="src/main/java">
<property name="enableSubPackages" value="false"/>
</sqlMapGenerator>
<!--
生成 MyBatis 的 Mapper 接口类文件
targetPackage 指定 Mapper 接口类的包名,
targetProject 指定生成的 Mapper 接口放在 eclipse 的哪个工程下面
-->
<javaClientGenerator type="XMLMAPPER"
targetPackage="com.example.springboot13.mapper"
targetProject="src/main/java">
<property name="enableSubPackages" value="false"/>
</javaClientGenerator>
<!--
数据库表名及对应的 Java 模型类名(实体类)
一个table标签代表一张表
-->
<table
tableName="t_student"
domainObjectName="Student"
enableCountByExample="false"
enableUpdateByExample="false"
enableDeleteByExample="false"
enableSelectByExample="false"
selectByExampleQueryId="false"
/>
</context>
</generatorConfiguration>
三、 添加逆向工程插件:
<!--mybatis代码自动生成插件(逆向工程插件)-->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.4.0</version>
<configuration>
<!--(逆向工程)配置文件位置-->
<configurationFile>GeneratorMapper.xml</configurationFile>
<verbose>true</verbose>
<overwrite>true</overwrite>
</configuration>
</plugin>
总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.5.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>springboot13</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!--修改父工程管理依赖的版本号-->
<properties>
<java.version>11</java.version>
<!--可以在此处声明mysql版本号,如果不声明则是默认版本-->
<!--eg<mysql.version>5.1.9</mysql.version>-->
</properties>
<dependencies>
<!--SpringBoot框架web项目起步依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--MySQL驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--MyBatis整合SpringBoot框架的起步依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
<!--SpringBoot框架测试依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<!--
手动指定文件夹为 resources
因为IDEA编译默认只编译java文件,而mapper包下的xxmapper.xml
文件是不能自动编译的,所以在target中查看发现并没有被编译,运行错误!
-->
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
<plugins>
<!--mybatis代码自动生成插件(逆向工程插件)-->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.4.0</version>
<configuration>
<!--(逆向工程)配置文件位置-->
<configurationFile>GeneratorMapper.xml</configurationFile>
<verbose>true</verbose>
<overwrite>true</overwrite>
</configuration>
</plugin>
<!--SpringBoot项目编译打包插件-->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
四、自动生成文件
注意保证配置文件不能出错(字段,mysql驱动包这些不能弄错),双击生成
五、生成文件报错处理:
1、如name,age等字段不能识别,就选择配置数据源
配置文件中配置数据源或者在下图所示配置也行
2、如下图错误则根据下图修改:
删除红框中的sql以及sql后边的竖线“|”
ok!
六、生成的代码Mapper.xml(简单复习)
StudentMapper.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.example.springboot11.mapper.StudentMapper">
<resultMap id="BaseResultMap" type="com.example.springboot11.model.Student">
<!--
column:数据库中的字段名称
jdbcType:数据库中对应的字段类型(可省略不写)
property:映射对象的属性名称
-->
<!--
resultMap作用:
1.当数据库中的字段名称与实体类的对象属性名不一致时可以进行转换
2.当前查询的结果没有对应一个表的时候可以自定义一个结果集映射查询结果
-->
<!--
如果数据库中字段名称由多个单词构成,通过Mybatis逆向工程生成的
对象属性名称会按照驼峰命名规则进行命名
其中:数据库中字段名称的多个单词是下划线连接的
数据库表字段名称 实体对象属性名称
user_name userName
username username
userName username
-->
<id column="id" jdbcType="INTEGER" property="id"/>
<result column="name" jdbcType="VARCHAR" property="name"/>
<result column="age" jdbcType="INTEGER" property="age"/>
</resultMap>
<!--
sql语句片段,将公共部分抽取出来
-->
<sql id="Base_Column_List">
id, name, age
</sql>
<!--id对应mapper接口中方法名-->
<select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
select
<include refid="Base_Column_List"/>
from t_student
where id = #{id,jdbcType=INTEGER}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
delete
from t_student
where id = #{id,jdbcType=INTEGER}
</delete>
<!--
写死的insert Sql语句
-->
<insert id="insert" parameterType="com.example.springboot11.model.Student">
insert into t_student (id, name, age)
values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, #{age,jdbcType=INTEGER})
</insert>
<!--
拼接的Sql (字段不一定都有)
suffixOverrides——去除多余的逗号
-->
<!--
parameterType="xxx"一般都是使用封装类型,很好第规避了
值为""的情况,所以只需要判断是否为null就行
-->
<insert id="insertSelective" parameterType="com.example.springboot11.model.Student">
insert into t_student
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">
id,
</if>
<if test="name != null">
name,
</if>
<if test="age != null">
age,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
#{id,jdbcType=INTEGER},
</if>
<if test="name != null">
#{name,jdbcType=VARCHAR},
</if>
<if test="age != null">
#{age,jdbcType=INTEGER},
</if>
</trim>
</insert>
<!--
选择性更新
和上边insert一个道理
-->
<update id="updateByPrimaryKeySelective" parameterType="com.example.springboot11.model.Student">
update t_student
<set>
<if test="name != null">
name = #{name,jdbcType=VARCHAR},
</if>
<if test="age != null">
age = #{age,jdbcType=INTEGER},
</if>
</set>
where id = #{id,jdbcType=INTEGER}
</update>
<update id="updateByPrimaryKey" parameterType="com.example.springboot11.model.Student">
update t_student
set name = #{name,jdbcType=VARCHAR},
age = #{age,jdbcType=INTEGER}
where id = #{id,jdbcType=INTEGER}
</update>
</mapper>
七、使用及其报错处理
新建如下包及类:
1、生成的mapper接口上加上**@Mapper注解**,也可以不加,而是在程序入口类加上注解:
@MapperScan(basePackages = "com.example.springboot13.mapper") //开启mapper扫描,扫描此包以及其子包
2、StudentService
public interface StudentService {
/**
* ----------------------------
* description: 根据学生ID查询学生
* create by: wang
* create date: 2021/12/24
*
* @Param: id
* @return: Student
* ----------------------------
*/
Student queryStudentById(Integer id);
}
3、StudentServiceImp
@Service
public class StudentServiceImp implements StudentService {
@Autowired
private StudentMapper studentMapper;
@Override
public Student queryStudentById(Integer id) {
/**
* ----------------------------
* description: 返回学生实体信息
* create by: wang
* create date: 2021/12/24
* @Param: [id]
* @return: com.example.springboot11.model.Student
* ----------------------------
*/
return studentMapper.selectByPrimaryKey(id);
}
}
4、测试用Controller
/**
* @ResponseBody
* 的作用其实是将java对象转为json格式的数据。
* @ResponseBody
* 注解的作用是将controller的方法返回的对象通过适当的转换器转换为指定的格式之后,
* 写入到response对象的body区,通常用来返回JSON数据或者是XML数据。
* 注意:在使用此注解之后不会再走视图处理器,而是直接将数据写入到输入流中,
* 他的效果等同于通过response对象输出指定格式的数据。
* <p>
* @ResponseBody既可以作用在类上也可以作用在方法上
* @ResponseBody 表示该方法的返回结果直接写入 HTTP response body 中,
* 一般在异步获取数据时使用【也就是AJAX】。
*/
@Controller
public class StudentController {
@Autowired
private StudentService studentService;
@RequestMapping(value = "/student/{id}")
@ResponseBody
public Object student(@PathVariable Integer id) {
Student student = studentService.queryStudentById(id);
return student;
}
}
5、测试结果
6、如果报错:
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.example.springboot13.mapper.StudentMapper.selectByPrimaryKey
可能是因为pom.xml文件的build标签下没有加上如下代码、导致不能扫描到mapper文件夹下的xxMapper.xml文件,因为xml属于资源文件,但是我们却放在java文件夹下面,后面会介绍怎么使生成的xml直接放在resources文件夹下
<!--
手动指定文件夹为 resources
因为IDEA编译默认只编译java文件,而mapper包下的xxmapper.xml
文件是不能自动编译的,所以在target中查看发现并没有被编译,运行错误!
-->
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
加入以后重新加载Maven项目,删除target文件夹,重新加载模块(项目),防止缓存没有更新
7、当然,也可以将mapper中的.mxl文件放在resources目录下(一般在resuorces目录下新建一个mapper文件夹存放xxMapper.xml文件(推荐))*
代码生成配置文件更改一下也可以自动生成到resources目录下:
<!--
生成 MyBatis 的 Mapper.xml 文件,
targetPackage 指定 mapper.xml 文件的包名,
targetProject 指定生成的 mapper.xml 放在哪个工程下面
-->
<sqlMapGenerator targetPackage="mapper"
targetProject="src/main/resources">
<property name="enableSubPackages" value="false"/>
</sqlMapGenerator>
并且在配置文件中加入以下配置:
# 指定mybatis映射文件路径,并不是指定编译路径,而是告诉你去哪里找
# IDEA编译会自动加入resources目录下的文件
mybatis.mapper-locations=classpath:mapper/*.xml
此时也能正常访问
如果出现如下图错误,并不影响项目运行
换用@Resources注解可以消除错误(按道理Autowired是没错的)
八、看看别人关于@Autowire注入报错解决方案:
1、添加@SuppressWarnings注解
的确有效,但是这个并不是解决问题,只是告诉IDEA忽略这种错误警告
简介:java.lang.SuppressWarnings是J2SE5.0中标准的Annotation之一。可以标注在类、字段、方法、参数、构造方法,以及局部变量上。
作用:告诉编译器忽略指定的警告,不用在编译完成后出现警告信息。
使用:
@SuppressWarnings(“”)
@SuppressWarnings({})
@SuppressWarnings(value={})根据sun的官方文档描述:
value -将由编译器在注释的元素中取消显示的警告集。允许使用重复的名称。忽略第二个和后面出现的名称。出现未被识别的警告名不是错误:编译器必须忽略无法识别的所有警告名。但如果某个注释包含未被识别的警告名,那么编译器可以随意发出一个警告。各编译器供应商应该将它们所支持的警告名连同注释类型一起记录。鼓励各供应商之间相互合作,确保在多个编译器中使用相同的名称。
示例:
· @SuppressWarnings(“unchecked”)
告诉编译器忽略 unchecked 警告信息,如使用List,ArrayList等未进行参数化产生的警告信息。
· @SuppressWarnings(“serial”)
如果编译器出现这样的警告信息:The serializable class WmailCalendar does notdeclare a static final serialVersionUID field of type long
使用这个注释将警告信息去掉。· @SuppressWarnings(“deprecation”)
如果使用了使用@Deprecated注释的方法,编译器将出现警告信息。
使用这个注释将警告信息去掉。· @SuppressWarnings(“unchecked”, “deprecation”)
告诉编译器同时忽略unchecked和deprecation的警告信息。
· @SuppressWarnings(value={“unchecked”, “deprecation”})
等同于@SuppressWarnings(“unchecked”, “deprecation”)
2、在mapper文件上添加@Repository注解
@Repository注解便属于最先引入的一批,它用于将数据访问层 (DAO 层 ) 的类标识为 Spring Bean。具体只需将该注解标注在 DAO类上即可
这是从spring2.0新增的一个注解,用于简化 Spring 的开发,实现数据访问
@repository需要在Spring中配置扫描包地址,然后生成dao层的bean,之后被注入到ServiceImpl中
3、在mapper文件上添加@Component注解
@Component把普通pojo实例化到spring容器中,相当于配置文件中的<bean id="" class=""/>
@Component是 @Service @Controller @Repository 的父注解 通过类路径扫描自动检测实现类
4、在mapper文件上添加@Mapper注解
使用@mapper后,不需要在spring配置中设置扫描地址,通过mapper.xml里面的namespace属性对应相关的mapper类,spring将动态的生成Bean后注入到ServiceImpl中。
以上解决方案都可以,但是如果用以上方案,那么我主程序类里面的**@MapperScan**注解又有什么用呢?,意义何在!
我们都知道,使用**@MapperScan**的目的是为了简化开发,不用每个mapper都去指定@Mapper注解,但是使用@MapperScan注解后却会爆红(虽然不影响执行,但是却让人一脸迷惑)
希望哪位大神给个关于这个问题的精确解释,欢迎留言,谢谢!!!!!!!
5、既然又想用@MapperScan,又不想写请其他注解该怎么办呢?
方法当然有:
A:忍受IDEA随便在你的代码上标红,能运行就行(反正我受不了)
B:使用**@Resource注解**代替@Autowired (也就是之前提到的解决方案)
@Resource
private StudentMapper studentMapper;
在大多数的应用场景下,@Resources都可以代替@Autowired
@Autowired注解 -【Spring底层原理】 (qq.com)