cho1-hello-springmvc:第一个springmvc项目
一. 需求:
用户在页面发起一个请求,请求交给springmvc的控制器对象,并显示请求的处理结果(在结果页面显示一个欢迎语句)。
二. 实现步骤:
-
新建web maven工程(main包下添加java包和resources包,然后修改web.xml文件的版本)
-
加入依赖,
1)spring-webmvc依赖,也就间接把spring的依赖都加入倒项目,
2)jsp,servlet依赖**(为什么没有jsp依赖?)**
-
重点:在web.xml项目中注册springmvc框架的核心对象DispatcherServlet(dispatcher英文:分配器)
1)DispatchServlet叫做中央调度器,是一个servlet,他的弗雷是继承HttpServlet.
2)DispatchServlet也叫做前端控制器(front controller)
3)DispatcherServlet负责接收用户提交的请求,调用其他的控制器对象,并把请求的处理结果显示给用户。
-
创建一个发起请求的页面 index.jsp。
-
创建控制器类
1)在类的上面加@Controller注解,创建对象,并放入倒springmvc容器中。
2)在类的方法上面加入@RequestMapping注解。
-
创建一个作为结果的jsp,显示请求的处理结果。
-
创建spring的配置文件(spring的配置文件一样)。
1)声明组件扫面器,指定@Controller注解所在的包名。
2)声明视图解析器,帮忙处理视图的。
文件访问流程:
- 请求(index.jsp文件)
- *.do(web.xml文件)
- springmvc(web.xml文件)
- 中央调度器org.springframework.web.servlet.DispatcherServlet(web.xml文件)
- classpath:springmvc.xml(web.xml文件)
- 组件扫描器(resources包下的springmvc.xml文件)组件扫描器中的实体类(控制器类Mycontroller类)
- 通过RequestMapping请求映射注解的属性可以得知相对应的“servlet"方法,“servlet"方法类似javaWeb中的doGet()方法
- 展示界面(show.jsp文件)
三. 源码及注释(代码知识点讲解):
1. web.xml文件("/" 和 " *.do "
这个xml文件需要更换版本
<!--
声明,注册springmvc的核心对象DispatcherServlet
需要在tomcat服务器启动后,创建DispatcherServlet对象实例,也就是下面的控制顺序的标签,
但是为什么要创建DispatcherServlet对象的实例呢?
DispatcherServlet在他的创建过程中,会同时创建springmvc容器对象,读取springmvc的配置文件,把这个配置文件 中的对象都创建好,当用户发起请求是法就可以直接使用对象。
servlet的初始化会指向init()方法。DispatcherServlet在init()中{
//创建容器,读取配置文件
WebApplicationContext ctx = new ClasspathXmlApplicationContext("springmvc.xml")
}
-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--自定义springmvc读取的配置文件的位置-->
<init-param>
<!--springmvc的配置文件的位置的属性-->
<param-name>contextConfigLocation</param-name>
<!--指定自定义文件的位置-->
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!--
在tomcat启动后,创建Servlet对象
load-on-startup:表示tomcat启动后创建安对昂的顺序,原本是在servlet被访问时创建DispatcherServlet中央调度 器对象。它的值是整数,数值越小,tomcat创建对象的时间越早。
-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<!--
使用框架是,url-pattern可以使用两种值
1.使用框架扩展名,语法 *.xxxx,xxxx是自定义扩展名,常用,*.do等,不能用*.jsp(不用加/)
2.使用"/"。表示中央调度器加载所有资源请求包括静态资源,和为映射到其他servlet的请求等(原本是交给tomcat处理的可查看tomcat中的web.xml文件源码里面的default,和中央调度器定义映射方法镭同),用上一种方法是只加载和扩展名对应的请求。
1)当项目中使用了 / , 它会替代tomcat中的default。
导致所有静态资源都给DispatcherServlet中央调度器处理,默认情况下DispatcherServlet没有处理静态资源。
但是没有控制器对象能处理静态资源的访问。所以静态资源(html, js, 图片, css)都是404,而动态资源some.do还是可以访问的,因为我们程序中有Mycontroller控制器对象,能处理some.do请求
2)有两种处理方法(避免404):
第一种处理静态资源的方法:
===========需要在springmvc配置文件中加入<mvc:default-servlet-handler>===============================
原理:加入这个标签后,框架会创建控制器对象DefaultServletHttpRequestHandler(类似我们自己创建的MyController),DefaultServletHttpRequsetHandler这个对象可以把接收的请求转发给tomcat的default这个servlet。(即用了请求转发知识点,request.getRequestDispatcher("").forward可查看DefaultServletHttpRequsetHandler源码。
3)但是 / 会把所有的请求都交给tomcat处理,因此<mvc:default-servlet-handler>和@RequestMapping注解有冲突,需要加入<mvc:annotation-driven/>注解驱动解决问题。
=======第二种处理静态资源的方法:=============================================================
<mvc:resources mapping="/images/**" location="/images/">
mvc:resources加入后框架会创建ResourceHttpRequestHandler这个处理器对象。
mapping:访问静态资源的url地址,使用通配符**,(**不仅代表文件,也可以代表子目录,可用于使用一个配置语句,指定多种静态资源的访问)。
location:访问静 态资源在你的项目中的目录位置。
但是仍然要加上注解驱动<mvc:annotation-driven/>,不然动态资源无法访问
-->
<url-pattern>*.do</url-pattern>
</servlet-mapping>
2. 控制器类(controller包下的MyController类)
需要在resources包下的springmvc.xml文件中声明组件扫描器。
@Controller
public class MyController {
@RequestMapping("/some.do")
public ModelAndView doSome(){
//这里将service调用处理省略了
ModelAndView mv = new ModelAndView();
//相当与javaWeb基础中的request.serAttribute("","");
//然后在jsp文件中getAttribute()获取
mv.addObject("msg","欢迎使用");
mv.addObject("fun","执行的是doSome方法");
//指定视图,指定视图的完整路径。
//框架对视图执行的forward操作,相当于javaWeb基础中的
//request.getRequestDispatcher("/show.jsp").for(request,response)
mv.setViewName("/show.jsp");
return mv;
}
}
3.视图解析器
resources包下的springmvc.xml文件(也有的用的DispatcherServlet.xml名称),InternalResourceViewResolver英文:内部资源视图解析器的意思。
<!--声明springmvc框架中的视图解析器,帮助开发人员设置视图文件的路径-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 前缀:视图文件的路径 -->
<property name="prefix" value="/WEB-INF/view"/>
<!-- 后缀:视图文件的扩展名 -->
<property name="suffix" value=".jsp"/>
</bean>
//mv.setViewName("/WEB-INF/view/show.jsp");//可将此代码修改为下方代码
mv.setViewName("show");
4. 过滤器(在5监听器下面)
web.xml文件
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<!--设置项目中使用的字符编码-->
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
<!--强制请求对象(HttpServletRequest)使用encoding编码的值-->
<init-param>
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<!--强制应答对象(HttpServletResponse)使用encoding编码的值-->
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<!--
/*:表示强制所有的请求先通过过滤器处理
-->
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
详情有单独的两篇文章介绍
- Get和Post请求方式
- 过滤器解决Post请求乱码
5.监听器(在1下面)
在使用监听器前需要加spring-web依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
web.xml加上下面配置
<!--
监听器对象被创建后,会读取applicationContext.xml文件,或spring.xml文件(名字不同)
为什么要读取:因为在监听器中要创建ApplicationContext对象,需要记载配置文件
-->
<context-param>
<!--contextConfigLocation:表示配置文件的路径-->
<param-name>contextConfigLocation</param-name>
<!--自定义配置文件路径,原本默认是/WEB_INF/applicationContext.xml-->
<param-value>classpath:conf/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
-
需求:
web项目中容器对象只需要创建一次, 把容器对象放入到全局作用域ServletContext中。 -
怎么实现:
使用监听器 当全局作用域对象被创建时 创建容器 存入ServletContext -
监听器作用:
1)创建容器对象,执行 ApplicationContext ctx = new ClassPathXmlApplicationContext(“applicationContext.xml”);
2)把容器对象放入到ServletContext, ServletContext.setAttribute(key,ctx)
3)监听器可以自己创建,也可以使用框架中提供好的ContextLoaderListener
-
配置监听器目的:是创建容器对象,创建了之后就能把spring.xml配置文件中所有的对象都创建好。用户发起请求就可以直接使用对象了。
-
如何调用?
1)原本调用:即不使用监听器时
String config = "spring.xml"; ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
2)使用监听器后:
-
自己写的获取容器对象的方式
//查看源代码分析 String key = WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE; Object attr = getServletContext().getAttribute(key); if(attr != null){ ctx = (webApplicationContext)attr; }
-
框架提供的工具方法
//使用框架中的方法获取容器对象 ServletContxt sc = getServletContext(); WebApplicationContextUtils.getRequiredWebApplicationContext(sc);
6. 注解驱动
(与3.视图解析器同目录)
-
<!--
1.响应ajax请求,放回json
2.解决静态资源访问问题
-->
<mvc:annotation-driven/>
需要加约束,不加会报错annotation-driven" is not bound.
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"
7.属性配置文件
- 与spring.xml文件同级
jdbc.url=jdbc:mysql://localhost:3306/springdb
jdbc.username=root
jdbc.password=A5413216
jdbc.maxActive=20
- 在spring.xml文件中,既然调用属性配置文件,就要声明文件的位置。
<context:property-placeholder location="classpath:conf/jdbc.properties"/>
四. bug:
-
错误描述:网页404,/show.jsp文件未找到
原因:将show.jsp文件放入到了webapp包下的WEB-INF包中了。应该放入webapp包下就可以了,与index.jsp,WEB-INF包同级。将jsp文件放入到WEB-INF包中可以防止用户通过地址栏输入非法跳转下一个页面。在后面的讲解中就将show.jsp放入到该包中,但是doSome方法中的地址理应修改。
WEB-INF:是Java的WEB应用的安全目录。所谓安全就是客户端无法访问,只有服务端可以访问的目录。有时候,为了安全,可能需要把jsp文件放在WEB-INF目录下。
-
网页报错:
org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from class path resource [springmvc.xml]; nested exception is java.io.FileNotFoundException: class path resource [springmvc.xml] cannot be opened because it does not exist
HTTP状态 500 - 内部服务器错误
类型 异常报告
消息 Servlet[springmvc]的Servlet.init()引发异常
描述 服务器遇到一个意外的情况,阻止它完成请求。
**原因:**在编译后target目录下的classes目录下没有resources资源包下的springmvc.xml文件,复制粘贴后便可以运行成功
到底是为什么编译成这样不太清除
遗留问题:
- bug中的第二个问题,到底是为什么会变成那样。