# 1.4 Advanced Usage of jfinal-undertow

# I. Basic Configuration

# 1. Enable Configuration File

Create an undertow.txt file in the src/main/resources directory. This file will be automatically loaded by jfinal undertow and configure it.

If you prefer not to use the filename "undertow.txt", you can specify your desired filename by passing it as the second parameter of the UndertowServer.create(AppConfig.class, "other.txt") method.

Once the configuration file is created, you can refer to the following documentation to set up the respective functionalities.

# 2. Common Configurations

# 'true' enables hot reloading
undertow.devMode=true
undertow.port=80
undertow.host=0.0.0.0
 
# In most cases, it's not recommended to set the context path
undertow.contextPath=/abc
1
2
3
4
5
6
7

Set to 'true' during development to enable hot reloading. Note that this devMode is unrelated to the devMode in the jfinal project. Please differentiate between them.

Important: The default value for the older version of undertow.host is localhost. Due to security settings on Linux, projects deployed under localhost may not be accessible from the public internet. Adjust the setting to undertow.host=0.0.0.0. If you're using nginx as a proxy, you can keep the localhost setting.

# 3. Web Resource Load Path Configuration

jfinal undertow can easily load web static resources from the file system directory, class path, or jar packages. Here's a configuration example:

undertow.resourcePath = src/main/webapp, classpath:static
1

As shown above, "src/main/webapp" indicates loading web static resources from the "src/main/webapp" directory in the project root. "classpath:static" signifies loading web static resources from the static path in the class path or jar packages.

Note: The configuration "classpath:static" was added in jfinal undertow 1.5.

Another key point about undertow.resourcePath is that configurations prefixed with "classpath:" require manual validation of the existence of the path. It's preferable to only specify existing paths. Configurations without the "classpath:" prefix can have both the development and deployment paths configured (separated by commas). jfinal undertow will check the existence of paths at runtime and only activate them if they exist. This is convenient for a one-time configuration suitable for both development and production environments.

Important: PathKit.getWebRootPath() will point to the first valid directory in the undertow.resourcePath configuration. The engine object in the configEngine(Engine engine) method has already been set by default to engine.setBaseTemplatePath(PathKit.getWebRootPath()). So, this configuration is related to the engine's baseTemplatePath.

# 4. Performance Configuration

# Number of io threads and worker threads
# undertow.ioThreads=
# undertow.workerThreads=
1
2
3

The default configuration has been optimized for common use cases. Without performance test data as guidance, it's recommended to stick to the default settings and avoid adding these configurations.

ioThreads represents the number of NIO threads handling io requests. In a production environment, it's suggested to set this between one to two times the number of CPU cores. Adjustments should be based on performance test results.

workerThreads denotes the number of threads processing requests. In production, the default setting can be used, or adjustments can be made based on performance tests. When performance reaches a certain level, increasing the value of workThreads won't lead to performance improvements but will increase system resource consumption.

# 5. Enable gzip Compression

# gzip compression switch
undertow.gzip.enable=true
# Set compression level, default is -1. Can be set between 1 and 9. 1 has the fastest compression speed, 9 has the highest compression rate.
undertow.gzip.level=-1
# Minimum content length to trigger compression
undertow.gzip.minLength=1024
1
2
3
4
5
6

Enabling gzip compression can reduce network traffic and improve access speed.

# 6. Session Configuration

# Session expiration time, note the unit is in seconds.
undertow.session.timeout=1800
# Support session hot reloading to avoid repeated logins for projects dependent on sessions. Default is true. Only for devMode, no impact in production.
undertow.session.hotSwap=true
1
2
3
4

# 7. HTTPS Configuration

# Whether to enable ssl
undertow.ssl.enable=false
# ssl listening port, set to 443 in a production environment
undertow.ssl.port=443
# Keystore type, recommended to use PKCS12
undertow.ssl.keyStoreType=PKCS12
# Keystore file
undertow.ssl.keyStore=demo.pfx
# Keystore password
undertow.ssl.keyStorePassword=123456
# Alias configuration, generally not used
undertow.ssl.keyAlias=demo
1
2
3
4
5
6
7
8
9
10
11
12

Instructions on obtaining an SSL certificate can be found in the following subsection.

# 8. HTTP2 Configuration

# Whether to enable http2 when ssl is on. To check if this configuration is active, enter in the Chrome address bar: chrome://net-internals/#http2
undertow.http2.enable=true
1
2

Enabling http2 can significantly speed up access. You don't need to worry about https being slower than http.

# 9. Redirecting HTTP to HTTPS

# When ssl is enabled, should http requests redirect to https?
undertow.http.toHttps=false
# When ssl is enabled, the status code used for redirecting http requests to https. Default value is 302.
undertow.http.toHttpsStatusCode=302
1
2
3
4

# 10. Disable HTTP

# Whether to disable http when ssl is on
undertow.http.disable=false
1
2

After enabling https, you can configure to disable http, so only https can be accessed. This configuration is suitable for mini-program servers.

For general web projects, it's not recommended to use this configuration. Instead, set undertow.http.toHttps=true to redirect http to https.

# 11. Freely Configure Undertow

The above configurations are directly supported by jfinal undertow. If these configurations don't meet your requirements, you can freely configure undertow as follows:

UndertowServer.create(YourJFinalConfig.class)
    .onStart( builder -> {
        builder.setServerOption(UndertowOptions.PARAMETER_NAME, PARAMETER_VALUE);	
     })
    .start();
1
2
3
4
5

As shown above, using the onStart method and calling builder.setServerOption(...) allows for deeper configuration of undertow. You can also call other APIs in the builder for different types of configurations. UndertowOptions defines many undertow configuration names. Check its documentation comments to find many useful configurations.

# 12. Add Filter, WebSocket, Servlet, Listener

It's crucial to note that Undertow is a web server designed for embedding, so the web.xml has been deprecated, meaning you can't configure web components through web.xml.

To address this, jfinal undertow provides UndertowServer.configWeb(...) which allows you to easily add standard Java Web components such as Filter, WebSocket, Servlet, and Listener:

UndertowServer.create(AppConfig.class)
     .configWeb( builder -> {
         // Configure Filter
         builder.addFilter("myFilter", "com.abc.MyFilter");
         builder.addFilterUrlMapping("myFilter", "/*");
         builder.addFilterInitParam("myFilter", "key", "value");
         
         // Configure Servlet
         builder.addServlet("myServlet", "com.abc.MyServlet");
         builder.addServletMapping("myServlet", "*.do");
         builder.addServletInitParam("myServlet", "key", "value");
         
         // Configure Listener
         builder.addListener("com.abc.MyListener");
         
         // Configure WebSocket. MyWebSocket should use the ServerEndpoint annotation
         builder.addWebSocketEndpoint("com.abc.MyWebSocket");
      })
     .start();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

Note: The JFinalFilter will take over all requests. Thus, servlets mapped in addServletMapping(...) in the above code by default cannot be accessed. You need to configure the UrlSkipHandler in the configHandler(Handlers me) to let jfinal skip these servlet URLs.

The MyWebSocket in the above code should be annotated with ServerEndpoint to indicate that it's a WebSocket component, like:

@ServerEndpoint("/myapp.ws")
public class MyWebSocket { 
    @OnMessage
    public void message(String message, Session session) {
        for (Session s : session.getOpenSessions()) {
            s.getAsyncRemote().sendText(message);
        }
    }
}
1
2
3
4
5
6
7
8
9

An example HTML that works with the above MyWebSocket can be downloaded from the link provided (not accessible in this context). Community members have also shared complete WebSocket code here (opens new window).

You need to adjust the URL in the HTML to: "ws://localhost:80/myapp.ws", changing the port number as appropriate.

Note: Since JFinalFilter takes over all URL requests that don't have a "." character, it's suggested that the URL parameter value in the @ServerEndpoint annotation should end with ".ws". Otherwise, you'll receive a 404 error, indicating the resource is not found, like:

@ServerEndpoint("/myapp.ws")
public class MyWebSocketEndpoint  {
    ......
}
1
2
3
4

Alternatively, if the URL in the ServerEndpoint doesn't end with ".ws", you can refer to jfinal's UrlSkipHandler and implement a Handler to skip WebSocket URLs.

Lastly, WebSocket support requires adding a dependency. The dependencies to be added can be found in the earlier documentation: link (opens new window).

# II. SSL Certificates

# 1. Apply for an SSL Certificate

It's recommended to obtain SSL certificates from platforms like Alibaba Cloud or Tencent Cloud. Both free and paid versions are available. For obtaining an SSL certificate from Alibaba Cloud, refer to the provided link (not accessible in this context).

Note: When applying for a free SSL certificate, the bound domain generally uses a hostname like www, e.g., www.jfinal.com.

# 2. Download the Appropriate Certificate Type

Once the SSL certificate has been approved, you can download it from the control panel as shown in the provided screenshot (not accessible in this context).

After clicking the download link, download the Tomcat type of SSL certificate as shown in the second screenshot.

Within the downloaded certificate, there's a file named xxx.pfx, which is the certificate file. Additionally, there's a pfx-password.txt file containing the certificate password. Place the xxx.pfx file in the project's src/main/resources directory and add the following lines to the undertow.txt configuration file:

# Enable ssl
undertow.ssl.enable=true
# ssl listening port, set to 443 in production
undertow.ssl.port=443
# Keystore type, typically either PKCS12 or JKS. Adjust based on actual type.
undertow.ssl.keyStoreType=PKCS12
# Keystore file
undertow.ssl.keyStore=demo.pfx
# Keystore password
undertow.ssl.keyStorePassword=123456
1
2
3
4
5
6
7
8
9
10

The "demo.pfx" in the configuration is the filename of the previously downloaded certificate, and "123456" is the certificate password. Adjust these settings based on the actual contents of your download. "PKCS12" is the certificate type; Alibaba Cloud's Tomcat type certificate uses PKCS12, while Tencent Cloud might use "JKS".

# 3. Launch the Project

Start the project and access it via the domain bound when applying for the certificate using "https".

# III. Two-Way SSL Authentication

If your jfinal undertow project needs to authenticate clients using SSL, configure it as follows:

UndertowServer.create(YourJFinalConfig.class)
  .onStart( builder -> {
    builder.setSocketOption(Options.SSL_CLIENT_AUTH_MODE, SslClientAuthMode.REQUESTED);
  })
  .start();
1
2
3
4
5

This method was shared by community users at the provided link https://jfinal.com/feedback/7758 (opens new window).

Last Updated: 9/17/2023, 5:25:03 AM