Spring框架第二篇

编程

public interface IAccountDao {

/**

* 查询所有账户信息

*

* @return

*/

List<Account> findAll();

/**

* 根据id查询一个数据

* @param id

* @return

*/

Account findOne(int id);

/**

* 添加一个新数据

* @param account

*/

void save(Account account);

/**

* 更新

* @param account

*/

void update(Account account);

/**

* 删除

* @param id

*/

void del(int id);

}

实现类

public class AccountDaoImpl implements IAccountDao {

private QueryRunner runner = null;

public void setRunner(QueryRunner runner) {

this.runner = runner;

}

@Override

public List<Account> findAll() {

try{

String sql = "select * from account";

return runner.query(sql,new BeanListHandler<Account>(Account.class));

}catch (Exception e){

e.printStackTrace();

}

return null;

}

@Override

public Account findOne(int id) {

try{

String sql = "select * from account where id=?";

return runner.query(sql,new BeanHandler<>(Account.class),id);

}catch (Exception e){

e.printStackTrace();

}

return null;

}

@Override

public void save(Account account) {

try{

String sql = "INSERT INTO account(NAME,money) VALUES(?,?)";

runner.update(sql,account.getName(),account.getMoney());

}catch (Exception e){

e.printStackTrace();

}

}

@Override

public void update(Account account) {

try{

String sql = "UPDATE account SET NAME=?,money=? WHERE id=?";

runner.update(sql,account.getName(),account.getMoney(),account.getId());

}catch (Exception e){

e.printStackTrace();

}

}

@Override

public void del(int id) {

try{

String sql = "DELETE FROM account WHERE id=?";

runner.update(sql,id);

}catch (Exception e){

e.printStackTrace();

}

}

}

1.2.5-创建业务层

接口

public interface IAccountServices {

/**

* 查询所有账户信息

*

* @return

*/

List<Account> findAll();

/**

* 根据id查询一个数据

* @param id

* @return

*/

Account findOne(int id);

/**

* 添加一个新数据

* @param account

*/

void save(Account account);

/**

* 更新

* @param account

*/

void update(Account account);

/**

* 删除

* @param id

*/

void del(int id);

}

实现类

public class AccountServicesImpl implements IAccountServices {

private IAccountDao dao = null;

public void setDao(IAccountDao dao) {

this.dao = dao;

}

@Override

public List<Account> findAll() {

return dao.findAll();

}

@Override

public Account findOne(int id) {

return dao.findOne(id);

}

@Override

public void save(Account account) {

dao.save(account);

}

@Override

public void update(Account account) {

dao.update(account);

}

@Override

public void del(int id) {

dao.del(id);

}

}

1.2.6-创建配置文件

<?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

https://www.springframework.org/schema/beans/spring-beans.xsd">

</beans>

1.3-配置步骤

<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

https://www.springframework.org/schema/beans/spring-beans.xsd">

<!--配置IAccountService对象-->

<bean id="accountService" class="cn.lpl666.services.impl.AccountServicesImpl">

<property name="dao" ref="accountDao"></property>

</bean>

<!--配置IAccountDao对象-->

<bean id="accountDao" class="cn.lpl666.dao.impl.AccountDaoImpl">

<property name="runner" ref="queryRunner"></property>

</bean>

<!--配置QueryRunner-->

<bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">

<!--注入数据源-->

<constructor-arg name="ds" ref="c3p0"></constructor-arg>

</bean>

<!--配置数据源-->

<bean id="c3p0" class="com.mchange.v2.c3p0.ComboPooledDataSource">

<!--注入连接数据库必备信息-->

<property name="driverClass" value="com.mysql.jdbc.Driver"></property>

<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/db1"></property>

<property name="user" value="root"></property>

<property name="password" value="root"></property>

</bean>

</beans>

1.4-测试

public class ClientTest {

// 创建Spring容器

private ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");

// 获取IAccountServices对象

private IAccountServices services = ac.getBean("accountService",IAccountServices.class);

/**

* 查询所有

*/

@Test

public void findAll(){

List<Account> all = services.findAll();

System.out.println(all);

}

/**

* 查询一个

*/

@Test

public void findOne(){

Account account = services.findOne(1);

System.out.println(account);

}

/**

* 添加

*/

@Test

public void save(){

Account account = new Account();

account.setName("test2");

account.setMoney(40000);

services.save(account);

}

/**

* 修改

*/

@Test

public void update(){

Account account = services.findOne(1);

account.setMoney(9999);

services.update(account);

}

/**

* 删除

*/

@Test

public void del(){

services.del(6);

}

}

第二章:基于注解的IOC配置

2.1-环境搭建

Maven引入依赖包

  <dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-context</artifactId>

<version>5.2.3.RELEASE</version>

</dependency>

持久层接口和实现类

接口

public interface IAccountDao {

void save();

}

实现类

@Component("accountDao")

public class AccountDaoImpl implements IAccountDao {

@Override

public void save() {

System.out.println("保存了账户");

}

}

服务层接口和实现类

接口

public interface IAccountServices {

void save();

}

实现类

@Component("accountService")

@Scope("prototype")

public class AccountServicesImpl implements IAccountServices {

@Autowired

@Qualifier("accountDao")

private IAccountDao dao = null;

@Value("10")

private int number;

@Override

public void save() {

dao.save();

System.out.println(number);

}

}

配置文件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

https://www.springframework.org/schema/beans/spring-beans.xsd

http://www.springframework.org/schema/context

https://www.springframework.org/schema/context/spring-context.xsd">

<!--

告知 spring 创建容器时要扫描的包

cn.lpl666包下所有的dao层、服务层、实体类都会被扫描

-->

<context:component-scan base-package="cn.lpl666"/>

</beans>

测试类

public class ClientUI {

public static void main(String[] args) {

ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");

IAccountServices services =(IAccountServices) ac.getBean("accountService");

services.save();

}

}

2.2-常用注解

2.2.1-用于创建对象的

相当于:<bean id="" class="">

@Component

作用:把资源让 spring 来管理。相当于在 xml 中配置一个 bean。

属性:value,指定 bean 的 id。如果不指定 value 属性,默认 bean 的 id 是当前类的类名。首字母小写

@Component("accountService")

public class AccountServicesImpl implements IAccountServices {}

@Controller、 @Service、 @Repository

他们三个注解都是针对一个的(@Component)衍生注解,他们的作用及属性都是一模一样的。

他们只不过是提供了更加明确的语义化。

@Controller:一般用于表现层的注解。

@Service:一般用于业务层的注解。

@Repository:一般用于持久层的注解。

细节:如果注解中有且只有一个属性要赋值时,且名称是 value,value 在赋值是可以不写。

2.2.2-用于注入数据的

相当于: <property name="" value=""><property name="" ref="">

@Autowired

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

@Qualifier

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

属性:value:指定 bean 的 id。

@Component("accountService")

public class AccountServicesImpl implements IAccountServices {

@Autowired

@Qualifier("accountDao")

private IAccountDao dao = null;

)

@Resource

作用: 直接按照 Bean 的 id 注入。它也只能注入其他 bean 类型。

属性: name,指定 bean 的 id。

@Component("accountService")

public class AccountServicesImpl implements IAccountServices {

@Resource(name="accountDao")

private IAccountDao dao = null;

)

@Value

作用: 注入基本数据类型和 String 类型数据的

属性: value,用于指定值

  @Value("10")

private int number;

2.2.3-用于改变作用范围的

相当于:<bean id="" class="" scope="">

@Scope

作用: 指定 bean 的作用范围。

属性: value,指定范围的值。

  • 取值:singleton prototype request session globalsession

@Component("accountService")

@Scope("prototype")

public class AccountServicesImpl implements IAccountServices {}

2.2.4-和生命周期相关的

相当于:<bean id="" class="" init-method="" destroy-method="">

@PostConstruct

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

@PreDestroy

作用:用于指定销毁方法

2.2.5-注解和 XML 的选择问题

注解的优势: 配置简单,维护方便(我们找到类,就相当于找到了对应的配置)。

XML 的优势: 修改时,不用改源码。不涉及重新编译和部署

Spring 管理 Bean 方式的比较:

2.3-注解IOC实现CRUD

2.3.1-需求和技术要求

同上第一章:1.1-需求和技术要求

2.3.2-Maven工程导入依赖

<dependencies>

<!--junit-->

<dependency>

<groupId>junit</groupId>

<artifactId>junit</artifactId>

<version>4.12</version>

<scope>test</scope>

</dependency>

<!--dbUtils-->

<dependency>

<groupId>commons-dbutils</groupId>

<artifactId>commons-dbutils</artifactId>

<version>1.4</version>

</dependency>

<!--c3p0-->

<dependency>

<groupId>com.mchange</groupId>

<artifactId>c3p0</artifactId>

<version>0.9.5.2</version>

</dependency>

<!--spring-->

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-context</artifactId>

<version>5.2.3.RELEASE</version>

</dependency>

<!--spring-test-->

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-test</artifactId>

<version>5.2.3.RELEASE</version>

<scope>test</scope>

</dependency>

<!--mysql-->

<dependency>

<groupId>mysql</groupId>

<artifactId>mysql-connector-java</artifactId>

<version>5.1.26</version>

</dependency>

</dependencies>

2.3.3-数据库脚本

同上第一章:1.2.2-数据库脚本

2.3.4-创建实体类

同上第一章:1.2.3-创建实体类

2.3.5-创建持久层

接口:

public interface IAccountDao {

/**

* 查询所有账户信息

*

* @return

*/

List<Account> findAll();

/**

* 根据id查询一个数据

* @param id

* @return

*/

Account findOne(int id);

/**

* 添加一个新数据

* @param account

*/

void save(Account account);

/**

* 更新

* @param account

*/

void update(Account account);

/**

* 删除

* @param id

*/

void del(int id);

}

实现类:

@Repository("accountDao")

public class AccountDaoImpl implements IAccountDao {

@Autowired

private QueryRunner runner = null;

@Override

public List<Account> findAll() {

try{

String sql = "select * from account";

return runner.query(sql,new BeanListHandler<Account>(Account.class));

}catch (Exception e){

e.printStackTrace();

}

return null;

}

@Override

public Account findOne(int id) {

try{

String sql = "select * from account where id=?";

return runner.query(sql,new BeanHandler<>(Account.class),id);

}catch (Exception e){

e.printStackTrace();

}

return null;

}

@Override

public void save(Account account) {

try{

String sql = "INSERT INTO account(NAME,money) VALUES(?,?)";

runner.update(sql,account.getName(),account.getMoney());

}catch (Exception e){

e.printStackTrace();

}

}

@Override

public void update(Account account) {

try{

String sql = "UPDATE account SET NAME=?,money=? WHERE id=?";

runner.update(sql,account.getName(),account.getMoney(),account.getId());

}catch (Exception e){

e.printStackTrace();

}

}

@Override

public void del(int id) {

try{

String sql = "DELETE FROM account WHERE id=?";

runner.update(sql,id);

}catch (Exception e){

e.printStackTrace();

}

}

}

2.3.6-创建业务层

接口:

public interface IAccountServices {

/**

* 查询所有账户信息

*

* @return

*/

List<Account> findAll();

/**

* 根据id查询一个数据

* @param id

* @return

*/

Account findOne(int id);

/**

* 添加一个新数据

* @param account

*/

void save(Account account);

/**

* 更新

* @param account

*/

void update(Account account);

/**

* 删除

* @param id

*/

void del(int id);

}

实现类:

@Service("accountService")

@Scope("prototype")

public class AccountServicesImpl implements IAccountServices {

@Autowired

@Qualifier("accountDao")

private IAccountDao dao = null;

@Override

public List<Account> findAll() {

return dao.findAll();

}

@Override

public Account findOne(int id) {

return dao.findOne(id);

}

@Override

public void save(Account account) {

dao.save(account);

}

@Override

public void update(Account account) {

dao.update(account);

}

@Override

public void del(int id) {

dao.del(id);

}

}

2.3.7-创建jdbc配置文件

jdbc.properties

jdbc.driver=com.mysql.jdbc.Driver

jdbc.url=jdbc:mysql://localhost:3306/db1

jdbc.user=root

jdbc.password=root

2.3.8-创建jdbc配置类

@PropertySource("classpath:jdbc.properties")

public class JdbcConfig {

@Value("${jdbc.driver}")

private String driver;

@Value("${jdbc.url}")

private String url;

@Value("${jdbc.user}")

private String username;

@Value("${jdbc.password}")

private String password;

/**

* 创建QueryRunner对象

* @param ds

* @return

*/

@Bean(name="runner")

@Scope("prototype")

public QueryRunner createQueryRunner(@Qualifier("dataSource") DataSource ds){

return new QueryRunner(ds);

}

/**

* 创建数据源对象

* @return

*/

@Bean(name = "dataSource")

public DataSource createDataSource() {

try {

ComboPooledDataSource ds = new ComboPooledDataSource();

ds.setUser(username);

ds.setPassword(password);

ds.setDriverClass(driver);

ds.setJdbcUrl(url);

return ds;

} catch (Exception e) {

throw new RuntimeException(e);

}

}

}

2.3.9-创建Spring配置类

/**

【Configuration】

标识该类是配置类,相当于bean.xml配置文件

【ComponentScan】

用于指定 spring 在初始化容器时要扫描的包。作用和在 spring 的 xml 配置文件中的:

<context:component-scan base-package="cn.lpl666"/>是一样的。

*/

@Configuration // 表示该类是配置类

@ComponentScan("cn.lpl666") // spring容器要扫描的包

@Import({JdbcConfig.class}) // 导入其他配置类

public class SpringConfiguration {

}

2.3.10-测试

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(classes = SpringConfiguration.class)

public class ClientTest {

// 创建Spring容器

private ApplicationContext as = null;

// 获取IAccountServices对象

@Autowired

private IAccountServices services = null;

/**

* 查询所有

*/

@Test

public void findAll(){

List<Account> all = services.findAll();

System.out.println(all);

}

/**

* 查询一个

*/

@Test

public void findOne(){

Account account = services.findOne(1);

System.out.println(account);

}

/**

* 添加

*/

@Test

public void save(){

Account account = new Account();

account.setName("test3");

account.setMoney(40000);

services.save(account);

}

/**

* 修改

*/

@Test

public void update(){

Account account = services.findOne(1);

account.setMoney(9999);

services.update(account);

}

/**

* 删除

*/

@Test

public void del(){

services.del(6);

}

}

2.4-新注解

@Configuration

作用: 用于指定当前类是一个 spring 配置类,当创建容器时会从该类上加载注解。获取容器时需要使用 AnnotationApplicationContext(有@Configuration 注解的类.class)。

属性: value:用于指定配置类的字节码

@Configuration    // 表示该类是配置类

public class SpringConfiguration {

}

@ComponentScan

作用: 用于指定 spring 在初始化容器时要扫描的包。作用和在 spring 的 xml 配置文件中的:<context:component-scan base-package="cn.lpl666"/> 是一样的。

属性: basePackages:用于指定要扫描的包。和该注解中的 value 属性作用一样。

@Configuration    // 表示该类是配置类

@ComponentScan("cn.lpl666") // spring容器要扫描的包

public class SpringConfiguration {

}

@Bean

作用: 该注解只能写在方法上,表明使用此方法创建一个对象,并且放入 spring 容器。

属性: name:给当前@Bean 注解方法创建的对象指定一个名称(即 bean 的 id)。

public class JdbcConfig {

/**

* 创建QueryRunner对象

* @param ds

* @return

*/

@Bean(name="runner")

@Scope("prototype")

public QueryRunner createQueryRunner(@Qualifier("dataSource") DataSource ds){

return new QueryRunner(ds);

}

}

@PropertySource

作用:用于加载.properties 文件中的配置。例如我们配置数据源时,可以把连接数据库的信息写到 properties 配置文件中,就可以使用此注解指定 properties 配置文件的位置。

属性: value[]:用于指定 properties 文件位置。如果是在类路径下,需要写上 classpath:

@PropertySource("classpath:jdbc.properties")

public class JdbcConfig {}

@Import

作用: 用于导入其他配置类,在引入其他配置类时,可以不用再写@Configuration 注解。当然,写上也没问 题。 属性: value[]:用于指定其他配置类的字节码。

@Import({JdbcConfig.class})  // 导入其他配置类

public class SpringConfiguration {

}

2.5-通过注解获取容器

ApplicationContext ac =

new AnnotationConfigApplicationContext(SpringConfiguration.class);

2.6- Spring 整合 Junit

2.6.1-问题

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

ApplicationContext ac =new AnnotationConfigApplicationContext(SpringConfiguration.class);

IAccountService as = ac.getBean("accountService",IAccountService.class);

这两行代码的作用是获取容器,如果不写的话,直接会提示空指针异常。所以又不能轻易删掉。

2.6.2-解决思路分析

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

无须手动创建了,问题也就解决了。

junit 是无法实现的,因为它自己都无法知晓我们是否使用了 spring 框架,更不用说帮我们创建 spring 容器了。不过好在,junit 给我们暴露了一个注解,可以让我们替换掉它的运行器。

这时,我们需要依靠 spring 框架,因为它提供了一个运行器,可以读取配置文件(或注解)来创建容器。我

们只需要告诉它配置文件在哪就行了。

2.6.3-配置步骤

第一步: Maven引入依赖包,并且junit的版本要在4.12或以上版本

    <!--junit-->

<dependency>

<groupId>junit</groupId>

<artifactId>junit</artifactId>

<version>4.12</version>

<scope>test</scope>

</dependency>

<!--spring-->

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-context</artifactId>

<version>5.2.3.RELEASE</version>

</dependency>

<!--spring-test-->

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-test</artifactId>

<version>5.2.3.RELEASE</version>

<scope>test</scope>

</dependency>

第二步:使用@RunWith 注解替换原有运行器

@RunWith(SpringJUnit4ClassRunner.class)

public class ClientTest {}

第三步:使用@ContextConfiguration 指定 spring 配置文件的位置

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(classes = SpringConfiguration.class)

// 若是xml配置,则使用:@ContextConfiguration(locations = "classpath:bean.xml")

public class ClientTest {}

@ContextConfiguration 注解:

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

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

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations = "classpath:bean.xml")

public class ClientTest {

// 获取IAccountServices对象

@Autowired

private IAccountServices services = null;

}

2.6.4-为什么不把测试类配置到xml中

在解释这个问题之前,先解除大家的疑虑,配到 XML 中能不能用呢?

答案是肯定的,没问题,可以使用。

那么为什么不采用配置到 xml 中的方式呢?

这个原因是这样的:

第一:当我们在 xml 中配置了一个 bean,spring 加载配置文件创建容器时,就会创建对象。

第二:测试类只是我们在测试功能时使用,而在项目中它并不参与程序逻辑,也不会解决需求上的问

题,所以创建完了,并没有使用。那么存在容器中就会造成资源的浪费。

所以,基于以上两点,我们不应该把测试配置到 xml 文件中。

以上是 Spring框架第二篇 的全部内容, 来源链接: utcz.com/z/513452.html

回到顶部