1.概述
M model 模型层 DAO封装 >>> Mybatis
V view 视图层 html css js jsp
C controller 控制层 Servlet封装 >>> springMVC
SpringMVC是spring为展现层提供的基于MVC设计理念的优秀WEB框架,是目前最主流的MVC框架之一
SpringMVC通过一套注解,可以让普通的JAVA类成为contrllor控制器,无需继承Servlet,实现了控制层和Servlet之间的解耦
SpringMVC支持Rest风格的URL写法
SpringMVC采用了松耦合,可热插的主键结构,比其他的框架更具扩展性和灵活性
2.执行流程
①DispatcherServlet:前端控制器
用户请求到达前端控制器,它就相当于 mvc 模式中的 c,dispatcherServlet 是整个流程控制的中心,由 它调用其它组件处理用户的请求,dispatcherServlet 的存在降低了组件之间的耦合性。
② HandlerMapping:处理器映射器
HandlerMapping 负责根据用户请求找到 Handler 即处理器,SpringMVC 提供了不同的映射器实现不同的 映射方式,例如:配置文件方式,实现接口方式,注解方式等。
③ Handler:处理器 (自己定义的Controller处理单元)
它就是我们开发中要编写的具体业务控制器。由 DispatcherServlet 把用户请求转发到 Handler。由 Handler 对具体的用户请求进行处理。
④ HandlAdapter:处理器适配器
通过 HandlerAdapter 对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行
⑤ View Resolver:视图解析器
View Resolver 负责将处理结果生成 View 视图,View Resolver 首先根据逻辑视图名解析成物理视图名 即具体的页面地址,再生成 View 视图对象,最后对 View 进行渲染将处理结果通过页面展示给用户。
⑥ View:视图
SpringMVC 框架提供了很多的 View 视图类型的支持,包括:jstlView、freemarkerView、pdfView等。我们最常用的视图就是 jsp。 一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开 发具体的页面。
⑦ mvc:annotation-driven说明
在 SpringMVC 的各个组件中,处理器映射器、处理器适配器、视图解析器称为 SpringMVC 的三大组件。
使 用 mvc:annotation-driven 自动加载 RequestMappingHandlerMapping (处理映射器) 和 RequestMappingHandlerAdapter ( 处 理 适 配 器 ) , 可 用 在 SpringMVC.xml 配 置 文 件 中 使 用 mvc:annotation-driven替代注解处理器和适配器的配置。
补充:
HandlerMapping的实现类的作用
实现类RequestMappingHandlerMapping,它会处理@RequestMapping 注解,并将其注册到请求映射表中。
HandlerAdapter的实现类的作用
实现类RequestMappingHandlerAdapter,则是处理请求的适配器,确定调用哪个类的哪个方法,并且构造方法参数,返回值。
当配置了mvc:annotation-driven/后,Spring就知道了我们启用注解驱动。然后Spring通过context:component-scan/标签的配置,会自动为我们将扫描到的@Component,@Controller,@Service,@Repository等注解标记的组件注册到工厂中,来处理我们的请求,这个时候接收返回json数据、参数验证、统一异常等功能。
<?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:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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/util
http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
">
<!--配置spring包扫描-->
<context:component-scan base-package="com.msb"></context:component-scan>
<!--配置处理器映射器-->
<!-- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"></bean>-->
<!--配置处理器适配器-->
<!-- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"></bean>-->
<!--一个注解替换上面的两个配置-->
<!--<mvc:annotation-driven>会自动注册RequestMappingHandlerMapping与RequestMappingHandlerAdapter两个Bean-->
<mvc:annotation-driven/>
<!--配置视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/" ></property>
<property name="suffix" value=".jsp" ></property>
</bean>
<!--静态资源放行-->
<!--<mvc:resources mapping="/js/**" location="/js/"></mvc:resources>
<mvc:resources mapping="/img/**" location="/img/"></mvc:resources>
<mvc:resources mapping="/css/**" location="/css/"></mvc:resources>-->
<mvc:resources mapping="/static/**" location="/static/"></mvc:resources>
</beans>
3.SpringMVC___RequestMapping注解
3.1
@RequestMapping控制请求方式
method属性可以控制请求的方式,值为RequestMethod的枚举值
@RequestMapping( value = "/***" ,method = RequestMethod.GET)
3.2
@RequestMapping控制请求参数params和请求头headers
param:表示请求中必须包含名为param的参数
!param:表示请求中不能包含名为param的参数
param = value 表示请求中包含名为param的参数,但是值必须是value
param != value 表示请求中包含名为param的参数,但是值不能是value
{“param1”,“param2=value”},可以将对于多个参数的要求写入数组
@RequestMapping( value = "/***" ,params = {"username!=root","password"})
@RequestMapping( value = "/***",headers = {"Accept-Encoding=gzip, deflate"})
4.常用注解
4.1**@RequestMapping**
作用**:用于建立URL和处理请求方法之间的对应关系
出现位置:**
类上:请求URL的第一季访问目录(此处不写的话,就相当于应用的根目录。写的话需要以/开通)
方法上:请求URL的第二级访问目录
属性**:**
value:用于指定请求的 URL。它和 path 属性的作用是一样的。
method:用于指定请求的方式。
params(了解):用于指定限制请求参数的条件。它支持简单的表达式。要求请求参数的 key 和 value 必须和 配置的一模一样。
headers(了解):用于指定限制请求消息头的条件。
4.2**@RequestParam**
作用**:**
把请求中指定名称的参数给控制器中的形参赋值
属性:
value:请求参数中的名称。
required:请求参数中是否必须提供此参数。默认值:true。表示必须提供,如果不提供将报错。
@RequestMapping("/getRequestParam")
public String getRequestParam(@RequestParam("name")String uname, @RequestParam(value="age",required=false)Integer age){
System.out.println(username+","+age);
return "success";
}
4.3@PathVariable
作用**:**
用于绑定 url 中的占位符。例如:请求 url 中 /delete/{id},这个{id}就是 url 占位符。 url 支持占位符是 spring3.0 之后加入的。是 springmvc 支持 rest 风格 URL 的一个重要标志。
属性**:**
value:用于指定 url 中占位符名称。
required:是否必须提供占位符。
@Controller
public class PathController {
@RequestMapping("/testPathVariable/{id}/{username}")
public String testPathVariable(@PathVariable("id") Integer id, @PathVariable("username") String username){
System.out.println("id:"+id);
System.out.println("username:"+username);
System.out.println("testPathVariable1");
return "success";
}
}
4.4@RequestHeader
作用:
用于获取请求消息头。
属性:
value:提供消息头名称
required:是否必须有此消息头
@RequestMapping("/getRequestHeader")
public String getRequestHeader(@RequestHeader(value="Accept", required=false)String requestHeader){
System.out.println(requestHeader);
return "success";
}
4.5、@CookieValue
作用:
用于把指定 cookie 名称的值传入控制器方法参数。
属性:
value:指定 cookie 的名称。
required:是否必须有此 cookie
@RequestMapping("/getCookie")
public String getCookie(@CookieValue(value="JSESSIONID",required=false) String cookieValue){
System.out.println(cookieValue);
return "success";
}
5.响应处理
①0单元返回值为 void
在SpringMVC中如果对于当前的控制单元,没有写对应的返回值,这个时候SpringMVC就会找和自己控制单元名称一致的页面展示,如果没有配置视图解析器的前缀和后缀是没有产生404,需要注意控制单元仍然可以进。
@RequestMapping("/testReturnVoid")
public void testReturnVoid() throws Exception {
System.out.println("AccountController 的 testForward 方法执行了。。。。");
}
②.转发和重定向ServletAPI实现
单元方法的返回值类型设置void。因为使用response对象在单元方法中直接对此次请求进行了响应,不再通过DispatcherServlet了,既然已经响应了,就不需要再给DispatcherServlet返回值了。在单元方法上声明HttpServletResponse形参,来接收此次请求的response对象。
@RequestMapping("demo1")
public void testDemo1(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 请求转发
//request.getRequestDispatcher("/forward.jsp").forward(request,response);
// 响应重定向
response.sendRedirect(request.getContextPath()+"/redirect.jsp");
}
③使用forward关键字完成响应
使用通过单元方法的返回值来告诉DispatcherServlet请求转发指定的资源,如果是请求转发,forward关键字可以省略不写的
/*
* 返回字符串告诉DispatcherServlet跳转的路径
* 在路径之前放上一个forward: 关键字,就是请求转发
* 如果路径前的关键字是forward,那么可以省略不写
* */
@RequestMapping("demo2")
public String testDemo2() throws Exception {
//return "forward:/forwardPage.jsp";
return "/forwardPage.jsp";
}
④使用redirect关键字完成响应
使用通过单元方法的返回值来告诉DispatcherServlet重定向指定的资源,注意这个redirect关键字不可以省去
/*
* 返回字符串告诉DispatcherServlet跳转的路径
* 在路径之前放上一个redirect: 关键字,就是重定向
* 如果路径前的关键字是redirect,那么不可以省略
* /表示当前项目下.这里不需要项目的上下文路径
* */
@RequestMapping("demo3")
public String testDemo3() throws Exception {
return "redirect:/redirectPage.jsp";
}
⑤使用View视图转发和重定向
RedirectView中所做的操作,最终的实现是在renderMergedOutputModel中完成实现的,简单来说RedirectView实现了链接的重定向,并且将数据保存到FlashMap中,这样在跳转后的链接中可以获取一些数据.
@RequestMapping("demo4")
public View testDemo4(HttpServletRequest req) {
View view =null;
// 请求转发
//view =new InternalResourceView("/forwardPage.jsp");
// 重定向
view=new RedirectView(req.getContextPath()+"/redirectPage.jsp");
return view;
}
⑥使用ModelAndView转发重定向
ModelAndView中的Model代表模型,View代表视图,这个名字就很好地解释了该类的作用。业务处理器调用模型层处理完用户请求后,把结果数据存储在该类的model属性中,把要返回的视图信息存储在该类的view属性中,然后让该ModelAndView返回该Spring MVC框架。
@RequestMapping("demo5")
public ModelAndView testDemo5(HttpServletRequest req) {
ModelAndView mv=new ModelAndView();
// 请求转发
//mv.setViewName("forward:/forwardPage.jsp");
//mv.setView(new InternalResourceView("/forwardPage.jsp"));
// 重定向
//mv.setViewName("redirect:/redirectPage.jsp");
mv.setView(new RedirectView(req.getContextPath()+"/redirectPage.jsp"));
return mv;
}
⑦ResponseBody 响应 json 数据
既然我们希望使用单元方法的返回值来响应ajax请求的处理结果,而目前DispatcherServlet的底层会将单元方法的返回值按照请求转发或者重定向来处理,所以就需要我们告诉DispatcherServlet,单元方法的返回值不要按照请求转发或者重定向处理,而是按照直接响应处理,将单元方法的返回值直接响应给浏览器。
声明单元方法处理ajax请求,并在单元方法上新增注解@ResponseBody
/*
* @ResponseBody
* 1方法的返回值不在作为界面跳转依据,而已直接作为返回的数据
* 2将方法的返回的数据自动使用ObjectMapper转换为JSON
*/
@ResponseBody
@RequestMapping("testAjax")
public Pet testAjax(Person p) throws JsonProcessingException {
System.out.println(p);
Pet pet =new Pet("Tom","cat");
return pet;
}
补充:
关于 @RestController
相当于@Controller+@ResponseBody两个注解的结合,返回json数据不需要在方法前面加@ResponseBody注解了,但使用@RestController这个注解,就不能返回jsp,html页面,视图解析器无法解析jsp,html页面
@RestController
public class AjaxController {
/*
* @ResponseBody
* 1方法的返回值不在作为界面跳转依据,而已直接作为返回的数据
* 2将方法的返回的数据自动使用ObjectMapper转换为JSON
*/
@RequestMapping("testAjax")
public Pet testAjax(Person p) throws JsonProcessingException {
System.out.println(p);
Pet pet =new Pet("Tom","cat");
return pet;
}
}
6.作用域
PageContext对象
作用域范围:当前jsp页面内有效
request对象
作用域范围:一次请求内。
作用: 解决了一次请求内的资源的数据共享问题
session对象
作用域范围:一次会话内有效。
说明:浏览器不关闭,并且后台的session不失效,在任意请求中都可以获取到同一个session对象。
作用:解决了一个用户不同请求的数据共享问题。
application(ServletContext)对象
作用域范围:整个项目内有效。
特点:一个项目只有一个,在服务器启动的时候即完成初始化创建无论如何获取都是同一个项目。
作用:解决了不同用户的数据共享问题
7.拦截器
过滤器的作用是保护请求的服务器资源,在请求资源被执行之前,如果请求地址符合拦截范围,则会先执行过滤器。过滤器的执行时机,是在Servlet之前执行的。但是在使用了SpringMVC后,Servlet只有一个了,也就是DisptcherServlet。那么,如果我们仍然使用过滤器来完成请求的拦截,因为过滤器是在Servlet之前执行的,就会造成,过滤器会拦截DispatcherServlet所有的请求。那么,如果我们有部分请求不想被拦截,怎么办?
7.1拦截器的使用
Spring MVC中的拦截器(Interceptor)类似于Servlet中的过滤器(Filter),它主要用于拦截用户请求并作相应的处理。例如通过拦截器可以进行权限验证、记录请求信息的日志、判断用户是否登录等。
要使用Spring MVC中的拦截器,就需要对拦截器类进行定义和配置。通常拦截器类可以通过两种方式来定义。
1.通过实现HandlerInterceptor接口,或继承HandlerInterceptor接口的实现类(如HandlerInterceptorAdapter)来定义。
2.通过实现WebRequestInterceptor接口,或继承WebRequestInterceptor接口的实现类来定义。
7.2拦截器和过滤器的区别
①拦截器SpringMVC的,而过滤器是servlet的。
②拦截器不依赖与servlet容器,由spring容器初始化,过滤器依赖与servlet容器,由servlet容器初始化。
③拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
④拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。
⑤在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。
⑥拦截器可以获取IOC容器中的各个bean,而过滤器就不太方便,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。
7.3实现
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
/*在请求到达我们定义的handler之前工作的*/
System.out.println("MyInterceptor preHandle");
/*返回的是true,代表放行,可以继续到达handler*/
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("MyInterceptor postHandle");
/*handler 处理单元返回ModelAndView 时候进行 拦截*/
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
/*
页面渲染完毕,但是还没有给浏览器响应数据的时候
*/
System.out.println("MyInterceptor afterCompletion");
}
}
springmvc.xml中注册拦截器
<!--注册拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/login.action"/>
<bean id="myInterceptor" class="com.msb.interceptor.MyInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
详解:
7.3.1、preHandle方法
执行时机
再进入控制单元方法之前执行
如何调用
按拦截器定义顺序调用
具体作用
如果程序员决定该拦截器对请求进行拦截处理后还要调用其他的拦截器,或者是业务处理器去 进行处理,则返回 true。 如果程序员决定不需要再调用其他的组件去处理请求,则返回 false。
参数详解
HttpServletRequest arg0,拦截的请求的request对象
HttpServletResponse arg1, 拦截的请求的response对象
Object arg2 封存了单元方法对象的HandleMethod对象
/**
*
* @param request 请求对象
* @param response 响应对象
* @param handler 目标要调用的Handler
* @return 返回true放行,返回false拦截
* @throws Exception
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
/*在请求到达我们定义的handler之前工作的*/
System.out.println("MyInterceptor preHandle");
/*设置请求和响应的乱码 */
/* request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");*/
// 判断是否登录
/*User user =(User) request.getSession().getAttribute("user");
if(null == user)
response.sendRedirect("index.jsp");
return false;*/
// 用户权限控制
return true;
}
7.3.2postHandle方法
执行时机
在进行数据处理和做出响应之间进行这个方法的调用
如何调用
在拦截器链内所有拦截器返成功调用
具体作用
在业务处理器处理完请求后,但是 DispatcherServlet 向客户端返回响应前被调用,
在该方法中对用户请求 request域数据进行处理。
参数详解
HttpServletRequest arg0, 拦截的请求的request对象
HttpServletResponse arg1, 拦截的请求的response对象
Object arg2, 封存了单元方法对象的HandleMethod对象
ModelAndView arg3 封存了单元方法的返回值资源路径和请求转到的Map数据
/**
*
* @param request
* @param response
* @param handler
* @param modelAndView controller响应的结果,视图和数据
* @throws Exception
*/
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("MyInterceptor postHandle");
/*控制数据*/
/*Map<String, Object> map = modelAndView.getModel();
String msg = (String)map.get("msg");
String newMsg = msg.replaceAll("脏话", "**");
map.put("msg", newMsg);*/
/*控制视图*/
/*modelAndView.setViewName("/testDemo1.jsp");*/
}
7.3.3、afterCompletion方法
执行时机
在进行页面渲染的时候执行
如何调用
按拦截器定义逆序调用
具体作用
在DispatcherServlet 完全处理完请求后被调用,可以在该方法中进行一些资源清理的操作。
参数详解
HttpServletRequest arg0, 拦截的请求的request对象
HttpServletResponsearg1, 拦截的请求的response对象
Object arg2, 封存了单元方法对象的HandleMethod对象
Exception arg3 存储了责任链的异常信息
/**
* 无论controller是否出现异常,都会执行的方法
* 一般来说都做一些资源释放工作
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
/*页面渲染完毕,但是还没有给浏览器响应数据的时候*/
System.out.println("MyInterceptor afterCompletion");
System.out.println(ex);
}
多个拦截器执行顺序
多个拦截器同时存在时,执行的顺序由配置顺序决定. 先配置谁, 谁就先执行.多个拦截器可以理解为拦截器栈, 先进后出(后进先出), 如图所示:
<!--注册拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/login.action"/>
<bean id="myInterceptor1" class="com.msb.interceptor.MyInterceptor"></bean>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/login.action"/>
<bean id="myInterceptor2" class="com.msb.interceptor.MyInterceptor2"></bean>
</mvc:interceptor>
</mvc:interceptors>
MyInterceptor preHandle
MyInterceptor2 preHandle
login.action
MyInterceptor2 postHandle
MyInterceptor postHandle
success.jsp
MyInterceptor2 afterCompletion
MyInterceptor afterCompletion