java后端接口开发小技巧

在后端开发中,有一些技巧能使我们的开发更加简洁优雅,可扩展性更强,减少代码之间的耦合性。

前端按钮后端控制

在之前的开发中,前端需要根据不同的状态来显示按钮的显示隐藏,这需要前后端来协商统一,但是现实情况很多是随着业务的开发扩展以及后期测试的bug修复这些状态逻辑会相应的做出修改和删减,很有可能前后端没有进行逻辑的同步导致一些差错和不愉快,所以需要后端来避免这些不必要的情况。
//1、返回vo中声明一个操作控制类,@Getter可以不声明变量把这个变量注入到返回类里
    @Getter
    public AllowOperation getAllowOperationVO() {
        //设置订单的可操作状态
        return new AllowOperation(this);
    }
 
//2、控制类中根据业务对不同显示按钮返回布尔值给前端,初始化这个类时可以传入不同的返回值来进行复用
@Data
public class AllowOperation implements Serializable {
 
    private static final long serialVersionUID = -5109440403955543227L;
 
    @ApiModelProperty(value = "可以取消")
    private Boolean cancel = false;
 
    @ApiModelProperty(value = "可以支付")
    private Boolean pay = false;
 
    @ApiModelProperty(value = "可以发货")
    private Boolean ship = false;
 
    /**
     * 根据各种状态构建对象
     *
     * @param order
     */
    public AllowOperation(Order order) {
 
        //获取订单类型
        String status = order.getOrderStatus();
        String payStatus = order.getPayStatus();
        //编辑订单价格 未付款并且是新订单
        if (payStatus.equals(PayStatusEnum.UNPAID.name()) && status.equals(OrderStatusEnum.UNPAID.name())) {
            this.editPrice = true;
        }
        //新订单,允许支付
        this.pay = status.equals(OrderStatusEnum.UNPAID.name()) && payStatus.equals(PayStatusEnum.UNPAID.name());
 
        ........
 
    }
}

查询列表接口入参统一封装

开发中涉及大量的列表查询,需要做分页、条件查询等,这些操作具有高度的相似性,所以需要进行封装省时省力
//1、列表入参dto继承分页父类,实现条件查询
public class OrderSearchParams extends PageVO {
 
    @ApiModelProperty(value = "关键字")
    private String keywords;
 
public <T> QueryWrapper<T> queryWrapper() {
        QueryWrapper<T> wrapper = new QueryWrapper<>();
 
        //关键字查询
        if (StrUtil.isNotEmpty(keywords)) {
            wrapper.like("o.sn", keywords);
            wrapper.like("oi.goods_name", keywords);
        }
        //按卖家查询
        wrapper.eq(StrUtil.equals(UserContext.getCurrentUser().getRole().name(), UserEnums.STORE.name()), "o.store_id", UserContext.getCurrentUser().getStoreId());
    }
}
 
//2、分页父类实现分页功能
@Data
public class PageVO implements Serializable {
 
    private static final long serialVersionUID = 1L;
 
    @ApiModelProperty(value = "页号")
    private Integer pageNumber = 1;
 
    @ApiModelProperty(value = "页面大小")
    private Integer pageSize = 10;
 
    @ApiModelProperty(value = "排序字段")
    private String sort;
 
    @ApiModelProperty(value = "排序方式 asc/desc")
    private String order;
 
    @ApiModelProperty(value = "需要驼峰转换蛇形", notes = "一般不做处理,如果数据库中就是蛇形,则这块需要处理。")
    private Boolean notConvert;
 
    public Integer getMongoPageNumber() {
        int i = pageNumber - 1;
        if (i < 0) {
            return pageNumber;
        } else {
            return i;
        }
    }
 
    public String getSort() {
        if (!StringUtils.isEmpty(sort)) {
            if (notConvert == null || Boolean.FALSE.equals(notConvert)) {
                return StringUtils.camel2Underline(sort);
            } else {
                return sort;
            }
        }
        return sort;
    }
 
}
 
//3、业务代码查询
public IPage<OrderSimpleVO> queryByParams(OrderSearchParams orderSearchParams) {
        QueryWrapper queryWrapper = orderSearchParams.queryWrapper();
        return this.baseMapper.queryByParams(PageUtil.initPage(orderSearchParams), queryWrapper);
    }

系统、业务日志存储

对不同业务进行日志的记录是开发中很常见的事情,包括系统日志、异常日志等,利用spring的aop切面特性我们可以很好的处理以及后期进行日常维护
//1、接口申明需要传入的变量
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AfterSaleLogPoint {
 
    /**
     * 日志名称
     *
     * @return
     */
    String description();
 
    /**
     * 售后SN
     *
     * @return
     */
    String sn();
}
 
//2、具体的实现类
@Slf4j
@Aspect
@Component
public class AfterSaleOperationLogAspect {
 
    @Autowired
    private AfterSaleLogService afterSaleLogService;
 
    @AfterReturning(returning = "rvt", pointcut = "@annotation(com.haifansafe.common.aspect.annotation.AfterSaleLogPoint)") //AfterReturning:切点的执行顺序时间,pointcut:切点的位置
    public void afterReturning(JoinPoint joinPoint, Object rvt) {
        try {
            AuthUser auth = UserContext.getCurrentUser();
            //日志对象拼接
            //默认操作人员,系统操作
            String userName = "系统操作", id = "-1", role = UserEnums.SYSTEM.getRole();
            if (auth != null) {
                //日志对象拼接
                userName = UserContext.getCurrentUser().getUsername();
                id = UserContext.getCurrentUser().getId();
                role = UserContext.getCurrentUser().getRole().getRole();
            }
            Map<String, String> afterSaleLogPoints = spelFormat(joinPoint, rvt);
            AfterSaleLog afterSaleLog = new AfterSaleLog(afterSaleLogPoints.get("sn"), id, role, userName, afterSaleLogPoints.get("description"));
            //调用线程保存
            ThreadPoolUtil.getPool().execute(new SaveAfterSaleLogThread(afterSaleLog, afterSaleLogService));
        } catch (Exception e) {
            log.error("售后日志错误",e);
        }
    }
}
 
//3、在方法处声明
 
    @AfterSaleLogPoint(sn = "#orderItemSn", description = "'售后申请:售后编号['+#orderItemSn+']'")
    public void saveAfterSale(String orderItemSn) {
         
        .......
 
    }

业务代码的抽取和解耦

当某项业务实现很复杂,需要大量逻辑代码时,仅仅靠注释很难阐明流程和逻辑。另外在一个类里进行大量代码的堆砌会使该类不断的臃肿,后期对该类的维护会很麻烦(之前一个类五千多行代码,我光编辑就会很卡,上传git也很慢,体验极差),所以需要进行代码解耦。
//1、用集合类对业务进行详细拆分
@Autowired
 private List<CartRenderStep> cartRenderSteps;
//按照计划进行渲染
        for (int index : cartRender) {
            try {
                cartRenderSteps.get(index).render(tradeDTO);
            } catch (Exception e) {
                log.error("购物车{}渲染异常:", cartRenderSteps.get(index).getClass(), e);
            }
        }
 
//2、具体业务实现类,还用@Order可以指定执行顺序
@Order(5)
@Service
public class CartPriceRender implements CartRenderStep {
 
        .........
 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值