SpringMVC02]返回值 ModelAndView、ajax 请求返回 json、全局异常处理、拦截器
目录
- 控制器方法返回值
- ModelAndView
- String
- void
- Object
- 静态资源处理
- 使用``
- 使用``
- 转发重定向
- 转发
- 重定向
- 异常处理
- 拦截器
- 多个拦截器
控制器方法返回值
ModelAndView
参照目录:“SpringMVC入门–使用” 中的代码
String
相当于ModelAndView中的View部分。
@RequestMapping(value = "/returnString.do")
public String receiveObject(){
return "other";
}
如果还想接受参数,那就使用ModelAndView,或者在形参中加入HttpRequest,手动接受即可
@RequestMapping(value = "/returnString.do")
public String receiveObject(HttpServletRequest request,
String name,
Integer age){
request.setAttribute("name", name);
request.setAttribute("age", age);
return "other";
}
另外,如果要返回完整路径,则不能配置视图解析器,否则会报错
void
不能表示数据也不能表示视图,在处理ajax请求时,可以使用void返回值,通过HttpServletRequest输出信息,响应ajax请求。
1、首先,在前端页面借一个按钮,发起ajax请求
<body>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script>
$(function(){
$("button").click(function(){
// alert("btn")
$.ajax({
url:"test/ajaxRequest.do",
data:{
name:"zhangsan",
age:12
},
type:"post",
dataType:"json",
success:function (resp) {
alert(resp.name
}
});
});
});
</script>
<button id="btn">发起ajax</button>
</body>
2、编写控制器方法代码
@RequestMapping(value = "/ajaxRequest.do")
public void ajaxRequest(HttpServletResponse response,
String name,
Integer age) throws IOException {
//这里假设service已经对数据进行处理,返回了一个Student
Student student = new Student();
student.setName(name);
student.setAge(age);
String json = "";
if (student != null){
ObjectMapper objectMapper = new ObjectMapper();
json = objectMapper.writeValueAsString(student);
}
//响应
response.setContentType("application/json;charset=utf-8");
PrintWriter writer = response.getWriter();
writer.println(json);
writer.flush();
writer.close();
}
控制器处理ajax请求,并返回json数据的过程,会发现有一部分是重复的工作,每个方法中都要这样写:
1、java对象转换成json字符串;2、通过response输出json
因此,可以由框架来实现:即最后一种返回值:Object
Object
可以是String、Integer,也可以是List、Map等。返回的数据不是作为逻辑视图出现,而是作为直接在页面上显示的数据出现。需要使用@ResponseBody
注解,将转换后的json数据放入响应体中
实现步骤:
1、加入依赖,springMVC默认使用的是jackson,处理json数据
2、在springMVC配置文件中加入注解驱动<mvc:annotataion-driven>
这一步相当于,将java对象转换成json数据
3、在控制器方法上加上@ResponseBody
注解
这一步相当于,将 json 输出到前端
1、加入依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
2、前端代码
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script>
$(function(){
$("#btn2").click(function(){
$.ajax({
url:"test/returnStudentJson.do",
data:{
name:"lisi",
age:12
},
type:"post",
dataType:"json",
success:function (resp) {
alert(resp.name)
}
});
});
});
</script>
</head>
<body>
<button id="btn2">springmvc内置转换json</button>
</body>
3、控制器代码
@ResponseBody
@RequestMapping(value = "/returnStudentJson.do")
public Student returnStudentJson(String name,Integer age){
Student student = new Student();
student.setName(name);
student.setAge(age);
return student;
}
4、springmvc配置文件中加入注解驱动
<mvc:annotation-driven/>
返回String字符串数据,非视图
/*这里使用@ResponseBody与返回视图的区分
* produces属性指定返回的ContentType
* */
@ResponseBody
@RequestMapping(value = "/returnStringData.do",produces = "text/plain;charset=utf-8")
public String returnString(String name){
return "返回的字符串";
}
静态资源处理
以上的代码全部都是基于<servlet-mapping>
中的<url-pattern>
为.do的情况,我们还有另外一种配置方法:" / "*
这就意味着所有的页面、资源都要交给框架处理,而除了经过注解配置的controller方法以外,框架没有处理一些静态资源如图片、html等未经配置的资源,这些资源一开始都是交由tomcat处理的。要解决这种问题,需要:
使用<mvc:default-servlet-handler/>
<mvc:annotation-driven/>
<!--
第一种处理静态资源的方式:
原理:加入此标签后,框架会创建控制器对象DefaultServletHttpRequestHandle(类似自己创建的Controller类)
此对象可以接受到的请求转发给tomcat的DefaultServlet
同时也要加入注解驱动标签<mvc:annotation-driven/>,否则所有的请求都会被转发给tomcat,自己配置的也会。
-->
<mvc:default-servlet-handler/>
使用<mvc:resources />
在Spring3.0后,spring定义了专门用于处理静态资源访问请求的处理器:ResourceHttpRequestHandle。
并且添加了<mvc:resources />
标签专门用于解决静态资源无法访问的问题,此种方式不依赖tomcat服务器。
<!--
mapping:表示访问静态资源的uri地址,使用通配符**
location:静态资源在你项目中的目录位置
同时也要加入注解驱动标签<mvc:annotation-driven/>
-->
<mvc:resources mapping="/images/**" location="/images/"/>
转发重定向
返回值ModelAndBView
转发
@RequestMapping(value = "/testForward.do")
public ModelAndView testForward(String name, Integer age){
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("name", name);
modelAndView.addObject("age", age);
//forward:完整路径(不和视图解析器一起使用)
modelAndView.setViewName("forward:/WEB-INF/jsp/test.jsp");
return modelAndView;
}
重定向
重定向无法访问WEB-INF中的页面
/*框架会把model中的简单类型数据,转为string使用,
作为重定向页面的get请求参数使用,目的是在重定向的两次请求之间传递数据
因为是两次不同的请求,两个不同的request作用域,因此要取数据的话需要:
${param.name}相当于<%=request.getParameter("name")*/
@RequestMapping(value = "/testRedirect.do")
public ModelAndView testRedirect(String name, Integer age){
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("name", name);
modelAndView.addObject("age", age);
modelAndView.setViewName("redirect:/test.jsp");
return modelAndView;
}
异常处理
springMVC使用的是统一、全局的异常处理。把controller所有异常集中处理,采用的是AOP的思想。把业务逻辑代码和异常处理代码解耦合。
需要这两个注解:@ExceptionHandle、@ControllerAdvice
实现步骤:
- 自定义一个异常类和两个子类
- 创建一个普通类,作为全局异常处理类
- 在类的上方加入@ControllerAdvice
- 在自定义方法中加入@ExceptionHandle
- 创建处理异常的视图页面
- springMVC的配置文件
- 组件扫描器:@controller
- 组件扫描器:@ControllerAdvice
- 注解驱动
自定义异常:
public class MyUserException extends Exception{
public MyUserException() {
super();
}
public MyUserException(String message) {
super(message);
}
}
===================================================================================================
public class NameException extends MyUserException {
public NameException() {
super();
}
public NameException(String message) {
super(message);
}
}
控制器方法:
@RequestMapping(value = "/testException.do")
public ModelAndView testException(String name, Integer age) throws MyUserException {
ModelAndView modelAndView = new ModelAndView();
if (!"zhangsan".equals(name)){
throw new NameException("姓名不正确");
}
modelAndView.addObject("name", name);
modelAndView.addObject("age", age);
modelAndView.setViewName("forward:/WEB-INF/jsp/test.jsp");
return modelAndView;
}
异常处理类:
/*@ControllerAdvice控制器增强,给控制器增加功能(异常处理)*/
@ControllerAdvice
public class GlobalExceptionHandle {
/*处理异常的方法和控制器方法的定义一样,可以有多个参数,可以有ModelAndView、
* String、void等返回值
* 形参:Exception e表示Controller类中抛出的异常对象
*
* @ExceptionHandler:
* 表示异常类型,当此类型异常发生时由此方法处理
* */
@ExceptionHandler(value = NameException.class)
public ModelAndView doNameExcpetion(Exception e){
/*异常处理流程
* 1、需要把异常记录下来,记录到数据库、日志等。
* 记录异常发生的时间、方法、错误内容
* 2、发送通知,把异常信息通过邮件、信息发送给相关人员
* 3、给用户提示
* */
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("msg", "姓名必须是“zhangsan”。");
modelAndView.addObject("ex" , e);
modelAndView.setViewName("nameError");
return modelAndView;
}
}
springMVC组件扫描器
<context:component-scan base-package="com.wm.handle"/>
其他异常:
除NameException以外的所有异常都会经过此方法处理
/*处理其他异常*/
@ExceptionHandler
public ModelAndView defaultException(Exception e){
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("msg", "信息异常!");
modelAndView.addObject("ex" , e);
modelAndView.setViewName("defaultError");
return modelAndView;
}
拦截器
拦截器需要实现HandlerInterceptor接口
拦截器和过滤器类似,但过滤器主要用于过滤请求:设置编码字符集等工作
拦截器是拦截用户请求做请求判断处理。
拦截器是全局的,可以对多个Controller做判断,一个项目可以有0个或多个拦截器
常用于:用户登录处理、权限检查、记录日志
实现步骤:
1、定义类实现HandlerInterceptor接口
2、在springmvc配置文件中声明拦截器
拦截器执行时间:
1、在请求处理之前,也就是controller执行之前
2、在控制器方法执行后
3、在请求处理完之后
拦截器代码:
public class MyInterceptor implements HandlerInterceptor {
/*preHandle:预处理方法
* 参数:
* Object handler:被拦截的控制器对象
* 返回值:
* true:请求通过了验证,可以执行控制器方法
* false:没通过
* 特点:
* 方法在控制器之前先执行的。
* 在这个方法中可以获取请求的信息,验证是否符合要求
* 如:验证用户是否登录、验证用户是否有权限访问某个url
* 如果验证失败则拦截,验证成功才放行,此时才执行controller方法
* */
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
System.out.println("拦截器preHandle");
// request.getRequestDispatcher("/WEB-INF/jsp/tips.jsp").forward(request,response);
return true;
}
/*postHandle:后处理方法
* 参数:
* Object handler:被拦截的控制器对象
* ModelAndView:处理器方法的返回值
* 特点:
* 在处理器方法之后执行。
* 能够获取处理器方法的返回值ModelAndView,可以修改ModelAndView的值
* 主要是对原来的执行结果做二次修正
* */
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("拦截器postHandle");
modelAndView.addObject("date",new Date());
}
/*afterCompletion:最后执行的方法
* 参数:
* Object handler:被拦截的控制器对象
* Exception ex:程序中发生的异常
*特点:
* 请求处理完成后执行的:即视图已经返回给用户了
* 一般用于资源回收
* */
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) throws Exception {
System.out.println("拦截器afterCompletion");
}
}
springmvc配置文件注册拦截器:
<!--拦截器-->
<mvc:interceptors>
<mvn:interceptor>
<!--指定拦截的请求uri地址
path:地址,可以使用通配符:**
**:表示任意字符、文件、或多级目录和目录中的文件
-->
<mvn:mapping path="/student/**"/>
<!--声明由哪个拦截器拦截-->
<bean class="com.wm.handle.MyInterceptor"/>
</mvn:interceptor>
</mvc:interceptors>
多个拦截器
以配置文件声明为顺序,最先拦截的最后出拦截,如下图所示
上一篇: Webpack 插件分析