一些在代码中踩过的坑,从来没遇到过的估计已经不是大头兵了。

310 篇文章 6 订阅
298 篇文章 3 订阅

前言

在我们日常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的欢迎评论区留言,踩坑踩的多了,填坑填的多了,慢慢就变成了路~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个在fragment自动轮播图片的示例代码: ```java public class BannerFragment extends Fragment { private ViewPager mViewPager; private List<Integer> mImageList; private int mCurrentPage = 0; private Timer mTimer; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_banner, container, false); mViewPager = (ViewPager) view.findViewById(R.id.view_pager); mImageList = new ArrayList<>(); mImageList.add(R.drawable.image1); mImageList.add(R.drawable.image2); mImageList.add(R.drawable.image3); mViewPager.setAdapter(new BannerPagerAdapter()); startAutoPlay(); return view; } private void startAutoPlay() { mTimer = new Timer(); mTimer.schedule(new TimerTask() { @Override public void run() { getActivity().runOnUiThread(new Runnable() { @Override public void run() { if (mCurrentPage == mImageList.size()) { mCurrentPage = 0; } mViewPager.setCurrentItem(mCurrentPage++, true); } }); } }, 3000, 3000); } private class BannerPagerAdapter extends PagerAdapter { @Override public int getCount() { return mImageList.size(); } @Override public boolean isViewFromObject(View view, Object object) { return view == object; } @Override public Object instantiateItem(ViewGroup container, int position) { ImageView imageView = new ImageView(getActivity()); imageView.setImageResource(mImageList.get(position)); container.addView(imageView); return imageView; } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView((View) object); } } @Override public void onDestroy() { super.onDestroy(); if (mTimer != null) { mTimer.cancel(); } } } ``` 这个示例代码使用了ViewPager和一个Timer来实现自动轮播,每隔3秒钟就会自动切换到下一张图片。PagerAdapter的作用是为ViewPager提供数据源。在onCreateView方法,我们创建了一个BannerPagerAdapter,然后将其设置给ViewPager。最后在onDestroy方法,我们取消了Timer的计时任务,以免内存泄漏。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值