第十章:Java Web开发入门(上)
在前面的章节中,我们已经学习了Java的基础知识、面向对象编程、高级特性、文件IO、多线程、网络编程和数据库操作。现在,我们将进入Java应用的一个重要领域:Web开发。本章将介绍Java Web开发的基础知识,帮助你理解Web应用的工作原理并开始构建自己的Web应用。
1. Web开发概述
1.1 什么是Web应用
Web应用是一种可以通过Web浏览器访问的应用程序。与传统的桌面应用不同,Web应用不需要安装在用户的计算机上,用户只需要一个浏览器就可以使用它。
想象一下,你使用的网上购物平台(如淘宝、京东)、社交媒体(如微博、微信网页版)、在线银行等,这些都是Web应用的例子。
1.2 Web应用的工作原理
Web应用的工作原理基于客户端-服务器模型:
- 客户端:通常是Web浏览器(如Chrome、Firefox、Safari等)
- 服务器:运行Web应用的计算机,处理客户端的请求并返回响应
基本工作流程如下:
- 用户在浏览器中输入网址(URL)或点击链接
- 浏览器向服务器发送HTTP请求
- 服务器处理请求(可能涉及数据库操作、业务逻辑处理等)
- 服务器返回HTTP响应(通常包含HTML、CSS、JavaScript等)
- 浏览器解析响应并渲染页面
- 用户与页面交互,可能触发新的请求
这就像你去餐厅点餐:
- 你(客户端)向服务员(服务器)点餐(发送请求)
- 服务员将订单传递给厨房处理(服务器处理请求)
- 厨房准备好食物后,服务员将食物送到你的桌子(服务器返回响应)
- 你享用食物(浏览器渲染页面)
1.3 Web开发的核心技术
前端技术(客户端)
- HTML:定义网页的结构和内容
- CSS:控制网页的样式和布局
- JavaScript:实现网页的交互功能
后端技术(服务器端)
- 服务器:如Tomcat、Jetty、Undertow等
- Java Web技术:Servlet、JSP、Spring MVC、Spring Boot等
- 数据库:MySQL、Oracle、PostgreSQL等
1.4 Java Web开发的优势
- 跨平台:Java的"一次编写,到处运行"特性使得Web应用可以在不同的操作系统上运行
- 安全性:Java提供了强大的安全机制
- 丰富的生态系统:大量的框架和库可供选择
- 企业级支持:适合开发大型、复杂的企业级应用
- 成熟的社区:大量的开发者和资源
2. Servlet基础
2.1 什么是Servlet
Servlet是Java Web开发的核心技术,它是运行在Web服务器上的Java程序,用于处理客户端的请求并生成响应。
简单来说,Servlet就像是餐厅里的服务员,负责接收客户的点餐(请求),将订单传递给厨房(业务逻辑),然后将准备好的食物(响应)送回给客户。
2.2 Servlet的生命周期
Servlet的生命周期包括以下阶段:
- 加载和实例化:服务器启动时或首次请求时,Servlet容器创建Servlet的实例
- 初始化:调用
init()
方法,进行必要的初始化工作 - 服务:调用
service()
方法处理客户端请求 - 销毁:调用
destroy()
方法释放资源,通常在服务器关闭时
这就像餐厅服务员的一天:上班前准备工作(初始化),接待客人(服务),下班后整理(销毁)。
2.3 创建第一个Servlet
要创建一个Servlet,我们需要:
- 创建一个Java类,继承
HttpServlet
类 - 重写
doGet()
和/或doPost()
方法 - 在web.xml中配置Servlet或使用注解配置
下面是一个简单的Servlet示例:
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("<!DOCTYPE html>");
out.println("<html>");
out.println("<head>");
out.println("<title>Hello Servlet</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>你好,这是我的第一个Servlet!</h1>");
out.println("</body>");
out.println("</html>");
}
}
2.4 Servlet的请求和响应
HttpServletRequest
HttpServletRequest
对象表示客户端的请求,通过它可以获取:
- 请求参数(如表单数据)
- 请求头信息
- Cookie
- Session信息
- 请求路径等
// 获取请求参数
String username = request.getParameter("username");
// 获取所有参数名
Enumeration<String> paramNames = request.getParameterNames();
// 获取请求头
String userAgent = request.getHeader("User-Agent");
// 获取Session
HttpSession session = request.getSession();
HttpServletResponse
HttpServletResponse
对象表示服务器的响应,通过它可以:
- 设置响应内容类型
- 设置响应头信息
- 设置Cookie
- 发送重定向
- 输出响应内容等
// 设置内容类型
response.setContentType("text/html;charset=UTF-8");
// 设置响应头
response.setHeader("Cache-Control", "no-cache");
// 设置Cookie
Cookie cookie = new Cookie("username", "john");
cookie.setMaxAge(3600); // 1小时
response.addCookie(cookie);
// 重定向
response.sendRedirect("/welcome.jsp");
// 输出内容
PrintWriter out = response.getWriter();
out.println("Hello, World!");
2.5 Servlet的配置
有两种方式配置Servlet:
使用注解(推荐,Java EE 6及以上)
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
// Servlet代码
}
使用web.xml配置
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>com.example.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
2.6 Servlet的应用场景
Servlet适用于各种Web应用场景,例如:
- 处理表单提交
- 实现RESTful API
- 文件上传和下载
- 会话管理
- 权限控制等
2.7 实战:简单的用户登录Servlet
下面是一个简单的用户登录Servlet示例:
import java.io.IOException;
import java.io.PrintWriter;
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 javax.servlet.http.HttpSession;
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
// 模拟用户数据库
private static final String VALID_USERNAME = "admin";
private static final String VALID_PASSWORD = "password";
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 显示登录表单
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("<!DOCTYPE html>");
out.println("<html>");
out.println("<head>");
out.println("<title>登录页面</title>");
out.println("</head>");
out.println("<body>");
out.println("<h2>用户登录</h2>");
out.println("<form method='post' action='login'>");
out.println("用户名: <input type='text' name='username'><br>");
out.println("密码: <input type='password' name='password'><br>");
out.println("<input type='submit' value='登录'>");
out.println("</form>");
out.println("</body>");
out.println("</html>");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 处理登录请求
String username = request.getParameter("username");
String password = request.getParameter("password");
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
// 验证用户名和密码
if (VALID_USERNAME.equals(username) && VALID_PASSWORD.equals(password)) {
// 登录成功,创建会话
HttpSession session = request.getSession();
session.setAttribute("username", username);
out.println("<!DOCTYPE html>");
out.println("<html>");
out.println("<head>");
out.println("<title>登录成功</title>");
out.println("</head>");
out.println("<body>");
out.println("<h2>登录成功!</h2>");
out.println("<p>欢迎, " + username + "!</p>");
out.println("<a href='logout'>退出登录</a>");
out.println("</body>");
out.println("</html>");
} else {
// 登录失败
out.println("<!DOCTYPE html>");
out.println("<html>");
out.println("<head>");
out.println("<title>登录失败</title>");
out.println("</head>");
out.println("<body>");
out.println("<h2>登录失败!</h2>");
out.println("<p>用户名或密码错误。</p>");
out.println("<a href='login'>返回登录页面</a>");
out.println("</body>");
out.println("</html>");
}
}
}
配套的登出Servlet:
import java.io.IOException;
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 javax.servlet.http.HttpSession;
@WebServlet("/logout")
public class LogoutServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 获取会话并使其无效(登出)
HttpSession session = request.getSession(false);
if (session != null) {
session.invalidate();
}
// 重定向到登录页面
response.sendRedirect("login");
}
}
在上一部分中,我们学习了Web开发的基本概念和Servlet技术。本部分将介绍JSP(JavaServer Pages)技术,这是Java Web开发中另一个重要的组成部分,它使得开发动态网页变得更加简单和直观。
3. JSP概述
3.1 什么是JSP
JSP(JavaServer Pages)是一种基于Java技术的网页开发技术,它允许开发者在HTML页面中嵌入Java代码,从而创建动态的Web内容。JSP页面在首次被访问时会被编译成Servlet,然后执行生成HTML响应返回给客户端。
想象一下,如果你经营一家在线书店,每天的畅销书榜单都会变化。使用静态HTML页面,你需要每天手动更新页面内容;而使用JSP,你可以编写一段代码,自动从数据库获取最新的畅销书信息并显示在页面上。
3.2 JSP与Servlet的关系
JSP和Servlet是紧密相关的技术:
- 本质上是一样的:JSP页面最终会被转换成Servlet执行
- 侧重点不同:
- Servlet侧重于处理业务逻辑
- JSP侧重于展示数据和页面设计
- 开发方式不同:
- Servlet是纯Java代码
- JSP是HTML和Java代码的混合体
3.3 JSP的优势
- 易于开发:对于熟悉HTML的开发者来说,学习曲线较低
- 分离关注点:可以将表现层(HTML)和业务逻辑(Java)分开
- 动态内容生成:能够根据用户请求动态生成内容
- 可重用性:支持组件重用,如包含文件、标签库等
4. JSP基本语法
4.1 JSP页面结构
JSP页面通常包含以下元素:
- HTML/CSS/JavaScript代码
- JSP脚本元素(Java代码)
- JSP指令
- JSP动作
- 表达式语言(EL)
- 自定义标签
4.2 JSP脚本元素
JSP提供了三种在页面中嵌入Java代码的方式:
4.2.1 声明(Declaration)
声明用于定义变量和方法,语法为 <%! ... %>
。
<%!
int count = 0;
public String getGreeting() {
return "Hello, visitor #" + (++count);
}
%>
4.2.2 脚本段(Scriptlet)
脚本段用于执行Java代码,语法为 <% ... %>
。
<%
String username = request.getParameter("username");
if (username != null && !username.isEmpty()) {
%>
<h2>欢迎, <%= username %>!</h2>
<%
} else {
%>
<h2>欢迎访问我们的网站!</h2>
<%
}
%>
4.2.3 表达式(Expression)
表达式用于输出变量或方法的值,语法为 <%= ... %>
。
<p>当前时间是: <%= new java.util.Date() %></p>
<p><%= getGreeting() %></p>
4.3 JSP指令
JSP指令用于设置整个JSP页面相关的属性,语法为 <%@ directive attribute="value" %>
。
4.3.1 page指令
设置页面的属性,如语言、内容类型、错误页面等。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ page import="java.util.Date, java.text.SimpleDateFormat" %>
<%@ page errorPage="error.jsp" %>
4.3.2 include指令
在编译时包含其他文件的内容。
<%@ include file="header.jsp" %>
<!-- 页面主体内容 -->
<%@ include file="footer.jsp" %>
4.3.3 taglib指令
引入自定义标签库。
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
4.4 JSP动作
JSP动作使用XML语法,用于执行各种操作,如包含文件、转发请求等。
4.4.1 jsp:include
在运行时包含其他资源的输出。
<jsp:include page="header.jsp" />
4.4.2 jsp:forward
将请求转发到另一个资源。
<jsp:forward page="result.jsp">
<jsp:param name="status" value="success" />
</jsp:forward>
4.4.3 jsp:useBean
创建或查找JavaBean实例。
<jsp:useBean id="user" class="com.example.User" scope="session" />
<jsp:setProperty name="user" property="username" value="张三" />
用户名: <jsp:getProperty name="user" property="username" />
5. JSP内置对象
JSP提供了9个内置对象,可以直接在页面中使用,无需创建:
- request:HttpServletRequest对象,包含客户端请求信息
- response:HttpServletResponse对象,用于向客户端发送响应
- session:HttpSession对象,表示客户端会话
- application:ServletContext对象,表示整个Web应用
- out:JspWriter对象,用于向客户端输出内容
- pageContext:PageContext对象,提供对所有JSP组件的访问
- config:ServletConfig对象,包含Servlet的配置信息
- page:代表当前JSP页面的实例(相当于this)
- exception:Exception对象,仅在错误页面中可用
5.1 内置对象的使用示例
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
<title>JSP内置对象示例</title>
</head>
<body>
<h1>JSP内置对象示例</h1>
<h2>Request对象</h2>
<p>客户端IP地址: <%= request.getRemoteAddr() %></p>
<p>请求方法: <%= request.getMethod() %></p>
<h2>Session对象</h2>
<%
// 获取会话ID
String sessionId = session.getId();
// 设置会话属性
session.setAttribute("lastVisit", new java.util.Date());
%>
<p>会话ID: <%= sessionId %></p>
<p>会话创建时间: <%= new java.util.Date(session.getCreationTime()) %></p>
<h2>Application对象</h2>
<%
// 获取应用属性或设置应用属性
Integer visitorCount = (Integer)application.getAttribute("visitorCount");
if (visitorCount == null) {
visitorCount = 1;
} else {
visitorCount++;
}
application.setAttribute("visitorCount", visitorCount);
%>
<p>网站访问次数: <%= visitorCount %></p>
</body>
</html>
6. JSP实战:简单留言板
下面我们将创建一个简单的留言板应用,用户可以提交留言,并查看所有留言。
6.1 创建留言实体类
首先,创建一个Message.java
类来表示留言:
package com.example.model;
import java.util.Date;
public class Message {
private String author;
private String content;
private Date createTime;
public Message(String author, String content) {
this.author = author;
this.content = content;
this.createTime = new Date();
}
// Getters and setters
public String getAuthor() { return author; }
public void setAuthor(String author) { this.author = author; }
public String getContent() { return content; }
public void setContent(String content) { this.content = content; }
public Date getCreateTime() { return createTime; }
public void setCreateTime(Date createTime) { this.createTime = createTime; }
}
6.2 创建留言处理Servlet
接下来,创建一个MessageServlet.java
来处理留言的提交:
package com.example.servlet;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
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 com.example.model.Message;
@WebServlet("/message")
public class MessageServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 设置请求和响应的字符编码
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
// 获取表单数据
String author = request.getParameter("author");
String content = request.getParameter("content");
// 创建新留言
Message message = new Message(author, content);
// 获取应用范围内的留言列表,如果不存在则创建新列表
List<Message> messages = (List<Message>) getServletContext().getAttribute("messages");
if (messages == null) {
messages = new ArrayList<>();
getServletContext().setAttribute("messages", messages);
}
// 添加新留言到列表
messages.add(message);
// 重定向到留言列表页面
response.sendRedirect("messageboard.jsp");
}
}
6.3 创建留言板JSP页面
最后,创建messageboard.jsp
页面来显示留言表单和留言列表:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ page import="java.util.List, com.example.model.Message, java.text.SimpleDateFormat" %>
<!DOCTYPE html>
<html>
<head>
<title>简易留言板</title>
<style>
body { font-family: Arial, sans-serif; margin: 0; padding: 20px; }
.container { max-width: 800px; margin: 0 auto; }
.form-group { margin-bottom: 15px; }
label { display: block; margin-bottom: 5px; }
input, textarea { width: 100%; padding: 8px; box-sizing: border-box; }
button { padding: 10px 15px; background-color: #4CAF50; color: white; border: none; cursor: pointer; }
.message { border: 1px solid #ddd; padding: 15px; margin-bottom: 15px; border-radius: 5px; }
.message-header { display: flex; justify-content: space-between; margin-bottom: 10px; }
.message-content { line-height: 1.5; }
</style>
</head>
<body>
<div class="container">
<h1>简易留言板</h1>
<!-- 留言表单 -->
<div>
<h2>发表留言</h2>
<form action="message" method="post">
<div class="form-group">
<label for="author">您的名字:</label>
<input type="text" id="author" name="author" required>
</div>
<div class="form-group">
<label for="content">留言内容:</label>
<textarea id="content" name="content" rows="5" required></textarea>
</div>
<button type="submit">提交留言</button>
</form>
</div>
<!-- 留言列表 -->
<div>
<h2>留言列表</h2>
<%
List<Message> messages = (List<Message>) application.getAttribute("messages");
if (messages != null && !messages.isEmpty()) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
for (int i = messages.size() - 1; i >= 0; i--) {
Message message = messages.get(i);
%>
<div class="message">
<div class="message-header">
<strong><%= message.getAuthor() %></strong>
<span><%= sdf.format(message.getCreateTime()) %></span>
</div>
<div class="message-content">
<%= message.getContent().replace("\n", "<br>") %>
</div>
</div>
<%
}
} else {
%>
<p>暂无留言</p>
<%
}
%>
</div>
</div>
</body>
</html>
7. JSP最佳实践
7.1 MVC模式与JSP
MVC(Model-View-Controller)是一种常用的设计模式,在Java Web开发中:
- Model(模型):JavaBean,表示数据和业务逻辑
- View(视图):JSP页面,负责展示数据
- Controller(控制器):Servlet,处理用户请求并协调模型和视图
使用MVC模式可以使代码更加清晰、易于维护和扩展。
7.2 避免在JSP中编写复杂的Java代码
JSP主要用于展示数据,应避免在JSP中编写复杂的业务逻辑:
- 将业务逻辑放在JavaBean或Servlet中
- 在JSP中只进行简单的数据展示和格式化
- 使用JSTL和EL表达式代替Java脚本
7.3 使用JSTL和EL表达式
JSTL(JSP标准标签库)和EL(表达式语言)可以简化JSP页面的开发:
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!-- 使用EL表达式访问属性 -->
<p>欢迎, ${user.name}!</p>
<!-- 使用JSTL标签遍历集合 -->
<c:forEach var="item" items="${itemList}">
<p>${item.name}: ${item.price}</p>
</c:forEach>
<!-- 使用JSTL条件标签 -->
<c:if test="${user.role == 'admin'}">
<p>您有管理员权限</p>
</c:if>
总结
在本章的第一部分,我们介绍了Web开发的基本概念和Servlet技术。我们了解了Web应用的工作原理、Java Web开发的优势,以及如何创建和配置Servlet。通过实战示例,我们学习了如何处理HTTP请求和响应,以及如何实现简单的用户登录功能。
在本章中第二部分,我们学习了JSP的基本概念、语法和使用方法。JSP作为Java Web开发中的重要技术,为开发动态网页提供了便捷的方式。我们了解了JSP脚本元素、指令、动作和内置对象,并通过一个简单的留言板应用实践了JSP的使用。
虽然在现代Java Web开发中,前后端分离的架构越来越流行,但JSP仍然是学习Java Web开发的重要基础,也是理解MVC模式的良好起点。
在下一部分,我们将学习Spring框架和SpringBoot,它们是现代Java Web开发中不可或缺的技术。
练习
- 创建一个简单的Servlet,显示当前时间和访问计数器。
- 实现一个简单的在线留言板,使用Servlet处理留言的提交和显示。
- 扩展登录示例,添加用户注册功能。
- 创建一个文件上传Servlet,允许用户上传图片并显示上传后的图片。
- 实现一个简单的购物车功能,使用Session存储购物车信息。