敞开掘金成长之旅!这是我参加「掘金日新方案 12 月更文挑战」的第4天,点击查看活动概况
前语
在咱们日常coding中,许多时分咱们都是把接口代码悉数写完再进行测试,在咱们查看代码的时分,常常很有决心查看了多遍今后,觉得自己的代码肯定没啥问题,逻辑很明晰、排版很规整、公共办法抽的很好,很有决心的去调自己的接口,不料动不动一会500、一会400,就差报250~,其实咱们常常的我以为,只是我以为,履行成果会教你做人,事实证明代码不需求只是看着美观的,还是需求看履行成果的,下面我共享一些日常会踩到坑的当地
八大常见bug
Top1 恳求参数为空
常常听到,数据库分明有数据呀,我把sql粘出来再mysql履行也有数据呀,为什么我用mybatis履行sql就没数据呢。
POST恳求,如参数为字符串,恳求到后端接口只能有一个成果,那便是 parameter参数为NULL,影响行数也0,POST恳求需求结合 RequestBody运用,所以POST恳求的入参是放到body里边的。
Top2 StringUtils.isEmpty 判别目标为空
User user = User(new LambdaQueryWrapper<User>()
.eq(User::getUserId, userId)
if (!StringUtils.isEmpty(user))
乍一看没啥问题,代码也没报错,判别user不为空,可是履行的时分往往就会有问题。
目标签名关于一般的属性处理代码很有用,这些代码一般处理字符串,但一般必须遍历目标,因为属性也可能是基本值目标。
Note: If the object is typed to String upfront, prefer hasLength(String) or hasText(String) instead.
Params:
str – the candidate object (possibly a String)
Since:
3.2.1
See Also:
hasLength(String), hasText(String)
public static boolean isEmpty(@Nullable Object str) {
return (str == null || "".equals(str));
}
看源码的解释,一般是处理字符串,判别目标需求重写isEmpty办法。
Top3 sql if 函数判别
if(p.transport_fee =1,p.payable_amount,s.actual_goods_number * p.goods_price ) as payableAmount,
正常情况下假如transport_fee =1 则会取p.payable_amount字段,反之则会取后边的运算成果,乍一看又没啥缺点。
可是 假如这个字段是NULL,那么就BBQ了,mysql if函数判别就不会判别到字段为NULL的数据。所以最好在创建这种需求逻辑判别的字段,设置默认值。
Top4 Mybatis plus lambda 表达式AND 和OR连用
其实咱们sql想要的效果是这样
select
<include refid="baseColumnList"/>
from slaughter_batch_statement
where
enable = 1
and (slaughter_statement_no
=#{dto.slaughterStatementNo
} or slaughter_statement_no is null)
LambdaQueryWrapper 查询过错用法:
SlaughterBatchStatement slaughterBatchStatement = slaughterBatchStatementMapper.selectOne(new LambdaQueryWrapper<SlaughterBatchStatement>().
eq(SlaughterBatchStatement::getSlaughterStatementNo, slaughterStatementNo).or().eq(SlaughterBatchStatement::getBatchNo,slaughterStatementNo));
or().eq()的用法会在sql,and 条件后追加or,而不能 (supplier_bill_statement_no =‘xxxxxxx’ or supplier_bill_statement_no is null) 像这样用括号括起来,括号括起来和不括起来的条件判别彻底不相同。
LambdaQueryWrapper or正确用法:
SlaughterBatchStatement slaughterBatchStatement = slaughterBatchStatementMapper.selectOne(new LambdaQueryWrapper<SlaughterBatchStatement>().
eq(SlaughterBatchStatement::getEnable, 1).and
(item -> item.eq(SlaughterBatchStatement::getSlaughterStatementNo, "xxxxx")
.or().eq(SlaughterBatchStatement::getSlaughterStatementNo, null)));
Top5 BigDecimal 保存两位小数
有时分做金额核算的时分,运用BigDecimal经常会在核算后保存两位小数。
BigDecimal receivableAmountNum = receivableFeeAmountNum.add(slaughterReceivableAmountNum).setScale(2, RoundingMode./HALF_UP/);
你以为光代码设置保存两位小数就行了么,数据库对字段的设置也是需求加两位小数限制的。
假如你不设置,那么保存到库里边的数据依旧是四舍五入后的整数。
Top6 Spring中一个类调用另一个类Null指针
新建一个类,然后在另一个类去调用,创建了一个类,定义了办法。
过错调用方法:这是空指针的罪魁祸首
正确的调用方法:
Spring中直接new 出来的目标无法经过@Autowired 的方法注入到spring的Bean容器里边。
Top7 Bean. copyProperties 引发的问题
在开发的过程中,遇到DTO和VO之间的转换,为了避免写许多的get、set,一般会运用Bean. copyProperties对目标进行赋值转换。
SlaughterBatchStatementResVO slaughterBatchStatementResVO = new SlaughterBatchStatementResVO();
SlaughterBatchStatement slaughterBatchStatement = slaughterBatchStatementMapper.selectOne(new LambdaQueryWrapper<SlaughterBatchStatement>().
eq(SlaughterBatchStatement::getSlaughterStatementNo, slaughterUpdateReqDTO.getSlaughterStatementNo()));
//目标进行copy
BeanCopyUtil.copyProperties(slaughterBatchStatement, slaughterBatchStatementResVO);
BeanCopyUtil.copyProperties 这儿的copy属于浅复制,两个目标都指向同一个指针,所以在对其中一个目标属性进行修改时,因为指针都是相同,那么别的一个目标的属性也会更改,就会呈现一些问题。
当然Bean的copy还有别的一种方法便是深复制,经过new新的目标进行copy
List<ReceivableFeeVO> receivableFeeResList = BeanCopyUtil.copyListProperties(slaughterUpdateReqDTO.getReceivableFees(), ReceivableFeeVO::new);
能够经过承继BeanUtils重写Bean复制的工具类实现
Top8 List.contains Interger 无法匹配
@Data
public class SlaughterBatchExportRequestDTO {
private List<String> slaughterBatchExportType;
}
if (slaughterBatchExportRequestDTO.getSlaughterBatchExportType().contains(2)) {
// ...
}
有时分一不留神就手抖写错了,contains的入参是一个Object类型,所以入参数是任何类型都不报错,可是能不能匹配到又是别的一回事了。
List调集去匹配int类型是否存在,那成果可想罢了永远不会进if判别。
总结
刚作业的时分经常会因为自己的大意,呈现一些比较初级的Bug,现在已经多少混成老油条了,所以去写愈加高级的Bug了,总而言之写代码不光要逻辑思路正确,最要害的我以为还是细心,重复的review自己的代码,而且进行自测,假如还有愈加常见的bug的欢迎谈论区留言,踩坑踩的多了,填坑填的多了,渐渐就变成了路~