SpringMVC 第八章 Spring 与 Web 环境集成


SpringMVC —— 第八章 Spring 与 Web 环境集成


1. 基本三层架构环境的搭建

  1. 创建一个 JavaEE 工程,选择模板为 Web 应用程序,并选用 Tomcat 作为服务器

    NewProject
  2. pom.xml 中导入需要用到的依赖包的坐标

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.gregperlinli</groupId>
        <artifactId>spring_mvc</artifactId>
        <version>1.0-SNAPSHOT</version>
        <name>spring_mvc</name>
        <packaging>war</packaging>
    
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <maven.compiler.target>1.8</maven.compiler.target>
            <maven.compiler.source>1.8</maven.compiler.source>
            <junit.version>5.7.1</junit.version>
        </properties>
    
        <dependencies>
            <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>javax.servlet.jsp-api</artifactId>
                <version>2.3.3</version>
            </dependency>
            <dependency>
                <groupId>org.junit.jupiter</groupId>
                <artifactId>junit-jupiter-api</artifactId>
                <version>$&#123;junit.version&#125;</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.junit.jupiter</groupId>
                <artifactId>junit-jupiter-engine</artifactId>
                <version>$&#123;junit.version&#125;</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>5.3.8</version>
            </dependency>
            <dependency>
                <groupId>javax.annotation</groupId>
                <artifactId>javax.annotation-api</artifactId>
                <version>1.3.2</version>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.20</version>
            </dependency>
            <dependency>
                <groupId>c3p0</groupId>
                <artifactId>c3p0</artifactId>
                <version>0.9.1.2</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-test</artifactId>
                <version>5.3.8</version>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-war-plugin</artifactId>
                    <version>3.3.1</version>
                </plugin>
            </plugins>
        </build>
    </project>
    
  3. 配置 JDBC 和数据源(连接池)

    jdbc.properties

    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/test
    jdbc.username=root
    jdbc.password=root
    

    com.yourname.config.DataSourceConfiguration

    import com.mchange.v2.c3p0.ComboPooledDataSource;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.PropertySource;
    import javax.sql.DataSource;
    
    @PropertySource("classpath:jdbc.properties") 
    public class DataSourceConfiguration &#123;
        @Value("$&#123;jdbc.driver&#125;")
        private String driver;
        @Value("$&#123;jdbc.url&#125;")
        private String url;
        @Value("$&#123;jdbc.username&#125;")
        private String username;
        @Value("$&#123;jdbc.password&#125;")
        private String password;
    
        @Bean("dataSource")
        public DataSource getDataSource() throws Exception &#123;
            ComboPooledDataSource dataSource = new ComboPooledDataSource();
            dataSource.setDriverClass(driver);
            dataSource.setJdbcUrl(url);
            dataSource.setUser(username);
            dataSource.setPassword(password);
            return dataSource;
        &#125;
    &#125;
    
  4. 配置 Spring 容器

    com.yourname.config.SpringConfiguration

    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Import;
    
    @Configuration
    @ComponentScan("com.gregperlinli")
    @Import(&#123;DataSourceConfiguration.class&#125;)
    public class SpringConfiguration &#123;
      
    &#125;
    
  5. 编写 Dao 层

    com.yourname.dao.UserDao

    public interface UserDao &#123;
        public void save();
    &#125;
    

    com.yourname.dao.impl.UserDaoImpl

    import com.gregperlinli.dao.UserDao;
    import org.springframework.stereotype.Repository;
    
    @Repository("userDao")
    public class UserDaoImpl implements UserDao &#123;
        @Override
        public void save() &#123;
            System.out.println("Save running ...");
        &#125;
    &#125;
    
  6. 编写 Service 层

    com.yourname.service.UserService

    public interface UserService &#123;
        public void save();
    &#125;
    

    com.yourname.service.impl.UserServiceImpl

    import com.gregperlinli.dao.UserDao;
    import com.gregperlinli.service.UserService;
    import org.springframework.stereotype.Service;
    import javax.annotation.Resource;
    
    @Service("userService")
    public class UserServiceImpl implements UserService &#123;
        @Resource(name = "userDao")
        private UserDao userDao;
    
        @Override
        public void save() &#123;
            userDao.save();
        &#125;
    &#125;
    
  7. 编写 Web 层

    com.yourname.web.UserServlet

    import com.gregperlinli.config.SpringConfiguration;
    import com.gregperlinli.service.UserService;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    @WebServlet(name = "UserServlet", value = "/userServlet")
    public class UserServlet extends HttpServlet &#123;
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException &#123;
            AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(SpringConfiguration.class);
            UserService userService = app.getBean(UserService.class);
            userService.save();
        &#125;
    &#125;
    

2. ApplicationContext 应用上下文获取方式

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

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

示例代码:

com.yourname.listener.ContextLoaderListener

import com.gregperlinli.config.SpringConfiguration;
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 &#123;
    @Override
    public void contextInitialized(ServletContextEvent sce) &#123;
        AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(SpringConfiguration.class);
        // Store the Spring application context object in the ServletContext domain
        ServletContext servletContext = sce.getServletContext();
        servletContext.setAttribute("app", app);
        System.out.println("Spring container created");
    &#125;
    @Override
    public void contextDestroyed(ServletContextEvent sce) &#123;
    &#125;
&#125;

com.yourname.utils.WebApplicationContextUtils

import org.springframework.context.ApplicationContext;
import javax.servlet.ServletContext;

public class WebApplicationContextUtils &#123;
    public static ApplicationContext getWebApplicationContext(ServletContext servletContext) &#123;
        return (ApplicationContext) servletContext.getAttribute("app");
    &#125;
&#125;

com.yourname.web.userServlet

import com.gregperlinli.service.UserService;
import com.gregperlinli.utils.WebApplicationContextUtils;
import org.springframework.context.ApplicationContext;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(name = "UserServlet", value = "/userServlet")
public class UserServlet extends HttpServlet &#123;
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException &#123;
        ServletContext servletContext = this.getServletContext();
        ApplicationContext app = WebApplicationContextUtils.getWebApplicationContext(servletContext);
        UserService userService = app.getBean(UserService.class);
        userService.save();
    &#125;
&#125;

3. Spring 提供获取应用上下文的工具

Spring 提供了要一个监听器 ContextLoaderListener 就是对上述功能的封装,该监听器内部加载 Spring 配置文件,创建应用上下文对象,并存储到 ServletContext 域中,提供了一个客户端工具 WebApplicationContextUtils 供使用者获得应用上下文对象。

我们只需要做两件事情

  1. 配置 ContextLoaderListener 监听器(需导入 spring-web 坐标)

  2. 使用 WebApplicationContextUtils 获得应用上下文对象 ApplicationContext

示例代码:

pom.xml

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>5.2.7.RELEASE</version>
</dependency>

web.xml

<?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">
  
      <!-- Global initialization parameters -->
      <context-param>
          <param-name>contetConfiguration</param-name>
          <param-value>classpath:applicationContext.xml</param-value>
      </context-param>
  
      <!-- Configure listeners -->
      <listener>
              <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
      </listener>
</web-app>

com.yourname.web.userServlet

import com.gregperlinli.service.UserService;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.context.ApplicationContext;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(name = "UserServlet", value = "/userServlet")
public class UserServlet extends HttpServlet &#123;
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException &#123;
        ServletContext servletContext = this.getServletContext();
        ApplicationContext app = WebApplicationContextUtils.getWebApplicationContext(servletContext);
        UserService userService = app.getBean(UserService.class);
        userService.save();
    &#125;
&#125;


文章作者: gregPerlinLi
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 gregPerlinLi !
  目录