1.概念
springMVC:是基于spring的一个框架, 实际上就是spring的一个模块, 专门是做web开发的。
理解是servlet的一个升级
web开发底层是servlet , 框架是在servlet基础上面加入一些功能,让你做web开发方便。
SpringMVC就是一个Spring。 Spring是容器,ioc能够管理对象,使用<bean>, @Component, @Repository, @Service, @Controller
SpringMVC能够创建对象, 放入到容器中(SpringMVC容器), springmvc容器中放的是控制器对象,
我们要做的是 使用@Contorller创建控制器对象, 把对象放入到springmvc容器中, 把创建的对象作为控制器使用
这个控制器对象能接收用户的请求, 显示处理结果,就当做是一个servlet使用。
使用@Controller注解创建的是一个普通类的对象, 不是Servlet。 springmvc赋予了控制器对象一些额外的功能。
web开发底层是servlet, springmvc中有一个对象是Servlet : DispatherServlet(中央调度器)
DispatherServlet: 负责接收用户的所有请求, 用户把请求给了DispatherServlet, 之后DispatherServlet把请求转发给我们的Controller对象, 最后是Controller对象处理请求。
springmvc请求的处理流程
浏览器发起地址请求
tomcat将这个请求给 DispatcherServlet(中央调度器,本质上是一个servlet,需要配置路径)
DispatcherServlet根据配置文件知道控制层里面的方法对应的路径,通过路径来调用方法
然后框架执行方法内容
简单来说就是:前端--------》DispatcherServlet------------》控制器
需要的配置:
首先需要在web.xml文件中配置DispatcherServlet这个servlet
<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_4_0.xsd"
version="4.0">
<!-- 注册springmvc的核心对象DispatcherServlet,需要在tomcat服务器启动之后就创建实例-->
<!-- 在DispatcherServlet创建过程中会在他的init初始化方法中创建容器对象,然后可以创建出controller对象,通过接收-->
<!-- 到的地址和控制器对象来决执行某些方法-->
<!-- DispatcherServlet是一个servlet,servlet初始化的时候会执行init()方法,init中有-->
<!-- WebApplicationContext ctx=new ClassPathXmlApplicationContext("srpingmvc.xml");-->
<!-- getServletContext().setAttribute(key,value);-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 在启动服务器的时候DispatcherServlet对象中的init方法会自动找WEB-INF/springmvc-servlet.xml文件(springmvc是这个servlet的名称)-->
<!-- 加上这个之后,会按照这个指定的路径来寻找文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<!-- 加上这个标签可以,让tomcat启动的时候就创建这个servlet对象,数字越小启动越快-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
然后需要在对应的路径配置扫描controller层的文件(这里指定的是resources下的)
<context:component-scan base-package="com.springmvc.controller"></context:component-scan>
然后配置环境就搭建完毕,只需要写控制层就可以开始使用了
springmvc执行过程源代码分析 (简单的原码分析)
1. tomcat启动,创建容器的过程
通过load-on-start标签指定的1,创建DisaptcherServlet对象,
DisaptcherServlet它的父类是继承HttpServlet的, 它是一个serlvet, 在被创建时,会执行init()方法。
在init()方法中
//创建容器,读取配置文件
WebApplicationContext ctx = new ClassPathXmlApplicationContext("springmvc.xml");
//把容器对象放入到ServletContext中
getServletContext().setAttribute(key, ctx);
上面创建容器作用: 创建@controller注解所在的类的对象, 创建MyController对象,
这个对象放入到 springmvc的容器中, 容器是map , 类似 map.put("myController",MyController对象)
2.请求的处理过程
1)执行servlet的service()
首先执行protected void service(HttpServletRequest request, HttpServletResponse response)
然后 protected void doService(HttpServletRequest request, HttpServletResponse response)
最后 DispatcherServlet.doDispatch(request, response){
调用MyController的.doSome()方法
}
doDispatch:springmvc中DispatcherServlet的核心方法, 所有的请求都在这个方法中完成的。
发起的请求是由哪些服务器程序处理的。
comcat服务器负责处理html,图片,js文件等资源
而 DispatcherServlet负责处理转发访问
@RequestParam注解
用法:请求中参数名和处理器方法的形参名不一样 属性;
value指定请求参数名称(前端传递过来的名称)
required,boolean类型用于指定该参数是否必须
框架调用request.getParameter()获取出前端传递来的值然后直接注入到参数中。 前端传递来的参数,框架会自动转换类型。注入的方式是根据命名。相同的名称参数会自动注入进去。 也可以使用实体类来接收前端传递来的参数。框架会自动创建对象
@RequestMapping("/some.do")
public ModelAndView somedo( @RequestParam("name")String name, @RequestParam("sex")String sex, @RequestParam("age")Integer age){
ModelAndView m=new ModelAndView();
m.addObject("name",name);
m.addObject("sex",sex);
m.addObject("age",age);
m.setViewName("show");
return m;
}
返回json数据
在目前的使用中,一般后台和前端都是使用ajax的交互方式,所以数据格式使用的就是json的数据格式。控制层方法一般会返回一个json数据(Student),一般这个过程由框架来实现。
框架将数据转换为json首先调用 ArrayList<HttpMessageConverter>中每个类的canWrite()方法检查,HttpMessageConverter接口的实现类能处理Student类型的数据--MappingJackson2HttpMessageConverter 2.框架会调用实现类的write(), MappingJackson2HttpMessageConverter的write()方法 把李四同学的student对象转为json,调用Jackson的ObjectMapper实现转为json contentType: application/json;charset=utf-8 3.框架会调用@ResponseBody把2的结果数据输出到浏览器, ajax请求处理完成
简单来说,想要使用mvc的转换功能需要的步骤:
- 首先添加相关的依赖
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.9.0</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.0</version> </dependency>
- 添加驱动,在中央调度处理器获取的xml文件里面添加
<mvc:annotation-driven />
- 添加注解@ResponseBody,在控制器上
前端ajax的使用
$(function () {
$("#button").click(function () {
$.ajax({
url:"some.do",
data:{name:"zhangsan",
sex:"nan",
age:12
},
type:"post",
dataType:"json",
success:function (res) {
alert(res.name+res.sex+res.age)
},
})
})
})
这如果返回值是string的话可能会出现乱码,只需将dataType的类型设置为text就行。
处理器方法返回的是String , String表示数据的,不是视图。 区分返回值String是数据,还是视图,看有没有@ResponseBody注解 如果有@ResponseBody注解,返回String就是数据,反之就是视图
将中央调度器设置为/路径
这样做之后就会发现静态资源无法访问,原因是因为tomcat处理静态资源借助的就是default servlet,这个servlet的路径就是/,如果中央调度处理器使用同一个就会将原本的覆盖。
<!--第一种处理静态资源的方式:
需要在springmvc配置文件加入 <mvc:default-servlet-handler> 原理是: 加入这个标签后,框架会创健控制器对象DefaultServletHttpRequestHandler(类似我们自己创建的MyController). DefaultServletHttpRequestHandler这个对象可以把接收的请求转发给 tomcat的default这servlet。
这种方式任然需要default来工作
<!--第二种处理静态资源的方式
mvc:resources 加入后框架会创建 ResourceHttpRequestHandler这个处理器对象。 让这个对象处理静态资源的访问,不依赖tomcat服务器。 mapping:访问静态资源的uri地址, 使用通配符 ** location:静态资源在你的项目中的目录位置。 images/**:表示 images/p1.jpg images/user/logo.gif , images/order/history/list.png -->
<mvc:resources mapping="/static/**" location="/static/" />
使用ssm整合项目
这里的配置文件详解放到一个单独的文档
ssm框架的配置文件完整方式_洛空_的博客-CSDN博客ssm配置解析https://blog.csdn.net/m0_64589497/article/details/127311493
请求转发forward和重定向redirect
从上述能够知道可以使用视图解析器来访问WEB-INF目录下的jsp文件,时候如果指定了试图解析器的前缀是WEB-INF/view,这时候需要访问WEB-INF下的另一个目录就需要用到forward
@RequestMapping("/forward.do")
public ModelAndView forward(Student student){
ModelAndView m=new ModelAndView();
m.addObject("msg",student);
m.setViewName("forward:/WEB-INF/forward/show.jsp");
return m;
}
这样就可以访问到需要的其他目录,需要写完整的目录。
重定向
@RequestMapping("/redirect.do")
public ModelAndView redirect(Student student){
ModelAndView m=new ModelAndView();
m.addObject("msg",student);
m.setViewName("redirect:/hellow.jsp");
return m;
}
重定向无法和视图解析器一起使用(无法访问WEB-INF目录下的jsp文件),使用重定向的时候,相当于一次新的请求,所以无法获取到m对象中的参数。ModelAndView是存放在reques请求域里面的数据,如果使用重定向的访问方式,那会生成一个新的request,所以无法获取数据。
使用全局异常处理
实际上就是一种全局的aop处理方式
只需要创建一个全局处理类,然后直接加上 @ControllerAdvice注解就可以了,然后可以选特定的异常类型捕捉使用不同的处理方式。这个类必须交给容器管理。
@ControllerAdvice
public class GlobalExceptionHander {
@ExceptionHandler(value= NameException.class)
public ModelAndView doNameException(Exception ex){
ModelAndView m=new ModelAndView();
m.addObject("msg","姓名必须是张三,其他用户不可以访问");
m.addObject("ex",ex);
m.setViewName("nameError");
return m;
}
@ExceptionHandler(value= AgeExecption.class)
public ModelAndView doAgeException(Exception ex){
ModelAndView m=new ModelAndView();
m.addObject("msg","年龄不能为空");
m.addObject("ex",ex);
m.setViewName("nameError");
return m;
}
@ExceptionHandler()
public ModelAndView doOtherException(Exception ex){
ModelAndView m=new ModelAndView();
m.addObject("msg","其他异常!");
m.addObject("ex",ex);
m.setViewName("nameError");
return m;
}
}
public class MyException extends Exception {
public MyException(String message) {
super(message);
}
public MyException() {
super();
}
}
里面的异常你可以自己定义,也可以用存在的,有一个全局的处理方式。
配置文件扫描
<context:component-scan base-package="com.ssm.handler"></context:component-scan>
拦截器
拦截器是springmvc中的一种,需要实现HandlerInterceptor接口,
拦截器和过滤器类似,功能方向不一样,过滤器是用来设置编码的
拦截器是全局的,可以对多个controller拦截。拦截器通常用在,验证身份,权限检查,日志
拦截器使用的步骤
首先定义一个类来实现HandlerInterceptor接口,然后再springmvc的配置文件中声明拦截器的位置以及访问路径
拦截器的执行时间,和过滤器一样,会在方法前后都执行
public class MyInterceptor implements HandlerInterceptor {
/**
*
* @param request
* @param response
* @param handler 被拦截的控制器对象
* @return 返回值是一个boolean对象,true通过,反之拦截
* @author liujun
* @date 这个方法是在控制器方法的前面执行,可以在这个方法里面获取请求信息,可以验证登录信息
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String name = request.getParameter("name");
String age = request.getParameter("age");
if ("张三".equals(name)){
return true;
}
return false;
}
/**
* 后处理方法,控制器执行之后执行
* @param request
* @param response
* @param handler 被拦截的控制器对象
* @param modelAndView 处理方法的返回值
* @return
* @author liujun
* @date 可以对原本的执行结果修改
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
modelAndView.addObject("msg","拦截器修改之后的modelAndView");
}
/**
*
* @param request
* @param response
* @param handler 被拦截器的处理器对象
* @param ex 程序中的异常
* @return
* @author liujun
* @creed: Talk is cheap,show me the code
* @date 在请求处理完成后执行,框架中规定是当你视图处理完成后,对视图转发。
* 一般是用来资源回收,删除对象等
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
throw ex;
}
}
<!-- 声明拦截器,可以声明多个-->
<mvc:interceptors>
<!-- 第一个-->
<mvc:interceptor>
<!-- 将拦截器和拦截路径绑定-->
<mvc:mapping path="/**"/>
<bean class="com.ssm.handler.MyInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
拦截器和过滤器
过滤器是servlet中的对象,拦截器是框架中的对象
过滤器是实现Filter接口的对象,拦截器是实现HandlerInteceptor接口的
过滤器是用来解决字符集的问题的额,拦截器是用来验证请求的
过滤器是tomcat创建的,拦截器是框架创建的
过滤器只有一个执行时间点,但是存在初始化和 销毁方法,而拦截器存在三个执行点
过滤器在servlet之前执行,而拦截器在中央调度的servlet之后执行
执行流程
- 浏览器发起请求some.do到DispatcherServlet
- 中央调度器将请求转发到处理器映射器
- 处理器映射器:框架吧实现了HandlerMapper接口的类都叫映射器,根据请求从springmvc容器中获取处理器对象(MyController controller=cx.getbean(“文件”))。将处理器对象和拦截器对象放到一个处理器执行链HandlerExecutionChain中保存,返回给中央调度处理器
- 中央调度处理器将这个执行链给处理器适配器(实现了HandlerAdapter接口的),用来执行处理器方法返回一个ModelAndView给中央调度处理器
- 中央调度处理器将这个给视图解析器(需要实现ViewResoler接口,也就是mvc中配置的),用来组成视图的完整路径,使用前缀。后缀创建view对象
- DispatcherServlet将上面的view对象获取到之后调用一个方法,将model中的数据存放到request域中,请求结束。