8.10 删空间id同时删关联图片、修复bug

This commit is contained in:
zhangsan 2025-08-10 19:12:47 +08:00
parent 1a02275023
commit 44e3bd9270
11 changed files with 221 additions and 129 deletions

View File

@ -10,48 +10,91 @@ events {
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile on;
sendfile on;
keepalive_timeout 65;
# 访问日志(含握手关键头,用于排查)
log_format dbg '$remote_addr "$request" $status '
'cliUpg:$http_upgrade cliConn:$http_connection '
'upUpg:$upstream_http_upgrade upConn:$upstream_http_connection';
access_log /var/log/nginx/access.log dbg;
# ---- 动态设置 Connection只有在有 Upgrade 时才 upgrade否则 close
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
# 上游后端定义
upstream picture_backend {
server smile-picture-backend:8096;
keepalive 32;
}
# -------------------- 80 端口:可选,统一跳转到 HTTPS --------------------
server {
listen 80;
server_name _;
server_name picture.bitday.top _;
return 301 https://$host$request_uri;
}
root /usr/share/nginx/html;
# -------------------- 443 端口HTTPS + WebSocket 透传 --------------------
server {
listen 443 ssl http2;
server_name picture.bitday.top _;
# 替换为你的证书路径
ssl_certificate /etc/ssl/certs/your.crt;
ssl_certificate_key /etc/ssl/private/your.key;
# (可选)基础 SSL 设置
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
root /usr/share/nginx/html;
index index.html;
# ---------- REST API 代理 ----------
location /api/ {
proxy_pass http://picture_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
client_max_body_size 10M; # 允许上传 100MB
# 添加代理超时设置(单位:秒)
proxy_connect_timeout 600s;
proxy_send_timeout 600s;
proxy_read_timeout 600s;
}
# ---------- WebSocket 代理 ----------
# ---------- WebSocket 代理(放在 /api/ 之前) ----------
location /api/ws/ {
proxy_pass http://picture_backend;
proxy_http_version 1.1;
# 关键Upgrade / Connection 透传(动态)
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Connection $connection_upgrade;
# 透传常用头
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Origin $http_origin;
proxy_buffering off;
proxy_read_timeout 86400s;
proxy_send_timeout 600s;
proxy_connect_timeout 600s;
# (可选)显式禁止缓存
add_header Cache-Control "no-store" always;
}
# ---------- 前端路由兼容 ----------
# HTML5 history-mode找不到文件时回退到 index.html 交给前端渲染
# ---------- REST API 代理 ----------
location /api/ {
proxy_pass http://picture_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
client_max_body_size 10M; # 允许上传 10MB
proxy_connect_timeout 600s;
proxy_send_timeout 600s;
proxy_read_timeout 600s;
}
# ---------- 前端路由兼容SPA ----------
location / {
try_files $uri $uri/ /index.html;
}

View File

@ -1 +1 @@
import{_ as o,c as s,a as t,o as a}from"./index-DXhv3sfF.js";const n={},c={class:"about"};function r(_,e){return a(),s("div",c,e[0]||(e[0]=[t("h1",null,"This is an about page",-1)]))}const l=o(n,[["render",r]]);export{l as default};
import{_ as o,c as s,a as t,o as a}from"./index-DM764s2i.js";const n={},c={class:"about"};function r(_,e){return a(),s("div",c,e[0]||(e[0]=[t("h1",null,"This is an about page",-1)]))}const l=o(n,[["render",r]]);export{l as default};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 101 KiB

View File

@ -6,8 +6,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Smile云图库</title>
<meta name="description" content="Smile云图库海量图片素材免费获取">
<script type="module" crossorigin src="/assets/index-DXhv3sfF.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-DVYdPOkg.css">
<script type="module" crossorigin src="/assets/index-DM764s2i.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-Bv_ENDgz.css">
</head>
<body>
<div id="app"></div>

View File

@ -267,8 +267,8 @@ public class PictureController {
@GetMapping("/tag_category")
public BaseResponse<PictureTagCategory> listPictureTagCategory() {
PictureTagCategory pictureTagCategory = new PictureTagCategory();
List<String> tagList = Arrays.asList("热门", "搞笑", "生活", "高清", "艺术", "校园", "背景", "简历", "创意");
List<String> categoryList = Arrays.asList("模板", "电商", "表情包", "素材", "海报");
List<String> tagList = Arrays.asList("热门", "搞笑", "生活", "艺术", "校园", "学习", "简历", "游戏", "动漫");
List<String> categoryList = Arrays.asList("模板", "表情包", "素材", "原创","高清");
pictureTagCategory.setTagList(tagList);
pictureTagCategory.setCategoryList(categoryList);
return ResultUtils.success(pictureTagCategory);

View File

@ -15,6 +15,7 @@ import edu.whut.smilepicturebackend.model.entity.Space;
import edu.whut.smilepicturebackend.model.entity.User;
import edu.whut.smilepicturebackend.model.enums.SpaceLevelEnum;
import edu.whut.smilepicturebackend.model.vo.SpaceVO;
import edu.whut.smilepicturebackend.service.PictureService;
import edu.whut.smilepicturebackend.service.SpaceService;
import edu.whut.smilepicturebackend.service.UserService;
import lombok.RequiredArgsConstructor;
@ -41,6 +42,8 @@ public class SpaceController {
private final SpaceUserAuthManager spaceUserAuthManager;
private final PictureService pictureService;
@PostMapping("/add")
public BaseResponse<Long> addSpace(@RequestBody SpaceAddRequest spaceAddRequest, HttpServletRequest request) {
ThrowUtils.throwIf(spaceAddRequest == null, ErrorCode.PARAMS_ERROR);
@ -56,15 +59,16 @@ public class SpaceController {
throw new BusinessException(ErrorCode.PARAMS_ERROR);
}
User loginUser = userService.getLoginUser(request);
Long id = deleteRequest.getId();
Long spaceId = deleteRequest.getId();
// 判断是否存在
Space oldSpace = spaceService.getById(id);
Space oldSpace = spaceService.getById(spaceId);
ThrowUtils.throwIf(oldSpace == null, ErrorCode.NOT_FOUND_ERROR);
// 仅本人或者管理员可删除
spaceService.checkSpaceAuth(loginUser, oldSpace);
// 操作数据库
boolean result = spaceService.removeById(id);
boolean result = spaceService.removeById(spaceId);
ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
pictureService.deleteAllBySpaceIdAsync(spaceId);
return ResultUtils.success(true);
}
@ -152,7 +156,7 @@ public class SpaceController {
long current = spaceQueryRequest.getCurrent();
long size = spaceQueryRequest.getPageSize();
// 限制爬虫
ThrowUtils.throwIf(size > 20, ErrorCode.PARAMS_ERROR);
ThrowUtils.throwIf(size > 30, ErrorCode.PARAMS_ERROR);
// 查询数据库
Page<Space> spacePage = spaceService.page(new Page<>(current, size),
spaceService.getQueryWrapper(spaceQueryRequest));

View File

@ -151,4 +151,6 @@ public interface PictureService extends IService<Picture> {
* @param loginUser
*/
CreateOutPaintingTaskResponse createPictureOutPaintingTask(CreatePictureOutPaintingTaskRequest createPictureOutPaintingTaskRequest, User loginUser);
void deleteAllBySpaceIdAsync(Long spaceId);
}

View File

@ -701,9 +701,9 @@ public class PictureServiceImpl extends ServiceImpl<PictureMapper, Picture>
// 2. 校验空间权限
Space space = spaceService.getById(spaceId);
ThrowUtils.throwIf(space == null, ErrorCode.NOT_FOUND_ERROR, "空间不存在");
if (!space.getUserId().equals(loginUser.getId())) {
throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "没有空间访问权限");
}
// if (!space.getUserId().equals(loginUser.getId())) {
// throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "没有空间访问权限");
// }
// 3. 查询该空间下的所有图片必须要有主色调
List<Picture> pictureList = this.lambdaQuery()
.eq(Picture::getSpaceId, spaceId)
@ -798,6 +798,49 @@ public class PictureServiceImpl extends ServiceImpl<PictureMapper, Picture>
return aliYunAiApi.createOutPaintingTask(createOutPaintingTaskRequest);
}
/**
* 批量删除该spaceId下的所有图片
* @param spaceId
*/
@Override
@Async
public void deleteAllBySpaceIdAsync(Long spaceId) {
final int pageSize = 500;
long current = 1;
while (true) {
// 只查必要字段避免大对象占内存
Page<Picture> page = this.page(
new Page<>(current, pageSize),
this.lambdaQuery()
.eq(Picture::getSpaceId, spaceId)
.select(Picture::getId, Picture::getSpaceId,
Picture::getUrl, Picture::getOriginalUrl, Picture::getThumbnailUrl)
.getWrapper()
);
List<Picture> batch = page.getRecords();
if (batch.isEmpty()) break;
// 先删数据库记录
List<Long> ids = batch.stream().map(Picture::getId).toList();
boolean removed = this.removeBatchByIds(ids);
if (!removed) {
//不中断主流程记录日志继续
log.warn("removeBatchByIds failed, spaceId={}, ids={}", spaceId, ids);
}
// 再删物理文件仅当不再被其他记录引用时
for (Picture p : batch) {
cosManager.deleteIfNotBlank(p.getUrl());
cosManager.deleteIfNotBlank(p.getOriginalUrl());
cosManager.deleteIfNotBlank(p.getThumbnailUrl());
}
if (current >= page.getPages()) break;
current++;
}
log.info("deleteAllBySpaceIdAsync finished, spaceId={}", spaceId);
}
/**
* nameRule 格式图片-{序号} =>图片-1 图片-2 ...
*