北京尚学堂2020java_SpringMVC第三天
第一节 SpringMVC拦截器学习
Servlet提供了原生的过滤器,其执行时机是在servlet之前。而使用SpringMVC之后,就只有一个servlet,如果使用拦截器那么就会拦截DS前的所有请求。有的部门不想被拦截,怎么办?——使用拦截器,其执行时机位DS之后,单元方法之前。其作为对单元方法进行过滤。
DispactherServlet能拿到的所有对象都在springmvc容器里
拦截器的使用:
- 创建实现了指定接口的java类
- 在拦截器中声明对应的功能代码
- 配置been及其拦截范围
1.1 拦截器代码实现
1.在inteceptor类中创建一个类:
package com.bjsxt.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return false; // false不会放行去执行单元方法,如果想放行返回true
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
1.2 拦截器方法详解
1.2.1 preHandle参数详解
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
handler中存储了此次单元方法请求对象HanlderMethod的实例化对象,可以通过反射拿到对象并调用方法。
拦截器需要调用mycontroller的方法,就需要拿到它的实例化对象,这两个对象都在springmvc容器中,即b和a都在springmvc容器中,b又需要a,这就是依赖注入,由autowired注释来解决这个问题。
@Autowired
private MyController myController;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println(handler instanceof HandlerMethod);
// 可以通过反射拿到单元方法
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
method.invoke(myController,null);
System.out.println("MyInterceptor.preHandle");
return true ;
}
1.2.2 postHandle方法详解
这段代码并非是返回string,而是会将请求转发到名为aa的单元方法,学了springmvc之后应该从这个角度来理解
@RequestMapping("demo")
public String testMethod() {
// 处理请求
System.out.println("MyController.testMethod:我是单元方法");
return "aa";
}
postHandle执行的时机:单元方法执行之后执行,单元方法请求转发的jsp执行之前。preHandle->单元方法->postHandle->jsp
作用:可以对请求转发的数据进行修改,还可以对单元方法要响应的资源进行重新定义。
- 对请求转发的数据进行修改
比如单元方法中设置了这样的数据:
// 声明单元方法
@RequestMapping("demo")
public String testMethod(Model model) {
// 处理请求
System.out.println("MyController.testMethod:我是单元方法");
model.addAttribute("str", "我是中国人");
return "aa.jsp";
}
然后在com/bjsxt/interceptor/MyInterceptor.java想要对“中国”这两字进行和谐:
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
// 对model中要流转的数据进行置换和处理
// 重新设定要跳转的资源路径
// modelAndView.setViewName("forward:/bb.jsp");
// 更改流转的数据
Map<String ,Object> model = modelAndView.getModel();
String str = (String)model.get("str");
if(str.contains("中国")) {
str = str.replaceAll("中国", "**");
}
model.put("str", str);
System.out.println("MyInterceptor.postHandle");
}
- 对要响应的资源进行重定义
本来单元方法让跳转到aa.jsp的,但经过检查决定跳转到bb.jsp:
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
// 重新设定要跳转的资源路径
modelAndView.setViewName("forward:/bb.jsp");
System.out.println("MyInterceptor.postHandle");
}
1.2.3 afterCompletion方法
检测请求过程是否正常执行:
- 处理在请求过程中出现的异常信息
- 请求的日志信息
- 资源流的关闭
执行时机:本次请求的最后,在jsp之后
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
if(ex != null) {
System.out.println("出现异常,使用log4j打印异常信息");
return;
}
System.out.println("MyInterceptor.afterCompletion");
}
1.2 多重拦截器配置总结
如果对于同一个单元方法,有N多层拦截器,那么配置在上的为外层拦截器,配置在下的为内层拦截器,中间是单元方法。
那么执行的方法顺序为上pre->下pre->单元方法->下post->上post->下afer->上after
第二节 SpringMVC运行原理
核心组件:(SpringMVC 四大组件)
- DispatchServlet: Servlet分发器,整个SPringMVC框架入口.
- HandlerMapping:寻找URL所请求的HandlerMethod,找@RequestMapping() 负责寻找单元方法
- 使用实现类DefaultAnnotationHandlerMapping实际工作.
- HandlerAdapter:实际调用HandlerMethod的组件. 实际调用方法
- 使用实现类AnnotationMethodHandlerAdapter
- ViewResovler:视图解析器.作用解析HandlerMethod返回值.把逻辑视图转换为需要调用的物理视图.
- 自定义时:InternalResourceViewResolver
当用户发起请求后,执行DiapacherServlet,如果是JSP直接调用jsp页面.如果不是JSP,DiapacherServlet调用HandlerMapping判断请求URL是否合法,如果URL不存在报错,如果URL存在使用HandlerAdapter调用具体的HandlerMethod,当HandlerMethod执行完成后会返回ModelAndView,会被ViewResovler解析,调用具体的物理视图.
第三节 SSM框架知识复习
第四节 SpringMVC对象ajax请求
问题:当浏览器发起一个ajax请求给服务器,服务器调用对应的单元方法处理ajax请求,而ajax的请求在被处理后需要立即响应。而目前我们在单元方法中响应ajax请求使用的是response对象,需要我们自己要响应的数据转换为json字符串响应比较麻烦,怎么办?而我们一直在单元方法中无论是否是ajax请求,都使用return语句来完成响应。
解决:既然我们希望使用单元方法的返回值来响应ajax请求的处理结果,而目前DispatcherServlet的底层会将单元方法的返回值按照请求转发或者重定向来处理,所以就需要我们告诉DispatcherServlet,单元方法的返回值不要按照请求转发或者重定向处理,而是按照直接响应处理,将单元方法的返回值直接响应给浏览器。
前端代码接收js请求:
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="<%=basePath %>"/>
<title>Title</title>
<%--引入jquery文件--%>
<script type="text/javascript" src="js/j.js"></script>
<%--声明js代码域--%>
<script type="text/javascript">
//声明页面加载事件
$(function () {
//给按钮增加单击事件
$("#btn").click(function () {
$.get("testAjax",{uname:"张三",age:18},function (data) {
alert(data.uname)
})
})
})
</script>
</head>
<body>
<h3>SpringMVC响应ajax请求处理结果</h3>
<hr>
<input type="button" value="点击发起ajax请求" id="btn">
</body>
</html>
后台代码非常简单:1.加上@ResponseBody注解2.把返回值类型改成某个具体的类3.导入jackjson包
在ajax的回调函数中,无需再次使用eval函数将响应数据转换为json对象,直接使用即可。
@Controller
public class MyController {
// 处理ajax请求并响应结果
@ResponseBody
@RequestMapping("testAjax")
public User testAjax(String uname, int age) {
// 处理请求
System.out.println("uname = " + uname + ", age = " + age);
// 响应结果
// 常规的方法是
User user = new User(1, "王五", "123");
// 直接返回要响应的数据
return user;
}
}