网站定制开发怎么写,安阳百度,找图纸的网站,网站还建设 域名可以备案吗文章目录 环境配置bean是什么最终成品功能数据库与缓存一致性整个web系统后端的结构spring mvc相关controller常见的代码写法mybatis相关常识测试、调试相关计网相关component相关注解spring全家桶族谱spring衍生框架 run之后发生了什么什么是spring#xff0c;spring和bean的… 文章目录 环境配置bean是什么最终成品功能数据库与缓存一致性整个web系统后端的结构spring mvc相关controller常见的代码写法mybatis相关常识测试、调试相关计网相关component相关注解spring全家桶族谱spring衍生框架 run之后发生了什么什么是springspring和bean的关系形如factoryBean的写法从请求到返回重定向与转发发邮件功能细节注册功能细节登录和会话功能登录信息显示与拦截器图片上传功能发布帖子与异步请求看帖子详情评论楼套楼私信/系统通知功能统一异常处理统一日志处理与AOP思想redis相关与点赞/关注redis与网站数据统计kafka相关与系统通知功能ElasticSearch与贴子搜索spring security和csrfspring quartz与任务调度spring的事务管理缓存与性能优化缓存一致性jmeter压测项目中能体现重载的点存储位置盘点附录redis命令行常用命令贴子分数计算方法生成长图 各官方文档都在spring.io。 比如查Thymeleaf配置项名称。 环境配置
idea中的maven报错信息确实不完整该用命令行还是得用命令行。 idea社区版和专业版有区别建议还是使用专业版可以手动访问https://start.spring.io/。 pom里报包找不到的错误先去本地看下包在不在不在就mvn install。
bean是什么
Java语言欠缺属性、事件、多重继承功能。所以如果要在Java程序中实现一些面向对象编程的常见需求只能手写大量胶水代码。Java Bean正是编写这套胶水代码的惯用模式或约定包括 所有属性私有提供getXxx、setXxx方法 isXxx、addXxxListener、XxxEvent 成员可序列化自身可序列化 有无参数构造器。
最终成品功能
一般规律是先开发展示功能再开发增添功能。
用户模块注册、登录、个人设置 贴子模块显示贴子、发帖、帖子详情 评论模块显示评论、发评论、评论的回复 消息模块私信、系统通知
数据库与缓存一致性
下图这个是课程设计。 下面这个是现在比较流行的解决方案。
当一条数据发生修改时MySQL 就会产生一条变更日志Binlog我们可以订阅这个日志拿到具体操作的数据然后再根据这条数据去删除对应的缓存。
整个web系统后端的结构
应用层Controller、服务层Service、数据层Dao。 可以从目录结构上看出来一个配置文件类上面三个目录。 如果想用第三方bean往往还会有config目录里面是configuration的配置类。 一般还会有Entity目录比如User用户实体、Post贴子实体。
controller目录下会有所有动态资源访问路径。 开发顺序库字段设计/实体类-mapper-service-controller-html模板。 表现层从外部获取数据、查询关联数据 业务层处理数据转义、过滤敏感词 数据层增删改查。
spring mvc相关
spring MVC就是解决表现层Model做数据封装view模板中的值用model里的数据来替换。 核心组件是Dispatcher Servlet前端控制器也就是下图中的front controller。 Thymeleaf是模板引擎用在MVC结构的V用模板model给的数据生成动态html。其它模板引擎未必以.html文件为模板。 在main的resources的application.properties中开发环境需要关闭缓存确保代码修改立即生效生产环境需要开启缓存降低服务器压力。 application.properties中的每一个配置项都对应一个配置类中的一个属性比如server.port对应ServerProperties类的port属性。
thymeleaf模板文件的写法感觉封装程度很高。一般是在标签头加th:xx。常用的功能如: th:each比如ul标签下列表列出20个贴子 th:if比如有置顶标记的才显示置顶图标 th:utext文本替换u表示转义 th:src${map.user.headerUrl}map为model给的数据这句话实际上相当于map.get(“user”).headerUrl有很多所谓的“自动识别”所以才说封装程度高。 dollar表示thymeleaf中的变量井号用于函数调用比如列表生成、日期格式化函数at表示路径比如
a classpage-link th:href{${page.path}(current1)}首页/athymeleaf的html中引用其它css等文件时相对路径要改成thymeleaf风格绝对路径可以不改视频中有提到解决方案th:src或者th:href配合at符号。我猜测公司里的前端部门会提供原始html后端部门负责改写为thymeleaf风格。
controller常见的代码写法
针对get方法、请求的路径等进行针对性处理。例如
// /students?current1limit20
RequestMapping(path/students, methodRequestMethod.GET)
ResponseBody // 不加这个修饰默认返回html。
public String getStudents(RequestParam(name current, required False, defaultValue 1) int current,RequestParam(name limit, required False, defaultValue 20) int limit,
) {//
}
// /students/123
// 这是另一种传参方式路径拼接有另外的写法此处略。此外也能处理post请求。 可以返回html也可以返回字符串也可以返回json(返回值类型填map)。 理论上json可以承载任何数据。
mybatis相关
有了mybatis操作属性就相当于操作数据库里的字段。前者是javaentity驼峰命名在mapper.xml中用#{}包裹后者用下划线分词。
dao目录下mapper接口把准备写的增删改查方法声明一遍 entity目录下建一个类类名和表名对应把属性字段声明一遍以及相应的get、set方法 resources的mapper目录下创建表名-mapper.xmlxml中把接口中各方法的sql语句写好
其实未必要在xml里写sql也可以在mapper接口中把sql语句写在insert等注解里。
xml的sql中有一些常用写法 列出所有字段而不是用星号 用sql标签类似宏定义只用改一处 对sql语句进行条件拼接传进来的条件多则where的and也变多。
日志等级设为debug打印出实际执行的sql语句以免xml里写错。
常识
tomcat轻量web服务器。 springbootapplication注解表示这个类用作为配置文件。 注解可以由更多注解组成。 IoC的调用方依赖的是接口接口可以随意做实现类。从而调用方与实现类解耦。 https://mvnrepository.com/上可以看想调某个第三方包时需要怎么写pom。 spring整合了各个衍生框架因此配置文件只用写一份儿。日志配置也写在这。 datasource连接池能控制资源上限、复用连接减少创建开销。如HikariDataSource。 idea中altins可以快速生成get set方法或者toString方法。 select返回的是字段结构体update、insert、delete返回的是行数。 表中的冗余字段可以减少关联查询。 查询第几行到第几行mysql可以直接简写limit offset, rows一般可以写为limit rows offset offset.
可以搞个global.js里面放一些全局变量充当配置文件来使用达到改一处改处处的效果。至于Java代码这边全局变量可以写spring的properties里然后value就可以了。
服务器会创建线程来处理每一个请求。
字典树前缀树可以做敏感词过滤而且可以跳过分隔符号来防止绕过。此外字典树也能词频统计和字符串排序。
set方法的一个小技巧返回对象本身这样写的时候可以instance.set(a).set(b)。
把常量放在一个接口里命名为xxxConstant然后可以通过implement来引用这些常量。
swagger配合java注解可以生成网页版的接口文档。
本项目使用jquery和bootstrap后者是个ui组件库。
测试、调试相关
ContextConfiguration这个注解通常与RunWith(SpringJUnit4ClassRunner.class)联合使用用来测试。 带有test注解的方法都可以单独运行。
想测谁就在测试类里autowire注入。
js代码的调试可以在浏览器中f12sources找到对应js文件下断点等经典调试操作都支持。
计网相关
get和post理论上可以解决所有问题。get也能发送但长度有限、而且裸奔。
为啥要有json因为json可以跨语言。
http本身无状态指请求之间没有关联借助cookies可以创建有状态的会话。cookie由服务器创建浏览器收到之后之后的请求都会带上cookie。cookie可以作为session id。
component相关注解
带有component注解的bean就会被扫描到。 service业务 controller处理网络请求 repository数据库访问 configuration配置类。 也可以直接用component。
这些注解后的括号和字符串就是bean的名字如果不加默认是类名首字母小写。通过名字或者名字类.class可以找到bean。
spring全家桶族谱
说spring一般是指spring framework。 Core 模块Spring 框架的基本组成部分它包括控制反转及依赖注入功能。 Beans 模块实现 Spring 对 Bean 的管理包括自动装配机制等功能。 Context 模块用于访问项目配置及自定义对象ApplicationContext 接口是 Context 模块最重要的接口。 SpEL 模块Spring Expression Language表达式语言模块提供在运行时查询和操作一个对象的表达式机制。 JDBC 模块用于实现 JDBC API 的抽象层。 ORM 模块对象关系数据库映射抽象层基于该模块Spring 框架可以方便地集成 Hibernate 和 MyBatis。 OXM 模块XML消息绑定抽象层基于该模块使 Spring 框架能够支持 JAXB、Castor、XMLBeans、JiBX 和 XStream。 JMS 模块Spring 支持 Java 消息服务的重要模块集成了 JMS 的项目即可实现消息生产和消费的功能。 Transactions 模块Spring 的事务模块Spring 框架支持编程式和声明式的事务管理。 Web 模块即 Spring MVC提供了基于“模型-视图-控制器”的基础 Web 应用框架可替代 Struts 2。 Servlet 模块实现统一的监听器和面向 Web 应用的上下文用以初始化 IoC 容器。 AOP 模块用于 Spring 面向切面的编程实现。 Aspects 模块Spring 与 AspectJ 的集成可以使用 AspectJ 来实现面向切面编程。 Test 测试模块支持 JUnit 和 TestNG 单元框架的集成可以快速开展业务代码的单元测试。
spring衍生框架
Spring Boot轻松地创建独立的基于 Spring 的生产级应用程序 Spring Cloud快速构建一个分布式系统的框架。 Spring Data为数据库的访问提供一个一致的基于 Spring 的编程模型保留底层数据存储的框架。 Spring Cloud Data Flow面向云计算和 Kubernetes 的基于微服务的流和数据批处理处理框架。 Spring Security一个功能强大且高度可定制的身份验证和访问控制的安全框架。 Spring Session在 Web 应用中管理用户会话信息的框架。 Spring AMQPAMQP 消息解决方案该框架为消息的发送和接收提供一个模板方法。 Spring Web Service该框架用于创建文档驱动的 Web 服务。
run之后发生了什么
tomcat会启动 spring容器会启动 带有springbootapplication注解的类自动扫描所在包和子包中带有component注解的bean并添加到容器中。
什么是springspring和bean的关系
spring容器的顶层接口是beanFactory常用其子接口ApplicationContext。 它可以创建、初始化postconstruct、添加、销毁predestroybean控制bean的作用域scope可以决定singleton还是prototype。前者单例后者每次get都是新的。默认是前者比较常用。 虽然可以applicationcontext可以getbean像这样主动获取来调用bean 但实际上一般是Autowired修饰属性spring会自动get bean然后放到声明的变量里之后直接用即可。 Qualifier可以与Autowired配合。
不止是在入口类里在bean里也可以autoWired从而实现controller调用Dao的代码。
bean可以装配第三方类和自定义类。
形如factoryBean的写法
XXXfactoryBean里写的是bean的实例化过程 加上Bean装配到Spring容器里 将XXXfactoryBean注入到其它bean里 其它bean就可以得到XXX的对象实例。
从请求到返回
题外话mozilla网站有http的官方文档。 以下内容可以f12 network看见。
DNS。 建立TCP连接。 http request http response一开始一般是个html解析过程中发现引用了css、js、图片 多轮request和response。 浏览器渲染完成。
重定向与转发
总结来说能在不耦合的情况下实现功能跳转。 下图做了删除操作后没什么好返回的就返回302建议对方另作请求对方查询后能看见删除的效果。 除了上图另一个常见场景是注册完跳转到登录。 登录成功重定向返回302建议浏览器重新请求另一个路径可以在地址栏看见地址发生变化。 重定向是低耦合的。
转发是与重定向并列的解决方案。 登录失败转发A无法处理内部转发给B两者协作完成请求存在耦合。
发邮件功能细节
整个行为的本质就是用java代码来模拟邮件客户端来自动发邮件从功能上来讲跟自己所写的主体web服务是可以分隔开的真正做事的是邮件服务提供商。
需要注册一个邮箱起一个官方的名字 把smtp服务器注册的新浪邮箱就是smtp.sina.com、服务端口465、邮箱账号、邮箱密码等参数写在spring的properties里。
整个JavaMailSender类也比较简单两个方法构建邮件发送邮件。
注册功能细节
分为三步 第一步点注册要能展示注册页面 第二步提交数据入库生成激活链接 第三步接受激活。
第一步主要是表示层、tyhmeleaf的工作不涉及数据层controller中处理get和post 第二步可以用java.util.uuid生成随机字符串然后要判断空、重复生成salt和激活码写进库里操作成功跳转操作成功界面操作失败跳转回原界面把用户的输入作为默认值留在原界面并展示错误信息。 第三步不能重复激活不能用错误的激活码或者激活成功。库里有两个字段一个是int型的激活状态一个是字符串型的激活码。
登录和会话功能
登陆状态维持、购物车都会用到cookie。 cookie的生成就是用uuid然后需要设置生效范围、生效时间。
nginx多服务器的时候如果是不同的服务器来处理那session就丢失了。 一种方案是粘性session即每个用户每次都在同一个服务器上处理后果是负载不均衡。 一种方案是同步session每个服务器存一份存储和通信成本很大。 一种方案是专门一台服务器专门存session其它服务器请求这台服务器缺点是session服务器可能挂不可靠、有性能瓶颈。
目前主流方案是session存在nosql数据库集群里理由如下 验证码一分钟内就会失效看不清的时候会反复刷新 访问很多地方都需要用到登录凭证和用户信息使用频率高。
验证码生成一般用kaptcha库kaptchaProducer输入字符串输出图片 将字符串答案记录到rediskey为新生成的UUID随机串value为答案 将key放在cookie里返回给用户 登录逻辑的入参要包含刚刚的cookie 用js实现刷新验证码链接加随机数可以避免浏览器偷懒。
顺利通过登录逻辑的以下验证后 验证码是否正确 用户是否存在 密码是否正确 生成登录凭证ticket存入redis并返回ticket给用户。这个ticket表的作用类似session。
ticket只需存在redis里无需存在mysql里不过user信息需要存两份。 存两份是因为访问频率高又需要持久化。 相关逻辑 查时先取redis 查时取不到则存redis 修改则删redis。
登录信息显示与拦截器
拦截器有点像插桩或者装饰器。有三个执行时机controller之前controller之后~模板之前模板引擎之后。 配置类中可以限制所有拦截器的生效范围一对多不过这种方法很麻烦。可以不exclude拦截器拦截所有请求利用反射获取注解加了自定义注解的方法就鉴权没加自定义注解的方法就直接放行。 拦截器的主要使用场景就是判断动态资源权限。权限判断、权限维持把用户信息存在threadlocal里。
图片上传功能
post请求提交表单时enc-typemultipart/form-data。 图片和其它数据的区别不只是在提交存储也不一样存储存在服务器硬盘。 文件操作在表示层处理Spring MVC的multifile。服务层只更新用户头像路径。 文件重命名并不是为了防文件上传漏洞只是因为用户可能会用一样的名字。
发布帖子与异步请求
AJAX异步javascript和xml。不过现在一般是用json。 目的是增量更新网页而不需要刷新整个页面。 需要异步请求的例子是注册功能的“该昵称已被占用”页面并没有刷新但其实暗中请求了服务器 另一个例子就是发帖。
实现异步请求关键是html中的jquery。jquery发异步请求有三个参数路径、数据、回调函数。
异步请求的http头会有x-requested-with。
dao层发帖本质是增 service层转义标签比如贴子内容里有html标签应避免这个被解析、过滤敏感词、调dao controller层fastjson的基本使用puthtml中要写jQuery。
看帖子详情
dao层看帖本质是select service层直接调dao层mapper controller层
此外会影响首页index.html 详情页的html里要展示头像、用户名、贴子标题、贴子内容。
评论楼套楼
数据库字段有三个实体类型实体编号目标。 实体类型是被评论对象类型可以是贴子可以是课程也可以是评论。 实体编号是被评论对象id 目标字段仅在实体类型为评论时生效表示被回复的对象。普通的评论的评论没有目标如果在楼中楼里发生相互回复才有目标。
添加评论时需要用到事务管理因为除了comment数据也要连带修改贴子数据评论数增加。
私信/系统通知功能
可以展示和任何人的会话多次对话系统通知就是系统管理员和用户的私信 可分为会话列表、私信详情也就是私信列表、发送私信会话未读量要统计并可查。 数据库中每行是一条私信关键字段from idto id所属会话私信内容已读未读。 “所属会话”格式为小id_大id因为a to b和b to a理应为同一个会话。
service层要想好提供什么查询按user查会话数量/会话按会话查消息数按会话和user查未读量。 显示的时候显示会话的另一方而不是自己。
统一异常处理
借助controllerAdvice可以处理所有异常少写很多代码。 统一在表现层处理异常统一在全局advice类内处理表现层异常 controllerAdvice加在类上这个类通常负责所有controller的全局配置总揽各controller。 这个advice类里可以有带以下注解的方法: ExceptionHandler各controller中出现异常后执行 ModelAttribute给model统一的共享参数cur/next与异常处理无关但与上一个并列 DataBinder能把get等网络请求参数转为对象的属性各controller参数的自动转换就靠这个
统一日志处理与AOP思想
我们希望把业务需求和系统需求日志是系统需求分开。 AOP与OOP互补上图的三条横线就是切面。 切这个动作英文是weaving一般称为“织入”。 可织入位置被称为joinpoint连接点。 编译时织入使用特殊的编译器。好处是快坏处是缺少运行时信息不够精细。例子是AspectJ。 装载时织入需要使用特殊的类装载器。 运行时织入为目标生成代理对象。例子是Spring AOP。 pointcut指定切入位置advice则是切入内容。
实际运行时目标对象不会被运行代理对象才是真正运行的那个。 如果目标对象有接口Spring AOP使用JDK动态代理创建接口的代理实例。 如果目标对象没有接口Spring AOP使用CGLib动态代理创建子类的代理实例。
redis相关与点赞/关注
redis.io官网上可以查命令。redis命令行常用指令见附录。 Redis 官方不建议在 windows 下使用 Redis微软提供了一个老版本。 键值对nosql全部在内存中。 偶尔往硬盘上写快照或日志前者耗时定时后者耗空间、存时快实时、恢复慢。 典型应用场景缓存、排行榜、计数器贴子浏览量、点赞。
java类型的数据要存到redis里需要做些转换在RedisConfig类里配置各种key的序列化方式。 配好之后可以通过redisTemplate.opsForXXX() 此处的XXX为redis数据类型比如string型对应opsForValue()来读写redis。 key一般是冒号连接的字符串value是string、list、hash、set、ordered set等。 可以通过redisTemplate.boundValueOps绑定key简化代码否则每次操作都要指定key。 java中操作redis命令会先进入队列在事务提交时才会批量查询。事务中间查询不会得到预期值。
点赞的设计需要知道谁、给哪个类型、的哪一个实体、和背后的作者点了赞userIDentityTypeentityIdentityUserId四个参数。 redis中与点赞相关的key有两大类 userId为key赞数为value 以entityType:entityId为key点赞者集合为value。 前者是为了方便按userId查点赞总数后者是方便单数赞双数取消。
类似点赞关注和取关也可反复点也希望能按userId查关注/粉丝数。并且也可以给多种实体关注。 我的followee是我关注的人我的follower是我的粉丝。 以userId:entityType为key关注实体zset(entityId, followTime)为value。 以entityType:entityId为key粉丝集合zset(userId, followTime)为value。 原视频在前端的处理是刷新页面window.location.reload()算是简化代码的dirty写法。
redis与网站数据统计
除了stringsetzsetlist等基本数据类型以外
HyperLogLog基数算法有误差但很小。常用于统计独立总数同一个人一天内访问多次算一次hyperloglog可以解决这种需要去重的情况比如UVunique visitor。set也能实现但hyperLogLog不管统计多少数据只占12k。多个hyperLogLog之间可以很方便地用union方法合并。
bitmap没这个类型实际使用string型写用opsForValue.setBit()读用opsForValue.getBit()统计用bitCount此外还可以多个bitmap做与或非运算可以看成byte数组。适合统计签到也就是DAUdaily active user。
kafka相关与系统通知功能
java自带阻塞队列BlockingQueue接口解决线程通信问题。有put和take方法。 阻塞指的是队列满了阻塞生产者队列空了阻塞消费者阻塞可以避免资源浪费。 原视频在test目录下写了个java原生阻塞队列实现类之一叫ArrayBlockingQueue的demo可以作为生产-消费模式的demo来复习。
生产消费和发布订阅有些相似。区别是一个消息可能被消费的次数。生产消费模式始终为1。
kafka把数据存在硬盘所以数据规模可以很大 硬盘的顺序读取速度约200-300MB/s接近内存随机读取速度的下限。 kafka使用zookeeper来管理集群。 kafka服务器称为broker一个topic分为多个partitionreplica副本决定复制的份数。
spring中 生产者调kafkaTemplate.send(topic, data) 消费者调KafkaListener(topics{“test”})修饰handleMessage方法。
评论、点赞、关注三大高频事件都要发通知消息队列可以实现异步。 构造事件对象开发事件生产者开发事件消费者。 事件的属性topicuserIdentityTypeentityIdentityUserIdmapString, Object。 在评论、点赞、关注的逻辑里构造事件塞给producer 生产者负责从事件中获取topic和data然后调用kafkaTemplate.send 消费者负责解析、处理data然后存到message表里。
生产者的入参是Event类型消费者的入参是ConsumerRecord类型。
每个topic对应一类需要消费的事件除了上面提到的评论关注点赞消费是发通知还有贴子搜索一节中的发帖消费是存取es新帖和新评论都算发帖事件。
ElasticSearch与贴子搜索
实时搜索。默认端口9300。 数据提交的时候就会在ES存一份分词、建立索引。 ES6和ES7区别较大。ES7.0后 ES的索引对标mysql的表 ES的文档对标mysql的行 ES的字段对标mysql的列。
分片提高并发能力副本提高可用性。
中文环境需要配合ik插件。IKAnalyzer.cfg.xml中可以添加自定义的扩展词典。 停止词会被作为分隔符。
ES提供服务都是靠rest api。 curl -X可以指定请求方式get、post、put等可以用于测试restapi。 postman可以当curl用有图形界面会方便一些可以直接写body。 用户提交的搜索关键字也会被分词。
给实体类加elasticsearch的Document(indexName, type, shards, replicas) 即可自动映射实体类和es库字段 es可以视为一种特殊的数据库与帖子库共同增删改查不过是异步构造事件塞给消息队列。 对实体类内部的字段也需要加注解指定field type。 除了field type还可以指定analyzer指定存储时分词策略、搜索时分词策略。 对title指定analyzer为ik_max_word指定search_analyzer为ik_smart。
extends es库的ElasticsearchRepository类不需要填什么内容 可以直接调用其实例的save和saveAll方法写入/批量写入es库。 此外还有delete和deleteAll方法。 查的时候需要先build一个query withQuery指定高级查询的关键词等选项 withSort方法按置顶、精华、分数、时间来排序。 withHighLightFields可以给匹配到的关键词前后加em等html tag。 此处未完全列举query构造过程回想一下各个论坛的搜索功能即可 构造好query后可以用ElasticsearchTemplate或者ElasticsearchRepository后者的封装程度更高。 在原视频中高亮关键字的功能实现起来有点绕用的elasticsearchTemplate。 查询会返回spring的page类型。
视图层在首页的顶栏代码里处理搜索其它页面复用此header即可。 展示搜索结果的页面和首页也比较相似。
spring security和csrf
提供身份认证和授权防护csrf。 filter是Java EE的可以在dispatcherServlet前进行拦截servlet也是Java EE的。这种拦截类似interceptor在controller前的拦截。之前的鉴权用的是interceptorsecurity的拦截更早更安全。
Spring security的核心就是11个filter各司其职比如其中一个专门验证账号密码其中一个专门退出等等。 可以自定义filterfilter可以在filter之前比如先校验验证码再校验账号密码。
让User实体类实现security的UserDetails接口然后就要实现以下方法 判断用户是否过期是否锁定是否可用凭证是否过期获取用户权限。 获取用户权限方法中一个用户可能有多种身份/权限。 让UserService类实现security的UserDetailsService接口。
Spring Security会有一个统一的配置类。 AuthenticationManager是认证核心接口ProviderManager是其实现类。 ProviderManager持有一组AuthenticationProvider每个AuthenticationProvider负责一种认证可能有多种登录方式比如微信登录等等。ProviderManager将认证委托给了AuthenticationProvider这是委托设计模式。
configure方法里可以对每个动态路径设置“可以访问的权限级别”示例如下。 http.authorizeRequests().antMatchers(/user/setting,).hasAnyAuthority(AUTHORITY_USER,AUTHORITY_ADMIN,AUTHORITY_MODERATOR).anyRequest().permitAll(); //除了上面列出的都允许随意访问spring security可以与thymeleaf互动使得高权限用户能看见的置顶、加精、删除的按钮。 可以把贴子id隐藏在页面里方便发异步请求的时候获取。
spring security可以防范csrf当用户请求表单页面服务端在返回的表单中加入隐藏项
input typehidden name_csrf value随机字符串对于异步请求没有表单 服务端需要在html的head里加两个meta字段分别是_csrf和_csrf_header 服务端提供的js会在ajax jQuery请求头里加上selector获取html中的csrf token。
spring quartz与任务调度
每隔一小时计算贴子分数只需要对发生变化的贴子重新运算变化时加入redis set 每隔半小时清理服务器临时文件 类似这样的需求需要定时任务。自动运行所以肯定是多线程。
ExecutorService和ScheduledExecutorService是JDK内置的线程池后者是做定时任务的。 ThreadPoolTaskExecutor和ThreadPoolTaskScheduler是Spring的线程池后者做定时任务。 另外Spring还提供Async、Scheduled分别作为Spring线程池、Spring定时任务线程池的简化方式。
普通线程用ThreadPoolTaskExecutor即可。 分布式环境下的定时任务一般用Spring整合quartz而不用上面的上面的基于内存不同服务器不共享内存因此多机可能会重复处理。而Quartz的相关配置存在单一数据库有锁任务就不会被重复做。
项目中用到的线程池参数 core-size核心线程不会被释放。 max-size线程池最大大小。 queue-size排队长度。
Quartz的使用先实现Job写好任务内容然后用JobDetailjob名字、描述、组、对应类等配置和Trigger上一次执行时间、执行次数。与Quartz数据库各表比如JobDetail表、trigger表字段对应。
spring的事务管理
声明式可以通过XML或者Transactional注解声明某方法的事务特征隔离级别、传播机制。 编程式用transactionTemplate类来实现虽然麻烦但可以精准操作一个方法中的局部步骤。 一般用编程式事务。
缓存与性能优化
分为两类 本地缓存如guava、caffeine目前最佳容量相对小。 分布式缓存如memcache、redis集群缓存在其它机器上容量相对大。 caffeine缓存性能接近理论最优结合了LRU和LFU的优点。
多级缓存是指三级存储本地缓存-分布式缓存-DB 缓存击穿是指缓存失效大量请求直达DB。 两种缓存同时失效的概率较小。
与用户强关联的数据应该缓存在分布式缓存。
对于热门贴子访问频率高希望能优化性能。 可以存在本地缓存。因为它不需要判断权限所以不需要去分布式缓存里取用户信息。
性能优化的代码一般在service层。
caffeine的核心接口为cacheloadingCache没查到就同步去取AsyncLoadingCache。
缓存的更新时间取决于变化频率和资源量。原视频设定是180s。
缓存一致性
原视频使用的是 写数据的时候构造event给kafka producer然后消费者写数据库、删缓存。
流行的方案是写数据时直接写库canal订阅mysql的binlogcanal给kafka消费者写数据库、删缓存。
jmeter压测
创建测试计划设置线程数让它循环设定运行时长。 指定协议、ip、端口、方法、参数。 创建定时器随机间隔。 添加监听器聚合报告看吞吐量。
项目中能体现重载的点
比如报错不一定有msg但一定有错误码 再比如补充传一个.class就不用强制父类转子类。
存储位置盘点
静态资源存硬盘用的文件系统 用户信息、贴子内容存mysql数据库 用户登陆凭证、用户信息、验证码存redis 用户上传的头像客户端直接传给云服务器 分享生成长图服务器传给云服务器
附录
redis命令行常用命令
通用指令 select 0/1/2换库 flushdb清空 keys看有哪些key比如keys *查看所有keykeys test*正则匹配看test开头的key type/exists/del key查看key类型、是否存在、删除 expire key time设置过期时间 操作字符串 set key value get key incr/decr key 操作hash表 hset key field value hget key field 操作list lpush/rpop listname左进、右出也可以左出右进 llen listname长度 lindex/lrange listname下标访问/区间访问 操作set sadd setname item1 item2 … 添加元素 scard setname大小 spop setname随机弹出可用于抽奖 smembers setname显示全部元素 操作ordered set zadd setname score1 item1 score2 item2 …添加元素 zcard setname大小 zscore setname item查分 zrank setname item查元素的大小顺序
贴子分数计算方法
考虑的变量如下 反比发布/更新时间stackoverflow经常会更新问题 正比精华阅读量评论/回答数评论点赞数收藏/关注数比如知乎就可以关注问题。 对上面的几个数值往往取log最早的10个赞比后来的100个赞更有含金量。
生成长图
服务端可以用html转pdf的工具。如wkhtmltopdf。转完之后服务器传给云服务器。