升级JFinal内置的jetty到9版本,并且支持ssl

JFinal本事内置的jetty8已经基本满足开发需求。由于本人是版本控,同时想在某些小型项目中直接用内置的jetty运行。

于是将内置的jetty升级到9.由于jetty9盒jetty8变化很大。所以几乎需要重写com.jfinal.server.JettyServer的doStart方法。需要引入jetty9的jar包。

最新的Jetty 9.3.0.v20150612 最低要求java8

代码如下:

/**
 * Copyright (c) 2011-2015, James Zhan 詹波 ([email protected]).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.jfinal.server;

import java.io.File;
import java.io.IOException;
import java.net.DatagramSocket;
import java.net.ServerSocket;
import java.util.EnumSet;

import javax.servlet.DispatcherType;

import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.SecureRequestCustomizer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.SessionManager;
import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.server.session.HashSessionManager;
import org.eclipse.jetty.server.session.SessionHandler;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.webapp.WebAppContext;

import com.jfinal.core.Const;
import com.jfinal.kit.FileKit;
import com.jfinal.kit.PathKit;
import com.jfinal.kit.StrKit;

/**
 * JettyServer is used to config and start jetty web server.
 * Jetty version 8.1.8
 */
class JettyServer implements IServer {

	private String webAppDir;
	private int port;
	private String context;
	private int scanIntervalSeconds;
	private boolean running = false;
	private Server server;
	private WebAppContext webApp;

	private String keyStorePath = null;
	private String keyStorePassword = null;
	private String keyManagerPassword = null;

	JettyServer(String webAppDir, int port, String context, int scanIntervalSeconds) {
		if (webAppDir == null)
			throw new IllegalStateException("Invalid webAppDir of web server: " + webAppDir);
		if (port < 0 || port > 65536)
			throw new IllegalArgumentException("Invalid port of web server: " + port);
		if (StrKit.isBlank(context))
			throw new IllegalStateException("Invalid context of web server: " + context);

		this.webAppDir = webAppDir;
		this.port = port;
		this.context = context;
		this.scanIntervalSeconds = scanIntervalSeconds;
	}

	JettyServer(String webAppDir, int port, String context, String keyStorePath,String keyStorePassword,String keyManagerPassword) {
		this(webAppDir,port,context,0);
		this.keyManagerPassword = keyManagerPassword;
		this.keyStorePassword = keyStorePassword;
		this.keyStorePath = keyStorePath;
	}

	public void start() {
		if (!running) {
			try {doStart();} catch (Exception e) {e.printStackTrace();}
			running = true;
		}
	}

	public void stop() {
		if (running) {
			try {webApp.stop();server.stop();} catch (Exception e) {e.printStackTrace();}
			running = false;
		}
	}

	private void doStart() {
		if (!available(port))
			throw new IllegalStateException("port: " + port + " already in use!");

		deleteSessionData();

		System.out.println("Starting JFinal " + Const.JFINAL_VERSION);
		server = new Server();

		//httl配置。
		if(null == this.keyStorePath){
			HttpConfiguration http_config = new HttpConfiguration();	        // HTTP connector
	        ServerConnector connector = new ServerConnector(server,new HttpConnectionFactory(http_config));
			connector.setReuseAddress(true);
			connector.setIdleTimeout(30000);

			connector.setPort(port);
			server.addConnector(connector);
		}else{
			//https 配置
			HttpConfiguration https_config = new HttpConfiguration();
			https_config.setSecureScheme("https");
			https_config.setSecurePort(port);
			https_config.setOutputBufferSize(32768);
			https_config.addCustomizer(new SecureRequestCustomizer());
			SslContextFactory sslContextFactory = new SslContextFactory();
	        sslContextFactory.setKeyStorePath(this.keyStorePath);
	        sslContextFactory.setKeyStorePassword(this.keyStorePassword);
	        sslContextFactory.setKeyManagerPassword(this.keyManagerPassword);
	        ServerConnector httpsConnector = new ServerConnector(server,
	                new SslConnectionFactory(sslContextFactory,"http/1.1"),
	                new HttpConnectionFactory(https_config));
	        httpsConnector.setPort(port);
	        httpsConnector.setIdleTimeout(500000);
	        server.addConnector(httpsConnector);
		}

		webApp = new WebAppContext();
	    /**
		 * 增加gzip支持
		 */
		FilterHolder  fh = new FilterHolder();
		fh.setAsyncSupported(true);
		fh.setClassName("org.eclipse.jetty.servlets.GzipFilter");
		fh.setInitParameter("mimeTypes", "text/html,text/plain,text/xml,text/css,text/javascript,application/javascript,image/gif,image/png");
		EnumSet<DispatcherType> set = EnumSet.noneOf(DispatcherType.class);
		set.add(DispatcherType.REQUEST);
		set.add(DispatcherType.FORWARD);
		set.add(DispatcherType.INCLUDE);
		set.add(DispatcherType.ERROR);
		set.add(DispatcherType.ASYNC);
		webApp.addFilter(fh, "/*", set);

		webApp.setContextPath(context);
		webApp.setResourceBase(webAppDir);
		webApp.setMaxFormContentSize(81920000);
		webApp.getInitParams().put("org.eclipse.jetty.servlet.Default.dirAllowed", "false");
		webApp.getInitParams().put("org.eclipse.jetty.servlet.Default.useFileMappedBuffer", "true");
		webApp.getInitParams().put("org.eclipse.jetty.server.Request.maxFormContentSize", "-1");

		persistSession(webApp);

		server.setHandler(webApp);
		changeClassLoader(webApp);

		// configureScanner
		if (scanIntervalSeconds > 0) {
			Scanner scanner = new Scanner(PathKit.getRootClassPath(), scanIntervalSeconds) {
				public void onChange() {
					try {
						System.err.println("\nLoading changes ......");
						webApp.stop();
						JFinalClassLoader loader = new JFinalClassLoader(webApp, getClassPath());
						webApp.setClassLoader(loader);
						webApp.start();
						System.err.println("Loading complete.");
					} catch (Exception e) {
						System.err.println("Error reconfiguring/restarting webapp after change in watched files");
						e.printStackTrace();
					}
				}
			};
			System.out.println("Starting scanner at interval of " + scanIntervalSeconds + " seconds.");
			scanner.start();
		}

		try {
			System.out.println("Starting web server on port: " + port);
			server.start();
			System.out.println("Starting Complete. Welcome To The JFinal World :)");
			server.join();
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(100);
		}
		return;
	}

	@SuppressWarnings("resource")
	private void changeClassLoader(WebAppContext webApp) {
		try {
			String classPath = getClassPath();
			JFinalClassLoader wacl = new JFinalClassLoader(webApp, classPath);
			wacl.addClassPath(classPath);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private String getClassPath() {
		return System.getProperty("java.class.path");
	}

	private void deleteSessionData() {
		try {
			FileKit.delete(new File(getStoreDir()));
		}
		catch (Exception e) {
		}
	}

	private String getStoreDir() {
		String storeDir = PathKit.getWebRootPath() + "/../../session_data" + context;
		if ("\\".equals(File.separator))
			storeDir = storeDir.replaceAll("/", "\\\\");
		return storeDir;
	}

	private void persistSession(WebAppContext webApp) {
		String storeDir = getStoreDir();

		SessionManager sm = webApp.getSessionHandler().getSessionManager();
		if (sm instanceof HashSessionManager) {
			try {
				((HashSessionManager)sm).setStoreDirectory(new File(storeDir));
			} catch (IOException e) {
				e.printStackTrace();
			}
			return ;
		}

		HashSessionManager hsm = new HashSessionManager();
		try {
			hsm.setStoreDirectory(new File(storeDir));
		} catch (IOException e) {
			e.printStackTrace();
		}
		SessionHandler sh = new SessionHandler();
		sh.setSessionManager(hsm);
		webApp.setSessionHandler(sh);
	}

	private static boolean available(int port) {
		if (port <= 0) {
			throw new IllegalArgumentException("Invalid start port: " + port);
		}

		ServerSocket ss = null;
		DatagramSocket ds = null;
		try {
			ss = new ServerSocket(port);
			ss.setReuseAddress(true);
			ds = new DatagramSocket(port);
			ds.setReuseAddress(true);
			return true;
		} catch (IOException e) {
		} finally {
			if (ds != null) {
				ds.close();
			}

			if (ss != null) {
				try {
					ss.close();
				} catch (IOException e) {
					// should not be thrown, just detect port available.
				}
			}
		}
		return false;
	}
}

为了支持ssl还得修改com.jfinal.core.JFinal实现,增加相应的方法。

public static void startSSLServer(String webAppDir, int port, String context, String keyStorePath,String keyStorePassword,String keyManagerPassword) {
		server = ServerFactory.getHttpsServer(webAppDir, port, context, keyStorePath, keyStorePassword, keyManagerPassword);
		server.start();
	}

jetty-all下载地址

http://repo1.maven.org/maven2/org/eclipse/jetty/aggregate/jetty-all/

时间: 2024-10-01 00:29:02

升级JFinal内置的jetty到9版本,并且支持ssl的相关文章

Windows 10 之删除内置应用

Windows 10预装了很多内置应用,其中有部分应用或许我们不喜欢,那么这些预装的如何彻底清除呢?其实这些内置应用,部分是可以删除.要注意的是,执行以下操作后会将应用商店也一并删除,目前也没有找回的方法,系统推送的某些更新会重新在系统中安装应用商店.另外,并不是所有的内置应用都能删除.部分内置应用,比如Cortana.联系支持人员.Edge浏览器.Windows反馈,设置和搜索无法从系统中删除. 方法一:用PowerSell命令进行删除(以管理员身份运行) OneNote: Get-AppxP

nginx内置变量 大全

nginx内置变量 内置变量存放在  ngx_http_core_module 模块中,变量的命名方式和apache 服务器变量是一致的.总而言之,这些变量代表着客户端请求头的内容,例如$http_user_agent, $http_cookie, 等等.下面是nginx支持的所有内置变量: $arg_name请求中的的参数名,即"?"后面的arg_name=arg_value形式的arg_name $args请求中的参数值 $binary_remote_addr客户端地址的二进制形式

Activiti系列: 如何给内置表单添加字段类型

对于内置的表单,除了原来支持的几种数据类型(string, long, enum, date, boolean, collection)之外,还可以自定义数据类型,比如增加一个javascript数据类型 需要增加一个自定义数据类型的处理类 public class JavascriptFormType extends AbstractFormType { @override public string getName() { return "javascript";} @overri

迅雷9窗口右侧的内置浏览器如何去掉。

迅雷9窗口右侧的内置浏览器如何去掉. 2016年6月,迅雷发布了全新迅雷9的正式版,相信很多读者对迅雷9窗口右侧的内置浏览器深恶痛绝. 早期版本的迅雷9会在窗口右侧的内置浏览器里自动播放视频,可能是迫于用户的压力,也可能是迅雷自己意识到这样做比较过分,于是在后来的版本中,迅雷对该页面进行了改版,不再自动播放视频. 结果改成了这个样子…… 今天,就教大家如何“干掉”迅雷9窗口右侧的内置浏览器. 操作简单但是不彻底的方法 退出迅雷9. 打开文件资源管理器(此电脑),进入以下目录: C:\Progra

05python 的内置函数以及匿名函数(python函数)

内置函数 截止到python版本3.6.2,现在python一共为我们提供了68个内置函数.它们就是python提供给你直接可以拿来使用的所有函数. 作用域相关 print(globals()) # 返回本地作用域中的所有名字 print(locals()) # 返回全局作用域中的所有名字 注意与函数中的global.local.nonlocal 关键字的区别 生成器迭代器相关 for i in range(10): print(i, end=' ') >>>0 1 2 3 4 5 6

Spydroid还是大牛直播内置RTSP服务SDK

废话不多说,先列二者功能: 1. Spydroid: The stream can be directly read by VLC which is great because VLC is a very powerful tool, for example you can really easily record the stream in a file. [FAQ See the FAQ to find out how]. You can enable/disable sound or vi

用Autofac替换.net core 内置容器

原文:用Autofac替换.net core 内置容器 官方建议使用内置容器,但有些功能并不支持,如下: 属性注入 基于名称的注入 子容器 自定义生存期管理 Func<T> 支持 所以可以使用其他第三方IOC容器,如Autofac,下面为学习使用记录 一.首先准备了一个接口和其实现类 public interface ITestService { string ShowMsg(); } public class TestService: ITestService { public string

【Python】【基础知识】【内置函数】【help的使用方法】

原英文帮助文档: help([object]) Invoke the built-in help system. (This function is intended for interactive use.) If no argument is given, the interactive help system starts on the interpreter console. If the argument is a string, then the string is looked u

win7升级win10激活指南——查看预装Win7/8/8.1电脑内置系统激活密钥(OEM Key)方法

1.AIDA64 查看内置Win8/8.1 OEM Key 首先下载aida64工具:AIDA64 的前身是EVEREST.在16位系统时代EVEREST叫AIDA16,随着32位技术的出现遂改名为AIDA32,之后又一次更名就成了EVEREST.现在它的开发商LavaAIDA6lys公司已经被FinalWire收购,就变成了现在的名字--AIDA64. [download title="AIDA64 下载" info="v3.00.2529 Beta" time=