• 猿创征文|13万字学会Spring+SpringMVC+Mybatis框架


    目录

    Spring介绍

    Spring是什么

    Spring发展历程

    Spring优势

    Spring的体系结构 

     Spring快速入门

    Spring程序开发步骤

    idea中快速入门

     Spring配置文件

    Bean标签基本配置

    Bean标签范围配置

     无参构造创建时机

    Bean生命周期配置

     Bean实例化三种方式

      

    Bean的依赖注入分析

    依赖注入概念

    将UserDao注入到UserService内部的方式

    set注入方法改进

     有参构造注入方法

    Bean的依赖注入的数据类型

    集合的数据类型注入

     引入其他配置文件(分模块开发)

    Spring的重点配置

    Spring相关的API

    ApplicationContext的继承体系

    ApplicationContext的实现类

    getBean()方法使用

     Spring配置数据源(连接池)

    数据源的开发步骤

     加载配置文件方式创建

    将DateSource的创建权交给Spring容器去完成

    抽取jdbc配置文件

     Spring注解开发

    Spring原始注解

    使用注解改进

     在UserServiceImpl中其他改进写法

    注解方式注入普通值

    初始方法注解 

    Spring新注解

    使用新注解替换xml文件

     Spring集成Junit

     Spring集成Junit步骤

    Spring与Web环境集成

     项目结构总览

     给Maven配置tomcat服务器

    使用maven手动创建web工程

    ApplicationContext应用上下文获取方法

    优化代码

    解耦合2

    spring自带的监听器

    SpringMVC概述

    web层的框架完成的相应的操作图示

    SpringMVC开发使用步骤

    SpringMVC流程图示

     SpringMVC的组件解析

    SpringMVC执行流程

    执行流程图示

    SpringMVC注解解析

    @RequestMapping

    SpringMVC的xml配置解析

    SpringMVC的相关组件

    SpringMVC的注解和配置

    SpringMVC的数据响应

    SpringMVC的数据响应方式

    ①页面跳转

    ②回写数据

    2、返回ModelAndView对象

    方式1:直接new对象

     方式2:写在方法里让SpringMVC创建

    方式3:model和view分开做

    方式4:通过HttpServletRequest

    回写数据

                                                                                                                                             将字符串转成json格式回传到客户端

    2、直接返回对象或集合      

    使用SpringMVC自动将对象或集合转化为json格式

     注解方式优化转化json

    SpringMVC获得请求数据

    获得请求参数

    基本数据类型

    获得POJO类型参数

     获得数组类型参数

    获得集合类型参数

    静态资源访问的开启

    配置全局乱码过滤器

    参数绑定注解@RequestParam

    注解@RequestParam的参数使用说明

    获得Restful风格的参数

    自定义类型转换器

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

     获得Servlet相关API

    获得请求头

    @RequestHeader

     @CookieValue

    文件上传 

    单文件上传步骤

     多文件上传实现

    法一:写下多个参数

     法二:数组接收

    JdbcTemplate概述

    JdbcTemplate开发步骤

     Spring产生JdbcTemplate对象

    测试插入

     运行时,出现java.lang.NoClassDefFoundError: org/springframework/core/metrics/ApplicationStartup 

    jdbc内容和配置解耦合

    使用Spring集成Junit完成JdbcTemplate修改和删除

     Junit4.11版本导致错误

    删除的操作

    查询操作

    查询所有

     查询单个

    聚合查询

     知识要点总结

     Spring的AOP简介

    什么是AOP

    AOP的作用及其优势

     AOP的底层实现

     AOP的动态代理技术

    JDK动态代理

     cglib的动态代理

    AOP相关概念

      AOP开发明确的事项

    1、需要编写的内容

    2、AOP技术实现的内容

    3、AOP底层使用哪种代理方式

    知识要点总结

    基于xml的AOP开发

     XML配置AOP详解

    切点表达式的写法

    通知/(增强)的类型

     前后置增强

     环绕增强

      异常抛出增强

     最终增强

     切点表达式的抽取

     知识要点

     基于注解的AOP开发

    编写测试 

     注解配置AOP详解

    注解通知的类型

     切点表达式的抽取

    编程式事务控制相关对象

    PlatformTransactionManager平台事务管理

    TransactionDefinition事务定义

    事务的传播行为

    TransactionStatus事务状态

     基于XML的声明式事务控制

    切点方法的事务参数的配置

    基于注解的声明式事务控制

     注解配置声明式事务控制解析

    MyBatis简介

    原始jdbc操作的分析

    什么是Mybatis

    MyBatis开发步骤

    ①添加pom相应的坐标

    ②数据库中创建表

     ③创建pojo下的user类

    ⑥编写测试类

    运行结果

     MyBatis的映射文件概述

     Mybatis增删改查操作

    Mybatis的增加/插入操作

    插入操作注意的问题

    MyBatis的修改数据操作

    Mybatis 删除数据操作

     删除操作注意的问题

    Mybatis常用核心配置文件概述

    envrionment标签

     mapper标签

     typeAliases标签

     MyBatis的相应API

    1、SqlSession工厂构建器SqlSessionFactoryBuilder

    2、SqlSession会话对象

    Mybatis的Dao层实现

    1、传统开发方式-编写UserDao接口

    测试编写UserDao接口

    2、 代理开发方式

    代码测试代理开发 

    Mybatis映射文件深入

    动态sql语句

    官方文档中动态sql

    动态SQL之if

    测试示例if

    动态sql之foreach

    测试示例foreach

     sql片段的抽取

    Mybatis映射文件深入知识小结

    Mybatis核心配置文件深入

     typeHandlers标签

    开发步骤:

    运行时发现 xxx  cannot be cast to xxx 

    plugins标签

    分页助手PageHelper

    开发步骤:

     获取分页相关参数测试

     知识小结之Mybatis核心配置文件标签

      Mybatis的多表操作

    1、一对一查询

    数据库中

    mapper包下orderMapper类下

    pojo包下的order类下

    pojo下user类下

    OrderMapper.xml下

     MybatisTest测试代码下

    运行结果

     OrderMap.xml中也可使用

    2、一对多查询

     UserMapper接口下

    UserMapper.xml下

    Mybatis测试下

    运行结果

    多对多查询

    多对多查询模型

     练习册多对多表查询

    将orders、role、user三者联系起来

     Mybatis的注解开发

    mybatis的常用注解

    注解完成增删改查操作

    新增操作

    修改操作

    删除操作

    查询操作

    查询全部操作

     Mybatis的注解实现复杂映射开发

     一对一注解查询

    查询用户时也查询出订单信息

     另一种,分两次查询

     一对多注解查询

    多对多查询

    SSM框架整合

    原始整合方式

    ①创建数据库

     ②创建maven工程

    ③叁导入maven对应坐标

    ④编写实体类

     ⑤编写Mapper接口(dao接口)

     ⑥编写service接口

     ​编辑

     ⑦编写Service接口实现

     ⑧编写Controller

     ⑨编写jsp添加页面

     ⑩编写列表jsp展示页面

    ①①编写响应的配置文件

    ①②测试添加账户

    ①③测试账户列表

    SSM整合测试

    ①创建数据库

    ②创建maven工程

     ③pom.xml中导入对应的坐标

    ④编写实体类

    ⑤编写Mapper接口(dao接口)

     ⑥编写service接口

     ⑦编写Service接口实现

     ⑧编写Controller

     ⑨编写jsp添加页面

     ⑩编写列表jsp展示页面

    ①①编写响应的配置文件

    applicationContext.xml

    jdbc.properties

    spring-mvc.xml

    sqlMapConfig.xml

    sqlMapConfig-spring.xml

    web.xml

    ①②测试添加账户和账户列表

    ①③数据库中测试


    Spring介绍

    Spring是什么

    Spring是分层的JavaSE/EE应用full-stack轻量级开源框架,以loC(InverseOfControl:反转控制)和 AOP(AspectOrientedProgramming:面向切面编程)为内核。

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

    Spring发展历程

    1997年,IBM提出了EJB的思想
    1998年,SUN制定开发标准规范EJB1.0
    1999年,EJB1.1发布
    2001年,EJB2.0发布
    2003年,EJB2.1发布
    2006年,EJB3.0发布

    Rod Johnson(Spring之父)
    ExpertOne-to-OneJ2EEDesignand Development(2002)
    阐述了J2EE使用EJB开发设计的优点及解决方案
    ExpertOne-to-OneJ2EEDevelopment without EJB(2004)
    阐述了J2EE开发不使用EJB的解决方式(Spring雏形)

    2017年9月份发布了Spring的最新版本 Spring5.0通用版(GA)

    Spring优势

    ①方便解耦,简化开发

    通过Spring提供的loC容器,可以将对象间的依赖关系交由Spring进行控制,避免硬编码所造成的过度耦合。用户也不必再为单例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用。

    ②AOP编程的支持

    通过Sprina的AOP功能,方便进行面向切面编程,许多不容易用传统OOP实现的功能可以通过AOP轻松实现

    ③声明式事务的支持

    可以将我们从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活的进行事务管理,提高开发效率和质量

    ④方便程序的测试

    可以用非容器依赖的编程方式进行几平所有的测试工作,测试不再是昂贵的操作,而是随手可做的事情

    ⑤方便集成各种优秀框架

    Spring对各种优秀框架(Struts、Hibernate、Hessian、Quartz等)的支持。

    ⑥降低JavaEE API的使用难度

    Spring对JavaEEAPI(如JDBC、JavaMail、远程调用等)进行了薄薄的封装层,使这些API的使用难度大为降低

    ⑦Java 源码是经典学习范例

    Spring的源代码设计精妙、结构清晰、匠心独用,处处体现着大师对Java设计模式灵活运用以及对Java技术的高深造诣。它的源代码无意是Java技术的最佳实践的范例。

    Spring的体系结构 

     Spring快速入门

    Spring程序开发步骤

    ①导入Spring开发的基本包坐标

    ②编写Dao接口和实现类

    ③创建Spring核心配置文件

    ④在Spring配置文件中配置UserDaoImpl

    ⑤使用Spring的API获得Bean

    这种 方式完成了解耦,后续只需要给配置文件即可

    idea中快速入门

    ①:在pom.xml中配置spring的坐标

    1. <dependencies>
    2. <dependency>
    3. <groupId>org.springframeworkgroupId>
    4. <artifactId>spring-contextartifactId>
    5. <version>5.0.5.RELEASEversion>
    6. dependency>
    7. dependencies>

    ②:在src下创建com.Dao.UserDao

     创建一个接口

    1. public interface UserDao {
    2. public void play();
    3. }

    创建UserDao的实现类

    1. import com.Dao.UserDao;
    2. public class UserDaoImpl implements UserDao {
    3. public void play(){
    4. System.out.println("play and play...");
    5. }
    6. }

    ③:创建spring核心配置文件(文件的名字任意)

     一般起名为applicationContext.xml

    ④在Spring配置文件中配置UserDaoImpl(id任意)

     id="userDao" class="com.Dao.impl.UserDaoImpl">

     ⑤:使用springAPI获得Bean

    创建一个Demo包下的UserDemo

    1. import com.Dao.UserDao;
    2. import org.springframework.context.ApplicationContext;
    3. import org.springframework.context.support.ClassPathXmlApplicationContext;
    4. public class UserDemo {
    5. public static void main(String[] args) {
    6. ApplicationContext app =new ClassPathXmlApplicationContext("applicationContext.xml");
    7. UserDao userDao = (UserDao) app.getBean("userDao");
    8. userDao.play();
    9. }
    10. }

    运行之后:

     Spring配置文件

    Bean标签基本配置

    用于配置对象交由Spring来创建

    默认情况下他调用的是类中的无参构造函数,如果没有无参构造函数则不能创建成功。

    基本属性:

    id:Bean实例在Spring容器中的唯一标识

    class:Bean的限定名称

    Bean标签范围配置

    scope:指对象的作用范围,取值如下:

    取值范围说明
    singleton默认值,单例的
    prototype多例的
    requestWEB项目中,Spring创建一个Bean的对象,将对象存入到request域中
    sessionWEB项目中,Spring创建一个Bean的对象,将对象存入到session域中
    global sessionWEB项目中,应用在Portlet环境,如果没有Porlet环境那么globalSession相当于session

     下pom.xml中配置junit的坐标

    1. <dependency>
    2. <groupId>junitgroupId>
    3. <artifactId>junitartifactId>
    4. <version>4.11version>
    5. dependency>

     在test模块下创建text类

    1. package com;
    2. import com.Dao.UserDao;
    3. import org.junit.Test;
    4. import org.springframework.context.ApplicationContext;
    5. import org.springframework.context.support.ClassPathXmlApplicationContext;
    6. public class text {
    7. @Test
    8. public void text1(){
    9. ApplicationContext app =new ClassPathXmlApplicationContext("applicationContext.xml");
    10. UserDao userDao1 = (UserDao) app.getBean("userDao");
    11. UserDao userDao2 = (UserDao) app.getBean("userDao");
    12. System.out.println(userDao1);
    13. System.out.println(userDao2);
    14. }
    15. }

     使用singleton打印出来的地址一致说明容器中只有一份

     使用prototype打印出来的地址不一致说明容器中有多份

     无参构造创建时机

    1)当scope的取值为singleton时

    Bean的实例化个数:1个

    Bean的实例化时机:当Spring核心文件被加载时,实例化配置的Bean实例 

    Bean的生命周期:

    •    对象创建:当应用加载,创建容器时,对象就被创建了
    •    对象运行:只要容器在,对象一直活着
    •    对象销毁:当应用卸载,销毁容器时,对象就被销毁了

    2)当scope取值为prototype时

    Bean的实例化个数:多个

    Bean的实例化时机:当调用getBean()方法时实例化Bean

    Bean的生命周期

    •    对象创建:当使用对象时,创建新的对象实例
    •    对象运行:只要对象在使用中,就一直活着
    •    对象销毁:当对象长时间不用时,被Java的垃圾回收器回收了

    Bean生命周期配置

    init-method:指定类中的初始化方法名称

    destory-method:指定类中的销毁方法名称

    在UserDaoImp类下

    创建的初始化方法init和销毁方法destory(名字为任意的)

    1. public class UserDaoImpl implements UserDao {
    2. public void play(){
    3. System.out.println("play and play...");
    4. }
    5. public UserDaoImpl(){
    6. System.out.println("UserDaoImpl被创建");
    7. }
    8. public void init(){
    9. System.out.println("初始化方法");
    10. }
    11. public void destory(){
    12. System.out.println("销毁方法");
    13. }
    14. }

     在applicationContext.xml文件中指定初始化和销毁方法

    1. <bean id="userDao" class="com.Dao.impl.UserDaoImpl"
    2. init-method="init" destroy-method="destory"
    3. >bean>

     在UserDemo方法运行结果:

     Bean实例化三种方式

    无参构造方法实例化

    工厂静态方法实例化

    工厂实例方法实例化

    ①:工厂静态方法实例化

    创建一个factory包下

    1. package com.factory;
    2. import com.Dao.UserDao;
    3. import com.Dao.impl.UserDaoImpl;
    4. public class StaticFactory {
    5. public static UserDao getUserDao(){
    6. return new UserDaoImpl();
    7. }
    8. }

    xml中配置:

    <bean id="userDao" class="com.factory.StaticFactory" factory-method="getUserDao">bean>

     在userDemo下运行,或者在test运行也可

    ② 工厂实例方法实例化演示

    创建一个DynamicFactory类

    1. import com.Dao.UserDao;
    2. import com.Dao.impl.UserDaoImpl;
    3. public class DynamicFactory {
    4. public UserDao getUserDao(){
    5. return new UserDaoImpl();
    6. }
    7. }

    在applicationContext.xml中

    1. <bean id="factory" class="com.factory.DynamicFactory" >bean>
    2. <bean id="userDao" factory-bean="factory" factory-method="getUserDao">bean>

    其余代码不变,在text下运行得

      

    Bean的依赖注入分析

    创建一个Service服务层的接口和实现类

    接口中写入

    1. public interface UserService {
    2. public void save();
    3. }

    service服务层的实现类去实现save方法

    1. public class UserServiceImpl implements UserService {
    2. @Override
    3. public void save() {
    4. ApplicationContext app =new ClassPathXmlApplicationContext("applicationContext.xml");
    5. UserDao userDao = (UserDao) app.getBean("userDao");
    6. userDao.save();
    7. }
    8. }

    dao持久层下的接口和实现类

    1. public interface UserDao {
    2. public void save();
    3. }

    实现类下

    1. public class UserDaoImpl implements UserDao {
    2. public void save(){
    3. System.out.println("run save...");
    4. }
    5. }

    resource下的applicationContext.xml下

    1. "1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    5. <bean id="userDao" class="com.Dao.impl.UserDaoImpl">bean>
    6. <bean id="userService" class="com.Service.Impl.UserServiceImpl">bean>
    7. beans>

    在demo包下模拟web环境的创建一个UserController

    1. import com.Service.UserService;
    2. import org.springframework.context.ApplicationContext;
    3. import org.springframework.context.support.ClassPathXmlApplicationContext;
    4. public class UserController {
    5. public static void main(String[] args) {
    6. ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
    7. UserService userService = (UserService) app.getBean("userService");
    8. userService.save();
    9. }
    10. }

    运行之后

    依赖注入概念

    上面的缺点也很明显,是同时获取service和dao层的到时我们只想要service层,所以此时,需要依赖注入,把dao注入到service服务层

    依赖注入(DependencyInjection):它是Spring框架核心IOC的具体实现。

    在编写程序时,通过控制反转,把对象的创建交给了Spring,但是代码中不可能出现没有依赖的情况。 IOC解耦只是降低他们的依赖关系,但不会消除。例如:业务层仍会调用持久层的方法。

    那这种业务层(Service)和持久层(Dao)的依赖关系,在使用Spring之后,就让Spring来维护了。简单的说,就是坐等框架把持久层对象传入业务层,而不用我们自己去获取

    将UserDao注入到UserService内部的方式

    构造方法和set方法

    法1:set方法

    在UserServiceImpl下创建userDao

    1. import com.Dao.UserDao;
    2. import com.Service.UserService;
    3. public class UserServiceImpl implements UserService {
    4. private UserDao userDao;
    5. public void setUserDao(UserDao userDao) {
    6. this.userDao = userDao;
    7. }
    8. @Override
    9. public void save() {
    10. userDao.save();
    11. }
    12. }

    在applicationContext.xml文件中配置

    1. <bean id="userDao" class="com.Dao.impl.UserDaoImpl">bean>
    2. <bean id="userService" class="com.Service.Impl.UserServiceImpl">
    3. <property name="userDao" ref="userDao">property>
    4. bean>

    然后之前创建的UserController就可以启动了

     如果直接new UserServiceImpl对象会报空指针异常的错,

     因为useDao是不是通过spring容器来获取的,自然就是null值了

    set注入方法改进

    P命名空间注入本质也是set方法注入,但比起上述的set方法更加方便,首先需要引入p命名空间:

       xmlns:p="http://www.springframework.org/schema/p"

    修改注入方式

    <bean id="userService" class="com.Service.Impl.UserServiceImpl" p:userDao-ref="userDao">
    

     是一个对象就用-ref,普通属性就不用

     userController运行之后

     有参构造注入方法

    在applicationContext.xml文件中

    1. <bean id="userService" class="com.Service.Impl.UserServiceImpl">
    2. <constructor-arg name="userDao" ref="userDao">constructor-arg>
    3. bean>

    userServiceImpl下 

     运行结果:

    Bean的依赖注入的数据类型

    上面的操作,都是注入引用Bean,除了对象的引用可以注入,普通数据类型,集合都可以在容器中进行注入。

    注入数据的三种数据类型

    • 普通数据类型
    • 引用数据类型
    • 集合数据类型

    普通数据注入,如在UserDao层注入两个普通数据类型(采用set方式注入)

    1. public class UserDaoImpl implements UserDao {
    2. private String name;
    3. private int age;
    4. public void setName(String name) {
    5. this.name = name;
    6. }
    7. public void setAge(int age) {
    8. this.age = age;
    9. }
    10. public void save(){
    11. System.out.println("姓名:"+name+"年龄:"+age);
    12. System.out.println("run save...");
    13. }
    14. }

    在applicationContext.xml文件中,在配置dao中设置参数

    1. <bean id="userDao" class="com.Dao.impl.UserDaoImpl">
    2. <property name="name" value="李四"/>
    3. <property name="age" value="20" />
    4. bean>

    在Usercontroller下

    1. public class UserController {
    2. public static void main(String[] args) {
    3. ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
    4. UserService userService = (UserService) app.getBean("userService");
    5. userService.save();
    6. }
    7. }

    运行结果

    集合的数据类型注入

    在UserDaoImpl下

    采用set注入方式,设置集合,提供对应得set方法

    1. package com.Dao.impl;
    2. import com.Dao.UserDao;
    3. import com.pojo.User;
    4. import java.util.List;
    5. import java.util.Map;
    6. import java.util.Properties;
    7. public class UserDaoImpl implements UserDao {
    8. private List strList;
    9. private Map userMap;
    10. private Properties properties;
    11. public void setStrList(List strList) {
    12. this.strList = strList;
    13. }
    14. public void setUserMap(Map userMap) {
    15. this.userMap = userMap;
    16. }
    17. public void setProperties(Properties properties) {
    18. this.properties = properties;
    19. }
    20. public void play(){
    21. System.out.println("play and play...");
    22. }
    23. public void save(){
    24. System.out.println("List集合-》"+strList);
    25. System.out.println("Map集合-》"+userMap);
    26. System.out.println("properties集合-》"+properties);
    27. System.out.println("run save...");
    28. }
    29. }

     在applicationContext.xml下配置注入值

    1. "1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xmlns:p="http://www.springframework.org/schema/p"
    5. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    6. <bean id="userDao" class="com.Dao.impl.UserDaoImpl">
    7. <property name="strList" >
    8. <list>
    9. <value>慧慧value>
    10. <value>孔超value>
    11. <value>value>
    12. list>
    13. property>
    14. <property name="userMap">
    15. <map>
    16. <entry key="宝1" value-ref="user1">entry>
    17. <entry key="宝2" value-ref="user2">entry>
    18. map>
    19. property>
    20. <property name="properties">
    21. <props>
    22. <prop key="p1">宝1prop>
    23. <prop key="p2">宝2prop>
    24. props>
    25. property>
    26. bean>
    27. <bean id="user1" class="com.pojo.User">
    28. <property name="name" value="慧慧"/>
    29. <property name="address" value="赣州"/>
    30. bean>
    31. <bean id="user2" class="com.pojo.User">
    32. <property name="name" value="孔超"/>
    33. <property name="address" value="赣州"/>
    34. bean>
    35. <bean id="userService" class="com.Service.Impl.UserServiceImpl">
    36. <constructor-arg name="userDao" ref="userDao">constructor-arg>
    37. bean>
    38. beans>

    在UserController测试下

    1. import com.Service.UserService;
    2. import org.springframework.context.ApplicationContext;
    3. import org.springframework.context.support.ClassPathXmlApplicationContext;
    4. public class UserController {
    5. public static void main(String[] args) {
    6. ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
    7. UserService userService = (UserService) app.getBean("userService");
    8. userService.save();
    9. }
    10. }

    运行结果: 

     引入其他配置文件(分模块开发)

    实际开发中,Spring的配置内容非常的多,这就导致Spring配置很繁琐且体积很大,所以可以将部分配置拆解到其他配置文件中,而且主配置文件通过import标签进行加载

    语法格式:

    <import resource="xxxx.xml"/>

    Spring的重点配置

    标签

    • id属性:在容器中Bean实例的唯一标识,不允许重复
    • class属性:要实例化的Bean的全限定名
    • scope属性:bean的作用范围,常用是Singleton(默认)和prototype

    标签:属性注入

    •         name属性:属性名称
    •         value属性:注入的普通属性值
    •         ref属性:注入的对象引用值

    标签

    标签

    标签

    标签:导入其他的Spring的分文件

    Spring相关的API

    ApplicationContext的继承体系

    applicationContext:接口类型,代表应用上下文,可以通过其实例获得Spring容器中的Bean对象

     紫色的为接口,浅绿色的为抽象类,绿色的为实现类

    ApplicationContext的实现类

    ①ClassPathXmlApplicationContext

    它是从类的跟路径下加载配置文件,只需要创建resource下的xml,参数写入xxx.xml即可(推荐使用)

    ②FileSystemXmlApplicationContext

    他是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置。

    ③AnnotationConfigApplicationContext

    当使用注解配置容器对象时,需要食用此类来创建spring容器骂他用来读取注解

    getBean()方法使用

    1. //根据id找
    2. public object getBean(String name) throws BeansException {
    3. assertBeanFactoryActive();
    4. return getBeanFactory().getBean(name);
    5. }
    6. //根据字节码对象找
    7. public T getBean(Class requiredType) throws BeansException {
    8. assertBeanFactoryActive();
    9. return getBeanFactory().getBean(requiredType);
    10. }

    其中,当参数的数据类型是字符串时,表示根据Bean的id从容器这种获得Bean实例,返回Object,需要强转。当参数的数据类型是Class类型是,表示根据类型从容器中匹配Bean实例,当容器中相同类型的Bean有多个是是,则clss方法会报错

    根据id

     根据字节码对象

    某一类型的bean对象存在多对时,只能使用id,因为id是唯一的,某一类型的bean对象存在一对是时,可以用id,也可以使用字节码对象,使用字节码对象更方便些。

     Spring配置数据源(连接池)

    •  数据源(连接池)是提高程序性能出现的
    • 事先实例化数据源,初始化部分连接资源
    • 使用连接资源时从数据源中获取
    • 使用完毕后将连接资源归还给数据源

    常见的数据源(连接池):DBCP、C3P0、BoneCP、Druid

    数据源的开发步骤

    1. 导入数据源的坐标和数据库驱动坐标
    2. 创建数据源对象
    3. 设置数据源的基本连接数据
    4. 使用数据源获取连接资源和归还连接资源

    ①:导入数据源坐标

    1. <dependencies>
    2. <dependency>
    3. <groupId>mysqlgroupId>
    4. <artifactId>mysql-connector-javaartifactId>
    5. <version>5.1.32version>
    6. dependency>
    7. //c3p0数据源
    8. <dependency>
    9. <groupId>c3p0groupId>
    10. <artifactId>c3p0artifactId>
    11. <version>0.9.1.2version>
    12. dependency>
    13. //druid数据源
    14. <dependency>
    15. <groupId>com.alibabagroupId>
    16. <artifactId>druidartifactId>
    17. <version>1.1.10version>
    18. dependency>
    19. <dependency>
    20. <groupId>junitgroupId>
    21. <artifactId>junitartifactId>
    22. <version>4.11version>
    23. <scope>testscope>
    24. dependency>
    25. dependencies>

    在test测试中创建类

    1. package com.test;
    2. import com.mchange.v2.c3p0.ComboPooledDataSource;
    3. import org.junit.Test;
    4. import java.sql.Connection;
    5. public class DateSourceTest {
    6. @Test
    7. public void test1() throws Exception{
    8. ComboPooledDataSource dataSource=new ComboPooledDataSource();
    9. dataSource.setDriverClass("com.mysql.jdbc.Driver");
    10. //访问数据库中kc_db01库
    11. dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/kc_db01");
    12. //数据库的账号密码
    13. dataSource.setUser("root");
    14. dataSource.setPassword("123456");
    15. Connection connection=dataSource.getConnection();
    16. System.out.println(connection);
    17. connection.close();
    18. }
    19. }

     运行结果

     打印出地址说明连接成功

    测试连接druid 

    1. @Test
    2. public void test2() throws Exception{
    3. DruidDataSource dataSource=new DruidDataSource();
    4. dataSource.setDriverClassName("com.mysql.jdbc.Driver");
    5. //访问数据库中kc_db01库
    6. dataSource.setUrl("jdbc:mysql://localhost:3306/kc_db01");
    7. //数据库的账号密码
    8. dataSource.setUsername("root");
    9. dataSource.setPassword("123456");
    10. Connection connection=dataSource.getConnection();
    11. System.out.println(connection);
    12. connection.close();
    13. }

     加载配置文件方式创建

    在resource资源下创建一个MyJdbc.properties文件测试c3p0数据源)

    内容是:

    1. jdbc.driver=com.mysql.jdbc.Driver
    2. jdbc.url=jdbc:mysql://localhost:3306/kc_db01
    3. jdbc.username=root
    4. jdbc.password=123456

    在测试类中:

    1. @Test
    2. //测试手动创建c3p0数据库源(加载properties配置文件)
    3. public void test3() throws Exception{
    4. //读取配置文件,获取的参数是你设置的配置文件的名字,
    5. ResourceBundle rb=ResourceBundle.getBundle("MyJdbc");
    6. String driver=rb.getString("jdbc.driver");
    7. String url=rb.getString("jdbc.url");
    8. String username=rb.getString("jdbc.username");
    9. String password=rb.getString("jdbc.password");
    10. //创建数据源对象,设置连接参数
    11. ComboPooledDataSource dataSource=new ComboPooledDataSource();
    12. dataSource.setDriverClass(driver);
    13. dataSource.setJdbcUrl(url);
    14. dataSource.setUser(username);
    15. dataSource.setPassword(password);
    16. Connection connection=dataSource.getConnection();
    17. System.out.println(connection);
    18. connection.close();
    19. }

    运行结果:

     配置文件的好处有给程序解耦,打完包之后不会变化,程序打完包都是对应的字节码文件,而配置文件还是原模原样。

    将DateSource的创建权交给Spring容器去完成

    先在pom.xml导入spring的基本坐标

    1. <dependency>
    2. <groupId>org.springframeworkgroupId>
    3. <artifactId>spring-contextartifactId>
    4. <version>5.0.5.RELEASEversion>
    5. dependency>

    在resource资源下创建ApplicationContext.xml

    1. "1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    5. <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    6. <property name="driverClass" value="com.mysql.jdbc.Driver">property>
    7. <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/kc_db01">property>
    8. <property name="user" value="root">property>
    9. <property name="password" value="123456">property>
    10. bean>
    11. beans>

    在DataSourceTest类下

    1. @Test
    2. public void test4() throws Exception{
    3. ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
    4. // DataSource dataSource= (DataSource) app.getBean("dataSource");
    5. DataSource dataSource= app.getBean(DataSource.class);
    6. Connection connection=dataSource.getConnection();
    7. System.out.println(connection);
    8. connection.close();
    9. }

    运行结果

    抽取jdbc配置文件

    applicationContext.xml加载jdbc.properties配置文件获得连接信息

    首先,需要引入context命名空间和约束路径:

    命名空间:

    xmlns:context="http://www.springframework.org/schema/context"

    约束路径:

    1. http://www.springframework.org/schema/context
    2. http://www.springframework.org/schema/context/spring-context.xsd

     applicationContext.xml文件

    1. "1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xmlns:context="http://www.springframework.org/schema/context"
    5. xsi:schemaLocation=
    6. "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    7. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    8. <context:property-placeholder location="classpath:MyJdbc.properties"/>
    9. <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    10. <property name="driverClass" value="${jdbc.driver}">property>
    11. <property name="jdbcUrl" value="${jdbc.url}">property>
    12. <property name="user" value="${jdbc.username}">property>
    13. <property name="password" value="${jdbc.password}">property>
    14. bean>
    15. beans>

    MyJdbc.properties文件下

    1. jdbc.driver=com.mysql.jdbc.Driver
    2. jdbc.url=jdbc:mysql://localhost:3306/kc_db01
    3. jdbc.username=root
    4. jdbc.password=123456

    类中代码不变,运行结果为

     Spring注解开发

    Spring是轻代码而中配置,配置比较繁琐,影响开发效率,所以注解开发是一种趋势,注解代替xml配置文件可以简化配置,提高开发效率。

    Spring原始注解

    Spring原始注解主要是替代的配置

    注意:使用注解进行开发是,需要在applicationContext.xml中配置组件扫描,作用是值定哪个宝及其子包下的Bean需要进行扫描以便识别使用注解的类、字段个方法

    使用注解改进

    在com包下创建Dao包,service包,web包

    在Dao包下的UserDao接口

    1. public interface UserDao {
    2. public void save();
    3. }

    在Dao包下的Impl包下的UserDaoImpl类

    注解替换位置

    1. //
    2. @Component("userDao")
    3. //这个注解和上面xml一样
    1. package com.Dao.impl;
    2. import com.Dao.UserDao;
    3. import org.springframework.stereotype.Component;
    4. //
    5. @Component("userDao")
    6. //这个注解和上面xml一样
    7. public class UserDaoImpl implements UserDao {
    8. @Override
    9. public void save() {
    10. System.out.println("running...");
    11. }
    12. }

     service包下的UserService接口

    1. public interface UserService {
    2. public void save();
    3. }

     service包下的Impl包下的UserServiceImpl类

    注解替换位置

    1. //
    2. @Component("userService")//这是一个组件,这个注解等于以上的xml配置
    1. //
    2. @Autowired // 这个表示自动注入
    3. @Qualifier("userDao")//里面写要注入的bean的id
    1. package com.service.Impl;
    2. import com.Dao.UserDao;
    3. import com.service.UserService;
    4. import org.springframework.beans.factory.annotation.Autowired;
    5. import org.springframework.beans.factory.annotation.Qualifier;
    6. import org.springframework.stereotype.Component;
    7. //
    8. @Component("userService")//这是一个组件
    9. public class UserServiceImpl implements UserService {
    10. //
    11. @Autowired // 这个表示自动注入
    12. @Qualifier("userDao")//里面写要注入的bean的id
    13. private UserDao userDao;
    14. //使用注解可以不写set方法
    15. /* public void setUserDao(UserDao userDao) {
    16. this.userDao = userDao;
    17. }
    18. */
    19. @Override
    20. public void save() {
    21. userDao.save();
    22. }
    23. }

    在web包下的UserController类下

    1. package com.web;
    2. import com.service.UserService;
    3. import org.springframework.context.ApplicationContext;
    4. import org.springframework.context.support.ClassPathXmlApplicationContext;
    5. public class UserController {
    6. public static void main(String[] args) {
    7. ApplicationContext app=new ClassPathXmlApplicationContext("ApplicationContext.xml");
    8. UserService userService = app.getBean(UserService.class);
    9. userService.save();
    10. }
    11. }

    运行结果

     在UserServiceImpl中其他改进写法

    1. @Component("userService")//这是一个组件
    2. public class UserServiceImpl implements UserService {
    3. //
    4. @Autowired // 按照数据类型从Spring容器中进行匹配的
    5. private UserDao userDao;
    6. @Override
    7. public void save() {
    8. userDao.save();
    9. }
    10. }

    如果根据id进行匹配就要

    1. @Autowired // 按照数据类型从Spring容器中进行匹配的
    2. @Qualifier("userDao")//是按照id从容器中进行匹配的,但是主要此处的 @Qualifier结合@Autowired一起使用
     @Resource(name ="userDao")//等价于 @Autowired +@Qualifier
    1. package com.service.Impl;
    2. import com.Dao.UserDao;
    3. import com.service.UserService;
    4. import org.springframework.beans.factory.annotation.Autowired;
    5. import org.springframework.beans.factory.annotation.Qualifier;
    6. import org.springframework.stereotype.Component;
    7. import javax.annotation.Resource;
    8. //
    9. @Component("userService")//这是一个组件
    10. public class UserServiceImpl implements UserService {
    11. //
    12. // @Autowired // 按照数据类型从Spring容器中进行匹配的
    13. // @Qualifier("userDao")//是按照id从容器中进行匹配的,但是主要此处的 @Qualifier结合@Autowired一起使用
    14. @Resource(name ="userDao")//等价于 @Autowired +@Qualifier
    15. private UserDao userDao;
    16. @Override
    17. public void save() {
    18. userDao.save();
    19. }
    20. }

     使用注解的方式set方法可以省略不写,使用想xml配置就必须写,注解是通过反射

    注解方式注入普通值

    @Value可以注入值,一般使用el表达式获取配置文件中的值

    1. @Value("${jdbc.driver}")
    2. private String user;

    运行结果 

     也可以注入普通值,但是显示十分的多余,下面两种方式一样。

    1. @Value("hello")
    2. private String test;
    3. private String test="hello";

    初始方法注解 

    在serviceImpl中

    1. @PostConstruct
    2. public void init(){
    3. System.out.println("初始方法");
    4. }
    5. @PreDestroy
    6. public void destory(){
    7. System.out.println("销毁方法");
    8. }

    Spring新注解

    使用上面的注解还不能 全部不代替xml配置文件,还需要使用注解替代的配置如下:

    非自定义的Bean的配置:

    加载properties文件的配置:

    组件扫描的配置:

    引入其他文件:

    spring新注解

    使用新注解替换xml文件

    在config包下,创建名为DataSourceConfiguration类下

    1. package com.config;
    2. import com.mchange.v2.c3p0.ComboPooledDataSource;
    3. import org.springframework.beans.PropertyAccessException;
    4. import org.springframework.beans.factory.annotation.Value;
    5. import org.springframework.context.annotation.Bean;
    6. import org.springframework.context.annotation.PropertySource;
    7. import javax.sql.DataSource;
    8. import java.beans.PropertyVetoException;
    9. // 加载外部properties文件
    10. @PropertySource("classpath:MyJdbc.properties")
    11. public class DataSourceConfiguration {
    12. @Value("${jdbc.driver}")
    13. private String driver;
    14. @Value("${jdbc.url}")
    15. private String url;
    16. @Value("${jdbc.password}")
    17. private String password;
    18. @Value("${jdbc.username}")
    19. private String username;
    20. @Bean("dataSource")//Spring会将当前方法的返回值以指定名称存储到Spring容器中
    21. public DataSource getDateSource() throws PropertyAccessException, PropertyVetoException {
    22. ComboPooledDataSource dataSource=new ComboPooledDataSource();
    23. dataSource.setDriverClass(driver);
    24. dataSource.setJdbcUrl(url);
    25. dataSource.setPassword(password);
    26. dataSource.setUser(username);
    27. return dataSource;
    28. }
    29. }

    在config包下创建SpringConfiguration类下

    1. package com.config;
    2. import com.mchange.v2.c3p0.ComboPooledDataSource;
    3. import org.springframework.beans.PropertyAccessException;
    4. import org.springframework.beans.factory.annotation.Value;
    5. import org.springframework.context.annotation.*;
    6. import javax.sql.DataSource;
    7. import java.beans.PropertyVetoException;
    8. //标志该类是Spring的核心配置类
    9. @Configuration
    10. // base是基本包他会扫描其子类下的所有包
    11. @ComponentScan("com")
    12. //在总配置中加载分配置,加载核心配置类,若有多个,则写xx.class,xxx.class....
    13. @Import(DataSourceConfiguration.class)
    14. public class SpringConfiguration {
    15. }

    web包下的UserController测试下

    1. package com.web;
    2. import com.config.SpringConfiguration;
    3. import com.service.UserService;
    4. import org.springframework.context.ApplicationContext;
    5. import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    6. import org.springframework.context.support.ClassPathXmlApplicationContext;
    7. public class UserController {
    8. public static void main(String[] args) {
    9. //ApplicationContext app=new ClassPathXmlApplicationContext("ApplicationContext.xml");
    10. ApplicationContext app=new AnnotationConfigApplicationContext(SpringConfiguration.class);
    11. UserService userService = app.getBean(UserService.class);
    12. userService.save();
    13. }
    14. }

    运行结果

     Spring集成Junit

    原始Junit测试Spring的问题

    在测试类中,每个测试方法都有一下两行代码:

    1. //获得应用上下文对象
    2. ApplicationContext ac=new ClassPathXmlApplicationContext("bean.xml");
    3. //获取要被测试的对象
    4. IAccountService as=ac.getBean("accountService",IAccountService.class);

    这两行代码的作用是获取容器,如果不写的话,直接会提示空指针异常,所以又不能轻易删除。

    解决思路

    • 让SpringJunit负责创建Spring容器,但是需要将配置文件的名称告诉他
    • 将需要进行测试Bean直接在测试类中进行注入 

     Spring集成Junit步骤

    ①导入spring集成Junit的坐标(首先导入好junit)

    ②使用@Runwith注解替换原来的运行期

    ③使用@ContextConfiguration指定配置文件或配置类

    ④使用@Autowired注入需要测试的对象

    ⑤创建测试方法进行测试

    在pom.xml中导入

    1. <dependencies>
    2. <dependency>
    3. <groupId>org.springframeworkgroupId>
    4. <artifactId>spring-contextartifactId>
    5. <version>5.0.5.RELEASEversion>
    6. dependency>
    7. <dependency>
    8. <groupId>junitgroupId>
    9. <artifactId>junitartifactId>
    10. <version>4.12version>
    11. dependency>
    12. <dependency>
    13. <groupId>org.springframeworkgroupId>
    14. <artifactId>spring-testartifactId>
    15. <version>5.0.5.RELEASEversion>
    16. dependency>
    17. dependencies>

     在test包下创建SpringJunitTest类

    1. package com.test;
    2. import com.service.UserService;
    3. import org.junit.Test;
    4. import org.junit.runner.RunWith;
    5. import org.springframework.beans.factory.annotation.Autowired;
    6. import org.springframework.test.context.ContextConfiguration;
    7. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    8. //指定Spring提供的内核去测试
    9. @RunWith(SpringJUnit4ClassRunner.class)
    10. //将要测试的文件告诉它
    11. @ContextConfiguration("classpath:ApplicationContext.xml")
    12. public class SpringJunitTest {
    13. @Autowired
    14. private UserService userService;
    15. @Test
    16. public void test1(){
    17. userService.save();
    18. }
    19. }

    测试结果

    Spring与Web环境集成

    在创建dao包,创建service包,创建web包,在resource资源

    在创建一个UserDao和UserDaoImpl实现类

    接口下

    1. package com.dao;
    2. public interface UserDao {
    3. public void save();
    4. }

     实现类

    1. package com.dao.Impl;
    2. import com.dao.UserDao;
    3. public class UserDaoImpl implements UserDao {
    4. public void save() {
    5. System.out.println("save running...");
    6. }
    7. }

    service包下,创建UserService和UserServiceImpl

    接口

    1. package com.service;
    2. public interface UserService {
    3. public void save();
    4. }

    实现类下

    1. package com.service.Impl;
    2. import com.dao.UserDao;
    3. import com.service.UserService;
    4. public class UserServiceImpl implements UserService {
    5. public UserDao userDao;
    6. public void setUserDao(UserDao userDao) {
    7. this.userDao = userDao;
    8. }
    9. public void save() {
    10. userDao.save();
    11. }
    12. }

    pom.xml下

    1. <dependencies>
    2. <dependency>
    3. <dependency>
    4. <groupId>junitgroupId>
    5. <artifactId>junitartifactId>
    6. <version>4.11version>
    7. dependency>
    8. <dependency>
    9. <groupId>org.springframeworkgroupId>
    10. <artifactId>spring-testartifactId>
    11. <version>5.0.5.RELEASEversion>
    12. dependency>
    13. <dependency>
    14. <groupId>javax.servlet.jspgroupId>
    15. <artifactId>javax.servlet.jsp-apiartifactId>
    16. <version>2.2.1version>
    17. <scope>providedscope>
    18. dependency>
    19. <dependency>
    20. <groupId>javax.servlet.jspgroupId>
    21. <artifactId>javax.servlet.jsp-apiartifactId>
    22. <version>2.2.1version>
    23. <scope>providedscope>
    24. dependency>
    25. <dependency>
    26. <groupId>org.springframeworkgroupId>
    27. <artifactId>spring-contextartifactId>
    28. <version>5.3.0version>
    29. <scope>compilescope>
    30. dependency>
    31. dependencies>

    resource资源路径下

     applicationContext.xml下

    1. "1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    5. <bean id="userDao" class="com.dao.Impl.UserDaoImpl">bean>
    6. <bean id="userService" class="com.service.Impl.UserServiceImpl">
    7. <property name="userDao" ref="userDao">property>
    8. bean>
    9. beans>

    web包下,UserServlet类下,使用注解完成配置

    1. package com.web;
    2. import com.service.UserService;
    3. import org.springframework.context.ApplicationContext;
    4. import org.springframework.context.support.ClassPathXmlApplicationContext;
    5. import javax.servlet.ServletException;
    6. import javax.servlet.annotation.WebServlet;
    7. import javax.servlet.http.HttpServlet;
    8. import javax.servlet.http.HttpServletRequest;
    9. import javax.servlet.http.HttpServletResponse;
    10. import java.io.IOException;
    11. //使用注解代替web.xml中的配置
    12. @WebServlet("/user")
    13. public class UserServlet extends HttpServlet {
    14. @Override
    15. protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    16. ApplicationContext app= new ClassPathXmlApplicationContext("applicationContext.xml");
    17. UserService userService = app.getBean(UserService.class);
    18. userService.save();
    19. System.out.println("jin");
    20. }
    21. }

     项目结构总览

     给Maven配置tomcat服务器

    首先这得是war包,如果这是普通包得添加webapp,并将pom.xml中加入如下,表示这是一个web文件

      <packaging>warpackaging>

    加完之后点击编辑配置

     其下的war二选一即可

     完成之后点击确认即可完成配置。

    使用maven手动创建web工程

    第一步,点击项目结构,选中 要添加的maven工程,右键添加web。

     第二步,点击web工程,修改web工程路径

     点击完成即可完成web工程的手动配置。

    ApplicationContext应用上下文获取方法

    应用上下文对象是通过new  ClasspathXmlApplicationContext(spring配置文件)方式获取的,但是每次从容器中获得Bean时都要编写new  ClasspathXmlApplicationContext(spring配置文件),这样的弊端是配置文件加载多次,应用上下文对象创建多次。

    在Web项目中,可以使用ServletContextListener监听Web应用的启动,我们可以在Web应用启动时,就加载Sprina的配置文件,创建应用上下文对象ApplicationContext,在将其存储到最大的域servletContext域中,这样就可以在任意位置从域中获得应用上下文ApplicationContext对象了。

    新建一个Listenter包下的ContextLoderListener

    1. package com.Listener;
    2. import org.springframework.context.ApplicationContext;
    3. import org.springframework.context.support.ClassPathXmlApplicationContext;
    4. import javax.servlet.ServletContext;
    5. import javax.servlet.ServletContextEvent;
    6. import javax.servlet.ServletContextListener;
    7. public class ContextLoaderListener implements ServletContextListener {
    8. public void contextInitialized(ServletContextEvent servletContextEvent) {
    9. ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
    10. //将Spring的应用上下文对象存储到ServletContext域中
    11. ServletContext servletContext = servletContextEvent.getServletContext();
    12. servletContext.setAttribute("app", app);
    13. System.out.println("Spring容器创建完毕");
    14. }
    15. public void contextDestroyed(ServletContextEvent servletContextEvent) {
    16. }
    17. }

    web包下

    1. package com.web;
    2. import com.service.*;
    3. import org.springframework.context.ApplicationContext;
    4. import javax.servlet.ServletContext;
    5. import javax.servlet.ServletException;
    6. import javax.servlet.annotation.WebServlet;
    7. import javax.servlet.http.HttpServlet;
    8. import javax.servlet.http.HttpServletRequest;
    9. import javax.servlet.http.HttpServletResponse;
    10. import java.io.IOException;
    11. @WebServlet("/user")
    12. public class UserServlet extends HttpServlet {
    13. @Override
    14. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    15. // ApplicationContext app= new ClassPathXmlApplicationContext("applicationContext.xml");
    16. ServletContext servletContext = req.getServletContext();
    17. ApplicationContext app = (ApplicationContext) servletContext.getAttribute("app");
    18. UserService userService=app.getBean(UserService.class);
    19. }
    20. }

    web.xml下配置监听器

    1. "1.0" encoding="UTF-8"?>
    2. <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
    5. version="4.0">
    6. <listener>
    7. <listener-class>com.Listener.ContextLoaderListenerlistener-class>
    8. listener>
    9. web-app>

    自动创建spring容器

    优化代码

    解耦合1

    由于监听器内部我们将代码写固定了,不利于后期的维护操作,所以要解耦合,写在配置文件中进行解耦合。(“”引号内的名字任意)

    ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");

    将此个代码写入到web.xml中进

    1. <context-param>
    2. <param-name>ContextConfigLocationparam-name>
    3. <param-value>applicationContext.xmlparam-value>
    4. context-param>

    在ContextLoaderListenter类中

    1. package com.Listener;
    2. import org.springframework.context.ApplicationContext;
    3. import org.springframework.context.support.ClassPathXmlApplicationContext;
    4. import javax.servlet.ServletContext;
    5. import javax.servlet.ServletContextEvent;
    6. import javax.servlet.ServletContextListener;
    7. public class ContextLoaderListener implements ServletContextListener {
    8. public void contextInitialized(ServletContextEvent servletContextEvent) {
    9. ServletContext servletContext = servletContextEvent.getServletContext();
    10. //读取web.xml中的全局参数
    11. String contextConfigLocation = servletContext.getInitParameter("ContextConfigLocation");
    12. ApplicationContext app = new ClassPathXmlApplicationContext(contextConfigLocation);
    13. //将Spring的应用上下文对象存储到ServletContext域中
    14. servletContext.setAttribute("app", app);
    15. System.out.println("Spring容器创建完毕");
    16. }
    17. }

    读取配置文件的值,这样就完成了解耦合

    解耦合2

    在userServlet类中 

    ApplicationContext app = (ApplicationContext) servletContext.getAttribute("app");

    这样耦合了app代码,让这个只能叫做app,这样不利于后期维护和辨认。

    所以我们这么改,在Listener包下创建一个工具类WebApplicationContextUtils

    1. package com.Listener;
    2. import org.springframework.context.ApplicationContext;
    3. import javax.servlet.ServletContext;
    4. public class WebApplicationContextUtils {
    5. public static ApplicationContext getApplicationContext(ServletContext servletContext){
    6. return (ApplicationContext) servletContext.getAttribute("app");
    7. }
    8. }

    在userServlet处代码修改为

    1. package com.web;
    2. import com.Listener.WebApplicationContextUtils;
    3. import com.service.*;
    4. import org.springframework.context.ApplicationContext;
    5. import javax.servlet.ServletContext;
    6. import javax.servlet.ServletException;
    7. import javax.servlet.annotation.WebServlet;
    8. import javax.servlet.http.HttpServlet;
    9. import javax.servlet.http.HttpServletRequest;
    10. import javax.servlet.http.HttpServletResponse;
    11. import java.io.IOException;
    12. @WebServlet("/user")
    13. public class UserServlet extends HttpServlet {
    14. @Override
    15. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    16. // ApplicationContext app= new ClassPathXmlApplicationContext("applicationContext.xml");
    17. ServletContext servletContext = req.getServletContext();
    18. //ApplicationContext app = (ApplicationContext) servletContext.getAttribute("app");
    19. //变动处
    20. ApplicationContext app = WebApplicationContextUtils.getApplicationContext(servletContext);
    21. UserService userService=app.getBean(UserService.class);
    22. }
    23. }

    spring自带的监听器

    上面写出的手动实现的监听器,Spring提供了一个监听器ContextLoderListener就是对上述功能的封装,该监听器内部加载Spring配置文件,创建应用上下文对象,并存储到ServletContext域中,提供一个客户亿工具WebApplicationContextUtils供使用者获得上下文对象

    要使用监听器,需要做两件事

    ①:在web.xml中配置ContextLoaderListener监听器(导入spring-web坐标)

    ②:使用WebApplicationContextUtils获得应用上下文对象  ApplicationContext              

    在pim.xml中导入坐标

    1. <dependency>
    2. <groupId>org.springframeworkgroupId>
    3. <artifactId>spring-webartifactId>
    4. <version>5.0.5.RELEASEversion>
    5. dependency>

    web.xml中

    1. <context-param>
    2. <param-name>ContextConfigLocationparam-name>
    3. <param-value>classpath:applicationContext.xmlparam-value>
    4. context-param>
    5. <listener>
    6. <listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>
    7. listener>

    userServlet类中,使用WebApplicationUtils获得上下文

    1. @WebServlet("/user")
    2. public class UserServlet extends HttpServlet {
    3. @Override
    4. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    5. // ApplicationContext app= new ClassPathXmlApplicationContext("applicationContext.xml");
    6. ServletContext servletContext = req.getServletContext();
    7. //ApplicationContext app = (ApplicationContext) servletContext.getAttribute("app");
    8. //变动处
    9. //ApplicationContext app = WebApplicationContextUtils.getApplicationContext(servletContext);
    10. WebApplicationContext app = WebApplicationContextUtils.getWebApplicationContext(servletContext);
    11. UserService userService=app.getBean(UserService.class);
    12. }
    13. }

    这样就成功使用了spring给我们提供的监听器。

    SpringMVC概述

    SpringMVC(M:Model模型,V:views视图,C:Controller控制器)是一种基于Java的实现MVC设计模型的请求驱动类型的轻量级Web框架,属于SpringFrameWork的后续产品,已经融合在Spring Web Flow中。

    SpringMVC已经成为目前最主流的MVC框架之一,并且随着Spring3.0的发布,全面超越Struct2,成为最优秀的MVC框架,他通过一套注解,让一个简单的Java类成为处理请求的控制器,而无须实现任何接口,同时他还支持RESTful编程分格的请求

    web层的框架完成的相应的操作图示

     SpringMVC的核心是前端控制器,SpringMVC使用Servlet充当前端控制器

    SpringMVC开发使用步骤

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

    1、先导入SpringMVC的相关坐标

    2、配置SpringMVC核心控制器DispathcerServlet

    3、创建Controller类和视图界面

    4、使用注解配置Controller类中业务方法的映射地址

    5、配置SpringMVC核心文件spring-mvc.xml

    6、客户端发起请求测试

    ②、导入坐标

    1. <dependency>
    2. <groupId>org.springframeworkgroupId>
    3. <artifactId>spring-webmvcartifactId>
    4. <version>5.0.5.RELEASEversion>
    5. dependency>

    ②、配置控制器

    1. <servlet>
    2. <servlet-name>DispatcherServletservlet-name>
    3. <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
    4. <load-on-startup>1load-on-startup>
    5. servlet>
    6. <servlet-mapping>
    7. <servlet-name>DispatcherServletservlet-name>
    8. <url-pattern>/url-pattern>
    9. servlet-mapping>

    ③、创建controller视图和视图界面④、使用注解映射地址

    创建一个controller包,包下创建一个userController类,类中

    1. package com.controller;
    2. import org.springframework.stereotype.Controller;
    3. import org.springframework.web.bind.annotation.RequestMapping;
    4. //配置类,使用注解把这个类放到容器中
    5. @Controller
    6. public class userController {
    7. //用注解给这个方法请求映射某个地址
    8. @RequestMapping("/quick")
    9. public String save(){
    10. System.out.println("controller save running");
    11. //就会跳转到KCandZH.jsp这个页面上去
    12. return "KCandZH.jsp";
    13. }
    14. }

    在webapp下创建一个KCandZH.jsp页面

    1. <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" %>
    2. <%
    3. String path = request.getContextPath();
    4. String basepath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
    5. %>
    6. <head>
    7. "<%=basepath %>"/>
    8. "utf-8"/>
    9. Insert title here
    10. kCandZH forever

    ⑤、配置核心spring-mvc.xml(web.xml中)

    1. <servlet>
    2. <servlet-name>DispatcherServletservlet-name>
    3. <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
    4. <init-param>
    5. <param-name>contextConfigLocationparam-name>
    6. <param-value>classpath:spring-mvc.xmlparam-value>
    7. init-param>
    8. <load-on-startup>1load-on-startup>
    9. servlet>
    10. <servlet-mapping>
    11. <servlet-name>DispatcherServletservlet-name>
    12. <url-pattern>/url-pattern>
    13. servlet-mapping>

    在resource下写一个spring-mvc.xml用于组件扫描

    1. "1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xmlns:context="http://www.springframework.org/schema/context"
    5. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    6. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd" >
    7. <context:component-scan base-package="com.controller"/>
    8. beans>

    SpringMVC流程图示

     SpringMVC的组件解析

    SpringMVC执行流程

    ①用户发送请求至前端控制器DispatcherServlet(负责组件调度)。

    ②DispatcherServlet收到请求调用HandlerMapping处理器映射器。

    ③处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet

    ④ DispatcherServlet调用HandlerAdapter处理器适配器。

    ⑤ HandlerAdapter经过适配调用具体的处理器(Controller(封装特有行为的后端代码),也叫后端控制器)。

    ⑥Controller执行完成返回ModelAndView。

    ⑦HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。

    ⑧DispatcherServlet将ModelAndView传给ViewReslover视图解析器。

    ⑨ViewReslover解析后返回具体View。

    ⑩DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。DispatcherServlet响应用户。

    执行流程图示

    SpringMVC注解解析

    @RequestMapping

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

    位置:①类上,请求URL的第一级访问目录,此处不写的话,就相当于应用的根目录

                ②方法上,请求URL的第二级访问目录,与类上的使用@RequestMapping标注的以及目录一起组成访问虚拟路径。

    1. //配置类,使用注解把这个类放到容器中
    2. @Controller
    3. @RequestMapping(value="KongChao")
    4. public class userController {
    5. //用注解给这个方法请求映射某个地址
    6. //所以访问这个地址则是http://localhost:8080/KongChao/ZengHui
    7. @RequestMapping("/ZengHui")
    8. public String save(){
    9. System.out.println("controller save running");
    10. //就会跳转到KCandZH.jsp这个页面上去
    11. //加个/表示从web工程下开始
    12. return "/KCandZH.jsp";
    13. }
    14. }

    属性:

    • value:用于指定请求的URL,他和path属性作用是一样的,只有一个url可以省略value,有多个用逗号隔开【如:
      1. @RequestMapping(value="user")
      2. @RequestMapping("user ")
    • method:用于指定请求的方式(不是这种请求无法访问)
    • params:用于指定限制请求参数的条件,他支持简单的表达式,要求请求参数的key和value必须和配置的一模一样,如:
      1. params={"accoubtName"},表示请求参数必须要accountName,直接在?后面写这个参数即可
      2. params={"eys!4"},表示请求参数中的money不能是4
       @RequestMapping(value = "/ZengHui",method = RequestMethod.GET,params = {"KCaZH"})

      则访问路径是ZengHui,请求方式是GET,带有参数KCaZH

       xxx内容可以任意,只要带有指定的参数即可。

    1.mvc命名空间引入

    1. 命名空间:xmlns:context="http://www.springframework.org/schema/context"
    2. xmlns:mvc="http://www.springframework.org/schema/mvc"
    3. 约束地址:http://www.springframework.org/schema/context
    4. http://www.springframework.org/schema/context/spring-context.xsd
    5. http://www.springframework.org/schema/mvc
    6. http://www.springframework.org/schema/mvc/spring-mvc.xsd

    2、组件扫描基于Spring容器,所以在进行SpringMVC操作时,需要将Controller存储到Spring容器中,如果使用@Controller注解标注的话,就需要使用

    "con.controller"/>

    进行组件扫描

    SpringMVC的xml配置解析

    1、视图解析器

    SpringMVC有默认组件配置,默认组件都是DispatcherServlet.propertier配置文件中配置的,该配置文件地址org/springframework/web/servlet/DospatcherServlet.properties,该文件中配置了默认视图解析器,如下:

    1. org.springframework.web.servlet.ViewResolver=org.springframework .web.servlet.view.I
    2. nternalResourceViewResolver
    1. 翻看该解析器源码,可以看到该解析器的默认设置,如下:
    2. REDIRECT URL PREFIX = "redirect:" --重定向前缀
    3. FORWARD URL PREFIX="forward:" --转发前缀(默认值)
    4. prefix=""; --视图名称前缀
    5. suffix =""; --视图名称后缀

     在webapp下新建一个jsp包,则每次访问视图,需要加上/jsp/xxx.jsp

    前面的是文件夹的名字,后面的是扩展名,每次都需要加上, 这十分的麻烦,所以我们可以在spring-mvc.xml(名字自定义的)配置文件中 ,配置前缀和后缀

    1. "1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xmlns:context="http://www.springframework.org/schema/context"
    5. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    6. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd" >
    7. <context:component-scan base-package="com.controller"/>
    8. <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    9. <property name="prefix" value="/jsp/">property>
    10. <property name="suffix" value=".jsp">property>
    11. bean>
    12. beans>

    配置完成之后,我们只需写jsp的名字即可,它会自动给我们拼接上前后缀

    SpringMVC的相关组件

    • 前端控制器:DispatcherServlet(负责调用其他功能组件,需要手动配置)
    • 处理器映射器:HandlerMapping
    • 处理器适配器:HandlerAdapter(被前端控制器调用,去执行处理器)
    • 处理器:Handler(可以理解为Controller,把一些特有行为进行封装的组件)
    • 视图解析器:ViewResolver.(负责把view解析处理)
    • 视图:View(视图的一些信息)

    SpringMVC的注解和配置

    • 请求映射注解:@RequestMapping(作用是进行虚拟地址映射,可以放在类上,也可以放在方法上)
    • 视图解析器配置:
    • REDIRECT URL PREFIX="redirect:" (重定向)
    • FORWARD URL PREFIX ="forward:"(转法)(默认值,可以不写)
    •  prefix = "";(前缀)
    •  suffix= "";(后缀)

    SpringMVC的数据响应

    SpringMVC的数据响应方式

    ①页面跳转

    • 直接返回字符串(如在一个方法中,return了一个"xxx.jsp",就会转发到那个jsp页面中,这就是直接返回字符串的形式)
    • 通过ModelAndView对象返回

    ②回写数据

    • 直接返回字符串(相当于在javaweb里的resp.getwrite(),print)
    • 返回对象或集合  

    页面跳转

    1、返回字符串形式

    直接返回字符串:此种方式会将返回的字符串与视图解析器的前后缀拼接后跳转。

     返回带有前缀的字符串:

    1. 转发:forward:/WEB_INF/views/index.jsp(forward可以省略不写)
    2. 重定向:redirect:/index.jsp

    2、返回ModelAndView对象

    方式1:直接new对象

    1. //配置类,使用注解把这个类放到容器中
    2. @Controller
    3. @RequestMapping(value="KongChao")
    4. public class userController {
    5. @RequestMapping(value = "/ZengHui2")
    6. public ModelAndView save2(){
    7. /*
    8. Model 模型 作用是封装数据
    9. View 视图 作用是展示数据
    10. */
    11. ModelAndView modelAndView=new ModelAndView();
    12. //设置模型数据(键值对,键为String,值为Oject)
    13. modelAndView.addObject("username", 1);
    14. //设置视图名字
    15. modelAndView.setViewName("KCandZH");//经过前后缀拼接就位/jsp/KCandZH.jsp
    16. return modelAndView;
    17. }
    18. }

    在jsp包下的KCandZH.jsp中

    1. <html>
    2. <head>
    3. <base href="<%=basepath %>"/>
    4. <meta charset="utf-8"/>
    5. <title>Insert title heretitle>
    6. head>
    7. <body>
    8. kCandZH forever ${username}
    9. body>
    10. html>

    加上一个El表达式,这样浏览器访问localhost:8080/KongChao/ZengHui2,就会显示出kCandZH forever  1

     方式2:写在方法里让SpringMVC创建

    也可以不new对象的方式,在方法中直接写model对象,SpringMVC会自动帮你创建

    1. //配置类,使用注解把这个类放到容器中
    2. @Controller
    3. @RequestMapping(value="KongChao")
    4. public class userController {
    5. @RequestMapping(value = "/ZengHui3")
    6. public ModelAndView save3( ModelAndView modelAndView){
    7. //设置模型数据(键值对,键为String,值为Oject)
    8. modelAndView.addObject("username", "babala");
    9. //设置视图名字
    10. modelAndView.setViewName("KCandZH");//经过前后缀拼接就位/jsp/KCandZH.jsp
    11. return modelAndView;
    12. }
    13. }

    方式3:model和view分开做

    model是SpringMVC框架封装好的

    1. //配置类,使用注解把这个类放到容器中
    2. @Controller
    3. @RequestMapping(value="/KongChao")
    4. public class userController {
    5. @RequestMapping(value = "/ZengHui4")
    6. public String save4(Model model){//是model
    7. //设置模型数据(键值对,键为String,值为Oject)
    8. model.addAttribute("username","曾慧");
    9. return "KCandZH";//是view
    10. }
    11. }

    方式4:通过HttpServletRequest

    1. //配置类,使用注解把这个类放到容器中
    2. @Controller
    3. @RequestMapping(value="/KongChao")
    4. public class userController {
    5. @RequestMapping(value = "/ZengHui5")
    6. public String save5(HttpServletRequest request){//是model
    7. //设置模型数据(键值对,键为String,值为Oject)
    8. request.setAttribute("username","kckckc");
    9. return "KCandZH";
    10. }
    11. }

    方式3和方式4的区别,model是SpringMVC封装好的,而HttpServletRequest是原生的javaweb,是由tomcat服务器产生的,这个产生的对象中有数据,有http请求的数据(请求行,请求体....),model对象则是空的。方式4不常用

    回写数据

    1、直接返回字符串

    Web基础截断,客户端访问服务器端,如果想直接回写字符串作为响应题返回的话,只需要使用response.getWrite().print("KCandZH")即可,所以在Controller中想直接回写字符串,可以直接在方法中写入response。

    方法1:通过SpringMVC框架注入的response对象,使用response.getWrite().print("hello")回写数据,此时不需要视图跳转,业务方法返回值为void

    1. //配置类,使用注解把这个类放到容器中
    2. @Controller
    3. @RequestMapping(value="/user")
    4. public class userController {
    5. @RequestMapping("/quick6")
    6. public void save6(HttpServletResponse response) throws IOException {
    7. response.getWriter().print("hello itcase");
    8. }
    9. }

     ②将需要回写的字符串直接返回,但需要通过@ResponseBody注解告知SpringMVC框架,方法返回的字符串不是跳转某个视图,而是直接在http响应体重返回。(加上则不会进行前后缀拼接)

    1. //配置类,使用注解把这个类放到容器中
    2. @Controller
    3. @RequestMapping(value="/user")
    4. @ResponseBody//告诉SpringMVC框架不进行视图跳转,而是直接进行数据响应
    5. public class userController {
    6. @RequestMapping("/quick7")
    7. public String save7(HttpServletResponse response) throws IOException {
    8. return "hello itcase";
    9. }
    10. }

                                                                                                                                             将字符串转成json格式回传到客户端

    user类下

    1. package com.pojo;
    2. public class User {
    3. private int age;
    4. private String username;
    5. public User() {
    6. }
    7. public void setAge(int age) {
    8. this.age = age;
    9. }
    10. public void setName(String username) {
    11. this.username = username;
    12. }
    13. }

    userController类下

    1. //配置类,使用注解把这个类放到容器中
    2. @Controller
    3. @RequestMapping(value="/user")
    4. public class userController {
    5. @RequestMapping("/quick9")
    6. @ResponseBody
    7. public String save9() throws JsonProcessingException {
    8. User user=new User();
    9. user.setAge(30);
    10. user.setName("lisi");
    11. //使用json的转换工具将对象转换成json格式字符串再返回
    12. ObjectMapper objectMapper=new ObjectMapper();
    13. String json = objectMapper.writeValueAsString(user);
    14. return json;
    15. }
    16. }

          要使用json转换工具,还得导入依赖

    1. <dependency>
    2. <groupId>com.fasterxml.jackson.coregroupId>
    3. <artifactId>jackson-coreartifactId>
    4. <version>2.9.0version>
    5. dependency>
    6. <dependency>
    7. <groupId>com.fasterxml.jackson.coregroupId>
    8. <artifactId>jackson-databindartifactId>
    9. <version>2.9.0version>
    10. dependency>
    11. <dependency>
    12. <groupId>com.fasterxml.jackson.coregroupId>
    13. <artifactId>jackson-annotationsartifactId>
    14. <version>2.9.0version>
    15. dependency>

      运行结果

    2、直接返回对象或集合      

    使用SpringMVC自动将对象或集合转化为json格式

    通过SpringMVC帮助我们对对象或集合进行json字符串的转换并回写,为处理器适配器配置消息转换参数是,指定使用jackson进行对象或集合的转换,因此需要在spring-mvc.xml中进行这样配置

    配置spring-mvc.xml中处理器映射器

    1. <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
    2. <property name="messageConverters">
    3. <list>
    4. <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
    5. list>
    6. property>
    7. bean>

       在userController类中                                                                                                             

    1. //配置类,使用注解把这个类放到容器中
    2. @Controller
    3. @RequestMapping(value="/user")
    4. public class userController {
    5. @RequestMapping("/quick10")
    6. @ResponseBody
    7. //配置完成处理器映射器后,SpringMVC会将USer转化为json格式
    8. public User save10() throws JsonProcessingException {
    9. User user=new User();
    10. user.setAge(32);
    11. user.setName("lisi2");
    12. return user;
    13. }
    14. }

    运行结果

     注解方式优化转化json

    在方法上添加@ResponseBody就可以返回json格式的字符串,但是这样配置比较麻烦,配置的代码比较多,因此,我们可以使用mvc的注解驱动代替上述配置。

    1. <mvc:annotation-driven/>

     、

    在SpringMVC的各个组件中,处理器映射器、处理器适配器、视图解析器称为SpringMVC的三大组件。使用自动加载RequestMappingHandlerMapping(处理映射器)和RequestMappingHandlerAdapter(处理适配器),可用在Spring-xml.xml配置文件中使用替代注解处理器和适配器的配置。
    同时使用默认底层就会集成jackson进行对象或集合的json格式字符串的转换

    因为使用了mvc命名空间,所以得导入mvc

    1. <beans xmlns="http://www.springframework.org/schema/beans"
    2. xmlns:mvc="http://www.springframework.org/schema/mvc"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    5. http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    在spring-mvc.xml配置文件中

    1. <mvc:annotation-driven/>

     这样就完成了注解配置

    SpringMVC获得请求数据

    获得请求参数

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

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

    • 基本数据类型
    • pojo类型 参数
    • 数据类型参数
    • 集合类型参数

    基本数据类型

    1. //配置类,使用注解把这个类放到容器中
    2. @Controller
    3. @RequestMapping(value="/user")
    4. public class userController {
    5. @RequestMapping("/quick11")
    6. @ResponseBody
    7. public void save11(String username,int age) {
    8. System.out.println(username);
    9. System.out.println(age);
    10. }
    11. }

     这个方法不进行页面跳转和回写数据@ResponseBody和void)

    然后在网页访问书写参数

     

     就可以看到控制台打印出张三 18,这就是基本数据类型

    获得POJO类型参数

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

    如:

     上图中的username和age属于User之中的,SpringMVC就会自动将这些值加进User去

    pojo包下的User类

    1. package com.pojo;
    2. public class User {
    3. private int age;
    4. private String username;
    5. public User() {
    6. }
    7. public User(int age, String username) {
    8. this.age = age;
    9. this.username = username;
    10. }
    11. public void setAge(int age) {
    12. this.age = age;
    13. }
    14. public int getAge() {
    15. return age;
    16. }
    17. public String getUsername() {
    18. return username;
    19. }
    20. public void setUsername(String username) {
    21. this.username = username;
    22. }
    23. @Override
    24. public String toString() {
    25. return "User{" +
    26. "age=" + age +
    27. ", username='" + username + '\'' +
    28. '}';
    29. }
    30. }
    1. //配置类,使用注解把这个类放到容器中
    2. @Controller
    3. @RequestMapping(value="/user")
    4. public class userController {
    5. @RequestMapping("/quick12")
    6. @ResponseBody
    7. public void save12(User user) {
    8. System.out.println(user);
    9. }
    10. }

     控制台可以看到

     获得数组类型参数

    Controller的业务方法数组名称与请求参数的name一致,参数值救赎自动映射配置。

    1. //配置类,使用注解把这个类放到容器中
    2. @Controller
    3. @RequestMapping(value="/user")
    4. public class userController {
    5. @RequestMapping("/quick13")
    6. @ResponseBody
    7. public void save13(String[] strs) {
    8. //数组直接打印是地址,为了更清楚看到,用Arrays,asList(作为集合打印)
    9. System.out.println(Arrays.asList(strs));
    10. }
    11. }

     网址搜素输入

     控制台显示

    获得集合类型参数

    获得集合参数时,要将集合参数包装到pojo对象才可以

    所以我们在pojo包下创建一个vo对象

    1. package com.pojo;
    2. import java.util.List;
    3. public class VO {
    4. private List userList;
    5. public VO(List userList) {
    6. this.userList = userList;
    7. }
    8. public List getUserList() {
    9. return userList;
    10. }
    11. public void setUserList(List userList) {
    12. this.userList = userList;
    13. }
    14. @Override
    15. public String toString() {
    16. return "VO{" +
    17. "userList=" + userList +
    18. '}';
    19. }
    20. }

     userController类下

    1. //配置类,使用注解把这个类放到容器中
    2. @Controller
    3. @RequestMapping(value="/user")
    4. public class userController {
    5. @RequestMapping("/quick14")
    6. @ResponseBody
    7. public void save14(VO vo){
    8. System.out.println(vo);
    9. }
    10. }

    form.jsp页面下

    1. <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" %>
    2. <%
    3. String path = request.getContextPath();
    4. String basepath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
    5. %>
    6. <head>
    7. "<%=basepath %>"/>
    8. "utf-8"/>
    9. Insert title here
    10. "${pageContext.request.contextPath}/user/quick14" method="post">
    11. <%--表明是第一个User对象username age--%>
    12. type="text" name="userList[0].name">
    13. type="text" name="userList[0].age">
    14. type="text" name="userList[1].name">
    15. type="text" name="userList[1].age">
    16. type="submit" value="提交">

    运行之后在页面输入数据,控制台输出 

    获得集合类型参数

    静态资源访问的开启

    当使用ajax提交时,可以指定contentType为json形式,那么在方法参数位置使用@RequestBody可以是直接接收结合数据而无需使用POJO进行包装。

    创建一个js下的

    还有ajax.jsp

    1. <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" %>
    2. <%
    3. String path = request.getContextPath();
    4. String basepath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
    5. %>
    6. <head>
    7. "<%=basepath %>"/>
    8. "utf-8"/>
    9. Insert title here

    userController类下

    1. //配置类,使用注解把这个类放到容器中
    2. @Controller
    3. @RequestMapping(value="/user")
    4. public class userController {
    5. @RequestMapping("/quick15")
    6. @ResponseBody
    7. public void save15(@ResponseBody List userList) throws Exception {
    8. System.out.println(userList);
    9. }
    10. }

    运行服务器后,发现控制台没有打印数据

     一般是页面出现了问题,打开开发者工具中查看

     发现是这个jQuery文件找不到

    这是静态资源访问权限的问题,解决方式是在spring-mvc中加入

    1. <mvc:resources mapping="/js/**" location="/js/"/>

    重启服务器运行之后就可以访问了,在网络中查看访问包的情况,共有三次请求

     运行之后控制台会打印数组中的数据。

    也可以在spring-mvc中配置,只需写入一个即可(常用)

    1. <mvc:default-servlet-handler/>
    2. beans>

    解释:访问资源时,SpringMVC找对应的匹配地址,如果找不到则交给原始的容器(这原始的容器为tomcat)tomcat可以找有能力访问静态资源

    配置全局乱码过滤器

    请求数据的乱码问题

    当postt请求时,数据会出现乱码,我们可以设置一个过滤器来进行编码的过滤。

    在web.xml中配置过滤器即可

    1. <filter>
    2. <filter-name>CharacterEncodingFilterfilter-name>
    3. <filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
    4. <init-param>
    5. <param-name>encodingparam-name>
    6. <param-value>UTF-8param-value>
    7. init-param>
    8. filter>
    9. <filter-mapping>
    10. <filter-name>CharacterEncodingFilterfilter-name>
    11. <url-pattern>/*url-pattern>
    12. filter-mapping>

    参数绑定注解@RequestParam

    当请求的参数名称与Controller的业务方法参数名称不一致是,就需要通过@RequestParam注解显式的绑定

    业务方法中的参数为username,请求的参数为name,两者不一致,所以需要进行绑定,使用@RequestParam(value="name")进

    注解@RequestParam的参数使用说明

    value:与请求参数名称

    required:指在指定的请求参数是否必须包括,默认是true,默认值下提交时如果没有此参数则报错

    defaultValue:放没有指定参数时,则使用的默认值赋值

    获得Restful风格的参数

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

    Restful风格的请求是使用“url+请求方式”表示一次请求的目的地,HTTP协议里面四个表示操作方式的动词如下

    • GET:用于获取资源
    • POST:用于新建资源
    • PUT:用于更新资源
    • DELETE:用于删除资源

    例如:

    • /user/1   GET:              得到id=1的user
    • /user.1   DELETE:        删除id=1的user
    • /user/1    PUT:             更新id=1的user
    • /user        POST:        新增user

    上述url地址/user/1中的1就是要获得的请求参数,在SpringMVC中可以使用占位符进行参数绑定。地址/user/1可以写成/user/{id},占位符{id}对应的就是1的值。在业务方法中我们可以使用@PathVariable注解进行占位符的匹配获取工作。

    1. //配置类,使用注解把这个类放到容器中
    2. @Controller
    3. @RequestMapping(value="/user")
    4. public class userController {
    5. //localhost:8080/quick17/zhangsan
    6. @RequestMapping(value = "/quick17/{username}",method=RequestMethod.GET)
    7. @ResponseBody
    8. public void save17(@PathVariable(value = "username") String username) {
    9. System.out.println(username);
    10. }
    11. }

     控制台就会打印出张三

    自定义类型转换器

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

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

    • ①定义转换器类实现Converter接口
    • ②在配置文件中声明转换器
    • ③在中引用转换器

    时间类型的,Spring提供了yyyy/MM/dd的日期输入格式,但是我们习惯使用,如2022-7-21而不会写2022/7/21,我们没按照规定写就会报错,所以我们配置自定义的转换器

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

    在converter包下。

    1. package com.converter;
    2. import org.springframework.core.convert.converter.Converter;
    3. import java.text.ParseException;
    4. import java.text.SimpleDateFormat;
    5. import java.util.Date;
    6. //ConverterString类型转date类型
    7. public class DateConverter implements Converter {
    8. public Date convert(String dateStr) {
    9. //将日期的字符串转换成日期对象 返回
    10. SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd");
    11. Date date = null;
    12. try {
    13. date = format.parse(dateStr);
    14. } catch (ParseException e) {
    15. e.printStackTrace();
    16. }
    17. return date;
    18. }
    19. }

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

    spring-mvc.xml中

    1. <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
    2. <property name="converters">
    3. <list>
    4. <bean class="com.converter.DateConverter"/>
    5. list>
    6. property>
    7. bean>

    ③在中引用转换器

    也在spring-mvc.xml中

    1. <mvc:annotation-driven conversion-service="conversionService"/>

     获得Servlet相关API

    SpringMVC支持使用原始ServletAPI对象作为控制器方法的参数进行注入,常用的对象如下:

    • HttpServletyRequest
    • HttpServletResponse
    • HttpSession

    会打印一些地址。

    获得请求头

    @RequestHeader

    使用@RequestHeader可以获得请求头信息,相当于web阶段学习的requestgetHeader(name)

    @RequestHeader注解的属性如下:

    • value:请求头的名称
    • required:是否必须携带此请求头,(写true必须携带请求头参数才可以访问)

    下列代码是,把请求头名为User-Agent的请求数据赋值给headerValue,然后

    访问之后, F12打开网络查看。

     @CookieValue

    使用@CookieValue可以获得指定的Cookie的值

    @CookieValue注解的属性如下:

    • value:指定cookie的名称
    • required:是否必须携带此cookie
    1. //配置类,使用注解把这个类放到容器中
    2. @Controller
    3. @RequestMapping(value="/user")
    4. public class userController {
    5. @RequestMapping("/quick21")
    6. @ResponseBody
    7. public void save21(@CookieValue(value = "JSEEEIONID")String jsessionId ) throws Exception {
    8. System.out.println(jsessionId);
    9. }
    10. }

    这样就可以获得cookie的值,cookie也是键值对的形式

    文件上传 

    文件上传客服端三要素

    • 表单项type="file"
    • 表单的提交方式是post
    • 表单的enctyoe属性是多部分表单形式,以及enctype="multipart/form-data"

    单文件上传步骤

    ①导入fileupload和io坐标

    1. <dependency>
    2. <groupId>commons-fileuploadgroupId>
    3. <artifactId>commons-fileuploadartifactId>
    4. <version>1.2.2version>
    5. dependency>
    6. <dependency>
    7. <groupId>commons-iogroupId>
    8. <artifactId>commons-ioartifactId>
    9. <version>2.4version>
    10. dependency>

    ②配置文件上传解析器

    在spring-mvc.xml中

    1. <bean id="MultipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    2. <property name="maxUploadSize" value="5242800"/>
    3. <property name="maxUploadSizePerFile" value="5242800"/>
    4. <property name="defaultEncoding" value="UTF-8"/>
    5. bean>

    ③编写文件上传代码

     upload.jsp中代码

    1. <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" %>
    2. <%
    3. String path = request.getContextPath();
    4. String basepath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
    5. %>
    6. <html>
    7. <head>
    8. <base href="<%=basepath %>"/>
    9. <meta charset="utf-8"/>
    10. <title>Insert title heretitle>
    11. head>
    12. <body>
    13. <form action="${pageContext.request.contextPath}/user/quick22" method="post" enctype="multipart/form-data">
    14. 名称<input type="text" name="username"><br/>
    15. 文件<input type="file" name="uploadFile"><br/>
    16. <input type="submit" value="提交">
    17. form>
    18. body>
    19. html>

    方法中参数要和jsp中的name值对应

    1. //配置类,使用注解把这个类放到容器中
    2. @Controller
    3. @RequestMapping(value="/user")
    4. public class userController {
    5. @RequestMapping("/quick22")
    6. @ResponseBody
    7. public void save22(String usernam, MultipartFile uploadFile) throws Exception{
    8. System.out.println(usernam);
    9. //获得上传文件的名称
    10. String originalFilename = uploadFile.getOriginalFilename();
    11. uploadFile.transferTo(new File("C:\\upload\\"+originalFilename));
    12. }
    13. }

     运行访问后

     多文件上传实现

    多文件上传只需要多加参数即可

    法一:写下多个参数

    1. <form action="${pageContext.request.contextPath}/user/quick22" method="post" enctype="multipart/form-data">
    2. 名称<input type="text" name="username"><br/>
    3. 文件1<input type="file" name="uploadFile"><br/>
    4. 文件2<input type="file" name="uploadFile2"><br/>
    5. <input type="submit" value="提交">
    6. form>
    1. //配置类,使用注解把这个类放到容器中
    2. @Controller
    3. @RequestMapping(value="/user")
    4. public class userController {
    5. @RequestMapping("/quick22")
    6. @ResponseBody
    7. public void save22(String usernam, MultipartFile uploadFile,MultipartFile uploadFile2) throws Exception{
    8. System.out.println(usernam);
    9. //获得上传文件的名称
    10. String originalFilename = uploadFile.getOriginalFilename();
    11. uploadFile.transferTo(new File("C:\\upload\\"+originalFilename));
    12. String originalFilename2 = uploadFile2.getOriginalFilename();
    13. uploadFile2.transferTo(new File("C:\\upload\\"+originalFilename2));
    14. }
    15. }

    运行访问后: 

     法二:数组接收

    jsp中name的值都一致

    1. <form action="${pageContext.request.contextPath}/user/quick23" method="post" enctype="multipart/form-data">
    2. 名称<input type="text" name="username"><br/>
    3. 文件1<input type="file" name="uploadFile"><br/>
    4. 文件2<input type="file" name="uploadFile"><br/>
    5. <input type="submit" value="提交">
    6. form>

    1. //配置类,使用注解把这个类放到容器中
    2. @Controller
    3. @RequestMapping(value="/user")
    4. public class userController {
    5. @RequestMapping("/quick23")
    6. @ResponseBody
    7. public void save23(String username, MultipartFile[] uploadFile) throws Exception{
    8. System.out.println(username);
    9. //获得上传文件的名称
    10. for (MultipartFile multipartFile : uploadFile) {
    11. String originalFilename = multipartFile.getOriginalFilename();
    12. multipartFile.transferTo(new File("C:\\upload\\"+originalFilename));
    13. }
    14. }
    15. }

    运行结果也是一致的

    JdbcTemplate概述

    他是spring框架中提供的一个对象,是对原始繁琐的jdbc API对象的简单封装。spring框架为我们提供了很多的操作模板类。例如:操作关系型数据的JdbcTemplate和HivernateTenplate,操作nosql数据库的RedisTemplate,操作消息队列的JmsTemplate等

    JdbcTemplate开发步骤

    • ①导入spring-jdbc和spring-tx坐标  
    • ②创建数据库表和实体
    • ③创建JdbcTemplate对象
    • ④执行数据库操作

    数据库中account表

     pom.xml中

    1. <dependency>
    2. <groupId>org.springframeworkgroupId>
    3. <artifactId>spring-jdbcartifactId>
    4. <version>5.0.5.RELEASEversion>
    5. dependency>
    6. <dependency>
    7. <groupId>org.springframeworkgroupId>
    8. <artifactId>spring-txartifactId>
    9. <version>5.0.5.RELEASEversion>
    10. dependency>

    测试java中实体类中

    1. package test;
    2. import com.mchange.v2.c3p0.ComboPooledDataSource;
    3. import org.junit.Test;
    4. import org.springframework.jdbc.core.JdbcTemplate;
    5. import java.beans.PropertyVetoException;
    6. public class JdbcTemplateTest {
    7. @Test
    8. //测试JdbcTemplate开发步骤
    9. public void test1() throws PropertyVetoException {
    10. //创建数据源对象
    11. ComboPooledDataSource dataSource=new ComboPooledDataSource();
    12. dataSource.setDriverClass("com.mysql.jdbc.Driver");
    13. //位置为本地,3306端口,test数据库
    14. dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
    15. //用户名
    16. dataSource.setUser("root");
    17. //用户密码
    18. dataSource.setPassword("123456");
    19. JdbcTemplate jdbcTemplate=new JdbcTemplate();
    20. //设置数据源对象,知道数据库在哪里
    21. jdbcTemplate.setDataSource(dataSource);
    22. //执行操作
    23. int row = jdbcTemplate.update("insert into account value(?,?)", "tom", 5000);
    24. System.out.println(row);
    25. }
    26. }

    domain包下的account类下

    1. package domain;
    2. public class Account {
    3. private String name;
    4. private double money;
    5. public String getName() {
    6. return name;
    7. }
    8. public void setName(String name) {
    9. this.name = name;
    10. }
    11. public double getMoney() {
    12. return money;
    13. }
    14. public void setMoney(double money) {
    15. this.money = money;
    16. }
    17. @Override
    18. public String toString() {
    19. return "Account{" +
    20. "name='" + name + '\'' +
    21. ", money=" + money +
    22. '}';
    23. }
    24. }

    运行结果: 

     数据库中的test数据库,account表

     Spring产生JdbcTemplate对象

    测试插入

    仔细看,这些都是参数注入(用了setXxx。。),我们可以将JdbcTemplate的创建权交给Spring,将数据源DataSource的创建权也交给Spring,在Spring容器内部将数据源DateSource注入到JdbcTemplate模版对象中,配置如下:

    在test测试包下创建一系列

     在applicationContext1.xml下

    1. "1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    5. <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    6. <property name="driverClass" value="com.mysql.jdbc.Driver"/>
    7. <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"/>
    8. <property name="user" value="root"/>
    9. <property name="password" value="123456"/>
    10. bean>
    11. <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    12. <property name="dataSource" ref="dataSource"/>
    13. bean>
    14. beans>

    pom.xml中

    1. "1.0" encoding="UTF-8"?>
    2. <project xmlns="http://maven.apache.org/POM/4.0.0"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    5. <modelVersion>4.0.0modelVersion>
    6. <groupId>org.examplegroupId>
    7. <artifactId>javaMaven02artifactId>
    8. <version>1.0-SNAPSHOTversion>
    9. <dependencies>
    10. <dependency>
    11. <groupId>mysqlgroupId>
    12. <artifactId>mysql-connector-javaartifactId>
    13. <version>5.1.32version>
    14. dependency>
    15. <dependency>
    16. <groupId>c3p0groupId>
    17. <artifactId>c3p0artifactId>
    18. <version>0.9.1.2version>
    19. dependency>
    20. <dependency>
    21. <groupId>com.alibabagroupId>
    22. <artifactId>druidartifactId>
    23. <version>1.1.10version>
    24. dependency>
    25. <dependency>
    26. <groupId>junitgroupId>
    27. <artifactId>junitartifactId>
    28. <version>4.11version>
    29. dependency>
    30. <dependency>
    31. <groupId>org.springframeworkgroupId>
    32. <artifactId>spring-testartifactId>
    33. <version>5.0.5.RELEASEversion>
    34. dependency>
    35. <dependency>
    36. <groupId>org.springframeworkgroupId>
    37. <artifactId>spring-contextartifactId>
    38. <version>5.0.5.RELEASEversion>
    39. <scope>compilescope>
    40. dependency>
    41. <dependency>
    42. <groupId>org.springframeworkgroupId>
    43. <artifactId>spring-webartifactId>
    44. <version>5.0.5.RELEASEversion>
    45. dependency>
    46. <dependency>
    47. <groupId>org.springframeworkgroupId>
    48. <artifactId>spring-webmvcartifactId>
    49. <version>5.0.5.RELEASEversion>
    50. dependency>
    51. <dependency>
    52. <groupId>com.fasterxml.jackson.coregroupId>
    53. <artifactId>jackson-coreartifactId>
    54. <version>2.9.0version>
    55. dependency>
    56. <dependency>
    57. <groupId>com.fasterxml.jackson.coregroupId>
    58. <artifactId>jackson-databindartifactId>
    59. <version>2.9.0version>
    60. dependency>
    61. <dependency>
    62. <groupId>com.fasterxml.jackson.coregroupId>
    63. <artifactId>jackson-annotationsartifactId>
    64. <version>2.9.0version>
    65. dependency>
    66. <dependency>
    67. <groupId>org.springframeworkgroupId>
    68. <artifactId>spring-jdbcartifactId>
    69. <version>5.0.5.RELEASEversion>
    70. dependency>
    71. <dependency>
    72. <groupId>org.springframeworkgroupId>
    73. <artifactId>spring-txartifactId>
    74. <version>5.0.5.RELEASEversion>
    75. dependency>
    76. dependencies>
    77. project>

    JdbcTemplateTest类下

    1. public class JdbcTemplateTest {
    2. @Test
    3. //测试Spring产生jdbcTemplate对象
    4. public void test2() throws PropertyVetoException {
    5. ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext1.xml");
    6. JdbcTemplate jdbcTemplate=app.getBean(JdbcTemplate.class);
    7. int row = jdbcTemplate.update("insert into account value(?,?)", "KC", 50000);
    8. System.out.println(row);
    9. }
    10. }

    运行结果:

     数据库中的变化

     运行时,出现java.lang.NoClassDefFoundError: org/springframework/core/metrics/ApplicationStartup 

    原因是:版本号不一致,改为一致即可正常运行

    jdbc内容和配置解耦合

    抽取配置文件中的jdbc代码,使用单独的一个配置文件将次分开

     jdbc.properties下

    1. jdbc.driver=com.mysql.jdbc.Driver
    2. jdbc.url=jdbc:mysql://localhost:3306/test
    3. jdbc.username=root
    4. jdbc.password=123456

    applicationContext1.xml下

    1. "1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xmlns:context="http://www.springframework.org/schema/context"
    5. xsi:schemaLocation="
    6. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    7. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
    8. ">
    9. <context:property-placeholder location="classpath:jdbc.properties"/>
    10. <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    11. <property name="driverClass" value="${jdbc.driver}"/>
    12. <property name="jdbcUrl" value="${jdbc.url}"/>
    13. <property name="user" value="${jdbc.username}"/>
    14. <property name="password" value="${jdbc.password}"/>
    15. bean>
    16. <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    17. <property name="dataSource" ref="dataSource"/>
    18. bean>
    19. beans>

     修改一下数据

    1. public class JdbcTemplateTest {
    2. @Test
    3. //测试Spring产生jdbcTemplate对象
    4. public void test2() throws PropertyVetoException {
    5. ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext1.xml");
    6. JdbcTemplate jdbcTemplate=app.getBean(JdbcTemplate.class);
    7. int row = jdbcTemplate.update("insert into account value(?,?)", "ZH",66666);
    8. System.out.println(row);
    9. }
    10. }

    返回测试,运行结果

     数据库中变化:

    使用Spring集成Junit完成JdbcTemplate修改和删除

    在pom.xml需要导入两个包,spring-test包和Juit包

    pom.xml

    1. <dependency>
    2. <groupId>junitgroupId>
    3. <artifactId>junitartifactId>
    4. <version>4.12version>
    5. dependency>
    6. <dependency>
    7. <groupId>org.springframeworkgroupId>
    8. <artifactId>spring-testartifactId>
    9. <version>5.0.5.RELEASEversion>
    10. dependency>

    新建一个类

    1. package test;
    2. import org.junit.Test;
    3. import org.junit.runner.RunWith;
    4. import org.springframework.beans.factory.annotation.Autowired;
    5. import org.springframework.jdbc.core.JdbcTemplate;
    6. import org.springframework.test.context.ContextConfiguration;
    7. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    8. //指定使用spring做为驱动内核进行测试
    9. @RunWith(SpringJUnit4ClassRunner.class)
    10. //配置文件的位置
    11. @ContextConfiguration("classpath:applicationContext1.xml")
    12. public class JdbcTemplateCRUDTest {
    13. //被测试的用 @Autowired注入(测试谁就注入谁)
    14. @Autowired
    15. private JdbcTemplate jdbcTemplate;
    16. @Test
    17. public void testUpdate(){
    18. int row = jdbcTemplate.update("update account set money=? where name=?", 222, "tom");
    19. System.out.println(row);
    20. }
    21. }

     Junit4.11版本导致错误

    一开始我使用了junit4.11的版本

    1. C:\java64\jdk1.8.0_131\bin\java.exe -ea -Didea.test.cyclic.buffer.size=1048576 "-javaagent:D:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=4613:D:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath "D:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar;D:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\plugins\junit\lib\junit5-rt.jar;D:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\plugins\junit\lib\junit-rt.jar;C:\java64\jdk1.8.0_131\jre\lib\charsets.jar;C:\java64\jdk1.8.0_131\jre\lib\deploy.jar;C:\java64\jdk1.8.0_131\jre\lib\ext\access-bridge-64.jar;C:\java64\jdk1.8.0_131\jre\lib\ext\cldrdata.jar;C:\java64\jdk1.8.0_131\jre\lib\ext\dnsns.jar;C:\java64\jdk1.8.0_131\jre\lib\ext\jaccess.jar;C:\java64\jdk1.8.0_131\jre\lib\ext\jfxrt.jar;C:\java64\jdk1.8.0_131\jre\lib\ext\localedata.jar;C:\java64\jdk1.8.0_131\jre\lib\ext\nashorn.jar;C:\java64\jdk1.8.0_131\jre\lib\ext\sunec.jar;C:\java64\jdk1.8.0_131\jre\lib\ext\sunjce_provider.jar;C:\java64\jdk1.8.0_131\jre\lib\ext\sunmscapi.jar;C:\java64\jdk1.8.0_131\jre\lib\ext\sunpkcs11.jar;C:\java64\jdk1.8.0_131\jre\lib\ext\zipfs.jar;C:\java64\jdk1.8.0_131\jre\lib\javaws.jar;C:\java64\jdk1.8.0_131\jre\lib\jce.jar;C:\java64\jdk1.8.0_131\jre\lib\jfr.jar;C:\java64\jdk1.8.0_131\jre\lib\jfxswt.jar;C:\java64\jdk1.8.0_131\jre\lib\jsse.jar;C:\java64\jdk1.8.0_131\jre\lib\management-agent.jar;C:\java64\jdk1.8.0_131\jre\lib\plugin.jar;C:\java64\jdk1.8.0_131\jre\lib\resources.jar;C:\java64\jdk1.8.0_131\jre\lib\rt.jar;D:\小项目\webTest\target\test-classes;D:\小项目\webTest\target\classes;E:\Maven_project\lib\javax.transaction.jar;E:\Maven_project\lib\javax.annotation.jar;E:\Maven_project\lib\javax.jms.jar;E:\Maven_project\lib\javax.resource.jar;E:\Maven_project\lib\javax.ejb.jar;E:\Maven_project\lib\javax.persistence.jar;E:\Maven_project\lib\javax.servlet.jar;E:\Maven_project\lib\javax.servlet.jsp.jstl.jar;E:\Maven_project\lib\javax.servlet.jsp.jar;C:\Users\执久\.m2\repository\mysql\mysql-connector-java\5.1.32\mysql-connector-java-5.1.32.jar;C:\Users\执久\.m2\repository\c3p0\c3p0\0.9.1.2\c3p0-0.9.1.2.jar;C:\Users\执久\.m2\repository\com\alibaba\druid\1.1.10\druid-1.1.10.jar;C:\Users\执久\.m2\repository\junit\junit\4.11\junit-4.11.jar;C:\Users\执久\.m2\repository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar;C:\Users\执久\.m2\repository\org\springframework\spring-test\5.0.5.RELEASE\spring-test-5.0.5.RELEASE.jar;C:\Users\执久\.m2\repository\org\springframework\spring-core\5.0.5.RELEASE\spring-core-5.0.5.RELEASE.jar;C:\Users\执久\.m2\repository\org\springframework\spring-jcl\5.0.5.RELEASE\spring-jcl-5.0.5.RELEASE.jar;C:\Users\执久\.m2\repository\org\springframework\spring-context\5.0.5.RELEASE\spring-context-5.0.5.RELEASE.jar;C:\Users\执久\.m2\repository\org\springframework\spring-aop\5.0.5.RELEASE\spring-aop-5.0.5.RELEASE.jar;C:\Users\执久\.m2\repository\org\springframework\spring-beans\5.0.5.RELEASE\spring-beans-5.0.5.RELEASE.jar;C:\Users\执久\.m2\repository\org\springframework\spring-expression\5.0.5.RELEASE\spring-expression-5.0.5.RELEASE.jar;C:\Users\执久\.m2\repository\org\springframework\spring-web\5.0.5.RELEASE\spring-web-5.0.5.RELEASE.jar;C:\Users\执久\.m2\repository\org\springframework\spring-webmvc\5.0.5.RELEASE\spring-webmvc-5.0.5.RELEASE.jar;C:\Users\执久\.m2\repository\com\fasterxml\jackson\core\jackson-core\2.9.0\jackson-core-2.9.0.jar;C:\Users\执久\.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.9.0\jackson-databind-2.9.0.jar;C:\Users\执久\.m2\repository\com\fasterxml\jackson\core\jackson-annotations\2.9.0\jackson-annotations-2.9.0.jar;C:\Users\执久\.m2\repository\org\springframework\spring-jdbc\5.0.5.RELEASE\spring-jdbc-5.0.5.RELEASE.jar;C:\Users\执久\.m2\repository\org\springframework\spring-tx\5.0.5.RELEASE\spring-tx-5.0.5.RELEASE.jar" com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit4 test.JdbcTemplateCRUDTest,testUpdate
    2. java.lang.ExceptionInInitializerError
    3. at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    4. at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    5. at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    6. at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    7. at org.junit.internal.builders.AnnotatedBuilder.buildRunner(AnnotatedBuilder.java:29)
    8. at org.junit.internal.builders.AnnotatedBuilder.runnerForClass(AnnotatedBuilder.java:21)
    9. at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
    10. at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:26)
    11. at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
    12. at org.junit.internal.requests.ClassRequest.getRunner(ClassRequest.java:26)
    13. at org.junit.internal.requests.FilterRequest.getRunner(FilterRequest.java:31)
    14. at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:49)
    15. at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
    16. at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
    17. at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
    18. Caused by: java.lang.IllegalStateException: SpringJUnit4ClassRunner requires JUnit 4.12 or higher.
    19. at org.springframework.util.Assert.state(Assert.java:73)
    20. at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.(SpringJUnit4ClassRunner.java:104)
    21. ... 15 more
    22. 进程已结束,退出代码 -1

     将其改为Junit4.12就可以正确执行了

    运行结果

     数据库中

    删除的操作

    1. @Test
    2. public void testDelete(){
    3. int row1 = jdbcTemplate.update("delete from account where name=?", "tom");
    4. System.out.println(row1);
    5. }

    运行结果 

     数据库中

    查询操作

    查询所有

    查询操作需要放入字节码对象.class

    1. @Test
    2. public void testQueryAll(){
    3. //后面括号中需要放入字节码对象
    4. List accountList = jdbcTemplate.query("select * from account", new BeanPropertyRowMapper(Account.class));
    5. System.out.println(accountList);
    6. }

    数据库中

     运行结果

     查询单个

    1. @Test
    2. public void testQueryOne(){
    3. Account account = jdbcTemplate.queryForObject("select *from account where name=?", new BeanPropertyRowMapper(Account.class), "ZH");
    4. System.out.println(account);
    5. }

     运行结果

    聚合查询

    1. @Test
    2. public void testQueryCount(){
    3. //查询数据条数
    4. Long count = jdbcTemplate.queryForObject("select count(*) from account", Long.class);
    5. System.out.println(count);
    6. }

     是一个实体就new一个对象,但是一个简单的数据,则创建一个普通的数据

     知识要点总结

    1. 1导入spring-jdbc和spring-tx坐标
    2. 2创建数据库表和实体
    3. 3创建JdbcTemplate对象
    4. JdbcTemplate jdbcTemplate=new JdbcTemplate();
    5. jdbcTemplate.setDatasource(datasource);
    6. 4执行数据库操作
    7. 更新操作:
    8. jdbcTemplate.update(sql,params)
    9. 查询操作:
    10. jdbcTemplate.query(sql,Mapper,params)
    11. jdbcTemplate.queryForobject(sql,Mapper,params)

     Spring的AOP简介

    什么是AOP

    AOP为Aspect Oriented Programming的缩写,意思为面向切面编程,是通过预编译方式和运行期动态代理实现程序功能的同一维护的一种技术。

    AOP是OOP(面向对象编程)的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的课重用性,同时提高了开发的效率。

    AOP的作用及其优势

    作用:在程序运行期间,在不修改源码的情况下对方法进行功能增强

    优势:减少重复代码,提高开发效率,并且便于维护

    举例示意图:

     AOP的底层实现

    实际上,AOP的底层是通过Spring提供的动态代理技术实现的,在运行期间,Spring通过动态地阿里技术动态的生成代理对象,代理对象方法执行时进行增强功能的介入,在去调用目标对象的方法,从而完成功能增强。 

     AOP的动态代理技术

    常用的动态代理技术

    JDK代理:基于接口的动态代理技术(有接口时用)

    cglib代理:基于父类的动态代理技术(没接口时用)

    JDK动态代理

    总览图

    proxy下的jdk包,TargetInterface

    1. package proxy.jdk;
    2. public interface TargetInterface {
    3. public void save();
    4. }

    Target类下

    1. package proxy.jdk;
    2. public class Target implements TargetInterface {
    3. @Override
    4. public void save() {
    5. System.out.println("save running。。。");
    6. }
    7. }

    Advice增强类下

    1. package proxy.jdk;
    2. //增强方法
    3. public class Advice {
    4. public void before(){
    5. System.out.println("前置增强。。");
    6. }
    7. public void afterReturning(){
    8. System.out.println("后置增强。。");
    9. }
    10. }

     ProxyTest类下

    1. package proxy.jdk;
    2. import java.lang.reflect.InvocationHandler;
    3. import java.lang.reflect.Method;
    4. import java.lang.reflect.Proxy;
    5. public class ProxyTest {
    6. public static void main(String[] args) {
    7. //创建目标对象
    8. final Target target=new Target();
    9. //获得增强对象
    10. final Advice advice=new Advice();
    11. //返回值 就是动态生成的代理对象
    12. TargetInterface proxy = (TargetInterface)Proxy.newProxyInstance(
    13. target.getClass().getClassLoader(),//目标对象类加载器
    14. target.getClass().getInterfaces(), //目标对象相同的接口字节码对象数组
    15. new InvocationHandler() {
    16. @Override
    17. //调用代理对象的任何方法,实质执行的都是invoke方法
    18. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    19. //执行目标方法有前置增强
    20. advice.before();
    21. Object invoke = method.invoke(target, args);//执行目标方法
    22. //之后有后置增强
    23. advice.afterReturning();
    24. return invoke;
    25. }
    26. }
    27. );
    28. //调用代理对象的方法
    29. proxy.save();
    30. }
    31. }

    运行结果

     cglib的动态代理

    cglib就是引入第三方jar包

    导入jar包

    1. <dependency>
    2. <groupId>org.springframeworkgroupId>
    3. <artifactId>spring-contextartifactId>
    4. <version>5.0.5.RELEASEversion>
    5. <scope>compilescope>
    6. dependency>

     spring后来版本已经将第三方的cglib给我们集成到spring核心中

     advice和Target和jdk一致,cglib不用接口,在ProxyTest下

    1. package proxy.cglib;
    2. import org.springframework.cglib.proxy.Enhancer;
    3. import org.springframework.cglib.proxy.MethodInterceptor;
    4. import org.springframework.cglib.proxy.MethodProxy;
    5. import proxy.jdk.TargetInterface;
    6. import java.lang.reflect.InvocationHandler;
    7. import java.lang.reflect.Method;
    8. import java.lang.reflect.Proxy;
    9. public class ProxyTest {
    10. public static void main(String[] args) {
    11. //创建目标对象
    12. final Target target = new Target();
    13. //获得增强对象
    14. final Advice advice = new Advice();
    15. //返回值 就是动态生成的代理对象 基于cglib
    16. //1、创建增强器
    17. Enhancer enhancer=new Enhancer();
    18. //2、设置父类(目标)
    19. enhancer.setSuperclass(Target.class);
    20. //3、设置回调
    21. enhancer.setCallback(new MethodInterceptor() {
    22. @Override
    23. public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
    24. advice.before(); //执行前置
    25. Object invoke = method.invoke(target, args);//执行目标
    26. advice.afterReturning();//执行后置
    27. return invoke;
    28. }
    29. });
    30. //创建代理对象
    31. Target proxy = (Target)enhancer.create();
    32. proxy.save();
    33. }
    34. }

    运行结果

    AOP相关概念

    Spring的AOP实现底层就是对上面的动态代理的代码进行了封装,封装后我们只需要对需要关注的部分进行代码编写,并通过配置的方式完成指定目标的方法增强。

    常用的术语如下:

    • Target(目标对象):代理的目标对象
    • Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类
    • Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点
    • Pointcut(切入点):所谓切入点是指我们要对哪些Joinpoint进行拦截的定义
    • Advice(通知/增强):所谓通知是指拦截到Joinpoint之后所要做的事情就是通知 Aspect(切面):是切入点和通知(引介)的结合
    • Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。spring采用动态代理织入,而 Aspect采用编译期织入和类装载期织入

      AOP开发明确的事项

    1、需要编写的内容

    • 编写核心业务代码(目标类的目标方法)
    • 编写切面类。切面类中有通知(增强功能方法)
    • 在配置文件中,配置织入关系,即将哪些通知与哪些连接点进行结合

    2、AOP技术实现的内容

    Spring框架监控切入点方法的执行,一旦监控到切入点方法被运行,使用代理机制,动态创建目标对象的代理对象,根据通知类别,在代理对象的对应位置,将通知对应的功能织入,完成完整的代码逻辑运行。

    3、AOP底层使用哪种代理方式

    在spring中,框架会根据目标类是否实现了接口来决定采用哪种动态代理的方式。

    知识要点总结

    ①aop:面向切面编程

    ②aop底层实现:基于JDK的动态代理和基于Cglib的动态代理 

    ③aop的重点概念:

    •     Pointcut(切入点):被增强的方法
    •     Advice(通知/增强):封装增强业务逻辑的方法
    •     Aspect(切面):切点+通知
    •     Weaving(织入):将切点与通知结合的过程

    ④开发明确事项:
     
    谁是切点(切点表达式配置)
    谁是通知(切面类中的增强方法)
    将切点和通知进行织入配置

    基于xml的AOP开发

    ①导入AOP相关坐标

    ②创建目标接口和目标类(内部有切点)

    ③创建切面类(内部有增强方法)

    ④将目标类和切面类的对象创建权交给spring

    ⑤在applicationContext.xml中配置织入关系

    ⑥测试代码

     1、导入坐标

    1. <dependency>
    2. <groupId>org.aspectjgroupId>
    3. <artifactId>aspectjweaverartifactId>
    4. <version>1.8.4version>
    5. dependency>

    spring-context本身有aop的实现,但是aspectj更好,aspectj本身就是一个小框架。

    MyAspect切面类(有增强方法)

    1. package aop;
    2. public class MyAspect {
    3. public void before(){
    4. System.out.println("前置增强....");
    5. }
    6. }

     applicationContext.xml下

    1. "1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xmlns:aop="http://www.springframework.org/schema/aop"
    5. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    6. http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
    7. ">
    8. <bean id="target" class="aop.Target">bean>
    9. <bean id="myAspect" class="aop.MyAspect">bean>
    10. <aop:config>
    11. <aop:aspect ref="myAspect">
    12. <aop:before method="before" pointcut="execution(public void aop.Target.save())"/>
    13. aop:aspect>
    14. aop:config>
    15. beans>

    AopTest测试类下

    1. package aop;
    2. import org.junit.Test;
    3. import org.junit.runner.RunWith;
    4. import org.springframework.beans.factory.annotation.Autowired;
    5. import org.springframework.test.context.ContextConfiguration;
    6. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    7. @RunWith(SpringJUnit4ClassRunner.class)
    8. @ContextConfiguration("classpath:applicationContext.xml")
    9. public class AopTest {
    10. @Autowired
    11. private TargetInterface target;
    12. @Test
    13. public void test1(){
    14. target.save();
    15. }
    16. }

    运行之后报错了

     仔细一看需要Junit4.12以上的版本,改完之后,

     XML配置AOP详解

    切点表达式的写法

    表达式语法:

    execution(修饰符] 返回值类型  包名.类名.方法名(参数))
    •  访问修饰符可以省略
    • 返回值类型、包名、类名、方法名可以使用星号*代表任意
    • 包名与类名之间一个点.代表当前包下的类,两个点..表示当前包及其子包下的类
    • 参数列表可以使用两个点..表示任意个数,任意类型的参数列表

    例如

    通知/(增强)的类型

    通知的配置语法:

    "切面类中的方法名" pointcut="切点表达式"/>

     前后置增强

    1. <aop:config>
    2. <aop:aspect ref="myAspect">
    3. <aop:before method="before" pointcut="execution(public void aop.Target.save())"/>
    4. <aop:after-returning method="afterReturn" pointcut="execution(public void aop.Target.save())"/>
    5. aop:aspect>
    6. aop:config>

    写下前后置增强

    1. public class MyAspect {
    2. public void before(){
    3. System.out.println("前置增强....");
    4. }
    5. public void afterReturn(){
    6. System.out.println("后置增强....");
    7. }
    8. }

    运行之后

     环绕增强

    切面类中的方法 

    1. import org.aspectj.lang.ProceedingJoinPoint;
    2. public class MyAspect
    3. //ProceedingJoinPoint:正在执行的连接点===切点
    4. public Object around(ProceedingJoinPoint point) throws Throwable {
    5. System.out.println("环绕前增强...");
    6. Object proceed=point.proceed();//切点方法
    7. System.out.println("环绕后增强...");
    8. return proceed;
    9. }
    10. }

    applicationContext.xml下

    1. <aop:config>
    2. <aop:aspect ref="myAspect">
    3. <aop:around method="around" pointcut="execution(public void aop.Target.save())"/>
    4. aop:aspect>
    5. aop:config>
    6. beans>

     运行结果

      异常抛出增强

    切面类下

    1. public void afterThrows(){
    2. System.out.println("异常抛出增强");
    3. }

     目标类中需要手动加一个异常

    1. public class Target implements TargetInterface {
    2. @Override
    3. public void save() {
    4. System.out.println("save running。。。");
    5. int i=1/0;
    6. }
    7. }

     applicationContext.xml中

    1. <aop:config>
    2. <aop:aspect ref="myAspect">
    3. <aop:after-throwing method="afterThrows" pointcut="execution(public void aop.Target.save())"/>
    4. aop:aspect>
    5. aop:config>

     最终增强

    最终增强即为无论抛不抛出异常,这个方法都会被执行 

    1. public void after(){
    2. System.out.println("最终增强...");
    3. }

    1. <aop:config>
    2. <aop:aspect ref="myAspect">
    3. <aop:after-throwing method="afterThrows" pointcut="execution(public void aop.Target.save())"/>
    4. <aop:after method="after" pointcut="execution(public void aop.Target.save())"/>
    5. aop:aspect>
    6. aop:config>

     运行结果

     切点表达式的抽取

    当多个增强的切点表达式相同时,可以将切点表达式进行抽取,在增强中使用pointcut-ref属性代替pointcut属性来引用抽取后的切点表达式。

      <aop:pointcut id="myPointcut" expression="execution(public void aop.Target.save())"/>

    applicationContext.xml中

    1. <aop:config>
    2. <aop:pointcut id="myPointcut" expression="execution(public void aop.Target.save())"/>
    3. <aop:aspect ref="myAspect">
    4. <aop:around method="around" pointcut-ref="myPointcut"/>
    5. <aop:after-returning method="after" pointcut-ref="myPointcut"/>
    6. aop:aspect>
    7. aop:config>

    运行结果

     知识要点

    aop织入

     通知的类型:前置通知、后置通知、环绕通知、异常抛出通知、最终通知

    点表达式的写法

     基于注解的AOP开发

    快速入门,基于注解的aop开发步骤

    ①创建目标接口和目标类(内部有切点)

    ②创建切面类(内部有增强方法)

    ③将目标类和切面类的对象创建权交给spring

    ④在切面类中使用注解配置织入关系

    ⑤在配置文件中开启组件扫描和AOP的自动代理

    ⑥测试

    编写测试 

    其中Target类下

    1. package anno;
    2. import org.springframework.stereotype.Component;
    3. //交给spring容器,起个名为target
    4. @Component("target")
    5. public class Target implements TargetInterface {
    6. public void save() {
    7. System.out.println("save running。。。");
    8. }
    9. }

     Interface类下

    1. package anno;
    2. public interface TargetInterface {
    3. public void save();
    4. }

     MyAspect切面类下

    1. package anno;
    2. import org.aspectj.lang.annotation.Aspect;
    3. import org.aspectj.lang.annotation.Before;
    4. import org.springframework.stereotype.Component;
    5. //交给spring容器
    6. @Component("myAspect")
    7. @Aspect //标注当前MyAspect是一个切面类
    8. public class MyAspect {
    9. @Before("execution(* anno.*.*(..))")
    10. public void before(){
    11. System.out.println("前置增强....");
    12. }
    13. }

     AnnoTest测试类下

    1. package anno;
    2. import org.junit.Test;
    3. import org.junit.runner.RunWith;
    4. import org.springframework.beans.factory.annotation.Autowired;
    5. import org.springframework.test.context.ContextConfiguration;
    6. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    7. @RunWith(SpringJUnit4ClassRunner.class)
    8. @ContextConfiguration("classpath:applicationContext_anno.xml")
    9. public class AnnoTest {
    10. @Autowired
    11. private TargetInterface target;
    12. @Test
    13. public void test1(){
    14. target.save();
    15. }
    16. }

    applicationContext_anno.xml配置文件

    1. "1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xmlns:aop="http://www.springframework.org/schema/aop"
    5. xmlns:context="http://www.springframework.org/schema/context"
    6. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    7. http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
    8. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
    9. ">
    10. <context:component-scan base-package="anno"/>
    11. <aop:aspectj-autoproxy/>
    12. beans>

    运行结果 

     注解配置AOP详解

    注解通知的类型

    通知的配置语法:@通知注解("切点表达式")

     切点表达式的抽取

    同xml配置aop一样。我们可以将切点表达式抽取,抽取方式是在切面内定义方法,早该方法上使用@Pointcut注解定义切点表达式,然后在在增强注解中进行引用。

     切面类中

    1. package anno;
    2. import org.aspectj.lang.annotation.AfterReturning;
    3. import org.aspectj.lang.annotation.Aspect;
    4. import org.aspectj.lang.annotation.Before;
    5. import org.aspectj.lang.annotation.Pointcut;
    6. import org.springframework.stereotype.Component;
    7. //交给spring容器
    8. @Component("myAspect")
    9. @Aspect //标注当前MyAspect是一个切面类
    10. public class MyAspect {
    11. @Before("execution(* anno.*.*(..))")
    12. public void before(){
    13. System.out.println("前置增强....");
    14. }
    15. //引入切点表达式方法
    16. @AfterReturning("pointcut()")//或者写MyAspect.pointcut()
    17. public void afterReturn(){
    18. System.out.println("后置增强....");
    19. }
    20. //定义切点表达式方法
    21. @Pointcut("execution(* anno.*.*(..))")
    22. public void pointcut(){ }
    23. }

    运行结果 

    编程式事务控制相关对象

    编程式:即使用java的api书写代码

    声明式:使用配置去配置

    PlatformTransactionManager平台事务管理

    PlatformTransactionManager接口时spring的事务管理器,它里面提供来我们常用的操作事务的方法

     PlatformTransactionManager是接口类型,不同的Dao层技术则有不同的实现类,例如:Dao层技术是jdbc或mybatis时:orqspringframeworkidbcdatasourceDataSourceTransactionManager
    Dao层技术是hibernate时:orq.springframework.orm.hibernate5.HibernateTransactionManager

    TransactionDefinition事务定义

    TransactionDefinition是事务的定义信息对象,里面有如下方法:

     设置隔离级别,可以解决事务并发产生的问题,如

    1. ISOLATION_DEFAULT//默认的
    2. ISOLATION_READ_UNCOMMITTED//读未提交,哪种都不能解决
    3. ISOLATION_READ_COMMITTED//读已提交,解决脏读
    4. ISOLATION_REPEATABLE READ//可重复读,解不可重复读
    5. ISOLATION_SERIALIZABLE//串行化,解决所有,性能最低

    事务的传播行为

    1. REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。一般的选择(默认值)
    2. SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行(没有事务)
    3. MANDATORY:使用当前的事务,如果当前没有事务,就抛出异常
    4. RFOUFRS NEW:新增事务,如果当前在事务中,把当前事务挂起
    5. NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
    6. NEVER:以非事务方式运行,如果当前存在事务,抛出异常
    7. NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行REOUIRED类似的操作
    8. 超时时间:默认值是-1.没有超时限制,如果有,以秒为单位进行设置
    9. 是否只读:建议查询时设置为只读,

    TransactionStatus事务状态

    TransactionStatus接口时提供事务具体运行状态(是被动产生的,不需要自己去设置),方法介绍如下

     基于XML的声明式事务控制

    spring的声明式事务就是指在配置文件中声明,用在spring配置文件中的声明式的处理事务来代替diam式的处理事务

      转账业务演示事务

     controller包下AccountController类

    1. package com.controller;
    2. import com.service.AccountService;
    3. import org.springframework.context.ApplicationContext;
    4. import org.springframework.context.support.ClassPathXmlApplicationContext;
    5. public class AccountController {
    6. public static void main(String[] args) {
    7. ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext1.xml");
    8. AccountService accountService = app.getBean(AccountService.class);
    9. accountService.transfer("KC","ZH",500);
    10. }
    11. }

    service包下AccountService接口

    1. package com.service;
    2. public interface AccountService {
    3. public void transfer(String outMan, String inMan, double money);
    4. }

    接口实现类

    1. package com.service.impl;
    2. import com.dao.AccountDao;
    3. import com.service.AccountService;
    4. public class AccountServiceImpl implements AccountService {
    5. private AccountDao accountDao;
    6. public void setAccountDao(AccountDao accountDao) {
    7. this.accountDao = accountDao;
    8. }
    9. public void transfer(String outMan, String inMan, double money) {
    10. accountDao.out(outMan,money);
    11. accountDao.in(inMan,money);
    12. }
    13. }

    pojo包下Account类

    1. package com.pojo;
    2. public class Account {
    3. private String name;
    4. private double money;
    5. public String getName() {
    6. return name;
    7. }
    8. public void setName(String name) {
    9. this.name = name;
    10. }
    11. public double getMoney() {
    12. return money;
    13. }
    14. public void setMoney(double money) {
    15. this.money = money;
    16. }
    17. }

    dao包下AccountDao

    1. package com.dao;
    2. public interface AccountDao {
    3. public void out(String outMan, double money);
    4. public void in(String inMan, double money);
    5. }

    实现类下

    1. package com.dao.impl;
    2. import com.dao.AccountDao;
    3. import org.springframework.jdbc.core.JdbcTemplate;
    4. public class AccountDaoImpl implements AccountDao {
    5. private JdbcTemplate jdbcTemplate;
    6. public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
    7. this.jdbcTemplate = jdbcTemplate;
    8. }
    9. public void out(String outMan, double money) {
    10. jdbcTemplate.update("update account set money=money-? where name=?",money,outMan);
    11. }
    12. public void in(String inMan, double money) {
    13. jdbcTemplate.update("update account set money=money+? where name=?",money,inMan);
    14. }
    15. }

    配置文件applicationCntext1.xml下

    1. "1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xmlns:aop="http://www.springframework.org/schema/aop"
    5. xmlns:tx="http://www.springframework.org/schema/tx"
    6. xsi:schemaLocation="
    7. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    8. http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
    9. http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
    10. ">
    11. <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    12. <property name="driverClass" value="com.mysql.jdbc.Driver"/>
    13. <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"/>
    14. <property name="user" value="root"/>
    15. <property name="password" value="123456"/>
    16. bean>
    17. <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    18. <property name="dataSource" ref="dataSource"/>
    19. bean>
    20. <bean id="accountDao" class="com.dao.impl.AccountDaoImpl">
    21. <property name="jdbcTemplate" ref="jdbcTemplate"/>
    22. bean>
    23. <bean id="accountService" class="com.service.impl.AccountServiceImpl">
    24. <property name="accountDao" ref="accountDao"/>
    25. bean>
    26. <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    27. <property name="dataSource" ref="dataSource"/>
    28. bean>
    29. <tx:advice id="txAdvice" transaction-manager="transactionManager">
    30. <tx:attributes>
    31. <tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
    32. <tx:method name="save" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
    33. <tx:method name="findAll" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="true"/>
    34. <tx:method name="update*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="true"/>
    35. <tx:method name="*"/>
    36. tx:attributes>
    37. tx:advice>
    38. <aop:config>
    39. <aop:pointcut id="txPointcut" expression="execution(* com.service.impl.*.*(..))"/>
    40. <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
    41. aop:config>
    42. beans>

    pom.xml下

    1. <dependencies>
    2. <dependency>
    3. <groupId>junitgroupId>
    4. <artifactId>junitartifactId>
    5. <version>4.12version>
    6. dependency>
    7. <dependency>
    8. <groupId>org.springframeworkgroupId>
    9. <artifactId>spring-testartifactId>
    10. <version>5.0.5.RELEASEversion>
    11. dependency>
    12. <dependency>
    13. <groupId>org.aspectjgroupId>
    14. <artifactId>aspectjweaverartifactId>
    15. <version>1.8.4version>
    16. dependency>
    17. <dependency>
    18. <groupId>org.springframeworkgroupId>
    19. <artifactId>spring-contextartifactId>
    20. <version>5.0.5.RELEASEversion>
    21. <scope>compilescope>
    22. dependency>
    23. <dependency>
    24. <groupId>org.springframeworkgroupId>
    25. <artifactId>spring-jdbcartifactId>
    26. <version>5.0.5.RELEASEversion>
    27. dependency>
    28. <dependency>
    29. <groupId>org.springframeworkgroupId>
    30. <artifactId>spring-testartifactId>
    31. <version>5.0.5.RELEASEversion>
    32. dependency>
    33. <dependency>
    34. <groupId>org.springframeworkgroupId>
    35. <artifactId>spring-txartifactId>
    36. <version>5.0.5.RELEASEversion>
    37. dependency>
    38. <dependency>
    39. <groupId>c3p0groupId>
    40. <artifactId>c3p0artifactId>
    41. <version>0.9.1.1version>
    42. dependency>
    43. <dependency>
    44. <groupId>mysqlgroupId>
    45. <artifactId>mysql-connector-javaartifactId>
    46. <version>5.1.32version>
    47. dependency>
    48. dependencies>

    数据库中

     运行结果

     数据库中

     当发生错误时,数据库中的值都不变这就控制住了事务

    切点方法的事务参数的配置

    1. <tx:advice id="txAdvice" transaction-manager="transactionManager">
    2. <tx:attributes>
    3. <tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED">
    4. tx:attributes>
    5. tx:advice>

    其中代表切点方法的事务参数的配置。例如:

    • name:切点方法名称
    • isolation:事务的隔离级别
    • propogation:事务的传播行为
    • timeout:超时时间
    • read-only:是否只读

    声明式事务控制的配置要点

    • 平台事务管理器配置
    • 事通知的配置
    • 事务aop织入的配置

    基于注解的声明式事务控制

    使用注解方式(改动bean,自定义的bean用注解,非自定义的bean配置到配置文件中去),需要改动两个,一个是配置文件applicationContext,另一个是AccountServiceImpl类

    1. package com_1.service.impl;
    2. import com.dao.AccountDao;
    3. import com.service.AccountService;
    4. import org.springframework.beans.factory.annotation.Autowired;
    5. import org.springframework.stereotype.Service;
    6. import org.springframework.transaction.annotation.Isolation;
    7. import org.springframework.transaction.annotation.Propagation;
    8. import org.springframework.transaction.annotation.Transactional;
    9. @Service("accountService")
    10. //在类上使用事务,其中的所有方法都会生效
    11. @Transactional(isolation = Isolation.REPEATABLE_READ)
    12. public class AccountServiceImpl implements AccountService {
    13. @Autowired
    14. private AccountDao accountDao;
    15. @Transactional(isolation = Isolation.READ_COMMITTED,propagation = Propagation.REQUIRED)
    16. public void transfer(String outMan, String inMan, double money) {
    17. accountDao.out(outMan,money);
    18. accountDao.in(inMan,money);
    19. }
    20. }

    applicationContext配置文件

    1. "1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xmlns:aop="http://www.springframework.org/schema/aop"
    5. xmlns:context="http://www.springframework.org/schema/context"
    6. xmlns:tx="http://www.springframework.org/schema/tx"
    7. xsi:schemaLocation="
    8. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    9. http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
    10. http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
    11. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
    12. ">
    13. <context:component-scan base-package="com_1"/>
    14. <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    15. <property name="driverClass" value="com.mysql.jdbc.Driver"/>
    16. <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"/>
    17. <property name="user" value="root"/>
    18. <property name="password" value="123456"/>
    19. bean>
    20. <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    21. <property name="dataSource" ref="dataSource"/>
    22. bean>
    23. <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    24. <property name="dataSource" ref="dataSource"/>
    25. bean>
    26. <tx:annotation-driven transaction-manager="transactionManager"/>
    27. beans>

    运行结果

     注解配置声明式事务控制解析

    ①使用@Transactional在需要进行事务控制的类或是方法上修饰,注解可用的属性同xml配置方式,例如隔离级别、传播行为等。

    ②注解使用在类上,那么该类下的所有方法都使用同一套注解参数配置

    ③使用在方法上,不同的方法可以采用不同的事务参数配置。

    ④xml配置文件中要开启事务的注解驱动

    配置要点

    平台事务管理器配置(xml方式)

    事务通知的配置(@Transactional注解)

    事务注解驱动的配置

    MyBatis简介

    原始jdbc操作的分析

    1. 原始jdbc开发存在的问题如下:
    2. ①数据库连接创建、释放频繁造成系统资源浪费从而影响系统性能
    3. ③sql语句在代码中硬编码,造成代码不易维护,实际应用sql变化的可能较大,
    4. sql变动需要改变java代码。
    5. ③查询操作时,需要手动将结果集中的数据手动封装到实体中。插入操作时,
    6. 需要手动将实体的数据设置到sql语句的占位符位置
    7. 应对上述问题给出的解决方案:
    8. ①使用数据库连接池初始化连接资源
    9. ②将sql语句抽取到xml配置文件中
    10. ③使用反射、内省等底层技术,自动将实体与表进行属性与字段的自动映射

    什么是Mybatis

    MyBatis实现了上述的解决方案

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

    MyBatis开发步骤

    ①添加MyBatis的坐标

    ②创建user数据表

    ③编写User实体类

    ④编写映射文件UserMapper.xml(主要写sql语句)

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

    ⑥编写测试类

    ①添加pom相应的坐标

    1. <dependency>
    2. <groupId>mysqlgroupId>
    3. <artifactId>mysql-connector-javaartifactId>
    4. <version>5.1.32version>
    5. dependency>
    6. <dependency>
    7. <groupId>org.mybatisgroupId>
    8. <artifactId>mybatisartifactId>
    9. <version>3.4.6version>
    10. dependency>
    11. <dependency>
    12. <groupId>junitgroupId>
    13. <artifactId>junitartifactId>
    14. <version>4.12version>
    15. dependency>
    16. <dependency>
    17. <groupId>log4jgroupId>
    18. <artifactId>log4jartifactId>
    19. <version>1.2.17version>
    20. dependency>

    ②数据库中创建表

     ③创建pojo下的user类

    1. package com_mybatis.pojo;
    2. public class User {
    3. private int id;
    4. private String username;
    5. private String password;
    6. public int getId() {
    7. return id;
    8. }
    9. public void setId(int id) {
    10. this.id = id;
    11. }
    12. public String getUsername() {
    13. return username;
    14. }
    15. public void setUsername(String username) {
    16. this.username = username;
    17. }
    18. public String getPassword() {
    19. return password;
    20. }
    21. public void setPassword(String password) {
    22. this.password = password;
    23. }
    24. @Override
    25. public String toString() {
    26. return "User{" +
    27. "id=" + id +
    28. ", username='" + username + '\'' +
    29. ", password='" + password + '\'' +
    30. '}'+"\n";
    31. }
    32. }

    ④编写映射文件UserMapper.xml(主要写sql语句)

    在resource下的com_mybatis/mapper/UserMapper.xml

    1. "1.0" encoding="UTF-8" ?>
    2. mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    3. <mapper namespace="userMapper">
    4. <select id="findAll" resultType="com_mybatis.pojo.User">
    5. select * from user
    6. select>
    7. mapper>

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

    在resource下的SqlMapConfig.xml

    1. "1.0" encoding="UTF-8" ?>
    2. configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
    3. <configuration>
    4. <environments default="development">
    5. <environment id="development">
    6. <transactionManager type="JDBC">transactionManager>
    7. <dataSource type="POOLED">
    8. <property name="driver" value="com.mysql.jdbc.Driver"/>
    9. <property name="url" value="jdbc:mysql://localhost:3306/test"/>
    10. <property name="username" value="root"/>
    11. <property name="password" value="123456"/>
    12. dataSource>
    13. environment>
    14. environments>
    15. <mappers>
    16. <mapper resource="com_mybatis/mapper/UserMapper.xml">mapper>
    17. mappers>
    18. configuration>

    ⑥编写测试类

    在java下新建一个test包下的mybatisTest类

    1. package com_mybatis.test;
    2. import com_mybatis.pojo.User;
    3. import org.apache.ibatis.io.Resources;
    4. import org.apache.ibatis.session.SqlSession;
    5. import org.apache.ibatis.session.SqlSessionFactory;
    6. import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    7. import org.junit.Test;
    8. import java.io.File;
    9. import java.io.IOException;
    10. import java.io.InputStream;
    11. import java.util.List;
    12. public class MybatisTest {
    13. @Test
    14. public void test1() throws IOException {
    15. //获得核心配置文件
    16. InputStream resourceAsFile = Resources.getResourceAsStream("sqlMapConfig.xml");
    17. //获得session工厂对象
    18. SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsFile);
    19. //获得session会话对象
    20. SqlSession sqlSession = sqlSessionFactory.openSession();
    21. //执行操作 参数:namespace+id
    22. List userList = sqlSession.selectList("userMapper.findAll");
    23. System.out.println(userList);
    24. //释放资源
    25. sqlSession.close();
    26. }
    27. }

    运行结果

     MyBatis的映射文件概述

     Mybatis增删改查操作

    Mybatis的增加/插入操作

    mybatisTest下

    1. @Test
    2. public void test2() throws IOException {
    3. //模拟user对象
    4. User user=new User();
    5. user.setUsername("ZengHui");
    6. user.setPassword("1234");
    7. //获得核心配置文件
    8. InputStream resourceAsFile = Resources.getResourceAsStream("sqlMapConfig.xml");
    9. //获得session工厂对象
    10. SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsFile);
    11. //获得session会话对象
    12. SqlSession sqlSession = sqlSessionFactory.openSession();
    13. //执行操作 参数:namespace+id
    14. int result= sqlSession.insert("userMapper.insertUser",user);
    15. //mybatis默认不自动提交事务,提交后才能持久化到数据库中
    16. sqlSession.commit();
    17. System.out.println(result);
    18. //释放资源
    19. sqlSession.close();
    20. }

     UserMapper.xml下

    1. <insert id="insertUser" parameterType="com_mybatis.pojo.User">
    2. insert into user values (#{id},#{username},#{password})
    3. insert>

     运行结果

    插入操作注意的问题

    • 插入语句使用insert标签
    • 在映射文件中时而用parameterType属性指定要插入的数据类型
    • Sq语句中使用#{实体属性名}方式引用实体中的属性值
    • 插入操作使用的ApI是sqlSession.insert(“命名空间.id,实体对象”);
    • 插入操作设计数据库变化,所以要使用sqlSession对象显示的提交事务,即sqlSession,commit()

    MyBatis的修改数据操作

    在UserMapper.xml文件下

    1. <update id="update" parameterType="com_mybatis.pojo.User">
    2. update user set username=#{username},password=#{password} where id=#{id}
    3. update>

    MybatisTest类下

    1. @Test
    2. //修改操作
    3. public void test3() throws IOException {
    4. //模拟user对象
    5. User user=new User();
    6. user.setId(3);
    7. user.setUsername("ZhaoLiu");
    8. user.setPassword("12345");
    9. //获得核心配置文件
    10. InputStream resourceAsFile = Resources.getResourceAsStream("sqlMapConfig.xml");
    11. //获得session工厂对象
    12. SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsFile);
    13. //获得session会话对象
    14. SqlSession sqlSession = sqlSessionFactory.openSession();
    15. //执行操作 参数:namespace+id
    16. sqlSession.update("userMapper.update", user);
    17. //mybatis默认不自动提交事务,提交后才能持久化到数据库中
    18. sqlSession.commit();
    19. //释放资源
    20. sqlSession.close();
    21. }

    运行之后,数据库中变化

    Mybatis 删除数据操作

    userMapper.xml

    1. <delete id="delete" parameterType="java.lang.Integer">
    2. delete from user where id=#{id}
    3. delete>

      mybatisTest类下

    1. @Test
    2. //删除
    3. public void test4() throws IOException {
    4. //获得核心配置文件
    5. InputStream resourceAsFile = Resources.getResourceAsStream("sqlMapConfig.xml");
    6. //获得session工厂对象
    7. SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsFile);
    8. //获得session会话对象
    9. SqlSession sqlSession = sqlSessionFactory.openSession();
    10. //执行操作 参数:namespace+id
    11. sqlSession.delete("userMapper.delete", 3);
    12. //mybatis默认不自动提交事务,提交后才能持久化到数据库中
    13. sqlSession.commit();
    14. //释放资源
    15. sqlSession.close();
    16. }

    运行结果

     删除操作注意的问题

    删除语句使用delete标签

    Sql语句中使你#{任意字符串}方式引用传递的单个参数

    删除操作使用的API是sqlSession.delete("命名空间.id",Object)

    Mybatis常用核心配置文件概述

    envrionment标签

    数据库环境配置。,支持多环境配置

    1. 其中,事务管理器(transactionManager)类型有两种:
    2. JDBC:这个配置就是直接使用了JDBC的提交和回滚设置,它依赖干从数据源得到
    3. 的连接来管理事务作用域
    4. MANAGED:这个配置几乎没做什么。它从来不提交或回滚一个连接,而是让容器
    5. 来管理事务的整个生命周期(比如JEE应用服务器的上下文)。默认情况下它会关
    6. 闭连接,然而一些容器并不希望这样,因此需要将closeConnection属性设置为
    7. false来阻止它默认的关闭行为。
    8. 其中,数据源(dataSource)类型有三种:
    9. ·UNPOOLED:这个数据源的实现只是每次被请求时打开和关闭连接。
    10. ·POOLED:这种数据源的实现利用“池”的概念将JDBC连接对象组织起来。
    11. ·JNDI:这个数据源的实现是为了能在如EJB或应用服务器这类容器中使用,
    12. 容器可以集中或在外部配置数据源,然后放置一个JNDI上下文的引用。

     mapper标签

    该标签的作用是加载映射的,加载方式有如下几种:

    • 使用相对于类路径的资源引用,例如:(常用)
    • 使用完全限定资源定位符(URL),例如:
    • 使用映射器接口实现类的完全限定类名,例如:
    • 将包内的映射器接口实现全部注册为映射器,例如:

     Properties标签

    实际开发中,习惯将数据源的配置信息单独抽取成一个properties文件,该标签可以加载额外配置的properties文件

     jdbc.properties文件下

    1. jdbc.driver=com.mysql.jdbc.Driver
    2. jdbc.url=jdbc:mysql://localhost:3306/test
    3. jdbc.username=root
    4. jdbc.password=123456

    sqlMapConfig.xml

    1. <properties resource="jdbc.properties">properties>
    2. <environments default="development">
    3. <environment id="development">
    4. <transactionManager type="JDBC">transactionManager>
    5. <dataSource type="POOLED">
    6. <property name="driver" value="${jdbc.driver}"/>
    7. <property name="url" value="${jdbc.url}"/>
    8. <property name="username" value="${jdbc.username}"/>
    9. <property name="password" value="${jdbc.password}"/>
    10. dataSource>
    11. environment>
    12. environments>

     执行一个查询操作,运行结果

     typeAliases标签

    类型别名是java类型设置一个短的名字,原来的类型名称配置如下

    在sqlMapConfig 配置typeAliases,将com_mybatis.pojo.User定义别名为user

     报了一个顺序错误,typeAliases应该放在properties之后

    1. <typeAliases>
    2. <typeAlias type="com_mybatis.pojo.User" alias="user">typeAlias>
    3. typeAliases>

     写sql语句的UserMapper.xml下

    1. <select id="findAll" resultType="user">
    2. select * from user
    3. select>

     MyBatis的相应API

    1、SqlSession工厂构建器SqlSessionFactoryBuilder

    常用API:SqlSessionFactory  build(InputStream inputStream)

    通过加载mybatis的核心文件的输入流的形式构建一个SqlSessionFactory对象

     其中,mybatis-config.xml是类加载器的路径,在maven工程下就是resource资源下Resources工具类,这个类在org.apache.ibatis.io包中。Resource类帮助你从类路径下、文件系统或一个webURL中加载资源文件。

    sqkSessionFactory有多个方法创建SqlSession实例,常用的有两个

    2、SqlSession会话对象

    SqlSession实例在MyBatis是非常强大的一个类,在这里会看到所有执行语句、提交或回滚事务和获取映射实例的方法有

     操作事务的方法主要有

    Mybatis的Dao层实现

    1、传统开发方式-编写UserDao接口

    测试编写UserDao接口

    controller包下UserController类下

    1. package com_Dao.controller;
    2. import com_Dao.service.Impl.UserServiceImpl;
    3. import com_Dao.service.UserService;
    4. import com_mybatis.pojo.User;
    5. import java.io.IOException;
    6. import java.util.List;
    7. public class UserController {
    8. public static void main(String[] args) throws IOException {
    9. UserService userService=new UserServiceImpl();
    10. List userList = userService.findAll();
    11. System.out.println(userList);
    12. }
    13. }

    service包下UserService下

    接口

    1. package com_Dao.service;
    2. import com_mybatis.pojo.User;
    3. import java.io.IOException;
    4. import java.util.List;
    5. public interface UserService {
    6. public List findAll() throws IOException;
    7. }

    实现类下

    1. package com_Dao.service.Impl;
    2. import com_Dao.Dao.Impl.UserDaoImpl;
    3. import com_Dao.Dao.UserDao;
    4. import com_Dao.service.UserService;
    5. import com_mybatis.pojo.User;
    6. import java.io.IOException;
    7. import java.util.List;
    8. public class UserServiceImpl implements UserService {
    9. UserDao userDao=new UserDaoImpl();
    10. @Override
    11. public List findAll() throws IOException {
    12. return userDao.findAll();
    13. }
    14. }

    dao包下的UserDao下

    接口下

    1. package com_Dao.Dao;
    2. import com_mybatis.pojo.User;
    3. import java.io.IOException;
    4. import java.util.List;
    5. public interface UserDao {
    6. public List findAll() throws IOException;
    7. }

    实现类下

    1. package com_Dao.Dao.Impl;
    2. import com_Dao.Dao.UserDao;
    3. import com_mybatis.pojo.User;
    4. import org.apache.ibatis.io.Resources;
    5. import org.apache.ibatis.session.SqlSession;
    6. import org.apache.ibatis.session.SqlSessionFactory;
    7. import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    8. import java.io.IOException;
    9. import java.io.InputStream;
    10. import java.util.List;
    11. public class UserDaoImpl implements UserDao {
    12. @Override
    13. public List findAll() throws IOException {
    14. //获得核心配置文件
    15. InputStream resourceAsFile = Resources.getResourceAsStream("sqlMapConfig.xml");
    16. //获得session工厂对象
    17. SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsFile);
    18. //获得session会话对象
    19. SqlSession sqlSession = sqlSessionFactory.openSession();
    20. //执行操作 参数:namespace+id
    21. List userList = sqlSession.selectList("userMapper.findAll");
    22. return userList;
    23. }
    24. }

    其他文件,如sqlMapConfig.xml和UserMapper.xml等中的配置和之前的一致

    运行结果

    2、 代理开发方式

    介绍

    采用Mybatis的电路考法方式实现Dao层的开发,这种方式是我们进入企业的主流。

    Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。 Mapper接口开发需要遵循以下规范:

    1. Mapper.xml文件中的namespace与mapper接口的全限定名相同
    2. Mapper接口方法名和Mapperxml中定义的每个statement的id相同
    3. Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameterType的类型相同
    4. Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同

    规范图示对应

    代码测试代理开发 

     UserDao下

    1. package com_Dao_DaiLi.Dao;
    2. import com_mybatis.pojo.User;
    3. import java.io.IOException;
    4. public interface UserDao {
    5. public User findById(int id) throws IOException;
    6. }

     service包下

    1. package com_Dao_DaiLi.service;
    2. import com_Dao_DaiLi.Dao.UserDao;
    3. import com_mybatis.pojo.User;
    4. import org.apache.ibatis.io.Resources;
    5. import org.apache.ibatis.session.SqlSession;
    6. import org.apache.ibatis.session.SqlSessionFactory;
    7. import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    8. import java.io.IOException;
    9. import java.io.InputStream;
    10. public class ServiceTest {
    11. public static void main(String[] args) throws IOException {
    12. InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
    13. SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
    14. SqlSession sqlSession = sqlSessionFactory.openSession();
    15. UserDao mapper = sqlSession.getMapper(UserDao.class);
    16. User user = mapper.findById(1);
    17. System.out.println(user);
    18. }
    19. }

    UserMapper1.xml下 

    1. "1.0" encoding="UTF-8" ?>
    2. mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    3. <mapper namespace="com_Dao_DaiLi.Dao.UserDao">
    4. <select id="findById" parameterType="int" resultType="user">
    5. select *from user where id=#{id}
    6. select>
    7. mapper>

     还需注意将sqlMapConfig.xml下加载UserMapper1.xml下 

    运行结果

    Mybatis映射文件深入

    动态sql语句

    概述:Mybatais的映射文件中,前面我们的SQL都是比较简单的,有时候业务逻辑复杂时,我们的sql时动态变化的,此时在其那面学习的sql就不能满足要求了

    官方文档中动态sql

    MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其他类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句有多么痛苦。拼接的时候要确保不能忘了必要的空格,还要注意省掉列名列表最后的逗号。利用动态 SQL 这一特性可以彻底摆脱这种痛苦。

    通常使用动态 SQL 不可能是独立的一部分,MyBatis 当然使用一种强大的动态 SQL 语言来改进这种情形,这种语言可以被用在任意的 SQL 映射语句中。

    动态 SQL 元素和使用 JSTL 或其他类似基于 XML 的文本处理器相似。在 MyBatis 之前的版本中,有很多的元素需要来了解。MyBatis 3 大大提升了它们,现在用不到原先一半的元素就可以了。MyBatis 采用功能强大的基于 OGNL 的表达式来消除其他元素。

    • if
    • choose (when, otherwise)
    • trim (where, set)
    • foreach

    动态SQL之if

    测试示例if

    UserMapper接口下

    1. package com_Mybatis_sql.mapper;
    2. import com_Mybatis_sql.pojo.User;
    3. import java.util.List;
    4. public interface UserMapper {
    5. public List findByCondition(User user);
    6. }

     UserMapper2.xml文件下

    1. "1.0" encoding="UTF-8" ?>
    2. mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    3. <mapper namespace="com_Mybatis_sql.mapper.UserMapper">
    4. <select id="findByCondition" parameterType="user" resultType="user">
    5. select *from user
    6. -- 用where标签保住等价于where 1=1,有条件就进入
    7. <where>
    8. <if test="id!=0">
    9. and id=#{id}
    10. if>
    11. <if test="username!=null">
    12. and username=#{username}
    13. if>
    14. <if test="password!=null">
    15. and password=#{password}
    16. if>
    17. where>
    18. select>
    19. mapper>

    test测试下

    1. public class MapperTest {
    2. @Test
    3. public void test1() throws IOException {
    4. InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
    5. SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
    6. SqlSession sqlSession = sqlSessionFactory.openSession();
    7. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    8. //模拟条件user
    9. User user=new User();
    10. user.setId(1);
    11. user.setUsername("zhangsan");
    12. user.setPassword("123");
    13. List userList = mapper.findByCondition(user);
    14. System.out.println(userList);
    15. }
    16. }

    运行结果

     当没有写条件时,原来的sql语句就等价于select *from user

    1. <select id="findByIds" parameterType="list" resultType="user">
    2. select *from user
    3. <where>
    4. <foreach collection="list" open="id in(" close=")" item="id" separator=",">
    5. #{id}
    6. foreach>
    7. where>
    8. select>

     这样的动态查询无论是有没有条件或者是有多个条件都能查询到

    动态sql之foreach

    循环执行sql的拼接操作,例如::select *from user where id in(1,2,3)

    测试示例foreach

    UserMapper接口下

    1. public interface UserMapper {
    2. public List findByIds(List ids);
    3. }

    配置文件UserMapper2.xml配置文件下

    1. <select id="findByIds" parameterType="list" resultType="user">
    2. select *from user
    3. <where>
    4. <foreach collection="list" open="id in(" close=")" item="id" separator=",">
    5. #{id}
    6. foreach>
    7. where>
    8. select>

    MapperTest测试类下

    1. public class MapperTest {
    2. @Test
    3. public void test2() throws IOException {
    4. InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
    5. SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
    6. SqlSession sqlSession = sqlSessionFactory.openSession();
    7. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    8. //模拟ids的数据
    9. List ids=new ArrayList();
    10. ids.add(1);
    11. ids.add(2);
    12. List byIds = mapper.findByIds(ids);
    13. System.out.println(byIds);
    14. }
    15. }

     运行结果

     sql片段的抽取

    sql中可将重复的sql提取出来,使用include引用即可,最终达到sql重用的目的

    1. <sql id="selectUser"> select *from usersql>
    2. <select id="findByIds" parameterType="list" resultType="user">
    3. <include refid="selectUser">include>
    4. <where>
    5. <foreach collection="list" open="id in(" close=")" item="id" separator=",">
    6. #{id}
    7. foreach>
    8. where>
    9. select>

    Mybatis映射文件深入知识小结