fix: 修复后端兼容性和前后端配置问题
后端修复: - Spring Boot 降级到 3.1.12 以兼容 MyBatis-Plus 3.5.6 - 添加 RedisConfig 配置 RedisTemplate Bean - 修复数据库连接字符编码 characterEncoding=UTF-8 - 添加健康检查接口 /api/v1/health 到认证白名单 - 实体字段同步数据库: WorkLog 添加 recordTime, LogTemplate 添加 templateContent/instruction - 修复 logback 滚动策略配置 - 密码验证临时改为明文比对(测试用) 前端修复: - API baseURL 统一修正为 /wlog/api/v1 - Vite 配置添加 base 路径 (/wladmin/, /wlmobile/) 脚本修复: - stop.sh/status.sh 使用动态 APP_HOME 获取路径
This commit is contained in:
parent
ba9e2c12c8
commit
e36ac36af5
@ -3,9 +3,12 @@
|
||||
# 工作日志服务平台 - 应用状态查看脚本
|
||||
# ====================================================
|
||||
|
||||
# 获取脚本所在目录的上级目录作为应用根目录
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
APP_HOME="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
|
||||
# 应用配置
|
||||
APP_NAME="worklog-api"
|
||||
APP_HOME="/opt/worklog/${APP_NAME}"
|
||||
PID_FILE="${APP_HOME}/${APP_NAME}.pid"
|
||||
|
||||
# 颜色输出
|
||||
|
||||
@ -3,9 +3,12 @@
|
||||
# 工作日志服务平台 - 应用停止脚本
|
||||
# ====================================================
|
||||
|
||||
# 获取脚本所在目录的上级目录作为应用根目录
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
APP_HOME="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
|
||||
# 应用配置
|
||||
APP_NAME="worklog-api"
|
||||
APP_HOME="/opt/worklog/${APP_NAME}"
|
||||
PID_FILE="${APP_HOME}/${APP_NAME}.pid"
|
||||
|
||||
# 检查 PID 文件是否存在
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>3.2.2</version>
|
||||
<version>3.1.12</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
@ -22,7 +22,7 @@
|
||||
<java.version>21</java.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<mybatis-plus.version>3.5.5</mybatis-plus.version>
|
||||
<mybatis-plus.version>3.5.6</mybatis-plus.version>
|
||||
<hutool.version>5.8.25</hutool.version>
|
||||
<springdoc.version>2.3.0</springdoc.version>
|
||||
<mysql.version>8.0.33</mysql.version>
|
||||
|
||||
@ -21,13 +21,14 @@ public class PasswordUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验密码
|
||||
* 校验密码(临时明文比对)
|
||||
*
|
||||
* @param rawPassword 明文密码
|
||||
* @param encodedPassword 加密后的密码
|
||||
* @return 是否匹配
|
||||
*/
|
||||
public static boolean matches(String rawPassword, String encodedPassword) {
|
||||
return ENCODER.matches(rawPassword, encodedPassword);
|
||||
// TODO: 临时使用明文比对,生产环境需恢复 BCrypt 验证
|
||||
return rawPassword.equals(encodedPassword);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,33 @@
|
||||
package com.wjbl.worklog.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
|
||||
/**
|
||||
* Redis 配置类
|
||||
*/
|
||||
@Configuration
|
||||
public class RedisConfig {
|
||||
|
||||
@Bean
|
||||
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
|
||||
RedisTemplate<String, Object> template = new RedisTemplate<>();
|
||||
template.setConnectionFactory(connectionFactory);
|
||||
|
||||
// Key 使用 String 序列化
|
||||
template.setKeySerializer(new StringRedisSerializer());
|
||||
template.setHashKeySerializer(new StringRedisSerializer());
|
||||
|
||||
// Value 使用 JSON 序列化
|
||||
GenericJackson2JsonRedisSerializer jsonSerializer = new GenericJackson2JsonRedisSerializer();
|
||||
template.setValueSerializer(jsonSerializer);
|
||||
template.setHashValueSerializer(jsonSerializer);
|
||||
|
||||
template.afterPropertiesSet();
|
||||
return template;
|
||||
}
|
||||
}
|
||||
@ -24,7 +24,7 @@ public class WebMvcConfig implements WebMvcConfigurer {
|
||||
private static final String[] WHITE_LIST = {
|
||||
"/api/v1/auth/login",
|
||||
"/api/v1/auth/logout",
|
||||
"/api/v1/auth/health",
|
||||
"/api/v1/health",
|
||||
"/swagger-ui.html",
|
||||
"/swagger-ui/**",
|
||||
"/v3/api-docs/**",
|
||||
|
||||
@ -30,7 +30,12 @@ public class LogTemplate implements Serializable {
|
||||
/**
|
||||
* 模板内容(Markdown格式)
|
||||
*/
|
||||
private String content;
|
||||
private String templateContent;
|
||||
|
||||
/**
|
||||
* 使用说明
|
||||
*/
|
||||
private String instruction;
|
||||
|
||||
/**
|
||||
* 状态(0-禁用,1-启用)
|
||||
|
||||
@ -34,9 +34,9 @@ public class WorkLog implements Serializable {
|
||||
private LocalDate logDate;
|
||||
|
||||
/**
|
||||
* 日志标题
|
||||
* 记录时间
|
||||
*/
|
||||
private String title;
|
||||
private LocalDateTime recordTime;
|
||||
|
||||
/**
|
||||
* 日志内容(Markdown格式)
|
||||
|
||||
@ -22,13 +22,6 @@ public class LogCreateDTO implements Serializable {
|
||||
@Schema(description = "日志日期,默认当天")
|
||||
private LocalDate logDate;
|
||||
|
||||
/**
|
||||
* 日志标题
|
||||
*/
|
||||
@NotBlank(message = "标题不能为空")
|
||||
@Schema(description = "日志标题", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 日志内容(Markdown格式)
|
||||
*/
|
||||
|
||||
@ -14,12 +14,6 @@ public class LogUpdateDTO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 日志标题
|
||||
*/
|
||||
@Schema(description = "日志标题")
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 日志内容(Markdown格式)
|
||||
*/
|
||||
|
||||
@ -27,4 +27,10 @@ public class TemplateCreateDTO implements Serializable {
|
||||
*/
|
||||
@Schema(description = "模板内容(Markdown格式)")
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 使用说明
|
||||
*/
|
||||
@Schema(description = "使用说明")
|
||||
private String instruction;
|
||||
}
|
||||
|
||||
@ -25,4 +25,10 @@ public class TemplateUpdateDTO implements Serializable {
|
||||
*/
|
||||
@Schema(description = "模板内容(Markdown格式)")
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 使用说明
|
||||
*/
|
||||
@Schema(description = "使用说明")
|
||||
private String instruction;
|
||||
}
|
||||
|
||||
@ -42,7 +42,7 @@ public class LogServiceImpl implements LogService {
|
||||
WorkLog workLog = new WorkLog();
|
||||
workLog.setUserId(currentUserId);
|
||||
workLog.setLogDate(logDate);
|
||||
workLog.setTitle(dto.getTitle());
|
||||
workLog.setRecordTime(LocalDateTime.now());
|
||||
workLog.setContent(dto.getContent());
|
||||
workLog.setTemplateId(dto.getTemplateId());
|
||||
workLog.setDeleted(0);
|
||||
@ -77,9 +77,6 @@ public class LogServiceImpl implements LogService {
|
||||
}
|
||||
|
||||
// 更新日志
|
||||
if (dto.getTitle() != null) {
|
||||
workLog.setTitle(dto.getTitle());
|
||||
}
|
||||
if (dto.getContent() != null) {
|
||||
workLog.setContent(dto.getContent());
|
||||
}
|
||||
|
||||
@ -37,7 +37,8 @@ public class TemplateServiceImpl implements TemplateService {
|
||||
// 创建模板
|
||||
LogTemplate template = new LogTemplate();
|
||||
template.setTemplateName(dto.getTemplateName());
|
||||
template.setContent(dto.getContent());
|
||||
template.setTemplateContent(dto.getContent());
|
||||
template.setInstruction(dto.getInstruction());
|
||||
template.setStatus(1); // 默认启用
|
||||
template.setDeleted(0);
|
||||
|
||||
@ -74,7 +75,10 @@ public class TemplateServiceImpl implements TemplateService {
|
||||
|
||||
// 更新模板内容
|
||||
if (dto.getContent() != null) {
|
||||
template.setContent(dto.getContent());
|
||||
template.setTemplateContent(dto.getContent());
|
||||
}
|
||||
if (dto.getInstruction() != null) {
|
||||
template.setInstruction(dto.getInstruction());
|
||||
}
|
||||
|
||||
// 设置审计字段
|
||||
@ -142,7 +146,13 @@ public class TemplateServiceImpl implements TemplateService {
|
||||
*/
|
||||
private TemplateVO convertToVO(LogTemplate template) {
|
||||
TemplateVO vo = new TemplateVO();
|
||||
BeanUtils.copyProperties(template, vo);
|
||||
vo.setId(template.getId());
|
||||
vo.setTemplateName(template.getTemplateName());
|
||||
vo.setContent(template.getTemplateContent());
|
||||
vo.setInstruction(template.getInstruction());
|
||||
vo.setStatus(template.getStatus());
|
||||
vo.setCreatedTime(template.getCreatedTime());
|
||||
vo.setUpdatedTime(template.getUpdatedTime());
|
||||
return vo;
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,12 +34,6 @@ public class LogVO implements Serializable {
|
||||
@Schema(description = "日志日期")
|
||||
private LocalDate logDate;
|
||||
|
||||
/**
|
||||
* 日志标题
|
||||
*/
|
||||
@Schema(description = "日志标题")
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 日志内容(Markdown格式)
|
||||
*/
|
||||
|
||||
@ -33,6 +33,12 @@ public class TemplateVO implements Serializable {
|
||||
@Schema(description = "模板内容(Markdown格式)")
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 使用说明
|
||||
*/
|
||||
@Schema(description = "使用说明")
|
||||
private String instruction;
|
||||
|
||||
/**
|
||||
* 状态(0-禁用,1-启用)
|
||||
*/
|
||||
|
||||
@ -22,7 +22,7 @@ spring:
|
||||
# 数据源配置
|
||||
datasource:
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
url: jdbc:mysql://localhost:3306/worklog?useUnicode=true&characterEncoding=utf8mb4&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true
|
||||
url: jdbc:mysql://localhost:3306/worklog?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true
|
||||
username: worklog
|
||||
password: Wlog@123
|
||||
type: com.zaxxer.hikari.HikariDataSource
|
||||
|
||||
@ -24,11 +24,9 @@
|
||||
<pattern>${LOG_PATTERN}</pattern>
|
||||
<charset>UTF-8</charset>
|
||||
</encoder>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_PATH}/app-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
|
||||
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||
<maxFileSize>100MB</maxFileSize>
|
||||
</timeBasedFileNamingAndTriggeringPolicy>
|
||||
<maxFileSize>100MB</maxFileSize>
|
||||
<maxHistory>30</maxHistory>
|
||||
</rollingPolicy>
|
||||
</appender>
|
||||
@ -40,11 +38,9 @@
|
||||
<pattern>${LOG_PATTERN}</pattern>
|
||||
<charset>UTF-8</charset>
|
||||
</encoder>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_PATH}/sql-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
|
||||
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||
<maxFileSize>100MB</maxFileSize>
|
||||
</timeBasedFileNamingAndTriggeringPolicy>
|
||||
<maxFileSize>100MB</maxFileSize>
|
||||
<maxHistory>30</maxHistory>
|
||||
</rollingPolicy>
|
||||
</appender>
|
||||
|
||||
@ -43,7 +43,6 @@ class LogServiceTest {
|
||||
testLog.setId("log-id-123");
|
||||
testLog.setUserId("user-id-123");
|
||||
testLog.setLogDate(LocalDate.now());
|
||||
testLog.setTitle("今日工作日志");
|
||||
testLog.setContent("今天完成了xxx任务");
|
||||
testLog.setDeleted(0);
|
||||
|
||||
@ -57,7 +56,6 @@ class LogServiceTest {
|
||||
void createLog_success() {
|
||||
// Given
|
||||
LogCreateDTO dto = new LogCreateDTO();
|
||||
dto.setTitle("新日志");
|
||||
dto.setContent("日志内容");
|
||||
dto.setLogDate(LocalDate.now());
|
||||
|
||||
@ -69,7 +67,7 @@ class LogServiceTest {
|
||||
|
||||
// Then
|
||||
assertNotNull(result);
|
||||
assertEquals("新日志", result.getTitle());
|
||||
assertEquals("日志内容", result.getContent());
|
||||
verify(workLogDataService).save(any(WorkLog.class));
|
||||
}
|
||||
|
||||
@ -78,7 +76,6 @@ class LogServiceTest {
|
||||
void createLog_alreadyExists() {
|
||||
// Given
|
||||
LogCreateDTO dto = new LogCreateDTO();
|
||||
dto.setTitle("新日志");
|
||||
dto.setContent("日志内容");
|
||||
dto.setLogDate(LocalDate.now());
|
||||
|
||||
@ -94,7 +91,6 @@ class LogServiceTest {
|
||||
void updateLog_success_ownLog() {
|
||||
// Given
|
||||
LogUpdateDTO dto = new LogUpdateDTO();
|
||||
dto.setTitle("更新后的标题");
|
||||
dto.setContent("更新后的内容");
|
||||
|
||||
when(workLogDataService.getById("log-id-123")).thenReturn(testLog);
|
||||
@ -105,7 +101,7 @@ class LogServiceTest {
|
||||
|
||||
// Then
|
||||
assertNotNull(result);
|
||||
assertEquals("更新后的标题", result.getTitle());
|
||||
assertEquals("更新后的内容", result.getContent());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -118,7 +114,7 @@ class LogServiceTest {
|
||||
otherUserLog.setLogDate(LocalDate.now());
|
||||
|
||||
LogUpdateDTO dto = new LogUpdateDTO();
|
||||
dto.setTitle("更新后的标题");
|
||||
dto.setContent("更新后的内容");
|
||||
|
||||
when(workLogDataService.getById("other-log-id")).thenReturn(otherUserLog);
|
||||
|
||||
@ -140,7 +136,7 @@ class LogServiceTest {
|
||||
otherUserLog.setLogDate(LocalDate.now());
|
||||
|
||||
LogUpdateDTO dto = new LogUpdateDTO();
|
||||
dto.setTitle("管理员更新");
|
||||
dto.setContent("管理员更新内容");
|
||||
|
||||
when(workLogDataService.getById("other-log-id")).thenReturn(otherUserLog);
|
||||
when(workLogDataService.updateById(any(WorkLog.class))).thenReturn(true);
|
||||
@ -150,7 +146,7 @@ class LogServiceTest {
|
||||
|
||||
// Then
|
||||
assertNotNull(result);
|
||||
assertEquals("管理员更新", result.getTitle());
|
||||
assertEquals("管理员更新内容", result.getContent());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -193,7 +189,7 @@ class LogServiceTest {
|
||||
|
||||
// Then
|
||||
assertNotNull(result);
|
||||
assertEquals("今日工作日志", result.getTitle());
|
||||
assertEquals("今天完成了xxx任务", result.getContent());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@ -42,7 +42,7 @@ class TemplateServiceTest {
|
||||
testTemplate = new LogTemplate();
|
||||
testTemplate.setId("template-id-123");
|
||||
testTemplate.setTemplateName("日报模板");
|
||||
testTemplate.setContent("# 今日工作\n\n## 完成事项\n\n## 明日计划");
|
||||
testTemplate.setTemplateContent("# 今日工作\n\n## 完成事项\n\n## 明日计划");
|
||||
testTemplate.setStatus(1);
|
||||
testTemplate.setDeleted(0);
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@ import { TOKEN_KEY } from '@/utils/constants'
|
||||
|
||||
// 创建 axios 实例
|
||||
const service: AxiosInstance = axios.create({
|
||||
baseURL: '/wlmobile/api/v1',
|
||||
baseURL: '/wlog/api/v1',
|
||||
timeout: 15000
|
||||
})
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -3,6 +3,7 @@ import vue from '@vitejs/plugin-vue';
|
||||
import { fileURLToPath, URL } from 'node:url';
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
base: '/wlmobile/',
|
||||
plugins: [vue()],
|
||||
resolve: {
|
||||
alias: {
|
||||
|
||||
@ -4,6 +4,7 @@ import { fileURLToPath, URL } from 'node:url'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
base: '/wlmobile/',
|
||||
plugins: [vue()],
|
||||
resolve: {
|
||||
alias: {
|
||||
|
||||
@ -5,7 +5,7 @@ import { TOKEN_KEY } from '@/utils/constants'
|
||||
|
||||
// 创建 axios 实例
|
||||
const service: AxiosInstance = axios.create({
|
||||
baseURL: '/wladmin/api/v1',
|
||||
baseURL: '/wlog/api/v1',
|
||||
timeout: 15000
|
||||
})
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@ import path from 'path'
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
base: '/wladmin/',
|
||||
plugins: [vue()],
|
||||
resolve: {
|
||||
alias: {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user