Servlet3.0新特性全解

 更新时间:2023年05月30日 10:18:25   作者:阿邦lucky  
Servlet3.0新特性有异步处理支持、新增的注解支持、可插性支持,下面我们将逐一讲解这些新特性,通过下面的学习,读者将能够明晰了解Servlet 3.0的变化,并能够顺利使用它进行日常的开发工作

Servlet3.0新特性全解

tomcat 7以上的版本都支持Servlet 3.0

Servlet 3.0 新增特性

  • 注解支持;Servlet、Filter、Listener无需在web.xml中进行配置,可以通过对应注解进行配置;
  • 支持Web模块;
  • Servlet异步处理;
  • 文件上传API简化;

Servlet3.0的注解

  • @WebServlet :修饰Servlet类,用于部署该Servlet类。
  • @WebFilter:修饰Filter类,用于部署该Filter类
  • @WebInitParam:与@WebServlet或@WebFilter注解连用,为它们配置参数
  • @MultipartConfig:修饰Servlet类,指定该Servlet类负责处理multipart/form-data类型的请求(主要用于处理上传文件)
  • @ServletSecurity:修饰Servlet类,与JAAS(Java验证和授权API)有关的注解
  • @HttpConstrait:与@ServletSecurity连用
  • @HttpMethodConstrait:与@ServletSecurity连用

示例代码片: 修饰过滤器Filter:

@WebFilter(
        filterName="log",
        urlPatterns={"/*"},
        initParams={
        @WebInitParam(name="encoding",value="GBK"),
        @WebInitParam(name="loginPage",value="/login.jsp")
        })
public class MyFilter implements Filter {
    //内容省略......
}

修饰Servlet

@WebServlet(name="test",
    urlPatterns={"/basic.do"},
    initParams={
        @WebInitParam(name="userName",value="peter"),
        @WebInitParam(name="age",value="100")
        })
public class TestServlet extends HttpServlet{
    //内容省略....
}

修饰监听器Listener:

@WebListener
public class MyRequestListener implements ServletRequestListener{
    //内容省略...
}

Servlet3.0的Web模块支持

  • 原来一个web应用的任何配置都需要在web.xml中进行,因此会使得web.xml变得很混乱,而且灵活性差。现在可通过Web模块来部署管理它们。

  • Web模块对应一个Jar包,即Servlet 3.0可以将每个Servlet、Filter、Listener打成jar包,然后放在WEB-INF\lib中。

  • 每个模块都有自己的配置文件,这个配置文件的名称为 web-fragment.xml 。

  • 制作一个Servlet模块的步骤:

    正常编写Servlet,并编译;

    将此编译class文件及所在包通过jar包命令打成jar包;

    将此jar包用winrar打开,将META-INF中的manifest删除后添加 web-fragment.xml;

    将此jar包放入WEB-INF\lib中即可;

  • web-fragment.xml说明:

    <web-fragment>为根元素;

    <name></name>表示模块名称(模块的唯一标识);

    <ordering></ordering>定义模块加载顺序的标签,当然可以不设置模块加载顺序;

    <before><others/></before>表示在所有模块前面加载(第一个加载);

    <after><name>A</name></after>表示在A模块后面加载;

    可以在里面部署listener、filter、servlet

    值得注意的是,web.xml中用<absolute-ordering>标签指定的模块加载顺序将会覆盖web模块的web-fragment.xml文件中指定的加载顺序。

  • 如何用myEclipse打jar包(有些人不知道) 右键你web项目里的编写的servlet(或filter或listener)类——>Export…——>JAR file——>NEXT——>(Browse)填写导出名字和存放位置——>finish 这样就生成了我们需要的jar包了

  • 示例 servlet类代码片:

@WebServlet(name="test",urlPatterns={"/basic.do"})
public class TestServlet extends HttpServlet{
​
    //使用该方法可响应客户端的所有请求
    public void service(HttpServletRequest req, HttpServletResponse resp)throws IOException{
        System.out.println("进servlet了");
        PrintStream out = new PrintStream(resp.getOutputStream());
        //向页面输入下面字符串
        out.print("1234567890");
    }
​
}

web-fragment.xml代码片

<web-fragment version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"  
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-fragment_3_0.xsd">  
​
   <!-- 指定模块名称 :唯一标识-->  
   <name>mySerModule</name>  
   <!-- 加载顺序 -->  
   <ordering>  
      <!-- 在其它模块之前加载 -->  
      <before>  
         <others/>  
      </before>  
   </ordering>      
</web-fragment> 

在web-fragment.xml里的配置和之前的web.xml里类似,如果是注解实现的servlet的配置,则在web-fragment.xml里就将不再写配置了,如果不是,则还需要写配置。 打成jar包放在一个项目里面启动后,就可通过上面servlet注解配置的/basic.do路径访问上面的servle了。

servlet3.0提供的异步处理

提供异步原因

在以前的servlet中,如果作为控制器的servlet调用了一个较为耗时的业务方法,则servlet必须等到业务执行完后才会生成响应,这使得这次调用成了阻塞式调用,效率比较差

实现异步原理

重新开一个线程单独去调用耗时的业务方法。

配置servlet类成为异步的servlet类

  • 通过注解asyncSupported=true实现
  • 通过web.xml配置
<servlet>
        <servlet-name>test1</servlet-name>
        <servlet-class>com.zrgk.servlet.AsyncServlet</servlet-class>
        <async-suppored>true</async-suppored>       
    </servlet>
    <servlet-mapping>
        <servlet-name>test1</servlet-name>
        <url-pattern>/basic.do</url-pattern>
    </servlet-mapping>

具体实现

java代码:

@WebServlet(name="AsyncServlet",urlPatterns={"/testAsyn.do"},asyncSupported=true)  
public class AsyncServlet extends HttpServlet{  
   public void service(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException{ 
       //解决乱码
       request.setCharacterEncoding("GBK");  
       response.setContentType("text/html;charset=GBK");  
       //通过request获得AsyncContent对象
       AsyncContext actx = request.startAsync(); //重点方法**
       //设置异步调用超时时长
        actx.setTimeout(30*3000);  
        //启动异步调用的线程
        actx.start(new MyThread(actx));//重点方法**
​
       // 直接输出到页面的内容(不等异步完成就直接给页面)
        //但这些内容必须放在标签内,否则会在页面输出错误内容,这儿反正我测试是这样,具体不知对不对??
       PrintWriter out = response.getWriter();
       out.println("<h1>不等异步返回结果就直接返到页面的内容</h1>");  
       out.flush(); 
   }  
}  
​
//异步处理业务的线程类
public class MyThread implements Runnable {
     private AsyncContext actx;  
     //构造
     public MyThread(AsyncContext actx){  
            this.actx = actx;  
     }  
     public void run(){  
        try{  
            //等待5秒,模拟处理耗时的业务
           Thread.sleep(4*1000); 
           //获得request对象,添加数据给页面
           ServletRequest req = actx.getRequest();
           req.setAttribute("content","异步获得的数据");
           //将请求dispath到index.jsp页面,该页面的session必须设为false
           actx.dispatch("/index.jsp");  
        }catch(Exception e){
            e.printStackTrace();
        }  
     }   
}

页面代码(页头里session设为false,表时该页面不会再创建session):

<%@ page language="java" import="java.util.*" pageEncoding="utf-8" session="false"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<html>  
  <body>
    <a href="<%=basePath%>/testAsyn.do">测试异步调用</a>
    异步结果:${content}
  </body>
</html>

异步监听器

异步监听器用来监听异步Servlet的异步处理事件,通过实现AsyncListener接口实现,代码如下:

public class MyAsyncListener implements AsyncListener{
​
    //异步调用完成时触发
    @Override
    public void onComplete(AsyncEvent event) throws IOException {
        // 省略....       
    }
​
    //异步调用出错时触发
    @Override
    public void onError(AsyncEvent event) throws IOException {
        // 省略....       
    }
​
    //异步调用开始触发
    @Override
    public void onStartAsync(AsyncEvent event) throws IOException {
        // 省略....       
    }
​
    //异步调用超时触发
    @Override
    public void onTimeout(AsyncEvent event) throws IOException {
        // 省略....       
    }
​
}

还需要在异步Servlet里注册异步监听器,即添加如下代码即可:

 actx.addListener(new MyAsyncListener());

Filter异步调用与Servlet一样。

改进的ServletAPI(上传文件)

  • 改进内容

    HttpServletRequest增加了对上传文件的支持

    ServletContext允许通过编程的方式动态注册Servlet、Filter

  • HttpServletRequest提供了如下两个方法处理文件的上传

    Part getPart(String name) 根据名称获取文件上传域

    Collection<Part> getParts() 获取所有文件上传域

  • 上传文件时一定要为表单域设置enctype属性,它表示表单数据的编码方式,有如下三个值:

    application/x-www-form-urlencoded (默认),它只处理表单里的value属性值,它会将value值处理成URL编码方式。如果此时表单域里有上传文件的域(type=”file”),则只会获取该文件在上传者电脑里的绝对路径串,该串没什么实际意义。

    multipart/form-data 此处编码方式会以二制流的方式来处理表单数据,此时会将文件内容也封装到请求参数里。

    texst/plain 当表单的action属性为mailto:URL的形式时比较方便,主要适用于直接通过表单发送邮件的方式

  • 上传文件的Servlet需要加上@MultipartConfig注解

  • 通过request获取的Part对象就可以操作文件域了

  • 示例

@WebServlet(name="uploadServlet",urlPatterns="/upload.do")
@MultipartConfig
public class UploaderServlet extends HttpServlet {
​
    public void service(HttpServletRequest request,HttpServletResponse response) throws IOException, ServletException{
        //获得Par对象(每个Part对象对应一个文件域)
        Part part = request.getPart("file");
        long size = part.getSize(); //获取上传文件大小
        String info = part.getHeader("content-disposition");//获得包含原始文件名的字符串
        //获取原始文件名
        String fileName = info.substring(info.indexOf("filename="")+10,info.length()-1);
        //将文件上传到某个位置
        part.write(getServletContext().getRealPath("/uploadFiles")+"/"+fileName);
    }
}

ServletContext提供了如下方法动态注册Servlet、Filter addServlet(); 动态注册Servlet addFilter(); 动态注册Filter addListener(); 动态注册Listener setInitParameter(String name ,String value); 为Web应用设置初始化参数。

以上就是Servlet3.0新特性全解的详细内容,更多关于Servlet3.0新特性的资料请关注脚本之家其它相关文章!

相关文章

  • 第三方网站微信登录java代码实现

    第三方网站微信登录java代码实现

    这篇文章主要为大家详细介绍了第三方网站微信登录的java代码实现,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-04-04
  • SpringBoot使用Redisson实现延迟执行的完整示例

    SpringBoot使用Redisson实现延迟执行的完整示例

    这篇文章主要介绍了SpringBoot使用Redisson实现延迟执行的完整示例,文中通过代码示例讲解的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下
    2024-06-06
  • mybatis中<choose>标签的用法说明

    mybatis中<choose>标签的用法说明

    这篇文章主要介绍了mybatis中<choose>标签的用法说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-06-06
  • java实现识别二维码图片功能方法详解与实例源码

    java实现识别二维码图片功能方法详解与实例源码

    这篇文章主要介绍了java实现识别二维码图片,java无法识别二维码情况下对二维码图片调优功能方法与实例源码,需要的朋友可以参考下
    2022-12-12
  • 详解Java中的do...while循环语句的使用方法

    详解Java中的do...while循环语句的使用方法

    这篇文章主要介绍了Java中的do...while循环语句的使用方法,是Java入门学习中的基础知识,需要的朋友可以参考下
    2015-10-10
  • spring cloud zuul修改请求url的方法

    spring cloud zuul修改请求url的方法

    这篇文章主要给大家介绍了关于spring cloud zuul修改请求url的方法,文中通过示例代码介绍的非常详细,对大家学习或者使用spring cloud具有一定的参考学习价值,需要的朋友们下面来一起看看吧。
    2017-09-09
  • java银行管理系统源码

    java银行管理系统源码

    这篇文章主要为大家详细介绍了java银行管理系统源码,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-12-12
  • MyBatis-Plus 实体类注解的实现示例

    MyBatis-Plus 实体类注解的实现示例

    MyBatis-Plus作为MyBatis的增强版,提供了一系列实用的注解,如@TableName、@TableId、@TableField等,旨在简化数据库和Java实体类之间的映射及CRUD操作,通过这些注解,开发者可以轻松实现表映射、字段映射、逻辑删除、自动填充和乐观锁等功能
    2024-09-09
  • spring @retryable不生效的一种场景分析

    spring @retryable不生效的一种场景分析

    项目中某个位置要调用其它部门的接口,一直有问题,对方让加重试,这篇文章主要介绍了spring @retryable不生效的一种场景分析,感兴趣的朋友跟随小编一起看看吧
    2024-07-07
  • VMware虚拟机下hadoop1.x的安装方法

    VMware虚拟机下hadoop1.x的安装方法

    这篇文章主要为大家详细介绍了VMware虚拟机下hadoop1.x的安装方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-09-09

最新评论