fix(config): 更新API地址和配置设置

- 修改前端环境配置文件中的API基础URL地址
- 切换路由模式从history到hash模式以解决部署问题
- 注释掉axios的withCredentials配置避免跨域问题
- 修复后端JWT认证过滤器中的代码注释和逻辑结构
- 更新Docker容器时区设置为上海时区
- 修复笔记编辑器中保存数据时字段缺失的问题
- 添加Vite构建输出目录和资源目录配置
- 恢复后端开发环境数据库路径配置
This commit is contained in:
ikmkj
2026-01-06 17:58:24 +08:00
parent 3e252e0043
commit 701a621552
11 changed files with 63 additions and 10 deletions

View File

@@ -33,38 +33,69 @@ public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
this.tokenHead = tokenHead;
}
/**
* 内部过滤器方法,用于处理请求的认证逻辑
* @param request HttpServletRequest对象包含请求信息
* @param response HttpServletResponse对象用于响应
* @param chain FilterChain过滤器链用于传递请求和响应
* @throws ServletException 可能抛出的Servlet异常
* @throws IOException 可能抛出的IO异常
*/
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
// 从请求头中获取认证信息
String authHeader = request.getHeader(this.tokenHeader);
// 检查请求头是否存在且以指定的token前缀开头
if (authHeader != null && authHeader.startsWith(this.tokenHead)) {
// 提取实际的token值去除前缀
final String authToken = authHeader.substring(this.tokenHead.length());
try {
// 从token中解析出用户名
String username = jwtTokenUtil.getUsernameFromToken(authToken);
// 验证用户名不为空且当前没有已认证的用户
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
// 通过用户名加载用户详情
UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
// 验证token的有效性
if (jwtTokenUtil.validateToken(authToken, userDetails)) {
// 创建认证对象
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
// 设置认证详情
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
// 将认证信息存入安全上下文
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
} catch (ExpiredJwtException e) {
// 处理token过期异常
sendErrorResponse(response, ResultCode.TOKEN_EXPIRED);
return;
} catch (SignatureException e) {
// 处理token签名异常
sendErrorResponse(response, ResultCode.TOKEN_INVALID);
return;
}
}
// 继续过滤器链的处理
chain.doFilter(request, response);
}
/**
* 发送错误响应信息
* @param response HTTP响应对象
* @param resultCode 结果代码,包含错误信息
* @throws IOException 可能抛出的IO异常
*/
private void sendErrorResponse(HttpServletResponse response, ResultCode resultCode) throws IOException {
// 设置响应内容类型为JSON字符编码为UTF-8
response.setContentType("application/json;charset=UTF-8");
// 设置HTTP状态码为401未授权
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
// 创建ObjectMapper实例用于对象与JSON之间的转换
ObjectMapper mapper = new ObjectMapper();
// 将失败结果转换为JSON字符串并写入响应输出流
response.getWriter().write(mapper.writeValueAsString(R.fail(resultCode)));
}
}

View File

@@ -32,12 +32,23 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
@Autowired
private UserMapper userMapper;
/**
* 重写Spring Security的loadUserByUsername方法用于用户认证
* @param username 用户名
* @return UserDetails 用户详细信息
* @throws UsernameNotFoundException 当用户未找到时抛出此异常
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 根据用户名从数据库查询用户信息
User user = userMapper.findByUsername(username);
// 判断用户是否存在,如果不存在则抛出异常
if (ObjectUtil.isNull(user)) {
throw new UsernameNotFoundException("User not found with username: " + username);
}
// 返回UserDetails对象包含用户名、密码和权限列表
// 这里使用Spring Security提供的User类实现UserDetails接口
// 参数分别为:用户名,密码,权限集合(这里使用空集合表示无额外权限)
return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), new ArrayList<>()); // 账号,密码,权限
}

View File

@@ -1,8 +1,7 @@
spring:
datasource:
driver-class-name: org.sqlite.JDBC
# url: jdbc:sqlite:C:\it\houtaigunli\biji\mydatabase.db
url: jdbc:sqlite:C:\KAIFA\2\mydatabase.db
url: jdbc:sqlite:C:\it\houtaigunli\biji\mydatabase.db
jpa:
hibernate:
ddl-auto: none

View File

@@ -1,4 +1,4 @@
VITE_BASE_URL=./
# 在为App构建前请将这里替换为你的真实后端API公网地址
VITE_API_BASE_URL=https://api.example.com
VITE_API_BASE_URL=https://biji-houduan.ikmkj.dpdns.org

View File

@@ -1,2 +1,2 @@
VITE_BASE_URL=/
VITE_API_BASE_URL=/api
VITE_API_BASE_URL=https://biji-houduan.ikmkj.dpdns.org

View File

@@ -83,7 +83,15 @@ const save = async (value) => {
const content = typeof value === 'string' ? value : vditor.value.getValue();
try {
saveStatus.value = '正在保存...';
await updateMarkdown({ id: props.editData.id, content: content });
// 发送完整的笔记对象,确保包含所有必要字段
await updateMarkdown({
id: props.editData.id,
content: content,
title: props.editData.title,
groupingId: props.editData.groupingId,
fileName: props.editData.fileName,
isPrivate: props.editData.isPrivate
});
// 保存成功,更新状态
saveStatus.value = '已保存';
emit('update:editData', { ...props.editData, content: content });

View File

@@ -1,4 +1,4 @@
import { createRouter, createWebHistory } from 'vue-router';
import { createRouter, createWebHashHistory } from 'vue-router';
import HomePage from '../components/HomePage.vue';
import LoginPage from '../components/LoginPage.vue';
import RegisterPage from '../components/RegisterPage.vue';
@@ -35,7 +35,7 @@ const routes = [
];
const router = createRouter({
history: createWebHistory(),
history: createWebHashHistory(), // 改为hash模式
routes
});
@@ -50,4 +50,4 @@ router.beforeEach((to, from, next) => {
}
});
export default router;
export default router;

View File

@@ -6,7 +6,7 @@ import router from '../router'
const instance = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL,
// 开发环境使用withCredentials生产环境关闭
withCredentials: import.meta.env.DEV,
// withCredentials: import.meta.env.DEV,
headers: {
'Content-Type': 'application/json'
}

View File

@@ -23,10 +23,12 @@ export default defineConfig(({ mode }) => {
}
},
build: {
outDir: 'dist',
assetsDir: 'assets',
minify: 'esbuild',
esbuild: {
drop: ['console', 'debugger'],
},
}
}
})
})

View File

@@ -28,5 +28,7 @@ services:
restart: unless-stopped
ports:
- "8084:8084"
environment:
TZ: "Asia/Shanghai" # 设置时区为上海时区
volumes:
- /docker/biji-houduan/data:/data

Binary file not shown.