C001.22届0727怪
C001.22届0727怪
1.ImptUspsFedexBillsServiceImpl.java 266-274
express-home 2022-07-27 20:11:22
//logger.info("ImptUspsFedexBillsService.importUspsFedexBills, deal data");
BigDecimal weightRaw = DecimalUtil.object(row.get(18), BigDecimal.ZERO); //包裹实量
BigDecimal weightIso = DecimalUtil.object(row.get(20), BigDecimal.ZERO); //计费重量
if ((weightIso.doubleValue() > 50.00 && weightIso.doubleValue() < 51.00)
|| (weightIso.doubleValue() > 100.00 && weightIso.doubleValue() < 101.00)
|| (weightIso.doubleValue() > 200.00 && weightIso.doubleValue() < 201.00)
|| (weightIso.doubleValue() > 300.00 && weightIso.doubleValue() < 301.00)
|| (weightIso.doubleValue() > 500.00 && weightIso.doubleValue() < 501.00)) {
weightIso = weightIso.setScale(0, BigDecimal.ROUND_UP);
}
魔法数字,可读性差 get(18)
row.get(18)
可读性极差,应定义变量名,或使用excel的AZ坐标体系。
硬核逻辑,硬编码
50.00 .. 51.00
的逻辑太硬核了,猜测其意图是个位的数字,在(0,1)
区间 ROUND_UP。
数值类型乱用
采用BigDecimal是为了,避免浮点类型精度
和比较
的问题。互转时必须统一界面。
2.DashboardController.java 30-33
tail-backend 2022-07-28 08:56:33
@Operation(summary = "获取5周提单变化趋势图")
@PostMapping(value = "/dashboard/out/line-chart-weeks.json")
public R<?> getLineChartWeeks(){
return R.okData(dashboardService.getLineChartWeeks());
}
并且作为对外接口,必须明确类型
R<?>
违反 A01H.方法签名宽进严出
推荐
- 以便Swagger可以自动生成Api文档。
- 若是有反序列化需求,则都需要使用具体实现类,以保证数据特征。
3.DashboardController.java 57-66
tail-backend 2022-07-28 10:28:01
@Operation(summary = "提单导出")
@PostMapping(value = "/dashboard/out/export.json")
@DoubleKill
public void export(@RequestBody DashboardService.QueryDate queryDate, HttpServletResponse response) throws IOException {
try {
dashboardService.export(queryDate);
} catch (Exception e) {
response.reset();
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
R<Object> data = R.ng();
response.getWriter().println(JSON.toJSONString(data));
}
}
避免破坏异常的统一处理
不要catch已经统一处理的异常。
此外内类可以静态引入,以缩短代码行长度。
疑似DoubleKill用错
@DoubleKill
以lock形式限制并发 ,此处应该是@Debounce
4.UnloadingController.java 83-84
tail-backend 2022-07-28 10:48:46
WingsUserDetails details = Objects.requireNonNull(SecurityContextUtil.getUserDetails());
requireNonNull 有点丑陋
修改SecurityContextUtil默认@NotNull
,同时也提供@Nullable
方法。
5.ExcelTemplateEnum.java 1-1
tail-backend 2022-07-28 12:29:23
package com.jiayu.tail.common.enums.temp;
不要乱用缩写
temp
和tmp
,行业内约定是临时(Temporary),而模板(Template或Templet)通常缩写为tmpl
6.CustomerServiceImpl.java 66-67
tail-backend 2022-07-28 12:34:54
@Setter(onMethod_ = {@Autowired})
private DSLContext dslContext;
使用Dao代替DSL注入
在WingsBoot中,Dao已经封装了常用的jooq及database方法。
7.CustomerServiceImpl.java 164-168
tail-backend 2022-07-28 13:41:59
if (stringRecord1 != null) {
return true;
} else {
return false;
}
蹩脚的if-true-return-true
Idea会提示这种蹩脚代码,修复为 return stringRecord1 != null
8.DashboardServiceImpl.java 108-117
tail-backend 2022-07-28 13:59:22
LocalDate startDate = LocalDate.now();
startDate= TimeUtil.getZoneIdLocalTime(startDate.atStartOfDay(), ZoneId.of("Asia/Shanghai")).toLocalDate();
LocalDate endDate;
int monthNow=startDate.getMonthValue();
if(monthNow<5)
endDate=startDate.with(TemporalAdjusters.firstDayOfYear());
else {
//获取最前一月的的第一天日期
endDate = startDate.plusMonths(-4).withDayOfMonth(1);
}
日期计算不是加减乘除
新手常见误区,以自己习惯的四则运算的数学知识,来计算日期,甚至时区。 比如,+年+月+日,不满足加法交换律。如,+3M+1D
!= +1D+3M
Asia/Shanghai
在WingsBoot中,凡是指定时区的代码,几乎都是错的monthNow
月份和星期的比较,推荐用其Enum类Month
和DayOfWeek
plusMonths(-4)
使用正向表达minusMonths(4)
startDate
和endDate
的语义,应该和时间轴一致,从小到大- 代码的逻辑表达很别扭,未能清晰表达意图:最近4个月,但不跨年
- 代码并未格式化
修改意见,参考以下比较不错的同意图代码。
final LocalDate endDate = LocalDate.now();
LocalDate startDate = endDate
.minusWeeks(4)
.with(TemporalAdjusters.previousOrSame(DayOfWeek.SUNDAY));
final LocalDate firstDayOfYear = endDate.with(TemporalAdjusters.firstDayOfYear());
if (startDate.isBefore(firstDayOfYear)) {
startDate = firstDayOfYear;
}
9.DashboardServiceImpl.java 123-124
tail-backend 2022-07-28 14:47:33
mt.CheckinTime.between(endDate.atStartOfDay().minusHours(8),
startDate.atTime(23, 59, 59, 999999999).minusHours(8))
.and(mt.Status.ge(2340250))
当天的开始和结束
已知,mysql的between
是两端包含(inclusive)的闭闭区间。
minusHours(8)
手动调整时区,必然业务模型错误。999999999
,用atStartOfDay().plusDays(1).minusNanos(1)- 此处
between
建议替换为明确的>=
和<
,以简化闭区间边界计算 2340250
为魔法数字,使用对应的Enum类
10.DashboardServiceImpl.java 129-145
tail-backend 2022-07-28 15:09:07
Map<Integer,LineChartDetail> detailMap=new HashMap<>();
LineChart lineChart=new LineChart();
for(int i=monthNow,j=5;i>0 && j>0;i--,j--){
detailMap.put(i,new LineChartDetail(i,0,0,0));
}
results.forEach(record->{
Integer monthCnt = record.value1().plusHours(8).getMonthValue();
LineChartDetail detail = detailMap.get(monthCnt);
// 设置detail代码,省略...
detailMap.put(monthCnt,detail);
});
Java集合框架不熟练
- Map的get-check-set,采用computeIfAbsent代替
- 非stream计算,以for-loop循环,代替forEach-lambda
- Iterable应该以for-in代替for-i
11.LadingServiceImpl.java 330-336
tail-backend 2022-07-28 15:45:03
public boolean needConfirm(ScanStatus scanStatus, ScanStatus scanStatusConfirm) {
if (scanStatus != null)
if (scanStatus == ScanStatus.MATCHED)
return false;
else
return scanStatus != scanStatusConfirm;
return false;
}
短if必须一行或括号
- 短
if
要么在一行,要么在花括号中 - 此处逻辑可以简化,但目前可读性优先
12.LadingServiceImpl.java 460-496
tail-backend 2022-07-28 16:01:34
switch (e.getEvent()) {
case "拆柜":
ladingVo.setDismantle(e.getSupplier());
break;
case "查验":
ladingVo.setIsExamined(true);
break;
}
强类型代替魔法
- 行业黑话,要么Const要么Enum,不可以字符串
- 大段的switch-case,可使用if-else代替
13.TruckOrderServiceImpl.java 237-242
tail-backend 2022-07-28 16:16:14
try (InputStream in = new FileInputStream(owtTruckOrder.getBolFileC());
ByteArrayOutputStream out = new ByteArrayOutputStream()) {
byte[] buffer = new byte[1024 * 4];
int n = 0;
while ((n = in.read(buffer)) != -1) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
IO工具不熟练
在业务层面,无需考虑buff复制的情况,所有IO操作都要Util
- spring StreamUtils.copyToByteArray()
- apache IOUtils.toByteArray()