个人经验
Controller层:全部使用包装类型!
Service层:全部使用包装类型!
Mapper层:返回值必须使用包装类型!
Pojo层:字段必须使用包装类型!
为什么使用包装类型,因为用户传参,可能会为null,数据库select的结果可能是null,即便数据库select的结果不是null,Pojo实际接收的字段,你无法保证是否为null!
如果需要参数校验,String类型必须使用StringUtils.isNotBlank(XXXX) 处理!
命名规范
- 包名:
- 全部小写
- 类名、接口名:
- 大驼峰AaaAaa
- 方法名、局部变量:
- 小驼峰 aaaAAA
- 成员变量:
- 小驼峰 aaaAAA
- 枚举
- 全部大写
其他场景
Abc的测试类命名为:AbcTest
包名在有且仅有一个正常语义单词的情况下,包名单数,类名复数含义可以使用复数
com.zanglikun.testDemo.util
其包下的类名建议用复数
StringUtils
不推荐使用尚未明确定义的值
String magicValue = "pilipala_" + account;
不推荐的理由:比如账号是789
pilipala_789 容易被写成pilipala789
long类型不允许使用小写l 必须使用大写L
Long timeStamp = 1L;
反例:Long timeStamp = 1l; 这样定义容易被别人理解成11
注释规范
注释类型
- 单行注释 // 必须用于方法体上一行
- 多行注释 /* */ 常用于类名、方法名、类属性、接口 必须使用Javadoc规范,除了基本介绍参数、返回值信息,最好声明:方法是干什么的
- @see 用法
- todo 用法
/**
* @param createReq 请求XXX的入参
* @return 响应的XXX
* @see <a href="https://www.zanglikun.com/docs">我是超链</a>
* @see com.zanglikun.digital.designer.scenario.sdk.service.bizquoteproject.BizQuoteProjectScenarioService 注释:跳转到指定类上
* @see com.zanglikun.digital.designer.scenario.sdk.service.bizquoteproject.BizQuoteProjectScenarioService#getAllBizTree(String, String, Integer) 注释:跳转到指定的类方法上
* 注意 如果see指向某变/常量后,阅读模式将不能添加其他注释信息了
* @see com.zanglikun.digital.designer.scenario.runtime.service.bizquoteproject.BizQuoteProjectScenarioServiceImpl#name
*/
public String a(String createReq){
}
public void b(){
// todo 这里需要做XXX逻辑
}
单行注释:注释符与注释正文之间:有且只能有一个空格!
// 我是注释
反例://我是注释
接口、抽象类必须使用Javadoc文档规范,不得使用//
数组命名
推荐:int[] userList;
而不是 int userList[];
强转类型:右括号强制与转换至中间无空格
int account = 1234;
String magicValue = (String)abc;
IDEA设置:
- text file encoding 设置成UTF-8
- 文件换行符:设定为Unix,不要使用Windows
POJO类不要加is前缀:这里有些框架会引起序列化错误
// 定义一个变量,命名为:isDeleted
private boolean isDeleted;
// 然后 Alt + Insert 然后getter/setter一下
public boolean isDeleted(){
return isDeleted;
}
public void setDeleted(boolean deleted){
this.isDeleted = deleted;
}
=================================================================
// 再次定义一个变量,命名为:Deleted
private boolean Deleted;
// 然后 Alt + Insert 然后get set一下
public boolean isDeleted(){
return isDeleted;
}
public void setDeleted(boolean deleted){
this.isDeleted = deleted;
}
对比发现,isXXX与XXX在定义成基本类型的时候,默认的属性名是:Deleted。
如果是包装类型 Boolean 则是正常getIsDeleted,与getDeleted
如果数据库表中有is_XXX,建议在mybatis <resultmap> 标签中进行配置。
OOP规约
避免通过类的对象去访问类的静态变量或者静态方法,直接使用类名. 即可
对象在堆中,类信息在方法区。
如果通过对象去访问静态变量:就需要获取对象的方法区,找到类信息,再去找到静态变量的值。
类名. 本身就在方法区,减少编译器的解析成本!
方法重写务必追加@Override,用于检测方法重写:不然无法准确是否是方法重写
方法参数尽量避免使用Object,作为参数类型:可以减少出现类型转换异常,
不建议开发者使用可变参数...编程
@Deprecated 过时 过期 未来可能删除方法需要加入此注解 待删除注解
方法过期了,不推荐使用了,请使用@Deprecated注解,并详细建议的使用新方法XXX
同理,不建议使用过期的方法
equals:避免引用类型调用equals,避免出现 空指针异常
String iPhone = null;
"abc".equals(iPhone); // 不会有问题
iPhone.equals("abc"); // 会有空指针异常风险
引入面试题
Integer a = 1;
Integer b = 1;
(a==b) // true
Integer a = 128;
Integer b = 128;
(a==b) // false
Idea Ctrl + 鼠标左键,Ctrl + F 搜索cache 找到
-128到127的单位内,使用的Integer是缓存的数据,此范围之外,才是new一个对象
货币类型:务必以最小的单位整形命名。 23章节
浮点型的等值比较:基本数据类型不能使用 == 包装数据类型不能使用equals()来判断,如下一条有说明
BigDecimal 等值强制使用compareTo()方法,而不是equals()方法,equals 方法会比较精度 ((1.0).equals(1.00) 就会报错
禁止使用构造方法 BigDecimal(duble)的方式将double转为BigDecimal对象,会有精度损失,而建议使用
BigDecimal g = new BigDecimal(string);
如:BigDecimal g = new BigDecimal("0.1");
因为BigDecimal的valueOf()是执行了Double的toString方法,所以valueOf也是能用的
BigDecimal g = BigDecimal.valueOf(0.1d);
定义数据类型DO 也就是与数据库对应的类型,属性类型,与字段类型要匹配
如果数据库字段money是bigint类型,创建Java类型字段不能使用
Integer money; // Integer范围大约是正负21亿,随着业务增长,java的Integer类型无法满足范围了
Long money; // 范围则会更一些。
所有POJO的数据类型务必使用包装类型,且使用时,务必保证NPE 也就是空指针异常的处理
所有的PRC方法的返回值必须使用包装类型
定义DO/DTO/VO/POJO不能设置默认值
比如日期字段:数据库查出来时空,你初始化了默认值,容易起业务争议
序列化类新增属性的时候,不要修改seriaVersionUID字段,避免反序列化失败。
构造方法,禁止写业务逻辑,如果有初始化逻辑,请自定义init()方法中
日期的正常格式 yyyy-MM-dd HH:mm:ss
M是月份
m是分钟
H是24小时进制
h是12小时进制
获取毫秒,务必使用System.currentTimeMillis(),而不是new Date.time()。创建对象,总归要慢一些。
程序不仅要写死一年时365天,避免公历闰年时出现日期转换错误
正确请使用:
// 获取今年的天数
int dayOfThisYear = LocalDate.now().lengthOfYear();
// 获取某年的天数
LocalDate.of(2011,1,1).lengthOfYear();
集合
https://www.zanglikun.com/2301.html#face
判断集合是否时空,使用isEmpty(),而不是获取size再去判断==0的情况;
List集合转Map的方式,必须使用 下面方法,尚未补全P39
List
线程
线程资源必须通过线程池提供,不允许应用自行显示创建线程。原因:创建大量线程导致OOM或内存切换导致性能下降。
创建线程,必须使用new ThreadPoolExecutor(...) 可以快速了解线程池的配置信息,需要复习本站的线程池知识
高并发时,能锁方法块,就不要锁完整方法体
加锁,加在try之外,释放锁必须在finally里面
控制语句
switch 务必追加 defult!
高并发情况下:使用 == 容易造成等于击穿的情况:比如奖品数量==0,然后返回。一旦==的判断值为复数,则后续的值,就跳过了奖品数量为0的判断了,建议使用>=0 或者<=0
前后端规范
后端接口必须使用Https
后端返回信息必须包含:1:Http状态码、2:错误码、3:错误信息、4:用户提示信息
后端返回给前端数字类型一律:String类型
Http请求:需要限制请求体Body大小。
前后端分页:要动态处理:规范分页参数有效
错误码
错误码:A0001与错误日志需要清晰明了
正确错误码:00000,必须传递
错误码由字母 + 4位编号组成。A代表用户错误、B服务端错误,C代表第三方错误。
错误码与错误信息不得反馈给用户!
异常日志
异常能提前避免,就提前避免:比如随便加些判断,避免空指针等情况
异常是为了处理,不是为了抛出去,必须有方法兜底去处理,不得被用户看到
事务控制中,如果自行catch了异常,请手动回滚事务
try 里面的return不会立即返回,必须finally走完,如果finally有return,则会抛弃try里面的
在调用RPC相关方法时,catch必须使用Throwable类来拦截
日志规约
使用日志框架,不要直接使用日志系统。推荐使用slf4j日志框架
日志文件建议保存15天。如:周一报错,其他时间不报错,就需要以周进行拦截与查看了。
对于网络运行状态、网络安全事件、个人敏感操作不少于6个月。国家规定
强烈推荐{} 占位符,因为字符串拼接使用append有性能损耗,占位符只是替换,性能更优
避免日志重复打印,务必在日志配置文件中设置additivity=false
生产环境禁止使用System.out或者 System.err 输出日志。
日志输出参数的时候,禁止使用JSON工具,因为JSON工具获取对象属性是get,如果get报错,那就麻烦了。推荐对象toString()
安全规约
用户敏感数据,必须要脱敏
防止SQL注入
防止XSS注入
用户传入任何参数都需要校验!
JAVA CSRF安全验证
对短信、右键等进行数量、疲劳、验证码校验。避免资源被滥刷
MySQL数据库
是否概念必须使用is_xxx命名unsigned tinyint 1表示是,0表示否。unsigned表示非负数
POJO类中任何与布尔类型的变量不得使用is前缀,使用mybatis中resultmap标签进行映射
主键命名pk_字段名,唯一索引名 uk_字段名,普通索引名idx_字段名
表必备按字段id,create_time,update_time
唯一索引是一定的约束
超过三张表禁止join,需要join字段数据类型绝对保持一直(避免索引失效),关联字段必须有索引
varchar建立索引必须指定长度,但不建议全部程度。这里建议百度一下!
不得使用左模糊、全模糊,如果有业务使用,使用搜索引擎
count(*) 与 count(1) 区别是 *会扫描null,但是1则查询非空的数量
不得使用外键
禁止使用存储过程
数据修改,一定要查一下,看一下是否是自己的要修改的
多表查询,必须使用别名
ORM映射
不得使用 * 作为查询的字段列表,容易引起与resultmap不一致。同时也会造成不必要的网络资源浪费,比如用不到的text的内容等等
任何返回必须定义一个ResultMap,不得直接返回Class
更新表记录时,必须更新对应的update_tiem字段为敌当前时间
不得使用HashMap或HashTable作为结果集返回。容易出现字段类型范围不匹配的问题
第三方平台不会及时更新本文最新内容。如果发现本文资料不全,可访问本人的Java博客搜索:标题关键字。以获取最新全部资料 ❤