IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Spring+SpringMVC+Mybatis的回顾 -> 正文阅读

[Java知识库]Spring+SpringMVC+Mybatis的回顾

目录

一、三个框架分别是用来操作什么的?

二、Spring框架

1. 什么是Spring框架?

2. SpringFarmWork的优势

3. Spring的体系结构

3.1Data Access/Integration(数据访问/集成)

3.2?Web 模块

3.3 Core Container(Spring 的核心容器)

3.4?AOP、Aspects、Instrumentation 和 Messaging

3.5?Test 模块

4. Spring IoC

4.1 控制反转(IoC)

?4.2?依赖注入(DI)

4.3 IoC工作原理

4.4 IoC容器的两种实现

5. Spring Bean

5.1 SpringBean的注入方式

5.2 Spring注入内部Bean

5.3 Spring注入集合

5.4 SpringBean的作用域

5.5 Spring Bean的生命周期

5.6 Spring的后置处理器

5.7 SpringBean继承

5.8 Bean定义模块

5.9 Spring的自动装配

5.10 基于注解的自动装配【?】

6. SpringAOP

?6.1 AOP的一些相关概念

6.2?Spring集成AspectJ

6.3 Spring 中基于 AOP 的 XML架构

6.4 Spring中基于AOP的@AspectJ的使用

7. SpringJDBC

7.1 Spring中SQL的存储过程?

8. Spring的事务管理

8.1 事务管理

8.2 局部事务 vs. 全局事务

8.3 编程式 vs. 声明式

8.4 Spring 事务抽象

8.4 Spring的编程式事务管理?

8.5 声明式事务控制

8.6 SpEL语言

8.7 SpEL对bean的支持

三、SpringMVC框架

1. 🐂DispatcherServlet🐂

?1.1 HelloWeb-servlet.xml的要点

1.2 定义控制器

2. Spring MVC概述

2.1 Spring mvc的开发步骤

?3. SpringMVC组件解析

?3.1 SpringMVC注解解析

3.2 Spring_mvc.xml文件的配置

?4. SpringMVC的数据响应

4.1 springmvc的数据响应方式

5. SpringMVC获得请求数据

5.1 获得请求参数

5.2 获得基本类型参数

5.3 获得POJO参数

5.4 获得数组类型参数

5.5 获得集合类型参数

5.6?参数绑定注解@requestParam

?5.7 获得RestFul风格的参数

5.8 自定义转换器?

5.9 SpringMVC获取请求头

5.10 文件上传

6. SpringMVC 拦截器

6.1 拦截器的作用

6.2 拦截器和过滤器的区别

?6.3 拦截器方法说明

?7. Spring MVC的异常处理机制

7.1 异常处理思路

7.2 异常处理的两种方式

四、Mybatis框架

1. Mybatis入门

1.1 原始JDBC的操作

1.2 什么是Mybatis?

1.3 Mybatis的开发步骤

2. Mybatis映射文件概述

2.1?Mapper XML 文件

2.2 参数?

2.3 字符串替换

2.4 ResultMap

?2.5 高级结果映射

3. Mybatis的一些关键对象的解析

4. Mybatis XML的配置

?4.1 属性

4.2 类型别名

?4.3 类型处理器

4.4 处理枚举类型

4.5 对象工厂

4.6 插件

4.7 配置环境

5. 动态sql

5.1 if

?5.2 choose、when、otherwise

5.3 trim、set、where

5.4 foreach

6. javaAPI

6.1 bind

6.2 Multi-db vendor support

6.3 应用目录结构

6.4 SqlSessions

6.5? SqlSessionFactoryBuilder

6.6 sqlSessionFactory

6.6 SqlSession

7. Mybatis的SQL语句的构造器

7.1 SQL语句的构造器

?7.2 SQL类

7.3 SelectBuilder(已经废弃) 和SqlBuilder

8. MyBatis日志?

8.1 Logging

8.2 Logging Configuration

?9. MyBatis 3.5.9新特性

10 Mybatis常见问题合集

10.1 大于号、小于号在sql中的转换

?10.2 Mybatis中的ResultType和ResultMap

10.3 Mybatis和ORM的区别

?10.4 Mybatis实现分页功能

10.5 Mybatis的四种分页方式

10.6 Mybatis中#{}和${}的区别

10.7 Mybatis接口绑定的两种方式

10.8 Mybatis使用Like进行模糊查询的几种方式?

10.9?通常一个mapper.XML对应一个DAO接口,DAO是否可以重载?

10.10?MyBatis映射文件中A标签引用B标签,如果B标签在A的后面定义,可以吗?

?10.11 Mybatis不同映射文件中的id是否可以重复?

10.12 Mybatis是否可以映射到枚举类?

10.13 Mybatis如何获取自动生成的主键ID

?10.14 Mybatis传递多个参数

?10.15 Mybatis缓存机制

?10.16 MyBatis时间timestamp做条件进行查询???????


已经学习完了这三个框架😊,但是学完就忘记了很多😟,没事,这就要重新来复习了!💪

一、三个框架分别是用来操作什么的?

1. Spring

????????Spring就像是整个项目中装配bean的大工厂,在配置文件中可以指定使用特定的参数去调用实体类的构造方法来实例化对象。也可以称之为项目中的粘合剂。Spring的核心思想是IoC(控制反转),即不再需要程序员去显式地`new`一个对象,而是让Spring框架帮你来完成这一切。

2. springMVC

????????SpringMVC在项目中拦截用户请求,它的核心Servlet即DispatcherServlet承担中介或是前台这样的职责,将用户请求通过HandlerMapping去匹配Controller,Controller就是具体对应请求所执行的操作。SpringMVC相当于SSH框架中struts。

3. mybatis

????????mybatis是对jdbc的封装,它让数据库底层操作变的透明。mybatis的操作都是围绕一个sqlSessionFactory实例展开的。mybatis通过配置文件关联到各实体类的Mapper文件,Mapper文件中配置了每个类对数据库所需进行的sql语句映射。在每次与数据库交互时,通过sqlSessionFactory拿到一个sqlSession,再执行sql命令。

二、Spring框架

1. 什么是Spring框架?

Spring是一个分层的?Java EE 编程领域的一款应用full-stack轻量级的开源框架,以IoC(Inverse Of control 反转控制)和AOP(面向切面编程)为内核。

提供展现层SpringMVC持久层Spring JDBCTemplate以及业务层事务管理等众多的企业级应用技术,还可以整个开源世界众多著名的第三框架和类库,逐渐成为使用最多的javaEE企业应用开源框架。

👍广义上的spring:泛指以Spring FarmWork为核心的spring技术栈👍

👍狭义上的spring:专指Spring FarmWork👍

Spring 框架是一个分层的、面向切面的 Java 应用程序的一站式轻量级解决方案,它是 Spring 技术栈的核心和基础,是为了解决企业级应用开发的复杂性而创建的。

Spring 是一种基于 Bean 的编程技术,它深刻地改变着 Java 开发世界。Spring 使用简单、基本的 Java Bean 来完成以前只有 EJB(企业JavaBeans) 才能完成的工作,使得很多复杂的代码变得优雅和简洁,避免了 EJB 臃肿、低效的开发模式,极大的方便项目的后期维护、升级和扩展。

?Spring 致力于 Java EE 应用各层的解决方案,对每一层都提供了技术支持。

  • 在表现层提供了对 Spring MVC、Struts2 等框架的整合;
  • 在业务逻辑层提供了管理事务和记录日志的功能;
  • 在持久层还可以整合 MyBatis、Hibernate 和 JdbcTemplate 等技术,对数据库进行访问。

2. SpringFarmWork的优势

① 方便解耦,简化开发

Spring 就是一个大工厂,可以将所有对象的创建和依赖关系的维护交给 Spring 管理。

② 方便集成各种优秀框架

Spring 不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如 Struts2、Hibernate、MyBatis 等)的直接支持。

③ 降低 Java EE API 的使用难度

Spring 对 Java EE 开发中非常难用的一些 API(JDBC、JavaMail、远程调用等)都提供了封装,使这些 API 应用的难度大大降低。

④ 方便程序的测试

Spring 支持 JUnit4,可以通过注解方便地测试 Spring 程序。

⑤ AOP 编程的支持

Spring 提供面向切面编程,可以方便地实现对程序进行权限拦截和运行监控等功能。

⑥ 声明式事务的支持

只需要通过配置就可以完成对事务的管理,而无须手动编程。

3. Spring的体系结构

3.1Data Access/Integration(数据访问/集成)

数据访问/集成层包括 JDBC、ORM、OXM、JMS 和 Transactions 模块,具体介绍如下。

  • JDBC 模块:提供了一个 JBDC 的样例模板,使用这些模板能消除传统冗长的 JDBC 编码还有必须的事务控制,而且能享受到 Spring 管理事务的好处。
  • ORM 模块:提供与流行的“对象-关系”映射框架无缝集成的 API,包括 JPA、JDO、Hibernate 和 MyBatis 等。而且还可以使用 Spring 事务管理,无需额外控制事务。
  • OXM 模块:提供了一个支持 Object /XML 映射的抽象层实现,如 JAXB、Castor、XMLBeans、JiBX 和 XStream。将 Java 对象映射成 XML 数据,或者将XML 数据映射成 Java 对象。
  • JMS 模块:指 Java 消息服务,提供一套 “消息生产者、消息消费者”模板用于更加简单的使用 JMS,JMS 用于用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。
  • Transactions 事务模块:支持编程和声明式事务管理。

3.2?Web 模块

Spring 的 Web 层包括 Web、Servlet、WebSocket 和 Portlet 组件,具体介绍如下。

  • Web 模块:提供了基本的 Web 开发集成特性,例如多文件上传功能、使用的 Servlet 监听器的 IOC 容器初始化以及 Web 应用上下文。
  • Servlet 模块:提供了一个 Spring MVC Web 框架实现。Spring MVC 框架提供了基于注解的请求资源注入、更简单的数据绑定、数据验证等及一套非常易用的 JSP 标签,完全无缝与 Spring 其他技术协作。
  • WebSocket 模块:提供了简单的接口,用户只要实现响应的接口就可以快速的搭建 WebSocket Server,从而实现双向通讯。
  • Portlet 模块:提供了在 Portlet 环境中使用 MVC 实现,类似 Web-Servlet 模块的功能。

3.3 Core Container(Spring 的核心容器)

Spring 的核心容器是其他模块建立的基础,由 Beans 模块、Core 核心模块、Context 上下文模块和 SpEL 表达式语言模块组成,没有这些核心容器,也不可能有 AOP、Web 等上层的功能。具体介绍如下。

  • Beans 模块:提供了框架的基础部分,包括控制反转和依赖注入。
  • Core 核心模块:封装了 Spring 框架的底层部分,包括资源访问、类型转换及一些常用工具类。
  • Context 上下文模块:建立在 Core 和 Beans 模块的基础之上,集成 Beans 模块功能并添加资源绑定、数据验证、国际化、Java EE 支持、容器生命周期、事件传播等。ApplicationContext 接口是上下文模块的焦点。
  • SpEL 模块:提供了强大的表达式语言支持,支持访问和修改属性值,方法调用,支持访问及修改数组、容器和索引器,命名变量,支持算数和逻辑运算,支持从 Spring 容器获取 Bean,它也支持列表投影、选择和一般的列表聚合等。

3.4?AOP、Aspects、Instrumentation 和 Messaging

在 Core Container 之上是 AOP、Aspects 等模块,具体介绍如下:

  • AOP 模块:提供了面向切面编程实现,提供比如日志记录、权限控制、性能统计等通用功能和业务逻辑分离的技术,并且能动态的把这些功能添加到需要的代码中,这样各司其职,降低业务逻辑和通用功能的耦合。
  • Aspects 模块:提供与 AspectJ 的集成,是一个功能强大且成熟的面向切面编程(AOP)框架。
  • Instrumentation 模块:提供了类工具的支持和类加载器的实现,可以在特定的应用服务器中使用。
  • messaging 模块:Spring 4.0 以后新增了消息(Spring-messaging)模块,该模块提供了对消息传递体系结构和协议的支持。

3.5?Test 模块

Test 模块:Spring 支持 Junit 和 TestNG 测试框架,而且还额外提供了一些基于 Spring 的测试功能,比如在测试 Web 框架时,模拟 Http 请求的功能。

4. Spring IoC

4.1 控制反转(IoC)

在传统的 Java 应用中,一个类想要调用另一个类中的属性或方法,通常会先在其代码中通过 new Object() 的方式将后者的对象创建出来,然后才能实现属性或方法的调用。为了方便理解和描述,我们可以将前者称为“调用者”,将后者称为“被调用者”。也就是说,调用者掌握着被调用者对象创建的控制权。

但在 Spring 应用中,Java 对象创建的控制权是掌握在 IoC 容器手里的,其大致步骤如下。

  1. 开发人员通过 XML 配置文件、注解、Java 配置类等方式,对?Java 对象进行定义,例如在 XML 配置文件中使用 <bean> 标签、在 Java 类上使用 @Component 注解等。
  2. Spring 启动时,IoC 容器会自动根据对象定义,将这些对象创建并管理起来。这些被 IoC 容器创建并管理的对象被称为 Spring Bean。
  3. 当我们想要使用某个 Bean 时,可以直接从 IoC 容器中获取(例如通过 ApplicationContext 的 getBean() 方法),而不需要手动通过代码(例如 new Obejct() 的方式)创建。


IoC 带来的最大改变不是代码层面的,而是从思想层面上发生了“主从换位”的改变。原本调用者是主动的一方,它想要使用什么资源就会主动出击,自己创建;但在 Spring 应用中,IoC 容器掌握着主动权,调用者则变成了被动的一方,被动的等待 IoC 容器创建它所需要的对象(Bean)。

这个过程在职责层面发生了控制权的反转,把原本调用者通过代码实现的对象的创建,反转给 IoC 容器来帮忙实现,因此我们将这个过程称为 Spring 的“控制反转”。

?4.2?依赖注入(DI)

依赖注入(Denpendency Injection,简写为 DI)是 Martin Fowler 在 2004 年在对“控制反转”进行解释时提出的。Martin Fowler 认为“控制反转”一词很晦涩,无法让人很直接的理解“到底是哪里反转了”,因此他建议使用“依赖注入”来代替“控制反转”。

B 中存在一个 A 类型的对象属性 a,此时我们就可以说 B 的对象依赖于对象 a。而依赖注入就是就是基于这种“依赖关系”而产生的。

4.3 IoC工作原理

若一个系统的耦合度过高,那么就会造成难以维护的问题,但完全没有耦合的代码几乎无法完成任何工作,这是由于几乎所有的功能都需要代码之间相互协作、相互依赖才能完成。因此我们在程序设计时,所秉承的思想一般都是在不影响系统功能的前提下,最大限度的降低耦合度。

IoC 底层通过工厂模式、Java 的反射机制、XML 解析等技术,将代码的耦合度降低到最低限度,其主要步骤如下。

  1. 在配置文件(例如 Bean.xml)中,对各个对象以及它们之间的依赖关系进行配置;
  2. 我们可以把 IoC 容器当做一个工厂,这个工厂的产品就是 Spring Bean;
  3. 容器启动时会加载并解析这些配置文件,得到对象的基本信息以及它们之间的依赖关系;
  4. IoC 利用 Java 的反射机制,根据类名生成相应的对象(即 Spring Bean),并根据依赖关系将这个对象注入到依赖它的对象中。


由于对象的基本信息、对象之间的依赖关系都是在配置文件中定义的,并没有在代码中紧密耦合,因此即使对象发生改变,我们也只需要在配置文件中进行修改即可,而无须对 Java 代码进行修改,这就是 Spring IoC 实现解耦的原理。

4.4 IoC容器的两种实现

Spring 框架为我们提供了两种不同类型 IoC 容器,它们分别是 BeanFactory 和?ApplicationContext。

1. BeanFactory

BeanFactory 是 IoC 容器的基本实现,也是 Spring 提供的最简单的 IoC 容器,它提供了 IoC 容器最基本的功能,由 org.springframework.beans.factory.BeanFactory 接口定义。

2. ApplicationContext

ApplicationContext 是 BeanFactory 接口的子接口,是对 BeanFactory 的扩展。ApplicationContext 在 BeanFactory 的基础上增加了许多企业级的功能,例如 AOP(面向切面编程)、国际化、事务支持等。

ApplicationContext接口常用的两个实现类有下面两个

5. Spring Bean

?Spring 配置文件支持两种格式,即 XML 文件格式和 Properties 文件格式。

  • Properties 配置文件主要以 key-value 键值对的形式存在,只能赋值,不能进行其他操作,适用于简单的属性配置。
  • XML 配置文件采用树形结构,结构清晰,相较于 Properties 文件更加灵活。但是 XML 配置比较繁琐,适用于大型的复杂的项目。

在xml配置的bean中可以有很多的属性或者子元素

5.1 SpringBean的注入方式

1. 使用构造函数注入

使用构造函数实现属性注入大致步骤如下:

  1. 在 Bean 中添加一个有参构造函数,构造函数内的每一个参数代表一个需要注入的属性;
  2. 在 Spring 的?XML 配置文件中,通过 <beans> 及其子元素 <bean> 对 Bean 进行定义;
  3. 在 <bean> 元素内使用?<constructor-arg> 元素,对构造函数内的属性进行赋值,Bean 的构造函数内有多少参数,就需要使用多少个 <constructor-arg> 元素。

2. 使用Setter注入

使用 setter 注入的方式进行属性注入,大致步骤如下:

  1. 在 Bean 中提供一个默认的无参构造函数(在没有其他带参构造函数的情况下,可省略),并为所有需要注入的属性提供一个 setXxx() 方法;
  2. 在 Spring 的?XML 配置文件中,使用 <beans> 及其子元素 <bean> 对 Bean 进行定义;
  3. 在 <bean> 元素内使用? <property> 元素对各个属性进行赋值。

3. 使用短命名空间注入

?①P命名空间

②c命名空间的注入

5.2 Spring注入内部Bean

?什么是内部bean??

Java 内部类是在其他类的范围内定义的,类似地,内部 bean是在另一个 bean 的范围内定义的 bean。因此,<property/> 或 <constructor-arg/> 元素内的 <bean/> 元素称为内部 bean

5.3 Spring注入集合

5.4 SpringBean的作用域

可以在 <bean> 元素中添加 scope 属性来配置 Spring Bean 的作用范围。

??注意?

在以上 6 种 Bean 作用域中,除了?singleton 和?prototype 可以直接在常规的 Spring IoC 容器(例如 ClassPathXmlApplicationContext)中使用外,剩下的都只能在基于 Web 的 ApplicationContext 实现(例如 XmlWebApplicationContext)中才能使用,否则就会抛出一个 IllegalStateException 的异常。

1. singleton

????????如果一个 Bean 定义的作用域为?singleton ,那么这个 Bean 就被称为?singleton bean。在 Spring IoC 容器中,singleton bean 是 Bean 的默认创建方式,可以更好地重用对象,节省重复创建对象的开销。所有的请求bean的时候都不会创建新的bean实例,都是同一个

2. propotype

????????如果一个 Bean 定义的作用域为 prototype,那么这个 Bean 就被称为 prototype bean。对于?prototype bean 来说,Spring 容器会在每次请求该 Bean 时,都创建一个新的 Bean 实例。

5.5 Spring Bean的生命周期

Bean的生命周期可以表达为:Bean的定义——Bean的初始化——Bean的使用——Bean的销毁

5.6 Spring的后置处理器

?BeanPostProcessor??接口定义回调方法,你可以实现该方法来提供自己的实例化逻辑,依赖解析逻辑等。你也可以在 ?Spring? 容器通过插入一个或多个 ?BeanPostProcessor? 的实现来完成实例化,配置和初始化一个?bean?之后实现一些自定义逻辑回调方法。

你可以配置多个 ?BeanPostProcessor??接口,通过设置 ?BeanPostProcessor??实现的??Ordered??接口提供的??order? 属性来控制这些??BeanPostProcessor? 接口的执行顺序。

?BeanPostProcessor? 可以对??bean?(或对象)实例进行操作,这意味着 ?Spring IoC? 容器实例化一个 ?bean? 实例,然后 ?BeanPostProcessor? 接口进行它们的工作。

ApplicationContext??会自动检测由??BeanPostProcessor??接口的实现定义的 ?bean?,注册这些??bean? 为后置处理器,然后通过在容器中创建??bean?,在适当的时候调用它。

5.7 SpringBean继承

在 Spring 中,Bean 和 Bean 之间也存在继承关系。我们将被继承的 Bean 称为父 Bean,将继承父 Bean 配置信息的 Bean 称为子 Bean。

Spring Bean 的定义中可以包含很多配置信息,例如构造方法参数、属性值。子 Bean 既可以继承父 Bean 的配置数据,也可以根据需要重写或添加属于自己的配置信息。

<!--父Bean-->
<bean id="parentBean" class="xxx.xxxx.xxx.ParentBean" >
    <property name="xxx" value="xxx"></property>
    <property name="xxx" value="xxx"></property>
</bean> 
<!--子Bean--> 
<bean id="childBean" class="xxx.xxx.xxx.ChildBean" parent="parentBean"></bean>

5.8 Bean定义模块

????????在父 Bean 的定义中,有一个十分重要的属性,那就是 abstract 属性。如果一个父 Bean 的 abstract 属性值为 true,则表明这个 Bean 是抽象的。
????????抽象的父 Bean 只能作为模板被子 Bean 继承,它不能实例化,也不能被其他 Bean 引用,更不能在代码中根据 id 调用 getBean() 方法获取,否则就会返回错误。【所以如果在父Bean中使用了抽象就会不能实例化!
????????在父 Bean 的定义中,既可以指定 class 属性,也可以不指定 class 属性。如果父 Bean 定义没有明确地指定 class 属性,那么这个父 Bean 的 abstract 属性就必须为 true。?

5.9 Spring的自动装配

在使用的量很少的时候,我们可以使用前面学习的手动装配的方式,但是当使用的量变多的时候就不行了?,这个时候我们可以使用自动装配的方式。

????????Spring 的自动装配功能可以让 Spring 容器依据某种规则(自动装配的规则,有五种),为指定的 Bean 从应用的上下文(AppplicationContext 容器)中查找它所依赖的 Bean,并自动建立 Bean 之间的依赖关系。而这一过程是在完全不使用任何?<constructor-arg>和 <property> 元素 ref 属性的情况下进行的。
????????Spring 的自动装配功能能够有效地简化 Spring 应用的 XML 配置,因此在配置数量相当多时采用自动装配降低工作量。

????????Spring 框架式默认不支持自动装配的,要想使用自动装配,则需要对 Spring XML 配置文件中 <bean> 元素的 autowire 属性进行设置。

🤑🤑?自动装配的规则如下所示🤑🤑?

1. 按照名称byName

autowire="byName" 表示按属性名称自动装配,XML 文件中 Bean 的 id 或 name 必须与类中的属性名称相同。

2. 按照类型byType

autowire="byType" 表示按类中对象属性数据类型进行自动装配。即使 XML 文件中 Bean 的 id 或 name 与类中的属性名不同,只要 Bean 的 class 属性值与类中的对象属性的类型相同,就可以完成自动装配。

3. 按照构造函数constructor

autowire="constructor" 表示按照 Java 类中构造函数进行自动装配。

4.按照默认方式default

默认采用上一级标签 <beans> 设置的自动装配规则(default-autowire)进行装配

5.10 基于注解的自动装配【?】

Spring 通过注解实现自动装配的步骤如下:

  1. 引入依赖
  2. 开启组件扫描【context】
  3. 使用注解定义 Bean
  4. 依赖注入

?1. 相关的注解【定义Bean】

?2. 相关的注解【实现依赖注入】

6. SpringAOP

????????Spring 框架的一个关键组件是面向切面的编程(AOP)框架。面向切面的编程需要把程序逻辑分解成不同的部分称为所谓的关注点。跨一个应用程序的多个点的功能被称为横切关注点,这些横切关注点在概念上独立于应用程序的业务逻辑。在软件开发过程中有各种各样的很好的切面的例子,如日志记录、审计、声明式事务、安全性和缓存等。

?6.1 AOP的一些相关概念

1. AOP术语?

2. 通知的类型

?3. 实现自定义方面

6.2?Spring集成AspectJ

????????Spring AOP 是一个简化版的 AOP 实现,并没有提供完整版的 AOP 功能。通常情况下,Spring AOP 是能够满足我们日常开发过程中的大多数场景的,但在某些情况下,我们可能需要使用 Spring AOP 范围外的某些 AOP 功能。

????????例如 Spring AOP 仅支持执行公共(public)非静态方法的调用作为连接点,如果我们需要向受保护的(protected)或私有的(private)的方法进行增强,此时就需要使用功能更加全面的 AOP 框架来实现,其中使用最多的就是 AspectJ。

????????AspectJ 是一个基于 Java 语言的全功能的 AOP 框架,它并不是 Spring 组成部分,是一款独立的 AOP 框架。?

使用 AspectJ 需要在 Spring 项目中导入 Spring AOP 和 AspectJ 相关 Jar 包。

  • spring-aop-xxx.jar
  • spring-aspects-xxx.jar
  • aspectjweaver-xxxx.jar

AspectJ 的jar包下载:AspectJ Downloads | The Eclipse Foundation?

6.3 Spring 中基于 AOP 的 XML架构

6.4 Spring中基于AOP的@AspectJ的使用

?@AspectJ 作为通过 Java 5 注释注释的普通的 Java 类,它指的是声明 aspects 的一种风格。通过在你的基于架构的 XML 配置文件中包含以下元素,@AspectJ 支持是可用的。

7. SpringJDBC

????????在使用普通的 JDBC 数据库时,就会很麻烦的写不必要的代码来处理异常,打开和关闭数据库连接等。但 Spring JDBC 框架负责所有的低层细节,从开始打开连接,准备和执行 SQL 语句,处理异常,处理事务,到最后关闭连接。

????????所以当从数据库中获取数据时,你所做的是定义连接参数,指定要执行的 SQL 语句,每次迭代完成所需的工作。

????????Spring JDBC 提供几种方法和数据库中相应的不同的类与接口。我将给出使用?JdbcTemplate?类框架的经典和最受欢迎的方法。这是管理所有数据库通信和异常处理的中央框架类。

????????JdbcTemplate?类的实例是线程安全配置的。所以你可以配置 JdbcTemplate 的单个实例,然后将这个共享的引用安全地注入到多个 DAOs 中。使用 JdbcTemplate 类时常见的做法是在你的 Spring 配置文件中配置数据源,然后共享数据源 bean 依赖注入到 DAO 类中,并在数据源的设值函数中创建了 JdbcTemplate。

7.1 Spring中SQL的存储过程?

?SimpleJdbcCall?类可以被用于调用一个包含 IN 和 OUT 参数的存储过程。

8. Spring的事务管理

8.1 事务管理

一个数据库事务是一个被视为单一的工作单元的操作序列。这些操作应该要么完整地执行,要么完全不执行。事务管理是一个重要组成部分,RDBMS(关系数据库管理系统) 面向企业应用程序,以确保数据完整性和一致性。事务的概念可以描述为具有以下四个关键属性说成是?ACID

  • 原子性:事务应该当作一个单独单元的操作,这意味着整个序列操作要么是成功,要么是失败的。

  • 一致性:这表示数据库的引用完整性的一致性,表中唯一的主键等。

  • 隔离性:可能同时处理很多有相同的数据集的事务,每个事务应该与其他事务隔离,以防止数据损坏。

  • 持久性:一个事务一旦完成全部操作后,这个事务的结果必须是永久性的,不能因系统故障而从数据库中删除。

一个真正的 RDBMS 数据库系统将为每个事务保证所有的四个属性。使用 SQL 发布到数据库中的事务的简单视图如下:

  • 使用 begin transaction 命令开始事务。

  • 使用 SQL 查询语句执行各种删除、更新或插入操作。

  • 如果所有的操作都成功,则执行提交操作,否则回滚所有操作。

Spring 框架在不同的底层事务管理 APIs 的顶部提供了一个抽象层。Spring 的事务支持旨在通过添加事务能力到 POJOs 来提供给 EJB 事务一个选择方案。Spring 支持编程式和声明式事务管理。EJBs 需要一个应用程序服务器,但 Spring 事务管理可以在不需要应用程序服务器的情况下实现。

8.2 局部事务 vs. 全局事务

局部事务是特定于一个单一的事务资源,如一个 JDBC 连接,而全局事务可以跨多个事务资源事务,如在一个分布式系统中的事务。

局部事务管理在一个集中的计算环境中是有用的,该计算环境中应用程序组件和资源位于一个单位点,而事务管理只涉及到一个运行在一个单一机器中的本地数据管理器。局部事务更容易实现。

全局事务管理需要在分布式计算环境中,所有的资源都分布在多个系统中。在这种情况下事务管理需要同时在局部和全局范围内进行。分布式或全局事务跨多个系统执行,它的执行需要全局事务管理系统和所有相关系统的局部数据管理人员之间的协调。

8.3 编程式 vs. 声明式

Spring 支持两种类型的事务管理:

  • 编程式事务管理 :这意味着你在编程的帮助下有管理事务。这给了你极大的灵活性,但却很难维护。

  • 声明式事务管理 :这意味着你从业务代码中分离事务管理。你仅仅使用注释或 XML 配置来管理事务。

声明式事务管理比编程式事务管理更可取,尽管它不如编程式事务管理灵活,但它允许你通过代码控制事务。但作为一种横切关注点,声明式事务管理可以使用 AOP 方法进行模块化。Spring 支持使用 Spring AOP 框架的声明式事务管理。

8.4 Spring 事务抽象

Spring事务管理的五大属性:隔离级别传播行为是否只读事务超时回滚规则

1. TransactionDefintion的定义如下:

public interface TransactionDefinition {
   int getPropagationBehavior();
   int getIsolationLevel();
   String getName();
   int getTimeout();
   boolean isReadOnly();
}

2. 隔离级别的可能值

?3. 传播类型的可能值

4.?TransactionStatus 接口为事务代码提供了一个简单的方法来控制事务的执行和查询事务状态。

8.4 Spring的编程式事务管理?

?编程式事务管理方法允许你在对你的源代码编程的帮助下管理事务。这给了你极大地灵活性,但是它很难维护。

8.5 声明式事务控制

声明式事务管理方法允许你在配置的帮助下而不是源代码硬编程来管理事务。这意味着你可以将事务管理从事务代码中隔离出来。你可以只使用注释或基于配置的 XML 来管理事务。 bean 配置会指定事务型方法。下面是与声明式事务相关的步骤:

  • 我们使用标签,它创建一个事务处理的建议,同时,我们定义一个匹配所有方法的切入点,我们希望这些方法是事务型的并且会引用事务型的建议。

  • 如果在事务型配置中包含了一个方法的名称,那么创建的建议在调用方法之前就会在事务中开始进行。

  • 目标方法会在 try / catch 块中执行。

  • 如果方法正常结束,AOP 建议会成功的提交事务,否则它执行回滚操作。

8.6 SpEL语言

Spring Expression Language(简称 SpEL)是一种功能强大的表达式语言,支持运行时查询和操作对象图 。表达式语言一般是用最简单的形式完成最主要的工作,以此减少工作量。

SpEL 提供了以下接口和类:

  • Expression interface:该接口负责评估表达式字符串
  • ExpressionParser interface:该接口负责解析字符串
  • EvaluationContext interface:该接口负责定义上下文环境

SpEL 支持如下表达式:

1. 基本表达式

字面量表达式、关系、逻辑与算术运算表达式、字符串连接及截取表达式、三目运算表达式、正则表达式、括号优先级表达式;

2. 类相关表达式

类类型表达式、类实例化、instanceof 表达式、变量定义及引用、赋值表达式、自定义函数、对象属性存取及安全导航表达式、对象方法调用、Bean 引用;

3. 集合相关表达式

内联 List、内联数组、集合、字典访问、列表、字典、数组修改、集合投影、集合选择;不支持多维内联数组初始化;不支持内联字典定义;

4. 其他表达式

模板表达式。

8.7 SpEL对bean的支持

三、SpringMVC框架

Spring web MVC 框架提供了模型-视图-控制的体系结构和可以用来开发灵活、松散耦合的 web 应用程序的组件。MVC 模式导致了应用程序的不同方面(输入逻辑、业务逻辑和 UI 逻辑)的分离,同时提供了在这些元素之间的松散耦合。

  • 模型封装了应用程序数据,并且通常它们由 POJO 组成。

  • 视图主要用于呈现模型数据,并且通常它生成客户端的浏览器可以解释的 HTML 输出。

  • 控制器主要用于处理用户请求,并且构建合适的模型并将其传递到视图呈现。

1. 🐂DispatcherServlet🐂

Spring Web 模型-视图-控制(MVC)框架是围绕?DispatcherServlet?设计的,DispatcherServlet?用来处理所有的 HTTP 请求和响应。

下面是对应于?DispatcherServlet?传入 HTTP 请求的事件序列:

  • 收到一个 HTTP 请求后,DispatcherServlet?根据?HandlerMapping?来选择并且调用适当的控制器

  • 控制器接受请求,并基于使用的 GET 或 POST 方法来调用适当的 service 方法。Service 方法将设置基于定义的业务逻辑的模型数据,并返回视图名称到?DispatcherServlet?中。

  • DispatcherServlet?会从?ViewResolver?获取帮助,为请求检取定义视图。

  • 一旦确定视图,DispatcherServlet?将把模型数据传递给视图,最后呈现在浏览器中。

上面所提到的所有组件,即 HandlerMapping、Controller 和 ViewResolver 是?WebApplicationContext?的一部分,而?WebApplicationContext?是带有一些对 web 应用程序必要的额外特性的?ApplicationContext?的扩展。

?1.1 HelloWeb-servlet.xml的要点

以下是关于?HelloWeb-servlet.xml?文件的一些要点:

  • [servlet-name]-servlet.xml?文件将用于创建 bean 定义,重新定义在全局范围内具有相同名称的任何已定义的 bean。

  • ?<context:component-scan>标签将用于激活 Spring MVC 注释扫描功能,该功能允许使用注释,如 @Controller 和 @RequestMapping 等等。

  • InternalResourceViewResolver?将使用定义的规则来解决视图名称。按照上述定义的规则,一个名称为?hello?的逻辑视图将发送给位于?/WEB-INF/jsp/hello.jsp?中实现的视图。

1.2 定义控制器

DispatcherServlet 发送请求到控制器中执行特定的功能。@Controller?注释表明一个特定类是一个控制器的作用。@RequestMapping?注释用于映射 URL 到整个类或一个特定的处理方法。

2. Spring MVC概述

2.1 Spring mvc的开发步骤

需求:客户端发起请求,服务端接收请求,执行逻辑并进行视图跳转

①导入SpringMVC的jar包

②配置Servlet(核心控制器DispathcerServlet) --- web.xml

<!--配置SpringMVC的前端控制器-->
    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
 
<!--<load-on-startup>标记容器是否在启动的时候就加载这个servlet。当值为0或者大于0时,表示容器在应用启动时就加载这个servlet;当是一个负数时或者没有指定时,则指示容器在该servlet被选择时才加载。正数的值越小,启动该servlet的优先级越高。-->

③编写POJO【习惯性的简称为Controller】和视图

④将Controller使用注解配置到Spring容器中(@Component/@Controller)

⑤配置组件扫描(配置Spring-mvc.xml核心配置文件)

⑥执行访问测试

?3. SpringMVC组件解析

?3.1 SpringMVC注解解析

@RequestMapping

作用:用于建立请求URL和处理方法之间的对应关系

属性:

????????value:用于指定请求的URL。他和path属性的作用是一样的

? ? ? ? method:用于指定请求的方式。

? ? ? ? params:用于制定限制请求参数的条件。支持简单的表达式。要求请求参数的key和value必须和配置一模一样

3.2 Spring_mvc.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:context="http://www.springframework.org/schema/context"
       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
">
 
    <!--Controller的组件扫描-->
    <!--context扫描的是对应的web层,也就是实现层,这里的实现层就是controller-->
   <!-- <context:component-scan base-package="com.wxy.controller"/>-->
    <context:component-scan base-package="com.wxy">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
 
    <!--手动配置内部资源视图解析器-->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--/jsp/-->
        <property name="prefix" value="/jsp/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>
 
</beans>

?4. SpringMVC的数据响应

4.1 springmvc的数据响应方式

1. 页面跳转

① 直接返回字符串:会将返回的字符串与视图解析器的前后缀拼接后进行跳转

② 通过ModelAndView对象返回

//第一种
    @RequestMapping("/quick2")
    public ModelAndView save2(){
        /*
        * Model:模型,封装数据
        * View:视图,展示数据
        * */
        ModelAndView modelAndView=new ModelAndView();
        //设置模型数据
        modelAndView.addObject("username","itcast");
        //设置视图名称
        modelAndView.setViewName("success");
        return modelAndView;
    }
 
 
 
 
//第二种
 @RequestMapping("/quick3")
    public ModelAndView save3(ModelAndView modelAndView){
 
        modelAndView.addObject("username","itwxy");
        //设置视图名称
        modelAndView.setViewName("success");
        return modelAndView;
 
    }
 
 
 @RequestMapping("/quick4")
    public String save4(Model model){
 
        model.addAttribute("username","博学多才");
        return "success";
 
    }

?2. 回写数据

①直接返回字符串

②返回对象或者集合

  <!--配置处理器映射器-->
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
        <property name="messageConverters">
            <list>
                <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"></bean>
            </list>
        </property>
    </bean>
   @RequestMapping("/quick9")
    @ResponseBody //告知SpringMVC框架,该方法不进行页面跳转,直接进行数据响应
    //期望SpringMVC自动将user转换为json格式的字符串
    public User save9() throws IOException {
        User user=new User();
        user.setName("lisi");
        user.setAge(30);
 
        return user;
 
 
    }

5. SpringMVC获得请求数据

5.1 获得请求参数

客户端请求参数的格式是:name=value&name=value......

服务器端要获得请求的参数,有时候还需要进行数据的封装,SpringMVC可以接收下面类型的参数:

①基本类型参数

②POJO类型参数

③数组类型参数

④集合类型参数

5.2 获得基本类型参数

Controller中的业务方法的参数名称与请求参数的name一致,参数值会自动映射匹配

5.3 获得POJO参数

??Controller中的业务方法的POJO参数的属性名和请求参数的name一致,参数值会自动映射匹配

@RequestMapping("/quick11")
    @ResponseBody //告知SpringMVC框架,该方法不进行页面跳转,直接进行数据响应
    public void save11(User user) throws IOException {
        System.out.println(user);
 
    }
package com.wxy.domian;
 
public class User {
    private int age;
    private String username;
 
    public int getAge() {
        return age;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
 
    public String getName() {
        return username;
    }
 
    public void setName(String username) {
        this.username = username;
    }
 
    @Override
    public String toString() {
        return "User{" +
                "age=" + age +
                ", username='" + username + '\'' +
                '}';
    }
}

5.4 获得数组类型参数

Controller中的业务方法数组名称和请求参数的name一致,参数值就会自动映射匹配。

 @RequestMapping("/quick12")
    @ResponseBody //告知SpringMVC框架,该方法不进行页面跳转,直接进行数据响应
    public void save12(String[] strs) throws IOException {
        System.out.println(Arrays.asList(strs));
 
    }

5.5 获得集合类型参数

获得集合参数的时候需要将集合参数包装到一个POJO中才可以

@RequestMapping("/quick13")
    @ResponseBody //告知SpringMVC框架,该方法不进行页面跳转,直接进行数据响应
    public void save13(VO vo) throws IOException {
        System.out.println(vo);
 
    }
package com.wxy.domian;
 
import java.util.List;
 
public class VO {
 
    private List<User> userList;
 
    public List<User> getUserList() {
        return userList;
    }
 
    public void setUserList(List<User> userList) {
        this.userList = userList;
    }
 
    @Override
    public String toString() {
        return "VO{" +
                "userList=" + userList +
                '}';
    }
}

??当使用ajax请求的时候,可以指定contentType为json形式,那么在方法参数位置使用@RequestBody可以直接接收集合数据而不用使用POJO进行包装

   @RequestMapping("/quick14")
    @ResponseBody //告知SpringMVC框架,该方法不进行页面跳转,直接进行数据响应
    public void save14(@RequestBody List<User> userList) throws IOException {
        System.out.println(userList);
 
    }

ajax.jsp

 
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <script src="${pageContext.request.contextPath}/js/jquery-3.3.1.js"></script>
    <script>
        var userList=new Array();
        userList.push({username:"zhangsan",age:18});
        userList.push({username:"lisi",age:28});
 
 
        $.ajax({
            type:"POST",
            url:"${pageContext.request.contextPath}/user/quick14",
            data:JSON.stringify(userList),
            contentType:"application/json;charset=UTF-8"
        })
    </script>
</head>
<body>
 
</body>
</html>

springmvc.xml

   <!--在Spingmvc框架中需要开放哪些资源的访问-->
   <!-- <mvc:resources mapping="/js/**" location="/js/"/>-->
    
    <!--如果mvc找不到资源的情况下就交给原始的容器tomcat帮忙找!-->
    <mvc:default-servlet-handler/>

5.6?参数绑定注解@requestParam

?5.7 获得RestFul风格的参数

Restful是一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。主要用于客户端和服务器交互类的软件,基于这个风格涉及的软件可以更加简洁,更有层次,更易于实现缓存机制等。

5.8 自定义转换器?

SpringMVC默认已经提供了一些常用的类型转换器, 例如客户端提交的字符串转换成int型进行参数设置。
但是不是所有的数据类型都提供了转换器,没有提供的就需要自定义转换器,例如:日期类型的数据就需要自定义转换器。

自定义类型转换器的开发步骤:

①定义转换器类实现Converter接口

package com.wxy.converter;
 
import org.springframework.core.convert.converter.Converter;
 
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
 
public class DataConverter implements Converter<String, Date> {
 
    @Override
    public Date convert(String dateStr) {
        //将日期的字符串转换为日期对象,然后返回就可
        SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd");
        Date date = null;
        try {
            date = format.parse(dateStr);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }
}

②在配置文件中声明转换器

 
<!--声明转换器-->
    <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <list>
                <bean class="com.wxy.converter.DataConverter"></bean>
            </list>
        </property>
    </bean>

③在<annotation-driven>中引用转换器

  <!--mvc的注解驱动-->
    <mvc:annotation-driven conversion-service="conversionService"/>

5.9 SpringMVC获取请求头

1. @RequestHeader

使用@RequestHeader可以获得请求头信息,相当于web阶段学习的request.getHeader(name)
@RequestHeader注解的属性如下:
? ? ? ? value: 请求头的名称
? ? ? ? required: 是否必须携带此请求头

2. @CookieValue

使用@CookieValue可以获得指定Cookie的值,@CookieValue注解的属性如下:

? ? ? ? value:指定cookie的名称

? ? ? ? required:是否必须携带此cookie

5.10 文件上传

1. 文件上传客户端三要素

①表单项type="file"

②表单的提交方式是post

③表单的enctype属性是多部分表单形式,即enctype="multipart/form-data"

2. 文件上传原理

3. 单文件上传步骤

①导入fileupload和Io坐标

        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.1</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
        </dependency>

②配置文件上传解析器

 <!--配置文件上传的解析器-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="defaultEncoding" value="UTF-8"></property>
        <property name="maxUploadSize" value="500000"></property>
    </bean>

?③编写文件上传代码

 @RequestMapping("/quick21")
    @ResponseBody //告知SpringMVC框架,该方法不进行页面跳转,直接进行数据响应
    public void save21(String username, MultipartFile upload)  throws IOException {
        System.out.println(username);
        System.out.println(upload);
    }
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <form action="${pageContext.request.contextPath}/user/quick21" method="post" enctype="multipart/form-data">
        名称<input type="text" name="username"><br/>
        文件<input type="file" name="upload"><br/>
        <input type="submit" name="提交">
    </form>
</body>
</html>

存放在本地

@RequestMapping("/quick21")
    @ResponseBody //告知SpringMVC框架,该方法不进行页面跳转,直接进行数据响应
    public void save21(String username, MultipartFile upload)  throws IOException {
        System.out.println(username);
        System.out.println(upload);
        String originalFilename = upload.getOriginalFilename();//获得文件的名称
        upload.transferTo(new File("C:\\Users\\王新云\\Desktop\\upload"+originalFilename));
    }

?4. 多文件上传实现

@RequestMapping("/quick22")
    @ResponseBody //告知SpringMVC框架,该方法不进行页面跳转,直接进行数据响应
    public void save22(String username, MultipartFile[] upload)  throws IOException {
        System.out.println(username);
        for (MultipartFile multipartFile : upload) {
            String originalFilename = multipartFile.getOriginalFilename();
            multipartFile.transferTo(new File("C:\\Users\\王新云\\Desktop\\upload"+originalFilename));
        }
    }
<form action="${pageContext.request.contextPath}/user/quick22" method="post" enctype="multipart/form-data">
    名称<input type="text" name="username"><br/>
    文件1<input type="file" name="upload"><br/>
    文件2<input type="file" name="upload"><br/>
    文件3<input type="file" name="upload"><br/>
    <input type="submit" name="提交">
</form>

6. SpringMVC 拦截器

6.1 拦截器的作用

Springmvc的拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理

将拦截器按一定的顺序联结成一条链,这条链称为拦截器链(Interceptor Chain) 。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。拦截器也是AOP思想的具体现。


6.2 拦截器和过滤器的区别

?6.3 拦截器方法说明

?7. Spring MVC的异常处理机制

7.1 异常处理思路

系统中的异常主要包含两类:预期异常和运行时异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试等手段减少运行时异常的发生。

系统的Dao、service、controller出现都通过throws Exception向上抛出,最后由Springmvc前端控制器交由异常处理器进行异常处理,如下图:

7.2 异常处理的两种方式

1. 使用Spring MVC提供的简单异常处理器SimpleMappingExceptionResolver?

2. 使用Spring的异常处理接口HandleExceptionResolver自定义自己的异常处理器

①创建异常处理实现类HandleExceptionResolver

②配置异常处理器

③编写异常页面

④测试异常跳转

四、Mybatis框架

1. Mybatis入门

要使用 MyBatis, 只需将?mybatis-x.x.x.jar?文件置于类路径(classpath)中即可。

1.1 原始JDBC的操作

?原始jdbc开发存在的问题如下?
①数据库连接创建、释放频繁造成系统资源浪费从而影响系统性能;
②sql 语句在代码中硬编码,造成代码不易维护,实际应用sql变化的可能较大,sql 变动需要改变java代码;
③查询操作时,需要手动将结果集中的数据手动封装到实体中。插入操作时,需要手动将实体的数据设置到sq|语句的占位符位置。

应对上述问题给出的解决方案:
①使用数据库连接池初始化连接资源;
②将sq|语句抽取到xm配置文件中;
③使用反射、内省等底层技术,自动将实体与表进行属性与字段的自动映射。

1.2 什么是Mybatis?

①mybatis是一个优秀的基于java的持久层框架,它内部封装了jdbc,使开发者只需要关注sq|语句本身,而不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。
②mybatis通过xml或注解的方式将要执行的各种statement配置起来,并通过java对象和statement中sq|的动态参数进行映射生成最终执行的sql语句。
③最后mybatis框架执行sql并将结果映射为java对象并返回。采用ORM(Object Realtion Mapping)思想解决了实体和数据库映射的问题,对jdbc 进行了封装,屏蔽了jdbc api底层访问细节,使我们不用与jdbc api打交道,就可以完成对数据库的持久化操作。

1.3 Mybatis的开发步骤

①添加mybatis的坐标

②创建对应的数据库表

③编写User实体类

④编写映射文件UserMapper.xml

<?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 namespace="userMapper">
 
    <!--resultType表示查询语句放到哪里-->
    <select id="findAll" resultType="com.wxy.domain.User">
        select * from user
    </select>
</mapper>

⑤编写核心配置文件SqlMapConfig.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!--配置数据源的环境-->
 
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql//localhost:3306/test"/>
                <property name="username" value="root"/>
                <property name="password" value=""/>
            </dataSource>
        </environment>
    </environments>
 
 
    <!--加载映射文件-->
    <mappers>
        <mapper resource="com/wxy/mapper/userMapper.xml"></mapper>
    </mappers>
    
</configuration>

⑥编写测试类

package com.wxy.test;
 
import com.wxy.domain.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
 
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
 
public class MyBatisTest {
    @Test
    public void test() throws IOException {
        //配置核心配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapperConfig.xml");
        //获得sqlSession工厂对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //获得session回话对象
        SqlSession sqlSession=sqlSessionFactory.openSession();
        //执行操作 参数:namespace+id
        List<User> userList = sqlSession.selectList("userMapper.findAll");
        //打印数据
        System.out.println(userList);
 
        //释放资源
        sqlSession.close();
    }
}

2. Mybatis映射文件概述

2.1?Mapper XML 文件

1. select

查询语句是 MyBatis 中最常用的元素之一,光能把数据存到数据库中价值并不大,如果还能重新取出来才有用,多数应用也都是查询比修改要频繁。对每个插入、更新或删除操作,通常对应多个查询操作。这是 MyBatis 的基本原则之一,也是将焦点和努力放到查询和结果映射的原因。简单查询的 select 元素是非常简单的。

?

?2. insert、delete、update

3. sql

2.2 参数?

前面的所有语句中你所见到的都是简单参数的例子,实际上参数是 MyBatis 非常强大的元素,对于简单的做法,大概 90% 的情况参数都很少

2.3 字符串替换

2.4 ResultMap

resultMap 元素是 MyBatis 中最重要最强大的元素。它就是让你远离 90%的需要从结果 集中取出数据的 JDBC 代码的那个东西, 而且在一些情形下允许你做一些 JDBC 不支持的事情。 事实上, 编写相似于对复杂语句联合映射这些等同的代码, 也许可以跨过上千行的代码。 ResultMap 的设计就是简单语句不需要明确的结果映射,而很多复杂语句确实需要描述它们 的关系。

那么ResultMap对比于ResultType的优秀之处在哪里?

?2.5 高级结果映射

MyBatis 创建的一个想法:数据库不用永远是你想要的或需要它们是什么样的。而我们 最喜欢的数据库最好是第三范式或 BCNF 模式,但它们有时不是。如果可能有一个单独的 数据库映射,所有应用程序都可以使用它,这是非常好的,但有时也不是。结果映射就是 MyBatis 提供处理这个问题的答案。

1. resultMap的概念视图

?2. id&result

这些是结果映射最基本内容。id 和 result 都映射一个单独列的值到简单数据类型(字符 串,整型,双精度浮点数,日期等)的单独属性或字段。

这两者之间的唯一不同是 id 表示的结果将是当比较对象实例时用到的标识属性。这帮 助来改进整体表现,特别是缓存和嵌入结果映射(也就是联合映射) 。

3. 支持的JDBC类型

?4. 构造方法

对于大多数数据传输对象(Data Transfer Object,DTO)类型,属性可以起作用,而且像你绝大多数的领域模型, 指令也许是你想使用一成不变的类的地方。 通常包含引用或查询数 据的表很少或基本不变的话对一成不变的类来说是合适的。 构造方法注入允许你在初始化时 为类设置属性的值,而不用暴露出公有方法。MyBatis 也支持私有属性和私有 JavaBeans 属性来达到这个目的,但是一些人更青睐构造方法注入。构造方法元素支持这个。

?5. 关联

①关联的嵌套查询

②关联的嵌套结果

看完有点懵😵,那么嵌套结果和嵌套查询的区别到底在哪里?

在这里插入图片描述

?6. 集合

①集合的嵌套查询

②集合的嵌套结果?

?7. 鉴别器

有时一个单独的数据库查询也许返回很多不同 (但是希望有些关联) 数据类型的结果集。 鉴别器元素就是被设计来处理这个情况的, 还有包括类的继承层次结构。 鉴别器非常容易理解,因为它的表现很像 Java 语言中的 switch 语句。

定义鉴别器指定了 column 和 javaType 属性。 列是 MyBatis 查找比较值的地方。 JavaType 是需要被用来保证等价测试的合适类型(尽管字符串在很多情形下都会有用)。

3. Mybatis的一些关键对象的解析

4. Mybatis XML的配置

?4.1 属性

4.2 类型别名

<typeAliases>
  <typeAlias alias="Author" type="domain.blog.Author"/>
  <typeAlias alias="Blog" type="domain.blog.Blog"/>
  <typeAlias alias="Comment" type="domain.blog.Comment"/>
  <typeAlias alias="Post" type="domain.blog.Post"/>
  <typeAlias alias="Section" type="domain.blog.Section"/>
  <typeAlias alias="Tag" type="domain.blog.Tag"/>
</typeAliases>

已经为许多常见的 Java 类型内建了相应的类型别名。它们都是大小写不敏感的,需要注意的是由基本类型名称重复导致的特殊处理。

?4.3 类型处理器

无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型。下表描述了一些默认的类型处理器。

??你可以重写类型处理器或创建你自己的类型处理器来处理不支持的或非标准的类型。 具体做法为:实现?org.apache.ibatis.type.TypeHandler?接口, 或继承一个很便利的类?org.apache.ibatis.type.BaseTypeHandler, 然后可以选择性地将它映射到一个 JDBC 类型。?

 // ExampleTypeHandler.java
    @MappedJdbcTypes(JdbcType.VARCHAR)
    public class ExampleTypeHandler extends BaseTypeHandler {

      @Override
      public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
        ps.setString(i, parameter);
      }

      @Override
      public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return rs.getString(columnName);
      }

      @Override
      public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return rs.getString(columnIndex);
      }

      @Override
      public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return cs.getString(columnIndex);
      }
    }
<!-- mybatis-config.xml -->
<typeHandlers>
  <typeHandler handler="org.mybatis.example.ExampleTypeHandler"/>
</typeHandlers>

通过类型处理器的泛型,MyBatis 可以得知该类型处理器处理的 Java 类型,不过这种行为可以通过两种方法改变:

  • 在类型处理器的配置元素(typeHandler element)上增加一个?javaType?属性(比如:javaType="String");
  • 在类型处理器的类上(TypeHandler class)增加一个?@MappedTypes?注解来指定与其关联的 Java 类型列表。 如果在?javaType?属性中也同时指定,则注解方式将被忽略。

可以通过两种方式来指定被关联的 JDBC 类型:

  • 在类型处理器的配置元素上增加一个?javaType?属性(比如:javaType="VARCHAR");
  • 在类型处理器的类上(TypeHandler class)增加一个?@MappedJdbcTypes?注解来指定与其关联的 JDBC 类型列表。 如果在?javaType?属性中也同时指定,则注解方式将被忽略。

4.4 处理枚举类型

若想映射枚举类型?Enum,则需要从?EnumTypeHandler?或者?EnumOrdinalTypeHandler?中选一个来使用。

比如说我们想存储取近似值时用到的舍入模式。默认情况下,MyBatis 会利用?EnumTypeHandler?来把?Enum?值转换成对应的名字。

注意?EnumTypeHandler?在某种意义上来说是比较特别的,其他的处理器只针对某个特定的类,而它不同,它会处理任意继承了?Enum?的类。

不过,我们可能不想存储名字,相反我们的 DBA 会坚持使用整形值代码。那也一样轻而易举: 在配置文件中把?EnumOrdinalTypeHandler?加到?typeHandlers?中即可, 这样每个?RoundingMode?将通过他们的序数值来映射成对应的整形。

4.5 对象工厂

MyBatis 每次创建结果对象的新实例时,它都会使用一个对象工厂(ObjectFactory)实例来完成。 默认的对象工厂需要做的仅仅是实例化目标类,要么通过默认构造方法,要么在参数映射存在的时候通过参数构造方法来实例化。 如果想覆盖对象工厂的默认行为,则可以通过创建自己的对象工厂来实现。

4.6 插件

4.7 配置环境

可以接受环境配置的两个方法签名为:

    SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, environment);
    SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, environment,properties);

1. 事务管理器(transactionManager)

在 MyBatis 中有两种类型的事务管理器(也就是 type="[JDBC|MANAGED]"):

  • JDBC – 这个配置就是直接使用了 JDBC 的提交和回滚设置,它依赖于从数据源得到的连接来管理事务范围。
  • MANAGED – 这个配置几乎没做什么。它从来不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。 默认情况下它会关闭连接,然而一些容器并不希望这样,因此需要将 closeConnection 属性设置为 false 来阻止它默认的关闭行为。

2. 数据源(dataSource)

dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。

  • 许多 MyBatis 的应用程序将会按示例中的例子来配置数据源。然而它并不是必须的。要知道为了方便使用延迟加载,数据源才是必须的。

有三种内建的数据源类型(也就是 type="[UNPOOLED|POOLED|JNDI]"):

UNPOOLED– 这个数据源的实现只是每次被请求时打开和关闭连接。虽然一点慢,它对在及时可用连接方面没有性能要求的简单应用程序是一个很好的选择。 不同的数据库在这方面表现也是不一样的,所以对某些数据库来说使用连接池并不重要,这个配置也是理想的。UNPOOLED 类型的数据源仅仅需要配置以下 5 种属性:

  • driver?– 这是 JDBC 驱动的 Java 类的完全限定名(并不是JDBC驱动中可能包含的数据源类)。
  • url?– 这是数据库的 JDBC URL 地址。
  • username?– 登录数据库的用户名。
  • password?– 登录数据库的密码。
  • defaultTransactionIsolationLevel?– 默认的连接事务隔离级别。

作为可选项,你也可以传递属性给数据库驱动。要这样做,属性的前缀为"driver.",例如:

  • driver.encoding=UTF8

这将通过DriverManager.getConnection(url,driverProperties)方法传递值为?UTF8?的?encoding?属性给数据库驱动。

POOLED– 这种数据源的实现利用"池"的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间。 这是一种使得并发 Web 应用快速响应请求的流行处理方式。

除了上述提到 UNPOOLED 下的属性外,会有更多属性用来配置 POOLED 的数据源:

  • poolMaximumActiveConnections?– 在任意时间可以存在的活动(也就是正在使用)连接数量,默认值:10
  • poolMaximumIdleConnections?– 任意时间可能存在的空闲连接数。
  • poolMaximumCheckoutTime?– 在被强制返回之前,池中连接被检出(checked out)时间,默认值:20000 毫秒(即 20 秒)
  • poolTimeToWait?– 这是一个底层设置,如果获取连接花费的相当长的时间,它会给连接池打印状态日志并重新尝试获取一个连接(避免在误配置的情况下一直安静的失败),默认值:20000 毫秒(即 20 秒)。
  • poolPingQuery?– 发送到数据库的侦测查询,用来检验连接是否处在正常工作秩序中并准备接受请求。默认是"NO PING QUERY SET",这会导致多数数据库驱动失败时带有一个恰当的错误消息。
  • poolPingEnabled?– 是否启用侦测查询。若开启,也必须使用一个可执行的 SQL 语句设置?poolPingQuery?属性(最好是一个非常快的 SQL),默认值:false。
  • poolPingConnectionsNotUsedFor?– 配置 poolPingQuery 的使用频度。这可以被设置成匹配具体的数据库连接超时时间,来避免不必要的侦测,默认值:0(即所有连接每一时刻都被侦测 — 当然仅当 poolPingEnabled 为 true 时适用)。

JNDI– 这个数据源的实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的引用。这种数据源配置只需要两个属性:

  • initial_context?– 这个属性用来在 InitialContext 中寻找上下文(即,initialContext.lookup(initial_context))。这是个可选属性,如果忽略,那么 data_source 属性将会直接从 InitialContext 中寻找。
  • data_source?– 这是引用数据源实例位置的上下文的路径。提供了 initial_context 配置时会在其返回的上下文中进行查找,没有提供时则直接在 InitialContext 中查找。

和其他数据源配置类似,可以通过添加前缀"env."直接把属性传递给初始上下文。比如:

  • env.encoding=UTF8

这就会在初始上下文(InitialContext)实例化时往它的构造方法传递值为?UTF8?的?encoding?属性。

3. databaseldProvider

5. 动态sql

5.1 if

动态sql通常要做的就是有条件的包含where语句的一部分

?5.2 choose、when、otherwise

有些时候,我们不想用到所有的条件语句,而只想从中择其一二。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。

还是上面的例子,但是这次变为提供了"title"就按"title"查找,提供了"author"就按"author"查找,若两者都没有提供,就返回所有符合条件的BLOG(实际情况可能是由管理员按一定策略选出BLOG列表,而不是返回大量无意义的随机结果)。

<select id="findActiveBlogLike"
     resultType="Blog">
  SELECT * FROM BLOG WHERE state = ‘ACTIVE’
  <choose>
    <when test="title != null">
      AND title like #{title}
    </when>
    <when test="author != null and author.name != null">
      AND author_name like #{author.name}
    </when>
    <otherwise>
      AND featured = 1
    </otherwise>
  </choose>
</select>

5.3 trim、set、where

1. where

<select id="findActiveBlogLike"
     resultType="Blog">
  SELECT * FROM BLOG 
  <where> 
    <if test="state != null">
         state = #{state}
    </if> 
    <if test="title != null">
        AND title like #{title}
    </if>
    <if test="author != null and author.name != null">
        AND author_name like #{author.name}
    </if>
  </where>
</select>

where 元素知道只有在一个以上的if条件有值的情况下才去插入"WHERE"子句。而且,若最后的内容是"AND"或"OR"开头的,where 元素也知道如何将他们去除。

所以采用这种方式就也许在单纯使用<if>标签的时候会出现的匹配错误的问题!

2. trim

3. set

那么将set设置为等价的trim应该怎么设置?

<trim prefix="set" prefixOverride=",">? ....? </trim>

5.4 foreach

动态 SQL 的另外一个常用的必要操作是需要对一个集合进行遍历,通常是在构建 IN 条件语句的时候。

<select id="selectPostIn" resultType="domain.blog.Post">
  SELECT *
  FROM POST P
  WHERE ID in
  <foreach item="item" index="index" collection="list"
      open="(" separator="," close=")">
        #{item}
  </foreach>
</select>

foreach 元素的功能是非常强大的,它允许你指定一个集合,声明可以用在元素体内的集合项和索引变量。它也允许你指定开闭匹配的字符串以及在迭代中间放置分隔符。这个元素是很智能的,因此它不会偶然地附加多余的分隔符。

?注意 ?

你可以将一个 List 实例或者数组作为参数对象传给 MyBatis,当你这么做的时候,MyBatis 会自动将它包装在一个 Map 中并以名称为键。List 实例将会以"list"作为键,而数组实例的键将是"array"。

6. javaAPI

6.1 bind

bind?元素可以从 OGNL (对象-图形导航语言)表达式中创建一个变量并将其绑定到上下文。

6.2 Multi-db vendor support

一个配置了"_databaseId"变量的 databaseIdProvider 对于动态代码来说是可用的,这样就可以根据不同的数据库厂商构建特定的语句。

6.3 应用目录结构

典型的目录结构

/my_application
  /bin
  /devlib
  /lib                <-- MyBatis *.jar文件在这里。
  /src
    /org/myapp/
      /action
      /data           <-- MyBatis配置文件在这里, 包括映射器类, XML配置, XML映射文件。
        /mybatis-config.xml
        /BlogMapper.java
        /BlogMapper.xml
      /model
      /service
      /view
    /properties       <-- 在你XML中配置的属性 文件在这里。
  /test
    /org/myapp/
      /action
      /data
      /model
      /service
      /view
    /properties
  /web
    /WEB-INF
      /web.xml

6.4 SqlSessions

使用 MyBatis 的主要 Java 接口就是 SqlSession。尽管你可以使用这个接口执行命令,获 取映射器和管理事务。我们会讨论 SqlSession 本身更多,但是首先我们还是要了解如果获取 一个 SqlSession 实例。SqlSessions 是由 SqlSessionFactory 实例创建的。SqlSessionFactory 对 象 包 含 创 建 SqlSession 实 例 的 所 有 方 法 。 而 SqlSessionFactory 本 身 是 由 SqlSessionFactoryBuilder 创建的,它可以从 XML 配置,注解或手动配置 Java 来创建 SqlSessionFactory。

?注意 ?

当?MyBatis?与?Spring?或?Guice?等依赖注入框架一起使用时,SqlSessions?由?DI(依赖注入) 框架创建和注入,因此您不需要使用?SqlSessionFactoryBuilder?或?SqlSessionFactory,可以直接进入?SqlSession?部分。?

6.5? SqlSessionFactoryBuilder

第一种方法是最常用的,它使用了一个参照了 XML 文档或上面讨论过的更特定的 mybatis-config.xml 文件的 Reader 实例。 可选的参数是 environment 和 properties。 Environment 决定加载哪种环境,包括数据源和事务管理器。

6.6 sqlSessionFactory

SqlSessionFactory 有六个方法可以用来创建 SqlSession 实例。通常来说,如何决定是你选择下面这些方法时:

  • Transaction (事务): 你想为 session 使用事务或者使用自动提交(通常意味着很多数据库和/或 JDBC 驱动没有事务)?
  • Connection (连接): 你想 MyBatis 获得来自配置的数据源的连接还是提供你自己
  • Execution (执行): 你想 MyBatis 复用预处理语句和/或批量更新语句(包括插入和 删除)?

重载的 openSession()方法签名设置允许你选择这些可选中的任何一个组合。

默认的 openSession()方法没有参数,它会创建有如下特性的 SqlSession:

  • 会开启一个事务(也就是不自动提交)
  • 连接对象会从由活动环境配置的数据源实例中得到。
  • 事务隔离级别将会使用驱动或数据源的默认设置。
  • 预处理语句不会被复用,也不会批量处理更新。

这些方法大都可以自我解释的。 开启自动提交, "true" 传递给可选的 autoCommit 参数。 提供自定义的连接,传递一个 Connection 实例给 connection 参数。注意没有覆盖同时设置 Connection 和 autoCommit 两者的方法,因为 MyBatis 会使用当前 connection 对象提供的设置。 MyBatis 为事务隔离级别调用使用一个 Java 枚举包装器, 称为 TransactionIsolationLevel, 否则它们按预期的方式来工作,并有 JDBC 支持的 5 级 ( NONE,READ_UNCOMMITTED,READ_COMMITTED,REPEA TABLE_READ,SERIALIZA BLE)

还有一个可能对你来说是新见到的参数,就是 ExecutorType。这个枚举类型定义了 3 个 值:

  • ExecutorType.SIMPLE: 这个执行器类型不做特殊的事情。它为每个语句的执行创建一个新的预处理语句。
  • ExecutorType.REUSE: 这个执行器类型会复用预处理语句。
  • ExecutorType.BATCH: 这个执行器会批量执行所有更新语句,如果 SELECT 在它们中间执行还会标定它们是 必须的,来保证一个简单并易于理解的行为。

?注意?

在 SqlSessionFactory 中还有一个方法我们没有提及,就是 getConfiguration()。这 个方法会返回一个 Configuration 实例,在运行时你可以使用它来自检 MyBatis 的配置。

6.6 SqlSession

如上面所提到的,SqlSession 实例在 MyBatis 中是非常强大的一个类。在这里你会发现 所有执行语句的方法,提交或回滚事务,还有获取映射器实例。

在 SqlSession 类中有超过 20 个方法,所以将它们分开成易于理解的组合。

1. 语句执行方法

这些方法被用来执行定义在 SQL 映射的 XML 文件中的 SELECT,INSERT,UPDA E T 和 DELETE 语句。它们都会自行解释,每一句都使用语句的 ID 属性和参数对象,参数可以是原生类型(自动装箱或包装类) ,JavaBean,POJO 或 Map。

selectOne 和 selectList 的不同仅仅是 selectOne 必须返回一个对象。 如果多余一个, 或者 没有返回 (或返回了 null) 那么就会抛出异常。如果你不知道需要多少对象, 使用 selectList。

?2.事务控制方法

?3. 清理Session级的缓存

4.? 确保Session被关闭

5. 使用映射器

总之, 每个映射器方法签名应该匹配相关联的 SqlSession 方法, 而没有字符串参数 ID。 相反,方法名必须匹配映射语句的 ID。

此外,返回类型必须匹配期望的结果类型。所有常用的类型都是支持的,包括:原生类 型,Map,POJO 和 JavaBean。

映射器接口不需要去实现任何接口或扩展任何类。 只要方法前面可以被用来唯一标识对 应的映射语句就可以了。

映射器接口可以扩展其他接口。当使用 XML 来构建映射器接口时要保证在合适的命名 空间中有语句。 而且, 唯一的限制就是你不能在两个继承关系的接口中有相同的方法签名 (这 也是不好的想法)。

你可以传递多个参数给一个映射器方法。 如果你这样做了, 默认情况下它们将会以它们 在参数列表中的位置来命名,比如:#{param1},#{param2}等。如果你想改变参数的名称(只在多参数 情况下) ,那么你可以在参数上使用@Param("paramName")注解。

你也可以给方法传递一个 RowBounds 实例来限制查询结果。

6. 映射器注射

因为最初设计时,MyBatis 是一个 XML 驱动的框架。配置信息是基于 XML 的,而且 映射语句也是定义在 XML 中的。而到了 MyBatis 3,有新的可用的选择了。MyBatis 3 构建 在基于全面而且强大的 Java 配置 API 之上。这个配置 API 是基于 XML 的 MyBatis 配置的 基础,也是新的基于注解配置的基础。注解提供了一种简单的方式来实现简单映射语句,而不会引入大量的开销。

7. Mybatis的SQL语句的构造器

7.1 SQL语句的构造器

?7.2 SQL类

// Anonymous inner class
    public String deletePersonSql() {
      return new SQL() {{
        DELETE_FROM("PERSON");
        WHERE("ID = ${id}");
      }}.toString();
    }

    // Builder / Fluent style
    public String insertPersonSql() {
      String sql = new SQL()
        .INSERT_INTO("PERSON")
        .VALUES("ID, FIRST_NAME", "${id}, ${firstName}")
        .VALUES("LAST_NAME", "${lastName}")
        .toString();
      return sql;
    }

    // With conditionals (note the final parameters, required for the anonymous inner class to access them)
    public String selectPersonLike(final String id, final String firstName, final String lastName) {
      return new SQL() {{
        SELECT("P.ID, P.USERNAME, P.PASSWORD, P.FIRST_NAME, P.LAST_NAME");
        FROM("PERSON P");
        if (id != null) {
          WHERE("P.ID like ${id}");
        }
        if (firstName != null) {
          WHERE("P.FIRST_NAME like ${firstName}");
        }
        if (lastName != null) {
          WHERE("P.LAST_NAME like ${lastName}");
        }
        ORDER_BY("P.LAST_NAME");
      }}.toString();
    }

    public String deletePersonSql() {
      return new SQL() {{
        DELETE_FROM("PERSON");
        WHERE("ID = ${id}");
      }}.toString();
    }

    public String insertPersonSql() {
      return new SQL() {{
        INSERT_INTO("PERSON");
        VALUES("ID, FIRST_NAME", "${id}, ${firstName}");
        VALUES("LAST_NAME", "${lastName}");
      }}.toString();
    }

    public String updatePersonSql() {
      return new SQL() {{
        UPDATE("PERSON");
        SET("FIRST_NAME = ${firstName}");
        WHERE("ID = ${id}");
      }}.toString();
    }

??注意?

SQL 类将原样插入 ?LIMIT?、?OFFSET?、?OFFSET n ROWS? 以及 ?FETCH FIRST n ROWS ONLY??子句。换句话说,类库不会为不支持这些子句的数据库执行任何转换。 因此,用户应该要了解目标数据库是否支持这些子句。如果目标数据库不支持这些子句,产生的 SQL 可能会引起运行错误。

7.3 SelectBuilder(已经废弃) 和SqlBuilder

8. MyBatis日志?

8.1 Logging

不少应用服务器的classpath中已经包含Commons Logging,如Tomcat和WebShpere, 所以MyBatis会把它作为具体的日志实现。记住这点非常重要。这将意味着,在诸如 WebSphere的环境中——WebSphere提供了Commons Logging的私有实现,你的Log4J配置将被忽略。 这种做法不免让人悲催,MyBatis怎么能忽略你的配置呢?事实上,因Commons Logging已经存 在了,按照优先级顺序,Log4J自然就被忽略了!不过,如果你的应用部署在一个包含Commons Logging的环境, 而你又想用其他的日志框架,你可以根据需要调用如下的某一方法:?

org.apache.ibatis.logging.LogFactory.useSlf4jLogging();
org.apache.ibatis.logging.LogFactory.useLog4JLogging();
org.apache.ibatis.logging.LogFactory.useJdkLogging();
org.apache.ibatis.logging.LogFactory.useCommonsLogging();
org.apache.ibatis.logging.LogFactory.useStdOutLogging();

??注意??

如果的确需要调用以上的某个方法,请在其他所有MyBatis方法之前调用它。另外,只有在相应日志实现中存在 的前提下,调用对应的方法才是有意义的,否则MyBatis一概忽略。如你环境中并不存在Log4J,你却调用了 相应的方法,MyBatis就会忽略这一调用,代之默认的查找顺序查找日志实现。

8.2 Logging Configuration

?9. MyBatis 3.5.9新特性

?官方下载链接:?Releases · mybatis/mybatis-3 · GitHub

功能上并没有什么变化

10 Mybatis常见问题合集

10.1 大于号、小于号在sql中的转换

?10.2 Mybatis中的ResultType和ResultMap

10.3 Mybatis和ORM的区别

?10.4 Mybatis实现分页功能

10.5 Mybatis的四种分页方式

1. 数组分页

2. Sql分页

3. 拦截器分页

创建拦截器,拦截mybatis接口方法id以ByPage结束的语句

package com.autumn.interceptor;
?
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
?
import java.sql.Connection;
import java.util.Map;
import java.util.Properties;
?
/**
 * @Intercepts 说明是一个拦截器
 * @Signature 拦截器的签名
 * type 拦截的类型 四大对象之一( Executor,ResultSetHandler,ParameterHandler,StatementHandler)
 * method 拦截的方法
 * args 参数,高版本需要加个Integer.class参数,不然会报错
 */
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class})})
public class MyPageInterceptor implements Interceptor {
?
    //每页显示的条目数
    private int pageSize;
    //当前现实的页数
    private int currPage;
    //数据库类型
    private String dbType;
?
?
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        //获取StatementHandler,默认是RoutingStatementHandler
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
        //获取statementHandler包装类
        MetaObject MetaObjectHandler = SystemMetaObject.forObject(statementHandler);
?
        //分离代理对象链
        while (MetaObjectHandler.hasGetter("h")) {
            Object obj = MetaObjectHandler.getValue("h");
            MetaObjectHandler = SystemMetaObject.forObject(obj);
        }
?
        while (MetaObjectHandler.hasGetter("target")) {
            Object obj = MetaObjectHandler.getValue("target");
            MetaObjectHandler = SystemMetaObject.forObject(obj);
        }
?
        //获取连接对象
        //Connection connection = (Connection) invocation.getArgs()[0];
?
?
        //object.getValue("delegate");  获取StatementHandler的实现类
?
        //获取查询接口映射的相关信息
        MappedStatement mappedStatement = (MappedStatement) MetaObjectHandler.getValue("delegate.mappedStatement");
        String mapId = mappedStatement.getId();
?
        //statementHandler.getBoundSql().getParameterObject();
?
        //拦截以.ByPage结尾的请求,分页功能的统一实现
        if (mapId.matches(".+ByPage$")) {
            //获取进行数据库操作时管理参数的handler
            ParameterHandler parameterHandler = (ParameterHandler) MetaObjectHandler.getValue("delegate.parameterHandler");
            //获取请求时的参数
            Map<String, Object> paraObject = (Map<String, Object>) parameterHandler.getParameterObject();
            //也可以这样获取
            //paraObject = (Map<String, Object>) statementHandler.getBoundSql().getParameterObject();
?
            //参数名称和在service中设置到map中的名称一致
            currPage = (int) paraObject.get("currPage");
            pageSize = (int) paraObject.get("pageSize");
?
            String sql = (String) MetaObjectHandler.getValue("delegate.boundSql.sql");
            //也可以通过statementHandler直接获取
            //sql = statementHandler.getBoundSql().getSql();
?
            //构建分页功能的sql语句
            String limitSql;
            sql = sql.trim();
            limitSql = sql + " limit " + (currPage - 1) * pageSize + "," + pageSize;
?
            //将构建完成的分页sql语句赋值个体'delegate.boundSql.sql',偷天换日
            MetaObjectHandler.setValue("delegate.boundSql.sql", limitSql);
        }
        //调用原对象的方法,进入责任链的下一级
        return invocation.proceed();
    }
?
?
    //获取代理对象
    @Override
    public Object plugin(Object o) {
        //生成object对象的动态代理对象
        return Plugin.wrap(o, this);
    }
?
    //设置代理对象的参数
    @Override
    public void setProperties(Properties properties) {
        //如果项目中分页的pageSize是统一的,也可以在这里统一配置和获取,这样就不用每次请求都传递pageSize参数了。参数是在配置拦截器时配置的。
        String limit1 = properties.getProperty("limit", "10");
        this.pageSize = Integer.valueOf(limit1);
        this.dbType = properties.getProperty("dbType", "mysql");
    }
}

4. RowBounds分页

10.6 Mybatis中#{}和${}的区别

10.7 Mybatis接口绑定的两种方式

10.8 Mybatis使用Like进行模糊查询的几种方式?

?

10.9?通常一个mapper.XML对应一个DAO接口,DAO是否可以重载?

10.10?MyBatis映射文件中A标签引用B标签,如果B标签在A的后面定义,可以吗?

?10.11 Mybatis不同映射文件中的id是否可以重复?

10.12 Mybatis是否可以映射到枚举类?

10.13 Mybatis如何获取自动生成的主键ID

?10.14 Mybatis传递多个参数

?10.15 Mybatis缓存机制

缓存机制减轻数据库压力,提高数据库性能

mybatis的缓存分为两级:一级缓存、二级缓存

?10.16 MyBatis时间timestamp做条件进行查询

?本文参考:

MyBatis 教程_w3cschool

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-08-06 10:29:56  更:2022-08-06 10:34:20 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/21 7:24:14-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码