SpringMVC的拦截器
拦截用户的请求,拦截时间在处理器映射器映射出要执行的处理器类,并且找到对应的处理器适配器,在适配器执行处理器之前拦截;
拦截器会和处理器绑定在一起,作为一个处理器执行链,返回给中央调度器
1.自定义拦截器需要实现HandlerInterceptor接口,重写其中3个方法:
preHandle方法在处理器执行前调用
有一个boolean类型返回值,返回false时会拦截跳转处理器的请求执行到此处就不会向下执行
postHandle方法在处理器执行后调用
afterCompletion在中央调度器将数据返回浏览器之前的最后时刻调用
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String attribute =(String) request.getSession().getAttribute("user");
if("beijing".equals(attribute)) {
return true ;
}
request.getRequestDispatcher("/fail.jsp").forward(request, response);
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("postHandle---------");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("afterCompletion---------");
}
}
2.在springmvc中注册拦截器
当任意请求到达处理器前后都会经过这个拦截器的方法
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.handlers.MyInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
3.调用处理器方法测试
@Controller
@RequestMapping("/test")
public class MyController {
@RequestMapping("/register.do")
@ResponseBody
public Object fun() {
System.out.println("执行处理器方法");
return 123.456;
}
}
多个拦截器
多个拦截器的注册
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.handlers.OneInterceptor"></bean>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.handlers.TwoInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
多个拦截器的执行顺序
OneInterceptor处理器执行之前拦截器的preHandle---------
TwoInterceptor处理器执行之前拦截器的preHandle---------
执行处理器方法
TwoInterceptor处理器执行之后拦截器的postHandle---------
OneInterceptor处理器执行之后拦截器的postHandle---------
TwoInterceptor拦截器的afterCompletion---------
OneInterceptor拦截器的afterCompletion---------
如果OneInterceptor的preHandle方法返回false,则后面都不会执行
拦截器的afterCompletion与preHandle方法
preHandle方法执行后(即返回值为true),那afterCompletion就一定会执行,无论后续的拦截器是否放行请求
preHandle方法未执行或者返回值为false,那afterCompletion都不会执行
权限拦截
只有登录的用户的请求才能进入处理器进行业务处理,在拦截器的方法中设置权限拦截
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String requestURI = request.getRequestURI();
if(!requestURI.contains("/login")){
String username = (String) request.getSession().getAttribute("USER_SESSION");
if(null == username){
response.sendRedirect(request.getContextPath() + "/login.do");
return false;
}
}
return true;
}
在处理器对于登录成功用户将登录信息放入session中
@RequestMapping(value = "/login.do",method = RequestMethod.GET)
public String login(){
return "login";
}
@RequestMapping(value = "/login.do",method = RequestMethod.POST)
public String login(String username
,HttpSession httpSession){
httpSession.setAttribute("USER_SESSION", username);
return "redirect:welcome";
}
SpringMVC执行流程
浏览器发出请求达到中央调度器,中央调度器首先判断是否是multipart请求(处理文件上传的请求)
无论是否都会交给处理器映射器(找到对应的处理器,和拦截器一起封装为一个处理器执行链)
如何找到对应的处理器?就是将所有的处理器映射器放入一个集合,然后遍历
根据请求找到对应处理器映射器,再找到处理器,将处理器和拦截器封装为处理器执行链.
将处理器执行链返回中央调度器,中央调度器根据处理器找到对应的处理器适配器
将所有的处理器适配放入一个集合在遍历,与处理器匹配,找到对应的处理器适配器
再拿处理器适配器去调用处理器(处理器执行前会调用拦截器的preHandle方法)
处理器返回ModelAndView(处理器执行前会调用拦截器的postHandle方法)
适配器直接将这个ModelAndView返回给中央调度器,中央调度器拿到ModelAndView将之给了视图解析器
视图解析器将之渲染(调用View对象的render方法,传入数据,View对象自己完成渲染,将这个对象封装为response对象响应给浏览器)
之后调用拦截器的afterCompletion方法
视图解析器:将ModelAndView的数据解析,将逻辑视图转换为物理视图,将物理视图返回给中央调度器,此时物理视图已经是一个View对象
中央调度器再调用View对象(实质是一个模板),将数据填充到View中,形成一个真正的View对象,
将这个对象封装为response响应给浏览器,渲染就是将数据进行填充
Spring+SpringMVC+Mybatis整合
使用SSM整合完成简单的用户注册
一,配置式开发:
1.导入相关jar包
2.配置web.xml
a.Spring配置文件的位置
b.ServletContext的监听器
c.SpringMVC的字符编码过滤器
d.SpringMVC的中央调度器
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:resources/spring-*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
3.form表单提交数据
<form action="${pageContext.request.contextPath}/test/register.do" method="POST">
姓名:<input type="text" name="name"/>
年龄:<input type="text" name="age"/>
<input type="submit" value="注册"/>
</form>
4.处理器
配置式需要实现Controller接口,在处理器中调用Service
public class StudentController implements Controller {
private IStudentService service;
public void setService(IStudentService service) {
this.service = service;
}
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
String name = request.getParameter("name");
Integer age = Integer.valueOf(request.getParameter("age"));
Student student = new Student(name,age);
service.addStudent(student);
return null;
}
}
其中处理器的注册和service属性的注入需要在SpringMVC中配置
<bean id="/test/register.do" class="com.handles.StudentController">
<property name="service" ref="studentService"></property>
</bean>
5.创建servlce及其实现类
public class StudentServiceImpl implements IStudentService {
private IStudentDao dao;
public void setDao(IStudentDao dao) {
this.dao = dao;
}
@Override
public void addStudent(Student student) {
dao.insertStudent(student);
}
}
service实体类的注册和dao属性的注入
spring-service.xml
<bean id="studentService" class="com.service.IStudentServiceImpl">
<property name="dao" ref="IStudentDao"></property>
</bean>
6.在dao层创建接口操作数据库,需要对应的xml文件
public interface IStudentDao {
void insertStudent(Student student);
}
<mapper namespace="com.dao.IStudentDao">
<insert id="insertStudent" >
insert into student (name,age) values(#{name},#{age})
</insert>
</mapper>
在mybatis.xml中注册接口文件位置
<mappers>
<package name="com.dao" />
</mappers>
spring-mybatis.xml中配置sqlSessionFactory
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="configLocation" value="classpath:resources/mybatis.xml"></property>
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
<property name="basePackage" value="com.dao"></property>
</bean>
操作数据库还需要事务管理的配置文件spring-tx.xml
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="add*" isolation="DEFAULT" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut expression="execution(* *..service.*.*(..))"
id="studentPointcut" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="studentPointcut"/>
</aop:config>
整合无法运行原因分析:
1.spring的jar包版本号不一致导致版本冲突
2.辅助jar包过低无法匹配Spring的jar包
3.c3p0-0.9.1.2.jar数据源的版本太低
注意c3p0-0.9.5.2.jar需要配合依赖包mchange-commons-java-0.2.11使用
二,全注解式开发
1.springmvc不需要实现Controller
直接在处理器上加注解@Controller表示这是一个处理器类
service属性的注册使用@Autowired或者@Qualifier()等完成注入
@Controller
@RequestMapping("/test")
public class StudentController {
@Qualifier("studentService")
private IStudentService service;
需要在spring-service配置文件中自动完成service的注册
使用的时候直接使用类名首字母小写表示这个bean
如果是自定义bean的名称需要在service类中@Service("studentService")注解中定义bean名称
<context:component-scan base-package="com.service"/>
在service实现类上添加注解@Service("studentService")表示这是一个service类并定义bean名称
默认的事务注解@Transactional
@Service("studentService")
public class IStudentServiceImpl implements IStudentService {
@Resource(name="IStudentDao")
private IStudentDao dao;
public void setDao(IStudentDao dao) {
this.dao = dao;
}
@Override
@Transactional
public void addStudent(Student student) {
dao.insertStudent(student);
}
使用事务注解需要事务注解驱动
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
mybatis的注解,为了开发效率,mybatis可以只需要配置式就可以
mybatis的注解式就是删除SQL映射文件,在方法上添加注解和SQL语句,其他都不用修改
public interface IStudentDao {
@Insert("insert into student (name,age) values(#{name},#{age})")
void insertStudent(Student student);
}