五 Servlet
5.1 Servlet介绍
Servlet是运算在服务器上的一个java程序,简单说,它就是一个java类。我们要使用servlet,需要导入servlet的api.
------------------------------
5.2 服务器编译环境设置
------------------------------
5.3 Servlet的入门
5.3.1 入门案例
package servlet;
//1,自定义类继承HttpServlet
public class Demo01Servlet extends HttpServlet {
//2,重写doGet和doPost方法
//doGet:处理get请求
//doPost:处理post请求
//在doGet方法中调用doPost方法,不管是 get请求 or post请求,都交给doGet方法处理
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//处理get请求
System.out.println("Demo01Servlet doGet");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//处理post请求
doGet(req, resp);
}
}
web/WEB-INF/web.xml
<?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_4_0.xsd"
version="4.0">
<!--3,配置Servlet-->
<!--3.1,声明Servlet-->
<servlet>
<!--servlet的名称-->
<servlet-name>Demo01Servlet</servlet-name>
<!--servlet的全类名-->
<servlet-class>com.qfedu.servlet.Demo01Servlet</servlet-class>
</servlet>
<!--
3.2,给Servlet设置访问名称
Servlet should have a mapping
-->
<servlet-mapping>
<!--servlet的名称-->
<servlet-name>Demo01Servlet</servlet-name>
<!--servlet的访问名称-->
<url-pattern>/demo01</url-pattern>
</servlet-mapping>
</web-app>
5.3.2 执行流程
浏览器发起请求: http://localhost:8080/day50/demo01
就会在服务器中找访问名称为demo01的Servlet -> Demo01Servlet
请求的处理就交给了Demo01Servlet的实例,根据请求方式get/post,决定是给doGet还是doPost方法处理
5.3.3 注意事项
不管是get请求还是post请求,对于服务器来说,没差别
get请求将请求参数放到请求网址
post请求将请求参数放到请求正文
服务器最终无非就要获取请求参数。getParameter()方法
------------------------------
5.4 Servlet详解
HttpServlet继承于GenericServlet、GenericServlet实现于Servlet,也就是说Servlet是顶层接口
5.4.1 Servlet处理请求
- Servlet接口下有一个实现类叫GenericServlet,GenericServlet有一个子类HttpServlet.
- 在Servlet接口中定义了一个方法service,它的主要作用是处理来自浏览器的请求操作。在service方法的重载的方法中,对请求方式进行判断,如果是GET就会调用doGet方法,如果是POST就会调用doPost方法。
5.4.2 创建Servlet的三种方式
- 方式一:实现Servlet接口
在servlet接口中,没有doGet和doPost方法,处理请求是service方法(抽象的)
- 方式二:继承GenericServlet类
在GenericServlet类中,没有doGet和doPost方法,处理请求是service方法(抽象的)
- 方式三:继承HttpServlet类
HttpServlet类中重写service方法。
根据源码,发现重写service方法中,
有将ServletRequest强转为HttpServletRequest,
将ServletResponse强转为HttpServletResponse
以上强转是因为,ServletRequest和ServletResponse并没有针对Http协议做优化!!!无法专门针对http协议调用方法!!
HttpServletRequest和HttpServletResponse有针对http协议做优化!!!
在开发中,一般应用比较多的是使用extends HttpServlet,优点是它是与http协议相关
的,封装了http协议相关的操作。
------------------------------
5.5 Servlet生命周期
在javax.servlet.Servlet接口中定义了三个方法init service destroy它们就是servlet的生命周期
方法
public interface Servlet {
//监听Servlet的初始化
void init(ServletConfig var1) throws ServletException;
ServletConfig getServletConfig();
//处理请求
void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
String getServletInfo();
//监听Servlet的销毁
void destroy();
}
- 调用构造方法创建Sevlet对象(Servlet是单例的,构造方法只执行一次)
- 调用init方法,进行初始化操作(只执行一次)
- 当有请求访问Servlet时,会执行service方法(每次请求都执行),在父类HttpServlet中,重写service方法,会把请求分发给doPost()和doGet()方法
- 当容器关闭时,会执行destroy方法,销毁对象,释放资源
------------------------------
5.6 load-on-startup配置
根据Servlet生命周期,可知,servlet默认不会随着服务器的启动而初始化
load on startup可以让servlet随着服务器的启动而初始化
对于load-on-startup它的可以配置的值有10个,1代表优先级最高,数值越大,优先级越低
------------------------------
5.7 Servlet配置
5.7.1 自定义Servlet
对于servlet,我们需要在web.xml文件中对其进行配置
- 在web.xml中声明Servlet
<servlet>
<servlet-name>Demo01Servlet</servlet-name>
<servlet-class>servlet.Demo01Servlet</servlet-class>
</servlet>
---------------
- 在web.xml中给Servlet映射访问路径
<servlet-mapping>
<servlet-name>Demo01Servlet</servlet-name>
<url-pattern>/demo01</url-pattern>
</servlet-mapping>
一个<servlet>可有多个<servlet-mapping>与其对应
5.7.2 < url-parttern >书写规则
- 完全匹配
要求网址上的访问名称完全和<url-parttern>一致
必须以"/"开头,否则会报错:IllegalArgumentException : Invalid <url-pattern>
---------------
- 目录匹配
要求网址上的访问名称中的目录和<url-parttern>一致
必须以"/"开头,以"*"结尾
比如:/a/b/* , 目录必须是/a/b,后面随便写
---------------
- 后缀名匹配
要求网址上的访问名称中的后缀和<url-parttern>一致
不能以"/"开头,以"*"开头,后缀名根据业务写
比如:*.xyz。后缀名必须是xyz,其他随意写!!!
------------------------------
5.8 缺省Servlet
创建一个servlet时,如果它的url-pattern的配置值为”/”这时这个servlet就是一个缺省的
servlet,tomcat服务器中默认就有缺省Servlet
- 缺省Servlet的作用
凡是在web.xml文件总找不到匹配的<servlet-mapping>元素的URL,它们的请求都将交给
缺省Servlet处理。也就是说,缺省的servlet用于处理其他Servlet处理不了的请求
当访问tomcat服务中的静态资源(html、图片等等)时,实际上是在访问这个缺省的servlet
- 自定义缺省Servlet
在当前工程中自定义Servlet,将url-parttern设置为"/",就覆盖了tomcat容器中的缺省Servlet
- 应用
SpringMVC框架中,用于放行静态资源
------------------------------
5.9 服务器中路径
- 带协议的绝对路径
http://localhost:8080/day51/img/girl.jpg
- 不带协议的绝对路径
/day51/img/girl.jpg
- 相对路径
当前目录:./ ,可以省略
上一级目录:../
------------------------------
5.10 ServletConfig对象
ServletConfig是javax.servlet.包下的一个接口。ServletConfig它是Servlet的一个配置对象
ServletConfig对象是由服务器创建的,它是通过Servlet的init方法传递到Servlet中
- 作用
获取Servlet名称 getServletName
获取Servlet初始化参数 getInitParameter getInitParameterNames
获取ServletContext对象
getInitParameter(String parameterName):根据参数名称获取指定的参数值
getInitParameterNames():获取所有的参数名称
获取域对象:ServletContext
public class Demo11Servlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletConfig servletConfig = getServletConfig();
String servletName = servletConfig.getServletName();
System.out.println(servletName+"正在运行...");
System.out.println("--------------------");
String username = servletConfig.getInitParameter("username");
System.out.println(username);
String password = servletConfig.getInitParameter("password");
System.out.println("--------------------");
Enumeration<String> parameterNames = servletConfig.getInitParameterNames();
while (parameterNames.hasMoreElements()){
String parameterName = parameterNames.nextElement();
String parameterValue = servletConfig.getInitParameter(parameterName);
System.out.println("name"+parameterName+"password"+parameterValue);
}
ServletContext servletContext = getServletContext();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
<servlet>
<servlet-name>Demo11Servlet</servlet-name>
<servlet-class>servlet.Demo11Servlet</servlet-class>
<init-param>
<param-name>username</param-name>
<param-value>root</param-value>
</init-param>
<init-param>
<param-name>password</param-name>
<param-value>root123</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Demo11Servlet</servlet-name>
<url-pattern>/demo11</url-pattern>
</servlet-mapping>
------------------------------
5.11 ServletContext对象
相当于是整个应用程序对象
5.11.1 介绍
- ServletContext它是javax.servlet包下的一个接口
- 当服务器启动时,会为服务器中的每一个web应用程序创建一个ServletContext对象,一个ServletContext对象对应的就是一个web应用程序
- 对于ServletContext,我们叫它上下文对象,ServletConfig对象中维护了ServletContext对象,也就是说,我们可以通过ServletConfig对象来获取ServletContext对象
- 在web应用中的servlet要想实现资源的共享,可以通过ServletContext来完成,
ServletContext也叫做域对象
5.11.2 ServletContext对象作用
- 实现Servlet资源共享
ServletContext是一个域对象,可以用来存储数据.可以将它想像成一个Map<String,Object>,可以通过它实现Servlet资源共享
在应用程序中的任何位置都能够访问
* getAttribute(String parameterName) : 获取ServletContext域中指定名称的参数值
* setAttribute(String paramterName,Object parameterValue):存储参数到ServletContext域中
* removeAttribute(String parameterNam):将ServletContext域中指定名称的参数移除
---------------
- 获取全局初始化参数
在web.xml中配置的全局初始化参数,可以通过ServletContext对象获取
public class Demo15Servlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = getServletContext();
Enumeration<String> parameterNames = servletContext.getInitParameterNames();
while (parameterNames.hasMoreElements()){
String parameterName = parameterNames.nextElement();
String parameterValue = servletContext.getInitParameter(parameterName);
System.out.println("name:"+parameterName+"value:"+parameterValue);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
<context-param>
<param-name>username</param-name>
<param-value>root</param-value>
</context-param>
<servlet>
<servlet-name>Demo15Servlet</servlet-name>
<servlet-class>servlet.Demo15Servlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Demo15Servlet</servlet-name>
<url-pattern>/demo15</url-pattern>
</servlet-mapping>
---------------
- 获取资源在服务器上的真实磁盘路径
getRealPath:依据当前项目去生成真实磁盘路径
servletContext.getRealPath("upload"):当前项目的服务器磁盘路径/upload
servletContext.getRealPath("upload/img"):当前项目的服务器磁盘路径/upload/img
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = getServletContext();
String upload = servletContext.getRealPath("upload");
System.out.println(upload);
}
------------------------------
5.12 ServletContext综合案例
- 需求:统计站点访问次数
public class Demo17Servlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1 获取ServletContext对象
ServletContext servletContext = getServletContext();
//2 判断是否第一次
Integer count = (Integer) servletContext.getAttribute("count");
if (count == null) {
//2.1 第一次访问
count = 1;
System.out.println(count);
servletContext.setAttribute("count", count);
} else {
//2.2 非第一次访问
count++;
System.out.println(count);
servletContext.setAttribute("count", count);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
------------------------------
5.13 Servlet3.0
支持注解开发,由注解配置来代替web.xml配置
- 在Servlet类上直接使用@WebServlet注解
@WebServlet(name = "Demo01Servlet", urlPatterns = {"/demo01", "/mydemo01"},
initParams = {@WebInitParam(name = "username", value = "root"),
@WebInitParam(name = "password", value = "123456")})
---------------
- 常用属性
name:String:设置Servlet名称
urlPatterns:String[]:设置Servlet的访问路径
loadOnStartup:int:设置Servlet的load-on-startup属性
initParams:WebInitParam[]:设置Servlet的初始化参数