solitaryclown

在线论坛

2022-05-07
solitaryclown

1. 在线论坛

1.1. 搭建项目环境

1.2. 开发登录功能

  1. 发送邮件
    1. 引入spring-boot-starter-mail
    2. 邮箱参数配置
    3. 编写发送邮件的工具类
  2. 注册
    1. 浏览器发送表单
    2. 服务器接受请求,调用service注册
    3. 响应注册结果
  3. 登录
    • 引入Kaptcha依赖,生成随机验证码 ```java @Configuration public class KaptchaConfig {

      @Bean public Producer kaptchaProducer() { DefaultKaptcha kaptcha = new DefaultKaptcha(); Properties properties = new Properties(); properties.setProperty(“kaptcha.image.width”, “100”); properties.setProperty(“kaptcha.image.high”, “40”); properties.setProperty(“kaptcha.textproducer.font.size”, “32”); properties.setProperty(“kaptcha.textproducer.font.color”, “0,0,0”); properties.setProperty(“kaptcha.textproducer.char.string”, “0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ”); //验证码长度 properties.setProperty(“kaptcha.textproducer.char.length”, “4”);

         //噪声类
         properties.setProperty("kaptcha.noise.impl", "com.google.code.kaptcha.impl.NoNoise");
              
         Config config = new Config(properties);
         kaptcha.setConfig(config);
         return kaptcha;
      

      } }

    - 编写验证码接口
     ```java
     @RequestMapping(path="/kaptcha",method = RequestMethod.GET)
     public void getKaptcha(HttpServletResponse response,HttpSession session) throws IOException {
         String code = kaptchaProducer.createText();
         BufferedImage codeImage = kaptchaProducer.createImage(code);
         //将验证码存入session
         session.setAttribute("kaptcha",code);
    		
         response.setContentType("image/png");
         ServletOutputStream outputStream = response.getOutputStream();
    		
         ImageIO.write(codeImage, "png", outputStream);
     }
    

1.3. 发布帖子

  1. 对标题和帖子内容做过滤,包括:
    1. html元素(利用spring.web提供的HtmlUtils)
    2. js脚本
    3. 敏感词汇

1.4. 显示评论、发布评论

1.5. 显示私信、发送私信

私信数据直接用MySQL进行存储,表结构如下: OawhJU.png

示例数据如下: Oa0iwt.png

说明:conversation_id由from_id和to_id拼接而成,且大的id在前,小的在后面,保证两个用户在同一个会话中。

1.5.1. 发送私信

  1. 使用ajax发送请求,请求响应后刷新私信列表
  2. 当访问私信详情时,将私信状态改为已读

1.5.2. 删除私信

让消息框元素带上消息id,当点击消息元素的close类的元素时获取消息id,发送post请求删除消息 js的代码如下:

function delete_msg() {

	//3.元素移除
	var e=$(this).parents(".media");
	if (confirm('您确定要删除这条消息吗?')) {
		//1.获取要删除的消息的id
		var deleteId = $(this).parents(".media").attr('id');
		console.log('要删除的消息id是:' + deleteId);

		//2.发送删除消息请求
		$.post(
			'/message/delete',
			{
				"messageId": deleteId
			},
			function (response) {
				if (response.code == 0) {
					alert('删除消息成功!');
					e.remove();
					console.log('删除消息成功');
				} else {
					alert('删除消息失败!' + response.msg);

				}
			}
		)
	
	}
}

1.6. 统一处理异常

  1. 使用BasicErrorController处理404异常

  2. 使用@ControllerAdivce+@ExceptionHandler处理500异常

1.7. 点赞

使用Redis存储点赞数据 主要存储的点赞数据有两类:

  1. 帖子或评论的点赞,以set方式存储,集合存储点赞的用户id,格式为 例如like:entity:0:10=[101,104,83]代表ID为10的帖子被ID为101、104、83的用户点赞 例如like:entity:1:33=[102,105,100]代表ID为33的评论被ID为102、105、100的用户点赞
  2. 用户的获赞数,直接用key-value存储,key的形式为like:user:{userid}=count

1.8. 关注与粉丝

需求:

  1. 关注、取消关注功能
  2. 统计用户的关注数和粉丝数
  3. 显示用户的粉丝列表和关注列表

实现:
跟点赞功能一样,粉丝数据和关注数据使用Redis存储,key的形式:

  1. 实体的粉丝 粉丝key格式:
    follower:{entityType}:{entityId}={userId=xxx,score=xxx}
  2. 用户的关注 followee:{userid}:{entityType}={entityId=xxx,score=xxx}

1.9. 优化登录模块

  1. 使用redis存储验证码

  2. 使用redis存储登录凭证

  3. 使用redis缓存用户信息 对于UserService.findUserById(),先从redis缓存查询,如果没有,初始化缓存,将user存入,如果user更新了信息,需要清除缓存。

1.10. 系统通知(使用Kafka)

1.10.1. Kafka

  1. 下载Kafka
  2. 启动zookeeper:./zookeeper-server-start.sh -daemon ../config/zookeeper.properties zookeeper默认端口:2181
  3. 启动Kafka:./kafka-server-start.sh -daemon ../config/server.properties Kafka默认端口:9092

    1.10.2. 功能

    • 需求 当用户被点赞、关注、评论时,系统发送通知消息(通知和处理通知是异步方式)。
  • 实现
    • 后台
      1. 安装Kafka服务器
      2. 创建Kafka消费者和Kafka生产者
      3. 在触发点赞、关注、评论行为时,生产者向事件服务器发送事件,事件封装了通知相关的信息。 消费者消费事件,具体就是向数据库插入消息记录。

      4. 用户在登录时查询相关系统消息并显示。
    • 前台
      1. 通知列表:显示评论、点赞、关注三种类型的通知
      2. 通知详情:分页显示某一类主题所包含的通知
      3. 未读消息:在页面头部显示所有的未读消息数量

1.11. 搜索功能

需求:实现论坛搜索功能

  1. 安装elasticsearch
    1. 下载解压
    2. 修改配置(注意需要登录到非root用户)
      • [用户名@centos-elk ~]$ sudo vi /etc/security/limits.conf #添加以下内容 用户名 hard nofile 65536 用户名 soft nofile 65536 重新登录
      • 配置文件elastisearch.yml样本 ```yml # ======================== Elasticsearch Configuration ========================= # # NOTE: Elasticsearch comes with reasonable defaults for most settings. # Before you set out to tweak and tune the configuration, make sure you # understand what are you trying to accomplish and the consequences. # # The primary way of configuring a node is via this file. This template lists # the most important settings you may want to configure for a production cluster. # # Please consult the documentation for further information on configuration options: # https://www.elastic.co/guide/en/elasticsearch/reference/index.html # # ———————————- Cluster ———————————– # # Use a descriptive name for yourcluster: # cluster.name: nowcoder # # ———————————— Node ———————————— # # Use a descriptive name for the node: # #node.name: node-1 # # Add custom attributes to the node: # #node.attr.rack: r1 # # ———————————– Paths ———————————— # # Path to directory where to store the data (separate multiple locations by comma): #data目录 path.data: /usr/local/elasticsearch-7.12.1/data # # Path to log files: #日志文件路径 path.logs: /usr/local/elasticsearch-7.12.1/logs # # ———————————– Memory ———————————– # # Lock the memory on startup: # #bootstrap.memory_lock: true # # Make sure that the heap size is set to about half the memory available # on the system and that the owner of the process is allowed to use this # limit. # # Elasticsearch performs poorly when the system is swapping the memory. # # ———————————- Network ———————————– # # By default Elasticsearch is only accessible on localhost. Set a different # address here to expose this node on the network: # network.host: 0.0.0.0 # # By default Elasticsearch listens for HTTP traffic on the first free port it # finds starting at 9200. Set a specific HTTP port here: # http.port: 9200 # # For more information, consult the network module documentation. # # ——————————— Discovery ———————————- # # Pass an initial list of hosts to perform discovery when this node is started: # The default list of hosts is [“127.0.0.1”, “[::1]”] # #discovery.seed_hosts: [“host1”, “host2”] # # Bootstrap the cluster using an initial set of master-eligible nodes: # #cluster.initial_master_nodes: [“127.0.0.1”, “node-2”] # # For more information, consult the discovery and cluster formation module documentation. # # ———————————- Various ———————————– # # Require explicit names when deleting indices: # #是否禁用交换区 bootstrap.memory_lock: false #因为Centos6起不支持SecComp,而ES默认bootstrap.system_call_filter为true进行检测 bootstrap.system_call_filter: false #action.destructive_requires_name: true

      discovery.seed_hosts: [“127.0.0.1”]

      cluster.initial_master_nodes: [“node-1”]

      ```

    3. 安装中文分词插件:https://github.com/medcl/elasticsearch-analysis-ik
    4. 启动,es安全配置默认不能以root用户启动,切换到其他用户,进入elasticsearch
  2. Spring Boot整合elasticsearch
    1. 导入依赖starter-data-elasticsearch
    2. 配置
    3. 使用(注意新版本和老版本的client API区别)

需求实现:

  1. 新增帖子时将帖子增加到搜索服务器(异步)
  2. 删除帖子是删除搜索服务器的帖子(异步)
  3. 帖子搜索功能

1.12. 认证鉴权升级-使用Spring Security

主要的需求和功能整改:

  1. 登录检查:将拦截器方案改为使用Spring Security来实现认证授权 登录方案不变,使用自定义的Interceptor检查登录,授权交给Spring Security, 主要是用在拦截器preHandler()方法中用SecurityContextHolder存储用户和其权限信息, Security有一个过滤器会将SecurityContextHolder中的context存储到当前请求的session中,并在过滤器链执行完后清除SecurityContextHolder中的context(holder使用ThreadLocal存储context): SecurityContextPersistenceFilter.doFilter(HttpServletRequest, HttpServletResponse, FilterChain)

  2. 访问控制:为系统的不同角色分配不同权限:普通用户、版主、管理员
  3. CSRF配置: 防止CSRF攻击

1.13. 帖子状态:置顶、加精

需求:

  1. 帖子置顶(版主)、加精(版主)、删除(管理员)
  2. 不同权限的用户这上面的操作有不同的访问权限

实现:

  1. 引入thymeleaf-security实现不同权限的菜单(置顶、加精和删除按钮)显示
    <dependency>
             <groupId>org.thymeleaf.extras</groupId>
             <artifactId>thymeleaf-extras-springsecurity5</artifactId>
         </dependency>
    

1.14. 网站数据统计

技术点:redis高级数据结构Hyperloglog和bitmap

  • 需求:
    1. 统计UV(Unique Visitor)——使用hyperloglog
    2. 统计DAU(Daily Active User)——使用bitmap

1.15. 热门贴排行

当帖子发生发帖、点赞、评论、加精等行为,将帖子ID加入redis缓存的一个set,服务器每1分钟对这个Set中的所有帖子进行score刷新。

1.16. 缓存

使用Caffeine缓存前几页帖子,降低数据库读压力


上一篇 JavaScript

Comments

Content