【IT168 技术文档】
在上篇文章中,我们已经从较高层解释了整个框架的结构,请求流程的基础,配置方式和Struts2和Struts1的不同之处。了解这些后从Struts 应用 迁移到 Struts 2 不再是难事。
在这篇文章中,我们将会更详细地讲述如何由Struts 的action转为Struts 2的action。
一个应用的例子
这个例子选择了大家都熟悉的 - weblog. 简单地介绍下这例子的功能需求:
- 增加一个新的日志
- 察看一个日志
- 修改一个日志
- 删除一个日志
- 列出所有日至
业务逻辑类在Struts 和 Struts2 应用都是可共用的。如:
public class BlogService ...{ private static List<Blog> blogs = new ArrayList<Blog>(); public List<Blog> list() ...{ ... } public Blog create(Blog blog) ...{ ... } public void update(Blog blog) ...{ ... } public void delete(int id) ...{ ... } public Blog findById(int id) ...{ ... } }
BlogService 只是个简单的业务逻辑类,并不是接口,Struts 和 Struts2 的action皆可调用其实例。虽然这样设计在实际项目中会带来不必要的耦合,但我们的例子只是集中在讨论web层上,所以无关重要。
QUOTE:
工具箱: 在第一篇文章中,我们谈论了在Struts2 actions中的依赖注入的接口注入方式。这个是servlet 相关类(HttpServletRequest, HttpServletResponse, PrincipalProxy, 等.)的主要注入方式,但这并不是唯一的方式。
Struts2 可以使用Spring框架作为默认的容器时,依赖注入的setter方法就可用了。通过在action中加入setter方法(如下演示), Struts2 框架将能从Spring框架中获得正确的信息,并通过setter加载在action中。
public void setBlogService(BlogService service) ...{
this.blogService = service;
}
和接口注入方式类似,我们需要一个拦截器来帮助我们完成任务,这就是 ActionAutowiringInterceptor 拦截器。这样我们的业务逻辑类就通过Spring框架管理自动在action被调用之前注入到Struts2得action中。有多种的配置参数(如by name, by type 或 automatically)可供选择,可以让对象和setter匹配的注入的方式根据你的需要而定。
Struts 应用中的代码
我们首先从Struts讲起。在Struts中,最普遍的做法是,对于每个需求用例(如save,update,remove,list)来说都会有对应的action类,同时也会有相应的action form类。在我们的应用中的这个方式或许不是非常好的的实现方式(其他的解决方案包括使用dynamic form或者使用request来分发action),但我们例子中的做法是所有Struts开发者最熟悉的一种形式。了解了这种简单的实现方法,你有能力在迁移到Struts2时,使用更为优秀的方法。
在第一篇文章中我们谈过Struts 和 Struts2 中action的区别。现在我们从UML中再次看看他们的差别。一般来说form在Struts action中的表现形式是: 下图 image1.jpg
这action form将会在多个action中使用,让我们来看看它:
public class BlogForm extends ActionForm ...{ private String id; private String title; private String entry; private String created; // public setters and getters for all properties }
如UML中展示的那样,其中一个限制就是必须继承ActionForm类,另外一个限制就是form中所有属性都必须是String类型,所以所有的getter和setter都必须只能接受String参数和返回String结果。
然后我们来看看action。我们这个例子中的action有view, create 和 update action。
The View Action:
The Create Action:
public class ViewBlogAction extends Action ...{ public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception ...{ BlogService service = new BlogService(); String id = request.getParameter("id"); request.setAttribute("blog",service.findById(Integer.parseInt(id))); return (mapping.findForward("success")); } } public class SaveBlogEntryAction extends Action ...{ public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception ...{ BlogService service = new BlogService(); BlogForm blogForm = (BlogForm) form; Blog blog = new Blog(); BeanUtils.copyProperties( blog, blogForm ); service.create( blog ); return (mapping.findForward("success")); } } public class UpdateBlogEntryAction extends Action ...{ public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception ...{ BlogService service = new BlogService(); BlogForm blogForm = (BlogForm) form; Blog blog = service.findById( Integer.parseInt(blogForm.getId())); BeanUtils.copyProperties( blog, blogForm ); service.update( blog ); request.setAttribute("blog",blog); return (mapping.findForward("success")); } }
这三个action都跟随着同一个模式:
产生一个新的业务逻辑对象实例 - 如前面所提到的,我们使用最直接的方式在action中使用业务逻辑对象,这表示在每个action中都会产生新的业务逻辑对象实例。
从请求中获得数据 - 这是两种形式之一。在view action中,"id"是从HttpServletRequest 对象中直接获取的。而在create 和 update action 中,则从ActionForm 中取值。ActionForm 与 HttpServletRequest 的调用方式其实很相似,唯一不同的ActionForm 是bean的从field中取值。
调用业务逻辑- 现在开始生成调用业务逻辑所需的参数并调用逻辑。如果参数(在view action中)是一个简单对象类型,则转换值时会自动转为正确的类型(如从String转到Integer)。如果参数是复杂的对象类型,,则ActionForm 需要通过BeanUtil 来帮忙转成相应的对象。
设定返回的数据 - 如果需要把数据返回显示给用户,那则要把这个数据设在HttpServletRequest 的attribute 中返回。返回一个 ActionForward - 所有 Struts action的最后都需要找到并返回其相应的 ActionForward 对象.
最后的两个action,remove和list action, 只有很少的差别。remove action如下所示,没有用BlogForm类. 通过从request的attribute中获取"id"(和view action相似),就能调用业务逻辑完成其需要的工作。在下面我们介绍配置时,你可以看到它并没有返回任何数据,因为它的"success"返回结果其实是执行remove后再执行了list action来返回信息的。
public class RemoveBlogEntryAction extends Action ...{ public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception ...{ BlogService service = new BlogService(); String id = request.getParameter("id"); service.delete(Integer.parseInt(id)); return (mapping.findForward("success")); } }
list action并不需要任何的用户输入,它只是简单地调用了业务逻辑的无参方法,同时返回所有的Blog对象。
public class ListBlogsAction extends Action ...{ public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception ...{ BlogService service = new BlogService(); request.setAttribute("bloglist",service.list()); return (mapping.findForward("success")); } }