? 本文為記錄Servlet學習時的一些筆記和代碼 課程參考黑馬程序員 對于Java Web 學習的一個復習
一 概述
server applet 運行在服務器端的小程序 本質就是一個接口 定義java類被瀏覽器訪問到(Tomcat識別)的規則
我們會自定義這樣一個類來實現復寫方法實現接口
二 快速入門
1 創建javaEE項目
2 定義一個類 實現servlet接口
3 實現接口的抽象方法
4 配置servlet
package com.ts.servletdem0.servlet;//import jakarta.servlet.*;
import jakarta.servlet.*;
import java.io.IOException;/*
* servlet的快速入門
* */
public class ServletDemo1 implements Servlet {@Overridepublic void init(ServletConfig servletConfig) throws ServletException {}@Overridepublic ServletConfig getServletConfig() {return null;}// 提供服務的方法@Overridepublic void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {System.out.println("Hello Servlet");}@Overridepublic String getServletInfo() {return null;}@Overridepublic void destroy() {}
}
?web配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"version="5.0">// 配置Servlet<servlet><servlet-name>demo1</servlet-name><servlet-class>com.ts.servletdem0.servlet.ServletDemo1</servlet-class></servlet><servlet-mapping><servlet-name>demo1</servlet-name><url-pattern>/demo1</url-pattern></servlet-mapping></web-app>
三 執行原理
1 當服務器接受到客戶端瀏覽器的請求后 會解析瀏覽器的URL路徑 獲取訪問的servlet資源
2 查找web.xml文件 是否有對應的<url-pattern>標簽體內容
3 如果有 則尋找對應的<servlet-class>全類名
4 tomcat會把字節碼文件加載進內存 并且創建對象
5 調用其方法
四 生命周期
?servlet的生命周期方法:
生命周期方法 | 觸發時機 | 執行次數 | 典型應用場景 |
---|---|---|---|
| 首次請求或服務器啟動時 | 1次 | 初始化數據庫連接、加載配置文件 |
| 每次HTTP請求 | 多次 | 核心業務邏輯處理 |
| 服務器正常關閉 | 1次 | 釋放資源、保存狀態 |
1.被創建:調用init方法 只執行一次
? ? 默認是第一次被訪問時創建
? ? 可以通過配置來決定執行的時機
<servlet><servlet-name>demo1</servlet-name><servlet-class>com.ts.servletdem0.servlet.ServletDemo1</servlet-class><!-- 初始化創建的時機 --><!-- 負數為第一次被訪問時創建 0或正整數是啟動服務器的時候創建--><load-on-startup>1</load-on-startup></servlet>
? ?[一個servlet在內存中只存在一個對象 是單例的]
? ?所以多個用戶訪問時會存在線程安全問題
? ?解決方法:在servlet中盡量不定義成員變量 即使定義也不要進行修改操作
2.提供服務:調用servlet方法 可以執行多次
3.被銷毀:執行destroy方法 只執行一次 (只有服務器正常關閉時才會執行)
/*
* servlet的方法
* */
public class ServletDemo2 implements Servlet {/** 初始化方法* 在servlet創建時執行 只會調用一次init方法* */@Overridepublic void init(ServletConfig servletConfig) throws ServletException {System.out.println("init...");}/** 獲取Servlet的配置對象* 返回ServletConfig對象* */@Overridepublic ServletConfig getServletConfig() {return null;}/* 提供服務的方法* 每一次servlet服務被請求時調用* */@Overridepublic void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {System.out.println("service...");}/** 獲取Servlet的信息* 返回一個字符串,用來描述Servlet* */@Overridepublic String getServletInfo() {return new String("ServletDemo2");}/** 銷毀方法* 在服務器關閉時執行一次 在servlet被銷毀時調用* */@Overridepublic void destroy() {System.out.println("destroy...");}
}
五 servlet配置?
? ?XML配置??:
<servlet-mapping><servlet-name>demo</servlet-name><!-- 支持多路徑映射 --><url-pattern>/api/*</url-pattern><url-pattern>.action</url-pattern>
</servlet-mapping>
? ?注解配置技巧??:
@WebServlet(name = "AdvancedServlet",urlPatterns = {"/v1/users", "/backup"},initParams = {@WebInitParam(name="timeout", value="5000")},loadOnStartup = 1
)
public class AdvancedServlet extends HttpServlet { ... }
? servlet_3.0 支持注解配置 使用@WebServlet("資源路徑”)
@WebServlet("/test")
public class TestServlet implements Servlet {@Overridepublic void init(ServletConfig servletConfig) throws ServletException {System.out.println("init");}@Overridepublic ServletConfig getServletConfig() {return null;}@Overridepublic void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {System.out.println("Servlet 3.0 啟動");}@Overridepublic String getServletInfo() {return null;}@Overridepublic void destroy() {}
}
servlet --> GenericServlet --> HttpServlet 抽象類? 對Http協議的一種封裝 簡化操作為繼承該類后 復寫doGet/doPost方法?
urlpartten: Servlet訪問路徑
(一個servlet可以配置多個訪問路徑)
@WebServlet({"/t4","/tt4","/ttt4"}) public class TestServlet1 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {System.out.println("Test_多路徑");}}
六 HTTP
概念:Htyper Text Transfer Protocol?傳輸協議 定義了客戶端和服務端通訊時 發送數據的格式
特點:1.基于TCP/IP的高級協議
? ? ? ? ? ?2.默認端口80
? ? ? ? ? ?3.基于請求/響應模型的:一次請求對應一次響應
? ? ? ? ? ?4.無狀態的:每次請求之間相互獨立 不能交互數據
請求方式:
常用的有兩種:
GET:1 請求參數在請求行中 在url后
? ? ? ? ? ?2 請求的url長度有限制
? ? ? ? ? ?3 不太安全
POST:1 請求參數在請求體中
? ? ? ? ? ?2 請求的url長度沒有限制的
? ? ? ? ? ?3 相對安全
請求消息數據格式:
請求報文結構??:
GET /test?name=value HTTP/1.1 ? ? ? ? ? → 請求行
Host: www.example.com ? ? ? ? ? ? ? ? ? ↗
Content-Type: text/html ? ? ? ? ? ? ? ?→ 請求頭
Accept-Language: zh-CN ? ? ? ? ? ? ? ? ↗
→ 空行
username=admin&password=123456 ? ? ? ?→ 請求體(僅POST)
? ? ? ?請求行? :請求方式 請求url 請求協議 版本
???????請求頭: 請求體名稱
???????請求空行:空行
???????請求體:正文
響應消息數據格式:
七 Request
// 獲取客戶端信息
String ip = request.getRemoteAddr();
String userAgent = request.getHeader("User-Agent");// 獲取請求參數
String username = request.getParameter("user");
String[] hobbies = request.getParameterValues("hobby");// 請求作用域傳值
request.setAttribute("currentUser", userObj);
User u = (User)request.getAttribute("currentUser");// 請求轉發
request.getRequestDispatcher("/success.jsp").forward(request, response);
八 案例
// File: src/main/java/com/example/web/UserServlet.java
package com.example.web;import jakarta.servlet.*;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.*;
import java.io.*;
import java.sql.*;@WebServlet("/user")
public class UserServlet extends HttpServlet {private static final String DB_URL = "jdbc:mysql://localhost:3306/userdb";private static final String DB_USER = "root";private static final String DB_PASS = "password";@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String action = request.getParameter("action");if ("register".equals(action)) {registerUser(request, response);} else if ("login".equals(action)) {loginUser(request, response);}}private void registerUser(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String username = request.getParameter("username");String password = request.getParameter("password");String email = request.getParameter("email");try (Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASS)) {String sql = "INSERT INTO users (username, password, email) VALUES (?, ?, ?)";try (PreparedStatement pstmt = conn.prepareStatement(sql)) {pstmt.setString(1, username);pstmt.setString(2, password);pstmt.setString(3, email);int rows = pstmt.executeUpdate();if (rows > 0) {request.setAttribute("message", "注冊成功!請登錄");request.getRequestDispatcher("/login.jsp").forward(request, response);} else {request.setAttribute("error", "注冊失敗");request.getRequestDispatcher("/register.jsp").forward(request, response);}}} catch (SQLException e) {throw new ServletException("數據庫錯誤: " + e.getMessage());}}private void loginUser(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String username = request.getParameter("username");String password = request.getParameter("password");try (Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASS)) {String sql = "SELECT * FROM users WHERE username = ? AND password = ?";try (PreparedStatement pstmt = conn.prepareStatement(sql)) {pstmt.setString(1, username);pstmt.setString(2, password);try (ResultSet rs = pstmt.executeQuery()) {if (rs.next()) {// 創建會話HttpSession session = request.getSession();session.setAttribute("username", username);session.setAttribute("email", rs.getString("email"));// 設置會話有效期30分鐘session.setMaxInactiveInterval(30 * 60);response.sendRedirect("profile.jsp");} else {request.setAttribute("error", "用戶名或密碼錯誤");request.getRequestDispatcher("/login.jsp").forward(request, response);}}}} catch (SQLException e) {throw new ServletException("數據庫錯誤: " + e.getMessage());}}@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 注銷處理String action = request.getParameter("action");if ("logout".equals(action)) {HttpSession session = request.getSession(false);if (session != null) {session.invalidate();}response.sendRedirect("login.jsp");}}
}
<!-- File: webapp/login.jsp -->
<!DOCTYPE html>
<html>
<head><title>用戶登錄</title><style>body { font-family: Arial, sans-serif; max-width: 400px; margin: 0 auto; padding: 20px; }.form-group { margin-bottom: 15px; }label { display: block; margin-bottom: 5px; }input[type="text"], input[type="password"] { width: 100%; padding: 8px; }button { padding: 10px 20px; background: #007bff; color: white; border: none; cursor: pointer; }.error { color: red; }</style>
</head>
<body><h2>用戶登錄</h2><% if (request.getAttribute("error") != null) { %><p class="error">${error}</p><% } %><form action="user" method="post"><input type="hidden" name="action" value="login"><div class="form-group"><label>用戶名:</label><input type="text" name="username" required></div><div class="form-group"><label>密碼:</label><input type="password" name="password" required></div><button type="submit">登錄</button></form><p>還沒有賬號? <a href="register.jsp">立即注冊</a></p>
</body>
</html>
<!-- File: webapp/register.jsp -->
<!DOCTYPE html>
<html>
<head><title>用戶注冊</title><style>body { font-family: Arial, sans-serif; max-width: 400px; margin: 0 auto; padding: 20px; }.form-group { margin-bottom: 15px; }label { display: block; margin-bottom: 5px; }input { width: 100%; padding: 8px; }button { padding: 10px 20px; background: #28a745; color: white; border: none; cursor: pointer; }.error { color: red; }</style>
</head>
<body><h2>用戶注冊</h2><% if (request.getAttribute("error") != null) { %><p class="error">${error}</p><% } %><form action="user" method="post"><input type="hidden" name="action" value="register"><div class="form-group"><label>用戶名:</label><input type="text" name="username" required></div><div class="form-group"><label>密碼:</label><input type="password" name="password" required></div><div class="form-group"><label>郵箱:</label><input type="email" name="email" required></div><button type="submit">注冊</button></form><p>已有賬號? <a href="login.jsp">立即登錄</a></p>
</body>
</html>
<!-- File: webapp/profile.jsp -->
<!DOCTYPE html>
<html>
<head><title>用戶資料</title><style>body { font-family: Arial, sans-serif; max-width: 500px; margin: 0 auto; padding: 20px; }.welcome { font-size: 1.2em; margin-bottom: 20px; }.info { background: #f8f9fa; padding: 15px; border-radius: 5px; }.logout { margin-top: 20px; }</style>
</head>
<body><div class="welcome"><h2>歡迎, ${username}!</h2></div><div class="info"><p><strong>用戶名:</strong> ${username}</p><p><strong>注冊郵箱:</strong> ${email}</p></div><div class="logout"><a href="user?action=logout">注銷登錄</a></div>
</body>
</html>
?數據庫
CREATE DATABASE userdb;
USE userdb;CREATE TABLE users (id INT AUTO_INCREMENT PRIMARY KEY,username VARCHAR(50) NOT NULL UNIQUE,password VARCHAR(100) NOT NULL,email VARCHAR(100) NOT NULL,created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
項目結構?
project-root/
├── src/
│ ? └── main/
│ ? ? ? ├── java/
│ ? ? ? │ ? └── com/
│ ? ? ? │ ? ? ? └── example/
│ ? ? ? │ ? ? ? ? ? └── web/
│ ? ? ? │ ? ? ? ? ? ? ? └── UserServlet.java
│ ? ? ? └── webapp/
│ ? ? ? ? ? ├── WEB-INF/
│ ? ? ? ? ? │ ? └── web.xml
│ ? ? ? ? ? ├── login.jsp
│ ? ? ? ? ? ├── register.jsp
│ ? ? ? ? ? ├── profile.jsp
│ ? ? ? ? ? └── index.html
└── pom.xml
學習時間? 2025.05.01