SpringMVC(王)
SpringMVC:是基于spring的框架,实际上就是spring的一个模块,专门是做web开发的,是servlet的一个升级
web开发底层是servlet,框架是在servlet基础上加入一些功能,让你做web开发更加方便
SpringMVC就是一个Spring。Spring是容器,ioc能够管理对象,使用,@Componet,@Repository,@Service,@Controller
SpringMVC能够创建对象,放入到容器中(SpringMVC容器),springmvc容器中放入的是控制器对象(controller)
我们要做的是:使用@Controller创建控制器对象,把对象放入到springmvc容器当中,把创建的对象作为控制器使用,这个控制器对象能够接收用户的请求,显示处理结果,就当作是一个servlet使用
使用@Controller注解创建的是一个普通类的对象,不是servlet,springmvc赋予了控制器对象一些额外的功能
web开发底层是servlet,springmvc中有一个对象是servlet:DispatcherServlet。DispatcherServlet:负责接收用户的所有请求,用户把请求给了DispatherServlet,之后DispatcherServlet把请求转发给了我们的Controller对象,最后是Controller对象处理请求
index.jsp------DispatcherServlet(servlet)-------转发,分配给Controller对象(@Controller注解创建的对象)
需求:用户在页面发起了一个请求,请求交给springmvc的控制器对象,并显示请求的处理结果(把结果页面显示一个欢迎语句)
实现步骤:
1.新建web maven工程
2.加入依赖
spring-mvc依赖,间接把spring的依赖都加入到项目
jsp,servlet依赖
3.重点:在web.xml中注册springmvc框架的核心对象DispatcherServlet
DispatcherServlet叫做中央调度器,是一个servlet,它的父类继承HttpServlet
DispatcherServlet也叫做前端控制器(front controller)
DispatcherServlet负责接收用户的请求,调用其它的控制器对象,并把请求的处理结果显示给用户
4.创建一个发起请求的页面,index.jsp
5.创建控制器类
在类的上面加入@Controller注解,创建对象,并放入到springmvc容器中
在类的方法上面加入@RequestMapping注解
6.创建一个作为结果的jsp,显示请求的处理结果
7.创建springmvc的配置文件(和spring的配置文件一样)
声明组件扫描,指定@Controller注解所在的包名
声明视图解析器,帮助处理视图的
springmvc请求的处理流程
- 用户发起some.do请求----
- tomcat(web.xml—url-pattern直到*.do的请求是给DispatcherServlet)-----
- DispatcherServlet(根据springmvc.xml配置知道some.do—doSome())------
- DispatcherServlet把some.do转发给MyController.doSome()方法------
- 框架执行doSome()把得到的ModelAndView进行处理,转发到show.jsp
springmvc执行过程源代码分析
-
tomcat启动,创建容器的过程
通过load-on-start标签指定的1,创建DispatcherServlet对象,父类继承HttpServlet,在被创建时,会执行init()方法,在init()方法中执行
//创建容器,读取配置文件 WebApplicationContext ac = new ClassPathXmlApplicationContext(springmvc.xml); //把容器对象放入到ServletContext中 getServletContext.setAttribute(key,ac);
上面创建容器作用:创建@Controller注解所在的类的对象,创建MyController对象,这个对象放入到springmvc的容器中,容器是map,类似于map.put(“myController”,MyController对象)
-
请求的处理过程
- 执行servlet的service()方法
- 执行doService()方法
- 执行doDispatch()方法,这个方法调用MyController的doSome()方法
控制器方法的返回值
使用@Controller注解的处理器的处理器方法,其返回值常用的有四种类型
- ModelAndView
- String
- 无返回值 void
- 返回自定义类型对象
根据不同的情况,使用不同的返回值
返回值 ModelAndView
如果处理器方法处理后,需要跳转到其它资源,且又要在跳转的资源间传递数据,此时处理器方法返回ModelAndView比较好,当然,若要返回ModelAndView,则处理器方法中需要定义ModelAndView对象,如果只需要数据或者只进行页面跳转就不推荐使用ModelAndView
返回值 String
如果只需要页面之间的跳转,可以使用String
返回void
若处理器对请求处理后,无需跳转到其它任何资源,此时可以让处理器方法返回void,例如:对于AJAX的异步请求的响应,通过HttpServletResponse输出数据,响应ajax请求,ajax请求服务器端返回的就是数据,和视图无关
返回对象Object
处理器方法可以返回Object对象,这个Object可以是Integer,String,自定义对象,Map,List等,但返回的对象不是作为逻辑视图出现的,而是作为直接在页面中显示的数据出现的
返回对象,需要使用ResponseBody注解,将转换后的JSON的数据放入到响应体中
现在做ajax,主要使用json的数据格式
实现步骤:
- 加入处理json的工具库的依赖,springmvc默认使用的是jackson
- 在springmvc配置文件中加入《mvc:annotation-driven》标签,注解驱动,作用是把java对象转换为json数据
- 在处理器方法的上面加入@ResponseBody注解,作用是将:json数据放入到响应中
springmvc处理器方法返回Object,可以转为json输出到浏览器,响应ajax的内部原理
-
《mvc:annotation-driven>注解驱动
注解驱动实现的功能是,完成java对象到json,xml,text,二进制等数据格式的转换
HttpMessageConverter:接口,消息转换器
功能:定义了java转为json,xml等数据格式的方法,这个接口有很多的实现类。这些实现类完成java对象到json,java对象到xml,java对象到二进制数据的转换
HttpMessageConverter接口中的下面两个方法是控制器类把结果输出到浏览器时使用的 boolean canWrite(Class<?> var1, @Nullable MediaType var2); void write(T var1, @Nullable MediaType var2, HttpOutputMessage var3)
在jsp,html中使用的地址,都是在前端页面中的地址,都是相对地址
相对地址不能独立使用,必须有一个参考地址,通过参考地址,相对地址本身才能指定资源
参考地址
在你的页面中,访问地址不加"/"
访问的是:http://localhost:8080/cho6-path/index.jsp
路径:http://localhosdt:8080/ch06-path/
资源:index.jsp
在index.jsp发起 user/some.do 请求,访问地址变为 http://localhost:8080/ch06-path/user/some.do
当你的地址没有斜杠开头,例如: user/some.do,当你点击连接时,访问地址是当前页面地址,再加上连接本身的地址
http://localhost:8080/ch06-path/ + user/some.do
在你的页面中,访问地址加上"/"
访问的是:http://localhost:8080/cho6-path/index.jsp
路径:http://localhosdt:8080/ch06-path/
资源:index.jsp
点击 /user/some.do ,访问地址变为 http://localhost:8080/user/some.do,缺少了网站名 cho6-path
加上 / 访问的是 ip+端口号
解决办法,在 /user/some.do 前面加上 /cho6-path/user/some.do,就可以了,但是这样不灵活,不推荐
还可以使用el表达式
<a href="${pageContext.request.contextPath}/user/some.do">发起user/some.do的请求</a>
在不加上 / 的时候,也会出现问题
还有一个问题,如果在index.jsp页面中点击user/some.do后,页面的跳转是跳转回index.jdp,这个时候再次点击user/some.do,会出现问题
第一次点击user/some.do跳转后的地址
http://localhost:8080/ch06-path/user/some.do
再次点击user/some.do之后跳转的地址
http://localhost:8080/ch06-path/user/user/some.do
这是因为,第一次跳转后,参考地址中的路径已经改变为http://localhost:8080/ch06-path/user/,这个时候再次点击就会加上user/some.do,变成http://localhost:8080/ch06-path/user/user/some.do
有两种解决方法
第一种,加上/,使用el表达式
第二种,加入一个base标签,是html语言当中的标签,表示当前页面中访问地址的基地址,你的页面当中所有没有”/“开头的地址,都是以base标签中的地址为参考地址
<html>
<head>
<title>title</title>
<base href="http://localhost:8080/ch06-path/" />
</head>
<body>
<a href="user/some.do">发起user/some.do的请求</a>
</body>
</html>
这样无论点多少次都不会有问题,但是这样不够灵活,话可以再次进行修改
<%
String basePath=request.getScheme()+"://"+request.getServerName()+":"+request.getServerPost+request.getContextPath()+"/";
%>
<html>
<head>
<title>title</title>
<base href="<%=basePath%>" />
</head>
<body>
<a href="user/some.do">发起user/some.do的请求</a>
</body>
</html>
这样就能动态的获取地址
SSM整合
springmvc中的请求转发和重定向
当处理器对请求处理完毕后,向其他资源进行跳转时,有两种跳转方式:请求转发和重定向,而根据索要跳转的资源类型,又可以分为两类:跳转到页面和跳转到其它处理器
注意,对于请求转发的页面,可以是WEB-INF中页面,而重定向的页面,是不能为WEB-INF中的页面的,因为重定向相当于用户再次发出一次请求,而用户是不能直接访问WEB-INF中的资源的
springmvc框架把原来的Servlet中的请求转发和重定向操作进行了封装,现在可以使用简单的方式实现转发和重定向
forward:表示转发,实现 request.getRequestDispatcher(“xx.jsp”).forward();
redirect:表示重定向,实现response.sendRedirect(“xxx.jsp”)
异常处理:
springmvc框架采用的是统一,全局的异常处理
把controller中的所有异常处理都集中到一个地方,采用的是aop的思想,把业务逻辑和异常代码分开,解耦合
使用到两个注解
@ExceptionHandler
@ControllerAdvice
异常的处理步骤
1.新建maven web项目
2.加入依赖
3.新建一个自定义异常类,MyUserException,在定义它的子类NameException,AgeException
4.在Controller中抛出NameException,AgeException
5.创建一个普通类,作为全局异常处理类
1)在类的上面加入@ControllerAdvice
2)在类中定义方法,方法的上面加入@ExceptionHandler
6.创建处理异常的视图页面
7.创建springmvc的配置文件、
1)组件扫描器,扫描@Controller注解
2)组件扫描器,扫描@ControllerAdvice所在的包名
3)声明注解驱动
拦截器
springmvc中的interceptor拦截器是非常重要和相当有用的,它的主要作用就是拦截指定的用户请求,并进行相应的预处理和后出处理,其拦截的时间点在“处理器映射器根据用户提交的请求映射出了索要执行的处理器类,并且也找到了要执行该处理类的处理器适配器,在处理器适配器执行处理器之前。当然,在处理器映射器映射出所要执行的处理器类时,已经将拦截器与处理器组合为了要给处理器执行链,并返回给了中央调度器
拦截器是springmvc中的一种,需要实现HandlerInterceptor接口
拦截器和过滤器类似,功能方向侧重点不同,过滤器是用来过滤请求参数,设置编码字符集等工作
拦截器是拦截用户的请求,对请求做判断处理的
拦截器是全局的,可以对多个Controller做拦截,项目中可以没有或者多个拦截器,他们在一起拦截用户的请求,拦截器常用在:用户登录处理,权限检查,记录日志
使用步骤
1.定义类实现HandlerInterceptor接口
2.在springmvc配置文件中,声明拦截器,让框架知道拦截器的存在
拦截器的执行时间
1.在请求处理之前,也就是controllerr类中的方法执行之前先被拦截
2.在控制器方法执行之后也会执行拦截器
3.在请求处理完成后也会执行拦截器
拦截器:看做是多个Controller中公用的功能,集中到拦截器统一处理,使用的aop的思想
多个拦截器
第一个拦截器preHandle=true,第二个拦截器preHandle=true
11111111-拦截器的MyInterceptor的preHandle()
2222222-拦截器的MyInterceptor的preHandle()
执行MyController的doSome()方法
2222222-拦截器的MyInterceptor的postHandle()
11111111-拦截器的MyInterceptor的postHandle()
2222222-拦截器的MyInterceptor的afterHandle()
11111111-拦截器的MyInterceptor的afterHandle()
以控制器方法为界限,有一种先进后出的感觉
拦截器执行链
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2SW5CZVz-1635916101636)(D:\知识点截图\java基础知识\拦截器执行链.png)]
第一个拦截器preHandle=true,第二个拦截器preHandle=false
11111111-拦截器的MyInterceptor的preHandle()
2222222-拦截器的MyInterceptor的preHandle()
11111111-拦截器的MyInterceptor的afterHandle()
拦截器的preHandle=true,则afterHandle()方法一定会执行
第一个拦截器preHandle=false,第二个拦截器preHandle=false/true
11111111-拦截器的MyInterceptor的preHandle()
拦截器和过滤器的区别
- 过滤器是servlet中的对象,拦截器是框架中的对象
- 过滤器实现Filter接口的对象,拦截器是实现HandlerInterceptor
- 过滤器是用来设置request,response的参数,属性的,侧重对数据过滤的,而拦截器是用来验证请求的,能截断请求
- 过滤器是在拦截器之前先执行的
- 过滤器是tomcat服务器创建的对象,拦截器是springmvc容器当中创建的对象
- 过滤器是一个执行时间点,而拦截器有三个执行时间点
- 过滤器可以处理jsp,js,html等等,而拦截器是侧重拦截对Controller的对象,如果你的请求不能被DispatcherServlet接收,这个请求不会执行拦截器内容
springmvc的执行流程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KnvzUSIl-1635916101639)(D:\知识点截图\java基础知识\springmvc的执行流程.png)]
springmvc内部请求的处理流程:也就是springmvc接收请求,到处理完成的过程
-
用户发起请求some.do
-
DispatcherServlet(中央调度器)接收请求some.do,把请求转交给处理器映射器
处理器映射器:Springmvc框架中的一种对象,框架把实现了HandlerMapping接口的类都叫做映射器(多个) ,我应该使用的实现类是RequestMappingHandlerMapping
处理器映射器作用:根据请求,从springmvc容器对象当中获取处理器对象(controller对象),框架会把找到的处理器对象放到一个叫做处理器执行链(HandlerExecutionChain)的类保存
HandlerExecutionChain:类中保存着,1.处理器对象(MyController);2.项目中的所有的拦截器
-
DispatcherServlet把2中的HandlerExecutionChain中的处理器对象交给了处理器适配器对象(多个)
处理器适配器:springmvc框架中的对象,需要实现HandlerAdapter接口
处理器适配器的作用:执行处理器方法(调用MyControler中的doSome()方法,得到返回值ModelAndView)
-
DispatchperServlet把3中获取的ModelAndView交给了视图解析器对象
视图解析器:springmvc中的随想,需要实现ViewResoler接口(可以有多个)
视图解析器作用:组成视图完成路径,使用前缀,后缀。并创建View对象,View是要给接口,表示视图的,在框架中jsp,html不是String表示,而是使用View和它的实现类表示视图
InternalResourceView:视图类,表示Jsp文件,视图解析器会创建InternalResourceView类对象,这个对象里面,有一个属性URL=/WEB-INF/view/show.jsp
-
DispatcherServlet把4步骤中创建的View对象获取到,调用View类自己的方法,把Model数据放入到request作用域,执行对象视图的forward,请求结束
et把3中获取的ModelAndView交给了视图解析器对象
视图解析器:springmvc中的随想,需要实现ViewResoler接口(可以有多个)
视图解析器作用:组成视图完成路径,使用前缀,后缀。并创建View对象,View是要给接口,表示视图的,在框架中jsp,html不是String表示,而是使用View和它的实现类表示视图
InternalResourceView:视图类,表示Jsp文件,视图解析器会创建InternalResourceView类对象,这个对象里面,有一个属性URL=/WEB-INF/view/show.jsp
- DispatcherServlet把4步骤中创建的View对象获取到,调用View类自己的方法,把Model数据放入到request作用域,执行对象视图的forward,请求结束