文档章节

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

青青小树
 青青小树
发布于 2014/04/11 23:01
字数 2041
阅读 793
收藏 26

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.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{



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


© 著作权归作者所有

青青小树

青青小树

粉丝 74
博文 110
码字总数 33227
作品 4
长春
程序员
私信 提问
加载中

评论(3)

青青小树
青青小树 博主
10不敢
随风流逝de昨天
真不敢想象,简单的东西反而需要抽象,79,不简单。
青青小树
青青小树 博主
13
spring boot框架学习学前掌握之重要注解(1)-sprng的java配置方式

本节主要内容: 1:重点注解介绍 2:使用重点注解环境搭建 声明: 本文是《凯哥陪你学系列-框架学习之spring boot框架学习》中学前掌握之重要注解(1) java配置是spring 4.x推荐的撇嘴方式。可以...

中凯_凯哥java
2017/10/13
78
1
Hibernate Spring 面试题

关于PreparedStatement和Statement具体区别 (1) PreparedStatement是,而Statement则,在DBMS中处理管理中,而PreparedStatement则不要。(2) PrepareStatement中执行的SQL语句中是,而。比如...

陶邦仁
2014/12/21
320
0
spring 3.2 各jar包的简单介绍

1.spring-aop:面向切面AOP编程中需要使用。声明式事物也用到此包。 2.spring-aspects:提供对AspectJ的支持,以便可以方便的将面向方面的功能集成进IDE中,比如Eclipse AJDT。 3.spring-bea...

40岁的青春
2015/08/11
52
0
SherlockHolmnes/Mars-java

一个来自火星的框架 我是谁 Mars-java是一个不需要容器的javaWeb开发框架,以netty作http服务管理,支持AOP,IOC,MVC,并且集成了Mybatis作为持久层,除此之外还提供了Mars-config 来支撑远程配...

SherlockHolmnes
04/21
0
0
Spring(二):配置和简单使用

1、下载地址(目前使用的是4.2.0) 下面都可以 http://repo.springsource.org/libs-release-local/org/springframework/spring http://repo.spring.io/simple/libs-release-local/org/sprin......

_Roger_
2015/08/16
275
0

没有更多内容

加载失败,请刷新页面

加载更多

centos 查看删除旧内核

1、查看系统中安装的内核 $ yum list installed | grep kernel 2、删除系统中旧内核 $ yum install yum-utils$ package-cleanup --oldkernels --count=2...

编程老陆
56分钟前
8
0
ES6

ES6:不改变原理的基础上,让API变得更简单 一、let:代替var用于声明变量 1、var的缺点: (1)声明提前 (2)没有块级作用域 2、let的优点: (1)组织了申明提前 (2)让let所在的块({}),...

wytao1995
今天
3
0
kubernetes 环境搭建 —— minikube

创建集群 minikube start 搭建好 k8s 集群后,可以查看集群的状态以及部署应用。主要用到的是 k8s 的 api,这通常需借助于 kutectl 命令行工具 基本操作 kubectl versionkubectl cluster-i...

lemos
今天
10
0
关于js混淆与反混淆还原操作

使用js的混淆加密,其目的是为了保护我们的前端代码逻辑,对应一些搞技术吃饭的公司来说,为了防止被竞争对手抓取或使用自己的代码,就会考虑如何加密,或者混淆js来达到代码保护。 1、为什么...

开源oschina
今天
12
0
用盛金公式解三次方程(ansi c版)

/* cc cubic.c -lm gcc cubic.c -lm Shengjin's Formulas Univariate cubic equation aX ^ 3 + bX ^ 2 + cX + d = 0, (a, b, c, d < R, and a!= 0). Multiple root disc......

wangxuwei
今天
9
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部