【抽奖系统开发实战】Spring Boot 项目的奖品模块开发:文件上传、时序设计与奖品创建

文章目录

    • 一、图片功能
    • 二、创建奖品
      • [2.1 时序图](#2.1 时序图)
      • [2.2 约定前后端交互接口](#2.2 约定前后端交互接口)
      • [2.3 前端实现](#2.3 前端实现)
      • [2.4 使用@RequestPart注解出现的错误](#2.4 使用@RequestPart注解出现的错误)
    • 三、奖品列表展示
      • [3.1 时序图](#3.1 时序图)
      • [3.2 约定前后端交互接口](#3.2 约定前后端交互接口)
      • [3.3 奖品列表页面前端实现](#3.3 奖品列表页面前端实现)

一、图片功能

  • application.properties 配置上传文件路径配置图片本地存储路径和静态资源映射。
bash 复制代码
## 图片服务 ##
pic.local-path=D:/PIC
# spring boot3 升级配置名
spring.web.resources.static-locations=classpath:/static/,file:${pic.local-path}

注意:

  1. 如果访问的本地路径,需要添加配置项:spring.web.resources.static-locations(spring boot 3升级过配置名,原本为spring.resources.static-locations)
  2. 访问静态资源不做拦截:AppConfig类中excludes新增"/*.jpg"

图片服务PictureService接口定义 定义保存图片的接口,接收MultipartFile文件,返回保存后的文件名。

接口实现

实现保存图片的逻辑:

  • 检查本地目录是否存在,不存在则创建。
  • 获取原始文件名和后缀。
  • 使用UUID生成新的文件名,防止重名。
  • 调用MultipartFile的transferTo方法将文件保存到指定路径。
  • 返回新文件名。

接口实现示例:

java 复制代码
/**
 * 保存图片
 */
@Service
public class PictureServiceImpl implements PictureService {

    @Value("${pic.local-path}")
    private String localPath;

    @Override
    public String savePicture(MultipartFile multipartFile) {

        // 创建目录
        File dir = new File(localPath);
        if(!dir.exists()){
            dir.mkdirs();
        }
        // 创建索引

        // 1. 获取文件全名称
        String filename = multipartFile.getOriginalFilename();
        assert filename != null;

        // 2. 拿到文件后缀
        String suffix = filename.substring(
                filename.lastIndexOf("."));

        // 3. 生成索引
        filename = UUID.randomUUID() + suffix;

        // 图片保存
        try {
            multipartFile.transferTo(new File(localPath + "/" + filename));
        } catch (IOException e) {
            throw new ServiceException(ServiceErrorCodeConstants.PIC_UPLOAD_ERROR);
        }
        return filename;
    }
}

二、创建奖品

2.1 时序图

2.2 约定前后端交互接口

请求

  • 接口地址:/prize/create
  • 请求方式:POST
  • 请求参数:
    • param{"prizeName":"吹风机","description":"吹风机","price":100}
    • prizePicObj-C.jpg(文件类型)

响应

json 复制代码
{
    "code": 200,
    "data": 17,
    "msg": ""
}

Controller层接口设计

  • 使用@RequestPart分别接收JSON参数(CreatePrizeParam)和图片文件(MultipartFile)。
  • 调用PrizeService的createPrize方法,并返回结果。
  • CreatePrizeParam:定义接收参数的实体类,包含奖品名称、描述和价值,并使用了参数校验注解。

Service层接口设计:定义PrizeService接口,包含创建奖品的方法。

接口实现

  • 实现createPrize方法。
  • 将参数封装为PrizeDO对象。
  • 调用PictureService保存图片,获取文件名。
  • 将图片URL设置到PrizeDO中。
  • 调用PrizeMapper的insert方法将奖品信息存入数据库。
  • 返回新生成的奖品ID。

接口实现示例:

java 复制代码
@Service
public class PrizeServiceImpl implements PrizeService {

    @Autowired
    private PrizeMapper prizeMapper;

    @Autowired
    private PictureService pictureService;

    /**
     * 创建奖品
     *
     * @param param 奖品属性
     * @param picFile 奖品图片
     * @return 返回奖品ID
     */
    @Override
    public Long createPrize(CreatePrizeParam param, MultipartFile picFile) {
        // 上传图片
        String fileName = pictureService.savePicture(picFile);
        // 存储库中
        PrizeDO prizeDO = new PrizeDO();
        prizeDO.setName(param.getPrizeName());
        prizeDO.setDescription(param.getDescription());
        prizeDO.setImageUrl(fileName);
        prizeDO.setPrice(param.getPrice());

        prizeMapper.insert(prizeDO);

        return prizeDO.getId();
    }
}

Dao层接口设计

  • 使用@Mapper定义PrizeMapper接口。
  • 提供@Insert方法插入PrizeDO,并使用@Options获取自增主键。

2.3 前端实现

前端页面使用jQuery和AJAX实现创建奖品的流程:

  • 获取用户token。
  • 创建FormData对象,添加奖品参数(JSON字符串)和图片文件。
  • 发送POST请求到/prize/create,设置请求头user_token
  • 成功或失败时给出相应提示。

2.4 使用@RequestPart注解出现的错误

  • 问题描述:前端请求创建奖品时,后端解析MultipartFile报错Content type 'application/octet-stream' not supported,但Postman测试正常。
  • 原因分析:请求的content-type可能为null,被默认设置为application/octet-stream,而Spring没有定义该类型的messageConverter。
  • 解决方案:自定义一个MultipartJackson2HttpMessageConverter,继承AbstractJackson2HttpMessageConverter,并指定其支持MediaType.APPLICATION_OCTET_STREAM,同时覆盖canWrite方法返回false,使其只用于读取。

三、奖品列表展示

3.1 时序图

3.2 约定前后端交互接口

请求

  • 接口地址:/prize/find-list
  • 请求方式:GET
  • 请求参数:
    • currentPage=1:当前页码
    • pageSize=10:每页记录数

响应

json 复制代码
{
    "code": 200,
    "data": {
        "total": 3,
        "records": [
            {
                "prizeId": 17,
                "prizeName": "吹风机",
                "description": "吹风机",
                "price": 100,
                "imageUrl": "d11fa79c-9cfb-46b9-8fb6-3226ba1ff6d6.jpg"
            }
        ]
    },
    "msg": ""
}

Controller层接口设计

  • 接收PageListParam参数(包含currentPage和pageSize)。
  • 调用PrizeService的findPrizeList方法,返回PageListDTO。
  • 将PageListDTO转换为FindPrizeListResult对象返回给前端。

Service层接口设计:在PrizeService中新增翻页查询奖品列表的方法。

接口实现

  • 实现findPrizeList方法。
  • 调用PrizeMapper的count方法获取总记录数。
  • 调用PrizeMapper的queryPrizeByPage方法,传入offset和pageSize获取当前页的PrizeDO列表。
  • 将PrizeDO列表转换为PrizeDTO列表。
  • 封装成PageListDTO对象返回。

接口实现示例:

java 复制代码
	/**
     * 返回奖品当前页列表和奖品总量
     *
     * @param param
     * @return
     */
    @Override
    public PageListDTO<PrizeDTO> findPrizeList(PageParam param) {

        // 设置总量
        int total = prizeMapper.selectPrizeCount();

        // 查询列表
        List<PrizeDTO> prizeDTOList = new ArrayList<>();

        List<PrizeDO> prizeDOList = prizeMapper.selectPrizeList(param.offset(),param.getPageSize());

        for (PrizeDO prizeDO : prizeDOList){
            PrizeDTO prizeDTO = new PrizeDTO();
            prizeDTO.setPrizeId(prizeDO.getId());
            prizeDTO.setDescription(prizeDO.getDescription());
            prizeDTO.setName(prizeDO.getName());
            prizeDTO.setPrice(prizeDO.getPrice());
            prizeDTO.setImageUrl(prizeDO.getImageUrl());
            prizeDTOList.add(prizeDTO);
        }
        return new PageListDTO<>(total,prizeDTOList);
    }

Dao层接口设计

在PrizeMapper中新增翻页查询所需的方法:

  • int count(); 获取总记录数。
  • List<PrizeDO> queryPrizesByPage(); 根据偏移量和页大小查询奖品列表。

3.3 奖品列表页面前端实现

前端页面使用jQuery和AJAX实现翻页展示奖品列表的流程:

  • 定义全局变量currentPage、pageSize、totalPages。
  • 创建fetchPrizes(page)函数,发送GET请求到/prize/find-list
  • 成功时,清空表格,遍历result.data.records生成表格行,并更新分页信息。
  • 实现上一页(previousPage)、下一页(nextPage)和输入框回车跳转功能。
相关推荐
东离与糖宝2 小时前
告别AI投毒!Java后端实现大模型prompt过滤与敏感信息拦截实战
java·人工智能
饕餮争锋2 小时前
Supabase 简介
后端·开源
yashuk2 小时前
怎么下载安装yarn
java
23.2 小时前
【Java】Arrays工具类——数组操作终极指南
java·算法·面试
ok_hahaha2 小时前
java从头开始-苍穹外卖-day12-数据统计以及excel报表
java
好家伙VCC2 小时前
# Deno实战:从零搭建一个安全、现代的后端服务在Node.js生态逐渐臃肿
java·python·安全·node.js
littlegirll2 小时前
一个KADB报错分析及实验
java·javascript·数据库
常利兵2 小时前
打造Spring Boot接口护盾:防重提交与限流秘籍
java·spring boot·后端
Hvitur2 小时前
解决报错:eclipse报错:LSP (Spring Boot Language Server)
spring boot·eclipse·里氏替换原则