springmvc框架由DispatchServlet,handlerMapping,handlerAdapter,和视图解析器组成
springmvc框架业务逻辑
导入maven包的网址——http://mvnrepository.com/
maven中如果只搭建springmvc,只需要在pom.xml中导入两个包,spring-mvc和spring-webmvc
这里说一下,新建的maven war项目会报错,因为webapp下缺少WEB-INF目录和web.xml文件,需要手动添加
导入包
4.0.0
com.test
springmvc0815
0.0.1-SNAPSHOT
war
4.1.6.RELEASE
org.springframework
spring-context
${spring.version}
org.springframework
spring-webmvc
${spring.version}
spring包不管用那个版本的一定要同一版本好,此处我做了版本管理,方便以后修改spring版本号
配置Servlet有两种方法,配xml或者配webservlet注解,但是此处DispatchServlet为maven提供的jar包,如果要加注解,则需要修改源码重新编译,所以此处我们选择配置xml文件。
servlet为单实例,多线程,对象是在首次访问的时候创建出来的,也就是说第一个访问的人,速度要慢一些,为了提高性能,我们要让他在服务器启动的时候就创建对象
添加
springmvc
org.springframework.web.servlet.DispatcherServlet
1
springmvc
/
启动,会发现控制台报错
org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from ServletContext resource [/WEB-INF/springmvc-servlet.xml]; nested exception is java.io.FileNotFoundException: Could not open ServletContext resource [/WEB-INF/springmvc-servlet.xml]
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:344)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:304)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:181)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:217)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:188)
at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:125)
at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:94)
at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:129)
at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:537)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:452)
at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:663)
at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:629)
at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:677)
at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:548)
at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:489)
at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:136)
at javax.servlet.GenericServlet.init(GenericServlet.java:158)
at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1188)
at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1132)
at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1021)
at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:5085)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5397)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1410)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1400)
at java.util.concurrent.FutureTask.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Caused by: java.io.FileNotFoundException: Could not open ServletContext resource [/WEB-INF/springmvc-servlet.xml]
at org.springframework.web.context.support.ServletContextResource.getInputStream(ServletContextResource.java:141)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:330)
... 28 more
Could not open ServletContext resource [/WEB-INF/springmvc-servlet.xml],找不到文件
我们回过头来看springmvc的底层原理,第一步用户发送请求给dispatchservlet,dispatchservlet拿url去handlermapping寻找,前提是handlermapping里面要有内容,那我们考虑如何往handlermapping中放东西
框架在于可供所有人使用,所以框架的搭建者不知道你会向handler mapping中放什么内容,这个时候,他都去了一个配置文件,spring-servlet.xml,使用框架的人需要往handlermapping中放什么,自己去配置文件中写,而spring-servlet.xml默认放在/WEB-INF目录下
那么文件名和路径能不能修改,我们来看dispatchservlet源码
/**
* Suffix for WebApplicationContext namespaces. If a servlet of this class is
* given the name "test" in a context, the namespace used by the servlet will
* resolve to "test-servlet".
*/
public static final String DEFAULT_NAMESPACE_SUFFIX = "-servlet";
/**
* Set a custom namespace for this servlet,
* to be used for building a default context config location.
*/
public void setNamespace(String namespace) {
this.namespace = namespace;
}
/**
* Return the namespace for this servlet, falling back to default scheme if
* no custom namespace was set: e.g. "test-servlet" for a servlet named "test".
*/
public String getNamespace() {
return (this.namespace != null ? this.namespace : getServletName() + DEFAULT_NAMESPACE_SUFFIX);
}
如果namespace为空,则配置文件名为servlet-name加后缀"-servlet"
如果namespace不为空,则配置文件名为namespace加后缀"-servlet"
所以我们想修改名字需要配namespace
springmvc
org.springframework.web.servlet.DispatcherServlet
namespace
springmvc
1
springmvc
/
load-on-startup一定要配在servlet节点的最后一行,不然会报错
首先,在WEB-INF下创建springmvc.xml,要带spring的命名空间
package com.test.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class MyController {
@RequestMapping("/index")
public String index(){
return "abcd";
}
}
此时我们依赖jstl,需要在pox.xml中导入jstl包
javax.servlet
jstl
1.2
关于前缀和后缀:接着上面的流程,我们拿到返回值/abcd,handlerAdapter将返回值(/abcd)给到视图解析器后,会把前缀(/WEB-INF/pages)放到返回值前,把后缀(.jsp)放到返回值后,以webapp为根目录去找这个文件(/WEB-INF/pages/abcd.jsp),进行转发
使用modelandview或者modelmap
@Controller
public class MyController {
//方法1
@RequestMapping("/index")
public String list(ModelMap map){
map.addAttribute("attributeName", attributeValue);
}
//方法2
@RequestMapping("/index2")
public ModelAndView list(){
ModelAndView modelAndView = new ModelAndView("abcd");//abcd为要转发的页面
modelAndView.addObject("attributeName", attributeValue);
return modelAndView;
}
}
modelmap底层仍会封装出modelandview
另:@RequestMapping("index")默认为value属性,get和post方法都会进入此方法
@RequestMapping(value="/index2",method=RequestMethod.POST)只会接受post方法
@RequestMapping(value="/index2",method=RequestMethod.GET)只会接受get方法
//方法1
@RequestMapping(value="/index2",method=RequestMethod.POST)
public String index(String name){
System.out.println(name);//只需要与前端那么属性值一样即可接收
return "abcd";
}
//方法2
//假设pojo中存在Student类型的对象,具有name,sex,age三个属性
@RequestMapping(value="/index2",method=RequestMethod.POST)
public String index(Student student){
System.out.println(student);//只要pojo对象的属性名,与前端页面的属性名一致,直接用对象接受即可
return "abcd";
}