Spring-集成Web

news2024/11/27 16:49:54
一、引子

前面我们在Spring集成Junit中为读者引出了Spring善于集成其它框架的优势,而Spring项目不可能仅限于小范围的某个方法的测试,终究会落脚于Web项目上。于是,我们就从这里正式进入Spring集成Web的话题。由于笔者会从原生的Java Web开发过渡到Spring集成Web,从而体现出Spring集成的魅力,因此在阅读这篇文章之前,希望读者已经有关于Java Web的一些基础(可先浏览Java Web专栏),包括Servlet,Tomcat,JSP等。

这里笔者想多说几句,虽然现在主流的开发似乎都不再与Servlet,Tomcat,JSP之流直接接触了,但是理解一个技术,是要理解这个技术为什么产生,是解决了当时的什么问题,这样能帮助我们将不断迭代的技术连贯起来,因此我们就需要了解这门技术产生之前使用的是什么技术,这样会让我们更深入地理解现在使用的技术的优势。Servlet是Web应用的基石,虽不直接使用却是必要掌握的;Tomcat(这里泛指Web服务器)似乎在SpringBoot的兴起后而不再需要像此前一样关注,但是Web项目离不开Tomcat;JSP更是一门难用、逐渐被摒弃的语言,虽然JSP是过时的技术,但依旧不妨去学习到能看懂JSP代码的程度,这样你将更能理解什么是前后端分离。重要的是,当你慢慢熟悉技术的迭代发展,你会对一些似乎耳熟能详的词语感觉到豁然开朗而不是"看似"理解了这些概念。

二、仅用Spring框架如何实现?

(1)利用我们上一篇介绍的Spring注解开发,声明一个配置类:

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.bylearning")
public class SpringConfiguration {
}

(2)定义Dao层与Service层类,注解在类上添加注解,表明将此类交给Spring容器:

import org.springframework.stereotype.Repository;

@Repository
public class UserDao {

    public void save() {
        System.out.println("save successfully...");
    }
}

Service层注入Dao层对象属性

import com.bylearning.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    @Autowired
    private UserDao userDao;

    public void saveUser() {
        userDao.save();
    }
}

Web层先延用在Java Web中使用的Servlet:

import com.bylearning.config.SpringConfiguration;
import com.bylearning.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/demo")
public class DemoServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
        ApplicationContext ioc = new AnnotationConfigApplicationContext(SpringConfiguration.class);
        UserService us = ioc.getBean(UserService.class);
        us.saveUser();
    }
}

配置Tomcat,启动项目,在浏览器地址栏中访问该Servlet便可在控制台中看到Dao层中打印的输出语句。至此便完成了原生的Spring 对于Web的开发。

三、在此基础上怎么改进?

我们注意到在DemoServlet类中,我们为了获取到容器中的Service层对象,利用配置类创建了一个IoC容器。我们不禁想到:难道每个Servlet中都要重复这一段代码吗,这不仅是代码的重复,可以想象更是性能的负担,我们不可能这么做。有经验的小伙伴可能会想到一个办法:提供一个静态方法来获取单例的IoC容器呗。例如这样:

import com.bylearning.config.SpringConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class IoCUtil {
    
    public static ApplicationContext ioc;
    
    static {
        ioc = new AnnotationConfigApplicationContext(SpringConfiguration.class);
    }
    
    public static ApplicationContext getIoC() {
        return ioc;
    }
}

但是我们根据Java类加载顺序知道,静态代码块会在类第一次被加载的时候自动执行,这意味着创建容器的耗时操作将落在第一次被访问的Servlet时,这似乎也不太优雅。

解决办法:还记得我们在介绍Java Web阶段简单提及的三大组件之一——Listener(回顾)。监听器中其中有一个ServletContextListener就是监听ServletContext对象的创建与销毁。因此我们在启动Web项目时,会自动执行该监听器的contextInitialized()方法。我们把创建容器的逻辑放在这个方法里很优雅了。

监听类中创建IoC容器:

import com.bylearning.config.SpringConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

@WebListener
public class ContextLoaderListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        System.out.println("listener init...");
        ApplicationContext ioc = new AnnotationConfigApplicationContext(SpringConfiguration.class);
        ServletContext servletContext = servletContextEvent.getServletContext();
        servletContext.setAttribute("ioc", ioc);
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {

    }

}

提供一个工具类:

import org.springframework.context.ApplicationContext;

import javax.servlet.ServletContext;

public class WebApplicationContextUtils {

    public static ApplicationContext getWebApplicationContext(ServletContext servletContext) {
        ApplicationContext ioc = (ApplicationContext) servletContext.getAttribute("ioc");
        return ioc;
    }
}

改造Servlet获取Service层对象:

import com.bylearning.WebApplicationContextUtils;
import com.bylearning.service.UserService;
import org.springframework.context.ApplicationContext;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/demo")
public class DemoServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
        ApplicationContext ioc = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
        UserService us = ioc.getBean(UserService.class);
        us.saveUser();
    }
}
四、Spring为我们做好了——Spring集成Web

如此典型的优化动作,Spring作为一个优秀的框架,当然为我们做好了。于是我们要开始介绍Spring集成Web。

1、引入依赖

<!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>5.3.1</version>
        </dependency>

2、使用spring-web依赖中提供的工具类。我们此时删除import,重新引入时发现了两个工具类供我们选择,一个是我们在上一步中自己实现的,下一个是spring-web提供的。我们选择下面那一个。

3、在web.xml里配置监听类。不用我们自己在定义监听类了,只需要在web.xml里配置好,并将Spring配置文件作为全局参数配置好。前面我们特意设计将我们自定义的监听类与spring-web提供的监听类名称一致。

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            classpath:applicationContext.xml
        </param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

4、Spring配置文件。进行包扫描即可

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <!--扫描控制层组件-->
    <context:component-scan base-package="com.bylearning"/>

</beans>
五、总结

至此,我们便完成了Spring集成Web的介绍,我们可以看到我们只需要完成监听器的配置与初始参数的配置,接着就可以利用工具类获取到IoC容器了。接下来,我们将为读者继续介绍SpringMVC的内容。

读者在阅读第三、四节时可能会有一个疑问:这里为什么是用一个Servlet来充当Web层呢,这和当下流行的Controller是什么关系呢?因为我们是从原生的Java Web开发过渡而来,因此采用在Java Web开发中常用的继承HttpServlet接口来承接客户端请求,下面我们将为读者介绍SpringMVC的内容,这将与大家熟知的Controller联系起来,请读者继续阅读SpringMVC-基本概念。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Kotlin中的内置函数-apply、let

在使用Kotlin的过程中会经常用到其内置函数&#xff0c;包括apply&#xff0c;let&#xff0c;run&#xff0c;with&#xff0c;also&#xff0c;takeIf,takeUnless函数等&#xff0c;想要更好熟悉Kotlin&#xff0c;这些函数必须烂熟于心&#xff0c;接下来让我们来逐步了解&a…

7.1、一致公钥密码系统

7.1、一致公钥密码系统 一、引言 在本节中&#xff0c;我们将描述一个真实公钥密码系统的玩具模型。这个模型与维数为 2 的格有着意想不到的联系&#xff0c;由于维数太低&#xff0c;因此存在致命漏洞。不过&#xff0c;它也是一个具有启发性的例子&#xff0c;说明了即使基…

【Pytorch】CNN中的Attention

目录 更大层面上的Attention在attention中&#xff0c;怎么分区channel-wise还是spatial-wise举一个Spatial-Channel Attention的例子 使用广泛的Dot-product Attentionattention机制中的query,key,value的概念解释Attention的一个例子 更大层面上的Attention 在attention中&a…

网络服务综合实验项目

目录 实验要求 运行环境 基础配置 业务需求 实验步骤 一、基础配置 1.1、配置静态IP 1.1.1、 在192.168.159.130中配置 1.1.2、 在192.168.159.131中配置 ​编辑 1.2、修改主机名及hosts映射 1.2.1、在192.168.159.130中配置 1.2.2、 编辑配置hosts文件 1.2.3、重启…

1. 两数之和(C++)(map)(哈希算法)

✨欢迎来到脑子不好的小菜鸟的文章✨ &#x1f388;创作不易&#xff0c;麻烦点点赞哦&#x1f388; 所属专栏&#xff1a;刷题 我的主页&#xff1a;脑子不好的小菜鸟 文章特点&#xff1a;关键点和步骤讲解放在 代码相应位置 前提&#xff1a; 看本文章之前&#xff0c;建…

前端开发项目技术总结

前端 vue框架简单学了一遍&#xff0c;也做了demo&#xff0c;主要学了创建项目、路由、状态管理、UI组件库等。 最近在做前端的项目&#xff0c;总结一些开发遇到的问题和解决方案 数据绑定模型 vue框架的标签 :data 和prop标签 data绑定对应的模型&#xff0c;prop是对应…

【C++杂货铺】详解类和对象 [下]

个人博客&#xff1a;代码菌-CSDN博客 专栏&#xff1a;C杂货铺_代码菌的博客-CSDN博客 目录 &#x1f308;前言&#x1f308; &#x1f4c1; 初始化列表&#xff08;灰常重要&#xff09; &#x1f4c2; 引入 &#x1f4c2; 概念 &#x1f4c2; 特性 &#x1f4c1; 拓展构…

【计算机二级考试C语言】C递归

目录 C 递归 数的阶乘 实例 斐波那契数列 实例 C 递归 递归指的是在函数的定义中使用函数自身的方法。 举个例子&#xff1a; 从前有座山&#xff0c;山里有座庙&#xff0c;庙里有个老和尚&#xff0c;正在给小和尚讲故事呢&#xff01;故事是什么呢&#xff1f;"从…

关闭idea之后,项目还在运行,端口被占用

今天在写项目的时候&#xff0c;中途安装了一个插件&#xff0c;而且插件显示需要重启idea&#xff0c;重启的时候项目正在运行&#xff0c;重启之后发现idea没有显示有项目正在运行&#xff0c;当我要开启项目的时候&#xff0c;发现无法开启&#xff0c;显示端口被占用了&…

您企业的(AI)人工智能处于哪个准备阶段?

全新AI准备度评估工具现已推出 根据Gartner 2020年CIO调查报告&#xff0c;仅19%的首席信息官声称其AI项目已投产。这意味着&#xff0c;如果要将AI计划部署到生产过程中&#xff0c;高达80%的企业无法实现。我们发现&#xff0c;澳鹏客户取得成功的几率要高出三倍&#xff0c…

@Test Annotation属性- dependsOnMethods属性

目录 语法 如果test1&#xff08;&#xff09;失败了怎么办&#xff1f;test2&#xff08;&#xff09;测试会发生什么&#xff0c;因为它依赖于test1&#xff1f; 如果我们在test1&#xff08;&#xff09;方法上不使用Test注释&#xff0c;但在test 2&#xff08;&#xf…

放弃Nacos作为配置中心,转而选择这款神器~

目前&#xff0c;我们所有微服务的配置中心都没有采用Nacos&#xff0c;而是选择了另一款携程开源的分布式配置中心Apollo&#xff0c;今天就跟大家详细介绍一下这款神级配置中心 1. 基本概念 由于 Apollo 概念比较多&#xff0c;刚开始使用比较复杂&#xff0c;最好先过一遍…

YOLOv5改进系列(29)——添加DilateFormer(MSDA)注意力机制(中科院一区顶刊|即插即用的多尺度全局注意力机制)

【YOLOv5改进系列】前期回顾&#xff1a; YOLOv5改进系列&#xff08;0&#xff09;——重要性能指标与训练结果评价及分析 YOLOv5改进系列&#xff08;1&#xff09;——添加SE注意力机制 YOLOv5改进系列&#xff08;2&#xff09;——添加CBAM注意力机制 YOLOv5改进系列&…

【Java 数据结构】栈和队列

栈和队列 1. 栈(Stack)1.1 概念1.2 栈的使用1.3 栈的模拟实现1.4 栈的应用场景1.5 概念区分 2. 队列(Queue)2.1 概念2.2 队列的使用2.3 队列模拟实现2.4 循环队列 3. 双端队列 (Deque)4. 面试题 1. 栈(Stack) 1.1 概念 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在…

STM32入门教程-2023版【5-1】NVIC

关注 点赞 不错过精彩内容 大家好&#xff0c;我是硬核王同学&#xff0c;最近在做免费的嵌入式知识分享&#xff0c;帮助对嵌入式感兴趣的同学学习嵌入式、做项目、找工作! 四、NVIC &#xff08;1&#xff09;NVIC基本结构 外部中断的整体结构图如下&#xff1a; 这个NVI…

代码随想录算法训练营29期|day37 任务以及具体任务

第八章 贪心算法 part06 738.单调递增的数字 版本2 class Solution {public int monotoneIncreasingDigits(int n) {String s String.valueOf(n);char[] chars s.toCharArray();int start s.length();for (int i s.length() - 2; i > 0; i--) {if (chars[i] > chars…

利用ASM功能实现零停机oracle RAC存储迁移

在实际生产过程中&#xff0c;经常会遇到比如新旧存储替换等场景&#xff0c;如果是一般情况可能只有做数据迁移才能实现&#xff0c;而迁移可能就存在停机的可能 这里介绍利用ASM DG加盘踢盘功能实现零停机存储迁移&#xff1b;原理很简单 将新存储磁盘添加到data dg&#xf…

江科大stm32学习笔记9——OLED调试工具

一、OLED OLED&#xff1a;有机发光二极管&#xff0c;供电3~5.5V&#xff0c;0.96寸OLED通信协议&#xff1a;I2C/SPI&#xff0c;分辨率&#xff1a;128*64 二、调试方式 串口调试&#xff1a;通过串口通信&#xff0c;将调试信息发送到电脑端&#xff0c;电脑使用串口助手…

Mysql数据库锁--全局锁、表锁、行锁

Mysql数据库按照加锁范围划分 根据加锁的范围&#xff0c;MySQL 里面的锁大致可以分成全局锁、表级锁和行锁三类 全局锁 全局锁就是对整个数据库实例加锁。MySQL 提供了一个加全局读锁的方法&#xff0c;命令是 Flush tables with read lock (FTWRL)。当你需要让整个库处于只…

CTF盲水印工具:Blind-WaterMark安装

工具下载地址&#xff1a;GitCode - 开发者的代码家园 下载完毕后&#xff0c;只留这些东西就行 接下来需要安装两个依赖&#xff1a; opencv、matplotlib 直接pip install安装的话&#xff0c;工具使用会报错 所以需要到网站里挑选适合的版本进行安装 下载地址&#xff1…