概述
MVC是现如今广泛应用的设计模式,在软件行业的应用非常广泛。所谓的MVC,具体为Model,View,Controller。用户的请求发给控制器,控制器根据请求的来源调用相应的Model组件完成业务逻辑,控制器根据Model返回的信息调用相应的View显示给用户。struts是MVC设计模式的具体应用,在经过人们群众广泛的实践后,已经成为了应用MVC设计模式的代表之作。笔者在培训期间学到了struts的奥妙所在,现梳理一番,加深记忆,也分享出来,希望得到大家的指教。
Step1
雏形
控制器是MVC的灵魂,它决定了数据的来与去,既然是灵魂,那么这个控制权当且仅当交给一个组件(中央集权)来管理,在我们的框架中,这个控制器名为ActionServlet,这个类继承自
HttpServlet,
用来接受用户请求并返回响应,既然所有的请求都交由ActionServlet来处理,我们需要在web.xml文件中配置一下,
<
servlet
>
<
servlet-name
>
ActionServlet
</
servlet-name
>
<
servlet-class
>
org.mystruts.action.ActionServlet
</
servlet-class
>
<
load-on-startup
>
1
</
load-on-startup
>
</
servlet
>
<
servlet-mapping
>
<
servlet-name
>
ActionServlet
</
servlet-name
>
<
url-pattern
>
*.action
</
url-pattern
>
</
servlet-mapping
>
这段配置说明了所有的.action请求都交由ActionServlet来处理。我们需要抽象一个用来代表所有对请求进行处理的类,这个类我们定义为Action
public
abstract
class
Action {
public
abstract
String execute(HttpServletRequest request,
HttpServletResponse response)
throws
Exception;
}
ActionServlet
根据用户的请求调用Action的子类完成业务逻辑处理,ActionServlet本身不处理请求,而是委派给对应的Action来处理,那么ActionServlet怎么知道哪些请求对应哪些Action呢?根据配置文件是一个比较好的解决方案,那么是属性文件呢,还是XML?我们选择XML,理由很简单,XML配置灵活且易于扩展,看看我们的配置信息怎么写:
<
action-mappings
>
<
action
path
=
"/test"
type
=
"test.TestAction"
>
<
forward
name
=
"success"
path
=
"/1.jsp" redirect=”true|false”
/>
</
action
>
</
action-mappings
>
aciton-mappings
是根元素,其中的每个action子元素代表了不同的请求调用哪个Action来处理,forward元素代表根据Action返回的信息决定调用哪个jsp组件完成显示。
在我们的ActionServlet中,我们需要根据这个配置文件分发请求,目前,XML的解析技术主要有Sax和dom,但是他们的处理方式都比较底层,我们选用apache的开源组件commons-digester解析XML,根据这个组件的需要,我们需要编写和xml中元素对应的类,即一个元素对应一个类,类的属性对应元素的属性,我们的类为ActionMappings、ActionMapping和ActionForward,分别对应action-mappings元素、action元素和forward元素
ActionMappings
public
class
ActionMappings {
private
Map<String, ActionMapping>
mappings
=
new
HashMap<String, ActionMapping>();
public
void
addActionMapping(ActionMapping mapping) {
mappings
.put(mapping.getPath(), mapping);
}
public
ActionMapping findActionMapping(String path) {
return
mappings
.get(path);
}
}
ActionMapping
public
class
ActionMapping {
private
String
path
;
private
String
type
;
private
Map<String, ActionForward>
forwards
=
new
HashMap<String, ActionForward>();
public
void
addActionForward(ActionForward forward) {
forwards
.put(forward.getName(), forward);
}
public
ActionForward findActionForward(String name) {
return
forwards
.get(name);
}
public
String getPath() {
return
path
;
}
public
void
setPath(String path) {
this
.
path
= path;
}
public
String getType() {
return
type
;
}
public
void
setType(String type) {
this
.
type
= type;
}
}
ActionForward
public
class
ActionForward {
private
String
name
;
private
String
path
;
private
boolean
redirect
=
false
;
public
String getName() {
return
name
;
}
public
void
setName(String name) {
this
.
name
= name;
}
public
String getPath() {
return
path
;
}
public
void
setPath(String path) {
this
.
path
= path;
}
public
boolean
isRedirect() {
return
redirect
;
}
public
void
setRedirect(
boolean
redirect) {
this
.
redirect
= redirect;
}
}
另外,我们需要在digester规定的规则文件中定义一些规则,
rule.xml
<?
xml
version
=
'1.0'
encoding
=
'UTF-8'
?>
<!--
这个xml文件是由commons-digester定义用于告诉digester组件
自定义的配置文件和配置对象之间的关系,commons-digester组件了解了这
个关系后就可以将配置文件中的信息转换为配置对象
-->
<
digester-rules
>
<!-- ActionMappings -->
<
pattern
value
=
"action-mappings"
>
<
pattern
value
=
"action"
>
<!--
每碰到一个action元素,就创建指定类的对象-->
<
object-create-rule
classname
=
"org.mystruts.config.ActionMapping"
/>
<!--
对象创建后,调用指定的方法,
将其加入它上一级元素所对应的对象
-->
<
set-next-rule
methodname
=
"addActionMapping"
/>
<!--
将action元素的各个属性按照相同的名称
赋值给刚刚创建的ActionMapping对象
-->
<
set-properties-rule
/>
<
pattern
value
=
"forward"
>
<
object-create-rule
classname
=
"org.mystruts.config.ActionForward"
/>
<
set-next-rule
methodname
=
"addActionForward"
/>
<
set-properties-rule
/>
</
pattern
>
</
pattern
>
</
pattern
>
</
digester-rules
>
在我们的ActionServlet中,我们只需调用digester组件的一些api就可以将xml文件的信息保存到内存中,代码为
Digester digester = DigesterLoader.createDigester(ActionServlet.
class
.getClassLoader().getResource(
"org/mystruts/action/rule.xml"
));
mappings
=
new
ActionMappings();//mappings
为ActionServlet类的成员变量
digester.push(
mappings
);
try
{
digester.parse(ActionServlet.
class
.getClassLoader()
.getResourceAsStream(
"mystruts.xml"
));
}
catch
(IOException e) {
throw
new
IOException(e.getMessage());
}
catch
(SAXException e) {
throw
new
SAXException(e.getMessage());
}
在actionServlet的service方法中,我们先获得用户请求的地址,然后截取地址的一部分,到mappings对象中找对应的Action,由这个Action处理请求,ActionServlet根据Action返回的信息再到mapping中查找对应的ActionForward,根据redirect属性,决定是转发还是重定向。
至此,雏形已经产生。我们暂且命名为mystruts1.0版本。
转载于:https://blog.51cto.com/robbietree/288400