Servlet
servlet有初始化、服务、销毁等方法,可以表示一个servlet的生命周期
Init 初始化
Service 服务
Destory 销毁
一个生命周期的方法
public class ServletLife implements Servlet {
@Override
public void init(ServletConfig config) throws ServletException {
System.out.println("init()方法执行了,servlet对象开始初始化...");
}
@Override
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
System.out.println("service()方法执行了,servlet对象开始运行...");
}
@Override
public void destroy() {
System.out.println("destroy()方法执行了,servlet对象销毁...");
}
@Override
public ServletConfig getServletConfig() {
System.out.println("getServletConfig()方法执行了,获取servlet配置对象...");
return null;
}
@Override
public String getServletInfo() {
System.out.println("getServletInfo()方法执行了,获取servlet信息...");
return null;
}
}
在web.xml里的配置
servlet>
<description></description>
<display-name>AServlet</display-name>
<servlet-name>AServlet</servlet-name>
<servlet-class>com.qun.ecoding.AServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>AServlet</servlet-name>
<url-pattern>/AServlet</url-pattern>//浏览器访问路径
</servlet-mapping>
总结:
servlet的生命周期:
生命周期所有三个方法init、service、destory;
请求第一次访问时被创建并初始化(init方法执行,初始化),只执行一次
每次处理请求service就会被执行一次
销毁方法在销毁Servlet之前执行;只执行一次;
特点:
Servlet是单例模的,(但是我可以写AServlet、BServlet、CServlet都可以创建对象)
一个对象同时应对多个请求时,就会出现线程安全问题,所以servlet线程不安全;Servlet有我们来写,但是对象由服务器创建,并且由服务器调用相关的方法;
**先记住,Servlet(默认)是第一次访问的时候实例化、然后初始化、service、destroy..
但是Servlet是在第一次访问被实例化的说法不准确**
ServletConfig
Servletconfig 是一个servlet对象的配置对象,servletConfig对象中封装了一个servlet对象的配置信息。
Servlet对象的配置信息在web.xml中。
一个servlet对象对应一个servletconfig,100个servlet对象对应100个servletconfig对象
Servlet有个 getServletConfig() 返回值是ServletConfig,可以通过API查看得到;
public class ServletConfig extends GenericServlet{
@Override
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
//获取配置对象
javax.servlet.ServletConfig config = getServletConfig();
//获取web.xml中servlet-name
String name = config.getServletName();
System.out.println("servlet名称为:"+name);
//获取web.xml中<Parameter-value>的值
String value = config.getInitParameter("用户名");
System.out.println("初始化参数的值为:"+value);
Enumeration<String> names = config.getInitParameterNames();
while (names.hasMoreElements()) {
String initName = (String) names.nextElement();
System.out.println(initName);
//通过名称获取value值
String initvalue = config.getInitParameter(initName);
System.out.println(initvalue);
}
//通过servletConfig对象获取servletContext对象
ServletContext context = config.getServletContext();
System.out.println(context);
}
}
ServletContext
1.ServletContext概述
服务器会为每个应用创建一个ServletContext对象:
- ServletContext对象的创建是在服务器启动时完成的;
- ServletContext对象的销毁是在服务器关闭时完成的。
ServletContext对象的作用是在整个Web应用的动态资源之间共享数据!
例如,在AServlet中向ServletContext对象中保存一个值,然后在BServlet中就可以获取这个值,这就是共享数据了。
一个项目只有一个ServletContext对象!通常给他的对象名取为application。
2.获取ServletContext对象
public class Servlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) {
ServletContext context = this.getServletContext();}}
为什么能使用this,因为是Servlet的对象来调用这个方法,Bservlet继承自HttpServlet,所以可以使用this.getServletContext()。
3.ServletContext的使用
jsp四大作用域
PageContext page 在当前页面那种有效 抽象类
ServletRequest request 在当前请求中有效 接口
HttpSession session 当前会话中有效 接口
ServletContext application 在所有应用程序中有效 接口
所有域对象都有存取数据的功能,因为域对象内部有一个Map,用来存储数据,下面是ServletContext对象用来操作数据的方法:
void setAttribute(String name, Object value):用来存储一个对象,也可以称之为存储一个域属性,例如:servletContext.setAttribute(“xxx”, “XXX”),在ServletContext中保存了一个域属性,域属性名称为xxx,域属性的值为XXX。请注意,如果多次调用该方法,并且使用相同的name,那么会覆盖上一次的值,这一特性与Map相同;
Object getAttribute(String name):用来获取ServletContext中的数据,当前在获取之前需要先去存储才行,例如:String value = (String)servletContext.getAttribute(“xxx”);,获取名为xxx的域属性;
void removeAttribute(String name):用来移除ServletContext中的域属性,如果参数name指定的域属性不存在,那么本方法什么都不做;
Enumeration getAttributeNames():获取所有域属性的名称;
public class BServlet extends HttpServlet {
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //获取servletContext域对象 ServletContext context = getServletContext(); //通过context取出域中的数据 String attr = (String) context.getAttribute("姓名"); System.out.println(attr); }
}
4.ServletContext获取公共的初始化参数
public class CServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取servletContent对象
ServletContext application = getServletContext();
//获取web.xml的初始化参数
String val = application.getInitParameter("姓名");
System.out.println(val);
Enumeration<String> names = application.getInitParameterNames();
while (names.hasMoreElements()) {
//获取单个参数名称
String name = (String) names.nextElement();
System.out.println(name);
//获取单个参数值
String value = application.getInitParameter(name);
System.out.println(value);
}
}
}
xml中的内容
<context-param>
<param-name>工程师</param-name>
<param-value>张三</param-value>
</context-param>
<context-param>
<param-name>总经理</param-name>
<param-value>李四</param-value>
</context-param>
<context-param>
<param-name>总裁</param-name>
<param-value>王五</param-value>
</context-param>
5.ServletContext获取资源相关方法
public class DServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取context对象
ServletContext application = getServletContext();
//获取login.html的本地磁盘真是路径
String realPath = application.getRealPath("login.html");
System.out.println(realPath);
//获取test.text文件的真实路径
String realPath2 = application.getRealPath("/WEB-INF/test.txt");
System.out.println("txt文件的路径为"+realPath2);
//以流的形式获取资源
InputStream stream = application.getResourceAsStream("/WEB-INF/test.txt");
System.out.println(stream);
}
}
Response
1.Response概述
sponse是Servlet.service方法的一个参数,类型为javax.servlet.http.HttpServletResponse。在客户端发出每个请求时,服务器都会创建一个response对象,并传入给Servlet.service()方法。response对象是用来对客户端进行响应的,这说明在service()方法中使用response对象可以完成对客户端的响应工作。
response对象的功能分为以下四种:
设置响应头信息;
发送状态码;
设置响应正文;
重定向;(Servlet===》Servlet;Servlet===》a.html)
2.Response对象发送状态码
常见状态码:
200 成功、
302 重定向、
404 路径错误(可能是资源不存在导致的)
405:提交方式不支持(如果你是get提交,但是只有doPost方法);
500 服务器内部错误(有可能代码写错了)
sendError(int sc); 发状态码
sendError(int sc,String msg) 发送状态码同时发送消息
setStatus(int sc); 设置状态码
3.响应头完成重定向
setHeader(String name,String value);适用单个响应头
addHeader(String name,String value);适用多个响应头
重定向状态码是302; 响应头对象的是Location:url
public class EServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("我要重定向。。。");
//通过相应头重定向到FServlet
resp.setHeader("Location", "/servlet02/FServlet");
resp.setStatus(302);
}
}
//重定向到FServlet
public class FServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("重定向到了FServlet");
}
}
4.响应头完成定时刷新
public class DServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//在页面输出一句话,使用汉语会乱码以后再讲
PrintWriter writer = response.getWriter();
writer.print("3秒以后跳转到另外一个页面");
response.setHeader("Refresh", "3;url=/servelt/EServlet");
}
}
public class EServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().println("看我乱码依旧!");
}
}
5.响应头完成普通字符数据和图片字符数据
public class GServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().print("汉字乱码");
//1.通过response对象给浏览器响应字符数据
String string = "loveDOUDOU";
//响应字符时需要将字符转化为字符数组
byte[] bytes = string.getBytes();
//通过输出流输出到浏览器
resp.getOutputStream().write(bytes);
//2.通过response对象给浏览器响应字节数据(图片)
String path = "D:\\123.jpg";
//将图片转化为流输入到内存
FileInputStream fileInputStream = new FileInputStream(path);
//将输入流转化为数组
byte[] byteArray = IOUtils.toByteArray(fileInputStream);
//通过输出流输出
resp.getOutputStream().write(byteArray);
}
}
响应头快捷重定义方法
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.重新定向本地路径
resp.sendRedirect("/servlet02/FServlet");
//2.重新定向到网络资源
resp.sendRedirect("http://www.baidu.com");
}
}
Resquest
1.Resquest的概述
request是Servlet.service()方法的一个参数,类型为javax.servlet.http.HttpServletRequest。在客户端发出每个请求时,服务器都会创建一个request对象,并把请求数据封装到request中,然后在调用Servlet.service()方法时传递给service()方法,这说明在service()方法中可以通过request对象来获取请求数据。
request的功能可以分为以下几种:(重点)
封装了请求头数据;
封装了请求正文数据,如果是GET请求,那么就没有正文;
request是一个域对象,可以把它当成Map来添加获取数据;
request提供了请求转发和请求包含功能
一个web应用只有一个ServletContext即application,所以在一个Servlet的app里存值,在另外一个Servlet的app里可以取到值;但是,一个web应用对应多个reqeust,在request1里存值,在reqeust2里取不到值;
request的常用方法
System.out.println(req.getRemoteAddr());
System.out.println(req.getMethod());
req.setCharacterEncoding("utf-8");
System.out.println(req.getCharacterEncoding());
System.out.println("serverName:"+req.getServerName());
System.out.println(req.getServerPort());
2.获取请求路径的方法
public class AServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取请求路径的常用方法
//servlet02/AServlet
System.out.println("URL"+req.getRequestURL());
//http://localhost:8080/servlet03/AServlet返回请求的URL路径
System.out.println("URL:"+req.getRequestURL());
//项目名/servlet03(重要)获取项目名
System.out.println(req.getContextPath());
//获取servlet路径/IServlet(重要)获取路径
System.out.println(req.getServletPath());
}d
}
3.请求转发和请求包含
请求转发(forward:转发)
请求转发:由下一个Servlet完成响应体!当前Servlet可以设置响应头!不能设置响应体,非得设置响应体可能会出现异常;(BServlet留头不留体,)BServlet完成不了去找CServlet完成;CSservlet能设置响应头;
public class BServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setHeader("bb", "BBB");
//不具备表现能力
resp.getWriter().print("BServlet");
//获取转发对象并转发
req.getRequestDispatcher("/CServlet").forward(req, resp);
}
}
public class CServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setHeader("cc", "CCCC");
resp.getWriter().print("CServlet");
}
}
请求包含(include:包含)
请求包含:将两个资源的输出进行合并后输出由两个Servlet共同来完成响应体!(DServlet留头也留体)两个Servlet共同完成,被包含的不能设置响应头;
public class DServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setHeader("ddd", "DDD");
//具备显示能力
resp.getWriter().print("DServlet");
//获取转发器并包含
req.getRequestDispatcher("/EServlet").include(req, resp);
}
}
public class EServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setHeader("ee", "EEEG");
resp.getWriter().print("EServlet...");
}
}
4.Request获取请求参数
最为常见的客户端传递参数方式有两种:
- 浏览器地址栏直接输入:一定是GET请求;
http://lcoalhost:8080/项目名称/AServlet?username=zhangsan&password=123456; - 超链接:一定是GET请求;
- 表单:可以是GET,也可以是POST,这取决与的method属性值;
注意:表单提交过来的值都是字符串类型;
GET请求和POST请求的区别:
GET请求:
请求参数会在浏览器的地址栏中显示,所以不安全;
请求参数长度限制长度在1K之内;
GET请求没有请求体,无法通过request.setCharacterEncoding()来设置参数的编码;
POST请求:
请求参数不会显示浏览器的地址栏,相对安全;
请求参数长度没有限制;
下面是使用request获取请求参数的API:
String getParameter(String name):通过指定名称获取参数值;
String[] getParameterValues(String name):当多个参数名称相同时,可以使用方法来获取;
Enumeration getParameterNames() 获取所有参数的名字;
Map
5.request域
Servlet中三大域对象:request、session、application(ServletContext的对象),都有如下三个方法:
void setAttribute(String name, Object value)
Object getAttribute(String name)
void removeAttribute(String name)
同一请求范围内使用request.setAttribute()、request.getAttribute()来传值!
前一个Servlet调用setAttribute()保存值,后一个Servlet调用getAttribute()获取值。(生命周期长,第二个servlet调用第一个servlet保存的值)
区别
parameter用来设置和获取表单给我们传递的值;
Attribute用来传递和获取servlet内部的数据;和域紧密联系到一起;
public class HServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//创建student对象
Stuent stuent = new Stuent();
//给student赋值
stuent.setUserName("张三");
stuent.setUserName("123");
//向请求域中保存数据
req.setAttribute("oo", stuent);
//从请求域中取出数据
Object object = req.getAttribute("oo");
//输出到浏览器
resp.getWriter().print(object);
//请求转发和重定向的区别
//转发
//转发是一次请求,在同一个request作用有中,所以可以共享数据
req.getRequestDispatcher("/IServlet").forward(req, resp);
//重定向到IServlet
//重定向是两次请求,而request作用域只作用于一次请求,不在同一个request作用域中,
//所以不能共享数据
resp.sendRedirect("/servlet03-request/IServlet");//null
}
}
public class IServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//从请求域中取出数据
Object object = req.getAttribute("oo");
//输出到浏览器
resp.getWriter().print(object);
}
}
6.转发和重定向的区别
请求转发和重定向的区别
- 请求转发是一个请求一次响应,而重定向是两次请求两次响应
- 请求转发地址栏不变化,而重定向会显示后一个请求的地址
- 请求转发只能转发到本项目其他Servlet(是Servlet在转发),而重定向不只能重定向到本项目的其他Servlet,还能定向到其他项目(其实是浏览器在重定向)
- 请求转发是服务器端行为,只需给出转发的Servlet路径,而重定向需要给出 requestURI,即包含项目名!
请求转发和重定向效率是转发高!因为是一个请求!
<> 需要地址栏发生变化,那么必须使用重定向!
<> 需要在下一个Servlet中获取request域中的数据,必须要使用转发!
<> 假如我要跳到百度去,这时候也只能用重定向;
乱码的解决
1.响应乱码的解决
- 当使用response.getWriter()来向客户端发送字符数据时,如果在之前没有设置编码,那么默认使用iso,因为iso不支持中文,一定乱码
- 在使用response.getWriter()之前可以使用response.setCharaceterEncoding()来设置字符流的编码为gbk或utf-8,当然我们通常会选择utf-8。这样使用response.getWriter()发送的字符就是使用utf-8编码的。但还是会出现乱码!因为浏览器并不知道服务器发送过来的是什么编码的数据!这时浏览器会使用gbk来解码,所以乱码!
在使用response.getWriter()之前可以使用response.setHeader(“Content-type”,”text/html;charset=utf-8”)来设置响应头,通知浏览器服务器这边使用的是utf-8编码,而且在调用setHeader()后,还会自动执行setCharacterEncding()方法。这样浏览器会使用utf-8解码,所以就不会乱码了!
public class AServlet extends HttpServlet{
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //在服务器响应之前设置编码 resp.setContentType("text/html;charset=utf-8"); //向浏览器输出 resp.getWriter().print("你好"); }
}
2.get提交方式乱码的解决
public class BServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取表单数据
String name = req.getParameter("userName");
//反编译
byte[] bytes = name.getBytes("iso-8859-1");
//重新设置编码格式为utf-8
String string = new String(bytes,"utf-8");
System.out.println(string);
}
}
3.post提交方式乱码的解决
public class CServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//在接收数据之前设置编码格式
request.setCharacterEncoding("UTF-8");
//获取表单数据
String name = request.getParameter("userName");
System.out.println(name);
//在响应之前设置编码
response.setContentType("text/html;charset=utf-8");
//响应给浏览器
response.getWriter().print(name);
}
}