Compare commits

...

103 Commits

Author SHA1 Message Date
2049f5f87d 修复了totalnum显示错误的问题 2024-07-06 15:07:25 +08:00
5b83c56f58 修复修改和删除 2024-07-06 14:53:04 +08:00
2b34113ab2 我的图片也送上去吧,太美了家人们 2024-07-06 09:21:58 +08:00
99862678e7 改完了,真改完了 2024-07-06 09:20:55 +08:00
5747e255e9 改! 2024-07-06 07:19:31 +08:00
f51a66073b 完善tenant权限相关 2024-07-06 06:15:11 +08:00
47bbdca5af 为管理员添加了动态加载租户options的功能 2024-07-06 01:54:12 +08:00
8f2fc48ad8 正式开始使用tenant字段,修改getNewsByRange 2024-07-06 01:19:47 +08:00
7834754dd3 Merge remote-tracking branch 'origin/merge/1' into merge/1 2024-07-06 00:19:20 +08:00
8c0283e96f 没有修改 2024-07-06 00:17:55 +08:00
546f0cce2d 尝试进行分权 2024-07-06 00:15:34 +08:00
554a0893c3 征询本人意见后删除了meetingController中的无效方法 2024-07-06 00:11:14 +08:00
8b12bb4201 Merge remote-tracking branch 'origin/MeetingByJerry' into merge/1
# Conflicts:
#	src/main/java/org/cmh/backend/authentication/repository/UserRepository.java
#	src/main/java/org/cmh/backend/authentication/service/UserService.java
2024-07-06 00:06:32 +08:00
50bfce4b23 微调了俩fileController避免冲突 2024-07-06 00:02:50 +08:00
8728f7f454 Merge remote-tracking branch 'origin/Chester' into merge/1
# Conflicts:
#	src/main/java/org/cmh/backend/authentication/controller/AuthenticationController.java
#	src/main/java/org/cmh/backend/authentication/controller/UserController.java
#	src/main/java/org/cmh/backend/authentication/dto/LoginRequest.java
#	src/main/java/org/cmh/backend/authentication/dto/RegisterResponse.java
#	src/main/java/org/cmh/backend/authentication/model/User.java
#	src/main/java/org/cmh/backend/authentication/repository/UserRepository.java
#	src/main/java/org/cmh/backend/authentication/service/UserService.java
#	src/main/resources/application.properties
2024-07-05 23:59:21 +08:00
b2a7f8b6eb 这里分权限进行不同请求 2024-07-05 23:50:20 +08:00
cff3b43983 添加getAllUsers和getUsersByTenant方法 2024-07-05 23:48:00 +08:00
82cb9d79ba 添加了一点点注释 2024-07-05 23:43:42 +08:00
fd65ed2c60 添加了一点点注释,/getAll那里还有问题 2024-07-05 23:41:19 +08:00
83d6713e93 Merge remote-tracking branch 'origin/merge/1' into merge/1
# Conflicts:
#	src/main/java/org/cmh/backend/UserManagement/controller/UserManagementController.java
2024-07-05 23:39:31 +08:00
a57b4be921 删除crossOrigin,添加总RequestMapping 2024-07-05 23:36:52 +08:00
fca88ffd68 删除OrganizationController中的无效依赖 2024-07-05 23:36:18 +08:00
e14bbcd2f8 Merge remote-tracking branch 'origin/merge/1' into merge/1 2024-07-05 23:35:56 +08:00
722fb47302 尝试修改User 2024-07-05 23:35:45 +08:00
2f57ff6a4c 修改了delete方法 2024-07-05 23:35:28 +08:00
ac677f1728 对User中的注释的无关紧要的修改 2024-07-05 23:35:05 +08:00
cdc1cefd85 添加了addUser和deleteUser的方法 2024-07-05 23:08:33 +08:00
1a42273465 Merge remote-tracking branch 'origin/personal/pjq/organization' into merge/1
# Conflicts:
#	src/main/java/org/cmh/backend/authentication/controller/AuthenticationController.java
#	src/main/java/org/cmh/backend/authentication/repository/UserRepository.java
#	src/main/java/org/cmh/backend/authentication/service/UserService.java
2024-07-05 21:02:22 +08:00
18966c0a93 添加了tenant字段 2024-07-05 20:55:02 +08:00
6643a7bdbb 去掉了外键约束 2024-07-05 20:51:13 +08:00
ba638747df 外键约束 2024-07-05 20:21:27 +08:00
ffa9189583 标准化租户表 2024-07-05 19:31:25 +08:00
ba886c7191 还剩测试没做 2024-07-05 19:18:41 +08:00
8b25a92b77 Merge branch 'personal/heshunme/news' into merge 2024-07-05 17:20:47 +08:00
11c548e7bd 临时改名避免冲突 2024-07-05 17:07:54 +08:00
afdcfa60fb Merge branch 'personal/lsd/UserManagement' into merge
# Conflicts:
#	src/main/java/org/cmh/backend/authentication/controller/AuthenticationController.java
#	src/main/java/org/cmh/backend/authentication/repository/UserRepository.java
#	src/main/java/org/cmh/backend/authentication/service/UserService.java
2024-07-05 17:05:31 +08:00
76ca17cf41 删除/移动auth相关内容 2024-07-05 17:04:51 +08:00
7a6d2b5c4b recovery 2024-07-05 16:32:33 +08:00
05f3af0c77 基本完成 2024-07-05 14:40:15 +08:00
c42a3a55ec 完善了搜索功能 2024-07-05 14:02:31 +08:00
33f811e6b7 GPT牛逼,搜索搞成了 2024-07-05 06:20:30 +08:00
9e03bb3873 能搜了,就是有点问题,范围太广,啥都搜到了 2024-07-05 06:11:11 +08:00
f104c89d08 初步添加了用户权限区别对待。 2024-07-05 02:21:59 +08:00
d027e26f8c 完善了删除功能 2024-07-05 01:52:46 +08:00
f9272335f2 修改了其他模块中的order字段名为orderNo 2024-07-04 23:05:42 +08:00
5885f365db 修改了order字段名为orderNo 2024-07-04 23:02:49 +08:00
780e4793de 去掉了verify 2024-07-04 22:51:24 +08:00
f6d5112ad5 更新了CourseController 2024-07-04 22:50:35 +08:00
dafdf82f5d 更新了Course相关dto 2024-07-04 22:50:11 +08:00
aae8147143 修改了全局文件上传大小限制 2024-07-04 22:49:48 +08:00
fe58248efc 完成了Course的相关支持 2024-07-04 22:49:05 +08:00
9569a30a8a 完成了文件上传的Controller 2024-07-04 22:47:52 +08:00
ef10067345 2 2024-07-04 21:21:46 +08:00
d1fa646f95 后端完成版(也许? 2024-07-04 20:50:16 +08:00
54f055dea9 只有组织管理模块.新 2024-07-04 17:37:53 +08:00
bdba24dc26 Revert "只有组织管理模块"
This reverts commit 9fb75be5ab.
2024-07-04 17:35:47 +08:00
9fb75be5ab 只有组织管理模块 2024-07-04 17:33:15 +08:00
aa8ca4e274 solve conflict 2024-07-04 17:26:39 +08:00
d2e3443c40 Merge remote-tracking branch 'origin/main'
# Conflicts:
#	src/main/java/org/cmh/backend/authentication/controller/UserController.java
2024-07-04 17:16:30 +08:00
1e874606f3 完成组织管理(测试用) 2024-07-04 17:09:24 +08:00
ecf466716a 完成组织管理 2024-07-04 17:09:24 +08:00
187a5afbc2 基本的组织管理完成 2024-07-04 17:09:24 +08:00
d9f54774bd 登录功能基础完成 2024-07-04 17:09:24 +08:00
bac47d9749 添加了注册功能,但User中username意义不够明确,想改成accout,此版作备份用 2024-07-04 17:09:23 +08:00
bdc19166a3 merge main& solve conflict 2024-07-04 17:09:00 +08:00
73d8b5452f Merge remote-tracking branch 'origin/main' into MeetingByJerry
# Conflicts:
#	src/main/java/org/cmh/backend/authentication/controller/UserController.java
2024-07-04 16:53:18 +08:00
2c12fc075f getNewsPage加了jwtVerify 2024-07-04 16:42:06 +08:00
ed0cde6968 添加了漏加的service中保存租户的逻辑 2024-07-04 16:41:36 +08:00
c0c6fed086 除生成表格功能外其他功能正常 2024-07-04 15:46:48 +08:00
e66695cbff 为了适应前端的列表动态加载,添加了getNewsByRange及其相关内容。 2024-07-04 12:20:04 +08:00
9de8c77764 Merge branch 'main' into personal/heshunme/news 2024-07-04 00:36:19 +08:00
30344b2162 添加了图片上传的后端支持 2024-07-04 00:33:49 +08:00
431ef62c12 添加了getById的请求方法 2024-07-04 00:33:32 +08:00
9056250574 添加租户字段,在联系上外键之前暂且设为字符串 2024-07-04 00:33:06 +08:00
a15f407c13 全局修改上传文件大小上限 2024-07-04 00:31:58 +08:00
2563cdbd51 回滚备份 2024-07-04 00:13:38 +08:00
1e202aa863 回滚备份 2024-07-03 20:17:31 +08:00
14dcc9de06 不知道有没有问题先提交一版 2024-07-03 15:03:37 +08:00
173b507361 删除了service中delete throw exception的message 2024-07-03 14:52:48 +08:00
fdb9dc6daf Merge branch 'main' into personal/heshunme/news 2024-07-03 14:50:24 +08:00
a38fd92801 给HttpMessageNotReadableException和MissingServletRequestParameterException指定了全局错误处理器,现在当前端发送给后端的参数不对的时候也能正确返回401错误了 2024-07-03 14:49:28 +08:00
df34d7cb28 给@JwtVerify添加了校验字符串参数的用法,现在只要有任意一个字符串参数的内容是JWT就也能校验了。 2024-07-03 14:40:25 +08:00
a4713648a2 完成了delete,尝试@JwtVerify校验字符串参数的用法 2024-07-03 14:39:05 +08:00
e4a11a8a53 Merge branch 'main' into personal/heshunme/news 2024-07-03 14:14:06 +08:00
a532eaa89c 尝试@JwtVerify的新用法 2024-07-03 14:13:05 +08:00
c4f0b2348f bugfix@JwtVerify 2024-07-03 14:12:42 +08:00
3a7b6ee605 Merge branch 'main' into personal/heshunme/news 2024-07-03 13:58:57 +08:00
a5aac1199d 升级了@JwtVerify的能力,现在被修饰的方法的任意一个参数是继承于JwtRequest的对象即可,不再强制为第一个参 2024-07-03 13:58:09 +08:00
6c36552c2f 重写了getNewsPage方法,取消了DTO,改用url参数 2024-07-03 13:53:16 +08:00
e6ba8c9a12 updateNews已完成 2024-07-03 13:48:10 +08:00
65f15eb9a9 createNews已完成 2024-07-03 13:41:01 +08:00
b4bdd2fc83 给news实体类添加自动生成时间戳 2024-07-03 13:17:41 +08:00
961a17efef 给news实体类添加约束 2024-07-03 13:08:55 +08:00
e56db8a92e Revert "根据warning修改为pagedModel"
This reverts commit 64d7ae8c59.
2024-07-03 13:02:40 +08:00
64d7ae8c59 根据warning修改为pagedModel 2024-07-03 13:02:32 +08:00
3579f93c0d 完成了/news/getNewsList全数据流程 2024-07-03 12:45:39 +08:00
f9a6a3c481 初步建立了NewsRepository 2024-07-03 11:06:54 +08:00
2505b63b88 Merge branch 'main' into personal/heshunme/news
# Conflicts:
#	src/main/java/org/cmh/backend/authentication/controller/UserController.java
2024-07-03 02:02:04 +08:00
97d2ba60f5 chat设计了newsController,待完善 2024-07-03 01:58:41 +08:00
df51dac024 创建了news实体类 2024-07-03 01:43:37 +08:00
09ebd82dac Merge branch 'main' into Chester
# Conflicts:
#	pom.xml
#	src/main/java/org/cmh/backend/Config/CorsConfig.java
#	src/main/java/org/cmh/backend/Config/SecurityConfig.java
2024-07-02 16:44:56 +08:00
94a7b1bc13 1 2024-07-02 16:40:45 +08:00
b173b37329 租户管理完成增和改 2024-06-30 15:40:23 +08:00
62 changed files with 2020 additions and 150 deletions

22
pom.xml
View File

@ -93,11 +93,6 @@
<scope>runtime</scope> <scope>runtime</scope>
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<!-- <dependency>-->
<!-- <groupId>com.h2database</groupId>-->
<!-- <artifactId>h2</artifactId>-->
<!-- <scope>runtime</scope>-->
<!-- </dependency>-->
<dependency> <dependency>
<groupId>com.mysql</groupId> <groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId> <artifactId>mysql-connector-j</artifactId>
@ -128,6 +123,12 @@
<artifactId>spring-boot-testcontainers</artifactId> <artifactId>spring-boot-testcontainers</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency> <dependency>
<groupId>org.mybatis.spring.boot</groupId> <groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter-test</artifactId> <artifactId>mybatis-spring-boot-starter-test</artifactId>
@ -164,6 +165,17 @@
<artifactId>mysql</artifactId> <artifactId>mysql</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.3</version> <!-- 请使用最新版本 -->
</dependency><!-- BY JERRY -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version> <!-- 请使用最新版本 -->
<scope>provided</scope>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

@ -4,6 +4,8 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; 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; import org.springframework.security.web.SecurityFilterChain;
@Configuration @Configuration
@ -11,13 +13,22 @@ public class SecurityConfig {
@Bean @Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
// Use the new API to disable CSRF // Disable CSRF
http.csrf(AbstractHttpConfigurer::disable) http.csrf(AbstractHttpConfigurer::disable)
// Permit all requests // Permit all requests to all endpoints
.authorizeHttpRequests(authorize -> authorize .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(); return http.build();
} }
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
} }

View File

@ -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<GetCourseListResponse> 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<Course> 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<MessageResponse> 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<MessageResponse> 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<MessageResponse> 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<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);
}
}
@GetMapping("/sort")
public ResponseEntity<GetCourseListResponse> 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<Course> 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);
}
}
}

View File

@ -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<UploadFileResponse> 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<Resource> 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);
}
}
}

View File

@ -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;
}

View File

@ -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<Course> courseList;
}

View File

@ -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;
}

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

@ -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;
}
}

View File

@ -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;
}

View File

@ -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<Course, Long>, JpaSpecificationExecutor<Course> {
Page<Course> findAllByOrderByIdDesc(Pageable pageable);
}

View File

@ -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<Course> 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<Course> 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<Course> 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();
}
}

View File

@ -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<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]));
};
}
public static Specification<Course> 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();
};
}
}

View File

@ -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<List<Meeting>> listAll() {
List<Meeting> data = meetingService.getAllMeetings();
return ResponseEntity.ok(data);
}
@PostMapping("/addMeeting")
public ResponseEntity<Meeting> add(@RequestBody Map<String, String> 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<String> delete(@RequestBody Map<String, String> 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<Meeting> update(@RequestBody Map<String, String> 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<Meeting> getById(@RequestBody Map<String, String> 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<List<Meeting>> searchMeetings(@RequestBody Map<String, String> 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<Meeting> meetings = meetingService.searchMeetings(name, organizer, startTime1);
return new ResponseEntity<>(meetings, HttpStatus.OK);
}
}

View File

@ -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 + '\'' +
'}';
}
}

View File

@ -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<Meeting, Long> {
@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<Meeting> searchMeetings(String name, String organizer, LocalDateTime startTime);
}

View File

@ -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<Meeting> getAllMeetings() {
return meetingRepository.findAll();
}
public Optional<Meeting> 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<Meeting> searchMeetings(String name, String organizer, LocalDateTime startTime) {
// 根据条件搜索会议
return meetingRepository.searchMeetings(name, organizer, startTime);
}
}

View File

@ -0,0 +1,98 @@
package org.cmh.backend.NewsManagement.controller;
import jakarta.persistence.EntityNotFoundException;
import org.cmh.backend.NewsManagement.dto.GetNewsListResponse;
import org.cmh.backend.NewsManagement.dto.MessageResponse;
import org.cmh.backend.NewsManagement.dto.NewsRequest;
import org.cmh.backend.NewsManagement.dto.SearchNewsRequest;
import org.cmh.backend.NewsManagement.model.News;
import org.cmh.backend.NewsManagement.service.NewsService;
import org.cmh.backend.Utils.JwtUtil;
import org.cmh.backend.Utils.JwtVerify;
import org.cmh.backend.authentication.model.UserHS;
import org.cmh.backend.authentication.service.UserService;
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;
@RestController
@RequestMapping("/news")
public class NewsController {
@Autowired
private NewsService newsService;
@Autowired
private UserService userService;
@GetMapping
@JwtVerify
public ResponseEntity<GetNewsListResponse> getNewsByRange(@RequestParam Integer start, @RequestParam Integer end, @RequestParam String token) {
String username = JwtUtil.extractUsername(token);
UserHS user = userService.getUserByUsername(username);
if (start >= end) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
List<News> newsList = newsService.getNewsByRange(start, end, user);
long newsCount = newsList.size();
return new ResponseEntity<>(new GetNewsListResponse(newsCount, newsList), HttpStatus.OK);
}
@PostMapping("/search")
@JwtVerify
public ResponseEntity<GetNewsListResponse> searchNews(@RequestBody SearchNewsRequest request) {
List<News> newsList = newsService.searchNews(request);
long newsCount = newsList.size();
return new ResponseEntity<>(new GetNewsListResponse(newsCount, newsList), HttpStatus.OK);
}
@GetMapping("/{id}")
@JwtVerify
public ResponseEntity<News> getNewsPage(@PathVariable Long id, @RequestParam String token) {
try {
return new ResponseEntity<>(newsService.getNewsById(id), HttpStatus.OK);
} catch (EntityNotFoundException e) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
@PostMapping
@JwtVerify
public ResponseEntity<MessageResponse> createNews(@RequestBody NewsRequest request) {
try {
newsService.createNews(request);
} catch (DataIntegrityViolationException e) {
return new ResponseEntity<>(new MessageResponse("创建失败,文章已存在或缺少字段"), HttpStatus.BAD_REQUEST);
} catch (Exception e) {
return new ResponseEntity<>(new MessageResponse("创建失败:" + e.getMessage()), HttpStatus.BAD_REQUEST);
}
return new ResponseEntity<>(new MessageResponse("创建成功"), HttpStatus.CREATED);
}
@PutMapping("/{id}")
@JwtVerify
public ResponseEntity<MessageResponse> updateNews(@PathVariable Long id, @RequestBody NewsRequest request) {
try {
newsService.updateNews(id, request);
} catch (DataIntegrityViolationException e) {
return new ResponseEntity<>(new MessageResponse("修改失败,新标题已存在或缺少字段"), HttpStatus.BAD_REQUEST);
} catch (Exception e) {
return new ResponseEntity<>(new MessageResponse("创建失败:" + e.getMessage()), HttpStatus.BAD_REQUEST);
}
return new ResponseEntity<>(new MessageResponse("修改成功"), HttpStatus.OK);
}
@DeleteMapping("/{id}")
@JwtVerify
public ResponseEntity<MessageResponse> deleteNews(@PathVariable Long id, @RequestParam String token) {
try {
newsService.deleteNews(id);
} catch (EntityNotFoundException e) {
return new ResponseEntity<>(new MessageResponse("删除失败,文章不存在"), HttpStatus.BAD_REQUEST);
}
return new ResponseEntity<>(new MessageResponse("删除成功"), HttpStatus.OK);
}
}

View File

@ -0,0 +1,65 @@
package org.cmh.backend.NewsManagement.controller;
import org.cmh.backend.NewsManagement.dto.UploadFileResponse;
import org.springframework.core.io.Resource;
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.web.multipart.MultipartFile;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@RestController
@RequestMapping("/news")
public class NewsFileController {
private static final String UPLOAD_DIR = "uploads/";
@PostMapping("/uploadPic")
public ResponseEntity<UploadFileResponse> 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/news/files/" + file.getOriginalFilename()), HttpStatus.OK);
} catch (IOException e) {
return new ResponseEntity<>(new UploadFileResponse("文件上传失败", null), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
@GetMapping("/files/{filename}")
public ResponseEntity<Resource> 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);
}
}
}

View File

@ -0,0 +1,17 @@
package org.cmh.backend.NewsManagement.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import org.cmh.backend.NewsManagement.model.News;
import java.util.List;
@Getter
@Setter
@AllArgsConstructor
public class GetNewsListResponse {
Long newsCount;
List<News> newsList;
}

View File

@ -0,0 +1,12 @@
package org.cmh.backend.NewsManagement.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@AllArgsConstructor
public class MessageResponse {
String message;
}

View File

@ -0,0 +1,16 @@
package org.cmh.backend.NewsManagement.dto;
import lombok.Getter;
import lombok.Setter;
import org.cmh.backend.Utils.JwtRequest;
@Getter
@Setter
public class NewsRequest extends JwtRequest {
private String title;
private String summary;
private String content;
private String imagePath;
private String author;
private String tenant;
}

View File

@ -0,0 +1,15 @@
package org.cmh.backend.NewsManagement.dto;
import lombok.Getter;
import lombok.Setter;
import org.cmh.backend.Utils.JwtRequest;
@Getter
@Setter
public class SearchNewsRequest extends JwtRequest {
private String author;
private String title;
private String imagePath;
private String summary;
private String sortBy;
}

View File

@ -0,0 +1,16 @@
package org.cmh.backend.NewsManagement.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;
}
}

View File

@ -0,0 +1,36 @@
package org.cmh.backend.NewsManagement.model;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.CreationTimestamp;
import java.time.LocalDateTime;
@Setter
@Getter
@Entity
public class News {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
private String title;
@Column(nullable = false)
private String summary;
@Column(nullable = false)
private String content;
private String imagePath;
@Column(nullable = false)
private String author;
@CreationTimestamp
private LocalDateTime createdAt;
// TODO:添加外键绑定
private String tenant;
}

View File

@ -0,0 +1,23 @@
package org.cmh.backend.NewsManagement.repository;
import org.cmh.backend.NewsManagement.model.News;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface NewsRepository extends JpaRepository<News, Long> {
Page<News> findAllByOrderByIdDesc(Pageable pageable);
Page<News> findByTenantOrderByIdDesc(String tenant, Pageable pageable);
List<News> findByTitleContainingOrSummaryContainingOrAuthorContainingOrImagePathContainingAndTenantEquals(
String title,
String summary,
String author,
String imagePath,
String tenant);
List<News> findByTitleContainingOrSummaryContainingOrAuthorContainingOrImagePathContaining(String title, String summary, String author, String imagePath);
}

View File

@ -0,0 +1,162 @@
package org.cmh.backend.NewsManagement.service;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityNotFoundException;
import jakarta.persistence.PersistenceContext;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import org.cmh.backend.NewsManagement.dto.NewsRequest;
import org.cmh.backend.NewsManagement.dto.SearchNewsRequest;
import org.cmh.backend.NewsManagement.model.News;
import org.cmh.backend.NewsManagement.repository.NewsRepository;
import org.cmh.backend.Utils.JwtUtil;
import org.cmh.backend.authentication.model.UserHS;
import org.cmh.backend.authentication.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class NewsService {
@Autowired
private NewsRepository newsRepository;
@Autowired
private UserService userService;
@PersistenceContext
private EntityManager entityManager;
public List<News> getNewsByRange(int start, int end, UserHS user) {
if (start < 0 || end <= start) {
throw new IllegalArgumentException("Invalid start or end range");
}
int pageSize = end - start; // 计算每页的大小
int startPageNumber = start / pageSize; // 计算起始页码
int endPageNumber = (end - 1) / pageSize; // 计算结束页码
List<News> result = new ArrayList<>();
for (int pageNumber = startPageNumber; pageNumber <= endPageNumber; pageNumber++) {
Pageable pageable = PageRequest.of(pageNumber, pageSize);
Page<News> newsPage = null;
if (user.getSuperAdmin()) {
newsPage = newsRepository.findAllByOrderByIdDesc(pageable);
} else {
newsPage = newsRepository.findByTenantOrderByIdDesc(user.getTenant(), pageable);
}
if (newsPage.hasContent()) {
result.addAll(newsPage.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 createNews(NewsRequest request) {
String username = JwtUtil.extractUsername(request.getToken());
UserHS user = userService.getUserByUsername(username);
if (!user.getSuperAdmin() && !user.getTenant().equals(request.getTenant())){
throw new IllegalArgumentException("只能在自己的租户的名下新增新闻!");
}
News news = new News();
news.setTitle(request.getTitle());
news.setSummary(request.getSummary());
news.setContent(request.getContent());
news.setAuthor(request.getAuthor());
news.setImagePath(request.getImagePath());
news.setTenant(request.getTenant());
newsRepository.save(news);
}
public void updateNews(Long id, NewsRequest request) {
News news = newsRepository.findById(id).orElse(null);
if (news != null) {
news.setTitle(request.getTitle());
news.setSummary(request.getSummary());
news.setContent(request.getContent());
news.setAuthor(request.getAuthor());
news.setImagePath(request.getImagePath());
if (userService.getUserByUsername(JwtUtil.extractUsername(request.getToken())).getSuperAdmin()) {
news.setTenant(request.getTenant());
}
newsRepository.save(news);
}
}
public void deleteNews(Long id) {
if (!newsRepository.existsById(id)) {
throw new EntityNotFoundException();
}
newsRepository.deleteById(id);
}
public News getNewsById(Long id) {
if (!newsRepository.existsById(id)) {
throw new EntityNotFoundException();
}
return newsRepository.findById(id).orElse(null);
}
public long getNewsCount() {
return newsRepository.count();
}
public List<News> searchNews(SearchNewsRequest request) {
String username = JwtUtil.extractUsername(request.getToken());
UserHS user = userService.getUserByUsername(username);
// Create a list to hold predicates
List<Predicate> predicates = new ArrayList<>();
// Create the query
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<News> criteriaQuery = criteriaBuilder.createQuery(News.class);
Root<News> root = criteriaQuery.from(News.class);
// Build the query conditionally based on non-empty fields
if (!request.getTitle().isEmpty()) {
predicates.add(criteriaBuilder.like(root.get("title"), "%" + request.getTitle() + "%"));
}
if (!request.getSummary().isEmpty()) {
predicates.add(criteriaBuilder.like(root.get("summary"), "%" + request.getSummary() + "%"));
}
if (!request.getAuthor().isEmpty()) {
predicates.add(criteriaBuilder.like(root.get("author"), "%" + request.getAuthor() + "%"));
}
if (!request.getImagePath().isEmpty()) {
predicates.add(criteriaBuilder.like(root.get("imagePath"), "%" + request.getImagePath() + "%"));
}
if (user.getSuperAdmin()) {
// Combine predicates with OR
criteriaQuery.where(criteriaBuilder.or(predicates.toArray(new Predicate[0])));
} else {
// Combine predicates with OR and add tenant condition
Predicate tenantPredicate = criteriaBuilder.equal(root.get("tenant"), user.getUsername());
predicates.add(tenantPredicate);
criteriaQuery.where(criteriaBuilder.and(predicates.toArray(new Predicate[0])));
}
// Execute the query
return entityManager.createQuery(criteriaQuery).getResultList();
}
}

View File

@ -0,0 +1,75 @@
package org.cmh.backend.OrganizationManagement.controller;
import org.cmh.backend.OrganizationManagement.model.Organization;
import org.cmh.backend.OrganizationManagement.service.OrganizationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import static org.springframework.http.ResponseEntity.ok;
@RestController
@RequestMapping("/organizations")
public class OrganizationController {
@Autowired
private OrganizationService organizationService;
@GetMapping("/listAll")
public ResponseEntity<List<Organization>> listAll() {
List<Organization> data = organizationService.listAll();
// System.out.println(data);
return ok(data);
}
@PostMapping("/addOrganization")
public Organization add(@RequestBody Map<String, String> credentials) {
Organization organization = new Organization();
if (credentials.get("organizationId") != null) {
organization.setOrganizationId(Long.parseLong(credentials.get("organizationId")));
}
organization.setOrganizationName(credentials.get("organizationName"));
organization.setOrganizationStatus(Boolean.parseBoolean(credentials.get("organizationStatus")));
if (Integer.parseInt(credentials.get("parentOrganization")) != 0) {
organization.setParentOrganization(organizationService.getById(Long.parseLong(credentials.get("parentOrganization"))));
} else {
organization.setParentOrganization(null);
}
organization.setEmail(credentials.get("email"));
organization.setLeader(credentials.get("leader"));
organization.setContactPhone(credentials.get("contactPhone"));
organization.setDisplayOrder(Integer.parseInt(credentials.get("displayOrder")));
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
String currentTime = sdf.format(new Date());
System.out.println(currentTime);
organization.setCreatedTime(currentTime);
Organization organizationAdd = organizationService.add(organization);
System.out.println(organizationAdd);
return organizationAdd;
}
@PostMapping("/deleteOrganization")
public String delete(@RequestBody Map<String, String> credentials) {
organizationService.delete(Long.valueOf(credentials.get("organizationId")));
return "success";
}
@PostMapping("/update")
public Organization update(@RequestBody Organization organization) {
return organizationService.update(organization);
}
@PostMapping("/getOrganizationById")
public Organization getById(@RequestBody Map<String, String> credentials) {
return organizationService.getById(Long.valueOf(credentials.get("organizationId")));
}
//ublic
}

View File

@ -0,0 +1,70 @@
package org.cmh.backend.OrganizationManagement.model;
import jakarta.persistence.*;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
@Table(name = "organizations")
@Entity
public class Organization {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Setter
@Getter
private long organizationId; // 部门ID作为数据库表的主键
@Setter
@Getter
@ManyToOne
@JoinColumn(name = "parent_organization_id")
private Organization parentOrganization; // 上级部门如果有的话
@Setter
@Getter
private String organizationName; // 部门名称
@Setter
@Getter
private int displayOrder; // 显示排序
@Setter
@Getter
private String leader; // 负责人
@Setter
@Getter
private String contactPhone; // 联系电话
@Setter
@Getter
private String email; // 邮箱
@Setter
@Getter
private boolean organizationStatus;
@Setter
@Getter
private String createdTime;
public Organization() {
}
public Organization(Organization organization, String organizationName, int displayOrder, String leader, String contactPhone, String email, boolean organizationStatus) {
this.parentOrganization = organization;
this.organizationName = organizationName;
this.displayOrder = displayOrder;
this.leader = leader;
this.contactPhone = contactPhone;
this.email = email;
this.organizationStatus = organizationStatus;
}
@Override
public String toString() {
return "Organization{" +
"organizationId=" + organizationId +
", parentOrganization='" + parentOrganization + '\'' +
", organizationName='" + organizationName + '\'' +
", displayOrder=" + displayOrder +
", leader='" + leader + '\'' +
", contactPhone='" + contactPhone + '\'' +
", email='" + email + '\'' +
", organizationStatus='" + organizationStatus + '\'' +
'}';
}
}

View File

@ -0,0 +1,20 @@
package org.cmh.backend.OrganizationManagement.repository;
import org.aspectj.weaver.ast.Or;
import org.cmh.backend.OrganizationManagement.model.Organization;
import org.cmh.backend.OrganizationManagement.service.OrganizationService;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface OrganizationRepository extends JpaRepository<Organization, Long> {
List<Organization> findAll();
Organization save(Organization organization);
void deleteById(Long id);
Organization findByOrganizationId(Long id);
Organization findByOrganizationName(String name);
}

View File

@ -0,0 +1,36 @@
package org.cmh.backend.OrganizationManagement.service;
import org.cmh.backend.OrganizationManagement.model.Organization;
import org.cmh.backend.OrganizationManagement.repository.OrganizationRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class OrganizationService {
@Autowired
private OrganizationRepository organizationRepository;
public List<Organization> listAll(){
return organizationRepository.findAll();
}
public Organization add(Organization organization){
return organizationRepository.save(organization);
}
public Organization update(Organization organization){
return organizationRepository.save(organization);
}
public String delete(Long id){
organizationRepository.deleteById(id);
return "success";
}
public Organization getById(Long organizationId){
return organizationRepository.findByOrganizationId(organizationId);
}
public Organization getByName(String name){
return organizationRepository.findByOrganizationName(name);
}
}

View File

@ -0,0 +1,25 @@
package org.cmh.backend.UserManagement.adpter;
import org.cmh.backend.UserManagement.model.User;
import org.cmh.backend.authentication.model.UserHS;
import java.time.LocalDateTime;
public class User2UserHS {
private String tenant;
public static UserHS convert(User user,String tenant) {
UserHS userHS = new UserHS();
userHS.setUsername(user.getAccount());
userHS.setPassword(user.getPassword());
userHS.setNickname(user.getName());
userHS.setDepartment(user.getOrganization());
userHS.setGender(user.getGender());
userHS.setEmail(user.getEmail());
userHS.setPhoneNumber(user.getPhone());
userHS.setRole("用户");
userHS.setCreatedAt(LocalDateTime.now());
userHS.setTenant(tenant);
return userHS;
}
}

View File

@ -0,0 +1,28 @@
package org.cmh.backend.UserManagement.adpter;
import org.cmh.backend.UserManagement.model.User;
import org.cmh.backend.authentication.model.UserHS;
import java.util.List;
import java.util.stream.Collectors;
public class UserHS2User {
public static User convert(UserHS userHS) {
User user = new User();
user.setId(userHS.getId());
user.setAccount(userHS.getUsername());
user.setPassword(userHS.getPassword());
user.setName(userHS.getNickname());
user.setOrganization(userHS.getDepartment());
user.setGender(userHS.getGender());
user.setEmail(userHS.getEmail());
user.setPhone(userHS.getPhoneNumber());
return user;
}
//不确定这个能不能用XD
public static List<User> convertList(List<UserHS> userHSList) {
return userHSList.stream()
.map(UserHS2User::convert)
.collect(Collectors.toList());
}
}

View File

@ -0,0 +1,100 @@
package org.cmh.backend.UserManagement.controller;
import jakarta.transaction.Transactional;
import org.cmh.backend.UserManagement.dto.TenantOptionsResponse;
import org.cmh.backend.UserManagement.model.Tenant;
import org.cmh.backend.UserManagement.model.User;
import org.cmh.backend.UserManagement.service.TenantManagementService;
import org.cmh.backend.Utils.JwtUtil;
import org.cmh.backend.Utils.JwtVerify;
import org.cmh.backend.authentication.model.UserHS;
import org.cmh.backend.authentication.service.UserService;
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.util.List;
@RestController
@RequestMapping("/tenant")
public class TenantManagementController {
@Autowired
private TenantManagementService tenantManagementService;
@Autowired
private UserService userService;
private boolean isAdmin(String token) {
UserHS user = userService.getUserByUsername(JwtUtil.extractUsername(token));
return user.getSuperAdmin();
}
@PostMapping("/addTenant")
@JwtVerify
public Tenant addTenant(@RequestBody Tenant tenant, @RequestParam String token) {
if (isAdmin(token)) {
Tenant tenant1 = tenantManagementService.registerTenant(tenant);
UserHS newUser = new UserHS();
newUser.setUsername(tenant.getManager());
newUser.setPassword(tenant.getSymbol());
newUser.setRole("企业管理员");
newUser.setTenant(tenant.getName());
newUser.setGender("");
newUser.setNickname(tenant.getManager());
newUser.setEmail(tenant.getContact());
newUser.setDepartment("企业管理员");
newUser.setCreatedAt(LocalDateTime.now());
newUser.setPhoneNumber(tenant.getPhone());
userService.addUser(newUser);
System.out.println(tenant.toString());
return tenant1;
}
return null;
}
@GetMapping("/getAllTenant")
@JwtVerify
public List<Tenant> getAll(@RequestParam String token) {
if (isAdmin(token)) {
return tenantManagementService.findAll();
} else {
return null;
}
}
@GetMapping("/getTenantOptions")
@JwtVerify
public ResponseEntity<TenantOptionsResponse> getAllForNews(@RequestParam String token) {
tenantManagementService.findAll();
try {
List<String> options = tenantManagementService.findAll().stream()
.map(Tenant::getName)
.toList();
return new ResponseEntity<>(new TenantOptionsResponse(options, "请求成功"), HttpStatus.OK);
} catch (Exception e) {
return new ResponseEntity<>(new TenantOptionsResponse(null, "请求失败" + e.getMessage()), HttpStatus.BAD_REQUEST);
}
}
@PostMapping("/updateTenant")
@JwtVerify
public Tenant update(@RequestBody Tenant tenant, @RequestParam String token) {
if (isAdmin(token)) {
tenantManagementService.update(tenant);
return tenant;
}
return null;
}
@PostMapping("/deleteTenant")
@Transactional
@JwtVerify
public void delete(@RequestBody User user, @RequestParam String token) {
if (isAdmin(token)){
tenantManagementService.delete(user.getId());
}
}
}

View File

@ -0,0 +1,117 @@
package org.cmh.backend.UserManagement.controller;
import jakarta.transaction.Transactional;
import org.cmh.backend.OrganizationManagement.service.OrganizationService;
import org.cmh.backend.UserManagement.adpter.User2UserHS;
import org.cmh.backend.UserManagement.adpter.UserHS2User;
import org.cmh.backend.UserManagement.model.User;
import org.cmh.backend.UserManagement.service.UserManagementService;
import org.cmh.backend.Utils.JwtUtil;
import org.cmh.backend.Utils.JwtVerify;
import org.cmh.backend.authentication.dto.UserProfileResponse;
import org.cmh.backend.authentication.model.UserHS;
import org.cmh.backend.authentication.repository.UserRepository;
import org.cmh.backend.authentication.service.UserService;
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.util.List;
@RestController
@RequestMapping("/user")
public class UserManagementController {
@Autowired
private UserManagementService userManagementService;
@Autowired
private OrganizationService organizationService;
@Autowired
private UserService userService;
@Autowired
private UserRepository userRepository;
@PostMapping("/addUser")
@JwtVerify
public ResponseEntity<UserProfileResponse> addUser(@RequestBody User user,@RequestParam String token) {
String username = JwtUtil.extractUsername(token);
UserHS operationUser = userService.getUserByUsername(username);
UserHS newuser = User2UserHS.convert(user,operationUser.getTenant());
UserProfileResponse response = new UserProfileResponse(
newuser.getUsername(),
newuser.getNickname(),
newuser.getGender(),
newuser.getPhoneNumber(),
newuser.getEmail(),
newuser.getDepartment(),
newuser.getRole(),
newuser.getCreatedAt()
);
if (organizationService.getByName(newuser.getDepartment()) != null) {
userService.addUser(newuser);
return new ResponseEntity<>(response, HttpStatus.OK);
} else {
return null;
}
}
@GetMapping("/getAll")
@JwtVerify
public List<User> getAll(@RequestParam String token) {
String username = JwtUtil.extractUsername(token);
UserHS userHS = userService.getUserByUsername(username);
if (userHS.getSuperAdmin()) {
return UserHS2User.convertList(userService.getAllUsers());
} else {
return UserHS2User.convertList(userService.getUsersByTenant(userHS.getTenant()));
}
}
@PostMapping("/update")
public ResponseEntity<UserProfileResponse> update(@RequestBody User user,@RequestParam String token) {
String username = JwtUtil.extractUsername(token);
UserHS operationUser = userService.getUserByUsername(username);
UserHS reqUser = User2UserHS.convert(user, operationUser.getTenant());
UserHS tarUser = userService.getUserByUsername(reqUser.getUsername());
if (tarUser != null) {
// tarUser.setNickname(reqUser.getNickname());
// tarUser.setGender(reqUser.getGender());
// tarUser.setPhoneNumber(reqUser.getPhoneNumber());
// tarUser.setEmail(reqUser.getEmail());
// tarUser.setRole(reqUser.getRole());
reqUser.setId(tarUser.getId());
UserProfileResponse response = new UserProfileResponse(
reqUser.getUsername(),
reqUser.getNickname(),
reqUser.getGender(),
reqUser.getPhoneNumber(),
reqUser.getEmail(),
reqUser.getDepartment(),
reqUser.getRole(),
reqUser.getCreatedAt()
);
if (organizationService.getByName(reqUser.getDepartment()) == null) {
return new ResponseEntity<>(null, HttpStatus.OK);
}
userRepository.save(reqUser);
return new ResponseEntity<>(response, HttpStatus.OK);
} else {
return new ResponseEntity<>(null, HttpStatus.OK);
}
}
@PostMapping("/delete")
@Transactional
public void delete(@RequestBody User user) {
UserHS userHS = userService.getUserByUsername(user.getAccount());
if (userHS != null) {
//根据用户名删除用户
userService.deleteUser(userHS.getUsername());
}
}
}

View File

@ -0,0 +1,18 @@
package org.cmh.backend.UserManagement.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import org.cmh.backend.NewsManagement.dto.MessageResponse;
import org.cmh.backend.UserManagement.model.Tenant;
import java.util.List;
@Getter
@Setter
@AllArgsConstructor
public class TenantOptionsResponse {
List<String> options;
String message;
}

View File

@ -0,0 +1,23 @@
package org.cmh.backend.UserManagement.model;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
import org.cmh.backend.authentication.model.UserHS;
@Entity
@Getter
@Setter
@Table(name="tenant")
public class Tenant {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String contact; // 联系人
private String phone; // 联系人电话
@Column(unique = true)
private String name; // 租户名称
private String manager; // 租户管理员
private String symbol; // 租户标识
}

View File

@ -0,0 +1,53 @@
package org.cmh.backend.UserManagement.model;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.Getter;
import lombok.Setter;
@Entity
@Setter
@Getter
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String account;
private String password;
private String name;
private String organization;
private String gender;
private String email;
private String phone;
public User() {
}
public User(String account, String password, String name, String organization, String gender, String email, String phone) {
this.account = account;
this.password = password;
this.name = name;
this.organization = organization;
this.gender = gender;
this.email = email;
this.phone = phone;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", account='" + account + '\'' +
", password='" + password + '\'' +
", name='" + name + '\'' +
", organization='" + organization + '\'' +
", gender='" + gender + '\'' +
", email='" + email + '\'' +
", phone='" + phone + '\'' +
'}';
}
}

View File

@ -0,0 +1,17 @@
package org.cmh.backend.UserManagement.repository;
import org.cmh.backend.UserManagement.model.Tenant;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface TenantManagementRepository extends JpaRepository<Tenant, Long>{
Tenant findByName(String name);
Tenant save(Tenant tenant);
List<Tenant> findAll();
Tenant findTenantById(Long id);
Tenant deleteByName(String Name);
void deleteById(Long id);
}

View File

@ -0,0 +1,24 @@
package org.cmh.backend.UserManagement.repository;
import org.cmh.backend.UserManagement.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface UserManagementRepository extends JpaRepository<User, Long> {
User findByName(String name);
User findByAccountAndPassword(String name,String password);
User save(User user);
List<User> findAll();
User findUserById(Long id);
User deleteByAccount(String account);
void deleteById(Long id);
}

View File

@ -0,0 +1,13 @@
package org.cmh.backend.UserManagement.repository;
import org.cmh.backend.UserManagement.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface UserRepositoryTemp extends JpaRepository<User, Long> {
User findByName(String name);
User findByAccountAndPassword(String name,String password);
User save(User user);
}

View File

@ -0,0 +1,28 @@
package org.cmh.backend.UserManagement.service;
import org.cmh.backend.UserManagement.model.Tenant;
import org.cmh.backend.UserManagement.repository.TenantManagementRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class TenantManagementService {
@Autowired
private TenantManagementRepository tenantManagementRepository;
public Tenant registerTenant(Tenant tenant) {
return tenantManagementRepository.save(tenant);
}
public List<Tenant> findAll(){
return tenantManagementRepository.findAll();
}
public Tenant update(Tenant tenant){return tenantManagementRepository.save(tenant);}
public Tenant delete(String name){return tenantManagementRepository.deleteByName(name);}
public void delete(Long id){tenantManagementRepository.deleteById(id);}
}

View File

@ -0,0 +1,31 @@
package org.cmh.backend.UserManagement.service;
import org.cmh.backend.UserManagement.repository.UserManagementRepository;
import org.cmh.backend.UserManagement.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserManagementService {
@Autowired
private UserManagementRepository userManagementRepository;
public User registerUser(User user) {
User savedUser = userManagementRepository.save(user);
return savedUser;
}
public List<User> findAll(){
return userManagementRepository.findAll();
}
public User findUserById(Long id){return userManagementRepository.findUserById(id);}
public User update(User user){return userManagementRepository.save(user);}
public void delete(Long id){userManagementRepository.deleteById(id);}
}

View File

@ -0,0 +1,24 @@
package org.cmh.backend.UserManagement.service;
import org.cmh.backend.UserManagement.model.User;
import org.cmh.backend.UserManagement.repository.UserRepositoryTemp;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserServiceTemp {
@Autowired
private UserRepositoryTemp userRepository;
public User getUserByUsername(String username) {
return userRepository.findByName(username);
}
public User getUserByAccountAndPassword(String name,String password){return userRepository.findByAccountAndPassword(name,password);}
public User registerUser(User user) {
User savedUser = userRepository.save(user);
return savedUser;
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -26,4 +26,5 @@ public class UserHS {
private String role; private String role;
private LocalDateTime createdAt; private LocalDateTime createdAt;
private Boolean superAdmin = false; private Boolean superAdmin = false;
private String tenant;
} }

View File

@ -3,6 +3,12 @@ package org.cmh.backend.authentication.repository;
import org.cmh.backend.authentication.model.UserHS; import org.cmh.backend.authentication.model.UserHS;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface UserRepository extends JpaRepository<UserHS, Long> { public interface UserRepository extends JpaRepository<UserHS, Long> {
UserHS findByUsername(String username); UserHS findByUsername(String username);
Integer deleteByUsername(String username);
List<UserHS> findByTenant(String tenant);
} }

View File

@ -1,5 +1,7 @@
package org.cmh.backend.authentication.service; package org.cmh.backend.authentication.service;
import org.cmh.backend.UserManagement.model.Tenant;
import org.cmh.backend.UserManagement.repository.TenantManagementRepository;
import org.cmh.backend.authentication.dto.ChangePasswordRequest; import org.cmh.backend.authentication.dto.ChangePasswordRequest;
import org.cmh.backend.authentication.dto.ManageUserProfileRequest; import org.cmh.backend.authentication.dto.ManageUserProfileRequest;
import org.cmh.backend.authentication.dto.RegisterRequest; import org.cmh.backend.authentication.dto.RegisterRequest;
@ -11,12 +13,15 @@ import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@Service @Service
public class UserService { public class UserService {
@Autowired @Autowired
private UserRepository userRepository; private UserRepository userRepository;
@Autowired
private TenantManagementRepository tenantRepository;
private final PasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); private final PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
@ -46,13 +51,61 @@ public class UserService {
newUser.setUsername(username); newUser.setUsername(username);
newUser.setPassword(encodedPassword); newUser.setPassword(encodedPassword);
newUser.setPhoneNumber(phoneNumber); newUser.setPhoneNumber(phoneNumber);
newUser.setRole("企业管理员");
newUser.setTenant(username);
newUser.setGender("");
newUser.setNickname(username);
newUser.setEmail("user@example.com");
newUser.setDepartment("企业管理员");
newUser.setCreatedAt(LocalDateTime.now()); newUser.setCreatedAt(LocalDateTime.now());
userRepository.save(newUser); userRepository.save(newUser);
Tenant newTenant = new Tenant();
newTenant.setName(username);
newTenant.setPhone(phoneNumber);
newTenant.setManager(username);
newTenant.setSymbol(username);
newTenant.setContact(username);
tenantRepository.save(newTenant);
return true; return true;
} }
public boolean addUser(UserHS user) {
String username = user.getUsername();
String password = user.getPassword();
String phoneNumber = user.getPhoneNumber();
// 验证用户名是否已存在
if (userRepository.findByUsername(username) != null) {
return false; // 用户已存在
}
// 验证输入格式
if (!isValidUsername(username) || !isValidPassword(password) || !isValidContactInfo(phoneNumber)) {
throw new IllegalArgumentException();
}
// 加密密码
String encodedPassword = passwordEncoder.encode(password);
user.setPassword(encodedPassword);
userRepository.save(user);
return true;
}
public Integer deleteUser(String username){
return userRepository.deleteByUsername(username);
}
public List<UserHS> getAllUsers() {
return userRepository.findAll();
}
public List<UserHS> getUsersByTenant(String tenant){
return userRepository.findByTenant(tenant);
}
public boolean loginUser(String username, String password) { public boolean loginUser(String username, String password) {
UserHS user = userRepository.findByUsername(username); UserHS user = userRepository.findByUsername(username);
return user != null && passwordEncoder.matches(password, user.getPassword()); return user != null && passwordEncoder.matches(password, user.getPassword());

View File

@ -23,7 +23,8 @@ server.servlet.encoding.charset=utf-8
# verificationCode # verificationCode
verification.code.images.path=src/main/resources/static/verificationCodeImages verification.code.images.path=src/main/resources/static/verificationCodeImages
# set the max size of a single file # 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 # set the max size of the total request
spring.servlet.multipart.max-request-size=50MB spring.servlet.multipart.max-request-size=500MB

View File

@ -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() {
}
}

View File

@ -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);
}
}

View File

@ -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"));
}
}

View File

@ -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;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 MiB