Servlet规范了JavaWeb项目的结构
Servlet的规范约束了服务器如何来实现Servlet规范,如何解析JavaWeb项目的结构。
Java就是通过接口来约束
Servlet规范的jar就在tomcat的lib目录下面,文件名:servlet-api.jar,其中还有webSocket-api.jar
创建servlet先只用servlet-api.jar即可。
一、开始使用Servlet规范开发JavaWeb项目:

然后开始配置:

注意:<url-pattern>里面的资源名称必须要用"/"开头
源码:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 5 http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" 6 version="3.1" 7 metadata-complete="true"> 8 9 <servlet> 10 <!-- 配置Servlet类的全限定名 --> 11 <servlet-name>HelloServlet</servlet-name> 12 <servlet-class>com.demo.testServlet.HelloServlet</servlet-class> 13 </servlet> 14 15 <!-- Servlet映射,用来访问资源名称,通过helloHeYang就可以访问资源 --> 16 <servlet-mapping> 17 <servlet-name>HelloServlet</servlet-name> 18 <url-pattern>/helloHeYang</url-pattern> 19 </servlet-mapping> 20 21 22 </web-app>
另外:

Servlet中的方法含义:
public void init(ServletConfig config):Servlet的初始化操作方法
public void service(ServletRequest req, ServletResponse res):处理请求和响应的方法
public void destroy():资源回收
public ServletConfig getServletConfig():获取Servlet的配置信息
public String getServletInfo():获取Servlet的相关的信息(作者/版本)
1 @Override
2 public void init(ServletConfig config) throws ServletException {
3 // TODO Auto-generated method stub
4 System.out.println("init初始化方法");
5 }
6
7 @Override
8 public ServletConfig getServletConfig() {
9 // TODO Auto-generated method stub
10 System.out.println("getServletConfig获取Servlet配置信息");
11 return null;
12 }
13
14 @Override
15 public void service(ServletRequest req, ServletResponse res)
16 throws ServletException, IOException {
17 // TODO Auto-generated method stub
18 System.out.println("service(ServletRequest req, ServletResponse res)处理请求和响应");
19 }
20
21 @Override
22 public String getServletInfo() {
23 // TODO Auto-generated method stub
24 System.out.println("getServletInfo():获取Servlet的相关的信息(作者/版本)");
25 return null;
26 }
27
28 @Override
29 public void destroy() {
30 // TODO Auto-generated method stub
31 System.out.println("destroy():资源回收");
32 }
启动tomcat服务器之后,然后打开浏览器:

---------------------------------------------------------------------------------------------------------------
Servlet的生命周期方法:
public void init(ServletConfig config):Servlet的初始化操作方法(在被第一次访问的时候执行)
public void service(ServletRequest req, ServletResponse res):处理请求和响应的方法(每次访问都会执行)
public void destroy():资源回收(在服务器正常关闭的时候执行)
----------------------------------------------------------------------------------------------
Servlet的生命周期方法的执行顺序:
Servlet是单例的(在其整个应用中只有一个对象)
执行顺序:
1.调用公共无参数的构造器创建对象(只会在第一次访问的时候执行)
2.执行init方法(只会在第一次访问的时候执行)
3.执行服务方法(每次访问都会执行)
4.执行destroy方法(在服务器被正常关闭的时候执行),不要将关闭资源的操作放到该方法中
注意:在Servlet类中必须保证有一个公共的无参数的构造器(使用反射创建对象,类的Class实例.newInstance())
类中的默认构造器的访问权限和类的访问权限一致
二、Servlet的请求流程:

1.通过浏览器发送请求
http://localhost:8080/demo/helloHeYang
2.Tomcat解析请求路径
协议:http
主机地址:localhost
端口:8080,确定访问的是该主机上的哪一个程序
上下文的路径:server.xml文件中配置的信息,/demo
资源名称:访问的资源是什么,/helloHeYang,在项目下的web.xml文件中配置的<url-pattern>的文本
3.根据上下文的路径去找到server.xml文件中的<Context>节点,确定项目的根路径
如果没有找到,返回404错误
反之,执行第4步
4.根据资源名称去项目下的WEB-INF下的web.xml文件中找到<url-pattern>文本内容为/hello的节点
可以确定找到Servlet对应的<servlet-name>
5.根据<Servlet-name>找到Servlet 的全限定名
6.使用反射创建对象
Tomcat中的缓存池:
Map<String, Servlet> cache=new HashMap<>();
Servlet obj = cache.get("类的全限定名");
if(obj==null){
//如果是第一次访问:
Object obj2 = Class.forName("类的全限定名").newInstance();
//将创建好的对象放到缓存池中
cache.put("类的全限定名",obj2);
} else {
//不是第一次访问:
//GOTO 7;
}
7.调用init方法进行初始化操作
创建ServletConfig对象,调用init(config)
8.执行service(ServletRequest req, ServletResponse resp),
执行之前先创建ServletRequest , ServletResponse 两个对象
9.给浏览器一个响应信息
三、Servlet初始化参数
在Servlet类中定义初始化参数,会将代码写死,应该将配置信息放到web.xml文件中

问题:如何将配置好的初始化参数获取到?
解决方案:使用ServletConfig来获取
------------------------------------------------------------------------------------
ServletConfig中的常用方法:
public String getServletName():获取Servlet的名称,配置中的<servlet-name>文本
public ServletContext getServletContext():获取Servlet的上下文信息
-------------------------------------
获取初始化参数的相关方法:
public String getInitParameter(String name):根据指定的名称获取当前的Servlet中的初始化参数
public Enumeration<String> getInitParameterNames():获取当前Servlet中的所有的初始化参数的名称
Enumeration:迭代器(Iterator)

关键代码:
1 @Override
2 public void init(ServletConfig config) throws ServletException {
3 // TODO Auto-generated method stub
4 System.out.println("init初始化方法");
5
6 // 初始化方法的参数
7 System.out.println(config.getServletName());
8 System.out.println(config.getInitParameter("encoding"));
9 System.out.println("----------------------------------");
10 Enumeration<String> inits = config.getInitParameterNames();
11 while (inits.hasMoreElements()) {
12 String name = inits.nextElement();
13 System.out.println("name");
14 System.out.println(name+"--->"+config.getInitParameter(name));
15 }
16
17 }
------------------------------------------------------------
目前的初始化参数只是为当前的Servlet做的配置,如果在多个Servlet中有相同的配置,那么该配置就重复了---解决方案(使用全局的初始化参数)。
四、Servlet继承体系
其实我们实际开发中需要继承HttpServlet这个关键的类,下面我们就来自己实现这个类,然后体会它里面的继承体系,了解它内部的关联性。
首先是自定义一个 HelloServlet,并且实现Servlet,ServletConfig两个接口以及接口的所有的方法。
1 import java.io.IOException;
2 import java.util.Enumeration;
3
4 import javax.servlet.Servlet;
5 import javax.servlet.ServletConfig;
6 import javax.servlet.ServletContext;
7 import javax.servlet.ServletException;
8 import javax.servlet.ServletRequest;
9 import javax.servlet.ServletResponse;
10
11 public class HelloServlet implements Servlet,ServletConfig{
12
13 // 声明私有的全局变量
14 private ServletConfig config;
15
16 public void init(){
17 // 事实上,如果子类没有用super方法,就不会被调用
18 System.out.println("调用了父类的init方法");
19 }
20
21 @Override
22 public void init(ServletConfig config) throws ServletException {
23 // TODO Auto-generated method stub
24 System.out.println("HelloServlet:init初始化方法");
25 this.config = config;
26 init();
27 }
28 @Override
29 public ServletConfig getServletConfig() {
30 // TODO Auto-generated method stub
31 System.out.println("HelloServlet:getServletConfig获取Servlet配置信息");
32 return config;// 在这里直接返回ServletConfig对象
33 }
34 @Override
35 public void service(ServletRequest req, ServletResponse res)
36 throws ServletException, IOException {
37 // TODO Auto-generated method stub
38 System.out.println("HelloServlet:service(ServletRequest req, ServletResponse res)处理请求和响应");
39
40 }
41 @Override
42 public String getServletInfo() {
43 // TODO Auto-generated method stub
44 System.out.println("getServletInfo():获取Servlet的相关的信息(作者/版本)");
45 return null;
46 }
47 @Override
48 public void destroy() {
49 // TODO Auto-generated method stub
50 System.out.println("HelloServlet:destroy():资源回收");
51 }
52
53
54 // 为什么要实现ServletConfig的接口,为了使用接口里面的方法,方便子类调用
55
56 @Override
57 public String getServletName() {
58 // TODO Auto-generated method stub
59 return config.getServletName();
60 }
61
62 @Override
63 public ServletContext getServletContext() {
64 // TODO Auto-generated method stub
65 return config.getServletContext();
66 }
67
68 @Override
69 public String getInitParameter(String name) {
70 // TODO Auto-generated method stub
71 return config.getInitParameter(name);
72 }
73
74 @Override
75 public Enumeration<String> getInitParameterNames() {
76 // TODO Auto-generated method stub
77 return config.getInitParameterNames();
78 }
79
80 }
然后再创建一个MyHttpServlet继承HelloServlet,来处理http请求和响应的类
1 import java.io.IOException;
2
3 import javax.servlet.ServletException;
4 import javax.servlet.ServletRequest;
5 import javax.servlet.ServletResponse;
6 import javax.servlet.http.HttpServletRequest;
7 import javax.servlet.http.HttpServletResponse;
8
9 // 单独一个子类处理service方法
10
11 public class MyHttpServlet extends HelloServlet {
12 @Override
13 public void service(ServletRequest req, ServletResponse res)
14 throws ServletException, IOException {
15 // TODO Auto-generated method stub
16
17
18 // 如果要访问http协议的方法,需要强转类型
19 HttpServletRequest request = (HttpServletRequest) req;
20 HttpServletResponse response = (HttpServletResponse) res;
21 service(req, res);
22 }
23
24 public void service(HttpServletRequest req,HttpServletResponse res){
25 // super.service(req, res);
26 }
27 }
最后再创建一个子类HelloSubServlet,直接继承自MyHttpServlet,注意不是继承最前面的HelloServlet基类哦。
1 import java.io.IOException;
2
3 import javax.servlet.ServletException;
4 import javax.servlet.ServletRequest;
5 import javax.servlet.ServletResponse;
6 import javax.servlet.http.HttpServletRequest;
7 import javax.servlet.http.HttpServletResponse;
8
9 public class HelloSubServlet extends MyHttpServlet {
10
11 /*
12 @Override
13 public void init(ServletConfig config) throws ServletException {
14 // TODO Auto-generated method stub
15 super.init(config);
16 }
17 * 由于config已经作为父类中全局变量来处理了,所以以上方法其实是多余了
18 * 但是又需要调用父类的初始化servlet方法init(ServletConfig...)方法,
19 * 如果子类没有实现,就会去找父类方法,如果子类实现了,而子类中没有用super调用父类方法,父类方法就不会执行
20 * 所以就采用在父类中声明一个init空的方法,然后在init(ServletConfig...)调用,然后子类只要重写init()方法即可
21 *
22 * 但是,前提是:如果子类重写了init(ServletConfig...),就一定要记得要用super调用父类同样的方法
23 */
24
25 @Override
26 public void init() {
27 // 所有初始化的方法写在这里
28 System.out.println("HelloSubServlet初始化方法");
29 }
30
31 @Override
32 public void service(HttpServletRequest req, HttpServletResponse res) {
33 super.service(req, res);
34
35 // 因为子类实现了ServletConfig的接口方法,所以可以直接调用即可。
36 String name = this.getInitParameter("name");
37 System.out.println(name);
38 }; 40 }
然后仔细体会他们之间的关系。
下面是展示直接开发需要知道的继承体系:

五、HttpServletRequest常用的方法
HttpServletRequest接口:处理基于HTTP协议的请求信息
常用的方法:
String getContextPath() :获取上下文的路径
String getHeader(String name) :根据名称获取请求头信息
String getMethod() :获取请求的类型
String getRequestURI() :获取请求的资源路径
StringBuffer getRequestURL():获取请求的全路径
String getParameter(String name) :根据名称获取请求参数的值
String getRemoteAddr() :获取请求的客户端的地址
---------------------------------------------------------------
ServletConfig中的getInitParameter(String name)
获取web.xml文件中配置的初始化参数的值
HttpServletRequest中的getParameter(String name)
获取用户提交的参数值
六、简单案例
一般情况下,一个表单对应一个Servlet。
在webapp目录下创建一个register.html
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Insert title here</title> 6 </head> 7 <body> 8 <!-- action:表单提交到哪个页面 9 method: 提交方式 10 get:提交之后,表单中的数据会显示到地址栏中(不安全) 11 post:提交之后,表单中的数据不会显示到地址中 12 enctype:application/x-www-form-urlencoded(默认) 13 上传文件:multipart/form-data 14 --> 15 <form action="/demo/register" method="post" enctype="application/x-www-form-urlencoded"> 16 姓名:<input type="text" name="name"> 17 <br> 18 密码:<input type="password" name="password"> 19 <br> 20 <br> 21 性别: 22 <input type="radio" name="sex" value="男" checked>男 23 <input type="radio" name="sex" value="女">女 24 <br> 25 职业: 26 <input type="checkbox" name="java" value="java">Java 27 <input type="checkbox" name="c" value="c">C 28 <input type="checkbox" name="IOS" value="ios">IOS 29 30 <br> 31 <br> 32 城市: 33 <select name="address"> 34 <option value="1">成都</option> 35 <option value="2" selected="selected">上海</option> 36 <option value="3">广州</option> 37 </select> 38 39 <br> 40 <br> 41 评论: 42 <textarea name="textarea" rows="10" cols="40">在这里输入文本。。。</textarea> 43 44 <br> 45 <br> 46 <input type="submit" value="提交"> 47 <input type="reset" value="重置"> 48 <br> 49 50 </form> 51 52 </body> 53 </html>
然后创建一个RegisterServlet.class
1 package com.demo.request;
2
3 import java.io.IOException;
4 import java.util.Map;
5
6 import javax.servlet.ServletException;
7 import javax.servlet.http.HttpServlet;
8 import javax.servlet.http.HttpServletRequest;
9 import javax.servlet.http.HttpServletResponse;
10
11 public class RegisterServlet extends HttpServlet {
12
13 /**
14 *
15 */
16 private static final long serialVersionUID = 1L;
17
18
19 @Override
20 protected void service(HttpServletRequest req, HttpServletResponse resp)
21 throws ServletException, IOException {
22 // TODO Auto-generated method stub
23
24 System.out.println("开始执行这段代码。");
25
26 // 1、获取请求参数
27 String name = req.getParameter("name");
28 String password = req.getParameter("password");
29
30 System.out.println("name"+name+" password"+password);
31
32 Map<String,String[]> map = req.getParameterMap();
33 String name2 = map.get("name")[0];
34 System.out.println("name2"+name2);
35 // 2、调用方法来处理业务逻辑
36
37 // 3、控制页面跳转
38 }
39
40 }
还要在web.xml中写好配置代码:
1 <!-- 配置的是子类Servlet --> 2 <servlet> 3 <!-- 配置Servlet类的全限定名 --> 4 <servlet-name>RegisterServlet</servlet-name> 5 <servlet-class>com.demo.request.RegisterServlet</servlet-class> 6 <init-param> 7 <param-name>encoding</param-name> 8 <param-value>UTF-8</param-value> 9 <param-name>name</param-name> 10 <param-value>hahaha</param-value> 11 </init-param> 12 </servlet> 13 14 <!-- Servlet映射,用来访问资源名称,通过helloHeYang就可以访问资源 --> 15 <servlet-mapping> 16 <servlet-name>RegisterServlet</servlet-name> 17 <url-pattern>/register</url-pattern> 18 </servlet-mapping>
Toncat中默认处理请求参数的编码方式默认是ISO-8859-1,只有一个字节,所以中文会乱码。
--解决方案:
方式一:
方式二:
Post:
// 将处理请求参数的编码改为UTF-8
req.setCharacterEncoding("UTF-8");
Get:
在service.xml文件中需要设置的配置(可能默认是URIEncoding="ISO-8859-1"):
1 <Connector port="8080" protocol="HTTP/1.1" 2 connectionTimeout="20000" 3 redirectPort="8443" URIEncoding="UTF-8"/>
另外规定:提交表单只能用POST请求。
HttpServletResponse接口:处理基于HTTP协议的响应信息
常用的方法:
PrintWriter getWriter() :向页面输出字符流
ServletOutputStream getOutputStream() :向页面输出字节流,实现文件下载
以上两个方法不能被同时调用
void setCharacterEncoding(String charset) :设置响应信息的字符编码
向页面输出一个html内容,必须要下面两个设置
resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html");:MIME的类型
上面两个设置可以合在一行代码中
resp.setContentType("text/html; charset=UTF-8");
// 处理响应
resp.setContentType("text/html;charset=UTF-8");
PrintWriter out = resp.getWriter();
out.print("<thml>");
out.print("<head>");
out.print("<title>");
out.print("你好");
out.print("</title>");
out.print("</head>");
out.print("<body>");
out.print("<font color='red'>你好</font>,世界");
out.print("</body>");
out.print("</html>");
来源:https://www.cnblogs.com/goodboy-heyang/p/6477113.html