Servlet3 学习

学习注解定义三大组件遇到的问题

1.注解定义servlet的时候如果 @WebServlet("some") 如果url-pattern前面不加 / 回报以下的错误,和web.xml中定义是一致的。

java 复制代码
java.lang.IllegalArgumentException: Invalid [some] in servlet mapping

2.urlPatterns = {"/some" , "/aaa" , "/bbb"} 和 value= {"/some" , "/aaa" , "/bbb"} 的作用是一样的都是用来定义访问改Servlet的 url-pattern 但是只能用一个 不能两个同事出现

3.如果同一个Servlet的类 既在web.xml中定义 又通过注解@WebServlet定义 那么最终只会注册一个Servlet实例 url-pattern 为 web,xml的url-pattern 和 注解中url-pattern 的并集

例如: web.xml 中 url-pattern为 /ccc @WebServlet中定义的 url-pattern 为 /aaa /bbb .那么该Servlet的最终 url-pattern 为 /aaa /bbb /ccc

4.如果web.xml中Servlet配置如下

XML 复制代码
<servlet>
        <servlet-name>Some-Servlet</servlet-name>
        <servlet-class>com.fll.servletannotation.servlets.SomeServlet</servlet-class>
        <init-param>
            <param-name>address</param-name>
            <param-value>北京</param-value>
        </init-param>
    </servlet>

    <servlet-mapping>
        <servlet-name>Some-Servlet</servlet-name>
        <url-pattern>/ccc</url-pattern>
    </servlet-mapping>

用注解配置如下

java 复制代码
@WebServlet(urlPatterns = {"/some" , "/aaa" , "/bbb"} ,
            initParams = {@WebInitParam(name = "name" , value = "冯亮亮") , @WebInitParam(name = "age" , value = "20")})
public class SomeServlet extends HttpServlet {


    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");

        PrintWriter writer = response.getWriter();
        writer.write("我是通过注解定义的Servlet3.0 <br>");

        Enumeration<String> initParameterNames = this.getInitParameterNames();

        while (initParameterNames.hasMoreElements()){
            String name = initParameterNames.nextElement();
            String value = this.getInitParameter(name);
            writer.write("name=" + name + " value=" + value + "<br>");
        }
    }
}

那么当通过 /some /aaa /bbb 访问是返回的是:

我是通过注解定义的Servlet3.0

name=name value=冯亮亮

name=age value=20

当通过 /ccc 访问的时候 返回的是:

我是通过注解定义的Servlet3.0

name=address value=北京

5.如果 同一个 Filter的类 既在 web.xml url-pattern=/* 中定义了 Filter 又通过 @WebFilter("/*") 定义Filter那么相当于注册的两个独立的 Filter 实例。一个请求如果既符合 web.xml 中的url-pattern 又符合 @WebFilter("/*") 中的 url-pattern 那么这两个 Filter 都会被执行

6.如果同一个 Listener的类 同时在 web.xml 和 @WebListener中定义 Listener 那么只会注册一个 Listener 实例

  1. 当 web.xml 中的 metadata-complete="true" 时所有注解的配置都会失效 false时 注解配置生效
XML 复制代码
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                      http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0" metadata-complete="true">

</web-app>

7.上传文件

java 复制代码
@MultipartConfig
@WebServlet("/upload")
public class UploadServlet extends HttpServlet {


    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        Part filePart = request.getPart("file");
        Collection<String> headers = filePart.getHeaderNames();
        for (String headerName : headers){
            String header = filePart.getHeader(headerName);
            System.out.println(headerName + "=================" + header);
        }
 //打印结果
        //content-disposition=================form-data; name="file"; filename="1501131329.png"
        //content-type=================image/png

        //获取该 part 的文件名
        String fileName = filePart.getSubmittedFileName();

        String realPath = this.getServletContext().getRealPath("/upload");

        String filePath = realPath + "/" + fileName;

        filePart.write(filePath);

    }
}

注意:(1)Servlet类上添加 @MultipartConfig

Annotation that may be specified on a {@link javax.servlet.Servlet} class, indicating that instances of the Servlet expect requests that conform to the multipart/form-data MIME type.

该注解的注释大概意思是: 该注解是被放在Servlet类上的,表明这个Servlet类的实例希望请求遵守 multipart/form-data MIME type.

  1. Servlet异步

获取AsyncContext 对象的时候要用

java 复制代码
AsyncContext asyncContext = request.startAsync();

千万不要使用AsyncContext asyncContext = request.getAsyncContext(); 这个方法是一个递归调用

如果该Servlet的属性 asyncSupported = false 的时候 执行上面的语句回报以下的错误

the processing chain do not support async [com.fll.servletannotation.servlets.AsyncServlet]

java.lang.IllegalStateException: 当前链的筛选器或servlet不支持异步操作。

具体代码如下:

java 复制代码
/**
 * @author fll
 */
@WebServlet(urlPatterns = "/async" , asyncSupported = true)
public class AsyncServlet extends HttpServlet {

    private static Logger logger = LoggerFactory.getLogger(AsyncServlet.class);


    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        System.out.println("================================");


        response.setContentType("text/html;charset=UTF-8");
        final PrintWriter writer = response.getWriter();

        writer.write("主线程开始<br>");

        //AsyncContext asyncContext = request.getAsyncContext();
        final AsyncContext asyncContext = request.startAsync();

        asyncContext.addListener(new AsyncListener() {
            @Override
            public void onComplete(AsyncEvent event) throws IOException {
                logger.info("=============================== onComplete");
            }

            @Override
            public void onTimeout(AsyncEvent event) throws IOException {
                logger.info("=============================== onTimeout");
            }

            @Override
            public void onError(AsyncEvent event) throws IOException {
                logger.info("=============================== onError");
            }

            @Override
            public void onStartAsync(AsyncEvent event) throws IOException {
                logger.info("=============================== onStartAsync");
            }
        });
        //asyncContext.setTimeout(3000);
        asyncContext.start(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    try {
                        Thread.sleep(500);
                        System.out.println("================ " + i);
                        writer.write("================ " + i + "<br>");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                asyncContext.complete();
  //asyncContext.dispatch("show.jsp");
  //asyncContext.dispatch("show.jsp");等价于 request.getRequestDispatcher("show.jsp").include(request , response);同样有通知主线程子线程已经执行完毕的作用  也就是该方法也会将response中的数据写道浏览器中


            }
        });

        writer.write("主线程结束<br>");

    }

}

以上代码 浏览器看到的内容是:

主线程开始

主线程结束

================ 0

================ 1

================ 2

================ 3

================ 4

================ 5

================ 6

================ 7

================ 8

================ 9

说明执行顺序是 主线程线执行完 然后等待asyncContext.complete();执行 一起把数据写到浏览器

如过将超时事件设置为 2秒 打印结果如下:

主线程开始

主线程结束

================ 0

================ 1

================ 2

================ 3

================ 4

说明 当超时的时候也会自动将response中的数据写到浏览器中

同步线程执行完成得通知 asyncContext.complete(); 如果不执行该语句 主线程会一直等待异步线程的执行完成 知道超时 默认的超时时间是 30秒。也可以asyncContext.setTimeout(3000);修改超时时间 超时之后监听器的onTimeout方法会被回调。

相关推荐
love_and_hope7 分钟前
Pytorch学习--神经网络--搭建小实战(手撕CIFAR 10 model structure)和 Sequential 的使用
人工智能·pytorch·python·深度学习·学习
Chef_Chen10 分钟前
从0开始学习机器学习--Day14--如何优化神经网络的代价函数
神经网络·学习·机器学习
芊寻(嵌入式)20 分钟前
C转C++学习笔记--基础知识摘录总结
开发语言·c++·笔记·学习
WaaTong21 分钟前
《重学Java设计模式》之 原型模式
java·设计模式·原型模式
m0_7430484421 分钟前
初识Java EE和Spring Boot
java·java-ee
AskHarries23 分钟前
Java字节码增强库ByteBuddy
java·后端
小灰灰__43 分钟前
IDEA加载通义灵码插件及使用指南
java·ide·intellij-idea
夜雨翦春韭1 小时前
Java中的动态代理
java·开发语言·aop·动态代理
hong1616881 小时前
跨模态对齐与跨领域学习
学习
程序媛小果1 小时前
基于java+SpringBoot+Vue的宠物咖啡馆平台设计与实现
java·vue.js·spring boot