1. 程式人生 > 實用技巧 >Spring與Web

Spring與Web

目錄


在 Web 專案中使用 Spring 框架,首先要解決在 web 層(這裡指 Servlet)中獲取到 Spring容器的問題。只要在 web 層獲取到了 Spring 容器,便可從容器中獲取到 Service 物件

一、Web專案中使用Spring

1. 新建一個Maven專案

此時選擇的就是maven-archetype-webapp

2. 使用之前的案例

還是使用Spring整合MyBatis那個案例的程式碼,目錄如下

  1. service層、Dao層,domain全部程式碼複製
  2. 配置檔案applicationContext.xml、jdbc.properties,mybatis.xml,複製
  3. pom.xml、主要新增加入servlet,jsp依賴

這裡還是直接把整個的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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.md</groupId>
  <artifactId>10-spring-web</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

  <dependencies>

    <!-- 單元測試-->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>

    <!--spring核心-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>

    <!--spring事務用到的-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>


    <!--mybatis的-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.1</version>
    </dependency>

    <!--mybatis和spring整合的-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>1.3.1</version>
    </dependency>

    <!--mysql驅動-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.9</version>
    </dependency>


    <!--德魯伊,資料庫連線池-->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.12</version>
    </dependency>

    <!-- servlet依賴 -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <scope>provided</scope>
    </dependency>
    <!-- jsp依賴 -->
    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.2.1-b03</version>
      <scope>provided</scope>
    </dependency>


    <!--為了使用監聽器物件,加入依賴-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>


  </dependencies>

  <build>

    <!--目的是把src/main/java目錄中的xml檔案包含到輸出結果中,也就是輸出到classes目錄中-->
    <resources>
      <resource>
        <directory>src/main/java</directory><!--所在的目錄-->
        <includes><!--包括目錄下的.properties,.xml 檔案都會掃描到-->
          <include>**/*.properties</include>
          <include>**/*.xml</include>
        </includes>
        <filtering>false</filtering>
      </resource>
    </resources>



  </build>

</project>

3. 定義index頁面

<%--
  Created by IntelliJ IDEA.
  User: MD
  Date: 2020/8/11
  Time: 15:12
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <p>學生註冊</p>
    <form action="reg" method="post">
        <table>
            <tr>
                <td>id</td>
                <td><input type="text" name="id"></td>
            </tr>

            <tr>
                <td>姓名:</td>
                <td><input type="text" name="name"></td>
            </tr>
            <tr>
                <td>email:</td>
                <td><input type="text" name="email"></td>
            </tr>
            <tr>
                <td>年齡</td>
                <td><input type="text" name="age"></td>
            </tr>

            <tr>
                <td></td>
                <td><input type="submit" value="註冊"></td>
            </tr>
        </table>


    </form>
</body>
</html>

4. 定義RegisterServlet

在com.md下新建一個包controller,在下面建立RegisterServlet,繼承HttpServlet

package com.md.controller;

import com.md.domain.Student;
import com.md.service.StudentService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author MD
 * @create 2020-08-11 15:22
 */
public class RegisterServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");

        String strId = request.getParameter("id");
        String strName = request.getParameter("name");
        String strEmail = request.getParameter("email");
        String strAge = request.getParameter("age");

        // 建立spring的容器物件
        String config = "spring.xml";
        ApplicationContext c = new ClassPathXmlApplicationContext(config);

        // 獲取service
        StudentService studentService = (StudentService) c.getBean("studentService");
        studentService.addStudent(new Student(Integer.parseInt(strId),
                                strName,strEmail,Integer.parseInt(strAge)));


        // 跳的另一個頁面
        request.getRequestDispatcher("/result.jsp").forward(request,response);

    }
}

5. 定義result頁面

<%--
  Created by IntelliJ IDEA.
  User: MD
  Date: 2020/8/11
  Time: 15:30
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

註冊成功

</body>
</html>

6. web.xml 註冊 Servlet

<?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">

    <!--
	version="4.0"
	如果新建的這個版本低,不是4.0的,可以找之前寫的專案,把上面的資訊貼上過來就行
	-->

    <servlet>
        <servlet-name>RegisterServlet</servlet-name>
        <servlet-class>com.md.controller.RegisterServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>RegisterServlet</servlet-name>
        <url-pattern>/reg</url-pattern>
    </servlet-mapping>
    
</web-app>

此時和java web類似,配置Tomcat,啟動,然後執行

7. 執行結果分析

當表單提交,跳轉到 result.jsp 後,多重新整理幾次頁面,檢視後臺輸出,發現每重新整理一次頁面,就 new 出一個新的 Spring 容器。即,每提交一次請求,就會建立一個新的 Spring 容器

對於一個應用來說,只需要一個 Spring 容器即可。所以,將 Spring 容器的建立語句放在 Servlet 的 doGet()或 doPost()方法中是有問題的,需要改進

二、 使用 Spring 的器監聽器 ContextLoaderListener

對於 Web 應用來說,ServletContext 物件是唯一的,一個 Web 應用,只有一個ServletContext 物件,該物件是在 Web 應用裝載時初始化的。

若將 Spring 容器的建立時機,放在 ServletContext 初始化時,就可以保證 Spring 容器的建立只會執行一次,也就保證了Spring 容器在整個應用中的唯一性

當 Spring 容器建立好後,在整個應用的生命週期過程中,Spring 容器應該是隨時可以被訪問的。即,Spring 容器應具有全域性性。而放入 ServletContext 物件的屬性,就具有應用的全域性性。所以,將建立好的 Spring 容器,以屬性的形式放入到 ServletContext 的空間中,就保證了 Spring 容器的全域性性

上述的這些工作,已經被封裝在瞭如下的 Spring 的 Jar 包的相關 API 中:spring-web-5.2.5.RELEASE

1. maven依賴pom.xml

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

2. 註冊監聽器 ContextLoaderListener

若 要 在 ServletContext 初 始 化 時 創 建 Spring 容 器 , 就 需 要 使 用 監 聽 器 接 口ServletContextListener 對 ServletContext 進行監聽。在 web.xml 中註冊該監聽器

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

3. 指定 Spring 配置檔案的位置

<context-param>

ContextLoaderListener 在對 Spring 容器進行建立時,需要載入 Spring 配置檔案。其預設的 Spring 配置檔案位置與名稱為:WEB-INF/applicationContext.xml。

但一般會將該配置檔案放置於專案的 classpath 下,即 src 下,所以需要在 web.xml 中對 Spring 配置檔案的位置及名稱進行指定

此時為了和預設的不同,把applicationContext.xml重新命名為spring.xml檔案

<context-param>
        <!--  contextConfigLocation:表示配置檔案的路徑 -->
        <param-name>contextConfigLocation</param-name>
        <!--自定義配置檔案的路徑-->
        <param-value>classpath:spring.xml</param-value>
    </context-param>

此時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">


    <!--如果新建的這個版本低,可以找之前寫的專案,把上面的資訊貼上過來就行-->


    <servlet>
        <servlet-name>RegisterServlet</servlet-name>
        <servlet-class>com.md.controller.RegisterServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>RegisterServlet</servlet-name>
        <url-pattern>/reg</url-pattern>
    </servlet-mapping>
    
    
    <!-- 註冊監聽器
        監聽器被建立後或讀取這個/WEB-INF/applicationContext.xml這個檔案
        為什麼要讀取檔案:
            因為監聽器中要建立ApplicationContext物件,需要載入配置檔案
            /WEB-INF/applicationContext.xml就是監聽器預設讀取的spring配置檔案路徑

        可以修改預設的檔案位置

        配置監聽器:目的是建立容器物件,建立了容器物件,就能把spring.xml配置檔案中的所有物件建立好
        使用者發起請求就可以直接使用物件了

        重點:下面的這段程式碼和如何獲取物件
    -->


    <context-param>
        <!--  contextConfigLocation:表示配置檔案的路徑 -->
        <param-name>contextConfigLocation</param-name>
        <!--自定義配置檔案的路徑-->
        <param-value>classpath:spring.xml</param-value>
    </context-param>

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

此時的目錄結構

4. 獲取Spring容器物件

1. 直接從 ServletContext 中獲取

        WebApplicationContext c = null;
        // 獲取ServletContext中的容器物件,建立好的容器物件
        String key = WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE;
        Object attr = getServletContext().getAttribute(key);
        if (attr != null){
            c = (WebApplicationContext) attr;
        }

2. 通過 WebApplicationContextUtils 獲取

// 使用框架中的方法獲取容器物件
        WebApplicationContext c = null;
        ServletContext sc = getServletContext();
        c = WebApplicationContextUtils.getRequiredWebApplicationContext(sc);

        System.out.println("容器物件的資訊--------"+c);

以上兩種方式,無論使用哪種獲取容器物件,重新整理 result頁面後,可看到程式碼中使用的 Spring 容器均為同一個物件

此時RegisterServlet的全部程式碼

package com.md.controller;

import com.md.domain.Student;
import com.md.service.StudentService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author MD
 * @create 2020-08-11 15:22
 */
public class RegisterServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");

        String strId = request.getParameter("id");
        String strName = request.getParameter("name");
        String strEmail = request.getParameter("email");
        String strAge = request.getParameter("age");

        // 建立spring的容器物件
        //String config = "spring.xml";
        //ApplicationContext c = new ClassPathXmlApplicationContext(config);


        // 配置完成之後可以直接這麼使用


//        WebApplicationContext c = null;
//        // 獲取ServletContext中的容器物件,建立好的容器物件
//        String key = WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE;
//        Object attr = getServletContext().getAttribute(key);
//        if (attr != null){
//            c = (WebApplicationContext) attr;
//        }


        // 使用框架中的方法獲取容器物件,推薦
        WebApplicationContext c = null;
        ServletContext sc = getServletContext();
        c = WebApplicationContextUtils.getRequiredWebApplicationContext(sc);
        
        // 直接縮短為一行
 //WebApplicationContext c = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
        System.out.println("容器物件的資訊--------"+c);




        // 獲取service
        StudentService studentService = (StudentService) c.getBean("studentService");
        studentService.addStudent(new Student(Integer.parseInt(strId),
                                strName,strEmail,Integer.parseInt(strAge)));


        // 跳的另一個頁面
        request.getRequestDispatcher("/result.jsp").forward(request,response);

    }
}