!14 存储桶改为private

* 后台 使用许可页面
* 优化:移除API访问地址配置
* 后台、pc、h5 删除无用配置
* docker部署优化
* 2.0 networkMode=bridge
* changelog
* 学员端权限为空报错
* h5 我的页面请求优化
* 缓存查询
* 后台 学员列表报错、线上课-上架时间字段优化
* 后台、pc、h5 使用签名地址
* 学员端接口修改
* 后台、pc 使用签名地址
* 后台 使用签名地址
* 上传接口
* 上传接口
* 系统配置
* 线上课封面
* bucket由public改为private
* 资源相关表实体及对象修改
* 统一数据库脚本
This commit is contained in:
白书科技
2025-05-22 07:23:06 +00:00
parent c206fa4bf2
commit 12daa31ab9
134 changed files with 10054 additions and 1231 deletions

View File

@@ -10,7 +10,7 @@
</parent>
<artifactId>playedu-api</artifactId>
<version>1.9</version>
<version>2.0</version>
<dependencies>
<dependency>

View File

@@ -1,32 +0,0 @@
/*
* Copyright (C) 2023 杭州白书科技有限公司
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package xyz.playedu.api.bus;
import java.util.Map;
import org.springframework.stereotype.Component;
import xyz.playedu.common.constant.ConfigConstant;
@Component
public class UserBus {
public String getUserDefaultAvatar(Map<String, String> configData) {
String memberDefaultAvatar = configData.get(ConfigConstant.MEMBER_DEFAULT_AVATAR);
if (memberDefaultAvatar == null || memberDefaultAvatar.trim().isEmpty()) {
return configData.get(ConfigConstant.SYSTEM_API_URL) + "/images/default_avatar.png";
}
return memberDefaultAvatar;
}
}

View File

@@ -31,11 +31,14 @@ import xyz.playedu.common.domain.AppConfig;
import xyz.playedu.common.service.AppConfigService;
import xyz.playedu.common.types.JsonResponse;
import xyz.playedu.common.util.StringUtil;
import xyz.playedu.resource.service.ResourceService;
@RestController
@RequestMapping("/backend/v1/app-config")
public class AppConfigController {
@Autowired private ResourceService resourceService;
@Autowired private AppConfigService configService;
@BackendPermission(slug = BPermissionConstant.SYSTEM_CONFIG)
@@ -43,13 +46,20 @@ public class AppConfigController {
@Log(title = "系统配置-读取", businessType = BusinessTypeConstant.GET)
public JsonResponse index() {
List<AppConfig> configs = configService.allShow();
List<AppConfig> data = new ArrayList<>();
List<AppConfig> appConfigList = new ArrayList<>();
for (AppConfig item : configs) {
if (item.getIsPrivate() == 1 && StringUtil.isNotEmpty(item.getKeyValue())) {
if (item.getIsPrivate() == 1 && !item.getKeyValue().isBlank()) {
item.setKeyValue(SystemConstant.CONFIG_MASK);
}
data.add(item);
appConfigList.add(item);
}
HashMap<String, Object> data = new HashMap<>();
data.put("app_config", appConfigList);
// 获取签名url
data.put(
"resource_url",
resourceService.chunksPreSignUrlByIds(configService.getAllImageValue()));
return JsonResponse.data(data);
}
@@ -57,26 +67,55 @@ public class AppConfigController {
@PutMapping("")
@Log(title = "系统配置-保存", businessType = BusinessTypeConstant.UPDATE)
public JsonResponse save(@RequestBody AppConfigRequest req) {
HashMap<String, String> data = new HashMap<>();
req.getData()
.forEach(
(key, value) -> {
// 过滤掉未变动的private配置
if (SystemConstant.CONFIG_MASK.equals(value)) {
return;
}
String saveValue = value;
HashMap<String, String> data = req.getData();
// 预览地址
String s3Endpoint = data.get(ConfigConstant.S3_ENDPOINT);
if (StringUtil.isNotEmpty(s3Endpoint)) {
// 协议http:// https://
if (s3Endpoint.length() < 7
|| (!"http://".equalsIgnoreCase(s3Endpoint.substring(0, 7))
&& !"https://".equalsIgnoreCase(s3Endpoint.substring(0, 8)))) {
s3Endpoint = "https://" + s3Endpoint;
}
// 后缀
if (s3Endpoint.endsWith("/")) {
s3Endpoint = s3Endpoint.substring(0, s3Endpoint.length() - 1);
}
// 移除bucket
String s3Bucket = data.get(ConfigConstant.S3_BUCKET);
if (StringUtil.isNotEmpty(s3Bucket)) {
String bucketDomain = s3Bucket + ".";
String endpointLower = s3Endpoint.toLowerCase();
String bucketDomainLower = bucketDomain.toLowerCase();
if (endpointLower.contains(bucketDomainLower)) {
int index = endpointLower.indexOf(bucketDomainLower);
s3Endpoint =
s3Endpoint.substring(0, index)
+ s3Endpoint.substring(index + bucketDomain.length());
}
}
data.put(ConfigConstant.S3_ENDPOINT, s3Endpoint);
}
// LDAP的url配置自动加ldap://处理
if (ConfigConstant.LDAP_URL.equals(key)
&& StringUtil.isNotEmpty(value)
&& !StringUtil.startsWithIgnoreCase(value, "ldap://")) {
saveValue = "ldap://" + saveValue;
}
HashMap<String, String> newConfig = new HashMap<>();
data.forEach(
(key, value) -> {
// 过滤掉未变动的private配置
if (SystemConstant.CONFIG_MASK.equals(value)) {
return;
}
String saveValue = value;
data.put(key, saveValue);
});
configService.saveFromMap(data);
return JsonResponse.data(null);
// LDAP的url配置自动加ldap://处理
if (ConfigConstant.LDAP_URL.equals(key)
&& StringUtil.isNotEmpty(value)
&& !StringUtil.startsWithIgnoreCase(value, "ldap://")) {
saveValue = "ldap://" + saveValue;
}
newConfig.put(key, saveValue);
});
configService.saveFromMap(newConfig);
return JsonResponse.success();
}
}

View File

@@ -20,10 +20,9 @@ import java.util.List;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import xyz.playedu.common.annotation.BackendPermission;
import xyz.playedu.common.annotation.Log;
import xyz.playedu.common.constant.BPermissionConstant;
import xyz.playedu.common.constant.BusinessTypeConstant;
import xyz.playedu.common.types.JsonResponse;
import xyz.playedu.common.util.MemoryCacheUtil;
@@ -33,29 +32,28 @@ import xyz.playedu.common.util.MemoryCacheUtil;
@RequestMapping("/backend/v1/cache")
public class CacheController {
@BackendPermission(slug = BPermissionConstant.CACHE_MANAGE)
@Autowired private MemoryCacheUtil memoryCacheUtil;
@GetMapping("/list")
@Log(title = "缓存列表", businessType = BusinessTypeConstant.GET)
public JsonResponse list(MemoryCacheUtil memoryCacheUtil) {
public JsonResponse list() {
Map<String, Object> data = new HashMap<>();
data.put("keys", memoryCacheUtil.getAllKeys());
data.put("cache", memoryCacheUtil.getAllCache());
return JsonResponse.data(data);
}
@BackendPermission(slug = BPermissionConstant.CACHE_MANAGE)
@DeleteMapping("/clear")
@Log(title = "缓存删除key", businessType = BusinessTypeConstant.DELETE)
public JsonResponse clear(@RequestParam HashMap<String, Object> params) {
String cache_key = MapUtils.getString(params, "cache_key");
MemoryCacheUtil.del(cache_key);
memoryCacheUtil.del(cache_key);
return JsonResponse.success();
}
@BackendPermission(slug = BPermissionConstant.CACHE_MANAGE)
@DeleteMapping("/clear/all")
@Log(title = "缓存清空", businessType = BusinessTypeConstant.DELETE)
public JsonResponse clearAll(MemoryCacheUtil memoryCacheUtil) {
public JsonResponse clearAll() {
List<String> keys = memoryCacheUtil.getAllKeys();
for (String key : keys) {
MemoryCacheUtil.del(key);

View File

@@ -44,10 +44,7 @@ import xyz.playedu.common.types.JsonResponse;
import xyz.playedu.common.types.paginate.CoursePaginateFiler;
import xyz.playedu.common.types.paginate.PaginationResult;
import xyz.playedu.common.util.StringUtil;
import xyz.playedu.course.domain.Course;
import xyz.playedu.course.domain.CourseAttachment;
import xyz.playedu.course.domain.CourseChapter;
import xyz.playedu.course.domain.CourseHour;
import xyz.playedu.course.domain.*;
import xyz.playedu.course.service.CourseAttachmentService;
import xyz.playedu.course.service.CourseChapterService;
import xyz.playedu.course.service.CourseHourService;
@@ -183,6 +180,12 @@ public class CourseController {
data.put("admin_users", adminUsers);
}
// 课程封面资源ID
data.put(
"resource_url",
resourceService.chunksPreSignUrlByIds(
result.getData().stream().map(Course::getThumb).toList()));
return JsonResponse.data(data);
}
@@ -320,6 +323,8 @@ public class CourseController {
if (!backendBus.isSuperAdmin() && !course.getAdminId().equals(BCtx.getId())) {
return JsonResponse.error("无权限操作");
}
List<Integer> rids = new ArrayList<>();
rids.add(course.getThumb());
List<Integer> depIds = courseService.getDepIdsByCourseId(course.getId());
List<Integer> categoryIds = courseService.getCategoryIdsByCourseId(course.getId());
@@ -327,17 +332,17 @@ public class CourseController {
List<CourseHour> hours = hourService.getHoursByCourseId(course.getId());
List<CourseAttachment> attachments =
attachmentService.getAttachmentsByCourseId(course.getId());
if (null != attachments && !attachments.isEmpty()) {
if (StringUtil.isNotEmpty(attachments)) {
List<Integer> attachmentIds =
attachments.stream().map(CourseAttachment::getRid).toList();
rids.addAll(attachmentIds);
Map<Integer, Resource> resourceMap =
resourceService
.chunks(attachments.stream().map(CourseAttachment::getRid).toList())
.stream()
resourceService.chunks(attachmentIds).stream()
.collect(Collectors.toMap(Resource::getId, Function.identity()));
attachments.forEach(
courseAttachment -> {
Resource resource = resourceMap.get(courseAttachment.getRid());
if (null != resource) {
courseAttachment.setUrl(resource.getUrl());
if (StringUtil.isNotNull(resource)) {
courseAttachment.setExt(resource.getExtension());
}
});
@@ -359,6 +364,8 @@ public class CourseController {
data.put("hours", hours.stream().collect(Collectors.groupingBy(CourseHour::getChapterId)));
data.put("attachments", attachments);
data.put("deps", deps);
// 获取签名url
data.put("resource_url", resourceService.chunksPreSignUrlByIds(rids));
return JsonResponse.data(data);
}
@@ -381,7 +388,7 @@ public class CourseController {
req.getShortDesc(),
req.getIsRequired(),
req.getIsShow(),
req.getPublishedAt(),
req.getSortAt(),
req.getCategoryIds(),
req.getDepIds());

View File

@@ -43,6 +43,7 @@ import xyz.playedu.course.domain.UserCourseRecord;
import xyz.playedu.course.service.CourseService;
import xyz.playedu.course.service.UserCourseHourRecordService;
import xyz.playedu.course.service.UserCourseRecordService;
import xyz.playedu.resource.service.ResourceService;
/**
* @Author 杭州白书科技有限公司
@@ -66,6 +67,8 @@ public class CourseUserController {
@Autowired private ApplicationContext ctx;
@Autowired private ResourceService resourceService;
@BackendPermission(slug = BPermissionConstant.COURSE_USER)
@GetMapping("/index")
@SneakyThrows
@@ -147,6 +150,11 @@ public class CourseUserController {
perUserEarliestRecords.stream()
.collect(Collectors.toMap(UserCourseHourRecord::getUserId, e -> e)));
// 获取签名url
data.put(
"resource_url",
resourceService.chunksPreSignUrlByIds(
result.getData().stream().map(User::getAvatar).toList()));
return JsonResponse.data(data);
}

View File

@@ -46,7 +46,7 @@ import xyz.playedu.common.types.paginate.UserPaginateFilter;
import xyz.playedu.common.util.StringUtil;
import xyz.playedu.course.domain.Course;
import xyz.playedu.course.domain.UserCourseRecord;
import xyz.playedu.course.service.CourseDepartmentService;
import xyz.playedu.course.service.CourseDepartmentUserService;
import xyz.playedu.course.service.CourseService;
import xyz.playedu.course.service.UserCourseRecordService;
@@ -57,7 +57,7 @@ public class DepartmentController {
@Autowired private DepartmentService departmentService;
@Autowired private CourseDepartmentService courseDepartmentService;
@Autowired private CourseDepartmentUserService courseDepartmentUserService;
@Autowired private UserService userService;
@@ -163,7 +163,7 @@ public class DepartmentController {
if (ldapBus.enabledLDAP()) {
return JsonResponse.error("已启用LDAP服务禁止添加部门");
}
List<Integer> courseIds = courseDepartmentService.getCourseIdsByDepId(id);
List<Integer> courseIds = courseDepartmentUserService.getCourseIdsByDepId(id);
List<Integer> userIds = departmentService.getUserIdsByDepId(id);
HashMap<String, Object> data = new HashMap<>();

View File

@@ -42,9 +42,7 @@ public class LdapSyncDetailController {
*
* @param id 同步记录ID
* @param type 详情类型department-部门user-用户
* @param action 操作类型:
* - 部门1-新增2-更新3-删除4-无变化
* - 用户1-新增2-更新3-删除4-无变化5-禁止
* @param action 操作类型: - 部门1-新增2-更新3-删除4-无变化 - 用户1-新增2-更新3-删除4-无变化5-禁止
* @param page 页码
* @param size 每页数量
* @return 分页结果
@@ -67,9 +65,9 @@ public class LdapSyncDetailController {
}
queryWrapper.orderByDesc("id");
IPage<LdapSyncDepartmentDetail> pageResult =
ldapSyncDepartmentDetailService.page(new Page<>(page, size), queryWrapper);
IPage<LdapSyncDepartmentDetail> pageResult =
ldapSyncDepartmentDetailService.page(new Page<>(page, size), queryWrapper);
return JsonResponse.data(pageResult);
} else if ("user".equals(type)) {
// 用户同步详情
@@ -80,9 +78,9 @@ public class LdapSyncDetailController {
}
queryWrapper.orderByDesc("id");
IPage<LdapSyncUserDetail> pageResult =
ldapSyncUserDetailService.page(new Page<>(page, size), queryWrapper);
IPage<LdapSyncUserDetail> pageResult =
ldapSyncUserDetailService.page(new Page<>(page, size), queryWrapper);
return JsonResponse.data(pageResult);
}

View File

@@ -43,9 +43,9 @@ import xyz.playedu.common.types.paginate.ResourcePaginateFilter;
import xyz.playedu.common.util.S3Util;
import xyz.playedu.common.util.StringUtil;
import xyz.playedu.resource.domain.Resource;
import xyz.playedu.resource.domain.ResourceVideo;
import xyz.playedu.resource.domain.ResourceExtra;
import xyz.playedu.resource.service.ResourceExtraService;
import xyz.playedu.resource.service.ResourceService;
import xyz.playedu.resource.service.ResourceVideoService;
@RestController
@RequestMapping("/backend/v1/resource")
@@ -55,7 +55,7 @@ public class ResourceController {
@Autowired private ResourceService resourceService;
@Autowired private ResourceVideoService resourceVideoService;
@Autowired private ResourceExtraService resourceExtraService;
@Autowired private AppConfigService appConfigService;
@@ -122,14 +122,18 @@ public class ResourceController {
HashMap<String, Object> data = new HashMap<>();
data.put("result", result);
if (type.equals(BackendConstant.RESOURCE_TYPE_VIDEO)) {
List<ResourceVideo> resourceVideos =
resourceVideoService.chunksByRids(
result.getData().stream().map(Resource::getId).toList());
Map<Integer, ResourceVideo> resourceVideosExtra =
resourceVideos.stream()
.collect(Collectors.toMap(ResourceVideo::getRid, e -> e));
data.put("videos_extra", resourceVideosExtra);
List<Integer> ids = result.getData().stream().map(Resource::getId).toList();
if (StringUtil.isNotEmpty(ids)) {
if (type.equals(BackendConstant.RESOURCE_TYPE_VIDEO)) {
List<ResourceExtra> resourceExtras = resourceExtraService.chunksByRids(ids);
Map<Integer, ResourceExtra> resourceVideosExtra =
resourceExtras.stream()
.collect(Collectors.toMap(ResourceExtra::getRid, e -> e));
data.put("videos_extra", resourceVideosExtra);
}
// 获取资源签名url
data.put("resource_url", resourceService.chunksPreSignUrlByIds(ids));
}
// 操作人
@@ -169,7 +173,7 @@ public class ResourceController {
s3Util.removeByPath(resource.getPath());
// 如果是视频资源文件则删除对应的时长关联记录
if (BackendConstant.RESOURCE_TYPE_VIDEO.equals(resource.getType())) {
resourceVideoService.removeByRid(resource.getId());
resourceExtraService.removeByRid(resource.getId());
}
// 删除资源记录
resourceService.removeById(resource.getId());
@@ -203,7 +207,7 @@ public class ResourceController {
s3Util.removeByPath(resourceItem.getPath());
// 如果是视频资源的话还需要删除视频的关联资源,如: 封面截图
if (BackendConstant.RESOURCE_TYPE_VIDEO.equals(resourceItem.getType())) {
resourceVideoService.removeByRid(resourceItem.getId());
resourceExtraService.removeByRid(resourceItem.getId());
}
// 删除数据库的记录
resourceService.removeById(resourceItem.getId());
@@ -226,6 +230,15 @@ public class ResourceController {
HashMap<String, Object> data = new HashMap<>();
data.put("resources", resource);
data.put("category_ids", resourceService.categoryIds(id));
// 获取资源签名url
data.put(
"resource_url",
resourceService.chunksPreSignUrlByIds(
new ArrayList<>() {
{
add(id);
}
}));
return JsonResponse.data(data);
}

View File

@@ -15,24 +15,23 @@
*/
package xyz.playedu.api.controller.backend;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import xyz.playedu.api.bus.UserBus;
import xyz.playedu.common.annotation.Log;
import xyz.playedu.common.constant.BusinessTypeConstant;
import xyz.playedu.common.constant.ConfigConstant;
import xyz.playedu.common.context.BCtx;
import xyz.playedu.common.service.AppConfigService;
import xyz.playedu.common.service.CategoryService;
import xyz.playedu.common.service.DepartmentService;
import xyz.playedu.common.types.JsonResponse;
import xyz.playedu.common.util.RequestUtil;
import xyz.playedu.common.util.StringUtil;
import xyz.playedu.resource.service.ResourceService;
@RestController
@RequestMapping("/backend/v1/system")
@@ -43,39 +42,34 @@ public class SystemController {
@Autowired private CategoryService categoryService;
@Autowired private UserBus userBus;
@Autowired private ResourceService resourceService;
@Autowired private AppConfigService appConfigService;
@GetMapping("/config")
@Log(title = "其它-系统配置", businessType = BusinessTypeConstant.GET)
public JsonResponse config() {
Map<String, String> configData = BCtx.getConfig();
String apiUrl = configData.get(ConfigConstant.SYSTEM_API_URL);
if (apiUrl == null || apiUrl.trim().isEmpty()) {
apiUrl = RequestUtil.uriWithProtocol();
} else {
if (apiUrl.endsWith("/")) {
apiUrl = apiUrl.substring(0, apiUrl.length() - 1);
}
}
HashMap<String, Object> data = new HashMap<>();
data.put(ConfigConstant.SYSTEM_NAME, configData.get(ConfigConstant.SYSTEM_NAME));
data.put(ConfigConstant.SYSTEM_LOGO, configData.get(ConfigConstant.SYSTEM_LOGO));
data.put(ConfigConstant.SYSTEM_API_URL, apiUrl);
data.put(ConfigConstant.SYSTEM_PC_URL, configData.get(ConfigConstant.SYSTEM_PC_URL));
data.put(ConfigConstant.SYSTEM_H5_URL, configData.get(ConfigConstant.SYSTEM_H5_URL));
// 学员的默认头像
data.put(ConfigConstant.MEMBER_DEFAULT_AVATAR, userBus.getUserDefaultAvatar(configData));
Integer rid = -1;
String avatar = configData.get(ConfigConstant.MEMBER_DEFAULT_AVATAR);
if (StringUtil.isNotEmpty(avatar)) {
rid = Integer.parseInt(avatar);
}
// 内置的三个线上课封面
List<String> defaultCourseThumbs = new ArrayList<>();
defaultCourseThumbs.add(apiUrl + "/images/courses/thumb1.png");
defaultCourseThumbs.add(apiUrl + "/images/courses/thumb2.png");
defaultCourseThumbs.add(apiUrl + "/images/courses/thumb3.png");
data.put("default.course_thumbs", defaultCourseThumbs);
data.put(ConfigConstant.MEMBER_DEFAULT_AVATAR, rid);
// 获取签名url
data.put(
"resource_url",
resourceService.chunksPreSignUrlByIds(appConfigService.getAllImageValue()));
// LDAP登录
data.put("ldap-enabled", "1".equals(configData.get(ConfigConstant.LDAP_ENABLED)));

View File

@@ -15,7 +15,10 @@
*/
package xyz.playedu.api.controller.backend;
import com.amazonaws.services.s3.model.PartSummary;
import java.util.HashMap;
import java.util.List;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
@@ -28,14 +31,18 @@ import xyz.playedu.common.annotation.Log;
import xyz.playedu.common.constant.BPermissionConstant;
import xyz.playedu.common.constant.BackendConstant;
import xyz.playedu.common.constant.BusinessTypeConstant;
import xyz.playedu.common.constant.CommonConstant;
import xyz.playedu.common.context.BCtx;
import xyz.playedu.common.exception.ServiceException;
import xyz.playedu.common.service.AppConfigService;
import xyz.playedu.common.types.JsonResponse;
import xyz.playedu.common.types.UploadFileInfo;
import xyz.playedu.common.types.config.S3Config;
import xyz.playedu.common.util.HelperUtil;
import xyz.playedu.common.util.S3Util;
import xyz.playedu.common.util.StringUtil;
import xyz.playedu.resource.domain.Resource;
import xyz.playedu.resource.service.ResourceExtraService;
import xyz.playedu.resource.service.ResourceService;
import xyz.playedu.resource.service.UploadService;
@@ -50,19 +57,39 @@ public class UploadController {
@Autowired private ResourceService resourceService;
@Autowired private ResourceExtraService resourceExtraService;
@BackendPermission(slug = BPermissionConstant.UPLOAD)
@PostMapping("/minio")
@Log(title = "上传-MinIO", businessType = BusinessTypeConstant.UPLOAD)
public JsonResponse uploadMinio(
@RequestParam HashMap<String, Object> params, MultipartFile file)
throws ServiceException {
// 校验存储配置是否完整
S3Config s3Config = appConfigService.getS3Config();
if (StringUtil.isEmpty(s3Config.getAccessKey())
|| StringUtil.isEmpty(s3Config.getSecretKey())
|| StringUtil.isEmpty(s3Config.getBucket())
|| StringUtil.isEmpty(s3Config.getEndpoint())
|| StringUtil.isEmpty(s3Config.getRegion())) {
throw new ServiceException("存储服务未配置");
}
String categoryIds = MapUtils.getString(params, "category_ids");
UploadFileInfo info = uploadService.upload(s3Config, file, null);
Resource res =
uploadService.storeMinio(
appConfigService.getS3Config().getService(),
resourceService.create(
BCtx.getId(),
file,
categoryIds);
categoryIds,
info.getResourceType(),
info.getOriginalName(),
info.getExtension(),
file.getSize(),
"",
info.getSavePath(),
CommonConstant.ZERO,
CommonConstant.ZERO);
return JsonResponse.data(res);
}
@@ -70,6 +97,16 @@ public class UploadController {
@GetMapping("/minio/upload-id")
@Log(title = "上传-MinIO-uploadId", businessType = BusinessTypeConstant.UPLOAD)
public JsonResponse minioUploadId(@RequestParam HashMap<String, Object> params) {
// 校验存储配置是否完整
S3Config s3Config = appConfigService.getS3Config();
if (StringUtil.isEmpty(s3Config.getAccessKey())
|| StringUtil.isEmpty(s3Config.getSecretKey())
|| StringUtil.isEmpty(s3Config.getBucket())
|| StringUtil.isEmpty(s3Config.getEndpoint())
|| StringUtil.isEmpty(s3Config.getRegion())) {
throw new ServiceException("存储服务未配置");
}
String extension = MapUtils.getString(params, "extension");
if (extension == null || extension.trim().isEmpty()) {
return JsonResponse.error("extension参数为空");
@@ -79,7 +116,7 @@ public class UploadController {
return JsonResponse.error("该格式文件不支持上传");
}
S3Util s3Util = new S3Util(appConfigService.getS3Config());
S3Util s3Util = new S3Util(s3Config);
String filename = HelperUtil.randomString(32) + "." + extension; // 文件名
String path = BackendConstant.RESOURCE_TYPE_2_DIR.get(type) + filename; // 存储路径
@@ -93,7 +130,6 @@ public class UploadController {
return JsonResponse.data(data);
}
@BackendPermission(slug = BPermissionConstant.UPLOAD)
@GetMapping("/minio/pre-sign-url")
@Log(title = "上传-MinIO-签名URL", businessType = BusinessTypeConstant.UPLOAD)
public JsonResponse minioPreSignUrl(@RequestParam HashMap<String, Object> params) {
@@ -101,9 +137,9 @@ public class UploadController {
Integer partNumber = MapUtils.getInteger(params, "part_number");
String filename = MapUtils.getString(params, "filename");
S3Util s3Util = new S3Util(appConfigService.getS3Config());
String url = s3Util.generatePartUploadPreSignUrl(filename, partNumber + "", uploadId);
String url =
new S3Util(appConfigService.getS3Config())
.generatePartUploadPreSignUrl(filename, partNumber + "", uploadId);
HashMap<String, String> data = new HashMap<>();
data.put("url", url);
@@ -111,6 +147,28 @@ public class UploadController {
return JsonResponse.data(data);
}
@GetMapping("/minio/list-parts")
@Log(title = "上传-MinIO-已上传查询", businessType = BusinessTypeConstant.UPLOAD)
public JsonResponse minioListParts(@RequestParam HashMap<String, Object> params) {
String uploadId = MapUtils.getString(params, "upload_id");
String filename = MapUtils.getString(params, "filename");
List<PartSummary> parts =
new S3Util(appConfigService.getS3Config()).listParts(uploadId, filename);
return JsonResponse.data(parts);
}
@GetMapping("/minio/purge-segments")
@Log(title = "上传-MinIO-已上传查询", businessType = BusinessTypeConstant.UPLOAD)
public JsonResponse purgeIncompleteSegments(@RequestParam HashMap<String, Object> params) {
String uploadId = MapUtils.getString(params, "upload_id");
String filename = MapUtils.getString(params, "filename");
new S3Util(appConfigService.getS3Config()).purgeSegments(uploadId, filename);
return JsonResponse.success();
}
@BackendPermission(slug = BPermissionConstant.UPLOAD)
@PostMapping("/minio/merge-file")
@Log(title = "上传-MinIO-文件合并", businessType = BusinessTypeConstant.UPLOAD)
@@ -126,10 +184,10 @@ public class UploadController {
// 合并资源文件
S3Config s3Config = appConfigService.getS3Config();
S3Util s3Util = new S3Util(s3Config);
String url = s3Util.merge(req.getFilename(), req.getUploadId());
s3Util.merge(req.getFilename(), req.getUploadId());
// 资源素材保存
Resource videoResource =
Resource resource =
resourceService.create(
BCtx.getId(),
req.getCategoryIds(),
@@ -137,50 +195,32 @@ public class UploadController {
originalFilename,
extension,
req.getSize(),
s3Config.getService(),
"",
req.getFilename(),
url);
CommonConstant.ZERO,
CommonConstant.ZERO);
// 记录资源详情信息
doSaveResourceExtra(resource, req.getPoster(), req.getDuration());
return JsonResponse.success();
}
/** 记录资源详情信息 */
@SneakyThrows
public void doSaveResourceExtra(Resource resource, String poster, Integer duration) {
log.info("资源文件,类型={},id={}", resource.getType(), resource.getId());
String type = resource.getType();
// 视频资源特殊处理--视频封面资源
if (BackendConstant.RESOURCE_TYPE_VIDEO.equals(type)) {
// 视频封面素材保存
Resource posterResource =
uploadService.storeBase64Image(
s3Config.getService(), BCtx.getId(), req.getPoster(), null);
// 视频的封面素材改为[隐藏 && 属于视频的子素材]
resourceService.changeParentId(posterResource.getId(), videoResource.getId());
// 视频信息
resourceService.storeResourceVideo(
videoResource.getId(), req.getDuration(), posterResource.getUrl());
Integer posterId = 0;
if (StringUtil.isNotEmpty(poster)) {
Resource posterResource =
uploadService.storeBase64Image(
appConfigService.getS3Config(), BCtx.getId(), poster, null);
posterId = posterResource.getId();
}
resourceExtraService.create(resource.getId(), duration, posterId);
}
HashMap<String, Object> data = new HashMap<>();
data.put("url", url);
return JsonResponse.data(data);
}
@BackendPermission(slug = BPermissionConstant.UPLOAD)
@GetMapping("/minio/merge")
@Log(title = "上传-MinIO-文件合并", businessType = BusinessTypeConstant.UPLOAD)
public JsonResponse minioMerge(@RequestParam HashMap<String, Object> params) {
String filename = MapUtils.getString(params, "filename");
String uploadId = MapUtils.getString(params, "upload_id");
if (filename == null || filename.trim().isEmpty()) {
return JsonResponse.error("filename必填");
}
if (uploadId == null || uploadId.trim().isEmpty()) {
return JsonResponse.error("uploadId必填");
}
S3Util s3Util = new S3Util(appConfigService.getS3Config());
String url = s3Util.merge(filename, uploadId);
HashMap<String, Object> data = new HashMap<>();
data.put("url", url);
return JsonResponse.data(data);
}
}

View File

@@ -27,7 +27,6 @@ import org.springframework.context.ApplicationContext;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import xyz.playedu.api.bus.UserBus;
import xyz.playedu.api.event.UserCourseHourRecordDestroyEvent;
import xyz.playedu.api.event.UserCourseRecordDestroyEvent;
import xyz.playedu.api.event.UserDestroyEvent;
@@ -35,9 +34,7 @@ import xyz.playedu.api.request.backend.UserImportRequest;
import xyz.playedu.api.request.backend.UserRequest;
import xyz.playedu.common.annotation.BackendPermission;
import xyz.playedu.common.annotation.Log;
import xyz.playedu.common.constant.BPermissionConstant;
import xyz.playedu.common.constant.BusinessTypeConstant;
import xyz.playedu.common.constant.SystemConstant;
import xyz.playedu.common.constant.*;
import xyz.playedu.common.context.BCtx;
import xyz.playedu.common.domain.*;
import xyz.playedu.common.exception.NotFoundException;
@@ -53,6 +50,7 @@ import xyz.playedu.common.util.HelperUtil;
import xyz.playedu.common.util.StringUtil;
import xyz.playedu.course.domain.*;
import xyz.playedu.course.service.*;
import xyz.playedu.resource.service.ResourceService;
/**
* @Author 杭州白书科技有限公司
@@ -84,6 +82,8 @@ public class UserController {
@Autowired private ApplicationContext ctx;
@Autowired private ResourceService resourceService;
@BackendPermission(slug = BPermissionConstant.USER_INDEX)
@GetMapping("/index")
@Log(title = "学员-列表", businessType = BusinessTypeConstant.GET)
@@ -164,6 +164,12 @@ public class UserController {
data.put("pure_total", userService.total());
data.put("dep_user_count", departmentService.getDepartmentsUserCount());
// 课程封面资源ID
data.put(
"resource_url",
resourceService.chunksPreSignUrlByIds(
result.getData().stream().map(User::getAvatar).toList()));
return JsonResponse.data(data);
}
@@ -208,6 +214,16 @@ public class UserController {
data.put("user", user);
data.put("dep_ids", depIds);
// 获取签名url
data.put(
"resource_url",
resourceService.chunksPreSignUrlByIds(
new ArrayList<>() {
{
add(user.getAvatar());
}
}));
return JsonResponse.data(data);
}
@@ -249,7 +265,7 @@ public class UserController {
@PostMapping("/store-batch")
@Transactional
@Log(title = "学员-批量导入", businessType = BusinessTypeConstant.INSERT)
public JsonResponse batchStore(@RequestBody @Validated UserImportRequest req, UserBus userBus) {
public JsonResponse batchStore(@RequestBody @Validated UserImportRequest req) {
List<UserImportRequest.UserItem> users = req.getUsers();
if (users.isEmpty()) {
return JsonResponse.error("数据为空");
@@ -262,7 +278,11 @@ public class UserController {
Integer startLine = req.getStartLine();
// 默认的学员头像
String defaultAvatar = userBus.getUserDefaultAvatar(BCtx.getConfig());
int defaultAvatar = CommonConstant.MINUS_ONE;
String defaultAvatarConfig = BCtx.getConfig().get(ConfigConstant.MEMBER_DEFAULT_AVATAR);
if (StringUtil.isNotEmpty(defaultAvatarConfig)) {
defaultAvatar = Integer.parseInt(defaultAvatarConfig);
}
List<String[]> errorLines = new ArrayList<>();
errorLines.add(new String[] {"错误行", "错误信息"}); // 错误表-表头
@@ -467,18 +487,20 @@ public class UserController {
PaginationResult<UserCourseRecord> result =
userCourseRecordService.paginate(page, size, filter);
List<Course> courseList =
courseService.chunks(
result.getData().stream().map(UserCourseRecord::getCourseId).toList());
HashMap<String, Object> data = new HashMap<>();
data.put("data", result.getData());
data.put("total", result.getTotal());
data.put("courses", courseList.stream().collect(Collectors.toMap(Course::getId, e -> e)));
// 获取签名url
data.put(
"courses",
courseService
.chunks(
result.getData().stream()
.map(UserCourseRecord::getCourseId)
.toList())
.stream()
.collect(Collectors.toMap(Course::getId, e -> e)));
"resource_url",
resourceService.chunksPreSignUrlByIds(
courseList.stream().map(Course::getThumb).toList()));
return JsonResponse.data(data);
}
@@ -492,6 +514,7 @@ public class UserController {
List<Department> departments = new ArrayList<>();
HashMap<Integer, List<Course>> depCourses = new HashMap<>();
List<Integer> courseIds = new ArrayList<>();
List<Integer> rids = new ArrayList<>();
if (depIds != null && !depIds.isEmpty()) {
departments = departmentService.chunk(depIds);
@@ -522,6 +545,7 @@ public class UserController {
if (tmpCourses != null && !tmpCourses.isEmpty()) {
courseIds.addAll(tmpCourses.stream().map(Course::getId).toList());
rids.addAll(tmpCourses.stream().map(Course::getThumb).toList());
}
});
}
@@ -530,6 +554,7 @@ public class UserController {
List<Course> openCourses = courseService.getOpenCoursesAndShow(1000);
if (openCourses != null && !openCourses.isEmpty()) {
courseIds.addAll(openCourses.stream().map(Course::getId).toList());
rids.addAll(openCourses.stream().map(Course::getThumb).toList());
}
// 读取学员的线上课学习记录
@@ -563,7 +588,8 @@ public class UserController {
"per_course_earliest_records",
perCourseEarliestRecords.stream()
.collect(Collectors.toMap(UserCourseHourRecord::getCourseId, e -> e)));
// 获取签名url
data.put("resource_url", resourceService.chunksPreSignUrlByIds(rids));
return JsonResponse.data(data);
}

View File

@@ -15,10 +15,7 @@
*/
package xyz.playedu.api.controller.frontend;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.SneakyThrows;
@@ -64,9 +61,15 @@ public class CourseController {
List<CourseHour> courseHours = hourService.getHoursByCourseId(course.getId());
List<Integer> rids = new ArrayList<>();
rids.add(course.getThumb());
List<CourseAttachment> attachments =
attachmentService.getAttachmentsByCourseId(course.getId());
if (null != attachments && !attachments.isEmpty()) {
List<Integer> attachmentIds =
attachments.stream().map(CourseAttachment::getRid).toList();
rids.addAll(attachmentIds);
Map<Integer, Resource> resourceMap =
resourceService
.chunks(attachments.stream().map(CourseAttachment::getRid).toList())
@@ -93,6 +96,10 @@ public class CourseController {
userCourseHourRecordService.getRecords(FCtx.getId(), course.getId()).stream()
.collect(Collectors.toMap(UserCourseHourRecord::getHourId, e -> e)));
data.put("attachments", attachments);
// 获取签名url
data.put("resource_url", resourceService.chunksPreSignUrlByIds(rids));
return JsonResponse.data(data);
}
@@ -105,7 +112,8 @@ public class CourseController {
Resource resource = resourceService.findOrFail(attachment.getRid());
HashMap<String, Object> data = new HashMap<>();
data.put("download_url", resource.getUrl());
// 获取资源签名url
data.put("resource_url", resourceService.downloadResById(attachment.getRid()));
courseAttachmentDownloadLogService.save(
new CourseAttachmentDownloadLog() {

View File

@@ -15,6 +15,7 @@
*/
package xyz.playedu.api.controller.frontend;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;
import lombok.SneakyThrows;
@@ -97,7 +98,15 @@ public class HourController {
Resource resource = resourceService.findOrFail(hour.getRid());
HashMap<String, Object> data = new HashMap<>();
data.put("url", resource.getUrl()); // 视频播放地址
// 获取资源签名url
data.put(
"resource_url",
resourceService.chunksPreSignUrlByIds(
new ArrayList<>() {
{
add(resource.getId());
}
}));
data.put("extension", resource.getExtension()); // 视频格式
data.put("duration", resourceService.duration(resource.getId())); // 视频时长

View File

@@ -24,6 +24,7 @@ import org.springframework.web.bind.annotation.RestController;
import xyz.playedu.common.constant.ConfigConstant;
import xyz.playedu.common.service.AppConfigService;
import xyz.playedu.common.types.JsonResponse;
import xyz.playedu.resource.service.ResourceService;
@RestController
@RequestMapping("/api/v1/system")
@@ -31,15 +32,16 @@ public class SystemController {
@Autowired private AppConfigService appConfigService;
@Autowired private ResourceService resourceService;
@GetMapping("/config")
public JsonResponse config() {
Map<String, String> configs = appConfigService.keyValues();
HashMap<String, String> data = new HashMap<>();
HashMap<String, Object> data = new HashMap<>();
data.put("system-name", configs.get(ConfigConstant.SYSTEM_NAME));
data.put("system-logo", configs.get(ConfigConstant.SYSTEM_LOGO));
data.put("system-api-url", configs.get(ConfigConstant.SYSTEM_API_URL));
data.put("system-pc-url", configs.get(ConfigConstant.SYSTEM_PC_URL));
data.put("system-h5-url", configs.get(ConfigConstant.SYSTEM_H5_URL));
data.put("system-pc-index-footer-msg", configs.get("system.pc_index_footer_msg"));
@@ -53,6 +55,11 @@ public class SystemController {
data.put("ldap-enabled", configs.get(ConfigConstant.LDAP_ENABLED));
// 获取签名url
data.put(
"resource_url",
resourceService.chunksPreSignUrlByIds(appConfigService.getAllImageValue()));
return JsonResponse.data(data);
}
}

View File

@@ -25,6 +25,7 @@ import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import xyz.playedu.api.request.frontend.ChangePasswordRequest;
import xyz.playedu.common.constant.CommonConstant;
import xyz.playedu.common.constant.FrontendConstant;
import xyz.playedu.common.context.FCtx;
import xyz.playedu.common.domain.Category;
@@ -32,16 +33,16 @@ import xyz.playedu.common.domain.Department;
import xyz.playedu.common.domain.User;
import xyz.playedu.common.domain.UserUploadImageLog;
import xyz.playedu.common.exception.ServiceException;
import xyz.playedu.common.service.AppConfigService;
import xyz.playedu.common.service.CategoryService;
import xyz.playedu.common.service.DepartmentService;
import xyz.playedu.common.service.UserService;
import xyz.playedu.common.service.*;
import xyz.playedu.common.types.JsonResponse;
import xyz.playedu.common.types.UploadFileInfo;
import xyz.playedu.common.types.config.S3Config;
import xyz.playedu.common.types.mapper.UserCourseHourRecordCourseCountMapper;
import xyz.playedu.common.util.PrivacyUtil;
import xyz.playedu.common.util.StringUtil;
import xyz.playedu.course.domain.*;
import xyz.playedu.course.service.*;
import xyz.playedu.resource.domain.Resource;
import xyz.playedu.resource.service.ResourceService;
import xyz.playedu.resource.service.UploadService;
@RestController
@@ -69,6 +70,10 @@ public class UserController {
@Autowired private AppConfigService appConfigService;
@Autowired private ResourceService resourceService;
@Autowired private UserUploadImageLogService userUploadImageLogService;
@GetMapping("/detail")
public JsonResponse detail() {
User user = FCtx.getUser();
@@ -78,25 +83,65 @@ public class UserController {
departments = departmentService.listByIds(depIds);
}
user.setIdCard(PrivacyUtil.hideIDCard(user.getIdCard()));
HashMap<String, Object> data = new HashMap<>();
data.put("user", user);
data.put("departments", departments);
// 获取资源签名url
data.put(
"resource_url",
resourceService.chunksPreSignUrlByIds(
new ArrayList<>() {
{
add(user.getAvatar());
}
}));
return JsonResponse.data(data);
}
@PutMapping("/avatar")
public JsonResponse changeAvatar(MultipartFile file) {
UserUploadImageLog log =
uploadService.userAvatar(
appConfigService.getS3Config().getService(),
FCtx.getId(),
file,
FrontendConstant.USER_UPLOAD_IMAGE_TYPE_AVATAR,
FrontendConstant.USER_UPLOAD_IMAGE_SCENE_AVATAR);
userService.changeAvatar(FCtx.getId(), log.getUrl());
// 校验存储配置是否完整
S3Config s3Config = appConfigService.getS3Config();
if (StringUtil.isEmpty(s3Config.getAccessKey())
|| StringUtil.isEmpty(s3Config.getSecretKey())
|| StringUtil.isEmpty(s3Config.getBucket())
|| StringUtil.isEmpty(s3Config.getEndpoint())
|| StringUtil.isEmpty(s3Config.getRegion())) {
throw new ServiceException("存储服务未配置");
}
UploadFileInfo info = uploadService.upload(s3Config, file, null);
Resource resource =
resourceService.create(
CommonConstant.ZERO,
null,
info.getResourceType(),
info.getOriginalName(),
info.getExtension(),
info.getSize(),
info.getDisk(),
info.getSavePath(),
CommonConstant.ZERO,
CommonConstant.ONE);
// 学员头像
userService.changeAvatar(FCtx.getId(), resource.getId());
// 学员上传图片记录
UserUploadImageLog log = new UserUploadImageLog();
log.setUserId(FCtx.getId());
log.setTyped(FrontendConstant.USER_UPLOAD_IMAGE_TYPE_AVATAR);
log.setScene(FrontendConstant.USER_UPLOAD_IMAGE_SCENE_AVATAR);
log.setSize(info.getSize());
log.setDriver(info.getDisk());
log.setPath(info.getSavePath());
log.setName(info.getOriginalName());
log.setCreatedAt(new Date());
userUploadImageLogService.save(log);
return JsonResponse.success();
}
@@ -173,7 +218,7 @@ public class UserController {
courses.stream()
.sorted(
Comparator.comparing(
Course::getPublishedAt,
Course::getSortAt,
Comparator.nullsFirst(Date::compareTo))
.reversed())
.toList();
@@ -256,6 +301,11 @@ public class UserController {
UserCourseHourRecordCourseCountMapper::getCourseId,
UserCourseHourRecordCourseCountMapper::getTotal)));
// 获取签名url
data.put(
"resource_url",
resourceService.chunksPreSignUrlByIds(
courses.stream().map(Course::getThumb).toList()));
return JsonResponse.data(data);
}
@@ -310,6 +360,7 @@ public class UserController {
userCourseRecordService.chunk(FCtx.getId(), courseIds).stream()
.collect(Collectors.toMap(UserCourseRecord::getCourseId, e -> e));
List<UserLatestLearn> userLatestLearns = new ArrayList<>();
List<Integer> rids = new ArrayList<>();
for (Integer courseId : courseIds) {
UserCourseRecord record = records.get(courseId); // 线上课学习进度
Course tmpCourse = courses.get(courseId); // 线上课
@@ -317,6 +368,10 @@ public class UserController {
UserCourseHourRecord tmpUserCourseHourRecord = hour2Record.get(tmpHourId); // 课时学习进度
CourseHour tmpHour = hours.get(tmpHourId); // 课时
if (StringUtil.isNotNull(tmpCourse)) {
rids.add(tmpCourse.getThumb());
}
userLatestLearns.add(
new UserLatestLearn() {
{
@@ -328,6 +383,11 @@ public class UserController {
});
}
return JsonResponse.data(userLatestLearns);
HashMap<String, Object> data = new HashMap<>();
data.put("user_latest_learns", userLatestLearns);
// 获取签名url
data.put("resource_url", resourceService.chunksPreSignUrlByIds(rids));
return JsonResponse.data(data);
}
}

View File

@@ -21,7 +21,7 @@ import org.springframework.stereotype.Component;
import xyz.playedu.api.event.CourseDestroyEvent;
import xyz.playedu.course.service.CourseAttachmentService;
import xyz.playedu.course.service.CourseCategoryService;
import xyz.playedu.course.service.CourseDepartmentService;
import xyz.playedu.course.service.CourseDepartmentUserService;
import xyz.playedu.course.service.UserCourseHourRecordService;
import xyz.playedu.course.service.UserCourseRecordService;
@@ -33,7 +33,7 @@ import xyz.playedu.course.service.UserCourseRecordService;
@Component
public class CourseDestroyListener {
@Autowired private CourseDepartmentService courseDepartmentService;
@Autowired private CourseDepartmentUserService courseDepartmentUserService;
@Autowired private CourseCategoryService courseCategoryService;
@@ -45,7 +45,7 @@ public class CourseDestroyListener {
@EventListener
public void departmentRelateRemove(CourseDestroyEvent event) {
courseDepartmentService.removeByCourseId(event.getCourseId());
courseDepartmentUserService.removeByCourseId(event.getCourseId());
}
@EventListener

View File

@@ -44,8 +44,8 @@ public class UserLearnCourseUpdateListener {
// 观看记录
userLearnDurationRecordService.store(
event.getUserId(),
event.getCourseId(),
event.getHourId(),
event.getCourseId() + "_" + event.getHourId(),
"hour",
event.getStartAt(),
event.getEndAt());
}

View File

@@ -18,7 +18,6 @@ package xyz.playedu.api.request.backend;
import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import java.util.Date;
import java.util.List;
import lombok.Data;
@@ -33,8 +32,8 @@ public class CourseRequest {
@NotBlank(message = "请输入课程标题")
private String title;
@NotBlank(message = "请上传课程封面")
private String thumb;
@NotNull(message = "请上传课程封面")
private Integer thumb;
@NotNull(message = "short_desc参数不存在")
@JsonProperty("short_desc")
@@ -56,8 +55,8 @@ public class CourseRequest {
@JsonProperty("category_ids")
private Integer[] categoryIds;
@JsonProperty("published_at")
private Date publishedAt;
@JsonProperty("sort_at")
private String sortAt;
@Data
public static class HourItem {

View File

@@ -51,6 +51,5 @@ public class UploadFileMergeRequest {
@JsonProperty("category_ids")
private String categoryIds;
@NotNull(message = "请上传视频封面")
private String poster;
}

View File

@@ -38,8 +38,8 @@ public class UserRequest {
@Length(min = 1, max = 20, message = "姓名长度在1-20个字符之间")
private String name;
@NotBlank(message = "请上传头像")
private String avatar;
@NotNull(message = "请上传头像")
private Integer avatar;
@NotNull(message = "password参数不存在")
private String password;

View File

@@ -26,6 +26,7 @@ import xyz.playedu.common.service.AdminPermissionService;
import xyz.playedu.common.service.AdminRoleService;
import xyz.playedu.common.service.AdminUserService;
import xyz.playedu.common.util.PrivacyUtil;
import xyz.playedu.common.util.StringUtil;
@Component
public class BackendBus {
@@ -70,6 +71,9 @@ public class BackendBus {
}
HashMap<String, Boolean> permissions = BCtx.getAdminPer();
if (StringUtil.isNull(permissions)) {
return "";
}
if (permissions.get(permissionSlug) != null) {
return value;
}

View File

@@ -587,7 +587,7 @@ public class LDAPBus {
return;
}
String defaultAvatar = appConfigService.defaultAvatar();
Integer defaultAvatar = appConfigService.defaultAvatar();
for (LdapTransformUser ldapTransformUser : userList) {
if (ldapTransformUser.isBan()) {
@@ -607,7 +607,7 @@ public class LDAPBus {
}
}
public User singleUserSync(LdapTransformUser ldapTransformUser, String defaultAvatar) {
public User singleUserSync(LdapTransformUser ldapTransformUser, Integer defaultAvatar) {
log.info(
"*****START*****LDAP-用户同步-开始|ctx=[dn:{},uuid:{}]",
ldapTransformUser.getDn(),

View File

@@ -27,6 +27,7 @@ public class BackendConstant {
{
add("/backend/v1/system/image-captcha");
add("/backend/v1/auth/login");
add("/backend/v1/cache/list");
}
};
@@ -46,6 +47,7 @@ public class BackendConstant {
public static final String RESOURCE_TYPE_ZIP = "ZIP";
public static final String RESOURCE_TYPE_RAR = "RAR";
public static final String RESOURCE_TYPE_TXT = "TXT";
public static final String RESOURCE_TYPE_OTHER = "OTHER";
public static final String RESOURCE_TYPE_ATTACHMENT =
RESOURCE_TYPE_PDF

View File

@@ -0,0 +1,113 @@
/*
* Copyright (C) 2023 杭州白书科技有限公司
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package xyz.playedu.common.constant;
public class CommonConstant {
public static final Integer MINUS_ONE = -1;
public static final Integer ZERO = 0;
public static final Integer ONE = 1;
public static final Integer TWO = 2;
public static final Integer THREE = 3;
public static final Integer FOUR = 4;
public static final Integer FIVE = 5;
public static final Integer SIX = 6;
public static final Integer SEVEN = 7;
public static final Integer EIGHT = 8;
public static final Integer TEN = 10;
public static final Integer ELEVEN = 11;
public static final Integer TWELVE = 12;
public static final Integer FIFTEEN = 15;
public static final Integer TWENTY_ONE = 21;
public static final Integer TWENTY_TWO = 22;
public static final Integer TWENTY_FIVE = 25;
public static final Integer THIRTY = 30;
public static final Integer THIRTY_ONE = 31;
public static final Integer THIRTY_TWO = 32;
public static final Integer THIRTY_FIVE = 35;
public static final Integer FORTY_ONE = 41;
public static final Integer FORTY_TWO = 42;
public static final Integer FORTY_FIVE = 45;
public static final Integer SIXTY = 60;
public static final Integer ONE_HUNDRED = 100;
public static final String SUCCESS = "0";
public static final String FAIL = "-1";
public static final String UTF8 = "UTF-8";
public static final String GLOBAL = "GLOBAL";
public static final String COURSE = "COURSE";
public static final String OFFLINE_COURSE = "OFFLINE_COURSE";
public static final String REQUIRED_COURSE = "REQUIRED_COURSE";
public static final String OPTIONAL_COURSE = "OPTIONAL_COURSE";
public static final String STUDY_TASK = "STUDY_TASK";
public static final String EXAM_TASK = "EXAM_TASK";
public static final String LOGIN = "LOGIN";
public static final String MANUAL = "MANUAL";
public static final String SHOP = "SHOP";
public static final String SHOP_ROLLBACK = "SHOP_ROLLBACK";
public static final String MANUAL_TIP = "手动调整";
public static final String LOGIN_TIP = "首次登录";
public static final String SHOP_TIP = "积分商城购物";
public static final String SHOP_ROLLBACK_TIP = "积分商城退还积分";
public static final String HOUR_FINISHED_TIP = "课时学习完成";
public static final String COURSE_FINISHED_TIP = "线上课程学习完成";
public static final String OFFLINE_COURSE_FINISHED_TIP = "线下课程签到完成";
public static final String EXAM_FINISHED_TIP = "考试首次合格";
public static final String TASK_EXAM_FINISHED_TIP = "考试任务首次合格";
public static final String TASK_STUDY_FINISHED_TIP = "学习任务学习完成";
public static final String EXAM = "EXAM";
public static final String EXAM_RANGE_BEGIN = "EXAM_RANGE_BEGIN";
public static final String EXAM_RANGE_END = "EXAM_RANGE_END";
public static final String STUDY = "STUDY";
public static final String STUDY_RANGE = "STUDY_RANGE";
public static final String RETAKE = "RETAKE";
public static final String USER_CREATE = "USER_CREATE";
public static final String OTHER = "OTHER";
public static final String TRANSCODE = "document-transcode/";
public static final String SEPARATOR = ".";
public static final String JSON = "json";
public static final String OTHER_DEP = "其他(待设置部门)";
public static final Integer LOGIN_CHANNEL_LOCAL = 0;
public static final Integer LOGIN_CHANNEL_WORK_WECHAT = 1;
public static final Integer LOGIN_CHANNEL_FEISHU = 2;
public static final Integer LOGIN_CHANNEL_DINGTALK = 3;
public static final Integer LOGIN_CHANNEL_LDAP = 4;
public static final Integer LOGIN_CHANNEL_YUNZHIJIA = 7;
public static final Integer LOGIN_CHANNEL_CREC = 8;
public static final int TYPE_DEP = 0;
public static final int TYPE_USER = 1;
public static final int TYPE_GROUP = 2;
public static final String OIDC_CLIENT_SECRET_POST = "client_secret_post";
public static final String OIDC_CLIENT_SECRET_BASIC = "client_secret_basic";
public static final String OIDC_NONE = "none";
public static final String EXPORT_ALL_USER_RECORD = "export_all_user_record";
public static final String EXTRA_V = "v1";
public static final String S3_ACCESS_MODE_PATH = "path";
public static final String S3_ACCESS_MODE_VIRTUAL = "virtual";
}

View File

@@ -46,7 +46,7 @@ public class User implements Serializable {
private String name;
/** 头像 */
private String avatar;
private Integer avatar;
/** 密码 */
@JsonIgnore private String password;

View File

@@ -35,9 +35,11 @@ public interface AppConfigService extends IService<AppConfig> {
S3Config getS3Config();
List<Integer> getAllImageValue();
boolean enabledLdapLogin();
String defaultAvatar();
Integer defaultAvatar();
LdapConfig ldapConfig();
}

View File

@@ -47,7 +47,7 @@ public interface UserService extends IService<User> {
User createWithDepIds(
String email,
String name,
String avatar,
Integer avatar,
String password,
String idCard,
Integer[] depIds);
@@ -56,7 +56,7 @@ public interface UserService extends IService<User> {
User user,
String email,
String name,
String avatar,
Integer avatar,
String password,
String idCard,
Integer[] depIds);
@@ -77,7 +77,7 @@ public interface UserService extends IService<User> {
Map<Integer, List<Integer>> getDepIdsGroup(List<Integer> userIds);
void changeAvatar(Integer userId, String avatar);
void changeAvatar(Integer userId, Integer avatar);
void updateName(Integer id, String cn);

View File

@@ -24,6 +24,8 @@ import java.util.stream.Collectors;
import lombok.extern.log4j.Log4j2;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import xyz.playedu.common.constant.BackendConstant;
import xyz.playedu.common.constant.CommonConstant;
import xyz.playedu.common.constant.ConfigConstant;
import xyz.playedu.common.domain.AppConfig;
import xyz.playedu.common.exception.ServiceException;
@@ -102,34 +104,26 @@ public class AppConfigServiceImpl extends ServiceImpl<AppConfigMapper, AppConfig
s3Config.setSecretKey(config.get(ConfigConstant.S3_SECRET_KEY));
s3Config.setBucket(config.get(ConfigConstant.S3_BUCKET));
s3Config.setEndpoint(config.get(ConfigConstant.S3_ENDPOINT));
s3Config.setDomain(config.get(ConfigConstant.S3_DOMAIN));
s3Config.setService(ConfigConstant.S3_SERVICE);
// region解析
String region = config.get(ConfigConstant.S3_REGION);
s3Config.setRegion(StringUtil.isEmpty(region) ? null : region);
if (StringUtil.isNotEmpty(s3Config.getService())
&& StringUtil.isNotEmpty(s3Config.getDomain())) {
String _domain = s3Config.getDomain();
// 拼接https://前缀
if (_domain.length() < 7
|| (!"http://".equalsIgnoreCase(_domain.substring(0, 7))
&& !"https://".equalsIgnoreCase(_domain.substring(0, 8)))) {
_domain = "https://" + _domain;
}
// 移除 / 后缀
if (StringUtil.endsWith(_domain, "/")) {
_domain = _domain.substring(0, _domain.length() - 1);
}
s3Config.setDomain(_domain);
}
return s3Config;
}
@Override
public List<Integer> getAllImageValue() {
return list(
query().getWrapper()
.eq("field_type", BackendConstant.APP_CONFIG_FIELD_TYPE_IMAGE)
.isNotNull("key_value"))
.stream()
.filter(appConfig -> !appConfig.getKeyValue().isEmpty())
.map(appConfig -> Integer.parseInt(appConfig.getKeyValue()))
.toList();
}
@Override
public boolean enabledLdapLogin() {
AppConfig appConfig =
@@ -138,10 +132,13 @@ public class AppConfigServiceImpl extends ServiceImpl<AppConfigMapper, AppConfig
}
@Override
public String defaultAvatar() {
public Integer defaultAvatar() {
AppConfig appConfig =
getOne(query().getWrapper().eq("key_name", ConfigConstant.MEMBER_DEFAULT_AVATAR));
return appConfig.getKeyValue();
if (StringUtil.isEmpty(appConfig.getKeyValue())) {
return CommonConstant.MINUS_ONE;
}
return Integer.parseInt(appConfig.getKeyValue());
}
@Override

View File

@@ -28,14 +28,14 @@ public class MemoryRateLimiterServiceImpl implements RateLimiterService {
public Long current(String key, Long duration) {
lock.lock();
try {
Long count = (Long) MemoryCacheUtil.get(key);
if (count == null) {
Object value = MemoryCacheUtil.get(key);
if (value == null) {
// 第一次访问,设置初始值和过期时间
MemoryCacheUtil.set(key, 1L, duration);
return 1L;
}
// 已存在计数器,直接自增
return MemoryCacheUtil.increment(key, 1L);
// 已存在计数器,直接自增increment方法已经能处理Long和AtomicLong类型
return MemoryCacheUtil.increment(key, 1L, duration);
} finally {
lock.unlock();
}

View File

@@ -90,7 +90,7 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
public User createWithDepIds(
String email,
String name,
String avatar,
Integer avatar,
String password,
String idCard,
Integer[] depIds) {
@@ -129,7 +129,7 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
User user,
String email,
String name,
String avatar,
Integer avatar,
String password,
String idCard,
Integer[] depIds) {
@@ -263,7 +263,7 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
}
@Override
public void changeAvatar(Integer userId, String avatar) {
public void changeAvatar(Integer userId, Integer avatar) {
User user = new User();
user.setId(userId);
user.setAvatar(avatar);

View File

@@ -30,5 +30,5 @@ public class UploadFileInfo {
private String saveName;
private String resourceType;
private String savePath;
private String url;
private String disk;
}

View File

@@ -22,8 +22,6 @@ public class S3Config {
private String accessKey;
private String secretKey;
private String bucket;
private String endpoint;
private String domain;
private String region;
private String service;
private String endpoint;
}

View File

@@ -145,13 +145,31 @@ public class MemoryCacheUtil {
}
// 内部方法
public static Long increment(String key, long delta) {
public static Long increment(String key, long delta, long expireSeconds) {
key = cacheNamePrefix + key;
CacheObject cacheObject = cache.get(key);
if (cacheObject == null || cacheObject.isExpired()) {
cache.put(key, new CacheObject(new AtomicLong(delta), Long.MAX_VALUE));
cache.put(
key,
new CacheObject(
new AtomicLong(delta),
System.currentTimeMillis() + expireSeconds * 1000));
return delta;
}
AtomicLong counter = (AtomicLong) cacheObject.getValue();
// 检查值的类型如果是Long类型将其转换为AtomicLong
Object value = cacheObject.getValue();
AtomicLong counter;
if (value instanceof Long) {
counter = new AtomicLong((Long) value);
cacheObject.setValue(counter); // 更新缓存对象中的值为AtomicLong类型
} else if (value instanceof AtomicLong) {
counter = (AtomicLong) value;
} else {
// 如果既不是Long也不是AtomicLong重新初始化为delta
counter = new AtomicLong(delta);
cacheObject.setValue(counter);
}
return counter.addAndGet(delta);
}

View File

@@ -23,6 +23,9 @@ import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.*;
import com.amazonaws.services.s3.model.AccessControlList;
import com.amazonaws.services.s3.model.Grant;
import com.amazonaws.services.s3.model.GroupGrantee;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
@@ -67,9 +70,37 @@ public class S3Util {
AmazonS3ClientBuilder builder = AmazonS3ClientBuilder.standard();
return builder.withCredentials(new AWSStaticCredentialsProvider(credentials))
.withEndpointConfiguration(endpointConfiguration)
.build();
AmazonS3 client =
builder.withCredentials(new AWSStaticCredentialsProvider(credentials))
.withEndpointConfiguration(endpointConfiguration)
.build();
// 检查bucket是否存在
if (client.doesBucketExistV2(defaultConfig.getBucket())) {
// 确保bucket为私有访问权限
AccessControlList acl = client.getBucketAcl(defaultConfig.getBucket());
boolean isPrivate = true;
// 检查是否有公开访问的权限
for (Grant grant : acl.getGrantsAsList()) {
if (grant.getGrantee() instanceof GroupGrantee
&& (GroupGrantee.AllUsers.equals(grant.getGrantee())
|| GroupGrantee.AuthenticatedUsers.equals(grant.getGrantee()))) {
isPrivate = false;
break;
}
}
if (!isPrivate) {
// 如果不是私有的,抛出异常
throw new ServiceException("Bucket " + defaultConfig.getBucket() + " 必须设置为私有访问权限");
}
} else {
// 如果bucket不存在抛出异常
throw new ServiceException("Bucket " + defaultConfig.getBucket() + " 不存在");
}
return client;
}
@SneakyThrows
@@ -100,6 +131,37 @@ public class S3Util {
return result.getUploadId();
}
@SneakyThrows
public UploadPartResult uploadPart(
byte[] file, String filename, String uploadId, int partNumber) {
InputStream inputStream = new ByteArrayInputStream(file);
UploadPartRequest uploadPartRequest =
new UploadPartRequest()
.withBucketName(defaultConfig.getBucket())
.withKey(filename)
.withUploadId(uploadId)
.withPartNumber(partNumber)
.withInputStream(inputStream)
.withPartSize(file.length);
// 上传分段文件
UploadPartResult uploadPartResult = getClient().uploadPart(uploadPartRequest);
return uploadPartResult;
}
public List<PartSummary> listParts(String uploadId, String filename) {
ListPartsRequest request =
new ListPartsRequest(defaultConfig.getBucket(), filename, uploadId);
PartListing partListing = getClient().listParts(request);
return partListing.getParts();
}
public void purgeSegments(String uploadId, String filename) {
AbortMultipartUploadRequest request =
new AbortMultipartUploadRequest(defaultConfig.getBucket(), filename, uploadId);
getClient().abortMultipartUpload(request);
}
public String generatePartUploadPreSignUrl(
String filename, String partNumber, String uploadId) {
GeneratePresignedUrlRequest request =
@@ -156,6 +218,21 @@ public class S3Util {
}
public String generateEndpointPreSignUrl(String path) {
return defaultConfig.getDomain() + "/" + path;
return generateEndpointPreSignUrl(path, "");
}
public String generateEndpointPreSignUrl(String path, String name) {
GeneratePresignedUrlRequest request =
new GeneratePresignedUrlRequest(defaultConfig.getBucket(), path, HttpMethod.GET);
request.setExpiration(new Date(System.currentTimeMillis() + 3600 * 3000)); // 三个小时有效期
// 文件名不为空
if (StringUtil.isNotEmpty(name)) {
ResponseHeaderOverrides responseHeaders = new ResponseHeaderOverrides();
responseHeaders.setContentDisposition("attachment; filename=\"" + name + "\"");
request.setResponseHeaders(responseHeaders);
}
return getClient().generatePresignedUrl(request).toString();
}
}

View File

@@ -60,7 +60,7 @@
AND `users`.`name` LIKE concat('%',#{name},'%')
</if>
<if test="email != null and email != ''">
AND `users`.`email` = #{email}
AND `users`.`email` LIKE concat('%',#{email},'%')
</if>
<if test="idCard != null and idCard != ''">
AND `users`.`id_card` = #{idCard}
@@ -111,7 +111,7 @@
AND `users`.`name` LIKE concat('%',#{name},'%')
</if>
<if test="email != null and email != ''">
AND `users`.`email` = #{email}
AND `users`.`email` LIKE concat('%',#{email},'%')
</if>
<if test="idCard != null and idCard != ''">
AND `users`.`id_card` = #{idCard}

View File

@@ -21,7 +21,6 @@ import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
import lombok.Data;
@@ -40,7 +39,7 @@ public class Course implements Serializable {
private String title;
/** 课程封面 */
private String thumb;
private Integer thumb;
/** 课程价格(分) */
private Integer charge;
@@ -61,12 +60,16 @@ public class Course implements Serializable {
@JsonProperty("is_show")
private Integer isShow;
@JsonProperty("published_at")
private Date publishedAt;
@JsonProperty("created_at")
private Date createdAt;
@JsonProperty("sort_at")
private Date sortAt;
/** 其它规则[课程设置] */
private String extra;
/** 管理员ID */
@JsonProperty("admin_id")
private Integer adminId;
@@ -74,7 +77,111 @@ public class Course implements Serializable {
@JsonIgnore private Date deletedAt;
@Serial
@TableField(exist = false)
private static final long serialVersionUID = 1L;
@Override
public boolean equals(Object that) {
if (this == that) {
return true;
}
if (that == null) {
return false;
}
if (getClass() != that.getClass()) {
return false;
}
Course other = (Course) that;
return (this.getId() == null ? other.getId() == null : this.getId().equals(other.getId()))
&& (this.getTitle() == null
? other.getTitle() == null
: this.getTitle().equals(other.getTitle()))
&& (this.getThumb() == null
? other.getThumb() == null
: this.getThumb().equals(other.getThumb()))
&& (this.getCharge() == null
? other.getCharge() == null
: this.getCharge().equals(other.getCharge()))
&& (this.getClassHour() == null
? other.getClassHour() == null
: this.getClassHour().equals(other.getClassHour()))
&& (this.getIsShow() == null
? other.getIsShow() == null
: this.getIsShow().equals(other.getIsShow()))
&& (this.getIsRequired() == null
? other.getIsRequired() == null
: this.getIsRequired().equals(other.getIsRequired()))
&& (this.getCreatedAt() == null
? other.getCreatedAt() == null
: this.getCreatedAt().equals(other.getCreatedAt()))
&& (this.getSortAt() == null
? other.getSortAt() == null
: this.getSortAt().equals(other.getSortAt()))
&& (this.getUpdatedAt() == null
? other.getUpdatedAt() == null
: this.getUpdatedAt().equals(other.getUpdatedAt()))
&& (this.getDeletedAt() == null
? other.getDeletedAt() == null
: this.getDeletedAt().equals(other.getDeletedAt()))
&& (this.getShortDesc() == null
? other.getShortDesc() == null
: this.getShortDesc().equals(other.getShortDesc()))
&& (this.getSortAt() == null
? other.getSortAt() == null
: this.getSortAt().equals(other.getSortAt()))
&& (this.getExtra() == null
? other.getExtra() == null
: this.getExtra().equals(other.getExtra()))
&& (this.getAdminId() == null
? other.getAdminId() == null
: this.getAdminId().equals(other.getAdminId()));
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((getId() == null) ? 0 : getId().hashCode());
result = prime * result + ((getTitle() == null) ? 0 : getTitle().hashCode());
result = prime * result + ((getThumb() == null) ? 0 : getThumb().hashCode());
result = prime * result + ((getCharge() == null) ? 0 : getCharge().hashCode());
result = prime * result + ((getShortDesc() == null) ? 0 : getShortDesc().hashCode());
result = prime * result + ((getClassHour() == null) ? 0 : getClassHour().hashCode());
result = prime * result + ((getIsShow() == null) ? 0 : getIsShow().hashCode());
result = prime * result + ((getIsRequired() == null) ? 0 : getIsRequired().hashCode());
result = prime * result + ((getCreatedAt() == null) ? 0 : getCreatedAt().hashCode());
result = prime * result + ((getSortAt() == null) ? 0 : getSortAt().hashCode());
result = prime * result + ((getUpdatedAt() == null) ? 0 : getUpdatedAt().hashCode());
result = prime * result + ((getDeletedAt() == null) ? 0 : getDeletedAt().hashCode());
result = prime * result + ((getSortAt() == null) ? 0 : getSortAt().hashCode());
result = prime * result + ((getExtra() == null) ? 0 : getExtra().hashCode());
result = prime * result + ((getAdminId() == null) ? 0 : getAdminId().hashCode());
return result;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(getClass().getSimpleName());
sb.append(" [");
sb.append("Hash = ").append(hashCode());
sb.append(", id=").append(id);
sb.append(", title=").append(title);
sb.append(", thumb=").append(thumb);
sb.append(", charge=").append(charge);
sb.append(", shortDesc=").append(shortDesc);
sb.append(", classHour=").append(classHour);
sb.append(", isShow=").append(isShow);
sb.append(", isRequired=").append(isRequired);
sb.append(", createdAt=").append(createdAt);
sb.append(", sortAt=").append(sortAt);
sb.append(", updatedAt=").append(updatedAt);
sb.append(", deletedAt=").append(deletedAt);
sb.append(", sortAt=").append(sortAt);
sb.append(", extra=").append(extra);
sb.append(", adminId=").append(adminId);
sb.append(", serialVersionUID=").append(serialVersionUID);
sb.append("]");
return sb.toString();
}
}

View File

@@ -24,17 +24,22 @@ import java.io.Serializable;
import lombok.Data;
/**
* @TableName course_department
* @TableName course_department_user
*/
@TableName(value = "course_department")
@Data
public class CourseDepartment implements Serializable {
@TableName(value = "course_department_user")
public class CourseDepartmentUser implements Serializable {
/** 任务ID */
@TableId(type = IdType.NONE)
@JsonProperty("course_id")
private Integer courseId;
@JsonProperty("dep_id")
private Integer depId;
/** 指派范围ID */
@JsonProperty("range_id")
private Integer rangeId;
/** 指派范围类型[0:部门,1:学员] */
private Integer type;
@TableField(exist = false)
private static final long serialVersionUID = 1L;
@@ -50,13 +55,16 @@ public class CourseDepartment implements Serializable {
if (getClass() != that.getClass()) {
return false;
}
CourseDepartment other = (CourseDepartment) that;
CourseDepartmentUser other = (CourseDepartmentUser) that;
return (this.getCourseId() == null
? other.getCourseId() == null
: this.getCourseId().equals(other.getCourseId()))
&& (this.getDepId() == null
? other.getDepId() == null
: this.getDepId().equals(other.getDepId()));
&& (this.getRangeId() == null
? other.getRangeId() == null
: this.getRangeId().equals(other.getRangeId()))
&& (this.getType() == null
? other.getType() == null
: this.getType().equals(other.getType()));
}
@Override
@@ -64,7 +72,8 @@ public class CourseDepartment implements Serializable {
final int prime = 31;
int result = 1;
result = prime * result + ((getCourseId() == null) ? 0 : getCourseId().hashCode());
result = prime * result + ((getDepId() == null) ? 0 : getDepId().hashCode());
result = prime * result + ((getRangeId() == null) ? 0 : getRangeId().hashCode());
result = prime * result + ((getType() == null) ? 0 : getType().hashCode());
return result;
}
@@ -75,7 +84,8 @@ public class CourseDepartment implements Serializable {
sb.append(" [");
sb.append("Hash = ").append(hashCode());
sb.append(", courseId=").append(courseId);
sb.append(", depId=").append(depId);
sb.append(", rangeId=").append(rangeId);
sb.append(", type=").append(type);
sb.append(", serialVersionUID=").append(serialVersionUID);
sb.append("]");
return sb.toString();

View File

@@ -61,6 +61,9 @@ public class CourseHour implements Serializable {
/** */
@JsonIgnore private Date createdAt;
/** 删除标志[0:存在,1:删除] */
private Integer deleted;
@TableField(exist = false)
private static final long serialVersionUID = 1L;
@@ -100,7 +103,10 @@ public class CourseHour implements Serializable {
: this.getDuration().equals(other.getDuration()))
&& (this.getCreatedAt() == null
? other.getCreatedAt() == null
: this.getCreatedAt().equals(other.getCreatedAt()));
: this.getCreatedAt().equals(other.getCreatedAt()))
&& (this.getDeleted() == null
? other.getDeleted() == null
: this.getDeleted().equals(other.getDeleted()));
}
@Override
@@ -116,6 +122,7 @@ public class CourseHour implements Serializable {
result = prime * result + ((getRid() == null) ? 0 : getRid().hashCode());
result = prime * result + ((getDuration() == null) ? 0 : getDuration().hashCode());
result = prime * result + ((getCreatedAt() == null) ? 0 : getCreatedAt().hashCode());
result = prime * result + ((getDeleted() == null) ? 0 : getDeleted().hashCode());
return result;
}
@@ -134,6 +141,7 @@ public class CourseHour implements Serializable {
sb.append(", rid=").append(rid);
sb.append(", duration=").append(duration);
sb.append(", createdAt=").append(createdAt);
sb.append(", deleted=").append(deleted);
sb.append(", serialVersionUID=").append(serialVersionUID);
sb.append("]");
return sb.toString();

View File

@@ -54,12 +54,12 @@ public class UserLearnDurationRecord implements Serializable {
private Date endAt;
/** */
@JsonProperty("course_id")
private Integer courseId;
@JsonProperty("from_id")
private String fromId;
/** */
@JsonProperty("hour_id")
private Integer hourId;
@JsonProperty("from_scene")
private String fromScene;
@TableField(exist = false)
private static final long serialVersionUID = 1L;
@@ -92,12 +92,12 @@ public class UserLearnDurationRecord implements Serializable {
&& (this.getEndAt() == null
? other.getEndAt() == null
: this.getEndAt().equals(other.getEndAt()))
&& (this.getCourseId() == null
? other.getCourseId() == null
: this.getCourseId().equals(other.getCourseId()))
&& (this.getHourId() == null
? other.getHourId() == null
: this.getHourId().equals(other.getHourId()));
&& (this.getFromId() == null
? other.getFromId() == null
: this.getFromId().equals(other.getFromId()))
&& (this.getFromScene() == null
? other.getFromScene() == null
: this.getFromScene().equals(other.getFromScene()));
}
@Override
@@ -110,8 +110,8 @@ public class UserLearnDurationRecord implements Serializable {
result = prime * result + ((getDuration() == null) ? 0 : getDuration().hashCode());
result = prime * result + ((getStartAt() == null) ? 0 : getStartAt().hashCode());
result = prime * result + ((getEndAt() == null) ? 0 : getEndAt().hashCode());
result = prime * result + ((getCourseId() == null) ? 0 : getCourseId().hashCode());
result = prime * result + ((getHourId() == null) ? 0 : getHourId().hashCode());
result = prime * result + ((getFromId() == null) ? 0 : getFromId().hashCode());
result = prime * result + ((getFromScene() == null) ? 0 : getFromScene().hashCode());
return result;
}
@@ -127,8 +127,8 @@ public class UserLearnDurationRecord implements Serializable {
sb.append(", duration=").append(duration);
sb.append(", startAt=").append(startAt);
sb.append(", endAt=").append(endAt);
sb.append(", courseId=").append(courseId);
sb.append(", hourId=").append(hourId);
sb.append(", fromId=").append(fromId);
sb.append(", fromScene=").append(fromScene);
sb.append(", serialVersionUID=").append(serialVersionUID);
sb.append("]");
return sb.toString();

View File

@@ -17,12 +17,12 @@ package xyz.playedu.course.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import xyz.playedu.course.domain.CourseDepartment;
import xyz.playedu.course.domain.CourseDepartmentUser;
/**
* @author tengteng
* @description 针对表course_department的数据库操作Mapper
* @description 针对表course_department_user的数据库操作Mapper
* @createDate 2023-02-24 14:53:52
*/
@Mapper
public interface CourseDepartmentMapper extends BaseMapper<CourseDepartment> {}
public interface CourseDepartmentUserMapper extends BaseMapper<CourseDepartmentUser> {}

View File

@@ -17,14 +17,14 @@ package xyz.playedu.course.service;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
import xyz.playedu.course.domain.CourseDepartment;
import xyz.playedu.course.domain.CourseDepartmentUser;
/**
* @author tengteng
* @description 针对表course_department的数据库操作Service
* @description 针对表course_department_user的数据库操作Service
* @createDate 2023-02-24 14:53:52
*/
public interface CourseDepartmentService extends IService<CourseDepartment> {
public interface CourseDepartmentUserService extends IService<CourseDepartmentUser> {
List<Integer> getCourseIdsByDepIds(List<Integer> depIds);

View File

@@ -16,7 +16,6 @@
package xyz.playedu.course.service;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.Date;
import java.util.List;
import java.util.Map;
import xyz.playedu.common.exception.NotFoundException;
@@ -35,7 +34,7 @@ public interface CourseService extends IService<Course> {
Course createWithCategoryIdsAndDepIds(
String title,
String thumb,
Integer thumb,
String shortDesc,
Integer isRequired,
Integer isShow,
@@ -46,11 +45,11 @@ public interface CourseService extends IService<Course> {
void updateWithCategoryIdsAndDepIds(
Course course,
String title,
String thumb,
Integer thumb,
String shortDesc,
Integer isRequired,
Integer isShow,
Date publishedAt,
String sortAt,
Integer[] categoryIds,
Integer[] depIds);

View File

@@ -24,7 +24,7 @@ import xyz.playedu.course.domain.UserLearnDurationRecord;
* @createDate 2023-03-20 16:41:12
*/
public interface UserLearnDurationRecordService extends IService<UserLearnDurationRecord> {
void store(Integer userId, Integer courseId, Integer hourId, Long startTime, Long endTime);
void store(Integer userId, String fromId, String fromScene, Long startTime, Long endTime);
void remove(Integer userId);
}

View File

@@ -18,30 +18,30 @@ package xyz.playedu.course.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import java.util.List;
import org.springframework.stereotype.Service;
import xyz.playedu.course.domain.CourseDepartment;
import xyz.playedu.course.mapper.CourseDepartmentMapper;
import xyz.playedu.course.service.CourseDepartmentService;
import xyz.playedu.course.domain.CourseDepartmentUser;
import xyz.playedu.course.mapper.CourseDepartmentUserMapper;
import xyz.playedu.course.service.CourseDepartmentUserService;
/**
* @author tengteng
* @description 针对表course_department的数据库操作Service实现
* @description 针对表course_department_user的数据库操作Service实现
* @createDate 2023-02-24 14:53:52
*/
@Service
public class CourseDepartmentServiceImpl
extends ServiceImpl<CourseDepartmentMapper, CourseDepartment>
implements CourseDepartmentService {
public class CourseDepartmentUserServiceImpl
extends ServiceImpl<CourseDepartmentUserMapper, CourseDepartmentUser>
implements CourseDepartmentUserService {
@Override
public List<Integer> getCourseIdsByDepIds(List<Integer> depIds) {
return list(query().getWrapper().in("dep_id", depIds)).stream()
.map(CourseDepartment::getCourseId)
return list(query().getWrapper().in("range_id", depIds)).stream()
.map(CourseDepartmentUser::getCourseId)
.toList();
}
@Override
public List<Integer> getDepIdsByCourseId(Integer courseId) {
return list(query().getWrapper().eq("course_id", courseId)).stream()
.map(CourseDepartment::getDepId)
.map(CourseDepartmentUser::getRangeId)
.toList();
}
@@ -52,8 +52,8 @@ public class CourseDepartmentServiceImpl
@Override
public List<Integer> getCourseIdsByDepId(Integer depId) {
return list(query().getWrapper().eq("dep_id", depId)).stream()
.map(CourseDepartment::getCourseId)
return list(query().getWrapper().eq("range_id", depId)).stream()
.map(CourseDepartmentUser::getCourseId)
.toList();
}
}

View File

@@ -15,6 +15,7 @@
*/
package xyz.playedu.course.service.impl;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import java.util.*;
import java.util.stream.Collectors;
@@ -28,10 +29,10 @@ import xyz.playedu.common.types.paginate.PaginationResult;
import xyz.playedu.common.util.StringUtil;
import xyz.playedu.course.domain.Course;
import xyz.playedu.course.domain.CourseCategory;
import xyz.playedu.course.domain.CourseDepartment;
import xyz.playedu.course.domain.CourseDepartmentUser;
import xyz.playedu.course.mapper.CourseMapper;
import xyz.playedu.course.service.CourseCategoryService;
import xyz.playedu.course.service.CourseDepartmentService;
import xyz.playedu.course.service.CourseDepartmentUserService;
import xyz.playedu.course.service.CourseService;
/**
@@ -42,7 +43,7 @@ import xyz.playedu.course.service.CourseService;
@Service
public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course> implements CourseService {
@Autowired private CourseDepartmentService courseDepartmentService;
@Autowired private CourseDepartmentUserService courseDepartmentUserService;
@Autowired private CourseCategoryService courseCategoryService;
@@ -62,7 +63,7 @@ public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course> impleme
@Transactional
public Course createWithCategoryIdsAndDepIds(
String title,
String thumb,
Integer thumb,
String shortDesc,
Integer isRequired,
Integer isShow,
@@ -76,7 +77,7 @@ public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course> impleme
course.setShortDesc(shortDesc);
course.setIsShow(isShow);
course.setIsRequired(isRequired);
course.setPublishedAt(new Date());
course.setSortAt(new Date());
course.setCreatedAt(new Date());
course.setUpdatedAt(new Date());
course.setAdminId(adminId);
@@ -94,23 +95,23 @@ public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course> impleme
if (depIds == null || depIds.length == 0) {
return;
}
List<CourseDepartment> courseDepartments = new ArrayList<>();
List<CourseDepartmentUser> courseDepartmentUsers = new ArrayList<>();
for (int i = 0; i < depIds.length; i++) {
Integer tmpDepId = depIds[i];
courseDepartments.add(
new CourseDepartment() {
courseDepartmentUsers.add(
new CourseDepartmentUser() {
{
setCourseId(course.getId());
setDepId(tmpDepId);
setRangeId(tmpDepId);
}
});
}
courseDepartmentService.saveBatch(courseDepartments);
courseDepartmentUserService.saveBatch(courseDepartmentUsers);
}
@Override
public void resetRelateDepartments(Course course, Integer[] depIds) {
courseDepartmentService.removeByCourseId(course.getId());
courseDepartmentUserService.removeByCourseId(course.getId());
relateDepartments(course, depIds);
}
@@ -144,11 +145,11 @@ public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course> impleme
public void updateWithCategoryIdsAndDepIds(
Course course,
String title,
String thumb,
Integer thumb,
String shortDesc,
Integer isRequired,
Integer isShow,
Date publishedAt,
String sortAt,
Integer[] categoryIds,
Integer[] depIds) {
Course newCourse = new Course();
@@ -159,8 +160,8 @@ public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course> impleme
newCourse.setIsRequired(isRequired);
newCourse.setShortDesc(shortDesc);
if (null != publishedAt) {
newCourse.setPublishedAt(publishedAt);
if (StringUtil.isNotEmpty(sortAt)) {
newCourse.setSortAt(DateUtil.parseDate(sortAt));
}
updateById(newCourse);
@@ -180,7 +181,7 @@ public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course> impleme
@Override
public List<Integer> getDepIdsByCourseId(Integer courseId) {
return courseDepartmentService.getDepIdsByCourseId(courseId);
return courseDepartmentUserService.getDepIdsByCourseId(courseId);
}
@Override
@@ -231,7 +232,7 @@ public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course> impleme
return new ArrayList<>();
}
// 获取部门课程ID
List<Integer> courseIds = courseDepartmentService.getCourseIdsByDepIds(depIds);
List<Integer> courseIds = courseDepartmentUserService.getCourseIdsByDepIds(depIds);
if (StringUtil.isEmpty(courseIds)) {
return new ArrayList<>();
}
@@ -258,7 +259,7 @@ public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course> impleme
return new ArrayList<>();
}
// 获取部门课程ID
List<Integer> courseIds = courseDepartmentService.getCourseIdsByDepIds(depIds);
List<Integer> courseIds = courseDepartmentUserService.getCourseIdsByDepIds(depIds);
if (StringUtil.isEmpty(courseIds)) {
return new ArrayList<>();
}
@@ -289,19 +290,21 @@ public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course> impleme
if (courseIds == null || courseIds.size() == 0) {
return null;
}
Map<Integer, List<CourseDepartment>> data =
courseDepartmentService
Map<Integer, List<CourseDepartmentUser>> data =
courseDepartmentUserService
.list(
courseDepartmentService
courseDepartmentUserService
.query()
.getWrapper()
.in("course_id", courseIds))
.stream()
.collect(Collectors.groupingBy(CourseDepartment::getCourseId));
.collect(Collectors.groupingBy(CourseDepartmentUser::getCourseId));
Map<Integer, List<Integer>> result = new HashMap<>();
data.forEach(
(courseId, records) -> {
result.put(courseId, records.stream().map(CourseDepartment::getDepId).toList());
result.put(
courseId,
records.stream().map(CourseDepartmentUser::getRangeId).toList());
});
return result;
}

View File

@@ -37,15 +37,15 @@ public class UserLearnDurationRecordServiceImpl
@Override
@SneakyThrows
public void store(
Integer userId, Integer courseId, Integer hourId, Long startTime, Long endTime) {
Integer userId, String fromId, String fromScene, Long startTime, Long endTime) {
// 处理日期
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
String date = simpleDateFormat.format(new Date(endTime));
UserLearnDurationRecord record = new UserLearnDurationRecord();
record.setUserId(userId);
record.setCourseId(courseId);
record.setHourId(hourId);
record.setFromId(fromId);
record.setFromScene(fromScene);
record.setStartAt(new Date(startTime));
record.setEndAt(new Date(endTime));
record.setDuration((int) (endTime - startTime));

View File

@@ -2,14 +2,15 @@
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="xyz.playedu.course.mapper.CourseDepartmentMapper">
<mapper namespace="xyz.playedu.course.mapper.CourseDepartmentUserMapper">
<resultMap id="BaseResultMap" type="xyz.playedu.course.domain.CourseDepartment">
<result property="courseId" column="course_id" jdbcType="INTEGER"/>
<result property="depId" column="dep_id" jdbcType="INTEGER"/>
<resultMap id="BaseResultMap" type="xyz.playedu.course.domain.CourseDepartmentUser">
<result property="courseId" column="course_id" jdbcType="INTEGER"/>
<result property="rangeId" column="range_id" jdbcType="INTEGER"/>
<result property="type" column="type" jdbcType="INTEGER"/>
</resultMap>
<sql id="Base_Column_List">
course_id,dep_id
course_id,range_id,type
</sql>
</mapper>

View File

@@ -5,25 +5,27 @@
<mapper namespace="xyz.playedu.course.mapper.CourseMapper">
<resultMap id="BaseResultMap" type="xyz.playedu.course.domain.Course">
<id property="id" column="id" jdbcType="INTEGER"/>
<result property="title" column="title" jdbcType="VARCHAR"/>
<result property="thumb" column="thumb" jdbcType="VARCHAR"/>
<result property="shortDesc" column="short_desc" jdbcType="VARCHAR"/>
<result property="charge" column="charge" jdbcType="INTEGER"/>
<result property="classHour" column="class_hour" jdbcType="INTEGER"/>
<result property="isShow" column="is_show" jdbcType="TINYINT"/>
<result property="isRequired" column="is_required" jdbcType="TINYINT"/>
<result property="publishedAt" column="published_at" jdbcType="TIMESTAMP"/>
<result property="createdAt" column="created_at" jdbcType="TIMESTAMP"/>
<result property="updatedAt" column="updated_at" jdbcType="TIMESTAMP"/>
<result property="deletedAt" column="deleted_at" jdbcType="TIMESTAMP"/>
<id property="id" column="id" jdbcType="INTEGER"/>
<result property="title" column="title" jdbcType="VARCHAR"/>
<result property="thumb" column="thumb" jdbcType="VARCHAR"/>
<result property="shortDesc" column="short_desc" jdbcType="VARCHAR"/>
<result property="charge" column="charge" jdbcType="INTEGER"/>
<result property="classHour" column="class_hour" jdbcType="INTEGER"/>
<result property="isShow" column="is_show" jdbcType="TINYINT"/>
<result property="isRequired" column="is_required" jdbcType="TINYINT"/>
<result property="createdAt" column="created_at" jdbcType="TIMESTAMP"/>
<result property="sortAt" column="sort_at" jdbcType="TIMESTAMP"/>
<result property="updatedAt" column="updated_at" jdbcType="TIMESTAMP"/>
<result property="deletedAt" column="deleted_at" jdbcType="TIMESTAMP"/>
<result property="extra" column="extra" jdbcType="VARCHAR"/>
<result property="adminId" column="admin_id" jdbcType="INTEGER"/>
</resultMap>
<sql id="Base_Column_List">
id,title,thumb,short_desc,
charge,class_hour,is_show,
is_required,published_at,created_at,updated_at,
deleted_at
is_required,created_at,updated_at,sort_at,
deleted_at,extra,admin_id
</sql>
<select id="paginate" resultType="xyz.playedu.course.domain.Course">
@@ -32,10 +34,10 @@
<if test="depIds != null and !depIds.isEmpty()">
<choose>
<when test="depIds.get(0) == 0">
LEFT JOIN `course_department` ON `course_department`.`course_id` = `courses`.`id`
LEFT JOIN `course_department_user` ON `course_department_user`.`course_id` = `courses`.`id`
</when>
<otherwise>
INNER JOIN `course_department` ON `course_department`.`course_id` = `courses`.`id`
INNER JOIN `course_department_user` ON `course_department_user`.`course_id` = `courses`.`id`
</otherwise>
</choose>
</if>
@@ -54,10 +56,10 @@
<if test="depIds != null and !depIds.isEmpty()">
<choose>
<when test="depIds.get(0) == 0">
AND `course_department`.`course_id` IS NULL
AND `course_department_user`.`course_id` IS NULL
</when>
<otherwise>
AND `course_department`.`dep_id` IN (<foreach collection="depIds" item="tmpId" separator=",">
AND `course_department_user`.`range_id` IN (<foreach collection="depIds" item="tmpId" separator=",">
#{tmpId}</foreach>)
</otherwise>
</choose>
@@ -127,10 +129,10 @@
<if test="depIds != null and !depIds.isEmpty()">
<choose>
<when test="depIds.get(0) == 0">
LEFT JOIN `course_department` ON `course_department`.`course_id` = `courses`.`id`
LEFT JOIN `course_department_user` ON `course_department_user`.`course_id` = `courses`.`id`
</when>
<otherwise>
INNER JOIN `course_department` ON `course_department`.`course_id` = `courses`.`id`
INNER JOIN `course_department_user` ON `course_department_user`.`course_id` = `courses`.`id`
</otherwise>
</choose>
</if>
@@ -149,10 +151,10 @@
<if test="depIds != null and !depIds.isEmpty()">
<choose>
<when test="depIds.get(0) == 0">
AND `course_department`.`course_id` IS NULL
AND `course_department_user`.`course_id` IS NULL
</when>
<otherwise>
AND `course_department`.`dep_id` IN (<foreach collection="depIds" item="tmpId" separator=",">
AND `course_department_user`.`range_id` IN (<foreach collection="depIds" item="tmpId" separator=",">
#{tmpId}</foreach>)
</otherwise>
</choose>
@@ -185,11 +187,11 @@
<select id="openCoursesAndShow" resultType="xyz.playedu.course.domain.Course">
SELECT `courses`.*
FROM `courses`
LEFT JOIN `course_department` ON `course_department`.`course_id` = `courses`.`id`
LEFT JOIN `course_department_user` ON `course_department_user`.`course_id` = `courses`.`id`
<if test="categoryIds != null and !categoryIds.isEmpty()">
INNER JOIN `resource_course_category` ON `resource_course_category`.`course_id` = `courses`.`id`
</if>
WHERE `course_department`.`course_id` IS NULL
WHERE `course_department_user`.`course_id` IS NULL
AND `courses`.`is_show` = 1
<if test="categoryIds != null and !categoryIds.isEmpty()">
AND `resource_course_category`.`category_id` IN (<foreach collection="categoryIds" item="tmpId"

View File

@@ -26,9 +26,9 @@ import java.util.Date;
import lombok.Data;
/**
* @TableName resources
* @TableName resource
*/
@TableName(value = "resources")
@TableName(value = "resource")
@Data
public class Resource implements Serializable {
/** */
@@ -54,16 +54,9 @@ public class Resource implements Serializable {
/** 存储磁盘 */
private String disk;
/** 文件id */
@JsonProperty("file_id")
private String fileId;
/** 相对地址 */
private String path;
/** URL地址 */
private String url;
/** */
@JsonProperty("created_at")
private Date createdAt;
@@ -109,15 +102,9 @@ public class Resource implements Serializable {
&& (this.getDisk() == null
? other.getDisk() == null
: this.getDisk().equals(other.getDisk()))
&& (this.getFileId() == null
? other.getFileId() == null
: this.getFileId().equals(other.getFileId()))
&& (this.getPath() == null
? other.getPath() == null
: this.getPath().equals(other.getPath()))
&& (this.getUrl() == null
? other.getUrl() == null
: this.getUrl().equals(other.getUrl()))
&& (this.getCreatedAt() == null
? other.getCreatedAt() == null
: this.getCreatedAt().equals(other.getCreatedAt()))
@@ -140,9 +127,7 @@ public class Resource implements Serializable {
result = prime * result + ((getExtension() == null) ? 0 : getExtension().hashCode());
result = prime * result + ((getSize() == null) ? 0 : getSize().hashCode());
result = prime * result + ((getDisk() == null) ? 0 : getDisk().hashCode());
result = prime * result + ((getFileId() == null) ? 0 : getFileId().hashCode());
result = prime * result + ((getPath() == null) ? 0 : getPath().hashCode());
result = prime * result + ((getUrl() == null) ? 0 : getUrl().hashCode());
result = prime * result + ((getCreatedAt() == null) ? 0 : getCreatedAt().hashCode());
result = prime * result + ((getParentId() == null) ? 0 : getParentId().hashCode());
result = prime * result + ((getIsHidden() == null) ? 0 : getIsHidden().hashCode());
@@ -162,9 +147,7 @@ public class Resource implements Serializable {
sb.append(", extension=").append(extension);
sb.append(", size=").append(size);
sb.append(", disk=").append(disk);
sb.append(", fileId=").append(fileId);
sb.append(", path=").append(path);
sb.append(", url=").append(url);
sb.append(", createdAt=").append(createdAt);
sb.append(", parentId=").append(parentId);
sb.append(", isHidden=").append(isHidden);

View File

@@ -19,29 +19,33 @@ import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import java.util.Date;
import lombok.Data;
/**
* @TableName resource_videos
* @TableName resource_extra
*/
@TableName(value = "resource_videos")
@Data
public class ResourceVideo implements Serializable {
@TableName(value = "resource_extra")
public class ResourceExtra implements Serializable {
/** */
@TableId(type = IdType.AUTO)
private Integer id;
/** */
@TableId(type = IdType.NONE)
private Integer rid;
/** 封面 */
private String poster;
private Integer poster;
/** 频时长[s] */
/** 频时长[s] */
private Integer duration;
/** 创建时间 */
@JsonIgnore private Date createdAt;
@JsonProperty("created_at")
private Date createdAt;
@TableField(exist = false)
private static final long serialVersionUID = 1L;
@@ -57,8 +61,9 @@ public class ResourceVideo implements Serializable {
if (getClass() != that.getClass()) {
return false;
}
ResourceVideo other = (ResourceVideo) that;
return (this.getRid() == null
ResourceExtra other = (ResourceExtra) that;
return (this.getId() == null ? other.getId() == null : this.getId().equals(other.getId()))
&& (this.getRid() == null
? other.getRid() == null
: this.getRid().equals(other.getRid()))
&& (this.getPoster() == null
@@ -76,6 +81,7 @@ public class ResourceVideo implements Serializable {
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((getId() == null) ? 0 : getId().hashCode());
result = prime * result + ((getRid() == null) ? 0 : getRid().hashCode());
result = prime * result + ((getPoster() == null) ? 0 : getPoster().hashCode());
result = prime * result + ((getDuration() == null) ? 0 : getDuration().hashCode());
@@ -89,6 +95,7 @@ public class ResourceVideo implements Serializable {
sb.append(getClass().getSimpleName());
sb.append(" [");
sb.append("Hash = ").append(hashCode());
sb.append(", id=").append(id);
sb.append(", rid=").append(rid);
sb.append(", poster=").append(poster);
sb.append(", duration=").append(duration);

View File

@@ -17,7 +17,7 @@ package xyz.playedu.resource.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import xyz.playedu.resource.domain.ResourceVideo;
import xyz.playedu.resource.domain.ResourceExtra;
/**
* @author tengteng
@@ -25,4 +25,4 @@ import xyz.playedu.resource.domain.ResourceVideo;
* @createDate 2023-03-08 13:39:06
*/
@Mapper
public interface ResourceVideoMapper extends BaseMapper<ResourceVideo> {}
public interface ResourceExtraMapper extends BaseMapper<ResourceExtra> {}

View File

@@ -23,7 +23,7 @@ import xyz.playedu.resource.domain.Resource;
/**
* @author tengteng
* @description 针对表【resources】的数据库操作Mapper
* @description 针对表【resource】的数据库操作Mapper
* @createDate 2023-03-13 10:25:30
*/
@Mapper

View File

@@ -17,18 +17,18 @@ package xyz.playedu.resource.service;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
import xyz.playedu.resource.domain.ResourceVideo;
import xyz.playedu.resource.domain.ResourceExtra;
/**
* @author tengteng
* @description 针对表resource_videos的数据库操作Service
* @createDate 2023-03-02 15:13:03
*/
public interface ResourceVideoService extends IService<ResourceVideo> {
public interface ResourceExtraService extends IService<ResourceExtra> {
void create(Integer resourceId, Integer duration, String poster);
void create(Integer resourceId, Integer duration, Integer poster);
void removeByRid(Integer resourceId);
List<ResourceVideo> chunksByRids(List<Integer> resourceIds);
List<ResourceExtra> chunksByRids(List<Integer> resourceIds);
}

View File

@@ -17,6 +17,7 @@ package xyz.playedu.resource.service;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
import java.util.Map;
import xyz.playedu.common.exception.NotFoundException;
import xyz.playedu.common.types.paginate.PaginationResult;
import xyz.playedu.common.types.paginate.ResourcePaginateFilter;
@@ -36,16 +37,25 @@ public interface ResourceService extends IService<Resource> {
String ext,
Long size,
String disk,
String fileId,
String path,
String url);
Integer parentId,
Integer isHidden);
void update(
Resource resource,
Integer adminId,
String categoryIds,
String type,
String filename,
String ext,
Long size,
String disk,
String path,
Integer parentId,
Integer isHidden);
Resource findOrFail(Integer id) throws NotFoundException;
void changeParentId(Integer id, Integer parentId);
void storeResourceVideo(Integer rid, Integer duration, String poster);
List<Resource> chunks(List<Integer> ids);
List<Resource> chunks(List<Integer> ids, List<String> fields);
@@ -59,4 +69,8 @@ public interface ResourceService extends IService<Resource> {
List<Integer> categoryIds(Integer resourceId);
Integer total(List<String> types);
Map<Integer, String> chunksPreSignUrlByIds(List<Integer> ids);
Map<Integer, String> downloadResById(Integer id);
}

View File

@@ -16,9 +16,9 @@
package xyz.playedu.resource.service;
import org.springframework.web.multipart.MultipartFile;
import xyz.playedu.common.domain.UserUploadImageLog;
import xyz.playedu.common.exception.ServiceException;
import xyz.playedu.common.types.UploadFileInfo;
import xyz.playedu.common.types.config.S3Config;
import xyz.playedu.resource.domain.Resource;
/**
@@ -28,14 +28,10 @@ import xyz.playedu.resource.domain.Resource;
*/
public interface UploadService {
UploadFileInfo upload(MultipartFile file, String dir) throws ServiceException;
Resource storeMinio(String disk, Integer adminId, MultipartFile file, String categoryIds)
UploadFileInfo upload(S3Config s3Config, MultipartFile file, String dir)
throws ServiceException;
Resource storeBase64Image(String disk, Integer adminId, String content, String categoryIds)
Resource storeBase64Image(
S3Config s3Config, Integer adminId, String content, String categoryIds)
throws ServiceException;
UserUploadImageLog userAvatar(
String disk, Integer userId, MultipartFile file, String typed, String scene);
}

View File

@@ -20,9 +20,9 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.springframework.stereotype.Service;
import xyz.playedu.resource.domain.ResourceVideo;
import xyz.playedu.resource.mapper.ResourceVideoMapper;
import xyz.playedu.resource.service.ResourceVideoService;
import xyz.playedu.resource.domain.ResourceExtra;
import xyz.playedu.resource.mapper.ResourceExtraMapper;
import xyz.playedu.resource.service.ResourceExtraService;
/**
* @author tengteng
@@ -30,11 +30,11 @@ import xyz.playedu.resource.service.ResourceVideoService;
* @createDate 2023-03-02 15:13:03
*/
@Service
public class ResourceVideoServiceImpl extends ServiceImpl<ResourceVideoMapper, ResourceVideo>
implements ResourceVideoService {
public class ResourceExtraServiceImpl extends ServiceImpl<ResourceExtraMapper, ResourceExtra>
implements ResourceExtraService {
@Override
public void create(Integer resourceId, Integer duration, String poster) {
ResourceVideo video = new ResourceVideo();
public void create(Integer resourceId, Integer duration, Integer poster) {
ResourceExtra video = new ResourceExtra();
video.setRid(resourceId);
video.setDuration(duration);
video.setPoster(poster);
@@ -48,7 +48,7 @@ public class ResourceVideoServiceImpl extends ServiceImpl<ResourceVideoMapper, R
}
@Override
public List<ResourceVideo> chunksByRids(List<Integer> resourceIds) {
public List<ResourceExtra> chunksByRids(List<Integer> resourceIds) {
if (resourceIds == null || resourceIds.size() == 0) {
return new ArrayList<>();
}

View File

@@ -21,29 +21,34 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import xyz.playedu.common.exception.NotFoundException;
import xyz.playedu.common.service.AppConfigService;
import xyz.playedu.common.types.paginate.PaginationResult;
import xyz.playedu.common.types.paginate.ResourcePaginateFilter;
import xyz.playedu.common.util.S3Util;
import xyz.playedu.common.util.StringUtil;
import xyz.playedu.resource.domain.Resource;
import xyz.playedu.resource.domain.ResourceCategory;
import xyz.playedu.resource.domain.ResourceVideo;
import xyz.playedu.resource.domain.ResourceExtra;
import xyz.playedu.resource.mapper.ResourceMapper;
import xyz.playedu.resource.service.ResourceCategoryService;
import xyz.playedu.resource.service.ResourceExtraService;
import xyz.playedu.resource.service.ResourceService;
import xyz.playedu.resource.service.ResourceVideoService;
/**
* @author tengteng
* @description 针对表【resources】的数据库操作Service实现
* @description 针对表【resource】的数据库操作Service实现
* @createDate 2023-02-23 10:50:26
*/
@Service
public class ResourceServiceImpl extends ServiceImpl<ResourceMapper, Resource>
implements ResourceService {
@Autowired private ResourceVideoService resourceVideoService;
@Autowired private ResourceExtraService resourceExtraService;
@Autowired private ResourceCategoryService relationService;
@Autowired private AppConfigService appConfigService;
@Override
public PaginationResult<Resource> paginate(int page, int size, ResourcePaginateFilter filter) {
PaginationResult<Resource> pageResult = new PaginationResult<>();
@@ -72,9 +77,9 @@ public class ResourceServiceImpl extends ServiceImpl<ResourceMapper, Resource>
String ext,
Long size,
String disk,
String fileId,
String path,
String url) {
Integer parentId,
Integer isHidden) {
Resource resource = new Resource();
resource.setAdminId(adminId);
resource.setType(type);
@@ -82,10 +87,10 @@ public class ResourceServiceImpl extends ServiceImpl<ResourceMapper, Resource>
resource.setExtension(ext);
resource.setSize(size);
resource.setDisk(disk);
resource.setFileId(fileId);
resource.setPath(path);
resource.setUrl(url);
resource.setCreatedAt(new Date());
resource.setParentId(parentId);
resource.setIsHidden(isHidden);
save(resource);
if (categoryIds != null && categoryIds.trim().length() > 0) {
@@ -109,6 +114,52 @@ public class ResourceServiceImpl extends ServiceImpl<ResourceMapper, Resource>
return resource;
}
@Override
@Transactional
public void update(
Resource resource,
Integer adminId,
String categoryIds,
String type,
String filename,
String ext,
Long size,
String disk,
String path,
Integer parentId,
Integer isHidden) {
resource.setAdminId(adminId);
resource.setType(type);
resource.setName(filename);
resource.setExtension(ext);
resource.setSize(size);
resource.setDisk(disk);
resource.setPath(path);
resource.setCreatedAt(new Date());
resource.setParentId(parentId);
resource.setIsHidden(isHidden);
updateById(resource);
if (categoryIds != null && categoryIds.trim().length() > 0) {
String[] idArray = categoryIds.split(",");
List<ResourceCategory> relations = new ArrayList<>();
for (String s : idArray) {
int tmpId = Integer.parseInt(s);
if (tmpId == 0) {
continue;
}
relations.add(
new ResourceCategory() {
{
setCid(tmpId);
setRid(resource.getId());
}
});
}
relationService.saveBatch(relations);
}
}
@Override
public Resource findOrFail(Integer id) throws NotFoundException {
Resource resource = getById(id);
@@ -118,20 +169,6 @@ public class ResourceServiceImpl extends ServiceImpl<ResourceMapper, Resource>
return resource;
}
@Override
public void changeParentId(Integer id, Integer parentId) {
Resource resource = new Resource();
resource.setId(id);
resource.setParentId(parentId);
resource.setIsHidden(1);
updateById(resource);
}
@Override
public void storeResourceVideo(Integer rid, Integer duration, String poster) {
resourceVideoService.create(rid, duration, poster);
}
@Override
public List<Resource> chunks(List<Integer> ids) {
return list(query().getWrapper().in("id", ids));
@@ -149,13 +186,13 @@ public class ResourceServiceImpl extends ServiceImpl<ResourceMapper, Resource>
@Override
public Integer duration(Integer id) {
ResourceVideo resourceVideo =
resourceVideoService.getOne(
resourceVideoService.query().getWrapper().eq("rid", id));
if (resourceVideo == null) {
ResourceExtra resourceExtra =
resourceExtraService.getOne(
resourceExtraService.query().getWrapper().eq("rid", id));
if (resourceExtra == null) {
return null;
}
return resourceVideo.getDuration();
return resourceExtra.getDuration();
}
@Override
@@ -188,4 +225,46 @@ public class ResourceServiceImpl extends ServiceImpl<ResourceMapper, Resource>
public Integer total(List<String> types) {
return Math.toIntExact(count(query().getWrapper().in("type", types).eq("is_hidden", 0)));
}
@Override
public Map<Integer, String> chunksPreSignUrlByIds(List<Integer> ids) {
if (StringUtil.isEmpty(ids)) {
return new HashMap<>();
}
S3Util s3Util = new S3Util(appConfigService.getS3Config());
Map<Integer, String> preSignUrlMap = new HashMap<>();
List<Resource> resourceList = list(query().getWrapper().in("id", ids));
if (StringUtil.isNotEmpty(resourceList)) {
resourceList.forEach(
resource -> {
String path = resource.getPath();
try {
String url = s3Util.generateEndpointPreSignUrl(path, "");
if (StringUtil.isNotEmpty(url)) {
preSignUrlMap.put(resource.getId(), url);
}
} catch (Exception e) {
log.error(e.getMessage());
}
});
}
return preSignUrlMap;
}
@Override
public Map<Integer, String> downloadResById(Integer id) {
Map<Integer, String> preSignUrlMap = new HashMap<>();
Resource resource = getById(id);
if (StringUtil.isNotNull(resource)) {
String name = resource.getName() + "." + resource.getExtension();
String url =
new S3Util(appConfigService.getS3Config())
.generateEndpointPreSignUrl(resource.getPath(), name);
if (StringUtil.isNotEmpty(url)) {
preSignUrlMap.put(resource.getId(), url);
}
}
return preSignUrlMap;
}
}

View File

@@ -15,22 +15,21 @@
*/
package xyz.playedu.resource.service.impl;
import java.util.Date;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import xyz.playedu.common.constant.BackendConstant;
import xyz.playedu.common.constant.FrontendConstant;
import xyz.playedu.common.domain.UserUploadImageLog;
import xyz.playedu.common.constant.CommonConstant;
import xyz.playedu.common.exception.ServiceException;
import xyz.playedu.common.service.AppConfigService;
import xyz.playedu.common.service.UserUploadImageLogService;
import xyz.playedu.common.types.UploadFileInfo;
import xyz.playedu.common.types.config.S3Config;
import xyz.playedu.common.util.Base64Util;
import xyz.playedu.common.util.HelperUtil;
import xyz.playedu.common.util.S3Util;
import xyz.playedu.common.util.StringUtil;
import xyz.playedu.resource.domain.Resource;
import xyz.playedu.resource.service.ResourceService;
import xyz.playedu.resource.service.UploadService;
@@ -43,12 +42,10 @@ public class UploadServiceImpl implements UploadService {
@Autowired private AppConfigService appConfigService;
@Autowired private UserUploadImageLogService userUploadImageLogService;
@Override
@SneakyThrows
public UploadFileInfo upload(MultipartFile file, String dir) {
if (file == null || file.isEmpty() || file.getOriginalFilename() == null) {
public UploadFileInfo upload(S3Config s3Config, MultipartFile file, String dir) {
if (file == null || file.isEmpty() || StringUtil.isEmpty(file.getOriginalFilename())) {
throw new ServiceException("请上传文件");
}
@@ -59,12 +56,17 @@ public class UploadServiceImpl implements UploadService {
// 文件大小
fileInfo.setSize(file.getSize());
// 解析扩展名
fileInfo.setExtension(HelperUtil.fileExt(filename));
fileInfo.setExtension(HelperUtil.fileExt(filename).toLowerCase());
// 解析扩展名称对应的系统资源类型
fileInfo.setResourceType(BackendConstant.RESOURCE_EXT_2_TYPE.get(fileInfo.getExtension()));
String type = BackendConstant.RESOURCE_EXT_2_TYPE.get(fileInfo.getExtension());
// 附件模块上传文件 非系统格式统一为OTHER
if (StringUtil.isEmpty(type)) {
type = BackendConstant.RESOURCE_TYPE_OTHER;
}
fileInfo.setResourceType(type);
// 检测是否为系统不支持的资源类型
if (fileInfo.getResourceType() == null) {
throw new ServiceException("当前资源扩展不支持上传");
if (StringUtil.isEmpty(fileInfo.getResourceType())) {
throw new ServiceException("当前格式不支持");
}
// 上传原文件的文件名
@@ -72,45 +74,24 @@ public class UploadServiceImpl implements UploadService {
// 自定义新的存储文件名
fileInfo.setSaveName(HelperUtil.randomString(32) + "." + fileInfo.getExtension());
// 生成保存的相对路径
if (dir == null || dir.isEmpty()) {
if (StringUtil.isEmpty(dir)) {
dir = BackendConstant.RESOURCE_TYPE_2_DIR.get(fileInfo.getResourceType());
}
fileInfo.setSavePath(dir + fileInfo.getSaveName());
// 保存文件并生成访问url
S3Util s3Util = new S3Util(appConfigService.getS3Config());
String url =
s3Util.saveFile(
// 保存文件
new S3Util(s3Config)
.saveFile(
file,
fileInfo.getSavePath(),
BackendConstant.RESOURCE_EXT_2_CONTENT_TYPE.get(fileInfo.getExtension()));
fileInfo.setUrl(url);
fileInfo.setDisk("");
return fileInfo;
}
@Override
@SneakyThrows
public Resource storeMinio(
String disk, Integer adminId, MultipartFile file, String categoryIds) {
UploadFileInfo info = upload(file, null);
return resourceService.create(
adminId,
categoryIds,
info.getResourceType(),
info.getOriginalName(),
info.getExtension(),
file.getSize(),
disk,
"",
info.getSavePath(),
info.getUrl());
}
@Override
@SneakyThrows
public Resource storeBase64Image(
String disk, Integer adminId, String content, String categoryIds) {
S3Config s3Config, Integer adminId, String content, String categoryIds) {
// data:image/jpeg;base64,
String[] base64Rows = content.split(",");
// 解析出content-type
@@ -121,8 +102,8 @@ public class UploadServiceImpl implements UploadService {
// 通过文件格式解析资源类型
String type = BackendConstant.RESOURCE_EXT_2_TYPE.get(ext);
// 资源类型必须存在
if (type == null) {
throw new ServiceException("资源类型不支持");
if (StringUtil.isEmpty(type)) {
throw new ServiceException("当前格式不支持");
}
byte[] binary = Base64Util.decode(base64Rows[1]);
@@ -130,10 +111,9 @@ public class UploadServiceImpl implements UploadService {
String savePath = BackendConstant.RESOURCE_TYPE_2_DIR.get(type) + filename;
// 保存文件
S3Util s3Util = new S3Util(appConfigService.getS3Config());
String url =
s3Util.saveBytes(
binary, savePath, BackendConstant.RESOURCE_EXT_2_CONTENT_TYPE.get(ext));
new S3Util(s3Config)
.saveBytes(binary, savePath, BackendConstant.RESOURCE_EXT_2_CONTENT_TYPE.get(ext));
// 上传记录
return resourceService.create(
adminId,
@@ -142,28 +122,9 @@ public class UploadServiceImpl implements UploadService {
filename,
ext,
(long) binary.length,
disk,
"",
savePath,
url);
}
@Override
@SneakyThrows
public UserUploadImageLog userAvatar(
String disk, Integer userId, MultipartFile file, String typed, String scene) {
UploadFileInfo info = upload(file, FrontendConstant.DIR_AVATAR);
UserUploadImageLog log = new UserUploadImageLog();
log.setUserId(userId);
log.setTyped(typed);
log.setScene(scene);
log.setSize(info.getSize());
log.setDriver(disk);
log.setPath(info.getSavePath());
log.setUrl(info.getUrl());
log.setName(info.getOriginalName());
log.setCreatedAt(new Date());
userUploadImageLogService.save(log);
return log;
CommonConstant.ZERO,
CommonConstant.ONE);
}
}

View File

@@ -12,9 +12,7 @@
<result property="extension" column="extension" jdbcType="VARCHAR"/>
<result property="size" column="size" jdbcType="BIGINT"/>
<result property="disk" column="disk" jdbcType="VARCHAR"/>
<result property="fileId" column="file_id" jdbcType="VARCHAR"/>
<result property="path" column="path" jdbcType="VARCHAR"/>
<result property="url" column="url" jdbcType="VARCHAR"/>
<result property="createdAt" column="created_at" jdbcType="TIMESTAMP"/>
<result property="parentId" column="parent_id" jdbcType="INTEGER"/>
<result property="isHidden" column="is_hidden" jdbcType="TINYINT"/>
@@ -24,75 +22,74 @@
id
,admin_id,type,
name,extension,size,
disk,file_id,path,
url,created_at,parent_id,
disk,path,created_at,parent_id,
is_hidden
</sql>
<select id="paginate" resultType="xyz.playedu.resource.domain.Resource">
SELECT `resources`.*
FROM `resources`
SELECT `resource`.*
FROM `resource`
<choose>
<when test="categoryIds != null and !categoryIds.isEmpty()">
<choose>
<when test="categoryIds.get(0) == 0">
LEFT JOIN `resource_category` ON `resource_category`.`rid` = `resources`.`id`
WHERE `resources`.`is_hidden` = 0
LEFT JOIN `resource_category` ON `resource_category`.`rid` = `resource`.`id`
WHERE `resource`.`is_hidden` = 0
AND `resource_category`.`cid` IS NULL
</when>
<otherwise>
INNER JOIN `resource_category` ON `resource_category`.`rid` = `resources`.`id`
WHERE `resources`.`is_hidden` = 0
INNER JOIN `resource_category` ON `resource_category`.`rid` = `resource`.`id`
WHERE `resource`.`is_hidden` = 0
AND `resource_category`.`cid` IN (<foreach collection="categoryIds" item="tmpId" separator=",">
#{tmpId}</foreach>)
</otherwise>
</choose>
</when>
<otherwise>
WHERE `resources`.`is_hidden` = 0
WHERE `resource`.`is_hidden` = 0
</otherwise>
</choose>
<if test="name != null and name != ''">
AND `resources`.`name` LIKE concat('%',#{name},'%')
AND `resource`.`name` LIKE concat('%',#{name},'%')
</if>
<if test="disk != null and disk != ''">
AND `resources`.`disk` = #{disk}
AND `resource`.`disk` = #{disk}
</if>
<if test="extension != null and extension != ''">
AND `resources`.`extension` = #{extension}
AND `resource`.`extension` = #{extension}
</if>
<if test="type != null and type != ''">
AND `resources`.`type` IN
AND `resource`.`type` IN
<foreach item="item" collection="type.split(',')" open="(" separator="," close=")">
#{item}
</foreach>
</if>
<if test="adminId != null and adminId != 0">
AND `resources`.`admin_id` = #{adminId}
AND `resource`.`admin_id` = #{adminId}
</if>
<if test="sortAlgo == 'asc'">
<choose>
<when test="sortField == 'size'">
ORDER BY `resources`.`size` ASC
ORDER BY `resource`.`size` ASC
</when>
<when test="sortField == 'created_at'">
ORDER BY `resources`.`created_at` ASC
ORDER BY `resource`.`created_at` ASC
</when>
<otherwise>
ORDER BY `resources`.`id` ASC
ORDER BY `resource`.`id` ASC
</otherwise>
</choose>
</if>
<if test="sortAlgo != 'asc'">
<choose>
<when test="sortField == 'size'">
ORDER BY `resources`.`size` DESC
ORDER BY `resource`.`size` DESC
</when>
<when test="sortField == 'created_at'">
ORDER BY `resources`.`created_at` DESC
ORDER BY `resource`.`created_at` DESC
</when>
<otherwise>
ORDER BY `resources`.`id` DESC
ORDER BY `resource`.`id` DESC
</otherwise>
</choose>
</if>
@@ -101,87 +98,87 @@
<select id="paginateCount" resultType="java.lang.Long">
SELECT count(1)
FROM `resources`
FROM `resource`
<choose>
<when test="categoryIds != null and !categoryIds.isEmpty()">
<choose>
<when test="categoryIds.get(0) == 0">
LEFT JOIN `resource_category` ON `resource_category`.`rid` = `resources`.`id`
WHERE `resources`.`is_hidden` = 0
LEFT JOIN `resource_category` ON `resource_category`.`rid` = `resource`.`id`
WHERE `resource`.`is_hidden` = 0
AND `resource_category`.`cid` IS NULL
</when>
<otherwise>
INNER JOIN `resource_category` ON `resource_category`.`rid` = `resources`.`id`
WHERE `resources`.`is_hidden` = 0
INNER JOIN `resource_category` ON `resource_category`.`rid` = `resource`.`id`
WHERE `resource`.`is_hidden` = 0
AND `resource_category`.`cid` IN (<foreach collection="categoryIds" item="tmpId" separator=",">
#{tmpId}</foreach>)
</otherwise>
</choose>
</when>
<otherwise>
WHERE `resources`.`is_hidden` = 0
WHERE `resource`.`is_hidden` = 0
</otherwise>
</choose>
<if test="name != null and name != ''">
AND `resources`.`name` LIKE concat('%',#{name},'%')
AND `resource`.`name` LIKE concat('%',#{name},'%')
</if>
<if test="disk != null and disk != ''">
AND `resources`.`disk` = #{disk}
AND `resource`.`disk` = #{disk}
</if>
<if test="extension != null and extension != ''">
AND `resources`.`extension` = #{extension}
AND `resource`.`extension` = #{extension}
</if>
<if test="type != null and type != ''">
AND `resources`.`type` IN
AND `resource`.`type` IN
<foreach item="item" collection="type.split(',')" open="(" separator="," close=")">
#{item}
</foreach>
</if>
<if test="adminId != null and adminId != 0">
AND `resources`.`admin_id` = #{adminId}
AND `resource`.`admin_id` = #{adminId}
</if>
</select>
<select id="paginateType" resultType="java.lang.String">
SELECT DISTINCT ( `resources`.`type` )
FROM `resources`
SELECT DISTINCT ( `resource`.`type` )
FROM `resource`
<choose>
<when test="categoryIds != null and !categoryIds.isEmpty()">
<choose>
<when test="categoryIds.get(0) == 0">
LEFT JOIN `resource_category` ON `resource_category`.`rid` = `resources`.`id`
WHERE `resources`.`is_hidden` = 0
LEFT JOIN `resource_category` ON `resource_category`.`rid` = `resource`.`id`
WHERE `resource`.`is_hidden` = 0
AND `resource_category`.`cid` IS NULL
</when>
<otherwise>
INNER JOIN `resource_category` ON `resource_category`.`rid` = `resources`.`id`
WHERE `resources`.`is_hidden` = 0
INNER JOIN `resource_category` ON `resource_category`.`rid` = `resource`.`id`
WHERE `resource`.`is_hidden` = 0
AND `resource_category`.`cid` IN (<foreach collection="categoryIds" item="tmpId" separator=",">
#{tmpId}</foreach>)
</otherwise>
</choose>
</when>
<otherwise>
WHERE `resources`.`is_hidden` = 0
WHERE `resource`.`is_hidden` = 0
</otherwise>
</choose>
<if test="name != null and name != ''">
AND `resources`.`name` LIKE concat('%',#{name},'%')
AND `resource`.`name` LIKE concat('%',#{name},'%')
</if>
<if test="disk != null and disk != ''">
AND `resources`.`disk` = #{disk}
AND `resource`.`disk` = #{disk}
</if>
<if test="extension != null and extension != ''">
AND `resources`.`extension` = #{extension}
AND `resource`.`extension` = #{extension}
</if>
<if test="type != null and type != ''">
AND `resources`.`type` IN
AND `resource`.`type` IN
<foreach item="item" collection="type.split(',')" open="(" separator="," close=")">
#{item}
</foreach>
</if>
<if test="adminId != null and adminId != 0">
AND `resources`.`admin_id` = #{adminId}
AND `resource`.`admin_id` = #{adminId}
</if>
</select>

View File

@@ -2,9 +2,9 @@
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="xyz.playedu.resource.mapper.ResourceVideoMapper">
<mapper namespace="xyz.playedu.resource.mapper.ResourceExtraMapper">
<resultMap id="BaseResultMap" type="xyz.playedu.resource.domain.ResourceVideo">
<resultMap id="BaseResultMap" type="xyz.playedu.resource.domain.ResourceExtra">
<result property="rid" column="rid" jdbcType="INTEGER"/>
<result property="poster" column="poster" jdbcType="VARCHAR"/>
<result property="duration" column="duration" jdbcType="INTEGER"/>

View File

@@ -55,16 +55,6 @@ public class AppConfigCheck implements CommandLineRunner {
setKeyValue("");
}
},
new AppConfig() {
{
setName("API访问地址");
setSort(30);
setFieldType(BackendConstant.APP_CONFIG_FIELD_TYPE_INPUT);
setKeyName(ConfigConstant.SYSTEM_API_URL);
setKeyValue("");
setHelp("请输入API访问地址");
}
},
new AppConfig() {
{
setName("PC端口访问地址");
@@ -174,17 +164,6 @@ public class AppConfigCheck implements CommandLineRunner {
put(
"S3存储",
new AppConfig[] {
new AppConfig() {
{
setName("服务商");
setSort(1);
setFieldType(BackendConstant.APP_CONFIG_FIELD_TYPE_SELECT);
setKeyName(ConfigConstant.S3_SERVICE);
setKeyValue("");
setOptionValue(
"[{\"name\":\"阿里云OSS\",\"value\":\"oss\"},{\"name\":\"腾讯云COS\",\"value\":\"cos\"}]");
}
},
new AppConfig() {
{
setName("AccessKey");
@@ -231,15 +210,6 @@ public class AppConfigCheck implements CommandLineRunner {
setKeyValue("");
}
},
new AppConfig() {
{
setName("Domain");
setSort(50);
setFieldType(BackendConstant.APP_CONFIG_FIELD_TYPE_TEXT);
setKeyName(ConfigConstant.S3_DOMAIN);
setKeyValue("");
}
},
});
put(
"LDAP配置",