From d612387a37410f374a020a565822329bb5cd696c Mon Sep 17 00:00:00 2001 From: "awayy1432@163.com" Date: Sun, 25 May 2014 01:40:45 +0800 Subject: [PATCH 1/2] init --- .classpath | 9 + .gitignore | 2 + .project | 23 ++ .settings/org.eclipse.jdt.core.prefs | 12 + .settings/org.maven.ide.eclipse.prefs | 7 + pom.xml | 40 ++++ .../eh/core/annotation/AnnocationHandler.java | 66 ++++++ .../org/eh/core/annotation/Controller.java | 28 +++ .../eh/core/annotation/RequestMapping.java | 19 ++ .../java/org/eh/core/common/Constants.java | 27 +++ .../org/eh/core/http/ApplicationContext.java | 124 ++++++++++ .../java/org/eh/core/http/EHHttpHandler.java | 212 ++++++++++++++++++ src/main/java/org/eh/core/http/EHServer.java | 71 ++++++ .../java/org/eh/core/http/HttpSession.java | 55 +++++ .../java/org/eh/core/model/ResultInfo.java | 31 +++ .../org/eh/core/task/SessionCleanTask.java | 45 ++++ src/main/java/org/eh/core/util/IOUtil.java | 89 ++++++++ .../java/org/eh/core/util/StringUtil.java | 20 ++ .../eh/core/web/controller/Controller.java | 11 + .../core/web/controller/IndexController.java | 37 +++ .../org/eh/core/web/view/ViewHandler.java | 56 +++++ src/main/view/page/index.page | 12 + src/main/view/static/js/test.js | 3 + src/main/view/static/pic/tx.jpg | Bin 0 -> 41853 bytes 24 files changed, 999 insertions(+) create mode 100644 .classpath create mode 100644 .gitignore create mode 100644 .project create mode 100644 .settings/org.eclipse.jdt.core.prefs create mode 100644 .settings/org.maven.ide.eclipse.prefs create mode 100644 pom.xml create mode 100644 src/main/java/org/eh/core/annotation/AnnocationHandler.java create mode 100644 src/main/java/org/eh/core/annotation/Controller.java create mode 100644 src/main/java/org/eh/core/annotation/RequestMapping.java create mode 100644 src/main/java/org/eh/core/common/Constants.java create mode 100644 src/main/java/org/eh/core/http/ApplicationContext.java create mode 100644 src/main/java/org/eh/core/http/EHHttpHandler.java create mode 100644 src/main/java/org/eh/core/http/EHServer.java create mode 100644 src/main/java/org/eh/core/http/HttpSession.java create mode 100644 src/main/java/org/eh/core/model/ResultInfo.java create mode 100644 src/main/java/org/eh/core/task/SessionCleanTask.java create mode 100644 src/main/java/org/eh/core/util/IOUtil.java create mode 100644 src/main/java/org/eh/core/util/StringUtil.java create mode 100644 src/main/java/org/eh/core/web/controller/Controller.java create mode 100644 src/main/java/org/eh/core/web/controller/IndexController.java create mode 100644 src/main/java/org/eh/core/web/view/ViewHandler.java create mode 100644 src/main/view/page/index.page create mode 100644 src/main/view/static/js/test.js create mode 100644 src/main/view/static/pic/tx.jpg diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..ed2609d --- /dev/null +++ b/.classpath @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..934e0e0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/bin +/target diff --git a/.project b/.project new file mode 100644 index 0000000..de8dd46 --- /dev/null +++ b/.project @@ -0,0 +1,23 @@ + + + learn-1 + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.maven.ide.eclipse.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.maven.ide.eclipse.maven2Nature + + diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..6249222 --- /dev/null +++ b/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,12 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.7 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.7 diff --git a/.settings/org.maven.ide.eclipse.prefs b/.settings/org.maven.ide.eclipse.prefs new file mode 100644 index 0000000..cfdba58 --- /dev/null +++ b/.settings/org.maven.ide.eclipse.prefs @@ -0,0 +1,7 @@ +activeProfiles= +eclipse.preferences.version=1 +fullBuildGoals=process-test-resources +resolveWorkspaceProjects=true +resourceFilterGoals=process-resources resources\:testResources +skipCompilerPlugin=true +version=1 diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..4579e0c --- /dev/null +++ b/pom.xml @@ -0,0 +1,40 @@ + + 4.0.0 + + learn-1 + learn-1 + 0.0.1-SNAPSHOT + jar + + learn-1 + http://maven.apache.org + + + UTF-8 + + + + + commons-logging + commons-logging + 1.1.3 + + + junit + junit + 4.10 + test + + + + + easy-httpserver + + + ${basedir}/src/main/view + + + + + diff --git a/src/main/java/org/eh/core/annotation/AnnocationHandler.java b/src/main/java/org/eh/core/annotation/AnnocationHandler.java new file mode 100644 index 0000000..5014dd3 --- /dev/null +++ b/src/main/java/org/eh/core/annotation/AnnocationHandler.java @@ -0,0 +1,66 @@ +package org.eh.core.annotation; + +import java.io.File; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.eh.core.common.Constants; + +/** + * 注解处理类 + * @author guojing + * @date 2014-3-5 + */ +public class AnnocationHandler { + + /** + * 将所有注解Controller加入Constants.UrlClassMap + * @param parkage 类名(包含包路径) + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + public void paserControllerAnnocation(String parkage) throws ClassNotFoundException { + List classlist = getPkgClass(parkage); + for (String str : classlist) { + Class c = Class.forName(str); + if (c.isAnnotationPresent(Controller.class)) { + Controller desc = (Controller) c.getAnnotation(Controller.class); + Constants.UrlClassMap.put(desc.url(), str); + } + } + } + + /** + * 获取指定包下的所有类名(包含包名) + * @param parkage 指定包名 + * @return + */ + public List getPkgClass(String parkage) { + String path = Constants.CLASS_PATH + parkage.replace(".", "/") + "/"; + List list = new ArrayList(); + + File file = new File(path); + for (String str : file.list()) { + if (str.endsWith(".class")) { + list.add(parkage + "." + str.replace(".class", "")); + } else if (str.indexOf(".") == -1) { + list.addAll(getPkgClass(parkage + "." + str)); + } + } + + return list; + } + + /** + * 获取类的指定方法 + * @param c + * @param methodName + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + public Method getMethod(Class c, String methodName) throws NoSuchMethodException, + SecurityException { + Method method = c.getMethod(methodName, Map.class); + return method.isAnnotationPresent(RequestMapping.class) ? method : null; + } +} diff --git a/src/main/java/org/eh/core/annotation/Controller.java b/src/main/java/org/eh/core/annotation/Controller.java new file mode 100644 index 0000000..53fd38a --- /dev/null +++ b/src/main/java/org/eh/core/annotation/Controller.java @@ -0,0 +1,28 @@ +package org.eh.core.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Controller注解 + * @author guojing + * @date 2014-3-5 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@Documented +public @interface Controller { + + /** + * controller名,暂时无用 + */ + public String name(); + + /** + * 对应url请求路径,如htp://127.0.0.1/test/list.do 则对应 controller为:/test/,对应方法为:list + */ + public String url(); +} diff --git a/src/main/java/org/eh/core/annotation/RequestMapping.java b/src/main/java/org/eh/core/annotation/RequestMapping.java new file mode 100644 index 0000000..4d4e66e --- /dev/null +++ b/src/main/java/org/eh/core/annotation/RequestMapping.java @@ -0,0 +1,19 @@ +package org.eh.core.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 方法映射注解 + * @author guojing + * @date 2014-3-13 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +@Documented +public @interface RequestMapping { + +} diff --git a/src/main/java/org/eh/core/common/Constants.java b/src/main/java/org/eh/core/common/Constants.java new file mode 100644 index 0000000..85a30ce --- /dev/null +++ b/src/main/java/org/eh/core/common/Constants.java @@ -0,0 +1,27 @@ +package org.eh.core.common; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * + * @author guojing + * @date 2014-3-3 + */ +public class Constants { + + /* 配置信息 */ + public static String CLASS_PATH = "";//classes文件夹路径 + public static String VIEW_BASE_PATH = ""; // 路径 + public static String STATIC_RESOURCE_PATH = ""; // 静态文件路径 + public static List STATIC_SUFFIXS = new ArrayList(Arrays.asList(".css", ".js", + ".jpg", ".png", ".gif", ".html")); // 静态文件后缀 + + /* session */ + public static Integer SESSION_TIMEOUT = 10; //session + + public static Map UrlClassMap = new HashMap(); // url与class映射 +} diff --git a/src/main/java/org/eh/core/http/ApplicationContext.java b/src/main/java/org/eh/core/http/ApplicationContext.java new file mode 100644 index 0000000..0b01e18 --- /dev/null +++ b/src/main/java/org/eh/core/http/ApplicationContext.java @@ -0,0 +1,124 @@ +package org.eh.core.http; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import org.eh.core.util.StringUtil; + +import com.sun.net.httpserver.HttpExchange; + +/** + * 全局数据和会话相关数据,单例 + * @author guojing + * @date 2014-3-17 + */ +public class ApplicationContext { + + private Map appMap = new HashMap(); // ApplicationContext全局数据 + + /** + * 这里自己也有点搞不清sessionMap是不是有必要考虑线程安全,还请指教 + */ + private ConcurrentMap sessionMap = new ConcurrentHashMap(); // session数据 + + private ApplicationContext(){ + + } + + /** + * 内部类实现单例 + */ + private static class ApplicationContextHolder { + private static ApplicationContext instance = new ApplicationContext(); + } + + public static ApplicationContext getApplicationContext() { + return ApplicationContextHolder.instance; + } + + public void addAttribute(String name, Object value) { + ApplicationContextHolder.instance.appMap.put(name, value); + } + + public Object getAttribute(String name) { + return ApplicationContextHolder.instance.appMap.get(name); + } + + public Map getAllAttribute() { + return ApplicationContextHolder.instance.appMap; + } + + public Set getAllNames() { + return ApplicationContextHolder.instance.appMap.keySet(); + } + + public boolean containsName(String name) { + return ApplicationContextHolder.instance.appMap.containsKey(name); + } + + public void addSession(String sessionId) { + HttpSession httpSession = new HttpSession(); + httpSession.setLastVisitTime(new Date()); + ApplicationContextHolder.instance.sessionMap.put(sessionId, httpSession); + } + + /** + * 获取session + */ + public HttpSession getSession(HttpExchange httpExchange) { + String sessionId = getSessionId(httpExchange); + if (StringUtil.isEmpty(sessionId)) { + return null; + } + HttpSession httpSession = ApplicationContextHolder.instance.sessionMap.get(sessionId); + if (null == httpSession) { + httpSession = new HttpSession(); + ApplicationContextHolder.instance.sessionMap.put(sessionId, httpSession); + } + return httpSession; + } + + /** + * 获取sessionId + */ + public String getSessionId(HttpExchange httpExchange) { + String cookies = httpExchange.getRequestHeaders().getFirst("Cookie"); + String sessionId = ""; + if (StringUtil.isEmpty(cookies)) { + cookies = httpExchange.getResponseHeaders().getFirst("Set-Cookie"); + } + + if (StringUtil.isEmpty(cookies)) { + return null; + } + + String[] cookiearry = cookies.split(";"); + for(String cookie : cookiearry){ + cookie = cookie.replaceAll(" ", ""); + if (cookie.startsWith("EH_SESSION=")) { + sessionId = cookie.replace("EH_SESSION=", "").replace(";", ""); + } + } + + return sessionId; + } + + /** + * 获取所有session + */ + public ConcurrentMap getAllSession() { + return ApplicationContextHolder.instance.sessionMap; + } + + /** + * 设置session最后访问时间 + */ + public void setSessionLastTime(String sessionId) { + HttpSession httpSession = ApplicationContextHolder.instance.sessionMap.get(sessionId); + httpSession.setLastVisitTime(new Date()); + } +} diff --git a/src/main/java/org/eh/core/http/EHHttpHandler.java b/src/main/java/org/eh/core/http/EHHttpHandler.java new file mode 100644 index 0000000..ed67828 --- /dev/null +++ b/src/main/java/org/eh/core/http/EHHttpHandler.java @@ -0,0 +1,212 @@ +package org.eh.core.http; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URI; +import java.net.URLDecoder; +import java.util.HashMap; +import java.util.Map; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eh.core.annotation.AnnocationHandler; +import org.eh.core.common.Constants; +import org.eh.core.model.ResultInfo; +import org.eh.core.util.IOUtil; +import org.eh.core.util.StringUtil; +import org.eh.core.web.controller.Controller; +import org.eh.core.web.controller.IndexController; +import org.eh.core.web.view.ViewHandler; +import com.sun.net.httpserver.Headers; +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; + +/** + * 处理Http请求 + * + * @author guojing + * @date 2014-3-3 + */ +public class EHHttpHandler implements HttpHandler { + private final Log log = LogFactory.getLog(EHHttpHandler.class); + + public void handle(HttpExchange httpExchange) throws IOException { + try { + String path = httpExchange.getRequestURI().getPath(); + log.info("Receive a request,Request path:" + path); + + // 设置sessionId + String sessionId = ApplicationContext.getApplicationContext() + .getSessionId(httpExchange); + if (StringUtil.isEmpty(sessionId)) { + sessionId = StringUtil.creatSession(); + ApplicationContext.getApplicationContext().addSession(sessionId); + } + + httpExchange.getResponseHeaders().set("Set-Cookie", + "EH_SESSION=" + sessionId + "; path=/"); + + // 根据后缀判断是否是静态资源 + String suffix = path + .substring(path.lastIndexOf("."), path.length()); + if (Constants.STATIC_SUFFIXS.contains(suffix)) { + byte[] bytes = IOUtil.readFileByBytes(Constants.CLASS_PATH + + "static" + path); + responseStaticToClient(httpExchange, 200, bytes); + return; + } + + // 调用对应处理程序controller + ResultInfo resultInfo = invokController(httpExchange); + + // 返回404 + if (resultInfo == null || StringUtil.isEmpty(resultInfo.getView())) { + responseToClient(httpExchange, 200, "

页面不存在

"); + return; + } + + // 解析对应view并返回 + String content = invokViewHandler(resultInfo); + if (content == null) { + content = ""; + } + responseToClient(httpExchange, 200, content); + return; + + } catch (Exception e) { + httpExchange.close(); + log.error("响应请求失败:", e); + } + } + + /** + * 响应请求 + * + * @param httpExchange + * 请求-响应的封装 + * @param code + * 返回状态码 + * @param msg + * 返回信息 + * @throws IOException + */ + private void responseToClient(HttpExchange httpExchange, Integer code, + String msg) throws IOException { + + switch (code) { + case 200: { // 成功 + byte[] bytes = msg.getBytes(); + httpExchange.sendResponseHeaders(code, bytes.length); + OutputStream out = httpExchange.getResponseBody(); + out.write(bytes); + out.flush(); + httpExchange.close(); + } + break; + case 302: { // 跳转 + Headers headers = httpExchange.getResponseHeaders(); + headers.add("Location", msg); + httpExchange.sendResponseHeaders(code, 0); + httpExchange.close(); + } + break; + case 404: { // 错误 + byte[] bytes = "".getBytes(); + httpExchange.sendResponseHeaders(code, bytes.length); + OutputStream out = httpExchange.getResponseBody(); + out.write(bytes); + out.flush(); + httpExchange.close(); + } + break; + default: + break; + } + } + + /** + * 响应请求,返回静态资源 + * + * @param httpExchange + * @param code + * @param bytes + * @throws IOException + */ + private void responseStaticToClient(HttpExchange httpExchange, + Integer code, byte[] bytes) throws IOException { + httpExchange.sendResponseHeaders(code, bytes.length); + OutputStream out = httpExchange.getResponseBody(); + out.write(bytes); + out.flush(); + httpExchange.close(); + } + + /** + * 调用对应Controller处理业务 + */ + private ResultInfo invokController(HttpExchange httpExchange) throws UnsupportedEncodingException, InstantiationException, IllegalAccessException, ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException { + String path = httpExchange.getRequestURI().getPath(); + + String classPath = Constants.UrlClassMap.get(path.substring(0, path.lastIndexOf("/") + 1)); + if (classPath == null || classPath.length() == 0) { + return null; + } + Class controllerClass = Class.forName(classPath); + Controller controller = (Controller) controllerClass.newInstance(); + + String methodName = path.substring(path.lastIndexOf("/") + 1, path.lastIndexOf(".")); + //通过反射获取对应方法 + AnnocationHandler annocationHandler = new AnnocationHandler(); + Method method = annocationHandler.getMethod(controllerClass, methodName); + + Map map = null; // 参数 + map = analysisParms(httpExchange); + + // 设置session + HttpSession httpSession = ApplicationContext.getApplicationContext().getSession( + httpExchange); + map.put("session", httpSession); + + return (ResultInfo) method.invoke(controller, new Object[] { map }); + } + + /** + * 调用ViewHandler渲染视图 + */ + private String invokViewHandler(ResultInfo resultInfo) throws IOException { + ViewHandler viewHandler = new ViewHandler(); + return viewHandler.processView(resultInfo); + } + + /** + * 解析参数 + */ + private Map analysisParms(HttpExchange httpExchange) + throws UnsupportedEncodingException { + Map map = new HashMap(); + + URI requestedUri = httpExchange.getRequestURI(); + String queryGet = requestedUri.getRawQuery(); + String queryPost = IOUtil.getRequestContent(httpExchange + .getRequestBody()); + String query = ""; + if (!StringUtil.isEmpty(queryGet)) { + query = queryGet; + } + if (!StringUtil.isEmpty(queryPost)) { + query = StringUtil.isEmpty(query) ? queryPost + : (query + "&" + queryPost); + } + if (StringUtil.isEmpty(query)) { + return map; + } + + for (String kv : query.split("&")) { + String[] temp = kv.split("="); + map.put(temp[0], URLDecoder.decode(temp[1], "utf-8")); + } + return map; + } +} diff --git a/src/main/java/org/eh/core/http/EHServer.java b/src/main/java/org/eh/core/http/EHServer.java new file mode 100644 index 0000000..0ef44f3 --- /dev/null +++ b/src/main/java/org/eh/core/http/EHServer.java @@ -0,0 +1,71 @@ +package org.eh.core.http; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.util.Date; +import java.util.Timer; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eh.core.annotation.AnnocationHandler; +import org.eh.core.common.Constants; +import org.eh.core.task.SessionCleanTask; + +import com.sun.net.httpserver.HttpServer; +import com.sun.net.httpserver.spi.HttpServerProvider; + +/** + * 主服务类 + * @author guojing + * @date 2014-3-3 + */ +public class EHServer { + private final Log log = LogFactory.getLog(EHServer.class); + + /** + * 初始化信息,并启动server + */ + public void startServer() throws IOException { + log.info("Starting EHServer......"); + + //设置路径 + Constants.CLASS_PATH = this.getClass().getResource("/").getPath(); + Constants.VIEW_BASE_PATH = "page"; + Constants.STATIC_RESOURCE_PATH = "static"; + + //启动session过期清理定时器 + Timer timer = new Timer(); + SessionCleanTask sessionCleanTask = new SessionCleanTask(); + log.info("Initializing SessionCleanTask,the session_out_time is " + Constants.SESSION_TIMEOUT * 2 + + " minute."); + timer.schedule(sessionCleanTask, new Date(), Constants.SESSION_TIMEOUT * 60 * 2 * 1000); + + // 加载注解配置的controller + AnnocationHandler annocationHandler = new AnnocationHandler(); + try { + annocationHandler + .paserControllerAnnocation("org.eh.core.web.controller"); + } catch (Exception e) { + log.error("加载controller配置出错!", e); + return; + } + + //设置端口号 + int port = 8899; + + // 启动服务器 + HttpServerProvider provider = HttpServerProvider.provider(); + HttpServer httpserver = provider.createHttpServer(new InetSocketAddress(port), 100); + httpserver.createContext("/", new EHHttpHandler()); + httpserver.setExecutor(null); + httpserver.start(); + log.info("EHServer is started, listening at 8899."); + } + + /** + * 项目main + */ + public static void main(String[] args) throws IOException { + new EHServer().startServer(); + } +} diff --git a/src/main/java/org/eh/core/http/HttpSession.java b/src/main/java/org/eh/core/http/HttpSession.java new file mode 100644 index 0000000..b117dae --- /dev/null +++ b/src/main/java/org/eh/core/http/HttpSession.java @@ -0,0 +1,55 @@ +package org.eh.core.http; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * session数据 + * @author guojing + * @date 2014-3-17 + */ +public class HttpSession { + + Map map = new HashMap(); + + Date lastVisitTime = new Date(); // 最后访问时间 + + public void addAttribute(String name, Object value) { + map.put(name, value); + } + + public Object getAttribute(String name) { + return map.get(name); + } + + public Map getAllAttribute() { + return map; + } + + public Set getAllNames() { + return map.keySet(); + } + + public boolean containsName(String name) { + return map.containsKey(name); + } + + public Map getMap() { + return map; + } + + public void setMap(Map map) { + this.map = map; + } + + public Date getLastVisitTime() { + return lastVisitTime; + } + + public void setLastVisitTime(Date lastVisitTime) { + this.lastVisitTime = lastVisitTime; + } + +} diff --git a/src/main/java/org/eh/core/model/ResultInfo.java b/src/main/java/org/eh/core/model/ResultInfo.java new file mode 100644 index 0000000..759883d --- /dev/null +++ b/src/main/java/org/eh/core/model/ResultInfo.java @@ -0,0 +1,31 @@ +package org.eh.core.model; + +import java.util.Map; + +/** + * Controller处理结果 + * @author guojing + * @date 2014-3-3 + */ +public class ResultInfo { + + private String view; // 对应页面路径 + private Map resultMap; // 返回参数值 + + public String getView() { + return view; + } + + public void setView(String view) { + this.view = view; + } + + public Map getResultMap() { + return resultMap; + } + + public void setResultMap(Map resultMap) { + this.resultMap = resultMap; + } + +} diff --git a/src/main/java/org/eh/core/task/SessionCleanTask.java b/src/main/java/org/eh/core/task/SessionCleanTask.java new file mode 100644 index 0000000..535f9c4 --- /dev/null +++ b/src/main/java/org/eh/core/task/SessionCleanTask.java @@ -0,0 +1,45 @@ +package org.eh.core.task; + +import java.util.Date; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.TimerTask; +import java.util.concurrent.ConcurrentMap; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eh.core.common.Constants; +import org.eh.core.http.ApplicationContext; +import org.eh.core.http.HttpSession; + +/** + * 定时清理过期session + * @author guojing + * @date 2014-3-17 + */ +public class SessionCleanTask extends TimerTask { + private final Log log = LogFactory.getLog(SessionCleanTask.class); + + @Override + public void run() { + log.info("清理session......"); + ConcurrentMap sessionMap = ApplicationContext.getApplicationContext() + .getAllSession(); + + Iterator> it = sessionMap.entrySet().iterator(); + while (it.hasNext()) { + ConcurrentMap.Entry entry= (Entry) it.next(); + HttpSession httpSession= entry.getValue(); + + Date nowDate = new Date(); + int diff = (int) ((nowDate.getTime() - httpSession.getLastVisitTime().getTime())/1000/60); + + if (diff > Constants.SESSION_TIMEOUT) { + it.remove(); + } + } + + log.info("清理session结束"); + } +} diff --git a/src/main/java/org/eh/core/util/IOUtil.java b/src/main/java/org/eh/core/util/IOUtil.java new file mode 100644 index 0000000..17ecbf9 --- /dev/null +++ b/src/main/java/org/eh/core/util/IOUtil.java @@ -0,0 +1,89 @@ +package org.eh.core.util; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * IO、文件处理 + * @author guojing + * @date 2014-3-4 + */ +public class IOUtil { + private static final Log log = LogFactory.getLog(IOUtil.class); + public static String getRequestContent(InputStream inputStream) { + if (inputStream == null) { + return null; + } + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); + StringBuilder sb = new StringBuilder(); + try { + String temp = null; + while ((temp = reader.readLine()) != null) { + sb.append(temp); + } + } catch (IOException e) { + log.error("读取请求内容错误:", e); + } + return sb.toString(); + } + + public static boolean isExist(String path) { + File file = new File(path); + return file.exists(); + } + + public static String readFile(String path) { + if (!isExist(path)) { + return ""; + } + FileInputStream fis = null; + StringBuilder sb = new StringBuilder(); + try { + fis = new FileInputStream(path); + FileChannel c = fis.getChannel(); + ByteBuffer bc = ByteBuffer.allocate(1024); + int i = c.read(bc); + while (i != -1) { + sb.append(new String(bc.array())); + bc.clear(); + i = c.read(bc); + } + c.close(); + fis.close(); + } catch (Exception e) { + log.error("读取模板文件失败:", e); + } + return sb.toString(); + } + + public static byte[] readFileByBytes(String path) { + if (!isExist(path)) { + return "".getBytes(); + } + byte[] bytes = null; + FileInputStream fis = null; + try { + fis = new FileInputStream(path); + FileChannel c = fis.getChannel(); + ByteBuffer bc = ByteBuffer.allocate((int) c.size()); + int i = c.read(bc); + if (i != -1) { + bytes = bc.array(); + } + c.close(); + fis.close(); + } catch (Exception e) { + log.error("读取资源文件失败:", e); + } + return bytes; + } +} diff --git a/src/main/java/org/eh/core/util/StringUtil.java b/src/main/java/org/eh/core/util/StringUtil.java new file mode 100644 index 0000000..5c905a3 --- /dev/null +++ b/src/main/java/org/eh/core/util/StringUtil.java @@ -0,0 +1,20 @@ +package org.eh.core.util; + +import java.util.UUID; + +/** + * 字符串工具类 + * @author guojing + * @date 2014-3-4 + */ +public class StringUtil { + + public static boolean isEmpty(String str) { + return str == null || str.length() == 0; + } + + public static String creatSession() { + UUID uuid = UUID.randomUUID(); + return uuid.toString(); + } +} diff --git a/src/main/java/org/eh/core/web/controller/Controller.java b/src/main/java/org/eh/core/web/controller/Controller.java new file mode 100644 index 0000000..1877b78 --- /dev/null +++ b/src/main/java/org/eh/core/web/controller/Controller.java @@ -0,0 +1,11 @@ +package org.eh.core.web.controller; + + +/** + * Controllrt接口 + * @author guojing + * @date 2014-3-3 + */ +public interface Controller { + +} diff --git a/src/main/java/org/eh/core/web/controller/IndexController.java b/src/main/java/org/eh/core/web/controller/IndexController.java new file mode 100644 index 0000000..8d25680 --- /dev/null +++ b/src/main/java/org/eh/core/web/controller/IndexController.java @@ -0,0 +1,37 @@ +package org.eh.core.web.controller; + +import java.util.Map; + +import org.eh.core.annotation.RequestMapping; +import org.eh.core.http.ApplicationContext; +import org.eh.core.http.HttpSession; +import org.eh.core.model.ResultInfo; + +/** + * 主页对应的contoller + * @author guojing + */ +@org.eh.core.annotation.Controller(name = "session", url = "/session/") +public class IndexController implements Controller{ + + @RequestMapping + public ResultInfo process(Map map){ + ResultInfo result =new ResultInfo(); + + // 这里我们判断请求中是否有name参数,如果有则放入session,没有则从session中取出name放入map + HttpSession session = (HttpSession) map.get("session"); + if (map.get("name") != null) { + Object name = map.get("name"); + session.addAttribute("name", name); + } else { + Object name = session.getAttribute("name"); + if (name != null) { + map.put("name", name); + } + } + + result.setView("index"); + result.setResultMap(map); + return result; + } +} diff --git a/src/main/java/org/eh/core/web/view/ViewHandler.java b/src/main/java/org/eh/core/web/view/ViewHandler.java new file mode 100644 index 0000000..c0548bd --- /dev/null +++ b/src/main/java/org/eh/core/web/view/ViewHandler.java @@ -0,0 +1,56 @@ +package org.eh.core.web.view; + +import java.io.IOException; + +import org.eh.core.common.Constants; +import org.eh.core.model.ResultInfo; +import org.eh.core.util.IOUtil; +import org.eh.core.util.StringUtil; + +/** + * 处理页面信息 + * @author guojing + * @date 2014-3-3 + */ +public class ViewHandler { + + /** + * 处理View模板,只提供建单变量(格式${XXX})替换,已废弃 + * @return + */ + public String processView(ResultInfo resultInfo) { + // 获取路径 + String path = analysisViewPath(resultInfo.getView()); + String content = ""; + if (IOUtil.isExist(path)) { + content = IOUtil.readFile(path); + } + + if (StringUtil.isEmpty(content)) { + return ""; + } + + // 替换模板中的变量,替换符格式:${XXX} + for (String key : resultInfo.getResultMap().keySet()) { + String temp = ""; + if (null != resultInfo.getResultMap().get(key)) { + temp = resultInfo.getResultMap().get(key).toString(); + } + content = content.replaceAll("\\$\\{" + key + "\\}", temp); + } + + return content; + } + + /** + * 解析路径(根据Controller返回ResultInfo的view),已废弃 + * @param viewPath + * @return + */ + private String analysisViewPath(String viewPath) { + String path = Constants.CLASS_PATH + + (Constants.VIEW_BASE_PATH == null ? "/" : Constants.VIEW_BASE_PATH+"/") + + viewPath + ".page"; + return path; + } +} diff --git a/src/main/view/page/index.page b/src/main/view/page/index.page new file mode 100644 index 0000000..77b4b2c --- /dev/null +++ b/src/main/view/page/index.page @@ -0,0 +1,12 @@ + + + + + +

Hello,${name}

+ + + \ No newline at end of file diff --git a/src/main/view/static/js/test.js b/src/main/view/static/js/test.js new file mode 100644 index 0000000..43d363e --- /dev/null +++ b/src/main/view/static/js/test.js @@ -0,0 +1,3 @@ +function hello(){ + console.log("hello!") +} \ No newline at end of file diff --git a/src/main/view/static/pic/tx.jpg b/src/main/view/static/pic/tx.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7bf50f35ea288768d77118926d1136f545f8d2c3 GIT binary patch literal 41853 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 literal 0 HcmV?d00001 From 4f6a9afb2c7c828b6da1bdce11e700be0a0bf81f Mon Sep 17 00:00:00 2001 From: "awayy1432@163.com" Date: Sun, 10 Aug 2014 17:55:44 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E7=BC=96=E7=A0=81=E8=BD=AC=E4=B8=BAutf-8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/eh/core/http/EHHttpHandler.java | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/eh/core/http/EHHttpHandler.java b/src/main/java/org/eh/core/http/EHHttpHandler.java index ed67828..723cc0d 100644 --- a/src/main/java/org/eh/core/http/EHHttpHandler.java +++ b/src/main/java/org/eh/core/http/EHHttpHandler.java @@ -147,26 +147,29 @@ private void responseStaticToClient(HttpExchange httpExchange, * 调用对应Controller处理业务 */ private ResultInfo invokController(HttpExchange httpExchange) throws UnsupportedEncodingException, InstantiationException, IllegalAccessException, ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException { - String path = httpExchange.getRequestURI().getPath(); - - String classPath = Constants.UrlClassMap.get(path.substring(0, path.lastIndexOf("/") + 1)); + String path = httpExchange.getRequestURI().getPath(); + + String classPath = Constants.UrlClassMap.get(path.substring(0, + path.lastIndexOf("/") + 1)); if (classPath == null || classPath.length() == 0) { return null; } Class controllerClass = Class.forName(classPath); Controller controller = (Controller) controllerClass.newInstance(); - String methodName = path.substring(path.lastIndexOf("/") + 1, path.lastIndexOf(".")); - //通过反射获取对应方法 + String methodName = path.substring(path.lastIndexOf("/") + 1, + path.lastIndexOf(".")); + // 通过反射获取对应方法 AnnocationHandler annocationHandler = new AnnocationHandler(); - Method method = annocationHandler.getMethod(controllerClass, methodName); - + Method method = annocationHandler + .getMethod(controllerClass, methodName); + Map map = null; // 参数 map = analysisParms(httpExchange); // 设置session - HttpSession httpSession = ApplicationContext.getApplicationContext().getSession( - httpExchange); + HttpSession httpSession = ApplicationContext.getApplicationContext() + .getSession(httpExchange); map.put("session", httpSession); return (ResultInfo) method.invoke(controller, new Object[] { map });