SSM
Ⅰ Spring
核心
一 Ioc
1.1 概念
IOC(Inversion Of Control)控制反转
使用对象的时候,由主动new产生对象转为外部提供对象,此过程的对象创建控制权由程序转移到外部,这个思想称为控制反转
- Spring提供了一个容器,称为Ioc容器,用来充当Ioc思想中的“外部”
- 被创建或者管理的对象在Ioc容器中统一称为Bean
- DI(Dependecy Injection)依赖注入:在容器中建立Bean与Bean之间的依赖关系的整个过程称为依赖注入
- 目标:充分解耦
- 最终效果:使用对象的时候不仅可以直接从Ioc容器中获取,并且获取到的Bean已经绑定了所有的依赖关系
1.2 IOC demo
- maven中导入spring坐标 spring-context
- 在xml文件中配置bean
<bean id = "bookDao123" class="com.itheima.dao.impl.BookDaoImpl"/>
- id为给bean起的名字
- class属性表示给bean定义类型(是实现类而不是接口)
- 获取IoC容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
- applicationContext. xml是上一步的配置文件
- 获取bean
BookDao bookDao = (BookDao) ctx.getBean("bookDao123");
1.3 DI demo
分析
- 基于IoC管理bean
- Service中使用new的形式创建Dao对象不再保留(为了解耦)
- Service中需要的Dao对象如何进入到Service中(提供方法)
- Service和Dao之间的关系如何描述(by配置文件)
删除上一个demo中new的方式创建对象
在xml中配置Service和Dao的关系
```xml
<!-- 配置Service和Dao的关系 --> <property name="bookDao" ref="bookDao123"/>
</bean>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
- property表示配置当前的bean属性
- name表示配置哪一个具体的属性(就是BookServiceImpl这个类的属性值的名称,里面 `private BookDao123 bookDao ` )
- ref表示参照哪一个bean
### 1.4 Bean
#### 1.4.1 bean配置
- 默认单例模式
- `<bean id = "bookDao123" class="com.itheima.dao.impl.BookDaoImpl" scope="prototype"/>`
- scope默认为singleton(单例)
- 为什么?高效
- 适合交给容器管理的bean
- 表现层、业务层、数据层、工具对象
- 不适合的
- 封装实体的域对象
- 多命名方式
#### 1.4.2 bean实例化
- 方式一:本质上是对象,使用**无参构造**方法创建,故需要提供无参构造方法
- **如何看报错**:从下往上看,第一行是连着下面的所有提示
- 方式二:使用静态工厂初始化对象(使用较少,以前用的多)
- `<bean id = "orderDao" class="com.itheima.factory.OrderDaoFactory" factory-method="getOrderDao"/>`
- `OrderDaoFactory`类是工厂类,里面提供了一个静态方法`getOrderDao()`new了一个对象
- 方式三:使用实例工厂初始化对象(了解)
- `<bean id = "userFactory" class="com.itheima.factory.UserDaoFactory"/>`
- `<bean id = "userDao" factory-method="getUserDao" factory-bean="userFactory">`
- 第一行先创建了工厂的实例对象
- 第二行使用`userFactory`工厂对象的`getUserDao`方法创建了对象
- 实际上userFactory没什么意义(只是创建了调用了他的创建对象的方法)
- 方法四:改良方法三(框架们用的很多)
- 创建一个工厂bean引入接口FactoryBean
```java
public class UserDaoFactoryBean implements FactoryBean<UserDao>{
public UserDao getObject() throws Exception {
return new UserDaoImpl();
}
public Class<?> getObjectType(){
return UserDao.class;
}
public boolean isSingleton(){
return false;//false表示非单例,true表示单例,通常都是单例的
}
}配置bean
<bean id = "userDao" class="com.itheima.factory.UserDaoFactoryBean">
1.4.3 bean的生命周期
配置bean的初始化、销毁时候的方法
- ```xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
- 其中`initm`和`destroym`为类中定义的方法
- 改进,实现类继承`initializingBean`和`DisposableBean`两个接口,然后实现`afterPropertiesSet`和`destroy`方法,配置文件中就不要init-method和destroy-method了
- 生命周期
- 初始化容器
- 创建对象(分配内存)
- 执行构造方法
- 执行属性注入(set操作)
- **执行bean初始化方法**
- 使用bean
- 关闭/销毁容器(手工关闭/注册关闭钩子)
- **执行bean的销毁方法**
### 1.5 DI
#### 1.5.1 简介
- 向一个类中传递数据的方式:普通方法(set)和构造方法
- 注入数据种类:引用类型和简单类型
- DI方式(四种)
- setter注入:简单类型/引用类型
- 构造器注入:简单类型/引用类型
#### 1.5.2 setter注入引用类型
![image-20230914224440089](https://myl-mdimg.oss-cn-beijing.aliyuncs.com/TyporaImg/SSM.assets/image-20230914224440089.png)
- 如果有多个属性就写多行`<property>`标签
#### 1.5.3 setter注入简单类型
- 在对象中定义简单类型(int、String等)并生成set方法
- 在配置文件中同样是`<property>`标签,只不过ref变为 `value=""`
#### 1.5.4 构造器注入
- 配置文件中
```xml
<bean id = "bookService" class="com.itheima.dao.impl.bookServiceImpl">
<constructor-arg name="bookDao" ref="bookDao123">
</bean>
- ```xml
name
中的名字是构造方法中形参的名字(会导致耦合度较高的问题)- 解决方案:用type来代替name,但是会导致多个同类型的参数无法分配的问题;用index代替name,也有一点问题
ref
是配置文件中bean的id- 如果是简单类型则
ref
变为value
1.5.5 怎么选
- 强制依赖使用构造器注入,使用setter注入有概率不进行注入导致null对象出现
- 可选依赖使用setter注入
- Spring倡导使用构造器,第三方框架内部多数采用构造器注入
- 自己开发的模块推荐setter注入
1.5.6 自动装配
- IoC容器根据bean所依赖的资源在容器中自动查找并注入到bean的过程称为自动装配
- 方式:按类型(常用)、按名称、按构造方法
- 用于引用类型的依赖注入
1 | <bean id = "bookDao123" class="com.itheima.dao.impl.BookDaoImpl" autowire="byType"/> |
- 注意:上述方法需要先在类中设置set方法
byType
改为byName
就是按名称- 按名称必须保障容器中具有指定名称的bean,因变量与配置耦合,不推荐使用
- 自动装配优先级低于setter注入与构造器注入,同时出现的时候自动装配配置失效
1.5.7 集合注入
- list、set、map、properties
1 | <bean id = "bookDao123" class="com.itheima.dao.impl.BookDaoImpl"> |
1.6 加载properties文件
xml文件头开命名空间(灰色的三行,直接copy然后beans换为context)
使用context空间加载properties文件
- 使用properties的数据(通过
${}
引用外部properties中的值)
- 注意
- 加载多个properties 在第二步的时候location后面加逗号连接,也可以写为
*.properties
或者classpath:*.properties
(推荐使用第二种)- 最佳为
classpath*:*.properties
区别是这个还可以加载导入的jar包里面的properties
- 最佳为
- 加载多个properties 在第二步的时候location后面加逗号连接,也可以写为
1.7 容器总结
加载容器
类路径加载(常用)
1
Applicationcontext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
文件系统加载
1
Applicationcontext ctx = new FileSystemXmlApplicationContext("绝对路径")
获取bean,三种方式
1
2
3BookDao bookDao = (BookDao) ctx.getBean("bookDao");
BookDao bookDao = ctx.getBean("bookDao", BookDao.class);
BookDao bookDao = ctx.getBean(BookDao.class);Beanfactory
是IoC容器的顶层接口,初始化的时候加载的bean延迟加载Applicationcontext
接口是Spring的核心接口,初始化的时候bean立即加载ClassPathXmlApplicationContext
和FileSystemXmlApplicationContext
是其常用的初始化类
bean相关的标签
1
2
3
4
5
6
7
8
9
10
11
12<bean
id = "" bean的id
name = "" bean的别名
class = "" bean的类型,静态工厂类,FactoryBean类
scope = "" 控制bean实例数量
init-method = "" 生命周期初始化方法
destroy-method = "" 生命周期销毁方法
autowoire = "" 自动装配类型
factory-method = "" bean工厂方法,应用于静态工厂或实例工厂
factory-bean = "" 实例工厂bean
lazy-init = "" 控制bean延迟加载
/>
1.8 注解开发
1.8.1 注解开发定义bean
- 使用
@component
定义Bean
1 | //指定了bean的名称为bookDao |
- 核心配置文件中通过组件扫描加载bean
1 | <context:component-scan base-package="com.itheima"> |
- Spring提供了三个衍生注解
@Service
、@Repository
、@Controller
- 分别表示业务层、数据层、表现层(为了方便阅读,功能都是一样的)
1.8.2 纯注解开发定义bean
Spring3.0新功能
使用配置类代替配置文件
1
2
3
4
5
6
7
8
//或者
//因为有些bean可能不能加载
public class SpringConfig{
}@Configuration
:表示该类为配置类@ComponentScan
:表示需要扫描的路径
加载使用
1
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class)
1.8.3 bean管理
- 单例与否
- 在类上添加注解
@Scope("singleton")
- 在类上添加注解
- 初始化方法:`PostConstruct
- 销毁前方法:
@reDestroy
1.8.4 依赖注入—自动装配
属性前加注解
@Autowired
使用的是反射注入,所以不用set方法
如果是简单类型就用
@Value("值")
如果简单类型引用的是配置文件的值
```java
@Configuration
@ComponentScan(“com.itheima”)
@PropertySource({“jdbc.properties”, “user.properties”})// 配置文件清单 不能用*.properties
public class SpringConfig {}
//类的定义
@Repository(“bookDao”)
public class BookDaoIml implements BookDao {@Value("${name}")//引入配置文件中的属性值 private String name;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#### 1.8.5 第三方bean管理
- 第三方bean管理
- ```java
@Configuration
@Import({JdbcConfig.class, ...})//3 导入配置类
public class SpringConfig {
}
// 0 新建一个配置类(也可以写在主配置类SpringConfig中,但是bean多了不好管理)
public class JdbcConfig {
@Value("driver")// 4 引入外部配置文件中的简单类型数据
private String driver;
@Value("url")
private String url;
@Value("userName")
private String userName;
@Value("password")
private String password;
// 1 定义一个方法获得要管理的对象
// 2 添加@Bean表示当前方法的返回值是一个bean
@Bean
public DataSource dataSource(BookDao bookdao){
System.out.println(bookdao.name);// 5 引用类型数据的自动装配
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(userName);
ds.setPassword(password);
return ds;
}
}
第三方bean依赖注入(上段代码第4、5点)
1.9 注解总结
二 框架整合
2.1 Spring整合MyBatis
- (项目Spring_MyBatis)
2.1.1 MyBatis核心步骤
- 主要就是SqlSessionFactory对象
2.1.2 整合步骤
新建一个MybatisConfig类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17public class MybatisConfig {
//定义bean,SqlSessionFactoryBean,用于产生SqlSessionFactory对象
public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){
SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();
ssfb.setTypeAliasesPackage("com.itheima.domain");//设置类型别名的包
ssfb.setDataSource(dataSource); // 设置数据库
return ssfb;
}
//定义bean,返回MapperScannerConfigurer对象
public MapperScannerConfigurer mapperScannerConfigurer(){
MapperScannerConfigurer msc = new MapperScannerConfigurer();
msc.setBasePackage("com.itheima.dao"); // 设置扫描的包
return msc;
}
}
2.2 Spring整合JUnit
- 在Maven配置文件中导入JUnit坐标
基本固定三步如下
```java
@RunWith(SpringJUnit4ClassRunner.class)//1 指定类运行器
@ContextConfiguration(classes = SpringConfig.class)//2 指定Spring配置类
public class AccountServiceTest {@AutoWired//3 自动装配bean private AccountService accountService; @Test public void testFindById(){ System.out.println(accountService.findById(1)); }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
## 三 AOP
### 3.1 概念
- AOP(Aspect Oriented Programming):面向切面编程,一种编程范式,指导开发者如何组织程序结构
- 作用:在不惊动原始设计的基础上为其进行功能增强
- Spring理念:无入侵式编程
### 3.2 AOP概念
- 连接点(JoinPoint):程序执行过程中的任意位置,粒度为执行方法、抛出异常、设置变量等
- 在Spring AOP中,理解为方法的执行
- 切入点(Pointcut):匹配连接点的式子
- 在Spring AOP中,一个切入点可以只描述一个具体的方法,也可以匹配多个方法
- 一个具体方法:com.itheima.dao包下单BookDao接口中的无形参无返回值的save方法
- 匹配多个方法:所有的save方法,所有的get开头的方法,所有以Dao结尾的接口方法,所有带有一个参数的方法
- 通知(Adcive):在切入点处执行的操作,也就是共性功能
- 在Spring AOP中功能最终以方法的形式呈现
- 通知类:定义通知的类
- 切面(Aspect):描述通知于切入点的对应关系
### 3.3 AOP demo
- 开发模式:XML或者注解
- 思路分析
- 1 导入坐标
- aspectjweaver
- spring-context
- 2 制作连接点方法(原始操作,Dao接口与实现类)
- 3 制作共性功能(通知类与通知)
- 创建一个新的类
- ```java
@Component //Spring会扫描它当作一个bean
@Aspect //告诉Spring这是一个AOP
public class MyAdvice {
@Pointcur("execution(void com.itheima.dao.BookDao.update())")// 4 切入点定义
private void pt(){}
@Before("pt()")// 5 绑定切入点与通知的关系
public void method(){
//方法体
}
}在Spring配置类中添加注解 @EnableAspectJAutoProxy
```java
@Configuration
@ComponentScan(“com.itheima”)
@EnableAspectJAutoProxy
public class SpringConfig {
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
- 4 定义切入点
- 5 绑定切入点与通知关系
- 结果:运行 `com.itheima.dao.BookDao.update()`的方法的时候在执行完update的内容前会额外执行MyAdvice中的`method()`的内容
### 3.4 AOP工作流程
- Spring容器启动
- 读取所有切面配置中的切入点
- 初始化bean,判定bean对应的类中的方法是否匹配到任意切入点
- 匹配失败,创建对象
- 匹配成功,创建原始对象(目标对象)的代理对象
- 获取bean执行方法
- 获取bean,调用方法并执行,完成操作
- 获取的bean是代理对象的时候,根据代理对象的运行模式运行原始方法与增强的内容,完成操作
- **AOP本质:代理模式**
### 3.5 AOP切入点表达式
- 切入点:要进行增强的方法
- 切入点表达式:要进行增强的方法的描述方式
- 切入点表达式标准格式:
- `动作关键字(访问修饰符 返回值 包名.类/接口名.方法名(参数) 异常名)`
- `execution(void com.itheima.dao.BookDao.update())`
- 动作关键字:描述切入点的行为动作,如execution表示执行到指定切入点
- 访问修饰符:public,private等,可以省略
- 异常名:方法中定义抛出的指定异常,可以省略
- 可以使用通配符描述切入点,快速描述
- `*`:单个独立的任意符号,可以独立出现,也可以作为前缀或者后缀匹配符
- `execution(public * com.itheima.*.UserService.find*(*))`:
匹配 com.itheima下的任意包的UserService类或接口中所有find开头的带一个参数的方法
- `..`:多个连续的任意符号,可以独立出现,常用于简化包名与参数的书写
- `execution(public User com..UserService.findById(..))`:
匹配com包下任意包中的UserService类或接口中所有名称为findById的方法
- `+`:专用于匹配子类类型
- 规范
![image-20230917231842486](https://myl-mdimg.oss-cn-beijing.aliyuncs.com/TyporaImg/SSM.assets/image-20230917231842486.png)
### 3.6 AOP通知类型
- AOP通知类型:前置通知、后置通知、环绕通知(重点)、返回后通知、抛出异常后通知
- 前置通知:`@Before()`
- 后置通知:`@After()`
- 环绕通知:`@Aroud()`(功能最强大)
- ```java
@Aroud("pt()")
public Object aroud(ProccdingJoinPoint pjp){
//前置操作
Object ret = pjp.proceed();
//后置操作
return ret;//这里的ret是原始方法的返回值,如果原始方法是void就不需要return
}
返回后通知:
@AfterReturning()
抛出异常后通知:
@AfterThrowing()
3.7 案例:测试业务曾接口万次执行效率
- 需求:任意业务层接口执行均可显示其执行效率(执行时长)
- 分析:
- 业务功能:分别获取前后执行的系统时间后取差值
- 通知类型选择环绕通知
3.8 AOP通知获取数据
- 获取切入点方法的参数
- JoinPoint:适用于前置、后置、返回后、抛出异常后通知
- ProccdingJoinPoint:适用于环绕通知
- 获取切入点方法返回值
- 返回后通知
- 环绕通知
- 获取切入点方法运行异常信息
- 环绕通知
- 抛出异常后通知
1 |
|
3.9 AOP总结
- 是一种编程范式。为了在不惊动原始设计的方法上对功能进行增强
- 核心概念
- 代理:SpringAOP核心本质是代理模式
- 连接点:SpringAOP中,理解为任意方法的执行
- 切入点:匹配连接点的式子,也是具有共性功能的方法描述
- 通知:若干个方法的共性功能,在切入点处执行,最终体现为一个方法
- 切面:描述通知与切入点的对应关系
- 目标对象:被代理的原始对象成为目标对象
四 事务
4.1 Spring事务简介
- 事务作用:在数据层保障一系列的数据库操作同成功同失败
- Spring事务的作用:在数据层或者业务层保障一系列的数据库操作同成功同失败
1 | public interface PlatformTransactionManager{ |
4.2 银行转账
需求:A账户减钱,B账户加钱
分析
- 数据层提供基础操作,指定账户减钱(outMoney),指定账户加钱(inMoney)
- 业务层提供转账操作(transfer),调用加钱与加钱操作
- 提供两个账户和操作金额执行转账操作
- 基于Spring整合MaBatis环境搭建上述操作
步骤
设置事务管理器(是jdbc的)
- ```java
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource){
}DataSourceTransactionManager transactionManager = new DataSourceTransactionManager() transactionManager.setDataSource(dataSource); return transactionManager
1
2
3
4
5
6
7
- 在transfer方法上添加注解 `@Transactional`开启事务(在接口中加比较规范)
- 在Spring配置文件中添加注解,开启事务驱动
- ```
@EnableTransactionManagement
- ```java
4.3 Spring事务
事务角色
- 事务管理员:发起事务方,在Spring中通常指开启事务的方法
- 事务协调员:加入事务方,在Spring中通常指数据层方法,也可以是业务层方法
相关配置:在注解上开启
eg:
1
事务传播行为
Ⅱ SpringMVC
一简介
1.1 概述
SpringMVC技术与Servlet技术功能等同,均属于web层开发技术
SpringMVC是一种基于Java实现的MVC模型单独轻量级Web框架(表现层)
是做表现层的,之前的Servlet技术也是表现层的技术,但是SpringMVC更简洁
1.2 demo
导入坐标
spring-webmvc
创建SpringMVC控制器类(等同于Servlet功能)
1
2
3
4
5
6
7
8
public class UserControlller {
//访问路径
//返回内容作为响应内容
public String save(){
}
}初始化SpringMVC环境(同Spring环境)设定SpringMVC加载对应的bean
1
2
3
4
5
public class SpringConfig{
}初始化Servlet容器,加载SpringMVC环境,并设置SpringMVC技术处理的请求
总结:
- 一次性工作
- 创建工程,设置服务器,加载工程
- 导入坐标
- 创建web容器启动类,加载SpringMVC配置,并设置SpringMVC请求拦截路径
- SpringMVC核心配置类(设置配置类,扫描controller包,加载Controller包控制器bean)
- 多次工作
- 定义处理请求的控制器类
- 定义处理请求的控制器方法,并配置映射路径(@RequestMapping)与返回的json数据@ResponseBody
- 一次性工作
1.3 demo工作流程分析
启动服务器初始化过程
- 服务器启动,执行ServletContainerInitConfig类,初始化web容器
- 执行createServletApplicationContext方法,创建WebApplicationContext对象
- 加载SpringMvcConfig
- 执行@ComponentScan加载bean
- 加载UserController,每个@ResponseBody名称对应一个具体的方法
- 执行getServletMappings方法,定义所有请求都通过SpringMVC
单次请求的过程
- 发送请求localhost/save
- web容器发现所有请求都经过SpringMVC,将请求交给SpringMVC处理
- 解析请求路径/save
- 由/save匹配执行对应的方法save()
- 执行save()
- 检测到有@ResponseBody直接将save方法的返回值作为响应体返回给请求方
1.4 bean的加载控制
- 加载Spring控制的bean的时候,排除SpringMVC的bean
- 方式一:Spring加载的bean设定范围为精确范围(常用)
- 方式二:排除controller包(Spring boot有用)
- 不区分两者,加载到同一容器
1.5 PostMan简介
- 是一款功能强大的网页调试与发送网页HTTP请求的Chrome插件
- 作用:用于进行接口测试
- 使用:
- 注册登录
- 创建工作空间
- 发起请求测试结果
二 请求与响应
2.1 请求映射路径
团队多人开发的时候,每个人设置不同的请求路径,冲突问题如何解决
规范命名
定义两层@RequestMapping
- 第一层在类上@RequestMapping
- 第二层在方法上@RequestMapping
2.2 请求参数
2.2.1 请求方式
Get请求
localhost:8080/commonparam?name=zhangsan&age=15
```java
@RequestMapping(“/commonparam”)
@ResponseBody
public String method(String name, int age){//方法体
}
1
2
3
4
5
6
7
8
9
10
11
12
13
- Post请求
#### 2.2.2 参数种类
- 普通参数:url地址传参,如果请求参数与形参不一致,形参前加注解
```java
@RequestMapping("/commonparam")
@ResponseBody
public String method(@RequestParam("username") String name, int age){
//方法体
}
POJO参数:请求参数名与形参对象属性名相同,定义POJO类型形参即可接收参数
1
2
3
4
5
public String method(User user){
//方法体
}嵌套POJO参数:POJO对象中包含POJO对象,则请求参数名与形参对象属性名相同,按照对象层次结构关系即可接收嵌套POJO属性参数
数组参数:请求参数名与形参对象属性名相同且请求参数为多个,定义数组类型形参即可接收参数
集合保存普通参数:请求参数名与形参集合对象名相同且请求参数为多个,@RequestParam绑定参数关系
1
2
3
4
5
public String listParam({ List<String> likes)
//方法体
}
2.2.3 请求参数传递json数据
步骤
maven导入坐标
在postman中定义发送json请求
Spring配置类上面添加注解
@EnableWebMvc
开启json转换为对象的功能在形参前面加入注解 @RequestBody
1
2
3
4
5
public String listParam({ List<String> likes)
//方法体
}
关键是
@RequestBody
注解
2.2.4 日期类数据
@DateTimeFormat(pattern="yyyy-MM-dd")
@DateTimeFormat(pattern="yyyy/MM/dd HH:MM:ss")
可以自定义格式,根据请求参数的格式来设置也有一个默认的格式
1
2
3
4
5
public String dataParam({ Date date)
//方法体
}
2.3 响应json数据
2.3.1 响应页面
1 |
|
2.3.2 响应数据
文本数据
1
2
3
4
5
public String toText(){
return "response text"
}json数据
POJO对象
1
2
3
4
5
6
public User toJsonPOJO(){
User user = new User();
return user;
}返回对象会自动转为json数据
POJO集合:返回对象改为返回集合即可
关键是
@ResponseBody
注解,可以将返回值自动转为json数据进行响应
三 REST风格
3.1 简介
REST(Representational State Transfer),表现形式状态转换
- 传统风格
http://localhost/user/getById?id=1
http://localhost/user/saveUser
- REST风格
http://localhost/user/1
http://localhost/user
- 传统风格
优点:
- 隐藏资源访问行为,无法通过地址得知对资源是何种操作
- 书写简化
风格
路径+请求方式 ==> 一个资源的访问行为
根据REST风格对资源进行访问称为RESTful
3.2 RESTful demo
1 | // 指定post方式的请求 |
按照REST风格修改相关的请求方法
快速版, 简化注解
3.3 restful 案例
rest_case项目
四 SSM整合
4.1 整合Spring、MyBatis、SpringMVC
com.itheima.config
目录下的配置类pom.xml
导入坐标
4.2 功能模块开发
com.itheima.domain
下定义Book类com.itheima.dao
下定义bookDaocom.itheima.service.impl
下定义方法接口并与相应实现类com.itheima.controller
下定义BookController实现控制层逻辑
4.3 接口测试
- 在test中创建相应的类与方法进行测试 业务层
4.4. 表现层与前端的接口
前端接收数据格式——创建结果模型类,封装数据到data属性中
但是无法确定某一个data是对应者什么操作
前端接收数据格式——封装操作到code属性中
但是对于查询来说不知道查询是否成功
前端接收数据格式——封装特殊消息到message(msg)属性中
设置统一数据返回结果类(Controller层)
1
2
3
4
5
6public class Result {
private Object data;
private Integer code;
private String msg
}
//注意:result类中的字段不是固定的,可以根据需求删减Controller中的方法的返回值设置为Result
4.5 异常处理
种类
- 框架内部异常
- 数据层抛出异常:因外部服务器故障
- 业务层抛出异常:业务逻辑错误
- 表现层抛出异常:收集数据,校验数据等
- 工具类抛出异常
一般写在表现层处理,其他层就往上抛(数据层->业务层->表现层),分类处理+AOP思想
异常处理器:集中统一的处理项目中的异常()
1
2
3
4
5
6
7
8
9
10
11
12
13
14package com.itheima.controller;
public class ProjectExceptionAdvice {
public Result doException(Exception e) {
//自定义异常处理逻辑
System.out.println(e);
return new Result(666, null);//返回错误提示结果给前端
}
}项目异常处理方案
五 拦截器
5.1 概念
拦截器(Interceptor)是一种动态拦截方法调用的机制,在SpringMVC中动态拦截控制器方法的执行
作用
- 在指定的方法调用前后执行预先设定的代码
- 阻止原始方法的执行
与过滤器的区别
- 归属不同:Filter属于Servlet技术,Interceptor属于SpringMVC技术
- 拦截内容不同:Filter对所有访问进行增强,Interceptor仅针对SpringMVC的访问进行增强
5.2 案例
在
com.itheima.controller.interceptor
包下创建ProjectInterceptor
类继承接口HandlerInterceptor
并重写方法(3个)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// 让spring能够扫描到
public class ProjectInterceptor implements HandlerInterceptor{
//preHandle postHandle afterComleption三种方法
public boolean preHandle(...) throws Exception {
System.out.println("preHandle...");
return true;//如果返回false执行完preHandle就不会执行另外两个了
}
public void postHandle(...) throws Exception {
System.out.println("postHandle...");
}
public void afterCompletion(...) throws Exception {
System.out.println("afterCompletion...");
}
}
定义配置类,继承WenMvcConfigurationSupport,实现addInterceptor方法,并添加拦截器访问路径
也可以直接在
SpringMvcConfig
配置类中继承WebMvcConfigurer
并重新addInterceptors
方法(但是侵入式较强)拦截器执行流程
5.3 拦截器参数
- 前置处理
preHandle
HttpServletRequest request
:请求对象HttpServletResponse response
:响应对象Object handler
:被调用的处理器对象,本质上是一个方法对象,对反射技术中的Method对象进行了再包装- 返回值
- 为false,被拦截的处理器将不再执行
- 后置处理
postHandle
- 多了一个
ModelAndView modelAndView
- 多了一个
- 完成后处理
afterCompletion
- 相对于
preHandle
多了一个Exception ex
- 相对于
5.4 拦截器工作流程分析
当配置多个拦截器的时候,形成拦截器链
拦截器的运行顺序参照拦截器添加顺序
当拦截器中出现对原始处理器的拦截,后面的拦截器均终止运行
Ⅲ Maven
一 分模块开发
- 创建不同模块,dao,domain,等都可以拆开
- 通过maven指令安装模块到本地仓库(install)
- 团队内部开发需要发布模块功能到团队内部可共享的仓库中(私服)
二 依赖管理
- 传递性:直接依赖与间接依赖
依赖传递冲突问题
- 路径优先:当依赖中出现相同的资源时,层级越深,优先级越低
- 声明优先:当资源中相同层级被依赖时,配置顺序靠前的覆盖配置顺序靠后
- 特殊优先:当同级配置了相同资源的不同版本,后配置的覆盖先配置的
可选依赖:对外隐藏依赖
- 在pom中的dependency标签中添加optional标签,true表示隐藏依赖(别人不知道依赖了这个)
排除依赖:主动断开依赖
- exclusion
三 继承与聚合
3.1 聚合
- 聚合:将多个模块组织成一个整体,同时进行项目构建的过程成为聚合
- 聚合工程:通常是一个不具有业务功能的空工程(有且仅有一个pom文件)
- 作用:使用聚合工程可以将多个工程编组,通过对聚合工程进行构建,实现对所包含的模块进行同步构建
- 当工程中某个模块发生更新的时候,必须保障工程中与已更新的模块同步更新,此时使用聚合工程可以批量解决
- 聚合工程的构建
- 打包类型设置为pom
- 不用管模块的顺序,实际的时候会根据它们之间的相互关系自动设置构建顺序
3.2 继承
- 继承:两个工程之间的关系,子工程可以继承父工程中的配置信息,常见于依赖关系的继承
- 作用
- 简化配置
- 减少依赖冲突
- 继承的定义
四 属性
在pom中定义属性
1
2
3<properties>
<spring.version>5.2.10.RELEASE</spring.version>
</properties>然后在坐标中的version标签中的版本改为
${spring.version}
,这样就不用一个一个更新版本了配置文件加载属性
- 然后就可以使用
${...}
来读取resources下的.propertise文件了
- 然后就可以使用
版本管理
- 工程版本
- SHAPSHOT(快照版本)
- 项目开发过程中临时输出的版本,成为快照版本
- 快照版本会随着开发的进展不断更新
- RELEASE(发布版本)
- 项目开发进入到里程碑后,向团队外部发布较为稳定的版本
- SHAPSHOT(快照版本)
- 工程版本
五 多环境配置与应用
maven提供配置多种环境的设定,帮助开发者使用过程中快速切换环境
pom文件中
也可以执行
maven install -P env_test
就不用设置activation
标签了mvn 指令 -P 环境定义id
- 跳过测试
- 应用场景
- 功能更新中并且没有开发完毕
- 快速打包等
mvn 指令 -D skipTest
- 或者配置插件,在pom中定义
- 应用场景
六 私服
6.1 概念
是一台独立的服务器,用于解决团队内部的资源共享与资源同步问题
Nexus
- 一款maven私服产品
https://help.sonatype.com/repomanager3/download
分类
6.2 本地资源访问私服配置
上传与下载的过程
配置修改
- maven的setting文件中修改
Ⅳ SpringBoot
一 demo
1.1 原始SpringMVC开发
配置依赖
web配置
SpringMvc配置
至少一个controller类
1.2 SpringBoot Demo
05_springboot_demo
只定义了一个类
对比原始
注意:基于idea开发springboot程序需要联网
- 也可以在springboot官网创建,然后下载zip
二 SpringBoot概述
设计目的是为了简化Spring应用的初始搭建以及开发过程
springboot项目快速启动
项目打jar包(boot程序一般打jar包)
执行启动命令
java -jar springboot.jar
springboot程序优点
- 自动配置
- 起步依赖(简化依赖配置)
- 辅助功能(内置服务器…)
起步依赖
starter
- springboot中常见项目名称,定义了当前项目使用的所有项目坐标,以达到减少依赖配置的目的
parent
- 所有springboot项目要继承的项目,定义了若干个坐标版本号(依赖管理,而非依赖),以达到减少依赖冲突的问题
辅助功能
排除tomcat服务器,使用jetty服务器
三 配置文件
修改服务器端口
默认是8080
方式一:resources目录下的
application.properties
文件中server.port=80
方式二:resources目录下创建
application.yml
(主要用这种)```yml
server:
port: 801
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
- 注意数据前需要加空格
- 方式三:resources目录下创建`application.yaml`
- 同上
- 三种冲突的话,优先级:`.properties` > `.yml` > `.yaml`
- yaml
- YAML:(YAML Ain't Markup Language),一种数据序列化格式
- 优点
- 易阅读、易与脚本语言交互、与数据为核心,重数据轻格式
- YAML文件扩展名
- .yml
- .yaml
- 语法
- 大小写敏感
- 属性层级关系使用多行描述,每行结尾使用冒号结束
- 使用缩进表示层级关系,同层级左侧对其,只允许使用空格(不允许tab)
- **属性值前面添加空格**
- #表示注释
- 数据读取
- 方式一:`@Value(${一级属性名.二级属性名...})`
![image-20230927210417992](https://myl-mdimg.oss-cn-beijing.aliyuncs.com/TyporaImg/SSM.assets/image-20230927210417992.png)
- 方式二:`@AutoWired`一次性全部装配所有的属性
```java
@AutoWired
private Environment enviroment;
enviroment.getProperty("lesson");//返回SpringBoot方式三:(常用)
1
2
3
4
5
6
7
8
9
public class Enterprise {
private String name;
private Integer age;
private String tel;
private String[] subject;
//会自动读取enterprise中的四个数据
}
多环境开发配置
多环境启动命令格式
带参数启动SpringBoot
java -jar springboot.jar --spring.profiles.active=test
java -jar springboot.jar --server.port=88
java -jar springboot.jar --server.port=88 --spring.profiles.active=test
配置文件分类
四 SpringBoot整合JUnit
spring整合JUnit
设置运行器 -> 加载环境 -> 注入测试对象 -> 测试功能
SpringBoot
定义好所需要测试的类
```java
@SpringBootTest
class ApplicationTests {@Autowired private BookService bookService; @Test public void saveTest() { bookService.save(); }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
![image-20230927220625953](https://myl-mdimg.oss-cn-beijing.aliyuncs.com/TyporaImg/SSM.assets/image-20230927220625953.png)
## 五 SpringBoot整合SSM
- 整合Spring和SpringMVC均不需要,只需整合MyBatis
### 5.1 Spring整合MyBatis
- SpringConfig
- 导入JdbcConfig
- 导入MyBatisConfig
- JDBCConfig
- 定义数据源(加载properties)
- MyBatisConfig
- 定义`SqlSessionFactoryBean`
- 定义映射配置
### 5.2 SpringBoot整合MyBatis
- 创建模块
- yml中设置数据源
![image-20230927224136784](https://myl-mdimg.oss-cn-beijing.aliyuncs.com/TyporaImg/SSM.assets/image-20230927224136784.png)
- 定义数据层接口与映射配置
![image-20230927224213163](https://myl-mdimg.oss-cn-beijing.aliyuncs.com/TyporaImg/SSM.assets/image-20230927224213163.png)
- 测试类中注入dao接口,测试功能
![image-20230927224238830](https://myl-mdimg.oss-cn-beijing.aliyuncs.com/TyporaImg/SSM.assets/image-20230927224238830.png)
# Ⅴ MyBatis Plus
## 一 简介
- 简称MP,是基于Mybatis框架基础上开发的增强型工具,旨在简化开发、提高效率
### 1.1 SpringBoot整合Mybatis过程
- 创建SpringBoot工程
- 勾选配置使用的技术
- 设置dataSource相关属性(JDBC参数)
![image-20231016210817888](.(https://myl-mdimg.oss-cn-beijing.aliyuncs.com/TyporaImg/SSM.assets/image-20231016210817888.png)
- 定义数据层接口映射配置
![image-20231016210853914](.(https://myl-mdimg.oss-cn-beijing.aliyuncs.com/TyporaImg/SSM.assets/image-20231016210853914.png)
### 1.2 SpringBoot整合Mybatis plus过程
- 创建SpringBoot工程
- 勾选配置使用的技术 (仅保留JDBC)
- 手动添加起步依赖
![image-20231016212322111](.(https://myl-mdimg.oss-cn-beijing.aliyuncs.com/TyporaImg/SSM.assets/image-20231016212322111.png)
- 设置Jdbc参数(application.yml),制作实体类与表结构
- 与之不同的是定义数据层接口的时候继承BaseMapper
```java
@Mapper
public interface UserDao extends BaseMapper<User> {
}
不再需要写
@Select
等测试
、
二 标准数据层开发
lombok
- 一个java类库,提供了一堆注解,简化POJO实体类开发
- 常用注解:
@Data
- 为当前实体类在编译期设置对应的get/set方法,无参/全参构造方法,toString方法,hashCode方法,equals方法等
分页功能
IPage类
```java
IPage page = new Page(1,2)//当前页码:1,每页2条
userDao.selectPage(page, null);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16![image-20231016214532717](.(https://myl-mdimg.oss-cn-beijing.aliyuncs.com/TyporaImg/SSM.assets/image-20231016214532717.png)
- 需要额外定义一个拦截器Bean
```java
@Configuration
public class MpConfig {
@Bean
pubic MybatisPlusInterceptor mpInterceptor(){
//定义Mp拦截器
MybatisPlusInterceptor mpi = new MybatisPlusInterceptor();
//添加具体的拦截器
mpi.addInterInterceptor(new PaginationInnerInterceptor());
return mpi
}
}
三 DQL控制
3.1 条件查询方式
MybatisPlus将复杂的SQL查询条件进行了封装,使用编程的形式完成条件的组合查询
方式一:
QueryWrapper
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Mybatisplus02DqlApplicationTests {
private UserDao userDao;
void testGetAll(){
QueryWrapper qw = new QueryWrapper();
qw.lt("age",30);
qw.gt("age", 10);//大于10小于30
List<User> userList = userDao.selectList(qw);
System.out.println(userList);
}
}方式二:
QueryWrapper的基础上使用lambda
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Mybatisplus02DqlApplicationTests {
private UserDao userDao;
void testGetAll(){
QueryWrapper<User> qw = new QueryWrapper<User>();
qw.lambda().lt(User::getAge, 10);//添加条件
List<User> userList = userDao.selectList(qw);
System.out.println(userList);
}
}方式三
LambdaQueryWrapper
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Mybatisplus02DqlApplicationTests {
private UserDao userDao;
void testGetAll(){
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
lqw.lt(User::getAge, 10);
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
}
}null值处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Mybatisplus02DqlApplicationTests {
private UserDao userDao;
void testGetAll(){
//模拟页面传递过来的查询数据
UserQuery uq = new UserQuery();
uq.setAge(10);
uq.setAge2(30);
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
lqw.lt(null!=uq.getAge2(),User::getAge, uq.getAge2());
lqw.gt(null!=uq.getAge(),User::getAge, uq.getAge());
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
}
}
3.2 查询投影
使用lambda
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Mybatisplus02DqlApplicationTests {
private UserDao userDao;
void testGetAll(){
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
lqw.select(User::getId,User::getName,User::getAge);
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
}
}手动指定查询字段
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Mybatisplus02DqlApplicationTests {
private UserDao userDao;
void testGetAll(){
QueryWrapper<User> lqw = new QueryWrapper<User>();
lqw.select("id","name","age","tel");
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
}
}
3.3 字段映射与表名映射
问题一:表字段与编码属性设计不同步
问题二:编码中添加了数据库中未定义的属性
问题三:采用了默认查询开放了更多的字段查看权限(比如密码)
问题四:表名与编码开发设计不同步
四 DML控制
4.1 增
- id生成策略控制
@TableId
- 雪花算法生成id
4.2 删
多条删除
- 多条查询:
selectBatchIds(list)
- 多条查询:
逻辑删除
4.3 改
乐观锁
- 原理:表字段中添加一个version,在set的时候对version进行判断,与此同时version+1以防止并发错误
实现:
表中添加version字段
实体类中添加属性,加
@version
注解在拦截器定义的bean中添加乐观锁拦截器
1
2
3
4
5
6
7
8
9
10
11
12
13
public class MpConfig {
pubic MybatisPlusInterceptor mpInterceptor(){
//定义Mp拦截器
MybatisPlusInterceptor mpi = new MybatisPlusInterceptor();
//添加具体的拦截器
mpi.addInterInterceptor(new PaginationInnerInterceptor());
//添加乐观锁拦截器
mpi.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return mpi;
}
}
五 快速开发
代码生成器
AutoGenerator
类psvm(){ AutoGenerator autoGenerator = new AutoGenerator(); //需要先定义DataSource对象 autoGenerator.setDataSource(dataSource); //需先定义全局配置对象 autoGenerator.setGlobalConfig(globalConfig); }