Servlet常用技术点
Servlet的概述
什么是Servlet
Servlet其实就是一个运行在web服务器上的小的Java程序,用于处理从web客户端发送的请求,并且对请求做出响应
使用Servlet
- 编写一个java类实现Servlet的接口
- 配置Servlet
Servlet快速入门
1.搭建web项目
搭建web
添加tomact服务器
添加服务器jar包
2.创建类并实现Servlet接口
public class HelloServlet implements Servlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
servletResponse.getWriter().println("Hello World");
}
。。。。。。
}
3.配置Servlet(web.xml)
<!-- 配置servlet-->
<servlet>
<!-- 配置servlet的名称-->
<servlet-name>hello</servlet-name>
<!-- 配置servlet类的全路径-->
<servlet-class>servlet.HelloServlet</servlet-class>
</servlet>
<!-- 配置servlet的映射-->
<servlet-mapping>
<!-- 使用servlet的名称-->
<servlet-name>hello</servlet-name>
<!-- 配置访问路径-->
<url-pattern>/hello</url-pattern>
</servlet-mapping>
4.访问Servlet
Servlet执行流程
- 1.浏览器输入访问地址
- 2.找到配置文件中的url-pattern
- 3.找到servlet-name
- 4.找到servlet-class
- 5.执行servlet中代码
Servlet实现方式
基本的实现关系
关系实现的概述
- SUN设计之初,是有野心,以后的互联网不仅仅只使用http协议,可以通过GenericServlet实现。
- HttpServlet是一个与协议相关的Servlet是专门用来处理HTTP协议的请求。
- 通常编写一个Servlet一般都会让这个Servlet继承HttpServlet重写service方法。在service方法内部根据请求方式不同执行不同的doXXX的方法(get请求执行doGet方法,如果是post请求就会执行doPost方法)。
- 往往继承了HttpServlet之后不需要重写service方法,只需要重写doGet和doPost方法即可。往往请求要处理的内容的代码都是一致的,所以需要让doGet和doPost相互调用可以简化编程。
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 如果是GET请求就会执行doGet中的代码
doPost(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 如果是POST请求就会执行doPost中的代码
resp.getWriter().println("Hello World 简化代码");
}
}
idea使用Servlet模板
new Servlet
//使用注解方式配置Servlet
//value 就是 配置文件中的 url-pattern (浏览器访问地址)
//使用注解不用再去web.xml中配置Servlet,方便快捷
@WebServlet(name = "hello2", value = "/hello2")
public class hello2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
右键new中没有Servlet
Servlet声明周期
什么是声明周期
生命周期:一个对象从创建到销毁过程。
Servlet生命周期
- Servlet生命周期:Servlet对象从创建到销毁的过程。
- Servlet何时被创建又是何时被销毁的?
- Servlet中有init,service,destroy方法,这几个方法称为是Servlet生命周期相关的方法。
- Servlet是在第一次被访问的时候会被实例化,只要Servlet一被实例化那么Servlet中的init方法就会执行(init只会执行一次)。
- 任何一次从客户端发送来的请求,那么Servlet中的service方法就会执行(在service方法的内部根据请求的方式不同调用不同doXXX方法)。
- 当Servlet从服务器中移除或者服务器关闭的时候Servlet对象被销毁,里面的destroy方法就会执行,然后垃圾回收就会将其回收掉。
public class ServletDemo1 implements Servlet {
//Servlet对象倍实例化的时候init方法就会执行,而且只执行一次。(Servlet是单例)
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("ServletDemo1 实例化");
}
//Service方法:任何一次请求都会执行service方法,可以执行多次
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("ServletDemo1 执行");
}
//Servlet从服务器中移除或服务器关闭的时候销毁Servlet,只执行一次
@Override
public void destroy() {
System.out.println("ServletDemo1 销毁");
}
}
Servlet启动时加载
为什么使用启动时加载
Servlet对象是第一次被访问的时候会被创建的,init方法就会执行。假设在init方法中做了一些比较耗时的操作(比如:加载了一些配置文件并且解析可能需要花费3秒钟)。第一个用户第一次访问这个Servlet的时候,需要等待3秒钟。如何使第一个用户在第一次访问的时候不需要花费这么长时间?
什么是启动时加载
Servlet默认是在第一次访问的时候创建的对象,现在通过一个配置将Servlet的实例化的过程放在服务器启动的时候(让服务器启动的时候创建Servlet的对象)。如果现在这样做那么之前花费的时间就会在服务器启动的时候一起花费掉了。对于用户来讲就不需要额外花费这个时间。
配置启动时加载
<servlet>
<servlet-name>ServletDemo1</servlet-name>
<servlet-class>servlet.ServletDemo1</servlet-class>
<!-- 启动时加载,有一个默认servlet为1,自己设置比1大的数字,正整数越小,启动优先级越高-->
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ServletDemo1</servlet-name>
<url-pattern>/ServletDemo1</url-pattern>
</servlet-mapping>
Servlet访问路径的配置
<url-pattern>的配置方式
- 完全路径匹配
- 以 / 开始 比如:/ServletDemo1
- 目录匹配
- 以 / 开始,以 /* 结束 比如:/aaa/*
- 扩展名匹配
- 不能以 / 开始,以 * 开始 比如:*.abc
<servlet-mapping>
<servlet-name>ServletDemo1</servlet-name>
<!-- 完全路径匹配-->
<!-- <url-pattern>/ServletDemo1</url-pattern>-->
<!-- 目录匹配-->
<!-- <url-pattern>/aaa/*</url-pattern>-->
<!-- 扩展名匹配-->
<url-pattern>*.abc</url-pattern>
</servlet-mapping>
访问的优先级
匹配指向同一个Servlet时
完全路径匹配 > 目录匹配 > 扩展名匹配
ServletConfig对象
ServletConfig对象的概述
ServletConfig用来获得Servlet的相关的配置的对象。
获得ServletConfig对象
getServletConfig()
ServletConfig对象的API
- 获得所有Servlet的初始化参数名称 getInitParameterNames()
- 获得Servlet的初始化参数 getInitParameter(String name)
- 获得ServletContext对象 getServletContext()
- 获得Servlet的名称 getServletName()
<servlet>
<servlet-name>ServletDemo2</servlet-name>
<servlet-class>servlet.ServletDemo2</servlet-class>
<!-- 配置Servlet的初始参数-->
<init-param>
<param-name>username</param-name>
<param-value>lisi</param-value>
</init-param>
<init-param>
<param-name>password</param-name>
<param-value>1234</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ServletDemo2</servlet-name>
<url-pattern>/ServletDemo2</url-pattern>
</servlet-mapping>
public class ServletDemo2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获得ServletConfig对象
ServletConfig servletConfig = this.getServletConfig();
//获得初始参数
String username = servletConfig.getInitParameter("username");
String password = servletConfig.getInitParameter("password");
System.out.println("username = " + username);
System.out.println("password = " + password);
System.out.println("------------------------");
//获得所有初始化参数名称
Enumeration<String> initParameterNames = servletConfig.getInitParameterNames();
while (initParameterNames.hasMoreElements()){
String name = initParameterNames.nextElement();
String value = servletConfig.getInitParameter(name);
System.out.println(name + " = " + value);
}
System.out.println("------------------------");
//获得Servlet名称
String servletName = servletConfig.getServletName();
System.out.println(servletName);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
ServletContext对象
什么是ServletContext
ServletContext:Servlet的上下文对象。ServletContext对象对Servlet之前和之后的内容都知道。这个对象一个web项目只有一个。在服务器启动的时候为每个web项目创建一个单独的ServletContext对象。
ServletContext对象的作用
- 用来获取web项目信息:因为一个web项目只有一个ServletContext对象,所以这个对象对整个项目的相关内容都是了解的。
用来获取web项目信息
<!-- 全局配置参数-->
<context-param>
<param-name>username</param-name>
<param-value>zhangsan</param-value>
</context-param>
<context-param>
<param-name>password</param-name>
<param-value>123</param-value>
</context-param>
<servlet>
<servlet-name>ServletDemo3</servlet-name>
<servlet-class>servlet.ServletDemo3</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletDemo3</servlet-name>
<url-pattern>/ServletDemo3</url-pattern>
</servlet-mapping>
public class ServletDemo3 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取ServletContext对象
ServletContext servletContext = this.getServletContext();
//获取文件的MIME的类型
String mimeType = servletContext.getMimeType("aa.txt");
System.out.println(mimeType);
System.out.println("-------------------");
//获取web项目请求工程名
String contextPath = servletContext.getContextPath();
System.out.println(contextPath);
System.out.println("-------------------");
//获得全局初始化参数
String username = servletContext.getInitParameter("username");
String password = servletContext.getInitParameter("password");
System.out.println(username + " = " + password);
System.out.println("-------------------");
//获得搜友初始化参数名
Enumeration<String> initParameterNames = servletContext.getInitParameterNames();
while (initParameterNames.hasMoreElements()){
String name = initParameterNames.nextElement();
String value = servletContext.getInitParameter(name);
System.out.println(name + " = " + value);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
ServletContext对象之作为域对象存取数据
什么是域对象
域对象:指的是将数据存入到域对象中,这个数据就会有一定的作用范围。域指的是一定的作用范围。
ServletContext作为域对象的API
-
存入数据的方法:
setAttribute(String name,Object Object) -
获取数据的方法:
getAttribute(String name) -
移除数据的方法:
removeAttribute(String anem)
ServletContext作为域对象的作用范围
ServletContext是在服务器启动的时候为每个web项目单独创建一个ServletContext对象。当web项目从服务器中移除,或者是关闭服务器的时候ServletContext对象会被销毁。向ServletContext中保存的数据一直存在(当服务器关闭的时候ServletContext对象被销毁,然后里面数据才会失效)。范围:整个web应用。
ServletDemo1
@WebServlet(name = "ServletDemo1", value = "/ServletDemo1")
public class ServletDemo1 extends HttpServlet {
@Override
public void init() throws ServletException {
this.getServletContext().setAttribute("name","张三");
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=UTF-8");
String name = (String) this.getServletContext().getAttribute("name");
response.getWriter().append("name: " + name);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
ServletDemo2
@WebServlet(name = "ServletDemo2", value = "/ServletDemo2")
public class ServletDemo2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=UTF-8");
String name = (String) this.getServletContext().getAttribute("name");
response.getWriter().append("name2: " + name);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
响应和请求概述
什么是Response(响应)和Request(请求)
开发的软件是B/S结构的软件,可以通过浏览器访问服务器的软件。从浏览器输入一个地址访问服务器(将这个过程称为是请求)。服务器接收到请求,需要进行处理,处理以后需要将处理结果显示回浏览器端(将这个过程称为是响应)。
Response对象的API
Response关于响应行的方法
- setStatus(int sc)
设置响应的状态码
200 正确
302 重定向
304 查找本地缓存
404 请求资源不存在
500 服务器内部错误
Response关于响应头的方法
- 设置响应头
setDateHeader(String anme, long date)
setHeader(String name, String value)
setIntHeader(String name, int value) - 追加响应头
addDateHeader(String name, long date)
addHeader(String name, String value)
addIntHeader(String anem , int value)
Response关于响应体的方法
- getOutputStream()
- getWriter()
Response其他的API
- 重定向的方法
sendRedirect(String location) - 设置浏览器打开页面时候采用的字符集
setContentType(String type) - 设置响应字符流的缓冲区字符集
setCharacterEncoding(String charser) - 服务器向浏览器回写Cookie的方法
addCookie(Cookie cookie) - 定时刷新
response.setHeader(“refresh”, “时间;url=地址”);
中文乱码处理
//设置从浏览器到服务器字符集
request.setCharacterEncoding("utf-8");
//设置从服务器到浏览器字符集
response.setContentType("text/html;charset=UTF-8");
Request对象的API
获得客户机信息
- 获得请求的方式
getMethod() - 获得请求路径后的提交参数的字符串
getQueryString() - 获得请求路径的URL和URI
getRequestURI()
getRequestURL() - 获得客户机的IP地址
getRemoteAddr()
获得请求头的方法
- 获得一个key对应一个value的请求头
getHeader(String name) - 获得一个key对应多个value的请求头
getHeaders(String name)
获得请求参数的方法
- 获得提交的参数(一个name对应一个value)
getParameter(String name) - 获得提交的参数(一个name对应多个value)
getParameterValues(String name) - 获得提交的参数,将提交的参数的名称和对应的值存入到一个Map集合中
getParameterMap()
Request作为域对象存取数据的方法
- 向request域中存数据
setAttribute(String name, Object o) - 从request域中获取数据
getAttribute(String name) - 从request域中移除数据
removeAttribute(String name)
会话技术
什么是会话
会话简单理解为:用户打开一个浏览器,点击多个超链接访问服务器的web资源,然后关闭浏览器,整个过程称为是一次会话。
为什么要使用会话
每个用户与服务器进行交互过程中,产生一些各自的数据,程序想要把这些数据进行保存,就需要使用会话技术。
例如:用户点击超链接购买一个商品,程序应该保存用户所购买的商品,以便于用户点击结账可以得到用户所购买的商品信息。
会话技术分类
Cookie技术
Cookie是客户端技术,程序把每个用户的数据以cookie的形式保存到各自浏览器中。当用户使用浏览器再次访问服务器中的web资源的时候,就会带着各自的数据过去。这样,web资源处理的就是用户各自的数据了。
Session技术
Session是服务器端技术,利用这个技术,服务器在运行时为每一个用户的浏览器创建一个独享的session对象。由于session为用户浏览器独享,所有用户在访问服务器的时候,可以把各自的数据放在各自的session中,当用户再次访问服务器中的web资源的时候,其他web资源再从用户各自的session中取出数据为用户服务。
Cookie对象的API
- Cookie的构造
Cookie(String name, String value) - 获得从浏览器带过来的Cookie
request.getCookies() - 向浏览器回写Cookie
response.addCookie(Cookie cookie) - 获得Cookie的名称的方法
getName() - 获得Cookie的值的方法
getValue() - 设置Cookie的有效域名
setDomain(String pattern) - 设置Cookie的有效路径
setPath(String uri) - 设置Cookie的有效时长
setMaxAge(int expiry)
Cookie的分类
默认级别的Cookie
指的是没有设置有效时间的Cookie,默认的情况下只要关闭了浏览器,Cookie也会被销毁。(Cookie存在于浏览器的内存中,当关闭了浏览器Cookie就销毁了)。
持久级别的Cookie
指的是有有效时间的Cookie,这种Cookie的内容不是保存在浏览器的内存中,将Cookie的内容保存(持久化)到硬盘上。这个时候,关闭浏览器,再次打开浏览器会加载硬盘上的文件,从而Cookie中的数据就不会丢失。
Cookie的使用细节总结
- 一个Cookie只用标识一种信息,至少含有一个标识该信息的名称和值。
- 一个web站点可以给一个浏览器发送多个Cookie。一个web浏览器可以存储多个web站点的Cookie。
- 如果创建了一个Cookie,并发送到浏览器,默认情况下它是一个会话级别的Cookie。用户退出浏览器就被删除。如果希望将这个Cookie存到磁盘上,需要设置有效时长调用setMaxAge(int maxAge)方法,以秒为单位的。
- 需要手动删除持久性Cookie,可以将Cookie的有效时长设置为0.必须注意:删除Cookie时候,path必须一致,否则无法删除。
什么是Session
Session称为是一次会话,Cookie将用户产生的私有的数据保存到浏览器端,Session将用户产生的私有的数据保存到服务器端。注意:一个浏览器独占一个session对象。因此,在需要保存用户数据时候,服务器程序可以将用户数据写到session对象中,当用户使用浏览器访问其他程序时,其他程序可以从用户的session中取出该用户的数据,为用户服务。
为什么有Cookie还要有Session
Cookie局限性:
- Cookie保存的数据是有个数和大小的限制的。
- 数据是保存客户端浏览器上(相对不是很安全)。
Session
- Session没有个数和大小限制。
- 数据是保存在服务器上(相对比较安全)。
Session作为域对象的API
-向session中存入数据
SetAttribute(String name, Object value)
- 从session域中获取数据
getAttribute(String name) - 从session域中移除数据
removeAttribute(String name)
Session作为域对象的作用范围
Session作为域对象,作用范围就是一次会话的范围。一次会话,指的是用户打开浏览器点击多个超链接,访问服务器资源,到最后关闭浏览器的过程。
Servlet的域对象的总结
请求范围(ServletRequest)
- 何时创建和销毁的
- 创建:当用户向服务器发送一次请求,服务器创建一个request对象。
- 销毁:当服务器对这次请求作出了响应,服务器就会销毁这个request对象。
- 如何存取数据
- 存数据:
void setAttribute(String name,Object value); - 取数据
Object getAttribute(String name);
- 存数据:
- 作用范围
- 作用范围:一次请求。(转发就是一次请求)。
会话范围(HttpSession)
- 何时创建和销毁的
- 创建:服务器端第一次调用getSession()方法的时候。
- 销毁:三种情况。
Session过期,默认的过期时间30分钟(web.xml中配置)。
非正常关闭服务器。(正常关闭服务器—session会被序列化)。
手动调用session.invalidate();
- 如何存取数据
- 存数据:
void setAttribute(String name,Object value); - 取数据
Object getAttribute(String name);
- 存数据:
- 作用范围
- 作用范围:一次会话(多次请求)
应用范围(ServletContext)
- 何时创建和销毁的
- 创建:服务器启动的时候创建,为每个web项目创建一个单独ServletContext对象。
- 销毁:服务器关闭的时候,或者项目从服务器中移除的时候。
- 如何存取数据
- 存数据:
void setAttribute(String name,Object value); - 取数据
Object getAttribute(String name);
- 存数据:
- 作用范围
- 作用范围:整个应用