这里写自定义目录标题
- Servlet
静态资源不会创建session,而加载jsp页面的时候会创建session
Servlet
1.Servlet的概念
概念:Servlet(Server Applet) 是Java Servlet 的简称,运行在服务器端的Java组件,用Java编写服务器端程序。
作用:用来接收、处理客户端请求,响应给浏览器的动态资源。在整个Web应用中,Servlet主要负责处理请求、协调调度功能。此时我们可以把Servlet称为Web应用中的 【控制器】
2 Servlet的使用
自定义Servlet 的需要两个东西。
- 实现java.serlvet.Servlet接口或继承其子类。
- 对自定义的Servlet 进行配置和映射。
2.1 目标
在页面上点击超链接,由Servlet处理这个请求,并返回一个响应字符串。
2.2 两种思路
2.2.1 使用xml配置(建议使用,后期方便维护)
2.2.1.1 创建动态Web module
如果有不会创建的,可以看我这篇文章
2.2.1.2 在jsp页面编写
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>用户登录</title>
</head>
<body>
<form action="login" method="get"> <!-- 这里的action 取值 和 下面的映射保持一致-->
<p> 用户名:<input name="username"></p>
<p> 密 码:<input name="password" type="password"></p>
<input type="submit" value="立即登录">
</form>
</body>
</html>
2.2.1.3 编写Servlet类
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException {
System.out.println("========doGet============");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException {
System.out.println("=========doPost===========");
}
}
2.2.1.4 编写web.xml配置
<servlet>
<!-- 给 Servlet 在此xml中起的逻辑名,和类名无关,可以任意定义取名符合规范即可-->
<servlet-name>LoginServlet</servlet-name>
<!-- 要配置和映射的 Servlet 完整类名-->
<servlet-class>com.zhang.servlet.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<!-- 和上面的逻辑名对应的 Servlet 逻辑名-->
<servlet-name>LoginServlet</servlet-name>
<!-- 给 Servlet 的映射名,客户端请求此 Servlet 使用的名字-->
<url-pattern>/login</url-pattern>
</servlet-mapping>
注意:在xml配置里的< url-pattern>/映射名</ url-pattern> 中的映射名用于客户端请求的路径,斜杠不能省略,这个一定要和页面提交的action的值对应。
映射支持通配符:/login/、.jsp等写法。
2.2.2 使用注解
与使用xml配置唯一不同的是,使用注解时不需要配置xml(两者不能同时使用),只需在类名上面加一句 @WebServlet(“/映射路径”)
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException {
System.out.println("========doGet============");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException {
System.out.println("=========doPost===========");
}
}
使用注解的好处: 代码更加简单。
使用注解的坏处: 耦合度高。
3. Servlet的生命周期
概念: Servlet的生命周期就是Servlet从创建到销毁的过程。并且它的生命周期完全由容器来决定的。实例的创建、初始化、调用、销毁都是由Tomcat容器来完成的。
3.1 servlet的生命周期的方法
-
实例化(创建):构造方法()------ 容器来调用
-
初始化:init() ----------- 一次
该方法会在Servlet实例对象创建出来之后执行,我们可以在该方法中获取当前Servlet的初始化参数,以及进行一些读取配置文件之类的操作。
-
服务:service() ----------- 多次
该方法会在Servlet实例对象每次接收到请求的时候均执行,我们可以在该方法中接收、处理请求,以及将客户端需要的数据响应给客户端。
-
销毁:destroy() ----------- 一次
该方法会在Servlet实例对象销毁之前执行,我们可以在该方法中做一些资源回收、释放、关闭等等操作。注意这个方法并不是来销毁servlet对象的。
3.2 Servlet的创建和销毁时间
Servlet对象的创建时间:默认情况下是在第一次有请求访问该Servlet实例的时候才会创建该Servlet对象。
Servlet对象的销毁时间: 在服务器关闭或当前项目从服务器中移除的时候会销毁当前项目中的所有Servlet对象。
3.3 在xml配置Servlet提前创建
Servlet 生命周期中的第一个阶段是实例化,整个生命周期中执行一次。
注意:
① 默认情况下,servlet的实例化(创建)是在第一次被请求访问时,由Servlet容器来完成实例化。
② 通过xml配置,可以让servlet随服务器启动时,创建和初始化servlet。
③ 默认值为负数,如果启动时,并不会被加载实例化。
④ 如果需要让servlet随服务器启动时进行实例化和初始化,可以让< load-on-startup>配置为大于等于0的值
⑤ 当配置不同的servlet的< load-on-startup>为相同值时,那么就按照写的顺序来加载。
<!-- 配置Servlet本身 -->
<servlet>
<!-- 全类名太长,给Servlet设置一个简短名称 -->
<servlet-name>LoginServlet</servlet-name>
<!-- 配置Servlet的全类名 -->
<servlet-class>com.zhang.servlet.LoginServlet</servlet-class>
<!-- -配置服务器启动时,配置Servlet启动顺序 -->
<load-on-startup>0</load-on-startup>
</servlet>
3.4 Servlet的初始化
Servlet 的初始化阶段是在 Servlet 实例化之后。
初始化方法在生命周期中只执行一次,Servlet API提供两个初始化方法,即一个有参,另一个无参。
源码中声明:
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
public void init() throws ServletException {
}
注意: 我们在自己的Servlet中,可以重写初始化方法
3.4.1 ServletConfig接口
此接口中的方法有:
方法名 | 作用 |
---|---|
getServletName() | 获取<servlet-name>LoginServlet</servlet-name>定义的Servlet名称 |
getServletContext() | 获取ServletContext对象(即全局域对象application) |
getInitParameter(String var1) | 获取配置Servlet时设置的『初始化参数』,根据名字获取值 |
getInitParameterNames() | 获取所有初始化参数名组成的Enumeration对象 |
概述: ServletConfig是作为 init()方法的参数类型。
我们通过在xml文件配置初始化参数,然后在通过Servlet类的带参的初始化方法获取其值。
web.xml的代码
<!-- 配置Servlet本身 -->
<servlet>
<!-- 全类名太长,给Servlet设置一个简短名称 -->
<servlet-name>LoginServlet</servlet-name>
<!-- 配置Servlet的全类名 -->
<servlet-class>com.zhang.servlet.LoginServlet</servlet-class>
<!-- 配置初始化参数 -->
<init-param>
<param-name>initCount</param-name>
<param-value>18000</param-value>
</init-param>
<!-- -配置服务器启动时,配置Servlet启动顺序 -->
<load-on-startup>0</load-on-startup>
</servlet>
java中servlet的代码
注意: 可以通过参数config获取web.xml中配置的初始化参数
@Override
public void init(ServletConfig config) throws ServletException {
// 获取单独的初始化参数值用此方法
String initCount = config.getInitParameter("initCount");
System.out.println("======>>"+initCount);
}
// 获取多个初始化参数值用此方法
Enumeration<String> enumeration = this.servletConfig.getInitParameterNames();
while (enumeration.hasMoreElements()) {
String initCount= enumeration.nextElement();
System.out.println("initCount= " + initCount);
String value = this.servletConfig.getInitParameter(initCount);
System.out.println("initCount= " + value);
}
3.5 服务(service方法)
注意: service()每次请求时都会执行的方法,根据请求的方式不同,调用对应的doGet和doPost方法
@Override
protected void service(HttpServletRequest request, HttpServletResponse resp)throws ServletException, IOException {
System.out.println("======service()=====");
String method = request.getMethod();
if("GET".equalsIgnoreCase(method)){
this.doGet(request,resp);
}else if("POST".equalsIgnoreCase(method)){
this.doPost(request,resp);
}
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throwsServletException, IOException {
System.out.println("=======doGet()====");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throwsServletException, IOException {
System.out.println("========doPost()====");
3.6 销毁(destroy方法)
注意: 此方法不是销毁servlet对象,而是在销毁servlet对象之前会调用的方法,提供程序来做善后处理的工作。
@Override
public void destroy() {
System.out.println("LoginServlet对象即将销毁,现在执行清理操作");
}
3.7 servlet的三种映射路径的配置
3.7.1 映射路径的作用
Servlet的映射路径是提供一个让别人能够访问该Servlet的路径,例如Servlet的映射路径是"/login",那么在浏览器上访问该Servlet的路径是http://localhost:8080/项目部署名/login
注意:一个Servlet可以配置多个映射路径,但是多个Servlet不能配置相同的映射路径
3.7.2 映射路径的分类
3.7.2.1 完全路径匹配
访问当前Servlet的路径需要和配置的映射路径完全一致,例如Servlet的配置是"login",那么访问该Servlet的时候的路径也必须是http://localhost:8080/项目部署名/login
才可以访问到
3.7.2.2 目录匹配
以 /
开始需要以 *
结束,注意: Servlet里面用的不多, 但是过滤器里面通常就使用目录匹配
3.7.2.1 扩展名匹配
以*
开头,以.扩展名
结束,能够匹配所有以.相同扩展名
结尾的请求路径
3.8 Servlet的应用
3.8.1 session的获取
- getSession()无参, 默认等价于getSession(true)
- .getSession(false) : 获取session 对象,如果获取不到,则返回null。
- getSesssion(true): 获取session 对象,如果获取不到,则会自动创建一个新的session 对象,并返回
HttpSession session = request.getSession(false|true);
HttpSession session = request.getSession();
3.8.2 ServletContext
概念: 服务器为其部署的每一个应用(项目)都创建了一个ServletContext对象。ServletContext属于整个项目的,该项目中的所有Servlet都可以共享同一个ServletContext对象
3.8.2.1 获取ServletContext的方法
// 直接调用Servlet自身的getServletContext()方法获取
ServletContext ServletContext = getServletContext();
// 调用ServletConfig接口的getServletContext方法
ServletContext ServletContext = servletConfig.getServletContext();
// HttpServletRequest对象也实现了ServletConfig接口,所以也有getServletContext()方法
ServletContext ServletContext = request.getServletContext();
3.8.2.2 ServletContext获取全局的初始化参数
在web.xml中配置Web应用级别的初始化参数
<context-param>
<param-name>username</param-name>
<param-value>hahahaha</param-value>
</context-param>
在Servlet的doGet或doPost方法中获取全局参数
String username = servletContext.getInitParameter("username");
System.out.println("获取全局的初始化参数username=" + username);
3.8.2.3 ServletContext作为全局域对象
ServletContext作为全局域对象可以在整个项目的所有动态资源(包含所有Servlet)中进行数据共享。
往全局域对象中存入数据
servletContext.setAttribute("key",value)
从全局域对象中取出数据
Object value = ServletContext.getAttribute("key");
3.8.2.4 获取资源的真实路径
为什么要获取资源的真实路径?
因为如果以后要拷贝服务器上的代码的话,你的路径肯定会发生变化的,所以应该要使用代码动态获取资源的真实路径。
获取所需用到的API。
ServletContext servletContext= getServletContext();
String realPath = servletContext.getRealPath("资源在web目录中的路径");
使用动态获取真实路径的优点:
只要使用了servletContext动态获取资源的真实路径,那么无论项目的部署路径发生什么变化,都会动态获取项目运行时候的实际路径,所以就不会发生由于写死真实路径而导致项目部署位置改变引发的路径错误问题
3.8.3 解决乱码问题
注意: 乱码处理一定区分是请求乱码还是响应乱码,并且在doGet或doPost方法中处理乱码问题,或者在过滤器中处理(之后会为讲如何在过滤器中处理乱码问题)
- 从客户端提交的数据出现乱码的,属于请求乱码,要设置请求对象
request.setCharacterEncoding("utf-8");
- 在向客户端输出显示乱码,属于响应乱码,在response 对象中设置
resonsep.setContentType("text/html;charset=utf-8");
3.9 Servlet的体系结构
Servlet类的结构
Servlet接口有一个实现类是GenericServlet,而GenericServlet有一个子类是HttpServlet,我们创建Servlet的时候会选择继承HttpServlet,因为它里面相当于也实现了Servlet接口,并且对一些方法做了默认实现;而且子类的功能会比父类的更加强大。
Servlet类的方法之间的关系
当Servlet类继承HttpServlet的时候,只需要重写doGet()和doPost()方法就行了。因为HttpServlet重写了service()方法,在service()方法中判断请求方式,根据不同的请求方式执行相对应的请求方法。
3.10 手动快速创建Servlet类
第一步
创建成功后出现以下情况。