Spring笔记(三)(Spring整合web环境)

01、Spring整合web环境

1.1 Javaweb三大组件及环境特点

在Java语言范畴内,web层框架都是基于Javaweb基础组件完成的,所以有必要复习一下Javaweb组件的特点

组件作用特点
Servlet服务端小程序,负责接收客户端请求并作出响应的单例对象,默认第一次访问创建,可以通过配置指定服务器启动就创建,Servlet创建完毕会执行初始化init方法。每个Servlet有一个service方法,每次访问都会执行service方法,但是缺点是一个业务功能就需要配置一个Servlet
Filter过滤器,负责对客户端请求进行过滤操作的单例对象,服务器启动时就创建,对象创建完毕执行init方法,对客户端的请求进行过滤,符合要求的放行,不符合要求的直接响应客户端,执行过滤的核心方法doFilter
Listener监听器,负责对域对象的创建和属性变化进行监听的根据类型和作用不同,又可分为监听域对象创建销毁和域对象属性内容变化的, 根据监听的域不同,又可以分为监听Request域的,监听Session域的,监听ServletContext域的

1.2 Spring整合web环境的思路及实现

在进行Java开发时要遵循三层架构+MVC,Spring操作最核心的就是Spring容器,web层需要注入Service, service层需要注入Dao(Mapper),web层使用Servlet技术充当的话,需要在Servlet中获得Spring容器
具体操作如下:

  1. 在第二节笔记中的转账业务模块,修改pom.xml 文件的打包方式及导包:
<packaging>war</packaging>
<dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version>
</dependency>
  1. 创建web层,servlet
@WebServlet(urlPatterns = "/accountServlet")
public class AccountServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// web层调用service层,获得accountService,现在accountService在Spring容器中ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AccountConfig.class);AccountService accountService = (AccountService) applicationContext.getBean("accountService");accountService.transferMoney("tom","lucy",500);System.out.println("转账操作成功");}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}
}
  1. 配置tomcat,部署项目,访问链接http://localhost:8080/accountServlet

测试事务

  • 模拟有异常

访问前:数据库tom:5000, lucy:5000
访问后:数据库tom:5000, lucy:5000
image.png

  • 无异常

访问前:数据库tom:5000, lucy:5000
访问后:数据库tom:4500, lucy:5500
image.png

上述方案的问题:web层代码如果都去编写创建AnnotationConfigApplicationContext的代码,
那么配置类重复被加载了, Spring容器也重复被创建了,不能每次想从容器中获得一个Bean都得先创建一次容器,这样肯定是不允许。
所以,我们现在的诉求很简单,如下:

  • ApplicationContext创建一次,配置类加载一次;
  • 最好web服务器启动时,就执行第1步操作,后续直接从容器中获取Bean使用即可;
  • ApplicationContext的引用需要在web层任何位置都可以获取到。

针对以上诉求我们给出解决思路,如下:

  • 在ServletContextListener的contextInitialized方法中执行ApplicationContext的创建。或在Servlet的init 方法中执行ApplicationContext的创建,并给Servlet的load-on-startup属性一个数字值,确保服务器启动Servlet就创建;
  • 将创建好的ApplicationContext存储到ServletContext域中,这样整个web层任何位置就都可以获取到了

实现:

  1. 在main目录下,新增webapp/WEB-INF/web.xml目录及文件
<?xml version="1.0" encoding="UTF8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaeehttp://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"version="3.1">
</web-app>
  1. 新建一个监听器ContextLoaderListener,用于创建applicationContext,并存入ServletContext域中
public class ContextLoaderListener implements ServletContextListener {@Override// 服务器启动,ServletContext创建,该方法被执行1次public void contextInitialized(ServletContextEvent sce) {System.out.println("ContextLoaderListener init ....");// 1. 创建spring容器ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");// 2. 将容器存储到servletContext域中sce.getServletContext().setAttribute("applicationContext",applicationContext);}
}
  1. 修改AccountServlet类中applicationContext的获取方式,改为从ServletContext域中获取
package com.mem.web;import com.mem.config.AccountConfig;
import com.mem.service.AccountService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;@WebServlet(urlPatterns = "/accountServlet")
public class AccountServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// web层调用service层// 从ServletContext域中获取applicationContext对象ApplicationContext applicationContext =(ApplicationContext) request.getServletContext().getAttribute("applicationContext");AccountService accountService = (AccountService) applicationContext.getBean("accountService");accountService.transferMoney("tom","lucy",500);System.out.println("转账操作成功####");}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}
}
  1. 将新建的监听器配置到web.xml中
<!--配置Listener-->
<listener><listener-class>com.mem.listener.ContextLoaderListener</listener-class>
</listener>
  1. 测试,结果同上

上述方案问题描述:
在ContextLoaderListener类中,配置文件的名称和容器的名称都写死了,不太友好;
解决方法:
利用常量进行解耦

改进:

  1. 在web.xml文件中,新增全局参数
<!--定义全局参数-->
<context-param><param-name>contextConfigLocation</param-name><param-value>classpath:applicationContext.xml</param-value>
</context-param>
  1. 修改ContextLoaderListener中的代码
public class ContextLoaderListener implements ServletContextListener {private String CONTEXT_CONFIG_LOCATION = "contextConfigLocation";@Override// 服务器启动,ServletContext创建,该方法被执行1次public void contextInitialized(ServletContextEvent sce) {System.out.println("ContextLoaderListener init ....");ServletContext servletContext = sce.getServletContext();// 0. 获取contextConfigLocation配置文件的名称String contextConfigLocation = servletContext.getInitParameter(CONTEXT_CONFIG_LOCATION);contextConfigLocation = contextConfigLocation.substring("classpath:".length());// 1. 创建spring容器ApplicationContext applicationContext = new ClassPathXmlApplicationContext(contextConfigLocation);// 2. 将容器存储到servletContext域中servletContext.setAttribute("applicationContext",applicationContext);}
}
  1. 新建一个工具类WebApplicationContextUtils获取applicationContext对象
public class WebApplicationContextUtils {public static ApplicationContext getWebApplicationContext(ServletContext servletContext){ApplicationContext applicationContext = (ApplicationContext) servletContext.getAttribute("applicationContext");return applicationContext;}
}
  1. 修改AccountServlet类中applicationContext的获取方式
@WebServlet(urlPatterns = "/accountServlet")
public class AccountServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// web层调用service层,从getWebApplicationContext()方法中获取applicationContext对象ApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(request.getServletContext());AccountService accountService = (AccountService) applicationContext.getBean("accountService");accountService.transferMoney("tom","lucy",500);System.out.println("转账操作成功####");}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}
}

1.3 Spring的web开发组件spring-web

到此,就将一开始的诉求都解决了,当然我们能想到的Spring 框架自然也会想到,Spring其实已经为我们定义 好了一个ContextLoaderListener,使用方式跟我们上面自己定义的大体一样,但是功能要比我们强百倍,所以 ,遵循Spring “拿来主义” 的精神,我们直接使用Spring提供的就可以了,开发如下:

  1. 先导入Spring-web的坐标:
<dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>5.3.9</version>
</dependency>
  1. 在web.xml中去配置ContextLoaderListener,并指定配置文件的位置
<!--自定义的Listener,用于创建applicationContext容器并存入到servletContext域中-->
<!--    <listener>-->
<!--        <listener-class>com.mem.listener.ContextLoaderListener</listener-class>-->
<!--    </listener>-->
<!--官方提供的-->
<listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
  1. 在Servlet中直接使用,改成官方的WebApplicationContextUtils
import org.springframework.web.context.support.WebApplicationContextUtils;@WebServlet(urlPatterns = "/accountServlet")
public class AccountServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// web层调用service层ApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(request.getServletContext());AccountService accountService = (AccountService) applicationContext.getBean("accountService");accountService.transferMoney("tom","lucy",500);System.out.println("转账操作成功####");}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}
}
  1. 测试,结果同上,容器名:XmlWebApplicationContext

如果核心配置类使用的是注解形式的,那么Spring容器是AnnotationConfigWebApplicationContext,如下配 置方式

    <!--配置类的方式(注解)--><context-param><param-name>contextClass</param-name><param-value>com.mem.web.MyAnnotationConfigWebApplicationContext</param-value></context-param><!--配置文件的方式-->
<!--    <context-param>-->
<!--        <param-name>contextConfigLocation</param-name>-->
<!--        <param-value>classpath:applicationContext.xml</param-value>-->
<!--    </context-param>-->

两个配置方式都打开,按配置类的方式创建容器,容器名是 MyAnnotationConfigWebApplicationContext
原因:在下面源码分析中,
determineContextClass方法里面,根据是否含有contextClass变量而决定的初始化哪个容器。
String contextClassName = servletContext.getInitParameter(“contextClass”);

public class MyAnnotationConfigWebApplicationContext extends AnnotationConfigWebApplicationContext {public MyAnnotationConfigWebApplicationContext(){super();// 注册配置类到容器this.register(AccountConfig.class);}
}

测试:结果同上,容器名为:MyAnnotationConfigWebApplicationContext

源码分析:
目的:如何决定是xml配置文件方式还是用配置类方式创建applicationContext
入口:org.springframework.web.context.ContextLoaderListener类的contextInitialized方法

public class ContextLoaderListener extends ContextLoader implements ServletContextListener {public ContextLoaderListener() {}public ContextLoaderListener(WebApplicationContext context) {super(context);}public void contextInitialized(ServletContextEvent event) {// 调用父类中的initWebApplicationContext方法,所以查看ContextLoader类this.initWebApplicationContext(event.getServletContext());}public void contextDestroyed(ServletContextEvent event) {this.closeWebApplicationContext(event.getServletContext());ContextCleanupListener.cleanupAttributes(event.getServletContext());}
}
public class ContextLoader {public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {// 调用本类的createWebApplicationContext方法this.context = this.createWebApplicationContext(servletContext);}protected WebApplicationContext createWebApplicationContext(ServletContext sc) {// 调用本类的determineContextClass方法,获取字节码对象,Class<?> contextClass = this.determineContextClass(sc);if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {throw new ApplicationContextException("Custom context class [" + contextClass.getName() + "] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");} else {return (ConfigurableWebApplicationContext)BeanUtils.instantiateClass(contextClass);}}protected Class<?> determineContextClass(ServletContext servletContext) {// 判断 web.xml 文件中有没有contextClass参数,// 如果有,则按配置类的方式(注解) 容器名:AnnotationConfigWebApplicationContext// 如果没有,则按配置文件的方式 容器名:XmlWebApplicationContextString contextClassName = servletContext.getInitParameter("contextClass");if (contextClassName != null) {return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());} else {contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());}}
}

查看WebApplicationContext的实现类:
image.png

02、web层MVC框架思想与设计思路

Java程序员在开发一般都是MVC+三层架构,MVC是web开发模式,传统的Javaweb技术栈实现的MVC如下
image.png
原始Javaweb开发中,Servlet充当Controller的角色,Jsp充当View角色,JavaBean充当模型角色,后期Ajax异 步流行后,在加上现在前后端分离开发模式成熟后,View就被原始Html+Vue替代。原始Javaweb开发中, Service充当Controller有很多弊端,显而易见的有如下几个:
image.png

负责共有行为的Servlet称之为前端控制器,负责业务行为的JavaBean称之为控制器Controller
image.png
分析前端控制器基本功能如下:

  1. 具备可以映射到业务Bean的能力
  2. 具备可以解析请求参数、封装实体 等共有功能
  3. 具备响应视图及响应其他数据的功能

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/185520.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

中国第二批,11个大模型备案获批

加上首批的 10 余个大模型&#xff0c;目前已有超过 20 个大模型获得审批。 据钛媒体独家报道&#xff0c;国内第二批通过备案的AI大模型包括11家公司&#xff0c;部分已面向全社会开放服务。加上首批的10余个大模型&#xff0c;目前已有超过20个大模型获得备案。 新一批备案…

JAVASSMmysql面向高校校园体育用品租借管理系统94593-计算机毕业设计项目选题推荐(附源码)

摘 要 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;微信小程序的面向高校校园体育用品租借管理系统被用户普遍…

微信小程序使用阿里巴巴矢量图标

一&#xff0c;介绍 微信小程序使用图标有两种方式&#xff0c;一种是在线获取&#xff0c;一种是下载到本地使用&#xff0c; 第一种在线获取的有个缺点就是图标是灰色的&#xff0c;不能显示彩色图标&#xff0c;而且第一种是每次请求资源的&#xff0c;虽然很快&#xff0…

2023亚太杯数学建模C题思路分析

文章目录 0 赛题思路1 竞赛信息2 竞赛时间3 建模常见问题类型3.1 分类问题3.2 优化问题3.3 预测问题3.4 评价问题 4 建模资料5 最后 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 竞赛信息 2023年第十三…

超好用!在线即可制作电子产品图册

​电子产品图册是展示产品特点、功能和外观的重要方式之一。通过图册&#xff0c;可以让客户更好地了解产品&#xff0c;增强信任感&#xff0c;从而促进销售。同时&#xff0c;对于企业来说&#xff0c;制作精美的电子产品图册也是展示企业文化和品牌形象的重要手段之一。 一、…

AP2005SPER 低噪声4.5A升压电流模式PWM转换器 最高可达9V 适用于升压5V/9V 大电流

AP2005 是电流模式 DC-DC 升压转换器。它是内置 0.05Q 功率 MOSFET 的 PWM 电路使转换器高效率。内部补偿电路也减少多达 6 个外部器件。误差放大器的同相输入端连接到一个精准的 0.6V基准电压。内部软启动功能&#xff0c;可降低浪涌电流AP2005 适应于 SOP8-PP 封装&#xff0…

vue+css动画 实现文字的上下轮播切换

突然间碰到一个比较丝滑的特效,就研究了一下想把它实现出来。 效果:渐隐消失,底部往上走覆盖出现 以下是完整代码,复制粘贴即可运行 <template><div class="aaa"><divclass="page1":class="{ private-fade-out: prevIndex === 1…

打开pr提示找不到vcomp100.dll无法继续执行代码怎么办?5种dll问题解决方案全解析

vcomp100.dll是一个由Microsoft开发的动态链接库&#xff08;DLL&#xff09;文件&#xff0c;它对于许多基于图形的应用程序&#xff08;如Photoshop&#xff09;和多个游戏&#xff08;如《巫师3》&#xff09;至关重要。以下是关于vcomp100.dll的属性介绍以及找不到vcomp100…

基于redis实现分布式锁

文章目录 基于redis实现分布式锁基本实现防死锁防误删高并发场景下无法保证原子性使用lua保证删除原子性 把redis锁封装成方法 基于redis实现分布式锁 基本实现 借助于redis中的命令setnx(key, value)&#xff0c;key不存在就新增&#xff0c;存在就什么都不做。同时有多个客…

动态内存管理(上)

目录 为什么要有动态内存分配malloc和freemallocfree calloc和realloccallocrealloc 感谢各位大佬对我的支持,如果我的文章对你有用,欢迎点击以下链接 &#x1f412;&#x1f412;&#x1f412; 个人主页 &#x1f978;&#x1f978;&#x1f978; C语言 &#x1f43f;️&…

mindspore mindcv图像分类算法;模型保存与加载

参考&#xff1a; https://www.mindspore.cn/tutorials/en/r1.3/save_load_model.html https://github.com/mindspore-lab/mindcv/blob/main/docs/zh/tutorials/finetune.md 1、mindspore mindcv图像分类算法 import os from mindcv.utils.download import DownLoad import o…

一文搞定多端开发,做全栈大牛 附三大企业实战项目

一个功能三套代码 一改需求就是加不完的班&#xff1f; 不存在的&#xff0c;告别改改改 拥抱多端开发 一套代码搞定多个平台 高效开发&#xff1a;一套代码&#xff0c;多端通用 根据统计数据&#xff0c;全球移动设备用户数已经超过了50亿。随着智能手机、平板电脑等移动…

AI:68-基于深度学习的身份证号码识别

🚀 本文选自专栏:AI领域专栏 从基础到实践,深入了解算法、案例和最新趋势。无论你是初学者还是经验丰富的数据科学家,通过案例和项目实践,掌握核心概念和实用技能。每篇案例都包含代码实例,详细讲解供大家学习。 📌📌📌在这个漫长的过程,中途遇到了不少问题,但是…

剑指JUC原理-15.ThreadLocal

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱吃芝士的土豆倪&#xff0c;24届校招生Java选手&#xff0c;很高兴认识大家&#x1f4d5;系列专栏&#xff1a;Spring源码、JUC源码&#x1f525;如果感觉博主的文章还不错的话&#xff0c;请&#x1f44d;三连支持&…

【Mac开发环境搭建】安装HomeBrew、HomeBrew安装Docker、Docker安装Mysql5.7和8

文章目录 HomeBrew安装相关命令安装包卸载包查询可用的包更新所有包更新指定包查看已经安装的包查看包的信息清理包查看brew的版本更新brew获取brew的帮助信息 Brew安装DockerDocker常用命令镜像相关查看已经拉取的所有镜像删除镜像 容器相关停止运行容器启动容器重启容器删除容…

OSPF下的MGRE实验

一、实验要求 1、R1-R3-R4构建全连的MGRE环境 2、R1-R5-R6建立hub-spoke的MGRE环境&#xff0c;其中R1为中心 3、R1-R3...R6均存在环回网段模拟用户私网&#xff0c;使用OSPF使全网可达 4、其中R2为ISP路由器&#xff0c;仅配置IP地址 二、实验拓扑图 三、实验配置 1、给各路…

自然语言处理中的文本聚类:揭示模式和见解

一、介绍 在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;文本聚类是一种基本且通用的技术&#xff0c;在信息检索、推荐系统、内容组织和情感分析等各种应用中发挥着关键作用。文本聚类是将相似文档或文本片段分组为簇或类别的过程。这项技术使我们能够发现隐藏的…

企业级低代码开发,科技赋能让企业具备“驾驭软件的能力”

科技作为第一生产力&#xff0c;其强大的影响力在各个领域中都有所体现。数字技术&#xff0c;作为科技领域中的一股重要力量&#xff0c;正在对传统的商业模式进行深度的变革&#xff0c;为各行业注入新的生命力。随着数字技术的不断发展和应用&#xff0c;企业数字化转型的趋…

10-27 maven概念

maven maven的概念模型: 项目对象模型(POM: Project object Model)&#xff0c;一组标准集合: pom.xml 依赖管理系统(Dependency Management System) 项目生命周期(Project Lifecycle) 项目对象模型&#xff1a; 把项目当成一个对象&#xff0c;描述这个项目&#xff0c;使用p…

计算机网络实验

计算机网络实验 使用软件PT7.0按照上面的拓扑结构建立网络&#xff0c;进行合理配置&#xff0c;使得所有计算机之间能够互相通信。并且修改各交换机的系统名称为&#xff1a;学号_编号&#xff0c;如你的学号为123&#xff0c;交换机Switch0的编号为0&#xff0c;则系统名称为…