Springmvc核心技术
请求转发和重定向
请求转发代码示例:
@Controller
public class MyController {
/*
* 逐个接收参数:
* 要求:控制器方法的形参名和请求中参数名必须一致
* 同名的请求参数赋值给同名的形参
* */
@RequestMapping(value = "/doForward.do")
public ModelAndView doSome(String name, Integer age){ //doGet方法
/*
* 处理器方法返回ModelAndView,实现转发forward
* 语法:setViewName("forward:视图完整路径")
* forward不和视图解析器一同使用,当作项目中没有视图解析器
* */
ModelAndView mv = new ModelAndView();
//添加数据
//框架最后将数据放到request作用域
mv.addObject("myname", name);
mv.addObject("myage", age);
//使用forward操作,显示转发,用在转发到非视图解析器规定的页面
mv.setViewName("forward:/WEB-INF/view/show.jsp");
//最后返回mv
return mv;
}
}
重定向代码示例:
@Controller
public class MyController {
@RequestMapping(value = "/doRedirect.do")
public ModelAndView doSome(String name, Integer age){ //doGet方法
/*
* 处理器方法返回ModelAndView,实现重定向Redirect
* 语法:setViewName("Redirect:视图完整路径")
* Redirect不和视图解析器一同使用,当作项目中没有视图解析器
*
* 框架对重定向的操作:
* 1.框架会把Model中的简单类型的数据,转为String使用,作为hello.jsp的get请求参数使用
* 目的是在doRedirect.do请求和hello.jsp请求之间传递数据
* 2.在目标hello.jsp页面可以使用参数集合对象${param.参数}获取请求参数值
* 例如:${param.myname}
* 3.redirect不能访问受保护的/WEB/INF下的资源,/WEB/INF下的资源不能从外部直接访问
* */
ModelAndView mv = new ModelAndView();
//添加数据
//在重定向中,框架会把参数加入到重定向的url地址中,但是request域中是没有数据的,所以需要使用${param.myname}获取参数数据
mv.addObject("myname", name);
mv.addObject("myage", age);
//使用Redirect操作,显示转发,用在转发到非视图解析器规定的页面
mv.setViewName("redirect:/hello.jsp");
//最后返回mv
return mv;
}
}
异常处理
框架采用统一全局的异常处理方案,基于AOP的思想,把Controller中的异常统一集中到一个地方,集中进行处理。将业务逻辑和异常处理分开。也就是解耦合。
使用两个注解:
1.@ExceptionHandler
2.@ControllerAdvice
异常的集中处理:
1.定义一个自定义异常类(MyUserException):
package com.exception;
public class MyUserException extends Exception{
public MyUserException() {
super();
}
public MyUserException(String message) {
super(message);
}
}
2.定义上面异常类的子类(AgeException, NameException):
package com.exception;
//表示当用户的姓名有异常,抛出AgeException
public class AgeException extends MyUserException{
public AgeException() {
super();
}
public AgeException(String message) {
super(message);
}
}
package com.exception;
//表示当用户的姓名有异常,抛出NameException
public class NameException extends MyUserException{
public NameException() {
super();
}
public NameException(String message) {
super(message);
}
}
3.创建一个全局异常处理类(GlobalExceptionHandler):
package com.handler;
import com.exception.AgeException;
import com.exception.NameException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
/*
* @ControllerAdvice: 控制器增强,也就是给控制器增加异常处理功能的
* 位置:在类的上面
* 特点:需要让框架知道这个注解所在的包名,需要在springmvc配置文件中声明组件扫描器。
* 指定@ControllerAdvice所在的包名
* */
@ControllerAdvice
public class GlobalExceptionHandler {
//定义方法,处理发生的异常
/*
* 处理异常的方法和控制器定义的方法一样,可以有多个参数,返回值也可以是ModelAndView,
* String,void对象类型的返回值
*
* 形参Exception,表示Controller对象中抛出的异常对象
* 通过这个形参可以获取发生的异常的详细信息
*
* 还需要加@ExceptionHandler ,里面有一个value属性,表示异常的类型,当发生此
* 异常时由当前的方法处理
* */
@ExceptionHandler(value = NameException.class)
public ModelAndView doNameException(Exception exception){
//处理NameException的异常
/*
* 异常发生处理的逻辑:
* 1.需要把异常记录下来,记录到数据库,日志文件。
* 记录异常发生的时间,哪个方法发生的,异常的错误内容。
* 2.发送通知,把异常消息通过邮件等消息发送给相关人员
* 3.给用户友好的提示
* */
ModelAndView mv = new ModelAndView();
mv.addObject("msg", "你的姓名必须是zs,其他用户不能访问");
mv.addObject("ex", exception);
mv.setViewName("nameError");
return mv;
}
@ExceptionHandler(value = AgeException.class)
public ModelAndView doAgeException(Exception exception){
//处理AgeException的异常
/*
* 异常发生处理的逻辑:
* 1.需要把异常记录下来,记录到数据库,日志文件。
* 记录异常发生的时间,哪个方法发生的,异常的错误内容。
* 2.发送通知,把异常消息通过邮件等消息发送给相关人员
* 3.给用户友好的提示
* */
ModelAndView mv = new ModelAndView();
mv.addObject("msg", "您的年龄不能大于80");
mv.addObject("ex", exception);
mv.setViewName("ageError");
return mv;
}
//处理除NameException,AgeException以外的不知类型的异常
@ExceptionHandler
public ModelAndView doOtherException(Exception exception){
//处理其他异常
ModelAndView mv = new ModelAndView();
mv.addObject("msg", "您的年龄不能大于80");
mv.addObject("ex", exception);
mv.setViewName("defaultError");
return mv;
}
}
4.创建异常接收页面(nameError.jsp):
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<p>nameError.jsp</p><br/>
<P>接收到的错误信息:${msg}</P><br/>
<p>系统异常消息:${ex.message}</p>
</body>
</html>
拦截器
拦截器的示例代码:
1.创建拦截器类:
package com.handler;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
public class MyInterceptor implements HandlerInterceptor {
private long btime = 0;
/*
* preHandle叫做预处理方法
* 参数:
* Object handler: 被拦截的控制器对象
* 返回值boolean:
* true:请求是通过了拦截器的验证,可以执行控制器的方法。
* false:请求的没有通过拦截器的验证,请求到达拦截器就停止了。
*
* 特点:
* 1.方法在控制器方法执行前先执行的,用户的请求首先到达此方法
* 2.在这个方法中,可以获取请求的信息,验证请求是否符合要求。
* 可以验证用户是否登录,验证用户是否具有权限访问某个资源。
* 验证失败,可以截断请求,请求不能被处理。
* 验证成功,可以放行请求,此时控制器请求才能被执行。
* */
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
btime = System.currentTimeMillis();
System.out.println("这是拦截器的preHandle方法");
return true;//如果返回假,请求就结束了,可以设计一个提示页面,作为用户交互
}
/*
* postHandle:后处理方法
* 参数:
* Object handler:被拦截的处理器对象
* ModelAndView modelAndView: 处理器方法的返回值
*
* 特点:
* 1.在处理器方法执行后执行的。
* 2.能够获取到处理器方法的返回值ModelAndView,可以对ModelAndView
* 中的数据和视图,可以影响到最后的执行结果。
* 3.主要是对原来的执行结果进行二次修正。
* */
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("这是拦截器的postHandle方法");
//对原来doSome的执行结果进行修改
if(modelAndView != null){
modelAndView.addObject("mydate", new Date());
modelAndView.setViewName("other");
}
}
/*
* afterCompletion:最后执行的方法
* 参数:
* Object handler:被拦截的处理器对象
* Exception ex:程序中发生的异常
* 特点:
* 1.请求处理完成后执行的,对视图执行forward了,才执行该方法。
* 2.一般用作资源回收的工作。
* */
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
long etime = System.currentTimeMillis();
System.out.println("计算从prehandle到请求处理结束的时间: " + (etime - btime));
}
}
2.配置springmvc配置文件,声明拦截器
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--声明组件扫描器,扫描Controller注解-->
<context:component-scan base-package="com.controller"/>
<!-- 声明springmvc框架中的视图解析器,帮助开发人员设置视图文件的路径-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--有两个属性,一个是前缀,另外一个是后缀-->
<!--前缀:视图文件的路径,前面的‘/’代表根,后面的‘/’代表路径-->
<property name="prefix" value="/WEB-INF/view/"/>
<!--后缀:表示视图文件的扩展名-->
<property name="suffix" value=".jsp"/>
</bean>
<!--声明拦截器,拦截器可以有多个-->
<mvc:interceptors>
<!--声明第一个拦截器-->
<mvc:interceptor>
<!--指定拦截的请求地址
path: 就是uri地址,可以使用通配符 **
**: 表示任意的字符,文件或者多级目录和目录中的文件-->
<mvc:mapping path="/user/**"/>
<!--声明拦截器对象-->
<bean class="com.handler.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
</beans>
多个拦截器的执行顺序
执行的顺序是按照声明的顺序执行的。
拦截器和过滤器的区别:
使用拦截器,实现的用户登录验证的例子:
springmvc执行的流程