package com.kaidi.oa.web; import com.kaidi.oa.common.ApiException; import com.kaidi.oa.common.ApiResp; import com.kaidi.oa.common.HtmlSanitizer; import com.kaidi.oa.common.NotFoundException; import com.kaidi.oa.domain.Announcement; import com.kaidi.oa.repository.AnnouncementRepository; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.time.Instant; import java.util.List; /** News / announcements. category is one of 新闻 / 公告. */ @RestController @RequestMapping("/api/oa/announcements") public class AnnouncementController { private final AnnouncementRepository announcementRepo; public AnnouncementController(AnnouncementRepository announcementRepo) { this.announcementRepo = announcementRepo; } @GetMapping public ApiResp> list( @RequestParam(required = false) String category, @RequestParam(defaultValue = "0") int pageNo, @RequestParam(defaultValue = "200") int pageSize) { List list = (category == null || category.isBlank()) ? announcementRepo.findAllByOrderByTopDescPublishedAtDesc() : announcementRepo.findByCategoryOrderByTopDescPublishedAtDesc(category); return ApiResp.ok(page(list, pageNo, pageSize)); } /** 内存切片:pageNo 从 0 起;pageSize<=0 取默认 200、超过 500 截为 500,避免全表载入。 */ private static final int DEFAULT_PAGE_SIZE = 200; private static final int MAX_PAGE_SIZE = 500; private static List page(List list, int pageNo, int pageSize) { if (pageSize <= 0) { pageSize = DEFAULT_PAGE_SIZE; } else if (pageSize > MAX_PAGE_SIZE) { pageSize = MAX_PAGE_SIZE; } long fromL = (long) Math.max(0, pageNo) * pageSize; if (fromL >= list.size()) { return List.of(); } int from = (int) fromL; return list.subList(from, Math.min(from + pageSize, list.size())); } @GetMapping("/{id}") public ApiResp get(@PathVariable Long id) { return ApiResp.ok(announcementRepo.findById(id) .orElseThrow(() -> new NotFoundException("announcement not found: " + id))); } public record CreateAnnouncementRequest( String category, String title, String content, String author, Boolean top, String publishRange) { } @PostMapping public ApiResp create(@RequestBody CreateAnnouncementRequest req) { if (req.title() == null || req.title().isBlank()) { throw new ApiException(400, "title is required"); } Announcement a = new Announcement(); a.setCategory(req.category() == null ? "公告" : req.category()); a.setTitle(req.title()); a.setContent(HtmlSanitizer.sanitize(req.content())); a.setAuthor(req.author()); a.setTop(Boolean.TRUE.equals(req.top())); a.setPublishRange(req.publishRange()); a.setPublishedAt(Instant.now()); return ApiResp.ok(announcementRepo.save(a)); } public record UpdateAnnouncementRequest(String title, String content, String category, String publishRange) { } /** PUT /{id} -> 编辑已发布的新闻/公告 (title/content/category/publishRange)。 */ @PutMapping("/{id}") public ApiResp update(@PathVariable Long id, @RequestBody UpdateAnnouncementRequest req) { Announcement a = announcementRepo.findById(id) .orElseThrow(() -> new NotFoundException("announcement not found: " + id)); if (req.title() != null) { if (req.title().isBlank()) { throw new ApiException(400, "标题不能为空"); } a.setTitle(req.title().trim()); } if (req.content() != null) a.setContent(HtmlSanitizer.sanitize(req.content())); if (req.category() != null) a.setCategory(req.category()); if (req.publishRange() != null) a.setPublishRange(req.publishRange()); return ApiResp.ok(announcementRepo.save(a)); } /** DELETE /{id} -> 撤回新闻/公告。 */ @DeleteMapping("/{id}") public ApiResp delete(@PathVariable Long id) { if (!announcementRepo.existsById(id)) { throw new NotFoundException("announcement not found: " + id); } announcementRepo.deleteById(id); return ApiResp.ok(null); } }