java web开发中的Servlet、Session与Cookie的七七八八

版权声明:本文为博主原创文章,未经博主允许不得转载,欢迎批评指正。 https://blog.csdn.net/Sandyxin5208/article/details/82454933

前言

  把文题中的三个概念放到一起做总结,完全是出于很长一段时间博主对它们的理解是非常混乱的,所以就毫无逻辑的把它们总结到一起啦。

1、Servlet

1.1servlet的运行原理

  在浏览器地址栏中输入一个网址并确认,浏览器会向服务器发送一个HTTP请求,服务器端接收这个请求,并对请求作相应的回应处理。并将回应处理结果返回给浏览器,浏览器再把回应的内容显示出来,这种基于请求-响应的模式就是典型的web应用程序的访问过程。
  我们知道:在计算机网络中,两台主机之间数据的交互需要遵循一系列的应用层,传输层,网络层,链路层以及物理层的相关协议。HTTP协议作为一种应用层协议 ,规定了因特网上数据传送的规则,因此要实现两台主机之间的交互,两台主机都必须实现该协议。
  而使用较多的免费版的Tomcat就可以看作是实现了服务器端HTTP协议的应用,而浏览器则是实现了客户端HTTP协议的应用。在Java Web项目中,服务器端具体的响应处理则是通过Servlet实现。
  servlet是什么?从程序语言的角度看,Servlet是实现了javax.servlet.Servlet接口的类,该接口针对不同HTTP请求规定了特定的方法来处理,只要实现了这些方法,客户端访问web程序的时候,web服务器就会调用相应方法完成业务处理(具体怎么被调用,这就需要对web服务器的比较了解,暂且搁置(暂时还没有计划到这块的内容囧))。在实际应用中,JDK中javax.servlet.*和javax.servlet.http.*包提供了对Servlet的支持,javax.servlet.http.HttpServlet类就实现了Servlet接口的所有方法,可以直接继承该类重写需要的方法,可以大大提供编程效率。
在java web程序中,servlet的基本配置如下:

web.xml文件内容:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		 xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
		 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" 
		 id="WebApp_ID" version="3.1">
	 <--为servlet命名-->
	 <servlet>
		 <servlet-name>uploadServlet</servlet-name>
		 <servlet-class>com.xin.servlet.UploadServlet</servlet-class>
		 <load-on-startup>0</load-on-startup>
	 </servlet>
 <--为servlet定制URL-->
	 <servlet-mapping>
		 <servlet-name>UploadServlet</servlet-name>
		 <url-pattern>/src/com/xin/servlet/*</url-pattern>
	 </servlet-mapping>
<--指定欢迎页面-->	 
 <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>

  <servlet’>配置相应的Servlet类;<servlet-mapping’>配置servlet的映射路径,也即是客户端相应路径的请求才会交给该servlet处理;servlet程序要被web服务器正常调用,必须继承相应的类,例如HttpServlet;应用中通常是扩展HttpServlet类,该类声明了一些处理客户端请求的对应方法,根据客户端的请求类型(POST、GET、HEAD等),编写相应的处理方法,在博主的小项目中,客户端使用的是post请求提交表单,因此在servlet中的编写了方法:doPost();servlet的规范规定了对应客户端的请求方法必须是do+请求类型(例如doGet);
uploadServlet

1.2 Servlet生命周期

  servlet会在服务器启动或者说是第一次请求servlet的时候开始生命周期,在服务器结束的时候结束生命周期,也就是说在整个应用进程中始终只存在一个servlet实例,当多个客户端并发请求时,服务器会启动多个线程来执行servlet中的service方法,而Servlet中的init()与destroy()方法只会分别在Servlet被加载和销毁时执行一次。

1.3 servlet的线程安全性

  通过上文中对servlet生命周期的描述可以知道,servlet不是线程安全的,如果在自定义的Servlet中定义属性,在被多个线程写入时会出现数据不同步的问题。
servlet,Session,Cookie生命周期的讨论

Session

  session可以说是由web服务器生成和管理的,用户初次访问服务器时会被创建,可以通过以下方式 获取到session对象: request.getSession()
  Session虽然保存在服务器中,对客户端浏览器来说貌似无要求,但是由于HTTP是一种无状态协议(简单来讲就是同一客户请求同一应用的不同URL时不能被服务器知晓是一个用户所为),不能够依据HTTP连接来判断是不是为同一用户,而Session的作用就是为了实现用户的浏览追踪,那么如何实现呢?
  在用户初次请求服务时,服务器自动向浏览器发送一个名为JSESSIONId的cookie,其值为session的id,可以通过HttpSession的getId()获取。

Cookie

  Cookie相当于是用户初次访问服务器时,服务器为用户颁发的通行证,客户端保存这个通行证,在二次访问中,客户端会将请求的网址连同这个通行证一起提交给服务器,服务器就可以检查该Cookie来辨别用户。在Seesion中,用户首次请求服务后被颁发一个会话ID(SessionID),作为其后面继续访问的服务的跟踪ID,服务器可以借此判断用户身份,添加或修改关于用户的相关信息。
以下是关于一个文件上传的小demo,主要通过该demo演示servlet处理请求的过程以及cookie与session的基本工作原理。

index页面:
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>首页</title>
</head>
<body>
	<div style="width:100%;hight:50px;margin-bottom: 10px;background-color: blue;color: yellow" align="center">文件上传功能测试</div>
	<div style="width:100%;">
		<div style="width:50%;height:100px"align="left">
				<form action="<%= request.getContextPath() %>/src/com/xin/servlet" method="post" enctype="multipart/form-data">
					  文件上传:<input type="file" name="file1" /></br>
					    文本域:<input type="text" name="description1"/>
					<button type="submit">提交</button>
				</form>
		</div>
		<div style="width:50%;height:300px">	
				<div style="margin-top: 20px;margin-bottom: 20px">服务器返回上传时间,保存在Session中的特性:<%=session.getAttribute("uploadTime") %></div>
				<div style="margin-bottom: 20px">服务器返回输入的文本域信息,保存在Session中的特性:<%=session.getAttribute("文本域") %></div>
				<div>服务器返回上传文件名称,保存在Cookie中的属性:</br>
					<%
						Cookie[] cookies=request.getCookies(); 
					if(cookies!=null&&cookies.length!=0){
						for(Cookie cookie:cookies){
					%>
						<p>Cookie的名称:<%=cookie.getName() %></p>
						<p>Cookie的取值:<%=cookie.getValue() %></p>
					<%	}	}%> 
				</div>
		</div>	
	</div>
</body>
</html>

servlet处理请求:`

package com.xin.servlet;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
/**
 * 
 * @author XueXin
 *
 */
public class UploadServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	/**
	 * 处理页面的post请求
	 */
	@Override
	public void doPost(HttpServletRequest request,HttpServletResponse response)
	throws ServletException,IOException{
		boolean isMultipart = ServletFileUpload.isMultipartContent(request);
		if(isMultipart) {
			DiskFileItemFactory fac = new DiskFileItemFactory();
			//创建一个新的文件上传处理程序
			ServletFileUpload  upload =new ServletFileUpload (fac);
			//获取会话对象,
			HttpSession session=request.getSession();
			//List<HttpSession> sessions=new LinkedList<HttpSession>();
			//会话跟踪的演示
			session.setAttribute("uploadTime",new Date());
			String description1=null;
			try {
				//解析浏览器请求,
				List <FileItem> list = upload.parseRequest(request);
				for (Iterator<FileItem> iterator = list.iterator(); iterator.hasNext();) {
					FileItem fileItem = (FileItem) iterator.next();
					//如果是文本域
					if (fileItem.isFormField()&&"description1".equals(fileItem.getFieldName())){
						description1=new String(fileItem.getString().getBytes("ISO-8859-1"), "UTF-8");
						session.setAttribute("文本域",description1);
					}else if("file1".equals(fileItem.getFieldName())){
							//如果是文档文件
							File file1=exportData(fileItem);
							//添加cookie,验证在客户端获取到cookie;
							Cookie cookie=new Cookie("fileName", file1.getName());
							response.addCookie(cookie);
						}
				}
				//请求转发,转发到不同的页面看看,session的追踪效果;
				RequestDispatcher dispatcher=request.getRequestDispatcher("/WEB-INF/views/welcome.jsp");
				dispatcher.forward(request, response);
			} catch (FileUploadException e) {
				e.printStackTrace();
			}
		}
		
	}
	
	/**
	 *@author XueXin
	 *@parameter 
	 *@return file 
	 *@date 2018年9月5日 
	 *@function 读取上传文件并保存在本地,IO模型的解析;
	 */
	public File exportData(FileItem fileItem) throws IOException {
		//存储下载文件
		File downLoadFile=new File(new String(fileItem.getName().getBytes("UTF-8")),"UTF-8");
		//下载文件的存储位置
		File file1=new File(this.getServletContext().getRealPath("exportData"),downLoadFile.getName());
		//创建目录
		file1.getParentFile().mkdirs();
		//创建文件
		file1.createNewFile();
		InputStream inputStream=fileItem.getInputStream();
		OutputStream outputStream=new FileOutputStream(file1);
		try {
			byte[] buffer=new byte[1024];
			int len=0;
			//从输入流读取数据
			while((len=inputStream.read(buffer))>-1) {
				//向输出流写入数据
				outputStream.write(buffer, 0, len);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			outputStream.close();
			inputStream.close();
		}
		return file1;
	}
	
}

跳转页面:
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>转发页面</title>
</head>
<body>
	<div style="margin-top: 20px;margin-bottom: 20px">服务器返回上传时间,保存在Session中的时间信息:<%=session.getAttribute("uploadTime") %></div>
	<div style="margin-bottom: 20px">服务器返回输入的文本域信息,保存在Session中的文本域信息:<%=session.getAttribute("文本域") %></div>
	<div>服务器返回上传文件名称,保存在Cookie中的属性:</br>
		<%
			Cookie[] cookies=request.getCookies(); 
		if(cookies.length!=0){
			for(Cookie cookie:cookies){
		%>
			<p>Cookie的名称:<%=cookie.getName() %></p>
			<p>Cookie的取值:<%=cookie.getValue() %></p>
		<%	}	}%>
	</div>
</body>
</html>

图片是关于项目运行之后的具体前台页面效果,在demo中,用户首次访问服务时,并没有经过servlet的处理,但是服务器自动为用户颁发了了个会话跟踪ID也即是JSESSIONID;
登录页面
上传文件b.txt,在文本域中输入message1提交之后,经过servlet中doPost()方法的处理,session中添加了message1属性值和文件上传时间:
跳转页面

返回到首页刷新

猜你喜欢

转载自blog.csdn.net/Sandyxin5208/article/details/82454933