feat: 移植工程

This commit is contained in:
2025-06-10 09:54:52 +08:00
commit a2de21b092
277 changed files with 11116 additions and 0 deletions

38
admin-service/.gitignore vendored Normal file
View File

@@ -0,0 +1,38 @@
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store

6
admin-service/Dockerfile Normal file
View File

@@ -0,0 +1,6 @@
FROM docker-0.unsee.tech/openjdk:11-jdk-slim
ARG JAR_FILE=target/*.jar
COPY $JAR_FILE app.jar
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo 'Asia/Shanghai' > /etc/timezone
ENTRYPOINT ["java","-jar","/app.jar"]

58
admin-service/pom.xml Normal file
View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.cxx</groupId>
<artifactId>sweet-hut-service</artifactId>
<version>2.0.0</version>
</parent>
<artifactId>admin-service</artifactId>
<version>2.0.0</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.cxx</groupId>
<artifactId>common</artifactId>
<version>2.0.0</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.checkerframework</groupId>-->
<!-- <artifactId>checker-qual</artifactId>-->
<!-- <version>2.0.0</version>-->
<!-- <scope>compile</scope>-->
<!-- </dependency>-->
<!-- 服务器监控 -->
<dependency>
<groupId>com.github.oshi</groupId>
<artifactId>oshi-core</artifactId>
<version>6.4.0</version>
</dependency>
<!-- influxdb -->
<dependency>
<groupId>com.influxdb</groupId>
<artifactId>influxdb-client-java</artifactId>
<version>7.2.0</version>
</dependency>
</dependencies>
<!-- <build>-->
<!-- <plugins>-->
<!-- <plugin>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-maven-plugin</artifactId>-->
<!-- </plugin>-->
<!-- </plugins>-->
<!-- </build>-->
</project>

View File

@@ -0,0 +1,15 @@
package com.cxx.admin;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@MapperScan(basePackages = {"com.cxx.common.mapper", "com.cxx.admin.mapper", "com.cxx.admin.dao"})
@EnableScheduling
public class AdminServiceApplication {
public static void main(String[] args) {
SpringApplication.run(AdminServiceApplication.class, args);
}
}

View File

@@ -0,0 +1,31 @@
package com.cxx.admin.config;
import com.cxx.admin.constant.FileConstant;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @Author: Cxx
* @Date: 2024/9/22 10:57
* @Description:
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Value("${file.path}")
private String filePath;
@Value("${file.log-path}")
private String logFilePath;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/" + FileConstant.FILE_URL_PREFIX + "/**")
.addResourceLocations("file:" + filePath);
registry.addResourceHandler("/" + FileConstant.FILE_LOG_PREFIX + "/**")
.addResourceLocations("file:" + logFilePath);
}
}

View File

@@ -0,0 +1,7 @@
package com.cxx.admin.constant;
public interface FileConstant {
String FILE_NAME_SPLIT = "_";
String FILE_URL_PREFIX = "files";
String FILE_LOG_PREFIX = "logs";
}

View File

@@ -0,0 +1,48 @@
package com.cxx.admin.controller;
import com.cxx.admin.service.AccountService;
import com.cxx.common.ReadView;
import com.cxx.common.WriteView;
import com.cxx.admin.dto.user.AccountDto;
import com.fasterxml.jackson.annotation.JsonView;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/account")
@Tag(name = "账户管理")
public class AccountController {
@Resource
private AccountService accountService;
@Operation(summary = "查询用户账号")
@GetMapping("")
public @JsonView(ReadView.class) List<AccountDto> queryAccountList() {
return accountService.queryAccountList();
}
@Operation(summary = "注册账户")
@PostMapping("")
public Boolean registerAccount(@JsonView(WriteView.class) @Validated @RequestBody AccountDto accountDto) {
return accountService.registerAccount(accountDto);
}
@Operation(summary = "注销账户")
@DeleteMapping("/{id}")
public Boolean deleteAccount(@PathVariable("id") Long id) {
return accountService.deleteAccount(id);
}
@Operation(summary = "更改账户密码")
@PutMapping("/password/{id}")
public Boolean updateAccountPassword(@PathVariable("id") Long id,
@RequestParam String oldPassword,
@RequestParam String newPassword) {
return Boolean.TRUE;
}
}

View File

@@ -0,0 +1,58 @@
package com.cxx.admin.controller;
import com.cxx.admin.service.BillManageService;
import com.cxx.common.WriteView;
import com.cxx.common.dto.bill.BillCategoryDto;
import com.cxx.common.dto.bill.BillItemDto;
import com.fasterxml.jackson.annotation.JsonView;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/bill-manage")
@Tag(name = "账单管理")
public class BillManageController {
@Resource
private BillManageService billManageService;
@Operation(summary = "新增支付账户")
@PostMapping("/pay")
public Boolean addBillPay(@JsonView(WriteView.class) @RequestBody BillItemDto billItemDto) {
return billManageService.addBillPay(billItemDto);
}
@Operation(summary = "更新支付账户")
@PutMapping("/pay/{id}")
public Boolean updateBillPay(@PathVariable("id") Long id,
@JsonView(WriteView.class) @RequestBody BillItemDto billItemDto) {
return billManageService.updateBillPay(id, billItemDto);
}
@Operation(summary = "新增账本类型")
@PostMapping("/book")
public Boolean addBillBook(@JsonView(WriteView.class) @RequestBody BillItemDto billItemDto) {
return billManageService.addBillBook(billItemDto);
}
@Operation(summary = "更新账本类型")
@PutMapping("/book/{id}")
public Boolean updateBillBook(@PathVariable("id") Long id,
@JsonView(WriteView.class) @RequestBody BillItemDto billItemDto) {
return billManageService.updateBillBook(id, billItemDto);
}
@Operation(summary = "新增账单类型")
@PostMapping("/category")
public Boolean addBillCategory(@RequestBody BillCategoryDto billCategoryDto) {
return billManageService.addBillCategory(billCategoryDto);
}
@Operation(summary = "更新账单类型")
@PutMapping("/category/{id}")
public Boolean updateBillCategory(@PathVariable("id") Long id,
@RequestBody BillCategoryDto billCategoryDto) {
return billManageService.updateBillCategory(id, billCategoryDto);
}
}

View File

@@ -0,0 +1,69 @@
package com.cxx.admin.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.cxx.admin.service.BlogManageService;
import com.cxx.common.ReadView;
import com.cxx.common.WriteView;
import com.cxx.common.dto.blog.BlogCategoryDto;
import com.cxx.common.dto.blog.BlogDto;
import com.cxx.common.dto.blog.BlogVisitDto;
import com.fasterxml.jackson.annotation.JsonView;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/blog-manage")
@Tag(name = "博客管理")
public class BlogManageController {
@Resource
private BlogManageService blogManageService;
@Operation(summary = "分页查询博客")
@GetMapping("/page")
public IPage<BlogDto> queryBlogByPage(@RequestParam("currentPage") Integer currentPage,
@RequestParam("pageSize") Integer pageSize) {
return blogManageService.queryBlogByPage(currentPage, pageSize);
}
@Operation(summary = "查询博客内容")
@GetMapping("/content/{id}")
public @JsonView(ReadView.class) BlogDto queryBlogById(@PathVariable("id") long id) {
return blogManageService.queryBlogById(id);
}
@Operation(summary = "查询博客分类")
@GetMapping("/category")
public List<BlogCategoryDto> queryBlogCategory() {
return blogManageService.queryBlogCategory();
}
@Operation(summary = "增加博客")
@PostMapping("")
public Boolean addBlog(@JsonView(WriteView.class) @RequestBody BlogDto blog) {
return blogManageService.addBlog(blog);
}
@Operation(summary = "更新博客")
@PutMapping("/{id}")
public Boolean updateBlog(@PathVariable("id") long id,
@JsonView(WriteView.class) @RequestBody BlogDto blog) {
return blogManageService.updateBlog(id, blog);
}
@Operation(summary = "删除博客")
@DeleteMapping("/{id}")
public Boolean deleteBlog(@PathVariable("id") long id) {
return blogManageService.deleteBlog(id);
}
@Operation(summary = "查询博客访问")
@GetMapping("/visit")
public IPage<BlogVisitDto> queryBlogVisit(@RequestParam("currentPage") Integer currentPage,
@RequestParam("pageSize") Integer pageSize) {
return blogManageService.queryBlogVisit(currentPage, pageSize);
}
}

View File

@@ -0,0 +1,27 @@
package com.cxx.admin.controller;
import com.cxx.admin.service.BudgetManageService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/budget-manage")
@Tag(name = "预算管理")
public class BudgetManageController {
@Resource
private BudgetManageService budgetManageService;
@Operation(summary = "新增预算类别")
@PostMapping("/category")
public Boolean addBudgetCategory(@RequestParam String category) {
return budgetManageService.addBudgetCategory(category);
}
@Operation(summary = "更新预算类别")
@PutMapping("/category/{id}")
public Boolean updateBudgetCategory(@PathVariable("id") Long id, @RequestParam String category) {
return budgetManageService.updateBudgetCategory(id, category);
}
}

View File

@@ -0,0 +1,65 @@
package com.cxx.admin.controller;
import com.cxx.admin.dto.file.ChunkInfoDto;
import com.cxx.admin.dto.file.ChunkResultDto;
import com.cxx.admin.dto.file.FileInfoDto;
import com.cxx.admin.service.FileService;
import com.cxx.admin.dto.file.FileRecordDto;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
@RestController
@RequestMapping("/file")
@Tag(name = "文件管理")
public class FileController {
@Resource
private FileService fileService;
@Operation(summary = "上传文件")
@PostMapping(value = "", headers = "content-type=multipart/form-data")
public FileRecordDto uploadFile(@RequestPart("file") MultipartFile file,
@RequestParam("path") String path,
@RequestParam("md5") String md5) {
return fileService.uploadFile(file, path, md5);
}
@Operation(summary = "上传文件块")
@PostMapping("/chunk")
public Boolean uploadChunk(ChunkInfoDto chunkInfo,
String path) {
return fileService.uploadChunk(chunkInfo, path);
}
@Operation(summary = "验证当前文件块是否上传")
@GetMapping("/chunk")
public ChunkResultDto checkChunk(@RequestParam String identifier,
@RequestParam String filename,
@RequestParam String path) {
return fileService.checkChunk(identifier, filename, path);
}
@Operation(summary = "删除当前已上传的文件块")
@DeleteMapping("/chunk")
public Boolean deleteChunk(@RequestParam String identifier,
@RequestParam String path) {
return fileService.deleteChunk(identifier, path);
}
@Operation(summary = "合并文件")
@PostMapping("/chunk/merge")
public FileRecordDto mergeFile(@RequestParam String filename,
@RequestParam String path) {
return fileService.mergeFile(filename, path);
}
@Operation(summary = "获取文件夹目录")
@GetMapping("/catalog")
public List<FileInfoDto> getFolderInfo(@RequestParam String folderName) {
return fileService.getFolderInfo(folderName);
}
}

View File

@@ -0,0 +1,30 @@
package com.cxx.admin.controller;
import com.cxx.admin.dto.server.*;
import com.cxx.admin.service.ServerMonitorService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/server-monitor")
@Tag(name = "服务器监控")
public class ServerMonitorController {
@Resource
private ServerMonitorService serverMonitorService;
@Operation(summary = "系统信息")
@GetMapping("/system/info")
public SystemInfoDto getSystemInfo() {
return serverMonitorService.getSystemInfo();
}
@Operation(summary = "系统指标")
@GetMapping("/system/metrics")
public List<SystemMetricsDto> querySystemMetrics(@RequestParam String range) {
return serverMonitorService.querySystemMetrics(range);
}
}

View File

@@ -0,0 +1,23 @@
package com.cxx.admin.controller;
import com.cxx.common.dto.user.SessionDto;
import com.cxx.admin.service.SessionService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/session")
@Tag(name = "会话管理")
public class SessionController {
@Resource
private SessionService sessionService;
@Operation(summary = "创建会话")
@PostMapping("")
public SessionDto createSession(@RequestParam String name,
@RequestParam String password) {
return sessionService.create(name, password);
}
}

View File

@@ -0,0 +1,33 @@
package com.cxx.admin.controller;
import com.cxx.admin.service.UserService;
import com.cxx.common.ReadView;
import com.cxx.common.WriteView;
import com.cxx.common.dto.user.UserDto;
import com.fasterxml.jackson.annotation.JsonView;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/user")
@Tag(name = "用户管理")
public class UserController {
@Resource
private UserService userService;
@Operation(summary = "查询用户")
@GetMapping("/{id}")
public @JsonView(ReadView.class) UserDto queryUser(@PathVariable("id") Long id) {
return userService.queryUser(id);
}
@Operation(summary = "更新用户")
@PutMapping("/{id}")
public Boolean updateUser(@PathVariable("id") Long id,
@JsonView(WriteView.class) @Validated @RequestBody UserDto userDto) {
return userService.updateUser(id, userDto);
}
}

View File

@@ -0,0 +1,19 @@
package com.cxx.admin.controller;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/wechat")
@Tag(name = "微信管理")
public class WeChatController {
@Operation(summary = "获取code")
@GetMapping("/code")
public Boolean getWeChatAuthCode(@RequestParam("code") String code) {
System.out.println(code);
return Boolean.TRUE;
}
}

View File

@@ -0,0 +1,12 @@
package com.cxx.admin.dao;
import com.cxx.admin.dto.user.AccountDto;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface AccountDao {
List<AccountDto> queryAccount();
}

View File

@@ -0,0 +1,24 @@
package com.cxx.admin.dao;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.cxx.common.dto.blog.BlogCategoryDto;
import com.cxx.common.dto.blog.BlogDto;
import com.cxx.common.dto.blog.BlogVisitDto;
import com.cxx.common.entity.Blog;
import com.cxx.common.vo.blog.BlogQueryVo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@Mapper
public interface BlogDao {
IPage<BlogDto> queryBlogByPage(IPage<Blog> page);
BlogDto queryBlogById(@Param("id") Long id);
List<BlogCategoryDto> queryBlogCategory();
IPage<BlogVisitDto> queryBlogVisit(IPage<Blog> page);
}

View File

@@ -0,0 +1,23 @@
package com.cxx.admin.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @Author: Cxx
* @Date: 2024/9/24 22:41
* @Description:
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class FtpInfo {
private String ftpIp;
private Integer ftpPort;
private String ftpUsername;
private String ftpPassword;
}

View File

@@ -0,0 +1,22 @@
package com.cxx.admin.dto.file;
import lombok.Getter;
import lombok.Setter;
import org.springframework.web.multipart.MultipartFile;
@Getter
@Setter
public class ChunkInfoDto {
/**
* 当前文件块从1开始
*/
private Integer chunkNumber;
/**
* 文件名
*/
private String filename;
/**
* 块内容
*/
private transient MultipartFile multipartFile;
}

View File

@@ -0,0 +1,20 @@
package com.cxx.admin.dto.file;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Getter
@Setter
public class ChunkResultDto {
/**
* 是否跳过上传(已上传的可以直接跳过,达到秒传的效果)
*/
private boolean isSkipUpload;
/**
* 已经上传的文件块编号,可以跳过,断点续传
*/
private List<Integer> uploadedChunkList;
}

View File

@@ -0,0 +1,17 @@
package com.cxx.admin.dto.file;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Getter;
import lombok.Setter;
import java.util.Date;
@Getter
@Setter
public class FileInfoDto {
private String name;
private String type;
private String size;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createDate;
}

View File

@@ -0,0 +1,14 @@
package com.cxx.admin.dto.file;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class FileRecordDto {
private Long id;
private String name;
private String md5;
private String path;
private String url;
}

View File

@@ -0,0 +1,10 @@
package com.cxx.admin.dto.server;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class CpuDto {
private double usagePercent;
}

View File

@@ -0,0 +1,13 @@
package com.cxx.admin.dto.server;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class DiskDto {
private double total;
private double used;
private double free;
private double usagePercent;
}

View File

@@ -0,0 +1,13 @@
package com.cxx.admin.dto.server;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class MemoryDto {
private double total;
private double used;
private double free;
private double usagePercent;
}

View File

@@ -0,0 +1,24 @@
package com.cxx.admin.dto.server;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Getter;
import lombok.Setter;
import java.util.Date;
@Getter
@Setter
public class SystemInfoDto {
// CPU信息
private String cpuName;
private String cpuVendor;
private int cpuLogicalCores;
private int cpuPhysicalCores;
private double cpuSystemLoad;
// 操作系统信息
private String osFamily;
private String osVersion;
private String osManufacturer;
// 系统运行时间
private long systemUptime;
}

View File

@@ -0,0 +1,24 @@
package com.cxx.admin.dto.server;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Getter;
import lombok.Setter;
import java.util.Date;
@Getter
@Setter
public class SystemMetricsDto {
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date time;
private double cpuUsage;
private double memoryTotal;
private double memoryUsed;
private double memoryFree;
private double memoryUsage;
private double diskTotal;
private double diskUsed;
private double diskFree;
private double diskUsage;
}

View File

@@ -0,0 +1,42 @@
package com.cxx.admin.dto.user;
import com.cxx.common.PlainView;
import com.cxx.common.ReadView;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonView;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Getter;
import lombok.Setter;
import java.util.Date;
@Getter
@Setter
@JsonView(PlainView.class)
public class AccountDto {
@Schema(description = "id")
@JsonView(ReadView.class)
private Long id;
@Schema(description = "账户名称")
@NotBlank(message = "账户名称不能为空")
private String accountName;
@Schema(description = "密码")
@NotBlank(message = "密码不能为空")
private String password;
@Schema(description = "用户名称")
@NotBlank(message = "用户名称不能为空")
private String username;
@Schema(description = "账户状态")
@JsonView(ReadView.class)
private Integer state;
@Schema(description = "创建日期")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
@JsonView(ReadView.class)
private Date date;
}

View File

@@ -0,0 +1,36 @@
package com.cxx.admin.dto.user;
import com.cxx.common.PlainView;
import com.cxx.common.ReadView;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonView;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Getter;
import lombok.Setter;
import java.time.LocalDateTime;
@Getter
@Setter
@JsonView(PlainView.class)
public class UserSummaryDto {
@Schema(description = "id")
@JsonView(ReadView.class)
private Long id;
@Schema(description = "id")
@JsonView(ReadView.class)
private String accountName;
@Schema(description = "用户名称")
@NotBlank(message = "用户名称不能为空")
private String username;
@Schema(description = "账户状态")
private Integer state;
@Schema(description = "创建日期")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
private LocalDateTime date;
}

View File

@@ -0,0 +1,21 @@
package com.cxx.admin.schedule;
import com.cxx.admin.service.ServerMonitorService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class ServerMonitor {
@Resource
private ServerMonitorService serverMonitorService;
// @Scheduled(fixedRate = 60000)
public void collectAndStoreMetrics() {
log.info("开始存储服务器状态");
serverMonitorService.storeSystemMetrics();
log.info("结束存储服务器状态");
}
}

View File

@@ -0,0 +1,17 @@
package com.cxx.admin.service;
import com.cxx.admin.dto.user.AccountDto;
import com.cxx.common.entity.Account;
import java.util.List;
public interface AccountService {
List<AccountDto> queryAccountList();
Account queryAccountByUserId(Long userId);
Boolean registerAccount(AccountDto accountDto);
Boolean deleteAccount(Long id);
}

View File

@@ -0,0 +1,18 @@
package com.cxx.admin.service;
import com.cxx.common.dto.bill.BillCategoryDto;
import com.cxx.common.dto.bill.BillItemDto;
public interface BillManageService {
Boolean addBillPay(BillItemDto billItemDto);
Boolean updateBillPay(Long id, BillItemDto billItemDto);
Boolean addBillBook(BillItemDto billItemDto);
Boolean updateBillBook(Long id,BillItemDto billItemDto);
Boolean addBillCategory(BillCategoryDto billCategoryDto);
Boolean updateBillCategory(Long id, BillCategoryDto billCategoryDto);
}

View File

@@ -0,0 +1,25 @@
package com.cxx.admin.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.cxx.common.dto.blog.BlogCategoryDto;
import com.cxx.common.dto.blog.BlogDto;
import com.cxx.common.dto.blog.BlogVisitDto;
import com.cxx.common.vo.blog.BlogQueryVo;
import java.util.List;
public interface BlogManageService {
IPage<BlogDto> queryBlogByPage(Integer currentPage, Integer pageSize);
BlogDto queryBlogById(Long id);
List<BlogCategoryDto> queryBlogCategory();
Boolean addBlog(BlogDto blog);
Boolean updateBlog(Long id, BlogDto blog);
Boolean deleteBlog(Long id);
IPage<BlogVisitDto> queryBlogVisit(Integer currentPage, Integer pageSize);
}

View File

@@ -0,0 +1,8 @@
package com.cxx.admin.service;
public interface BudgetManageService {
Boolean addBudgetCategory(String category);
Boolean updateBudgetCategory(Long id, String category);
}

View File

@@ -0,0 +1,48 @@
package com.cxx.admin.service;
import com.cxx.admin.dto.file.ChunkInfoDto;
import com.cxx.admin.dto.file.ChunkResultDto;
import com.cxx.admin.dto.file.FileInfoDto;
import com.cxx.admin.dto.file.FileRecordDto;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
public interface FileService {
FileRecordDto uploadFile(MultipartFile file, String path, String md5);
/**
* 上传文件块
* @param chunkInfo 文件块信息
* @param path 上传路径
* @return 是否上传成功
*/
Boolean uploadChunk(ChunkInfoDto chunkInfo, String path);
/**
* 检查文件块信息
* @param identifier 唯一标识
* @param filename 文件名
* @param path 上传文件夹路径
* @return 检查结果
*/
ChunkResultDto checkChunk(String identifier, String filename, String path);
/**
* 删除文件块
* @param identifier 唯一标识
* @param path 上传文件夹路径
* @return 是否删除成功
*/
Boolean deleteChunk(String identifier, String path);
/**
* 合并文件
* @param filename 文件名
* @param path 上传文件夹路径
* @return 是否合并成功
*/
FileRecordDto mergeFile(String filename, String path);
List<FileInfoDto> getFolderInfo(String folderName);
}

View File

@@ -0,0 +1,19 @@
package com.cxx.admin.service;
import com.cxx.admin.dto.server.*;
import java.util.List;
public interface ServerMonitorService {
CpuDto getCpuInfo();
MemoryDto getMemoryInfo();
DiskDto getDiskInfo();
SystemInfoDto getSystemInfo();
void storeSystemMetrics();
List<SystemMetricsDto> querySystemMetrics(String range) ;
}

View File

@@ -0,0 +1,7 @@
package com.cxx.admin.service;
import com.cxx.common.dto.user.SessionDto;
public interface SessionService {
SessionDto create(String name, String password);
}

View File

@@ -0,0 +1,10 @@
package com.cxx.admin.service;
import com.cxx.common.dto.user.UserDto;
public interface UserService {
UserDto queryUser(Long id);
Boolean updateUser(Long id, UserDto userDto);
}

View File

@@ -0,0 +1,84 @@
package com.cxx.admin.service.impl;
import cn.dev33.satoken.secure.BCrypt;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cxx.admin.dao.AccountDao;
import com.cxx.admin.service.AccountService;
import com.cxx.admin.dto.user.AccountDto;
import com.cxx.common.entity.Account;
import com.cxx.common.entity.User;
import com.cxx.common.mapper.AccountMapper;
import com.cxx.common.mapper.UserMapper;
import com.cxx.framework.web.CustomException;
import jakarta.annotation.Resource;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
@Service
public class AccountServiceImpl implements AccountService {
@Resource
private AccountDao accountDao;
@Resource
private AccountMapper accountMapper;
@Resource
private UserMapper userMapper;
@Override
public List<AccountDto> queryAccountList() {
return accountDao.queryAccount();
}
@Override
public Account queryAccountByUserId(Long userId) {
LambdaQueryWrapper<Account> queryWrapper = new LambdaQueryWrapper<>();
return accountMapper.selectOne(queryWrapper.eq(Account::getUserId, userId));
}
@Transactional
@Override
public Boolean registerAccount(AccountDto accountDto) {
LambdaQueryWrapper<Account> queryWrapper = new LambdaQueryWrapper<>();
if (accountMapper.exists(queryWrapper.eq(Account::getAccountName, accountDto.getAccountName()))) {
throw new CustomException("该账户已经存在");
}
LambdaQueryWrapper<User> userQueryWrapper = new LambdaQueryWrapper<>();
if (userMapper.exists(userQueryWrapper.eq(User::getUsername, accountDto.getUsername()))) {
throw new CustomException("该用户已注册");
}
List<Integer> results = new ArrayList<>();
User user = new User();
BeanUtils.copyProperties(accountDto, user);
results.add(userMapper.insert(user));
Account account = new Account();
account.setAccountName(accountDto.getAccountName());
account.setPassword(BCrypt.hashpw(accountDto.getPassword(), BCrypt.gensalt()));
account.setUserId(user.getId());
account.setState(0);
results.add(accountMapper.insert(account));
return results.stream().allMatch(x -> x > 0);
}
@Override
public Boolean deleteAccount(Long id) {
Account account = accountMapper.selectById(id);
if (account == null) {
throw new CustomException("该账号不存在");
}
accountMapper.deleteById(id);
return userMapper.deleteById(account.getUserId()) == 1;
}
}

View File

@@ -0,0 +1,134 @@
package com.cxx.admin.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cxx.admin.service.BillManageService;
import com.cxx.common.dto.bill.BillCategoryDto;
import com.cxx.common.dto.bill.BillItemDto;
import com.cxx.common.entity.BillBook;
import com.cxx.common.entity.BillCategory;
import com.cxx.common.entity.BillPay;
import com.cxx.common.mapper.BillBookMapper;
import com.cxx.common.mapper.BillCategoryMapper;
import com.cxx.common.mapper.BillPayMapper;
import com.cxx.framework.web.CustomException;
import jakarta.annotation.Resource;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import java.util.Objects;
@Service
public class BillManageServiceImpl implements BillManageService {
@Resource
private BillPayMapper billPayMapper;
@Resource
private BillBookMapper billBookMapper;
@Resource
private BillCategoryMapper billCategoryMapper;
@Override
public Boolean addBillPay(BillItemDto billItemDto) {
// 1. 校验是否存在
LambdaQueryWrapper<BillPay> queryWrapper = new LambdaQueryWrapper<>();
if (billPayMapper.exists(queryWrapper.eq(BillPay::getName, billItemDto.getName()))) {
throw new CustomException("该账户已经存在");
}
// 2. 新增账户
BillPay newbillPay = new BillPay();
BeanUtils.copyProperties(billItemDto, newbillPay);
return billPayMapper.insert(newbillPay) == 1;
}
@Override
public Boolean updateBillPay(Long id, BillItemDto billItemDto) {
// 1. 校验是否存在
if (Objects.isNull(billPayMapper.selectById(id))) {
throw new RuntimeException("该账户不存在");
}
// 2. 更新账户
BillPay billPay = new BillPay();
BeanUtils.copyProperties(billItemDto, billPay);
billPay.setId(id);
return billPayMapper.updateById(billPay) == 1;
}
@Override
public Boolean addBillBook(BillItemDto billItemDto) {
// 1. 校验是否存在
LambdaQueryWrapper<BillBook> queryWrapper = new LambdaQueryWrapper<>();
if (billBookMapper.exists(queryWrapper.eq(BillBook::getName, billItemDto.getName()))) {
throw new CustomException("该账本已经存在");
}
// 2. 新增账本
BillBook billBook = new BillBook();
BeanUtils.copyProperties(billItemDto, billBook);
return billBookMapper.insert(billBook) == 1;
}
@Override
public Boolean updateBillBook(Long id, BillItemDto billItemDto) {
// 1. 校验是否存在
if (Objects.isNull(billBookMapper.selectById(id))) {
throw new CustomException("该账单不存在");
}
// 2. 更新账本
BillBook billBook = new BillBook();
BeanUtils.copyProperties(billItemDto, billBook);
billBook.setId(id);
return billBookMapper.updateById(billBook) == 1;
}
private Long getBillBook(String name) {
LambdaQueryWrapper<BillBook> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(BillBook::getName, name);
BillBook billBook = billBookMapper.selectOne(queryWrapper);
if (Objects.isNull(billBook)) {
throw new CustomException("该账本类型不存在");
}
return billBook.getId();
}
@Override
public Boolean addBillCategory(BillCategoryDto billCategoryDto) {
// 1. 校验是否存在
LambdaQueryWrapper<BillCategory> queryWrapper = new LambdaQueryWrapper<>();
if (billCategoryMapper.exists(queryWrapper.eq(BillCategory::getName, billCategoryDto.getName()))) {
throw new CustomException("该账单类型已经存在");
}
// 2. 新增账单类型
BillCategory newBillCategory = new BillCategory();
BeanUtils.copyProperties(billCategoryDto, newBillCategory);
newBillCategory.setBookId(getBillBook(billCategoryDto.getBookName()));
return billCategoryMapper.insert(newBillCategory) == 1;
}
@Override
public Boolean updateBillCategory(Long id, BillCategoryDto billCategoryDto) {
// 1. 校验是否存在
if (Objects.isNull(billCategoryMapper.selectById(id))) {
throw new CustomException("该账单类型不存在");
}
// 2. 更新账单类型
BillCategory billCategory = new BillCategory();
BeanUtils.copyProperties(billCategoryDto, billCategory);
billCategory.setBookId(getBillBook(billCategoryDto.getBookName()));
billCategory.setId(id);
return billCategoryMapper.updateById(billCategory) == 1;
}
}

View File

@@ -0,0 +1,193 @@
package com.cxx.admin.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cxx.admin.dao.BlogDao;
import com.cxx.admin.service.BlogManageService;
import com.cxx.admin.util.BlogUtils;
import com.cxx.common.dto.blog.BlogCategoryDto;
import com.cxx.common.dto.blog.BlogDto;
import com.cxx.common.dto.blog.BlogVisitDto;
import com.cxx.common.entity.Blog;
import com.cxx.common.entity.BlogCategory;
import com.cxx.common.entity.BlogContent;
import com.cxx.common.mapper.BlogCategoryMapper;
import com.cxx.common.mapper.BlogContentMapper;
import com.cxx.common.mapper.BlogMapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Objects;
@Service
public class BlogManageServiceImpl implements BlogManageService {
@Resource
private BlogDao blogDao;
@Resource
private BlogMapper blogMapper;
@Resource
private BlogCategoryMapper categoryMapper;
@Resource
private BlogContentMapper contentMapper;
@Override
public IPage<BlogDto> queryBlogByPage(Integer currentPage, Integer pageSize) {
return blogDao.queryBlogByPage(new Page<>(currentPage, pageSize));
}
@Override
public BlogDto queryBlogById(Long id) {
return blogDao.queryBlogById(id);
}
@Override
public List<BlogCategoryDto> queryBlogCategory() {
return blogDao.queryBlogCategory();
}
@Transactional
@Override
public Boolean addBlog(BlogDto blogDto) {
// 1. 新增博客基本信息
Blog blog = saveOrUpdateNewBlog(blogDto);
// 2. 新增博客内容信息
blog.setContentId(addBlogContent(blogDto.getContent()));
// 3. 插入数据库
return blogMapper.insert(blog) == 1;
}
@Transactional
@Override
public Boolean updateBlog(Long id, BlogDto blogDto) {
Blog blog = saveOrUpdateNewBlog(blogDto);
blog.setId(id);
// 1. 更新博客内容信息
updateBlogContent(getBlogById(id).getContentId(), blogDto.getContent());
// 2. 校验是否删除博客类别
deleteBlogCategory(getBlogById(id).getCategoryId());
// 3. 更新数据库
return blogMapper.updateById(blog) == 1;
}
@Transactional
@Override
public Boolean deleteBlog(Long id) {
// 1. 删除博客类别
deleteBlogCategory(getBlogById(id).getCategoryId());
// 2. 删除博客内容
contentMapper.deleteById(getBlogById(id).getContentId());
// 3. 删除博客
return blogMapper.deleteById(id) == 1;
}
@Override
public IPage<BlogVisitDto> queryBlogVisit(Integer currentPage, Integer pageSize) {
return blogDao.queryBlogVisit(new Page<>(currentPage, pageSize));
}
/**
* 通过博客id获取博客
* @param id id
* @return 博客
*/
private Blog getBlogById(Long id) {
Blog blog = blogMapper.selectById(id);
if (Objects.isNull(blog)) {
throw new RuntimeException("暂无该博客");
}
return blog;
}
/**
* 增加/更新 博客
* @param blogDto 前端传入的博客内容
* @return 博客
*/
private Blog saveOrUpdateNewBlog(BlogDto blogDto) {
Blog newBlog = new Blog();
// 设置博客基础信息
newBlog.setTitle(blogDto.getTitle());
newBlog.setTopValue(blogDto.getTopValue());
newBlog.setIsGreat(blogDto.getIsGreat());
// 设置博客类别
newBlog.setCategoryId(saveOrUpdateBlogCategory(blogDto.getCategory()));
// 设置博客内容
newBlog.setSummary(BlogUtils.getBlogSummary(blogDto.getContent()));
// 设置博客字数统计
Integer wordCount = BlogUtils.getWordCount(blogDto.getContent());
newBlog.setWordCount(wordCount);
newBlog.setReadDuration(BlogUtils.getReadDuration(wordCount));
return newBlog;
}
/**
* 设置博客类别
* @param category 类别
* @return 类别id
*/
private Long saveOrUpdateBlogCategory(String category) {
// 1. 查找类别是否存在
LambdaQueryWrapper<BlogCategory> queryWrapper = new LambdaQueryWrapper<>();
BlogCategory blogCategory = categoryMapper.selectOne(queryWrapper.eq(BlogCategory::getName, category));
// 2. 如果存在则返回id 否则需要新增类别
if (Objects.isNull(blogCategory)) {
BlogCategory newBlogCategory = new BlogCategory();
newBlogCategory.setName(category);
categoryMapper.insert(newBlogCategory);
return newBlogCategory.getId();
} else {
return blogCategory.getId();
}
}
/**
* 判断是否需要删除博客类别
* @param categoryId 博客类别id
*/
private void deleteBlogCategory(Long categoryId) {
LambdaQueryWrapper<Blog> queryWrapper = new LambdaQueryWrapper<>();
if (!blogMapper.exists(queryWrapper.eq(Blog::getCategoryId, categoryId))) {
// 如果没有该类别的博客 则删除博客类别
categoryMapper.deleteById(categoryId);
}
}
/**
* 新增博客内容
* @param content 博客内容
* @return 博客内容id
*/
private Long addBlogContent(String content) {
BlogContent blogContent = new BlogContent();
blogContent.setContent(content);
contentMapper.insert(blogContent);
return blogContent.getId();
}
/**
* 更新博客内容
* @param contentId 博客内容id
* @param content 博客内容
*/
private void updateBlogContent(Long contentId, String content) {
BlogContent blogContent = new BlogContent();
blogContent.setContent(content);
blogContent.setId(contentId);
contentMapper.updateById(blogContent);
}
}

View File

@@ -0,0 +1,43 @@
package com.cxx.admin.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cxx.admin.service.BudgetManageService;
import com.cxx.common.entity.BudgetCategory;
import com.cxx.common.mapper.BudgetCategoryMapper;
import com.cxx.framework.web.CustomException;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import java.util.Objects;
@Service
public class BudgetManageServiceImpl implements BudgetManageService {
@Resource
private BudgetCategoryMapper budgetCategoryMapper;
@Override
public Boolean addBudgetCategory(String category) {
LambdaQueryWrapper<BudgetCategory> queryWrapper = new LambdaQueryWrapper<>();
if (budgetCategoryMapper.exists(queryWrapper.eq(BudgetCategory::getName, category))) {
throw new CustomException("该预算类别已存在");
}
BudgetCategory budgetCategory = new BudgetCategory();
budgetCategory.setName(category);
return budgetCategoryMapper.insert(budgetCategory) == 1;
}
@Override
public Boolean updateBudgetCategory(Long id, String category) {
if (Objects.isNull(budgetCategoryMapper.selectById(id))) {
throw new CustomException("该预算类别不存在");
}
BudgetCategory budgetCategory = new BudgetCategory();
budgetCategory.setId(id);
budgetCategory.setName(category);
return budgetCategoryMapper.updateById(budgetCategory) == 1;
}
}

View File

@@ -0,0 +1,204 @@
package com.cxx.admin.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.cxx.admin.constant.FileConstant;
import com.cxx.admin.dto.file.ChunkInfoDto;
import com.cxx.admin.dto.file.ChunkResultDto;
import com.cxx.admin.dto.file.FileInfoDto;
import com.cxx.admin.service.FileService;
import com.cxx.admin.dto.file.FileRecordDto;
import com.cxx.admin.util.FileUtils;
import com.cxx.admin.util.UploadFileUtil;
import com.cxx.common.entity.FileRecord;
import com.cxx.common.mapper.FileRecordMapper;
import com.cxx.framework.web.CustomException;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
@Service
@Slf4j
public class FileServiceImpl implements FileService {
@Value("${file.path}")
private String fileRootPath;
@Resource
private FileRecordMapper fileRecordMapper;
@Override
public FileRecordDto uploadFile(MultipartFile multipartFile, String path, String md5) {
UploadFileUtil.checkDirIsExist(getFilePath(path));
String filename = multipartFile.getOriginalFilename();
String newPath = path + File.separator + md5 + "." + FilenameUtils.getExtension(filename);
File newFile = new File(getFilePath(newPath));
saveFile(multipartFile, newFile);
// 这里的url需要加上 WebMvcConfig 中设置的前缀
String url = FileConstant.FILE_URL_PREFIX + File.separator + newPath;
return getFileRecord(filename, md5, path, url);
}
@Override
public Boolean uploadChunk(ChunkInfoDto chunkInfo, String path) {
MultipartFile file = chunkInfo.getMultipartFile();
try {
// 1. 校验路径是否存在
UploadFileUtil.checkDirIsExist(getFilePath(path));
// 2. 获取文件块路径
Path chunkPath = Paths.get(UploadFileUtil.generateChunkPath(getFilePath(path), chunkInfo));
// 3. 将文件块写入指定路径
Files.write(chunkPath, file.getBytes());
} catch (IOException exception) {
log.error("文件上传块失败: {}", exception.getMessage());
throw new CustomException("文件上传块失败: " + exception.getMessage());
}
return true;
}
@Override
public ChunkResultDto checkChunk(String identifier, String filename, String path) {
ChunkResultDto chunkResult = new ChunkResultDto();
List<Integer> uploadedChunkList = new ArrayList<>();
String folder = getFilePath(path) + File.separator + identifier;
String file = folder + File.separator + filename;
// 判断文件夹是否存在
if (UploadFileUtil.fileExists(folder)) {
// 先判断整个文件是否已经上传过了,如果是,则告诉前端跳过上传,实现秒传
if (UploadFileUtil.fileExists(file)) {
chunkResult.setSkipUpload(true);
chunkResult.setUploadedChunkList(uploadedChunkList);
log.info("完整文件已存在,直接跳过上传,实现秒传");
} else {
chunkResult.setSkipUpload(false);
// 获取已经上传的文件块
chunkResult.setUploadedChunkList(UploadFileUtil.getUploadedChunkList(folder, filename));
}
} else {
chunkResult.setSkipUpload(false);
chunkResult.setUploadedChunkList(uploadedChunkList);
}
return chunkResult;
}
@Override
public Boolean deleteChunk(String identifier, String path) {
String folder = getFilePath(path) + File.separator + identifier;
log.info("开始删除文件: " + folder);
// 判断文件夹是否存在
if (UploadFileUtil.fileExists(folder)) {
UploadFileUtil.deleteDirectory(folder);
} else {
throw new CustomException("文件: " + folder + "不存在");
}
return true;
}
@Override
public FileRecordDto mergeFile(String filename, String path) {
String uuid = UUID.randomUUID().toString().replace("-", "");
String newFilename = uuid + "." + FilenameUtils.getExtension(filename);
try {
UploadFileUtil.mergeFile(newFilename, getFilePath(path));
} catch (IOException exception) {
throw new CustomException("合并文件: " + filename + " 失败");
}
String newPath = path + File.separator + newFilename;
String url = FileConstant.FILE_URL_PREFIX + File.separator + newPath;
return getFileRecord(filename, uuid, path, url);
}
@Override
public List<FileInfoDto> getFolderInfo(String folderName) {
File folder = new File(folderName);
List<FileInfoDto> fileInfoList = new ArrayList<>();
if (folder.exists() && folder.isDirectory()) {
File[] files = folder.listFiles();
if (files != null) {
List<FileInfoDto> folderInfoList = new ArrayList<>();
List<FileInfoDto> fileInfoSubList = new ArrayList<>();
for (File file : files) {
FileInfoDto fileInfo = new FileInfoDto();
fileInfo.setName(file.getName());
if (file.isDirectory()) {
fileInfo.setType("文件夹");
fileInfo.setSize("-");
folderInfoList.add(fileInfo);
} else {
fileInfo.setType(FileUtils.getFileType(file.getName()));
fileInfo.setSize(FileUtils.formatSize(file.length()));
fileInfoSubList.add(fileInfo);
}
fileInfo.setCreateDate(new Date(file.lastModified()));
}
fileInfoList.addAll(folderInfoList);
fileInfoList.addAll(fileInfoSubList);
}
}
return fileInfoList;
}
private void saveFile(MultipartFile multipartFile, File file) {
// 如果文件不存在
if (!file.exists()) {
try {
// 3. 如果不存在则创建文件
multipartFile.transferTo(file);
} catch (IOException e) {
throw new CustomException("文件上传失败:{}", e.getMessage());
}
}
}
private FileRecordDto getFileRecord(String filename, String md5, String path, String url) {
FileRecord fileRecord = new FileRecord();
fileRecord.setName(filename);
fileRecord.setMd5(md5);
fileRecord.setPath(path);
fileRecord.setUrl(url);
fileRecord.setId(saveDatabase(fileRecord, md5));
// 4. 返回文件信息
FileRecordDto fileRecordDto = new FileRecordDto();
BeanUtils.copyProperties(fileRecord, fileRecordDto);
return fileRecordDto;
}
private Long saveDatabase(FileRecord fileRecord, String md5) {
LambdaQueryWrapper<FileRecord> queryWrapper = Wrappers.lambdaQuery(FileRecord.class);
FileRecord dbFileRecord = fileRecordMapper.selectOne(queryWrapper.eq(FileRecord::getMd5, md5));
if (Objects.isNull(dbFileRecord)) {
fileRecordMapper.insert(fileRecord);
return fileRecord.getId();
} else {
return dbFileRecord.getId();
}
}
private String getFilePath(String path) {
return fileRootPath + path;
}
}

View File

@@ -0,0 +1,214 @@
package com.cxx.admin.service.impl;
import com.cxx.admin.dto.server.*;
import com.cxx.admin.service.ServerMonitorService;
import com.influxdb.client.InfluxDBClient;
import com.influxdb.client.InfluxDBClientFactory;
import com.influxdb.client.QueryApi;
import com.influxdb.client.WriteApi;
import com.influxdb.client.domain.WritePrecision;
import com.influxdb.client.write.Point;
import com.influxdb.query.FluxTable;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import oshi.SystemInfo;
import oshi.hardware.CentralProcessor;
import oshi.hardware.GlobalMemory;
import oshi.hardware.HWDiskStore;
import oshi.hardware.HardwareAbstractionLayer;
import oshi.software.os.OperatingSystem;
import java.io.File;
import java.text.DecimalFormat;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.TimeUnit;
@Service
public class ServerMonitorServiceImpl implements ServerMonitorService {
private final SystemInfo systemInfo = new SystemInfo();
private final HardwareAbstractionLayer hardware = systemInfo.getHardware();
private final OperatingSystem os = systemInfo.getOperatingSystem();
private final CentralProcessor processor = hardware.getProcessor();
private final InfluxDBClient client;
private final QueryApi queryApi;
private final String SYSTEM_METRICS = "system_metrics";
private final long GB = 1024 * 1024 * 1024;
private final DecimalFormat df = new DecimalFormat("0.00");
public ServerMonitorServiceImpl(
@Value("${influxdb.url}") String url,
@Value("${influxdb.token}") String token,
@Value("${influxdb.org}") String org,
@Value("${influxdb.bucket}") String bucket) {
this.client = InfluxDBClientFactory.create(url, token.toCharArray(), org, bucket);
this.queryApi = this.client.getQueryApi();
}
@Override
public CpuDto getCpuInfo() {
CpuDto cpuDto = new CpuDto();
cpuDto.setUsagePercent(formatPercent(hardware.getProcessor().getSystemCpuLoad(500) * 100));
return cpuDto;
}
@Override
public MemoryDto getMemoryInfo() {
GlobalMemory memory = hardware.getMemory();
MemoryDto memoryDto = new MemoryDto();
long total = memory.getTotal();
long free = memory.getAvailable();
long used = total - free;
memoryDto.setTotal(bytesToGb(total));
memoryDto.setUsed(bytesToGb(used));
memoryDto.setFree(bytesToGb(free));
memoryDto.setUsagePercent(formatPercent((used * 100.0) / total));
return memoryDto;
}
@Override
public DiskDto getDiskInfo() {
List<HWDiskStore> disks = hardware.getDiskStores();
if (disks.isEmpty()) {
return null;
}
// 获取根分区信息
HWDiskStore rootDisk = disks.get(0);
DiskDto diskInfo = new DiskDto();
diskInfo.setTotal(bytesToGb(rootDisk.getSize()));
// 获取文件系统使用情况
os.getFileSystem().getFileStores().stream()
.filter(fs -> fs.getMount().equals(File.separator))
.findFirst()
.ifPresent(fs -> {
long total = fs.getTotalSpace();
long free = fs.getFreeSpace();
long used = total - free;
diskInfo.setUsed(bytesToGb(used));
diskInfo.setFree(bytesToGb(free));
diskInfo.setUsagePercent(formatPercent((double) (used) * 100.0 / total));
});
return diskInfo;
}
@Override
public SystemInfoDto getSystemInfo() {
SystemInfoDto dto = new SystemInfoDto();
// 获取CPU信息
dto.setCpuName(processor.getProcessorIdentifier().getName());
dto.setCpuVendor(processor.getProcessorIdentifier().getVendor());
dto.setCpuLogicalCores(processor.getLogicalProcessorCount());
dto.setCpuPhysicalCores(processor.getPhysicalProcessorCount());
// 获取CPU负载
double[] loadAverage = processor.getSystemLoadAverage(3);
dto.setCpuSystemLoad(loadAverage[0]); // 1分钟平均负载
// 获取操作系统信息
dto.setOsFamily(os.getFamily());
dto.setOsVersion(os.getVersionInfo().getVersion());
dto.setOsManufacturer(os.getManufacturer());
// 获取系统运行时间(秒)
dto.setSystemUptime(TimeUnit.MILLISECONDS.toSeconds(systemInfo.getOperatingSystem().getSystemUptime()));
return dto;
}
@Override
public void storeSystemMetrics() {
try (WriteApi writeApi = client.getWriteApi()) {
CpuDto cpuDto = getCpuInfo();
MemoryDto memoryDto = getMemoryInfo();
DiskDto diskDto = getDiskInfo();
Point point = Point
.measurement(SYSTEM_METRICS)
.addTag("host", "localhost")
.addField("cpu_usage", cpuDto.getUsagePercent())
.addField("memory_total", memoryDto.getTotal())
.addField("memory_used", memoryDto.getUsed())
.addField("memory_free", memoryDto.getFree())
.addField("memory_usage", memoryDto.getUsagePercent())
.addField("disk_total", diskDto.getTotal())
.addField("disk_used", diskDto.getUsed())
.addField("disk_free", diskDto.getFree())
.addField("disk_usage", diskDto.getUsagePercent())
.time(Instant.now(), WritePrecision.S);
writeApi.writePoint(point);
}
}
@Override
public List<SystemMetricsDto> querySystemMetrics(String range) {
String fluxQuery = "from(bucket: \"server_metrics\")" +
"|> range(start: -" + range + ")" + // range 可以是 "1h", "24h" 等
"|> filter(fn: (r) => r._measurement == \"system_metrics\")" +
"|> pivot(rowKey: [\"_time\"], columnKey: [\"_field\"], valueColumn: \"_value\")";
List<Map<String, Object>> results = executeQuery(fluxQuery);
List<SystemMetricsDto> systemMetricsList = new ArrayList<>();
for (Map<String, Object> data : results) {
SystemMetricsDto systemMetrics = new SystemMetricsDto();
systemMetrics.setCpuUsage((Double) data.get("cpu_usage"));
systemMetrics.setMemoryTotal((Double) data.get("memory_total"));
systemMetrics.setMemoryUsed((Double) data.get("memory_used"));
systemMetrics.setMemoryFree((Double) data.get("memory_free"));
systemMetrics.setMemoryUsage((Double) data.get("memory_usage"));
systemMetrics.setDiskTotal((Double) data.get("disk_total"));
systemMetrics.setDiskUsed((Double) data.get("disk_used"));
systemMetrics.setDiskFree((Double) data.get("disk_free"));
systemMetrics.setDiskUsage((Double) data.get("disk_usage"));
systemMetrics.setTime(Date.from((Instant) data.get("time")));
systemMetricsList.add(systemMetrics);
}
return systemMetricsList;
}
private List<Map<String, Object>> executeQuery(String fluxQuery) {
List<FluxTable> tables = queryApi.query(fluxQuery);
List<Map<String, Object>> results = new ArrayList<>();
for (FluxTable table : tables) {
table.getRecords().forEach(record -> {
Map<String, Object> data = new HashMap<>();
data.put("time", record.getTime());
record.getValues().forEach((key, value) -> {
if (!key.startsWith("_")) { // 过滤掉内部字段
data.put(key, value);
}
});
results.add(data);
});
}
return results;
}
private double bytesToGb(long bytes) {
double gb = bytes / (double) GB;
return Double.parseDouble(df.format(gb));
}
public double formatPercent(double percent) {
return Double.parseDouble(df.format(percent));
}
}

View File

@@ -0,0 +1,56 @@
package com.cxx.admin.service.impl;
import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.cxx.common.dto.user.SessionDto;
import com.cxx.admin.service.SessionService;
import com.cxx.common.dto.user.UserDto;
import com.cxx.common.entity.Account;
import com.cxx.common.entity.User;
import com.cxx.common.mapper.AccountMapper;
import com.cxx.common.mapper.UserMapper;
import com.cxx.framework.web.CustomException;
import jakarta.annotation.Resource;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
@Service
public class SessionServiceImpl implements SessionService {
@Resource
private AccountMapper accountMapper;
@Resource
private UserMapper userMapper;
@Override
public SessionDto create(String name, String password) {
LambdaQueryWrapper<Account> queryWrapper = Wrappers.lambdaQuery(Account.class).eq(Account::getAccountName, name);
Account account = accountMapper.selectOne(queryWrapper);
if (account == null) {
throw new CustomException("账户: " + name + " 不存在");
}
if (!BCrypt.checkpw(password, account.getPassword())) {
throw new CustomException("密码不正确");
}
User user = userMapper.selectById(account.getUserId());
UserDto userDto = new UserDto();
BeanUtils.copyProperties(user, userDto);
userDto.setAccountId(account.getId());
userDto.setAccountName(name);
SessionDto sessionDto = new SessionDto();
StpUtil.login(account.getId());
sessionDto.setSaToken(StpUtil.getTokenInfo());
sessionDto.setUserInfo(userDto);
StpUtil.getSession().set("username", name);
return sessionDto;
}
}

View File

@@ -0,0 +1,53 @@
package com.cxx.admin.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cxx.admin.service.AccountService;
import com.cxx.admin.service.UserService;
import com.cxx.common.dto.user.UserDto;
import com.cxx.common.entity.User;
import com.cxx.common.mapper.UserMapper;
import com.cxx.framework.web.CustomException;
import jakarta.annotation.Resource;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
@Resource
private UserMapper userMapper;
@Resource
private AccountService accountService;
@Override
public UserDto queryUser(Long id) {
User user = userMapper.selectById(id);
if (user == null) {
throw new CustomException("未查询到该用户");
}
UserDto userDto = new UserDto();
BeanUtils.copyProperties(user, userDto);
userDto.setAccountName(accountService.queryAccountByUserId(id).getAccountName());
return userDto;
}
@Override
public Boolean updateUser(Long id, UserDto userDto) {
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
if (!userMapper.exists(queryWrapper.eq(User::getId, id))) {
throw new CustomException("该用户不存在");
}
queryWrapper.clear();
if (userMapper.exists(queryWrapper.eq(User::getUsername, userDto.getUsername()).ne(User::getId, id))) {
throw new CustomException("该用户已经存在");
}
User user = new User();
BeanUtils.copyProperties(userDto, user);
user.setId(id);
return userMapper.updateById(user) == 1;
}
}

View File

@@ -0,0 +1,73 @@
package com.cxx.admin.util;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class BlogUtils {
/**
* 博客概要字数
*/
private static final Integer BLOG_SUMMARY_COUNT = 100;
/**
* 阅读速度 600 字/分钟
*/
private static final Double READ_SPEED = 600.0;
/**
* 博客非统计字符
*/
private static final List<Character> excludeChart = new ArrayList<>(Arrays.asList(' ', '\n', '\t'));
/**
* 获取文本字数
*
* @param str 文本
* @return 字数
*/
public static Integer getWordCount(String str) {
Integer count = 0;
if (null == str || str.isEmpty()) {
return count;
}
for (int i = 0; i < str.length(); i++) {
char tmp = str.charAt(i);
if (!excludeChart.contains(tmp)) {
count++;
}
}
return count;
}
/**
* 获取阅读时长 单位:分钟
*
* @param wordCount 文本字数
* @return 阅读时长
*/
public static Double getReadDuration(Integer wordCount) {
return wordCount / READ_SPEED;
}
/**
* 获取简要信息
*
* @param content 博客内容
* @return 简要信息
*/
public static String getBlogSummary(String content) {
if (content.length() > BLOG_SUMMARY_COUNT) {
return content.substring(0, BLOG_SUMMARY_COUNT);
}
return content;
}
public static String getHexTimeStamp() {
return Long.toHexString(System.currentTimeMillis());
}
}

View File

@@ -0,0 +1,28 @@
package com.cxx.admin.util;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class FileUtils {
public static String getFileType(String fileName) {
int lastIndex = fileName.lastIndexOf('.');
if (lastIndex != -1) {
return fileName.substring(lastIndex + 1);
}
return "未知类型";
}
public static String formatSize(long size) {
if (size < 1024) {
return size + " B";
} else if (size < 1024 * 1024) {
return String.format("%.2f KB", (double) size / 1024);
} else if (size < 1024 * 1024 * 1024) {
return String.format("%.2f MB", (double) size / (1024 * 1024));
} else {
return String.format("%.2f GB", (double) size / (1024 * 1024 * 1024));
}
}
}

View File

@@ -0,0 +1,125 @@
package com.cxx.admin.util;
import com.cxx.admin.dto.FtpInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.net.PrintCommandListener;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import java.io.*;
import java.nio.charset.StandardCharsets;
/**
* @Author: Cxx
* @Date: 2024/9/24 21:49
* @Description:
*/
@Slf4j
public class FtpUtils {
private static FTPClient ftpClient;
/**
* 文件名分隔符
*/
public static String FILE_NAME_SPLIT = "_";
private static boolean connectFtp(FtpInfo ftpInfo) {
try {
ftpClient = new FTPClient();
// 设置utf-8 编码 否则中文文件名会乱码
ftpClient.setControlEncoding("utf-8");
ftpClient.connect(ftpInfo.getFtpIp(), ftpInfo.getFtpPort());
ftpClient.login(ftpInfo.getFtpUsername(), ftpInfo.getFtpPassword());
ftpClient.addProtocolCommandListener(
new PrintCommandListener(
new PrintWriter(new OutputStreamWriter(System.out, StandardCharsets.UTF_8)), true));
log.info("连接ftp服务器成功");
} catch (IOException e) {
log.error("连接ftp服务器失败", e);
throw new RuntimeException("连接ftp服务器失败");
}
return true;
}
private static void disConnectFtp() {
try {
if (ftpClient != null) {
ftpClient.disconnect();
}
log.info("关闭ftp服务器成功");
} catch (IOException e) {
log.error("关闭ftp服务器失败", e);
throw new RuntimeException("关闭ftp服务器失败");
}
}
private static void closeInputStream(FileInputStream fileInputStream) {
try {
if (fileInputStream != null) {
fileInputStream.close();
}
} catch (IOException e) {
log.error("关闭文件流失败:", e);
throw new RuntimeException("关闭文件流失败");
}
}
public static void uploadFile(FtpInfo ftpInfo, String remotePath, String fileName, File file) {
FileInputStream fileInputStream = null;
try {
if (connectFtp(ftpInfo)) {
ftpClient.changeWorkingDirectory(remotePath);
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
fileInputStream = new FileInputStream(file);
boolean uploadResult = ftpClient.storeFile(fileName, fileInputStream);
if (uploadResult) {
log.info("上传文件:{}成功", fileName);
} else {
throw new RuntimeException("上传ftp文件失败");
}
}
} catch (IOException e) {
log.error("上传ftp文件异常", e);
throw new RuntimeException("上传ftp文件异常");
} finally {
disConnectFtp();
closeInputStream(fileInputStream);
}
}
/**
* 校验是否存在文件
*
* @param ftpInfo ftp信息
* @param remotePath 文件路径
* @param md5 md5值
* @return 校验结果
*/
public static boolean checkIsExitFile(FtpInfo ftpInfo, String remotePath, String md5) {
boolean isExist = false;
try {
if (connectFtp(ftpInfo)) {
ftpClient.changeWorkingDirectory(remotePath);
FTPFile[] fileList = ftpClient.listFiles();
if (fileList != null) {
for (FTPFile imageFile : fileList) {
String fileMd5 = imageFile.getName().split(FILE_NAME_SPLIT)[0];
if (fileMd5.equals(md5)) {
log.info("文件{}已经存在", imageFile.getName());
isExist = true;
}
}
}
}
} catch (IOException e) {
log.error("校验ftp文件异常", e);
throw new RuntimeException("校验ftp文件异常");
} finally {
disConnectFtp();
}
return isExist;
}
}

View File

@@ -0,0 +1,173 @@
package com.cxx.admin.util;
import cn.hutool.core.io.file.FileNameUtil;
import com.cxx.admin.dto.file.ChunkInfoDto;
import lombok.extern.slf4j.Slf4j;
import java.io.File;
import java.io.IOException;
import java.nio.file.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;
/**
* @Author: chenxiuxiang
* @Date: 2023/7/24 14:49
* @Description: 上传文件工具类
*/
@Slf4j
public class UploadFileUtil {
private static final String FILE_SEPARATOR = "_";
/**
* 校验文件夹是否存在
*
* @param path 路径
*/
public static void checkDirIsExist(String path) {
File dir = new File(path);
if (!dir.exists() && !dir.isDirectory()) {
boolean mkdir = dir.mkdirs();
}
}
/**
* 获取文件路径
*
* @param path 上传文件夹路径
* @param chunkInfo 分片文件信息
* @return 文件路径
*/
public static String generateChunkPath(String path, ChunkInfoDto chunkInfo) {
return path + File.separator + chunkInfo.getFilename() + FILE_SEPARATOR + chunkInfo.getChunkNumber();
}
public static List<Integer> getUploadedChunkList(String folder, String filename) {
List<Integer> uploadedChunkList = new ArrayList<>();
// 获取文件夹下所有的文件
try (Stream<Path> list = Files.list(Paths.get(folder))) {
// 去除需要合并的文件
list.filter(path -> !path.getFileName().toString().equals(filename))
// 循环遍历文件 将已经上传的文件序号添加至列表中
.forEach(path -> {
String chunkPath = path.getFileName().toString();
int index = chunkPath.lastIndexOf(FILE_SEPARATOR);
uploadedChunkList.add(Integer.valueOf(chunkPath.substring(index + 1)));
});
} catch (IOException e) {
throw new RuntimeException(e);
}
return uploadedChunkList;
}
/**
* 文件合并
*/
public static void mergeFile(String filename, String path) throws IOException {
// 判断文件是否存在
String file = path + File.separator + filename;
if (fileExists(file)) {
deleteFile(file);
}
// 不存在的话,进行合并
Files.createFile(Paths.get(file));
// 获取文件夹下所有的文件
try (Stream<Path> list = Files.list(Paths.get(path))) {
// 保留后缀包含分隔符的
list.filter(chunkPath -> FileNameUtil.getSuffix(chunkPath.getFileName().toString()).contains(FILE_SEPARATOR))
// 按照文件名排序
.sorted((o1, o2) -> {
String p1 = o1.getFileName().toString();
String p2 = o2.getFileName().toString();
int i1 = p1.lastIndexOf(FILE_SEPARATOR);
int i2 = p2.lastIndexOf(FILE_SEPARATOR);
return Integer.valueOf(p1.substring(i1 + 1))
.compareTo(Integer.valueOf(p2.substring(i2 + 1)));
})
// 循环写入到文件中
.forEach(chunkPath -> {
try {
// 以追加的形式写入文件
Files.write(Paths.get(file), Files.readAllBytes(chunkPath), StandardOpenOption.APPEND);
// 合并后删除该块
Files.delete(chunkPath);
} catch (IOException exception) {
log.error("写入文件失败: " + exception.getMessage());
throw new RuntimeException(exception);
}
});
}
}
/**
* 根据文件的全路径名判断文件是否存在
*/
public static boolean fileExists(String file) {
Path path = Paths.get(file);
return Files.exists(path, LinkOption.NOFOLLOW_LINKS);
}
/**
* 删除目录(文件夹)以及目录下的文件
*
* @param sPath 被删除目录的文件路径
* @return 目录删除成功返回true否则返回false
*/
public static boolean deleteDirectory(String sPath) {
// 如果sPath不以文件分隔符结尾自动添加文件分隔符
if (!sPath.endsWith(File.separator)) {
sPath = sPath + File.separator;
}
File dirFile = new File(sPath);
// 如果dir对应的文件不存在或者不是一个目录则退出
if (!dirFile.exists() || !dirFile.isDirectory()) {
return false;
}
boolean flag = true;
// 删除文件夹下的所有文件(包括子目录)
File[] files = dirFile.listFiles();
for (File file : Objects.requireNonNull(files)) {
// 删除子文件
if (file.isFile()) {
flag = deleteFile(file.getAbsolutePath());
}
// 删除子目录
else {
flag = deleteDirectory(file.getAbsolutePath());
}
if (!flag) {
break;
}
}
if (!flag) {
return false;
}
log.info("文件删除成功");
// 删除当前目录
return dirFile.delete();
}
/**
* 删除单个文件
*
* @param sPath 被删除文件的文件名
* @return 单个文件删除成功返回true否则返回false
*/
public static boolean deleteFile(String sPath) {
boolean flag = false;
File file = new File(sPath);
// 路径为文件且不为空则进行删除
if (file.isFile() && file.exists()) {
flag = file.delete();
}
return flag;
}
}

View File

@@ -0,0 +1,15 @@
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/sweet_hut?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=UTF-8&useSSL=false
username: root
password: 123456
logging:
level:
root: info
config:
file:
path: D:\\temp\\
log-path: D:\\temp\\

View File

@@ -0,0 +1,16 @@
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://mysql:3306/sweet_hut?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=UTF-8&useSSL=false
username: docker
password: 19940822Cxx
logging:
fluentd:
host: fluent-bit
port: 24224
level:
root: info
file:
path: /upload-file/

View File

@@ -0,0 +1,16 @@
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/sweet_hut?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=UTF-8&useSSL=false
username: cxx
password: 19940822Cxx@1213
logging:
level:
root: info
config:
classpath:logback-spring-drop.xml
file:
path: /root/docker/upload-file/
log-path: /root/service/logs/

View File

@@ -0,0 +1,36 @@
server:
port: 8080
spring:
application:
name: @project.artifactId@
version: @project.version@
profiles:
active: dev
servlet:
multipart:
max-file-size: 10MB
max-request-size: 100MB
# mybatis plus mapper路径
mybatis-plus:
# mybatis plus
mapper-locations: classpath*:/mapper/**/*.xml
configuration:
log-impl:
org.apache.ibatis.logging.stdout.StdOutImpl
ftp:
ip: 192.168.31.54
port: 21
username: ftp-cxx
password: 19940822cxx
influxdb:
url: http://localhost:8086
token: i3eja-5jMQBxxF29pvKBialZ_j4y3p8iAMI86Ht3YcMTXhitIeUfx30vAv79xfhckC5YExTKj91AribNwBZBOQ==
org: cxx
bucket: server_metrics
web-starter:
base-package: com.cxx.service

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="10 seconds">
<contextName>logback</contextName>
<property name="log.path" value="logs/adminService"/>
<!--控制台日志格式:彩色日志-->
<!-- magenta:洋红 -->
<!-- boldMagenta:粗红-->
<!-- cyan:青色 -->
<!-- white:白色 -->
<!-- magenta:洋红 -->
<property name="CONSOLE_LOG_PATTERN"
value="%yellow(%date{yyyy-MM-dd HH:mm:ss}) |%highlight(%-5level) |%blue(%thread) |%blue(%file:%line) |%green(%logger) |%cyan(%msg%n)"/>
<!--文件日志格式-->
<property name="FILE_LOG_PATTERN"
value="%date{yyyy-MM-dd HH:mm:ss} |%-5level |%thread |%file:%line |%logger |%msg%n"/>
<!--编码-->
<property name="ENCODING"
value="UTF-8"/>
<!--输出到控制台-->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<!--日志级别-->
<level>DEBUG</level>
</filter>
<encoder>
<!--日志格式-->
<Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
<!--日志字符集-->
<charset>${ENCODING}</charset>
</encoder>
</appender>
<!--输出到文件-->
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--日志过滤器此日志文件只记录INFO级别的-->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_info.log</file>
<encoder>
<pattern>${FILE_LOG_PATTERN}</pattern>
<charset>${ENCODING}</charset>
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 每天日志归档路径以及格式 -->
<fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>500MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
</appender>
<appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 日志过滤器此日志文件只记录WARN级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARN</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_warn.log</file>
<encoder>
<pattern>${FILE_LOG_PATTERN}</pattern>
<charset>${ENCODING}</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
</appender>
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 日志过滤器此日志文件只记录ERROR级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_error.log</file>
<encoder>
<pattern>${FILE_LOG_PATTERN}</pattern>
<charset>${ENCODING}</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="INFO_FILE"/>
<appender-ref ref="WARN_FILE"/>
<appender-ref ref="ERROR_FILE"/>
</root>
</configuration>

View File

@@ -0,0 +1,13 @@
<?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.cxx.admin.dao.AccountDao">
<select id="queryAccount" resultType="com.cxx.admin.dto.user.AccountDto">
SELECT b.id AS id,
b.account_name AS accountName,
a.username AS username,
b.state AS state,
b.create_time AS date
FROM user as a
LEFT JOIN account as b on a.id = b.user_id
</select>
</mapper>

View File

@@ -0,0 +1,64 @@
<?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.cxx.admin.dao.BlogDao">
<select id="queryBlogByPage" resultType="com.cxx.common.dto.blog.BlogDto">
SELECT a.id AS id,
a.title AS title,
a.top_value AS topValue,
a.is_great AS isGreat,
b.NAME AS category,
a.summary AS summary,
a.word_count AS wordCount,
a.read_duration AS readDuration,
COUNT(c.id) AS visitCount,
a.create_time AS createTime,
a.update_time AS updateTime
FROM blog a
LEFT JOIN blog_category b ON b.id = a.category_id
LEFT JOIN blog_visit c ON c.blog_id = a.id
GROUP BY a.id
ORDER BY a.top_value DESC,
a.update_time DESC
</select>
<select id="queryBlogById" resultType="com.cxx.common.dto.blog.BlogDto">
SELECT a.id AS id,
a.title AS title,
a.top_value AS topValue,
a.is_great AS isGreat,
b.NAME AS category,
a.summary AS summary,
c.content AS content,
a.word_count AS wordCount,
a.read_duration AS readDuration,
COUNT(d.id) AS visitCount,
a.create_time AS createTime,
a.update_time AS updateTime
FROM blog a
LEFT JOIN blog_category b ON b.id = a.category_id
LEFT JOIN blog_content c ON c.id = a.content_id
LEFT JOIN blog_visit d ON d.blog_id = a.id
WHERE a.id = #{id} LIMIT 1
</select>
<select id="queryBlogCategory" resultType="com.cxx.common.dto.blog.BlogCategoryDto">
SELECT b.name AS name,
count(b.name) AS count
FROM blog a
LEFT JOIN blog_category b
ON a.category_id = b.id
GROUP BY b.name
</select>
<select id="queryBlogVisit" resultType="com.cxx.common.dto.blog.BlogVisitDto">
SELECT a.ip AS ip,
a.os AS os,
a.browser AS browser,
a.uri AS uri,
b.title AS title,
a.create_time AS visitTime
FROM blog_visit AS a
LEFT JOIN blog AS b on a.blog_id = b.id
ORDER BY a.create_time DESC
</select>
</mapper>

View File

@@ -0,0 +1,21 @@
package com.cxx.admin;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.Date;
@SpringBootTest
public class AdminServiceApplicationTests {
@Test
public void contextLoads() {
}
@Test
public void TestEmail() {
}
}