一 Servlet概述
- servlet= server+applet 运行在服务器端的java程序。
- Servlet是一个接口(规范),一个类要想通过浏览器被访问到,那么这个类就必须直接或间接的实现Servlet接口
作用
接收请求,处理业务,响应结果
二 Servlet快速入门
目标:编写一个普通的java类,通过浏览器可以访问
#编写步骤
1. 定义一个类,实现Servlet接口,重写所有的抽象方法(特别是service方法)
2. 配置web.xml
2.1 代码编写
① 创建web项目
② 编写普通java类,实现servlet接口
重写抽象方法(service方法)
package com.itheima01.servlet;
import javax.servlet.*;
import java.io.IOException;
/*
* ctrl+i(implements) : 提示重写所有抽象方法
* ctrl+ enter: 万能提示
* */
public class MyServlet implements Servlet {
/*
* servletRequest : 请求
* servletResponse : 响应
* */
@Override
public void service(ServletRequest servletRequest,
ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("接收到请求"); //控制台打印
servletResponse.getWriter().print("hello servlet");//响应给浏览器
}
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
③ 配置web.xml
配置servlet网络访问路径
<?xml version="1.0" encoding="UTF-8"?>
<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_3_1.xsd"
version="3.1">
<!--
1. servlet和servlet-mapping标签里都有servlet-name子标签
内部文本可以随意命名,但是必须一致
2. servlet-class标签: 写Servlet实现类的全限定名(包名+类名)
3. url-pattern : 指定的是该Servlet的虚拟路径
-->
<servlet>
<servlet-name>MyServlet01</servlet-name>
<servlet-class>com.itheima01.servlet.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet01</servlet-name>
<url-pattern>/myServlet</url-pattern>
</servlet-mapping>
</web-app>
④ 部署web项目
⑤ 启动测试
2.2 执行原理
三 Servlet相关API
3.1 生命周期方法
3.1.1 思想介绍
- 生命周期:指的是一个对象从生(创建)到死(销毁)的一个过程
// 1. servlet对象创建时,调用此方法
public void init(ServletConfig servletConfig);
// 2. 用户访问servlet时,调用此方法
public void service(ServletRequest servletRequest, ServletResponse servletResponse);
// 3. servlet对象销毁时,调用此方法
public void destroy();
* 创建
1)默认情况下
用户第一次访问时,创建servlet,执行init方法
2)修改创建时机
<load-on-startup></load-onstartup>
正数:4-N 【服务器启动时,创建】
补充:Tomcat的web.xml里有1,3 所以推荐4-n
负数(默认值):-1 【用户第一次访问时,创建】
* 运行(提供服务)
用户每次访问时,都执行service方法
* 销毁
服务器正常关闭时,销毁servlet,执行destroy方法
3.1.2 代码演示
① LifeServlet
package com.itheima02.lifecycle;
import javax.servlet.*;
import java.io.IOException;
/*
* 1. servlet的api(方法) -> 生命周期方法
* 2. 生命周期(lifecycle) : 从创建到销毁的整个过程
* 3. servlet的重要三个方法
* 1). init : 初始化
* a. 此方法默认Servlet第一次被访问的时候调用
* b. 适合做一些数据初始化工作
*
* 2). service : 活动 (最重要)
* a. 此方法Servlet每次被访问,都会执行一次
* b. 这是servlet的核心方法(接收请求,业务处理,响应数据)
*
* 3). destroy : 销毁
* a. 此方法是tomcat关闭的时候调用一次
* b. 这个方法适合资源释放,数据保存
*
* 注意: 每新增一个Servlet,由于tomcat要重新读取配置信息,所以必须重启tomcat
*
* 测试:
* 浏览器第一次访问: 执行一次 init, service
* 浏览器再次访问 : 每访问一次,执行一次service
* 关闭tomcat的时候: 执行一次 destroy
* */
public class LifeServlet implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("init");
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("service");
}
@Override
public void destroy() {
System.out.println("destroy");
}
// 了解: 这两个方法是servlet配置相关(一般不怎么用了)
@Override
public ServletConfig getServletConfig() {
System.out.println("getServletConfig");
return null;
}
@Override
public String getServletInfo() {
System.out.println("getServletInfo");
return null;
}
}
② 配置web.xml
<!--
书写规范:
1. servlet-name虽然可以自定义,但是一般与类名相同(见名知意)
2. servlet的虚拟路径: 必须/开头, 可以自定义,一般是类名的小驼峰写法
-->
<servlet>
<servlet-name>LifeServlet</servlet-name>
<servlet-class>com.itheima02.lifecycle.LifeServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LifeServlet</servlet-name>
<url-pattern>/lifeServlet</url-pattern>
</servlet-mapping>
3.1.3 启动加载
# 启动加载
* 1)问题: 发现 init 默认第一次被访问的时候才调用,适合用来初始化项目数据
* 如果项目数据很多, 加载就需要一定的时候,这样就会给第一个用户的体验不好,因为要等比较久
*
* 2)解决: 服务器一启动,就执行init方法
*
* 3) 实现: 要在web.xml配置
<servlet>
<servlet-name>LifeServlet</servlet-name>
<servlet-class>com.itheima02.lifecycle.LifeServlet</servlet-class>
<!--
启动加载:
<load-on-startup> n </load-on-startup>
n取值必须是整数
1) n < 0 , 表示第一次被访问的时候才加载(默认-1)
2) n >= 0, tomcat 一启动就会加载这个servlet(创建对象,并调用init方法)
a. 数字越小,优先级越高
b. 我们一般取值n>=4, tomcat已经默认占用前几位
(tomcat/conf/web.xml 全局配置文件)
-->
<load-on-startup>4</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>LifeServlet</servlet-name>
<url-pattern>/lifeServlet</url-pattern>
</servlet-mapping>
四 Servlet体系结构
快捷键:
1. ctrl + alt + u : 查看一个类的继承结构图
2. ctrl + h : 这个类的简化版继承结构
4.1 GenericServlet
1. 问题:
Servlet中使用频率最高,最重要的方法是service方法(大部分场景)
但是我们每次编写Servlet实现类,都是直接实现Servlet接口,重写5个抽象方法(太冗余了)
2. 需求: 如果我们以后编写Servlet实现类,只要重写service方法就好了
3. 解决:
1) 定义一个类 GenericServlet implements Servlet
2) 重写除service方法之外其他抽象方法 -> GenericServlet 只剩下一个service抽象方法
-> GenericServlet就保存起来 (适配器设计模式)
3) 以后,我们再编写 Servlet实现类,只要extends GenericServlet,重写service方法即可
a. 我们的类依然是Servlet实现类(因为继承可以多重继承: B继承A, C继承B)
b. 我们的类依然可以重写其他方法(GenericServlet普通方法也可以被重写)
4. 发现: 好巧啊,GenericServlet不需要我们写,因为开发包已经提供了
① 编写普通java类,继承GenericServlet抽象类
public class GoodServlet extends GenericServlet {
@Override
public void init() throws ServletException {
System.out.println("其他方法如果有需要,也可以重写");
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("GoodServlet被访问了~~");
}
}
② 配置web.xml
<servlet>
<servlet-name>GoodServlet</servlet-name>
<servlet-class>com.itheima03.generic.GoodServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>GoodServlet</servlet-name>
<url-pattern>/goodServlet</url-pattern>
</servlet-mapping>
4.2 HttpServlet
1. 问题:
我们在请求中,学习过有两种常用的请求方式(get/post)
我们现在的service方法是这样的: 用户发送请求,无论是什么请求方式,都会统一的执行service方法, 我们无法很好的区别是哪一种请求方式
2. 需求: 我们如果想确切的知道是哪一种请求方式,必须要先了解HttpServletRequest
3. 解决: 自己封装了一个MyHttpServlet -> 开发包 HttpServlet
// 拥有抽象方法的类必须是抽象类
// 抽象doGet和doPost的目的: 为了封装
// 以后,只要定义一个类继承MyHttpServlet,重写 doGet和doPost就可以了
// 可以通过执行的方法就可以区分到底是哪一种请求
public abstract class MyHttpServlet extends GenericServlet {
/*
* ServletRequest : 这个对象包含了请求报文内容(兼容大部分协议)
* 请求行: 里面有请求方式
* */
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
//简单的来说, 父类类型调用不了子类特有方法,所以要强转
// 因为我们的协议确实是http协议,强转是没有问题的
HttpServletRequest request = (HttpServletRequest) servletRequest;
// 获取请求方式
String method = request.getMethod();
if("post".equalsIgnoreCase(method)){
//如果是post请求,执行doPost方法
doPost((HttpServletRequest)servletRequest,(HttpServletResponse)servletResponse);
}else if("get".equalsIgnoreCase(method)){
//如果是get请求,执行doGet方法
doGet((HttpServletRequest)servletRequest,(HttpServletResponse)servletResponse);
}
}
//如果是get请求,执行doGet方法 -> 实际上就是只处理get请求的service方法
public abstract void doGet(HttpServletRequest servletRequest, HttpServletResponse servletResponse);
//如果是post请求,执行doPost方法 -> 实际上就是只处理post请求的service方法
public abstract void doPost(HttpServletRequest servletRequest, HttpServletResponse servletResponse);
}
① 编写前端html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>login</title>
</head>
<body>
<!--
表单的提交按钮被点击, 提交数据到action地址(没有请求参数)
前端中发送的请求,不指定默认get
-->
<h1>get请求</h1>
<form action="http://localhost:8080/day08-servlet_xml/betterServlet" method="get">
<input type="submit">
</form>
<h1>post请求</h1>
<form action="http://localhost:8080/day08-servlet_xml/betterServlet" method="post">
<input type="submit">
</form>
</body>
</html>
② 编写普通java类,继承HttpServlet抽象类
/*
* 浏览器访问,如果不指定请求方式,默认是get
* */
public class BetterServlet extends HttpServlet {
@Override
public void doGet(HttpServletRequest servletRequest, HttpServletResponse servletResponse) {
System.out.println("执行的get方法: 具体业务");
}
@Override
public void doPost(HttpServletRequest servletRequest, HttpServletResponse servletResponse) {
System.out.println("执行的post方法 : 具体业务");
}
}
③ 配置web.xml
<servlet>
<servlet-name>BetterServlet</servlet-name>
<servlet-class>com.itheima04.http.BetterServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>BetterServlet</servlet-name>
<url-pattern>/betterServlet</url-pattern>
</servlet-mapping>
4.3 经验值分享
① 响应状态码405
请求方法没有重写…
/*
注意: 如果我们不重写doGet/doPost方法, 那么父类的doGet/doPost方法会执行(继承)
给浏览器响应一个错误: 状态码405 (http1.1)
*/
** 响应状态码500**
java代码写错了…
五 Servlet路径
5.1 url-pattern
作用:将一个请求网络地址和servlet类建立一个映射关系
5.1.1 Servlet映射多个url
5.1.2 url映射模式【了解】
配置 <url-pattern> url地址取值可以是:
```markdown
1. 精确匹配(掌握)
/servletDemo3
2. 目录匹配
/aa/*
3. 后缀匹配
*.xxx 例如:*.do
<!--
现在浏览器地址栏输入: (http://localhost:8080/day08-servlet_xml)
通过 /urlServlet01 就可以访问到 UrlServlet
1. 一个servlet的url可以设置多个
<servlet-mapping>标签设置多个
/urlServlet01 和 /urlServlet02 都可以访问UrlServlet
作用: 其实没什么用,了解即可(为过滤器做铺垫)
2. 路径匹配模式
a. 精确匹配(掌握)
/urlServlet01
b. 目录匹配
/aa/* (* 符号匹配所有)
c. 后缀匹配
*.xxx 例如:*.do (前面不要加/)
访问的url后缀名带do就可以访问到
-->
<servlet-mapping>
<servlet-name>UrlServlet</servlet-name>
<url-pattern>/urlServlet01</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>UrlServlet</servlet-name>
<url-pattern>/aa/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>UrlServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
5.2 相对/绝对路径
- 现阶段我们访问资源的方式越来越多,请求路径在编写时难免出现混淆
- 浏览器的地址栏 (输入地址,敲回车会发送请求)
- a标签的href属性 (超链接被点击的时候会发送请求)
- form表单的action属性 (form中的submit按钮被点击的时候,发送请求)
- js的loation.href属性 (只要设置, 触发相应的)
- ajax请求地址
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="http://www.baidu.com">超链接</a> <br>
<form action="http://www.baidu.com">
<input type="text" name="username"> <br>
<input type="submit">
</form>
<input type="button" value="按钮" id="myid">
<script>
//js
document.getElementById("myid").onclick = function () {
//bom对象: window,location地址栏
location.href = "http://www.baidu.com"
}
</script>
</body>
</html>
这里我们复习下路径规则:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--
1. 绝对路径
a. 完整路径: http://localhost:8080/day08-servlet_xml/urlServlet01
b. 简要写法: /day08-servlet_xml/urlServlet01 (只要在本项目内,省略三要素, 协议://ip:port)
(推荐)
2. 相对路径 (不推荐)
web/test下的url.html ->
http://localhost:8080/day08-servlet_xml/test/url.html
发现:
http://localhost:8080/day08-servlet_xml/urlServlet01
观察: /urlServlet01 是 /test/url.html
相对: url.html 要找到urlServlet01, 先回到上一级,才能找到
符号:
./ 当前路径 可以省略
../ 上一级
-->
<a href="http://localhost:8080/day08-servlet_xml/urlServlet01">访问/urlServlet01_完整路径</a> <br>
<a href="/day08-servlet_xml/urlServlet01">访问/urlServlet01_简略路径</a> <br>
<hr>
<a href="../urlServlet01">访问/urlServlet01_相对路径</a> <br>
</body>
</html>
5.3 ServletConfig
ServletConfig概述 它是Servlet的配置参数对象,在Servlet规范中,允许为每个Servlet都提供一些初始化配置。所以,每个Servlet都一个自己的ServletConfig。它的作用是在Servlet初始化期间,把一些配置信息传递给Servlet。
生命周期
由于它是在初始化阶段读取了web.xml中为Servlet准备的初始化配置,并把配置信息传递给Servlet,所以生命周期与Servlet相同。这里需要注意的是,如果Servlet配置了<load-on-startup>1</load-on-startup>
,那么ServletConfig也会在应用加载时创建。
如何获取
首先,我们要清楚的认识到,它可以为每个Servlet都提供初始化参数,所以肯定可以在每个Servlet中都配置。那是配置在Servlet的声明部分,还是映射部分呢?我们接下来先准备一个Servlet,然后给同学们揭秘。
/**
* 演示Servlet的初始化参数对象
* @author 黑马程序员
* @Company http://www.itheima.com
*/
public class ServletDemo8 extends HttpServlet {
//定义Servlet配置对象ServletConfig
private ServletConfig servletConfig;
/**
* 在初始化时为ServletConfig赋值
* @param config
* @throws ServletException
*/
@Override
public void init(ServletConfig config) throws ServletException {
this.servletConfig = config;
}
/**
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//输出ServletConfig
System.out.println(servletConfig);
}
/**
* 调用doGet方法
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
<!--配置ServletDemo8-->
<servlet>
<servlet-name>servletDemo8</servlet-name>
<servlet-class>com.itheima.web.servlet.ServletDemo8</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>servletDemo8</servlet-name>
<url-pattern>/servletDemo8</url-pattern>
</servlet-mapping>
如何配置
在上一小节中,我们已经准备好了Servlet,同时也获取到了它的ServletConfig对象,在本小节中我们将告诉同学们如何配置初始化参数,它需要使用<servlet>
标签中的<init-param>
标签来配置。这也就揭秘上一小节的悬念,Servlet的初始化参数都是配置在Servlet的声明部分的。并且每个Servlet都支持有多个初始化参数,并且初始化参数都是以键值对的形式存在的。接下来,我们看配置示例:
<!--配置ServletDemo8-->
<servlet>
<servlet-name>servletDemo8</servlet-name>
<servlet-class>com.itheima.web.servlet.ServletDemo8</servlet-class>
<!--配置初始化参数-->
<init-param>
<!--用于获取初始化参数的key-->
<param-name>encoding</param-name>
<!--初始化参数的值-->
<param-value>UTF-8</param-value>
</init-param>
<!--每个初始化参数都需要用到init-param标签-->
<init-param>
<param-name>servletInfo</param-name>
<param-value>This is Demo8</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>servletDemo8</servlet-name>
<url-pattern>/servletDemo8</url-pattern>
</servlet-mapping>
/**
* 演示Servlet的初始化参数对象
* @author 黑马程序员
* @Company http://www.itheima.com
*/
public class ServletDemo8 extends HttpServlet {
//定义Servlet配置对象ServletConfig
private ServletConfig servletConfig;
/**
* 在初始化时为ServletConfig赋值
* @param config
* @throws ServletException
*/
@Override
public void init(ServletConfig config) throws ServletException {
this.servletConfig = config;
}
/**
* doGet方法输出一句话
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.输出ServletConfig
System.out.println(servletConfig);
//2.获取Servlet的名称
String servletName= servletConfig.getServletName();
System.out.println(servletName);
//3.获取字符集编码
String encoding = servletConfig.getInitParameter("encoding");
System.out.println(encoding);
//4.获取所有初始化参数名称的枚举
Enumeration<String> names = servletConfig.getInitParameterNames();
//遍历names
while(names.hasMoreElements()){
//取出每个name
String name = names.nextElement();
//根据key获取value
String value = servletConfig.getInitParameter(name);
System.out.println("name:"+name+",value:"+value);
}
//5.获取ServletContext对象
ServletContext servletContext = servletConfig.getServletContext();
System.out.println(servletContext);
}
/**
* 调用doGet方法
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
5.4ServletContext
基本介绍 ServletContext对象,它是应用上下文对象。每一个应用有且只有一个ServletContext对象。它可以实现让应用中所有Servlet间的数据共享。
生命周期
出生——活着——死亡
出生: 应用一加载,该对象就被创建出来了。一个应用只有一个实例对象。(Servlet和ServletContext都是单例的)
活着:只要应用一直提供服务,该对象就一直存在。
死亡:应用被卸载(或者服务器挂了),该对象消亡。
域对象概念
域对象的概念,它指的是对象有作用域,即有作用范围。
域对象的作用,域对象可以实现数据共享。不同作用范围的域对象,共享数据的能力不一样。
在Servlet规范中,一共有4个域对象。今天我们讲解的ServletContext就是其中一个。它也是我们接触的第一个域对象。它是web应用中最大的作用域,叫application域。每个应用只有一个application域。它可以实现整个应用间的数据共享功能。
如何获取
在讲解ServletConfig对象时,我们已经看到了获取ServletContext对象的方式,它只需要调用ServletConfig对象的getServletContext()
方法就可以了。具体代码如下:我们创建一个新的Servlet用于演示ServletContext。
/**
* 用于演示ServletContext对象的使用
* @author 黑马程序员
* @Company http://www.itheima.com
*/
public class ServletDemo9 extends HttpServlet {
//定义Servlet配置对象ServletConfig
private ServletConfig servletConfig;
/**
* 在初始化时为ServletConfig赋值
* @param config
* @throws ServletException
*/
@Override
public void init(ServletConfig config) throws ServletException {
this.servletConfig = config;
}
/**
*
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取ServletContext对象
ServletContext servletContext = servletConfig.getServletContext();
System.out.println(servletContext);
}
/**
* 调用doGet方法
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
<!--配置ServletDemo9-->
<servlet>
<servlet-name>servletDemo9</servlet-name>
<servlet-class>com.itheima.web.servlet.ServletDemo9</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>servletDemo9</servlet-name>
<url-pattern>/servletDemo9</url-pattern>
</servlet-mapping>
在实际开发中,如果我们每个Servlet对ServletContext都使用频繁的话,那么每个Servlet里定义ServletConfig,再获取ServletContext的代码将非常多,造成大量的重复代码。Servlet规范的定义中也为我们想到了这一点,所以它在GenericServlet中,已经为我们声明好了ServletContext获取的方法,如下图所示:
我们的Servlet都是继承自HttpServlet,而HttpServlet又是GenericServlet的子类,所以我们在获取ServletContext时,如果当前Servlet没有用到它自己的初始化参数时,就可以不用再定义初始化参数了,而是直接改成下图所示的代码即可:
如何配置
ServletContext既然被称之为应用上下文对象,所以它的配置是针对整个应用的配置,而非某个特定Servlet的配置。它的配置被称为应用的初始化参数配置。
配置的方式,需要在<web-app>
标签中使用<context-param>
来配置初始化参数。具体代码如下:
<!--配置应用初始化参数-->
<context-param>
<!--用于获取初始化参数的key-->
<param-name>servletContextInfo</param-name>
<!--初始化参数的值-->
<param-value>This is application scope</param-value>
</context-param>
<!--每个应用初始化参数都需要用到context-param标签-->
<context-param>
<param-name>globalEncoding</param-name>
<param-value>UTF-8</param-value>
</context-param>
六 Servlet3.0
- 通过注解配置Servlet,简化web.xml配置Servlet复杂性,提高开发效率,几乎所有的框架都在使用注解
① 创建web工程【注解】
② 编写普通java类,继承HttpServlet
public class QuickServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("QuickServlet....3.0");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("QuickServlet....3.0");
}
}
③ 配置@WebServlet
// @WebServlet(name = "QuickServlet",urlPatterns = "/quickServlet")
// @WebServlet(urlPatterns = "/quickServlet")
// @WebServlet(value = "/quickServlet")
@WebServlet("/quickServlet") // 注解中有且仅有一个属性,名为value时,属性名可以省略...
public class QuickServlet extends HttpServlet {
}
idea创建web模块的规律
tomcat可以同时运行多个web模块,但是现在一般只运行一个模块
注意: project structure中要设置这两项
手动创建容器
1)前置说明
在使用Servlet3.1版本的规范时,脱离了web.xml进行注解开发,它除了支持使用注解的配置方式外,还支持纯手动创建Servlet容器的方式。要想使用的话,必须遵循它的编写规范。它是从Servlet3.0规范才开始引入的,加入了一个新的接口:
package javax.servlet;
import java.util.Set;
/**
* 初始化Servlet容器必须实现此接口
* 它是Servlet3.0规范提供的标准接口
* @since Servlet 3.0
*/
public interface ServletContainerInitializer {
/**
* 启动容器时做一些初始化操作,例如注册Servlet,Filter,Listener等等。
* @since Servlet 3.0
*/
void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException;
}
同时可以利用@HandlesTypes注解,把要加载到onStartup方法中的类字节码传入进来,@HandlesTypes源码如下:
/**
* 用于指定要加载到ServletContainerInitializer接口实现了中的字节码
* @see javax.servlet.ServletContainerInitializer
* @since Servlet 3.0
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface HandlesTypes {
/**
* 指定要加载到ServletContainerInitializer实现类的onStartUp方法中类的字节码。
* 字节码可以是接口,抽象类或者普通类。
*/
Class[] value();
}
2)编写步骤
第一步:创建工程,并移除web.xml
第二步:编写Servlet
/**
* 注解开发Servlet 之 手动初始化容器
* @author 黑马程序员
* @Company http://www.itheima.com
*/
public class ServletDemo1 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 {
System.out.println("Servlet Demo1 Annotation manual");
}
}
第三步:创建初始化容器的类,并按照要求配置
/**
* 初始化容器操作
* @author 黑马程序员
* @Company http://www.itheima.com
*/
public class MyServletContainerInitializer implements ServletContainerInitializer {
@Override
public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
}
}
在脱离web.xml时,要求在src目录下包含一个META-INF目录,位置和及字母都不能改变,且严格区分大小写。在目录中创建一个名称为javax.servlet.ServletContainerInitializer
的文件,里面写实现了ServletContainerInitializer
接口的全限定类名。如下图所示:
第四步:编写注册Servlet的代码
第五步:测试