0.前言

1. 对象、类、包、组件、容器、框架概念

**对象(Object):**在java的世界里,对象是通过属性和方法来分别对应事物所具有的静态属性和动态属性.

**类(Class):**用于描述同一类型的对象的一个抽象的概念.

**组件(component):**组件也是抽象的概念,可以理解为一些符合某种规范的类组合在一起就构成了组件。他可以提供某些特定的功能。J2EE来说,有什么servlet,jsp, javabean,ejb都是组件。但实际他们都是类,只不过有他们特殊的规定。组件和类的关系:符合某种规范的类的组合构成组件

**容器(Container):**容器也叫做组件容器,组件容器是一种比较特殊的组件,它可以包含其他的组件。我们可以把组件放在组件容器中。

框架(framework):就是某种应用的半成品,就是一组组件,供你选用完成你自己的系统.java框架就是一些类和接口的集合,通过这些类和接口协调来完成一系列的程序实现。框架又叫做开发中的半成品,它不能提供整个WEB应用程序的所有东西,但是有了框架,我们就可以集中精力进行业务逻辑的开发而不用去关心它的技术实现以及一些辅助的业务逻辑。我们熟知的Structs和Spring就是表示层和业务层框架的代表。

架构:软件架构描述的对象是直接构成系统的抽象组件。各个组件之间的连接则明确和相对细致地描述组件之间的通讯。在实现阶段,这些抽象组件被细化为实际的组件,比如具体某个类或者对象。在面向对象领域中,组件之间的连接通常用接口()来实现

框架不是构架。架构确定了系统整体结构、层次划分,不同部分之间的协作等设计考虑。框架比架构更具体,更偏重于技术涉嫌。对于同一架构(比如Web开发中的MVC),可以通过多种框架来实现。

2.组件和对象的区别
(1)组件可以在另一个称为容器(有时也称为承载者或宿主)的应用程序中使用,也可以作为独立过程使用;

(2)组件可以由一个类构成,也可以由多个类组成,或者是一个完整的应用程序;

(3)组件为模块重用,而对象为代码重用。

(4)但是模块想要调用组件,也得先创建个对象不是。所以说,这两者还真不好搞懂。

总结:容器中的bean,可以叫做组件,也可以叫做某某的对象。一般都叫做组件,倘若叫对象,必须指明谁谁的对象,倘若不指明,说的太过笼统,容易让人误解,反而不对。Spring容器中确实都是对象不错,但是这些对象,很多是依赖于很多其他的对象实现的,要不然也不会叫做组件,所以我们叫组件更准确。

3.Spring核心组件详解
Spring核心组件只有Core、Context、Beans三个。core包侧重于帮助类,操作工具。context更侧重全局控制,功能衍生。Bean 组件在 Spring 的 org.springframework.beans 包下。这个包下的所有类主要解决了三件事:Bean 的定义、Bean 的创建以及对 Bean 的解析。对 Spring 的使用者来说唯一需要关心的就是 Bean 的创建,其他两个由 Spring 在内部帮你完成了,对你来说是透明的。

1.Spring框架的引言

spring(春天),生于在2002年,由Rod Johnson创作。Spring框架是一个集众多设计模式于一身的开源的轻量级项目管理框架,致力于JAVAEE轻量级解决方案。相对于原来学过的框架而言,spring框架和之前学习的struts2 、mybatis 框架有了本质的区别,不是替换原来的某个框架,而是对其进行整合管理
轻量级解决方案:提供一个以简单的、统一的、高效的方式构造整个应用,并且可以将单层框架以最佳的组合揉和在一起建立一个连贯的体系。

补充:Maven Repository网址:https://mvnrepository.com/ Spring官网:https://docs.spring.io/spring-framework/reference/6.2-SNAPSHOT/index.html Spring中文文档:https://springdoc.cn/spring/

2.Spring框架的核心作用

Spring 框架用来管理[创建|使用|销毁]项目中的组件,由于spring 框架可以帮我们生产项目中组件对象,因此也习惯称spring是一个工厂|容器

组件: 项目中的service,dao,action,都是项目中的组件

注意: spring框架通常不管理对实体类对象创建,例如entity

image-20240325162651851

3.第一个环境搭建

3.1思路概述

image-20240324120715418

3.2代码实现

回顾之前:通过new创建对象,拿到对象后去调用方法,然后jvm会帮我们销毁组件。下面讲解使用spring框架,如何实现组件的创建,使用,销毁。

创建Maven—webapp工程(要先勾选Create from archetype,才能选择maven-archetype-webapp)

准备目录结构:main下新建java、resources(若以普通文件夹创建时,需要右键—Mark Directory As—Source/Resources Root)

a.引入依赖:在pom.xml的dependencies中添加(注意版本要一致)

<!--spring核心及相关依赖-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>4.3.2.RELEASE</version>
</dependency>
<!--spring相关依赖-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-beans</artifactId>
    <version>4.3.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>4.3.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-expression</artifactId>
    <version>4.3.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>4.3.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>4.3.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
    <version>4.3.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>4.3.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>4.3.2.RELEASE</version>
</dependency>

b.引入配置文件:在resources中的包上右键—new—XML Configuration File—Spring Config—新建spring.xml

1
2
3
4
5
6
7
8
9
# 配置文件名称: 任意名称,最好做到见名知意
# 配置文件位置: 项目中根目录下任意位置,一般放在resources目录下
# 配置文件的内容:
<?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-3.2.xsd ">
</beans>

c.创建组件

UserDAO接口

image-20240324120552254

UserDAOImpl实现类

image-20240324120601416

d.工厂管理:在spring.xml中添加**

1
2
3
4
5
6
7
8
9
10
11
12
13
 <?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">

<!--配置文件:位置任意,只要在所属项目根路径下就行,可建在resources文件夹下,名称任意,最好见名知意-->
<!--通过bean标签管理组件对象
bean:用来管理组件对象的创建
id:用来指定spring框架创建的当前组件对象在spring中的唯一标识,全局唯一,一般为接口名首字母小写
class:用来指定管理组件对象的全限定名:包名.类名
-->
<bean id="userDAO" class="com.baizhi.dao.UserDAOImpl"></bean>
</beans>

image-20240324120623329

e.启动工厂测试

1
2
3
4
5
6
7
8
public static void main(String[] args) {//main方法快捷方式psvm或main
//启动工厂,一读到配置文件,就会根据我们指定的类创建组件对象,并且在工厂中给创建的组件对象起了唯一的标识
ApplicationContext context = new ClassPathXmlApplicationContext("init/spring.xml");//指定xml文件位置
//获取工厂中创建的对象 参数:获取工厂中指定对象的唯一标识
UserDAO userDAO = (UserDAO) context.getBean("userDAO");//对应xml中唯一标识
System.out.println(userDAO);//可以打印出来看看是不是创建好一个对象
userDAO.save("茶白");
}

4.Spring框架中的核心思想

4.0 概述

img

4.1 IOC

1.IOC(inversion of control)控制反转

定义:将对象的创建由原来(new)的方式转移到spring配置文件中,交给spring工厂,由spring工厂完成对象的创建。

2.DI(dependency injection)依赖注入:在IOC的基础上提出的补充概念

定义: Spring不仅要创建对象,还要建立类与类之间的关系,因此在控制反转的基础上又提出了依赖注入的概念。

4.2AOP

AOP( Aspect Oriental Programing ) :面向切面的编程

4.3 代码实现

spring.xml

image-20240324122101038

DeptServiceImpl

image-20240324122201807

测试:

image-20240324122227849

补充:

xml文件中的bean里面的id命名要见名知意,推荐使用接口首字母小写进行命名

容器中都有IOC的概念,例如:tomcat 容器/网络服务器

注释快捷键:Ctrl+/

复制当前行到下一行:Ctrl+D

get、set、toString、构造方法、重写方法等:Alt+Insert

跳转到接口实现类方法上:在接口上—Ctrl+Alt+B

添加if/else、while、for、try/catch、synchronized、Runnable等:选中代码—Ctrl+Alt+T

psvm 打印 main方法

sout 打印 System.out.println();

fori 打印 for (int i = 0; i < ; i++) { },forj、forz以此类推

itar 打印 for (int i = 0; i < array.length; i++) { = array[i]; }

iter 打印 for (Object o : ) { }

DAO层:(持久层 / 数据访问层)主要与数据库进行交互,做数据持久层的操作【面向表】

Service层:(业务层 / 服务层 )主要负责业务模块的逻辑应用设计,在service层调用接口进行业务逻辑处理【面向业务】

Controller层:(控制层 )负责对具体业务模块的流程控制,与前台互交,把前台传进来的参数进行处理,即:Controller负责请求转发,接受页面过来的参数,传给Service处理,接到返回值,再传给页面。

Entity层: (实体层 )数据库在项目中的类

View层: (视图层)负责前台jsp页面的表示

5.Spring中注入方式

5.1SET注入(重点)

5.1.0SET注入概述

img

1.组件对象中需要哪个组件|谁, 就将谁声明为成员变量井提供公开的SET方法

2.在spring的配置文件中对应的组件标签内使用property标签去完成属性的赋值操作

5.1.1 八种基本类型+String类型 +日期类型的注入

1
2
3
4
5
6
private String name;
private Interger age;
private Boolean sex;
private Double price;
private Float counts;
private Date bir;
1
2
3
4
5
6
<property name="name" value="zhagnsan"/>
<property name="age" value="21"/>
<property name="id" value="100063"/>
<property name="bir" value="2012/12/12"/>
<property name="counts" value="23.23"/>
<property name="price" value="256.34"/>

5.1.2 引用类型的注入

1
private ClazzDAO clazzDAO;
1
2
<!--注入引用类型-->
<property name="clazzDAO" ref="clazzDAO"/>

5.1.3 数组类型的注入

1
2
private String[] qqs;
private ClazzDAO clazzDAOS;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!--管理DAO组件->
<bean id="clazzDAO" class="setdi.ClazzDAOImpl"></bean>
<!--管理Service组件->
<bean id="clazzService" class="setdi.ClazzServiceImpl">
<!--使用property完成属性注入赋值操作->
<property name="clazzDAO" ref="clazzDAO"/>
<!--注入数组类型(基本类型数组)->
<property name="qqs">
<array>
<value>xxx</value>
<value>qqq</value>
<value>vvvv</value>
</array>
</property>
<!--注入数组类型(引用类型数组)->
<property name="clazzDAOS">
<array>
<ref bean="clazzDAO"></ref>
<ref bean="clazzDAO"></ref>//工厂创建对象默认是单例,无论注入多少个始终是单例的,后边可以改多例的
<ref bean="clazzDAO"></ref>
</array>
</property>
</bean>

5.1.4 注入引用类型和集合类型

1
2
3
4
5
private List<String> hobbys;
private List<ClazzDAO> clazzDAOList;
private Map<String,String> maps;
//注入properties
private Properties properties;
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
<!--注入list集合(基本类型数组)->  
<property name="hobbys">
<list>
<value>aaa</value>
<value>bbb</value>
<value>ccc</value>
</list>
</property>
<!--注入list集合(引用类型)->
<property name="clazzDAOLists">
<list>
<ref bean="ClazzDAO"/>
<ref bean="ClazzDAO"/>
<ref bean="ClazzDAO"/>
</list>
</property>
<!--注入map集合(基本类型数组)->
<property name="maps">
<map>
<entry key="aa" value="xiaohei"/>
<entry key="bb" value="xiaoming"/>
<entry key="cc" value="xiaosan"/>
</map>
</property>
<!--注入properties类型->
<property name="properties">
<props>
<prop key="url">jdbc:mysql://localhost:3306/test</prop>
<prop key="driver">com.mysql.jdbc.Driver</prop>
<prop key="username">hr</prop>
<prop key="password">hr</prop>
</props>
</property>

注意:

1.引用类型使用ref属性注入,基本类型使用value属性注入

2.props是特殊的map,也采用key-value的形式进行标识

5.1.5 实测

DeptServiceImpl.java

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
package di;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Properties;

public class DeptServiceImpl implements DeptService{
private DeptDAOImpl deptDAO2;
private String name;
private Date bir;
private String[] array;
private DeptDAO[] deptDAOS;
private List<String> hobbies;
private List<DeptDAO> daos;
private Map<String,String> maps;
private Properties properties;
public void setDeptDAO2(DeptDAOImpl deptDAO2) {
this.deptDAO2 = deptDAO2;
}

public void setName(String name) {
this.name = name;
}

public void setBir(Date bir) {
this.bir = bir;
}

public void setArray(String[] array) {
this.array = array;
}

public void setDeptDAOS(DeptDAO[] deptDAOS) {
this.deptDAOS = deptDAOS;
}

public void setHobbies(List<String> hobbies) {
this.hobbies = hobbies;
}

public void setDaos(List<DeptDAO> daos) {
this.daos = daos;
}

public void setMaps(Map<String, String> maps) {
this.maps = maps;
}

public void setProperties(Properties properties) {
this.properties = properties;
}

@Override
public void save(String name) {
System.out.println("DeptServiceImpl: " + name);
deptDAO2.save(name);
System.out.println("Name: " + this.name);
System.out.println("Bir: " + bir);
for (String arr:array) {
System.out.println(arr);
}
for (DeptDAO dao:deptDAOS) {
System.out.println(dao);
}
hobbies.forEach(hobby-> System.out.println("hobby = " + hobby));
daos.forEach(dao-> System.out.println("dao = " + dao));
maps.forEach((key,value)-> System.out.println("key = " + key +",value = " + value));
properties.forEach((key,value)-> System.out.println("key = " + key +",value = " + value));
}
}

spring.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
45
46
47
48
49
50
51
52
53
54
<?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="deptDAO" class="di.DeptDAOImpl"></bean>

<bean id="deptService" class="di.DeptServiceImpl">
<property name="deptDAO2" ref="deptDAO"/>
<property name="name" value="Li Ming"/>
<property name="bir" value="2022/03/31 20:17:58"/>
<property name="array">
<array>
<value>小猪</value>
<value>小狗</value>
<value>小猫</value>
</array>
</property>
<property name="deptDAOS">
<array>
<ref bean="deptDAO"/>
<ref bean="deptDAO"/>
<ref bean="deptDAO"/>
</array>
</property>
<property name="hobbies">
<list>
<value>看书</value>
<value>打豆豆</value>
<value>睡觉</value>
</list>
</property>
<property name="daos">
<list>
<ref bean="deptDAO"/>
<ref bean="deptDAO"/>
<ref bean="deptDAO"/>
</list>
</property>
<property name="maps">
<map>
<entry key="aaa" value="123"/>
<entry key="bbb" value="456"/>
<entry key="ccc" value="789"/>
</map>
</property>
<property name="properties">
<props>
<prop key="111">qwe</prop>
<prop key="222">asd</prop>
<prop key="333">zxc</prop>
</props>
</property>
</bean>
</beans>

测试类

1
2
3
4
5
6
7
8
9
10
11
12
package di;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestSpring {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("di/spring.xml");
DeptService deptService = (DeptService) context.getBean("deptService");
deptService.save("2022年3月31日15:23:06");
}
}

5.2构造器注入

5.2.1定义

使用类中构造方法为类中成员变量进行赋值的过程 称之为构造注入

5.2.2语法

1.需要哪个组件属性就将谁声明为成员变量,并提供公开的构造方法

2.在配置文件中对应的组件标签内部使用<constructor-arg>标签进行注入(联想记忆:set注入时使用property标签)

5.2.3实测

DeptDAO

1
2
3
4
package cdi;
public interface DeptDAO{
void save(String name);
}

DeptDAOImpl

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
package cdi;

import java.util.Date;
import java.util.List;

public class DeptDAOImpl implements DeptDAO{

//构造注入语法
private String name;
private Integer age;
private Date bir;
private String[] qqs;
private List<String> hobbies;

public DeptDAOImpl() {
}

public DeptDAOImpl(String name, Integer age, Date bir, String[] qqs) {
this.name = name;
this.age = age;
this.bir = bir;
this.qqs = qqs;
}

public DeptDAOImpl(String name, Integer age, Date bir, String[] qqs, List<String> hobbies) {
this.name = name;
this.age = age;
this.bir = bir;
this.qqs = qqs;
this.hobbies = hobbies;
}

@Override
public void save(String name) {
System.out.println("name = " + name);
System.out.println("this.name = " + this.name);
System.out.println("age = " + age);
System.out.println("bir = " + bir);
hobbies.forEach(hobby-> System.out.println("bobby = " + hobby));
for (String qq : qqs) {
System.out.println("qq = " + qq);
}
}
}

spring.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
<?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">
<!--管理DAO组件
1.SET方式注入 注入时使用property标签
2.构造方法注入 注入时使用constructor-arg标签
-->
<bean class="cdi.DeptDAOImpl" id="deptDAO">
<!--index从0开始,表示第一个成员变量注入参数,以此类推-->
<!--String-->
<constructor-arg index="0" name="name" value="茶白"/>
<!--Integer-->
<constructor-arg index="1" name="age" value="20"/>
<!--Date-->
<constructor-arg index="2" name="bir" value="2022/04/01"/>
<!--String[]-->
<constructor-arg index="3" name="qqs">
<array>
<value>小猫</value>
<value>小图</value>
<value>小哈</value>
</array>
</constructor-arg>
<!--List<String>-->
<constructor-arg index="4" name="hobbies">
<list>
<value>今天</value>
<value>明天</value>
<value>后天</value>
</list>
</constructor-arg>
</bean>
</beans>

测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package cdi;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestSpring {
public static void main(String[] args) {
//启动工厂
ApplicationContext context = new ClassPathXmlApplicationContext("cdi/spring.xml");

DeptDAO deptDAO = (DeptDAO)context.getBean("deptDAO");

deptDAO.save("笑笑");
}
}

注意:

1.构造注入并不常用,不过在一些框架类中必须使用构造注入,这里先了解其注入语法即可。

2.数组、List等语法与set注入相同

5.3自动注入

5.3.1定义

在spring工厂配置文件(spring.xml)中通过指定自动注入方式,开启组件属性的自动赋值

注意:

a.自动注入底层使用的原理仍是set注入方式

b.自动注入使用时,需要在对应组件标签上开启才能使用

c.只能完成引用类型|对象类型|组件类型的注入

5.3.2语法

a. 需要注入谁,就将谁声明为成员变量,并提供公开的set方法

b. 在对应的组件标签中加入autowired属性,并指定自动注入的方式即可完成注入

自动注入的方式主要使用byName和byType两种

autowire: 用来给组件中成员变量完成自动赋值操作

autowire=”byName”根据注入的名称完成自动注入,将成员变量名与配置文件中bean的名称(id)进行匹配, 找到则注入, 找不到就报错。

autowire=”byType”根据注入的属性类型完成自动注入, 将成员变量类型与配置文件中的类型匹配,类型一致时完成注入,找不到不赋值,注意:如果工厂中存在多个类型一致的组件,会产生歧义,使用类型自动注入会报错。

5.3.3实测

DeptDA0

1
2
3
4
package adi;
public interface DeptDA0{
void save(String name);
}

DeptDAOImpl

1
2
3
4
5
6
7
8
package adi;
public class DeptDAOImpl implements DeptDA0{

@Override
public void save(String name) {
System.out.println("DAO = " + name);
}
}

DepetService

1
2
3
4
package adi;
public interface DepetService{
void save(String name);
}

DeptServiceImpl.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package adi;

/**
* 自动注入
*/
public class DeptServiceImpl implements DeptService{

private DeptDAO deptDAO;

public void setDeptDAO(DeptDAO deptDAO) {
this.deptDAO = deptDAO;
}

@Override
public void save(String name) {
System.out.println("Service = " + name);
deptDAO.save(name);
}
}

spring.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?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">
<!--管理DAO组件-->
<bean class="adi.DeptDAOImpl" id="deptDAO"/>
<!--管理Service组件-->
<!--
autowired:用来给组件成员变量完成自动赋值操作
byType: 根据类型完成自动注入 根据成员变量类型去工厂找 找到对应类型完成注入 找不到注入
byName: 根据名称完成自动注入 根据成员变量名字去工厂中获取与之一致名字 找到完成注入 找不到不注入
-->
<bean class="adi.DeptServiceImpl" id="deptService" autowire="byName"/>
<!--这里按名称找到成功故把DAO对象注入到Service-->
</beans>

注:应优先使用接口而不是类来引用对象对象,即DeptDAO deptDAO= new DeptServiceImpl(); 故这里<bean class="adi.DeptDAOImpl" id="deptDAO"/>也属于DeptDAO类型

测试

1
2
3
4
5
6
7
8
9
10
11
12
package adi;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestSpring {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("adi/spring.xml");
DeptService deptService = (DeptService)context.getBean("deptService");
deptService.save("茶白");
}
}

5.4注解式注入

看16

6.Spring工厂相关特性

6.1Spring工厂中创建对象的模式

spring中bean的创建方式主要有2种:singleton(单例模式)、prototype(多例模式

(1) singleton:单例模式,默认spring在管理组件时采用的是单例的创建方式,全局唯一,且只创建一次,无论在工厂中获取多少次始终 是同一个对象

例:service、dao等,以单例形式管理

(2) prototype:多例模型,全局不唯一,每次使用时都会创建一个新的对象

例:structs2中action必须以多例形式管理,因为成员变量间数据共享,会导致数据安全问题

具体配置:

单例:<bean id="xxx" class="xxx" scope="singleton"/>

或 : <bean id="xxx" class="xxx"/>

多例:<bean id="xxx" class="xxx" scope="prototype"/>

6.2.Spring工厂创建对象的原理

原理:反射 + 构造方法(一般使用无参构造创建,在使用构造注入时,会采用有参构造)

1
2
3
//工会远离
UserDAOImpl userDAO = (UserDAOImpl) Class.forName("com.baizhi.dao.UserDAOImpl").newInstance();
System.out.println(userDAO);

6.3.Spring工厂管理组件生命周期

6.3.1组件生命周期

(1) 对象什么时候创建

单例:随着工厂启动,工厂中的所有单例对象随之创建

多例:非单例的对象在每次使用的时候创建

(2) 对象什么时候销毁

单例:随着工厂关闭,工厂中的所有单例对象随之销毁

多例:非单例的对象在创建后失去spring工厂的管理,需要JVM进行销毁

注意: spring对多例bean管理松散,不会负责多例bean的销毁

(3) 生命周期方法

init-method=”” 在对象初始化调用方法(单例/多例均调用)

destroy-method=”” 在对象销毁时调用方法(仅单例调用)

6.3.2spring工厂使用的好处

(1)解耦合。使用配置文件管理java类,在生产环境中如需更换类的实现时,不需要重新部署,修改文件即可

(2)减少jvm内存占用。spring默认使用单例的模式创建bean,可以减少内存的占用。

(3)方便组件管理和代码维护。通过依赖注入方式建立了组件与组件、对象与对象之间的依赖关系,使java之间的关系更为清晰,方便我们进行代码的维护和管理

6.3.3实测

UserServiceI

1
2
3
4
package fdi;
public interface UserServiceImpl{
public void save();
}

UserServiceImpl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package fdi;

public class UserServiceImpl implements UserService{
@Override
public void save(String name) {
System.out.println("UserServiceImpl = " + name);
}

//init
public void init(){
System.out.println("组件对象初始化完毕");
}

//destory
public void destroy(){
System.out.println("组件对象销毁完毕");
}
}

spring.xml

1
2
3
4
5
6
7
8
<?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">
<!--单例:scope="singleton"-->
<!--多例:scope="prototype"-->
<bean class="fdi.UserServiceImpl" id="userService" scope="prototype" init-method="init" destroy-method="destroy"/>
</beans>

测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package fdi;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestSpring {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
ApplicationContext context = new ClassPathXmlApplicationContext("fdi/spring.xml");
UserService userService = (UserService)context.getBean("userService");//创建对象时调用init方法
System.out.println(userService);
userService.save("2022年4月2日10:35:30");
UserService userService2 = (UserService)context.getBean("userService");//创建对象时调用init方法
System.out.println(userService2);
userService2.save("2022年4月2日10:40:46");
((ClassPathXmlApplicationContext)context).close();//单例时调用destroy方法

//利用反射机制创建对象 Alt+Enter:抛异常
UserServiceImpl userService3 =(UserServiceImpl)Class.forName("fdi.UserServiceImpl").newInstance();
}
}

7IOC和DI知识回顾

7.1.1spring框架?

spring 框架是一个项目管理框架,核心是用来管理项目中组件对象的创建、使用、销毁。

7.1.2spring框架第一个环境搭建

1).引入依赖

1
2
3
4
5
6
7
spring-core
spring-context
spring-beans
spring-expression
spring-jdbc
spring-web
.....

2).引入配置文件spring.xml

1
名字 随便  位置:resources目录下随便

3).通过spring管理组件的创建

1
2
interface UserDAO { void save(String name)}
class UserDAOImpl implements UserDAO

spring.xml

1
<bean id="userDAO" clsss="xxx.UserDAOImpl"/>

4).启动工厂

1
2
ApplicationContext  context = new ClassPathXmlApplicationContext("xxx/spring.xml");
context.getBean("beanid");

7.1.3spring核心思想

IOC&DI
IOC:inversion of control 控制反转
就是将手动通过new关键字创建对象的权利交给spring,由工厂创建对象的过程
DI: Dependency Injection 依赖注入
Spring工厂不仅要创建对象,还要在创建对象的同时维护组件和组件的依赖关系

AOP: 面前切面编程

7.1.4spring中的注入方式

1.SET方式[重点] 2.构造方法 3.自动注入

1.SET注入

定义: 使用set方法形式为成员变量赋值过程称之为set注入

语法:

1.需要谁将谁声明为成员变量并提供公开SET方法

2.在spring配置文件中对应组件标签内部使用 property标签完成注入

1
2
3
4
5
6
7
8
9
10
11
12
1.String + 八种基本类型 + 日期类型 使用 value属性进行注入
<property name="name" value="xx">
注意: spring中日期格式 默认为 yyyy/MM/dd HH:mm:ss
2.对象|引用类型
<property name="" ref="beanid">
3.数组类型
array 基本:value 引用: ref bean="beanid"
4.list set map
list 基本:value 引用: ref
map entry 基本:key="" value="" 引用: key-ref="beanid" value-ref="beanid
5.properties
props prop key="" <prop key="">value</prop>

7.1.5spring工厂细节

1).创建方式 默认使用单例
<bean class="" id="" scope="singleton(service dao)|prototype(struts2action)">

2).工厂原理

反射+构造方法

Class.forName("xxxx").newInstance();

3).工厂生命周期

单例: 工厂启动,工厂中单例对象随之创建;工厂正常关闭,工厂中单例对象随之销毁
多例: 每次使用时工厂进行多例对象的创建;spring工厂不负责多例对象的销毁

8.静态代理和动态代理

8.1代理引言

8.1.1什么是代理?

代理: 指的是java中的一种设计模式

8.1.2为什么需要代理?

很多时候除了当前类能够提供的功能外,我们还需要补充一些额外功能

8.1.3代理的作用

代理对象可以在客户和目标对象之间起到中介作用,从而为目标对象增添额外的功能。

8.1.4代理图例

img

8.2现有业务层开发存在问题

引入spring相关依赖

定义业务接口 UserService

1
2
3
4
5
6
7
public interface UserService {
void save(String name);
void delete(String id);
void update();
String findAll(String name);
String findOne(String id);
}

实现业务接口 UserServiceImpl

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
//原始业务逻辑对象
public class UserServiceImpl implements UserService {

//开启事务 处理业务 调用DAO
@Override
public void save(String name) {
try {
System.out.println("开启事务");
System.out.println("处理业务逻辑,调用DAO~~~");
System.out.println("提交事务");
}catch (Exception e){
System.out.println("回滚事务");
e.printStackTrace();
}
}

@Override
public void delete(String id) {
try {
System.out.println("开启事务");
System.out.println("处理业务逻辑,调用DAO~~~");
System.out.println("提交事务");
}catch (Exception e){
System.out.println("回滚事务");
e.printStackTrace();
}
}

@Override
public void update() {
try {
System.out.println("开启事务");
System.out.println("处理业务逻辑,调用DAO~~~");
System.out.println("提交事务");
}catch (Exception e){
System.out.println("回滚事务");
e.printStackTrace();
}
}

@Override
public String findAll(String name) {
try {
System.out.println("开启事务");
System.out.println("处理业务逻辑,调用DAO~~~");
System.out.println("提交事务");
}catch (Exception e){
System.out.println("回滚事务");
e.printStackTrace();
}
return name;
}

@Override
public String findOne(String id) {
try {
System.out.println("开启事务");
System.out.println("处理业务逻辑,调用DAO~~~");
System.out.println("提交事务");
}catch (Exception e){
System.out.println("回滚事务");
e.printStackTrace();
}
return id;
}
}

spring.xml

1
2
3
4
5
6
7
<?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">
<!--管理Service-->
<bean id="userService" class="staticproxy.UserServiceImpl"></bean>
</beans>

TestSpring

1
2
3
4
5
6
7
8
package staticproxy;

public class TestSpring{
ApplicationContext context = new ClassPathXmlApplicationContext("staticproxy/spring.xml");
UserService userService = (UserService)context.getBean("userService");

userService.findAll("小陈");
}

问题:从上面的代码可以发现,现有业务层中控制事务代码出现了大量的冗余,如何解决现有业务层出现的冗余问题? 下面从代理的角度进行分析。

解决方法:静态代理

8.3静态代理的开发

**目标类|对象(target)**: 被代理类称之为目标类 或者 被代理的对象的称之为目标对象

开发代理的原则: 代理类和目标类功能一致且实现相同的接口, 同时代理类中依赖于目标类对象

更改目标实现类

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
//原始业务逻辑对象
public class UserServiceImpl implements UserService {

//开启事务 处理业务 调用DAO
@Override
public void save(String name) {
System.out.println("处理业务逻辑,调用DAO~~~");
}

@Override
public void delete(String id) {
System.out.println("处理业务逻辑,调用DAO~~~");
}

@Override
public void update() {
try {
System.out.println("处理业务逻辑,调用DAO~~~");
}

@Override
public String findAll(String name) {
try {
System.out.println("处理业务逻辑,调用DAO~~~");
}

@Override
public String findOne(String id) {
try {
System.out.println("处理业务逻辑,调用DAO~~~");
}

开发静态代理类

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
75
76
77
78
79
80
81
//开发原则: 代理类和目标类实现相同接口,依赖于真正的目标类
//注意:这里为每个业务层通过手动开发一个代理对象的过程称之为 静态代理对象
//代理对象:保证原始功能不变的情况下 完成业务逻辑中附加操作
public class UserServiceStaticProxy implements UserService {

//依赖原始业务逻辑对象|Target:目标对象|被代理对象称之为目标对象|原始业务逻辑对象|真正业务逻辑对象
private UserService userService;
public void setUserService(UserService userService){
this.userService = userService;
}

@Override
public void save(String name) {
try {
System.out.println("开启事务");
//调用原始业务逻辑对象方法
userService.save(name);
System.out.println("提交事务");
}catch (Exception e){
System.out.println("回滚事务");
e.printStackTrace();
}
}

@Override
public void delete(String id) {
try {
System.out.println("开启事务");
//调用原始业务逻辑对象方法
userService.delete(id);
System.out.println("提交事务");
}catch (Exception e){
System.out.println("回滚事务");
e.printStackTrace();
}
}

@Override
public void update() {
try {
System.out.println("开启事务");
//调用原始业务逻辑对象方法
userService.update();
System.out.println("提交事务");
}catch (Exception e){
System.out.println("回滚事务");
e.printStackTrace();
}
}

@Override
public String findAll(String name) {
try {
System.out.println("开启事务");
//调用原始业务逻辑对象方法
String all = userService.findAll(name);
System.out.println("提交事务");
return all;
}catch (Exception e){
System.out.println("回滚事务");
e.printStackTrace();
}
return name;
}

@Override
public String findOne(String id) {
try {
System.out.println("开启事务");
//调用原始业务逻辑对象方法
String One = userService.findOne(id);
System.out.println("提交事务");
return One;
}catch (Exception e){
System.out.println("回滚事务");
e.printStackTrace();
}
return id;
}

}

配置静态代理类

1
2
3
4
5
6
7
8
9
10
11
12
<?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">
<!--管理Service--> <!--配置目标类-->
<bean id="userService" class="staticproxy.UserServiceImpl"></bean>
<!--管理Service中proxy--> <!--配置代理类-->
<bean id="userServiceStaticProxy" class="staticproxy.UserServiceStaticProxy">
<!--依赖于真正业务逻辑对象--> <!--注入目标对象-->
<property name="userService" ref="userService"></property>
</bean>
</beans>

调用代理方法

1
2
3
4
5
6
7
8
package staticproxy;

public class TestSpring{
ApplicationContext context = new ClassPathXmlApplicationContext("staticproxy/spring.xml");
UserService userService = (UserService)context.getBean("userServiceStaticProxy");

userService.findAll("茶白");
}

新的问题:往往在开发时我们书写的业务层会有很多,如果为每一个业务层开发一个静态代理类,不仅没有减轻工作量,甚至让我们的工作量多了一倍不止怎么解决以上这个问题呢?

解决方案:为业务层在运行过程中动态创建代理类,通过动态代理类去解决我们现有业务层中业务代码冗余的问题。

8.4动态代理的原理(能理解即可)

通过jdk提供的Proxy这个类动态的为现有的业务生成代理类

参数一:当前线程类加载器

参数二:生成代理类的接口类型

参数三通过代理类对象调用方法时会优先进入参数三中的invoke方Proxy newProxyInstance(loader interfaces, h)//返回值就是动态代理对象

TestDynamicProxy

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
package staticproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class TestDynamicProxy {
public static void main(String[] args) {
//动态代理对象:指的是在程序运行过程中动态通过代码的方式为指定的类生成动态代理对象
//proxy 用来生成动态代理的类

//目标对象 或 被代理对象
UserService userService = new UserServiceImpl();

//参数1:classLoader 类加载器
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();//当前线程类加载器

//参数2:Class[] 生成代理类的接口类型的数组 | 目标对象接口类型的数组

Class[] classes = {UserService.class};
//参数3:InvocationHandler接口类型,其中的invoke方法用来书写额外的附加功能
//通过代理类对象调用方法时会优先进入参数3中的invoke方法

//dao UserDAO userDAO = sqlSession.getMapper(userDAO.class); userDAO.save()=

//返回值proxy就是生成的动态代理对象
UserService proxy = (UserService)Proxy.newProxyInstance(classLoader, classes, new InvocationHandler() {
@Override
//通过动态代理对象调用自己里面代理方法会优先执行InvocationHandler类中的invoke
//参数1:proxy 当前创建好的代理对象
//参数2:method 当前代理对象执行的方法对象
//参数3:args 当前代理对象执行方法的参数
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//mapper文件xml save id=“save” sql+jdbc+pstm args mybatis底层实现原理是动态代理
System.out.println("当前执行的方法:" + method.getName());
System.out.println("当前执行的方法中的参数:" + args[0]);

try {
System.out.println("开启事务");//附加操作
//调用目标类中业务方法通过反射机制调用目标类中当前方法
Object invoke = method.invoke(new UserServiceImpl(),args);
System.out.println("提交事务");//附加操作
return invoke;
} catch (Exception e) {
System.out.println("回滚事务");//附加操作
e.printStackTrace();
}
return null;
}
});
System.out.println(proxy.getClass());
//通过动态代理对象调用代理中方法
String result = proxy.findAll("茶白");
System.out.println(result);
}
}

9.AOP

9.1 基本概念

AOP(Aspect Oriented Programming)编程:即 面向切面编程

其中:Aspect(切面)、Oriented(面向)、Programming(编程)

底层原理:java代理设计模式(动态代理)

好处:在保证原始业务逻辑不变的情况下,通过代理对象完成业务中的附加操作(如事务等),将业务中核心操作放在目标对象中执行,实现了附加操作和核心操作解耦。

1
2
3
4
5
6
7
8
9
10
//有了spring框架以后创建代理的过程不需要我们做了,已给我们做好了封装,只需把额外功能单独告诉即可
try{
System.out.println("开启事务");//额外功能|附加操作|专有名词:通知
Object invoke = method.invoke(new UserServiceImpl(),args);//真正目标方法执行
System.out.println("提交事务");//额外功能|附加操作|专有名词:通知
return invoke;
} catch (Exception e) {
System.out.println("回滚事务");//额外功能|附加操作|专有名词:通知
e.printStackTrace();
}

基本概念:

  • 通知(Advice):除了目标方法之外的操作都可以称之为通知,可理解为附加操作、额外功能,比如:事务通知、日志通知、性能通知……

    通知细分如下

    image-20240324144127597

  • 切入点(Pointcut):将开发好的通知应用于项目中的哪些组件中的哪些方法,给方法加入通知,一般通知多用于业务层,例如:UserService

  • 切面(Aspect)=通知(Advice)+切入点(Pointcut)

9.2AOP编程步骤

AOP面向切面编程:

  1. 给哪些类做附加功能,就根据附加功能开发通知类(附加功能)—新建通知

  2. 配置切入点 —指定通知位置

  3. 利用通知和切入点组装切面,对通知和切入点进行绑定 —组装切面(Apect)

    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
    //编程步骤
    # 1.引入AOP编程相关依赖
    spring-aop
    spring-expression
    spring-aspects

    # 2.开发通知类
    MethodInterceptor 环绕通知
    MethodBeforeAdvice 前置通知
    AfterReturningAdvice 后置通知 / 返回后通知
    ThrowsAdvice 异常通知

    MyAdvice implements 通知接口{.....}

    //自定义通知类:用来完成额外功能
    //自定义记录业务方法名称前置通知,前置通知即目标方法执行之前先执行的额外操作
    public class MyAdvice implements MethodBeforeAdvice {
    @Override
    //参数1:当前调用的方法对象
    //参数2:当前调用方法对象的参数
    //参数3:目标对象
    public void before(Method method, Object[] args, Object target) throws Throwable {
    System.out.println("目标方法名: "+method.getName());
    System.out.println("目标方法的参数: "+args[0]);
    System.out.println("目标对象: "+target.getClass());
    }
    }
    # 3.配置切面(在spring.xml)
    a.引入aop命名空间
    <?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:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    b.注册通知类
    <!--注册通知类-->
    <bean id="myAdvice" class="before.MyAdvice"/>
    c.配置/组装切面 aspect = advice + pointcut
    <!--组装切面-->
    <aop:config>
    <!--配置切入点pointcut
    id:切入点在工厂中的唯一标识
    expression:用来指定切入项目中哪些组件中哪些方法 execution(返回值 包名.类名.方法名(参数))
    *表示任意、所有
    -->
    <aop:pointcut id="pc" expression="execution(* aop.UserServiceImpl.*(..))"/>
    <!--配置切面 advice-ref:工厂中通知id pointcut-ref:工厂切入点唯一标识-->
    <aop:advisor advice-ref="myAdvice" pointcut-ref="pc"/>
    </aop:config>

    # 4.启动工厂测试
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("aop/spring.xml");
    UserService userSerivce = (UserService) context.getBean("userService");
    System.out.println(userSerivce.getClass());
    //代理对象
    userSerivce.save("小黑");

9.3前置通知使用

EmpService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
package aop;

/**
* @ClassName EmpService
* @Description 接口
* @Author chabai
* @Date 2022/4/4 18:36
* @Version 1.0
*/
public interface EmpService {
void save(String name);
String find(String name);
}

EmpServiceImpl.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package aop;
//原始业务对象 | 目标对象
/**
* @ClassName EmpServiceImpl
* @Description EmpService实现类 原始业务对象 / 目标对象
* @Author chabai
* @Date 2022/4/4 18:37
* @Version 1.0
*/
public class EmpServiceImpl implements EmpService{
@Override
public void save(String name) {
System.out.println("处理业务逻辑saveDao!" + name);
}

@Override
public String find(String name) {
System.out.println("处理业务逻辑findDAO!" + name);
return name;
}
}

MyBeforeAdvice.java自定义前置通知

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 package aop;
//自定义记录业务方法名称通知 前置通知:目标方法执行前先执行的额外操作
import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

/**
* @ClassName MyBeforeAdvice
* @Description 自定义记录业务方法名称的前置通知
* @Author chabai
* @Date 2022/4/4 18:46
* @Version 1.0
*/
public class MyBeforeAdvice implements MethodBeforeAdvice {
@Override
//before
//参数1:method表示当前执行方法的对象
//参数2:objects表示当前执行方法的参数
//参数3:o表示目标对象
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("当前执行方法的名称:" + method.getName());
}
}

spring.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
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--管理Service组件对象-->
<bean class="aop.EmpServiceImpl" id="empService"></bean>

<!--注册通知 | 管理BeforeAdvice组件-->
<bean class="aop.MyBeforeAdvice" id="myBeforeAdvice"></bean>

<!--组装切面-->
<aop:config>
<!--配置切入点 pointcut
id:切入点在工厂中的唯一标识
expression:用来指定切入项目中哪些组件中哪些方法 execution(返回值 包.类名.方法名(..))[固定写]
-->
<aop:pointcut id="pc" expression="execution(* aop.*ServiceImpl.*(..))"/>
<!--配置切面 advisor
advice-ref:工厂中通知id
pointcut-ref:工厂切入点唯一标识
-->
<aop:advisor advice-ref="myBeforeAdvice" pointcut-ref="pc"/>
</aop:config>
</beans>

TestSpring.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package aop;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
* @ClassName TestSpring
* @Description 测试
* @Author chabai
* @Date 2022/4/4 20:49
* @Version 1.0
*/
public class TestSpring {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("aop/spring.xml");
EmpService empService = (EmpService)context.getBean("empService");
System.out.println(empService.getClass());
//此时的EmpService不再是单纯的类,而是动态代理类
empService.save("茶白");
}
}

输出结果:

1
2
3
class com.sun.proxy.$Proxy2
当前执行方法的名称:save
处理业务逻辑saveDao!茶白

9.4 环绕通知的使用

9.4.1编程思想

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#1.引入aop相关依赖
spring-aop spring-apsect spring-expression(切入点表达式)

#2.开发业务组件
DeptDAO
DeptDAOImpl
DeptService
DeptServiceImpl

#3.开发环绕通知
性能通知:计算业务层目标方法执行时长

#4.配置spring.xml
a.管理业务DAO组件
b.配置切面
1.注册通知
2.配置切面

9.4.2代码实测

DeptDAO.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package dao;

/**
* @ClassName DeptDAO
* @Description TODO
* @Author chabai
* @Date 2022/4/5 20:58
* @Version 1.0
*/
public interface DeptDAO {
void save(String name);
void update(String name);
void delete(Integer id);
String find(String name);
}

DeptDAOImpl.java

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
package dao;

/**
* @ClassName DeptDAOImpl
* @Description TODO
* @Author chabai
* @Date 2022/4/5 20:59
* @Version 1.0
*/
public class DeptDAOImpl implements DeptDAO{
@Override
public void save(String name) {
System.out.println("save DAO :" + name);
}

@Override
public void update(String name) {
System.out.println("update DAO :" + name);
}

@Override
public void delete(Integer id) {
System.out.println("delete DAO :" + id);
}

@Override
public String find(String name) {
System.out.println("find DAO :" + name);
return name;
}
}

DeptService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package service;

/**
* @ClassName DeptService
* @Description TODO
* @Author chabai
* @Date 2022/4/5 21:02
* @Version 1.0
*/
public interface DeptService {
void save(String name);
void update(String name);
void delete(Integer id);
String find(String name);
}

DeptServiceImpl.java

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
 package service;
//业务层组件
import dao.DeptDAO;

/**
* @ClassName DeptServiceImpl
* @Description 业务层组件
* @Author chabai
* @Date 2022/4/5 21:03
* @Version 1.0
*/
public class DeptServiceImpl implements DeptService{
//业务层需要DAO组件,就把DAO声明为成员变量,并提供公开的set方法
private DeptDAO deptDAO;
public void setDeptDAO(DeptDAO deptDAO) {
this.deptDAO = deptDAO;
}

@Override
public void save(String name) {
System.out.println("处理save业务逻辑!");
deptDAO.save(name);
}

@Override
public void update(String name) {
System.out.println("处理update业务逻辑!");
deptDAO.update(name);
}

@Override
public void delete(Integer id) {
System.out.println("处理delete业务逻辑!");
deptDAO.delete(id);
}

@Override
public String find(String name) {
System.out.println("处理find业务逻辑!");
deptDAO.find(name);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//throw new RuntimeException("执行出错啦!");
return null;
}
}

MethodInvokeTimeAdvice.java自定义环绕通知用来记录目标方法的执行时长

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
package advices;
//自定义环绕通知用来记录目标方法的执行时长
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import java.util.Date;

/**
* @ClassName MethodInvokeTimeAdvice
* @Description 自定义环绕通知用来记录目标方法的执行时长
* @Author chabai
* @Date 2022/4/5 21:17
* @Version 1.0
*/
public class MethodInvokeTimeAdvice implements MethodInterceptor {
@Override
//参数:methodInvocation将invoke之前的参数封装到一个参数里,
//可通过该参数获得当前执行的方法、当前执行的方法参数、目标对象、放行目标方法的执行
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
//调入目标方法先进入这里,如果放行继续执行,如果不放行到这里就结束了
System.out.println("进入环绕通知......");
System.out.println("当前执行方法:" + methodInvocation.getMethod().getName());
System.out.println("当前执行方法的参数:" + methodInvocation.getArguments()[0]);
System.out.println("当前执行的目标对象:" + methodInvocation.getThis());
try {
long start = new Date().getTime();
//放行目标方法:返回值为目标方法返回值,这个返回值一定要在通知中返回
Object proceed = methodInvocation.proceed();//继续处理
long end = new Date().getTime();
System.out.println(methodInvocation.getMethod().getName() + "方法执行了" + (end-start) + "ms!");
return proceed;
} catch (Exception e) {
e.printStackTrace();
System.out.println("出现异常时业务处理");
}
return null;
}
}

spring.xml配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--管理DAO组件-->
<bean class="dao.DeptDAOImpl" id="deptDAO"/>

<!--管理Service组件-->
<bean class="service.DeptServiceImpl" id="deptService">
<property name="deptDAO" ref="deptDAO"/>
</bean>

<!--注册通知类-->
<bean class="advices.MethodInvokeTimeAdvice" id="methodInvokeTimeAdvice"/>

<!--配置切面-->
<aop:config>
<!--配置切入点-->
<aop:pointcut id="pc" expression="execution(* service.*ServiceImpl.*(..))"/>
<!--组装切面-->
<aop:advisor advice-ref="methodInvokeTimeAdvice" pointcut-ref="pc"/>
</aop:config>
</beans>

环绕通知测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import service.DeptService;

/**
* @ClassName TestDeptService
* @Description 测试环绕通知
* @Author chabai
* @Date 2022/4/5 21:32
* @Version 1.0
*/
public class TestDeptService {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
DeptService deptService = (DeptService) context.getBean("deptService");
System.out.println(deptService.getClass());
deptService.find("茶白");
}
}

输出结果:

(1)正常执行时

1
2
3
4
5
6
7
8
class com.sun.proxy.$Proxy2
进入环绕通知......
当前执行方法:find
当前执行方法的参数:茶白
当前执行的目标对象:service.DeptServiceImpl@5ad851c9
处理find业务逻辑!
find DAO :茶白
find方法执行了1000ms!

(2)执行出错时

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class com.sun.proxy.$Proxy2
进入环绕通知......
当前执行方法:find
当前执行方法的参数:茶白
当前执行的目标对象:service.DeptServiceImpl@5ad851c9
处理find业务逻辑!
find DAO :小崔
java.lang.RuntimeException: 执行出错啦!
at service.DeptServiceImpl.find(DeptServiceImpl.java:47)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at advices.MethodInvokeTimeAdvice.invoke(MethodInvokeTimeAdvice.java:27)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
at com.sun.proxy.$Proxy2.find(Unknown Source)
at test.TestDeptService.main(TestDeptService.java:19)
出现异常时业务处理

9.5后置通知与异常通知使用

UserService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
package service;

/**
* @ClassName UserService
* @Description TODO
* @Author chabai
* @Date 2022/4/6 17:34
* @Version 1.0
*/
public interface UserService {
String save(String name);
}

UserServiceImpl.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 
package service;

/**
* @ClassName UserServiceImpl
* @Description TODO
* @Author chabai
* @Date 2022/4/6 17:34
* @Version 1.0
*/
public class UserServiceImpl implements UserService{
@Override
public String save(String name) {
System.out.println("UserService save" + name);
return name;
}
}

自定义后置通知和异常通知MyAfterAndThrowsAdvice.java

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
package advices;

import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.ThrowsAdvice;

import java.lang.reflect.Method;

/**
* @ClassName MyAfterAndThrowsAdvice
* @Description 自定义后置通知和异常通知
* @Author chabai
* @Date 2022/4/6 17:36
* @Version 1.0
*/
public class MyAfterAndThrowsAdvice implements AfterReturningAdvice, ThrowsAdvice {
@Override
//后置通知
//主体逻辑:此中的过程将在核心业务执行之后执行
//参数1:目标方法返回值 如果方法返回值时void,返回值为null
//参数2:当前执行方法对象
//参数3:执行方法参数
//参数4:目标对象
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("进入后置通知...");
System.out.println("返回值:" + returnValue);
System.out.println("当前执行方法对象:" + method.getName());
System.out.println("当前执行方法的参数:" + args[0]);
System.out.println("目标对象:" + target);
}

//出现异常时执行通知处理
//注意:异常通知继承了后置通知,虽然实现该接口时不用实现方法,但最好实现afterThrowing方法,以免异常报错
//主体逻辑:此中的过程将在核心业务出现异常之后执行
//参数1:当前执行方法对象
//参数2:执行方法参数
//参数3:目标对象
//参数4:目标抛出的异常
public void afterThrowing(Method method, Object[] args, Object target, Exception ex){
System.out.println("进入异常通知.......");
System.out.println("方法名: " + method.getName());
System.out.println("方法的参数: " + args[0]);
System.out.println("目标对象: " + target);
System.out.println("异常信息: "+ ex.getMessage());
}

//注意:两者不能同时工作
}

spring.xml配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--管理Service组件-->
<bean class="service.UserServiceImpl" id="userService"/>

<!--注册通知类-->
<bean class="advices.MyAfterAndThrowsAdvice" id="myAfterAndThrowsAdvice"/>

<!--组装切面-->
<aop:config>
<aop:pointcut id="pc" expression="execution(* service.*ServiceImpl.*(..))"/>
<aop:advisor advice-ref="myAfterAndThrowsAdvice" pointcut-ref="pc"/>
</aop:config>
</beans>

测试自定义后置通知和异常通知MyAfterAndThrowsAdviceTest.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import service.UserService;

/**
* @ClassName MyAfterAndThrowsAdviceTest
* @Description 测试自定义后置通知和异常通知
* @Author chabai
* @Date 2022/4/6 17:47
* @Version 1.0
*/
public class MyAfterAndThrowsAdviceTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("after/spring.xml");
UserService userService = (UserService) context.getBean("userService");
System.out.println(userService.getClass());
userService.save("茶白");
}
}

测试结果:

(1)正常执行时,后置通知起作用

1
2
3
4
5
6
7
8
class com.sun.proxy.$Proxy2
UserService save 茶白
进入后置通知...
返回值:茶白
当前执行方法对象:save
当前执行方法的参数:茶白
目标对象:service.UserServiceImpl@17c1bced

(2)抛出异常时,异常通知起作用

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
class com.sun.proxy.$Proxy2
UserService save 茶白
进入异常通知.......
方法名: save
方法的参数: 茶白
目标对象: service.UserServiceImpl@2d9d4f9d
异常信息: save方法执行出错啦
Exception in thread "main" java.lang.RuntimeException: save方法执行出错啦
at service.UserServiceImpl.save(UserServiceImpl.java:15)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.aop.framework.adapter.ThrowsAdviceInterceptor.invoke(ThrowsAdviceInterceptor.java:125)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:52)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
at com.sun.proxy.$Proxy2.save(Unknown Source)
at test.MyAfterReturningAdviceTest.main(MyAfterReturningAdviceTest.java:19)

Process finished with exit code 1

9.6切入点表达表(这里讲解常用的两种)

spring (pointcut)切入点表达式作用:主要是用来决定项目中那些组件中那些方法需要加入通知

如果切入点表达式切中了这个组件,且这个组件在运行时配置了切面的话,拿到的就是代理对象,通过代理调用方法时就会进入相应的前置,后置,环绕,异常通知。

1.execution方法级别

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
execution 切入点表达式   --->方法级别的切入点表达式  控制粒度: 方法级别   效率低
格式:expression="切入点表达式"
完整语法:
1.execution(访问权限修饰符 返回值 包名.类名.方法名(参数类型))
2.execution(返回值 包名.类名.方法名(参数类型)),默认public访问,因此可以省略访问修饰符
* 任意多个字符
..作用于参数类型:表示任意多个
作用于类:表示当前包及子包
1).execution(* com.baizhi.service.*.*(..)) [比较多一种]
包: com.baizhi.service
类: 任意类
方法: 任意方法
参数: 参数任意
返回值: 任意返回值类型
2).execution(String com.baizhi.service.*ServiceImpl.*(..))
包: com.baizhi.service
类: 以ServiceImpl结尾的类
方法: 方法名任意
参数: 任意参数
返回值: 返回值必须String类型相关方法
3).execution(String com.baizhi.service.*Service*.*(String))
包: com.baizhi.service
类: 类名中包含Service关键字的类
方法: 任意
参数: 参数只有一个类型必须是String
返回值: 返回值必须是String
4).execution(* com.baizhi.service..*.*(..)) [比较多一种]
包: com.baizhi.service及这个包中子包的子包
类: 任意类
方法: 任意方法
参数: 任意参数
返回值: 任意类型
5).execution(* com.baizhi.service.*ServiceImpl.*(..)) [比较多一种]
包: com.baizhi.service 包
类: 以ServiceImpl结尾的类
方法: 任意方法
参数: 任意参数
返回值: 任意类型
6).execution(* *.*(..)) //全部方法 避免使用这种方式
包: 项目中所有包
类: 项目中所有类
方法: 所有方法
参数: 所有参数
返回值: 任意类型

注意: 方法级别的切入点表达式尽可能精准,避免不必要的切入,否则程序运行可能出现异常

2.within类级别

1
2
3
4
5
6
7
8
9
10
11
12
13
within    切入点表达式   --->类级别的切入点表达式    控制粒度: 类级别    效率高  推荐
格式:expression="within()"
完整语法:
1. within(包.类名)
1).within(com.baizhi.service.*ServiceImpl)
包:com.baizhi.service
类:以ServiceImpl结尾的类
2)within(com.baizhi.service.*)
包: com.baizhi.service
类: 所有类中所有方法不关心返回值和参数
3)within(com.baizhi.service.UserServiceImpl)
包: com.baizhi.service
类: UserServiceImpl类中所有方法不关心返回值和参数

注意:within的效率高于execution表达式,推荐使用within表达式,切入到方法级别时在使用execution表达式

10.IOC和AOP回顾

spring 框架核心

image-20240324150210561

11.spring创建复杂对象方式

复杂对象:类中没有构造方法或者构造方法不能调用,如接口类型或抽象类实例

img

新建Maven-webapp工程,添加java、resources目录

pom.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
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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>org.example</groupId>
<artifactId>spring03</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>

<name>spring03 Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>

<!--spring核心及相关依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>

<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>

<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.4</version>
</dependency>

<!--mybatis-spring-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.4</version>
</dependency>

<!--druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.19</version>
</dependency>

</dependencies>

<build>
<finalName>spring03</finalName>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>

1 .抽象类Calendar

CalendarFactoryBean.java

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
package factorybean;

import org.springframework.beans.factory.FactoryBean;

import java.util.Calendar;

/**
* @ClassName CalendarFactoryBean
* @Description 用来在工厂中创建复杂对象Calendar
* @Author chabai
* @Date 2022/4/7 21:33
* @Version 1.0
*/
public class CalendarFactoryBean implements FactoryBean<Calendar> {
//用来书写复杂对象的创建方式
@Override
public Calendar getObject() throws Exception {
return Calendar.getInstance();
}

//指定创建的复杂对象类型
@Override
public Class<?> getObjectType() {
return Calendar.class;
}

//用来指定创建的对象模式 true表示单例,false表示多例
@Override
public boolean isSingleton() {
return true;
}
}

spring.xml

1
2
3
4
5
6
7
<?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 class="factorybean.CalendarFactoryBean" id="calendar"/>
</beans>

CalendarTest.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.Calendar;

/**
* @ClassName CalendarTest
* @Description TODO
* @Author chabai
* @Date 2022/4/7 21:39
* @Version 1.0
*/
public class CalendarTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("factorybean/spring.xml");
Calendar calendar = (Calendar) context.getBean("calendar");
System.out.println(calendar);
Calendar calendar1 = (Calendar) context.getBean("calendar");
System.out.println(calendar1);
System.out.println(calendar==calendar1);
}
}

2.接口Connection

ConnectionFactoryBean.java

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
package factorybean;

import org.springframework.beans.factory.FactoryBean;

import java.sql.Connection;
import java.sql.DriverManager;

/**
* @ClassName ConnectionFactoryBean
* @Description 用工厂创建复杂对象Connection
* @Author chabai
* @Date 2022/4/7 21:43
* @Version 1.0
*/
public class ConnectionFactoryBean implements FactoryBean<Connection> {
@Override
public Connection getObject() throws Exception {
Class.forName("com.mysql.jdbc.Driver");
return DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis","root","123456");
}

@Override
public Class<?> getObjectType() {
return Connection.class;
}

@Override
public boolean isSingleton() {
return false;
}
}

spring.xml

1
<bean class="factorybean.ConnectionFactoryBean" id="connection"/>

ConnectionTest.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.sql.Connection;

/**
* @ClassName ConnectionTest
* @Description TODO
* @Author chabai
* @Date 2022/4/7 21:48
* @Version 1.0
*/
public class ConnectionTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("factorybean/spring.xml");
Connection connection = (Connection) context.getBean("connection");
System.out.println(connection);
Connection connection1 = (Connection) context.getBean("connection");
System.out.println(connection1);
System.out.println(connection==connection1);
}
}

12.spring整合mybatis

12.1SM整合思路分析

整合思路: 两个框架作用不同,貌似没有什么联系,更深入看才能看出所谓Spring整合Mybatis,其实就是通过spring框架接管mybatis框架中核心对象的创建

1.总体示意图:

img2.Spring整合Mybatis思路分析:

img

3.Spring整合Mybatis编程步骤:

img4.具体实现

不用我们再自定义创建SqlSessionFactoryBean,Mybatis官方已封装好了,导入jar包即可

(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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
<!--spring核心及相关依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>

<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>

<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.4</version>
</dependency>

<!--mybatis-spring-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.4</version>
</dependency>

<!--druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.19</version>
</dependency>

(2)配置spring.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!--创建sqlSessionFactory对象-->
<bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactory">
<!--依赖数据源对象-->
<property name="dataSource" ref="dataSource"/>
<!--依赖mapper文件注册这里不用写,只是为了完整-->
<property name="mapperLocations">
<array>
<value>......</value>
<value>......</value>
<value>......</value>
</array>
</property>
</bean>

<!--创建数据源对象druid,需要引入druid依赖,类似的数据源还有C3p0、dbcp等-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>

(3)测试SqlSessionFactory是否创建成功

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package test;

import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
* @ClassName SqlSessionFactoryTest
* @Description 测试SqlSessionFactory是否创建成功
* @Author chabai
* @Date 2022/4/8 16:59
* @Version 1.0
*/
public class SqlSessionFactoryTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("factorybean/spring.xml");
SqlSessionFactory sqlSessionFactory = (SqlSessionFactory) context.getBean("sqlSessionFactory");
System.out.println(sqlSessionFactory);

}
}

结果:

1
org.apache.ibatis.session.defaults.DefaultSqlSessionFactory@2d2e5f00

12.2SM整合DAO编程开发

1.整合思路

SM整合编码之DAO层思路分析流程:

img

SM整合之DAO层编程步骤:

img

2.实现

1 引入mybatis的依赖jar包

1
2
3
4
5
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.2.8</version>
</dependency>

2 引入Spring相关jar包

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
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>

3 mybatis-spring整合jar

1
2
3
4
5
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>

4 引入数据库驱动jar

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.40</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.12</version>
</dependency>

5 建表

1
2
3
4
5
6
7
CREATE TABLE `t_user` (
`id` varchar(40) NOT NULL,
`name` varchar(40) DEFAULT NULL,
`age` int(3) DEFAULT NULL,
`bir` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

6 编写实体类

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
package entity;

import java.util.Date;

/**
* @ClassName User
* @Description TODO
* @Author chabai
* @Date 2022/4/8 17:44
* @Version 1.0
*/
public class User {
private String id;
private String name;
private Integer age;
private Date bir;

public User() {
}

public User(String id, String name, Integer age, Date bir) {
this.id = id;
this.name = name;
this.age = age;
this.bir = bir;
}

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}

public Date getBir() {
return bir;
}

public void setBir(Date bir) {
this.bir = bir;
}

@Override
public String toString() {
return "User{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", age=" + age +
", bir=" + bir +
'}';
}
}

7 书写DAO接口

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
package dao;

import entity.User;

import java.util.List;

/**
* @ClassName UserDAO
* @Description TODO
* @Author chabai
* @Date 2022/4/8 17:46
* @Version 1.0
*/
public interface UserDAO {
//根据id查询用户信息
User findById(String id);

//查询所有用户信息
List<User> findAll();

//新增用户
void insert(User user);

//根据id修改用户
void update(User user);

//根据id删除用户
void delete(String id);
}

8 编写mapper配置文件

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
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<!--
mapper为映射的根节点,用来管理DAO接口
namespace指定DAO接口的完整类名,表示mapper配置文件管理哪个DAO接口(包.接口名)
mybatis会依据这个接口动态创建一个实现类去实现这个接口,而这个实现类是一个Mapper对象
-->
<mapper namespace="dao.UserDAO">
<!--
id = "接口中的方法名"
parameterType = "接口中传入方法的参数类型"
resultType = "返回实体类对象:包.类名" 处理结果集 自动封装
注意:sql语句后不要出现";"号
查询:select标签
增加:insert标签
修改:update标签
删除:delete标签
-->
<!--根据id查询用户信息-->
<select id="findById" parameterType="String" resultType="entity.User">
select id,name,age,bir from t_user where id=#{id}
</select>

<!--查询所有用户信息-->
<select id="findAll" resultType="entity.User">
select id,name,age,bir from t_user
</select>

<!--新增用户-->
<insert id="insert" parameterType="entity.User">
insert into t_user values(#{id},#{name},#{age},#{bir});
</insert>

<!--根据id修改用户-->
<update id="update" parameterType="entity.User">
update t_user set name=#{name},age=#{age},bir=#{bir} where id=#{id}
</update>

<!--根据id删除用户-->
<delete id="delete" parameterType="String">
delete from t_user where id=#{id}
</delete>

</mapper>

9 编写Spring-myabtis整合配置文件spring.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
<?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">

<!--创建sqlSessionFactory-->
<bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactory">
<!--依赖数据源-->
<property name="dataSource" ref="dataSource"/>
<!--注入mapper配置文件-->
<property name="mapperLocations">
<array>
<!--依次注册mapper-->
<value>classpath:mapper/UserDAOMapper.xml</value>
</array>
</property>
</bean>

<!--创建dataSource-->
<bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>

<!--创建DAO组件类-->
<bean class="org.mybatis.spring.mapper.MapperFactoryBean" id="userDAO">
<!--注入SqlSessionFactory-->
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
<!--注入创建的DAO接口类型(接口的全限定名:包名.接口名)-->
<property name="mapperInterface" value="dao.UserDAO"/>
</bean>

</beans>

10 启动工厂测试

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
package test;


import dao.UserDAO;
import entity.User;
import org.apache.ibatis.session.SqlSessionFactory;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
* @ClassName UserDAOTest
* @Description TODO
* @Author chabai
* @Date 2022/4/8 17:55
* @Version 1.0
*/
public class UserDAOTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
//SqlSessionFactory sqlSessionFactory = (SqlSessionFactory) context.getBean("sqlSessionFactory");
//SqlSession sqlSession = sqlSessionFactory.openSession();
//System.out.println(sqlSession);
//UserDAO userDAO = sqlSession.getMapper(UserDAO.class);
//mybatis-spring jar MapperFactoryBean 创建DAO对象一个类
// 1.依赖于SqlSessionFactory 2.依赖创建DAO全限定名
UserDAO userDAO = (UserDAO) context.getBean("userDAO");
List<User> users = userDAO.findAll();
users.forEach(user-> System.out.println("user = " + user));
}

@Test
public void findByIdTest(){
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
UserDAO userDAO = (UserDAO) context.getBean("userDAO");
User user1 = userDAO.findById("1");
System.out.println("user1 = " + user1);
}

@Test
public void findAllTest(){
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
UserDAO userDAO = (UserDAO) context.getBean("userDAO");
List<User> users = userDAO.findAll();
users.forEach(user -> System.out.println("user = " + user));
}

@Test
public void insertTest(){
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
UserDAO userDAO = (UserDAO) context.getBean("userDAO");
String id = UUID.randomUUID().toString();
userDAO.insert(new User(id,"lisi",60,new Date()));
}

@Test
public void updateTest(){
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
UserDAO userDAO = (UserDAO) context.getBean("userDAO");
userDAO.update(new User("4","wangwu",25,new Date()));
}

@Test
public void deleteTest(){
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
UserDAO userDAO = (UserDAO) context.getBean("userDAO");
userDAO.delete("4");
}
}

3.补充:SM整合编码之DAO细节优化

img

即:

(1)mapper配置文件注入方式

a. 以数组形式单个注入

1
2
3
4
5
6
<property name="mapperLocations">
<array>
<!--依次注册mapper-->
<value>classpath:mapper/UserDAOMapper.xml</value>
</array>
</property>

b. 通用mapper配置文件扫描注入(推荐使用) 通配符

1
<property name="mapperLocations" value="classpath:mapper/*.xml"/>

+ 补充:起别名

1
2
3
4
5
6
7
8
9
10
11
12
13
<!--
在创建sqlSessionFactory 时 别名一块注入
注入别名相关配置typeAliasesPackage:用来给指定包中所有类起别名
默认的别名:类名/类名首字母小写
-->
<!--指定包:entity包下所有类-->
<property name="typeAliasesPackage" value="com.chabai.entity"/>
<!--指定类-->
<property name="typeAliases">
<array>
<value>com.chabai.entity.User</value> <!--类名/类名首字母小写-->
</array>
</property>

(2)创建DAO组件类

a. 单个注入

1
2
3
4
5
6
<bean class="org.mybatis.spring.mapper.MapperFactoryBean" id="userDAO">
<!--注入SqlSessionFactory-->
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
<!--注入创建的DAO接口类型(接口的全限定名:包名.接口名)-->
<property name="mapperInterface" value="com.chabai.dao.UserDAO"/>
</bean>

b. 一次性注入所有(推荐使用)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!--
一次项目创建项目中所有DAO对象
MapperScannerConfigurer:
默认创建对象在工厂中的唯一标识为接口首字母小写
例如:UserDAO->userDAO Userdao->userdao
OrderDAO->orderDAO Orderdao->orderdao
EmpDAO->empDAO
-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--注入SqlSessionFactory对象-->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
<!--扫描DAO接口所在包-->
<property name="basePackage" value="com.chabai.dao"/>
</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
<!--创建dataSource-->
<bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>

<!--创建sqlSessionFactory-->
<bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactory">
<!--依赖数据源-->
<property name="dataSource" ref="dataSource"/>
<!--通用mapper配置文件扫描注入,推荐使用-->
<property name="mapperLocations" value="classpath:mapper/*.xml"/>
<!--
注入别名相关配置typeAliasesPackage:用来给指定包中所有类起别名
默认的别名:类名/类名首字母小写
-->
<!--指定包-->
<property name="typeAliasesPackage" value="entity"/>
</bean>

<!--创建DAO组件类:一次项目创建项目中所有DAO对象-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--注入SqlSessionFactory对象-->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
<!--扫描DAO接口所在包-->
<property name="basePackage" value="dao"/>
</bean>

12.3SM整合Service层事务控制

1.整合思路

SM整合之Service层事务控制思路分析:

img

SM整合DAO和Service部分编程步骤:

img

2. 具体实现:

开发Service接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package service;

import entity.User;

import java.util.List;

/**
* @ClassName UserService
* @Description TODO
* @Author chabai
* @Date 2022/4/9 17:13
* @Version 1.0
*/
public interface UserService {
//查询所有用户
List<User> findAll();

//插入用户数据
void insert(User user);
}

开发Service实现类

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
package service;

import dao.UserDAO;
import entity.User;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import java.util.List;
import java.util.UUID;

/**
* @ClassName UserServiceImpl
* @Description TODO
* @Author chabai
* @Date 2022/4/9 17:14
* @Version 1.0
*/
public class UserServiceImpl implements UserService{
//Service层需要调用DAO层
private UserDAO userDAO;

public void setUserDAO(UserDAO userDAO) {
this.userDAO = userDAO;
}

//生成事务管理器
private PlatformTransactionManager platformTransactionManager;

public void setPlatformTransactionManager(PlatformTransactionManager platformTransactionManager) {
this.platformTransactionManager = platformTransactionManager;
}

//查询所有用户信息
//注意:查询不需要事务管理
@Override
public List<User> findAll() {
return userDAO.findAll();
}

//插入用户信息
//注意:增删改需要事务管理
@Override
public void insert(User user) {
//int i = 1/0;
// 控制事务:创建事务配置对象
TransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
//获取事务状态
TransactionStatus status = platformTransactionManager.getTransaction(transactionDefinition);
try {
//处理业务
user.setId(UUID.randomUUID().toString());
//调用业务
//注意:在DAO层进行数据库增删改时,也能操作成功的原因是因为DAO层提供了方法测试的小事务,方便测试DAO
// 当外部存在事务时,小事务自动消失
userDAO.insert(user);
platformTransactionManager.commit(status);
} catch (Exception e) {
e.printStackTrace();
platformTransactionManager.rollback(status);
}

}
}

编写spring.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
<!--配置数据源事务管理器-->
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager">
<!--注入数据源对象 DataSource-->
<property name="dataSource" ref="dataSource"/>
</bean>

<!--管理Service组件-->
<bean class="service.UserServiceImpl" id="userService">
<!--Service组件需要DAO组件,需要注入-->
<property name="userDAO" ref="userDAO"/>
<!--需要在Service进行事务管理-->
<property name="platformTransactionManager" ref="transactionManager"/>
</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
package test;

import entity.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import service.UserService;

import java.util.Date;

/**
* @ClassName UserServiceTest
* @Description TODO
* @Author chabai
* @Date 2022/4/9 17:41
* @Version 1.0
*/
public class UserServiceTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
UserService userService = (UserService) context.getBean("userService");
//System.out.println(userService.getClass());
userService.insert(new User(null,"小超超",36,new Date()));
userService.findAll().forEach(user -> System.out.println("user = " + user));
}
}

12.4SM整合回顾

img

12.5SM整合Service层事务优化思路分析

1.思路分析

spring中的两种事务管理方式:

img

spring中声明式事务分析思路:

img

2.实现

在spring-mybatis.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
<!--管理Service组件-->
<bean class="service.UserServiceImpl" id="userService">
<!--Service组件需要DAO组件,需要注入-->
<property name="userDAO" ref="userDAO"/>
<!--Service组件原有的事务管理移出-->
</bean>

<!--创建数据源事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源对象 DataSource-->
<property name="dataSource" ref="dataSource"/>
</bean>

<!--配置事务属性
tx:advice标签
id: 基于事务管理器创建的环绕通知对象在工厂中唯一标识
作用:
1.根据指定的事务管理器在工厂中创建一个事务的环绕通知对象
2.对业务层方法进行细粒度事务控制
transactionManager:指定事务管理器是谁
-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--事务细粒度配置-->
<tx:attributes>
<!--*表示任意,此处针对增删改方法添加事务管理-->
<tx:method name="insert*"/>
<tx:method name="delete*"/>
<tx:method name="update*"/>
</tx:attributes>
</tx:advice>

<!--配置事务切面-->
<aop:config>
<!--指定切点-->
<aop:pointcut id="pc" expression="within(service.*ServiceImpl)"/>
<!--绑定切面-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pc"/>
</aop:config>

配置图示

img

优化UserServiceImpl实现类

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
package service;

import dao.UserDAO;
import entity.User;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import java.util.List;
import java.util.UUID;

/**
* @ClassName UserServiceImpl
* @Description TODO
* @Author chabai
* @Date 2022/4/9 17:14
* @Version 1.0
*/
public class UserServiceImpl implements UserService{
//Service层需要调用DAO层
private UserDAO userDAO;

public void setUserDAO(UserDAO userDAO) {
this.userDAO = userDAO;
}

/**
* @MethodName findAll
* @Description 查询所有用户信息,查询不需要事务管理
* @return: java.util.List<entity.User>
* @Author chabai
* @Date 2022/4/11 21:31
*/
@Override
public List<User> findAll() {
return userDAO.findAll();
}


/**
* @MethodName insert
* @Description 插入用户信息,需要事务管理
* @param: user
* @Author chabai
* @Date 2022/4/11 21:29
*/
@Override
public void insert(User user) {
//处理业务
user.setId(UUID.randomUUID().toString());
//调用业务
//注意:在DAO层进行数据库增删改时,也能操作成功的原因是因为DAO层提供了方法测试的小事务,方便测试DAO
// 当外部存在事务时,小事务自动消失
userDAO.insert(user);
//int i = 1/0;//测试异常
}
}

启动测试

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
package test;

import entity.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import service.UserService;

import java.util.Date;

/**
* @ClassName UserServiceTest
* @Description TODO
* @Author chabai
* @Date 2022/4/9 17:41
* @Version 1.0
*/
public class UserServiceTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
UserService userService = (UserService) context.getBean("userService");
//System.out.println(userService.getClass());
//insert
userService.insert(new User(null,"小胖墩",3,new Date()));
//findAll
userService.findAll().forEach(user -> System.out.println("user = " + user));
}
}

测试结果:

(1)不注释int i = 1/0;数据插入不成功

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Exception in thread "main" java.lang.ArithmeticException: / by zero
at service.UserServiceImpl.insert(UserServiceImpl.java:63)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:280)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
at com.sun.proxy.$Proxy9.insert(Unknown Source)
at test.UserServiceTest.main(UserServiceTest.java:23)

(2)注释掉int i = 1/0;数据插入成功

1
2
3
4
5
6
7
8
9
10
11
user = User{id='1', name='张三', age=10, bir=Fri Apr 01 00:00:00 CST 2022}
user = User{id='2', name='李四', age=20, bir=Sat Apr 02 00:00:00 CST 2022}
user = User{id='2f278828-6422-432d-ab1b-a727b33c23bc', name='小胖墩', age=3, bir=Mon Apr 11 21:43:57 CST 2022}
user = User{id='3', name='王五', age=30, bir=Sun Apr 03 00:00:00 CST 2022}
user = User{id='4', name='灰太狼', age=60, bir=Sun Apr 10 09:56:17 CST 2022}
user = User{id='5', name='小超超', age=36, bir=Sun Apr 10 09:55:41 CST 2022}
user = User{id='6', name='小呆呆', age=60, bir=Sun Apr 10 09:55:43 CST 2022}
user = User{id='7', name='小超超', age=36, bir=Sun Apr 10 09:55:44 CST 2022}
user = User{id='8', name='胖嘟嘟', age=50, bir=Sun Apr 10 09:55:39 CST 2022}
user = User{id='9', name='茶白', age=25, bir=Sun Apr 10 09:55:52 CST 2022}
user = User{id='e3863fd3-173c-46f4-a753-c72f7c92ad56', name='小猫咪', age=3, bir=Mon Apr 11 21:36:31 CST 2022}

12.6 SM最终开发步骤

img

junit中注解的使用

@Before @Test @After

12.7log4j日志使用

img

pom.xml中添加依赖:

1
2
3
4
5
6
7
8
9
10
11
12
13
<!--log4j依赖-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.0.2</version>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
</dependency>
</dependencies>

在src-main-resources下新建log4j.properties:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
## 根日志
## 日志级别
log4j.rootLogger=ERROR,stdout
## 输出位置
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
## 布局
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
## 格式
log4j.appender.stdout.layout.conversionPattern=[%p] %d{yyyy-MM-dd} %m%n

## 子日志
## 日志级别
log4j.logger.dao=DEBUG
## 监听spring框架的日志级别
log4j.logger.org.springframework=ERROR

测试结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[DEBUG] 2022-04-12 ==>  Preparing: insert into t_user values(?,?,?,?); 
[DEBUG] 2022-04-12 ==> Parameters: 8a3e8ab8-5abc-44e1-9aec-31f3978d97f2(String), 小胖墩(String), 3(Integer), 2022-04-12 10:23:32.991(Timestamp)
[DEBUG] 2022-04-12 <== Updates: 1
[DEBUG] 2022-04-12 ==> Preparing: select id,name,age,bir from t_user
[DEBUG] 2022-04-12 ==> Parameters:
[DEBUG] 2022-04-12 <== Total: 14
user = User{id='1', name='张三', age=10, bir=Fri Apr 01 00:00:00 CST 2022}
user = User{id='2', name='李四', age=20, bir=Sat Apr 02 00:00:00 CST 2022}
user = User{id='2f278828-6422-432d-ab1b-a727b33c23bc', name='小胖墩', age=3, bir=Mon Apr 11 21:43:57 CST 2022}
user = User{id='3', name='王五', age=30, bir=Sun Apr 03 00:00:00 CST 2022}
user = User{id='4', name='灰太狼', age=60, bir=Sun Apr 10 09:56:17 CST 2022}
user = User{id='5', name='小超超', age=36, bir=Sun Apr 10 09:55:41 CST 2022}
user = User{id='586a5f71-836c-4171-a038-4620fe0f9354', name='葫芦娃', age=5, bir=Tue Apr 12 09:45:17 CST 2022}
user = User{id='6', name='小呆呆', age=60, bir=Sun Apr 10 09:55:43 CST 2022}
user = User{id='7', name='小超超', age=36, bir=Sun Apr 10 09:55:44 CST 2022}
user = User{id='8', name='胖嘟嘟', age=50, bir=Sun Apr 10 09:55:39 CST 2022}
user = User{id='8a3e8ab8-5abc-44e1-9aec-31f3978d97f2', name='小胖墩', age=3, bir=Tue Apr 12 10:23:33 CST 2022}
user = User{id='9', name='茶白', age=25, bir=Sun Apr 10 09:55:52 CST 2022}
user = User{id='cd280176-68b2-4ceb-b781-ba2f5e1fbeff', name='小胖墩', age=3, bir=Tue Apr 12 10:21:18 CST 2022}
user = User{id='e3863fd3-173c-46f4-a753-c72f7c92ad56', name='小猫咪', age=3, bir=Mon Apr 11 21:36:31 CST 2022}

注:ERROR前还有OFF,一般不用。

13.事务属性

1. 事务传播属性

img

image-20240324162826719

2.事务的隔离级别

image-20240324162840428

3.读写和异常性

image-20240324162855705

14.spring整合Struts2开发(过时了,建议学习整合Spring MVC)

14.1Struts2框架测试

新建maven-webapp项目,main目录下新建java、resources目录

pom.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
45
46
47
48
49
50
51
52
53
<!--spring核心及相关依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>

<!--struts2-core-->
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-core</artifactId>
<version>2.3.16</version>
</dependency>

java目录下新建com.study.action.UserAction.java组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.study.action;

import com.opensymphony.xwork2.Action;

/**
* @ClassName UserAction
* @Description TODO
* @Author chabai
* @Date 2022/4/13 9:43
* @Version 1.0
*/
public class UserAction {
public String hello(){
System.out.println("hello spring struts2");
return Action.SUCCESS;
}
}

resources下新建struts.xml,管理Action组件

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>
<package name="user" extends="struts-default" namespace="/user">
<action name="hello" class="com.study.action.UserAction" method="hello">
<result name="success">/index.jsp</result>
</action>
</package>
</struts>

在webapp/WEB-INF下的web.xml中添加filter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
<display-name>Archetype Created Web Application</display-name>

<!--filter-->
<filter>
<filter-name>struts</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>

<filter-mapping>
<filter-name>struts</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>

部署Tomcat进行测试

Add Configuration…–> + –>Tomcat Server–>Local,配置相关参数(通过Artifact导入spring_struts2:war exploded),注意自己的8080端口被占用,此处使用8888端口进行测试

image-20240324170426155

image-20240324170443001

启动服务进行测试,出现下面的提示表示项目启动成功

1
2
3
4
5
6
7
8
9
10
11
12
13
14
D:\Software_Development\IDEA_code\apache-tomcat-8.5.73-windows-x64\apache-tomcat-8.5.73\bin\catalina.bat run
[2022-04-13 10:27:16,424] Artifact spring_struct2:war exploded: Waiting for server connection to start artifact deployment...
Using CATALINA_BASE: "C:\Users\cjn\AppData\Local\JetBrains\IntelliJIdea2020.1\tomcat\Unnamed_spring_struct2"
Using CATALINA_HOME: "D:\Software_Development\IDEA_code\apache-tomcat-8.5.73-windows-x64\apache-tomcat-8.5.73"
Using CATALINA_TMPDIR: "D:\Software_Development\IDEA_code\apache-tomcat-8.5.73-windows-x64\apache-tomcat-8.5.73\temp"
Using JRE_HOME: "D:\Software_Development\JDK"
Using CLASSPATH: "D:\Software_Development\IDEA_code\apache-tomcat-8.5.73-windows-x64\apache-tomcat-8.5.73\bin\bootstrap.jar;D:\Software_Development\IDEA_code\apache-tomcat-8.5.73-windows-x64\apache-tomcat-8.5.73\bin\tomcat-juli.jar"
Using CATALINA_OPTS: ""
......
Connected to server
[2022-04-13 10:27:18,026] Artifact spring_struct2:war exploded: Artifact is being deployed, please wait...
......
[2022-04-13 10:27:20,164] Artifact spring_struct2:war exploded: Artifact is deployed successfully
[2022-04-13 10:27:20,164] Artifact spring_struct2:war exploded: Deploy took 2,138 milliseconds

打开网址进行测试:http://localhost:8888/spring_struts2/user/hello

网页呈现效果:

image-20240324170539551

控制台输出内容:

hello spring struts2

出现上述效果表示创建成功!

14.2Spring整合Struts2框架

14.2.1思路分析

img

14.2.2spring整合struts2编码步骤总结

img

14.2.3代码实现

pom.xml需要额外引入依赖:

  • struts2-spring-plugin :spring整合struts2
  • servlet-api:引入监听器ContextLoaderListener
1
2
3
4
5
6
7
8
9
10
11
12
13
14
 
<!--struts2-spring-plugin-->
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-spring-plugin</artifactId>
<version>2.3.16</version>
</dependency>

<!--servlet-api-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>

resources下新建spring.xml,管理Action组件

1
2
3
4
5
6
7
8
<?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">

<!--管理Action组件对象的创建-->
<bean id="userAction" class="com.study.action.UserAction" scope="prototype"/>
</beans>

web.xml配置监听器和spring.xml文件位置

1
2
3
4
5
6
7
8
9
10
<!--配置启动工厂的监听器Listener,使用前需添加servlet-api依赖-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<!--配置spring配置文件位置-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring.xml</param-value>
</context-param>

修改struts.xml中class对象名称为对象id

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>
<package name="user" extends="struts-default" namespace="/user">
<action name="hello" class="userAction" method="hello">
<result name="success">/index.jsp</result>
</action>
</package>
</struts>

注意: 配置文件中书写的是工厂中管理的action的bean的id

部署项目测试:与上边一致

14.2.4自定义监听器MyListener

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.study.listener;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

public class MyListener implements ServletContextListener {
private ClassPathXmlApplicationContext context ;

@Override
public void contextInitialized(ServletContextEvent sce) {
String springConfig = sce.getServletContext().getInitParameter("springConfig");
System.out.println(springConfig);
System.out.println("服务器启动时初始化");
this.context = new ClassPathXmlApplicationContext(springConfig);
}

@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("服务器关闭时销毁");
context.close();
}
}

15.SSM整合(Struts2过时了,建议学习整合Spring MVC)

15.1整合Spring+Mybatis

15.1.1整合Spring+Mybatis思路分析

img

15.1.2实现

1.整合Spring+Mybatis

a. 新建Maven-webapp项目,main下新建java、resources目录,src下新建test目录,并在此路径下新建java、resources目录

b.在pom.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
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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>

<!--spring相关-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>

<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.4</version>
</dependency>

<!--mybatis-spring-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.4</version>
</dependency>

<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>

<!--druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.19</version>
</dependency>

<!--struts相关 2.3.16版本一致-->
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-core</artifactId>
<version>2.3.16</version>
</dependency>

<!--struts2-spring-plugin 2.3.16版本一致-->
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-spring-plugin</artifactId>
<version>2.3.16</version>
</dependency>

<!--servlet-api-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>

<!--jstl-->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>

<!--fastjson-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>

<!--log4j-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.10.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>

c.新建实体类User

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
package com.study.entity;

import java.util.Date;

/**
* @ClassName User
* @Description TODO
* @Author chabai
* @Date 2022/4/14 12:33
* @Version 1.0
*/
public class User {
private String id;
private String name;
private Integer age;
private Date bir;

public User() {
}
public User(String id, String name, Integer age, Date bir) {
this.id = id;
this.name = name;
this.age = age;
this.bir = bir;
}

@Override
public String toString() {
return "User{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", age=" + age +
", bir=" + bir +
'}';
}

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}

public Date getBir() {
return bir;
}

public void setBir(Date bir) {
this.bir = bir;
}
}

d.新建DAO接口:UserDAO

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
package com.study.dao;

import com.study.entity.User;

import java.util.List;

/**
* @ClassName UserDAO
* @Description TODO
* @Author chabai
* @Date 2022/4/14 12:36
* @Version 1.0
*/
public interface UserDAO {
/**
* @MethodName insert
* @Description 插入用户数据
* @param: user
* @Author chabai
* @Date 2022/4/14 12:37
*/
void insert(User user);

/**
* @MethodName selectAll
* @Description 查询用户所有数据
* @return: java.util.List<com.study.entity.User>
* @Author chabai
* @Date 2022/4/14 12:37
*/
List<User> selectAll();
}

e.新建Mapper配置文件:UserDAOMapper(resources/com/study/mapper目录下)

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
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<!--
mapper为映射的根节点,用来管理DAO接口
namespace指定DAO接口的完整类名,表示mapper配置文件管理哪个DAO接口(包.接口名)
mybatis会依据这个接口动态创建一个实现类去实现这个接口,而这个实现类是一个Mapper对象
-->
<mapper namespace="com.study.dao.UserDAO">
<!--
id = "接口中的方法名"
parameterType = "接口中传入方法的参数类型" 基本类型和String正常使用,引用类型使用类的全限定名(包名.类名)
resultType = "返回实体类对象:包.类名" 处理结果集 自动封装
注意:sql语句后不要出现";"号
查询:select标签
多参数查询时注意接口中的参数必须使用@Param注解绑定,select标签中parameterType省略不写
查询所有时,无论查询一个还是多个,最终resultType的值都是要封装的实体类全名(包名.类名)
例:<select id="findById" parameterType="int" resultType="entity.Student">
select id,name,age from student where id=#{id}
</select>
增加:insert标签
例:<insert id="insert" parameterType="entity.Student">
insert into student values(#{id},#{name},#{age})
</insert>
修改:update标签
例:<update id="update" parameterType="entity.Student">
update student set name=#{name},age=#{age} where id=#{id}
</update>
删除:delete标签
例:<delete id="delete" parameterType="int">
delete from student where id=#{id}
</delete>

Mybatis框架在执行插入(insert)、更新(update)操作时,默认不允许插入或修改NULL值到数据库中,
要在sql语句的取值处设置一个jdbcType类型(类型全部字母大写)),例如:#{age,jdbcType=INTEGER}
-->
<!--insert-->
<insert id="insert" parameterType="User">
insert into t_user values(#{id},#{name},#{age},#{bir})
</insert>

<!--selectAll-->
<select id="selectAll" resultType="User">
select id,name,age,bir from t_user
</select>

</mapper>

f.新建Service接口:UserService

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
package com.study.service;

import com.study.entity.User;

import java.util.List;

/**
* @ClassName UserService
* @Description TODO
* @Author chabai
* @Date 2022/4/14 12:42
* @Version 1.0
*/
public interface UserService {
/**
* @MethodName insert
* @Description 插入用户数据
* @param: user
* @Author chabai
* @Date 2022/4/14 12:37
*/
void insert(User user);

/**
* @MethodName selectAll
* @Description 查询用户所有数据
* @return: java.util.List<com.study.entity.User>
* @Author chabai
* @Date 2022/4/14 12:37
*/
List<User> selectAll();
}

g.新建UserService接口实现类:UserServiceImpl,依赖UserDAO组件,需要注入

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
package com.study.service;

import com.study.dao.UserDAO;
import com.study.entity.User;

import java.util.List;
import java.util.UUID;

/**
* @ClassName UserServiceImpl
* @Description TODO
* @Author chabai
* @Date 2022/4/14 12:42
* @Version 1.0
*/
public class UserServiceImpl implements UserService{
//依赖UserDAO
private UserDAO userDAO;

public void setUserDAO(UserDAO userDAO) {
this.userDAO = userDAO;
}

@Override
public void insert(User user) {
//处理业务
user.setId(UUID.randomUUID().toString());
userDAO.insert(user);
}

@Override
public List<User> selectAll() {
//处理业务
return userDAO.selectAll();
}
}

h.编写spring.xml配置文件(resources目录下)

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
<?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:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

<!--创建数据源-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?
useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=UTC&amp;useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>

<!--创建SqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mapperLocations" value="classpath:com/study/mapper/*.xml"/>
<property name="typeAliasesPackage" value="com.study.entity"/>
</bean>

<!--创建DAO组件-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<property name="basePackage" value="com.study.dao"/>
</bean>

<!--创建事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>

<!--基于事务管理器创建事务通知对象,并配置事务细粒度控制-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="insert*"/>
<tx:method name="select*" propagation="SUPPORTS"/>
</tx:attributes>
</tx:advice>

<!--配置事务切面-->
<aop:config>
<aop:pointcut id="pc" expression="within(com.study.service.*ServiceImpl)"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pc"/>
</aop:config>

<!--管理Service组件对象-->
<bean id="userService" class="com.study.service.UserServiceImpl">
<property name="userDAO" ref="userDAO"/>
</bean>
</beans>

i.在resources目录下新建log4j.properties记录日志信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
## 根日志
## 日志级别
log4j.rootLogger=ERROR,stdout
## 输出位置
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
## 布局
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
## 格式
log4j.appender.stdout.layout.conversionPattern=[%p] %d{yyyy-MM-dd} %m%n

## 子日志
## 日志级别
log4j.logger.com.study.dao=DEBUG
## 监听spring框架的日志级别
## log4j.logger.org.springframework=ERROR

j.测试Spring+Mybatis是否整合成功(src/test/java/com/study/test目录下)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.study.test;

import com.study.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
* @ClassName TestUserService
* @Description TODO
* @Author chabai
* @Date 2022/4/14 13:07
* @Version 1.0
*/
public class TestUserService {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
UserService userService = (UserService) context.getBean("userService");
userService.selectAll().forEach(user -> System.out.println("user = " + user));
}
}

输出结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[DEBUG] 2022-04-14 ==>  Preparing: select id,name,age,bir from t_user 
[DEBUG] 2022-04-14 ==> Parameters:
[DEBUG] 2022-04-14 <== Total: 14
user = User{id='1', name='张三', age=10, bir=Fri Apr 01 00:00:00 CST 2022}
user = User{id='2', name='李四', age=20, bir=Sat Apr 02 00:00:00 CST 2022}
user = User{id='2f278828-6422-432d-ab1b-a727b33c23bc', name='小胖墩', age=3, bir=Mon Apr 11 21:43:57 CST 2022}
user = User{id='3', name='王五', age=30, bir=Sun Apr 03 00:00:00 CST 2022}
user = User{id='4', name='灰太狼', age=60, bir=Sun Apr 10 09:56:17 CST 2022}
user = User{id='5', name='小超超', age=36, bir=Sun Apr 10 09:55:41 CST 2022}
user = User{id='586a5f71-836c-4171-a038-4620fe0f9354', name='葫芦娃', age=5, bir=Tue Apr 12 09:45:17 CST 2022}
user = User{id='6', name='小呆呆', age=60, bir=Sun Apr 10 09:55:43 CST 2022}
user = User{id='7', name='小超超', age=36, bir=Sun Apr 10 09:55:44 CST 2022}
user = User{id='8', name='胖嘟嘟', age=50, bir=Sun Apr 10 09:55:39 CST 2022}
user = User{id='8a3e8ab8-5abc-44e1-9aec-31f3978d97f2', name='小胖墩', age=3, bir=Tue Apr 12 10:23:33 CST 2022}
user = User{id='9', name='茶白', age=25, bir=Sun Apr 10 09:55:52 CST 2022}
user = User{id='cd280176-68b2-4ceb-b781-ba2f5e1fbeff', name='小胖墩', age=3, bir=Tue Apr 12 10:21:18 CST 2022}
user = User{id='e3863fd3-173c-46f4-a753-c72f7c92ad56', name='小猫咪', age=3, bir=Mon Apr 11 21:36:31 CST 2022}

15.2整合Spring+Struts2

15.2.1实现

a. 配置web.xml(webapp/WEB-INF目录下)

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
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
<display-name>Archetype Created Web Application</display-name>

<!--配置工厂配置文件的位置-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring.xml</param-value>
</context-param>

<!--配置struts2中核心filter-->
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<!--配置Spring监听器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>

b.开发Action组件:UserAction,注入Service组件

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
package com.study.action;

import com.opensymphony.xwork2.Action;
import com.study.entity.User;
import com.study.service.UserService;

import java.util.List;

/**
* @ClassName UserAction
* @Description TODO
* @Author chabai
* @Date 2022/4/14 13:57
* @Version 1.0
*/
@Controller
@Scope("prototype")
public class UserAction {
//依赖注入
@Autowired
private UserService userService;

//接收参数 数据传递 必须同时提供GET、SET方法
private List<User> users;//struts2传值机制:成员变量替换request的作用域
private User user;

public List<User> getUsers() {
return users;
}

public void setUsers(List<User> users) {
this.users = users;
}

public User getUser() {
return user;
}

public void setUser(User user) {
this.user = user;
}

/**
* @MethodName insert
* @Description 插入用户信息
* @return: java.lang.String
* @Author chabai
* @Date 2022/4/14 14:31
*/
public String insert(){
//1.接收参数
//2.调用业务方法
userService.insert(user);
//3.处理响应
return Action.SUCCESS;
}

/**
* @MethodName selectAll
* @Description 查询所有用户数据
* @return: java.lang.String
* @Author chabai
* @Date 2022/4/14 14:34
*/
public String selectAll(){
//1.收集数据
//2.调用业务
//3.处理响应
this.users = userService.selectAll();
return Action.SUCCESS;
}
}

c.resources目录下引入struts.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>
<package name="user" extends="struts-default" namespace="/user">
<!--selectAll,访问端口:http://localhost:端口号/项目名/user/selectAll
例如:http://localhost:8888/ssm_struts2_annotation/user/selectAll
-->
<action name="selectAll" class="userAction" method="selectAll">
<result name="success">/showAll.jsp</result>
</action>

<!--insert,访问端口:http://localhost:端口号/项目名/user/insert?user.name=xxx&user.age=xxx&user.bir=xxxx-xx-xx
例如:http://localhost:8888/ssm_struts2_annotation/user/insert?user.name=唐三&&user.age=20&user.bir=2022-04-15-->
<action name="insert" class="userAction" method="insert">
<result name="success" type="redirect">/user/selectAll</result>
</action>
</package>
</struts>

d.webapp路径下新建showAll.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@page pageEncoding="UTF-8" contentType="text/html; UTF-8" isELIgnored="false" %>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>展示所有用户</title>
</head>
<body>
<h1>用户列表</h1>
<c:forEach items="${requestScope.users}" var="user">
${user.id}----${user.name}----${user.age}----<fmt:formatDate value="${user.bir}" pattern="yyyy-MM-dd"/> <br>
</c:forEach>
</body>
</html>

d.部署Tomcat进行测试

image-20240324165941039

image-20240324165951186

项目启动成功后自动访问页面:

image-20240324170006794

控制台打印输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
D:\Software_Development\IDEA_code\apache-tomcat-8.5.78\bin\catalina.bat run
[2022-04-15 08:15:02,252] Artifact ssm_struts2_annotation:war exploded: Waiting for server connection to start artifact deployment...
Using CATALINA_BASE: "C:\Users\cjn\AppData\Local\JetBrains\IntelliJIdea2020.1\tomcat\Unnamed_ssm_struts2_annotation"
Using CATALINA_HOME: "D:\Software_Development\IDEA_code\apache-tomcat-8.5.78"
Using CATALINA_TMPDIR: "D:\Software_Development\IDEA_code\apache-tomcat-8.5.78\temp"
Using JRE_HOME: "D:\Software_Development\JDK"
Using CLASSPATH: "D:\Software_Development\IDEA_code\apache-tomcat-8.5.78\bin\bootstrap.jar;D:\Software_Development\IDEA_code\apache-tomcat-8.5.78\bin\tomcat-juli.jar"
Using CATALINA_OPTS: ""
......
Connected to server
[2022-04-15 08:15:04,464] Artifact ssm_struts2_annotation:war exploded: Artifact is being deployed, please wait...
......
[2022-04-15 08:15:21,685] Artifact ssm_struts2_annotation:war exploded: Artifact is deployed successfully
[2022-04-15 08:15:21,686] Artifact ssm_struts2_annotation:war exploded: Deploy took 17,222 milliseconds

访问路径:http://localhost:8888/ssm_struts2_annotation/user/selectAll 查询所有用户信息,显示效果如下:

img

访问路径:http://localhost:8888/ssm_struts2_annotation/user/insert?user.name=唐三&&user.age=20&user.bir=2022-04-15 插入用户信息,显示效果如下:

img

15.3最终项目结构

img

16.Spring注解

创建对象相关注解:@Component, @Repository,@Service,@Controller

注解注入语法:需要谁就把谁声明为成员变量,并加入相应的注入注解

注意:注入对象的话必须在工厂先创建好对象才可

img

1 常用注解总结

image-20240324164055335

image-20240324164106532

image-20240324164139857

2.注解式注入

1).八种基本类型+String+日期+数组+set list map标签集合类型属性

回顾标签式注入

1
private String name;
1
<property name="name" value="zhagnsan"/>

注解式注入

1
2
@Value("xxx")//可以给成员变量赋值  但这种方法把值写死了不利于代码维护  还是推荐写到配置文件里
private String name;

2).对象类型注入

回顾标签式注入(略)

注解式注入

1
2
3
4
5
6
7
@Repository(value = "userDAO")
public class UserDAOImpl implements UserDAO{
@Override
public void save(String name) {
System.out.println("UserDAO: " + name);
}
}
1
2
@Autowired
private UserDAO userDAO;

3.使用实现

新建Maven-webapp项目,添加java、resources目录

pom.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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>compile</scope>
</dependency>

<!--spring核心及相关依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>

编写DAO接口及其实现类

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
package com.study.dao;

/**
* @ClassName UserDAO
* @Description TODO
* @Author chabai
* @Date 2022/4/15 15:51
* @Version 1.0
*/
public interface UserDAO {
void save(String name);
}



package com.study.dao;

import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;


/**
* @ClassName UserDAOImpl
* @Description TODO
* @Author chabai
* @Date 2022/4/15 15:52
* @Version 1.0
*/
//1.通用注解
//默认@Component(value="userDAOImpl"),即类名首字母小写,简写为@Component("userDAOImpl"),只有一个参数时才可以省略value 即@Component(value = "userDAO") ===== 等价于 @Component("userDAO")
//指定其他名称是,须通过value指定
//@Component(value = "userDAO")

//2.DAO层专用注解
//默认@Repository(value="userDAOImpl"),即类名首字母小写,简写为@Repository("userDAOImpl"),只有一个参数时才可以省略value
//指定其他名称是,须通过value指定
@Repository(value = "userDAO")
public class UserDAOImpl implements UserDAO{
@Override
public void save(String name) {
System.out.println("UserDAO: " + name);
}
}

5编写Service接口及其实现类

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
75
76
package com.study.service;

/**
* @ClassName UserService
* @Description TODO
* @Author chabai
* @Date 2022/4/15 15:53
* @Version 1.0
*/
public interface UserService {
void save(String name);

String find(String id);
}



package com.study.service;

import com.study.dao.UserDAO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

/**
* @ClassName UserServiceImpl
* @Description TODO
* @Author chabai
* @Date 2022/4/15 15:54
* @Version 1.0
*/
//1.通用注解
//默认@Component(value="userServiceImpl"),即类名首字母小写,简写为@Component("userServiceImpl"),只有一个参数时才可以省略value
//指定其他名称是,须通过value指定
//@Component(value = "userService")

//2.Service层专用注解
//默认@Repository(value="userServiceImpl"),即类名首字母小写,简写为@Repository("userServiceImpl"),只有一个参数时才可以省略value
//指定其他名称是,须通过value指定
@Service(value = "userService")

//Service层需要添加事务,默认属性,查询方法额外添加属性
@Transactional

// 默认单例,prototype为多例
@Scope(value = "prototype")
public class UserServiceImpl implements UserService{
//Service层需要调用DAO层
@Autowired
private UserDAO userDAO;

@Override
public void save(String name) {
userDAO.save("UserDAO");
System.out.println("UserService = " + name);

}

@Override
//查询方法需要额外添加事务属性
@Transactional(
propagation = Propagation.SUPPORTS,
isolation = Isolation.DEFAULT,
noRollbackFor = {},
rollbackFor = {},
readOnly = false,
timeout = -1
)
public String find(String id) {
return id;
}
}

编写spring.xml配置文件,开启注解扫描配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?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" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- &lt;!&ndash;管理DAO组件&ndash;&gt;-->
<!-- <bean id="userDAO" class="com.study.dao.UserDAOImpl"/>-->

<!-- &lt;!&ndash;管理Service组件&ndash;&gt;-->
<!-- <bean id="userService" class="com.study.service.UserServiceImpl"/>-->

<!--开启注解扫描-->
<context:component-scan base-package="com.study"/>

<!--开启事务注解,上面要进行数据源及事务管理配置-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
</beans

测试

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
package com.study.test;

import com.study.dao.UserDAO;
import com.study.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
* @ClassName TestSpring
* @Description TODO
* @Author chabai
* @Date 2022/4/15 15:57
* @Version 1.0
*/
public class TestSpring {
/**
* @MethodName TestUserDAO
* @Description 测试DAO层注解
* @Author chabai
* @Date 2022/4/15 16:23
*/
@Test
public void TestUserDAO(){
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
UserDAO userDAO = (UserDAO) context.getBean("userDAO");
System.out.println("userDAO = " + userDAO);
userDAO.save("2022年4月15日15:59:50");
}

/**
* @MethodName TestUserService
* @Description 测试Service层注解
* @Author chabai
* @Date 2022/4/15 16:23
*/
@Test
public void TestUserService(){
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
UserService userService = (UserService) context.getBean("userService");
System.out.println("userService = " + userService);
System.out.println(userService.find("1"));
UserService userService1 = (UserService) context.getBean("userService");
System.out.println("userService1 = " + userService1);
System.out.println(userService1.find("2"));
System.out.println(userService==userService1);

userService.save("UserService");
}
}

输出结果:

1
2
3
4
5
6
7
8

userService = com.study.service.UserServiceImpl@19d37183
1
userService1 = com.study.service.UserServiceImpl@1a0dcaa
2
false
UserDAO: UserDAO
UserService = UserService

17.SSM整合注解式开发

1.思路分析

img

2.代码实现

整合Spring+Mybatis

a. 新建Maven-webapp项目,main下新建java、resources目录,src下新建test目录,并在此路径下新建java、resources目录

b.在pom.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
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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>

<!--spring相关-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>

<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.4</version>
</dependency>

<!--mybatis-spring-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.4</version>
</dependency>

<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>

<!--druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.19</version>
</dependency>

<!--struts相关 2.3.16版本一致-->
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-core</artifactId>
<version>2.3.16</version>
</dependency>

<!--struts2-spring-plugin 2.3.16版本一致-->
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-spring-plugin</artifactId>
<version>2.3.16</version>
</dependency>

<!--servlet-api-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>

<!--jstl-->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>

<!--fastjson-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>

<!--log4j-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.10.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>

c.新建实体类User

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
package com.study.entity;

import java.util.Date;

/**
* @ClassName User
* @Description TODO
* @Author chabai
* @Date 2022/4/14 12:33
* @Version 1.0
*/
public class User {
private String id;
private String name;
private Integer age;
private Date bir;

public User() {
}

public User(String id, String name, Integer age, Date bir) {
this.id = id;
this.name = name;
this.age = age;
this.bir = bir;
}

@Override
public String toString() {
return "User{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", age=" + age +
", bir=" + bir +
'}';
}

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}

public Date getBir() {
return bir;
}

public void setBir(Date bir) {
this.bir = bir;
}
}

d.新建DAO接口:UserDAO

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
package com.study.dao;

import com.study.entity.User;

import java.util.List;

/**
* @ClassName UserDAO
* @Description TODO
* @Author chabai
* @Date 2022/4/14 12:36
* @Version 1.0
*/
public interface UserDAO {
/**
* @MethodName insert
* @Description 插入用户数据
* @param: user
* @Author chabai
* @Date 2022/4/14 12:37
*/
void insert(User user);

/**
* @MethodName selectAll
* @Description 查询用户所有数据
* @return: java.util.List<com.study.entity.User>
* @Author chabai
* @Date 2022/4/14 12:37
*/
List<User> selectAll();
}

e.新建Mapper配置文件:UserDAOMapper(resources/com/study/mapper目录下)

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
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<!--
mapper为映射的根节点,用来管理DAO接口
namespace指定DAO接口的完整类名,表示mapper配置文件管理哪个DAO接口(包.接口名)
mybatis会依据这个接口动态创建一个实现类去实现这个接口,而这个实现类是一个Mapper对象
-->
<mapper namespace="com.study.dao.UserDAO">
<!--
id = "接口中的方法名"
parameterType = "接口中传入方法的参数类型" 基本类型和String正常使用,引用类型使用类的全限定名(包名.类名)
resultType = "返回实体类对象:包.类名" 处理结果集 自动封装
注意:sql语句后不要出现";"号
查询:select标签
多参数查询时注意接口中的参数必须使用@Param注解绑定,select标签中parameterType省略不写
查询所有时,无论查询一个还是多个,最终resultType的值都是要封装的实体类全名(包名.类名)
例:<select id="findById" parameterType="int" resultType="entity.Student">
select id,name,age from student where id=#{id}
</select>
增加:insert标签
例:<insert id="insert" parameterType="entity.Student">
insert into student values(#{id},#{name},#{age})
</insert>
修改:update标签
例:<update id="update" parameterType="entity.Student">
update student set name=#{name},age=#{age} where id=#{id}
</update>
删除:delete标签
例:<delete id="delete" parameterType="int">
delete from student where id=#{id}
</delete>

Mybatis框架在执行插入(insert)、更新(update)操作时,默认不允许插入或修改NULL值到数据库中,
要在sql语句的取值处设置一个jdbcType类型(类型全部字母大写)),例如:#{age,jdbcType=INTEGER}
-->
<!--insert-->
<insert id="insert" parameterType="User">
insert into t_user values(#{id},#{name},#{age},#{bir})
</insert>

<!--selectAll-->
<select id="selectAll" resultType="User">
select id,name,age,bir from t_user
</select>

</mapper>

f.新建Service接口:UserService

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
package com.study.service;

import com.study.entity.User;

import java.util.List;

/**
* @ClassName UserService
* @Description TODO
* @Author chabai
* @Date 2022/4/14 12:42
* @Version 1.0
*/
public interface UserService {
/**
* @MethodName insert
* @Description 插入用户数据
* @param: user
* @Author chabai
* @Date 2022/4/14 12:37
*/
void insert(User user);

/**
* @MethodName selectAll
* @Description 查询用户所有数据
* @return: java.util.List<com.study.entity.User>
* @Author chabai
* @Date 2022/4/14 12:37
*/
List<User> selectAll();
}

g.新建UserService接口实现类:UserServiceImpl,依赖UserDAO组件,需要注入

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
package com.study.service;

import com.study.dao.UserDAO;
import com.study.entity.User;

import java.util.List;
import java.util.UUID;

/**
* @ClassName UserServiceImpl
* @Description TODO
* @Author chabai
* @Date 2022/4/14 12:42
* @Version 1.0
*/
@Service("userService")
@Transational
public class UserServiceImpl implements UserService{
//依赖UserDAO
@Autowired
private UserDAO userDAO;

@Override
public void insert(User user) {
//处理业务
user.setId(UUID.randomUUID().toString());
userDAO.insert(user);
}

@Override
@Transactional(propagation = Propagation.SUPPORTS)
public List<User> selectAll() {
//处理业务
return userDAO.selectAll();
}
}

h.编写spring.xml配置文件(resources目录下)

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
<?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" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

<!--开启注解扫描-->
<context:component-scan base-package="com.study"/>

<!--创建数据源对象-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?
useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=UTC&amp;useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>

<!--创建SqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mapperLocations" value="classpath:com/study/mapper/*.xml"/>
<property name="typeAliasesPackage" value="com.study.entity"/>
</bean>

<!--创建DAO组件-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<property name="basePackage" value="com.study.dao"/>
</bean>

<!--创建事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>

<!--开启注解式事务生效-->
<tx:annotation-driven transaction-manager="transactionManager"/>

</beans>

i.在resources目录下新建log4j.properties记录日志信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
## 根日志
## 日志级别
log4j.rootLogger=ERROR,stdout
## 输出位置
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
## 布局
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
## 格式
log4j.appender.stdout.layout.conversionPattern=[%p] %d{yyyy-MM-dd} %m%n

## 子日志
## 日志级别
log4j.logger.com.study.dao=DEBUG
## 监听spring框架的日志级别
## log4j.logger.org.springframework=ERROR

j.测试Spring+Mybatis是否整合成功(src/test/java/com/study/test目录下)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.study.test;

import com.study.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
* @ClassName TestUserService
* @Description TODO
* @Author chabai
* @Date 2022/4/14 13:07
* @Version 1.0
*/
public class TestUserService {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
UserService userService = (UserService) context.getBean("userService");
userService.selectAll().forEach(user -> System.out.println("user = " + user));
}
}

输出结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[DEBUG] 2022-04-15 ==>  Preparing: select id,name,age,bir from t_user 
[DEBUG] 2022-04-15 ==> Parameters:
[DEBUG] 2022-04-15 <== Total: 17
user = User{id='1', name='张三', age=10, bir=Fri Apr 01 00:00:00 CST 2022}
user = User{id='2', name='李四', age=20, bir=Sat Apr 02 00:00:00 CST 2022}
user = User{id='2d237778-835d-477b-9721-fe6f575064b9', name='波比', age=18, bir=Sun Feb 02 00:00:00 CST 2020}
user = User{id='2f278828-6422-432d-ab1b-a727b33c23bc', name='小胖墩', age=3, bir=Mon Apr 11 21:43:57 CST 2022}
user = User{id='3', name='王五', age=30, bir=Sun Apr 03 00:00:00 CST 2022}
user = User{id='4', name='灰太狼', age=60, bir=Sun Apr 10 09:56:17 CST 2022}
user = User{id='5', name='小超超', age=36, bir=Sun Apr 10 09:55:41 CST 2022}
user = User{id='586a5f71-836c-4171-a038-4620fe0f9354', name='葫芦娃', age=5, bir=Tue Apr 12 09:45:17 CST 2022}
user = User{id='6', name='小呆呆', age=60, bir=Sun Apr 10 09:55:43 CST 2022}
user = User{id='7', name='小超超', age=36, bir=Sun Apr 10 09:55:44 CST 2022}
user = User{id='8', name='胖嘟嘟', age=50, bir=Sun Apr 10 09:55:39 CST 2022}
user = User{id='8a3e8ab8-5abc-44e1-9aec-31f3978d97f2', name='小胖墩', age=3, bir=Tue Apr 12 10:23:33 CST 2022}
user = User{id='9', name='茶白', age=25, bir=Sun Apr 10 09:55:52 CST 2022}
user = User{id='985cd035-dedc-4e84-973a-a5fdaa2b8475', name='喜洋洋', age=8, bir=Tue Oct 10 00:00:00 CST 2000}
user = User{id='a6be9263-f05f-415f-855e-33843b22e71d', name='皮卡丘', age=10, bir=Thu Apr 14 00:00:00 CST 2022}
user = User{id='cd280176-68b2-4ceb-b781-ba2f5e1fbeff', name='小胖墩', age=3, bir=Tue Apr 12 10:21:18 CST 2022}
user = User{id='e3863fd3-173c-46f4-a753-c72f7c92ad56', name='小猫咪', age=3, bir=Mon Apr 11 21:36:31 CST 2022

整合Spring+Struts2

a. 配置web.xml(webapp/WEB-INF目录下)

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
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
<display-name>Archetype Created Web Application</display-name>

<!--配置工厂配置文件的位置-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring.xml</param-value>
</context-param>

<!--配置struts2中核心filter-->
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<!--配置Spring监听器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>

b.开发Action组件:UserAction,注入Service组件

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
package com.study.action;

import com.opensymphony.xwork2.Action;
import com.study.entity.User;
import com.study.service.UserService;

import java.util.List;

/**
* @ClassName UserAction
* @Description TODO
* @Author chabai
* @Date 2022/4/14 13:57
* @Version 1.0
*/
@Controller
@Scope("prototype")
public class UserAction {
//依赖注入
@Autowired
private UserService userService;

//接收参数 数据传递 必须同时提供GET、SET方法
private List<User> users;//struts2传值机制:成员变量替换request的作用域
private User user;

public List<User> getUsers() {
return users;
}

public void setUsers(List<User> users) {
this.users = users;
}

public User getUser() {
return user;
}

public void setUser(User user) {
this.user = user;
}

/**
* @MethodName insert
* @Description 插入用户信息
* @return: java.lang.String
* @Author chabai
* @Date 2022/4/14 14:31
*/
public String insert(){
//1.接收参数
//2.调用业务方法
userService.insert(user);
//3.处理响应
return Action.SUCCESS;
}

/**
* @MethodName selectAll
* @Description 查询所有用户数据
* @return: java.lang.String
* @Author chabai
* @Date 2022/4/14 14:34
*/
public String selectAll(){
//1.收集数据
//2.调用业务
//3.处理响应
this.users = userService.selectAll();
return Action.SUCCESS;
}
}

c.resources目录下引入struts.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>
<package name="user" extends="struts-default" namespace="/user">
<!--selectAll,访问端口:http://localhost:端口号/项目名/user/selectAll
例如:http://localhost:8888/ssm_struts2_annotation/user/selectAll
-->
<action name="selectAll" class="userAction" method="selectAll">
<result name="success">/showAll.jsp</result>
</action>

<!--insert,访问端口:http://localhost:端口号/项目名/user/insert?user.name=xxx&user.age=xxx&user.bir=xxxx-xx-xx
例如:http://localhost:8888/ssm_struts2_annotation/user/insert?user.name=唐三&&user.age=20&user.bir=2022-04-15-->
<action name="insert" class="userAction" method="insert">
<result name="success" type="redirect">/user/selectAll</result>
</action>
</package>
</struts>

d.webapp路径下新建showAll.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@page pageEncoding="UTF-8" contentType="text/html; UTF-8" isELIgnored="false" %>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>展示所有用户</title>
</head>
<body>
<h1>用户列表</h1>
<c:forEach items="${requestScope.users}" var="user">
${user.id}----${user.name}----${user.age}----<fmt:formatDate value="${user.bir}" pattern="yyyy-MM-dd"/> <br>
</c:forEach>
</body>
</html>

d.部署Tomcat进行测试

image-20240324165344750

image-20240324165353764

项目启动成功后自动访问页面:

img

控制台打印输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
D:\Software_Development\IDEA_code\apache-tomcat-8.5.78\bin\catalina.bat run
[2022-04-15 08:15:02,252] Artifact ssm_struts2_annotation:war exploded: Waiting for server connection to start artifact deployment...
Using CATALINA_BASE: "C:\Users\cjn\AppData\Local\JetBrains\IntelliJIdea2020.1\tomcat\Unnamed_ssm_struts2_annotation"
Using CATALINA_HOME: "D:\Software_Development\IDEA_code\apache-tomcat-8.5.78"
Using CATALINA_TMPDIR: "D:\Software_Development\IDEA_code\apache-tomcat-8.5.78\temp"
Using JRE_HOME: "D:\Software_Development\JDK"
Using CLASSPATH: "D:\Software_Development\IDEA_code\apache-tomcat-8.5.78\bin\bootstrap.jar;D:\Software_Development\IDEA_code\apache-tomcat-8.5.78\bin\tomcat-juli.jar"
Using CATALINA_OPTS: ""
......
Connected to server
[2022-04-15 08:15:04,464] Artifact ssm_struts2_annotation:war exploded: Artifact is being deployed, please wait...
......
[2022-04-15 08:15:21,685] Artifact ssm_struts2_annotation:war exploded: Artifact is deployed successfully
[2022-04-15 08:15:21,686] Artifact ssm_struts2_annotation:war exploded: Deploy took 17,222 milliseconds

访问路径:http://localhost:8888/ssm_struts2_annotation/user/selectAll 查询所有用户信息,显示效果如下:

img

访问路径:http://localhost:8888/ssm_struts2_annotation/user/insert?user.name=唐三&&user.age=20&user.bir=2022-04-15 插入用户信息,显示效果如下:

img

最终项目结构

img