项目待实现/可优化的点(已在计划中)

      • 发信模板:不管使用文字、图片、附件还是HTML,都必须要使用变量,同一内容被大量群发后,腾讯就会识别然后设置为垃圾邮件内容,所以变量是防止垃圾内容的方法之一。
      • 发信ip:通过vps切换ip来达到模拟人工操作的要求。
        • 自建邮局方法并非不可行,有避免被主流邮箱屏蔽的方法:使用中继主机。我开通了Amazon Simple Email Service (SES)(主用)和Mailgun(备用)作为发件中继主机,SES每个月免费 62000封,Mailgun每个月免费1000封,两者免费版的都使用共享 IP 地址,理论上仍有可能因其他共享用户发送垃圾邮件或自己大量发件被收件方邮局屏蔽,送达率可能不如大厂的邮箱,解决办法是购买专用IP,但这半年来我没有碰到过邮件被拒收的情况,除了163邮箱莫名收不到Mailgun的邮件,163邮箱似乎会屏蔽大部分海外来件。
        • 此外通过中继主机发送的邮件,有些收件人客户端会显示“由 代发”字样,可能会给对方带来困惑,因此最好在Amazon SES或Mailgun上配置与发件地址同一域名下的子域作为发件域。
      • Amazon Simple Email Service (SES)限制:每天50000封、每秒14封、每条消息 50 个收件人、每封邮件包括附件最大 40MB,带宽上行 40MB/秒
      • 发送时用Guava RateLimiter来限制每秒发10封邮件,这样就能避免被封IP的问题,发送出错的重新放回消息队列并记录重发次数超限就不发了,(千用户以内,用户多了就买企业邮箱,我不收费就用免费的方案,不行的话就不自建邮箱服务器了,还是配多个邮箱账号轮询来发邮件吧)
      • 自建邮箱服务也不可以大量发送
      • SMTP/POP3协议介绍。采用常用的SMTP作为邮件发送协议,采用常用的POP3作为邮件读取协议。请注意,SMTP和 POP3 (或IMAP)都是使用TCP连接来传送邮件的,使用TCP的目的是为了可靠地传送 邮件。
    • 可以考虑引入消息队列(一般来说,消息队列的意义主要是削峰填谷、异步解耦。)对本项目而言,引入消息队列有以下好处:
      • 任务调度和任务执行解耦(调度服务并不需要关心任务执行结果);
      • 异步化,保证调度服务的高效执行,调度服务的执行是以 ms 为单位;
      • 借助消息队列实现任务的可靠消费( At least once );
      • 将瞬时高并发的任务量打散执行,达到削峰的作用。
    • 实现用户级别的可靠性,即要保证所有订阅用户都被至少推送一次(At least once)。At least once推送如何实现?
      • 前提是当把用户 uin 从订阅列表中取出进行推送后,在推送结果返回之前,必须保证用户 uin 被妥善保存,以防止推送失败后没有机会再推送。由于 Redis 没有提供从一个 set 中批量 move 数据到另一个set中,这里采取的做法是通过 redis lua 脚本来保证这个操作的原子性,具体 lua 代码如下(近似):
    • 微信相关的模块分成具体的要点写,亮点就可以了。比如微信支付接入的时序可靠性;可以引入如小程序二维码的时效性和要求
    • 使用VARCHAR字段来存储多个标签ID,然后用逗号分隔,是一种常见的简化数据库设计的做法,尤其是在一些小型或不需要高度正规化的数据库中。然而,这样做会影响到数据库的拓展性、性能和数据完整性
    • 一个接口仅拥有少量标签时,可以在“接口信息表”中用一个varchar类型的字段存放多个标签的id(id间用逗号分隔开),使用MySQL的FIND_IN_SET函数能实现按单个标签查询接口,不用创建“接口标签表”,优化了按标签查询接口和查询接口标签的操作;
    • MySQL手册中FIND_IN_SET函数的语法解释:FIND_IN_SET(str,strlist)
      • str 要查询的字符串
      • strlist 字段名 参数以”,”分隔 如 (1,2,6,8,10,22)
      • 查询字段(strlist)中包含(str)的结果,返回结果为 null或记录
    • MySQL的IND_IN_SET函数确实能够查询出含有特定标签的记录,但这种方式并不高效,尤其是在标签数量较多或是记录数量庞大时。这是因为FIND_IN_SET是一种字符串函数,它不会利用索引,所以每次查询都需要进行全表扫描。
    • 如果考虑到可维护性和性能,建议使用一种更可扩展的设计,比如创建一个标签表和一个接口与标签的关联表(通常称为“联结表”或”中间表”)
    • fooId字段可以用逗号分隔储存成varchar类型 一个字段储存多个fooId,一查查个String出来再按逗号分割可以分出多个fooId,MySQL的varchar类型支持输入逗号并且MySQL有FIND_IN_SET函数支持逗号,fooId数量少的时候实现了存可变数量的fooId数据(可以设置not null);不用设置 fooId_1、fooId_2、fooId_3…… 多个字段(有的时候只存一个数据,但查得全查则查出的后面几个字段会是还要判空,且浪费空间)

项目待实现/可优化的点以及部分具体亮点整理(酌情写到简历上,在面试中提出)

可能的项目亮点

  1. 校招vip免费的推电影项目参考
    • 可以做接口热度的排行榜,排行榜变动时的性能压力,怎么优化解决
    • 多纬度条件查询和筛选的动态实现
    • 自定义感兴趣标签,按标签推荐
  2. 校招vip免费的推推小说项目参考
    • 书目列表在更新频繁情况下的有效实现
    • 书籍详情在更新前后面临的性能压力
      • 描述为啥使用xx架构或中间件,例如因为作者通常在半夜12点或早上6点更新,此时间点前后十分钟左右访问量会激增,有聚集效应,所以使用xx方案应对此时间段访问量的激增
    • 较多书籍时构建查询系统
    • 定时任务自动爬取并添加书籍最新章节
    • 小程序的通知机理与平台实现
    • 搜索如何主从库分离,分离的数据同步怎么实现,搜索的质量和性能怎么样
  3. 敏感词过滤,及其性能优化
  4. 多维度大V或身份认证
  5. 订单状态
  6. 这个项目的业务是可以展开的,比如说视频播放,这个功能有很多的课程或者文档在不断地去展开,怎么能够防止视频被别人探测和下载?怎么能够在视频比较大的情况下进行切片?怎么能够加上前置的广告功能?视频怎么存储?我认为这点突出去写很容易展开,而且亮点足够,跟别人写的不重复
  7. 为什么并发量是500,而不是1000,你就会发现这里面跟很多框架的参数有关系,而且跟长短链接也有关系,但是你答不上来。包括为什么加redis并发量是4000,不是3000或者5000,怎么进行的估量和测试?那你这个最大并发量的情况下,有多少线程在等待状态
  8. 验证码,比较常用的图形验证码或者滑块,以及它们之间的性能或者功能的对比。
  9. 用缓存,那就进一步,扩展现在有哪些缓存分类?最后决定用这种缓存,然后把缓存的对比性能分析放到简历上。一方面有着亮点和独特性,另一方面也是工作中做事情的习惯性做法,会比较吸引面试官。
  10. 这个表格有什么复杂的逻辑?poi很难实现,然后你花了大量的时间去解决它
  11. 那你就重点去把支付功能扩展开写。像描述里面说重点做了支付宝扫码或者是微信扫码的整个支付流程。能把这个讲明白,你就是比别人有优势。它的难度在什么地方?怎么能够让它更好的流程完善?
  12. 项目的上传下载文档,和评价模块可以以这个描述作为重点,怎么去具体实现的?评价怎么实现评价的图片压缩?敏感文字过滤?图片PC与移动端怎么共享共用?对一个贴的评论和对评论的评论数据库怎么设计和存储(怎么保证稳定性)?
  13. 使用OOS对象存储服务,做了xxxxxxxxxx,解决多平台图片多辨率的问题,完成图片分发
  14. 项目需要突出什么优势? 做了搜索就可以把其他的模块删一下,重点讲,搜索怎么来进行?怎么能够去多字段查询?怎么能够主从分离,再到现在的弹性框架, 选择一个可以真实去做的业务点。
  15. 比如说搜索如何实现主库从库的分离?分离的数据同步是怎么实现的?搜索的质量和性能怎么样?把这部分重点用两行左右的文字描述,并且掌握中其中的回答。
  16. 增加一些技术亮点,比如jjwt登录,或者security权限管理等
  17. 网盘项目实际上是一个产品功能难点非常多的项目,直播中会针对文件的存储、非常文件识别、下载的安全性,和下载带宽限制的商用功能点的细节进行展开
  18. 外卖订餐项目实际上是一个产品功能难点非常多的项目,可以对订单、套餐等多种亮点模块进行展开
  19. 项目的描述仅仅是并发,还没有写出秒杀的技术点。
  20. 众筹类项目是比较常见的项目这一,重复度过高导致校招简历很难通过简历筛选。直播会对项目的核心功能模块,比如说参与资质、人数控制和回报条件等模块过手
  21. 社区项目实际上是一个产品功能难点非常多的项目,包括文本和图片的合法判断、帖子多级评论、排行榜等模块,都是难点较大,面试官感兴趣的功能点
  22. 复杂购物车逻辑进行产品功能难点的展开
  23. 课堂学习类平台,这类产品有不少核心功能点,比如课程上传和播放,作品上传、点评流转等。但是描述里没有这些核心功能,只有非常常见的权限管理、登录等
  24. 考试系统,怎么防作弊,调用摄像头
  25. 针对学习系统类项目的核心功能,如课程播放、作品跟踪、专项刷题等模块进行展开,难点较多,比较容易突出项目的真实性,降低重复度
  26. 新闻项目是一个很复杂的产品业务项目,不要过度追求不存在的大数据量,而是从真实的产品需求角度去展开,就会很好的降低重复度。
  27. 路路通项目是一个老牌培训班项目,但是这几年反而出现的少,重复度不高,而且项目里的产品功能点比较明显,可以很好的按照功能展开,提高简历通过率
  28. 云相册的项目不需要增加这么多的中间件, 甚至出现明显的不适合的场景描述,比如异步执行图片审核,这个场景本身就不成立,如果给面试机会,这些地方就一定是给自己挖坑。
  29. 比如为什么不用悲观锁,需要从场景上作为明确解答
  30. 优惠券秒杀是很常见的项目模块,但是在实际商用环境里业务功能比较复杂,比如说线下券的销售和核对,券池的生成和维护,超卖的现实商业产品逻辑等
  31. 咨询项目虽然比较常见,但是因为有比较具体的功能点,可以进一步提炼产品难点,使亮点更多,重复度更低。比如说计算热门文章分值本身就是一个亮点,热门的规则是怎么样的?
  32. 项目的亮点不要出现明显的错误,比如论坛的敏感词过滤使用前缀树就是不合理的方案,在面试里,面试官只要一追问,就是给自己挖坑。包括对方案的选型,比如发帖和私信为什么用kafka,而不是用其它的MQ中间件,区别是什么?
  33. 搜索的字段维度、付费的实现 和券相关的实现
  34. 小说平台可以从产品需求细节来展开
  35. 充斥着不少商业项目的错误点,比如说自定义统一的错误码,在一个大系统里的众多模块,错误提示可以上百个,统一的话,非常不方便开发。
  36. 在简历的最后,提到过做过爬虫,爬过boss直聘和淘宝的信息,这个反而可以做为项目经历的亮点进行展开
  37. 描述具体的话题分类或者搜索等功能
  38. 上线的原创应用,就更应该讲清楚核心功能是什么,整个产品是怎么运转的。另外,不需要写项目流程或者分配流程。
  39. 微信相关的模块分成具体的要点写,亮点就可以了。比如微信支付接入的时序和可靠性; 可以如小程序二维码的时效性和要求
  40. 对25届985同学来说,要理清楚一个事情,明年3月就是大厂的春季&暑假实习(属于校招阶段)。但是每年都有大量的顶尖985因为没准备好,在两三个月的投递和面试后,颗粒无收。所以目标是找大厂的实习,还是先找一个中小公司的正式实习,再找暑假实习,或者直接秋招。每年都有不少985的学生,因为先后顺序出问题,所以在秋招依然没有太好的机会。
  41. 分片下载,服务器端怎么分片多线程?
  42. 爬虫,怎么绕过验证码,怎么周期性爬取数据,聚合整理数据,怎么统计,统计的意义,防ip被封
  43. 断点续传,文件分片是前端的技术要点(前端实现,后端很难,一般是挖坑,但做好了是个大亮点{例如,迅雷间传,QQ间传大文件}),一般Java对大文件正常传就好,除非对实时性要求很强的项目
  44. 稳定常规大流量(多开几个服务器,负载均衡后对每个服务器来说就是正常流量),突发大流量(真正要解决的)
  45. 主流还是MySQL+Redis,MongoDB存文件只有游戏文档用的场景多
  46. Linux 守卫线程
  47. 但是要想具体的可行的后端防重复提交的实现之前,你要考虑2个场景的区别:
    • 后端提交完全没有限制,黑客1秒反复提交10次 ;
    • 每次有限制,但是黑客设置了100个终端1s端各自重复提交同一个提问。
  48. 使用OSS做存储和媒体服务,不用自己用定时任务实现对图片的处理(比如压缩、反转、清晰度调整),对视频的处理(比如转码),让OSS自动化流程,各种码率的实现了什么量级下的压缩反转,提高了效率。
  49. MySQL存储数据变更,通过数据库的日志传给ElasticSearch;数据量ElasticSearch每次解析日志都要花1s以上,但前端页面不能等待那么久,且不允许查出来的是原始老数据,必须是更新后的数据;ElasticSearch用来检索搜索效率不错,但ES不是强实时性框架满足不了强实时性;可以考虑数据的预加载(看当前页的时候自动查出下一页),那第一页咋办?(可以在MySQL的从库里查,使用全文索引{从库只存储第一页的数据,数据量就小了,百万级别内的数据用全文索引效果不错,千万级别搜索才考虑使用搜索引擎{如,ElasticSearch}代替全文索引})
  50. 要会写SQL脚本,商用项目不管大厂/小厂一般不用PageHelper 分页插件,插件性能低(且自己实现简单,故而自己定制一个),无法自动化审核脚本
  51. 亮点 为了反爬虫,实现用户普通访问时能正常看到文字信息,但爬虫出来的是乱码,混用非常用编码,使用svg绘制技术
  52. 防抖一般全是前端处理
  53. 挖坑了,不要写 简历别写 分布式相关的,银行金融要求钱不可以出错,所以还是使用分布式事务,一般用Oracle数据库,Oracle对分布式事务支持比MySQL好;但商业环境一般不允许使用分布式事务(,对性能影响大,多个业务一起锁了),商业可以用补偿式方法乐观锁,有的时候微信支付宝会支付不成功要再付一次款,定时任务两三分钟跑一次看看有没有出错的订单或等用户主动投诉与用户沟通。
  54. 挖坑了,不要写分库分表。分库简单,分表很复杂,与业务高度相关且一天数据量增量要百万千万才需要分表,架构师才考
  55. 挖坑了,不要写用了MyBatisPlus,Spring分了几层
  56. 挖坑了,不要写 防止商品超卖用乐观锁/悲观锁。乐观锁的机制,有一万个人来update加一个随机数,同时update时有一个人的update成功了,那其他人的update都要失效,这样每次只能卖出一个,性能差,但悲观锁也解决不了秒杀,乐观锁和悲观锁都不用,要根据实际的量级和业务特点进行设计。
  57. 挖坑了,不要写 使用ThreadLocal实现线程隔离,因为Spring本身就是线程隔离的(默认单线程)
    • 因为99%的场景,都不会有单线程的冲突问题。用ThreadLocal的场景
      • 比如说一个接口请求,他的参数格式都是固定的。但是这个接口的服务部署在两个地区的服务器上,但是产品业务上有一个特殊需求,需要确定访问是哪个地域的服务器,而且根据不同的地区有不同的处理逻辑?
      • 那就发现这个需求,跟用户访问的地址没关系,因为他在页面上发起请求的时候也不知道是哪台服务器?这就出现了线程冲突场景,也就是本身的参数是固定的没有办法需修改,包括接口本身的参数也是固定的没有办法需求改;但是相同的一个访问链接,还需要做不同的逻辑判断。
      • 那这个时候,只能在接口的参数之外,用容器赋值ThreadLocal的设置参数
  58. 挖坑了,不要写git和svn对比,
    • 很多学生可能是老师让用啥就用啥.没接触过svn对比自然无从谈起.所以面试问这个并不聪明. 其实单就学校这个场景,几名老师+每年几十名学生,单人/分组作业,如果当事人都能熟练使用,恰好能发挥git的优势;但”都能熟练使用”可能不太容易.
    • git对比svn的几个区别
      • 0.github。这个没啥可说的,如果你项目有上github的需求,至少应该让项目经理用git来做这件事;研发继续用svn无妨.同理,如果我想给公司一份自己再留一份(到外网),肯定比svn方便.
      • 1.分布式vs中心式。公司视角下这个很可能是缺点,你代码服务器天天down,公司还开不开,it部门工资还要不要.反之,实习生更容易找到机会把其他东西拷走;护网你家被社攻的时候也会更狼狈.
      • 2.分支管理+强制本地解决冲突。这俩特性是一体的.要求本地解决冲突,就必须做更好的分支管理功能,你团队越内聚,这个功能就越没用;别说”我们组5个人,有开发需求拉5个分支”这种笑话.只有当你的小组经常需要跟大项目合代码的时候,才有用.后端极少遇到这个情况,中台可能有一些,客户端超级app用得到;大型游戏团队需要,但游戏团队恐怕接受不了下一条.
      • 3.为了实现本地merge,需要付出一定代价。代价指的是开发人员精力+本地存储.很多时候我们知道自己的代码没有外部耦合、其他分支改出来的问题我也没法帮他修正,在svn里是可以把我改动的部分传上去的,git不允许,git规定谁要push就得先把merge做完.比如游戏,其他分支改了1000个资源文件索引,这跟我有啥关系?游戏配置文件(策划表)可能比较大,大到以G甚至以T计,每人本地存一套还得了?再比如做android系统的,系统源码100+G,拿服务器编译一次俩小时.整个项目40M,同事可能考下来学学;你项目10T,谁爱看谁看好吧.随着协作者人数、项目总体积增大,git的优点会变成缺点;而要不断设置分支权限、缩小每个小组、每个人的管辖范围,那为啥不用svn呢?
      • 4.svn远端同步有个好处,远端可以收集一段时间内的commit,整体分析、然后自动处理掉很多冲突.
      • 5.ai工具上马后git优势会更明显.
    • ps.有人说git可以敲命令行。在现实团队中,cvs软件能用GUI绝不要用命令行.GUI可以强制规范每个人的操作习惯,而这正是cvs的必要环节.
  59. 挖坑了,不要写Nginx配置,除非真了解各种功能如何配置
  60. 挖坑了,不要写利用MinIO分布式系统存储静态页面,代替数据库访问。大量级还有分发云服务CDN之类的加速静态页面加载的东西,存储只是一个很小的点。使用静态页面说明访问量级已经达到Redis都扛不住的情况了,动态页面最主要的消耗是查数据库出数据,优化一般把数据上Redis缓存(百万级),还不行才用静态页面(,例如京东首页){使用一个流程模板引擎,不断把数据库里的的数据读出并生成新的静态页面,可能每分钟生成一个静态页面,每分钟更新页面上的点赞、评论之类的变动数据}
  61. 挖坑了,不要写使用字典树对输入的文本进行敏感词的检测;字典树是对英文的,一层只有26个字母,但是放到中文上一层就2000-5000,根本就不对,可以试试ElasticSearch利用Ik分词器去做分词检测,将敏感词也保存到分词器的配置文件中,这样只要文本中有敏感词,必定会被IK分词出来;且在商业上,敏感词是动态的,一定不是自己实现的,只要有一个词没考虑到,系统就可能会封
  62. 挖坑了,不要写 简历别写 分布式相关的,优惠券使用 Redis 分布式锁,解决超卖和一人一单的问题;三个问题,为什么用分布式锁?量级很多的话,用锁会不会造成业务假死?券是券池还是当时生成?;券可以预生成的,而且每个券都是唯一的券码,为什么不直接在单个redis放可用的券码(秒杀场景是人多券少,数量100万张以下的券{一般几千几十万}单个redis就能存下无需分布式),直接操作即可。
  63. 挖坑了,不要写 中间件的模拟,造轮子项目(容易变成算法题,算法选型为什么用这种不用另外一种),你知道netty吗?MQ底层就是channel,是怎么实现的?【实验室真实的数据库引擎开发项目可以写】
  64. 挖坑了,不要写 对项目所有错误返回,统一进行接口返回信息和错误码,并封装了全局异常处理(全局异常处理是最后的屏障,异常拦不住了才用),正常商业项目不用统一整理错误码(除非甲乙方合作类,例如微信支付公开的开放API会整理所有错误返回,统一进行接口返回信息和错误码的整理,方便对方排查出现问题的是自己程序还是微信支付提供的API)
  65. 挖坑了,不要写 使用 Redis 的位图 BitMap 实现用户的签到功能,redis内存空间不值钱,大量的数据都在放到缓存里,没必要为一个小功能所谓的单独优化,用位图虽然节省了空间,但是却增加了计算消耗。目前都是用空间换时间;场景题:签到流程是怎么样的,发现对个人签到来说是一个之前数据是低频的,当前数据也是低频的事情,用不到缓存,MySQL存就好,以前的签到数据是死的且不用经常查询;但是上班打卡的话,签到时间比较集中,可以考虑使用缓存先存缓存,再定时任务批量保存到数据库
  66. 问道不会的场景题可以说没接触过,不要强答
  67. 文章审核是同步场景,审核完了才能反馈结果给用户
  68. 算法实验室项目,展开来写针对什么问题?怎么处理?怎么生成?怎么做模型?
  69. 真实性问题 怎么跟测试进行沟通,团队有多少开发多少全职员工,项目是怎么上线的(可以以实习的名义,简单绕过,实习生不让上线,只能测试环境,测试环境流程也要明白。但是只是一个判别问题,一两句话描述一下就行{通过git或svn提交对应的版本分支,通过自动化工具jenkins来发布分支,通过日志工具远程到日志环境看运行情况有没有bug,有bug就回滚再次发布});
  70. 前端知识点Websocket协议、sse协议
  71. 前端Honor商城项目的首页是有大亮点的,比如自适应和轮播兼容等;搜索模块更是要考虑点击的频度,可以很好的展开和强调难点。
  72. 前端组件封装,文件上传模块(上传给腾讯云阿里云,跨域、安全、认证、时效性、文档参数不一样),商用回复(二级评论{对评论的评论},一级能有头像二级不可以,能不能富文本,能不能表情包,能不能点赞,不同级别可选,发布列表排序,能不能展示,关键字过滤,回复去重,防抖,发图的大小尺寸比例折叠压缩满足移动端要求)。

项目整理和小亮点(小亮点别写到简历上)

对于此项目,别人的面经[免费接口守护平台(API开放平台{API Harmony Hub})项目面经与整理](点击跳转查看),大致看看不一定对

Java里面你了解的一些锁,按照锁的粒度排个序?

提到我会Docker,说一下Dockerfile你经常用的一些命令?

数据库IO是对项目性能影响较大的,能不查数据库就不查,先对参数判断再执行下面的流程

在数据库里图片存为访问链接

后端接口设计入参要给前端用

Spring里的entity一般要实现get、set、toString方法

使用注解@Slf4j后代码里打印日志用log.info(“xxx”)、log.error(“xxx”)等方法

按10条分页最后正好剩10条时,前端怎么不显示下一页?

每次多查1条,如果能查到11条后面就还有,只能查出11条以下后就表示没有下一页了

部分具体亮点(可以酌情在面试中提出)

  1. 小说是否更新爬虫抓取周期,白天15分钟一次,半夜12点到早上6点没30分钟一次,更新集中时间段每3分钟一次
  2. 流水插入失败也要能自动重插,不要让用户又再输入一遍
  3. 把所有非法校验抽离出来形成一个方法,用返回值标记校验成功还是失败
  4. Controller的接口是对外的,参数一定要做比较到位的校验,不能能完全依赖前端;Controller一上来先验证参数
  5. 一般Controller的接口逻辑是独一无二的,Service的逻辑是可复用的;所以可以先全部写到Controller里面,再把重复的接口逻辑抽离出来放到Service里
  6. Service的方法入参和返回值不要是map类型ResponseDO<Foo>类型,别人要用的话还得看map里要哪些参数/返回的map里有哪些参数
  7. try catch在商用环境里不要随便用,会捕捉不到报错信息,一般throw
  8. 评分、钱……小数 在MySQL数据库可以用decimal类型存,不用float
  9. 分页接口不要对前端暴露分页的size,分页的size后端一般定死了为几个值(,例如10,20,50,100),前端选择size的编号即可;若暴露可能导致前端恶意请求传入一个大的size分页对数据库破坏;
  10. 商业返回要有明确的错误信息,不能使用统一的错误码,例如400,404,403等,因为这些错误码对用户来说没有意义,用户需要知道具体错误
  11. ip在请求头里一查就能查出来
  12. 商用代码脚本要审核后才能上线,尽量别使用 MyBatis Plus 不好审核
  13. 使用NumberUtil类字符串转数字,String的parseInt()方法会抛出异常,而NumberUtil类会自动处理异常
  14. 方法参数在能用基本类型时尽量用基本类型,不用包装类,传入的参数一定要判空

Spring Controller返回对象:一般BaseResponse<T> 有三个字段data、message、code,并有success、error两个抽象方法,Controller返回BaseResponse<T>变JSON给前端返回;Controller的参数有默认的HttpServletRequest、HttpServletResponse,还有自己定义的参数

  1. 直接返回对象(Foo):如果你的API要求简单并且不需要添加任何额外的状态码或者响应头,那么你可以直接返回一个对象。Spring MVC会使用HttpMessageConverter将该对象转换为JSON或XML格式,依据请求中的Accept头部信息。
  2. 返回ResponseEntity<Foo>:当你需要控制更详细的响应细节,比如状态码和响应头时,你可以返回ResponseEntity<Foo>。ResponseEntity是Spring的一个泛型类,它代表了整个HTTP响应,包括状态码、响应头和响应体。
  3. 返回自定义的响应对象(如ResponseDO<Foo>或ResponseDO<Object>):如果你想要一个统一的响应格式,你可能会创建一个自定义的响应对象来封装状态信息、消息和数据。这使得你的API响应具有一致的结构,便于客户端处理。ResponseDO<Foo>使用泛型可以提供类型安全,而ResponseDO<Object>则可以接受任何类型的对象作为数据,两者有各自的使用场景。通常,强类型的响应ResponseDO<Foo>更受推荐,因为它提供了更好的类型安全和文档表达。当然,ResponseDO<Object>在某些情况下也适用,特别是当返回的数据类型不是固定的时候。

别听校招vip瞎忽悠,代码还没鱼皮懂,可能数据库设计好点 上GitHub搜代码,看看顶级开源项目咋写的,乐 apache顶级开源项目incubator-seata的代码,自己按这个学着写就好,Spring里也是用泛型

Enum枚举类里要有枚举常量、私有字段、一个全参数构造方法(无需无参构造方法)、get、set、最重要的getById方法(处理从数据库只能拿到id的情况,由数据库得到的id获得枚举值)

Spring 分层,每层当一个模块开发,自己有一个 pom ; Spring 的注解

jar包的入口点是一个main方法,war包的入口点是一个xml文件 Spring内部集成了一个Tomcat再封装了war包,打成jar包可以直接执行(去xml文件),要调优的话要拆开打出来jar包操作 不前后端分离是MVC架构:访问Controller,Controller调用Model查数据,最后展示到View层页面上 前后端分离的架构:Controller -> Service -> Model(Spring Boot里叫Mapper) 简洁分层(少了不少东西,每层当一个模块开发,自己有一个pom):

  1. Controller层
    • Controller(xxxController)
  2. Service层
    • Service服务实现类(xxxServiceImpl)
  3. Interface层
    • Service服务接口(xxxService)
    • Util类(xxxUtil)
    • 枚举(xxxEnum)
    • 常量
  4. Model/Mapper层
    • Mapper(xxxMapper)
  5. Entity/dto层
    • Entity(entity包里){xxx}
      • 放POJO类,一张数据表对应字段的存放在POJO类中
    • DO(dto包里){xxxDO}
      • 在Java编程语言中,“DO”通常是”Data Object”或”Domain Object”的缩写。它是用于表示从数据存储中得到的数据,通常与数据库表结构对应,用于实现领域模型和业务逻辑。例如,一个用户的DO可能包含用户名、密码和其他个人信息,这些信息直接映射到数据库的用户表。这样的对象主要用于数据访问层(DAO),通过DAO层向上传输数据源对象。简而言之,DO是从现实世界中抽象出来的有形或无形的业务实体

默认的固定方法闷头正向写(Model/Mapper -> Service -> Controller) 业务逻辑的方法的反向写(Controller -> Service -> Model/Mapper) 一般业务逻辑校验是判定异常就return或抛错误,这样就只写if不用写else方便

VO、DTO、DO、PO是在软件开发中用于数据处理和传输的不同类别。它们通常用于Java编程语言中,但也可以应用于其他编程语言。这些类别有助于在软件开发中组织和管理数据,确保数据在不同层之间正确传输。下面是它们的简要说明:介绍的网址

  1. VO(View Object): 显示层对象,通常是 Web 向模板渲染引擎层传输的对象。值对象,主要用于表示层和控制层之间传输的数据。它通常包含展示给用户的数据。
  2. DTO(Data Transfer Object): 数据传输对象,Service 或 Manager 向外传输的对象。数据传输对象,用于不同系统或应用层之间传输数据。它可以包含多个对象的数据,以减少网络请求次数。
  3. DO(Data Object) / PO(Persistent Object) / Entity: 与数据库表结构一一对应,通过 DAO 层向上传输数据源对象。数据对象,通常与数据库表结构相对应,用于表示从数据存储中得到的数据。
  4. BO(Business Object): 业务对象。由 Service 层输出的封装业务逻辑的对象。
  5. AO(Application Object): 应用对象。在 Web 层与 Service 层之间抽象的复用对象模型, 极为贴近展示层,复用度不高。
  6. Query: 数据查询对象,各层接收上层的查询请求。注意超过 2 个参数的查询封装,禁止使用 Map 类来传输。

Maven的好处是能很好的管理包(管理共用jar包),按分出的几层,每层当作一个模块(使用一个pom)来开发,主目录放一个父pom管理此项目中的每个模块的pom(每层)

Spring Boot 分类中 Template Engine(模板引擎):做前端的 Spring Boot 分类中 Spring Session:分布式Session Spring Boot 分类中 SQL:引入数据库组件MySQL Driver、Mybatis Framework Spring Boot 分类中 NoSQL

接口的方法要写注释,要Junit写测试

String判空可以用StringUtils工具类 自己写工具类,方法一般都是public static的

1
2
3
4
String name;
if(StringUtils.isEmpty(name)){
return null;
}
  • Java9后处理日期时间用DateTime,一些用法
  • 在Spring框架中,@Autowired 是根据类型进行注入,而 @Resource注解默认是通过名称来进行依赖注入的。如果没有找到匹配的名称,那么它会退回到类型匹配。这意味着如果你的bean名称不匹配,Spring会尝试按类型来注入相应的bean。这是一个备用选项,以确保如果名称不可用,依赖仍然可以被注入。 @Qualifier注解通常与@Autowired一起使用@Qualifier能指定名字
  • 在Spring框架中,@Data注解是Lombok库的一部分,用于简化实体类的代码。当你在类上使用@Data注解时,它会自动为该类生成getter和setter方法,以及equals、hashCode和toString方法。这样,你就不需要手动编写这些通常是标准的Java代码,从而使得代码更加简洁并减少了潜在的错误。记得要在你的项目中添加Lombok依赖才能使用@Data注解。
  • 在Spring框架中,@RestController注解是一个用于创建RESTful Web服务的便捷方式。它是@Controller和@ResponseBody注解的结合体,这意味着它不仅将类标记为Web请求的处理器,同时也确保响应是直接以JSON或XML格式返回给客户端的,而不是导航到一个视图。
  • @RequestMapping(“/user”)在Controller类上就表示这个Controller类所有请求前都加上/user来访问,@PostMapping(“/register”)、@GetMapping(“/getCaptcha”)在方法上表示这个方法是POST请求或GET请求,方法参数中的注解 fooFunction(@RequestParam(“name”) String name)表示这个URL查询参数中的name的值会被自动提取并赋值给方法的name参数,fooFunction(@RequestBody User user)表示这个请求的body中的JSON或XML数据会被自动转换成User对象
  • 在Spring框架中,@RequestBody注解用于将HTTP请求的body部分绑定到一个对象上。这通常用于处理POST或PUT请求,其中请求的body包含了需要被转换为Java对象的JSON或XML数据。请求的body中的JSON或XML数据会被自动转换成User对象。
  • 在Spring框架中,@RequestParam注解用于从请求的URL查询参数中获取值。这个注解通常用于处理GET请求,其中URL中包含了需要被提取的参数。URL查询参数中的name的值会被自动提取并赋值给方法的name参数
  • 在Spring框架中,@Controller注解用于标记在一个类上,使用它标记的类就是一个SpringMvc Controller对象,分发处理器会扫描使用该注解的类的方法,并检测该方法是否使用了@RequestMapping注解。@Controller只是定义了一个控制器类,而使用@RequestMapping注解的方法才是处理请求的处理器。
  • 在Spring框架中,@Service注解通常用在Service服务层,主要涉及一些复杂的逻辑,需要用到Dao层。
  • 在Spring框架中,@Component是一个通用的注解,可以标注任意类为Spring的组件。如果一个Bean不知道属于哪个层,可以使用@Component注解标注。这个注解通常是通过类路径扫描来自动侦测以及自动装配到Spring容器中
  • 在Spring框架中,@Repository注解主要用于标注数据访问层,也就是DAO层的组件。
    • DAO层,也被称为数据访问层,是软件架构中的一部分,主要负责与数据库进行交互。
    • 在实际开发中,DAO层通常会定义为接口,然后提供具体的实现类来完成数据库操作。这样做的好处是,当数据库发生变化时,只需要修改DAO的实现类,而无需修改业务逻辑层的代码。
  • 在Spring框架中,@Bean注解用于告诉方法,产生一个Bean对象,然后这个Bean对象交给Spring管理。

String 可以设计有占位符的模板

用 String.format() 来向模板的占位符里插入数据

%d:表示整数类型(十进制)。 %c:表示单个字符。 %b:表示布尔值。 %f:表示浮点数类型。 %e or %E:表示科学计数法的浮点数类型。 %x or %X:表示十六进制整数。 %o:表示八进制整数。 %t:表示日期/时间值(后面需要跟具体的时间或日期格式指示符例如 %tB 表示 locale-specific 月份名称,%td 表示一月中的日子等)。 %%:表示文字%字符。

1
2
String exampleFormat = "Name: %s, Number: %d, Decimal: %.2f, Flag: %b";
String formattedString = String.format(formatExample, name, number, decimal, flag);

POJO类全属性private,只能用get/set操作属性,好处是啥?

  1. 可以监控get/set方法,看哪里调了,如果分析出调用次数非常多,可以考虑做个集群或者把次POJO类分到一个性能更好的地方

三次握手时在客户端和服务器端等待对方握手时的状态是啥?明确TCP协议里的标志位的变化?说出在握手过程中每个端的等待状态?

  1. 说出在握手过程中每个端的等待状态
  2. 明确TCP协议里的标志位的变化

记录用户点赞用MySQL就行?

  1. 因为这是分两步的,第一步要先记录哪个用户对哪个帖子点了赞(也可以选择不实现此功能),这个操作是一对一的,此行为每个用户都得分开看,只看一个用户的话就是低频操作,第二步记录帖子的总点赞数,这个操作是多对一的,才是高频操作,可以考虑Redis。
  2. 量级不大用户数据还是可以放在MySQL里,而不用放在Redis里,数据库的读写性能差,用户数据经常变怎么优化?
    • 优先对MySQL主从分离,唯一索引
  3. 记录热帖的总点赞数才用Redis记录并且定时任务同步到MySQL数据库里,因为热帖的点赞数是高频操作

搜索如何实现主库从库的分离?分离的数据同步是怎么实现的?搜索的质量和性能?怎么样怎么能够去多姿段查询?搜索的字段维度?

后端数据库里储存什么值来让前端判断渲染权限对应的界面(无权限的页面、按钮…… 隐藏)?

在数据库设计中,通常并不直接存放与前端按钮可见性或交互性相关的信息。这些通常是前端应用的实现细节。数据库层面关心的是数据的结构和完整性,而对如何展示或使用这些数据并不涉及。前端的可见性和可交互性通常是基于用户的角色和权限来决定的。(例如,我用的Vue/React框架)

  1. 目前前端通过 loginUser.userRole 的函数获取数据库中 userRole 字段的值来判断渲染 user/admin 权限对应的界面(没权限的不渲染,隐藏)
  2. 所以修改 userRole 字段类型为 tinyint 的话,前端通过 loginUser.userRole 的函数获取到的值就是 tinyint 类型的,前端判断权限的语句得改

不过,如果你需要后端控制前端按钮的显示与否,你可以在数据库中设置相关的权限控制表。例如:

  1. 用户角色表:定义了可用的角色。
  2. 权限表:定义了不同的权限,每个权限对应前端界面上的一个或多个元素如按钮
  3. 用户角色权限关联表:标识每个角色拥有的权限。

这样前端应用可以根据用户的角色和关联的权限动态地显示或隐藏按钮,或设置其为不可点击状态。例如:

  1. 当用户登录时,前端应用会查询数据库或通过API获取后端数据库用户角色字段。前端根据用户角色字段,决定渲染什么权限的字段
  2. 是否渲染特定的按钮或将其设置为不可用状态或更改描述。如管理员点击封禁用户并且用户状态变成封禁后,前端原本显示封禁的按钮要变成显示解封,前端可以通过API查询后端数据库用户状态字段,通过字段值判断怎么渲染

某些客户端框架可能会在渲染之前将权限数据用作渲染决策的依据。(例如,我用的Vue/React) 请注意,即使前端隐藏了按钮,逻辑仍然应该在后端进行验证,以确保没有权限的用户不能通过直接调用API等方式执行不被允许的操作。始终在服务端进行权限检查是保护应用安全的重要措施。

类的变量加static和不加的区别是什么?是不是所有变量都要加static?

  1. 存储位置和生命周期:
    • Static变量:也称为静态变量,它是类的一个类变量,不属于类的任何一个实例。静态变量在类被加载时创建,在程序结束时销毁。无论你创建了类的多少实例,都只有一份静态变量的副本。
    • 非Static变量:也称为实例变量,它属于类的一个实例。每当你创建类的新实例时,都会为非静态变量创建新的副本,且每个实例的非静态变量都是独立的。
  2. 访问方式:
    • Static变量:可以不创建类的实例就直接通过类名访问。
    • 非Static变量:必须创建类的实例才能访问。
  3. 内存管理:
    • Static变量:既然它们只有一份副本,静态变量被所有实例共享,所以它们是一种节约内存的方式,当你的变量值应该在类的所有实例之间共享时。
    • 非Static变量:每个实例有自己的变量副本,因此它们不共享状态,可能会占用更多的内存。
  4. 默认值:
    • Static变量:如果未显式初始化,它们会获得类型的默认值(例如,int的默认值是0,对象引用的默认值是null)。
    • 非Static变量:同样未初始化时,也会获得类型的默认值。

是否所有变量都应该加上static取决于你的具体需求: 如果某个变量应该跨所有实例共享,比如常量、serialVersionUID、配置信息、状态标记或者计数器,那么它应该声明为static。 如果每个实例都应该拥有自己的变量副本,如对象的属性或者状态,那么它就不应该是static。 滥用static会导致设计上的问题,比如对于那些应该是实例独有的属性,如果进行了static声明,就会引起不必要的数据共享,可能会引发安全问题或是逻辑上的错误。因此,不是所有变量都适合加上static。

MySQL怎么分页?怎么查全部分类的条目?

1
SELECT * FROM table_name LIMIT offset, count;

其中,table_name为要查询的表名;offset指定从第几条记录开始返回结果(索引值从0开始);count指定每次返回多少条记录。

可以用 WHERE type != 0 这种限制条件,查全部分类的条目。动态多条件查询,例如Mybatis的mapper的xml中写:

1
2
3
4
5
6
7
8
9
10
11
12
SELECT * FROM BLOG 
<where>
<if test="state != null">
state = #{state}
</if>
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</where>
1
2
3
4
5
6
7
8
9
SELECT * FROM BLOG WHERE
Status !=0
<if test="sort == 1">
ORDER BY AddTime desc
</if>
<if test="sort == 2">
ORDER BY SubscribeNum desc
</if>
limit #{offset},#{size}

项目的架构你是怎么设计的?(简历别写分布式相关的,面试聊想法时可回答)

  1. 我采用前后端分离的架构,前端 Ant Design Pro 使用Nginx部署,通过Nginx 反向代理将请求转发到 web 项目(注意通过反向代理这句话不一定对,我在 Ant Design Pro 打包生成的前端没用上),因为项目刚刚上线,所以这里暂时采用了单机部署的模式,未来可能采取水平扩容的方式,增加多台节点,通过Nginx 的负载均衡,将请求平均的分发到我的每个节点上,以支撑更高的并发。
  2. 我的 web 项目使用Spring Boot开发,并连接到了数据库和 Redis,数据库使用的是 MySQL,主要用来存储用户的信息和接口的信息;通过 Redis 实现了分布式 session,因为考虑到未来要使用分布式架构,为了避免使用 tomcat 保存 session 有用户登录失效的问题。

注:这里我说出了反向代理,水平扩容,负载均衡等技术名词,很多面试官会根据这些名词进行延伸提问(引导面试官往自己熟悉的东西上提问)比如:说说什么是正向代理/反向代理?什么是水平扩容?什么是负载均衡?你了解哪些负载均衡的算法?提前准备好这些知识之后,就可以跟面试官一顿输出了。

你怎么做的技术选型?为什么要用这些技术?(简历别写分布式相关的,面试聊想法时可回答)

  1. 使用 SpringBoot 是因为通过自动装配能够提高项目的开发效率,还能够很好的整合其他服务
  2. 使用 MySQL 的原因是因为考虑到未来有用户充值交易,限制调用次数等场景需要用事务保证数据的完整性和一致性
  3. 使用 Redis 的原因是因为可以用来实现分布式 session、缓存等功能。因为 Redis 是一个单独的中间件,不同客户端可以往同一个 Redis 或者集群中存放session/缓存,这样就能保证资源能够在分布式服务下都可见
  4. 并且由于Redis 也是单线程的,同时也支持 lua 脚本,可以保证并发安全的问题,所以可以很简单的实现分布式锁的功能。(简历别写分布式,面试聊想法时可回答)

注:被面试官追问自动装配的原理你了解过吗?自动装配是怎么实现的?分布式 session 的原理?

为什么你要使用网关?Spring Cloud Gateway网关有什么用?

  1. 见链接
  2. 我这个平台的关键点就在于提供接口服务,要保证接口的可用性和稳定性,所以将接口服务独立部署在另一台机器上,隐藏真实的接口地址及端口,调用接口服务的请求都必须经过网关流量染色之后…… (这里细节太多,比如 rpc 调用获取用户sk,重新生成签名认证等等) 之后,将请求转发到真实的接口地址(网关就是个代理),防止接口被恶意调用、盗刷。(知道了真实地址和端口还可以DDOS攻击)
  3. 有网关后,前端抓包就只能发现请求的是网关地址,只能得到网关的真实地址,接口服务的真实地址无法得到。

注:这个问题要对网关做了什么事情非常非常熟悉,建议反复观看鱼皮大佬的直播回放。

为什么使用 RPC 调用?有了解过其他的方式吗?

  1. 因为如果在网关引入数据库的操作的话,不仅会增加项目体积,还违背了设计原则的单一职责原则降低了系统的可维护性,所以我考虑通过服务间调用的方式,我了解过有两种方式,第一种是Open feign,原理是构造了一个 HTTP 请求,并会添加很多的请求头,body 是使用 json 字符串传输,所以调用效率会比较低,更加适合外部服务间的调用。
  2. 然后我了解到RPC是可以基于 TCP 协议,避免了无用的请求头,以及可以通过将数据序列化为二进制流的形式传输,效率更加高效,更加安全,所以更适用于我这个场景。最终我选择了 Dubbo RPC 框架来实现这个功能。

你的接口调用次数统计以及排行是怎么实现的?可以做接口热度的排行榜,排行榜变动时的性能压力,怎么优化解决?

答:通过 MySQL 统计,每次调用结束后,网关都会发起一个 rpc 请求,调用次数+1。

注:这里我会抛出一个设计缺陷,在实际测试过程中,通过 jmeter 压测工具,会出现调用次数不准的情况,原因是因为没有在业务层面加锁,导致数据库出现并发写的问题。并且并发量大的话,对数据库造成很大的压力。引导面试官问出,那你有什么更好的解决方案吗?

  1. 等调用完api接口并成功返回后才让数据库中的统计数据加1,容易形成并发写(MySQL写入时加写锁),用Redis代替MySQL
  2. 如果在业务层面加一个写锁的话,会影响业务的执行效率,所以我想使用 Redis 去解决,Redis 有一个数据结构 Zset 支持排序,score 可以用来存储调用次数,并且 Redis 是单线程,可以解决并发问题。 如果用 MySQL 实现接口热度排行榜,每次生成接口热度排行榜时,取出数据后还需要对数据排序排行榜更新变动时的性能压力大

注:这里被追问过 Zset 的底层实现,以及如何将这些数据进行持久化保存,防止 Redis 宕机导致数据丢失,可以从 AOF,RDB 展开来讲,或者在后台开启一个定时任务,定时每分钟将这些数据进行落库

你做过什么优化吗?你接口的性能怎么样?

答:我有一个接口是随机返回土味情话,我在数据库中插入了几千条土味情话,当调用接口时随机返回一条。在还没有优化前,接口的 qps 在 300左右,但是考虑到这个接口只有读操作,没有增删改操作,所以我将这张表的存储引擎从 Innodb 改为了 MyISAM,接口的qps 提升到了 1500

注:被面试官追问为什么改为 MyISAM 有这么大的性能提升?Innodb 和 MyISAM 有什么区别? 这个问题一定要根据自己实际情况来答,根据自己擅长的方面,比如对查询语句做了索引优化,提升了接口的性能。

Spring 常用方法与注解?

  1. 见链接
  2. Spring @Scheduled任务它默认有一个线程池大小为1的线程池,Controller方法默认多线程并发,或者@Async注解标记异步实现的方法也是多线程并发
  3. @PostConstruct是Java自带的注解,在方法上加该注解会在项目启动的时候执行该方法,也可以理解为在spring容器初始化的时候执行该方法,可作为一些数据的常规化加载,比如数据字典之类的。
  4. @SpringBootApplication 包含 @ComponentScan 默认扫描配置类所在目录下的所有包(以配置类所在目录为根目录) 还要扫描别的位置的话,需要自己在注解里写明

搜索怎么实现?怎么实现多字段查询?搜索的字段维度?

Token核心字段?

  1. userId
  2. 有效期

user/admin 访问的身份如何控制

使用 Spring 中 AOP 配合自定义注解进行鉴权(目前只实现了方法拦截, 对类拦截要使用反射[后续可能更改为Spring Security]) ; 具体实现在/aop/AuthInterceptor 和 /annotation/AuthCheck 中