|
@@ -1,4 +1,5 @@
|
|
|
-## 基础框架
|
|
|
+
|
|
|
+# 基础框架
|
|
|
|
|
|
框架基于ruoyi-vue版本,做了部分优化改造,并命名为miaxis。
|
|
|
|
|
@@ -33,10 +34,16 @@
|
|
|
* 新增非系统用户的登录方式,包含密码登录和手机验证码登录
|
|
|
* ResponseEnum统一状态消息管理,方便排查问题
|
|
|
* 修改打包方式为war包,方便部署远程tomcat
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
# 技术选型
|
|
|
* 前端:Vue、Element UI
|
|
|
* 后端:Spring Boot、Spring Security、Redis、Jwt、Swagger2 & Swagger-Bootstrap-UI、 Lombok、mybatis、mybatis-plus。
|
|
|
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
# 项目结构
|
|
|
|
|
|
```
|
|
@@ -63,48 +70,169 @@ com.miaxis
|
|
|
```
|
|
|
|
|
|
# 后端开发流程
|
|
|
-1. 创建表,表结构规范参考
|
|
|
-2. 使用代码生成器
|
|
|
+## 创建表
|
|
|
+建表规范,参考表结构规范参考
|
|
|
+## 使用代码生成器
|
|
|
本次以sys_config举例,实际项目中不要去生成系统自带的sys开头的表,否则启动不了,因为代码模板不一样,有细微区别
|
|
|
打开后台管理系统,点击菜单——>系统工具——>代码生成
|
|
|
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
|
|
|
如果生成之前要更改信息,可以点击编辑进入更改,注意要修改路径,模块名
|
|
|
|
|
|
-
|
|
|
+
|
|
|
|
|
|
|
|
|
可以点击预览查看代码生成的效果
|
|
|
|
|
|
-
|
|
|
+
|
|
|
|
|
|
勾选然后可以点击生成(如果数据库中配好了comment注释,和table注释可以直接生成注释文字)
|
|
|
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
+解压后可以看到代码生产结果,然后拷贝到项目中对应的文件夹即可——main是java代码,vue是前端代码,deptMenu.sql是在菜单表中添加一条菜单数据,后端而言,可以直接复制整个main文件夹到我们项目模块src下,并且将controller 剪切到 admin 模块中
|
|
|
|
|
|
-解压后可以看到代码生产结果,然后拷贝到项目中对应的文件夹即可——main是java代码,vue是前端代码,deptMenu.sql是在菜单表中添加一条菜单数据,后端而言,可以直接复制整个main文件夹到我们项目模块src下
|
|
|
+
|
|
|
+
|
|
|
+如果该表是实体表,在前端有相应的列表,则需要将xxxMenu.sql在数据库中执行,即可以把相应的菜单按钮权限等数据写入数据库(这样可以不用在后台管理系统中去手动添加)
|
|
|
|
|
|
-
|
|
|
|
|
|
到此,基本的增删改查代码已经生成。
|
|
|
|
|
|
-3. swagger文档使用
|
|
|
+## swagger文档使用
|
|
|
|
|
|
未登录授权前,接口无法调试
|
|
|
|
|
|
-
|
|
|
+
|
|
|
|
|
|
登录用法-用登录(免验证码)
|
|
|
|
|
|
-
|
|
|
+
|
|
|
|
|
|
然后保存
|
|
|
|
|
|
-
|
|
|
+
|
|
|
|
|
|
之后就能愉快的调试了
|
|
|
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+# 后端开发规范
|
|
|
+## 命名规范
|
|
|
+
|
|
|
+* 命名使用英文词组合,使用驼峰式,严禁使用中文拼音或拼音首字母组合命名(专有名词例外) 如: OrganizationTreeNode, OrganizationVO, OrganizationDTO, 常量应该用全大写,下划线命名,如: APP_SECRET
|
|
|
+* Controller, Service, Mapper统一添加到对应分层目录
|
|
|
+* 接口实现类添加Impl后缀标识
|
|
|
+* 枚举类添加Enum后缀标识
|
|
|
+* 接口api路径,使用restful风格命名规范,简单来说,url上不允许出现动词,只能使用名次,动作由请求方式来制定:GET-获取 POST-新增
|
|
|
+PUT-更新 DELETE-删除(可以参考代码生成器生成的代码)
|
|
|
+
|
|
|
+## 返回值类型
|
|
|
+
|
|
|
+http请求固定返回类型Response ,泛型一定要指定类型,否则swagger无法识别返回值具体数据格式以及注解,如
|
|
|
+
|
|
|
+```java
|
|
|
+@GetMapping(value = "/{id}")
|
|
|
+@ApiOperation("获取电子教学日志详细信息")
|
|
|
+public Response<TMClassRecordDetail> getInfo(
|
|
|
+ @ApiParam(name = "id", value = "电子教学日志参数", required = true)
|
|
|
+ @PathVariable("id") Long id){
|
|
|
+
|
|
|
+ return Response.success(tMClassRecordDetailService.getById(id));
|
|
|
+}
|
|
|
+
|
|
|
+```
|
|
|
+## 异常
|
|
|
+* Controller层,可直接使用Response.error ,重载了多个方法,根据具体情形使用
|
|
|
+
|
|
|
+```java
|
|
|
+@Log(title = "电子教学日志", businessType = BusinessTypeEnum.INSERT)
|
|
|
+@PostMapping
|
|
|
+@ApiOperation("新增电子教学日志")
|
|
|
+public Response<Integer> add(@RequestBody TMClassRecordDetail tMClassRecordDetail){
|
|
|
+ if (tMClassRecordDetail == null){
|
|
|
+ return Response.error();
|
|
|
+ }
|
|
|
+ return toResponse(tMClassRecordDetailService.save(tMClassRecordDetail) ? 1 : 0);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+```
|
|
|
+* service层,若有运行时异常,无需捕获,直接抛出自定义异常,如业务异常:CustomException,统一由全局 异常处理器GlobalExceptionHandler 进行处理,例子如下:
|
|
|
+
|
|
|
+```java
|
|
|
+private void validateCode(String principal, String credential) {
|
|
|
+ if (StringUtils.isEmpty(credential)){
|
|
|
+ throw new CustomException("验证码不能为空");
|
|
|
+ }
|
|
|
+ String cacheCode = (String) redisTemplate.opsForValue().get(RedisPrefixUtils.getSmsKeyPrefix("login", principal));
|
|
|
+ if (StringUtils.isEmpty(cacheCode)){
|
|
|
+ throw new CustomException("验证码已过期,请重新发送");
|
|
|
+ }else if (!credential.equals(cacheCode)){
|
|
|
+ throw new CustomException("验证码不正确");
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+```
|
|
|
+## 枚举类
|
|
|
+
|
|
|
+原则上,代码中不应该出现魔法数字,比如下面代码
|
|
|
+```java
|
|
|
+if (type == 1){
|
|
|
+ xxx
|
|
|
+}
|
|
|
+```
|
|
|
+正确做法应该新建一个枚举类,如
|
|
|
+```java
|
|
|
+public enum UserStatusEnum
|
|
|
+{
|
|
|
+ OK("0", "正常"), DISABLE("1", "停用"), DELETED("2", "删除");
|
|
|
+
|
|
|
+ private final String code;
|
|
|
+ private final String info;
|
|
|
+
|
|
|
+ UserStatusEnum(String code, String info)
|
|
|
+ {
|
|
|
+ this.code = code;
|
|
|
+ this.info = info;
|
|
|
+ }
|
|
|
+
|
|
|
+ public String getCode()
|
|
|
+ {
|
|
|
+ return code;
|
|
|
+ }
|
|
|
+
|
|
|
+ public String getInfo()
|
|
|
+ {
|
|
|
+ return info;
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+使用的时候
|
|
|
+```java
|
|
|
+if (type == UserStatusEnum.OK.getCode()){
|
|
|
+ xxx
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+## 入参,出参
|
|
|
+
|
|
|
+如果传入参数与实体字段相差较大,可以新建DTO对象,DTO 意思为数据传输对象,包含了出参,入参,如果为了区分,也可以把入参命名为DTO,返参命名为VO
|
|
|
+```java
|
|
|
+@PostMapping("/login")
|
|
|
+@ApiOperation("系统-登录方法")
|
|
|
+public Response<TokenDTO> login(@RequestBody LoginBody loginBody)
|
|
|
+{ TokenDTO tokenDTO = new TokenDTO();
|
|
|
+ // 生成令牌
|
|
|
+ String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
|
|
|
+ loginBody.getUuid());
|
|
|
+ tokenDTO.setToken(token);
|
|
|
+ return Response.success(tokenDTO);
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
|