文章目录
概述
SpringMVC底层原理
- DispatcherServlet:协调各组件,从而完成请求处理
- 视图解析器:根据客户端要求的数据类型,比如页面/XML/JSON来返回数据给客户端
- 拦截器:影响4,5步骤(请求处理前和处理后)
- web.xml文件:用于注册组件
项目搭建
- maven工具:可用于打包编译和运行
- groupId:填写公司或组织名称
- artifactId:填写项目名称或模块名称
- 然后选择自己的maven仓库(本地仓库)
- 模板会自动创建项目骨架,自己需要创建java文件夹(make source directory)
- 版本设置为一参数
Tomcat配置
- 关注
- 名称
- 端口号
- 热部署选项
- 启动后打开的网址
- Tomcat使用与创建:配置——》local——》选择Tomcat本地的存放目录——》命名服务器——》进行deployment,即部署war包(可实时热部署)
web.xml配置
-
使用模板时,maven构建的web容器配置项过低
-
为了增加更多的Servlet支持和更好渲染——》提高容器版本(>3.0)——》修改默认头声明
-
讨巧的方法:创建一个新模块,具体选项如上图(JavaEE7),然后复制该模块web.xml的头声明,放置在自己工程中,再删除该模块
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>namespace</param-name>
<param-value>imoocmvc</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
- 三种配置核心配置文件的方式
第一种:[servlet-name]-servlet.xml ,比如:springmvc-servlet.xml(指定了servlet-name,则核心XML配置文件名被固定死)
第二种是:改变命名空间 namespace,可自由指定核心XML配置文件名
前两种方式必须将配置文件放在web-inf目录下。
第三种可通过:contextConfigLocation配置,如上图
核心配置文件
<?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/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!-- 配置自定义扫描包 -->
<context:component-scan base-package="com.imooc.web"></context:component-scan>
//表示扫描com.imooc.web下的类
<!-- 拦截器的注册 -->
<mvc:interceptors>
//拦截器1,先配置,优先处理
<mvc:interceptor>
<mvc:mapping path="/user/**"/> //表示拦截/user/下的所有请求方法,包括子集,如/user/1/2或者/user/3等等
<bean class="com.imooc.core.LogInterceptor"></bean> //配置拦截器方法
</mvc:interceptor>
//拦截器2,后配置
<mvc:interceptor>
<!--<mvc:mapping path="/user/search"/> //具体说明URL的拦截方式
<mvc:mapping path="/user/updatepwd"/>
<mvc:mapping path="/user/updateheaderPic"/>-->
<!--<mvc:mapping path="/user/*"></mvc:mapping>--> //一个*只有一层目录,不包括子集
<mvc:mapping path="/user/**"></mvc:mapping> //两个*包括子集
<!--exclude-mapping在所有拦截中进行排除,一般在通配符会有意义。-->
<mvc:exclude-mapping path="/user/updatepwd"></mvc:exclude-mapping> //在上述/user/**的范围内排除,取差集
<mvc:exclude-mapping path="/user/updatebackground/*"></mvc:exclude-mapping>
<bean class="com.imooc.core.LoginInterceptor"></bean> //配置拦截器方法
</mvc:interceptor>
</mvc:interceptors>
<!-- 映射物理路径 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
//定义视图解析器,其为JSP渲染的一种视图
//采用JSP视图解析器(拦截的是JSP)
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".jsp"></property>
//用于controller类方法返回逻辑视图时的拼接
//如返回show,则指明页面为/WEB-INF/pages/show.jsp路径
</bean>
</beans>
- RequestMapping注解作用:URL匹配的规则,通过路由RequestMapping配置来完成
加载controller类到内存中,即把mapping生成一个requestmapping类
- Controller类注册了路由和对应的请求处理方法
- 客户端的请求地址——》根据对应的路由,找到方法
- 视图——》页面(基于不同模板引擎,如JSP,选择不同的视图解析器类型)
拦截器和过滤器
-
过滤器(web.xml中配置):过滤请求,即request对象
-
拦截器(核心配置文件中配置):抽离逻辑代码到公共位置,然后进行请求对象延续的过程
-
拦截器:动态代理,AOP编程,无侵入性,在对象执行特定方法时拦截
-
拦截器机制:客户端发起请求,根据路由,找到方法(对象调用特定方法的拦截机制)
登录的拦截器
- 应用场景:CSDN博客若直接输入其他页面URL,且没登录,则要求跳转到登录界面——》AOP织入登录界面
拦截器方法
- render表示返回响应给客户端
拦截器实例
public class LoginInterceptor implements HandlerInterceptor { //实现拦截器接口
//处理请求前执行
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
User user = (User)request.getSession().getAttribute("session_user"); //先确认是否有用户信息
if(user==null) { //没有,则还没登录
System.out.println("1:keketip--login====preHandle===>");
response.sendRedirect(request.getContextPath()+"/login"); //跳转到登录界面
return false; //false代表不执行controller类中URL对应的处理方法
}
return true;//不做处理,然后会执行controller类中URL对应的处理方法
//会终止所有的请求
}
//处理请求后,返回响应前执行
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("3:-----keketip==--login==postHandle===>");
}
//一切请求处理完毕执行
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("4--->keketip=--login===afterCompletion===>");
}
}
-
/为根,/user表示放置在根路由下
-
div标签为盒子
-
数据绑定(获取参数)方式多样,参考如下教程
Controller类
@Controller
public class LoginController {
@RequestMapping("/login")
public String login(){
return "login";
}
@RequestMapping("/logined")
public String logined(@RequestParam("account")String account,
@RequestParam("password")String password,
HttpSession session){
//@RequestParam,数据绑定注解,表示将前端name=account的表单内容绑定到形参account上
if(account.equals("xuke") && password.equals("123456")) {
User user = new User();
user.setAccount(account);
user.setPassword(password);
//登录成功,将对象放置在session中
session.setAttribute("session_user",user); //引入jar包,才有session对象
return "redirect:user/search"; //默认的跳转方式为转发
}else{
return "redirect:login";
}
}
}
------
对应地,可在request域中取出数据
<body>
<h1>用户搜索模块</h1>
<h2>你当前登录的用户是:${session_user.account}</h2>
</body>
- 引入以下jar包,才有session对象
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
-
Tomcat已经提供了相关容器的配置,所以在部署时要忽略(上述provided配置),不去打包
-
JDK动态代理要有接口——》拦截器底层的实现接口为HandlerInterceptor
-
ALT+INSERT快捷键用于快速实现接口
拦截器配置详解
- 在核心配置文件中配置,配置命名空间(灰色的头声明)
- 创建定义拦截器方法的类
- 注册拦截器,定义拦截规则,配置定义拦截器方法的bean节点,开启注解扫描
<?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/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!-- 配置自定义扫描包 -->
<context:component-scan base-package="com.imooc.web"></context:component-scan>
<!-- 拦截器的注册 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/user/**"/>
<bean class="com.imooc.core.LogInterceptor"></bean>
</mvc:interceptor>
<mvc:interceptor>
<!--<mvc:mapping path="/user/search"/>
<mvc:mapping path="/user/updatepwd"/>
<mvc:mapping path="/user/updateheaderPic"/>-->
<!--<mvc:mapping path="/user/*"></mvc:mapping>-->
<mvc:mapping path="/user/**"></mvc:mapping>
<!--exclude-mapping在所有拦截中进行排除,一般在通配符会有意义。-->
<mvc:exclude-mapping path="/user/updatepwd"></mvc:exclude-mapping>
<mvc:exclude-mapping path="/user/updatebackground/*"></mvc:exclude-mapping>
//exclude仅仅针对上方存在通配符匹配才有效,与具体配置无关
<bean class="com.imooc.core.LoginInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
<!-- 映射物理路径 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
多个拦截器
日志拦截器
- 新增日志拦截器
package com.imooc.core;
import com.imooc.bean.User;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LogInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("log------>1:-----keketip====preHandle===>");
System.out.println("keketip====当前执行的类是:"+handler.getClass()); //handler对象可获得当前请求的方法名
System.out.println("keketip===="+handler);
return true;//会终止所有的请求
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("log------>3:-----keketip====postHandle===>");
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("log------>4--->keketip====afterCompletion===>");
}
}
执行顺序
- 谁配置在前谁先执行preHandler方法
- Z字型执行顺序,注意postHandler和afterCompletion是后配置的拦截器先执行
-
若第二个拦截器的preHandler方法返回false(不进入controller类的方法),则直接跳转到第一个拦截器的afterCompletion去执行
-
拦截器1的preHandler——》return true——》controller类的方法还有拦截器——》拦截器2的preHandler——》return true——》执行controller类方法——》拦截器2的postHandler——》拦截器1的postHandler——》拦截器2的afterCompletion——》拦截器1的afterCompletion——》返回客户端响应
-
aftercompletion:所有请求和posthandler执行完毕才执行
-
日志拦截器可获取当前执行的方法和处理对象