1 spring的常用注解
1.1 环境搭建
(1)新建Maven项目,spring_day02_01annotation
(2)pom.xml文件引入依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
(3)创建业务层代码
AccountServiceImpl.java
package com.spg.service.impl;
import com.spg.dao.AccountDao;
import com.spg.dao.impl.AccountDaoImpl;
import com.spg.service.AccountService;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
/**
* 账户的业务层实现类
*
* 曾经XML的配置:
* <bean id="accountService" class="com.spg.service.impl.AccountServiceImpl"
* scope="" init-method="" destroy-method="" >
* <property name="" value="" | ref="" ></property>
* </bean>
* 用于创建对象的:
* 它们的作用就和在XML配置文件中编写一个<bean></bean>标签实现的功能一样的
* @Component
* 作用:用于把当前类对象存入spring容器
* 属性:
* value:用于指定bean的id。当不写是,它的默认值是当前类名,且首字母改小写
* @Controler:一般用在表现层
* @Service:一般用在业务层
* @Repository:一般用在持久层
* 以上三个注解:它们的作用和属性与@Component是一模一样。
* 它们三个是spring框架为我们提供明确的三层使用的注解,使我们三层对象更加清晰
* 用于注入数据的:
* 它们的作用就和在XML配置文件中的<bean></bean>标签写一个<property></property>标签的作用是一样的
* @Autowired:
* 作用:自动按照类型注入。只要容器中有唯一的一个bean对象类型和要注入的变量类型匹配,就可以注入成功
* 如果IOC中没有任何bean的类型和要注入的变量类型匹配,则报错。
* 如果IOC容器有多个匹配时,
* 出现位置:可以是变量上,也可以是方法上
* @Qualifier:
* 在按照类型注入的基础之上在按照名称注入,它在给类成员注入时不能单独使用,但是在给方法参数注入时可以
* 属性:
* value:用于指定注入bean的id
* @Resource:
* 作用:直接按照bean的id注入。它可以独立使用
* 属性:
* name:用于指定bean的id
* 以上三个注入都只能注入其它bean类型的数据,而基本类型和String类型无法使用上述注解实现
* 另外,集合类型的注入只能通过XMl来复制。
* @Value:
* 作用:用于注入基本类型和String类型的数据
* 属性:
* value:用于指定数据的值,他可以使用spring中ApEL(也就是Spring的EL表达式)
* ApEL的写法:${表达式}
* 用于改变作用范围的:
* 它们的作用就和在<bean></bean>标签中使用scope属性是一样的
* @Scope:
* 作用:用于指定bean的作用范围
* 属性:
* value:指定范围的取值:singleton prototype
* 和生命周期相关的:
* 它们的作用就和在<bean></bean>标签中使用init-method和destroy-method是一样的
* @PreDestroy:
* 作用:用于指定销毁方法
* @PostConstruct:
* 作用:用于指定初始化方法
*/
@Service(value = "accountService")
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao = new AccountDaoImpl();
private AccountServiceImpl(){
System.out.println("对象创建了...");
}
public void saveAccount(){
accountDao.saveAccount();
}
}
AccountService.java
package com.spg.service;
/**
* 账户业务层的接口
*/
public interface AccountService {
/**
* 模拟保存账户
*/
void saveAccount();
}
(4)创建持久层代码
AccountDaoImpl.java
package com.spg.dao.impl;
import com.spg.dao.AccountDao;
import org.springframework.stereotype.Repository;
/**
* 账户的持久层实现类
*/
@Repository("accountDao")
public class AccountDaoImpl implements AccountDao {
private AccountDao accountDao;
public void saveAccount(){
accountDao.saveAccount();
}
}
AccountDao.java
package com.spg.dao;
/**
* 账户的持久层接口
*/
public interface AccountDao {
/**
* 模拟保存账户
*/
void saveAccount();
}
(5)在resources下创建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">
<!-- bean 标签:用于配置让 spring 创建对象,并且存入 ioc 容器之中
id 属性:对象的唯一标识。
class 属性:指定要创建对象的全限定类名
-->
<!-- 告知spring创建容器时要扫描的包,配置所需要的标签不是在beans的约束中
而是一个名称为context名称空间和约束中
-->
<context:component-scan base-package="com.spg"/>
</beans>
(6)检查配置是否成功
Client.java
package com.spg.ui;
import com.spg.dao.AccountDao;
import com.spg.service.AccountService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* 模拟一个表现层,用于调用业务层
*/
public class Client {
public static void main(String[] args) {
// 1. 获取核心容器对象
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
// 2.根据id获取Bean对象
AccountService accountService = (AccountService) applicationContext.getBean("accountService");
AccountDao accountDao = applicationContext.getBean("accountDao",AccountDao.class);
System.out.println(accountService);
System.out.println(accountDao);
}
}
运行结果:
项目工程结构图如下:
1.2 常用注解
1.2.1 用于创建对象的
相当于:
<bean id="" class="" />
(1)@Component
作用: 把资源让 spring 来管理。相当于在 xml
中配置一个 bean
。
属性: value
:指定 bean
的 id
。如果不指定 value
属性,默认 bean
的 id
是当前类的类名。首字母小写。
(2)@Controller @Service @Repository
他们三个注解都是针对一个的衍生注解,他们的作用及属性都是一模一样的。
他们只不过是提供了更加明确的语义化。
@Controller
: 一般用于表现层的注解。
@Service
: 一般用于业务层的注解。
@Repository
: 一般用于持久层的注解。
Tips:如果注解中有且只有一个属性要赋值时,且名称是
value
,value
在赋值是可以不写。
1.2.2 用于注入数据的
相当于:
<property name="" ref="" />
<property name="" value="" />
(1) @Autowired
作用: 自动按照类型注入。当使用注解注入属性时, set
方法可以省略。它只能注入其他 bean
类型。当有多个类型匹配时,使用要注入的对象变量名称作为 bean
的 id
,在 spring 容器查找,找到了也可以注入成功。找不到就报错。
修改AccountDaoImpl.java
package com.spg.dao.impl;
import com.spg.dao.AccountDao;
import org.springframework.stereotype.Repository;
/**
* 账户的持久层实现类
*/
@Repository("accountDao")
public class AccountDaoImpl implements AccountDao {
public void saveAccount(){
System.out.println("保存了账户");
}
}
修改AccountServiceImpl.java
package com.spg.service.impl;
import com.spg.dao.AccountDao;
import com.spg.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* 曾经XML的配置:
* <bean id="accountService" class="com.spg.service.impl.AccountServiceImpl"
* scope="" init-method="" destroy-method="" >
* <property name="" value="" | ref="" ></property>
* </bean>
* 用于注入数据的:
* 它们的作用就和在XML配置文件中的<bean></bean>标签写一个<property></property>标签的作用是一样的
* @Autowired:
* 自动按照类型注入。只要容器中有唯一的一个bean对象类型和要注入的变量类型匹配,就可以注入成功
* 出现位置:可以是变量上,也可以是方法上
*/
@Service(value = "accountService")
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
public void saveAccount(){
accountDao.saveAccount();
}
}
修改Client.java
package com.spg.ui;
import com.spg.service.AccountService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* 模拟一个表现层,用于调用业务层
*/
public class Client {
/**
* @param args
*/
public static void main(String[] args) {
// 1. 获取核心容器对象
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
// 2.根据id获取Bean对象
AccountService accountService = (AccountService) applicationContext.getBean("accountService");
accountService.saveAccount();
}
}
运行结果:
(2) @Qualifier
作用: 在自动按照类型注入的基础之上,再按照 Bean
的 id
注入。它在给字段注入时不能独立使用,必须和@Autowire 一起使用;但是给方法参数注入时,可以独立使用。
属性: value
:指定 bean
的 id
。
(3) @Resource
作用: 直接按照 Bean
的 id
注入。它也只能注入其他 bean
类型。
属性: name
:指定 bean
的 id
。
(4) @Value
作用: 注入基本数据类型和 String
类型数据的
属性: value
:用于指定值
1.2.3 用于改变作用范围的
相当于:
<bean id="" class="" scope="" />
(1)@Scope
作用: 指定 bean
的作用范围。
属性: value
:指定范围的值。
取值: singleton
prototype
request
session
global session
修改AccountServiceImpl.java
package com.spg.service.impl;
import com.spg.dao.AccountDao;
import com.spg.service.AccountService;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* 账户的业务层实现类
* 曾经XML的配置:
* <bean id="accountService" class="com.spg.service.impl.AccountServiceImpl"
* scope="" init-method="" destroy-method="" >
* <property name="" value="" | ref="" ></property>
* </bean>
* 用于改变作用范围的:
* 它们的作用就和在<bean></bean>标签中使用scope属性是一样的
* @Scope:
* 作用:用于指定bean的作用范围
* 属性:
* value:指定范围的取值:singleton prototype
*/
@Service(value = "accountService")
@Scope("singleton")
public class AccountServiceImpl implements AccountService {
// @Autowired
// @Qualifier("accountDao")
@Resource(name = "accountDao")
private AccountDao accountDao;
public void saveAccount(){
accountDao.saveAccount();
}
}
修改Client.java
package com.spg.ui;
import com.spg.service.AccountService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* 模拟一个表现层,用于调用业务层
*/
public class Client {
/**
* @param args
*/
public static void main(String[] args) {
// 1. 获取核心容器对象
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
// 2.根据id获取Bean对象
AccountService accountService = (AccountService) applicationContext.getBean("accountService");
AccountService accountService2 = (AccountService) applicationContext.getBean("accountService");
System.out.println(accountService);
System.out.println(accountService2);
}
}
当@Scope("singleton")
时,运行结果:
当@Scope("prototype")
时,运行结果:
1.2.4 和生命周期相关的
相当于:
<bean id="" class="" init-method="" destroy-method="" />
(1) @PostConstruct
作用: 用于指定初始化方法。
(2) @PreDestroy
作用: 用于指定销毁方法。
修改AccountServiceImpl.java
package com.spg.service.impl;
import com.spg.dao.AccountDao;
import com.spg.service.AccountService;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
/**
* 账户的业务层实现类
*
* 曾经XML的配置:
* <bean id="accountService" class="com.spg.service.impl.AccountServiceImpl"
* scope="" init-method="" destroy-method="" >
* <property name="" value="" | ref="" ></property>
* </bean>
* 和生命周期相关的:
* 它们的作用就和在<bean></bean>标签中使用init-method和destroy-method是一样的
* @PreDestroy:
* 作用:用于指定销毁方法
* @PostConstruct:
* 作用:用于指定初始化方法
*/
@Service(value = "accountService")
// @Scope("prototype"):多例对象Spring销毁是不负责的
public class AccountServiceImpl implements AccountService {
// @Autowired
// @Qualifier("accountDao")
@Resource(name = "accountDao")
private AccountDao accountDao;
public void saveAccount(){
accountDao.saveAccount();
}
@PostConstruct
public void init(){
System.out.println("初始化方法执行了...");
}
@PreDestroy
public void destroy(){
System.out.println("销毁方法执行了...");
}
}
修改Client.java
package com.spg.ui;
import com.spg.service.AccountService;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* 模拟一个表现层,用于调用业务层
*/
public class Client {
/**
* @param args
*/
public static void main(String[] args) {
// 1. 获取核心容器对象
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
// 2.根据id获取Bean对象
AccountService accountService = (AccountService) applicationContext.getBean("accountService");
accountService.saveAccount();
applicationContext.close();
}
}
运行结果:
1.2.5 Spring 注解和 XML 的比较
注解的优势: 配置简单,维护方便(我们找到类,就相当于找到了对应的配置)。
XML 的优势: 修改时,不用改源码。不涉及重新编译和部署。
Spring 管理 Bean 方式的比较:
基于XML配置 | 基于注解配置 | |
---|---|---|
bean定义 | <bean id="..." class="..."/> | @Component、衍生类、@Controller、@Service 、@Repository |
bean名称 | 通过id或name指定 | @Component(“person”) |
bean注入 | <property> 或者通过p命名空间 | @Autowried按类型注入、@Qualifier按名称注入 |
生命过程、bean作用范围 | init-method、destroy-method范围scope属性 | @PostConstruct初始化、@PreDestroy销毁、@Scope设置作用范围 |
适用场景 | bean来自第三方,使用其它 | bean的实现类由用户自己开发 |
1.4 Spring基于xml的IOC配置
1.4.1 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.spg</groupId>
<artifactId>spring_day02_02account_xmlioc</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
</project>
1.4.2 准备数据库表和实体类
-- 创建数据库:
create database u4t117;
use u4t117;
-- 创建表:
create table account(
id int primary key auto_increment,
name varchar(40),
money float
)character set utf8 collate utf8_general_ci;
Account .java
package com.spg.domain;
import java.io.Serializable;
/**
* 账户的实体类
*/
public class Account implements Serializable {
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.4.3 编写持久层接口和实现类
package com.spg.dao;
import com.spg.domain.Account;
import java.util.List;
/**
* 账户的持久层接口
*/
public interface AccountDao {
/**
* 查询所有
* @return
*/
List<Account> findAllAccount();
/**
* 查询一个
* @return
*/
Account findAccountById(Integer accountId);
/**
* 保存
* @param account
*/
void saveAccount(Account account);
/**
* 更新
* @param account
*/
void updateAccount(Account account);
/**
* 删除
* @param acccountId
*/
void deleteAccount(Integer acccountId);
}
package com.spg.dao.impl;
import com.spg.dao.AccountDao;
import com.spg.domain.Account;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import java.util.List;
/**
* 账户的持久层实现类
*/
public class AccountDaoImpl implements AccountDao {
private QueryRunner runner;
public void setRunner(QueryRunner runner) {
this.runner = runner;
}
@Override
public List<Account> findAllAccount() {
try{
return runner.query("select * from account",new BeanListHandler<Account>(Account.class));
}catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public Account findAccountById(Integer accountId) {
try{
return runner.query("select * from account where id = ? ",new BeanHandler<Account>(Account.class),accountId);
}catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
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);
}
}
@Override
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);
}
}
@Override
public void deleteAccount(Integer accountId) {
try{
runner.update("delete from account where id=?",accountId);
}catch (Exception e) {
throw new RuntimeException(e);
}
}
}
1.4.4 编写业务层接口和实现类
package com.spg.service;
import com.spg.domain.Account;
import java.util.List;
/**
* 账户的业务层接口
*/
public interface AccountService {
/**
* 查询所有
* @return
*/
List<Account> findAllAccount();
/**
* 查询一个
* @return
*/
Account findAccountById(Integer accountId);
/**
* 保存
* @param account
*/
void saveAccount(Account account);
/**
* 更新
* @param account
*/
void updateAccount(Account account);
/**
* 删除
* @param acccountId
*/
void deleteAccount(Integer acccountId);
}
package com.spg.service.impl;
import com.spg.dao.AccountDao;
import com.spg.domain.Account;
import com.spg.service.AccountService;
import java.util.List;
/**
* 账户的业务层实现类
*/
public class AccountServiceImpl implements AccountService{
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public List<Account> findAllAccount() {
return accountDao.findAllAccount();
}
@Override
public Account findAccountById(Integer accountId) {
return accountDao.findAccountById(accountId);
}
@Override
public void saveAccount(Account account) {
accountDao.saveAccount(account);
}
@Override
public void updateAccount(Account account) {
accountDao.updateAccount(account);
}
@Override
public void deleteAccount(Integer accountId) {
accountDao.deleteAccount(accountId);
}
}
1.4.5 在配置文件中配置业务层和持久层
<?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">
<!-- 配置Service -->
<bean id="accountService" class="com.spg.service.impl.AccountServiceImpl">
<!-- 注入dao -->
<property name="accountDao" ref="accountDao"/>
</bean>
<!--配置Dao对象-->
<bean id="accountDao" class="com.spg.dao.impl.AccountDaoImpl">
<!-- 注入QueryRunner -->
<property name="runner" ref="runner"/>
</bean>
<!--配置QueryRunner-->
<bean id="runner" 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:3307/t117"/>
<property name="user" value="root"/>
<property name="password" value="root"/>
</bean>
</beans>
测试:
package com.spg.test;
import com.spg.domain.Account;
import com.spg.service.AccountService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;
/**
* 使用Junit单元测试:测试我们的配置
*/
public class AccountServiceTest {
@Test
public void testFindAll(){
// 1.获取容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
// 2.得到业务层对象
AccountService accountService = applicationContext.getBean("accountService", AccountService.class);
// 3.执行方法
List<Account> accounts = accountService.findAllAccount();
for (Account account : accounts) {
System.out.println(account);
}
}
@Test
public void testFindOne(){
// 1.获取容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
// 2.得到业务层对象
AccountService accountService = applicationContext.getBean("accountService", AccountService.class);
// 3.执行方法
Account account = accountService.findAccountById(1);
System.out.println(account);
}
@Test
public void testSave(){
// 1.获取容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
// 2.得到业务层对象
AccountService accountService = applicationContext.getBean("accountService", AccountService.class);
// 3.执行方法
Account account = new Account();
account.setName("Lily");
account.setMoney(1000f);
accountService.saveAccount(account);
}
@Test
public void testUpdate(){
// 1.获取容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
// 2.得到业务层对象
AccountService accountService = applicationContext.getBean("accountService", AccountService.class);
// 3.执行方法
Account account = new Account();
account.setId(4);
account.setName("rose");
account.setMoney(3000f);
accountService.updateAccount(account);
}
@Test
public void testDelete(){
// 1.获取容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
// 2.得到业务层对象
AccountService accountService = applicationContext.getBean("accountService", AccountService.class);
// 3.执行方法
accountService.deleteAccount(4);
}
}
1.5 Spring基于注解的IOC配置
修改持久层实现类
package com.spg.dao.impl;
import com.spg.dao.AccountDao;
import com.spg.domain.Account;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* 账户的持久层实现类
*/
@Repository("accountDao")
public class AccountDaoImpl implements AccountDao {
@Autowired
private QueryRunner runner;
@Override
public List<Account> findAllAccount() {
try{
return runner.query("select * from account",new BeanListHandler<Account>(Account.class));
}catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public Account findAccountById(Integer accountId) {
try{
return runner.query("select * from account where id = ? ",new BeanHandler<Account>(Account.class),accountId);
}catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
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);
}
}
@Override
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);
}
}
@Override
public void deleteAccount(Integer accountId) {
try{
runner.update("delete from account where id=?",accountId);
}catch (Exception e) {
throw new RuntimeException(e);
}
}
}
修改业务层实现类
package com.spg.service.impl;
import com.spg.dao.AccountDao;
import com.spg.domain.Account;
import com.spg.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 账户的业务层实现类
*/
@Service("accountService")
public class AccountServiceImpl implements AccountService{
@Autowired
private AccountDao accountDao;
@Override
public List<Account> findAllAccount() {
return accountDao.findAllAccount();
}
@Override
public Account findAccountById(Integer accountId) {
return accountDao.findAccountById(accountId);
}
@Override
public void saveAccount(Account account) {
accountDao.saveAccount(account);
}
@Override
public void updateAccount(Account account) {
accountDao.updateAccount(account);
}
@Override
public void deleteAccount(Integer accountId) {
accountDao.deleteAccount(accountId);
}
}
修改配置文件
<?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">
<!--配置Spring在创建容器时需要扫描的包-->
<context:component-scan base-package="com.spg"/>
<!--配置QueryRunner-->
<bean id="runner" 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:3307/t117"/>
<property name="user" value="root"/>
<property name="password" value="root"/>
</bean>
</beans>
1.6 spring 的纯注解配置
(1)@Configuration
作用: 用于指定当前类是一个 spring 配置类, 当创建容器时会从该类上加载注解。 获取容器时需要使用AnnotationApplicationContext
(有@Configuration
注解的类.class
)。
属性: value:
用于指定配置类的字节码
package com.spg.config;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbutils.QueryRunner;
import org.springframework.context.annotation.*;
import javax.sql.DataSource;
/**
* 该类是一个配置类,它的作用和bean.xml是一样的
* Spring中的新注解:
* @Configuration:
* 作用:指定当前类是一个配置类
* 细节:
* 当配置类作为AnnotationConfigApplicationContext对象创建的参数时,该注解可以不写
*/
@Configuration
public class SpringConfiguration {
}
(2)@ComponentScan
作用: 用于指定spring在初始化容器时要扫描的包。 作用和在spring的xml配置文件中的:<context:component-scan base-package="com.spg"/>
是一样的。
属性: basePackages:
用于指定要扫描的包。和该注解中的 value
属性作用一样。
package com.spg.config;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbutils.QueryRunner;
import org.springframework.context.annotation.*;
import javax.sql.DataSource;
/**
* 该类是一个配置类,它的作用和bean.xml是一样的
* Spring中的新注解:
* @ComponentScan:
* 作用:用于通过注解指定spring在创建容器时要扫描的包
* 属性:
* value:它和basePackages的作用是一样的,都是用于指定创建容器时要扫描的包
* 我们使用此注解就等同于在XML中配置了:
* <context:component-scan base-package="com.spg"/>
*/
//@Configuration
@ComponentScan("com.spg")
public class SpringConfiguration {
}
(3) @Bean
作用: 该注解只能写在方法上,表明使用此方法创建一个对象,并且放入 spring 容器。
属性: name:
给当前@Bean
注解方法创建的对象指定一个名称(即 bean
的 id
)。
jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3307/t117
jdbc.username=root
jdbc.password=root
package com.spg.config;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbutils.QueryRunner;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import javax.sql.DataSource;
/**
* 和spring连接数据库相关的配置类
*/
//@Configuration
public class JdbcConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
/**
* 用于创建一个QueryRunner对象
* @param dataSource
* @return
*/
@Bean(name = "runner")
@Scope("prototype")
public QueryRunner createQueryRunner(@Qualifier("dataSource") DataSource dataSource){
return new QueryRunner(dataSource);
}
/**
* 创建数据源对象
* @return
*/
@Bean(name = "dataSource")
@Scope("prototype")
public DataSource createDataSource(){
try {
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setDriverClass(driver);
ds.setJdbcUrl(url);
ds.setUser(username);
ds.setPassword(password);
return ds;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
(4) @PropertySource
作用: 用于加载.properties
文件中的配置。例如我们配置数据源时,可以把连接数据库的信息写到properties
配置文件中,就可以使用此注解指定 properties
配置文件的位置。
属性: value[]:
用于指定 properties
文件位置。如果是在类路径下,需要写上 classpath:
package com.spg.config;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbutils.QueryRunner;
import org.springframework.context.annotation.*;
import javax.sql.DataSource;
/**
* 该类是一个配置类,它的作用和bean.xml是一样的
* Spring中的新注解:
* @PropertySource:
* 作用:用于指定properties文件的位置
* 属性:
* value:指定文件的名称和路径。
* 关键字:classpath,表示类路径下
*/
//@Configuration
@ComponentScan("com.spg")
@PropertySource("classpath:jdbcConfig.properties")
public class SpringConfiguration {
}
(5) @Import
作用: 用于导入其他配置类,在引入其他配置类时,可以不用再写@Configuration
注解。 当然,写上也没问题。
属性: value[]:
用于指定其他配置类的字节码。
package com.spg.config;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbutils.QueryRunner;
import org.springframework.context.annotation.*;
import javax.sql.DataSource;
/**
* 该类是一个配置类,它的作用和bean.xml是一样的
* Spring中的新注解:
* @Import:
* 作用:用于导入其它的配置类
* 属性:
* value:用于指定其他配置类的字节码。
* 当我们使用@Import的注解之后,有@Import注解的类就是父配置类,而导入的都是子配置类
*/
//@Configuration
@ComponentScan("com.spg")
@Import(JdbcConfig.class)
@PropertySource("classpath:jdbcConfig.properties")
public class SpringConfiguration {
}
(6) 通过注解获取容器
ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class);
代码示例:
package com.spg.test;
import com.spg.config.JdbcConfig;
import com.spg.config.SpringConfiguration;
import com.spg.domain.Account;
import com.spg.service.AccountService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;
/**
* 使用Junit单元测试:测试我们的配置
*/
public class AccountServiceTest {
@Test
public void testFindAll(){
// 1.获取容器
// ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration.class);
// 2.得到业务层对象
AccountService accountService = applicationContext.getBean("accountService", AccountService.class);
// 3.执行方法
List<Account> accounts = accountService.findAllAccount();
for (Account account : accounts) {
System.out.println(account);
}
}
@Test
public void testFindOne(){
// 1.获取容器
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration.class);
// 2.得到业务层对象
AccountService accountService = applicationContext.getBean("accountService", AccountService.class);
// 3.执行方法
Account account = accountService.findAccountById(1);
System.out.println(account);
}
@Test
public void testSave(){
// 1.获取容器
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration.class);
// 2.得到业务层对象
AccountService accountService = applicationContext.getBean("accountService", AccountService.class);
// 3.执行方法
Account account = new Account();
account.setName("Lily");
account.setMoney(1000f);
accountService.saveAccount(account);
}
@Test
public void testUpdate(){
// 1.获取容器
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration.class);
// 2.得到业务层对象
AccountService accountService = applicationContext.getBean("accountService", AccountService.class);
// 3.执行方法
Account account = new Account();
account.setId(4);
account.setName("rose");
account.setMoney(3000f);
accountService.updateAccount(account);
}
@Test
public void testDelete(){
// 1.获取容器
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration.class);
// 2.得到业务层对象
AccountService accountService = applicationContext.getBean("accountService", AccountService.class);
// 3.执行方法
accountService.deleteAccount(4);
}
}
测试类:
package com.itheima.test;
import com.itheima.domain.Account;
import com.itheima.service.IAccountService;
import config.SpringConfiguration;
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.SpringJUnit4ClassRunner;
import java.util.List;
/**
* 使用Junit单元测试:测试我们的配置
* Spring整合junit的配置
* 1、导入spring整合junit的jar(坐标)
* 2、使用Junit提供的一个注解把原有的main方法替换了,替换成spring提供的
* @Runwith
* 3、告知spring的运行器,spring和ioc创建是基于xml还是注解的,并且说明位置
* @ContextConfiguration
* locations:指定xml文件的位置,加上classpath关键字,表示在类路径下
* classes:指定注解类所在地位置
*
* 当我们使用spring 5.x版本的时候,要求junit的jar必须是4.12及以上
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfiguration.class)
public class AccountServiceTest {
@Autowired
private IAccountService as = null;
@Test
public void testFindAll() {
//3.执行方法
List<Account> accounts = as.findAllAccount();
for(Account account : accounts){
System.out.println(account);
}
}
@Test
public void testFindOne() {
//3.执行方法
Account account = as.findAccountById(1);
System.out.println(account);
}
@Test
public void testSave() {
Account account = new Account();
account.setName("test anno");
account.setMoney(12345f);
//3.执行方法
as.saveAccount(account);
}
@Test
public void testUpdate() {
//3.执行方法
Account account = as.findAccountById(4);
account.setMoney(23456f);
as.updateAccount(account);
}
@Test
public void testDelete() {
//3.执行方法
as.deleteAccount(4);
}
}