前言
在这篇文章介绍并记录关于Springboot+Mybatis后端集成Layui后台管理,实现前后端分离模式开发。
主要实现增加、删除、查询、修改、分页、批量删除等功能。一看就明白
不说别的,就直接贴上代码实现Demo例子。
1. 后台管理新增页面代码---add.html
注: 页面只贴跟后端代码实现的相关代码有关,主要参考使用ajax方法向后端传递参数,实现前后端分离开发模式。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<!-- 公共样式 开始 -->
<!--注意:可引入在线jquery和layui 或者本地下载引用-->
<script type="text/javascript" src="../../framework/jquery-2.1.4.min.js"></script>
<link rel="stylesheet" type="text/css" href="../../layui/css/layui.css">
<script type="text/javascript" src="../../layui/layui.js"></script>
<!-- 公共样式 结束 -->
<style>
.layui-form{
margin-right: 30%;
}
</style>
</head>
<body>
<div class="cBody" id="app">
<form id="addForm" class="layui-form" >
<div class="layui-form-item">
<label class="layui-form-label">服务名称</label>
<div class="layui-input-inline shortInput">
<input type="text" name="itemName" required lay-verify="required" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">描述</label>
<div class="layui-input-block">
<textarea name="itemDesc" placeholder="请输入内容" class="layui-textarea">
</textarea>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">状态</label>
<div class="layui-input-block">
<input type="radio" name="itemStatus" value="0" title="启用" checked>
<input type="radio" name="itemStatus" value="1" title="禁用">
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn" lay-submit lay-filter="submitBut">立即提交</button>
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
</div>
</div>
</form>
</div>
<script type="text/javascript">
layui.use('form', function() {
var form = layui.form;
//监听提交,从后端服务器传递参数实现增加功能
form.on('submit(submitBut)', function(data) {
// layer.msg(JSON.stringify(data.field.itemName));
$.ajax({
url:'http://localhost:8009/hc/aItem/addAItem',
data:{
'itemName': data.field.itemName,
'itemDesc': data.field.itemDesc,
'itemStatus': data.field.itemStatus
},
type:'post',
cache:'false',
dataType:'json',
success:function(result){
// console.log(result);
if(result.code == 0){
layer.msg("添加成功",{
shift:1,
time:500,
},function(){
location.reload();
});
}
},
error:function(result){
layer.msg(result.message);
}
});
return false;
});
});
</script>
</body>
</html>
2.2 后台管理列表页面代码--list.html
注意:列表页面实现的功能主要有查询、表格分页、修改、删除、批量删除。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<!-- 公共样式 开始 -->
<!--注意:可引入在线jquery和layui 或者本地下载引用-->
<script type="text/javascript" src="../../framework/jquery-2.1.4.min.js"></script>
<link rel="stylesheet" type="text/css" href="../../layui/css/layui.css">
<script type="text/javascript" src="../../layui/layui.js"></script>
<!-- 公共样式 结束 -->
</head>
<body>
<div class="layui-row" id="EditUser" style="display:none;">
<div class="layui-col-md10">
<form id="addForm" class="layui-form" action="">
<div class="layui-form-item">
<label class="layui-form-label">编号ID</label>
<div class="layui-input-block">
<input type="text" readonly="readonly" id="itemId" name="itemId" autocomplete="off" class="layui-input" />
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">服务名称</label>
<div class="layui-input-block">
<input type="text" id="itemName" name="itemName" required lay-verify="required" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">描述</label>
<div class="layui-input-block">
<textarea id="itemDesc" name="itemDesc" class="layui-textarea"></textarea>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">状态</label>
<div class="layui-input-block">
<input type="radio" id="startStatus" name="itemStatus" value="0" title="启用" >
<input type="radio" id="displayStatus" name="itemStatus" value="1" title="禁用" >
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn" lay-submit lay-filter="submitUpdate">立即提交</button>
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
</div>
</div>
</form>
</div>
</div>
<div class="cBody">
<div class="console">
<form class="layui-form" action="">
<div class="layui-form-item">
<div class="layui-input-inline">
<input type="text" id="keywords" name="itemName" required lay-verify="required" placeholder="输入服务名称" autocomplete="off" class="layui-input">
</div>
<button class="layui-btn" data-type="reload" lay-submit lay-filter="formDemo">检索</button>
</div>
</form>
<script>
</script>
</div>
<table class="layui-hide" id="tableContent" lay-filter="test">
</table>
<script type="text/html" id="toolbarDemo">
<div class="layui-btn-container">
<button class="layui-btn layui-btn-sm layui-btn-danger" lay-submit data-type="getCheckData" lay-filter="batchDel">批量删除</button>
</div>
</script>
<script type="text/html" id="barDemo">
<a class="layui-btn layui-btn-xs" lay-event="edit">编辑</a>
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
</script>
<script>
layui.use([ 'layer','table','form'], function() {
var layer = layui.layer;
var table = layui.table;
var form = layui.form;
//监听提交,实现查询功能
form.on('submit(formDemo)', function(data) {
layer.msg(JSON.stringify(data.field));
// load(data.field);
// if(data.field != null){
// load(data);
// }
var queryPo = data.field;
console.log("queryPo",queryPo.itemName);
var table = layui.table;
table.reload('testReload',{
url: 'http://localhost:8009/hc/aItem/pagesAItems',
page:{
curr: 1 //从第一页开始
},
where:{
itemName: queryPo.itemName
},
parseData:function(res){
console.log("进来...",res)
return{
"code":res.code,
"data":res.data.list,
"count":res.data.total
}
}
});
return false;
});
//执行一个table 示例,实现table表格分页
tableIns = table.render({
elem:'#tableContent',
height: 500,
url:'http://localhost:8009/hc/aItem/pagesAItems',//数据接口
parseData:function(res){
console.log("进来...",res)
return{
"code":res.code,
"data":res.data.list,
"count":res.data.total
}
},
toolbar:'#toolbarDemo',
id:'testReload',
title:'服务列表',
page: true,//开启分页
limits:[10],
limit:10,
cols:[[
{type: 'checkbox',checkbox:true,fixed: 'left'},
{field:'itemId',title:'编号ID',width:200,sort: true},
{field:'itemName',title:'服务名称',width:150,sort: true},
{field:'itemDesc',title:'描述',width:200},
{field:'itemStatus',title:'状态',width:80},
{field:'createTime',title:'创建时间',width:200},
{field:'updateTime',title:'修改时间',width:200},
{title:'操作',width:165,align:'center',toolbar: '#barDemo'}
]]
});
//监听行工具事件 实现删除和编辑功能
table.on('tool(test)', function(obj){ //注:tool 是工具条事件名,test 是 table 原始容器的属性 lay-filter="对应的值"
var id = obj.data.itemId; //获得当前行数据
layEvent = obj.event; //获得 lay-event 对应的值
if(layEvent === 'del'){
layer.confirm('真的删除行么', function(index){
obj.del();
$.ajax({
type:"DELETE",
url:"http://localhost:8009/hc/aItem/deletetAItem/"+id,
contentType:"application/json",
dataType:"json",
success:function(res){
console.log("删除结果"+res.data);
if(res.data == 1){
layer.close(index);
layer.msg("删除成功",{icon: 1, time: 1000, shade: 0.1});
table.reload('testReload',{
page:{
curr:1
}
})
}
}
})
});
} else if(layEvent === 'edit'){
// layer.msg('编辑操作');
layui.use('layer', function() {
var layer = layui.layer;
console.log("编辑栏"+id);
var data = obj.data;
$("#itemId").val(data.itemId);
$("#itemName").val(data.itemName);
$("#itemDesc").val(data.itemDesc);
var status = data.itemStatus;
// 判断启用和禁用状态
$('[name=itemStatus]').each(function(i,item){
console.log("i="+i+"item"+item)
if($(item).val()== status ){
$(item).prop('checked',true);
console.log($(item));
form.render();
}
});
console.log("编辑:"+data.itemId);
//iframe层-父子操作
updateFrame = layer.open({
title: "服务信息修改",
type: 1,
area: ['520px', '540px'],
scrollbar: false, //默认:true,默认允许浏览器滚动,如果设定scrollbar: false,则屏蔽
maxmin: true,
content: $("#EditUser")
});
});
}
});
//修改
form.on('submit(submitUpdate)', function(data) {
// layer.msg(JSON.stringify(data.field));
$.ajax({
type:"POST",
url:"http://localhost:8009/hc/aItem/updateAItem/",
contentType:"application/json",
data:JSON.stringify(data.field),
dataType:"json",
success:function(res){
console.log("更新结果"+res.data);
if(res.data == 1){
layer.msg("更新",{icon: 1, time: 2000, shade: 0.1});
setTimeout(function(){
layer.closeAll();//关闭所有的弹出层
table.reload('testReload',{
page:{
curr:1
}
});
}, 800);
}
}
});
return false;
});
// 批量删除
// 1.获取选中数据
function getCheckData() {
var checkStatus = table.checkStatus('testReload')
var data = checkStatus.data;
// layer.msg(JSON.stringify(data));
console.log("批量删除:"+JSON.stringify(data));
// console.log(JSON.stringify(data[0].itemId));
var itemIds = "";
if(data.length >0){
for(var i in data){
itemIds+=data[i].itemId+",";
}
}
return itemIds
}
// 2. 提交批量删除
form.on('submit(batchDel)',function(data){
var itemIds = getCheckData();
if(itemIds.length == 0){
layer.msg("请先选择批量删除的内容", {
time: 2000,
icon: 5
});
return;
}
// 3. 是否要删除所有内容
layer.confirm('确认删除所有选中的内容吗?',function(index){
console.log("得到批量数据ID"+JSON.stringify(itemIds));
$.ajax({
type:"POST",
url:"http://localhost:8009/hc/aItem/batchDelAItem/"+itemIds,
contentType:"application/json",
// data:JSON.stringify(itemIds),
dataType:"json",
success:function(res){
console.log("批量删除结果"+res.data);
layer.close(index);
layer.msg("批量删除成功",{icon: 1, time: 1000, shade: 0.1});
table.reload('testReload',{
page:{
curr:1
}
})
}
});
})
});
});
</script>
</div>
</body>
</html>
3. 后端Springboot+Mybatis代码实现功能
注意:后端使用Springboot+Mybatis,使用了通用mapper以及pagehelper插件。
3.1 使用maven项目构建,先贴上pom.xml依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!--通用mapper-->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>2.0.2</version>
</dependency>
<!--MySQL依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- 分页插件 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.5</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- apache 提供的一些工具类 -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.9</version>
</dependency>
<!-- 集合类操作 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.0</version>
</dependency>
</dependencies>
3.2 Springboot yml配置文件
server:
servlet:
context-path: /自己的路径
port: 自己的端口
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
username: root
password: 自己密码
url: jdbc:mysql://自己的地址/数据库名字?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
mybatis:
mapper-locations: classpath:mapper/*Mapper.xml
type-aliases-package: com.mi.entity
pagehelper:
helper-dialect: mysql
reasonable: true
support-methods-arguments: true
params: count==countSql
page-size-zero: true
logging:
level:
com.mi.mapper: trace
3.3 贴上工具类
3.3.1 keyUtil 生成唯一主键
public class keyUtil {
/**
* 生成唯一的主键
* 格式:时间+随机数
* @return
*/
public static synchronized String genUniqueKey(){
Random random = new Random();
Integer number = random.nextInt(900000)+100000;
return System.currentTimeMillis() + String.valueOf(number);
}
}
3.3.2 TimeUtil 转化时间工具类
public class TimeUtil {
public static Date getNowDate(Date currentTime) {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = formatter.format(currentTime);
ParsePosition pos = new ParsePosition(0);
Date currentTime_2 = formatter.parse(dateString, pos);
return currentTime_2;
}
}
3.3.3 统一返回数据封装类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CommonResponse<T> implements Serializable {
private Integer code;
private String message;
private T data;
public CommonResponse(Integer code, String message) {
this.code = code;
this.message = message;
}
}
3.3.4 统一返回数据封装工具类
public class ResponseVoUtil {
public static CommonResponse success(Object object) {
CommonResponse response = new CommonResponse();
response.setData(object);
response.setCode(0);
response.setMessage("成功");
return response;
}
public static CommonResponse success(){
return success(null);
}
public static CommonResponse error(Integer code,String msg){
CommonResponse response = new CommonResponse();
response.setCode(code);
response.setMessage(msg);
return response;
}
}
3.3.5 跨域配置
注意:要是前后端分离跨域不成功,需要配置这个方可配置
@Configuration
public class CorsFilter implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry corsRegistry){
corsRegistry.addMapping("/**")
.allowedHeaders("*")
.allowedMethods("*")
.maxAge(1800)
.allowedOrigins("*");
}
}
3.3.6 Springboot 启动类
@SpringBootApplication
@MapperScan("com.mi.mapper") //自己需要扫描的mapper包名
public class WebApplication {
public static void main(String args[]){
SpringApplication.run(WebApplication.class,args);
}
}
3.4 后端其它需要的类
3.4.1 实体类
注意:该实体类可以自己定义,此处只为了参考
@Data
@Table(name = "appoint_item") //填写自己数据库的表名,最好用下划线声明表,例如appoint_item举例
public class AppointItem implements Serializable {
/**服务id**/
@Id
@KeySql(useGeneratedKeys = true) //回显
private String itemId;
/**服务名称**/
private String itemName;
/**服务状态 0 正常 1 关闭**/
private Integer itemStatus;
/**服务描述**/
private String itemDesc;
/**创建时间**/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date createTime;
/**修改时间**/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date updateTime;
}
3.4.2 实体类form表单
注意:该类是会接受页面传递的值,然后使用转换属性的工具转到具体的对应数据库的实体类,下面会具体实现。
@Data
public class AppointItemForm {
private String itemId;
/**服务名称**/
private String itemName;
/**服务状态 0 正常 1 关闭**/
private Integer itemStatus;
/**服务描述**/
private String itemDesc;
/**创建时间**/
private Timestamp createTime;
/**修改时间**/
private Timestamp updateTime;
}
3.4.3 对应Dao层的mapper接口
注意:通过使用通用mapper插件,继续该mapper,就会有增删查改方法。
public interface AItemMapper extends Mapper<AppointItem> {
/**
* 批量删除
* @param itemIds
* @return
*/
public int batchDelAItem(List<String> itemIds);
}
3.4.4 业务接口类
public interface AItemService {
public void addAItem(AppointItem item);
public AppointItem seleceByOne(String appointId);
public int delectByOne(String appointId);
public int updateItem(AppointItem item);
/**
* 分页
* @param offset
* @param pageSize
* @return
*/
public PageInfo<AppointItem> selectByPages(Integer offset, Integer pageSize,String keywords);
/**
* 批量删除
* @param itemIds
* @return
*/
public int batchDelAItem(List<String> itemIds);
}
3.4.4 业务接口实现类
@Service
@Slf4j
public class AItemServiceImpl implements AItemService {
@Autowired
private AItemMapper aItemMapper;
/**
* 新增
* @param item
*/
@Override
public void addAItem(AppointItem item) {
aItemMapper.insertSelective(item);
}
/**
* 查询一个Item
* @param appointId
* @return
*/
@Override
public AppointItem seleceByOne(String appointId) {
return aItemMapper.selectByPrimaryKey(appointId);
}
/**
* 删除一个Item
* @param appointId
*/
@Override
public int delectByOne(String appointId) {
return aItemMapper.deleteByPrimaryKey(appointId);
}
/**
* 更新
* @param item
* @return
*/
@Override
public int updateItem(AppointItem item) {
return aItemMapper.updateByPrimaryKeySelective(item);
}
/**
* 分页
* @param offset
* @param pageSize
* @param itemName
* @return
*/
@Override
public PageInfo<AppointItem> selectByPages(Integer offset, Integer pageSize,String itemName) {
PageHelper.startPage(offset,pageSize);
Example example = new Example(AppointItem.class);
Example.Criteria criteria = example.createCriteria();
// 1. 查询keywords 关键字
if (!StringUtils.isEmpty(itemName) && itemName.length() > 0) {
log.info("itemName = {}",itemName);
criteria.andLike("itemName","%"+itemName+"%");
}
List<AppointItem> itemPages = aItemMapper.selectByExample(example);
PageInfo<AppointItem> pageInfo = new PageInfo<>(itemPages);
return pageInfo;
}
/**
* 批量删除
* @param itemIds
* @return
*/
@Override
public int batchDelAItem(List<String> itemIds) {
int isBatch = aItemMapper.batchDelAItem(itemIds);
return isBatch;
}
}
3.4.5 mapper.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.mi.mapper.AItemMapper">
<resultMap id="BaseResultMap" type="com.mi.entity.AppointItem">
<result column="item_id" jdbcType="VARCHAR" property="itemId"></result>
<result column="item_name" jdbcType="VARCHAR" property="itemName"></result>
<result column="item_status" jdbcType="INTEGER" property="itemStatus"></result>
<result column="item_desc" jdbcType="VARCHAR" property="itemDesc"></result>
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"></result>
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime"></result>
</resultMap>
<sql id="Base_Column_List">
item_id,item_name,item_status,item_desc,create_time,update_time
</sql>
<!--批量删除-->
<delete id="batchDelAItem" parameterType="list" >
DELETE FROM appoint_item WHERE item_id IN
<foreach collection="list" item="item" open="(" separator="," close=")" index="index">
#{item}
</foreach>
</delete>
</mapper>
3.5 控制器实现类-controller
注意:该controller就是后台管理页面通过ajax调用controller的api接口实现前后端分离模式开发。
RestController
@Slf4j
@RequestMapping("/aItem")
public class StoreAItemController {
@Autowired
private AItemService aItemService;
/**
* 新增
* @param itemForm
* @return
*/
@PostMapping(value = "/addAItem")
public CommonResponse addAItem(AppointItemForm itemForm){
log.info("【使用addAItem方法】");
//1. 创建服务实体类
AppointItem item = new AppointItem();
//2. 判断服务名称是否为空
if (!StringUtils.isEmpty(itemForm.getItemName())){
itemForm.setItemId(keyUtil.genUniqueKey());
BeanUtils.copyProperties(itemForm,item);
item.setCreateTime(TimeUtil.getNowDate(new java.util.Date()));
aItemService.addAItem(item);
}
return ResponseVoUtil.success();
}
/**
* 查询一个Item
* @param appointId
* @return
*/
@GetMapping(value = "/selectAItem/{id}")
public CommonResponse selectAItem(@PathVariable("id")String appointId){
log.info("【使用selectAItem 方法】 = {}",appointId);
// 1.判断appointid是否为空
if (!StringUtils.isEmpty(appointId)){
AppointItem item = aItemService.seleceByOne(appointId);
return ResponseVoUtil.success(item);
}
// 2. 为空就返回null
return null;
}
/**
* 删除一个Item
* @param appointId
* @return
*/
@DeleteMapping(value = "/deletetAItem/{id}")
public CommonResponse deletetAItem(@PathVariable("id")String appointId){
log.info("【使用delectAItem】 = {}",appointId);
int isDelete = aItemService.delectByOne(appointId);
return ResponseVoUtil.success(isDelete);
}
/**
* 分页
* @param offset
* @param size
* @param itemName
* @return
*/
@GetMapping(value = "/pagesAItems")
public CommonResponse pagesAItems(@RequestParam(value = "page",defaultValue = "0")Integer offset,
@RequestParam(value = "size",defaultValue = "10")Integer size
, @RequestParam(value = "itemName",required = false) String itemName
){
log.info("【使用pagesAItems】");
log.info(" itemName = {}",itemName);
PageInfo<AppointItem> pageInfo = aItemService.selectByPages(offset,size,itemName);
return ResponseVoUtil.success(pageInfo);
}
/**
* 更新预约服务
* @param itemForm
* @return
*/
@PostMapping(value = "updateAItem")
public CommonResponse updateAItem(@RequestBody AppointItemForm itemForm){
log.info("【使用updateAItem】");
log.info(" item = {}",itemForm);
AppointItem item = new AppointItem();
if (!StringUtils.isEmpty(itemForm.getItemName())){
BeanUtils.copyProperties(itemForm,item);
item.setUpdateTime(TimeUtil.getNowDate(new java.util.Date()));
int isUpdate = aItemService.updateItem(item);
return ResponseVoUtil.success(isUpdate);
}
return null;
}
/**
* 批量删除
* @param itemIds
* @return
*/
@PostMapping(value = "/batchDelAItem/{itemIds}")
public CommonResponse batchDelAItem (@PathVariable("itemIds") String itemIds){
log.info("【使用batchDelAItem】");
log.info("itemIds = {}",itemIds);
List<String> idsList = new ArrayList<String>();
String [] strIds = itemIds.split(",");
for (String str : strIds){
idsList.add(str);
}
log.info("idsList = {}",idsList);
int isBatch = aItemService.batchDelAItem(idsList);
return ResponseVoUtil.success(isBatch);
}
}
4 表格分页效果图展示
4.1 新增页面效果图
4.2 列表页面效果图
4.3 查询效果图
4.4 修改效果图
4.5 删除效果图
4.6 批量删除效果图
5.结语
大致就把一个Demo案例实现了,目前只有增删查改、分页、批量删除功能。需要的同学可以参考该Demo的实例实现自己的相关功能。
如果觉得不错的话就为我点个赞吧。
要是有问题可在留言提问,我们来讨论讨论。