1. MVC开发模式
1.1. 运行流程
1.2. SpringMVC 核心组件
1.3. 注解解释
2. ORM与MyBatis
2.1. ORM—对象关系映射
2.2. MyBatis
2.2.1. 创建步骤
会话是单例的,不能跨方法。(单例的原因主要是从数据安全角度出发)
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;import java.io.IOException;
import java.io.Reader;
import java.util.List;public class MyBatisExample {public static void main(String[] args) {SqlSessionFactory sqlSessionFactory = null;try (Reader reader = Resources.getResourceAsReader("mybatis-config.xml")) {sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);} catch (IOException e) {e.printStackTrace();}try (SqlSession session = sqlSessionFactory.openSession()) {// 获取 Mapper 接口的代理对象UserMapper userMapper = session.getMapper(UserMapper.class);// 使用 Mapper 接口的方法执行 SQL 操作1User user = userMapper.selectUserById(1);System.out.println(user);User newUser = new User();newUser.setName("John");newUser.setAge(30);// 使用 Mapper 接口的方法执行 SQL 操作2userMapper.insertUser(newUser);session.commit(); // 提交事务// 使用 Mapper 接口的方法执行 SQL 操作3List<User> users = userMapper.selectAllUsers();for (User u : users) {System.out.println(u);}} catch (Exception e) {e.printStackTrace();}}
}
2.2.2. mybatis-config.xml 配置
UserDao 是接口,在 namespace 必须是完整的路径。
2.2.3. sql 注入
2.2.4. 动态 SQL
if 和 where 是最重要的。
2.2.4.1. if
2.2.4.2. where
where 可以自动选择去掉多余的 and
2.2.4.3. set
set 可以自动去掉多余的 ,
2.2.4.4. foreach 语句
collection 是集合的变量名
。
2.2.4.5. trim 标签
2.2.4.6. choose、when、otherwise
2.2.5. Mybatis 的结果类型(使用 resultMap 和 resultType)
2.2.5.1. resultMap 的详细使用
在 MyBatis 中,resultMap
是一个非常重要的标签,它主要用于复杂的结果映射,特别是当数据库表的列名和 Java 对象的属性名不一致,或者需要映射关联关系(如一对一、一对多等)时。以下是 resultMap
的详细使用方法:
一、基本使用步骤
- 定义
resultMap
:
在 Mapper XML 文件中,首先定义一个resultMap
,指定id
(用于在 SQL 语句中引用该结果映射)和type
(映射结果的 Java 类型)。
<resultMap id="userResultMap" type="com.example.User"><id property="id" column="user_id"/><result property="userName" column="user_name"/><result property="age" column="user_age"/>
</resultMap>
在上述 resultMap
中:
id="userResultMap"
:是结果映射的唯一标识符,后续会在select
语句中使用。type="com.example.User"
:表示映射的 Java 类型是com.example.User
类。<id>
标签:用于映射主键,property
是 Java 对象的属性名,column
是数据库表的列名。<result>
标签:用于映射非主键的普通列,property
是 Java 对象的属性名,column
是数据库表的列名。
- 在
select
语句中使用resultMap
:
将resultMap
应用于select
语句中,而不是resultType
。
<select id="selectUserById" resultMap="userResultMap">select user_id, user_name, user_age from users where user_id = #{id}
</select>
二、处理复杂对象映射
当处理对象之间的关联关系时,resultMap
变得更加重要。
2.2.5.1.1. 一对一关联映射
假设 User
类中有一个 Address
对象作为属性,并且 Address
存储在另一个表中,需要进行一对一关联映射。
- 首先,在
User
类中添加Address
属性:
public class User {private int id;private String userName;private int age;private Address address;// getters and setters
}
- 然后,在 Mapper XML 文件中定义
resultMap
包含association
元素:
<resultMap id="userWithAddressResultMap" type="com.example.User"><id property="id" column="user_id"/><result property="userName" column="user_name"/><result property="age" column="user_age"/><association property="address" javaType="com.example.Address"><id property="id" column="address_id"/><result property="street" column="address_street"/><result property="city" column="address_city"/><result property="zipcode" column="address_zipcode"/></association></resultMap>
- 在
select
语句中使用该resultMap
:
<select id="selectUserWithAddressById" resultMap="userWithAddressResultMap">select u.user_id, u.user_name, u.user_age, a.address_id, a.address_street, a.address_city, a.address_zipcodefrom users ujoin addresses a on u.user_id = a.user_idwhere u.user_id = #{id}
</select>
2.2.5.1.2. 一对多关联映射
假设 User
类中有一个 List<Order>
表示用户的多个订单,需要进行一对多关联映射。
- 在
User
类中添加List<Order>
属性:
public class User {private int id;private String userName;private int age;private List<Order> orders;// getters and setters
}
- 在 Mapper XML 文件中定义
resultMap
包含collection
元素:
<resultMap id="userWithOrdersResultMap" type="com.example.User"><id property="id" column="user_id"/><result property="userName" column="user_name"/><result property="age" column="user_age"/><collection property="orders" ofType="com.example.Order"><id property="id" column="order_id"/><result property="orderName" column="order_name"/><result property="amount" column="order_amount"/></collection></resultMap>
- 在
select
语句中使用该resultMap
:
<select id="selectUserWithOrdersById" resultMap="userWithOrdersResultMap">select u.user_id, u.user_name, u.user_age, o.order_id, o.order_name, o.order_amountfrom users ujoin orders o on u.user_id = o.user_idwhere u.user_id = #{id}
</select>
三、继承和扩展 resultMap
可以使用 extends
属性扩展已有的 resultMap
,以避免重复定义。
<resultMap id="extendedUserResultMap" type="com.example.User" extends="userResultMap"><result property="email" column="user_email"/>
</resultMap>
四、使用 resultMap
的好处
- 灵活映射:可以处理各种复杂的映射情况,包括列名和属性名不匹配、关联对象映射等。
- 代码清晰:将结果映射的逻辑集中在 XML 文件中,使得 SQL 语句和结果映射逻辑清晰,易于维护。
五、注意事项
- 列名和属性名:确保
resultMap
中的column
与 SQL 语句中的列名一致,property
与 Java 对象的属性名一致。 - 关联关系:使用
association
处理一对一关系,使用collection
处理一对多关系,确保关联的对象和集合类型正确。
使用 resultMap
可以让 MyBatis 更好地处理复杂的结果映射,使数据库结果能够准确地映射到 Java 对象及其关联对象或集合,提供了强大而灵活的结果映射机制,特别是在处理对象之间的复杂关系时,它是 MyBatis 实现对象关系映射的关键元素。
2.2.5.2. typeAliases
2.2.6. 查询的 resultType
2.2.7. sql 抽取
3. Spring MVC
SpringMVC 中有默认的编码拦截器
,所以不用管乱码的问题。
3.1. Spring MVC工作原理
3.2. 控制器编写
3.3. 拦截器
3.3.1. 拦截器配置
3.3.1.1. 编写拦截器
3.3.1.2. 配置拦截器
3.3.1.2.1. 基于代码
3.3.1.2.2. 基于 xml
3.3.2. 单个拦截器
3.3.3. 多个拦截器
4. Spring
4.1. Spring 体系结构
4.2. 核心容器
4.3. web
4.4. 数据访问
4.5. 其他模块
4.6. Spring 特征
4.7. IOC
4.8. DI
4.9. Bean配置(重点)
使用ApplicationContext 对象获取 bean:
bean 的配置文件:
4.9.1. xml 的四种方式配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><!-- 1.使用property标签--><bean id="book" class="com.bean.Book"><!-- 如果类中有显示构造函数,则必须加上这两行--><constructor-arg index="0" value=""/><constructor-arg index="1" value=""/><property name="name" value="书名0"></property><property name="price" value="2022.12"></property></bean><!-- 2.使用 构造器+index 标签--><bean id="book" class="com.bean.Book"><constructor-arg index="0" value="书名1"/><constructor-arg index="1" value="2024.12"/></bean><!-- 3.使用 构造器+name 标签--><bean id="book" class="com.bean.Book"><constructor-arg name="name" value="书名2"></constructor-arg><constructor-arg name="price" value="2023.12"></constructor-arg></bean><!-- 4.使用 p标签--><bean id="book" class="com.bean.Book" p:name="书名3" p:price="2025.12"><!-- 如果类中有显示构造函数,则必须加上这两行--><constructor-arg index="0" value=""/><constructor-arg index="1" value=""/></bean>
</beans>
4.9.2. 注解配置(重点)
4.9.3. ApplicationContext 的构造方式
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
ApplicationContext applicationContext = new FileSystemXmlApplicationContext("D:\\code\\4Spring\\ssm_st" +
ClassPathXmlApplicationContext:使用文件名
FileSystemXmlApplicationContext:使用绝对路径
4.9.4. Bean的作用域
4.9.4.1. 多例模式
<bean id="book" class="com.bean.Book" p:name="书名3" p:price="2025.12" scope="prototype"><!-- 如果类中有显示构造函数,则必须加上这两行--><constructor-arg index="0" value=""/><constructor-arg index="1" value=""/></bean>
4.9.4.2. 单例模式
<bean id="book" class="com.bean.Book" p:name="书名3" p:price="2025.12" scope="singleton"><!-- 如果类中有显示构造函数,则必须加上这两行--><constructor-arg index="0" value=""/><constructor-arg index="1" value=""/></bean>
4.9.5. bean 的 xml 装配
4.9.5.1. 手动-ref 标签
<!-- bean的装配--><!-- 1.手动装配--><bean id="cat" class="com.bean.Cat"></bean><bean id="dog" class="com.bean.Dog"></bean><bean id="animal" class="com.bean.Animal"><property name="cat" ref="cat"/><property name="dog" ref="dog"/></bean>
4.9.5.2. 自动-autowire
- 通过名字
<!-- 2.自动装配--><bean id="cat" class="com.bean.Cat"></bean><bean id="dog" class="com.bean.Dog"></bean><bean id="animal" class="com.bean.Animal" autowire="byName"></bean>
- 通过类型
<!-- 2.自动装配--><bean id="cat" class="com.bean.Cat"></bean><bean id="dog" class="com.bean.Dog"></bean><bean id="animal" class="com.bean.Animal" autowire="byType"></bean>
4.9.5.2.1. autowire 属性取值
4.9.5.3. 总结
- 手动需要使用 ref 标签进行引用
- 自动需要通过
名字
或者类型
,间接使用 setter 方法进行装配
4.10. bean 的注解装配
4.10.1. Autowired
- 匹配流程:
-
- 根据类型
- 类型相同,根据名称
- 不用 setter 方法
4.10.2. Qualifier
- 按照名字查
- 不能单独使用
4.10.3. Resource
- 匹配流程:
-
- 根据名称
- 名称相同,根据类型
4.10.4. 注解包扫描装配
4.11. AOP
4.11.1. 相关概念
4.11.2. 基于 xml
<!-- 注册bean--><bean id="userService" class="com.bean.service.UserService"></bean><!-- 注册切面bean--><bean id="myPoint" class="com.pointCut.MyPointCut"></bean><!-- 配置切面--><aop:config><aop:aspect ref="myPoint"><!-- 配置切点--><aop:pointcut id="point" expression="execution(String com.bean.service.UserService.show())"/><!-- 配置通知--><aop:before method="before" pointcut-ref="point"></aop:before><aop:after method="after" pointcut-ref="point"></aop:after></aop:aspect></aop:config>
切点和通知不需要注册 bean。
4.11.3. 基于注解
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;import java.util.Arrays;// 配置类,启用 AOP 支持
@Configuration
@EnableAspectJAutoProxy
@SpringBootApplication
public class AopExampleApplication {public static void main(String[] args) {SpringApplication.run(AopExampleApplication.class, args);}// 定义一个简单的业务服务@Servicepublic static class UserService {public String getUserById(int id) {System.out.println("Executing getUserById with id: " + id);return "User " + id;}public void updateUser(int id, String name) {System.out.println("Updating user with id: " + id + " and name: " + name);}}// 定义自定义注解@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface Loggable {}// 切面类,包含各种通知@Aspect@Componentpublic static class LoggingAspect {// 定义切点,拦截 UserService 类的所有方法@Pointcut("execution(* com.example.AopExampleApplication.UserService.*(..))")public void userServicePointcut() {}// 前置通知@Before("userServicePointcut()")public void beforeAdvice(JoinPoint joinPoint) {System.out.println("Before method execution: " + joinPoint.getSignature().getName());System.out.println("Arguments: " + Arrays.toString(joinPoint.getArgs()));}// 后置通知@After("userServicePointcut()")public void afterAdvice(JoinPoint joinPoint) {System.out.println("After method execution: " + joinPoint.getSignature().getName());}// 环绕通知@Around("userServicePointcut()")public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {System.out.println("Before around advice: " + joinPoint.getSignature().getName());Object result = joinPoint.proceed();System.out.println("After around advice: " + joinPoint.getSignature().getName());return result;}// 返回通知,获取方法返回值@AfterReturning(pointcut = "userServicePointcut()", returning = "result")public void afterReturningAdvice(JoinPoint joinPoint, Object result) {System.out.println("Method returned: " + result);}// 异常通知,处理方法抛出的异常@AfterThrowing(pointcut = "userServicePointcut()", throwing = "e")public void afterThrowingAdvice(JoinPoint joinPoint, Exception e) {System.out.println("Method threw exception: " + e.getMessage());}// 自定义注解作为切点@Pointcut("@annotation(Loggable)")public void loggablePointcut() {}@Before("loggablePointcut()")public void loggableBeforeAdvice(JoinPoint joinPoint) {System.out.println("Before annotated method execution: " + joinPoint.getSignature().getName());}}
}
还需要在 xml 开启配置:
<!-- 基于注解配置切面的xml--><context:component-scan base-package="com.*"></context:component-scan><aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
4.11.4. 环绕通知
@Around("execution(String com.bean.service.UserService.show())")public void around(ProceedingJoinPoint pjp) throws Throwable {System.out.println("====around->执行方法之前的处理====");Object res = pjp.proceed();System.out.println("====around->执行方法之后的处理====");System.out.println("方法执行的返回结果:"+res);}
4.11.5. 返回结果后的通知
@AfterReturning("execution(String com.bean.service.UserService.show())")public void afterReturning() {System.out.println("====afterReturning->执行方法之后的处理====");}
4.11.6. 抛异常后的通知
@AfterThrowing("execution(String com.bean.service.UserService.show())")public void afterThrowing() {System.out.println("====afterThrowing->执行异常之后的处理====");}