第27周JavaSpringboot电商进阶开发 2.常用功能进阶

电商常用功能进阶 - 课程笔记整理

Excel解析与处理

一、课程内容概述

本小节开始进入电商常用功能进阶部分,主要讲解以下内容:

  1. Excel的解析和处理
  2. 商品图片的处理
  3. Valid注解对列表的验证
  4. 订单数变化趋势图
  5. Spring Boot高级功能

二、Excel解析与处理的背景

在Java中解析Excel表格是非常常见的需求,尤其在电商场景中。例如,运营人员可能需要批量导入商品或用户信息,使用Excel可以提高效率,因为Excel在数据处理、求和、平均值计算等方面能力强大。

三、主流技术栈介绍

目前有两个主流的Excel处理工具:

  1. Apache POI
    • 官网:Apache POI
    • 特点:
      • 用于处理Microsoft文档的Java API,包括Excel、Word、PPT等。
      • 从4.0版本开始,需要Java 8或更高版本。
      • 支持处理Excel(.xls和.xlsx)、Word(.doc和.docx)、PPT(.ppt和.pptx)等格式。
      • Maven依赖可直接引入,无需手动下载。
  2. 阿里EasyExcel
    • 官网:阿里EasyExcel
    • 特点:
      • 阿里巴巴出品,基于语雀展示。
      • 主要解决内存溢出问题,适合处理超大Excel文件。
      • 内部利用了POI,但对POI 07版解析进行了重写,避免内存问题。

四、Excel相关概念

Apache POI中的重要概念
  1. Workbook:整个Excel表格文件,可以包含多个Sheet。
  2. Sheet:工作表,每个Sheet是一个有行有列的内容区域。
  3. Row:行,代表Excel中的一行数据。
  4. Cell:单元格,代表Excel中的一个单元格数据。

五、技术选型建议

  • Apache POI:适用于大多数场景,功能全面,社区支持广泛。不仅可用于Excel,还可用于Word、PPT等文档处理。
  • EasyExcel:适用于需要处理超大Excel文件的场景,避免内存溢出问题。

六、课程实践

代码编写
1. 添加商品批量导入功能

ProductAdminController中添加一个方法,用于处理商品批量导入:

@PostMapping("/admin/upload/product")
public void uploadProduct(@RequestParam("file") MultipartFile file) {// 获取文件名String fileName = file.getOriginalFilename();// 获取文件后缀String suffix = fileName.substring(fileName.lastIndexOf("."));// 生成唯一文件名String uuid = UUID.randomUUID().toString();String newFileName = uuid + suffix;// 创建文件File destFile = new File(Constant.FILE_PATH + newFileName);// 创建文件夹(如果不存在)File fileDirectory = new File(Constant.FILE_PATH);if (!fileDirectory.exists()) {boolean created = fileDirectory.mkdirs();if (!created) {throw new ImMoreException("文件夹创建失败");}}try {file.transferTo(destFile);// 通过Excel导入商品addProductByExcel(destFile);} catch (IOException e) {throw new ImMoreException("文件上传失败");}
}
2. 读取Excel文件并解析商品信息

创建一个方法addProductByExcel,用于读取Excel文件并解析商品信息:

private void addProductByExcel(File excelFile) {try (FileInputStream inputStream = new FileInputStream(excelFile)) {XSSFWorkbook workbook = new XSSFWorkbook(inputStream);Sheet firstSheet = workbook.getSheetAt(0);Iterator<Row> rowIterator = firstSheet.iterator();List<Product> products = new ArrayList<>();while (rowIterator.hasNext()) {Row nextRow = rowIterator.next();Iterator<Cell> cellIterator = nextRow.cellIterator();Product product = new Product();while (cellIterator.hasNext()) {Cell nextCell = cellIterator.next();int columnIndex = nextCell.getColumnIndex();Object cellValue = getCellValue(nextCell);switch (columnIndex) {case 0:product.setName((String) cellValue);break;case 1:product.setImage((String) cellValue);break;case 2:product.setDetail((String) cellValue);break;case 3:product.setCategoryId(((Double) cellValue).intValue());break;case 4:product.setPrice((Double) cellValue);break;case 5:product.setStock(((Double) cellValue).intValue());break;case 6:product.setStatus((String) cellValue);break;}}products.add(product);}// 将商品信息存入数据库saveProductsToDatabase(products);} catch (IOException e) {throw new ImMoreException("Excel文件读取失败");}
}
3. 工具方法getCellValue

创建一个工具类ExcelUtils,用于处理Excel单元格的值:

public class ExcelUtils {public static Object getCellValue(Cell cell) {switch (cell.getCellType()) {case STRING:return cell.getStringCellValue();case BOOLEAN:return cell.getBooleanCellValue();case NUMERIC:return cell.getNumericCellValue();default:return null;}}
}
4. 将商品信息存入数据库
private void saveProductsToDatabase(List<Product> products) {for (Product product : products) {Product existingProduct = productMapper.selectByName(product.getName());if (existingProduct != null) {throw new ImMoreException("商品名不允许重复");}int count = productMapper.insertSelective(product);if (count == 0) {throw new ImMoreException("新增失败");}}
}

七、测试与验证

  1. 启动项目:确保项目正常启动。
  2. 准备Excel文件:按照模板格式准备商品数据。
  3. 使用Postman测试
    • 创建一个POST请求,URL为/admin/upload/product
    • 在请求体中选择form-data,添加一个文件字段file,选择准备好的Excel文件。
    • 发送请求,检查响应是否成功。
  4. 验证数据库:检查数据库中是否成功插入了商品数据。

八、总结

本小节通过实际案例演示了如何使用Apache POI进行Excel文件的解析和处理,包括文件上传、Excel读取、数据解析和数据库操作。希望小伙伴们能够掌握这些技能,灵活应用于实际项目中。

图片处理

一、图片处理的背景

在电商项目中,用户或运营人员上传的图片往往尺寸较大,不适用于移动端浏览,不仅耗费流量,还会增加加载时间。此外,图片容易被其他商家盗用,因此需要进行处理,包括缩放和添加水印。

二、工具介绍

我们将使用 Thumbnails 工具,它支持读取图像并进行缩放、旋转、透明化、打水印等操作,支持多种图片格式(如 JPG、PNG、GIF、BMP)。其官网提供了丰富的示例,便于学习和使用。

三、功能实现

1. 引入依赖

pom.xml 中添加以下依赖:

<dependency><groupId>net.coobird</groupId><artifactId>thumbnailator</artifactId><version>0.4.8</version>
</dependency>
2. 图片处理工具类

创建 ImageUtils 工具类,实现图片的裁剪、缩放、旋转和打水印功能:

import javax.imageio.ImageIO;
import java.io.File;
import java.util.UUID;public class ImageUtils {public static void main(String[] args) {String path = "你的图片路径"; // 替换为你的图片路径String fileName = "草莓.jpg";// 裁剪图片new File(path + File.separator + "crop.jpg").getParentFile().mkdirs();Thumbnails.of(new File(path + File.separator + fileName)).sourceRegion(Positions.BOTTOM_RIGHT, 200, 200).size(200, 200).toFile(path + File.separator + "crop.jpg");// 缩放图片new File(path + File.separator + "scale_1.jpg").getParentFile().mkdirs();Thumbnails.of(new File(path + File.separator + fileName)).scale(0.7).toFile(path + File.separator + "scale_1.jpg");new File(path + File.separator + "scale_2.jpg").getParentFile().mkdirs();Thumbnails.of(new File(path + File.separator + fileName)).scale(1.5).toFile(path + File.separator + "scale_2.jpg");new File(path + File.separator + "size_1.jpg").getParentFile().mkdirs();Thumbnails.of(new File(path + File.separator + fileName)).size(500, 500).keepAspectRatio(false).toFile(path + File.separator + "size_1.jpg");new File(path + File.separator + "size_2.jpg").getParentFile().mkdirs();Thumbnails.of(new File(path + File.separator + fileName)).size(500, 500).keepAspectRatio(true).toFile(path + File.separator + "size_2.jpg");// 旋转图片new File(path + File.separator + "rotate_90.jpg").getParentFile().mkdirs();Thumbnails.of(new File(path + File.separator + fileName)).rotate(90).toFile(path + File.separator + "rotate_90.jpg");new File(path + File.separator + "rotate_180.jpg").getParentFile().mkdirs();Thumbnails.of(new File(path + File.separator + fileName)).rotate(180).toFile(path + File.separator + "rotate_180.jpg");// 打水印new File(path + File.separator + "watermark.jpg").getParentFile().mkdirs();try {Thumbnails.of(new File(path + File.separator + fileName)).watermark(Positions.BOTTOM_RIGHT,ImageIO.read(new File(path + File.separator + "watermark.png")), 0.5f).toFile(path + File.separator + "watermark.jpg");} catch (Exception e) {e.printStackTrace();}}
}
3. 图片上传接口的改造

ProductAdminController 中改造图片上传接口,实现图片的自动处理:

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;import java.io.File;
import java.io.IOException;
import java.util.UUID;@RestController
@RequestMapping("/admin")
public class ProductAdminController {@PostMapping("/upload/image")public String uploadImage(@RequestParam("file") MultipartFile file) {// 获取文件名String fileName = file.getOriginalFilename();// 获取文件后缀String suffix = fileName.substring(fileName.lastIndexOf("."));// 生成唯一文件名String newFileName = UUID.randomUUID().toString() + suffix;// 创建文件File destFile = new File(Constant.FILE_UPLOAD_DIR + newFileName);// 创建文件夹(如果不存在)File fileDirectory = new File(Constant.FILE_UPLOAD_DIR);if (!fileDirectory.exists()) {boolean created = fileDirectory.mkdirs();if (!created) {throw new ImMoreException("文件夹创建失败");}}try {file.transferTo(destFile);// 处理图片:缩放并打水印Thumbnails.of(destFile).size(400, 400).watermark(Positions.BOTTOM_RIGHT,ImageIO.read(new File(Constant.FILE_UPLOAD_DIR + Constant.WATERMARK_JPG)), Constant.IMAGE_OPACITY).toFile(Constant.FILE_UPLOAD_DIR + "processed_" + newFileName);return "图片上传并处理成功";} catch (IOException e) {throw new ImMoreException("图片处理失败");}}
}

四、测试与验证

  1. 启动项目:确保项目正常启动。
  2. 准备图片:选择一张图片作为测试文件。
  3. 使用Postman测试
    • 创建一个POST请求,URL为/admin/upload/image
    • 在请求体中选择form-data,添加一个文件字段file,选择准备好的图片。
    • 发送请求,检查响应是否成功。
  4. 验证处理结果:检查处理后的图片是否符合预期,包括尺寸、水印和透明度等。

五、总结

本小节学习了使用 Thumbnails 工具进行图片处理的方法,包括裁剪、缩放、旋转和打水印。通过改造图片上传接口,实现了自动处理上传图片的功能,提高了图片的实用性和美观度。

列表参数校验的实现方法

一、问题背景

在实际开发中,前端传入的参数可能是一个列表,需要对列表中的每个元素进行校验。例如,校验列表中的每个 ID 是否大于零。常见的校验注解如 @Min@Max 在列表场景下无法直接使用,因此需要寻找解决方案。

二、解决方案

方法一:手动校验
  1. 实现步骤
    • 使用 for 循环遍历列表。
    • 对每个元素的属性进行手动校验,如 if (updateRequest.getPrice() < 1)
    • 如果校验失败,抛出自定义异常。
  2. 优点:简单直接,易于理解。
  3. 缺点:代码冗长,不优雅,难以统一管理。
方法二:自定义列表类
  1. 实现步骤
    • 创建一个自定义列表类 ValidList,实现 List 接口。
    • 在自定义列表类中,对每个元素添加校验逻辑。
    • 将普通列表替换为自定义列表。
  2. 优点:代码优雅,复用性强。
  3. 缺点:需要额外实现一个类,稍微增加复杂度。
方法三:使用 @Validated 注解
  1. 实现步骤
    • 在控制器类上添加 @Validated 注解。
    • 在方法参数前添加 @Valid 注解,对列表中的每个元素进行校验。
    • 处理校验异常,提供友好的错误信息。
  2. 优点:代码简洁,充分利用 Spring 的校验机制。
  3. 缺点:需要处理特定的校验异常。

三、代码示例

手动校验
@PostMapping("/admin/product/batchUpdate")
public APIResponse batchUpdateProduct(@RequestBody List<UpdateProductRequest> updateRequests) {for (UpdateProductRequest updateRequest : updateRequests) {if (updateRequest.getPrice() < 1) {throw new ImMoreException("价格过低");}if (updateRequest.getStock() > 10000) {throw new ImMoreException("库存过多");}// 其他校验逻辑}// 更新逻辑return APIResponse.success();
}
自定义列表类
public class ValidList<E> implements List<E> {private List<E> list;public ValidList(List<E> list) {this.list = list;}@Overridepublic int size() {return list.size();}// 其他 List 方法的实现public static void main(String[] args) {List<UpdateProductRequest> updateRequests = new ArrayList<>();ValidList<UpdateProductRequest> validList = new ValidList<>(updateRequests);// 校验逻辑}
}
使用 @Validated 注解
@Validated
@RestController
@RequestMapping("/admin/product")
public class ProductAdminController {@PostMapping("/batchUpdate3")public APIResponse batchUpdateProduct3(@Valid @RequestBody List<UpdateProductRequest> updateRequests) {// 更新逻辑return APIResponse.success();}
}

四、总结

本小节介绍了三种对列表参数进行校验的方法:手动校验、自定义列表类和使用 @Validated 注解。每种方法都有其优缺点,选择时需根据项目实际情况和技术选型进行权衡。手动校验适合简单场景,自定义列表类和 @Validated 注解则更适合复杂和批量校验场景。

电商功能优化与高级特性

一、功能优化

订单状态提示升级

order service impl 中,优化订单状态流转相关的异常提示:

  1. 取消订单:新增枚举 CANCEL_ORDER_STATUS,提示 “订单状态有误,付款后暂不支持取消订单”。
  2. 付款操作:新增枚举 PAY_RUN_OTHER_STATUS,提示 “仅能在未付款时付款”。
  3. 发货操作:新增枚举 DELIVER_RUN_ORDER_STATUS,提示 “仅能在付款后发货”。
  4. 完单操作:新增枚举 FINISH_RUN_ORDER_STATUS,提示 “仅能在发货后完单”。
商品图片上传优化

product admin controller 中,优化图片上传功能:

  1. 问题分析:原实现方式在服务器部署时可能因转发导致获取的 IP 不准确。
  2. 解决方案:将 IP 和端口号配置为固定值,避免动态获取。
  3. 代码调整
    • 引入配置文件中的 file.upload.uri,替换动态获取 IP 的代码。
    • 拼接图片访问地址时,使用配置的 URI 作为前缀。

二、新功能开发

订单数变化趋势图
  1. 接口开发
    • order admin controller 中新增 GET 接口 adminOrderStatistics,用于获取每日订单量统计。
    • 接口参数为 start_dateend_date,指定统计的时间范围。
  2. 服务实现
    • order service 中新增 statistics 方法,接收起始时间和结束时间作为参数。
    • 调用 order mapper 中的查询方法,获取统计数据。
  3. 数据查询与转换
    • 创建 order statistics query 类,封装查询条件。
    • order mapper 中编写 SQL 语句,使用 date_format 函数按天聚合订单数据,计算每天的订单数量。
    • 处理时区问题,确保统计结果的准确性。

三、Spring Boot 高级功能

指定配置
  1. 命令行参数:通过命令行指定配置参数,如 server.portspring.profiles.active,覆盖默认配置。
  2. 多环境配置:介绍常见的四种环境(本地开发、测试、预发、生产),根据实际需求调整配置。
热加载与调试技巧(详情)
  1. 热加载配置
    • 在 IDEA 中配置调试选项,启用热加载功能。
    • 自动编译和更新类资源,提高开发效率。
  2. 调试技巧
    • 使用断点调试,灵活控制程序执行流程。
    • 强制返回值和抛出异常,快速验证逻辑。
    • 重新加载修改后的类,实时查看代码改动效果。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/32633.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

G-Star 公益行起航,挥动开源技术点亮公益!

公益组织&#xff0c;一直是社会温暖的传递者&#xff0c;但在数字化浪潮中&#xff0c;也面临着诸多比大众想象中复杂的挑战&#xff1a;项目管理如何更高效&#xff1f;志愿者管理又该如何创新&#xff1f;宣传推广怎么才能更有影响力&#xff1f;内部管理和技术支持又该如何…

STM32-Unix时间戳

一&#xff1a;什么是时间戳 Unix时间戳&#xff08;Unix Timestamp&#xff09;是一个计数器数值&#xff0c;这个数值表示的是一个从1970年1月1日0时0分0秒开始到现在所经过的秒数&#xff0c;不考虑闰秒。 时间戳存储在一个秒计数器里&#xff0c;秒计数器为32位/64位的整…

zsh: command not found: adb 报错问题解决

哈喽小伙伴们大家好&#xff0c;我是小李&#xff0c;今天&#xff0c;我满怀信心想要在本地跑一下pda,然而&#xff0c; what? 居然报错了&#xff01;&#xff01;别逗我啊&#xff01; 好吧&#xff0c;究其原因&#xff1a;没有配置好sdk 那就配呗。 首先&#xff0c;…

嵌入式八股C语言---面向对象篇

面向对象与面向过程 面向过程 就是把整个业务逻辑分成多个步骤,每步或每一个功能都可以使用一个函数来实现面向对象 对象是类的实例化,此时一个类就内部有属性和相应的方法 封装 在C语言里实现封装就是实现一个结构体,里面包括的成员变量和函数指针,然后在构造函数中,为结构体…

Linux_17进程控制

前提回顾&#xff1a; 页表可以将无序的物理地址映射为有序的; 通过进程地址空间&#xff0c;避免将内存直接暴漏给操作系统&#xff1b; cr3寄存器存放的有当前运行进程的页表的物理地址&#xff1b; 一、查看命令行参数和环境变量的地址 因为命令行参数和环境变量都是字符…

NVIDIA k8s-device-plugin源码分析与安装部署

在《kubernetes Device Plugin原理与源码分析》一文中&#xff0c;我们从源码层面了解了kubelet侧关于device plugin逻辑的实现逻辑&#xff0c;本文以nvidia管理GPU的开源github项目k8s-device-plugin为例&#xff0c;来看看设备插件侧的实现示例。 一、Kubernetes Device Pl…

MySql索引下推(ICP)是什么?有什么用?

目录 基本介绍为什么需要索引下推&#xff1f;未引入ICP&#xff08;x&#xff09;引入ICP&#xff08;√&#xff09; 如何指导sql优化适用场景sql优化 基本介绍 索引下推&#xff08;Index Condition Pushdown, ICP&#xff09;&#xff0c;是MySQL5.6 引入的优化技术&#…

用户可免费体验!国家超算互联网平台上线阿里开源推理模型接口服

近日&#xff0c;国家超算互联网平台上线阿里巴巴开源推理模型QwQ-32B API接口服务&#xff0c;现在用户可获得免费的100万Tokens。基于国产深算智能加速卡以及全国一体化算力网&#xff0c;平台支持海量用户便捷调用QwQ-32B、DeepSeek-R1等国产开源大模型的接口服务。 了解QwQ…

大数据学习(63)- Zookeeper详解

&&大数据学习&& &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 用力所能及&#xff0c;改变世界。 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4dd;支持一下博主哦&#x1f91e; &#x1f…

【蓝桥杯python研究生组备赛】003 贪心

题目1 股票买卖 给定一个长度为 N 的数组&#xff0c;数组中的第 i 个数字表示一个给定股票在第 i 天的价格。 设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易&#xff08;多次买卖一支股票&#xff09;。 注意&#xff1a;你不能同时参与多笔交易&…

mmdet3d.models.utils的clip_sigmoid理解

Sigmoid 函数 标准的 sigmoid 函数定义为&#xff1a; 容易得出结论&#xff1a; 取值范围(0, 1) clip_sigmoid 是在标准的 sigmoid 函数基础上进行 裁剪&#xff08;clip&#xff09;&#xff0c;即对 sigmoid 输出的结果加以限制&#xff0c;避免其超出特定范围。 import …

侯捷 C++ 课程学习笔记:进阶语法之lambda表达式(二)

侯捷 C 课程学习笔记&#xff1a;进阶语法之lambda表达式&#xff08;二&#xff09; 一、捕获范围界定 1. 局部变量与函数参数 ​非静态局部变量&#xff1a;Lambda 所在作用域内定义的局部变量&#xff08;如函数内部的 int x&#xff09;会被完整复制其当前值。捕获后外部变…

有必要使用 Oracle 向量数据库吗?

向量数据库最主要的特点是让传统的只能基于具体值/关键字的数据检索&#xff0c;进化到了可以直接基于语义的数据检索。这在AI时代至关重要&#xff01; 回到标题问题&#xff1a;是否有必要使用 Oracle 向量数据库&#xff1f; 这实际还要取决于你的具体应用需求。 客观来讲…

论文解读 | AAAI'25 CoRA:基于大型语言模型权重的协作信息感知用于推荐

点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入&#xff01; 点击 阅读原文 观看作者讲解回放&#xff01; 个人信息 作者&#xff1a;刘禹廷&#xff0c;东北大学博士生 内容简介 将协作信息融入大型语言模型&#xff08;LLMs&#xff09;是一种有前景的适应推荐任务的技…

es扩容节点以后写入数据量增加1倍

背景&#xff1a; es扩容一倍的数据节点以后 写入数据量增加1倍 业务反馈业务访问量没增加。 最后定位是监控数据&#xff1a; PUT _cluster/settings {"persistent": {"xpack.monitoring.collection.enabled" : "false"} }这个索引记录的是 节…

G-Star 公益行 | 温暖相约 3.30 上海「开源×AI 赋能公益」Meetup

你是否曾想过&#xff0c;在这个数字化浪潮席卷的时代&#xff0c;公益组织如何突破技术瓶颈&#xff1f;当 AI 成为热门话题&#xff0c;它能为公益事业带来怎样的温度&#xff1f;开源的力量&#xff0c;如何让每一份善意都拥有无限可能&#xff1f; G-Star 公益行&#xff…

MySQL数据库复杂的增删改查操作

在前面的文章中&#xff0c;我们主要学习了数据库的基础知识以及基本的增删改查的操作。接下去将以一个比较实际的公司数据库为例子&#xff0c;进行讲解一些较为复杂且现时需求的例子。 基础知识&#xff1a; 一文清晰梳理Mysql 数据库基础知识_字段变动如何梳理清楚-CSDN博…

kafka-docker版

Kafka-docker版 1 概述 1.1 定义 Kafka传统定义&#xff1a; Kafka是一个分布式的基于发布/订阅模式的消息队列(MessageQucue)&#xff0c;主要应用于大数据实时处理领域。它是一个开源的分布式事件流平台( Event Streaming Platform)&#xff0c;被数千家公司用于高性能数据…

Zabbix 7.2 + Grafana 中文全自动安装ISO镜像

简介 ​ 基于Zabbix 官方的Alma Linux 8 作为基础镜像。 镜像源都改为国内大学镜像站&#xff0c;自动联网安装ZabbixGrafana。 安装中文字体、Zabbix和Grafana也配置默认中文。 Zabbix 也指定中文字体&#xff0c;绘图无乱码。 配置时区为东八区&#xff0c;Zabbix配置We…