Servlet
Servlet的实现
学习导图
Servlet简介
Servlet是Server与Applet的缩写,是服务端小程序的意思。使用Java语言编写的服务端程序,可以像生成动态的WEB页,Servlet主要运行在服务器端,并由服务器调用执行,是一种按照Servlet标准来开发的类,是SUN公司提供的一门用于开发动态Web资源的技术。
Servlet本质上也是Java类,但要遵循Servet规范进行编写,没有main()方法,它的创建、使用、销毁都由Servlet容器进行管理(如Tomcat)。
Servlet是和HTTP协议是紧密联系的,其可以处理HTTP协议相关的所有内容。这也是Servlet应用广泛的原因之一。
Servlet的实现【@WebServlet注解】
【实现步骤】:
- 在Web项目下创建包中的java类
package com.xxxx.servlet;
public class Servlet01{
}
- 实现Servlet规范:
实现Servlet规范,即继承HttpServlet类,并到如响应的包,该类中已经完成了通信的规则,我们只需要进行业务的实现即可。
package com.xxxx.servlet;
import javax.servlet.http.HttpServlet;
public class Servlet01 extends HttpServlet{
}
- 重写service方法
满足Servlet规范只是让我们的类能够满足接收请求的要求,接收到请求后需要对请求进行分析,以及进行业务逻辑处理,计算出结果,则需要添加代码,在规范中有一个叫做service的方法,专门用来做请求处理的操作,业务代码则可以写在该方法中。
package com.xxxx.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class Servlet01 extends HttpServlet{
@Override
protected void service(HttpServletRequest req,HttpServletResponse resp)throws ServletException,IOException{
Sysetem.out.println("Hello Servlet!");
resp.getWeriter().write("Hello World!");
}
}
- 设置注解:
在完成好了一切代码的编写后,还需要向服务器说明,特定请求对应特定资源。
开发servlet项目,使用 @WebServlet 将一个javax.servlet.http.HttpServlet的类定义为Servlet组件。在Servlet3.0中,可以使用@WebServlet注解将一个继承于javax.servlet.http.HttpServlet的类标注为可以处理用户请求的Servlet。
package com.xxxx.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/s02")//在浏览器中输入的url添加上/s02可以直接访问到当前的Servlet动态资源
public class Servlet01 extends HttpServlet{
@Override
protected void service(HttpServletRequest req,HttpServletResponse resp)throws ServletException,IOException{
Sysetem.out.println("Hello Servlet!");
resp.getWeriter().write("Hello World!");
}
}
【后端操作通过@WebServlet与前端交互】
前端创建一个与上面Servlet类(通过下面的标签s02)相关联的jsp界面,其中前端数据会自动通过Tomcat服务器传入后端,后端可以通过request.getParamer("uname");request.getParamer("upwd");
获得
Servlet的实现方式
HttpServlet
继承于父类GenericServlet
,故要想实现Servlet类可以继承于GenericServlet类,如:
@WebServlet("/ser01")
public class Servlet01 extends GenericServlet{
@Override
protected void service(HttpServletRequest req,HttpServletResponse resp)throws ServletException,IOException{
Sysetem.out.println("Hello Servlet!");
resp.getWeriter().write("Hello World!");
}
- 实现Servlet接口
@WebServlet("/ser01")
public class Servlet01 implements Servlet{
@Override
protected void service(HttpServletRequest req,HttpServletResponse resp)throws ServletException,IOException{
Sysetem.out.println("Hello Servlet!");
resp.getWeriter().write("Hello World!");
}
- doGet方法与doPost方法
@WebServlet("/ser01")
public class Servlet01 extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req,HttpServletResponse resp)throws ServletException,IOException{
Sysetem.out.println("Get请求……");
}
@Override
protected void doPost(HttpServletRequest req,HttpServletResponse resp)throws ServletException,IOException{
Sysetem.out.println("Post请求……");
}
结论:最常用的还是继承HttpServlet类并重写service方法。
Servlet的生命周期
简介:Servlet没有main()方法,不能独立运行,它的运行完全由Servlet引擎来控制与调度。所谓生命周期,指的是servlet容器何时创建servlet实例,何时调用其方法进行请求的处理、何时并销毁其实例的整个过程。
- 实例和初始化时机
当请求到达容器时,容器查找该servlet对象是否存在,如果不存在,则会创建实例并进行初始化。
//init方法,在Servlet实例创建后执行(证明该Servlet有实例创建了)
public void init(ServletConfig config)thows ServletException{
System.out.println("实例创建了……");
}
- 就绪/调用/服务阶段
有请求到达容器,容器调用servlet对象的service()方法,处理请求的方法在整个生命周期中可以被多次调用;HttpServlet的service()方法,会依据请求方式来调用doGet()或者doPost()方法。但是,这两个do方法默认情况下,会抛出异常,需要子类去override。
//service方法,每次有请求到达某个Servlet方法时执行,用来处理请求(证明该Servlet进行服务了)
protected void service(HttpServletRequest req,HttpServletResponse resp)thows ServletException,IOException{
System.out.println("服务调用了……");
}
- 销毁时机
当容器关闭时(应用程序停止时),会将程序中的Servlet实例进行销毁。
//destroy方法,Servlet实例销毁时执行(证明该Servlet的实例销毁了)
public void destroy(){
System.out.println("实例销毁了……");
}
上述的生命周期可以通过Servlet中的生命周期方法来观察。在 Servlet中有三个生命周期方法,不由用户手动调用,而是在特定的时机有容器自动调用 ,观察这三个生命周期方法即可以观察到Servlet的生命周期。
时序图与说明:
- Web Client向Servlet容器(Tomcat)发出Http请求
- Servlet容器接收Web Client的请求
- Servlet容器创建一个HttpServletResquest对象(上面的req),将Web Client请求的信息封装到这个对象中【都是Servlet容器自动创建自动封装的】
- Servle容器创建一个HttpServletResponse对象(上面的resp)【都是Servlet容器自动创建自动封装的】
- Servlet容器调用HttpServlet对象service方法,把Request(req)和Response(resp)作为参数,传给HttpServlet
- HttpServlet调用HttpServletRequest对象的相关方法,获取Http的请求信息
- HttpServlet调用HttpServletResponse对象的相关方法,生成响应数据
- Servlet容器把HttpServlet的响应结果传给Web Client
HttpServletRequest对象
简介
HttpServletRequest对象:主要作用是 用来接收客户端发送过来的请求 ,例如:请求的参数,发送的头信息等都属于客户端发来的信息,service()方法中形参接收的是HttpServletRequest接口的实例化对象,表示该对象主要应用在HTTP协议上,该对象是由Tomcat封装好传递过来的。
在HttpServletRequest接口中,定义的方法很多,但都是围绕接收客户端参数的。但是怎么拿到该对象呢? 不需要,直接在Service方法中由容器传入过来,而我们需要做的是取出对象中的数据,进行分析,处理。
常用方法
下面的request和respose即是req和resp
请求参数获取
请求乱码问题
由于现在的request属于接收客户端的参数,所以必然有其默认的语言编码,主要是由于在解析过程中默认使用的编码方式为ISO-8859-1(不支持中文),所以解析时一定会出现乱码。要想解决这种乱码问题,需要设置request中的编码方式,告诉服务器以何种方式来解析数据。或者在接收到乱码数据以后,再通过相应的编码格式还原。
- 方式一:
request.setCharacterEncoding("UTF-8")
这种方式只针对POST有效(必须再接收所有的数据之前设定) - 方式二:
new String(request.getParamer(name).getBytes("ISO-8859-1"),"UTF-8")
,对任何请求方式都有效,是通用的。 - 注意:Tomcat8以后的GET方式请求时不会出现乱码的。
请求转发
请求转发,是一种服务器行为,当客户端请求到达后,服务器进行转发,此时会将请求对象进行保存,地址栏中的 URL地址不会改变 ,得到响应后,服务器端再将响应发送给客户端,从始至终只有一个请求发出,实现方式如下,达到多个资源协同响应的效果。【通俗来说,就是能实现页面跳转且页面跳转后能数据都相互传递共享】
request.getRequestDispatcher(url).forword(request,response);
request.getRequestDispatcher(s02).forword(request,response);
//Servlet之间数据共享,要是标签为s01使用此语句,则s01获得的请求参数或数据会共享给s02
request.getRequestDispatcher(login.xml).forword(request,response);
//共享界面,可以使得当前的Servlet共享login.xml页面(相当于跳转)
request作用域
通过该对象可以在一个请求中传递数据,作用范围:在一次请求中有效,即服务器跳转有效【即要搭配请求转发语句一起使用,如下:】
Servlet05:
Servlet06:
此时Servlet05的数据就可以共享给Servlet06了,同理也可以将Servlet05的数据共享给jsp页面
request域对象中的数据在一次请求中有效,则经过请求转发,request域中的数据依旧存在,则在请求转发的过程中可以通过request来传输/共享数据。
HttpServletResponse对象
简介
Web服务器收到客户端http请求,会针对每一次请求,风别创建一个用于用于代表请求的request对象和代表响应的response对象。
request和response对象代表请求和响应:获取客户端数据,需要通过request对象;向客户端输出数据,需要通过response对象。
HttpServletResponse的主要功能用于服务器对客户端的请求进行响应,将Web服务器处理后的结果返回给客户端。service()方法中的形参接收的是HttpServletResponse接口的实例化对象,这个对象中封装了向客户端发送数据、发送响应头,发送响应状态码的方法。
响应数据
接收到客户端请求后,可以通过HttpServletResponse对象进行响应,响应时候需要获取输出流有两种形式:
getWriter()
获取字符流(只能响应回字符)使用:PrintWriter writer = response.getWriter();writer.write("Hello");
getOutputStream()
获取字节流(能响应一切数据)使用:ServletOutputStream out = response.getOutputStream();out.write("Hi".getBytes());
- 两者不能同时使用
响应乱码问题
在响应中,如果我们响应的内容中含有中文,则有可能出现乱码,这是因为服务器响应的数据也会经过网络传输,服务器端有一种编码方式,在客户端也存在一种编码方式,当两端使用的编码方式不同时则会出现乱码。
-
getWriter()的字符乱码
-
getOutputStream()的字符乱码
【注意】:可以同时设置客户端和服务端的编码方式,上面两种情况都通用,一般用这种方式:response.setContentType("text/html,charset=UTF-8");
重定向
重定向是一种服务器指导,客户端行为。(1)、(客户端发出第一个请求,被服务器接收处理后,服务器会进行响应,在响应的同时,服务器会给客户端一个新的地址(下次请求的地址response.sendRedirect(url或.jsp);//重定向跳转到url或.jsp
), (2)、 当客户端接收到响应后,会立刻、马上、自动根据服务器给的新地址发起第二个请求,服务器接收请求并做出响应,重定向完成 。
重定向与请求转发的区别
Cookie对象
简介
Cookie是浏览器提供的一种技术,通过服务器的程序能将一些只须保留在客户端,或者在客户端进行处理的数据,放在本地的计算机上,不需要通过网络传输,因而 提高网页处理的效率,并且能够减少服务的负载,但是由于Cookie是服务器端保存在客户端的信息,所以安全性也是很差的。例如常见的记住密码则可以通过Cookie来实现。
有个专门操作Cookie的类javax.servlet.http.Cookie.随着服务器端的响应发送给客户端,保存在浏览器。当下次再访问服务器时把Cookie再带回服务器。
Cookie的格式:键值对用"=“链接,多个键值对通过”;"隔开。
Cookie的创建和发送
通过new Cookie("key","value");
来创建一个Cookie对象,要想将Cookie随响应发送到客户端,需要先添加到response对象中,response.addCookie(cookie);
此时该cookie对象则随着响应发送至了客户端。在浏览器上可以看见。
//创建Cookie对象
Cookie cookie = new Cookie("uname","zhangsan");
//发送Cookie对象
response.addCookie(cookie);
Cookie的获取
在服务器端只提供了一个getCookie()
的方法用来获取客户端回传的所有cookie组成的一个数组,如果需要获取单个cookie则需要通过遍历,getName()
获取Cookie的名称,getValue()
获取Cookei的值。
//获取客户端传来的Cookie数组
Cookie[ ] cookies = request.getCookiees();
//判断数组是否为空
if(cookies !=null&&cookies.length>0){
//遍历Cookie数组
for(Cookie cookies:cookies){
System.out.println(cookie.getName());
System.out.println(cookie.getValue());
}
}
Cookie设置到期时间
除了Cookie的名称和内容外,我们还需要关心一个信息,到期时间,到期时间用来指定cookie何时失效。默认为当前浏览器关闭即失效。我们可以手动设定cookie的有效时间(通过到期时间计算),通过setMaxAge(int time);方法设定cookie的最大有效时间,以秒为单位.
【到期时间取值】:
- 负整数
若为负数,表示不存储cookie。
cookie的maxAge属性的默认值就是-1,表示只在浏览器内存中存活,一旦关闭浏览器,那么cookie就会消失。 - 正整数
若大于0的整数,表示存储的秒数。
表示cookie对象可存活指定的秒数。当生命大于0时,浏览器会把Cookie保存在硬盘上,就算关闭浏览器,就算重启客户端电脑,cookie也会存活相应的时间。 - 零
若为0,表示删除该cookie
cookie生命等于0是一个特殊的值,它表示cookie被作废!也就是说,如果原来浏览器已经保存了这个Cookie,那么可以通过Cookie的setMaxAge(0)来删除这个Cookie。无论是在浏览器内存中,还是在客户端硬盘上都会删除这个Cookie。
Cookie的注意点
- Cookie保存在当前浏览器中。
在一般的站点中常常有记住用户名这样的操作,在操作只是将信息保存在本机上,换电脑以后这些信息就无效了。而且cookie还不能跨浏览器。 - Cookie存在中文问题
Cookie中不能出现中文,如果有中文则通过URLEncoder.encode()来进行编码,获取时通过URLDecoder.decode()来进行解码。
String name = "姓名";
String value = "张三";
//通过URLEncoder.enode()来进行编码
name = URLEncoder.encode(name);
value = URLEncoder.encode(value);
//创建Cookie对象
Cookie cookie = new Cookie(name,value);
//发送Cookie对象
response.addCookie(cookie);
//获取时通过URLDecoder.decode()来进行解码
URLDecoder.decode(cookie.getName());
URLDecoder.decode(cookue.getValue());
- 同名Cookie问题
如果服务器端发送重复的Cookie(同名的Cookie)那么会覆盖原有的Cookie。 - 不同的浏览器对Cookie也有限定,Cookie的存储是有上限的。Cookie是存储在客户端(浏览器)的,而且一般是由服务器端创建和设定。后期结合Session来实现会话跟踪。
Cookie的路径
HttpSession对象
Session概述
标识符JSESSIONID
session域对象
【概述】:Session用来表示一次会话,在一次会话中数据是可以共享的【与request域对象只能实现一次请求数据共享不同的是,只要是在一次会话中(同一个session)session可以实现多个请求的数据共享】,这时候session作为域对象存在,可以通过setAttribute(name,value)
方法向域对象中添加数据,通过getAttribute(name)
从域对象中获取数据,通过removeAttribute(name)
从域对象中移除数据。
//获取session对象
HttpSession session = request.getSession();
//设置session域对象
session.setAttribute("uanme","admin");
//获取指定名称的session域对象
String uname = (String)request.getSession().getAttribute("uname");
//移除指定名称的session域对象
session.removeAttribute("uname");
………………………………………………………………session实现共享数据…………………………………………………………
@WebServlet("/s02")
public class Servlet01 extends HttpServlet{
@Override
protected void service(HttpServletRequest req,HttpServletResponse resp)throws ServletException,IOException{
//获取session对象
HttpSession session = request.getSession();
//设置session域对象
session.setAttribute("uanme","admin");
session.setAttribute("upwd","123");
//移除指定名称的session域对象
session.removeAttribute("upwd");
//请求转发跳转到jsp页面
request.getRequestDispatcher("index.jsp").forward(request,response);
//重定向到jsp页面
response.sendRedirect("index.jsp");
}
}
index.jsp代码如下:
【结果】:无论是请求转发还是重定向到index.jsp页面,session域对象中的数据都是能够共享的。
注意:数据存储在session域对象中,当session对象不存在了,或者是两个不同的session对象时,数据也就不能共享了。这就不得不谈到session的生命周期了。
session对象的销毁
【概述】:登录一个网站,过了一段时间不操作,浏览器会提醒 “登录过时请重新登录”,这就说明session已经失效了。其中sessoin的有效时间有下面几种情况:
ServiceContext对象
【简介】:
【ServletContext对象的创建以及一些常用方法】
【ServletContext域对象】: