- A+
所属分类:.NET技术
目前,关于java的面试相关的,网上可以说是多的数不胜数,但是关于.net的,找来找去却发现很少,并且大部分相似,所以,我这里便想做个关于.net面试相关的功能,所以就我花了好几个周末的时间,毛毛糙糙的算是把这个功能赶了出来,当然也有很多不完善的地方。欢迎大家赏脸哈!现在我把我的实现步骤贴出来分享一下。
因为一个人开发,个人精力以及能力有限,很多地方也会有不好的地方,所以希望大家多多包涵,如果感兴趣的话,可以点进去瞧瞧 https://www.xiandanplay.com/interview-manual
1.功能需求
大致罗列下需求:
- 题目分类管理
- 题目的发布,只要谁登录了网站都可以发布,默认是待审核的,网页只显示 已审核、待审核的功能
- 题目解析,发布者必须填写自己的对题目的解析,其他人也可以提交参考解析,并且展现出来
- 对题目解析的查看,如果第一次查看这个题目,需要点击“查看解析”的按钮,如果已登录并且查看过,则第二次就不需要点“查看解析”的按钮了。
- 支持对题目的标题、难度、标签的查询
2.表(实体)结构设计
这里我就用实体来表示了,因为我是用的ef,基本上用CodeFirst就是表结构了
1.题目表
public class Question : Entity<long> { /// <summary> /// 标题 /// </summary> public string Title { get; set; } /// <summary> /// 类型 /// </summary> public QuestionTypeEnum QuestionType { get; set; } /// <summary> /// 提交人id /// </summary> public long UserId { get; set; } /// <summary> /// 提交人 /// </summary> public User User { get; set; } /// <summary> /// 题目分类id /// </summary> public long? QuestionCategoryId { get; set; } /// <summary> /// 题目标签 /// </summary> public string QuestionTag { get; set; } /// <summary> /// 浏览数 /// </summary> public int BrowserCount { get; set; } /// <summary> /// 评论数 /// </summary> public int CommentCount { get; set; } /// <summary> /// 收藏数 /// </summary> public int CollectCount { get; set; } /// <summary> /// 奖励金币 /// </summary> public int RewardCoin { get; set; } /// <summary> /// 是否发布 /// </summary> public bool IsPublish { get; set; } /// <summary> /// 审核状态 /// </summary> public ApproveStatus ApproveStatus { get; set; } }
2.题目解析表
public class QuestionAnalysis : Entity<long> { /// <summary> /// 题目id /// </summary> public long InterviewQuestionId { get; set; } /// <summary> /// 解析简要 /// </summary> public string AnalysisContentDescription { get; set; } /// <summary> /// 题目解析 /// </summary> public string AnalysisContent { get; set; } /// <summary> /// 提交人id /// </summary> public long UserId { get; set; } /// <summary> /// 提交人 /// </summary> public User User { get; set; } /// <summary> /// 评论数 /// </summary> public int CommentCount { get; set; } /// <summary> /// 赞同数 /// </summary> public int AgreeCount { get; set; } /// <summary> /// 反对数 /// </summary> public int AgainstCount { get; set; } /// <summary> /// 是否最佳解析 /// </summary> public bool? Best { get; set; } /// <summary> /// 是否默认 /// </summary> public bool? IsDefault { get; set; } /// <summary> /// 收货金币 /// </summary> public int? GetCoin { get; set; } /// <summary> /// 审核状态 /// </summary> public ApproveStatus ApproveStatus { get; set; } }
3.题目分类表
public class InterviewQuestionCategory: Entity<long> { /// <summary> /// 分类名称 /// </summary> public string Name { get; set; } /// <summary> /// 图标 /// </summary> public string Icon { get; set; } /// <summary> /// 父分类id /// </summary> public long? ParentCategoryId { get; set; } /// <summary> /// 是否启用 /// </summary> public bool IsEnable { get; set; } /// <summary> /// 排序 /// </summary> public int SortNo { get; set; } /// <summary> /// 描述 /// </summary> public string Description { get; set; } }
大致就罗列这几个主要的吧。
4、业务逻辑实现
业务代码逻辑倒是没有特别复杂,都是写CRUD,一看就会,这里举例部分代码。
递归获取分类树
public async Task<List<TreeVM>> GetCategoryTreesAsync() { List<InterviewQuestionCategory> categorys = await GetCategorys(); return BuildTrees(categorys); } private List<TreeVM> BuildTrees(List<InterviewQuestionCategory> interviewQuestionCategories) { List<TreeVM> list = new List<TreeVM>(); var roots = interviewQuestionCategories.Where(s => !s.ParentCategoryId.HasValue).OrderBy(s => s.SortNo); foreach (var root in roots) { TreeVM interviewCategoryTreeVM = new TreeVM(); interviewCategoryTreeVM.Id = root.Id; interviewCategoryTreeVM.Label = root.Name; interviewCategoryTreeVM.Icon = root.Icon; GetChildrens(root, interviewQuestionCategories, interviewCategoryTreeVM); list.Add(interviewCategoryTreeVM); } return list; } private List<TreeVM> GetChildrens(InterviewQuestionCategory root, List<InterviewQuestionCategory> interviewQuestionCategories, TreeVM interviewCategoryTreeVM = null) { var childrens = interviewQuestionCategories.Where(s => s.ParentCategoryId == root.Id).OrderBy(s => s.SortNo); List<TreeVM> list = new List<TreeVM>(); foreach (var item in childrens) { TreeVM treeVM = new TreeVM(); treeVM.Id = item.Id; treeVM.Label = item.Name; treeVM.Icon = item.Icon; list.Add(treeVM); if (interviewQuestionCategories.Any(s => s.ParentCategoryId == item.Id)) GetChildrens(item, interviewQuestionCategories, treeVM); } interviewCategoryTreeVM.Children = list; return list; }
创建题目
public async Task<long> SaveQuestion(SaveInterviewQuestionVM saveInterviewQuestion) { if (saveInterviewQuestion.IsPublish && string.IsNullOrEmpty(saveInterviewQuestion.AnalysisContent)) throw new ValidationException("题目解析内容为空"); var questionRepository = unitOfWork.GetRepository<Question>(); var questionAnalysisRepository = unitOfWork.GetRepository<QuestionAnalysis>(); Question question = null; QuestionAnalysis questionAnalysis = null; bool isAddQuestion = true; bool isAddAnalysis = true; if (saveInterviewQuestion.Id.HasValue) { question = await questionRepository.SelectByIdAsync(saveInterviewQuestion.Id.Value); if (question.Id != CurrentLoginUser.UserId) throw new ValidationException("无权修改"); questionAnalysis = await questionAnalysisRepository.Select(s => s.InterviewQuestionId == saveInterviewQuestion.Id.Value && s.IsDefault == true).FirstOrDefaultAsync(); isAddQuestion = false; } else { question = new Question() { Id = CreateEntityId() }; } question.Title = saveInterviewQuestion.Title; question.QuestionDifficulty = saveInterviewQuestion.Difficultion; question.QuestionCategoryId = saveInterviewQuestion.CategoryId; question.UserId = LoginUserId.Value; question.ApproveStatus = ApproveStatus.ToPass; question.IsPublish = saveInterviewQuestion.IsPublish; question.QuestionType = QuestionTypeEnum.面试题; if (saveInterviewQuestion.QuestionTags != null && saveInterviewQuestion.QuestionTags.Length > 0) question.QuestionTag = string.Join(',', saveInterviewQuestion.QuestionTags); if (questionAnalysis == null) { questionAnalysis = new QuestionAnalysis(); questionAnalysis.Id = CreateEntityId(); questionAnalysis.IsDefault = true; questionAnalysis.InterviewQuestionId = question.Id; questionAnalysis.UserId = LoginUserId.Value; questionAnalysis.ApproveStatus = ApproveStatus.ToPass; questionAnalysis.AnalysisContent = saveInterviewQuestion.AnalysisContent; } else { questionAnalysis.AnalysisContent = saveInterviewQuestion.AnalysisContent; isAddAnalysis = false; } if (isAddQuestion) await questionRepository.InsertAsync(question); else await questionRepository.UpdateAsync(question); if (isAddAnalysis) await questionAnalysisRepository.InsertAsync(questionAnalysis); else await questionAnalysisRepository.UpdateAsync(questionAnalysis); await unitOfWork.CommitAsync(); return question.Id; }
使用Redis的Set类型处理赞成与反对操作
public async Task<bool> AgreeFunc(InterviewQuestionAnalysisAgreeVM agreeVM) { var cache = CacheClient.CreateClient(); string cacheKey = $"{CacheKey.InterviewQuestionAnalysisAgreeKey}_{agreeVM.InterviewQuestionAnalysisId}"; string cacheValue = $"{agreeVM.AgreeType}_{agreeVM.InterviewQuestionAnalysisId}_{LoginUserId.Value}"; if (agreeVM.AgreeType == 1) { string oldCacheValue = $"2_{agreeVM.InterviewQuestionAnalysisId}_{LoginUserId.Value}"; cache.SetRemove(cacheKey, oldCacheValue); } else { string oldCacheValue = $"1_{agreeVM.InterviewQuestionAnalysisId}_{LoginUserId.Value}"; cache.SetRemove(cacheKey, oldCacheValue); } bool result = cache.AddSet(cacheKey, cacheValue); if (result) { List<string> setMembers= cache.GetMembersBySetKey(cacheKey); int agreeCount = 0; int againstCount = 0; foreach (var item in setMembers) { if (item.StartsWith('1')) agreeCount += 1; else againstCount += 1; } await qaRepository.UpdateAgree(agreeVM.InterviewQuestionAnalysisId, agreeCount, againstCount); await unitOfWork.CommitAsync(); return true; } return false; }
以上只是部分代码,仅供一下参考,但是也花费了我好多个周末的时间,其它的就不说了,放几个截图看看吧,部分的功能还没完善,这个只是初版。
面试宝典首页图(每日推荐那里还没完成)
详细的面试列表界面
查看页面
提交参考解析的页面
作者:程序员奶牛
个人主页:https://www.xiandanplay.com/user/user-home?id=16782377660907520