Portlet的简单认识
- Portlet不能够想Spring一样直接经由HttpServletRequest指向相对路径(如:action="/SpringDuty/sign.jsp")将页面表单信息传给
指定页面或者Controller,而是用另一种写法经由指定的Action转向(如:action"<portlet:actionURL> <portlet:param name='action' value='coming'/></portlet:actionURL>")。(关于这句语句下会面有说明) - Portlet有自己定义的Request,我使用到了两种:ActionRequest*、*RenderRequest。
- ActionRequest:它的作用与HttpServletRequest相同,将当前表单对象传给转向对象。
- RenderRequest:在门户系统中,Portlet之间的共享信息是放在RenderRequest中,这样可以在单点登陆后每个Portlet即可在相应权限下获取所需的信息(如用户信息)
Spring转Portlet
- Portlet和Spring一样,也有自己的转发器org.springframework.web.portlet.DispatcherPortlet,它负责将获得的Action转发给相应处理。
- portlet根据自己的转发器与当前Portlet的状态会跳转到相应页面,大致流程是:
- portlet会根据配置信息,首先找到View或者经由Controller跳转到View
- 当进行相应动作时,portlet根据当前的状态(View,edit,help)跳转到相应View或者Controller
- 其它过程与Spring类似
如何获得RenderRequest
- 为了获得RenderRequest,可以首先让Portlet经由一个自己做的DispatcherController通过
protected ModelAndView handleRenderRequestInternal(RenderRequest arg0, RenderResponse arg1)方法来返回一个ModelAndView,
其中ModelAndView返回一个Map对象,Map中放入RenderRequest对象arg0和RenderResponse对象arg1,View是需要呈现的首页,这样,首页就能获取RenderRequest了。
Spring转Portlet过程举例
首先,请先下载一个Spring和Spring-portlet的源码,比较一下
下载附件
Web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://Java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<servlet>
<servlet-name>ViewRendererServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.ViewRendererServlet</servlet-class>
<load-on-startup>3</load-on-startup>
</servlet>
<servlet>
<servlet-name>ViewRendererServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.ViewRendererServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>searchModule</servlet-name>
<display-name>search</display-name>
<description>please search</description>
<servlet-class>org.apache.pluto.core.PortletServlet</servlet-class>
<init-param>
<param-name>portlet-class</param-name>
<param-value>org.springframework.web.portlet.DispatcherPortlet</param-value>
</init-param>
<init-param>
<param-name>portlet-guid</param-name>
<param-value>DSEPortletDemo.searchModule</param-value>
//注意:DSEPortletDemo为项目名称,searchModule为portlet.xml中对应的portlet-name
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>ViewRendererServlet</servlet-name>
<url-pattern>/WEB-INF/servlet/view</url-pattern>
</servlet-mapping>
</web-app>
<%@ taglib prefix="portlet" uri="http://java.sun.com/portlet" %> |
² 为了使其解析EL语句,必须加入:
<%@ page contentType="text/html; charset=UTF-8" isELIgnored="false"%> |
applicationContext.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="parameterMappingInterceptor" class="org.springframework.web.portlet.handler.ParameterMappingInterceptor"/>
<bean id="dispatcher" class="cssduty.operation.DispatherController">
<property name="viewPage" value="enter" ></property>
</bean>*
一个简单的处理器映射,它是基于当前的portlet模式(比如:'view', 'edit', 'help').:
<bean id="portletModeHandlerMapping" class="org.springframework.web.portlet.handler.PortletModeHandlerMapping">
<property name="order" value="20"/>
<property name="portletModeMap">
<map>
<entry key="view"><ref bean="dispatcher"/></entry>
<entry key="help"><ref bean=""/></entry>//可以不写
</map> </property>
</bean>
在不改变Portlet模式的情况下在多个控制器间切换,参数的缺省名是"action",但可以通过parameterName来修改。
<bean id="parameterMappingInterceptor" class="org.springframework.web.portlet.handler*.ParameterMappingInterceptor"/>
<bean id="portletModeParameterHandlerMapping" class="org.springframework.web.portlet.handler.PortletModeParameterHandlerMapping">
<property name="order" value="1"/>
<property name="interceptors">
<list>
<ref bean="parameterMappingInterceptor"/>
</list>
</property>
<property name="portletModeParameterMap">
<map>
<entry key="view">
<map>
<entry key="coming"><ref bean="comingRecord"/></entry>
<entry key="leaving"><ref bean="leaveRecord"/></entry>
<entry key="change"><ref bean="changeTeam"/></entry>
<entry key="sending"><ref bean="sendInfo"/></entry>
<entry key="dispatcher"><ref bean="dispatcher"/></entry>
</map>
</entry>
</map>
</property>
</bean>
Portlet包也带一个名为ParameterMappingInterceptor 的具体拦截器,它可以和ParameterHandlerMapping 以及PortletModeParameterHandlerMapping一起使用。 这个拦截器可以把用来控制映射的参数从ActionRequest 带到随后的RenderRequest,这能够确保 RenderRequest映射到和 ActionRequest相同的处理器。这些都是在 preHandle方法里完成的,所以在你的处理器里仍然可以改变决定 RenderRequest映射的参数值。
注意这个拦截器会调用ActionResponse 的setRenderParameter方法,这意味着在使用它的时候, 不能在处理器里调用sendRedirect。如果确实需要重定向, 可以手工地把映射参数向前传,或者另写一个拦截器来处理。
<bean id="parameterMappingInterceptor" class="org.springframework.web.portlet.handler.ParameterMappingInterceptor"/>
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="cache" value="false"/>
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/JSP/"/>
<property name="suffix" value=".jsp"/>
</bean>
<bean id="comingRecord" class="cssduty.operation.ComingRecord">
<property name="viewPage">
<value>sign</value>
</property>
</bean>
<bean id="leaveRecord" class="cssduty.operation.LeaveRecord">
<property name="viewPage">
<value>sign</value>
</property>
</bean>
<bean id="changeTeam" class="cssduty.operation.ChangeTeam">
<property name="viewPage">
<value>team</value>
</property>
</bean>
<bean id="sendInfo" class="cssduty.operation.SendBrowseInfo">
<property name="viewPage">
<value>List</value>
</property>
</bean>
</beans>
Spring的DispacherController
package cssduty.operation;
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 DispatherController implements Controller{
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
// TODO Auto-generated method stub
String hid=request.getParameter("hid");
System.out.println("hid is "+request.getParameter("hid"));
System.out.println("user is "+request.getParameter("user"));
if(hid.equals("onduty"))
{
response.sendRedirect("/SpringDuty/comingRecord.do?user="+request.getParameter("user"));
}
return null;
}
}
Spring-portlet的Controller
package cssduty.operation;
import java.util.HashMap;
import java.util.Map;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletMode;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import org.springframework.web.portlet.ModelAndView;
import org.springframework.web.portlet.handler.PortletModeParameterHandlerMapping;
import org.springframework.web.portlet.mvc.AbstractController;
import org.springframework.web.portlet.mvc.PortletModeNameViewController;
public class DispatherController extends AbstractController{
private String viewPage="";
Map map=null;
protected ModelAndView handleRenderRequestInternal(RenderRequest arg0, RenderResponse arg1) throws Exception {
map=new HashMap();
map.put("disRequest",arg0);
return new ModelAndView(this.getViewPage(),map); }
public void handleActionRequestInternal(ActionRequest request, ActionResponse response) throws Exception {
// TODO Auto-generated method stub
response.setRenderParameter("hid",hid);
}
public String getViewPage() {
return viewPage;
}
public void setViewPage(String viewPage) {
this.viewPage = viewPage;
}
}
两个Controller的区别在于包引入的不同
前者实现Controller接口,后者继承AbstractController类,实现的方法也就不同
后者不能直接提交ModelAndView,需要经由handleActionRequestInternal(ActionRequest request, ActionResponse response)方法提交给
handleRenderRequestInternal(RenderRequest arg0, RenderResponse arg1) 才可以。
enter.jsp
<%@ page language="java" pageEncoding="gb2312"%>
<%@ taglib prefix="portlet" uri="http://java.sun.com/portlet" %>
<%@page import="javax.portlet.*" %>
<%@ taglib uri="c.tld" prefix="c" %>
<%@ taglib uri="c-1_0-rt.tld" prefix="c-rt" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>enter.jsp</title>
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="this is my page">
<meta http-equiv="content-type" content="text/html; charset=gb2312">
<!--<link rel="stylesheet" type="text/css" href="./styles.css">-->
<script language="javascript" type="text/javascript">
function getOn()
{
document.enter_form.elements[2].value=document.all.onduty.name;
document.enter_form.action="<portlet:actionURL> <portlet:param name='action' value='coming'/></portlet:actionURL>";
enter_form.submit();
}
function getLeave()
{
document.enter_form.elements[2]=document.all.leave.name;
document.enter_form.action="<portlet:actionURL> <portlet:param name='action' value='leaving'/></portlet:actionURL>";
enter_form.submit();
}
function getTeamChange()
{
document.enter_form.elements[2].value=document.all.changeTeam.name;
document.enter_form.action="<portlet:actionURL> <portlet:param name='action' value='change'/></portlet:actionURL>";
enter_form.submit();
}
</script>
</head>
<body>
<form name="enter_form" method="post" id="f1" action="" >
<%
RenderRequest renderRequest=((RenderRequest)(request.getAttribute("disRequest")));
%>
<%== renderRequest.getPreferences().getValue("userName", null) %>
<table border="0" width="208" height="58">
<tr>
//获取DispatcherController传过来的RenderRequest
<%=((RenderRequest)(request.getAttribute("disRequest"))).getUserPrincipal()%>
<c-rt:forEach var="userAttr" items="<%= request.getAttribute(PortletRequest.USER_INFO)%>">
<tr>
<c:if test="${userAttr.key=='user.name'}">
<td>用户:<c:out value="${userAttr.value}"/></td>
<td><input type="hidden" name="user" value="${userAttr.value}"/></td>
</c:if>
<c:if test="${userAttr.key=='user.department'}">
<td>部门:<c:out value="${userAttr.value}"/></td>
<td><input type="hidden" name="department" value="${userAttr.value}"/></td>
</c:if>
</tr>
</c-rt:forEach>
</tr>
<tr>
<td colspan="8" align="center">
<input type="hidden" name="hid">
<input type="button" value="上班" name="onduty" οnclick="getOn()">
<input type="button" value="下班" οnclick="getLeave()" name="leave">
<input type="button" value="项目组变更" οnclick="getTeamChange()" name="changeTeam">
</td>
</tr>
</table>
</form>
</body>
</html>