Day1 Spring IOC入门
1.1IOC思想推导
-
IOC Inversion of Control(控制反转)由传统的主动实例化对象(new 对象),变为从容器(map)集合中获取
-
对象创建的两种方式:
-
通过手动反射创建对象
-
map集合(容器)中获取
-
创建xml配置文件
<beans> <bean id="" class=""></bean> </beans>
-
单例工厂
-
获取配置文件的输入流
-
创建SAXReader对象
-
获取Document对象
-
获取跟节点
-
获取所有的bean节点
-
解析bean节点,获取id和class属性
-
用反射创建对象
-
将id和对应的对象存入map集合
-
根据id获取map中的对象并返回
-
-
1.2Spring概述和IOC
Spring介绍
- spring是于2003 年兴起的一个full-stack轻量级的Java 开源框架
- Spring以IOC Inversion of Control(控制反转)和AOP(面向切面编程)为核心
- Spring提供了展现层Spring MVC、持久层Spring JDBC、业务层事务管理等众多的企业级应用技术
- Spring还能整合开源世界众多的第三方框架和类库,逐渐成为使用最多的Java EE企业应用开源框架
IOC(控制反转)
- 一种设计思想,目的是指导我们设计出更加松耦合的程序。
- 指将对象的控制权由原来的 程序员在类中主动控制 反转到 由Spring容器来控制。
- 对象的创建交由Spring容器管理,需要对象从容器中获取即可
- 主要功能是解耦,底层原理是反射
1.3SpringIOC的入门
-
创建工程导入依赖
<dependencies> <!--spring的坐标--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.1.6.RELEASE</version> </dependency> </dependencies>
-
创建Dao接口和实现类
-
创建Spring配置文件
- spring配置文件约定俗称:applicationContext.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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="唯一标识" class="全限定类名"></bean> </beans>
-
spring的API介绍
- Spring的API体系异常庞大,我们现在只关注两个:
- BeanFactory
- BeanFactory是 Spring 的"心脏",是 IOC 容器的核心接口,它定义了IOC的基本功能。
- 用来配置文档,管理bean的加载,实例化并维护bean之间的依赖关系,负责bean的声明周期
- ApplicationContext
- 由BeanFactory派生而来,可以比喻为Spring的躯体,添加了很多功能。
- 支持了aop功能和web应用
- MessageSource, 提供国际化的消息访问
- 通过配置来实现BeanFactory中很多编码才能实现的功能
- 常用实现类
- ClassPathXmlApplicationContext: 从classpath目录读取配置文件
- FileSystemXmlApplicationContext: 从文件系统或者url中读取配置文件
- AnnotationConfigApplicationContext:当我们使用注解配置容器对象时,需要使用此类来创建 spring容器。它用来读取注解。
- 由BeanFactory派生而来,可以比喻为Spring的躯体,添加了很多功能。
- 区别:
- beanFactory主要是面向Spring框架的基础设施,供spring自身内部调用
- Applicationcontext 主要面向Spring的使用者。
- BeanFactroy在第一次使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化,而ApplicationContext是在容器启动时,一次性创建并加载了所有的Bean
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ozEziRuR-1605668946277)(assets\11.png)]
1.4对象的作用域和生命周期
<bean id="唯一标识" class="全类名" scope="..." init-method="方法名1" destroy-method="方法名2"></bean>
<!--
scope :作用
singleton :单例对象
容器创建,自动的反射创建UserDaoImpl对象存入容器
自动的执行init-method中配置的对象方法
容器关闭时,对象销毁之前自动的执行destroy-method配置的对象方法
prototype:多例对象
当调用一次getBean方法,创建一次对象
当对象创建,调用init-method中配置的对象方法
多例对象(没有存在容器中),自动的进行垃圾回收
init-method :
对象实例化之后,自动执行的对象方法
destroy-method:
容器关闭,对象被销毁之前,自动执行的对象方法
-->
1.5依赖注入
- 依赖注入:Dependency Injection (DI)。是 spring 框架核心 ioc 的具体实现
- 本质是用于对象中的私有属性赋值
- 构造方法注入
- set方法注入
构造方法注入
-
向对象添加有参构造方法
public class UserDaoImpl implements UserDao { private String username; private Integer age; public UserDaoImpl(String username,Integer age){ this.username = username; this.age = age; } }
-
在spring的配置文件中,通过bean标签配置对象创建
<bean id="userDao" class="cn.....UserDaoImpl"> <constructor-arg name="username" value="参数1"></constructor-arg> <constructor-arg name="age" value="参数2"></constructor-arg> <!-- index 指定参数的索引 从0开始; type 通过参数类型定位 name 通过参数名称定位 以上三个用于定位构造参数,三选一 ----------------------------------- value 对基本数据类型的数据赋值(8个基本+String) ref 对Java实体类对象赋值 以上两个用于对参数赋值 --> </bean>
set方法注入
-
提供属性的set方法
public class UserDaoImpl implements UserDao { private String username; private Integer age; private List<String> list; private Set<String> set; private String[] array; private Map<String,String> map; private Properties properties; 此处应有7个Set方法 }
-
在spring配置文件中,通过bean结合property配置set方法调用
<bean id="userDao" class="cn.....UserDaoImpl"> <propertey name="username" value="参数1"></propertey> <propertey name="age" value="参数2"></propertey> <!-- property: name 定位执行的set方法 value 对基本数据类型赋值 ref 对Java实体类对象赋值 --> <property name="list"> <list> <value>参数1</value> <value>参数2</value> </list> </property> <property name="set"> <set> <value>参数1</value> <value>参数2</value> </set> </property> <property name="array"> <array> <value>参数1</value> <value>参数2</value> </array> </property> --------------------------------------------------------------- <property name="map"> <map> <entry key="k1" value="v1"></entry> <entry key="k2" value="v2"></entry> </map> </property> <property name="properties"> <props> <entry key="k1" value="v1"></entry> <entry key="k2" value="v2"></entry> </props> </property> </bean>
注入对象
- 推荐set方法注入
配置文件的模块化
-
并列的多个配置文件
- 直接编写多个配置文件,beans1.xml…
- 创建ApplicationContext的时候,直接传入多个配置文件。
ApplicationContext act = new ClassPathXmlApplicationContext("beans1.xml","beans2.xml","...");
-
主从配置文件
- 先配置一个主配置文件
- 然后在里面导入其它的配置文件。
<import resource="beans1.xml" /> <import resource="beans2.xml" />
-
注意事项:
- 同一个xml文件中不能出现相同名称的bean,如果出现会报错
- 多个xml文件如果出现相同名称的bean,不会报错,但是后加载的会覆盖前加载的bean,所以企业开发中尽量保证bean的名称是唯一的。
Day02DbUtils&xml、注解、单元测试
2.1DbUtils
DbUtils是Apache的一款用于简化Dao代码的工具类,它底层封装了JDBC技术。
核心类:
- QueryRunner 用于执行增删改查的SQL语句
- ResultSetHandler 这是一个接口,主要作用是将数据库返回的记录封装进实体对象,查询数据封装,结果集处理器
核心方法:
- update() 用来执行增、删、改语句 executeUpate
- query() 用来执行查询语句 executeQuery
DbUtils基本使用:
-
创建工程导入依赖
- mysql,druid,commons-dbutils,junit
-
创建实体类
public class Accout { private Integer id; private String name;//账户名称 private Float money;//账户金额 set... toString... }
-
CRUD
@Test public void testInsert() throws Exception { //1、创建DataSource DruidDataSource dataSource = new DruidDataSource(); dataSource.setUsername("root"); dataSource.setPassword("root"); dataSource.setDriverClassName("com.mysql.jdbc.Driver"); dataSource.setUrl("jdbc:mysql:///heima31"); //2、创建QueryRunner对象 (通过构造参数,传入datasource) QueryRunner queryRunner = new QueryRunner(dataSource); //3、保存账户数据 queryRunner.update("insert into account(name,money) values (?,?)", "小张",2); //4.查询单个账户 Account account = queryRunner.query("select * from account where name=?", new BeanHandler<Account>(Account.class), "小张"); } //5.查询多个个账户 List<Account> list = queryRunner.query("select * from account", new BeanListHandler<Account>(Account.class));
2.2基于XML配置数据库操作
-
创建工程导入坐标
- mysql,druid,commons-dbutils,junit,spring-context,spring-test
-
创建实体类
public class Account { private Integer id; private String name; private Float money; get... set... }
-
创建dao接口
public interface AccountDao { //1、保存账户 public void saveAccount(Account account); }
-
创建dao接口实现类
public class AccountDaoImpl implements AccountDao { //依赖属性 private QueryRunner queryRunner; public void setQueryRunner(QueryRunner queryRunner) { this.queryRunner = queryRunner; } //保存 public void saveAccount(Account account) { queryRunner.update("insert into account(name,money) values(?,?)", account.getName(),account.getMoney()); } }
-
创建service接口
public interface AccountService {
//1、保存账户
public void saveAccount(Account account);
}
-
创建service接口实现类
public class AccountServiceImpl implements AccountService { //依赖属性(依赖注入) private AccountDao accountDao; //用于property的set注入 public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } //保存 public void saveAccount(Account account) { accountDao.saveAccount(account); } }
-
Spring配置
- applicationContext.xml
<!-- 创建AccountService对象,交给Spring管理--> <bean id="accountService" class="cn...AccountServiceImpl"> <!--ref:被spring容器管理的对象 id--> <property name="accountDao" ref="accountDao"></property> </bean> <bean id="accountDao" class="cn...accountDao"> <property name="queryRunner" ref="queryRunner"></property> </bean> <!----> <bean id="queryRunner" class="cn...QueryRunnerImpl"> <!--构造方法注入--> <constructor-arg name="ds" ref="dataSource"></constructor-arg> </bean> <bean id="dataSource" class="cn...DataSourceImpl"> <property name="username" value="root"></property> .... </bean>
-
测试
public static void main(String[] args) { //1、创建spring容器 ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); // 2、从容器中获取对象 AccountService accountService = (AccountService)ac.getBean("accountService"); accountService.saveAccount(new Acount(...)); }
2.3Spring中的常见注解
-
xml中加入包扫描&托管properties文件
<!--包扫描:扫描指定包及子包下的所有java类,扫描类中的Spring注解,帮助我们自动的创建对象存入容器--> <context:component-scan base-package="cn.itcast"></context:component-scan> <!--将properties文件,交给spring管理--> <context:property-placeholder location="jdbc.properties"></context:property-placeholder>
-
对象创建的注解
创建对象交给spring容器管理,语义话的形式代码分层
<bean id="userDao" class="cn...UserDaoImpl"></bean>
@Component (组件):
@Controller :在web层使用
@Service :在service层
@Repository :在dao层使用
* 当spring容器启动时,根据包扫描配置自动的扫描到@Component注解,反射创建注解标注的对象,存入容器
* 默认存入容器的id(唯一标识) = 当前类名首字母小写(userDaoImpl)
* value属性 :自定义容器中对象的唯一标识
-
生命周期的注解
对象的生命周期的注解 @Scope : 配置到类上,生命对象的生命周期 singleton:单例(默认) prototype:多例 @PostConstruct: 相当于xml中的init-method 对象初始化方法:配置到对象的方法上 @PreDestory:相当于xml中的destory-method 对象的销毁方法:配置到对象的方法上
-
@Autowired
@Autowired 1、配置到依赖关系的属性上(通过Autowired依赖注入,不需要配置set方法) 2、默认按照对象类型(接口类型)从容器中查找对象并注入赋值 3、如果按照类型查询出多个对象,按照属性名作为id从容器中查找对象并注入赋值 对于 @Autowired注解,大部分情况只需要此注解配置到属性上,即可完成依赖注入 但是对于容器中存在多个同类型对象时 1、修改属性名称(不常用) 2、@Autowired结合@Qualifier共同使用,配置到属性上 * 在@Qualifier中可以指定容器中对象的id
-
@Reource
@Resource: * 是jdk提供的依赖注入的注解,此注解在jdk9及以上版本已经移除 * 配置到依赖对象的属性上,可以通过name属性,根据id从容器中查找对象,并注入
-
@value
@Value:配置到属性上 1、注入基本数据类型的常量 2、被Spring容器管理的properties文件中的内容 i、配置文件交给Spring容器管理 ii、通过@Value,从容器中得到配置项,并注入 : 语法规则:@Value(value="${properties文件中的key}")
-
注解总结
- 使用注解编程之前,必须执行包扫描!!!
xml配置 | 注解配置 | 说明 |
---|---|---|
< bean id="" class="" > | @Component @Controller @Service @Repository | bean的实例化,向Spring容器中放入对象 |
< property name="" ref=""> | @Autowired @Qualifier @Resource | bean的对象属性注入,从Spring容器中获取对象 |
< property name="" value=""> | @Value | bean的简单属性注入 |
< bean scope=""> | @Scope | 控制bean的作用范围 |
< bean init-method=“init” destroy method=“destory” /> | @PostConstruct @PreDestroy | bean创建之后和销毁之前分别调用的方法 |
2.4注解结合XML
注解结合XML:
- 自定义的java对象通过注解配置(service,dao)
- service,repository,autowired
- 第三方对象通过XML配置(QueryRunner,DataSource)
2.5纯注解
-
新建配置类
# 通过SpringConfig替换之前的xml配置项 1、声明配置类,在类上配置一个注解 @Configuration 2、开启包扫描 @ComponentScan(basePackages = "cn.itcast") basePackages: 指定需要扫描的包 3、将第三方jar包对象,创建并交给容器管理 @Bean # 步骤 1、@Bean注解需要配置到方法上 2、方法需要返回值 3、在Spring容器启动的时候,自动的扫描所有配置了@Bean的方法 4、自动执行被@Bean扫描的方法,将返回值存入Spring容器 5、如果方法需要参数,Spring会从容器中根据类型获取对象,再调用在@Bean标注的方法中,可以配置依赖的属性参数 6.spring会从容器中获取到依赖的对象,自动调用方法 # 加载外部配置文件 1、声明配置类,在类上配置一个注解 @Configuration 2、开启包扫描 @ComponentScan(basePackages = "cn.itcast") basePackages: 指定需要扫描的包 3、将第三方jar包对象,创建并交给容器管理 @Bean 4、将properties配置文件,交给spring容器管理 @PropertySource("jdbc.properties") value : properties路径 5、从从容器中获取值 @Value("${jdbc.username}") # 模块化 1、在主配置类中,通过Import引入其他的配置类 @Import(value=JdbcConfig.class)
-
测试
public static void main(String[] args){ //创建spring容器,根据注解配置类创建容器 ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class); ... }
2.6Spring整合单元测试
-
Junit在单元测试底层工作的是一个运行器,默认是ParentRunner
-
Spring提供了一个可以获取对象的运行器
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.1.6.RELEASE</version> </dependency>
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations ="classpath:applicationContext.xml") public class AccountJunitTest { //@Autowired注入待测试的对象,通过@Test发起测试 @Autowired private AccountService accountService; //测试保存 @Test public void testInsert() { //调用方法保存 Account account = new Account(); account.setMoney(100f); account.setName("小李1"); accountService.saveAccount(account); } }
Day03SpringAOP壹
3.1转账事务问题
- 原因
- 每执行完一条sql语句后, jdbc会自动提交事务
- 解决
- 关闭事务的自动提交, 选择手动提交事务
- 保证执行多条sql语句的是同一个connection
- 方法
- Service创建connection向后传递
- Threadlocal方法
3.2Threadlocal
-
原理
- 将数据绑定到当前线程上,同一个线程中,从Threadlocal获取的数据是同一个对象
-
使用
//T是要存储的数据类型 ThreadLocal<T> sThreadLocal = new ThreadLocal<T>(); sThreadLocal.set() //将数据绑定到当前线程 sThreadLocal.get() //从当前线程中获取数据
3.3事务管理器
- 普通方式
- 步骤
- 编写事务管理器,提供获取connection及其他事务方法
- 各代码层,引入事务管理器,从Threadlocal获取connection及事务方法
- 问题
- 事务代码和业务代码严重耦合在一起
- 解决
- 动态代理,在不改变源代码的前提下,对功能进行增强
- java代码中只需要重点关注业务逻辑即可
- 增强部分内容,通过动态代理添加
- 步骤
- 动态代理方式
- jdk动态代理
- cglib动态代理
- 两中代理方式的选择
- 在创建代理实现类时, jdk的速度要高于cglib
- 当被代理类有接口的时候,使用jdk动态代理, 因为它的效率高
- 当被代理类没有接口的时候,使用cglib动态代理, 因为没办法
3.4cglib动态代理
-
原理
- 基于子类的动态代理
-
使用cglib的方式创建代理对象
//编写代理逻辑
InvocationHandler invocationHandler = new InvocationHandler() {public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//增强方法
};
// 使用cglib的方式创建代理对象
// 1 创建增强器
Enhancer enhancer = new Enhancer();
// 2 设置父类
enhancer.setSuperclass(AccountServiceImpl.class);
// 3 设置代理逻辑
enhancer.setCallback(invocationHandler);
// 4 产生代理对象
AccountServiceImpl instance = (AccountServiceImpl) enhancer.create();
//5 使用代理对象运行方法
instance.save(参数);
3.5AOP
- 概念
- AOP( 面向切面编程 )是一种思想, 它的目的就是在不修改源代码的基础上,对原有功能进行增强.
- Spring AOP是对AOP思想的一种实现,Spring底层同时支持jdk和cglib动态代理.
- Spring会根据被代理的类是否有接口自动选择代理方式:
- 如果有接口,就采用jdk动态代理(当然,也可以强制使用cglib)
- 没有接口就采用cglib的方式
- 优点
- 逻辑清晰,开发核心业务的时候,不必关注增强业务的代码码复用性高:增强代码不用重复书写
- 总结
- 当核心业务和增强业务同时出现时,我们可以在开发时对他们分别开发,运行时再组装在一起(使用动态代理的方式)
- 工作原理
- 开发阶段分别开发 运行阶段组装运行
- 开发阶段
- 开发共性功能,制作成增强
- 开发非共性功能,制作成切点
- 在配置文件中,声明切点与增强间的关系,即切面
- 容器启动阶段
- Spring读取配置文件中的切面信息,根据切面中的描述,
- 将增强功能增加在 目标对象 的 切点方法 上,动态创建代理对象
- 最后将经过代理之后对象放入容器中 (存入容器的是动态代理对象
3.6术语
- 目标对象
- target :被代理对象
- 连接点
- jointPoint:被代理对象中的所有方法
- 切入点
- pointCut: 被增强的方法
- 增强(通知)
- advice:一个具体的增强功能
- 前置通知,后置通知,异常通知,最终通知,环绕通知
- 代理对象
- proxy :生成的动态代理对象
- 切面
- aspect:切面是一种描述,描述了一个什么样的功能添加到了哪个切入点的什么位置上
- 切面 = 切点 + 增强
3.7SpringAOP的入门案例
-
创建工程,引入坐标
- spring-context,aspectjweaver,junit
-
创建AccountDao的接口和实现类
-
开发增强功能
- 在SpringAOP中,需要增强的功能需要配置到类中方法上
-
基于XML配置切面
- 切面类需要交给Spring容器管理
- 通过
<aop:config>
开启AOP配置- 配置切入点(被增强的类和方法)
- 配置切面
<!--创建AccoutDao--> ... <!--配置AOP--> <!--切面类交给容器管理--> <bean id="logger" class="cn...Logger"></bean> <!--通过aop:config开启配置aop--> <aop:config> <!-- 配切入点: id:唯一标志 expression(方法类型 返回值 全类名.方法(参数):切入点表达式 方法类型:可以省略 * :表示任意字符串 .. : 表示任意个 --> <aop:pointcut id="pt" expression="execution(public void cn...AccountDaoImpl.save())"/> <!-- 配置切面 ref:配置切面类(具有增强功能类) --> <aop:aspect ref="logger"> <!-- 四大通知之一: method:切面类中的方法 pointcut-ref:切入点 --> <aop:before method="before" pointcut-ref="pt"></aop:before> </aop:aspect> </aop:config>
-
测试
3.8SpringAOP配置详解
-
四大通知
- 分类
- 前置通知(before) : 在切点运行之前执行
- 后置通知(after-returning): 在切点正常运行结束之后执行
- 异常通知(after-throwing): 在切点发生异常的时候执行
- 最终通知(after): 在切点的最终执行
- 缺点
- 四大通知的配置顺序不同,执行效果会不同
- 分类
-
环绕通知
-
一种特殊的通知,他允许你以编码的形式实现四大通知
-
和手动定义动态代理类似
-
方法
/** 环绕通知 和自定义动态代理类似 1.具有返回:Object 2.参数:ProceedingJoinPoint:被代理对象执行的方法 目的 程序员自己编写去实现代码增强 1.增强代码块 2.被代理对象的方法 */ public Object around(ProceedingJoinPoint pjp) throw Throwable{ Object obj = null; try{ sout("前置通知"); obj = pjp.proceed(); sout("后置通知") }catch(Exception e){ sout("异常通知") } return obj; }
-
配置
<aop:pointcut id="pt" expression="execution(* cn.itcast.dao.impl.*.*(..))"/> <aop:aspect ref=logger> <aop:around method="around" pointcut-ref="pt"></aop:around> </aop:aspect>
-
Day04SpringAOP贰
4.1基于XML结合注解的配置
-
开启注解支持
- IOC的包扫描
- AOP的自动代理
- 自定义的对象,通过IOC注解进行对象创建和依赖注入
- 第三方的对象,通过XML配置对象创建和依赖注入
<!--包扫描--> <context:component-scan base-package="cn.itcast"></context:component-scan> <!--开启AOP注解的支持,开启自动代理--> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
-
修改dao,通过注解创建对象,交给容器管理
-
修改Logger切面类
- 交给Spring容器管理
- 在类上声明切面类 : @Aspect
- 在类中的通知方法上:通过@Before,@After,@AfterReturning,@AfterThrowing,@Around配置通知类型
@Component @Aspect public class Logger { //抽取公共参数 @pointcut(value="execution(* cn.itcast.dao.impl.*.*(..))") public void pt(){} //前置通知 @Before(value="execution(* cn.itcast.dao.impl.*.*(..))") public void before() { System.out.println("执行前置通知:before方法"); } //环绕通知 @Around (value="pt()") public Object around(ProceedingJoinPoint pjp) throws Throwable { Object obj = null; try { System.out.println("执行前置通知"); obj = pjp.proceed(); //执行被代理对象的方法 System.out.println("执行后置通知"); }catch (Exception e) { System.out.println("执行异常通知"); }finally { System.out.println("执行最终通知"); } return obj; } }
4.2基于纯注解的配置
-
编写配置类
- 删除
applicationContext.xml
配置文件 - 编写配置类:SpringConfig.java
- 在配置类中替换xml中的配置内容
- 声明配置类
- 开其IOC包扫描
- 开启AOP的自动代理
@Configuration//声明配置类 @ComponentScan(basePackages = "cn.itcast")//IOC支持 @EnableAspectJAutoProxy//AOP支持 public class SpringConfig{ }
- 对象创建,AOP的切面配置
- 删除
4.3基于XML的AOP事务配置
-
修改AccoutServiceImpl
- 只保留业务逻辑即可,将通知的内容。编写到对应的切面类中
-
修改AccoutDaoImpl
- 准备set注入
-
配置切面类
-
配置AOP
- 基于xml的配置方式
- IOC配置 : 对象的创建和依赖注入
- AOP配置
- 切面类交给容器管理
- 通过
<aop:config>
开启配置
<!--对象创建IOC-->
<bean id="accountService" class="cn.itcast.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"></property>
</bean>
<bean id="accountDao" class="cn.itcast.dao.impl.AccountDaoImpl">
<property name="queryRunner" ref="queryRunner"></property>
<property name="txManager" ref="txManager"></property>
</bean>
<bean id="txManager" class="cn.itcast.utils.TxManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner">
<constructor-arg name="ds" ref="dataSource"></constructor-arg>
</bean>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="username" value="root"></property>
<property name="password" value="root"></property>
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql:///heima31"></property>
</bean>
<!--AOP配置-->
<aop:config>
<!--切入点表达式 : 查找需要增强的方法-->
<aop:pointcut id="pt" expression="execution(* cn.itcast.service.impl.*.*(..))"/>
<!--配置切面-->
<aop:aspect ref="txManager">
<!--前置通知-->
<aop:before method="begin" pointcut-ref="pt"></aop:before>
</aop:aspect>
</aop:config>
</beans>
4.4基于XML结合注解的AOP事务配置
- 开启对注解的支持(ioc包扫描,aop的自动代理)
- 通过IOC注解创建对象和依赖注入
- 注解:替换自动的对象创建
- XML:第三方jar包对象
- 通过AOP注解完成切面配置
- 声明切面类
- 通过AOP注解配置通知类型
4.5JdbcTemplate
- 介绍
- JdbcTemplate是Spring提供的持久层技术,用于操作数据库,它底层封装了JDBC技术。使用方式和DbUtils基本类似.
- 核心类:
- JdbcTemplate 用于执行增删改查的SQL语句 (QueryRunner)
- 创建过程和QueryRunner一模一样,构造方法传入DataSource
- 调用JdbcTemplate 中的方法完成数据库操作
- RowMapper 这是一个接口,主要作用是将数据库返回的记录封装进实体对象(BeanHandler)
- JdbcTemplate 用于执行增删改查的SQL语句 (QueryRunner)
- 核心方法:
- update() 用来执行增、删、改语句,和QueryRunner相同
- query() 用来执行查询语句,查询数据列表
- queryForObject(),查询单一对象
//创建一个JdbcTemplate对象,用来执行增删改查, 需要给一个数据源
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
//update方法,用于执行增删改语句
jdbcTemplate.update("insert into account value(null,?,?)",1,2);
//query或者queryForObject方法,用于执行查询语句
//query 用于查询多条记录,返回一个集合 queryForObject用于查询一条记录,返回一个实体
jdbcTemplate.query("select * from account", new BeanPropertyRowMapper<Account>(Account.class)); jdbcTemplate.queryForObject("select * from account where aid = ?", new BeanPropertyRowMapper<Account>(Account.class), 1);
4.6Spring中的事务管理
- 根据SpringAOP拓展出来的事务控制功能
- 事务管理方式
- 编程式事务
- 将业务代码和事务代码放在一起书写
- 耦合性太高,开发中不使用
- 声明式事务
- 通过一段配置让程序组装运行,最后达到事务控制的目的.
- 通过AOP原理实现
- 编程式事务
- PlatformTransactionManager这是Spring进行事务管理的一个根接口,我们要使用它的实现类做事务管理器(增强的事务处理的功能)
- DataSourceTransactionManager :对mybatis和jdbcTemplate操作做事务控制
- JpaTransactionManager:对JPA操作数据库进行数据库
- TransactionDefinition
- 用来做事务定义
- 面向配置(事务隔离级别,传播行为,是否只读事务,超时时间)
- 隔离级别
- mysql支持四种,默认可重复度
- Oracle支持两种(读已提交和串行化),默认读已提交
- 传播行为
- 在多方法嵌套调用时,被调用方法对事务的支持情况
- Required 加入事务或创建事务
- supports 加入事务或以非事务形态运行
- 是否只读事务
- Read Only : true | false
- 只读事务只能用于查询方法
- 超时时长
- 事务超时时间, 此属性需要底层数据库的支持
- 使用默认值-1,代表不限制
4.7声明式事务xml版
- 基于XML的方式完成声明式事务配置:
- 配置事务管理器交给Spring容器管理(切面类)
- 配置事务通知
- 配置事务的AOP
<!--配置Spring的声明式事务-->
<!--1、事务管理器交给容器管理 transactionManager-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入DataSource对象-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--2、配置事务通知 : 配置方法对事务的配置-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!--不同方法,对事务的要求配置
name : 方法名(可以接受 * 作为通配符)
propagation:传播行为
read-only: 是否只读事务
timeout:超时时间
isolation:事务隔离级别
-->
<tx:method name="*" propagation="REQUIRED" read-only="false" ></tx:method>
<tx:method name="find*" propagation="SUPPORTS" read-only="true"></tx:method>
</tx:attributes>
</tx:advice>
<!--3、配置事务的AOP : 定位到所有需要添加事务的方法-->
<aop:config>
<!--切入点-->
<aop:pointcut id="pt" expression="execution(* cn.itcast.service.impl.*.*(..))"/>
<!--事务配置:事务通知-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pt"></aop:advisor>
</aop:config>
</beans>
4.8声明式事务注解结合XML版
注解:
- IOC注解:自定义对象通过注解创建对象和依赖注入
- 声明式事务注解:替换xml中的事务通知和事务AOP配置
- 需要开启事务注解的支持 : 事务注解驱动
- 在需要事务的类或者方法上,使用@Transactional注解配置事务
步骤:
-
删除xml中的tx:advice和aop:config
-
添加一个事务注解驱动
<!--开启事务注解支持: 事务注解驱动--> <tx:annotation-driven></tx:annotation-driven>
-
在方法生添加声明式事务的注解
/** * 通过注解配置事务 * @Transactional: * 1、可以配置到类上,表明此类中的所有方法都需要此事务配置 * 2、也可以配置到方法上,表明此方法需要类似配置 * 3、即配置到类上也配置到了方法上:就近原则(使用方法的配置为依据) */ @Service @Transactional(propagation = Propagation.REQUIRED,readOnly = false) public class AccountServiceImpl implements AccountService { //查询全部 @Transactional(propagation = Propagation.SUPPORTS,readOnly = true) public List<Account> findAll() { return accountDao.findAll(); } @Autowired private AccountDao accountDao; //保存 public void save(Account account) { accountDao.save(account); } }
4.9声明式事务纯注解版
- 通过配置类,替换原有的XML配置文件
- 包扫描
- 事务注解驱动
- @EnableTransactionManagement
- 第三方的相关对象,创建并交给容器管理
- @Bean
Day05SpringMVC 壹
5.1介绍
-
mvc 是一种用于设计创建web应用表现层的模式。使用它可以将业务逻辑,数据,页面显示代码分离出来
- Model(模式):数据模型(封装对象)
- View(试图):用于展示数据(html,jsp)
- Controller(控制器):用于程序业务逻辑处理
-
SpringMVC是Spring产品对MVC模式的一种具体实现, 它可以通过一套注解,让一个简单的Java类成为控制器,而无须实现任何接口。
- 在SpringMVC中,前端控制器通过Servlet实现
- 在Struts2框架中,前端控制器通过Filter实现
5.2SpringMVC原理
- 用户通过浏览器发送请求至DispatcherServlet
- DispatcherServlet收到请求调用HandlerMapping
- HandlerMapping找到具体的处理器链返回给DispatcherServlet
- DispatcherServlet会根据返回的处理器链调用HandlerAdapter
- HandlerAdapter经过适配调用具体的Handler(controller)
- Controller执行完成返回一个执行结果
- HandlerAdapter将Handler的结果ModelAndView对象返回给DispatcherServlet
- DispatcherServlet将ModelAndView对象传给ViewReslover
- ViewReslover解析后得到具体View,并返回给DispatcherServlet
- DispatcherServlet根据View进行视图渲染(即将模型数据填充至视图中)
- DispatcherServlet会将渲染后的视图响应给浏览器
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dz4DpZj2-1605668946279)(assets\12.png)]
5.3SpringMVC的三大组件
- 前端控制器
- SpringMVC的核心组件(DispathcherServlet),协调所有组件的运行
- 处理器映射器
- 根据URL请求去寻找对应的处理方法( Controller中的方法)
- 处理器适配器
- 真正的去调用处理方法(执行Controller中的方法)
- 视图解析器
- 将逻辑视图翻译成物理视图
- 物理视图:jsp页面的完整路径
5.4RequestMapping
- RequestMapping用于建立请求URL和处理方法之间的对应关系, 也可以通过它的属性对请求做出各种限制.
- 可以标注在方法上,也可以标注在类上,标注在类上代表类中的所有方法都可以共用一段URL
- value(path): 用于限制请求URL(和path作用一样)
- method:用于限制请求类型(post,get,delete,put)
- params:用于限制请求参数的条件(如果没有指定参数,抛出异常)
5.5接收请求参数
-
简单类型
- 8 基本类型 + 8 基本类型的包装类型 + 字符串
- 只需要保证前端传递的参数名称跟方法的形参名称一致就好
-
对象类型
- 保证前端传递的参数名称跟pojo的属性名称(set方法)一致
-
数组类型
- 用于接受多个同名参数传递
- 需要保证前端传递的参数名称跟方法中的数组形参名称一致
-
集合类型
- 将前端传入的数据自动的封装成集合,需要将集合包装到一个对象中
- 获取集合参数时,要将集合参数包装到一个实体中
-
日期类型
- 一些常见的类型, SpringMVC是内置了类型转换器,但是对于一些格式比较灵活的参数(日期 时间),SpringMVC无法完成类型转换.
- SpringMVC对日期: yyyy/MM/dd。
- 此时需要自定义类型转换器
- 自定义一个类型转换器,实现类型转换的方法
- 将自定义的类型转换注册到SpringMvc的转换服务中,然后再将服务注册到SpringMVC的注解驱动
-
中文乱码
- SpringMVC在使用post提交请求时,对于中文参数有乱码问题
- Spring提供了一个中文乱码过滤器,我们需要进行配置.
- 在
web.xml
配置SpringMVC中中文乱码过滤器
/** * 日期类型转化器: * 将输入的String字符串,按照自定义的规则转化为date对象 * 1、实现Converter接口,并提供泛型 * 2、实现convert方法,进行类型转化 */ public class StringToDateConverter implements Converter<String, Date> { @Override public Date convert(String s) { Date date = null; try { date = new SimpleDateFormat("yyyy-MM-dd").parse(s); }catch (Exception e) { e.printStackTrace(); } return date; } }
-
文件类型
- 页面:文件上传的三要素
- form表单的method = post
- form表单的enctype=“multipart/form-data”
- from表单中的input的type = file
- 加入文件上传的包
- 在SpringMVC的配置文件中添加文件解析器
- 页面:文件上传的三要素
-
@RequestParam
- @RequestParam标注在方法参数之前,用于对传入的参数做一些限制, 支持三个属性
- value:默认属性,用于指定前端传入的参数名称
- required:用于指定此参数是否必传
- defaultValue:当参数为非必传参数且前端没有传入参数时,指定一个默认值
- @RequestParam标注在方法参数之前,用于对传入的参数做一些限制, 支持三个属性
-
接收请求头信息
- @RequestHeader配置到方法参数上 : 前端控制器自动获取头信息
- @RequestHeader Map map : 获取所有的请求头
- @RequestHeader(“cookie”) String cookie : 根据key从所有头信息中获取指定头信息
- @CookieValue(“key”):
- 从cookie中根据key获取指定value数据
- @RequestHeader配置到方法参数上 : 前端控制器自动获取头信息
5.6SpringMVC入门案例
-
创建一个Project
-
创建一个新的Model 加入坐标
<!--springmvc--> spring-webmvc <!--servlet--> javax.servlet-api <!--jsp--> jsp-api <!--文件上传的包--> commons-fileupload <!-- 添加tomcat7插件 --> tomcat7-maven-plugin
-
补全目录结构
- JBLJavaToWeb: 将普通的maven工程,转化为web工程
-
加入SpringMVC的配置文件
-
在resource下创建springmvc.xml作为程序的配置文件
<!--1、包扫描--> <context:component-scan base-package="cn.itcast"></context:component-scan> <!--2、配置视图解析器--> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"></bean> <!--3、配置SpringMVC的注解驱动--> <mvc:annotation-driven></mvc:annotation-driven>
-
-
加入web的配置文件
-
web.xml文件
<!--1、包扫描--> <context:component-scan base-package="cn.itcast"></context:component-scan> <!-- 2、配置视图解析器 将逻辑视图转化为物理视图 主要功能,自动的对返回的逻辑试图添加前缀和后缀 前缀 + 逻辑视图 + 后缀 --> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!--配置返回路径的前缀--> <property name="prefix" value="/WEB-INF/jsp/"></property> <!--后缀--> <property name="suffix" value=".jsp"></property> </bean> <!--配置类型转化器 : 将自定义的类型转化器加入到SpringMVC的类型转化器集合中--> <bean id="conversionService2" class="org.springframework.context.support.ConversionServiceFactoryBean"> <property name="converters"> <set> <bean class="cn.itcast.converter.StringToDateConverter"></bean> </set> </property> </bean> <!--3、配置SpringMVC的注解驱动 相当于配置了增强版的处理器映射器和处理器适配器 --> <mvc:annotation-driven conversion-service="conversionService2"></mvc:annotation-driven> <!-- 文件解析器 id:固定值(multipartResolver) 其中指定上传文件的大小规则 --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!--文件的大小规则 5M = 1024 * 1024 * 5 --> <property name="maxUploadSize" value="5242880"></property> </bean>
-
-
开启请求页面
<%-- 对于集合中元素赋值 集合属性[索引|key] 对集合中的数据赋值 --%> <form action="${pageContext.request.contextPath}/hello/demo7" method="post"> 第一个User的name: <input type="text" name="users[0].name"/> 第一个User的age: <input type="text" name="users[0].age"> 第二个User的name: <input type="text" name="users[1].name"/> 第二个User的age: <input type="text" name="users[1].age"> <hr> map的第1个元素 <input type="text" name="map['1001']"/> map的第2个元素 <input type="text" name="map['1002']"/> map的第2个元素 <input type="text" name="map['1003']"/> <input type="submit" value="测试集合类型请求参数"> </form> <a href="${pageContext.request.contextPath}/hello/demo8?birthday=2020-09-09">测试日期类型请求参数</a> <br><br>
-
开发控制器
/** * 入门案例 * 1、在控制器类上,添加@Controller注解 * 2、在控制器类中,添加处理请求的方法 */ @Controller @RequestMapping(value="/hello") public class HelloController { /** * 入门案例: * 此方法,接收请求,数据响应和指定页面的跳转 * 返回值String * @RequestMapping : 指定进入此控制器方法的请求路径 * 可以配置到类上,配置到方法上,如果配置到类上,相当于配置此类中所有方法的共同一级连接 * value(path): * 指定当前的请求连接 * method: * 此方法可以接受的发送请求的方式 get,post * */ @RequestMapping(value="/demo") //hello/demo public String demo1() { System.out.println("第一个案例,终于执行了,真厉害"); return "success"; //经过处理器,请求需要转发的页面路径 } //当前请求路径只能,通过post发送 @RequestMapping(value="/demo2",method = {RequestMethod.POST}) //hello/demo public String demo2() { System.out.println("第一个案例,终于执行了,真厉害"); return "success"; //经过处理器,请求需要转发的页面路径 } /** * 请求参数:集合类型参数 * 1、集合需要封装到对象中:vo * 2、方法的参数:对象vo */ @RequestMapping(value="/demo7") //hello/demo public String demo6(Vo vo) { System.out.println(vo); return "success"; } /** * 请求参数:日期参数 * 日期:Date对象 * 请求连接:/hello/demo8?birthday=1990-09-09 */ @RequestMapping(value="/demo8") //hello/demo public String demo8(Date birthday) { System.out.println(birthday); return "success"; } /** * 请求参数:文件上传 * 文件上传:字节流 * SpringMVC提供对象MultipartFile,通过这个对象描述上传文件 * 1、配置到方法参数上 * 2、参数的名称和传递的文件input框中的name一致 */ @RequestMapping(value="/demo10") public String demo10(MultipartFile uploadFile) throws IOException { System.out.println(uploadFile.getOriginalFilename()); //文件名称 System.out.println(uploadFile.getSize()); //文件大小 File file = new File(new File("d:/upload"),uploadFile.getOriginalFilename()); //将上传文件中的数据,写入到本地文件中 uploadFile.transferTo(file); return "success"; } /** * 在控制器中获取,当前请求的请求头 * 1、@RequestHeader配置到方法参数上 : 前端控制器自动获取头信息 * @RequestHeader Map map : 获取所有的请求头 * @RequestHeader("cookie") String cookie : 根据key从所有头信息中获取指定头信息 * 2、@CookieValue("key"): * 从cookie中根据key获取指定value数据 * */ @RequestMapping(value="/demo12") public String demo12(@RequestHeader Map map, @RequestHeader("cookie") String cookie, @CookieValue("JSESSIONID") String sessionId) { System.out.println(map); System.out.println(cookie); System.out.println(sessionId); return "success"; }
-
开发响应页面
Day06 SpringMVC 贰
6.1请求转发
- 方式一:简单方式(推荐)
- 直接返回逻辑视图地址
- Springmvc通过视图解析器获取完整物理视图进行跳转
- 方式二:使用forward转发(其次)
- Springmvc提供的页面转发方式
- return :“forward:物理视图地址”
- 方式三:使用servlet原生api(了解)
- 获取Servlet原生API
- 将需要的对象通过参数的形式配置到方法上
- 将需要的对象,通过@Autowired注入到控制器中
- request.getRequestDispatcher("/路径").forward(request,response);
- 获取Servlet原生API
6.2转发时携带数据
-
方式一:绑定到request域(推荐)
- request.setAttribute(“name”,“jack”);
- ${name}
-
方式二:绑定到Model对象(了解)
-
将数据绑定到Model对象上(Model底层通过Request实现)
-
将Model以参数的形式配置到方法上
-
调用model的addAttribute方法,将数据存入request
public String demo3(Model model) throws Exception { //request.setAttribute("name", "jack"); //将数据存入request model.addAttribute("name", "rose"); return "success"; }
-
-
方式三:通过ModelAndView返回(官方推荐)
-
ModelAndView : 模型视图对象,通过此对象可以指定返回的视图地址和数据绑定
-
语法规则:
-
方法的返回值:ModelAndView
-
在方法中通过ModelAndView的setViewName指定跳转的页面
-
在方法中通过ModelAndView的addObject指定需要存入request域中的数据
public ModelAndView demo4() throws Exception { ModelAndView mv = new ModelAndView(); mv.setViewName("success"); //参数的写法遵循控制器返回值的写法(逻辑视图地址,forward:物理视图地址) mv.addObject("name", "王者荣耀"); return mv; }
-
-
6.3重定向
发送两次请求(第一次用户行为,第二次是浏览器的自动行为)。响应数据会丢失
-
方式一:通过redirect关键字配置
-
返回值:String
-
redirect:/重定向的路径
public String demo5() throws Exception { return "redirect:/hello/demo1"; }
-
-
方式二:通过servlet原生API配置
-
返回值void
public void demo6(HttpServletResponse response) throws Exception { response.sendRedirect(request.getContextPath()+"/success.jsp"); }
-
6.4释放静态资源
-
SpringMVC的前端控制器DispatcherServlet的url-pattern配置的是 /(缺省),代表除了jsp请求不拦截, 其他的所有请求都会拦截
-
因此当有静态资源需要加载时,一些静态文件(js html css jpg等等)被拦截后找不到对应的处理器方法来处理, 就会报错
-
因此需要释放静态资源(不交给SpringMVC处理)
-
方式一:在Springmvc的配置文件中添加释放静态资源
<!-- 释放静态资源的方式一 mapping : 请求路径的URL的映射规则 location: 静态资源的物理目录 当静态资源请求到SpringMVC的前端控制器时,根据释放资源的配置 1、不在查找具体的controller处理 2、从location路径中查找匹配的资源 --> <mvc:resources mapping="/js/*" location="/js/"></mvc:resources> <mvc:resources mapping="/image/*" location="/image/"></mvc:resources> <mvc:resources mapping="/css/*" location="/css/"></mvc:resources>
-
方式二:在Springmvc的配置文件中添加释放静态资源
<!-- 统一释放所有的静态资源文件 当SpringMVC处理静态资源时,委托给默认的Servlet处理 默认Servlet:tomcat中的默认Servlet --> <mvc:default-servlet-handler></mvc:default-servlet-handler>
-
方式三:修改前端控制器的URL映射规则
-
修改
web.xml
中前端控制器的URL映射规则,以特殊字符串结尾的请求会交给前端控制器处理。 -
需要进入SpringMVC的所有请求,都需要已.do结尾
-
控制器方法中@RequestMapping不需要做额外的配置,和之前一模一样
<!-- 配置前端控制器 DispatcherServlet --> <servlet> <servlet-name>mvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!--自动加载Springmvc的配置文件--> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>mvc</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping>
-
6.5Ajax+json实现异步交互
在SpringMVC中进行ajax的数据交互,需要通过两个注解简化开发
Springmvc默认用MappingJackson2HttpMessageConverter对json数据进行转换,需要加入jackson的包
-
@RequestBody : 自动的将请求的json字符串,转化为指定java对象(处理请求)
-
@ResponseBody:自动的将java对象,转化为json字符串并相应(处理相应)
//@ResponseBody public @ResponseBody User demo7(@RequestBody User user) throws Exception { System.out.println(user); //调用service完成业务逻辑,模拟出返回对象 User temp = new User(); temp.setName("lisi"); temp.setAge(18); return temp;
6.6Restful风格
REST是一种软件架构风格, 其强调HTTP请求的URL应当以资源为中心 ( 以后的URL中尽量不要出现动词 )
REST规范了HTTP请求动作(请求方式:post,put),使用四个词语分别表示对资源的CRUD操作:
GET(获取)、POST(新建)、PUT(更新)、DELETE(删除)
Restful :
- 针对同一个URL,根据不同的请求方式做不一样的业务处理
- 地址参数 /user/{id}
- 请求方式:GET(获取),POST(新建),PUT(更新),DELETE(删除)
/**
* 测试Restful编程风格
* 1、对同一个URL,根据不同的请求方式,完成不同的业务处理
* 2、请求URL上存在,地址参数 /user/{id}
*
* /user
* 保存 :post
* 查询所有 :get
* /user/{id}
* 根据id查询用户
* 删除用户
* 根据id更新用户
*/
@Controller
public class UserController {
//保存
@RequestMapping(value = "/user",method = RequestMethod.POST)
public String saveUser() {
System.out.println("保存用户");
return "success";
}
//查询所有
@RequestMapping(value = "/user",method = RequestMethod.GET)
public String findAll() {
System.out.println("查询所有用户");
return "success";
}
/**
* 根据id查询用户
* 传入地址参数:
* 请求URL /user/1
* 地址参数: {自定义参数名}
* 在java方法中如何获取地址参数中的数据
* @PathVariable : 配置到方法参数上
* 自动的从地址参数中,根据名称获取参数值
* @PathVariable("自定义的参数名")
*
*/
//@RequestMapping(value = "/user/{id}",method = RequestMethod.GET)
@GetMapping(value="/user/{id}")
public String findById(
@PathVariable(value="id") Integer userId) {
System.out.println("根据id查询用户userId="+userId);
return "success";
}
//根据id更新 :put
//@RequestMapping(value = "/user/{id}",method = RequestMethod.PUT)
@PutMapping(value = "/user/{id}")
public String update(
@PathVariable(value="id") Integer userId) {
System.out.println("根据id更新用户userId="+userId);
return "success";
}
//根据id删除 :delete
@RequestMapping(value = "/user/{id}",method = RequestMethod.DELETE)
public String delete(
@PathVariable(value="id") Integer userId) {
System.out.println("根据id删除用户userId="+userId);
return "success";
}
}
6.7异常处理机制
对于异常的处理一般有两种方式:
一种是当前方法处理(try-catch),这种处理方式会造成业务代码和异常处理代码的耦合。
一种是当前方法不处理, 出现异常后直接抛给调用者处理。
使用Spring框架后,我们的代码最终是由框架来调用的。异常最终会抛到框架中, 然后由框架指定异常处理器来统一处理异常。
-
方式一:自定义异常处理器
-
自定义一个类实现HandlerExceptionResolver接口,将异常处理器交给spring容器管理即可
@Component public class HandlerExcepton implements HandlerExceptionResolver { /** * 当程序抛出异常时,SpringMVC框架会自动的调用此方法。完成后续异常处理工作 * 1、跳转到一个错误页面 * 2、错误信息 * 返回值:ModelAndView * 模型与视图对象 */ public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) { e.printStackTrace(); ModelAndView mv = new ModelAndView(); mv.addObject("errorMsg", "对不起,我错了"); mv.setViewName("forward:/error.jsp"); //和success return mv; } }
-
-
方式二: @ControllerAdvice
-
配置java类
-
定义一个异常处理方法
- 返回值String (视图)
- 参数:Model
@ControllerAdvice //全局异常处理器 public class HandlerException2 { /** * @ExceptionHandler : * 配置此方法可以处理的异常类型 */ @ExceptionHandler(value = Exception.class) //空指针 public String resolveException(Model model) { model.addAttribute("errorMsg", "对不起,我又错了。"); return "forward:/error.jsp"; }
-
Day07 SpringMVC 叁
7.1拦截器
-
拦截器是SpringMVC提供的一种技术, 它的功能似于过滤器Filter,它会在进入controller之前,离开controller之后以及页面渲染完毕之后进行拦截
-
可以单独使用,也可以同时使用多个拦截器形成一条拦截器链,注册的时候注册多个,注册的顺序就代表拦截器执行的顺序。
-
自定义拦截器
- 实现HnadlerInterceptor接口
- 实现其中的三个方法(三个拦截点)
- preHandle:返回值true(拦截)/false(过滤)
- postHandle
- afterCompletion
-
配置拦截器
-
在SpringMVC的配置文件中,添加拦截器配置
<!--配置SpringMVC的拦截器--> <mvc:interceptors> <!--配置具体的拦截器和拦截器的拦截规则--> <mvc:interceptor> <mvc:mapping path="/**"/> <mvc:exclude-mapping path="/hello/demo2"/> <bean class="cn.itcast.interceptors.MyInterceptor01"></bean> </mvc:interceptor> <!--配置具体的拦截器和拦截器的拦截规则--> <mvc:interceptor> <mvc:mapping path="/**"/> <mvc:exclude-mapping path="/hello/demo2"/> <bean class="cn.itcast.interceptors.MyInterceptor02"></bean> </mvc:interceptor> </mvc:interceptors>
-
-
拦截器和过滤器的区别
- 过滤器是Servlet 规范中的一部分,任何java web工程都可以使用。
- 拦截器是SpringMVC框架的,只有使用了SpringMVC框架的工程才能用。
- 过滤器在url-pattern中配置了/*之后,可以对所有要访问的资源拦截。
- 拦截器只会拦截访问的控制器方法,如果访问的是jsp,js,html,css,image等,它是不拦截的。
7.2SSM整合
-
借助Spring框架,完成对象的创建和依赖注入。通过Spring的声明式事务完成Service层的事务控制
-
整合的步骤(初学者):
-
搭建mybatis的运行环境(保证mybatis可以独立运行)
- 建立数据库
- 创建工程
- 创建实体类
- 创建Dao接口
- 创建Dao的映射文件
- 创建Mybatis的核心配置文件
-
搭建Spring的运行环境(IOC)
- 创建service接口
- 创建Service接口实现类
- 开启注解支持(包扫描)
- 自定义的java对象 (注解)
- 第三方jar包中的java对象(XML)
-
整合Spring和mybatis
- Spring管理mybatis的配置对象(datasource,sqlsessionfactory,mapperscannerconfigurer)
- Spring的事务管理(xml,xml + 注解)
- service中注入dao的依赖
-
搭建Springmvc的运行环境
- springmvc的配置文件(包扫描,视图解析器,mvc的注解驱动,释放静态资源)
- web.xml的配置文件(前端控制器,字符集编码的过滤器)
- 编写控制器Controller
- 准备页面
-
整合Spring和SpringMVC
- 父子容器的关系(两种配置方式)
-
-
监听器配置Spring容器(父),通过dispatcherServlet配置mvc的容器(子)
- 通过dispatcherServlet配置所有对象
<servlet>
<servlet-name>mvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml,classpath:applicationContext.xml</param-value>
</init-param>
</servlet>
```
Day08maven高级
8.1依赖
- 依赖传递
- 当工程中依赖于A,而A依赖于B,那么工程也依赖于B。
- 依赖冲突
- 由于依赖的传递特性,导致依赖jar包的导入混乱,可能导致项目出现问题。
- 依赖冲突解决方法:
- 约定俗成
- 第一声明优先原则
- 路径近者优先原则
- 排除依赖
- 排除依赖配置中某个传递依赖的jar包
- 锁定版本
- 定义公共版本号
- 锁定版本
- 导入依赖
- 约定俗成
8.2聚合工程
- 分模块构建工程,将一个大型项目,按照功能模块拆分。
- 拆分标准:
- domain层,dao层,service层,web层
- maven分模块开发的架构:
- 父工程
- 多个子模块
- 继承
- 子模块可以继承父工程中定义的所有依赖
- 聚合
- 父工程统一管理所有的子模块
8.3聚合工程SSM搭建环境
- 定义父工程和子模块
- 创建export_parent父工程
- 创建export_commons子模块
- 创建export_domain子模块
- 创建export_dao子模块
- 创建export_system_service子模块
- 创建export_manager_web子模块
- 在父工程pom文件中定义公共依赖
- 在子模块中配置模块间的依赖关系
- 找到export_manager_web的pom文件,配置对service依赖
- 找到export_system_service的pom文件,配置对dao依赖
- 找到export_dao的pom文件,配置对domain依赖
8.4整合SSM
- 实体类:export_domain模块
- 搭建Mybatis的运行环境
- 代码需要编写到
export_dao
模块下 - dao接口,dao映射文件,mybatis核心配置文件,spring中关于dao的配置文件
- 代码需要编写到
- 搭建SpringIOC的运行环境
- 代码需要编写
export_system_service
下 - service接口和实现类,spring对service的配置文件(事务)
- 代码需要编写
- 整合Spring和Mybatis
- 整合mybatis的对象交给容器管理
- service的事务处理
- 搭建SpringMVC的运行环境
- 代码书写到
export_manager_web
中 - web.xml,springmvc.xml,controller,页面
- 代码书写到
- 整合Spring和SpringMVC
8.5搭建Mybatis运行环境
- 创建实体类
- 属性&getter & setter & toString
- 创建dao接口
- findAll
- 创建映射文件CompanyDao.xml
- 创建核心配置文件SqlMapConfig.xml(整合后删除)
- Spring整合mybatis: 将dao层中mybatis的相关对象,交给spring容器管理
- datasource
- sqlSessionfactoryBean
- mapperscannerconfigurer
- Spring整合mybatis: 将dao层中mybatis的相关对象,交给spring容器管理
8.6搭建Spring运行环境
- service接口
- findAll
- service接口实现类
- findAll
- spring配置文件
- Spring配置service的对象管理
- 事务配置: xml的方式
- 创建事务管理器
- 配置事务的通知
- 配置事务的AOP
8.7整合Spring和mybaits
-
spring的配置方式:
- xml结合注解
-
将dao层中mybatis的相关对象,交给spring容器管理
- 在
export_dao
工程的resources目下创建spring/applicationContext-dao.xml
- 在
-
配置Service的事务管理
- Spring配置service的对象管理
- 事务配置: xml的方式
- 创建事务管理器
- 配置事务的通知
- 配置事务的AOP
8.8搭建SpringMVC运行环境
-
springmvc的配置文件
- controller包扫描
- 视图解析器
- mvc的注解驱动
-
web.xml配置文件
- 前端控制器dispatcherServlet
- 中文乱码的过滤器 CharacterEncodingFilter
-
controller
8.9maven私服
- 私服的安装和启动和卸载
- nexus.bat install
- nexus.bat start
- nexus.bat uninstall
- 进入私服的管理后台
- 浏览器访问 localhost:8081/nexus
- 用户名/密码:admin/admin123
- 私服中仓库的种类
- virtual: 虚拟仓库(失效了,兼容maven1)
- hosted:宿主仓库(公司内部的所有jar包)
- proxy:代理仓库(代理从中央仓库下载jar包)
- group:仓库组(合并以上三种中所有仓库)
- 将本地的工程打包存入私服
- 找到maven的setting.xml配置文件,设置私服访问密码
- 找到带上传工程pom.xml配置文件,设置需要上传到的服务路径
- 执行maven命令上传:deploy
- 从私服上下载jar包
- 在maven安装目录的conf文件中的settings配置文件中配置profile
- 在maven安装目录的conf文件中的settings配置文件中激活profile
Day09 Git
9.1git概述
svn : 是一个集中式的版本控制工具(管理代码)
git :是分布式的版本控制工具
-
svn:集中式版本控制工具
- 优点:简单
- 缺点:单点故障(svn服务器出现故障)
-
git:分布式版本控制工具
-
每个客户端记录所有代码操作
-
git工作流程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c0yTWofS-1605668946280)(assets\13.png)]
9.2git的本地操作
- 初始化仓库
- 添加新文件(暂存区)
- 提交到本地版本库(本地库)
- 查看操作记录
- 还原文件
- 设置忽略
9.3在线git远程服务器
- github&gitee(中国码云)
- 码云的访问地址:https://gitee.com/
- 项目推送
- 搭建项目环境
- 初始化本地版本库
- 项目代码添加到本地版本库的暂存区
- 将暂存区内容提交到本地版本库
- 创建本地版本库和远程版本库的联系
- 将本地版本库推送到远程版本库中
- 项目克隆
- ssh协议(配置)
- 秘钥生成
- ssh密钥配置
9.4通过IDEA插件完成git操作
- 配置git的插件
- 初始化本地版本库
- 配置忽略
- 将.gitignore,添加到工程的根路径下
- 添加与提交
- 推送到远程仓库
- 克隆工程
- push修改的内容
- pull拉取最新修改的文件
- 冲突解决Merge
9.5git的分支
- 创建分支
- 切换分支
- 合并分支代码
- 将分支中最新修改的内容合并到master上
- 切换到master操作
9.6搭建私人git服务器
- 需要搭建到linux系统中
-
安装git服务环境准备
yum -y install curl curl-devel zlib-devel openssl-devel perl cpio expat-devel gettext-devel gcc cc yum install perl-ExtUtils-CBuilder perl-ExtUtils-MakeMaker
-
下载git-2.5.0.tar.gz
- 解压缩 用
tar -xzf
解压 cd git-2.5.0
进入目录中autoconf
自动配置./configure
配置脚本make
编译make install
安装
- 解压缩 用
-
添加用户
adduser -r -s /bin/sh -c 'git version control' -d /home/git git
-
输入两次密码
passwd git
-
设置/home/git文件夹操作权限
mkdir /home/git chown git:git /home/git
-
切换到git用户
su git
-
创建git仓库
cd /home/git git --bare init first 如果不使用“--bare”参数,初始化仓库后,提交master分支时报错。这是由于git默认拒绝了push操作,需要.git/config添加如下代码: [receive] denyCurrentBranch = ignore 推荐使用:git --bare init初始化仓库。
-
连接服务器
-
私有git服务器搭建完成后就可以向连接github一样连接使用了,但是我们的git服务器并没有配置密钥登录,所以每次连接时需要输入密码。
-
仓库的url:
ssh://git@192.168.66.137/home/git/first
-
库下载jar包)
- group:仓库组(合并以上三种中所有仓库)
- 将本地的工程打包存入私服
- 找到maven的setting.xml配置文件,设置私服访问密码
- 找到带上传工程pom.xml配置文件,设置需要上传到的服务路径
- 执行maven命令上传:deploy
- 从私服上下载jar包
- 在maven安装目录的conf文件中的settings配置文件中配置profile
- 在maven安装目录的conf文件中的settings配置文件中激活profile
Day09 Git
9.1git概述
svn : 是一个集中式的版本控制工具(管理代码)
git :是分布式的版本控制工具
-
svn:集中式版本控制工具
- 优点:简单
- 缺点:单点故障(svn服务器出现故障)
-
git:分布式版本控制工具
-
每个客户端记录所有代码操作
-
git工作流程
[外链图片转存中…(img-c0yTWofS-1605668946280)]
9.2git的本地操作
- 初始化仓库
- 添加新文件(暂存区)
- 提交到本地版本库(本地库)
- 查看操作记录
- 还原文件
- 设置忽略
9.3在线git远程服务器
- github&gitee(中国码云)
- 码云的访问地址:https://gitee.com/
- 项目推送
- 搭建项目环境
- 初始化本地版本库
- 项目代码添加到本地版本库的暂存区
- 将暂存区内容提交到本地版本库
- 创建本地版本库和远程版本库的联系
- 将本地版本库推送到远程版本库中
- 项目克隆
- ssh协议(配置)
- 秘钥生成
- ssh密钥配置
9.4通过IDEA插件完成git操作
- 配置git的插件
- 初始化本地版本库
- 配置忽略
- 将.gitignore,添加到工程的根路径下
- 添加与提交
- 推送到远程仓库
- 克隆工程
- push修改的内容
- pull拉取最新修改的文件
- 冲突解决Merge
9.5git的分支
- 创建分支
- 切换分支
- 合并分支代码
- 将分支中最新修改的内容合并到master上
- 切换到master操作
9.6搭建私人git服务器
- 需要搭建到linux系统中
-
安装git服务环境准备
yum -y install curl curl-devel zlib-devel openssl-devel perl cpio expat-devel gettext-devel gcc cc yum install perl-ExtUtils-CBuilder perl-ExtUtils-MakeMaker
-
下载git-2.5.0.tar.gz
- 解压缩 用
tar -xzf
解压 cd git-2.5.0
进入目录中autoconf
自动配置./configure
配置脚本make
编译make install
安装
- 解压缩 用
-
添加用户
adduser -r -s /bin/sh -c 'git version control' -d /home/git git
-
输入两次密码
passwd git
-
设置/home/git文件夹操作权限
mkdir /home/git chown git:git /home/git
-
切换到git用户
su git
-
创建git仓库
cd /home/git git --bare init first 如果不使用“--bare”参数,初始化仓库后,提交master分支时报错。这是由于git默认拒绝了push操作,需要.git/config添加如下代码: [receive] denyCurrentBranch = ignore 推荐使用:git --bare init初始化仓库。
-
连接服务器
-
私有git服务器搭建完成后就可以向连接github一样连接使用了,但是我们的git服务器并没有配置密钥登录,所以每次连接时需要输入密码。
-
仓库的url:
ssh://git@192.168.66.137/home/git/first
-
使用TortoiseGit同步
-