1.异步调用
1.发送异步请求
<a href="javascript:void(0);" id="testAjax">访问controller</a>
<script type="text/javascript" src="js/jquery-3.7.1.js"></script>
<script type="text/javascript">
$(function(){
$("#testAjax").click(function(){ //为id="testAjax"的组件绑定点击事件
$.ajax({ //发送异步调用
type:"POST", //请求方式: POST请求
url:"ajaxController", //请求参数(也就是请求内容)
data:'ajax message', //请求参数(也就是请求内容)
dataType:"text", //响应正文类型
contentType:"application/text", //请求正文的MIME类型
});
});
});
</script>
接收异步请求参数
名称: @RequestBody
类型: 形参注解
位置:处理器类中的方法形参前方
作用:将异步提交数据组织成标准请求参数格式,并赋值给形参
范例
@RequestMapping("/ajaxController")
public String ajaxController(@RequestBody String message){
System.out.println(message);
return "page.jsp";
}
注解添加到Pojo参数前方时,封装的异步提交数据按照Pojo的属性格式进行关系映射
注解添加到集合参数前方时,封装的异步提交数据按照集合的存储结构进行关系映射
@RequestMapping("/ajaxPojoToController")
//如果处理参数是POJO,且页面发送的请求数据格式与POJO中的属性对应,@RequestBody注解可以自动映射对应请求数据到POJO中
//注意:POJO中的属性如果请求数据中没有,属性值为null,POJO中没有的属性如果请求数据中有,不进行映射
public String ajaxPojoToController(@RequestBody User user){
System.out.println("controller pojo :"+user);
return "page.jsp";
}
@RequestMapping("/ajaxListToController")
//如果处理参数是List集合且封装了POJO,且页面发送的数据是JSON格式的对象数组,数据将自动映射到集合参数中
public String ajaxListToController(@RequestBody List<User> userList){
System.out.println("controller list :"+userList);
return "page.jsp";
}
2.异步请求接受响应数据
方法返回值为Pojo时,自动封装数据成json对象数据
@RequestMapping("/ajaxReturnJson")
@ResponseBody
public User ajaxReturnJson(){
System.out.println("controller return json pojo...");
User user = new User();
user.setName("Jockme");
user.setAge(40);
return user;
}
@RequestMapping("/ajaxReturnJsonList")
@ResponseBody
//基于jackon技术,使用@ResponseBody注解可以将返回的保存POJO对象的集合转成json数组格式数据
public List ajaxReturnJsonList(){
System.out.println("controller return json list...");
User user1 = new User();
user1.setName("Tom");
user1.setAge(3);
User user2 = new User();
user2.setName("Jerry");
user2.setAge(5);
ArrayList al = new ArrayList();
al.add(user1);
al.add(user2);
return al;
}
3.跨域访问
跨域访问介绍
当通过域名A下的操作访问域名B下的资源时,称为跨域访问
跨域访问时,会出现无法访问的现象
跨域环境搭建
为当前主机添加备用域名
修改windows安装目录中的host文件
格式:ip 域名
动态刷新DNS
命令:ipconfig /displaydns
命令:ipconfig /flushdns
跨域访问支持
名称: @CrossOrigin
类型: 方法注解 、 类注解
位置:处理器类中的方法上方 或 类上方
作用:设置当前处理器方法/处理器类中所有方法支持跨域访问
@RequestMapping("/cross")
@ResponseBody
//使用@CrossOrigin开启跨域访问
//标注在处理器方法上方表示该方法支持跨域访问
//标注在处理器类上方表示该处理器类中的所有处理器方法均支持跨域访问
@CrossOrigin
public User cross(HttpServletRequest request){
System.out.println("controller cross..."+request.getRequestURL());
User user = new User();
user.setName("ljb");
user.setAge(21);
return user;
}
2.拦截器
1.拦截器概述
请求处理过程解析
拦截器( Interceptor)是一种动态拦截方法调用的机制
作用:
在指定的方法调用前后执行预先设定后的的代码
阻止原始方法的执行
核心原理: AOP思想
拦截器链:多个拦截器按照一定的顺序,对原始被调用功能进行增强
拦截器VS过滤器
归属不同: Filter属于Servlet技术, Interceptor属于SpringMVC技术
拦截内容不同: Filter对所有访问进行增强, Interceptor仅针对SpringMVC的访问进行增强
2.自定义拦截器的开发
package com.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class InterceptorController {
@RequestMapping("/handleRun")
public String handleRun(){
System.out.println("业务处理器运行---------main");
return "page.jsp";
}
}
实现HandlerInterceptor接口
package com.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//自定义拦截器需要实现HandleInterceptor接口
public class MyInterceptor implements HandlerInterceptor {
//处理器运行之前执行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("前置运行----a1");
//返回值为false将拦截原始处理器的运行
//如果配置多拦截器,返回值为false将终止当前拦截器后面配置的拦截器的运行
return true;
}
//处理器运行之后执行
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("后置运行----b1");
}
//所有拦截器的后置执行全部结束后,执行该操作
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("完成运行----c1");
}
//三个方法的运行顺序为 preHandle -> postHandle -> afterCompletion
//如果preHandle返回值为false,三个方法仅运行preHandle
}
<context:component-scan base-package="com"/>
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/handleRun"/>
<bean class="com.interceptor.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
<mvc:annotation-driven/>
注意:配置顺序为先配置执行位置,后配置执行类
3.拦截器配置与方法参数
前置处理方法
原始方法之前运行
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
System.out.println("preHandle");
return true;
}
参数:
request:请求对象
response:响应对象
handler:被调用的处理器对象,本质上是一个方法对象,对反射中的Method对象进行了再包装
返回值:
返回值为false,被拦截的处理器将不执行
后置处理方法
原始方法运行后运行,如果原始方法被拦截,则不执行
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("postHandle");
}
参数:
modelAndView:如果处理器执行完成具有返回结果,可以读取到对应数据与页面信息,并进行调整
完成处理方法
拦截器最后执行的方法,无论原始方法是否执行
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) throws Exception {
System.out.println("afterCompletion");
}
参数:
ex:如果处理器执行过程中出现异常对象,可以针对异常情况进行单独处理
拦截器配置项
<mvc:interceptors>
<!--开启具体的拦截器的使用,可以配置多个-->
<mvc:interceptor>
<!--设置拦截器的拦截路径,支持*通配-->
<!--/** 表示拦截所有映射-->
<!--/* 表示拦截所有/开头的映射-->
<!--/user/* 表示拦截所有/user/开头的映射-->
<!--/user/add* 表示拦截所有/user/开头,且具体映射名称以add开头的映射-->
<!--/user/*All 表示拦截所有/user/开头,且具体映射名称以All结尾的映射-->
<mvc:mapping path="/*"/>
<mvc:mapping path="/**"/>
<mvc:mapping path="/handleRun*"/>
<!--设置拦截排除的路径,配置/**或/*,达到快速配置的目的-->
<mvc:exclude-mapping path="/b*"/>
<!--指定具体的拦截器类-->
<bean class="MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
4.多拦截器配置
当配置多个拦截器时,形成拦截器链
拦截器链的运行顺序参照配置的先后顺序
当拦截器中出现对原始处理器的拦截,后面的拦截器均终止运行
当拦截器运行中断,仅运行配置在前面的拦截器的afterCompletion操作
附:责任链模式
责任链模式是一种行为模式
特征:
沿着一条预先设定的任务链顺序执行,每个节点具有独立的工作任务
优势:
独立性:只关注当前节点的任务,对其他任务直接放行到下一节点
隔离性:具备链式传递特征,无需知晓整体链路结构,只需等待请求到达后进行处理即可
灵活性:可以任意修改链路结构动态新增或删减整体链路责任
解耦:将动态任务与原始任务解耦
弊端:
链路过长时,处理效率低下
可能存在节点上的循环引用现象,造成死循环,导致系统崩溃
3.异常处理
1.异常处理器
HandlerExceptionResolver接口(异常处理器)
@Component
public class ExceptionResolver implements HandlerExceptionResolver {
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) {
System.out.println("my exception is running...");
ModelAndView modelAndView = new ModelAndView();
//定义异常现象出现后,反馈给用户查看的信息
modelAndView.addObject("msg","出错啦! ");
//定义异常现象出现后,反馈给用户查看的页面
modelAndView.setViewName("error.jsp");
return modelAndView;
}
}
根据异常的种类不同,进行分门别类的管理,返回不同的信息
public class ExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) {
System.out.println("my exception is running ...."+ex);
ModelAndView modelAndView = new ModelAndView();
if( ex instanceof NullPointerException){
modelAndView.addObject("msg","空指针异常");
}else if ( ex instanceof ArithmeticException){
modelAndView.addObject("msg","算数运算异常");
}else{
modelAndView.addObject("msg","未知的异常");
}
modelAndView.setViewName("error.jsp");
return modelAndView;
}
}
2.注解开发异常处理器
使用注解实现异常分类管理
名称: @ControllerAdvice
类型: 类注解
位置:异常处理器类上方
作用:设置当前类为异常处理器类
名称: @ExceptionHandler
类型: 方法注解
位置:异常处理器类中针对指定异常进行处理的方法上方
作用:设置指定异常的处理方式
@Component
@ControllerAdvice
public class ExceptionAdvice {
@ExceptionHandler(Exception.class)
@ResponseBody
public String doNullException(Exception ex){
return "空指针异常";
}
}
3.异常处理解决方案
4.自定义异常
package com.exception;
//自定义异常继承RuntimeException,覆盖父类所有的构造方法
public class BusinessException extends RuntimeException {
public BusinessException() {
}
public BusinessException(String message) {
super(message);
}
public BusinessException(String message, Throwable cause) {
super(message, cause);
}
public BusinessException(Throwable cause) {
super(cause);
}
public BusinessException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
异常触发方式
if(user.getName().trim().length()<4) {
throw new BusinessException("用户名长度必须在2-4位之间,请重新输入! ");
}
通过自定义异常将所有的异常现象进行分类管理,以统一的格式对外呈现异常消息