MyBatis从入门到精通(二):MyBatis XML方式的基本用法之Select
最近在读刘增辉老师所著的《mybatis从入门到精通》一书,很有收获,于是将自己学习的过程以博客形式输出,如有错误,欢迎指正,如帮助到你,不胜荣幸!
1. 明确需求
书中提到的需求是一个基于角色的权限控制需求(rbac,即role-based access control),提到权限管理,相信大家都不陌生,因为大部分的系统都是需要权限管理的,我在上家公司负责的系统之一就是权限系统,设计思路和书中提到的差不多,大致描述如下:
1)权限点用来管理要控制权限的资源,比如某个页面,某个按钮。
2)创建一个角色,给这个角色分配某些权限点,比如商品模块的所有页面的权限。
3)新建一个用户,给这个用户分配某些角色。
数据关系图如下所示:
2. 数据准备
首先执行如下脚本创建上图中的5张表:用户表,角色表,权限表,用户角色关联表,角色权限关联表。
create table sys_user ( id bigint not null auto_increment comment '用户id', user_name varchar(50) comment '用户名', user_password varchar(50) comment '密码', user_email varchar(50) comment '邮箱', user_info text comment '简介', head_img blob comment '头像', create_time datetime comment '创建时间', primary key (id) ); alter table sys_user comment '用户表'; create table sys_role ( id bigint not null auto_increment comment '角色id', role_name varchar(50) comment '角色名', enabled int comment '有效标志', create_by bigint comment '创建人', create_time datetime comment '创建时间', primary key (id) ); alter table sys_role comment '角色表'; create table sys_privilege ( id bigint not null auto_increment comment '权限id', privilege_name varchar(50) comment '权限名称', privilege_url varchar(200) comment '权限url', primary key (id) ); alter table sys_privilege comment '权限表'; create table sys_user_role ( user_id bigint comment '用户id', role_id bigint comment '角色id' ); alter table sys_user_role comment '用户角色关联表'; create table sys_role_privilege ( role_id bigint comment '角色id', privilege_id bigint comment '权限id' ); alter table sys_role_privilege comment '角色权限关联表';
然后执行如下脚本添加测试数据:
insert into sys_user values (1,'admin','123456','admin@mybatis.tk','管理员',null,current_timestamp); insert into sys_user values (1001,'test','123456','test@mybatis.tk','测试用户',null,current_timestamp); insert into sys_role values (1,'管理员',1,1,current_timestamp); insert into sys_role values (2,'普通用户',1,1,current_timestamp); insert into sys_user_role values (1,1); insert into sys_user_role values (1,2); insert into sys_user_role values (1001,2); insert into sys_privilege values (1,'用户管理','/users'); insert into sys_privilege values (2,'角色管理','/roles'); insert into sys_privilege values (3,'系统日志','/logs'); insert into sys_privilege values (4,'人员维护','/persons'); insert into sys_privilege values (5,'单位维护','/companies'); insert into sys_role_privilege values (1,1); insert into sys_role_privilege values (1,2); insert into sys_role_privilege values (1,3); insert into sys_role_privilege values (2,4); insert into sys_role_privilege values (2,5);
3. 创建实体类
在包com.zwwhnly.mybatisaction.model下依次创建这5张表对应的实体类:
package com.zwwhnly.mybatisaction.model; import java.util.date; /** * 用户表 */ public class sysuser { /** * 用户id */ private long id; /** * 用户名 */ private string username; /** * 密码 */ private string userpassword; /** * 邮箱 */ private string useremail; /** * 简介 */ private string userinfo; /** * 头像 */ private byte[] headimg; /** * 创建时间 */ private date createtime; // 按alt+insert快捷键生成get和set方法 }
package com.zwwhnly.mybatisaction.model; import java.util.date; /** * 角色表 */ public class sysrole { /** * 角色id */ private long id; /** * 角色名 */ private string rolename; /** * 有效标志 */ private integer enabled; /** * 创建人 */ private long createby; /** * 创建时间 */ private date createtime; // 按alt+insert快捷键生成get和set方法 }
可以参考类似的命名方式创建sysprivilege.java,sysuserrole.java,sysroleprivilege.java。
也可以按照文末提供的源码地址下载下源代码。
注意事项:
1)mybatis默认遵循“下划线转驼峰”命名方式。
如sys_user表对应的实体类名是sys_user,数据库字段user_name对应的实体类字段是username。
2)在实体类中不要使用java的基本类型,基本类型包括byte、int、short、long、float、doubule、char、boolean。
因为java中的基本类型会有默认值,例如当某个类中存在private int age;字段时,age的默认值为0,所以无法满足age为null的情况,如果使用age !=null,结果总为ture,会导致一些隐藏的bug。
4. 创建mapper.xml文件
在src/main/resources下的com/zwwhnly/mybatisaction/mapper目录下依次创建5张表对应的mapper.xml文件。
为了后续更快速的创建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> </mapper>
然后选中目录,右键新增文件,如下图所示:
刚生成的sysusermapper.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> </mapper>
我们只需要给mapper标签添加个namespace属性即可:
<?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.zwwhnly.mybatisaction.mapper.sysusermapper"> </mapper>
按照同样的方式依次创建sysrolemapper.xml,sysprivilegemapper.xml,sysuserrolemapper.xml和sysroleprivilegemapper.xml。
创建完成后,打开我们在上篇博客中创建的mybatis-config.xml文件,修改
使用这种方式,最明显的缺点就是,我们后续如果新增了mapper.xml文件,仍然需要来修改文件,非常不好维护,因此我们修改成如下配置方式,配置一个包名: 修改完成后,运行上篇博客中的单元测试countrymappertest,发现执行报如下错误: 报错的原因是上篇博客中,我们并没有为countrymapper.xml文件创建对应的接口,使用包名配置方式后,就需要创建,所以解决方案就是在src/main/java下新建包com.zwwhnly.mybatisaction.mapper下,然后在该包下新建接口countrymapper,然后在接口中添加方法selectall()。 找到src/main/java目录下的包com.zwwhnly.mybatisaction.mapper,在该包下创建xml文件对应的接口类,分别为sysusermapper.java,sysrolemapper.java,sysprivilegemapper.java,sysuserrolemapper.java,sysroleprivilegemapper.java。 这里只展示下sysusermapper.java的代码: 注意事项:当mapper接口和xml文件关联的时候,命名空间namespace的值需要配置成接口的全限定名称,mybatis内部就是通过这个值将接口和xml关联起来的。 例如sysusermapper.xml中配置的namespace就com.zwwhnly.mybatisaction.mapper.sysusermapper 假设我们需要通过id查询用户的信息,首先,我们需要打开sysusermapper.java接口定义方法: 然后打开对应的sysusermapper.xml文件添加如下内容: 说明: 1)mybatis通过select标签的id属性值和接口的名称进行关联。 2)标签的id属性值不能出现英文句号"."。 3)标签的id属性值在同一个命名空间下不能重复。 4)因为接口方法是可以重载的,所以接口中可以出现多个同名但参数不同的方法,但是xml中id的值不能重复,因此接口中的所有同名方法会对应着xml中的同一个id的方法。 为了验证第2点,我们将selectbyid修改成select.byid: 此时如果调用该方法,会报如下错误: 为了验证第3点,我们将xml内容修改为如下: 此时如果调用该方法,会报如下错误: xml 代码讲解: resultmap标签用于配置java对象的属性和查询结果列的对应关系,通过resultmap中配置的column和property可以将查询列的值映射到type对象的属性上。 上面查询语句用到的resultmap标签讲解: 假设我们需要查询所有用户的信息,首先,我们需要打开sysusermapper.java接口定义方法: 然后打开对应的sysusermapper.xml文件添加如下内容: 注意事项:这里我们并没有使用resultmap属性来设置要返回结果的类型,而是通过resulttype属性直接指定 要返回结果的类型,使用此种方式需要设置查询列的别名,别名要和resulttype指定对象的属性名保持一致, 进而实现自动映射。 mybatis提供了一个全局属性mapunderscoretocamelcase,将这个属性的值设置为ture可以自动将以下划线命名的数据库列映射到java对象的驼峰式命名属性中。 那么如何打开呢? 方法是打开我们在上篇博客中新建的mybatis-config文件,在settings节点添加如下配置: 此时,前面的selectall语句可以简化为如下。 新建基础测试类basemappertest,代码如下。 将上篇博客中的countrymappertest类代码修改为如下。 修改点: 1)继承基础测试类basemappertest,调用基类getsqlsession()方法即可获取sqlsession对象,实现代码重用。 2)selectlist()方法的参数值由selectall修改为com.zwwhnly.mybatisaction.mapper.countrymapper.selectall, 因为在sysusermapper中也添加了一个selectall()方法,selectall不再唯一,因此调用时必须带上namespace。 参考countrymappertest测试类新建sysusermappertest测试类,代码如下。 运行测试类代码,测试通过,输出日志如下所示。 debug [main] - ==> preparing: select id, user_name, user_password, user_email, user_info, head_img, create_time from sys_user debug [main] - ==> parameters: trace [main] - <== columns: id, user_name, user_password, user_email, user_info, head_img, create_time trace [main] - <== row: 1, admin, 123456, admin@mybatis.tk, <
trace [main] - <== row: 1001, test, 123456, test@mybatis.tk, <
debug [main] - <== total: 2 debug [main] - ==> preparing: select * from sys_user where id = ? debug [main] - ==> parameters: 1(long) trace [main] - <== columns: id, user_name, user_password, user_email, user_info, head_img, create_time trace [main] - <== row: 1, admin, 123456, admin@mybatis.tk, <
debug [main] - <== total: 1 源码地址:,欢迎下载。 刘增辉《mybatis从入门到精通》<mappers>
<mapper resource="com/zwwhnly/mybatisaction/mapper/countrymapper.xml"/>
<mapper resource="com/zwwhnly/mybatisaction/mapper/sysusermapper.xml"/>
<mapper resource="com/zwwhnly/mybatisaction/mapper/sysrolemapper.xml"/>
<mapper resource="com/zwwhnly/mybatisaction/mapper/sysprivilegemapper.xml"/>
<mapper resource="com/zwwhnly/mybatisaction/mapper/sysuserrolemapper.xml"/>
<mapper resource="com/zwwhnly/mybatisaction/mapper/sysroleprivilegemapper.xml"/>
</mappers>
<mappers>
<package name="com.zwwhnly.mybatisaction.mapper"/>
</mappers>
package com.zwwhnly.mybatisaction.mapper;
import com.zwwhnly.mybatisaction.model.country;
import java.util.list;
public interface countrymapper {
/**
* 查询全部国家
*
* @return
*/
list<country> selectall();
}
5. 创建mapper接口
package com.zwwhnly.mybatisaction.mapper;
public interface sysusermapper {
}
6. select用法
6.1 查询单条数据
/**
* 通过id查询用户
*
* @param id
* @return
*/
sysuser selectbyid(long id);
<resultmap id="sysusermap" type="com.zwwhnly.mybatisaction.model.sysuser">
<id property="id" column="id"/>
<result property="username" column="user_name"/>
<result property="userpassword" column="user_password"/>
<result property="useremail" column="user_email"/>
<result property="userinfo" column="user_info"/>
<result property="headimg" column="head_img" jdbctype="blob"/>
<result property="createtime" column="create_time" jdbctype="timestamp"/>
</resultmap>
<select id="selectbyid" resultmap="sysusermap">
select * from sys_user where id = #{id}
</select>
<select id="select.byid" resultmap="sysusermap">
select * from sys_user where id = #{id}
</select>
<select id="selectbyid" resultmap="sysusermap">
select * from sys_user where id = #{id}
</select>
<select id="selectbyid" resultmap="sysusermap">
select * from sys_user where id = #{id}
</select>
6.2 查询多条数据
/**
* 查询全部用户
*
* @return
*/
list<sysuser> selectall();
<select id="selectall" resulttype="com.zwwhnly.mybatisaction.model.sysuser">
select id,
user_name username,
user_password userpassword,
user_email useremail,
user_info userinfo,
head_img headimg,
create_time createtime
from sys_user
</select>
<settings>
<!--其他配置-->
<setting name="mapunderscoretocamelcase" value="true"/>
</settings>
<select id="selectall" resulttype="com.zwwhnly.mybatisaction.model.sysuser">
select id,
user_name,
user_password,
user_email,
user_info,
head_img,
create_time
from sys_user
</select>
7. 单元测试
package com.zwwhnly.mybatisaction.mapper;
import org.apache.ibatis.io.resources;
import org.apache.ibatis.session.sqlsession;
import org.apache.ibatis.session.sqlsessionfactory;
import org.apache.ibatis.session.sqlsessionfactorybuilder;
import org.junit.beforeclass;
import java.io.ioexception;
import java.io.reader;
/**
* 基础测试类
*/
public class basemappertest {
private static sqlsessionfactory sqlsessionfactory;
@beforeclass
public static void init() {
try {
reader reader = resources.getresourceasreader("mybatis-config.xml");
sqlsessionfactory = new sqlsessionfactorybuilder().build(reader);
reader.close();
} catch (ioexception e) {
e.printstacktrace();
}
}
public sqlsession getsqlsession() {
return sqlsessionfactory.opensession();
}
}
package com.zwwhnly.mybatisaction.mapper;
import com.zwwhnly.mybatisaction.model.country;
import org.apache.ibatis.session.sqlsession;
import org.junit.test;
import java.util.list;
public class countrymappertest extends basemappertest {
@test
public void testselectall() {
sqlsession sqlsession = getsqlsession();
try {
list<country> countrylist = sqlsession.selectlist("com.zwwhnly.mybatisaction.mapper.countrymapper.selectall");
printcountrylist(countrylist);
} finally {
sqlsession.close();
}
}
private void printcountrylist(list<country> countrylist) {
for (country country : countrylist) {
system.out.printf("%-4d%4s%4s\n", country.getid(), country.getcountryname(), country.getcountrycode());
}
}
}
package com.zwwhnly.mybatisaction.mapper;
import com.zwwhnly.mybatisaction.model.sysuser;
import org.apache.ibatis.session.sqlsession;
import org.junit.assert;
import org.junit.test;
import java.util.list;
public class sysusermappertest extends basemappertest {
@test
public void testselectbyid() {
sqlsession sqlsession = getsqlsession();
try {
sysusermapper sysusermapper = sqlsession.getmapper(sysusermapper.class);
sysuser sysuser = sysusermapper.selectbyid(1l);
assert.assertnotnull(sysuser);
assert.assertequals("admin", sysuser.getusername());
} finally {
sqlsession.close();
}
}
@test
public void testselectall() {
sqlsession sqlsession = getsqlsession();
try {
sysusermapper sysusermapper = sqlsession.getmapper(sysusermapper.class);
list<sysuser> sysuserlist = sysusermapper.selectall();
assert.assertnotnull(sysuserlist);
assert.asserttrue(sysuserlist.size() > 0);
} finally {
sqlsession.close();
}
}
}
8. 源码
9. 参考
推荐阅读
-
MyBatis从入门到精通(三):MyBatis XML方式的基本用法之多表查询
-
MyBatis从入门到精通(八):MyBatis动态Sql之foreach标签的用法
-
MyBatis从入门到精通(四):MyBatis XML方式的基本用法之增删改
-
MyBatis从入门到精通(七):MyBatis动态Sql之choose,where,set标签的用法
-
MyBatis从入门到精通(二):MyBatis XML方式的基本用法之Select
-
MyBatis从入门到精通(三):MyBatis XML方式的基本用法之多表查询
-
MyBatis从入门到精通(八):MyBatis动态Sql之foreach标签的用法
-
MyBatis从入门到精通(四):MyBatis XML方式的基本用法之增删改
-
MyBatis从入门到精通(七):MyBatis动态Sql之choose,where,set标签的用法
-
MyBatis从入门到精通(二):MyBatis XML方式的基本用法之Select