├── README.md ├── Web ├── Allocation.java ├── BaseTemplate.java ├── Cookie.java ├── DB.java ├── ExceptionalHandling.java ├── Handler.java ├── HttpServer.java ├── InternalServerError500.java ├── Json.java ├── NotFound404.java ├── Options.java ├── README.md ├── Request.java ├── ResolveQuery.java ├── Response.java ├── StaticFileServer.java ├── TemplateCompile.java ├── Tools.java └── TplCompile.java └── demo ├── Handler ├── AdminHandler.java ├── ArticleHandler.java ├── CreateHandler.java ├── IndexHandler.java └── LoginHandler.java ├── Main.java ├── Static ├── base.css └── favicon.ico ├── Template ├── article.html ├── articleTemplate.java ├── base.html ├── baseTemplate.java ├── create.html ├── createTemplate.java ├── index.html ├── indexTemplate.java ├── jump.html ├── jumpTemplate.java ├── login.html ├── loginTemplate.java ├── test.html └── testTemplate.java ├── Web ├── Allocation.java ├── BaseTemplate.java ├── Cookie.java ├── DB.java ├── ExceptionalHandling.java ├── Handler.java ├── HttpServer.java ├── InternalServerError500.java ├── Json.java ├── NotFound404.java ├── Options.java ├── Request.java ├── ResolveQuery.java ├── Response.java ├── StaticFileServer.java ├── TemplateCompile.java ├── Tools.java └── TplCompile.java └── blog.sql /README.md: -------------------------------------------------------------------------------- 1 | # Web.Java 简介 2 | ========= 3 | 4 | 轻量级,无依赖 5 | ---- 6 | 7 | Web.Java没有任何依赖,只要安装JDK7及以上版本就可以独立运行。不需要安装其他任何的东西。 8 | 当然,如果你要使用数据库需要需要相应的JDBC。如果你想,你可以使用任何你想使用的扩展。 9 | 10 | 非阻塞,高性能 11 | ---- 12 | 13 | Web.Java是一个高性能,轻量级的非阻塞式服务器,而且速度相当快。 14 | 为了能更好的提高性能,Web.Java把HTTP服务区分应用和文件服务两种。 15 | - Web.Java 整体采用Reactor模式用来接收或响应HTTP请求(原理同Nginx)。 16 | - 应用服务采用了Reactor来响应请求。 17 | - 文件服务采用了Proactor模式,并搭配304状态使用,能极大的提高静态文件的相应速度,且不影响整体。 18 | 19 | 模板引擎 20 | ---- 21 | - 简单的标签:只需要记住{{}}标签用于输出变量,{%%}标签用于if,for 等操作。 22 | - 可以继承的模版:页面的布局,HTML文件的复用等问题,通过模版继承机制可以得到解决。用{%extends xx%}关键字实现继承。 23 | - 高性能:Web.Java会自动把Html文件,编译成Java文件。应用到生产环境的时候,速度等同于Java的硬输出。且在DEBUG模式下,会动态的加载模板文件,而不需要重启进程。 24 | 25 | 26 | 27 | 灵活漂亮的URL 28 | ---- 29 | 随便打开几个J2EE的网站,我就不想吐槽那个URL了。Web.Java使用正则表达式来配置URL,这样做可以提供足够强大和灵活的URL模式。比如像用“/Article/23”想获取文章的ID可以这样来配置URL 30 | ``` 31 | HttpServer.setPATH("/Article/(\\d+)",new ArticleHandler()); 32 | 33 | //ArticleHandler.java文件 get方法 34 | public void get(String id){ 35 | //获取ID进行其他操作 36 | …… 37 | } 38 | ``` 39 | 这样在ArticleHandler中对应的get或者post方法中就会获取相应的参数。当然,你可以任意的使用正则表达式来配置你的URL 40 | 41 | 简单易用的数据库操作 42 | ---- 43 | ``` 44 | Options.DBURL = "jdbc:mysql://localhost:3306/test"; 45 | Options.DBDriver = "com.mysql.jdbc.Driver"; 46 | Options.DBUser = "root"; 47 | Options.DBPassword = "123456"; 48 | ``` 49 | 配置好数据库信息后,可以直接在Handler中使用DB中的静态方法进行操作。 50 | 具体的操作在DB中有说明。当然如果你想,可以使用任何你想用的ORM。当然,希望你能直接使用SQL,不想解释为什么。 51 | 52 | Hello World! 53 | ---- 54 | 看名字就知道了。让我们开始使用Web.Java吧! 55 | 把源码包放到你的项目目录下面。 56 | 然后在main方法中加入 57 | ``` 58 | HttpServer.setPATH("/", new IndexHandler()); 59 | System.out.println("Listen 8080"); 60 | HttpServer.init(8080); 61 | ``` 62 | IndexHandler.java 63 | ``` 64 | public void get() { 65 | this.writer("Hello World!"); 66 | } 67 | ``` 68 | 现在Run it 浏览器打开就会看到你Writer的内容了。 69 | -------------------------------------------------------------------------------- /Web/Allocation.java: -------------------------------------------------------------------------------- 1 | package Web; 2 | 3 | import java.lang.reflect.InvocationTargetException; 4 | import java.lang.reflect.Method; 5 | import java.util.Arrays; 6 | import java.util.HashMap; 7 | import java.util.logging.Level; 8 | import java.util.logging.Logger; 9 | import java.util.regex.Matcher; 10 | import java.util.regex.Pattern; 11 | 12 | /** 13 | * 检查path,分配调用的handler 14 | * 15 | * @author Ma 16 | */ 17 | public class Allocation { 18 | 19 | /** 20 | * 路径配置 21 | */ 22 | public static HashMap PATH = new HashMap(); 23 | 24 | /** 25 | * 初始化,分配器 26 | * 27 | * @param request 请求header 28 | */ 29 | public static void init(Request request) { 30 | 31 | 32 | //说明访问的非静态文件 33 | String[] pathArray = HttpServer.getAllPath(); 34 | for (int i = 0; i < pathArray.length; i++) { 35 | Pattern pattern = Pattern.compile(pathArray[i]); 36 | 37 | Matcher matcher = pattern.matcher(request.Path); 38 | 39 | if (matcher.matches()) { 40 | try { 41 | Class handler = Allocation.PATH.get(pathArray[i]).getClass(); 42 | //处理参数 43 | Class[] paramType = new Class[matcher.groupCount()]; 44 | Arrays.fill(paramType, String.class); 45 | Method method = handler.getMethod(request.Method.toLowerCase(), paramType); 46 | //把request赋值过去 使用 47 | handler.getMethod("init", new Class[]{Request.class}).invoke(Allocation.PATH.get(pathArray[i]), request); 48 | //调用类似构造方法; 49 | handler.getMethod("construct").invoke(Allocation.PATH.get(pathArray[i])); 50 | String[] param = new String[matcher.groupCount()]; 51 | for (int j = 0; j < param.length; j++) { 52 | param[j] = matcher.group(j + 1); 53 | 54 | } 55 | method.invoke(Allocation.PATH.get(pathArray[i]), param); 56 | 57 | } catch (NoSuchMethodException ex) { 58 | //Handler中方法不存在 59 | ExceptionalHandling.set404(ex); 60 | Logger.getLogger(Allocation.class.getName()).log(Level.SEVERE, null, ex); 61 | } catch (SecurityException ex) { 62 | //安全异常。由安全管理器抛出,用于指示违反安全情况的异常。 63 | Logger.getLogger(Allocation.class.getName()).log(Level.SEVERE, null, ex); 64 | } catch (IllegalAccessException ex) { 65 | //设置成了私有方法,应该为public 66 | InternalServerError500.set500(ex); 67 | Logger.getLogger(Allocation.class.getName()).log(Level.SEVERE, null, ex); 68 | } catch (IllegalArgumentException ex) { 69 | //调用方法的时候传递的参数不正确 70 | InternalServerError500.set500(ex); 71 | Logger.getLogger(Allocation.class.getName()).log(Level.SEVERE, null, ex); 72 | } catch (InvocationTargetException ex) { 73 | //ex.getCause() 才能获取真实的异常 74 | //一般是构造方法的错误。所以Handler中的构造方法不能有参数 75 | Logger.getLogger(Allocation.class.getName()).log(Level.SEVERE, null, ex.getCause()); 76 | } catch (Exception ex) { 77 | //这里处理其他异常,因为是用反射运行的这里要处理异常 78 | Logger.getLogger(Allocation.class.getName()).log(Level.SEVERE, null, ex); 79 | } 80 | //如果有就直接Return,终止往下执行,下面处理没找到。 81 | return; 82 | } else { 83 | 84 | continue; 85 | } 86 | } 87 | 88 | //执行到这里,说明没有找到匹配的URL发送404错误 89 | 90 | NotFound404.set404("未设置对应URL:" + request.Path); 91 | 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /Web/BaseTemplate.java: -------------------------------------------------------------------------------- 1 | package Web; 2 | 3 | import java.util.HashMap; 4 | 5 | /** 6 | * @author Ma 7 | */ 8 | public class BaseTemplate { 9 | 10 | public HashMap param; 11 | 12 | public BaseTemplate() { 13 | this.param = new HashMap(); 14 | } 15 | 16 | public String display() { 17 | return null; 18 | } 19 | 20 | public String get(String s) { 21 | if (this.param.containsKey(s)) { 22 | return this.param.get(s).toString(); 23 | } else { 24 | return null; 25 | } 26 | 27 | } 28 | 29 | /** 30 | * 获取boolean值 31 | * 32 | * @param s 33 | * @return 34 | */ 35 | public boolean getBoolean(String s) { 36 | Boolean bool = (Boolean) this.param.get(s); 37 | return bool.booleanValue(); 38 | } 39 | 40 | /** 41 | * 获取int值 42 | * 43 | * @param s 44 | * @return 45 | */ 46 | public int getInt(String s) { 47 | Integer num = (Integer) this.param.get(s); 48 | return num.intValue(); 49 | } 50 | 51 | /** 52 | * 获取一维数组 53 | * 54 | * @param s 55 | * @return 56 | */ 57 | public Object[] getArray(String s) { 58 | return (Object[]) this.param.get(s); 59 | } 60 | 61 | /** 62 | * 获取二维数组 63 | * 64 | * @param s 65 | * @return 66 | */ 67 | public Object[][] getArray2(String s) { 68 | return (Object[][]) this.param.get(s); 69 | } 70 | 71 | /** 72 | * 赋值操作 73 | */ 74 | public void assign(String key, String value) { 75 | this.param.put(key, value); 76 | } 77 | 78 | /** 79 | * 赋值操作 80 | */ 81 | public void assign(String key, int value) { 82 | this.param.put(key, value); 83 | } 84 | 85 | /** 86 | * 赋值操作 87 | */ 88 | public void assign(String key, boolean value) { 89 | this.param.put(key, value); 90 | } 91 | 92 | /** 93 | * 赋值操作 94 | */ 95 | public void assign(String key, Object[] value) { 96 | this.param.put(key, value); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /Web/Cookie.java: -------------------------------------------------------------------------------- 1 | package Web; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | import java.util.HashMap; 5 | import java.util.logging.Level; 6 | import java.util.logging.Logger; 7 | 8 | /** 9 | * Cookie操作类 maxAge 说明 0表示立即删除,负数表示关闭页面删除,正数表示生存时间 10 | * 11 | * @author Ma 12 | */ 13 | public class Cookie { 14 | 15 | public static HashMap RequestCookie; 16 | 17 | public static void analysis(String request) { 18 | String[] temp = request.split(";"); 19 | Cookie.RequestCookie = new HashMap(); 20 | for (int i = 0; i < temp.length; i++) { 21 | String[] item = temp[i].trim().split("\\="); 22 | Cookie.RequestCookie.put(item[0].trim(), item[1].trim()); 23 | } 24 | 25 | } 26 | 27 | /** 28 | * 设置cookie 29 | */ 30 | public static void setCookie(String name, String value, int maxAge, String path, String domain) { 31 | String cookieString = "Set-Cookie: " + name + "=" + Cookie.encode(value) + "; Max-Age=" + maxAge + ";path=" + path + ";domian=" + domain + ";"; 32 | Response.Cookies.add(cookieString); 33 | 34 | } 35 | 36 | /** 37 | * 设置cookie 38 | */ 39 | public static void setCookie(String name, String value, int maxAge, String path) { 40 | String cookieString = "Set-Cookie: " + name + "=" + Cookie.encode(value) + "; Max-Age=" + maxAge + ";path=" + path + ";"; 41 | Response.Cookies.add(cookieString); 42 | 43 | } 44 | 45 | /** 46 | * 设置cookie 47 | */ 48 | public static void setCookie(String name, String value, int maxAge) { 49 | String cookieString = "Set-Cookie: " + name + "=" + Cookie.encode(value) + "; Max-Age=" + maxAge + ";"; 50 | Response.Cookies.add(cookieString); 51 | 52 | } 53 | 54 | /** 55 | * 设置cookie 56 | */ 57 | public static void setCookie(String name, String value) { 58 | 59 | String cookieString = "Set-Cookie: " + name + "=" + Cookie.encode(value) + ";"; 60 | Response.Cookies.add(cookieString); 61 | } 62 | 63 | /** 64 | * 获取Cookie值 65 | * 66 | * @param name 67 | * @return 68 | */ 69 | public static String getCookie(String name) { 70 | if (Cookie.RequestCookie !=null && Cookie.RequestCookie.containsKey(name)) { 71 | String value = (String) Cookie.RequestCookie.get(name); 72 | return Cookie.decode(value); 73 | }else{ 74 | return null; 75 | } 76 | } 77 | 78 | /** 79 | * 编码字符串 80 | * 81 | * @param encode 82 | * @return 83 | */ 84 | private static String encode(String encode) { 85 | try { 86 | encode = java.net.URLEncoder.encode(encode, "UTF-8"); 87 | return encode; 88 | } catch (UnsupportedEncodingException ex) { 89 | Logger.getLogger(Cookie.class.getName()).log(Level.SEVERE, null, ex); 90 | } 91 | return null; 92 | } 93 | 94 | /** 95 | * 解码字符串 96 | * 97 | * @param decode 98 | * @return 99 | */ 100 | private static String decode(String decode) { 101 | 102 | try { 103 | decode = java.net.URLDecoder.decode(decode, "UTF-8"); 104 | return decode; 105 | } catch (UnsupportedEncodingException ex) { 106 | Logger.getLogger(Cookie.class.getName()).log(Level.SEVERE, null, ex); 107 | } 108 | return null; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /Web/DB.java: -------------------------------------------------------------------------------- 1 | package Web; 2 | 3 | /** 4 | * 数据库操作 5 | * @author Ma 6 | */ 7 | 8 | import com.sun.org.apache.regexp.internal.REUtil; 9 | 10 | import java.sql.Connection; 11 | import java.sql.DriverManager; 12 | import java.sql.PreparedStatement; 13 | import java.sql.ResultSet; 14 | import java.sql.ResultSetMetaData; 15 | import java.sql.SQLException; 16 | import java.sql.Types; 17 | import java.util.logging.Level; 18 | import java.util.logging.Logger; 19 | 20 | public class DB { 21 | 22 | public static Connection Connection; 23 | public static int lastUserTime; 24 | 25 | public static void connection() { 26 | 27 | if ((Options.DBDriver != null) && (Options.DBURL != null) && (Options.DBUser != null) && (Options.DBPassword != null)) { 28 | String driver = Options.DBDriver; // 驱动程序名 29 | String url = Options.DBURL; // URL指向要访问的数据库名 30 | try { 31 | Class.forName(driver); // 加载驱动程序 32 | Connection conn = DriverManager.getConnection(url, Options.DBUser, Options.DBPassword); // 连续数据库 33 | //验证是否连接成功 34 | if (!conn.isClosed()) { 35 | DB.Connection = conn; 36 | DB.lastUserTime = (int) (System.currentTimeMillis() / 1000); 37 | } else { 38 | DB.Connection = null; 39 | } 40 | 41 | //DB.Connection.close();如果会自动处理就不用手动释放资源了 42 | } catch (ClassNotFoundException ex) { 43 | Logger.getLogger(Allocation.class.getName()).log(Level.SEVERE, null, ex); 44 | System.exit(-1); 45 | } catch (SQLException ex) { 46 | Logger.getLogger(Allocation.class.getName()).log(Level.SEVERE, null, ex); 47 | System.exit(-1); 48 | } catch (Exception ex) { 49 | Logger.getLogger(Allocation.class.getName()).log(Level.SEVERE, null, ex); 50 | } 51 | } 52 | } 53 | 54 | /** 55 | * 用原生态的executeQuery 返回ResultSet 56 | * 57 | * @param sql 58 | * @param params 59 | * @return ResultSet 60 | */ 61 | public static ResultSet executeQuery(String sql, String... params) { 62 | DB.cursor(); 63 | PreparedStatement statement; 64 | try { 65 | statement = DB.Connection.prepareStatement(sql); 66 | for (int i = 0; i < params.length; i++) { 67 | statement.setString((i + 1), params[i]); 68 | } 69 | ResultSet r = statement.executeQuery(); 70 | return r; 71 | } catch (SQLException ex) { 72 | Logger.getLogger(DB.class.getName()).log(Level.SEVERE, null, ex); 73 | } 74 | 75 | return null; 76 | } 77 | 78 | /** 79 | * 用原生态的executeUpdate 80 | * 81 | * @param sql 82 | * @param params 83 | * @return 84 | */ 85 | public static int executeUpdate(String sql, String... params) { 86 | DB.cursor(); 87 | try { 88 | PreparedStatement statement = DB.Connection.prepareStatement(sql); 89 | for (int i = 0; i < params.length; i++) { 90 | statement.setString((i + 1), params[i]); 91 | } 92 | int r = statement.executeUpdate(); 93 | statement.close(); 94 | return r; 95 | } catch (SQLException ex) { 96 | Logger.getLogger(DB.class.getName()).log(Level.SEVERE, null, ex); 97 | } 98 | return 0; 99 | 100 | } 101 | 102 | /** 103 | * 获取多个结果集 104 | * 105 | * @param sql 106 | * @param params 107 | */ 108 | public static Object[][] get(String sql, String... params) { 109 | DB.cursor(); 110 | Object[][] data = null; 111 | try { 112 | PreparedStatement statement = DB.Connection.prepareStatement(sql); 113 | for (int i = 0; i < params.length; i++) { 114 | statement.setString((i + 1), params[i]); 115 | } 116 | 117 | ResultSet r = statement.executeQuery(); 118 | //获取字段信息getMetaData 119 | ResultSetMetaData columns = r.getMetaData(); 120 | 121 | int columnCount = columns.getColumnCount(); 122 | String[] columnName = new String[columnCount]; 123 | int[] columnTypeName = new int[columnCount]; 124 | for (int i = 1; i <= columnCount; i++) { 125 | columnName[i - 1] = columns.getColumnName(i); 126 | columnTypeName[i - 1] = DB.getTypeName(columns.getColumnType(i)); 127 | } 128 | 129 | r.last(); 130 | 131 | int rowCount = r.getRow(); 132 | if (rowCount < 1) { 133 | return new Object[rowCount][columnCount]; 134 | } 135 | r.first(); 136 | data = new Object[rowCount][columnCount]; 137 | int i = 0; 138 | 139 | do { 140 | Object[] temp = new Object[columnCount]; 141 | for (int j = 0; j < columnName.length; j++) { 142 | switch (columnTypeName[j]) { 143 | case 0: 144 | temp[j] = r.getBoolean(j + 1); 145 | break; 146 | case 1: 147 | temp[j] = r.getInt(j + 1); 148 | break; 149 | default: 150 | temp[j] = r.getString(j + 1); 151 | break; 152 | 153 | } 154 | } 155 | 156 | data[i] = temp; 157 | i++; 158 | } while (r.next()); 159 | //随手关闭 160 | r.close(); 161 | 162 | statement.close(); 163 | return data; 164 | 165 | 166 | } catch (SQLException ex) { 167 | Logger.getLogger(Handler.class.getName()).log(Level.SEVERE, null, ex); 168 | } 169 | return data; 170 | } 171 | 172 | /** 173 | * 获取一行 174 | * 175 | * @param sql 176 | * @param params 177 | * @return 178 | */ 179 | public static Object[] find(String sql, String... params) { 180 | Object[][] r = DB.get(sql, params); 181 | if (r.length < 1) { 182 | return new Object[0]; 183 | } 184 | return r[0]; 185 | } 186 | 187 | /** 188 | * 获取一个字段 189 | * 190 | * @param sql 191 | * @param params 192 | * @return 193 | */ 194 | public static Object getField(String sql, String... params) { 195 | Object[][] r = DB.get(sql, params); 196 | if (r.length < 1) { 197 | return null; 198 | } else { 199 | return r[0][0]; 200 | } 201 | 202 | } 203 | 204 | /** 205 | * 更新数据 206 | * 207 | * @param sql 208 | * @param params 209 | * @return 210 | */ 211 | public static int update(String sql, String... params) { 212 | DB.cursor(); 213 | try { 214 | PreparedStatement statement = DB.Connection.prepareStatement(sql); 215 | for (int i = 0; i < params.length; i++) { 216 | statement.setString((i + 1), params[i]); 217 | } 218 | //获取字段信息getMetaData 219 | int r = statement.executeUpdate(); 220 | statement.close(); 221 | return r; 222 | } catch (SQLException ex) { 223 | Logger.getLogger(DB.class.getName()).log(Level.SEVERE, null, ex); 224 | } 225 | return 0; 226 | } 227 | 228 | public static int insert(String sql, String... params) { 229 | return DB.update(sql, params); 230 | } 231 | 232 | public static int delete(String sql, String... params) { 233 | return DB.update(sql, params); 234 | } 235 | 236 | /** 237 | * 解析SQL便于开发 238 | * 239 | * @param sql 240 | * @param params 241 | * @return 242 | */ 243 | public static String getSQL(String sql, String... params) { 244 | for (int i = 0; i < params.length; i++) { 245 | sql = sql.replaceFirst("\\?", sql); 246 | } 247 | return sql; 248 | } 249 | 250 | public static int getTypeName(int typeId) { 251 | switch (typeId) { 252 | case Types.NUMERIC: 253 | //Int 类型 254 | return 1; 255 | case Types.BOOLEAN: 256 | //Boolean类型 257 | return 0; 258 | default: 259 | //其余的当作String处理 260 | return 2; 261 | } 262 | } 263 | 264 | /** 265 | * 检查链接时间是否过期 266 | */ 267 | public static void cursor() { 268 | if ((DB.lastUserTime + Options.DBIdleTime) < System.currentTimeMillis()) { 269 | DB.connection(); 270 | } else { 271 | DB.lastUserTime = (int) System.currentTimeMillis() / 1000; 272 | } 273 | } 274 | } 275 | -------------------------------------------------------------------------------- /Web/ExceptionalHandling.java: -------------------------------------------------------------------------------- 1 | package Web; 2 | 3 | /** 4 | * 处理整体异常的 5 | * 6 | * @author Ma 7 | */ 8 | public class ExceptionalHandling { 9 | 10 | /** 11 | * 404异常处理 12 | * 13 | * @param ex 14 | */ 15 | public static void set404(Exception ex) { 16 | NotFound404.set404(ex); 17 | } 18 | 19 | /** 20 | * 500错误处理 21 | * 22 | * @param ex 23 | */ 24 | public static void set500(Exception ex) { 25 | InternalServerError500.set500(ex); 26 | } 27 | 28 | /** 29 | * 处理其他异常 30 | * @param ex 31 | */ 32 | public static void handling(Exception ex){ 33 | 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Web/Handler.java: -------------------------------------------------------------------------------- 1 | package Web; 2 | 3 | import java.util.logging.Level; 4 | import java.util.logging.Logger; 5 | import java.util.HashMap; 6 | 7 | /** 8 | * 9 | * @author Ma 10 | */ 11 | public class Handler { 12 | 13 | public Request request; 14 | 15 | /** 16 | * 初始化Handler 17 | */ 18 | public void init(Request request) { 19 | this.request = request; 20 | 21 | } 22 | 23 | /** 24 | * 用于实现一些类似构造方法的作用 25 | * @todo 装饰器实现 26 | */ 27 | public void construct() { 28 | ; 29 | } 30 | 31 | /** 32 | * 获取参数 33 | * @param key 34 | * @return 35 | */ 36 | public Object getArgument(String key){ 37 | return this.request.Arguments.get(key); 38 | } 39 | /** 40 | * 把模版或者字符串写入 41 | * @param s 42 | */ 43 | public void writer(String s) { 44 | Response.setContent(s); 45 | } 46 | 47 | /** 48 | * 读取模版 49 | */ 50 | public BaseTemplate render(String fileName) { 51 | 52 | try { 53 | BaseTemplate object; 54 | if (Options.DEBUG) { 55 | fileName = fileName.replace(".", "/");//把点替换成路径 56 | TplCompile tplCompile = new TplCompile(); 57 | object = (BaseTemplate) tplCompile.run(fileName + ".html"); 58 | if (object == null) { 59 | InternalServerError500.set500(fileName + "模版不存在!"); 60 | } 61 | } else { 62 | Class TemplateClass = Class.forName("Template." + fileName + "Template"); 63 | object = (BaseTemplate) TemplateClass.newInstance(); 64 | } 65 | return object; 66 | } catch (ClassNotFoundException ex) { 67 | //模版不存在 68 | InternalServerError500.set500(fileName + "模版不存在!"); 69 | Logger.getLogger(Handler.class.getName()).log(Level.SEVERE, null, ex); 70 | } catch (InstantiationException ex) { 71 | Logger.getLogger(Handler.class.getName()).log(Level.SEVERE, null, ex); 72 | } catch (IllegalAccessException ex) { 73 | Logger.getLogger(Handler.class.getName()).log(Level.SEVERE, null, ex); 74 | } 75 | return null; 76 | } 77 | 78 | /** 79 | * 重定向到URL,发送303 80 | * 81 | * @param url 82 | */ 83 | public void redirect(String url) { 84 | Response.setStatus(303); 85 | if (url.toLowerCase().indexOf("http://") < 0) { 86 | url = "http://" + this.request.Header.get("Host") + url; 87 | } 88 | Response.header("Location: " + url); 89 | } 90 | 91 | /** 92 | * 页面跳转到URL中,通过HTML 93 | * 94 | * @param url 95 | * @param time 96 | */ 97 | public void jump(String message, String url, int time, boolean status) { 98 | 99 | boolean isSetUrl = false; 100 | 101 | if (message == null) { 102 | message = "Message!"; 103 | } 104 | if (time < 1) { 105 | time = 3; 106 | } 107 | if ("XMLHttpRequest".equals(this.request.Header.get("X-Requested-With"))) { 108 | //判断Ajax请求 109 | HashMap map = new HashMap(); 110 | map.put("static", status); 111 | map.put("data", message); 112 | Response.setContentType(Response.findContentType("json")); 113 | this.writer(Json.encode(map)); 114 | } else { 115 | BaseTemplate jump = this.render("jump"); 116 | jump.assign("status", status); 117 | jump.assign("message", message); 118 | if (url != null) { 119 | isSetUrl = true; 120 | } 121 | jump.assign("isSetUrl", isSetUrl); 122 | jump.assign("url", url); 123 | jump.assign("wait", time); 124 | this.writer(jump.display()); 125 | } 126 | 127 | } 128 | 129 | /** 130 | * 操作成功 131 | */ 132 | public void success(String message, String url, int time) { 133 | if (message == null) { 134 | message = "Success!"; 135 | } 136 | this.jump(message, url, time, true); 137 | } 138 | 139 | /** 140 | * 操作成功 141 | */ 142 | public void success(String message, String url) { 143 | this.success(message, url, 0); 144 | } 145 | 146 | /** 147 | * 操作成功 148 | */ 149 | public void success(String message) { 150 | this.success(message, null, 0); 151 | } 152 | 153 | /** 154 | * 操作错误 155 | */ 156 | public void error(String message, String url, int time) { 157 | if (message == null) { 158 | message = "Error!"; 159 | } 160 | this.jump(message, url, time, false); 161 | } 162 | 163 | /** 164 | * 操作错误 165 | */ 166 | public void error(String message, String url) { 167 | this.error(message, url, 0); 168 | } 169 | 170 | /** 171 | * 操作错误 172 | */ 173 | public void error(String message) { 174 | this.error(message, null, 0); 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /Web/HttpServer.java: -------------------------------------------------------------------------------- 1 | package Web; 2 | 3 | import java.io.IOException; 4 | import java.net.InetSocketAddress; 5 | import java.nio.ByteBuffer; 6 | import java.nio.CharBuffer; 7 | import java.nio.channels.SelectionKey; 8 | import java.nio.channels.Selector; 9 | import java.nio.channels.ServerSocketChannel; 10 | import java.nio.channels.SocketChannel; 11 | import java.nio.charset.Charset; 12 | 13 | import java.util.Iterator; 14 | import java.util.Set; 15 | import java.util.logging.Level; 16 | import java.util.logging.Logger; 17 | 18 | /** 19 | * 服务器 负责分配静态文件服务器和应用服务 20 | * 21 | * @author Ma 22 | */ 23 | public class HttpServer { 24 | 25 | public static void init(int port) { 26 | try { 27 | //初始化数据库连接 28 | DB.connection(); 29 | Selector selector = Selector.open();//创建selector 30 | ServerSocketChannel serverChannel = ServerSocketChannel.open(); 31 | serverChannel.socket().bind(new InetSocketAddress(port)); 32 | serverChannel.configureBlocking(false); 33 | serverChannel.register(selector, SelectionKey.OP_ACCEPT);//注册 34 | SocketChannel channel; 35 | try { 36 | while (true) { 37 | selector.select(); 38 | Iterator iter = selector.selectedKeys().iterator(); 39 | while (iter.hasNext()) { 40 | 41 | SelectionKey key = iter.next(); 42 | iter.remove(); 43 | 44 | Object attach = key.attachment(); 45 | //如果有正在读取静态文件的标记就返回 46 | if (attach != null && attach.equals(0)) { 47 | continue; 48 | } 49 | 50 | 51 | //开始处理 52 | if (key.isAcceptable()) { // 接收请求 53 | ServerSocketChannel server = (ServerSocketChannel) key.channel(); 54 | channel = server.accept(); 55 | //设置非阻塞模式 56 | channel.configureBlocking(false); 57 | channel.register(selector, SelectionKey.OP_READ); 58 | } else if (key.isReadable()) { // 读信息 59 | channel = (SocketChannel) key.channel(); 60 | ByteBuffer clientBuffer = ByteBuffer.allocate(1024); 61 | int count = channel.read(clientBuffer); 62 | String receive = ""; 63 | while (count > 0) { 64 | clientBuffer.flip(); 65 | CharBuffer charBuffer = Charset.forName("UTF-8").decode(clientBuffer); 66 | String temp = charBuffer.toString(); 67 | receive = receive + temp; 68 | clientBuffer.clear(); 69 | count = channel.read(clientBuffer); 70 | channel.register(selector, SelectionKey.OP_WRITE); 71 | } 72 | 73 | key.attach(receive); 74 | clientBuffer.clear(); 75 | } else if (key.isWritable()) { // 写事件 76 | 77 | //开始处理事件 78 | //开始时间 79 | long startTime = System.currentTimeMillis(); 80 | channel = (SocketChannel) key.channel(); 81 | boolean accessStaticFile = false;//是不是访问的静态文件 82 | // 写事件 83 | Request request = new Request((String) key.attachment()); 84 | if (request.Path.equals("/favicon.ico") || request.Path.equals("robots.txt") || request.Path.toLowerCase().indexOf("/static") == 0) { 85 | //##处理 86 | //#说明是访问静态文件 87 | accessStaticFile = true; 88 | StaticFileServer staticFile = new StaticFileServer(request); 89 | if (staticFile.exists()) { 90 | staticFile.read(channel); 91 | key.attach(0);//这个标记是正在读取静态文件 92 | continue;//读取下一个循环 93 | } else { 94 | //如果不存在 95 | //当作非静态文件处理404 省事 96 | accessStaticFile = false; 97 | Response.setStatus(404); 98 | } 99 | 100 | } 101 | //访问的不是静态文件,或者静态文件不存在 102 | if (!accessStaticFile) { 103 | //###处理请求 104 | //获取客户端IP 105 | request.setRemoteIP(channel.socket().getLocalAddress().getHostName()); 106 | //开始分配到Handler 107 | Allocation.init(request); 108 | 109 | //Handler结束 110 | 111 | if (Response.Content == null) { 112 | Response.setContent("未知错误造成,无返回实体!"); 113 | Response.setStatus(500); 114 | } 115 | byte[] contentBytes = Response.Content.getBytes("UTF-8"); 116 | //先设置实体长度 117 | Response.setContentLength(contentBytes.length); 118 | 119 | //然后获取header 120 | byte[] headerBytes = Response.getHeader().getBytes("UTF-8"); 121 | ByteBuffer writerBuffer = ByteBuffer.allocate(headerBytes.length + contentBytes.length); 122 | writerBuffer.clear(); 123 | writerBuffer.put(headerBytes); 124 | writerBuffer.put(contentBytes); 125 | writerBuffer.flip(); 126 | while (writerBuffer.hasRemaining()) { 127 | channel.write(writerBuffer); 128 | } 129 | writerBuffer.clear(); 130 | channel.close(); 131 | //输出debug信息 132 | if (Options.DEBUG || Options.ParseLine) { 133 | System.out.println(Response.Status + " " + request.Header.get("Host") + request.Path + " " + (System.currentTimeMillis() - startTime) + "ms"); 134 | } 135 | //完成响应,清理相应信息 136 | Response.finish(); 137 | } 138 | 139 | } 140 | 141 | } 142 | } 143 | } finally { 144 | serverChannel.close(); 145 | } 146 | } catch (IOException ex) { 147 | Logger.getLogger(HttpServer.class.getName()).log(Level.SEVERE, null, ex); 148 | } 149 | } 150 | 151 | /** 152 | * 设置URL 153 | * 154 | * @param path 155 | * @param handler 156 | */ 157 | public static void setPATH(String path, Object handler) { 158 | Allocation.PATH.put(path, handler); 159 | } 160 | 161 | /** 162 | * 获取所有的Path 163 | * 164 | * @return 165 | */ 166 | public static String[] getAllPath() { 167 | String[] pathArray = new String[Allocation.PATH.size()]; 168 | Set set = Allocation.PATH.entrySet(); 169 | Iterator iterator = set.iterator(); 170 | int i = 0; 171 | while (iterator.hasNext()) { 172 | java.util.Map.Entry item = (java.util.Map.Entry) iterator.next(); 173 | pathArray[i] = (String) item.getKey(); 174 | i++; 175 | } 176 | return pathArray; 177 | } 178 | } -------------------------------------------------------------------------------- /Web/InternalServerError500.java: -------------------------------------------------------------------------------- 1 | package Web; 2 | 3 | /** 4 | * 处理500错误 5 | * 6 | * @author Ma 7 | */ 8 | public class InternalServerError500 { 9 | 10 | public static void set500(String string) { 11 | Response.setContent("

500 服务器方法生错误

" + string); 12 | Response.setStatus(500); 13 | } 14 | 15 | /** 16 | * 触发500异常 17 | */ 18 | public static void set500(Exception ex) { 19 | InternalServerError500.set500(ex.toString()); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Web/Json.java: -------------------------------------------------------------------------------- 1 | package Web; 2 | 3 | import java.util.Collection; 4 | import java.util.HashMap; 5 | import java.util.Iterator; 6 | import java.util.Map; 7 | 8 | /** 9 | * Json处理,只处理声称Json字符串 10 | * 11 | * @author Ma 12 | */ 13 | public class Json { 14 | 15 | public static String encode(HashMap map) { 16 | Iterator iters = map.entrySet().iterator(); 17 | 18 | String json = "{"; 19 | while (iters.hasNext()) { 20 | Map.Entry entry = (Map.Entry) iters.next(); 21 | Object key = entry.getKey(); 22 | Object val = entry.getValue(); 23 | json += key.toString() + ":"; 24 | if (val instanceof HashMap) { 25 | json += Json.encode((HashMap) val) + ","; 26 | } else { 27 | json = json + "\"" + val.toString() + "\","; 28 | } 29 | } 30 | json = json.substring(0, json.length() - 1) + "}"; 31 | return json; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Web/NotFound404.java: -------------------------------------------------------------------------------- 1 | package Web; 2 | 3 | /** 4 | * 处理404错误 5 | * 6 | * @author Ma 7 | */ 8 | public class NotFound404 { 9 | 10 | public static void set404(String string) { 11 | Response.setContent("

404 没找到

"+string); 12 | Response.setStatus(404); 13 | } 14 | 15 | /** 16 | * 异常引起的404 17 | */ 18 | public static void set404(Exception ex) { 19 | NotFound404.set404(ex.toString()); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Web/Options.java: -------------------------------------------------------------------------------- 1 | package Web; 2 | 3 | /** 4 | * 运行时的配置 5 | * 6 | * @author Ma 7 | */ 8 | public class Options { 9 | 10 | /** 11 | * 是不是debug模式 12 | */ 13 | public static boolean DEBUG = false; 14 | /** 15 | * 是否打印信息 16 | */ 17 | public static boolean ParseLine = false; 18 | public static String DBURL = null;//地址 19 | public static String DBDriver = null;//驱动 20 | public static String DBUser = null;//用户 21 | public static String DBPassword = null;//密码 22 | public static int DBIdleTime = 25200;//数据库最大闲置时间 23 | 24 | public static String ServerName = "Web.Java 1.0";//服务器名字 25 | 26 | public static String StaticPath = "/src/Web/Static/";//静态文件目录 27 | public static String TemplatePath = "/src/Web/Template/";//模版文件目录 28 | 29 | 30 | } 31 | -------------------------------------------------------------------------------- /Web/README.md: -------------------------------------------------------------------------------- 1 | 2 | 模版说明 3 | 使用继承 4 | 顶顶顶顶顶 5 | {% block body %} 6 | XXXX 7 | hkud 8 | {% end %} 9 | 开始和end标记之间是默认内容,如果没有被继承就显示默认内容否则显示 10 | 11 | 文件的开始处生命继承的模版只允许单一继承(一层继承关系 待定) 12 | 13 | 一个文件可以包含多个文本块。在继承的文件只实现多个 14 | 15 | {%block de%} 16 | 得到 17 | 18 | dddd{%if(true)%} 19 |
dsssssssssssssssss
20 | {%endif%}sss 21 | {% end %} 22 | 语法 23 | 测试语法开始 24 |
25 |
26 | 测试For 27 | {%for(int i = 0; i < $for:array.length; i++)%} 28 | 城市是:{{for:i}} 29 | {%endfor%} 30 |
31 |
32 | {{frist}} 33 | dddd{%if(true)%} 34 |
dddddddddddddddddddddd
35 | {%elseif($name:boolean&&true)%} 36 |
fsssssssssssssssfffff
37 | {%else%} 38 |
fffffffffffff
39 | {%endif%}sss 40 | 41 | {{name}} 42 | 43 | {%for(int i=0;i<5;i++)%} 44 | for循环的测试点点滴滴点点滴滴的的的的的的 45 | {%endfor%} 46 | 47 | {#de = de+"fr"#} 48 | 测试执行任意Java语句 49 | 50 | {{}} 表示 输出变量 51 | {%%}if for 语句 52 | {##}执行的语句 53 | 54 | ###### 55 | 以上部分是文档说明 56 | -------------------------------------------------------------------------------- /Web/Request.java: -------------------------------------------------------------------------------- 1 | package Web; 2 | 3 | import java.util.HashMap; 4 | import java.util.StringTokenizer; 5 | 6 | /** 7 | * 处理接受到的数据 8 | * 9 | * @author Ma 10 | */ 11 | public class Request { 12 | 13 | public HashMap Header; 14 | public HashMap Arguments; 15 | public HashMap Cookies; 16 | public String Path; 17 | public String Method; 18 | public String RemoteIP; 19 | 20 | /** 21 | * 处理接收数据 22 | * @param receive 接受 23 | */ 24 | public Request(String receive) { 25 | 26 | StringTokenizer stringTokenizer = new StringTokenizer(receive, "\n"); 27 | String[] receiveArray = new String[stringTokenizer.countTokens()]; 28 | HashMap hashMap = new HashMap(); 29 | this.Header = new HashMap(); 30 | this.Arguments = new HashMap(); 31 | this.Cookies = new HashMap(); 32 | String[] URLStrings = stringTokenizer.nextToken().split(" "); 33 | this.Method = URLStrings[0];//请求方式 34 | String href = URLStrings[1]; //URL 35 | String[] hrefSplit = href.split("\\?", 2); 36 | this.Path = hrefSplit[0]; 37 | //分析URL传值 38 | if (hrefSplit.length > 1) { 39 | String query = hrefSplit[1]; 40 | this.Arguments = ResolveQuery.query(query); 41 | } 42 | 43 | while (stringTokenizer.hasMoreTokens()) { 44 | String temp = stringTokenizer.nextToken().trim(); 45 | //长度小于1说明是个空白行,说明header可以结束了,如果是POST请求下面的就是参数了 46 | if (temp.length() < 1) { 47 | break; 48 | } 49 | String[] split = temp.split(":", 2); 50 | if (split.length < 2) { 51 | ; 52 | } 53 | if (split[0].toLowerCase().equals("cookie")) { 54 | //解析Cookie,不记录到Header中 55 | Cookie.analysis(split[1].trim()); 56 | continue; 57 | } 58 | this.Header.put(split[0], split[1].trim()); 59 | } 60 | while (stringTokenizer.hasMoreTokens()) { 61 | String temp = stringTokenizer.nextToken().trim(); 62 | //长度小于1说明是个空白行,说明header可以结束了,如果是POST请求下面的就是参数了 63 | if (temp.length() < 1) { 64 | continue; 65 | } 66 | this.Arguments.putAll(ResolveQuery.query(temp)); 67 | 68 | } 69 | 70 | } 71 | 72 | /** 73 | * 获取用户远程IP 74 | * @return 远程IP 75 | */ 76 | public String getRemoteIP() { 77 | if(this.Header.containsKey("True-ip")){ 78 | this.RemoteIP = (String) this.Header.get("True-ip"); 79 | } 80 | return this.RemoteIP; 81 | } 82 | 83 | /** 84 | * 设置远程IP 85 | * @param RemoteIP 86 | */ 87 | public void setRemoteIP(String RemoteIP) { 88 | this.RemoteIP = RemoteIP; 89 | } 90 | 91 | 92 | 93 | } 94 | -------------------------------------------------------------------------------- /Web/ResolveQuery.java: -------------------------------------------------------------------------------- 1 | package Web; 2 | 3 | import java.util.HashMap; 4 | 5 | /** 6 | * 解析处理URL Query 7 | * 8 | * @author Ma 9 | */ 10 | public class ResolveQuery { 11 | 12 | /** 13 | * 负责解析处理 14 | * @param query 需要解析 15 | * @return 解析完成的数据 16 | */ 17 | public static HashMap query(String query) { 18 | HashMap hashMap = new HashMap(); 19 | String[] split = query.split("&"); 20 | for (int i = 0; i < split.length; i++) { 21 | String string = split[i]; 22 | String[] kvsplit = string.split("=",2); 23 | hashMap.put(java.net.URLDecoder.decode(kvsplit[0]), java.net.URLDecoder.decode(kvsplit[1])); 24 | } 25 | return hashMap; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Web/Response.java: -------------------------------------------------------------------------------- 1 | package Web; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | import java.util.ArrayList; 5 | import java.util.Arrays; 6 | import java.util.HashMap; 7 | 8 | /** 9 | * 用于记录一些相应信息 如状态码,cookie等 10 | * 11 | * @author Ma 12 | */ 13 | public class Response { 14 | 15 | /** 16 | * 返回消息实体 17 | */ 18 | public static String Content = ""; 19 | /** 20 | * 如果是文件就直接些进去 21 | */ 22 | public static byte[] FileBytes; 23 | /** 24 | * 标记这次是不是请求文件的 25 | */ 26 | public static boolean IsFile = false; 27 | public static ArrayList Header = new ArrayList(); 28 | public static String Status = "HTTP/1.1 200 OK"; 29 | public static ArrayList Cookies = new ArrayList(); 30 | public static String ContentType = "text/html;charset=UTF-8;"; 31 | /** 32 | * 服务器的名字 33 | */ 34 | public static String Server = Options.ServerName; 35 | /** 36 | * 只包含Contest的长度不包含header的长度 37 | */ 38 | public static int ContentLength; 39 | 40 | /** 41 | * //禁用页面缓存
42 | * header('Cache-Control: no-cache, no-store, max-age=0,must-revalidate'); 43 | *
44 | * header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
45 | * header('Pragma: no-cache');
46 | * 47 | * public static String X-Powered-By; 48 | * 49 | */ 50 | /** 51 | * 设置状态码 HTTP/1.1 200 OK
52 | * HTTP/1.1 303 See Other \r\nLocation:http://www.maiyoule.com/ 结尾没有分号
53 | * HTTP/1.1 304 Not Modified 缓存
54 | * HTTP/1.1 403 Forbidden
55 | * HTTP/1.1 404 Not Found
56 | * HTTP/1.1 500 Internal Server Error
57 | * 58 | * @param code 59 | */ 60 | public static void setStatus(int code) { 61 | String string; 62 | switch (code) { 63 | case 200: 64 | string = "HTTP/1.1 200 OK"; 65 | break; 66 | case 303: 67 | string = "HTTP/1.1 303 See Other"; 68 | break; 69 | case 304: 70 | string = "HTTP/1.1 304 Not Modified"; 71 | break; 72 | case 403: 73 | string = "HTTP/1.1 403 Forbidden"; 74 | break; 75 | case 404: 76 | string = "HTTP/1.1 404 Not Found"; 77 | break; 78 | case 500: 79 | string = "HTTP/1.1 500 Internal Server Error"; 80 | break; 81 | default: 82 | string = "HTTP/1.1 200 OK"; 83 | } 84 | Response.Status = string; 85 | 86 | } 87 | 88 | /** 89 | * 设置content-length长度 90 | * 91 | * @param length 92 | */ 93 | public static void setContentLength(int length) { 94 | Response.ContentLength = length; 95 | } 96 | 97 | /** 98 | * 设置ContentType application/json; charset=utf-8;
99 | * text/html;charset=UTF-8;
100 | * application/xml;charset=UTF-8;
101 | */ 102 | public static void setContentType(String type) { 103 | Response.ContentType = type; 104 | } 105 | 106 | /** 107 | * 查找ContentType类型 不能识别的文件,默认当作zip处理 108 | * 109 | * @todo 是否允许自己配置 110 | */ 111 | public static String findContentType(String type) { 112 | HashMap contentType = new HashMap(); 113 | contentType.put("html", "text/html;charset=UTF-8;"); 114 | contentType.put("json", "application/json; charset=utf-8;"); 115 | contentType.put("xml", "application/xml;charset=UTF-8;"); 116 | contentType.put("zip", "application/x-zip-compressed"); 117 | contentType.put("ico", "image/x-icon"); 118 | String returnType = ""; 119 | if (contentType.containsKey(type)) { 120 | returnType = contentType.get(type); 121 | } else { 122 | returnType = "application/x-zip-compressed"; 123 | } 124 | return returnType; 125 | } 126 | 127 | /** 128 | * 设置返回实体 129 | * 130 | * @param content 131 | */ 132 | public static void setContent(String content) { 133 | Response.Content = content; 134 | } 135 | 136 | /** 137 | * 追加返回实体 138 | * 139 | * @param content 140 | */ 141 | public static void addContent(String content) { 142 | Response.Content = Response.Content + content; 143 | } 144 | 145 | /** 146 | * 添加自定义Header 147 | * 148 | * @param header 149 | * @return 150 | */ 151 | public static boolean header(String header) { 152 | return Response.Header.add(header); 153 | } 154 | 155 | /** 156 | * 获取此次响应的header 157 | * 158 | * @return 159 | */ 160 | public static String getHeader() { 161 | String header; 162 | header = Response.Status + "\r\n"; 163 | //检查cookie 164 | for (int i = 0; i < Response.Cookies.size(); i++) { 165 | header += Response.Cookies.get(i) + "\r\n"; 166 | } 167 | header += "Content-type: " + Response.ContentType + "\r\n"; 168 | header += "Content-ength: " + Response.ContentLength + "\r\n"; 169 | //检查自定义Header 170 | for (int i = 0; i < Response.Header.size(); i++) { 171 | header += Response.Header.get(i) + "\r\n"; 172 | } 173 | 174 | header += "Server: " + Response.Server + "\r\n\r\n"; 175 | 176 | return header; 177 | } 178 | 179 | public static byte[] getContentBytes() throws UnsupportedEncodingException { 180 | 181 | return Response.Content.getBytes("UTF-8"); 182 | } 183 | 184 | /** 185 | * 请求结束,清理信息 186 | */ 187 | public static void finish() { 188 | 189 | Response.Status = "HTTP/1.1 200 OK"; 190 | Response.Content = ""; 191 | Response.Header = new ArrayList(); 192 | Response.Cookies = new ArrayList(); 193 | Response.ContentLength = 0; 194 | Response.ContentType = "text/html;charset=UTF-8;"; 195 | Response.FileBytes = new byte[0]; 196 | //取消是文件标识 197 | Response.IsFile = false; 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /Web/StaticFileServer.java: -------------------------------------------------------------------------------- 1 | package Web; 2 | 3 | import java.nio.channels.SocketChannel; 4 | import java.util.logging.Level; 5 | import java.util.logging.Logger; 6 | import java.io.IOException; 7 | import java.nio.ByteBuffer; 8 | import java.nio.channels.AsynchronousFileChannel; 9 | import java.nio.channels.CompletionHandler; 10 | import java.nio.file.Files; 11 | import java.nio.file.Path; 12 | import java.nio.file.Paths; 13 | import java.nio.file.attribute.BasicFileAttributeView; 14 | import java.nio.file.attribute.BasicFileAttributes; 15 | import java.util.concurrent.TimeUnit; 16 | 17 | /** 18 | * 静态文件服务器 19 | * 20 | * @author Ma 21 | */ 22 | public class StaticFileServer { 23 | 24 | public Request request; 25 | public int size; 26 | public ByteBuffer byteBuffer; 27 | public SocketChannel socketChannel; 28 | public Path filePath; 29 | public String ExName;//扩展名字 30 | 31 | /** 32 | * 初始化一些东西 33 | * 34 | * @param request 35 | */ 36 | public StaticFileServer(Request request) { 37 | this.request = request; 38 | String path = Options.StaticPath + this.request.Path.substring(8); 39 | this.filePath = Paths.get(path); 40 | //设置扩展名 41 | int index = this.request.Path.lastIndexOf("."); 42 | this.ExName = this.request.Path.substring(index + 1); 43 | } 44 | 45 | /** 46 | * 检测文件是否存在 47 | * 48 | * @return 49 | */ 50 | public boolean exists() { 51 | return Files.exists(filePath); 52 | 53 | } 54 | 55 | /** 56 | * 检查文件是否需要更新还是304状态吗 57 | * 58 | * @return 59 | */ 60 | public boolean update() { 61 | try { 62 | int lastTime = (int) Files.getLastModifiedTime(filePath).to(TimeUnit.SECONDS);//获取最后修改的时间戳 63 | Object paramTime = this.request.Header.get("If-Modified-Since"); 64 | 65 | if ((paramTime != null) && (Integer.parseInt((String) paramTime) <= lastTime)) { 66 | //处理304 67 | Response.setStatus(304); 68 | Response.setContentType(Response.findContentType(this.ExName)); 69 | Response.header("Last-Modified: " + lastTime); 70 | Response.header("Cache-Control:public, max-age=2592000"); 71 | byte[] headerBytes = Response.getHeader().getBytes(); 72 | ByteBuffer writerBuffer = ByteBuffer.allocate(headerBytes.length); 73 | writerBuffer.clear(); 74 | writerBuffer.put(headerBytes); 75 | writerBuffer.flip(); 76 | while (writerBuffer.hasRemaining()) { 77 | this.socketChannel.write(writerBuffer); 78 | } 79 | writerBuffer.clear(); 80 | this.socketChannel.close(); 81 | //输出debug信息 82 | if (Options.DEBUG || Options.ParseLine) { 83 | System.out.println(Response.Status + " " + this.request.Header.get("Host") + this.request.Path); 84 | } 85 | Response.finish();//清理信息 86 | return false; 87 | } 88 | } catch (IOException ex) { 89 | Logger.getLogger(StaticFileServer.class.getName()).log(Level.SEVERE, null, ex); 90 | } 91 | return true; 92 | } 93 | 94 | public void read(SocketChannel socketChannel) { 95 | this.socketChannel = socketChannel; 96 | //处理304 97 | if (this.update()) { 98 | //输出debug信息 99 | if (Options.DEBUG || Options.ParseLine) { 100 | System.out.println("Static File" + " " + this.request.Header.get("Host") + this.request.Path); 101 | } 102 | //处理200 103 | BasicFileAttributeView basicView = Files.getFileAttributeView(this.filePath, BasicFileAttributeView.class); 104 | 105 | try { 106 | BasicFileAttributes basicAttrs = basicView.readAttributes(); 107 | long size = basicAttrs.size(); 108 | if (size > 2097152) { 109 | //说明文件大于2M 110 | } 111 | this.size = (int) size; 112 | int lastTime = (int) Files.getLastModifiedTime(filePath).to(TimeUnit.SECONDS);//获取最后修改的时间戳 113 | this.byteBuffer = ByteBuffer.allocate((int) size);//申请缓存空间 114 | //开始获取通道,读取文件 115 | AsynchronousFileChannel afc = AsynchronousFileChannel.open(this.filePath); 116 | afc.read(byteBuffer, 0, lastTime, new CompletionHandlerImpl(afc)); 117 | 118 | } catch (IOException ex) { 119 | //处理500错误 120 | Logger.getLogger(StaticFileServer.class.getName()).log(Level.SEVERE, null, ex); 121 | } 122 | } 123 | } 124 | 125 | /** 126 | * 成员类 处理文件完成后的操作 127 | */ 128 | private class CompletionHandlerImpl implements CompletionHandler { 129 | 130 | AsynchronousFileChannel afc; 131 | 132 | public CompletionHandlerImpl(AsynchronousFileChannel afc) { 133 | this.afc = afc; 134 | } 135 | 136 | /** 137 | * 处理成功的操作 138 | * 139 | * @param result 140 | * @param attachment 141 | */ 142 | @Override 143 | public void completed(Integer result, Object attachment) { 144 | 145 | Integer lastModifyInteger = (Integer) attachment; 146 | int lastModify = lastModifyInteger.intValue(); 147 | //Header不能使用Response 148 | String header = "HTTP/1.1 200 OK\r\n" 149 | + "Content-type: " + Response.findContentType(StaticFileServer.this.ExName) + ";\r\n" 150 | + "Content-ength: " + StaticFileServer.this.size + "\r\n" 151 | + "Last-Modified: " + lastModify + "\r\n" 152 | + "Cache-Control:public, max-age=2592000 \r\n" 153 | + "Server: " + Response.Server + "\r\n\r\n"; 154 | 155 | byte[] headerBytes = header.getBytes(); 156 | byte[] contentBytes = StaticFileServer.this.byteBuffer.array(); 157 | ByteBuffer writerBuffer = ByteBuffer.allocate(headerBytes.length + contentBytes.length); 158 | writerBuffer.clear(); 159 | 160 | writerBuffer.put(headerBytes); 161 | writerBuffer.put(contentBytes); 162 | writerBuffer.flip(); 163 | try { 164 | while (writerBuffer.hasRemaining()) { 165 | StaticFileServer.this.socketChannel.write(writerBuffer); 166 | } 167 | writerBuffer.clear(); 168 | 169 | StaticFileServer.this.socketChannel.close(); 170 | this.afc.close(); 171 | } catch (IOException ex) { 172 | Logger.getLogger(StaticFileServer.class.getName()).log(Level.SEVERE, null, ex); 173 | } 174 | } 175 | 176 | /** 177 | * 处理失败的操作 178 | * 179 | * @param exc 180 | * @param attachment 181 | */ 182 | @Override 183 | public void failed(Throwable exc, Object attachment) { 184 | System.out.println(exc.getCause()); 185 | //@todo 处理500错误 186 | try { 187 | StaticFileServer.this.socketChannel.close(); 188 | this.afc.close(); 189 | } catch (IOException ex) { 190 | Logger.getLogger(StaticFileServer.class.getName()).log(Level.SEVERE, null, ex); 191 | } 192 | } 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /Web/TemplateCompile.java: -------------------------------------------------------------------------------- 1 | package Web; 2 | 3 | import java.io.File; 4 | import java.io.BufferedReader; 5 | import java.io.BufferedWriter; 6 | import java.io.FileNotFoundException; 7 | import java.io.FileReader; 8 | import java.io.FileWriter; 9 | import java.util.regex.Pattern; 10 | import java.io.IOException; 11 | import java.util.ArrayList; 12 | import java.util.logging.Level; 13 | import java.util.logging.Logger; 14 | import java.util.regex.Matcher; 15 | 16 | /** 17 | * 编译模版成Java代码 18 | * 19 | * @author Ma 20 | */ 21 | public class TemplateCompile { 22 | 23 | /** 24 | * 模版目录 25 | */ 26 | String TemplatePath = Options.TemplatePath; 27 | protected ArrayList block; 28 | protected ArrayList blockContent; 29 | protected boolean isBlock = false; 30 | protected boolean isExtends = false;//标记是否是有继承关系 31 | private BufferedWriter writer; 32 | 33 | public TemplateCompile() { 34 | this.blockContent = new ArrayList(); 35 | this.block = new ArrayList(); 36 | this.TemplatePath = Options.TemplatePath; 37 | } 38 | 39 | /** 40 | * public static void main(String[] args) { TemplateCompile self = new 41 | * TemplateCompile(); File tplDir = new File(self.TemplatePath); //判断目录是否存在 42 | * tplDir.isDirectory(); 43 | * 44 | * String[] fileList = tplDir.list(); 45 | * 46 | * for (int i = 0; i < fileList.length; i++) { String string = fileList[i]; 47 | * if (string.matches(".+\\.java")) {//不处理Java文件 continue; } 48 | * self.start(string); System.out.println(string);//@todo 后期处理子目录的问题 } } 49 | * 50 | */ 51 | public int start(String fileName) { 52 | File tplFile = new File(this.TemplatePath + fileName); 53 | if (tplFile.exists()) { 54 | try { 55 | BufferedReader reader = new BufferedReader(new FileReader(tplFile)); 56 | String line = null; 57 | //编译文件Start 58 | 59 | File compilerFile = this.getFile(fileName);//获取Java文件 60 | if (compilerFile.exists()) { 61 | //如果文件存在就比较时间 62 | if (compilerFile.lastModified() > tplFile.lastModified()) { 63 | //如果最后修改的时候小于编译后的Java文件的最后日期 64 | //直接返回 65 | //return 0;注释掉,每次都重新编译 66 | } 67 | } else { 68 | //如果文件不存在就创建 69 | compilerFile.createNewFile(); 70 | } 71 | 72 | this.writer = new BufferedWriter(new FileWriter(compilerFile)); 73 | if (!compilerFile.isFile()) { 74 | ;//说明创建失败 75 | } 76 | //编译文件END 77 | String fatherTpl = "Web.BaseTemplate";//默认继承 78 | line = reader.readLine();//分析第一行是否继承 79 | Pattern pat = Pattern.compile("\\{\\%\\s*extends\\s*\\s(\\w+)\\s*\\%\\}"); 80 | Matcher mat = pat.matcher(line); 81 | if (mat.find()) { 82 | fatherTpl = mat.group(1) + "Template"; 83 | line = line.replace(mat.group(), ""); 84 | this.isExtends = true; 85 | //遇到继承,就去解析父模版 86 | TemplateCompile templateCompile = new TemplateCompile(); 87 | int r = templateCompile.start(mat.group(1) + ".html"); 88 | } 89 | //识别继承标识Start 90 | Pattern blockPat = Pattern.compile("\\{\\%\\s*block\\s*(\\w+)\\s*\\%\\}"); 91 | //识别继承标识END 92 | 93 | 94 | //writer.write("package Web.Template" + this.getPackage(fileName) + ";\npublic class " 95 | writer.write("package Template" + this.getPackage(fileName) + ";\npublic class " 96 | + this.getfileName(fileName) 97 | + "Template extends " + fatherTpl + "{"); 98 | if (!this.isExtends) { 99 | writer.write("\n\tpublic String display(){\n\t\tString str= \n"); 100 | } 101 | while (line != null) { 102 | line = line.trim(); 103 | if (line.length() < 1) { 104 | line = reader.readLine();//读取下一行 105 | continue; 106 | } 107 | //检查是否是block Start 108 | Matcher blockMat = blockPat.matcher(line); 109 | if (blockMat.find()) { 110 | this.block.add(blockMat.group(1)); 111 | this.blockContent.add(""); 112 | this.isBlock = true; 113 | line = line.replace(blockMat.group(), "\"\"+this." + blockMat.group(1) + "()"); 114 | this.writerFile(line, true); 115 | line = reader.readLine();//读取下一行 116 | continue; 117 | //System.out.println(blockMat.group(1)); 118 | } 119 | 120 | //检查是否是block End 121 | if (this.isBlock && line.matches("\\{\\%\\s*end\\s*\\%\\}")) { 122 | this.isBlock = false; 123 | line = reader.readLine();//读取下一行 124 | continue; 125 | 126 | } 127 | 128 | 129 | 130 | //检查if 语句 131 | if (line.matches(".*\\{\\%\\s*if\\s*\\(.+\\)\\s*\\%\\}.*")) { 132 | 133 | line = line.replace("\"", "\\\""); 134 | line = line.replace("{%", "\";"); 135 | line = line.replace("%}", "{str=str"); 136 | line = "\"" + line + "\n"; 137 | 138 | if (this.isBlock) { 139 | this.writerBlock(line, true); 140 | } else { 141 | this.writerFile(line, true); 142 | } 143 | line = reader.readLine();//读取下一行 144 | continue; 145 | } 146 | //检查endif 语句 147 | if (line.matches(".*\\{\\%\\s*endif\\s*\\%\\}.*")) { 148 | line = line.replaceAll("\\{\\%\\s*endif\\s*\\%\\}", "\";}str=str+\""); 149 | line = "\"" + line + "\"\n"; 150 | if (this.isBlock) { 151 | this.writerBlock(line, true); 152 | } else { 153 | this.writerFile(line, true); 154 | } 155 | line = reader.readLine();//读取下一行 156 | continue; 157 | } 158 | //检查elseif 语句 159 | if (line.matches(".*\\{\\%\\s*elseif\\s*\\(.+\\)\\s*\\%\\}.*")) { 160 | line = line.replace("{%", "\";}"); 161 | line = line.replace("%}", "{str=str"); 162 | line = line.replace("elseif", "else if"); 163 | line = "\"" + line + "\n"; 164 | 165 | if (this.isBlock) { 166 | this.writerBlock(line, true); 167 | } else { 168 | this.writerFile(line, true); 169 | } 170 | line = reader.readLine();//读取下一行 171 | continue; 172 | } 173 | //检查else 语句 174 | if (line.matches(".*\\{\\%\\s*else\\s*\\%\\}.*")) { 175 | line = line.replaceAll("\\{\\%\\s*else\\s*\\%\\}", "\";}else{str=str"); 176 | 177 | line = "\"" + line + "\n"; 178 | if (this.isBlock) { 179 | this.writerBlock(line, true); 180 | } else { 181 | this.writerFile(line, true); 182 | } 183 | line = reader.readLine();//读取下一行 184 | continue; 185 | } 186 | //检查for 语句 187 | if (line.matches(".*\\{\\%\\s*for\\s*\\(.+\\)\\s*\\%\\}.*")) { 188 | line = line.replace("{%", "\";"); 189 | line = line.replace("%}", "{str=str"); 190 | line = "\"" + line + "\n"; 191 | if (this.isBlock) { 192 | this.writerBlock(line, true); 193 | } else { 194 | this.writerFile(line, true); 195 | } 196 | line = reader.readLine();//读取下一行 197 | continue; 198 | } 199 | 200 | //检查endfor 语句 201 | if (line.matches(".*\\{\\%\\s*endfor\\s*\\%\\}.*")) { 202 | line = line.replaceAll("\\{\\%\\s*endfor\\s*\\%\\}", "\";}str=str"); 203 | line = "\"" + line + "\n"; 204 | if (this.isBlock) { 205 | this.writerBlock(line, true); 206 | } else { 207 | this.writerFile(line, true); 208 | } 209 | line = reader.readLine();//读取下一行 210 | continue; 211 | } 212 | 213 | 214 | if (this.isBlock) { 215 | this.writerBlock(line); 216 | } else { 217 | this.writerFile(line); 218 | } 219 | 220 | 221 | writer.newLine(); 222 | //writer.newLine(); 223 | line = reader.readLine();//读取下一行 224 | } 225 | 226 | reader.close(); 227 | this.flush(); 228 | this.writer.flush(); 229 | this.writer.close(); 230 | return 0; 231 | 232 | } catch (FileNotFoundException ex) { 233 | Logger.getLogger(TemplateCompile.class.getName()).log(Level.SEVERE, null, ex); 234 | } catch (IOException ex) { 235 | Logger.getLogger(TemplateCompile.class.getName()).log(Level.SEVERE, null, ex); 236 | } 237 | 238 | 239 | } else { 240 | return 1; 241 | } 242 | return 0; 243 | } 244 | 245 | /** 246 | * 创建编译后的文件 247 | * 248 | * @param fileName 249 | * @return 250 | */ 251 | protected File getFile(String fileName) { 252 | fileName = this.getFilePath(fileName) + "/" + this.getfileName(fileName); 253 | String javaTplName = fileName + "Template.java"; 254 | File JavaFile = new File(this.TemplatePath + javaTplName); 255 | 256 | return JavaFile; 257 | } 258 | 259 | /** 260 | * 获取文件名字,不包括扩展名字 261 | * 262 | * @param fileName 263 | * @return 264 | */ 265 | protected String getfileName(String fileName) { 266 | //获取文件名字,不包含扩展名 267 | int index = fileName.lastIndexOf(".html"); 268 | fileName = fileName.substring(0, index); 269 | index = fileName.lastIndexOf("/"); 270 | fileName = fileName.substring(index + 1); 271 | return fileName; 272 | } 273 | 274 | /** 275 | * 获取文件的路径 276 | * 277 | * @param fileName 278 | * @return 279 | */ 280 | protected String getFilePath(String fileName) { 281 | int index = fileName.lastIndexOf(".html"); 282 | fileName = fileName.substring(0, index); 283 | index = fileName.lastIndexOf("/"); 284 | String path = ""; 285 | if (index > 0) { 286 | path = fileName.substring(0, index); 287 | } 288 | return path; 289 | } 290 | 291 | protected String getPackage(String fileName) { 292 | String path = this.getFilePath(fileName); 293 | if (path.equals("")) { 294 | path = ""; 295 | } else { 296 | path = "." + path.replace("/", "."); 297 | } 298 | return path; 299 | } 300 | 301 | /** 302 | * 写入bolck,自动添加引号 303 | * 304 | * @param line 305 | * @return 306 | */ 307 | protected String writerBlock(String line) { 308 | String r = ""; 309 | //首先把所有变量修改{{}} 310 | if (line.matches(".*\\{\\{.+\\}\\}.*")) { 311 | Pattern pattern = Pattern.compile(".*\\{\\{(\\w+):(\\w+):?(\\w+)?\\}\\}.*"); 312 | Matcher matcher = pattern.matcher(line); 313 | if (matcher.find()) { 314 | line = line.replace("\"", "\\\""); 315 | if (matcher.group(3) == null) { 316 | line = line.replaceFirst("\\{\\{(.+):(.+)\\}\\}", "\"+this.getArray(\"" 317 | + matcher.group(1) + "\")[" 318 | + matcher.group(2) + "]+\""); 319 | } else {//说明是引用2维数组 320 | line = line.replaceFirst("\\{\\{(.+):(.+):(.+)\\}\\}", "\"+this.getArray2(\"" 321 | + matcher.group(1) + "\")[" 322 | + matcher.group(2) + "][" + matcher.group(3) + "]+\""); 323 | } 324 | } else { 325 | line = line.replace("{{", "\"+this.get(\""); 326 | line = line.replace("}}", "\")+\""); 327 | line = line.replace("\"", "\\\""); 328 | } 329 | r = this.blockContent.set(this.block.size() - 1, this.blockContent.get(this.block.size() - 1) + "+\n" + "\"" + line + "\""); 330 | } else { 331 | r = this.blockContent.set(this.block.size() - 1, this.blockContent.get(this.block.size() - 1) + "+\n" + "\"" + line.replace("\"", "\\\"") + "\""); 332 | } 333 | return r; 334 | } 335 | 336 | /** 337 | * 写入 bolck,不写入引号 338 | * 339 | * @param line 340 | * @param eval 341 | * @return 342 | */ 343 | protected String writerBlock(String line, boolean eval) { 344 | 345 | //首先把所有变量修改{{}} 346 | Pattern pat = Pattern.compile("\\(.*\\$([_a-zA-Z][_a-zA-Z0-9]*):?(\\w*).*\\)"); 347 | Matcher mat = pat.matcher(line); 348 | 349 | if (mat.find()) { 350 | String param = mat.group(1); 351 | String valueType = ""; 352 | if (mat.group(2).length() > 0) { 353 | valueType = mat.group(2).replaceFirst(mat.group(2).substring(0, 1), mat.group(2).substring(0, 1).toUpperCase()); 354 | } 355 | line = line.replaceAll("\\$([_a-zA-Z][_a-zA-Z0-9]*):?(\\w*)", "this.get" 356 | + valueType 357 | + "(\"" + param + "\")"); 358 | } 359 | String r = this.blockContent.set(this.block.size() - 1, this.blockContent.get(this.block.size() - 1) + "+\n" + line); 360 | return r; 361 | } 362 | 363 | /** 364 | * 写入引号 365 | * 366 | * @param line 367 | */ 368 | protected void writerFile(String line) { 369 | line = line.replace("\"", "\\\""); 370 | //首先把所有变量修改{{}} 371 | if (line.matches(".*\\{\\{.+\\}\\}.*")) { 372 | Pattern pattern = Pattern.compile(".*\\{\\{(\\w+):(\\w+)\\}\\}.*"); 373 | Matcher matcher = pattern.matcher(line); 374 | if (matcher.matches()) { 375 | 376 | line = line.replaceAll("\\{\\{(.+):(.+)\\}\\}", "\"+this.getArray(\"" 377 | + matcher.group(1) + "\")[" 378 | + matcher.group(2) + "]+\""); 379 | } else { 380 | line = line.replace("{{", "\"+this.get(\""); 381 | line = line.replace("}}", "\")+\""); 382 | } 383 | } 384 | try { 385 | writer.write("\"" + line + "\"+"); 386 | 387 | } catch (IOException ex) { 388 | Logger.getLogger(TemplateCompile.class.getName()).log(Level.SEVERE, null, ex); 389 | } 390 | } 391 | 392 | /** 393 | * 不写入引号 394 | * 395 | * @param line 396 | * @param eval 397 | */ 398 | protected void writerFile(String line, boolean eval) { 399 | 400 | //首先把所有变量修改{{}} 401 | Pattern pat = Pattern.compile("\\(.*\\$([_a-zA-Z][_a-zA-Z0-9]*):?(\\w*).*\\)"); 402 | Matcher mat = pat.matcher(line); 403 | 404 | if (mat.find()) { 405 | String param = mat.group(1); 406 | String valueType = ""; 407 | if (mat.group(2).length() > 0) { 408 | valueType = mat.group(2).replaceFirst(mat.group(2).substring(0, 1), mat.group(2).substring(0, 1).toUpperCase()); 409 | } 410 | line = line.replaceAll("\\$([_a-zA-Z][_a-zA-Z0-9]*):?(\\w*)", "this.get" 411 | + valueType 412 | + "(\"" + param + "\")"); 413 | } 414 | try { 415 | if (!this.isExtends) { 416 | writer.write("" + line + "+"); 417 | } 418 | } catch (IOException ex) { 419 | Logger.getLogger(TemplateCompile.class.getName()).log(Level.SEVERE, null, ex); 420 | } 421 | } 422 | 423 | /** 424 | * 处理结尾,把block写在里面 425 | */ 426 | protected void flush() { 427 | try { 428 | if (!this.isExtends) { 429 | this.writer.write("\"\";return str;\n}"); 430 | } 431 | for (int i = 0; i < this.block.size(); i++) { 432 | try { 433 | this.writer.write("public String " + this.block.get(i) + " (){ String str = \"\"" + this.blockContent.get(i) + ";return str;}"); 434 | 435 | } catch (IOException ex) { 436 | Logger.getLogger(TemplateCompile.class.getName()).log(Level.SEVERE, null, ex); 437 | } 438 | 439 | } 440 | this.writer.write("\n}"); 441 | } catch (IOException ex) { 442 | Logger.getLogger(TemplateCompile.class.getName()).log(Level.SEVERE, null, ex); 443 | } 444 | } 445 | } 446 | -------------------------------------------------------------------------------- /Web/Tools.java: -------------------------------------------------------------------------------- 1 | package Web; 2 | 3 | /** 4 | * 常用工具类 5 | * 6 | * @author Ma 7 | */ 8 | public class Tools { 9 | 10 | /** 11 | * 获取完整静态文件路径 12 | * 13 | * @param path 文件路径 14 | * @return 完整文件路径 15 | */ 16 | public static String staticFile(String path) { 17 | return ""; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /Web/TplCompile.java: -------------------------------------------------------------------------------- 1 | package Web; 2 | 3 | import java.util.logging.Level; 4 | import java.util.logging.Logger; 5 | import javax.tools.JavaCompiler; 6 | import javax.tools.ToolProvider; 7 | 8 | /** 9 | * 动态编译Java文件 10 | * 11 | * @author Ma 12 | */ 13 | public class TplCompile { 14 | 15 | public String TemplatePath = Options.TemplatePath; 16 | 17 | /* 18 | public static void main(String[] args) { 19 | TplCompile Compiler = new TplCompile(); 20 | Compiler.setTemplatePath(); 21 | Compiler.run("dd/test.html"); 22 | }*/ 23 | public void setTemplatePath() { 24 | this.TemplatePath = Options.TemplatePath; 25 | } 26 | 27 | /** 28 | * 开始编译 29 | */ 30 | public Object run(String fileName) { 31 | this.setTemplatePath();//先配置路径 32 | TemplateCompile templateCompile = new TemplateCompile(); 33 | int r = templateCompile.start(fileName); 34 | if (r > 0 && r == 1) { 35 | //1表示说明文件不存在 36 | //0表示解析正常 37 | return null; 38 | } 39 | String javaFile = this.TemplatePath + templateCompile.getFilePath(fileName) + "/" + templateCompile.getfileName(fileName) + "Template.java"; 40 | String classPath = this.getClass().getResource("/").getPath(); 41 | //动态编译 42 | JavaCompiler javac = ToolProvider.getSystemJavaCompiler(); 43 | int status = javac.run(null, null, null, "-d", classPath, javaFile); 44 | if (status != 0) { 45 | System.out.println("没有编译成功!"); 46 | } 47 | 48 | //动态执行 49 | try { 50 | //返回与带有给定字符串名的类 或接口相关联的 Class 对象。 51 | 52 | Class cls = Class.forName("Template." + templateCompile.getFilePath(fileName).replace("/", ".") + templateCompile.getfileName(fileName) + "Template"); 53 | BaseTemplate object = (BaseTemplate) cls.newInstance(); 54 | return object; 55 | } catch (ClassNotFoundException ex) { 56 | Logger.getLogger(TplCompile.class.getName()).log(Level.SEVERE, null, ex); 57 | } catch (InstantiationException ex) { 58 | Logger.getLogger(TplCompile.class.getName()).log(Level.SEVERE, null, ex); 59 | } catch (IllegalAccessException ex) { 60 | Logger.getLogger(TplCompile.class.getName()).log(Level.SEVERE, null, ex); 61 | } 62 | return null; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /demo/Handler/AdminHandler.java: -------------------------------------------------------------------------------- 1 | package Handler; 2 | 3 | import Web.*; 4 | 5 | /** 6 | * 博客管理模块,做一些基础过滤等 7 | * 8 | * @author Ma 9 | */ 10 | public class AdminHandler extends Handler { 11 | 12 | 13 | /** 14 | * 获取用户的ID 15 | * 16 | * @return 返回用户当前ID 17 | */ 18 | public int getUserID() { 19 | String userID = Cookie.getCookie("id"); 20 | if (userID == null) { 21 | return 0; 22 | } 23 | System.out.println(Integer.parseInt(userID)); 24 | return Integer.parseInt(userID); 25 | } 26 | 27 | 28 | } 29 | -------------------------------------------------------------------------------- /demo/Handler/ArticleHandler.java: -------------------------------------------------------------------------------- 1 | package Handler; 2 | 3 | import Web.*; 4 | import java.sql.Timestamp; 5 | import java.text.SimpleDateFormat; 6 | 7 | /** 8 | * 9 | * @author Ma 10 | */ 11 | public class ArticleHandler extends Handler { 12 | 13 | public void get(String id) { 14 | BaseTemplate index = this.render("article"); 15 | Object[] r = DB.find("select * from article where id=?", id); 16 | if (r.length < 1) { 17 | NotFound404.set404("文章不存在"); 18 | return; 19 | } 20 | long time = Integer.parseInt((String) r[3]); 21 | SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 22 | Timestamp now = new Timestamp(time * 1000); 23 | r[3] = df.format(now); 24 | index.assign("article", r); 25 | index.assign("title", r[1].toString()); 26 | this.writer(index.display()); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /demo/Handler/CreateHandler.java: -------------------------------------------------------------------------------- 1 | package Handler; 2 | 3 | import Web.BaseTemplate; 4 | import Web.DB; 5 | 6 | /** 7 | * 添加文章 8 | * 9 | * @author Ma 10 | */ 11 | public class CreateHandler extends AdminHandler { 12 | 13 | /** 14 | * 添加文章 15 | */ 16 | public void get() { 17 | 18 | if (this.getUserID() < 1) { 19 | this.error("请登录!", "/Login", 5); 20 | return; 21 | } 22 | BaseTemplate create = this.render("create"); 23 | create.assign("title", "Create"); 24 | this.writer(create.display()); 25 | } 26 | 27 | /** 28 | * 添加文章 29 | */ 30 | public void post() { 31 | if (this.getUserID() < 1) { 32 | this.error("请登录!", "/Login", 5); 33 | return; 34 | } 35 | String title = (String) this.getArgument("title"); 36 | String content = (String) this.getArgument("content"); 37 | int date = (int) (System.currentTimeMillis() / 1000); 38 | String dateString = date + ""; 39 | int r = DB.insert("INSERT INTO article (title,content,creat_date,user_id) VALUE (?,?,?,?)", title.trim(), content.trim(), dateString, this.getUserID() + ""); 40 | if (r < 1) { 41 | this.success("失败"); 42 | } else { 43 | this.success("成功", "/"); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /demo/Handler/IndexHandler.java: -------------------------------------------------------------------------------- 1 | package Handler; 2 | 3 | import Web.*; 4 | 5 | /** 6 | * 博客首页 7 | * @author Ma 8 | */ 9 | public class IndexHandler extends Handler { 10 | 11 | /** 12 | * 博客首页 13 | */ 14 | public void get() { 15 | 16 | BaseTemplate index = this.render("index"); 17 | Object[][] r = DB.get("select id,title,creat_date from article"); 18 | index.assign("articles", r); 19 | index.assign("title", "HM Blog"); 20 | this.writer(index.display()); 21 | 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /demo/Handler/LoginHandler.java: -------------------------------------------------------------------------------- 1 | package Handler; 2 | 3 | import Web.*; 4 | 5 | /** 6 | * 登陆 7 | * 8 | * @author Ma 9 | */ 10 | public class LoginHandler extends Handler { 11 | 12 | /** 13 | * 获取登录页面 14 | */ 15 | public void get() { 16 | BaseTemplate login = this.render("login"); 17 | login.assign("title", "Login"); 18 | this.writer(login.display()); 19 | } 20 | 21 | /** 22 | * 登录操作 23 | */ 24 | public void post() { 25 | String name = (String) this.getArgument("name"); 26 | String password = (String) this.getArgument("password"); 27 | Object id = DB.getField("SELECT id FROM user WHERE `name`=? AND password=?", name, password); 28 | if (id == null) { 29 | this.success("失败"); 30 | } else { 31 | Cookie.setCookie("id", (String) id); 32 | this.success("成功", "/"); 33 | } 34 | 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /demo/Main.java: -------------------------------------------------------------------------------- 1 | import Handler.*; 2 | import Web.*; 3 | 4 | /** 5 | * @author Ma 6 | */ 7 | public class Main { 8 | 9 | /** 10 | * @param args Main 方法 11 | */ 12 | public static void main(String[] args) { 13 | 14 | Options.DBURL = "jdbc:mysql://localhost:3306/blog"; 15 | Options.DBDriver = "com.mysql.jdbc.Driver"; // 驱动程序名 16 | Options.DBUser = "root"; 17 | Options.DBPassword = "123456"; 18 | 19 | //关于路径说明:在IDE环境下user.dir和jar包中的user.dir不一样,这里手动指定 20 | Options.StaticPath = System.getProperty("user.dir") + "/src/Static/";//静态文件目录 21 | Options.TemplatePath = System.getProperty("user.dir") + "/src/Template/";//模版文件目录 22 | 23 | Options.DEBUG = true; // 开启调试模式 24 | // 注册控制器。 25 | HttpServer.setPATH("/", new IndexHandler()); 26 | HttpServer.setPATH("\\/Article\\/(\\d+)", new ArticleHandler()); 27 | HttpServer.setPATH("\\/Admin", new AdminHandler()); 28 | HttpServer.setPATH("\\/Login", new LoginHandler()); 29 | HttpServer.setPATH("\\/Create", new CreateHandler()); 30 | System.out.println("Welcome BLOG Listen port 8080"); 31 | HttpServer.init(8080); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /demo/Static/base.css: -------------------------------------------------------------------------------- 1 | table{ 2 | } -------------------------------------------------------------------------------- /demo/Static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/laomafeima/WebJava/bc0e4e476f8a913bee22a33a5b549264ea2d4fa3/demo/Static/favicon.ico -------------------------------------------------------------------------------- /demo/Template/article.html: -------------------------------------------------------------------------------- 1 | {% extends base%} 2 | 3 | {% block body%} 4 |
5 |

{{article:1}}

6 |

发表时间:{{article:3}}

7 |
{{article:2}}
8 | 9 |
10 | 11 | {%end%} -------------------------------------------------------------------------------- /demo/Template/articleTemplate.java: -------------------------------------------------------------------------------- 1 | package Template; 2 | public class articleTemplate extends baseTemplate{ 3 | 4 | 5 | 6 | 7 | public String body (){ String str = ""+ 8 | "
"+ 9 | "

"+this.getArray("article")[1]+"

"+ 10 | "

发表时间:"+this.getArray("article")[3]+"

"+ 11 | "
"+this.getArray("article")[2]+"
"+ 12 | "
";return str;} 13 | } -------------------------------------------------------------------------------- /demo/Template/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{title}} 5 | 6 | 7 | {% block head %} 8 | {% end %} 9 | 10 | 11 | 添加文章 12 | {% block body %} 13 | 欢迎归来 14 | {% end %} 15 | 16 | 17 | -------------------------------------------------------------------------------- /demo/Template/baseTemplate.java: -------------------------------------------------------------------------------- 1 | package Template; 2 | public class baseTemplate extends Web.BaseTemplate{ 3 | public String display(){ 4 | String str= 5 | ""+ 6 | ""+ 7 | ""+ 8 | ""+this.get("title")+""+ 9 | ""+ 10 | ""+ 11 | ""+this.head()+""+ 12 | ""+ 13 | "添加文章"+ 14 | ""+this.body()+ 15 | ""+ 16 | ""+ 17 | "";return str; 18 | }public String head (){ String str = "";return str;}public String body (){ String str = ""+ 19 | "欢迎归来";return str;} 20 | } -------------------------------------------------------------------------------- /demo/Template/create.html: -------------------------------------------------------------------------------- 1 | {% extends base%} 2 | 3 | {% block body%} 4 |
5 |
6 |
7 | 8 |
9 |
10 | 11 |
12 | 13 | 14 |
15 |
16 | 17 | {%end%} -------------------------------------------------------------------------------- /demo/Template/createTemplate.java: -------------------------------------------------------------------------------- 1 | package Template; 2 | public class createTemplate extends baseTemplate{ 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | public String body (){ String str = ""+ 14 | "
"+ 15 | "
"+ 16 | "
"+ 17 | ""+ 18 | "
"+ 19 | "
"+ 20 | ""+ 21 | "
"+ 22 | ""+ 23 | "
"+ 24 | "
";return str;} 25 | } -------------------------------------------------------------------------------- /demo/Template/index.html: -------------------------------------------------------------------------------- 1 | {% extends base%} 2 | 3 | {% block body%} 4 |
5 | 6 | 7 | 8 | 9 | 10 | {%for(int i = 0; i < $articles:array2.length; i++)%} 11 | 12 | 15 | 16 | 17 | {%endfor%} 18 |
标题发表时间
13 | {{articles:i:1}} 14 | {{articles:i:2}}
19 |
20 | 21 | {%end%} -------------------------------------------------------------------------------- /demo/Template/indexTemplate.java: -------------------------------------------------------------------------------- 1 | package Template; 2 | public class indexTemplate extends baseTemplate{ 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | public String body (){ String str = ""+ 17 | "
"+ 18 | ""+ 19 | ""+ 20 | ""+ 21 | ""+ 22 | ""+ 23 | "";for(int i = 0; i < this.getArray2("articles").length; i++){str=str 24 | + 25 | ""+ 26 | ""+ 29 | ""+ 30 | ""+ 31 | "";}str=str 32 | + 33 | "
标题发表时间
"+ 27 | ""+this.getArray2("articles")[i][1]+""+ 28 | ""+this.getArray2("articles")[i][2]+"
"+ 34 | "
";return str;} 35 | } -------------------------------------------------------------------------------- /demo/Template/jump.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 跳转提示 6 | 50 | 51 | 52 |
53 | {%if($status:boolean)%} 54 |

^_^

55 | {%else%} 56 |

-_-!

57 | {%endif%} 58 |

{{message}}

59 |

60 | 页面自动 跳转 等待时间: 67 | {{wait}} 68 |

69 |
70 | 83 | 84 | -------------------------------------------------------------------------------- /demo/Template/jumpTemplate.java: -------------------------------------------------------------------------------- 1 | package Template; 2 | public class jumpTemplate extends Web.BaseTemplate{ 3 | public String display(){ 4 | String str= 5 | ""+ 6 | ""+ 7 | ""+ 8 | ""+ 9 | "跳转提示"+ 10 | ""+ 47 | ""+ 48 | ""+ 49 | "
"+ 50 | "";if(this.getBoolean("status")){str=str 51 | +"

^_^

"+ 52 | "";}else{str=str 53 | +"

-_-!

"+ 54 | "";}str=str+"" 55 | +"

"+this.get("message")+"

"+ 56 | "

"+ 57 | "页面自动 跳转 等待时间:"+ 64 | ""+this.get("wait")+""+ 65 | "

"+ 66 | "
"+ 67 | ""+ 80 | ""+ 81 | ""+ 82 | "";return str; 83 | } 84 | } -------------------------------------------------------------------------------- /demo/Template/login.html: -------------------------------------------------------------------------------- 1 | {% extends base%} 2 | 3 | {% block body%} 4 |
5 |
6 | 7 | 8 | 9 | 10 |
11 |
12 | 13 | {%end%} -------------------------------------------------------------------------------- /demo/Template/loginTemplate.java: -------------------------------------------------------------------------------- 1 | package Template; 2 | public class loginTemplate extends baseTemplate{ 3 | 4 | 5 | 6 | 7 | 8 | 9 | public String body (){ String str = ""+ 10 | "
"+ 11 | "
"+ 12 | ""+ 13 | ""+ 14 | ""+ 15 | "
"+ 16 | "
";return str;} 17 | } -------------------------------------------------------------------------------- /demo/Template/test.html: -------------------------------------------------------------------------------- 1 | 2 | 模版说明 3 | 使用继承 4 | 顶顶顶顶顶 5 | {% block body %} 6 | XXXX 7 | hkud 8 | {% end %} 9 | 开始和end标记之间是默认内容,如果没有被继承就显示默认内容否则显示 10 | 11 | 文件的开始处生命继承的模版只允许单一继承(一层继承关系 待定) 12 | 13 | 一个文件可以包含多个文本块。在继承的文件只实现多个 14 | 15 | {%block de%} 16 | 得到 17 | 18 | dddd{%if(true)%} 19 |
dsssssssssssssssss
20 | {%endif%}sss 21 | {% end %} 22 | 语法 23 | 测试语法开始 24 |
25 |
26 | 测试For 27 | {%for(int i = 0; i < $for:array.length; i++)%} 28 | 城市是:{{for:i}} 29 | {%endfor%} 30 |
31 |
32 | {{frist}} 33 | dddd{%if(true)%} 34 |
dddddddddddddddddddddd
35 | {%elseif($name:boolean&&true)%} 36 |
fsssssssssssssssfffff
37 | {%else%} 38 |
fffffffffffff
39 | {%endif%}sss 40 | 41 | {{name}} 42 | 43 | {%for(int i=0;i<5;i++)%} 44 | for循环的测试点点滴滴点点滴滴的的的的的的 45 | {%endfor%} 46 | 47 | {#de = de+"fr"#} 48 | 测试执行任意Java语句 49 | 50 | {{}} 表示 输出变量 51 | {%%}if for 语句 52 | {##}执行的语句 53 | 54 | ###### 55 | 以上部分是测试文档 56 | 下面是文档说明 57 | 这个是一个 58 | -------------------------------------------------------------------------------- /demo/Template/testTemplate.java: -------------------------------------------------------------------------------- 1 | package Template; 2 | public class testTemplate extends Web.BaseTemplate{ 3 | public String display(){ 4 | String str= 5 | "模版说明"+ 6 | "使用继承"+ 7 | "顶顶顶顶顶"+ 8 | ""+this.body()+ 9 | 10 | "开始和end标记之间是默认内容,如果没有被继承就显示默认内容否则显示"+ 11 | "文件的开始处生命继承的模版只允许单一继承(一层继承关系 待定)"+ 12 | "一个文件可以包含多个文本块。在继承的文件只实现多个"+ 13 | ""+this.de()+ 14 | 15 | "语法"+ 16 | "测试语法开始"+ 17 | "
"+ 18 | "
"+ 19 | "测试For"+ 20 | "";for(int i = 0; i < this.getArray("for").length; i++){str=str 21 | +"城市是:"+this.getArray("for")[i]+""+ 22 | "";}str=str 23 | +"
"+ 24 | "
"+ 25 | ""+this.get("frist")+""+ 26 | "dddd";if(true){str=str 27 | +"
dddddddddddddddddddddd
"+ 28 | "";}else if(this.getBoolean("name")&&true){str=str 29 | +"
fsssssssssssssssfffff
"+ 30 | "";}else{str=str 31 | +"
fffffffffffff
"+ 32 | "";}str=str+"sss" 33 | +""+this.get("name")+""+ 34 | "";for(int i=0;i<5;i++){str=str 35 | +"for循环的测试点点滴滴点点滴滴的的的的的的"+ 36 | "";}str=str 37 | +"{#de = de+\"fr\"#}"+ 38 | "测试执行任意Java语句"+ 39 | "{{}} 表示 输出变量"+ 40 | "{%%}if for 语句"+ 41 | "{##}执行的语句"+ 42 | "######"+ 43 | "以上部分是测试文档"+ 44 | "下面是文档说明"+ 45 | "这个是一个"+ 46 | "";return str; 47 | }public String body (){ String str = ""+ 48 | "XXXX"+ 49 | "hkud";return str;}public String de (){ String str = ""+ 50 | "得到"+ 51 | "dddd";if(true){str=str 52 | + 53 | "
dsssssssssssssssss
"+ 54 | "";}str=str+"sss" 55 | ;return str;} 56 | } -------------------------------------------------------------------------------- /demo/Web/Allocation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * To change this template, choose Tools | Templates 3 | * and open the template in the editor. 4 | */ 5 | package Web; 6 | 7 | import java.lang.reflect.InvocationTargetException; 8 | import java.lang.reflect.Method; 9 | import java.util.Arrays; 10 | import java.util.HashMap; 11 | import java.util.logging.Level; 12 | import java.util.logging.Logger; 13 | import java.util.regex.Matcher; 14 | import java.util.regex.Pattern; 15 | 16 | /** 17 | * 检查path,分配调用的handler 18 | * 19 | * @author Ma 20 | */ 21 | public class Allocation { 22 | 23 | /** 24 | * 路径配置 25 | */ 26 | public static HashMap PATH = new HashMap(); 27 | 28 | /** 29 | * 初始化,分配器 30 | * 31 | * @param request 请求header 32 | */ 33 | public static void init(Request request) { 34 | 35 | 36 | //说明访问的非静态文件 37 | String[] pathArray = HttpServer.getAllPath(); 38 | for (int i = 0; i < pathArray.length; i++) { 39 | Pattern pattern = Pattern.compile(pathArray[i]); 40 | 41 | Matcher matcher = pattern.matcher(request.Path); 42 | 43 | if (matcher.matches()) { 44 | try { 45 | Class handler = Allocation.PATH.get(pathArray[i]).getClass(); 46 | //处理参数 47 | Class[] paramType = new Class[matcher.groupCount()]; 48 | Arrays.fill(paramType, String.class); 49 | Method method = handler.getMethod(request.Method.toLowerCase(), paramType); 50 | //把request赋值过去 使用 51 | handler.getMethod("init", new Class[]{Request.class}).invoke(Allocation.PATH.get(pathArray[i]), request); 52 | //调用类似构造方法; 53 | handler.getMethod("construct").invoke(Allocation.PATH.get(pathArray[i])); 54 | String[] param = new String[matcher.groupCount()]; 55 | for (int j = 0; j < param.length; j++) { 56 | param[j] = matcher.group(j + 1); 57 | 58 | } 59 | method.invoke(Allocation.PATH.get(pathArray[i]), param); 60 | 61 | } catch (NoSuchMethodException ex) { 62 | //Handler中方法不存在 63 | ExceptionalHandling.set404(ex); 64 | Logger.getLogger(Allocation.class.getName()).log(Level.SEVERE, null, ex); 65 | } catch (SecurityException ex) { 66 | //安全异常。由安全管理器抛出,用于指示违反安全情况的异常。 67 | Logger.getLogger(Allocation.class.getName()).log(Level.SEVERE, null, ex); 68 | } catch (IllegalAccessException ex) { 69 | //设置成了私有方法,应该为public 70 | InternalServerError500.set500(ex); 71 | Logger.getLogger(Allocation.class.getName()).log(Level.SEVERE, null, ex); 72 | } catch (IllegalArgumentException ex) { 73 | //调用方法的时候传递的参数不正确 74 | InternalServerError500.set500(ex); 75 | Logger.getLogger(Allocation.class.getName()).log(Level.SEVERE, null, ex); 76 | } catch (InvocationTargetException ex) { 77 | //ex.getCause() 才能获取真实的异常 78 | //一般是构造方法的错误。所以Handler中的构造方法不能有参数 79 | Logger.getLogger(Allocation.class.getName()).log(Level.SEVERE, null, ex.getCause()); 80 | } catch (Exception ex) { 81 | //这里处理其他异常,因为是用反射运行的这里要处理异常 82 | Logger.getLogger(Allocation.class.getName()).log(Level.SEVERE, null, ex); 83 | } 84 | //如果有就直接Return,终止往下执行,下面处理没找到。 85 | return; 86 | } else { 87 | 88 | continue; 89 | } 90 | } 91 | 92 | //执行到这里,说明没有找到匹配的URL发送404错误 93 | 94 | NotFound404.set404("未设置对应URL:" + request.Path); 95 | 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /demo/Web/BaseTemplate.java: -------------------------------------------------------------------------------- 1 | /* 2 | * To change this template, choose Tools | Templates 3 | * and open the template in the editor. 4 | */ 5 | package Web; 6 | 7 | import java.util.HashMap; 8 | 9 | /** 10 | * @author Ma 11 | */ 12 | public class BaseTemplate { 13 | 14 | public HashMap param; 15 | 16 | public BaseTemplate() { 17 | this.param = new HashMap(); 18 | } 19 | 20 | public String display() { 21 | return null; 22 | } 23 | 24 | public String get(String s) { 25 | if (this.param.containsKey(s)) { 26 | return this.param.get(s).toString(); 27 | } else { 28 | return null; 29 | } 30 | 31 | } 32 | 33 | /** 34 | * 获取boolean值 35 | * 36 | * @param s 37 | * @return 38 | */ 39 | public boolean getBoolean(String s) { 40 | Boolean bool = (Boolean) this.param.get(s); 41 | return bool.booleanValue(); 42 | } 43 | 44 | /** 45 | * 获取int值 46 | * 47 | * @param s 48 | * @return 49 | */ 50 | public int getInt(String s) { 51 | Integer num = (Integer) this.param.get(s); 52 | return num.intValue(); 53 | } 54 | 55 | /** 56 | * 获取一维数组 57 | * 58 | * @param s 59 | * @return 60 | */ 61 | public Object[] getArray(String s) { 62 | return (Object[]) this.param.get(s); 63 | } 64 | 65 | /** 66 | * 获取二维数组 67 | * 68 | * @param s 69 | * @return 70 | */ 71 | public Object[][] getArray2(String s) { 72 | return (Object[][]) this.param.get(s); 73 | } 74 | 75 | /** 76 | * 赋值操作 77 | */ 78 | public void assign(String key, String value) { 79 | this.param.put(key, value); 80 | } 81 | 82 | /** 83 | * 赋值操作 84 | */ 85 | public void assign(String key, int value) { 86 | this.param.put(key, value); 87 | } 88 | 89 | /** 90 | * 赋值操作 91 | */ 92 | public void assign(String key, boolean value) { 93 | this.param.put(key, value); 94 | } 95 | 96 | /** 97 | * 赋值操作 98 | */ 99 | public void assign(String key, Object[] value) { 100 | this.param.put(key, value); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /demo/Web/Cookie.java: -------------------------------------------------------------------------------- 1 | /* 2 | * To change this template, choose Cookie | Templates 3 | * and open the template in the editor. 4 | */ 5 | package Web; 6 | 7 | import java.io.UnsupportedEncodingException; 8 | import java.util.HashMap; 9 | import java.util.logging.Level; 10 | import java.util.logging.Logger; 11 | 12 | /** 13 | * Cookie操作类 maxAge 说明 0表示立即删除,负数表示关闭页面删除,正数表示生存时间 14 | * 15 | * @author Ma 16 | */ 17 | public class Cookie { 18 | 19 | public static HashMap RequestCookie; 20 | 21 | public static void analysis(String request) { 22 | String[] temp = request.split(";"); 23 | Cookie.RequestCookie = new HashMap(); 24 | for (int i = 0; i < temp.length; i++) { 25 | String[] item = temp[i].trim().split("\\="); 26 | Cookie.RequestCookie.put(item[0].trim(), item[1].trim()); 27 | } 28 | 29 | } 30 | 31 | /** 32 | * 设置cookie 33 | */ 34 | public static void setCookie(String name, String value, int maxAge, String path, String domain) { 35 | String cookieString = "Set-Cookie: " + name + "=" + Cookie.encode(value) + "; Max-Age=" + maxAge + ";path=" + path + ";domian=" + domain + ";"; 36 | Response.Cookies.add(cookieString); 37 | 38 | } 39 | 40 | /** 41 | * 设置cookie 42 | */ 43 | public static void setCookie(String name, String value, int maxAge, String path) { 44 | String cookieString = "Set-Cookie: " + name + "=" + Cookie.encode(value) + "; Max-Age=" + maxAge + ";path=" + path + ";"; 45 | Response.Cookies.add(cookieString); 46 | 47 | } 48 | 49 | /** 50 | * 设置cookie 51 | */ 52 | public static void setCookie(String name, String value, int maxAge) { 53 | String cookieString = "Set-Cookie: " + name + "=" + Cookie.encode(value) + "; Max-Age=" + maxAge + ";"; 54 | Response.Cookies.add(cookieString); 55 | 56 | } 57 | 58 | /** 59 | * 设置cookie 60 | */ 61 | public static void setCookie(String name, String value) { 62 | 63 | String cookieString = "Set-Cookie: " + name + "=" + Cookie.encode(value) + ";"; 64 | Response.Cookies.add(cookieString); 65 | } 66 | 67 | /** 68 | * 获取Cookie值 69 | * 70 | * @param name 71 | * @return 72 | */ 73 | public static String getCookie(String name) { 74 | if (Cookie.RequestCookie !=null && Cookie.RequestCookie.containsKey(name)) { 75 | String value = (String) Cookie.RequestCookie.get(name); 76 | return Cookie.decode(value); 77 | }else{ 78 | return null; 79 | } 80 | } 81 | 82 | /** 83 | * 编码字符串 84 | * 85 | * @param encode 86 | * @return 87 | */ 88 | private static String encode(String encode) { 89 | try { 90 | encode = java.net.URLEncoder.encode(encode, "UTF-8"); 91 | return encode; 92 | } catch (UnsupportedEncodingException ex) { 93 | Logger.getLogger(Cookie.class.getName()).log(Level.SEVERE, null, ex); 94 | } 95 | return null; 96 | } 97 | 98 | /** 99 | * 解码字符串 100 | * 101 | * @param decode 102 | * @return 103 | */ 104 | private static String decode(String decode) { 105 | 106 | try { 107 | decode = java.net.URLDecoder.decode(decode, "UTF-8"); 108 | return decode; 109 | } catch (UnsupportedEncodingException ex) { 110 | Logger.getLogger(Cookie.class.getName()).log(Level.SEVERE, null, ex); 111 | } 112 | return null; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /demo/Web/DB.java: -------------------------------------------------------------------------------- 1 | package Web; 2 | 3 | /** 4 | * 数据库操作 5 | * @author Ma 6 | */ 7 | 8 | import com.sun.org.apache.regexp.internal.REUtil; 9 | 10 | import java.sql.Connection; 11 | import java.sql.DriverManager; 12 | import java.sql.PreparedStatement; 13 | import java.sql.ResultSet; 14 | import java.sql.ResultSetMetaData; 15 | import java.sql.SQLException; 16 | import java.sql.Types; 17 | import java.util.logging.Level; 18 | import java.util.logging.Logger; 19 | 20 | public class DB { 21 | 22 | public static Connection Connection; 23 | public static int lastUserTime; 24 | 25 | public static void connection() { 26 | 27 | if ((Options.DBDriver != null) && (Options.DBURL != null) && (Options.DBUser != null) && (Options.DBPassword != null)) { 28 | String driver = Options.DBDriver; // 驱动程序名 29 | String url = Options.DBURL; // URL指向要访问的数据库名 30 | try { 31 | Class.forName(driver); // 加载驱动程序 32 | Connection conn = DriverManager.getConnection(url, Options.DBUser, Options.DBPassword); // 连续数据库 33 | //验证是否连接成功 34 | if (!conn.isClosed()) { 35 | DB.Connection = conn; 36 | DB.lastUserTime = (int) (System.currentTimeMillis() / 1000); 37 | } else { 38 | DB.Connection = null; 39 | } 40 | 41 | //DB.Connection.close();如果会自动处理就不用手动释放资源了 42 | } catch (ClassNotFoundException ex) { 43 | Logger.getLogger(Allocation.class.getName()).log(Level.SEVERE, null, ex); 44 | System.exit(-1); 45 | } catch (SQLException ex) { 46 | Logger.getLogger(Allocation.class.getName()).log(Level.SEVERE, null, ex); 47 | System.exit(-1); 48 | } catch (Exception ex) { 49 | Logger.getLogger(Allocation.class.getName()).log(Level.SEVERE, null, ex); 50 | } 51 | } 52 | } 53 | 54 | /** 55 | * 用原生态的executeQuery 返回ResultSet 56 | * 57 | * @param sql 58 | * @param params 59 | * @return ResultSet 60 | */ 61 | public static ResultSet executeQuery(String sql, String... params) { 62 | DB.cursor(); 63 | PreparedStatement statement; 64 | try { 65 | statement = DB.Connection.prepareStatement(sql); 66 | for (int i = 0; i < params.length; i++) { 67 | statement.setString((i + 1), params[i]); 68 | } 69 | ResultSet r = statement.executeQuery(); 70 | return r; 71 | } catch (SQLException ex) { 72 | Logger.getLogger(DB.class.getName()).log(Level.SEVERE, null, ex); 73 | } 74 | 75 | return null; 76 | } 77 | 78 | /** 79 | * 用原生态的executeUpdate 80 | * 81 | * @param sql 82 | * @param params 83 | * @return 84 | */ 85 | public static int executeUpdate(String sql, String... params) { 86 | DB.cursor(); 87 | try { 88 | PreparedStatement statement = DB.Connection.prepareStatement(sql); 89 | for (int i = 0; i < params.length; i++) { 90 | statement.setString((i + 1), params[i]); 91 | } 92 | int r = statement.executeUpdate(); 93 | statement.close(); 94 | return r; 95 | } catch (SQLException ex) { 96 | Logger.getLogger(DB.class.getName()).log(Level.SEVERE, null, ex); 97 | } 98 | return 0; 99 | 100 | } 101 | 102 | /** 103 | * 获取多个结果集 104 | * 105 | * @param sql 106 | * @param params 107 | */ 108 | public static Object[][] get(String sql, String... params) { 109 | DB.cursor(); 110 | Object[][] data = null; 111 | try { 112 | PreparedStatement statement = DB.Connection.prepareStatement(sql); 113 | for (int i = 0; i < params.length; i++) { 114 | statement.setString((i + 1), params[i]); 115 | } 116 | 117 | ResultSet r = statement.executeQuery(); 118 | //获取字段信息getMetaData 119 | ResultSetMetaData columns = r.getMetaData(); 120 | 121 | int columnCount = columns.getColumnCount(); 122 | String[] columnName = new String[columnCount]; 123 | int[] columnTypeName = new int[columnCount]; 124 | for (int i = 1; i <= columnCount; i++) { 125 | columnName[i - 1] = columns.getColumnName(i); 126 | columnTypeName[i - 1] = DB.getTypeName(columns.getColumnType(i)); 127 | } 128 | 129 | r.last(); 130 | 131 | int rowCount = r.getRow(); 132 | if (rowCount < 1) { 133 | return new Object[rowCount][columnCount]; 134 | } 135 | r.first(); 136 | data = new Object[rowCount][columnCount]; 137 | int i = 0; 138 | 139 | do { 140 | Object[] temp = new Object[columnCount]; 141 | for (int j = 0; j < columnName.length; j++) { 142 | switch (columnTypeName[j]) { 143 | case 0: 144 | temp[j] = r.getBoolean(j + 1); 145 | break; 146 | case 1: 147 | temp[j] = r.getInt(j + 1); 148 | break; 149 | default: 150 | temp[j] = r.getString(j + 1); 151 | break; 152 | 153 | } 154 | } 155 | 156 | data[i] = temp; 157 | i++; 158 | } while (r.next()); 159 | //随手关闭 160 | r.close(); 161 | 162 | statement.close(); 163 | return data; 164 | 165 | 166 | } catch (SQLException ex) { 167 | Logger.getLogger(Handler.class.getName()).log(Level.SEVERE, null, ex); 168 | } 169 | return data; 170 | } 171 | 172 | /** 173 | * 获取一行 174 | * 175 | * @param sql 176 | * @param params 177 | * @return 178 | */ 179 | public static Object[] find(String sql, String... params) { 180 | Object[][] r = DB.get(sql, params); 181 | if (r.length < 1) { 182 | return new Object[0]; 183 | } 184 | return r[0]; 185 | } 186 | 187 | /** 188 | * 获取一个字段 189 | * 190 | * @param sql 191 | * @param params 192 | * @return 193 | */ 194 | public static Object getField(String sql, String... params) { 195 | Object[][] r = DB.get(sql, params); 196 | if (r.length < 1) { 197 | return null; 198 | } else { 199 | return r[0][0]; 200 | } 201 | 202 | } 203 | 204 | /** 205 | * 更新数据 206 | * 207 | * @param sql 208 | * @param params 209 | * @return 210 | */ 211 | public static int update(String sql, String... params) { 212 | DB.cursor(); 213 | try { 214 | PreparedStatement statement = DB.Connection.prepareStatement(sql); 215 | for (int i = 0; i < params.length; i++) { 216 | statement.setString((i + 1), params[i]); 217 | } 218 | //获取字段信息getMetaData 219 | int r = statement.executeUpdate(); 220 | statement.close(); 221 | return r; 222 | } catch (SQLException ex) { 223 | Logger.getLogger(DB.class.getName()).log(Level.SEVERE, null, ex); 224 | } 225 | return 0; 226 | } 227 | 228 | public static int insert(String sql, String... params) { 229 | return DB.update(sql, params); 230 | } 231 | 232 | public static int delete(String sql, String... params) { 233 | return DB.update(sql, params); 234 | } 235 | 236 | /** 237 | * 解析SQL便于开发 238 | * 239 | * @param sql 240 | * @param params 241 | * @return 242 | */ 243 | public static String getSQL(String sql, String... params) { 244 | for (int i = 0; i < params.length; i++) { 245 | sql = sql.replaceFirst("\\?", sql); 246 | } 247 | return sql; 248 | } 249 | 250 | public static int getTypeName(int typeId) { 251 | switch (typeId) { 252 | case Types.NUMERIC: 253 | //Int 类型 254 | return 1; 255 | case Types.BOOLEAN: 256 | //Boolean类型 257 | return 0; 258 | default: 259 | //其余的当作String处理 260 | return 2; 261 | } 262 | } 263 | 264 | /** 265 | * 检查链接时间是否过期 266 | */ 267 | public static void cursor() { 268 | if ((DB.lastUserTime + Options.DBIdleTime) < System.currentTimeMillis()) { 269 | DB.connection(); 270 | } else { 271 | DB.lastUserTime = (int) System.currentTimeMillis() / 1000; 272 | } 273 | } 274 | } 275 | -------------------------------------------------------------------------------- /demo/Web/ExceptionalHandling.java: -------------------------------------------------------------------------------- 1 | package Web; 2 | 3 | /** 4 | * 处理整体异常的 5 | * 6 | * @author Ma 7 | */ 8 | public class ExceptionalHandling { 9 | 10 | /** 11 | * 404异常处理 12 | * 13 | * @param ex 14 | */ 15 | public static void set404(Exception ex) { 16 | NotFound404.set404(ex); 17 | } 18 | 19 | /** 20 | * 500错误处理 21 | * 22 | * @param ex 23 | */ 24 | public static void set500(Exception ex) { 25 | InternalServerError500.set500(ex); 26 | } 27 | 28 | /** 29 | * 处理其他异常 30 | * @param ex 31 | */ 32 | public static void handling(Exception ex){ 33 | 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /demo/Web/Handler.java: -------------------------------------------------------------------------------- 1 | package Web; 2 | 3 | import java.util.logging.Level; 4 | import java.util.logging.Logger; 5 | import java.util.HashMap; 6 | 7 | /** 8 | * 9 | * @author Ma 10 | */ 11 | public class Handler { 12 | 13 | public Request request; 14 | 15 | /** 16 | * 初始化Handler 17 | */ 18 | public void init(Request request) { 19 | this.request = request; 20 | 21 | } 22 | 23 | /** 24 | * 用于实现一些类似构造方法的作用 25 | * @todo 装饰器实现 26 | */ 27 | public void construct() { 28 | ; 29 | } 30 | 31 | /** 32 | * 获取参数 33 | * @param key 34 | * @return 35 | */ 36 | public Object getArgument(String key){ 37 | return this.request.Arguments.get(key); 38 | } 39 | /** 40 | * 把模版或者字符串写入 41 | * @param s 42 | */ 43 | public void writer(String s) { 44 | Response.setContent(s); 45 | } 46 | 47 | /** 48 | * 读取模版 49 | */ 50 | public BaseTemplate render(String fileName) { 51 | 52 | try { 53 | BaseTemplate object; 54 | if (Options.DEBUG) { 55 | fileName = fileName.replace(".", "/");//把点替换成路径 56 | TplCompile tplCompile = new TplCompile(); 57 | object = (BaseTemplate) tplCompile.run(fileName + ".html"); 58 | if (object == null) { 59 | InternalServerError500.set500(fileName + "模版不存在!"); 60 | } 61 | } else { 62 | Class TemplateClass = Class.forName("Template." + fileName + "Template"); 63 | object = (BaseTemplate) TemplateClass.newInstance(); 64 | } 65 | return object; 66 | } catch (ClassNotFoundException ex) { 67 | //模版不存在 68 | InternalServerError500.set500(fileName + "模版不存在!"); 69 | Logger.getLogger(Handler.class.getName()).log(Level.SEVERE, null, ex); 70 | } catch (InstantiationException ex) { 71 | Logger.getLogger(Handler.class.getName()).log(Level.SEVERE, null, ex); 72 | } catch (IllegalAccessException ex) { 73 | Logger.getLogger(Handler.class.getName()).log(Level.SEVERE, null, ex); 74 | } 75 | return null; 76 | } 77 | 78 | /** 79 | * 重定向到URL,发送303 80 | * 81 | * @param url 82 | */ 83 | public void redirect(String url) { 84 | Response.setStatus(303); 85 | if (url.toLowerCase().indexOf("http://") < 0) { 86 | url = "http://" + this.request.Header.get("Host") + url; 87 | } 88 | Response.header("Location: " + url); 89 | } 90 | 91 | /** 92 | * 页面跳转到URL中,通过HTML 93 | * 94 | * @param url 95 | * @param time 96 | */ 97 | public void jump(String message, String url, int time, boolean status) { 98 | 99 | boolean isSetUrl = false; 100 | 101 | if (message == null) { 102 | message = "Message!"; 103 | } 104 | if (time < 1) { 105 | time = 3; 106 | } 107 | if ("XMLHttpRequest".equals(this.request.Header.get("X-Requested-With"))) { 108 | //判断Ajax请求 109 | HashMap map = new HashMap(); 110 | map.put("static", status); 111 | map.put("data", message); 112 | Response.setContentType(Response.findContentType("json")); 113 | this.writer(Json.encode(map)); 114 | } else { 115 | BaseTemplate jump = this.render("jump"); 116 | jump.assign("status", status); 117 | jump.assign("message", message); 118 | if (url != null) { 119 | isSetUrl = true; 120 | } 121 | jump.assign("isSetUrl", isSetUrl); 122 | jump.assign("url", url); 123 | jump.assign("wait", time); 124 | this.writer(jump.display()); 125 | } 126 | 127 | } 128 | 129 | /** 130 | * 操作成功 131 | */ 132 | public void success(String message, String url, int time) { 133 | if (message == null) { 134 | message = "Success!"; 135 | } 136 | this.jump(message, url, time, true); 137 | } 138 | 139 | /** 140 | * 操作成功 141 | */ 142 | public void success(String message, String url) { 143 | this.success(message, url, 0); 144 | } 145 | 146 | /** 147 | * 操作成功 148 | */ 149 | public void success(String message) { 150 | this.success(message, null, 0); 151 | } 152 | 153 | /** 154 | * 操作错误 155 | */ 156 | public void error(String message, String url, int time) { 157 | if (message == null) { 158 | message = "Error!"; 159 | } 160 | this.jump(message, url, time, false); 161 | } 162 | 163 | /** 164 | * 操作错误 165 | */ 166 | public void error(String message, String url) { 167 | this.error(message, url, 0); 168 | } 169 | 170 | /** 171 | * 操作错误 172 | */ 173 | public void error(String message) { 174 | this.error(message, null, 0); 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /demo/Web/HttpServer.java: -------------------------------------------------------------------------------- 1 | package Web; 2 | 3 | import java.io.IOException; 4 | import java.net.InetSocketAddress; 5 | import java.nio.ByteBuffer; 6 | import java.nio.CharBuffer; 7 | import java.nio.channels.SelectionKey; 8 | import java.nio.channels.Selector; 9 | import java.nio.channels.ServerSocketChannel; 10 | import java.nio.channels.SocketChannel; 11 | import java.nio.charset.Charset; 12 | 13 | import java.util.Iterator; 14 | import java.util.Set; 15 | import java.util.logging.Level; 16 | import java.util.logging.Logger; 17 | 18 | /** 19 | * 服务器 负责分配静态文件服务器和应用服务 20 | * 21 | * @author Ma 22 | */ 23 | public class HttpServer { 24 | 25 | public static void init(int port) { 26 | try { 27 | //初始化数据库连接 28 | DB.connection(); 29 | Selector selector = Selector.open();//创建selector 30 | ServerSocketChannel serverChannel = ServerSocketChannel.open(); 31 | serverChannel.socket().bind(new InetSocketAddress(port)); 32 | serverChannel.configureBlocking(false); 33 | serverChannel.register(selector, SelectionKey.OP_ACCEPT);//注册 34 | SocketChannel channel; 35 | try { 36 | while (true) { 37 | selector.select(); 38 | Iterator iter = selector.selectedKeys().iterator(); 39 | while (iter.hasNext()) { 40 | 41 | SelectionKey key = iter.next(); 42 | iter.remove(); 43 | 44 | Object attach = key.attachment(); 45 | //如果有正在读取静态文件的标记就返回 46 | if (attach != null && attach.equals(0)) { 47 | continue; 48 | } 49 | 50 | 51 | //开始处理 52 | if (key.isAcceptable()) { // 接收请求 53 | ServerSocketChannel server = (ServerSocketChannel) key.channel(); 54 | channel = server.accept(); 55 | //设置非阻塞模式 56 | channel.configureBlocking(false); 57 | channel.register(selector, SelectionKey.OP_READ); 58 | } else if (key.isReadable()) { // 读信息 59 | channel = (SocketChannel) key.channel(); 60 | ByteBuffer clientBuffer = ByteBuffer.allocate(1024); 61 | int count = channel.read(clientBuffer); 62 | String receive = ""; 63 | while (count > 0) { 64 | clientBuffer.flip(); 65 | CharBuffer charBuffer = Charset.forName("UTF-8").decode(clientBuffer); 66 | String temp = charBuffer.toString(); 67 | receive = receive + temp; 68 | clientBuffer.clear(); 69 | count = channel.read(clientBuffer); 70 | channel.register(selector, SelectionKey.OP_WRITE); 71 | } 72 | 73 | key.attach(receive); 74 | clientBuffer.clear(); 75 | } else if (key.isWritable()) { // 写事件 76 | 77 | //开始处理事件 78 | //开始时间 79 | long startTime = System.currentTimeMillis(); 80 | channel = (SocketChannel) key.channel(); 81 | boolean accessStaticFile = false;//是不是访问的静态文件 82 | // 写事件 83 | Request request = new Request((String) key.attachment()); 84 | if (request.Path.equals("/favicon.ico") || request.Path.equals("robots.txt") || request.Path.toLowerCase().indexOf("/static") == 0) { 85 | //##处理 86 | //#说明是访问静态文件 87 | accessStaticFile = true; 88 | StaticFileServer staticFile = new StaticFileServer(request); 89 | if (staticFile.exists()) { 90 | staticFile.read(channel); 91 | key.attach(0);//这个标记是正在读取静态文件 92 | continue;//读取下一个循环 93 | } else { 94 | //如果不存在 95 | //当作非静态文件处理404 省事 96 | accessStaticFile = false; 97 | Response.setStatus(404); 98 | } 99 | 100 | } 101 | //访问的不是静态文件,或者静态文件不存在 102 | if (!accessStaticFile) { 103 | //###处理请求 104 | //获取客户端IP 105 | request.setRemoteIP(channel.socket().getLocalAddress().getHostName()); 106 | //开始分配到Handler 107 | Allocation.init(request); 108 | 109 | //Handler结束 110 | 111 | if (Response.Content == null) { 112 | Response.setContent("未知错误造成,无返回实体!"); 113 | Response.setStatus(500); 114 | } 115 | byte[] contentBytes = Response.Content.getBytes("UTF-8"); 116 | //先设置实体长度 117 | Response.setContentLength(contentBytes.length); 118 | 119 | //然后获取header 120 | byte[] headerBytes = Response.getHeader().getBytes("UTF-8"); 121 | ByteBuffer writerBuffer = ByteBuffer.allocate(headerBytes.length + contentBytes.length); 122 | writerBuffer.clear(); 123 | writerBuffer.put(headerBytes); 124 | writerBuffer.put(contentBytes); 125 | writerBuffer.flip(); 126 | while (writerBuffer.hasRemaining()) { 127 | channel.write(writerBuffer); 128 | } 129 | writerBuffer.clear(); 130 | channel.close(); 131 | //输出debug信息 132 | if (Options.DEBUG || Options.ParseLine) { 133 | System.out.println(Response.Status + " " + request.Header.get("Host") + request.Path + " " + (System.currentTimeMillis() - startTime) + "ms"); 134 | } 135 | //完成响应,清理相应信息 136 | Response.finish(); 137 | } 138 | 139 | } 140 | 141 | } 142 | } 143 | } finally { 144 | serverChannel.close(); 145 | } 146 | } catch (IOException ex) { 147 | Logger.getLogger(HttpServer.class.getName()).log(Level.SEVERE, null, ex); 148 | } 149 | } 150 | 151 | /** 152 | * 设置URL 153 | * 154 | * @param path 155 | * @param handler 156 | */ 157 | public static void setPATH(String path, Object handler) { 158 | Allocation.PATH.put(path, handler); 159 | } 160 | 161 | /** 162 | * 获取所有的Path 163 | * 164 | * @return 165 | */ 166 | public static String[] getAllPath() { 167 | String[] pathArray = new String[Allocation.PATH.size()]; 168 | Set set = Allocation.PATH.entrySet(); 169 | Iterator iterator = set.iterator(); 170 | int i = 0; 171 | while (iterator.hasNext()) { 172 | java.util.Map.Entry item = (java.util.Map.Entry) iterator.next(); 173 | pathArray[i] = (String) item.getKey(); 174 | i++; 175 | } 176 | return pathArray; 177 | } 178 | } -------------------------------------------------------------------------------- /demo/Web/InternalServerError500.java: -------------------------------------------------------------------------------- 1 | package Web; 2 | 3 | /** 4 | * 处理500错误 5 | * 6 | * @author Ma 7 | */ 8 | public class InternalServerError500 { 9 | 10 | public static void set500(String string) { 11 | Response.setContent("

500 服务器方法生错误

" + string); 12 | Response.setStatus(500); 13 | } 14 | 15 | /** 16 | * 触发500异常 17 | */ 18 | public static void set500(Exception ex) { 19 | InternalServerError500.set500(ex.toString()); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /demo/Web/Json.java: -------------------------------------------------------------------------------- 1 | package Web; 2 | 3 | import java.util.Collection; 4 | import java.util.HashMap; 5 | import java.util.Iterator; 6 | import java.util.Map; 7 | 8 | /** 9 | * Json处理,只处理声称Json字符串 10 | * 11 | * @author Ma 12 | */ 13 | public class Json { 14 | 15 | public static String encode(HashMap map) { 16 | Iterator iters = map.entrySet().iterator(); 17 | 18 | String json = "{"; 19 | while (iters.hasNext()) { 20 | Map.Entry entry = (Map.Entry) iters.next(); 21 | Object key = entry.getKey(); 22 | Object val = entry.getValue(); 23 | json += key.toString() + ":"; 24 | if (val instanceof HashMap) { 25 | json += Json.encode((HashMap) val) + ","; 26 | } else { 27 | json = json + "\"" + val.toString() + "\","; 28 | } 29 | } 30 | json = json.substring(0, json.length() - 1) + "}"; 31 | return json; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /demo/Web/NotFound404.java: -------------------------------------------------------------------------------- 1 | package Web; 2 | 3 | /** 4 | * 处理404错误 5 | * 6 | * @author Ma 7 | */ 8 | public class NotFound404 { 9 | 10 | public static void set404(String string) { 11 | Response.setContent("

404 没找到

"+string); 12 | Response.setStatus(404); 13 | } 14 | 15 | /** 16 | * 异常引起的404 17 | */ 18 | public static void set404(Exception ex) { 19 | NotFound404.set404(ex.toString()); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /demo/Web/Options.java: -------------------------------------------------------------------------------- 1 | package Web; 2 | 3 | /** 4 | * 运行时的配置 5 | * 6 | * @author Ma 7 | */ 8 | public class Options { 9 | 10 | /** 11 | * 是不是debug模式 12 | */ 13 | public static boolean DEBUG = false; 14 | /** 15 | * 是否打印信息 16 | */ 17 | public static boolean ParseLine = false; 18 | public static String DBURL = null;//地址 19 | public static String DBDriver = null;//驱动 20 | public static String DBUser = null;//用户 21 | public static String DBPassword = null;//密码 22 | public static int DBIdleTime = 25200;//数据库最大闲置时间 23 | 24 | public static String ServerName = "Web.Java 1.0";//服务器名字 25 | 26 | public static String StaticPath = "/src/Web/Static/";//静态文件目录 27 | public static String TemplatePath = "/src/Web/Template/";//模版文件目录 28 | 29 | 30 | } 31 | -------------------------------------------------------------------------------- /demo/Web/Request.java: -------------------------------------------------------------------------------- 1 | package Web; 2 | 3 | import java.util.HashMap; 4 | import java.util.StringTokenizer; 5 | 6 | /** 7 | * 处理接受到的数据 8 | * 9 | * @author Ma 10 | */ 11 | public class Request { 12 | 13 | public HashMap Header; 14 | public HashMap Arguments; 15 | public HashMap Cookies; 16 | public String Path; 17 | public String Method; 18 | public String RemoteIP; 19 | 20 | /** 21 | * 处理接收数据 22 | * @param receive 接受 23 | */ 24 | public Request(String receive) { 25 | 26 | StringTokenizer stringTokenizer = new StringTokenizer(receive, "\n"); 27 | String[] receiveArray = new String[stringTokenizer.countTokens()]; 28 | HashMap hashMap = new HashMap(); 29 | this.Header = new HashMap(); 30 | this.Arguments = new HashMap(); 31 | this.Cookies = new HashMap(); 32 | String[] URLStrings = stringTokenizer.nextToken().split(" "); 33 | this.Method = URLStrings[0];//请求方式 34 | String href = URLStrings[1]; //URL 35 | String[] hrefSplit = href.split("\\?", 2); 36 | this.Path = hrefSplit[0]; 37 | //分析URL传值 38 | if (hrefSplit.length > 1) { 39 | String query = hrefSplit[1]; 40 | this.Arguments = ResolveQuery.query(query); 41 | } 42 | 43 | while (stringTokenizer.hasMoreTokens()) { 44 | String temp = stringTokenizer.nextToken().trim(); 45 | //长度小于1说明是个空白行,说明header可以结束了,如果是POST请求下面的就是参数了 46 | if (temp.length() < 1) { 47 | break; 48 | } 49 | String[] split = temp.split(":", 2); 50 | if (split.length < 2) { 51 | ; 52 | } 53 | if (split[0].toLowerCase().equals("cookie")) { 54 | //解析Cookie,不记录到Header中 55 | Cookie.analysis(split[1].trim()); 56 | continue; 57 | } 58 | this.Header.put(split[0], split[1].trim()); 59 | } 60 | while (stringTokenizer.hasMoreTokens()) { 61 | String temp = stringTokenizer.nextToken().trim(); 62 | //长度小于1说明是个空白行,说明header可以结束了,如果是POST请求下面的就是参数了 63 | if (temp.length() < 1) { 64 | continue; 65 | } 66 | this.Arguments.putAll(ResolveQuery.query(temp)); 67 | 68 | } 69 | 70 | } 71 | 72 | /** 73 | * 获取用户远程IP 74 | * @return 远程IP 75 | */ 76 | public String getRemoteIP() { 77 | if(this.Header.containsKey("True-ip")){ 78 | this.RemoteIP = (String) this.Header.get("True-ip"); 79 | } 80 | return this.RemoteIP; 81 | } 82 | 83 | /** 84 | * 设置远程IP 85 | * @param RemoteIP 86 | */ 87 | public void setRemoteIP(String RemoteIP) { 88 | this.RemoteIP = RemoteIP; 89 | } 90 | 91 | 92 | 93 | } 94 | -------------------------------------------------------------------------------- /demo/Web/ResolveQuery.java: -------------------------------------------------------------------------------- 1 | /* 2 | * To change this template, choose Tools | Templates 3 | * and open the template in the editor. 4 | */ 5 | package Web; 6 | 7 | import java.util.HashMap; 8 | 9 | /** 10 | * 解析处理URL Query 11 | * 12 | * @author Ma 13 | */ 14 | public class ResolveQuery { 15 | 16 | /** 17 | * 负责解析处理 18 | * @param query 需要解析 19 | * @return 解析完成的数据 20 | */ 21 | public static HashMap query(String query) { 22 | HashMap hashMap = new HashMap(); 23 | String[] split = query.split("&"); 24 | for (int i = 0; i < split.length; i++) { 25 | String string = split[i]; 26 | String[] kvsplit = string.split("=",2); 27 | hashMap.put(java.net.URLDecoder.decode(kvsplit[0]), java.net.URLDecoder.decode(kvsplit[1])); 28 | } 29 | return hashMap; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /demo/Web/Response.java: -------------------------------------------------------------------------------- 1 | package Web; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | import java.util.ArrayList; 5 | import java.util.Arrays; 6 | import java.util.HashMap; 7 | 8 | /** 9 | * 用于记录一些相应信息 如状态码,cookie等 10 | * 11 | * @author Ma 12 | */ 13 | public class Response { 14 | 15 | /** 16 | * 返回消息实体 17 | */ 18 | public static String Content = ""; 19 | /** 20 | * 如果是文件就直接些进去 21 | */ 22 | public static byte[] FileBytes; 23 | /** 24 | * 标记这次是不是请求文件的 25 | */ 26 | public static boolean IsFile = false; 27 | public static ArrayList Header = new ArrayList(); 28 | public static String Status = "HTTP/1.1 200 OK"; 29 | public static ArrayList Cookies = new ArrayList(); 30 | public static String ContentType = "text/html;charset=UTF-8;"; 31 | /** 32 | * 服务器的名字 33 | */ 34 | public static String Server = Options.ServerName; 35 | /** 36 | * 只包含Contest的长度不包含header的长度 37 | */ 38 | public static int ContentLength; 39 | 40 | /** 41 | * //禁用页面缓存
42 | * header('Cache-Control: no-cache, no-store, max-age=0,must-revalidate'); 43 | *
44 | * header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
45 | * header('Pragma: no-cache');
46 | * 47 | * public static String X-Powered-By; 48 | * 49 | */ 50 | /** 51 | * 设置状态码 HTTP/1.1 200 OK
52 | * HTTP/1.1 303 See Other \r\nLocation:http://www.maiyoule.com/ 结尾没有分号
53 | * HTTP/1.1 304 Not Modified 缓存
54 | * HTTP/1.1 403 Forbidden
55 | * HTTP/1.1 404 Not Found
56 | * HTTP/1.1 500 Internal Server Error
57 | * 58 | * @param code 59 | */ 60 | public static void setStatus(int code) { 61 | String string; 62 | switch (code) { 63 | case 200: 64 | string = "HTTP/1.1 200 OK"; 65 | break; 66 | case 303: 67 | string = "HTTP/1.1 303 See Other"; 68 | break; 69 | case 304: 70 | string = "HTTP/1.1 304 Not Modified"; 71 | break; 72 | case 403: 73 | string = "HTTP/1.1 403 Forbidden"; 74 | break; 75 | case 404: 76 | string = "HTTP/1.1 404 Not Found"; 77 | break; 78 | case 500: 79 | string = "HTTP/1.1 500 Internal Server Error"; 80 | break; 81 | default: 82 | string = "HTTP/1.1 200 OK"; 83 | } 84 | Response.Status = string; 85 | 86 | } 87 | 88 | /** 89 | * 设置content-length长度 90 | * 91 | * @param length 92 | */ 93 | public static void setContentLength(int length) { 94 | Response.ContentLength = length; 95 | } 96 | 97 | /** 98 | * 设置ContentType application/json; charset=utf-8;
99 | * text/html;charset=UTF-8;
100 | * application/xml;charset=UTF-8;
101 | */ 102 | public static void setContentType(String type) { 103 | Response.ContentType = type; 104 | } 105 | 106 | /** 107 | * 查找ContentType类型 不能识别的文件,默认当作zip处理 108 | * 109 | * @todo 是否允许自己配置 110 | */ 111 | public static String findContentType(String type) { 112 | HashMap contentType = new HashMap(); 113 | contentType.put("html", "text/html;charset=UTF-8;"); 114 | contentType.put("json", "application/json; charset=utf-8;"); 115 | contentType.put("xml", "application/xml;charset=UTF-8;"); 116 | contentType.put("zip", "application/x-zip-compressed"); 117 | contentType.put("ico", "image/x-icon"); 118 | String returnType = ""; 119 | if (contentType.containsKey(type)) { 120 | returnType = contentType.get(type); 121 | } else { 122 | returnType = "application/x-zip-compressed"; 123 | } 124 | return returnType; 125 | } 126 | 127 | /** 128 | * 设置返回实体 129 | * 130 | * @param content 131 | */ 132 | public static void setContent(String content) { 133 | Response.Content = content; 134 | } 135 | 136 | /** 137 | * 追加返回实体 138 | * 139 | * @param content 140 | */ 141 | public static void addContent(String content) { 142 | Response.Content = Response.Content + content; 143 | } 144 | 145 | /** 146 | * 添加自定义Header 147 | * 148 | * @param header 149 | * @return 150 | */ 151 | public static boolean header(String header) { 152 | return Response.Header.add(header); 153 | } 154 | 155 | /** 156 | * 获取此次响应的header 157 | * 158 | * @return 159 | */ 160 | public static String getHeader() { 161 | String header; 162 | header = Response.Status + "\r\n"; 163 | //检查cookie 164 | for (int i = 0; i < Response.Cookies.size(); i++) { 165 | header += Response.Cookies.get(i) + "\r\n"; 166 | } 167 | header += "Content-type: " + Response.ContentType + "\r\n"; 168 | header += "Content-ength: " + Response.ContentLength + "\r\n"; 169 | //检查自定义Header 170 | for (int i = 0; i < Response.Header.size(); i++) { 171 | header += Response.Header.get(i) + "\r\n"; 172 | } 173 | 174 | header += "Server: " + Response.Server + "\r\n\r\n"; 175 | 176 | return header; 177 | } 178 | 179 | public static byte[] getContentBytes() throws UnsupportedEncodingException { 180 | 181 | return Response.Content.getBytes("UTF-8"); 182 | } 183 | 184 | /** 185 | * 请求结束,清理信息 186 | */ 187 | public static void finish() { 188 | 189 | Response.Status = "HTTP/1.1 200 OK"; 190 | Response.Content = ""; 191 | Response.Header = new ArrayList(); 192 | Response.Cookies = new ArrayList(); 193 | Response.ContentLength = 0; 194 | Response.ContentType = "text/html;charset=UTF-8;"; 195 | Response.FileBytes = new byte[0]; 196 | //取消是文件标识 197 | Response.IsFile = false; 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /demo/Web/StaticFileServer.java: -------------------------------------------------------------------------------- 1 | package Web; 2 | 3 | import java.nio.channels.SocketChannel; 4 | import java.util.logging.Level; 5 | import java.util.logging.Logger; 6 | import java.io.IOException; 7 | import java.nio.ByteBuffer; 8 | import java.nio.channels.AsynchronousFileChannel; 9 | import java.nio.channels.CompletionHandler; 10 | import java.nio.file.Files; 11 | import java.nio.file.Path; 12 | import java.nio.file.Paths; 13 | import java.nio.file.attribute.BasicFileAttributeView; 14 | import java.nio.file.attribute.BasicFileAttributes; 15 | import java.util.concurrent.TimeUnit; 16 | 17 | /** 18 | * 静态文件服务器 19 | * 20 | * @author Ma 21 | */ 22 | public class StaticFileServer { 23 | 24 | public Request request; 25 | public int size; 26 | public ByteBuffer byteBuffer; 27 | public SocketChannel socketChannel; 28 | public Path filePath; 29 | public String ExName;//扩展名字 30 | 31 | /** 32 | * 初始化一些东西 33 | * 34 | * @param request 35 | */ 36 | public StaticFileServer(Request request) { 37 | this.request = request; 38 | String path = Options.StaticPath + this.request.Path.substring(8); 39 | this.filePath = Paths.get(path); 40 | //设置扩展名 41 | int index = this.request.Path.lastIndexOf("."); 42 | this.ExName = this.request.Path.substring(index + 1); 43 | } 44 | 45 | /** 46 | * 检测文件是否存在 47 | * 48 | * @return 49 | */ 50 | public boolean exists() { 51 | return Files.exists(filePath); 52 | 53 | } 54 | 55 | /** 56 | * 检查文件是否需要更新还是304状态吗 57 | * 58 | * @return 59 | */ 60 | public boolean update() { 61 | try { 62 | int lastTime = (int) Files.getLastModifiedTime(filePath).to(TimeUnit.SECONDS);//获取最后修改的时间戳 63 | Object paramTime = this.request.Header.get("If-Modified-Since"); 64 | 65 | if ((paramTime != null) && (Integer.parseInt((String) paramTime) <= lastTime)) { 66 | //处理304 67 | Response.setStatus(304); 68 | Response.setContentType(Response.findContentType(this.ExName)); 69 | Response.header("Last-Modified: " + lastTime); 70 | Response.header("Cache-Control:public, max-age=2592000"); 71 | byte[] headerBytes = Response.getHeader().getBytes(); 72 | ByteBuffer writerBuffer = ByteBuffer.allocate(headerBytes.length); 73 | writerBuffer.clear(); 74 | writerBuffer.put(headerBytes); 75 | writerBuffer.flip(); 76 | while (writerBuffer.hasRemaining()) { 77 | this.socketChannel.write(writerBuffer); 78 | } 79 | writerBuffer.clear(); 80 | this.socketChannel.close(); 81 | //输出debug信息 82 | if (Options.DEBUG || Options.ParseLine) { 83 | System.out.println(Response.Status + " " + this.request.Header.get("Host") + this.request.Path); 84 | } 85 | Response.finish();//清理信息 86 | return false; 87 | } 88 | } catch (IOException ex) { 89 | Logger.getLogger(StaticFileServer.class.getName()).log(Level.SEVERE, null, ex); 90 | } 91 | return true; 92 | } 93 | 94 | public void read(SocketChannel socketChannel) { 95 | this.socketChannel = socketChannel; 96 | //处理304 97 | if (this.update()) { 98 | //输出debug信息 99 | if (Options.DEBUG || Options.ParseLine) { 100 | System.out.println("Static File" + " " + this.request.Header.get("Host") + this.request.Path); 101 | } 102 | //处理200 103 | BasicFileAttributeView basicView = Files.getFileAttributeView(this.filePath, BasicFileAttributeView.class); 104 | 105 | try { 106 | BasicFileAttributes basicAttrs = basicView.readAttributes(); 107 | long size = basicAttrs.size(); 108 | if (size > 2097152) { 109 | //说明文件大于2M 110 | } 111 | this.size = (int) size; 112 | int lastTime = (int) Files.getLastModifiedTime(filePath).to(TimeUnit.SECONDS);//获取最后修改的时间戳 113 | this.byteBuffer = ByteBuffer.allocate((int) size);//申请缓存空间 114 | //开始获取通道,读取文件 115 | AsynchronousFileChannel afc = AsynchronousFileChannel.open(this.filePath); 116 | afc.read(byteBuffer, 0, lastTime, new CompletionHandlerImpl(afc)); 117 | 118 | } catch (IOException ex) { 119 | //处理500错误 120 | Logger.getLogger(StaticFileServer.class.getName()).log(Level.SEVERE, null, ex); 121 | } 122 | } 123 | } 124 | 125 | /** 126 | * 成员类 处理文件完成后的操作 127 | */ 128 | private class CompletionHandlerImpl implements CompletionHandler { 129 | 130 | AsynchronousFileChannel afc; 131 | 132 | public CompletionHandlerImpl(AsynchronousFileChannel afc) { 133 | this.afc = afc; 134 | } 135 | 136 | /** 137 | * 处理成功的操作 138 | * 139 | * @param result 140 | * @param attachment 141 | */ 142 | @Override 143 | public void completed(Integer result, Object attachment) { 144 | 145 | Integer lastModifyInteger = (Integer) attachment; 146 | int lastModify = lastModifyInteger.intValue(); 147 | //Header不能使用Response 148 | String header = "HTTP/1.1 200 OK\r\n" 149 | + "Content-type: " + Response.findContentType(StaticFileServer.this.ExName) + ";\r\n" 150 | + "Content-ength: " + StaticFileServer.this.size + "\r\n" 151 | + "Last-Modified: " + lastModify + "\r\n" 152 | + "Cache-Control:public, max-age=2592000 \r\n" 153 | + "Server: " + Response.Server + "\r\n\r\n"; 154 | 155 | byte[] headerBytes = header.getBytes(); 156 | byte[] contentBytes = StaticFileServer.this.byteBuffer.array(); 157 | ByteBuffer writerBuffer = ByteBuffer.allocate(headerBytes.length + contentBytes.length); 158 | writerBuffer.clear(); 159 | 160 | writerBuffer.put(headerBytes); 161 | writerBuffer.put(contentBytes); 162 | writerBuffer.flip(); 163 | try { 164 | while (writerBuffer.hasRemaining()) { 165 | StaticFileServer.this.socketChannel.write(writerBuffer); 166 | } 167 | writerBuffer.clear(); 168 | 169 | StaticFileServer.this.socketChannel.close(); 170 | this.afc.close(); 171 | } catch (IOException ex) { 172 | Logger.getLogger(StaticFileServer.class.getName()).log(Level.SEVERE, null, ex); 173 | } 174 | } 175 | 176 | /** 177 | * 处理失败的操作 178 | * 179 | * @param exc 180 | * @param attachment 181 | */ 182 | @Override 183 | public void failed(Throwable exc, Object attachment) { 184 | System.out.println(exc.getCause()); 185 | //@todo 处理500错误 186 | try { 187 | StaticFileServer.this.socketChannel.close(); 188 | this.afc.close(); 189 | } catch (IOException ex) { 190 | Logger.getLogger(StaticFileServer.class.getName()).log(Level.SEVERE, null, ex); 191 | } 192 | } 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /demo/Web/TemplateCompile.java: -------------------------------------------------------------------------------- 1 | package Web; 2 | 3 | import java.io.File; 4 | import java.io.BufferedReader; 5 | import java.io.BufferedWriter; 6 | import java.io.FileNotFoundException; 7 | import java.io.FileReader; 8 | import java.io.FileWriter; 9 | import java.util.regex.Pattern; 10 | import java.io.IOException; 11 | import java.util.ArrayList; 12 | import java.util.logging.Level; 13 | import java.util.logging.Logger; 14 | import java.util.regex.Matcher; 15 | 16 | /** 17 | * 编译模版成Java代码 18 | * 19 | * @author Ma 20 | */ 21 | public class TemplateCompile { 22 | 23 | /** 24 | * 模版目录 25 | */ 26 | String TemplatePath = Options.TemplatePath; 27 | protected ArrayList block; 28 | protected ArrayList blockContent; 29 | protected boolean isBlock = false; 30 | protected boolean isExtends = false;//标记是否是有继承关系 31 | private BufferedWriter writer; 32 | 33 | public TemplateCompile() { 34 | this.blockContent = new ArrayList(); 35 | this.block = new ArrayList(); 36 | this.TemplatePath = Options.TemplatePath; 37 | } 38 | 39 | /** 40 | * public static void main(String[] args) { TemplateCompile self = new 41 | * TemplateCompile(); File tplDir = new File(self.TemplatePath); //判断目录是否存在 42 | * tplDir.isDirectory(); 43 | * 44 | * String[] fileList = tplDir.list(); 45 | * 46 | * for (int i = 0; i < fileList.length; i++) { String string = fileList[i]; 47 | * if (string.matches(".+\\.java")) {//不处理Java文件 continue; } 48 | * self.start(string); System.out.println(string);//@todo 后期处理子目录的问题 } } 49 | * 50 | */ 51 | public int start(String fileName) { 52 | File tplFile = new File(this.TemplatePath + fileName); 53 | if (tplFile.exists()) { 54 | try { 55 | BufferedReader reader = new BufferedReader(new FileReader(tplFile)); 56 | String line = null; 57 | //编译文件Start 58 | 59 | File compilerFile = this.getFile(fileName);//获取Java文件 60 | if (compilerFile.exists()) { 61 | //如果文件存在就比较时间 62 | if (compilerFile.lastModified() > tplFile.lastModified()) { 63 | //如果最后修改的时候小于编译后的Java文件的最后日期 64 | //直接返回 65 | //return 0;注释掉,每次都重新编译 66 | } 67 | } else { 68 | //如果文件不存在就创建 69 | compilerFile.createNewFile(); 70 | } 71 | 72 | this.writer = new BufferedWriter(new FileWriter(compilerFile)); 73 | if (!compilerFile.isFile()) { 74 | ;//说明创建失败 75 | } 76 | //编译文件END 77 | String fatherTpl = "Web.BaseTemplate";//默认继承 78 | line = reader.readLine();//分析第一行是否继承 79 | Pattern pat = Pattern.compile("\\{\\%\\s*extends\\s*\\s(\\w+)\\s*\\%\\}"); 80 | Matcher mat = pat.matcher(line); 81 | if (mat.find()) { 82 | fatherTpl = mat.group(1) + "Template"; 83 | line = line.replace(mat.group(), ""); 84 | this.isExtends = true; 85 | //遇到继承,就去解析父模版 86 | TemplateCompile templateCompile = new TemplateCompile(); 87 | int r = templateCompile.start(mat.group(1) + ".html"); 88 | } 89 | //识别继承标识Start 90 | Pattern blockPat = Pattern.compile("\\{\\%\\s*block\\s*(\\w+)\\s*\\%\\}"); 91 | //识别继承标识END 92 | 93 | 94 | //writer.write("package Web.Template" + this.getPackage(fileName) + ";\npublic class " 95 | writer.write("package Template" + this.getPackage(fileName) + ";\npublic class " 96 | + this.getfileName(fileName) 97 | + "Template extends " + fatherTpl + "{"); 98 | if (!this.isExtends) { 99 | writer.write("\n\tpublic String display(){\n\t\tString str= \n"); 100 | } 101 | while (line != null) { 102 | line = line.trim(); 103 | if (line.length() < 1) { 104 | line = reader.readLine();//读取下一行 105 | continue; 106 | } 107 | //检查是否是block Start 108 | Matcher blockMat = blockPat.matcher(line); 109 | if (blockMat.find()) { 110 | this.block.add(blockMat.group(1)); 111 | this.blockContent.add(""); 112 | this.isBlock = true; 113 | line = line.replace(blockMat.group(), "\"\"+this." + blockMat.group(1) + "()"); 114 | this.writerFile(line, true); 115 | line = reader.readLine();//读取下一行 116 | continue; 117 | //System.out.println(blockMat.group(1)); 118 | } 119 | 120 | //检查是否是block End 121 | if (this.isBlock && line.matches("\\{\\%\\s*end\\s*\\%\\}")) { 122 | this.isBlock = false; 123 | line = reader.readLine();//读取下一行 124 | continue; 125 | 126 | } 127 | 128 | 129 | 130 | //检查if 语句 131 | if (line.matches(".*\\{\\%\\s*if\\s*\\(.+\\)\\s*\\%\\}.*")) { 132 | 133 | line = line.replace("\"", "\\\""); 134 | line = line.replace("{%", "\";"); 135 | line = line.replace("%}", "{str=str"); 136 | line = "\"" + line + "\n"; 137 | 138 | if (this.isBlock) { 139 | this.writerBlock(line, true); 140 | } else { 141 | this.writerFile(line, true); 142 | } 143 | line = reader.readLine();//读取下一行 144 | continue; 145 | } 146 | //检查endif 语句 147 | if (line.matches(".*\\{\\%\\s*endif\\s*\\%\\}.*")) { 148 | line = line.replaceAll("\\{\\%\\s*endif\\s*\\%\\}", "\";}str=str+\""); 149 | line = "\"" + line + "\"\n"; 150 | if (this.isBlock) { 151 | this.writerBlock(line, true); 152 | } else { 153 | this.writerFile(line, true); 154 | } 155 | line = reader.readLine();//读取下一行 156 | continue; 157 | } 158 | //检查elseif 语句 159 | if (line.matches(".*\\{\\%\\s*elseif\\s*\\(.+\\)\\s*\\%\\}.*")) { 160 | line = line.replace("{%", "\";}"); 161 | line = line.replace("%}", "{str=str"); 162 | line = line.replace("elseif", "else if"); 163 | line = "\"" + line + "\n"; 164 | 165 | if (this.isBlock) { 166 | this.writerBlock(line, true); 167 | } else { 168 | this.writerFile(line, true); 169 | } 170 | line = reader.readLine();//读取下一行 171 | continue; 172 | } 173 | //检查else 语句 174 | if (line.matches(".*\\{\\%\\s*else\\s*\\%\\}.*")) { 175 | line = line.replaceAll("\\{\\%\\s*else\\s*\\%\\}", "\";}else{str=str"); 176 | 177 | line = "\"" + line + "\n"; 178 | if (this.isBlock) { 179 | this.writerBlock(line, true); 180 | } else { 181 | this.writerFile(line, true); 182 | } 183 | line = reader.readLine();//读取下一行 184 | continue; 185 | } 186 | //检查for 语句 187 | if (line.matches(".*\\{\\%\\s*for\\s*\\(.+\\)\\s*\\%\\}.*")) { 188 | line = line.replace("{%", "\";"); 189 | line = line.replace("%}", "{str=str"); 190 | line = "\"" + line + "\n"; 191 | if (this.isBlock) { 192 | this.writerBlock(line, true); 193 | } else { 194 | this.writerFile(line, true); 195 | } 196 | line = reader.readLine();//读取下一行 197 | continue; 198 | } 199 | 200 | //检查endfor 语句 201 | if (line.matches(".*\\{\\%\\s*endfor\\s*\\%\\}.*")) { 202 | line = line.replaceAll("\\{\\%\\s*endfor\\s*\\%\\}", "\";}str=str"); 203 | line = "\"" + line + "\n"; 204 | if (this.isBlock) { 205 | this.writerBlock(line, true); 206 | } else { 207 | this.writerFile(line, true); 208 | } 209 | line = reader.readLine();//读取下一行 210 | continue; 211 | } 212 | 213 | 214 | if (this.isBlock) { 215 | this.writerBlock(line); 216 | } else { 217 | this.writerFile(line); 218 | } 219 | 220 | 221 | writer.newLine(); 222 | //writer.newLine(); 223 | line = reader.readLine();//读取下一行 224 | } 225 | 226 | reader.close(); 227 | this.flush(); 228 | this.writer.flush(); 229 | this.writer.close(); 230 | return 0; 231 | 232 | } catch (FileNotFoundException ex) { 233 | Logger.getLogger(TemplateCompile.class.getName()).log(Level.SEVERE, null, ex); 234 | } catch (IOException ex) { 235 | Logger.getLogger(TemplateCompile.class.getName()).log(Level.SEVERE, null, ex); 236 | } 237 | 238 | 239 | } else { 240 | return 1; 241 | } 242 | return 0; 243 | } 244 | 245 | /** 246 | * 创建编译后的文件 247 | * 248 | * @param fileName 249 | * @return 250 | */ 251 | protected File getFile(String fileName) { 252 | fileName = this.getFilePath(fileName) + "/" + this.getfileName(fileName); 253 | String javaTplName = fileName + "Template.java"; 254 | File JavaFile = new File(this.TemplatePath + javaTplName); 255 | 256 | return JavaFile; 257 | } 258 | 259 | /** 260 | * 获取文件名字,不包括扩展名字 261 | * 262 | * @param fileName 263 | * @return 264 | */ 265 | protected String getfileName(String fileName) { 266 | //获取文件名字,不包含扩展名 267 | int index = fileName.lastIndexOf(".html"); 268 | fileName = fileName.substring(0, index); 269 | index = fileName.lastIndexOf("/"); 270 | fileName = fileName.substring(index + 1); 271 | return fileName; 272 | } 273 | 274 | /** 275 | * 获取文件的路径 276 | * 277 | * @param fileName 278 | * @return 279 | */ 280 | protected String getFilePath(String fileName) { 281 | int index = fileName.lastIndexOf(".html"); 282 | fileName = fileName.substring(0, index); 283 | index = fileName.lastIndexOf("/"); 284 | String path = ""; 285 | if (index > 0) { 286 | path = fileName.substring(0, index); 287 | } 288 | return path; 289 | } 290 | 291 | protected String getPackage(String fileName) { 292 | String path = this.getFilePath(fileName); 293 | if (path.equals("")) { 294 | path = ""; 295 | } else { 296 | path = "." + path.replace("/", "."); 297 | } 298 | return path; 299 | } 300 | 301 | /** 302 | * 写入bolck,自动添加引号 303 | * 304 | * @param line 305 | * @return 306 | */ 307 | protected String writerBlock(String line) { 308 | String r = ""; 309 | //首先把所有变量修改{{}} 310 | if (line.matches(".*\\{\\{.+\\}\\}.*")) { 311 | Pattern pattern = Pattern.compile(".*\\{\\{(\\w+):(\\w+):?(\\w+)?\\}\\}.*"); 312 | Matcher matcher = pattern.matcher(line); 313 | if (matcher.find()) { 314 | line = line.replace("\"", "\\\""); 315 | if (matcher.group(3) == null) { 316 | line = line.replaceFirst("\\{\\{(.+):(.+)\\}\\}", "\"+this.getArray(\"" 317 | + matcher.group(1) + "\")[" 318 | + matcher.group(2) + "]+\""); 319 | } else {//说明是引用2维数组 320 | line = line.replaceFirst("\\{\\{(.+):(.+):(.+)\\}\\}", "\"+this.getArray2(\"" 321 | + matcher.group(1) + "\")[" 322 | + matcher.group(2) + "][" + matcher.group(3) + "]+\""); 323 | } 324 | } else { 325 | line = line.replace("{{", "\"+this.get(\""); 326 | line = line.replace("}}", "\")+\""); 327 | line = line.replace("\"", "\\\""); 328 | } 329 | r = this.blockContent.set(this.block.size() - 1, this.blockContent.get(this.block.size() - 1) + "+\n" + "\"" + line + "\""); 330 | } else { 331 | r = this.blockContent.set(this.block.size() - 1, this.blockContent.get(this.block.size() - 1) + "+\n" + "\"" + line.replace("\"", "\\\"") + "\""); 332 | } 333 | return r; 334 | } 335 | 336 | /** 337 | * 写入 bolck,不写入引号 338 | * 339 | * @param line 340 | * @param eval 341 | * @return 342 | */ 343 | protected String writerBlock(String line, boolean eval) { 344 | 345 | //首先把所有变量修改{{}} 346 | Pattern pat = Pattern.compile("\\(.*\\$([_a-zA-Z][_a-zA-Z0-9]*):?(\\w*).*\\)"); 347 | Matcher mat = pat.matcher(line); 348 | 349 | if (mat.find()) { 350 | String param = mat.group(1); 351 | String valueType = ""; 352 | if (mat.group(2).length() > 0) { 353 | valueType = mat.group(2).replaceFirst(mat.group(2).substring(0, 1), mat.group(2).substring(0, 1).toUpperCase()); 354 | } 355 | line = line.replaceAll("\\$([_a-zA-Z][_a-zA-Z0-9]*):?(\\w*)", "this.get" 356 | + valueType 357 | + "(\"" + param + "\")"); 358 | } 359 | String r = this.blockContent.set(this.block.size() - 1, this.blockContent.get(this.block.size() - 1) + "+\n" + line); 360 | return r; 361 | } 362 | 363 | /** 364 | * 写入引号 365 | * 366 | * @param line 367 | */ 368 | protected void writerFile(String line) { 369 | line = line.replace("\"", "\\\""); 370 | //首先把所有变量修改{{}} 371 | if (line.matches(".*\\{\\{.+\\}\\}.*")) { 372 | Pattern pattern = Pattern.compile(".*\\{\\{(\\w+):(\\w+)\\}\\}.*"); 373 | Matcher matcher = pattern.matcher(line); 374 | if (matcher.matches()) { 375 | 376 | line = line.replaceAll("\\{\\{(.+):(.+)\\}\\}", "\"+this.getArray(\"" 377 | + matcher.group(1) + "\")[" 378 | + matcher.group(2) + "]+\""); 379 | } else { 380 | line = line.replace("{{", "\"+this.get(\""); 381 | line = line.replace("}}", "\")+\""); 382 | } 383 | } 384 | try { 385 | writer.write("\"" + line + "\"+"); 386 | 387 | } catch (IOException ex) { 388 | Logger.getLogger(TemplateCompile.class.getName()).log(Level.SEVERE, null, ex); 389 | } 390 | } 391 | 392 | /** 393 | * 不写入引号 394 | * 395 | * @param line 396 | * @param eval 397 | */ 398 | protected void writerFile(String line, boolean eval) { 399 | 400 | //首先把所有变量修改{{}} 401 | Pattern pat = Pattern.compile("\\(.*\\$([_a-zA-Z][_a-zA-Z0-9]*):?(\\w*).*\\)"); 402 | Matcher mat = pat.matcher(line); 403 | 404 | if (mat.find()) { 405 | String param = mat.group(1); 406 | String valueType = ""; 407 | if (mat.group(2).length() > 0) { 408 | valueType = mat.group(2).replaceFirst(mat.group(2).substring(0, 1), mat.group(2).substring(0, 1).toUpperCase()); 409 | } 410 | line = line.replaceAll("\\$([_a-zA-Z][_a-zA-Z0-9]*):?(\\w*)", "this.get" 411 | + valueType 412 | + "(\"" + param + "\")"); 413 | } 414 | try { 415 | if (!this.isExtends) { 416 | writer.write("" + line + "+"); 417 | } 418 | } catch (IOException ex) { 419 | Logger.getLogger(TemplateCompile.class.getName()).log(Level.SEVERE, null, ex); 420 | } 421 | } 422 | 423 | /** 424 | * 处理结尾,把block写在里面 425 | */ 426 | protected void flush() { 427 | try { 428 | if (!this.isExtends) { 429 | this.writer.write("\"\";return str;\n}"); 430 | } 431 | for (int i = 0; i < this.block.size(); i++) { 432 | try { 433 | this.writer.write("public String " + this.block.get(i) + " (){ String str = \"\"" + this.blockContent.get(i) + ";return str;}"); 434 | 435 | } catch (IOException ex) { 436 | Logger.getLogger(TemplateCompile.class.getName()).log(Level.SEVERE, null, ex); 437 | } 438 | 439 | } 440 | this.writer.write("\n}"); 441 | } catch (IOException ex) { 442 | Logger.getLogger(TemplateCompile.class.getName()).log(Level.SEVERE, null, ex); 443 | } 444 | } 445 | } 446 | -------------------------------------------------------------------------------- /demo/Web/Tools.java: -------------------------------------------------------------------------------- 1 | package Web; 2 | 3 | /** 4 | * 常用工具类 5 | * 6 | * @author Ma 7 | */ 8 | public class Tools { 9 | 10 | /** 11 | * 获取完整静态文件路径 12 | * 13 | * @param path 文件路径 14 | * @return 完整文件路径 15 | */ 16 | public static String staticFile(String path) { 17 | return ""; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /demo/Web/TplCompile.java: -------------------------------------------------------------------------------- 1 | package Web; 2 | 3 | import java.util.logging.Level; 4 | import java.util.logging.Logger; 5 | import javax.tools.JavaCompiler; 6 | import javax.tools.ToolProvider; 7 | 8 | /** 9 | * 动态编译Java文件 10 | * 11 | * @author Ma 12 | */ 13 | public class TplCompile { 14 | 15 | public String TemplatePath = Options.TemplatePath; 16 | 17 | /* 18 | public static void main(String[] args) { 19 | TplCompile Compiler = new TplCompile(); 20 | Compiler.setTemplatePath(); 21 | Compiler.run("dd/test.html"); 22 | }*/ 23 | public void setTemplatePath() { 24 | this.TemplatePath = Options.TemplatePath; 25 | } 26 | 27 | /** 28 | * 开始编译 29 | */ 30 | public Object run(String fileName) { 31 | this.setTemplatePath();//先配置路径 32 | TemplateCompile templateCompile = new TemplateCompile(); 33 | int r = templateCompile.start(fileName); 34 | if (r > 0 && r == 1) { 35 | //1表示说明文件不存在 36 | //0表示解析正常 37 | return null; 38 | } 39 | String javaFile = this.TemplatePath + templateCompile.getFilePath(fileName) + "/" + templateCompile.getfileName(fileName) + "Template.java"; 40 | String classPath = this.getClass().getResource("/").getPath(); 41 | //动态编译 42 | JavaCompiler javac = ToolProvider.getSystemJavaCompiler(); 43 | int status = javac.run(null, null, null, "-d", classPath, javaFile); 44 | if (status != 0) { 45 | System.out.println("没有编译成功!"); 46 | } 47 | 48 | //动态执行 49 | try { 50 | //返回与带有给定字符串名的类 或接口相关联的 Class 对象。 51 | 52 | Class cls = Class.forName("Template." + templateCompile.getFilePath(fileName).replace("/", ".") + templateCompile.getfileName(fileName) + "Template"); 53 | BaseTemplate object = (BaseTemplate) cls.newInstance(); 54 | return object; 55 | } catch (ClassNotFoundException ex) { 56 | Logger.getLogger(TplCompile.class.getName()).log(Level.SEVERE, null, ex); 57 | } catch (InstantiationException ex) { 58 | Logger.getLogger(TplCompile.class.getName()).log(Level.SEVERE, null, ex); 59 | } catch (IllegalAccessException ex) { 60 | Logger.getLogger(TplCompile.class.getName()).log(Level.SEVERE, null, ex); 61 | } 62 | return null; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /demo/blog.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS `article`; 2 | CREATE TABLE `article` ( 3 | `id` int(11) NOT NULL AUTO_INCREMENT, 4 | `title` char(30) DEFAULT NULL COMMENT '文章标题', 5 | `content` text COMMENT '文章内容', 6 | `creat_date` int(11) DEFAULT NULL COMMENT '创建时间', 7 | `user_id` int(11) DEFAULT NULL COMMENT '作者ID', 8 | PRIMARY KEY (`id`) 9 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 10 | 11 | 12 | DROP TABLE IF EXISTS `user`; 13 | CREATE TABLE `user` ( 14 | `id` int(11) NOT NULL AUTO_INCREMENT, 15 | `name` char(10) DEFAULT NULL COMMENT '管理员用户名', 16 | `password` char(32) DEFAULT NULL COMMENT '管理员密码', 17 | PRIMARY KEY (`id`) 18 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 19 | INSERT INTO `user` VALUES ('1', '123', '123'); 20 | --------------------------------------------------------------------------------