







Servlet是Java Web开发中的重要组件,它运行在服务器端,用于处理客户端的请求并返回响应。其工作原理涉及多个组件和步骤,从客户端发起请求到服务器端的处理和响应,整个过程有条不紊地进行。
Servlet容器是Servlet运行的环境,负责管理Servlet的生命周期、资源分配和请求处理等工作。Tomcat是常用的Servlet容器之一,它具有强大的功能和良好的性能。在Tomcat中,Context容器直接管理Servlet的包装类Wrapper,一个Context对应一个Web工程。例如,在Tomcat的配置文件中,可以通过<Context>标签来配置Web应用的相关参数,如路径、文档库等。
public void init(ServletConfig config) throws ServletException {
super.init(config);
// 在这里进行初始化操作,如获取初始化参数
String paramValue = config.getInitParameter("paramName");
// 其他初始化逻辑
}
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取用户名和密码
String username = request.getParameter("username");
String password = request.getParameter("password");
// 进行登录验证等业务逻辑处理
if (isValidUser(username, password)) {
response.getWriter().println("登录成功");
} else {
response.getWriter().println("登录失败");
}
}
public void destroy() {
// 释放资源的逻辑,如关闭数据库连接
if (connection!= null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
super.destroy();
}
Servlet规范基于几个关键类运转,其中ServletConfig、ServletRequest和ServletResponse与Servlet主动关联。ServletConfig在初始化时传递给Servlet,用于获取Servlet的配置属性;ServletRequest和ServletResponse在请求处理时传递给Servlet,分别用于获取请求信息和设置响应信息。
在Tomcat容器中,存在门面设计模式的应用。例如,StandardWrapper和StandardWrapperFacade实现了ServletConfig接口,传给Servlet的是StandardWrapperFacade对象,它能保证Servlet获取到所需数据而不暴露无关数据。同样,ServletContext也有类似结构,Servlet中获取的实际对象是ApplicationContextFacade,用于获取应用的相关信息。
创建Servlet类需要继承HttpServlet类并重写相应方法。例如,创建一个简单的HelloWorldServlet:
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class HelloWorldServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 设置响应内容类型为HTML
response.setContentType("text/html");
// 获取输出流对象
PrintWriter out = response.getWriter();
// 输出HTML内容
out.println("<html><body>");
out.println("<h1>Hello, World!</h1>");
out.println("</body></html>");
}
}
在web.xml文件中,需要配置Servlet的相关信息,包括名称、类名、初始化参数和映射路径等。以下是上述HelloWorldServlet的配置示例:
<servlet>
<servlet-name>HelloWorldServlet</servlet-name>
<servlet-class>com.example.HelloWorldServlet</servlet-class>
<init-param>
<param-name>greeting</param-name>
<param-value>Hello!</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>HelloWorldServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
JSP本质上是Servlet的扩展,JSP页面在第一次被访问时会被翻译成Servlet并执行。在Tomcat中,通过JspServlet来处理JSP页面的翻译工作,其在conf/web.xml中有相应的配置,会拦截所有以.jsp或.jspx为后缀的请求并进行翻译。例如,一个简单的JSP页面:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<title>JSP Example</title>
</head>
<body>
<%
// 这里可以嵌入Java代码
String message = "This is a JSP page.";
%>
<h1><%=message%></h1>
</body>
</html>
当访问该JSP页面时,Tomcat会将其翻译成对应的Servlet类并执行,最终将生成的HTML内容返回给客户端。
@WebServlet(urlPatterns = "/asyncDemo", asyncSupported = true)
public class AsyncDemoServlet extends HttpServlet {
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
resp.setContentType("text/html;charset=UTF-8");
PrintWriter out = resp.getWriter();
out.println("进入Servlet的时间:" + new Date() + ".");
out.flush();
// 启动异步处理
AsyncContext ctx = req.startAsync();
// 执行异步业务逻辑
new Thread(new AsyncTask(ctx)).start();
out.println("结束Servlet的时间:" + new Date() + ".");
out.flush();
}
}
class AsyncTask implements Runnable {
private AsyncContext ctx;
public AsyncTask(AsyncContext ctx) {
this.ctx = ctx;
}
@Override
public void run() {
try {
// 模拟耗时业务操作,这里等待5秒
Thread.sleep(5000);
PrintWriter out = ctx.getResponse().getWriter();
out.println("业务处理完毕的时间:" + new Date() + ".");
out.flush();
ctx.complete();
} catch (Exception e) {
e.printStackTrace();
}
}
}
<servlet>标签中添加<async-supported>true</async-supported>子标签。使用注解配置时,在@WebServlet或@WebFilter注解中设置asyncSupported = true。@WebServlet(urlPatterns = {"/demoServlet"}, asyncSupported = true, loadOnStartup = 1, name = "DemoServlet", displayName = "DS", initParams = {@WebInitParam(name = "param1", value = "value1")})
public class DemoServlet extends HttpServlet {...}
@WebFilter(servletNames = {"DemoServlet"}, filterName = "DemoFilter")
public class DemoFilter implements Filter {...}
@WebListener("This is a demo listener")
public class SimpleListener implements ServletContextListener {...}
multipart/form-data,并可配置文件大小阈值、存放地址、允许上传的最大值等属性。例如:@MultipartConfig(fileSizeThreshold = 1024 * 1024, location = "/tmp/uploads", maxFileSize = 1024 * 1024 * 5, maxRequestSize = 1024 * 1024 * 10)
@WebServlet("/uploadServlet")
public class UploadServlet extends HttpServlet {...}
<?xml version="1.0" encoding="UTF-8"?>
<web-fragment xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-fragment_3.0.xsd"
metadata-complete="true">
<servlet>
<servlet-name>FragmentServlet</servlet-name>
<servlet-class>com.example.FragmentServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>FragmentServlet</servlet-name>
<url-pattern>/fragment</url-pattern>
</servlet-mapping>
</web-fragment>
<name>和<ordering>两个可选顶层标签,用于指定加载顺序。<name>标识文件,<ordering>通过<after>和<before>子标签指定与其他文件的相对位置关系,还可使用<others/>表示除自身外的其他文件,其优先级低于明确指定的相对位置关系。ServletContext context = getServletContext();
ServletRegistration.Dynamic dynamicServlet = context.addServlet("DynamicServlet", DynamicServlet.class);
dynamicServlet.addMapping("/dynamic");
dynamicServlet.setLoadOnStartup(2);
contextInitialized方法或ServletContainerInitializer的onStartup()方法中调用。ServletContainerInitializer是Servlet 3.0新增接口,容器启动时使用JAR服务API发现其实现类,并将WEB-INF/lib目录下JAR包中的类交给onStartup()方法处理,通常需使用@HandlesTypes注解指定处理的类。getPart()和getParts()方法用于从请求中解析上传文件,每个文件用javax.servlet.http.Part对象表示,该接口提供了处理文件的简易方法,如write()、delete()等。例如:@WebServlet("/upload")
@MultipartConfig
public class FileUploadServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Part filePart = request.getPart("file");
if (filePart!= null) {
filePart.write("/tmp/uploadedFile.txt");
response.getWriter().println("文件上传成功");
} else {
response.getWriter().println("没有选择文件上传");
}
}
}
@MultipartConfig注解对上传操作进行自定义配置,如限制文件大小和保存路径等。注意,如果请求的MIME类型不是multipart/form-data,使用上述方法会抛出异常。<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<title>Login Page</title>
</head>
<body>
<h1>Login</h1>
<form action="login" method="post">
<label for="username">Username:</label><input type="text" id="username" name="username"><br>
<label for="password">Password:</label><input type="password" id="password" name="password"><br>
<input type="submit" value="Login">
</form>
</body>
</html>
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 设置响应内容类型为HTML
response.setContentType("text/html");
// 获取输出流对象
PrintWriter out = response.getWriter();
// 获取用户名和密码
String username = request.getParameter("username");
String password = request.getParameter("password");
// 假设这里进行简单的用户名和密码验证,实际应用中应与数据库比对
if ("admin".equals(username) && "123456".equals(password)) {
// 登录成功,跳转到欢迎页面
response.sendRedirect("welcome.jsp");
} else {
// 登录失败,返回错误提示
out.println("<html><body>");
out.println("<h1>Login Failed</h1>");
out.println("<p>Invalid username or password.</p>");
out.println("</body></html>");
}
}
}
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>com.example.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<title>Welcome</title>
</head>
<body>
<h1>Welcome, <%= request.getParameter("username") %>!</h1>
</body>
</html>
通过这个案例,可以看到Servlet在处理用户请求、验证用户身份以及控制页面跳转等方面的实际应用,它是构建Java Web应用的重要基础组件,在实际开发中还有更多复杂和高级的应用场景等待开发者去探索和实践。
Servlet作为Java Web开发的核心技术之一,在服务器端处理请求和生成响应方面有着不可替代的作用。从其基本的工作原理、生命周期到配置使用,再到Servlet 3.0带来的一系列新特性,都为Java Web开发提供了更强大、更灵活的工具。在实际应用中,它广泛应用于各种Web系统的构建,从简单的网站到复杂的企业级应用。随着技术的不断发展,Servlet也在不断演进,未来可能会在性能优化、与新兴技术的融合等方面有更多的突破,开发者需要持续关注其发展动态,以便更好地利用Servlet构建高效、稳定的Web应用。
作者:代老师的编程课
出处:https://blog.jsdiff.com/
如果你喜欢本文,请长按二维码,关注 Java码界探秘
.
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。