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 createError from 'http-errors'
import express from 'express' import express from 'express'
import path from 'path' import path from 'path'
import logger from 'morgan' import logger from 'morgan'
import cors from 'cors' import cors from 'cors'
import session from 'express-session' import session from 'express-session'
import { RedisStore } from 'connect-redis' import { RedisStore } from 'connect-redis'
import Redis from 'ioredis' import Redis from 'ioredis'
import { fileURLToPath } from 'url'
import cookieParser from 'cookie-parser' import cookieParser from 'cookie-parser'
import indexRouter from './routes/index.js'
import indexRouter from './routes/index' import userRouter from './routes/userRouter.js'
import accountRouter from './routes/accountRouter.js'
import userRouter from './routes/userRouter'
import accountRouter from './routes/accountRouter'
import { config } from 'dotenv' import { config } from 'dotenv'
import { connectMongoDB } from './config/mongodbConfig.js'
// mongodb数据库连接 import { HTTP_STATUS } from './common/constant/httpStatus.js'
import { connectMongoDB } from './config/mongodbConfig' import { authenticateSession } from './utils/loginUtil.js'
import { HTTP_STATUS } from './common/constant/httpStatus'
import loginUtil from './utils/loginUtil'
config() config()
// 初始化 Redis 客户端 // 初始化 Redis 客户端
@ -42,6 +27,9 @@ const redisClient = new Redis({
const app = express() const app = express()
const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
app.use(logger('dev')) app.use(logger('dev'))
app.use(express.json()) app.use(express.json())
app.use(express.urlencoded({ extended: false })) app.use(express.urlencoded({ extended: false }))
@ -81,7 +69,7 @@ async function startServer() {
startServer().then((r) => logger(r)) startServer().then((r) => logger(r))
app.use('/', indexRouter) app.use('/', indexRouter)
app.use('/user', loginUtil.authenticateSession, userRouter) app.use('/user', authenticateSession, userRouter)
app.use('/account', accountRouter) app.use('/account', accountRouter)
// catch 404 and forward to error handler // 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. * Module dependencies.
*/ */
const app = require('../app') import app from '../app.js'
const debug = require('debug')('express:server') import debug from 'debug'
const http = require('http') import http from 'http'
/** /**
* Get port from environment and store in Express. * Get port from environment and store in Express.

View File

@ -1,12 +1,12 @@
import { body, validationResult } from 'express-validator' import { body, validationResult } from 'express-validator'
import logger from 'morgan' import logger from 'morgan'
import userService from '../services/userService' import userService from '../services/userService.js'
import FetchResult from '../common/web/fetchResult' import FetchResult from '../common/web/fetchResult.js'
import messages from '../config/messages' import messages from '../config/messages.js'
import { HTTP_STATUS } from '../common/constant/httpStatus' import { HTTP_STATUS } from '../common/constant/httpStatus.js'
import { SearchQuery } from '../models/search' import { SearchQuery } from '../models/search.js'
export default UserController = { const UserController = {
async getAllUsers(res) { async getAllUsers(res) {
try { try {
const users = await userService.getUserList() 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 { Schema as _Schema, model } from 'mongoose'
import { hashPassword } from '../utils/hashUtils' import { hashPassword } from '../utils/hashUtils.js'
const Schema = _Schema const Schema = _Schema
const UserSchema = new Schema({ const UserSchema = new Schema({
@ -7,12 +7,12 @@ const UserSchema = new Schema({
gender: { type: String, enum: ['male', 'female', 'other'], maxlength: 20 }, gender: { type: String, enum: ['male', 'female', 'other'], maxlength: 20 },
birth: { type: Date }, birth: { type: Date },
avatar: { type: String, maxlength: 100 }, 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 }, password: { type: String, required: true, maxlength: 100 },
email: { type: String, maxlength: 255, index: true }, email: { type: String, match: /^\S+@\S+\.\S+$/, maxlength: 255, index: true },
phone: { type: String, maxlength: 11 }, phone: { type: String, match: /^1[3-9]\d{9}$/, maxlength: 11 },
registerDate: { type: Date, default: Date.now }, registerDate: { type: Date, default: Date.now },
lastLoginDate: { type: Date, default: Date.now }, lastLoginDate: { type: Date },
status: { type: String, enum: ['active', 'inactive', 'pending'], default: 'pending' } status: { type: String, enum: ['active', 'inactive', 'pending'], default: 'pending' }
}) })
@ -20,13 +20,18 @@ UserSchema.pre('save', async function (next) {
const user = this const user = this
if (!user.isModified('password')) return next() if (!user.isModified('password')) return next()
try { try {
console.log(user.password)
user.password = await hashPassword(user.password) user.password = await hashPassword(user.password)
next() next()
} catch (error) { } 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) export default model('User', UserSchema)

View File

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

View File

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

View File

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

View File

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

View File

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