一、背景
上一篇介绍了Javs整体项目的相关内容,本篇将重点介绍一下JavsScript的核心语法和相关特性。这里将对整个Javs脚本语言中涉及到的概念和相关的规则定义等做一个相对全面的介绍,后续可据此扩展和完善。
二、概念
2.1 关键字
同Java和其他的计算机编程语言一样,JavsScript同样也有关键字,这些关键字被分为两种,一种是基于Java原生关键字扩展出的Javs关键字如ret,ifnull等,当然还有基于Java原生SDK或者二方包扩展出的关键字,这种场景可以方便用户自定义常用的二方包引用方式。另外一种就是业务关键字,业务关键字同样具有很强的灵活性和代表意义,比如bo,cmd,vo,dto,factory等等。这些都是从业务代码模型中抽象出来的。
2.2 函数
在Javs中的函数是非常简单的,javs中的函数声明只有func开头和函数名,以及简化的函数参数,比较特别的是没有返回值。Javs文件中比较重要的组成部分就是函数了,至于函数具体返回什么,以及函数真正的参数类型这些都由PlantUML领域模型文档中的方法定义决定。基于Javs函数编写伪代码则相当于在写真正的java方法函数。
2.3 代码段
Javs函数体里的重要组成部分就是代码段了,代码段通常也分为几种,如果从是否原生的角度来看带有Java语句;表示的则是java原生代码段,否则就是javs代码段。一般来说Javs中的一行代码至少可以表达Java中的一行代码,甚至是Java中的多行代码。从其他角度来看代码段则包括条件判断,赋值,循环控制等类型,这会在第四节讲到。
2.4 宏定义
在Javs中仍然有一个比较特别的概念,就是宏定义类似于C中的一些全局声明,Javs中的宏定义目前主要包括全局变量声明,和包引用,或者组件引用。对应着Java原生代码中的全局变量声明,类的引用和二方包的引用。
2.5 对象
众所周知,Java是面向对象编程的一门编程语言,所以基于Java的Javs也有一些对象的影子,这些对象则包括变量引用和变量池,在Javs中声明变量和使用变量都会被Javs引擎中的变量池进行引用方便转译代码。对于对象的声明则与Java原生代码差别不大。
2.6 变体
在Javs中,变体的概念也比较重要,相对于java原生代码而言关键字和函数的区分是比较明显的,但是在Javs中则不太明显,比如if或者return,在javs中if可以演变出很多不同的花样,同时return对应的ret既可以是关键字也可以是关键字函数,得益于Javs中的变体,这让Javs天生具有比较高的灵活性,写伪代码也不会受到原生代码或者原生语法规则的限制。
三、关键字说明
3.1 符号说明
. :代表对象.资源 或者对象.属性 => 代表下一行代码 ; :代表是一段原生代码—>java 代码 () :代表函数 $:防止属性或者函数与内置函数相同,进行特别标示
解析的优先级或者顺序:
-
=> -
. -
()
3.2 对象关键字列表
代码元素名称 | 代码元素标识 | 代码元素对应的调用资源 | 代码元素对应的调用函数 | 说明 |
---|---|---|---|---|
业务对象 | bo | .factory .gataway .service .repository | bo.convertdo() –> 借助mapstruct返回do对象bo.convertdos() –> 借助mapstruct返回do 列表对象bo.convertdto() –> 借助mapstruct返回dto对象 bo.convertdtos() –> 借助mapstruct返回dto 列表对象 | 其他的点则是属性比如bo.xxName,或者bo.xxCode,如果有重名的则可以用$repository代替bo指向的对象。其他为bo对象自己的函数如bo.instance() bo.identifer()bo.disable() |
数据库实体对象 | do | .mapper | do.convertbo() –> 借助mapstruct返回bo对象do.convertbos() –> 借助mapstruct返回bo 列表对象 | 比如do.id,或者do.xxCode,如果有重名的则可以用$xxCode代替do指向的对象 |
命令对象 | cmd | .executor | 找到对应的执行器,如果有多个实现—>直接.springbean,如.userCmdExecutor.mapping –> 这里类似于mapstruct或者factory将找到一个工厂转换函数对象转换到其他对象 | cmd.convertevent():返回一个event对象 (可能要走mapstruct返回event对象或者cmd自己内部的方法) |
事件对象 | event | .publisher | 借助spring event函数发布 | event.convertmsg() –> 返回一个msg对象 (可能要走mapstruct返回msg对象或者event自己内部的方法) |
数据传输对象 | dto | .factory .validator .convertbo() | 找到对应的工厂bean 找到对应的校验bean | dto.convertbo() –> 借助mapstruct返回bo对象,dto.convertbos() –> 借助mapstruct返回bo 列表对象 |
这里需要说明的是,上述的对象是基于模型驱动的,其好处在于可以让模型根据方法参数匹配去寻找合适的service来构建方法引用从而完成方法调用,另外一方面也可以避免过多的命名导致的心智负担。
3.3 if else条件关键字列表
语法关键字/语法函数 | 语法说明 | Java原生语句 |
---|---|---|
if() | 条件判断成立 | if(a == 1){ |
if(b){ | ||
ifbreack() | 条件判断成立然后break | if(a == 1){ break;} |
ifempty() | 参数为空,非集合判断 | if(StringUtils.isEmpty(a)){ |
ifemptys() | 参数为空,用于集合 | if(CollectionUtils.isEmpty(aList)){ |
ifeq() | 如果参数相等 | if(Objects.equals(a,b)){ |
ifnotemptys() | 如果参数不为空,集合判断 | if(CollectionUtils.isNotEmpty(list)) |
ifnotempty | 如果参数不为空,非集合判断 | if(StringUtils.isNotEmpty(a))if(Objects.isNotNull(b)) |
ifnotnull | 如果不为null | if(!Objects.isNull(a)){ |
ifret() | 如果条件成立则返回 | if(a == 1){return;} |
ifretf() | 如果条件成立则返回失败 | if(a == 0){return ResultDto.fail(xxxx,xxx);} |
ifrets() | 如果条件成立则返回成功 | if(a == 1){ return ResultDto.success();} |
ifrettrue() | 如果条件成立则返回true | if(a == 1){return true;} |
ifretfalse() | 如果条件成立则返回false | if(a == 1){return false;} |
if关键字存在很多变体,这些变体的由来是通过对原生代码结构的分析而进行简化的,这样的话就可以通过非常简短的词组来表达一部分代码段,而我们所要做的就是简单理解这些词组的含义。如果上面常见的变体场景不能满足你的需求的话,那么你可以自定义变体然后在Javs引擎中实现自定义的解析替换规则。
3.4 return关键字列表
语法关键字/语法函数 | 语法说明 | Java原生语句 | 是否是变体 |
---|---|---|---|
ret | 方法内返回 不带返回值 | return; | 否 |
ret() | 返回 | return 0; | |
return “success”; | |||
retf() | 方法内返回 返回失败 | return ResultDto.fail(000,111); | 是 |
rets() | 方法内返回 返回成功 | return ResultDto.success(data) | 是 |
retfalse | 返回false | return false; | |
rettrue | 返回true | return true; |
return关键字与条件关键字基本是一样的,不同的地方是retun关键字的变体可以是一种内置的函数关键字,上面的if关键字几乎都是函数关键字,相当于通过()进行参数引用和传递。这样的话其灵活性会更高,你可以相对自由地定义此关键字是单纯的关键字还是带有函数性质的关键字。
3.5 for循环关键字
语法关键字/语法函数 | 语法说明 | Java原生语句 |
---|---|---|
fore() | 增强列表for循环 | for(String str : listStr){} |
fori() | 普通列表for循环 | for(int 1=0;i<listStr.size();i++) |
sfore | java8 stream for循环 | listStr.stream().foreach(str->{}) |
通常来说Java原生代码中有很多比较重的代码段,比如trycatch,forstream等。所以对于Javs来说去简化Java原生代码的写法收益并不是很多,这里相当于对java的一些语法糖进行简单化的表示然后通过javs引擎去转换,需要说明的一点是这些转换牵扯到了两个方面一方面是java的SDK部分,另外一方面则是语法部分。
3.6 JavaSDK与二方包关键字
语法关键字/语法函数 | 语法说明 | Java原生语句 |
---|---|---|
list() | 没有范型的list声明 | Lists.newArrayList(); |
list<> | 带有范型的list声明 | new ArrayList<>(); |
linkedlist() | 没有范型的linkedlist声明 | Lists.newLinkedList(); |
list<> | 带有范型的linkedlist声明 | new LinkedList<>(); |
map() | 没有范型的map声明 | Maps.newHashMap() |
autowired | spring的bean的autowired声明 | |
resource | spring的bean的resource声明 | |
set() | 没有范型声明的set声明 | Sets.newHashSet() |
cl() |
就目前而言,大多数业务系统对于JavaSDK中的工具类或者工具包使用的并不是特别特别多,所以Javs对使用率比较高的一些JavaSDK的类进行了简化,这样可以保障我们在写Javs代码的时候不需要去想太多Java方面的事情。
3.7 log关键字
语法关键字/语法函数 | 语法说明 | Java原生语句 |
---|---|---|
logdebug() | debug等级的log日志 | log.debug(); |
logerror() | error等级的log日志 | log.error(); |
loginfo() | info等级的log日志 | log.info(); |
logwarn() | warn等级的log日志 | log.warn(); |
通常来说,在任何Java项目中都有一些log的影子,常规做法是声明Logger 对象并初始化,然后在必要的地方进行log输出,但是在Javs世界里我们可以通过log关键字的变体进行log打印,如:
logdebug(xxxxxx)--->log.debug(xxxxxx);
从这里可以看出Javs的设计核心思想就是尽量简洁,尽量简单。
四、代码段示例
在这一节里我将向大家展示一下Javs代码的一些写法案例,来看下Javs像你学的哪种编程语言,毕竟他可能也是四不像(手动狗头)。
4.0 hello world
下面先来个hello world热身下:
func main(args){
//sout为Javs关键字
sout("Hello World.")
}
-
java原生代码
public class Main {
public static void main(String[] args) {
System.out.println("Hello World.");
}
}
需要说明的sout目前可能还不在Javs关键字里,但是不用担心,一般情况下如果你遇到javs没有支持或者没有表达过的语法内容你可以仿照Javs中的一些关键字做自定义。
4.1 宏定义
通常来说在Java原生代码中我们会对一些变量进行全局的声明,受限于java的变量的访问规则所以在javs中可以通过宏定义的方式来定义全局变量,案例代码如下:
场景 | JavsScritp代码 | Java原生代码 | 关键字说明 |
---|---|---|---|
组件导入场景 | import dubbo-client-api | 在对应的Java原生类所在模块中引用dubbo-client-api 方便包导入 | import为Javs关键字 |
组件 + 类导入场景 | import common.ResultDto | import com.coderman.common.ResultDto; | |
特定类导入场景 | import com.tianhua.javs.TagConstant | import com.tianhua.javs.TagConstant; | |
全局变量定义 | log = log() | private Logger log = LoggerFactory.getLogger(Service.class); | log,log()均为关键字 |
静态全局变量定义 | static log = log() | private static Logger log = LoggerFactory.getLogger(Service.class); | |
公共全局静态final 变量定义 | publicsf log = log() | public static final Logger log = LoggerFactory.getLogger(Service.class); | publicsf为关键字 |
私有全局静态final变量定义 | privatesf map = map<String,LogBeanBO>() | private static final Map<String,LogBeanBO> map = new HashMap(); | privatesf 为关键字 |
公共全局静态final 常量定义 | publicsf long CODE_INFO_LONG = 2L | public static final Long CODE_INFO_LONG = 2L | |
spring 业务服务引入的属性,自动导包 | autowired docParseService = DocParseService | @Autowirdprivate DocParseService docParseService; | 这里对spring的常见属性做了内置处理,autowired也可以作为javs关键字存在 |
spring 业务服务引入的属性,自动导包 | resource xService = IParseService | @Resource(name = “xService”)private IParseService xService; |
4.2 赋值语句
上面的宏定义部分已经展现了部分赋值语句的场景,这里来看一下对象声明的场景:
场景 | javsScript代码 | java原生代码 | 说明 |
---|---|---|---|
对象初始化 | memberBO = MemberBO() | ||
MemberBO memberBO = new MemberBO(); | 对象初始化相对简单,左边是变量名,右边则是变量类型。 | ||
对象带参数初始化 | memberBOV2 = MemberBO(a,b) | MemberBO memberBOV2 = new MemberBO(a,b); | |
对象属性赋值 | memberBO.memberId = “23232” | memberBO.setMemberId(“23232”); | |
对象通过静态方法初始化 | memberBOV3 = MemberBO.getInstance(a) | MemberBO memberBOV3 = MemberBO.getInstance(a); | |
对象属性set,get | memberBOV2.userName = bo.userName | memberBOV2.setUserName(memberBO.getUserName()); |
4.3 流程判断
现在我们来看一个比较实际的例子,在PlantUML Doc中定义一个Repository接口javsScript脚本
func registUser(bo){
old = userService.checkUser(bo)
ifrettrue(old)
do = bo.convertdo()
count = do.mapper.insert()
return count == 1;
}
java原生代码
@Autowired
private UserService userService;
@Resource
private UserMapper userMapper;
@Override
public boolean registUser(UserBO userBO){
boolean old = userService.checkUser(userBO);
if(old){
return true;
}
UserDO userDo = UserConvert.getInstance().convertdobo(userBO);
int count = UserMapper.insert(userDo);
return count == 1;
}
4.4 循环控制
现在我们简单演示一下循环控制相关的关键字的使用,javs代码段如下:
listb = list<JavsParamBean>()
listb.fore(javsParam) ->{ sout(javsParam) }
listb.for() ->{ sout(geti()) }
java代码段如下:
List<JavsParamBean> listb= new ArrayList<>();
listb.stream().forEach(javsParam ->{
System.out.println(javsParam);
});
for(int i = 0;i < listb.size();i ++){
System.out.println(listb.get(i));
}
4.5 返回与结束
现在我们看一下如果是facade层的方法存在返回ResultDto的场景下如何编写Javs代码。首先看PlantUML Doc文档:javsScript代码:
func registUser(dto){
bo = dto.convertbo()
check = bo.userValidateService.checkUser()
ifretf(check,"E000001")
regist = bo.repository.registUser()
ifrets(regist)
retf("E000002")
}
java原生代码
@Autowired
private UserRepository userRepository;
@Autowired
private UserValidateService userValidateService;
@Override
public ResultDto registUser(UserDTO userDto){
UserBO userBO = UserConvert.getInstance().dto2bo(userDto);
boolean check = userValidateService.checkUser(userBO);
if(check){
return Result.fail("E000001");
}
boolean regist = UserRepository.registUser(userBO);
if(regist){
return Result.success();
}
return Result.fail("E000002");
}
4.6 文档与注释
在JavsScript中也支持编写注释内容,比较特别的是JavsScript可以支持三种形式的注释风格:
-
单行注释
单行注释使用//开头和#开头,与脚本语言的注释和Java原生代码的注释风格保持一致
-
多行注释
多行注释的话,这里使用的是doc()关键字,如: doc(“这是多行注释, 另起一行来说明doc的用法。”)
五、总结
本篇重点讲述了javs语法相关的概念和相关的关键字,并给出部分案例代码说明,需要特别指出的是Javs目前处于起步阶段,所以很多新特性并没有完善,文章披露的内容只是对常见的Java业务代码段进行转译和整理,并形成JavsScript的初步版本,欢迎感兴趣的人加我交流。
原文始发于微信公众号(神帅的架构实战):JavsScript核心语法和特性介绍
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/241471.html