完善业务闭环,实现对轮播图的管理,优化数据库表文件
This commit is contained in:
+97
@@ -0,0 +1,97 @@
|
||||
package cn.novalon.gym.manage.notify.core.domain;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public class Banner {
|
||||
|
||||
private Long id;
|
||||
private String imageUrl;
|
||||
private String title;
|
||||
private String subtitle;
|
||||
private Integer sortOrder;
|
||||
private String isActive;
|
||||
private String linkUrl;
|
||||
private LocalDateTime createdAt;
|
||||
private LocalDateTime updatedAt;
|
||||
private LocalDateTime deletedAt;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getImageUrl() {
|
||||
return imageUrl;
|
||||
}
|
||||
|
||||
public void setImageUrl(String imageUrl) {
|
||||
this.imageUrl = imageUrl;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getSubtitle() {
|
||||
return subtitle;
|
||||
}
|
||||
|
||||
public void setSubtitle(String subtitle) {
|
||||
this.subtitle = subtitle;
|
||||
}
|
||||
|
||||
public Integer getSortOrder() {
|
||||
return sortOrder;
|
||||
}
|
||||
|
||||
public void setSortOrder(Integer sortOrder) {
|
||||
this.sortOrder = sortOrder;
|
||||
}
|
||||
|
||||
public String getIsActive() {
|
||||
return isActive;
|
||||
}
|
||||
|
||||
public void setIsActive(String isActive) {
|
||||
this.isActive = isActive;
|
||||
}
|
||||
|
||||
public String getLinkUrl() {
|
||||
return linkUrl;
|
||||
}
|
||||
|
||||
public void setLinkUrl(String linkUrl) {
|
||||
this.linkUrl = linkUrl;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public void setCreatedAt(LocalDateTime createdAt) {
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
|
||||
public LocalDateTime getUpdatedAt() {
|
||||
return updatedAt;
|
||||
}
|
||||
|
||||
public void setUpdatedAt(LocalDateTime updatedAt) {
|
||||
this.updatedAt = updatedAt;
|
||||
}
|
||||
|
||||
public LocalDateTime getDeletedAt() {
|
||||
return deletedAt;
|
||||
}
|
||||
|
||||
public void setDeletedAt(LocalDateTime deletedAt) {
|
||||
this.deletedAt = deletedAt;
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package cn.novalon.gym.manage.notify.core.repository;
|
||||
|
||||
import cn.novalon.gym.manage.notify.core.domain.Banner;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public interface IBannerRepository {
|
||||
|
||||
Flux<Banner> findByDeletedAtIsNull();
|
||||
|
||||
Flux<Banner> findActiveBanners();
|
||||
|
||||
Mono<Banner> findById(Long id);
|
||||
|
||||
Mono<Banner> save(Banner banner);
|
||||
|
||||
Mono<Void> deleteByIdAndDeletedAtIsNull(Long id);
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package cn.novalon.gym.manage.notify.core.service;
|
||||
|
||||
import cn.novalon.gym.manage.notify.core.domain.Banner;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public interface IBannerService {
|
||||
|
||||
Flux<Banner> getAllBanners();
|
||||
|
||||
Flux<Banner> getActiveBanners();
|
||||
|
||||
Mono<Banner> getBannerById(Long id);
|
||||
|
||||
Mono<Banner> createBanner(Banner banner);
|
||||
|
||||
Mono<Banner> updateBanner(Long id, Banner banner);
|
||||
|
||||
Mono<Void> deleteBanner(Long id);
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
package cn.novalon.gym.manage.notify.core.service.impl;
|
||||
|
||||
import cn.novalon.gym.manage.notify.core.domain.Banner;
|
||||
import cn.novalon.gym.manage.notify.core.repository.IBannerRepository;
|
||||
import cn.novalon.gym.manage.notify.core.service.IBannerService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Service
|
||||
public class BannerServiceImpl implements IBannerService {
|
||||
|
||||
private final IBannerRepository bannerRepository;
|
||||
|
||||
public BannerServiceImpl(IBannerRepository bannerRepository) {
|
||||
this.bannerRepository = bannerRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<Banner> getAllBanners() {
|
||||
return bannerRepository.findByDeletedAtIsNull();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<Banner> getActiveBanners() {
|
||||
return bannerRepository.findActiveBanners();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Banner> getBannerById(Long id) {
|
||||
return bannerRepository.findById(id)
|
||||
.filter(banner -> banner.getDeletedAt() == null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Banner> createBanner(Banner banner) {
|
||||
banner.setCreatedAt(LocalDateTime.now());
|
||||
return bannerRepository.save(banner);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Banner> updateBanner(Long id, Banner banner) {
|
||||
return bannerRepository.findById(id)
|
||||
.flatMap(existing -> {
|
||||
if (banner.getImageUrl() != null) {
|
||||
existing.setImageUrl(banner.getImageUrl());
|
||||
}
|
||||
if (banner.getTitle() != null) {
|
||||
existing.setTitle(banner.getTitle());
|
||||
}
|
||||
if (banner.getSubtitle() != null) {
|
||||
existing.setSubtitle(banner.getSubtitle());
|
||||
}
|
||||
if (banner.getSortOrder() != null) {
|
||||
existing.setSortOrder(banner.getSortOrder());
|
||||
}
|
||||
if (banner.getIsActive() != null) {
|
||||
existing.setIsActive(banner.getIsActive());
|
||||
}
|
||||
if (banner.getLinkUrl() != null) {
|
||||
existing.setLinkUrl(banner.getLinkUrl());
|
||||
}
|
||||
existing.setUpdatedAt(LocalDateTime.now());
|
||||
return bannerRepository.save(existing);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> deleteBanner(Long id) {
|
||||
return bannerRepository.findById(id)
|
||||
.filter(banner -> banner.getDeletedAt() == null)
|
||||
.flatMap(banner -> {
|
||||
banner.setDeletedAt(LocalDateTime.now());
|
||||
return bannerRepository.save(banner);
|
||||
})
|
||||
.then();
|
||||
}
|
||||
}
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
package cn.novalon.gym.manage.notify.handler;
|
||||
|
||||
import cn.novalon.gym.manage.notify.core.domain.Banner;
|
||||
import cn.novalon.gym.manage.notify.core.service.IBannerService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.reactive.function.server.ServerRequest;
|
||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
|
||||
@Component
|
||||
@Tag(name = "轮播图管理", description = "首页轮播图相关操作")
|
||||
public class BannerHandler {
|
||||
|
||||
private final IBannerService bannerService;
|
||||
|
||||
public BannerHandler(IBannerService bannerService) {
|
||||
this.bannerService = bannerService;
|
||||
}
|
||||
|
||||
@Operation(summary = "获取所有轮播图", description = "获取系统中所有轮播图列表(按排序升序)")
|
||||
public Mono<ServerResponse> getAllBanners(ServerRequest request) {
|
||||
Flux<Banner> banners = bannerService.getAllBanners();
|
||||
return ServerResponse.ok().body(banners, Banner.class);
|
||||
}
|
||||
|
||||
@Operation(summary = "获取启用的轮播图", description = "获取所有启用状态的轮播图(按排序升序),供外部页面调用")
|
||||
public Mono<ServerResponse> getActiveBanners(ServerRequest request) {
|
||||
Flux<Banner> banners = bannerService.getActiveBanners();
|
||||
return ServerResponse.ok().body(banners, Banner.class);
|
||||
}
|
||||
|
||||
@Operation(summary = "根据ID获取轮播图", description = "根据轮播图ID获取详细信息")
|
||||
public Mono<ServerResponse> getBannerById(ServerRequest request) {
|
||||
Long id = Long.parseLong(request.pathVariable("id"));
|
||||
return bannerService.getBannerById(id)
|
||||
.flatMap(banner -> ServerResponse.ok().bodyValue(banner))
|
||||
.switchIfEmpty(ServerResponse.notFound().build());
|
||||
}
|
||||
|
||||
@Operation(summary = "创建轮播图", description = "创建新轮播图")
|
||||
public Mono<ServerResponse> createBanner(ServerRequest request) {
|
||||
return request.bodyToMono(Map.class)
|
||||
.map(this::mapToBanner)
|
||||
.filter(banner -> banner.getImageUrl() != null && !banner.getImageUrl().trim().isEmpty())
|
||||
.switchIfEmpty(Mono.error(new IllegalArgumentException("轮播图图片地址不能为空")))
|
||||
.filter(banner -> banner.getTitle() != null && !banner.getTitle().trim().isEmpty())
|
||||
.switchIfEmpty(Mono.error(new IllegalArgumentException("轮播图标题不能为空")))
|
||||
.flatMap(banner -> {
|
||||
if (banner.getSortOrder() == null) {
|
||||
banner.setSortOrder(0);
|
||||
}
|
||||
if (banner.getIsActive() == null) {
|
||||
banner.setIsActive("1");
|
||||
}
|
||||
return bannerService.createBanner(banner);
|
||||
})
|
||||
.flatMap(banner -> ServerResponse.ok().bodyValue(banner))
|
||||
.onErrorResume(IllegalArgumentException.class, ex ->
|
||||
ServerResponse.badRequest().bodyValue(Map.of(
|
||||
"code", 400,
|
||||
"message", ex.getMessage(),
|
||||
"timestamp", LocalDateTime.now()
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
@Operation(summary = "更新轮播图", description = "更新轮播图信息")
|
||||
public Mono<ServerResponse> updateBanner(ServerRequest request) {
|
||||
Long id = Long.parseLong(request.pathVariable("id"));
|
||||
return request.bodyToMono(Map.class)
|
||||
.map(this::mapToBanner)
|
||||
.flatMap(banner -> bannerService.updateBanner(id, banner))
|
||||
.flatMap(banner -> ServerResponse.ok().bodyValue(banner))
|
||||
.switchIfEmpty(ServerResponse.notFound().build());
|
||||
}
|
||||
|
||||
@Operation(summary = "删除轮播图", description = "删除指定轮播图(软删除)")
|
||||
public Mono<ServerResponse> deleteBanner(ServerRequest request) {
|
||||
Long id = Long.parseLong(request.pathVariable("id"));
|
||||
return bannerService.getBannerById(id)
|
||||
.filter(banner -> banner.getDeletedAt() == null)
|
||||
.flatMap(banner -> bannerService.deleteBanner(id)
|
||||
.then(ServerResponse.noContent().build()))
|
||||
.switchIfEmpty(ServerResponse.notFound().build());
|
||||
}
|
||||
|
||||
/**
|
||||
* 将前端传来的 Map 转换为 Banner 领域对象
|
||||
* 兼容 isActive 以 boolean 或 string 形式传入
|
||||
*/
|
||||
private Banner mapToBanner(Map<String, Object> body) {
|
||||
Banner banner = new Banner();
|
||||
banner.setImageUrl((String) body.get("imageUrl"));
|
||||
banner.setTitle((String) body.get("title"));
|
||||
banner.setSubtitle((String) body.get("subtitle"));
|
||||
banner.setLinkUrl((String) body.get("linkUrl"));
|
||||
|
||||
// sortOrder 处理
|
||||
Object sortOrderObj = body.get("sortOrder");
|
||||
if (sortOrderObj instanceof Number) {
|
||||
banner.setSortOrder(((Number) sortOrderObj).intValue());
|
||||
}
|
||||
|
||||
// isActive 兼容 boolean 和 string
|
||||
Object isActiveObj = body.get("isActive");
|
||||
if (isActiveObj instanceof Boolean) {
|
||||
banner.setIsActive((Boolean) isActiveObj ? "1" : "0");
|
||||
} else if (isActiveObj instanceof String) {
|
||||
banner.setIsActive((String) isActiveObj);
|
||||
}
|
||||
|
||||
return banner;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user