完善了搜索功能

This commit is contained in:
Chester.X 2024-07-05 14:02:31 +08:00
parent d027e26f8c
commit c42a3a55ec
5 changed files with 135 additions and 63 deletions

View File

@ -1,26 +1,32 @@
package org.cmh.backend.CourseManagement.controller; package org.cmh.backend.CourseManagement.controller;
import jakarta.persistence.EntityNotFoundException;
import org.cmh.backend.CourseManagement.dto.GetCourseListResponse; import org.cmh.backend.CourseManagement.dto.GetCourseListResponse;
import org.cmh.backend.CourseManagement.dto.MessageResponse; import org.cmh.backend.CourseManagement.dto.MessageResponse;
import org.cmh.backend.CourseManagement.dto.CourseRequest; import org.cmh.backend.CourseManagement.dto.CourseRequest;
import org.cmh.backend.CourseManagement.dto.SearchCourseRequest;
import org.cmh.backend.CourseManagement.model.Course; import org.cmh.backend.CourseManagement.model.Course;
import org.cmh.backend.CourseManagement.service.CourseService; import org.cmh.backend.CourseManagement.service.CourseService;
import org.cmh.backend.Utils.JwtVerify;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException; import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.util.List;
import jakarta.persistence.EntityNotFoundException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@RestController @RestController
@RequestMapping("/courses") @RequestMapping("/courses")
public class CourseController { public class CourseController {
private static final Logger logger = LoggerFactory.getLogger(CourseController.class);
@Autowired @Autowired
private CourseService courseService; private CourseService courseService;
@GetMapping @GetMapping
// @JwtVerify
public ResponseEntity<GetCourseListResponse> getCoursesByRange(@RequestParam Integer start, @RequestParam Integer end, @RequestParam String token) { public ResponseEntity<GetCourseListResponse> getCoursesByRange(@RequestParam Integer start, @RequestParam Integer end, @RequestParam String token) {
if (start >= end) { if (start >= end) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST); return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
@ -30,49 +36,82 @@ public class CourseController {
} }
@GetMapping("/{id}") @GetMapping("/{id}")
// @JwtVerify
public ResponseEntity<Course> getCoursePage(@PathVariable Long id, @RequestParam String token) { public ResponseEntity<Course> getCoursePage(@PathVariable Long id, @RequestParam String token) {
try { try {
return new ResponseEntity<>(courseService.getCourseById(id), HttpStatus.OK); return new ResponseEntity<>(courseService.getCourseById(id), HttpStatus.OK);
} catch (EntityNotFoundException e) { } catch (EntityNotFoundException e) {
logger.error("Course not found with id: {}", id, e);
return new ResponseEntity<>(HttpStatus.NOT_FOUND); return new ResponseEntity<>(HttpStatus.NOT_FOUND);
} }
} }
@PostMapping @PostMapping
// @JwtVerify
public ResponseEntity<MessageResponse> createCourse(@RequestBody CourseRequest request) { public ResponseEntity<MessageResponse> createCourse(@RequestBody CourseRequest request) {
try { try {
courseService.createCourse(request); courseService.createCourse(request);
} catch (DataIntegrityViolationException e) { } catch (DataIntegrityViolationException e) {
logger.error("Create course failed: Data integrity violation", e);
return new ResponseEntity<>(new MessageResponse("创建失败,课程已存在或缺少字段"), HttpStatus.BAD_REQUEST); return new ResponseEntity<>(new MessageResponse("创建失败,课程已存在或缺少字段"), HttpStatus.BAD_REQUEST);
} catch (Exception e) { } catch (Exception e) {
logger.error("Create course failed: {}", e.getMessage(), e);
return new ResponseEntity<>(new MessageResponse("创建失败:" + e.getMessage()), HttpStatus.BAD_REQUEST); return new ResponseEntity<>(new MessageResponse("创建失败:" + e.getMessage()), HttpStatus.BAD_REQUEST);
} }
return new ResponseEntity<>(new MessageResponse("创建成功"), HttpStatus.CREATED); return new ResponseEntity<>(new MessageResponse("创建成功"), HttpStatus.CREATED);
} }
@PutMapping("/{id}") @PutMapping("/{id}")
// @JwtVerify
public ResponseEntity<MessageResponse> updateCourse(@PathVariable Long id, @RequestBody CourseRequest request) { public ResponseEntity<MessageResponse> updateCourse(@PathVariable Long id, @RequestBody CourseRequest request) {
try { try {
courseService.updateCourse(id, request); courseService.updateCourse(id, request);
} catch (DataIntegrityViolationException e) { } catch (DataIntegrityViolationException e) {
logger.error("Update course failed: Data integrity violation", e);
return new ResponseEntity<>(new MessageResponse("修改失败,新标题已存在或缺少字段"), HttpStatus.BAD_REQUEST); return new ResponseEntity<>(new MessageResponse("修改失败,新标题已存在或缺少字段"), HttpStatus.BAD_REQUEST);
} catch (EntityNotFoundException e) {
logger.error("Course not found with id: {}", id, e);
return new ResponseEntity<>(new MessageResponse("修改失败: 课程不存在"), HttpStatus.NOT_FOUND);
} catch (Exception e) { } catch (Exception e) {
logger.error("Update course failed: {}", e.getMessage(), e);
return new ResponseEntity<>(new MessageResponse("修改失败:" + e.getMessage()), HttpStatus.BAD_REQUEST); return new ResponseEntity<>(new MessageResponse("修改失败:" + e.getMessage()), HttpStatus.BAD_REQUEST);
} }
return new ResponseEntity<>(new MessageResponse("修改成功"), HttpStatus.OK); return new ResponseEntity<>(new MessageResponse("修改成功"), HttpStatus.OK);
} }
@DeleteMapping("/{id}") @DeleteMapping("/{id}")
// @JwtVerify
public ResponseEntity<MessageResponse> deleteCourse(@PathVariable Long id, @RequestParam String token) { public ResponseEntity<MessageResponse> deleteCourse(@PathVariable Long id, @RequestParam String token) {
try { try {
courseService.deleteCourse(id); courseService.deleteCourse(id);
} catch (EntityNotFoundException e) { } catch (EntityNotFoundException e) {
logger.error("Course not found with id: {}", id, e);
return new ResponseEntity<>(new MessageResponse("删除失败,课程不存在"), HttpStatus.BAD_REQUEST); return new ResponseEntity<>(new MessageResponse("删除失败,课程不存在"), HttpStatus.BAD_REQUEST);
} catch (Exception e) {
logger.error("Delete course failed: {}", e.getMessage(), e);
return new ResponseEntity<>(new MessageResponse("删除失败:" + e.getMessage()), HttpStatus.BAD_REQUEST);
} }
return new ResponseEntity<>(new MessageResponse("删除成功"), HttpStatus.OK); return new ResponseEntity<>(new MessageResponse("删除成功"), HttpStatus.OK);
} }
@GetMapping("/search")
public ResponseEntity<GetCourseListResponse> searchCourses(@RequestParam String token,
@RequestParam(required = false) String title,
@RequestParam(required = false) String author,
@RequestParam(required = false) String description,
@RequestParam(required = false) String sortOrder,
@RequestParam Integer start,
@RequestParam Integer end) {
if (start >= end) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
try {
SearchCourseRequest request = new SearchCourseRequest(token, title, author, description, sortOrder, start, end);
List<Course> courses = courseService.searchCourses(request);
long courseCount = courseService.getCourseCountByCriteria(title, author, description, sortOrder);
return new ResponseEntity<>(new GetCourseListResponse(courseCount, courses), HttpStatus.OK);
} catch (Exception e) {
logger.error("Search courses failed with parameters: title={}, author={}, description={}, sortOrder={}, start={}, end={}",
title, author, description, sortOrder, start, end, e);
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
} }

View File

@ -0,0 +1,18 @@
package org.cmh.backend.CourseManagement.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@AllArgsConstructor
public class SearchCourseRequest {
private String token;
private String title;
private String author;
private String description;
private String sortOrder;
private int start;
private int end;
}

View File

@ -4,7 +4,10 @@ import org.cmh.backend.CourseManagement.model.Course;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface CourseRepository extends JpaRepository<Course, Long> { @Repository
public interface CourseRepository extends JpaRepository<Course, Long>, JpaSpecificationExecutor<Course> {
Page<Course> findAllByOrderByIdDesc(Pageable pageable); Page<Course> findAllByOrderByIdDesc(Pageable pageable);
} }

View File

@ -1,94 +1,72 @@
package org.cmh.backend.CourseManagement.service; package org.cmh.backend.CourseManagement.service;
import jakarta.persistence.EntityNotFoundException;
import org.cmh.backend.CourseManagement.dto.CourseRequest; import org.cmh.backend.CourseManagement.dto.CourseRequest;
import org.cmh.backend.CourseManagement.dto.SearchCourseRequest;
import org.cmh.backend.CourseManagement.model.Course; import org.cmh.backend.CourseManagement.model.Course;
import org.cmh.backend.CourseManagement.repository.CourseRepository; import org.cmh.backend.CourseManagement.repository.CourseRepository;
import org.cmh.backend.CourseManagement.specification.CourseSpecification;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import jakarta.persistence.EntityNotFoundException;
import java.util.ArrayList;
import java.util.List; import java.util.List;
@Service @Service
public class CourseService { public class CourseService {
@Autowired @Autowired
private CourseRepository courseRepository; private CourseRepository courseRepository;
public long getCourseCount() {
return courseRepository.count();
}
public List<Course> getCoursesByRange(int start, int end) { public List<Course> getCoursesByRange(int start, int end) {
if (start < 0 || end <= start) { Pageable pageable = PageRequest.of(start, end - start);
throw new IllegalArgumentException("Invalid start or end range"); return courseRepository.findAll(pageable).getContent();
} }
int pageSize = end - start; // 计算每页的大小 public Course getCourseById(Long id) {
int startPageNumber = start / pageSize; // 计算起始页码 return courseRepository.findById(id).orElseThrow(() -> new EntityNotFoundException("Course not found"));
int endPageNumber = (end - 1) / pageSize; // 计算结束页码
List<Course> result = new ArrayList<>();
for (int pageNumber = startPageNumber; pageNumber <= endPageNumber; pageNumber++) {
Pageable pageable = PageRequest.of(pageNumber, pageSize);
Page<Course> coursePage = courseRepository.findAllByOrderByIdDesc(pageable);
if (coursePage.hasContent()) {
result.addAll(coursePage.getContent());
} else {
break; // 如果没有更多内容提前退出
}
}
int startIndex = start % pageSize;
int endIndex = startIndex + (end - start);
if (endIndex > result.size()) {
endIndex = result.size();
}
return result.subList(startIndex, endIndex);
} }
public void createCourse(CourseRequest request) { public void createCourse(CourseRequest request) {
Course course = new Course(); Course course = new Course();
course.setTitle(request.getTitle()); course.setTitle(request.getTitle());
course.setAuthor(request.getAuthor());
course.setDescription(request.getDescription()); course.setDescription(request.getDescription());
course.setOrderNo(request.getOrderNo()); course.setOrderNo(request.getOrderNo());
course.setAuthor(request.getAuthor());
course.setVideoPath(request.getVideoPath());
course.setImagePath(request.getImagePath());
courseRepository.save(course); courseRepository.save(course);
} }
public void updateCourse(Long id, CourseRequest request) { public void updateCourse(Long id, CourseRequest request) {
Course course = courseRepository.findById(id).orElse(null); Course course = courseRepository.findById(id).orElseThrow(() -> new EntityNotFoundException("Course not found"));
if (course != null) { course.setTitle(request.getTitle());
course.setTitle(request.getTitle()); course.setAuthor(request.getAuthor());
course.setDescription(request.getDescription()); course.setDescription(request.getDescription());
course.setOrderNo(request.getOrderNo()); course.setOrderNo(request.getOrderNo());
course.setAuthor(request.getAuthor()); courseRepository.save(course);
course.setVideoPath(request.getVideoPath());
course.setImagePath(request.getImagePath());
courseRepository.save(course);
}
} }
public void deleteCourse(Long id) { public void deleteCourse(Long id) {
if (!courseRepository.existsById(id)) {
throw new EntityNotFoundException();
}
courseRepository.deleteById(id); courseRepository.deleteById(id);
} }
public Course getCourseById(Long id) { public List<Course> searchCourses(SearchCourseRequest request) {
if (!courseRepository.existsById(id)) { Pageable pageable = PageRequest.of(request.getStart(), request.getEnd() - request.getStart());
throw new EntityNotFoundException(); return courseRepository.findAll(
} CourseSpecification.searchCourses(
return courseRepository.findById(id).orElse(null); request.getTitle(),
request.getAuthor(),
request.getDescription(),
request.getSortOrder()
),
pageable
).getContent();
} }
public long getCourseCount() { public long getCourseCountByCriteria(String title, String author, String description, String sortOrder) {
return courseRepository.count(); return courseRepository.count(CourseSpecification.searchCourses(title, author, description, sortOrder));
} }
} }

View File

@ -0,0 +1,34 @@
package org.cmh.backend.CourseManagement.specification;
import org.cmh.backend.CourseManagement.model.Course;
import org.springframework.data.jpa.domain.Specification;
import jakarta.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.List;
public class CourseSpecification {
public static Specification<Course> searchCourses(
String title, String author, String description, String sortOrder) {
return (root, query, criteriaBuilder) -> {
List<Predicate> predicates = new ArrayList<>();
if (title != null && !title.isEmpty()) {
predicates.add(criteriaBuilder.like(root.get("title"), "%" + title + "%"));
}
if (author != null && !author.isEmpty()) {
predicates.add(criteriaBuilder.like(root.get("author"), "%" + author + "%"));
}
if (description != null && !description.isEmpty()) {
predicates.add(criteriaBuilder.like(root.get("description"), "%" + description + "%"));
}
if (sortOrder != null && !sortOrder.isEmpty()) {
predicates.add(criteriaBuilder.like(root.get("orderNo"), "%" + sortOrder+ "%"));
}
return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
};
}
}