原创声明:本文为作者原创,未经允许不得转载,经授权转载需注明作者和出处
本帖子介绍ssm框架之一的springmvc,网上的资料常常把它和struts进行对比,为了掌握一个框架,了解它的原理,知晓与它对等框架之间的区别和联系很有必要,这里提供一个分析springmvc和struts很好的一篇博客:http://blog.csdn.net/gstormspire/article/details/8239182
对于springmvc(也称之为Spring Web MVC),其整体工作流程我画了一个草图,如下
springmvc有两种配置方式,一种是基于springmvc.xml文件进行配置,一种是基于注解的配置,当然后者更广泛的被应用,本篇将介绍的是xml版配置,之后介绍注解版的配置。之所以不直接学习实用的注解配置,正是因为“学习”二字,这是一个过程,我习惯于从繁化简(当学习到最后我能吐槽一句原来这样更简单就说明我成功了)
图中的前端控制器即为 DispatcherServlet ,在web.xml中配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>MVC</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<!-- 注册控制器 -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:config/springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.mn</url-pattern>
</servlet-mapping>
</web-app>
welcome-file-list
是默认进入页面,即直接输入 “localhost:8080/项目名/” 就会加载的页面,默认名为index,在/WebContent
目录下
导入springmvc所需的jar包:http://pan.baidu.com/s/1kV39hC7
目前还未使用maven,所以直接下载jar包放入/WebContent/WEB-INF/lib
目录下即可
init-param
为选填,如果不写,则DispatcherServlet默认会去查找/WEB-INF/<servlet-name>-servlet.xml
文件,(例:我上诉的配置将会自动去查到springmvc-servlet.xml
)
如果配置了init-param
,则会根据param-value
去对应的目录下查找配置文件,并且可以自定义xml文件名称。
其中param-name
是固定名称,大小写敏感classpath:
表示根目录(与src同级)
如上诉配置,DispatcherServlet会去src/config下寻找springmvc.xml文件
(自定义的方式可以更好的统一管理配置文件,建议使用)
url-pattern
配置拦截器,即判断什么请求可以去访问action类。上诉配置是接受以.mn
为后缀的请求,也可以写成/*
,但是这样会接受所有的请求,包括html、jsp后缀,对于页面的请求我们是不需要到后台的,所以不建议该写法,拦截器可配置多个,重复写servlet-mapping
即可
Action类的形式有很多
可以是实现接口的类,可以是继承类,甚至可以是普通类
以实现Controller为例(这不是最好的方法)
package action;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
public class HelloWorldAction implements Controller{
@Override
public ModelAndView handleRequest(HttpServletRequest req,HttpServletResponse resp) throws Exception {
ModelAndView modelAndView=new ModelAndView();
modelAndView.addObject("msg","第一个springmvc项目!");
modelAndView.setViewName("/jsp/helloWorld.jsp");
return modelAndView;
}
}
addObject用于传值,setViewName指定返回的模型(注意,现在写的是真实路径)
<body>
${requestScope.msg}
</body>
这是JSP的EL表达式,不需要过多理解,只要知道是获取Action传递的值
<?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:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<!-- 注册Action处理类 -->
<bean name="/hw.mn" class="action.HelloWorldAction"></bean>
</beans>
这是最简单的配置,头信息固定不变,需要我们写的只有Action处理类,class表示处理类的全路径,name表示请求路径。
运行结果:
运行成功
在springmvc.xml中可以配置的有:
1.注册Action处理类(控制器)
2.映射器
3.适配器
4.视图解析器
有这么多,但是我们上面只写了一行处理类,由此可见,Action处理类是必写项,而其它的都是可选
完整版如下:
<bean name="/hw.mn" class="action.HelloWorldAction"></bean>
<!-- 映射器 BeanNameUrlHandlerMapping(其中之一)表示将上一行bean标签中的name属性当作url请求-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
</bean>
<!-- 适配器 SimpleControllerHandlerAdapter表示用于寻找HelloWorldAction类-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter">
</bean>
<!-- 视图解析器 InternalResourceViewResolver表示通过ModelAndView封装的视图名找到页面-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
</bean>
通过三种常见场景,理解一下它们
页面之间的跳转
不推荐配置拦截器的时候使用/*
,是因为当直接跳转页面请的时候,请求是不需要经过后台的,如果写成/*
会导致普通的跳转页面也要经过后台。这里就有一个问题需要注意的,当你要跳转的页面不在WEB-INF下的时候,可以直接在url上写上真实路径就能跳转。
例如:<a href="${pageContext.request.contextPath }/jsp/xxx.jsp">跳转到jsp文件夹下的页面</a>
前面部分是EL表达式获取当前路径,等价http://localhost:8080/springMVC
但是!如果你要请求的页面在WEB-INF下的话,出于安全考虑,这个设定就是不能通过url直接访问WEB-INF目录下的页面,不过,通过配置控制器
<bean name="/xxx.mn" class="org.springframework.web.servlet.mvc.ParameterizableViewController">
<property name="viewName" value="success"/>
</bean>
可以把.mn
请求通过 ParameterizableViewController
类转换成普通的页面之间跳转,包括对WEB-INF目录下页面的访问
之前的例子可以理解为一对一,一个请求就需要写一个Action处理类的bean,如果多个请求访问的是同一个Action类,则是如下写法:
<bean name="/hw1.mn" class="action.HelloWorldAction"></bean>
<bean name="/hw2.mn" class="action.HelloWorldAction"></bean>
<bean name="/hw2.mn" class="action.HelloWorldAction"></bean>
<!--映射器-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
优化后的代码:
<bean id="hwId" class="action.HelloWorldAction"></bean>
<!-- 映射器 -->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<!-- key表示请求路径 -->
<prop key="/hw1.mn">hwId</prop>
<prop key="/hw2.mn">hwId</prop>
<prop key="/hw3.mn">hwId</prop>
</props>
</property>
</bean>
此时注册Action处理类不是用name,而是用id,通过SimpleUrlHandlerMapping实现多个请求访问同一个Action
刚开始在Action类中setViewName方法写的是文件的真实路径,那如何使用逻辑路径定位到真实的页面路径呢
视图解析器就是做这一行的:
springmvc.xml新增配置:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
HelloWorld.java:
public ModelAndView handleRequest(HttpServletRequest req,HttpServletResponse resp) throws Exception {
ModelAndView modelAndView=new ModelAndView();
modelAndView.addObject("msg","第一个springmvc项目!");
modelAndView.setViewName("helloWorld");
return modelAndView;
}
此时会自动把helloWorld补全成/jsp/helloWorld.jsp
小技巧:
eclipse打开文件所在目录插件,使用Marketplace下载安装非常慢,这里提供出离线插件
http://pan.baidu.com/s/1geEqzXx