目录
- [1. 项目概述](#1. 项目概述)
- [2. 代码风格规范](#2. 代码风格规范)
- [3. Java类规范](#3. Java类规范)
- [4. Spring Boot规范](#4. Spring Boot规范)
- [5. 文件命名规范](#5. 文件命名规范)
- [6. 目录结构规范](#6. 目录结构规范)
- [7. Git提交规范](#7. Git提交规范)
- [8. 注释规范](#8. 注释规范)
- [9. 数据库规范](#9. 数据库规范)
- [10. API接口规范](#10. API接口规范)
- [11. 最佳实践](#11. 最佳实践)
1. 项目概述
1.1 技术栈
- Java版本: Java 8+
- 框架: Spring Boot 2.4.0+
- 数据库: KingBase(兼容PostgreSQL)
- ORM框架: MyBatis-Plus 3.x+
- 缓存: Redis + Spring Cache
- 文档: Swagger 2.9.2
- 构建工具: Maven
- 代码生成: Lombok
1.2 开发工具配置
- IDE: IntelliJ IDEA(推荐)
- 代码格式化: IDEA内置格式化(遵循阿里巴巴规范)
- 代码检查: Alibaba Java Coding Guidelines
- Git钩子: 提交前代码检查
2. 代码风格规范
2.1 基本规则
2.1.1 缩进和空格
- 使用 4个空格 进行缩进,不使用Tab
- 行尾不允许有空格
- 文件末尾保留一个空行
java
// ✅ 正确
public class Example {
private String name;
public void method() {
if (condition) {
doSomething();
}
}
}
// ❌ 错误 - 使用Tab或2个空格
public class Example {
private String name; // 2个空格
}
2.1.2 大括号
- 左大括号不换行(项目标准)
- 右大括号单独一行
- 单行语句也使用大括号
java
// ✅ 正确
public void method() {
if (condition) {
doSomething();
}
}
// ❌ 错误 - 左大括号换行
public void method()
{
// ...
}
// ❌ 错误 - 单行语句不使用大括号
if (condition) doSomething();
2.1.3 行长度
- 每行代码不超过 120个字符
- 超长代码需要换行,保持合理的缩进
java
// ✅ 正确 - 合理换行
String result = service.getData(
regionCode,
startDate,
endDate
);
// ✅ 正确 - 超长行换行
String longString = "这是一个很长的字符串,需要换行显示,"
+ "以保持代码的可读性和维护性";
// ❌ 错误 - 行过长
String result = service.getData(regionCode, startDate, endDate, includeSubRegions, format);
2.1.4 空行
- 类成员之间使用一个空行分隔
- 方法之间使用一个空行分隔
- 逻辑块之间使用空行分隔
java
// ✅ 正确
public class Example {
private String name;
private Integer age;
public void method1() {
// ...
}
public void method2() {
// ...
}
}
3. Java类规范
3.1 类结构顺序
Java类应按照以下顺序组织:
java
package com.soilsurvey.webapi.project.survey.controller;
// 1. 导入语句(按顺序:JDK、第三方库、项目内部)
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import com.soilsurvey.webapi.common.core.Result;
import com.soilsurvey.webapi.project.survey.service.IService;
// 2. 类注释
/**
* 示例Controller类
*
* @author 作者名
* @date 2024-01-01
*/
// 3. 类注解
@Api(tags = "01.1....模块名称")
@RestController
@RequestMapping("/ssp/example")
// 4. 类声明
public class ExampleController {
// 5. 常量(如果有)
private static final String CONSTANT = "value";
// 6. 成员变量
@Autowired
private IService service;
// 7. 构造方法
public ExampleController() {
// ...
}
// 8. 公共方法
@ApiOperation(value = "接口说明")
@GetMapping("/list")
public Result getList() {
// ...
}
// 9. 私有方法
private void helperMethod() {
// ...
}
}
3.2 导入语句规范
3.2.1 导入顺序
- JDK标准库
- 第三方库(Spring、MyBatis等)
- 项目内部类
java
// ✅ 正确
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import com.soilsurvey.webapi.common.core.Result;
import com.soilsurvey.webapi.project.survey.service.IService;
3.2.2 导入规则
- 不使用通配符导入(
import java.util.*) - 按字母顺序排列同组导入
- 使用IDE自动优化导入
java
// ✅ 正确
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
// ❌ 错误 - 使用通配符
import java.util.*;
3.3 类命名规范
3.3.1 类命名
- 使用 PascalCase(大驼峰命名)
- 类名应该是有意义的名词或名词短语
- Controller类以
Controller结尾 - Service接口以
I开头,实现类以Impl结尾 - Mapper接口以
Mapper结尾 - VO类以
Vo结尾 - Entity类使用业务名称
java
// ✅ 正确
public class UserController { }
public interface IUserService { }
public class UserServiceImpl implements IUserService { }
public class UserMapper { }
public class UserVo { }
public class SysUser { }
3.3.2 包命名
- 使用 小写字母,多个单词用点分隔
- 包名应该反映模块结构
java
// ✅ 正确
package com.soilsurvey.webapi.project.survey.controller;
package com.soilsurvey.webapi.common.core;
package com.soilsurvey.webapi.framework.config;
4. Spring Boot规范
4.1 Controller规范
4.1.1 Controller结构
java
@Api(tags = "01.1....模块名称")
@RestController
@RequestMapping("/ssp/module")
public class ModuleController {
@Autowired
private IService service;
@ApiOperation(value = "接口说明", notes = "详细说明")
@GetMapping("/list")
@RegionScope(paramName = "vo") // 如果需要区域权限控制
public Result getList(@ModelAttribute QueryVo vo) {
return Result.OK(service.getList(vo));
}
}
4.1.2 注解使用规范
- 依赖注入 : 优先使用
@Autowired,不使用@Resource - 请求参数 : 优先使用
@RequestParam、@RequestBody、@ModelAttribute - 路径参数 : 不推荐使用
@PathVariable(项目规范)
java
// ✅ 正确
@GetMapping("/page")
public Result getPage(
@RequestParam(required = false) String keyword,
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "10") Integer pageSize
) {
// ...
}
@PostMapping("/save")
public Result save(@RequestBody EntityVo vo) {
// ...
}
// ❌ 错误 - 使用@PathVariable
@GetMapping("/{id}")
public Result getById(@PathVariable Long id) {
// ...
}
4.1.3 返回值规范
- 统一使用
Result<T>包装返回值 - 成功使用
Result.OK(data) - 失败使用
Result.error(message)
java
// ✅ 正确
@GetMapping("/detail")
public Result getDetail(@RequestParam Long id) {
Entity entity = service.getById(id);
return Result.OK(entity);
}
@PostMapping("/save")
public Result save(@RequestBody EntityVo vo) {
try {
service.save(vo);
return Result.OK("保存成功");
} catch (Exception e) {
return Result.error("保存失败:" + e.getMessage());
}
}
4.2 Service规范
4.2.1 Service接口命名
- 接口以
I开头 - 实现类以
Impl结尾 - 接口和实现类在同一包下
java
// ✅ 正确
// 接口
public interface IUserService {
User getById(Long id);
Page<User> page(QueryVo vo);
}
// 实现类
@Service
public class UserServiceImpl implements IUserService {
@Autowired
private UserMapper userMapper;
@Override
public User getById(Long id) {
return userMapper.selectById(id);
}
}
4.2.2 方法命名规范
- 分页查询 :
page或getXxxPage - 列表查询 :
list或getXxxList - 详情查询 :
getById或getXxxDetail - 保存 :
save(新增或修改) - 新增 :
add(只新增) - 修改 :
update(只修改) - 删除 :
delete或remove
java
// ✅ 正确
public interface IUserService {
Page<User> page(UserQueryVo vo);
List<User> list(String keyword);
User getById(Long id);
void save(User user);
void add(User user);
void update(User user);
void delete(Long id);
}
4.3 Mapper规范
4.3.1 Mapper接口
- 继承
BaseMapper<T>(MyBatis-Plus) - 自定义方法使用
@Param注解 - 复杂查询写在XML中
java
// ✅ 正确
@Mapper
public interface UserMapper extends BaseMapper<User> {
List<User> selectByRegion(@Param("xzqdm") String xzqdm);
Page<User> selectPageWithJoin(
@Param("page") Page<User> page,
@Param("vo") UserQueryVo vo
);
}
4.3.2 XML映射文件
- 放在
resources/mapper目录下 - 命名与Mapper接口一致
- 使用MyBatis-Plus标签
xml
<!-- ✅ 正确 -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.soilsurvey.webapi.project.survey.mapper.UserMapper">
<select id="selectByRegion" resultType="User">
SELECT * FROM sys_user
WHERE xzqdm LIKE CONCAT(#{xzqdm}, '%')
</select>
</mapper>
4.4 Entity规范
4.4.1 Entity类结构
java
// ✅ 正确
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("ssp_gcsj_dcyd")
public class Dcyd extends BaseEntity {
@TableId(type = IdType.ASSIGN_ID)
private String id;
@TableField("ydbh")
private String ydbh;
@TableField("ydlb")
private String ydlb;
}
4.4.2 Lombok使用规范
- 使用
@Getter、@Setter - 禁止使用
@Data(项目规范) - 继承BaseEntity时使用
@EqualsAndHashCode(callSuper = true)
java
// ✅ 正确
@Getter
@Setter
@EqualsAndHashCode(callSuper = true)
public class User extends BaseEntity {
// ...
}
// ❌ 错误 - 使用@Data
@Data
public class User {
// ...
}
5. 文件命名规范
5.1 Java文件命名规则
- 类文件 : PascalCase(如:
UserController.java) - 接口文件 : PascalCase,以
I开头(如:IUserService.java) - 实现类 : PascalCase,以
Impl结尾(如:UserServiceImpl.java) - VO类 : PascalCase,以
Vo结尾(如:UserQueryVo.java) - Entity类 : PascalCase(如:
SysUser.java) - 枚举类 : PascalCase,以
Enum结尾(如:StatusEnum.java) - 工具类 : PascalCase,以
Utils结尾(如:DateUtils.java) - 常量类 : PascalCase,以
Constants结尾(如:RoleConstants.java)
5.2 资源文件命名规则
- Mapper XML : 与Mapper接口同名(如:
UserMapper.xml) - 配置文件 : kebab-case(如:
application.yml) - SQL脚本 : kebab-case(如:
ssp-system.sql)
5.3 目录命名规则
-
目录名使用 小写字母,多个单词用点分隔
-
包结构反映业务模块
com.soilsurvey.webapi
├── common # 共用代码
├── framework # 框架配置
└── project # 业务模块
├── survey # 业务逻辑
├── system # 系统管理
└── login # 登录模块
6. 目录结构规范
6.1 标准目录结构
src/main/java/com/soilsurvey/webapi/
├── common/ # 共用代码
│ ├── annotation/ # 自定义注解
│ ├── constant/ # 常量定义
│ ├── core/ # 核心类(Result、BaseEntity等)
│ ├── enums/ # 枚举类
│ └── utils/ # 工具类
├── framework/ # 框架配置和增强
│ ├── aspectj/ # AOP切面
│ ├── config/ # 配置类
│ ├── interceptor/ # 拦截器
│ ├── security/ # 安全配置
│ └── service/ # 框架服务
└── project/ # 业务模块
├── survey/ # 业务逻辑
│ ├── controller/ # 控制器
│ ├── service/ # 服务层
│ │ └── impl/ # 服务实现
│ ├── mapper/ # 数据访问层
│ ├── domain/ # 实体类
│ │ └── vo/ # 值对象
│ └── vo/ # 视图对象
├── system/ # 系统管理
└── login/ # 登录模块
src/main/resources/
├── mapper/ # MyBatis XML映射文件
│ └── system/
├── i18n/ # 国际化资源
└── application.yml # 配置文件
6.2 模块划分原则
- common: 所有模块共用的代码
- framework: 框架级别的配置和增强
- project: 业务模块,按功能划分
7. Git提交规范
7.1 提交信息格式
<type>(<scope>): <subject>
<body>
<footer>
7.2 提交类型(type)
- feat: 新功能
- fix: 修复bug
- docs: 文档更新
- style: 代码格式调整(不影响功能)
- refactor: 代码重构
- perf: 性能优化
- test: 测试相关
- chore: 构建过程或辅助工具的变动
7.3 提交示例
bash
# ✅ 正确
feat(survey): 添加智能查询功能
fix(region): 修复区域权限控制问题
docs(api): 更新API接口文档
refactor(service): 重构用户服务层代码
# ❌ 错误
update code
fix bug
修改
8. 注释规范
8.1 类注释
java
/**
* 用户管理Controller
* 提供用户相关的CRUD操作接口
*
* @author 张三
* @date 2024-01-01
*/
@RestController
@RequestMapping("/sys/user")
public class UserController {
// ...
}
8.2 方法注释
java
/**
* 分页查询用户列表
*
* @param keyword 关键词(可选)
* @param pageNum 页码,默认1
* @param pageSize 每页条数,默认10
* @return 分页结果
*/
@GetMapping("/page")
public Result<Page<User>> page(
@RequestParam(required = false) String keyword,
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "10") Integer pageSize
) {
// ...
}
8.3 复杂逻辑注释
java
// ✅ 正确 - 解释为什么这样做
// 使用LIKE前缀匹配,因为样点编号以行政区代码开头
queryWrapper.likeRight(Dcyd::getYdbh, xzqdm);
// ✅ 正确 - 解释复杂算法
// 计算区域样点统计:按行政区代码分组,统计每个区域的样点数量
List<Map<String, Object>> result = dcydList.stream()
.collect(Collectors.groupingBy(Dcyd::getXzqdm))
.entrySet().stream()
.map(entry -> {
Map<String, Object> map = new HashMap<>();
map.put("xzqdm", entry.getKey());
map.put("count", entry.getValue().size());
return map;
})
.collect(Collectors.toList());
// ❌ 错误 - 注释说明显而易见的内容
// 设置name变量
String name = "test";
9. 数据库规范
9.1 表命名规范
- 使用 小写字母 和 下划线
- 表名使用业务前缀(如:
ssp_gcsj_、ssp_cgsj_、sys_)
sql
-- ✅ 正确
ssp_gcsj_dcyd -- 过程数据-调查样点
ssp_cgsj_om -- 成果数据-有机质
sys_user -- 系统-用户
sys_dict -- 系统-字典
-- ❌ 错误
Dcyd -- 缺少前缀
user_table -- 使用驼峰命名
9.2 字段命名规范
- 使用 小写字母 和 下划线
- 字段名应该有意义,使用业务术语
- 主键统一使用
id - 时间字段使用
ctime(创建时间)、utime(更新时间)
sql
-- ✅ 正确
id -- 主键
ydbh -- 样点编号
ydlb -- 样点类别
xzqdm -- 行政区代码
ctime -- 创建时间
utime -- 更新时间
-- ❌ 错误
userId -- 使用驼峰命名
create_time -- 使用下划线但不符合项目规范
9.3 日期时间规范
- 统一使用
LocalDateTime类型 - 格式统一为
yyyy-MM-dd HH:mm:ss - 不使用
Date或Timestamp
java
// ✅ 正确
@TableField("dcsj")
private LocalDateTime dcsj;
// 格式化
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formatted = localDateTime.format(formatter);
// ❌ 错误
private Date dcsj;
private Timestamp dcsj;
10. API接口规范
10.1 接口路径规范
- 使用 RESTful风格
- 路径使用 小写字母 和 斜杠
- 模块路径使用业务前缀(如:
/ssp/、/sys/)
java
// ✅ 正确
@GetMapping("/ssp/onemap/ldtj") // 一张图-立地条件
@GetMapping("/ssp/process/ldtj/page") // 过程数据-调查采样-分页
@PostMapping("/ssp/public/appr") // 公共数据-申请提交
@GetMapping("/sys/user/page") // 系统管理-用户-分页
// ❌ 错误
@GetMapping("/getUserList") // 不符合RESTful
@GetMapping("/SSP/Onemap/Ldtj") // 使用大写
10.2 请求参数规范
- GET请求使用
@RequestParam或@ModelAttribute - POST请求使用
@RequestBody - 参数使用VO对象封装(复杂查询)
java
// ✅ 正确 - GET请求
@GetMapping("/page")
public Result page(
@RequestParam(required = false) String keyword,
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "10") Integer pageSize
) {
// ...
}
// ✅ 正确 - GET请求(复杂参数)
@GetMapping("/page")
public Result page(@ModelAttribute QueryVo vo) {
// ...
}
// ✅ 正确 - POST请求
@PostMapping("/save")
public Result save(@RequestBody EntityVo vo) {
// ...
}
10.3 响应数据规范
- 统一使用
Result<T>包装 - 分页数据使用
Page<T> - 列表数据使用
List<T>
java
// ✅ 正确
@GetMapping("/detail")
public Result<User> getDetail(@RequestParam Long id) {
User user = service.getById(id);
return Result.OK(user);
}
@GetMapping("/page")
public Result<Page<User>> getPage(@ModelAttribute QueryVo vo) {
Page<User> page = service.page(vo);
return Result.OK(page);
}
@GetMapping("/list")
public Result<List<User>> getList() {
List<User> list = service.list();
return Result.OK(list);
}
10.4 Swagger文档规范
- 使用
@Api标注Controller - 使用
@ApiOperation标注方法 - 使用
@ApiModelProperty标注VO字段
java
// ✅ 正确
@Api(tags = "01.1....一张图-基础信息")
@RestController
@RequestMapping("/ssp/onemap")
public class OneMapController {
@ApiOperation(value = "一张图-立地条件调查信息", notes = "根据样点编号获取立地条件详情")
@GetMapping("/ldtj")
public Result getLdtjdcxx(@RequestParam String ydbh) {
// ...
}
}
// VO类
public class QueryVo {
@ApiModelProperty(value = "行政区代码", example = "420100")
private String xzqdm;
@ApiModelProperty(value = "页码", example = "1")
private Integer pageNum = 1;
}
11. 最佳实践
11.1 异常处理
- 使用统一的异常处理机制
- 业务异常使用
Result.error() - 记录异常日志
java
// ✅ 正确
@PostMapping("/save")
public Result save(@RequestBody EntityVo vo) {
try {
service.save(vo);
return Result.OK("保存成功");
} catch (IllegalArgumentException e) {
log.warn("参数错误:{}", e.getMessage());
return Result.error("参数错误:" + e.getMessage());
} catch (Exception e) {
log.error("保存失败", e);
return Result.error("保存失败,请稍后重试");
}
}
11.2 日志规范
- 使用
@Slf4j注解(Lombok) - 日志级别:
error、warn、info、debug - 关键操作记录日志
java
// ✅ 正确
@Slf4j
@Service
public class UserServiceImpl implements IUserService {
public void save(User user) {
log.info("保存用户:{}", user.getUserName());
try {
userMapper.insert(user);
log.info("用户保存成功,ID:{}", user.getId());
} catch (Exception e) {
log.error("用户保存失败:{}", user.getUserName(), e);
throw e;
}
}
}
11.3 缓存使用
- 使用
@Cacheable标注可缓存方法 - 使用
@CacheEvict标注需要清除缓存的方法 - 缓存键要唯一且有意义
java
// ✅ 正确
@Cacheable(value = "left_panel", key = "'left_' + #xzqdm")
public Result getLeftPanel(@RequestParam String xzqdm) {
// ...
}
@CacheEvict(value = "left_panel", allEntries = true)
public Result clearCache() {
// ...
}
11.4 权限控制
- 使用
@RegionScope注解进行区域权限控制 - 在Controller方法上标注
- 指定参数名(VO对象使用
paramName)
java
// ✅ 正确
@RegionScope(paramName = "vo")
@GetMapping("/page")
public Result getPage(@ModelAttribute QueryVo vo) {
// ...
}
@RegionScope
@GetMapping("/list")
public Result getList(@RequestParam String xzqdm) {
// ...
}
11.5 代码复用
- 使用
BaseEntity作为实体基类 - 使用
BaseQueryVo作为查询VO基类 - 使用
Result<T>统一返回格式 - 使用
UserToken获取当前用户
java
// ✅ 正确
public class User extends BaseEntity {
// 自动继承id、ctime、utime等字段
}
public class UserQueryVo extends BaseQueryVo {
// 自动继承pageNum、pageSize
private String keyword;
}
public Result<User> getUser(UserToken userToken) {
// 使用userToken获取当前用户信息
String gsddm = userToken.getUser().getGsddm();
// ...
}
11.6 性能优化
- 大数据量查询使用分页
- 使用并行流处理大数据集
- 合理使用缓存
- 避免N+1查询问题
java
// ✅ 正确 - 使用并行流
ExecutorService executor = Executors.newFixedThreadPool(3);
CompletableFuture<List<Map<String, Object>>> future1 =
CompletableFuture.supplyAsync(() -> service.getData1(), executor);
CompletableFuture<List<Map<String, Object>>> future2 =
CompletableFuture.supplyAsync(() -> service.getData2(), executor);
CompletableFuture.allOf(future1, future2).join();
11.7 代码检查
- 提交前使用IDEA的
Analyze -> Inspect Code检查 - 使用 Alibaba Java Coding Guidelines 插件
- 修复所有警告和错误
- 删除未使用的导入和变量
附录:常用代码模板
Controller模板
java
@Api(tags = "XX.1....模块名称")
@RestController
@RequestMapping("/ssp/module")
public class ModuleController {
@Autowired
private IModuleService moduleService;
@ApiOperation(value = "接口说明")
@GetMapping("/page")
@RegionScope(paramName = "vo")
public Result<Page<Entity>> getPage(@ModelAttribute QueryVo vo) {
Page<Entity> page = moduleService.page(vo);
return Result.OK(page);
}
}
Service接口模板
java
public interface IModuleService {
Page<Entity> page(QueryVo vo);
Entity getById(Long id);
void save(Entity entity);
void delete(Long id);
}
Service实现模板
java
@Slf4j
@Service
public class ModuleServiceImpl implements IModuleService {
@Autowired
private ModuleMapper moduleMapper;
@Override
public Page<Entity> page(QueryVo vo) {
Page<Entity> page = new Page<>(vo.getPageNum(), vo.getPageSize());
return moduleMapper.selectPage(page, buildQueryWrapper(vo));
}
private LambdaQueryWrapper<Entity> buildQueryWrapper(QueryVo vo) {
LambdaQueryWrapper<Entity> wrapper = Wrappers.lambdaQuery();
if (StrUtil.isNotEmpty(vo.getKeyword())) {
wrapper.like(Entity::getName, vo.getKeyword());
}
return wrapper;
}
}