Liferay技术求助:Portal.getUser登录后失效及文档阅读事件记录需求
Let's tackle your two Liferay issues one by one with practical, actionable solutions:
Portal.getUser() Failing After User Login If Portal.getUser() isn't returning the authenticated user post-login, here's how to diagnose and fix it:
- Confirm request context validity:
Portal.getUser()relies on being called within an active Liferay request context (e.g., inside a Portlet action, MVC command, or servlet filter). If you're calling it from a background thread or non-request-triggered code, it won't work—instead, pass theUserobject explicitly or fetch it viaUserLocalServiceUtilusing a known user ID. - Verify login status first: Always check if the user is signed in before calling
Portal.getUser()withPortal.isUserSignedIn(request). This avoids null returns when the session is invalid or expired. - Handle multi-tenant environments: In a multi-portal setup, ensure you're targeting the correct company instance. Use
Portal.getCompanyId(request)to scope your user lookup if needed. - Fallback to a reliable alternative: If
Portal.getUser()continues to misbehave, use this more direct approach:String remoteUserId = request.getRemoteUser(); if (remoteUserId != null) { User user = UserLocalServiceUtil.getUserById(Long.parseLong(remoteUserId)); // Use the user object here }
Intercepting direct document access URLs (like your example http://localhost:8080/documents/20181/323505/dddd.pdf/d188618b-56c5-4be6-bf94-548fac22bc24) to log reader events requires a custom filter hooked into Liferay's document download servlet. Here's a step-by-step implementation:
Step 1: Create a Custom Filter
Implement javax.servlet.Filter to capture download requests and log reader events. This example parses the URL, fetches the authenticated user, and logs the event to your database:
package com.yourcompany.liferay.hooks.filter; import com.liferay.portal.kernel.model.User; import com.liferay.portal.kernel.util.PortalUtil; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.util.Date; public class DLDocumentReadTrackingFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException {} @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; String requestURI = httpRequest.getRequestURI(); // Match direct document library access URLs if (requestURI.startsWith("/documents/")) { User currentUser = PortalUtil.getUser(httpRequest); if (currentUser != null) { // Parse URL components: groupId, folderId, fileName, document UUID String[] uriParts = requestURI.split("/"); if (uriParts.length >= 6) { try { long groupId = Long.parseLong(uriParts[2]); long folderId = Long.parseLong(uriParts[3]); String fileName = uriParts[4]; String documentUuid = uriParts[5]; // Log the read event to your database logDocumentReadEvent( currentUser.getUserId(), groupId, folderId, fileName, documentUuid, new Date() ); } catch (NumberFormatException e) { // Handle invalid URL format gracefully e.printStackTrace(); } } } // Optional: Add logic for anonymous users (log IP address, etc.) } // Continue processing the download request chain.doFilter(request, response); } private void logDocumentReadEvent(long userId, long groupId, long folderId, String fileName, String documentUuid, Date readDate) { // Implement your database insert logic here // Example using Liferay's service builder (if you generated a DLReadEvent entity): /* DLReadEvent readEvent = DLReadEventLocalServiceUtil.createDLReadEvent( CounterLocalServiceUtil.increment(DLReadEvent.class.getName()) ); readEvent.setUserId(userId); readEvent.setGroupId(groupId); readEvent.setFolderId(folderId); readEvent.setFileName(fileName); readEvent.setDocumentUuid(documentUuid); readEvent.setReadDate(readDate); DLReadEventLocalServiceUtil.addDLReadEvent(readEvent); */ } @Override public void destroy() {} }
Step 2: Register the Filter via Hook
Update your liferay-hook.xml to attach the filter to Liferay's DLFileEntryDownloadServlet (the servlet that handles direct document downloads):
<?xml version="1.0"?> <!DOCTYPE hook PUBLIC "-//Liferay//DTD Hook 7.4.0//EN" "http://www.liferay.com/dtd/liferay-hook_7_4_0.dtd"> <hook> <servlet-filter> <servlet-filter-name>DLDocumentReadTrackingFilter</servlet-filter-name> <servlet-filter-impl>com.yourcompany.liferay.hooks.filter.DLDocumentReadTrackingFilter</servlet-filter-impl> </servlet-filter> <servlet-filter-mapping> <servlet-filter-name>DLDocumentReadTrackingFilter</servlet-filter-name> <servlet-name>DLFileEntryDownloadServlet</servlet-name> </servlet-filter-mapping> </hook>
Key Notes
- Performance optimization: To avoid slowing down document downloads, run the database log asynchronously using Liferay's
MessageBusor a scheduled task. - URL edge cases: Test for URLs with version numbers (e.g.,
/documents/.../version/1.0/...) and adjust your parsing logic to handle them. - Anonymous users: If consumers can access documents without logging in, add logic to log their IP address or session ID instead of a user ID.
内容的提问来源于stack exchange,提问作者Óscar Ibáñez Fernández

