A servlet is a small Java program that runs within a Web server. Servlets receive and respond to requests from Web clients, usually across HTTP, the HyperText Transfer Protocol.
Defines methods that all servlets must implement
PrimitiveServlet
类PrimitiveServlet
类并实现javax.servlet.Servlet
接口。package cn.edu.ecut.servlet;
import javax.servlet.*;
import java.io.IOException;
public class PrimitiveServlet implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse)
throws ServletException, IOException {
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse)
throws ServletException, IOException {
// 向控制台输出字符串
System.out.println( "service" );
servletResponse.setContentType( "text/html;charset=UTF-8" );
PrintWriter w = servletResponse.getWriter();
LocalDate date = LocalDate.now();
// 通过可以向 浏览器 输出 字符数据的输出流 向 浏览器 发送数据
w.println( ""
);
w.println( date );
w.println( "" );
}
System.out.println
语句则会输出到控制台servletResponse.getWriter()
流输出数据,则会输出到浏览器因为使用 maven 原型创建的 webapp 中 web.xml 所采用的 Servlet 版本太低,因此需要修改 web.xml 。
将原来的 web.xml 中的内容替换为以下内容:
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
web-app>
主要目的是为了能够使用 Servlet 3.x 之后的新特性。
最新的 Servlet 规范是 4.0 。
在 web.xml 中,添加以下内容:
<servlet>
<servlet-name>primitiveservlet-name>
<servlet-class>cn.edu.ecut.servlet.PrimitiveServletservlet-class>
servlet>
所谓注册,就是告知 容器 ,这里有一个 servlet 实例需要被管理,其中:
用于指定 servlet 名称,该名称在容器中必须是唯一的 ( 类似于 Map 集合中的 key )
用于指定相应的 Servlet 类的类名 ( 必须是规范化类名 )为已经注册好的 servlet 建立 映射。
<servlet-mapping>
<servlet-name>primitiveservlet-name>
<url-pattern>/primitive/servleturl-pattern>
servlet-mapping>
所谓建立映射,就是 告知 容器 ,将来浏览器 那个 路径 时 对应那个 servlet 程序,其中:
必须跟已经注册过的 servlet 程序的名称保持相同
用于指定将来在浏览器访问时使用的路径比如访问 /primitive/servlet
时,就需要去寻找 名称为 primitive
的 servlet 实例,随后由 容器 去调用 servlet 实例 的 service 方法为 客户端提供服务。
注意:
url-pattern
,比如: <servlet-mapping>
<servlet-name>primitiveservlet-name>
<url-pattern>/psurl-pattern>
<url-pattern>/primitiveurl-pattern>
<url-pattern>/primitive/servleturl-pattern>
servlet-mapping>
url-pattern
,比如 <servlet-mapping>
<servlet-name>firstservlet-name>
<url-pattern>/furl-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>secondservlet-name>
<url-pattern>/furl-pattern>
servlet-mapping>
此时,启动 容器 时将会发生异常:
java.lang.IllegalArgumentException:
The servlets named [primitive] and [primary] are both mapped to the url-pattern [/primitive/servlet] which is not permitted
启动 容器 后,即可在浏览器的地址栏中输入:
http://localhost:8080/primitive/servlet
从而访问刚刚发布的 servlet 程序。
通过 继承 javax.servlet.GenericServlet 类并实现 其 service 抽象方法的方式来开发 PrimaryServlet :
package cn.edu.ecut.servlet;
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.time.LocalDateTime;
public class PrimaryServlet extends GenericServlet {
@Override
public void service(ServletRequest request, ServletResponse response )
throws ServletException, IOException {
System.out.println( "PrimaryServlet : service" );
// 获得可以向 Web 客户端 ( 浏览器 ) 发送 字符数据的 输出流
PrintWriter w = response.getWriter();
// LocalDateTime datetime = LocalDateTime.now();
LocalDateTime datetime =
LocalDateTime.of( 1998 , 10 , 20 , 7 , 30 , 50 , 100200300 );
w.println( "");
w.println( datetime );
w.println( "");
}
}
通过 web.xml 来部署 servlet 。
<servlet>
<servlet-name>primaryservlet-name>
<servlet-class>cn.edu.ecut.servlet.PrimaryServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>primaryservlet-name>
<url-pattern>/primaryurl-pattern>
<url-pattern>/primary/*url-pattern>
<url-pattern>/primary/servleturl-pattern>
servlet-mapping>
在浏览器中输入以下路径之一都可以访问 primary 对应的 servlet :
http://localhost:8080/primary
或者:
http://localhost:8080/primary/servlet
或者:
http://localhost:8080/primary/sui/bian/bian/sui/dong/hua
在 HTTP 协议中,允许 浏览器 发起 8 种不同的请求,其中你知道的只有两种:
以继承javax.servlet.http.HttpServlet
类并重写其 doGet
和 doPost
两个方法的方式来开发一个名称为 DispatchServlet 的 Servlet 接口实现类:
package cn.edu.ecut.servlet;
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 DispatchServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println( "GET" );
response.setContentType( "text/html;charset=UTF-8" );
PrintWriter w = response.getWriter();
w.println( "DispatchServlet : doGet
" );
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println( "POST" );
response.setContentType( "text/html;charset=UTF-8" );
PrintWriter w = response.getWriter();
w.println( "DispatchServlet : doGet
" );
}
}
通过 在 Servlet 实现类上标注 @WebServlet 的方式来部署 servlet 。
@WebServlet( "/dispatch" )
public class DispatchServlet extends HttpServlet {
}
相当于在 web.xml 中添加了以下内容:
<servlet>
<servlet-name>dispatchservlet-name>
<servlet-class>cn.edu.ecut.servlet.DispatchServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>dispatchservlet-name>
<url-pattern>/dispatchurl-pattern>
servlet-mapping>
为了能够使用不同的方式来访问 servelt,我们需要开发一个页面,这里就直接修改 index.html 。
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<a href="/dispatch">点我试试a>
<br>
<h5>使用GET方式提交表单h5>
<form action="/dispatch" method="get" >
<input type="text" name="username" placeholder="请留下尊姓大名">
<input type="submit" value="提交">
form>
<h5>使用POST方式提交表单h5>
<form action="/dispatch" method="post" >
<input type="text" name="username" placeholder="请留下尊姓大名">
<input type="submit" value="提交">
form>
body>
html>
可以在浏览器地址栏中直接输入:
http://localhost:8080/dispatch
来以 GET 方式请求 dispatch 对应的 servlet 。
或者 直接打开 index.html 后,通过 点击超链接 或 提交表单来访问 dispatch 对应的 servlet 。
除非必须区分 GET 方式 和 POST 方式的请求,比如处理文件上传时,就必须使用 POST 请求。
否则,绝对没有必要分开重写 doGet 和 doPost 方法。
凡是重写 doGet 和 doPost 方法并在其中一个方法中调用另一个方法的做法都是王八蛋做法。
通过继承 HttpServlet 类并重写 service( HttpServletRequest , HttpServletResponse )
方法的方式来开发一个 Servlet 实现类:
package cn.edu.ecut.servlet;
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;
@WebServlet( "/general" )
public class GeneralServlet extends HttpServlet {
@Override
protected void service( HttpServletRequest request , HttpServletResponse response )
throws ServletException, IOException {
System.out.println( "GeneralServlet : service => " + request.getMethod() );
String ip = request.getRemoteAddr();
System.out.println( "ip : " + ip );
// 设置 请求对象 和 响应对象 的编码
request.setCharacterEncoding( "UTF-8" );
response.setContentType( "UTF-8" );
String message ;
//
String uname = request.getParameter( "username" );
if( uname == null || uname.trim().isEmpty() ) {
message = "你没有输入你的用户名" ;
} else {
message = "欢迎 " + uname ;
}
response.setContentType( "text/html;charset=UTF-8" );
PrintWriter w = response.getWriter();
w.println( " "
+ message + "" );
}
}
在 index.html 中添加以下内容:
<hr>
<h5>使用GET方式提交表单 ( general )h5>
<form action="/general" method="get" >
<input type="text" name="username" placeholder="请留下尊姓大名">
<input type="submit" value="提交">
form>
<h5>使用POST方式提交表单( general )h5>
<form action="/general" method="post" >
<input type="text" name="username" placeholder="请留下尊姓大名">
<input type="submit" value="提交">
form>
随后启动 容器,直接打开 index.html 后,通过提交表单即可 访问 general 对应的 servlet 。