Servlet

匿名 (未验证) 提交于 2019-12-03 00:15:02

一.Servlet概述
编码格式的设置:
Request: 请求编码格式
doget()方法中:不需要设置
dopost()方法中:request.setCharactorEncoding(“utf-8”)
response 响应编码格式(以字符流的形式响应正文时都要设置)
response.setContentType(“text/html;charset=utf-8”)

1.用用再说!
我们先不要去管Servlet是个什么东西,先用用再说!在使用之后,你就会对Servlet有一个简单的了解。






Servlet的原始创建方式

public class AServlet implements Servlet {
public void init(ServletConfig config) throws ServletException {}
public ServletConfig getServletConfig() {return null;}

public void service(ServletRequest req, ServletResponse res) 		throws ServletException, IOException { 	res.getWriter().print("Hello JavaWeb!"); }  public String getServletInfo() {return null;} public void destroy() {} 

}

1.JavaWeb三大组件
Servlet是JavaWeb三大组件之一,它是我们学习JavaWeb最为基本的组件,也就是说你一定要100%的掌握它。
其它两种:Filter(拦截器)、Listener(观察者模式)

2.Servlet的作用
Servlet,即Server Let的意思,用来处理用户请求。当客户端发出请求后,由Tomcat去找到可以处理这一请求的Servlet来处理。
也就是说,用户的请求是由Servlet来处理的!例如用户发出注册请求,那么就应该有处理注册的Servlet来处理;用户发出登录请求,那么就应该有登录Servlet来处理。
也就是说,Servlet是由我们自己来完成的!但Servlet一定要实现javax.servlet.Servlet接口,并且还要在web.xml文件中部署!不然Tomcat是找不到我们写的Servlet的。

one
com.kgc.web.AServlet


one
/AServlet

当我们写好了com.kgc.web.AServlet类后,还需要在web.xml文件中添加上面的内容。这就是把AServlet部署到项目中去了!

3.JavaWeb请求响应原理
当Tomcat接收到请求(http://localhost:8080/hello/AServlet)后,Tomcat会找到hello项目中的web.xml文件,然后通过AServlet这个请求路径,查找处理这个请求的Servlet类型。这刚好与/AServlet匹配,这说明存在一个可以通过这个请求的Servlet。然后再通过/AServlet查找到one,然后再通过one查找到 com.kgc.web.AServlet。这时Tomcat已经得到了一个Servlet类名字(一个字符串而已)。
Tomcat通过Servlet类名字去查找Servlet缓存池中是否已经存在了这个Servlet对象,如果存在,那么就不用再去创建,直接获取这个Servlet实例,调用它的service()方法完成请求!
如果这个Servlet不存在,那么Tomcat会通过反射来创建Servlet实例,并把Servlet实例存放到Servlet池中,再去调用Servlet的service方法处理请求。
画图分析:从浏览器的请求到服务器调用service方法

4.Servlet接口
javax.servlet.Servlet接口中方法如下:




5.Servlet生命周期
javax.servlet.Servlet接口中,有三个方法说明了Servlet的生命周期:


现在你应该已经清楚了,Servlet的实例不由我们创建,Servlet的方法不由我们来调用,这一切都是由Tomcat来完成!!!这就是说由Tomcat来管理Servlet,而我们只需要去编写Servlet实现类,并将其部署到web.xml文件中去!
再次提醒,只有这三个方法是生命周期中的方法。也就是说,生命周期方法会被Tomcat在不同的时间点来调用!而其它方法就不会被调用了!!!如果你在自己写的Servlet中添加了其他方法,那么Tomcat也是不会去调用它们的!但你可以让生命周期方法去调用你自己写的方法就OK了!

6.请求对象和响应对象的基本使用(不是今天的重点)
在Tomcat调用Servlet的service()方法时,需要给service()方法传递参数,这两个参数一个是ServletRequest,另一个是ServletResponse。其实Tomcat传递的是HttpServletRequest和HttpServletResponse对象。因为我们的请求都是基于HTTP协议的!
HttpServletRequest是ServletRequest的子接口;
HttpServletResponse是HttpServletResponse的子接口。
Tomcat会把所有与请求相关的数据封装到HttpServletRequest对象中。例如请求的是POST还是GET,所有请求头信息,以及请求参数,这些数据都封装到了HttpServletRequest对象中!!!当我们需要使用这些信息时,可以去调用HttpServletRequest的相关方法来获取。
HttpServletRequest方法:



Tomcat会传递给service()方法一个HttpServletResponse对象,这个对象我们称之为响应对象。它可以完成与响应相关的工作。例如向客户端发送响应状态码,向客户端发送响应头信息,向客户端发送响应正文等等!反正只要是与响应相关的方法,你就去HttpServletResponse对象中去查找。



Hello JavaWeb!

”);

7.ServletConfig
ServletConfig对象对应web.xml文件中的元素。例如你想获取当前Servlet在web.xml文件中的配置名,那么可以使用servletConfig.getServletName()方法获取!

你不能自己去创建ServletConfig对象,Servlet的init()方法的参数就是ServletConfig类型的。Tomcat在调用init()方法时,会传递ServletConfig对象。你可以在init()方法中使用它!
在元素中还可以配置初始化参数:

BServlet

com.kgc.web.BServlet


paramName1
paramValue1


paramName2
paramValue2

添加了两个初始化参数,第一个参数的名称为paramName1,第一个参数的值为paramValue1;第二个参数的名称为paramName2,第二个参数值为paramValue2。
在元素中可以加载多个,每个表示一个参数。下有两个子元素:和,其中表示参数的名称,而元素参数的值。
注意,是添加到元素中,而不是中。
使用ServletConfig对象的getInitParameter(String paramName)方法可以获取指定参数名称的参数值。getInitParameterNames()方法返回所有参数的名字,返回值类型为Enumeration。

二.Servlet 补充

1.Servlet的限制
Servlet必须要有一个公有无参构造器,因为Tomcat会调用这个构造器来创建Servlet对象。
反射
2.第一次惩罚
前面已经说过了Servlet的生命周期。
当第一次访问一个Servlet时,Tomcat会创建Servlet实例,然后把Servlet实例存放到Servlet缓存池中,在第二次访问Servlet时,就不会再次创建Servlet了。这说明第一次需要创建,第一次就比较慢!!!这种第一次比较慢的情况被称之为“第一次惩罚”。

3.Tomcat启动时创建Servlet
有些Servlet需要在Tomcat启动时就被创建,而不是第一次访问时被创建,那么可以在web.xml文件中配置元素。
在元素中添加子元素元素!
这个元素的值必须是一个大于等于0的整数!!!

One
com.kgc.web.AServlet
0


Two
com.kgc.web.BServlet
1

所有添加了子元素的Servle,都会在Tomcat启动时被创建!当然,只是被创建,但没有处理请求!但我们知道在Servlet生命周期中init()方法会在创建后被调用,所以你可以在init()方法中做一些输出,查看是否在Tomcat启动时调用了它。
元素的值是一个序号,Tomcat会使用这个序号给多个Servlet排序!然后在Tomcat启动时会按这个顺序来创建Servlet实例对象!

4.单例的Servlet
因为Servlet实例是由Tomcat来创建的,但Tomcat只会创建一个Servlet实例,所以Servlet就是单例的!这与我们自己写的单例模式不太一样。因为这种单例是通过容器来管理而实现的!
(不是只能创建一个servlet,而是一个Servlet类在内存中只能有一个对象)
一个实例需要在同一个时间点上处理多个请求!

Servlet是线程不安全的!处理办法:

三.通用Servlet 父类

1.java.awt.MouseListener
在java.awt包中,有一个鼠标监听器,下面我们来使用一下鼠标监听器。
public class AWTTest {
public static void main(String[] args) {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(300, 200);
f.addMouseListener(new MyMouseListener());
f.setVisible(true);
}
}

class MyMouseListener implements MouseListener {
@Override
public void mouseClicked(MouseEvent e) {
System.out.println(“点击了”);
}

@Override public void mousePressed(MouseEvent e) { 	System.out.println("压下了"); }  @Override public void mouseReleased(MouseEvent e) { 	System.out.println("释放了"); }  @Override public void mouseEntered(MouseEvent e) { 	System.out.println("进入了"); }  @Override public void mouseExited(MouseEvent e) { 	System.out.println("退出了"); } 

}

假如现在我们需要对鼠标点击做出响应,而其他事件不关心时,那么我们的监听器类也要给出其他几个实现,只是空实现而已。
class MyMouseListener implements MouseListener {
public void mouseClicked(MouseEvent e) {
System.out.println(“点击了”);
}
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
}

是否可以不给出这些空实现呢?看来是不行,因为实现一个接口,必须把所有方法都实现了才行啊。
但我们可以自己写一个完全空现实的类,让子类去继承。这样已后所有的类都去继承我们自己写的空实现类,不用再去实现MouseListener。子类具有父类所有方法,所以子类只需要去覆盖想去覆盖的方法,而其它方法就不用写了。
class MyMouseListener extends MouseAdapter {
public void mouseClicked(MouseEvent e) {
System.out.println(“点击了”);
}
}
class MouseAdapter implements MouseListener {
public void mouseClicked(MouseEvent e) {}
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
}

你可能会说,这不是更麻烦!多写了一个类!!!
没错,但这个MouseAdapter只需要写一次,以后就不用再写了。这么算来还是方便了很多!

2.为Servlet编写通用父类
你也知道,Servlet接口中有5个方法,平时我们只对其中一部分方法感兴趣,但还是要把所有方法都覆盖了,那么我们不如写一个通用父类,从此以后,所有人都去继承这个通用父类,而不是实现Servlet接口。
public class MyServlet implements Servlet {
public void init(ServletConfig config) throws ServletException {}
public ServletConfig getServletConfig() {return null;}

public void service(ServletRequest req, ServletResponse res) 		throws ServletException, IOException { }  public String getServletInfo() {return null;} public void destroy() {} 

}
public class OneServlet extends MyServlet {
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
res.getWriter().print(“Hello JavaWeb!”);
}
}

其实在Servlet方法中,init()和getServletConfig()方法我们可以完成了。因为我相信我的实现是所有人都想要的实现。如果我不能肯定这一点,那么我也不敢去实现这两个方法。
public class MyServlet implements Servlet {
private ServletConfig config;
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
public void init() {}
public ServletConfig getServletConfig() {
return config;
}

public void service(ServletRequest req, ServletResponse res) 		throws ServletException, IOException { } public String getServletInfo() {return null;} public void destroy() {} 

}

多么完美的MyServlet类啊。在init(ServletConfig)方法中把Tomcat传递过来的ServletConfig对象保存了起来(赋值给属性)。在getServletConfig()方法中返回它!!!
如果子类想添加初始化工作,去覆盖init(ServletConfig)方法后,那么this.config=config这句就不会被执行了,所以建议子类不要去覆盖init(ServletConfig)方法,而应该去覆盖init()方法。因为init(ServletConfig)方法中会调用init()方法。

当调用子类对象OneServlet的init(ServletConfig)方法会执行什么内容?
当调用getServletConfig()方法返回的是什么?

3.GenericServlet
javax.servlet.GenericServlet与我们自己写的MyServlet类很相似,你现在使用它应该已经没有问题了吧!

四.专注HTTP请求的Servlet

1.写一个专门处理HTTP请求的Servlet
因为现在我们的请求都是基于HTTP协议的,所以我们应该专门为HTTP请求写一个Servlet做为通用父类。
对于专注于HTTP的Servlet,我们需要处理以下几个问题:
service()方法的参数ServletRequest和ServletResponse,但因为所有的请求都是HTTP请求,所以传递给service()就去的参数其实是HttpServletRequest和HttpServletResponse对象。如果子类希望使用的是HttpServletRequest,而不是ServletRequest,那么它需要自己去做强转。我们的MyHttpServlet这个通用父类可以把强转的工作完成!
public class MyHttpServlet extends GenericServlet {
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
HttpServletRequest httpReq = (HttpServletRequest)req;
HttpServletResponse httpRes = (HttpServletResponse)res;
service(httpReq, httpRes);
}
// 子类应该去覆盖这个方法,而不是上面的方法
// 这个方法的参数是HTTP的
public void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
}
}

在MyHttpServlet类中的service(ServletRequest,ServletResponse)方法调用了本类中自己写的方法service(HttpServletRequest,HttpServletResponse)。子类应该去覆盖后者!

2.doGet()和doPost()
我们知道,在HTTP中请求的方法最为常见的就是GET和POST。往往我们需要在service()方法中去判断客户端的请求方法,然后为GET写一种处理请求的方案,再为POST写一种处理请求的方法。这说明我们需要在service()方法中写if语句来做判断!为什么我们的MyHttpServlet不把这个工作完成了呢?
public class MyHttpServlet extends GenericServlet {
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
HttpServletRequest httpReq = (HttpServletRequest)req;
HttpServletResponse httpRes = (HttpServletResponse)res;
service(httpReq, httpRes);
}
public void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String method = request.getMethod();
if(method.equals(“GET”)) {
doGet(request, response);
} else if(method.equals(“POST”)) {
doPost(request, response);
}
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

} public void doPost(HttpServletRequest request, HttpServletResponse response)  		throws ServletException, IOException { 	 } 

}

3.子类不能覆盖这个类的service()方法
子类不能去覆盖MyHttpServlet类的service()方法!如果覆盖了这个方法,那么它就不能去调用service(HttpServletRequest,HttpServletResponse)方法了,那么也就不会通过请求方式去调用doGet()或doPost()方法了。
注意,现在已经有两个service()方法了,这两个service()方法的关系一定要搞清楚!!!
doGet()和doPost()与service()方法的关系是怎样的也一定要搞清楚!

4.HttpServlet
没错,Java中已经存在了javax.servlet.http.HttpServlet类。它与我们自己写的MyHttpServlet类很相似。打开源代码看看这个类!它比我们自己的MyHttpServlet复杂一点,但最为常用的特性都已经写在MyHttpServlet中了,如果你会用了MyHttpServlet,那么HttpServlet你也就会用了。
我们以后写的Servlet基本都是从HttpServlet开始派生!

5.HTTP请求方法
HTTP请求方法不只是GET和POST,还有其他的方法,但基本上用不上。这里只是简单介绍一下。HTTP请求除了GET和POST之外还有别的:









6.HttpServlet中doXXX()的默认实现
在HttpServlet中提供了7种不同的请求方式处理的方法:






7.HTTP状态码
HTTP的状态码我们也需要了解一下!
我们现在已经知道的状态码有:200、206、404、416、500。
下面深入了解一下HTTP状态码:
1XX:信息类(Information),表示收到Web浏览器请求,正在进一步的处理中;
2XX:成功类(Successful),表示用户请求被正确接收,理解和处理例如:200 OK;
3XX:重定向类(Redirection),表示请求没有成功,客户必须采取进一步的动作;
4XX:客户端错误(Client Error),表示客户端提交的请求有错误。 例如:404 Not Found,意味着请求中所引用的文档不存在;
5XX:服务器错误(Server Error)表示服务器不能完成对请求的处理:如 500。

五.注册功能

1.功能说明
没有人不知道什么叫注册功能吧!
我们这里的注册功能很简单,给用户提供一个页面,在页面中给出一个注册表单,用户输入自己的注册信息(用户名和密码)。然后提交表单,把请求发送到Servlet,Servlet会把用户的注册信息保存到数据库中。完毕!
我们也不打算让Servlet做太多的事情,所以真正保存信息的工作还是交给DAO来做吧!所以在Servlet中只是获取DAO对象,然后调用DAO的方法来完成保存信息!



不能用业务数据做主键(唯一标识!)
username:用户名是唯一的!
password
email:唯一的!

2.项目分析
用户通过注册页面的表单向Servlet发送请求,Servlet获取DAO对象,然后调用DAO对象的方法save()方法完成向数据库中保存注册信息。





3.从注册页面开始

<h1>测试页面</h1> <form action="servlet路径" method="post"> 	用户名:<input type="text" name="username"/><br/> 	密 码:<input type="password" name="password"/><br/> 	<input type="submit" value="提交"/> </form> 

4从底层开始(javabean对象)

package com.kgc.bean;

public class User {
private String username;
private String password;

}

5.创建数据库
6.RegistDao
RegistDao只是一个接口,它定义了save(User user)方法。
public interface RegistDao {
public void save(User user) throws Exception;
}

7.RegistDaoImpl
RegistDaoImpl是RegistDao的实现类!
8.RegistServlet
只编写doPost()方法即可。

public class RegistServlet extends HttpServlet {
@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
try {
req.setCharacterEncoding(“UTF-8”);
String username = req.getParameter(“username”);
String password = req.getParameter(“password”);
User user = new User(username, password);

		RegistDao registDao = new RegistDaoImpl(); 		registDao.save(user);  		resp.setContentType("text/html;charset=UTF-8"); 		resp.getWriter().print("注册成功!!!"); 	} catch (Exception e) { 		throw new RuntimeException(e); 	} } 

}

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!