1. 重定向(Redirect)
在SpringMVC项目中,如果处理请求的方法的返回值是String
类型的,则返回值默认表示转发到的视图名称,如果需要使用重定向,则应该使用redirect:
作为前缀,并加上重定向到的目标路径(在网址中体现的)!
return "redirect:index.do";
2. 使用Session
Session是保存在服务器端的内存中的数据。
在SpringMVC框架中,在处理请求的方法的参数列表中添加HttpSession
类型的参数,即可使用Session!例如向Session中存入数据:
session.setAttribute("username", username);
后续,在Java程序中,就可以获取以上数据:
String username = session.getAttribute("username");
如果需要在Thymeleaf模版页面中显示Session中的数据,可以例如:
<span th:text="${session.username}">XXX</span>
后续,当需要清除Session中的数据时,调用invaliate()
方法即可:
session.invalidate();
在SpringMVC中,也提供了框架所特有处理Session的做法,可以通过ModelMap
封装Session中的数据,并结合在类之前添加@SessionAttriubtes({"id", "username"})
注解来确定ModelMap
中哪些数据是Session数据!但是,这种做法并不直观,并且与传统的Session机制不同,甚至都无法通过session.invalidate()
清除Session的数据,只能通过SpringMVC框架的机制进行管理!通常,并不推荐这样使用Session!
使用传统的方式(使用HttpSession
)的唯一缺点是不便于执行单元测试!但是,一般控制器中的方法并不会执行单元测试!通常,可以直接在浏览器的地址栏中输入URL来测试控制器中的方法,或者,使用专业的测试软件进行测试!
甚至,在一些大型的应用中,根本就不会去使用Session。
3. 拦截器(Interceptor)
3.1. 基本概念
假设设定规则:如果用户没有登录,不允许访问用户中心页面!
@RequestMapping("user.do")
public String showUser(HttpSession session) {
System.out.println("UserController.showUser()");
// 判断用户是否已经登录
if (session.getAttribute("username") == null) {
// 如果没有登录,转到登录页
System.out.println("\t没有登录信息");
return "redirect:login.do";
}
return "user";
}
在绝大部分应用中,需要用户登录才可以进行的操作种类非常多,那么,处理相关请求时,都需要添加以上判断登录的代码!但是,在多个处理请求的方法中都粘贴相同的代码,这样的做法是不可行的,工作量较大,不易于调整,不易于管理维护!
在SpringMVC框架中,使用拦截器可以解决以上问题!
拦截器(Interceptor)是可以执行在控制器之前的组件,则可以在拦截器对若干种请求进行相关判断,以决定是否执行控制器中的方法!最终选择阻止运行,或选择放行!
3.2. 创建拦截器类
在SpringMVC框架中,可以将自定义的拦截器放在任何包中!即:并不要求放在组件扫描范围之内!
可以创建cn.tedu.spring.LoginInterceptor
拦截器,实现HandlerInterceptor
接口:
public class LoginInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("LoginInterceptor.preHandle()");
return false;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("LoginInterceptor.postHandle()");
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("LoginInterceptor.afterCompletion()");
}
}
3.3. 配置拦截器
拦截器必须在spring.xml中添加配置:
<!-- 配置拦截器链 -->
<mvc:interceptors>
<!-- 配置第1个拦截器 -->
<mvc:interceptor>
<!-- 拦截路径 -->
<mvc:mapping path="user.do"/>
<!-- 拦截器类 -->
<bean class="cn.tedu.spring.LoginInterceptor" />
</mvc:interceptor>
<!-- 配置第2个拦截器 -->
<!-- 配置第3个拦截器 -->
</mvc:interceptors>
通过运行,可以看到效果及结论:
-
当
preHandle()
方法返回false
时,表示阻止继续运行,在浏览器显示一片空白,并且,阻止继续运行时,控制器中的方法并不会被执行,拦截器类中剩下的2个方法也不会执行! -
当
preHandle()
方法返回true
时,表示放行,即允许向后执行,则浏览器可以显示希望访问的页面,在Eclipse的控制台中,可以看到先执行了控制器的方法,然后依次执行了拦截器中的postHandle()
和afterCompletion()
方法!即:preHandle()
-> 控制器中的方法 ->postHandle()
->afterCompletion
。
所以,可以在preHandle()
中添加对Session的判断:
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("LoginInterceptor.preHandle()");
// 判断用户是否已经登录
if (request.getSession()
.getAttribute("username") == null) {
// 重定向到登录页
String contextPath = request.getContextPath();
response.sendRedirect(contextPath + "/login.do");
// 如果没有登录,则阻止继续运行
return false;
}
// 放行
return true;
}
然后,在处理user.do
请求的showUser()
方法中,就不再需要判断Session的代码了!
-------------------------
附1:关于GET请求与POST请求
GET与POST都是HTTP请求的提交方式之一,其实,还有其它的提交方式,例如PUT、DELETE等,但是,一般只使用GET与POST这2种。
如果使用GET方式提交请求,请求参数将被体现在URL中,例如http://localhost:8080/reg.do?username=root&password=1234
,如果使用POST方式提交请求,请求参数将被封装在请求体中,并不会表现在URL中!
由于GET请求会把请求参数的名称与值都体现在URL中,所以,被视为是一种不安全的提交方式,通常,不建议用于提交敏感数据,例如涉及账号安全的、涉及用户隐私的等,另外,还会受到URL长度的限制,通常理解为2K即可(具体值取决于浏览器和服务器端的限制值)。
以上GET请求存在的问题,在POST请求中都不存在!但是,POST请求并不能完全取代GET请求,有些操作必须通过GET方式才可以实现,例如:搜索,收藏,分享。
另外,GET请求的提交效率要高于POST请求!当使用GET方式提交请求时,URL中的参数将直接提交到服务器;当使用POST方式提交请求时,其实并不会直接提交请求参数,当服务器端接收到请求后,客户端会使用同一个连接继续提交请求参数,也就说,POST请求是分2次完成的!
附2:转发与重定向
首先,转发是服务器端内部的行为,而重定向则不是!
在转发过程中,客户只向服务器端发出过1次请求!在重定向过程中,客户端发出第1次请求后,服务器端响应了302及目标路径,然后客户端发出了第2次请求!
在转发过程中,客户端只与服务器端的控制器直接交互,所以,在客户端的浏览器中,只显示请求的路径,即控制器的路径!在重定向过程中,客户端与服务器出现2次交互过程,在浏览器中,显示的是最后一次交互的URL!
在编程时,使用SpringMVC框架,当处理请求的方法的返回值是String
时,转发的返回值是视图名称,重定向的返回值中redirect:
右侧是路径。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8PqyVEeb-1572542192876)(01.png)]
如果使用重定向,客户端浏览器中的URL是最后一次请求的URL,应该可以反复刷新页面,却不会重复此前提交的数据!如果希望刷新时不会重复提交此前的数据,则必须使用重定向!
使用重定向也是有缺点的!因为重定向的过程中出现过多次请求,基于HTTP协议是无状态协议,则第1次请求时产生的数据,在第2次处理请求的过程中,是不可以直接使用的!而转发是服务器内部的行为,整个处理过程中,只发生过1次请求,所以,控制器中产生的数据可以直接由页面来呈现!
附3:使用Session存储哪些数据
Session是保存在服务器端内存中的数据,如果服务器端设置Session的有效期是30分钟,则保存到Session中的数据至少会存在30分钟以上的时间!
通常,会存入到Session的数据有:
-
用户的身份标识,例如用户的id;
-
使用频率较高的数据,例如用户名;
-
不便于使用其它技术存取的数据。