服务端
目录结构
├─📂 server //服务端根目录(管理后台、接口)
│ ├─📂 like-admin.src.main //后台应用
│ │ ├─📂 java.com.mdd.admin //Java包
│ │ │ ├─📂cache //缓存层
│ │ │ ├─📂config //配置层
│ │ │ ├─📂controller //控制器
│ │ │ ├─📂service //服务层
│ │ │ │ ├─📂impl //实现层
│ │ │ ├─📂validate //Dto层
│ │ │ ├─📂vo //Vo层
│ │ │ ├─📄LikeAdminApplication //项目入口文件
│ │ │ ├─📄LikeAdminInterceptor //项目的拦截器
│ │ │ ├─📄LikeAdminThreadLocal //项目本地线程
│ │ ├─📂 resources //资源目录
│ │ │ ├─📂META-INF //配置
│ │ │ ├─📂static //静态目录
| | | ├─📄application.yml //项目配置文件
| | | ├─📄banner.txt //启动Banner
| | | ├─📄log4j2-spring.xml //日志配置文件
│ │
│ ├─📂 like-front.src.main //前端应用
│ │ ├─📂 java.com.mdd.front //Java包
│ │
│ ├─📂 like-common //公共类库
│ │ ├─📂config //全局配置
│ │ ├─📂core //核心目录
│ │ ├─📂entity //实体目录
│ │ ├─📂exception //异常目录
│ │ ├─📂mapper //Mapper
│ │ ├─📂plugin //扩展插件
│ │ ├─📂utils //工具目录
│ │ ├─📂validator //自定验证器
│ |
| ├─📂 like-generator //代码生成器
开发规范
- cache
- 统一存放缓存的实现类
- controller
- controller只做简单的调用,不做具体的逻辑实现,代码相对来说比较简介。
- controller主要参与参数的接收,调用服务类,返回JSON数据
- 如特殊要求不在此处编写逻辑代码
- service
- 主要编写功能相关逻辑,提供给controller层调用,或者其它service层调用
- validate
- 负责请求参数的处理和对参数的校验
- vo
- 负责返回前端规定的字段格式
公共状态
全局公共的响应状态码,方便根据状态码排查错误
您可以根据自己的项目需求调整或者增减都是可以的。
// 定义位置: com.mdd.common.enums => HttpEnum
SUCCESS(200, "成功"),
FAILED(300, "失败"),
PARAMS_VALID_ERROR(310, "参数校验错误"),
PARAMS_TYPE_ERROR(311, "参数类型错误"),
REQUEST_METHOD_ERROR(312, "请求方法错误"),
ASSERT_ARGUMENT_ERROR(313, "断言参数错误"),
ASSERT_MYBATIS_ERROR(314, "断言Mybatis错误"),
LOGIN_ACCOUNT_ERROR(330, "登录账号或密码错误"),
LOGIN_DISABLE_ERROR(331, "登录账号已被禁用了"),
TOKEN_EMPTY(332, "token参数为空"),
TOKEN_INVALID(333, "token参数无效"),
CAPTCHA_ERROR(334, "验证码错误"),
NO_PERMISSION(403, "无相关权限"),
REQUEST_404_ERROR(404, "请求接口不存在"),
SYSTEM_ERROR(500, "系统错误");
请求拦截
- 说明
- 无论是
登录拦截
还是权限拦截
,统一都在LikeAdminInterceptor
完成。
- 无论是
- 注意
- 目前权限框架使用了
sa-token
如果对此框架没有了解,请先看下官方文档! - sa-token官方文档: https://sa-token.cc/doc.html
- 目前权限框架使用了
- 拦截
@NotLogin
:免登录注解@NotPower
:免权限注解@NotLogin
和@NotPower
正常来说这两个注解不会同时出现在一个方法上。- 因为如果添加了免登录,则不需要登录权限
- 配置示例:
@NotLogin // 在方法上加上此注解,标识该接口不需要登录也能访问 @NotPower // 加上此注解,标识该方法不需要校验权限 @GetMapping("/config") @ApiOperation(value="公共配置") public AjaxResult<Map<String, Object>> config() { Map<String, Object> map = iIndexService.config(); return AjaxResult.success(map); }
管理员
// 一、如何获取当前管理员ID
Integer adminId = LikeAdminThreadLocal.getAdminId();
// 二、如何获取当前角色ID
Integer roleId = LikeAdminThreadLocal.getRoleId();
// 三、如何获取当前管理员信息
Integer adminId = LikeAdminThreadLocal.getAdminId(); // 管理员ID
Integer roleId = LikeAdminThreadLocal.getRoleId(); // 管理员角色ID
String username = LikeAdminThreadLocal.get("username").toString(); // 账号
工具库
工具类
- ArithUtil : 算术运算工具
- ListUtil : 列表数组工具
- MapUtil : Map对象工具
- ConfigUtil : 配置管理工具
- HttpUtil : Http请求工具
- IpUtil : Ip获取工具
- RedisUtil : Redis工具
- RequestUtil : 请求信息工具
- SpringUtil : Spring容器工具
- TimeUtil : 时间日期工具
- ToolsUtil : 通用工具类
- UrlUtil : 资源路径处理工具
- YmlUtil : application配置获取工具
搜索器
为了更方便的实现搜索功能,为此设计了一个基本的搜索器工具
此工具可以实现一些常见的搜索条件,这样就可以省略很多if语句
// 使用示例
systemAdminMapper.setSearch(queryWrapper, params, new String[]{
"like:username:str",
"like:nickname:str",
"like:email@t.eamil:str",
"=:role:int",
"datetime:startTime-endTime@create_time:str"
});
// 参数说明:
systemAdminMapper:是Mapper类,因为此工具定义在了Mapper基类,所以它的子类可以直接使用
queryWrapper: 此参数是条件构造器
params: 是前端传递过来的参数: Map<String, String> params
new String[]{} : 里面的是搜索条件规则,满足条件就会实现搜索
// 条件说明
如: like:username:str
like: 标识模糊搜索 %username%
username: 表示参数的字段,需和数据库字段一致
str: 表示是字符串类型的 其它类型有: [str, long, int]
如: "like:email@t.eamil:str",
这里的: email@youxiang 分别是什么意思呢?
email: 表示前端传递过来的参数名称
youxiang: 表示数据库中的字段名
为什么这样做?: 因为前端传递的字段名 可能 和 数据库中的不一致!
// 特别的时间查询
如: datetime:startTime-endTime@create_time:str
表示时间范围查询: 开始时间 ~ 结束时间 查询字段是 create_time
如: datetime:startTime@create_time:str
表示时间范围查询: 开始时间 ,不限制结束时间 查询字段是 create_time
如: datetime:startTime@create_time:long
表示前端需要传递时间戳去查询, long=时间戳, str=日期事件
// 【提供的条件有】
=
<>
>=
>
<=
<
between
notBetween
like
notLike
likeLeft
likeRight
in
notIn
datetime
验证器
- 验证器可以理解为参数接收的dto, 每一个方法对应一个实体类
- 旧版本采用了分组验证的方式, 但个人觉得不太好维护,故而改成单一得实体类
// 1、以下是示例代码
@Data
public class ArticleCreateValidate implements Serializable {
private static final long serialVersionUID = 1L;
@IDMust(message = "cid参数必传且需大于0")
private Integer cid;
}
// 2、自定义验证器
// 验证主键ID
@IDMust(message = "cid参数必传且需大于0")
// 验证整数类型得数组
@IntegerContains(values = {0, 1}, message = "isShow不是合法值")
// 验证字符串类型得数组
@StringContains(values = {"add", "edit"}, message = "isShow不是合法值")
// 3、实现自己的参数验证器
// 你可以把它写在此路径下: like-common/src/main/java/com.mdd.commpn/validator
权限拦截
注意
后台端已接入了sa-token来管理登录和权限拦截
权限拦截处理函数位置: like-admin/src/java/com.mdd.admin/config/stp/StpInterConfig
如果你想修改权限拦截规则 可以在此文件调整, 具体请参考sa-token的文档
IDEA注释
开启IDEA的目录注释,增加源码的阅读效率 treeinfotip
安装操作: File -> Settings -> Plugins -> Marketplace
Swagger3配置
- swagger默认是开启状态, 如果你需要关闭可以在
application.yml
中进行配置 - 注意: 在生产环境中, 最好把swagger关闭
- 访问地址: http://localhost:8084/swagger-ui/index.html
- PS: 地址中的 http://localhost:8084 改成你自己的项目地址
like:
# 上传目录
upload-directory: /www/uploads/likeadmin-java/
# Swagger配置
swagger:
# 是否开启swagger
enabled: true
# 请求前缀
pathMapping: /dev-api
短信发送
NoticeSmsVo params = new NoticeSmsVo()
.setScene(smsValidate.getScene()) // 场景码
.setMobile(smsValidate.getMobile()) // 接收的手机号
.setExpire(900) // 设置验证码失效时长, 可不设置
.setParams(new String[] { // 短信模板附带的参数
"code:" + ToolUtils.randomInt(4)
});
NoticeDriver.handle(params);
验证【验证码】
// 导入验证的类
import com.mdd.common.plugin.notice.NoticeCheck;
// 需验证的场景码
int sceneCode = NoticeEnum.LOGIN_CODE.getCode();
// 进行验证判断
if (!NoticeCheck.verify(sceneCode, code)) {
throw new OperateException("验证码错误!");
}