software copyright
This commit is contained in:
@@ -0,0 +1,423 @@
|
||||
/*
|
||||
* 自然写教学资源管理与内容分发系统软件 V1.0
|
||||
* model/Resource.java - 资源数据模型
|
||||
* model/DotPattern.java - 点阵码模型
|
||||
* model/AuditRecord.java - 审核记录模型
|
||||
* config/OssConfig.java - OSS对象存储配置
|
||||
* config/ElasticsearchConfig.java - ES配置
|
||||
* security/ResourceSecurity.java - 资源安全(防盗链+水印)
|
||||
*/
|
||||
package com.writech.resource.model;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 资源数据模型(对应MySQL resource表)
|
||||
*/
|
||||
public class Resource {
|
||||
|
||||
/** 资源ID(UUID) */
|
||||
private String id;
|
||||
|
||||
/** 资源名称 */
|
||||
private String name;
|
||||
|
||||
/** 资源描述 */
|
||||
private String description;
|
||||
|
||||
/** 资源类型(COURSEWARE/COPYBOOK/EXAM_PAPER/TEMPLATE/DOT_CODE/VIDEO) */
|
||||
private String type;
|
||||
|
||||
/** 学科 */
|
||||
private String subject;
|
||||
|
||||
/** 适用年级 */
|
||||
private String grade;
|
||||
|
||||
/** 出版社 */
|
||||
private String publisher;
|
||||
|
||||
/** 版本号 */
|
||||
private String version;
|
||||
|
||||
/** 审核状态(PENDING/APPROVED/REJECTED/WITHDRAWN) */
|
||||
private String auditStatus;
|
||||
|
||||
/** OSS文件存储Key */
|
||||
private String fileKey;
|
||||
|
||||
/** 文件大小(字节) */
|
||||
private long fileSize;
|
||||
|
||||
/** MIME类型 */
|
||||
private String mimeType;
|
||||
|
||||
/** 缩略图URL */
|
||||
private String thumbnailUrl;
|
||||
|
||||
/** 上传者ID */
|
||||
private String uploaderId;
|
||||
|
||||
/** 上传者姓名 */
|
||||
private String uploaderName;
|
||||
|
||||
/** 所属学校ID */
|
||||
private String schoolId;
|
||||
|
||||
/** 标签(逗号分隔) */
|
||||
private String tags;
|
||||
|
||||
/** 下载次数 */
|
||||
private int downloadCount;
|
||||
|
||||
/** 使用次数 */
|
||||
private int useCount;
|
||||
|
||||
/** 创建时间 */
|
||||
private Date createdAt;
|
||||
|
||||
/** 更新时间 */
|
||||
private Date updatedAt;
|
||||
|
||||
/** 是否已删除(软删除标记) */
|
||||
private boolean deleted;
|
||||
|
||||
// ============================================================
|
||||
// Getter / Setter
|
||||
// ============================================================
|
||||
|
||||
public String getId() { return id; }
|
||||
public void setId(String id) { this.id = id; }
|
||||
public String getName() { return name; }
|
||||
public void setName(String name) { this.name = name; }
|
||||
public String getDescription() { return description; }
|
||||
public void setDescription(String description) { this.description = description; }
|
||||
public String getType() { return type; }
|
||||
public void setType(String type) { this.type = type; }
|
||||
public String getSubject() { return subject; }
|
||||
public void setSubject(String subject) { this.subject = subject; }
|
||||
public String getGrade() { return grade; }
|
||||
public void setGrade(String grade) { this.grade = grade; }
|
||||
public String getPublisher() { return publisher; }
|
||||
public void setPublisher(String publisher) { this.publisher = publisher; }
|
||||
public String getVersion() { return version; }
|
||||
public void setVersion(String version) { this.version = version; }
|
||||
public String getAuditStatus() { return auditStatus; }
|
||||
public void setAuditStatus(String auditStatus) { this.auditStatus = auditStatus; }
|
||||
public String getFileKey() { return fileKey; }
|
||||
public void setFileKey(String fileKey) { this.fileKey = fileKey; }
|
||||
public long getFileSize() { return fileSize; }
|
||||
public void setFileSize(long fileSize) { this.fileSize = fileSize; }
|
||||
public String getMimeType() { return mimeType; }
|
||||
public void setMimeType(String mimeType) { this.mimeType = mimeType; }
|
||||
public String getThumbnailUrl() { return thumbnailUrl; }
|
||||
public void setThumbnailUrl(String thumbnailUrl) { this.thumbnailUrl = thumbnailUrl; }
|
||||
public String getUploaderId() { return uploaderId; }
|
||||
public void setUploaderId(String uploaderId) { this.uploaderId = uploaderId; }
|
||||
public String getSchoolId() { return schoolId; }
|
||||
public void setSchoolId(String schoolId) { this.schoolId = schoolId; }
|
||||
public String getTags() { return tags; }
|
||||
public void setTags(String tags) { this.tags = tags; }
|
||||
public int getDownloadCount() { return downloadCount; }
|
||||
public int getUseCount() { return useCount; }
|
||||
public Date getCreatedAt() { return createdAt; }
|
||||
public Date getUpdatedAt() { return updatedAt; }
|
||||
public boolean isDeleted() { return deleted; }
|
||||
public void setDeleted(boolean deleted) { this.deleted = deleted; }
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Resource{id='" + id + "', name='" + name + "', type='" + type +
|
||||
"', subject='" + subject + "', grade='" + grade + "'}";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 点阵码模型(对应MySQL dot_pattern表 + OSS文件)
|
||||
*/
|
||||
class DotPattern {
|
||||
|
||||
/** 点阵码ID(全局唯一) */
|
||||
private long dotCodeId;
|
||||
|
||||
/** 关联的资源ID */
|
||||
private String resourceId;
|
||||
|
||||
/** 页面序号 */
|
||||
private int pageIndex;
|
||||
|
||||
/** 区域类型 */
|
||||
private String areaType;
|
||||
|
||||
/** 区域坐标和尺寸(mm) */
|
||||
private double areaX;
|
||||
private double areaY;
|
||||
private double areaWidth;
|
||||
private double areaHeight;
|
||||
|
||||
/** 点阵码图案文件OSS Key */
|
||||
private String patternFileKey;
|
||||
|
||||
/** 生成参数JSON */
|
||||
private String generateParams;
|
||||
|
||||
/** 状态(ACTIVE/REVOKED) */
|
||||
private String status;
|
||||
|
||||
/** 创建时间 */
|
||||
private Date createdAt;
|
||||
|
||||
public long getDotCodeId() { return dotCodeId; }
|
||||
public void setDotCodeId(long id) { this.dotCodeId = id; }
|
||||
public String getResourceId() { return resourceId; }
|
||||
public void setResourceId(String rid) { this.resourceId = rid; }
|
||||
public int getPageIndex() { return pageIndex; }
|
||||
public void setPageIndex(int idx) { this.pageIndex = idx; }
|
||||
public String getAreaType() { return areaType; }
|
||||
public void setAreaType(String type) { this.areaType = type; }
|
||||
public double getAreaX() { return areaX; }
|
||||
public double getAreaY() { return areaY; }
|
||||
public double getAreaWidth() { return areaWidth; }
|
||||
public double getAreaHeight() { return areaHeight; }
|
||||
public String getPatternFileKey() { return patternFileKey; }
|
||||
public String getStatus() { return status; }
|
||||
public void setStatus(String status) { this.status = status; }
|
||||
public Date getCreatedAt() { return createdAt; }
|
||||
}
|
||||
|
||||
/**
|
||||
* 审核记录模型(对应MySQL audit_record表)
|
||||
*/
|
||||
class AuditRecord {
|
||||
|
||||
/** 记录ID */
|
||||
private String id;
|
||||
|
||||
/** 关联的资源ID */
|
||||
private String resourceId;
|
||||
|
||||
/** 审核人ID */
|
||||
private String auditorId;
|
||||
|
||||
/** 审核人姓名 */
|
||||
private String auditorName;
|
||||
|
||||
/** 审核操作(APPROVE/REJECT/RETURN/WITHDRAW) */
|
||||
private String action;
|
||||
|
||||
/** 审核意见 */
|
||||
private String comment;
|
||||
|
||||
/** 审核前状态 */
|
||||
private String preStatus;
|
||||
|
||||
/** 审核后状态 */
|
||||
private String postStatus;
|
||||
|
||||
/** 审核时间 */
|
||||
private Date createdAt;
|
||||
|
||||
public String getId() { return id; }
|
||||
public void setId(String id) { this.id = id; }
|
||||
public String getResourceId() { return resourceId; }
|
||||
public void setResourceId(String rid) { this.resourceId = rid; }
|
||||
public String getAuditorId() { return auditorId; }
|
||||
public void setAuditorId(String aid) { this.auditorId = aid; }
|
||||
public String getAction() { return action; }
|
||||
public void setAction(String action) { this.action = action; }
|
||||
public String getComment() { return comment; }
|
||||
public void setComment(String comment) { this.comment = comment; }
|
||||
public String getPreStatus() { return preStatus; }
|
||||
public String getPostStatus() { return postStatus; }
|
||||
public Date getCreatedAt() { return createdAt; }
|
||||
}
|
||||
|
||||
/**
|
||||
* OSS对象存储配置
|
||||
*
|
||||
* 多副本冗余存储(99.99%数据持久性),
|
||||
* 支持STS临时凭证直传,生命周期管理。
|
||||
*/
|
||||
class OssConfig {
|
||||
|
||||
/** OSS区域端点 */
|
||||
private String endpoint;
|
||||
|
||||
/** 存储桶名称 */
|
||||
private String bucketName;
|
||||
|
||||
/** AccessKey ID */
|
||||
private String accessKeyId;
|
||||
|
||||
/** AccessKey Secret(加密存储) */
|
||||
private String accessKeySecret;
|
||||
|
||||
/** STS角色ARN(用于前端直传临时授权) */
|
||||
private String stsRoleArn;
|
||||
|
||||
/** STS会话名称 */
|
||||
private String stsSessionName;
|
||||
|
||||
/** 资源前缀路径 */
|
||||
private String resourcePrefix;
|
||||
|
||||
/** 缩略图前缀路径 */
|
||||
private String thumbnailPrefix;
|
||||
|
||||
/** 临时文件过期天数 */
|
||||
private int tempFileExpireDays;
|
||||
|
||||
public OssConfig() {
|
||||
this.endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
|
||||
this.bucketName = "writech-resources";
|
||||
this.resourcePrefix = "resources/";
|
||||
this.thumbnailPrefix = "thumbnails/";
|
||||
this.tempFileExpireDays = 7;
|
||||
this.stsSessionName = "writech-upload-session";
|
||||
}
|
||||
|
||||
public String getEndpoint() { return endpoint; }
|
||||
public void setEndpoint(String ep) { this.endpoint = ep; }
|
||||
public String getBucketName() { return bucketName; }
|
||||
public void setBucketName(String name) { this.bucketName = name; }
|
||||
public String getAccessKeyId() { return accessKeyId; }
|
||||
public void setAccessKeyId(String id) { this.accessKeyId = id; }
|
||||
public String getAccessKeySecret() { return accessKeySecret; }
|
||||
public void setAccessKeySecret(String secret) { this.accessKeySecret = secret; }
|
||||
public String getStsRoleArn() { return stsRoleArn; }
|
||||
public void setStsRoleArn(String arn) { this.stsRoleArn = arn; }
|
||||
public String getResourcePrefix() { return resourcePrefix; }
|
||||
public String getThumbnailPrefix() { return thumbnailPrefix; }
|
||||
public int getTempFileExpireDays() { return tempFileExpireDays; }
|
||||
}
|
||||
|
||||
/**
|
||||
* Elasticsearch配置
|
||||
*
|
||||
* ES集群部署,索引按学科/年级分片,
|
||||
* 支持IK中文分词器。
|
||||
*/
|
||||
class ElasticsearchConfig {
|
||||
|
||||
/** ES集群节点列表 */
|
||||
private List<String> nodes;
|
||||
|
||||
/** 连接超时(毫秒) */
|
||||
private int connectTimeout;
|
||||
|
||||
/** 读取超时(毫秒) */
|
||||
private int socketTimeout;
|
||||
|
||||
/** 索引名称 */
|
||||
private String indexName;
|
||||
|
||||
/** 分片数 */
|
||||
private int shards;
|
||||
|
||||
/** 副本数 */
|
||||
private int replicas;
|
||||
|
||||
/** 用户名(X-Pack安全) */
|
||||
private String username;
|
||||
|
||||
/** 密码 */
|
||||
private String password;
|
||||
|
||||
public ElasticsearchConfig() {
|
||||
this.nodes = Arrays.asList("localhost:9200");
|
||||
this.connectTimeout = 5000;
|
||||
this.socketTimeout = 30000;
|
||||
this.indexName = "writech_resources";
|
||||
this.shards = 3;
|
||||
this.replicas = 1;
|
||||
}
|
||||
|
||||
public List<String> getNodes() { return nodes; }
|
||||
public void setNodes(List<String> nodes) { this.nodes = nodes; }
|
||||
public int getConnectTimeout() { return connectTimeout; }
|
||||
public int getSocketTimeout() { return socketTimeout; }
|
||||
public String getIndexName() { return indexName; }
|
||||
public int getShards() { return shards; }
|
||||
public int getReplicas() { return replicas; }
|
||||
public String getUsername() { return username; }
|
||||
public void setUsername(String u) { this.username = u; }
|
||||
public String getPassword() { return password; }
|
||||
public void setPassword(String p) { this.password = p; }
|
||||
}
|
||||
|
||||
/**
|
||||
* 资源安全服务
|
||||
*
|
||||
* 负责:
|
||||
* - 防盗链(Referer校验 + 签名URL)
|
||||
* - 数字水印(PDF/图片添加学校教师标识水印)
|
||||
* - 权限控制(按学校/区域授权)
|
||||
* - 点阵码安全(全局唯一分配防冲突)
|
||||
*/
|
||||
class ResourceSecurity {
|
||||
|
||||
/** 防盗链Referer白名单 */
|
||||
private static final Set<String> REFERER_WHITELIST = new HashSet<>(Arrays.asList(
|
||||
"*.writech.com",
|
||||
"localhost"
|
||||
));
|
||||
|
||||
/**
|
||||
* 校验资源访问权限
|
||||
*
|
||||
* 规则:
|
||||
* - 管理员:可访问本校所有资源
|
||||
* - 教师:可访问本校已授权资源
|
||||
* - 学生/家长:仅可访问已分配的资源
|
||||
*/
|
||||
public boolean checkPermission(
|
||||
String userId,
|
||||
String userRole,
|
||||
String userSchoolId,
|
||||
String resourceSchoolId
|
||||
) {
|
||||
// 超级管理员无限制
|
||||
if ("super_admin".equals(userRole)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 校级管理员和教师:必须同校
|
||||
if ("admin".equals(userRole) || "teacher".equals(userRole)) {
|
||||
return userSchoolId != null && userSchoolId.equals(resourceSchoolId);
|
||||
}
|
||||
|
||||
// 学生/家长:需要额外的资源分配记录校验
|
||||
// return resourceAssignmentMapper.isAssigned(userId, resourceId);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证Referer防盗链
|
||||
*/
|
||||
public boolean validateReferer(String referer) {
|
||||
if (referer == null || referer.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
for (String pattern : REFERER_WHITELIST) {
|
||||
if (pattern.startsWith("*.")) {
|
||||
String domain = pattern.substring(2);
|
||||
if (referer.contains(domain)) return true;
|
||||
} else {
|
||||
if (referer.contains(pattern)) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成水印文本
|
||||
* 格式:学校名称 + 教师姓名 + 日期
|
||||
*/
|
||||
public String generateWatermarkText(
|
||||
String schoolName, String teacherName
|
||||
) {
|
||||
String dateStr = new java.text.SimpleDateFormat("yyyy-MM-dd")
|
||||
.format(new Date());
|
||||
return String.format("%s %s %s", schoolName, teacherName, dateStr);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user