3一、最簡單的mvc框架tiny,增長Ioc,jdbc工具類(1個類),鏈接池(1個類)

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);



Container.inject代碼以下:
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類,而後實例化,注入到這個action的屬性。

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);
					}
				}



同action幾乎同樣,這裏不細說。咱們看到增長model模型,咱們沒有增長一個類,只是增長1個方法,和10幾行代碼。

模型的使用(數據庫鏈接池還未測試) 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);
	}
}



model類
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();
	}
}



我把查詢的結果自動轉化爲map或list<map>,其中modelConverterSql爲「 model和表的自動映射只作了一個查詢」,很簡單的,其餘的增刪改查我會補上。其中註釋掉的「SqlLoader」,想把sql保存到文件裏,而後用這個來讀取。最下面有這個類的代碼,也沒有開發完就是思路雛形。(這個我不想在完善了,原本tiny就像想簡單,感受分開sql了,反而會和tiny不協調,再說吧)。

鏈接池 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



測試action 的index.jsp

<%@ 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{
上面註釋掉的註解,就是用來實現這個的。
相關文章
相關標籤/搜索