[JAVA] [Updated December 2018] Tips for embedded web server and servlet created with Jetty9

As you know Jetty9 is a lightweight and highly functional web server, servlet container.

I will post the setting tips that are often used when using Jetty9 in Java application embedded and sample code including servlet.

The working source code set (maven project) is listed at https://github.com/riversun/jetty9-quick-start.

The article on HTTPS (SSL / TLS) with Jetty9 is summarized at https://qiita.com/riversun/items/2909019123b28471ea79.

Jetty9 built-in setting tips (operation confirmed with v.9.4.12)

● Add Servlet

Add a Servlet called ExampleServlet.java that accepts with the path "/ api"

//ServletContextHandler handles Servlet
ServletContextHandler servletHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);

//Add Servlet
servletHandler.addServlet(new ServletHolder(new ExampleServlet()), "/api");

● Specify the upload size of the form

If you try to upload large size data, you may get ** java.lang.IllegalStateException: Form too large **. In such a case, specify the required size with ** setMaxFormContentSize **.


//Specify form upload size
servletHandler.setMaxFormContentSize(1024 * 1024 * 1024);

● Specify the location of static content (static file)

Specify the resource base with ** setResourceBase **.

//ResourceHandler handles static content (roughly speaking)
final ResourceHandler resourceHandler = new ResourceHandler();

//Specify where to put static content
resourceHandler.setResourceBase(System.getProperty("user.dir") + "/htdocs");

● I don't want to show a list of static content files

It is a traditional ~~ nosy ~~ function of web servers such as Apache. If you don't want to see the file list (listing), do this

//Do not display the static content file list (listing)
resourceHandler.setDirectoriesListed(false);

● I want to change the default html from index.html

Can be changed with ** setWelcomeFiles **

//Specify the file to be initially displayed
resourceHandler.setWelcomeFiles(new String[] { "index.html" });

● Disable the cache. Do not cache.

A way to turn off caching of static content that plagues HTML and JavaScript developers. ** setCacheControl ** frees you from F5 repeated hits of water on burnt stones.

//Do not cache
resourceHandler.setCacheControl("no-store,no-cache,must-revalidate");

● Do not send server version information in headers, etc.

It is used when you do not want to display information such as jetty version number in HTTP header or default error screen. It can be set with ** HttpConfig # setSendServerVersion **.

I will show you two methods (What I want to do is simple, but the code is a bit longer. This is more complicated than jetty8 with the jetty9 refactoring)

[Method 1] Make your own http connector and set httpConfig

//Initialize the server with the default constructor
final Server jettyServer = new Server();
jettyServer.setHandler(handlerList);

final int PORT = 8080;

//http configuration class
final HttpConfiguration httpConfig = new HttpConfiguration();

//Don't put server version information in header
httpConfig.setSendServerVersion(false);
final HttpConnectionFactory httpConnFactory = new HttpConnectionFactory(httpConfig);
final ServerConnector httpConnector = new ServerConnector(jettyServer, httpConnFactory);
httpConnector.setPort(PORT);
jettyServer.setConnectors(new Connector[] { httpConnector });

[Method 2] Pull out the (existing) http connector and set httpConfig

final int PORT = 8080;

final Server jettyServer = new Server(PORT );

for (Connector conn : jettyServer.getConnectors()) {
  for (ConnectionFactory connFactory : conn.getConnectionFactories()) {
    if (connFactory instanceof HttpConnectionFactory) {
      ((HttpConnectionFactory) connFactory).getHttpConfiguration().setSendServerVersion(false);
    }
  }
}

Full text of Servlet on Jetty9 sample code

A CORS (cross-domain) access-enabled Web API-like servlet sample that returns JSON containing the code described above. Set the Maven dependency, copy and execute, and access as http: // localhost: 8080 / api? Message = hello.

package com.example.jetty;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.server.handler.ResourceHandler;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;

import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * Jetty9 Quick Start Example
 */
public class ServletApp
{
	public static void main(String[] args) {

		//ServletContextHandler handles Servlet
		ServletContextHandler servletHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);

		//Specify form upload size
		servletHandler.setMaxFormContentSize(1024 * 1024 * 1024);

		//Add Servlet
		servletHandler.addServlet(new ServletHolder(new ExampleServlet()), "/api");

		//ResourceHandler handles static content (roughly speaking)
		final ResourceHandler resourceHandler = new ResourceHandler();

		//Specify where to put static content
		resourceHandler.setResourceBase(System.getProperty("user.dir") + "/htdocs");

		//Do not display the static content file list (listing)
		resourceHandler.setDirectoriesListed(false);

		//Specify the file to be initially displayed
		resourceHandler.setWelcomeFiles(new String[] { "index.html" });

		//Do not cache
		resourceHandler.setCacheControl("no-store,no-cache,must-revalidate");

		HandlerList handlerList = new HandlerList();

		//Specify resourceHandler to come first (reversely, static content will not be called forever.)
		handlerList.addHandler(resourceHandler);
		handlerList.addHandler(servletHandler);

		//Initialize the server with the default constructor
		final Server jettyServer = new Server();
		jettyServer.setHandler(handlerList);

		final int PORT = 8080;

		//http configuration class
		final HttpConfiguration httpConfig = new HttpConfiguration();

		//Don't put server version information in header
		httpConfig.setSendServerVersion(false);
		final HttpConnectionFactory httpConnFactory = new HttpConnectionFactory(httpConfig);
		final ServerConnector httpConnector = new ServerConnector(jettyServer, httpConnFactory);
		httpConnector.setPort(PORT);
		jettyServer.setConnectors(new Connector[] { httpConnector });

		try {
			jettyServer.start();
			jettyServer.join();
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	@SuppressWarnings("serial")
	public static class ExampleServlet extends HttpServlet {

		final ObjectMapper mObjectMapper = new ObjectMapper();

		final class Result {
			public boolean success;
			public String message;
		}

		@Override
		protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

			//get query parameters
			final String paramMessage = req.getParameter("message");

			//POJO for response storage(Convert to JSON later)
			final Result result = new Result();
			result.success = true;
			result.message = "You say '" + paramMessage + "'";

			// CORS(Cross-Origin Resource Sharing)Enable
			resp.addHeader("Access-Control-Allow-Origin", "*");
			resp.addHeader("Access-Control-Allow-Headers", "Content-Type");

			//Content that returns JSON-Set Type to JSON
			final String CONTENT_TYPE = "application/json; charset=UTF-8";
			resp.setContentType(CONTENT_TYPE);

			final PrintWriter out = resp.getWriter();
			//Convert POJOs to JSON in Jackson
			final String json = mObjectMapper.writeValueAsString(result);

			//Generate a response
			out.println(json);
			out.close();

		}

		@Override
		protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
			resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Sorry, POST is not supported");
		}

		@Override
		protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
			resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Sorry, PUT is not supported");
		}

		@Override
		protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
			resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Sorry, DELETE is not supported");
		}

		@Override
		protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

			// For PreFlight Access
			// CORS(Cross-Origin Resource Sharing)Enable
			resp.addHeader("Access-Control-Allow-Origin", "*");
			resp.addHeader("Access-Control-Allow-Headers", "Content-Type");

		}

	}

		
}

Maven

<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>9.4.12.v20180830</version>
</dependency>

<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-webapp</artifactId>
<version>9.4.12.v20180830</version>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.8.1</version>
</dependency>

Source code

The source code is here https://github.com/riversun/jetty9-quick-start

in conclusion

For the detailed operation of ** Jetty **, use the motif of "Create an HTTPS server with 20 lines!" [this article](https: / /qiita.com/riversun/items/2909019123b28471ea79).

Recommended Posts

[Updated December 2018] Tips for embedded web server and servlet created with Jetty9
Hello World with Java Servlet and JSP (Easy web server startup with Maven + Jetty)
Of the three Java embedded web servers, Tomcat, Jetty, and Undertow, which one worked with GraalVM?
Rails web server and application server
Comparison of WEB application development with Rails and Java Servlet + JSP
[Tips] How to solve problems with XCode and Swift for beginners