呵呵,这明显是标题党了,勿喷!

当今是互联网爆发的时代,所有行业都采用各种方式挤入互联网,不管餐饮小店还是小作坊,都知道要在互联网做宣传。互联网已经是新时代的广告平台!很多网站都是靠网络广告作为其主要收入来源。但要获得好的收入,首先网站的PV/UV量要比较高,才会有广告主找上门。或者你本身是需要做广告,通过广告提高网站PV量,从而提高销售额。提高了销售额,就提高了营收,也就可以提高网站的估值,最终把钱赚入腰包!

PV就是金钱,提高PV就是赚钱!

为了提高PV,是否只能做广告呢?当然不是,广告的目的是把你的信息发布到各个地方,让很多人看到,而新闻也有同样的作用!
新闻相对广告而言更具优势,因为广告是被动接收的,而新闻是人们主动要索取的信息。而且新闻具有广泛的传播平台,而且一段时间内还会成为大家的谈资,推广效果更好! 如果一个爆炸性的新闻中包含你的广告信息(当然是隐秘的间接的,比如公司名),传播不需要一分钱,能给你带来大量的PV,那是不是一件再好不过的事情呢?

然而,哪来这样爆炸性的新闻而其中又包含你的广告信息呢? 自己制造吧!如何制造呢?花钱吧!

  1. 花100万去做一个慈善,叫上各家媒体来做宣传;
  2. 或节省一点,花1万买上万个茶叶蛋声势浩大的在街上发放,表示你对白领吃不起茶叶蛋言论的不满,同时告之各路记者来采访;

但有没有不花钱的呢? 有!用你的声誉来制造新闻吧! 当然这些声誉损失不能影响你的未来发展,不然就得不偿失了!
比如你是某某集团网站的CEO,如果能够爆出和一个比自己小年龄相差很大的名气女神约会,而且是女神倒追你!这样的新闻是不是很爆炸啊!这个新闻足够大家谈论一段时间!而之前很大一部分人不知道某某集团的,开始访问你的网站,给你带来大量的PV,而其中一部分人会成为你的客户,给你带来不俗的交易量,让你赚取100万,1000万或更多,你是否会欣喜的接受呢? 你问女神愿意吗?女神说我会因此变得更有名气!

如果我再告诉你,互联网信息爆炸的今天,你的新闻很快就会被大家忘记!用你的声誉换100万,你是否愿意?
你问我愿意吗?我愿意但怕没有女神会愿意!

最后说明,此文纯属个人想法,切勿当真!

-- tablespace
CREATE tablespace MYPROJECT datafile 'D:\oracle\product\10.2.0\oratablespace\MYPROJECT.dbf'  SIZE 5m  autoextend ON NEXT  10m maxsize unlimited;

-- temporary tablespace
CREATE TEMPORARY tablespace MYPROJECT_TEMP tempfile 'D:\oracle\product\10.2.0\oratablespace\MYPROJECT_TEMP.dbf' SIZE 5m autoextend ON NEXT 10m maxsize unlimited;

-- USER SQL
CREATE USER MYUSER IDENTIFIED BY password
DEFAULT TABLESPACE "MYPROJECT"
TEMPORARY TABLESPACE "MYPROJECT_TEMP";

-- ROLES
GRANT "CONNECT","RESOURCE","DBA" TO MYUSER ;

-- SYSTEM PRIVILEGES

-- QUOTAS

整理一种Spring Security Web认证实现方案,其核心组件及认证过程说明如下:

实体设计说明:
1. Function,权限对象,和Role对象为多对多关系;
2. Role,角色对象,实现GrantedAuthority和ConfigAttribute接口;Autority和Attribute都返回RoleId;
3. User,用户对象,实现UserDetails接口,和Role对象为多对多关系;

服务设计说明:
1. FilterSecurityInterceptor继承AbstractSecurityInterceptor,需注入AccessDecisionManager、AuthenticationManager、SecurityMetadataSource;
2. SecurityMetadataSource需根据请求信息获得ConfigAttribute信息;具体实现类根据请求URI获得Function,再根据Functon获得ConfigAttribute(Role)列表;
3. AuthenticationManager需注入UserDetailsService,对提交信息进行认证,并获得UserDetails(User)的GrantedAuthority(Role)列表;
4. AccessDecisionManager实现类中decide方法,对以上获得的ConfigAttribute(Role)列表和GrantedAuthority(Role)列表进行对比,判断是否包含相同的项,若有则有权限,否则无权限;

一个可以抓图和录像的ActiveX控件,详情如下:

1. 网址:http://www.videocapx.com/

2. 其lite版包含大部分基本功能,售价99美元,standard版售价199美元( 1,236.32 人民币);

3. 其支持不同的视频编码和音频编码模式;使用视频MJPEG Compressor压缩模式,用200万高清摄像头录制10秒的影像录音文件大小大概为3M;

4. 此产品产商为欧洲产商,提供support网站进行支持;
其他联系方式:
Phone: 00387 30 513 858
Fax: 00387 30 513 858
Email: fathsoft@fathsoft.com

5. 产品特性如下:
1) Full access to all WDM-compatible devices
2) Support for multiple video inputs
3) Capture live video and audio
4) Text/Logo/Image overlay on video
5) Full multimedia player functionality
6) Capture live audio directly to MP3
7) Pause and resume capture without frame loss
8) Motion detection
9) Easily build video-surveillance , quality control or video-conferencing apps
10) Save video frames as JPG or PNG
11) Full access to RGB pixel data
12) Chroma-key effect (live or post-process)
13) Video-processing filters available
14) Resize, crop or zoom video
15) Samples with full source code included
16) Add video-capture to your web pages
17) Control PTZ camera, set brightness, saturation, hue, contrast
18) Draw graphics on video
19) Supports VC++, VB6, VB.NET, C#
20) Compatible with Windows 98, 2000, XP, Vista, Windows7 (32-bit and 64-bit)
21) Preview live video or playback video files to DeckLink card output
22) Video preview, capture and motion detection from IP/network cameras
23) Transfer video over network. Video-chat functionality.
24) Broadcast live video to Windows Media clients
25) Ti+A1:B25me Unlimited, Royalty-Free License

定义一个javascirpt方法,传入需要加载国际化消息key键数组,获得这些消息加载到页面中。

/*
 load i18n resource through javascript
 */

function loadi18n(keys) {
    if (keys == null || keys.length == 0) {
        return;
    }
    if(!window.i18n){var i18n = window.i18n = {}}
    jQuery(document).ready(function(){
        var method = keys.length > 20 ? "POST" : "GET";
        jQuery.ajax({
            url : context_path + "/js/resource",
            data:{"key[]":keys},
            type:method,
            cache:true,
            dataType:"script",
            success:function(data){}
        })}
    )
}

以下是一个Spring Controller根据传入key键返回国际化消息:

@RequestMapping(value = "/js/resource")
public void getMessages(@RequestParam(value = "key[]") String[] keys, HttpServletRequest request, HttpServletResponse response, Locale locale) {
    ResourceBundle resourceBundle = ResourceBundle.getBundle("message/messages", locale, JsI18nController.class.getClassLoader());
    response.setCharacterEncoding("utf-8");
    response.setContentType("application/javascript");
    StringBuilder contents = new StringBuilder();
    if (keys != null && keys.length > 0) {
        for (String key : keys) {
            String value = resourceBundle.getString(key);
            contents.append("i18n['" + key + "']=\"" + value + "\";");
        }
        try {
            response.getWriter().write(contents.toString());
        } catch (IOException e) {
            logger.error(e.getMessage(), e);
        }
    }  
}

以下是javascript动态调用获取国际化例子:

loadi18n([ "sure.delete", "success.delete" ]);
loadi18n([ "failure.delete" ]); //根据需要可多次反复调用

function delUser(userId) {
    if (confirm(i18n['sure.delete'])) {
        // to delete the user
    }
}

框架对关键的电子商务流程提供一个可配置的工作流的功能。如结算、支付、定价、购物车等的操作。这些工作流通过spring xml配置文件进行定义。一般其概况,broadleaf提供一个默认的配置,包括结算和支付这些基本的步骤,只需使用到简单的一些模块。大多数用户需要覆盖部分或全部步骤以满足实际商业需求。先讲解默认配置,再讲解如何客制化需求。

1.工作流概览

每个工作流实际上是一个SequenceProcessor 的实例。它管理顺序性的流程活动,以及处理异常状况。一个工作流主要有三个配置,process context factory、activities list、rollback handler。

<bean p:order="1000" id="blPaymentActivity" class="org.broadleafcommerce.core.payment.service.workflow.CompositeActivity">
    <property name="workflow" ref="blAuthorizeAndDebitWorkflow"/>
</bean>
<bean id="blPaymentWorkflow" class="org.broadleafcommerce.core.workflow.SequenceProcessor">
    <property name="processContextFactory">
        <bean class="org.broadleafcommerce.core.payment.service.workflow.SimplePaymentProcessContextFactory"/>
    </property>
    <property name="activities">
        <list>
            <ref bean="blPaymentActivity" />
        </list>
    </property>
    <property name="defaultErrorHandler" ref="blDefaultErrorHandler"/>
</bean>

1.1 ProcessContextFactory
processContextFactory 属性必须是一个实现ProcessContextFactory接口的类。此类负责创建一个ProcessContext实例。此例SimplePaymentProcessContextFactory创建了一个SimplePaymentContext实例。

ProcessContexts一般指和某一特殊的工作流有关,所以不同的工作流会有不同的ProcessContextFactory。一个特例是购物车工作流的新增、删除、更新等操作使用同一个ProcessContext 和ProcessContextFactory 。

1.2 Activities
activities 属性包含一个或个活动列表。每个活动只处理单一的工作(如计算税费、订单价格加总)。以上例子,提供了一个组合活动。组合活动可以包含一个“子工作流”,这样可以创建复杂嵌套的工作流。这个特殊的组合活动处理认证和借贷的组合功能。组合活动后面会再讲。

1.3 Error Handler
defaultErrorHandler属性设置异常处理器,它是一个ErrorHandler的实例。默认设置blDefaultErrorHandler,框架提供的一个简单的异常处理器,它只记录异常信息到system.out然后再抛出异常—停止工作流和当前线程正在处理的活动。稍后会再讲异常处理器。

2.Activity Ordering(活动顺序)

上例中的活动配置:

<bean p:order="1000" id="blPaymentActivity" class="org.broadleafcommerce.core.payment.service.workflow.CompositeActivity">
    <property name="workflow" ref="blAuthorizeAndDebitWorkflow"/>
</bean>

blPaymentActivity 有一个p:order属性,这是设置此活动的顺序,框架根据此属性决定各个活动执行的先后顺序。这让框架合并活动列表到同一个bean中时非常便捷。看一个更复杂的例子:

<bean p:order="1000" id="blVerifyCustomerMaxOfferUsesActivity" class="org.broadleafcommerce.core.offer.service.workflow.VerifyCustomerMaxOfferUsesActivity"/>
<bean p:order="2000" id="blPaymentServiceActivity" class="org.broadleafcommerce.core.checkout.service.workflow.PaymentServiceActivity"/>
<bean p:order="3000" id="blRecordOfferUsageActivity" class="org.broadleafcommerce.core.offer.service.workflow.RecordOfferUsageActivity"/>
<bean p:order="4000" id="blCompleteOrderActivity" class="org.broadleafcommerce.core.checkout.service.workflow.CompleteOrderActivity"/>

<bean id="blCheckoutWorkflow" class="org.broadleafcommerce.core.workflow.SequenceProcessor">
    <property name="processContextFactory">
        <bean class="org.broadleafcommerce.core.checkout.service.workflow.CheckoutProcessContextFactory"/>
    </property>
    <property name="activities">
        <list>
            <ref bean="blVerifyCustomerMaxOfferUsesActivity" />
            <ref bean="blPaymentServiceActivity" />
            <ref bean="blRecordOfferUsageActivity" />
            <ref bean="blCompleteOrderActivity" />
        </list>
    </property>
    <property name="defaultErrorHandler" ref="blDefaultErrorHandler"/>
</bean>

在Broadleaf工作流中,每个活动顺序都会定义大于1000,这样允许你在其间插入你自己的活动。例如增加一个活动在记录促销使用情况和标记订单完成两个活动之间,可以在自己的spring配置文件applicationContext-mycompany.xml中进行如下定义:

<bean id="blCheckoutWorkflow" class="org.broadleafcommerce.core.workflow.SequenceProcessor">
    <propety name="activities">
        <bean p:order="3500" class="com.mycompany.core.workflow.DecrementInventoryActivity" />
    </property>
</bean>

需要注意:如果2个活动的顺序一样(例如都是3000),那么将根据所处位置进行排序。意思是根据applicationContext配置文件中的被解析合并的顺序(在web.xml中的patchConfigLocations 中定义)。整合模块定义活动顺序应该以100为间隔(如3100,3200等),这样未来还可以在其间加入一些特殊的活动。所有框架的活动可以通过bean id覆盖同时改变p:order的值以改变活动顺序。如果没有明确声明顺序的活动将在流程最后执行(默认顺序是Ordered.LOWEST_PRECEDENCE)。

3.Rollback Handlers(回滚处理器)

回滚处理器为活动提供了注册状态的途径,可以在之后的某一个时间执行一个回滚动作。此例,结算流程第一步可以是一个信用卡借贷。信用卡支付后,第二步是改变购物车状态。假如此时因某些原因导致购物车状态更新失败,应有一个标准的方式将之前信用卡支付进行退还或者作废。这就是回滚处理器的作用。
回滚处理器能处理任何客户代码,也能根据传入状态进行处理。总之,回滚操作无需向支付网关一样需要一个外部服务。可以认为是一个compensating transaction(补偿事务)恢复DB到执行活动之前的状态。这是一个重要的差别,大多是工作流在JDBC事务中无法执行,因为工作流的生命周期长度让保证事务开启状态变得不切实际。既然整个工作流并没有在单一的某一个事务中,那么遇到异常的时候就不能立刻自动回滚DB状态,意味着回滚处理器需要明确的将DB设置回想要的状态。
最简单回滚处理器可通过在配置在spring活动定义中。看一个例子:

<bean id="blTestRollbackHandler" class="org.broadleafcommerce.core.workflow.state.test.TestRollbackHandler"/>

<bean p:order="1000" id="blVerifyCustomerMaxOfferUsesActivity" class="org.broadleafcommerce.core.offer.service.workflow.VerifyCustomerMaxOfferUsesActivity"/>
<bean p:order="2000" id="blPaymentServiceActivity" class="org.broadleafcommerce.core.checkout.service.workflow.PaymentServiceActivity">
    <property name="rollbackHandler" ref="blTestRollbackHandler"/>
</bean>
<bean p:order="3000" id="blRecordOfferUsageActivity" class="org.broadleafcommerce.core.offer.service.workflow.RecordOfferUsageActivity"/>
<bean p:order="4000" id="blCompleteOrderActivity" class="org.broadleafcommerce.core.checkout.service.workflow.CompleteOrderActivity"/>

<bean id="blCheckoutWorkflow" class="org.broadleafcommerce.core.workflow.SequenceProcessor">
    <property name="processContextFactory">
        <bean class="org.broadleafcommerce.core.checkout.service.workflow.CheckoutProcessContextFactory"/>
    </property>
    <property name="activities">
        <list>
            <ref bean="blVerifyCustomerMaxOfferUsesActivity" />
            <ref bean="blPaymentServiceActivity" />
            <ref bean="blRecordOfferUsageActivity" />
            <ref bean="blCompleteOrderActivity" />
        </list>
    </property>
    <property name="defaultErrorHandler" ref="blDefaultErrorHandler"/>
</bean>

此例,blPaymentServiceActivity配置rollbackHandler 为blTestRollbackHandler,它将在任何子活动发送异常的时候执行。注意,一个活动发生异常时,它自己的回滚处理器不会被执行,只执行那些在工作流中已经处理过的活动的回滚处理器。如果需要,当活动失败的时候,活动有职责修正自身的状态。此例test rollback handler只是简单记录log,但在实际生产环境需要调用支付网关将支付退还或作废。

3.1 RollbackHandler Interface(回滚处理器接口)
所有回滚处理器实现RollbackHandler接口,它只有一个方法。

public void rollbackState(Activity<? extends ProcessContext> activity
    , ProcessContext processContext
    , Map<String, Object> stateConfiguration) throws RollbackFailureException;

接口参数包含所有补偿事务所需的信息,包括活动对象activity和ProcessContext以及stateConfiguration。stateConfiguration包含前面活动执行相关操作的信息,可用于反转之前的操作。stateConfiguration是活动activity执行的时候提供的,后面会再讲。

3.2 ActivityStateManager(活动状态管理器)
ActivityStateManager是一个灵活的组件,用来注册rollback handler回滚处理器和其他附随的状态信息。它可在工作流任何位置直接调用(Activity, Module, ErrorHandler, 等).如下获得其实例:

ActivityStateManagerImpl.getStateManager();

ActivityStateManager接口提供多个方法注册RollbackHandler(回滚处理器)和state(状态)。实际上,你可以重载版本的registerState(其接收region参数)改善回滚行为。Region允许给一个活动多个RollbackHandler添加一个群组标签,这样提供了一个方式可选择性的回滚一部分已注册rollback handler。ActivityStateManager也提供方法清除状态或执行回滚,这些方法可以在任何时间调用执行(或者让系统在之后自动调用这些方法)。
以下实际的例子,PaymentActivity执行完后注册状态。

if (getRollbackHandler() != null && automaticallyRegisterRollbackHandlerForPayment) {
    Map<String, Object> myState = new HashMap<String, Object>();
    if (getStateConfiguration() != null && !getStateConfiguration().isEmpty()) {
        myState.putAll(getStateConfiguration());
    }
    myState.put(ROLLBACK_ACTIONTYPE, seed.getActionType());
    myState.put(ROLLBACK_PAYMENTCONTEXT, paymentContext);
    myState.put(ROLLBACK_RESPONSEITEM, paymentResponseItem);

    ActivityStateManagerImpl.getStateManager().registerState(this, context, getRollbackHandler(), myState);
}

此代码片段看是否在context配置了静态的state。接着将当前支付信息加入到state配置中。最后注册Activity、ProcessContext、RollbackHandler和state MAP对象到ActivityStateManager单例中。

3.3 Implicit vs Explicit Registration (隐式或显式注册)
默认需在代码中(如上例)显示注册RollbackHandler,因为RollbackHandler需要注册特殊线程状态以便获得可行的回滚状态。但对于简单的rollback handler,无需特殊线程状态完成回滚,系统可以配置为隐式(自动的)回滚注册类型。例如:

<bean id="myActivity"
     class="com.test.MyActivity">
    <property name="rollbackHandler" ref="blTestRollbackHandler"/>
    <property name="stateConfiguration">
        <map>
            <entry key="testProperty" value="testValue"/>
        </map>
    </property>
    <property name="automaticallyRegisterRollbackHandler" value="true"/>
</bean>

此例,声明了rollbackHandler和一些静态状态,让系统自动注册RollbackHandler。因为这里我们不关系线程特殊状态,注册RollbackHandler到ActivityStateManager单例中,这些就是所有需要的配置。

3.4 Implicit vs Explicit Rollback (隐式或显式回滚)
默认,工作流执行异常时会自动执行注册的RollbackHandler。但有时可能更希望是通过代码中通过ActivityStateManager明确的调用回滚。要启动“显式回滚”,需在runtime property文件中声明配置:

workflow.auto.rollback.on.error=false

注意,此配置会被每个workflow工作流的autoRollbackOnError属性覆盖。

4.ProcessContext(执行容器)

ProcessContext是一个容器对象,作为activity的传入传出参数。它一般包含workflow工作流相关信息。支付workflow工作流用SimplePaymentContext,它包含PaymentSeed。而PaymentSeed中包含多个PaymentInfo、Order和PaymentResponse这些处理订单请求的对象。另外 ProcessContext提供stopProcess和isStopped方法设置和检查工作流状态。调用stopProcess可不用抛出异常停止工作流继续执行。

public class SimplePaymentContext implements ProcessContext {

    public final static long serialVersionUID = 1L;

    private boolean stopEntireProcess = false;
    private PaymentSeed seedData;

    public void setSeedData(Object seedObject) {
        this.seedData = (PaymentSeed) seedObject;
    }

    public boolean stopProcess() {
        this.stopEntireProcess = true;
        return stopEntireProcess;
    }

    public boolean isStopped() {
        return stopEntireProcess;
    }

    public PaymentSeed getSeedData() {
        return seedData;
    }

}

4.1 Conditional Activity Execution(活动条件执行)
Activity接口根据ProcessContext中的信息决定是否要跳过执行当前活动。Activity再调用前都会调用此方法进行判断,避免工作流重复定义,因为或许一个较大的工作流配置使用同一个ProcessContext的多个配置。

5.Activities(活动)

一个活动是Activity接口的实例,提供执行活动和获取error handler的方法。大多活动对象继承BaseActivity虚类。如PaymentActivity,可获得PaymentContext对象,也可加入到PaymentService中完成支付交易。
一个Java范型定义活动只针对特定的工作流(及只能在特定的ProcessContext中执行),例如下面这个针对blPricingWorkflow工作流的活动:

public class TotalActivity extends BaseActivity<PricingContext> {

    @Override
    public PricingContext execute(PricingContext context) throws Exception {
        Order order = context.getSeedData();
        //compute all totals for the order
        return context;

    }
}

针对blCheckoutWorkflow工作流的活动:

public class CompleteOrderActivity extends BaseActivity<CheckoutContext> {

    @Override
    public CheckoutContext execute(CheckoutContext context) throws Exception {
        CheckoutSeed seed = context.getSeedData();

        seed.getOrder().setStatus(OrderStatus.SUBMITTED);
        seed.getOrder().setOrderNumber(new SimpleDateFormat("yyyyMMddHHmmssS").format(SystemTime.asDate()) + seed.getOrder().getId());
        seed.getOrder().setSubmitDate(Calendar.getInstance().getTime());

        return context;
    }

}

组合活动也是继承于BaseActivity,所以也可加入到工作流活动list列表中。但他们配置上有差异,组合活动需配置一个子工作流。组合活动由父工作流调用,传递到子工作流,子工作流的活动也会依次被调用。所有子工作流和所有异常都绑定到同一个ProcessContext对象,调用stopProcess方法将停止所有嵌套的工作流。使用组合活动,可以方便实现复杂嵌套的工作流。

6.Error Handlers(错误处理器)

Error handlers错误处理器都实现ErrorHandler接口。但发送异常时,可以通过Error handlers做一些必要的事情。如记录异常日志,或释放资源等。之前提过,所有工作流默认使用DefaultErrorHandler,它只是将异常信息输出到System.out后再抛出异常。

public interface ErrorHandler extends BeanNameAware {
    public void handleError(ProcessContext context, Throwable th) throws WorkflowException;
}

7.Removing a Broadleaf Workflow(删除工作流)

如果因为需要扩展功能而需要删除框架默认定义的工作流,可通过定义一个EmptySequenceProcess实例的工作流覆盖默认配置(但我们不建议这样做)。如因你已继承了OrderService覆盖了performCheckout()方法,你想去掉blCheckoutWorkflow工作流,可以通过如下定义去掉:

<bean id="blCheckoutWorkflow" class="org.broadleafcommerce.core.workflow.EmptySequenceProcessor" />

8.Provided Workflows(已提供的工作流)

以下是一些框架提供的工作流:

blAddItemWorkflow 添加商品到购物车流程
blUpdateItemWorkflow 更新购物车商品流程
blRemoveItemWorkflow 删除购物车商品流程
blPricingWorkflow 被 blPricingService(被OrderService调用)使用 来计算订单价格
blCheckoutWorkflow 订单中被blCheckoutService 调用以完成订单结算(支付、标记减少存货、改变状态为SUBMITTED等等)
blPaymentWorkflow blCheckoutWorkflow 中的 CompositeActivity ,其运行多种支付方式

订单支付有多种发生情况也有多种支付方式。blPaymentWorkflow 是一个活动组件,可将默认的支付配置流程进行包装(即blAuthorizeAndDebitWorkflow)。一般情况,如果在订单送货之前无需支付,可将blPaymentWorkflow 的workflow属性改为blAuthorizeWorkflow ,它只会简单的通过支付提供者对客户的支付信息进行认证。当到快递包装的时候再执行blDebitWorkflow完成支付。支付相关流程列举如下:
broadleaf_framework_workflow

9.参考

1. Workflows and Activities
2.bl-framework-applicationContext-workflow.xml

Merge configuration是通过web.xml处理的,broadleaf的merge功能智能的合并一个或多个spring配置文件。合并的最终版本才被传递给spring处理。为了让broadleaf知道要merge那些文件,你必须在web.xml中声明。首先,我们提供一个patchConfigLocation的参数,表示你的spring context文件列表。你可以任意添加,它们将被合并到broadleaf配置中。

<context-param>
    <param-name>patchConfigLocation</param-name>
    <param-value>
        /WEB-INF/applicationContext-custom.xml
        /WEB-INF/applicationContext-email.xml
        /WEB-INF/applicationContext-search.xml
        /WEB-INF/applicationContext-security.xml
    </param-value>
</context-param>

其次,需声明org.broadleafcommerce.common.web.extensibility.MergeContextLoaderListener这个listener。它的职责是负责初始化broadleaf内部context信息和你声明的context文件直接的merge。

<listener>
    <listener-class>org.broadleafcommerce.common.web.extensibility.MergeContextLoaderListener</listener-class>
</listener>

当merge遇到有冲突的bean声明的时候,broadleaf知道如何处理合并或覆盖。
如,你声明了一个id为blOrderService的bean,broadleaf将使用你声明的bean。但是,某一些情况不会覆盖,而是会合并bean的内容。如以下blWebTemplateEngine声明:

<bean id="blWebTemplateEngine" class="org.thymeleaf.spring3.SpringTemplateEngine">
    <property name="dialects">
        <set>
            <ref bean="thymeleafSpringStandardDialect" />
            <ref bean="blDialect" />
        </set>
    </property>
</bean>

如果你想添加你自己的dialect,你可以简单的在你的context文件中添加以下声明。

<bean id="blWebTemplateEngine" class="org.thymeleaf.spring3.SpringTemplateEngine">
    <property name="dialects">
        <set>
            <ref bean="myCustomDialect" />
        </set>
    </property>
</bean>

我们已经表明这个bean的属性为可merge的属性,而不是覆盖。所以最终,被spring处理的bean将是如下的样子:

<bean id="blWebTemplateEngine" class="org.thymeleaf.spring3.SpringTemplateEngine">
    <property name="dialects">
        <set>
            <ref bean="thymeleafSpringStandardDialect" />
            <ref bean="blDialect" />
            <ref bean="myCustomDialect" />
        </set>
    </property>
</bean>

参考

1.Broadleaf’s Unique Application Context Merge Process Explained
2.Broadleaf Merge Process 2.0
3.Merge Configuration

1. What’s BroadleafCommerce

BroadleafCommerce是一个Java开源电子商务网站框架。其目标是开发企业级商务网站,它提供健壮的数据和服务模型、富客户端管理平台、已经一些核心电子商务有关的工具。

2.Features

2.1 Catalog (目录分类)
提供灵活的产品和类型管理,一个重要的特性是可以继承产品分类来满足特殊的商业需求。
管理界面可以管理各种类别和产品。

2.2 Promotion System(促销系统)

可通过配置的方式管理促销。
以下类促销示无需客制化而通过管理界面即可管理:
百分比折扣、金额折扣、固定价格(Percent Off / Dollar Off / Fixed Price)
订单、订单项、快递级别促销
买一赠一促销
基于客户、购物车或类别属性的促销

2.3 Content Management System(内容管理系统)
内容管理系统有以下特性:
支持用户直接管理静态页面
可以配置顾客内容类型(如广告)
提供UI界面管理静态页面、结构化内容、图片以及其他内容;
结构化内容能够针对性的对某些客户显示(如对满足一定条件的客户显示广告)

3.Architecture

3.1 Spring Framework
Spring提供诸多功能,包括依赖注入和事务管理

3.2 Security
Spring Security提供强健的安全认证框架,控制代码和页面级别的认证和授权。

3.3 Persistence
使用JPA和hibernate实现ORM基础

3.4 Asynchronous Messaging
使用spring JMS和一个现代的JMS代理交互来实现应用消息的异步处理。

3.5 Search
通过整合流行的Compass和lucene项目提供可灵活的domain查找功能。

3.6 Task Scheduling
使用Quartz提供排程功能。

3.7 Email
Email功能分为同步和异步(jms)两种模式。Email内容可以通过velocity模块客制化。支持mail打开和连接点击跟踪。

3.8 Modular Design(模块化设计)
提供各种模块,可以和电子商务的一些重要功能进行交互,如信用卡处理、税收服务、快递公司。
比如,USPS快递模块是一个好的案例。 客户模块可以很方便的开发并整合进来。

3.9 Configurable Workflows(可配置的工作流)
电子商务生命周期的关键表现在可配置的工作流。系统能够对这些关键的地方进行完全的控制,包括价格和结账,允许对订单、行为和客户执行模块进行操作。支持复杂内嵌行为的合成工作流。

3.10 Extensible Design(可扩展性设计)
扩展性是我们设计的核心,几乎broadleaf所有的组件都是可以继承、或添加、或者通过修改增强和改变默认的行为。 这些组件包括所有的service、数据访问对象、实体。

3.11 Configuration Merging(配置合并)
我们以扩展模块的附加部分,为客户提供对spring配置文件进行合并的功能。它可以最小化配置,一个实现必须清楚它允许用户只需把精力放在他们自己的配置细节。 Broadleaf在运行时会智能的将实现者的配置信息和自己的配置信息进行合并。

3.12 Runtime Configuration Management(运行时配置管理)
services、模块和其他子系统的配置属性通过JMX暴露,这样管理者不用关闭系统就可以改变应用行为。

3.13 Presentation Layer Support(表现层支持)
提供很多事先写好的spring MVC控制器来加快表现层的开发。

3.14 QoS(服务质量)
提供对客户和默认模块的服务质量监控,同时支持外部日志和email。其他客户Qos处理器可以通过我们的open API添加。

3.15 PCI Considerations(PCI注意事项)
我们的架构和设计经过了仔细的分析,帮助你在决定存储和使用敏感的客户金融账号信息的时候实现PCI遵从性。支付账号信息是分别引用的,允许你将机密的数据隔离存储到一个独立的安全的数据库平台。已经添加了API方法来包含PCI遵从性加密schema。另外,提供冗长的日志跟踪交易交互信息。

PCI(Payment Card Industry)(Payment Card Industry (PCI) Data Security Standard).支付卡行业 (PCI) 数据安全标准 (DSS)是一组全面的要求,旨在确保持卡人的信用卡和借记卡信息保持安全,而不管这些信息是在何处以何种方法收集、处理、传输和存储。

PCI DSS 由 PCI 安全标准委员会的创始成员(包括 American Express、Discover Financial Services、JCB、MasterCard Worldwide 和 Visa International)制定,旨在鼓励国际上采用一致的数据安全措施。
PCI DSS 中的要求是针对在日常运营期间需要处理持卡人数据的公司和机构提出的。具体而言,PCI DSS 对在整个营业日中处理持卡人数据的金融机构、贸易商和服务提供商提出了要求。PCI DSS 包括有关安全管理、策略、过程、网络体系结构、软件设计的要求的列表,以及用来保护持卡人数据的其他措施。

3.16 Customizable Administration Platform (客制化管理平台)
管理应用基于我们新的开放的管理平台,使用标准面向对象的技术提供一个清晰的客制化方式。管理平台和核心框架一样,都有很好扩展性。表现层是基于有名的可信赖的GWT和SmartGWT技术。

4.Reference

4.1.get start
4.2.Framework source code:
4.3.Switching to MySQL
4.4.Customize the UI(客制化UI界面)
4.5.Configure Checkout(配置结账)
4.6.Production Considerations
4.7.Storing additional customer properties
4.8.Extend the Customer entity
4.9.Hook into the order submit workflow
4.10.Hook into the add to cart workflow

目录

1.关于Maven
2.关于POM
3.关于Repository
4.关于Settings
5.关于Repository Mirror
6.标准文件结构:
7.依赖机制
8.引用依赖(Importing Dependencies)
9.系统依赖(System Dependencies)
10.FAQs

1.关于Maven

Maven开发者的愿景:
We wanted a standard way to build the projects, a clear definition of what the project consisted of, an easy way to publish project information and a way to share JARs across several projects.
The result is a tool that can now be used for building and managing any Java-based project. We hope that we have created something that will make the day-to-day work of Java developers easier and generally help with the comprehension of any Java-based project.

Maven的目标:
Making the build process easy – 让创建过程变动容易
Providing a uniform build system – 提供一个统一的创建部署系统
Providing quality project information – 提供有质量的项目信息支持
Providing guidelines for best practices development – 提供最佳开发实际指导
Allowing transparent migration to new features – 允许无缝整合新的功能特性

参考:
1.What is maven
2.Maven Documents
3.Maven Reference

2.关于POM

POM全称 Project Object Model(项目对象模型),它是Maven工作的基础。

POM中包含以下信息:
Dependencies – libraries依赖关系
developers and contributors – 开发者和共享者信息
plugin lists (including reports) – 插件列表
plugin executions with matching ids – id关联的插件执行
plugin configuration – 插件配置
resources – 其他资源信息

POM中并不需要全部配置这些信息,POM配置通过继承方式继承parent POM(父POM)或super POM(顶级POM)的配置(另外repository相关配置信息还继承于settings.xml),这样极大简化配置要求。

最简单的POM只需配置modelVersion、groupdId、artifactId、version即可,其他信息则继承于super POM和seetings.xml,如:

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.mycompany.app</groupId>
  <artifactId>my-module</artifactId>
  <version>1</version>
</project>

如果是继承于parent,需声明parent的groupId、artifactId、version、relativePath(Parent POM位置);如果groupId和version同parent一致,则无需再声明; 如果该模块要打包为jar,则可声明packaging为jar;如:

<project>
  <parent>
    <groupId>com.mycompany.app</groupId>
    <artifactId>my-app</artifactId>
    <version>1</version>
    <relativePath>..</relativePath>
  </parent>
  <modelVersion>4.0.0</modelVersion>
  <artifactId>my-module</artifactId>
<packaging>jar</packaging>
</project>

Parent模块的POM需声明packaging方式为POM,并指定子模块modules,如下:

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.mycompany.app</groupId>
  <artifactId>my-app</artifactId>
  <version>1</version>
  <packaging>pom</packaging>

  <modules>
    <module>my-module</module>
  </modules>
</project>

声明依赖关系的方式如下(下例中还说明如何声明一个变量):

<project>
  ...
  <properties>
    <mavenVersion>2.1</mavenVersion>
  </properties>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
    </dependency>
    <dependency>
      <groupId>org.apache.maven</groupId>
      <artifactId>maven-artifact</artifactId>
      <version>${mavenVersion}</version>
    </dependency>
    <dependency>
      <groupId>org.apache.maven</groupId>
      <artifactId>maven-project</artifactId>
      <version>${mavenVersion}</version>
    </dependency>
  </dependencies>
  ...
</project>

关于super POM:
All Maven project POMs extend the Super POM, which defines a set of defaults shared by all projects. This Super POM is a part of the Maven installation. Depending on the Maven version it can be found in the maven-x.y.z-uber.jar or maven-model-builder-xy.z.jar file in ${M2_HOME}/lib. If you look in this JAR file, you will find a file named pom-4.0.0.xml under the org.apache.maven.model package. It is also published on the Maven reference site
This setting can be overridden by a custom settings.xml file.

参考:introduction to the pom

3.关于Repository

Repository用于存放artifacts以及各种依赖相关文件。
Repository分两种:local、remote;local repository指本地文件缓存,其结构跟remote repository一样,便于同步比较更新; remote repository分为internal和internet两种,建立内网internal repository是为了下载方便(更快速、更好管理);internal repository有时作为repository manager,可以proxy多个外网repository,而只需一个配置一个internal repository地址即可。

Repository软件参考:Nexus,Artifacotry

参考:introduction to repositories

4.关于Settings

默認settings配置文件是:~/.m2/settings.xml,首先需要配置本地repository存放位置:

<settings>
  ...
<localRepository>f:/maven_repository</localRepository>
...
</settings>

配置repository,先聲明一個profile,聲明其id和下載屬性,然後配置repositories和pluginRepositories; 最後在activeProfile中聲明那一個profile是生效的:

<settings>
<localRepository>f:/maven_repository</localRepository>
<profiles>
<profile>
    <id>artifactory</id>
    <properties>
        <downloadSources>true</downloadSources>
        <downloadJavadocs>true</downloadJavadocs>          
    </properties>
    <repositories>
          <repository>
                <id>central</id>
                <url>http://192.168.1.10:9999/nexus/content/groups/public</url>
                <snapshots>
                      <enabled>true</enabled>
                </snapshots>
          </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
                <id>central</id>
                <url>http://192.168.1.10:9999/nexus/content/groups/public</url>
                <snapshots>
                      <enabled>false</enabled>
                </snapshots>
          </pluginRepository>
    </pluginRepositories>
</profile>
</profiles>

<activeProfiles>
  <activeProfile>artifactory</activeProfile>
</activeProfiles>

</settings>

Repository訪問先後順序:

  1. 优先访问settings.xml中的配置的repository,然后再访问pom.xml中配置的repository;
  2. 如果setting.xml和pom.xml中的repository的id重复,则直接使用setting.xml中的配置;
  3. 如果setting.xml和pom.xml中都未配置repository,则使用默认的repository:http://repo.maven.apache.org/maven2

參考:
Settings配置説明

5.关于Repository Mirror

Repository Mirror (鏡像)用於轉發一個或多個對repository的請求到指定的Mirror (鏡像)服務器下載。以下幾種情景需要用到Repository Mirror (鏡像):
鏡像服務器離得跟進,訪問速度更快;
用本地的Repository服務替換特定的Repository服務,以便更好的管理;
運行Repository Manager作本地緩存;

鏡像配置方式:

<settings>
  ...
  <mirrors>
    <mirror>
      <id>UK</id>
      <name>UK Central</name>
      <url>http://uk.maven.org/maven2</url>
      <mirrorOf>central</mirrorOf>
    </mirror>
  </mirrors>
  ...
</settings>

如上,將對central (repository ID)repository的訪問全部轉向到http://uk.maven.org/maven2鏡像;
mirrorOf有多种配置方式:

  1. *:表示所有的repository
  2. xxx,yyy:表示repository的id名稱,如果要轉發多個repository,則多個id值用逗號區隔;
  3. *,!repo1 :表示所有repository但除開repo1
  4. external:* :表示所有repository,但除開本地以及文件訪問路徑的repository(非http)

可以強制將所有repository請求都轉發到内網repository服務器上,可以提高訪問速度的同時也便於管理:

<settings>
  ...
  <mirrors>
    <mirror>
      <id>internal-repository</id>
      <name>Maven Repository Manager running on repo.mycompany.com</name>
      <url>http://repo.mycompany.com/proxy</url>
      <mirrorOf>*</mirrorOf>
    </mirror>
  </mirrors>
  ...
</settings>

參考:maven mirros settings

6.标准文件结构

Maven项目默认的标准文件结构如下:

src/main/java       Application/Library sources
src/main/resources  Application/Library resources
src/main/filters    Resource filter files
src/main/assembly   Assembly descriptors
src/main/config     Configuration files
src/main/scripts    Application/Library scripts
src/main/webapp     application sources
src/test/java       Test sources
src/test/resources  Test resources
src/test/filters    Test resource filter files
src/site            Site
LICENSE.txt         Project's license
NOTICE.txt          Notices and attributions required by libraries that the project depends on
README.txt          Project's readme

顶层子目录有src和target,target是编译部署相关的输出目录。
参考:maven standard directory layout

7.依赖机制

Transitive dependencies传递依赖:
不用 显式的声明所有依赖,maven会自动将所有依赖包含进来;不管依赖数量或依赖层级有多少,但是如果发现循环依赖,则会出错。
因为传递依赖的特性,可能会导致依赖的library数量不断增大;Maven提供了一些限制加入依赖的特性:

  1. Dependency mediation(依赖仲裁) – 当遇到多个版本的library的时候决定使用哪一个版本;Maven2.0开始支持“nearest definition”最短定义机制,它会选择使用依赖树中位置最靠近的依赖版本;但是也可以明确的再POM中声明需要使用那一个版本(对主要的依赖建议明确声明,如使用Spring MVC会自动依赖引入Spring core,但是明确声明Spring Core的版本是比较好的选择,比如Spring Security所需的Spring Core版本可能与Spring MVC不一样)。如果在依赖树中同一层级发现两个版本,从Maven2.0.9开始,会使用第一个声明的版本;”nearest definition”(最短定义)说明:如声明了依赖A,B,C, 其中有依赖关系 A -> B -> C -> D 2.0 和A -> E -> D 1.0, 这个时候就会选择D 1.0 ,因为A到D的路径通过E最短. 但是引入D1.0会导致B,C无法正常依赖,此时可以明确的添加依赖声明依赖D2.0.
  2. Dependency Management(依赖管理)- 直接声明所需library的版本。在上例中D间接被A引用,尽管已被引用,但可以再配置中明确的声明所需版本。
  3. Dependency scope(依赖范围)- 允许你在当前build阶段只包含适合的依赖。
  4. Excluded dependencies (非包含依赖)- 如果X依赖Y, Y依赖Z, 但可以通过声明“exclusion”标签明确去除对Z的依赖。
  5. Optional dependencies (选择依赖)- Y依赖Z,Y可以把Z通过optional标签表明为选择依赖。X依赖Y,但X不会传递依赖Z. X只有明确声明依赖Z才会生效。选择依赖可以理解为“默认的非包含依赖”。

Dependency scope(依赖范围)
依赖范围用于限制依赖传递,同时影响各种build任务的classpath引用范围;
有6中依赖范围:

  1. compile(编译范围)- 默认范围。编译范围的依赖再所有项目的classpath都是可以引用到的。且这些依赖可以传递到所有子项目中。
  2. provided(供给范围)- 很像compile编译范围,但它表明在运行时由JDK或者container提供这些依赖。例如,创建企业级java web应用,你可能会设置servlet和其他一些JavaEE的范围为provided,因为这些library会由container提供。供给范围只会在当前项目的编译和测试的classpath可以引用。不具传递性!
  3. runtime(运行时范围)- 此范围表明在编译的时候是不需要的,只有在运行时才需要。在运行时和测试的classpath才可以引用到。
  4. test(测试范围)- 此范围表明在一般情况下不会使用到,只有在测试编译或测试运行的时候才会引用到。
  5. system(系统范围)- 此范围类似provided供给范围,但除了一点,那就是你必须明确的在项目中提供这个jar档,maven认为它任何时候都是引用到的,不会从任何repository查看。
  6. import (2.0.9或之后的版本)(引用范围)- 此范围仅被用于packaging 为pom类型的节点下的依赖声明,表明这个特殊的POM的依赖会被 节点下的声明所覆盖。既然是被覆盖了,这些import范围的依赖并不会实际限制传递依赖。

每一个范围(除了import引用范围)对传递依赖的影响不一样,如下表显示。

依赖范围--> 传递依赖范围
compile --> compile(*)、runtime
provided--> provided
runtime --> runtime
test    --> test

注意:(*)表示这本应该是runtime范围,所以所有compile范围的依赖都需要明确的声明。但有一种情况,一个依赖的library继承了其他library的一个class,那么就会强制要求在compile的时候就需要引入。因为这个原因编译范围依赖任然保持为编译范围依赖,尽管它是可传递的。

dependencymanagement 和 dependencies的区别:

  1. 父项目的POM可以声明dependencies和dependencymanagement节点依赖;
  2. Dependencies会被所有子项目的POM直接继承;
  3. Dependencymanagement不会被子项目POM继承,但至项目可以在dependencies节点中声明所需的library,无需声明version版本;则此依赖会被父POM中Dependencymanagement定义的对应依赖声明覆盖。也就是说Dependencymanagement可以起到一个统一管理library版本信息的作用。同时因为其不会被子项目POM继承,这样就不会造成所有子项目都继承相同library,而其中很多library可能都是不需要的。

参考:
1.Introduction to the Dependency Mechanism
2.differences between dependencymanagement and dependencies of maven

8.引用依赖(Importing Dependencies)

Maven2.0.9开始加入此特性。之前的版本将不会解析import范围的声明。在考虑使用它之前请仔细权衡。如果一定要使用,建议使用enforce plugin强制使用Maven 2.0.9或以上版本。因为只能继承一个parent,可能不能满足一些大项目的要求,为了能够引用依赖多个项目,可以通过定义一个import范围的POM artifact。

Project A:

<project>
 <modelVersion>4.0.0</modelVersion>
 <groupId>maven</groupId>
 <artifactId>A</artifactId>
 <packaging>pom</packaging>
 <name>A</name>
 <version>1.0</version>
 <dependencyManagement>
   <dependencies>
     <dependency>
       <groupId>test</groupId>
       <artifactId>a</artifactId>
       <version>1.2</version>
     </dependency>
     <dependency>
       <groupId>test</groupId>
       <artifactId>b</artifactId>
       <version>1.0</version>
       <scope>compile</scope>
     </dependency>
     <dependency>
       <groupId>test</groupId>
       <artifactId>c</artifactId>
       <version>1.0</version>
       <scope>compile</scope>
     </dependency>
     <dependency>
       <groupId>test</groupId>
       <artifactId>d</artifactId>
       <version>1.2</version>
     </dependency>
   </dependencies>
 </dependencyManagement>
</project>

Project B:

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>maven</groupId>
  <artifactId>B</artifactId>
  <packaging>pom</packaging>
  <name>B</name>
  <version>1.0</version>
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>maven</groupId>
        <artifactId>A</artifactId>
        <version>1.0</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
      <dependency>
        <groupId>test</groupId>
        <artifactId>d</artifactId>
        <version>1.0</version>
      </dependency>
    </dependencies>
  </dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>test</groupId>
      <artifactId>a</artifactId>
      <version>1.0</version>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>test</groupId>
      <artifactId>c</artifactId>
      <scope>runtime</scope>
    </dependency>
  </dependencies>
</project>

所有A的管理依赖将被合并加入到B中,除了d,因为它已经在B中定义了。
Project X:

<project>
 <modelVersion>4.0.0</modelVersion>
 <groupId>maven</groupId>
 <artifactId>X</artifactId>
 <packaging>pom</packaging>
 <name>X</name>
 <version>1.0</version>
 <dependencyManagement>
   <dependencies>
     <dependency>
       <groupId>test</groupId>
       <artifactId>a</artifactId>
       <version>1.1</version>
     </dependency>
     <dependency>
       <groupId>test</groupId>
       <artifactId>b</artifactId>
       <version>1.0</version>
       <scope>compile</scope>
     </dependency>
   </dependencies>
 </dependencyManagement>
</project>

Project Y:

<project>
 <modelVersion>4.0.0</modelVersion>
 <groupId>maven</groupId>
 <artifactId>Y</artifactId>
 <packaging>pom</packaging>
 <name>Y</name>
 <version>1.0</version>
 <dependencyManagement>
   <dependencies>
     <dependency>
       <groupId>test</groupId>
       <artifactId>a</artifactId>
       <version>1.2</version>
     </dependency>
     <dependency>
       <groupId>test</groupId>
       <artifactId>c</artifactId>
       <version>1.0</version>
       <scope>compile</scope>
     </dependency>
   </dependencies>
 </dependencyManagement>
</project>

Project Z:

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>maven</groupId>
  <artifactId>Z</artifactId>
  <packaging>pom</packaging>
  <name>Z</name>
  <version>1.0</version>
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>maven</groupId>
        <artifactId>X</artifactId>
        <version>1.0</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
      <dependency>
        <groupId>maven</groupId>
        <artifactId>Y</artifactId>
        <version>1.0</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
</project>

Z引用了X和Y的依赖。虽X和Y都包含a,但最终会使用1.1版本,因为1.1版本的a在X中被先声明(先被引用),且Z中也并没有a的声明。
这个引用过程是递归的。比如,如果X引用另外一个pom Q,当Z处理X引用的时候,X已经包含了所有Q的管理依赖;
引用功能相当有效,可以定义一个“library”(一个POM),包含多项目创建的artifact。其他项目就可以很方便的引用这个library中的一个或多个artifact。
但是有时为了使项目中使用的artifact的版本和在library中发布的版本保持一致变得有些困难。以下模式描述一个被其他项目使用的“bill of materials”(BOM)是如何被创建的?
跟项目是BOM pom,它定义了所有在library中创建的artifact的版本。其他项目通过在dependencyManagement中引用这个pom来引用这个library。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.test</groupId>
  <artifactId>bom</artifactId>
  <version>1.0.0</version>
  <packaging>pom</packaging>
  <properties>
    <project1Version>1.0.0</project1Version>
    <project2Version>1.0.0</project2Version>
  </properties>
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>com.test</groupId>
        <artifactId>project1</artifactId>
        <version>${project1Version}</version>
      </dependency>
      <dependency>
        <groupId>com.test</groupId>
        <artifactId>project2</artifactId>
        <version>${project1Version}</version>
      </dependency>
    </dependencies>
  </dependencyManagement>
  <modules>
    <module>parent</module>
  </modules>
</project>

子项目声明parent为BOM pom。它是一个一般的多项目pom。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.test</groupId>
    <version>1.0.0</version>
    <artifactId>bom</artifactId>
  </parent>

  <groupId>com.test</groupId>
  <artifactId>parent</artifactId>
  <version>1.0.0</version>
  <packaging>pom</packaging>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.12</version>
      </dependency>
      <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.1.1</version>
      </dependency>
    </dependencies>
  </dependencyManagement>
  <modules>
    <module>project1</module>
    <module>project2</module>
  </modules>
</project>

接下来,才是实际项目的pom:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.test</groupId>
    <version>1.0.0</version>
    <artifactId>parent</artifactId>
  </parent>
  <groupId>com.test</groupId>
  <artifactId>project1</artifactId>
  <version>${project1Version}</version>
  <packaging>jar</packaging>

  <dependencies>
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
    </dependency>
  </dependencies>
</project>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.test</groupId>
    <version>1.0.0</version>
    <artifactId>parent</artifactId>
  </parent>
  <groupId>com.test</groupId>
  <artifactId>project2</artifactId>
  <version>${project2Version}</version>
  <packaging>jar</packaging>

  <dependencies>
    <dependency>
      <groupId>commons-logging</groupId>
      <artifactId>commons-logging</artifactId>
    </dependency>
  </dependencies>
</project>

以下项目描述了其他项目如何不用声明项目版本(版本信息统一在BOM中定义)而引用到此library。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.test</groupId>
  <artifactId>use</artifactId>
  <version>1.0.0</version>
  <packaging>jar</packaging>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>com.test</groupId>
        <artifactId>bom</artifactId>
        <version>1.0.0</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>com.test</groupId>
      <artifactId>project1</artifactId>
    </dependency>
    <dependency>
      <groupId>com.test</groupId>
      <artifactId>project2</artifactId>
    </dependency>
  </dependencies>
</project>

最后,创建项目引用依赖的时候需要注意:
1)不要引用一个定义在当前pom的一个子模块中的pom,如果那样做会出现找不到pom的错误;
2)不要定义一个pom A引用另外一个pom B,且A作为B的父类(或祖父类等),因为没有办法解决循环引用而会抛出一个错误。
3)当所依赖的artifacts所属的pom有传递依赖的时候,项目需要声明这些artifacts的版本以使之成为可控的依赖。不这样做会导致build失败,因为这些artifact可能没有声明版本信息。(在任何情况下这都可以被认为是最佳实践,因为从一次build到下次build它能始终保持一致的版本信息)

9.系统依赖(System Dependencies)

声明system范围的依赖是任何时候都可以引用到,不需要从repository中查找。它经常用来告知maven这个依赖是有JDK或VM提供的。所以,系统依赖对解决由JDK提供的artifact,它们可以提前下载好。如JDBC、JAAS(Java Authentication and Authorization Service)等。
一个简单的实例如:

<project>
  ...
  <dependencies>
    <dependency>
      <groupId>javax.sql</groupId>
      <artifactId>jdbc-stdext</artifactId>
      <version>2.0</version>
      <scope>system</scope>
      <systemPath>${java.home}/lib/rt.jar</systemPath>
    </dependency>
  </dependencies>
  ...
</project>

如果你的artifact由JDK的tools.jar提供可以像如下方式定义:

<project>
  ...
  <dependencies>
    <dependency>
      <groupId>sun.jdk</groupId>
      <artifactId>tools</artifactId>
      <version>1.5.0</version>
      <scope>system</scope>
      <systemPath>${java.home}/../lib/tools.jar</systemPath>
    </dependency>
  </dependencies>
  ...
</project>

参考:Introduction to the Dependency Mechanism

10. FAQs

FAQ1: What’s maven artifact?
An artifact is a file, usually a JAR, that gets deployed to a Maven repository.
A Maven build produces one or more artifacts, such as a compiled JAR and a “sources” JAR.
Each artifact has a group ID (usually a reversed domain name, like com.example.foo), an artifact ID (just a name), and a version string. The three together uniquely identify the artifact.
A project’s dependencies are specified as artifacts.

参考:source

FAQ2: What exactly is a Maven Snapshot and why do we need it?
A snapshot version in Maven is one that has not been released.
The idea is that before a 1.0 release (or any other release) is done, there exists a 1.0-SNAPSHOT. That version is what might become 1.0. It’s basically “1.0 under development”. This might be close to a real 1.0 release, or pretty far (right after the 0.9 release, for example).
The difference between a “real” version an a snapshot version is that snapshots might get updates. That means that downloading 1.0-SNAPSHOT today might give a different file than downloading it yesterday.
Usually, snapshot dependencies should only exist during development and no released version (i.e. no non-snapshot) should have a dependency on a snapshot version.
he three others answers provide you a good vision of what a -SNAPSHOT version is. I just wanted to add some information regarding the behavior of Maven when it finds a SNAPSHOT dependency.
When you build an application, Maven will search for dependencies in the local repository. If a stable version is not found there, it will search the remote repositories (defined in settings.xml or pom.xml) to retrieve this dependency. Then, it will copy it into the local repository, to make it available for the next builds.
For example, a foo-1.0.jar library is considered as a stable version, and if Maven finds it in the local repository, it will use this one for the current build.
Now, if you need a foo-1.0-SNAPSHOT.jar library, Maven will know that this version is not stable and is subject to changes. That’s why Maven will try to find a newer version in the remote repositories, even if a version of this library is found on the local repository. However, this check is made only once per day. That means that if you have a foo-1.0-20110506.110000-1.jar (i.e. this library has been generated on 2011/05/06 at 11:00:00) in your local repository, and if you run the Maven build again the same day, Maven will not check the repositories for a newer version.
Maven provides you a way to can change this update policy in your repository definition:

<repository>
    <id>foo-repository</id>
    <url>...</url>
    <snapshots>
        <enabled>true</enabled>
        <updatePolicy>XXX</updatePolicy>
    </snapshots>
</repository>

where XXX can be:
always: Maven will check for a newer version on every build;
daily, the default value;
interval:XXX: an interval in minutes (XXX)
never: Maven will never try to retrieve another version. It will do that only if it doesn’t exist locally. With the configuration, SNAPSHOT version will be handled as the stable libraries.
(model of the settings.xml can be found here)

参考:source

客户传真接收程式莫名原因会卡住,需重启才会好。传真接收程式很旧,也暂无时间查原因,为快速解决,使用Windows任务计划和shell脚本,每隔一个小时重启一下传真接收程式。

1. 准备shell脚本(以下以WORD进程为例):

@echo off
rem --------------------------------------
rem author:geln_yang
rem date:2013-11-06
rem --------------------------------------

rem --------------------------------------

rem configuration variables
rem --------------------------------------
set log_file_path=C:\schedule_command\restart.log
set command_name=WINWORD.EXE
set command_path="D:\App\Microsoft Office\Office15\WINWORD.EXE"
set kill_start_interval=10

rem --------------------------------------

rem start to kill process
rem --------------------------------------
echo %date% %time%[INFO] start to kill process:%command_name% >> %log_file_path%
taskkill /IM %command_name% /f >> %log_file_path%  2>&1

rem --------------------------------------

rem sleep for a while
rem --------------------------------------
echo %date% %time%[INFO] sleep %kill_start_interval% seconds >> %log_file_path%
timeout %kill_start_interval% >> %log_file_path%

rem --------------------------------------

rem try to start process
rem --------------------------------------
echo %date% %time%[INFO] try to start process:%command_path% >> %log_file_path%
start "%command_name%" %command_path%

说明:
1)此脚本需配置日志文件路径、服务进程名称、启动服务命令路径(注意命令路径有空格时需加引号);
2)启动服务进程时,通过start命令执行,避免cmd指令等待;
3)输出命令结果到日志的时候,添加2>&1为将STDERR的输入也写到日志中;

2.配置系统任务计划:
1)创建任务计划,使用管理员帐号执行,勾选“不管用户是否登录都要运行”,勾选“使用最高权限运行”;
2)触发器,设置每天运行一次,开始时间为00:00,设置重复任务间隔时间为一小时,持续时间为“无限期”;
3)操作,添加运行脚本路径,”起始于”设置为脚本所在目录;
4)设置,勾选“如果过了计划开始时间,立即启动任务”;

3.参考:
1.Microsoft DOS start command, http://www.computerhope.com/starthlp.htm
2.Using command redirection operators,http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/redirection.mspx?mfr=true