此篇为萌新级别hzero 食用指南,记述了我学习过程中遇到的问题和心得,所记述不一定正确,仅供参考~
PS:有些图很模糊,不晓得为什么从word或者Ty里拿出来的画质压缩得这么厉害,见谅。
1.版本号问题,当前应避免hzero企业版的 1.6.1和1.6.4版本服务组件(但是也不一定,有的人会出现的问题,别的人不一定会出现。很玄学,可能后续兼容性会加强吧)
2.前端页面404问题:请查看package.json和hzerorc.json内是否添加了依赖,
然后看其workspace文件下(一般是/dist/packages/,如果是服务模块,看routers.ts中的路径)是否有对应组件,没有则进行install并build,注意每次添加新的依赖后应当保存,然后运行的位置也要注意,比如子模块单独运行的话就不要在父模块那个路径下启动,子模块会无法及时刷新的,尽量在子模块下编译运行,如果想访问父模块(一般就是平台治理这些一级菜单模块),可以单独开一个命令行,在项目的根目录运行就可以(因为子模块运行无法向上访问父模块内容)
还有一种情况,因为平台和租户两个级别下 可以浏览的页面是不一样的,所以也有可能是没有给用户授予权限(去子账户管理->对应账号->编辑),比如我以前遇到的(工作流练习中,未授权的账户无法访问【我的待办事项】,从消息中点击【处理】会显示404.)
3.如果安装了某个组件,服务也启动了,但是前端找不到显示,这个恐怕不是前端的问题,因为h0组件是先基于数据库进行渲染的,如果数据库利用种子文件初始化有问题,在浏览器页面可能会无法显示对应的组件,可以考虑先查看数据库,再决定是否删掉对应库然后重新建立并导入数据。
4.系统页面提示【未安装相关服务或者访问的资源不存在】,可能是后台相关模块未启动,遇到这个问题可以先查看网页控制台/审查元素,->network->请求状态,若为200则ok(当然想必不会是200),40x 这类说不好,还是要排查一下依赖而且可能是其余关联的模块没有成功加载导致的,根据后台报错信息来判断,比如401,就是无权限,看账户是否登录,启动类的相关权限注解是否添加, 资源注解没有的话也是无法读取或访问资源的;
我曾遇到问题:swagger中可以看到对应模块,但是系统工具刷新其权限缺失败,最后服务都起了一遍然后前端也重启了一遍就好了,中间还发现某些模块显示【访问资源不存在】,后来也是刷新权限即可。
50x则是服务问题,先去后端看看是否日志里有报错, 然后重新启动一下,再看看路由id,路径这些易错的地方,如果都没问题就去浏览器内hzero的页面里看看,点击服务管理
5.关于权限刷新问题:
刷新权限有很多种办法,可以去swagger里刷新:admin->RefreshController,然后选择serviceName,点击Try it out,前四个都可以刷一下
也可以用平台刷新:平台管理员->【系统工具】,以及【服务管理】;
以及【缺失权限管理】,可以针对请求失败的特定API进行权限添加。
6.通用调试思路:
报错了,看报错信息,判断是前端还是后端问题,
->前端(前端一般都是直接导入,所以多半是依赖或版本问题)(单个组件问题可以用服务管理和系统工具刷一下,在超级管理员权限下)
->后端,查看模块是否有日志报错,
->若有则根据报错信息和状态码去判断
->若无报错,先去swaggerUI界面查看一下相关服务是否启动了
一般来说后台不报错,逻辑也正确,前端页面不报错,那浏览器控制台的请求码多半会有错误,如果都没有报错那就只能打断点一点一点找了ORZ
具体调试方法仁者见仁智者见智,不多唠叨了。
7.基础服务:
hzero-register:注册中心
hzero-admin:平台治理服务
hzero-gatway:网关服务
hzero-oauth:认证服务
hzero-swaggr:API测试服务(调试必备)
hzero-iam:用户身份服务
Hzero-platform:平台服务
8.利用swagger测试API
响应体Response Body:
{"requestStatus":"PERMISSION_MISMATCH","requestCode":"error.permission.mismatch","requestMessage":"This request mismatch any permission","detailsMessage":"您访问的资源不存在或者未安装相关的服务"}
相应码 为404
解决过程:
查看后台6组件+swagger,没有报错提示,再去看todo服务模块,也没报错。
改了一下控制类的函数名和返回类型,无果
这下好了,还得启动一下界面刷新权限;
刷新(todo和admin)后果然可以访问了,状态码200
Unknown exception, Request: {URI=/v2/orderHeader/byId, method=NullMethod}, User: null
org.springframework.web.bind.MissingPathVariableException: Missing URI template variable 'companyId' for method parameter of type Long
更改请求:@GetMapping("/{companyId}")
这种基本上就是mapper注解里没加{xxx}变量名xxx为要从路径中获取的变量
Unknown exception, Request: {URI=/v2/orderHeader/12, method=NullMethod}, User: null
java.lang.NullPointerException: null
空指针这个问题当时没有解决,调用封装好的API就不会空指针
后来发现空指针是因为我ddd开发不规范,使用@service注释但是没有调用对应的mapper,而是调用repository,(总之,自己写的api 是控制层->repository的接口函数->repository的实现类->mapper接口->sql语句函数,开发要尽量规范)
9.引入前端后,问题变得多了起来,总之尽量先接口跑通后再去修改前端的url。
10.Mapper.xml里面sql语句尽量不要写具体的数据库名字(因为可以通过yaml配置文件确定是哪个库)防止同名惨案
11.关于404,如果是h0页面404,查看数据库和部分组件依赖, 如果是前端url请求404,那么查看报错信息,多半是permission _mismitch之类的权限问题,去系统工具或者swagger里面刷新”一下”权限就好了(怎么可能一次就好呢233)
12.接口测试的话,注意一下请求方法和response body
客户端接口测试的话需要用post
13.前端可以直接传递对象给后端控制层,只不过其对象必然被包含在List数组内传给后端:
后端参数内需添加注解@RequestBody
14.遇到写完api后运行服务,发现swagge里没有对应的api接口,只有其他接口。
看看基础组件是否正常运行,刷新swagger,重启所写的服务类。
这个不是大问题,基本上基础服务都跑起来,多刷几次就好了
15.接口传参报错(状态码200)
org.springframework.http.converter.HttpMessageNotReadableException:
Required request body is missing: public java.util.List<com.hand.Test.domain.entity.OrderAll> com.hand.Test.api.controller.v1.OrderController.queryById(com.hand.Test.domain.entity.OrderAll,io.choerodon.mybatis.pagehelper.domain.PageRequest,int,int)
此处我使用了get方法访问@RequestBody修饰的接口,应使用post方法访问
16.传参报错 (状态码200)
org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Unrecognized token 'zoey': was expecting ('true', 'false' or 'null'); nested exception is com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'zoey': was expecting ('true', 'false' or 'null')
经查询,这种错误一般是由于返回的数据格式和接收返回结果的格式不同,比如我明明规定createdBy是long类型,但是自己却输入了zoey 这种字符串,就会报错。
17.时间类型的报错:
date format error java.text.ParseException: Unparseable date: "2019-08-14T07:22:33.117Z"
仔细看,发现这个date 不符合规范,应该yy-mm-dd:hh:mm:ss(好像是,反正没有那个117z)
接口传个正常的就可以了
18.org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'item_id' in 'class com.hand.Test.domain.entity.OrderAll'
这个就是字段问题,仔细查看set/get方法内的字段是否正确, 以及实体类内的,sql语句中的,这个问题并不复杂,主要是粗心导致。
19.当控制层返回参数以及SQL语句正常时 却发现swagger接口查询后的responsebody内缺少自己想要的字段,此时应该查看对应实体类,看看是不是少了什么字段
20.Error attempting to get column 'company_name' from result set.
查看数据库和实体类,二者的字段类型不一致
21.我算是发现了,几乎每次新写一个api,用swagger测试基本都是404未授权,建议去动态刷新里一个个都把 todo服务刷新一遍
22.java.lang.IllegalStateException: Type handler was null on parameter mapping for property '__frch_soHeaderId_0'. It was either not specified and/or could not be found for the javaType (com.hand.Test.domain.entity.OrderHeader) : jdbcType (INTEGER) combination.]
这个错是映射问题,仔细查看一下result映射和实体类的数据类型是否相符。
23.h0后端问题:遍历查询要注意判空,api应当添加校验
写导入客户端的时候,点击导入报了个错:
发现idea后台报错了,说没有找到himp_import数据库, 去数据库一看,果然没有,通过种子文件或者从别的库导入即可,注意,用种子文件会覆盖相关的import原表.
另外:
一直处于数据校验状态,有人遇到过,他的是由于版本问题,建议改为1.6.3,不幸的是,我也是,换了版本就可以了。
还有:
空指针异常:
其在importServiceImpl,也就是导入的实现类中,可能是由于导入的repository对象没有加注解,所以找不到,另外,从逻辑上讲,service应当调用repository的对象而不是mapper,其实如果你用private XXXMapper xxx也通常会提示无法autowire,没有bean。
加注解后再导入有新的错误:
我用的是猪齿鱼的插入函数,可能是其引用了sql解析工具jsqlparser.jar,是工具包抛出的异常,既然是封装的sql,所以不是sql语句问题,可能是我数据源引用错误或者字段问题:
然后用debug打断点,
注意,执行到4的时候才能看出3的值,例如此刻执行到4,就会显示orderline为空
另外,点1执行当前页面运行语句的下一行语句,2为当前函数的深层调用,会跳出本类页面。
言归正传,我debug发现接收后对象都是空,是我接口平台写的【维护模板列】有问题,应当和实体类对应,其字段要写成驼峰的形式才可以。
23.如果报错空指针空方法,重点在于空,可能是顺着路径找不到对象,属于对象空,或者是路径不对,也找不到对象,这种我理解为方法空。最近一次遇到的空指针是我引用了某个类的mapper,但是没加@Autowire注解,导致找不到bean(有的时候它是会提示缺少bean的,有的时候就没什么有用的报错信息,孤零零一个空指针,就很难受了)
24.log打印输出信息是个好习惯,偷懒写法:给类上加@Sl4j注解( 有两个,用这个:import lombok.extern.slf4j.Slf4j ),然后直接log.xxx即可
25工作流审批,审批人点 消息 -> 处理 ,会遇到404,这是由于审批人这个账户没有分配租户管理员权限,没有租户管理员就没有 【我的待办事项】,自然就无法审批处理了。
26.这次的问题依然是工作流:
我需要:流程审批通过后需要修改订单头状态为【已审批】,拒绝操作后修改订单状态为【已拒绝】,通过节点事件触发。
现在的问题是:工作流中审批人审批后无法触发【服务节点】
甚至都没进入工作流的控制类:
主服务打了断点,但是压根儿就没进去这个控制类;
问题在哪呢?我有理由怀疑我规定的这个 【工作流事件】根本没执行,于是去流程监控里看了一眼,果然:停在这里了
也不能说没有执行,只能说,好像是卡在这里了,流程状态【异常暂挂】
Workflow内的报错信息如上
然后呢,在审批人未提交审批意见时,workflow有报错但是没有影响运行(大概):
提交后:
可能是因为我没添加流程变量,
运行:
如果测接口时显示【PERMISSION_NOT_PASS】就去平台的【缺失权限管理】里添加权限即可,主要是添加【客户端授权】等
正常运行:
Swagger测试有问题,但是用平台的发布模拟是可以的,很奇怪
27.复测批量删除
关于批量操作可以有两种,一种是把遍历放在sql里,一种是放在service里,此处为service里;
测试数据:
展开下方可查看 测试用例
![【初次使用h0遇到的一些问题】第26张](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![【初次使用h0遇到的一些问题】第27张](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
[
{
"companyId": 1007,
"createdBy": 2,
"customerId": 100,
"itemId": 78,
"lineList": [
{
"_innerMap": {},
"addition1": "无",
"addition2": "string",
"addition3": "string",
"addition4": "string",
"addition5": "string",
"createdBy": 2,
"creationDate": "2021-08-13 15:03:48",
"description": "备注:广受猫咪好评的猫罐头",
"itemId": 78,
"lastUpdateDate": "2021-08-13 15:03:48",
"lastUpdatedBy": 0,
"lineNumber": "string",
"objectVersionNumber": 0,
"orderQuantity": 0,
"orderQuantityUom": "string",
"soHeaderId": 100,
"soLineId": 35,
"unitSellingPrice": 0
},
{
"_innerMap": {},
"addition1": "猫罐头",
"addition2": "string",
"addition3": "string",
"addition4": "string",
"addition5": "string",
"createdBy": 2,
"creationDate": "2021-08-13 15:03:48",
"description": "备注:广受猫咪好评的猫罐头",
"itemId": 78,
"lastUpdateDate": "2021-08-13 15:03:48",
"lastUpdatedBy": 0,
"lineNumber": "string",
"objectVersionNumber": 0,
"orderQuantity": 0,
"orderQuantityUom": "string",
"soHeaderId": 100,
"soLineId": 36,
"unitSellingPrice": 0
}
],
"orderDate": "2021-08-13 15:03:48",
"orderHeader": {
"_innerMap": {},
"companyId": 1007,
"createdBy": 2,
"creationDate": "2021-08-13 15:03:48",
"customerId": 100,
"lastUpdateDate": "2021-08-13 15:03:48",
"lastUpdatedBy": 0,
"objectVersionNumber": 0,
"orderDate": "2021-08-13 15:03:48",
"orderNumber": "NEW",
"orderStatus": "NEW",
"soHeaderId": 100
},
"orderNumber": "100",
"orderStatus": "NEW",
"price": 110,
"soHeaderId": 100,
"soLineId": 36
},
{
"companyId": 1007,
"createdBy": 2,
"customerId": 100,
"itemId": 78,
"lineList": [
{
"_innerMap": {},
"addition1": "无",
"addition2": "string",
"addition3": "string",
"addition4": "string",
"addition5": "string",
"createdBy": 2,
"creationDate": "2021-08-13 15:03:48",
"description": "备注:广受猫咪好评的猫罐头",
"itemId": 78,
"lastUpdateDate": "2021-08-13 15:03:48",
"lastUpdatedBy": 0,
"lineNumber": "string",
"objectVersionNumber": 0,
"orderQuantity": 0,
"orderQuantityUom": "string",
"soHeaderId": 101,
"soLineId": 37,
"unitSellingPrice": 0
}
],
"orderDate": "2021-08-13 15:03:48",
"orderHeader": {
"_innerMap": {},
"companyId": 1007,
"createdBy": 2,
"creationDate": "2021-08-13 15:03:48",
"customerId": 100,
"lastUpdateDate": "2021-08-13 15:03:48",
"lastUpdatedBy": 0,
"objectVersionNumber": 0,
"orderDate": "2021-08-13 15:03:48",
"orderNumber": "NEW",
"orderStatus": "NEW",
"soHeaderId": 101
},
"orderNumber": "100",
"orderStatus": "NEW",
"price": 110,
"soHeaderId": 101,
"soLineId": 37
}
]
中间遇到了一个小问题, 输入订单状态无论是NEW还是REJECTED,都会抛出异常,后来发现是逻辑问题,如下图,应当使用逻辑与而不是逻辑或进行判断。
头表与行表: 执行后删除了订单头id 100和101两个和对应的行表
28.编码规则与保存
保存分为插入和更新两部分,其中插入时希望订单编号(OrderNumber)为编码规则生成 ,
编码规则代码:HZERO.xxxxx.ORDER.NUMBER
(租户管理员->系统管理->编码规则->编码规则)
SO+YYYYMMDD+6位流水号
根据文档中描述:
关键代码如下:
String code = codeRuleBuilder.generateCode(CodeConstants.Level.TENANT, 0L, "HZERO.xxxxx.ORDER.NUMBER", CodeConstants.CodeRuleLevelCode.CUSTOM, "DEMO", map);
至于这些参数对应什么,可以看下图:
TENANT(tenant为租户),
RuleCode: HZERO.xxxxx.ORDER.NUMBER:(规则代码)
CUSTOM: leavelCode (层级),这里CUSTOM代表自定义参数
“DEMO” : leavel values 层级值
Map: 一个S-S的map变量
平台设置如下:
其实一开始流水号想用UUID的,但是UUID没有6位,所以只能用序列了,序列是自增的(每调用一次加1),也很好用;
相关代码:
这样插入so_header_id 为102 的数据,且主要目标OrderNumber 符合 编码命名 要求。
最后:要注意代码规范,比如url路径不要用驼峰:PostMapping(value=”/delete/page-mapping/batch”)