昨天的一点小总结:
为什么使用BeanUtils??因为javaBean属性不确定,你根本就不可能知道它是什么,也不知道sql语句是什么,
必须动态的在循环中生成每个对象
注意由于老师课上频繁的修改代码,所以以下代码不过是课堂上的笔记而已,很乱,不能作数的,一切还要以
老师的标准源代码为主(当然即便是老师的代码bug也是不少……)
public class DBUtil
{
public static Object filterValue(Object value)
{
Object obj = value ;
if(value instanceof java.lang.String)
{
cloVal = "'"+value.toString()+"'" ; //拼装sql插入语句的时候还要考虑日期和时间的问题,因为要加上单引号!
}
else if(value instanceof Timestamp)
{}
return obj ;
}
}
public class DBWriter
{
private DBManager dbManager ;
public DBWriter(DBManager dbManager)
{
this.dbManager = dbManager ;
}
public int setData(Connection conn,String sql) throws SQLException
{
int result = -1;
if(sql==null||sql.length==0) return result ;//DBReader最好也作这个校验
PreparedStatement pstmt = null;
boolean needClose = false;
try
{
if(conn==null)
{
conn = dbManager.getConnection();
needClose = true;
}
pstmt = conn.prepareStatement(sql);
result = pstmt.executeUpdate();
}
finally
{
if(needClose)
{
dbManager.release(conn, pstmt, null);
}
else
{
dbManager.release(null,pstmt, null);
}
}
return result; //如果result是-1的话发生异常,如果是0的话,那么是DDL语句
}
public int setData(String sql) throws SQLException
{
return this.setData(null,sql);
}
public int addData(String table , Object obj , boolean autoKey, String keyName) throws SQLException
{
}
public int addData(String table , Object obj) throws SQLException //执行一条insert语句,还可以做成考虑批处理的情况!
{
StringBuffer sql = null ;
sql = new StringBuffer("insert into ").append(table);
//昨天用了BeanUtils将map塞到对象的同名属性中,现在是反过来,根据一个对象得到一个Map
Map map = BeanUtils.describe(obj);//map里面存的就是属性名(键)和属性的值(值)
if(map == null)
{
return -1;
}
Set entry = map.entrySet() ;
Iterator it = entry.iterator();
StringBuffer cols = new StringBuffer("(");
StringBuffer vals = new StringBuffer(" values (");
int count = 0 ;
while(it.hasNext())
{
Map.Entry me = (Map.Entry)it.next();//key里面存的是列名、value里面存的是列值
Object colVal = me.getValue();
if(me.getValue()!=null)
{
if(count == 0)
{
cols.append(me.getKey());
vals.append(DBUtil.filterValue(me.getValue()));
}
else
{
cols.append(", ").append(me.getKey());
vals.append(", ").append(DBUtil.filterValue(me.getValue()));
}
count ++ ;
}
}
if(count != 0)
{
cols.append(") ");
vals.append(") ");
sql.append(cols).append(vals);
return setData(sql.toString()) ; //拼完sql语句调用这个方法!
}
else
{
return -1 ;
}
}
public void modifyData(Object obj)//执行一条update语句
{}
}
=====================================================
课间休息,附上老师的第一节课的源代码如下(并不完整)
package org.mybbs.db;
import java.lang.reflect.InvocationTargetException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.apache.commons.beanutils.BeanUtils;
public class DBWriter {
private DBManager dbManager;
public DBWriter(DBManager dbManager) {
this.dbManager = dbManager;
}
public int setData(Connection conn, String sql) throws SQLException {
int result = -1;
if(sql==null||sql.length()==0) {
return result;
}
PreparedStatement pstmt = null;
boolean needClose = false;
try {
if(conn==null) {
conn = dbManager.getConnection();
needClose = true;
}
pstmt = conn.prepareStatement(sql);
result = pstmt.executeUpdate();
} finally {
if(needClose) {
dbManager.release(conn, pstmt, null);
} else {
dbManager.release(pstmt, null);
}
}
return result;
}
public int setData(String sql) throws SQLException {
return setData(null, sql);
}
/**
* 将一个对象插入到数据库中,用于主键自增的情况
* @param table 对象要插入到哪个表中
* @param obj 要插入的对象
* @param keyName 主键名称
* @return 插入语句影响的行数
* @throws SQLException
*/
public int addData(String table, Object obj, String keyName) throws SQLException {
StringBuffer sql = null;
/*
* 对象中的属性名、属性值
*/
Map map = null;
try {
/*
* 将对象的属性转成Map形式
*/
map = BeanUtils.describe(obj);
//这里尤其需要注意的一点是由于每一个Object都有getClass方法,所以这个describe方法会把obj中
//的所有getter方法都执行,并把取出的值作为值存入map,并将getter方法在get后面的那个名字存为
//map的键!当然这里面也必定包含那个class!在后面的判断中要注意考量这种情况!!!
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(map==null) {
return -1;
}
/*
* 根据属性及其值,生成SQL语句
*/
Set entry = map.entrySet();
Iterator it = entry.iterator();
StringBuffer cols = new StringBuffer("(");
StringBuffer vals = new StringBuffer(" values (");
int count = 0;
while(it.hasNext())
{
Map.Entry me = (Map.Entry)it.next();
if(me.getValue()!=null&&(!me.getKey().equals(keyName)))
{
if(count==0)
{
cols.append(me.getKey());
vals.append(DBUtil.filterValue(me.getValue()));
}
else
{
cols.append(", ")
.append(me.getKey());
vals.append(", ")
.append(DBUtil.filterValue(me.getValue()));
}
count++;
}
}
sql = new StringBuffer("insert into ").append(table);
if(count!=0) {
cols.append(") ");
vals.append(")");
sql.append(cols)
.append(vals);
return setData(sql.toString());
} else {
return -1;
}
}
public int addData(String table, Object obj) throws SQLException {
return addData(table, obj, null);
}
public void modifyData(Object obj) {
}
}
--------------------------
这个类里面的filter方法是用来过滤对象的,根据对象所属的类来
进行相应的业务处理。
package org.mybbs.db;
import java.sql.Timestamp;
public class DBUtil {
public static Object filterValue(Object value) {
Object obj = value;
if(value instanceof String) {
obj = "'"+value.toString()+"'";
} else if(value instanceof Timestamp) {
}
return obj;
}
}
与之对应的不仅有addData插入一个对象的方法,还应该有一个modifyData用来传入一个对象来更新的方法!
===================================================
下午课程开始:
获得单例的方法应该使用同步!
public static DBManager getInstance()
{
if(instance == null)
{
synchronized(DBManager.class)
{
if(instance == null)
{
instance = new DBManager();
}
}
}
return instance ;
}
还可以用静态块:
static
{
instance = new DBManager();
} //这样就不用考虑同步了,直接返回instance即可。
---------------------------
使用properties文件:
在包中加入config.properties(即org.mybbs.db.config),里面仅有一行:
datasource=java:comp/env/jdbc/mybbsDS
public class DBConfig
{
//使用资源包较好,无论properties文件放在哪里都无所谓
private static ResourceBundle dbConfig ;
static
{
dbConfig = ResourceBundle.getBundle("org.mybbs.db.config");//基名
}
public static String getProperty(String key)
{
return dbConfig.getString(key) ;
}
public static String getDataSourceName()
{
return getProperty("datasource");
}
}
这样就可以利用属性文件来修改数据源名称而不用修改代码了!
====================================
下面封装日志:
首先,日志的信息是存在级别问题的,
info:记录一般的程序运行信息
debug:只记录程序在异常时出现的信息
然后,日志记录在哪里?
要么是控制台,要么是文件。
首先新建一个日志包org.mybbs.log:
里面新建一个日志配置文件config.properties:
target=F:/log //表明日志的记录目录 如果写成target=sys.out(就是输出到控制台上去)
target=sys.out //日志输出到标准的控制台中去,且打印的日志信息是info或debug类型的。
level=info,debug
新建一个类:
package org.mybbs.log;
public class Logger //也要做成单例模式
{
private static Logger logger = null ;
private String target = null ;
private String[] level = null ;
private String prefix = "" ;
private String suffix = "log" ;
private boolean configed ;
private boolean isInfoEnabled ;
private boolean isDebugEnabled ;
static
{
logger = new Logger() ;
}
public static logger getInstance()
{
return logger ;
}
public void config()
{
if(configed)
{
return ;
}
ResourceBundle logConfig = ResourceBundle.getBundle("org.mybbs.og.config");
target = logConfig.getString("target");
String levels = logConig.getString("level");
prefix = logConfig.getString("prefix");
suffix = logConfig.getString("suffix");
level = levels.split(",");
for(int i = 0 ; i < level.length ; i ++)
{
if("info".equalsIgnoreCase(level[i].trim()))
{
isInfoEnabled = true ;
}
else if("debug".equalsIgnoreCase(level[i].trim()))
{
isDebugEnabled = true ;
}
}
}
public void info(String msg)
{
if(!isInfoEnabled)
return ;
print(msg) ;
}
public void debug(String msg)
{
if(!isDebugEnabled)
return ;
print(msg);
}
protected void print(String msg) throws IOException
{
//DateFormat dtf = new SimpleDateFormat("yyyyMMddHHmmss") ;
DateFormat dtf = new SimpleDateFormat("yyyyMMdd") ;
OutputStream out = null
if("sys.out".equalsIgnoreCase(target.trim()))
{
out = System.out ;
}
else if("sys.err".equalsIgnoreCase(target.trim()))
{
out = System.err ;
}
else
{
//prefix和suffix是前缀名和后缀名
out = new FileOutputStream(target+"/"+prefix+"-"+dtf.format(new Date())+"."+suffix,true) ;
//注意:后面的这个true实际是OutputStream中的append属性,设为true则在相同的文件中不会覆盖前面的内容
}
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") ;
msg = df.format(new Date()) + " " + msg ;//让日志输出的信息里面含有年月日时分秒!
out.write(msg.getBytes());
out.close() ;
}
}
========================================================
我今天的精神很不好,和昨天一样……上面记录的代码错误很多,还是看下面老师的代码吧:
当然在此之前,还是要先整理一下数据表,比如实体:
users(用户)、sections(版块)、roles(角色)、privilege(权限)、
老师的封装日志源代码如下:
首先自然是要创建出一个属性文件,由于我们还没有讲xml的解析过程,所以日志信息暂时不放在xml里面。
config.properties文件:
target=sys.out
suffix=log
prefix=mybbs
perType=day
level=info,debug
------------------------
然后就是封装日志类,就像今天说的一样,日志最重要的是两点:1是日志的各个级别,2是日志输出的地点,
应该保证该日志类可以读取上面的配置文件的信息,把里面最重要的target(日志输出地点)和level(日志信息级别)
两个东西提取出来,然后根据级别制定相应的方法,有几个级别就制定几个方法,该方法的目的都是一样的,按照
对应的级别输出日志里面的信息。在读取配置信息的时候使用了资源包的方式而不是属性类里面的方法,这样作的好处是:
配置文件可以随意放在工程中的任意位置,如果使用属性类的方法,要求必须属性配置文件和调用类在同一个包里面。
package org.mybbs.log;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.ResourceBundle;
public class Logger {
//这里初始化日志中的各种信息
private static Logger logger = null;//Logger类的实例,本类采用单例模式
private String target = null; //target表明日志存储的位置
private String[] level = null; //level字符串数组中存储着日志的各个级别
private String prefix = ""; //最后生成日志的前缀名,是自己根据情况添加的
private String suffix = "log";//最后生成的日志的后缀名
private boolean configed; //一般情况下,日志实例只需要读取一次属性文件即可,该布尔值判断是否读取过属性文件。
private boolean isInfoEnabled;//日志的Info级别是否可用,其实只要属性文件中的level中指明的就可以使用
private boolean isDebugEnabled;//日志的debug级别是否可用
static {
logger = new Logger();//使用静态块制造对象,类加载的时候就会调用它,它仅仅就调用一次,所以保证了私有静态Logger对象的唯一性。
}
private Logger(){}
public static Logger getInstance() {
return logger; //这个没什么好说的了,返回唯一的那个私有静态Logger对象。
}
public void config() {
if(configed) { //这个config()方法应该仅仅被调用一次而已,第二次configed的值就被设为true了。
return;
}
ResourceBundle logConfig = ResourceBundle.getBundle("org.mybbs.log.config");
//利用资源包的方式定位配置文件
target = logConfig.getString("target");//getString方法取得相应的键值,然后赋给初始变量
String levels = logConfig.getString("level");
prefix = logConfig.getString("prefix");
suffix = logConfig.getString("suffix");
level = levels.split(",");
for(int i=0; i<level.length; i++) {
//System.out.println(level[i]); //下面将level中指明的级别设为可用
if("info".equalsIgnoreCase(level[i].trim())) {
isInfoEnabled = true;
} else if("debug".equalsIgnoreCase(level[i].trim())) {
isDebugEnabled = true;
}
}
configed = true ;
}
public void info(String msg) { //只有info级别可用时才调用这个方法
if(!isInfoEnabled) return;
msg = "INFO : " + msg;
print(msg);
}
public void debug(String msg){ //只有debug级别可用时才调用这个方法
if(!isDebugEnabled) return;
msg = "DEBUG : " + msg;
print(msg);
}
protected void print(String msg) { //由于两个级别的输出代码的过程完全一样,所以单独提出来弄一个方法
DateFormat dtf = new SimpleDateFormat("yyyyMMdd");
OutputStream out = null;
boolean needClose = false;
try {
if("sys.out".equalsIgnoreCase(target.trim())) {
out = System.out;
} else if("sys.err".equalsIgnoreCase(target.trim())) {
out = System.err;
} else {
out = new FileOutputStream(target+"/"+prefix+"-"+dtf.format(new Date())+"."+ suffix, true);
needClose = true;
}
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
msg = df.format(new Date()) + " " + msg;
out.write(msg.getBytes());
out.write(System.getProperty("line.separator").getBytes());
out.flush();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
if(out!=null) {
out.close();
out = null;
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
----------------------------------------------
这就可以在类中使用上面封装的日志了,在DBWriter类中使用封装日志的代码如下:
package org.mybbs.db;
import java.lang.reflect.InvocationTargetException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.mybbs.log.Logger;
import org.apache.commons.beanutils.BeanUtils;
public class DBWriter {
private DBManager dbManager;
public DBWriter(DBManager dbManager) {
this.dbManager = dbManager;
}
public int setData(Connection conn, String sql) throws SQLException {
Logger log = Logger.getInstance();
log.config();
log.info(sql); //注意这三行代码,千万不要拉掉那个log.config()!!!
int result = -1;
if(sql==null||sql.length()==0) {
return result;
}
PreparedStatement pstmt = null;
boolean needClose = false;
try {
if(conn==null) {
conn = dbManager.getConnection();
needClose = true;
}
pstmt = conn.prepareStatement(sql);
result = pstmt.executeUpdate();
} catch(Exception e){
log.debug(e.toString());
} finally {
if(needClose) {
dbManager.release(conn, pstmt, null);
} else {
dbManager.release(pstmt, null);
}
}
return result;
}
public int setData(String sql) throws SQLException {
return setData(null, sql);
}
/**
* 将一个对象插入到数据库中,用于主键自增的情况
* @param table 对象要插入到哪个表中
* @param obj 要插入的对象
* @param keyName 主键名称
* @return 插入语句影响的行数
* @throws SQLException
*/
public int addData(String table, Object obj, String keyName) throws SQLException {
StringBuffer sql = null;
/*
* 对象中的属性名、属性值
*/
Map map = null;
try {
/*
* 将对象的属性转成Map形式
*/
map = BeanUtils.describe(obj);
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(map==null) {
return -1;
}
/*
* 根据属性及其值,生成SQL语句
*/
Set entry = map.entrySet();
Iterator it = entry.iterator();
StringBuffer cols = new StringBuffer("(");
StringBuffer vals = new StringBuffer(" values (");
int count = 0;
while(it.hasNext()) {
Map.Entry me = (Map.Entry)it.next();
if(me.getValue()!=null&&(!me.getKey().equals(keyName))&&(!me.getKey().equals("class"))) {
if(count==0) {
cols.append(me.getKey());
vals.append(DBUtil.filterValue(me.getValue()));
} else {
cols.append(", ")
.append(me.getKey());
vals.append(", ")
.append(DBUtil.filterValue(me.getValue()));
}
count++;
}
}
sql = new StringBuffer("insert into ").append(table);
if(count!=0) {
cols.append(") ");
vals.append(")");
sql.append(cols)
.append(vals);
return setData(sql.toString());
} else {
return -1;
}
}
public int addData(String table, Object obj) throws SQLException {
return addData(table, obj, null);
}
public void modifyData(Object obj) {
}
}
------------------------------------------
还有最后,老师的测试DBWriter的用例!
package org.mybbs.db;
import java.sql.SQLException;
import junit.framework.TestCase;
public class DBWriterTest extends TestCase {
DBWriter target = null;
TestBean bean;
public static void main(String[] args) {
junit.textui.TestRunner.run(DBWriterTest.class);
}
protected void setUp() throws Exception {
super.setUp();
target = DBManager.getInstance().getDBWriter();
bean = new TestBean();
bean.setId(10);
bean.setIp("12322323");
}
protected void tearDown() throws Exception {
super.tearDown();
}
/*
* Test method for 'org.mybbs.db.DBWriter.addData(String, Object, String)'
*/
public void testAddDataStringObjectString() {
try {
assertEquals(target.addData("ips", bean, "id"), 1);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
http://bbs1.greedland.net/topic27_topicId903252_forumId41_sortId0_enterSortId0_forumPage1.html