# spring-learn
**Repository Path**: hrbu2024/spring-learn
## Basic Information
- **Project Name**: spring-learn
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2026-11-02
- **Last Updated**: 2026-11-04
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# 框架的迭代
Spring SpringMVC MyBaits ( SSM )
SSH: Struts1.x(MVC) Spring(解耦) Hibernate( 持久层 JBDC封装)
SSH: Struts2.x(MVC) Spring(解耦) Hibernate( 持久层 JBDC封装)
SSI: Struts2.x (MVC) Spring (解耦) IBatis (1.x 2.x)( 持久层 JBDC封装)
SSI: SpringMVC(MVC) Spring (解耦) IBatis (1.x 2.x)( 持久层 JBDC封装)
SSM: SpringMVC(MVC) Spring (解耦) MBatis (3.X)( 持久层 JBDC封装)
# Spring 介绍
[Spring | Home](https://spring.io/)
[Spring Framework Documentation :: Spring Framework](https://docs.spring.io/spring-framework/reference/6.2/index.html)
Spring是一个基于java的轻量级的、一站式框架。 虽然Spring是一个轻量级框架,但并不表示它的功能少。实际上,spring是一个庞然大物,包罗万象。 时至今日,Spring已经成为java世界中事实上的标准。
Spring之父:Rod Johnson(罗德.约翰逊) 他是悉尼大学音乐学博士,而计算机仅仅是学士学位。 由于Rod对JAVAEE笨重、臃肿的现状深恶痛绝,以至于他将他在JAVAEE实战中的经历称为噩梦般的经历。他决定改变这种现状,于是就有了Spring。


Spring 总共大约有 20 个模块,由 1300 多个不同的文件构成。而这些组件被分别整合在6 个模块中:
1. 核心容器(Core Container)
2. AOP(Aspect Oriented Programming)
3. 设备支持(Instrmentation)
4. 数据访问及集成(Data Access/Integeration)
5. Web报文发送(Messaging)
6. Test测试
## 两大核心
- IOC/DI
- IOC:控制反转(Inversion of Control):它是一种控制权的转移。即组件与组件之间的依赖由主动变为被动。也就是说:应用程序本身不再负责组件的创建、维护等,而是将控制权移交出去。从这一点来说,几乎所有的框架都是IOC框架。
- DI:依赖注入(Dependency Injection):依赖其他容器(比如spring)来创建和维护所需要的组件,并将其注入到应用程序中。
- IOC 控制翻转, Service 依赖Dao,原来需要在serice 中new Dao,使用IOC容器
- DI 将dao 放到Service 过程 依赖注入
- AOP: 面相切面变成
# 上手Helloworld
聚合项目
- spring-learn
- 01-spring-helloword-xml
- 02-spring-helloword-xml
- 03-spring-helloword-xml
- 04-spring-helloword-xml
- 05-spring-helloword-xml
- 06-spring-helloword-xml
- 依赖
- 父项目定义版本
- 子项目使用依赖(无需再重复编写版本号)
## 创建项目


## 编写依赖
父项目pom.xml
```xml
4.0.0com.neuedu.springspring-learn1.0pomspring-learnhttp://maven.apache.org01-spring-helloword-xmlUTF-86.2.19org.springframeworkspring-core${spring.version}compileorg.springframeworkspring-beans${spring.version}compileorg.springframeworkspring-context${spring.version}compileorg.springframeworkspring-expression${spring.version}compile
```
子项目 pom.xml
```xml
4.0.0com.neuedu.springspring-learn1.001-spring-helloword-xmljar01-spring-helloword-xmlhttp://maven.apache.orgUTF-8org.springframeworkspring-coreorg.springframeworkspring-beansorg.springframeworkspring-contextorg.springframeworkspring-expression
```
## 使用Qualifier注解区分多个同名的类型

# 使用配置类代替配置文件(spring-beans.xml)
04-spring-javaconfig
```java
package com.neuedu.spring;
import org.springframework.context.annotation.ComponentScan;
/***
*
* 项目名称: spring-learn
* 类名称:com.neuedu.spring
* 类描述: 使用Java类代替配置文件
* 创建人:金山老师
* 创建时间:2026/11/02 14:49
* 版本:1.0
*
*/
//
@ComponentScan("com.neuedu.spring")
public class SpringApp {
}
```

junit的报错 可以不用管

D:\app\Java\jdk-21\bin\java.exe -ea -Didea.test.cyclic.buffer.size=1048576 "-javaagent:D:\app\JetBrains\IntelliJ IDEA 2024.3.1.1\lib\idea_rt.jar=54401:D:\app\JetBrains\IntelliJ IDEA 2024.3.1.1\bin" -javaagent:C:\Users\Administrator\AppData\Local\JetBrains\IntelliJIdea2024.3\captureAgent\debugger-agent.jar -Dkotlinx.coroutines.debug.enable.creation.stack.trace=false -Ddebugger.agent.enable.coroutines=true -Dkotlinx.coroutines.debug.enable.flows.stack.trace=true -Dkotlinx.coroutines.debug.enable.mutable.state.flows.stack.trace=true -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8 -classpath "C:\Users\Administrator\.m2\repository\org\junit\platform\junit-platform-launcher\1.14.4\junit-platform-launcher-1.14.4.jar;C:\Users\Administrator\.m2\repository\org\junit\platform\junit-platform-engine\1.14.4\junit-platform-engine-1.14.4.jar;C:\Users\Administrator\.m2\repository\org\opentest4j\opentest4j\1.3.0\opentest4j-1.3.0.jar;C:\Users\Administrator\.m2\repository\org\junit\platform\junit-platform-commons\1.14.4\junit-platform-commons-1.14.4.jar;C:\Users\Administrator\.m2\repository\org\apiguardian\apiguardian-api\1.1.2\apiguardian-api-1.1.2.jar;C:\Users\Administrator\.m2\repository\org\junit\jupiter\junit-jupiter-engine\5.14.4\junit-jupiter-engine-5.14.4.jar;C:\Users\Administrator\.m2\repository\org\junit\jupiter\junit-jupiter-api\5.14.4\junit-jupiter-api-5.14.4.jar;D:\app\JetBrains\IntelliJ IDEA 2024.3.1.1\lib\idea_rt.jar;D:\app\JetBrains\IntelliJ IDEA 2024.3.1.1\plugins\junit\lib\junit5-rt.jar;D:\app\JetBrains\IntelliJ IDEA 2024.3.1.1\plugins\junit\lib\junit-rt.jar;D:\workspace\spring-learn\04-spring-javaconfig\target\test-classes;D:\workspace\spring-learn\04-spring-javaconfig\target\classes;D:\app\apache-maven-3.9.9\jarrepository\org\springframework\spring-context\6.2.19\spring-context-6.2.19.jar;D:\app\apache-maven-3.9.9\jarrepository\org\springframework\spring-aop\6.2.19\spring-aop-6.2.19.jar;D:\app\apache-maven-3.9.9\jarrepository\org\springframework\spring-beans\6.2.19\spring-beans-6.2.19.jar;D:\app\apache-maven-3.9.9\jarrepository\org\springframework\spring-core\6.2.19\spring-core-6.2.19.jar;D:\app\apache-maven-3.9.9\jarrepository\org\springframework\spring-jcl\6.2.19\spring-jcl-6.2.19.jar;D:\app\apache-maven-3.9.9\jarrepository\org\springframework\spring-expression\6.2.19\spring-expression-6.2.19.jar;D:\app\apache-maven-3.9.9\jarrepository\io\micrometer\micrometer-observation\1.15.12\micrometer-observation-1.15.12.jar;D:\app\apache-maven-3.9.9\jarrepository\io\micrometer\micrometer-commons\1.15.12\micrometer-commons-1.15.12.jar;D:\app\apache-maven-3.9.9\jarrepository\org\springframework\spring-test\6.2.19\spring-test-6.2.19.jar;D:\app\apache-maven-3.9.9\jarrepository\org\junit\jupiter\junit-jupiter-api\5.14.4\junit-jupiter-api-5.14.4.jar;D:\app\apache-maven-3.9.9\jarrepository\org\opentest4j\opentest4j\1.3.0\opentest4j-1.3.0.jar;D:\app\apache-maven-3.9.9\jarrepository\org\junit\platform\junit-platform-commons\1.14.4\junit-platform-commons-1.14.4.jar;D:\app\apache-maven-3.9.9\jarrepository\org\apiguardian\apiguardian-api\1.1.2\apiguardian-api-1.1.2.jar" com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit5 com.neuedu.spring.service.UserServiceTest,queryUser
org.junit.platform.launcher.core.DiscoveryIssueException: TestEngine with ID 'junit-jupiter' encountered a critical issue during test discovery:
(1) [ERROR] MethodSelector [className = 'com.neuedu.spring.service.UserServiceTest', methodName = 'queryUser', parameterTypes = '', classLoader = null] resolution failed
Source: MethodSource [className = 'com.neuedu.spring.service.UserServiceTest', methodName = 'queryUser', methodParameterTypes = '']
at com.neuedu.spring.service.UserServiceTest.queryUser(SourceFile:0)
Cause: java.lang.ClassCircularityError: java/lang/WeakPairMap$Pair$Weak
at java.base/java.lang.WeakPairMap$Pair.weak(WeakPairMap.java:201)
at java.base/java.lang.WeakPairMap.putIfAbsent(WeakPairMap.java:123)
at java.base/java.lang.Module.implAddReads(Module.java:551)
at java.base/java.lang.Module.implAddReads(Module.java:512)
at java.base/java.lang.System$2.addReads(System.java:2422)
at java.base/jdk.internal.module.Modules.addReads(Modules.java:90)
at java.base/java.lang.reflect.Proxy$ProxyBuilder.lambda$getDynamicModule$1(Proxy.java:915)
at java.base/jdk.internal.loader.AbstractClassLoaderValue$Memoizer.get(AbstractClassLoaderValue.java:329)
at java.base/jdk.internal.loader.AbstractClassLoaderValue.computeIfAbsent(AbstractClassLoaderValue.java:205)
at java.base/java.lang.reflect.Proxy$ProxyBuilder.getDynamicModule(Proxy.java:905)
at java.base/java.lang.reflect.Proxy$ProxyBuilder.proxyClassContext(Proxy.java:840)
at java.base/java.lang.reflect.Proxy$ProxyBuilder.(Proxy.java:638)
at java.base/java.lang.reflect.Proxy$ProxyBuilder.(Proxy.java:643)
at java.base/java.lang.reflect.Proxy.lambda$getProxyConstructor$0(Proxy.java:429)
at java.base/jdk.internal.loader.AbstractClassLoaderValue$Memoizer.get(AbstractClassLoaderValue.java:329)
at java.base/jdk.internal.loader.AbstractClassLoaderValue.computeIfAbsent(AbstractClassLoaderValue.java:205)
at java.base/java.lang.reflect.Proxy.getProxyConstructor(Proxy.java:427)
at java.base/java.lang.reflect.Proxy.newProxyInstance(Proxy.java:1034)
at java.base/sun.reflect.annotation.AnnotationParser$1.run(AnnotationParser.java:301)
at java.base/sun.reflect.annotation.AnnotationParser$1.run(AnnotationParser.java:299)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:319)
at java.base/sun.reflect.annotation.AnnotationParser.annotationForMap(AnnotationParser.java:299)
at java.base/sun.reflect.annotation.AnnotationParser.parseAnnotation2(AnnotationParser.java:288)
at java.base/sun.reflect.annotation.AnnotationParser.parseAnnotations2(AnnotationParser.java:121)
at java.base/sun.reflect.annotation.AnnotationParser.parseSelectAnnotations(AnnotationParser.java:102)
at java.base/sun.reflect.annotation.AnnotationType.(AnnotationType.java:146)
at java.base/sun.reflect.annotation.AnnotationType.getInstance(AnnotationType.java:85)
at java.base/sun.reflect.annotation.AnnotationParser.parseAnnotation2(AnnotationParser.java:262)
at java.base/sun.reflect.annotation.AnnotationParser.parseAnnotations2(AnnotationParser.java:121)
at java.base/sun.reflect.annotation.AnnotationParser.parseAnnotations(AnnotationParser.java:73)
at java.base/java.lang.Class.createAnnotationData(Class.java:4246)
at java.base/java.lang.Class.annotationData(Class.java:4235)
at java.base/java.lang.Class.getAnnotation(Class.java:4118)
at java.base/java.lang.reflect.AnnotatedElement.isAnnotationPresent(AnnotatedElement.java:292)
at java.base/java.lang.Class.isAnnotationPresent(Class.java:4128)
at org.junit.platform.commons.util.AnnotationUtils.findAnnotation(AnnotationUtils.java:136)
at org.junit.platform.commons.util.AnnotationUtils.isAnnotated(AnnotationUtils.java:105)
at org.junit.platform.commons.support.AnnotationSupport.isAnnotated(AnnotationSupport.java:97)
at org.junit.jupiter.engine.discovery.predicates.TestClassPredicates.isAnnotatedButNotComposed(TestClassPredicates.java:168)
at org.junit.jupiter.engine.discovery.predicates.TestClassPredicates.lambda$new$0(TestClassPredicates.java:47)
at org.junit.jupiter.engine.discovery.predicates.TestClassPredicates.lambda$new$3(TestClassPredicates.java:54)
at org.junit.jupiter.engine.discovery.MethodSelectorResolver.resolve(MethodSelectorResolver.java:105)
at org.junit.jupiter.engine.discovery.MethodSelectorResolver.resolve(MethodSelectorResolver.java:78)
at org.junit.platform.engine.support.discovery.EngineDiscoveryRequestResolution.lambda$resolve$2(EngineDiscoveryRequestResolution.java:150)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
at java.base/java.util.ArrayList$ArrayListSpliterator.tryAdvance(ArrayList.java:1685)
at java.base/java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:129)
at java.base/java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:527)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:513)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
at java.base/java.util.stream.FindOps$FindOp.evaluateSequential(FindOps.java:150)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.findFirst(ReferencePipeline.java:647)
at org.junit.platform.engine.support.discovery.EngineDiscoveryRequestResolution.resolve(EngineDiscoveryRequestResolution.java:189)
at org.junit.platform.engine.support.discovery.EngineDiscoveryRequestResolution.resolve(EngineDiscoveryRequestResolution.java:126)
at org.junit.platform.engine.support.discovery.EngineDiscoveryRequestResolution.resolveCompletely(EngineDiscoveryRequestResolution.java:92)
at org.junit.platform.engine.support.discovery.EngineDiscoveryRequestResolution.run(EngineDiscoveryRequestResolution.java:83)
at org.junit.platform.engine.support.discovery.EngineDiscoveryRequestResolver.resolve(EngineDiscoveryRequestResolver.java:149)
at org.junit.jupiter.engine.discovery.DiscoverySelectorResolver.resolveSelectors(DiscoverySelectorResolver.java:63)
at org.junit.jupiter.engine.JupiterTestEngine.discover(JupiterTestEngine.java:70)
at org.junit.platform.launcher.core.EngineDiscoveryOrchestrator.discoverEngineRoot(EngineDiscoveryOrchestrator.java:195)
at org.junit.platform.launcher.core.EngineDiscoveryOrchestrator.discoverSafely(EngineDiscoveryOrchestrator.java:174)
at org.junit.platform.launcher.core.EngineDiscoveryOrchestrator.discover(EngineDiscoveryOrchestrator.java:119)
at org.junit.platform.launcher.core.EngineDiscoveryOrchestrator.discover(EngineDiscoveryOrchestrator.java:84)
at org.junit.platform.launcher.core.DefaultLauncher.discover(DefaultLauncher.java:104)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:91)
at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:47)
at org.junit.platform.launcher.core.InterceptingLauncher.lambda$execute$1(InterceptingLauncher.java:39)
at org.junit.platform.launcher.core.ClasspathAlignmentCheckingLauncherInterceptor.intercept(ClasspathAlignmentCheckingLauncherInterceptor.java:25)
at org.junit.platform.launcher.core.InterceptingLauncher.execute(InterceptingLauncher.java:38)
at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:47)
at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:66)
at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:57)
at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:232)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:55)
Process finished with exit code -1
# 使用包扫描的形式注册


- Controller ( 目前可以随便写 后面使用Spirngmvc的时候有特殊要求)
- @RestController
- Repository
- Service
- Component
除了@Component这个泛指组件的注解外,Spring还提供了与@Component功能相同的三个语义化注解。
1. @Service 业务层组件
2. @Controller 控制层组件
3. @Repository 数据层组件
修改上面代码,使用@Repository 和 @Service 替换 dao 与 service 组件上的注解。
# BeanFactory与ApplicationContext
获取Spring容器也可以使用BeanFactory接口。BeanFactory与ApplicationContext的区别是:
1. BeanFactory
Bean工厂(org.springframework.beans.factory.BeanFactory)是Spring框架最核心的接口,提供了IoC的配置机制,使管理不同类型的Java对象成为可能。特点是:采用延迟加载Bean,直到第一次使用Bean实例时才会创建Bean。
2. ApplicationContext
应用上下文(org.springframework.context.ApplicationContext),继承自BeanFactory,提供了更多面向应用的功能,比如国际化支持、框架事件体系,更易于创建实际应用。
应用时,我们一般称BeanFactory为IoC容器,ApplicationContext为应用上下文:
1. BeanFactory是Spring框架的基础设施,面向Spring本身;
2. ApplicationContext面向使用Spring框架的开发者;
3. 几乎所有的应用场合都可以直接使用ApplicationContext而非底层的BeanFactory;

# AOP 面向切面编程
AOP:全称是 Aspect Oriented Programming 即:面向切面编程。
简单的说它就是把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对我们的已有方法进行增强。
即当需要扩展功能时,传统方式采用纵向继承方式实现。但这种方式有很多缺点。 比如:父类方法名称改变时,子类也要修改。给多个方法扩展功能时,子类也需要修改。 因此,spring的AOP,实际上是采用横向抽取机制,取代传统的纵向继承体系。
实现AOP示意图:
1. 先将方面代码抽取出来

2. 运行时将业务代码和方面代码编织在一起



通知 Around
### 切面(Aspect)
切面是切点和通知组成,通知和切点共同定义了切面的全部内容即:它是什么,在何时何处完成其功能;
举例:将pointcut和Advice配置整合的过程切面
### 连接点(Joinpoint)
连接点是在应用执行过程中能够插入切面的一个点,Spring仅支持方法的连接点,即仅能在方法调用前,方法调用后,方法抛出异常时及方法调用前后插入切面代码。 .
举例:如果在insert之前执行扩展(增强、通知),简单理解insert这个方法可以称之为连接点。
连接点: 1 Com.neuedu.service.StuServiceImpl.insert()
连接点: 2 Com.neuedu.service.UserServiceImpl.insert()
### 切点(Pointcut)
```
Com.neuedu.service.*Impl.insert()
```
### 通知(Advice)、增强
切面的工作被成为通知,定义了切面是什么及何时使用。除了描述切面要完成的工作,通知还解决了何时执行这个工作的问题,它应该在某个方法被调用之前?之后?等。
举例:额外定义一个方法想要在连接点上进行扩展的功能
#### Spring切面可以应用5种类型的通知:
前置通知(Before)在目标方法被调用之前调用通知功能;
后置通知(After)在目标方法被完成之后调用通知功能,不关心方法的输出是什么;
环绕通知(Around advice)通知包裹了目标方法,在目标方法调用之前和之后执行自定义的行为;
异常通知(After-throwing)在目标方法抛出异常后调用通知;
返回通知(After-returning)在目标方法成功执行之后调用通知;
### 目标对象(Target)
通知逻辑的织入目标类。如果没有AOP,那么目标业务类需要自己实现所有的逻辑,在AOP的帮助下,目标类只需要实现那些非横切逻辑的程序逻辑,而比如事务管理等这些横切逻辑就可以使用AOP动态织入特定的连接点上。
举例:两个Service即是目标对象
### 引入(Introduction)
引介是一种特殊的通知,为类添加一些属性和方法。这样,即使一个业务类原本没有实现某个接口,通过AOP的引介功能,也可以动态地为该业务类添加接口的实现逻辑,使业务类成为这个接口的实现类。
几乎由框架完成,我们可以暂时透明
### 代理(Proxy)
一个类被AOP织入通知后,就产生一个结果类,它是融合了原类和通知逻辑的代理类。根据不同的代理方式,代理类既可能是和原类具有相同接口的类,也可能就是原类的子类,所以可以采用与调用原类相同的方式调用代理类。
举例:IOC容器创建的两个Service类型对象
### 织入(Weaving)
织入是将通知添加到目标类的具体连接点上的过程.AOP就像一台织布机,将目标类,通知或引介编织到一起。 AOP有三种织入方式: ①编译期织入:切面在目标类编译时被织入,需要特殊的编译器; ②类装载期织入:切面在目标类加载到JVM时被织入,需要特殊的类装载器; ③动态代理织入:切面在应用运行的某个时刻呗织入,AOP容器会为目标对象动态创建一个代理对象;
- 编写Service
- 增强的代码(通知)
- 配置前面
05-aop-xml


# Spring整合Mybatis
- Spring的项目(xml、javaconfig)
- 添加依赖
- spring-context
- spring-aop
- aspectjweaver
- spring-test
- junit
- spring-jdbc
- mysql驱动
- mybatis
- mybatis-spring
- 数据源:druid
- lombok
- 编写service
- 编写配置文件 spring-mybatis.xml
- 包扫描
- 编写MyBatis
- 核心配置文件 SqlMapConfig.xml
- 编写实体类 Emp
- 编写EmpMapper.xml
- 编写EmpMapper.java
- 就的SqlSessionFactory测试
- 整合
- 数据源 druid
- 把SqlSessionFactory放到IOC容器中
- 在容器中管理Mapper的代理对象
- 整合测试 使用@Autowired从容器中获取Mapper
## 创建项目

## 添加依赖
### 父项目
```xml
4.0.0com.neuedu.springspring-learn1.0pomspring-learnhttp://maven.apache.org01-spring-helloword-xml02-spring-package-scan03-spring-qualifier04-spring-javaconfig05-aop-xml06-aop-xml-annotation07-aop-javaconfig-annotation08-spring-mybatis-xmlUTF-86.2.195.14.41.8.78.4.03.5.61.18.481.2.284.0.0org.springframeworkspring-core${spring.version}compileorg.springframeworkspring-aop${spring.version}compileorg.aspectjaspectjweaver${aspectj.version}org.springframeworkspring-beans${spring.version}compileorg.springframeworkspring-context${spring.version}compileorg.springframeworkspring-expression${spring.version}compileorg.springframeworkspring-test${spring.version}compileorg.springframeworkspring-jdbc${spring.version}compileorg.junit.jupiterjunit-jupiter-api${junit.version}testcom.mysqlmysql-connector-j${mysql.version}compileorg.mybatismybatis${mybatis.version}org.projectlomboklombok${lombok.version}providedcom.alibabadruid${druid.version}compileorg.mybatismybatis-spring${mybatis.spring.version}compile
```
### 子项目
```xml
4.0.0com.neuedu.springspring-learn1.008-spring-mybatis-xmljar08-spring-mybatis-xmlhttp://maven.apache.orgUTF-8org.springframeworkspring-contextorg.springframeworkspring-aoporg.aspectjaspectjweaverorg.springframeworkspring-testorg.springframeworkspring-jdbcorg.junit.jupiterjunit-jupiter-apicom.mysqlmysql-connector-jorg.mybatismybatisorg.projectlomboklombokcom.alibabadruidorg.mybatismybatis-spring
```

## 搭建spring
### 编写Service
```java
package com.neuedu.spring.service;
import com.neuedu.spring.po.Emp;
import org.springframework.stereotype.Service;
/***
*
* 项目名称: spring-learn
* 类名称:com.neuedu.spring.service
* 类描述:
* 创建人:金山老师
* 创建时间:2026/11/03 13:36
* 版本:1.0
*
*/
@Service
public class EmpService {
public Emp queryById(int id){
System.out.println("根据id查询数据库");
return new Emp(); //根据id查询数据库
}
}
```
### 配置文件
spring-mybaits.xml
```xml
```
### 单元测试
```java
package com.neuedu.spring.service;
import com.neuedu.spring.po.Emp;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import static org.junit.jupiter.api.Assertions.*;
/***
*
* 项目名称: spring-learn
* 类名称:com.neuedu.spring.service
* 类描述:
* 创建人:金山老师
* 创建时间:2026/11/03 13:39
* 版本:1.0
*
*/
@SpringJUnitConfig(locations = "classpath:spring-mybaits.xml")
class EmpServiceTest {
@Autowired
private EmpService empService;
@Test
void queryById1() {
System.out.println(empService);
Emp emp = empService.queryById(10);
}
}
```
## 在spring中管理数据源
获取连接对象Connection
Druid
[Apache Druid | Apache® Druid](https://druid.apache.org/)

### 单元测试
```java
package com.neuedu.spring.service;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
/***
*
* 项目名称: spring-learn
* 类名称:com.neuedu.spring.service
* 类描述:
* 创建人:金山老师
* 创建时间:2026/11/03 14:01
* 版本:1.0
*
*
*
* spring-mybatis.xml
* spring-mybatis.xml
*
*
*/
@SpringJUnitConfig(locations = "classpath:spring-mybatis.xml")
public class DataSourceTest {
@Autowired
private DataSource dataSource;
@Test
public void testConnection(){
try {
Connection connection = dataSource.getConnection();
System.out.println("connection = " + connection);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
```
## 整合MyBaits
### 编写SqlMapconfig.xml
```xml
```
### 实体类
```java
package com.neuedu.spring.po;
import lombok.Data;
import java.util.Date;
/***
*
* 项目名称: spring-learn
* 类名称:com.neuedu.spring.po
* 类描述:
* 创建人:金山老师
* 创建时间:2026/11/03 13:37
* 版本:1.0
*
*/
@Data
public class Emp {
private Integer empno ;
private String ename ;
private String job ;
private Integer mgr ;
private Date hiredate ;
private Double sal ;
private String comm ;
private Double deptno ;
}
```
### Mapper.java

```java
package com.neuedu.spring.mapper;
import com.neuedu.spring.po.Emp;
import java.util.List;
/***
*
* 项目名称: mybatis-app
* 类名称:com.neuedu.mybatis.mapper
* 类描述:
* 创建人:金山老师
* 创建时间:2026/10/26 10:40
* 版本:1.0
*
*/
public interface EmpMapper {
public List selectList();
public Emp selectById( int id );
public long total( );
public int updateById(Emp emp);
public int insert(Emp emp);
public int deleteById (int id );
}
```
### Mapper.xml
```xml
`empno`, `ename`, `job`, `mgr`, `hiredate`, `sal`, `comm`, `deptno`
UPDATE
`emp`
`ename` = #{ename}, `job` = #{job}, `mgr` = #{mgr}, `hiredate` = #{hiredate}, `sal` = #{sal}, `comm` = #{comm}, `deptno` = #{deptno},
WHERE `empno` = #{empno} ;
INSERT INTO `emp`
`empno` , `ename` , `job` , `mgr` , `hiredate` , `sal` , `comm` , `deptno` ,
VALUES
#{empno},#{ename},#{job},#{mgr},#{hiredate},#{sal},#{comm},#{deptno},
delete from emp where empno = #{empno}
```
## 使用spring管理 SqlSessionFactory
在spring-mybaits.xml中配置
```xml
```
## 在容器中声明一个Mapper

## 批量注册Mapper到Spring容器
```xml
```

# 事务管理器
使用AOP 在 需要添加事务的 service方法上 增加额外的代码( 通知、增强 )
只需要配置事务管理器
```
```
在serice 中编写了一个需要事务的方法
```java
/**
* sal 字段暂时当做 账户余额
* @param success
* @return
*/
public boolean transfer(boolean success){
int id1 = 7369; //SMITH 7369 800.00 + 500 = 1300
int id2 = 7788; //SCOTT 7788 3000.00 - 500 = 2500
Emp smith = empMapper.selectById(id1);
Emp scott = empMapper.selectById(id2);
//内存中修改了下数据
smith.setSal(smith.getSal() + 500);
scott.setSal(smith.getSal() - 500);
int count1 = empMapper.updateById(smith);
//中间过程还有一些代码逻辑,可能产生错误
if(!success){
throw new RuntimeException("保存smith的余额之后报错了 ");
}
int count2 = empMapper.updateById(scott);
return count1 + count2 == 2;
}
```
## 单元测试
```java
@Test
void transfer() {
//success 模拟代码是否成功、出错
boolean success = false;
boolean result = empService.transfer(success);
System.out.println("result = " + result);
}
```
## 添加事务
在容器中声明事务管理器
```xml
```
## 传播特性

## 使用@Transactional待提xml切面

# 纯注解的方式实现spring-mybais整合

# SpringMVC
[SpringMVC 官网文档](https://docs.spring.io/spring-framework/reference/6.2/web.html)


- web项目
- 配置tomcat
- 添加依赖
- Handler(Controller)自定义
- 编写-spring-web.xml 容器的配置文件
- web.xml
- 配置前端控制器(DispatcherServlet)
- 读取spring-web.xml
- 发布到Tomcat测试
## HelloWorld

### 添加依赖
需要父项目和子项目中都添加依赖
```xml
4.0.0com.neuedu.springspring-learn1.012-springmvc-helloworldwar12-springmvc-helloworld Maven Webappjakarta.servletjakarta.servlet-apiorg.springframeworkspring-webmvc
```


### 编写Controller
```java
package com.neuedu.his.controller;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import java.sql.Array;
import java.util.ArrayList;
import java.util.List;
/***
*
* 项目名称: spring-learn
* 类名称:com.neuedu.his.controller
* 类描述:
* 创建人:金山老师
* 创建时间:2026/11/04 14:22
* 版本:1.0
*
*/
@Controller
public class UserController {
/***
* http://localhost:8080/web/user/index
* @param request
* @return
*/
@RequestMapping("/user/index")
public String index(HttpServletRequest request){
//从数据库查询数据
List list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add("张三"+i);
}
//设置数据
request.setAttribute("userList",list);
return "/user/list.jsp";
}
}
```
```jsp
<%@ page import="java.util.List" %><%--
Created by IntelliJ IDEA.
User: Administrator
Date: 2026/11/4
Time: 14:23
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
用户表格
序号
姓名
<%
List list = (List) request.getAttribute("userList");
%>
<%
for (int i = 0; i < list.size(); i++) {
String name = list.get(i);
%>
<%=i%>
<%=name%>
<% }
%>
```
配置核心的配置文件
### spring-mvc.xml
```xml
```
### 配置前端控制器
web.xml中配置
```xml
DispatcherServletorg.springframework.web.servlet.DispatcherServletcontextConfigLocationclasspath:spring-mvc.xmlDispatcherServlet/
```

## 整合Spring、Mybaits
从11 复制代码 注意包
原来com.neuedu.spring
现在com.neuedu.his

### 依赖
```xml
4.0.0com.neuedu.springspring-learn1.012-springmvc-helloworldwar12-springmvc-helloworld Maven Webappjakarta.servletjakarta.servlet-apiorg.springframeworkspring-webmvcorg.aspectjaspectjweaverorg.springframeworkspring-testorg.springframeworkspring-jdbcorg.junit.jupiterjunit-jupiter-apicom.mysqlmysql-connector-jorg.mybatismybatisorg.projectlomboklombokcom.alibabadruidorg.mybatismybatis-spring
```

# SpringMVC 的参数绑定
[Method Arguments :: Spring Framework](https://docs.spring.io/spring-framework/reference/6.2/web/webmvc/mvc-controller/ann-methods/arguments.html)
| Controller method argument | Description |
| :----------------------------------------------------------- | :----------------------------------------------------------- |
| `WebRequest`, `NativeWebRequest` | Generic access to request parameters and request and session attributes, without direct use of the Servlet API. |
| `jakarta.servlet.ServletRequest`, `jakarta.servlet.ServletResponse` | Choose any specific request or response type — for example, `ServletRequest`, `HttpServletRequest`, or Spring’s `MultipartRequest`, `MultipartHttpServletRequest`. |
| `jakarta.servlet.http.HttpSession` | Enforces the presence of a session. As a consequence, such an argument is never `null`. Note that session access is not thread-safe. Consider setting the `RequestMappingHandlerAdapter` instance’s `synchronizeOnSession` flag to `true` if multiple requests are allowed to concurrently access a session. |
| `jakarta.servlet.http.PushBuilder` | Servlet 4.0 push builder API for programmatic HTTP/2 resource pushes. Note that, per the Servlet specification, the injected `PushBuilder` instance can be null if the client does not support that HTTP/2 feature. |
| `java.security.Principal` | Currently authenticated user — possibly a specific `Principal` implementation class if known.Note that this argument is not resolved eagerly, if it is annotated in order to allow a custom resolver to resolve it before falling back on default resolution via `HttpServletRequest#getUserPrincipal`. For example, the Spring Security `Authentication` implements `Principal` and would be injected as such via `HttpServletRequest#getUserPrincipal`, unless it is also annotated with `@AuthenticationPrincipal` in which case it is resolved by a custom Spring Security resolver through `Authentication#getPrincipal`. |
| `HttpMethod` | The HTTP method of the request. |
| `java.util.Locale` | The current request locale, determined by the most specific `LocaleResolver` available (in effect, the configured `LocaleResolver` or `LocaleContextResolver`). |
| `java.util.TimeZone` + `java.time.ZoneId` | The time zone associated with the current request, as determined by a `LocaleContextResolver`. |
| `java.io.InputStream`, `java.io.Reader` | For access to the raw request body as exposed by the Servlet API. |
| `java.io.OutputStream`, `java.io.Writer` | For access to the raw response body as exposed by the Servlet API. |
| `@PathVariable` | For access to URI template variables. See [URI patterns](https://docs.spring.io/spring-framework/reference/6.2/web/webmvc/mvc-controller/ann-requestmapping.html#mvc-ann-requestmapping-uri-templates). |
| `@MatrixVariable` | For access to name-value pairs in URI path segments. See [Matrix Variables](https://docs.spring.io/spring-framework/reference/6.2/web/webmvc/mvc-controller/ann-methods/matrix-variables.html). |
| `@RequestParam` | For access to the Servlet request parameters, including multipart files. Parameter values are converted to the declared method argument type. See [`@RequestParam`](https://docs.spring.io/spring-framework/reference/6.2/web/webmvc/mvc-controller/ann-methods/requestparam.html) as well as [Multipart](https://docs.spring.io/spring-framework/reference/6.2/web/webmvc/mvc-controller/ann-methods/multipart-forms.html).Note that use of `@RequestParam` is optional for simple parameter values. See “Any other argument”, at the end of this table. |
| `@RequestHeader` | For access to request headers. Header values are converted to the declared method argument type. See [`@RequestHeader`](https://docs.spring.io/spring-framework/reference/6.2/web/webmvc/mvc-controller/ann-methods/requestheader.html). |
| `@CookieValue` | For access to cookies. Cookies values are converted to the declared method argument type. See [`@CookieValue`](https://docs.spring.io/spring-framework/reference/6.2/web/webmvc/mvc-controller/ann-methods/cookievalue.html). |
| `@RequestBody` | For access to the HTTP request body. Body content is converted to the declared method argument type by using `HttpMessageConverter` implementations. See [`@RequestBody`](https://docs.spring.io/spring-framework/reference/6.2/web/webmvc/mvc-controller/ann-methods/requestbody.html). |
| `HttpEntity` | For access to request headers and body. The body is converted with an `HttpMessageConverter`. See [HttpEntity](https://docs.spring.io/spring-framework/reference/6.2/web/webmvc/mvc-controller/ann-methods/httpentity.html). |
| `@RequestPart` | For access to a part in a `multipart/form-data` request, converting the part’s body with an `HttpMessageConverter`. See [Multipart](https://docs.spring.io/spring-framework/reference/6.2/web/webmvc/mvc-controller/ann-methods/multipart-forms.html). |
| `java.util.Map`, `org.springframework.ui.Model`, `org.springframework.ui.ModelMap` | For access to the model that is used in HTML controllers and exposed to templates as part of view rendering. |
| `RedirectAttributes` | Specify attributes to use in case of a redirect (that is, to be appended to the query string) and flash attributes to be stored temporarily until the request after redirect. See [Redirect Attributes](https://docs.spring.io/spring-framework/reference/6.2/web/webmvc/mvc-controller/ann-methods/redirecting-passing-data.html) and [Flash Attributes](https://docs.spring.io/spring-framework/reference/6.2/web/webmvc/mvc-controller/ann-methods/flash-attributes.html). |
| `@ModelAttribute` | For access to an existing attribute in the model (instantiated if not present) with data binding and validation applied. See [`@ModelAttribute`](https://docs.spring.io/spring-framework/reference/6.2/web/webmvc/mvc-controller/ann-methods/modelattrib-method-args.html) as well as [Model](https://docs.spring.io/spring-framework/reference/6.2/web/webmvc/mvc-controller/ann-modelattrib-methods.html) and [`DataBinder`](https://docs.spring.io/spring-framework/reference/6.2/web/webmvc/mvc-controller/ann-initbinder.html).Note that use of `@ModelAttribute` is optional (for example, to set its attributes). See “Any other argument” at the end of this table. |
| `Errors`, `BindingResult` | For access to errors from validation and data binding for a command object (that is, a `@ModelAttribute` argument) or errors from the validation of a `@RequestBody` or `@RequestPart` arguments. You must declare an `Errors`, or `BindingResult` argument immediately after the validated method argument. |
| `SessionStatus` + class-level `@SessionAttributes` | For marking form processing complete, which triggers cleanup of session attributes declared through a class-level `@SessionAttributes` annotation. See [`@SessionAttributes`](https://docs.spring.io/spring-framework/reference/6.2/web/webmvc/mvc-controller/ann-methods/sessionattributes.html) for more details. |
| `UriComponentsBuilder` | For preparing a URL relative to the current request’s host, port, scheme, context path, and the literal part of the servlet mapping. See [URI Links](https://docs.spring.io/spring-framework/reference/6.2/web/webmvc/mvc-uri-building.html). |
| `@SessionAttribute` | For access to any session attribute, in contrast to model attributes stored in the session as a result of a class-level `@SessionAttributes` declaration. See [`@SessionAttribute`](https://docs.spring.io/spring-framework/reference/6.2/web/webmvc/mvc-controller/ann-methods/sessionattribute.html) for more details. |
| `@RequestAttribute` | For access to request attributes. See [`@RequestAttribute`](https://docs.spring.io/spring-framework/reference/6.2/web/webmvc/mvc-controller/ann-methods/requestattrib.html) for more details. |
| Any other argument | If a method argument is not matched to any of the earlier values in this table and it is a simple type (as determined by [BeanUtils#isSimpleProperty](https://docs.spring.io/spring-framework/docs/6.2.19/javadoc-api/org/springframework/beans/BeanUtils.html#isSimpleProperty(java.lang.Class))), it is resolved as a `@RequestParam`. Otherwise, it is resolved as a `@ModelAttribute`. |
## @RequestParam
用于访问 Servlet 请求参数,包括多部分文件。参数值 转换为声明的方法参数类型。也请参见[`@RequestParam`](https://docs.spring.io/spring-framework/reference/6.2/web/webmvc/mvc-controller/ann-methods/requestparam.html) 作为[多部分](https://docs.spring.io/spring-framework/reference/6.2/web/webmvc/mvc-controller/ann-methods/multipart-forms.html)。
注意,对于简单参数值,使用该值是可选的。 参见本表末尾的“其他论证”。`@RequestParam`
```
@ResponseBody //将返回结果转换成json
@RequestMapping("/emp/getById")
public String getById(@RequestParam("id") int id){
Emp emp = empService.queryById(id);
String json = "{\"ename\": \""+ emp.getEname()+"\",\"empno\": \""+ emp.getEmpno()+"\"}";
return json;
}
```