package org.jim.server.http; import java.beans.PropertyDescriptor; import java.io.File; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ExecutionException; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.tio.core.ChannelContext; import org.jim.common.http.Cookie; import org.jim.common.http.HttpConfig; import org.jim.common.http.HttpConst; import org.jim.common.http.HttpRequest; import org.jim.common.http.HttpResponse; import org.jim.common.http.HttpResponseStatus; import org.jim.common.http.RequestLine; import org.jim.common.http.handler.IHttpRequestHandler; import org.jim.common.http.listener.IHttpServerListener; import org.jim.common.http.session.HttpSession; import org.jim.server.http.mvc.Routes; import org.jim.server.util.ClassUtils; import org.jim.server.util.HttpResps; import org.tio.utils.cache.guava.GuavaCache; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.convert.Convert; import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.ClassUtil; /** * * @author WChao * */ public class DefaultHttpRequestHandler implements IHttpRequestHandler { private static Logger log = LoggerFactory.getLogger(DefaultHttpRequestHandler.class); // /** // * 静态资源的CacheName // * key: path 譬如"/index.html" // * value: HttpResponse // */ // private static final String STATIC_RES_CACHENAME = "TIO_HTTP_STATIC_RES"; /** * 静态资源的CacheName * key: path 譬如"/index.html" * value: FileCache */ private static final String STATIC_RES_CONTENT_CACHENAME = "TIO_HTTP_STATIC_RES_CONTENT"; /** * @param args * * @author WChao * 2016年11月18日 上午9:13:15 * */ public static void main(String[] args) { } protected HttpConfig httpConfig; protected Routes routes = null; // private LoadingCache loadingCache = null; private IHttpServerListener httpServerListener; private GuavaCache staticResCache; /** * * @param httpConfig * @author WChao */ public DefaultHttpRequestHandler(HttpConfig httpConfig) { this.httpConfig = httpConfig; if (httpConfig.getMaxLiveTimeOfStaticRes() > 0) { // GuavaCache.register(STATIC_RES_CACHENAME, (long) httpConfig.getMaxLiveTimeOfStaticRes(), null); staticResCache = GuavaCache.register(STATIC_RES_CONTENT_CACHENAME, (long) httpConfig.getMaxLiveTimeOfStaticRes(), null); } this.setHttpServerListener(httpConfig.getHttpServerListener()); } /** * * @param httpConfig * @param routes * @author WChao */ public DefaultHttpRequestHandler(HttpConfig httpConfig, Routes routes) { this(httpConfig); this.routes = routes; } /** * 创建httpsession * @return * @author WChao */ private HttpSession createSession() { String sessionId = httpConfig.getSessionIdGenerator().sessionId(httpConfig); HttpSession httpSession = new HttpSession(sessionId); return httpSession; } /** * @return the httpConfig */ public HttpConfig getHttpConfig() { return httpConfig; } public IHttpServerListener getHttpServerListener() { return httpServerListener; } private Cookie getSessionCookie(HttpRequest request, HttpConfig httpConfig) throws ExecutionException { Cookie sessionCookie = request.getCookie(httpConfig.getSessionCookieName()); return sessionCookie; } /** * @return the staticResCache */ public GuavaCache getStaticResCache() { return staticResCache; } @Override public HttpResponse handler(HttpRequest request, RequestLine requestLine) throws Exception { log.info("执行 DefaultHttpRequestHandler.handler()方法..."); HttpResponse ret = null; try { processCookieBeforeHandler(request, requestLine); HttpSession httpSession = request.getHttpSession();//(HttpSession) channelContext.getAttribute(); if (httpServerListener != null) { ret = httpServerListener.doBeforeHandler(request, requestLine, ret); if (ret != null) { return ret; } } String path = requestLine.getPath(); String initPath = path; Method method = routes.pathMethodMap.get(initPath); if (method != null) { String[] paramNames = routes.methodParamnameMap.get(method); Class[] parameterTypes = method.getParameterTypes(); Object bean = routes.methodBeanMap.get(method); Object obj = null; Map params = request.getParams(); if (parameterTypes == null || parameterTypes.length == 0) { obj = method.invoke(bean); } else { //赋值这段代码待重构,先用上 Object[] paramValues = new Object[parameterTypes.length]; int i = 0; for (Class paramType : parameterTypes) { try { if (paramType.isAssignableFrom(HttpRequest.class)) { paramValues[i] = request; } else if (paramType == HttpSession.class) { paramValues[i] = httpSession; } else if (paramType.isAssignableFrom(HttpConfig.class)) { paramValues[i] = httpConfig; } else if (paramType.isAssignableFrom(ChannelContext.class)) { paramValues[i] = request.getChannelContext(); } else { if (params != null) { if (ClassUtils.isSimpleTypeOrArray(paramType)) { Object[] value = params.get(paramNames[i]); if (value != null && value.length > 0) { if (paramType.isArray()) { paramValues[i] = Convert.convert(paramType, value); } else { paramValues[i] = Convert.convert(paramType, value[0]); } } } else { paramValues[i] = paramType.newInstance();//BeanUtil.mapToBean(params, paramType, true); Set> set = params.entrySet(); label2: for (Entry entry : set) { String fieldName = entry.getKey(); Object[] fieldValue = entry.getValue(); PropertyDescriptor propertyDescriptor = BeanUtil.getPropertyDescriptor(paramType, fieldName, true); if (propertyDescriptor == null) { continue label2; } else { Method writeMethod = propertyDescriptor.getWriteMethod(); if (writeMethod == null) { continue label2; } writeMethod = ClassUtil.setAccessible(writeMethod); Class[] clazzes = writeMethod.getParameterTypes(); if (clazzes == null || clazzes.length != 1) { log.info("方法的参数长度不为1,{}.{}", paramType.getName(), writeMethod.getName()); continue label2; } Class clazz = clazzes[0]; if (ClassUtils.isSimpleTypeOrArray(clazz)) { if (fieldValue != null && fieldValue.length > 0) { if (clazz.isArray()) { writeMethod.invoke(paramValues[i], Convert.convert(clazz, fieldValue)); } else { writeMethod.invoke(paramValues[i], Convert.convert(clazz, fieldValue[0])); } } } } } } } } } catch (Exception e) { log.error(e.toString(), e); } finally { i++; } } obj = method.invoke(bean, paramValues); } if (obj instanceof HttpResponse) { ret = (HttpResponse) obj; return ret; } else { throw new Exception(bean.getClass().getName() + "#" + method.getName() + "返回的对象不是" + HttpResponse.class.getName()); } } else { GuavaCache contentCache = null; FileCache fileCache = null; if (httpConfig.getMaxLiveTimeOfStaticRes() > 0) { contentCache = GuavaCache.getCache(STATIC_RES_CONTENT_CACHENAME); fileCache = (FileCache) contentCache.get(initPath); } if (fileCache != null) { byte[] bodyBytes = fileCache.getData(); Map headers = fileCache.getHeaders(); long lastModified = fileCache.getLastModified(); log.info("从缓存获取:[{}], {}", path, bodyBytes.length); ret = HttpResps.try304(request, lastModified); if (ret != null) { ret.addHeader(HttpConst.ResponseHeaderKey.tio_from_cache, "true"); return ret; } ret = new HttpResponse(request, httpConfig); ret.setBody(bodyBytes, request); ret.addHeaders(headers); return ret; } else { String root = FileUtil.getAbsolutePath(httpConfig.getPageRoot()); File file = new File(root + path); if (!file.exists() || file.isDirectory()) { if (StringUtils.endsWith(path, "/")) { path = path + "index.html"; } else { path = path + "/index.html"; } file = new File(root, path); } if (file.exists()) { ret = HttpResps.file(request, file); ret.setStaticRes(true); if (contentCache != null && request.getIsSupportGzip()) { if (ret.getBody() != null && ret.getStatus() == HttpResponseStatus.C200) { String contentType = ret.getHeader(HttpConst.ResponseHeaderKey.Content_Type); String contentEncoding = ret.getHeader(HttpConst.ResponseHeaderKey.Content_Encoding); String lastModified = ret.getHeader(HttpConst.ResponseHeaderKey.Last_Modified); Map headers = new HashMap<>(); if (StringUtils.isNotBlank(contentType)) { headers.put(HttpConst.ResponseHeaderKey.Content_Type, contentType); } if (StringUtils.isNotBlank(contentEncoding)) { headers.put(HttpConst.ResponseHeaderKey.Content_Encoding, contentEncoding); } if (StringUtils.isNotBlank(lastModified)) { headers.put(HttpConst.ResponseHeaderKey.Last_Modified, lastModified); } headers.put(HttpConst.ResponseHeaderKey.tio_from_cache, "true"); fileCache = new FileCache(headers, file.lastModified(), ret.getBody()); contentCache.put(initPath, fileCache); log.info("放入缓存:[{}], {}", initPath, ret.getBody().length); } } return ret; } } } ret = resp404(request, requestLine);//Resps.html(request, "404--并没有找到你想要的内容", httpConfig.getCharset()); return ret; } catch (Exception e) { logError(request, requestLine, e); ret = resp500(request, requestLine, e);//Resps.html(request, "500--服务器出了点故障", httpConfig.getCharset()); return ret; } finally { if (ret != null) { try { processCookieAfterHandler(request, requestLine, ret); if (httpServerListener != null) { httpServerListener.doAfterHandler(request, requestLine, ret); } } catch (Exception e) { logError(request, requestLine, e); } } } } private void logError(HttpRequest request, RequestLine requestLine, Exception e) { StringBuilder sb = new StringBuilder(); sb.append("\r\n").append("remote :").append(request.getRemote()); sb.append("\r\n").append("request :").append(requestLine.getLine()); log.error(sb.toString(), e); } private void processCookieAfterHandler(HttpRequest request, RequestLine requestLine, HttpResponse httpResponse) throws ExecutionException { HttpSession httpSession = request.getHttpSession();//(HttpSession) channelContext.getAttribute();//.getHttpSession();//not null Cookie cookie = getSessionCookie(request, httpConfig); String sessionId = null; if (cookie == null) { String domain = request.getHeader(HttpConst.RequestHeaderKey.Host); String name = httpConfig.getSessionCookieName(); long maxAge = httpConfig.getSessionTimeout(); // maxAge = Integer.MAX_VALUE; //把过期时间掌握在服务器端 sessionId = httpSession.getId();//randomCookieValue(); cookie = new Cookie(domain, name, sessionId, maxAge); httpResponse.addCookie(cookie); httpConfig.getSessionStore().put(sessionId, httpSession); log.info("{} 创建会话Cookie, {}", request.getChannelContext(), cookie); } else { sessionId = cookie.getValue(); HttpSession httpSession1 = (HttpSession) httpConfig.getSessionStore().get(sessionId); if (httpSession1 == null) {//有cookie但是超时了 sessionId = httpSession.getId(); String domain = request.getHeader(HttpConst.RequestHeaderKey.Host); String name = httpConfig.getSessionCookieName(); long maxAge = httpConfig.getSessionTimeout(); // maxAge = Long.MAX_VALUE; //把过期时间掌握在服务器端 cookie = new Cookie(domain, name, sessionId, maxAge); httpResponse.addCookie(cookie); httpConfig.getSessionStore().put(sessionId, httpSession); } } } private void processCookieBeforeHandler(HttpRequest request, RequestLine requestLine) throws ExecutionException { Cookie cookie = getSessionCookie(request, httpConfig); HttpSession httpSession = null; if (cookie == null) { httpSession = createSession(); } else { String sessionId = cookie.getValue(); httpSession = (HttpSession) httpConfig.getSessionStore().get(sessionId); if (httpSession == null) { log.info("{} session【{}】超时", request.getChannelContext(), sessionId); httpSession = createSession(); } } request.setHttpSession(httpSession); } @Override public HttpResponse resp404(HttpRequest request, RequestLine requestLine) { String file404 = httpConfig.getPage404(); String root = FileUtil.getAbsolutePath(httpConfig.getPageRoot()); File file = new File(root + file404); if (file.exists()) { HttpResponse ret = HttpResps.redirect(request, file404 + "?tio_initpath=" + requestLine.getPathAndQuery()); return ret; } else { HttpResponse ret = HttpResps.html(request, "404"); return ret; } } @Override public HttpResponse resp500(HttpRequest request, RequestLine requestLine, Throwable throwable) { String file500 = httpConfig.getPage500(); String root = FileUtil.getAbsolutePath(httpConfig.getPageRoot()); File file = new File(root + file500); if (file.exists()) { HttpResponse ret = HttpResps.redirect(request, file500 + "?tio_initpath=" + requestLine.getPathAndQuery()); return ret; } else { HttpResponse ret = HttpResps.html(request, "500"); return ret; } } /** * @param httpConfig the httpConfig to set */ public void setHttpConfig(HttpConfig httpConfig) { this.httpConfig = httpConfig; } public void setHttpServerListener(IHttpServerListener httpServerListener) { this.httpServerListener = httpServerListener; } /** * @param staticResCache the staticResCache to set */ public void setStaticResCache(GuavaCache staticResCache) { this.staticResCache = staticResCache; } @Override public void clearStaticResCache(HttpRequest request) { if (staticResCache != null) { staticResCache.clear(); } } }