完成大作业部分,并完成第一次黑箱测试

This commit is contained in:
li-chx 2025-05-08 11:02:12 +08:00
parent 9c17f3b845
commit 8828f148da
23 changed files with 429 additions and 44 deletions

View File

@ -2,8 +2,10 @@ package top.lichx.webclassbackend;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
@SpringBootApplication
@EnableAsync
public class WebClassBackendApplication {
public static void main(String[] args) {

View File

@ -0,0 +1,117 @@
package top.lichx.webclassbackend.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.Async;
import org.springframework.web.bind.annotation.*;
import top.lichx.webclassbackend.pojo.dto.ArticleInfoDTO;
import top.lichx.webclassbackend.pojo.vo.ArticleManagerInfoVO;
import top.lichx.webclassbackend.pojo.vo.VisibleUserInfoVO;
import top.lichx.webclassbackend.result.Result;
import top.lichx.webclassbackend.service.ArticleManagerService;
import top.lichx.webclassbackend.service.UserService;
import top.lichx.webclassbackend.util.AIUtil;
import top.lichx.webclassbackend.util.COSIO;
import java.time.format.DateTimeFormatter;
@Slf4j
@RestController
@RequestMapping("/article")
public class ArticleController {
@Resource
private ArticleManagerService articleManagerService;
@Resource
private UserService userService;
@Resource
private COSIO cosio;
@Resource
private AIUtil aiUtil;
@Resource
private TaskExecutor taskExecutor;
@GetMapping("/page")
public Result<IPage<ArticleManagerInfoVO>> getUserManagerInfoPage(@RequestParam int page, @RequestParam int size) {
return Result.success("", articleManagerService.getArticleManagerInfoPage(page, size));
}
@GetMapping("/total")
public Result<Integer> total() {
return Result.success("", articleManagerService.getTotal());
}
@GetMapping("/userAvatar")
public Result<?> getUserAvatar(@RequestParam String userId) {
var user = userService.getUserByUserId(Integer.parseInt(userId));
if (user == null)
return Result.error("用户不存在");
return Result.success("", cosio.GetFileLink(user.getAvatarPath()));
}
@GetMapping("/userInfo")
public Result<?> getUserInfo(@RequestParam String userId) {
var user = userService.getUserByUserId(Integer.parseInt(userId));
if (user == null)
return Result.error("用户不存在");
var returnVO = new VisibleUserInfoVO();
returnVO.setUserId("" + user.getId());
returnVO.setUserName(user.getName());
returnVO.setUserEmail(user.getEmail());
returnVO.setUserAvatarPath(user.getAvatarPath());
returnVO.setUserAmount(user.getAmount());
returnVO.setUserBirthday(user.getBirth().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
return Result.success("", returnVO);
}
@PostMapping("/addArticle")
public Result<?> addArticle(@RequestBody ArticleInfoDTO articleInfoDTO) {
var id = articleManagerService.InsertArticleInfo(articleInfoDTO);
UpdateArticleMainIdea(id, articleInfoDTO.getTitle(), articleInfoDTO.getContent());
return Result.success("添加文章成功");
}
@PostMapping("/updateArticle")
public Result<?> updateArticle(@RequestBody ArticleInfoDTO articleInfoDTO) {
articleManagerService.UpdateArticleInfo(articleInfoDTO);
UpdateArticleMainIdea(articleInfoDTO.getId(), articleInfoDTO.getTitle(), articleInfoDTO.getContent());
return Result.success("更新文章成功");
}
@Async
protected void UpdateArticleMainIdea(Integer articleId, String title, String content) {
System.out.println("task start");
taskExecutor.execute(() -> {
var mainIdea = aiUtil.GetMainIdeaOfArticle(title, content);
System.out.println(articleId);
System.out.println(mainIdea);
articleManagerService.UpdateArticleMainIdea(articleId, mainIdea);
});
}
@GetMapping("/page/{authorName}")
public Result<?> GetArticleById(@PathVariable String authorName, @RequestParam int page, @RequestParam int size) {
var article = articleManagerService.GetArticlesByAuthorName(authorName, page, size);
if (article == null)
return Result.error("文章不存在");
return Result.success("", article);
}
@GetMapping("/total/{authorName}")
public Result<?> GetUserArticleTotal(@PathVariable String authorName) {
var result = articleManagerService.GetArticleCountByAuthorName(authorName);
return Result.success("", result);
}
@GetMapping("/deleteArticle")
public Result<?> deleteArticle(@RequestParam String id) {
articleManagerService.deleteArticleById(Integer.parseInt(id));
return Result.success("删除文章成功");
}
}

View File

@ -1,10 +1,9 @@
package top.lichx.webclassbackend.controller;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import top.lichx.webclassbackend.pojo.vo.AvatarInfo;
import top.lichx.webclassbackend.pojo.vo.AvatarInfoVO;
import top.lichx.webclassbackend.result.Result;
import top.lichx.webclassbackend.util.COSIO;
@ -55,7 +54,7 @@ public class FileController {
var fileName = cosio.UploadFile(file);
file.delete();
var fileURL = cosio.GetFileLink(fileName);
var avatarInfo = new AvatarInfo(fileName, fileURL);
var avatarInfo = new AvatarInfoVO(fileName, fileURL);
return Result.success("文件上传成功", avatarInfo);
}

View File

@ -17,6 +17,7 @@ import top.lichx.webclassbackend.util.PasswordUtil;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Random;
@RestController
@RequestMapping("/login")
@ -195,7 +196,7 @@ public class Login {
if (user != null && passwordUtil.matches(password,user.getPassword())) {
String token = JwtUtil.generateToken(user.getName());
// 设置HttpOnly和Secure属性的Cookie
response.setHeader("Set-Cookie", "Authorization=Bearer " + token + "; HttpOnly; Max-Age=86400; Path=/; SameSite=Strict");
response.setHeader("Set-Cookie", "Authorization=Bearer " + token + "; HttpOnly; Secure; Max-Age=86400; Path=/; SameSite=Strict");
// response.setHeader("Set-Cookie", "token=Bearer " + token + "; HttpOnly; Secure; Path=/; SameSite=Strict");
return Result.success("登录成功");
}
@ -236,7 +237,11 @@ public class Login {
user.setPassword(passwordUtil.encrypt(registerDTO.getPassword()));
user.setEmail(registerDTO.getEmail());
user.setBirth(LocalDate.parse(registerDTO.getBirth(), DateTimeFormatter.ISO_LOCAL_DATE).atStartOfDay());
user.setAvatarURL(registerDTO.getAvatarFile());
user.setAvatarPath(registerDTO.getAvatarFile());
Random random = new Random();
int randomNumber = 100 + random.nextInt(901);
String randomString = Integer.toString(randomNumber);
user.setAmount(randomString);
if (!identifyingCode.testIdentifyingCode(registerDTO.getEmail(),
IdentifyingCode.IdentifyingCodeType.REGISTER,

View File

@ -46,7 +46,8 @@ public class User {
returnVO.setUserId("" + user.getId());
returnVO.setUserName(user.getName());
returnVO.setUserEmail(user.getEmail());
returnVO.setUserAvatar(cosio.GetFileLink(user.getAvatarURL()));
returnVO.setUserAvatarPath(user.getAvatarPath());
returnVO.setUserAmount(user.getAmount());
returnVO.setUserBirthday(user.getBirth().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
return Result.success("", returnVO);
}
@ -69,6 +70,6 @@ public class User {
var user = userService.getUserByUserName(username);
if (user == null)
return Result.error("用户不存在");
return Result.success("", cosio.GetFileLink(user.getAvatarURL()));
return Result.success("", cosio.GetFileLink(user.getAvatarPath()));
}
}

View File

@ -52,14 +52,14 @@ public class UserManager {
return Result.success("更新用户成功");
}
@GetMapping("deleteUser")
@GetMapping("/deleteUser")
public Result<?> deleteUser(@RequestParam Integer id)
{
userManagerService.deleteUserManagerInfo(id);
return Result.success("删除用户成功");
}
@GetMapping("total")
@GetMapping("/total")
public Result<Integer> total(@RequestParam String situation)
{
return Result.success("", userManagerService.getTotal(situation));

View File

@ -0,0 +1,9 @@
package top.lichx.webclassbackend.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import top.lichx.webclassbackend.pojo.entity.Article;
@Mapper
public interface articleManagerInfoMapper extends BaseMapper<Article> {
}

View File

@ -0,0 +1,11 @@
package top.lichx.webclassbackend.pojo.dto;
import lombok.Data;
@Data
public class ArticleInfoDTO {
private Integer id;
private String author;
private String title;
private String content;
}

View File

@ -1,9 +0,0 @@
package top.lichx.webclassbackend.pojo.dto;
import lombok.Data;
@Data
public class In {
Long id;
String test;
}

View File

@ -4,7 +4,6 @@ import lombok.Data;
@Data
public class LoginDTO {
private String usernameOrEmail;
private String password;
}

View File

@ -0,0 +1,29 @@
package top.lichx.webclassbackend.pojo.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("article")
public class Article {
Integer id;
String title;
String author;
@TableField("mainIdea")
String mainIdea;
String content;
public Article(Integer id, String title, String author, String content) {
this.id = id;
this.title = title;
this.author = author;
this.content = content;
this.mainIdea = "概述生成中...";
}
}

View File

@ -18,6 +18,7 @@ public class User {
String password;
String email;
LocalDateTime birth;
@TableField("avatarURL")
String avatarURL;
@TableField("avatarPath")
String avatarPath;
String amount;
}

View File

@ -0,0 +1,14 @@
package top.lichx.webclassbackend.pojo.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ArticleManagerInfoVO {
Integer id;
String name;
Integer amount;
}

View File

@ -8,7 +8,7 @@ import java.net.URL;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class AvatarInfo {
public class AvatarInfoVO {
private String avatarFilePath;
private URL avatarFileURL;
}

View File

@ -13,6 +13,7 @@ public class VisibleUserInfoVO {
private String userId;
private String userName;
private String userEmail;
private URL userAvatar;
private String userAvatarPath;
private String userBirthday;
private String userAmount;
}

View File

@ -0,0 +1,24 @@
package top.lichx.webclassbackend.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import top.lichx.webclassbackend.pojo.dto.ArticleInfoDTO;
import top.lichx.webclassbackend.pojo.entity.Article;
import top.lichx.webclassbackend.pojo.vo.ArticleManagerInfoVO;
public interface ArticleManagerService {
IPage<ArticleManagerInfoVO> getArticleManagerInfoPage(int page, int size);
Integer getArticleManagerInfoLastId();
Integer getTotal();
Integer InsertArticleInfo(ArticleInfoDTO articleInfoDTO);
void UpdateArticleInfo(ArticleInfoDTO articleInfoDTO);
void UpdateArticleMainIdea(Integer id, String mainIdea);
IPage<Article> GetArticlesByAuthorName(String authorName, Integer page, Integer size);
Integer GetArticleCountByAuthorName(String authorName);
void deleteArticleById(Integer id);
}

View File

@ -1,5 +0,0 @@
package top.lichx.webclassbackend.service;
public interface Test {
void test();
}

View File

@ -10,5 +10,4 @@ public interface UserManagerService {
public IPage<UserManagerInfo> getUserManagerInfoPage(int page, int size, String situation);
public Integer getUserManagerInfoLastId();
public Integer getTotal(String situation);
}

View File

@ -5,6 +5,7 @@ import top.lichx.webclassbackend.pojo.entity.User;
public interface UserService {
public void insertUser(User user);
public User getUserByUserName(String userName);
public User getUserByUserId(Integer userId);
public void changeUserPasswordByUserName(String userName, String password);
public User getUserByEmail(String email);

View File

@ -0,0 +1,120 @@
package top.lichx.webclassbackend.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import top.lichx.webclassbackend.mapper.articleManagerInfoMapper;
import top.lichx.webclassbackend.mapper.userMapper;
import top.lichx.webclassbackend.pojo.dto.ArticleInfoDTO;
import top.lichx.webclassbackend.pojo.entity.Article;
import top.lichx.webclassbackend.pojo.entity.User;
import top.lichx.webclassbackend.pojo.vo.ArticleManagerInfoVO;
import top.lichx.webclassbackend.service.ArticleManagerService;
import java.util.ArrayList;
import java.util.List;
@Service
public class ArticleManagerServiceImpl implements ArticleManagerService {
@Resource
private userMapper userMapper;
@Resource
private articleManagerInfoMapper articleManagerInfoMapper;
@Override
public IPage<ArticleManagerInfoVO> getArticleManagerInfoPage(int page, int size) {
// 查询所有用户的 id name
List<User> users = userMapper.selectList(null);
// 创建结果列表
List<ArticleManagerInfoVO> result = new ArrayList<>();
// 遍历用户列表
for (User user : users) {
String name = user.getName();
// 查询 articleManagerInfoMapper author name 的数量
int articleCount = articleManagerInfoMapper.selectCount(
new QueryWrapper<Article>().eq("author", name)
).intValue();
// 将结果添加到列表中
result.add(new ArticleManagerInfoVO(user.getId(), name, articleCount));
}
Page<ArticleManagerInfoVO> pageResult = new Page<>(page, size);
pageResult.setRecords(result);
pageResult.setTotal(users.size());
return pageResult;
}
@Override
public Integer getArticleManagerInfoLastId() {
Article lastRecord = articleManagerInfoMapper.selectOne(
new QueryWrapper<Article>().orderByDesc("id").last("LIMIT 1")
);
// 如果记录为空返回 0否则返回最后一条记录的 ID + 1
return lastRecord == null ? 0 : lastRecord.getId() + 1;
}
@Override
public Integer getTotal() {
return userMapper.selectCount(null).intValue();
}
@Override
public Integer InsertArticleInfo(ArticleInfoDTO articleInfoDTO)
{
Article article = new Article(getArticleManagerInfoLastId(), articleInfoDTO.getTitle(), articleInfoDTO.getAuthor(), articleInfoDTO.getContent());
articleManagerInfoMapper.insert(article);
return article.getId();
}
@Override
public void UpdateArticleInfo(ArticleInfoDTO articleInfoDTO)
{
Article article = articleManagerInfoMapper.selectById(articleInfoDTO.getId());
if(!article.getAuthor().equals(articleInfoDTO.getAuthor()))
{
throw new RuntimeException("作者不一致");
}
if (article != null) {
article.setTitle(articleInfoDTO.getTitle());
article.setContent(articleInfoDTO.getContent());
article.setMainIdea("概述生成中...");
articleManagerInfoMapper.updateById(article);
}
}
@Override
public void UpdateArticleMainIdea(Integer id, String mainIdea) {
Article article = articleManagerInfoMapper.selectById(id);
if (article != null) {
article.setMainIdea(mainIdea);
articleManagerInfoMapper.updateById(article);
}
}
@Override
public IPage<Article> GetArticlesByAuthorName(String authorName, Integer page, Integer size)
{
return articleManagerInfoMapper.selectPage(new Page<>(page, size),
new QueryWrapper<Article>().eq("author", authorName));
}
@Override
public Integer GetArticleCountByAuthorName(String authorName)
{
return articleManagerInfoMapper.selectCount(
new QueryWrapper<Article>().eq("author", authorName)
).intValue();
}
@Override
public void deleteArticleById(Integer id)
{
articleManagerInfoMapper.deleteById(id);
}
}

View File

@ -1,13 +0,0 @@
package top.lichx.webclassbackend.service.impl;
import org.springframework.stereotype.Service;
import top.lichx.webclassbackend.service.Test;
@Service
public class TestImpl implements Test {
@Override
public void test() {
}
}

View File

@ -5,7 +5,6 @@ import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import top.lichx.webclassbackend.mapper.userMapper;
import top.lichx.webclassbackend.pojo.entity.User;
import top.lichx.webclassbackend.pojo.entity.UserManagerInfo;
import top.lichx.webclassbackend.service.UserService;
@Service
@ -13,16 +12,26 @@ public class UserServiceImpl implements UserService {
@Resource
private userMapper webclassMapper;
@Override
public void insertUser(User user) {
webclassMapper.insert(user);
}
@Override
public User getUserByUserName(String userName) {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("name", userName);
return webclassMapper.selectOne(queryWrapper);
}
@Override
public User getUserByUserId(Integer userId) {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("id", userId);
return webclassMapper.selectOne(queryWrapper);
}
@Override
public void changeUserPasswordByUserName(String userName, String password) {
User user = getUserByUserName(userName);
if (user != null) {
@ -45,7 +54,6 @@ public class UserServiceImpl implements UserService {
);
// 如果记录为空返回 0否则返回最后一条记录的 ID
return lastRecord == null ? 0 : lastRecord.getId() + 1;
}
@Override

View File

@ -0,0 +1,72 @@
package top.lichx.webclassbackend.util;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import jakarta.annotation.PostConstruct;
import lombok.AllArgsConstructor;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.client.RestTemplate;
import org.springframework.http.HttpHeaders;
import java.util.concurrent.CompletableFuture;
@Component
public class AIUtil {
@Value("${deepseek.apikey}")
private String apikey;
@Value("${deepseek.apiurl}")
private String apiurl;
@Value("${deepseek.model}")
private String model;
public String GetMainIdeaOfArticle(String title, String content) {
Message[] messages = new Message[] {
new Message("system", "你需要总结出一篇文章的主要内容写成概述字数限制在100字以内请尽量简洁明了请直接输出观点不要以文章主要观点文章概述开头直接输出即可"),
new Message("user", "文章标题:" + title + " 文章内容:" + content)
};
BodyData bodyData = new BodyData(messages, model, false);
String jsonBody = new Gson().toJson(bodyData);
String response = SendPostRequest(jsonBody);
Gson gson = new Gson();
JsonObject jsonObject = gson.fromJson(response, JsonObject.class);
String mainIdea = jsonObject
.getAsJsonArray("choices")
.get(0)
.getAsJsonObject()
.getAsJsonObject("message")
.get("content")
.getAsString();
return mainIdea;
}
private String SendPostRequest(String jsonBody) {
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Bearer " + apikey);
headers.set("Content-Type", "application/json");
HttpEntity<String> entity = new HttpEntity<String>(jsonBody, headers);
ResponseEntity<String> responseEntity = restTemplate.exchange(apiurl, HttpMethod.POST, entity, String.class);
if (responseEntity.getStatusCode().is2xxSuccessful()) {
return responseEntity.getBody();
} else {
return "生成文章大意失败";
}
}
@AllArgsConstructor
class BodyData {
Message[] messages;
String model;
boolean stream;
}
@AllArgsConstructor
class Message {
String role;
String content;
}
}