refactor(user): 重构用户相关代码

- 更新导入路径,使用 .js 后缀
-修正用户模型中的密码加密和验证逻辑
- 优化用户路由和控制器
- 重构用户服务和仓库,使用原生 mongoose 方法- 更新错误处理和日志记录
This commit is contained in:
LingandRX 2025-01-05 18:28:06 +08:00
parent e6adea5f52
commit 039317d229
10 changed files with 94 additions and 91 deletions

36
app.js
View File

@ -1,35 +1,20 @@
import createError from 'http-errors'
import express from 'express'
import path from 'path'
import logger from 'morgan'
import cors from 'cors'
import session from 'express-session'
import { RedisStore } from 'connect-redis'
import Redis from 'ioredis'
import { fileURLToPath } from 'url'
import cookieParser from 'cookie-parser'
import indexRouter from './routes/index'
import userRouter from './routes/userRouter'
import accountRouter from './routes/accountRouter'
import indexRouter from './routes/index.js'
import userRouter from './routes/userRouter.js'
import accountRouter from './routes/accountRouter.js'
import { config } from 'dotenv'
// mongodb数据库连接
import { connectMongoDB } from './config/mongodbConfig'
import { HTTP_STATUS } from './common/constant/httpStatus'
import loginUtil from './utils/loginUtil'
import { connectMongoDB } from './config/mongodbConfig.js'
import { HTTP_STATUS } from './common/constant/httpStatus.js'
import { authenticateSession } from './utils/loginUtil.js'
config()
// 初始化 Redis 客户端
@ -42,6 +27,9 @@ const redisClient = new Redis({
const app = express()
const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
app.use(logger('dev'))
app.use(express.json())
app.use(express.urlencoded({ extended: false }))
@ -81,7 +69,7 @@ async function startServer() {
startServer().then((r) => logger(r))
app.use('/', indexRouter)
app.use('/user', loginUtil.authenticateSession, userRouter)
app.use('/user', authenticateSession, userRouter)
app.use('/account', accountRouter)
// catch 404 and forward to error handler
@ -105,4 +93,4 @@ app.use(function (err, req, res) {
})
})
module.exports = app
export default app

View File

@ -3,9 +3,9 @@
/**
* Module dependencies.
*/
const app = require('../app')
const debug = require('debug')('express:server')
const http = require('http')
import app from '../app.js'
import debug from 'debug'
import http from 'http'
/**
* Get port from environment and store in Express.

View File

@ -1,12 +1,12 @@
import { body, validationResult } from 'express-validator'
import logger from 'morgan'
import userService from '../services/userService'
import FetchResult from '../common/web/fetchResult'
import messages from '../config/messages'
import { HTTP_STATUS } from '../common/constant/httpStatus'
import { SearchQuery } from '../models/search'
import userService from '../services/userService.js'
import FetchResult from '../common/web/fetchResult.js'
import messages from '../config/messages.js'
import { HTTP_STATUS } from '../common/constant/httpStatus.js'
import { SearchQuery } from '../models/search.js'
export default UserController = {
const UserController = {
async getAllUsers(res) {
try {
const users = await userService.getUserList()
@ -128,3 +128,5 @@ export default UserController = {
}
}
}
export default UserController

View File

@ -1,5 +1,5 @@
import { Schema as _Schema, model } from 'mongoose'
import { hashPassword } from '../utils/hashUtils'
import { hashPassword } from '../utils/hashUtils.js'
const Schema = _Schema
const UserSchema = new Schema({
@ -7,12 +7,12 @@ const UserSchema = new Schema({
gender: { type: String, enum: ['male', 'female', 'other'], maxlength: 20 },
birth: { type: Date },
avatar: { type: String, maxlength: 100 },
account: { type: String, required: true, unique: true, maxlength: 100, index: true },
account: { type: String, required: true, unique: true, maxlength: 100 },
password: { type: String, required: true, maxlength: 100 },
email: { type: String, maxlength: 255, index: true },
phone: { type: String, maxlength: 11 },
email: { type: String, match: /^\S+@\S+\.\S+$/, maxlength: 255, index: true },
phone: { type: String, match: /^1[3-9]\d{9}$/, maxlength: 11 },
registerDate: { type: Date, default: Date.now },
lastLoginDate: { type: Date, default: Date.now },
lastLoginDate: { type: Date },
status: { type: String, enum: ['active', 'inactive', 'pending'], default: 'pending' }
})
@ -20,13 +20,18 @@ UserSchema.pre('save', async function (next) {
const user = this
if (!user.isModified('password')) return next()
try {
console.log(user.password)
user.password = await hashPassword(user.password)
next()
} catch (error) {
next(error)
// 记录错误日志,避免泄露敏感信息
console.error('Error hashing password:', error.message)
next(new Error('Failed to hash password'))
}
})
// 更新 lastLoginDate 在用户登录时
UserSchema.methods.updateLastLoginDate = function () {
this.lastLoginDate = new Date()
}
export default model('User', UserSchema)

View File

@ -1,19 +1,27 @@
import {
startSession,
find,
aggregate,
findById,
findOne,
exists,
create,
findByIdAndUpdate,
findByIdAndDelete,
deleteMany
} from '../models/userModel'
import { SearchResult } from '../models/search'
import User from '../models/userModel.js'
import { SearchResult } from '../models/search.js'
const userRepository = {
startTransaction,
commitTransaction,
rollbackTransaction,
selectAllUser,
selectUserList,
selectUserById,
selectUserByAccount,
selectUserByEmail,
selectUserByUsername,
selectUserByPhone,
selectUserByAccountExist,
createUser,
updateUserById,
updateUserByLoginDate,
deleteUserById,
deleteAllUser
}
export async function startTransaction() {
const session = await startSession()
const session = await User.startSession()
session.startTransaction()
return session
}
@ -27,7 +35,7 @@ export async function rollbackTransaction(session) {
}
export async function selectAllUser() {
return find()
return User.find()
}
export async function selectUserList(search = {}) {
@ -43,7 +51,7 @@ export async function selectUserList(search = {}) {
const matchFilters = filters ? { ...filters } : {}
const sortObj = sort && typeof sort === 'object' ? sort : { _id: 1 } // 默认按 _id 升序排序
const result = await aggregate([
const result = await User.aggregate([
// 应用过滤条件确保filters存在时才传入
{ $match: matchFilters },
{
@ -69,46 +77,48 @@ export async function selectUserList(search = {}) {
}
export async function selectUserById(id) {
return findById(id)
return User.findById(id)
}
export async function selectUserByAccount(account) {
return findOne({ account: account })
return User.findOne({ account: account })
}
export async function selectUserByEmail(email) {
return findOne({ email: email })
return User.findOne({ email: email })
}
export async function selectUserByUsername(username) {
return findOne({ username: username })
return User.findOne({ username: username })
}
export async function selectUserByPhone(phone) {
return findOne({ phone: phone })
return User.findOne({ phone: phone })
}
export async function selectUserByAccountExist(account) {
const exist = await exists({ account: account })
const exist = await User.exists({ account: account })
return exist !== null
}
export async function createUser(user) {
return create(user)
return User.create(user)
}
export async function updateUserById(id, user) {
return findByIdAndUpdate(id, user)
return User.findByIdAndUpdate(id, user)
}
export async function updateUserByLoginDate(id, loginDate) {
return findByIdAndUpdate(id, { last_login_date: loginDate })
return User.findByIdAndUpdate(id, { lastLoginDate: loginDate })
}
export async function deleteUserById(id) {
return findByIdAndDelete(id)
return User.findByIdAndDelete(id)
}
export async function deleteAllUser() {
return deleteMany()
return User.deleteMany()
}
export default userRepository

View File

@ -1,9 +1,9 @@
// routes/userRoutes.js
import express from 'express'
const userController = import('../controllers/userController')
import userController from '../controllers/userController.js'
const router = express.Router()
router.get('/', getUserExists)
router.get('/', userController.getUserExists)
export default router

View File

@ -1,6 +1,6 @@
import express from 'express'
import userController from '../controllers/userController'
import userController from '../controllers/userController.js'
const router = express.Router()
router.get('/', function (req, res) {

View File

@ -1,7 +1,5 @@
// routes/userRoutes.js
import userController from '../controllers/userController'
import express from 'express'
import userController from '../controllers/userController.js'
const router = express.Router()

View File

@ -1,9 +1,9 @@
import userMapper from '../repositories/userRepository'
import userRepository from '../repositories/userRepository.js'
import logger from 'morgan'
import messages from '../config/messages'
import { comparePassword } from '../utils/hashUtils'
import messages from '../config/messages.js'
import { comparePassword } from '../utils/hashUtils.js'
export default userServeice = {
const userService = {
/**
* 用户登录
* @param {string} account - 用户账号
@ -12,7 +12,7 @@ export default userServeice = {
* @throws {Error} - 如果用户不存在或密码不正确
*/
async login(account, password) {
const user = await userMapper.selectUserByAccount(account)
const user = await userRepository.selectUserByAccount(account)
// 用户不存在
if (!user) {
@ -27,7 +27,7 @@ export default userServeice = {
// 更新用户的最后登录时间
user.lastLoginDate = new Date()
await userMapper.updateUserByLoginDate(user.id, user.lastLoginDate)
await userRepository.updateUserByLoginDate(user.id, user.lastLoginDate)
return user
},
@ -38,16 +38,16 @@ export default userServeice = {
* @returns {Promise<boolean>}
*/
async getUserExists(account) {
return userMapper.selectUserByAccountExist(account)
return userRepository.selectUserByAccountExist(account)
},
// Removed the unnecessary try-catch block and simplified the function
async getAllUser() {
return await userMapper.selectAllUser()
return await userRepository.selectAllUser()
},
async getUserList(searchQuery) {
return userMapper.selectUserList(searchQuery)
return userRepository.selectUserList(searchQuery)
},
/**
@ -58,27 +58,29 @@ export default userServeice = {
*/
async createUser(user) {
const { account } = user
const session = await userMapper.startTransaction()
const session = await userRepository.startTransaction()
try {
// 检查用户是否已存在
const existingUser = await userMapper.selectUserByAccount(account)
const existingUser = await userRepository.selectUserByAccount(account)
if (existingUser) {
return new Error(messages.user.alreadyExists)
}
// 创建新用户
const result = await userMapper.createUser(user)
const result = await userRepository.createUser(user)
// 提交事务
await userMapper.commitTransaction(session)
await userRepository.commitTransaction(session)
return result
} catch (err) {
// 回滚事务
await userMapper.rollbackTransaction(session).catch((rollbackErr) => {
await userRepository.rollbackTransaction(session).catch((rollbackErr) => {
logger('Error rolling back transaction: ', rollbackErr)
})
throw err // 将错误抛给调用方Controller 层)
}
}
}
export default userService

View File

@ -5,7 +5,7 @@ import bcrypt from 'bcrypt'
* @param {string} password 密码
* @returns password 加密后的密码
*/
async function hashPassword(password) {
export async function hashPassword(password) {
return bcrypt.hash(password, 10)
}
@ -18,5 +18,3 @@ async function hashPassword(password) {
export async function comparePassword(password, hashedPassword) {
return bcrypt.compare(password, hashedPassword)
}
export default { hashPassword, comparePassword }