專案中的一個AOP的編寫案例(配置+案例)
AOP和Spring事務處理2008年05月01日 星期四 00:40二. AOP
1. AOP是什麼?
AOP是OOP的延續,是Aspect Oriented Programming的縮寫,意思是面向方面程式設計。AOP實際是GoF設計模式的延續,設計模式孜孜不倦追求的是呼叫者和被呼叫者之間的解耦,AOP可以說也是這種目標的一種實現。
2. 切面意義何在?
就可以在這層切面上進行統一的集中式許可權管理。而業務邏輯元件則無需關心許可權方面的問題。也就是說,通過切面,我們可以將系統中各個不同層次上的問題隔離開來,實現統一集約式處理。各切面只需集中於自己領域內的邏輯實現。這一方面使得開發邏輯更加清晰,專業化分工更加易於進行;另一方面,由於切面的隔離,降低了耦合性,我們就可以在不同的應用中將各個切面組合使用,從而使得程式碼可重用性大大增強。
3. AOP應用範圍
Authentication 許可權
Caching 快取
Context passing 內容傳遞
Error handling 錯誤處理
Lazy loading 懶載入
Debugging 除錯
logging, tracing, profiling and monitoring 記錄跟蹤 優化 校準
Performance optimization 效能優化
Persistence 持久化
Resource pooling 資源池
Synchronization 同步
Transactions 事務
applicationContext.xml配置:
<?xml version=”1.0″ encoding=”UTF-8″?>
<beans xmlns=”http://www.springframework.org/schema/beans“
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xmlns:context=”http://www.springframework.org/schema/context“
xmlns:tx=”http://www.springframework.org/schema/tx” xmlns:aop=”http://www.springframework.org/schema/aop“
xsi:schemaLocation=”http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd“>
<!– setting annotation –>
<context:annotation-config />
<!– auto proxy configuration –>
<!– 啟動對@Aspect–>
<aop:aspectj-autoproxy />
<!–
scan annotation for @Controller(action), @Service(service),
@Repository(dao)
–>
<context:component-scan base-package=”cn.com” />
<!– 屬性檔案讀入 –>
<bean id=”propertyConfigurer”
class=”org.springframework.beans.factory.config.PropertyPlaceholderConfigurer”>
<property name=”locations”>
<list>
<value>classpath:jdbc.properties</value>
</list>
</property>
</bean>
<!– pls config the parameter for c3p0 setting –>
<bean id=”dataSource” class=”com.mchange.v2.c3p0.ComboPooledDataSource”
destroy-method=”close”>
<!– c3p0 type –>
<property name=”driverClass” value=”${jdbc.driverClass}” />
<property name=”jdbcUrl” value=”${jdbc.jdbcUrl}” />
<property name=”user” value=”${jdbc.user}” />
<property name=”password” value=”${jdbc.password}” />
<!– 連線池中保留的最小連線數 –>
<property name=”minPoolSize” value=”${c3p0.minPoolSize}” />
<!–連線池中保留的最大連線數。Default: 15 –>
<property name=”maxPoolSize” value=”${c3p0.maxPoolSize}” />
<!–初始化時獲取的連線數,取值應在minPoolSize與maxPoolSize之間。Default: 3 –>
<property name=”initialPoolSize” value=”${c3p0.initialPoolSize}” />
<!–最大空閒時間,60秒內未使用則連線被丟棄。若為0則永不丟棄。Default: 0 –>
<property name=”maxIdleTime” value=”${c3p0.maxIdleTime}” />
<!–當連線池中的連線耗盡的時候c3p0一次同時獲取的連線數。Default: 3 –>
<property name=”acquireIncrement” value=”${c3p0.acquireIncrement}” />
<!–
JDBC的標準引數,用以控制資料來源內載入的PreparedStatements數量。但由於預快取的statements
屬於單個connection而不是整個連線池。所以設定這個引數需要考慮到多方面的因素。
如果maxStatements與maxStatementsPerConnection均為0,則快取被關閉。Default: 0
–>
<property name=”maxStatements” value=”${c3p0.maxStatements}” />
<!–每60秒檢查所有連線池中的空閒連線。Default: 0 –>
<property name=”idleConnectionTestPeriod” value=”${c3p0.idleConnectionTestPeriod}” />
<!–定義在從資料庫獲取新連線失敗後重復嘗試的次數。Default: 30 –>
<property name=”acquireRetryAttempts” value=”${c3p0.acquireRetryAttempts}” />
<!–
獲取連線失敗將會引起所有等待連線池來獲取連線的執行緒丟擲異常。但是資料來源仍有效
保留,並在下次呼叫getConnection()的時候繼續嘗試獲取連線。如果設為true,那麼在嘗試
獲取連線失敗後該資料來源將申明已斷開並永久關閉。Default: false
–>
<property name=”breakAfterAcquireFailure” value=”${c3p0.breakAfterAcquireFailure}” />
<!–
因效能消耗大請只在需要的時候使用它。如果設為true那麼在每個connection提交的
時候都將校驗其有效性。建議使用idleConnectionTestPeriod或automaticTestTable
等方法來提升連線測試的效能。Default: false
–>
<property name=”testConnectionOnCheckout” value=”${c3p0.testConnectionOnCheckout}” />
</bean>
<bean id=”sessionFactory”
class=”org.springframework.orm.hibernate4.LocalSessionFactoryBean”>
<property name=”dataSource” ref=”dataSource”>
</property>
<property name=”hibernateProperties”>
<props>
<!–
<prop
key=”hibernate.dialect”>org.hibernate.dialect.MySQLDialect</prop>
–>
<prop key=”hibernate.dialect”>org.hibernate.dialect.OracleDialect</prop>
<prop key=”hibernate.show_sql”>true</prop>
<prop key=”hibernate.temp.use_jdbc_metadata_defaults”>false</prop>
<prop key=”hibernate.hbm2ddl.auto”>update</prop>
<prop key=”javax.persistence.validation.mode”>none</prop>
<!– default 10 –>
<prop key=”hibernate.jdbc.fetch_size”>50</prop>
<prop key=”hibernate.jdbc.batch_size”>30</prop>
<prop key=”hibernate.connection.autocommit”>true</prop>
<!–
ON_CLOSE:Hibernate session在第一次需要進行JDBC操作的時候獲取連線,然後
持有他,直到session關閉。不鼓勵使用
AFTER_TRANSACTION:在org.hibernate.Transaction結束後釋放連線。這一個不應該在JTA環境下使用。
AFTER_STATEMENT:(也被稱做積極釋放),在每一條語句被執行後就釋放連線。
–>
<prop key=”hibernate.connection.release_mode”>after_transaction</prop>
</props>
</property>
<property name=”packagesToScan”>
<list>
<value>cn.com.css.misps.domain</value>
</list>
</property>
</bean>
<!– Transaction configuration–>
<bean id=”txManager”
class=”org.springframework.orm.hibernate4.HibernateTransactionManager”>
<property name=”sessionFactory” ref=”sessionFactory” />
</bean>
<!– auto transaction manager configuration –>
<tx:annotation-driven transaction-manager=”txManager” />
<!– 引入web Service的定義xml –>
<import resource=”graph.xml” />
</beans>
這裡是要做aop的一個類:
package cn.com.css.misps.graph.service.impl;
import java.util.Date;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import cn.com.css.misps.domain.TCoGraph;
import cn.com.css.misps.graph.dao.ITCoGraphDao;
import cn.com.css.misps.graph.dao.ITProductLDao;
import cn.com.css.misps.graph.dao.ITTaskStateDao;
import cn.com.css.misps.graph.dao.impl.TCoGraphDaoImpl;
import cn.com.css.misps.graph.service.ITCoGraphService;
import cn.com.css.misps.graph.util.ProductLUtils;
/**
* @brief ITCoGraphServiceImpl.java 操作流程配置的介面
* @attention
* @author 塗作權
* @date 2013-9-23
* @note begin modify by null
*/
@Transactional
@Service(“iTCoGraphService”)
public class TCoGraphServiceImpl extends TCoGraphDaoImpl implements ITCoGraphService {
@Resource
private ITCoGraphDao tCoGraphDao;
@Resource(name = “iTTaskStateDao”)
private ITTaskStateDao taskStateDao;
@Resource(name = “iTProductLDao”)
private ITProductLDao productLDao;
/**
* rief 獲得圖形制作的引數
*
* @return
* @attention 通過
* @author 塗作權
* @date 2013-9-23
* @note begin modify by null
*/
public Object[] getServiceParametersByAccountIdAndDataType(Long accountId,String code) {
TCoGraph tCoGraph = tCoGraphDao.getConfigByCondition(accountId, code);
String[] parameters = tCoGraph.getCserviceParameters()
.split(“##”);
String[] serviceParameters = new String[parameters.length + 1];
//將服務引數儲存到陣列中
for (int i = 0; i < parameters.length; i++) {
serviceParameters[i] = parameters[i].split(“=”)[1];
}
// 通過這個serviceId來判斷到底是使用哪個服務
String serviceId = tCoGraph.getVserviceId().toString();
serviceParameters[parameters.length] = serviceId;
//這個地方表示獲取資料(包括MICAPS日誌資料和服務配置資料)完成,服務引數為20
new ProductLUtils().saveOrUpdateTaskStateLAndProductL(
taskStateDao, //操作任務表的Dao
productLDao, //操作產品日誌庫的Dao
accountId, //使用者賬號
code, //產品CODE
“20”, //狀態標識
new Date(), //最後製作時間
“GRAPH”, //產品類別
“資料獲取完成” //操作型別
);
return serviceParameters;
}
}
對上面的一個裡做AOP操作
package cn.com.css.misps.graph.aop;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
/**
* @brief GraphAop.java 這是出圖過程中的切面
* @attention
* @author 塗作權
* @date 2013-9-21
* @note begin modify by null
*/
@Aspect
@Component(value = “generateGraphAop”)
@SuppressWarnings(“unused”)
public class GraphAop {
/**
* rief 將micaps釋出日誌中資訊進行拼裝整合的過程
*
* @attention
* @author 塗作權
* @date 2013-9-22
* @note begin modify by null
*/
@Pointcut(value = “execution(* cn.com.css.misps.graph.service.impl.TCoGraphServiceImpl.getServiceParametersByAccountIdAndDataType(long,String))&&args(accountId,code)”, argNames = “accountId,code”)
private void micapsPathAndDatatypePointcut(Long accountId, String code) {
System.out.println(“操作日誌表”);
}
/**
* rief 只有發現有釋出日誌的時候才會接著執行下面的程式碼,否則不執行。所以這裡就是就是資料獲取的部分,
* 並且是在服務引數也獲取到了之後才算是資料獲取階段
*
* @param accountId
* :表示最後配置的系統管理員角色的使用者的使用者id
* @param code
* :這裡代表的時候是micaps日誌檔案中用來區分產品標識,這裡希望是類似11節的產品CODE
* @attention 這裡的CODE代表的意義可能在MICAPS日誌規範定下來了之後會變
* @author 塗作權
* @date 2013-9-23
* @note begin modify by null
*/
@AfterReturning(value = “micapsPathAndDatatypePointcut(accountId,code)”, argNames = “accountId,code”)
private void serviceParametersAdvice(Long accountId, String code) {
System.out.println(“資料獲取中”);
}
// /**
// * rief 獲取圖形流程配置表中的資料資訊
// *
// * @attention 這裡面的引數可變
// * @author 塗作權
// * @date 2013-9-22
// * @note begin modify by null
// *
// @Pointcut(“execution(* cn.com.css.misps.graph.dao.impl.TCoGraphDaoImpl.getConfigByCondition(..))”)
// private void tCoGraphPointcut() {
// }
//
// /**
// * rief 圖形生成的過程
// *
// * @attention
// * @author 塗作權
// * @date 2013-9-22
// * @note begin modify by null
// */
// @Pointcut(“execution(* cn.com.css.misps.graph.service.impl.GraphServiceImpl.generateGraphs(..))”)
// private void generateGraphsPointcut() {
// }
//
// /**
// * rief 生成獲取micaps檔案的路徑和資料型別的日誌
// *
// * @attention 將micaps檔案的路徑和資料型別儲存到資料庫中
// * @author 塗作權
// * @date 2013-9-22
// * @note begin modify by null
// */
// @Before(“micapsPathAndDatatypePointcut()”)
// public void micapsPathAndDatatypeAdvice() {
// System.out.println(“獲取micaps檔案路徑和資料型別的拼接字串……”);
// }
//
// /**
// * rief 生成圖形前做日誌
// *
// * @attention 將日誌資訊儲存到製作圖形產品的日誌表中
// * @author 塗作權
// * @date 2013-9-22
// * @note begin modify by null
// */
// @Before(“generateGraphsPointcut()”)
// public void generateGraphsAdvice() {
// System.out.println(“生成圖形產品…..”);
// }
}
這裡是另外一個AOP的寫法:
package cn.com.css.misps.graph.aop;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.tempuri.IMPService;
/**
* @brief GraphUtilsAop.java 這個圖形制作工具類的切面
* @attention
* @author 塗作權
* @date 2013-9-26
* @note begin modify by null
*/
@SuppressWarnings(“unused”)
@Aspect
@Component(“GraphUtilsAop”)
public class GraphUtilsAop {
/**
* rief 圖形制作的切入點
*
* @attention 這裡是圖形制作切入點
* @author 塗作權
* @date 2013-9-26
* @note begin modify by null
*/
@Pointcut(value = “execution(* cn.com.css.misps.graph.util.GraphUtils.getGraphBytesByMpServiceFile(Long,String))&&args(accountId,code)”,
argNames = “accountId,code”)
private void getGraphBytesByMpServiceFilePointcut(Long accountId,
String code) {
}
@Before(“getGraphBytesByMpServiceFilePointcut(accountId,code)”)
private void getGraphBytesByMpServiceFileAdvice(Long accountId,
String code) {
System.out.println(“accountId = ” + accountId);
System.out.println(“code = ” + code);
}
}
這裡是另外一個AOP的寫法:
package cn.com.css.misps.graph.aop;
import javax.annotation.Resource;
import org.aopalliance.intercept.Joinpoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import cn.com.css.misps.domain.TProductL;
import cn.com.css.misps.graph.dao.ITMicapsLDao;
import cn.com.css.misps.graph.dao.ITProductLDao;
/**
* @brief MicapsAOP.java 這個類是關於MICAPS日誌相關的aop
* @attention
* @author 塗作權
* @date 2013-9-22
* @note begin modify by null
*/
@Aspect
@Component(value = “micapsAOP”)
@SuppressWarnings(“unused”)
public class MicapsAOP {
@Resource(name = “iTProductLDao”)
private ITProductLDao productLDao;
@Resource(name = “iTMicapsLDao”)
private ITMicapsLDao tMicapsLDao;
/**
* rief 查詢狀態是”釋出”的,並且掃描狀態為0的MICAPS日誌,
* 0表示未掃描過的,也就是說是新產生的MICAPS製作日誌檔案
*
* @attention 掃描MICAPS製作日誌檔案
* @author 塗作權
* @date 2013-9-22
* @note begin modify by null
*/
@Pointcut(value = “execution(* cn.com.css.misps.graph.dao.impl.TMicapsLDaoImpl.findTMicapsLByState(String,String))&&args(state,ifScanned)”, argNames = “state,ifScanned”)
private void dataSourcePointcut(String state, String ifScanned) {}
/**
* rief 說明一直在進行
*
* @attention 注意這裡的引數是cn.com.css.misps.graph.dao.impl.TMicapsLDaoImpl.
* findTMicapsLByState(..)方法中的引數
* 還可以直接通過:@Before(“dataSourcePointcut()&&args(state,ifScanned)”
* )方式, 在上面的切入點部分直接寫execution表示式,也就是: execution(*
* cn.com.css.misps
* .graph.dao.impl.TMicapsLDaoImpl.findTMicapsLByState(..))<br/>
*
* 這裡不用再寫:args(state,ifScanned)
*
* @author 塗作權
* @date 2013-9-22
* @note begin modify by null
*/
// @Before(value = “dataSourcePointcut(state,ifScanned)”, argNames = “state,ifScanned”)
// public void dataSourceBeforeAdvice(String state, String ifScanned) {
// System.out.println(“state=======” + state);
// System.out.println(“ifScanned===” + ifScanned);
// System.out.println(“按照條件查詢micaps日誌的dao.impl….”);
// }
/**
* rief 這裡是後置通知
*
* @param state
* 標識狀態的引數
* @param ifScanned
* 表示是否掃描過,如果為0表示掃描過,如果為1表示掃描過
* @attention 通過後置通知將查詢過T_MICAPS_L表中的ifScanned引數變為1,表示掃描過
* @author 塗作權
* @date 2013-9-22
* @note begin modify by null
*/
@AfterReturning(value = “dataSourcePointcut(state,ifScanned)”, argNames = “state,ifScanned”)
public void dataSourceAfterReturningAdvice(String state, String ifScanned) {
//更新狀態
tMicapsLDao.updateFieldOfIfScanned();
}
/**
* rief 這裡是一個最終通知
*
* @param state
* 標識狀態的引數
* @param ifScanned
* 表示是否掃描過,如果為0表示掃描過,如果為1表示掃描過
* @attention
* @author 塗作權
* @date 2013-9-22
* @note begin modify by null
*/
// @After(value = “dataSourcePointcut(state,ifScanned)”, argNames = “state,ifScanned”)
// public void dataSourceAfterAdvice(String state, String ifScanned) {
// System.out.println(“這裡是MICAPS相關的最終通知,暫時不做任何動作…………..”);
// }
/**
* rief 這裡是一個異常通知
*
* @attention 如果呼叫中出現了異常,則執行這一句
* @author 塗作權
* @date 2013-9-22
* @note begin modify by null
*/
// @AfterThrowing(value = “dataSourcePointcut(state,ifScanned)”, throwing = “ex”)
// public void dataSourceThrowMethod(String state, String ifScanned,
// Throwable ex) {
// System.out.println(ex.getMessage());
// System.out.println(“如果在查詢MICAPS日誌資訊的時候出現了異常,那麼將執行這一句……”);
// }
}
這裡是另外一個AOP的寫法:
package cn.com.css.misps.graph.aop;
import java.util.Date;
import javax.annotation.Resource;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import cn.com.css.misps.graph.dao.ITProductLDao;
import cn.com.css.misps.graph.dao.ITTaskStateDao;
import cn.com.css.misps.graph.util.ProductLUtils;
/**
* @brief TCoGraphAOP.java 類或者介面的簡要說明
* @attention 如果沒有找到這個CODE對應的產品提示:這種產品沒有配置, 或者沒有對產品進行管理,請管理員新增圖形產品的配置
*
* @author 圖形產品相關的日誌資訊
* @date 2013-9-25
* @note begin modify by null
*/
@Aspect
@Component(“tCoGraphAOP”)
public class TCoGraphAOP {
@Resource(name = “iTTaskStateDao”)
private ITTaskStateDao taskStateDao;
@Resource(name = “iTProductLDao”)
private ITProductLDao productLDao;
@SuppressWarnings(“unused”)
@Pointcut(value = “execution(* cn.com.css.misps.graph.service.impl.TCoGraphServiceImpl.getServiceParametersByAccountIdAndDataType(*,Long,String))” +
“&&args(accountId,code)”,
argNames = “accountId,code”)
private void queryGraphConfig(Long accountId, String code) {
}
/**
* rief 獲取流程配置引數方法的前置通知,這個時候一定發現了MICAPS日誌釋出資訊
*
* @param accountId
* @param code
* @attention 如果在BaseInfo表中沒有找到這種產品,做出提示,告訴系統管理員進行圖形產品配置
* @author 塗作權
* @date 2013-9-25
* @note begin modify by null
*/
@AfterReturning(value = “queryGraphConfig(accountId,code)”,
argNames = “accountId,code”)
public void queryGraphConfigAdvice(Long accountId, String code) {
new ProductLUtils().saveOrUpdateTaskStateLAndProductL(
taskStateDao, //操作任務表的Dao
productLDao, //操作產品日誌庫的Dao
accountId, //使用者賬號
code, //產品CODE
“20”, //狀態標識
new Date(), //最後製作時間
“GRAPH”, //產品類別
“資料獲取完成” //操作型別
);
}
}
AOP的單元測試類:
package cn.com.css.misps.graph.aop;
import java.io.File;
import java.util.List;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.com.css.misps.domain.TMicapsL;
import cn.com.css.misps.graph.dao.ITMicapsLDao;
import cn.com.css.misps.graph.service.impl.TCoGraphServiceImpl;
/**
* @brief PersonProxyTest.java 類或者介面的簡要說明
* @attention 使用注意事項
* @author Administrator
* @date 2013-9-22
* @note begin modify by 修改人 修改時間 修改內容摘要說明
*/
public class ProxyTest {
@Test
public void test() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
“applicationContext.xml”);
PersonDao personDao = (PersonDao) applicationContext
.getBean(“personDao”);
personDao.deletePerson();
}
@Test
public void test1() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
“applicationContext.xml”);
TCoGraphServiceImpl coGraphService = (TCoGraphServiceImpl) applicationContext
.getBean(“iTCoGraphService”);
coGraphService.getServiceParametersByAccountIdAndDataType(1L, “SEVP_PWSC_SJCF_PRO_EQ2_TRD_L88_PB_001_01_PNG”);
}
@Test
public void test2() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
“applicationContext.xml”);
ITMicapsLDao tMicapsLDao = (ITMicapsLDao) applicationContext
.getBean(“iTMicapsLDao”);
List<TMicapsL> tMicapsLByStateList = tMicapsLDao
.findTMicapsLByState(“釋出”,”0″);
if (tMicapsLByStateList != null) {
for (int i = 0; i < tMicapsLByStateList.size(); i++) {
TMicapsL tMicapsL = tMicapsLByStateList.get(i);
System.out.println(tMicapsL.getCoutputfolder() + File.separator
+ tMicapsL.getCoutputdata() + “##”
+ tMicapsL.getCcode());
}
} else {
return;
}
}
}
相關文章
- 專案管理的一個案例,聽聽大家的意見專案管理
- 求一個ot的專案例項
- 編譯FFMPEG原始碼的指令碼編寫案例編譯原始碼指令碼
- 找了幾個 Solon 框架的商業落地專案案例!框架
- 配置檔案的編寫
- GO 中 ETCD 的編碼案例分享Go
- 專案案例:寵物商店
- 一個js編寫全選、彈出對話方塊、ajax-json的案例JSON
- 怎樣快速將一個非jbuilder編寫的專案變為jbuilder專案UI
- 找不到Java的專案案例學習,可以看看這個Java
- MySQL:一個奇怪的hang案例MySql
- 一個動態ACL的案例
- 一個效能優化的案例優化
- spring之AOP的概念及簡單案例Spring
- 專案管理案例研究(轉)專案管理
- 專案策劃書案例
- 夏敏捷主編的Python專案案例開發著作出版了敏捷Python
- Windows 專案的 CMakeLists 編寫Windows
- 初學原始碼之——銀行案例手寫IOC和AOP原始碼
- 【MySQL】NOT EXISTS優化的一個案例MySql優化
- 一個簡單的MVP模式案例MVP模式
- 巧妙使用exchange partition的一個案例
- 一個濫用程式碼的案例
- Oracle效能解決的一個案例Oracle
- 一個簡單的sql稽核案例SQL
- 一個JDO的成功案例分析 (轉)
- 一個C++專案的Makefile編寫-Tony與Alex的對話系列C++
- 完整的python專案例項-python完整專案Python
- 管理的挑戰——軟技能在專案管理中的應用案例(轉)專案管理
- 一個mount -a引發的ora-600案例分析
- OceanBase 金融專案最佳化案例(union all 改寫)
- 編寫一個 Makefile 檔案,對階段專案一的程式碼進行自動化編譯編譯
- MyBatis第四章:專案案例mybatis主要配置解析MyBatis
- Bootstrap一個小案例boot
- 一個需求分析做的不夠的案例
- 如何編寫一個前端框架之一-專案結構(譯)前端框架
- flask專案之圖書案例Flask
- 3. 投票 案例專案(合集)