学习注解定义三大组件遇到的问题
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 实例
- 当 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.
- 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方法会被回调。