提交 887743cf authored 作者: liupengfei's avatar liupengfei

--no commit message

上级 89dbd7bf
服用层次 | 存放位置
--- | ----
跨应用共享常量 | 放置在单位私服中,通常是client.jar中的constant目录下。
应用内共享常量 | 子模块中的constant目录下
子工程内部共享常量 | 即在当前子工程的constant目录下。
包内共享常量 | 即在当前包下单独的constant目录下。
类内共享常量 | 直接在类内部private static final定义。
## (五)Controller参数类型
1. 参数类型不能使用 Map,可读性差。
2. Get请求查询方法用Query对象,保存和修改方法用实体对象接收。
3. 参数使用包装类型,不能超过两个,超过两个时包装成Query对象。
4. POST请求用Form对象接口,并且 需要加入@RequestBody注解。
5. 使用 @RequestBody注解 每个方法只能使用一次,否则报流已经关闭错误。
6. POST请求接收内容统一放到@RequestBody中(URL中参数除外)。
## (六)Controller返回类型
1. 统一使用相同的返回类型 CallBack<T> ,泛型需要根据业务指向实际对象。
2. Controller负责对接收参数验证。
3. Controller代码中不能出现重复的业务逻辑。
## (七)Service 返回类型
1. 尽量不要使用JSON作为返回类型。
## (八)Dao返回类型
1. 如果使用VO 来接收Dao的查询结果,按需查询, VO的字段按需写。
## (九) Manage 通用处理层
1. 通用处理层
* 1) 对第三方平台封装的层,预处理返回结果及转化异常信息;
* 2) 对 Service 层通用能力的下沉,如缓存方案、 中间件通用处理;
* 3) 与 DAO 层交互,对多个 DAO 的组合复用。
* 4) 提供其他service 调用的方法
## (十)数据库
1. 表名 以服务名开头,单词间以下划线 <strong>"_" </strong> 隔开
```
# 例:图书表
bk_book
# 例: 配货单表
ord_order_blank
```
## (十一)枚举
* ~~枚举代表的状态码和类型码需要统一设为int类型。实体中使用Integer类型~~
* 枚举代表的状态码和类型码需要统一设为String类型。实体中使用String类型
2. 列名 以驼峰的形式书写,与实体类中 名称保持一致
```
# 例 图书名称
bookName 或者 name
```
3. 索引 索引以 列名开头 +<strong>"_"</strong> + 索引类型
```
# 例 订单编号 唯一索引
code_unique
```
4. 表连接 字段保证有 索引,<strong>like</strong> 查询尽量避免全模糊,可以使用右模糊,并且like条件需要放到sql语句的最后
# 二 编码规约
1. 所有的POJO 都需要重写 toString()方法。方便日志打印。
2. 避免通过一个类的对象引用访问此类的静态变量或静态方法,无谓增加编译器解析成本,直接用类名来访问即可。
3. 所有的覆写方法,必须加@Override注解。
4. 所有的局部变量使用基本数据类型。
5. 所有的POJO类属性必须使用包装数据类型。
6. RPC方法的返回值和参数必须使用包装数据类型。
7. POJO类中 不要设定任何属性默认值。
8. 构造方法里面禁止加入任何业务逻辑,如果有初始化逻辑,请放在init方法中。
9. POJO类必须写toString方法。
10. 字符串的连接方式,使用StringBuilder的append方法进行扩展。
11. 获取当前毫秒数 System.currentTimeMillis(); 而不是 new Date().getTime();
12. 不要在视图模板中加入任何复杂的逻辑。根据 MVC 理论,视图的职责是展示,不要抢模型和控制器的活。
13. 表达异常的分支时,少用if-else方式,这种方式可以改写成:
``` java?linenums
if (condition) {
...
return obj;
}
// 接着写else的业务逻辑代码;
```
14. 如果非得使用if()...else if()...else...方式表达逻辑,【强制】避免后续代码维护困难,请勿超过3层。超过3层的 if-else 的逻辑判断代码可以使用卫语句、策略模式、状态模式等来实现。其中卫语句示例如下:
``` java?linenums
public void today() {
if (isBusy()) {
System.out.println(change time.);
return;
}
if (isFree()) {
System.out.println(go to travel.);
return;
}
System.out.println(stay at home to learn Alibaba Java Coding Guidelines.);
return;
}
```
15. 除常用方法(如getXxx/isXxx)等外,不要在条件判断中执行其它复杂的语句,将复杂逻辑判断的结果赋值给一个有意义的布尔变量名,以提高可读性。
<span style="color:green">正例</span>
``` java?linenums
// 伪代码如下 final boolean existed = (file.open(fileName, "w") != null) && (...) || (...);
if (existed) {
...
}
```
<span style="color:red">反例</span>
``` java?linenums
if ((file.open(fileName, "w") != null) && (...) || (...)) {
...
}
```
16. 删除不用的导入,尽量不要使用整个包的导入。在eclipse下经常使用快捷键 ctrl+shift+o 修正导入。
17.
# 三 异常规约
1. 异常不要用来做流程控制,条件控制。
2. catch时请分清稳定代码和非稳定代码,稳定代码指的是无论如何不会出错的代码。对于非稳定代码的catch尽可能进行区分异常类型,再做对应的异常处理。
3. 捕获异常是为了处理它,不要捕获了却什么都不处理而抛弃之,如果不想处理它,请将该异常抛给它的调用者。最外层的业务使用者,必须处理异常,将其转化为用户可以理解的内容。
4. 禁止对一大段代码进行try-catch
5. 有try块放到了事务代码中,catch异常后,如果需要回滚事务,一定要注意手动回滚事务。
# 四 日志规约
1. 对trace/debug/info级别的日志输出,必须使用条件输出形式或者使用占位符的方式。
2. 日志打印异常信息。异常信息应该包括两类信息:案发现场信息和异常堆栈信息。如果不处理,那么通过关键字throws往上抛出。
# 五 注释规约
1. 类、类属性、类方法的注释必须使用Javadoc规范
2. 所有的抽象方法(包括接口中的方法)必须要用Javadoc注释、除了返回值、参数、异常说明外,还必须指出该方法做什么事情,实现什么功能。
3. 所有的类都必须添加创建者和创建日期。
4. 方法内部单行注释,在被注释语句上方另起一行,使用//注释。方法内部多行注释使用/* */注释,注意与代码对齐。
5. 所有的枚举类型字段必须要有注释,说明每个数据项的用途。
6. eclipse模板参考: ![codetemplates.xml](code/codetemplates.xml)
7. http接口信息相关的内容 使用swagger 注解配置,方便与前端人员交互。
# 六 格式规约
1. java文件,编写完成 格式化下。参考 : ![ctrl+shift+f](code/ctrl+shif+f.xml)
2. 大括号的使用约定。如果是大括号内为空,则简洁地写成{}即可,不需要换行;如果是非空代码块则:
> 1) 左大括号前不换行。
2) 左大括号后换行。
3) 右大括号前换行。
4) 右大括号后还有else等代码则不换行;表示终止的右大括号后必须换行。
3. 左小括号和字符之间不出现空格;同样,右小括号和字符之间也不出现空格。
``` javascript?linenums
public static void main(String[] args) {
// 缩进4个空格
String say = "hello";
// 运算符的左右必须有一个空格
int flag = 0;
// 关键词if与括号之间必须有一个空格,括号内的f与左括号,0与右括号不需要空格
if (flag == 0) {
System.out.println(say);
}
// 左大括号前加空格且不换行;左大括号后换行
if (flag == 1) {
System.out.println("world");
// 右大括号前换行,右大括号后有else,不用换行
} else {
System.out.println("ok");
// 在右大括号后直接结束,则必须换行
}
}
```
4. 注释的双斜线与注释内容之间有且仅有一个空格。
``` java?linenums
// 这是示例注释,请注意在双斜线之后有一个空格
String ygb = new String();
```
5. 换行 范例
``` java?linenums
StringBuffer sb = new StringBuffer();
// 超过120个字符的情况下,换行缩进4个空格,点号和方法名称一起换行
sb.append("zi").append("xin")...
.append("huang")...
.append("huang")...
.append("huang");
```
6. 方法参数在定义和传入时,多个参数逗号后边必须加空格。
``` java
method("a", "b", "c");
```
# 七 URI规约
1. <strong>URI中尽量使用连字符"-"代替下划线"_"的使用</strong>
<br><span style="color:orange">说明</span>:连字符"-"一般用来分割URI中出现的字符串(单词),来提高URI的可读性
2. <strong>URI中统一使用小写字母</strong>
<br><span style="color:orange">说明</span>: 单词用 "-" 分割
3. URI中不要包含文件(脚本)的扩展名
4. 响应结果类型一致
```
//T 需要指定实际对象,不能用Object 代替
CallBack<T>
```
5. URI结构如下
```
http://ip:port/接口应用类型(bg|fg|wap|app|)/资源名称(实体名称)/操作;
```
6. URI 操作定义,
增删改,上传 统一使用 <strong>@PostMapping</strong>
查询,下载 使用 <strong>@GetMapping</strong> 示例如下
> 后台管理
操作名 | 编码 | URI | 备注
------------- | ------------- | ------------- | -------------
添加 | save | /bg/book/save | 添加单本图书
修改 | update | /bg/book/update | 修改单本图书
行内操作上架(即修改状态) | update/{id}/status | /bg/book/update/{id}/status | 修改指定图书的属性信息
行内操作删除(单条删除) | delete/{id} | /bg/book/delete/{id} | 删除指定图书
获取指定图书 | {id} | /bg/book/{id} | 根据id获取指定图书 |
根据条件指定图书 | get/业务名称 | /bg/book/get/业务名称 |
查询图书列表 | list | /bg/book/list | ?Query条件
获取指定业务的图书列表 | list/业务名 | /bg/book/list/业务名 | ?Query
查询分页列表 | page | /bg/book/page | ?Query条件,分页条件
获取指定业务的分页列表 | page/业务名 | /bg/book/page/业务名 | 获取指定业务的图书分页
获取树形数据 | tree | /bg/book/tree |
获取指定业务的树形数据 | tree/业务名 | /bg/book/tree/业务名 | 获取指定业务的树形数据
批量操作 | batch/业务名 | /bg/book/batch/业务名 |
批量上架(批量修改状态) | batch/update/status | /bg/book/batch/update/status |
批量删除 | batch/delete | /bg/book/batch/delete |
上传 | upload | /bg/upload | ?fileType 统一上传路径(适用于产品)
上传图书封面 | upload | /bg/book/upload-cover | 适用于(之前的项目)
下载 | download | /bg/download | ?filePath 统一下载路径
导入 | import | /bg/book/import | 导入数据
导出 | export | /bg/book/export | 导出数据
图书相关资源功能 | {id}/实体名称 | /bg/book/{id}/resource/list | 相关资源列表,操作参照以上的操作 /bg/book/{id}/resource/增删改查
> 前台示例
操作名 | 编码 | URI | 备注
------- | -----------| -----------| ----------
热门图书 | list/hot | /fg/book/list/hot |
销量排行 | list/consider | /fg/book/list/consider |
相关资源 | {id}/resource/list | /fg/book/{id}/resource/list
相关图书 | {id}/book/list | /fg/book/{id}/book/list | 自联表查询可省略id后的 实体名称 /fg/book/{id}/list
帮助中心 | list/help-center | /fg/news/list/help-center | /fg/news/list/{channel-code}
# 八 代码规约插件
阿里开源的 IDE 代码规约检测插件: [点此下载](https://github.com/alibaba/p3c)
# 九 最佳实践和禁忌
1. 每次保存的时候,都让你的代码是最美的
<br><span style="color:orange">说明:</span>
程序员都是懒惰的,不要想着等我完成了功能,再来优化代码的格式和结构,等真的把功能完成,很少有人会再愿意回头调整代码。
2. 使用log而不是System.out.println()
<br><span style="color:orange">说明:</span>
log可以设定级别,可以控制输出到哪里,容易区分是在代码的什么地方打印的,而System.out.print则不行。而且,System.out.print的速度很慢。所以,除非是有意的,否则,都要用log。至少在提交到svn之前把System.out.print换成log。
3. 每个if while for等语句,都不要省略大括号{}
<br><span style="color:orange">说明:</span>
``` java?linenums
// 看下面的代码:
if (a > b)
a++;
// 如果在以后维护的时候,需要在a > b 时,把b++,一步小心就会写成:
if (a > b)
a++;
b++;
// 这样就错了,因为无论a和b是什么关系,b++都会执行。 如果一开始就这样写:
if (a > b) {
a++;
}
// 相信没有哪个笨蛋会把b++添加错的。而且,这个大括号使作用范围更明显,尤其是后面那行很长要折行时。
```
4. 善用TODO:
<br><span style="color:orange">说明:</span>
在代码中加入 //TODO: ,大部分的ide都会帮你提示,让你知道你还有什么事没有做。比如:
``` java?linenums
if (order.isPaid()) {
//TODO: 更新订单
}
```
5. 在需要留空的地方放一个空语句或注释,告述读者,你是故意的
<br><span style="color:orange">说明:</span>
``` java?linenums
if (!exists(order)) {
;
}
// 或者
if (!exists(order)) {
//nothing to do
}
```
6. 不要再对boolean值做true false判断
``` java?linenums
if (order.isPaid() == true) {
// Do something here
}
// 不如写成:
if (order.isPaid()) {
//Do something here
}
```
后者读起来就很是 if order is paid, …. 要比 if order’s isPaid method returns true, … 更容易理解
7. 减少代码嵌套层次
<br><span style="color : red">反例:</span>
``` java?linenums
public void demo(int a, int b, int c) {
if (a > b) {
if (b > c) {
doJobA();
} else if (b < c) {
doJobB()
}
} else {
if (b > c) {
if (a < c) {
doJobC();
}
}
}
}
```
减少嵌套的方法有很多:
- 合并条件
- 利用 return 以省略后面的else
- 利用子方法
比如上例,合并条件后成为:
``` java?linenums
public void demo(int a, int b, int c) {
if (a > b && b > c) {
doJobA();
}
if (a > b && c > b) {
doJobB();
}
if (a <= b && c < b && a < c) {
doJobC();
}
}
```
如果利用return 则成为:
``` java?linenums
public void demo(int a, int b, int c) {
if (a > b) {
if (b > c) {
doJobA();
return;
}
doJobB()
return;
}
if (b > c) {
if (a < c) {
doJobC();
}
}
}
```
利用子方法,就是将嵌套的程序提取出来放到另外的方法里。
8. 程序职责单一
<br><span style="color:orange">说明:</span>关注点分离是软件开发的真理。人类自所以能够完成复杂的工作,就是因为人类能够将工作分解到较小级别的任务上,在做每个任务时关注更少的东西。让程序单元的职责单一,可以使你在编写这段程序时关注更少的东西,从而降低难度,减少出错。
9. 变量的声明,初始化和被使用尽量放到一起
比方说如下代码:
``` java?linenums
int orderNum= getOrderNum();
// do something withou orderNum here
call(orderNum);
// 上例中的注释处代表了一段和orderNum不相关的代码。orderNum的声明和初始化离被使用的地方相隔了很多行的代码,这样做不好,不如这样:
// do something withou orderNum here
int orderNum= getOrderNum();
call(orderNum);
```
11. 缩小变量的作用域
12. 尽量不要用参数来带回方法运算结果
``` java?linenums
public void calculate(Order order) {
int result = 0;
//do lots of computing and store it in the result
order.setResult(result);
}
public void action() {
order = orderDao.findOrder();
calculate(order);
// do lots of things about order
}
// 例子中calculate方法通过传入的order对象来存储结果, 不如如下写:
public int calculate(Order order) {
int result = 0;
//do lots of computing and store it in the result
return result;
}
public void action() {
order = orderDao.findOrder();
order.setResult(calculate(order));
// do lots of things about order
}
```
# 十 其他
1. 系统中对用户的任何输入都进行了合法性验证(敏感词过滤、长度、类型、语法以及业务规则)。
2. 系统中禁止出现任何拼装的SQL语句,所有的操作都参数化。
3. 系统中对于数据库操作都是严格按照特定用户,特定权限执行,禁用sa连接。
4. 在系统的cookie中敏感信息都采用特定的加密方式加密存储,防止被盗用。
5. 数据导入完成后,检测导入数据的数据量是否完整、数据字段是否完整、数据在新网站中是否有效存储、数据在新网站中是否有效展示。
6. 系统中的上传程序只允许信任的用户使用。
7. double类型的数据进行基础运算时会导致精度丢失,得到意外的结果。
> 使用 BigDecimal 进行运算。
``` java?linenums
/**
* 字符串转 bigdecimal 运算正常
*
* @author lpf
* @date: 2018年12月6日 下午3:04:32
*/
@Test
public void test8(){
String tempData;
//微信支付需要金额
String realData;
tempData="77.10";
BigDecimal tempDataBig = new BigDecimal(tempData);
// 元换算为 分
realData = tempDataBig.multiply(new BigDecimal(100d)).intValue() + "";
System.out.println(realData);
}
/**
* double运算精度丢失
*
* @author lpf
* @date: 2018年12月6日 下午3:04:20
*/
@Test
public void test9(){
double bcd = 77.10;
double a = 100;
double result = bcd * a;
System.out.println(result + "");
}
/**
* 字符串转 double 在转 bigdecimal 对象运算精度丢失
*
* @author lpf
* @date: 2018年12月6日 下午3:03:46
*/
@Test
public void test10(){
String tempData = "77.10";
Double bcd = Double.parseDouble(tempData);
System.out.println(bcd);
BigDecimal tempDataBig = new BigDecimal(bcd);
System.out.println(tempDataBig.doubleValue());
System.out.println(tempDataBig.multiply(new BigDecimal(100d)).doubleValue());
// 元换算为 分
String realData = tempDataBig.multiply(new BigDecimal(100d)).intValue() + "";
System.out.println(realData);
}
```
# 十一 版本更新记录
版本 | 更新记录 | 更新人 |更新时间
--- | --- | ---| ---|
v1| init | lpf | 2018-05-21
v2| 1. 类名增加Form ,WarpForm对象<br>2.增加Manage层 <br> 3.增加通用字段createTime updateTime| lpf | 2018-07-09
v3| 增加数据库表名属性名索引的命名规约 | lpf | 2018-07-11
v4| 增加枚举状态码类型要求 和实体 类型或状态属性 要求 | lpf | 2018-07-18
v5| Controller参数类型 要求补充第六条 | lpf | 2018-08-21
v6| double 运算精度丢失,不要使用 | lpf | 2018-12-06
v7| Controller职责 | lpf | 2019-01-28
v8| 枚举状态码类型要求 和实体 类型或状态属性 要求由int改为String | lpf | 2019-12-19
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论