#
/**
* Second scenario:transaction is rare
* we control connection inside service classes.
*/
/**
* -----ConnectionManager.class---------
*/
public static Connection getConnection()
{
return getConnection(ModuleConfig.getDefaultJndi());
}
public static Connection getConnection(final String jndi)
{
Connection conn = null;
try
{
DataSource ds = dsMap.get(jndi);
if(ds==null) return null;
conn = ds.getConnection();
conn.setAutoCommit(true);
}
catch(SQLException sqle)
{
SysLogger.error("Database fail to get connection 1",sqle);
}
catch(Exception sqle)
{
SysLogger.error("Database fail to get connection 2",sqle);
}
return conn;
}
public static void rollback(Connection conn)
{
try
{
if(conn==null || conn.isClosed())
return;
if(!conn.getAutoCommit())
conn.rollback();
}
catch(SQLException se)
{
SysLogger.error("Can not do rollback operation.",se);
}
}
}
/**
* -----ActionServlet.class---------
*/
private void processHttpRequest(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException
{
response.setContentType("text/html;charset=GB2312");
request.setCharacterEncoding("GB2312");
String beanId = extractBeanID(request.getRequestURI());
String methodName = request.getParameter("method");
String targetJsp = null;
if(beanId==null || methodName==null)
{
request.setAttribute(EXCEPTION_MESSAGE,"請求URI錯誤.");
forward(request,response,targetJsp);
return;
}
BaseAction ba = BeanFactory.newAction(beanId);
BaseService bs = BeanFactory.newService(beanId);
if(ba==null || bs == null)
{
request.setAttribute(EXCEPTION_MESSAGE,"沒有Bean為" + beanId + "的action或service");
forward(request,response,targetJsp);
return;
}
ActionAnnotation ann = AnnotationExtractor.getAnnotation(ba.getClass(), methodName);
ba.setRequest(request);
ba.setService(bs);
Method method = SysUtil.lookupMethod(ba.getClass().getMethods(),methodName);
Connection conn = null;
if(ann.isNeedDB())
{
conn = ConnectionManager.getConnection();
bs.setConnection(conn);
bs.setDao(BeanFactory.newDao(beanId,conn));
}
if(method!=null)
{
try
{
targetJsp = (String)method.invoke(ba);
}
catch(Exception e)
{
SysLogger.error("Error:" + bs.getClass().getName() + "." + method.getName(),e);
targetJsp = null;
}
}
if(ann.isNeedDB())
ConnectionManager.close(conn);
forward(request,response,targetJsp);
}
/**
* example:method in service class
* operating conncetion in service
*/
/**
* 這是兩個dao實現一個事處的最好例子
*/
public void addTop(MenuDto dto) throws Exception
{
Connection conn = getConnection();
try
{
conn.setAutoCommit(false);
MenuDao mDao = new MenuDao(conn);
MenuRoleDao mrDao = new MenuRoleDao(conn);
MenuDto menu = mDao.getNextMenu();
menu.setTitle(dto.getTitle());
mDao.save(menu);
mrDao.saveMenu(menu.getId());
conn.commit();
}
catch(Exception e)
{
ConnectionManager.rollback(conn);
throw e;
}
}
/**
* First scenario:transaction is often used in the system
* we control connection outside service classes.
*/
/**
* -----ConnectionManager.class---------
*/
public static Connection getConnection()
{
return getConnection(ModuleConfig.getDefaultJndi(),true);
}
public static Connection getConnection(final boolean auto)
{
return getConnection(ModuleConfig.getDefaultJndi(),auto);
}
public static Connection getConnection(final String jndi,final boolean auto)
{
Connection conn = null;
try
{
DataSource ds = dsMap.get(jndi);
if(ds==null) return null;
conn = ds.getConnection();
conn.setAutoCommit(auto);
}
catch(SQLException sqle)
{
SysLogger.error("Database fail to get connection 1",sqle);
}
catch(Exception sqle)
{
SysLogger.error("Database fail to get connection 2",sqle);
}
return conn;
}
public static void rollback(Connection conn)
{
try
{
if(conn==null || conn.isClosed())
return;
if(!conn.getAutoCommit())
conn.rollback();
}
catch(SQLException se)
{
SysLogger.error("Can not do rollback operation.",se);
}
}
}
/**
* -----ActionServlet.class---------
*/
private void processHttpRequest(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException
{
response.setContentType("text/html;charset=GB2312");
request.setCharacterEncoding("GB2312");
String beanId = extractBeanID(request.getRequestURI());
String methodName = request.getParameter("method");
String targetJsp = null;
if(beanId==null || methodName==null)
{
request.setAttribute(EXCEPTION_MESSAGE,"請求URI錯誤.");
forward(request,response,targetJsp);
return;
}
BaseAction ba = BeanFactory.newAction(beanId);
BaseService bs = BeanFactory.newService(beanId);
if(ba==null || bs == null)
{
request.setAttribute(EXCEPTION_MESSAGE,"沒有Bean為" + beanId + "的action或service");
forward(request,response,targetJsp);
return;
}
ActionAnnotation ann = AnnotationExtractor.getAnnotation(ba.getClass(), methodName);
ba.setRequest(request);
ba.setService(bs);
Method method = SysUtil.lookupMethod(ba.getClass().getMethods(),methodName);
Connection conn = null;
if(ann.isNeedDB())
{
/**
* -----get connection and set autoCommit to false---------
*/
conn = ConnectionManager.getConnection(false);
bs.setConnection(conn);
bs.setDao(BeanFactory.newDao(beanId,conn));
}
if(method!=null)
{
try
{
targetJsp = (String)method.invoke(ba);
/**
* -----if method is executed successfully,commit connection---------
*/
if(ann.isNeedDB()) conn.commit();
}
catch(Exception e)
{
SysLogger.error("Error:" + bs.getClass().getName() + "." + method.getName(),e);
/**
* connection rollback when run into exception
*/
if(ann.isNeedDB()) ConnectionManager.rollback(conn);
targetJsp = null;
}
}
if(ann.isNeedDB())
ConnectionManager.close(conn);
forward(request,response,targetJsp);
}
/**
* example:method in service
* there has not code for operating conncetion
*/
public void addTop(MenuDto dto) throws Exception
{
Connection conn = getConnection();
MenuDao mDao = new MenuDao(conn);
MenuRoleDao mrDao = new MenuRoleDao(conn);
MenuDto menu = mDao.getNextMenu();
menu.setTitle(dto.getTitle());
mDao.save(menu);
mrDao.saveMenu(menu.getId());
}
摘要: package afu.framework;
import java.sql.Connection;
import java.lang.reflect.Constructor;
import afu.framework.service.*;
import afu.framework.action.*;
import af...
閱讀全文
perfect DAO solution
------BaseDao------
public abstract class BaseDao
{
private static final int maxRow = 1000;
protected Connection conn;
protected String table;
protected Class<? extends DtoInterface> dtoClass;
protected JspPage jspPage;
protected boolean insideConnection;
public BaseDao(Connection conn)
{
init();
if(conn==null)
{
this.conn = ConnectionManager.getConnection();
insideConnection = true;
}
else
{
this.conn = conn;
insideConnection = false;
}
}
public BaseDao()
{
init();
this.conn = ConnectionManager.getConnection();
insideConnection = true;
}
public void close(Statement stmt,ResultSet rs)
{
try
{
if(rs!= null)
rs.close();
if(stmt!=null)
stmt.close();
/**
* if the connection is passed from outside
* do not close it.
*/
if(insideConnection)
ConnectionManager.close(conn);
}
catch(SQLException se)
{
}
}
protected abstract void init();
}
------sub dao class example------
public class ProducerDao extends BaseDao
{
public ProducerDao(Connection conn)
{
super(conn);
}
protected void init()
{
super.dtoClass = ProducerDto.class;
super.table = "nms_producer";
}
}
------client code-----
For the first scenario
ProducerDao dao = new ProducerDao(null);
or ProducerDao dao = (ProducerDao)BeanFactory.newDao("producer");
dao.method();
For the second scenario
Connection conn = ConnectionManager.createConnection();
ProducerDao dao1 = new ProducerDao(conn);
AnOtherDao dao2 = new AnOtherDao(conn);
dao1.method1();
dao2.method2();
dao2.method3();
ConnectionManager.close(conn);
or Connection conn = ConnectionManager.createConnection();
ProducerDao dao = (ProducerDao)BeanFactory.newDao("producer",conn);
AnOtherDao dao = (AnOtherDao)BeanFactory.newDao("another",conn);
dao1.method1();
dao2.method2();
dao2.method3();
ConnectionManager.close(conn);

在SourceView1.0中,采集層的對象和表現層的對象經常會混在一起,搞得很
亂。而且因為對象的不確定性給系統維護帶來很大困難。
所以在SourceView2.0的設計中,我特地把這兩部分分開,分別放在mvc和nms
這兩個包中。
雖然只是簡單地分為兩個package,但卻標志著設計思想的一大進步。
現在J2SE 5.0提供了靜態導入的功能,你只需要在import關鍵字后面寫一個static關鍵字就可以直接
使用類中定義的常量了,例如
import static afu.framework.util.Constant.CURRENT_USER;
import static afu.framework.util.Constant.EXCEPTION_MESSAGE;
public String login()

{
String userId = getParaValue("userid");
String password = getParaValue("password");
String remoteIp = request.getRemoteAddr();
UserDto dto = ((SysService)service).login(userId, password, remoteIp);
if(dto==null)

{
request.setAttribute(EXCEPTION_MESSAGE,"用戶名或密碼不對");
return null;
}
request.setAttribute(CURRENT_USER,dto);
return "/common/index.jsp";
}

而沒有這個功能之前,我們得這么寫
request.setAttribute(Constant.EXCEPTION_MESSAGE,"用戶名或密碼不對");
利用反射構成SQL語句,這樣,對于一般表的CURD,都可快速實現。
protected String buildInsertSQL(ResultSetMetaData rsm,DtoInterface dto)

{
String insertSql = null;
try

{
StringBuffer sqlBuf = new StringBuffer(50);
StringBuffer valueBuf = new StringBuffer(50);
sqlBuf.append("insert into ").append(table).append("(");
for(int i=1;i<=rsm.getColumnCount();i++)

{
String methodName = "get" + rsm.getColumnName(i).replaceAll("_", "");
Method method = lookupMethod(dtoClass.getMethods(), methodName);
if(method==null)

{
SysLogger.debug("get" + rsm.getColumnName(i) + " does not exist");
continue;
}
sqlBuf.append(rsm.getColumnName(i)).append(",");
valueBuf.append("'").append(method.invoke(dto)).append("',");
}
sqlBuf.delete(sqlBuf.length() - 1, sqlBuf.length());
valueBuf.delete(valueBuf.length() - 1, valueBuf.length());
sqlBuf.append(")values(").append(valueBuf.toString()).append(")");
insertSql = sqlBuf.toString();
SysLogger.debug(insertSql);
}
catch(Exception e)

{
SysLogger.error("BaseDao.buildInsertSQL()",e);
}
return insertSql;
}
protected String buildUpdateSQL(ResultSetMetaData rsm,DtoInterface dto)

{
String updateSql = null;
try

{
Method getId = lookupMethod(dtoClass.getMethods(),"getId");
if(getId==null)

{
SysLogger.error(dtoClass.getClass().getName() + ":getId method does not exist");
return null;
}
StringBuffer sqlBuf = new StringBuffer(100);
sqlBuf.append("update ").append(table).append(" set ");
for(int i=1;i<=rsm.getColumnCount();i++)

{
if(rsm.getColumnName(i).equals("id")) continue;
String methodName = "get" + rsm.getColumnName(i).replaceAll("_", "");
Method method = lookupMethod(dtoClass.getMethods(), methodName);
if(method==null)

{
SysLogger.debug("get" + rsm.getColumnName(i) + " does not exist");
continue;
}
sqlBuf.append(rsm.getColumnName(i)).append("='");
sqlBuf.append(method.invoke(dto)).append("',");
}
sqlBuf.delete(sqlBuf.length() - 1, sqlBuf.length());
sqlBuf.append(" where id='").append(getId.invoke(dto)).append("'");
updateSql = sqlBuf.toString();
SysLogger.debug(updateSql);
}
catch(Exception e)

{
SysLogger.error("BaseDao.buildUpdateSQL()",e);
}
return updateSql;
}
今天試了一下用反射從ResultSet 提取數據,然后調用相應的dto的方法。
這樣就不要每次都針對一個新表來寫一次extractData方法了,挺爽的。
缺點就是數據表中的字段與dto的方法必須一一對應。

/** *//**
* extract data from ResultSet to dto
*/
protected DtoInterface extractData(ResultSet rs) throws Exception

{
if(dtoClass == null)
throw new NullPointerException("dtoClass is not setted!");
DtoInterface dto = dtoClass.newInstance();
ResultSetMetaData rsm = rs.getMetaData();
for(int i=1;i<=rsm.getColumnCount();i++)

{
String methodName = "set" + rsm.getColumnName(i).replaceAll("_", "");
SysLogger.debug("[" + rsm.getColumnName(i) + "]=" + rsm.getColumnType(i) + ",method=" + methodName);
Method method = lookupMethod(dtoClass.getMethods(), methodName);
if(method==null)

{
SysLogger.error("set" + rsm.getColumnName(i) + " does not exist");
continue;
}
if(rsm.getColumnType(i)==Types.INTEGER)
method.invoke(dto,rs.getInt(i));
else if(rsm.getColumnType(i)==Types.VARCHAR)
method.invoke(dto,rs.getString(i));
}
return dto;
}
protected Method lookupMethod(Method[] methods,String methodName)

{
Method result = null;
for(Method method:methods)

{
if(method.getName().equalsIgnoreCase(methodName))

{
result = method;
break;
}
}
return result;
}
摘要: html中的selectBox也是令我頭疼的東西,因為它總和數據庫關聯,但我們在jsp中又不能直接調用dao,
就算直接調用了dao,jsp中的代碼也是一團亂。所以我專門寫了這個類來解決這個問題。
我們只要專一個list給它,并告訴哪個方法可以得到key,哪個方法可以得到value,
就能生成一個selectBox。
package afu.framework.util;
...
閱讀全文
之前的架構都沒有service這一層,jsp到manager(action),然后在manager中調用dao。
Action其實屬于web這一層,在web層直接調用dao是不妥的,所以新架構中多了一層
Service。Service位于action和dao之間,action把從jsp中傳來的參數封裝好傳給dao。
我覺得最大好處就是不會在調用dao的同時又看到一大堆request.getParameter代碼。

平時編碼時不曾注意的問題,看完這本書后,改進了不少。