跳至主要內容

C001.22届0727怪

trydofor原创技债大约 4 分钟

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;

不要乱用缩写

temptmp,行业内约定是临时(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类MonthDayOfWeek
  • plusMonths(-4) 使用正向表达 minusMonths(4)
  • startDateendDate的语义,应该和时间轴一致,从小到大
  • 代码的逻辑表达很别扭,未能清晰表达意图:最近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()