文章目录
-
-
- 环境搭建
-
- 0.实体类
- 1.业务层接口
- 2.业务层实现类
- 3.持久层接口
- 4.持久层实现类
- 5.配置文件:bean.xml
- 6.测试类
- 通过注解代替bean.xml配置文件
-
- @Component("account")
- @Value("zhangsan")
- @Service("accountDao")
- @Autowired
- @Repository("accountDao")
- @Configuration
- @ComponentScan
- @Bean
- 测试
- @Import
- @PropertySource
- Spring整合Junit
- 总结
-
- 0.实体类
- 1.业务层接口
- 2.业务层实现类
- 3.持久层接口
- 4.持久层实现类
- 5.SpringConfig配置主类
- 6.jdbcConfig.properties
- 7.JDBCConfig配置副类
- 8.测试类
-
环境搭建
数据库:
create table account(
id int primary key auto_increment,
name varchar(40),
money float
)character set utf8 collate utf8_general_ci;
insert into account(name,money) values('aaa',1000);
insert into account(name,money) values('bbb',1000);
insert into account(name,money) values('ccc',1000);
项目的目录结构:
pom.xml:
<dependencies>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.18</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/c3p0/c3p0 -->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-dbutils/commons-dbutils -->
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.7</version>
</dependency>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
0.实体类
public class Account {
private Integer id;
private String name;
private Float money;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Float getMoney() {
return money;
}
public void setMoney(Float money) {
this.money = money;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", name='" + name + '\'' +
", money=" + money +
'}';
}
}
1.业务层接口
public interface AccountService {
//查询所有
List<Account> findAllAccount();
//查询一个
Account findAccountById(Integer id);
//保存
void saveAccount(Account account);
//更新
void updateAccount(Account account);
//删除
void deleteAccount(Integer id);
}
2.业务层实现类
//业务层实现类,业务层调用持久层
public class AccountServiceImpl implements AccountService{
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
public List<Account> findAllAccount() {
return accountDao.findAllAccount();
}
public Account findAccountById(Integer id) {
return accountDao.findAccountById(id);
}
public void saveAccount(Account account) {
accountDao.saveAccount(account);
}
public void updateAccount(Account account) {
accountDao.updateAccount(account);
}
public void deleteAccount(Integer id) {
accountDao.deleteAccount(id);
}
}
3.持久层接口
//账户的持久层接口
public interface AccountDao {
//查询所有
List<Account> findAllAccount();
//查询一个
Account findAccountById(Integer id);
//保存
void saveAccount(Account account);
//更新
void updateAccount(Account account);
//删除
void deleteAccount(Integer id);
}
4.持久层实现类
//持久层实现类
public class AccountDaoImpl implements AccountDao {
private QueryRunner runner;
public void setRunner(QueryRunner runner) {
this.runner = runner;
}
public List<Account> findAllAccount() {
try {
return runner.query("select * from account",new BeanListHandler<Account>(Account.class));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public Account findAccountById(Integer id) {
try {
return runner.query("select * from account where id=?",new BeanHandler<Account>(Account.class),id);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void saveAccount(Account account) {
try {
runner.update("insert into account(name,money) values(?,?)",account.getName(),account.getMoney());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void updateAccount(Account account) {
try {
runner.update("update account set name=?,money=? where id=?",account.getName(),account.getMoney(),account.getId());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void deleteAccount(Integer id) {
try {
runner.update("delete from account where id=?",id);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
5.配置文件:bean.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--Spring在创建容器时,要扫描的包-->
<context:component-scan base-package="com.hh"/>
<!--配置实体类-->
<bean id="account" class="com.hh.domain.Account">
<property name="name" value="zhangsan"/>
<property name="money" value="2000"/>
</bean>
<!--配置AccountService-->
<bean id="accountService" class="com.hh.service.AccountServiceImpl">
<!--注入accountDao-->
<property name="accountDao" ref="accountDao"/>
</bean>
<!--配置AccountDao-->
<bean id="accountDao" class="com.hh.dao.AccountDaoImpl">
<!--注入QueryRunner-->
<property name="runner" ref="queryRunner"/>
</bean>
<!--配置QueryRunner-->
<bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
<!--注入数据源-->
<constructor-arg name="ds" ref="dataSource"/>
</bean>
<!--配置数据源-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!--连接数据库的必备信息-->
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring"/>
<property name="user" value="root"/>
<property name="password" value="123"/>
</bean>
</beans>
6.测试类
public class MyTest {
@Test
public void testFindAll(){
//获取Spring核心容器
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
//得到业务层对象
AccountService service =
context.getBean("accountService", AccountService.class);
List<Account> accounts = service.findAllAccount();
for(Account account :accounts){
System.out.println(account);
}
}
@Test
public void testFindone(){
//获取Spring核心容器
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
//得到业务层对象
AccountService service =
context.getBean("accountService", AccountService.class);
Account account = service.findAccountById(3);
System.out.println(account);
}
@Test
public void testSave(){
//获取Spring核心容器
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
//得到业务层对象
AccountService service =
context.getBean("accountService", AccountService.class);
//获取Account对象
Account account = context.getBean("account",Account.class);
service.saveAccount(account);
}
@Test
public void testUpdate(){
//获取Spring核心容器
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
//得到业务层对象
AccountService service =
context.getBean("accountService", AccountService.class);
context.getBean("account");
//获取Account对象
Account account = service.findAccountById(4);
account.setMoney(3000f);
service.updateAccount(account);
}
@Test
public void testDelete(){
//获取Spring核心容器
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
//得到业务层对象
AccountService service =
context.getBean("accountService", AccountService.class);
context.getBean("account");
service.deleteAccount(4);
}
}
通过注解代替bean.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--Spring在创建容器时,要扫描的包-->
<context:component-scan base-package="com.hh"/>
<!--配置实体类-->
<bean id="account" class="com.hh.domain.Account">
<property name="name" value="zhangsan"/>
<property name="money" value="2000"/>
</bean>
<!--配置AccountService-->
<bean id="accountService" class="com.hh.service.AccountServiceImpl">
<!--注入accountDao-->
<property name="accountDao" ref="accountDao"/>
</bean>
<!--配置AccountDao-->
<bean id="accountDao" class="com.hh.dao.AccountDaoImpl">
<!--注入QueryRunner-->
<property name="runner" ref="queryRunner"/>
</bean>
<!--配置QueryRunner-->
<bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
<!--注入数据源-->
<constructor-arg name="ds" ref="dataSource"/>
</bean>
<!--配置数据源-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!--连接数据库的必备信息-->
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring"/>
<property name="user" value="root"/>
<property name="password" value="123"/>
</bean>
</beans>
既然是使用注解开发,那么思考一个问题,要通过哪些注解把上面的xml文件去掉,不再使用bean.xml呢?
@Component(“account”)
使用@Component来创建Account对象,将Account对象放进IOC容器
代替bean.xml中下面的配置:
<bean id="account" class="com.hh.domain.Account">
</bean>
@Value(“zhangsan”)
如果不想在测试类中调用setter方法初始化,可以使用注解依赖注入
代替bean.xml中下面的配置:
<bean id="account" class="com.hh.domain.Account">
<property name="name" value="zhangsan"/>
<property name="money" value="2000"/>
</bean>
@Service(“accountDao”)
使用@Service来创建accountService对象
代替bean.xml中下面的配置:
<!--配置AccountService-->
<bean id="accountService" class="com.hh.service.AccountServiceImpl">
<!--注入accountDao-->
<property name="accountDao" ref="accountDao"/>
</bean>
@Autowired
由于AccountServiceImpl中有一个bean对象属性,因此可以通过@Autowired依赖注入,可以省略setter方法
@Repository(“accountDao”)
使用@Repository来创建accountDao对象
代替bean.xml中下面的配置:
<!--配置AccountDao-->
<bean id="accountDao" class="com.hh.dao.AccountDaoImpl">
<!--注入QueryRunner-->
<property name="runner" ref="queryRunner"/>
</bean>
@Configuration
作用:指定当前类是一个配置类,作用和bean.xml相同
//该类是一个配置类,作用和bean.xml相同
@Configuration
public class SpringConfig {
}
@ComponentScan
作用:用于通过注解指定Spring在创建容器中要扫描的包
属性:value和bacePackages作用相同,都是指定要扫描的包
作用等同于xml中的:<context:component-scan base-package="com.hh"/>
使用@ComponentScan指定要扫描的包
代替bean.xml中下面的配置:
<!--Spring在创建容器时,要扫描的包-->
<context:component-scan base-package="com.hh"/>
@Bean
作用:用于把当前方法的返回值作为bean对象存入Spring容器中
属性:name:用于指定bean的id,不写时默认为当前方法的名称
细节:当我们使用注解配置方法时,如果方法有参数,Spring框架回去容器中找有没有可用的bean对象,查找的方式和Autowired一样。
代替bean.xml中下面的配置:
<!--配置QueryRunner-->
<bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
<!--注入数据源-->
<constructor-arg name="ds" ref="dataSource"/>
</bean>
<!--配置数据源-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!--连接数据库的必备信息-->
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring"/>
<property name="user" value="root"/>
<property name="password" value="123"/>
</bean>
<bean id="account" class="com.hh.domain.Account">
<property name="name" value="zhangsan"/>
<property name="money" value="2000"/>
</bean>
到目前为止,我们已经把配置文件中所有的配置都去掉了,目前就是下面这个样子,同时就可以吧这个bean.xml删除了:
bean.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
http://www.springframework.org/schema/context/spring-context.xsd">
</beans>
测试
下面我们需要对注解改造过的项目进行测试,那么问题来了,之前我们都是通过配置文件bean.xml来获取Spring的IOC核心容器ApplicationContext,现在注解删了,还怎么获取?
下面要通过ApplicationContext的另一个实现类:
public class MyTest {
@Test
public void testSave(){
//获取Spring核心容器
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
//得到业务层对象
AccountService service =
context.getBean("accountService", AccountService.class);
//获取Account对象
Account account = context.getBean("account",Account.class);
service.saveAccount(account);
}
@Import
当配置类作为容器对象AnnotationConfigApplicationContext的参数时,@Configuration注解可以省略不写
配置类JDBCConfig:
//和Spring连接数据库相关的配置类
public class JDBCConfig {
//用于创建一个QueryRunner对象
@Bean(name="queryRunner")
public QueryRunner createQueryRunner(DataSource dataSource){
return new QueryRunner(dataSource);
}
//创建一个DataSource对象
@Bean(name="dataSource")
public DataSource createDataSource() throws PropertyVetoException {
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setDriverClass("com.mysql.jdbc.Driver");
ds.setJdbcUrl("jdbc:mysql://localhost:3306/spring");
ds.setUser("root");
ds.setPassword("123");
return ds;
}
}
如上图,重新在config包下面写一个配置类JDBCConfig,如果把这个配置类的注解@Configuration省略不写,就要把这个配置类JDBCConfig.class加到容器对象的参数中
如果在JDBCConfig类上加了@Configuration注解,那么就不需要再容器对象参数中写入JDBCConfig.class
问题来了,现在有两个配置类SpringConfig和JDBCConfig,如果我既不想在JDBCConfig类上加一个@Configuration注解,也不想在容器对象参数中加入JDBCConfig.class呢?这个时候就需要引入一个新注解@Import。把配置类JDBCConfig导入配置类SpringConfig中。
@Import作用:用于导入其他的配置类
使用Import注解后,有Import注解的类就是主配置类,导入的都是副配置类
@PropertySource
现在还有一个问题注意看SpringConfig配置类:
//和Spring连接数据库相关的配置类
public class JDBCConfig {
//用于创建一个QueryRunner对象
@Bean(name="queryRunner")
public QueryRunner createQueryRunner(DataSource dataSource){
return new QueryRunner(dataSource);
}
//创建一个DataSource对象
@Bean(name="dataSource")
public DataSource createDataSource() throws PropertyVetoException {
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setDriverClass("com.mysql.jdbc.Driver");
ds.setJdbcUrl("jdbc:mysql://localhost:3306/spring");
ds.setUser("root");
ds.setPassword("123");
return ds;
}
}
写一个jdbcConfig.properties配置文件:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/spring
username=root
password=123
在配置类JDBCConfig中写入这几个属性,并指定值:
@PropertySource
作用:用于指定properties文件的位置
属性:value用于指定文件的名称和路径
关键字:classPath:表示类路径下
Spring整合Junit
1.导入spring整合Junit的jar包
<!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.0.RELEASE</version>
<scope>test</scope>
</dependency>
2.使用Junit提供的一个注解把原有的main方法替换了,替换成spring提供的@Runwith
3.告知spring的运行器,spring的ioc的创建是基于xml的还是基于注解的,并说明位置。
@ContextConfigration
locations:指定xml文件的位置,加上classpath关键字,表示在类路径下。
classes:自定注解所在的位置
总结
0.实体类
package com.hh.domain;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
//实体类
@Component("account")
public class Account {
private Integer id;
@Value("zhangsan")
private String name;
@Value("2000f")
private Float money;
public void setId(Integer id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setMoney(Float money) {
this.money = money;
}
public Integer getId() {
return id;
}
public String getName() {
return name;
}
public Float getMoney() {
return money;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", name='" + name + '\'' +
", money=" + money +
'}';
}
}
1.业务层接口
public interface AccountService {
//查询所有
List<Account> findAllAccount();
//查询一个
Account findAccountById(Integer id);
//保存
void saveAccount(Account account);
//更新
void updateAccount(Account account);
//删除
void deleteAccount(Integer id);
}
2.业务层实现类
@Service("accountService")
public class AccountServiceImpl implements AccountService{
@Autowired
private AccountDao accountDao;
public List<Account> findAllAccount() {
return accountDao.findAllAccount();
}
public Account findAccountById(Integer id) {
return accountDao.findAccountById(id);
}
public void saveAccount(Account account) {
accountDao.saveAccount(account);
}
public void updateAccount(Account account) {
accountDao.updateAccount(account);
}
public void deleteAccount(Integer id) {
accountDao.deleteAccount(id);
}
}
3.持久层接口
//账户的持久层接口
public interface AccountDao {
//查询所有
List<Account> findAllAccount();
//查询一个
Account findAccountById(Integer id);
//保存
void saveAccount(Account account);
//更新
void updateAccount(Account account);
//删除
void deleteAccount(Integer id);
}
4.持久层实现类
//持久层实现类
@Repository("accountDao")
public class AccountDaoImpl implements AccountDao {
@Autowired
private QueryRunner runner;
public List<Account> findAllAccount() {
try {
return runner.query("select * from account",new BeanListHandler<Account>(Account.class));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public Account findAccountById(Integer id) {
try {
return runner.query("select * from account where id=?",new BeanHandler<Account>(Account.class),id);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void saveAccount(Account account) {
try {
runner.update("insert into account(name,money) values(?,?)",account.getName(),account.getMoney());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void updateAccount(Account account) {
try {
runner.update("update account set name=?,money=? where id=?",account.getName(),account.getMoney(),account.getId());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void deleteAccount(Integer id) {
try {
runner.update("delete from account where id=?",id);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
5.SpringConfig配置主类
//该类是一个配置类,作用和bean.xml相同
@ComponentScan("com.hh")
@Import(JDBCConfig.class)
@PropertySource("classpath:jdbcConfig.properties")
public class SpringConfig {
//用于创建一个QueryRunner对象
@Bean(name="queryRunner")
public QueryRunner createQueryRunner(DataSource dataSource){
return new QueryRunner(dataSource);
}
}
6.jdbcConfig.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/spring?serverTimezone=UTC
username=root
password=123
7.JDBCConfig配置副类
//和Spring连接数据库相关的配置类
public class JDBCConfig {
@Value("${driver}")
private String driver;
@Value("${url}")
private String url;
@Value("${username}")
private String username;
@Value("${password}")
private String password;
//用于创建一个QueryRunner对象
@Bean(name="queryRunner")
public QueryRunner createQueryRunner(DataSource dataSource){
return new QueryRunner(dataSource);
}
//创建一个DataSource对象
@Bean(name="dataSource")
public DataSource createDataSource() throws PropertyVetoException {
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setDriverClass(driver);
ds.setJdbcUrl(url);
ds.setUser(username);
ds.setPassword(password);
return ds;
}
}
8.测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class AccountServiceTest {
@Autowired
private AccountService service=null;
@Autowired
private Account account=null;
@Test
public void testFindAll(){
List<Account> accounts = service.findAllAccount();
for(Account account :accounts){
System.out.println(account);
}
}
@Test
public void testFindone(){
Account account = service.findAccountById(3);
System.out.println(account);
}
@Test
public void testSave(){
service.saveAccount(account);
}
@Test
public void testUpdate(){
account.setMoney(3000f);
service.updateAccount(account);
}
@Test
public void testDelete(){
service.deleteAccount(4);
}
}