Spring與Web
目錄
在 Web 專案中使用 Spring 框架,首先要解決在 web 層(這裡指 Servlet)中獲取到 Spring容器的問題。只要在 web 層獲取到了 Spring 容器,便可從容器中獲取到 Service 物件
一、Web專案中使用Spring
1. 新建一個Maven專案
此時選擇的就是maven-archetype-webapp
2. 使用之前的案例
還是使用Spring整合MyBatis那個案例的程式碼,目錄如下
- service層、Dao層,domain全部程式碼複製
- 配置檔案applicationContext.xml、jdbc.properties,mybatis.xml,複製
- 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);
}
}