1. Servlet基础
1.1 Servlet概述
- Servlet的请求首先会被HTTP服务器接收,服务器只负责静态HTML页面的解析
- 而Servlet的请求则转交给Servlet容器(例如:Tomcat),容器根据请求路径以及servlet之间的映射关系,调用相应的servlet
- servlet将处理结果返回给容器,并通过服务器将响应传输给客户端
1.2 Servlet的特点
-
功能强大:可调用JavaAPI
-
可移植:Java语言是跨平台的
-
性能高效:servlet对象在容器启动时被初始化,第一次请求时,容器将对象实例化,常驻内存;如果存在多个请求,servlet不会再被实例化
-
安全性高
-
可扩展
1.3 Servlet接口
- Servlet接口的方法
void init(ServletConfig config)//完成初始化工作
ServletConfig getServletConfig()//获取servlet对象的配置信息
String getServletInfo()//返回值中包含关于servlet的信息
void service(ServletRequest req, ServletResponse res)//负责响应用户的请求,当容器收到请求时,就会调用此方法
void destroy()//负责释放servlet对象占用的资源
-
Servlet接口的两个默认的接口实现类
- GenericServlet:抽象类,为servlet接口提供了部分实现,但没有实现HTTP请求处理
- HttpServlet:是GenericServlet的子类,继承了父类的所有方法,并为HTTP请求提供了具体的操作
-
HttpServlet类的常用方法
HttpServletRequest req;//代表HTTP请求
HttpServletResponse resp;//代表HTTP响应
protected void doGet(req, resp)//处理get类型的HTTP请求
protected void doPost(req, resp)//处理post类型的HTTP请求
protected void doPut(req, resp)//处理put类型的HTTP请求
2. Servlet开发入门
2.1 Servlet的配置
- 使用web.xml配置Servlet
<!--通过<servlet>标签进行注册-->
<servlet>
<!--Servlet的名称,一般与类名相同,要求唯一-->
<servlet-name></servlet-name>
<!--Servlet类的位置,包括包名和类名-->
<servlet-class></servlet-class>
<description></description> <!--描述信息-->
<display-name></display-name> <!--Servlet的显示名-->
</servlet>
<!--把Servlet映射到URL地址-->
<servlet-mapping>
<!--要映射的servlet名称,必须要和注册的相同-->
<servlet-name></servlet-name>
<!--映射url地址,地址前必须加"/",否则访问不到-->
<url-pattern></url-pattern>
</servlet-mapping>
- 使用@WebServlet注解配置Servlet
@WebServlet(name="", ...)//格式
属性:
String name//Servlet的名称
String[] value//等价于urlPatterns属性,二者不能同时使用,如果同时存在,通常忽略value
String[] urlPatterns//指定一组Servlet的url匹配模式
int loadOnStartup//Servlet的加载顺序
WebInitParam[]//指定一组Servlet初始化参数
boolean asyncSupported//声明Servlet是否支持异步操作
String descripion//描述信息
String displayName//显示名,通常配合工具使用
2.2 Servlet的生命周期
- 初始化阶段
- 客户端向容器发送请求
- 容器解析请求,检查内存中Servlet对象是否存在
- 存在:直接调用
- 不存在:创建对象,通过init()完成初始化
- 运行阶段
- 容器会为请求创建ServletRequest和ServletResponse的对象,然后传递给Servlet的service()方法
- **service()**从ServletRequest中获得请求信息并处理,通过ServletResponse生成响应结果
- 销毁阶段
- 当服务器关闭或web应用被移出容器时,Servlet随着销毁,在销毁之前,容器会调用destroy()
注意:
- 在Servlet整个生命周期内,init()只被调用一次
- Servlet的每一次访问请求,容器都会调用一次service(),并且创建新的ServletRequest和ServletResponse的对象
- 在Servlet整个生命周期内,destroy()只被调用一次
3. ServletConfig和ServletContext
3.1 ServletConfig接口
-
在初始化一个Servlet时,会将Servlet的配置信息封装到一个ServletConfig对象中,通过调用init(ServletConfig config)将ServletConfig对象传递给Servlet
-
ServletConfig获取配置信息的方法
//获得ServletConfig对象
ServletConfig config = this.getServletConfig();
//根据初始化参数名获得对应的初始化参数值
String param = config.getInitParameter(参数名);
//获得一个代表当前应用的ServletContext对象
ServletContext context = this.getServletContext();
//获得所有的初始化参数名
Enumeration<String> paramNames = config.getInitParameterNames();
//获得Servlet的名字
String name = config.getServletName();
3.2 ServletContext接口
-
容器启动时,会为每一个web应用创建一个唯一的ServletContext对象代表当前web应用。该对象不仅封装了当前web应用的所有信息,而且实现了多个Servlet之间数据的共享
-
获取Web应用程序的初始化参数
<!--在web.xml文件中,可以配置servlet的初始化信息-->
<context-param>
<param-name>参数名</param-name>
<param-value>参数值</param-value>
</context-param>
<!--必须位于根元素<web-app>中-->
//获取初始化参数
//得到ServletContext对象
ServletContext context = this.getServletContext();
//得到包含所有初始化参数名的Enumeration对象
Enumeration<String> paramNames = context.getInitParameterNames();
//遍历所有的初始化参数名,得到响应的参数值
while (paramNames.hasMoreElements()) {
String name = paramNames.nextElement();
String value = context.getInitParameter(name);
}
- 实现多个Servlet对象共享数据
//得到包含了存放在ServletContext中的所有域属性名
Enumeration<String> paramNames = context.getAttributeNames();
//根据参数指定的域属性名获得对应的域属性值
Object obj = context.getAttribute(域属性名);
//根据参数指定的域属性名,删除指定的域属性
context.removeAttribute(域属性名);
//设置域属性
context.setAttribute(域属性名, 域属性值);
- 读取Web应用下的资源文件
String path = "/WEB-INF";//必须以"/"开头,"/"表示当前Web应用(WEB-INF)的根目录
//获取映射到某个资源文件的InputStream输入流对象
InputStream in = context.getResourceAsStream(path);
//获取映射到某个资源文件的URL对象
URL url = context.getResourc(path);
//获取文件的绝对路径(文件在服务器文件系统上的真实路径),如果容器不能将虚拟路径转换为绝对路径,则返回null
String ph = context.getRealPath(path);
//获取包含资源目录中子目录和文件的路径名称
Set<String> setPaths = context.getResourcePaths(path);
4. HttpServletResponse对象
4.1 发送状态码相关的方法
//设置HTTP响应消息的状态码,并生成响应状态行,即可实现状态行的发送,默认产生一个200的状态码
setStatus(int status);
//发送表示错误信息的状态码,例如:404表示找不到客户端请求的资源
sendError(int sc);
//设置错误信息的状态码,还向客户端发送一条错误的信息
sendError(int code, String message);
4.2 发送响应消息头相关的方法
//设置HTTP协议的响应头字段
void setHeader(String name, String value);//覆盖同名的头字段
void addHeader(String name, String value);//增加同名的响应头字段
//设置包含整数值的响应头,避免了调用setHeader()和addHeader()时,需要将int转换为String的麻烦
void setIntHeader(String name, int value);
void addIntHeader(String name, int value);
/*
设置响应消息的实体内容的大小,单位为字节
对于HTTP协议而言,就是设置Content-Length响应头字段的值
*/
void setContentLength(int len);
/*
设置Servlet输出内容的MIME类型
对于HTTP协议而言,就是设置Content-Type响应头字段的值
例如:发送内容是jpeg格式的图像数据,type="image/jpeg"
发送内容是文本,type="text/html;charset=UTF-8"
*/
void setContentType(String type);
/*
设置响应消息的本地化信息
对于HTTP协议而言,就是设置Content-Language响应头字段和Content-Type头字段的字符集编码部分
注意:
1. 如果HTTP消息没有设置Content-Type头字段,setLocale()设置的字符集编码不会出现在HTTP消息的响应头中
2. 如果调用setCharacterEncoding()或setContentType()指定了响应内容的字符集编码,setLocale()将不再
具有指定字符集编码的功能
*/
void setLocale(Localse loc);
/*
设置输出内容使用的字符集编码
对于HTTP协议而言,就是设置Content-Type的字符集编码部分
注意:
1. 如果HTTP消息没有设置Content-Type头字段,setCharacterEncoding()设置的字符集编码不会出现在HTTP消息的响应头中
2. setCharacterEncoding()的优先权比setContentType()和setLocale()高,它设置的结果将覆盖它们两个设置的字符码表
*/
void setCharacterEncoding(String charset);
4.3 发送响应消息体相关的方法
/*
获取ServletOutputStream类型的字节输出流对象
ServletOutputStream是OutputStream的子类,可直接输出字节数组中的二进制数据
*/
OutputStream out = response.getOutputStream();
//获取PrintWriter类型的字符输出流,可直接输出字符的文本内容
PrintWriter print = response.getWriter();
4.4 实现请求重定向
- 请求重定向:web服务器接收到客户端请求后,可能由于某些限制,无法访问当前URL的所指的web资源,而是指定了一个新的资源路径,让客户端重新发送请求
//生成302响应码和Location响应头,从而通知客户端重新访问Location响应头中指定的URL
sendRedirect(String location) throws IOException;
//注意:location可以使用相对URL,Web服务器会自动将其翻译成绝对URL,再生成Location头字段
4.5 解决中文输出乱码问题
- 出现原因:编码时采用的字符码表和浏览器对接收数据解码时所采用的字符码表不一致所导致的
//解决方案1
//设置HttpServletResponse使用utf-8编码
response.setCharacterEncoding("utf-8");
//通知浏览器使用utf-8解码
response.setHeader("Content-Type", "text/html;charset=utf-8");
//解决方案2,包含第一种两种功能
response.setContentType("text/html;charset=utf-8");
5. HttpServletRequest对象
5.1 获取请求行信息的相关方法
//获取HTTP请求消息中的请求方式
String getMethod();
//获取请求行中资源名称部分,即位于URL的主机和端口之后,参数部分之前的数据
String getRequestURL();
//获取请求行中的参数部分,也就是资源路径后面问号(?)以后的所有内容
String getQueryString();
//获取请求行中的协议名和版本,例如HTTP/1.1
String getProtocol();
/*
获取请求URL中属于Web应用程序的路径
这个路径以"/"开头,表示整个web站点的根目录,结尾不含"/"
如果请求URL属于web站点的根目录,那么返回结果为空字符串
*/
String getContextPath();
//获取Servlet名称或Servlet映射的路径
String getServletPath();
//获取请求客户端的IP地址,其格式类似于"192.168.0.3"
String getRemoteAddr();
//获取请求客户端的主机名,格式类似于"pc1.why.in";如果无法解析出完整主机名,返回客户端IP地址
String getRemoteHost();
//获取请求客户端网络连接的端口号
int getRemotePort();
//获取web服务器上接收当前请求网络连接的ip地址
String getLocalAddr();
//获取Web服务器上接收当前网络连接ip地址所对应的主机名
String getLocalName();
//获取Web服务器上接收当前网络连接的端口号
int getLocalPort();
//获取当前请求所指向的主机名,即HTTP请求消息中Host头字段所对应的主机名部分
String getServerName();
//获取当前请求所连接的服务器的端口号,即HTTP请求消息中Host头字段所对应的端口号部分
int getServerPort();
//获取请求的协议名,例如HTTP、HTTPS、FTP等
String getScheme();
//获取客户端发出请求时的完整URL,包括协议、服务器名、端口号、资源路径等信息,但不包含查询参数部分
StringBuffer getRequestURL();
5.2 获取请求头的相关方法
//获取一个指定头字段的值,如果没有该头字段,返回null,如果有多个该头字段,返回第一个的值
String getHeader(String name);
//获得请求消息中指定头字段所有的值
Enumeration getHeaders(String name);
//获取包含所有请求头字段
Enumeration getHeaderNames();
//获取指定名称的头字段,并将其值转为int型,如果没有,返回-1,如果不能转为int,将发生异常
int getIntHeader(String name);
//获取指定头字段的值,并转换成一个代表日期/时间的长整数
long getDateHeader(String name);
//获取Content-Type头字段的值
String getContentType();
//获取Content-Length头字段的值
int getContentLength();
//获取请求消息的实体部分的字符集编码
String getCharacterEncoding();
5.3 请求转发
- 例如:使用一个servlet实现用户登录,然后跳转到另外一个servlet实现用户资料修改
- Servlet的跳转要通过RequestDispatcher接口的实例对象实现
//获取封装了某条路径所指定资源的RequestDispatcher对象
RequestDispatcher getRequestDispatcher(String path);
/*
将当前请求传递给其他Web资源,由其他资源对这些信息进行处理并将响应提交给客户端
注意:该方法必须在将响应提交给客户端之前被调用
*/
forward(ServletRequest req, SevletResponse res);
5.4 获取请求参数
/*获取指定名称的参数值
如果没有,返回null;
如果存在但没有设置值,返回空串;
如果存在多个,返回第一个
*/
String getParameter(String name);
//获取请求消息中同一个参数名所对应的所有参数值
String[] getParameterValues(String name);
//获取请求消息中所有参数名
Enumeration getParameterNames();
//将所有参数名和值装入一个Map对象中
Map getParameterMap();
5.5 通过Request对象传递数据
//将一个对象和一个name关联后存储进ServletRequest对象中
public void setAttribute(String name, Object obj);
//从ServletRequest对象中返回指定名称的属性对象
public Object getAttribute(String name);
//从ServletRequest对象中删除指定名称的属性
public void removeAttribute(String name);
//返回一个包含ServletRequest对象中的所有属性名的Enumeration对象
public Enumeration getAttributeNames();
5.6 解决请求参数的中文乱码问题
//设置request对象的解码方式
request.setCharacterEncoding("utf-8");