servlet3.0的出现是servlet史上最大的变革,其中的许多新特性大大的简化了web应用的开发,为广大劳苦的程序员减轻了压力,提高了web开发的效率。主要新特性有以下几个:
- 引入注解配置
- 支持web模块化开发
- 程序异步处理
- 改进文件上传api
- 非阻塞式io读取流
- websocket实时通信
一、注解配置
servlet3.0新规范顺应了时代的潮流,使用注解配置,取代混乱的web.xml全局配置。在这之前我们在创建servlet,filter,listener时,都是在web.xml中配置。
|
1
2
3
4
5
6
7
8
9
|
//创建一个servlet需要在web.xml中配置如下内容
<servlet>
<servlet-name>myfirstservlet</servlet-name>
<servlet-class>test.myservlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>myfirstservlet</servlet-name>
<url-pattern>/aaa</url-pattern>
</servlet-mapping>
|
|
1
2
3
4
5
6
7
8
9
10
11
12
|
//我们只使用一行代码完成servlet的配置
@webservlet(name = "myfirstservlet",urlpatterns = {"/aaaa"})
public class myservlet extends httpservlet {
@override
public void service(httpservletrequest req, httpservletresponse resp) throws servletexception, ioexception {
requestdispatcher rd = req.getrequestdispatcher("/default.jsp");
rd.forward(req,resp);
}
}
|
关于filter和listener的注解配置方法和上述形式一样,在3.0新规范中主要提供了以下一些注解用于配置:
- websocket :用于配置socket
- webinitparam :用于配置初始化参数,往往和servlet和filter结合使用
- weblistener :用于配置listener
- webfilter :用于配置filter
- multipartconfig :用于文件上传(后面会详细介绍)
还有一些,暂时没有涉及,就不列举了
二、servlet3.0 web模块化开发
在这之前我们对于web应用中的各个servlet,filter,listener都是需要在web.xml中进行配置,如果只是本项目中的各个点的配置,那倒还好,但是如果我们引入框架,是不是每个框架中的各种配置也是需要在我们的web.xml中配置?这无疑会导致我们唯一的web.xml中内容混乱。servlet3.0新规范提出了模块化开发,也就是每个servlet,filter,listener都可以有属于自己的配置文件,功能和web.xml一样,它只负责配置当前的servlet。然后我们只需要将配置文件和自己写的servlet等内容打包成jar,引入到具体项目中即可。(就像我们想要使用了某个功能,引入了从网上下载的jar包到项目中)下面我们看如何使用,由于servlet,filter,listener的配置类似,此处以servlet为例作为演示:
首先我们写一个servlet类:
|
1
2
3
4
5
6
7
8
|
public class myservlet extends httpservlet {
@override
public void service(httpservletrequest req, httpservletresponse resp) throws servletexception, ioexception{
requestdispatcher rd = req.getrequestdispatcher("/default.jsp");
rd.forward(req,resp);
}
}
|
然后我们创建一个web-fragment.xml文件,这就是属于此servlet自己的配置文件,功能类似于web.xml,只是这个是私有的。键入以下内容:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<?xml version="1.0" encoding="utf-8"?>
<web-fragment
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" version="3.0"
xsi:schemalocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-fragment_3_0.xsd"
metadata-complete="false">
<servlet>
<servlet-name>myservlet</servlet-name>
<servlet-class>test.myservlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>myservlet</servlet-name>
<url-pattern>/index</url-pattern>
</servlet-mapping>
</web-fragment>
|
我们可以对比看出,web.xml文件和web-fragment.xml文件除了头部的不一样,一个是web-app,一个是web-fragment,别处几乎一样。我们创建的这个servlet主要负责拦截url为index的请求,并转向default.jsp页面。
接下来我们看如何打包jar,然后再次为我们项目使用。第一步,无论你是用javac命令还是用ide编译,首先我们需要将此.java文件编译成class文件。在你的电脑的任意位置创建一个空文件夹,将编译后的class文件及其包复制进去,因为我们myservlet在test包下,此处我就是将test文件夹复制进去(你们需要根据自己建立的文件进行操作)
然后创建一个空文件夹,命名为meta-inf,一定要这样命名,因为等我们把jar包引入到项目中之后,一旦web应用启动时,就会去我们引入的jar包的此文件夹下查找web-fragment.xml文件并加载,如果没有找到就不会加载,我们的配置也就不会生效。此时我们文件夹中的内容如下:
将刚刚写完的web-fragment.xml文件复制到meta-inf下,然后我们将这两个文件夹压缩成zip格式,然后修改zip为jar即可(因为jar和zip的区别就在于jar中多了一个meta-inf文件夹,如果我们已经手动添加了,那他们这两种格式就是一样了)
此处我们使用手动添加meta-inf文件夹,然后压缩zip格式的形式来完成打包jar的工作,你也可以使用jdk自带jar命令来完成打包操作,效果是一样的。然后我们将此jar包复制到任意web应用的web-inf/lib下,这就是web应用的所有外部引入包所存放的地方。然后我们启动web容器:
结果如上,当我们请求index,拦截器拦截并调向default.jsp页面。这样我们就完成了通过引入外部的jar包而不需要做任何配置,使用了其功能。可能此例并没有很好的展示了这种模块化开发的优势,等到我们学到框架的时候就可以很直观的感受到这种方式的简洁,易于携带。
三、异步处理
在传统的servlet开发中,如果servlet调用了一个耗时很长的逻辑处理方法,那么此servlet必须待在原地等待方法调用结束,这是很低效的一种形式。servlet3.0提出了异步处理的概念,也就是释放了主程序,大大提高了运行效率。
servlet3.0中异步处理主要是通过接口asynccontext来实现的,我们可以通过httpservletrequest对象来过去该接口的实现对象。
|
1
|
asynccontext getasynccontext();
|
在使用异步处理之前,我们还需要配置指定当前的servlet是支持异步处理。有两种方法,第一种是在web.xml中配置
|
1
|
<async-supported>true</async-supported>
|
或者使用webservlet指定属性asyncsupported=true。下面用一个实例演示如何使用servlet的异步处理机制:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
@webservlet(name = "myservlet",urlpatterns = "/index",asyncsupported = true)
public class myservlet extends httpservlet {
@override
public void doget(httpservletrequest req, httpservletresponse resp) throws servletexception, ioexception{
resp.setcontenttype("text/html;charset=utf-8");
printwriter writer = resp.getwriter();
writer.println("servlet 开始:"+new date()+"<br />");
writer.flush();
asynccontext asy = req.startasync();
asy.settimeout(4000);
asy.start(new myinfo(asy));
writer.println("servlet 结束:"+new date()+"<br />");
writer.flush();
}
}
|
我们可以看到,这个servlet非常简单,截取url为index的请求,首先打印启动时间,然后通过request的startasync方法创建asynccontext 对象,设置过期时间,启动异步处理。这个线程类代码如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
public class myinfo extends thread {
private asynccontext asynccontext;
public myinfo(asynccontext as){
this.asynccontext = as;
}
@override
public void run(){
try {
thread.sleep(3000);
printwriter pw = asynccontext.getresponse().getwriter();
pw.println("hello walker:"+new date()+"<br />");
asynccontext.complete();
} catch (interruptedexception e) {
e.printstacktrace();
} catch (ioexception e) {
e.printstacktrace();
}
}
}
|
一个构造方法接受asynccontext 对象,run方法中,先打印一句话然后结束异步调用。我们看看结果:
通过时间我们可以看到servlet开始和结束几乎同时,而我们的异步处理却相差三秒钟,正是我们sleep的三秒钟。虽然我们实现了在servlet中异步调用别的线程来处理一些逻辑,但是我们还是不能完全控制整个异步处理中的各个过程,比如何时开始,何时结束等。servlet3.0中的asynclistener接口提供了以下几个方法帮助我们监控整个过程:
- onstartasync(asyncevent event) :当异步调用开始时触发
- oncomplete(asyncevent event) :当异步完成时触发
- onerror(asyncevent event) :当异步调用出错的时候触发
- ontimeout(asyncevent event):当异步调用超时时候触发
想要实现监控异步调用,首先需要编写一个类继承自asynclistener然后实现如上四个方法,之后这个类就是一个可以监控异步调用的监听器。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
public class myasynclistener implements asynclistener {
public void oncomplete(asyncevent var1) throws ioexception{
system.out.println("异步调用结束了。。。");
}
public void ontimeout(asyncevent var1) throws ioexception{
system.out.println("异步调用超时了。。。");
}
public void onerror(asyncevent var1) throws ioexception{
system.out.println("异步调用出错了。。。");
}
public void onstartasync(asyncevent var1) throws ioexception{
system.out.println("异步调用开始了。。。");
}
}
|
在我们的servlet主程序中使用以下语句绑定此异步监听器:
|
1
|
asy.addlistener(new myasynclistener());
|
此时异步处理的四个结点的动态,我们都是实时掌控的。但是需要注意一点的是:虽然理论上我们是可以监听四个状态的,但是其实异步开始这个事件我们是没法监听的,也就是异步开始的方法永远不会被触发,原因是在注册asynccontext 的时候,已经开始了异步,然而我们却在注册之后才绑定监听器,自然是不能监听到异步开始这个事件的。
四、文件上传api
对于传统的文件上传,我们是需要借助于外部工具的,例如:common-fileupload等。自从servlet3.0新规范以来,改进了文件上传api。
|
1
2
3
4
5
6
7
8
|
<body>
<h1>这是index页面</h1>
<form method="post" action="/submit" enctype="multipart/form-data">
姓名:<input type="text" name="name" /><br /><br />
头像:<input type="file" name="mfile" /><br /><br />
<input type="submit" value="提交" />
</form>
</body>
|
我们知道,在html中上传文件的表单用type="file"来指定,这是一点,还有一点就是from标签的enctype属性,他指定了表单参数的编码方式,主要有以下三种:
- application/form-data :这是enctype的默认值,指定了这个值就表名表单只会提交所有input标签中的value值,对于我们的文件,提交的就是文件名。
- multipart/form-data:这种方式是将参数以二进制存储,上传文件的内容也会被封装成二进制流提交。
- text/plain:这种方式主要用于发送邮件
对于需要上传文件功能的我们自然选择第二个参数值,正如上述代码展示的一样。下面我们写一个servlet用于处理上传的信息。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
@webservlet(name = "myservlet",urlpatterns = {"/submit"})
@multipartconfig //处理文件上传的servlet需要配置此注解
public class fileupload extends httpservlet {
public void service(httpservletrequest req, httpservletresponse resp) throws servletexception, ioexception{
resp.setcontenttype("text/html;charset=utf-8");
printwriter writer = resp.getwriter();
part part = req.getpart("mfile");
writer.println("文件类型:"+part.getcontenttype()+"<br />");
writer.println("文件名:"+part.getname()+"<br />");
part.write("c:\\\\users\\\\administrator\\\\desktop\\\\photo.jpg");
}
}
|
在servlet3.0中采用part接口来处理文件上传,可以通过htppservletrequest的以下两个方法来获取此接口对象:
|
1
2
|
part getpart(string name);
collection<part> getparts();
|
一个part对应于我们一个文件上传域,也就是一个input类型为file的元素。part中有以下一些方法:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
string getcontenttype(); //返回文件类型,如image/png
string getname(); //返回文件名
string getsubmittedfilename();
long getsize(); //返回文件的大小
void write(string var1) throws ioexception; //将文件写入到服务器磁盘
void delete() throws ioexception; //删除此文件
string getheader(string var1); //获取指定文件名的值
collection<string> getheaders(string var1); //获取指定文件名的所有的值
collection<string> getheadernames(); //获取所有header 的name集合
|
在上面的程序中,我们使用了其中一些方法。打印了文件类型,文件名,最后将文件保存到本地桌面上。下面是运行的结果截图:
综上就是关于文件上传api的基本使用情况,希望对大家的学习有所帮助,也希望大家多多支持快网idc。
原文链接:http://www.cnblogs.com/yangming1996/p/6745531.html
相关文章
- ASP.NET本地开发时常见的配置错误及解决方法? 2025-06-10
- ASP.NET自助建站系统的数据库备份与恢复操作指南 2025-06-10
- 个人网站服务器域名解析设置指南:从购买到绑定全流程 2025-06-10
- 个人网站搭建:如何挑选具有弹性扩展能力的服务器? 2025-06-10
- 个人服务器网站搭建:如何选择适合自己的建站程序或框架? 2025-06-10
- 2025-07-10 怎样使用阿里云的安全工具进行服务器漏洞扫描和修复?
- 2025-07-10 怎样使用命令行工具优化Linux云服务器的Ping性能?
- 2025-07-10 怎样使用Xshell连接华为云服务器,实现高效远程管理?
- 2025-07-10 怎样利用云服务器D盘搭建稳定、高效的网站托管环境?
- 2025-07-10 怎样使用阿里云的安全组功能来增强服务器防火墙的安全性?
快网idc优惠网
QQ交流群
-
2025-06-04 89
-
2025-06-04 51
-
2025-05-25 83
-
2025-05-29 42
-
2025-05-29 98








