#
/**
* 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代码。
平时编码时不曾注意的问题,看完这本书后,改进了不少。