仿牛客社区项目描述
本项目是一个校内互动交流平台,主要涉及模块有权限模块、帖子模块、性能模块、通知模块、搜索模块。主要使用的技术有SpringBoot,SpringMVC,MyBatis,MySQL,Redis,Kafka。
权限模块主要实现了注册登录和权限管理等功能。
帖子模块主要实现了发帖,评论和私信等功能。
性能模块使用Redis实现点赞,关注和网站数据统计等功能。
通知模块使用Kafka实现系统通知功能。
搜索模块使用Elasticsearch实现帖子搜索功能
输入账户,密码,确认密码,邮箱,点击注册按钮。根据 /register(post)传入User。调用 userService.register 方法。
userService.register 方法首先根据用户名和邮箱查询数据库看是否已经存在,如果存在,返回错误信息。如果不存在,对User加入 Salt 属性,即五位随机字符串,为了和密码拼接后进行md5加密。将加密后的密码存入数据库。分别设置Type,Status为0(Type 0普通用户 1管理员 2版主;Status 0未激活 1已激活)。设置随机字符串激活码。设置用户头像和创建时间。将User插入数据库。
使用JavaMailSender发送激活邮件。将可能带有错误信息的Map返回。
LoginController 层得到 Map 判断是否为空,为空则注册成功,返回 /site/operate-result 页面。否则返回 /site/register 页面,并将错误信息加入model中。
在邮箱中点击激活链接,调用LoginController层的 /activation/{userId}/{code} 。调用userService.activation(userId, code)方法。首先判断 User 中的status是否已经等于1,已经等于1返回 重复激活 信息。然后判断 User 中的激活码是否与code相等,等则设置status为1,返回激活成功。不等返回激活失败。
首先在首页点击登录或者在其他页面转入登录页面时,验证码路径访问 “/kaptcha” 。
在 LoginController 层中根据 KaptchaConfig 配置类中的 kaptchaProducer (google提供)来生成验证码文本和图像, 生成随机字符串作为Redis中验证码的key,将key放在cookie中通过response传给浏览器。然后利用key将验证码文本存入Redis,设置失效时间为60s。为了判断用户在登录时传入的code是否等于该文本。
再通过response将图像返回给浏览器。
在登录页面输入用户名,密码,验证码和是否勾选“记住我”。将对应的username,password,code,rememberme通过 “/login” 传入 login 方法。
Llogin方法在参数中使用 @CookieValue 注解从cookie中取出Redis中验证码文本的key,判断一下key是否为空,不为空则取出Redis中的验证码文本判断是否和code相等,不等返回Map。然后根据remember选取登录凭证超时时间。然后将username,password 和超时时间 传入给userService.login 方法。
userService.login 方法拿到 三个值先判空,空则返回Map。然后根据username查询数据库看账号是否存在。然后查询status看账户是否已经激活。最后验证密码(调取salt和password拼接后使用md5加密再和数据库中密码比对)。然后生成登录凭证,见LoginTicket,将登陆凭证放入Redis,key为随机字符串Ticket字段。将凭证的key放入Map并返回给 LoginController 层。
LoginController 层拿到Map。查看其中是否有凭证的key,有将凭证的key放入cookie,设置过期时间,返回给浏览器,重定向转入index。无则将Map中报错信息加入model,转入login。
使用 Ajax 在 index 页面发送异步请求(局部刷新)。在 Controller 层返回 Json 数据显示。
附加:当点击某个帖子时,进入详情页面。该页面首先将帖子信息返回显示,然后将该帖子评论查库返回,同时将评论的评论也返回。因为某个用户可以对帖子进行评论,也可以对评论进行评论,反映在评论表中就是entity_type字段不同,1是帖子,2是评论。
添加评论有三种方式:① 回帖,② 回复评论,③ 回复某人的评论。
分为两部分:
一、① 在消息页面发私信 ,② 在与某人会话中给TA发私信。
二、将未读消息转为已读。(其实应该放置在 1.6 私信列表 )
前提:在 util 的 RedisKeyUtil 工具类中写 getEntityLikeKey 方法,传入 entityType, entityId 返回某个实体(帖子或回复)的赞的key值 。
分为两种:① 给帖子点赞 ② 给回复点赞。
注: 另外在 HomeController 层中 /index 映射的方法中,增加向浏览器返回帖子赞的数量的功能。在 DiscussPostController 层中 /detail/{discussPostId} 映射的方法中,增加向浏览器返回帖子和回复列表的赞数量和状态的功能。
前提:在 util 的 RedisKeyUtil 工具类中写 getFolloweeKey 和 getFollowerKey 方法,返回某个用户关注的实体的key和某个实体拥有的粉丝的key。
使用的Redis数据结构:

UV统计用户数量(包括不登录用户),DAU统计登录用户数量。

首先UV和DAU通过Redis存储。根据今日日期定义单日UV和单日DAU的key,类似于 uv:20220516。通过起始日期和终止日期定义区间UV和区间DAU的key,类似于 uv:20220516:20220517。
private String topic; // 存放消息空间
private int userId; // 触发事件用户id
private int entityType; // 事件目标类型
private int entityId; // 事件目标id
private int entityUserId ;// 事件目标所有者id
private Map<String, Object> data = new HashMap<>(); // 其他
@Component
public class EventProducer {
@Autowired
private KafkaTemplate kafkaTemplate;
// 处理事件
public void fireEvent(Event event) {
// 将事件发布到指定的主题
kafkaTemplate.send(event.getTopic(), JSONObject.toJSONString(event));
}
}
@Component
public class EventConsumer implements CommunityConstant {
private static final Logger logger = LoggerFactory.getLogger(EventConsumer.class);
@Autowired
private MessageService messageService;
@KafkaListener(topics = {TOPIC_COMMENT, TOPIC_LIKE, TOPIC_FOLLOW})
public void handleCommentMessage(ConsumerRecord record) {
if (record == null || record.value() == null) {
logger.error("消息的内容为空!");
return;
}
Event event = JSONObject.parseObject(record.value().toString(), Event.class);
if (event == null) {
logger.error("消息格式错误!");
return;
}
// 发送站内通知
Message message = new Message();
// 系统发送 设为 1
message.setFromId(SYSTEM_USER_ID);
message.setToId(event.getEntityUserId());
// ConversationId 设为 topic。
message.setConversationId(event.getTopic());
message.setCreateTime(new Date());
// message 的 content
Map<String, Object> content = new HashMap<>();
content.put("userId", event.getUserId());
content.put("entityType", event.getEntityType());
content.put("entityId", event.getEntityId());
if (!event.getData().isEmpty()) {
for (Map.Entry<String, Object> entry : event.getData().entrySet()) {
content.put(entry.getKey(), entry.getValue());
}
}
// 保存为 json 字符串
message.setContent(JSONObject.toJSONString(content));
messageService.addMessage(message);
}
}
最后使用 MessageInterceptor 拦截器查询出私信未读数量和系统通知未读数量,将其加和放入modelAndView,在顶部栏的消息上显示总的未读数量。
发布帖子,增加评论时要将帖子异步提交到 Elasticsearch 服务器。利用kafka实现。
如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby
我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘
我已经像这样安装了一个新的Rails项目:$railsnewsite它执行并到达:bundleinstall但是当它似乎尝试安装依赖项时我得到了这个错误Gem::Ext::BuildError:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcheckingforlibkern/OSAtomic.h...yescreatingMakefilemake"DESTDIR="cleanmake"DESTDIR="
假设我有这个范围:("aaaaa".."zzzzz")如何在不事先/每次生成整个项目的情况下从范围中获取第N个项目? 最佳答案 一种快速简便的方法:("aaaaa".."zzzzz").first(42).last#==>"aaabp"如果出于某种原因你不得不一遍又一遍地这样做,或者如果你需要避免为前N个元素构建中间数组,你可以这样写:moduleEnumerabledefskip(n)returnto_enum:skip,nunlessblock_given?each_with_indexdo|item,index|yieldit
1.在Python3中,下列关于数学运算结果正确的是:(B)a=10b=3print(a//b)print(a%b)print(a/b)A.3,3,3.3333...B.3,1,3.3333...C.3.3333...,3.3333...,3D.3.3333...,1,3.3333...解析: 在Python中,//表示地板除(向下取整),%表示取余,/表示除(Python2向下取整返回3)2.如下程序Python2会打印多少个数:(D)k=1000whilek>1: print(k)k=k/2A.1000 B.10C.11D.9解析: 按照题意每次循环K/2,直到K值小于等
我正在尝试创建一个带有项目符号字符的Ruby1.9.3字符串。str="•"+"helloworld"但是,当我输入它时,我收到有关非ASCII字符的语法错误。我该怎么做? 最佳答案 你可以把Unicode字符放在那里。str="\u2022"+"helloworld" 关于ruby-如何在Ruby字符串中插入项目符号字符?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/1195
我的Rails站点使用了一个确实不是很好的gem。每次我需要做一些新的事情时,我最终不得不花费与向实际Rails项目添加代码一样多的时间来为gem添加功能。但我不介意,我将我的Gemfile设置为指向我的gem的GitHub分支(我尝试提交PR,但维护者似乎已经下台)。问题是我真的没有找到一种合理的方法来测试我添加到gem的新东西。在railsc中测试它会特别好,但我能想到的唯一方法是a)更改~/.rvm/gems/.../foo。rb,这看起来不对或者b)升级版本,推送到Github,然后运行bundleup,这除了耗时之外显然是一场灾难,因为我不确定我所做的promise是否正
随着ruby被引入为新的编程救世主,我想知道是否有人基于易用性、运行所需的资源、可用性和易定制性而有偏好。两者有更好的吗? 最佳答案 好吧,任何基于Rails的社交网络应用程序的比较都应该包括insoshi(http://portal.insoshi.com/)。话虽这么说,这三个都非常相似,区别在于实现细节。Lovd和Insoshi都是完整的Rails应用程序;它旨在供您将它们用作入门工具包,并使用您自己的自定义功能对其进行扩展。另一方面,CommunityEngine是一个Rails插件。这意味着您可以更轻松地向现有Rail
我一直在尝试使用nanoc用于生成静态网站。我需要组织一个复杂的排列页面,我想让我的内容保持干燥。包含或合并的概念在nanoc系统中如何运作?我已阅读文档,但似乎找不到我想要的内容。例如:我如何获取两个部分内容项并将它们合并到一个新的内容项中。在staticmatic您可以在您的页面中执行以下操作。=partial('partials/shared/navigation')类似的约定在nanoc中如何运作? 最佳答案 这里是nanoc的作者。在nanoc中,部分是布局。因此,您可以拥有layouts/partials/shared/
我安装了ruby、yeoman,当我运行我的项目时,出现了这个错误:Warning:Running"compass:dist"(compass)taskWarning:YouneedtohaveRubyandCompassinstalledthistasktowork.Moreinfo:https://github.com/gruUse--forcetocontinue.Use--forcetocontinue.我有进入可变session目标的路径,但它不起作用。谁能帮帮我? 最佳答案 我必须运行这个:geminstallcom