zoukankan      html  css  js  c++  java
  • Servlet3.0的新特性

    注意:Servlet3.0的项目一定要使用Tomcat7.0才能看到效果!!

    1、新增标注支持

        在Servlet3.0的部署描述文件web.xml的顶层标签<web-app>中有一个metadata-complete属性,如果把该属性的值设置为true,则容器在部署时只依赖于web.xml部署文件中的配置,会忽略所以的标注(同时也会跳过web-fragment.xml的扫描,即禁用可插性支持);如果把该属性的值设置为false或者不配置该属性,则表示启用标注支持和可插性支持。
        1)WebServlet标注
        @WebServlet用于将一个类声明为Servlet,该标注将会在部署时被容器处理,容器将根据具体的属性配置将相应的类部署为Servlet。
        e824b899a9014c0818ddbb0e087b02087af4f4b3.jpg
        2)WebInitParam标注
        @WebInitParam标注通常不单独使用,而是配合@WebServlet或者@WebFilter使用。它的作业是为Servlet或者过滤器指定初始化参数,这等价于web.xml中<servlet>和<filter>的<init-param>子标签
    属性名 类型 是否可选 描述
    name String 指定参数的名字,等价于<param-name>
    value String 指定参数的值,等价于<param-value>
    description String 指定参数的描述,等价于<description>
     
    创建一个Servlet3Annotation类:
    package com.yyq.servlet3.annotation;
    import javax.servlet.ServletConfig;
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebInitParam;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.PrintWriter;
    /**
     * Created by gao on 16-4-14.
     */
    @WebServlet(name = "servlet3annotation", urlPatterns = {"/servlet3"},
            description = "servletinfo", displayName = "abc", asyncSupported = true, loadOnStartup = -1,
            initParams = {@WebInitParam(name = "username", value = "YangYuqin")})
    public class Servlet3Annotation extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doPost(req, resp);
        }
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //获取ServletConfig的实例
            ServletConfig config = this.getServletConfig();
            //获取指定参数名称的值
            String name = config.getInitParameter("username");
            resp.setContentType("text/html;charset=utf-8");
            PrintWriter out = resp.getWriter();
            out.println("<html>");
            out.println("<head><title>Servlet3应用实例</title></head>");
            out.println("<body>");
            out.print("获取InitParamServlet的初始化参数"username"的字符串值:" + name);
            out.println("</body>");
            out.println("</html>");
        }
        @Override
        public void destroy() {
            //
        }
        @Override
        public void init() throws ServletException {
            //
        }
    }

     启动Tomcat,输入:http://localhost:8080/servlet3

        3)WebFilter标注
        @WebFilter用于将一个类声明为过滤器,该标注将会在部署时被容器处理。以下属性均为可选属性,但是value、urlPatterns、servletNames三者必需至少包含一个,且value和urlPattern不能共存,如果同时指定,通常忽略value的取值。
    属性名 类型 描述
    filterName String 指定过滤器的name属性,等价于<filter-name>
    value String[] 该属性等价于urlPatterns属性,两个属性不能同时使用
    urlPatterns String[] 指定一组Servlet的URL匹配模式,等价于<url-pattern>标签
    servletNames String[] @WebServlet中的name属性的取值,或者是web.xml中<servlet-name>的取值
    initParams WebInitParam[] 指定一组Servlet初始化参数,等价于<init-param>标签
    dispatcherTypes DispatcherType 指定过滤器的转发模式。具体取值包括:ASYNC、ERROR、FORWARD、INCLUDE、REQUEST
    asyncSupported boolean 声明过滤器是否支持异步操作模式,等价于<async-supported>标签
    description String 该Servlet的描述信息,等价于<description>标签
    displayName String 该Servlet的显示名,通常配合工具使用,等价于<display-name>标签

     
    package com.yyq.servlet3.filter;
    import javax.servlet.*;
    import javax.servlet.annotation.WebFilter;
    import javax.servlet.annotation.WebInitParam;
    import java.io.IOException;
    /**
     * Created by gao on 16-4-14.
     */
    @WebFilter(servletNames = {"servlet3filterannotation"}, filterName = "characterFilter",
            initParams = {@WebInitParam(name = "encoding", value = "UTF-8")})
    public class Servlet3FilterAnnotation implements Filter {
        private FilterConfig filterConfig = null;
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            this.filterConfig = filterConfig;
        }
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            //获取此Filter的初始参数的值
            String encoding = filterConfig.getInitParameter("encoding");
            System.out.println(encoding);
            //设置请求数据的编码方式
            servletRequest.setCharacterEncoding(encoding);
            //把请求和响应对象传给过滤链中的下一个要调用的过滤器或Servlet
            filterChain.doFilter(servletRequest,servletResponse);
        }
        @Override
        public void destroy() {
            //
        }
    }

      4)WebListener标注

        该标注用于将类声明为监听器。
    属性名 类型 是否可选 描述
    value String 该监听器的描述信息
    监听类:
    package com.yyq.servlet3.listener;
    import javax.servlet.ServletContext;
    import javax.servlet.ServletContextEvent;
    import javax.servlet.ServletContextListener;
    import javax.servlet.annotation.WebListener;
    import javax.servlet.http.HttpSessionAttributeListener;
    import javax.servlet.http.HttpSessionBindingEvent;
    import javax.servlet.http.HttpSessionEvent;
    import javax.servlet.http.HttpSessionListener;
    import java.util.LinkedList;
    import java.util.List;
    /**
     * Created by gao on 16-4-14.
     */
    @WebListener("This is the Listener")
    public class Servlet3Listener implements ServletContextListener, HttpSessionAttributeListener, HttpSessionListener {
        private ServletContext application = null;
        //往会话中添加属性时回调的方法
        public void attributeAdded(HttpSessionBindingEvent httpSessionBindingEvent) {
            //取得用户名列表
            List<String> online = (List<String>) this.application.getAttribute("online");
            if ("username".equals(httpSessionBindingEvent.getName())) {
                //将当前用户名添加到列表中
                online.add((String) httpSessionBindingEvent.getValue());
            }
            //将添加后的列表重新设置到application属性中
            this.application.setAttribute("online", online);
        }
        //以下方法用空实现
        @Override
        public void attributeRemoved(HttpSessionBindingEvent httpSessionBindingEvent) {
        }
        @Override
        public void attributeReplaced(HttpSessionBindingEvent httpSessionBindingEvent) {
        }
        @Override
        public void sessionCreated(HttpSessionEvent httpSessionEvent) {
        }
        @Override
        public void contextDestroyed(ServletContextEvent servletContextEvent) {
        }
        //应用上下文初始化会回调的方法
        @Override
        public void contextInitialized(ServletContextEvent servletContextEvent) {
            //初始化一个application对象
            this.application = servletContextEvent.getServletContext();
            //设置一个列表属性,用于保存在线用户名
            this.application.setAttribute("online",new LinkedList<String>());
        }
        //会话销毁时会回调的方法
        @Override
        public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
            //取得用户名列表
            List<String> online = (List<String>) this.application.getAttribute("online");
            //取得当前用户名
            String username = (String) httpSessionEvent.getSession().getAttribute("username");
            //将此用户名从列表中删除
            online.remove(username);
            //将删除后的列表重新设置到application属性中
            this.application.setAttribute("online", online);
        }
    }

     登录Servlet类:

    package com.yyq.servlet3.listener;
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.util.List;
    /**
     * Created by gao on 16-4-14.
     */
    @WebServlet(name = "servlet3login",urlPatterns = {"/login"})
    public class Servlet3Login extends HttpServlet {
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //设置响应内容类型
            req.setCharacterEncoding("utf-8");
            //获取请求参数中的用户名
            String username = req.getParameter("username");
            //往Session中添加属性
            //会触发HttpSessionAttributeListener中的attributeAdded方法
            if (username != null && !username.equals("")) {
                req.getSession().setAttribute("username", username);
            }
            //从应用上下文中获取在线用户名列表
            List<String> online = (List<String>) getServletContext().getAttribute("online");
            resp.setContentType("text/html;charset=utf-8");
            PrintWriter out = resp.getWriter();
            out.println("<html>");
            out.println("<head><title>用户列表</title></head>");
            out.println("<body>");
            out.println("当前用户是:" + username);
            out.println("<hr/><h3>在线用户列表</h3>>");
            int size = ((online == null) ? 0 : online.size());
            for (int i = 0; i < size; i++) {
                if (i > 0) {
                    out.println("<br />");
                }
                out.println(i + 1 + "." + online.get(i));
            }
            //注意:要对连接URL进行自动重写处理
            out.println("<hr/><a href="" + resp.encodeURL("logout") + "">注销</a>");
            out.println("</body>");
            out.println("</html>");
            out.flush();
            out.close();
        }
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            this.doPost(req, resp);
        }
        @Override
        public void destroy() {
            //
        }
        @Override
        public void init() throws ServletException {
            //
        }
    }

    注销Servlet类:

    package com.yyq.servlet3.listener;
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.util.List;
    /**
     * Created by gao on 16-4-14.
     */
    @WebServlet(name = "servlet3logout", urlPatterns = {"/logout"})
    public class Servlet3Logout extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            this.doPost(req, resp);
        }
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //设置响应内容类型
            req.setCharacterEncoding("utf-8");
            //销毁会话,会触发SessionLinstener中的sessionDestroyed方法
            req.getSession().invalidate();
            //从应用上下文中获取在线用户名列表
            List<String> online = (List<String>)getServletContext().getAttribute("online");
            resp.setContentType("text/html;charset=utf-8");
            PrintWriter out = resp.getWriter();
            out.println("<html>");
            out.println("<head><title>用户列表</title></head>");
            out.println("<body>");
            out.print("<h3>在线用户列表</h3>");
            int size = ((online == null) ? 0 : online.size());
            for (int i = 0; i < size; i++) {
                if (i > 0) {
                    out.println("<br />");
                }
                out.println(i + 1 + "." + online.get(i));
            }
            out.println("<hr><a href="index.jsp">主页</hr>");
            out.println("</body>");
            out.println("</html>");
            out.flush();
            out.close();
        }
        @Override
        public void destroy() {
            //
        }
        @Override
        public void init() throws ServletException {
            //
        }
    }

    登录页面:index.jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title></title>
    </head>
    <body>
    <form action="login" method="post">
        用户名:<input type="text" name="username">
        <input type="submit" value="登录">
        <br />
        <br />
    </form>
    </body>
    </html>
        5)MultipartConfig标注
        该标注主要是为了辅助Servlet3.0中HttpServletRequest提供的对上传文件的支持。该标注标注在Servlet上,表示该Servlet希望处理的请求的MIME类型是multipart/form-data。
    属性名 类型 是否可选 描述
    fileSizeThreshold int 当数据量大于该值时,内容将被写入文件
    location String 存放生成的文件地址
    maxFileSize long 允许上传的文件最大值。默认值为-1,表示没有限制
    maxRequestSize long 针对该multipart/form-data请求的最大数量,默认值为-1,表示没有限制


    文件上传页面upload.jsp:

    <%@ page contentType="text/html;charset=UTF-8" language="java" import="java.util.*" pageEncoding="UTF-8" %>
    <%
        String path = request.getContextPath();
        String basePath = request.getScheme() + "://" + request.getServerName() + ":"
                + request.getServerPort() + path + "/";
    %>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
    <head>
        <title>Servlet3.0 上传文件</title>
    </head>
    <body>
    <form action="uploadfile" method="post" enctype="multipart/form-data">
        <table>
            <tr>
                <td>
                    选择文件:
                </td>
                <td>
                    <input type="file" name="file"/>
                </td>
            </tr>
            <tr>
                <td>描述:
                </td>
                <td>
                    <input type="text" name="description"/>
                </td>
            </tr>
            <tr>
                <td colspan="2">
                    <input type="submit" value="提交"/>&nbsp;&nbsp;
                    <input type="reset" value="重置"/>
                </td>
            </tr>
        </table>
    </form>
    </body>
    </html>

    处理上传文件的Servlet:

    package com.yyq.servlet3.multipartconfig;
    import javax.servlet.ServletException;
    import javax.servlet.annotation.MultipartConfig;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.Part;
    import java.io.File;
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.util.UUID;
    /**
     * Created by gao on 16-4-14.
     */
    @WebServlet(name = "upFile", urlPatterns = {"/uploadfile"})
    @MultipartConfig(maxFileSize = 500000, maxRequestSize = -1)
    public class FileUploadServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            this.doPost(req, resp);
        }
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //resp.setContentType("text/html;charset=utf-8");
            //获取请求参数值
            Part part = req.getPart("file");
            //存储路径
            String storePath = req.getServletContext().getRealPath("/temp");
            //Servlet3没有提供直接获取文件名,后缀名的方法,需要从请求头中解析出来
            //获取请求头
            String header = part.getHeader("content-disposition");
            //获取文件后缀名
            //String suffix = parseFileName(header);
            String name = parseFileName(header);
            //重新命名
            //String name = UUID.randomUUID() + suffix;
            //把文件写到指定路径
            part.write(storePath + File.separator + name);
    //        PrintWriter out = resp.getWriter();
    //        out.println("上传成功");
    //        out.flush();
    //        out.close();
            //获得文件描述信息
            String description = req.getParameter("description");
            req.setAttribute("f", name);
            req.setAttribute("des", description);
            req.getRequestDispatcher("info.jsp").forward(req, resp);
        }
        /*
        *根据请求头解析出上传文件的后缀名称
        */
        /**
         * 根据请求头解析出文件名
         * 请求头的格式:火狐和google浏览器下:form-data; name="file"; filename="snmp4j--api.zip"
         * IE浏览器下:form-data; name="file"; filename="E:snmp4j--api.zip"
         *
         * @param header 请求头
         * @return 文件名
         */
        public String parseFileName(String header) {
            //return header.substring(header.lastIndexOf("."), header.length() - 1);
            /**
             * String[] tempArr1 = header.split(";");代码执行完之后,在不同的浏览器下,tempArr1数组里面的内容稍有区别
             * 火狐或者google浏览器下:tempArr1={form-data,name="file",filename="snmp4j--api.zip"}
             * IE浏览器下:tempArr1={form-data,name="file",filename="E:snmp4j--api.zip"}
             */
            String[] tempArr1 = header.split(";");
            /**
             *火狐或者google浏览器下:tempArr2={filename,"snmp4j--api.zip"}
             *IE浏览器下:tempArr2={filename,"E:snmp4j--api.zip"}
             */
            String[] tempArr2 = tempArr1[2].split("=");
            //获取文件名,兼容各种浏览器的写法
            String fileName = tempArr2[1].substring(tempArr2[1].lastIndexOf("\") + 1).replaceAll(""", "");
            return fileName;
        }
        @Override
        public void destroy() {
            //
        }
        @Override
        public void init() throws ServletException {
            //
        }
    }

    显示上传文件和描述信息的页面info.jsp:

    <%@ page contentType="text/html;charset=UTF-8" language="java" import="java.util.*" pageEncoding="UTF-8" %>
    <%
        String path = request.getContextPath();
        String basePath = request.getScheme() + "://" + request.getServerName() + ":"
                + request.getServerPort() + path +"/";
    %>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
    <head>
        <title>Servlet3.0 上传文件</title>
    </head>
    <body>
        <h3><%=request.getAttribute("des")%></h3>
        <img alt = "servlet3" src="<%=basePath %>temp/<%=request.getAttribute("f")%>">
    </body>
    </html>
    2、异步处理支持
        Servlet3.0支持异步处理支持,Servlet接收到请求之后,可能首先需要对请求携带的数据进行一些预处理;接着,Servlet线程将请求转交给一个异步线程来执行业务处理,线程本身返回至容器,此时Servlet还没有生成响应数据,异步线程处理完业务以后,可以直接生成响应数据(异步线程拥有ServletRequest和ServletResponse对象的引用),或者将请求继续转发给其他Servlet。
        1)对于使用传统的部署描述文件web.xml配置Servlet和过滤器的情况,Servlet3.0为<servlet>和<filter>标签增加了<async-supported>子标签,该标签的默认取值为false,要启用异步处理支持,则将其设为true即可。
    <servlet>
        <servlet-name>DemoServlet</servlet-name>
        <servlet-class>com.yyq.servlet3.asyncsupported.AsyncDemoServlet</servlet-class>
        <async-supported>true</async-supported>
    </servlet>

       2)对于使用Servlet3.0提供的@WebServlet和@WebFilter进行Servlet或过滤器配置的情况,这两个标注都提供了asyncSupported属性,默认该属性的取值为false,要启动异步处理支持,只需将该属性设置为true即可。

    package com.yyq.servlet3.asyncsupported;
    import javassist.bytecode.analysis.Executor;
    import javax.servlet.AsyncContext;
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.util.Date;
    /**
     * Created by gao on 16-4-15.
     */
    @WebServlet(urlPatterns = {"/asyncdemo"}, asyncSupported = true)
    public class AsyncDemoServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            this.doPost(req, resp);
        }
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            resp.setContentType("text/html;charset=utf-8");
            PrintWriter out = resp.getWriter();
            out.println("进入Servlet的时间:" + new Date() + ".");
            out.flush();
            //在子线程中执行业务调用,并由其负责输出响应,主线程退出
            AsyncContext ctx = req.startAsync();
            new Thread(new Executor(ctx)).start();
            out.println("结束Servlet的时间:" + new Date() + ".");
            out.flush();
        }
        public class Executor implements Runnable {
            private AsyncContext ctx = null;
            public Executor(AsyncContext ctx) {
                this.ctx = ctx;
            }
            public void run() {
                try {
                    //等待10秒钟,以模拟业务方法的执行
                    Thread.sleep(10000);
                    PrintWriter out = ctx.getResponse().getWriter();
                    out.println("业务处理完毕的时间:" + new Date() + ".");
                    out.flush();
                    ctx.complete();
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
        @Override
        public void destroy() {
            //
        }
        @Override
        public void init() throws ServletException {
            //
        }
    }

    启动Tomcat,输入:http://localhost:8080/asyncdemo

     
    3、可插性支持
        Servlet3.0新增的可插性(Pluggability)支持则将Servlet配置的灵活性提升到了新的高度。使用该特性,现在我们可以在不修改已有Web应用的前提下,只需将按照一定格式打包成的JAR包放到WEB-INF/lib目录下,即可实现新的功能的扩充,不需要额外的配置。Servlet3.0引入了称为“Web模块部署描述文件片段”的web-fragment.xml来实现可插性的。web-fragment.xml部署描述文件可以定义一切可以在web.xml中定义的内容。
    1)新建的Servlet类:
    package com.yyq.servlet3.pluggability;
    import javax.naming.NamingException;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.PrintWriter;
    /**
     * Created by gao on 16-4-15.
     */
    public class FragmentDemoServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            this.doPost(req, resp);
        }
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            resp.setContentType("text/html;charset=utf-8");
            PrintWriter out = resp.getWriter();
            out.println("这是我Servlet3.0的第一个可插性示例");
            out.flush();
        }
        @Override
        public void destroy() {
            //
        }
        @Override
        public void init() throws ServletException {
            //
        }
    }

     2)在web目录下新建一个目录META-INF,在该目录下新建一个web-fragment.xml模块部署描述符文件片段:

    <?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="true">
        <!--给当前配置文件定义一个名称-->
        <name>FragmentA</name>
        <servlet>
            <servlet-name>fragmentDemo</servlet-name>
            <servlet-class>com.yyq.servlet3.pluggability.FragmentDemoServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>fragmentDemo</servlet-name>
            <url-pattern>/fragment</url-pattern>
        </servlet-mapping>
    </web-fragment>
    3)将FragmentDemoServlet和META-INF目录一起打包成JAR包,假如JAR包叫fragment.jar。
    4)将fragment.jar放到其他Web项目中的WEBlib目录中,然后访问http://localhost:8080/fragment即可。
     
     
  • 相关阅读:
    非关系数据库之mongodb入门到实战(8)mongodb的常用命令
    非关系数据库之mongodb入门到实战(7)mongodb的window版安装与使用详解
    非关系数据库之mongodb入门到实战(6)mongodb基础详解
    非关系数据库之redis入门到实战(5)Redis企业运用
    非关系数据库之redis入门到实战(4)Redis基本操作
    非关系数据库之redis入门到实战(3)Redis入门介绍与安装
    非关系数据库之redis入门到实战(2)Redis常用命令
    非关系数据库之redis入门到实战(1)Redis高级应用
    Java从入门到实战之(16)面向对象之对象的多态性(四)
    Java从入门到实战之(15)面向对象之接口(三)
  • 原文地址:https://www.cnblogs.com/yangyquin/p/5428914.html
Copyright © 2011-2022 走看看