Servlet 3.0的注解
Servlet 3.0的显著变化是抛弃了web.xml配置Servlet,Filter和Listener的繁琐步骤,允许开发人员使用注解的方式来配置这些类。 Servlet 3.0规范在javax.servlet.annotation包下提供了如下注解:
@WebServlet :用于修饰一个Servlet类,用于部署Servlet类
@WebInitParam :用于与@WebServlet或@WebFilter一起使用,为Servlet、Filter配置参数
@WebListener :用于修饰一个Listener类,用于部署Listener类
@WebFilter :用于修饰一个Filter类,用于部署Filter类
@MultipartConfig :用于修饰Servlet,指定该Servlet将会负责处理multipart/form-data类型的请求(主要用于文件上传)
@ServletSecurity :一个与JAAS有关的注解,修饰Servlet指定该Servlet的安全与授权控制
@HttpConstraint :用于与@ServletSecurity一起使用
@HttpMethodConstraint :用于与@ServletSecurity一起使用
Servlet 3.0的Web模块化支持
Servlet3.0规范不在要求所有的Web组件(如Servlet、Filter和Listener)多必须定义在web.xml文件中,而是允许采用“Web模块”来部署、管理他们。 一个web模块通常是对应一个jar包,jar包的格式如下:
webmodule.jar
|--META-INF
| |--web-fragment.xml
|--Web模块所用的类文件、资源文件等
配置文件web-fragment.xml的格式类似于web.xml,但多出了两个元素name 和ordering ,具体的配置信息用到了可以查。 将web模块化对应的JAR包复制到任意web应用下的WEB-INF/lib目录下,启动web应用就可以了。
Servlet 3.0提供的异步处理
在以前的Servlet规范中,如果Servlet作为控制器调用了一个费时的操作,那么Servlet就必须等到业务方法执行完毕之后才生成响应。在Servlet3.0中,异步处理允许Servlet重新发起一条新的线程去调用耗时的业务方法,这样就避免了用户等待。 实现方式是通过AsyncContext类来处理的,Servlet可通过ServletRequest的如下两个方法开启异步调用、创建AsyncContext对象。
AsyncContext startAsync() AsyncContext startAsync(ServletRequest,ServletResponse)
重复调用上边的方法得到的都是同一个AsyncContext对象 。AsyncContext对象代表异步处理的上下文,提供了一些工具方法,可完成设置异步调用的超时时间,dispatch用于请求、启动后台线程、获取request、response对象等功能。 咱们来举个栗子来说明一下,下边是一个异步处理的Servlet类:
@WebServlet(urlPatterns = "/async",name = "async",asyncSupported = true)
public class AsyncServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req,HttpServletResponse resp) throws ServletException,IOException {
resp.setContentType("text/html;charset=utf-8");
PrintWriter out = resp.getWriter();
out.println("异步调用示例");
out.println("进入Servlet的时间是:"+new Date()+" ");
//创建AsyncContext,开始异步调用
AsyncContext asyncContext = req.startAsync();
//设置异步调用的超时时间
asyncContext.setTimeout(60*1000);
//启动异步调用的线程
asyncContext.start(new GetBookTarget(asyncContext));
out.println("结束Servlet的时间是:" + new Date() + " ");
out.flush();
}
}
GetBookTarget类表示如下:
public class GetBookTarget implements Runnable{
private AsyncContext asyncContext;
public GetBookTarget(AsyncContext asyncContext){
this.asyncContext = asyncContext;
}
@Override
public void run() {
try{
Thread.sleep(5*1000);
ServletRequest request = asyncContext.getRequest();
ArrayList<String> books = new ArrayList<>();
books.add("权利的游戏");
books.add("列王的纷争");
books.add("冰雨的风暴");
request.setAttribute("a",books);
asyncContext.dispatch("/jsp/Async.jsp");
}catch (Exception e){
e.printStackTrace();
}
}
}
Async.jsp的内容如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" session="false" %>
<%@ taglib prefix="mytag" tagdir="/WEB-INF/tags" %>
<%
out.println("业务调用结束的时间"+new Date());
if (request.isAsyncStarted()){
request.getAsyncContext().complete();
}
%>
有两种方式来启用异步的Servlet:
为@WebServlet指定asyncSupported=true
在web.xml文件中为servlet元素添加<async-supported> 子元素 另外,还可以对异步线程的执行情况进行监听,通过实现AsyncListener接口来完成。
改进的Servlet API
Servlet 3.0改进了部分API,其中两个比较大的改进是:
HttpServletRequest增加了对文件上传的支持 ServletContext允许通过编程的方式动态的注册Servlet、Filter
还是来举个栗子,下边是文件提交页面:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
文件上传
选择文件:
处理文件上传的Servlet:
@WebServlet(name = "upload",urlPatterns = {"/upload"})
@MultipartConfig
public class Upload extends HttpServlet {
@Override
public void service(ServletRequest req,ServletResponse res) throws ServletException,IOException {
res.setContentType("text/html;charset=utf-8");
PrintWriter out = res.getWriter();
req.setCharacterEncoding("utf-8");
String name = req.getParameter("filename");
out.println("普通的name参数为:"+name+" ");
HttpServletRequest httpServletRequest = (HttpServletRequest)req;
//获取文件上传域
Part part = httpServletRequest.getPart("file");
out.println("文件上传的类型:"+part.getContentType()+" ");
out.println("文件上传的大小:"+part.getSize()+" ");
//获取该文件上传域的Header Name
Collection headerNames = part.getHeaderNames();
for (String headerName : headerNames){
out.println(headerName+"----->"+part.getHeader(headerName)+" ");
}
out.println("文件名:"+part.getSubmittedFileName());
part.write(getServletContext().getRealPath("/uploadFiles")+"/"+part.getSubmittedFileName());
}
}
Servlet 3.1新增的非阻塞式IO
伴随Java EE7一起发布了Servlet3.1,Servlet3.1引入了不少新特性。尤其是Servlet3.1提供的非阻塞IO进行输入、输出,可以更好地提升性能。 以Servlet读取数据为例,传统的读取方式采用阻塞式IO——当Servlet读取浏览器提交的数据时,如果数据暂时不可用,或者数据没有读取完成,Servlet当前所在的线程会被阻塞,无法继续向下执行。Servlet3.1开始,ServletInputStream新增了一个setReadListener(ReadListener listener)方法,该方法允许以非阻塞IO读取数据,实现ReadListener监听器需要实现如下三个方法:
onAllDataRead():当所有数据读取完成时激发该方法。 onDataAvailable():当有数据可用时激发该方法。 OnError():读取数据出现错误时激发该方法。
下边来举个栗子:
@WebServlet(urlPatterns = "/asyncio",name = "asyncio",asyncSupported = true)
public class AsyncServlet3_1 extends HttpServlet {
@Override
protected void service(HttpServletRequest req,IOException {
resp.setContentType("text/html;charset=utf-8");
PrintWriter out = resp.getWriter();
out.println("非阻塞IO示例");
out.println("进入Servlet的时间:"+new Date()+" ");
//创建AsyncContext,开始异步调用
AsyncContext asyncContext = req.startAsync();
//设置异步调用的超时时长
asyncContext.setTimeout(30*1000);
ServletInputStream inputStream= req.getInputStream();
inputStream.setReadListener(new AsyncIOListener(asyncContext,inputStream));
out.println("结束Servlet的时间:" + new Date() + " ");
out.flush();
}
}
AsyncIOListener的代码如下:
public class AsyncIOListener implements ReadListener {
private ServletInputStream inputStream;
private AsyncContext asyncContext;
public AsyncIOListener(AsyncContext asyncContext,ServletInputStream inputStream){
this.inputStream = inputStream;
this.asyncContext = asyncContext;
}
@Override
public void onDataAvailable() throws IOException {
System.out.println("数据可用!");
try {
Thread.sleep(2*1000);
StringBuffer sb = new StringBuffer();
int len = -1;
byte[] buffer = new byte[1024];
while (inputStream.isReady() && (len = inputStream.read(buffer)) > 0){
String data = new String(buffer,len);
sb.append(data);
}
System.out.println(sb);
asyncContext.getRequest().setAttribute("info",sb.toString());
//转发到视图页面,原理类似于forward
asyncContext.dispatch("/jsp/Async3_1.jsp");
}catch (Exception e){
e.printStackTrace();
}
}
@Override
public void onAllDataRead() throws IOException {
System.out.println("请求数据读取完成");
}
@Override
public void onError(Throwable throwable) {
System.out.println("读取请求数据出错");
}
}
Async3_1.jsp的代码如下所示:
<%@ page contentType="text/html;charset=UTF-8" language="java" session="false" %>
<%out.println("业务调用结束的时间:"+new Date());%>
<%
if (request.isAsyncStarted()){
request.getAsyncContext().complete();
}
%>
Tomcat8的WebScoket支持 (编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|