2022-05-04 00:11阅读: 17评论: 0推荐: 0

项目笔记整理

一、背景介绍

此次项目依托于微信小程序,用于线上预定酒店的产品。

二、使用到的技术(技术架构)

nginx、springCloud-gateway、SpringBoot、Nacos、Docker 、ElasticSearch、Kafaka、Beats、Logstash、kibana

DNS解析:客户端、WAF、CDN、防火墙、Nginx集群

服务监控:spring Boot Admin
注册中心:Nacos注册中心 —> 注册与发现、服务注册
Webflux网关:springCloud GateWay -----> Ribbon、Sentinel(熔断降级)
认证接受、动态路由:Seatinel+Shard

配置中心:Nacos配置中心 ----> 动态配置、配置管理
业务集群:QAuth2.0认证、Spring Security、SpringBoot应用、OpenFeign
持续化: Master Slave、Mysql
消息队列:Mirror、RabbitMQ

监控中心:Skywalking -----> 链路追踪、监控警报
分布式 主键:分布式锁、分布式事务、CAP、BASE
全文检索:Shard、ElasticSearch
对象存储:OSS

运维报警系统:Prometheus、Grafana、Alertmanager -----> 短信、微信、邮件
日志系统:Kafaka、Beats、Logstash、kibana、ElasticSearch
任务管理: XXL-JOB

Developer—> Github —> docker -----> Kubermeters API ------> K8S UAT/PROD-----> Jenkins Plpeline -----> OP运维

三、项目流程概述

主线:梳理产品流程、数据库设计(E-R图)、接口设计、编码、前后端联调、项目上线、整理成文档、项目总结。
支线:数据库设计前:环境搭建、项目熟悉、开发工具、阿里规范手册
           项目任务:基础服务、功能分配
           阶段性任务:第一阶段需求开发、技术需求
                                 第二阶段需求开发、技术需求
           优化:代码 review、代码优化
           验收:技术博客、项目整体验收

四、 问题注意事项梳理

注:不同公司有不同的规范,需要遵循。

4.1 数据库设计注意事项

命名上:单词与单词使用下滑线连接
              不能简写单词,要见名知意
规范上:表中字段大小写统一,别混合大小写
               表中不能有外键
               少用中间表
                表中字段多数尽量设置不能为空,避免空指针异常
                每个字段长度,要合理
                前缀不加is,例如:不用 is_status类似的作为状态
                金额、评分都使用整型
                表中有创建时间、最后一次执行时间
                正确使用update_time
                表中得有逻辑删除

注:为什么不使用is作为前缀?
如果加的话哪个mybatisGenerator生成代码的时候会自动生成is_,这样序列化就会报错,如果改也比较麻烦

4.2 接口设计注意事项

命名上: 接口别使用驼峰,使用杠(-)来命名,例如:enum-list
                前台统一使用,/项目名/模块/方法 ,例如:/hotel/search/enum-list
                后台统一使用 /admin/项目名/模块/方法,例如:/admin/hotel/search/enum-add

规范上: 不使用RestFul风格
                数据结构统一字段名

es部分: 查询接口
                搜索接口
                枚举值四个接口,增删改查

4.3 代码编写注意事项

命名上: 使用驼峰命名

规范上: try-catch异常内容写入日志
                统一返回值
                关键地方使用try-catch
                所有异常都回滚,拼接字符串的使用
                写完整的注释
                设置非空验证,进行校验
                过长代码能进行抽取尽量抽取出来封装成类或者方法,代码需要整洁
                service调service
                使用lamba表达式、流
                异常在service层写
                实现类不加I,只有接口加I,例如:HotelService-> IHotelService
                data里面传true,尽量别用null
                在controller层返回的结果,不论失败还是成功都返回成功的结果。
                对于一些常量,需要提取出来

五、 总结

1、在这次项目中,学到了项目中的开发流程,熟悉产品、数据库设计、接口设计、代码编写、前端联调,每一阶段做什么,遵循什么规范,团队协作技巧
学到了一些编码规范,代码规范比如常见的判断非空,使用哪些需要判断为空的工具,对一些hutool工具的使用,业务层中使用IService等
代码优化方面,对一些能代码比较多的能提取出来的就提取出来或封装成一个方法,尽量代码简洁。
2、每次会议也学到许多技巧的,比如面试技巧,一些细节注意点,工作中遇到的问题,每次都了解了一些行业情况。
3、不足的地方也挺多的,比如编码能力、相关技术的学习、相关技术底层原理了解等都还不够。

附件:

1.1 项目中接触到的中间件:

网关:Nginx、Kong、Zuul
缓存:Redis、MemCached、OsCache、EhCache
搜索:ElasticSearch、Solr
熔断:Hystrix、resilience4j
负载均衡:DNS、F5、LVS、Nginx、OpenResty、HAproxy
注册中心:Eureka、Zookeeper、Redis、Etcd、Consul
认证鉴权:JWT、SpringSecurity
消费队列:RabbitMQ、Kafka、RocketMQ、ActiveMQ、Redis
系统监控:Grafana、Prometheus、Influxdb、Telegraf、Lepus
文件系统:OSS、NFS、FastDFS、MogileFS
RPC框架: Dubbo、Motan、Thrift、grpc
构建工具:Maven、Gradle
集成部署:Docker、Jenkins、Git、Maven
分布式配置:Disconf、Apollo、Spring Cloud Config、Diamond
压测:LoadRunner、JMeter、AB、webbench
数据库:MySQL、Redis、MongoDB、PostgreSQL、Memcache、HBase
网络:专用网络VPC、弹性公网IP、CDN
数据库中间件:DRDS、Mycat、360 Atlas、Cobar
分布式框架:Dubbo、Motan、Spring-Could
分布式任务:XXL-JOB、Elastic-Job、Saturn、Quartz
分布式追踪:Pinpoint、CAT、zipkin
分布式日志:elasticsearch、logstash、Kibana 、redis、kafka
版本发布:蓝绿部署、A/B测试、灰度发布/金丝雀发布

1.2 项目时间线

在这里插入图片描述
1.3接口设计

1.3 编码细节

1.设置非空验证
官网:http://hibernate.org/validator
例如:

public class Car {
​
   @NotNull
   private String manufacturer;
​
   @NotNull
   @Size(min = 2, max = 14)
   private String licensePlate;
​
   @Min(2)
   private int seatCount;
​
   // ...
}

2.一些配置不要放在业务层
例如:

@Configuration
public class DruidConfig {
​
    /**
     * 配置Druid 监控启动页面
     *
     * @return servletRegistrationBean
     */
    @Bean
    @ConditionalOnMissingBean
    public ServletRegistrationBean<Servlet> druidStartViewServlet() {
        ServletRegistrationBean<Servlet> servletRegistrationBean = new ServletRegistrationBean<Servlet>(new StatViewServlet(), "/druid/*");
        // 白名单
		// servletRegistrationBean.addInitParameter("allow", "127.0.0.1");
        // 黑名单
        servletRegistrationBean.addInitParameter("deny", "192.168.1.100");
        // 登录查看信息的账密,用于登录Druid监控后台
        servletRegistrationBean.addInitParameter("loginUsername", "druid");
        servletRegistrationBean.addInitParameter("loginPassword", "druid");
        // 是否能够重置数据
        servletRegistrationBean.addInitParameter("resetEnable", "true");
        return servletRegistrationBean;
    }

3.不用try catch
使用全局捕捉异常,例如:GlobalExceptionHandler、ApiException直接引common模块使用。
4.if else问题
可以直接if return让代码简洁。

if(){
    ...
}
return ...

5.日志打印问题
主要流程关键环节加日志 , 错误的不用加入日志,目的节约资源
6.接口注释写好增加可读性。
7.if else特别多时用switch语句,让代码干净整洁些。
8.相应模块写在对应模块里,例如admin的写admin模块里。
9.使用mybatis-plus ,例如Service直接继承Iservice的方法简洁代码
例如:

public interface IEnumService extends IService<EnumType> {
    
    /**
     * 查询所有枚举
     *
     * @return 枚举
     */
    List<EnumType> getDictItem();
}

例如:接口需要带一个 I

public interface IEnumService extends IService<EnumType> {

    /**
     * 查询所有枚举
     *
     * @return 枚举
     */
    List<EnumType> getDictItem();
 }

10.minio上传文件单独写一个service
例如:
minio官网:http://www.minio.org.cn/
在这里插入图片描述

11.字符串拼接问题
12.redis的使用要修改
13.mybatis-plus使用LambdaQueryWrapper通过方法引用的方式来使用实体字段名的操作
例如:

LambdaQueryWrapper<User> lambda = Wrappers.<User>lambdaQuery();
lambda.like(User::getName, "xaoming").lt(User::getAge, 40);

14.lamba表达式和流的使用
例如:

List<HotelDTO> collect = list1.stream().map(item -> {
    HotelDTO entity = new HotelDTO();
    entity.setCityName(item.getCityName());
    entity.setKeyWord(item.getName());
    return entity;
}).collect(Collectors.toList());

15.大小写问题,例如使用DTO,而不使用Dto;使用VO,而不使用Vo;使用DAO,而不使用Dao;
例如:DTO的使用

@Data
@AllArgsConstructor
@NoArgsConstructor
@Validated
public class HotelDTO {
    @ApiModelProperty(value = "关键字/城市/品牌/酒店名")
    private String queryText;
    @ApiModelProperty(value = "附近地标")
    ...
 }

VO的使用

@Data
@AllArgsConstructor
public class ImageVO {
    private String breviaryPicture; // 缩略图地址
    private String detailPicture; // 详细大图
}

DAO的使用

@Mapper
public interface HotelImageDAO extends BaseMapper<HotelImageEntity> {

}

16.非空用hutool工具
判断集合是否为空,为什么这么使用呢,size可能为0,而不是使用==null
CollUtil.isEmpty()

17.对lombok插件的使用
自定义了构造方法之后,lombok就不会生成有参无参构造方法
18.一些固定的常量提取出,单独封装
例如:
部分代码:

			//查询价格高低使用到"floor_special_price";
			//提取出来为:SearchCode.FLOOR_SPECIAL_PRICE
    		public static final String FLOOR_SPECIAL_PRICE = "floor_special_price";
    		...
			//价格低高排序
            case SearchCode.PRICE_ASC:
                nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort(SearchCode.FLOOR_SPECIAL_PRICE).order(SortOrder.ASC));
                break;
                ...

1.4 Java开发手册

嵩山版与黄山版的区别:
在这里插入图片描述在这里插入图片描述

2022黄山版
【强制】前后端交互的API,需要明确协议、域名、路径、请求方法、请求内容、响应码、响应体。
在这里插入图片描述
3. 【强制】在varchar字段上建立素引时,必须指定索引长度,没必要对全字段建立索引,根据实际文本区
分度决定索引长度。
说明:索引的长度与区分度是-对矛盾休, -般对字符申类型数据,长度为20的索引,区分度会高达90%以上,可以使
用count(distinct left(列名,索引长度)) / count(*)的区分度来确定.

4、 【强制】如果系统中某个功能的调用链路上的涉及对象超过3个,使用时序图来表达并且明确各调用环
节的输入与输出。

6、. 【强制】得使用外键与级联,-切外键概念必须在应用层解决。
说明: (概念解释) 学生表中的student id是主键,那么成绩表中的student id则为外键。如果更新学生表中的
student_ id,同时触发成绩表中的student id更新,即为级联更新。外键与级联更新适用于单机低并发,不适合分布工
高并发生群:级联更新是强阳塞,存在数据库更新风年的风险:外键影响数据库的插入速度。

7、. 【强制】更新数据表记录时,必须同时更新记录对应的update_ time字段值为当前时间。
7.1【强制】禁止使用存储过程,存储过程难以调试和扩展,更没有移植性。

8、 【强制】任何货币金额,均以最小货币单位且为整型类型进行存储。
9、 【强制】表必备三字段: id, create_ time,update time。
9.1 【参考】 @Transactional 事务不要滥用。事务会影响数据库的QPS,另外使用事务的地方需要考虑各
方面的回滚方案,包括缓存回滚.搜索引擎回滚,消息补偿、统计修正等。

9.2 【强制】 POJO类中的任何布尔类型的变量,都不要加is前缀,否则部分框架解析会引起序列化错误。
说明:本文MySQL规约中的建表约定第1条,表达是与香的变量采用is. )ox的命名方式,所以需要在
设置从is. _)o0 到xxx的映射关系。
反例:定义为基本数据类型Boolean isDeleted的属性,它的方法也是isDeleted0.框架在反向解析时,“误以为" 对
应的属性名称是deleted,导致属性获取不到,进而抛出异常,

直接使用deleted字段就可以,如果加的话哪个mybatisGenerator生成代码的时候会自动生成is_,这样序列化就会报错,如果改也比较麻烦
10、 【强制】在数据库中不能使用物理删除操作,要使用逻辑删除。
说明:逻辑删除在数据删除后可以追溯到行为操作。不过会使得一些情况下的唯一主键变得
情解决。.

10.1 [强制] BigDecimal 的等值比较应使用compareTo()方法,而不是equals0 方法。」
说明: equals0方法会比较值和精度(1.0 与1.00返回结果为false)。而compareTo0则会忽略精度。」

这条规则我们直接在数据库定义的时候,表示是与否的情况不加 is 前缀
是说在代码实体类中,不要加is,数据库中要加吗? 都不加。
在这里插入图片描述
11.1 【强制】并发修改同- -记录时,避免更新丟失,需要加锁。要么在应用层加锁,要么在缓存加锁,要么
在数据库层使用乐观锁,使用version作为更新依据。
说明:如果每次访问冲突概率小于20%,推荐使用乐观锁,否则使用悲观锁。乐观锁的重试次数不得小于3次.
11.2 【参考】创建索引时避免有如下极端误解:
1)索引宁滥勿缺。认为一一个查询就需要建一个索引。
2)吝啬索引的创建。认为索引会消耗空间、严重拖慢记录的更新以及行的新增速度。
3)抵制唯一索引.认为唯一索引一律需要在应用层通过“先查后插”方式解决。

11.2 【推荐】防止NPE,是程序员的基本修养,注意NPE产生的场景:
1)返回类型为基本数据类型,return 包装数据类型的对象时,自动拆箱有可能产生NPE
反例: public int method( { return Integer对象; },如果为null,自动解箱抛NPE.
2)数据库的查询结果可能为null.
3)集合里的元素即使isNotEmpty,取出的数据元素也可能为null。
4)远程调用返回对象时,-律要求进行空指针判断,防止NPE.
5)对于Session中获取的数据,建议进行NPE检查,避免空指针。
6)级联调用obj.getA().getB).getC0;-连串调用, 易产生NPE.
正例:使用JDK8的Optional类来防止NPE问题。

11.3【推荐】表的命名最好是遵循“业务名称表的作用”。
正例: alipay_task/force_project/trade_ config / tes_question
12. [推荐]库名与应用名称尽量一致。
在这里插入图片描述
12. 2【强制】杜绝完全不规范的英文缩写,避免望文不知义。
反例: AbstractClass “缩写”成AbsClass; condition “缩写” 成condi; Function “缩写”成Fu,此类随意缩写
严重降低了代码的可阅读性,
13. 【推荐】资金相关的金融敏感信息,使用悲观锁策略。
说明:乐观锁在获得锁的同时已经完成了更新操作,校验逻胡容易出现漏洞。另外,乐观锁对冲突的解决策路有较复杂
的要求,处理不当容易造成系统压力或数据异常,所以资金相关的金融敏感信息不建议使用乐观锁更新。
正例:悲观锁遵循- -锁二判三更新四释放的原则。
14. 【推荐】字段允许适当冗余,以提高查询性能,但必须考虑数据一 致。冗余字段应遵循:
1)不是频繁修改的字段。
2)不是唯- -索引的字段。
3)不是varchar超长字段,更不能是text字段。
正例:各业务线经常冗余存储商品名称,避免查询时需要调用IC服务获取。
15. 【推荐】单表行数超过500万行或者单表容量超过2GB,才推荐进行分库分表。
说明:如果预计三年后的数据量根本达不到这个级别,请不要在创建表时就分库分表。

在这里插入图片描述
ORM映射

  1. [强制]在表查询中,- -律不要使用*作为查询的字段列表,需要哪些字段必须明确写明。
    说明:
    1)增加查询分析器解析成本。
    2)增减字段容易与resultMap配置不- -致。
    3)无用字段增加网络消耗,尤其是text类型的字段。

命名:
A) service / DAO层力法可名机约
1)获取单个对象的方法用get做前缀。
2)获取多个对象的方法用list做前缀,复数结尾,如: listObjects
3)获取统计值的方法用count做前缀。
4)插入的方法用save / insert做前缀。
5)删除的方法用remove / delete做前缀。
6)修改的方法用update做前缀。

es思路:
经纬度的查询,圆形、正方形、多个点的、点与点的之间的

1.5 工具推荐

数据库设计工具:https://www.oschina.net/p/chiner
接口工具:https://www.apipost.cn/

面试题部分整理(答案在Java中高级核心知识全面解析.pdf中)

注:下方答案不完整

基础篇

1、索引有哪些?普通索引、唯一索引…

2、事务的隔离级别:读未提交–>遇到的问题
读已提交–>遇到的问题

3、锁有哪些锁?共享锁、排他锁、行锁、悲观锁、乐观锁

4、进程线程的区别

5、守护线程是什么?

6、线程的生命周期?创建进程,调用runstart可运行状态
创建,就绪,运行,阻塞,结束

7、数组有什么特征?下标从0开始

8、java为什么能跨平台?

9、jdk与jre的区别???jvm、jre、jdk的区别

10、事务有哪些?

11、哪些集合是线程安全的?

12、springBoot常用注解,

13、SpringMVC执行流程(重点)
DispatcherServlet --> HandlerMapping --> Handler --> View

14、SpringBoot中starter为什么自动注入到容器中

15、SpringMVC 中aop(面向切面)跟ioc(控制反转)
环绕通知

16、springCloud工具集常用的五个?

17、hashMap和threeMap区别?
hashMap无,threeMap有序,linked

18、mvcc是什么?

19、ArrayList和linklist的特点
ArrayList可以动态扩容,扩容一半,查询快
linklist没有扩容,插入、删除快。

进阶篇

1、redis与mysql数据怎么能保持一致性?

2、内存屏障
cup三条指令,执行顺序
禁止cpu操作
在这里插入图片描述
3、双亲委派机制

4、如何用两个栈实现队列

5、数据库什么时候会索引失效?
or 中的条件如若都走索引就不会索引失效
索引失效
在这里插入图片描述
注:索引失效

6、可达性分析算法?
导致Full GC的原因:老年代被写满、永久代(Perm)被写满和System.gc()被显式调用

7、可达性分析可以避免引用计数法无法挥手循环引用的情况

8、链表、cs

通过hash运算后两个相同hash值的key在HashMap中是如何存储的? 先equals 再 比较内存地址?
不是key相同,是key的hash值相同,key值不同

双向链表 , cs 直接操作内存,保证原子性

9、链地址法解决hash冲突
在这里插入图片描述
10、redis为什么那么快?
多路复用,

11、selector 选择多个频道?

12、sql执行纪录
sql执行计划是指个执行顺序吗from - where -group by -having - select - order by-limit

13、日志有哪些?
binlog
redo log 重做日志 undo log 回滚日志

14、数据库底层存储引擎哪些?

15、数据库底层存储数据结构哪些?B+树
MyISAM B- InnoDB B+

16、什么是聚合索引?
聚合索引-----> 数据和索引放一起就是聚簇索引

17、select语句加锁没?默认不加锁的,

18、怎么加共享锁、排他锁
后面加个关键字 for update(加的是排他锁) 加锁

19、浅拷贝和深拷贝是什么
浅拷贝和深拷贝?浅,创建指针,指向原来的地址,,深拷贝是创建新内存,复制进去

  1. 浅拷贝:对基本数据类型进行值传递,对引用数据类型进行引用传递般的拷贝,此为浅拷贝。
  2. 深拷贝:对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容,此为 深拷贝。

20、HashMap如何实现的??产生闭环链表

21、hashCode()与 equals()的相关规定

  1. 如果两个对象相等,则 hashcode 一定也是相同的
  2. 两个对象相等,对两个对象分别调用 equals 方法都返回 true
  3. 两个对象有相同的 hashcode 值,它们也不一定是相等的
  4. 因此,equals 方法被覆盖过,则 hashCode 方法也必须被覆盖
  5. hashCode() 的默认行为是对堆上的对象产生独特值。如果没有重写 hashCode(),则该 class 的两 个对象无论如何都不会相等(即使这两个对象指向相同的数据)

22、String StringBuffer 和 StringBuilder 的区别是什么? String 为什么是不可变的?
简单的来说: String 类中使用 final 关键字修饰字符数组来保存字符串, private final char
value[] ,所以 String 对象是不可变的
而 StringBuilder 与 StringBuffer 都继承自 AbstractStringBuilder 类,在
AbstractStringBuilder 中也是使用字符数组保存字符串 char[]value 但是没有用 final 关键字
修饰,所以这两种对象都是可变的
StringBuilder 与 StringBuffer 的构造方法都是调用父类构造方法也就是
AbstractStringBuilder 实现的
线程安全性
String 中的对象是不可变的,也就可以理解为常量,线程安全。 AbstractStringBuilder 是
StringBuilder 与 StringBuffer 的公共父类,定义了一些字符串的基本操作,如
expandCapacity 、 append 、 insert 、 indexOf 等公共方法。 StringBuffer 对方法加了同步锁或
者对调用的方法加了同步锁,所以是线程安全的。 StringBuilder 并没有对方法进行加同步锁,所以
是非线程安全的。
性能
每次对 String 类型进行改变的时候,都会生成一个新的 String 对象,然后将指针指向新的
String 对象。 StringBuffer 每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象
并改变对象引用。相同情况下使用 StringBuilder 相比使用 StringBuffer 仅能获得 10%~15% 左
右的性能提升,但却要冒多线程不安全的风险。
对于三者使用的总结:

  1. 操作少量的数据: 适用 String
  2. 单线程操作字符串缓冲区下操作大量数据: 适用 StringBuilder
  3. 多线程操作字符串缓冲区下操作大量数据: 适用 StringBuffer

23、 System.arraycopy()和Arrays.copyOf()方法 区别:
arraycopy()需要目标数组,将原数组拷贝到你自己定义的数组里,而且可以选择拷贝的起点和长 度以及放入新数组中的位置
copyOf()是系统自动在内部新建一个数组,并返回该数组

posted @   所遇所思  阅读(17)  评论(0编辑  收藏  举报  
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
🔑
点击右上角即可分享
微信分享提示
  1. 1 404 not found REOL
  2. 2 偏爱 张芸京
  3. 3 Glimpse of Us Joji
偏爱 - 张芸京
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.

作词 : 葛大为

作曲 : 陈伟

编曲 : 陈伟

把昨天都作废

现在你在我眼前

我想爱 请给我机会

如果我错了也承担

认定你就是答案

我不怕谁嘲笑我极端

相信自己的直觉

相信自己的直觉

顽固的人不喊累

爱上你 我不撤退

我说过 我不闪躲

我说过 我不闪躲

我非要这么做

讲不听 也偏要爱

更努力爱 让你明白

没有别条路能走

你决定要不要陪我

讲不听 偏爱

靠我感觉爱

等你的依赖

对你偏爱

痛也很愉快

把昨天都作废

把昨天都作废

现在你在我眼前

我想爱 请给我机会

如果我错了也承担

认定你就是答案

我不怕谁嘲笑我极端

相信自己的直觉

相信自己的直觉

顽固的人不喊累

爱上你 我不撤退

我说过 我不闪躲

我说过 我不闪躲

我非要这么做

讲不听 也偏要爱

更努力爱 让你明白

没有别条路能走

你决定要不要陪我

讲不听 偏爱

靠我感觉爱

等你的依赖

不后悔 有把握

不后悔 有把握

我不闪躲 我非要这么做

讲不听 也偏要爱

更努力爱 让你明白

没有别条路能走

你决定要不要陪我

讲不听 偏爱

靠我感觉爱

等你的依赖

对你偏爱 爱

痛也很愉快