锘??xml version="1.0" encoding="utf-8" standalone="yes"?>精品亚洲A∨无码一区二区三区,亚洲人成网站色7799,亚洲电影国产一区http://www.tkk7.com/hengheng123456789/category/17304.htmlzh-cnTue, 04 Sep 2007 22:24:14 GMTTue, 04 Sep 2007 22:24:14 GMT60Give Your Business Logic a Framework with Droolshttp://www.tkk7.com/hengheng123456789/archive/2007/09/03/142399.html鍝煎摷鍝煎摷Mon, 03 Sep 2007 09:40:00 GMThttp://www.tkk7.com/hengheng123456789/archive/2007/09/03/142399.htmlhttp://www.tkk7.com/hengheng123456789/comments/142399.htmlhttp://www.tkk7.com/hengheng123456789/archive/2007/09/03/142399.html#Feedback0http://www.tkk7.com/hengheng123456789/comments/commentRss/142399.htmlhttp://www.tkk7.com/hengheng123456789/services/trackbacks/142399.htmlMost web and enterprise Java applications can be split into three parts: a front end to talk to the user, a service layer to talk to back-end systems such as databases, and business logic in between. While it is now common practice to use frameworks for both front- and back-end requirements (e.g., Struts, Cocoon, Spring, Hibernate, JDO, and Entity Beans), there is no standard way of structuring business logic. Frameworks like EJB and Spring do this at a high level, but don't help us in organizing our code. Wouldn't it would be great if we could replace messy, tangled if...then statements with a framework that gave us the same benefits of configurability, readability, and reuse that we already enjoy in other areas? This article suggests using the Drools rules engine as a framework to solve the problem.

The sample code below gives a sample of the problem we're trying to avoid. It shows some business logic in a typical Java application.


if ((user.isMemberOf(AdministratorGroup)
      && user.isMemberOf(teleworkerGroup))
     || user.isSuperUser(){
        
         // more checks for specific cases
         if((expenseRequest.code().equals("B203")
           ||(expenseRequest.code().equals("A903")
                        &&(totalExpenses<200)
                &&(bossSignOff> totalExpenses))
           &&(deptBudget.notExceeded)) {
               //issue payments
           } else if {
               //check lots of other conditions
           }
} else {
     // even more business logic
}

We've all come across similar (or even more complex) business logic. While this has been the standard way of implementing business logic in Java, there are many problems with it.

  • What if the business users come up with another form ("C987") that needs to be added to the already hard-to-understand code? Would you want to be the person to maintain it, once all of the original programmers had moved on?
  • How do we check that these rules are correct? It's hard enough for technical people--never mind commercial folks--to review. Do we have any methodical way of testing this business logic?
  • Many applications have similar business rules--if one of the rules change, can we be sure that it is changed consistently across all systems? If a new application uses some of these rules, but also adds some new ones, do we need to rewrite all of the logic from scratch?
  • Is the business logic easily configurable, not so firmly tied to Java code that we need to recompile/redeploy every time that a small change is made?
  • What if other (scripting) languages want to leverage the existing investment in business rule logic?

J2EE/EJB and "inversion of control" frameworks (such as Spring, Pico, and Avalon) give us the ability to organize our code at a high level. While they are very good at providing reusability, configuration, and security, none of them would replace the "spaghetti code" in the above example. Ideally, whatever framework we choose will be compatible with not only J2EE applications, but also "normal" Java (J2SE--Standard Edition) programs, and most of the widely used presentation and persistence frameworks. Such a framework should allow us to do the following:

  • Business users should be able to easily read and verify the business logic.
  • Business rules should be reusable and configurable across applications.
  • The framework should be scalable and performant under heavy load.
  • It should be as easy to use for Java programmers as existing front-end (Struts, Spring) and back-end (object-relational mapping) frameworks.

An additional problem is that while there are only so many ways to organize web pages and database access, business logic tends to differ widely between applications. Our framework should be able to cope with this and still promote code reuse. Ideally, our application would be "frameworks all the way down." By using frameworks in this way, we can a large amount of our application "out of the box," allowing us to write only the parts that add value for the customer.

Rule Engines to the Rescue

How are we going to solve this problem? One solution that is gaining traction is to use a rule engine. Rule engines are frameworks for organizing business logic that allow the developer to concentrate on things that are known to be true, rather than the low-level mechanics of making decisions.

Often, business users are more comfortable with expressing things that they know to be true, than to express things in an if...then format. Examples of things that you might hear from a business expert are:

  • "FORM 10A is used for expense claims over 200 Euro."
  • "We only trade shares in quantities of 10,000 or more."
  • "Purchases over 鈧?0m need the approval of a company director."

By focusing on what we know to be true, rather than the mechanics of how to express it in Java code, the above statements are clearer than our previous code sample. Still, clear as they may be, we still need a mechanism to apply these rules to the facts that we know and get a decision. Such a mechanism is a rule engine.


Rule Engines in Java

JSR 94, the javax.rules API, sets a common standard for interacting with rule engines, much as JDBC allows us to interact with varying databases. What JSR-94 does not specify is how the actual rules are written, leaving plenty of choice among the most widely used Java rule engines:


  • Jess is perhaps the most mature Java rule engine, with good tool support (including Eclipse plugins) and documentation. However it is a commercial product, and it writes its rules in a Prolog-style notation, which can be intimidating for many Java programmers.
  • Jena is an open source framework, originally from HP. While it has a rules engine, and is especially strong for those interested in the Semantic Web, it is not fully JSR-94-compliant.
  • Drools is a JSR-94-complaint rules engine, and is fully open source under an "Apache-style" license. Not only does it express rules in familiar Java and XML syntax, it has a strong user and developer community. For the examples in this article, we'll be using Drools, as it has the easiest to use Java-like syntax and it has the most open license.

Starting a Java Application using Drools

Imagine this scenario: minutes after reading this article, your boss asks your to prototype a stock trading application. As the business users still haven't fully defined the business logic, you think it a good idea to implement it using a rules engine. The final system will be accessible over an intranet and will need to communicate with back-end database and messaging systems. To get started, download the Drools framework (with dependencies). Create a new project in your favorite IDE and make sure all of the .jars are referenced in it, as per Figure 1. This screenshot is Eclipse-based, but the setup will be similar for other IDEs.

Libraries needed to Run Drools
Figure 1. Libraries needed to run Drools

Due to the huge potential losses if our stock trading system went amok, it's vital that we have some sort of simulator to put our system through its paces. Such a simulator also gives you confidence that the decisions made by the system are those that are intended, even after rule changes are made. We'll borrow some tools from the Agile toolbox and use JUnit as a framework for our simulations.

The first code we write is the JUnit Test/simulator, as per the following listing. Even if we can't test every combination of values likely to be input into our application, some tests are better than none at all. In this example, all of our files and classes (including unit tests) are in one folder/package, but in reality, you would implement a proper package and folder structure. We'd also use Log4j instead of the System.out calls in the sample code.


import junit.framework.TestCase;
/*
* JUnit test for the business rules in the
* application.
*
* This also acts a 'simulator' for the business
* rules - allowing us to specify the inputs,
* examine the outputs and see if they match our
* expectations before letting the code loose in
* the real world.
*/
public class BusinessRuleTest extends TestCase {
/**
* Tests the purchase of a stock
*/
public void testStockBuy() throws Exception{
//Create a Stock with simulated values
StockOffer testOffer = new StockOffer();
testOffer.setStockName("MEGACORP");
testOffer.setStockPrice(22);
testOffer.setStockQuantity(1000);
//Run the rules on it
BusinessLayer.evaluateStockPurchase(testOffer);
//Is it what we expected?
assertTrue(
testOffer.getRecommendPurchase()!=null);
assertTrue("YES".equals(
testOffer.getRecommendPurchase()));
}
}


This is a basic JUnit test, as we know that our (very simple!) system should buy all stocks with a price of less than 100 Euro. Obviously, this won't compile without our data holding class (StockOffer.java) and our business layer class (BusinessLayer.java). These are provided in the following listings.


/**
* Facade for the Business Logic in our example.
*
* In this simple example, all our business logic
* is contained in this class but in reality it
* would delegate to other classes as required.
*/
public class BusinessLayer {
/**
* Evaluate whether or not it is a good idea
* to purchase this stock.
* @param stockToBuy
* @return true if the recommendation is to buy
*   the stock, false if otherwise
*/
public static void evaluateStockPurchase
(StockOffer stockToBuy){
return false;
}
}

The StockOffer class looks like this:

/**
* Simple JavaBean to hold StockOffer values.
* A 'Stock offer' is an offer (from somebody else)
* to sell us a Stock (or Company share).
*/
public class StockOffer {
//constants
public final static String YES="YES";
public final static String NO="NO";
//Internal Variables
private String stockName =null;
private int stockPrice=0;
private int stockQuantity=0;
private String recommendPurchase = null;
/**
* @return Returns the stockName.
*/
public String getStockName() {
return stockName;
}
/**
* @param stockName The stockName to set.
*/
public void setStockName(String stockName) {
this.stockName = stockName;
}
/**
* @return Returns the stockPrice.
*/
public int getStockPrice() {
return stockPrice;
}
/**
* @param stockPrice The stockPrice to set.
*/
public void setStockPrice(int stockPrice) {
this.stockPrice = stockPrice;
}
/**
* @return Returns the stockQuantity.
*/
public int getStockQuantity() {
return stockQuantity;
}
/**
* @param stockQuantity to set.
*/
public void setStockQuantity(int stockQuantity){
this.stockQuantity = stockQuantity;
}
/**
* @return Returns the recommendPurchase.
*/
public String getRecommendPurchase() {
return recommendPurchase;
}
}

We run BusinessRuleTest through the JUnit extension of our favorite IDE. If you're not familiar with JUnit, more information can be found at . Not surprisingly, our test fails at the second assertion, shown in Figure 2, as we don't (yet) have the appropriate business logic in place. This is reassuring, as it shows that our simulator/unit tests are highlighting the problems that they should.



JUnit Test Results
Figure 2. JUnit test results

Writing the Business Logic using Rules

At this point, we need to write some business logic that says, "If the stock price is less than 100 Euro, then we should buy it." To do this, we will modify BusinessLayer.java to read:


import java.io.IOException;
import org.drools.DroolsException;
import org.drools.RuleBase;
import org.drools.WorkingMemory;
import org.drools.event.DebugWorkingMemoryEventListener;
import org.drools.io.RuleBaseLoader;
import org.xml.sax.SAXException;
/**
* Facade for the Business Logic in our example.
*
* In this simple example, all our business logic
* is contained in this class but in reality it
* would delegate to other classes as required.
* @author default
*/
public class BusinessLayer {
//Name of the file containing the rules
private static final String BUSINESS_RULE_FILE=
"BusinessRules.drl";
//Internal handle to rule base
private static RuleBase businessRules = null;
/**
* Load the business rules if we have not
* already done so.
* @throws Exception - normally we try to
*          recover from these
*/
private static void loadRules()
throws Exception{
if (businessRules==null){
businessRules = RuleBaseLoader.loadFromUrl(
BusinessLayer.class.getResource(
BUSINESS_RULE_FILE ) );
}
}
/**
* Evaluate whether or not to purchase stock.
* @param stockToBuy
* @return true if the recommendation is to buy
* @throws Exception
*/
public static void evaluateStockPurchase
(StockOffer stockToBuy) throws Exception{
//Ensure that the business rules are loaded
loadRules();
//Some logging of what is going on
System.out.println( "FIRE RULES" );
System.out.println( "----------" );
//Clear any state from previous runs
WorkingMemory workingMemory
= businessRules.newWorkingMemory();
//Small ruleset, OK to add a debug listener
workingMemory.addEventListener(
new DebugWorkingMemoryEventListener());
//Let the rule engine know about the facts
workingMemory.assertObject(stockToBuy);
//Let the rule engine do its stuff!!
workingMemory.fireAllRules();
}
}

This class now has some important methods:

  • loadRules(), which loads the rules from the BusinessRules.drl file.
  • An updated evaluateStockPurchase(), which evaluates these business rules. Some points to note about this method are:
    • We can reuse the same RuleSet over and over (as business rules in memory are stateless).
    • We use a new WorkingMemory for every evaluation, as this is our knowledge of what we know to be true at this time. We use assertObject() to place known facts (as Java Objects) into this memory.
    • Drools has an event listener model, to allow us to "see" what is going on within the event model. Here we use it to print debug information.
  • The fireAllRules() method on the working memory class causes the rules to be evaluated and updated (in this case, stock offer).

Before we can run the example again, we need to create our BusinessRules.drl file, as follows:


<?xml version="1.0"?>
<rule-set name="BusinessRulesSample"
xmlns="http://drools.org/rules"
xmlns:java="http://drools.org/semantics/java"
xmlns:xs
="http://www.w3.org/2001/XMLSchema-instance"
xs:schemaLocation
="http://drools.org/rules rules.xsd
http://drools.org/semantics/java java.xsd">
<!-- Import the Java Objects that we refer
to in our rules -->
<java:import>
java.lang.Object
</java:import>
<java:import>
java.lang.String
</java:import>
<java:import>
net.firstpartners.rp.StockOffer
</java:import>
<!-- A Java (Utility) function we reference
in our rules-->
<java:functions>
public void printStock(
net.firstpartners.rp.StockOffer stock)
{
System.out.println("Name:"
+stock.getStockName()
+" Price: "+stock.getStockPrice()
+" BUY:"
+stock.getRecommendPurchase());
}
</java:functions>
<rule-set>
<!-- Ensure stock price is not too high-->
<rule name="Stock Price Low Enough">
<!-- Params to pass to business rule -->
<parameter identifier="stockOffer">
<class>StockOffer</class>
</parameter>
<!-- Conditions or 'Left Hand Side'
(LHS) that must be met for
business rule to fire -->
<!-- note markup -->
<java:condition>
stockOffer.getRecommendPurchase() == null
</java:condition>
<java:condition>
stockOffer.getStockPrice() < 100
</java:condition>
<!-- What happens when the business
rule is activated -->
<java:consequence>
stockOffer.setRecommendPurchase(
StockOffer.YES);
printStock(stockOffer);
</java:consequence>
</rule>
</rule-set>

This rules file has several interesting parts:

  • Just after the XML-Schema definitions come the Java objects we reference in our rules. These objects can come from any Java library as required.
  • Next comes our functions, which can incorporate standard Java code. In this case, we incorporate a logging function to help us see what is going on.
  • After that comes our rule set, consisting of one or more rules.
  • Each rule can take parameters (the StockOffer class), one or more conditions that need to be fulfilled, and a consequence that is carried out if and when the conditions are met.

Having modified and compiled our code, we run the JUnit test simulations again. This time, the business rules are called, our logic evaluates correctly, and our tests pass, as seen in Figure 3. Congratulations--you've just built your first rule-based application!

Successful JUnit Test
Figure 3. Successful JUnit test


Smarter Rules

Fresh from building the application, you demonstrate the prototype above to the business users, and they remember a few more rules that they forgot to mention earlier. One of the new rules is that we shouldn't trade stocks where the quantity is a negative number (<0). "No problem," you say, and return to your desk, secure in the knowledge that you can quickly evolve your system.

The first thing you do is to update your simulator, and add the following code to BusinessRuleTest.java:


/**
* Tests the purchase of a stock
* makes sure the system will not accept
* negative numbers.
*/
public void testNegativeStockBuy()
throws Exception{
//Create a Stock with our simulated values
StockOffer testOffer = new StockOffer();
testOffer.setStockName("MEGACORP");
testOffer.setStockPrice(-22);
testOffer.setStockQuantity(1000);
//Run the rules on it
BusinessLayer
.evaluateStockPurchase(testOffer);
//Is it what we expected?
assertTrue("NO".equals(
testOffer.getRecommendPurchase()));
}

This tests for the new rule described by the business users. If we run this JUnit test, our new test fails, as expected. We need to add a new rule to our .drl file, as follows.


<!-- Ensure that negative prices
are not accepted-->
<rule name="Stock Price Not Negative">
<!-- Parameters we can pass into
the business rule -->
<parameter identifier="stockOffer">
<class>StockOffer</class>
</parameter>
<!-- Conditions or 'Left Hand Side' (LHS)
that must be met for rule to fire -->
<java:condition>
stockOffer.getStockPrice() < 0
</java:condition>
<!-- What happens when the business rule
is activated -->
<java:consequence>
stockOffer.setRecommendPurchase(
StockOffer.NO);
printStock(stockOffer);
</java:consequence>
</rule>

This rule is similar in format to the previous one, expect that our <java:condition> is different (testing for negative numbers) and the <java:consequence> sets the recommend purchase to No. We run our unit tests/simulator again, and this time the test passes.

At this point, if you're used to procedural programming (like most Java programmers), you may be scratching your head: here we have a file containing two separate business rules, yet we haven't told the rule engine which is more important. However, our stock price (of -22) satisfies both rules (i.e., it is less than 0 and it is less than 100). Despite this, we get the correct result, even if we swap the order of the rules around. How does this work?

The extract of the console output below helps us to see what is going on. We see that both rules are firing (the [activationfired] line), and that the Recommend Buy is first set to Yes and then to No. How does Drools know to fire these rules in the correct order? If you look at the Stock Price Low Enough rule, you will see that one of the conditions is that recommendPurchase() is null. This is enough for the Drools rule engine to decide that the Stock Price Low Enough rule should be fired before the Stock Price Not Negative rule. This process is called conflict resolution.


FIRE RULES
----------
[ConditionTested: rule=Stock Price Not Negative;
condition=[Condition: stockOffer.getStockPrice()
< 0]; passed=true; tuple={[]}]
[ActivationCreated: rule=Stock Price Not Negative;
tuple={[]}]
[ObjectAsserted: handle=[fid:2];
object=net.firstpartners.rp.StockOffer@16546ef]
[ActivationFired: rule=Stock Price Low Enough;
tuple={[]}]
[ActivationFired: rule=Stock Price Not Negative;
tuple={[]}]
Name:MEGACORP Price: -22 BUY:YES
Name:MEGACORP Price: -22 BUY:NO

If you're a procedural programmer, no matter how clever you think this is, you still may not trust it completely. That is why we have our unit tests/simulator: "hard" JUnit tests (using normal Java code) ensure that the rule engine makes its decisions along the lines we want it to. (And doesn't spend billions on worthless stock!) At the same time, the power and the flexibility of our rule engine allows us to quickly develop the business logic.

Later on, we will see more sophisticated forms of conflict resolution.


Conflict Resolution

Now the folks on the business side are really impressed and are starting to think through the possible options. They've come across a problem with stocks of XYZ Corp and have decided to implement a new rule: Only buy stocks of XYZ Corp if they are less than 10 Euro.

As before, you add the test to our simulator and include the new business rule in our rules file, as per the following listings. First, we add a new method to BusinessRuleTest.java:


/**
* Makes sure the system will buy stocks
* of XYZ corp only if it really cheap
*/
public void testXYZStockBuy() throws Exception{
//Create a Stock with our simulated values
StockOffer testOfferLow = new StockOffer();
StockOffer testOfferHigh = new StockOffer();
testOfferLow.setStockName("XYZ");
testOfferLow.setStockPrice(9);
testOfferLow.setStockQuantity(1000);
testOfferHigh.setStockName("XYZ");
testOfferHigh.setStockPrice(11);
testOfferHigh.setStockQuantity(1000);
//Run the rules on it and test
BusinessLayer.evaluateStockPurchase(
testOfferLow);
assertTrue("YES".equals(
testOfferLow.getRecommendPurchase()));
BusinessLayer.evaluateStockPurchase(
testOfferHigh);
assertTrue("NO".equals(
testOfferHigh.getRecommendPurchase()));
}

Next, we need a new <rule> in BusinessRules.drl:


<rule name="XYZCorp" salience="-1">
<!-- Parameters we pass to rule -->
<parameter identifier="stockOffer">
<class>StockOffer</class>
</parameter>
<java:condition>
stockOffer.getStockName().equals("XYZ")
</java:condition>
<java:condition>
stockOffer.getRecommendPurchase() == null
</java:condition>
<java:condition>
stockOffer.getStockPrice() > 10
</java:condition>
<!-- What happens when the business
rule is activated -->
<java:consequence>
stockOffer.setRecommendPurchase(
StockOffer.NO);
printStock(stockOffer);
</java:consequence>
</rule>

Note that in the business rules file, after the rule name, we set our salience to -1 (i.e., the lowest priority of all of the rules we have specified so far). Most of the rules in our system conflict, meaning Drools must make some decision on the order in which to fire rules, given that the conditions for all of the rules will be met. The default way of deciding is:

  • Salience: A value we assign, as per the above listing.
  • Recency: How many times we have used a rule.
  • Complexity: Specific rules with more complicated values fire first.
  • LoadOrder: The order in which rules are loaded.

If we did not specify the saliency of our rule in this example, what would happen is:

  • The XYZ Corp rule ("Don't buy XYZ if the price is more than 10 Euro") would fire first (the status of the Recommend Buy flag would be set to No).
  • Then the more general rule ("Buy all stock under 100") fires, setting the Recommended Buy flag to yes.

This would give a result that we don't want. However, since our example does set the saliency factor, the test and our business rules work as expected.

While most of the time, writing clear rules and setting the saliency will give enough information to Drools for it to choose the proper order in which to fire rules, sometimes we want to change the entire manner in which rule conflicts are resolved. An example of how to change this is given below, where we tell the rule engine to fire the simplest rules first. A word of warning: be careful when changing conflict resolution, as it can fundamentally change the behavior of the rule engine--a lot of problems can be solved first with clear and well-written rules.


//Generate our list of conflict resolvers
ConflictResolver[] conflictResolvers =
new ConflictResolver[] {
SalienceConflictResolver.getInstance(),
RecencyConflictResolver.getInstance(),
SimplicityConflictResolver.getInstance(),
LoadOrderConflictResolver.getInstance()
};
//Wrap this up into one composite resolver
CompositeConflictResolver resolver =
new CompositeConflictResolver(
conflictResolvers);
//Specify this resolver when we load the rules
businessRules = RuleBaseLoader.loadFromUrl(
BusinessLayer.class.getResource(
BUSINESS_RULE_FILE),resolver);

For our simple application, driven by JUnit tests, we don't need to alter the way the Drools resolves rule conflicts. It is useful to know how conflict resolution works, especially when your application grows to meet more complex and demanding requirements.

Conclusion

This article demonstrated a problem that most programmers have had to face: how to put some order on the complexity of business logic. We demonstrated a simple application using Drools as a solution and introduced the notion of rule-based programming, including how these rules are resolved at runtime. Later on, a follow-up article will take these foundations and show how to use them in an enterprise Java application.

Resources

Paul Browne , based in Dublin, Ireland, has been consulting in enterprise Java with FirstPartners.net for almost seven years.



鍝煎摷 2007-09-03 17:40 鍙戣〃璇勮
]]>
Using Drools in Your Enterprise Java Applicationhttp://www.tkk7.com/hengheng123456789/archive/2007/09/03/142394.html鍝煎摷鍝煎摷Mon, 03 Sep 2007 09:28:00 GMThttp://www.tkk7.com/hengheng123456789/archive/2007/09/03/142394.htmlhttp://www.tkk7.com/hengheng123456789/comments/142394.htmlhttp://www.tkk7.com/hengheng123456789/archive/2007/09/03/142394.html#Feedback0http://www.tkk7.com/hengheng123456789/comments/commentRss/142394.htmlhttp://www.tkk7.com/hengheng123456789/services/trackbacks/142394.htmlUsing Drools in Your Enterprise Java Application by Paul Browne
08/24/2005

These days enterprise Java could almost put you to sleep. How many hundreds of J2EE-EJB web applications have been written that capture information from a web page and store it in a database? What really keeps developers awake at night is trying to write and maintain the complex business logic in their applications. This is a problem not only for new applications, but increasingly, for long-lived, business-critical apps whose internal logic needs to change frequently, often at very short notice.

In an earlier article, "Give Your Business Logic a Framework with Drools," I introduced the Drools framework and showed how it could be used to organize complicated business logic. Drools replaced many tangled if ... then statements with a simple set of things known to be true. If you are ever in a meeting with business customers, and your head hurts with the complexity of what they want you to implement, then maybe you should consider a rule engine such as Drools. This article will show you how you can do this in an enterprise Java application.

Frameworks All the Way Down

Most enterprise Java developers already have their favorite frameworks. In no particular order, these include presentation frameworks (Struts, JSF, Cocoon, and Spring), persistence frameworks (JDO, Hibernate, Cayenne, and Entity Beans) and structural frameworks (EJB, Spring again, Pico, and Excalibur), as well as many others. Each framework does one very useful thing (or more), and gives developers a lot of instant "out of the box" functionality. Deploying an application using frameworks means you avoid a lot of the boring bits and concentrate on what is really needed.

Until now, there was a gap in what the frameworks were able to do, in that business logic had no framework. Tools like EJB and Spring are good, but have little to say about how to organize your if ... then statements! Adding Drools to your developer toolbox means that it is now possible to build an application with "frameworks all the way down." Figure 1 shows a diagram of such an application.

Figure 1
Figure 1. Frameworks for Java applications

This article will build on what we already know of the Drools framework and allow us to build such an application.

When Should I Use a Rule Engine?


It's almost a cliche in software engineering to say that "if you have a hammer, everything looks like a nail." While rule engines can solve a lot of problems for us, it is worth considering whether a rule engine is really appropriate for our enterprise Java application. Some questions to ask are:

  • How complex is my application? For applications that shuffle data to and from a database, but not much more, it is probably best not to use a rule engine. However, where there is even a moderate amount of processing implemented in Java, it is worthwhile to consider the use of Drools. This is because most applications develop complexity over time, and Drools will let you cope easily with this.
  • What is the lifetime of my application? The answer to this is often "surprisingly long"--remember the mainframe programmers who thought their applications wouldn't be around for the year 2000? Using a rule engine pays off, especially in the medium to long term. As this article demonstrates, even prototypes can benefit from the combination of Drools and agile methods to take the "prototype" into production.
  • Will my application need to change? The only sure thing about your requirements is that they will change, either during or just after development. Drools helps you cope with this by specifying the business rule in one or more easy-to-configure XML files.

What About Performance?

If you're writing an enterprise application, chances are that it will need to scale to hundreds, if not thousands, of users. You know that existing Java and J2EE applications can do this, but how will a application using Drools cope with this pressure? The answer is "surprisingly well." While most developers hate to "lose control" and rely on other people's code (i.e., a framework), consider the points below--not only should your application be as fast as "traditional" coding methods, but Drools may even make your application run faster:

  • Avoids badly written code: Drools guides developers to do "the right thing." You may be sure the code you are writing is good, but would you say the same for the code of your co-developers? Using a framework makes it easier to write good, fast code.
  • Optimized framework: How often have you seen business logic that repeatedly accesses a database for the same information, slowing down the entire application? Used correctly, Drools can remember not only the information, but also the results of previous tests using this information, giving the entire application a speed boost.
  • Rete algorithm: Many times we apply "if" conditions that we didn't really need. The Rete algorithm, as implemented by Drools, replaces all of the if ... then statements with an optimized network. It is important to note that the Rete algorithm involves a tradeoff between using more memory to reduce delays at run time. While this isn't a factor in most modern servers, we wouldn't yet recommend deploying Drools on your mobile phone!


Where Were We?

In our previous article, we wrote a simple stock trading application based around the Drools engine. We implemented various business rules, showed how we could rapidly change the rules to meet changing business requirements, and wrote JUnit tests to give us a high degree of confidence that the system would act as it was supposed to. However, the application as we left it had little or no user interface, and used hard-coded data instead of a database. To evolve our application into something that is more enterprise level, we need to add two main things:
  • Some sort of user interface, ideally based one of the standard web-presentation frameworks.
  • A Data Access Object (DAO) to let Drools work with a database (or other back end system).

Calling the Rule Engine from a Presentation Framework

Most enterprise Java applications are accessed using a web interface, and one of the most widely adopted web-presentation frameworks is Struts, from Apache. Ideally, we'll write our application so that the presentation layer knows about the business layer underneath, but not the other way around. This has the advantage not only of allowing us to change the presentation framework at a later date (e.g., to an Ajax or web service interface), but also means the code examples give should be readily applicable to other web frameworks like Spring.


The following code snippet demonstrates how to call the business logic tier (using the rule engine) from the web presentation layer. The code uses the results to decide which page to display. In this sample, we use a Struts action, but the code is similar for any other web framework or even a servlet or a JSP page. This snippet works with a supporting struts-config.xml, JSP pages to post/display data, and a way of generating the WAR file for deployment. The snippet shows how to integrate the rule engine with the web framework.


import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import BusinessLayer;
/**
* Sample Struts action with Pseudocode
*/
public class SampleStrutsAction extends Action{
/**
* Standard Struts doPerfom method
*/
public ActionForward doPerform(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws InvalidEntryPointException {
//Local Variables
StockOffer userOffer =null;
//Get any previous values from the session
userOffer=(StockOffer)request.getSession()
.getAttribute("PREVIOUS_STOCK_OFFER");
//create this object if it is null
if (null==userOffer){
userOffer = new StockOffer();
}
//Update with the incoming values
//These values match those on the form
userOffer.setStockName(request.
getParameterValue("STOCK_NAME"));
userOffer.setStockPrice(request
.getParameterValue("STOCK_PRICE"));
userOffer.setStockQuantity(request
.getParameterValue("STOCK_QTY"));
//Reset the output value
userOffer.setRecommendPurchase(null);
//Call the Business Layer
BusinessLayer
.evaluateStockPurchase(userOffer);
//Forward to the appropriate page
if ("YES".equals(
testOffer.getRecommendPurchase()){
return mapping.findForward("YES_WEB_PAGE");
}
//otherwise default to the no page
return mapping.findForward("NO_WEB_PAGE");
}
}

There are a couple of things going on this sample. Often, we build up the data we need from the user over several web pages, so this sample shows how we can achieve this by retrieving the StockOffer object that we have previously stored in the web server session. Next, we update the StockOffer with any values that the user may have changed on the web page. We then reset the recommendPurchase flag to clear any previous results before we call the business logic layer. Finally, we take the response of the business logic and use it to decide which page to forward the user to.

In this example, note how we split the business logic (yes/no on whether or not to buy a stock) from the presentation logic (decide which page to go to). This allows us to reuse our business rules across several different applications In addition, take look at how the state information (i.e., things that the user has already told us) is stored in the StockOffer object/web server session, and not in the business layer. By keeping the business layer stateless in this way, we make the entire application much more scalable and performant.


Integrating the Rule Engine with the Database Layer

So far, our application has a web presentation layer and a rules engine for the business layer, but no means of getting data to and from a database. This section gives an example of how to do this. We base our example on the Data Access Object (DAO) pattern, where we encapsulate all code that "talks" to the database (or back-end data source) in one pluggable, configurable class. As such, the example is applicable to other persistence frameworks, such as Hibernate and Cayenne.


Some important points about the way we want to organize the data layer are:

  • Only the business layer should talk to the data layer; if a class in the presentation layer (front end) wants some data, it should pass through the business layer first. This helps makes our code easier to organize and read.
  • As far as possible, we should keep our data layer stateless--we should hold client data elsewhere (e.g., in the server session at the web front end, as per the previous example). This is distinct from caching of data, which we can do at this level. The difference between the two is state information is often user-specific, while data we cache at the data access layer is mainly sharable across the application. Organizing our layer in this way increases performance.
  • We should allow the business logic to decide if data is needed or not--if not needed, the call to get the data should not be made.

To implement our simple Data Access Object, we create three new objects: StockNameDao, DaoImplementation, and DaoFactory.

StockNameDao is an interface that defines two methods: getStockNames() returns a list of the stock names that we deal with, and isOnStockList() checks that a given stock is on the list of stocks that we deal with. Our business layer will call these methods as and when it needs the information.

DaoImplementation is an actual implementation of StockNameDao. In this case the values are hard-coded, but we could have queried a database or accessed an information system like Bloomberg via a web service.

DaoFactory is what we use to create an appropriate instance of StockNameDao. The advantage this approach has over creating the class directly is that it allows us to configure what DAO implementation we use at runtime (frameworks like Spring are especially good at this). One factory can return many types of DAOs (e.g., StockNameDao, StockPriceDao, StockHistoryDao), which means we can pass in our DaoFactory, and let the individual rules decide on the data and DAOs that they require.

Here's what the StockNameDao interface looks like:


/**
* Defines a Data Access Object - a non data
* source specific way of obtaining data.
*/
public interface StockNameDao {
/**
* Get a list of stock names for the application
* @return String[] array of stock names
*/
public String [] getStockNames();
/**
* Check if our stock is on the list
* @param stockName
* @return
*/
public boolean isOnStockList(String stockName);
}

And here's the DaoImplementation:


/**
* Concrete Definition of a Data Access Object
*/
public class DaoImplementation
implements StockNameDao {
/**
* Constructor with package level access only
* to encourage use of factory method
*
*/
DaoImplementation(){}
/**
* Get a list of stock names for the app.
* This is a hard coded sample
* normally we would get this from
* a database or other datasource.
* @return String[] array of stock names
*/
public String[] getStockNames() {
String[] stockNames=
{"XYZ","ABC","MEGACORP","SOMEOTHERCOMPANY"};
return stockNames;
}
/**
* Check if our stock is on the list
* @param stockName
* @return true / false as appropriate
*/
public boolean isOnStockList(String stockName){
//Get our list of stocks
String stockList[] = getStockNames();
//Loop and see if our stock is on it
// done this way for clarity . not speed!
for (int a=0; a<stockList.length;a++){
if(stockList[a].equals(stockName)){
return true;
}
}
//Default return value
return false;
}
}

The simple DaoFactory just returns a DaoImplementation:


package net.firstpartners.rp;
/**
* Factory Method to get the Data Access Object.
* Normally we could replace this with a
* framework like Spring or Hibernate
*/
public class DaoFactory {
/**
* Get the stock name Dao
* This sample is hardcoded - in reality
* we would make this configurable / cache
* instances of the Dao as appropriate
* @return an instance of StockNameDao
*/
public static StockNameDao getStockDao(){
return new DaoImplementation();
}
}


Now that we have our simple DAO implementation to serve as our database layer, how do we integrate it with the Drools business layer? The updated business rules file, BusinessLayer.xml, shows us how.



<?xml version="1.0"?>
<rule-set name="BusinessRulesSample"
xmlns="http://drools.org/rules"
xmlns:java="http://drools.org/semantics/java"
xmlns:xs="
http://www.w3.org/2001/XMLSchema-instance"
xs:schemaLocation="
http://drools.org/rules rules.xsd
http://drools.org/semantics/java java.xsd">
<!-- Import the Java Objects that
we refer to in our rules -->
<java:import>
java.lang.Object
</java:import>
<java:import>
java.lang.String
</java:import>
<java:import>
net.firstpartners.rp.StockOffer
</java:import>
<java:import>
net.firstpartners.rp.DaoFactory
</java:import>
<java:import>
net.firstpartners.rp.StockNameDao
</java:import>
<!-- Application Data not associated -->
<!-- with any particular rule -->
<!-- In this case it's our factory -->
<!-- object which gives us back -->
<!-- a handle to whatever Dao (Data -->
<!-- access object) that we need -->
<application-data
identifier="daoFactory">DaoFactory
</application-data>
<!-- A Java (Utility) function -->
<! we reference in our rules -->
<java:functions>
public void printStock(
net.firstpartners.rp.StockOffer stock)
{
System.out.println(
"Name:"+stock.getStockName()
+" Price: "+stock.getStockPrice()
+" BUY:"+stock.getRecommendPurchase());
}
</java:functions>
<!-- Check for XYZ Corp-->
<rule name="XYZCorp" salience="-1">
<!-- Parameters we can pass into-->
<!-- the business rule -->
<parameter identifier="stockOffer">
<class>StockOffer</class>
</parameter">
<!-- Conditions that must be met for -->
<!-- business rule to fire -->
<java:condition>
stockOffer.getStockName().equals("XYZ")
</java:condition>
<java:condition>
stockOffer.getRecommendPurchase() == null
</java:condition>
<java:condition>
stockOffer.getStockPrice() > 10
</java:condition>
<!-- What happens when the business -->
<!-- rule is activated -->
<java:consequence>
stockOffer.setRecommendPurchase(
StockOffer.NO);
printStock(stockOffer);
</java:consequence>
</rule>
<!-- Ensure that negative prices -->
<!-- are not accepted -->
<rule name="Stock Price Not Negative">
<!-- Parameters we can pass into the -->
<!-- business rule -->
<parameter identifier="stockOffer">
<class>StockOffer</class>
</parameter>
<!-- Conditions for rule to fire -->
<java:condition>
stockOffer.getStockPrice() < 0
</java:condition>
<!--When rule is activated then ... -->
<java:consequence>
stockOffer.setRecommendPurchase
(StockOffer.NO);
printStock(stockOffer);
</java:consequence>
</rule>
<!-- Check for Negative Prices-->
<rule name="Stock Price Low Enough">
<!-- Parameters for the rule -->
<parameter identifier="stockOffer">
<class>StockOffer</class>
</parameter>
<!-- Now uses Dao to get stock list -->
<java:condition>
daoFactory.getStockDao().isOnStockList(
stockOffer.getStockName())
</java:condition>
<java:condition>
stockOffer.getRecommendPurchase() == null
</java:condition>
<java:condition>
stockOffer.getStockPrice() < 100
</java:condition>
<!-- When rule is activated do this -->
<java:consequence>
stockOffer.setRecommendPurchase(
StockOffer.YES);
printStock(stockOffer);
</java:consequence>
</rule>
</rule-set>

There are several changes to this file to integrate the data access layer with our business rules:

  • At the top of the file, we have several new <java:import> statements to reference the StockNameDao, DaoImplementation, and DaoFactory classes that we added to the system.
  • We have a new tag, <application-data>, which assigns an instance of the DaoFactory class to a variable. <application-data> tags are similar to parameters, except they apply to all business rules, and not just one.
  • The Stock Price Low Enough rule has a new condition, which uses the DaoFactory and StockNameDao to check if the stock is on the list of those that we deal with.

We run our BusinessRulesTest (simulator) again. The simulator/unit tests run OK, since even though we have changed the structure of the program, we haven't (yet) changed what it does. From looking at the output logs, we can see that our business rules are using StockNameDao as part of their evaluations, and that DaoImplementation.isOnStockList() is being called.

While this example shows the reading of information from a data source, the principles are the same for writing information, if that is what a rule has decided should be done. The differences would be that our DAO would have a setSomeInformation() method, and that the method would be called in the <java:consequence> part of the business rule, once the specific conditions had been met.

Summary

In this article, we showed that most Java server applications have three tiers: presentation, business logic, and data persistence. While the use of frameworks is widely accepted in the presentation and persistence layers, until now no framework has been available to encapsulate low-level business logic. As we've seen in the examples, Drools and JSR-94 are ideal candidates for reducing the complexity and speeding the development of Java applications. I hope that these examples inspire you to take a closer look at rule engines, and that they save many hours of development and maintenance time in your applications.

Resources

Paul Browne , based in Dublin, Ireland, has been consulting in enterprise Java with FirstPartners.net for almost seven years.



鍝煎摷 2007-09-03 17:28 鍙戣〃璇勮
]]>
Implement business logic with the Drools rules enginehttp://www.tkk7.com/hengheng123456789/archive/2007/09/03/142392.html鍝煎摷鍝煎摷Mon, 03 Sep 2007 09:24:00 GMThttp://www.tkk7.com/hengheng123456789/archive/2007/09/03/142392.htmlhttp://www.tkk7.com/hengheng123456789/comments/142392.htmlhttp://www.tkk7.com/hengheng123456789/archive/2007/09/03/142392.html#Feedback0http://www.tkk7.com/hengheng123456789/comments/commentRss/142392.htmlhttp://www.tkk7.com/hengheng123456789/services/trackbacks/142392.html闃呰鍏ㄦ枃

鍝煎摷 2007-09-03 17:24 鍙戣〃璇勮
]]>
Drools Documentationhttp://www.tkk7.com/hengheng123456789/archive/2007/09/03/142366.html鍝煎摷鍝煎摷Mon, 03 Sep 2007 08:36:00 GMThttp://www.tkk7.com/hengheng123456789/archive/2007/09/03/142366.htmlhttp://www.tkk7.com/hengheng123456789/comments/142366.htmlhttp://www.tkk7.com/hengheng123456789/archive/2007/09/03/142366.html#Feedback0http://www.tkk7.com/hengheng123456789/comments/commentRss/142366.htmlhttp://www.tkk7.com/hengheng123456789/services/trackbacks/142366.html闃呰鍏ㄦ枃

鍝煎摷 2007-09-03 16:36 鍙戣〃璇勮
]]>
BI鐩稿叧鐨勫紑婧愬伐鍏鳳紙杞級http://www.tkk7.com/hengheng123456789/archive/2006/12/30/90982.html鍝煎摷鍝煎摷Sat, 30 Dec 2006 04:26:00 GMThttp://www.tkk7.com/hengheng123456789/archive/2006/12/30/90982.htmlhttp://www.tkk7.com/hengheng123456789/comments/90982.htmlhttp://www.tkk7.com/hengheng123456789/archive/2006/12/30/90982.html#Feedback0http://www.tkk7.com/hengheng123456789/comments/commentRss/90982.htmlhttp://www.tkk7.com/hengheng123456789/services/trackbacks/90982.html 杞嚜錛?a >http://challenger11.blogdriver.com/challenger11/1241587.html

鎴戜滑閮界煡閬撯滅瀻瀛愭懜璞♀濈殑鏁呬簨銆備笉鍚岀殑鐬庡瓙瀵瑰ぇ璞$殑璁よ瘑涓嶅悓錛屽洜涓轟粬浠彧璁よ瘑浜嗚嚜宸辨懜鍒扮殑鍦版柟銆傝屼紒涓氬鏋滆閬垮厤閲嶇姱榪欐牱鐨勯敊璇紝閭e氨紱諱笉寮鍟嗗姟鏅鴻兘錛圔I錛夈備笓瀹惰涓猴紝BI瀵逛簬浼佷笟鐨勯噸瑕佹у氨鍍忚仾鏄庢墠鏅哄浜庝釜浜虹殑閲嶈鎬с傛緹庝紒涓氱殑緇忛獙涔熻瘉鏄庯紝浼佷笟閬垮厤鏃犵煡鍜屼竴鐭ュ崐瑙e嵄闄╃殑鏈夋晥鎵嬫灝辨槸鍟嗗姟鏅鴻兘銆傚晢鍔℃櫤鑳芥棬鍦ㄥ厖鍒嗗埄鐢ㄤ紒涓氬湪鏃ュ父緇忚惀榪囩▼涓敹闆嗙殑澶ч噺鏁版嵁鍜岃祫鏂欙紝騫跺皢瀹冧滑杞寲涓轟俊鎭拰鐭ヨ瘑鏉ュ厤闄ゅ悇縐嶆棤鐭ョ姸鎬佸拰鐬庣寽琛屼負銆?/b>聽

鏀寔BI鐨勫紑婧愬伐鍏鋒暟閲忎紬澶氾紝浣嗘槸澶у鏁扮殑宸ュ叿閮芥槸鍋忛噸鏌愭柟闈㈢殑銆備緥濡傦紝CloverETL鍋忛噸ETL錛孞Pivot鍋忛噸澶氱淮鍒嗘瀽灞曠幇錛孧ondrian鏄疧LAP鏈嶅姟鍣ㄣ傝孊ee銆丳entaho鍜孲pagoBI絳夐」鐩垯閽堝鍟嗗姟鏅鴻兘闂鎻愪緵浜嗗畬鏁寸殑瑙e喅鏂規銆?/font>

ETL 宸ュ叿

ETL寮婧愬伐鍏蜂富瑕佸寘鎷珻loverETL鍜孫ctupus絳夈?

錛?錛塁loverETL鏄竴涓狫ava鐨凟TL妗嗘灦錛岀敤鏉ヨ漿鎹㈢粨鏋勫寲鐨勬暟鎹紝鏀寔澶氱瀛楃闆嗕箣闂寸殑杞崲錛堝ASCII銆乁TF-8鍜孖SO-8859-1絳夛級錛涙敮鎸丣DBC錛屽悓鏃舵敮鎸乨Base鍜孎oxPro鏁版嵁鏂囦歡錛涙敮鎸佸熀浜嶺ML鐨勮漿鎹㈡弿榪般?

(2)Octupus鏄竴涓熀浜嶫ava鐨凟TL宸ュ叿錛屽畠涔熸敮鎸丣DBC鏁版嵁婧愬拰鍩轟簬XML鐨勮漿鎹㈠畾涔夈侽ctupus鎻愪緵閫氱敤鐨勬柟娉曡繘琛屾暟鎹漿鎹紝鐢ㄦ埛鍙互閫氳繃瀹炵幇杞崲鎺ュ彛鎴栬呬嬌鐢↗script浠g爜鏉ュ畾涔夎漿鎹㈡祦紼嬨?

OLAP鏈嶅姟鍣?

(1)Lemur涓昏闈㈠悜HOLAP錛岃櫧鐒墮噰鐢–++緙栧啓錛屼絾鏄彲浠ヨ鍏朵粬璇█鐨勭▼搴忔墍璋冪敤銆侺emur鏀寔鍩烘湰鐨勬搷浣滐紝濡傚垏鐗囥佸垏鍧楀拰鏃嬭漿絳夊熀鏈搷浣溿?

(2)Mondrian闈㈠悜ROLAP鍖呭惈4灞傦細琛ㄧず灞傘佽綆楀眰銆佽仛闆嗗眰銆佸瓨鍌ㄥ眰銆?

鈼?琛ㄧず灞傦細鎸囨渶緇堝憟鐜板湪鐢ㄦ埛鏄劇ず鍣ㄤ笂鐨勪互鍙婁笌鐢ㄦ埛涔嬮棿鐨勪氦浜掞紝鏈夎澶氭柟娉曟潵灞曠幇澶氱淮鏁版嵁錛屽寘鎷暟鎹忚琛ㄣ侀ゼ銆佹煴銆佺嚎鐘跺浘銆?

鈼?璁$畻灞傦細鍒嗘瀽銆侀獙璇併佹墽琛孧DX鏌ヨ銆?

鈼?鑱氶泦灞傦細涓涓仛闆嗘寚鍐呭瓨涓竴緇勮綆楀?cell)錛岃繖浜涘奸氳繃緇村垪鏉ラ檺鍒躲傝綆楀眰鍙戦佸崟鍏冭姹傦紝濡傛灉璇鋒眰涓嶅湪緙撳瓨涓紝鎴栬呬笉鑳介氳繃鏃嬭漿鑱氶泦瀵煎嚭鐨勮瘽錛岄偅涔堣仛闆嗗眰鍚戝瓨鍌ㄥ眰鍙戦佽姹傘傝仛鍚堝眰鏄竴涓暟鎹紦鍐插眰錛屼粠鏁版嵁搴撴潵鐨勫崟鍏冩暟鎹紝鑱氬悎鍚庢彁渚涚粰璁$畻灞傘傝仛鍚堝眰鐨勪富瑕佷綔鐢ㄦ槸鎻愰珮緋葷粺鐨勬ц兘銆?

鈼?瀛樺偍灞傦細鎻愪緵鑱氶泦鍗曞厓鏁版嵁鍜岀淮琛ㄧ殑鎴愬憳銆傚寘鎷笁縐嶉渶瑕佸瓨鍌ㄧ殑鏁版嵁錛屽垎鍒槸浜嬪疄鏁版嵁銆佽仛闆嗗拰緇淬?

OLAP瀹㈡埛绔?

JPivot鏄疛SP椋庢牸鐨勬爣絳懼簱錛岀敤鏉ユ敮鎸丱LAP琛紝浣跨敤鎴峰彲浠ユ墽琛屽吀鍨嬬殑OLAP鎿嶄綔錛屽鍒囩墖銆佸垏鍧椼佷笂閽匯佷笅閽葷瓑銆侸Pivot浣跨敤Mondrian鏈嶅姟鍣紝鍒嗘瀽緇撴灉鍙互瀵煎嚭涓篍xcel鎴朠DF鏂囦歡鏍煎紡銆?

鏁版嵁搴撶鐞嗙郴緇?

涓昏鐨勫紑婧愬伐鍏峰寘鎷琈onetDB銆丮ySQL銆丮axDB鍜孭ostgreSQL絳夈傝繖浜涙暟鎹簱閮借璁捐鐢ㄦ潵鏀寔BI鐜銆侻ySQL銆丮axDB鍜孭ostgreSQL鍧囨敮鎸佸崟鍚戠殑鏁版嵁澶嶅埗銆侭izGres欏圭洰鐨勭洰鐨勫湪浜庝嬌PostgreSQL鎴愪負鏁版嵁浠撳簱鍜?BI鐨勫紑婧愭爣鍑嗐侭izGres涓築I鐜鏋勫緩涓撶敤鐨勫畬鏁存暟鎹簱騫沖彴銆?

瀹屾暣鐨凚I寮婧愯В鍐蟲柟妗?

1.Pentaho 鍏徃鐨凱entaho BI 騫沖彴

瀹冩槸涓涓互嫻佺▼涓轟腑蹇冪殑銆侀潰鍚戣В鍐蟲柟妗堢殑妗嗘灦錛屽叿鏈夊晢鍔℃櫤鑳界粍浠躲侭I 騫沖彴鏄互嫻佺▼涓轟腑蹇冪殑錛屽叾涓灑鎺у埗鍣ㄦ槸涓涓伐浣滄祦寮曟搸銆傚伐浣滄祦寮曟搸浣跨敤嫻佺▼瀹氫箟鏉ュ畾涔夊湪 BI 騫沖彴涓婃墽琛岀殑鍟嗗姟鏅鴻兘嫻佺▼銆傛祦紼嬪彲浠ュ緢瀹規槗琚畾鍒訛紝涔熷彲浠ユ坊鍔犳柊鐨勬祦紼嬨侭I 騫沖彴鍖呭惈緇勪歡鍜屾姤琛紝鐢ㄤ互鍒嗘瀽榪欎簺嫻佺▼鐨勬ц兘銆侭I 騫沖彴鏄潰鍚戣В鍐蟲柟妗堢殑錛屽鉤鍙扮殑鎿嶄綔鏄畾涔夊湪嫻佺▼瀹氫箟鍜屾寚瀹氭瘡涓椿鍔ㄧ殑 action 鏂囨。閲屻傝繖浜涙祦紼嬪拰鎿嶄綔鍏卞悓瀹氫箟浜嗕竴涓晢鍔℃櫤鑳介棶棰樼殑瑙e喅鏂規銆傝繖涓?BI 瑙e喅鏂規鍙互寰堝鏄撳湴闆嗘垚鍒板鉤鍙板閮ㄧ殑鍟嗕笟嫻佺▼銆備竴涓В鍐蟲柟妗堢殑瀹氫箟鍙互鍖呭惈浠繪剰鏁伴噺鐨勬祦紼嬪拰鎿嶄綔銆?

BI騫沖彴鍖呮嫭涓涓?BI 妗嗘灦銆丅I 緇勪歡銆佷竴涓?BI 宸ヤ綔鍙板拰妗岄潰鏀朵歡綆便侭I 宸ヤ綔鍙版槸涓濂楄璁″拰綆$悊宸ュ叿錛岄泦鎴愬埌Eclipse鐜銆傝繖浜涘伐鍏峰厑璁稿晢涓氬垎鏋愪漢鍛樻垨寮鍙戜漢鍛樺垱寤烘姤琛ㄣ佷華琛ㄧ洏銆佸垎鏋愭ā鍨嬨佸晢涓氳鍒欏拰 BI 嫻佺▼銆侾entaho BI 騫沖彴鏋勫緩浜庢湇鍔″櫒銆佸紩鎿庡拰緇勪歡鐨勫熀紜涔嬩笂錛屽寘鎷琂2EE 鏈嶅姟鍣ㄣ佸畨鍏ㄤ笌鏉冮檺鎺у埗銆乸ortal銆佸伐浣滄祦銆佽鍒欏紩鎿庛佸浘琛ㄣ佸崗浣溿佸唴瀹圭鐞嗐佹暟鎹泦鎴愩佸緇村垎鏋愬拰緋葷粺寤烘ā絳夊姛鑳姐傝繖浜涚粍浠剁殑澶ч儴鍒嗘槸鍩轟簬鏍囧噯鐨勶紝鍙嬌鐢ㄥ叾浠栦駭鍝佹浛鎹箣銆?

2.ObjectWeb

璇ラ」鐩繎鏃ュ彂甯冧簡SpagoBi 1.8鐗堟湰銆係pagoBi 鏄竴嬈懼熀浜嶮ondrain+JProvit鐨凚I鏂規錛岃兘澶熼氳繃OpenLaszlo浜х敓瀹炴椂鎶ヨ〃錛屼負鍟嗗姟鏅鴻兘欏圭洰鎻愪緵浜嗕竴涓畬鏁村紑婧愮殑瑙e喅鏂規錛屽畠娑電洊浜嗕竴涓狟I緋葷粺鎵鏈夋柟闈㈢殑鍔熻兘錛屽寘鎷細鏁版嵁鎸栨帢銆佹煡璇€佸垎鏋愩佹姤鍛娿丏ashboard浠〃鏉跨瓑絳夈係pagoBI浣跨敤鏍稿績緋葷粺涓庡姛鑳芥ā鍧楅泦鎴愮殑鏋舵瀯錛岃繖鏍峰湪紜繚騫沖彴紼沖畾鎬т笌鍗忚皟鎬х殑鍩虹涓婂張淇濊瘉浜嗙郴緇熷叿鏈夊緢寮虹殑鎵╁睍鑳藉姏銆傜敤鎴鋒棤闇浣跨敤SpagoBI鐨勬墍鏈夋ā鍧楋紝鑰屾槸鍙互鍙埄鐢ㄥ叾涓殑涓浜涙ā鍧椼?

SpagoBI浣跨敤浜嗚澶氬凡鏈夌殑寮婧愯蔣浠訛紝濡係pago鍜孲pagosi絳夈傚洜姝わ紝SpagoBI闆嗘垚浜?Spago鐨勭壒寰佸拰鎶鏈壒鐐癸紝浣跨敤瀹冧滑綆$悊鍟嗗姟鏅鴻兘瀵硅薄錛屽鎶ヨ〃銆丱LAP鍒嗘瀽銆佷華琛ㄧ洏銆佽鍒嗗崱浠ュ強鏁版嵁鎸栨帢妯″瀷絳夈係pagoBI鏀寔BI緋葷粺鐨勭洃鎺х鐞嗭紝鍖呮嫭鍟嗗姟鏅鴻兘瀵硅薄鐨勬帶鍒躲佹牎楠屻佽璇佸拰鍒嗛厤嫻佺▼銆係pagoBI閲囩敤Portalet鎶鏈皢鎵鏈夌殑BI瀵硅薄鍙戝竷鍒扮粓绔敤鎴鳳紝鍥犳BI瀵硅薄灝卞彲浠ラ泦鎴愬埌涓虹壒瀹氱殑浼佷笟闇姹傝屽凡緇忛夋嫨濂界殑Portal緋葷粺涓幓銆?

3.Bee欏圭洰

璇ラ」鐩槸涓濂楁敮鎸佸晢鍔℃櫤鑳介」鐩疄鏂界殑宸ュ叿濂椾歡錛屽寘鎷珽TL宸ュ叿鍜孫LAP 鏈嶅姟鍣ㄣ侭ee鐨凟TL宸ュ叿浣跨敤鍩轟簬Perl鐨凚EI錛岄氳繃鐣岄潰鎻忚堪嫻佺▼錛屼互XML褰㈠紡榪涜瀛樺偍銆傜敤鎴峰繀欏誨杞崲榪囩▼榪涜緙栫爜銆侭ee鐨凴OLAP 鏈嶅姟鍣ㄤ繚璇佸閫歋QL 鐢熸垚鍜屽己鏈夊姏鐨勯珮閫熺紦瀛樼鐞?浣跨敤MySQL鏁版嵁搴撶鐞嗙郴緇?銆俁OLAP鏈嶅姟鍣ㄩ氳繃SOAP搴旂敤鎺ュ彛鎻愪緵涓板瘜鐨勫鎴峰簲鐢ㄣ俉eb Portal浣滀負涓昏鐨勭敤鎴鋒帴鍙o紝閫氳繃Web嫻忚鍣ㄨ繘琛屾姤琛ㄨ璁°佸睍紺哄拰綆$悊鎺у埗錛屽垎鏋愮粨鏋滃彲浠ヤ互Excel銆丳DF銆丳NG銆丳owerPoint銆?text鍜孹ML絳夊縐嶅艦寮忓鍑恒?

Bee欏圭洰鐨勭壒鐐瑰湪浜庯細

鈼?綆鍗曞揩鎹風殑鏁版嵁璁塊棶錛?

鈼?鏀寔棰勫厛瀹氫箟鎶ヨ〃鍜屽疄鏃舵煡璇紱

鈼?閫氳繃鎷栨嫿鏂瑰紡杞繪澗瀹炵幇鎶ヨ〃瀹氬埗錛?

鈼?瀹屾暣鎶ヨ〃鐨勮交鏉炬帶鍒訛紱

鈼?浠ヨ〃鍜屽浘榪涜楂樿川閲忕殑鏁版嵁灞曠ず銆?/p>

鍝煎摷 2006-12-30 12:26 鍙戣〃璇勮
]]>
2006錛氫腑鍥紹I甯傚満鐨勫崄澶у彂灞曡秼鍔?/title><link>http://www.tkk7.com/hengheng123456789/archive/2006/09/08/68509.html</link><dc:creator>鍝煎摷</dc:creator><author>鍝煎摷</author><pubDate>Fri, 08 Sep 2006 06:18:00 GMT</pubDate><guid>http://www.tkk7.com/hengheng123456789/archive/2006/09/08/68509.html</guid><wfw:comment>http://www.tkk7.com/hengheng123456789/comments/68509.html</wfw:comment><comments>http://www.tkk7.com/hengheng123456789/archive/2006/09/08/68509.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/hengheng123456789/comments/commentRss/68509.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/hengheng123456789/services/trackbacks/68509.html</trackback:ping><description><![CDATA[ <p> <font class="font14">聽聽聽 2006騫寸殑BI浜у搧灝嗘妸鏁版嵁浠撳簱寤烘ā浠ュ強鏁版嵁鎸栨帢絳夋妧鏈疄璐ㄦу湴搴旂敤榪涙潵銆傚悓鏃禕I鎶鏈皢涓嶦RP銆丆RM銆佷紒涓氶棬鎴風瓑鎶鏈浉铻嶅悎錛屽艦鎴愰泦鎴愬寲鐨勪駭鍝併?</font> </p> <p> <font class="font14">聽聽聽 緇忚繃2005騫寸殑寮哄姴鍙戝睍錛屼腑鍥藉晢涓氭櫤鑳斤紙BI錛夎蔣浠跺競鍦洪攢鍞杈懼埌10.15浜垮厓浜烘皯甯侊紝騫村闀跨巼杈懼埌54.96錛呫?006騫達紝闅忕潃灞ヨ鍔犲叆WTO鍏ㄩ潰寮鏀懼競鍦烘壙璇烘椂闂寸殑涓磋繎鍜屼腑鍥戒紒涓氬浗闄呭寲鐨勬浼愬姞蹇互鍙婃斂搴滆亴鑳界殑鍏ㄩ潰杞彉錛屼腑鍥介噾铻嶃佺數淇°佹斂搴溿侀浂鍞佸埗閫犵瓑琛屼笟瀵瑰晢涓氭櫤鑳芥妧鏈簲鐢ㄧ殑闇姹傚叏闈㈢垎鍙戙傝禌榪【闂璁?006騫翠腑鍥紹I杞歡甯傚満瑙勬ā灝嗚秴榪?6浜垮厓浜烘皯甯?瑙佸浘1)銆?<br />聽聽聽 <br />聽聽聽 鍥藉唴鍟嗕笟鏅鴻兘杞歡甯傚満灝嗗憟鐜板崄澶у彂灞曡秼鍔褲?<br />聽聽聽 <br />聽聽聽 瓚嬪娍涓:铻嶅悎澶氱鎶鏈殑闆嗘垚浜у搧鍑虹幇銆?<br />聽聽聽 <br />聽聽聽 2006騫碆I浜у搧鎶鏈殑鍙戝睍瓚嬪娍鏄細鐢辯幇鏈夌殑鍒濇搴旂敤濡傛姤琛ㄥ垎鏋愩佹暟鎹泦鎴愶紝鍚戞繁搴﹀拰騫垮害搴旂敤鍙戝睍錛屾暟鎹粨搴撳緩妯″拰鏁版嵁鎸栨帢絳夋妧鏈殑搴旂敤灝嗗疄璐ㄦф帹寮銆?<br />聽聽聽 <br />聽聽聽 2006騫寸殑BI浜у搧灝嗘妸鏁版嵁浠撳簱寤烘ā浠ュ強鏁版嵁鎸栨帢絳夋妧鏈疄璐ㄦу湴搴旂敤榪涙潵銆傚悓鏃禕I鎶鏈皢涓嶦RP銆丆RM銆佷紒涓氶棬鎴風瓑鎶鏈浉铻嶅悎錛屽艦鎴愰泦鎴愬寲鐨勪駭鍝併傚挨鍏跺湪闈㈠悜涓皬浼佷笟鐢ㄦ埛鐨勪紒涓氱鐞嗚蔣浠舵柟妗堜腑錛孍RP銆丆RM鍘傚晢浼氬皢BI鏂規宓屽叆鍒拌嚜宸辯殑ERP鎴朇RM緋葷粺涓傝屾暣鍚堜簡浼佷笟闂ㄦ埛鐨凚I浜у搧錛屽湪浜轟滑緙哄皯鏃墮棿銆佸繀欏誨皢娉ㄦ剰鍔涙斁鍦ㄧ湡姝i噸瑕佺殑鍐崇瓥瑙勫垯涓婄殑騫翠唬錛屽彲浠ュ噺灝戜綔鍐崇瓥鏃跺繀欏誨垎鏋愮殑鏁版嵁閲忋?<br />聽聽聽 <br />聽聽聽 瓚嬪娍浜?BI浜у搧鐨勬暣浣撲環鏍煎湪閫愭涓嬮檷銆?<br />聽聽聽 <br />聽聽聽 鍦ㄤ環鏍兼柟闈紝BI杞歡涓鐩村浜庨珮绔環浣嶏紝鎻愪緵緇欎俊鎭寲寤鴻鈥滆吹鏃忊濅嬌鐢ㄣ傝屼互涓皬浼佷笟涓轟唬琛ㄧ殑涓佷綆绔鎴鳳紝涔熷笇鏈涜姳涓婂嚑鍗佷竾灝卞彲浠ヤ笂涓濂桞I杞歡銆傚洜姝ゆ棤璁烘槸鍥介檯BI鍘傚晢榪樻槸鍥藉唴BI浼佷笟閮介拡瀵歸珮銆佷腑銆佷綆绔敤鎴峰憟鐜板嚭涓嶅悓鐨勪環鏍肩瓥鐣ワ紝鎬諱綋浠蜂綅鍛堢幇涓嬮檷瓚嬪娍銆傝繖涓哄浗鍐呮洿騫垮ぇ鐨勪紒涓氬簲鐢˙I浜у搧鎻愪緵浜嗗彲鑳姐?<br />聽聽聽 <br />聽聽聽 瓚嬪娍涓?楂樼甯傚満褰掑睘鍥介檯錛屼腑浣庣钀芥埛鍥藉唴銆?<br />聽聽聽 <br />聽聽聽 涓浗鐨凚I甯傚満浠庡紑濮嬪氨緇忓巻浜嗕竴涓縺鐑堢珵浜夌殑鏃舵湡錛岄珮绔競鍦鴻鍥介檯澶у巶鍟嗘墍鍗犳嵁錛屼綆绔競鍦烘槸鍥藉唴鐨凚I鍘傚晢鍙婅涓氱殑ISV鍙婇泦鎴愬晢鍦ㄧ珵浜夈?006騫翠腑鍥界殑BI甯傚満鍙兘鍦ㄤ綆绔競鍦哄垵姝ュ嚭鐜板儚鐢ㄥ弸銆侀噾铦跺湪璐㈠姟濂楄杞歡閭f牱鐨勬牸灞錛屽嚑涓ぇ鐨勫浗鍐匓I鍘傚晢鍑熸湰鍦板寲鍜岄攢鍞綉緇滃崰鎹競鍦?0錛呬互涓婄殑甯傚満浠介銆傝屽湪澶х殑琛屼笟甯傚満閲岋紝BI灝嗕細涓庤В鍐蟲柟妗堣瀺鍚堝湪涓璧鳳紝甯傚満琚涓氱殑ISV鎵鎶婃寔銆?<br />聽聽聽 <br />聽聽聽 瓚嬪娍鍥?鍦ㄨ惀閿絳栫暐涓婏紝鏁村悎钀ラ攢瓚嬪娍鍑告樉銆?<br />聽聽聽 <br />聽聽聽 2006騫碆I鍘傚晢灝嗛潰涓存縺鐑堣岀幇瀹炵殑甯傚満绔炰簤銆傝惀閿鎵嬫銆佷駭鍝佺爺鍙戝彈鍒板墠鎵鏈湁鐨勯噸瑙嗐傛洿澶氱殑杞枃瀹d紶銆佺爺璁ㄤ細錛堝寘鎷涓氱爺璁ㄤ細錛夈佹柊鍝佸彂甯冧細銆佸貳璁蹭互鍙婅仈鍚堛佸茍璐瓑灝嗕細鍦?006騫翠腑鍥紹I甯傚満閲屼笂婕斻傚縐嶅鏍風殑钀ラ攢鏂瑰紡灝嗚浜虹洰涓嶆殗鎺ャ?<br />聽聽聽 <br />聽聽聽 瓚嬪娍浜?鐢ㄦ埛閲嶈鏁堢泭錛屽叧娉˙PM銆?<br />聽聽聽 <br />聽聽聽 鐢ㄦ埛涔嬫墍浠ユ姇鍏ュ法棰濊祫閲戣喘涔癇I杞歡錛岀洰鐨勯兘鏄笇鏈涘榪愯惀鏁版嵁榪涜鍒嗘瀽錛屼互瀹炵幇瀹炴椂鍝嶅簲銆傚浜庝紒涓氭潵璁詫紝榪樺笇鏈汢I鑳藉鏀寔浼佷笟嫻佺▼浼樺寲浠ュ強鎻愰珮鐢熶駭鍔涖傚綋鐒跺叾鏈緇堢洰鏍囬兘鏄悜綺劇泭綆$悊瑕佹晥鐩娿備絾鏄洰鍓嶇殑寰堝緇勭粐騫舵病鏈夊緩绔嬭儲鍔℃爣鍑嗘潵琛¢噺姝ら」IT鎶曞叆鐨勬晥鐩娿備負姝わ紝灝咮I鎶鏈拰緇╂晥綆$悊灝嗙粨鍚堣屽艦鎴愮殑BPM (浼佷笟緇╂晥綆$悊)鎴愪負BI棰嗗煙鐢ㄦ埛鐨勫叧娉ㄧ偣銆傚湪搴旂敤棰嗗煙鏂歸潰錛孊PM鍙互娣卞叆鐗瑰畾鐨勪笟鍔℃祦紼嬫垨鍔熻兘錛涘湪鍔熻兘鍒掑垎鏂歸潰錛孊PM鍙寜浼佷笟涓氬姟鍔熻兘鍒掑垎錛屽璐㈠姟緇╂晥綆$悊銆佸鎴峰叧緋葷嘩鏁堢鐞嗐佺敓浜ц繍钀ョ嘩鏁堢鐞嗐佷氦鍙変笟鍔$嘩鏁堢鐞嗭紱鍦ㄧ郴緇熸瀯閫犳柟闈紝BPM鑳藉鍗忚皟涓氬姟媧誨姩浠ヨ揪鍒扮壒瀹氱殑緇撴灉錛屽緙栧埗棰勭畻銆佽瘎浼板叧閿緵搴斿晢絳夈傚洜姝わ紝BI杞歡渚涘簲鍟嗗湪鐢˙I鎶鏈彁鍗囦紒涓氱嘩鏁堜笂闈㈠仛鏂囩珷錛屼竴瀹氫細杈懼埌涓瀹氱殑鐢ㄦ埛婊℃剰搴︺偮犅犅犅?/font> </p> <p> <font class="font14">聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽 聽<img src="http://www.226e.net/upload/2006-3-8/2006389252754100.jpg" border="1" /></font> </p> <p> <font class="font14">聽聽聽 瓚嬪娍鍏?浠ヤ駭鍝佷負渚濇墭錛屽鍊兼湇鍔℃垚涓昏銆?<br />聽聽聽 <br />聽聽聽 鐩墠BI杞歡棰嗗煙涓殑澶氭暟杞歡渚涘簲鍟嗭紝鍏惰蔣浠舵巿鏉冩敹鍏ュ拰鏈嶅姟鏀跺叆鍩烘湰鎸佸鉤錛屼絾闅忕潃鏁版嵁浠撳簱鍜屾煡璇€佹姤琛ㄥ伐鍏瘋蔣浠剁殑搴旂敤鏅強錛屼笅涓姝ュ浣曞紑灞曞垎鏋愬瀷搴旂敤灝嗘垚涓轟富瀵鹼紝浠庨攢鍞駭鍝佷腑鍙幏寰楃殑鏀跺叆灝嗛愭笎闄嶄綆銆傛娑堝郊闀匡紝甯姪鐢ㄦ埛寤虹珛鍒嗘瀽鍜屾寲鎺樻ā鍨嬬瓑搴旂敤瑙e喅鏂規鍜屽挩璇㈡湇鍔$殑鏀跺叆灝嗗湪鏄庡勾涓婂崌錛屾渶緇堝皢瓚呰繃杞歡浜у搧鎺堟潈鏀跺叆銆傚洜姝わ紝濡備綍鍦ㄦ彁渚涘鍊兼湇鍔¤繖鏂頒竴杞殑杈冮噺涓儨鍑猴紝鏄疊I杞歡渚涘簲鍟嗙幇鍦ㄩ渶瑕佹湭闆ㄧ桓緙殑銆偮犅犅犅?br />聽聽聽聽<br />聽聽聽 瓚嬪娍涓?搴旂敤鑼冨洿涓嶆柇鎵╁睍錛屽尯鍩熻竟鐣屾棩瓚嬫ā緋娿?<br />聽聽聽 <br />聽聽聽 鐩墠錛屽崕鍖椼佸崕涓滃拰鍗庡崡鍦板尯BI杞歡鍗犳嵁浜嗙粷澶ч儴鍒嗙殑甯傚満浠介錛岃屽叾瀹冨洓鍦板尯鐨勫競鍦轟喚棰濈浉瀵瑰亸浣庛備絾鍗庡寳銆佸崕涓溿佸崕鍗楀湴鍖虹敱浜庣數淇°侀噾铻嶃佹斂搴滅瓑琛屼笟淇℃伅鍖栨按騫寵緝楂橈紝縐瘡浜嗗ぇ閲忔暟鎹紝娓存湜浠庤繖浜涙暟鎹腑鑾風泭錛屽洜姝わ紝2006騫村唴灝嗕粛鏄疊I杞歡鐨勪富瑕佸簲鐢ㄩ鍩熴備絾闅忕潃BI杞歡搴旂敤鑼冨洿鐨勪笉鏂墿澶у拰鐢ㄦ埛璁ょ煡搴︾殑鎻愬崌錛屽悇BI杞歡渚涘簲鍟嗗皢鑷村姏浜庡紑鎷撳叾瀹冨尯鍩熺殑甯傚満銆傚彟澶?006騫村浗瀹剁殑鈥滆タ閮ㄥぇ寮鍙戔濆拰鈥滄尟鍏翠笢鍖楄佸伐涓氬熀鍦扳濅袱澶ф垬鐣ョ殑娣卞叆鎺ㄨ繘鍜屽疄鏂斤紝灝嗕績榪涜タ閮ㄥ拰涓滃寳鍦板尯瀵逛簬浜ら氥佽兘婧愩佺數淇°佺數瀛愭斂鍔$殑寤鴻錛岃繖灝嗗湪涓瀹氱▼搴︿笂甯﹀姩瑗塊儴鍜屼笢鍖楀湴鍖哄浜嶣I杞歡浜у搧鍙婂簲鐢ㄧ殑闇姹傦紝浠庤屼負BI杞歡鐨勬帹騫垮拰搴旂敤甯︽潵鏂扮殑鍙戝睍鏈洪亣銆傦紙瑙佸浘2錛?/font> </p> <p> <font class="font14">聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽 聽<img src="http://www.226e.net/upload/2006-3-8/2006389252810298.jpg" border="1" /></font> </p> <p> <font class="font14">聽聽聽 瓚嬪娍鍏?涓皬浼佷笟鐨凚I搴旂敤甯傚満浠介灝嗛愭笎鎵╁ぇ銆?<br />聽聽聽 <br />聽聽聽 铏界劧鍦ㄥ瀭鐩村競鍦轟笂錛屽ぇ鍨嬩紒涓氫緷鐒舵槸BI鐨勫簲鐢ㄤ富浣擄紝浣嗘槸涓皬浼佷笟鐨凚I搴旂敤闇姹傚紑濮嬮噴鏀俱?<br />聽聽聽 <br />聽聽聽 涓皬浼佷笟瓚婃潵瓚婃敞閲嶈嚜韜緩璁撅紝宸茬粡鎰忚瘑鍒頒俊鎭寲鐨勯噸瑕佹у拰榪垏鎬с傚洜姝わ紝鍥藉唴騫垮ぇ鐨勪腑灝忎紒涓氶愭笎鍛堢幇瀵圭鐞嗚蔣浠舵椇鐩涚殑闇姹傛佸娍錛屽繀灝嗘垚涓?006騫村浗鍐?BI甯傚満閲嶈緇勬垚閮ㄥ垎銆傚浗闄呬竴嫻佺殑BI鍘傚晢BO鍏徃鍜屽浗鍐匓I棰嗗煙浣間郊鑰呰彶濂堢壒鍏徃宸茬粡寮鍙戝嚭閫傚悎涓皬浼佷笟搴旂敤鐨凚I瑙e喅鏂規銆?<br />聽聽聽 <br />聽聽聽 璧涜開欏鵑棶棰勮2006騫村浗鍐呬腑灝忎紒涓氬BI鐨勫簲鐢ㄩ渶姹傚皢蹇熷闀匡紝甯傚満浠介灝嗙敱2005騫寸殑32.7%涓婂崌鍒?2.5%錛屾垚涓築I甯傚満涓婃柊鐨勫闀夸寒鐐廣傦紙瑙佸浘3錛壜?/font> </p> <p> <font class="font14">聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽 <img src="http://www.226e.net/upload/2006-3-8/2006389252972074.jpg" border="1" /></font> </p> <p> <font class="font14">聽聽聽 瓚嬪娍涔?浼樺娍琛屼笟鍦頒綅涓嶅噺錛岃涓氶泦鎴愬拰瑙e喅鏂規鎴愪負涓繪祦銆?<br />聽聽聽 <br />聽聽聽 浠庤涓氬簲鐢ㄦ潵鐪嬶紝涓浗鐨勯噾铻嶄笟銆佺數淇′笟鍦?006騫翠粛灝嗗崰鎹潃BI搴旂敤鐨勪紭鍔胯涓氬湴浣嶃傚彟澶栨斂搴滃拰娑堣垂鍝佸埗閫犱笟鍙婇浂鍞笟(濡傜櫨璐т紒涓氬強榪為攣浼佷笟)瀵笲I鐨勯渶姹備篃涓嶅蹇借銆傜敱浜嶣I鐨勫垎鏋愬瀷搴旂敤灝嗗湪鏈潵鍗犱富瀵煎湴浣嶏紝姣忎釜琛屼笟鍙堥兘闇瑕佷笉鍚岀殑琛屼笟鐭ヨ瘑錛屽洜姝ょ數淇″強閲戣瀺鐨凚I涓氬姟灝嗕細琚涓氱殑闆嗘垚鍙奍SV鍗犳嵁涓瀹氱殑甯傚満浠介銆傦紙瑙佸浘4錛壜?/font> </p> <p> <font class="font14">聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽 聽 <img src="http://www.226e.net/upload/2006-3-8/2006389253080974.jpg" border="1" /></font> </p> <font class="font14">聽聽聽 瓚嬪娍鍗?涓誨姏鍘傚晢绔炰簤浠庘滅兢闆勯愰箍鈥濆埌鈥滀笁瓚抽紟绔嬧濄?<br />聽聽聽 <br />聽聽聽 2006騫翠富鍔涘巶鍟嗙殑绔炰簤灝嗙敱鈥滅兢闆勯愰箍鈥濇佸娍杞彉鍒扳滀笁瓚抽紟绔嬧濈殑鏍煎眬銆傞珮绔競鍦轟紶緇熷浗闄呭ぇ鍘傚晢鍗犳湁鏄庢樉浼樺娍錛涗腑浣庣甯傚満浠嶇劧鏄浗鍐呯殑BI鍘傚鍙婅涓氱殑 ISV錛堢嫭绔嬭蔣浠跺紑鍙戝晢錛夊強闆嗘垚鍟嗙殑鍦扮洏錛涙柊鍏寸殑鍘傚晢鍚庢潵灞呬笂錛岃繀閫熸姠鍗犻珮銆佷腑銆佸簳绔競鍦轟粠鑰屽湪BI甯傚満閲屽艦鎴愭柊鐨?鈥滀笁瓚抽紟绔嬧濇佸娍绔炰簤鏍煎眬銆?<br />聽聽聽 <br />聽聽聽 楂樼甯傚満涓夿O銆丠yperion銆丯CR銆両BM 銆佺敳楠ㄦ枃銆佸井杞丼AS絳変紶緇熺殑鍥介檯涓撲笟BI鍘傚晢灝嗙戶緇崰鎹珮绔競鍦虹浉褰撲喚棰濄?<br />聽聽聽 <br />聽聽聽 鍥藉唴鐨勪笓涓欱I鍘傚晢鍙婅涓氱殑ISV錛屼笓涓欱I鍘傚晢鑿插鐗癸紝鍦?006騫村皢緇х畫浣滀負鍥藉唴BI鍘傚晢棰嗗厛浠h〃鎵涜搗鍥戒駭鍖栧ぇ鏃楋紝鑰岀敤鍙嬨侀噾铦躲佸崥縐戠瓑杞歡浼佷笟鐨勫競鍦烘綔鍔涙閫愭鏄劇幇銆?006騫村競鍦轟喚棰濆皢蹇熶笂鍗囥?<br />聽聽聽 <br />聽聽聽 2005騫存秾鍏ュ浗鍐匓I甯傚満鐨勬柊鍏村姏閲忥紝濡備笁鑿辯數鏈轟俊鎭妧鏈湁闄愬叕鍙革紙MDIT錛夈佷笂嫻鋒鼎鐧劇瓑浼佷笟銆傚皢浼氭垚涓?006騫翠腑鍥紹I甯傚満鐨勯粦椹備紶緇熷浗闄呭巶鍟嗐佸浗鍐匓I浼佷笟鍜屾柊榪涘叆浼佷笟灝嗗艦鎴?006騫翠腑鍥紹I甯傚満鈥滀笁瓚抽紟绔嬧濅箣鍔褲?/font> <img src ="http://www.tkk7.com/hengheng123456789/aggbug/68509.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/hengheng123456789/" target="_blank">鍝煎摷</a> 2006-09-08 14:18 <a href="http://www.tkk7.com/hengheng123456789/archive/2006/09/08/68509.html#Feedback" target="_blank" style="text-decoration:none;">鍙戣〃璇勮</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <p>感谢您访问我们的网站,您可能还对以下资源感兴趣:</p> <a href="http://www.tkk7.com/" title="亚洲av成人片在线观看">亚洲av成人片在线观看</a> <div class="friend-links"> </div> </div> </footer> 主站蜘蛛池模板: <a href="http://500308k.com" target="_blank">亚洲视频国产精品</a>| <a href="http://wwwtoutoulu.com" target="_blank">国产av无码专区亚洲av果冻传媒</a>| <a href="http://njchxf.com" target="_blank">亚洲国产情侣一区二区三区</a>| <a href="http://gnebs.com" target="_blank">午夜免费福利小电影</a>| <a href="http://ac839.com" target="_blank">亚洲国产精久久久久久久</a>| <a href="http://xian66.com" target="_blank">99久久免费精品视频</a>| <a href="http://zzhjnmzp.com" target="_blank">亚洲第一页中文字幕</a>| <a href="http://952268.com" target="_blank">91香蕉成人免费网站</a>| <a href="http://igo98.com" target="_blank">亚洲精品无码av片</a>| <a href="http://zhaofeiz.com" target="_blank">亚洲AV无码乱码国产麻豆穿越</a>| <a href="http://123994.com" target="_blank">国产人成网在线播放VA免费</a>| <a href="http://ahbbht.com" target="_blank">亚洲一区爱区精品无码</a>| <a href="http://xsdggzs.com" target="_blank">永久免费av无码网站yy</a>| <a href="http://tmg-beelen.com" target="_blank">亚洲伦另类中文字幕</a>| <a href="http://516698.com" target="_blank">国产精品久久久久久久久免费</a>| <a href="http://yy7699.com" target="_blank">精品亚洲成A人无码成A在线观看</a>| <a href="http://2121065.com" target="_blank">在线观看视频免费完整版</a>| <a href="http://youyou8tv.com" target="_blank">激情五月亚洲色图</a>| <a href="http://otkaxap.com" target="_blank">免费大香伊蕉在人线国产 </a>| <a href="http://hjndgb.com" target="_blank">亚洲精品456播放</a>| <a href="http://sdzsks.com" target="_blank">a一级爱做片免费</a>| <a href="http://shulan88.com" target="_blank">亚洲AV乱码一区二区三区林ゆな</a>| <a href="http://mp4888.com" target="_blank">蜜臀AV免费一区二区三区</a>| <a href="http://lanchenews.com" target="_blank">亚洲AV无码专区在线亚</a>| <a href="http://ittenyear.com" target="_blank">国产美女精品久久久久久久免费</a>| <a href="http://wwwav800.com" target="_blank">无码精品人妻一区二区三区免费 </a>| <a href="http://jldledu.com" target="_blank">在线观看特色大片免费视频 </a>| <a href="http://66keke.com" target="_blank">亚洲欧美一区二区三区日产</a>| <a href="http://plladay.com" target="_blank">亚洲AV无码乱码在线观看性色扶 </a>| <a href="http://w5524.com" target="_blank">99爱在线精品视频免费观看9</a>| <a href="http://aqdav22.com" target="_blank">亚洲福利电影一区二区?</a>| <a href="http://cswsfz.com" target="_blank">免费看大黄高清网站视频在线</a>| <a href="http://lemonbt.com" target="_blank">高潮内射免费看片</a>| <a href="http://mironpress.com" target="_blank">亚洲成AV人片在线观看无</a>| <a href="http://2266511.com" target="_blank">在线观看AV片永久免费</a>| <a href="http://qq367.com" target="_blank">午夜在线免费视频</a>| <a href="http://miya77772.com" target="_blank">亚洲邪恶天堂影院在线观看</a>| <a href="http://8654123.com" target="_blank">国产精品二区三区免费播放心</a>| <a href="http://beijinzhongliuyiyuan.com" target="_blank">一进一出60分钟免费视频</a>| <a href="http://tsxyhq.com" target="_blank">亚洲综合在线成人一区</a>| <a href="http://zzhjnmzp.com" target="_blank">国产免费变态视频网址网站</a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>