侧边栏壁纸
博主头像
落叶人生博主等级

走进秋风,寻找秋天的落叶

  • 累计撰写 130562 篇文章
  • 累计创建 28 个标签
  • 累计收到 9 条评论
标签搜索

目 录CONTENT

文章目录

31、最简单的mvc框架tiny,增加Ioc,jdbc工具类(1个类),连接池(1个类)

2022-07-03 星期日 / 0 评论 / 0 点赞 / 80 阅读 / 15952 字

Ioc 按照mvc,我们需要把tiny分成3层,其中视图(Renderer抽象类)和Action我们已经在前面实现了,这次我们用最少的代码实现Model。 model沿用Action的想法,用

Ioc

按照mvc,我们需要把tiny分成3层,其中视图(Renderer抽象类)和Action我们已经在前面实现了,这次我们用最少的代码实现Model。

    model沿用Action的想法,用户自定义类,类名必须以Model结尾,同Action一样在初始化时放入Container容器内。model就是数据模型,我们这里充血模型,model的类名默认是同数据库的表名做关联的,即类名去掉Model后(转为小写)为表明,这样一对一映射,有时会简单很多,如保存和查询单个表时,当然了你可以传入复杂sql,返回的结果有基本类型、map、list等。

    model里需要访问数据库时,我们设计了DbUtil工具类,建议在model里使用,当然了这个还是看你,DbUtil本身没有限制。model是通过ioc注入进来的,在你访问这个action前。下面代码中的Container.inject(o);为容器向action中注入model实例。

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的初始化,代码如下:

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几行代码。

模型的使用(数据库连接池还未测试)

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工具类

这个还没有开发全,model和表的自动映射只做了一个查询。(以后补上),其他的都已经实现。代码如下:

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不协调,再说吧)。

连接池

我写了简单的连接池,可以默认初始化连接、不够是自增等,还未测试。(等测试后,我们把代码放到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.Driverjdbc.url=jdbc:h2:./h2db/eternaljdbc.username=oneteamjdbc.password=1q2w3e initial.active=10max.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{



上面注释掉的注解,就是用来实现这个的。


广告 广告

评论区