Spring案例:使用IoC实现账户的CRUD及注解配置

需求:实现账户的CRUD操作
技术要求:使用Spring的IoC实现对象的管理
使用DBAssit作为持久层的解决方案
使用c3p0数据源

环境搭建

拷贝jar包

Spring案例:使用IoC实现账户的CRUD及注解配置_第1张图片

创建数据库和编写实体类

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); 
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;  } 
} 

编写持久层代码

public interface IAccountDao {    /** 
  * 保存   * @param account   */ 
   void save(Account account);    
   /** 
  * 更新   * @param account   */  
  void update(Account account); 
  /** 
  * 删除   * @param accountId   */ 
   void delete(Integer accountId);  
     /** 
  * 根据 id 查询   * @param accountId   * @return   */ 
   Account findById(Integer accountId);   
    /** 
  * 查询所有   * @return   */ 
 List findAll(); 
 
} 
 
public class AccountDaoImpl implements IAccountDao { 
 
 private DBAssit dbAssit;      
 public void setDbAssit(DBAssit dbAssit) {   
 this.dbAssit = dbAssit;  } 
 
 @Override  
 public void save(Account account) {   
 dbAssit.update("insert into account(name,money)values(?,?)",account.getName(),account.getMoney());  } 
 
 @Override 
  public void update(Account account) {   
 dbAssit.update("update account set name=?,money=? where id=?",account.getName(),account.getMoney(),account.getId());  } 
 
 @Override  
 public void delete(Integer accountId) {  
 dbAssit.update("delete from account where id=?",accountId);  } 
 
 @Override 
 public Account findById(Integer accountId) {   
 **return dbAssit.query("select * from account where id=?",new BeanHandler(Account.class),accountId);**  } 
 
 @Override  
 public List findAll() {   
 return  dbAssit.query("select * from account where id=?",new BeanListHandler(Account.class));  } 
 
} 

编写业务层代码

public interface IAccountService { 
 
 /** 
  * 保存账户   * @param account   */  
  void saveAccount(Account account);    
   /** 
  * 更新账户   * @param account   */ 
   void updateAccount(Account account);   
 /** 
  * 删除账户   * @param account   */  
  void deleteAccount(Integer accountId);   
   /** 
  * 根据 id 查询账户   * @param accountId   * @return   */ 
   Account findAccountById(Integer accountId);   
    /** 
  * 查询所有账户   * @return   */  
  List findAllAccount(); 
} 
public class AccountServiceImpl implements IAccountService {   
 private IAccountDao accountDao; 

 public void setAccountDao(IAccountDao accountDao) {  
  this.accountDao = accountDao; 
   } 
 
 @Override  
 public void saveAccount(Account account) {   
 accountDao.save(account);  } 
 
 @Override  
 public void updateAccount(Account account) {   
 accountDao.update(account);  } 
 
 @Override  
 public void deleteAccount(Integer accountId) {   
 accountDao.delete(accountId);  } 
 
 @Override  
 public Account findAccountById(Integer accountId) {   
 return accountDao.findById(accountId);  } 
 
 @Override  
 public List findAllAccount() {   
 return accountDao.findAll();  } 
} 

创建并编写配置文件

Spring案例:使用IoC实现账户的CRUD及注解配置_第2张图片

 

  

配置对象

  
   
 
  
 
   
    
   
 

  
 
 
 

  
 
    
   
   
   
  

编写测试类

public class AccountServiceTest {    /** 
  * 测试保存   */  
  @Test  
  public void testSaveAccount() {   
  Account account = new Account();   
  account.setName("张三");   
  account.setMoney(100000f);   
  ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");   
  IAccountService as = ac.getBean("accountService",IAccountService.class);   
  as.saveAccount(account);  } 
 
 /** 
  * 测试查询一个   */ 
 @Test  
 public void testFindAccountById() {   
 ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); 
 IAccountService as = ac.getBean("accountService",IAccountService.class);   
 Account account = as.findAccountById(1);   System.out.println(account);  } 
 /** 
  * 测试更新   */ 
 @Test  
 public void testUpdateAccount() {  
 ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");  
 IAccountService as = ac.getBean("accountService",IAccountService.class);   
 Account account = as.findAccountById(1);   
 account.setMoney(20301050f); 
  as.updateAccount(account);  }   
   /** 
  * 测试删除   */  
  @Test  
 public void testDeleteAccount() {   
 ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");  
 IAccountService as = ac.getBean("accountService",IAccountService.class);  
  as.deleteAccount(1);  } 
 
 /** 
  * 测试查询所有   */ 
 @Test 
 public void testFindAllAccount() {   
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");   
IAccountService as = ac.getBean("accountService",IAccountService.class);  
 List list = as.findAllAccount();  
  for(Account account : list) {    
  System.out.println(account);  
   }  
   } 
}

上述测试类每个测试方法都重新获取了一次spring的核心容器,造成不必要的重复代码。

上述案例基于xml配置,下面介绍基于注解的配置方式

拷贝jar包

Spring案例:使用IoC实现账户的CRUD及注解配置_第3张图片

使用@Component注解配置管理的资源

@Component("accountService") 
public class AccountServiceImpl implements IAccountService {    
private IAccountDao accountDao; 
public void setAccountDao(IAccountDao accountDao) {   
this.accountDao = accountDao; 
 } 
} 
@Component("accountDao") 
public class AccountDaoImpl  implements IAccountDao { 
  private DBAssit dbAssit; } 

当使用注解注入时,set方法不用写

创建spring的xml配置文件并开启对注解的支持

基于注解整合时,导入约束时需要多导入一个 context 名称空间下的约束。 由于我们使用了注解配置,此时不能在继承 JdbcDaoSupport,需要自己配置一个 JdbcTemplate

  
   
   
    
  
    
   
    
    
    
    
   
  

常用注解

用于创建对象

相当于

@Component

  • 作用: 把资源让 spring 来管理。相当于在 xml 中配置一个 bean。
  • 属性: value:指定 bean 的 id。如果不指定 value 属性,默认 bean 的 id 是当前类的类名。首字母小写。

@Controller @Service @Repository

  • 他们三个注解都是针对一个的衍生注解,他们的作用及属性都是一模一样的。 他们只不过是提供了更加明确的语义化。
  • @Controller:一般用于表现层的注解。
  • @Service:一般用于业务层的注解。
  • @Repository:一般用于持久层的注解。
  • 细节:如果注解中有且只有一个属性要赋值时,且名称是 value,value在赋值是可以不写。

用于注入数据

相当于

@Autowired

  • 自动按照类型注入。当使用注解注入属性时,set方法可以省略。它只能注入其他 bean 类型。当有多个 类型匹配时,使用要注入的对象变量名称作为 bean 的 id,在 spring 容器查找,找到了也可以注入成功。找不到 就报错。
  • 属性: value:指定 bean 的 id。

@Qualifier

  • 在自动按照类型注入的基础之上,再按照 Bean 的 id 注入。它在给字段注入时不能独立使用,必须和 @Autowire 一起使用;但是给方法参数注入时,可以独立使用。
  • 属性: name:指定 bean 的 id。

@Resource

  • 直接按照 Bean 的 id 注入。它也只能注入其他 bean 类型。
  • 属性: name:指定 bean 的 id。

@Value

  • 作用: 注入基本数据类型和 String 类型数据的
  • 属性: value:用于指定值

用于改变作用范围

相当于

@Scope

  • 指定 bean 的作用范围。
  • 属性: value:指定范围的值。
  • 取值:singleton prototype request session globalsession

如何选择注解或xml

注解的优势

  • 配置简单,维护方便

XML的优势

  • 修改时,不用改源码。不涉及重新编译和部署
    Spring案例:使用IoC实现账户的CRUD及注解配置_第4张图片

上述注解配置还是不能彻底脱离xml文件 <<<<<<<<<<<<<

@Configuration

  • 用于指定当前类是一个 spring 配置类,当创建容器时会从该类上加载注解。获取容器时需要使用 AnnotationApplicationContext(有@Configuration 注解的类.class)。
  • 属性: value:用于指定配置类的字节码
/** 
 * spring 的配置类,相当于 bean.xml 文件  * / 
 @Configuration 
 public class SpringConfiguration { } 
注意:  我们已经把配置文件用类来代替了,但是如何配置创建容器时要扫描的包呢? 

@ComponentScan

  • 作用: 用于指定 spring 在初始化容器时要扫描的包。
  • 作用和在 spring 的 xml 配置文件中的: 是一样的。
  • 属性: basePackages:用于指定要扫描的包。和该注解中的 value 属性作用一样。
@Configuration @ComponentScan("com.itheima") 
public class SpringConfiguration { } 
注意:  我们已经配置好了要扫描的包,但是数据源和 JdbcTemplate 对象如何从配置文件中移除呢? 

@Bean

  • 该注解只能写在方法上,表明使用此方法创建一个对象,并且放入 spring 容器。
  • 属性: name:给当前@Bean 注解方法创建的对象指定一个名称(即 bean 的 id)
public class JdbcConfig { 
 
 /** 
  * 创建一个数据源,并存入 spring 容器中   * @return   */  
 @Bean(name="dataSource") 
 public DataSource createDataSource() {  
  try {    
  ComboPooledDataSource ds = new ComboPooledDataSource();    
  ds.setUser("root");
  ds.setPassword("1234");   
   ds.setDriverClass("com.mysql.jdbc.Driver"); 
   ds.setJdbcUrl("jdbc:mysql:///spring_day02");    
   return ds;   } 
   catch (Exception e) {  
     throw new RuntimeException(e);  
      }  }  
 
 /** 
  * 创建一个 DBAssit,并且也存入 spring 容器中   * @param dataSource   * @return   */  
  @Bean(name="dbAssit")  
  public DBAssit createDBAssit(DataSource dataSource) {   
  return new DBAssit(dataSource);  }  } 
  我们已经把数据源和 DBAssit 从配置文件中移除了,此时可以删除 bean.xml 了。  但是由于没有了配置文件,创建数据源的配置又都写死在类中了。如何把它们配置出来呢

@PropertySource

  • 用于加载.properties 文件中的配置。
  • 例如我们配置数据源时,可以把连接数据库的信息写到 properties 配置文件中,就可以使用此注解指定 properties 配置文件的位置。
  • 属性: value[]:用于指定 properties 文件位置。如果是在类路径下,需要写上 classpath:
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; 
 
 /** 
  * 创建一个数据源,并存入 spring 容器中   * @return   */  
  @Bean(name="dataSource")  
  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);   }  }  
} 
 
jdbc.properties 文件: 
 jdbc.driver=com.mysql.jdbc.Driver  
 jdbc.url=jdbc:mysql://localhost:3306/day44_ee247_spring 
 jdbc.username=root 
 jdbc.password=1234 
 此时我们已经有了两个配置类,但是他们还没有关系。如何建立他们的关系呢? 

Import

  • 用于导入其他配置类,在引入其他配置类时,可以不用再写@Configuration 注解。当然,写上也没问 题。
  • 属性: value[]:用于指定其他配置类的字节码。
@Configuration 
@ComponentScan(basePackages = "com.itheima.spring") 
@Import({ JdbcConfig.class}) 
public class SpringConfiguration { } 
 
@Configuration 
@PropertySource("classpath:jdbc.properties") 
public class JdbcConfig{ }
我们已经把要配置的都配置好了,但是新的问题产生了,由于没有配置文件了,如何获取容器呢? 

通过注解获取容器

ApplicationContext ac =     new AnnotationConfigApplicationContext(SpringConfiguration.class); 

Spring整合Junit

测试类中的问题及解决思路

  • 问题:
  • 在测试类中,每个测试方法都有以下两行代码:
  • ApplicationContext ac = new ClassPathXmlApplicationContext(“bean.xml”);
  • IAccountService as = ac.getBean(“accountService”,IAccountService.class);
    这两行代码的作用是获取容器,如果不写的话,直接会提示空指针异常。所以又不能轻易删掉。
  • 解决思路:
  • 我们需要的是程序能自动帮我们创建容器。一旦程序能自动为我们创建 spring 容器,我们就 无须手动创建了,问题也就解决了。 我们都知道,junit 单元测试的原理(在 web 阶段课程中讲过),但显然,junit 是无法实现的,因为它自 己都无法知晓我们是否使用了 spring 框架,更不用说帮我们创建 spring 容器了。不过好在,junit 给我们暴露 了一个注解,可以让我们替换掉它的运行器。 这时,我们需要依靠 spring 框架,因为它提供了一个运行器,可以读取配置文件(或注解)来创建容器。我 们只需要告诉它配置文件在哪就行了

配置步骤

拷贝jar包

Spring案例:使用IoC实现账户的CRUD及注解配置_第5张图片

使用@RunWith注解替换原有运行器

@RunWith(SpringJUnit4ClassRunner.class) 
public class AccountServiceTest { } 

使用@ContextConfiguration指定spring配置文件的位置

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations= {"classpath:bean.xml"}) 
public class AccountServiceTest { } 

@ContextConfiguration 注解:
locations 属性:用于指定配置文件的位置。如果是类路径下,需要用 classpath:表明
classes 属性:用于指定注解的类。当不使用 xml 配置时,需要用此属性指定注解类的位置。

使用@Autowired给测试类中的变量注入数据

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations= {"classpath:bean.xml"})
 public class AccountServiceTest {    
@Autowired 
 private IAccountService as ; }

你可能感兴趣的:(Spring案例:使用IoC实现账户的CRUD及注解配置)