Spring
MVC设计模式:当拿到任何一个需求的时候,都可以从MVC三个方面进行拆分
M:Model,模型,处理数据
V:View,视图,接收和显示数据
C:Controller,控制器,由谁来接收和显示数据,有谁来处理数据
三层结构:企业级应用的要求
- 表示层
- 业务逻辑层
- 数据访问层
概述
- spring是一个开源框架,是为了解决企业级应用开发的复杂性而设计的
- spring最根本的使命:全方位的简化java开发
- 核心思想:
- IoC:控制反转,就是把依赖对象创建的控制权交给第三方(Spring容器)来管理
- DI:依赖注入,组件之间的依赖关系,在程序运行期间,由第三方动态注入
使用
添加 spring 依赖
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.8.RELEASE</version> </dependency>
添加spring容器的配置类,并添加组件
@Configuration public class AppConfig { @Bean(name = {"empDao1","empDao2"}) public EmpDao empDao() { return new EmpDaoImpl(); } }
测试
public class EmpDaoTest { @Test public void testInsert() { //启动容器 ApplicationContext c = new AnnotationConfigApplicationContext(AppConfig.class); //得到组件 //EmpDao empDao = c.getBean(EmpDao.class); //通过组件名得到组件,默认是方法名 EmpDao empDao = (EmpDao)c.getBean("empDao2"); //调用业务方法 empDao.insert(); //关闭容器 ((AnnotationConfigApplicationContext)c).close(); } }
组件装配
@Getter @Setter public class EmpServiceImpl implements EmpService { private EmpDao empDao ; @Override public int insert() { return empDao.insert(); } }
属性注入:
@Configuration public class AppConfig { @Bean(name = {"empDao1","empDao2"}) public EmpDao empDao() { return new EmpDaoImpl(); } @Bean public EmpService empService() { EmpServiceImpl service = new EmpServiceImpl(); //依赖注入 service.setEmpDao(empDao()); return service; } }
构造注入:
@Getter @Setter public class EmpServiceImpl implements EmpService { public EmpServiceImpl() { } public EmpServiceImpl(EmpDao empDao) { this.empDao = empDao; } private EmpDao empDao ; @Override public int insert() { return empDao.insert(); } }
@Bean public EmpService empService() { EmpServiceImpl service = new EmpServiceImpl(empDao()); return service; }
依赖注入三种方式:
- 属性注入
- 构造注入
- 接口注入(Spring不支持该方式)
Bean说明
@Scope:作用域(单例:singleton(默认的),原生:prototype)
@Bean @Scope("prototype") public EmpService empService() { EmpServiceImpl service = new EmpServiceImpl(empDao()); return service; }
@Lazy:懒加载(延迟加载,在getBean()的时候再加载),默认值@Lazy(false)
注意:在@Scope(“prototype”)的时候,一定是懒加载的
@Bean // @Scope("prototype") @Lazy(true) public EmpService empService() { EmpServiceImpl service = new EmpServiceImpl(empDao()); return service; }
组件扫描
在配置类上添加组件扫描注解
@Configuration @ComponentScan(basePackages = {"com.neu.dao","com.neu.service"}) public class AppConfig {}
在需要成为组件的类上添加@Component注解(组件默认名字为:类名首字母小写)
//组件 @Component public class EmpDaoImpl implements EmpDao {}
自动装配
//默认按照类型装配 @Autowired private EmpDao empDao ;
解决自动装配冲突(使用组件名装配)
@Autowired @Qualifier("empOracleDaoImpl")//注解参数就是组件名,默认为类名首字母小写 private EmpDao empDao ;
修改组件的默认名
@Component(value = "oracleemp") public class EmpOracleDaoImpl implements EmpDao {}
使用Spring的测试模块
导入依赖
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>4.3.8.RELEASE</version> </dependency>
测试
//设置配置文件 @ContextConfiguration(classes = {AppConfig.class}) //相当于测试框架与Spring的一个接口 @RunWith(SpringJUnit4ClassRunner.class) public class EmpTest { @Autowired private EmpService empService; @Test public void testInsert() { empService.insert(); } }
Spring对持久层的支持
在Spring中使用数据库连接池
导入连接池及数据库驱动
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.22</version> </dependency> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.4</version> </dependency>
定义一个属性文件(db.properties),在其中配置数据库连接池需要的参数
jdbc.username=root jdbc.password=root jdbc.url=jdbc:mysql://localhost:3306/neusoft?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai jdbc.driverClassName=com.mysql.cj.jdbc.Driver jdbc.maxActive=20 jdbc.maxWait=2000 jdbc.maxIdle=5
定义一个配置类,读取数据库连接属性文件
package com.neu; import javax.sql.DataSource; import org.apache.commons.dbcp.BasicDataSource; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; @Configuration //配置属性源文件 @PropertySource("classpath:db.properties") public class DBConfig { @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; @Value("${jdbc.url}") private String url; @Value("${jdbc.driverClassName}") private String driverClassName; @Value("${jdbc.maxActive}") private int maxActive; @Value("${jdbc.maxWait}") private int maxWait; @Value("${jdbc.maxIdle}") private int maxIdle; @Bean public DataSource dataSource() { BasicDataSource ds = new BasicDataSource(); ds.setUsername(username); ds.setPassword(password); ds.setUrl(url); ds.setDriverClassName(driverClassName); ds.setMaxActive(maxActive); ds.setMaxIdle(maxIdle); ds.setMaxWait(maxWait); return ds; } }
测试
@ContextConfiguration(classes = {AppConfig.class,DBConfig.class}) //相当于测试框架与Spring的一个接口 @RunWith(SpringJUnit4ClassRunner.class) public class EmpTest { @Autowired private EmpService empService; @Autowired private DataSource dataSource; @Test public void testDataSource() throws SQLException { Connection connection = dataSource.getConnection(); System.out.println("连接成功!"); connection.close(); } @Test public void testInsert() { empService.insert(); } }
Spring与Mybatis集成
导入依赖
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>4.3.8.RELEASE</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.1</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.6</version> </dependency>
配置SqlSessionFactory
@Configuration @ComponentScan(basePackages = {"com.neu.service","com.neu.mapper"}) public class MybatisConfig { @Autowired private DataSource dataSource; @Bean public SqlSessionFactory sqlSessionFactory() throws Exception { SqlSessionFactoryBean factory = new SqlSessionFactoryBean(); factory.setDataSource(dataSource); return factory.getObject(); } }
配置 mapper 扫描
@Configuration public class MybatisMapperScannerConfig { @Bean public MapperScannerConfigurer mapperScannerConfigurer() { MapperScannerConfigurer c = new MapperScannerConfigurer(); c.setSqlSessionFactoryBeanName("sqlSessionFactory"); c.setBasePackage("com.neu.mapper"); return c; } }
作业
- spring+mybatis实现如下功能(使用单元测试,业务逻辑层+数据访问层):
- 查询所有员工信息
- 添加员工
- 删除员工
- 分页查询员工(每页显示3条记录,打印第2页数据)
Spring+Mybatis+Servlet
修改打包方式:war
导入相关web依赖
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>4.3.8.RELEASE</version> </dependency>
AOP
定义:面向切面编程,模块化横切关注点(把相同的代码加到关注的方法上)
导入包
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.7.3</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.7.3</version> </dependency>
定义一个类,实现切面的功能(类定义在com.neu.utils包下,要把该包添加到组件的扫描路径中)
@Configuration @EnableAspectJAutoProxy//开启切面自动代理 @Component @Aspect//切面 public class AOPUtil { //切点(切入点):加入相同代码的一组关注点(连接点) @Pointcut("execution (* com.neu.mapper.*.*(..))") public void pointcut() { } //通知 @Around("pointcut()") public Object around(ProceedingJoinPoint p) throws Throwable { long startTime = System.nanoTime(); //调用代理的方法 Object object = p.proceed(); long m = System.nanoTime() - startTime; System.out.println(m); return object; } }
- 连接点(joinPoint):程序执行过程中的特定点
- 通知(Advice):在特定连接点加入的代码
- 切入点(pointcut):加入相同通知的一组连接点
- 切面(aspect):通知与切入点的组合
前置通知
@Before("pointcut()") public void before() { SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String format = f.format(new Date()); System.out.println("开始执行方法:"+format); }
返回后通知:执行了return语句后执行的代码
@AfterReturning("pointcut()") public void afterReturning() { SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String format = f.format(new Date()); System.out.println("方法正常结束:"+format); }
异常通知:
@AfterThrowing("pointcut()") public void afterThrowing() { SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String format = f.format(new Date()); System.out.println("抛出异常:"+format); }
最终通知
@After("pointcut()") public void after() { SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String format = f.format(new Date()); System.out.println("方法最终结束时间:"+format); }
环绕通知
@Around("pointcut()") public Object around(ProceedingJoinPoint p) throws Throwable { long startTime = System.nanoTime(); //调用代理的方法 Object object = p.proceed(); long m = System.nanoTime() - startTime; System.out.println(m); return object; }
Spring对事务的支持
添加事务管理器
@Bean public PlatformTransactionManager transactionManager() { return new DataSourceTransactionManager(dataSource()); }
启用事务管理器
@Configuration //配置属性源文件 @PropertySource("classpath:db.properties") @EnableTransactionManagement//启用事务管理器 public class DBConfig {}
在业务逻辑类上或方法上添加@Transactional
当添加了事务注解的方法中,抛出异常,则回滚事务,否则,提交事务
@Transactional public int insert(Dept dept) { deptMapper.insert(dept); return deptMapper.insert(dept); }
使用静态资源
在 webapp 目录下,新建一个文件夹:staitc,在其中放入静态资源(css、js)
例如:/webapp/static/css/style1.css
配置资源注册
@Configuration @EnableWebMvc//启用mvc注解驱动 @ComponentScan(basePackages = "com.neu.controller") public class SpringMVCConfig implements WebMvcConfigurer { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/static/**").addResourceLocations("/static/");//访问的静态资源 } }
在 jsp 中引入css
<link rel="stylesheet" href="${ pageContext.request.contextPath }/static/css/style1.css">