From bbbc0043c3352a5135556e78eb58eb167abaf410 Mon Sep 17 00:00:00 2001 From: "awayy1432@163.com" Date: Fri, 2 May 2014 22:41:12 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E4=BF=AE=E6=94=B9readme?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 57 ++++--------------------------------------------------- 1 file changed, 4 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index ed43d5c..868a3b6 100644 --- a/README.md +++ b/README.md @@ -3,59 +3,10 @@ easy-httpserver 简介 ----------------- -一个java实现的简单的web服务器,主要目的是为了理解web服务器的工作原理。http请求的接收和返回使用JDK自带的HttpServer,请求处理和页面解析是自己实现的。目前已经能够支持web服务器一些基本的功能。 +web服务器实现初始化分支,仅实现如下基本功能 功能 ----------------- -目前项目已经能够完成一个动态网站的处理,并且采用类似jetty的嵌入启动方式,网站项目只需实现Controller和View页面并引入该项目jar包即可。 -已完成主要功能如下: - - -如何使用 ------------------ -easy-httpserver项目内也有测试代码,可自行研究。这里介绍test-httpserver示例项目的使用,其中已经实现了一些例子,可参照这些例子实现。 - - -项目结构 ------------------ -项目采用eclipse开发,并使用maven构建。 -

~src/main/java
  --org.eh.core
      --annotation
           AnnocationHandler.java   注解处理类
           Controller.java    Controller注解
       RequestMapping    请求方法注解,用来标注Controller中的处理方法
      --common
           Constants.java    常量类,包括系统常量和配置文件对应信息
           ReturnType.java    枚举,返回类型
      --http
           EHHttpHandler.java    httpserver请求核心处理类,完成请求的接收、处理、返回
           EHServer.java    项目启动类,完成服务器启动
       ApplicationContext.java   全局数据和会话相关数据,单例
       HttpSession.java   session会话
      --model
           FileInfo.java    上传文件信息封装
           ResultInfo.java    Controller返回结果
      --util
           FileUploadContentAnalysis.java    上传请求解析类,从中提取表单中的域值和文件信息
           FileUtil.java   文件工具类
           IOUtil.java    IO工具类
           PropertyUtil.java    配置文件工具类
           StringUtil.java    字符串工具类
           VelocityUtil.java    Velocity工具类
      --web
         --controller
              Controller.java    Controller接口,实现类必须继承Controller且标记Controller注解,实现方法必须标记RequestMapping注解
         --view
              ViewHandler.java    View处理类,完成页面文件渲染
~src/main/resources
     velocity.properties
     web.properties

- - - +> - 1、基本的接收和响应http请求 +> - 2、根据后缀区别分别静态和动态请求,静态请求直接返回,动态请求则交给controller处理 +> - 3、controller加载模板页并渲染数据,并将页面返回 From 4813fd4e258c759b070c4fc6cdacc7236569b3e4 Mon Sep 17 00:00:00 2001 From: "awayy1432@163.com" Date: Fri, 2 May 2014 23:20:14 +0800 Subject: [PATCH 2/5] init --- .classpath | 27 -- .gitignore | 7 - .project | 29 --- .settings/org.eclipse.core.resources.prefs | 7 - .settings/org.eclipse.jdt.core.prefs | 12 - .settings/org.eclipse.m2e.core.prefs | 4 - LICENSE | 202 --------------- README.md | 12 - pom.xml | 48 ---- .../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 | 59 ----- .../java/org/eh/core/common/ReturnType.java | 10 - .../org/eh/core/http/ApplicationContext.java | 124 --------- .../java/org/eh/core/http/EHHttpHandler.java | 240 ------------------ src/main/java/org/eh/core/http/EHServer.java | 98 ------- .../java/org/eh/core/http/HttpSession.java | 55 ---- src/main/java/org/eh/core/model/FileInfo.java | 43 ---- .../java/org/eh/core/model/ResultInfo.java | 31 --- .../org/eh/core/task/SessionCleanTask.java | 45 ---- .../core/util/FileUploadContentAnalysis.java | 194 -------------- src/main/java/org/eh/core/util/IOUtil.java | 89 ------- .../java/org/eh/core/util/PropertyUtil.java | 34 --- .../java/org/eh/core/util/StringUtil.java | 20 -- .../java/org/eh/core/util/VelocityUtil.java | 35 --- .../eh/core/web/controller/Controller.java | 11 - .../org/eh/core/web/view/ViewHandler.java | 91 ------- src/main/resources/velocity.properties | 2 - src/main/resources/web.properties | 20 -- .../annotation/AnnotationHandlerTest.java | 61 ----- .../eh/core/controller/Test1Controller.java | 21 -- .../eh/core/controller/Test2Controller.java | 13 - .../eh/core/controller/TestAnnocation.java | 38 --- .../core/controller/pss/Test3Controller.java | 13 - .../java/org/eh/core/other/StringTest.java | 18 -- .../java/org/eh/core/util/FileUtilTest.java | 21 -- .../org/eh/core/util/PropertyUtilTest.java | 24 -- .../java/org/eh/velocity/VelocityTest.java | 31 --- src/test/java/org/eh/velocity/test.vm | 1 - .../eh/web/controller/Test1Controller.java | 13 - .../org/eh/web/controller/TestController.java | 27 -- .../java/org/eh/web/view/test/myinfo.page | 7 - target/classes/web.properties | 20 -- target/maven-archiver/pom.properties | 5 - 45 files changed, 1975 deletions(-) delete mode 100644 .classpath delete mode 100644 .gitignore delete mode 100644 .project delete mode 100644 .settings/org.eclipse.core.resources.prefs delete mode 100644 .settings/org.eclipse.jdt.core.prefs delete mode 100644 .settings/org.eclipse.m2e.core.prefs delete mode 100644 LICENSE delete mode 100644 README.md delete mode 100644 pom.xml delete mode 100644 src/main/java/org/eh/core/annotation/AnnocationHandler.java delete mode 100644 src/main/java/org/eh/core/annotation/Controller.java delete mode 100644 src/main/java/org/eh/core/annotation/RequestMapping.java delete mode 100644 src/main/java/org/eh/core/common/Constants.java delete mode 100644 src/main/java/org/eh/core/common/ReturnType.java delete mode 100644 src/main/java/org/eh/core/http/ApplicationContext.java delete mode 100644 src/main/java/org/eh/core/http/EHHttpHandler.java delete mode 100644 src/main/java/org/eh/core/http/EHServer.java delete mode 100644 src/main/java/org/eh/core/http/HttpSession.java delete mode 100644 src/main/java/org/eh/core/model/FileInfo.java delete mode 100644 src/main/java/org/eh/core/model/ResultInfo.java delete mode 100644 src/main/java/org/eh/core/task/SessionCleanTask.java delete mode 100644 src/main/java/org/eh/core/util/FileUploadContentAnalysis.java delete mode 100644 src/main/java/org/eh/core/util/IOUtil.java delete mode 100644 src/main/java/org/eh/core/util/PropertyUtil.java delete mode 100644 src/main/java/org/eh/core/util/StringUtil.java delete mode 100644 src/main/java/org/eh/core/util/VelocityUtil.java delete mode 100644 src/main/java/org/eh/core/web/controller/Controller.java delete mode 100644 src/main/java/org/eh/core/web/view/ViewHandler.java delete mode 100644 src/main/resources/velocity.properties delete mode 100644 src/main/resources/web.properties delete mode 100644 src/test/java/org/eh/core/annotation/AnnotationHandlerTest.java delete mode 100644 src/test/java/org/eh/core/controller/Test1Controller.java delete mode 100644 src/test/java/org/eh/core/controller/Test2Controller.java delete mode 100644 src/test/java/org/eh/core/controller/TestAnnocation.java delete mode 100644 src/test/java/org/eh/core/controller/pss/Test3Controller.java delete mode 100644 src/test/java/org/eh/core/other/StringTest.java delete mode 100644 src/test/java/org/eh/core/util/FileUtilTest.java delete mode 100644 src/test/java/org/eh/core/util/PropertyUtilTest.java delete mode 100644 src/test/java/org/eh/velocity/VelocityTest.java delete mode 100644 src/test/java/org/eh/velocity/test.vm delete mode 100644 src/test/java/org/eh/web/controller/Test1Controller.java delete mode 100644 src/test/java/org/eh/web/controller/TestController.java delete mode 100644 src/test/java/org/eh/web/view/test/myinfo.page delete mode 100644 target/classes/web.properties delete mode 100644 target/maven-archiver/pom.properties diff --git a/.classpath b/.classpath deleted file mode 100644 index 8f5c07e..0000000 --- a/.classpath +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/.gitignore b/.gitignore deleted file mode 100644 index acd1ac3..0000000 --- a/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -*.class - -# Package Files # -*.jar -*.war -*.ear -/target diff --git a/.project b/.project deleted file mode 100644 index a375ecd..0000000 --- a/.project +++ /dev/null @@ -1,29 +0,0 @@ - - - easy-httpserver - - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.maven.ide.eclipse.maven2Builder - - - - - org.eclipse.m2e.core.maven2Builder - - - - - - org.maven.ide.eclipse.maven2Nature - org.eclipse.jdt.core.javanature - org.eclipse.m2e.core.maven2Nature - - diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs deleted file mode 100644 index 1ce660c..0000000 --- a/.settings/org.eclipse.core.resources.prefs +++ /dev/null @@ -1,7 +0,0 @@ -eclipse.preferences.version=1 -encoding//src/main/java=UTF-8 -encoding//src/main/resources=UTF-8 -encoding//src/main/resources/velocity.properties=ISO-8859-1 -encoding//src/main/resources/web.properties=UTF-8 -encoding//src/test/java=UTF-8 -encoding/=UTF-8 diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index 6249222..0000000 --- a/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,12 +0,0 @@ -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.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs deleted file mode 100644 index f897a7f..0000000 --- a/.settings/org.eclipse.m2e.core.prefs +++ /dev/null @@ -1,4 +0,0 @@ -activeProfiles= -eclipse.preferences.version=1 -resolveWorkspaceProjects=true -version=1 diff --git a/LICENSE b/LICENSE deleted file mode 100644 index e06d208..0000000 --- a/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ -Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - 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. - diff --git a/README.md b/README.md deleted file mode 100644 index 868a3b6..0000000 --- a/README.md +++ /dev/null @@ -1,12 +0,0 @@ -easy-httpserver -================= - -简介 ------------------ -web服务器实现初始化分支,仅实现如下基本功能 - -功能 ------------------ -> - 1、基本的接收和响应http请求 -> - 2、根据后缀区别分别静态和动态请求,静态请求直接返回,动态请求则交给controller处理 -> - 3、controller加载模板页并渲染数据,并将页面返回 diff --git a/pom.xml b/pom.xml deleted file mode 100644 index d87e77b..0000000 --- a/pom.xml +++ /dev/null @@ -1,48 +0,0 @@ - - 4.0.0 - - org.eh.http - easy-httpserver - 0.0.1 - jar - - easy-httpserver - http://maven.apache.org - - - UTF-8 - - - - - commons-logging - commons-logging - 1.1.3 - - - org.apache.velocity - velocity - 1.7 - - - org.apache.velocity - velocity-tools - 2.0 - - - junit - junit - 4.10 - - - - - easy-httpserver - - - ${basedir}/src/main/resources - - - - diff --git a/src/main/java/org/eh/core/annotation/AnnocationHandler.java b/src/main/java/org/eh/core/annotation/AnnocationHandler.java deleted file mode 100644 index 5014dd3..0000000 --- a/src/main/java/org/eh/core/annotation/AnnocationHandler.java +++ /dev/null @@ -1,66 +0,0 @@ -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 deleted file mode 100644 index 53fd38a..0000000 --- a/src/main/java/org/eh/core/annotation/Controller.java +++ /dev/null @@ -1,28 +0,0 @@ -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 deleted file mode 100644 index 4d4e66e..0000000 --- a/src/main/java/org/eh/core/annotation/RequestMapping.java +++ /dev/null @@ -1,19 +0,0 @@ -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 deleted file mode 100644 index 00ab418..0000000 --- a/src/main/java/org/eh/core/common/Constants.java +++ /dev/null @@ -1,59 +0,0 @@ -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; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.eh.core.util.PropertyUtil; - -/** - * - * @author guojing - * @date 2014-3-3 - */ -public class Constants { - private static final Log log = LogFactory.getLog(Constants.class); - - /* 配置信息 */ - public static String PACKAGE_PREFIX = "org.eh.web."; // 包前缀 - public static String VIEW_BASE_PATH = ""; // 路径 - public static String STATIC_RESOURCE_PATH = ""; // 静态文件路径 - public static String CLASS_PATH = "";//classes文件夹路径 - - public static Map UrlClassMap = new HashMap(); // url与class映射 - public static Map OTHER_CONFIG_INFO = new HashMap(); // 其他配置信息 - public static List STATIC_SUFFIXS = new ArrayList(Arrays.asList(".css", ".js", - ".jpg", ".png", ".gif", ".html")); // 静态文件后缀 - - /* 常量值 */ - public static String PROPERTIES_NAME = "web.properties"; // 配置文件名 - public static String PROPERTIES_VELOCITY_NAME = "velocity.properties"; // 配置文件名 - public static String PROPERTIES_CONTROLLER_PACKAGE = "controller.package"; // controller配置文件中属性名 - public static String PROPERTIES_HPPTSERVER_PORT = "httpserver.port"; // 服务端口名 - public static String SESSION_TIMEOUT = "session_timeout"; // 服务端口名 - - public static void loadFromProp(String path) { - Map map = new HashMap(); - try { - map = PropertyUtil.analysisProperties(path); - } catch (Exception e) { - log.error("配置文件不存在!", e); - } - - for (String key : map.keySet()) { - if (key.equals("PACKAGE_PREFIX")) { - PACKAGE_PREFIX = map.get(key).toString(); - } else if (key.equals("VIEW_BASE_PATH")) { - VIEW_BASE_PATH = map.get(key).toString(); - } else if (key.startsWith("url")) { - UrlClassMap.put(key.replace("url", ""), map.get(key).toString()); - } else { - OTHER_CONFIG_INFO.put(key, map.get(key).toString()); - } - } - } -} diff --git a/src/main/java/org/eh/core/common/ReturnType.java b/src/main/java/org/eh/core/common/ReturnType.java deleted file mode 100644 index 7055a9b..0000000 --- a/src/main/java/org/eh/core/common/ReturnType.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.eh.core.common; - -/** - * - * @author guojing - * @date 2014-3-7 - */ -public enum ReturnType { - velocity, redirect, json -} diff --git a/src/main/java/org/eh/core/http/ApplicationContext.java b/src/main/java/org/eh/core/http/ApplicationContext.java deleted file mode 100644 index 420ab40..0000000 --- a/src/main/java/org/eh/core/http/ApplicationContext.java +++ /dev/null @@ -1,124 +0,0 @@ -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 deleted file mode 100644 index a9dc4ce..0000000 --- a/src/main/java/org/eh/core/http/EHHttpHandler.java +++ /dev/null @@ -1,240 +0,0 @@ -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.common.ReturnType; -import org.eh.core.model.ResultInfo; -import org.eh.core.util.FileUploadContentAnalysis; -import org.eh.core.util.IOUtil; -import org.eh.core.util.StringUtil; -import org.eh.core.web.controller.Controller; -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; - } - - String viewPath = resultInfo.getView(); - if (viewPath.startsWith(ReturnType.redirect.name())) {// redirect跳转 - String redirectUrl = viewPath.replace(ReturnType.redirect.name() + ":", ""); - responseToClient(httpExchange, 302, redirectUrl); - return; - } else if (viewPath.startsWith(ReturnType.json.name())) { // 返回json数据 - String jsonContent = viewPath.replace(ReturnType.json.name() + ":", ""); - responseToClient(httpExchange, 200, jsonContent); - return; - } else if (viewPath.startsWith(ReturnType.velocity.name())) { // 解析对应view并返回 - String content = invokViewHandler(resultInfo); - if (content == null) { - content = ""; - } - responseToClient(httpExchange, 200, content); - return; - } else { - responseToClient(httpExchange, 200, resultInfo.getView()); - 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处理业务 - */ - @SuppressWarnings("rawtypes") - private ResultInfo invokController(HttpExchange httpExchange) throws ClassNotFoundException, - InstantiationException, IllegalAccessException, IOException, 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; // 参数 - // 判断表单类型,若是multipart/form-data,则是文件上传;否则做普通处理 - Headers headers = httpExchange.getRequestHeaders(); - // 获取ContentType - String contentType = ""; - if(null != headers.get("Content-type")){ - contentType = headers.get("Content-type").toString().replace("[", "") - .replace("]", ""); - } - - if (contentType.indexOf("multipart/form-data") != -1) { - // 获取content长度 - int length = Integer.parseInt(headers.get("Content-length").toString().replace("[", "") - .replace("]", "")); - map = FileUploadContentAnalysis.parse(httpExchange.getRequestBody(), contentType, - length); - } else { - 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); - return viewHandler.processVelocityView(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 deleted file mode 100644 index 8d17efb..0000000 --- a/src/main/java/org/eh/core/http/EHServer.java +++ /dev/null @@ -1,98 +0,0 @@ -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.apache.velocity.app.Velocity; -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......"); - log.info("Loading configuration......"); - - //设置classes文件夹路径 - Constants.CLASS_PATH = this.getClass().getResource("/").getPath().replace("bin", "classes"); - // 加载配置文件 - String propPath = Constants.CLASS_PATH + Constants.PROPERTIES_NAME; - Constants.loadFromProp(propPath); - - - // 加载注解配置的controller - if (Constants.OTHER_CONFIG_INFO.get(Constants.PROPERTIES_CONTROLLER_PACKAGE) != null) { - AnnocationHandler annocationHandler = new AnnocationHandler(); - try { - annocationHandler.paserControllerAnnocation(Constants.OTHER_CONFIG_INFO.get( - Constants.PROPERTIES_CONTROLLER_PACKAGE).toString()); - } catch (Exception e) { - log.error("加载controller配置出错!", e); - return; - } - } - - // 初始化Velocity模板 - log.info("Initializing velocity......"); - Velocity.init(Constants.CLASS_PATH - + Constants.PROPERTIES_VELOCITY_NAME); - - for (String key : Constants.UrlClassMap.keySet()) { - log.info("Add url-class:" + key + " " + Constants.UrlClassMap.get(key)); - } - - int port = 8899; - //设置端口号 - String portValue = Constants.OTHER_CONFIG_INFO.get(Constants.PROPERTIES_HPPTSERVER_PORT); - log.info("Set port:" + portValue); - if (portValue != null) { - try { - port = Integer.parseInt(portValue); - } catch (Exception e) { - log.error("端口错误!", e); - return; - } - } - - //启动session过期清理定时器 - Timer timer = new Timer(); - SessionCleanTask sessionCleanTask = new SessionCleanTask(); - int session_timeout = Integer.parseInt(Constants.OTHER_CONFIG_INFO - .get(Constants.SESSION_TIMEOUT)); - log.info("Initializing SessionCleanTask,the session_out_time is " + session_timeout * 2 - + " minute."); - timer.schedule(sessionCleanTask, new Date(), session_timeout * 60 * 2 * 1000); - - // 启动服务器 - HttpServerProvider provider = HttpServerProvider.provider(); - HttpServer httpserver = provider.createHttpServer(new InetSocketAddress(port), 100); - httpserver.createContext("/", new EHHttpHandler()); - httpserver.setExecutor(null); - httpserver.start(); - log.info("EHServer has started"); - } - - /** - * 项目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 deleted file mode 100644 index b117dae..0000000 --- a/src/main/java/org/eh/core/http/HttpSession.java +++ /dev/null @@ -1,55 +0,0 @@ -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/FileInfo.java b/src/main/java/org/eh/core/model/FileInfo.java deleted file mode 100644 index b92c684..0000000 --- a/src/main/java/org/eh/core/model/FileInfo.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.eh.core.model; - -/** - * 上传文件信息 - * @author guojing - * @date 2014-3-3 - */ -public class FileInfo { - - private String filename; //文件名 - private String fieldname; // 表单中参数名 - private int length; //文件长度 - private byte[] bytes; //文件字节数组 - - public String getFilename() { - return filename; - } - public void setFilename(String filename) { - this.filename = filename; - } - public int getLength() { - return length; - } - public void setLength(int length) { - this.length = length; - } - public byte[] getBytes() { - return bytes; - } - public void setBytes(byte[] bytes) { - this.bytes = bytes; - } - - public String getFieldname() { - return fieldname; - } - - public void setFieldname(String fieldname) { - this.fieldname = fieldname; - } - - -} diff --git a/src/main/java/org/eh/core/model/ResultInfo.java b/src/main/java/org/eh/core/model/ResultInfo.java deleted file mode 100644 index 759883d..0000000 --- a/src/main/java/org/eh/core/model/ResultInfo.java +++ /dev/null @@ -1,31 +0,0 @@ -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 deleted file mode 100644 index 2df93da..0000000 --- a/src/main/java/org/eh/core/task/SessionCleanTask.java +++ /dev/null @@ -1,45 +0,0 @@ -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 > Integer.parseInt(Constants.OTHER_CONFIG_INFO.get(Constants.SESSION_TIMEOUT))) { - it.remove(); - } - } - - log.info("清理session结束"); - } -} diff --git a/src/main/java/org/eh/core/util/FileUploadContentAnalysis.java b/src/main/java/org/eh/core/util/FileUploadContentAnalysis.java deleted file mode 100644 index 6b99ed0..0000000 --- a/src/main/java/org/eh/core/util/FileUploadContentAnalysis.java +++ /dev/null @@ -1,194 +0,0 @@ -package org.eh.core.util; - -import java.io.BufferedReader; -import java.io.DataInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.StringReader; -import java.util.HashMap; -import java.util.Map; - -import org.eh.core.model.FileInfo; - -/** - * 解析content获取上传文件表单信息 - * @author 自己写的老有问题,一怒之下copy了一份。不过这个也有些问题,由于office不同版本的Content-Type格式不固定, 所以office文件上传生成的文件一般会少几个字节,以后有心情了再改吧 - * @date 2014-3-10 - */ -public class FileUploadContentAnalysis { - static final int NONE = 0; - static final int DATAHEADER = 1; - static final int FILEDATA = 2; - static final int FIELDDATA = 3; - static final int MXA_SEGSIZE = 1000 * 1024 * 10; //最大文件长度 - - public static Map parse(InputStream ins, String contentType, int totalLength) - throws IOException { - - FileInfo fileInfo =new FileInfo(); - String fieldname = ""; // 表单域的名称 - String fieldvalue = ""; // 表单域的值 - String filename = ""; // 文件名 - String boundary = ""; // 分界符 - String lastboundary = ""; // 结束符 - String filefieldname = ""; // 文件表单域名 - Map formfields = new HashMap(); - int filesize = 0; // 文件长度 - - int pos = contentType.indexOf("boundary="); - - if (pos != -1) { // 取得分界符和结束符 - pos += "boundary=".length(); - boundary = "--" + contentType.substring(pos); - lastboundary = boundary + "--"; - } - int state = NONE; - // 得到数据输入流reqbuf - DataInputStream in = new DataInputStream(ins); - // 将请求消息的实体送到b变量中 - int totalBytes = totalLength; - if (totalBytes > MXA_SEGSIZE) {// 每批大于10m时 - return null; - } - byte[] b = new byte[totalBytes]; - in.readFully(b); - in.close(); - String reqContent = new String(b, "UTF-8");// - BufferedReader reqbuf = new BufferedReader(new StringReader(reqContent)); - - boolean flag = true; - while (flag == true) { - String s = reqbuf.readLine(); - if ((s == null) || (s.equals(lastboundary))) - break; - - switch (state) { - case NONE: - if (s.startsWith(boundary)) { - state = DATAHEADER; - } - break; - case DATAHEADER: - pos = s.indexOf("filename="); - if (pos == -1) { // 将表单域的名字解析出来 - pos = s.indexOf("name="); - pos += "name=".length() + 1; - s = s.substring(pos); - int l = s.length(); - s = s.substring(0, l - 1); - fieldname = s; - state = FIELDDATA; - } else { - String temp = s; - // 将文件表单参数名解析出来 - pos = s.indexOf("name="); - pos += "name=".length() + 1; - s = s.substring(pos); - int pos1 = s.indexOf("\";"); - filefieldname = s.substring(0, pos1); - - // 将文件名解析出来 - pos = s.indexOf("filename="); - pos += "filename=".length() + 1; - s = s.substring(pos); - int l = s.length(); - s = s.substring(0, l - 1);// 去掉最后那个引号” - pos = s.lastIndexOf("\\"); - s = s.substring(pos + 1); - filename = s; - // 从字节数组中取出文件数组 - pos = byteIndexOf(b, temp, 0); - b = subBytes(b, pos + temp.getBytes().length + 2, b.length);// 去掉前面的部分 - int n = 0; - /** - * 过滤boundary下形如 Content-Disposition: form-data; name="bin"; filename="12.pdf" Content-Type: - * application/octet-stream Content-Transfer-Encoding: binary 的字符串 - */ - while ((s = reqbuf.readLine()) != null) { - if (n == 1) - break; - if (s.equals("")) - n++; - - b = subBytes(b, s.getBytes().length + 2, b.length); - } - pos = byteIndexOf(b, boundary, 0); - if (pos != -1) - b = subBytes(b, 0, pos - 1); - - filesize = b.length - 1; - state = FILEDATA; - } - break; - case FIELDDATA: - s = reqbuf.readLine(); - fieldvalue = s; - formfields.put(fieldname, fieldvalue); - state = NONE; - break; - case FILEDATA: - while ((!s.startsWith(boundary)) && (!s.startsWith(lastboundary))) { - s = reqbuf.readLine(); - if (s.startsWith(boundary)) { - state = DATAHEADER; - break; - } - } - break; - } - } - fileInfo.setFieldname(filefieldname); - fileInfo.setBytes(b); - fileInfo.setFilename(filename); - fileInfo.setLength(filesize); - formfields.put(filefieldname, fileInfo); - return formfields; - - } - - // 字节数组中的INDEXOF函数,与STRING类中的INDEXOF类似 - public static int byteIndexOf(byte[] b, String s, int start) { - return byteIndexOf(b, s.getBytes(), start); - } - - // 字节数组中的INDEXOF函数,与STRING类中的INDEXOF类似 - public static int byteIndexOf(byte[] b, byte[] s, int start) { - int i; - if (s.length == 0) { - return 0; - } - int max = b.length - s.length; - if (max < 0) - return -1; - if (start > max) - return -1; - if (start < 0) - start = 0; - search: for (i = start; i <= max; i++) { - if (b[i] == s[0]) { - int k = 1; - while (k < s.length) { - if (b[k + i] != s[k]) { - continue search; - } - k++; - } - return i; - } - } - return -1; - } - - // 用于从一个字节数组中提取一个字节数组 - public static byte[] subBytes(byte[] b, int from, int end) { - byte[] result = new byte[end - from]; - System.arraycopy(b, from, result, 0, end - from); - return result; - } - - // 用于从一个字节数组中提取一个字符串 - public static String subBytesString(byte[] b, int from, int end) { - return new String(subBytes(b, from, end)); - } - -} diff --git a/src/main/java/org/eh/core/util/IOUtil.java b/src/main/java/org/eh/core/util/IOUtil.java deleted file mode 100644 index 17ecbf9..0000000 --- a/src/main/java/org/eh/core/util/IOUtil.java +++ /dev/null @@ -1,89 +0,0 @@ -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/PropertyUtil.java b/src/main/java/org/eh/core/util/PropertyUtil.java deleted file mode 100644 index 7a8cdbd..0000000 --- a/src/main/java/org/eh/core/util/PropertyUtil.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.eh.core.util; - -import java.io.BufferedInputStream; -import java.io.FileInputStream; -import java.io.InputStream; -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * 配置文件工具类 - * @author guojing - * @date 2014-3-4 - */ -public class PropertyUtil { - private static final Log log = LogFactory.getLog(PropertyUtil.class); - public static Map analysisProperties(String path) { - Map map = new HashMap(); - Properties props = new Properties(); - try { - InputStream in = new BufferedInputStream(new FileInputStream(path)); - props.load(in); - for (String key : props.stringPropertyNames()) { - map.put(key, props.get(key).toString()); - } - } catch (Exception e) { - log.error("配置文件解析错误:", e); - } - return map; - } -} diff --git a/src/main/java/org/eh/core/util/StringUtil.java b/src/main/java/org/eh/core/util/StringUtil.java deleted file mode 100644 index 5c905a3..0000000 --- a/src/main/java/org/eh/core/util/StringUtil.java +++ /dev/null @@ -1,20 +0,0 @@ -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/util/VelocityUtil.java b/src/main/java/org/eh/core/util/VelocityUtil.java deleted file mode 100644 index 08c5f3b..0000000 --- a/src/main/java/org/eh/core/util/VelocityUtil.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.eh.core.util; - -import java.io.IOException; -import java.io.StringWriter; -import java.util.Map; - -import org.apache.velocity.VelocityContext; -import org.apache.velocity.app.Velocity; - -/** - * Velocity解析类 - * @author guojing - * @date 2014-3-10 - */ -public class VelocityUtil { - - /** - * 渲染Velocity模板 - * @param path - * @param map - */ - public static String mergeTemplate(String path, Map map) throws IOException { - VelocityContext vc = new VelocityContext(); - if (null != map) { - for (String key : map.keySet()) { - vc.put(key, map.get(key)); - } - } - StringWriter w = new StringWriter(); - Velocity.mergeTemplate(path, "utf-8", vc, w); - String content = w.toString(); - w.close(); - return content; - } -} diff --git a/src/main/java/org/eh/core/web/controller/Controller.java b/src/main/java/org/eh/core/web/controller/Controller.java deleted file mode 100644 index 1877b78..0000000 --- a/src/main/java/org/eh/core/web/controller/Controller.java +++ /dev/null @@ -1,11 +0,0 @@ -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/view/ViewHandler.java b/src/main/java/org/eh/core/web/view/ViewHandler.java deleted file mode 100644 index 1a1bbab..0000000 --- a/src/main/java/org/eh/core/web/view/ViewHandler.java +++ /dev/null @@ -1,91 +0,0 @@ -package org.eh.core.web.view; - -import java.io.IOException; - -import org.eh.core.common.Constants; -import org.eh.core.common.ReturnType; -import org.eh.core.model.ResultInfo; -import org.eh.core.util.IOUtil; -import org.eh.core.util.StringUtil; -import org.eh.core.util.VelocityUtil; - -/** - * 处理页面信息 - * @author guojing - * @date 2014-3-3 - */ -public class ViewHandler { - - /** - * 处理View模板,只提供建单变量(格式${XXX})替换,已废弃 - * @return - */ - @Deprecated - 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; - } - - /** - * 处理Velocity模板 - * @param resultInfo - * @return - * @throws IOException - */ - public String processVelocityView(ResultInfo resultInfo) throws IOException { - if (StringUtil.isEmpty(resultInfo.getView())) { - return ""; - } - - // 获取路径 - String path = analysisVelocityViewPath(resultInfo.getView()); - String content = VelocityUtil.mergeTemplate(path, resultInfo.getResultMap()); - - if (StringUtil.isEmpty(content)) { - return ""; - } - - return content; - } - - /** - * 解析路径(根据Controller返回ResultInfo的view),已废弃 - * @param viewPath - * @return - */ - @Deprecated - private String analysisViewPath(String viewPath) { - String path = Constants.CLASS_PATH - + (Constants.VIEW_BASE_PATH == null ? "/" : Constants.VIEW_BASE_PATH) - + viewPath + ".page"; - return path; - } - - /** - * 解析velocity路径(根据Controller返回ResultInfo的view) - */ - private String analysisVelocityViewPath(String viewPath) { - String path = Constants.VIEW_BASE_PATH + "/" - + viewPath.replace(ReturnType.velocity.name() + ":", "") + ".vm"; - return path; - } -} diff --git a/src/main/resources/velocity.properties b/src/main/resources/velocity.properties deleted file mode 100644 index db5a5ec..0000000 --- a/src/main/resources/velocity.properties +++ /dev/null @@ -1,2 +0,0 @@ -resource.loader=class -class.resource.loader.class=org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader \ No newline at end of file diff --git a/src/main/resources/web.properties b/src/main/resources/web.properties deleted file mode 100644 index 897b070..0000000 --- a/src/main/resources/web.properties +++ /dev/null @@ -1,20 +0,0 @@ -#包前缀 -PACKAGE_PREFIX=org.eh.web - -#模板页面根路径(相对classes文件夹,项目src/main/view下) -VIEW_BASE_PATH=page - -#静态资源路劲(相对classes文件夹,项目src/main/view下) -STATIC_RESOURCE_PATH=static - -#端口 -httpserver.port=8888 - -#controller包路径,配置后可通过annocation直接配置 -controller.package=com.gj.web.controller - -#url与controller类对应关系 -#url/list=com.gj.web.controller.MyController - -#session超时时间(分钟) -session_timeout = 10 \ No newline at end of file diff --git a/src/test/java/org/eh/core/annotation/AnnotationHandlerTest.java b/src/test/java/org/eh/core/annotation/AnnotationHandlerTest.java deleted file mode 100644 index fe2d5f5..0000000 --- a/src/test/java/org/eh/core/annotation/AnnotationHandlerTest.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.eh.core.annotation; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Map; - -import org.junit.Test; - -/** - * - * @author guojing - * @date 2014-3-13 - */ -public class AnnotationHandlerTest { - - @Test - @SuppressWarnings("rawtypes") - public void testMethods() { - try { - Class c = Class.forName("org.eh.core.controller.Test1Controller"); - Method[] methods = c.getMethods(); - for (Method method : methods) { - if (method.isAnnotationPresent(RequestMapping.class)) { - System.out.println(method.getName()); - org.eh.core.web.controller.Controller controller = (org.eh.core.web.controller.Controller) c - .newInstance(); - method.invoke(controller, new Object[] { null }); - } - } - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IllegalArgumentException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (InvocationTargetException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (InstantiationException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - @Test - public void testMethod() { - try { - Class c = Class.forName("org.eh.core.controller.Test1Controller"); - Method methods = c.getMethod("add", Map.class); - System.out.println(methods.getName()); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } catch (NoSuchMethodException e) { - e.printStackTrace(); - } catch (SecurityException e) { - e.printStackTrace(); - } - } -} diff --git a/src/test/java/org/eh/core/controller/Test1Controller.java b/src/test/java/org/eh/core/controller/Test1Controller.java deleted file mode 100644 index 5e611ed..0000000 --- a/src/test/java/org/eh/core/controller/Test1Controller.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.eh.core.controller; - -import java.util.Map; - -import org.eh.core.annotation.RequestMapping; -import org.eh.core.web.controller.Controller; - -/** - * - * @author guojing - * @date 2014-3-5 - */ -@org.eh.core.annotation.Controller(name = "test1", url = "/test/show") -public class Test1Controller implements Controller { - - @RequestMapping - public String add(Map map) { - System.out.println("aaa"); - return null; - } -} diff --git a/src/test/java/org/eh/core/controller/Test2Controller.java b/src/test/java/org/eh/core/controller/Test2Controller.java deleted file mode 100644 index e1045d5..0000000 --- a/src/test/java/org/eh/core/controller/Test2Controller.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.eh.core.controller; - -import org.eh.core.annotation.Controller; - -/** - * - * @author guojing - * @date 2014-3-5 - */ -@Controller(name = "test2", url = "/test/list") -public interface Test2Controller { - -} diff --git a/src/test/java/org/eh/core/controller/TestAnnocation.java b/src/test/java/org/eh/core/controller/TestAnnocation.java deleted file mode 100644 index 109ef27..0000000 --- a/src/test/java/org/eh/core/controller/TestAnnocation.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.eh.core.controller; - -import java.io.File; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import org.junit.Test; - -/** - * - * @author guojing - * @date 2014-3-5 - */ -public class TestAnnocation { - - @Test - public void getAnnontion() { - List list = getPkgClass("org.eh.core.controller"); - System.out.println(Arrays.toString(list.toArray())); - } - - public List getPkgClass(String parkage) { - String path = this.getClass().getResource("/").getPath() + 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; - } -} diff --git a/src/test/java/org/eh/core/controller/pss/Test3Controller.java b/src/test/java/org/eh/core/controller/pss/Test3Controller.java deleted file mode 100644 index 28839db..0000000 --- a/src/test/java/org/eh/core/controller/pss/Test3Controller.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.eh.core.controller.pss; - -import org.eh.core.annotation.Controller; - -/** - * - * @author guojing - * @date 2014-3-5 - */ -@Controller(name = "test3", url = "/test/send") -public class Test3Controller { - -} diff --git a/src/test/java/org/eh/core/other/StringTest.java b/src/test/java/org/eh/core/other/StringTest.java deleted file mode 100644 index 630765c..0000000 --- a/src/test/java/org/eh/core/other/StringTest.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.eh.core.other; - -import org.junit.Test; - -/** - * - * @author guojing - * @date 2014-3-6 - */ -public class StringTest { - - @Test - public void testSub() { - // String path = "test/path/list.do"; - // String suffix = path.substring(path.lastIndexOf("."), path.length()); - System.out.println(System.getProperty("user.dir")); - } -} diff --git a/src/test/java/org/eh/core/util/FileUtilTest.java b/src/test/java/org/eh/core/util/FileUtilTest.java deleted file mode 100644 index 419e1e8..0000000 --- a/src/test/java/org/eh/core/util/FileUtilTest.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.eh.core.util; - -import org.eh.core.common.Constants; -import org.junit.Test; - -/** - * - * @author guojing - * @date 2014-3-4 - */ -public class FileUtilTest { - - @Test - public void TestRead() { - String path = Constants.CLASS_PATH - + "org/eh/web/view/test/myinfo.page"; - String content = IOUtil.readFile(path); - System.out.println(content); - } - -} diff --git a/src/test/java/org/eh/core/util/PropertyUtilTest.java b/src/test/java/org/eh/core/util/PropertyUtilTest.java deleted file mode 100644 index 2ec031e..0000000 --- a/src/test/java/org/eh/core/util/PropertyUtilTest.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.eh.core.util; - -import org.eh.core.common.Constants; -import org.eh.core.common.ReturnType; -import org.junit.Test; - -/** - * - * @author guojing - * @date 2014-3-4 - */ -public class PropertyUtilTest { - - @Test - public void testResd() { - PropertyUtil.analysisProperties(Constants.CLASS_PATH - + "web.properties"); - } - - @Test - public void testReflect() { - System.out.println(ReturnType.redirect.name()); - } -} diff --git a/src/test/java/org/eh/velocity/VelocityTest.java b/src/test/java/org/eh/velocity/VelocityTest.java deleted file mode 100644 index 89e360b..0000000 --- a/src/test/java/org/eh/velocity/VelocityTest.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.eh.velocity; - -import java.io.StringWriter; -import java.util.Properties; - -import org.apache.velocity.VelocityContext; -import org.apache.velocity.app.Velocity; -import org.junit.Test; - -/** - * - * @author guojing - * @date 2014-3-10 - */ -public class VelocityTest { - - @Test - public void testVelocity() { - Properties p =new Properties(); - p.setProperty("resource.loader", "class"); - p.setProperty("class.resource.loader.class", - "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader"); - - Velocity.init(p); - VelocityContext vc = new VelocityContext(); - vc.put("name", "guojing"); - StringWriter w = new StringWriter(); -// Velocity.mergeTemplate("org/eh/velocity/test.vm", "utf-8", vc, w); - System.out.println(w); - } -} diff --git a/src/test/java/org/eh/velocity/test.vm b/src/test/java/org/eh/velocity/test.vm deleted file mode 100644 index ccf2d93..0000000 --- a/src/test/java/org/eh/velocity/test.vm +++ /dev/null @@ -1 +0,0 @@ -hello!$!{name}。 \ No newline at end of file diff --git a/src/test/java/org/eh/web/controller/Test1Controller.java b/src/test/java/org/eh/web/controller/Test1Controller.java deleted file mode 100644 index 926ef10..0000000 --- a/src/test/java/org/eh/web/controller/Test1Controller.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.eh.web.controller; - -import org.eh.core.annotation.Controller; - -/** - * - * @author guojing - * @date 2014-3-5 - */ -@Controller(name = "test1", url = "/test/mark") -public class Test1Controller { - -} diff --git a/src/test/java/org/eh/web/controller/TestController.java b/src/test/java/org/eh/web/controller/TestController.java deleted file mode 100644 index cc53eb0..0000000 --- a/src/test/java/org/eh/web/controller/TestController.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.eh.web.controller; - -import java.util.HashMap; -import java.util.Map; - -import org.eh.core.model.ResultInfo; -import org.eh.core.web.controller.Controller; - -/** - * - * @author guojing - * @date 2014-3-3 - */ -public class TestController implements Controller { - - public ResultInfo process(Map parms) { - ResultInfo resultInfo = new ResultInfo(); - Map map = new HashMap(); - map.put("name", parms.get("name")); - map.put("msg", parms.get("msg")); - - resultInfo.setResultMap(map); - resultInfo.setView("test/myinfo"); - return resultInfo; - } - -} diff --git a/src/test/java/org/eh/web/view/test/myinfo.page b/src/test/java/org/eh/web/view/test/myinfo.page deleted file mode 100644 index c7fbbc5..0000000 --- a/src/test/java/org/eh/web/view/test/myinfo.page +++ /dev/null @@ -1,7 +0,0 @@ - - - - -

${msg},${name}

- - \ No newline at end of file diff --git a/target/classes/web.properties b/target/classes/web.properties deleted file mode 100644 index 897b070..0000000 --- a/target/classes/web.properties +++ /dev/null @@ -1,20 +0,0 @@ -#包前缀 -PACKAGE_PREFIX=org.eh.web - -#模板页面根路径(相对classes文件夹,项目src/main/view下) -VIEW_BASE_PATH=page - -#静态资源路劲(相对classes文件夹,项目src/main/view下) -STATIC_RESOURCE_PATH=static - -#端口 -httpserver.port=8888 - -#controller包路径,配置后可通过annocation直接配置 -controller.package=com.gj.web.controller - -#url与controller类对应关系 -#url/list=com.gj.web.controller.MyController - -#session超时时间(分钟) -session_timeout = 10 \ No newline at end of file diff --git a/target/maven-archiver/pom.properties b/target/maven-archiver/pom.properties deleted file mode 100644 index 87bbb17..0000000 --- a/target/maven-archiver/pom.properties +++ /dev/null @@ -1,5 +0,0 @@ -#Generated by Maven -#Thu Mar 27 22:41:48 CST 2014 -version=0.0.1 -groupId=org.eh.http -artifactId=easy-httpserver From 35abba90ef6e94c0841a75ddf7a6faaa6f54b639 Mon Sep 17 00:00:00 2001 From: "awayy1432@163.com" Date: Sat, 3 May 2014 00:36:41 +0800 Subject: [PATCH 3/5] learn-1 --- pom.xml | 40 ++++ .../java/org/eh/core/common/Constants.java | 20 ++ .../java/org/eh/core/http/EHHttpHandler.java | 180 ++++++++++++++++++ src/main/java/org/eh/core/http/EHServer.java | 50 +++++ .../java/org/eh/core/model/ResultInfo.java | 31 +++ 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 | 19 ++ .../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 13 files changed, 531 insertions(+) create mode 100644 pom.xml create mode 100644 src/main/java/org/eh/core/common/Constants.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/model/ResultInfo.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/pom.xml b/pom.xml new file mode 100644 index 0000000..5ea5db7 --- /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/common/Constants.java b/src/main/java/org/eh/core/common/Constants.java new file mode 100644 index 0000000..524d4f3 --- /dev/null +++ b/src/main/java/org/eh/core/common/Constants.java @@ -0,0 +1,20 @@ +package org.eh.core.common; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * + * @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")); // 静态文件后缀 +} 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..4698674 --- /dev/null +++ b/src/main/java/org/eh/core/http/EHHttpHandler.java @@ -0,0 +1,180 @@ +package org.eh.core.http; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +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.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.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); + + // 根据后缀判断是否是静态资源 + 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处理业务 + * @throws UnsupportedEncodingException + */ + private ResultInfo invokController(HttpExchange httpExchange) throws UnsupportedEncodingException { + // 获取参数 + Map map = analysisParms(httpExchange); + + IndexController controller = new IndexController(); + return controller.process(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..b731702 --- /dev/null +++ b/src/main/java/org/eh/core/http/EHServer.java @@ -0,0 +1,50 @@ +package org.eh.core.http; + +import java.io.IOException; +import java.net.InetSocketAddress; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eh.core.common.Constants; + +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"; + + //设置端口号 + 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/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/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..45b7816 --- /dev/null +++ b/src/main/java/org/eh/core/web/controller/IndexController.java @@ -0,0 +1,19 @@ +package org.eh.core.web.controller; + +import java.util.Map; + +import org.eh.core.model.ResultInfo; + +/** + * 主页对应的contoller + * @author guojing + */ +public class IndexController implements Controller{ + + public ResultInfo process(Map map){ + ResultInfo result =new ResultInfo(); + 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 7f9df8607e6455e4197d2a91f12ce25fea65fc7c Mon Sep 17 00:00:00 2001 From: NotBadPad Date: Sat, 3 May 2014 13:53:46 +0800 Subject: [PATCH 4/5] Create README.md --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..8fa571f --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +learn-1 +=============== + +示例项目第一版 +完成功能如下 +--------------- +-> 基本的http请求接收和响应 +-> 可以分别处理动态和静态资源请求,对于静态请求直接返回对应资源,对于动态请求处理后返回 +-> 简单的模板处理,通过替代符替换的方法实现模板数据渲染 From bda0347e9d1dda03cd13b0674e52681e0f8b5fff Mon Sep 17 00:00:00 2001 From: NotBadPad Date: Sat, 3 May 2014 13:55:41 +0800 Subject: [PATCH 5/5] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8fa571f..f4fda53 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,6 @@ learn-1 示例项目第一版 完成功能如下 --------------- --> 基本的http请求接收和响应 --> 可以分别处理动态和静态资源请求,对于静态请求直接返回对应资源,对于动态请求处理后返回 --> 简单的模板处理,通过替代符替换的方法实现模板数据渲染 +* 基本的http请求接收和响应 +* 可以分别处理动态和静态资源请求,对于静态请求直接返回对应资源,对于动态请求处理后返回 +* 简单的模板处理,通过替代符替换的方法实现模板数据渲染