2 Commits

Author SHA1 Message Date
KilLze
4b96a49b27 完成动态发布功能(审核未实现) 2025-12-18 11:36:54 +08:00
KilLze
6ef38ac5e0 完成动态发布功能(审核未实现) 2025-12-18 10:59:29 +08:00
15 changed files with 390 additions and 4 deletions

26
pom.xml
View File

@@ -19,6 +19,11 @@
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
@@ -44,6 +49,25 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.17.4</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>green20220302</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
@@ -89,4 +113,4 @@
</plugins>
</build>
</project>
</project>

View File

@@ -3,9 +3,9 @@ package com.bao.dating;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DatingApplication {
public static void main(String[] args) {
SpringApplication.run(DatingApplication.class, args);
}

View File

@@ -0,0 +1,60 @@
package com.bao.dating.common;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 通用返回结果类
* @author lenovo
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Result<T> {
private int code;
private String msg;
private T data;
/**
* 返回成功结果
* @param data 返回的数据
* @param <T> 数据类型
* @return Result对象
*/
public static <T> Result<T> success(ResultCode code, T data) {
return new Result<>(code.code(), code.msg(), data);
}
/**
* 返回成功结果
* @param data 返回的数据
* @param msg 提示信息
* @param <T> 数据类型
* @return Result对象
*/
public static <T> Result<T> success(ResultCode code, String msg, T data) {
return new Result<>(code.code(), msg, data);
}
/**
* 返回失败结果
* @param code 错误码
* @param <T> 数据类型
* @return Result对象
*/
public static <T> Result<T> error(ResultCode code) {
return new Result<>(code.code(), code.msg(), null);
}
/**
* 返回失败结果
* @param code 错误码
* @param msg 错误信息
* @param <T> 数据类型
* @return Result对象
*/
public static <T> Result<T> error(ResultCode code, String msg) {
return new Result<>(code.code(), msg, null);
}
}

View File

@@ -0,0 +1,27 @@
package com.bao.dating.common;
public enum ResultCode {
SUCCESS(200, "成功"),
SUCCESS_REVIEW(201, "请求已成功处理"),
PARAM_ERROR(400, "参数错误"),
UNAUTHORIZED(401, "未登录或 Token 失效"),
FORBIDDEN(403, "无权限"),
NOT_FOUND(404, "数据不存在"),
SYSTEM_ERROR(500, "系统异常");
private final int code;
private final String msg;
ResultCode(int code, String msg) {
this.code = code;
this.msg = msg;
}
public int code() {
return code;
}
public String msg() {
return msg;
}
}

View File

@@ -0,0 +1,26 @@
package com.bao.dating.config;
import com.bao.dating.properties.AliOssProperties;
import com.bao.dating.util.AliOssUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 配置类用于创建AliOssUtil对象
*/
@Configuration
@Slf4j
public class OssConfiguration {
@Bean
@ConditionalOnMissingBean
public AliOssUtil aliOssUtil(AliOssProperties aliOssProperties){
log.info("开始创建阿里云文件上传工具类对象:{}",aliOssProperties);
return new AliOssUtil(aliOssProperties.getEndpoint(),
aliOssProperties.getAccessKeyId(),
aliOssProperties.getAccessKeySecret(),
aliOssProperties.getBucketName());
}
}

View File

@@ -0,0 +1,24 @@
package com.bao.dating.controller;
import com.bao.dating.common.Result;
import com.bao.dating.common.ResultCode;
import com.bao.dating.pojo.entity.Post;
import com.bao.dating.service.PostService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/posts")
public class PostController {
@Autowired
private PostService postService;
@PostMapping
public Result<Post> createPost(Post post) {
// 调用 Service 层处理发布动态业务逻辑
Post result = postService.createPost(post);
return Result.success(ResultCode.SUCCESS_REVIEW,"动态发布成功,等待审核。",result);
}
}

View File

@@ -0,0 +1,9 @@
package com.bao.dating.mapper;
import com.bao.dating.pojo.entity.Post;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface PostMapper {
int insert(Post post);
}

View File

@@ -3,6 +3,7 @@ package com.bao.dating.pojo.entity;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.List;
/**
* 动态表
@@ -17,7 +18,9 @@ public class Post {
private String content;
private String mediaOssKeys;
private List<String> mediaOssKeys;
private List<String> tags;
private String location;

View File

@@ -0,0 +1,15 @@
package com.bao.dating.properties;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "aliyun.oss")
@Data
public class AliOssProperties {
private String endpoint;
private String accessKeyId;
private String accessKeySecret;
private String bucketName;
}

View File

@@ -0,0 +1,7 @@
package com.bao.dating.service;
import com.bao.dating.pojo.entity.Post;
public interface PostService {
Post createPost(Post post);
}

View File

@@ -0,0 +1,65 @@
package com.bao.dating.service.impl;
import com.bao.dating.mapper.PostMapper;
import com.bao.dating.pojo.entity.Post;
import com.bao.dating.service.PostService;
import com.bao.dating.util.AliOssUtil;
import com.bao.dating.util.FileUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
@Service
public class PostServiceImpl implements PostService {
@Autowired
private AliOssUtil ossUtil;
@Autowired
private PostMapper postMapper;
@Override
public Post createPost(Post post) {
// 处理图片和视频上传到 OSS
List<String> mediaOssKeys = new ArrayList<>();
// 判断媒体文件是否为空
if (post.getMediaOssKeys() != null && !post.getMediaOssKeys().isEmpty()) {
// 上传媒体文件并判断文件类型
for (String mediaUrl : post.getMediaOssKeys()) {
// 根据文件扩展名判断文件类型
String fileType = FileUtil.getFileType(mediaUrl);
// 生成唯一文件名
String fileName = UUID.randomUUID().toString() + "." + FileUtil.getFileExtension(mediaUrl);
// 获取文件字节数据
byte[] fileBytes = mediaUrl.getBytes();
// 根据文件类型处理
String ossUrl = "";
if ("image".equals(fileType)) {
// 上传图片
ossUrl = ossUtil.upload(fileBytes, fileName);
} else if ("video".equals(fileType)) {
// 上传视频
ossUrl = ossUtil.upload(fileBytes, fileName);
}
// 添加上传后的 URL
mediaOssKeys.add(ossUrl);
}
}
post.setMediaOssKeys(mediaOssKeys);
post.setIsPublic(0);
post.setUpdatedAt(LocalDateTime.now());
post.setCreatedAt(LocalDateTime.now());
// 保存动态到数据库
postMapper.insert(post);
return post;
}
}

View File

@@ -0,0 +1,59 @@
package com.bao.dating.util;
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.io.ByteArrayInputStream;
@Data
@AllArgsConstructor
@Slf4j
public class AliOssUtil {
private String endpoint;
private String accessKeyId;
private String accessKeySecret;
private String bucketName;
/**
* 文件上传
* @param bytes
* @param objectName
* @return
*/
public String upload(byte[] bytes, String objectName) {
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
try {
// 创建PutObject请求。
ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(bytes));
} catch (OSSException oe) {
log.error("OSS Exception: {}", oe.getMessage());
} catch (ClientException ce) {
log.error("Client Exception: {}", ce.getMessage());
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
//文件访问路径规则 https://BucketName.Endpoint/ObjectName
StringBuilder stringBuilder = new StringBuilder("https://");
stringBuilder
.append(bucketName)
.append(".")
.append(endpoint)
.append("/")
.append(objectName);
log.info("文件上传到:{}", stringBuilder.toString());
return stringBuilder.toString();
}
}

View File

@@ -0,0 +1,36 @@
package com.bao.dating.util;
/**
* 文件工具类
* @author KilLze
*/
public class FileUtil {
/**
* 根据文件 URL 扩展名获取文件类型
* @param fileUrl 文件的 URL
* @return 文件类型image、video、unknown
*/
public static String getFileType(String fileUrl) {
String extension = getFileExtension(fileUrl);
if (extension.equals("jpg") || extension.equals("jpeg") || extension.equals("png") || extension.equals("gif")) {
return "image";
} else if (extension.equals("mp4") || extension.equals("avi") || extension.equals("mov")) {
return "video";
}
return "unknown";
}
/**
* 获取文件的扩展名
* @param fileUrl 文件的 URL
* @return 文件扩展名(小写)
*/
public static String getFileExtension(String fileUrl) {
int dotIndex = fileUrl.lastIndexOf(".");
if (dotIndex != -1) {
return fileUrl.substring(dotIndex + 1).toLowerCase();
}
return "";
}
}

View File

@@ -8,9 +8,18 @@ spring:
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
# MyBatis 配置
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.bao.dating.pojo
configuration:
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 阿里云 OSS 配置
aliyun:
oss:
endpoint: oss-cn-hangzhou.aliyuncs.com
access-key-id: LTAI5tKo9TpWH1aW6JxWm1Gp
access-key-secret: LHk9DdHECKCwIdaIM9fkGgEuowt18W
bucket-name: heimato

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bao.dating.mapper.PostMapper">
<!-- 动态添加 -->
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
INSERT INTO post
(user_id, content,
<if test="mediaOssKeys != null and mediaOssKeys != ''">
media_oss_keys,
</if>
tags,
<if test="location != null and location != ''">
location,
</if>
is_public, like_count, favorite_count, created_at, updated_at)
VALUES
(#{userId}, #{content}, #{mediaOssKeys}, #{tags}, #{location}, #{isPublic}, 0, 0, #{created_at}, #{updated_at})
</insert>
</mapper>