由于新工作是在AWS PaaS平台上进行开发,为不耽误工作,先整理一下AWS MVS的使用规范,快速上手。对AWS PaaS平台的相关介绍留到以后再来补充。本文几乎是对官方学习文档的整理,有遗漏的后补。
1.简介
AWS MVC(Model-View-Controller),轻量级、高性能,是开发AWS App的标准框架,同时AWS PaaS自身也是基于它开发。与传统开源的Spring MVC、Strusts2相比:
- 清晰、干净、
请求驱动
(请求-响应)的轻量级Web编程框架 - 学习难度远小于Spring MVC和Strusts2
No Servlet
、No JSP
,Just J2SE
,更容易的开发调试和问题追踪- 与AWS平台架构兼容的会话安全、DAO、I18N国际化、日志、审计和SLA告警机制
- 没有值栈、OGNL表达式、标签库等增加代码复杂度和性能下降的架构缺陷
- 优于Strusts2的注解编程和方法拦截,能直接根据注解绑定Request参数,更简洁
- 对处理结果是HTML、JSON、XML数据结构和错误码的统一处理,避免业务架构缺陷
- 提供了一套基于JQuery和JQuery Mobile的AWS UI库,针对企业级需求进行了增强封装
- 内核采用了
NIO
通信和多线程池化管理,能够充分对计算资源的扩容做出适应,实现纵向扩展(Scale Up) - 为多个集群节点提供自我发现和自我纠正能力,简化部署和运维,轻松实现弹性的横向扩展(Scale Out)
特点:基于请求驱动,使用了前端控制器模式设计,再根据请求映射规则分发给相应的后端逻辑控制器(动作/处理器)进行处理
上图,前端控制器
(AWS Web Server / Front Controller)和后端处理控制
(AWS App Server / Controller)是AWS MVC的核心通信框架,黄色区域(视图组装、模型、模版)写业务逻辑,元素描述:
AWS Web Server | 安装有AWS Portal的标准Servlet容器,例如:Tomcat、WebLogic |
AWS App Server | 安装有AWS Server的应用服务器,所有的业务逻辑在这里处理 |
Servlet 前端控制器 | 接收所有来自用户的请求,封装后转发给AWS App服务器 |
后端处理控制器 | 通过注解拦截到方法,绑定逻辑处理程序 |
View视图组装 | 实现业务逻辑,返回处理的结果 |
Model模型 | 资源处理对象,如处理逻辑、对象、国际化、Dao处理、缓存 |
Template模版 | 基于静态模版的渲染,处理成动态页面结果 |
AWS MVC编程框架的主要组成部分:
- 提交请求(submit)
- 前端参数解析
- 后端控制器(controller)
- 业务对象封装(ModelBean)
- DAO封装
- Cache缓存
- View视图(返回结果)
- 页面模版渲染(Template)
其它(略):提高生产环境下的SLA服务可用性;应用的分发、安装和卸载;对计算资源的扩容做出适应,实现纵向扩展(Scale Up)、获得线性的横向扩展(Scale Out)
2. 框架详解
2.1 提交请求
AWS MVC基于Command命令请求驱动,约定5类常见url
请求地址,都可以通过GET
/POST
提交
url | 类型 | 说明 |
---|---|---|
./w | text/html | (web)-请求结果一定是普通Web页面数据时 |
./jd | application/json | (json data)-请求结果一定是ResponseObject Json |
./xd | application/xml | (xml data)-请求结果一定是ResponseObject XML |
./df | application/octet-stream(成功) application/json(失败) |
(download file)-文件下载流,如下载失败或权限校验不通过,返回Json处理结果 |
./uf | application/json | (upload file)-文件上传流,返回Json处理结果 |
测试:启动完本地AWS服务,浏览器输入请求url:http://localhost:8088/portal/r/w?cmd=API_BENCHMARK_TEST&p=Hello AWS
说明
1.8088
是安装AWS开发服务的默认Web端口号
2./portal
/是默认的Web App根名
3.返回结果:“Hello AWS”,如下:
·Web可靠性编程习惯
任何请求在极端环境或服务故障时都会发生错误。如果在浏览器背后(如一个Ajax请求)发送的HTTP返回一个特定数据结构或操作状态值,那么AWS MVC会要求你在Java代码使用ResponseObject
对象进行封装,并在前端对result
进行检查,只有当result
为ok
时从data
中读取结果,否则应该检查errorCode
及msg
项,并处理该异常(如提醒操作者或其他操作)。模拟一个停机故障:关闭AWS服务,但保持Web服务的正常运行,在浏览器中输入以下URL请求:http://localhost:8088/portal/r/jd?cmd=API_BENCHMARK_TEST&p=Hello AWS
说明
1.使用./jd请求一个json数据结果,模拟加载ajax数据
2.获得了非预期的“Hello AWS”
{
result: "error",
msg: "AWS Instance Server连接失败!(590)"
}
result值类型
ok
(操作成功)error
(服务端发生错误,错误描述在msg
项)warning
(服务端发生警告,警告描述在msg
项)
3.查看结果:↓
默认编码字符集:utf-8
常规请求必须参数
sid
(用户会话)cmd
(请求指令。命名规范:前缀为该应用的Id,后面是动作名,中间以下划线分割,区分大小写)
Web层配置文件
每个AWS App的Web资源被独立的定义在webapp根目录apps/%AppId%
下。如果该应用需要cmd处理,至少应定义一个接参配置文件,并建议命名为action.xml
(如果使用AWS自带的Developer开发工具,该配置文件可忽略,AWS Developer会自动根据Controller类同步构建该配置)。配置文件存为 UTF-8 NO BOM,格式为一个或多个符合Schema规范、以action(不区分大小写)开头、后缀为xml的文件。action.xml位置
及内容示例:
<?xml version="1.0" encoding="utf-8"?>
<aws-actions>
<cmd-bean name="%AppId%_xxx1">
<param name="p1" />
</cmd-bean>
<cmd-bean name="%AppId%_xxx2">
<param name="p1" />
</cmd-bean>
<cmd-bean name="%AppId%_xxx3">
<param name="p1" type="body"/>
</cmd-bean>
</aws-actions>
实际项目中配置
cmd-bean的type属性:
type
不配置时,该参数的值来自请求中查询参数或者application/x-www-form-urlencoded类型内容中请求参数type=body
时,该参数的值来自请求内容application/xml、application/json等类型的值,Controller将接收到请求内容的字符串值type=cookie
时,该参数的值来自请求内容的cookie,Controller将接收到对应name
的cookie
值type=header
时,该参数的值来自请求内容的header,Controller将接收到对应name
的header
值
2.1.1 Form Submit提交
普通表单提交处理方式,包括HTML的form提交和js提交。如下模拟一个数值运算场景,由浏览器提交两个数值和运算类型,经过前端控制器传参和后端控制器的接参,最终抵达逻辑区
a) HTML提交:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>数据计算</title>
<!-- JQuery -->
<script type="text/javascript" src="../commons/js/jquery/scripts/jquery.js"></script>
<!-- AWS UI -->
<link rel="stylesheet" type="text/css" href="../commons/css/awsui.css">
<script type="text/javascript" src="../commons/js/awsui.js"></script>
</head>
<body>
<form id="editForm" method="post" action="./jd?sid=<#sid>&cmd=%AppId%_calculation">
<table class="awsui-ux">
<tr>
<td class="awsui-ux-title">计算</td>
<td class="required">
<input id="number1" name="number1" class="awsui-textbox" />
<select id="sign" name="sign" class="awsui-select">
<option value="+">+</option>
<option value="-">-</option>
<option value="*">*</option>
<option value="/">/</option>
</select>
<input id="number2" name="number2" class="awsui-textbox" />
<span> = </span>
<input id="results" name="results" class="awsui-textbox" />
</td>
</tr>
<tr>
<td class="awsui-ux-title" colspan="2" style="text-align: center; ">
<span id="submitBtn" class="button blue">提交</span>
</td>
</tr>
</table>
</form>
</body>
</html>
注:上述源码中,<#sid>
在实际运行中由实际的用户会话Id替代
b) JavaScript提交:
$(\'#submitBtn\').click(function(e) {
// 提交表单
$(\'#editForm\').submit();
});
c) 前端传参配置(Web层action.xml配置文件)
<?xml version="1.0" encoding="utf-8"?>
<aws-actions>
<cmd-bean name="%AppId%_calculation">
<param name="number1" />
<param name="number2" />
<param name="sign" />
</cmd-bean>
</aws-actions>
- 声明
%AppId%
_calculation命令,%AppId%
是你实际的应用Id- 该命令接收
number1
,number2
,sign
三个参数
d) 后端接参处理
方式1(推荐)
@Mapping("%AppId%_calculation")
public String calculation(UserContext me, int number1, int number2, @Param(defaultValue = "+")String sign) {
TestWeb web = new TestWeb(me);
return web.calculation(number1, number2, sign);
}
- 显示定义与变量名匹配的方法参数
UserContext
是AWS MVC内置对象,获得当前操作者上下文信息
方式2
@Mapping("%AppId%_calculation")
public String calculation(UserContext me, RequestParams params) {
// 参数接收
int number1 = params.getInt("number1"); // 获取整数类型
int number2 = params.getInt("number2"); // 获取整数类型
String sign = params.get("sign", "+"); // 获取字符串类型,第二个参数为默认值,以下方式相同
// Boolean bool = params.getBoolean(\'paramsName\'); // 获取Boolean类型
// Double number = params.getDouble(\'paramsName\'); // 获取浮点型参数
TestWeb web = new TestWeb(me);
return web.calculation(number1, number2, sign);
}
- 不定义方法参数,动态从
RequestParams
对象中读取变量- 这种方式可以让你的代码更灵活,但不利于重构
e) View层逻辑处理
public class TestWeb extends ActionWeb {
public TestWeb() {
}
public TestWeb(UserContext ctx) {
super(ctx);
}
public String calculation(int number1, int number2, String sign) {
ResponseObject ro = ResponseObject.newOkResponse();
// 处理逻辑
// ro.put("newNum",newNum);
return ro.toString();
}
}
2.1.2 Ajax请求
1)AWS在JQuery ajax基础上对常用异步请求封装,提供4类请求(request、load、post、get),并对底层进行了统一的处理,如异常拦截。方法说明:
1.awsui.ajax.request
a) 通过 HTTP 请求加载远程数据,参考jQuery.ajax()。
b) 参数:url,[settings]。分别是String,Object类型
url:一个用来包含发送请求的URL字符串。
settings:AJAX 请求设置。所有选项都是可选的。
2.awsui.ajax.load
a) 载入远程 HTML 文件代码并插入至 DOM 中。默认使用 GET 方式 - 传递附加参数时自动转换为 POST 方式
b) 参数:url,[data,[callback]]。类型:String,Map/String,Callback
url:待装入 HTML 网页网址。
data:发送至服务器的
key/value 数据。
callback:载入成功时回调函数
3.awsui.ajax.post
a) 简单POST 请求,成功可调用回调函数
b) 参数:url,[data],[callback],[type]。类型:String,Map,Function,String
url:发送请求地址。
data:待发送 Key/value
参数。
callback:发送成功时回调函数。
type:返回内容格式,xml,
html, script, json, text, _default
4.awsui.ajax.get
a) 简单GET 请求。请求成功时可调用回调函数
b) url,[data],[callback],[type]。类型:String,Map,Function,String
url:发送请求地址。
data:待发送 Key/value
参数。
callback:发送成功时回调函数。
type:返回内容格式,xml,
html, script, json, text, _default。
5,awsui.ajax.ok
a) 验证是否为返回状态是否为成功
b) data:ajax请求后的返回对象
6.awsui.ajax.responseObject
a)验证是否为ResponseObject对象
b)data:字符串或对象。
7.awsui.ajax.alert
a)弹出请求提示消息
b)data,
model, callback 。类型:Object,
boolean,Function
data: 异步请求返回对象。
model: 消息提示框的展示模式,是否为模态。
callback:弹出消息提示后回调函数
示例代码
awsui.ajax.request 示例
awsui.ajax.request({
type: "POST",
url: "./jd?sid="+sid+"&cmd=%AppId%_calculation",
data: "number1=15&number2=1032&sign=+",
ok : function(r) {
//请求处理成功
},
err : function(r){
//请求处理错误
}
});
awsui.ajax.load 示例
awsui.ajax.load("./jd?sid="+sid+"&cmd=%AppId%_calculation", { number1: 15, number2: 1032, sign: \'+\' }, function(data){
awsui.ajax.alert(data, true, function(){ alert(\'callback\'); });
});
awsui.ajax.post 示例
awsui.ajax.post("./jd?sid="+sid+"&cmd=%AppId%_calculation", { number1: 15, number2: 1032, sign: \'+\' }, function(data) {
awsui.ajax.alert(data, true, function(){ alert(\'callback\'); });
}, \'json\');
awsui.ajax.get 示例
awsui.ajax.get("./jd?sid="+sid+"&cmd=%AppId%_calculation", { number1: 15, number2: 1032, sign: \'+\' }, function(data) {
if(awsui.ajax.responseObject(data))
awsui.ajax.alert(data, true, function(){ alert(\'callback\'); });
}, \'json\');
awsui.ajax.ok 示例
if(awsui.ajax.ok(data))
alert(data[\'msg\']);
awsui.ajax.responseObject 示例
if(awsui.ajax.responseObject(data))
awsui.ajax.alert(data, true, function(){ alert(\'callback\'); });
awsui.ajax.alert 示例
awsui.ajax.alert(data, true, function(){ alert(\'callback\'); });
2)后端接参
@Mapping("%AppId%_calulation")
public String calculation(UserContext me, int number1, int number2, String sign) {
TestWeb web = new TestWeb(me);
return web.calculation(number1, number2, sign);
}
3)View层逻辑处理
public class TestWeb extends ActionWeb {
public TestWeb() {
}
public TestWeb(UserContext ctx) {
super(ctx);
}
public String calculation(int number1, int number2, String sign) {
ResponseObject ro = ResponseObject.newOkResponse();
// 处理逻辑
// ro.put("newNum",newNum);
return ro.toString();
}
}
2.1.3 上传文件
AWS容器对各资源提供沙箱管理,对文件读写提供了一套完善的DC
(Doc Center)机制,文件必须通过DC处理器进行处理。AWS对文件上传封装了一个公用的组件,能够满足常用浏览器(IE8+, Firefox,Google Chrome,Safari,平板UC等)的文件上传功能。
a)服务端插件注册和声明
注册DCPluginProfile要声明repositoryName
(存放文件的根目录名)和文件处理器(继承com.actionsoft.bpms.server.fs.AbstFileProcessor)。
- 有关
DC
开发详细内容,参见《AWS 插件扩展开发参考指南》- 有关DC API操作(如读、写文件),参见aws-api-doc提供的
DCAPI
b)客户端调用
upfile
是AWS UI封装的通用文件上传组件,采用双核技术(IE8/IE9提供Flash模式,对支持HTML5的浏览器采用无插件模式)实现批量文件上传、文件类型过滤、文件大小控制和上传进度控制,对各类浏览器提供了较好的体验支持。
i)上传组件的资源引用
<link rel="stylesheet" type="text/css" href="../commons/css/awsui.css"/>
<script type="text/javascript" src="../commons/js/jquery/scripts/jquery.js"></script>
<script type="text/javascript" src="../commons/js/awsui.js"></script>
ii)用JavaScript打开上传对话框
<script type="text/javascript">
$(function(){
//myUpfile对象绑定upfile组件
$("#myUpfile").upfile({
sid: "<#sid>", // 会话ID
appId: "com.actionsoft.apps.poc.plugin", // 应用ID
groupValue: "dir1", // DC大类,建议变量规则
fileValue: "dir2", // DC小类,建议变量规则
numLimit: "2", //最多一次允许上传几个,0(无限制)
filesToFilter : [["Images (*.jpg; *.jpeg; *.gif; *.png; *.bmp)","*.jpg; *.jpeg; *.gif; *.png; *.bmp"]],
repositoryName: "myfile", // 该应用申请的DC名
done: function(e, data){
//事件回调函数
//上传完成后,开始调用导入代码
if (awsui.ajax.ok(data.result.data)) {//判断请求是否执行成功
//可以调用公共方法处理提示信息
awsui.ajax.alert(data.result.data);
//或者自行处理提示信息
//$.simpleAlert(\'文件上传成功!\');
// downloadURL
var url = data.result.data.data.attrs.url;
//如果定义了其他返回的属性,也需要使用data.result.data.data.attrs调用
} else {
// 上传失败,提示出错误信息
awsui.ajax.alert(data.result.data);
}
}
});
});
</script>
iii)上传按钮的定义
<span id="myUpfile" class="button green" onclick="return false;">上传</span>
上述客户端调用示例,也可从
AWS企业应用商店
安装扩展插件概念验证
应用,所有源码在src目录下
c)参数说明
- 属性
Name | Type | Description | Default |
---|---|---|---|
sid(*-必须) | String | 会话ID | |
appId(*-必须) | String | 应用ID | |
repositoryName(*-必须) | String | DC插件定义 | |
groupValue(*-必须) | String | 文件大类 | |
fileValue(*-必须) | String | 文件小类 | |
filesToFilter | String | var filter = [["Images (.jpg; .jpeg; .gif; .png; .bmp)",".jpg; .jpeg; .gif; .png; .bmp"]]; | 不过滤,可上传所有文件 |
sizeLimit | number | 文件大小限制 | 25*1024*1024(25M) |
numLimit | int | 上传个数限制 | 0(无限制) |
- 事件
Name | Param | Description |
---|---|---|
add | e 事件;data(返回的数据) | 文件被添加到上传列表时触发,当返回false时,可阻止上传。 例如: //data.files 为上传文件的数组 add:function(e, data){ //data.files 为上传文件的数组 $.each(data.files, function(index, file) { // file.name 文件名称 file.size 文件大小 file.type 文件类型 }) if(size==0){ //空文件不允许上传 return false; } } |
progress | e 事件;data(返回的数据) | 文件上传中触发 |
done | e 事件;data(返回的数据) | 单个文件上传完毕后触发 |
error | e 事件;data(返回的数据) | 单个文件上传失败后触发。 可能是web服务器也可能是app服务器造成的失败 |
complete | 文件成功上传结束后触发 |
2.1.4 下载文件
下载DC
仓库内文件的url必须由DCContext
的getDownloadURL()
获取。
-
以下是获取文件下载链接的Java示例
// 构造下载附件的url链接 UserContext me = getContext(); String appId = "xxxxxx"; //该App Id名 String repositoryName = "orderFile"; //该App的DC仓库根目录 String groupValue = yearMonth; //一级目录为年月,201402 String fileValue = orderId; //订单Id String fileName = "order.jpg"; //文件名 DCContext context = new DCContext(me, SDK.getDCAPI().getDCProfile(appId, repositoryName), appId, groupValue, fileValue, fileName); result.put("url", context.getDownloadURL());
-
JavaScript示例
window.open(url); // or window.location.href = url;
2.2 后端处理控制器
就这么简单,提交的请求已经被AWS MVC传输至AWS应用层。
AWS MVC的后端控制器以@Controller
注解到普通的Java类,并为该方法增加@Mapping("%Command%")
注解即可。控制器会负责将前端cmd参数名与该Java方法的参数名进行匹配和赋值,完成拦截、绑定和执行过程。
下面是一个Controller示例
@Controller
public class ABCController {
// Test1
@Mapping("%AppId%_xxx1")
public String apiTestHome(UserContext me, String p1) {
return "Hi,p1="+p1;
}
//Test2
@Mapping("%AppId%_xxx2")
public String apiInfo(UserContext me, String p2) {
ABCWeb abc= new ABCWeb(me);
return abc.getMainPage(p2);
}
}
注解
控制器只负责拦截、绑定和执行cmd方法,对于该方法的具体实现应交给View层处理,不建议直接在Controller中完成逻辑处理。
注解 | 说明 |
---|---|
@Controller | 类注解。声明该类是一个后端处理控制器 |
@Mapping | 方法注解。声明该方法将响应一个前端Web请求,参数值是该cmd值 |
默认每个请求必须含有sid的会话信息,如开发者要求在无session场景下执行服务端请求,可参考如下语法
@Mapping(value = "%AppId%_xxx3",
session = false,
noSessionEvaluate = "无安全隐患",
noSessionReason = "用于MVC框架稳定性测试")
- value,cmd的名称
- session,是否拦截sessionId进行合法性校验
- noSessionEvaluate,对安全隐患做出评估说明
- noSessionReason,设计该cmd的原因或功效
被标记为无session验证的请求是非常不安全的,原因是AWS无法识别请求者身份。开发者应审慎评估该请求背后执行的逻辑规则,不会被用于恶意处理
参数映射
以下参数可以出现在方法参数中
参数 | 说明 |
---|---|
UserContext对象类型 | 【可选】获取AWS用户会话对象 |
RequestParams对象类型 | 【可选】获取请求参数,Key为变量名,Value为值 |
clientIp变量名 | 【可选】String类型。客户端ip地址 |
responseType变量名 | 【可选】String类型。请求结果类型(W/JD/XD...)见Message常量 |
%变量名% | 【可选】cmd的参数名,支持String、Integer、Boolean、Long、Double类型。变量的命名来自具体请求中提供的参数 |
package包结构命名建议
- /model/ 存放modelBean类
- /dao/ 存放DAO类
- /cache/ 存放cache类
- /web/ 存放view类
- /util/ 存放util或service逻辑处理类
注意事项
第一次创建Controller类并进行调试时,需要编译jar文件至该app的lib目录下,否则可能会提示找不到cmd异常。这是一个设计缺陷,我们计划在时间充分的时候修复
下图为实例:
2.3 View视图
不建议直接在处理控制器中完成业务处理过程。
在AWS MVC框架中,View层负责实现具体的业务逻辑,组织处理结果。View提供客户端用户会话、身份及设备等信息,通过继承ActionWeb
,完成View的开发。
开发示例
public class ABCWeb extends ActionWeb {
public ABCWeb (UserContext uc) {
super(uc);
}
public String getMainPage(String p2) {
return “Hi,p2=”+p2;
}
}
异常处理
当操作发生错误时,框架将抛出uncheck
异常(如AWSDataAccessException),如果你的逻辑没有方案或需求去处理这个异常可以继续向外抛出。
当操作发生参数非法、执行非法等常见View层处理逻辑场景时,建议抛出如下异常(详细请参见异常处理章节)
- AWSIllegalArgumentException 非法参数异常造成错误的访问请求,对应400错误
- AWSObjectNotFindException 资源未找到异常,对应404错误
- AWSForbiddenException 访问被拒绝异常,对应403错误
框架范围之外的util或service层
如果业务处理逻辑相对复杂,建议将逻辑操作封装成util类或service类
识别访问者设备类型
通常你在为PC端浏览器的界面交互编程。如果需要你的程序能够更好的服务于其他移动设备,可以调用UserContext.getDeviceType()
方法获取到当前用户的设备类型。
- LoginConst.DEVICE_PC PC桌面电脑
- LoginConst.DEVICE_TABLET 平板电脑
- LoginConst.DEVICE_MOBILE 智能手机
与View相关的常见开发
- Server端开发
- 模版渲染(HTML静态文件+标签)
- ModelBean封装
- DAO封装
- Cache封装
- Web端开发
- JavaScript
- CSS
- 熟悉portal/commons下的各种组件资源,如AWS UI、JQuery Mobile
2.3.1 HTML Document
AWS MVC提供了页面模版处理框架,通过定义模版变量和程序对变量的处理生成最终页面内容。
提交请求的响应结果通常是一个完整的HTML Document。在一些前端动态拼装场景,局部DOM结构也可以被独立的定义成模版文件。但有时局部DOM无需使用模版,直接由程序动态组装。
模版被存放在该应用安装目录的template/page
下,通常以html或htm后缀结尾(命名区分大小写)。除内容符合标准HTML、CSS、JavaScript规范外,模版标签变量定义的规则是,将需要程序生成的部分以<#变量名>
替换,最终由HtmlPageTemplate.merge()
混合成用户浏览器中的html内容。
如果该模版中出现的文字需要进行多语言处理,可以<I18N#变量名
>定义,其中变量名是为该应用抽取的多语言配置项的Item的Key。
在View层程序中完成模版处理的示例
public class ABCWeb extends ActionWeb {
public ABCWeb (UserContext uc) {
super(uc);
}
public String getMainPage(String p2) {
Map<String, Object> macroLibraries = new HashMap<String, Object>();
macroLibraries.put("page_title", "hello");
macroLibraries.put("p2", p2);
macroLibraries.put("sid", getContext().getSessionId());
return HtmlPageTemplate.merge("%AppId%", "模版文件名", macroLibraries);
}
}
HTML模板示例
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title><#page_title></title>
<!-- 在JS中使用变量,如果需要 -->
<script>
var sid = \'<#sid>\';
</script>
</head>
<body>
<form action="./w" method=post name=frmMain >
<!-- 在HTML中使用变量,如果需要 -->
p2的值是<b><#p2></b>
</form>
</body>
</html>
模版文件默认编码字符集
utf-8
HTML模版资源引用范围
- AWS平台Web目录commons/下的js、css、图片等公共资源
- AWS平台Web目录apps/%appId%/下自定义的资源(appId为本应用的id)
- 建议使用相对路径,如../apps/xxx、../commons/xxx
2.3.2 非HTML结果
一些来自前端Ajax操作或服务请求通常需要响应一个结构化数据:
- 一个操作结果是否成功
- 一个被封装的数据结构
类型支持:
- JSON
- XML
ResponseObject
com.actionsoft.bpms.commons.mvc.view.ResponseObject
ResponseObject
对象是AWS为开发者提供的一个通用数据对象封装,用于封装一个结构化处理结果。ResponseObject
支持三种处理状态:
常量 | 值 | 说明 |
---|---|---|
ResponseObject.SUCCESS | ok | 被成功处理。对应AWS UI中simpleAlertd的ok或info提示 |
ResponseObject.WARNING | warning | 操作发生警告。对应AWS UI中simpleAlertd的warning提示 |
ResponseObject.ERROR | error | 操作发生错误。对应AWS UI中simpleAlertd的error提示 |
状态值可在返回结果的
result
项检查,这是一个必须结构
msg-信息
当处理成功或发生失败时,应该将进阶的信息反馈给调用者。
//success msg
return ResponseObject.newOkResponse("a订单被取消").toString();
//或者
ResponseObject ro=ResponseObject.newOkResponse();
ro.msg("a订单被取消");
return ro.toString();
//warning msg
return ResponseObject.newWarnResponse("a订单已经发出").toString();
//或者
ResponseObject ro=ResponseObject.newWarnResponse();
ro.msg("a订单已经发出");
return ro.toString();
//error msg
return ResponseObject.newErrResponse("a订单取消失败,原因是xxxx").toString();
//或者
ResponseObject ro=ResponseObject.newErrResponse();
ro.msg("a订单取消失败,原因是xxxx");
return ro.toString();
补充信息可在返回结果的
msg
项检查,这是一个附加结构
data-数据
以key/value形式由开发者自定义,value可以是一个简单Java对象也可以是一个集合对象。
Map<String, Object> orderDetails = new HashMap<>();
orderDetails.put("orderId", "001");
orderDetails.put("customerId", "999");
orderDetails.put("customerName", "Actionsoft");
orderDetails.put("amount", Double.valueOf("980.01"));
ResponseObject ro = ResponseObject.newOkResponse();
ro.put("enabled", true);
ro.put("orderDetails", orderDetails);
return ro.toString();
数据可在返回结果的
data
项检查,这是一个附加结构
处理成JSON
默认ResponseObject
的toString()
将数据结构拼装成JSON串。
return ro.toString();
含有状态信息的JSON结构
{
data: {
enabled: true,
orderDetails: {
amount: 980.01,
customerName: "Actionsoft",
customerId: "999",
orderId: "001"
}
},
msg: "",
result: "ok"
}
return ro.toDataString();
只有数据的JSON结构
{
enabled: true,
orderDetails: {
amount: 980.01,
customerName: "Actionsoft",
customerId: "999",
orderId: "001"
}
}
处理成XML
return ro.toXML();
含有状态的XML Document片段
<result type="ok" errorCode="" msg="" />
数据来自文件系统
如果你的Java程序读取本地文件系统的文件,建议文件名和内容强制以utf-8读和写。这样做的原因是中文系统的Window默认是936
字符集(可以使用chcp
命令查看和设置),而大部分OS Server以utf-8进行编码。
如果程序强制以utf-8处理文件,当AWS PaaS在部署一段时间后,客户希望在Windows和Linux之间做迁移时,能够确保用户数据编码格式的一致性。
2.4 业务对象封装
与其他MVC开发框架一样,编写出结构清晰的程序代码,需要对业务实体对象进行属性封装(概念如POJO
、JavaBean
)。
AWS MVC提供了设计业务实体对象的父类ModelBean
和IModelBean
接口,采用ModelBean
封装的业务实体对象,还有以下优势:
- 提供方法转换成JSON数据结构
- 提供方法转换成XML数据结构
- 作为DAO处理的实体表结构对象
- 作为集群Cache的数据结构对象
TestModel开发示例
public class TestModel extends ModelBean implements IModelBean {
private String id;
private String f1;
private double f2;
public TestModel() {
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getF1() {
if (f1 == null) {
f1 = "";
}
return f1;
}
public void setF1(String f1) {
this.f1 = f1;
}
public double getF2() {
return f2;
}
public void setF2(double f2) {
this.f2 = f2;
}
}
IModelBean接口声明
/**
* AWS MVC框架中,表示实体业务对象接口
*/
public interface IModelBean extends Serializable {
/**
* 将当前对象转换成json处理对象
*/
public JSONObject toJsonObject();
/**
* 将当前对象转换成json串
*/
public String toJson();
/**
* 将当前对象转化成XML片段
*/
public String toXML();
}
2.5 DAO封装
AWS的DAO基于对JDBC的直接封装,与当今流行的Hibernate、iBATIS相比,去除了O/R映射关系的直接依赖,并借鉴了Apache DBUtils设计思想,只在需要的场景完成O/R Mapping。
采用AWS MVC的DAO优势如下:
- 代码简单、直接,性能高
- 无需拼写SQL语句,自动提供表查询、删除和更新操作
- 屏蔽分页技术,自动适应不同数据库的物理分页
- 提供自定义的
RowMapper
,将JDBC对象转换成业务实体对象(ModelBean
) - 提供操作复杂数据库操作的
DBSql
工具类 - 所有操作受控于
AWS SLA
的质量和性能监控、告警
DaoObject类和方法介绍
Dao(Data Access Object)是一个设计模式,它是对数据访问的一种抽象。com.actionsoft.bpms.commons.mvc.dao.IDaoObject
是AWS设计的数据库访问接口,DaoObject
是实现了IDaoObject
接口用于访问AWS本地数据库的抽象父类,该类对单主键数据库表的查询/更新/删除等常规操作提供了实现。
TestDao开发示例
- 继承
ModelBean
,实现业务实体对象 -
继承
DaoObject
,实现Dao处理对象public class TestDao extends DaoObject<TestModel> { public TestDao() { } /** * 插入一条测试记录 */ @Override public int insert(TestModel model) throws DataAccessException{ model.setId(UUIDGener.getUUID()); String sql = "INSERT INTO " + entityName() + "(ID,F1,F2)VALUES(:ID,:F1,:F2)"; Map<String, Object> paraMap = new HashMap<>(); paraMap.put("ID", model.getId()); paraMap.put("F1", model.getF1()); paraMap.put("F2", model.getF2()); return DBSql.update(sql, paraMap); } /** * 更新一条测试记录 */ @Override public int update(TestModel model) throws DataAccessException{ if (UtilString.isEmpty(model.getId())) { throw new DataAccessException("Method getId() Does Not Allow Empty!"); } Map<String, Object> paraMap = new HashMap<>(); paraMap.put("F1", model.getF1()); paraMap.put("F2", model.getF2()); // 不需要写sql,可调用基类封装的update方法 return update(model.getId(), paraMap); } /** * 封装测试 * * @param id * @param f2 * @return */ public int updateF2(String id, double f2) throws DataAccessException{ Map<String, Object> paraMap = new HashMap<>(); paraMap.put("F2", f2); return update(id, paraMap); } /** * 封装DBSql测试 * * @return */ public long count() { return DBSql.getLong("SELECT COUNT(ID) AS C FROM " + entityName(), "C"); } /** * 封装DBSql测试 * * @param f2 * @return */ public List<TestModel> queryByF1(String f1) { return query("F1=?", f1).orderBy("F2").desc().list(); } /** * 该Dao实现的表名称 */ @Override public String entityName() { return "TEST_DAO"; } /** * 构建该Dao从一条记录转换成对象的映射对象 */ @Override public RowMapper<TestModel> rowMapper() { return new Mapper(); } /** * TestDao Mapper */ private class Mapper implements RowMapper<TestModel> { public TestModel mapRow(ResultSet rset, int rowNum) throws SQLException { TestModel model = new TestModel(); try { model.setId(rset.getString("ID")); model.setF1(rset.getString("F1")); model.setF2(rset.getDouble("F2")); } catch (Exception e) { e.printStackTrace(); } return model; } } }
异常处理
当操作发生错误时,框架将抛出
uncheck
异常(如AWSDataAccessException),如果你的逻辑没有方案或需求去处理这个异常可以继续向外抛出。
当操作发生参数非法、执行非法等常见Dao处理逻辑场景时,建议抛出如下异常(详细请参见异常处理章节)
- AWSIllegalArgumentException 非法参数异常造成错误的访问请求,对应400错误
- AWSObjectNotFindException 资源未找到异常,对应404错误
- AWSForbiddenException 访问被拒绝异常,对应403错误
默认编码字符集
utf-8
事务处理与资源释放
Spring MVC自动接管了事务与资源释放,这是非常棒的编程体验。为提高性能,目前AWS DAO框架未接管JDBC事务和自动完成Connection
释放。
当你的程序需要事务支持时,可以遵循标准的JDBC编程规范,对Connection
对象进行事务的开启、回滚或提交。
如果你的程序获得了一个新的Connection
(如通过DBSql.open()
),那么最终需要你的代码通过DBSql.close()
释放这个连接。
物理表
建议使用AWS的BO
模型设计和维护你的物理表结构,如果某些表必须由自己的sql创建(不推荐),那么需要遵循App开发规范中约定的表名前缀和sql安装/升级脚本规范。
数据库连接池
AWS MVC的数据库连接池使用了tomcat-jdbc,相关高级参数调优,可修改对应AWS安装目录bin/conf/db_pool.properties
文件。
DBSql类和方法介绍
com.actionsoft.bpms.util.DBSql
是和AWS数据库交互的工具类,它基于PreparedStatement
实现了数据库的查询、插入、更新、批处理,DBSql一般用于DaoObject中。
- get方法用于简单类型查询
- query方法用于自定义复杂查询
- update方法用于数据库的更新/插入/删除
- batch方法用于批处理
- open/close数据库连接/释放
- 其它工具方法
// 查询单个字段
String value_a = DBSql.getString("select a from table_test where id=?", new Object[]{"id1"});
// 查询多个字段
Map<String,Object> value_map = DBSql.getMap("select a,b,c from table_test where id=?", "id1");
// 查询返回自定义对象,MyBean是java类
List<MyBean> list = DBSql.query("select a,b,c from table_test where id=?", new RowMapper<MyBean>() {
@Override
public MyBean mapRow(ResultSet rs, int rowNum) throws SQLException {
MyBean mybean = new MyBean();
mybean.setA(rs.getString("a"));
return mybean;
}
}, "id1");
详细请参见aws-api-doc的
DBSql
2.6 Cache缓存
AWS MVC的Cache框架支持本地缓存和集群缓存,可以通过扩展AWS平台的Cache插件(Plugin)实现自己的缓存对象。
有关Cache开发详细内容,参见《AWS 插件扩展开发参考指南》
3 异常处理框架
AWS MVC框架的异常处理过程如下所示
在上图中,请求者(用户或服务API)被前端控制器封装成指令并传输至AWS服务器,当图中红色、橙色和黄色区域异常发生后,由AWS的顶层异常拦截器捕获,向请求者返回错误消息。
在这个章节中,你将了解如下内容:
- 错误码定义
- 抛出异常
- 处理异常
3.1 错误码
通过对错误码定义,能够简单的帮助用户或开发者识别和理解异常性质,错误码与错误不是一对一关系,是错误类型的一种抽象代号。
AWS的错误码参照了HTTP
状态码定义。错误码以3
位的数字代码表达,所有错误码首数字
代表的一类错误。
首数字 | 说明 |
---|---|
4 | 客户端错误 |
5 | 服务端错误 |
7 | 服务可用性 |
8 | 配合限制和其他 |
当请求返回了AWS非预期消息或错误时,除了提供错误码,通常我们会根据具体的场景提供问题概要说明,如果是出错类异常,详细信息一定被记录到AWS的error.log
文件。
码表
Code | 描述 | 异常或发生场景 |
---|---|---|
400 | 错误的参数请求(Bad Request) 通常当缺少必要参数,或者参数值格式不正确时,会返回该错误信息。此时可以查看相关文档确认每个参数的格式是否正确。例如:执行启动流程方法时,未提供processInstId参数 |
AWSIllegalArgumentException * 当客户端请求AWS服务时,若处于该场景将以该错误码返回到ResponseObject数据结构 |
401 | 未授权被拒绝(Unauthorized) 当用户提供了无效的session,或者请求的鉴权结果不正确时,会返回该错误信息。 |
目前只适用于SOAP/REST API的Web层封装的错误代码,不适用于服务器端异常处理 当客户端请求AWS服务时,若处于该场景将以该错误码返回到ResponseObject数据结构 |
403 | 访问被拒绝(Forbidden) 该请求是有效的,但操作是被禁止且不应该再次尝试时,会返回该错误信息。例如:要执行的任务实例已结束 |
AWSForbiddenException * 当客户端请求AWS服务时,若处于该场景将以该错误码返回到ResponseObject数据结构 |
404 | 找不到资源对象(Not Find Resource) 当用户试图访问不存在的资源时,会返回该错误信息。例如:要执行的任务实例已不存;账户不存在 |
AWSObjectNotFindException |
405 | 请求方法不允许(Method Not Allowed) 使用了不支持的请求方法去操作资源时,会返回该错误信息。例如:使用GET请求一个POST操作 |
* 目前只适用于REST API的Web层封装的错误代码,不适用于服务器端异常处理 |
408 | 资源请求超时(Request Timeout) 请求超出了等待时间,会返回该错误信息。例如:在调用AWS的SOAP或REST服务,连接至AWS服务器超时 |
* 目前只适用于SOAP/REST API的Web层封装的错误代码,不适用于服务器端异常处理 |
500 | 内部错误(Internal Server Error) 当服务器执行请求过程中,遇到内部处理错误时,会返回该错误信息。遇到这种错误,请检查AWS的错误日志,及时与我们联系 |
AWSException 所有继承该异常子类,未实现错误号的异常(getAPIErrorCode()) 所有JDK或非AWS异常抛出,被系统捕获的 * 当客户端请求AWS服务时,若处于该场景将以该错误码返回到ResponseObject数据结构 |
520 | 引擎错误(Engine Error) 当服务器执行请求过程中,遇到流程引擎、表单引擎等引擎类错误时,会返回该错误信息。遇到这种错误,请检查AWS的错误日志,及时与我们联系 |
AWSEngineException AWSExpressionException |
521 | 传输转换错误(Transfer Error) 当服务器执行请求过程中,遇到导入导出或格式转换错误时,会返回该错误信息。遇到这种错误,请检查AWS的错误日志,及时与我们联系 |
AWSTransferException |
530 | 应用容器错误(App Container Error) 当服务器执行请求过程中,遇到PaaS应用容器类错误时,会返回该错误信息。遇到这种错误,请检查AWS的错误日志,及时与我们联系 |
AppContainerException |
540 | 应用商店错误(AppStore Error) 当服务器执行请求过程中,遇到PaaS与AppStore相互处理过程中发生错误时,会返回该错误信息。遇到这种错误,请检查AWS的错误日志,及时与我们联系 |
AppStoreException |
550 | 业务错误(BPMN Error) 当BPMN引擎执行时由开发者抛出BPMNError业务异常时,会返回该错误信息。遇到这种错误,请与业务开发者联系 |
BPMNError |
590 | AWS Instance Server连接失败 当客户端以HTTP(S)经Web连接至AWS服务器时,未能正常建立通信连接时会返回该错误信息。遇到这种错误,可能是AWS服务已停止或Web与AWS之间的网络故障 |
Web层错误 |
591 | 处理AWS Instance Server响应时发生错误 当客户端以HTTP(S)与AWS服务器建立连接后,在发生指令请求等待返回结果发生错误时,会返回该错误信息。遇到这种错误,请检查AWS的错误日志,及时与我们联系 |
Web层错误 |
760 | 服务正在启动(Instance Starting) 当服务器正在启动尚未就绪时,会返回该错误信息。遇到这种错误,请稍后执行 |
*当客户端请求AWS服务时,若处于该场景将以该错误码返回到ResponseObject数据结构 |
761 | 服务正在关闭(Instance Stoping) 当服务器正在关闭时,会返回该错误信息。遇到这种错误,请不要再重复请求,服务器将被关闭 |
* 当客户端请求AWS服务时,若处于该场景将以该错误码返回到ResponseObject数据结构 |
762 | 服务脱机(Instance Offline) 当服务器处于运行中,由运维人员暂停客户端响应时,会返回该错误信息。遇到这种错误,请联系系统管理员 |
* 当客户端请求AWS服务时,若处于该场景将以该错误码返回到ResponseObject数据结构 |
770 | 应用正在启动(App Starting) 当访问的应用正在启动尚未就绪时,会返回该错误信息。遇到这种错误,请稍后执行 |
* 当客户端请求AWS服务时,若处于该场景将以该错误码返回到ResponseObject数据结构 |
771 | 应用正在关闭(App Stoping) 当访问的应用正在关闭时,会返回该错误信息。遇到这种错误,请不要再重复请求,应用将被关闭 |
* 当客户端请求AWS服务时,若处于该场景将以该错误码返回到ResponseObject数据结构 |
772 | 应用脱机(App Offline) 当应用处于就绪但依赖的应用未安装或暂停后,会返回该错误信息,如果该应用未被授权或订阅也会处于772状态。遇到这种错误,排出错误后再启动该应用 |
* 当客户端请求AWS服务时,若处于该场景将以该错误码返回到ResponseObject数据结构 |
773 | 应用已卸载(App Uninstall) 当应用已经被卸载后,会返回该错误信息。遇到这种错误可以忽略,或访问应用管理,将卸载的应用还原 |
* 当客户端请求AWS服务时,若处于该场景将以该错误码返回到ResponseObject数据结构 |
774 | 应用出错暂停(App Failed) 当应用启动失败后,会返回该错误信息。遇到这种错误,请检查该应用的日志,排出错误后再启动该应用 |
* 当客户端请求AWS服务时,若处于该场景将以该错误码返回到ResponseObject数据结构 |
800 | 许可配额限制(Quota Limit) 当资源配额超过许可限制时,会返回该错误信息。例如:超过许可的注册用户数 |
AWSQuotaException * 当客户端请求并超过许可证允许的最大并发返回到ResponseObject中 |
如何使用错误码
- 如果错误来自
AWSException
及其子类,可以通过getAPIErrorCode()
在Java代码中获取 - 如果错误来自客户端API,可通过
ResponseObject
结构的errorCode
读取
3.2 异常抛出
AWS平台提供的异常对象都是uncheck
类型,开发者可以根据处理的需要进行捕获,如果开发者非常明确的要抛出这些异常,那么可以不对其处理。
除AWSAPIException
外,所有AWS内部异常的父类都是AWSExceptione
,常见异常如下:
Exception | 说明 |
---|---|
AWSAPIException | API调用异常(uncheck) |
AWSException | AWS平台异常(以下均内部使用,uncheck)【通用】 |
AWSClassLoaderException | 类加载异常 |
AWSEngineException | 引擎内部异常(流程、表单、报表等,见该类常量) |
BPMNDefException | BPMN定义异常(设计阶段) |
BPMNError | BPMN规范要求捕获的异常抛出(运行阶段) |
AWSDataAccessException | 数据操作异常。如数据库操作、JSON数据操作 |
AWSIllegalArgumentException | 参数校验异常【通用】 |
AppStoreServiceException | 访问AWS企业应用商店异常 |
常用异常
虽然AWS平台定义了很多异常对象,但是对于应用开发者,只需要熟练掌握以下几个,即可满足大部分开发场景的需要:
- AWSIllegalArgumentException(400)
- AWSForbiddenException(403)
- AWSObjectNotFindException(404)
- AWSException(500)
//参数合法性异常
throw new AWSIllegalArgumentException("参数1", AWSIllegalArgumentException.FORMAT,"参数必须是0-9数字");
throw new AWSIllegalArgumentException("参数1", AWSIllegalArgumentException.EMPT);
throw new AWSIllegalArgumentException("参数1不能为空");
//操作被拒绝
throw new AWSForbiddenException("流程已经挂起,操作被拒绝");
throw new AWSForbiddenException("ctx类型不当,应给定begin()返回的上下文对象");
//对象不存在
throw new AWSObjectNotFindException("App文件不存在[" + appFile.getPath() + "]");
throw new AWSObjectNotFindException("流程定义未找到。processDefinitionId:" + processDefinitionId);
注意事项
- 4类异常,通常可以直接抛出给前端处理
- 5类异常,除非开发者捕获该异常也无法提供解决方案,否则应在上层逻辑捕获并处理
- 7和8类异常属于底层非预期信息,开发者不必捕获可直接抛出
- 在捕获异常时,不建议直接捕获Exception,除非你的意图是处理掉所有异常的抛出
- 如果开发者的程序捕获了所有异常,应当使用e.printStackTrace(System.err)记录日志
3.3 异常处理
当异常被AWS MVC顶层框架捕获后,会根据cmd请求类型处理成客户端能够理解的文档格式。
请求类型 | 格式 |
---|---|
./w | HTML Document |
./jd | JSON Document |
./xd | XML Document |
Java Exception处理
当发生底层Java异常或其他非AWSException
异常时,AWS MVC将该异常封装成500
错误。
异常日志
捕获的异常被记录至AWS logs目录下
error.log
(单一部署)error-%AWS节点名%.log
(集群部署)
HTML Document警告页面
JSON Document数据结构
XML Document数据结构
4 国际化
4.1 多语言
AWS MVC框架对HTML/JavaScript多语言和Java程序多语言提供了一整套完善的开发方案,以下为AWS MVC的多语言处理架构。
AWS MVC每次接收到用户请求时,在会话对象(UserContext.getLanguage()
)提供了该用户的界面语言信息,AWS MVC为应用提供了两种常见解决方案:
Java程序
通过SDK.getAppAPI().i18nValue()
获得指定用户界面的多语言资源配置
SDK.getAppAPI().i18NValue("com.actionsoft.apps.poc.api", me, "info1")
HTML模版
在HTML页面或JavaScript中出现的多语言标签,使用<I18N#变量名
>替代,其中变量名为多语言资源配置Item
的Key
。
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title><I18n#PageTitle></title>
<script>
var var1 = "<I18n#Var1>";
var var2 = "<I18N#Var2>";
alert(var1);
alert(var2);
</script>
</head>
<body>
Hi,<I18n#PageTitle>
</body>
</html>
多语言资源文件
遵循AWS PaaS对App的资源定义规范,每个AWS应用的多语言资源配置文件被存放在应用安装目录/i18n/
下。
该目录允许存在1个或多个符合Schema规范的xml文件,建议为自己的应用创建一个名为resource.xml
的资源配置文件。
项 | 说明 |
---|---|
item/key | 多语言资源名,同个App下不允许重复 |
item/cn | 中文简体 |
item/en | 英文 |
item/big5 | 中文繁体 |
item/%lang% | 其他扩展的语言名 |
resource.xml示例
<locale-config>
<lang>
<item key="info1">
<cn><![CDATA[这是中文简体语言]]></cn>
<en><![CDATA[This is the English language]]></en>
<big5><![CDATA[這是中文繁體語言]]></big5>
</item>
<item key="PageTitle">
<cn><![CDATA[这是标题]]></cn>
<en><![CDATA[This is Title]]></en>
<big5><![CDATA[這是標題]]></big5>
</item>
<item key="Var1">
<cn><![CDATA[这是变量1]]></cn>
<en><![CDATA[This is Var1]]></en>
<big5><![CDATA[這是變量1]]></big5>
</item>
<item key="Var2">
<cn><![CDATA[这是变量2]]></cn>
<en><![CDATA[This is Var2]]></en>
<big5><![CDATA[這是變量2]]></big5>
</item>
</lang>
</locale-config>
多语言资源文件管理
建议访问AWS企业应用商店,安装“多语言管理工具
”。
该工具提供了可视化的多语言配置工具,能够极大提高翻译人员的工作效率。
如何扩展更多种语言
默认AWS PaaS只提供了中文简体、英文和中文繁体三种界面语言,可以安装“多语言管理工具
”扩展更多种语言。
以下代码打印出当前AWS PaaS支持的语言集
List<LanguageModel> langs = SDK.getPlatformAPI().getlanguages();
for (LanguageModel lang : langs) {
System.out.println(lang.getName());
}
4.2 时区和工作日历
对于跨国企业/组织或长期国际差旅时,用户需要根据工作地点的时区获得与当地时间一致的日期信息,并遵守当地的节假日和企业工作时间要求。
在AWS MVC框架中,时区主要解决符合用户当地时间的日期显示;工作日历主要解决对员工有效工作时间的计算,如流程执行效率,并提供API来处理业务需求,如差旅请假时长计算。
AWS是如何处理时区的
时区和工作日历的管理和设置
工作日历API接口
5 附录1-编程资源
AWS MVC是一个开放的编程架构,你可以方便的将自己需要的工具包加入到自己的App中使用:
- 三方Jar类库 存放到App安装目录的lib下
- 三方JavaScript、CSS库 存放到Web层的
apps/%appId%/
下
AWS PaaS提供的开源Jar类库
可在你的程序中直接使用AWS PaaS自带的一些第三方开源类库,这些Jar文件存放在AWS安装目录的bin/lib
和bin/jdbc
下。
类库 | 说明 |
---|---|
commons-* | Apache提供的若干工具类 |
barcode4j | 条形码生成 |
cajo | RMI工具类 |
csv | CSV数据处理工具 |
xalan/... | XML数据处理 |
json-lib | JSON数据处理 |
poi | Office文件处理 |
httpclient | HTTP客户端 |
itext | PDF处理 |
sigar | 系统性能监控 |
log4j | Java日志处理系统 |
cxf | Web服务处理框架 |
... | ... |
AWS PaaS封装的Web UI
这些组件全部基于JQuery和JQueryMobile底层框架封装,使用这些UI有助于开发的应用界面与AWS其他应用保持一致的交互习惯。详细说明参见AWS UI章节
5.1 SDK API
AWS PaaS作为App运行的容器环境和资源平台,为App开发者提供了丰富的API,这些API可以直接在你的Java程序中使用。
对于API详细说明及用法,参见aws-api-doc(一个Java API Doc)。
MVC编程常用API
类 | 说明 |
---|---|
SDK | SDK API的总入口 |
ActionWeb | Web(View)请求处理的父类 |
ModelBean | 业务实体对象父类 |
DaoObject | DAO对象父类 |
ResponseObject | 返回JSON、XML结构化数据,如操作状态、业务数据 |
UserContext | 用户会话,获得用户会话串、登录IP、语言、设备类型、用户组织等 |
AppAPI | 多语言处理、跨应用的ASLP调用、应用日志 |
ORGAPI | 访问组织结构相关接口 |
PermAPI | 访问AWS权限相关接口 |
PortalAPI | 访问或构建门户应用相关接口 |
RuleAPI | 规则处理接口 |
DCAPI | 文件处理接口 |
平台系统常用API
类 | 说明 |
---|---|
PlatformAPI | 查询平台及服务状态接口 |
ConfAPI | 查询平台常用配置参数接口 |
SLAAPI | 监控告警接口 |
BPM引擎常用API
类 | 说明 |
---|---|
ProcessAPI | 流程实例控制接口 |
TaskAPI | 任务实例控制接口 |
ProcessExecuteQuery | 引擎执行结果查询接口 |
ProcessQueryAPI | 流程实例查询接口 |
TaskQueryAPI | 任务查询接口 |
HistoryTaskQueryAPI | 历史任务查询接口 |
DelegationAPI | 任务委托/代理接口 |
RepositoryAPI | 模型资源库访问接口 |
BOAPI | BO操作接口 |
BOQueryAPI | BO查询接口 |
监听器常见接口(事件编程)
类 | 说明 |
---|---|
ValueListener | 取值类监听器父类 |
ExecuteListener | 执行类监听器父类 |
InterruptListener | 中断类监听器父类 |
注意事项
- 不推荐直接调用aws-api-doc未提供的接口方法
- SDK API适用于在AWS Server端执行,不能用于Web层开发。如果你在Web层使用了不符合AWS MVC框架的开发模式,可以通过AWS CC发布Server API或封装ASLP服务来访问AWS Server端操作
5.2 AWS UI
为统一PaaS用户的交互体验(UX)和界面展示(UI),AWS MVC框架为开发者提供了一套基于JQuery封装的JavaScript UI组件库。目前这个UI库仍处在完善中,如果增强了用户体验或封装了新的UI类型,欢迎你的贡献!请邮件联系liujx@actionsoft.com.cn
了解每个AWS UI组件的文档、示例,可本地启动AWS服务后,在浏览器输入以下url访问。
http://localhost:8088/portal/commons/js/jquery/demo/index.html
在你的页面引入AWS UI
以下代码可将JQuery、AWS基本UI加入到你的页面中。对于部分专用UI,请参见相关示例引入特定的资源
<link rel="stylesheet" type="text/css" href="../commons/css/awsui.css">
<script type="text/javascript" src="../commons/js/jquery/scripts/jquery.js"></script>
<script type="text/javascript" src="../commons/js/awsui.js"></script>
5.3 量命名词汇表
为规范App开发者对专业变量的命名和识别,在这里给出一个词汇表参考。
设计期
项 | 命名参考 |
---|---|
存储模型ID | boDefId |
表单模型ID | formDefId |
表单子表模型ID | formItemDefId |
流程模型ID | processDefId |
节点模型ID | 通用:activityDefId 特定:userTaskDefId、serviceTaskDefId.. |
报表模型ID | reportDefId |
DW模型ID | dwDefId |
各种Context对象 | 如UserContext、TaskBehaviorContext... 建议:单独出现时命名变量为ctx或context,同时出现多个不同类型的Context时,使用userContext、taskContext区分 |
登录账户名 | uid、uids(多个),对应ORGUSER的USERID字段 |
单位ID | companyId |
部门ID | departmentId |
角色ID | roleId |
小组ID | teamId |
小组成员ID | teamMemberId |
运行期
项 | 命名参考 |
---|---|
流程实例ID | 建议processInstId,可以使用processInstanceId |
流程实例对象 | 建议processInst,可以使用processInstance |
任务实例ID | 建议taskInstId,可以使用taskId、taskInstanceId |
任务实例对象 | 通用:建议taskInst,可以使用task、taskInstance 特定:建议historyTaskInst,可以使用historyTask、historyTaskInstance |
BO表ID | boId |
BO表与流程实例绑定 | 通用:bindId 特定:纯流程驱动场景下,也可使用processInstId |
6 附录2-程序文件
应用的安装、部署和运行由AWS PaaS自动化完成,但在开发阶段需要开发者了解这些资源结构。
Web层资源
Web层是指部署在Web Server
(如Tomcat)的资源。AWS PaaS为每个App分配了独立的目录,被称为Web层根资源根目录。
你可以在这个目录中规划自己的js、css等资源结构。
//存放Web参数解析配置
%AWS-HOME%/webserver/webapps/portal/apps/%appId%/action.xml
//存放css
%AWS-HOME%/webserver/webapps/portal/apps/%appId%/css/
//存放js
%AWS-HOME%/webserver/webapps/portal/apps/%appId%/js/
//存放图片
%AWS-HOME%/webserver/webapps/portal/apps/%appId%/img/
//存放jsp程序(*不允许jsp直连数据库的开发模式,使用MVC cmd开发)
%AWS-HOME%/webserver/webapps/portal/apps/%appId%/jsp/
//自定义
%AWS-HOME%/webserver/webapps/portal/apps/%appId%/.../
%AWS-HOME%
是AWS PaaS的安装根目录%appId%
是应用的Id名
App层资源
App层是指部署在AWS Server
的资源。AWS PaaS为每个App分配了独立的目录,并通过安装、卸载库进行管理。
在开发的应用在容器仓库里处于install
状态,与MVC编程相关的目录资源如下
//存放App的配置描述
%AWS-HOME%/apps/install/%appId%/manifest.xml
//存放App的LOGO
%AWS-HOME%/apps/install/%appId%/icon16.png
%AWS-HOME%/apps/install/%appId%/icon64.png
%AWS-HOME%/apps/install/%appId%/icon96.png
//存放程序编译的jar文件和第三方类库
%AWS-HOME%/apps/install/%appId%/lib/
//存放HTML模版
%AWS-HOME%/apps/install/%appId%/template/page/
//存放多语言资源
%AWS-HOME%/apps/install/%appId%/i18n/resource.xml
7 附录3-开发工具
AWS MVC的开发者可以根据自己的编程习惯选择开发工具。
AWS Developer
当安装了AWS PaaS开发环境后,会为开发者提供一个专有的开发工具。该工具基于Eclipse IDE封装,提供了专有的扩展插件,能够更直观、高效的进行AWS App开发。
//开发工具根目录
%AWS-HOME%/developer/
使用AWS Developer的优点
- 无需配置即可在工程代码中启动、调试、编译和分发操作
- 根据Controller类自动生成Web端接参配置文件,提高工作效率
- 向导式开发
- 创建App应用
- 创建cmd请求
- 创建ModelBean
- 创建Dao
- 创建Cache
- 管理系统Jar包依赖
- 创建各种AWS扩展插件...
- 提供对App各类参数的配置管理
- 内嵌支持
SVN
代码版本管理
Eclipse
对于熟悉AWS PaaS和App应用资源配置结构的开发者,也可以直接使用Eclipse完成所有的任务目标。
- 新建
Java普通工程
- 在
Java Build Path>Libraries
下创建aws_lib
库,增加以下资源%AWS-HOME%/bin/lib/*.jar(含子目录) %AWS-HOME%/bin/jdbc/*.jar
- 启动
aws-infrastructure-common.jar
的StartUp
com.actionsoft.bpms.server.AWSServer.StartUp
- 指定启动选项中
Working directory
目录%AWS-HOME%/bin
developer.csr
在你的团队正式开发应用前,应获得应用开发者证书(ISV)。证书文件路径如下
%AWS-HOME%/apps/developer.csr
8 微信企业号框架
微信企业号框架基于AWS MVC框架,将请求根据请求类型(URL跳转、消息/事件)交由不同的Servlet处理,再根据请求的映射规则分发给相应的后端逻辑控制器进行处理。
上图中的三个Servlet(AWS Web Server / 一般请求Servlet,WS Web Server /重定向Servlet,WS Web Server /回调Servlet),后端处理控制
(AWS App Server / Controller)和微信企业号管理平台
是微信企业号的核心通信框架,AWS微信App是开发者实现业务逻辑的区域,主要元素描述如下:
项 | 说明 |
---|---|
AWS Web Server | 安装有AWS Portal的标准Servlet容器,例如:Tomcat、WebLogic |
AWS App Server | 安装有AWS Server的应用服务器,所有的业务逻辑在这里处理 |
一般请求Servlet | 接收URL跳转请求,收到请求后会检查是否带有包含用户认证信息的Cookie,如果包含则封装后转发给后端控制器,若不包含则构造微信OAuth验证链接,重定向到下面的重定向Servlet |
重定向Servlet | 处理微信OAuth验证请求,封装后转发给后端控制器,最终交由微信管理平台处理并返回验证结果。如果验证通过,将验证信息写入Cookie,最后重定向到原始URL |
回调Servlet | 微信企业号应用的回调地址指向此处。处理微信消息/事件请求,封装后转发给后端控制器,再由微信管理平台转发到指定的AWS微信App处理请求 |
后端处理控制器 | 通过注解拦截到方法,绑定逻辑处理程序 |
微信企业号管理平台 | 管理微信企业号应用,可为企业号应用设置、绑定菜单和指定处理消息/事件的AWS 微信App |
AWS微信App | 实现业务逻辑,一般包含H5页面(View视图组装,Model/Dao/Cache模型,Template模板),和消息/事件处理实现类。 |
9 文档历史记录
下表说明了对该文档所做出的重要更改。
类型 | 说明 | 修改日期 |
---|---|---|
首次发布 | 这是AWS MVC框架参考指南的首次发布 | 2015年01月22日 |