关于gradle:效率提升maven-转-gradle-实战-京东云技术团队

一、灵魂三问1、gradle 是什么?一个打包工具, 是一个开源构建自动化工具,足够灵便,能够构建简直任何类型的软件,高性能、可扩大、能洞察等。其中洞察,能够用于剖析构建过程中数据,提供剖析参考,不便排查问题和一直优化构建性能,以下一次编译剖析报告。 2、有什么劣势参考官网文章,针对蕴含10 子模块的工程,绝对 maven 构建速度,大略有 2-3 倍的性能晋升,增量编译大略 7 倍的性能晋升,参考官网 实测比照: gradle 耗时maven 耗时全新构建(clean 及下载依赖包)1m 35s1m58s全新构建(clean)43s60s增量构建14s43sgradle 执行命令: time gradle clean build package -x test mvn 执行的命令: time mvn clean package -Dmaven.test.skip=true -f $(pwd) -T 1C -Dmaven.artifact.threads=16 综述,通过多轮测试,在增量编译场景劣势比较突出均匀有 2 倍的性能晋升,工程模块越多效率晋升越大。 3、迁徙是否容易摸着心口说,并不容易,尽管官网提供了一键迁徙的工具,然而还是有肯定学习老本,但革新实现的确节俭了大把的工夫,尤其是改了一两行代码再次编译时。 二、动动手试试1、装置 gradle举荐应用 sdkman ,次要用于工具多版本治理的工具,如 java 、gradle 、maven 等能够依据理论状况装置应用其中某个一个版本,如jdk8,jdk11 等,版本间切换十分简便。 sdk 介绍: sdk install gradle 8.1.12、执行迁徙命令在以后 maven 工程下,执行如下的命令。 gradle init Found a Maven build. Generate a Gradle build from this? (default: yes) [yes, no] yesSelect build script DSL: 1: Groovy 2: KotlinEnter selection (default: Groovy) [1..2] 1Generate build using new APIs and behavior (some features may change in the next minor release)? (default: no) [yes, no] no不出意外下,会在默认子模块下增加 build.gradle 文件,如下图: ...

September 22, 2023 · 2 min · jiezi

关于gradle:IDEA-使用-gradle-乱码之谜

指标理解乱码的成因理解乱码的定位形式和解决办法 为什么须要编码呢?因为字符串是须要编码成字节数组作为载体的来存储和传输. 为什么会乱码?乱码产生的起因个别是因为编码转换出错. 字符串常见编码有GBK和UTF-8等. 如果一个字符串的编码和解码形式不一样, 就会呈现乱码. 例如是通过UTF-8编码的, 但通过GBK来解码, 就会变成上面的样子. 字节数组: [-28, -67, -96, -27, -91, -67]UTF-8解码后: 你好GBK解码后: 浣犲ソ 如果是通过GBK编码, 但通过UTF-8解码, 就会变成上面的样子.UTF-8解码后: ���GBK解码后: 你好 下面是常见的乱码, 能够记住乱码表现形式, 如果是相似的乱码, 就能够大略晓得是什么编码问题了. 如何模仿乱码如果让你写一个java程序, 模仿乱码的状况, 你会怎么写? java程序模仿乱码上面这么写会不会有问题, 在编辑器 (例如 IDEA) 外面的控制台看到的是 "浣犲ソ"吗? public static void main(String[] args) throws IOException { System.out.println(new String("你好".getBytes("UTF-8"), "GBK"));}答案是 不肯定. 程序编解码剖析你在控制台看到的字符串通过层层转换最终能力出现后果, 上面5局部都会对字符串的出现产生影响: .class 文件的编码getBytes("UTF-8") 进行转码获取对应编码的字节数组new String(,"GBK") 进行解码用于显示字符串System.out.println 编码后转成字节流写入控制台控制台读取字节流数据进行编码后出现在控制台下面 .class 文件的编码.class 编码默认是UTF-8的. 但 .java 不肯定. jdk编译器会把 .java 转成 .class. 意味着.java的编码和编译器程序的解码必须是统一的, (IDEA批改编译编码的形式在备注1)否则会呈现上面的状况, 尽管 .java外面显示的是 "你好", 但实际上变量的内容是 "浣犲ソ"! ...

January 31, 2023 · 2 min · jiezi

关于gradle:微服务开发系列为什么用-gradle-构建

构建在该微服务架构中,并没有应用常见的 maven 作为管理工具,而是应用了 gradle。 我在应用 maven 搭建这个架构实现了大部分的工作之后,决定全面转向 gradle,花了四天的工夫才全面相熟与替换。 总结一下这个我的项目中为什么应用 gradle,以及应用 gradle 须要恪守的规定。 1 maven 与 gradle两者相比拟思维是一样的,都是治理 jar 的依赖版本,定义了一个我的项目从编译到打包两头的各个阶段。 在应用下来之后发现,对于小型或者单个我的项目,应用 maven 与 gradle 实际上没有什么差异,甚至 小型我的项目 maven 更加不便一些,因为配置都是提前定义好的,不须要做过多的配置,就能间接应用,而 gradle 想要用起来配置略微麻烦一些。 然而对于多模块我的项目,两层甚至三层我的项目构造时,应用 gradle 相对是必须的,应用 maven 经常不能达到的目标,在 gradle 外面轻松就可能实现。 两者基本的区别是,maven 是配置型的,配置的设计依赖于配置的设计者是否留有批改的接口,gradle 是脚本型的,如何配置绝大部分取决于使用者如何设计。 一个主动权在 maven 插件作者,一个主动权在 gradle 的使用者。1.1 mavenmaven 的配置是固定的,不可批改的,只能基于配置上做定制化的革新,略微超出配置之外的操作,就要通过插件扩大来实现。 比如说我心愿打包的时候将 git sha1 作为版本号,你必须要装置一个 git-commit-id-plugin 插件。 在单层构造下没什么,齐全能够达到我应用的目标,两层构造也勉强够用,三层构造貌似也没什么问题。 然而当我应用心愿把一个我的项目提供给其它所有我的项目作为依赖时,问题就来了 \--- server +---framework +---gateway \---business +---business-foundation +---business-webframework 就是我将要提供给所有我的项目作为根本依赖。在这个需要外面,maven 有两个问题解决不了: git-commit-id-plugin 插件提供的变量 git.commit.id.abbrev 没法传递 dependency,像上面的形式,就无奈实现,因为插件在解决依赖时是不失效的,只有在编译打包的时候能力失效,因而变量也就无奈提供。 <dependency> <groupId>cn.server</groupId> <artifactId>framework</artifactId> <version>${git.commit.id.abbrev}</version> </dependency>maven 无奈解决我的项目之间的循环依赖,如果心愿各个我的项目不必本人手动援用 framework ,那么我就要在顶层去援用,然而 framework 也在这个框架之中,parent 曾经被指定顶层我的项目是 server,当然不指定 parent 是 server,可能很轻易的解决这个问题,然而在 parent 中的其它援用,都要在 framework 中被从新援用一遍,并且还不能设置 framework 的版本变量。这两个问题困扰了我十分久,直到应用 gradle 替换了之后。 ...

September 19, 2022 · 2 min · jiezi

关于gradle:gradle环境搭建

操作系统 - CentOS$ cat /etc/redhat-release CentOS Linux release 7.5.1804 (Core)what's needed?OpenJDKAndroid-SDKgradle装置Open JDK# 参考文档https://openjdk.java.net/install/# 官网装置阐明Fedora, Oracle Linux, Red Hat Enterprise Linux, etc.On the command line, type:$ su -c "yum install java-1.8.0-openjdk"The java-1.8.0-openjdk package contains just the Java Runtime Environment. If you want to develop Java programs then install the java-1.8.0-openjdk-devel package.# yum装置java# java-1.8.0-openjdk只是运行环境,java-1.8.0-openjdk-devel是开发环境yum -y install java-1.8.0-openjdk java-1.8.0-openjdk-devel# 获取JAVA_HOME$ which java/usr/lib/jvm/java-1.8.0-openjdk/bin/java# JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk# 配置环境变量export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk export PATH=$PATH:$JAVA_HOME/binexport CLASSPATH=.:$JAVA_HOME/jre/lib:$JAVA_HOME/lib:$JAVA_HOME/lib/tools.jar装置Android-SDK# 下载android sdk压缩包# 手动http://sdk.android-studio.org/ ,抉择你要的版本#主动 wget http://dl.google.com/android/android-sdk_r24.4.1-linux.tgz# 解压$ mkdir android-sdk$ mv android-sdk_r24.4.1-linux.tgz android-sdk/$ cd android-sdk && tar xzvf android-sdk_r24.4.1-linux.tgz# 配置环境变量export ANDROID_HOME=~/android-sdk/android-sdk-linuxexport PATH=$ANDROID_HOME/tools:$PATHexport PATH=$ANDROID_HOME/platform-tools:$PATH# 更新下载android组件# 更新全副android update sdk --no-ui# 抉择更新android list sdk --all #列出所有包和对应的序号android update sdk -u --all --filter 序号1,序号2...# 查看是否装置胜利adb装置gradle# 下载gradle压缩包# 手动 https://services.gradle.org/distributions/ ,抉择你要的版本# 主动wget https://services.gradle.org/distributions/gradle-6.5-bin.zip# 解压mkdir ~/local/gradlemv gradle-6.5-bin.zip ~/local/gradle/cd ~/local/gradle/ && unzip gradle-6.5-bin.zip# 配置环境变量export GRADLE_HOME=~/local/gradle/gradle-6.5export PATH=${JAVA_HOME}/bin:${JRE_HOME}/bin:${GRADLE_HOME}/bin:${JAVA_HOME}:${PATH}# 查看是否装置胜利gradle -v

February 9, 2022 · 1 min · jiezi

关于gradle:Gradle入门

Gradle是什么?一个开源的我的项目自动化构建工具,建设在Apache Anthe和Apache Maven概念的根底上,引入了基于Groovy的特定畛域语言(DSL),而不再应用XML模式治理构建脚本。 为什么须要我的项目自动化构建工具?对于大部分的软件开发者都会面临上面的问题: 开发人员都会应用IDE来进行编码,IDE帮用户实现了代码环境配置,编译代码,重构优化代码等性能。但因为不同开发人员应用的IDE版本不一样,可能会导致其他人在IDE中无奈胜利运行程序。在开发过程中,开发人员个别会调用很多现有的类库,这些类库不仅数量繁多,而且版本也千差万别。要想让程序正确执行,咱们必须要够引入适合的类库。在软件开发实现后,开发人员还要对软件进行一系列测试后能力让产品上线,然而须要测试的代码有许多,手动一个一个测试会重大影响产品迭代的效率。产品在公布之前,开发人员须要将代码进行打包,并上传到相应的云端。人为管制这个过程会很繁琐,同时也极易出错。对于上述的问题,咱们心愿能有一个工具帮咱们解决,于是我的项目自动化构建工具就应运而生了。 我的项目自动化构建工具的作用进行依赖治理自动化测试、打包、公布的过程Gradle的组织模式在Gradle构建中有两个根本的概念,别离为我的项目(project)和工作(task),每个构建至多蕴含一个我的项目,我的项目中蕴含一个或者多个工作。 我的项目(project)一个我的项目代表一个正在构建的组件(比方编译代码,将代码打包成一个jar文件),当构建启动后,Gradle会基于build.gradle实例化一个org.gradle.api.Project类,并且可能通过project变量使其隐式可用。 工作(task)对于之前提到的构建需要,咱们不难看出: 每个构建需要都须要实现特定的性能,比方在构建过程中须要管制类库的版本,对代码进行编译等。不同的构建需要之间有前后的依赖关系,比方测试过程必须是在代码编译后能力进行。于是,Gradle定义了工作(Task)来组织构建的过程。工作是指实现最小的工作单元,不同的工作通过构建一个有向无环图来示意工作之间的依赖,具体过程如下图: 我的项目实例整体介绍 对于一个我的项目来说,次要进行我的项目依赖管制的文件是"build.gradle"。这个文件在根目录下必须存在,用于对整个我的项目进行配置。对于子模块,如果须要进行自动化构建的话,那么对应的文件夹上面也须要蕴含build.gradle的文件。 创立工作Gradle中所有的工作都是通过task定义的,每个工作实现了一种性能,我定义的这个工作实现了创立文件夹的性能。同时,工作之间能够依赖,通过应用dependOn来依赖其余的工作。这个依赖表明须要在申明依赖的地位执行对应依赖的工作。 构建的生命周期次要蕴含三个阶段,别离为初始化,配置,执行。 初始化阶段初始化所有参加到构建中的我的项目。能够了解为这个阶段次要确定哪些模块须要参加到构建中(比方只有上图的model模块参加到构建中),哪些工作须要蕴含到构建中(工作能够定义多个,并不是所有工作都须要执行,所以须要确定参加到构建的工作)。 配置阶段生成task的依赖程序以及执行程序,依据配置代码来生成,在工作的定义中,除了动作代码(doFirst,doLast)以外的代码叫配置代码。 执行阶段执行动作代码。 在构建的过程中,gradle还提供了钩子代码,钩子代码是指在构建的每个阶段执行完结后能够插入的代码。比方我须要在初始化阶段后给用户提醒初始化实现,那么我能够在下图Hook的地位插入代码,输入肯定的提示信息。

August 9, 2021 · 1 min · jiezi

关于gradle:Gradle-GitHub-Actions-自动发布项目至-Maven-仓库

摘要文章内容外围是应用 Gradle 整合 GitHub Actions 自动化公布 Java 我的项目至 Maven 仓库。文章内是将我的项目公布至 sonatype 提供的仓库中。如果你须要自动化公布,或者须要将我的项目同步至 Maven 地方仓库请仔细阅读。 后期筹备可同步 Maven 地方仓库的门票,在 Issues Sonatype 上申请;OpenPGP 证书,须要同步至公共的服务器;一个 Java Project;GitHub。对于同步门票局部可参考提供的链接,文章内次要叙述证书相干的内容。 OpenPGP 证书因我应用的 Windows 操作系统这里应用 Gpg4win 工具生成同步证书。如果你应用的是 Mac 或者 Linux 操作系统可应用其它 GPG 工具如 GnuPG。 装置 Gpg4win下载地址 Gpg4win。 生成证书$ gpg --full-generate-key运行下面的命令依照批示生成 RSA 的证书。 C:\Users\admin>gpg --full-generate-keygpg (GnuPG) 2.2.23; Copyright (C) 2020 Free Software Foundation, Inc.This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law.... 省略局部 ...public and secret key created and signed.pub rsa3072 2020-11-10 [SC] [expires: 2021-11-10] 449B75F00B2DA482AB8D03E8493DA88E2B89E19Fuid kk70-blog (blog) <kevinz@weghst.com>sub rsa3072 2020-11-10 [E] [expires: 2021-11-10]浏览证书能够应用 gpg --list-secret-keys --keyid-format SHORT 命令查问证书列表。 ...

November 11, 2020 · 3 min · jiezi

关于gradle:Gradle系列之Android-Gradle插件

原文发于微信公众号 jzman-blog,欢送关注交换。通过后面几篇文章学习了 Gradle 基础知识以及 Gradle 插件相干的常识,对于 Gradle 及其插件相干常识请先浏览上面几篇文章: Gradle系列之初识GradleGradle之Groovy根底篇Gradle系列之构建脚本根底Gradle系列之意识Gradle工作Gradle系列之Gradle插件Gradle系列之Java Gradle插件学习 Gradle 的目标次要是为了更好的在 Android 开发中应用 Gradle,这篇文章的次要内容是 Android Gradle 插件的相干常识,次要内容如下: 理解 Android Gradle 插件Android Gradle 插件分类应用 Android Gradle 插件Android Gradle 工程目录Android Gradle 根本配置Android Gradle 工作理解 Android Gradle 插件顾名思义,Android Gradle 插件就是一个用于 Android 构建我的项目的一个 Gradle 插件,该插件有 Google Android 开发团队开发,而且 Android 开发 IDE Android Studio 就采纳 Gradle 构建我的项目,上面是 Android Gradle 插件的劣势: 不便重用代码和资源;可更不便的创立利用的衍生版本,如多渠道打包;配置不便。能够扩大,还能够自定义构建过程Android Studio 与 Gradle 深度交融Android Gradle 插件分类Android 插件的分类是依据 Android 工程的属性进行分类的,Android 工程分为三类,具体如下: ...

August 23, 2020 · 2 min · jiezi

关于gradle:Gradle系列之Java-Gradle插件

原文发于微信公众号 jzman-blog,欢送关注交换。上篇文章中理解了 Gradle 插件相干常识以及如何自定义一个 Gradle 插件,为不便了解能够先浏览上面几篇文章: Gradle系列之初识GradleGradle之Groovy根底篇Gradle系列之构建脚本根底Gradle系列之意识Gradle工作Gradle系列之Gradle插件本篇文章次要来学习 Java Gradle 插件相干的常识,因为 Java Gradle 插件相干的内容也是 Android Gradle 插件的根底。应用 Gradle 来构建我的项目无非就是帮忙开发者做一些重复性的工作,如配置第三方依赖、编译源文件、单元测试、打包公布等,应用相应的 Grade 插件可不便我的项目的构建以及肯定水平上进步开发效率,上面是明天学习的次要内容: Java Gradle 插件的应用Java 插件约定的我的项目构造配置第三方依赖如何构建 Java 我的项目SourceSet 源集概念Java 插件可增加的工作Java 插件可增加的属性多我的项目构建公布构件Java Gradle 插件的应用应用一个 Gradle 插件应用的是 Project 的 apply() 办法: //java是Java Gradle插件的plugin idapply plugin:'java'应用 Java 插件之后会为以后工程增加默认设置和约定,如源代码的地位、单元测试代码的地位、资源文件的地位等,个别应用默认设置即可。 Java 插件约定的我的项目构造Java 插件设置一些默认的设置和约定,上面来看一看 Java 我的项目的默认工程目录,目录构造根本如下: JavaGradle└─src ├─main │ ├─java │ └─resources └─test ├─java └─resources下面目录构造中,src/main/java 默认是源代码寄存目录,src/main/resources 是资源文件、配置文件等目录,arc/test 上面的目录当然是与其绝对应的单元测试相干文件的存储目录,main 和 test 是 Java Gradle 插件内置的两个源代码汇合,当然除此之外能够本人定义其余源代码汇合,定义形式如下: ...

August 23, 2020 · 2 min · jiezi

关于gradle:Gradle系列之认识Gradle任务

原文发于微信公众号 jzman-blog,欢送关注交换。后面几篇学习了 Gradle 构建工作的基础知识,理解了 Project 和 Task 这两个概念,倡议先浏览后面几篇文章: Gradle系列之初识GradleGradle之Groovy根底篇Gradle系列之构建脚本根底Gradle 的构建工作是有一系列的 Task 来实现的,本文将针对 Task 进行具体介绍,本文次要内容如下: 多种形式创立工作多种形式拜访工作工作分组和形容操作符工作的执行剖析工作排序工作的启用和禁用工作的onlyIf断言工作规定多种形式创立工作Gradle 中能够应用多种形式来创立工作,多种创立工作的形式最终反映在 Project 提供的快捷办法以及内置的 TaskContainer 提供的 create 办法,上面是几种常见的创立工作的形式: /** * 第一种创立工作形式: * 办法原型:Task task(String name) throws InvalidUserDataException; *///定义Task变量接管task()办法创立的Task,办法配置创立的Taskdef Task taskA = task(taskA)//配置创立的TasktaskA.doFirst { println "第一种创立工作的形式"}/**task * 第二种创立工作形式:可在Map参数中进行相干配置,如依赖、工作形容、组别等 * 办法原型:Task task(Map<String, ?> args, String name) throws InvalidUserDataException; */def Task taskB = task(group: BasePlugin.BUILD_GROUP,taskB,description: "形容")//配置创立的TasktaskB.doLast { println "第二种创立工作的形式" println "工作taskB分组:${taskB.group}" println "工作taskB形容:${taskB.description}"}/** * 第三种创立工作形式:通过闭包的形式创立Task,闭包里的委托对象就是Task,即可在闭包内调用Task * 的所有属性和办法来进行Task的配置 * 办法原型:Task task(String name, Closure configureClosure); */task taskC{ description 'taskC的形容' group BasePlugin.BUILD_GROUP doFirst{ println "第三种创立工作的形式" println "工作taskC分组:${group}" println "工作taskC形容:${description}" }}/** * 第四种创立工作的形式:可在闭包中灵便配置,也可在Map参数中配置,闭包中中的配置父笼罩Map中雷同的配置 * 办法原型:Task task(Map<String, ?> args, String name, Closure configureClosure); */def Task taskD = task(group: BasePlugin.BUILD_GROUP,taskD,description: "形容"){ description 'taskD的形容' group BasePlugin.UPLOAD_GROUP doFirst{ println "第四种创立工作的形式" println "工作taskD分组:${group}" println "工作taskD形容:${description}" }}下面是创立工作的四种形式,应用时抉择适合的创立形式即可,下面提到 Map 中能够配置 Task 的相干参数,上面是是 Map 中可应用的配置: ...

August 15, 2020 · 4 min · jiezi

buildgradle里dependencies标签页的实现原理

build.gradle里的dependencies标签页: 如果把dependencies改成dependencies2, gradle build的输入会遇到谬误音讯: A problem occurred evaluating root project 'quickstart'.Could not find method dependencies2() for arguments [build_a2307i03s3k13jdug3afl2lin$_run_closure3@21c69f73] on root project 'quickstart' of type org.gradle.api.Project. 找到这个org.gradle.api.Project类,位于目录orggradleapi上面: 关上Project.java, 查看对于dependencies的阐明: <p>A project generally has a number of dependencies it needs in order to do its work. Also, a project generallyproduces a number of artifacts, which other projects can use. Those dependencies are grouped in configurations, andcan be retrieved and uploaded from repositories. You use the {@link org.gradle.api.artifacts.ConfigurationContainer}returned by {@link #getConfigurations()} method to manage the configurations. The {@linkorg.gradle.api.artifacts.dsl.DependencyHandler} returned by {@link #getDependencies()} method to manage thedependencies. The {@link org.gradle.api.artifacts.dsl.ArtifactHandler} returned by {@link #getArtifacts()} method tomanage the artifacts. The {@link org.gradle.api.artifacts.dsl.RepositoryHandler} returned by {@linkgetRepositories()} method to manage the repositories.</p>Project是一个接口: ...

July 12, 2020 · 2 min · jiezi

buildgradle里repositories的mavenCentral实现原理解析

如果把build.gradle里的mavenCentral改成mavenCentral2会产生什么事? 谬误音讯:Could not find method mavenCentral2() for arguments [] on repository container of type org.gradle.api.internal.artifacts.dsl.DefaultRepositoryHandler. 这个DefaultRepositoryHandler,到Gradle目录下搜寻,找到了对应的Java文件: DEFAULT_MAVEN_CENTRAL_REPO_NAME常量的定义在下列文件里: DefaultBaseRepositoryFactory的createMavenCentralRepository办法内,创立Maven仓库,url为Repository.MAVEN_CENTRAL_URL: 这个常量定义在文件ArtifactRepositoryContainer.java里: String MAVEN_CENTRAL_URL = "https://repo.maven.apache.org/maven2/"; 浏览器里能够关上这个url,外面寄存着各种开发库: 因而build.gradle里下列这段配置信息,意思是通知Gradle从Maven地方仓库获取工具库的内容,即url https://repo.maven.apache.org... 要获取更多Jerry的原创文章,请关注公众号"汪子熙":

July 12, 2020 · 1 min · jiezi

Gradle-依赖关系中-compile和-implementation的区别

将在一个项目中展示implementation,api以及compile之间的差异。 假设我有一个包含三个Gradle模块的项目: app(Android应用)my-android-library(Android库)my-java-library(Java库)app具有my-android-library与依赖。my-android-library具有my-java-library依赖。 依赖1my-java-library有一个MySecret班 public class MySecret { public static String getSecret() { return "Money"; }}my-android-library 拥有一个类 MyAndroidComponent,里面有调用 MySecret 类的值。 public class MyAndroidComponent { private static String component = MySecret.getSecret(); public static String getComponent() { return "My component: " + component; } }最后,app 只对来自 my-android-library TextView tvHelloWorld = findViewById(R.id.tv_hello_world);tvHelloWorld.setText(MyAndroidComponent.getComponent());现在,让我们谈谈依赖性... app需要:my-android-library库,所以在app build.gradle文件中使用implementation。 (注意:您也可以使用api/compile, 但是请稍等片刻。) dependencies { implementation project(':my-android-library') }依赖2您认为 my-android-library 的 build.gradle应该是什么样?我们应该使用哪个范围? 我们有三种选择: dependencies { // 选择 #1 implementation project(':my-java-library') // 选择 #2 compile project(':my-java-library') // 选择 #3 api project(':my-java-library') }依赖3它们之间有什么区别,我应该使用什么? ...

October 17, 2019 · 1 min · jiezi

Gradle构建SpringBoot程序依赖管理之依赖版本自动控制

前言:Spring体系中很多库之间相互依赖,但是由于版本之间差异比较大,我们需要比较精确的知道每个库的版本对应关系,不然很容易造成“库”与“库”之间对应不上,导致部分功能无效,甚至是异常情况。程序员排查起来一个头两个大,本篇文章将介绍如何利用gradle的插件来实现版本自动管理机制1、依赖管理SpringBoot构建系统文档 1、每个SpringBoot版本都提供了他能支持的依赖清单, 所以开发中我们不需要在配置文件中指定版本,SpringBoot会自动帮我们管理这些依赖,当我们升级SpringBoot的时候,SpringBoot所支持的依赖清单也会自动升级2、我们在用SpringBoot管理依赖的时候,可以自定义版本号覆盖SpringBoot本身依赖的版本3、springBoot支持的依赖清单包括Spring所有模块以及Springboot依赖的第三方库4、每个发布的SpringBoot版本都与一个基础版本的SpringFramework有关联,官方是不建议指定版本的上述的官方文档关于依赖管理的描述,总结下来就是:在SpringBoot开发中,如果使用了依赖管理,那么Spring所有模块和SpringBoot依赖的第三方库我们不需要指定版本号 关于SpringBoot依赖的第三库在上述链接文档的这个部分(点击POM即可查看): ⚠️:此处提供 SpringBoot 2.1.6 依赖的三方库,其他版本自行找到指定版本的文档查看2、gradle自动依赖本文重点讲解gradle如何配置自动依赖,关于maven配置 点击这里查看gradle配置点击这里 文档中描述:如果你想使用依赖关系管理,那么你需要保证你的gradle的版本大于4.4 我们通过实战方式,针对gradle配置自动依赖管理进行说明。 3、实战build.gradle配置 方式一: 将SpringBoot插件应用于项目,依赖的插件将依赖清单加载到项目中,详细见配置中描述(建议直接使用此配置) plugins { //id 'java' //springboot插件,加入版本,那么Spring相关依赖,则自动加入(当使用其他插件的时候,还会自动加载插件所带的任务) id 'org.springframework.boot' version '2.1.6.RELEASE' //第一种引入方式:写在此处,需要手动设置依赖管理的版本,否则无法执行(手动指定版本,好处是插件集中管理在plugins里面)// id 'io.spring.dependency-management' version '1.0.8.RELEASE'}apply plugin: 'java'//第二种引入方式:应用依赖管理插件,自动给插件追加版本号(建议使用此配置)apply plugin: 'io.spring.dependency-management'sourceCompatibility = 1.8repositories { mavenLocal() maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'}}//设置commons-pool2版本为'2.6.1',Spring依赖的是2.6.2ext['commons-pool2.version'] = '2.6.1'dependencies { //Spring模块 compile("org.springframework.boot:spring-boot-starter-web") //Spring依赖的第三方模块(2.1.6依赖的是3.8.1) compile("org.apache.commons:commons-lang3") //Spring依赖的第三方模块(2.1.6依赖的是2.6.2)指定依赖版本为2.6.1 compile('org.apache.commons:commons-pool2') //未被依赖的库需要手动:我司开源的 轻代码开发框架核心包,文末源码链接 compile('com.diboot:diboot-core:2.0.0')}方式二:如果你仅仅是为了要依赖管理,而不需要插件的功能,你可以使用SpringBootPlugin提供的BOM_COORDINATES来进行依赖管理控制也可以达到效果 plugins { //依赖springboot插件,但是不应用 id 'org.springframework.boot' version '2.1.6.RELEASE' apply false}apply plugin: 'java'apply plugin: 'io.spring.dependency-management'//使用SpringBootPlugin提供的依赖插件dependencyManagement { imports { mavenBom org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES }}sourceCompatibility = 1.8repositories { mavenLocal() maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'}}//设置commons-pool2版本为'2.6.1',Spring依赖的是2.6.2ext['commons-pool2.version'] = '2.6.1'dependencies { //Spring模块 compile("org.springframework.boot:spring-boot-starter-web") //Spring依赖的第三方模块(2.1.6依赖的是3.8.1) compile("org.apache.commons:commons-lang3") //Spring依赖的第三方模块(2.1.6依赖的是2.6.2)指定依赖版本为2.6.1 compile('org.apache.commons:commons-pool2') //未被依赖的库需要手动:我司开源的 轻代码开发框架核心包,文末源码链接 compile('com.diboot:diboot-core:2.0.0')}4、总结Spring相关模块,以及SpringBoot依赖的库可以通过依赖管理,自动获取最适合的库版本未加入SpringBoot依赖清单的库,版本号不可省略,需要手动设置版本版本依赖管理是开发中基础环节,使用版本管理有效减少版本依赖的校对,可以提高开发效率diboot 简单高效的轻代码开发框架 ...

June 30, 2019 · 1 min · jiezi

Docker-Jenkins-Gradle-http代理设置

公司为了省钱,除了一台服务器能够上网之外,其余的都是内网服务器,我把jenkins装在内网服务器下,用Dockder来搭建的,所以就出现题目的问题。怎么设置Docker jenkins容器下的gradle http代理,让gradle能下外网的依赖包。一、宿主机创建gradle.properties文件vim ./gradle.properties文件配置http代理信息 systemProp.http.proxyPort=8888systemProp.http.proxyHost=172.111.111.111systemProp.https.proxyPort=8888systemProp.https.proxyHost=172.111.111.111二、将配置文件copy到容器#暂且放到容器的/home/目录下吧docker cp ./gradle.properties jenkins:/home三、进入Jenkins容器#通过docker命令进入容器docker exec -it jenkins bash#进入容器后创建在用户目录创建「.gradle」目录mkdir ~/.gralde#把放在/home/目录的配置文件移动到~/.gralde目录mv /home/gradle.properties ~/.gradle四、完成可以去jenkins网页上试试重新build

June 28, 2019 · 1 min · jiezi

Gradle环境下导出Swagger为PDF

更多精彩博文,欢迎访问我的个人博客 说明我个人是一直使用Swagger作为接口文档的说明的。但是由于在一些情况下,接口文档说明需要以文件的形式交付出去,如果再重新写一份文档难免有些麻烦。于是在网上看到了Swagger2Markup + asciidoctor导出PDF的方法,百度一番后感觉网上的文章还是有很多没有描述清楚的地方,遂还是硬着头皮把官方的英文文档大致浏览了一下,按照自己的思路整理出具体的步骤。 本文用到的工具: Gradle - 4.10.3SpringBoot - 2.1.6.RELEASESwagger - 2.9.2Swagger2Markup - 1.3.3asciidoctorspring-restdocs-mockmvc准备Swagger数据SpringBoot中使用Swagger的过程就不再赘述了,下面是本文使用的范例: @Configuration@EnableSwagger2class SwaggerConfig { @Bean public Docket createRestApi() { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.basePackage("com.jptangchina.gradle.controller")) .paths(PathSelectors.any()) .build(); } private ApiInfo apiInfo() { return new ApiInfoBuilder() .title("Swagger2Markup Test Api") .version("1.0") .build(); }}@RestController@RequestMapping("/user")@Api(tags = "用户接口")public class UserController { @ApiOperation("用户登录") @ResponseBody @PostMapping("/login") public Result<Void> login( @ApiParam(value = "用户名", example = "jptangchina", required = true) @RequestParam String username, @ApiParam(value = "密码", example = "jptangchina", required = true) @RequestParam String password) { return Result.ok(); }}使用org.asciidoctor.convert生成PDF(个人不推荐使用)官方教程地址:https://github.com/Swagger2Ma...仅为了简单的导出PDF而言,本文针对官方案例均有所改动,去掉了部分没有用到的配置。 ...

June 25, 2019 · 3 min · jiezi

Gradle项目引入Lombok

接前面一篇文章 《Lombok常用注解的使用总结》 这里主要讲解,如何在Gradle项目中引入Lombok依赖。 以上,Lombok官网提供了两种方式: Lombok Gradle插件添加Lombok依赖我们使用第二种方式,先对Gradle的两个内置作用域做简单说明: compileOnly:只编译时有效,不参与打包。代替旧版本的provided annotationProcessor:管理注解处理器,并将其添加到处理器类路径中重点来了,是否所有Gradle版本都支持官网这种写法呢? 答案是否定的。 Gradle 5.0及以上版本:annotationProcessor 'org.projectlombok:lombok:1.18.8'Gradle 5.0版本以下:compileOnly 'org.projectlombok:lombok:1.18.8'Diboot - 简单高效的轻代码开发框架

June 25, 2019 · 1 min · jiezi

Android动态改变工程依赖

在app/build.gradle有如下库依赖: dependencies { compile "com.xxx.yyy:somelib:$version"}现在如果要改成源码依赖(工程依赖)需要改2处地方:app/build.gradle: dependencies { compile project(':somelib')}settings.gradle: include ':somelib'project(":somelib").projectDir = new File("/lib/dir", "/some/path/somelib")现在依赖的库非常多, 而且还存在依赖嵌套, 希望只改一处配置就能够切换库依赖与源码依赖 显然用库依赖settings.gradle里不需要include那坨语句, 那么必然需要在settings.gradle里定义一个变量来作条件判断, 这里需要解决的一个核心问题是app/build.gradle能够访问到settings.gradle里的这个变量来继续来作compile "com.xxx.yyy:somelib:$version"还是compile project(':somelib')的判断, 也就是需要一个全局可访问的gradle变量 网上搜索了一圈竟然没找到! 研究了一下发现以下重要2点: settings.gradle对象生成早于app/build.gradle甚至早于根目录的build.gradle, 所以在build.gradle里声明ext { someVar=xxx }变量无效, settings无法访问app/build.gradle上下文依赖的project对象与settings.gradle共享同一个gradle对象于是有如下配置:settings.gradle: def module_config = [ 'somelib': '', 'aaa': '1.0.0', 'bbb': '0.2.0', 'ccc': '0.0.3',]module_config.each { k, v -> if (!v) { include ":${k}" project(":${k}").projectDir = new File(rootDir.getParent(), "/some/path/${k}") }}gradle.ext.dependon = { project, name -> def ver = module_config[name] def handler = project.dependencies if (!ver) { handler.compile project.project(":$name") } else { handler.compile "com.xxx.yyy:$name:$ver" }}这里用gradle.ext定义了一个全局的方法而不是一个变量, 这样在引用的时候直接调用:app/build.gradle: ...

June 11, 2019 · 1 min · jiezi

Android-Gradle系列进阶篇

上篇文章我们已经将Gradle基础运用介绍了一遍,可以这么说,只要你一直看了我这个Gradle系列,那么你的Gradle也将过关了,应对正常的工作开发已经不成问题了。 这篇文章我要向你介绍的是关于如何使用Gradle来更加优雅的管理多个module之间的依赖关系。 相信你一定有这样的经历:主项目依赖于多个子项目,或者项目间互相依赖。不同子项目间的依赖的第三方库版本又没有进行统一,升级一个版本所有依赖的项目都要进行修改;甚至minSdkVersion与targetSdkVersion也不相同。 今天我们就来解决这个问题,让Gradle版本管理更加优雅。 Google推荐之前的文章Android Gradle系列-运用篇中的dependencies使用的是最基本的引用方式。如果你有新建一个kotlin项目的经历,那么你将看到Google推荐的方案 buildscript { ext.kotlin_version = '1.1.51' repositories { google() jcenter() } dependencies { classpath 'com.android.tools.build:gradle:3.0.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" }}在rootProject的build.gradle中使用ext来定义版本号全局变量。这样我们就可以在module的build.gradle中直接引用这些定义的变量。引用方式如下: dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation"org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"}你可以将这些变量理解为java的静态变量。通过这种方式能够达到不同module中的配置统一,但局限性是,一但配置项过多,所有的配置都将写到rootProject项目的build.gradle中,导致build.gradle臃肿。这不符合我们的所提倡的模块开发,所以应该想办法将ext的配置单独分离出来。 这个时候我就要用到之前的文章Android Gradle系列-原理篇中所介绍的apply函数。之前的文章我们只使用了apply三种情况之一的plugin(应用一个插件,通过id或者class名),只使用在子项目的build.gradle中。 apply plugin: 'com.android.application'这次我们需要使用它的from,它主要是的作用是应用一个脚本文件。作用接下来我们需要做的是将ext配置单独放到一个gradle脚本文件中。 首先我们在rootProject目录下创建一个gradle脚本文件,我这里取名为version.gradle。 然后我们在version.gralde文件中使用ext来定义变量。例如之前的kotlin版本号就可以使用如下方式实现 ext.deps = [:] def versions = [:]versions.support = "26.1.0"versions.kotlin = "1.2.51"versions.gradle = '3.2.1' def support = [:]support.app_compat = "com.android.support:appcompat-v7:$versions.support"support.recyclerview = "com.android.support:recyclerview-v7:$versions.support"deps.support = support def kotlin = [:]kotlin.kotlin_stdlib = "org.jetbrains.kotlin:kotlin-stdlib-jre7:$versions.kotlin"kotlin.plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:$versions.kotlin"deps.kotlin = kotlin deps.gradle_plugin = "com.android.tools.build:gradle:$versions.gradle" ext.deps = deps def build_versions = [:]build_versions.target_sdk = 26build_versions.min_sdk = 16build_versions.build_tools = "28.0.3"ext.build_versions = build_versions def addRepos(RepositoryHandler handler) { handler.google() handler.jcenter() handler.maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }}ext.addRepos = this.&addRepos因为gradle使用的是groovy语言,所以以上都是groovy语法例如kotlin版本控制,上面代码的意思就是将有个kotlin相关的版本依赖放到deps的kotlin变量中,同时deps放到了ext中。其它的亦是如此。 ...

June 10, 2019 · 2 min · jiezi

Gradle系列运用篇

上次我们说到gradle的原理,主要是偏理论上的知识点,直通车在这Android Gradle系列-原理篇。这次我们来点实战的,随便巩固下之前的知识点。 android在app module下的gradle.build中都有一个android闭包,主要配置都在这里设置。例如默认配置项:defaultConfig;签名相关:signingConfig;构建变体:buildTypes;产品风格:productFlavors;源集配置:sourceSets等。 defaultConfig对于defaultConfig其实它是也一个productFlavor,只不过这里是用来提供默认的设置项,如果之后的productFlavor没有特殊指定的配置都会使用defaultConfig中的默认配置。 public class DefaultConfig extends BaseFlavor { @Inject public DefaultConfig( @NonNull String name, @NonNull Project project, @NonNull ObjectFactory objectFactory, @NonNull DeprecationReporter deprecationReporter, @NonNull Logger logger) { super(name, project, objectFactory, deprecationReporter, logger); }} public abstract class BaseFlavor extends DefaultProductFlavor implements CoreProductFlavor { ...}可以看到defaultConfig的超级父类就是DefaultProductFlavor。而在DefaultProductFlavor中定义了许多我们经常见到的配置:VersionCode、VersionName、minSdkVersion、targetSdkVersion与applicationId等等。 有了上面的基础,那么在defaultConfig中我们要配置的变量就显而易见了。 defaultConfig { applicationId "com.idisfkj.androidapianalysis" minSdkVersion 16 targetSdkVersion 26 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" }signingConfigssigningConfig是用来配置keyStore,我们可以针对不同的版本配置不同的keyStore,例如 signingConfigs { config { //默认配置 storeFile file('key.store') storePassword 'android123' keyAlias 'android' keyPassword 'android123' } dev { //dev测试版配置 storeFile file('xxxx') storePassword 'xxx' keyAlias 'xxx' keyPassword 'xxx' } }有人可能会说这不安全的,密码都是明文,都暴露出去了。是的,如果这项目发布到远程,那么这些秘钥就泄露出去了。所以为了安全起见,我们可以对其进一些特殊处理。 ...

May 30, 2019 · 3 min · jiezi

gradle多模块打jar上传本地仓库并给本地其他项目使用

1、前言本篇主要讲述:gradle多模块打jar包,上传本地仓库,并交由本地其他项目使用2、环境准备操作系统: mac osgradle版本:4.1.0开发软件:idea注:gradle版本不同,引入依赖方式可能不同,如果你发现本地导包是OK的,但是打包就报错,可以看看是不是gradle版本所引起的问题3、多模块gradle文档【gradle多环境讲解,官方文档】,官方文档描述了多模块配置中的几个闭包的常规使用allprojects{}, subprojects{}。前者配置应用包括root模块在内的所有模块,后者只应用子模块,详细的使用规则进入官方文档详细了解 4、项目实战项目1结构 |──root-project-one 项目1名称 ├── common-project 基础子项目 │ └── build.gradle 基础子项目配置文件 ├── example-project 依赖common项目的示例项目 │ └── build.gradle 依赖common项目的示例项目的配置文件 ├── build.gradle 项目1的配置文件项目2结构 |──root-project-two 项目2名称 ├── build.gradle 项目2的配置文件(需要引用项目1中的example-project)各个项目的配置文件(此处只列举主要配置) root-project-one/build.gradle //所有子项目共享配置subprojects { apply plugin: 'maven' // 获取本地仓库路径 def localRepositoryPath = 'file://' + new File(System.getProperty('user.home'), '.m2/repository').absolutePath //打包至本地仓库配置 uploadArchives { repositories { //mavenDeployer 需要依赖 apply plugin: 'maven' mavenDeployer { repository(url: localRepositoryPath) pom.project { name = project.name // 当前项目名称 version = project.version //当前项目版本 0.0.1 groupId = project.group // 当前项目组 com.xxx } } } }}common-project/build.gradle ...

May 18, 2019 · 1 min · jiezi

Android-Gradle系列入门篇

接下来的一段时间会对Android Gradle的相关知识进行梳理,所以借此整理成一个系列。如果你是刚入行的新秀,那么这个系列将会非常适合你,因为Android基本的配置都与Gradle有关。当然如果你已经入行,但对Gradle还是停留在表面的认知上,这个系列也会对你有所帮助。 这篇文章定义为入门篇,将结合自己刚开始学习Android时的疑惑与现在对Gradle的认识,进一步整理Gradle在Android中的整体结构。 思考当我使用Android Studio时,一直有几个疑问围绕着我: Android Studio是怎样将Java与Kotlin代码的编译成APK文件?Gradle是怎样将Java与Kotlin代码编译成APK文件?后来知道Android Studio自身是不能够编译成APK的,它是集成了Gradle。通过研究Gradle,发现Gradle也只是一个构建工具,真正编译成APK的功能是由Android app plugins提供的。Gradle只是自动化构建工具,提供构建时的各种生命周期,例如:building、testing、publishing等。所以Gradle不仅支持Android还支持C/C++、Scale等。 而这个plugin其实就是在project中的build.gradle中声明的classpath buildscript { repositories { // Gradle 4.1 and higher include support for Google's Maven repo using // the google() method. And you need to include this repo to download // Android Gradle plugin 3.0.0 or higher. google() ... } dependencies { classpath 'com.android.tools.build:gradle:3.4.0' }}所有每次对Android构建进行了优化,我们都要来更新这个版本。 Scripts有了上面的基础,当我们新建一个Android项目时,你将会看到如下与Gradle相关的文件: 你会看到文件名几乎都有gradle字段,下面我会一一介绍它们的作用 Gradle Wrapper首先是gradle-wrapper.properties文件,打开它你将会看到如下类似信息 #Sat Jan 19 08:25:46 CST 2019distributionBase=GRADLE_USER_HOMEdistributionPath=wrapper/distszipStoreBase=GRADLE_USER_HOMEzipStorePath=wrapper/distsdistributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip这个是gradle版本的配置项,申明你当前项目中使用的gradle版本。当我们构建项目的时候,它会根据版本自动下载。并且保存到你的电脑本地中。如果你使用的是Mac,你可以使用如下命令查看你的所有已经下载的gradle版本。 ...

May 7, 2019 · 1 min · jiezi

Homebrew 安装指定版本软件

查看软件信息使用brew info [options] [formula]查看软件信息关键信息:From: https://github.com/Homebrew/homebrew-core/blob/master/Formula/gradle.rb2. 修改源信息从https://github.com/Homebrew/homebrew-core/blob/master/Formula/gradle.rb下载文件修改url “https://services.gradle.org/distributions/gradle-4.0-all.zip", 将版本信息修改为url “https://services.gradle.org/distributions/gradle-3.-all.zip"3. 取消当前版本关联执行brew unlink gradle4. 安装修改过的源在修改过的gradle.rb目录下,执行brew install gradle.rb,此时报错:将gradle.rb 里的sha256参数,改为a0af75d3d35799a90f56255a24de69c53cd9aea90f0b532586c8f818668e1734 ,Actual: a0af75d3d35799a90f56255a24de69c53cd9aea90f0b532586c8f818668e17344. 切换版本执行brew switch gradle 3.1进行版本切换执行brew info gradle 查看当前版本。后缀带有*号,表明当前版本。

April 15, 2019 · 1 min · jiezi

提升效率——自动打包上传蒲公英

时间是最宝贵的财富,我们的时间得用在刀刃上。在文章 使用 Gradle 对应用进行个性化定制 中,我们能够针对一个应用的正式服、测试服、超管服等其他版本,进行个性化定制。所以经常会有测试跑过来说,帮我打个测试服的包吧、帮我打个正式服的包吧、帮我打个超管服的包吧。我打你一脸包????????????。我们的目标是一行命令完成:自动编译 apk 上传到蒲公英上传完成后输出二维码地址和版本号支持多环境包上传自动上传蒲公英直接使用蒲公英的上传 API ,在 Gradle 中封装如下方法:private def uploadPGY(String filePath) { def stdout = new ByteArrayOutputStream() exec { executable = ‘curl’ args = [’-F’, “file=@${filePath}”, ‘-F’, “_api_key=${rootProject.ext.pgy[“apiKey”]}”, rootProject.ext.pgy[“uploadUrl”]] standardOutput = stdout } String output = stdout.toString() def parsedJson = new groovy.json.JsonSlurper().parseText(output) println parsedJson.data.buildQRCodeURL println “版本号:” + parsedJson.data.buildVersion}好了,执行以上方法就可以实现我们上面的两个目标啦。看不懂的我们继续,包教包会。curl 是一种命令行工具,作用是发出网络请求,然后得到和提取数据,显示在"标准输出"(stdout)上面。我们使用 curl 命令来调用蒲公英的接口上传 apk 文件。将蒲公英的 apiKey 和 uploadUrl 放在 config.gradle 中进行统一的管理。ext{ pgy = [apiKey : “xxxxxxxxxxx”, uploadUrl: “https://www.pgyer.com/apiv2/app/upload”]}stdout 变量是用来获取网络请求返回的数据流,我们解析成 JSON 对象后打印出二维码地址和版本号信息。如果你还想上传或者输出更多信息请查看蒲公英的上传 API 。这个时候大家要问了,apk 的文件路径从哪来呢?实现不同环境包上传我们有正式环境、测试环境和超管环境,并且每个环境生成的 apk 文件名也不同,那么我们怎么获取到 apk 文件的路径呢?统一文件命名规则在config.gradle 中增加版本信息ext{ pgy = [apiKey : “xxxxxxxxxxx”, uploadUrl: “https://www.pgyer.com/apiv2/app/upload” ] android = [compileSdkVersion: 28, buildToolsVersion: “28.0.3”, minSdkVersion : 16, targetSdkVersion : 28, versionCode : 1, versionName : “1.0.0” ]}在根目录的 build.gradle 中增加获取 getApkName 方法def getTestVersionName(String suffix) { def testVersion = “001” if (suffix == null || suffix.isEmpty()) { return String.format("%s.%s", rootProject.ext.android[“versionName”], testVersion) } else { return String.format("%s.%s.%s", rootProject.ext.android[“versionName”], testVersion, suffix) }}def getApkName(String versionName) { return String.format(“我是一个包-v%s.apk”, versionName)}在 application 工程的 build.gradle 中修改 apk 文件名productFlavors { offline { buildConfigField “String”, “DOMAIN_NAME”, “"https://offline.domain.com/"” versionName getTestVersionName(“offline”) //修改 versionName } online { buildConfigField “String”, “DOMAIN_NAME”, “"https://online.domain.com/"” versionName rootProject.ext.android[“versionName”] } admin { buildConfigField “String”, “DOMAIN_NAME”, “"https://admin.domain.com/"” versionName versionName getTestVersionName(“管理员”) //修改 versionName }}android.applicationVariants.all { variant -> variant.outputs.all { outputFileName = getApkName(variant.versionName) }}实现多环境上传def offlineFile = “${projectDir.absolutePath}/build/outputs/apk/offline/release/${getApkName(getTestVersionName(“offline”))}“def adminFile = “${projectDir.absolutePath}/build/outputs/apk/admin/release/${getApkName(getTestVersionName(“管理员”))}“def onlineFile = “${projectDir.absolutePath}/build/outputs/apk/online/release/${getApkName(rootProject.ext.android[“versionName”])}”/** * 执行 “uploadOfflineApk” 命令自动打测试服包,并上传到蒲公英 /task uploadOfflineApk(dependsOn: ‘assembleOfflineRelease’) { group = “publish” doLast { uploadPGY(offlineFile) }}/* * 执行 “uploadOnlineApk” 命令自动打正式服包,并上传到蒲公英 /task uploadOnlineApk(dependsOn: ‘assembleOnlineRelease’) { group = “publish” doLast { uploadPGY(onlineFile) }}/* * 执行 “uploadAdminApk” 命令自动打超管服包,并上传到蒲公英 */task uploadAdminApk(dependsOn: ‘assembleAdminRelease’) { group = “publish” doLast { uploadPGY(adminFile) }}一行命令打3个包上传:./gradlew uploadOfflineApk uploadOnlineApk uploadAdminApk下篇预告我们的超管包是需要发给运营人员去使用的,防止泄露导致的安全风险,我们希望对超管包先进行加固然后再上传到蒲公英。相关阅读使用 Gradle 对应用进行个性化定制使用 Gradle 实现一套代码开发多个应用欢迎关注微信公众号:大脑好饿,更多干货等你来尝 ...

March 18, 2019 · 2 min · jiezi

使用Gradle做Java代码质量检查

Maven –> Gradle首先安装gradle:Mac安装brew install gradle Ubuntu安装apt install gradleMaven项目切换Gradle项目,再Maven根目录下运行:gradle init –type pom运行成功之后运行命令gradle build,成功之后删除pom.xml即可。使用jacoco分析单元测试jacoco是一个分析单元测试覆盖率的工具,使用它运行单元测试后,可以给出代码中那些部分被单元测试到,哪些部分没有被单元测试覆盖,并且还会给出整个项目的单元测试覆盖情况。在build.gradle中添加jacoco插件apply plugin: ‘jacoco’运行命令进行单元测试分析gradle jacocoTestReport或者可以再Gradle的工具菜单中Tasks -> other -> jacocoTsestReport可以直接启动单元测试的分析。在项目中build目录下可以看到jacoco目录,以及reports/test/html目录,后者主要是jacoco生成的报告。使用SonarQube做代码质量检查SonarQube是一个开源的代码质量管理系统,支持超过25种编程语言,提供重复代码、编码标准、单元测试、单元测试覆盖率,代码复杂度,潜在Bug、注释和软件设计的报告等。在gradle中使用SonarQube首先要添加依赖,在编译脚本中添加:buildscript { repositories { maven { url “https://plugins.gradle.org/m2/" } } dependencies { classpath(“org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.6-rc1”) classpath(“org.springframework.boot:spring-boot-gradle-plugin:2.0.5.RELEASE”) }}添加插件:apply plugin: “org.sonarqube"配置SonarQube:sonarqube { properties { property “sonar.sourceEncoding”, “UTF-8” property “sonar.host.url”, “https://sonarcloud.io” property “sonar.jdbc.url”, “jdbc:mysql://my.server.com/sonar” property “sonar.jdbc.driverClassName”, “com.mysql.jdbc.Driver” property “sonar.login”, “test” property “sonar.password”, “test” }}或者只使用token上传分析结果即可:property “sonar.login”, “token"SonarQube本身并没有提供单元测试覆盖率的工具,需要在使用jacoco的分析结果,在SonarQube中添加jacoco相关的配置sonarqube { properties { property “sonar.jacoco.reportPath”, “$rootDir/build/jacoco/test.exec” property “sonar.jacoco.itReportPath”, “$rootDir/build/jacoco/acceptanceTest.exec” property “sonar.jacoco.excludes”, “/st/” property “sonar.sourceEncoding”, “UTF-8” property “sonar.host.url”, “https://sonarcloud.io” property “sonar.jdbc.url”, “jdbc:mysql://my.server.com/sonar” property “sonar.jdbc.driverClassName”, “com.mysql.jdbc.Driver” property “sonar.login”, “test” property “sonar.password”, “test” }}运行命令gradle sonarqube即可对代码进行分析,并上传分析结果,因为SonarQube的分析依赖jacoco的单元测试分析,所以需要先运行命令gradle jacocoTestReport。最终需要运行的组合命令是:gradle jacocoTestReportgradle sonarqube ...

March 17, 2019 · 1 min · jiezi

Gradle原型模板工具调研

为了方便小组里的同学快速创建新项目,并且保持框架及配置的一致性,维护了模板工程。接下来需要一个好用的工具来快速生成新项目。模板工程基于Gradle,用不了Maven Archetype,需要另外找。工具需要满足的条件模板工程需要更新,能直接跑单元测试,所以工具不能限制工程结构,不能让模板工程来适应这个工具模板工程放在公司内网,所以工具不能强制要求模板上传到工具自建的公网仓库网上找了一些工具,目前找到的不太符合要求gradle-archetype-plugin:不符合条件1yeoman:不符合条件2后来自建了一段小脚本及操作规范来解决这个问题模板工程:1)包名唯一标识使用prjName,可定制,2)需要配置的地方注释里加上标记[config],可定制执行自建的 dup_architype.sh 创建新项目在IDE打开新项目,搜索[config]找到所有需要手动修改配置的地方,根据注释及上下文做出修改dup_architype.sh 的大致执行流程:把模板工程拷贝到指定的新项目所在路径,排除掉不需要的目录重命名prjName这个唯一标识为自定义的业务名称替换项目文件中的prjName为自定义的业务名称dup_architype.sh 内容:# template project absolute pathSRC=/Users/sandynz/Documents/projects/boottemp/# target project absolute pathTARGET=/Users/sandynz/Documents/projects/prj1# target project package namePKGNAME=prj1# copyecho ‘start copy’rsync -avz –exclude out –exclude build –exclude target –exclude .git –exclude .gradle –exclude .idea $SRC $TARGET# rename direcho ‘start rename dir’find $TARGET -name prjName -execdir mv {} $PKGNAME ‘;’# replace contentecho ‘start replace content’find $TARGET -type f -exec sed -i ’’ “s/prjName/$PKGNAME/g” {} ;该脚本里的 SRC/TARGET/PKGNAME 都需要在执行之前修改。含义如下:SRC : 模板工程绝对路径TARGET : 目标项目绝对路径PKGNAME : 目标项目唯一标识,用于包名,不包含com.xyz.这样的前缀脚本预设工程使用 Gradle/Git/IntellijIDEA,不需要复制的目录已经在rsync参数排除掉;其它需要排除的目录可以添加–exclude自行排除包名中的唯一标识是prjName(整体包名com.xyz.prjName),可自行定制实际使用下来还算方便,简单有效。 ...

March 16, 2019 · 1 min · jiezi

gradle-学习笔记(2)-多项目构建

记得在maven中支持多个子项目的构建方法,同样的在gradle 中也会支持多项目的构建方法还记得在maven中如何配置多项目工程吗, 这里回忆一下首先我们需要一个父元素pom文件比如这样<?xml version=“1.0” encoding=“UTF-8”?><project xmlns=“http://maven.apache.org/POM/4.0.0" xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=“http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.kyssion</groupId> <artifactId>maven-demo</artifactId> <version>1.0-SNAPSHOT</version> <packaging>pom</packaging></project>而在gradle中,我们并不需要指定父元素的标签,我们只需要编写好对应的文件夹名称,并且将文件夹名称和对应的目录结构对应清,gradle 就能自动的识别这个子项目比如我创建这样一个子项目名称是greeting-library子项目中的配置未见build.gradleplugins { id ‘groovy’}group ‘com.kyssion’version ‘1.0-SNAPSHOT’repositories { mavenCentral()}dependencies { compile ‘org.codehaus.groovy:groovy-all:2.5.6’ testCompile group: ‘junit’, name: ‘junit’, version: ‘4.12’}父项目中的setting.gradle中添加这样一条配置include ‘greeting-library’这样就能使用greeting-library目录下的gradle子项目了一个简单的项目这使用一个简单的项目介绍一下这个如何使用gradle 实现整合打包项目结构和模块划分├── build.gradle├── greeter│ ├── build│ │ ├── classes│ │ │ └── java│ │ │ └── main│ │ │ └── greeter│ │ │ └── Greeter.class│ │ ├── distributions│ │ │ ├── greeter-1.0-SNAPSHOT.tar│ │ │ └── greeter-1.0-SNAPSHOT.zip│ │ ├── generated│ │ │ └── sources│ │ │ └── annotationProcessor│ │ │ └── java│ │ │ └── main│ │ ├── libs│ │ │ └── greeter-1.0-SNAPSHOT.jar│ │ ├── scripts│ │ │ ├── greeter│ │ │ └── greeter.bat│ │ └── tmp│ │ ├── compileJava│ │ └── jar│ │ └── MANIFEST.MF│ ├── build.gradle│ └── src│ ├── main│ │ ├── java│ │ │ └── greeter│ │ │ └── Greeter.java│ │ └── resources│ └── test│ ├── java│ └── resources├── greeting-library│ ├── build│ │ ├── classes│ │ │ └── groovy│ │ │ ├── main│ │ │ │ └── greeter│ │ │ │ └── GreetingFormatter.class│ │ │ └── test│ │ │ └── greeter│ │ │ └── GreetingFormatterSpec.class│ │ ├── generated│ │ │ └── sources│ │ │ └── annotationProcessor│ │ │ └── groovy│ │ │ ├── main│ │ │ └── test│ │ ├── libs│ │ │ └── greeting-library-1.0-SNAPSHOT.jar│ │ ├── reports│ │ │ └── tests│ │ │ └── test│ │ │ ├── classes│ │ │ │ └── greeter.GreetingFormatterSpec.html│ │ │ ├── css│ │ │ │ ├── base-style.css│ │ │ │ └── style.css│ │ │ ├── index.html│ │ │ ├── js│ │ │ │ └── report.js│ │ │ └── packages│ │ │ └── greeter.html│ │ ├── test-results│ │ │ └── test│ │ │ ├── binary│ │ │ │ ├── output.bin│ │ │ │ ├── output.bin.idx│ │ │ │ └── results.bin│ │ │ └── TEST-greeter.GreetingFormatterSpec.xml│ │ └── tmp│ │ ├── compileGroovy│ │ │ └── groovy-java-stubs│ │ ├── compileTestGroovy│ │ │ └── groovy-java-stubs│ │ ├── jar│ │ │ └── MANIFEST.MF│ │ └── test│ │ └── jar_extract_15307722744227685163_tmp│ ├── build.gradle│ └── src│ ├── main│ │ ├── groovy│ │ │ └── greeter│ │ │ └── GreetingFormatter.groovy│ │ ├── java│ │ └── resources│ └── test│ ├── groovy│ │ └── greeter│ │ └── GreetingFormatterSpec.groovy│ ├── java│ └── resources└── settings.gradle这个项目中划分为根项目gradle-demo,包项目greeting-library,core可运行项目greeter。注意: 通过上面的例子我们可以得出,在gradle 中不同的子项目的命名规则是使用文件夹的注意:在java 项目中,gradle 要求 必须指定项目的main函数具体方法见下方这里针对gradle的多语言的编程的目录结构做一下补充,gradle中源代码同意放置在这样的位置中src->main/test->编程语言名称文件夹 下plugins { id ‘java’ id ‘application’}group ‘com.kyssion’version ‘1.0-SNAPSHOT’sourceCompatibility = 1.8mainClassName = “greeter.Greeter” //这一句指定了main函数repositories { mavenCentral()}dependencies { compile project(’:greeting-library’) testCompile group: ‘junit’, name: ‘junit’, version: ‘4.12’}总结在构建gradle 多模块项目的时候,一定要注意多模块的之间的引用,模块中main函数的编写,父模块的include ...

February 26, 2019 · 2 min · jiezi

gradle-学习笔记(1)-初步使用

最近想深入的学习一下工程化方面相关的东西,在maven和gradle直接纠结不已,因为maven的扩展性太差劲了,学习成本颇高,所以最后投入了gradle的怀抱中,以后有时间再重新学习一下maven吧最近的学习笔记是基于gradle 5 系列,其中各种教程和例子大都是来源于官方文档或者网络上的博客。内容涵盖我在学习gradle过程中的各种心得和gradle的一些使用方法注意: 这里使用的配偶语言世kotlin 而不是使用groovygradle创建项目一个命令gradle init用户可以通过这个命令创建一个基本的gradle项目包括gradle项目的目录结构├── build.gradle (1)├── gradle│ └── wrapper│ ├── gradle-wrapper.jar (2)│ └── gradle-wrapper.properties (3)├── gradlew (4)├── gradlew.bat (5) └── settings.gradle (6) (1) gradle 的构建脚本用来构建当前的gradle项目,最核心的配置文件(2) (3) 一个gradle副本和配置文件,用来当如果系统中的gradle版本和项目使用的gradle版本不同,将会在这里下载一个项目中的版本(4) (5) 配套使用的命令行工具 没有.bat后缀的是unix系统命令有的是windowns系统,可以用来执行gradle中定义的各种task 任务(6) 用于配置Gradle构建的Gradle设置脚本gradle的taskgradle 方便用户进行配置的特性是源于gradle提供了方便使用task参数这里编写一个很基本的copy文件的权限,在路径中添加一个src文件夹和dest文件夹,在src文件中添加一个文件markfile.txt 并且里面有一个内容hello world!然后在build.gradle 中编写一个任务task copy(type:Copy,group:“custom”,description:“test one”){ from “src” into “dest”}其中的type 字段将会调用系统中的Copy函数,而group和description 只是描述这个过程的描述符,只会影响系统的log输出,并不会影响实际的效果./gradlew Copy运行对应的命令就能运行对应的copy方法使用一个gradle内部的插件系统在项目中使用插件标签plugins添加指定的base插件到系统中plugins { id “base”}然后在指定的位置我们添加一个插件(和任务的使用方法相同,我怀疑其实gradle的插件就是打包好的任务)task zip(type: Zip, group: “Archive”, description: “Archives sources in a zip file”) { from “src” setArchiveName “basic-demo-1.0.zip”}然后运行对应的命令,就可以在对应的目录 build/distributions 中找到 src目录下的压缩文件了./gradlew Zip查看当前拥有的taskgradle 有一个内置的命令./gradlew task这条命令将会将所有的当前的gradle项目中拥有的构建命令全部列出来> Task :tasks————————————————————Tasks runnable from root project————————————————————Archive tasks————-zip - Archives sources in a zip fileBuild tasks———–assemble - Assembles the outputs of this project.build - Assembles and tests this project.clean - Deletes the build directory.Build Setup tasks—————–init - Initializes a new Gradle build.wrapper - Generates Gradle wrapper files.Custom tasks————copy - Copies sources to the dest directoryHelp tasks———-buildEnvironment - Displays all buildscript dependencies declared in root project ‘gradle’.components - Displays the components produced by root project ‘gradle’. [incubating]dependencies - Displays all dependencies declared in root project ‘gradle’.dependencyInsight - Displays the insight into a specific dependency in root project ‘gradle’.dependentComponents - Displays the dependent components of components in root project ‘gradle’. [incubating]help - Displays a help message.model - Displays the configuration model of root project ‘gradle’. [incubating]projects - Displays the sub-projects of root project ‘gradle’.properties - Displays the properties of root project ‘gradle’.tasks - Displays the tasks runnable from root project ‘gradle’.Verification tasks——————check - Runs all checks.Rules—–Pattern: clean<TaskName>: Cleans the output files of a task.Pattern: build<ConfigurationName>: Assembles the artifacts of a configuration.Pattern: upload<ConfigurationName>: Assembles and uploads the artifacts belonging to a configuration.To see all tasks and more detail, run gradlew tasks –allTo see more detail about a task, run gradlew help –task <task>BUILD SUCCESSFUL in 1s1 actionable task: 1 executed<————-> 0% WAITING> IDLEgradle 提供的在线查看构建详情的方法 –scan命令我们在使用构建命令的时候可以在命令的后面添加一个 –scan命令,通过这个命令可以链接到gradle官方的view显示仓库或者连接到自定义的链接仓库中,然后轻松的查看项目使用的构建任务,构建时间等等信息./gradlew Zip –scan然后可以登入命令行打出的一个网址,在其中的form表单中填写邮箱地址,然后就会将构建的信息发送到邮箱中了注意:这个功能是收费的gradle 展示当前系统的可用参数信息 properties命令$ ./gradlew properties> Task :properties————————————————————Root project————————————————————buildDir: /Users/…/basic-demo/buildbuildFile: /Users/…/basic-demo/build.gradledescription: nullgroup:name: basic-demoprojectDir: /Users/…/basic-demoversion: unspecifiedBUILD SUCCESSFUL ...

February 26, 2019 · 2 min · jiezi

IDEA 插件开发入门教程

IntelliJ IDEA 是目前最好用的 JAVA 开发 IDE,它本身的功能已经非常强大了,但是每个人的需求不一样,有些需求 IDEA 本身无法满足,于是我们就需要自己开发插件来解决。工欲善其事,必先利其器,想要提高开发效率,我们可以借助 IDEA 提供的插件功能来满足我们的需求。如果没有我需要的功能怎么办?很简单,我们自己造一个!插件能做什么?IDEA 的插件几乎可以做任何事情,因为它把 IDE 本身的能力都封装好开放出来了。主要的插件功能包含以下四种:自定义语言支持:如果有 IDEA 暂时不支持的语言,你可以自己写一个插件来支持,例如 Go 语言原来的支持就是通过插件做的,后来单独做了一个 Goland。官方有自定义语言插件支持的教程。框架支持:例如Struts 2 的框架支持工具集成:可以给 IDEA 的自带功能进行增强,例如对 Git 的操作增加 CodeReview 的功能。参考Gerrit用户界面:自定义的插件改变用户界面。参考BackgroundImage我为了减少重复代码的编写,写了一个代码生成的插件IDEA代码生成插件CodeMaker,支持自定义代码生成的模板。Hello world 插件依照惯例,我们从 Hello world 开始。新建一个 Gradle 的插件工程有些教程推荐用 IDEA 默认的插件工程来开始,但是我比较推荐用 Gradle 来管理整个插件工程,后面的依赖管理会很方便,否则都得靠手动管理。点击新建工程,选择 Gradle接下来填写项目属性配置 Gradle,用默认配置就行新建完工程之后,IDEA 会自动开始解析项目依赖,因为它要下载一个几百兆的 SDK 依赖包,所以会比较久,打开科学上网能快一点。Gradle 依赖解析完成之后,项目结构如下图,其中 plugin.xml 是插件的配置,build.gradle 是项目依赖的配置(类比 pom.xml)。下面就是默认生成的 plugin.xml<idea-plugin> <!–插件id–> <id>com.xiaokai.test.demo</id> <!–插件名称–> <name>Demo</name> <!–开发者信息–> <vendor email=“support@yourcompany.com” url=“http://www.yourcompany.com”>YourCompany</vendor> <!–插件说明–> <description><![CDATA[ Enter short description for your plugin here.<br> <em>most HTML tags may be used</em> ]]></description> <!– please see http://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/plugin_compatibility.html on how to target different products –> <!– uncomment to enable plugin in all products <depends>com.intellij.modules.lang</depends> –> <!–依赖的其他插件能力–> <extensions defaultExtensionNs=“com.intellij”> <!– Add your extensions here –> </extensions> <!–插件动作–> <actions> <!– Add your actions here –> </actions></idea-plugin>创建一个 ActionAction 是 IDEA 中对事件响应的处理器,它的 actionPerformed 就像是 JS 中的 onClick 方法。可以看出来,插件的开发本质上跟 web、Android 的开发没有什么不同,因为都是事件驱动的编程。我们可以直接使用 IDEA 提供的 Action 生成器点击 OK 之后会在 src 生成类文件:package com.xiaokai.test;import com.intellij.openapi.actionSystem.AnAction;import com.intellij.openapi.actionSystem.AnActionEvent;public class HelloWorldAction extends AnAction { @Override public void actionPerformed(AnActionEvent e) { // TODO: insert action logic here }}同时,动作的信息也会注册到 plugin.xml 中 <!–插件动作–> <actions> <!– Add your actions here –> <action id=“demo.hello.world” class=“com.xiaokai.test.HelloWorldAction” text=“HelloWorld” description=“Say Hello World”> <add-to-group group-id=“GenerateGroup” anchor=“last”/> </action> </actions>弹出对话框创建完 Action 之后我们就要开始往里面写逻辑了,既然是 Hello World 教学,那我们就来试一下最简单的弹出对话框。 @Override public void actionPerformed(AnActionEvent e) { //获取当前在操作的工程上下文 Project project = e.getData(PlatformDataKeys.PROJECT); //获取当前操作的类文件 PsiFile psiFile = e.getData(CommonDataKeys.PSI_FILE); //获取当前类文件的路径 String classPath = psiFile.getVirtualFile().getPath(); String title = “Hello World!”; //显示对话框 Messages.showMessageDialog(project, classPath, title, Messages.getInformationIcon()); }代码写完之后,打开 Gradle 的界面,点击 runIde 就会启动一个安装了插件的 IDEA,然后就可以进行测试。你还可以右键启动 Debug 模式,这样还能进行断点。运行的效果如下图:可以看到,我们右键打开 Generate 菜单之后,里面最后一项就是我们添加的 Action,进阶的教程如果想学习更多的原理和设计理念可以看IntelliJ Platform SDK的官方文档。不过老实说,它的文档写的挺差的,基本上就是简单讲了一下概念和原理,没有深入的分析。所以如果要深入研究还得靠自己。最靠谱的学习方式就是看别人写的插件,举个例子,你想知道怎么样实现自动生成代码,你就去找支持这个功能的插件,看他的源码是怎么写的。我当时写CodeMaker的时候也是靠自己啃源码之后写出来的。下面我简单介绍一下我用过的一些 API,这些 API 基本都没有文档说明,全靠代码相传。判断当前光标选择的元素是什么 //获取当前事件触发时,光标所在的元素 PsiElement psiElement = anActionEvent.getData(LangDataKeys.PSI_ELEMENT); //如果光标选择的不是类,弹出对话框提醒 if (psiElement == null || !(psiElement instanceof PsiClass)) { Messages.showMessageDialog(project, “Please focus on a class”, “Generate Failed”, null); return; }获取当前类文件的所有类对象一个类文件中可能会有内部类,所以读取的时候返回的是一个列表 public static List<PsiClass> getClasses(PsiElement element) { List<PsiClass> elements = Lists.newArrayList(); List<PsiClass> classElements = PsiTreeUtil.getChildrenOfTypeAsList(element, PsiClass.class); elements.addAll(classElements); for (PsiClass classElement : classElements) { //这里用了递归的方式获取内部类 elements.addAll(getClasses(classElement)); } return elements; }格式化代码 public static void reformatJavaFile(PsiElement theElement) { CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(theElement.getProject()); try { codeStyleManager.reformat(theElement); } catch (Exception e) { LOGGER.error(“reformat code failed”, e); } }使用粘贴板 CopyPasteManager.getInstance() .setContents(new SimpleTransferable(table.toString(), DataFlavor.allHtmlFlavor));更多更多的技巧可以参考我的项目CodeMaker,以及其他的开源插件。本文作者:风马萧萧 阅读原文本文为云栖社区原创内容,未经允许不得转载。 ...

February 25, 2019 · 2 min · jiezi

实战:基于Spring Boot快速开发RESTful风格API接口

写在前面的话这篇文章计划是在过年期间完成的,示例代码都写好了,结果亲戚来我家做客,文章没来得及写。已经很久没有更新文章了,小伙伴们,有没有想我啊。言归正传,下面开始,今天的话题。目标写一套符合规范,并且具有RESTful风格的API接口。假定你已会使用Spring Boot 2.x。你已会使用Gradle构建Spring Boot工程。你已会基于Spring Boot编写API接口。你已会使用接口调试工具。如果你还不会使用Spring Boot写接口,建议先看一下这篇文章 :用Spring Boot开发API接口步骤1、基于Gradle构建Spring Boot示例项目。2、引入JavaLib。3、编写接口代码。4、测试接口。引入JavaLib测试版(SNAPSHOT),都会发布到 JitPack 上,所以,从这里拉取的,都会是最新的,但是需要配置仓库地址。正式版(RELEASE),才会推送到 Maven中央。UserModel我们用UserModel来存放我们的数据,以便存取。我个人比较喜欢用bean的,如果你喜欢用Map,那也是可以的。不过需要注意的是,需要加@JsonInclude(JsonInclude.Include.NON_NULL) ,他的作用是,如果某个字段为空时,在返回的JSON中,则不显示,如果没有,将为 null。完整代码如下:package com.fengwenyi.demojavalibresult.model;import com.fasterxml.jackson.annotation.JsonInclude;import lombok.Data;import lombok.experimental.Accessors;import java.io.Serializable;/** * User Model * @author Wenyi Feng * @since 2019-02-05 /@Data@Accessors(chain = true)@JsonInclude(JsonInclude.Include.NON_NULL)public class UserModel implements Serializable { private static final long serialVersionUID = -835481508750383832L; /* UID / private String uid; /* Name / private String name; /* Age / private Integer age;}编写接口返回码这里我们使用 JavaLib 中result模块为我们提供的方法。只需要调用 BaseCodeMsg.app(Integer, String)即可。这里我们只写几个用作示例,完整代码如下:package com.fengwenyi.demojavalibresult.util;import com.fengwenyi.javalib.result.BaseCodeMsg;/* * 自定义返回码以及描述信息 * @author Wenyi Feng * @since 2019-02-05 /public class CodeMsg { / user error ————————————————————————————————————*/ /** 用户不存在 / public static final BaseCodeMsg ERROR_USER_NOT_EXIST = BaseCodeMsg.app(10001, “User Not Exist”); /* UID不能为空 / public static final BaseCodeMsg ERROR_USER_UID_NOT_NULL = BaseCodeMsg.app(10002, “User UID Must Not null”);}BaseCodeMsg我们看一下源码:package com.fengwenyi.javalib.result;/* * (基类)返回码及描述信息 * @author Wenyi Feng * @since 2019-01-22 /public class BaseCodeMsg { /* 返回码 / private Integer code; /* 返回码描述 / private String msg; /* * 无参数构造方法 / private BaseCodeMsg() {} /* * 构造方法 * @param code * @param msg / private BaseCodeMsg(Integer code, String msg) { this.code = code; this.msg = msg; } public static BaseCodeMsg app(Integer code, String msg) { return new BaseCodeMsg(code, msg); } /* * 返回码填充 * @param args 填充内容 * @return CodeMsgEnum / public BaseCodeMsg fillArgs(Object … args) { this.msg = String.format(this.msg, args); return this; } /* * 获取返回码 * @return 返回码 / public Integer getCode() { return code; } /* * 获取描述信息 * @return 描述信息 / public String getMsg() { return msg; } /* 成功 / public static final BaseCodeMsg SUCCESS = BaseCodeMsg.app(0, “Success”); /* 失败 / public static final BaseCodeMsg ERROR_INIT = BaseCodeMsg.app(-1, “Error”);}成功的标识是:当 code=0 时。另外,我们还为你提供了预留字符串替换的方法。比如你想告诉用户某个字段不合法,那么你可以这样:第一步:在CodeMsg中添加public static final BaseCodeMsg ERROR_PARAM_ILLEGAL = BaseCodeMsg.app(20001, “Request Param Illegal : %s”);第二步:返回 /* * 测试参数错误 * @return {@link Result} / @GetMapping("/test-param-error") public Result testParamError() { return Result.error(CodeMsg.ERROR_PARAM_ILLEGAL.fillArgs(“account”)); }测试结果:编写接口代码接下来,开始编写我们的接口代码。首先指明,我们的接口接收和返回的文档格式。consumes = MediaType.APPLICATION_JSON_UTF8_VALUEproduces = MediaType.APPLICATION_JSON_UTF8_VALUE再使用 JavaLib 中 Result。完整代码如下:package com.fengwenyi.demojavalibresult.controller;import com.fengwenyi.demojavalibresult.model.UserModel;import com.fengwenyi.demojavalibresult.util.CodeMsg;import com.fengwenyi.javalib.result.Result;import org.springframework.http.MediaType;import org.springframework.util.StringUtils;import org.springframework.web.bind.annotation.;import javax.annotation.PostConstruct;import java.util.ArrayList;import java.util.List;import java.util.UUID;/** * User Controller : 用户操作 * @author Wenyi Feng * @since 2019-02-05 /@RestController@RequestMapping(value = “/user”, consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)public class UserController { /* 临时存放用户信息 / private List<UserModel> userModelList = new ArrayList<>(); /* * 初始化用户 / @PostConstruct public void init() { for (int i = 0; i < 10; i++) userModelList.add(new UserModel().setUid(UUID.randomUUID().toString()).setName(“u” + i).setAge(10 + i)); } /* * 查询用户列表 * @return {@link Result} / @GetMapping("/list") public Result list() { return Result.success(userModelList); } /* * 添加用户 * @param userModel 这里传JSON字符串 * @return {@link Result} / @PostMapping("/add") public Result add(@RequestBody UserModel userModel) { if (userModel != null) { userModelList.add(userModel.setUid(UUID.randomUUID().toString())); return Result.success(); } return Result.error(); } /* * 根据UID获取用户 * @param uid UID * @return {@link Result} */ @GetMapping("/get/{uid}") public Result getByUid(@PathVariable(“uid”) String uid) { if (StringUtils.isEmpty(uid)) return Result.error(CodeMsg.ERROR_USER_UID_NOT_NULL); for (UserModel userModel : userModelList) if (userModel.getUid().equals(uid)) return Result.success(userModel); return Result.error(CodeMsg.ERROR_USER_NOT_EXIST); }}测试1、启动2、list访问:http://localhost:8080/user/list{ “code”: 0, “msg”: “Success”, “data”: [ { “uid”: “d8e2dfac-b6e8-46c7-9d43-5bb6bf99ce30”, “name”: “u0”, “age”: 10 }, { “uid”: “87001637-9f21-4bc7-b589-bea1b2c795c4”, “name”: “u1”, “age”: 11 }, { “uid”: “5e1398ca-8322-4a68-b0d2-1eb4c1cac9de”, “name”: “u2”, “age”: 12 }, { “uid”: “e6ee5452-4148-4f6d-b820-9cc24e5c91b5”, “name”: “u3”, “age”: 13 }, { “uid”: “3f428e26-57e1-4661-8275-ce3777b5da54”, “name”: “u4”, “age”: 14 }, { “uid”: “b9d994b4-f090-40de-b0f3-e89c613061f2”, “name”: “u5”, “age”: 15 }, { “uid”: “748d1349-5978-4746-b0c1-949eb5613a28”, “name”: “u6”, “age”: 16 }, { “uid”: “abaadb7c-23fb-4297-a531-0c490927f6d5”, “name”: “u7”, “age”: 17 }, { “uid”: “5e5917a1-8674-4367-94c6-6a3fd10a08d6”, “name”: “u8”, “age”: 18 }, { “uid”: “03ed6a83-0cc0-4714-9d0d-f653ebb3a2eb”, “name”: “u9”, “age”: 19 } ]}2、添加数据看一下,数据是什么样子与我们预想的结果一样。获取数据有数据样式:无数据样式:关于冯文议。2017年毕业于阿坝师范学院计算机应用专业。现就职于深圳警圣技术股份有限公司,主要负责服务器接口开发工作。技术方向:Java。 开源软件:JavaLib。后记到这里就结束了,如果在遇到什么问题,或者有不明白的地方,可以通过评论、留言或者私信等方式,告诉我。 ...

February 21, 2019 · 3 min · jiezi

building xxx gradle project info的解决办法

AndroidStudio创建项目,最后一步finish后,一直长时间处于building“project name”gradle project info,界面就一直停留在如图所示:解决办法:定位一下gradle的版本以及存放位置。查看gradle版本:查看目录C:Users用户名.gradlewrapperdistsgradle-1.XX-all存放位置:C:Users用户名.gradlewrapperdistsgradle-1.XX-all3jdgemv0iv8uqohg3kcp2o88r1gradle-1.XX-all.zip知道了版本,知道了位置,剩下的就是在网上下载离线包了,搜索gradle-1.XX-all.zip,我的版本为gradle-1.10-all下载完毕后直接把zip拷贝到C:Users用户名.gradlewrapperdistsgradle-1.XX-all3jdgemv0iv8uqohg3kcp2o88r1 下即可。重启Android Studio后,打开项目即可。所有gradle包下载地址:https://services.gradle.org/d…

February 18, 2019 · 1 min · jiezi

IDEA下Gradle多模块(项目)的构建

IDEA下Gradle多模块项目的构建我们在新起一个项目的时候,一般都会建多个子项目(IDEA里面称之为Module模块)。通过Gradle构建,多个Module之间需要将公用的配置抽取到全局,子项目中只写差异化的配置,以便于维护。多模块项目的Gradle目录结构示例:我的示例项目demo,我需要有一个common模块用于公用代码,一个rest模块用于提供rest接口,rest依赖common,如果用gradle构建,目录树会是这样:demo├── build.gradle – 全局配置├── settings.gradle – 全局配置├── common – 子模块1目录│ └── build.gradle – 子模块1配置├── rest – 子模块2配置│ └── build.gradle – 子模块2配置…IDEA下初始创建root目录结构A. IDEA本地创建项目并定义项目名如果是通过IDEA新建一个本地项目,可按照如下步骤先创建root项目:File -> New -> Project: 选择Gradle->JavaNext, 填写GroupId和ArtifactId:GroupId: 如com.dibootArtifactId:如demoNext, 指定Gradle home和JVM等Next, 选择项目存放路径。完成之后IDEA会创建相关文件接下来如果你需要将本地新项目代码上传到代码仓库,可以通过VCS菜单导入:B. 基于代码仓库指定的项目名创建root项目而如果项目名已经在仓库中定义,你需要基于仓库名初始项目的gradle配置,则项目的初始创建是通过VCS导入,然后用命令行初始化gradle:File -> New -> Project from Version Control -> …切换到Terminal命令行,输入 gradle init,按照操作提示进行root项目的初始化。创建子模块/项目在根目录demo文件夹右键选择 New -> Module -> Gradle -> Java, 指定子模块ArtifactId名称,依次添加common模块和rest模块后,gradle相关的目录结构就跟我们期望的一致了。全局gradle配置在demo根目录下: settings.gradle中的结构定义如下rootProject.name = ‘demo’include ‘common’include ‘rest’build.gradle中可以定义全局公用的构建配置,以Spring Boot项目配置示例:buildscript { ext { springBootVersion = ‘2.1.2.RELEASE’ } repositories { maven{ url ‘http://maven.aliyun.com/nexus/content/groups/public/'} } dependencies { classpath(“org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}”) }}// 所有模块/项目的通用配置allprojects { group ‘com.diboot’ version ‘1.0-SNAPSHOT’ apply plugin: ‘idea’}// 子模块/项目的统一配置subprojects { apply plugin: ‘java’ // 指定JDK版本 sourceCompatibility = 1.8 targetCompatibility = 1.8 // 指定编码格式 [compileJava,compileTestJava,javadoc].options.encoding = ‘UTF-8’ repositories { maven{ url ‘http://maven.aliyun.com/nexus/content/groups/public/'} } ext {//依赖版本 springBootVersion = “2.1.2.RELEASE” mysqlConnectorVersion = “8.0.13” mybatisStarterVersion = “1.3.2” fastjsonVersion = “1.2.54” } dependencies { compile(“javax.servlet:javax.servlet-api:4.0.1”) compile(“org.springframework.boot:spring-boot-starter-web:$springBootVersion”) // Mybatis compile(“org.mybatis.spring.boot:mybatis-spring-boot-starter:$mybatisStarterVersion”) // Log4j2 compile(“org.springframework.boot:spring-boot-starter-log4j2:$springBootVersion”) // JDBC Driver compile(“mysql:mysql-connector-java:$mysqlConnectorVersion”) // JSON compile(“com.alibaba:fastjson:$fastjsonVersion”) // Apache Commons compile(“org.apache.commons:commons-lang3:3.8.1”) // 单元测试 testCompile(“org.springframework.boot:spring-boot-starter-test:$springBootVersion”) testCompile(“junit:junit:4.12”) } configurations { //移除spring boot 默认logger依赖 all*.exclude module: ‘spring-boot-starter-logging’ }}子模块/项目gradle配置通用的依赖配置可以在根目录下的build.gradle中,子模块/项目仅配置差异化的部分即可,如子项目特定的依赖。common下的build.gradle示例:dependencies { // 配置该项目特有的依赖}rest下的build.gradle示例(rest项目依赖common项目):dependencies { // 依赖common项目 compile project(":common") // 配置该项目特有的依赖}代码参考:Diboot-v2初始项目Gradle官方相关文章:Gradle多项目构建介绍Gradle多项目构建Diboot轻代码开发平台, Diboot开发助理 ...

January 26, 2019 · 1 min · jiezi

使用Gradle发布构件(Jar)到Maven中央仓库

OSSRH在开始之前,先对OSSRH做下了解是很必要的,因为一开始,我并不知道这是个啥玩儿意。我想和我一样的人应该还是有很多的。OSSRH:Sonatype Open Source Software Repository Hosting Service,为开源软件提供maven仓库托管服务。你可以在上面部署snapshot、release等,最后你可以申请把你的release同步到Maven Central Repository(Maven中央仓库)。个人的理解,OSSRH是Maven中央仓库的前置审批仓库,只有你完全符合了发布要求,成功的将你的项目发布到了OSSRH,才有机会申请同步到Maven中央仓库。这篇主要是记录这整个流程,方便以后自己查阅,同时可以帮助到想做同样事情的朋友。1、注册Sonatype JIRA账号JIRA是Atlassian公司出品的项目与事务跟踪工具,被广泛应用于缺陷跟踪、客户服务、需求收集、流程审批、任务跟踪、项目跟踪和敏捷管理等工作领域。网址:https://issues.sonatype.org/无非就是填写下注册信息,没有什么特别的2、创建一个Issue填写资料可以在头部看到一个Create的按钮会弹出Create Issue表单Project选择Community Support - Open Source Project Repository Hosting (OSSRH)Issue Type选择New ProjectSummary写个标题做个简单概述你要做啥。真不知道写什么,直接把项目名称写上就行,我就这么干了哈。Group Id自己有域名可以使用子域名作为Group Id 。例:我的项目叫paladin2,那么就用org.zhangxiao.paladin2作为Group Id注意:不能瞎编一个,因为后面审核人员会来审核你是否是该域名的拥有者自己没域名可以借助github,例:我的用户名为michaelzx,那么就用com.github.michaelzx.paladin2作为作为Group IdProject URL要与Group Id一定关联性例1:Project URL=http://paladin2.zhangxiao.orgGroup Id=org.zhangxiao.paladin2例2:Project URL=https://github.com/michaelzx/Paladin2Group Id=com.github.michaelzx.paladinSCM url版本仓库的拉取地址等待回复如果有问题,老外在评论中把问题给你指出来,可以在原有的issue把资料改正确我之前是犯了个低级的错误把Group Id写成了域名审核人员要处理的issue很多,你可能要耐心等待一会,不要急 我之前急了,就重新提交了2个新的issue,最后管理员还是耐心的把重复的issue关闭如果一切顺利,那么你会收到审核人员,这样的一个评论:3、准备工作文件要求为了确保中央存储库中可用组件的质量水平,OSSRH对提交的文件有明确的要求。一个基础的提交,应该包含一下文件:example-application-1.4.7.pomexample-application-1.4.7.pom.ascexample-application-1.4.7.jarexample-application-1.4.7.jar.ascexample-application-1.4.7-sources.jarexample-application-1.4.7-sources.jar.ascexample-application-1.4.7-javadoc.jarexample-application-1.4.7-javadoc.jar.asc除了jar包和pom文件,Javadoc和Sources是必须的,后面会说到用Gradle的一些插件来生成每个文件都有一个对应的asc文件,这是GPG签名文件,可以用于校验文件GPG安装说明:后续过程均在OSX环境下OSX下可以通过brew来安装gpg命令行工具$ brew update$ brew install -v gpg你会发现从brew的gpg命令行工具,做了国际化支持,连help都是中文,赞????另外推荐一个工具GPG Suite,传送门在OSX提供了一个图形化界面,把GPG作为钥匙串来做管理,蛮有意思,不过感觉缺失点功能Windows下可以安装gpg4win,网址:传送门 页面最上面有个很大的下载按钮,点了以后,貌似会让你捐个款啥的……不过你可以往下看,有所有版本的列表地址,可以跳过捐款,在祭上一个传送门人家只是隐藏的好了一些而已,还是免费的。装完了以后,在命令行中也可以用gpg了公钥、私钥、签名GPG的默认秘钥类型是RSA,这里涉及涉及几个概念公钥(public-key)、私钥(secret-key)、签名(sign/signature)公钥和私钥是成对公钥加密,私钥解密。私钥签名,公钥验证。新建一个密钥生成了密钥以后,才能导出公钥、私钥$ gpg –generate-key创建的时候,会让你输入密码,别输了以后忘记了,后面gradle插件中会用到。查看已经生成的密钥$ gpg -k———————————pub rsa2048 2019-01-25 [SC] [有效至:2021-01-24] 72963F6B33D962380B1DC4BD8C446B86DF855F85uid [ 绝对 ] zhangxiao’paladin2 <mail@zhangxiao.org>sub rsa2048 2019-01-25 [E] [有效至:2021-01-24]72963F6B33D962380B1DC4BD8C446B86DF855F85,这个叫做密钥指纹,用来做唯一识别 后面8位DF855F85,叫做标识或KEY ID,后面会用到导出私钥文件很多英文文档或文章中经常出现KeyRingFile这个词,这个到底是啥?https://users.ece.cmu.edu/ad…Keys are stored in encrypted form. PGP stores the keys in two files on your hard disk; one for public keys and one for private keys. These files are called keyrings. As you use PGP, you will typically add the public keys of your recipients to your public keyring. Your private keys are stored on your private keyring. If you lose your private keyring, you will be unable to decrypt any information encrypted to keys on that ring.$ gpg –export-secret-keys [密钥指纹] > secret.gpg以上命令就可以生成一个二进制的私钥文件,后面需要配置到gradle中,让插件帮我们给文件批量签名加上-a会生成一个用ASCII 字符封装的文本文件,方便复制,不过我们这里不需要上传公钥到公钥服务器$ gpg –keyserver keyserver.ubuntu.com –send-keys [密钥指纹]在sonatype的仓库提交后,会需要一个校验步骤 会需要从多个公钥服务器上下载匹配的公钥,然后来校验你上传的文件的签名简单的说,你用来签名的私钥和你上传的公钥,必须要一对,这样才能通过校验以下是sonatype会去拉取的公钥服务器列表keys.gnupg.netpool.sks-keyservers.netkeyserver.ubuntu.com为什么我要特意列出来?因为有些文章或教程里面,都仅给出了一个服务器,如pool.sks-keyservers.net但是,我在实际操作有时候因为网络原因,并不是总能成功上传。所以,如果把公钥上传到keyserver.ubuntu.com也是OK的。总结密钥的key id密钥的password私钥的KeyRingFile公钥上传到了公钥服务器准备好了以上几项,我们就可以开始撸Gradle了有些文章说,最好是先生成一个吊销凭证备用,暂时不知道什么场景下会用到4、配置Gradle插件Gradle版本:4.10.2start.spring.io中生成的gradle工程,是用4.10.2。所以我就这个版本为标准。signing:https://docs.gradle.org/4.10….maven-publish:https://docs.gradle.org/4.10….主要核心就是以上两个插件修改build.gradle// … 在最下面新增以下代码apply plugin: ‘maven-publish’apply plugin: ‘signing’task sourcesJar(type: Jar) { from sourceSets.main.allJava classifier = ‘sources’}task javadocJar(type: Jar) { from javadoc classifier = ‘javadoc’}publishing { // 定义发布什么 publications { mavenJava(MavenPublication) { // groupId = project.group // artifactId = project.name // version = project.version // groupId,artifactId,version,如果不定义,则会按照以上默认值执行 from components.java artifact sourcesJar artifact javadocJar pom { // 构件名称 // 区别于artifactId,可以理解为artifactName name = ‘Paladin2 Common’ // 构件描述 description = ‘Paladin2 Common library’ // 构件主页 url = ‘https://paladin2.zhangxiao.org’ // 许可证名称和地址 licenses { license { name = ‘The Apache License, Version 2.0’ url = ‘http://www.apache.org/licenses/LICENSE-2.0.txt' } } // 开发者信息 developers { developer { name = ‘听风.Michael’ email = ‘mail@zhangxiao.org’ } } // 版本控制仓库地址 scm { url = ‘https://github.com/michaelzx/Paladin2' connection = ‘scm:git:git://github.com/michaelzx/Paladin2.git’ developerConnection = ‘scm:git:ssh://git@github.com:michaelzx/Paladin2.git’ } } } } // 定义发布到哪里 repositories { maven { // 从命令行参数中获取账号密码,这样你把这个文件传到GitHub这关系也不大,不会暴露账号密码 // -DsonatypeUsername=michaelzx -DsonatypePassword=xxxxxx def sonatypeUsername = System.getProperty(“sonatypeUsername”) def sonatypePassword = System.getProperty(“sonatypePassword”) // 打印出来看看,你参数设置对了没 println(“sonatypeUsername:” + sonatypeUsername) println(“sonatypePassword:” + sonatypePassword) url “https://oss.sonatype.org/service/local/staging/deploy/maven2" credentials { // 这里就是之前在issues.sonatype.org注册的账号 // 直接写在不太安全,应该是有办法通过参数,配置到工程之外 username sonatypeUsername password sonatypePassword } } }}signing { sign publishing.publications.mavenJava}javadoc { // <meta http-equiv=“Content-Type” content=“text/html; charset=UTF-8”> // 防止本地打开中文乱码 options.addStringOption(“charset”, “UTF-8”)}在工程根目录下新增gradle.propertiessigning.keyId=密钥keyIdsigning.password=密钥passwordsigning.secretKeyRingFile=私钥keyRingFile路径如果要提交到GitHub上,那么keyId,password好像是暴露了,不过感觉好像也没什么关系,把私钥保护好就好了5、提交到Sonatype仓库首先,用Gradle执行publishToMavenLocal任务,先在本地发布下,看看生成了哪些文件,或还有什么问题然后,用Gradle执行publish任务,发布到指定的maven仓库如果没有报错,那么恭喜你,已经成功提交到了sonatype的仓库中但是提交成功,并不代表发布成功6、到Sonatype OSS发布用你之前注册的账号密码,登录:https://oss.sonatype.org/登录后查看左侧的Build Promotion->Staging Repositories你的提交,会出现在最下面,至于其他是啥,我也不太清楚????Close你的提交在未处理前,是open状态,然后点击Close按钮。一开始不太明白这个Close是啥意思,后来看了下,主要按照中央仓库的要求来验证下你上传到文件签名就是其中一个步骤,会去公钥服务器拉取公钥,然后来验证你所有的文件需要等待一会,等它执行完毕,状态会从open变成closed如果碰到错误的话,仔细看下Activity选项卡,执行了什么步骤,那个步骤出现了什么错误,很清晰的Release一般情况下,感觉如果顺利close后,再次选中点击Release,耐心等待一会,就大功告成了!可以在侧边栏Artifact Search中搜索下你的groupId,此时应该能看到对应的构件名称和版本了7、回复Issue但是很抱歉,到此为止,你的jar包,还不会同步到maven仓库中你需要在你原先创建issue中,告诉下管理人员,你已经完成了第一次发布我用我蹩脚的英文,回复如下:I have already completed the first release.然后管理人员给我回复了:Central sync is activated for org.zhangxiao.paladin2. After you successfully release, your component will be published to Central, typically within 10 minutes, though updates to search.maven.org can take up to two hours.OK,至此,你的构建就会同步到Maven Central Repository了。8、同步需要多久可能你会像我一样很着急,啥时候可以用,怎么还搜不到呢。~ 从sonatype同步到中央仓库,的确是需要一定的时间 不过根据我的观察,文件的同步,会早于索引的同步 比如,比如你等了半天,然后 https://search.maven.org/ 上搜一下依然搜不到那么,你可以去 https://repo1.maven.org/maven2/ 上按照坐标找下,是否能找到你的包如果能找到,那你就可以开始引用它了9、新版本更新只要完成第一个发布,后续就不需要再创建issue了,只要重复5-6步骤可以了。你可以在groupId范围内发布任意名称的构件结束语以前在NPM仓库中发布过自己的东西。相比之下,Maven仓库的发布流程,让人感觉严谨很多。赶紧一起在Maven全球中央仓库中,留下你自己专属的印记吧!一定会让你感觉棒棒的^_^参考文章https://central.sonatype.org/… ...

January 25, 2019 · 2 min · jiezi

使用Gradle构建Java项目

本指南将引导您使用Gradle构建一个简单的Java项目。你要构建什么您将创建一个简单的应用程序,然后使用Gradle构建它。你需要什么大约15分钟最喜欢的文本编辑器或IDEJDK 6或更高版本如何完成本指南与大多数Spring入门指南一样,您可以从头开始并完成每个步骤,或者您可以绕过您已熟悉的基本设置步骤。无论哪种方式,您最终都会使用工作代码。要从头开始,请继续使用Gradle构建。要跳过基础知识,请执行以下操作:下载并解压缩本指南的源存储库,或使用Git克隆它:git clone https://github.com/spring-guides/gs-gradle.git进入gs-gradle/initial跳转到安装Gradle。完成后,可以根据gs-gradle/complete中的代码检查结果。设置项目首先,您要为Gradle建立一个Java项目。为了保持对Gradle的关注,让项目尽可能简单。创建目录结构在您选择的项目目录中,创建以下子目录结构;例如,在*nix系统上使用mkdir -p src/main/java/hello:└── src └── main └── java └── hello在src/main/java/hello目录中,您可以创建所需的任何Java类。为了简单起见并与本指南的其余部分保持一致,Spring建议您创建两个类:HelloWorld.java和Greeter.java。src/main/java/hello/HelloWorld.javapackage hello;public class HelloWorld { public static void main(String[] args) { Greeter greeter = new Greeter(); System.out.println(greeter.sayHello()); }}src/main/java/hello/Greeter.javapackage hello;public class Greeter { public String sayHello() { return “Hello world!”; }}安装Gradle现在您有了一个可以使用Gradle构建的项目,您就可以安装Gradle了。强烈建议使用安装程序:SDKMANHomebrew(brew install gradle)最后,如果这些工具都不适合您的需要,您可以从http://www.gradle.org/downloads下载二进制文件。只有二进制文件是必需的,所以要查找到gradle-version-bin.zip 的链接。(您也可以选择gradle-version-all.zip以获取源代码和文档以及二进制文件。)将文件解压缩到您的计算机,然后将bin文件夹添加到您的路径中。要测试Gradle安装,请从命令行运行Gradle:gradle如果一切顺利,您会看到一条欢迎信息::helpWelcome to Gradle 2.3.To run a build, run gradle <task> …To see a list of available tasks, run gradle tasksTo see a list of command-line options, run gradle –helpBUILD SUCCESSFULTotal time: 2.675 secs您现在安装了Gradle。了解Gradle可以做些什么现在已经安装了Gradle,看看它能做什么。在为项目创建build.gradle文件之前,您可以询问它可用的任务:gradle tasks您应该看到可用任务列表。假设您在没有build.gradle文件的文件夹中运行Gradle ,您将看到一些非常基本的任务,例如::tasks== All tasks runnable from root project== Build Setup taskssetupBuild - Initializes a new Gradle build. [incubating]== Help tasksdependencies - Displays all dependencies declared in root project ‘gs-gradle’.dependencyInsight - Displays the insight into a specific dependency in root project ‘gs-gradle’.help - Displays a help messageprojects - Displays the sub-projects of root project ‘gs-gradle’.properties - Displays the properties of root project ‘gs-gradle’.tasks - Displays the tasks runnable from root project ‘gs-gradle’.To see all tasks and more detail, run with –all.BUILD SUCCESSFULTotal time: 3.077 secs即使这些任务可用,但如果没有项目构建配置,它们也不会提供太多价值。当你充实build.gradle文件时,一些任务会更有用。在添加build.gradle插件时,任务列表会增加,因此您偶尔会想要再次运行任务以查看可用的任务。说到添加插件,接下来添加一个启用基本Java构建功能的插件。构建Java代码从简单的build.gradle开始,在本指南开头创建的中创建一个非常基本的文件。只给它一行apply plugin: ‘java’构建配置中的这一行带来了大量功率。再次运行gradle tasks,您会看到添加到列表中的新任务,包括构建项目,创建JavaDoc和运行测试的任务。您将经常使用gradle build。此任务将代码编译,测试并组装到JAR文件中。你可以像这样运行它:gradle build几秒钟后,“BUILD SUCCESSFUL”表示构建已完成。要查看构建工作的结果,请查看构建文件夹。在那里你会找到几个目录,包括这三个值得注意的文件夹:classes:该项目已编译的.class文件。reports:构建生成的报告(例如测试报告)。libs:汇编的项目库(通常是JAR和/或WAR文件)。classes文件夹具有通过编译Java代码生成的.class文件。具体来说,您应该找到HelloWorld.class和Greeter.class。此时,项目没有任何库依赖项,因此dependency_cache文件夹中没有任何内容。reports文件夹应包含项目运行单元测试的报告。由于该项目尚未进行任何单元测试,因此该报告无效。libs文件夹应包含以项目文件夹命名的JAR文件。再往下,您将看到如何指定JAR的名称及其版本。声明依赖项简单的Hello World示例是完全独立的,不依赖于任何其他库。但是,大多数应用程序依赖于外部库来处理常见或复杂的功能。例如,假设除了说“Hello World!”之外,您还希望应用程序打印当前日期和时间。您可以使用本机Java库中的日期和时间工具,但是通过使用Joda Time库可以使事情变得更有趣。首先,将HelloWorld.java更改为如下所示:package hello;import org.joda.time.LocalTime;public class HelloWorld { public static void main(String[] args) { LocalTime currentTime = new LocalTime(); System.out.println(“The current local time is: " + currentTime); Greeter greeter = new Greeter(); System.out.println(greeter.sayHello()); }}这里HelloWorld使用Joda Time的LocalTime类来获取和打印当前时间。如果您现在运行gradle build来构建项目,那么构建将失败,因为您没有在构建中将Joda Time声明为编译依赖项。对于初学者,您需要为第三方库添加源。repositories { mavenCentral()}repositories块指示构建应从Maven Central存储库解析其依赖关系。Gradle严重依赖Maven构建工具建立的许多约定和工具,包括使用Maven Central作为库依赖关系源的选项。现在我们已经为第三方库做好了准备,让我们宣布一些。sourceCompatibility = 1.8targetCompatibility = 1.8dependencies { compile “joda-time:joda-time:2.2” testCompile “junit:junit:4.12”}使用dependencies块,您可以为Joda Time声明一个依赖项。具体来说,你在joda-time组中要求(从右到左阅读)joda-time库2.2版。关于这种依赖关系的另一个注意事项是它是一个compile依赖项,表明它应该在编译时可用(如果你正在构建一个WAR文件,包含在WAR的/WEB-INF/libs文件夹中)。其他值得注意的依赖类型包括:providedCompile。编译项目代码所需的依赖项,但是运行代码的容器将在运行时提供该依赖项(例如,Java Servlet API)。testCompile。用于编译和运行测试的依赖项,但不是构建或运行项目的运行时代码所必需的。最后,让我们指定JAR工件的名称。jar { baseName = ‘gs-gradle’ version = ‘0.1.0’}jar块指定如何命名JAR文件。在这种情况下,它将呈现gs-gradle-0.1.0.jar。现在,如果您运行gradle build,Gradle应该从Maven Central存储库解析Joda Time依赖项,并且构建将成功。使用Gradle Wrapper构建项目Gradle Wrapper是启动Gradle构建的首选方式。它由Windows的批处理脚本和OS X和Linux的shell脚本组成。这些脚本允许您运行Gradle构建,而无需在系统上安装Gradle。这曾经是添加到您的构建文件中的东西,但它已被折叠到Gradle中,因此不再需要。相反,您只需使用以下命令。$ gradle wrapper –gradle-version 2.13完成此任务后,您会注意到一些新文件。这两个脚本位于文件夹的根目录中,而包装jar和属性文件已添加到新gradle/wrapper文件夹中。└── <project folder> └── gradlew └── gradlew.bat └── gradle └── wrapper └── gradle-wrapper.jar └── gradle-wrapper.propertiesGradle Wrapper现在可用于构建项目。将它添加到您的版本控制系统,克隆项目的每个人都可以构建它。它可以与安装的Gradle版本完全相同的方式使用。运行包装器脚本来执行构建任务,就像之前一样:./gradlew build第一次运行指定版本的Gradle的包装器时,它会下载并缓存该版本的Gradle二进制文件。Gradle Wrapper文件旨在提交源代码控制,以便任何人都可以构建项目,而无需先安装和配置特定版本的Gradle。在此阶段,您将构建代码。你可以在这里看到结果:build├── classes│ └── main│ └── hello│ ├── Greeter.class│ └── HelloWorld.class├── dependency-cache├── libs│ └── gs-gradle-0.1.0.jar└── tmp └── jar └── MANIFEST.MF包括的是两个预期类文件Greeter和HelloWorld,以及JAR文件。快速浏览一下:$ jar tvf build/libs/gs-gradle-0.1.0.jar 0 Fri May 30 16:02:32 CDT 2014 META-INF/ 25 Fri May 30 16:02:32 CDT 2014 META-INF/MANIFEST.MF 0 Fri May 30 16:02:32 CDT 2014 hello/369 Fri May 30 16:02:32 CDT 2014 hello/Greeter.class988 Fri May 30 16:02:32 CDT 2014 hello/HelloWorld.class类文件被捆绑在一起。值得注意的是,即使您将joda-time声明为依赖项,此处也不包含该库。并且JAR文件也不可运行。为了使这段代码可以运行,我们可以使用gradle的application插件。将其添加到您的build.gradle文件中。apply plugin: ‘application’mainClassName = ‘hello.HelloWorld’然后你可以运行该应用程序!$ ./gradlew run:compileJava UP-TO-DATE:processResources UP-TO-DATE:classes UP-TO-DATE:runThe current local time is: 16:16:20.544Hello world!BUILD SUCCESSFULTotal time: 3.798 secs捆绑依赖关系需要更多思考。例如,如果我们构建一个WAR文件,一种通常与第三方依赖关系打包相关的格式,我们可以使用gradle的WAR插件。如果您使用的是Spring Boot并且想要一个可运行的JAR文件,那么spring-boot-gradle-plugin非常方便。在这个阶段,gradle对您的系统不了解,无法做出选择。但就目前而言,这应该足以开始使用gradle了。要完成本指南的内容,这里是完整的build.gradle文件:apply plugin: ‘java’apply plugin: ’eclipse’apply plugin: ‘application’mainClassName = ‘hello.HelloWorld’// tag::repositories[]repositories { mavenCentral()}// end::repositories[]// tag::jar[]jar { baseName = ‘gs-gradle’ version = ‘0.1.0’}// end::jar[]// tag::dependencies[]sourceCompatibility = 1.8targetCompatibility = 1.8dependencies { compile “joda-time:joda-time:2.2” testCompile “junit:junit:4.12”}// end::dependencies[]// tag::wrapper[]// end::wrapper[]此处嵌入了许多开始/结束注释。这使得可以将构建文件的位提取到本指南中,以获得上述详细说明。您在生产构建文件中不需要它们。概要恭喜!您现在已经创建了一个简单而有效的Gradle构建文件,用于构建Java项目。 ...

January 23, 2019 · 2 min · jiezi

Gradle 5.0 正式版发布

Gradle 5.0 正式版发布了,官方表示这是史上最快、最安全,最强大的版本,且没有之一。改进的增量编译和增量注释处理构建在已经具有构建缓存和最新检查功能的可靠性能基础之上。依赖对齐和版本锁定提供了可扩展且灵活的依赖管理模型。通过新的性能和依赖关系管理、日志记录和弃用的 API 使用检查,构建扫描得到了显著的改进。静态类型的 Kotlin DSL 可在创建构建逻辑时提供代码完成、重构和其他的 IDE 辅助。根据官方文档介绍,此次更新主要带来了如下几个方面的改进:更快的构建细粒度的传递依赖管理编写 Gradle 构建逻辑更高效的内存执行新的 Gradle 调用选项新的 Gradle 任务和插件 API更快的构建缓慢的构建过程既浪费钱又浪费精力,而通过使用Gradle 5.0中的新构建缓存和增量处理特性,将使得构建过程带来质的提升。升级到Gradle 5.0之后,您的构建速度将明显提升,您还可以通过使用和配置本节中描述的其他特性来进一步提高构建的性能。构建缓存通过重用构建缓存来避免重复的构建工作,这使得Gradle的构建将非常快,Gradle 4.0引入了构建缓存,其目的是重用以前调用Gradle时的输出。现在,Gradle 5.0可以用于Android、Kotlin、c++、Scala和许多其他插件的插件,使得任务可以缓存,因此可以跨不同的机器重用。有效地使用构建缓存可以将构建时间减少90%左右。此外,Gradle 5.0中的构建缓存在很多场景中也是启用的,例如当一个任务声明一个@ outputdirectory或@OutputFiles集合时。Java增量编译在Gradle 5.0中,增量编译器是经过高度优化的,且默认使用增量编译功能。这是一个非常棒的消息,因为编译java任务不需要重新编译所有的源文件,除了第一次之外,这将大大的提供代码编译的效率。增量注解处理Gradle 5.0中的增量编译器支持增量注解处理,当有注解处理程序时,可以显著提高增量编译的效率。这是一个重要的创新,因为依赖注解处理器的项目越来越多。要利用增量注解处理,请确保升级到选择该特性的注解处理程序版本。您可以通过info日志记录或查看注解处理程序来发现给定的注解过程是否具有支持增量功能。使用新的annotationProcessor配置可以方便地管理注解处理器,并将它们放到注解处理器路径上。构建扫描通过对性能、依赖管理、日志记录和废弃api的使用进行新的检查,构建扫描有了显著的改进。这是一个免费的服务,主要提供给Gradle用户在需要添加扫描时使用,在命令行上执行Gradle或应用和配置即可构建扫描。细粒度的传递依赖管理Gradle 5.0提供了几个新的特性来定制如何选择依赖项,以及改进的POM和BOM支持:依赖约束允许您定义版本或版本范围,从而限制和传递依赖版本(Maven不支持)。平台定义(又称Maven BOM依赖项)是本地支持的,它允许在不使用外部插件的情况下导入Spring之类的东西。依赖项对齐允许逻辑组中的不同模块(例如Jackson模块)对齐到相同的版本。依赖约束依赖约束提供了对传递依赖项的可靠性控制,已声明的约束列在改进的依赖关系洞察报告和构建扫描中。例如,下面是常见的Groovy依赖脚本:dependencies { implementation ‘org.apache.httpcomponents:httpclient’ constraints { implementation(‘org.apache.httpcomponents:httpclient:4.5.3’) { because ‘previous versions have a bug impacting this application’ } implementation(‘commons-codec:commons-codec:1.11’) { because ‘version 1.9 pulled from httpclient has bugs affecting this application’ } }}OM支持Gradle 5.0可导入BOM文件,bom (bill of materials) 可以有效解决同一项目,不同版本依赖的问题。dependencies { // import a BOM implementation platform(‘org.springframework.boot:spring-boot-dependencies:1.5.8.RELEASE’) // define dependencies without versions implementation ‘com.google.code.gson:gson’ implementation ‘dom4j:dom4j’}此外,Gradle 5.0在使用Maven构建生成的依赖项时提供了更无缝的体验。在使用POM文件时,Gradle将正确地分离编译和运行时范围。这可以有效的避免由于以前在编译类路径中包含运行时依赖项而导致的性能下降和依赖项泄漏问题。Gradle现在也可以用在< pom>元素中。依赖对齐依赖项版本对齐,允许属于同一逻辑组(平台)的不同模块在依赖项中拥有相同的版本。这确保所有Spring或Hibernate依赖项具有相同版本的问题。事实上,有许多库是以集合的形式发布的,集合中的每个库具有相同的版本。依赖版本锁定您可以使用Gradle 5.0将动态或远程依赖项锁定到特定的版本,从而使依赖项解析更加确定和可重现,这可以防止依赖项的更改带来地破坏构建问题。编写 Gradle 构建逻辑现在可以使用Kotlin编写Gradle构建脚本。此外,gradle init还扩展了项目类型和交互性。Kotlin DSL帮助信息Kotlin DSL 从1.0版本便提供了对Gradle的支持。Kotlin中的静态类型允许工具提供更好的IDE帮助,包括调试和重构构建脚本、自动完成和您期望的其他一切。如果您对用Kotlin编写构建感兴趣,可以从Gradle Kotlin DSL入门开始扩大和互动希望使用Gradle构建项目的用户可以选择其他项目类型一起使用,如kotlin-library和kotlin-application。此外,您可以选择生成Groovy或Kotlin DSL构建脚本,并自定义项目名称和包。更有指导性的文档此外,Gradle文档和入门指南提供了更多的信息,并且更容易发现和访问,主要体现在:改进了包括入门、故障排除、CLI引用、管理传递依赖关系,以及其他一些的一些页面。由Algolia DocSearch托管的可搜索参考文档。一个重新格式化的PDF供离线查看。分类导航。文档版本选择。更高效的内存执行更高效的内存执行命令行参数等特性允许更好的开发工作流,同时降低内存需求和缓存清理可以减少Gradle在系统上的开销。更低的内存要求升级Gradle 5.0 不仅会使构建速度更快,而且还会大大减少内存的使用。许多缓存机制在Gradle 5.0中得到了优化,并且Gradle进程的默认最大内存大大减少。Process Type Gradle 4.x default heap Gradle 5.0 default heap Command-line client 1 GB 64 MB Gradle Daemon 1 GB 512 MB Worker processes 1/4 of physical memory 512 MB 阶段性缓存清理现在,手动清理缓存的日子已经结束了,Gradle现在可以实现定期清理过期缓存。Gradle还更精确地跟踪陈旧的任务输出,并在不导致错误结果的情况下清理它们。新的 Gradle 调用选项JUnit 测试Gradle 5.0添加了对JUnit 5测试的支持:JUnit平台、JUnit Jupiter和JUnit Vintage。这将支持允许您启用测试分组和筛选,并包括定制的测试引擎。test { useJUnitPlatform { excludeTags ‘slow’ includeEngines ‘junit-vintage’ failFast = true }}您可以使用fail-fast标志来启用一个更快的红绿循环,默认情况下,第5.0版本将首先执行失败的测试,这进一步改进了该标志。日志在Gradle 5.0中,日志消息可以按照非交互环境(如持续集成执行),进行日志消息的任务分组。除了显示正在执行哪些测试之外,Gradle丰富的命令行控制台还显示了一个彩色的构建状态,可以一眼就看出是那些测试失败的情况。您还可以要求Gradle在任务使用“详细”控制台模式执行时记录它们。最后,通过配置警告模式,Gradle还可以总结、沉默或扩展Gradle警告日志。复合构建复合构建允许您包含其他独立项目,例如,您可以同时开发应用程序和依赖的库。现在您还可以使用构建扫描检查复合构建。复合构建还可以与continuous兼容。默认情况下它们是并行构建的,现在可以嵌套了。JVM命令行参数使用Gradle 5.0运行带有自定义参数的Java应用程序将比其他版本容易得多,因为您可以在命令行上或通过IDE简单地使用它们。新的 Gradle 任务和插件 APIGradle 5.0提供了许多新的api,这些api支持更快、更通用的构建逻辑。高性能API新的Worker API将允许您安全的并行和异步执行任务。按照我们的指南,使用Worker API为自定义任务启用更快的构建任务,下图展示了使用Worker API和不是也Worker API的区别。改进的I/O任务正确声明输入和输出对于增量构建和构建缓存行为至关重要。Gradle 5.0加强了约束,并为输入/输出声明引入了新的api,这些api可以帮助您避免一些低级问题。避免冗余配置有些项目在执行过程中会产生很多的任务,当只执行一些操作时,配置所有这些操作是没有意义的。这就是Gradle 5.0的新配置避免api的神奇之处。通过在自定义任务中采用这些配置,大型项目可以节省高达10%的配置时间。APIsGradle 5.0引入了新的api来改进对Maven和Ivy存储库的管理。主要包括:签名插件支持对发布的所有工件签名。发布了配置范围内的依赖项排除。Maven发布和Ivy发布插件提供类型安全的dsl来定制作为发布的一部分生成的pom或Ivy模块。任务超时处理现在您可以为任务指定超时时间,超时后任务将被中断。自定义Cli 参数Gradle 5.0提供允许用户配置自定义任务的新方法。首先,您可以使用@Option创建自定义命令行选项,用户可以通过执行gradle help——task your-task来执行。public class UrlVerify extends DefaultTask { private String url; @Option(option = “url”, description = “Configures the URL to be verified.”) public void setUrl(String url) { this.url = url; } @Input public String getUrl() { return url; } @TaskAction public void verify() { getLogger().quiet(“Verifying URL ‘{}’”, url); // verify URL by making a HTTP call }}定制嵌套dsl为使用内部api的任务Gradle提供自定义的嵌套DSL。Gradle 5.0为嵌套DSL元素提供了一流的api,在考虑用户如何配置任务时提供了更大的灵活性。Gradle 5.0为计算(或延迟)任务输入和输出提供了额外的API便利。这使得自定义任务时能够将Gradle模型连接在一起,而不用担心给定的属性值被修改,也不用担心在任务配置期间会避免资源密集型工作。升级指南为了升级到5.0版本。升级前,我们给出如下一些建议:使用Gradle包装器升级到Gradle 4.10.2。运行gradle帮助:扫描列出所有不推荐使用的gradle api及其位置,包括插件。更新您的Gradle插件,特别是那些在构建扫描的警告的插件。升级到JDK 8或更高版本,需要运行Gradle 5.0。如果遇到问题,请参阅故障排除指南或联系社区论坛,您也可以参考我们给出的升级文档。参考:Gradle 5.0都有哪些新特性 ...

November 29, 2018 · 2 min · jiezi

android gradle 3.0.0 中依赖指令implementation、api 的区别

AndroidStudio升级到3.0之后,gradle版本也随之升级到了3.0.0版本。classpath ‘com.android.tools.build:gradle:3.0.0'1在新建一个Android工程的时候,build.gradle中的依赖默认为implementation,而不是之前的compile。另外,gradle 3.0.0版本以上,还有依赖指令api。本文主要介绍下implementation和api的区别。新建工程默认生成的app的build.gradle文件中的依赖:dependencies {implementation fileTree(include: [’*.jar’], dir: ’libs’)implementation ‘com.android.support:appcompat-v7:26.1.0’implementation ‘com.android.support.constraint:constraint-layout:1.0.2’testImplementation ‘junit:junit:4.12’androidTestImplementation ‘com.android.support.test🏃1.0.1’androidTestImplementation ‘com.android.support.test.espresso:espresso-core:3.0.1’}12345678api 指令完全等同于compile指令,没区别,你将所有的compile改成api,完全没有错。implementation指令这个指令的特点就是,对于使用了该命令编译的依赖,对该项目有依赖的项目将无法访问到使用该命令编译的依赖中的任何程序,也就是将该依赖隐藏在内部,而不对外部公开。简单的说,就是使用implementation指令的依赖不会传递。例如,有一个module为testsdk,testsdk依赖于gson:implementation ‘com.google.code.gson:gson:2.8.2'1这时候,在testsdk里边的java代码是可以访问gson的。另一个module为app,app依赖于testsdk:implementation project(’:testsdk’)1这时候,因为testsdk使用的是implementation 指令来依赖gson,所以app里边不能引用gson。但是,如果testsdk使用的是api来引用gson:api ‘com.google.code.gson:gson:2.8.2'1则与gradle3.0.0之前的compile指令的效果完全一样,app的module也可以引用gson。这就是api和implementation的区别。建议在Google IO 相关话题的中提到了一个建议,就是依赖首先应该设置为implementation的,如果没有错,那就用implementation,如果有错,那么使用api指令。使用implementation会使编译速度有所增快。参考:http://blog.csdn.net/soslinke…https://zhuanlan.zhihu.com/p/...https://stackoverflow.com/que...http://blog.csdn.net/JF_1994/…

October 17, 2018 · 1 min · jiezi