【JAVA】SpringBoot + mongodb 分页、排序、动态多条件查询及事务处理
【JAVA】SpringBoot + mongodb 分页、排序、动态多条件查询及事务处理
1.引入依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- mongodb ↓ --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-mongodb</artifactId></dependency><!-- mongodb ↑ -->
2.配置application.yml
spring:data:# mongodb多数据源配置mongodb:host: 192.168.36.238port: 27017username: yapipassword: Qsxdcfr2313!database: yapi# 验证数据库authentication-database: admin# 第二个数据库low-code:uri: mongodb://yapi:Qsxdcfr2313!@192.168.36.238:27017/low-code?authSource=admin# 第三个数据库event:uri: mongodb://yapi:Qsxdcfr2313!@192.168.36.238:27017/event?authSource=admin
3.MongoDB多数据源配置
创建MongoConfig类
package com.xhs.config;import com.mongodb.client.MongoClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.mongo.MongoProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory;import javax.annotation.Resource;/*** @desc: MongoDB多数据源配置* @projectName: spring-boot-demo* @author: xhs* @date: 2023-11-23 16:06:22* @version: JDK 1.8*/@Configuration
public class MongoConfig {@Resourceprivate MongoClient mongoClient;@Resourceprivate MongoProperties mongoProperties;/*** 默认的数据库** @return MongoTemplate*/@Beanpublic MongoTemplate mongoTemplate() {return new MongoTemplate(mongoClient, mongoProperties.getDatabase());}/*** 第二个数据源** @param adminUri uri* @return MongoTemplate*/@Beanpublic MongoTemplate mongoTemplateLowCode(@Value("${spring.data.mongodb.low-code.uri}") String adminUri) {return new MongoTemplate(new SimpleMongoClientDatabaseFactory(adminUri));}/*** 第三个数据源** @param adminUri uri* @return MongoTemplate*/@Beanpublic MongoTemplate mongoTemplateEvent(@Value("${spring.data.mongodb.event.uri}") String adminUri) {return new MongoTemplate(new SimpleMongoClientDatabaseFactory(adminUri));}
}
4.创建实体类
创建三个库的实体类
第一库的实体类
package com.xhs.entity.mongo;import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;/*** @desc: yapi库的user集合* @projectName: spring-boot-demo* @author: xhs* @date: 2023-11-23 023 16:14* @version: JDK 1.8*/
@Data
@Document(collection = "user")
public class User {@Idprivate String id;/*** 用户名*/private String username;/*** 角色*/private String role;
}
第二个库的实体类
package com.xhs.entity.mongo;import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;import java.util.Date;/*** @desc: low-code库的low_code_url集合* @projectName: spring-boot-demo* @author: xhs* @date: 2023-11-23 023 16:10* @version: JDK 1.8*/
@Data
@Document(collection = "low_code_url")
public class LowCodeUrl {@Idprivate String id;/*** 系统类型*/private String systemName;/*** 对象名称*/private String objectName;/*** 接口地址*/private String interfaceUrl;/*** 接口类型*/private String interfaceType;/*** 创建时间*/@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")private Date createTime;/*** 更新时间*/@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")private Date updateTime;
}
第三个库的实体类
package com.xhs.entity.mongo;import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;import java.util.Date;/*** @desc: event库的event集合* @projectName: spring-boot-demo* @author: xhs* @date: 2023-11-23 023 16:17* @version: JDK 1.8*/
@Data
@Document(collection = "event")
public class Event {@Idprivate String id;/*** 事件名称*/private String eventName;/*** 事件类型*/private String eventType;/*** 触发方式*/private String triggerMode;/*** 创建时间*/@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")private Date createTime;/*** 更新时间*/@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")private Date updateTime;
}
5.创建Controller层
package com.xhs.controller;import com.xhs.dto.request.AddEventParams;
import com.xhs.dto.request.AddLowCodeUrlParams;
import com.xhs.dto.request.FindLowCodeUrlParams;
import com.xhs.dto.request.PageEventParams;
import com.xhs.message.ReturnResult;
import com.xhs.service.MongoService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;import javax.annotation.Resource;/*** @desc:* @projectName: spring-boot-demo* @author: xhs* @date: 2023-11-23 023 16:19* @version: JDK 1.8*/
@RestController
@RequestMapping("/mongo")
public class MongoController {@Resourceprivate MongoService mongoService;/*** 查询所有用户** @return ReturnResult<Object>*/@GetMapping("/getUser")public ReturnResult<Object> getUser() {return mongoService.getUser();}/*** 条件查询 LowCodeUrl** @param findLowCodeUrlParams 查询条件* @return ReturnResult<Object>*/@PostMapping("/getLowCodeUrl")public ReturnResult<Object> getLowCodeUrl(@RequestBody FindLowCodeUrlParams findLowCodeUrlParams) {return mongoService.getLowCodeUrl(findLowCodeUrlParams);}/*** 新增 LowCodeUrl 数据** @param lowCodeUrlParams LowCodeUrl 数据* @return ReturnResult<Object>*/@PostMapping("/addLowCodeUrl")public ReturnResult<Object> addLowCodeUrl(@Validated @RequestBody AddLowCodeUrlParams lowCodeUrlParams) {return mongoService.addLowCodeUrl(lowCodeUrlParams);}/*** 新增 event 数据** @param eventParams LowCodeUrl 数据* @return ReturnResult<Object>*/@PostMapping("/addEvent")public ReturnResult<Object> addEvent(@Validated @RequestBody AddEventParams eventParams) {return mongoService.addEvent(eventParams);}/*** 分页查询 event 数据** @param eventParams 查询条件* @return ReturnResult<Object>*/@PostMapping("/pageEvent")public ReturnResult<Object> pageEvent(@Validated @RequestBody PageEventParams eventParams) {return mongoService.pageEvent(eventParams);}
}
6.创建Service层
package com.xhs.service;import com.xhs.dto.request.AddEventParams;
import com.xhs.dto.request.AddLowCodeUrlParams;
import com.xhs.dto.request.FindLowCodeUrlParams;
import com.xhs.dto.request.PageEventParams;
import com.xhs.message.ReturnResult;/*** @desc:* @projectName: spring-boot-demo* @author: xhs* @date: 2023-11-23 023 16:20* @version: JDK 1.8*/
public interface MongoService {/*** 查询所有用户** @return ReturnResult<Object>*/ReturnResult<Object> getUser();/*** 条件查询 LowCodeUrl** @param findLowCodeUrlParams 查询条件* @return ReturnResult<Object>*/ReturnResult<Object> getLowCodeUrl(FindLowCodeUrlParams findLowCodeUrlParams);/*** 新增 LowCodeUrl 数据** @param lowCodeUrlParams LowCodeUrl 数据* @return ReturnResult<Object>*/ReturnResult<Object> addLowCodeUrl(AddLowCodeUrlParams lowCodeUrlParams);/*** 新增 event 数据** @param eventParams LowCodeUrl 数据* @return ReturnResult<Object>*/ReturnResult<Object> addEvent(AddEventParams eventParams);/*** 分页查询 event 数据** @param eventParams 查询条件* @return ReturnResult<Object>*/ReturnResult<Object> pageEvent(PageEventParams eventParams);
}
7.创建ServiceImpl层
package com.xhs.service.impl;import com.xhs.dto.request.AddEventParams;
import com.xhs.dto.request.AddLowCodeUrlParams;
import com.xhs.dto.request.FindLowCodeUrlParams;
import com.xhs.dto.request.PageEventParams;
import com.xhs.dto.response.PageResult;
import com.xhs.entity.mongo.Event;
import com.xhs.entity.mongo.LowCodeUrl;
import com.xhs.entity.mongo.User;
import com.xhs.message.Result;
import com.xhs.message.ReturnResult;
import com.xhs.service.MongoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;import javax.annotation.Resource;
import java.util.Date;
import java.util.List;/*** @desc:* @projectName: spring-boot-demo* @author: xhs* @date: 2023-11-23 023 16:20* @version: JDK 1.8*/
@Slf4j
@Service
public class MongoServiceImpl implements MongoService {@Resource@Qualifier("mongoTemplate")private MongoTemplate mongoTemplate;@Resource@Qualifier("mongoTemplateLowCode")private MongoTemplate mongoTemplateLowCode;@Resource@Qualifier("mongoTemplateEvent")private MongoTemplate mongoTemplateEvent;/*** 查询所有用户** @return ReturnResult<Object>*/@Overridepublic ReturnResult<Object> getUser() {List<User> users = mongoTemplate.find(new Query(), User.class);return ReturnResult.build(Result.QUERY_SUCCESS).setData(users);}/*** 条件查询 LowCodeUrl** @param findLowCodeUrlParams 查询条件* @return ReturnResult<Object>*/@Overridepublic ReturnResult<Object> getLowCodeUrl(FindLowCodeUrlParams findLowCodeUrlParams) {Query query = new Query();if (StringUtils.hasLength(findLowCodeUrlParams.getSystemName())) {// regex 模糊查询query.addCriteria(Criteria.where("systemName").regex(findLowCodeUrlParams.getSystemName()));}if (StringUtils.hasLength(findLowCodeUrlParams.getObjectName())) {// regex 模糊查询query.addCriteria(Criteria.where("objectName").regex(findLowCodeUrlParams.getObjectName()));}if (StringUtils.hasLength(findLowCodeUrlParams.getInterfaceType())) {query.addCriteria(Criteria.where("interfaceType").is(findLowCodeUrlParams.getInterfaceType()));}List<LowCodeUrl> lowCodeUrlList = mongoTemplateLowCode.find(query, LowCodeUrl.class);return ReturnResult.build(Result.QUERY_SUCCESS).setData(lowCodeUrlList);}/*** 新增 LowCodeUrl 数据** @param lowCodeUrlParams LowCodeUrl 数据* @return ReturnResult<Object>*/@Override@Transactional(rollbackFor = Exception.class)public ReturnResult<Object> addLowCodeUrl(AddLowCodeUrlParams lowCodeUrlParams) {Date date = new Date();LowCodeUrl codeUrl = new LowCodeUrl();codeUrl.setSystemName(lowCodeUrlParams.getSystemName());codeUrl.setObjectName(lowCodeUrlParams.getObjectName());codeUrl.setInterfaceUrl(lowCodeUrlParams.getInterfaceUrl());codeUrl.setInterfaceType(lowCodeUrlParams.getInterfaceType());codeUrl.setCreateTime(date);codeUrl.setUpdateTime(date);LowCodeUrl insert = mongoTemplateLowCode.insert(codeUrl);return ReturnResult.build(Result.ADD_SUCCESS).setData(insert.getId());}/*** 新增 event 数据** @param eventParams LowCodeUrl 数据* @return ReturnResult<Object>*/@Overridepublic ReturnResult<Object> addEvent(AddEventParams eventParams) {Date date = new Date();Event event = new Event();event.setEventName(eventParams.getEventName());event.setEventType(eventParams.getEventType());event.setTriggerMode(eventParams.getTriggerMode());event.setCreateTime(date);event.setUpdateTime(date);Event insert = mongoTemplateEvent.insert(event);return ReturnResult.build(Result.ADD_SUCCESS).setData(insert.getId());}/*** 分页查询 event 数据** @param eventParams 查询条件* @return ReturnResult<Object>*/@Overridepublic ReturnResult<Object> pageEvent(PageEventParams eventParams) {// 排序字段Sort sort = Sort.by(Sort.Direction.DESC, "createTime");// 分页,PageNumber()-1是因为第一页的下标为0 ,入参PageNumber最小值为1Pageable pageRequest = PageRequest.of(eventParams.getPageNumber()-1, eventParams.getPageSize(), sort);// 查询条件Query query = new Query();if (StringUtils.hasLength(eventParams.getEventName())) {// regex 模糊查询query.addCriteria(Criteria.where("eventName").regex(eventParams.getEventName()));}if (StringUtils.hasLength(eventParams.getEventType())) {// regex 模糊查询query.addCriteria(Criteria.where("eventType").regex(eventParams.getEventType()));}if (StringUtils.hasLength(eventParams.getTriggerMode())) {// regex 模糊查询query.addCriteria(Criteria.where("triggerMode").regex(eventParams.getTriggerMode()));}query.with(pageRequest);// 查询总数long count = mongoTemplateEvent.count(query, Event.class);// 查询数据List<Event> events = mongoTemplateEvent.find(query, Event.class);// 分页结果PageResult<List<Event>> result = new PageResult<>();result.setPageNumber(eventParams.getPageNumber());result.setPageSize(eventParams.getPageSize());result.setTotalRow(count);result.setRecords(events);return ReturnResult.build(Result.QUERY_SUCCESS).setData(result);}
}
8.源码地址
https://gitee.com/xhs101/spring-boot-demo
9.查询效果:


相关文章:
【JAVA】SpringBoot + mongodb 分页、排序、动态多条件查询及事务处理
【JAVA】SpringBoot mongodb 分页、排序、动态多条件查询及事务处理 1.引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- mongodb ↓ -->&…...
nrm安装及使用
一、介绍 nrm 是一个 Node.js 的 registry 管理工具,它允许你快速地在不同的 npm registry 之间进行切换。通过使用 nrm,你可以方便地将 npm 的 registry 切换为淘宝镜像、npm 官方镜像或者其他定制的镜像,以加快包的下载速度。nrm仓库请点击…...
docker报错standard init linux.go:228 exec user process caused: exec format error
1、报错 使用Dockerfile自己做的服务镜像,docker run时启动失败,报错如下: standard init linux.go:228 exec user process caused: exec format error2、原因一 当前服务器的CPU架构和构建镜像时的CPU架构不兼容。比如做镜像是在arm机器下…...
Docker 的基本概念和优势,以及在应用程序开发中的实际应用。
Docker 是一种容器化技术,它将一个应用程序及其所有依赖项打包在一起,形成一个独立的、可移植的容器。这个容器可以在任何支持 Docker 的操作系统上运行,而且具有很好的可移植性和可扩展性。以下是 Docker 的基本概念和优势: 镜像…...
libmosquitto库的一个bug,任务消息id(mid)分配后不起作用
代码如图所示: 当订阅了所有主题后,每个主题的mid是他们的下标索引加100的数字,可是实际打印出来的值是: mid依然是1,2,这个参数在这里失效了,不知道是bug还是mqtt的什么机制?...
亚马逊云科技re:Invent大会:云计算与生成式AI共筑科技新局面,携手构建未来
随着科技的飞速发展,云计算和生成式 AI 已经成为了推动科技进步的重要力量。这两者相互结合,正在为我们创造一个全新的科技局面。 亚马逊云科技的re:Invent大会再次证明了云计算和生成式AI的强大结合正在塑造科技的新未来。这次大会聚焦了云计算的前沿技…...
Docker 部署 Nacos(单机),利用 MySQL 数据库存储配置信息
前面的话 默认你已经懂 Docker、docker-compose Nacos版本:v2.2.3 MySQL 版本:8.2.0 一、下载 打开 Nacos 官网 官网地址:官网 点击手册 左侧 Nacos Docker 克隆项目到本地 # 克隆项目,如果提示连接不到 github 请自行解决 …...
【LeeCode】35.搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 你可以假设数组中无重复元素。 解: class Solution {public int searchInsert(int[] nums, int target) {int …...
18.天气小案例
1►新增带Layout组件的页面 直接在views文件夹下面新增weather.vue。然后随便写一个123,现在先让我们页面能跳过去先。 让页面能跳过去,有好几种方法: 1、在菜单管理自己添加一个菜单,然后把菜单分配给某个角色,再把…...
医保线上购药系统:代码驱动的医疗创新
医保线上购药系统,这是一个融合技术和医疗的创新典范。本文将通过简单的技术代码示例,为您揭示这一系统是如何通过技术驱动医疗创新,为用户提供更智能、便捷的健康管理体验的。 1. 前端界面开发 使用React框架,我们可以轻松构建…...
VMware OpenSLP漏洞解决方案
PS:早期为客户做VMware检测的方法,大家如有遇到可参考 OpenSLP堆溢出漏洞攻击大量ESXI服务器,该漏洞编号为CVE-2021-21974,由 OpenSLP 服务中的堆溢出问题引起 大于以下版本则不受影响 ESXi versions 7.x prior to ESXi7…...
UEditor编辑器实现上传图片自动加水印功能PHP源码
UEditor编辑器是百度旗下的免费开源富文本编辑器,使用很方便,但是也有缺点,比如,上传图片不能自动添加水印,下边我们就来说说如何在UEditor编辑器中自动实现上传图片添加水印功能,操作很简单。 首先找到UEditor/PHP目录下的Uploader.class.php的文件,打开该文件,找到以…...
【从浅识到熟知Linux】基本指定之find、grep、head和tail
🎈归属专栏:从浅学到熟知Linux 🚗个人主页:Jammingpro 🐟每日一句:一篇又一篇,学写越上头。 文章前言:本文介绍find、grep、head和tail指令用法并给出示例和截图。 文章目录 find基本…...
【云备份】文件操作实用工具类设计
文章目录 为什么要单独设计文件工具类?整体实现Filesize ——文件大小stat接口 LastMTime ——最后一次修改时间LastATime —— 最后一次访问时间FileName —— 文件名称GetPostLen ——获取文件指定位置 指定长度的数据GetContnet —— 读取文件数据SetContent ——…...
LeetCode Hot100 199.二叉树的右视图
题目: 给定一个二叉树的 根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。 方法(灵神):先递归右子树,再递归左子树,在递归的同…...
Nacos身份绕过漏洞复现(QVD-2023-6271)
Nacos身份绕过漏洞复现(QVD-2023-6271) 环境配置 该漏洞主要用了win10_JAVA的环境,参考网上已有的复现文章,使用jdk-11.0.2_windows-x64_bin.exe 由于2.2.0之后的nacos已将本漏洞修复,所以本次复现使用2.2.0的包 下…...
Elasticsearch集群部署 head监控插件 Kibana部署 Nginx反向代理 Logstash部署
一、组件介绍1、Elasticsearch:2 、Logstash3、Kibana4、Kafka:5、Filebeat: 二、 Elasticsearch集群部署服务器创建用户安装ES修改配置文件创建数据和日志目录设置JVM堆大小 #7.0默认为4G修改安装目录及存储目录权限系统优化(1)增…...
网络和Linux网络_5(应用层)HTTP协议(方法+报头+状态码)
目录 1. HTTP协议介绍 1.1 URL介绍 1.2 urlencode和urldecode 1.3 HTTP协议格式 1.4 HTTP的方法和报头和状态码 2. 代码验证HTTP协议格式 HttpServer.hpp 2.2 html正式测试 Util.hpp index.html 2.3 再看HTTP方法和报头和状态码 2.3.1 方法_GET和POST等 2.3.2 报头…...
人工智能-注意力机制之残差连接和层规范化
残差连接和层规范化 层规范化和批量规范化的目标相同,但层规范化是基于特征维度进行规范化。尽管批量规范化在计算机视觉中被广泛应用,但在自然语言处理任务中(输入通常是变长序列)批量规范化通常不如层规范化的效果好。 以下代…...
linux centos安装nvm
安装目录 mkdir /opt/nvm && cd /opt/nvm安装包下载 wget https://github.com/nvm-sh/nvm/archive/refs/tags/v0.39.5.tar.gz注意:https://github.com/nvm-sh/nvm/tags获取新版本或所需版本下载链接并替换 安装包解压 for file in *.tar.gz; do tar -zxv…...
linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
C++ 基础特性深度解析
目录 引言 一、命名空间(namespace) C 中的命名空间 与 C 语言的对比 二、缺省参数 C 中的缺省参数 与 C 语言的对比 三、引用(reference) C 中的引用 与 C 语言的对比 四、inline(内联函数…...
什么是EULA和DPA
文章目录 EULA(End User License Agreement)DPA(Data Protection Agreement)一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA(End User License Agreement) 定义: EULA即…...
【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)
🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...
相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...
Ascend NPU上适配Step-Audio模型
1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...
Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...
CSS设置元素的宽度根据其内容自动调整
width: fit-content 是 CSS 中的一个属性值,用于设置元素的宽度根据其内容自动调整,确保宽度刚好容纳内容而不会超出。 效果对比 默认情况(width: auto): 块级元素(如 <div>)会占满父容器…...
短视频矩阵系统文案创作功能开发实践,定制化开发
在短视频行业迅猛发展的当下,企业和个人创作者为了扩大影响力、提升传播效果,纷纷采用短视频矩阵运营策略,同时管理多个平台、多个账号的内容发布。然而,频繁的文案创作需求让运营者疲于应对,如何高效产出高质量文案成…...
