1、认知Java Servlet
1.1 Web开发的相关的概念
- Web服务器: Tomcat 、Apache 、ngix 、IIS
- Web浏览器:Google Chrome 、Mozilla FireFox 、Apple Safari 、Microsoft Edge 、IE
- HTTP:HyperText Transfer Protocol 超文本传输协议
- HTML:HyperText Markup Language 超文本标记语言
1.2 什么是Servlet
- 什么事Servlet:servlet就是运行在Web服务器上的java小程序。
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.
- Servlet负责接收Web客户端的HTTP请求。
- Servlet容器:负责管理Servlet程序的Web服务器。
- javax.servlet.Servlet接口:所有的自定义的servlet类都必须实现Servlet接口定义的所有方法。
Defines methods that all servlets must implement
2、创建Servlet类
2.1创建Servlet类
2.1.1创建创建 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() {
}
}
2.1.2、修改 service 方法
@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( "<h1 style='text-align:center ; color:red ;'>" );
w.println( date );
w.println( "</h1>" );
}
- 如果是
System.out.println
语句则会输出到控制台 - 如果是通过
servletResponse.getWriter()
流输出数据,则会输出到浏览器
2.2、部署 servlet
因为使用 maven 原型创建的 webapp 中 web.xml 所采用的 Servlet 版本太低,因此需要修改 web.xml 。
将原来的 web.xml 中的内容替换为以下内容:
<?xml version="1.0" encoding="UTF-8"?>
<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 。
2.2.1、注册 servlet
在 web.xml 中,添加以下内容:
<servlet>
<servlet-name>primitive</servlet-name>
<servlet-class>cn.edu.ecut.servlet.PrimitiveServlet</servlet-class>
</servlet>
所谓注册,就是告知 容器 ,这里有一个 servlet 实例需要被管理,其中:
<servlet-name>
用于指定 servlet 名称,该名称在容器中必须是唯一的 ( 类似于 Map 集合中的 key )<servlet-class>
用于指定相应的 Servlet 类的类名 ( 必须是规范化类名 )
2.2.2、发布 servlet
为已经注册好的 servlet 建立 映射。
<servlet-mapping>
<servlet-name>primitive</servlet-name>
<url-pattern>/primitive/servlet</url-pattern>
</servlet-mapping>
所谓建立映射,就是 告知 容器 ,将来浏览器 那个 路径 时 对应那个 servlet 程序,其中:
<servlet-name>
必须跟已经注册过的 servlet 程序的名称保持相同<url-pattern>
用于指定将来在浏览器访问时使用的路径
比如访问 /primitive/servlet
时,就需要去寻找 名称为 primitive
的 servlet 实例,随后由 容器 去调用 servlet 实例 的 service 方法为 客户端提供服务。
注意:
- 同一个 servlet 程序可以有多个
url-pattern
,比如:
<servlet-mapping>
<servlet-name>primitive</servlet-name>
<url-pattern>/ps</url-pattern>
<url-pattern>/primitive</url-pattern>
<url-pattern>/primitive/servlet</url-pattern>
</servlet-mapping>
- 多个 servlet 不可共用同一个
url-pattern
,比如
<servlet-mapping>
<servlet-name>first</servlet-name>
<url-pattern>/f</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>second</servlet-name>
<url-pattern>/f</url-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
2.3、访问 servlet
启动 容器 后,即可在浏览器的地址栏中输入:
http://localhost:8080/primitive/servlet
从而访问刚刚发布的 servlet 程序。
3、开发Servlet程序:擒贼擒王
3.1、开发 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( "<div style='text-align:center;font-size:100px;color:red;'>");
w.println( datetime );
w.println( "</div>");
}
}
3.2、部署 servlet
通过 web.xml 来部署 servlet 。
3.2.1、注册 servlet
<servlet>
<servlet-name>primary</servlet-name>
<servlet-class>cn.edu.ecut.servlet.PrimaryServlet</servlet-class>
</servlet>
3.2.2、发布 servlet
<servlet-mapping>
<servlet-name>primary</servlet-name>
<url-pattern>/primary</url-pattern>
<url-pattern>/primary/*</url-pattern>
<url-pattern>/primary/servlet</url-pattern>
</servlet-mapping>
3.3、访问 servlet
在浏览器中输入以下路径之一都可以访问 primary 对应的 servlet :
http://localhost:8080/primary
或者:
http://localhost:8080/primary/servlet
或者:
http://localhost:8080/primary/sui/bian/bian/sui/dong/hua
4、开发Servlet程序:分而治之
在 HTTP 协议中,允许 浏览器 发起 8 种不同的请求,其中你知道的只有两种:
- GET : 用于获取数据,通常在浏览器发起 GET 请求的方式有:
- 在浏览器地址栏中直接输入网址
- 点击超链接
- 以 GET 方式提交表单
- POST : 用于 提交新数据 或 更新原有数据,在浏览器中发起POST请求的方式:
- 以 POST 方式提交表单
4.1、开发并部署Servlet
4.1.1、开发 Servlet 类
以继承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( "<h1>DispatchServlet : doGet</h1>" );
}
@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( "<h1>DispatchServlet : doGet</h1>" );
}
}
4.1.2、使用注解部署 servlet
通过 在 Servlet 实现类上标注 @WebServlet 的方式来部署 servlet 。
@WebServlet( "/dispatch" )
public class DispatchServlet extends HttpServlet {
}
相当于在 web.xml 中添加了以下内容:
<servlet>
<servlet-name>dispatch</servlet-name>
<servlet-class>cn.edu.ecut.servlet.DispatchServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>dispatch</servlet-name>
<url-pattern>/dispatch</url-pattern>
</servlet-mapping>
4.2、开发页面
为了能够使用不同的方式来访问 servelt,我们需要开发一个页面,这里就直接修改 index.html 。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</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>
4.3、访问
可以在浏览器地址栏中直接输入:
http://localhost:8080/dispatch
来以 GET 方式请求 dispatch 对应的 servlet 。
或者 直接打开 index.html 后,通过 点击超链接 或 提交表单来访问 dispatch 对应的 servlet 。
除非必须区分 GET 方式 和 POST 方式的请求,比如处理文件上传时,就必须使用 POST 请求。
否则,绝对没有必要分开重写 doGet 和 doPost 方法。
凡是重写 doGet 和 doPost 方法并在其中一个方法中调用另一个方法的做法都是王八蛋做法。
5、开发Servlet程序:殊途同归
5.1、开发并部署Servlet
通过继承 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 ;
//<input type="text" name="username" >
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( "<h1 style='text-align:center;'> " + message + "</h1>" );
}
}
5.2、访问 servlet
在 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 。