Spring一:入门程序和增删改查
目录
- 1 概述
- 2 入门程序
- 2.1 xml方式
- 2.2 annotation方式
- 3 增删改查
- 3.1 xml方式
- 3.2 annotation方式
1 概述
简介
-
Spring是分层的Java SE/EE应用full-stack(一站式)轻量级开源框架,以IoC(Inverse Of Control 反转控制)和AOP(Aspect Oriented Programming 面向切面编程)为内核,使用基本的Java Bean来完成以前只可能由EJB ( Enterprise Java Beans, Java企业Bean)完成的工作,取代了EJB的靡肿、低效的开发模式。
-
Spring在表现层提供了SpringMVC与Struts框架的整合功能;在业务逻辑层可以管理事务、记录日志等;在持久层可以整合MyBatis、 Hibernate、JdbcTemplate等技术。因此,可以说Spring是企业应用开发很好的"一站式"选择。
-
优点
- 方便解耦、简化开发
- 支持AOP
- 支持声明式事务处理
- 方便程序的测试
- 方便集成各种优秀框架
- 降低JavaEE API的使用难度
- 非侵入式设计
-
体系结构
IoC & DI
-
耦合性
- 耦合性(Coupling),也叫耦合度,是对模块间关联程度的度量。耦合的强弱取决于模块间接口的复杂性、调用模块的方式以及通过界面传送数据的多少。模块间的耦合度是指模块之间的依赖关系,包括控制关系、调用关系、数据传递关系。模块间联系越多,其耦合性越强,同时表明其独立性越差( 降低耦合性,可以提高其独立性)。耦合性存在于各个领域,而非软件设计中独有的,但是我们只讨论软件工程中的耦合。
- 在软件工程中,耦合指的就是就是对象之间的依赖性。对象之间的耦合越高,维护成本越高。因此对象的设计应使类和构件之间的耦合最小。软件设计中通常用耦合度和内聚度作为衡量模块独立程度的标准。划分模块的一个准则就是高内聚低耦合。
- 耦合类型
- 内容耦合:当一个模块直接修改或操作另一个模块的数据时,或一个模块不通过正常入口而转入另一个模块时,这样的耦合被称为内容耦合。内容耦合是最高程度的耦合,应该避免使用。
- 公共耦合:两个或两个以上的模块共同引用一个全局数据项,这种耦合被称为公共耦合。
- 外部耦合:一组模块都访问同一全局简单变量而不是同一全局数据结构,而且不是通过参数表传递该全局变量的信息,则称之为外部耦合。
- 控制耦合:一个模块通过接口向另一个模块传递一个控制信号,接受信号的模块根据信号值而进行适当的动作,这种耦合被称为控制耦合。
- 标记耦合:若一个模块A通过接口向两个模块B和C传递一个公共参数,那么称模块B和C之间存在一个标记耦合。
- 数据耦合:模块之间通过参数来传递数据,那么被称为数据耦合。数据耦合是最低的一种耦合形式。
- 非直接耦合:两个模块之间没有直接关系,它们之间的联系完全是通过主模块的控制和调用来实现的。
- 总结: 耦合是影响软件复杂程度和设计质量的一个重要因素,在设计上我们应采用以下原则:如果模块间必须存在耦合,就尽量使用数据耦合,少用控制耦合,限制公共耦合的范围,尽量避免使用内容耦合。
-
内聚性
- 内聚标志一个模块内各个元素彼此结合的紧密程度,它是信息隐蔽和局部化概念的自然扩展。内聚是从功能角度来度量模块内的联系,一个好的内聚模块应当恰好做一件事。
- 内聚描述的是模块内的功能联系,耦合是模块之间的联系。
- 程序讲究的是低耦合,高内聚。就是同一个模块内的各个元素之间要高度紧密,但是各个模块之间的相互依存度却要不那么紧密。
- 内聚和耦合是密切相关的,同其他模块存在高耦合的模块意味着低内聚,而高内聚的模块意味着该模块同其他模块之间是低耦合。在进行软件设计时,应力争做到高内聚,低耦合。
-
可以使用工厂模式解耦。
-
控制反转(IoC)作用:它不能实现数据库的增删改查,也不能实现表现层的请求参数的封装,甚至也无法接收请求,能干的事情只有一件,即降低程序间的耦合(依赖关系)。注:是降低(用到工厂模式,工程模式用到反射),不能消除。
xml 和 annotation 对比
-
见下表
- xml优点:修改时,不用改源码,不涉及重新编译和部署;annotation优势:配置简单,维护方便。
对比项 xml annotation Bean的定义 @Component,衍生物@Controller @Service @Repository Bean的名称 通过id或name指定 @Component("user") Bean的注入
属性(即set注入,最常用)@Autowired按类型注入 ; @Qualifier按名称注入 生命周期 init-method、destroy-method @PostConstruct初始化、@PreDestroy销毁 Bean作用范围 scope属性 @Scope 适用场景 Bean来自第三方,使用它 Bean的实现类由用户自己开发 -
常用注解
分类 注解 说明 xml 方式 创建对象 @Component
@Controller
@Service
@Repository把资源让spring来管理,即在xml中配置一个bean 注入数据 @Autowired
@Qualifier
@Resource
@Value前三个用于注入 bean,第四个用于注入值
或作用域 @Scope 指定bean的作用范围 生命周期 @PostConstruct
@PreDestroy用于指定初始化/销毁的方法 新注解 @Configuration 用于指定当前类是一个spring配置类,相当于代替了bean.xml @ComponentScan 用于指定spring在初始化容器时要扫描的包 @Bean 该注解只能写在方法上,表明使用此方法创建一个对象,并且放入spring容器 @PropertySource 用于加载 .properties
文件中的配置@Import 用于导入其他配置类,在引入其他配置类时,可以不用再写@Configuration注解(当然写上也没问题)
2 入门程序
2.1 xml方式
-
创建普通 maven 工程即可,项目整体结构如下
-
依赖
org.springframework spring-context 5.2.18.RELEASE -
业务层
package cn.service; public interface UserService { void say(); }
package cn.service.impl; import cn.service.UserService; public class UserServiceImpl implements UserService { @Override public void say() { System.out.println("Hello Spring ! 我用xml方式入门了!"); } }
-
application.xml
<?xml version="1.0" encoding="UTF-8"?>
-
运行
package cn; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import cn.service.UserService; public class App { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml"); UserService service = (UserService) applicationContext.getBean("userService"); service.say(); /** * 结果 * Hello Spring ! 我用xml方式入门了! */ } }
2.2 annotation方式
-
普通maven工程,项目结构如下
-
依赖
org.springframework spring-context 5.2.18.RELEASE -
业务层
package cn.service; public interface UserService { void say(); }
package cn.service.impl; import cn.service.UserService; import org.springframework.stereotype.Component; @Component("userService") public class UserServiceImpl implements UserService { @Override public void say() { System.out.println("Hello Spring ! 我用annotation方式入门了!"); } }
-
配置类
package cn.conf; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan("cn.service") public class SpringConf { }
-
运行
package cn; import cn.conf.SpringConf; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import cn.service.UserService; public class App { public static void main(String[] args) { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConf.class); UserService service = (UserService) applicationContext.getBean("userService"); service.say(); /** * 结果 * Hello Spring ! 我用annotation方式入门了! */ } }
3 增删改查
SQL脚本
create table account(
id int primary key auto_increment,
name varchar(40),
money double
)character set utf8 collate utf8_general_ci;
insert into account(name,money) values('张三',500.0);
insert into account(name,money) values('李四',1000.0);
insert into account(name,money) values('王五',2000.0);
3.1 xml方式
-
普通maven工程,结构图如下
-
依赖
org.springframework spring-context 5.2.18.RELEASE org.springframework spring-jdbc 5.2.18.RELEASE mysql mysql-connector-java 8.0.21 junit junit 4.12 org.projectlombok lombok 1.18.22 -
实体类
package cn.pojo; import lombok.Data; @Data public class Account { private Integer id; private String name; private Double money; }
-
持久层
package cn.dao; import cn.pojo.Account; import java.util.List; public interface AccountDao { // 返回受影响的行数 Integer addAccount(Account account); Integer deleteAccount(Integer id); Integer updateAccount(Account account); Account findAccountById(Integer id); List
findAll(); } package cn.dao.impl; import cn.dao.AccountDao; import cn.pojo.Account; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import java.util.List; public class AccountDaoImpl implements AccountDao { /** * 定义JdbcTemplate属性并实现其set方法(依赖注入时使用) */ private JdbcTemplate jdbcTemplate; public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } /** * 增删改全用 update 方法 */ public Integer addAccount(Account account) { String sql = "insert into account(name,money) values (?,?) "; Object[] obj = new Object[]{account.getName(), account.getMoney()}; int num = jdbcTemplate.update(sql, obj); return num; } public Integer deleteAccount(Integer id) { String sql = "delete from account where id=? "; Integer num = jdbcTemplate.update(sql, id); return num; } public Integer updateAccount(Account account) { String sql = "update account set name=? , money=? where id=? "; Object[] params = new Object[]{account.getName(), account.getMoney(), account.getId()}; Integer num = jdbcTemplate.update(sql, params); return num; } public Account findAccountById(Integer id) { String sql = "select * from account where id=? "; RowMapper
rowMapper = new BeanPropertyRowMapper (Account.class); return jdbcTemplate.queryForObject(sql, rowMapper, id); } public List findAll() { String sql = "select * from account "; RowMapper rowMapper = new BeanPropertyRowMapper (Account.class); return jdbcTemplate.query(sql, rowMapper); } } -
配置文件
<?xml version="1.0" encoding="UTF-8"?>
-
测试类
package cn.dao; import cn.pojo.Account; import org.junit.Before; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.util.List; public class AccountDaoTest { private AccountDao accountDao; @Before public void init() { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml"); accountDao = (AccountDao) applicationContext.getBean("accountDao"); } @Test public void addAccount() { Account account = new Account(); account.setName("孙悟空"); account.setMoney(666.6); Integer num = accountDao.addAccount(account); if (num > 0) { System.out.println("添加成功"); } else { System.out.println("添加失败"); } } @Test public void deleteAccount() { Integer num = accountDao.deleteAccount(4); if (num > 0) { System.out.println("删除成功"); } else { System.out.println("删除失败"); } } @Test public void updateAccount() { Account account = new Account(); account.setName("李小四"); account.setMoney(500.0); account.setId(2); Integer num = accountDao.updateAccount(account); if (num > 0) { System.out.println("更新成功"); } else { System.out.println("更新失败"); } } @Test public void findAccountById() { Account account = accountDao.findAccountById(1); System.out.println(account); } @Test public void findAll() { List
accounts = accountDao.findAll(); accounts.forEach(account -> System.out.println(account)); } }
3.2 annotation方式
-
普通maven工程,结构图如下
-
依赖
org.springframework spring-context 5.2.18.RELEASE com.alibaba druid 1.2.8 mysql mysql-connector-java 8.0.21 commons-dbutils commons-dbutils 1.4 junit junit 4.12 org.springframework spring-test 5.2.18.RELEASE org.projectlombok lombok 1.18.22 -
实体类
package cn.pojo; import lombok.Data; @Data public class Account { private Integer id; private String name; private Double money; }
-
持久层
package cn.dao; import cn.pojo.Account; import java.util.List; public interface AccountDao { void addAccount(Account account); void deleteAccount(Integer id); void updateAccount(Account account); Account findAccountById(Integer id); List
findAll(); } package cn.dao.impl; import cn.dao.AccountDao; import cn.pojo.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 public class AccountDaoImpl implements AccountDao { @Autowired private QueryRunner runner; /** * 增删改全用QueryRunner的update方法 * xml中的 jdbtTemplate类似,也是增删改全用update */ public void addAccount(Account account) { try { String sql = " insert into account(name,money) values (?,?) "; runner.update(sql, account.getName(), account.getMoney()); } catch (Exception e) { throw new RuntimeException(e); } } public void deleteAccount(Integer id) { try { String sql = " delete from account where id=? "; runner.update(sql, id); } catch (Exception e) { throw new RuntimeException(e); } } public void updateAccount(Account account) { try { String sql = " update account set name=? , money=? where id=? "; runner.update(sql, account.getName(), account.getMoney(), account.getId()); } catch (Exception e) { throw new RuntimeException(e); } } public Account findAccountById(Integer id) { try { String sql = " select * from account where id=? "; // 类似于JdbcTemplate中的RowMapper BeanHandler
beanHandler = new BeanHandler (Account.class); return runner.query(sql, beanHandler, id); } catch (Exception e) { throw new RuntimeException(e); } } public List findAll() { try { String sql = " select * from account "; BeanListHandler beanListHandler = new BeanListHandler (Account.class); return runner.query(sql, beanListHandler); } catch (Exception e) { throw new RuntimeException(e); } } } -
配置
# 数据源配置文件内容 # 路径:resources/dataSource.properties datasource.driver=com.mysql.cj.jdbc.Driver datasource.url=jdbc:mysql://192.168.181.160:3306/test?serverTimezone=CTT datasource.username=root datasource.password=root
package cn.conf; import com.alibaba.druid.pool.DruidDataSource; 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.Scope; import javax.sql.DataSource; public class DataSourceConf { @Value("${datasource.driver}") private String driver; @Value("${datasource.url}") private String url; @Value("${datasource.username}") private String username; @Value("${datasource.password}") private String password; // @Bean:创建一个对象,并且放入spring容器 @Bean(name = "runner") @Scope("prototype") public QueryRunner createQueryRunner(@Qualifier("ds") DataSource dataSource) { return new QueryRunner(dataSource); } @Bean(name = "ds") public DataSource createDataSource() { try { DruidDataSource druidDataSource = new DruidDataSource(); druidDataSource.setDriverClassName(driver); druidDataSource.setUrl(url); druidDataSource.setUsername(username); druidDataSource.setPassword(password); return druidDataSource; } catch (Exception e) { throw new RuntimeException(e); } } }
package cn.conf; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.context.annotation.PropertySource; @Configuration @ComponentScan("cn.dao") @PropertySource("classpath:dataSource.properties") @Import(DataSourceConf.class) public class SpringConf { }
-
测试
package cn.dao; import cn.conf.SpringConf; import cn.pojo.Account; 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; // 这俩注解在spring-test依赖中 // @RunWith(SpringJUnit4ClassRunner.class)替换原有运行器(即Spring整合junit) // @ContextConfiguration(classes = SpringConfig.class)指定spring配置类 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = SpringConf.class) public class AccountDaoTest { @Autowired private AccountDao accountDao; @Test public void addAccount() { Account account = new Account(); account.setName("lkf"); account.setMoney(2000.5); accountDao.addAccount(account); } @Test public void deleteAccount() { accountDao.deleteAccount(6); } @Test public void updateAccount() { Account account = new Account(); account.setName("张小三"); account.setMoney(500.0); account.setId(1); accountDao.updateAccount(account); } @Test public void findAccountById() { Account account = accountDao.findAccountById(1); System.out.println(account); } @Test public void findAll() { List
accounts = accountDao.findAll(); accounts.forEach(account -> System.out.println(account)); } }
- 源码链接:blogs-spring