MyBatis
# MyBatis
## 一、简介
- 是一个 持久层(DAO) 框架
- 是一个ORM(Object Relation Mapping--> RowMapper)框架
- 对 持久层技术(JDBC)的封装
- **JDBC 是 Java 访问数据库的 唯一途径**
- 代码托管在[github](github.com)上
## 二、关于 持久层框架
- ORM 框架 对象关系映射
- 所有的ORM框架都是对JDBC的封装
- 所有的ORM框架关心的:
- 数据源(Datasource)
数据库连接信息
`url`,`driverClassName`,`username`,`password`
- SQL语句
Mybatis:程序员自己写
Hibernate: HQL ---》 SQL
- RM , 关系映射(表<-->实体类 一条数据<-->一个java对象 列 <--->类属性)
## 三、HelloWorld
### 0、建表、建库
```mysql
create database mybatis;
use mybatis;
create table t_user(
id int primary key auto_increment,
name varchar(200),
pwd varchar(200),
age int
);
```
### 1、添加dtd文件(选做)
1. mybatis-confit.dtd
> public id : -//mybatis.org//DTD Config 3.0//EN
2. mybatis-mapper.dtd
> public id :"-//mybatis.org//DTD Mapper 3.0//EN"
### 2、添加jar包
- mybatis.jar
- 数据库的jar包
### 3、配置config文件
在src(类加载路径)下,创建`mybatis-config.dtd`
填入以下内容
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "mybatis-3-config.dtd" >
<configuration>
<environments default="jdbc">
<environment id="jdbc">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="url"
value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value=""/>
</dataSource>
</environment>
</environments>
</configuration>
```
### 4、配置mapper文件
在 `day01.dao.mapper`下创建 `userMapper.xml`, 编写以下代码
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "mybatis-3-mapper.dtd" >
<mapper namespace="abc">
<insert id="ins">
insert into
t_user
(name,pwd,age)
values
('zhangsan','123',22)
</insert>
</mapper>
```
**在config中配置mapper**
```xml
<environments default="jdbc">
</environments>
<mappers>
<!-- 写的是路径-->
<mapper resource="day01/dao/mapper/userMapper.xml"/>
</mappers>
```
### 5、编写java代码
```java
package day01.test;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class HelloWorld {
public static void main(String[] args) {
// 创建Sq1Session的工厂
SqlSessionFactory sf = new SqlSessionFactoryBuilder()
.build(
// 参数是一个流,指定config文件的位置
HelloWorld.class
.getClassLoader()
.getResourceAsStream("mybatis-config.xml")
);
//Mybatis的核心类
// 打开一个会话/开启一个事务
SqlSession session = sf.openSession();
// 执行对应的sql语句
session.insert("abc.ins");
// 提交事务
session.commit();
System.out.println("over");
}
}
```
### 6、打开调试(debug)
加入log4j的jar包 以及 配置文件 将日志等级设置为debug
## 四、HelloWorld-2
前四步不变
### 1、编写dao接口
```java
package day01.dao;
public interface UserDao {
public void insertUser();
}
```
### 2、配置mapper文件
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "mybatis-3-mapper.dtd" >
<!-- namespace 写dao接口的包名.类名 -->
<mapper namespace="day01.dao.UserDao">
<!-- id值 写 dao接口中的方法名 -->
<insert id="insertUser">
insert into
t_user
(name,pwd,age)
values
('zhangsan','123',22)
</insert>
</mapper>
```
### 3、编写测试类
```java
package day01.test;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import day01.dao.UserDao;
public class HelloWorld2 {
public static void main(String[] args) {
// 创建Sq1Session的工厂
SqlSessionFactory sf = new SqlSessionFactoryBuilder()
.build(
// 参数是一个流,指定config文件的位置
HelloWorld2.class
.getClassLoader()
.getResourceAsStream("mybatis-config.xml")
);
//Mybatis的核心类
// 打开一个会话/开启一个事务
SqlSession session = sf.openSession();
// 获取dao实现类对象
UserDao userDao = session.getMapper(UserDao.class);
userDao.insertUser();
// 提交事务
session.commit();
System.out.println("over");
}
}
```
## 五、config文件
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "mybatis-3-config.dtd" >
<configuration>
<!-- 配置类的别名 -->
<typeAliases>
<!-- 为 day01.entity.User 取别名 叫做 User
所有使用day01.entity.User的地方都可以使用User代替-->
<!--<typeAlias type="day01.entity.User" alias="User"></typeAlias> -->
<!-- 为day01.entity包中的所有类取别名。别名就是简单类名 -->
<package name="day01.entity"></package>
</typeAliases>
<!--配置环境
myBatis 支持多数据源配置
default 指定了默认的数据源,值是某个数据源的id值
-->
<environments default="jdbc">
<!--配置一个数据源 id 是该数据源的唯一标志-->
<environment id="jdbc">
<!--事务管理器
type:jdbc
使用jdbc的方式管理事务
mybatis依赖于Connection对象管理事务
managed
如果设置为managed,mybatis将不再关心事务
事务的管理将交给其他容器(框架)(tomcat、spring)
-->
<transactionManager type="JDBC"></transactionManager>
<!--配置数据源/数据库连接信息
type:
pooled:池,使用数据库连接池管理connection
unpooled: 不使用连接池,每次访问数据库,获取新的
Connection
jndi :向其他容器(框架)要连接对象
-->
<dataSource type="POOLED">
<property name="url"
value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value=""/>
</dataSource>
</environment>
</environments>
<!--指定mapper文件的位置-->
<mappers>
<mapper resource="day01/dao/mapper/userMapper.xml"/>
</mappers>
</configuration>
```
## 六、mapper文件
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "mybatis-3-mapper.dtd" >
<!-- namespace
1. session.insert();
namespace可以随便写,insert方法的参数是namespace . id
2. dao.insert()
namespace必须是dao的 包名.类名
-->
<mapper namespace="day01.dao.UserDao">
<!--
1. session.insert();
id可以随便写,insert方法的参数是namespace . id
2. dao.insert()
id值 写 dao接口中的方法名
--》 id 值要唯一
--》 dao中不存在同名方法
--》 dao中的方法不能重载
-->
<insert id="insertUser">
insert into
t_user
(name,pwd,age)
values
('zhangsan','123',22)
</insert>
<!-- 根据id删除 注意:不写参数 -->
</mapper>
```
## 七、单表操作
### 1、基本增删改查操作
```xml
<!-- id值 写 dao接口中的方法名 -->
<insert id="insertUser">
insert into
t_user
(name,pwd,age)
values
('zhangsan','123',22)
</insert>
<!-- 根据id删除 注意:不写参数 -->
<delete id="delete">
delete
from
t_user
where
id = 5
</delete>
<update id="update">
update
t_user
set
name='abc'
where
id = 7
</update>
<!-- resultType结果的类型 -->
<select id="selectAll" resultType="day01.entity.User">
select
id,
name,
pwd,
age
from
t_user
</select>
```
```java
public void insertUser();
public void delete();
public void update();
public List<User> selectAll();
```
```java
SqlSession session = sf.openSession();
// 获取dao实现类对象
UserDao userDao = session.getMapper(UserDao.class);
userDao.insertUser();
userDao.update();
userDao.delete();
userList = userDao.selectAll();
System.out.println(userList);
// 提交事务
session.commit();
```
### 2、保存返回主键
```xml
<!--
useGeneratedKeys 启用保存返回主键功能
keyColumn 主键对应的列名
keyProperty 将主键值放入方法参数的哪个属性中
-->
<insert id="insert"
useGeneratedKeys="true"
keyColumn="id"
keyProperty="id"
>
insert into
t_user
(name,pwd,age)
values
(#{name},#{pwd},#{age})
</insert>
```
```java
User user = new User(null, "abc", "123", 99);
userDao.insert(user);
System.out.println(user.getId());
```
### 3、对象关系映射
#### 3-1、默认情况
**myBatis 会将查询结果封装成对象,对应关系是 将对应列的值放到同名属性中**
#### 3-2、使用重命名
```mysql
CREATE TABLE `t_user2` (
`id` int(11) NOT NULL DEFAULT '0',
`username` varchar(200) DEFAULT NULL,
`password` varchar(200) DEFAULT NULL,
`age` int(11) DEFAULT NULL
)
```
```java
package day01.entity;
public class User {
private Integer id;
private String name;
private String pwd;
private Integer age;
//get set
}
```
```xml
<select id="selectAll2" resultType="day01.entity.User">
select
id,
username as name,
password as pwd,
age
from
t_user2
</select>
```
#### 3-3、使用resultMap
```xml
<!--
1.位置:在insert/update。。。前面
2.作用:定义映射关系
3.id:resultMap的唯一标识
4.type:最终封装的对象类型
-->
<resultMap type="day01.entity.User" id="rm1">
<id column="id" property="id"/>
<result column="password" property="pwd"/>
<result column="age" property="age"/>
<result column="username" property="name"/>
</resultMap>
<select id="selectAll3" resultMap="rm1">
select
id,
username,
password,
age
from
t_user2
</select>
```
### 4、方法参数
**Mybatis dao方法支持写0个或者多个参数,但是官方建议最多写一个参数**
#### 4-1 对象类型参数
使用`#{xx}` 的方式 获取参数的属性值
\#将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。
${} $将传入的数据直接显示生成在sql中。
1. #方式能够很大程度防止sql注入,$方式无法防止Sql注入。
2. $方式一般用于传入数据库对象,例如传入表名。
3. 从安全性上考虑,能使用#尽量使用#来传参,因为这样可以有效防止SQL注入的问题。
#将值加双引号,$**直接传入不做处理**
```java
// dao 接口
public List<User> selectByUser(User user);
```
```xml
<!--mapper文件-->
<!--
使用#{name} 获取user参数的name属性的值
-->
<select id="selectByUser" resultType="User">
select
id,
name,
pwd,
age
from
t_user
where
name = #{name}
</select>
```
#### 4-2 map类型参数
用法 和 对象类型一致,只是 `#{}`中写的是 map的 key值
```java
//dao 接口
public List<User> selectByMap(Map<String, Object> map);
```
```java
SqlSessionFactory sf = new SqlSessionFactoryBuilder()
.build(Test01.class.getClassLoader().getResourceAsStream("mybatis-config.xml"));
SqlSession session = sf.openSession();
UserDao userDao = session.getMapper(UserDao.class);
Map<String, Object> map = new HashMap<String, Object>();
map.put("name", "zhangsan");
List<User> userList = userDao.selectByMap(map);
System.out.println(userList);
```
```xml
<!--mapper-->
<select id="selectByMap" resultType="User">
select
id,
name,
pwd,
age
from
t_user
where
name = #{name}
</select>
```
#### 4-3 简单类型参数
基本数据类型、包装类、字符串等等
```java
//dao 接口
public List<User> selectByName(String name);
```
```xml
<select id="selectByName" resultType="User">
select
id,
name,
pwd,
age
from
t_user
where
name = #{name}
</select>
```
如果dao方法参数只有一个,并且是简单类型
- `#{}`中的内容可以随便写
- 建议使用 参数名
- **万能写法(建议写法):** 配合dao接口中的一个注解使用
```java
//dao
// @Param("username") 为name参数取别名,叫做username
public List<User> selectByName2( @Param("username") String name);
```
```xml
<!--由于dao方法参数上加了 @Param("username") 注解,所以只能写#{username}-->
<select id="selectByName2" resultType="User">
select
id,
name,
pwd,
age
from
t_user
where
name = #{username}
</select>
```
#### 4-4 多个参数
**MyBatis 本身不建议写多个参数,官方文档中也不存在多个参数的例子**
1. 默认解决方案
```java
// dao接口
public List<User> selectByNameAndPwd(String name,String pwd);
```
```xml
<select id="selectByNameAndPwd" resultType="User">
select
id,
name,
pwd,
age
from
t_user
where
name = #{param1}/#{0}
and
pwd = #{param2}/#{1}
</select>
```
2. 万能解决方案
```java
public List<User> selectByNameAndPwd2(
@Param("username") String name,
@Param("password") String pwd);
```
```xml
<select id="selectByNameAndPwd2" resultType="User">
select
id,
name,
pwd,
age
from
t_user
where
name = #{username}
and
pwd = #{password}
</select>
```
## 八、动态SQL
**mybatis中提供了一系列的标签,用于生成动态sql**
### 1、if
```java
//dao接口
/**
* 条件查询,如果name不为null name作为查询条件,如果pwd不为null pwd作为查询条件,
* @param user
* @return
*/
public List<User> selectFuzzy(User user);
```
```xml
<!-- 在标签中获取参数的属性,不需要#{}
if 标签用法类似于jstl的c:if
-->
<select id="selectFuzzy" resultType="User">
select
id,
name,
pwd,
age
from
t_user
where
1=1
<if test="name != null">
and name = #{name}
</if>
<if test="pwd != null">
and pwd = #{pwd}
</if>
</select>
```
**案例**
```xml
<update id="update">
update
t_user
set
<if test="name != null">
name = #{name},
</if>
<if test="pwd != null">
pwd = #{pwd},
</if>
<if test="age != null">
age = #{age},
</if>
id = #{id}
where
id = #{id}
</update>
<select id="selectByAge" resultType="User">
select
<include refid="selCols"></include>
from
t_user
where
<if test="age != null">
age = #{age}
</if>
<if test="age == null">
age is null
</if>
</select>
```
### 2、where
```xml
<!-- 替代where关键字
删除多余的and|or
-->
<select id="selectFuzzy2" resultType="User">
select
id,
name,
pwd,
age
from
t_user
<where>
<if test="name != null">
and name = #{name}
</if>
<if test="pwd != null">
and pwd = #{pwd}
</if>
</where>
</select>
```
### 3、set
```xml
<!-- 替代set关键字
删除多余的逗号
-->
<update id="update">
update
t_user
<set>
<if test="name != null">
name = #{name},
</if>
<if test="pwd != null">
pwd = #{pwd},
</if>
<if test="age != null">
age = #{age},
</if>
</set>
where
id = #{id}
</update>
```
### 4、trim
- 在标签头 或者 尾添加内容
- 删除标签头 或者 标签尾的内容
```xml
<select id="selectFuzzy3" resultType="User">
select
id,
name,
pwd,
age
from
t_user
<trim prefix="where" prefixOverrides="and">
<if test="name != null">
and name = #{name}
</if>
<if test="pwd != null">
and pwd = #{pwd}
</if>
</trim>
</select>
<update id="update3">
update
t_user
<trim prefix="set" prefixOverrides="," >
<if test="name != null">
,name = #{name}
</if>
<if test="pwd != null">
,pwd = #{pwd}
</if>
<if test="age != null">
,age = #{age}
</if>
</trim>
where
id = #{id}
</update>
```
### 5、foreach
用于遍历
```xml
<!--
foreach
collection
如果参数类型是List -》 list
如果参数类型是数组 -》 array
如果参数类型是 对象,并且要遍历的是对象属性 -》 属性名
如果参数类型是 map,并且要遍历的是map中的某个值-》 map的key
item 每次遍历的元素的别名
separator 每次遍历的元素之间的分隔符
open 遍历开始前的字符
close 遍历结束后的字符
-->
<delete id="deleteBatch">
delete
from
t_user
where
id in
<!--(2,34,56,7,89,0)
2,34,56,7,89,0
c:foreach items="" var="d"
-->
<foreach collection="array" item="id"
separator="," open="(" close=")">
#{id}
</foreach>
</delete>
<delete id="deleteBatch2">
delete
from
t_user
where
id in
<foreach collection="deleteIds" item="id"
separator="," open="(" close=")">
#{id}
</foreach>
</delete>
```
```java
//dao 接口
public void deleteBatch(int[] ids);
public void deleteBatch2(Map<String, Integer[]> map);
```
### 6、bind
```java
/**
* 根据名字 模糊查询
* @param name
* @return
*/
public List<User> selectByNameFuzzy(@Param("name") String name);
```
```xml
<select id="selectByNameFuzzy" resultType="User">
<!-- 绑定一个变量n,n的值是 '%' + name + '%'-->
<bind name="n" value=" '%' + name + '%' "/>
select
<include refid="selCols"></include>
from
t_user
where
name like #{n}
</select>
```
### 7、choose-when-otherwise
```java
//dao 接口
public List<User> selectByAge2(@Param("age") String age);
```
```xml
<!--
注意转义 &
-->
<select id="selectByAge2" resultType="User">
select
<include refid="selCols"></include>
from
t_user
where
<choose>
<when test="age == -1">
1=1
</when>
<when test="age != null && age != '' ">
age = #{age}
</when>
<otherwise>
age is null
</otherwise>
</choose>
</select>
```
## 九、多表关系映射
### 1、准备工作
1. 建表
```mysql
set names utf8;
use mybatis;
create table t_hero_type(
id int primary key auto_increment,
name varchar(200)
)engine=Innodb default charset=utf8;
insert into t_hero_type (name) values ('AD');
insert into t_hero_type (name) values ('AP');
insert into t_hero_type (name) values ('ADC');
create table t_hero(
id int primary key auto_increment,
name varchar(200),
typeId int,
foreign key(typeId) references t_hero_type(id)
)engine=Innodb default charset=utf8;
insert into t_hero (name,typeId) values('jax',1);
insert into t_hero (name,typeId) values('gay',1);
insert into t_hero (name,typeId) values('cindera',2);
insert into t_hero (name,typeId) values('razi',2);
insert into t_hero (name,typeId) values('Catalina',3);
```
2. 实体类
```java
public class HeroType {
private Integer id;
private String name;
private Set<Hero> heros = new HashSet<Hero>();
// constructer
// get / set
}
public class Hero {
private Integer id;
private String name;
private HeroType heroType;
// constructer
// get / set
}
```
3. 多表查询
1. 笛卡尔积
将一张表的每条数据和另一张表的每条数据进行无条件连接
`select * from t_hero,t_hero_type`
2. 连接查询
将一张表的每条数据 和 另一张表的每条数据 根据 连接条件 进行连接
当且仅当 两条数据 满足 连接条件时 该数据才会作为 最终的 查询结果
**约定:from的表叫做 左表,连接的表叫做 右表**
1. 内连接 ( inner join )
所有的左表中能够在右表找到满足连接条件的数据
2. 左外连接 ( left join )
所有的左表中的数据,如果在右表中找不到对应的数据,右表的字段补NULL
3. 右外连接 (right join)
所有的右表中的数据,如果在左表中找不到对应的数据,左表的字段补NULL
**连接查询语法**
` 连接方式 表名 on 连接条件 `

### 2、多对一查询
从`t_hero` 查询 `t_hero_type`
最终查询的是Hero对象
#### 2-1 方式1
```xml
<!--
ht.id as 'heroType.id',
将查询结果中的ht.id列的名字 重命名为 heroType.id
即:将查询结果中的ht.id这个列对应到 Hero 的 heroType属性 的 id属性上
-->
<select id="selectAll" resultType="Hero">
select
h.id,
h.name,
h.typeId,
ht.id as 'heroType.id',
ht.name as 'heroType.name'
from
t_hero h
inner join t_hero_type ht on h.typeId = ht.id
</select>
```
#### 2-2 方式2 (**最常用**)
```xml
<resultMap type="Hero" id="rm2">
<id column="id" property="id"/>
<result column="name" property="name"/>
<!-- 配置多对一关系
property: 一方(Hero中的HeroType)的属性名
javaType: property 对应的属性的java类型
-->
<association property="heroType" javaType="HeroType">
<!-- 此处内容语法和外部的resultMap一致 ,用于映射一方对象-->
<id column="htid" property="id"/>
<result column="htname" property="name"/>
</association>
</resultMap>
<select id="selectAll2" resultMap="rm2">
select
h.id,
h.name,
h.typeId,
ht.id htid,
ht.name htname
from
t_hero h
inner join t_hero_type ht on h.typeId = ht.id
</select>
```
#### 2-3 方式3
```xml
<resultMap type="Hero" id="rm3">
<id column="id" property="id"/>
<result column="name" property="name"/>
<!--
resultMap
引用其他resultMap配置
如果其他的resultMap 配置在当前mapper文件中,
可以直接写resultMap的id值
如果其他的resultMap 配置在其他mapper文件中,
使用其他mapper文件的namespace.id
-->
<association property="heroType" javaType="HeroType" resultMap="day03.dao.HeroTypeDao.htrm">
</association>
</resultMap>
<select id="selectAll3" resultMap="rm3">
select
h.id,
h.name,
h.typeId,
ht.id htid,
ht.name htname
from
t_hero h
inner join t_hero_type ht on h.typeId = ht.id
</select>
```
**heroTypeMapper.xml**
```xml
<resultMap type="HeroType" id="htrm">
<id column="htid" property="id"/>
<result column="htname" property="name"/>
</resultMap>
```
#### 2-4 方式4(**不建议使用**)
```xml
<!--
select 另外一个查询的id
column 查询条件,对应当前查询的某个列
效率低。进行了多次查询,N + 1 次
1次: 所有的Hero对象
N次:每个Hero对象对应N次中的一次
-->
<resultMap type="Hero" id="rm4">
<id column="id" property="id"/>
<result property="name" column="name"/>
<association property="heroType"
javaType="HeroType"
select="day03.dao.HeroTypeDao.selectById"
column="typeId"
></association>
</resultMap>
<select id="selectAll4" resultMap="rm4">
select
id,
name,
typeId
from
t_hero
</select>
```
```xml
<resultMap type="HeroType" id="htrm">
<id column="htid" property="id"/>
<result column="htname" property="name"/>
</resultMap>
<select id="selectById" resultType="HeroType">
select
id,
name
from
t_hero_type
where
id = #{id}
</select>
```
### 3、一对多查询
从`t_hero_type` 查询 `t_hero`
最终查询的是HeroType对象
同样用三种方式(多对一的方式2到方式4),只是要将
1. `association`改成`Collection`
2. `javaType`改成`ofType`
## 十、分页
**可以使用MyBatis分页插件事件分页功能**
### 1、导入jar包
```xml
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>最新版本</version>
</dependency>
```
### 2、配置插件
**在config文件中。使用`plugin`配置分页插件**
```xml
<plugins>
<!-- com.github.pagehelper为PageHelper类所在包名 -->
<plugin interceptor="com.github.pagehelper.PageHelper">
<!-- 4.0.0以后版本可以不设置该参数 -->
<property name="dialect" value="mysql"/>
<!-- 设置为true时,如果pageSize=0或者RowBounds.limit = 0就会查询出全部的结果 -->
<!-- (相当于没有执行分页查询,但是返回结果仍然是Page类型)-->
<property name="pageSizeZero" value="true"/>
<!-- 3.3.0版本可用 - 分页参数合理化,默认false禁用 -->
<!-- 启用合理化时,如果pageNum小于1会查询第一页,
如果pageNum大于pages会查询最后一页 -->
<!-- 禁用合理化时,如果pageNum小于1或pageNum大于pages会返回空数据 -->
<property name="reasonable" value="true"/>
</plugin>
</plugins>
```
### 3、service代码
```java
PageHelper.startPage(2,3);
List<Hero> heroList = heroDao.selectAll5();
PageInfo<Hero> info = new PageInfo<Hero>(heroList);
System.out.println("当前页"+info.getPageNum());
System.out.println("上一页"+info.getPrePage());
System.out.println("下一页"+info.getNextPage());
System.out.println("总页数"+info.getPages());
System.out.println("数据总条数"+info.getTotal());
for (int i = 0; i < info.getList().size(); i++) {
Hero h = info.getList().get(i);
System.out.println(h);
}
```

浙公网安备 33010602011771号