Ioc html
按照mvc,咱们须要把tiny分红3层,其中视图(Renderer抽象类)和Action咱们已经在前面实现了,此次咱们用最少的代码实现Model。 java
model沿用Action的想法,用户自定义类,类名必须以Model结尾,同Action同样在初始化时放入Container容器内。model就是数据模型,咱们这里充血模型,model的类名默认是同数据库的表名作关联的,即类名去掉Model后(转为小写)为代表,这样一对一映射,有时会简单不少,如保存和查询单个表时,固然了你能够传入复杂sql,返回的结果有基本类型、map、list等。 c++
model里须要访问数据库时,咱们设计了DbUtil工具类,建议在model里使用,固然了这个仍是看你,DbUtil自己没有限制。model是经过ioc注入进来的,在你访问这个action前。下面代码中的Container.inject(o);为容器向action中注入model实例。 git
Map<String,String> args = this.converter(req.getParameterMap()); String key = UUID.randomUUID().toString(); Container.inject(o); this.before(routes,args,key); Object result = o.getClass().getMethod(routes[1],Map.class).invoke(o,args); this.after(args,key); Container.clearReqAops(key);
public static void inject(Object o) throws IllegalArgumentException, IllegalAccessException, InstantiationException{ Field filedArr[] = o.getClass().getDeclaredFields(); for (Field field:filedArr) { String ftn = field.getType().getSimpleName(); if (ftn.endsWith("Model")) { Object m = Container.getCls(ftn); if(m != null){ field.set(o,((Class)m).newInstance()); } } } }
model的初始化,代码以下: web
if (className.endsWith("Action.class")) { packPath=packPath.replace(".class.", ""); Object o = Class.forName(packPath).newInstance(); String clsName = o.getClass().getSimpleName().substring(0,o.getClass().getSimpleName().lastIndexOf("Action")); if(clsMap.get(clsName) != null){ new IllegalAccessException(clsName+" class 重复"); }else{ clsMap.put(clsName, o); } }else if (className.endsWith("Model.class")) { className=className.replace(".class", ""); packPath=packPath.replace(".class.", ""); Class o = Class.forName(packPath); if(clsMap.get(className) != null){ new IllegalAccessException(className+" class 重复"); }else{ clsMap.put(className, o); } }
模型的使用(数据库链接池还未测试) sql
testAction 数据库
package web; import java.util.Map; import tiny.ContextUtil; import tiny.JspRenderer; import tiny.Renderer; public class TinyTestAction { public UserModel user; public void hello(Map<String,String> args){ System.out.println("aa:"+args.get("aa")); System.out.println("访问时间1:"+System.currentTimeMillis()); //ContextUtil.getContext().getXXX; } public String hello2(Map<String,String> args){ return "/index.jsp"; } public Renderer hello3(Map<String,String> args){ //数据库 Map<String,Object> data = user.outStr(args); return new JspRenderer("/index.jsp",data); } }
package web; import java.sql.SQLException; import java.util.HashMap; import java.util.Map; import tiny.DbUtil; public class UserModel { public Map<String,Object> outStr(Map<String,String> params){ try { //验证,参数转换 Map<String,Object> args = new HashMap(); //访问数据库 Map<String,Object> data = DbUtil.dao.load(this, args); //业务逻辑处理 return data; } catch (SQLException e) { e.printStackTrace(); return null; } } }
jdbc工具类 mvc
这个尚未开发全,model和表的自动映射只作了一个查询。(之后补上),其余的都已经实现。代码以下: oracle
package tiny; import java.sql.Connection; import java.sql.ParameterMetaData; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Statement; import java.sql.Types; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class DbUtil { DataBase instance; //SqlLoader loader; public static final DbUtil dao = new DbUtil(); public DbUtil(){ instance = DataBase.instance(); //loader = SqlLoader.instance(); } public Map<String, Object> load(Object o, Map<String, Object> params) throws SQLException { Connection conn = instance.getConnection(); PreparedStatement stmt = null; ResultSet rs = null; Map<String, Object> result = null; try { stmt = this.prepareStatement(conn, dao.modelConverterSql(o, params)); rs = stmt.executeQuery(); result = this.mapConverter(rs); } finally { try { close(rs); } finally { close(stmt); } instance.release(conn); } return result; } public Map<String, Object> load(String sql, Object[] params) throws SQLException { Connection conn = instance.getConnection(); PreparedStatement stmt = null; ResultSet rs = null; Map<String, Object> result = null; try { stmt = this.prepareStatement(conn, sql); if (params != null) { this.setParams(stmt, params); } rs = stmt.executeQuery(); result = this.mapConverter(rs); } finally { try { close(rs); } finally { close(stmt); } instance.release(conn); } return result; } public List<Map<String, Object>> query(String sql, Object[] params) throws SQLException { Connection conn = instance.getConnection(); PreparedStatement stmt = null; ResultSet rs = null; List<Map<String, Object>> result = null; try { stmt = this.prepareStatement(conn, sql); if (params != null) { this.setParams(stmt, params); } rs = stmt.executeQuery(); result = this.listConverter(rs); } finally { try { close(rs); } finally { close(stmt); } instance.release(conn); } return result; } public int update(String sql, Object[] params) throws SQLException { Connection conn = instance.getConnection(); PreparedStatement stmt = null; int rows = 0; try { stmt = this.prepareStatement(conn, sql); this.setParams(stmt, params); rows = stmt.executeUpdate(); } finally { close(stmt); instance.release(conn); } return rows; } public void setParams(PreparedStatement stmt, Object... params) throws SQLException { if (params == null) { return; } ParameterMetaData pmd = null; pmd = stmt.getParameterMetaData(); if (pmd.getParameterCount() < params.length) { throw new SQLException("Too many parameters: expected " + pmd.getParameterCount() + ", was given " + params.length); } for (int i = 0; i < params.length; i++) { if (params[i] != null) { stmt.setObject(i + 1, params[i]); } else { int sqlType = Types.VARCHAR; try { sqlType = pmd.getParameterType(i + 1); } catch (SQLException e) { } stmt.setNull(i + 1, sqlType); } } } private Map<String, Object> mapConverter(ResultSet rs) throws SQLException { Map<String, Object> result = null; if (rs.next()) { result = new HashMap<String, Object>(); ResultSetMetaData metaData = rs.getMetaData(); for (int i = 1; i <= metaData.getColumnCount(); i++) { String filed = metaData.getColumnName(i); result.put(filed, rs.getObject(filed)); } } return result; } private List<Map<String, Object>> listConverter(ResultSet rs) throws SQLException { List<Map<String, Object>> result = new ArrayList<Map<String, Object>>(); while (rs.next()) { ResultSetMetaData metaData = rs.getMetaData(); Map<String, Object> rowData = null; for (int i = 1; i <= metaData.getColumnCount(); i++) { rowData = new HashMap<String, Object>(); String filed = metaData.getColumnName(i); rowData.put(filed, rs.getObject(filed)); result.add(rowData); } } if (result.size() > 0) { return result; } else { return null; } } private PreparedStatement prepareStatement(Connection conn, String sql) throws SQLException { return conn.prepareStatement(sql); } protected void close(Statement stmt) throws SQLException { if (stmt != null) { stmt.close(); } } protected void close(ResultSet rs) throws SQLException { if (rs != null) { rs.close(); } } private String modelConverterSql(Object o,Map<String, Object> params){ String table = o.getClass().getSimpleName().replace("Model.", "").toLowerCase(); StringBuffer sql = new StringBuffer(); sql.append("select * from "+table+" where 1=1 "); if(params != null){ for(String key : params.keySet()){ Object v = params.get(key); if(v instanceof Integer){ sql.append(" and " + key +"="+ v); }else if(v instanceof String){ sql.append(" and " + key +"='"+v+"'"); }else if(v instanceof String){ //其余未实现 } } } return sql.toString(); } }
链接池 app
我写了简单的链接池,能够默认初始化链接、不够是自增等,还未测试。(等测试后,咱们把代码放到oschina的git上)
这个等我完善后,在细说下。
package tiny; import java.io.IOException; import java.io.InputStream; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.Properties; import java.util.Vector; public class DataBase { private Vector<Connection> pool; private static int init_active = 10; private static int curr_active = 10; private static int max_active = 50; private static DataBase instance = null; private DataBase(){ pool = new Vector<Connection>(); InputStream propStream = DataBase.class.getResourceAsStream("/database.properties"); Properties props = new Properties(); if (propStream != null) { try { props.load(propStream); init_active = Integer.parseInt(props.getProperty("initial.active")); max_active = Integer.parseInt(props.getProperty("max.active")); //for(int c=0;c<init_active;c++){ for(int c=0;c<max_active;c++){ Class.forName(props.getProperty("jdbc.driver")); Connection conn = DriverManager.getConnection(props.getProperty("jdbc.url"),props.getProperty("jdbc.username"),props.getProperty("jdbc.password")); pool.add(conn); } } catch (Exception e) { e.printStackTrace(); } finally { try { propStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } public synchronized void release(Connection conn){ pool.add(conn); } public synchronized void closePool(){ for(int c=0;c<pool.size();c++){ try { pool.get(c).close(); } catch (SQLException e) { e.printStackTrace(); } pool.remove(c); } } public static DataBase instance(){ if(instance == null){ instance = new DataBase(); } return instance; } public synchronized Connection getConnection(){ if(pool.size()>0){ Connection conn = pool.get(0); pool.remove(conn); return conn; }else{ return null; } } }
#jdbc.driver=oracle.jdbc.driver.OracleDriver #jdbc.url=jdbc:oracle:thin:@(DESCRIPTION =(ADDRESS = (PROTOCOL = TCP)(HOST = 127.0.0.1)(PORT = 1521))(LOAD_BALANCE = yes)(CONNECT_DATA = (SERVER = DEDICATED)(SERVICE_NAME = xe))) #jdbc.username=oneteam #jdbc.password=1q2w3e jdbc.driver=org.h2.Driver jdbc.url=jdbc:h2:./h2db/eternal jdbc.username=oneteam jdbc.password=1q2w3e initial.active=10 max.active=50
<%@ page language="java" pageEncoding="UTF-8" contentType="text/html;charset=UTF-8"%> <!DOCTYPE html> <html> <head> <base href="<%=request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+request.getContextPath()+"/"%>"> <title>tiny-瘦成一道隐形闪电</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> </head> <body> <p align="center"> tiny-瘦成一道隐形的闪电 </p> <p align="center"> <% String dd = (String)request.getAttribute("name"); if(dd != null){ out.print(dd); } %> </p> </body> </html>
SqlLoader类
package tiny; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Map; import java.util.Properties; public class SqlLoader { private static SqlLoader instance = null; private Map<String,String> sqls = null; public static SqlLoader instance() { if(instance == null){ instance = new SqlLoader(); } return instance; } private SqlLoader() { InputStream propStream = SqlLoader.class.getResourceAsStream("/sqls.properties"); Properties props = new Properties(); if (propStream != null) { try { props.load(propStream); } catch (IOException e) { e.printStackTrace(); } finally { try { propStream.close(); } catch (IOException e) { e.printStackTrace(); } } sqls = (HashMap<String,String>)(new HashMap(props)); } } @SuppressWarnings("unchecked") protected String get(String key) throws IOException { if(sqls == null){ return null; } return sqls.get(key); } public synchronized void unload(){ this.sqls = null; } }
tiny的开发就是忽然的想法,虽然前先后后加一块儿开发的时间也就1天,可是咱们仍是开发出了不少东西的,实际使用时问题确定是有的,tiny的开发主要想实现我当时的想法“瘦成一道隐形的闪电”,就是代码少的不能在少了,完全0配置,不说你都不知道有action、model啥的(娱乐因素比较多,呵呵),最后的闪电就是tiny虽小,可是功能仍是不少的action、多视图支持、aop、ioc、model充血模型、链接池、jdbc的dao封装等,也算一道小闪电。呵呵。
tiny还有一个就是一直吵吵要增长的java调用前台js的,这个一直没实现,这个在酝酿,不过第一次写时就预留了,看西面代码:
//@WebFilter(urlPatterns = { "/demoAsyncLink" }, asyncSupported = true) @WebFilter(urlPatterns = { "/ty/*" }) public class FrontControl implements Filter{上面注释掉的注解,就是用来实现这个的。