??xml version="1.0" encoding="utf-8" standalone="yes"?>
So , along comes Struts 2. Be careful - it’s good , but a different beast under the covers from Struts 1. It does a lot of things better - for example , the way it has Actions as normal POJO’s makes it a lot of things easier to unit test.
Struts 2 also gives you Ajax ‘out of the box’. No writing of javascript, no debugging against various browsers; just configure and go. A full description of how to setup Struts 2 to use Ajax is in this wiki article. The quick version is:
1. Setup Struts 2
2. Add the Struts-Ajax URL and Div Tag.
That’s it. Ajax without the fuss.
Even better that the Struts guys have implemented the Ajax functionality using the Prototype Ajax Library, so you get the benefit of all the improvements there.
What do you think? Will you move to Struts 2 just for the new Ajax capabilities?
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.
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. 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.
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:
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:
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! 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.
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:
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:
<java:import>
statements to reference the StockNameDao
, DaoImplementation
, and DaoFactory
classes that we added to the system.
<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.
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.
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.
Paul Browne , based in Dublin, Ireland, has been consulting in enterprise Java with FirstPartners.net for almost seven years.
http://hi.baidu.com/ofbase/blog/item/9acf45d05989f88ea1ec9c11.html
Added by Mark Webb, last edited by Trustin Lee on Apr 16, 2007 (view change)
1 ?/span>
建立一个基?/span>MINA的时间服务器Q下面的内容需要先准备好?/span>
MINA 1.1 Core
JDK 1.5 or greater
SLF4J 1.3.0 or greater
>>Log4J 1.2 users: slf4j-api.jar, slf4j-log4j12.jar, and Log4J 1.2.x
>>Log4J 1.3 users: slf4j-api.jar, slf4j-log4j13.jar, and Log4J 1.3.x
>>java.util.logging users: slf4j-api.jar and slf4j-jdk14.jar
q个E序只测试了Windows2000pro?/span>LinuxpȝQƈ且在做的时候没有依赖于一些开发^台的环境?/span>
2 ~写MINA旉服务
下面先徏立一个文?/span>MinaTimeServer.javaQ代码如下:
public class MinaTimeServer {
public static void main(String[] args) {
// code will go here next
}
}
下面会慢慢将q个cd完,q里先定义一?/span>main用于启动E序。这一步结束后Q还需要一个监听连接的对象Q因个程序是ZTCP/IP的,q里增加一?/span>SocketAcceptor?/span>
import org.apache.mina.common.IoAcceptor;
import org.apache.mina.transport.socket.nio.SocketAcceptor;
public class MinaTimeServer {
public static void main(String[] args) {
// The following two lines change the default buffer type to 'heap',
// which yields better performance.
ByteBuffer.setUseDirectBuffers(false);
ByteBuffer.setAllocator(new SimpleByteBufferAllocator());
IoAcceptor acceptor = new SocketAcceptor();
}
}
通过q里?/span>SocketAcceptorc,下面把它绑定到一个端口上Q如果你惛_加一个线E模型到该类的话Q参?/span>"配置U程模型"部分?/span>
import java.io.IOException;
import java.net.InetSocketAddress;
import org.apache.mina.common.IoAcceptor;
import org.apache.mina.transport.socket.nio.SocketAcceptor;
public class MinaTimeServer {
private static final int PORT = 9123;
public static void main(String[] args) throws IOException {
ByteBuffer.setUseDirectBuffers(false);
ByteBuffer.setAllocator(new SimpleByteBufferAllocator());
IoAcceptor acceptor = new SocketAcceptor();
SocketAcceptorConfig cfg = new SocketAcceptorConfig();
cfg.getSessionConfig().setReuseAddress( true );
cfg.getFilterChain().addLast( "logger", new LoggingFilter() );
cfg.getFilterChain().addLast( "codec", new ProtocolCodecFilter(
new TextLineCodecFactory( Charset.forName( "UTF-8" ))));
acceptor.bind( new InetSocketAddress(PORT), new TimeServerHandler(), cfg);
System.out.println("MINA Time server started.");
}
}
q里定义了一个整型的端口变量Q呼?/span>SocketAcceptor.bind(SocketAddress,IoHandler,cfg)Q第一个参数是要监听的|址Q是本地?/span>9123端口?/span>
W二个参C的是实现IoHandler接口的类Q是服务于所有的客户端请求的。在q里Q将会扩?/span>IoHandlerAdapterc,q类遵@"适配器设计模?/span>"的?/span>
W三个参数是配置对象Q用于配|日志和~码qo器。每一个信息都会通过?/span>IoAcceptor中定义的qo器链的所有过滤器。在q风景点Q将会将信息通过日志和编码过滤器。日志过滤器?/span>SL4J库记录信息,而编码过滤器则反~码所有收到的信息Qƈ且将所?/span>TextLineCodecFactory发送的信息q行~码?/span>
下面是TimeServerHandlercȝ代码Q?/span>
import java.util.Date;
import org.apache.mina.common.IoHandlerAdapter;
import org.apache.mina.common.IoSession;
public class TimeServerHandler extends IoHandlerAdapter {
public void exceptionCaught(IoSession session, Throwable t) throws Exception {
t.printStackTrace();
session.close();
}
public void messageReceived(IoSession session, Object msg) throws Exception {
String str = msg.toString();
if( str.trim().equalsIgnoreCase("quit") ) {
session.close();
return;
}
Date date = new Date();
session.write( date.toString() );
System.out.println("Message written...");
}
public void sessionCreated(IoSession session) throws Exception {
System.out.println("Session created...");
if( session.getTransportType() == TransportType.SOCKET )
((SocketSessionConfig) session.getConfig() ).setReceiveBufferSize( 2048 );
session.setIdleTime( IdleStatus.BOTH_IDLE, 10 );
}
}
q里用于理信息Q覆盖了exceptionCaughtQ?/span>messageReceived?/span>sessionCreatedҎ(gu)Q如前所C,该类扩展?/span>IoHandlerAdapter?/span>
exceptionCaughtҎ(gu)会打印错误q且关闭对话Q对于大多数的情冉|Ԍq是标准的处理方法,除非能从异常中恢复过来?/span>
messageReceivedҎ(gu)收C客户端发来的数据Qƈ且写回当前时间。如果收C"quit"Q对话将被关闭。该Ҏ(gu)当前时间发往客户端,依赖于你使用的协议编码,发送至Ҏ(gu)的对象(W二个参敎ͼ会有不同Q发送到session.write(Object)Ҏ(gu)的对象类同。如果你没有指定协议~码Q则一般会收到ByteBuffer对象Q而发送的也要?/span>ByteBuffer对象?/span>
sessionCreatedҎ(gu)用于对话初始化,在这里,先打C条信息,然后判断对话的类型,再设|缓冲大,q里讄的是2048个字节。空闲时间设|ؓ10U,如果覆盖?/span>sessionIdleҎ(gu)Q则该方法每10U被呼叫一ơ?/span>
3 试
到这里,~译E序。如果成功,那么q行Q然?/span>telnetq个E序Q如下所C:
客户端内容:
user@myhost:~> telnet 127.0.0.1 9123
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
hello
Mon Apr 09 23:42:55 EDT 2007
quit
Connection closed by foreign host.
user@myhost:~>
服务端内容:
MINA Time server started.
Session created...
Message written...
4 参考文?/span>
Apache MINA Quick Start Guide http://mina.apache.org/documentation.html
Added by Mark Webb, last edited by Trustin Lee on Apr 16, 2007 (view change)
http://mywicket.group.javaeye.com/group/blog_post/259300
一、概?/span>
Wicket是基?/span>web应用框架的高U组Ӟ其主要特点:
* ?/span>HTML?/span>java之间的明分?/span>
* OOlg模式
* 自动状态管?/span>
* 高度生?/span>
* 低学?fn)投?/span>
* 屏蔽Servlet API?/span>HTTP协议l节
* 无需XML配置文g
* 易于构造可重用lg
Struts是以Model2 MVC 本构建的web应用框架。其工作围绕着处理HTTPh?/span>actioncL完成。配|方式采?/span>XML文g?/span>
下文对Wicket?/span>Struts在体pR?/span>HTTPh处理?/span>Servlet API?/span>HTTP协议抽取、状态管理、配|这六方面进行比较?/span>
二、比较第一斚wQ体p?/span>
Struts体系Z解释每个HTTPhq将其定向到某个处理该类型请求的指定ActioncR每?/span>Actioncd处理后的l果q回Qƈ军_下一步走向——通过转发或者重定向到另一?/span>Action或者将控制权交l输?/span>HTML?/span>JSP面。从技术较大来Ԍ虽然每个部分之间做到了很好的解耦,但是ZHTTPh的处理模式可谓与时代不符Q与wicket相比是q时了)。两大原因如下:
* Strutsq不是真正意义上的纯_w向对象,每个Actioncd义了一?/span>abstractionQ抽取)Q但?/span>abstraction是由HTTP协议的请求机制决定的Q而ƈ非面向对象的分析?/span>
* 除非我们?/span>java代码中直接输?/span>HTMLQ当焉非我们疯了)Q那么ؓ了输?/span>HTML我们p学习(fn)另外的主技术,比如JSP和自定义tag。用在JSP中?/span>tagq易事Q尤其是当我们把q项工作交给工组Ӟq会直接D两个l果Q?/span>JSP代码被他Z的一沓糊涂,或者是我们自己完成q项d?/span>
?/span>Wicket的处理方式则不同Q从整体来讲应该说是更加优雅些。它采用面向对象的组件技术实?/span>web与用L(fng)交互Q这Ҏ(gu)些如SwingQ。在Wicket中的每一|pq的使用l合设计模板生成的组件构成。页面和lg各自渲染自己Qƈ直接或者间接的?/span>markup文gQ标识文Ӟ形式像JSPQ关联。当HTTPh到来Ӟq些h被{换、传递到lg上的相应事g中来Q这一点与微Y?/span>VS很相象。所?/span>Wicket能够解决struts体系中存在的问题Q?/span>
* Wicket是完全面向对象的。我们可以利用组件的l承性设计自q应用。这里不需要ؓ处理HTTP协议的请?/span>/响应而作M工作?/span>
* Wicket所使用?/span>markup文g与纯_的HTML很接q,所以容易上手用?/span>Wicket?/span>markup文g中所引入的内定w常整z,q符?/span>XHTML标准。Q何了?/span>HTML的开发者都可以如编?/span>HTML文g那样~辑Wicket?/span>markup文gQ就好似他ƈ不知道这?/span>Wicket?/span>markup文g一栗?/span>
三?/span>HTTPh处理
?/span>Struts中,一?/span>HTTPh被接收后Q?/span>Struts在配置文g中查?/span>request path和相应的ActioncR如果这些已l被配置好了Q它?yu)将提取h参数攑օ?/span>ActionForm bean中,q执行一些验证。然?/span>HTTPh、回应和ActionForm对象都将作ؓ参数传入?/span>ActioncM。从q点可以看出Action的开发者掌握着应用的方斚w面:他们必须处理HTTP sessionQ维?/span>HTTPh?/span>session的属性,q在action执行完时建立需要返回的信息Q最后还要返回相应的ActionForward以struts知道下一步在哪里。假如此?/span>ActionForward控制权交给?/span>JSP面Q开发者就要?/span>struts自定义的tag库编?/span>JSP代码。如此繁复的工作环节很容易出现错误,而且strutsq需要三个位|保持一_struts XML配置文g?/span>java ActioncR?/span>JSP自定?/span>tag?/span>
而在Wicket中,一?/span>HTTPh被接收后Q?/span>Wicket确?/span>HTTP所h的那个页面和在这个页面关联的lg。如果请求的目的?/span>formQ?/span>Wicket自动提取请求参数、验证参数、进行一些预先规定好的类型{换、设|?/span>formlg中的modelQ模式,q里用法?/span>MVC中类|但有不同Q|接着转化h为相应类型的事g、调用目标组件上的相应事件侦听器Q这样就会导致事件处理代码运行来执行业务逻辑Q然后,事g处理器还指定下一步页面的位置Q被指定的页面将初始化(如果面从未被初始化的话Qƈ自动渲染Q渲染处理将按照序讉K每个面lgQ要求它们进行自我渲染。在markup文g中能够组件仅通过名字?/span>HTML元素q行映射?/span>
Wicket的原因:
* 每个lg知道如何处理自己事g。因此我们只需要将lg攑ֈ面上,~写事g处理器就行了。如果一个页面中存在20个能引发事g的不同的lgQ我们除了进行将它们d到页面上的工作外没有别的工作。但如果?/span>struts中,我们可能需要徏?/span>20个不同的ActioncL者一个具?/span>20个分支语句的Actionc,q要?/span>XML配置中逐一d?/span>
* Wicket带给了我们考虑lg/事g重用的机会。而不用将注意力放到如何处?/span>HTTPh和回应上?/span>
* ?/span>struts相比使用Wicket会降低我们的代码量,q正是重用组件带来的益处?/span>Wicket本n不用Q何的XML配置文g。只需要修?/span>web容器?/span>web.xml文g中的servlet声明部分?/span>
假如我们曄~写q?/span>Windows API、ƈ用过Visual Basic或?/span>Borland Delphi的话Q下面的比较会更加让人印象深刅R?/span>struts开发就像?/span>Windows API一P接收原始消息Q解码原始消息,然后再处理这些消息。由?/span>Windows API是基于消息@环工作的Q所以系l除了消息回应外不期望Q何的q回倹{?/span>
从另一斚w看,Dephi?/span>TApplicationcM隐藏?/span>Windows消息循环Q开发h员围l着TApplicationcd立其他的cR原始的pȝ消息p栯Dephi内徏cLӞ被内建类解析q被定其接U。消息被转换Z个事Ӟq被传送到某个特定的对象?/span>
?/span>Windows应用E序一PWicket应用也具有服务于文本?/span>HTML模板的资源文件。从q点看,Wicket象用Delphi做桌面开发一栯用来?/span>web开发?/span>
四?/span>Servlet API?/span>HTTP协议的抽?/span>
Struts没有隐藏Servlet API?/span>HTTP协议的细节。ؓ了?/span>StrutsQ我们必M于和HTTPServletRequest?/span>HttpServletResponse ?/span>HttpSessioncL交道。ƈ围绕着h和回应徏立应用。这便是所?/span>Model2 MVC wen框架与生俱来的弱炏V?/span>
正如上面说的Q?/span>Wicket隐藏?/span>Servlet API?/span>HTTP协议的细节。对于一些应用,我们甚至触及不到q些l节。甚臛_于非常复杂的应用Q我们也仅用适当?/span>Wicket协议抽取cR而经常用到的?/span>javalgcR?/span>POJO业务模型、纯HTML标记文g?/span>
五、状态管?/span>
使用Struts开发,我们获得全部的状态管理权。这对于建立大规模的、高升I间的、集应用来讲是很好的,因ؓ我们获得对HttpSession上每件事物的控制权。但是对于中型应用Q我们将没有~由~写一些额外的代码。这样将D应用变得复杂和编写费时?/span>
在状态管理上Q?/span>Wicket可以作ؓ一个不错的选择?/span>Wicket框架默认代管所有的lg状态。这对于中小型应用,在状态管理上的代码量几乎?/span>0。但?/span>Wicket也提供了一?/span>API使我们进行标准状态管理和实现自己的状态管理。这P即是大型应用,我们也能够全权掌握状态管理。事实上Q即使在使用Wicket~写大型应用Ӟ通常也是先让Wicket代管所有的状态,然后再慢慢的实现自己定义的状态管理以提高应用性能?/span>
六、配|?/span>
不言自明Q?/span>Struts需要一?/span>XML文gQ定义对HTTPh和响应的映射和所有的ActionForm对象{。这个文件可能非常大而且复杂。而新版本?/span>Struts提供了将q个文g分解为多个模块的Ҏ(gu)Q虽然这样可以将模块分类Q但是这样同栯l护许多的小文g?/span>
Wicket不需要配|文件?/span>Wicket通过一个简单的应用配置cL者通过~写web容器?/span>web.xml文g?/span>Servlet init参数来完成程序的初始化。?/span>HTTPh到组件事件的映射、组件如何输?/span>HTML{被包含在了Wicket的应用逻辑里,从而极大地化了配置?/span>
七、参考资?/span>
http://wicket.sourceforge.net/
http://www.wicket-wiki.org.uk/wiki/index.php/Newuserguide
http://www.tkk7.com/tommyjian/archive/2007/06/10/123202.html
Z么是WicketQ?/span>
如果(zhn)正在寻求?/span>Java开?/span>Web应用E序Q目前,(zhn)有很多的选择。实际上Q存在如此众多的Web应用E序框架昑־有点搞笑。来自于互联|一个博客站点的问题Q?zhn)能说出多?/span>Java Web应用框架的名字?他们展现的结果如下:
框架Q到处都是框Ӟ参看后面附带的表根{?/span>
Z么要“重新发明轮子”Q?/span>
从这个角度看Q?zhn)对?/span>“另一?/span>Web应用E序框架有多?/span>”q个问题L耿耿于怀Q确实,Z们要“重新发明轮子”呢?对这个古老的谚语的答复是Q因一ơ可以轮子更圆Q?/span>
但是对于高质量的期待q不是构?/span>Wicket框架的唯一动因。甚x很多的观点,认ؓ没有其他?/span>Web工具集填补这一I白Q?/span>Wicket做到了。实际上Q?/span>Wicket与上面提及的众多框架不太一栗?/span>
?/span>Wicket最相近的或许是Tapestry?/span>EchoQ但是这U相似性也很有限。和Tapestry一PWicket使用特定?/span>HTML属性来标识lgQ?/span>ComponentsQ声明,q可以方便用一般的HTML~辑器进行文件编辑。和Echo一PWicket拥有一的lg模型。但是基?/span>Wicket的应用程序和那些ZTapestry?/span>Echo的应用程序不一Pq是因ؓ?/span>Wicket框架中两斚w都可以受益。?zhn)获得了一的lg模型和对HTML没有q扰所带来的益处。在很多情况下,q种复合的好处可以带来非帔R要的开发优ѝ?/span>
理解了构?/span>Wicket的动机有助于(zhn)理解ؓ什?/span>Wicket会表现的不一栗?/span>
Echo |
Cocoon |
Millstone |
OXF |
Struts |
SOFIA |
Tapestry |
WebWork |
RIFE |
Spring MVC |
Canyamo |
Maverick |
JPublish |
JATO |
Folium |
Jucas |
Verge |
Niggle |
Bishop |
Barracuda |
Action Framework |
Shocks |
TeaServlet |
wingS |
Expresso |
Bento |
jStatemachine |
jZonic |
OpenEmcee |
Turbine |
Scope |
Warfare |
JMAA |
Jaffa |
Jacquard |
Macaw |
Smile |
MyFaces |
Chiba |
JBanana |
Jeenius |
JWarp |
Genie |
Melati |
Dovetail |
Cameleon |
JFormular |
Xoplon |
Japple |
Helma |
Dinamica |
WebOnSwing |
Nacho |
Cassandra |
Baritus |
动机
目前存在的大多数Web框架对于服务端的状态管理都仅仅提供了较q支持?/span>
q就意味着?/span>Web应用E序中存在着很多Ҏ(gu)的代码来处理和维护繁复的状态管理机制。虽?/span>Wicketq不允许Ҏ(gu)务端的状态完全不考虑Q但是它在状态管理的便性和透明化方面做了很多的工作?/span>
?/span>Wicket中,所有服务端的状态都被纳入了自动的管理。?zhn)始终不需要直接?/span>HttpSession对象或者类似的装对象d储状态信息。相反,状态信息已l都与组件关联v来,而在lg后端的数据模型都是传l的Java对象Q?/span>POJOQ?/span>Wicket在每个用户会话期内维护着面的映表Q?/span>MapQ。这个页面映表Q以及每个一面内的组件层ơ)的目的在于得框枉藏了lg以及数据模型讉K的细节。?zhn)只需要处理简单而熟(zhn)的Java对象Q?/span>Wicket则处理诸?/span>URL、会话期标识以及GET/POSTh的Q务?/span>
(zhn)接着也会发现q种l构良好的服务端状态得解决o人恐惧的“后退按钮问题”变得十分的容易。实际上Q针寚w面内lg数据模型的结构性变化带来的数据q期Q?/span>Wicket提供了通用而且健壮的解x案,q个Ҏ(gu)可以有效地对览器缓存页面进行甄别和q期?/span>
最后,Wicket在设计的时候就考虑与诸?/span>JDO?/span>Hibernate的普?/span>Java对象Q?/span>POJOQ序列化框架协同工作。这一点得构建数据驱动的Web应用E序昑־非常单?/span>
对于很多应用E序来说Q必d额外服务端状态导致服务器负蝲增加和其带来的好处之间进行权衡,服务端状态管理可以降低开发成本、减维护成本、加快对市场的响应时间以及生产高质量的Y件。这里提出的基本观点是:软g是十分昂c复杂的Q而来自于E-machines?/span>Dell的服务器则相对便宜?/span>
在效率和生性方面,Wicket?/span>JSP的优性则犹如Java语言?/span>C语言一栗?zhn)使?/span>Wicket可以实现的功能?/span>JSP也都可以实现。甚至于在内存和CPU消耗方面效率也非常的高。但是?/span>JSP开发应用程序则需要耗费(zhn)更多的旉。最后,因ؓ?/span>JSP中进行状态管理时使用了特别的方式Q?zhn)可能发现不少的安全问题,也能看到到处y出来的错误。上面提及的大部分框架在q方面仅仅提供了有限的辅助?/span>
大部分现存的框架需要特定的HTML代码
JSPh最q侵入性,它允许将Java代码直接嵌入Web面中。但是,上面列示的框Ӟ除了TapestryQ都不同E度地针?/span>HTML代码引入了特D的语法?/span>
因ؓҎ(gu)语法改变了单U而简单的HTML标记的实质,?/span>Web设计者对于这一Ҏ(gu)十分的熟(zhn),所以特D语法ƈ不是十分得h心。而且预览、编辑和理解q种包含Ҏ(gu)语法?/span>HTML也是十分困难的事情?/span>
Wicketq没引入M新的HTML语法。相反,它通过Wicket命名I间Q?/span>namespaceQ的标准兼容方式扩展?/span>HTMLQ这完全兼容XHTML标准。这意味q?zhn)可以使?/span>Macromedia Dreamweaver?/span>Microsoft Frontpage?/span>Word?/span>Adobe Go Live以及其他现有?/span>HTML~辑器来~辑(zhn)的Web面Qƈ且可以和Wicket的组件协同工作。ؓ了实现这个目标,Wicket始终?/span>Wicket命名I间内用单?/span>id属性(“wicket:id”Q来标识那些需要框架进行特D处理的标签。如果?zhn)q不喜欢有Wicket命名I间修饰的标{֒属性展C给(zhn)的最l用P通过单的讄可以完全消除它们,从而得到普通的与标准兼容的HTML代码?/span>
HTML中没有特D的语法意味着设计者可以直接模拟页面,而?zhn)可以在开发的q程中直接用这些页面。向HTML面中添?/span>Javalg和讄lg的名U属性一L(fng)单。然后,(zhn)可以直接将q些面交给Web设计人员Q他们可以充满信心地对其q行修改?/span>
与其他的应用框架相比Q?/span>Wicket在各斚w的分M提供更多的支持?/span>Web设计者在对应用程序代码不甚了解的情况下就可以~辑HTMLQ当Ӟ他们不能U除lg名称标签Q而且不能L改变lg嵌套的层ơ,其他的事情都是可以的Q。另一斚wQ编E者只需要关注与HTML混在一L(fng)JavalgQ而不需要了解页面的最l陈现是什么样子。通过q种职能清楚的工作方式,每个人都可以工作得更为顺畅?/span>
现存的框架易用性不?/span>
目前存在的大部分框架工具在对象模型方面做得不够。在一些框架中Q对象模型是通过特定?/span>XML来定义的。这些语法o人生厌,而且q需要特定的工具来编辑这些配|信息。由于这些框架ƈ不是单一?/span>JavacdQ?zhn)׃能用包含编辑器、调试器和编译器?/span>IDE工具来编辑它们?/span>
Wicket是化Jؓ的代表。在学习(fn)Wicket的过E中不需要了解Q何配|文件?/span>Wicket是lgl构良好的普通的cd。在Wicket中,(zhn)的Web应用E序与普通的Swing应用E序cMQ而不?/span>JSP应用E序。如果?zhn)熟(zhn)?/span>JavaQ特别是如果(zhn)熟(zhn)?/span>SwingQ,那么(zhn)就已经?/span>Wicket有不的了解了?/span>
现存的框架可复用性不?/span>
Tapestry?/span>JSF虽然有可以重用的lg模型Q但是?zhn)发CWicket相比qƈ不是特别Ҏ(gu)做到的事情?/span>Wicket从设计之初就十分地注重组件的复用。在Wicket中,从现有的lg扩展~制诸如SignInPanel或?/span>AddressForm的复合组件是十分单的事情。相Ҏ(gu)_针对览器的新特性编制新的组件也是十分容易的事情?/span>Wicket的组件可以?/span>JAR格式q行打包Q直接通过库引用的方式可以实现重?/span>—?span style="font-family: 宋体">不需要Q何配|文Ӟ
Web~程应该更关注编E乐!
q就是我~写Wicket的个人方面的目标。现存的框架在实现开发的直接性、快h和易性方面真正地吸引我。我希望Wicket?/span>Web应用E序开发的性和乐趣斚w能够q出重要的一步?/span>
目标
Z上面的这些动机,下面?/span>Wicket的目标:
开?/span>Wicket的一些网站和资料
1 Wicket
Wicket框架的大本营Q在q里你可以通过Wiki了解更多关于Wicket开发的概念和技巧,q可以下载相关的资源Q如Wicket核心包,Wicket的扩展包Q还?/span>Wicket自带的例子?/span>
http://gocom.primeton.com/modules/newbb/viewforum41.htm(本文作者主持的中文论坛)
http://wicket.sourceforge,netQ这?/span>Wicket?/span>sourceforge的根据地Q?/span>
http://www.wicketframework.orgQ这?/span>Wicket的独立域名)
2 Wicket-Stuff
因ؓWicket作ؓ一?/span>Web框架Q只可能提供最核心的功能,但是在实际的开发中Q需要更多的控g以及辅助的功能,如与Hibernate的整合,数据分布列表控g{,Wicket-Stuff是一个致力于开?/span>Wicket扩展功能的站点,目前已经提供了以下的扩展功能:
v 整合Dojo
v 整合Hibernate的控?/span>Hibernate (2.1 and 3) components
v 支持客户端数据验证的控g
v 支持Groovy脚本~程
v Velocity控g面板
v 整合Freemarker
v 整合JasperReports
v 整合TinyMCEq个Html~辑?/span>
v 整合Yahoo Ajax UI控g
http://wicket-stuff.sourceforge.net/
3 Wicket-Quickstart
Wicket虽然入门门框不高Q但是许多热心的开发h员还是提供了许多详细的教E,帮助开发h员学?fn)如何在各?/span>IDE环境下开?/span>Wicket应用E序?/span>
http://wicketframework.org/wicket-quickstart/index.htmlHtml
4 Wicket-Library
Wicket-Library也是一个类gWicket-Stuff的站点,它的目的也是Z提供更多?/span>Wicket控gQؓ开发h员服务,但是目前q没有提供什么有用的控g?/span>
它的|站上提供了Wicket例子的在U演C,如果你不惛_本机上安?/span>TomcatQ?/span>JDK{YӞ可以在q个|站上看Wicket提供的例子?/span>
http://www.wicket-library.com/
5 DataBinder
DataBinder是一个将Hibernate整合?/span>Wicket中的一个扩展功能,对于那些以数据驱动ؓ开发目的的WebE序Q它是不二之选?/span>
6 Hibernate
Hibernate本n?/span>Wicketq没有关p,但是Wicket-Stuff?/span>DataBinder都已l提供了Hibernate的扩展功能,所以把Hibernate也放入这个列表,方便大家使用Hibernate?/span>
7 QWicket
QWicket是一些热心的Wicket开发h员,Z让更多的开发h员了?/span>WicketQ所以提供了一个很完整的应用程序,它是Wicket世界中的Appfuse?/span>
http://www.antwerkz.com/qwicket/
8 Wicket Bench
Wicket Bench是一个用来辅?/span>Wicketq行开发的Eclipse插g工具。前面已l对它进行了详细的介l?/span>
http://www.laughingpanda.org/mediawiki/index.php/Wicket_Bench
9 Mail-Archive
Mail-Archive本n不是一个与技术有关的|站Q它是一个邮件组归档的站点,常用的邮件组在上面都有归档,?/span>Jakarta组的开源YӞWicket也在上面Q还有许多,在上面可以查看许?/span>Wicket的讨论,非常的精彩?/span>
你可以通过下面的网址直接讉KMail-Archive|站?/span>Wicket邮gl的归档:
http://www.mail-archive.com/wicket-user%40lists.sourceforge.net/
10 一?/span>Blog
Wicket的开发h员和Wicket一些资q户将自己关于Wicket的开发经验放在自qBlog上,与大家共?/span>:
v A Wicket Diary - Martijn Dashorst
v Chillenious! - Eelco Hillenius
v System Mobile - Nick Heudecker
v Geertjan - Geertjan Wielenga
1、首先下?Liferay Portal Professional 4.2.1 (Bundled with Tomcat for JDK 5.0)
2、用其默认?HSQL 数据库,即不L改其数据库配|?/p>
3、下?liferay-portal-servicemix-4.2.1.war ?iferay-portal-jbpm-4.2.1.war
http://www.liferay.com/web/guest/downloads
4、把下蝲的这两个包分别更名ؓjbpm-web.war ?servicemix-web.war
5、把 jbpm-web.war ?servicemix-web.war 拯?Tomcat ?webapps 目录?br />
6、把 webapps\jbpm-web\WEB-INF\sql 目录中的 hsqldb.create.jbpm.3.1.sql 文g更名?jbpm.script Qƈ把它攑օ tomcat ?bin 目录?br />
7、运?Tomcat ?startup.bat
8、打开 http://localhost:8080/ Qƈ使用 test@liferay.com 用户d Q密码ؓ testQ?br />
9、增加?workflow portlet ,选择其中?definitions 标签Q选择 add 按钮?br />
10、在 text area 中输入工作流定义Q如Q?br />
1
<?xml version="1.0" encoding="UTF-8"?>
<process-definition xmlns="urn:jbpm.org:jpdl-3.1" name="Example Process">
<start-state name="start">
<task>
<assignment class="com.liferay.jbpm.handler.IdentityAssignmentHandler" >
<companyId>liferay.com</companyId>
<type>user</type>
<name>test@liferay.com</name>
</assignment>
<controller>
<variable name="text:color" />
<variable name="text:size" />
</controller>
</task>
<transition name="to_t" to="t"/>
</start-state>
<task-node name="t">
<task name="t" >
<controller >
<variable name="text:color" access="read" />
<variable name="text:size" access="read"/>
</controller>
<assignment class="com.liferay.jbpm.handler.IdentityAssignmentHandler" >
<companyId>liferay.com</companyId>
<type>user</type>
<name>test@liferay.com</name>
</assignment>
</task>
<transition name="to_end" to='end' />
</task-node>
<end-state name="end"></end-state>
</process-definition>
11、提交此CZQ则生成一个工作流E?br />
12、在 tasks view Q选择 "manage" 来执行此 tasks ?br />
首先介绍一下top-down方式Q?br />
UDDI includes an XML schema for SOAP messages that defines a set of documents to describe business and services information, a common set of APIs for querying and publishing information to the directories, and an API for replicating directory entries between peer UDDI nodes.
2、WSIL
Web Services Inspection Language (WSIL) is a service discovery mechanism that is an alternative to UDDI as well as complementary to UDDI. When you discover Web services with UDDI, you go to a centralized registry. WSIL is an alternative approach to Web service discovery. WSIL allows you to go directly to the service provider and ask for the services it provides.
WSIL也是用于查找W(wng)eb Services 的机制。它是UDDI的补充?br />
The Web Services Inspection Language (WSIL) and the Universal Description, Discovery, and Integration (UDDI) specification both address issues related to Web service discovery. However, each specification takes a different approach to the discovery of Web services. The two specifications can be used separately or jointly; searching with WSIL can result in finding items in UDDI.
3、WSDL
WSDL is an XML-based open specification that describes the interfaces to and instances of Web services on the network. It is extensible, so endpoints can be described regardless of the message formats or network protocols that are used to communicate.
Relationship between UDDI and WSDL
Figure illustrates the relationship between UDDI and WSDL. The WSDL service element references the WSDL binding element. The URL of the document containing the WSDL binding element is published to the UDDI business registry as a tModel. The URL of the document containing the WSDL service element is published to the UDDI business registry as a businessService and contains information about the bindingTemplate.
4、SOAP
SOAP is an XML-based standard for messaging over HTTP and other Internet protocols. It is a lightweight protocol for the exchange of information in a decentralized, distributed environment. It is based on XML and consists of three parts:
SOAP enables the binding and usage of discovered Web services by defining a message path for routing messages. SOAP may be used to query UDDI for Web services.
单对象访问协议(SOAPQ是一U轻量的、简单的、基?XML 的协议,它被设计成在 WEB 上交换结构化的和固化的信息?SOAP 可以和现存的许多因特|协议和格式l合使用Q包括超文本传输协议Q?HTTPQ,单邮件传输协议(SMTPQ,多用途网际邮件扩充协议(MIMEQ。它q支持从消息pȝ到远E过E调用(RPCQ等大量的应用程序?/p>
SOAP 包括三个部分Q?
SOAP 消息基本上是从发送端到接收端的单向传输,但它们常常结合v来执行类gh / 应答的模式。所有的 SOAP 消息都?XML ~码。一?SOAP 消息是一个包含有一个必需?SOAP 的封装包Q一个可选的 SOAP 标头和一个必需?SOAP 体块?XML 文档?br />
SOAP 消息格式Q?/p>
SOAP 标头
<SOAP-ENV: Envelope Attributes>
<SOAP-ENV:Body>
Attributes
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
service provider主要是徏立发布Web services?/p>
Service brokers 是归cdƈ注册W(xu)eb servicesQ以利于查询?/p>
Service clients 则是在Service brokers中查扑ֈWeb servicesQ然后绑定到Service providersq调用之?/p>
可以参?a target="_blank">www.ibm.com/developerworks/webservices
Liferay Portal?/span>CMS功能是通过Journal Portlet实现的,在介l怎样使用Journal Portlet之前Q有必要理解structures?/span>templates?/span>articles的概念,它们?/span>Journal portlet功能的基?/span>
l StructuresQ定于了content的类型和数量Q?/span>content的类型包?/span>text?/span>text area?/span>images?/span>selection lists{?/span>
l TemplatesQ确?/span>content怎样排列或摆?/span>
l ArticlesQ确定每?/span>content包含的实际的text?/span>images
W一步、创?/span>StructureQ包含一下元素:一?/span>text元素名ؓ?/span>headline”(对应囄1区域Q、三?/span>text area元素为名U分别ؓ?/span>body-text”(对应4区域Q?/span>caption-1”(对应2区域Q?/span>caption-2”(对应6区域Q、两?/span>image元素名称分别为?/span>image-1”(对应3区域Q和?/span>image-2”(对应5区域Q?/span>
d完这些元素后的界面如下:点击Launch Editor按钮Q可以看?/span>XML定义Q也可以在此增删或修改元素及cdQ内容如下:
W二步、创?/span>TemplateQ添?/span>ID?/span>Name?/span>Description信息后,?/span>Structure一栏选择上一步创建的StructureQ这里ؓtestQ?br />
然后点击Launch Editor按钮Q打开Template~辑H口Q按照所需要的格式定义TemplateQ如下:
下面对该文gq行说明Q?/span>
1、这里的@name=?/font>名称?/font>必须要和W一步中创徏Structure中的元素名称一_面格式Ҏ(gu)需求?/span>HTML语言定义卛_?/span>
2、对text?/span>text areacd的元素输出时的格式如下:
<xsl:value-of
disable-output-escaping="yes" select="root/dynamic-element[@name='caption-2']/dynamic-content"/>
1?span style="FONT: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">
?/span>imagecd的元素输出时的格式如下:<img>
<xsl:attribute name="src">
<xsl:value-of
disable-output-escaping="yes" select="root/dynamic-element[@name='image-2']/dynamic-content"/>
</xsl:attribute>
</img>
W三步、创?/span>ArticleQ添写基本信息后Q在Structure一栏选择testQ对应的Template一栏也选择test卛_Q然后在对应的元素域里添入合适的文本或者图片,点击预览卛_以看到如下界面,定无问题后Q点M存或者保存ƈ发布按钮卛_完成content的定制?br />通过以上三个步骤Q我们就实现了定?/span>content的功能。?/span>Journal PortletQ我们可以定制Q何不同风格的content来展C必要的信息?/span>
1.Velocity的?/p>
Velocity是一个开放源吗的模版引擎Q由apache.org组负责开发,现在最新的版本是Velocity1.3.1Q?a >http://jakarta.apache.org/velocity/index.html可以了解Velocity的最C息?/p>
Velocity允许我们在模版中讑֮变量Q然后在q行Ӟ动态的数据插入到模版中,替换q些变量?/p>
例如Q?/p>
<html>
<body>HELLO$CUSTOMERNAME</body>
</html>
我们可以在运行时得到客户的名字,然后把它插入到这个模版中替换变量$CUSTOMERNAMEQ整个替换过E是由Velocityq行控制的,而且java的调用代码也非常单,如我们可以在java代码中这栯?/p>
/***********************************************************/
//q个文g中设定了Velocity使用的log4j的配|和Velocity的模版文件所在的目录
Velocity.init("D:\\Template\\resource\\jt.properties");
//模版文g名,模版文g所在的路径在上一条语句中已经讄?/p>
Templatetemplate=Velocity.getTemplate("hello.vm","gb2312");
//实例化一个Context
VelocityContextcontext=newVelocityContext();
//把模版变量的D|到context?/p>
context.put("CUSTOMERNAME","MyFirstTemplateEngine----Velocity.");
//开始模版的替换
template.merge(context,writer);
//写到文g?/p>
PrintWriterfilewriter=newPrintWriter(newFileOutputStream(outpath),true);
filewriter.println(writer.toString());
filewriter.close();
/***********************************************************/
q就是整个java的代码,非常的简单。如果我们有多个模版变量Q我们仅需要把q些模版变量的D|到context中?/p>
下面我们单的分析一下,Velocity引擎d模板文gӞ它直接输出文件中所有的文本Q但?字符开头的除外Q?W号标识着一个模版变量位|,
context.put("CUSTOMERNAME","MyFirstTemplateEngine----Velocity.");
当Velocity模板引擎解析q输出模板的l果Ӟ模板中所有出?CUSTOMERNAME的地斚w插入客L(fng)名字Q即被加入到VelocityContext的对象的toString()Ҏ(gu)q回值将替代Velocity变量Q模板中?开头的变量Q?/p>
模板引擎中最强大、用最频繁的功能之一是它通过内徏的映像(ReflectionQ引擎查扑֯象信息的能力。这个映像引擎允许用一U方便的Java?”类似的操作W,提取L加入到VelocityContext的对象的M公用Ҏ(gu)的|或对象的L数据成员?/p>
映像引擎q带来了另外一个改q:快速引用JavaBean的属性。用JavaBean属性的时候,我们可以忽略getҎ(gu)和括受请看下面这个模板的例子?/p>
<html>
<body>
Name:$Customer.Name()
Address:$Customer.Address()
Age:$Customer.Age()
</body>
</html>
java的代码:
/***********************************************************/
//讄客户信息
Customermycustomer=newCustomer();
mycustomer.setName("Velocity");
mycustomer.setAddress("jakarta.apache.org/velocity/index.html");
mycustomer.setAge(2);
//q个文g中设定了Velocity使用的Log4j的配|和Velocity的模版文件所在的目录Velocity.init("D:\\Template\\resource\\jt.properties");
//模版文g名,模版文g所在的路径在上一条语句中已经讄?/p>
Templatetemplate=Velocity.getTemplate("hello.vm","gb2312");
//实例化一个Context
VelocityContextcontext=newVelocityContext();
//把模版变量的D|到context?/p>
context.put("Customer",mycustomer);
//开始模版的替换
template.merge(context,writer);
//写到文g?/p>
PrintWriterfilewriter=newPrintWriter(newFileOutputStream(outpath),true);
filewriter.println(writer.toString());
filewriter.close();
输出l果Q?/p>
<html>
<body>
Name:Velocity
Address:jakarta.apache.org/velocity/index.html
Age:2
</body>
</html>
除了替换变量之外Q象Velocity高引擎q能做其他许多事情,它们有用来比较和q代的内建指令,通过q些指o我们可以完成E序语言中的条g判断语句和@环语句等?/p>
例如Q我们想要输出年龄等?的所有客L(fng)信息Q我们可以这样定义我们的模版
模版Q?/p>
<html>
<body>
<table>
<tr>
<td>名称</td>
<td>地址</td>
<td>q龄</td>
</tr>
#foreach($Customerin$allCustomer)
#if($Customer.Age()=="2")
<tr>
<td>$Customer.Name()</td>
<td>$Customer.Address()</td>
<td>$Customer.Age()</td>
</tr>
#end
#end
</table>
</body>
</html>
java的代码:
/******************************************************/
//讄客户信息
ArrayListallMyCustomer=newArrayList();
//客户1
Customermycustomer1=newCustomer();
mycustomer1.setName("Velocity");
mycustomer1.setAddress("jakarta.apache.org/velocity/index.html");
mycustomer1.setAge(2);
//客户2
Customermycustomer2=newCustomer();
mycustomer2.setName("Tomcat");
mycustomer2.setAddress("jakarta.apache.org/tomcat/index.html");
mycustomer2.setAge(3);
//客户3
Customermycustomer3=newCustomer();
mycustomer3.setName("Log4J");
mycustomer3.setAddress("jakarta.apache.org/log4j/docs/index.html");
mycustomer3.setAge(2);
//d到allMyCustomer(ArrayList)?
allMyCustomer.add(mycustomer1);
allMyCustomer.add(mycustomer2);
allMyCustomer.add(mycustomer3);
//q个文g中设定了Velocity使用的log4j的配|和Velocity的模版文件所在的?/p>
Velocity.init("D:\\Template\\resource\\jt.properties");
//模版文g名,模版文g所在的路径在上一条语句中已经讄?/p>
Templatetemplate=Velocity.getTemplate("hello.vm","gb2312");
//实例化一个Context
VelocityContextcontext=newVelocityContext();
/**注意q里我们仅仅需要给一个模版变量负?/
context.put("allCustomer",allMyCustomer);
//开始模版的替换
template.merge(context,writer);
//写到文g?/p>
PrintWriterfilewriter=newPrintWriter(newFileOutputStream(outpath),true);
filewriter.println(writer.toString());
filewriter.close();
/******************************************************/
l果Q?/p>
<html>
<body>
<table>
<tr>
<td>名称</td>
<td>地址</td>
<td>q龄</td>
</tr>
<tr>
<td>Velocity</td>
<td>jakarta.apache.org/velocity/index.html</td>
<td>2</td>
</tr>
<tr>
<td>Log4J</td>
<td>jakarta.apache.org/log4j/docs/index.html</td>
<td>2</td>
</tr>
</table>
</body>
</html>
#if语句完成逻辑判断Q这个我想不用多说了?/p>
allCustomer对象包含零个或者多个Customer对象。由于ArrayList(List,HashMap,HashTable,Iterator,Vector{?属于JavaCollectionsFramework的一部分Q我们可以用#foreach指oq代其内宏V我们不用担心如何定型对象的cd——映像引擎会为我们完成这个Q务?foreach指o的一般格式是?foreachin”?foreach指oq代listQ把list中的每个元素攑օitem参数Q然后解?foreach块内的内宏V对于list内的每个元素Q?foreach块的内容都会重复解析一ơ。从效果上看Q它相当于告诉模板引擎说Q“把list中的每一个元素依ơ放入item变量Q每ơ放入一个元素,输出一?foreach块的内容”?/p>
2.MVC设计模型
使用模板引擎最大的好处在于Q它分离了代码(或程序逻辑Q和表现Q输出)。由于这U分,你可以修改程序逻辑而不必担心邮件消息本w;cM圎ͼ你(或公关部门的职员Q可以在不重新编译程序的情况下,重新~写客户列表。实际上Q我们分Mpȝ的数据模式(DataModelQ即提供数据的类Q、控制器QControllerQ即客户列表E序Q以及视图(ViewQ即模板Q。这U三层体pȝ为Model-View-Controller模型QMVCQ?/p>
如果遵从MVC模型Q代码分成三个截然不同的层,化了软g开发过E中所有相关h员的工作?/p>
l合模板引擎使用的数据模式可以是MJava对象Q最好是使用JavaCollectionFramework的对象。控制器只要了解模板的环境(如VelocityContextQ,一般这U环境都很容易用?/p>
一些关pL据库的“对?关系”映工兯够和模板引擎很好地协同,化JDBC操作Q对于EJBQ情形也cM。模板引擎与MVC中视图这一部分的关pL为密切。模板语a的功能很丰富、强大,以处理所有必需的视囑֊能,同时它往往很简单,不熟(zhn)编E的Z可以使用它。模板语a不仅使得设计者从q于复杂的编E环境中解脱出来Q而且它保护了pȝQ避免了有意或无意带来危险的代码。例如,模板的编写者不可能~写出导致无限@环的代码Q或侵占大量内存的代码。不要轻估这些安全机制的价|大多数模板编写者不懂得~程Q从长远来看Q避免他们接触复杂的~程环境相当于节省了你自q旉。许多模板引擎的用户怿Q在采用模板引擎的方案中Q控制器部分和视N分的明确分离Q再加上模板引擎固有的安全机Ӟ使得模板引擎以成ؓ其他内容发布pȝQ比如JSPQ的替代Ҏ(gu)。因此,Java模板引擎最常见的用途是替代JSP也就不为奇了?/p>
3.HTML处理
׃ZL看重模板引擎用来替换JSP的作用,有时他们会忘记模板还有更q泛的用途。到目前为止Q模板引擎最常见的用途是处理HTMLWeb内容。但我还用模板引擎生成过SQL、email、XML甚至Java源代码?br />
y
1、什么是Content Repository Q?br /> 可以把Content Repository 看作是一个通用的数据存储程序,可以用于存储txt和其他二q制文gQ图片、Word、PDF{)?br /> Content Repository 的一个关键特性是Q你不必兛_数据是如何存攄Q无论数据存攑֜数据库、文件系l还是XML文gQ?br /> Content Repository 可以Ҏ(gu)件进行访问控制、查询、版本控制、锁定等?/p>
2、JSR-170的目标:
通过javax.jcr.* 中的cd接口可以讉K所有兼容JSR-170?Content Repository?br />实现了内Ҏ(gu)务的一些功能如Z~辑者的版本控制、完全文本搜索、访问控制、内容分cd内容事g监控。可以把JSR-170看作是一个访问内容仓库的cMJDBC的API?br /> 如果一些厂家的内容仓库不支持JSR-170则可以通过q些厂家提供的JSR-170驱动来完成从JSR-170与厂家特定的内容仓库的{换?br /> 内容仓库的数据存储方式可以是数据库或者文件系l或者是二者的混合?br />
3、JSR-170h如下优点Q?br />●对于开发者无需了解厂家的仓库特定的APIQ只要兼容JSR-170可以通过JSR-170讉K其仓库?br />●对于用CMS的公司则无需p资金用于在不同种cCMS的内容仓库之间进行{换?br />●对于CMS厂家Q无需自己开发内容仓库,而专注于开发CMS应用?/p>
4、JSR-170内容仓库模型Q?br />JSR-170声称内容仓库是由一些workspacel成的,每个工作I间应该存放怼的数据,每个工作I间包含一个树(wi)根节点,下面是一些itemsQ每个item是一个node或者propertyQ每个node下面包含一个或多个child node和一个或者多个propertyQproperty不能有子节点Q它们是叶子节点Q内容仓库中真正的值存攑֜property中?/p>
5、ؓ了厂家更容易的实现JSR-170QJSR-170提供了三U承诺别:
Level 1Q定义了一个只ȝ内容仓库?br />Level 2Q定义了可写的内容仓库?br />Advanced optionsQ定义实CU附加功能,版本控制、JTA、SQL查询、清晰的内容锁定和监视?/p>
引自Q?a >http://blogger.org.cn/blog/more.asp?name=lylhelin&id=20455