Using Servlet Filters
Servlet filters can both pre-process requests as they arrive and post-process responses before they go to the client browser. You can apply functionality to requests and responses for multiple servlets, without the servlets knowing. Here are some common filter use cases:
- Logging
- Auditing
- Transaction management
- Security
You can use patterns in descriptors to map the filters to servlet URLs. When requests arrive at these URLs, your filters process them. Filter chaining lets you apply filters in an order you want. Here are the steps for creating and deploying a servlet filter:
Deploying a Servlet Filter
Start a new Liferay instance by running
docker run -it -m 8g -p 8080:8080 liferay/portal:7.4.3.112-ga112
Sign in to Liferay at http://localhost:8080. Use the email address test@liferay.com and the password test. When prompted, change the password to learn.
Then, follow these steps to download, build, and deploy the sample Servlet Filter to the new docker container:
-
Download and unzip the example module.
curl https://resources.learn.liferay.com/dxp/latest/en/liferay-development/liferay-internals/extending-liferay/liferay-m9a3.zip -O
unzip liferay-m9a3.zip
-
Run the following
gradlew
command to build the JAR file and deploy it to your new Docker container:cd liferay-m9a3
./gradlew deploy -Ddeploy.docker.container.id=$(docker ps -lq)
-
Confirm the module was deployed successfully and started via the container console.
STARTED com.acme.m9a3.impl_1.0.0 [1630]
-
Verify the portlet filter is working by visiting
localhost:8080
. Whenever a request is forwarded to the servlet, the container console shows a message stating that the method was successfully invoked.INFO [http-nio-8080-exec-6][M9A3ServletFilter:37] Invoking #processFilter(HttpServletRequest, HttpServletResponse, FilterChain)
Intercepting Requests with a Servlet Filter
Any time a request is made to the chosen servlets, the servlet filter intercepts the request and calls the processFilter
method.
-
To make your own servlet filter, create a class that extends
com.liferay.portal.kernel.servlet.BaseFilter
.public class M9A3ServletFilter extends BaseFilter {
-
Override the
processFilter
method to add the desired functionality. In this example, the filter outputs a message to the console to assert that it’s been called.
@Override
protected void processFilter(
HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse, FilterChain filterChain)
throws Exception {
if (_log.isInfoEnabled()) {
_log.info(
"Invoking #processFilter(HttpServletRequest, " +
"HttpServletResponse, FilterChain)");
}
httpServletResponse.addHeader(
"X-M9A3-Servlet-Filter", httpServletRequest.getRequestURI());
processFilter(
M9A3ServletFilter.class.getName(), httpServletRequest,
httpServletResponse, filterChain);
}
- In the
processFilter
method, make sure to also add a header to the HTTP response. You can use any text for the string as long as it’s not already the name of an existing header. This works as a key.
httpServletResponse.addHeader(
"X-M9A3-Servlet-Filter", httpServletRequest.getRequestURI());
- After that, you generally want the HTTP request to go through the next filters and finish being processed. To continue processing the request, call
BaseFilter
’sprocessFilter
method:
processFilter(
M9A3ServletFilter.class.getName(), httpServletRequest,
httpServletResponse, filterChain);
-
Annotate the class with
@Component
. You need two arguments:service
andproperty
. For a servlet filter, theservice
argument must be set toFilter.class
. Theproperty
argument holds a list of URLs to be mapped to the servlet filter as well as other options specific to servlet filters.-
url-pattern
: URL patterns you want to filter requests and responses for (required) -
dispatcher
: Dispatcher enumerated constants to constrain how the filter is applied to requests,REQUEST
by default (optional)
NoteYou can add many dispatchers to one filter.
-
servlet-filter-name
: Human readable name to identify the servlet filter (required) -
before-filter
andafter-filter
: The filter that should be run before the custom filter you’re creating and the filter that should be run after, respectively (optional)
TipWhenever you alter the order of servlet filters, it’s recommended to set the
after-filter
toAbsolute Redirects Filter
. This lowers the risk of various bugs.servlet-context-name
: This value must always be set to an empty string (required)
-
@Component(
property = {
"after-filter=Absolute Redirects Filter",
"before-filter=Auto Login Filter", "dispatcher=FORWARD",
"servlet-context-name=", "servlet-filter-name=M9A3 Servlet Filter",
"url-pattern=/group/*", "url-pattern=/user/*", "url-pattern=/web/*"
},
service = Filter.class
)
public class M9A3ServletFilter extends BaseFilter {