组件开发指南

来自Javashop dev docs
跳转到: 导航, 搜索

目录

概述

EOP组件是基于EOP开发平台,为扩展EOP应用而提供的一种机制。
他在整个架构的层次如下图所示:

QQ20141017-2.png

EOP组件可以在后台“设置->组件管理”菜单中被安装、启动或停用、卸载。
EOP应用本身很多核心功能就是基于组件开发,因此Javashop默认安装了很组件,如下图所示:

Component-admin.jpg


组件包结构

组件的包名必须符合一定规则,EOP组件机制才能识别这些组件:
必须以如下包名开头:


com.enation.app.base.component
com.enation.app.saas.compoent
com.enation.app.shop.component
com.enation.app.cms.component


如一个网店邮件组件包应为如下:

 
com.enation.app.shop.component.email

那么他的插件及挂件包,命名如下:

 
com.enation.app.shop.component.email.plugin
com.enation.app.shop.component.email.widget


一个组件包应包含如下文件

  • 组件类
  • component.xml(组件描述文件)
  • 插件或挂件类及相应页面(非必须)
  • 后台管理action及service类(非必须)


一个组件包看起来像如下的样子:

Component-package.jpg

组件开发详细指南

下面我们以后会员详细页的会员备注插件来一步步的来学习组件开发。

需求定义

我们需要建立一个会员组件,可以被安装或卸载,
并且在后台会员详细页中加入一个tab页,名称为“会员备注”。
点击此tab显示会员的备注信息,并可以修改。

第一步,建立组件包

按上述规范,我们建立如下包结构:

com.enation.app.shop.component.membertest
com.enation.app.shop.component.membertest.plugin

第二步建立组件类

我们建立 “网店会员组件类”,如下:

/**
 * 网店会员组件
 * @author kingapex
 *2012-4-1上午9:25:49
 */
@Component
public class MyMemberComponent implements IComponent {

	@Override
	public void install() {
		 System.out.println("hi,my first compoent install");

	}

	@Override
	public void unInstall() {
		 System.out.println("o,my first compoent unInstall");

	}

}


注意组件类必须符合两个规范:

组件类必须实现IComponent接口
此接口的install和uninstall方法在组件被安装和卸载时会被调用,你可以在需要时在此执行sql创建数据库结构,或者作一些你想做的事。

  • 用@Component注解来标记

EOP组件机制使用Spring自动化扫描注解的机制来完成组件的扫描的,应此需要使用@Component注解来标记此组件类。
此时这个组件就有了一个唯一的spring beanid:"shopMemberComponent " 。
这是spring规范中的一部分,你可以通过下面的注解代码来自定义beanid:

@Component("my_bean_id")

这个beanid我们不会被用到,但你要确保他是唯一的,否则spring是不允许的。

第三步,建立component.xml文件

component.xml文件位于和上述组件类同级目录

用于描述组件信息及组件包含的插件挂件:
我们暂时只定义组件本身的信息,插件和挂件信息稍后我们再定义:

<?xml version="1.0" encoding="UTF-8"?>
<component name="网店会员组件"  version="1.0" javashop_version="3.0.0" author="javashop">
 
</component>

上述文件中的信息比较明了,值得解释的是javashop_version属性,这个属性定义了组件依赖的javashop版本,

如果在低于这个标识的版本中运行此组件(如2.1.4),那么此组件将不被安装或启动,并在后台显示出需要的具体版本信息。
ok,我们的第一个组件就开发完成了,现在让我们运行javashop,去看看组件的样子吧:

Component-member.jpg


点击安装,在控制台我们会发现调用了组件的install方法而输出:hi,my first compoent install
点击卸载,则会调用组件的uninstall方法,输出:o,my first compoent unInstall
此时我们的组件已经可以正常运转了。接下来我们为组件开发一个插件。

第四步,开发插件

插件是基于事件机制来运转的,参见EOP插件机制
参见:EOP各应用事件及插件桩集合

我们要开发的会员详细插件涉及到两个事件:

插件必须继承于AutoRegisterPlugin,且再实现上述两个事件,代码如下 :


/**
 * 会员备注插件
 * @author kingapex
 *2012-4-1下午5:12:29
 */
@Component
public class MemberRemarkPlugin extends AutoRegisterPlugin implements IMemberTabShowEvent,IAjaxExecuteEnable{

	@Override
	public String execute() {
		
		return null;
	}

	@Override
	public String getTabName(Member member) {
		
		return null;
	}

	@Override
	public int getOrder() {
		
		return 0;
	}

	@Override
	public boolean canBeExecute(Member member) {
		
		return false;
	}

	@Override
	public String onShowMemberDetailHtml(Member member) {
		
		return null;
	}

}

注意插件类必须符合两个规范:

继承此类才成为一个EOP的插件,系统会自动识别后,将其插入相应的业务插件桩中,将来在业务被调用。


  • 用@Component注解来标记

同样地,EOP插件机制使用Spring自动化扫描注解的机制来完成插件的扫描的,应此需要使用@Component注解来标记此插件类。
此时这个插件就有了一个唯一的spring beanid:"memberRemarkPlugin" 。
当然,你可以通过下面的注解代码来自定义beanid:

@Component("my_bean_id")

请记住这个beanid,我们在下面的步骤中将要用到

  • 实现相关业务的事件,以便被业务类调用

接下来,我们完善插件相应的逻辑。在这个插件中,我们有两个逻辑:

  • 显示tab页及会员备注表单

对应IMemberTabShowEvent事件

  • 保存会员备注

对应IAjaxExecuteEnable事件

实现后的插件代码:



/**
 * 会员备注插件
 * @author kingapex
 *2012-4-1下午5:12:29
 */
@Component
public class MemberRemarkPlugin extends AutoRegisterPlugin implements IMemberTabShowEvent,IAjaxExecuteEnable{

	private IMemberManager memberManager;
	/**
	 * 响应异步请求
	 */
	@Override
	public String execute() {
		HttpServletRequest request = ThreadContextHolder.getHttpRequest();
		String modify_memo = request.getParameter("modify_memo");
		int memberid  = StringUtil.toInt(request.getParameter("memberid"),true);
		Member member = this.memberManager.get(memberid);
		member.setRemark(modify_memo);
		try {
			memberManager.edit(member);
			return JsonMessageUtil.getSuccessJson("会员备注修改成功");
		} catch (Exception e) {
			 this.logger.error("修改会员备注",e);
			return JsonMessageUtil.getErrorJson("会员备注修改成功"); 
		}
	}

	
	
	
	/**
	 * 定义tab的名称
	 */
	@Override
	public String getTabName(Member member) {
		
		return "会员备注";
	}

	
	/**
	 * 定义tab显次序为7
	 */
	@Override
	public int getOrder() {
		
		return 7;
	}

	
	/**
	 * 在这里,我们可以根据会员的情况定义是否执行此插件
	 */
	@Override
	public boolean canBeExecute(Member member) {
		
		return true;
	}

	
	/**
	 * 响应会员详细信息显示事件,先显示出一个容器,然后在点击相应的tab页时加载会员备注。
	 * 这样做的目的是为了避免在显示会员详细信息时一次性多过的查询数据库(通过tab页切换时再加载一次方式)。
	 * 
	 */
	@Override
	public String onShowMemberDetailHtml(Member member) {
		FreeMarkerPaser freeMarkerPaser =FreeMarkerPaser.getInstance();
		freeMarkerPaser.setClz(this.getClass());
		freeMarkerPaser.putData("memberid",member.getMember_id());		 //为页面put变量 
		freeMarkerPaser.setPageName("remark");//解析此类同级目录中的remark.html
		return freeMarkerPaser.proessPageContent();//返回上述页面的内容作为tab页的内容

	}




	public IMemberManager getMemberManager() {
		return memberManager;
	}




	public void setMemberManager(IMemberManager memberManager) {
		this.memberManager = memberManager;
	}

	
	
	
}

这个插件通过FreemarkUtil解析了同级目录remark.thml:

<form id="editRemarkForm">
<div id="Member_Form_Point_" class="division">
<table cellspacing="0" cellpadding="0" border="0" width="100%">
	<tbody>
		<tr>
			<th>会员备注:</th>
			<td>
				<textarea name="modify_memo" style="width: 750px; height: 200px;" >${member.remark!'' }</textarea>
			</td>
		</tr>
	</tbody>
</table>
<input type="hidden" value="${memberid }" name="memberid"></div>

<div class="submitlist" align="center">
<table>
	<tr>
		<td><input name="button" type="button" value=" 确    定   "
			class="submitBtn" id="editRemarkBtn"/></td>
	</tr>
</table>
</div>

</form>
<script>
$(function(){

	$("#editRemarkBtn").click(function(){
		$.Loading.show('正在更新数据,请稍侯...');
		var that =this;
		var options = {
			url : "${ctx}/admin/plugin?beanid=memberRemarkPlugin",
			type : "POST",
			dataType : 'json',
			success : function(result) {	
				$.Loading.hide();
				if(result.result==0){
					alert(result.message);
					 
				}else{
					alert(result.message);
				}
			},
			error : function(e) {
				$.Loading.hide();
				alert("出现错误 ,请重试");
			}
		};
		$('#editRemarkForm').ajaxSubmit(options);
		
	});
});
</script>

上述插件开发完成后 接下来,我们在compoent.xml中声明我们的插件:


<?xml version="1.0" encoding="UTF-8"?>
<component name="网店会员组件"  version="1.0" javashop_version="3.0.0" author="javashop">

	<plugins>
		<plugin name="会员备注插件" id="memberRemarkPlugin">
			<bundle id="memberPluginBundle"></bundle>
		</plugin>
		
	</plugins>

 
</component>

其中两个地方需要解释:

  • plugin的节点的id属性对应我们插件的beanid
  • bundle 节点对应相应业务插件桩

我们的这个插件需要插入到memberPluginBundle插件桩。
参见EOP各应用事件及插件桩集合

至此,我们插件工作也完成了,运行程序,并在后台确认我们组件正常安装并启用了。

在后台菜单:“会员-》会员列表”处访问会员详细页,展现如下:

Component-member-remark.jpg
输入备注文字,点击确定按钮,由我们javascript程序控制访问如下地址:

${ctx}/admin/plugin?beanid=memberRemarkPlugin

此时调用了MemberRemarkPlugin.execute方法,返回json串,提示成功。