Java后端详解下

1.异常处理
ava 类库中定义的可以通过预检查方式规避的 RuntimeException 异常不应该通过
catch 的方式来处理
反例:try { obj.method(); } catch (NullPointerException e) {…}
异常捕获后不要用来做流程控制,条件控制。
捕获异常是为了处理它,不要捕获了却什么都不处理而抛弃之,如果不想处理它,请
将该异常抛给它的调用者。最外层的业务使用者,必须处理异常,将其转化为用户可以理解的
内容。
2.日志规约
所有日志文件至少保存 15 天,因为有些异常具备以“周”为频次发生的特点。对于
当天日志,以“应用名.log”来保存,保存在/home/admin/应用名/logs/目录下,过往日志
格式为: {logname}.log.{保存日期},日期格式:yyyy-MM-dd
对于 trace/debug/info 级别的日志输出,必须进行日志级别的开关判断。
避免重复打印日志,浪费磁盘空间,务必在日志配置文件中设置 additivity=false。
生产环境禁止直接使用 System.out 或 System.err 输出日志或使用
e.printStackTrace()打印异常堆栈。
3.单元测试
好的单元测试必须遵守 AIR 原则。
⚫ A:Automatic(自动化)
⚫ I:Independent(独立性)
⚫ R:Repeatable(可重复)
单元测试应该是全自动执行的,并且非交互式的。
单元测试是可以重复执行的,不能受到外界环境的影响。
对于单元测试,要保证测试粒度足够小,有助于精确定位问题。
编写单元测试代码遵守 BCDE 原则,以保证被测试模块的交付质量。
⚫ B:Border,边界值测试,包括循环边界、特殊取值、特殊时间点、数据顺序等。
⚫ C:Correct,正确的输入,并得到预期的结果。
⚫ D:Design,与设计文档相结合,来编写单元测试。
⚫ E:Error,强制错误信息输入(如:非法数据、异常流程、业务允许外等),并得到预期的结果。
4.安全规约
隶属于用户个人的页面或者功能必须进行权限控制校验。
用户输入的 SQL 参数严格使用参数绑定或者 METADATA 字段值限定,防止 SQL 注入,
禁止字符串拼接 SQL 访问数据库。
用户请求传入的任何参数必须做有效性验证。
⚫ page size 过大导致内存溢出
⚫ 恶意 order by 导致数据库慢查询
⚫ 缓存击穿
⚫ SSRF
⚫ 任意重定向
⚫ SQL 注入,Shell 注入,反序列化注入
⚫ 正则输入源串拒绝服务 ReDoS
5.MySQL数据库
1)建表规约
表达是与否概念的字段,必须使用 is_xxx 的方式命名,数据类型是 unsigned tinyint
(1 表示是,0 表示否)。
正例:表达逻辑删除的字段名 is_deleted,1 表示删除,0 表示未删除。
表名、字段名必须使用小写字母或数字,禁止出现数字开头,禁止两个下划线中间只
出现数字。
正例:aliyun_admin,rdc_config,level3_name
反例:AliyunAdmin,rdcConfig,level_3_name
表名不使用复数名词。
2)索引规约
业务上具有唯一特性的字段,即使是组合字段,也必须建成唯一索引。
索引的长度与区分度是一对矛盾体,一般对字符串类型数据,长度为 20 的索引,区分度会高达 90%
以上,可以使用 count(distinct left(列名, 索引长度))/count(*)的区分度来确定。

利用延迟关联或者子查询优化超多分页场景。
正例:先快速定位需要获取的 id 段,然后再关联:
SELECT t1.* FROM 表 1 as t1, (select id from 表 1 where 条件 LIMIT 100000,20 ) as t2 where t1.id=t2.id
SQL 性能优化的目标:至少要达到 range 级别,要求是 ref 级别,如果可以是 consts
最好。
⚫consts 单表中最多只有一个匹配行(主键或者唯一索引),在优化阶段即可读取到数据。
⚫ref 指的是使用普通的索引(normal index)。
⚫range 对索引进行范围检索。
3)SQL语句
不要使用 count(列名)或 count(常量)来替代 count(),count()是 SQL92 定义的标
准统计行数的语法,跟数据库无关,跟 NULL 和非 NULL 无关。
count(distinct col) 计算该列除 NULL 之外的不重复行数,注意 count(distinct col1,
col2) 如果其中一列全为 NULL,那么即使另一列有不同的值,也返回为 0。
当某一列的值全是 NULL 时,count(col)的返回结果为 0,但 sum(col)的返回结果为
NULL,因此使用 sum()时需注意 NPE 问题。
使用 ISNULL()来判断是否为 NULL 值。
⚫NULL<>NULL 的返回结果是 NULL,而不是 false。
⚫NULL=NULL 的返回结果是 NULL,而不是 true。
⚫NULL<>1 的返回结果是 NULL,而不是 true。
学生表中的 student_id 是主键,那么成绩表中的 student_id 则为外键。如果更新学
生表中的 student_id,同时触发成绩表中的 student_id 更新,即为级联更新。

4)ORM映射
在表查询中,一律不要使用 * 作为查询的字段列表,需要哪些字段必须明确写明。
不要用 resultClass 当返回参数,即使所有类属性名与数据库字段一一对应,也需要
定义;反过来,每一个表也必然有一个与之对应。
sql.xml 配置参数使用:#{},#param# 不要使用${} 此种方式容易出现 SQL 注入。
6.工程结构
1)应用分层
• 开放 API 层:可直接封装 Service 接口暴露成 RPC 接口;通过 Web 封装成 http 接口;网关控制层等。
• 终端显示层:各个端的模板渲染并执行显示的层。当前主要是 velocity 渲染,JS 渲染,JSP 渲染,移
动端展示等。
• Web 层:主要是对访问控制进行转发,各类基本参数校验,或者不复用的业务简单处理等。
• Service 层:相对具体的业务逻辑服务层。
• Manager 层:通用业务处理层,它有如下特征:
1) 对第三方平台封装的层,预处理返回结果及转化异常信息,适配上层接口。
2) 对 Service 层通用能力的下沉,如缓存方案、中间件通用处理。
3) 与 DAO 层交互,对多个 DAO 的组合复用。
• DAO 层:数据访问层,与底层 MySQL、Oracle、Hbase、OB 等进行数据交互。
• 第三方服务:包括其它部门 RPC 服务接口,基础平台,其它公司的 HTTP 接口,如淘宝开放平台、支
付宝付款服务、高德地图服务等。
• 外部数据接口:外部(应用)数据存储服务提供的接口,多见于数据迁移场景中。
分层领域模型规约:
• DO(Data Object):此对象与数据库表结构一一对应,通过 DAO 层向上传输数据源对象。
• DTO(Data Transfer Object):数据传输对象,Service 或 Manager 向外传输的对象。
• BO(Business Object):业务对象,可以由 Service 层输出的封装业务逻辑的对象。
• Query:数据查询对象,各层接收上层的查询请求。注意超过 2 个参数的查询封装,禁止使用 Map 类
来传输。
• VO(View Object):显示层对象,通常是 Web 向模板渲染引擎层传输的对象。
2)二方库依赖
定义 GAV 遵从以下规则:
• GroupID 格式:com.{公司/BU }.业务线 [.子业务线],最多 4 级。
说明:{公司/BU} 例如:alibaba/taobao/tmall/aliexpress 等 BU 一级;子业务线可选。
正例:com.taobao.jstorm 或 com.alibaba.dubbo.register
• ArtifactID 格式:产品线名-模块名。语义不重复不遗漏,先到中央仓库去查证一下。
正例:dubbo-client / fastjson-api / jstorm-tool
所有 pom 文件中的依赖声明放在语句块中,所有版本仲裁放在
语句块中。
7.设计规约
存储方案和底层数据结构的设计获得评审一致通过,并沉淀成为文档。
避免如下误解:敏捷开发 = 讲故事 + 编码 + 发布。
在做无障碍产品设计时,需要考虑到:
⚫ 所有可交互的控件元素必须能被 tab 键聚焦,并且焦点顺序需符合自然操作逻辑。
⚫ 用于登录校验和请求拦截的验证码均需提供图形验证以外的其它方式。
⚫ 自定义的控件类型需明确交互方式。

posted @ 2024-08-14 16:25  羡仟  阅读(3)  评论(0编辑  收藏  举报