1 测试1[2024-5-23-9:00]
两次获取Session,第一次在查询到用户名密码是否与数据库数据匹配之前,即没有显式地getSession
之前;
第二次在查询到用户名密码与数据库数据匹配,显式地getSession
之后。
未通过登录验证的Session
通过登录验证的Session
结论
Session生命周期并不是从第一次执行req.getSession()
时创建,这里的第一次指的是程序员第一次显式地在后端程序中写req.getSession()
[2024-5-23-11:02]进一步补充:
流程是服务器启动->自动访问index.jsp
->点击登录,访问login.jsp
->输入用户名密码->发送servlet请求->后端处理,打印两次session
这个session是由jsp自动创建的,即在自动访问index.jsp
时,就已经有了,详见测试2
2 测试2[2024-5-23-10:50]
<%@ page session="ture" %>
(默认的,没有显式写出来)
访问index.jsp
:
在index.jsp
中加一句<%@ page session="false" %>
访问index.jsp
:
再访问login.jsp
:
login.jsp
没加<%@ page session="false" %>
,默认会创建session
结论
一定程度说明,jsp的本质是servlet
3 GPT-Session的自动创建
是的,自动创建Session以备不时之需确实是一个合理的解释。让我们深入探讨一下这种自动创建Session的行为及其背后的原因。
自动创建Session的原因
-
状态管理的需要:
- Web应用需要在多个请求之间保持一些用户的状态信息,如购物车内容、表单数据、用户偏好等。
- 即使当前请求没有显式使用Session,未来的请求可能会需要Session。因此,提前创建Session可以确保状态管理的准备工作已经完成。
-
简化开发:
- 自动创建Session可以简化开发工作,开发人员不必显式地在每个需要状态管理的请求中创建Session。
- 开发人员可以随时调用
request.getSession()
而不需要担心Session是否已经创建。
-
默认行为:
- 某些容器和框架的设计默认是为了简化开发流程,因此会在合适的时机自动创建Session。
- 这种行为确保了一致的用户体验和简化的状态管理。
具体示例和行为
JSP页面自动创建Session
在JSP页面中,默认情况下Session是启用的。这是为了确保在页面中使用Session相关功能(如存储用户信息)时,不会因为Session未创建而导致问题。
<%@ page session="true" %>
Servlet自动创建Session
即使在Servlet中没有显式地调用request.getSession()
,当某些框架或过滤器需要使用Session时,它们会隐式地调用getSession()
方法,这就触发了Session的创建。
实际应用中的影响
用户登录示例
即使在用户未登录的情况下,自动创建Session可以确保未来的请求中,服务器能够方便地存储和访问用户的临时数据。
示例代码
假设你有一个简单的Servlet,它没有显式创建Session:
@WebServlet("/example")
public class ExampleServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 没有显式创建Session
response.getWriter().println("Hello, World!");
}
}
尽管在代码中没有调用request.getSession()
,但响应中可能仍包含Set-Cookie
头,这意味着Session已经被创建。
使用过滤器或框架时的Session创建
一些过滤器或框架可能在处理请求时隐式地调用了getSession()
,例如:
- 安全过滤器:检查用户是否已登录。**【注释】**检查登录肯定要看session里边有没有用户,一旦请求,即使没有也会创建(
getSession()
默认参数为true) - 用户跟踪:记录用户的访问路径和行为。
- 临时数据存储:如购物车、表单数据等。
这些场景下,即使你在Servlet中没有显式创建Session,框架或过滤器的工作机制也会导致Session的创建。
控制Session的创建
如果你不希望自动创建Session,可以在JSP页面中禁用Session,或者在Servlet中避免调用request.getSession()
,并确保框架和过滤器不会隐式创建Session。
禁用JSP页面中的Session
<%@ page session="false" %>
确保Servlet不创建Session
确保在Servlet代码中没有调用request.getSession()
。
总结
- 自动创建Session的目的:为了简化开发,确保在未来请求中需要状态管理时Session已经准备好。
- 常见场景:JSP页面、使用框架和过滤器时会自动创建Session。
- 控制创建:可以通过配置和代码避免不必要的Session创建。
这种自动创建Session的机制可以确保Web应用在处理状态管理时更加灵活和可靠。**【注释】**可把初学者害惨了
4 登录验证与自动登录
登录验证
单纯的登录验证并不一定需要Session的参与,如果只是简单地控制页面跳转。
功能1 根据登录信息跳转(单纯跳转,并不需要Session)
UserServlet
:
登录信息匹配------>跳转到相关页面
登录信息不匹配---->跳转到失败页面
功能2 页面右上角展示用户相关信息(需要用到Session)
UserServlet
:
登录信息匹配------>将登录信息存到session,跳转到相关页面
用户信息展示------>相关页面从session中获取到用户信息并展示
或者不用Session使用转发(重定向不行):
UserServlet
:
登录信息匹配------>将登录信息存到request,跳转到相关页面
用户信息展示------>相关页面从request中获取到用户信息并展示
本质就是借助域对象存储信息,实现信息的“持久化”
域对象的范围:
-
request的范围只在转发中有效。
-
session的范围是当前这个用户的所有操作都有效。
-
servletContext的范围整个项目都有效。
使用原则:
小的范围能完成功能就放到小的里面。
结合过滤器
LoginFilter
:
只有少输页面可以不登录访问(过滤器直接放行),对于大多数页面,先要能够通过过滤器才能访问到。
如何通过过滤器?自己写放行条件,一般是是否登录,即从Session中获取登录信息,有就是登录,放行;没有就是未登录,拦截。
过滤器是访问每一个未放行的页面都会存在的,实现一次登录,随意访问的效果,第一次登录将用户名密码存到Session中,
过滤器每次从Session中获取用户名密码并验证,决定是否放行,是一个比较好的做法。
思考:
request是不是也能做?
可以但麻烦且危险,每次请求页面附上用户名密码,然后filter从req里边验证用户名密码
不能一次登录省事
自动登录
即使关闭浏览器,再次访问页面自动完成登录
cookie持久化,定义好路径,发送请求时一起带过去,当请求需要判断是否登录的资源时,根据cookie中的信息,执行登录操作(请求session但是空的,然后执行登录)
还有一个思路(未验证):保存我的sessionid,这样就能直接找到已经存有登录信息的session,不用再去和数据库比对等操作的。(如果密码修改了呢?)
filter只登录没有放行:
需要第二次访问页面才可以出现信息
只从cookie中拿到用户名密码进行了登录,并没继续对这也页面请求的处理,没有放行。
5 对于session处理的再思考
modifyPassword
修改密码会直接删除SessionManager
中所有该用户id关联的记录(键值对),
LoginFilter
过滤器会主动查找user对应的session是否可用(是否有键值对),没有则删除该session并重定向至登录;
用户主动注销不会影响session,只是移除其中的user属性;
为了效率->只要user!=null就放行,没有进一步验证->一个账号多处登录,其中一端改密,其他端登录状态不会受到影响->引入会话管理 ->将userid与sessionid绑定->user!=null且会话管理键值对“有效”(存在)才放行->改密时userid所有的键值对标记为“失效”(删掉) ->user!=null且没记录,整个删除session结束会话->重新登录->完成
或者可以在user!=null且没记录时,不删掉整个session,而是移除user属性并重定向,应该也可以实现同样的效果
因为session并不是全局存储结构,一个会话中没法看到其他session,所以没法直接通过遍历所有session并移除user属性的方法, 必须借助一个“全局存储结构”存储每个用户的session,并以此为标记来实现会话同步