gradle groovy_使用Gradle获取Groovy

gradle groovy

朋友不允许朋友写用户身份验证。 厌倦了管理自己的用户? 立即尝试Okta的API和Java SDK。 数分钟之内即可在任何应用程序中对用户进行身份验证,管理和保护。

在Java世界中,有两个主要的构建系统:Gradle和Maven。 构建系统主要管理潜在的复杂依赖关系网并编译项目。 还将已编译的项目以及所有资源和元文件打包到最终的.war.jar文件中。 对于简单的构建,Maven和Gradle之间的选择几乎是个人喜好之一,或者也许是您的CTO或技术经理的喜好。 他们俩都很棒。 但是,对于更复杂的项目,Gradle是赢家。

使用Gradle构建的利与弊

我个人喜欢Gradle; 我讨厌XML,并花了几年时间从事大型,复杂的Java / Groovy项目,如果没有Gradle,这是不可能的。 除了缺少XML之外,Gradle还使用Groovy或Kotlin编写的构建文件提供了灵活性和构建速度。 借助Kotlin或Groovy的全部功能以及Gradle API库,您可以创建功能强大且复杂的构建脚本。 这肯定是一种祝福和诅咒。

DSL(特定于域的语言)需要一些时间来适应,并且Gradle以难以学习而著称。 但是,我认为这主要是因为人们已经习惯了Maven。 使用Gradle,您实质上可以学习一种构建语言 ,而不仅仅是学习XML。 与仅在Maven中添加依赖项相比,充分利用Gradle无疑具有更高的学习曲线。 但是向Gradle文件添加依赖项实际上并不比在Maven中困难。 扩展和自定义Gradle构建要比编写Maven插件和自定义构建步骤简单得多。

Gradle还大大缩短了构建时间,尤其是在较大的项目中,因为Gradle仅处理已更改的任务和文件就做得很好。 此外,它提供了构建缓存和构建守护程序,使重复构建的性能更高。 而且,像Maven一样,它使用并行线程进行依赖关系解析和项目构建。 同样,对于小型,简单的构建,这种性能提升可能并不明显。 但是对于大型项目而言,这是巨大的。

因此,总结一下。 Gradle是:

  • 大型项目更快
  • 无限可定制==更陡峭的学习曲线
  • 使用Groovy或Kotlin代替XML

而Maven是:

  • 尝试和真实
  • 无处不在
  • 对于不需要自定义的较小项目更简单
  • 带有XML和尖括号

Groovy的优点

简要介绍一下Groovy。 Groovy是一种JVM语言,因为它可以编译为与Java相同的字节码,并且可以与Java类无缝地互操作。 Groovy是Java的向后兼容超集,这意味着Groovy可以透明地与Java库和代码交互。 但是,它还增加了许多新功能:可选的键入,函数式编程,运行时灵活性以及许多元编程内容。 它还极大地清理了Java中许多冗长的仪式代码。 Groovy尚未成为主流的开发语言,在很大程度上被Scala和Kotlin所取代,但是它在测试(由于其简化的语法和元编程功能)和构建系统中找到了利基。

依存关系

您需要在本教程中安装一些东西(以及注册Okta帐户):

Java:您可能已经安装了Java。 本教程至少需要Java 1.8。 如果不是,请导航到OpenJDK网站并安装它。 您还可以在OSX和Linux上使用Homebrew安装Java,方法是: brew cask install java

Gradle:通常使用Gradle构建,您实际上不必安装它。 Gradle提供了一个称为Gradle包装器的功能,该功能包括一个脚本,该脚本可下载正确的Gradle版本以自动构建项目。 但是,由于本教程是有关Gradle的教程,因此在本教程中,您可以继续进行安装。 纯娱乐。 Gradle可以通过自制软件, SDKMAN或通过下载来安装。 他们在Gradle网站上说明

Okta开发者帐户 :对于示例应用程序的身份验证部分,您将需要一个免费的Okta开发者帐户。 您将使用Okta作为OAuth / OIDC(OpenID Connect)提供商。 如果您还没有,请转到Okta注册页面并注册。 注意:首次登录时,您需要单击Admin按钮以进入开发人员控制台。

HTTPie :您将使用一个很棒的命令行实用程序来从命令行运行一些HTTP请求。 如果尚未安装,请访问他们的网站并安装。

下载样例项目

出于本教程的目的,我编写了一个简单的示例项目。 这是使用Spring Boot和Java编写的基本REST服务。 Spring Boot使构建安全的Java Web应用程序变得容易。 另外,我还包括使用OAuth 2.0 / OIDC(OpenID Connect)的JWT身份验证。 该项目使用的身份验证提供程序是Okta,即软件即服务身份管理提供程序。 您应该已经注册了一个免费的开发者帐户

请继续从GitHub页面下载或克隆示例项目,并检出start分支。

git clone https://github.com/oktadeveloper/okta-spring-boot-gradle-example.git -b start
cd reponame

了解

build.gradle文件是Gradle项目的核心。 在此处配置构建。 它相当于Maven的pom.xml (没有所有令人讨厌的尖括号–我是否提到我作为一个年轻的开发人员而受到XML的攻击,并且从未克服过?)

让我们来看一个。 这来自刚刚下载的示例项目。

// 1) configure the requirements to run the build script
buildscript { 
    // set a custom property 
    ext {  
       springBootVersion = '2.1.6.RELEASE'  
    }  
    // check for dependencies in Maven Central when resolving the
    // dependencies in the buildscript block
    repositories {  
       mavenCentral()  
    }  
    // we need the spring boot plugin to run the build script
    dependencies {  
       classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")  
    }  
}  
  
// 2) apply some plugins
apply plugin: 'java'  
apply plugin: 'org.springframework.boot'  
apply plugin: 'io.spring.dependency-management'  
  
// 3) set some standard properties
group = 'com.okta.springboottokenauth'  
version = '0.0.1-SNAPSHOT'  
sourceCompatibility = 1.8  
  
// 4) repos to search to resolve dependencies for the project
repositories {  
    mavenCentral()  
}  

// 5) project dependencies
dependencies {  
    implementation( 'com.okta.spring:okta-spring-boot-starter:1.2.1' )  
    implementation('org.springframework.boot:spring-boot-starter-security')  
    implementation('org.springframework.boot:spring-boot-starter-web')  
    testImplementation('org.springframework.boot:spring-boot-starter-test')  
    testImplementation('org.springframework.security:spring-security-test')  
}

理解Gradle构建文件的关键是认识到它是一个脚本,内置在Groovy DSL中。 粗略地讲,它是一个配置脚本,它调用定义了配置选项的一系列闭包(请考虑函数,更多有关此内容)。 它几乎看起来像JSON或属性文件,尽管从技术上来说这是非常错误的,但是作为起点并不遥远。

但是,真正的强大之处在于build.gradle是一个Groovy脚本。 因此,它可以执行任意代码并访问任何Java库,特定于构建的Gradle DSL和Gradle API。 您可能可以使用Gradle文件发射航天飞机。

Gradle

让我们从上至下查看脚本:

1) buildscript闭包配置构建脚本本身(与应用程序相对)所需的属性,依赖项和源存储库。

2)接下来, apply plugin ,令人震惊地,应用插件。 这些扩展了Gradle-Groovy DSL框架的基本功能:应用了java插件,以及Spring Boot和Spring依赖项管理。 Java插件将Gradle配置为期望标准Java项目目录结构: src/main/javasrc/main/resourcessrc/test/java等。可以将其配置为更改默认目录或添加新目录。 Gradle Java插件文档是细读更多信息的好地方。

3)接下来,将一些标准属性应用于构建。

4) repositories块定义了构建脚本将在哪里寻找依赖项。 Maven Central是最常见的( mavenCentral() ),但是也可以配置其他存储库,包括自定义存储库和本地存储库。 可以使用mavenLocal()将本地Maven缓存配置为存储库。 如果团队希望协调项目之间的构建,但又不想将项目构建文件实际捆绑在一起,这将很有帮助。

5)最后,定义项目依赖项。

标准的预定义闭包的顺序无关紧要,因为大多数build.gradle文件仅定义依赖项,设置项目属性并使用预定义的任务,因此文件中元素的顺序无关紧要。 例如,没有理由将repositories块放在dependencies块之前。 您可以将build.gradle文件看作只是Gradle在执行调用它的shell命令分配的任务之前读取的配置文件。

但是,当您开始使用Gradle的功能来定义自定义任务并执行任意代码时,它将变得更加复杂。 Gradle将以自上而下的方式读取build.gradle文件,并执行在其中找到的所有代码块; 根据这段代码的作用,它可以在脚本中创建强制排序。 此外,当您定义自定义任务和属性(在Gradle API中找不到)时,排序很重要,因为这些符号不会预先定义,因此必须在构建脚本中定义它们才能使用它们。

什么是封包?

回到Groovy刚问世时,函数式编程是相当小众的领域,将闭包之类的东西带入JVM感觉很疯狂。 如今,它变得更加普遍:Javascript中的每个函数都是闭包。 一般来说,闭包是具有范围的一流函数。

这意味着两件事:

  1. 闭包是可以在运行时作为变量传递的函数
  2. 闭包保留对定义它们的变量范围的访问

Java版本的闭包称为lambda。 这些是在1.8版中引入Java的,顺便说一句,这并不是在Groovy获得最初的流行和函数式编程起步的同时发生的。

为了演示lambda,请看一下名为LambdaTest.java的JUnit测试。

src/test/java/com/okta/springboottokenauth/LambdaTest.java

interface SimpleLambda {  
    public int sum(int x, int y);  
}  
  
public class LambdaTest {  
  
    // create a lambda function with an var  
    // encapsulated in its scope  
    public SimpleLambda getTheLambda(int offset) {  
        int scopedVar = offset;  
        return (int x, int y) -> x + y + scopedVar;  
    }  
  
    @Test  
    public void testClosure() {  
        // get and test a lambda/closure with offset = 1  
        SimpleLambda lambda1 = getTheLambda(1);  
        assertEquals(lambda1.sum(2,2), 5);  
  
        // get and test a lambda/closure with offset = 2  
        SimpleLambda lambda2 = getTheLambda(2);  
        assertEquals(lambda2.sum(2,2), 6);  
    }
}

这个示例有些人为,但是演示了lambda的两个基本属性。 在闭包或lambda函数中,实现是在getTheLambda(int offset)方法中定义的。 创建lambda时,将offset变量封装在闭包范围中并返回。 该lambda被分配给变量。 可以重复调用它,并且它将引用相同的作用域。 此外, 可以使用封装在单独范围内的新偏移量变量创建新的lambda,并将其分配给其他变量。

来自强大的面向对象的背景,封闭最初感觉就像虫洞在严格的对象范围连续体上打Kong一样,奇怪地将对象的各个部分随时间和空间连接在一起。

Gradle只是关闭

采取build.gradle文件的依赖项部分:

dependencies {  
    implementation( 'com.okta.spring:okta-spring-boot-starter:1.2.1' )  
    implementation('org.springframework.boot:spring-boot-starter-security')  
    ...
}

没有Groovy DSL速记,实际上是:

project.dependencies({
    implementation( 'com.okta.spring:okta-spring-boot-starter:1.2.1' )  
    implementation('org.springframework.boot:spring-boot-starter-security')  
    ... 
})

括号中的所有内容实际上都是传递给project.dependencies()方法的闭包。 project对象是Project类的实例, Project类是构建的主要API父类。

如您所见,这些函数将一系列依赖项作为字符串传递。 那么,为什么不只使用更传统的静态数据结构(如JSON,属性或XML)呢? 由于这些重载函数也可以接受闭包代码块,因此可以进行深度自定义。

Gradle网站上Project类文档中此块的定义:

dependencies {}
配置此项目的依赖项。
此方法针对此项目的DependencyHandler执行给定的关闭。 DependencyHandler作为闭包的委托传递给闭包。

我们不需要深入研究Groovy闭包,但是上面提到的委托对象是可分配的上下文对象。 它的用法就像绑定this Javascript一样,但是在这里,委托是一个单独的,可分配的变量,它使实际的执行范围保持不变并可以访问。

探索Gradle依赖项配置

依赖关系块内部是一系列配置和名称。

dependencies {
    configurationName dependencyNotation
}

我们的build.gradle文件使用两种配置: implementationtestImplementation

implementation()定义了编译时所需的依赖项。 这种配置方法称为compiletestImplementation()并定义了仅用于测试所需的依赖项(旧的testCompile )。

您可能会看到的另一个依赖项配置是runtimeOnlytestRuntimeOnly 。 这声明了运行时提供的不需要进行编译的依赖项。

定义依赖关系的方法比对本文的范围有用的方法更多。 几乎可以说任何东西都可以是依赖项:本地文件,jar目录,另一个Gradle项目等…,并且可以将依赖项配置为执行某些操作,例如排除某些子依赖项。

值得注意的是:Gradle和Maven不能以完全相同的方式解析依赖关系。 您可以在Maven项目和Gradle项目中具有相同的依赖关系集,最终在一个问题而不是另一个问题中遇到依赖关系问题。

例如,假设我们想从Okta Spring Boot Starter中排除Log4j依赖关系,我们可以这样做:

dependencies {  
    implementation( 'com.okta.spring:okta-spring-boot-starter:1.2.1' ) {
        exclude group: 'org.apache.logging.log4j', module: 'log4j-api'
    }
}

或者说我们想将libs目录中的所有文件都包含为依赖项:

dependencies {  
    implementation fileTree('libs')
}

完整的符号记录在Gradency文档站点上的DependencyHandlerJava插件的Gradle文档中

包装Gradle版本

关于Gradle的一件很棒的事情是Gradle包装器。 Gradle命令行是gradle 。 但是,您会注意到在网上的很多地方,您都会看到./gradlewgradlew.bat 。 这些是调用包装程序的命令。

包装器允许项目捆绑在项目本身内部构建项目所需的Gradle版本。 这样可以确保对Gradle的更改不会破坏构建,因为正确的版本也将始终可用。 它还可以确保即使没有安装Gradle,人们也可以运行构建。

它将以下文件添加到您的项目:

├── gradle
│   └── wrapper
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew
└── gradlew.bat

gradlewgradlew.bat分别是Linux / OSX和Window的执行脚本。 他们使用gradle/wrapper子目录中捆绑的Gradle .jar运行build.gradle文件。

该项目使用Gradle 5.5版本包装,如果按照建议安装了Gradle,则可以顺利运行该项目。 但是,您可以使用包装器轻松完成整个教程。

任务,任务和更多任务

任务是Gradle的核心。 Java插件添加了许多任务,包括: cleancompiletestjaruploadArchives 。 Spring Boot插件添加了bootRun任务,该任务运行Spring Boot应用程序。

通常,任务是这样运行的: gradle taskName otherTaskName ,或使用包装器: ./gradlew taskName otherTaskName

如果打开终端并cd到示例项目的基本目录,则可以使用gradle tasks列出build.gradle文件定义的所有任务。 tasks本身就是由基本Gradle API定义的任务。

> Task :tasks

------------------------------------------------------------
Tasks runnable from root project
------------------------------------------------------------

Application tasks
-----------------
bootRun - Runs this project as a Spring Boot application.

Build tasks
-----------
assemble - Assembles the outputs of this project.
bootJar - Assembles an executable jar archive containing the main classes and their dependencies.
build - Assembles and tests this project.
buildDependents - Assembles and tests this project and all projects that depend on it.
buildNeeded - Assembles and tests this project and all projects it depends on.
classes - Assembles main classes.
clean - Deletes the build directory.
jar - Assembles a jar archive containing the main classes.
testClasses - Assembles test classes.

Build Setup tasks
-----------------
init - Initializes a new Gradle build.
wrapper - Generates Gradle wrapper files.

Documentation tasks
-------------------
javadoc - Generates Javadoc API documentation for the main source code.

Help tasks
----------
buildEnvironment - Displays all buildscript dependencies declared in root project 'SpringBootGradleProject'.
components - Displays the components produced by root project 'SpringBootGradleProject'. [incubating]
dependencies - Displays all dependencies declared in root project 'SpringBootGradleProject'.
dependencyInsight - Displays the insight into a specific dependency in root project 'SpringBootGradleProject'.
dependencyManagement - Displays the dependency management declared in root project 'SpringBootGradleProject'.
dependentComponents - Displays the dependent components of components in root project 'SpringBootGradleProject'. [incubating]
help - Displays a help message.
model - Displays the configuration model of root project 'SpringBootGradleProject'. [incubating]
projects - Displays the sub-projects of root project 'SpringBootGradleProject'.
properties - Displays the properties of root project 'SpringBootGradleProject'.
tasks - Displays the tasks runnable from root project 'SpringBootGradleProject'.

Verification tasks
------------------
check - Runs all checks.
test - Runs the unit tests.

...

我想指出dependencies任务。 它将列出一棵树,其中包含项目所需的所有依赖关系(包括子依赖关系)。 尝试在项目根目录中运行gradle dependencies 。 您可以使用dependencyInsight任务深入查看特定的子dependencyInsight项。

故障排除的另一个有用的任务是properties任务,该任务列出了在根项目对象实例上定义的所有属性。

当然,在开发Spring Boot项目时,十分之九,我使用的命令是: ./gradlew bootJar 。 这是一个由Spring Boot Gradle插件添加的任务,该任务将项目及其依赖项打包在一个jar文件中。

创建自定义任务

打开build.gradle文件,并在末尾添加以下内容:

println "1"  
  
task howdy {  
    println "2"  
    doLast {  
        println "Howdy"  
    }  
}  
  
println "3"

这将演示有关Gradle脚本如何工作的一些信息。 使用以下命令运行它:

./gradlew howdy

您将看到(省略了一些多余的行):

> Configure project :
1
2
3

> Task :howdy
Howdy

在这里,“ Configure project任务将生成并运行生成脚本。 当Gradle执行Configure project任务时,它会执行以下操作:

  • 它到达第一个println并打印“ 1”
  • 它找到您要howdy任务任务定义块,一个闭包,并显示“ 2”。 请注意,它不会执行doLast闭包,因此尚未打印“ A”。
  • 它继续执行脚本,并打到第四个println ,并打印“ 3”。

至此,构建脚本本身已完成对构建环境的配置。 下一步是执行命令行上指定的所有任务,在本例中为howdy任务。

这是task.doLast {}块的执行位置,因此您会在输出中看到“ Howdy”。

doLast是该块的误称;它的真正含义是类似于“任务操作”,而外部块是任务设置和配置。 见下文。

task howdy {  
    // always executed at during initial build script configuration
    doLast {  
        // only executed if task itself is invoked  
    }
    // always executed at during initial build script configuration  
}

使用Graovy DSL根据Gradle文档定义任务的各种方式如下:

task taskName
task taskName { configure closure }
task taskName(type: SomeType)
task taskName(type: SomeType) { configure closure }

只是为了doLast ,在运行构建脚本时立即执行 “配置闭包”,而在明确执行任务时执行在配置闭包中定义的doLast闭包。

将第二个自定义任务添加到build.gradle文件:

task partner {  
    println "4"  
    doLast {  
        println "Partner"  
    }  
}  
println "5"

如果您是./gradlew partner ,您将看到:

> Configure project :
1
2
3
4
5

> Task :partner
Partner

如果您希望一个自定义任务依赖另一个任务怎么办? 这很容易。 在两个自定义任务的定义之后, build.gradle添加到build.gradle文件中的某处。

partner.dependsOn howdy

并运行: ./gradlew partner

...
> Task :howdy
Howdy

> Task :partner
Partner

您还可以使用task属性finalizedBy表示类似的关系。 如果用以下内容替换dependsOn行:

howdy.finalizedBy partner

并运行: /gradlew howdy

...
> Task :howdy
Howdy

> Task :partner
Partner

am! 您好伙伴。

您得到相同的输出。 当然,他们表达不同的关系。

有很多选项。 这是Gradle令人困惑的声誉的部分来源。 Task APIGradle文档是一个很好的参考。

关于任务的最后一点:在实践中,您很少编写自定义任务来表达诸如“ Howdy Partner”之类的东西(很难相信,我知道)。 实际上,通常您会覆盖已经定义的任务类型。 例如,Gradle定义了Copy文件从一个位置复制到另一位置的Copy任务。

这是一个将文档复制到构建目标的示例:

task copyDocs(type: Copy) {
    from 'src/main/doc'
    into 'build/target/doc'
}

当您意识到因为build.gradle文件实际上是Groovy脚本时,Groovy和Gradle才真正发挥作用,您可以根据需要执行任意代码来过滤和转换这些文件。

下面的任务将转换每个副本文件,并排除.DS_Store文件。 DSL非常灵活。 您可以有多个from块并excludes ,也可以执行诸如重命名文件或专门包含文件之类的操作。 再次查看“复制”任务的文档以获取更完整的想法。

task copyDocs(type: Copy) {
    from 'src/main/doc'
    into 'build/target/doc'
    eachFile { file ->
	    doSomething(file);
    }
    exclude '**/.DS_Store'
}

在Gradle JarWar ,我最优先执行的任务是负责打包.jar.war文件以进行最终分发的任务。 像“ Copy任务一样,它们具有自定义过程的开放式功能,这对于需要自定义最终产品的项目可能会提供巨大帮助。 实际上,您可以使用Gradle DSL来完全控制打包过程的各个方面。 (当然,强大的力量伴随着巨大的责任)。

Spring Boot插件的bootJarbootWar任务继承自JarWar任务,因此它们包括其所有配置选项,包括复制,过滤和修改文件的能力以及自定义清单的能力。

创建一个OIDC应用程序

既然您是高级Gradle忍者(或者至少希望它不受Gradle DSL的威胁),现在该回到原始的Spring Boot项目了。

转到Okta开发人员仪表板以创建OpenID Connect应用程序。

单击应用程序顶部菜单。 单击添加应用程序按钮。

选择应用程序类型Web

单击下一步

为应用命名。 我将其命名为“ Spring Boot Gradle Demo”。

登录重定向URI下,添加值: https://oidcdebugger.com/debug : https://oidcdebugger.com/debug

在“ 允许的授予类型”下 ,单击“ 隐式(混合)”旁边的复选框。

其余的默认值将起作用。

单击完成

让页面保持打开状态,注意客户端ID 。 稍后您将需要它来生成JWT。

更新Spring Boot应用程序

您需要对Spring Boot应用程序进行一些更改。 首先,如果需要,从build.gradle文件中删除所有Howdy Partner资料。 它实际上并没有伤害任何东西,但现在不再需要了。

将以下闭合添加到build.gradle文件的底部:

processResources {  
    expand(project.properties)  
}

这将配置Java任务,以将项目属性扩展到资源文件中。

如果您查看src/main/resources/application.yml文件:

okta:  
  oauth2:  
    issuer: ${oauthIssuer}

您会注意到,我们要填写两个属性。最好的方法是使用gradle.properties文件。

在项目根目录中创建gradle.properties文件:

oauthIssuer={yourIssuerUri}

您需要填写两个值。 客户端ID来自您刚创建的OIDC应用。 发行者URI如下所示: https://dev-123456.oktapreview.com/oauth2/default : https://dev-123456.oktapreview.com/oauth2/default ,可以在Okta开发人员仪表板中找到。 转到API并选择“ 授权服务器” 。 在表中查找默认授权服务器和颁发者URI值。

使用OIDC调试器生成令牌

使用OIDC调试器为您的OIDC应用程序生成令牌。

您将需要填写:

  • 授权URI与您的Okta开发人员URI匹配
  • 客户端ID与OIDC应用程序客户端ID相匹配
  • 声明什么都可以,只是不能空白。 在生产中, 状态有助于防止跨站点伪造请求,并且应该是CSRF令牌。

完成此操作后,向下滚动并点击发送请求

您应该看到成功屏幕。

复制访问令牌,打开终端,然后将其存储在如下的shell变量中:

export TOKEN=eyJraWQiOiJxMm5rZmtwUDRhMlJLV2REU2JfQ09LTlFD...

使用令牌运行请求

Spring Boot应用程序定义了一个控制器: HelloController.java

// ...
  
@RestController
public class HelloController {  The Spring Boot app defines one contr
  
    // REQUIRES AUTHENTICATION  
    @RequestMapping("/")  
    public String home(java.security.Principal user) {  
        return "Hello " + user.getName() + "!";  
    }  
    
    // DOES NOT REQUIRE AUTHENTICATION  
    @RequestMapping("/allow-anonymous")  
    public String anonymous() {  
        return "Hello whoever!";  
    } 
}

有两个端点。 尽管从控制器文件本身并不明显,但/终结点需要身份验证,而/allow-anonymous终结点则不需要。 为此的配置在Application.java文件的configure(HttpSecurity http)方法中进行。 我在这里介绍了Spring Boot的细节,因为这不是本教程的重点,并且在其他博客文章中也对此进行了详细介绍(请参阅最后的链接)。

从一个单独的shell(而不是您刚刚保存TOKEN var的shell)中,使用以下命令运行Spring Boot应用程序:

./gradlew bootRun

回到带有TOKEN var的外壳中,运行一个包含JWT的HTTP请求:

http :8080 "Authorization: Bearer $TOKEN"

您将获得一个HTTP 200:

HTTP/1.1 200
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
...

Hello andrew.hughes@example.com!

成功!

您可以在没有JWT的情况下运行请求以查看是否需要auth:

http :8080
HTTP/1.1 401
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Length: 0
...

有关Spring Boot应用程序和身份验证/授权的更多详细信息,请查看最后的链接以获取更多博客文章。

下一步是编写一些测试,并使用Gradle运行它们。

测试代码

创建一个测试文件: src/test/java/com/okta/springbootgradle/HelloControllerTest.java

package com.okta.springbootgradle;  
  
import org.junit.Test;  
import org.junit.runner.RunWith;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;  
import org.springframework.boot.test.context.SpringBootTest;  
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;  
import org.springframework.boot.web.server.LocalServerPort;  
import org.springframework.test.context.junit4.SpringRunner;  
import org.springframework.test.web.servlet.MockMvc;  
  
import static org.hamcrest.Matchers.containsString;  
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;  
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;  
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;  
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;  
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;  
  
@RunWith(SpringRunner.class)  
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = {"okta.oauth2.issuer=https://oauth.example.com/oauth2/default"})  
@AutoConfigureMockMvc  
public class HelloControllerTest {  
  
    @LocalServerPort  
    private int port;  
  
    @Autowired  
    private MockMvc mockMvc;  
      
    // test for auth required on home endpoine
    @Test  
    public void homeShouldFail() throws Exception {  
        this.mockMvc  
            .perform(get("/"))  
            .andDo(print())  
            .andExpect(status().isUnauthorized());  
    } 
    
    // test home endpoint with auth
    @Test  
    public void homeShouldPass() throws Exception {  
        this.mockMvc  
            .perform(get("/").with(user("Mister Tester")))  
            .andDo(print())  
            .andExpect(status().isOk())  
            .andExpect(content().string(containsString("Hello Mister Tester!")));  
    }  
      
    // test anonymous endpoint
    @Test  
    public void anonymous() throws Exception {  
        this.mockMvc  
            .perform(get("/allow-anonymous"))  
            .andDo(print())  
            .andExpect(status().isOk())  
            .andExpect(content().string(containsString("Hello whoever!")));;  
    } 
}

该测试文件包含三个测试。 第一个测试检查本地端点,以确保不提供身份验证的请求失败并出现未授权错误。 第二个测试使用Spring MockMVC库提供身份验证并再次测试本地端点。 最后一个测试检查/allow-anonymous端点。

使用以下./gradlew test运行测试: ./gradlew test

输出非常小:

> Task :test
INFO [Thread-6] o.s.s.c.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'

BUILD SUCCESSFUL in 7s
5 actionable tasks: 5 executed

如果您想查看更多信息,请尝试添加-i标志,如下所示:

./gradlew test -i

使用Spring进行的测试本身就是一个完整的教程,因此我将其保留下来。 Spring的不错的指南介绍了一些测试Spring Boot REST服务的不同方法。

我永远不会宽恕这一点,但是如果您需要运行构建并希望跳过测试,则可以使用: gradle build -x test

像Gradle一样, Test任务是高度可定制的。 您可以设置特定于测试的系统属性,配置JVM参数,更改堆大小,包括或排除特定测试等,等等。在Gradle页面上查看Test任务的文档

您还可以在master分支的GitHub页面上查看项目的最终状态。

结语

在本教程中,您学习了Gradle构建系统的基础知识。 您已经看到Gradle具有高度的灵活性和可定制性,可以与Groovy DSL或Kotlin DSL一起使用。 您查看了教程项目中的示例build.gradle文件,并了解了如何配置典型的构建。 接下来,本教程深入探讨了闭包的世界,并了解了如何在Gradle DSL中使用它们来创建配置块。 之后,您使用Gradle包装器将项目构建系统封装在项目本身内,然后深入Gradle任务,创建自定义任务以及查看如何处理和执行任务。 还有更多! 哈哈。 然后,教程向您展示了如何使用Gradle构建和运行简单的Spring Boot项目,以及如何使用Spring和Gradle定义和运行一些测试。

如所承诺的,如果您想了解有关Spring Boot和Java的更多信息,Okta博客将提供大量的出色教程:

如果您喜欢这篇文章,请在社交媒体{ TwitterFacebookLinkedInYouTube }上关注我们,以了解我们何时发布类似的信息。

使用Gradle获取Groovy最初于2019年9月7日发布在Okta开发人员博客上。

朋友不允许朋友写用户身份验证。 厌倦了管理自己的用户? 立即尝试Okta的API和Java SDK。 数分钟之内即可在任何应用程序中对用户进行身份验证,管理和保护。

翻译自: https://www.javacodegeeks.com/2019/11/get-groovy-with-gradle.html

gradle groovy

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值