javaweb基础——servlet -ag凯发k8国际
目录:
1.servlet入门
2.我的第一个servlet
3.继承httpservlet类的方法来实现servlet
4.使用ide直接创建servlet程序
5.servlet的继承体系
6.servletconfig类
7.servletcotext类
8.http协议
9. genericservlet抽象类
10.httpservletrequest
11.httpservletresponse
12.请求重定向
如何实现servlet:servlet技术的核心是servlet,它是所有servlet类必须直接或者间接实现的一个接口。在编写实现servlet的servlet类时,直接实现它。在扩展实现这个这个接口的类时,间接实现它。
servlet接口定义了servlet与servlet容器之间的契约。这个契约是:servlet容器将servlet类载入内存,并产生servlet实例和调用它具体的方法。但是要注意的是,在一个应用程序中,每种servlet类型只能有一个实例。
用户请求致使servlet容器调用servlet的service()方法,并传入一个servletrequest对象和一个servletresponse对象。servletrequest对象和servletresponse对象都是由servlet容器(例如tomcat)封装好的,并不需要程序员去实现,程序员可以直接使用这两个对象。
servletrequest中封装了当前的http请求,因此,开发人员不必解析和操作原始的http数据。servletresponse表示当前用户的http响应,程序员只需直接操作servletresponse对象就能把响应轻松的发回给用户。
对于每一个应用程序,servlet容器还会创建一个servletcontext对象。这个对象中封装了上下文(应用程序)的环境详情。每个应用程序只有一个servletcontext。每个servlet对象也都有一个封装servlet配置的servletconfig对象。
servlet工作流程:
httpservlet要比genericservlet强大,其实也是有道理的。httpservlet是由genericservlet抽象类扩展而来的,httpservlet抽象类的声明如下所示:
public abstract class httpservlet extends genericservlet implements serializablehttpservlet之所以运用广泛的另一个原因是现在大部分的应用程序都要与http结合起来使用。这意味着我们可以利用http的特性完成更多更强大的任务。javax。servlet.http包是servlet api中的第二个包,其中包含了用于编写servlet应用程序的类和接口。javax.servlet.http中的许多类型都覆盖了javax.servlet中的类型。
httpservlet抽象类是继承于genericservlet抽象类而来的。使用httpservlet抽象类时,还需要借助分别代表servlet请求和servlet响应的httpservletrequest和httpservletresponse对象。
httpservletrequest接口扩展于javax.servlet.servletrequest接口,httpservletresponse接口扩展于javax.servlet.servletresponse接口。
public interface httpservletrequest extends servletrequest public interface httpservletresponse extends servletresponsehttpservlet抽象类覆盖了genericservlet抽象类中的service( )方法,并且添加了一个自己独有的service(httpservletrequest request,httpservletresponse方法。
让我们来具体的看一看httpservlet抽象类是如何实现自己的service方法吧:
首先来看genericservlet抽象类中是如何定义service方法的:
public abstract void service(servletrequest var1, servletresponse var2) throws servletexception, ioexception;我们看到是一个抽象方法,也就是httpservlet要自己去实现这个service方法,我们在看看httpservlet是怎么覆盖这个service方法的:
public void service(servletrequest req, servletresponse res) throws servletexception, ioexception {httpservletrequest request;httpservletresponse response;try {request = (httpservletrequest)req;response = (httpservletresponse)res;} catch (classcastexception var6) {throw new servletexception("non-http request or response");}this.service(request, response); }我们发现,httpservlet中的service方法把接收到的servletrequsest类型的对象转换成了httpservletrequest类型的对象,把servletresponse类型的对象转换成了httpservletresponse类型的对象。之所以能够这样强制的转换,是因为在调用servlet的service方法时,servlet容器总会传入一个httpservletrequest对象和httpservletresponse对象,预备使用http。因此,转换类型当然不会出错了。
转换之后,service方法把两个转换后的对象传入了另一个service方法,那么我们再来看看这个方法是如何实现的:
protected void service(httpservletrequest req, httpservletresponse resp) throws servletexception, ioexception {string method = req.getmethod();long lastmodified;if (method.equals("get")) {lastmodified = this.getlastmodified(req);if (lastmodified == -1l) {this.doget(req, resp);} else {long ifmodifiedsince = req.getdateheader("if-modified-since");if (ifmodifiedsince < lastmodified) {this.maybesetlastmodified(resp, lastmodified);this.doget(req, resp);} else {resp.setstatus(304);}}} else if (method.equals("head")) {lastmodified = this.getlastmodified(req);this.maybesetlastmodified(resp, lastmodified);this.dohead(req, resp);} else if (method.equals("post")) {this.dopost(req, resp);} else if (method.equals("put")) {this.doput(req, resp);} else if (method.equals("delete")) {this.dodelete(req, resp);} else if (method.equals("options")) {this.dooptions(req, resp);} else if (method.equals("trace")) {this.dotrace(req, resp);} else {string errmsg = lstrings.getstring("http.method_not_implemented");object[] errargs = new object[]{method};errmsg = messageformat.format(errmsg, errargs);resp.senderror(501, errmsg);}}我们发现,这个service方法的参数是httpservletrequest对象和httpservletresponse对象,刚好接收了上一个service方法传过来的两个对象。
接下来我们再看看service方法是如何工作的,我们会发现在service方法中还是没有任何的服务逻辑,但是却在解析httpservletrequest中的方法参数,并调用以下方法之一:doget,dopost,dohead,doput,dotrace,dooptions和dodelete。这7种方法中,每一种方法都表示一个http方法。doget和dopost是最常用的。所以,如果我们需要实现具体的服务逻辑,不再需要覆盖service方法了,只需要覆盖doget或者dopost就好了。
总之,httpservlet有两个特性是genericservlet所不具备的:
1.不用覆盖service方法,而是覆盖doget或者dopost方法。在少数情况,还会覆盖其他的5个方法。
2.使用的是httpservletrequest和httpservletresponse对象。
a.html文件按照第一个servlet进行配置就行了
实现servlet程序,当我们是以继承了httpservlet类,我们可以使用getservletconfig()方法来获取当前的servlet对应的servleconfigt对象,但是当我们直接实现了servlet接口,就不能使用这个方法来获取servleconfigt对象,因为这个方法会返回null
当我们使用继承httpconfig实现servlet程序,在重写init()方法的时候我们需要在重写的第一行加上一句super.init(config),因为httpconfig类是继承了genericservlet类,而genericservlet类,而genericservlet的init()方法又保存了servlet的servletconfig的对象(genericservlet实现了servlet接口)所以如果不使用super.init(config)就无法保存servletconfig对象
servletcontext对象表示servlet应用程序。每个web应用程序都只有一个servletcontext对象。在将一个应用程序同时部署到多个容器的分布式环境中,每台java虚拟机上的web应用都会有一个servletcontext对象。
通过在servletconfig中调用getservletcontext方法,也可以获得servletcontext对象。
那么为什么要存在一个servletcontext对象呢?存在肯定是有它的道理,因为有了servletcontext对象,就可以共享从应用程序中的所有资料处访问到的信息,并且可以动态注册web对象。前者将对象保存在servletcontext中的一个内部map中。保存在servletcontext中的对象被称作属性。
servletcontext中的下列方法负责处理属性:
object getattribute(string var1);enumeration<string> getattributenames();void setattribute(string var1, object var2);void removeattribute(string var1);servletcontext对象只能获取
我们通过servletconfig对象获取servletcontext对象,同时我们还可以通过getservletcontext()直接获取
servletcontext对象是在web工程启动时创建,web工程停止时销毁我们setattribute()与getattribute()都是建立在服务器销毁销毁前,而且保存的数据可以在不同的servlet服务器端进行获取,有点全局变量的意思
以上四个选项:
update resources ---- 更新静态的资源,比如html,js,css等 运行模式和调试模式都是立即生效;
update classes and resources ---- 更新java,jsp和静态资源( 1. java修改后,会被编译成.class,然后覆盖到target/kao文件夹下,ide调试模式的情况下,立即生效。ide运行模式下,不立即生效,需要redeployed才可生效。jsp修改后,再次被访问的时候,会自动更新,重新编译成java.class保存在tomcat的work目录下。由于是访问时才检测是否修改,是否需要重新编译,所以 ide 运行模式 和idea调试模式下,都是立即生效。刷新下页面就可);
redeployed ----- 重新部署,发布到tomcat里,不重启tomcat,而是把原来的删掉,然后重新发布(此时的web工程未停止);
restart server ----- 重启tomcat。最彻底!(此时的web工程停止)
谷歌浏览器查看http协议:
前面我们编写servlet一直是通过实现servlet接口来编写的,但是,使用这种方法,则必须要实现servlet接口中定义的所有的方法,即使有一些方法中没有任何东西也要去实现,并且还需要自己手动的维护servletconfig这个对象的引用。因此,这样去实现servlet是比较麻烦的。
void init(servletconfig var1) throws servletexception;幸好,genericservlet抽象类的出现很好的解决了这个问题。本着尽可能使代码简洁的原则,genericservlet实现了servlet和servletconfig接口,下面是genericservlet抽象类的具体代码:
public abstract class genericservlet implements servlet, servletconfig, serializable {private static final string lstring_file = "javax.servlet.localstrings";private static resourcebundle lstrings = resourcebundle.getbundle("javax.servlet.localstrings");private transient servletconfig config;public genericservlet() {}public void destroy() {}public string getinitparameter(string name) {servletconfig sc = this.getservletconfig();if (sc == null) {throw new illegalstateexception(lstrings.getstring("err.servlet_config_not_initialized"));} else {return sc.getinitparameter(name);}}public enumeration<string> getinitparameternames() {servletconfig sc = this.getservletconfig();if (sc == null) {throw new illegalstateexception(lstrings.getstring("err.servlet_config_not_initialized"));} else {return sc.getinitparameternames();}}public servletconfig getservletconfig() {return this.config;}public servletcontext getservletcontext() {servletconfig sc = this.getservletconfig();if (sc == null) {throw new illegalstateexception(lstrings.getstring("err.servlet_config_not_initialized"));} else {return sc.getservletcontext();}}public string getservletinfo() {return "";}public void init(servletconfig config) throws servletexception {this.config = config;this.init();}public void init() throws servletexception {}public void log(string msg) {this.getservletcontext().log(this.getservletname() ": " msg);}public void log(string message, throwable t) {this.getservletcontext().log(this.getservletname() ": " message, t);}public abstract void service(servletrequest var1, servletresponse var2) throws servletexception, ioexception;public string getservletname() {servletconfig sc = this.getservletconfig();if (sc == null) {throw new illegalstateexception(lstrings.getstring("err.servlet_config_not_initialized"));} else {return sc.getservletname();}} }其中,genericservlet抽象类相比于直接实现servlet接口,有以下几个好处:
1.为servlet接口中的所有方法提供了默认的实现,则程序员需要什么就直接改什么,不再需要把所有的方法都自己实现了。
2.提供方法,包围servletconfig对象中的方法。
3.将init( )方法中的servletconfig参数赋给了一个内部的servletconfig引用从而来保存servletconfig对象,不需要程序员自己去维护servletconfig了。
但是,我们发现在genericservlet抽象类中还存在着另一个没有任何参数的init()方法:
public void init() throws servletexception { }设计者的初衷到底是为了什么呢?在第一个带参数的init()方法中就已经把servletconfig对象传入并且通过引用保存好了,完成了servlet的初始化过程,那么为什么后面还要加上一个不带任何参数的init()方法呢?这不是多此一举吗?
当然不是多此一举了,存在必然有存在它的道理。我们知道,抽象类是无法直接产生实例的,需要另一个类去继承这个抽象类,那么就会发生方法覆盖的问题,如果在类中覆盖了genericservlet抽象类的init()方法,那么程序员就必须手动的去维护servletconfig对象了,还得调用super.init(servletconfig)方法去调用父类genericservlet的初始化方法来保存servletconfig对象,这样会给程序员带来很大的麻烦。genericservlet提供的第二个不带参数的init( )方法,就是为了解决上述问题的。
这个不带参数的init()方法,是在servletconfig对象被赋给servletconfig引用后,由第一个带参数的init(servletconfig servletconfig)方法调用的,那么这意味着,当程序员如果需要覆盖这个genericservlet的初始化方法,则只需要覆盖那个不带参数的init( )方法就好了,此时,servletconfig对象仍然有genericservlet保存着。
说了这么多,通过扩展genericservlet抽象类,就不需要覆盖没有计划改变的方法。因此,代码将会变得更加的简洁,程序员的工作也会减少很多。
因为request代表请求,所以我们可以通过该对象分别获得http请求的请求行,请求头和请求体。
在前面我们讲过,在service中使用的编码解码方式默认为:iso-8859-1编码,但此编码并不支持中文,因此会出现乱码问题,所以我们需要手动修改编码方式为utf-8编码,才能解决中文乱码问题,下面是发生乱码的具体细节:
解决post提交方式的乱码:request.setcharacterencoding("utf-8");解决get提交的方式的乱码:parameter = newstring(parameter.getbytes("iso8859-1"),"utf-8");上图在获取请求参数之前调用的意思是,在设置请求体字符编码之前不调用httpservletrequest的get之类方法,避免发生乱码
上图的?username=wzg168只是一种格式一般都是代表请求参数一般写法是...=...
base标签的作用:
上面两张图可以实现c.html和index.html之间的跳转,但是当我们使用请求转发进行跳转的时候(服务
器默认打开index.html页面),再点击回到a.html的时候就会发现跳转不回去,以上代码执行顺序,服务器先默认打开index.html页面——》点击请求转发a/b/c.html——》c.html然后再点击c.html的的跳回ag凯发k8国际首页就会发生错误,错误原因如下(含base标签作用):
我们只需要改进c.html就行,如下:
响应的数据通过两个流传递给客户端, javax.servlet.servletresponse接口表示一个servlet响应,在调用servlet的service( )方法前,servlet容器会先创建一个servletresponse对象,并把它作为第二个参数传给service( )方法。servletresponse隐藏了向浏览器发送响应的复杂过程。
printwriter getwriter()
获得字符流,通过字符流的write(string s)方法可以将字符串设置到response 缓冲区中,随后tomcat会将response缓冲区中的内容组装成http响应返回给浏览器端。
servletoutputstream getoutputstream()
获得字节流,通过该字节流的write(byte[] bytes)可以向response缓冲区中写入字节,再由tomcat服务器将字节内容组成http响应返回给浏览器。
其中的getwriter方法,它返回了一个可以向客户端发送文本的的java.io.printwriter对象。默认情况下,printwriter对象使用iso-8859-1编码(该编码在输入中文时会发生乱码)。
在向客户端发送响应时,大多数都是使用该对象向客户端发送html。
还有一个方法也可以用来向浏览器发送数据,它就是getoutputstream,从名字就可以看出这是一个二进制流对象,因此这个方法是用来发送二进制数据的。
在发送任何html之前,应该先调用setcontenttype()方法,设置响应的内容类型,并将“text/html”作为一个参数传入,这是在告诉浏览器响应的内容类型为html,需要以html的方法解释响应内容而不是普通的文本,或者也可以加上“charset=utf-8”改变响应的编码方式以防止发生中文乱码现象。
当我们write的数据是中文就可能出现乱码,那么以下是解决中文乱码的问题的方法
方法1:
方法2:
response工作流程
请求重定向第一种方法:
上图的setheader方法的name参数代表新的地址,value代表新的访问地址,可以是工程外的资源比如百度等等
请求重定向第二种方法:
总结
以上是ag凯发k8国际为你收集整理的javaweb基础——servlet的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: 为什么iee754标准中,32位浮点数的
- 下一篇: c stl 之 unordered_