热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

gradle项目打包成多个jar包_快速上手Gradle

“Gradle介绍*Gradle安装*Gradle项目创建注意事项*Gradle项目目录结构*Groovy简单语法*Gradle配置文件*Gradle使用Maven仓库*Gradl

a2f25c7cb64160d4e27f99ba5bd3320b.png

“Gradle介绍*Gradle安装*Gradle项目创建注意事项*Gradle项目目录结构*Groovy简单语法*Gradle配置文件*Gradle使用Maven仓库*Gradle构建Jar工程*Gradle构建War工程*Gradle构建聚合工程

最近的项目需要使用Gradle构建,初上手时也是一脸懵逼。不过没关系呀,咱们课余时间可以好好学习一下呀~

01

Gradle介绍

先上官网:https://gradle.org/

fb60c5608aa903ba10dc2c9ffdff380a.png

Gradle弥补Maven的不足:

Maven两个功能:1.管理Jar包。2.构建项目。

在管理jar包中,我们都知道Maven是在pom.xml中以坐标的形式去管理,一般一个Jar包的引用至少需要占两行代码以上(version可以统一管理)。虽然一般微服务的项目Jar包会相对较少,但依然会有40行往上的代码,切看起来不直观,更别说一些巨石项目了(找一个坐标要翻很久)。Gradle借用Groovy弥补了这个特性,使咱们Jar包依赖的代码更简洁且增加了编程容错性,同时由于Groovy的编程语言特性,他可以生成文件,因此也可以利用Gradle在构建时生成POM,对持物集成和服务器更友好。

02

Gradle安装

官方下载地址:https://services.gradle.org/distributions/

28d30e95f815cee2ca70f7ef2e2664f1.png


为了和项目版本一致,我就下载:gradle-4.7-bin.zip这个了。

解压好后的目录

00241d10041002e344cc7e28177906f7.png

bin目录下

d580f63d9064e59ab82efc89439f6d16.png

第一个是sh脚本,第二个是windows的执行脚本。

所以这里是我们配置环境变量的目录。

配置环境变量的操作都是相同的。

1c498dd534eac0dcb5e7c82f268a42ff.png

5077fe0ce2c716b992d66acdd6a9f9af.png

cmd里执行gradle -v ,出现类似如下信息,就说明gradle可以使用了。

88459584bf9a68435ce01e4c0c4588d6.png

第一次启动时会在C:\Users\Administrator出现.gradle的文件夹,这个就是类似Maven的.m2文件夹。

c658137bb95fbe8a27aa8775cac4542f.png

Caches文件夹作为Gradle默认的本地仓库去存储Jar包。

03

Gradle项目创建注意事项

接下来我们用idea创建一个最简单的Gradle管理项目看一下其项目结构。

进入Idea初始界面,先看看是否可以配置Gradle的默认使用。

e921c41e26a8ac0d514fdd364b223399.png

21a66f6b549a5c361f1200c244a93a54.png

发现只能配置Gradle的仓库位置,并不能确定版本,那就先不设置了。

还是回到首页先创建Gradle项目

404843331f9f3126afa5f6bda53a1d16.png

940c0b0e4ed508c8e1c31fa93e428d11.pngfinish创建Gradle项目。

2f3d6951801989a8e1fcedc305ab6f5b.png

进去之后是这个样子。

我们要设置一下使用Gradle的版本。

af7076c1022fb0c6592fa7a6e9d01f7d.png

默认使用.gradle作为默认仓库,同时使用版本读取gradle-wrapper.properties,下面是文件内容

556c8a9c02acf1ea292b4e39265a2db6.png

文件的意思是会先去读取系统变量中的%Gradle_User_Home%作为发布包/打压缩包地址,/wrapper/dists作为Gradle的下载目录,同时默认使用的是gradle6.1版本。

我们作个性化设置。

2726670c8888d7defc86ab5c34f55a68.png

使用Maven的仓库并且使用Gradle4.7。

但是这里要注意一个问题,此处设置了默认仓库只是针对Idea的,如果我们想在自己在cmd中编译打包等操作也用我们指定的仓库时,需要在系统变量中添加如下配置。

fc47593cb4aa5959a198d1aeed1e26bf.png

OK,这些基本配置好后就可以开始玩Gradle了。

04

Gradle项目目录结构

c55e13b86bd6f0edafa7ea42f9c02bc3.png

可以看到项目里是没有Pom文件的,相对的会有一个build.gradle以及settings.gradle。另外还会有一个专门的gradle文件包,目前里面只装了wrapper(包装者?)里面的配置我们上面有贴出来。项目主体src下的内容和Maven创建时没有什么不同。

8001715fc540144595082a481cf17c9d.png

05

Groovy简单语法

这里先不说这些配置文件里面的内容,因为这里面的内容都是用Groovy语言编写的,先大概了解了语言我们才能明白配置文件里写了什么。

a10e8305023c7a23f0f9744ad2abff18.png

看到其结合语言就知道,Groovy是追求容错低的弱语言。

Groovy 是 用于Java虚拟机的一种敏捷的动态语言,它是一种成熟的面向对象编程语言,既可以用于面向对象编程,又可以用作纯粹的脚本语言。使用该种语言不必编写过多的代码,同时又具有闭包和动态语言中的其他特性。

Groovy是JVM的一个替代语言(替代是指可以用 Groovy 在Java平台上进行 Java 编程),使用方式基本与使用 Java代码的方式相同,该语言特别适合与Spring的动态语言支持一起使用,设计时充分考虑了Java集成,这使 Groovy 与 Java 代码的互操作很容易。(注意:不是指Groovy替代java,而是指Groovy和java很好的结合编程。

大概先看这些了解一下,我们这里追求快速了解哈。

cf350d0b7c82acbb88e043b11931294c.png

先使用Idea默认的Groovy控制台来编写代码,直接上代码和结果了。

代码

//介绍Groovy//支持Java语言编程System.out.println("hello Groovy");//Groovy自己的编程方式println("hello Groovy");//Groovy可以省略末尾分号println("hello Groovy")//Groovy可以省略末尾分号println "hello Groovy"//Groovy中定义简单变量//def是弱类型&#xff0c;groovy会根据情况来赋值的类型def i &#61; 18println i&#43;1def s &#61; "小明"println s&#43;1//Groovy中定义复杂变量//定义集合类型,注意这里单双引号都是一个效果def list &#61; [&#39;a&#39;,"b"]//往list中添加元素list <<&#39;c&#39;//取出第三个元素println list.get(2)//定义一个mapdef map &#61; [&#39;key1&#39;:&#39;value1&#39;,&#39;key2&#39;:&#39;value2&#39;]//向map中添加键值对map.key3 &#61; &#39;value3&#39;//打印key3的值println map.get(&#39;key3&#39;)

结果

hello Groovyhello Groovyhello Groovyhello Groovy19小明1cvalue3

好的&#xff0c;简单的说完了&#xff0c;我们再讲个groovy中的闭包(类似Java中的函数式编程)

无参数闭包调用

//Groovy中的闭包//闭包其实是一段代码块。在闭包中&#xff0c;我们主要把闭包当参数来使用//定义一个闭包def b1 &#61; { println "hello b1"}//定义一个方法&#xff0c;方法里面需要闭包类型的参数def method1(Closure closure){ closure()}//调用method1method1(b1)

结果

hello b1

有参数的闭包调用

//定义一个闭包&#xff0c;带参数def b2 &#61; { v -> println "hello ${v}"}//定义一个方法&#xff0c;方法里面需要闭包类型的参数def method2(Closure closure){    closure("小pw")}//调用method2method2(b2)

输出

hello 小pw

06

Gradle配置文件

接下来我们看下Gradle配置文件以及如何使用。

打开build.gradle文件如下

963ae84dfd116743070366fc7bff5f6b.png

这里做一个注解

//当前项目运行环境plugins { id &#39;java&#39;}//项目的坐标group &#39;cn.pw&#39;version &#39;1.0-SNAPSHOT&#39;//指定仓库的路径//mavenCentral()默认只使用远程中央仓库去拉取jar包&#xff0c;下载到我们指定的本地仓库repositories { mavenCentral()}//gradle中所有的jar包的坐标都在dependencies属性内放置//每个jar包的坐标有三个基本元素对应Maven中的坐标//group name version//testCompile表示该jar包在测试时起作用//我们在gradle添加坐标时都要带上jar包的作用域dependencies { testCompile group: &#39;junit&#39;, name: &#39;junit&#39;, version: &#39;4.12&#39;}

然后假如我们要使用spring的jar包&#xff0c;过程应该如下。

先去maven中央仓库地址&#xff1a;https://mvnrepository.com/

27ed3591f1ee53eaaeaa0266b758716c.png

搜索spring&#xff0c;选取spring framework

8b3bc09586e9183b02751f15ef1c2a11.png

选取版本

cd8d8bcf904b0e93411915194e88e1d5.png

选取gradle

a329e636cde280074a86f6b57576858c.png

下面的内容就是gradle的坐标格式了&#xff0c;复制粘贴到build.gradle中就好。

712194fdfc1eaaf9d6e9d2dc1b0825ba.png

OK&#xff0c;这样一个依赖就加好了。

07

Gradle使用Maven仓库

从groovy语法可以知道&#xff0c;其实配置文件中的内容都是方法&#xff0c;比如mavenCentral()&#xff0c;我们按住ctrl点击进去&#xff0c;可以看到类和方法&#xff0c;和java一样。

2f813911c758d57eba1a40accadcdb88.png

我们看到其中有一个方法是mavenLocal()&#xff0c;这个方法就是调用本地仓库去拉取jar包&#xff0c;因此我们可以在代码中作如下更改。

//指定仓库的路径//mavenCentral()默认只使用远程中央仓库去拉取jar包&#xff0c;下载到我们指定的本地仓库repositories { //先去本地仓库拉取Jar包 mavenLocal() //本地仓库拉取不到去中央仓库拉取Jar包 mavenCentral()}

这样&#xff0c;我们就可以先使用Maven本地仓库的Jar包啦。

08

Gradle构建Jar工程

上代码测试

build.gradle

//当前项目运行环境plugins { id &#39;java&#39;}//项目的坐标group &#39;cn.pw&#39;version &#39;1.0-SNAPSHOT&#39;//指定仓库的路径//mavenCentral()默认只使用远程中央仓库去拉取jar包&#xff0c;下载到我们指定的本地仓库repositories { //先去本地仓库拉取Jar包 mavenLocal() //本地仓库拉取不到去中央仓库拉取Jar包 mavenCentral()}//解决gradle控制台乱码的问题tasks.withType(JavaCompile) { options.encoding &#61; "UTF-8"}//gradle中所有的jar包的坐标都在dependencies属性内放置//每个jar包的坐标有三个基本元素对应Maven中的坐标//group name version//testCompile表示该jar包在测试时起作用//我们在gradle添加坐标时都要带上jar包的作用域dependencies { testCompile group: &#39;junit&#39;, name: &#39;junit&#39;, version: &#39;4.12&#39; // https://mvnrepository.com/artifact/org.springframework/spring compile group: &#39;org.springframework&#39;, name: &#39;spring&#39;, version: &#39;2.5.6&#39;}

dao

package cn.pw;import java.util.List;public interface gradleDao { public List findAll();}

daoImpl

package cn.pw;import java.util.LinkedList;import java.util.List;public class gradleDaoImpl implements gradleDao{ &#64;Override public List findAll() { LinkedList stringLinkedList &#61; new LinkedList<>(); stringLinkedList.add("hello World"); System.out.println("列表查询成功"); return stringLinkedList; }}

test

import cn.pw.gradleDao;import org.junit.Test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class GradleJarTest { &#64;Test public void gradlejarTest() { //得到Spring容器 ApplicationContext applicationContext &#61; new ClassPathXmlApplicationContext("bean.xml"); //从容器中拿对象 gradleDao gradleDao &#61; (cn.pw.gradleDao) applicationContext.getBean("gradleDao"); //对象执行方法 gradleDao.findAll(); }}

启动参数

-Dfile.encoding&#61;utf-8

输出

Testing started at 上午 1:41 ...> Task :compileJava UP-TO-DATE> Task :processResources> Task :classes> Task :compileTestJava> Task :processTestResources NO-SOURCE> Task :testClasses> Task :test六月 26, 2020 1:41:10 上午 org.springframework.context.support.AbstractApplicationContext prepareRefresh信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext&#64;53500d47: display name [org.springframework.context.support.ClassPathXmlApplicationContext&#64;53500d47]; startup date [Fri Jun 26 01:41:10 GMT&#43;08:00 2020]; root of context hierarchy六月 26, 2020 1:41:10 上午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions信息: Loading XML bean definitions from class path resource [bean.xml]六月 26, 2020 1:41:11 上午 org.springframework.context.support.AbstractApplicationContext obtainFreshBeanFactory信息: Bean factory for application context [org.springframework.context.support.ClassPathXmlApplicationContext&#64;53500d47]: org.springframework.beans.factory.support.DefaultListableBeanFactory&#64;65f56674六月 26, 2020 1:41:11 上午 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory&#64;65f56674: defining beans [gradleDao]; root of factory hierarchy列表查询成功BUILD SUCCESSFUL in 2s4 actionable tasks: 3 executed, 1 up-to-date上午 1:41:11: Task execution finished &#39;:test --tests "GradleJarTest.gradlejarTest" -Dfile.encoding&#61;utf-8&#39;.

打Jar包

9293aaf0ea4c2f52e0471c57e6cf5332.png

输出

上午 1:42:19: Executing task &#39;jar&#39;...> Task :compileJava UP-TO-DATE> Task :processResources> Task :classes> Task :jar UP-TO-DATEBUILD SUCCESSFUL in 0s3 actionable tasks: 1 executed, 2 up-to-date上午 1:42:20: Task execution finished &#39;jar&#39;.

jar包位置

6baf3c103c8c18a156d64089825cd215.png

09

Gradle构建War工程

web工程创建和jar是一样的&#xff0c;只是需要自己在src下创建webapp以及在build.gradle中添加war包类型即可。

06e5dec4c556dc00e015876856478af6.png

813625419871105df844ebbd973cb954.png

web.xml

springmvcservlet-name> org.springframework.web.servlet.DispatcherServletservlet-class> contextConfigLocationparam-name> classpath:springmvc.xmlparam-value> init-param> servlet> springmvcservlet-name> /url-pattern> servlet-mapping>web-app>

springmvc.xml

bean> beans>

controller

package cn.pw.controller;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;&#64;Controller&#64;RequestMapping("hello")public class HelloController { &#64;RequestMapping("index") public String toindex(){ return "index"; }}

index.jsp

<%&#64; page contentType&#61;"text/html; charset&#61;UTF-8" language&#61;"java" %>body>html>

index.jsp

Hello World!h2>body>html>

本机 tomcat启动后的输出

a0b335eef6ac2e7b71b76fe9b5d25ebe.png

打war包

9267be3d032f2cbf9702a34e7514700f.png

8ccdcbabb0c46639b9d52cf32efbc5a0.png

10

Gradle构建聚合工程

聚合工程是最重要的&#xff0c;因为一般项目里都会是这个模式,类似于Maven的聚合&#xff0c;也是由Parent管理子模块的共性Jar包。具体如何创建我们来看下。

首先创建父工程和一般的项目一样。

f79aad4784b2155ccb2a51fbc1ddb6b6.png

然后对着项目右键newModule,操作差不多&#xff0c;改个名字就好。

9d8f2bb48a1d89c557864a9d2f9f3319.png

出现子项目&#xff0c;且在父工程的settings.gradle文件中包含子模块信息。

如法再建一个web

06231c51c179d1f8ef9a84cbf2e55385.png

我们将web还是变成war工程

cf47eabe9e89485f9f5147cde9b6ba34.png

再创建一个service

fc3476b2e0f0686d0e4cd399708a6b1e.png

把之前的web工程的配置都拷贝过来。

6fa567bc6559214dcbfffa5b9f7a9259.png

然后开始导jar包&#xff0c;这里共同jar包要放到父工程中&#xff0c;添加allprojects标签。

父工程build.gradle

allprojects { apply plugin: &#39;java&#39; group &#39;cn.pw&#39; version &#39;1.0-SNAPSHOT&#39; repositories { mavenLocal() mavenCentral() } dependencies { testCompile group: &#39;junit&#39;, name: &#39;junit&#39;, version: &#39;4.12&#39;// https://mvnrepository.com/artifact/org.springframework/spring compile group: &#39;org.springframework&#39;, name: &#39;spring&#39;, version: &#39;5.2.0.RELEASE&#39;, ext: &#39;pom&#39; // https://mvnrepository.com/artifact/org.springframework/spring-web compile group: &#39;org.springframework&#39;, name: &#39;spring-web&#39;, version: &#39;5.0.2.RELEASE&#39;// https://mvnrepository.com/artifact/org.springframework/spring-webmvc        compile group: &#39;org.springframework&#39;, name: &#39;spring-webmvc&#39;, version: &#39;5.0.2.RELEASE&#39; }}

然后去除子模块中相同的配置项比如daoProject

5ad62e1309b63e228cbdbc5c7419b38e.png

这些父工程都有&#xff0c;可以先清掉&#xff0c;以后有个性化配置可以给每个子工程自己的build.gradle里面加&#xff0c;和Maven类似。

serviceProject需要引入daoProject的坐标。

dependencies { compile project(":daoProject")}

webProject则需要保留打war包的配置和serviceProject坐标引入&#xff0c;以及serverlet坐标

apply plugin: &#39;war&#39;dependencies { compile project(":serviceProject") // https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api providedCompile group: &#39;javax.servlet&#39;, name: &#39;javax.servlet-api&#39;, version: &#39;3.0.1&#39;// https://mvnrepository.com/artifact/javax.servlet/jsp-api providedCompile group: &#39;javax.servlet&#39;, name: &#39;jsp-api&#39;, version: &#39;2.0&#39;}

配置完毕&#xff0c;把之前jar工程和war工程的代码贴过来跑吧~

web

1cfa0f079c63038313503433ccd7585e.png

web改一下springmvc.xml

b02b53189ccc69fad9577b545a5300fc.png

controller

package cn.pw.controller;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.RequestMapping;import cn.pw.service.HelloSerivce;&#64;Controller&#64;RequestMapping("hello")public class HelloController { &#64;Autowired private HelloSerivce helloService; &#64;RequestMapping("index") public String toindex(Model model){ String hello &#61; helloService.sayHello(); model.addAttribute("hello",hello); return "index"; }}

service

0506bb8dc89910387889d08f58385e72.png

Helloservice

package cn.pw.service;public interface HelloSerivce { public String sayHello();}

HelloserviceImpl

package cn.pw.service.impl;import cn.pw.service.HelloSerivce;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import cn.pw.HelloDao;&#64;Servicepublic class HelloServiceImpl implements HelloSerivce { &#64;Autowired private HelloDao helloDao; &#64;Override public String sayHello() { return helloDao.sayHello(); }}

dao

d267a52ce307feacd18ec5d63dfed8b3.png

HelloDao

package cn.pw;public interface HelloDao { public String sayHello();}

HelloDaoImpl

package cn.pw;import org.springframework.stereotype.Repository;&#64;Repositorypublic class HelloDaoImpl implements HelloDao { &#64;Override public String sayHello() { return "Moudle Hello"; }}

用tomcat把web跑起来后页面如图

8a9a51f3368b0d856540fc7dca7c63d8.png

如果想打包&#xff0c;对着parent去build就可以啦

2ed45b381a242c820d65c2a995f36d4d.png

73f267b4afe3e0d4f1fcb355bd89b69c.png

58b4253d1f8a7c8346a005347cd5d372.png

OK&#xff0c;今天就分享到这里啦~

项目源码&#xff1a;

https://github.com/pengwenqq/studyDemo




推荐阅读
  • Windows 7 64位系统下Redis的安装与PHP Redis扩展配置
    本文详细介绍了在Windows 7 64位操作系统中安装Redis以及配置PHP Redis扩展的方法,包括下载、安装和基本使用步骤。适合对Redis和PHP集成感兴趣的开发人员参考。 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • Python自动化处理:从Word文档提取内容并生成带水印的PDF
    本文介绍如何利用Python实现从特定网站下载Word文档,去除水印并添加自定义水印,最终将文档转换为PDF格式。该方法适用于批量处理和自动化需求。 ... [详细]
  • 深入解析Redis内存对象模型
    本文详细介绍了Redis内存对象模型的关键知识点,包括内存统计、内存分配、数据存储细节及优化策略。通过实际案例和专业分析,帮助读者全面理解Redis内存管理机制。 ... [详细]
  • Python处理Word文档的高效技巧
    本文详细介绍了如何使用Python处理Word文档,涵盖从基础操作到高级功能的各种技巧。我们将探讨如何生成文档、定义样式、提取表格数据以及处理超链接和图片等内容。 ... [详细]
  • Java 中重写与重载的区别
    本文详细解析了 Java 编程语言中重写(Override)和重载(Overload)的概念及其主要区别,帮助开发者更好地理解和应用这两种多态性机制。 ... [详细]
  • 本文将介绍如何编写一些有趣的VBScript脚本,这些脚本可以在朋友之间进行无害的恶作剧。通过简单的代码示例,帮助您了解VBScript的基本语法和功能。 ... [详细]
  • 在当前众多持久层框架中,MyBatis(前身为iBatis)凭借其轻量级、易用性和对SQL的直接支持,成为许多开发者的首选。本文将详细探讨MyBatis的核心概念、设计理念及其优势。 ... [详细]
  • XNA 3.0 游戏编程:从 XML 文件加载数据
    本文介绍如何在 XNA 3.0 游戏项目中从 XML 文件加载数据。我们将探讨如何将 XML 数据序列化为二进制文件,并通过内容管道加载到游戏中。此外,还会涉及自定义类型读取器和写入器的实现。 ... [详细]
  • 深入理解Redis的数据结构与对象系统
    本文详细探讨了Redis中的数据结构和对象系统的实现,包括字符串、列表、集合、哈希表和有序集合等五种核心对象类型,以及它们所使用的底层数据结构。通过分析源码和相关文献,帮助读者更好地理解Redis的设计原理。 ... [详细]
  • 本文详细介绍了如何准备和安装 Eclipse 开发环境及其相关插件,包括 JDK、Tomcat、Struts 等组件的安装步骤及配置方法。 ... [详细]
  • 在成功安装和测试MySQL及Apache之后,接下来的步骤是安装PHP。为了确保安全性和配置的一致性,建议在安装PHP前先停止MySQL和Apache服务,并将MySQL集成到PHP中。 ... [详细]
  • 本文深入探讨了MySQL中常见的面试问题,包括事务隔离级别、存储引擎选择、索引结构及优化等关键知识点。通过详细解析,帮助读者在面对BAT等大厂面试时更加从容。 ... [详细]
  • 本文将详细介绍通过CAS(Central Authentication Service)实现单点登录的原理和步骤。CAS由耶鲁大学开发,旨在为多应用系统提供统一的身份认证服务。文中不仅涵盖了CAS的基本架构,还提供了具体的配置实例,帮助读者更好地理解和应用这一技术。 ... [详细]
  • 深入解析Spring Cloud微服务架构与分布式系统实战
    本文详细介绍了Spring Cloud在微服务架构和分布式系统中的应用,结合实际案例和最新技术,帮助读者全面掌握微服务的实现与优化。 ... [详细]
author-avatar
风尚宣城_588
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有