Spring 2.0开始对JSR168 Portlet支持,其的MVC模式区别于WW/Struts2,重要的区别就是WW/Struts2对portlet的封装是统一于Servlet的封装,即把Portlet的RequestRender和RequestAction的生命周期封装为RequestAction,而Spring Portlet MVC保留了这特性。Spring Portlet MVC的模式与Spring MVC一样,但是是对Portlet重新开发,故应用Spring Portlet MVC与Spring MVC是一样的,具体注入的类不一样。
在这篇文章中,我会结合Spring和Hibernate开发实现一个基于联系人(Contact)数据对象的增、删、改功能;由于这篇文章重点讲述的是Portlet MVC,对于Spring+Hibernate的配置内容不作重点,请读者参考相关资料。这里只是个简单的例子,在实际应用中,还要读者根据实际情况自行修改适应实际的应用。由于在我上一篇文章中已经讲述过如何开发部署简单的Spring Portlet MVC的例子,在这里只讲述一些重要的细节,其余内容的请参考文章后面的例子原码。
数据模型
联系人Contact.,它包括名字,邮件地址等信息,如下所示: Contact.java public class Contact extends BaseEntity{ private String firstName; private String lastName; private String email; private String phoneNumber; …... 这个Contact对象是继承了BaseEntity,它是封装所有数据模型的唯一标识id的抽象类,把id抽象出来作为重用元素。 BaseEntity.java public abstract class BaseEntity implements IdEntity { private String contactId; ……. 如上所示,它实现一个通用的id存取接口。
DAO层操作
DAO层的接口,它负责数据对象的增删改的功能实现。
接口代码如下:
IStorage.java public interface IStorage {
//增加
IdEntity doCreateEntity( IdEntity object );
//修改
IdEntity doUpdateEntity( IdEntity object );
//删除
void doDeleteEntity( IdEntity id );
//凭ID找数据对象
Object doFindEntityById( Class clazz, IdEntity object );
//找出某个数据对象的实体
Collection doFindAllEntities( Class clazz );
从上面可以看到这个接口是基于数据对象的增删改功能,其的实际类SpringStorage.java是应用Spring封装的Hiberante的操作接口来实现,详细内容请参考源码。
服务层接口
服务层接口是Spring层(业务接口)的实现。接口类IContactService代码如下,它是DAO操作的延伸,接口的实现详见例子。
public interface IContactService {
Contact createContact( Contact contact );
Contact updateContact( Contact contact );
void deleteContact( Contact contact );
Contact findContactById( IdEntity object );
List findAllContacts(); }
Portlet层
Portlet层的代码简单,但是理清增删改的逻辑非常重要。
1) 显示列表SelectController.java
显示列表,是通过服务接口取出所有数据,再跟跳转到页面上显示;跳转到显示页面是由返回ModelAndView对象控制到达哪个页面。
SelectController.java
public class SelectController implements Controller{
private static Log log = LogFactory.getLog(SelectController.class);
private IContactService contactService;
public void setContactService(IContactService contactService)
{ this.contactService = contactService; }
public IContactService getContactService() {
return contactService;
}
显示列表Portlet Action实现org.springframework.web.portlet.mvc.Controller接口,在Servlet支持也有相应的接口。上面的代码只是设置IoC容器注入服务类。
public ModelAndView handleRenderRequest(RenderRequest renderRequest,
RenderResponse response) throws Exception {
ModelAndView modelAndView = new ModelAndView("list");
modelAndView.addObject("contactList", contactService.findAllContacts());
return modelAndView;
}
上面代码是从服务接口取出所有数据,再跳转到list.jsp页面。 在list.jsp里取得相应的数据信息显示,这个和Sping MVC是完全一致,但是在显示页面了,有三个跳转:增加跳转,修改跳转,删除跳转。
增加跳转页面代码:
<a href='<portlet:renderURL>
<portlet:param name="action" value="insert"/>
</portlet:renderURL>'>Add Contact</a>
上面代码说明这个链接是跳view里面的action为insert,这个action的跳转在配置里定义,这里跳转到增加数据的页面。
修改跳转页面代码:
<a href='<portlet:renderURL>
<portlet:param name="action" value="update"/>
<portlet:param name="contactId">
<jsp:attribute name="value">
<c:out value="${contact.contactId}"/>
</jsp:attribute>
</portlet:param>
</portlet:renderURL>
'><c:out value="${contact.contactId}"/></a>
上面代码是说明根据对象的id作为参数跳转到修改的控制器,这里注意的是应用<jsp:attribute>标记来传递参数,而不是servlet的直接追加参数,portlet里的URL和参数是经过编码处理的。
删除跳转页面代码:
<a href='<portlet:actionURL>
<portlet:param name="action" value="delete"/>
<portlet:param name="contactId">
<jsp:attribute name="value">
<c:out value="${contact.contactId}"/>
</jsp:attribute>
</portlet:param>
</portlet:actionURL>
'>Remove</a>
是通过传入数据对象的id跳转到删除对象的控制器。
页面效果如下:
2)增加联系人InsertController.java
增加数据是过程:当控制器接到renderrequest时,控制器会跳转到form页面,这个页面会在配置文件里作配置;当控制器接到renderaction时,则会调用服务接口作保存操作。
跳转到form的配置:
<bean id="insertController" class="com.yds.portal.portlet.InsertController">
<property name="contactService" ref="contactService"></property>
<property name="commandName" value="contact"/>
<property name="commandClass" value="com.gdcn.portal.contact.model.Contact" />
<property name="formView" value="insert"></property>
<property name="successView" value="list"></property>
</bean>
这是增加控制器的配置,其中formView属性就是说明跳转到form页面insert.jsp,而successView是requestaction成功处理后的跳转。
增加保存的代码:
protected void onSubmitAction(ActionRequest request, ActionResponse response, Object command, BindException errors) throws Exception {
Contact contact =(Contact)command;
contactService.createContact(contact);
response.setRenderParameter("action", "list");
}
当form页面提交后,通过command对象取得页面的对象,从而保存。上面的onSubmitAction方面是监听页面的form的submit操作,如果要作具体的那个submit(页面有保存和取消按钮),则可以重写方法。效果图如下:
3) 修改联系人UpdateController.java
修改与增加一样有两个操作,跳转到form页面和作更的保存操作。保存操作和增加的一样不作介绍,这里只说明下跳转到form页面。跳转到form页面前则要得到要修改的目标对象,通过取得页面传过来的参数,调用服务方法获取目标对象,再跳转到form页面。从列表跳转到修改页面作取得数据对象的代码如下:
protected Object formBackingObject(PortletRequest request) throws Exception {
Contact updateContact =(Contact)super.formBackingObject(request);
if(updateContact.getContactId() == null){
String contactId = request.getParameter("contactId");
updateContact.setContactId(contactId);
updateContact = contactService.findContactById(updateContact);
}
return updateContact;
}
效果图如下:
4)删除联系人DeleteController.java
删除只是简单的接收到要删除对象的id,调用服务取得对象,再作删除操作。这里过程的细节在上面已经有所述。其效果如下:
Spring Portlet项目的配置
在项目中spring的配置在两个地方读入,一是servlet容器时,即web.xml;另一个是配置portlet.xml里。
在Servlet容器里读取时,设置把spring对portlet的全部配置,服务器设置,Hibernate层设置等等信息读入到servlet容器。
Web.xml中
context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/springconfig/applicationContext*.xml</param-value>
</context-param>
设置读取/WEB-INF/springconfig/目录下,以applicationContext开头的xml配置文件,在这个项目里有:
applicationContext.xml 全局的配置信息
applicationContext-Services.xml 服务层的配置信息
applicationContext-hibernate.xml Hibernate的配置信息
在applicationContext.xml里设置jsp页面的目录和view的一些信息;applicationContext-Services.xml是配置服务类的信息;applicationContext-hibernate.xml是配置事务,DAO,数据库配置等等信息。
在portlet.xml中,是配置portlet项目的控制器信息:
<portlet-class>org.springframework.web.portlet.DispatcherPortlet</portlet-class>
<init-param>
<name>contextConfigLocation</name>
<value>/WEB-INF/springconfig/contact-portlet.xml</value>
</init-param>
在当前的portlet中读取contact-portlet.xml配置,这是一个portlet的配置,项目中配置多个portlet时,可以配置多个。
Contact-portlet.xml中配置各个控制器和模式:
<bean id="selectController" … 列表控制器
<bean id="insertController"… 插入控制器
<bean id="updateController" … 修改控制器
<bean id="deleteController"…. 删除控制器
<bean id="portletModeParameterHandlerMapping"… 在view模式中配置各个控制器,前面的key为视图标识。
<bean id="portletModeHandlerMapping"… porttlet的模式映射可以配置view,edit,help等各种模式的控制器。
综上所述,说明了基于spring portlet mvc的crud例子构建,上面对外WEB三层的概要,代码作了说明,也对portlet项目的配置作了介绍。关于spring在portlet的应用还有很多细节,读者在实际应用中获得更多的经验,这里只作下介绍,希望有利于各位应用到实际项目中去。
以下是本例子的项目及源码:
SpringInfrastructurePortlet.part1.rar(977 KB)
SpringInfrastructurePortlet.part2.rar(977 KB)
SpringInfrastructurePortlet.part3.rar(977 KB)
SpringInfrastructurePortlet.part4.rar(977 KB)
SpringInfrastructurePortlet.part5.rar(977 KB)
SpringInfrastructurePortlet.part6.rar(977 KB)
SpringInfrastructurePortlet.part7.rar(749 KB)