文章目录

一、图片功能
- application.properties 配置上传文件路径配置图片本地存储路径和静态资源映射。
bash
## 图片服务 ##
pic.local-path=D:/PIC
# spring boot3 升级配置名
spring.web.resources.static-locations=classpath:/static/,file:${pic.local-path}
注意:
- 如果访问的本地路径,需要添加配置项:spring.web.resources.static-locations(spring boot 3升级过配置名,原本为spring.resources.static-locations)
- 访问静态资源不做拦截: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}prizePic:Obj-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)和输入框回车跳转功能。