SSM整合
有两个容器:
1、spring容器,负责写service,dao,工具类对象的
2、springmvc容器,负责写controller
spring和springmvc两个容器是有关系的,已经确定好的关系
springmvc是spring的子容器,类似于java中的继承关系,子容器可以访问父容器的内容
也就是子容器中的controller可以访问父容器中的service
基本步骤
- 建立数据库
- 新建maven web项目
- 加入依赖
- springmvc, spring, mybatis, Jackson, MySQL驱动, Druid连接池,servlet
- 写web.xml
- 注册DispatcherServlet
- 目的是创建springmvc容器对象
- 注册ContextLoaderListener
- 目的是创建spring容器对象
- 注册DispatcherServlet
- 创建package: controller, service, dao, 实体类
- 写配置文件
- springmvc
- spring
- mybatis
- 数据库属性
- 写代码:dao,mapper,service和实现类,controller, 实体类
具体实现
添加依赖
有springmvc, spring, jackson, servlet-api, mysql-connector-java, mybatis, mybatis-spring, druid
创建容器
在web.xml中添加DispathcerServlet类,这是springmvc容器
在web.xml中添加<Listener>ContextLoaderListener<Listener/>
来创建spring容器
在web.xml中添加<context-param>
,指定spring配置文件的位置
配置文件
springmvc的容器配置文件
<!-- 指定controller类的所在位置-->
<context:component-scan base-package="controller"/>
<!-- 启用注解-->
<mvc:annotation-driven/>
<!-- 设置静态文件位置和访问方法-->
<mvc:resources mapping="static/**" location="/static/"/>
spring的容器配置文件
创建DataSource
,使用Druid
创建SqlSessionFactory
,使用以上的DataSource
,配置我们放到另一个文件夹mybatis.xml
创建MapperScannerConfigurer
,指定mapper
所在位置
指定service
类的位置,使用component-scan
配置mybatis
可以添加log配置
指定mappers文件位置?(我搞不懂了,不是在spring里面配置过了吗),哦吼果然不需要,这两个有什么区别呢我也不知道,下次再说
写各种类了
写schema
,dao
,service
,controller
重定向和转发(redirect, forward)
用法
modelAndView.setViewName("redirect:/add");
modelAndView.setViewName("forward:/add");
其中,redirect
不能将参数带过去,或者说参数会在modelAndView.addObject("student", student);
后,在URL中直接以?student=xxxx
传过去,也就是说被重定向的URL得到的参数可能跟直接请求该URL所得到的参数形式不一样
还有redirect
不能访问WEB-INF
里面的数据,因为redirect
本质是由客户端再次发送一次请求,客户端不能访问WEB-INF
异常处理
就两个注解
@ControllerAdvice
添加在类上
@ExceptionHandler
添加在异常处理方法上
很明显,这就是aop,其中@ControllerAdvice
表明这个类是以Advice围绕着所有的Controller,
而@ExceptionHandler
就是专门用来处理异常的方法
ExceptionHandler
使用方法
ExceptionHandler(MyException.class)
如果不加参数,表示其他类型的错误,也就是没有被其他的ExceptionHandler
捕捉到的
作用
一般是打印日志,方便日后修改的时候查看问题
拦截器Interceptor
类似于过滤器,主要是用来拦截请求的,可以处理返回的结果
用法:
实现这个HandlerInterceptor
接口,有一下三个方法:
preHandle
postHandle
afterCompletion
这三个方法都是默认方法,可以不重写
public class MyIntercept implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 在controller之前执行,如果返回为true则放行
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
// 这个Object handler是被处理的controller对象
// 这个ModelAndView modelAndView是controller的返回值,在拦截器中我们可以对此修改
//
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// 如果preHandle方法返回值为true,那么这段就会在方法完成后执行,否则不执行
// 一般用来进行资源回收的
}
}
实现好拦截器方法后在springmvc的配置文件中注册该拦截器:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="login/**"/>
<mvc:mapping path="admin/**"/>
<bean class="intercept.MyIntercept"/>
</mvc:interceptor>
</mvc:interceptors>
也可以设置多个拦截器:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="intercept.MyIntercept"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="intercept.MyIntercept2"/>
</mvc:interceptor>
</mvc:interceptors>
拦截器的调用顺序按照以上的声明顺序
如果拦截器1通过,拦截器2拦截,那么1的preHandle和afterCompletion都会执行,2只执行preHandle
如果都通过,那么afterCompletion方法来说,1在2后面
过滤器和拦截器的区别
- 过滤器是servlet中的对象,是Tomcat的;拦截器是springmvc框架的对象
- 过滤器实现filter接口; 拦截器实现HandlerInterception
- 过滤器用来设置,修改request,response,侧重于对数据过滤;拦截器用来验证请求,用来拦截的
- 过滤器先执行;拦截器后执行
- 过滤器有一个执行时间;拦截器有三个
- 过滤器可以处理静态文件;拦截器只能处理对controller的请求,如果请求不能被DispatcherServlet接收,就不会被拦截器处理
springmvc的执行流程
- 用户发送请求
DispatcherServlet
接收请求,转交给HandlerMapping
HandleMapping
找到Handler
,并将其封装为HandlerExecutionChain
后转交给DispatcherServletDispatcherServlet
根据HandlerExecutionChain
找到HandlerAdaptor
HandlerAdaptor
调用Controller
Controller
执行并且将ModelAndView
返回给HandlerAdaptor
HandlerAdaptor
将ModelAndView
返回给DispatcherServlet
DispatcherServlet
调用ViewResolver
ViewResolver
将View
封装为对象返回给DispatcherServlet
DispatcherServlet
调用View对象让其渲染,形成响应对象DispatcherServlet
将响应对象返回给用户
为什么这么麻烦呢
因为这些涉及到了很多个对象,而这些对象都没有直接联系,都是经过DispatcherServlet来进行联系的,这样子当修改其中一个对象的时候,其他的几个对象不用也一起修改,起到了解耦合的作用