项目通用
接口管理工具
knife4j
- pom文件
1
2
3
4
5<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>2.0.2</version>
</dependency> - 配置类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42package com.itheima.config;
import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
public class Knife4jConfiguration {
public Docket buildDocket() {
//构建在线API概要对象
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(buildApiInfo())
.select()
// 要扫描的API(Controller)基础包
.apis(RequestHandlerSelectors.basePackage("com.itheima.controller"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo buildApiInfo() {
//网站联系方式
Contact contact = new Contact("GYM","https://www.itheima.com/","1984906301@qq.com");
return new ApiInfoBuilder()
.title("今日指数-在线接口API文档")//文档标题
.description("这是一个方便前后端开发人员快速了解开发接口需求的在线接口API文档")//文档描述信息
.contact(contact)//站点联系人相关信息
.version("1.0.0")//文档版本
.build();
}
} - 在启动类添加@MapperScan(“com.itheima.mapper”)
- 访问地址:http://localhost:8091/doc.html
- 注解的使用
@Api(tags= “01 通用模块”)
@ApiOperation(“根据条件查询数据”)
@ApiModel(“通用查询条件实体”)
@ApiModelProperty(value = “页码”, required = true, example = “1”)
Yapi
Yapi安装流程
docker安装过程参考:https://www.jianshu.com/p/a97d2efb23c5
流程如下:
- 安装mongo数据库:
1
2
3
4
5
6
7
8
9
10
11
12
13拉取mongo镜像,当然一位内部包比较大,直接导入资料包中的镜像资源即可
docker pull mongo
安装mongo数据库服务
创建存储卷
docker volume create mongo-data
启动 MongoDB
docker run -d \
--name mongo-yapi \
-v mongo-data:/data/db \
-p 27017:27017 \
-e MONGO_INITDB_ROOT_USERNAME=anoyi \
-e MONGO_INITDB_ROOT_PASSWORD=anoyi.com \
mongo - 初始化yaml的管理员账号和密码:效果如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24拉取yapi镜像包
docker pull registry.cn-hangzhou.aliyuncs.com/anoyi/yapi
自定义名称为config.json的配置文件
{
"port": "3000",
"adminAccount": "admin@anoyi.com",
"timeout":120000,
"db": {
"servername": "mongo",
"DATABASE": "yapi",
"port": 27017,
"user": "anoyi",
"pass": "anoyi.com",
"authSource": "admin"
}
}
初始化管理员账户和密码
docker run -it --rm \
--link mongo-yapi:mongo \
--entrypoint npm \
--workdir /yapi/vendors \
-v $PWD/config.json:/yapi/config.json \
registry.cn-hangzhou.aliyuncs.com/anoyi/yapi \
run install-server - 最后初始化yaml容器:访问路径:
1
2
3
4
5
6
7
8docker run -d \
--name yapi \
--link mongo-yapi:mongo \
--workdir /yapi/vendors \
-p 3000:3000 \
-v $PWD/config.json:/yapi/config.json \
registry.cn-hangzhou.aliyuncs.com/anoyi/yapi \
server/app.js1
2
3访问: http://192.168.200.130:3000
登录账号:admin@anoyi.com
密码:ymfe.org注意:
**重启yapi服务时,需要同时启动mongo服务,可通过 docker start mongo-yapi yapi 启动
Yapi基本使用
登录到Yapi平台之后,我们可以创建项目,在项目下创建接口分类,在对应的分类中添加接口。
- 创建项目
- 添加分类
在当前项目中,有针对用户、股票、日志、权限等相关的操作,我们在进行接口维护时,可以针对接口进行分类,如果没有对应的分类,我们自己添加分类;
接口基本信息录入之后,点击提交按钮,就可以看到该接口的基本信息: - 运行接口
自动同步swagger
实体类设计
- 实体类中的公共字段(例如
id
、create_time
、update_time
、is_deleted
)抽取到一个基类,进行统一管理,然后让各实体类继承该基类。 - 实体类中的状态字段(例如
status
)或类型字段(例如type
),全部使用枚举类型。例如:订单状态(1:待支付,2:待发货,3:待收货,4:已收货,5:已完结)。
定义枚举1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18public enum Status {
CANCEL(0, "已取消"),
WAIT_PAY(1, "待支付"),
WAIT_TRANSFER(2, "待发货"),
WAIT_RECEIPT(3, "待收货"),
RECEIVE(4, "已收货"),
COMPLETE(5, "已完结");
private final Integer value;
private final String desc;
public Integer value() {
return value;
}
public String desc() {
return desc;
}
}定义实体类
1
2
3
4
5
public class Order{
private Status status;
...
}调用
1
order.setStatus(Status.WAIT_PAY);
配置类实体类
- yaml文件
1
2
3
4
5minio:
endpoint: http://<hostname>:<port>
access-key: <access-key>
secret-key: <secret-key>
bucket-name: <bucket-name> - 实体类
1
2
3
4
5
6
7
8
9
10
11
12
public class MinioProperties {
private String endpoint;
private String accessKey;
private String secretKey;
private String bucketName;
} - 使用 —-@AUtowired注入
mybatis-plus
入门
- 导入依赖
1
2
3
4
5<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency> - application.yml
1
2
3
4
5
6
7
8
9
10
11server:
port: 8800
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 查看日志
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/guigu-auth?characterEncoding=utf-8&useSSL=false
username: root
password: root - 启动类
1
2
3
4
5
6
7
8
9
public class ServiceAuthApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceAuthApplication.class, args);
}
} - 实体类
@TableName:表名注解,标识实体类对应的表
@TableId:主键注解,type = IdType.AUTO(数据库 ID 自增)
@TableField:字段注解(非主键)
@TableLogic:逻辑删除1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class SysRole {
private static final long serialVersionUID = 1L;
//角色id
private Long id;
//角色名称
private String roleName;
//逻辑删除
private Integer isDeleted;
} 添加mapper
1
2
3
public interface SysRoleMapper extends BaseMapper<SysRole> {
}添加service
1
2
3
4
5public interface SysRoleService();
public class SysRoleServiceImpl exantend IService<SysRoleMapper,SysRole> implements SysRoleService(){
}
逻辑删除
- application.yml
1
2
3
4
5
6mybatis-plus:
global-config:
db-config:
logic-delete-field: flag # 全局逻辑删除的实体字段名(配置后可以忽略不配置步骤二)
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0) - 在实体类中的删除标识字段上增加@TableLogic注解
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class BaseEntity {
private Long id;
private Date createTime;
private Date updateTime;
private Byte isDeleted;
}逻辑删除功能只对Mybatis-Plus自动注入的sql起效,也就是说,对于手动在Mapper.xml文件配置的sql不会生效,需要单独考虑。
忽略特定字段
通常情况下接口响应的Json对象中并不需要create_time、update_time、is_deleted等字段,这时只需在实体类中的相应字段添加@JsonIgnore注解,该字段就会在序列化时被忽略。
1 |
|
字段自动填充
保存或更新数据时,前端通常不会传入
isDeleted
、createTime
、updateTime
这三个字段,因此我们需要手动赋值。但是数据库中几乎每张表都有上述字段,所以手动去赋值就显得有些繁琐。为简化上述操作,我们可采取以下措施。
is_deleted
字段:可将数据库中该字段的默认值设置为0。create_time
和update_time
:可使用mybatis-plus的自动填充功能,所谓自动填充,就是通过统一配置,在插入或更新数据时,自动为某些字段赋值
实体类 —-注意fill属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class BaseEntity {
private Date createTime;
private Date updateTime;
private Byte isDeleted;
}MybatisMetaObjectHandler
1
2
3
4
5
6
7
8
9
10
11
12
public class MybatisMetaObjectHandler implements MetaObjectHandler {
public void insertFill(MetaObject metaObject) {
this.strictInsertFill(metaObject, "createTime", Date.class, new Date());
}
public void updateFill(MetaObject metaObject) {
this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
}
}在做完上述配置后,当写入数据时,Mybatis-Plus会自动将实体对象的
create_time
字段填充为当前时间,当更新数据时,则会自动将实体对象的update_time
字段填充为当前时间。
业务类
三级菜单 —-自关联表
在实体类添加属性List<自身> children; 使用Stream流递归实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public List<CategoryEntity> listWithTree() {
//1.查出所有分类
List<CategoryEntity> entities = baseMapper.selectList(null);
//2.组装成父子的树型结构
List<CategoryEntity> level1Menus = entities.stream().filter(categoryEntity -> {
return categoryEntity.getParentCid() == 0;
}).map((menu)->{
menu.setChildren(getChildrens(menu,entities));
return menu;
}).sorted((menu1,menu2)->{
return menu1.getSort() - menu2.getSort();
}).collect(Collectors.toList());
return level1Menus;
}
//递归查找所有菜单的子菜单
private List<CategoryEntity> getChildrens(CategoryEntity root, List<CategoryEntity> all){
List<CategoryEntity> children = all.stream().filter(categoryEntity -> {
return categoryEntity.getParentCid() == root.getCatId();
}).map((categoryEntity)->{
//1.找到子菜单
categoryEntity.setChildren(getChildrens(categoryEntity,all));
return categoryEntity;
}).sorted((menu1,menu2)->{
//2.菜单的排序
return (menu1.getSort()==null?0:menu1.getSort()) - (menu2.getSort()==null?0:menu2.getSort());
}).collect(Collectors.toList());
return children;
} 直接递归实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public List<SysMenu> findMenuNodes() {
//1. 查询所有的菜单
List<SysMenu> sysMenusAllList = sysMenuMapper.selectList(null);
//2. 组装成树(倒着的树)
List<SysMenu> treeList=MenuHelper.buildTreeList(sysMenusAllList);
return treeList;
}
public class MenuHelper {
public static List<SysMenu> buildTreeList(List<SysMenu> sysMenusAllList) {
//树形集合
List<SysMenu> treeList=new ArrayList<>();
for (SysMenu sysMenu : sysMenusAllList) {
//先找根节点
if(sysMenu.getParentId()==0){
treeList.add(findChildNode(sysMenu,sysMenusAllList));
}
}
return treeList;
}
//查找子节点
private static SysMenu findChildNode(SysMenu sysMenu, List<SysMenu> sysMenusAllList) {
sysMenu.setChildren(new ArrayList<>());
for (SysMenu childNode : sysMenusAllList) {
if(childNode.getParentId()==sysMenu.getId()){
//把子节点保存
if(sysMenu.getChildren()==null){
sysMenu.setChildren(new ArrayList<>());
}
sysMenu.getChildren().add(findChildNode(childNode,sysMenusAllList));
}
}
return sysMenu;
}
}
日志类
- 导入依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24<!-- Spring Boot 集成 log4j2 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
如果上面出现错误--使用下面的
<!-- 排除 Spring Boot 依赖的日志包冲突 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Spring Boot 集成 log4j2 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency> - 创建log4j2-dev.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
<Configuration monitorInterval="180" packages="">
<properties>
<property name="logdir">logs</property>
<property name="PATTERN">%date{YYYY-MM-dd HH:mm:ss,SSS} %level [%thread][%file:%line] - %msg%n%throwable</property>
</properties>
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="${PATTERN}"/>
</Console>
<RollingFile name="ErrorAppender" fileName="${logdir}/error.log"
filePattern="${logdir}/$${date:yyyy-MM-dd}/error.%d{yyyy-MM-dd-HH}.log" append="true">
<PatternLayout pattern="${PATTERN}"/>
<ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1" modulate="true" />
</Policies>
</RollingFile>
<RollingFile name="DebugAppender" fileName="${logdir}/info.log"
filePattern="${logdir}/$${date:yyyy-MM-dd}/info.%d{yyyy-MM-dd-HH}.log" append="true">
<PatternLayout pattern="${PATTERN}"/>
<ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1" modulate="true" />
</Policies>
</RollingFile>
<!--异步appender-->
<Async name="AsyncAppender" includeLocation="true">
<AppenderRef ref="ErrorAppender"/>
<AppenderRef ref="DebugAppender"/>
</Async>
</Appenders>
<Loggers>
<!--过滤掉spring和mybatis的一些无用的debug信息
<logger name="org.springframework" level="INFO">
</logger>
<logger name="org.mybatis" level="INFO">
</logger>-->
<logger name="cn.itcast.wanxinp2p.consumer.mapper" level="DEBUG">
</logger>
<logger name="springfox" level="INFO">
</logger>
<logger name="org.apache.http" level="INFO">
</logger>
<logger name="com.netflix.discovery" level="INFO">
</logger>
<logger name="RocketmqCommon" level="INFO" >
</logger>
<logger name="RocketmqRemoting" level="INFO" >
</logger>
<logger name="RocketmqClient" level="WARN">
</logger>
<logger name="org.dromara.hmily" level="WARN">
</logger>
<logger name="org.dromara.hmily.lottery" level="WARN">
</logger>
<logger name="org.dromara.hmily.bonuspoint" level="WARN">
</logger>
<!--OFF 0-->
<!--FATAL 100-->
<!--ERROR 200-->
<!--WARN 300-->
<!--INFO 400-->
<!--DEBUG 500-->
<!--TRACE 600-->
<!--ALL Integer.MAX_VALUE-->
<Root level="DEBUG" includeLocation="true">
<AppenderRef ref="AsyncAppender"/>
<AppenderRef ref="Console"/>
<AppenderRef ref="DebugAppender"/>
</Root>
</Loggers>
</Configuration> - yaml配置
1
2
3# 日志文件配置路径
logging:
config: classpath:log4j2-dev.xml
常用的方法
对象复制
BeanUtils.copyProperties(被复制的对象,复制的对象)
hutool万能工具包
导入依赖1
2
3
4
5<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.21</version>
</dependency>
生成图片验证码
1 | //1.生成图片验证码 |