Tag Archives: Java

教学贴:如何编写Maven2插件

Maven插件的编写非常容易,所以,简单的几个流水帐吧。

创建插件工程

# mvn archetype:generate

选择12,回答groupId,artifactId之类的问题,工程就OK了。导入到喜欢的IDE吧。

定义插件参数

完成的定义请参考Maven官方教程,这里简要介绍。

Maven2使用了很多注释中的Annotation来定义插件行为,完整文档点这里,常见的如:

Annotation

功能介绍
@goal <goalName>所谓目标了。每个Mojo类包含一个目标,一个Plugin可能若干Mojo类也就有若干目标了

@parameter expression="${aSystemProperty}" default-value="${anExpression}"

这是用于Mojo的属性的,可以通过表达式来获取系统参数,项目参数,以及从命令行输入参数。
@required同样用于Mojo的属性,定义该参数为必须的。
  

下面是简单的代码

package com.yuchengtech.emp;

/*
 * Copyright 2001-2005 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import java.io.File;
import java.net.URL;
import java.util.Collection;
import java.util.Iterator;

import org.apache.commons.digester.Digester;
import org.apache.commons.digester.xmlrules.DigesterLoader;
import org.apache.commons.io.FileUtils;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;

/**
 * 用于编译EMP相关文件,生成部署资源
 *
 * @goal emp-compile
 *
 * @phase process-sources
 */
public class EmpCompileMojo extends AbstractMojo {
	/**
	 * 输出文件路径
	 *
	 * @parameter expression=
	 *            "${project.build.directory}/${project.build.finalName}/WEB-INF/tables"
	 * @required
	 */
	private File outputDirectory;

	/**
	 * EMP设计文件路径
	 *
	 * @parameter expression="${emp.design.dir}"
	 * @required
	 */
	private File empDesignDir;

	public void execute() throws MojoExecutionException {
		getLog().info("Design Files Folder: " + empDesignDir.getAbsolutePath());
		getLog().info(
				"Output Table Files Folder: "
						+ outputDirectory.getAbsolutePath());
		URL rule = this.getClass().getClassLoader().getResource(
				"rule-table.xml");
		Digester digester = DigesterLoader.createDigester(rule);

		Collection files = FileUtils.listFiles(empDesignDir,
				new String[] { "table" }, true);

		for (Iterator it = files.iterator(); it.hasNext();) {
			File table = (File) it.next();
			getLog().info("EMP: covert file - " + table.getName());
			ModelConverter convert = new ModelConverter(table, outputDirectory,
					digester);
			StringBuffer s = new StringBuffer();
			boolean result = convert.convert(s);
			if (!result) {
				throw new MojoExecutionException(s.toString());
			}
		}
	}
}

发布插件

使用简单的mvn install 之后就可以在本地使用这个插件了。或者发布到公共服务器上供更多人使用。

可以在项目中用命令行 mvn groupId:artifactId:goal来执行插件操作,也可以在项目POM中配置。

请继续参看Maven官方教程

Java Scripting in JDK6

对动态语言的爱啊,少年啊,前进~~

无聊的开场,简单的说,就是Java Scripting其实很容易,比你想象的要容易的多,特别是在JDK6的时候。

JavaScript的例子

  ScriptEngineManager mgr = new ScriptEngineManager();
  ScriptEngine jsEngine = mgr.getEngineByName("JavaScript");
  try {
    jsEngine.eval("print('Hello, world!')");
  } catch (ScriptException ex) {
      ex.printStackTrace();
  }

无需过多解释,只要用了JDK6的环境以上代码就可以运行,默认使用Mozilla Rhino (1.6 release 2)脚本引擎,支持JavaScript 1.6

Ruby的例子

Ruby的例子要麻烦一点,因为要手工添加支持。但是其实也非常简单,只要把JRuby的实现和JRuby Scripting Engine加入就行了。

下载:

  • jruby.jar – download jruby-bin-1.0.tar.gz file from JRuby website and extract the files jruby.jar, asm-2.2.3.jar, asm-commons-2.2.3.jar, backport-util-concurrent.jar from directory jruby-1.0/lib/. You don’t need the other files.
  • jruby-engine.jar – download jsr223-engines.tar.gz file from scripting.dev.java.net and extract the file jruby/build/jruby-engine.jar

使用Maven添加相关依赖:

  • jruby – groupId=org.jruby artifactId=jruby version=1.1.2
  • jruby-engine – groupId=javax.scripting artifactId=jruby-engine version=20080611

jruby-engine需要添加附加的repository,例如http://shibboleth.internet2.edu/downloads/maven2

之后的使用和JavaScript的例子一样,当然,语法不一样。

使用下面的代码可以打印支持的脚本信息

ScriptEngineManager mgr = new ScriptEngineManager();
for (ScriptEngineFactory factory : mgr.getEngineFactories()) {
	System.out.println("ScriptEngineFactory Info");
	System.out.printf("\tScript Engine: %s (%s)\n", factory
		.getEngineName(), factory.getEngineVersion());
	System.out.printf("\tLanguage: %s (%s)\n", factory
		.getLanguageName(), factory.getLanguageVersion());
	for (String name : factory.getNames()) {
		System.out.printf("\tEngine Alias: %s\n", name);
	}
}

本地输出示例

ScriptEngineFactory Info
Script Engine: Mozilla Rhino (1.6 release 2)
Language: ECMAScript (1.6)
Engine Alias: js
Engine Alias: rhino
Engine Alias: JavaScript
Engine Alias: javascript
Engine Alias: ECMAScript
Engine Alias: ecmascript
ScriptEngineFactory Info
Script Engine: JRuby Engine (1.1.4)
Language: ruby (1.8.6)
Engine Alias: jruby
Engine Alias: ruby

本文主要参考: Java Scripting and JRuby Examples

JRuby Note: 简单就是美

恩,我是一个Java中毒症患者,而且还是写了些传统程序,被传染了些OO顽疾的患者,对于Ruby这种太轻巧的东西接受起来还是有个过程的。

然而,我仍旧是个年轻人,早已坚定的支持Ruby代表的“小快灵”俱乐部,受够了传统软件工艺的铺张浪费,心存着的一点点幻想仍然让我被种种传说诱惑。

趁着一周唯二的两天不加班,研究了些JRuby 1.1.1——好吧,我就是纯粹的Java中毒症。顺便还关注了下ROX荡气回肠的季后赛第三场——然后浅浅的发现了JRuby的点点好处。

出色的SCM基础支持,小巧便捷的扩展,标准化的实现

SCM基础支持

GEM真的是非常有用的工具。Ruby毕竟晚生了几年,许多新的思路得以应用的更加完善。GEM类似于Maven的Resp,配合Rake就构成了非常好用的构建工具,连版本都被模糊化了,“我只要最新的就可以了”,是这样么?我只研究了两个小时,还只能猜猜。至于之前就听过的Raven,对于不懂Ruby的人来讲,简直比Maven还难用(我是新人,我不懂上个世纪的构建方法)。SCM早晚会成为一种标准化的事情,就像之前的Java Module被接受成为标准,每种语言形成产品都需要重视这一点。

不得不说的是ROR的DB扩展,数据迁移,在我看来,这就是很棒的数据库重构工具。重构在较小的时间段上对于软件的意义,有赶超迭代开发的趋势。而数据库重构,是其中最难最复杂的主题。虽然这不是Ruby天生的特性,但随着ROR的流行,也一定会慢慢深入人心。

模块化的扩展

Java是模块化的么,你真的确定jar和package是模块化的表现么?

动态语言天生就有这种优势,耦合和约束在非常低的水平,模块的互操作也就简单的多。加上良好的SCM,全球化的组件工厂,模块化对于Ruby,简直就是天生的完美排档。

标准化

这是一个不怎么显而易见的优点。正如标题所说,简单就是美。那么,如何简单,怎样简单?用大家都接受的概念。

用BlueCloth,HTML标签前开后闭,不用大大咧咧的程序员操心。

Wiki式的标记方法,写模板就像写文档。

学术上我们说Closure,我Ruby就实现个Closure。理论与实际尽量靠拢。“小快灵”你想要的,我最快实现。说Ajax,无非就是Autocomplete,DnD,一个单词搞定。什么,你要GoogleDoc?

前两天见了徐昊一面,于是现在对于“语言”更特质的东西很有兴趣,而所谓标准,就是直接到大多数人都觉得应该是这个样子,把一些不显而易见的东西挑明了,固定下来。当然,我说的是与钱无关的情况,虽然这种情况不存在。

完工

怨念的说,公司发调查问卷,征求个人发展计划。网上搜了搜IT认证,中国的IT培训环境糟糕的要死。高校没有软件理论,社会没有工业协作,我们的软件行业,还弱小的很呢。

Technorati 标签: ,,

Java:利用XML生成Word文档

Word 2003后提供了一种xml的文档格式。可以利用这一点方便的生成doc文档

Word 2007更完全使用xml与数据压缩包的方式存储,使得用类似的方法处理附件也变为可能。

相关demo下载 doc-creator

概述

实现步骤如下:

  1. 定义Word文档样式,存为xml文档。
  2. 定义数据xml格式,生成样本数据。
  3. 修改word文档样式xml文件,制作xsl模板文件。
  4. 编程实现:数据->xml数据->模板转换->doc文档

创建模板

打开Word文档,另存为:Word 2003 xml格式。

使用xsl编辑器 (如 Stylus Studio)或手工编辑,创建XSL模板 。

   

   

相关XSL问题可以参考 http://www.w3schools.com/xsl/

利用dom4j处理相关xml操作

下面是一些基础实现方法

    /*
     * (non-Javadoc)
     *
     * @see cn.ccb.sarm.bizprocess.assetdeal.exam.approve.bizservice.IWfConferenceBS#writeXML(java.io.OutputStream,
     *      cn.ccb.sarm.bizprocess.assetdeal.exam.approve.common.bo.TaskVO,
     *      java.util.List, cn.ccb.sarm.common.model.bo.WfConferenceBO,
     *      cn.ccb.sarm.common.model.bo.WfConfBpBO)
     */
    public void writeXML(OutputStream output, TaskVO task, List opinionList, WfConferenceBO conf,
            WfConfBpBO confBP) throws IOException, IllegalAccessException,
            InvocationTargetException, NoSuchMethodException {
        Document doc = DocumentHelper.createDocument();
        Element root = doc.addElement("conference");
        Element taskNode = root.addElement("task");
        addBeanProp(task, taskNode);
        Element confNode = root.addElement("conferenceInfo");
        addBeanProp(conf, confNode);
        Element confBpNode = root.addElement("confBPInfo");
        addBeanProp(confBP, confBpNode);
        Element approveNode = root.addElement("approvers");

        addListMapEntry(opinionList, approveNode);

        XMLWriter writer = new XMLWriter(output);
        writer.write(doc);

    }

    /**
     * 转换list对象为多个元素
     *
     * @param list
     *            对象list
     * @param node
     *            父节点
     */
    private void addListMapEntry(List list, Element node) {
        Iterator it = list.iterator();
        while (it.hasNext()) {
            Map map = (Map) it.next();
            Element approveNode = node.addElement("approver");
            addMapEntry(map, approveNode);
        }
    }

    /**
     * 转换bean为xml
     *
     * @param bean
     *            对象bean
     * @param node
     *            父节点
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     * @throws NoSuchMethodException
     */
    private void addBeanProp(Object bean, Element node) throws IllegalAccessException,
            InvocationTargetException, NoSuchMethodException {
        Map propMap = BeanUtils.describe(bean);
        addMapEntry(propMap, node);
    }

    /**
     * 转换map对象为xml
     *
     * @param map
     *            数据对象
     * @param node
     *            父节点
     */
    private void addMapEntry(Map map, Element node) {
        Set entrySet = map.entrySet();
        Iterator it = entrySet.iterator();
        while (it.hasNext()) {
            Map.Entry e = (Entry) it.next();
            node.addElement(e.getKey().toString()).addText(
                    (e.getValue() == null ? "" : e.getValue().toString()));
        }
    }

    /*
     * (non-Javadoc)
     *
     * @see cn.ccb.sarm.bizprocess.assetdeal.exam.approve.bizservice.IWfConferenceBS#transformDocument(java.io.OutputStream,
     *      java.io.FileInputStream, java.io.FileInputStream)
     */
    public void transformDocument(OutputStream out, InputStream data, InputStream template)
            throws TransformerException {
        TransformerFactory factory = TransformerFactory.newInstance();
        Transformer transform = factory.newTransformer(new StreamSource(template));

        Result result = new StreamResult(out);
        transform.transform(new StreamSource(data), result);
    }

测试代码

    public void testWriteXML() throws Exception {
        IWfConferenceBS conferenceBS = new WfConferenceBS();
        TaskVO task = new TaskVO();
        task.setBizTypeName("测试业务类型");
        List opinionList = new ArrayList();
        Map m = new HashMap();
        m.put("userName", "testUser");
        m.put("userConfRole", "testUserRole");
        m.put("approverOpinion", "approverOpinion");
        m.put("lastChangeTime", "time");
        opinionList.add(m);
        WfConferenceBO conf = new WfConferenceBO();
        conf.setConfPlace("place");
        WfConfBpBO confBP = new WfConfBpBO();
        confBP.setConfResult("testResult");
        confBP.setConfOpinion("confOpinion");
        File tempOutputFile = File.createTempFile("specialApproveTemp", ".xml");
        OutputStream output = new FileOutputStream(tempOutputFile);
        conferenceBS.writeXML(output, task, opinionList, conf, confBP);
        output.flush();
        output.close();

        OutputStream out = new FileOutputStream(File.createTempFile("specialApproveTemp", ".doc"));
        File template = ResourceUtils
                .getFile("classpath:cn/ccb/clpm/wf/common/specialApproveTemplate.xsl");
        conferenceBS.transformDocument(out, new FileInputStream(tempOutputFile),
                new FileInputStream(template));
        output.flush();
        output.close();

    }