Servlet规范了JavaWeb项目的结构
Servlet的规范约束了服务器如何来实现Servlet规范,如何解析JavaWeb项目的结构。
Java就是通过接口来约束
Servlet规范的jar就在tomcat的lib目录下面,文件名:servlet-api.jar,其中还有webSocket-api.jar
创建servlet先只用servlet-api.jar即可。
一、开始使用Servlet规范开发JavaWeb项目:
然后开始配置:
注意:里面的资源名称必须要用"/"开头
源码:
1 <?xml version="1.0" encoding="UTF-8"?>
2
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee5 http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
6 version="3.1"
7 metadata-complete="true">
8
9
10
11 HelloServlet
12 com.demo.testServlet.HelloServlet
13
14
15
16
17 HelloServlet
18 /helloHeYang
19
20
21
22
另外:
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 @Override2 public void init(ServletConfig config) throwsServletException {3 //TODO Auto-generated method stub
4 System.out.println("init初始化方法");5 }6
7 @Override8 publicServletConfig getServletConfig() {9 //TODO Auto-generated method stub
10 System.out.println("getServletConfig获取Servlet配置信息");11 return null;12 }13
14 @Override15 public voidservice(ServletRequest req, ServletResponse res)16 throwsServletException, IOException {17 //TODO Auto-generated method stub
18 System.out.println("service(ServletRequest req, ServletResponse res)处理请求和响应");19 }20
21 @Override22 publicString getServletInfo() {23 //TODO Auto-generated method stub
24 System.out.println("getServletInfo():获取Servlet的相关的信息(作者/版本)");25 return null;26 }27
28 @Override29 public voiddestroy() {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文件中配置的的文本
3.根据上下文的路径去找到server.xml文件中的节点,确定项目的根路径
如果没有找到,返回404错误
反之,执行第4步
4.根据资源名称去项目下的WEB-INF下的web.xml文件中找到文本内容为/hello的节点
可以确定找到Servlet对应的
5.根据找到Servlet 的全限定名
6.使用反射创建对象
Tomcat中的缓存池:
Map 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的名称,配置中的文本
public ServletContext getServletContext():获取Servlet的上下文信息
-------------------------------------
获取初始化参数的相关方法:
public String getInitParameter(String name):根据指定的名称获取当前的Servlet中的初始化参数
public Enumeration getInitParameterNames():获取当前Servlet中的所有的初始化参数的名称
Enumeration:迭代器(Iterator)
关键代码:
1 @Override2 public void init(ServletConfig config) throwsServletException {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 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 importjava.io.IOException;2 importjava.util.Enumeration;3
4 importjavax.servlet.Servlet;5 importjavax.servlet.ServletConfig;6 importjavax.servlet.ServletContext;7 importjavax.servlet.ServletException;8 importjavax.servlet.ServletRequest;9 importjavax.servlet.ServletResponse;10
11 public class HelloServlet implementsServlet,ServletConfig{12
13 //声明私有的全局变量
14 privateServletConfig config;15
16 public voidinit(){17 //事实上,如果子类没有用super方法,就不会被调用
18 System.out.println("调用了父类的init方法");19 }20
21 @Override22 public void init(ServletConfig config) throwsServletException {23 //TODO Auto-generated method stub
24 System.out.println("HelloServlet:init初始化方法");25 this.config =config;26 init();27 }28 @Override29 publicServletConfig getServletConfig() {30 //TODO Auto-generated method stub
31 System.out.println("HelloServlet:getServletConfig获取Servlet配置信息");32 return config;//在这里直接返回ServletConfig对象
33 }34 @Override35 public voidservice(ServletRequest req, ServletResponse res)36 throwsServletException, IOException {37 //TODO Auto-generated method stub
38 System.out.println("HelloServlet:service(ServletRequest req, ServletResponse res)处理请求和响应");39
40 }41 @Override42 publicString getServletInfo() {43 //TODO Auto-generated method stub
44 System.out.println("getServletInfo():获取Servlet的相关的信息(作者/版本)");45 return null;46 }47 @Override48 public voiddestroy() {49 //TODO Auto-generated method stub
50 System.out.println("HelloServlet:destroy():资源回收");51 }52
53
54 //为什么要实现ServletConfig的接口,为了使用接口里面的方法,方便子类调用
55
56 @Override57 publicString getServletName() {58 //TODO Auto-generated method stub
59 returnconfig.getServletName();60 }61
62 @Override63 publicServletContext getServletContext() {64 //TODO Auto-generated method stub
65 returnconfig.getServletContext();66 }67
68 @Override69 publicString getInitParameter(String name) {70 //TODO Auto-generated method stub
71 returnconfig.getInitParameter(name);72 }73
74 @Override75 public EnumerationgetInitParameterNames() {76 //TODO Auto-generated method stub
77 returnconfig.getInitParameterNames();78 }79
80 }
然后再创建一个MyHttpServlet继承HelloServlet,来处理http请求和响应的类
1 importjava.io.IOException;2
3 importjavax.servlet.ServletException;4 importjavax.servlet.ServletRequest;5 importjavax.servlet.ServletResponse;6 importjavax.servlet.http.HttpServletRequest;7 importjavax.servlet.http.HttpServletResponse;8
9 //单独一个子类处理service方法
10
11 public class MyHttpServlet extendsHelloServlet {12 @Override13 public voidservice(ServletRequest req, ServletResponse res)14 throwsServletException, IOException {15 //TODO Auto-generated method stub16
17
18 //如果要访问http协议的方法,需要强转类型
19 HttpServletRequest request =(HttpServletRequest) req;20 HttpServletResponse response =(HttpServletResponse) res;21 service(req, res);22 }23
24 public voidservice(HttpServletRequest req,HttpServletResponse res){25 //super.service(req, res);
26 }27 }
最后再创建一个子类HelloSubServlet,直接继承自MyHttpServlet,注意不是继承最前面的HelloServlet基类哦。
1 importjava.io.IOException;2
3 importjavax.servlet.ServletException;4 importjavax.servlet.ServletRequest;5 importjavax.servlet.ServletResponse;6 importjavax.servlet.http.HttpServletRequest;7 importjavax.servlet.http.HttpServletResponse;8
9 public class HelloSubServlet extendsMyHttpServlet {10
11 /*
12 @Override13 public void init(ServletConfig config) throws ServletException {14 // TODO Auto-generated method stub15 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 @Override26 public voidinit() {27 //所有初始化的方法写在这里
28 System.out.println("HelloSubServlet初始化方法");29 }30
31 @Override32 public voidservice(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
2
3
4
5
Insert title here6
7
8
15
16 姓名:
17
18 密码:
19
20
21 性别:22 男23 女24
25 职业:26 Java27 C28 IOS29
30
31
32 城市:33
34 成都
35 上海
36 广州
37
38
39
40
41 评论:42 在这里输入文本。。。
43
44
45
46
47
48
49
50
51
52
53
然后创建一个RegisterServlet.class
1 packagecom.demo.request;2
3 importjava.io.IOException;4 importjava.util.Map;5
6 importjavax.servlet.ServletException;7 importjavax.servlet.http.HttpServlet;8 importjavax.servlet.http.HttpServletRequest;9 importjavax.servlet.http.HttpServletResponse;10
11 public class RegisterServlet extendsHttpServlet {12
13 /**
14 *15 */
16 private static final long serialVersionUID = 1L;17
18
19 @Override20 protected voidservice(HttpServletRequest req, HttpServletResponse resp)21 throwsServletException, 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 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
2
3
4 RegisterServlet
5 com.demo.request.RegisterServlet
6
7 encoding
8 UTF-8
9 name
10 hahaha
11
12
13
14
15
16 RegisterServlet
17 /register
18
Toncat中默认处理请求参数的编码方式默认是ISO-8859-1,只有一个字节,所以中文会乱码。
--解决方案:
方式一:
方式二:
Post:
// 将处理请求参数的编码改为UTF-8
req.setCharacterEncoding("UTF-8");
Get:
在service.xml文件中需要设置的配置(可能默认是URIEncoding="ISO-8859-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("");
out.print("
");out.print("
");out.print("你好");
out.print("
");out.print("");
out.print("
");out.print("你好,世界");
out.print("");
out.print("