<h2>回顾</h2>
1. mybatis框架介绍 mybatis是一款基于ORM思想设计的优秀的持久层框架,封装了jdbc实现细节,让开发者只关注sql本身。 ORM对象关系映射 对象:user实体类 关系:user表 映射:mybatis框架 2. mybatis的API Resources 读取mybatis核心配置文件 SqlSessionFactoryBuilder 构建mybatis工厂对象 SqlSessionFactory 生产会话对象 SqlSession 执行CRUD操作 3. mybatis映射文件 <select id="" parameterType="" resultType=""></select> <insert id="" parameterType=""></insert> <update id="" parameterType=""></update> <delete id="" parameterType=""></delete> 4. dao层开发 传统实现类 接口代理(动态代理) 5. mybatis查询 ResutlMap标签 多条件查询 @Param UserQuery 模糊查询 ${} statement concat("%",#{},"%") preparedStatement 主键返回 6. mybatis主配置文件 不需要手动编写,看懂即可
<h2>今日目标</h2>
1. 动态sql【重点】 2. 注解简化xml配置文件 crud 3. 员工查询案例(mybatis)【大作业】 分页 4. 分页插件【简化我们自己编写原始分页】 5. lombok 简化实体 getter、setter、toString... 6. mybatisX
动态SQL【重点】
* 先来看一个需求: find(UserQuery userQuery) 根据user对象[ name, email ]进行查询,将userQuery对象中不为空的属性作为查询条件 * 那么这时候就可能产生多个sql: 1) 如果用户名和邮箱不为空 select * from user where name= #{name} and email = #{email} 2) 如果用户名不为空 select * from user where name= #{name} 3)如果邮箱不为空 select * from user where email = #{email} 4)如果二个都为空 select * from user
像上面这样,需要根据不同的条件来执行不同的sql语句的情况,就需要用到动态sql。
导入java模块
if
* 查询findByUser1(UserQuery userQuery) 根据UserQuery对象(name email)中不为空的属性进行查询 * 需求: 如果name不为空 拼接上name 如果email不为空 拼接上email 如果两个都不为空 都拼上 如果都为空 查询所有
UserQuery
接口
public interface UserMapper { //修改 void update(User user); // 条件查询1 List<User> findUser1(UserQuery userQuery); }
映射
<!-- 动态sql if标签:用于判断表达式是否为真,如果为真,则执行标签的sql代码 在test判断字符串类型时,除了非空判断还需要增加非空串判断 where标签: 相当于 where 1=1 1)如果条件都不成立,那么where就不存在 2)如果条件成立一个,那么就把第一条条件and | or 关键字抹除 --> <select id="findUser1" resultType="User"> select * from user <where> <if test="name !=null and name !=''"> and name = #{name} </if> <if test="email !=null and email!=''"> and email = #{email} </if> </where> </select>
测试
// 条件查询1 @Test public void test01()throws Exception{ // 创建条件 UserQuery userQuery = new UserQuery(); userQuery.setName(""); userQuery.setEmail("jack@itcast.cn"); // 执行查询 List<User> list = userMapper.findUser1(userQuery); for (User user : list) { System.out.println(user); } }
总结
* if标签用于单分支条件判断, 相当于java中的if关键字 * where关键字作用: 1) 当where代码块中的条件都不成立的时候, where代码块不生效 2) 当where代码块中的条件至少有一个成立的时候 在代码块之前加入一个where关键字 当代码块以and|or开头的时候,它会帮你去掉第一个and|or
choose
* 查询findByUser2(UserQuery userQuery) 根据UserQuery对象(name email)中第一个不为空的属性进行查询 * 需求: 如果name有值,优先根据name查询 如果name没有值,再判断email是否有值,如果有就使用email查询 如果email也没有值,就什么查不到
接口
// choose标签 List<User> findUser2(UserQuery userQuery);
映射
<!-- 动态sql之choose标签 相当于 swtich when相当于 case + break otherwise相当于 default --> <select id="findUser2" resultType="User"> select * from user <where> <choose> <when test="name !=null and name !=''"> and name = #{name} </when> <when test="email !=null and email !=''"> and email = #{email} </when> <otherwise> and 1=2 </otherwise> </choose> </where> </select>
测试
// 条件查询2 @Test public void test02()throws Exception{ // 创建条件 UserQuery userQuery = new UserQuery(); // userQuery.setName("jack"); // userQuery.setEmail("jack@itcast.cn"); // 执行查询 List<User> list = userMapper.findUser2(userQuery); for (User user : list) { System.out.println(user); } }
总结
* choose 用于包含多个条件 * when 用于编写某个条件 * otherwise所有的when都判断失败时,进入此分支
set
根据uid进行更新一个user对象中不为空的属性
接口
//修改 set标签 void update(User user);
映射
<!-- 动态判断用户传递实体属性需要进行判断 ,使用if标签 set标签 1)去掉最后一个set代码块中 逗号 2)必须保证set代码至少一个条件成立 --> <update id="update" parameterType="com.itheima.domain.User"> update user <set> <if test="name !=null and name !=''"> name = #{name}, </if> <if test="password !=null and password !=''"> password = #{password}, </if> <if test="email !=null and email !=''"> email = #{email}, </if> <if test="birthday !=null"> birthday = #{birthday}, </if> </set> where uid = #{uid} </update>
测试
@Test public void testUpdate() throws IOException { //0. 模拟一个User,必须带着所有属性 User user = new User(); user.setName("传智111"); user.setPassword("admin1111"); // user.setEmail("admin1111@itcast.cn"); // user.setBirthday(new Date()); user.setUid(1); userMapper.update(user); }
总结
* update标签的作用: 1) 在代码块之前加入一个set关键字 2) 删除掉代码块中的最后一个,
foreach
根据uids( 多个uid )查询 一个对象的集合
select * from user where uid in (41,43,46);
* 标签用于遍历集合 <foreach collection="" open="" close="" item="" seperator=""></foreach> * 它的属性: • collection:代表要遍历的集合元素,注意如果遍历的是list集合,里面就写list,跟参数名无关,遍历的是一个array数组,collection="array", 遍历的是一个实体中的list|array的,collection="实体的属性名" • open:代表语句的开始部分,左括号 • close:代表结束部分,右括号 • item:代表遍历集合的每个元素,生成的变量名 • seperator:代表分隔符,逗号
查询实体
接口
// 根据多个id查询 List<User> findList1(List<Integer> uids); // 根据多个id查询 List<User> findList2(Integer[] uids); // 根据多个id查询 List<User> findList3(UserQuery userQuery);
映射
<!-- 根据多个id查询 遍历的是一个list集合,collection="list" --> <select id="findList1" resultType="User"> select * from user where uid in <foreach collection="list" open="(" close=")" separator="," item="uid"> #{uid} </foreach> </select> <!-- 遍历的是一个array数组,collection="array" --> <select id="findList2" resultType="User"> select * from user where uid in <foreach collection="array" open="(" close=")" separator="," item="uid"> #{uid} </foreach> </select> <!-- 遍历的是一个实体中的list|array的,collection="实体的属性名" --> <select id="findList3" resultType="User"> select * from user where uid in <foreach collection="uids" open="(" close=")" separator="," item="uid"> #{uid} </foreach> </select>
测试
// 根据多个id查询一 @Test public void test03()throws Exception{ // 准备查询的id集合 List<Integer> uids = new ArrayList<>(); uids.add(1); uids.add(3); uids.add(5); // 调用mapper查询 List<User> list = userMapper.findList1(uids); for (User user : list) { System.out.println(user); } } @Test public void test04()throws Exception{ Integer[] uids = {1,3,5}; // 调用mapper查询 List<User> list = userMapper.findList2(uids); System.out.println(list); } @Test public void test05()throws Exception{ // 查询条件 UserQuery userQuery = new UserQuery(); Integer [] uids = {1,3,5}; userQuery.setUids(uids); // 调用mapper查询 List<User> list = userMapper.findList3(userQuery); System.out.println(list); }
总结
* collection 会根据传入参数的类型不同而采用不同的值 集合---list 数组---array 实体---实体的属性
注解【会用】
使用注解书写SQL其实是对使用XML书写SQL的一种替代方式,其功能基本一致。
MyBatis常用注解
* @Insert:实现新增,代替了<insert></insert> * @Update:实现更新,代替了<update></update> * @Delete:实现删除,代替了<delete></delete> * @Select:实现查询,代替了<select></select> * @Result:实现结果集封装,代替了<result></result> * @Results:可以与@Result 一起使用,封装多个结果集,代替了<resultMap></resultMap>
增删改查
package com.itheima.mapper; import com.itheima.domain.User; import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Update; public interface UserMapperAnno { // 新增 @Insert("insert into user values(null,#{name},#{password},#{email},#{birthday})") void save(User user); // 修改 @Update("update user set name=#{name},password=#{password}," + "email=#{email},birthday=#{birthday} where uid = #{uid}") void update(User user); // 删除 @Delete("delete from user where uid = #{uid}") void delete(Integer uid); // 查询 @Select("select * from user where uid = #{uid}") User findByUid(Integer uid); }
package com.itheima.service; import com.itheima.domain.User; import com.itheima.domain.UserQuery; import com.itheima.mapper.UserMapper; import com.itheima.mapper.UserMapperAnno; import com.itheima.util.MybatisUtil; import org.apache.ibatis.session.SqlSession; import org.junit.After; import org.junit.Before; import org.junit.Test; import java.io.IOException; import java.util.ArrayList; import java.util.Date; import java.util.List; public class UserServiceAnno { private SqlSession sqlSession = null; private UserMapperAnno userMapperAnno = null; @Before//被这个注解标注的方法会在所有的测试方法之前执行 public void before() { sqlSession = MybatisUtil.getSqlSession(); userMapperAnno = sqlSession.getMapper(UserMapperAnno.class);//方法名 } @After//被这个注解标注的方法会在所有的测试方法之后执行 public void after() { MybatisUtil.close(sqlSession); } // 新增 @Test public void test01()throws Exception{ User user = new User(); user.setName("hehe"); user.setPassword("333"); user.setEmail("hehe@itcast.cn"); user.setBirthday(new Date()); userMapperAnno.save(user); } // 修改 @Test public void test02()throws Exception{ User user = new User(); user.setUid(14); user.setName("heihei"); user.setPassword("999"); user.setEmail("heihei@itcast.cn"); user.setBirthday(new Date()); userMapperAnno.update(user); } @Test public void test03()throws Exception{ userMapperAnno.delete(14); } @Test public void test04()throws Exception{ User user = userMapperAnno.findByUid(1); System.err.println(user); } }
结果映射
手动映射
// 查询 @Select("select uid as id ,name as username, password as pwd,email,birthday from user where uid = #{uid}") @Results({ @Result(column = "id",property = "uid",id = true), @Result(column = "username",property = "name"), @Result(column = "pwd",property = "password"), @Result(column = "email",property = "email"), @Result(column = "birthday",property = "birthday"), }) User findByUid(Integer uid);
案例【大作业】
编程风格
* 类名 首字母大写 驼峰命名 * 方法名 首字母小写 驼峰命名 * com.公司名.[项目名].包名 mapper -> dao service web domain util
环境搭建
准备数据环境
创建web模块,导入jar包
创建包结构
复制基础代码
启动测试
查询所有
需求分析
三层架构+mybatis实现案例
代码实现
index.jsp
EmpServlet
package com.itheima.web.servlet; import com.itheima.domain.Emp; import com.itheima.service.EmpService; import com.itheima.service.impl.EmpServiceImpl; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.List; @WebServlet("/EmpServlet") public class EmpServlet extends HttpServlet { protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 接收请求action参数 String action = request.getParameter("action"); // 判断 if (action.equals("findAll")) { this.findAll(request, response); } } private EmpService empService = new EmpServiceImpl(); // 查询所有 protected void findAll(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1.调用service查询 List<Emp> empList = empService.findAll(); // 2.将list存入request域 request.setAttribute("empList", empList); // 3.转发list.jsp request.getRequestDispatcher("/list.jsp").forward(request, response); } }
EmpService和实现
package com.itheima.service; import com.itheima.domain.Emp; import java.util.List; public interface EmpService { List<Emp> findAll(); }
package com.itheima.service.impl; import com.itheima.domain.Emp; import com.itheima.mapper.EmpMapper; import com.itheima.service.EmpService; import com.itheima.util.MyBatisUtil; import org.apache.ibatis.session.SqlSession; import java.util.List; public class EmpServiceImpl implements EmpService { @Override public List<Emp> findAll() { // 1.获取sqlSession SqlSession sqlSession = MyBatisUtil.openSession(); // 2.创建EmpMapper代理对象 EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class); // 3.查询list List<Emp> empList = empMapper.findAll(); // 4.释放资源 MyBatisUtil.close(sqlSession); // 5.返回结果 return empList; } }
EmpMapper
package com.itheima.mapper; import com.itheima.domain.Emp; import org.apache.ibatis.annotations.Select; import java.util.List; public interface EmpMapper { @Select("select * from emp") List<Emp> findAll(); }
list.jsp
分页查询【难点】
mysql分页
-- 语法: select * from 表名 limit 索引,每页个数 -- 索引公式: index = (当前页-1) × 每页个数
思路分析
PageInfo
package com.itheima.domain; import java.util.List; // 分页对象 public class PageInfo<E> { // 总记录数 private Integer total; // 总页数 private Integer pages; // 当前页结果集 private List<E> list; // 当前页 private Integer pageNum; // 每页个数 private Integer pageSize; // getter\setter方法 }
代码流程图
代码实现
index.jsp
EmpServlet
package com.itheima.web.servlet; import com.itheima.domain.Emp; import com.itheima.domain.PageInfo; import com.itheima.service.EmpService; import com.itheima.service.impl.EmpServiceImpl; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.List; @WebServlet("/EmpServlet") public class EmpServlet extends HttpServlet { protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 接收请求action参数 String action = request.getParameter("action"); // 判断 if (action.equals("findAll")) { this.findAll(request, response); } else if (action.equals("findByPage")) { this.findByPage(request, response); } } private EmpService empService = new EmpServiceImpl(); // 分页查询 protected void findByPage(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1.接收前端参数 String pageNumStr = request.getParameter("pageNum"); String pageSizeStr = request.getParameter("pageSize"); // 前端传递null值问题,提供默认值 if (pageNumStr == null || pageNumStr.equals("")) { pageNumStr = "1"; } if (pageSizeStr == null || pageSizeStr.equals("")) { pageSizeStr = "5"; } // 转换int类型 int pageNum = Integer.parseInt(pageNumStr); int pageSize = Integer.parseInt(pageSizeStr); // 2.调用service查询 PageInfo<Emp> pageInfo = empService.findByPage(pageNum, pageSize); // 3.存入request域 request.setAttribute("pageInfo", pageInfo); // 4.转发jsp request.getRequestDispatcher("/list2.jsp").forward(request, response); } }
EmpService和实现
PageInfo<Emp> findByPage(int pageNum, int pageSize);
@Override public PageInfo<Emp> findByPage(int pageNum, int pageSize) { // 创建代理对象 SqlSession sqlSession = MyBatisUtil.openSession(); EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class); // 1.查询总记录数 Integer total = empMapper.findCount(); // 2.计算总页数 Integer pages = (int) Math.ceil(total * 1.0 / pageSize); // 3.查询当前页结果集 Integer index = (pageNum - 1) * pageSize; List<Emp> empList = empMapper.findList(index, pageSize); // 释放资源 MyBatisUtil.close(sqlSession); // 4.返回并封装pageInfo PageInfo<Emp> pageInfo = new PageInfo<>(); pageInfo.setTotal(total); // 总记录数 pageInfo.setPages(pages); // 总页数 pageInfo.setList(empList); // 当前页结果集(数据) pageInfo.setPageNum(pageNum);// 当前页 pageInfo.setPageSize(pageSize);// 每页个数 return pageInfo; }
EmpMapper
// count(0) -> count(*) @Select("select count(0) from emp") Integer findCount(); @Select("select * from emp limit #{index},#{pageSize}") List<Emp> findList(@Param("index") Integer index,@Param("pageSize") int pageSize);
list2.jsp
分页插件【会用】
PageHelper 是国内非常优秀的一款开源的mybatis分页插件,它支持基本主流的常用的数据库,
他可以帮助程序员构建PageInfo对象,内部实现了分页逻辑,程序员可以直接使用。
添加插件
导入jar包
添加配置
在mybatis的主配置文件的environments上方加入下面配置
<plugins> <plugin interceptor="com.github.pagehelper.PageInterceptor"> <property name="autoRuntimeDialect" value="true"/> </plugin> </plugins>
内置分页对象
编写代码
删除分页对象
EmpServlet
EmpServiceImpl
插件原理
Lombok
Lombok提供了简单的注解的形式来帮助我们简化消除一些必须有但显得很臃肿的 java 代码。
通过使用对应的注解,可以在编译源码(java->class)的时候生成对应的方法,所以不会影响任何运行效率。
常用的 Lombok注解
* @Data:注解在类上;生成toString,getter/setter * @NoArgsConstructor:注解在类上;为类提供一个无参的构造方法 * @AllArgsConstructor:注解在类上;为类提供一个全参的构造方法
IDEA配置lombok插件支持
在设置setting 中找到plugins。在检索框中检索lom:
在setting中找到下图界面,在右侧红框出打钩:
重启idea,大功告成
项目中使用
导入jar包
修改实体类
MybatisX
MybatisX 是一款基于 IDEA 的快速开发插件,为效率而生,主要功能有:
-
Java 与 XML 调回跳转
-
Mapper 方法自动生成 XML
IDEA配置MybatisX插件支持
打开 IDEA,进入 File -> Settings -> Plugins -> Browse Repositories,输入
mybatisx
搜索并安装