Servlet
前言
之前我们学习Tomcat,Servlet的运行强依赖Tomcat这种Web容器。
Servlet是Server Applet的简称,中文意思是运行在Web服务器端中的小程序。整个Java Web的核心知识体系都是围绕Servlet来展开的。
Servlet是什么?
Servlet就是接口,定义了Java类可以被Tomcat所识别并实例化的规则。
如果定义1个类,实现Servlet接口,实现Serlet中的规定的方法,就可以被Web服务器软件(Tomcat)所识别和调用,从而开发1个Java Web程序。
Servlet快速入门
1.web.xm设置如下
在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"> <servlet> <servlet-name>zhanggenservlet-name> <servlet-class>com.zhanggen.servlet.ServletDemo1servlet-class> servlet> <servlet-mapping> <servlet-name>zhanggenservlet-name> <url-pattern>/zhanggenurl-pattern> servlet-mapping> web-app>web.xml
2.创建类
在src目录下新增如下包和类
package com.zhanggen.servlet; import javax.servlet.*; import java.io.IOException; public class ServletDemo1 implements Servlet { @Override public void init(ServletConfig servletConfig) throws ServletException { } @Override public ServletConfig getServletConfig() { return null; } @Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { System.out.println("Helow Servlet"); } @Override public String getServletInfo() { return null; } @Override public void destroy() { } }ServletDemo1.java
3.servlet执行原理
用户通过http://127.0.0.1:8080/zhanggen这个URL地址访问Tomcat。
Tomcat接收用户请求之后读取web.xml配置,查询url-pattern标签中内容,锁定ServletDemo1这个Java类。
Tomcat将ServletDemo1类对应的Class字节文件加载到内存。
Tomcat实例化ServletDemo1类创建其对象,调用其对象中定义的service()方法。
4.servlet的生命周期
Servlet的实现类(ServletDemo1)中的方法就是servlet的生命周期。
package com.zhanggen.servlet; import javax.servlet.*; import java.io.IOException; public class ServletDemo1 implements Servlet { /* * init()方法:Servlet的初始化方法 * 当用户访问Tomcat,Tomcat读取web.xml配置文件,Servelt被创建的时,执行。只会执行一次。 * */ @Override public void init(ServletConfig servletConfig) throws ServletException { System.out.println("初始化"); } /* *getServletConfig()方法:获取ServletConfig对象的 * ServletConfig:Servlet的配置对象 * */ @Override public ServletConfig getServletConfig() { return null; } /* * service()方法:提供Serlet服务 * 每1次Servlet被访问时,执行。会被执行多次。 * * */ @Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { System.out.println("1111111"); } /* * getServletInfo()方法:获取Servlet的信息,版本,作者等。 * */ @Override public String getServletInfo() { return null; } /* * destroy() 销毁方法 *在servlet被销毁时执行,只会执行1次 * */ @Override public void destroy() { System.out.println("销毁"); } }ServletDemo1.java
A.Servlet实现类的对象被Tomcat创建,执行init()方法,只执行1次。单例模式。
B.对象提供服务:执行service()方法,执行多次。
C.对象被Tomcat销毁:执行destroy()方法,只执行1次。
5.Servlet生命周期详解
A.init()方法
Servlet实现类的对象被创建时,只会执行一次init方法。
默认情况下,Servlet第一次被访问时,Servlet实现类的对象被创建
可以通过配置web.xml控制执行Servlet的创建时机:
<servlet> <servlet-name>zhanggenservlet-name> <servlet-class>com.zhanggen.servlet.ServletDemo1servlet-class> <load-on-startup>6load-on-startup> servlet>
Servlet的实现类对象是单例的,在内存中只会存在1个。
多个用户同时访问Servlet时,可能存在线程安全的问题。
尽量不要再Servlet中定义成员变量,即使定义了成员变量,也不要对其进行修改。
B.service()方法
每次访问Servlet时,service()方法都会被调用一次。
C.destroy()方法
只有Tomcat服务器正常关闭时,才会执行destory()方法。
在destory()执行在Servlet实现类对象被销毁之前,一般用于释放资源。
6.注解配置
通过web.xml配置Servlet,一旦新增了URL就需要增加1对servlet和servlet-mapping配置项。
在Servlet 3.0版本之后开始支持通过注解的方式配置Servlet,而不是通过web.xml配置文件配置Servlet。
package cn.zhanggen.web.servlet; import javax.servlet.*; import javax.servlet.annotation.WebServlet; import java.io.IOException; //@WebServlet(urlPatterns = "/index") @WebServlet("/index") public class ServletDemo implements Servlet { @Override public void init(ServletConfig servletConfig) throws ServletException { } @Override public ServletConfig getServletConfig() { return null; } @Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { System.out.println("Servlet 3.0 来了"); } @Override public String getServletInfo() { return null; } @Override public void destroy() { } }ServletDemo.java
Servlet的体系结构
Servlet是1个接口,该接口下面有2个抽象类分别为:
GenericServlet抽象类:GenericServlet是Servlet接口的抽象类,将Servlet接口中其他方法做了默认空实现,只将service()方法做为抽象。
将来定义Servlet类时,可以继承GenericServlet,实现service()方法即可,简化操作。
package cn.zhanggen.web.servlet; import javax.servlet.GenericServlet; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import java.io.IOException; public class ServletDemo extends GenericServlet { @Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { } }
HttpServlet抽象类:HttpServlet是继承了GenericServlet的抽象类,对http协议进行了封装,简化操作。
package cn.zhanggen.web.servlet; import javax.servlet.GenericServlet; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet("/zhanggen") public class ServletDemo extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("doGet方法在执行"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { super.doPost(req, resp); } }
Servlet的请求和响应
当用户发起http请求到Tomcat服务器之后,Tomcat服务器会创建1对request和response对象。
开发人员使用request对象获取请求信息,使用response对象来设置响应消息。
1.request对象继承关系
servletRequest 接口
|继承
HttpServletRequest接口
|实现
org.apache.catalina.connector.RequestFacade
Tomcat通过org.apache.catalina.connector.RequestFacade类来创建request对象,并且传递给service()方法。
2.request对象获取请求消息
HTTP请求信息可分为请求行(请求的URL)、请求头和请求体信息。
A.获取请求行信息
package cn.zhanggen.web.servlet; import javax.servlet.GenericServlet; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet("/zhanggen") public class ServletDemo extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //1.获取请求方式:GET或者POST System.out.println(req.getMethod()); //2.获取虚拟目录 System.out.println(req.getContextPath()); //3.获取Servlet 路径 System.out.println(req.getServletPath()); //4.获取请求参数字符串 System.out.println(req.getQueryString()); //5.获取URI(统一资源标识符):/zhanggen System.out.println(req.getRequestURI()); //6.获取URL(统一资源定位符):http://127.0.0.1:8080/zhanggen System.out.println(req.getRequestURL()); //7.获取协议版本 System.out.println(req.getProtocol()); //8.获取客户机的IP地址 System.out.println(req.getRemoteAddr()); System.out.println("doGet方法在执行"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { super.doPost(req, resp); } }
B.获取请求头信息
package cn.zhanggen.web.servlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Enumeration; @WebServlet("/index") public class ServletDemo1 extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1.获取所有请求头名称 EnumerationheaderNames = request.getHeaderNames(); while (headerNames.hasMoreElements()) { String name = headerNames.nextElement(); String value = request.getHeader(name); System.out.println(name + "<------------------->" + value); } //2.获取agent使用的浏览器信息:可用于浏览器兼容性 String agent = request.getHeader("user-agent"); System.out.println(agent); //3.获取refer信息可以进行防盗链操作:http://localhost:8080/login.html System.out.println(request.getHeader("referer")); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException { } }
C.获取请求体信息
只有POST请求才会有请求体信息。
获取字符输入流:
BufferedReader bufferReader = request.getReader();
protected void doPost(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException { //1.获取字符流 BufferedReader bufferReader = request.getReader(); String line = null; while ((line = bufferReader.readLine()) != null) { System.out.println(line); } }
获取字节输入流:
ServletInputStream inputStream = request.getInputStream();
3.获取请求参数通用方式
以下方法可以获取GET和POST请求携带的参数和值
package cn.zhanggen.web.servlet; import javax.servlet.ServletException; import javax.servlet.ServletInputStream; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.BufferedReader; import java.io.IOException; import java.util.Arrays; import java.util.Enumeration; import java.util.Map; import java.util.Set; @WebServlet("/index") public class ServletDemo1 extends HttpServlet { @Override protected void doPost(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException { //1.获取请求参数信息:根据名称获取参数值,GET和POST请求通用。 String username = request.getParameter("username"); String password = request.getParameter("password"); //2.获取多选框的值 String[] cars = request.getParameterValues("cars"); System.out.println(username); System.out.println(password); System.out.println(Arrays.toString(cars)); //3.获取所有参数的名称 EnumerationparameterNames = request.getParameterNames(); while (parameterNames.hasMoreElements()) { String s = parameterNames.nextElement(); System.out.println(s); } //4.获取所有参数和值的map集合 Map parameterMap = request.getParameterMap(); Set keyset = parameterMap.keySet(); for (String name : keyset) { String[] values = parameterMap.get(name); System.out.println(Arrays.toString(values)); } } }
4.获取请求参数乱码问题
package cn.zhanggen.web.servlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet("/zhanggen66") public class ServletDemo3 extends HttpServlet { @Override protected void doPost(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException { //1.设置字符流的编码 request.setCharacterEncoding("utf-8"); String username = request.getParameter("username"); System.out.println(username); } }
5.请求转发
package cn.zhanggen.web.servlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet("/zhanggen66") public class ServletDemo3 extends HttpServlet { @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); //1.转发请求 //request.getRequestDispatcher("/index").forward(request, resp); //2.响应字符串 response.setCharacterEncoding("utf-8"); response.setHeader("Content-Type", "text/html;charset=utf-8"); response.getWriter().write("登录成功"); } }
6.Request对象数据共享
1个servlet对应1个URL,那么当不同的Servlet直接如何共享数据呢?
request.setAttribute("msg","222"); //设置数据
Object msg = request.getAttribute("msg"); //获取数据
msg=(String)msg;
System.out.println(msg);
request.removeAttribute("msg"); //删除数据
参考