这是一篇记录如何从建仓开始到最后安全测试完整流程的笔记,使用的spring
生态,目的是为spring
的基础后端开发及后期渗透测试打一个模板。本篇采用springSecurity作为安全框架,搭载了redis-cache
、spring-valid
等功能,并开放了OAuth2授权登录。
本篇代码格式规范为优雅,代码大量使用java8
新特性以及apache
包下方便的工具类,能一行代码写完的就不用两行。当然本文也配备了大量注释,方便有需要的同学学习。
限于篇幅,文章内只能简短提及使用原因以及简略使用方法,具体步骤还请参考本篇附带代码或百度
代码仓库:https://github.com/23DAY01/blog_23DAY
项目初始化
创建git仓库
github上创建一个仓库,复制仓库地址
https://github.com/xxx/xxx.git
创建spring项目
文件
->新建
->来自版本控制的项目
->填写仓库地址
文件初始化
根据项目需要,更改.gitignore
并修改配置文件
测试提交
- git命令行
git add –ignore-error **.java
git commit -m 'init'
git push --progress --porcelain origin refs/heads/master:master
- 用idea的GUI直接提交也可以
JavaBean
设计原则
- 设置逻辑删除字段
- 设置生成时间、更新时间字段
- 单一关联时可违反第三范式
- 不设置外键
数据表
为不占用篇幅,数据表放在篇末
生成实体类
诸多工具可以实现从数据库直接生成pojo实体类,本篇采用mybatis plus
Mybatis-Plus生成器生成domain、dto、vo、controller、service、serviceImpl、mapper、mapperXml
生成器模板具体见mybatis-plus使用手册
领域驱动
这里简单描述一下领域驱动,他主要的目的是为了降低各层之间的耦合,业务层只做业务逻辑
对象 | 含义 | 作用 | 作用范围 |
---|---|---|---|
DO(Data Object) | 数据对象 | 与数据库表结构对应,通过DAO层向上传输数据源对象 | 数据库与Dao层,Dao层与Service层 |
DTO(Data Transfer Object) | 数据传输对象 | 主要用于远程调用等需大量传输对象的地方 | Sevice层和Web层 |
BO(Business Object) | 业务对象 | 业务对象,可以由 Service 层输出的封装业务逻辑的对象 | Sevice层和Web层 |
VO(View Object) | 视图对象 | 对应页面所显示的数据,将这些数据进行封装并返回 | Web层与页面 |
POJO(Plain Ordinary Java Object) | 普通Java对象 | - | - |
盗用别人的一张图来描述领域驱动
当业务不复杂的时候BO和DTO可以合成一个,VO可以直接使用DTO
概念是死的,人是活的,当团队协作开发时一定要保证大家理解的概念是一样的
本篇采用的是domain
、dto
、vo
三层
JavaBean转换
对于pojo封装的实体类在各层之间的转换,可以采用工具进行转换
- mapStruct
- spring
- hutools
- EntityUtils
- BeanCopier
- ……
本篇采用的是mapStruct进行实体类转化
引入依赖,编写转换器即可使用。mapStruct在打包后会自动生成一段转换代码,并不是使用反射的方式去进行javabean的转换。在转换的过程中,字段名相同的字段会直接转换,不同的字段需要使用@Mapping
注解定义,对于嵌套的字段,mapStruct会在自身中自动寻找对应的转换方法。
@Mapper(componentModel = "spring" , injectionStrategy = InjectionStrategy.CONSTRUCTOR)
@Component
public interface MapStruct {
@Mappings({
@Mapping(target = "id",source = "studentId"),
})
Student studentConvert(StudentRequestVo studentRequestVo);
}
API文档
业务状态码
目前大家对于业务状态码的评论出现两极分化状态,详见https://www.v2ex.com/t/611572
本篇采用业务状态码,并参考微信小程序官方给出的状态码设计规则,自定义状态码
- 前三位遵循http状态码:200、400、500
- 中间两位表示错误范围(file、param、authentication等)
- 后两位表示细粒度错误类型
业务状态码已放在篇末
swagger/knife4j
生成接口文档,导入包并配置文件Knife4jConfig
,使用@Api
@ApiOperation
@ApiParam
等标注方法和类,在写完业务逻辑后访问配置文件中配置的文档地址,即可查看全部标注过的接口
Knife4j是一个集Swagger2 和 OpenAPI3为一体的增强解决方案
接口设计
RESTful 的核心思想就是,客户端发出的数据操作指令都是"动词 + 宾语"的结构。比如,GET /articles这个命令,GET是动词,/articles是宾语。
- GET:读取(Read)
- POST:新建(Create)
- PUT:更新(Update)
- PATCH:更新(Update),通常是部分更新
- DELETE:删除(Delete)
宾语就是 API 的 URL,是 HTTP 动词作用的对象。它应该是名词,不能是动词。比如,/articles这个 URL 就是正确的
耦合处理
通过构建常量、枚举、工具等类降低项目耦合性,减小后期维护难度
枚举常量
constant
常量类 | 描述 |
---|---|
AuthConst | 认证常量,token过期时间、随机数种子等 |
CommonConst | 公共常量 |
DateConst | 日期常量,借鉴hutool封装的日期常量 |
OptTypeConst | 操作日志常量,操作类型等 |
RedisPrefixConst | redis常量,用于生成redis的key |
SocialLoginConst | 登录常量,oauth2相关常量 |
StatusMsgConst | 业务状态码常量 |
WebConst | 数据包常量 |
enums
- FileExtEnum
- FilePathEnum
- LoginTypeEnum
- StatusCodeEnum
- UploadModeEnum
工具类
如果想自己造轮子可以仿照诸多工具去自己造,不想造的话直接调用即可
工具类 | 描述 |
---|---|
ArithmeticUtil.java | 浮点数算数工具,用于提供server性能计算 |
AuthUtil.java | 认证工具,用于支持SpringSecurity |
BeanCopyUtil.java | 实体类转换工具,spring自带工具 |
ConvertUtil.java | 类型转换工具 |
DateUtil.java | 日期工具 |
FileUtil.java | 文件工具 |
JsonUtil.java | Json处理工具 |
JwtUtil.java | JWT工具,用于支持SpringSecurity |
MapStruct.java | 实体类转换工具,mapStruct |
OssUtil.java | OSS工具 |
RedisUtil.java | redis工具 |
ResponseAPI.java | 封装响应体 |
EncryptUtil.java | 加解密工具 |
StringUtil.java | 字符串工具 |
WebUtil.java | 网络工具,处理数据包 |
异常处理
GlobalExceptionHandler
利用@RestControllerAdvice
和@ExceptionHandler
注解实现异常统一处理
目前对于异常自定义的写法有很多,本篇采用的是根据多篇文章和Java特性自己总结出来的一种写法,主旨依旧是降低耦合、提高复用性
自定义异常,并继承BaseException,复写withErrorMessage
和withErrorCodeEnum
即可
对于异常处理的流程:
-
DAO
- 尽量不 catch 任何异常, 该向上抛就抛
- 不用记录 log 日志, 或者仅使用 logger.debug() 记录
-
Service
- 对于一些关键问题,应该及时
throw
异常, 以确保事务完整 - Service 层一般的日志级别, 应该用 logger.debug() 记日志
- 对于一些关键问题,应该及时
-
Controller 层:
- Controller 层负责组装 Service, 在关键步骤上应该加日志输出 (info 级别)
- Controller 层不应再主动 throw 异常
-
统一异常处理层:
通过 json 或 UI 返回详细的报错信息, 包括 HttpStatus 和详尽的 ErrorCode/ErrorMessage
日志框架
本篇采用slf4j+logback记录日志
导入包并进行文件配置logback-spring.xml`
可以通过@Log4j2
注解,在方法内部直接使用log即可
缓存技术
为了提高性能,引入缓存技术,目前springCache的实现有很多种
- GENERIC
- JCACHE
- EHCACHE
- HAZELCAST
- INFINISPAN
- COUCHBASE
- REDIS
- CACHE2K
- CAFFEINE
- SIMPLE
- NONE
本篇采用redis,继承CachingConfigurerSupport
复写配置方法即可自定义key与过期时间等
首先连接redis,进行文件配置RedisConfig
,编写redisUtil
方便redis数据操作,编写配置文件CacheConfig
并选定redis作为缓存类型即可
注解:
@Cacheable
:当重复(n>1)调用该方法时,不次执行方法体,其结果直接从缓存中找到并返回@CachePut
:确保方法调用即执行,执行后更新缓存@CacheEvict
:@Cachable
注解的反向操作,它负责从给定的缓存中移除一个值@Caching
:@Caching
是一个组注解,可以为一个方法定义提供基于@Cacheable
、@CacheEvict
或者@CachePut
注解的数组@CacheConfig
:在@CacheConfig
注解中定义了类级别的缓存和自定义键生成器
切面编程
spring里可以有三种方法实现切面编程,过滤器、拦截器、切面
三者的顺序为:过滤器->拦截器->切面
可以根据业务需要使用三者中的任意一个进行业务逻辑的编写
拦截器可以访问controller上下文、值栈里的对象,而过滤器不能访问
拦截器可以获取IOC容器中的各个bean,而过滤器就不行
操作日志
如果有对人员的行为进行记录的需求,则可以通过自定义注解OptLog
,然后写一个切面OptLogAspect
,并配置切入点即可实现对重点资产的操作行为记录
接口限流
实现对部分接口的接口限流操作,防止人员恶意访问接口。通过自定义注解AccessLimit
,通过实现HandlerIntercept
生成自定义拦截器ApiAccessRestrictionInterceptor
,注入到spring里面,并在WebMvcConfigurer
中添加拦截器
重复提交限制
实现对部分接口的重复提交限制。通过自定义注解RepeatSubmit
,通过实现HandlerIntercept
生成自定义拦截器RepeatSubmitInterceptor
,注入到spring里面,并在WebMvcConfigurer
中添加拦截器
安全框架
认证安全
本篇实现的是1.5次开发的springSecurity,复写了一部分的springSecurity的处理器,实现了部分的定制,这一部分内容推荐大家自己debug一下源码,这样会更容易理解
采用session管理用户,session信息保存在redis里面
所有bean注入全部放入SecurityBeanCreateConfig
本篇由于重写了UsernamePasswordAuthenticationFilter
,所以对于springSecurity
的原有配置做了比较大的改动,配置起来较为麻烦
认证
继承WebSecurityConfigurerAdapter
对configure
复写,对http
进行配置
- formLogin
- 复写
loadUserByUsername
- 认证成功处理器
authenticationSuccessHandler
- 认证失败处理器
authenticationFailHandler
- 登录url
- 复写
- logout
- 登出成功处理器
logoutSuccessHandler
- 登出url
- 登出成功处理器
- authorizeRequests
- 密码比对策略
DaoAuthenticationProviderImpl
- 自定义接口拦截规则
filterInvocationSecurityMetadataSource
- 自定义权限提取规则
accessDecisionManager
- 密码比对策略
- rememberMe
- 其他配置
- 前认证检查
preAuthenticationChecks
- 后认证检查
postAuthenticationChecks
- 前认证检查
会话管理
利用@EnableRedisHttpSession
开启redis管理session
在WebSecurityConfig
中配置http.session
- sessionId策略
- session过期策略
- session并发策略
- session集群会话处理
- session错误策略
上述部分策略由CompositeSessionAuthenticationStrategy
集合后注入到LoginAuthenticationFilter
其余策略注入到springSecurity
配置的session管理器中
验证码
本篇采用图形验证码,先编写配置文件CaptchaConfig
,VerificationCodeFilter
实现OncePerRequestFilter
在WebSecurityConfig
中的http.addFilterAt
将VerificationCodeFilter
添加过滤器在UsernamePasswordAuthenticationFilter
在前面即可
数据流恢复
通过BodyReaderRequestWrapper
和RepeatableFilter
恢复数据流,通过repeatableFilterRegistration
方法注册,解决在Filter中读取Request中的流后,后续controller或restful接口中无法获取流的问题
将取出来的字符串,再次转换成流,然后把它放入到新request 对象中,在chain.doFiler方法中 传递新的request对象
网络配置
实现WebMvcConfigurer
,配置定义的拦截器,解决跨域问题以及资源处理器问题
数据校验
由于对外接口全部体现为VO,我们在VO的对应字段上加入@Valid
的相关注解,并在参数位置使用@Valid
即可实现对数据的校验
- 针对 UI 输入检查, 如果 js 前端检查有困难, 可以在 Controller 层使用 Pojo validation 手段做检查, 然后前端使用 ajax 拿到校验结果. 检查过程没有触发 UI 完整渲染, 用户体验会很好
- Controller 层使用 validation 进行检查, 可以在视图函数的形参上检查, 或者在视图函数内部检查.
- Service 层, 使用 Assert 进行数据验证
- DAO 层, 不做任何数据验证
会话监听
通过session
监听器对session
的创建、销毁等行为进行自定义,其中就包括存在于session
里面的id,即每次会话产生一次作用的javabean
RedisHttpSessionListener
通过实现HttpSessionListener
能监听session
的创建销毁,实现HttpSessionAttributeListener
能监听session
里面的键值的创建销毁,然后将RedisHttpSessionListener
作为bean注入到spring里面就可以实现监听了
注入检测
通过加一层过滤器实现对输入的安全过滤
定义过滤器后写一个wrapper
把过滤器增强,重写里面的getParam
等方法,然后将过滤器加入过滤器链中,从而实现过滤
策略
文件上传策略
通过构建文件上传上下文UploadStrategyContext
来存储全局文件上传参数,UploadStrategy
接口和AbstractUploadStrategyImpl
抽象类,通过继承可实现本地文件上传LocalUploadStrategyImpl
,oss文件上传OssUploadStrategyImpl
等上传策略
登录策略
策略构建方法同上,可以构建qq登录、微博登录、邮箱登录方法
业务逻辑
介绍本篇重要利用的某些语法,主要为java8
新特性、自定义分页、自定义响应包等
Optional
主要用于对null的判断,利用ofNullable
、isPresent
等
Stream
流的操作包含如下三个部分:创建流、中间流、关闭流。筛选、去重、映射、排序属于流的中间操作,收集属于终止操作。Stream是流操作的基础关键类
通过流操作可以更优雅快速的实现对javaBean
的处理
先通过stream生成流,再通过map
、distinct
等处理流,最后收集流
分页
在mybatisplus
自带的page
的基础上构建PageUtil
,构建了一个仅存在于一次request
的page
通过一个过滤器实现对参数内current
、size
的获取,在控制层之前构建出page
,从而实现在参数内无需出现分页参数
通过PageUtil
可以解决返回参数时无法知道total
的问题
最后通过pageResult
封装一下分页bean
即可
注意:page使用前后是一个实体
CompletableFuture
使用CompletableFuture
可以实现异步任务,当前后业务逻辑无关时可以将耗时较长的方法设为异步任务
ResponseAPI
通过自定义响应包,将业务状态码与状态信息、响应体封装在一起
collections4
对于mybatis-plus
的lambdaQuery
或contains
等需要判空的地方可以使用emptyIfNull
、isNotEmpty
等方法,方便编写业务逻辑
定时任务
对于游客用户的地域统计可以采用定时任务的形式,统计数据存入redis即可
上线部署
本篇用的是docker-compose去部署这个博客系统,在application.yml
中将active
字段设置为prod
,然后创建application-prod.yml
配置文件,将上线部署的环境变量配置进去即可,避免将本地配置暴露
把利用到的中间件等配置文件写好,利用docker-compose去构建这些docker容器即可,记得将容器放在一个网络内,而每个容器的ip或域名与其名字是一样的,也就是我们在application-prod.yml
中可以直接使用容器名作为ip
另外,本篇用另一个域名处理管理员对应操作,nginx和vue打包时需要对应两个文件
安全测试
容灾备份
The end
数据表
day_article
文章表
字段名 | 字段类型 | 属性 | 备注 |
---|---|---|---|
id | int | not null | 主键 |
user_id | int | not null | 作者id |
category_id | int | null;default null | 分类id |
article_cover | varchar | null;default null | 文章封面 |
article_content | longtext | not null | 文章内容 |
article_title | varchar | not null | 文章标题 |
type | int | not null;default 0(1原创 2转载 3翻译) | 文章类型 |
original_url | varchar | null;default null | 原文链接 |
is_top | tinyint | not null;default 0(0否 1是) | 是否置顶 |
status | int | not null;default 1(1公开 2私密 3草稿) | 文章状态 |
deleted | tinyint | null;default 0(0否 null是) | 逻辑删除 |
create_time | datetime | not null | 创建时间 |
update_time | datetime | null;default null | 修改时间 |
day_article_tag
文章标签关系表
字段名 | 字段类型 | 属性 | 备注 |
---|---|---|---|
id | int | not null | 主键 |
article_id | int | not null | 文章id |
tag_id | int | not null | 标签id |
deleted | tinyint | null;default 0(0否 null是) | 逻辑删除 |
create_time | datetime | not null | 创建时间 |
update_time | datetime | null;default null | 修改时间 |
day_category
分类表
字段名 | 字段类型 | 属性 | 备注 |
---|---|---|---|
id | int | not null | 主键 |
category_name | varchar | not null | 分类名称 |
deleted | tinyint | null;default 0(0否 null是) | 逻辑删除 |
create_time | datetime | not null | 创建时间 |
update_time | datetime | null;default null | 修改时间 |
day_chat_record
聊天记录表
字段名 | 字段类型 | 属性 | 备注 |
---|---|---|---|
id | int | not null | 主键 |
user_id | int | null;default null | 用户id |
nickname | varchar | not null | 用户昵称 |
avatar | varchar | not null | 用户头像 |
content | varchar | not null | 聊天内容 |
ip_address | varchar | not null | ip地址 |
ip_source | varchar | not null | ip来源 |
type | int | not null | 记录类型 |
deleted | tinyint | null;default 0(0否 null是) | 逻辑删除 |
create_time | datetime | not null | 创建时间 |
update_time | datetime | null;default null | 修改时间 |
day_comment
评论表
除一级评论(顶级评论)外,其他嵌套评论均归为二级评论
parent_id是父评论id
top_id是顶级评论
reply_user_id是当前comment作为回复时,被回复的评论的用户id,属于冗余设计
user_id是当前comment的用户id
affiliation_id是属主的id
type是属主的类型
字段名 | 字段类型 | 属性 | 备注 |
---|---|---|---|
id | int | not null | 主键 |
user_id | int | not null | 用户id |
affiliation_id | int | null;default null | 所属主体id |
type | int | not null;default 0(1文章 2友链 3说说) | 评论类型 |
comment_content | text | not null | 评论内容 |
reply_user_id | int | null;default null | 回复用户id |
parent_id | int | null;default null | 父评论id |
top_id | int | null;default null | 顶级评论id |
is_review | tinyint | not null;default 0(0否 1是) | 是否审核 |
deleted | tinyint | null;default 0(0否 null是) | 逻辑删除 |
create_time | datetime | not null | 创建时间 |
update_time | datetime | null;default null | 修改时间 |
day_friend_link
友链表
字段名 | 字段类型 | 属性 | 备注 |
---|---|---|---|
id | int | not null | 主键 |
link_name | varchar | not null | 链接名称 |
link_avatar | varchar | not null | 链接头像 |
link_address | varchar | not null | 链接地址 |
link_info | varchar | not null | 链接简介 |
deleted | tinyint | null;default 0(0否 null是) | 逻辑删除 |
create_time | datetime | not null | 创建时间 |
update_time | datetime | null;default null | 修改时间 |
day_menu
菜单表
字段名 | 字段类型 | 属性 | 备注 |
---|---|---|---|
id | int | not null | 主键 |
menu_name | varchar | not null | 菜单名称 |
menu_path | varchar | not null | 菜单路径 |
compoent | varchar | not null | 组件 |
icon | varchar | not null | 菜单图标 |
order_num | int | not null | 排序级别 |
parent_id | int | not null | 父菜单id |
is_hidden | tinyint | not null;default 0(0否 1是) | 是否隐藏 |
deleted | tinyint | null;default 0(0否 null是) | 逻辑删除 |
create_time | datetime | not null | 创建时间 |
update_time | datetime | null;default null | 修改时间 |
day_message
留言表
字段名 | 字段类型 | 属性 | 备注 |
---|---|---|---|
id | int | not null | 主键 |
nickname | varchar | not null | 用户昵称 |
avatar | varchar | not null | 用户头像 |
message_content | varchar | not null | 留言内容 |
ip_address | varchar | not null | ip地址 |
ip_source | varchar | not null | ip来源 |
speed | int | null;default null | 弹幕速度 |
is_review | tinyint | not null;default 0(0否 1是) | 是否审核 |
deleted | tinyint | null;default 0(0否 null是) | 逻辑删除 |
create_time | datetime | not null | 创建时间 |
update_time | datetime | null;default null | 修改时间 |
day_operation_log
操作日志表
字段名 | 字段类型 | 属性 | 备注 |
---|---|---|---|
id | int | not null | 主键 |
opt_module | varchar | not null | 操作模块 |
opt_type | varchar | not null | 操作类型 |
opt_url | varchar | not null | 操作url |
opt_method | varchar | not null | 操作方法 |
opt_desc | varchar | not null | 操作描述 |
request_param | longtext | not null | 请求参数 |
request_method | varchar | not null | 请求方式 |
response_data | longtext | not null | 响应数据 |
user_id | int | not null | 用户id |
nickname | varchar | not null | 用户昵称 |
ip_address | varchar | not null | ip地址 |
ip_source | varchar | not null | ip来源 |
deleted | tinyint | null;default 0(0否 null是) | 逻辑删除 |
create_time | datetime | not null | 创建时间 |
update_time | datetime | null;default null | 修改时间 |
day_page
页面表
字段名 | 字段类型 | 属性 | 备注 |
---|---|---|---|
id | int | not null | 主键 |
page_name | varchar | not null | 页面名称 |
page_label | varchar | null;default null | 页面标签 |
page_cover | varchar | not null | 页面封面 |
deleted | tinyint | null;default 0(0否 null是) | 逻辑删除 |
create_time | datetime | not null | 创建时间 |
update_time | datetime | null;default null | 修改时间 |
day_resource
资源表
字段名 | 字段类型 | 属性 | 备注 |
---|---|---|---|
id | int | not null | 主键 |
resource_name | varchar | not null | 资源名称 |
url | varchar | null;default null | 权限路径 |
request_method | varchar | null;default null | 请求方式 |
parent_id | int | null;default null | 父权限id |
is_anonymous | tinyint | not null;default 0(0否 1是) | 是否可以匿名访问 |
deleted | tinyint | null;default 0(0否 null是) | 逻辑删除 |
create_time | datetime | not null | 创建时间 |
update_time | datetime | null;default null | 修改时间 |
day_role
角色表
字段名 | 字段类型 | 属性 | 备注 |
---|---|---|---|
id | int | not null | 主键 |
role_name | varchar | not null | 角色名称 |
role_label | varchar | not null | 角色描述 |
is_disable | tinyint | not null;default 0(0否 1是) | 是否禁用 |
deleted | tinyint | null;default 0(0否 null是) | 逻辑删除 |
create_time | datetime | not null | 创建时间 |
update_time | datetime | null;default null | 修改时间 |
day_role_menu
角色菜单表
字段名 | 字段类型 | 属性 | 备注 |
---|---|---|---|
id | int | not null | 主键 |
role_id | int | null;default null | 角色id |
menu_id | int | null;default null | 菜单id |
deleted | tinyint | null;default 0(0否 null是) | 逻辑删除 |
create_time | datetime | not null | 创建时间 |
update_time | datetime | null;default null | 修改时间 |
day_role_resource
角色资源表
字段名 | 字段类型 | 属性 | 备注 |
---|---|---|---|
id | int | not null | 主键 |
role_id | int | null;default null | 角色id |
resource_id | int | null;default null | 资源id |
deleted | tinyint | null;default 0(0否 null是) | 逻辑删除 |
create_time | datetime | not null | 创建时间 |
update_time | datetime | null;default null | 修改时间 |
day_tag
标签表
字段名 | 字段类型 | 属性 | 备注 |
---|---|---|---|
id | int | not null | 主键 |
tag_name | varchar | not null | 标签名称 |
deleted | tinyint | null;default 0(0否 null是) | 逻辑删除 |
create_time | datetime | not null | 创建时间 |
update_time | datetime | null;default null | 修改时间 |
day_talk
说说表
字段名 | 字段类型 | 属性 | 备注 |
---|---|---|---|
id | int | not null | 主键 |
user_id | int | not null | 用户id |
content | varchar | not null | 说说内容 |
image | varchar | null;default null | 图片 |
is_top | tinyint | not null;default 0(0否 1是) | 是否置顶 |
status | tinyint | not null;default 1(0公开 1私密) | 说说状态 |
deleted | tinyint | null;default 0(0否 null是) | 逻辑删除 |
create_time | datetime | not null | 创建时间 |
update_time | datetime | null;default null | 修改时间 |
day_view
访问量表
字段名 | 字段类型 | 属性 | 备注 |
---|---|---|---|
id | int | not null | 主键 |
view_count | int | not null | 访问量 |
deleted | tinyint | null;default 0(0否 null是) | 逻辑删除 |
create_time | datetime | not null | 创建时间 |
update_time | datetime | null;default null | 修改时间 |
day_user_auth
用户权限表
字段名 | 字段类型 | 属性 | 备注 |
---|---|---|---|
id | int | not null | 主键 |
user_info_id | int | not null | 用户信息id |
username | varchar | not null | 用户名 |
password | varchar | not null | 密码 |
login_type | int | not null | 登录类型 |
ip_address | varchar | null;default null | ip地址 |
ip_source | varchar | null;default null | ip来源 |
is_disabled | tinyint | not null;default 0(0否 1是) | 是否禁用 |
last_login_time | datetime | null;default null | 上次登录时间 |
deleted | tinyint | null;default 0(0否 null是) | 逻辑删除 |
create_time | datetime | not null | 创建时间 |
update_time | datetime | null;default null | 修改时间 |
day_user_info
用户信息表
字段名 | 字段类型 | 属性 | 备注 |
---|---|---|---|
id | int | not null | 主键id |
varchar | null;default null | 邮箱 | |
nickname | varchar | not null | 用户昵称 |
avatar | varchar | not null;default ‘’ | 用户头像 |
intro | varchar | null;default null | 用户介绍 |
website | varchar | null;default null | 个人网站 |
deleted | tinyint | null;default 0(0否 null是) | 逻辑删除 |
create_time | datetime | not null | 创建时间 |
update_time | datetime | null;default null | 修改时间 |
day_user_role
用户角色表
字段名 | 字段类型 | 属性 | 备注 |
---|---|---|---|
id | int | not null | 主键 |
user_id | int | null;default null | 用户id |
role_id | int | null;default null | 角色id |
deleted | tinyint | null;default 0(0否 null是) | 逻辑删除 |
create_time | datetime | not null | 创建时间 |
update_time | datetime | null;default null | 修改时间 |
day_website_config
网站配置表
字段名 | 字段类型 | 属性 | 备注 |
---|---|---|---|
id | int | not null | 主键 |
name | varchar | not null | 网站名称 |
intro | varchar | null;default null | 网站简介 |
author | varchar | null;default null | 网站作者 |
url | varchar | null;default null | 网站地址 |
notice | varchar | null;default null | 网站通知 |
about | varchar | null;default null | 关于我 |
github | varchar | null;default null | github |
varchar | null;default null | qq号 | |
beian_id | varchar | null;default null | 备案号 |
author_avatar | varchar | null;default ‘’ | 作者头像 |
user_avatar | varchar | null;default‘’ | 游客头像 |
deleted | tinyint | null;default 0(0否 null是) | 逻辑删除 |
create_time | datetime | not null | 创建时间 |
update_time | datetime | null;default null | 修改时间 |
业务状态码
2xx:
http状态码 | 错误范围 | 细粒度错误 | 业务状态码 | 错误原因 | 错误名称 |
---|---|---|---|---|---|
200 | 00 | 00 | 200000 | null | OK |
4xx(client):
http状态码 | 错误范围 | 细粒度错误 | 业务状态码 | 错误原因 | 错误名称 |
---|---|---|---|---|---|
400 | 01 | 01 | 4000101 | 参数缺失 | ACCESS_PARAM_MISSING |
400 | 01 | 02 | 4000102 | 参数类型错误 | ACCESS_PARAM_TYPE_ERROR |
400 | 01 | 03 | 4000103 | 参数校验错误 | ACCESS_PARAM_NOT_VALID |
400 | 02 | 01 | 4000201 | 文件为空 | FILE_EMPTY |
400 | 02 | 02 | 4000202 | 文件类型错误 | FILE_TYPE_ERROR |
400 | 03 | 01 | 4000301 | 尚未登录 | AUTH_NO_LOGIN |
400 | 03 | 02 | 4000302 | 缺少权限 | AUTH_PERMISSION_DENIED |
400 | 03 | 03 | 4000303 | 认证失败 | AUTH_UorP_ERROR |
400 | 03 | 04 | 4000304 | 用户名为空 | AUTH_USERNAME_EMPTY |
400 | 03 | 05 | 4000305 | 账号不存在 | AUTH_USER_NOT_FOUND |
400 | 03 | 06 | 4000306 | 认证失败 | AUTH_FAILED |
400 | 03 | 07 | 4000307 | 校验码错误 | AUTH_CODE_ERROR |
400 | 03 | 08 | 4000308 | 校验码为空 | AUTH_CODE_MISSING |
400 | 03 | 09 | 4000309 | session过期 | AUTH_SESSION_TIMEOUT |
400 | 03 | 10 | 4000310 | 访问登录接口方法错误 | AUTH_METHOD_NOT_AVAILABLE |
400 | 03 | 11 | 4000311 | 账号已在别处登录 | AUTH_SESSION_CONCURRENCY_MAX |
400 | 03 | 12 | 4000312 | 用户账号已锁定 | AUTH_USER_ACCOUNT_LOCKED |
400 | 03 | 13 | 4000313 | 用户账号不可用 | AUTH_USER_ACCOUNT_DISABLED |
400 | 03 | 14 | 4000314 | 用户账号已过期 | AUTH_USER_ACCOUNT_EXPIRED |
400 | 03 | 15 | 4000315 | 用户账号密码过期 | AUTH_USER_CREDENTIALS_EXPIRED |
400 | 03 | 16 | 4000316 | 用户名已存在 | AUTH_USER_USERNAME_REPEAT |
400 | 03 | 17 | 4000317 | 密码错误 | AUTH_PASSWORD_ERROR |
400 | 03 | 18 | 4000318 | qq登录失败 | AUTH_QQ_ERROR |
400 | 04 | 01 | 4000401 | 接口访问频繁 | API_ACCESS_FREQUENT |
400 | 04 | 02 | 4000402 | 重复提交 | API_REPEAT_SUBMIT |
400 | 04 | 03 | 4000403 | 接口访问方法错误 | API_ACCESS_METHOD_ERROR |
400 | 05 | 01 | 4000501 | 检测到xss或sql注入 | SECURITY_CHECK_XSSorSQL |
400 | 10 | 01 | 4001001 | 文章不存在 | ARTICLE_MISSING |
400 | 11 | 01 | 4001101 | 说说不存在 | TALK_MISSING |
400 | 12 | 01 | 4001201 | 分类已存在 | CATEGORY_NAME_REPEAT |
400 | 12 | 02 | 4001202 | 分类不存在 | CATEGORY_MISSING |
400 | 12 | 03 | 4001203 | 分类下存在文章 | CATEGORY_ARTICLE_RELATION |
400 | 13 | 01 | 4001301 | 标签已存在 | TAG_NAME_REPEAT |
400 | 13 | 02 | 4001302 | 标签不存在 | TAG_MISSING |
400 | 13 | 03 | 4001303 | 标签下存在文章 | TAG_ARTICLE_RELATION |
400 | 14 | 01 | 4001401 | 菜单下存在角色 | MENU_ROLE_RELATION |
400 | 15 | 01 | 4001501 | 资源下存在角色 | RESOURCE_ROLE_RELATION |
400 | 99 | 01 | 4009901 | 未知异常 | UNKNOWN_CLIENT_ERROR |
5xx(server):
http状态码 | 错误范围 | 细粒度错误 | 业务状态码 | 错误原因 | 错误名称 |
---|---|---|---|---|---|
500 | 01 | 01 | 5000101 | 参数封装失败 | PARAM_OPERATION_ERROR |
500 | 02 | 01 | 5000201 | 文件上传失败 | FILE_UPLOAD_ERROR |
500 | 02 | 02 | 5000202 | 文件下载失败 | FILE_DOWNLOAD_ERROR |
500 | 04 | 01 | 5000401 | 数据库异常 | SQL_ERROR |
500 | 04 | 02 | 5000402 | redis连接异常 | REDIS_CONNECTION_ERROR |
500 | 99 | 01 | 5009901 | 运行时未知异常 | UNKNOWN_RUNTIME_ERROR |
500 | 99 | 02 | 5009902 | 系统未知异常 | UNKNOWN_SYSTEM_ERROR |