欢迎访问 生活随笔!

ag凯发k8国际

当前位置: ag凯发k8国际 > 编程语言 > java >内容正文

java

javaweb基础——servlet -ag凯发k8国际

发布时间:2024/10/14 java 34 豆豆
ag凯发k8国际 收集整理的这篇文章主要介绍了 javaweb基础——servlet 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

目录:
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 serializable

httpservlet之所以运用广泛的另一个原因是现在大部分的应用程序都要与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 servletresponse

httpservlet抽象类覆盖了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对象获取

我们通过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了。

public void init(servletconfig config) throws servletexception {this.config = config;this.init(); }

但是,我们发现在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的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得ag凯发k8国际网站内容还不错,欢迎将ag凯发k8国际推荐给好友。

网站地图