二、JavaEE核心技术 - Servlet与JSP
一、Servlet
Servlet(服务器端小程序)是JavaEE中用于处理HTTP请求的核心组件。它是一个Java类,运行在Web服务器上,负责接收和响应HTTP请求。
1. Servlet的生命周期
Servlet的生命周期由以下几个阶段组成:
- 初始化阶段(Initialization):
- 触发: 当Servlet容器(如Tomcat)启动时,或者当第一次请求访问Servlet时,容器会创建Servlet的实例。
- 方法: 调用Servlet的
init()
方法。 - 作用: 初始化资源,读取配置参数,为后续的请求处理做准备。
- 服务阶段(Service):
- 触发: 当客户端发送HTTP请求,并且请求映射到该Servlet时。
- 方法: 调用Servlet的
service()
方法。 - 作用: 处理HTTP请求,根据请求类型(GET、POST等)调用相应的
doGet()
或doPost()
方法,生成响应。
- 销毁阶段(Destruction):
- 触发: 当Servlet容器关闭,或者Servlet被移除时。
- 方法: 调用Servlet的
destroy()
方法。 - 作用: 释放资源,关闭数据库连接,清理临时数据。
2. Servlet的配置
Servlet可以通过以下两种方式配置:
-
基于XML配置(web.xml):
-
在
web.xml
文件中,通过<servlet>
和<servlet-mapping>
元素配置Servlet。 -
示例:
xml<servlet> <servlet-name>MyServlet</servlet-name> <servlet-class>com.example.MyServlet</servlet-class> <init-param> <param-name> ParamName </param-name> <param-value> ParamValue </param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>MyServlet</servlet-name> <url-pattern>/myServlet</url-pattern> </servlet-mapping>
-
-
基于注解配置:
-
使用
@WebServlet
注解直接在Servlet类上配置。 -
示例:
java@WebServlet(name = "MyServlet", urlPatterns = "/myServlet") public class MyServlet extends HttpServlet { // Servlet实现 }
-
3. Servlet的基本实现
以下是一个基本的Servlet实现示例:
java
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class MyServlet extends HttpServlet {
@Override
public void init() throws ServletException {
// 初始化代码
System.out.println("Servlet initialized");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 处理GET请求
resp.setContentType("text/html");
resp.getWriter().println("<h1>Hello, World!</h1>");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 处理POST请求
String username = req.getParameter("username");
resp.setContentType("text/html");
resp.getWriter().println("<h1>Hello, " + username + "!</h1>");
}
@Override
public void destroy() {
// 销毁资源
System.out.println("Servlet destroyed");
}
}
二、JSP
JavaServer Pages(JSP)是一种动态网页技术,允许开发者在HTML页面中嵌入Java代码,以生成动态内容。
1. JSP的语法
JSP的语法包括以下几种元素:
-
表达式:
- 用于在页面中输出Java表达式的值。
- 语法:
<%= 表达式 %>
示例:
jsp<h2>当前时间:<%= new java.util.Date() %></h2>
-
指令:
- 用于提供指示,告诉JSP引擎如何处理页面。
- 常见指令:
<%@ page %>
、<%@ include %>
、<%@ taglib %>
。
示例:
jsp<%@ page language="java" contentType="text/html; charset=UTF-8" %>
-
动作标签:
- 用于在JSP页面中执行某些操作,如转发请求、包含其他页面等。
- 示例:
<jsp:forward>
、<jsp:include>
。
示例:
jsp<jsp:include page="header.jsp" />
-
声明:
- 用于在页面中定义Java代码块。
- 语法:
<% 声明 %>
。
示例:
jsp<%! private int counter = 0; %>
-
脚本лет:
- 用于在页面中嵌入Java代码。
- 语法:
<% 代码 %>
。
**示例:
<% for(int i=0; i<10; i++) { %> <p>Loop: <%= i %></p> <% } %>
2. 动态内容生成
JSP可以通过以下方式生成动态内容:
-
使用JavaBeans:
-
定义JavaBean:
javapublic class User { private String name; // Getters and setters }
-
在JSP中使用JavaBeans:
jsp<jsp:useBean id="user" class="com.example.User" scope="request"/> <jsp:getProperty name="user" property="name"/>
-
-
使用Expression Language (EL):
-
示例:
jsp<h2>Hello, ${user.name}</h2>
-
-
使用JSP Standard Tag Library (JSTL):
-
导入JSTL标签库:
jsp<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
-
使用JSTL标签:
jsp<c:forEach var="item" items="${items}"> <p>${item}</p> </c:forEach>
-
三、Servlet与JSP的联动开发
Servlet和JSP的结合是JavaEE Web开发的核心模式。Servlet负责处理业务逻辑,JSP负责生成视图。
1. 分离Concerns(关注点分离)
- Servlet: 处理业务逻辑,接收请求,调用模型(如JavaBeans)执行业务操作。
- JSP: 生成动态的HTML页面,展示数据。
2. 请求转发与共享数据
-
请求转发: 使用
RequestDispatcher
将请求从Servlet转发到JSP。javaRequestDispatcher dispatcher = req.getRequestDispatcher("result.jsp"); dispatcher.forward(req, resp);
-
共享数据: 将数据存储在
HttpServletRequest
对象中,供JSP访问。javareq.setAttribute("message", "Hello, JSP!");
在JSP中访问数据:
jsp<h2>${message}</h2>
3. 用户登录案例
以下是一个简单的用户登录案例,展示了Servlet与JSP的联动开发:
-
登录页面(login.jsp):
jsp<%@ page language="java" contentType="text/html; charset=UTF-8" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <html> <head> <title>用户登录</title> </head> <body> <h2>用户登录</h2> <form action="/loginServlet" method="post"> <p>用户名:<input type="text" name="username" /></p> <p>密码:<input type="password" name="password" /></p> <p><input type="submit" value="登录" /></p> </form> </body> </html>
-
登录处理Servlet(LoginServlet.java):
javaimport javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class LoginServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String username = req.getParameter("username"); String password = req.getParameter("password"); // 假设这是一个简单的验证逻辑 if (username.equals("admin") && password.equals("admin")) { req.setAttribute("message", "登录成功,欢迎您," + username + "!"); req.getRequestDispatcher("/welcome.jsp").forward(req, resp); } else { req.setAttribute("message", "用户名或密码错误!"); req.getRequestDispatcher("/login.jsp").forward(req, resp); } } }
-
欢迎页面(welcome.jsp):
jsp<%@ page language="java" contentType="text/html; charset=UTF-8" %> <html> <head> <title>欢迎页面</title> </head> <body> <h2>${message}</h2> <p><a href="/login.jsp">退出</a></p> </body> </html>
四、实践:用户登录与注册功能
在本节中,我们将通过一个完整的用户登录和注册功能来实践Servlet和JSP的联动开发。
1. 功能需求
- 用户登录:
- 用户输入用户名和密码,提交登录请求。
- 系统验证用户信息,成功则跳转到欢迎页面,失败则显示错误信息。
- 用户注册:
- 用户填写用户名、密码、邮箱等信息,提交注册请求。
- 系统验证用户输入,成功则跳转到登录页面,失败则显示错误信息。
2. 项目结构
以下是一个典型的JavaEE Web项目结构:
css
MyWebProject/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── example/
│ │ │ ├── controller/
│ │ │ │ ├── LoginServlet.java
│ │ │ │ └── RegisterServlet.java
│ │ │ └── model/
│ │ │ └── User.java
│ │ ├── resources/
│ │ │ └── META-INF/
│ │ │ └── persistence.xml
│ │ └── webapp/
│ │ ├── WEB-INF/
│ │ │ └── web.xml
│ │ ├── login.jsp
│ │ ├── register.jsp
│ │ └── welcome.jsp
├── pom.xml
└── README.md
3. 实现步骤
-
创建项目:
- 使用Eclipse或IntelliJ IDEA创建一个新的JavaEE Web项目。
- 配置项目结构,确保包含上述文件夹和文件。
-
设计数据库:
- 创建一个
users
表,包含id
、username
、password
和email
字段。 - 使用JDBC或JPA技术与数据库交互。
- 创建一个
-
实现JavaBeans:
-
创建User JavaBean,用于封装用户数据。
javapublic class User { private int id; private String username; private String password; private String email; // Getters and setters }
-
-
实现Servlet:
- LoginServlet: 处理登录请求,验证用户信息。
- RegisterServlet: 处理注册请求,保存用户信息到数据库。
-
实现JSP页面:
- login.jsp: 提供登录表单。
- register.jsp: 提供注册表单。
- welcome.jsp: 显示登录成功的欢迎信息。
-
配置安全性:
- 添加输入验证,防止SQL注入和XSS攻击。
- 使用HTTPS加密通信。
-
部署和测试:
- 将项目部署到Tomcat服务器。
- 测试登录和注册功能,确保所有场景都能正常处理。
4. 代码示例
以下是部分代码示例:
-
LoginServlet.java:
javaimport javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; public class LoginServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String username = req.getParameter("username"); String password = req.getParameter("password"); try { // 验证用户信息 if (isValidUser(username, password)) { req.getSession().setAttribute("user", username); req.getRequestDispatcher("/welcome.jsp").forward(req, resp); } else { req.setAttribute("error", "用户名或密码错误!"); req.getRequestDispatcher("/login.jsp").forward(req, resp); } } catch (Exception e) { // 处理异常 } } private boolean isValidUser(String username, String password) throws Exception { // 数据库验证逻辑 Connection conn = null; PreparedStatement stmt = null; ResultSet rs = null; try { conn = getConnection(); stmt = conn.prepareStatement("SELECT * FROM users WHERE username = ?"); stmt.setString(1, username); rs = stmt.executeQuery(); if (rs.next()) { return rs.getString("password").equals(password); } return false; } finally { closeResources(conn, stmt, rs); } } }
-
login.jsp:
jsp<%@ page language="java" contentType="text/html; charset=UTF-8" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <html> <head> <title>用户登录</title> </head> <body> <h2>用户登录</h2> <form action="${pageContext.request.contextPath}/loginServlet" method="post"> <p>用户名:<input type="text" name="username" /></p> <p>密码:<input type="password" name="password" /></p> <p><input type="submit" value="登录" /></p> </form> <c:if test="${error != null}"> <p style="color: red;">${error}</p> </c:if> </body> </html>
-
register.jsp:
jsp<%@ page language="java" contentType="text/html; charset=UTF-8" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <html> <head> <title>用户注册</title> </head> <body> <h2>用户注册</h2> <form action="${pageContext.request.contextPath}/registerServlet" method="post"> <p>用户名:<input type="text" name="username" /></p> <p>密码:<input type="password" name="password" /></p> <p>邮箱:<input type="email" name="email" /></p> <p><input type="submit" value="注册" /></p> </form> <c:if test="${error != null}"> <p style="color: red;">${error}</p> </c:if> </body> </html>
-
welcome.jsp:
jsp<%@ page language="java" contentType="text/html; charset=UTF-8" %> <html> <head> <title>欢迎页面</title> </head> <body> <h2>欢迎,${user}!</h2> <p><a href="${pageContext.request.contextPath}/login.jsp">退出</a></p> </body> </html>
5. 使用Expression Language (EL) 和 JSTL
-
Expression Language (EL): 用于在JSP中访问JavaBean的属性。
jsp<h2>${user.username}</h2>
-
JSTL: 用于在JSP中执行逻辑操作,如条件判断、循环等。
jsp<c:if test="${user.role == 'admin'}"> <p>您是管理员:</p> </c:if>
6. 依赖管理
在项目中,可以使用Maven或Gradle来管理依赖。以下是一个Maven pom.xml
文件的示例:
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.example</groupId>
<artifactId>mywebapp</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<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>jsp-api</artifactId>
<version>2.3.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.21</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.1</version>
<configuration>
<warSourceDirectory>src/main/webapp</warSourceDirectory>
</configuration>
</plugin>
</plugins>
</build>
</project>