欢迎来访~
目录
1.回忆cookie和session
在前面的内容里,其实已经给大家介绍过cookie和session的一些内容,今天让我们更深入地了解掌握如何基于API来完成会话管理的操作。
会话(Session)跟踪是web程序中常用的技术,用来跟踪用户的整个会话,常用的会话跟踪技术是Cookie与Session 。Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份。
1.1cookie
我们先回忆一下我们之前举的例子:
如果我们第一次去一个医院,首先先会填写自己的相关信息,来办一张就诊卡,这张卡就相当于(cookie),无论我们在那个科室看病,都能够刷这个卡,刷卡的时候,实际上是通过医院的服务器来获取到当前患者的一些列详情,包括他的身份信息,以及他的既往病史,当然这个机制最主要的左永刚其实就是帮助服务器来做一个身份识别,毕竟存储在一个医院服务器上的人是非常多的,要明白你是哪个,才能获取先关信息,而就诊卡在这里就是cookie。
1.2session
而医院的数据服务器上就保存着用户的信息也就是通过session 的方式来保存的。也就类似于我们前面所说的微信聊天记录的对话框,cookie相当于这个这个账号的信息,登录后就可以继续以往的操作,而session就是相当于里面一条一条的对话框,也就是和不同人的聊天记录;
1.3cookie和session的区别
Cookie 是客户端的机制. Session 是服务器端的机制.Cookie 和 Session 经常会在一起配合使用. 但是不是必须配合.完全可以用 Cookie 来保存一些数据在客户端. 这些数据不一定是用户身份信息, 也不一定是token / sessionIdSession 中的 token / sessionId 也不需要非得通过 Cookie / Set-Cookie 传递.
2.核心方法
这里的核心方法是指servlet提供的一些API
①HttpServletRequest 类中的相关方法
getSession()方法:
(1)参数:既能获取到服务器上的对话,也能够用于创建对话,具体行为,取决于参数。如果参数为true,若是此时会话存在则获取,会话不存在则创建;如果此时参数为false,若是此时会话存在则获取,不存在则返回null;
(2)在调用getSession()时,具体要做的事情
a.创建对话
首先先获取到请求中cookie里面的sessionld字段(相当于会话的身份标识),判断这个sessionld是否在当前服务器上存在,如果不存在,则进入创建会话逻辑。
创建会话:会创建一个HttpSession对象,并且生成一个sessionld(一个很长的数字,通常用16进制来表示,来保证唯一性),接下来就会把这个sessionld作为key,把这个HttpSession对象作为value,把这个键值对,给保存到服务器内存的一个类似于“哈希表”这样的结果中。(实际的实现不一定真实Hash表,但是一定是类似的能够存储键值对的结构,并且这个数据是在内存中的),再然后,服务器就会返回一个HTTP响应,把sessionld通过Set-Cookie字段返回给浏览器,浏览器就可以保存这个sessionld到cookie中了。
b.获取会话先获取到请求中cookie里面的sessionld字段(也就是会话的身份标识),判定这个sessionld是否在当前服务器上存在,也就是是否存在于类似于哈希表这样的结构中,如果有,就直接查询出这个HttpSession对象,并且通过返回值返回回去。
(3)HTTPSession
这个对象本质上是一个“键值对”的结构,允许我们往HTTPSession对象中,存取任意的键值对数据(key必须是String,value是一个Object)
内部结构图如下:
在一个服务器中可以存在多个HTTPSession,每个HttpSession对象中又包含了若干的键值对,里面的key,和value都是程序员自定义的,HttpSession中的每个键值对,称为属性(Atrribute),而HttpSession提供了两个方法:分别是getAtrribute用来取键值对,setAtrribute用来存键值对。
getCookie()方法:
(1)cookie中的说明:
获取请求中的cookie数据。getCookie()的返回值是cookie类型的数组,每个元素是一个Cookie对象,每个cookie对象又包含了两个属性,name和value(仍然是以键值对的形式存在)。HTTP请求中的cookie字段就是按照键值对的方式来组织的,这里的这些键值对,大概的格式,使用;来分割多个键值对,使用=来分割键和值,这些键值对都会在请求中通过cookie字段传给服务器,服务器收到请求之后,就会进行解析,解析成上述看到的cookie[]这样的形式。cookie这里是可以保存任意自定制的键值对,如果是一般的键值对,直接通过getCookies来获取,如果是特殊的键值对(表示sessionld的键值对),不需要使用getCookies,直接用getSession其实就自动帮我们从cookie中取得sessionld了。
(2)cookie类中的相关方法:
②HttpServletResponse 类中的相关方法
响应中就可以根据addCookie这个方法,来添加一个cookie信息到响应报文中,这里添加进来的键值对,就会作为HTTP响应中的set-cookie字段来表示
3.案例一:实现用户登录
①解释要实现的操作:
我们需要实现的是可以输入用户名和密码实现登录,然后服务器会给客户端返回一个302,表示服务器上存储成功,然后通过客户端请求获取主页,然后从服务器获取主页。
图示如下:
②步骤:
(1)我们需要约定前后端的交互接口,我们这里需要两组交互:一个是登录,另一个是获取主页。而针对前后端交互接口的话,实际上有很多种约定方式,我们选择下面这种来进行约定 我们可以看出我们登录的交互使用的是post请求,并且类型使用form表单来进行完成的,而相应也是转到了另一个页面。而获取主页的交互是由get请求来完成的,而相应的body中也是一个简单的html文件来进行表示的。
(2)实现登录的交互:
a.前端用form表单来实现
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登录页面</title> </head> <body> <form action="/login" method="post"> <input type="text" name="userName"> <input type="text" name="password"> <input type="submit" value="login"> </form> </body> </html>
b.编写一个servlet来处理这个登录请求
import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; @WebServlet("/login") public class loginServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //用户请求,从用户这里获取到输入的账户和密码 //getParameter()可以得到它的value值 String userName=req.getParameter("userName"); String password=req.getParameter("password"); //判断用户名或者密码是否正确 //正常来讲是应该放在数据库中的,这个样子可以核对,我们这里假设账户需要为lisi,密码需要为12345才对 //我们利用equals来判断,为了避免空指针异常的情况出现,所以我们这里直接用账户和密码来比对 if ("lisi".equals("userName")&&"12345".equals("password")){ //为了当输入账户密码成功时,要跳转到index页面,我们需要获取到当前用户的信息 //这个时候我们就需要创建好一个session来供后面使用 //并且在session中填写一些必要的身份信息,以供后面的逻辑来使用(身份信息需要啥就保存啥) //创建会话,并保存身份信息(当有的时候就获取,没得时候就创建,所以是true) HttpSession httpSession=req.getSession(true); //往会话中存储键值对必要的信息 httpSession.setAttribute("userName",userName); //这里还可以实现一个登录次数的信息 httpSession.setAttribute("count",0); //表明登录成功,那么这里就会进行跳转,重定向到另一个页面 resp.sendRedirect("index"); }else{//登陆失败,返回失败 resp.getWriter().write("login failed"); } } }
(3)页面交互:
a.编写服务器返回主页的逻辑
import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; @WebServlet("/index") public class indexServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //这里的参数应该是false,之前创建了,这里如果是空返回null,不是空,则返回存储的 HttpSession httpSession = req.getSession(false); //然后通过getAttribute这个方法就可以获取到信息了,因为是object类,所以强制转换成String类 String username = (String)httpSession.getAttribute("username"); //每访问一次页面则count+1 Integer count = (Integer) httpSession.getAttribute("count"); count += 1; //需要把次数更新写回 httpSession.setAttribute("count",count); //设置数据格式 resp.setContentType("text/html;charset=utf8"); //这里就直接返回一个简单的页面就可以了 resp.getWriter().write("<h3> 欢迎你!" + username +" 这是第" + count + "次访问页面 </h3>"); } }
输出结果:(每刷新一次,count+1)
(4)遇到的难点:
a.如何保证拿到的是同一用户
b.为什么要用Interger来接收count
4.案例二:上传文件
上传文件也是属于开发中的一个典型的需求,我们常用getPart()方法来处理。
①part核心方法:
每个文件都称为一个Part,每个part都有一个name(身份标识),服务器代码中就可以根据name,招待对应的part,基于这个part既可以进一步获取到文件的信息,进行下一阶段的操作
②关于part另外的方法:
方法 描述 getSubmittedFileName() 获取文件名 getContentType() 获取文件类型 long getSize() 获取文件大小 void write(String path) 将提交的文件写入到磁盘文件中去 ③上传文件:
(1)前端:使用form表单
原理:上传文件的时候,此时form表单就需要使用到特殊的类型form-data,然后提交文件的时候,浏览器就会把文件内容以form-data的格式构造到HTTP请求中去了,服务器就通过这个getPart方法就可以获得到这个文件的内容。
代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>提交文件</title> </head> <body> <!-- 这里enctype="multipart/form-data"就是使用form-data的格式构造到请求中 --> <form action="file" method="post" enctype="multipart/form-data"> <!-- 设置为file就会有个自带的选择文件的按钮 --> <input type="file" name="MyImage"> <input type="submit" value="提交"> </form> </body> </html>
(2)后端操作:
import javax.servlet.ServletException; import javax.servlet.annotation.MultipartConfig; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.Part; import java.io.IOException; @MultipartConfig @WebServlet("/file") public class fileServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //要上传文件就需要获取这个文件,而通过getPart方法就可以获取到 //而这里的参数就是html里面的那么内容 Part part = req.getPart("MyImage"); //然后这里可以打印出这个文件的一系列信息 System.out.println(part.getSubmittedFileName());//获取文件名字 System.out.println(part.getContentType());//获取文件类型 System.out.println(part.getSize());//获取文件大小 //将这个文件写入到哪里去 part.write("C:\\zhuomian\\picture.jpg"); resp.setContentType("text/html;charset=utf8"); resp.getWriter().write("上传成功!"); } }
结果展示:
servlet的内容就告一段落啦!