1 MVC概念
1.1 什么是MVC模式
MVC全称是Model View Controller,模型(Model) - 视图(View) - 控制器(Controller)。MVC起源于20世纪70年代后期,它开始是由Trygve Reenskaug为Smalltalk平台开发的框架,现成为了一种流行的模式。
Model(模型):模型是信息的载体,包括业务数据。
View(视图):视图是用户看到并与之交互的界面。
Controller(控制器):从视图中接收数据,调用业务逻辑处理数据,并将获取的数据对象返回到相应的视图中。
由图可见:
1)View依赖Model,但是Model不依赖View。
从模型中分离出表现,这样可以使开发人员更加专注,因为开发视图的人,更加关注如何布局,美观,界面操作友好性,而开发模型的人,才更关注业务逻辑,同数据库的交互等等,这样可以将两者开发人员分离开来,使开发人员更加专注于某一方面,做起来才更专业。毕竟人无完人,上帝给了你一个才能的同时也关闭了另一份才能,所以做人嘛,千万别拿自己的短处去PK别人的长处,想弥补自己的缺点去追赶别人,其实只要充分发挥自己的长处,将之发挥到极致,才能与众不同、出类拔萃。
另外使系统更加松耦合,可以使用同一套模型,切换不同的View去展示,比如PC端、手机端,另外可以在不修改另外两层的情况下替换Model,这个跟分层模式一样,同分层不同的是分层架构中不相邻的层不允许相互依赖和调用,而在MVC中View要依赖Model。
2)Contoller充当一个中转站。从View中接收参数,调用业务逻辑,生成Model,然后将Model和请求转发到相应的View中。
1.2 J2EE领域的MVC
Model:业务对象Bean。
View:通常由JSP、Servlet或者XSLT等实现。
Controller:通常是一个Controller Servlet,这个一般会借助于框架实现例如Spring mvc的Controller,Struts mvc的Action等。
2 Spring MVC 之helloworld
仍然是国际惯例,helloworld:
因为这个需要应用服务器,所以要遵循servlet规范目录,代码的目录如下图所示:
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<display-name>spring mvc helloworld</display-name>
<description>spring mvc helloworld</description>
<!--配置controller的控制器,可以用逗号分隔配置多个 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/hello-servlet.xml</param-value>
</context-param>
<listener>
<!--配置上下文载入器,用于载入contextConfigLocation配置的配置文件 --> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--配置DispatcherServlet,这是Spring mvc的核心,匹配的url由他处置 -->
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<!--*.htm均指向DispatcherServlet,当然可以配置成*.do,等,也可以配置多个-->
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
</web-app>
控制器, HelloController:
public class HelloController implements Controller {
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println("hello controller");
return new ModelAndView("jsp/hello.jsp");
}
}
配置控制器,hello-servlet.xml:
注意其中的bean配置的是name属性,而不是id,因为id不可以有"/"
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean name="/hello.htm" class="org.frank1234.spring.mvc.HelloController">
</bean>
</beans>
JSP页面,hello.jsp:
<html>
<body>
<h1>hello frank1234 ,begin spring mvc</h1>
</body>
</html>
启动tomcat,浏览器中输入:
http://localhost:8088/hello/hello.htm ,输出如下图所示:
3 Spring MVC
3.1 请求的生命周期
结合helloworld程序解释步骤:
1)用户请求URL http://localhost:8088/hello/hello.htm,由于在web.xml配置了匹配规则,符合匹配规则,所以请求会交到DispatcherServlet中。
2)DispatcherServlet会根据默认的映射处理器BeanNameUrlHandlerMapping,根据hello-servlet中的配置信息找到HelloController。
3)DispatcherServlet将请求分发给HelloController.
4)HelloController返回一个ModelAndView对象,
5)由于helloworld程序没有使用视图解析器ViewResolver,所以就没有步骤5。
6)将请求导向"jsp/hello.jsp",显示页面。
3.2 控制器
1)简单控制器:
helloworld使用的就是简单控制器。
实现Controller接口或者继承AbstractController都属于简单控制器。
只是实现Controller接口要实现方法:
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
继承AbstractController要实现方法:
public ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
2)命令控制器
使用命名控制器可以将请求的参数自动绑定到命令对象中,类似于struts的ActionForm,只是Spring的命令对象不需要继承Spring的类。
代码示例:
public class HelloCommandController extends AbstractCommandController {
public HelloCommandController(){
setCommandClass(HelloCommand.class);
}
public ModelAndView handle(HttpServletRequest request,HttpServletResponse response,Object command,BindException errors) throws Exception{
HelloCommand helloCommand = (HelloCommand)command;
//xxxx
return new ModelAndView("jsp/hello.jsp");
}
}
3)多动作控制器
上面这种一个url就得对应一个Controller,如果url很多的话,就会造成大量的Controller类,如果想某一类url都请求同一个Controller,然后每个url请求Controller中的某个方法的话,可以使用Spring的MultiActionController,这个类似于Struts的DispatchAction。
代码示例:
HelloMultiActionController类:
public class HelloMultiActionController extends MultiActionController {
public ModelAndView sayHello(HttpServletRequest request,HttpServletResponse response){
return null;
}
public ModelAndView sayGoodbye(HttpServletRequest request,HttpServletResponse response){
return null;
}
}
hello-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="paramResolver"
class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver">
<property name="paramName">
<value>method</value>
</property>
</bean>
<bean name="/hello.htm"
class="org.frank1234.spring.mvc.HelloMultiActionController">
<property name="methodNameResolver">
<ref bean="paramResolver" />
</property>
</bean>
</beans>
这样如果http://localhost:8088/hello/hello.htm?method=sayHello
就会请求到HelloMultiActionController中的sayHello()方法。
另外,hello-servlet.xml还可以这么配置:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="paramResolver"
class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver">
<property name="paramName">
<value>method</value>
</property>
</bean>
<bean name="/hello.htm"
class="org.springframework.web.servlet.mvc.multiaction.MultiActionController">
<property name="methodNameResolver">
<ref bean="paramResolver" />
</property>
<property name="delegate">
<ref bean="login_delegate" />
</property>
</bean>
<bean id="login_delegate"
class="org.frank1234.spring.mvc.HelloMultiActionController" />
</beans>
这样类HelloMultiActionController,就不用继承MultiActionController了,直接写成如下就可以了:
public class HelloMultiActionController {
public ModelAndView sayHello(HttpServletRequest request,HttpServletResponse response){
return null;
}
public ModelAndView sayGoodbye(HttpServletRequest request,HttpServletResponse response){
return null;
}
}
4)FormController
我觉得校验用js处理更合适,这样可以减轻服务器端的压力。
4 Struts2 MVC之 helloworld
代码目录结构如下:
struts2依赖的jar包列表:
web.xml配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<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_3_1.xsd"
version="3.1">
<display-name>Struts 2 demo</display-name>
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
如果filter-class配置成:org.apache.struts2.dispatcher.FilterDispatcher
会显示这个FilterDispatcher已过期。
struts.xml配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<!-- 定义成true可以看到日志输出,生产环境下要关闭-->
<constant name="struts.devMode" value="true" />
<package name="helloworld" extends="struts-default">
<action name="hello"
class="org.frank1234.struts2.helloworld.HelloWorldAction"
method="go">
<result name="success">/jsp/helloworld.jsp</result>
</action>
</package>
</struts>
其中的method="go"可以随便命名,只要和HelloWorldAction中的方法名对应就OK了。
HelloWorldAction类:
public class HelloWorldAction {
private String name;
public String go() throws Exception {
System.out.println("helloworldaction");
setName("frank1234");
return "success";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
连HttpServletRequest对象和HttpServletResponse对象都不需要啦,爽歪歪啊。
helloworld.jsp:
<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>Hello World struts2</title>
</head>
<body>
<h1> Hello World, <s:property value="name"/></h1>
</body>
</html>
启动tomcat,浏览器中输入:
http://localhost:8088/hello/hello.action
不加.action效果一样。
5 Spring MVC vs Struts MVC
Struts1和Struts2有较大的不同,本文说的主要是Struts2的MVC,Struts2是从Webwork发展而来的。Struts1太老了,搞技术的应该喜新厌旧,关注新技术。
1)从web.xml配置可以看出Spring基于Servlet,Struts2基于Filter机制。
2)用Spring mvc的话,使用Spring的IoC和AOP会更容易些。
3)Struts2省去了HttpServletRequest和HttpServletResponse对象,并且不依赖任何Struts2的类,这样更容易测试,更符合可测试性和松耦合这两个核心价值观。
4)Struts2提供的前台taglib更多一些,不过笔者更倾向于使用JSTL。
5)Spring的Controller是单例的,Struts2每次都产生新的实例,这样需要注意Spring的实例变量的线程安全性。
6)总体感受,都很优秀,由于了解的不深入,感觉struts2更简练一些。偶觉得团队用哪个用的熟就可以选择哪个,因为对于开发来说,难的是业务逻辑。
《Spring in action》
《企业应用架构模式》
http://baike.baidu.com/link?url=1KYanQ3dwZX0yOu-5_GVGn9pCjMWGgEBQ9Zg3PiB_yNL3xgKXpzduLJNYEoPHxQE0InNip03woCdOBrtRmRUDDyKRWn9_y7JaaNX-Y8pSJm6_cKGaz7ierPjejZ6jDMOHQ_6P5JleQpJ9V8tBeYKSVRgtRCQPAwcshn17PORY3SIdqmubW8FNCawXdRi2rZfBPY1lF15_6Q-V8UGXDxtm_
http://xp9802.iteye.com/blog/1214256
http://zh.wikipedia.org/zh/MVC
http://www.ruanyifeng.com/blog/2007/11/mvc.html
http://blog.csdn.net/wanghuan203/article/details/8623048
http://developer.51cto.com/art/200906/130473.htm
http://blog.csdn.net/qiulongtianshi/article/details/7776694
http://wuquanyin1011.iteye.com/blog/693364
http://blog.csdn.net/gstormspire/article/details/8239182
http://www.yiibai.com/struts_2/struts_examples.html