package org.voovan.http.server.context; import org.voovan.http.server.HttpRequest; import org.voovan.http.server.HttpResponse; import org.voovan.tools.*; import org.voovan.tools.json.JSONDecode; import org.voovan.tools.log.Logger; import org.voovan.tools.log.SingleLogger; import org.voovan.tools.reflect.TReflect; import java.io.File; import java.io.UnsupportedEncodingException; import java.text.ParseException; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * Web上下文(配置信息读取) * @author helyho * * Voovan Framework. * WebSite: https://github.com/helyho/Voovan * Licence: Apache v2 License */ public class WebContext { private static final String VERSION = "Voovan-WebServer/V1.5.2"; private static final String SESSION_NAME = "VOOVAN_SESSIONID"; /** * Web Config */ private static final Map<String, Object> WEB_CONFIG = loadMapFromFile("/conf/web.json"); /** * MimeMap */ private static final Map<String, Object> MIME_TYPES = getMimeDefine(); /** * 错误输出 Map */ private static final Map<String, Object> ERROR_DEFINE = loadMapFromFile("/conf/error.json"); /** * accessLog 的文件路径 */ private static final String ACCESS_LOG_FILE_NAME = TFile.getContextPath()+File.separator+"logs"+File.separator+"access.log"; private static WebServerConfig webServerConfig = initWebServerConfig(); private WebContext(){ } /** * 从 js 配置文件读取配置信息到 Map * @param filePath * @return */ private static Map<String, Object> loadMapFromFile(String filePath){ if(TFile.fileExists(TFile.getSystemPath(filePath))) { String fileContent = null; try { fileContent = new String(TFile.loadFileFromContextPath(filePath),"UTF-8"); Object configObject = JSONDecode.parse(fileContent); return TObject.cast(configObject); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } return new HashMap<String,Object>(); } /** * 从配置文件初始化 config 对象 * @return */ private static WebServerConfig initWebServerConfig() { WebServerConfig config = new WebServerConfig(); //使用反射工具自动加载配置信息 try { config = (WebServerConfig) TReflect.getObjectFromMap(WebServerConfig.class, WEB_CONFIG, true); config = TObject.nullDefault(config, new WebServerConfig()); } catch (ReflectiveOperationException e) { Logger.error(e); } catch (ParseException e) { Logger.error(e); } //如果是相对路径则转换成绝对路 if(!config.getContextPath().startsWith(File.separator)){ config.setContextPath(System.getProperty("user.dir")+File.separator+config.getContextPath()); } if(config.getContextPath().endsWith(File.separator)){ config.setContextPath(TString.removeSuffix(config.getContextPath())); } return config; } public static void initWebServerPlugin(){ //初始化过滤器 webServerConfig.addFilterByList(getContextParameter("Filters",new ArrayList<Map<String,Object>>())); //初始路由处理器 webServerConfig.addRouterByList(getContextParameter("Routers",new ArrayList<Map<String,Object>>())); //初始化模块 webServerConfig.addModuleByList(getContextParameter("Modules",new ArrayList<Map<String,Object>>())); Logger.simple("============================================================================================="); } /** * 获取WebServer配置对象 * @return WebServer配置对象 */ public static WebServerConfig getWebServerConfig(){ return webServerConfig; } /** * 显示欢迎信息 * @param config WebServer配置对象 */ public static void welcome(WebServerConfig config){ Logger.simple("*********************************************************************************************"); Logger.simple(""); Logger.simple(" == == ========== ========== == == ==== == == == "); Logger.simple(" == == == == == == == == == == == == == "); Logger.simple(" == == == == == == == == == == == == == "); Logger.simple(" == == == == == == == == == == == == == "); Logger.simple(" == == == == == == == == ============ == == == "); Logger.simple(" == == == == == == == == == == == == == "); Logger.simple(" ==== ========== ========== ==== == == == == == "); Logger.simple(""); Logger.simple("*********************************************************************************************"); Logger.simple(""); Logger.simple("============================== [Config file parameter list] ================================="); Logger.simple(TString.rightPad(" Timeout:",35,' ')+config.getTimeout()); Logger.simple(TString.rightPad(" ContextPath:",35,' ')+config.getContextPath()); Logger.simple(TString.rightPad(" CharacterSet: ",35,' ')+config.getCharacterSet()); Logger.simple(TString.rightPad(" SessionContainer:",35,' ')+config.getSessionContainer()); Logger.simple(TString.rightPad(" SessionTimeout:",35,' ')+config.getSessionTimeout()); Logger.simple(TString.rightPad(" KeepAliveTimeout:",35,' ')+config.getKeepAliveTimeout()); Logger.simple(TString.rightPad(" MatchRouteIgnoreCase:",35,' ')+config.isMatchRouteIgnoreCase()); Logger.simple(TString.rightPad(" Gzip:",35,' ')+ config.isGzip()); Logger.simple(TString.rightPad(" AccessLog:",35,' ')+ config.isAccessLog()); if(config.isHttps()) { Logger.simple(TString.rightPad(" CertificateFile:",35,' ')+config.getHttps().getCertificateFile()); Logger.simple(TString.rightPad(" CertificatePassword:",35,' ')+config.getHttps().getCertificatePassword()); Logger.simple(TString.rightPad(" KeyPassword:",35,' ')+config.getHttps().getKeyPassword()); } Logger.simple("============================================================================================="); Logger.simple(" This WebServer based on VoovanFramework."); Logger.simple(" Version: "+WebContext.getVERSION()); Logger.simple(" WebSite: http://www.voovan.org"); Logger.simple(" Author: helyho"); Logger.simple(" E-mail: helyho@gmail.com"); Logger.simple("============================================================================================="); } /** * 生成 accessLog 日志 * @param request HTTP 请求对象 * @param response HTTP 响应对象 * @return 日志信息 */ private static String genAccessLog(HttpRequest request, HttpResponse response){ StringBuilder content = new StringBuilder(); content.append("["+TDateTime.now()+"]"); content.append(" "+TString.rightPad(request.getRemoteAddres(),15,' ')); content.append(" "+TString.rightPad(request.getRemotePort()+"",5,' ')); content.append(" "+request.protocol().getProtocol()+"/"+request.protocol().getVersion()+" "+TString.rightPad(request.protocol().getMethod(),6,' ')); content.append(" "+response.protocol().getStatus()); content.append(" "+response.body().getBodyBytes().length); content.append("\t "+request.protocol().getPath()); content.append("\t "+TObject.nullDefault(request.header().get("User-Agent"),"")); content.append("\t "+TObject.nullDefault(request.header().get("Referer"),"")); content.append("\r\n"); return content.toString(); } /** * 写入access.log * @param request HTTP 请求对象 * @param response HTTP 响应对象 */ public static void writeAccessLog(HttpRequest request,HttpResponse response){ //配置文件控制是否写入 access.log //监控程序的不写出 access.log if(webServerConfig.isAccessLog() && !request.protocol().getPath().contains("/VoovanMonitor/")) { SingleLogger.writeLog(ACCESS_LOG_FILE_NAME, genAccessLog(request, response)); } } /** * 取配置中的参数定义 * @param <T> 范型 * @param name 参数名 * @param defaultValue 默认值 * @return 参数定义 */ @SuppressWarnings("unchecked") public static <T> T getContextParameter(String name, T defaultValue) { return TObject.nullDefault((T) WEB_CONFIG.get(name),defaultValue); } /** * 获取 mime 定义 * @return MIME 定义 Map */ public static Map<String, Object> getMimeDefine() { byte[] mimeDefBytes = TFile.loadResource("org/voovan/http/server/conf/mime.json"); Map<String, Object> mimeDefMap = new ConcurrentHashMap<String, Object>(); try { Map<String, Object> systemMimeDef = TObject.cast(JSONDecode.parse(new String(mimeDefBytes,"UTF-8"))); mimeDefMap.putAll(systemMimeDef); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } mimeDefMap.putAll(loadMapFromFile("/conf/mime.json")); return mimeDefMap; } /** * 获取错误输出定义 * @return 错误输出定义 */ public static Map<String, Object> getErrorDefine() { return ERROR_DEFINE; } /** * 获取版本号 * @return 版本号 */ public final static String getVERSION() { return VERSION; } /** * 获取在 Cookie 中保存 session id 的名称 * @return session id 的名称 */ public static String getSessionName() { return SESSION_NAME; } /** * 默认错误输出定义 * @return 错误输出定义 */ public static String getDefaultErrorPage(){ return "RequestMethod: {{RequestMethod}} <hr/>" + "StatusCode: {{StatusCode}} <hr/>" + "RequestPath: {{RequestPath}} <hr/>" + "ErrorMessage: {{ErrorMessage}} <hr/>" + "Version: {{Version}} <hr/>" + "Description: <br>{{Description}} <hr/>"; } }