Servlet深入学习(持续更新)

Servlet深入

Servlet 的生命周期

  1. 从第一次调用,到服务器关闭。
  2. 如果在 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中的方法都是有服务器自己完成,不需要程序员亲自动手操刀。

使用:

  1. 获取请求头数据
req.getMethod();//获取请求方式
req.getRequestURL();//获取请求URL信息
req.getRequestURI();//获取请求URI信息
req.getScheme();//获取协议
  1. 获取请求行数据
req.getHeader("键名");//返回指定的请求头信息
req.getHeaderNames();//返回请求头的键名的枚举集合
  1. 获取用户数据
req.getParameter("键名");//返回指定的用户数据
req.getParameterValues("键名");//返回同键不同值的请求数据(多选),返回的数组。
req.getParameterNames()//返回所有用户请求数据的枚举集合

注意:

如果要获取的请求数据不存在,不会报错,返回null。

Response 对象

问题引入:
在使用 Request 对象获取了请求数据并进行处理后,处理的结果如何显示到浏览器中呢?

解决:
使用 Response 对象

解释:
服务器在调用指定的 Servlet 进行请求处理的时候,会给 Servlet 的方法传递两个实参 request 和 response。其中 request 中封存了请求相关的请求数据,而 response 则是用来进行响应的一个对象。

使用:

  1. 设置响应头
setHeader(String name,String value);//在响应头中添加响应信息,但是同键会覆盖
addHeader(String name,String value);//在响应头中添加响应信息,但是不会覆盖。
  1. 设置响应状态
sendError(int num,String msg);//自定义响应状态码。
  1. 设置响应实体
resp.getWrite().write(String str);//响应具体的数据给浏览器
  1. 设置响应编码格式:
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的编码格式(双方的编码格式不一致)就会发生乱码现象。

解决:

  1. 使用 String 进行重新编码:

    uname=new String(uname.getBytes(“iso8859-1”),“utf-8”);

  2. Get 方式请求:

    在 service 方法中使用: req.setCharacterEncoding(“utf-8”);

    在 tomcat 服务器目录下的 conf 文件下找到 server.xml 文件,打开进行如下配置:

在这里插入图片描述

  1. Post 方式请求:

    在 service 方法中使用: req.setCharacterEncoding(“utf-8”);

Servlet流程总结

Servlet 的使用流程
  1. 设置请求编码格式
  2. 设置响应编码格式
  3. 获取请求信息
  4. 处理请求信息
  5. 响应处理结果
数据流转流程

浏览器—(发出请求)—>服务器----(查询数据库有无此数据)—>数据库
浏览器<—(响应请求)—服务器<—(响应并传递数据)----数据库

请求转发

问题引入:
服务器在接收到浏览器的请求后,仅仅使用一个Servlet 进行请求处理,会造成不同的 Servlet 逻辑代码冗余,Servlet 的职责不明确。

解决:
使用请求转发。

解释:

比如你需要将表交到窗口中的人手中处理并且盖章,那个人处理完后需要递给另外一个人进行盖章,然后全部处理完之后才把响应结果告诉给你

特点:

  • 在一次请求内
  • 地址栏信息不改变
Request 对象作用域

问题引入:

使用请求转发后,不同的 Servlet 之间怎么进行数据的共享呢?或者说数据怎么从一个 servlet 流转给另外一个 Servlet 呢?

解决:使用 request 对象的作用域

使用:

request.setAttribute(object name,Object value);
request.getAttribute(Object obj)

作用:解决了一次请求内的不同 Servlet 的数据(请求数据+其他数据)共享问题

作用域:基于请求转发,一次请求中的所有 Servlet 共享

注意:
使用 Request 对象进行数据流转,数据只在一次请求内有效

特点:

  • Request对象由服务器创建

  • Request对象每次请求都会创建

  • Request的生命周期为一次请求

重定向

问题引入:

  1. 如果当前的请求,Servlet 无法进行处理怎么办?比如现实中你到窗口交表需要盖章,结果那个人说这里处理不了,需要你到其他部门去处理并且盖章,你就得重新跑到其他地方去处理完成事情。
  2. 如果使用请求转发,造成表单数据重复提交怎么办?特别是牵连到关键核心事件,比如支付宝转账,如果转账之后因为网络等问题出现延迟响应,如果你再次刷新界面,重复提交表单数据,就会出现转账两次的情况,会造成不必要的金钱损失。

解决:
使用重定向跳转到另外一个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学习");
			//请求转发
			//重定向
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值