目录
HttpServletRequest接口:请求对象:获取请求信息
HttpServletResponse接口 响应对象: 设置响应对象
ServletContextListener(Servlet全局监听器)
简介
运行在B/S架构上的一种技术(规范)
Servlet是Server Applet的简称,翻译过来就是服务程序。是由sun公司提供的一门用于开发动态Web资源的技术。简单的讲,Servlet就是运行在服务器上的一个小程序,用来处理服务器接收到的请求。
ps:软件服务架构
-
C/S:Client/Server(QQ,微信)
-
B/S:Browser/Server(浏览器/服务器)
比如一般的网页程序,是由我们通过浏览器来访问实现的,在这个过程中,我们的浏览器发送访问请求,服务器接收到请求,并对浏览器的请求做出相应的处理,而Servlet就是对请求做出处理的组件,运行于支持java的应用服务器中;
作用:数组操作
MVC模型(模型 - 界面 - 控制器)
ps:最经典的MVC模型:JSP+JavaBean+Servlet开发模式。
Servlet在其中承担的作用是Controller(控制器),起到对数据进行操作的作用;
Servlet处理的信息:请求报文
Web应用完全是基于http协议的。而http有请求报文(request)和响应报文(response),请求报文就是浏览器向服务器发送的数据形成的数据对象,同理,响应报文就是服务器向浏览器发送的数据形成的数据对象,而http有两个重要的方法,doPost()和doGet()方法。
服务器的请求类型(由接口HttpServlet得到):
-
post
-
get
-
delete
-
head
-
options
-
put
-
trace
Servlet的工作模式:
-
客户端发送请求至服务器
-
服务器启动并调用Servlet,Servlet根据客户端请求生成响应内容并将其传给服务器
-
服务器将响应返回客户端
说明:
用户请求致使Servlet容器调用Servlet的Service()方法,并传入一个ServletRequest对象和一个ServletResponse对象。ServletRequest对象和ServletResponse对象都是由Servlet容器(例如TomCat)封装好的,并不需要程序员去实现,程序员可以直接使用这两个对象。
Tomcat工作原理:
Servlet的开发流程
(一):实现Servlet接口或者继承HttpServlet类
ps:继承HttpServlet类更简洁更常用。
(二):重写HttpServlet类的doGet()和doPost()方法
(三):配置web.xml文件或者使用注解对servlet进行配置
1,在maven配置文件pom.xml中导入Servlet - API的依赖
<dependencies> <!-- 引入servlet3.1的依赖 --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <!-- 引入jstl的依赖,jsp页面中会使用到 --> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependencies>
2,使用web.xml配置servlet访问路径
<servlet> <servlet-name>hello</servlet-name> <servlet-class>com.*****.servlet.test01_servlet</servlet-class> <load-on-startup>2</load-on-startup> </servlet> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping>
<servlet-name>:Servlet的名字
<servlet-class>:servlet的路径
<url-pattern>:浏览器访问Servlet的映射地址
3,使用注解配置servlet访问路径
使用注解配置访问路径,更加简洁常用;
Servlet的生命周期
生命周期:就是Servlet什么时候创建,调用了何种方法,最后在什么时候被销毁;java对象都是自己手动创建的,最后由JVM来销毁,而Servlet的整个生命周期,都是由tomcat服务器来控制的。
Servlet的生命周期是:实例化 -->初始化 -->多次调用service服务 --> tomcat容器关闭时销毁
-
默认情况下Servlet是在第一次访问的时候实例化和初始化的
-
第一次访问就会调用service()服务方法
-
直到关闭服务器时,Servlet才会被销毁
-
tomcat在调用对象映射的时候,启动无参构造器穿件servlet对象(并且Servlet是单例的);
-
也可以通过load-on-startup标签(web.xml中的)可以配置项目启动时创建Servlet对象(实例化+初始化);并且load-on-startup数字越小越先被创建;ps:此操作也可以通过注解@WebServlet来配置;
Servlet获取参数的方法
主要解析Servlet获取get和post参数的方式,主要有三种:
-
使用getParameter()获取参数方法,单个获取。
-
使用getParameterMap()获取Map键值对参数的方法。
-
get特有的查询字符串的方法以及post以流的形式查询字符串的方法:get获取的是浏览器中URL地址栏访问路径?后面的参数,而post是从请求体中获取参数,这两者获取到的字符串参数都是URL编过码的,所以在获取参数时候都需要解码。
(1),get特有的查询字符串的方法
(2),post以流的形式查询字符串的方法
注意:获取流查询字符串参数的方式要放在最前面执行,因为流是只能消耗一次,放在其它操作过流的方法后面该方法就获取不到数据了,因为流被消耗了。
Servlet响应页面和数据
响应页面:
就是收到前端的请求响应需要跳转的页面。Servlet响应页面有转发和重定向两种方式
1,转发:携带客户端发送的请求转发跳转到下一个页面,使用的是request请求对象。
//转发可以将请求中的数据带到新的页面。 //getRequestDispatcher():表示获取请求转发器的方法 //forward():表示将请求及响应对象一并转发到下一个新页面 request.getRequestDispatcher("跳转页面路径").forward(request,response);
2,重定向:服务器接收到前端请求,通过响应将要跳转的页面地址响应给客户端,客户端再重新发送请求跳转到目标页面。
//重定向是将要跳转的页面路径交给前端重新发送请求跳转页面。 //相当于客户端发送了两次请求,所以原来请求中的数据就没有了。 response.sendRedirect("响应的页面路径")
响应数据:
数据通过流的方式响应给前端,这里主要用到的是一条打印流,响应数据一般都是响应的json格式的数据,前端获取到json格式的数据就相当于拿到了一个对象,通过对象的方式去获取数据。
获取到打印流响应普通数据(注意:有乱码要设置编码格式)
响应json字符串格式的数据
Servlet的线程安全问题:
同一个Servlet在服务器中只会存在一个实例,不论是多少个访问,都调用的是同一个实例,也就是Servlet是单实例多线程的。这就存在着一定的线程安全问题,如果在Servlet中定义一个全局变量,那么程序运行这个变量的值很有可能会不是我们所预期的,所以在Servlet中要尽量避免使用全局变量
解决方法:
-
把使用到共享数据的代码块进行同步(使用synchronized关键字进行同步)
-
在servlet类中尽量不要使用成员变量。如果确实要使用成员,必须同步,而且尽量缩小同步代码块的范围(哪里使用到了成员变量,就同步哪里!!),以避免因为同步而导致并发效率降低。
-
在servlet类中不使用共享数据,就不影响servlet的正常使用。
HttpServlet
HttpServlet是Servlet中的主角,虽然GenericServlet是对Servlet的一个很好加强,但是也不经常使用,而更近常使用的是HttpServlet,原因如下:
-
HttpServlet是由GenericServlet抽象类继承而来的,相较于GenericServlet更高级了;
-
HttpServlet之所以运用广泛的另一个原因是现在大部分的应用程序都要与HTTP结合起来使用。这意味着我们可以利用HTTP的特性完成更多更强大的任务。
HttpServlet抽象类:
HttpServlet抽象类覆盖了GenericServlet抽象类中的Service( )方法,并且添加了一个自己独有的Service(HttpServletRequest request,HttpServletResponse response)方法。
Http实现GenericServlet抽象类中的Service( )方法源码:
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
HttpServletRequest request;
HttpServletResponse response;
try {
request = (HttpServletRequest)req;
response = (HttpServletResponse)res;
} catch (ClassCastException var6) {
throw new ServletException("non-HTTP request or response");
}
this.service(request, response);
}
由此可以看出:使用HttpServlet抽象类时,还需要借助分别代表Servlet请求和Servlet响应的HttpServletRequest和HttpServletResponse对象。其中HttpServletRequest接口扩展于javax.servlet.ServletRequest接口,HttpServletResponse接口扩展于javax.servlet.servletResponse接口;
然后在调用自身的service()方法,源码展示:
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getMethod();
long lastModified;
if (method.equals("GET")) {
lastModified = this.getLastModified(req);
if (lastModified == -1L) {
this.doGet(req, resp);
} else {
long ifModifiedSince = req.getDateHeader("If-Modified-Since");
if (ifModifiedSince < lastModified) {
this.maybeSetLastModified(resp, lastModified);
this.doGet(req, resp);
} else {
resp.setStatus(304);
}
}
} else if (method.equals("HEAD")) {
lastModified = this.getLastModified(req);
this.maybeSetLastModified(resp, lastModified);
this.doHead(req, resp);
} else if (method.equals("POST")) {
this.doPost(req, resp);
} else if (method.equals("PUT")) {
this.doPut(req, resp);
} else if (method.equals("DELETE")) {
this.doDelete(req, resp);
} else if (method.equals("OPTIONS")) {
this.doOptions(req, resp);
} else if (method.equals("TRACE")) {
this.doTrace(req, resp);
} else {
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[]{method};
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(501, errMsg);
}
}
从源码可以看出,我们一般调用的是继承的service方法,然后在调用自己的service方法,由自身service()方法再分别针对http的请求类型调用不同的处理方法:doGet,doPost,doHead,doPut,doTrace,doOptions和doDelete(其中doGet和doPost是最常用的);
HttpServlet有两个特性是GenericServlet所不具备的:
-
不用覆盖service方法,而是覆盖doGet或者doPost方法。在少数情况,还会覆盖其他的5个方法。
-
使用的是HttpServletRequest和HttpServletResponse对象。
HttpServletRequest接口:请求对象:获取请求信息
HttpServletRequest表示Http环境中的Servlet请求。它扩展于javax.servlet.ServletRequest接口,所以我们一次总结一下在我们的servlet继承于HttpServlet的情况下request对象所拥有的方法:
首先是ServletRequest接口的方法:
int getContentLength();//返回请求主体的字节数
String getContentType();//返回主体的MIME类型
String getParameter(String var1);//返回请求参数的值
接下来时HttpServletRequest接口的方法:
String getContextPath();//返回请求上下文的请求URI部分
Cookie[] getCookies();//返回一个cookie对象数组
String getHeader(String var1);//返回指定HTTP标题的值
String getMethod();//返回生成这个请求HTTP的方法名称
String getQueryString();//返回请求URL中的查询字符串
HttpSession getSession();//返回与这个请求相关的会话对象
Request代表请求。所以我们通过分析Request对象分别获得来自于HTTP的请求行,请求头,请求体;
HTTP请求的格式:
请求行:占一行,说明请求方式(POST/GET)请求资源,以及HTTP协议的版本(主流为1.1/1.0); 请求头:请求头的格式为键值对:key:value;请求头是浏览器自动封装的,这是浏览器要告知服务器的信息; (空行) 请求体:请求参数,get提交:请求参数在url地址的后面,标志?开始后是参数(例:?username=zs&password=123);post提交:请求参数在HTTP请求体中封装
通过request获得请求行
假设查询字符串为:username=zhangsan&password=123
获得客户端的请求方式:String getMethod()
获得请求的资源:
String getRequestURI()
StringBuffer getRequestURL()
String getContextPath() ---web应用的名称
String getQueryString() ---- get提交url地址后的参数字符串
通过request获得请求头
long getDateHeader(String name)
String getHeader(String name)
Enumeration getHeaderNames()
Enumeration getHeaders(String name)
int getIntHeader(String name)
referer头的作用:执行该此访问的的来源,做防盗链
通过request获得请求体
请求体中的内容是通过post提交的请求参数,格式是:username=zhangsan&password=123&hobby=football&hobby=basketball
通过一下方法得到请求参数:
String getParameter(String name)
String[] getParameterValues(String name)
Enumeration getParameterNames()
Map<String,String[]> getParameterMap() get请求方式的请求参数 上述的方法一样可以获得。
HttpServletResponse接口 响应对象: 设置响应对象
response对象的格式:
通过Response设置响应:
void addCookie(Cookie var1);//给这个响应添加一个cookie
void addHeader(String var1, String var2);//给这个请求添加一个响应头
void sendRedirect(String var1) throws IOException;//发送一条响应码,讲浏览器跳转到指定的位置
void setStatus(int var1);//设置响应行的状态码
addHeader(String name, String value)
addIntHeader(String name, int value)
addDateHeader(String name, long date)
setHeader(String name, String value)
setDateHeader(String name, long date)
setIntHeader(String name, int value)
//add表示添加,而set表示设置
PrintWriter getWriter()//获得字符流,通过字符流的write(String s)方法可以将字符串设置到response缓冲区中,随后Tomcat会将response缓冲区中的内容组装成Http响应返回给浏览器端。
ServletOutputStream getOutputStream()//获得字节流,通过该字节流的write(byte[] bytes)可以向response缓冲区中写入字节,再由Tomcat服务器将字节内容组成Http响应返回给浏览器。
ps:虽然response对象的getOutSream()和getWriter()方法都可以发送响应消息体,但是他们之间相互排斥,不可以同时使用,否则会发生异常。
乱码问题的解决
service中使用的编码解码方式默认为:ISO-8859-1编码,但此编码并不支持中文,因此会出现乱码问题,所以我们需要手动修改编码方式为UTF-8编码,才能解决中文乱码问题;
-
解决post提交方式的乱码:request.setCharacterEncoding("UTF-8");
-
解决get提交的方式的乱码:parameter = newString(parameter.getbytes("iso8859-1"),"utf-8");
-
更改response的编码方式:response.setCharacterEncoding("UTF-8");
-
但是由此还是不能解决乱码问题,因为浏览器接收端仍然使用GB2312方式编码,解决方式:response.setHeader("Content-Type","text/html;charset=UTF-8");
-
针对response的第二种方式:response.setContentType("text/html;charset=UTF-8");包含了3,4两个方法的调用;
ServletConfig接口:servlet配置对象
创建时间:在创建完servlet对象的时候,接着创建servletConfig对象.
方法:
String getServletName();//获得Servlet在web.xml中配置的那么的值 String getInitParameter(String name);//获得servlet的初始化参数 Enumeration getInitParameterNames();//获得servlet所以初始化参数的名称;
ServletContext对象:servlet上下文对象
ServletContext对象表示Servlet应用程序。每个Web应用程序都只有一个ServletContext对象。在将一个应用程序同时部署到多个容器的分布式环境中,每台Java虚拟机上的Web应用都会有一个ServletContext对象。
作用:共享从应用程序中的所有资料处访问到的信息,并且可以动态注册Web对象。前者将对象保存在ServletContext中的一个内部Map中,保存在ServletContext中的对象被称作属性。
ServletContext中的方法:
Object getAttribute(String var1);//获取数据 Enumeration<String> getAttributeNames();//以集合的形式获取数据 void setAttribute(String var1, Object var2);//保存数据 void removeAttribute(String var1);//删除数据
ServletContextListener(Servlet全局监听器)
ServletContextListener是一个接口,我们随便写一个类,只要这个类实现了ServletContextListener接口,那么这个类就实现了【监听ServletContext】的功能。通过在ServletConfig中调用getServletContext方法,也可以获得ServletContext对象。
源码:
package javax.servlet;
import java.util.EventListener;
public interface ServletContextListener extends EventListener {
void contextInitialized(ServletContextEvent var1);
void contextDestroyed(ServletContextEvent var1);
}
说明:当应用启动时,ServletContext进行初始化,然后Servlet容器会自动调用正在监听ServletContext的ServletContextListener的void contextInitialized(ServletContextEvent var1)方法,并向其传入一个ServletContextEvent对象。当应用停止时,ServletContext被销毁,此时Servlet容器也会自动地调用正在监听ServletContext的ServletContextListener的void contextDestroyed(ServletContextEvent var1)方法。
自己整理的一些关于servlet的基础知识,希望对大家有所帮助!