02【Spring注解开发、JdbcTemplate、整合Junit】

02【Spring注解开发、JdbcTemplate、整合Junit】

一、注解配置

相对于XML方式而言,通过注解的方式配置bean更加简洁和优雅,需要注意的是,注解配置和 xml 配置要实现的功能都是一样的,只是配置的形式不一样。

关于实际的开发中到底使用xml还是注解,每家公司有着不同的使用习惯。所以这两种配置方式我们都需要掌握。

1.1 使用xml方式配置增删改查

1.1.1 pom.xml:

<dependencies>
    
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.2.12.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.37</version>
    </dependency>

    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.2.1</version>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.18</version>
    </dependency>
    
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.9</version>
        <scope>test</scope>
    </dependency>
</dependencies>

1.1.2 实体类:

  • sql语句:
drop table if exists user;

CREATE TABLE `user`  (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户名',
  `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '密码',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

INSERT INTO `user` VALUES (1, 'admin', '111');
INSERT INTO `user` VALUES (2, 'root', '222');
INSERT INTO `user` VALUES (3, 'zhangsan', '333');
INSERT INTO `user` VALUES (4, 'lisi', '444');
  • 实体类:
package com.dfbz.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

    private Integer id;
    private String username;
    private String password;
}

1.1.3 controller

package com.dfbz.controller;

import com.dfbz.entity.User;
import com.dfbz.service.UserService;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class UserController {
    private UserService userService;

    public User findById(Integer id){
        return userService.findById(id);
    }

    // 提供set方法
    public void setUserService(UserService userService) {
        this.userService = userService;
    }
}

1.1.4 service

package com.dfbz.service;

import com.dfbz.dao.UserDao;
import com.dfbz.entity.User;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class UserService {

    private UserDao userDao;

    /**
     * 根据id查询用户
     * @param id
     * @return
     */
    public User findById(Integer id) {
        return userDao.findById(id);
    }

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
}

1.1.5 dao

package com.dfbz.dao;

import com.dfbz.entity.User;

import javax.sql.DataSource;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class UserDao {

    private DataSource dataSource;

    /**
     * 根据id查询用户
     *
     * @param id
     * @return
     */
    public User findById(Integer id) {

        try {
            PreparedStatement ps = dataSource.getConnection().prepareStatement("select * from user where id=?");
            ps.setInt(1, id);

            ResultSet rs = ps.executeQuery();

            if (rs.next()) {
                return new User(rs.getInt("id"), rs.getString("username"), rs.getString("password"));
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }

        return null;
    }

    // 提供set方法
    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }
}

1.1.6 配置文件

  • jdbc.properties:
jdbc.username=root
jdbc.password=admin
jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.driverClassName=com.mysql.jdbc.Driver
  • spring.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <!--加载jdbc.properties配置文件-->
    <context:property-placeholder location="jdbc.properties" />
    
    <!--配置数据源-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
        <property name="url" value="${jdbc.url}" />
        <property name="driverClassName" value="${jdbc.driverClassName}" />
    </bean>

    <!--配置userDao-->
    <bean id="userDao" class="com.dfbz.dao.UserDao">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <bean id="userService" class="com.dfbz.service.UserService">
        <!--注入userDao-->
        <property name="userDao" ref="userDao"></property>
    </bean>

    <bean id="userController" class="com.dfbz.controller.UserController">
        <!--注入userService-->
        <property name="userService" ref="userService" />
    </bean>
</beans>

1.2 常用注解

  • 1)普通组件:@Component

往IOC容器中添加一个普通组件;

  • 2)dao层组件:@Respository

往IOC容器中添加一个dao层组件;

  • 3)service层组件:@Service

往IOC容器中添加一个service层组件;

  • 4)controller层组件:@Controller

往IOC容器中添加一个controller组件;

其实Spring第一版注解的实现(spring 2.5),就是使用一个@Component。从3.0以后,作者认为根据分层的需要,把它拆成了四个。为了可以让开发人员,可见即可得,一看到注解,立即知道类的性质。所以分成了四个

注意:@Component、@Respository、@Service、@Controller这几个注解仅仅是为了让开发人员自己明确当前的组件扮演的角色。他们的作用及属性都是一模一样的,他们只不过是提供了更加明确的语义化。

组件命名规则

  • 默认情况:使用组件的简单类名首字母小写后得到的字符串作为bean的id

  • 使用组件注解的value属性指定bean的id

定义实体类:

package com.dfbz.entity;

import org.springframework.stereotype.Component;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */

// 定义一个组件类属于spring.xml中的<bean>
@Component
public class Book {

    private String id;
    private String name;
    private String price;
}

1.3 扫描组件

Spring3.0后为我们引入了组件自动扫描机制,它可以在指定包及子包底下寻找标注了@Component、@Service、@Controller、@Repository注解的类,并把这些类纳入进spring容器中管理。它的作用和在xml文件中使用bean节点配置组件是一样的。

  • spring.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <!--
        包扫描
        base-package:指定要扫码的包
    -->
    <context:component-scan base-package="com.dfbz" />
</beans>

1.4 组件装配

Controller组件中往往需要用到Service组件的实例,Service组件中往往需要用到Repository组件的实例。Spring可以通过注解的方式帮我们实现属性的装配。

1.4.1 改造xml方式代码

  • UserController:
package com.dfbz.controller;

import com.dfbz.entity.User;
import com.dfbz.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
@Component("userController")        // 注册UserController到IOC容器,id默认为类名首字母小写
public class UserController {
    
    // 装配UserService
    @Autowired      
    private UserService userService;

    public User findById(Integer id){
        return userService.findById(id);
    }

    // 不需要提供set方法
}
  • UserService:
package com.dfbz.service;

import com.dfbz.dao.UserDao;
import com.dfbz.entity.User;
import org.springframework.stereotype.Service;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
@Service
public class UserService {
    
	@Autowired
    private UserDao userDao;

    /**
     * 根据id查询用户
     * @param id
     * @return
     */
    public User findById(Integer id) {
        return userDao.findById(id);
    }

}
  • UserDao:
package com.dfbz.dao;

import com.dfbz.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import javax.sql.DataSource;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
@Repository
public class UserDao {

    @Autowired
    private DataSource dataSource;

    /**
     * 根据id查询用户
     *
     * @param id
     * @return
     */
    public User findById(Integer id) {

        try {
            PreparedStatement ps = dataSource.getConnection().prepareStatement("select * from user where id=?");
            ps.setInt(1, id);

            ResultSet rs = ps.executeQuery();

            if (rs.next()) {
                return new User(rs.getInt("id"), rs.getString("username"), rs.getString("password"));
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }

        return null;
    }
}
  • spring.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <!--
        包扫描
        base-package:指定要扫描的包(会扫描子包孙包等..)
    -->
    <context:component-scan base-package="com.dfbz" />

    <!--加载jdbc.properties配置文件-->
    <context:property-placeholder location="jdbc.properties" />
    
    <!--配置数据源-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
        <property name="url" value="${jdbc.url}" />
        <property name="driverClassName" value="${jdbc.driverClassName}" />
    </bean>

</beans>

1.4.2 @Autowired注解

@Autowired注解:用于根据类型给引用装配容器的对象

构造器、普通字段、一切具有参数的方法都可以应用@Autowired注解

  • 在属性上使用:
@Component("userController")        // 注册UserController到IOC容器,id默认为类名首字母小写
public class UserController {

    // 装配UserService
    @Autowired
    private UserService userService;

    public User findById(Integer id){
        return userService.findById(id);
    }

}
  • 在方法上使用:
@Component("userController")        // 注册UserController到IOC容器,id默认为类名首字母小写
public class UserController {

    private UserService userService;

    /**
     * 在方法上标注@Autowired注解
     * @param userService
     */
    @Autowired
    public void setUserService(UserService userService){
        this.userService=userService;
    }
    
    public User findById(Integer id){
        return userService.findById(id);
    }
}
  • 在构造方法上使用:
@Component("userController")        // 注册UserController到IOC容器,id默认为类名首字母小写
public class UserController {

    private UserService userService;

    @Autowired
    public UserController(UserService userService){
        this.userService=userService;
    }

    public User findById(Integer id){
        return userService.findById(id);
    }

}

Tips:@Autowired注解是根据类型进行匹配的,当IOC容器中存在两个一样的类型时将默认使用首字母小写的名称类型;

1.4.3 @Qualifier注解

@Qualifier注解:用于指定装配的对象名,使用@Autowired装配对象时,@Autowired是根据对象类型来装配的,当容器中有多个相同类型的对象时,使用@Autowired注解来装配对象会出现装配异常;并不能根据对象id来装配对象;想要根据对象id来装配对象需要借助@Qualifier注解来指定id名称,

@Component("userController")        // 注册UserController到IOC容器,id默认为类名首字母小写
public class UserController {

    @Autowired
    @Qualifier("userService")		//@Qualifier不能单独使用,配合Autowired使用
    private UserService userService;

    public User findById(Integer id){
        return userService.findById(id);
    }
}

Tips:

  • 1)@Qualifier必须搭配@Autowired注解使用,不能单独使用
  • 2)@Autowired注解在装配对象时,如果IOC容器中存在多个一样类型的对象,默认取类名首字母小写的对象进行装配;

1.4.4 @Resource注解

@Resource注解是Spring框架支持Sun官方制定的JSR-250标准注入对象的实现。

@Resource 功能等同 @Autowired + @Qualifier ,等同配置文件标签 <proprty name="..." ref="...">

@Resource注解:用于给引用注入容器的对象,可以通过name属性指定对象名

@Resource(name = "userService")                   // @Autowired+ @Qualifier()
private UserService userService;

Tips:@Resource注解只能注入方法和属性,不能注入构造方法

1.4.6 @Value注解

value只能设置,普通类型=基础数据类型+包装类+String

@Value注解:注入基本数据类型以及它们的包装类和String类型数据的,

支持${} 注入Properties文件的键值对,等同 <proprty name="..." value="${Key}">

  • 定义一个MyDataSource:
package com.dfbz;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
@Component
public class MyDataSource {
    @Value("${jdbc.username}")
    private String username;

    @Value("${jdbc.password}")
    private String password;

    @Value("${jdbc.url}")
    private String url;

    @Value("${jdbc.driverClassName}")
    private String driverClassName;

    public void print(){
        System.out.println("username: "+username);
        System.out.println("password: "+password);
        System.out.println("url: "+url);
        System.out.println("driverClassName: "+driverClassName);
    }

}
  • 测试类:
@Test
public void test3(){

    ApplicationContext app=new ClassPathXmlApplicationContext("spring2.xml");

    MyDataSource dataSource = app.getBean(MyDataSource.class);

    dataSource.print();
}

属性value:注入基本数据类型和String类型数据的

1.5 作用域相关注解

Spring是通过@Scope注解来指定对象的作用域的。

  • 回顾Bean的生命周期:

    • singleton:单例(默认值),容器创建时bean初始化,容器关闭时销毁;
    • prototype:多例,等到用到的时候再初始化,容器关闭时不会销毁,自行销毁;
    • reqeust:在WEB环境中,一次请求创建一次;
    • session:在WEB环境中,一次会话创建一次;
    • application:在WEB环境中,创建了一个上下文对象的时候创建该对象;
  • 创建实体类:

@Component
@Scope("prototype")     // 多例
public class Article {

    private Integer id;
    private String title;
    private String author;
}
  • 测试类:
package com.dfbz.demo;

import com.dfbz.entity.Article;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class Demo05 {
    ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("spring2.xml");
    @Test
    public void test1(){

        Article bean1 = app.getBean(Article.class);
        Article bean2= app.getBean(Article.class);

        System.out.println(bean1 == bean2);				// false

        app.close();
    }
}

1.6 生命周期相关注解

  • @PostConstruct注解

等同于<bean init-method="">

作用:用于指定初始化方法。

  • @PreDestroy注解

等同于<bean destory-method="">

作用:用于指定销毁方法。

  • 修改Article实体类:
@Component
@Scope("singleton")     // 多例
public class Article {

    private Integer id;
    private String title;
    private String author;

    /**
     * 初始化方法
     */
    @PostConstruct
    public void init(){
        System.out.println("article初始化了");
    }

    /**
     * 销毁方法
     */
    @PreDestroy
    public void destroy(){
        System.out.println("article销毁了");
    }
}

二、纯注解开发

2.1 配置相关注解

我们发现,之所以我们现在离不开xml配置文件,是因为我们有一句很关键的配置:

<!-- 告知spring框架在,读取配置文件,创建容器时,扫描注解,依据注解创建对象,并存入容器中 -->
<context:component-scan base-package="com.dfbz" />

<!--加载jdbc.properties配置文件-->
<context:property-placeholder location="jdbc.properties" />

配置相关注解如下:

替换XML配置文件的@Configuration注解@Configuration配置类注解,在纯注解配置中,类加了该注解,就意味着该类是Spring的配置类。该类的功能就是用于替代原来的XML配置文件。 作用:用于指定当前类是一个spring配置类,当创建容器时会从该类上加载注解。获取容器时需要使用AnnotationConfigApplicationContext(有@Configuration注解的类.class)。
@ComponentScan注解@ComponentScan注解扫描类,作用就是配置扫描Spring组件类的路径。功能等同原来配置文件的 --作用:用于指定spring在初始化容器时要扫描的包。作用和在spring的xml配置文件中的:<context:component-scan base-package=“com”/>是一样的。–属性:basePackages:用于指定要扫描的包。和该注解中的value属性作用一样。
@PropertySource注解作用:用于加载.properties文件中的配置。例如我们配置数据源时,可以把连接数据库的信息写到properties配置文件中,就可以使用此注解指定properties配置文件的位置。属性:value[]:用于指定properties文件位置。如果是在类路径下,需要写上classpath:encoding:用于指定文件编码
@Bean注解作用:该注解只能写在方法上,使用此方法创建一个对象,并且放入spring容器。它就相当于我们之前在xml配置中介绍的<bean标签> 属性:name:给当前@Bean注解方法创建的对象指定一个名称(即bean的id)。
@Import注解作用:用于导入其他配置类,在引入其他配置类时,可以不用再写@Configuration注解。当然,写上也没问题。 属性:value[]:用于指定其他配置类的字节码。

2.2 使用纯注解改造xml方式

  • 创建配置类:
package com.dfbz;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

import javax.sql.DataSource;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
@Configuration          // 标注该类是一个配置类
@ComponentScan("com.dfbz")      // 包扫描
@PropertySource("jdbc.properties")      // 加载properties文件
public class SpringConfig {


    @Value("${jdbc.username}")
    private String username;

    @Value("${jdbc.password}")
    private String password;

    @Value("${jdbc.url}")
    private String url;

    @Value("${jdbc.driverClassName}")
    private String driverClassName;


    /**
     * 配置数据源
     * @return
     */
    @Bean       // 相当于<bean>标签
    public DataSource dataSource(){
        DruidDataSource dataSource=new DruidDataSource();
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        dataSource.setUrl(url);
        dataSource.setDriverClassName(driverClassName);

        return dataSource;
    }

}

复制之前的UserController、UserService、UserDao、User实体类、jdbc.properties等;

在这里插入图片描述

  • 测试类:
package com.dfbz.test;

import com.dfbz.SpringConfig;
import com.dfbz.controller.UserController;
import com.dfbz.entity.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class Demo01 {

    @Test
    public void test1(){


        // 创建IOC容器,并指定配置类
        ApplicationContext app=new AnnotationConfigApplicationContext(SpringConfig.class);

        UserController userController = app.getBean(UserController.class);

        User user = userController.findById(1);

        System.out.println(user);
    }
}

2.3 @Import注解

@Import注解主要的功能就是往IOC容器里面配置Bean,并且只能标注在类上;

2.3.1 @Import注解用法

1)直接配置
  • 修改SpringConfig配置类:
@Configuration          // 标注该类是一个配置类
@ComponentScan("com.dfbz")      // 包扫描
@PropertySource("jdbc.properties")      // 加载properties文件
@Import({UserDao.class, UserService.class})         // 直接配置两个bean到IOC容器中
public class SpringConfig {
    ....
}

注释UserDao、UserService上的@Repository、@Service注解;执行测试类;

2)ImportSelector配置

编写一个导入器类,实现ImportSelector接口;

  • 导入器:
package com.dfbz.selectors;

import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;

/**
 * @author lscl
 * @version 1.0
 * @intro: 编写一个配置导入器,指定需要导入的全类名
 */
public class MySelectors implements ImportSelector {
    /**
     * 导入具体的bean
     * @param annotationMetadata: 获取注解的一些元信息
     * @return
     */
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {

        // 要导入类的全类名
        return new String[]{"com.dfbz.service.UserService","com.dfbz.dao.UserDao"};
    }
}

配置类:

@Configuration          // 标注该类是一个配置类
@ComponentScan("com.dfbz")      // 包扫描
@PropertySource("jdbc.properties")      // 加载properties文件
@Import({MySelectors.class})            // 指定导入器导入
public class SpringConfig {
}
3)ImportBeanDefinitionRegistrar配置

和ImportSelector方式类似,由自己往IOC容器中注册bean,可以定义bean的名称;

  • 编写导入器:
package com.dfbz.selectors;

import com.dfbz.dao.UserDao;
import com.dfbz.service.UserService;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class MySelectors2 implements ImportBeanDefinitionRegistrar {


    @Override
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
        //指定bean定义信息(包括bean的类型、作用域...)
        RootBeanDefinition userDaoBeanDefinition = new RootBeanDefinition(UserDao.class);

        //注册一个bean指定bean名字(id)
        beanDefinitionRegistry.registerBeanDefinition("userDao",userDaoBeanDefinition);

        //指定bean定义信息(包括bean的类型、作用域...)
        RootBeanDefinition userServiceBeanDefinition = new RootBeanDefinition(UserService.class);

        //注册一个bean指定bean名字(id)
        beanDefinitionRegistry.registerBeanDefinition("userService",userServiceBeanDefinition);
    }
}

三、Spring整合JdbcTemplate

3.1 项目搭建

  • 导入依赖
<?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.dfbz</groupId>
    <artifactId>03_Spring</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.9.RELEASE</version>
        </dependency>

        <!--jdbcTemplate依赖-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.9.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.48</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.1</version>
        </dependency>
    </dependencies>
</project>

复制之前的项目,把注解全部剔除;

在这里插入图片描述

3.1 使用xml方式整合

UserDao:

package com.dfbz.dao;

import com.dfbz.entity.User;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.*;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class UserDao {

    private JdbcTemplate jdbcTemplate;

    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    /**
     * 新增
     * @param user
     */
    public void save(User user) {
        jdbcTemplate.update("insert into user values(null,?,?)", user.getUsername(), user.getPassword());
    }

    /**
     * 删除
     * @param id
     */
    public void delete(Integer id) {
        jdbcTemplate.update("delete from user where id=?", id);
    }

    /**
     * 修改
     * @param user
     */
    public void update(User user) {
        jdbcTemplate.update("update user set username=?,password=? where id=?", user.getUsername(), user.getPassword(), user.getId());
    }

    /**
     * 根据id查询(自动映射)
     * @param id
     * @return
     */
    public User findById(Integer id) {
        try {

            // 最好抓一下异常,因为jdbctemplate没有查询任何的数据不是返回null,而是抛出异常
            return jdbcTemplate.queryForObject("select * from user where id=?", new BeanPropertyRowMapper<>(User.class), id);
        } catch (DataAccessException e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 根据id查询返回map类型
     * @param id
     * @return
     */
    public Map<String, Object> findUserMapById(Integer id) {
        try {

            // 最好抓一下异常,因为jdbctemplate没有查询任何的数据不是返回null,而是抛出异常
            return jdbcTemplate.queryForMap("select * from user where id=?",id);
        } catch (DataAccessException e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 查询全部(自动映射)
     * @return
     */
    public List<User> findAll() {
        return jdbcTemplate.query("select * from user ", new BeanPropertyRowMapper<>(User.class));
    }

    /**
     * 查询全部手动映射,方式一
     * @return
     */
    public List<User> findAll2() {
        return jdbcTemplate.query("select * from user ", new RowMapper<User>() {
            /**
             * 这个方法会执行很多次,将此次SQL语句查询到的每一条记录都封装到ResultSet中
             * @param rs: 查询到的一行数据
             * @param i :遍历的次数
             * @return
             * @throws SQLException
             */
            @Override
            public User mapRow(ResultSet rs, int i) throws SQLException {

                return new User(rs.getInt("id"),rs.getString("username"),rs.getString("password"));
            }
        });
    }

    /**
     * 查询全部手动映射,方式二
     * @return
     */
    public List<User> findAll3() {
        return jdbcTemplate.query("select * from user ", new ResultSetExtractor<List<User>>() {

            /**
             * 这个方法只会执行一次,将此次SQL语句查询的所有结果集都封装到ResultSet中
             * @param rs
             * @return
             * @throws SQLException
             * @throws DataAccessException
             */
            @Override
            public List<User> extractData(ResultSet rs) throws SQLException, DataAccessException {

                List<User> userList=new ArrayList<>();
                while (rs.next()){
                    userList.add(new User(rs.getInt("id"),rs.getString("username"),rs.getString("password")));
                }

                return userList;
            }
        });
    }

    /**
     * 查询全部返回map结果
     * @return
     */
    public List<Map<String, Object>> findUserMapAll() {
        return jdbcTemplate.queryForList("select * from user");
    }

    /**
     * 查询单个
     * @return
     */
    public Long count() {
        return jdbcTemplate.queryForObject("select count(1) from user",Long.class);
    }
}

spring.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">


    <!--加载jdbc.properties配置文件-->
    <context:property-placeholder location="jdbc.properties" />

    <!--配置数据源-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
        <property name="url" value="${jdbc.url}" />
        <property name="driverClassName" value="${jdbc.driverClassName}" />
    </bean>

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!--注入dataSource-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--配置userDao-->
    <bean id="userDao" class="com.dfbz.dao.UserDao">
        <!--要提供set方法-->
        <property name="jdbcTemplate" ref="jdbcTemplate" />
    </bean>

    <bean id="userService" class="com.dfbz.service.UserService">
        <!--注入userDao-->
        <!--要提供set方法-->
        <property name="userDao" ref="userDao"></property>
    </bean>

    <bean id="userController" class="com.dfbz.controller.UserController">
        <!--注入userService-->
        <!--要提供set方法-->
        <property name="userService" ref="userService" />
    </bean>

</beans>
  • 测试类:
package com.dfbz.test;

import com.dfbz.controller.UserController;
import com.dfbz.entity.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class Demo01 {
    // 创建IOC容器,并指定配置类
    ApplicationContext app=new ClassPathXmlApplicationContext("spring.xml");

    UserController userController = app.getBean(UserController.class);

    @Test
    public void test1(){

        User user = userController.findById(1);

        System.out.println(user);
    }
}

3.2 xml和注解混用

在xml中去除注入,使用@autowired注解注入

在这里插入图片描述

spring.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <!--扫描包-->
    <context:component-scan base-package="com.dfbz" />
    
    <!--加载jdbc.properties配置文件-->
    <context:property-placeholder location="jdbc.properties" />

    <!--配置数据源-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
        <property name="url" value="${jdbc.url}" />
        <property name="driverClassName" value="${jdbc.driverClassName}" />
    </bean>

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!--注入dataSource-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>

</beans>

3.3 使用纯注解

  • 新建配置类:
package com.dfbz;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
@Configuration
@ComponentScan("com.dfbz")
@PropertySource("jdbc.properties")
public class SpringConfig {

    @Value("${jdbc.username}")
    private String username;

    @Value("${jdbc.password}")
    private String password;

    @Value("${jdbc.url}")
    private String url;

    @Value("${jdbc.driverClassName}")
    private String driverClassName;


    /**
     * 配置数据源
     * @return
     */
    @Bean
    public DataSource dataSource(){
        DruidDataSource dataSource=new DruidDataSource();
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        dataSource.setUrl(url);
        dataSource.setDriverClassName(driverClassName);

        return dataSource;
    }

    /**
     * 配置JdbcTemplate
     * @param dataSource
     * @return
     */
    @Bean
    public JdbcTemplate jdbcTemplate(DataSource dataSource){

        return new JdbcTemplate(dataSource);
    }
}
  • 测试类:
package com.dfbz.test;

import com.dfbz.SpringConfig;
import com.dfbz.controller.UserController;
import com.dfbz.entity.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class Demo02 {
    // 创建IOC容器,并指定配置类
    ApplicationContext app=new AnnotationConfigApplicationContext(SpringConfig.class);

    UserController userController = app.getBean(UserController.class);

    @Test
    public void test1(){

        User user = userController.findById(1);

        System.out.println(user);
    }
}

四、Spring整合Junit

在测试类中,每个测试方法都有以下两行代码:

ApplicationContext app = new ClassPathXmlApplicationContext("application.xml");

UserController userController = app.getBean(UserController.class);

这两行代码的作用是获取容器,比较繁琐,如何解决?

针对上述问题,我们需要的是程序能自动帮我们创建容器。一旦程序能自动为我们创建 spring 容器,我们就无须手动创建了,问题也就解决了。

但显然, junit 是无法实现的,因为它自己都无法知晓我们是否使用了 spring 框架,更不用说帮我们创建 spring 容器了。

不过好在, junit 给我们暴露了一个注解,可以让我们替换掉它的运行器。这时,我们需要依靠 spring 框架,因为它提供了一个运行器,可以读取配置文件(或注解)来创建容器。

4.1. 测试基于XML的配置

4.1.1 创建项目引入依赖

<!-- spring整合junit包 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>5.2.9.RELEASE</version>
</dependency>

4.1.2 创建实体类

public class User {

    private Integer id;
    private String username;
    private String password;

    public User() {
    }

    public User(Integer id, String username, String password) {
        this.id = id;
        this.username = username;
        this.password = password;
    }
}

4.1.3 编写Spring配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <bean id="user" class="com.dfbz.entity.User">
        <property name="id" value="1"></property>
        <property name="username" value="zhangsan"></property>
        <property name="password" value="123"></property>
    </bean>

</beans>

4.1.4 测试类

package com.dfbz.test;

import com.dfbz.entity.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
@RunWith(SpringRunner.class)
@ContextConfiguration(locations = "classpath:spring.xml")
public class Demo01 {

    @Autowired
    private User user;

    @Test
    public void test(){
        System.out.println(user);
    }
}

4.2 基于注解的配置

4.2.1 修改User实体类:

@Component
public class User {

    @Value("1")
    private Integer id;

    @Value("zhangsan")
    private String username;

    @Value("123")
    private String password;
}

4.2.2 spring配置类

package com.dfbz;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
@Configuration
@ComponentScan("com.dfbz")          // 包扫描
public class SpringConfig {


}

4.2.3 测试类

package com.dfbz.test;

import com.dfbz.SpringConfig;
import com.dfbz.entity.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = SpringConfig.class)         // 换成配置类
public class Demo02 {

    @Autowired
    private User user;

    @Test
    public void test(){
        System.out.println(user);
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

緑水長流*z

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值