文章目录
Servlet深入
Servlet 的生命周期
- 从第一次调用,到服务器关闭。
- 如果在 web.xml 中配置了 load-on-startup 则是从服务器开启到服务器关闭。
注意:
- init方法是对Servlet进行初始化的一个方法,会在Servlet第一次加载进行存储时执行,第二次运行同一个Servlet时不会在执行init方法,它只执行一次
- destory方法是在servlet被销毁时执行,也就服务器关闭时执行。
示例代码如下:
package com.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ServletLife extends HttpServlet {
//初始化方法,在servlet第一次加载内容的时候被调用
@Override
public void init() throws ServletException {
System.out.println("servlet初始化完成");
}
//service方法,真正处理请求的方法
@Override
protected void service(HttpServletRequest req,
HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("servlet life");
System.out.println("servlet life");
}
@Override
public void destroy() {
System.out.println("我被销毁了...");
}
}
Servlet中的Service、doGet、doPost 方法
浏览器发出请求时,不一定只能够调用service方法来处理请求,与service方法具有相同功能的处理功能的还有doGet和doPost方法,以下是他们之间的区别:
-
Service 方法
不管是 get 方式还是 post 方式的请求,如果 Servlet 类中有service 方法,则优先调用 Service 方法。
注意:如果在覆写的service方法中调用了父类的service方法(super.service(arg0, arg1)),则service方法处理完后,会再次根据请求方式响应的doGet和doPost方法执行。如果调用doGet或者doPost方法时发现并没有Servlet中并没有这种方法,会发生405错误,所以,一般情况下我们是不在覆写的service中调用父类的service方法的,避免出现405错误。
-
doGet 方法
在没有 service 方法的情况下如果是 get 方式的请求所调用的处理请求的方法
-
doPost 方法
在没有service方法的情况下如果是post方式的请求所调用的处理请求的方法
Servlet的常见错误
-
404错误:资源未找到
原因一:在请求地址中的servlet的别名书写错误。
原因二:虚拟项目名称拼写错误
-
500错误:内部服务器错误
错误一:java.lang.ClassNotFoundException: com.bjsxt.servlet.ServletMothod
解决:
在web.xml中校验servlet类的全限定路径是否拼写错误。
错误二:
因为service方法体的代码执行错误导致
解决:
根据错误提示对service方法体中的代码进行错误更改。
-
405错误:请求方式不支持
原因:
请求方式和servlet中的方法不匹配所造成的。
解决:
尽量使用service方法进行请求处理,并且不要再service方法中调用父类的service。
Servlet的请求处理
Request对象
能够调用Service方法实现浏览器和服务器之间的简单交互后,我们还需要将请求数据进行封装给服务器,这时候就需要用到Request对象
问题引入:
浏览器发起请求到服务器,会遵循HTTP协议将请求数据发送给服务器。那么服务器接受到请求的数据改怎么存储呢?不但要存,而且要保证完成性。
解决:
使用对象进行存储,服务器每接受一个请求,就创建一个对象专门的存储此次请求的请求数据。
实现:
request 对象
解释:
服务器接收到浏览器的请求后,会创建一个 Request 对象,对象中存储了此次请求相关的请求数据。服务器在调用 Servlet 时会将创建的Request 对象作为实参传递给 Servlet 的方法,比如:service 方法。
注意:创建Request对象和将对象作为实参传递给Servlet中的方法都是有服务器自己完成,不需要程序员亲自动手操刀。
使用:
- 获取请求头数据
req.getMethod();//获取请求方式
req.getRequestURL();//获取请求URL信息
req.getRequestURI();//获取请求URI信息
req.getScheme();//获取协议
- 获取请求行数据
req.getHeader("键名");//返回指定的请求头信息
req.getHeaderNames();//返回请求头的键名的枚举集合
- 获取用户数据
req.getParameter("键名");//返回指定的用户数据
req.getParameterValues("键名");//返回同键不同值的请求数据(多选),返回的数组。
req.getParameterNames()//返回所有用户请求数据的枚举集合
注意:
如果要获取的请求数据不存在,不会报错,返回null。
Response 对象
问题引入:
在使用 Request 对象获取了请求数据并进行处理后,处理的结果如何显示到浏览器中呢?
解决:
使用 Response 对象
解释:
服务器在调用指定的 Servlet 进行请求处理的时候,会给 Servlet 的方法传递两个实参 request 和 response。其中 request 中封存了请求相关的请求数据,而 response 则是用来进行响应的一个对象。
使用:
- 设置响应头
setHeader(String name,String value);//在响应头中添加响应信息,但是同键会覆盖
addHeader(String name,String value);//在响应头中添加响应信息,但是不会覆盖。
- 设置响应状态
sendError(int num,String msg);//自定义响应状态码。
- 设置响应实体
resp.getWrite().write(String str);//响应具体的数据给浏览器
- 设置响应编码格式:
resp.setContentType("text/html;charset=utf-8");
示例代码如下所示:
public class ResponseServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//获取请求信息
//获取请求头
//获取请求行
//获取用户数据
//处理请求
//响应处理结果
//设置响应头
resp.setHeader("book", "Lucky boy");
resp.setHeader("book", "Funny girl");//会覆盖
resp.addHeader("School", "The Ocean of university");
resp.addHeader("School", "NBA learning school");//不会覆盖
//设置响应编码格式
//resp.setHeader("content-type", "text/html;charset=utf-8");
//resp.setContentType("text/plain;charset=utf-8");
//resp.setContentType("text/xml;charset=utf-8");
resp.setContentType("text/html;charset=utf-8");//普遍格式
//设置响应状态码
//resp.sendError(404, "this Method is not supported");
//如果设置了响应状态码,会直接发出警告,人工提醒浏览器错误信息,即便并没 //有发生任何错误
//设置响应实体
resp.getWriter().write("<b>Java从入门到放弃</b>");
}
}
请求乱码问题解决
问题引入:
浏览器发送请求的时候会用自己浏览器的编码格式去编码,当服务器解析的时候使用的是utf-8的编码格式(双方的编码格式不一致)就会发生乱码现象。
解决:
-
使用 String 进行重新编码:
uname=new String(uname.getBytes(“iso8859-1”),“utf-8”);
-
Get 方式请求:
在 service 方法中使用: req.setCharacterEncoding(“utf-8”);
在 tomcat 服务器目录下的 conf 文件下找到 server.xml 文件,打开进行如下配置:
-
Post 方式请求:
在 service 方法中使用: req.setCharacterEncoding(“utf-8”);
Servlet流程总结
Servlet 的使用流程
- 设置请求编码格式
- 设置响应编码格式
- 获取请求信息
- 处理请求信息
- 响应处理结果
数据流转流程
浏览器—(发出请求)—>服务器----(查询数据库有无此数据)—>数据库
浏览器<—(响应请求)—服务器<—(响应并传递数据)----数据库
请求转发
问题引入:
服务器在接收到浏览器的请求后,仅仅使用一个Servlet 进行请求处理,会造成不同的 Servlet 逻辑代码冗余,Servlet 的职责不明确。
解决:
使用请求转发。
解释:
比如你需要将表交到窗口中的人手中处理并且盖章,那个人处理完后需要递给另外一个人进行盖章,然后全部处理完之后才把响应结果告诉给你
特点:
- 在一次请求内
- 地址栏信息不改变
Request 对象作用域
问题引入:
使用请求转发后,不同的 Servlet 之间怎么进行数据的共享呢?或者说数据怎么从一个 servlet 流转给另外一个 Servlet 呢?
解决:使用 request 对象的作用域
使用:
request.setAttribute(object name,Object value);
request.getAttribute(Object obj)
作用:解决了一次请求内的不同 Servlet 的数据(请求数据+其他数据)共享问题
作用域:基于请求转发,一次请求中的所有 Servlet 共享
注意:
使用 Request 对象进行数据流转,数据只在一次请求内有效
特点:
-
Request对象由服务器创建
-
Request对象每次请求都会创建
-
Request的生命周期为一次请求
重定向
问题引入:
- 如果当前的请求,Servlet 无法进行处理怎么办?比如现实中你到窗口交表需要盖章,结果那个人说这里处理不了,需要你到其他部门去处理并且盖章,你就得重新跑到其他地方去处理完成事情。
- 如果使用请求转发,造成表单数据重复提交怎么办?特别是牵连到关键核心事件,比如支付宝转账,如果转账之后因为网络等问题出现延迟响应,如果你再次刷新界面,重复提交表单数据,就会出现转账两次的情况,会造成不必要的金钱损失。
解决:
使用重定向跳转到另外一个URL执行请求
使用:
response.sendRedirect(“路径”).
本地路径为:uri
网络路径为:定向资源的 URL 信息
特点:
- 两次请求
- 浏览器地址栏信息改变
- 避免表单重复提交
Cookie
Cookie介绍
问题:
HTTP 协议是没有记忆功能的,一次请求结束后,相关数据会被销毁即Request对象会被销毁。如果第二次的请求需要使用相同的请求数据怎么办呢?难道是让用户再次请求书写吗?
解决:
使用 Cookie 技术解决了发送的不同请求的数据共享问题
解释:
Cookie 技术其实是浏览器端的数据存储技术,解决了不同请求需要使用相同的请求数据的问题。我们把请求需要共享的请求数据,存储在浏览器端,避免用户进行重复的书写请求数据。但是哪些数据需要使用 Cookie 技术存储起来是一个主观问题,需要在后台进行响应的时候来告诉浏览器,有些数据其他请求还会使用,需要存储起来。
特点:
- 浏览器端的数据存储技术
- 适合少量数据
- 键值对的关系
- 不安全
使用:
Cookie的创建和存储
//创建Cookie对象
Cookie c=new Cookie(String name, String value);
//设置cookie(可选)
//设置有效期
c.setMaxAge(int seconds);
//设置有效路径
c.setPath(String uri)
//响应Cookie信息给客户端
resp.addCookie(c);
Cookie的获取
//获取Cookie信息数组
Cookie[] cks=req.getCookies();
//遍历数组获取Cookie信息
使用for循环遍历即可,示例:
if(cks!=null){
for(Cookie c:cks){
String name=c.getName();
String value=c.getValue();
System.out.println(name+":"+value);
}
}
注意:
一个Cookie对象存储一条数据。多条数据,可以多创建几个Cookie对象进行存储。
特点:
-
浏览器端的数据存储技术。
-
存储的数据声明在服务器端。
-
临时存储:
存储在浏览器的运行内存中,浏览器关闭即失效。
-
定时存储:
设置了Cookie的有效期,存储在客户端的硬盘中,在有效期内符合路径要求的请求都会附带该信息。
-
默认cookie信息存储好之后,每次请求都会附带,除非设置有效路径,设置有效路径之后,在该路径下才会附带cookie信息
示例代码如下:
public class CookieServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//设置请求编码格式
req.setCharacterEncoding("utf-8");
//设置响应编码格式
resp.setContentType("text/html;charset=utf-8");
//获取请求信息
//处理请求信息
//响应处理结果
//使用Cookie进行浏览器端的数据存储
//创建Cookie对象
Cookie c=new Cookie("book", "Lucky boy");
Cookie c2=new Cookie("school", "The Ocean of university");
//设置Cookie
//设置Cookie的有效期
c2.setMaxAge(3*24*3600);
//设置有效路径
c2.setPath("/cookie/ck");
//响应Cookie信息
resp.addCookie(c);
resp.addCookie(c2);
//直接响应
resp.getWriter().write("Cookie学习");
//请求转发
//重定向
}
}