【项目实战 Day9】springboot + vue 苍穹外卖系统(用户端订单模块 + 商家端订单管理模块 完结)

一、用户端订单模块

1、查询历史订单 - GET接口

(1)需求分析

(2)代码开发

【1】controller层

java 复制代码
    /**
     * 历史订单查询
     * @param page
     * @param pageSize
     * @param status 订单状态 1待付款 2待接单 3已接单 4派送中 5已完成 6已取消
     * @return
     */
    @GetMapping("/historyOrders")
    @ApiOperation("历史订单查询")
    public Result<PageResult> page(int page,int pageSize,Integer status){
        PageResult pageResult = orderService.pageQueryHistory(page,pageSize,status);
        return Result.success(pageResult);
    }

【2】service层

  • 使用分页插件PageHelper设置分页参数
  • 创建OrdersPageQueryDTO,并绑定相应参数(userId、status),传入mapper层进行条件分页查询,获得相应的所有订单信息
  • 判断返回的订单信息是否为空,若不为空,遍历每一个订单信息order
    • 通过订单id在ordersDetailMapper中获取对应订单明细列表
    • 创建OrderVO,并将订单信息order赋值给OrderVO,再加上之前获取的对应订单明细列表
    • 接着将每一个封装好的OrderVO加入list列表
  • 最后返回PageResult(page.getTotal()订单总数,list)
java 复制代码
    /**
     * 订单状态 1待付款 2待接单 3已接单 4派送中 5已完成 6已取消
     * @param pageNum
     * @param pageSize
     * @param status
     * @return
     */
    public PageResult pageQueryHistory(int pageNum, int pageSize, Integer status) {
        //1.设置分页参数,使用分页插件开始分页
        PageHelper.startPage(pageNum,pageSize);

        //条件分页查询
        OrdersPageQueryDTO ordersPageQueryDTO = new OrdersPageQueryDTO();
        ordersPageQueryDTO.setUserId(BaseContext.getCurrentId());
        ordersPageQueryDTO.setStatus(status);
        //返回分页结果(相当于返回所有历史订单数据)
        Page<Orders> page = orderMapper.pageQuery(ordersPageQueryDTO);

        //创建OrderVO列表用于封装返回数据
        List<OrderVO> list = new ArrayList<>();

        if(page != null && page.getTotal() > 0){
            //遍历分页中每一个订单对象
            for (Orders orders : page) {
                //获取当前订单id
                Long orderId = orders.getId();
                //用订单id去获取其对应的订单明细
                List<OrderDetail> dlist = orderDetailMapper.getByOrderId(orderId);

                //封装到VO
                //OrderVO继承了Orders中的所有数据(在OrderVO中存在extend Orders),因此可以将orders赋值给ordervo
                OrderVO orderVO = new OrderVO();
                BeanUtils.copyProperties(orders,orderVO);
                orderVO.setOrderDetailList(dlist);

                //封装好的VO加入结果列表中
                list.add(orderVO);
            }
        }

        return new PageResult(page.getTotal(),list);
    }

【3】mapper层

1)OrderMapper

java 复制代码
    /**
     * 订单分页查询
     * @param ordersPageQueryDTO
     * @return
     */
    Page<Orders> pageQuery(OrdersPageQueryDTO ordersPageQueryDTO);

2)OrderDetailMapper

java 复制代码
    /**
     * 根据订单id查询对应订单明细
     * @param orderId
     * @return
     */
    @Select("select * from sky_take_out.order_detail where order_id = #{orderId}")
    List<OrderDetail> getByOrderId(Long orderId);

【4】mybatis层

1)OrderMapper

java 复制代码
    <select id="pageQuery" resultType="com.sky.entity.Orders">
        select * from sky_take_out.orders
        <where>
            <if test="status != null">and status = #{status}</if>
            <if test="userId != null">and user_id = #{userId}</if>
            <if test="number != null and number!=''">
                and number like concat('%',#{number},'%')
            </if>
            <if test="phone != null and phone!=''">
                and phone like concat('%',#{phone},'%')
            </if>
            <if test="beginTime != null">
                and order_time &gt;= #{beginTime}
            </if>
            <if test="endTime != null">
                and order_time &lt;= #{endTime}
            </if>
        </where>
        order by order_time desc
    </select>

2、查询订单详情 - GET接口

(1)需求分析

(2)代码开发

【1】controller层

java 复制代码
    /**
     * 查询订单详情
     * @param id
     * @return
     */
    @GetMapping("/orderDetail/{id}")
    @ApiOperation("查询订单详情")
    public Result<OrderVO> details(@PathVariable Long id){
        OrderVO orderVO = orderService.getById(id);
        return Result.success(orderVO);
    }

【2】service层

java 复制代码
    /**
     * 查询订单详情
     * @param id
     * @return
     */
    public OrderVO getById(Long id) {
        OrderVO orderVO = new OrderVO();

        Orders order = orderMapper.getById(id);
        BeanUtils.copyProperties(order,orderVO);

        List<OrderDetail> list = orderDetailMapper.getByOrderId(id);
        orderVO.setOrderDetailList(list);

        return orderVO;
    }

【3】mapper层

java 复制代码
    /**
     * 根据订单id查询订单
     * @param id
     * @return
     */
    @Select("select * from sky_take_out.orders where id = #{id}")
    Orders getById(Long id);

3、取消订单 - PUT接口

(1)需求分析

(2)代码开发

【1】controller层

java 复制代码
    /**
     * 取消订单
     * @param id
     * @return
     */
    @PutMapping("/cancel/{id}")
    @ApiOperation("取消订单")
    public Result cancel(@PathVariable Long id) throws Exception {
        orderService.cancel(id);
        return Result.success();
    }

【2】service层

取消订单的实质是修改订单信息(订单状态、取消原因、取消时间)

  • 判断订单是否存在
  • 判断订单状态是否可以取消【3已接单、4派送中、5已完成、6已取消】不可以取消
  • 如果订单处于待接单状态取消,需要进行退款并更新支付状态
  • 最后更新订单状态、取消原因、取消时间(用OrderMapper的update方法)
java 复制代码
    /**
     * 取消订单
     * @param id
     */
    public void cancel(Long id) throws Exception {

        //1.校验订单是否存在
        Orders od = orderMapper.getById(id);

        if(od == null){
            throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
        }
         //2.订单若为【3已接单、4派送中、5已完成、6已取消】则不能取消
        if(od.getStatus() > 2){
            throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }

        //3.若订单处于待接单状态下取消,需要进行退款
        if(od.getStatus().equals(Orders.TO_BE_CONFIRMED)){
//            //调用微信支付退款接口
//            weChatPayUtil.refund(
//                    od.getNumber(), //商户订单号
//                    od.getNumber(), //商户退款单号
//                    new BigDecimal(0.01),//退款金额,单位 元
//                    new BigDecimal(0.01));//原订单金额
            od.setPayStatus(Orders.REFUND);
        }

        //4.更新订单状态、取消原因、取消时间
        od.setStatus(Orders.CANCELLED);
        od.setCancelReason("用户取消");
        od.setCancelTime(LocalDateTime.now());
        orderMapper.update(od);
    }

4、再来一单 - POST接口

(1)需求分析

(2)代码开发

【1】controller层

java 复制代码
    /**
     * 再来一单
     * @param id
     * @return
     */
    @PostMapping("/repetition/{id}")
    @ApiOperation("再来一单")
    public Result repetition(@PathVariable Long id){
        orderService.repetition(id);
        return Result.success();
    }

【2】service层

再来一单的业务逻辑就是把订单商品全部重新插入购物车中

  • 通过订单id获取订单详情列表
  • 循环将【订单中的每一个商品】赋值到【单个购物车记录对象】中
  • 循环将【单个购物车记录对象】加入购物车列表中
  • 把购物车列表通过shoppingCartMapper的insertBatch批量插入进购物车表
java 复制代码
    /**
     * 再来一单
     * @param id
     */
    public void repetition(Long id) {
        //再来一单逻辑就是原订单商品重新加入购物车

        Long currentId = BaseContext.getCurrentId();

        //1.获取该订单的订单详情列表
        List<OrderDetail> orderDetailList = orderDetailMapper.getByOrderId(id);

        
        List<ShoppingCart> shoppingCartList = new ArrayList<>();

        //2.生成若干购物车商品对象,并加入购物车列表
        for (OrderDetail orderDetail : orderDetailList) {

            ShoppingCart shoppingCart = new ShoppingCart();
            // 将订单详情中的菜品信息重新复制到购物车对象中,"id" 参数表示忽略复制 id 字段(因为购物车需要生成新的id)
            BeanUtils.copyProperties(orderDetail,shoppingCart,"id");

            shoppingCart.setUserId(currentId);
            shoppingCart.setCreateTime(LocalDateTime.now());

            shoppingCartList.add(shoppingCart);
        }

        //第2部分等价写法:
//        // 将订单详情对象转换为购物车对象
//        List<ShoppingCart> shoppingCartList = orderDetailList.stream().map(x -> {
//            ShoppingCart shoppingCart = new ShoppingCart();
//
//            // 将原订单详情里面的菜品信息重新复制到购物车对象中
//            BeanUtils.copyProperties(x, shoppingCart, "id");
//            shoppingCart.setUserId(userId);
//            shoppingCart.setCreateTime(LocalDateTime.now());
//
//            return shoppingCart;
//        }).collect(Collectors.toList());

        //3.将购物车列表中的内容批量插入购物车表
        shoppingCartMapper.insertBatch(shoppingCartList);
    }

【3】mapper层

1)ShoppingCartMapper

java 复制代码
    /**
     * 批量插入购物车表
     * @param shoppingCartList
     */
    void insertBatch(List<ShoppingCart> shoppingCartList);

【4】mybatis层

1)ShoppingCartMapper

XML 复制代码
    <insert id="insertBatch" parameterType="list">
        insert into sky_take_out.shopping_cart(name, image, user_id, dish_id, setmeal_id, dish_flavor, amount, create_time)
        VALUES
        <foreach collection="shoppingCartList" item="sc" separator=",">
            (#{sc.name},#{sc.image},#{sc.userId},#{sc.dishId},#{sc.setmealId},#{sc.dishFlavor},#{sc.amount},#{sc.createTime})
        </foreach>
    </insert>

二、商家端订单管理模块

1、订单搜索 - GET接口

(1)需求分析

  • 通过需求分析中【返回数据】我们可以知道,要返回的结果为【Orders】+【OrderVO中的orderDishes字符串】
  • 而且已知OrderVO中已经继承了Orders的数据,所以只需要把Orders的数据赋值给OrderVO,再加上订单包含菜品的字符串即可
  • 因此我们Service层需要封装好这部分返回数据

(2)代码开发

【1】controller层

java 复制代码
    /**
     * 订单搜索
     * @param ordersPageQueryDTO
     * @return
     */
    @GetMapping("/conditionSearch")
    @ApiOperation("订单搜索")
    public Result<PageResult> conditionSearch(OrdersPageQueryDTO ordersPageQueryDTO){
        PageResult pageResult = orderService.conditionSearch(ordersPageQueryDTO);
        return Result.success(pageResult);
    }

【2】service层

这里处理逻辑其实就是分页查询的常规思路,只是将【打包数据】和【把订单菜品列表转换为字符串】两部分提取成两个函数

java 复制代码
    /**
     * 订单搜索
     * @param ordersPageQueryDTO
     * @return
     */
    public PageResult conditionSearch(OrdersPageQueryDTO ordersPageQueryDTO) {
        //开始分页,查询分页参数
        PageHelper.startPage(ordersPageQueryDTO.getPage(),ordersPageQueryDTO.getPageSize());

        //Page<Orders> 对象包含了分页查询的完整结果
        Page<Orders> page = orderMapper.pageQuery(ordersPageQueryDTO);

        //把order + ordervo数据打包成list列表
        List<OrderVO> orderVOList = getOrderVOList(page);

        return new PageResult(page.getTotal(),orderVOList);
    }

    //把order + ordervo数据打包成list列表
    public List<OrderVO> getOrderVOList(Page<Orders> page){
        List<OrderVO> orderVOList = new ArrayList<>();

        List<Orders> ordersList = page.getResult();

        //ordersList != null && ordersList.size() > 0
        if(!CollectionUtils.isEmpty(ordersList)) {
            for (Orders orders : ordersList) {
                //把每一个订单取出来赋值给OrderVO
                OrderVO orderVO = new OrderVO();
                BeanUtils.copyProperties(orders,orderVO);

                //创建订单菜品字符串并加入OrderVO
                String str = getOrderDishesStr(orders);
                orderVO.setOrderDishes(str);

                //加入orderVO列表
                orderVOList.add(orderVO);
            }
        }
        return orderVOList;
    }

    //创建订单菜品字符串并加入OrderVO
    public String getOrderDishesStr(Orders orders){
        List<OrderDetail> orderDetailList = orderDetailMapper.getByOrderId(orders.getId());

        // 将每一条订单菜品信息拼接为字符串(格式:宫保鸡丁*3;)
        List<String> orderDishList = orderDetailList.stream().map(x->{
            String str = x.getName() + "*" + x.getNumber();
            return str;
        }).collect(Collectors.toList());

        return String.join(" ",orderDishList);
    }

2、各个状态的订单数量统计 - GET接口

(1)需求分析

(2)代码开发

【1】controller层

java 复制代码
    /**
     * 各个状态的订单数量统计
     * @return
     */
    @GetMapping("/statistics")
    @ApiOperation("各个状态的订单数量统计")
    public Result<OrderStatisticsVO> statistics(){
        OrderStatisticsVO orderStatisticsVO = orderService.statistics();
        return Result.success(orderStatisticsVO);
    }

【2】service层

java 复制代码
    /**
     * 各个状态的订单数量统计
     * 订单状态 1待付款 2待接单 3已接单 4派送中 5已完成 6已取消
     * @return
     */
    public OrderStatisticsVO statistics() {
        OrderStatisticsVO orderStatisticsVO = new OrderStatisticsVO();

        Integer confirmed = orderMapper.getStatus(Orders.COMPLETED);
        Integer deliver = orderMapper.getStatus(Orders.DELIVERY_IN_PROGRESS);
        Integer tobeconfirmed = orderMapper.getStatus(Orders.TO_BE_CONFIRMED);

        orderStatisticsVO.setConfirmed(confirmed);
        orderStatisticsVO.setDeliveryInProgress(deliver);
        orderStatisticsVO.setToBeConfirmed(tobeconfirmed);

        return orderStatisticsVO;
    }

【3】mapper层

java 复制代码
    /**
     * 根据状态查询订单数量
     * @param status
     * @return
     */
    @Select("select count(id) from sky_take_out.orders where status = #{status}")
    int getStatus(Integer status);

3、查询订单详情 - GET接口

(1)需求分析

(2)代码开发

【1】controller层

java 复制代码
    /**
     * 查询订单详情
     * @param id
     * @return
     */
    @GetMapping("/details/{id}")
    @ApiOperation("查询订单详情")
    public Result<OrderVO> orderDetails(@PathVariable Long id){
        OrderVO orderVO = orderService.getDetailById(id);
        return Result.success(orderVO);
    }

【2】service层

java 复制代码
    /**
     * 根据id查询订单详情
     * @param id
     * @return
     */
    public OrderVO getDetailById(Long id) {
        OrderVO orderVO = new OrderVO();
        Orders orders = orderMapper.getById(id);
        List<OrderDetail> orderDetailList = orderDetailMapper.getByOrderId(id);

        BeanUtils.copyProperties(orders,orderVO);
        orderVO.setOrderDetailList(orderDetailList);
        String str = getOrderDishesStr(orders);
        orderVO.setOrderDishes(str);

        return orderVO;
    }

4、接单 - PUT接口

(1)需求分析

(2)代码开发

【1】controller层

java 复制代码
    /**
     * 接单
     * @param ordersConfirmDTO
     * @return
     */
    @PutMapping("/confirm")
    @ApiOperation("接单")
    public Result confirm(@RequestBody OrdersConfirmDTO ordersConfirmDTO){
        orderService.confirm(ordersConfirmDTO);
        return Result.success();
    }

【2】service层

接单业务逻辑就是:修改订单状态

java 复制代码
    /**
     * 接单
     * 订单状态 1待付款 2待接单 3已接单 4派送中 5已完成 6已取消
     * @param ordersConfirmDTO
     */
    public void confirm(OrdersConfirmDTO ordersConfirmDTO) {
        Orders orders = Orders.builder()
                .id(ordersConfirmDTO.getId())
                .status(Orders.CONFIRMED)
                .build();

        orderMapper.update(orders);
    }

5、拒单 - PUT接口

(1)需求分析

(2)代码开发

【1】controller层

java 复制代码
    /**
     * 拒单
     * @param ordersRejectionDTO
     * @return
     */
    @PutMapping("/rejection")
    @ApiOperation("拒单")
    public Result reject(@RequestBody OrdersRejectionDTO ordersRejectionDTO) throws Exception {
        orderService.reject(ordersRejectionDTO);
        return Result.success();
    }

【2】service层

如果【订单不存在】或【订单状态不为"待接单"】,则需要抛出异常,其他业务逻辑也是修改订单信息

java 复制代码
    /**
     * 拒单
     * @param ordersRejectionDTO
     */
    public void reject(OrdersRejectionDTO ordersRejectionDTO) throws Exception {
        Orders ordersDB = orderMapper.getById(ordersRejectionDTO.getId());

        //只有订单存在且状态为2(待接单)才可以拒单
        if(ordersDB == null || !ordersDB.getStatus().equals(Orders.TO_BE_CONFIRMED)){
            throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }

//        //支付状态
//        Integer payStatus = ordersDB.getPayStatus();
//        if (payStatus == Orders.PAID) {
//            //用户已支付,需要退款
//            String refund = weChatPayUtil.refund(
//                    ordersDB.getNumber(),
//                    ordersDB.getNumber(),
//                    new BigDecimal(0.01),
//                    new BigDecimal(0.01));
//            log.info("申请退款:{}", refund);
//        }

        Orders orders = Orders.builder()
                .id(ordersRejectionDTO.getId())
                .status(Orders.CANCELLED)
                .cancelTime(LocalDateTime.now())
                .rejectionReason(ordersRejectionDTO.getRejectionReason())
                .build();

        orderMapper.update(orders);
    }

6、取消订单 - PUT接口

(1)需求分析

(2)代码开发

【1】controller层

java 复制代码
    /**
     * 商家取消订单
     * @param ordersCancelDTO
     * @return
     */
    @PutMapping("/cancel")
    @ApiOperation("取消订单")
    public Result cancel(@RequestBody OrdersCancelDTO ordersCancelDTO) throws Exception {
        orderService.shopCancel(ordersCancelDTO);
        return Result.success();
    }

【2】service层

java 复制代码
    /**
     * 商家取消订单
     * @param ordersCancelDTO
     */
    public void shopCancel(OrdersCancelDTO ordersCancelDTO) {
//        Orders ordersDB = orderMapper.getById(ordersCancelDTO.getId());

//        //支付状态
//        Integer payStatus = ordersDB.getPayStatus();
//        if (payStatus == 1) {
//            //用户已支付,需要退款
//            String refund = weChatPayUtil.refund(
//                    ordersDB.getNumber(),
//                    ordersDB.getNumber(),
//                    new BigDecimal(0.01),
//                    new BigDecimal(0.01));
//            log.info("申请退款:{}", refund);
//        }

        Orders orders = Orders.builder()
                .id(ordersCancelDTO.getId())
                .status(Orders.CANCELLED)
                .cancelReason(ordersCancelDTO.getCancelReason())
                .cancelTime(LocalDateTime.now())
                .build();

        orderMapper.update(orders);
    }

7、派送订单 - PUT接口

(1)需求分析

(2)代码开发

【1】controller层

java 复制代码
    /**
     * 派送订单
     * @param id
     * @return
     */
    @PutMapping("/delivery/{id}")
    @ApiOperation("派送订单")
    public Result delivery(@PathVariable Long id){
        orderService.delivery(id);
        return Result.success();
    }

【2】service层

java 复制代码
    /**
     * 派送订单
     * @param id
     */
    public void delivery(Long id) {
        Orders orderDB = orderMapper.getById(id);

        if(orderDB == null || !orderDB.getStatus().equals(Orders.CONFIRMED)){
            throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }

        Orders orders = Orders.builder()
                .id(id)
                .status(Orders.DELIVERY_IN_PROGRESS)
                .build();

        orderMapper.update(orders);
    }

8、完成订单 - PUT接口

(1)需求分析

(2)代码开发

【1】controller层

java 复制代码
    /**
     * 完成订单
     * @param id
     * @return
     */
    @PutMapping("/complete/{id}")
    @ApiOperation("完成订单")
    public Result complete(@PathVariable Long id){
        orderService.complete(id);
        return Result.success();
    }

【2】service层

java 复制代码
    /**
     * 完成订单
     * @param id
     */
    public void complete(Long id) {
        Orders orderDB = orderMapper.getById(id);

        if(orderDB == null || !orderDB.getStatus().equals(Orders.DELIVERY_IN_PROGRESS)){
            throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }

        Orders orders = Orders.builder()
                .id(id)
                .status(Orders.COMPLETED)
                .deliveryTime(LocalDateTime.now())
                .build();

        orderMapper.update(orders);
    }

三、校验收货地址是否超出配送范围

1、环境准备

进入控制台,创建应用,获取AK:

2、代码开发

(1)application.yml

(2)OrderServiceImpl

OrderServiceImpl中注入下面的配置项

java 复制代码
    @Value("${sky.shop.address}")
    private String shopAddress;

    @Value("${sky.baidu.ak}")
    private String ak;

在OrderServiceImpl中提供校验方法

java 复制代码
/**
     * 检查客户的收货地址是否超出配送范围
     * @param address
     */
    private void checkOutOfRange(String address) {
        Map map = new HashMap();
        map.put("address",shopAddress);
        map.put("output","json");
        map.put("ak",ak);

        //获取店铺的经纬度坐标
        String shopCoordinate = HttpClientUtil.doGet("https://api.map.baidu.com/geocoding/v3", map);

        JSONObject jsonObject = JSON.parseObject(shopCoordinate);
        if(!jsonObject.getString("status").equals("0")){
            throw new OrderBusinessException("店铺地址解析失败");
        }

        //数据解析
        JSONObject location = jsonObject.getJSONObject("result").getJSONObject("location");
        String lat = location.getString("lat");
        String lng = location.getString("lng");
        //店铺经纬度坐标
        String shopLngLat = lat + "," + lng;

        map.put("address",address);
        //获取用户收货地址的经纬度坐标
        String userCoordinate = HttpClientUtil.doGet("https://api.map.baidu.com/geocoding/v3", map);

        jsonObject = JSON.parseObject(userCoordinate);
        if(!jsonObject.getString("status").equals("0")){
            throw new OrderBusinessException("收货地址解析失败");
        }

        //数据解析
        location = jsonObject.getJSONObject("result").getJSONObject("location");
        lat = location.getString("lat");
        lng = location.getString("lng");
        //用户收货地址经纬度坐标
        String userLngLat = lat + "," + lng;

        map.put("origin",shopLngLat);
        map.put("destination",userLngLat);
        map.put("steps_info","0");

        //路线规划
        String json = HttpClientUtil.doGet("https://api.map.baidu.com/directionlite/v1/driving", map);

        jsonObject = JSON.parseObject(json);
        if(!jsonObject.getString("status").equals("0")){
            throw new OrderBusinessException("配送路线规划失败");
        }

        //数据解析
        JSONObject result = jsonObject.getJSONObject("result");
        JSONArray jsonArray = (JSONArray) result.get("routes");
        Integer distance = (Integer) ((JSONObject) jsonArray.get(0)).get("distance");

        if(distance > 5000){
            //配送距离超过5000米
            throw new OrderBusinessException("超出配送范围");
        }
    }

在OrderServiceImpl的submitOrder方法中调用上面的校验方法

java 复制代码
//检查用户的收货地址是否超出配送范围
        checkOutOfRange(addressBook.getCityName() + addressBook.getDistrictName() + addressBook.getDetail());
相关推荐
葫芦和十三7 分钟前
图解 MongoDB 21|选举与 failover:Primary 是怎么选出来的
后端·mongodb·agent
GetcharZp34 分钟前
26k Star 开源内网穿透神器 NetBird,一分钟实现全球设备互联!
后端
考虑考虑1 小时前
Mybatis实现批量插入
java·后端·mybatis
咖啡八杯2 小时前
GoF设计模式——中介者模式
java·后端·spring·设计模式
lizhongxuan4 小时前
多Agent之间的区别
后端
青石路6 小时前
记一次多JDK版本问题的排查,一坑套一坑,差点没爬上来
java
杨充6 小时前
1.面向对象设计思想
后端
IT_陈寒6 小时前
Java的Date类又坑了我一次,改用时间戳真香
前端·人工智能·后端
systemPro7 小时前
2.6亿条设备数据,历史查询从超时到50ms,我做了什么
后端
要阿尔卑斯吗7 小时前
提示词优化启示:为什么“按顺序输出“比“关键度评分“更有效
后端