goshop电商项目02

电商轮播图

复制代码
@RestController
@RequestMapping("/index")
public class CarouselController {

    @Autowired
    private CarouselService carouselService;

    /**
     * 获取轮播图列表
     *
     * @return
     */
    @GetMapping("/carousel")
    public JsonResult carousel() {

        return JsonResult.ok(carouselService.queryAll(YesOrNo.YES.type));
    }

}

@Service
public class CarouselServiceImpl  implements CarouselService {

    @Autowired
    private CarouselMapper carouselMapper;

    @Override
    public List<CarouselDO> queryAll(Integer isShow) {

       return carouselMapper.selectList(new QueryWrapper<CarouselDO>().eq("is_show", isShow).orderByDesc("sort"));

    }
}

首页分类

  • 第一次刷新主页查询大分类,渲染展示到首页
  • 如果鼠标移动到大分类,则加载小分类的内容

一级分类

复制代码
    /**
     * 获取商品分类(一级分类)
     *
     * @return
     */
    @GetMapping("/cats")
    public JsonResult cats() {
        return JsonResult.ok(categoryService.queryAllRootLevelCat());
    }

@Service
public class CategoryServiceImpl implements CategoryService {

    @Autowired
    private CategoryMapper categoryMapper;

    /**
     * 查询所有一级分类
     * @return
     */
    @Override
    public List<CategoryDO> queryAllRootLevelCat() {

        return categoryMapper.selectList(new QueryWrapper<CategoryDO>().eq("type", CategoryType.FIRST.type));

    }
}

查询子分类

复制代码
/**
 * 二级分类VO
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class CategoryVO {

    private Integer id;
    private String name;
    private Integer type;
    private Integer fatherId;

    private List<SubCategoryVO> subCatList;
}

/**
 * 三级分类VO
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class SubCategoryVO {

    private Integer subId;
    private String subName;
    private Integer subType;
    private Integer subFatherId;

}

    /**
     * 获取商品子分类
     *
     * @param rootCatId
     * @return
     */
    @GetMapping("/subCat/{rootCatId}")
    public JsonResult subCat(@PathVariable Integer rootCatId) {

        if (rootCatId == null){
            return JsonResult.errorMsg("分类不存在");
        }
        return JsonResult.ok(categoryService.querySubLevelCat(rootCatId));
    }

   /**
     * 查询所有二级分类
     * @param fatherId
     * @return
     */
    @Override
    public List<CategoryVO> querySubLevelCat(Integer fatherId) {
        // 从数据库查询符合条件的二级分类DO列表
        List<CategoryDO> categoryDOS = categoryMapper.selectList(new QueryWrapper<CategoryDO>()
                .eq("type", CategoryType.SECOND.type)
                .eq("father_id", fatherId));

        List<CategoryVO> categoryVOS = categoryDOS.stream()
                .map(categoryDO -> {
                    CategoryVO categoryVO = CategoryVO.builder()
                            .id(categoryDO.getId())
                            .name(categoryDO.getName())
                            .type(categoryDO.getType())
                            .fatherId(categoryDO.getFatherId())
                            .subCatList(queryThirdLevelCat(categoryDO.getId()))
                            .build();
                    return categoryVO;
                })
                .collect(Collectors.toCollection(ArrayList::new));

       return categoryVOS;
    }
    /**
     * 查询所有三级分类
     * @param fatherId
     * @return
     */
    @Override
    public List<SubCategoryVO> queryThirdLevelCat(Integer fatherId) {

        List<CategoryDO> categoryDOS = categoryMapper.selectList(new QueryWrapper<CategoryDO>()
                .eq("type", CategoryType.THIRD.type)
                .eq("father_id", fatherId));
                List<SubCategoryVO> subCategoryVOS = categoryDOS.stream()
                .map(categoryDO -> {
                    SubCategoryVO subCategoryVO = SubCategoryVO.builder()
                            .subId(categoryDO.getId())
                            .subName(categoryDO.getName())
                            .subType(categoryDO.getType())
                            .subFatherId(categoryDO.getFatherId())
                            .build();
                    return subCategoryVO;
                })
                .collect(Collectors.toCollection(ArrayList::new));
                return subCategoryVOS;
    }

首页推荐

分类表

商品表

商品图片表

复制代码
    /**
     * 查询每个一级分类下的最新6条商品
     * @param rootCatId
     * @return
     */
    @Override
    public List<NewItemsVO> querySixNewItems(Integer rootCatId) {

        List<ItemsDO> itemsDOS = itemsMapper.selectList(new QueryWrapper<ItemsDO>().eq("root_cat_id", rootCatId).eq("on_off_status", 1));
        CategoryDO categoryDO = categoryMapper.selectOne(new QueryWrapper<CategoryDO>().eq("id", rootCatId));
        NewItemsVO newItemsVO = NewItemsVO.builder()
                .rootCatId(rootCatId)
                .rootCatName(categoryDO.getName())
                .slogan(categoryDO.getSlogan())
                .catImage(categoryDO.getCatImage())
                .bgColor(categoryDO.getBgColor())
                .simpleItemList(itemsDOS.stream().map(itemsDO -> querySimpleItemList(itemsDO.getId(), itemsDO.getItemName())).collect(Collectors.toCollection(ArrayList::new)))
                .build();
                return Collections.singletonList(newItemsVO);

    }

    /**
     * 查询商品列表
     * @param id
     * @return
     */
    @Override
    public SimpleItemVO querySimpleItemList(String id,String itemName) {
        ItemsImgDO itemsImgDO = itemsImgMapper.selectOne(new QueryWrapper<ItemsImgDO>().eq("item_id", id).eq("is_main", 1));
        SimpleItemVO simpleItemVO = SimpleItemVO.builder()
                .itemId(id)
                .itemName(itemName)
                .itemUrl(itemsImgDO.getUrl())
                .build();
        return simpleItemVO;
    }

    /**
     * 查询每个一级分类下最新的6条商品
     * @param rootCatId
     * @return
     */
    @GetMapping("/sixNewItems/{rootCatId}")
    public JsonResult sixNewItems(@PathVariable Integer rootCatId) {
        if (rootCatId == null){
            return JsonResult.errorMsg("分类不存在");
        }
        return JsonResult.ok(categoryService.querySixNewItems(rootCatId));
    }

商品详情功能

商品规格表

商品参数表

复制代码
@Service
public class ItemsServiceImpl implements ItemsService {

    @Autowired
    private ItemsMapper itemsMapper;
    @Autowired
    private ItemsImgService itemsImgService;
    @Autowired
    private ItemsSpecMapper itemsSpecMapper;
    @Autowired
    private ItemsParamService itemsParamService;
    @Autowired
    private ItemsImgMapper itemsImgMapper;


    /**
     * 根据商品id查询商品
     *
     * @param itemId
     * @return
     */
    @Override
    public ItemsDO queryItemById(String itemId) {
        return  itemsMapper.selectById(itemId);
    }

    @Override
    public List<ItemsImgDO> queryItemImgList(String itemId) {
        return  itemsImgMapper.selectList(new QueryWrapper<ItemsImgDO>().eq("item_id",itemId));
    }

    @Override
    public List<ItemsSpecDO> queryItemSpecList(String itemId) {
        return itemsSpecMapper.selectList(new QueryWrapper<ItemsSpecDO>().eq("item_id",itemId));
    }

    @Override
    public ItemsParamDO queryItemParam(String itemId) {
        return itemsParamService.getOne(new QueryWrapper<ItemsParamDO>().eq("item_id",itemId));
    }
}

商品评价

商品评价表

复制代码
    @GetMapping("/commentLevel")
    public JsonResult commentLevel(@RequestParam String itemId) {

        if (StringUtils.isBlank(itemId)) {
            return JsonResult.errorMsg("商品不存在");
        }
        CommentLevelCountsVO countsVO = itemsService.queryCommentCounts(itemId);
        return JsonResult.ok(countsVO);
    }


    /**
     * 查询商品评价等级数量
     *
     * @param itemId
     * @return
     */
    @Override
    public CommentLevelCountsVO queryCommentCounts(String itemId) {

        Integer goodCounts = getCountByLevel(itemId, CommentLevel.SELLER_LEVEL_ONE.type);
        Integer normalCounts = getCountByLevel(itemId, CommentLevel.SELLER_LEVEL_TWO.type);
        Integer badCounts = getCountByLevel(itemId, CommentLevel.SELLER_LEVEL_THREE.type);
        CommentLevelCountsVO commentLevelCountsVO = new CommentLevelCountsVO();
        commentLevelCountsVO.setTotalCounts(goodCounts + normalCounts + badCounts);
        commentLevelCountsVO.setGoodCounts(goodCounts);
        commentLevelCountsVO.setNormalCounts(normalCounts);
        commentLevelCountsVO.setBadCounts(badCounts);
        return commentLevelCountsVO;

    }

    Integer getCountByLevel(String itemId,Integer level){

        ItemsComments itemsComments = new ItemsComments();
        itemsComments.setItemId(itemId);
        if (level != null){
            itemsComments.setCommentLevel(level);
        }
        return itemsCommentsMapper.selectCount(new QueryWrapper<ItemsComments>().eq("item_id",itemId).eq("comment_level",level));
    }

分页查询评价

分页插件

复制代码
@Configuration
public class MybatisPlusPageConfig {

    /**
     * 新的分页插件,一缓和二缓遵循mybatis的规则,
     * 需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor interceptor=new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

代码编写

复制代码
    /**
     * 分页查询商品评价
     *
     * @param itemId
     * @param level
     * @param page
     * @param pageSize
     * @return
     */
    @Override
    public Map<String, Object> queryPageComments(String itemId, Integer level, Integer page, Integer pageSize) {
        // 1. 基础参数校验(避免非法参数导致查询异常)
        if (page == null || page < 1) {
            page = 1;
        }
        if (pageSize == null || pageSize < 1 || pageSize > 100) {
            pageSize = 10; // 限制最大每页100条,防止查询压力过大
        }
        if (level == null) {
            level = 1; // 兼容前端可能传递的空值,默认查好评
        }

        // 2. 构建 MyBatis-Plus 分页对象,执行查询
        Page<ItemsComments> pageInfo = new Page<>(page, pageSize);
        QueryWrapper<ItemsComments> queryWrapper = new QueryWrapper<ItemsComments>()
                .eq("item_id", itemId) // 按商品ID筛选
                .eq("comment_level", level); // 按评论等级筛选

        // 执行分页查询
        Page<ItemsComments> selectPage = itemsCommentsMapper.selectPage(pageInfo, queryWrapper);

        // 3. 修复 ItemCommentVO 构建问题(关键:builder() 必须赋值给 VO 对象,否则返回空数据)
        List<ItemCommentVO> itemCommentVOS = new ArrayList<>();
        for (ItemsComments itemsComments : selectPage.getRecords()) {
            // 正确构建 ItemCommentVO:直接用 builder() 构建并赋值,无需先 new 空对象
            ItemCommentVO itemCommentVO = ItemCommentVO.builder()
                    .commentLevel(itemsComments.getCommentLevel())
                    .content(itemsComments.getContent())
                    .specName(itemsComments.getSepcName()) // 注意:若数据库字段是 specName,此处修正笔误为 getSpecName()
                    .createdTime(itemsComments.getCreatedTime())
                    .userFace(usersMapper.selectById(itemsComments.getUserId()).getFace())
                    .nickname(usersMapper.selectById(itemsComments.getUserId()).getNickname())
                    .build(); // 完成构建,字段才会有值

            itemCommentVOS.add(itemCommentVO);
        }

        // 4. 构建前端需要的返回对象(字段名完全匹配前端取值逻辑)
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("rows", itemCommentVOS); // 对应前端 grid.rows(评论列表)
        resultMap.put("total", selectPage.getPages()); // 对应前端 grid.total(总页数,赋值给 maxPage)
        resultMap.put("records", selectPage.getTotal()); // 对应前端 grid.records(总记录数,赋值给 total)

        // 5. 返回该 map,供 Controller 层包装后返回给前端
        return resultMap;
    }

    /**
     * 商品评论
     *
     * @param itemId
     * @param level
     * @param page
     * @param pageSize
     * @return
     */
    @GetMapping("/comments")
    public JsonResult comments(@RequestParam String itemId,
                               @RequestParam(defaultValue = "1") Integer level,
                               @RequestParam(defaultValue = "1") Integer page,
                               @RequestParam(defaultValue = "10") Integer pageSize) {

        // 1. 校验商品ID(和前端逻辑一致,提示商品不存在)
        if (StringUtils.isBlank(itemId)) {
            return JsonResult.errorMsg("商品不存在");
        }

        // 2. 调用 Service 层,获取适配前端的分页数据(包含 rows、total、records)
        Map<String, Object> commentPageData = itemsService.queryPageComments(itemId, level, page, pageSize);

        // 3. 直接返回该数据,前端 res.data.data 即可拿到 grid 对象
        return JsonResult.ok(commentPageData);
    }

脱敏工具类

复制代码
public class DesensitizationUtil {

    private static final int SIZE = 6;
    private static final String SYMBOL = "*";
    /**
     * 通用脱敏方法
     * @param value
     * @return
     */
    public static String commonDisplay(String value) {
        if (null == value || "".equals(value)) {
            return value;
        }
        int len = value.length();
        int pamaone = len / 2;
        int pamatwo = pamaone - 1;
        int pamathree = len % 2;
        StringBuilder stringBuilder = new StringBuilder();
        if (len <= 2) {
            if (pamathree == 1) {
                return SYMBOL;
            }
            stringBuilder.append(SYMBOL);
            stringBuilder.append(value.charAt(len - 1));
        } else {
            if (pamatwo <= 0) {
                stringBuilder.append(value.substring(0, 1));
                stringBuilder.append(SYMBOL);
                stringBuilder.append(value.substring(len - 1, len));

            } else if (pamatwo >= SIZE / 2 && SIZE + 1 != len) {
                int pamafive = (len - SIZE) / 2;
                stringBuilder.append(value.substring(0, pamafive));
                for (int i = 0; i < SIZE; i++) {
                    stringBuilder.append(SYMBOL);
                }
                if ((pamathree == 0 && SIZE / 2 == 0) || (pamathree != 0 && SIZE % 2 != 0)) {
                    stringBuilder.append(value.substring(len - pamafive, len));
                } else {
                    stringBuilder.append(value.substring(len - (pamafive + 1), len));
                }
            } else {
                int pamafour = len - 2;
                stringBuilder.append(value.substring(0, 1));
                for (int i = 0; i < pamafour; i++) {
                    stringBuilder.append(SYMBOL);
                }
                stringBuilder.append(value.substring(len - 1, len));
            }
        }
        return stringBuilder.toString();
    }

}

商品搜索

复制代码
    /**
     * 商品搜索
     *
     * @param keywords
     * @param sort
     * @param page
     * @param pageSize
     * @return
     */
    @GetMapping("/search")
    public JsonResult search(@RequestParam String keywords,
                             @RequestParam(defaultValue = "") String sort,
                             @RequestParam(defaultValue = "1") Integer page,
                             @RequestParam(defaultValue = "10") Integer pageSize) {

        // 1. 校验
        if (StringUtils.isBlank(keywords)) {
            return JsonResult.errorMsg(null);
        }

        // 2. 调用 Service 层,获取适配前端的分页数据(包含 rows、total、records)
        Map<String, Object> result = itemsService.searchItems(keywords, sort, page, pageSize);
        return JsonResult.ok(result);
    }

    /**
     * 商品搜索
     *
     * @param keywords
     * @param sort
     * @param page
     * @param pageSize
     * @return
     */
    @Override
    public Map<String, Object> searchItems(String keywords, String sort, Integer page, Integer pageSize) {
        // 1. 分页参数校验与默认值处理(避免非法参数导致异常,和之前评论分页逻辑一致)
        if (page == null || page < 1) {
            page = 1;
        }
        if (pageSize == null || pageSize < 1 || pageSize > 100) {
            pageSize = 10; // 限制最大每页100条,防止查询压力过大
        }
        // 排序参数默认值(匹配 XML 中的 otherwise,默认按商品名称升序)
        if (StringUtils.isBlank(sort)) {
            sort = "k";
        }

        // 2. 构建 MyBatis 分页对象(注意:这里因为你用了自定义 XML SQL,需手动处理分页)
        // 方式:先构建分页参数,再封装查询条件 Map(和 XML 中的 parameterType="Map" 对应)
        Page<SearchItemsVO> pageInfo = new Page<>(page, pageSize);

        // 3. 封装 XML SQL 需要的查询参数(key 必须和 XML 中的 paramsMap 对应)
        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("keywords", keywords); // 搜索关键词
        paramsMap.put("sort", sort); // 排序条件(c: 销量降序,p: 价格升序,k: 默认名称升序)

        // 4. 执行分页查询(分两步:① 查询符合条件的总记录数 ② 查询当前页的商品列表)
        // 注意:你现有 XML 中没有总记录数查询,需先补充一个 count 方法(下面会给出补充说明),这里先按完整逻辑实现
        // ① 查询总记录数(用于计算总页数)
        Long totalRecords = itemsMapperCustom.countSearchItems(paramsMap);
        // ② 查询当前页的商品列表(传递分页参数,适配自定义 XML 分页)
        // 给 paramsMap 补充分页参数(limit 起始位置、每页条数)
        paramsMap.put("start", (page - 1) * pageSize);
        paramsMap.put("pageSize", pageSize);
        List<SearchItemsVO> searchItemsVOList = itemsMapperCustom.searchItems(paramsMap);

        // 5. 封装分页对象(计算总页数)
        pageInfo.setRecords(searchItemsVOList);
        pageInfo.setTotal(totalRecords);
        long totalPages = (totalRecords + pageSize - 1) / pageSize; // 向上取整计算总页数
        pageInfo.setPages(totalPages);

        // 6. 构建前端需要的返回 Map(和评论分页格式一致,字段名严格匹配)
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("rows", searchItemsVOList); // 商品列表(对应前端 grid.rows)
        resultMap.put("total", pageInfo.getPages()); // 总页数(对应前端 grid.total → maxPage)
        resultMap.put("records", pageInfo.getTotal()); // 总记录数(对应前端 grid.records → total)

        // 7. 返回结果 Map
        return resultMap;
    }

package com.guslegend.mapper;

import com.guslegend.vo.SearchItemsVO;

import java.util.List;
import java.util.Map;

public interface ItemsMapperCustom {

    /**
     * 商品搜索 - 查询符合条件的总记录数
     */
    Long countSearchItems(Map<String, Object> paramsMap);

    /**
     * 商品搜索 - 分页查询商品列表(补充分页参数)
     */
    List<SearchItemsVO> searchItems(Map<String, Object> paramsMap);
}

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.guslegend.mapper.ItemsMapperCustom" >

    <!-- 商品搜索 - 查询总记录数 -->
    <select id="countSearchItems" parameterType="Map" resultType="java.lang.Long">
        SELECT
        COUNT(DISTINCT i.id)
        FROM
        items i
        LEFT JOIN
        items_img ii
        ON
        i.id = ii.item_id
        LEFT JOIN
        (SELECT item_id,MIN(price_discount) as price_discount from items_spec GROUP BY item_id) tempSpec
        ON
        i.id = tempSpec.item_id
        WHERE
        ii.is_main = 1
        <!-- 去掉 paramsMap.,直接用 keywords -->
        <if test="keywords != null and keywords != '' ">
            AND i.item_name like concat('%', #{keywords}, '%')
        </if>
    </select>

    <!-- 商品搜索 - 分页查询商品列表 -->
    <select id="searchItems" parameterType="Map" resultType="com.guslegend.vo.SearchItemsVO">
        SELECT
        i.id as itemId,
        i.item_name as itemName,
        i.sell_counts as sellCounts,
        ii.url as imgUrl,
        tempSpec.price_discount as price
        FROM
        items i
        LEFT JOIN
        items_img ii
        on
        i.id = ii.item_id
        LEFT JOIN
        (SELECT item_id,MIN(price_discount) as price_discount from items_spec GROUP BY item_id) tempSpec
        on
        i.id = tempSpec.item_id
        WHERE
        ii.is_main = 1
        <!-- 去掉 paramsMap.,直接用 keywords -->
        <if test="keywords != null and keywords != '' ">
            AND i.item_name like concat('%', #{keywords}, '%')
        </if>
        ORDER BY
        <choose>
            <!-- 去掉 paramsMap.,直接用 sort -->
            <when test="sort == &quot;c&quot; ">
                i.sell_counts desc
            </when>
            <!-- 去掉 paramsMap.,直接用 sort -->
            <when test="sort == &quot;p&quot; ">
                tempSpec.price_discount asc
            </when>
            <otherwise>
                i.item_name asc
            </otherwise>
        </choose>
        <!-- 去掉 paramsMap.,直接用 start 和 pageSize -->
        LIMIT #{start}, #{pageSize}
    </select>
</mapper>

购物车存储功能

商品添加到购物车

复制代码
@RestController
@RequestMapping("/orderStatusDO")
public class ShopCartController {

    @PostMapping("/add")
    public JsonResult add(@RequestParam String userId, @RequestBody ShopCartBO shopCartBO, HttpServletRequest  request, HttpServletResponse response){

        if (StringUtils.isBlank(userId)){
            return JsonResult.errorMsg("用户不存在");
        }

        //TODO 后端同步到redis

        return JsonResult.ok();

    }
}

渲染购物车

复制代码
    @GetMapping("/refresh")
    public JsonResult refresh(@RequestParam String itemSpecIds) {
        if (StringUtils.isBlank(itemSpecIds)) {
            return JsonResult.ok(Collections.emptyList());
        }

        List<ShopCartVO> list = itemsService.queryItemsBySpecIds(itemSpecIds);

        return JsonResult.ok(list);
    }

    @Override
    public List<ShopCartVO> queryItemsBySpecIds(String itemSpecIdsStr) {
        // 1. 校验字符串参数
        if (StringUtils.isBlank(itemSpecIdsStr)) {
            return Collections.emptyList();
        }

        // 2. 拆分字符串为 List<String>(按逗号分割,过滤空值)
        String[] specIdArray = itemSpecIdsStr.split(",");
        // 优化:避免数组转 List 后无法修改,同时过滤空字符串
        List<String> specIdList = new ArrayList<>();
        for (String specId : specIdArray) {
            if (StringUtils.isNotBlank(specId)) {
                specIdList.add(specId.trim());
            }
        }

        return itemsMapperCustom.queryItemsBySpecIds(specIdList);
    }

    List<ShopCartVO> queryItemsBySpecIds(@Param("specIdList") List<String> specIdList);

      <select id="queryItemsBySpecIds" parameterType="java.util.List" resultType="com.guslegend.vo.ShopCartVO">
            SELECT
            t_items.id as itemId,
            t_items.item_name as itemName,
            t_items_img.url as itemImgUrl,
            t_items_spec.id as specId,
            t_items_spec.`name` as specName,
            t_items_spec.price_discount as priceDiscount,
            t_items_spec.price_normal as priceNormal
            FROM
            items_spec t_items_spec
            LEFT JOIN
            items t_items ON t_items.id = t_items_spec.item_id
            LEFT JOIN
            items_img t_items_img ON t_items_img.item_id = t_items.id
            WHERE
            t_items_img.is_main = 1
            AND
            t_items_spec.id IN
            <foreach collection="specIdList" index="index" item="specId" open="(" separator="," close=")">
                #{specId}
            </foreach>
        </select>
相关推荐
guslegend1 天前
goshop电商项目01
电商
indexsunny6 天前
互联网大厂Java面试实战:Spring Boot微服务在电商场景中的应用
java·数据库·spring boot·redis·微服务·kafka·电商
indexsunny7 天前
互联网大厂Java求职面试实录:Spring Boot微服务在电商场景中的应用及技术深度解析
java·数据库·spring boot·缓存·微服务·面试·电商
indexsunny9 天前
互联网大厂Java求职面试实战:Spring Boot、微服务与Redis缓存技术解析
java·spring boot·redis·微服务·面试·电商·技术栈
indexsunny11 天前
互联网大厂Java面试实战:Spring Boot与微服务在电商场景中的应用
java·spring boot·redis·微服务·kafka·spring security·电商
小学生波波13 天前
HarmonyOS6 - 鸿蒙电商页面实战案例
登录页面·arkts·鸿蒙系统·电商·harmonyos6
indexsunny14 天前
互联网大厂Java面试实战:Spring Boot与微服务在电商场景中的应用解析
java·数据库·spring boot·微服务·maven·flyway·电商
aliprice17 天前
构建你的市场雷达:如何通过速卖通价格历史数据建立竞品监控体系
电商
aliprice19 天前
逆向拆解:用速卖通图片搜索破解竞品设计,找到你的差异化定价空间
大数据·跨境电商·电商