Spring 整合 web

学习自用


前言

Spring 容器在整个项目应该只有一个,且是共享的

JavaWeb 四大域:page(当前页面有效) -> request(HttpServletRequest,当前请求的全过程有效)-> session(HttpSession,会话期间有效,即页面不关闭)-> application(HttpContext,项目不关闭全局有效)(从低到高

因为是共享的,所以 Spring 容器应该保存在 application 域上


监听器

JavaWeb 三剑客之一(servlet、过滤器、监听器

监听 Tomcat 的启动,用于在 Tomcat 启动之后将 Spring 容器创建,并保存在 application 域上

步骤

1)依赖

必须具备 spring-web 项目,也可以直接导入 spring-webmvc,其包含了 spring 所具备的依赖

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.1</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>jsp-api</artifactId>
        <version>2.1</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

2)创建 Spring 容器

纯注解方式,提供一个配置类

@Configuration
@ComponentScan("com.fs")
public class AppConfig {
}

在 webapp 下的 web.xml 中配置监听器,监听 Tomcat 的启动

<?xml version="1.0" encoding="UTF-8"?>
<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/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <!-- 监听器 -->
    <listener>
        <!-- 监听器的全限定类名 -->
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!-- 全局初始化参数 -->
    <context-param>
      	<!-- 二选一 -->
      
        <!-- 配置类的方式 -->
        <param-name>contextClass</param-name>
        <param-value>com.fs.config.AppConfig</param-value>

        <!-- 配置文件方式 -->
     	  <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>
</web-app>

此时 Spring 容器已经创建好
image.png

ContextLoaderListener 监听器作用:
  在 web 容器(如 Tomcat 启动)时,自动装配 Spring 的配置文件(applicationContext.xml)或配置类信息

  由上图可知 ContextLoaderListener 继承了 ContextLoader 类,并且实现了 ServletContextListener 类。ServletContext 是被Servlet 程序用来与 Web 容器进行通信的,为应用上下文对象,每一个 Web 都只有一个 ServletContext,用来保存资源以及供 Web 内各个应用(Servlet)共享资源。Web 应用一加载则 ServletContext 创建,应用被停止则 ServletContext 销毁

  ServletContextListener 作为 ServletContext 的监听者,主要是监听 ServletContext 数据的变化,包含以下两个方法:

  • contextInitialized(ServletContextEvent sce)
  • contextDestroyed(ServletContextEvent sce)

  Web 容器启动时,ServletContextListener 的 contextInitialized()方法被调用,在此方法里面创建好缓存。调用完该方法之后,容器再对Filter 初始化,并且对那些在Web 应用启动时就需要被初始化的Servlet 进行初始化

  Web 容器将要关闭时,ServletContextListener 的 contextDestroyed()方法被调用,在此方法里面保存缓存的更改。调用该方法之前,容器会先销毁所有的Servlet 和Filter 过滤器

  而 ContextLoaderListener 实现了 ServletContextListener 接口,也就重写了上面两个方法,所以在 web.xml 文件中配置这个监听器之后,Web容器启动时,就会默认执行 ContextLoaderListener 重写的方法,自动装配配置信息。


编写一个 Servlet

@WebServlet("/testServlet")
public class TestServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("hello");
    }
}

问题1

如果是纯注解方式开发,即使用配置类替代配置文件时,启动项目会报错

image.png
原因 :即在Web项目中,Spring 使用纯注解开发方式默认不兼容

解决一 :使用 SpringBoot 框架(暂时不说

解决二 :使用配置文件的开发方式,删除配置类

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

    <context:component-scan base-package="com.fs"/>
</beans>

问题2

此时如果想要获取 Spring Bean,会报错

@WebServlet("/testServlet")
public class TestServlet extends HttpServlet {
    // 获取 Spring 容器中的 userService 对象
    @Autowired
    private UserService userService;
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        userService.addUser();
    }
}

在这里插入图片描述

原因
  众所周知,一个对象想要获取到受 Spring 容器管理的 Bean 对象,这个对象本身也需要注入到 Spring 容器中。此处的 TestServlet 并未注入到容器中,所以无法获取 userService 实例,抛出空指针异常

那么使用 @Controller 注解将这个 Servlet 类进行注入会成功吗?

@WebServlet("/testServlet")
// 注入到容器中
@Controller
public class TestServlet extends HttpServlet {
    @Autowired
    private UserService userService;
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        userService.addUser();
    }
}

同样也会报错,仍然无法获取 userService 实例
在这里插入图片描述

原因
  使用 @Controller 注解将该 Servlet 对象注入到 Spring IOC 容器 中,即 Spring 容器中存在一个 servlet 对象,此对象可以获取其他的 Spring Bean 对象。

  而当我们在浏览器上第一次访问一个Servlet时,会在 Web 容器(如 Tomcat 容器)中创建该 servlet 的对象,这个 servlet 对象是无法获取 Spring 容器中的 Bean 对象的。

  简而言之,此时的 TestServlet 存在两个对象,分别在 Spring 容器和 Tomcat 容器上
而我们在浏览器上进行访问的是 Tomcat 容器上的 servlet 对象,所以这里无法获取 userService 对象,报空指针异常

解决

不将 Servlet 注入到 Spring 容器中,而是直接从 Spring 容器中手动获取 Bean 对象

  从 ServletContext (application域)中获取 Spring 容器,再从容器中获取 Spring bean

@WebServlet("/testServlet")
public class TestServlet extends HttpServlet {
    private UserService userService;
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // ServletContext(Application域)
        ServletContext application = this.getServletContext();
        // 获取 Spring 容器
        ApplicationContext applicationContext = (ApplicationContext) application.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
        userService = applicationContext.getBean(UserService.class);
        userService.addUser();
    }
}

  也可以使用 spring-web 包下的 WebApplicationContextUtils 工具类获取 Spring 容器

@WebServlet("/testServlet")
public class TestServlet extends HttpServlet {
    private UserService userService;
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
        userService = webApplicationContext.getBean(UserService.class);
        userService.addUser();
    }
}

至此
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring框架提供了多种方式来整合Web开发。以下是一种常见的方式: 1. 添加依赖:在你的项目中,添加Spring Web的依赖。你可以使用Maven或Gradle来管理依赖。 Maven: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> ``` Gradle: ```groovy implementation 'org.springframework.boot:spring-boot-starter-web' ``` 2. 创建控制器:创建一个控制器类来处理请求和响应。在这个类上使用`@Controller`注解,并在方法上使用`@RequestMapping`注解来映射URL和处理方法。 ```java @Controller public class MyController { @RequestMapping("/hello") public String hello() { return "Hello, World!"; } } ``` 3. 配置Spring MVC:创建一个配置类,使用`@Configuration`注解,并继承`WebMvcConfigurerAdapter`类。在这个类中,可以配置视图解析器、静态资源处理等。 ```java @Configuration public class WebConfig extends WebMvcConfigurerAdapter { @Override public void configureViewResolvers(ViewResolverRegistry registry) { registry.jsp("/WEB-INF/views/", ".jsp"); } @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/static/**").addResourceLocations("/static/"); } } ``` 4. 启动应用程序:使用Spring Boot或其他方式启动你的应用程序,Spring会自动扫描并注册控制器。 这只是一个简单的示例,你可以根据你的需求进行更多的配置和定制。希望对你有所帮助!如果还有其他问题,请继续提问。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值