本文用一个实例来说明liferay中portlet action的处理流程.
在liferay的演示网站上随便输入用户名/密码提交后,就可以如下的一个url.
http://demo.liferay.net/c/portal/layout?p_l_id=PUB.1001.1
&p_p_id=58
&p_p_action=1
&p_p_state=normal
&p_p_mode=view
&p_p_col_id=column-1
&p_p_col_pos=0
&p_p_col_count=1
&_58_struts_action=%2Flogin%2Fview
&_58_cmd=update
&#p_58
在liferay中,是用struts来做FrontController的,
〈action path="/portal/layout" type="com.liferay.portal.action.LayoutAction"〉
〈forward name="portal.layout" path="portal.layout" /〉
〈/action〉
LayoutAction
LayoutAction.execute(ActionMapping mapping, ActionForm form,
HttpServletRequest req, HttpServletResponse res)
throws Exception {
String plid = ParamUtil.getString(req, "p_l_id");
String action = ParamUtil.getString(req, "p_p_action");
if (Validator.isNotNull(plid)) {
try {
if (action.equals("1")) { // 处理action请求.
_processActionRequest(req, res);
ActionResponseImpl actionResponseImpl =
(ActionResponseImpl)req.getAttribute(WebKeys.JAVAX_PORTLET_RESPONSE);
String redirectLocation = actionResponseImpl.getRedirectLocation();
if (Validator.isNotNull(redirectLocation)) {
res.sendRedirect(redirectLocation);
return null;
}
if (LiferayWindowState.isExclusive(req)) {
return null;
}
}
else if (action.equals("0")) { // 处理render请求.
_processRenderRequest(req, res);
}
return mapping.findForward("portal.layout");
} catch (Exception e) {
req.setAttribute(PageContext.EXCEPTION, e);
return mapping.findForward(Constants.COMMON_ERROR);
} finally {
// 清理工作。
}
} else {
try {
_forwardLayout(req);
return mapping.findForward(Constants.COMMON_FORWARD);
} catch (Exception e) {
req.setAttribute(PageContext.EXCEPTION, e);
return mapping.findForward(Constants.COMMON_ERROR);
}
}
}
Layout._processPortletRequest(
HttpServletRequest req, HttpServletResponse res, boolean action)
throws Exception {
HttpSession ses = req.getSession();
// 查找portlet.
String companyId = PortalUtil.getCompanyId(req);
User user = PortalUtil.getUser(req);
Layout layout = (Layout)req.getAttribute(WebKeys.LAYOUT);
String portletId = ParamUtil.getString(req, "p_p_id");
Portlet portlet = PortletLocalServiceUtil.getPortletById(
companyId, portletId);
ServletContext ctx = (ServletContext)req.getAttribute(WebKeys.CTX);
CachePortlet cachePortlet = PortletInstanceFactory.create(portlet, ctx);
if (user != null) {
CachePortlet.clearResponse(ses, layout.getPrimaryKey(), portletId);
}
PortletPreferencesPK prefsPK =
PortletPreferencesFactory.getPortletPreferencesPK(req, portletId);
PortletPreferences prefs =
PortletPreferencesLocalServiceUtil.getPreferences(companyId, prefsPK);
// portlet配置及上下文.
PortletConfig portletConfig = PortletConfigFactory.create(portlet, ctx);
PortletContext portletCtx = portletConfig.getPortletContext();
// window状态.
WindowState windowState = new WindowState(ParamUtil.getString(req, "p_p_state"));
// portlet模式.
PortletMode portletMode = new PortletMode(ParamUtil.getString(req, "p_p_mode"));
if (action) { // 处理action.
ActionRequestImpl actionRequestImpl = ActionRequestFactory.create(
req, portlet, cachePortlet, portletCtx, windowState,
portletMode, prefs, layout.getPlid());
ActionResponseImpl actionResponseImpl =
ActionResponseFactory.create(
actionRequestImpl, res, portletId, user, layout,
windowState, portletMode);
actionRequestImpl.defineObjects(portletConfig, actionResponseImpl);
cachePortlet.processAction(actionRequestImpl, actionResponseImpl);
RenderParametersPool.put(req, layout.getPlid(), portletId,
actionResponseImpl.getRenderParameters());
} else { // 处理render.
PortalUtil.updateWindowState(portletId, user, layout, windowState, req);
PortalUtil.updatePortletMode(portletId, user, layout, portletMode);
}
}
CachePortlet对普通Portlet进行了包装,加入了cache处理,
CachePortlet
CachePortlet.processAction(ActionRequest req, ActionResponse res)
throws IOException, PortletException {
_invoke(req, res, true);
}
CachePortlet._invoke(
PortletRequest req, PortletResponse res, boolean action)
throws IOException, PortletException {
Map properties = null;
if (_portletConfig.isWARFile()) { // 如果Portlet是外部war整合方式的,则转发请求.
String path = StringPool.SLASH + _portletConfig.getPortletName() + "/invoke";
RequestDispatcher rd = _portletCtx.getServletContext().getRequestDispatcher(path);
HttpServletRequest httpReq = null;
HttpServletResponse httpRes = null;
ActionRequestImpl actionReqImpl = null;
ActionResponseImpl actionResImpl = null;
RenderRequestImpl renderReqImpl = null;
RenderResponseImpl renderResImpl = null;
if (action) {
actionReqImpl = (ActionRequestImpl)req;
actionResImpl = (ActionResponseImpl)res;
httpReq = actionReqImpl.getHttpServletRequest();
httpRes = actionResImpl.getHttpServletResponse();
} else {
renderReqImpl = (RenderRequestImpl)req;
renderResImpl = (RenderResponseImpl)res;
httpReq = renderReqImpl.getHttpServletRequest();
httpRes = renderResImpl.getHttpServletResponse();
}
httpReq.setAttribute(WebKeys.JAVAX_PORTLET_PORTLET, _portlet);
try {
rd.include(httpReq, httpRes);
} catch (ServletException se) {
// 重新抛出异常.
}
if (action) {
properties = actionResImpl.getProperties();
} else {
properties = renderResImpl.getProperties();
}
} else { // Portlet是liferay内部整合方式的,直接交由_portlet处理。
if (action) {
ActionRequestImpl actionReqImpl = (ActionRequestImpl)req;
ActionResponseImpl actionResImpl = (ActionResponseImpl)res;
_portlet.processAction(actionReqImpl, actionResImpl);
properties = actionResImpl.getProperties();
} else {
RenderRequestImpl renderReqImpl = (RenderRequestImpl)req;
RenderResponseImpl renderResImpl = (RenderResponseImpl)res;
_portlet.render(renderReqImpl, renderResImpl);
properties = renderResImpl.getProperties();
}
}
if ((properties != null) && (properties.size() > 0)) {
if (_expCache != null) {
String[] expCache = (String[])properties.get(RenderResponse.EXPIRATION_CACHE);
if ((expCache != null) && (expCache.length > 0) && (expCache[0] != null)) {
_expCache = new Integer(GetterUtil.getInteger(expCache[0]));
}
}
}
}
在这里,Login portlet是liferay内部整合方式的,
通过portlet.xml文件和它的portletId,找到它的实现类是StrutsPortlet.
StrutsPortlet
StrutsPortlet.processAction(ActionRequest req, ActionResponse res)
throws IOException, PortletException {
String path = req.getParameter("struts_action"); // 这里为/login/view
if (Validator.isNotNull(path)) {
// Call processAction of com.liferay.portal.struts.PortletAction
PermissionChecker checker = PermissionThreadLocal.getPermissionChecker();
try {
checker.setValues(req);
// Process action
PortletRequestProcessor processor = _getPortletRequestProcessor(req);
processor.process(req, res, path);
} catch (ServletException se) {
throw new PortletException(se);
} finally {
checker.resetValues();
}
}
if (copyRequestParameters) {
PortalUtil.copyRequestParameters(req, res);
}
}
// /login/view定义.
〈action path="/login/view" type="com.liferay.portlet.login.action.ViewAction"〉
〈forward name="portlet.login.view" path="portlet.login.view" /〉
〈/action〉
PortletRequestProcessor
PortletRequestProcessor.process(ActionRequest req, ActionResponse res, String path)
throws IOException, ServletException {
ActionRequestImpl reqImpl = (ActionRequestImpl)req;
ActionResponseImpl resImpl = (ActionResponseImpl)res;
HttpServletRequest httpReq = reqImpl.getHttpServletRequest();
HttpServletResponse httpRes = resImpl.getHttpServletResponse();
ActionMapping mapping = processMapping(httpReq, httpRes, path);
if (mapping == null) {
return;
}
// processRoles处理,略...
ActionForm form = processActionForm(httpReq, httpRes, mapping);
processPopulate(httpReq, httpRes, form, mapping);
if (!processValidateAction(httpReq, httpRes, form, mapping)) {
return;
}
// 构建ViewAction.
PortletAction action =
(PortletAction)processActionCreate(httpReq, httpRes, mapping);
if (action == null) {
return;
}
PortletConfigImpl portletConfig =
(PortletConfigImpl)req.getAttribute(WebKeys.JAVAX_PORTLET_CONFIG);
// 处理action.
try {
action.processAction(mapping, form, portletConfig, req, res);
}
catch (Exception e) {
String exceptionId = WebKeys.PORTLET_STRUTS_EXCEPTION +
StringPool.PERIOD + portletConfig.getPortletId();
req.setAttribute(exceptionId, e);
}
// 处理forward, 略...
ViewAction
ViewAction.processAction(
ActionMapping mapping, ActionForm form, PortletConfig config,
ActionRequest req, ActionResponse res) throws Exception {
String cmd = req.getParameter(Constants.CMD); // update
ThemeDisplay themeDisplay =
(ThemeDisplay)req.getAttribute(WebKeys.THEME_DISPLAY);
if (req.getRemoteUser() != null) { // 已经登录,直接redirect.
res.sendRedirect(themeDisplay.getPathMain());
}
else if (Validator.isNotNull(cmd)) {
try {
_login(themeDisplay, req, res); // 登录处理.
} catch (Exception e) {
// 异常处理.
}
}
}
ViewAction._login(
ThemeDisplay themeDisplay, ActionRequest req, ActionResponse res)
throws Exception {
ActionRequestImpl reqImpl = (ActionRequestImpl)req;
ActionResponseImpl resImpl = (ActionResponseImpl)res;
HttpServletRequest httpReq = reqImpl.getHttpServletRequest();
HttpServletResponse httpRes = resImpl.getHttpServletResponse();
String login = ParamUtil.getString(req, "login");
String password = ParamUtil.getString(req, "password");
boolean rememberMe = ParamUtil.getBoolean(req, "rememberMe");
LoginAction.login(httpReq, httpRes, login, password, rememberMe);
res.sendRedirect(themeDisplay.getPathMain() + "/portal/protected");
}
LoginAction.login的处理这里就不说明了,请查看源码,
以上就是liferay中portlet的action处理流程了。
有关在liferay中以外部war方式整合的portlet的处理流程,请关注我的后续文章。