Java
Servlet主要功能是可以交互式地浏览和修改数据,生成动态Web内容。
Servlet及其工作模式
Servlet 为创建基于 web
的应用程序提供了基于组件、独立于平台的方法,可以不受 CGI
程序的性能限制。Servlet 有权限访问所有的 Java
API,包括访问企业级数据库的 JDBC API。
使用Servlet的优点如下:
- 性能更好。
- Servlet 在 Web
服务器的地址空间内执行。这样它就没有必要再创建一个单独的进程来处理每个客户端请求。
- Servlet 是独立于平台的,因为它们是用 Java 编写的。
- 服务器上的 Java
安全管理器执行了一系列限制,以保护服务器计算机上的资源。因此,Servlet
是可信的。
- Java 类库的全部功能对 Servlet 来说都是可用的。它可以通过 sockets 和
RMI 机制与 applets、数据库或其他软件进行交互。
Servlet的定位大概是这样的位置:

客户端发出请求到HTTP服务器,请求内容由Servlet进行处理,由Servlet来作为中间层去调用如数据库等这类资源,最终处理结果作为响应返回给客户端浏览器。
Servlet生命周期
一个Servlet程序的生命周期有三步:

即init() -> service() ->
destroy()。其中service()方法是执行任务的主体,每次服务器接收到一个
Servlet 请求时,服务器会产生一个新的线程并调用服务。service() 方法检查
HTTP 请求类型(GET、POST、PUT、DELETE 等),并在适当的时候调用
doGet、doPost、doPut,doDelete
等方法,这些方法都定义在HttpServlet
这个抽象类中,该类的UML图如下:

简单实例
建立项目
首先先建立一个最基本的项目:

选中Web
APPlication项目即可。也可以使用Maven建立,我这里下好了tomcat所以就用javaEE模板了。之后取项目名称,结束。
Tomcat的配置如下:

主要配置端口等项目,然后到Deployment
中设置好war包以及访问路径:

更多建立细节请移步https://www.cnblogs.com/javabg/p/7976977.html进行参考。
Servlet编写
下面主要重点关注Servlet的使用、过滤器的作用及原理、数据库的使用。其他如Cookie操作、Session操作等请移步https://www.runoob.com/servlet学习
首先我们写一个简单的类来进行了解。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| import java.io.*; import javax.servlet.*; import javax.servlet.http.*;
@WebServlet("/Hello") public class HelloWorld extends HttpServlet { private String message;
public void init() throws ServletException { message = "Hello World"; }
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html");
PrintWriter out = response.getWriter(); out.println("<h1>" + message + "</h1>"); }
public void destroy() { System.out.println("Destroy"); } }
|
在你写的类的开头使用@WebService注解就可以将他作为一个servlet了,或者你可以将这个类写到web.xml中来体现:
1 2 3 4 5 6 7 8 9 10 11
| <web-app> <servlet> <servlet-name>HelloWorld</servlet-name> <servlet-class>HelloWorld</servlet-class> </servlet>
<servlet-mapping> <servlet-name>HelloWorld</servlet-name> <url-pattern>/HelloWorld</url-pattern> </servlet-mapping> </web-app>
|
使用过滤器
Servlet的过滤器机制以前看到过这样的设计,Struts2中就有过滤器这样的组件,都是由这个发展过去的。过滤器的作用主要是动态地拦截请求和响应,以变化或使用在请求或响应中地信息,可以实现以下目的:
- 在客户端的请求访问后端资源之前,拦截这些请求。
- 在服务器的响应发送到客户端之前,处理这些响应。
常见的由以下作用类型的过滤器:
- 身份验证过滤器(Authentication Filters)。
- 数据压缩过滤器(Data compression Filters)。
- 加密过滤器(Encryption Filters)。
- 触发资源访问事件过滤器。
- 图像转换过滤器(Image Conversion Filters)。
- 日志记录和审核过滤器(Logging and Auditing Filters)。
- MIME-TYPE 链过滤器(MIME-TYPE Chain Filters)。
- 标记化过滤器(Tokenizing Filters)。
- XSL/T 过滤器(XSL/T Filters),转换 XML 内容。
过滤器类的编写主要是实现了javax.servlet.Filter
接口,该接口的定义如下:
1 2 3 4 5 6 7 8 9 10 11
| package javax.servlet;
import java.io.IOException;
public interface Filter { default void init(FilterConfig filterConfig) throws ServletException {}
void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;
default void destroy() {} }
|
其中init为初始化函数,doFilter函数为业务逻辑函数,destory函数为销毁函数。下面实现一个例子,在用户访问一个页面前对其用户名进行检查,这里使用Filter类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| import javax.servlet.*; import javax.servlet.annotation.WebFilter; import java.io.IOException; import java.io.PrintWriter;
@WebFilter("/Hello") public class MyFilter implements Filter {
private static String passMsg;
@Override public void init(FilterConfig filterConfig) throws ServletException { passMsg = "<h1>Login Ok.</h1>"; }
@Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { servletResponse.setContentType("text/html;charset=UTF-8"); servletRequest.setCharacterEncoding("UTF-8"); servletResponse.setCharacterEncoding("UTF-8"); PrintWriter out = servletResponse.getWriter(); if (servletRequest.getParameter("name").isEmpty()) { out.println("<!DOCTYPE html> \n" + "<html>\n" + "<head><meta charset=\"utf-8\"><title>登录页面</title></head>\n" + "<body>\n" + "please input name!" + "</body>\n" + "</html>"); } else if (servletRequest.getParameter("name").equals("float")) { out.println("<!DOCTYPE html> \n" + "<html>\n" + "<head><meta charset=\"utf-8\"><title>登录页面</title></head>\n" + "<body>\n" + passMsg + "</body>\n" + "</html>"); filterChain.doFilter(servletRequest, servletResponse); } else { out.println("<!DOCTYPE html> \n" + "<html>\n" + "<head><meta charset=\"utf-8\"><title>登录页面</title></head>\n" + "<body>\n" + "wrong username!" + "</body>\n" + "</html>"); } } }
|
我使用了webFilter将这个类作为Hello的Servlet的过滤器,其中要求了传入的用户名不为空且为float
,这样才会放过这个请求到Hello的Servlet中去。访问结果:



这里HTTP头的操作可以遍历HttpServletRequest
对象的headers来实现,使用getHeaderNames
和getHeader
即可。
其中的filterChain.doFilter(servletRequest, servletResponse);
意为继续调用下一个过滤器,因为我这里只有一个过滤器,所以没有太大用途。过滤器可以使用@WebFilter注解进行标注,/*
意为全局过滤器,也可以在web.xml
中进行定义,过滤器之间的顺序由xml文档中的顺序决定:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <filter> <filter-name>LogFilter</filter-name> <filter-class>com.runoob.test.LogFilter</filter-class> <init-param> <param-name>test-param</param-name> <param-value>Initialization Paramter</param-value> </init-param> </filter>
<filter> <filter-name>AuthenFilter</filter-name> <filter-class>com.runoob.test.AuthenFilter</filter-class> <init-param> <param-name>test-param</param-name> <param-value>Initialization Paramter</param-value> </init-param> </filter>
<filter-mapping> <filter-name>LogFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
<filter-mapping> <filter-name>AuthenFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
|
比如上述的这个配置中有两个过滤器,但是因为filter-mapping的顺序为:LogFilter -> AuthenFilter
,所以会先进入LogFilter再进入AuthenFilter过滤器。
连接数据库
Java Database
Connectivity,简称JDBC,是Java中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。下面使用mysql5.7进行配合使用JDBC,可以使用Maven拉取依赖,这里选择了引入jar文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
| 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 java.io.IOException; import java.io.PrintWriter; import java.sql.*;
@WebServlet("/DatabaseAccess") public class DatabaseAccess extends HttpServlet {
static final String JDBC_DRIVER = "com.mysql.jdbc.Driver"; static final String DB_URL = "jdbc:mysql://localhost:3306/RUNOOB";
static final String USER = "root"; static final String PASS = "990311puk";
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Connection conn = null; Statement stmt = null; resp.setContentType("text/html;charset=UTF-8"); PrintWriter out = resp.getWriter(); String title = "Servlet Mysql"; String docType = "<!DOCTYPE HTML>"; out.println(docType + "<html>\n" + "<head><title>" + title + "</title></head>\n" + "<body bgcolor=\"#f0f0f0\">\n" + "<h1 align=\"center\">" + title + "</h1>\n"); try { Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection(DB_URL, USER, PASS);
stmt = conn.createStatement(); String sql; sql = "SELECT id, name, url FROM websites"; ResultSet rs = stmt.executeQuery(sql);
while(rs.next()){ int id = rs.getInt("id"); String name = rs.getString("name"); String url = rs.getString("url");
out.println("ID: " + id); out.println(", 站点名称: " + name); out.println(", 站点 URL: " + url); out.println("<br />"); } out.println("</body></html>");
rs.close(); stmt.close(); conn.close(); } catch (Exception e) { e.printStackTrace(); } finally { try{ if(stmt!=null) stmt.close(); }catch(SQLException se2){ } try{ if(conn!=null) conn.close(); }catch(SQLException se){ se.printStackTrace(); } } }
@Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
|
访问结果:

参考
- https://www.runoob.com/servlet