diff --git a/pom.xml b/pom.xml index 6c0c137..7b7ec21 100644 --- a/pom.xml +++ b/pom.xml @@ -93,11 +93,6 @@ runtime true - - - - - com.mysql mysql-connector-j @@ -170,6 +165,17 @@ mysql test + + org.apache.poi + poi-ooxml + 5.2.3 + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + diff --git a/src/main/java/org/cmh/backend/Config/SecurityConfig.java b/src/main/java/org/cmh/backend/Config/SecurityConfig.java index c917d0a..c5a4336 100644 --- a/src/main/java/org/cmh/backend/Config/SecurityConfig.java +++ b/src/main/java/org/cmh/backend/Config/SecurityConfig.java @@ -4,6 +4,8 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; @Configuration @@ -11,13 +13,22 @@ public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { - // Use the new API to disable CSRF + // Disable CSRF http.csrf(AbstractHttpConfigurer::disable) - // Permit all requests + // Permit all requests to all endpoints .authorizeHttpRequests(authorize -> authorize - .anyRequest().permitAll() - ); + .anyRequest().permitAll() // Allow all requests without authentication + ) + // Disable form login + .formLogin(AbstractHttpConfigurer::disable) + // Disable logout + .logout(AbstractHttpConfigurer::disable); return http.build(); } + + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } } diff --git a/src/main/java/org/cmh/backend/CourseManagement/controller/CourseController.java b/src/main/java/org/cmh/backend/CourseManagement/controller/CourseController.java new file mode 100644 index 0000000..a386572 --- /dev/null +++ b/src/main/java/org/cmh/backend/CourseManagement/controller/CourseController.java @@ -0,0 +1,138 @@ +package org.cmh.backend.CourseManagement.controller; + +import org.cmh.backend.CourseManagement.dto.GetCourseListResponse; +import org.cmh.backend.CourseManagement.dto.MessageResponse; +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.service.CourseService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import jakarta.persistence.EntityNotFoundException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@RestController +@RequestMapping("/courses") +public class CourseController { + + private static final Logger logger = LoggerFactory.getLogger(CourseController.class); + + @Autowired + private CourseService courseService; + + @GetMapping + public ResponseEntity getCoursesByRange(@RequestParam Integer start, @RequestParam Integer end, @RequestParam String token) { + if (start >= end) { + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + long courseCount = courseService.getCourseCount(); + return new ResponseEntity<>(new GetCourseListResponse(courseCount, courseService.getCoursesByRange(start, end)), HttpStatus.OK); + } + + @GetMapping("/{id}") + public ResponseEntity getCoursePage(@PathVariable Long id, @RequestParam String token) { + try { + return new ResponseEntity<>(courseService.getCourseById(id), HttpStatus.OK); + } catch (EntityNotFoundException e) { + logger.error("Course not found with id: {}", id, e); + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + } + + @PostMapping + public ResponseEntity createCourse(@RequestBody CourseRequest request) { + try { + courseService.createCourse(request); + } catch (DataIntegrityViolationException e) { + logger.error("Create course failed: Data integrity violation", e); + return new ResponseEntity<>(new MessageResponse("创建失败,课程已存在或缺少字段"), HttpStatus.BAD_REQUEST); + } 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("创建成功"), HttpStatus.CREATED); + } + + @PutMapping("/{id}") + public ResponseEntity updateCourse(@PathVariable Long id, @RequestBody CourseRequest request) { + try { + courseService.updateCourse(id, request); + } catch (DataIntegrityViolationException e) { + logger.error("Update course failed: Data integrity violation", e); + 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) { + logger.error("Update course failed: {}", e.getMessage(), e); + return new ResponseEntity<>(new MessageResponse("修改失败:" + e.getMessage()), HttpStatus.BAD_REQUEST); + } + return new ResponseEntity<>(new MessageResponse("修改成功"), HttpStatus.OK); + } + + @DeleteMapping("/{id}") + public ResponseEntity deleteCourse(@PathVariable Long id, @RequestParam String token) { + try { + courseService.deleteCourse(id); + } catch (EntityNotFoundException e) { + logger.error("Course not found with id: {}", id, e); + 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); + } + + @GetMapping("/search") + public ResponseEntity 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 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); + } + } + @GetMapping("/sort") + public ResponseEntity sortCourses(@RequestParam String token, + @RequestParam String sortField, + @RequestParam String sortDirection, + @RequestParam Integer start, + @RequestParam Integer end) { + if (start >= end) { + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + + try { + long courseCount = courseService.getCourseCount(); + List sortedCourses = courseService.sortCourses(sortField, sortDirection, start, end); + + return new ResponseEntity<>(new GetCourseListResponse(courseCount, sortedCourses), HttpStatus.OK); + } catch (Exception e) { + logger.error("Sort courses failed with parameters: sortField={}, sortDirection={}, start={}, end={}", + sortField, sortDirection, start, end, e); + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); + } + } +} \ No newline at end of file diff --git a/src/main/java/org/cmh/backend/CourseManagement/controller/CourseFileController.java b/src/main/java/org/cmh/backend/CourseManagement/controller/CourseFileController.java new file mode 100644 index 0000000..94cbf38 --- /dev/null +++ b/src/main/java/org/cmh/backend/CourseManagement/controller/CourseFileController.java @@ -0,0 +1,64 @@ +package org.cmh.backend.CourseManagement.controller; + +import org.cmh.backend.CourseManagement.dto.UploadFileResponse; +import org.springframework.core.io.UrlResource; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.core.io.Resource; +import org.springframework.web.multipart.MultipartFile; + + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +@RestController +@RequestMapping("/courses") +public class CourseFileController { + private static final String UPLOAD_DIR = "uploads/"; + + @PostMapping("/upload") + public ResponseEntity uploadFile(@RequestParam("file") MultipartFile file) { + if (file.isEmpty()) { + return new ResponseEntity<>(new UploadFileResponse("文件不能为空", null), HttpStatus.BAD_REQUEST); + } + + try { + // 确保上传目录存在 + Path uploadDirPath = Paths.get(UPLOAD_DIR); + if (!Files.exists(uploadDirPath)) { + Files.createDirectories(uploadDirPath); + } + + // 生成文件路径 + byte[] bytes = file.getBytes(); + Path path = Paths.get(UPLOAD_DIR + file.getOriginalFilename()); + Files.write(path, bytes); + + // 返回成功信息 + return new ResponseEntity<>(new UploadFileResponse("文件上传成功", "/api/courses/files/" + file.getOriginalFilename()), HttpStatus.OK); + } catch (IOException e) { + return new ResponseEntity<>(new UploadFileResponse("文件上传失败", null), HttpStatus.INTERNAL_SERVER_ERROR); + } + } + @GetMapping("/files/{filename}") + public ResponseEntity getFile(@PathVariable String filename) { + try { + Path filePath = Paths.get(UPLOAD_DIR).resolve(filename).normalize(); + Resource resource = new UrlResource(filePath.toUri()); + + if (resource.exists() && resource.isReadable()) { + return ResponseEntity.ok() + .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"") + .body(resource); + } else { + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + } catch (Exception e) { + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); + } + } +} diff --git a/src/main/java/org/cmh/backend/CourseManagement/dto/CourseRequest.java b/src/main/java/org/cmh/backend/CourseManagement/dto/CourseRequest.java new file mode 100644 index 0000000..86b1ff7 --- /dev/null +++ b/src/main/java/org/cmh/backend/CourseManagement/dto/CourseRequest.java @@ -0,0 +1,16 @@ +package org.cmh.backend.CourseManagement.dto; + +import lombok.Getter; +import lombok.Setter; +import org.cmh.backend.Utils.JwtRequest; + +@Getter +@Setter +public class CourseRequest extends JwtRequest { + private String title; + private String description; + private String orderNo; + private String author; + private String videoPath; + private String imagePath; +} \ No newline at end of file diff --git a/src/main/java/org/cmh/backend/CourseManagement/dto/GetCourseListResponse.java b/src/main/java/org/cmh/backend/CourseManagement/dto/GetCourseListResponse.java new file mode 100644 index 0000000..8e9d3d9 --- /dev/null +++ b/src/main/java/org/cmh/backend/CourseManagement/dto/GetCourseListResponse.java @@ -0,0 +1,16 @@ +package org.cmh.backend.CourseManagement.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; +import org.cmh.backend.CourseManagement.model.Course; + +import java.util.List; + +@Getter +@Setter +@AllArgsConstructor +public class GetCourseListResponse { + Long courseCount; + List courseList; +} \ No newline at end of file diff --git a/src/main/java/org/cmh/backend/CourseManagement/dto/MessageResponse.java b/src/main/java/org/cmh/backend/CourseManagement/dto/MessageResponse.java new file mode 100644 index 0000000..92a14fa --- /dev/null +++ b/src/main/java/org/cmh/backend/CourseManagement/dto/MessageResponse.java @@ -0,0 +1,12 @@ +package org.cmh.backend.CourseManagement.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +public class MessageResponse { + String message; +} \ No newline at end of file diff --git a/src/main/java/org/cmh/backend/CourseManagement/dto/SearchCourseRequest.java b/src/main/java/org/cmh/backend/CourseManagement/dto/SearchCourseRequest.java new file mode 100644 index 0000000..aac0c93 --- /dev/null +++ b/src/main/java/org/cmh/backend/CourseManagement/dto/SearchCourseRequest.java @@ -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; +} \ No newline at end of file diff --git a/src/main/java/org/cmh/backend/CourseManagement/dto/UploadFileResponse.java b/src/main/java/org/cmh/backend/CourseManagement/dto/UploadFileResponse.java new file mode 100644 index 0000000..2a8edb3 --- /dev/null +++ b/src/main/java/org/cmh/backend/CourseManagement/dto/UploadFileResponse.java @@ -0,0 +1,15 @@ +package org.cmh.backend.CourseManagement.dto; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class UploadFileResponse extends MessageResponse { + private String url; + + public UploadFileResponse(String message, String url) { + super(message); + this.url = url; + } +} diff --git a/src/main/java/org/cmh/backend/CourseManagement/model/Course.java b/src/main/java/org/cmh/backend/CourseManagement/model/Course.java new file mode 100644 index 0000000..137fae8 --- /dev/null +++ b/src/main/java/org/cmh/backend/CourseManagement/model/Course.java @@ -0,0 +1,21 @@ +package org.cmh.backend.CourseManagement.model; + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; + +@Entity +@Getter +@Setter +public class Course { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String title; + private String description; + private String orderNo; + private String author; + private String videoPath; + private String imagePath; +} \ No newline at end of file diff --git a/src/main/java/org/cmh/backend/CourseManagement/repository/CourseRepository.java b/src/main/java/org/cmh/backend/CourseManagement/repository/CourseRepository.java new file mode 100644 index 0000000..40e0281 --- /dev/null +++ b/src/main/java/org/cmh/backend/CourseManagement/repository/CourseRepository.java @@ -0,0 +1,13 @@ +package org.cmh.backend.CourseManagement.repository; + +import org.cmh.backend.CourseManagement.model.Course; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +@Repository +public interface CourseRepository extends JpaRepository, JpaSpecificationExecutor { + Page findAllByOrderByIdDesc(Pageable pageable); +} \ No newline at end of file diff --git a/src/main/java/org/cmh/backend/CourseManagement/service/CourseService.java b/src/main/java/org/cmh/backend/CourseManagement/service/CourseService.java new file mode 100644 index 0000000..3e00d0f --- /dev/null +++ b/src/main/java/org/cmh/backend/CourseManagement/service/CourseService.java @@ -0,0 +1,82 @@ +package org.cmh.backend.CourseManagement.service; + +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.repository.CourseRepository; +import org.cmh.backend.CourseManagement.specification.CourseSpecification; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import jakarta.persistence.EntityNotFoundException; +import java.util.List; + +@Service +public class CourseService { + + @Autowired + private CourseRepository courseRepository; + + public long getCourseCount() { + return courseRepository.count(); + } + + public List getCoursesByRange(int start, int end) { + Pageable pageable = PageRequest.of(start, end - start); + return courseRepository.findAll(pageable).getContent(); + } + + public Course getCourseById(Long id) { + return courseRepository.findById(id).orElseThrow(() -> new EntityNotFoundException("Course not found")); + } + + public void createCourse(CourseRequest request) { + Course course = new Course(); + course.setTitle(request.getTitle()); + course.setAuthor(request.getAuthor()); + course.setDescription(request.getDescription()); + course.setOrderNo(request.getOrderNo()); + course.setVideoPath(request.getVideoPath()); // 确保保存视频路径 + course.setImagePath(request.getImagePath()); // 确保保存图片路径 + courseRepository.save(course); + } + + public void updateCourse(Long id, CourseRequest request) { + Course course = courseRepository.findById(id).orElseThrow(() -> new EntityNotFoundException("Course not found")); + course.setTitle(request.getTitle()); + course.setAuthor(request.getAuthor()); + course.setDescription(request.getDescription()); + course.setOrderNo(request.getOrderNo()); + course.setVideoPath(request.getVideoPath()); // 确保更新视频路径 + course.setImagePath(request.getImagePath()); // 确保更新图片路径 + courseRepository.save(course); + } + + public void deleteCourse(Long id) { + courseRepository.deleteById(id); + } + + public List searchCourses(SearchCourseRequest request) { + Pageable pageable = PageRequest.of(request.getStart(), request.getEnd() - request.getStart()); + return courseRepository.findAll( + CourseSpecification.searchCourses( + request.getTitle(), + request.getAuthor(), + request.getDescription(), + request.getSortOrder() + ), + pageable + ).getContent(); + } + public long getCourseCountByCriteria(String title, String author, String description, String sortOrder) { + return courseRepository.count(CourseSpecification.searchCourses(title, author, description, sortOrder)); + } + public List sortCourses(String sortField, String sortDirection, int start, int end) { + Pageable pageable = PageRequest.of(start, end - start); + return courseRepository.findAll( + CourseSpecification.sortCourses(sortField, sortDirection), + pageable + ).getContent(); + } +} \ No newline at end of file diff --git a/src/main/java/org/cmh/backend/CourseManagement/specification/CourseSpecification.java b/src/main/java/org/cmh/backend/CourseManagement/specification/CourseSpecification.java new file mode 100644 index 0000000..23411a4 --- /dev/null +++ b/src/main/java/org/cmh/backend/CourseManagement/specification/CourseSpecification.java @@ -0,0 +1,44 @@ +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 searchCourses( + String title, String author, String description, String sortOrder) { + + return (root, query, criteriaBuilder) -> { + List 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])); + }; + } + public static Specification sortCourses(String sortField, String sortDirection) { + return (root, query, cb) -> { + if ("asc".equalsIgnoreCase(sortDirection)) { + query.orderBy(cb.asc(root.get(sortField))); + } else if ("desc".equalsIgnoreCase(sortDirection)) { + query.orderBy(cb.desc(root.get(sortField))); + } + return cb.conjunction(); + }; + } +} \ No newline at end of file diff --git a/src/main/java/org/cmh/backend/MeetingManagement/controller/MeetingController.java b/src/main/java/org/cmh/backend/MeetingManagement/controller/MeetingController.java new file mode 100644 index 0000000..349c2ce --- /dev/null +++ b/src/main/java/org/cmh/backend/MeetingManagement/controller/MeetingController.java @@ -0,0 +1,153 @@ +package org.cmh.backend.MeetingManagement.controller; + +import org.cmh.backend.MeetingManagement.model.Meeting; +import org.cmh.backend.MeetingManagement.service.MeetingService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.Map; + + +@RestController +@RequestMapping("/meetings") +public class MeetingController { + + @Autowired + private MeetingService meetingService; + + private final DateTimeFormatter formatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME; + + @GetMapping("/listAll") + public ResponseEntity> listAll() { + List data = meetingService.getAllMeetings(); + return ResponseEntity.ok(data); + } + + @PostMapping("/addMeeting") + public ResponseEntity add(@RequestBody Map credentials) { + try { + Meeting meeting = new Meeting(); + if (credentials.get("id") != null) { + meeting.setId(Long.parseLong(credentials.get("id"))); + } + meeting.setName(credentials.get("name")); + meeting.setOrganizer(credentials.get("organizer")); + + // Parse startTime and endTime to OffsetDateTime, then convert to LocalDateTime + OffsetDateTime startTime = OffsetDateTime.parse(credentials.get("startTime"), formatter); + OffsetDateTime endTime = OffsetDateTime.parse(credentials.get("endTime"), formatter); + meeting.setStartTime(startTime.toLocalDateTime()); + meeting.setEndTime(endTime.toLocalDateTime()); + + meeting.setContent(credentials.get("content")); + meeting.setStatus(credentials.get("status")); + + Meeting meetingAdd = meetingService.createMeeting(meeting); + return new ResponseEntity<>(meetingAdd, HttpStatus.CREATED); + } catch (Exception e) { + return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST); + } + } + + @PostMapping("/deleteMeeting") + public ResponseEntity delete(@RequestBody Map credentials) { + try { + meetingService.deleteMeeting(Long.valueOf(credentials.get("id"))); + return new ResponseEntity<>("success", HttpStatus.OK); + } catch (Exception e) { + return new ResponseEntity<>("failure", HttpStatus.BAD_REQUEST); + } + } + + + @PostMapping("/updateMeeting") + public ResponseEntity update(@RequestBody Map credentials) { + try { + // Validate and parse id + String idStr = credentials.get("id"); + if (idStr == null || idStr.isEmpty()) { + throw new IllegalArgumentException("ID cannot be null or empty"); + } + Long id = Long.parseLong(idStr); + + // Validate and parse other fields + String name = credentials.get("name"); + if (name == null || name.isEmpty()) { + throw new IllegalArgumentException("Name cannot be null or empty"); + } + + String organizer = credentials.get("organizer"); + if (organizer == null || organizer.isEmpty()) { + throw new IllegalArgumentException("Organizer cannot be null or empty"); + } + + String startTimeStr = credentials.get("startTime"); + if (startTimeStr == null || startTimeStr.isEmpty()) { + throw new IllegalArgumentException("Start time cannot be null or empty"); + } + LocalDateTime startTime = LocalDateTime.parse(startTimeStr, DateTimeFormatter.ISO_LOCAL_DATE_TIME); + + String endTimeStr = credentials.get("endTime"); + if (endTimeStr == null || endTimeStr.isEmpty()) { + throw new IllegalArgumentException("End time cannot be null or empty"); + } + LocalDateTime endTime = LocalDateTime.parse(endTimeStr, DateTimeFormatter.ISO_LOCAL_DATE_TIME); + + String content = credentials.get("content"); + if (content == null || content.isEmpty()) { + throw new IllegalArgumentException("Content cannot be null or empty"); + } + + String status = credentials.get("status"); + if (status == null || status.isEmpty()) { + throw new IllegalArgumentException("Status cannot be null or empty"); + } + + // Create and update meeting + Meeting meeting = new Meeting(); + meeting.setId(id); + meeting.setName(name); + meeting.setOrganizer(organizer); + meeting.setStartTime(startTime); + meeting.setEndTime(endTime); + meeting.setContent(content); + meeting.setStatus(status); + + Meeting updatedMeeting = meetingService.updateMeeting(meeting.getId(), meeting); + return new ResponseEntity<>(updatedMeeting, HttpStatus.OK); + } catch (IllegalArgumentException e) { + return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST); + } catch (Exception e) { + return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + @PostMapping("/getMeetingById") + public ResponseEntity getById(@RequestBody Map credentials) { + try { + Meeting meeting = meetingService.getMeetingById(Long.valueOf(credentials.get("id"))).orElse(null); + return new ResponseEntity<>(meeting, HttpStatus.OK); + } catch (Exception e) { + return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST); + } + } + + @PostMapping("/searchMeetings") + public ResponseEntity> searchMeetings(@RequestBody Map params) { + String name = params.get("name"); + String organizer = params.get("organizer"); + OffsetDateTime startTimeStr = OffsetDateTime.parse(params.get("startTime"), formatter); + LocalDateTime startTime1 = (startTimeStr.toLocalDateTime()); + //LocalDateTime startTime = startTimeStr != null ? LocalDateTime.parse(startTimeStr) : null; + + List meetings = meetingService.searchMeetings(name, organizer, startTime1); + return new ResponseEntity<>(meetings, HttpStatus.OK); + } + +} \ No newline at end of file diff --git a/src/main/java/org/cmh/backend/MeetingManagement/model/Meeting.java b/src/main/java/org/cmh/backend/MeetingManagement/model/Meeting.java new file mode 100644 index 0000000..ff06aef --- /dev/null +++ b/src/main/java/org/cmh/backend/MeetingManagement/model/Meeting.java @@ -0,0 +1,48 @@ +package org.cmh.backend.MeetingManagement.model; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import lombok.Getter; +import lombok.Setter; +import java.time.LocalDateTime; + +@Setter +@Getter +@Entity +public class Meeting { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + private String name; + private String organizer; + private LocalDateTime startTime; // Changed to LocalDateTime + private LocalDateTime endTime; // Changed to LocalDateTime + private String content; + private String status; + + public Meeting() {} + + public Meeting(String name, String organizer, LocalDateTime startTime, LocalDateTime endTime, String content, String status) { + this.name = name; + this.organizer = organizer; + this.startTime = startTime; + this.endTime = endTime; + this.content = content; + this.status = status; + } + + @Override + public String toString() { + return "Meeting{" + + "id=" + id + + ", name='" + name + '\'' + + ", organizer='" + organizer + '\'' + + ", startTime=" + startTime + + ", endTime=" + endTime + + ", content='" + content + '\'' + + ", status='" + status + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/src/main/java/org/cmh/backend/MeetingManagement/repository/MeetingRepository.java b/src/main/java/org/cmh/backend/MeetingManagement/repository/MeetingRepository.java new file mode 100644 index 0000000..20a987c --- /dev/null +++ b/src/main/java/org/cmh/backend/MeetingManagement/repository/MeetingRepository.java @@ -0,0 +1,15 @@ +package org.cmh.backend.MeetingManagement.repository; + +import org.cmh.backend.MeetingManagement.model.Meeting; +import org.springframework.data.jpa.repository.JpaRepository; +import java.time.LocalDateTime; +import java.util.List; +import org.springframework.data.jpa.repository.Query; + +public interface MeetingRepository extends JpaRepository { + @Query("SELECT m FROM Meeting m WHERE " + + "(?1 IS NULL OR m.name LIKE %?1%) AND " + + "(?2 IS NULL OR m.organizer LIKE %?2%) AND " + + "(?3 IS NULL OR m.startTime >= ?3)") + List searchMeetings(String name, String organizer, LocalDateTime startTime); +} diff --git a/src/main/java/org/cmh/backend/MeetingManagement/service/MeetingService.java b/src/main/java/org/cmh/backend/MeetingManagement/service/MeetingService.java new file mode 100644 index 0000000..b9de395 --- /dev/null +++ b/src/main/java/org/cmh/backend/MeetingManagement/service/MeetingService.java @@ -0,0 +1,74 @@ +package org.cmh.backend.MeetingManagement.service; + +import org.cmh.backend.MeetingManagement.model.Meeting; +import org.cmh.backend.MeetingManagement.repository.MeetingRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Optional; + +@Service +public class MeetingService { + @Autowired + private MeetingRepository meetingRepository; + + public List getAllMeetings() { + return meetingRepository.findAll(); + } + + public Optional getMeetingById(Long id) { + return meetingRepository.findById(id); + } + + public Meeting createMeeting(Meeting meeting) { + validateMeeting(meeting); + return meetingRepository.save(meeting); + } + + public Meeting updateMeeting(Long id, Meeting meetingDetails) { + validateMeeting(meetingDetails); + Meeting meeting = meetingRepository.findById(id) + .orElseThrow(() -> new RuntimeException("Meeting not found with id " + id)); + meeting.setName(meetingDetails.getName()); + meeting.setOrganizer(meetingDetails.getOrganizer()); + meeting.setStartTime(meetingDetails.getStartTime()); + meeting.setEndTime(meetingDetails.getEndTime()); + meeting.setContent(meetingDetails.getContent()); + meeting.setStatus(meetingDetails.getStatus()); + return meetingRepository.save(meeting); + } + + public void deleteMeeting(Long id) { + Meeting meeting = meetingRepository.findById(id) + .orElseThrow(() -> new RuntimeException("Meeting not found with id " + id)); + meetingRepository.delete(meeting); + } + + private void validateMeeting(Meeting meeting) { + if (meeting.getName() == null || meeting.getName().isEmpty()) { + throw new RuntimeException("会议名称不能为空"); + } + if (meeting.getOrganizer() == null || meeting.getOrganizer().isEmpty()) { + throw new RuntimeException("组织者不能为空"); + } + if (meeting.getStartTime() == null) { + throw new RuntimeException("开始时间不能为空"); + } + if (meeting.getEndTime() == null) { + throw new RuntimeException("结束时间不能为空"); + } + if (meeting.getStatus() == null || meeting.getStatus().isEmpty()) { + throw new RuntimeException("状态不能为空"); + } + } + + + public List searchMeetings(String name, String organizer, LocalDateTime startTime) { + // 根据条件搜索会议 + return meetingRepository.searchMeetings(name, organizer, startTime); + } + } + + diff --git a/src/main/java/org/cmh/backend/NewsManagement/controller/FileController.java b/src/main/java/org/cmh/backend/NewsManagement/controller/NewsFileController.java similarity index 92% rename from src/main/java/org/cmh/backend/NewsManagement/controller/FileController.java rename to src/main/java/org/cmh/backend/NewsManagement/controller/NewsFileController.java index b48660a..16eb41d 100644 --- a/src/main/java/org/cmh/backend/NewsManagement/controller/FileController.java +++ b/src/main/java/org/cmh/backend/NewsManagement/controller/NewsFileController.java @@ -15,12 +15,12 @@ import java.nio.file.Path; import java.nio.file.Paths; @RestController -@CrossOrigin // 如果前端和后端不在同一个域名或端口下,需要启用跨域 -public class FileController { +@RequestMapping("/news") +public class NewsFileController { private static final String UPLOAD_DIR = "uploads/"; - @PostMapping("/news/uploadPic") + @PostMapping("/uploadPic") public ResponseEntity uploadFile(@RequestParam("file") MultipartFile file) { if (file.isEmpty()) { return new ResponseEntity<>(new UploadFileResponse("文件不能为空", null), HttpStatus.BAD_REQUEST); @@ -45,7 +45,7 @@ public class FileController { } } - @GetMapping("/news/files/{filename}") + @GetMapping("/files/{filename}") public ResponseEntity getFile(@PathVariable String filename) { try { Path filePath = Paths.get(UPLOAD_DIR).resolve(filename).normalize(); diff --git a/src/main/java/org/cmh/backend/authentication/dto/ProfileResponse.java b/src/main/java/org/cmh/backend/authentication/dto/ProfileResponse.java new file mode 100644 index 0000000..d60fed8 --- /dev/null +++ b/src/main/java/org/cmh/backend/authentication/dto/ProfileResponse.java @@ -0,0 +1,19 @@ +package org.cmh.backend.authentication.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +import java.time.LocalDateTime; + +@Getter +@Setter +@AllArgsConstructor +public class ProfileResponse { + private String username; + private String email; + private String role; + private String phoneNumber; + private String company; + private LocalDateTime createdDate; +} diff --git a/src/main/java/org/cmh/backend/authentication/dto/UpdateRequest.java b/src/main/java/org/cmh/backend/authentication/dto/UpdateRequest.java new file mode 100644 index 0000000..9ba3ea3 --- /dev/null +++ b/src/main/java/org/cmh/backend/authentication/dto/UpdateRequest.java @@ -0,0 +1,15 @@ +package org.cmh.backend.authentication.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +public class UpdateRequest { + private String username; + private String email; + private String phoneNumber; + private String company; +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 2a38a12..3cd6354 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -23,7 +23,8 @@ server.servlet.encoding.charset=utf-8 # verificationCode verification.code.images.path=src/main/resources/static/verificationCodeImages # set the max size of a single file -spring.servlet.multipart.max-file-size=50MB +spring.servlet.multipart.max-file-size=500MB # set the max size of the total request -spring.servlet.multipart.max-request-size=50MB +spring.servlet.multipart.max-request-size=500MB + diff --git a/src/test/java/org/cmh/backend/BackendApplicationTests.java b/src/test/java/org/cmh/backend/BackendApplicationTests.java deleted file mode 100644 index 8bc26ca..0000000 --- a/src/test/java/org/cmh/backend/BackendApplicationTests.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.cmh.backend; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.annotation.Import; - -@Import(TestcontainersConfiguration.class) -@SpringBootTest -class BackendApplicationTests { - - @Test - void contextLoads() { - } - -} diff --git a/src/test/java/org/cmh/backend/TestBackendApplication.java b/src/test/java/org/cmh/backend/TestBackendApplication.java deleted file mode 100644 index a752147..0000000 --- a/src/test/java/org/cmh/backend/TestBackendApplication.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.cmh.backend; - -import org.springframework.boot.SpringApplication; - -public class TestBackendApplication { - - public static void main(String[] args) { - SpringApplication.from(BackendApplication::main).with(TestcontainersConfiguration.class).run(args); - } - -} diff --git a/src/test/java/org/cmh/backend/TestcontainersConfiguration.java b/src/test/java/org/cmh/backend/TestcontainersConfiguration.java deleted file mode 100644 index 27f9122..0000000 --- a/src/test/java/org/cmh/backend/TestcontainersConfiguration.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.cmh.backend; - -import org.springframework.boot.test.context.TestConfiguration; -import org.springframework.boot.testcontainers.service.connection.ServiceConnection; -import org.springframework.context.annotation.Bean; -import org.testcontainers.containers.MariaDBContainer; -import org.testcontainers.containers.MySQLContainer; -import org.testcontainers.utility.DockerImageName; - -@TestConfiguration(proxyBeanMethods = false) -class TestcontainersConfiguration { - - @Bean - @ServiceConnection - MariaDBContainer mariaDbContainer() { - return new MariaDBContainer<>(DockerImageName.parse("mariadb:latest")); - } - - @Bean - @ServiceConnection - MySQLContainer mysqlContainer() { - return new MySQLContainer<>(DockerImageName.parse("mysql:latest")); - } - -} diff --git a/src/test/java/org/cmh/backend/Utils/JwtVerifyAspectTest.java b/src/test/java/org/cmh/backend/Utils/JwtVerifyAspectTest.java deleted file mode 100644 index 22b12e1..0000000 --- a/src/test/java/org/cmh/backend/Utils/JwtVerifyAspectTest.java +++ /dev/null @@ -1,88 +0,0 @@ -package org.cmh.backend.Utils; - -import org.cmh.backend.authentication.service.UserService; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.runner.RunWith; -import org.mockito.InjectMocks; -import org.mockito.Mockito; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.EnableAspectJAutoProxy; -import org.springframework.context.annotation.Import; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -public class JwtVerifyAspectTest { - - @Configuration - @EnableAspectJAutoProxy - @Import({JwtVerifyAspect.class}) - static class Config { - @Bean - public JwtUtil jwtUtil() { - return Mockito.mock(JwtUtil.class); - } - - @Bean - public UserService userService() { - return Mockito.mock(UserService.class); - } - } - - private JwtUtil jwtUtil = new JwtUtil(); - - @InjectMocks - private JwtVerifyAspect jwtVerifyAspect; - - @BeforeClass - public static void setUpClass() { - // Static setup if needed - } - - @Before - public void setUp() { - Mockito.when(jwtUtil.isTokenValid("validToken")).thenReturn(true); - Mockito.when(jwtUtil.isTokenValid("invalidToken")).thenReturn(false); - } - - // TODO:这个测试跑不动,有问题,先取消掉 -// @Test -// public void testVerify() { -// SomeController validTokenController = new SomeController("validToken"); -// SomeController invalidTokenController = new SomeController("invalidToken"); -// -// Assert.assertTrue("Valid token should pass verification", validTokenController.run()); -// Assert.assertFalse("Invalid token should fail verification", invalidTokenController.run()); -// } -} - -class SomeController { - private SomeJwtRequest request; - - SomeController(String token) { - this.request = new SomeJwtRequest(token, "test"); - } - - public boolean run() { - try { - return verify(request); - } catch (JwtValidationException e) { - return false; - } - } - - @JwtVerify - public boolean verify(SomeJwtRequest request) { - return true; - } -} - -class SomeJwtRequest extends JwtRequest { - String msg; - - public SomeJwtRequest(String token, String msg) { - super.setToken(token); - this.msg = msg; - } -} \ No newline at end of file