目标对象不可访问,需要通过动态代理对象增强功能访问

动态代理存在的意义

在三层架构中,业务逻辑层要通过接口访问数据访问层的功能,动态代理可以实现

我想要调用的是对应接口的方法,但又不想解析xml文件,调用方法直接用就完了我要的是功能,而不是sql语句所以动态代理可以解决这个问题

MyBaits中动态代理的实现规范

  • 1)UsersMapper.xml文件与UsersMapper.java的接口必须同一个目录下
  • 2)UsersMapper.xml文件与UsersMapper.java的接口的文件必须一致,后缀不管(必须都叫同一个名称)
  • 3)UsersMapper.xml文件中标签的id值UsersMapper.java的接口中方法的名称完全一致
  • 4)UsersMapper.xml文件中标签的parameterType的属性值与UsersMapper.java的接口中方法的参数类型完全一致
  • 5)UsersMapper.xml文件中resultType值与UsersMapper.java的接口中方法的返回值类型完全一致
  • 6)UsersMapper.xml文件中namespace的属性必须是接口的完全限定名称(com.chentianyu.mapper.UsersMapper)
  • 7)在SqlMapperConfig.xml(核心配置文件)文件中注册mapper文件时,使用class=接口的完全限定名称(com.chentianyu.mapper.UsersMapper)
  • 这么多一致就是把这个接口与xml标签绑在一起,全部做成一样的,调接口就是调用标签

创建项目

New Project->Maven->勾选Create from archetype->maven-archetype-quickstart->(projectName,路径,GroupId(包名)) -Next-> 默认(Finish)

动态代理访问的步骤
  • 创建Users
  • 新建maven工程,刷新可视化(IDEAIJ中最右Maven旁Database)
  • 修改目录
  • 修改pom.xml文件
    • 添加依赖
  • 添加jdbc.properties文件到resources目录下
  • 添加核心配置文件
  • 添加实体类
  • 添加mapper文件夹
    • 新建xxxmapper接口
  • mapper文件夹下
    • 新建xxxmaper.xml完成增删改查功能
  • 添加测试类,测试功能

创建Users
  1. USE ssm;
  2. -- ----
  3. -- Table structure for `users`
  4. -- -----
  5. DROP TABLE IF EXISTS `users`;
  6. CREATE TABLE `users`(`id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
  7. `username` VARCHAR(255) COMMENT '用户名称',
  8. `birthday` DATE DEFAULT NULL COMMENT '生日',
  9. `sex` CHAR(2) DEFAULT NULL COMMENT '性别',
  10. `address` VARCHAR(256) DEFAULT NULL COMMENT '地址'
  11. )ENGINE=INNODB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8;
  12. -- -----------
  13. -- Records of User
  14. -- -----------
  15. INSERT INTO `users` VALUES(1,"王五",'2000-09-10','1','安徽');#自增,但是可以直接给值
  16. INSERT INTO `users` VALUES(2,"李四",'2000-05-19','1','上海市');
  17. INSERT INTO `users` VALUES(3,"张三",'2000-07-03','1','北京');
  18. SELECT * FROM `users`;

IDEADataBase(最右边Maven旁边)'+'号,Data Source选择MySQL,选择用户名,密码和要连接的数据库名称-> Test Connection(测试)->OK

修改目录+pom.xml文件
  • resources
    • 项目根目录->src->main(new Directory(resources)) -> Mark Directory As(Resources Root)
    • 项目根目录->src->test(new Directory(resources)) -> Mark Directory As(Test Resources Root)
    • 删除自带的AppTest.javaApp.java
  • 创建pojo包,mapper包
    • 目录结构
      项目名
      |_.idea
      |_src
      |__main
      |___java
      |____com
      |_____chentianyu
      |______mapper
      |______pojo
      |__resources
      |___jdbc.properties
      |___mybatis.xml(核心配置文件)
      |_test
      |__java
      |___com
      |____chentianyu
      |__resources
      

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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.chentianyu</groupId>
  <artifactId>JDKDL_MyBatis_Learn_One</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>JDKDL_MyBatis_Learn_One</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <!--添加mybatis的依赖-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.9</version>
    </dependency>
    <!--添加mysql的依赖-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.28</version>
    </dependency>
  </dependencies>

  <build>
    <!--指定资源文件的位置-->
    <resources>
      <resource>
        <directory>src/main/java</directory>
        <includes>
          <include>**/*.xml</include>
          <include>**/*.properties</include>
        </includes>
      </resource>

      <resource>
        <directory>src/main/resources</directory>
        <includes>
          <include>**/*.xml</include>
          <include>**/*.properties</include>
        </includes>
      </resource>
    </resources>
  </build>
</project>

jdbc.properties

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm
jdbc.username=root
jdbc.password=自己的密码

mybatis.xml(核心配置文件)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybaits.org//Configuration 3.0//EN"
         "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!--读取jdbc.properties属性-->
    <properties resource="jdbc.properties"></properties>
    <!--设置日志输出-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
    <!--注册实体类的别名-->
    <typeAliases>
        <package name="com.chentianyu.pojo"/>
    </typeAliases>
    <!--配置环境变量-->
    <environments default="one">
        <environment id="one">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    <!--注册mapper.xml文件-->
    <mappers></mappers>
</configuration>

实体类构建
package com.chentianyu.pojo;

import java.util.Date;

public class Users {
    private Integer id;
    private String userName;//列名无所谓,类中成员变量必须大驼峰写法
    private Date birthday;
    private String sex;
    private String address;

    public Users() {
    }

    public Users(Integer id, String userName, Date birthday, String sex, String address) {
        this.id = id;
        this.userName = userName;
        this.birthday = birthday;
        this.sex = sex;
        this.address = address;
    }

    public Users(String userName, Date birthday, String sex, String address) {
        this.userName = userName;
        this.birthday = birthday;
        this.sex = sex;
        this.address = address;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

参数构造可以使用**alt+ins/alt+fn+ins**来构建构造方法和**getter and setter**

新建xxxmapper接口

UsersMapper.java

package com.chentianyu.mapper;

import com.chentianyu.pojo.Users;

import java.util.List;

/**
 * 数据访问层的接口,规定了数据库中可进行的各种操作
 */
public interface UsersMapper {
    //查询用户的全部信息
    List<Users> getAll();
}

UsersMapper.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.chentianyu.mapper.UsersMapper">
    <!--
    //查询全部用户信息
    List<Users> getAll()
    -->
    <select id="getAll" resultType="users">
        select * from users
    </select>
</mapper>

记得要在核心配置文件中注册Mappper

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybaits.org//Configuration 3.0//EN"
         "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
...
    <!--注册mapper.xml文件-->
    <mappers>
        <mapper class="com.chentianyu.mapper.UsersMapper"></mapper>
    </mappers>
</configuration>

测试

package com.chentianyu.test;

import com.chentianyu.mapper.UsersMapper;
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.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;

/**
 *
 */
public class MyTest {
    SqlSession sqlSession;
    @Before
    public void test01() throws IOException {
        InputStream in = Resources.getResourceAsStream("mybatis.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        sqlSession = factory.openSession();
    }
    @Test
    public void test02(){
        //重点: 取出代理的对象,完成接口中方法的调用,实则是调用xml文件中相同标签的功能
        UsersMapper uMapper = sqlSession.getMapper(UsersMapper.class);
        System.out.println(uMapper.getClass());
        //sqlSession.selectList("");
    }
    @After
    public void test03(){
        sqlSession.close();
    }
}

你会看到

class jdk.proxy2.$Proxy9

这就是jdk动态代理的类型

所以

package com.chentianyu.test;import com.chentianyu.mapper.UsersMapper;import com.chentianyu.pojo.Users;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.After;import org.junit.Before;import org.junit.Test;import java.io.IOException;import java.io.InputStream;import java.util.List;/** * */public class MyTest {    SqlSession sqlSession;    @Before    public void test01() throws IOException {        InputStream in = Resources.getResourceAsStream("mybatis.xml");        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);        sqlSession = factory.openSession();    }    @Test    public void test02(){        //重点: 取出代理的对象,完成接口中方法的调用,实则是调用xml文件中相同标签的功能        UsersMapper uMapper = sqlSession.getMapper(UsersMapper.class);        System.out.println(uMapper.getClass());        //List<Users> list = sqlSession.selectList("");        //就是在调试接口的方法,mybatis框架已经为我们把功能代理出来了        List<Users> list = uMapper.getAll();        list.forEach(users -> System.out.println(users));    }    @After    public void test03(){        sqlSession.close();    }}

用户更新
package com.chentianyu.mapper;import com.chentianyu.pojo.Users;import java.util.List;/** * 数据访问层的接口,规定了数据库中可进行的各种操作 */public interface UsersMapper {    //查询全部用户信息    List<Users> getAll();    //根据用户主键查用户    //根据用户名模糊查询用户    //用户更新    int update(Users users);    //添加用户    //根据主键删除用户}

UsersMapper.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.chentianyu.mapper.UsersMapper">    <!--    //查询全部用户信息    List<Users> getAll()    -->    <select id="getAll" resultType="users">        select * from users    </select>    <!--    //用户更新    int update(Users users);    private Integer id;    private String userName;    private Date birthday;    private String sex;    private String address;    -->    <update id="update" parameterType="users">        update users set username=#{userName},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id}    </update></mapper>

测试类

public class MyTest {
    SqlSession sqlSession;
    UsersMapper uMapper;
    @Before
    public void test01() throws IOException {
        InputStream in = Resources.getResourceAsStream("mybatis.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        sqlSession = factory.openSession();
        uMapper = sqlSession.getMapper(UsersMapper.class);
    }
    @Test
    public void test02(){
        //重点: 取出代理的对象,完成接口中方法的调用,实则是调用xml文件中相同标签的功能
        System.out.println(uMapper.getClass());
        //List<Users> list = sqlSession.selectList("");
        //就是在调试接口的方法,mybatis框架已经为我们把功能代理出来了
        List<Users> list = uMapper.getAll();
        list.forEach(users -> System.out.println(users));
    }
    @After
    public void test03(){
        sqlSession.close();
    }

    @Test
    public void testUpdate01(){
        Users users = new Users(2,"haha",new Date(),"2","北京");
        int num = uMapper.update(users);
        System.out.println(num);
        //切记: 手工提交
        sqlSession.commit();
    }
}

可以是可以,就是我们不能一直这么去获取**你当前的时间**,得用**格式刷**

public class MyTest {
    SqlSession sqlSession;
    //动态代理对象
    UsersMapper uMapper;
    //日期的格式化刷子
    SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
    @Before
    public void test01() throws IOException {
        InputStream in = Resources.getResourceAsStream("mybatis.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        sqlSession = factory.openSession();
        uMapper = sqlSession.getMapper(UsersMapper.class);
    }
    @Test
    public void test02(){
        //重点: 取出代理的对象,完成接口中方法的调用,实则是调用xml文件中相同标签的功能
        System.out.println(uMapper.getClass());
        //List<Users> list = sqlSession.selectList("");
        //就是在调试接口的方法,mybatis框架已经为我们把功能代理出来了
        List<Users> list = uMapper.getAll();
        list.forEach(users -> System.out.println(users));
    }
    @After
    public void test03(){
        sqlSession.close();
    }

    @Test
    public void testUpdate01() throws ParseException {
        Users users = new Users(2,"haha6",sf.parse("2000-01-02"),"2","北京");
        int num = uMapper.update(users);
        System.out.println(num);
        //切记: 手工提交
        sqlSession.commit();
    }
}

Ctrl+p(查看方法返回值)

根据主键id查询用户

UsersMapper.java

public interface UsersMapper {    //查询全部用户信息    List<Users> getAll();    //根据用户主键查用户    Users getById(Integer id);    //根据用户名模糊查询用户    //用户更新    int update(Users users);    //添加用户    //根据主键删除用户}

UsersMapper.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.chentianyu.mapper.UsersMapper">....    <!--    //根据用户主键查用户    Users getById();    -->    <select id="getById" resultType="users" parameterType="int">        select * from users where id=#{id}    </select></mapper>

测试类

public class MyTest {    SqlSession sqlSession;    //动态代理对象    UsersMapper uMapper;    //日期的格式化刷子    SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");    @Before    public void test01() throws IOException {        InputStream in = Resources.getResourceAsStream("mybatis.xml");        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);        sqlSession = factory.openSession();        uMapper = sqlSession.getMapper(UsersMapper.class);    }    ...    @Test    public void testSelectById(){        Users users = uMapper.getById(3);        System.out.println(users);    }}

根据用户名模糊查询
public interface UsersMapper {
....
    //根据用户名模糊查询用户
    List<Users> getLikeByName(String name);
...
}
<?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.chentianyu.mapper.UsersMapper">
....
    <!--
    //根据用户名模糊查询用户
    List<Users> getLikeByName(String name);
    -->
    <select id="getLikeByName" resultType="users" parameterType="string">
        select * from users where username like "%${name}%"
    </select>
</mapper>

测试

@Test
public void testGetByName(){
    List<Users> list = uMapper.getLikeByName("三");
    list.forEach(users -> System.out.println(users));
}

增加用户
/** * 数据访问层的接口,规定了数据库中可进行的各种操作 */public interface UsersMapper {    ....    //添加用户    int insertUsers(Users users);    //根据主键删除用户}
<?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.chentianyu.mapper.UsersMapper">
....
    <!--
    //添加用户
    Users insertUsers(Users users);
    private String userName;
    private Date birthday;
    private String sex;
    private String address;
    -->
    <insert id="insertUsers" parameterType="users">
        insert into users(username,birthday,sex,address) values(#{userName},#{birthday},#{sex},#{address})
    </insert>
</mapper>

测试

@Test
public void testInsertUsers() throws ParseException {
    int num = uMapper.insertUsers(new Users("李明", sf.parse("2001-02-05"), "1", "大兴"));
    System.out.println(num);
    sqlSession.commit();
}

根据主键删除用户
public interface UsersMapper {
    ...
    //根据主键删除用户
    int deleteUsers(Integer id);
}
<?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.chentianyu.mapper.UsersMapper">
....
    <!--
    //根据主键删除用户
    int deleteUsers(Integer id);
    -->
    <delete id="deleteUsers" parameterType="int">
        delete from users where id=#{id}
    </delete>
</mapper>

测试

@Test
public void testDeleteUsers(){
    int num = uMapper.deleteUsers(29);
    System.out.println(num);
    sqlSession.commit();
}