如何利用ci自动化构建工具构建一个完整的webapp项目

您所在位置: &
&nbsp&&nbsp&nbsp&&nbsp
应用Ant实现项目的全流程自动化工作.doc13页
本文档一共被下载:
次 ,您可全文免费在线阅读后下载本文档。
文档加载中...广告还剩秒
需要金币:120 &&
你可能关注的文档:
··········
··········
正在加载中,请稍后...如何构建自动化的前端开发流程 - 文章 - 伯乐在线
& 如何构建自动化的前端开发流程
如今的前端开发中,已经不再只是一些简单的静态文件了,对于很多Web App来说,前端代码甚至比后端代码要更加复杂,更加难于管理,例如:
我们有许多的第三方库的依赖需要管理;
我们有独立的前端测试需要自动运行;
我们还有很多代码需要在发布时进行打包压缩;
所以构建一个自动化的前端开发流程是非常必要的,但现在前端开发流程的构建是百花齐放,没有一个统一的标准,还有很多依赖于后端的架构来做前端开发管理。例如在Rails开发中,就有各种前端库的gem包。但是这种依赖于后端框架的管理方式有许多问题:
许多gem包的维护者并不是前端库的维护者,所以更新不一定即时;
不利于前端代码与后端代码做分离;
增加了前端开发者的学习和使用成本;
于是现在出现了一些不依赖于后端代码(虽然还是要依赖Node.js??)的管理工具,对于前端开发者非常友好,例如:、、、、??但是这些工具都或多或少有自己的一些问题,所以我决定用一些更轻量的工具(、)来搭建自己的前端开发流程。本文的例子来自本人正在开发的一个项目,可以在github上查看。
什么是开发流程?
在我看来一个完整的开发流程应该包括:
本地开发环境的初始化
第三方依赖的管理
源文件编译
自动化测试
发布到pipeline和各个环境
而现代的开发流程,就是要使上面的各个部分都可以自动化,一个命令就可以使这些流程都自动走完,并且快速的得到错误或通过的反馈,让我们可以方便快速的修复错误和release。
本地开发环境的初始化
这里我使用的工具是和,它们都基于JavaScript,使用Json来配置,对于前端开发人员非常友好。
安装完成Node.js和NPM后,在项目根目录下创建NPM的配置文件package.json:
JavaScript
"name": "Project Name",
"version": "0.0.1",
"description": "Project Description",
"repository": {
"type": "git",
"url": "git:///path/to/your_project"
"author": "Author Name",
"license": "BSD",
"readmeFilename": "README.md",
"gitHead": "git head",
"devDependencies": {
"grunt": "latest",
"grunt-contrib-connect": "latest",
"grunt-contrib-concat": "latest",
"grunt-contrib-jasmine": "latest",
"grunt-contrib-watch": "latest",
"grunt-contrib-compass": "latest"
123456789101112131415161718192021
{&&&&"name": "Project Name",&&&&"version": "0.0.1",&&&&"description": "Project Description",&&&&"repository": {&&&&&&&&"type": "git",&&&&&&&&"url": "git:///path/to/your_project"&&&&},&&&&"author": "Author Name",&&&&"license": "BSD",&&&&"readmeFilename": "README.md",&&&&"gitHead": "git head",&&&&"devDependencies": {&&&&&&&&"grunt": "latest",&&&&&&&&"grunt-contrib-connect": "latest",&&&&&&&&"grunt-contrib-concat": "latest",&&&&&&&&"grunt-contrib-jasmine": "latest",&&&&&&&&"grunt-contrib-watch": "latest",&&&&&&&&"grunt-contrib-compass": "latest"&&&&}}
其中最重要的一个配置项是devDependencies,这是用于开发的依赖,例如:自动化测试、源文件编译等等,其中各个依赖的作用和用法将会在后面讲到。而前端生产代码的依赖会使用另一个工具来管理,也在后面讲到。创建完成以后运行npm install,NPM就会将这些依赖都安装到项目根目录的node_modules文件夹中。
第三方依赖的管理
这里我使用的工具是。其实NPM也可以管理,但是NPM并不是读取第三方依赖原始的repository,而是读取自己管理的一个repository,所以更新可能会慢点,并且它使用CommonJS的接口方便Node.js项目的开发,并不是针对纯前端开发的项目;而bower是读取原始的github repository,没有更新延迟的问题,所有包都是针对纯前端开发项目的。
要使用bower只需要简单的三步:
安装:npm install bower -g
在项目根目录中创建配置文件.bowerrc
在项目根目录中创建依赖配置文件components.json
我们首先来看看.bowerrc的内容:
"directory" : "components",
: "component.json",
"endpoint"
{&&&&"directory" : "components",&&&&"json"&&&&&&: "component.json",&&&&"endpoint"&&: ""}
其中directory指定了所有的依赖会被安装到哪里;json指定了依赖配置文件的路径;endpoint制定了依赖的repository的寻址服务器,你可以替换为自己的寻址服务器。
然后我们来看看components.json的内容:
"name": "Project Name",
"version": "0.0.1",
"dependencies": {
"jquery": "latest",
"underscore": "latest",
"backbone": "latest",
"jasmine-jquery": "latest",
"jasmine-ajax": ":pivotal/jasmine-ajax.git"
1234567891011
{&&&&"name": "Project Name",&&&&"version": "0.0.1",&&&&"dependencies": {&&&&&&"jquery": "latest",&&&&&&"underscore": "latest",&&&&&&"backbone": "latest",&&&&&&"jasmine-jquery": "latest",&&&&&&"jasmine-ajax": ":pivotal/jasmine-ajax.git"&&&&}}
其中最重要的就是dependencies,它指定了所有前端开发依赖的包。所有bower包含的依赖都可以在查到,对于bower没有包含的依赖也可以直接指定github的repository,例如:"jasmine-ajax": ":pivotal/jasmine-ajax.git"。
最后运行bower install就可以在components文件夹中看到所有第三方依赖的文件了。但是bower有一个问题,就是它将所有github repository中的文件都下载下来了,其中有许多是我们不需要的文件。下面我们会将我们需要的文件提取出来打包放到我们指定的目录中。
源文件编译
这里我使用的工具是,他本身主要是基于Node.js的文件操作包,其中有许多插件可以让我们完成js文件的compile和compress、sass到css的转换等等操作。要使用它需要先安装命令行工具:npm install grunt-cli -g,然后在项目根目录中创建文件Gruntfile.js,这个文件用于定义各种task,我们首先定义一个task将从bower下载的第三方依赖都打包到文件app/js/lib.js中:
JavaScript
module.exports = function(grunt) {
var dependencies = [
'components/jquery/jquery.js',
'components/underscore/underscore.js',
'components/backbone/backbone.js'];
grunt.initConfig({
src: dependencies,
dest: 'app/js/lib.js'
grunt.loadNpmTasks('grunt-contrib-concat');
123456789101112131415
module.exports = function(grunt) {&&&&var dependencies = [&&&&&&&&'components/jquery/jquery.js',&&&&&&&&'components/underscore/underscore.js',&&&&&&&&'components/backbone/backbone.js'];&&&&grunt.initConfig({&&&&&&&&concat: {&&&&&&&&&&&&js: {&&&&&&&&&&&&&&&&src: dependencies,&&&&&&&&&&&&&&&&dest: 'app/js/lib.js'&&&&&&&&&&&&}&&&&&&&&}&&&&});&&&&grunt.loadNpmTasks('grunt-contrib-concat');};
这里的grunt-contrib-concat就是grunt的一个插件,用于文件的合并操作,我们已经在前面的package.json中引入了。js是task name;src指定了合并的源文件地址;dest指定了合并的目标文件。这样当我们运行grunt concat:js后,所有的依赖文件都会被合并为app/js/lib.js。这样做的好处是我们可以控制每个依赖的引入顺序,但是麻烦的是每次引入新的依赖都需要手动加入到dependencies数组中。这个暂时没有更好的解决方案,因为不是所有的包都在自己的components.js中声明了main文件,很多时候必须自己手动指定。
JavaScript文件编译完成以后就是CSS文件,在现代的前端开发中,我们已经很少直接写CSS文件了,一般都使用SASS或者LESS。grunt也提供了这种支持,这里我使用的是:
JavaScript
module.exports = function(grunt) {
var sasses = 'sass';
grunt.initConfig({
compass: {
development: {
options: {
sassDir: sasses,
cssDir: 'app/css'
grunt.loadNpmTasks('grunt-contrib-compass');
1234567891011121314
module.exports = function(grunt) {&&&&var sasses = 'sass';&&&&grunt.initConfig({&&&&&&&&compass: {&&&&&&&&&&&&development: {&&&&&&&&&&&&&&&&options: {&&&&&&&&&&&&&&&&&&&&sassDir: sasses,&&&&&&&&&&&&&&&&&&&&cssDir: 'app/css'&&&&&&&&&&&&&&&&}&&&&&&&&&&&&}&&&&&&&&}&&&&});&&&&grunt.loadNpmTasks('grunt-contrib-compass');};
然后运行grunt compass:development就可以完成CSS文件的编译了。
自动化测试
这里我使用的自动化测试工具是,它grunt中同样有一个插件:。下面我们来看看如何在Gruntfile.js中定义测试的task:
JavaScript
module.exports = function(grunt) {
var sources = 'app/js/**/*.js',
specs = 'spec/**/*Spec.js';
grunt.initConfig({
jasmine: {
src: [sources],
options: {
specs: specs,
helpers: ['spec/helper/**/*.js'],
vendor: 'app/js/lib.js'
grunt.loadNpmTasks('grunt-contrib-jasmine');
1234567891011121314151617
module.exports = function(grunt) {&&&&var sources = 'app/js/**/*.js',&&&&&&&&specs = 'spec/**/*Spec.js';&&&&grunt.initConfig({&&&&&&&&jasmine: {&&&&&&&&&&&&test: {&&&&&&&&&&&&&&&&src: [sources],&&&&&&&&&&&&&&&&options: {&&&&&&&&&&&&&&&&&&&&specs: specs,&&&&&&&&&&&&&&&&&&&&helpers: ['spec/helper/**/*.js'],&&&&&&&&&&&&&&&&&&&&vendor: 'app/js/lib.js'&&&&&&&&&&&&&&&&}&&&&&&&&&&&&}&&&&&&&&}&&&&});&&&&grunt.loadNpmTasks('grunt-contrib-jasmine');};
配置完成以后就可以运行grunt jasmine:test来跑测试,但问题是每次写完代码都要手动执行一次非常麻烦,最好可以每次代码有更改都自动跑一次,让我们可以更快的得到反馈。grunt的就提供了这种支持:
JavaScript
module.exports = function(grunt) {
var sources = 'app/js/**/*.js',
specs = 'spec/**/*Spec.js';
grunt.initConfig({
jasmine: {
src: [sources],
options: {
specs: specs,
helpers: ['spec/helper/**/*.js'],
vendor: 'app/js/lib.js'
files: [sources, specs],
tasks: ['jasmine:test']
grunt.loadNpmTasks('grunt-contrib-jasmine');
grunt.loadNpmTasks('grunt-contrib-watch');
123456789101112131415161718192021222324
module.exports = function(grunt) {&&&&var sources = 'app/js/**/*.js',&&&&&&&&specs = 'spec/**/*Spec.js';&&&&grunt.initConfig({&&&&&&&&jasmine: {&&&&&&&&&&&&test: {&&&&&&&&&&&&&&&&src: [sources],&&&&&&&&&&&&&&&&options: {&&&&&&&&&&&&&&&&&&&&specs: specs,&&&&&&&&&&&&&&&&&&&&helpers: ['spec/helper/**/*.js'],&&&&&&&&&&&&&&&&&&&&vendor: 'app/js/lib.js'&&&&&&&&&&&&&&&&}&&&&&&&&&&&&}&&&&&&&&},&&&&&&&&watch: {&&&&&&&&&&&&test: {&&&&&&&&&&&&&&&&files: [sources, specs],&&&&&&&&&&&&&&&&tasks: ['jasmine:test']&&&&&&&&&&&&}&&&&&&&&}&&&&});&&&&grunt.loadNpmTasks('grunt-contrib-jasmine');&&&&grunt.loadNpmTasks('grunt-contrib-watch');};
files指定了需要监听变动的文件;tasks指定了修改后自动触发的task。现在只要我们运行grunt watch:test,那么有任何源文件、测试文件的改动,Jasmine测试都会自动运行了。有时候我们也希望测试的结果显示在网页上,便于我们做js的调试。那么可以将tasks:['jasmine:test']改为tasks: ['jasmine:test:build'],然后打开根目录下的_SpecRunner.html文件,就可以在网页中看到测试结果了,再加上一些Chrome的,就可以不用刷新实时的看到测试结果,效率非常之高。虽然grunt插件中也有,但是与grunt-contrib-watch无法很好的集成,所以我没有使用这种方式。
CI Pipeline
由于我的项目是host在github上,所以我选择作为我的CI服务器。要启用travis-ci需要以下几步:
在中注册一个账号,获取一个token;
在你的github项目的Settings–&Service Hooks中找到Travis,填入token并且启用;
回到,在Accounts–&Repositories中打开你的项目的service hook
Push一个.travis.yml到github,触发第一次build。
修改package.json的scripts项,指定运行测试的命令
下面我们来看看如何配置.travis.yml:
language: node_js
before_script:
- npm install -g grunt-cli
language: node_jsnode_js:&&- "0.8"before_script:&&- npm install -g grunt-cli
由于我们的环境是基于Node.js搭建的,所以在language设置了nodejs;而**nodejs指定了Node.js的版本;before_script**指定了在测试运行前需要执行的命令,由于我们的脚本都是基于grunt的,所以需要先安装grunt的命令行包。
然后再修改package.json:
"scripts": {
"test": "grunt jasmine:test"
{&&&&??&&&&"scripts": {&&&&&&&&"test": "grunt jasmine:test"&&&&}&&&&??}
将修改以后的package.jsonpush到github上,再次触发一个新的build,你可以看到你之前错误的build已经绿了。
这里还有一个小提示:如何让build状态显示在项目的readme中?很简单,只需要在README.md中加入以下代码就可以了:
[![Build Status](https://travis-ci.org/path/to/your_repository.png?branch=master)](http://travis-ci.org/path/to/your_repository)
[![Build Status](https://travis-ci.org/path/to/your_repository.png?branch=master)](http://travis-ci.org/path/to/your_repository)
到这里基本的环境搭建就完成了,当然我们还可以使用grund的registerTask来定义一个任务序列,还可以加入template的编译??这些都可以通过grunt来灵活设置。最重要的是现在别人拿到一个项目的代码以后,可以通过一些命令来快速的搭建本地环境,方便的进行测试和开发,而且没有依赖与后端的开发环境,只要定义好接口,前端开发可以完全独立开了。虽然这其中还有很多问题没有解决,例如:
如何让第三方依赖自申明main文件
package.json与components.json其实有些重复
Live Reload还需要Chrome插件才能完成
这正是由于现在前端开发环境还没有后端开发的那种标准化,也正是挑战和机遇之所在!
可能感兴趣的话题
关于伯乐在线博客
在这个信息爆炸的时代,人们已然被大量、快速并且简短的信息所包围。然而,我们相信:过多“快餐”式的阅读只会令人“虚胖”,缺乏实质的内涵。伯乐在线内容团队正试图以我们微薄的力量,把优秀的原创文章和译文分享给读者,为“快餐”添加一些“营养”元素。
新浪微博:
推荐微信号
(加好友请注明来意)
– 好的话题、有启发的回复、值得信赖的圈子
– 分享和发现有价值的内容与观点
– 为IT单身男女服务的征婚传播平台
– 优秀的工具资源导航
– 翻译传播优秀的外文文章
– 国内外的精选文章
– UI,网页,交互和用户体验
– 专注iOS技术分享
– 专注Android技术分享
– JavaScript, HTML5, CSS
– 专注Java技术分享
– 专注Python技术分享
& 2016 伯乐在线一、Yeoman 简介
通常在开发新项目时我们都需要配置工程环境,开发目录,需要下载一些库、框架文件(如 jQuery、Backbone 等),配置编译环境(Less、Sass、Coffeescript等),甚至还要配置单元测试框架,过程非常繁琐,还没开始编码时间就耗了大半天。为了解决这个问题 Paul Irish、Addy Osmani、Sindre Sorhus、Mickael Daniel、Eric Bidelman 和 Yeoman 社区共同开发的一个项目——Yeoman。
Yeoman 是由三个工具的组成:YO、GRUNT、BOWER
YO:Yeoman核心工具,项目工程依赖目录和文件生成工具,项目生产环境和编译环境生成工具。
GRUNT:前端构建工具,jQuery就是使用这个工具打包的。
BOWER:Web 开发的包管理器,概念上类似 npm,npm 专注于 NodeJs 模块,而 bower 专注于 CSS、JavaScript、图像等前端相关内容的管理。
Yeoman 特性:
快速创建骨架应用程序——使用可自定义的模板(例如:HTML5、Boilerplate、Twitter Bootstrap等)、AMD(通过RequireJS)以及其他工具轻松地创建新项目的骨架。
自动编译 CoffeeScrip 和 Compass——在做出变更的时候,Yeoman 的 LiveReload 监视进程会自动编译源文件,并刷新浏览器,而不需要你手动执行。
自动完善你的脚本——所有脚本都会自动针对 JSHint 运行,从而确保它们遵循语言的最佳实践。
内建的预览服务器——你不需要启动自己的 HTTP 服务器。内建的服务器用一条命令就可以启动。
非常棒的图像优化——使用 OptPNG 和 JPEGTran 对所有图像做了优化。
生成 AppCache 清单——Yeoman 会为你生成应用程序缓存的清单,你只需要构建项目就好。
“杀手级”的构建过程——你所做的工作不仅被精简到最少,让你更加专注,为你节省大量工作。
集成的包管理——Yeoman 让你可以通过命令行轻松地查找新的包,安装并保持更新,而不需要你打开浏览器。
对ES6模块语法的支持——你可以使用最新的 ECMAScript 6 模块语法来编写模块。这还是一种实验性的特性,它会被转换成 eS5,从而你可以在所有流行的浏览器中使用编写的代码。
PhantomJS单元测试——你可以通过 PhantomJS 轻松地运行单元测试。当你创建新的应用程序的时候,它还会为你自动创建测试内容的骨架。
这里以 OSX 上的安装为例,先来看下 Yeoman 的安装环境要求:
NodeJS >= 0.8.x
Ruby >= 1.8.7
Compass >= 0.12.1
PhantomJS >= 1.6
在 OSX 上 Ruby 是内置的,所以只需要手动配置下其它服务:
NodeJS 安装请直接去 .pkg 安装包进行安装(Homebrew 安装的 NodeJS 会有问题,无法运行 Yeoman 命令)
Compass 可以使用 Ruby 自带的包管理工具安装:
$gem install compass
其余的 optipng、jpegtran、PhantomJS 可以通过 Homebrew 安装,如果已经安装了 Xcode 那么 Xcode CLI Tools 就已经内置。
开始安装 Yeoman:
npm install -g yo grunt-cli bower
遇到权限问题请加sudo
安装完毕后,会看到以下提示:
1、创建工程
安装好 Yeoman 后,就可以通过命令来新建工程,首先新建一个工程目录,比如 demo,首先创建 demo 目录然后在该下键入命令:
这时 Yeoman 会询问一些配置设置(这里全部选择了 Yes),之后就开始自动创建工程。
工程创建完毕后就可以看到 demo 目录下已经生成了许多目录及文件,这时开发所需的环境就搭建好了,可以开始编码了。
webapp 其实是 Yeoman 内置的工程模板,它整合了 html5 Boilerplate、jquery、Modernizr、Bootstrap、RequireJS 等框架或库文件,使我们创建完后就能直接使用。除了generator-webapp 还有一个 generator-mocha、generator-backbone、generator-angular等工程模板,可以通过npm search yeoman-generator命令查找,然后使用npm install [name]来安装。
如果工程中需要其它类库,也可以使用命令方便的添加,例如添加 underscore:
bower install underscore
2、启动工程服务
Yeoman 内置 Node 服务。启动命令:
grunt server
服务启动后会自动打开浏览器访问http://localhost:9000/(端口号可以在 gruntfile.js 中配置),然后工程服务会监听工程目录下的预编译文件,一旦发生改变就自动编译并刷新浏览器。比如我们修改工程下的 main.scss 文件,工程服务就会开始运作:
3、运行测试框架
Yeoman 内置 mocha 测试框架,在 PhantomJS 环境下进行测试,测试命令:
grunt test
运行完毕后可以在工程里的 test 目录找到测试报告。
至此 Yeoman 的部署就完成了。接下来就是自定义一套工程模板。免费移动应用测试框架——Appium篇
&对于移动应用开发者而言,无论是iOS还是Android应用,各种Bug、终端测试都十分让人头疼。不同于时时刻刻可以修补的Web App,
移动App中的Bug往往隐藏得很深,甚至有时候等到用户使用才显现出来,这么一来开发者搞不好就会赔了名声又折钱。
所以在应用发行之前,对其进行严格的测试是非常必要的。而移动应用测试框架可以帮助开发者简化测试流程,从而很好地解决这一问题。
本专题将围绕当下最受开发者喜爱的免费应用测试框架—Appium展开,希望能给想要了解移动应用测试的小伙伴带来帮助!
Appium是一个开源的,适用于原生或混合移动应用应用(hybrid mobile apps)的自动化测试平台。Appium应用WebDriver: JSON wire protocol驱动安卓和iOS移动应用
我们相信,对原生应用的自动化测试,应当不必要包含其他的SDK组件或者特别编译您的App,并且应当可以选择任何您喜欢的测试方法,框架和工具。基于这些出发点我们开发了Appium。现在Appium是一个开源项目,通过一系列设计和工具抉择,鼓励广大开发者为社区提供多种多样的贡献。
Appium的初衷是将使用任何开发语言、测试框架进行移动app自动化测试成为可能,同时支持测试代码拥有完全的对应用后台API和数据库的访问权限。编写测试程序可以使用任何开发工具,和目前支持的上面任何一种开发语言。(对于其他语言,只需要支持SeleniumWebDriver?API 和该语言相关的 client libraries即可)。
iOS: Mac OSX 10.7+ XCode 4.5+ w/ Command Line Tools
Android: Mac OSX 10.7+ or Windows 7+ or Linux Android SDK ≥ 16 (SDK < 16 in Selendroid mode) 推荐使用linux。
一、适用操作系统: Win7 旗舰版Sp1 64位操作系统 或 32位操作系统
二、所需软件: jdk-7u45-windows-i586.exe......三、安装步骤: 1)安装JDK,并进行环境变量配置
JDK安装很简单,按默认安装即可...
Appium是一个开源、跨平台的测试框架,可以用来测试原生及混合的移动端应用。Appium支持iOS、Android及FirefoxOS平台测试。Appium使用WebDriver的json wire协议,来驱动Apple系统的UIAutomation库、Android系统的UIAutomator框架...
本专题主要围绕移动互联网测试的现状、未来的发展趋势等方面进行探讨
本专题采访了测试行业资深人士—顾翔,采访主要围绕他的个人经历展开
意见反馈/投稿邮箱:(请将#修改为@)
Copyright(
All Rights Reserved如何把一个简单的WEB转化成APP应用
[问题点数:50分,结帖人town_send]
如何把一个简单的WEB转化成APP应用
[问题点数:50分,结帖人town_send]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
2008年11月 总版技术专家分月排行榜第三2008年5月 总版技术专家分月排行榜第三2008年3月 总版技术专家分月排行榜第三
2009年3月 Web 开发大版内专家分月排行榜第一2009年2月 Web 开发大版内专家分月排行榜第一2008年11月 Web 开发大版内专家分月排行榜第一2008年7月 Web 开发大版内专家分月排行榜第一2008年6月 Web 开发大版内专家分月排行榜第一2008年5月 Web 开发大版内专家分月排行榜第一2008年4月 Web 开发大版内专家分月排行榜第一2008年3月 Web 开发大版内专家分月排行榜第一2008年2月 Web 开发大版内专家分月排行榜第一
2015年2月 总版技术专家分月排行榜第二
2015年2月 Web 开发大版内专家分月排行榜第一2015年1月 Web 开发大版内专家分月排行榜第一2014年12月 Web 开发大版内专家分月排行榜第一2014年11月 Web 开发大版内专家分月排行榜第一2014年10月 Web 开发大版内专家分月排行榜第一
匿名用户不能发表回复!|
每天回帖即可获得10分可用分!小技巧:
你还可以输入10000个字符
(Ctrl+Enter)
请遵守CSDN,不得违反国家法律法规。
转载文章请注明出自“CSDN(www.csdn.net)”。如是商业用途请联系原作者。}

我要回帖

更多关于 前端自动化构建工具 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信