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/java
, src/main/resources
, src/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中的每个函数都是闭包。 一般来说,闭包是具有范围的一流函数。
这意味着两件事:
- 闭包是可以在运行时作为变量传递的函数
- 闭包保留对定义它们的变量范围的访问
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
文件使用两种配置: implementation
和testImplementation
。
implementation()
定义了编译时所需的依赖项。 这种配置方法称为compile
。 testImplementation()
并定义了仅用于测试所需的依赖项(旧的testCompile
)。
您可能会看到的另一个依赖项配置是runtimeOnly
和testRuntimeOnly
。 这声明了运行时提供的不需要进行编译的依赖项。
定义依赖关系的方法比对本文的范围有用的方法更多。 几乎可以说任何东西都可以是依赖项:本地文件,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文档站点上的DependencyHandler和Java插件的Gradle文档中 。
包装Gradle版本
关于Gradle的一件很棒的事情是Gradle包装器。 Gradle命令行是gradle
。 但是,您会注意到在网上的很多地方,您都会看到./gradlew
或gradlew.bat
。 这些是调用包装程序的命令。
包装器允许项目捆绑在项目本身内部构建项目所需的Gradle版本。 这样可以确保对Gradle的更改不会破坏构建,因为正确的版本也将始终可用。 它还可以确保即使没有安装Gradle,人们也可以运行构建。
它将以下文件添加到您的项目:
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
└── gradlew.bat
gradlew
和gradlew.bat
分别是Linux / OSX和Window的执行脚本。 他们使用gradle/wrapper
子目录中捆绑的Gradle .jar
运行build.gradle
文件。
该项目使用Gradle 5.5版本包装,如果按照建议安装了Gradle,则可以顺利运行该项目。 但是,您可以使用包装器轻松完成整个教程。
任务,任务和更多任务
任务是Gradle的核心。 Java插件添加了许多任务,包括: clean
, compile
, test
, jar
和uploadArchives
。 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 API的Gradle文档是一个很好的参考。
关于任务的最后一点:在实践中,您很少编写自定义任务来表达诸如“ 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 Jar
或War
,我最优先执行的任务是负责打包.jar
和.war
文件以进行最终分发的任务。 像“ Copy
任务一样,它们具有自定义过程的开放式功能,这对于需要自定义最终产品的项目可能会提供巨大帮助。 实际上,您可以使用Gradle DSL来完全控制打包过程的各个方面。 (当然,强大的力量伴随着巨大的责任)。
Spring Boot插件的bootJar
和bootWar
任务继承自Jar
和War
任务,因此它们包括其所有配置选项,包括复制,过滤和修改文件的能力以及自定义清单的能力。
创建一个OIDC应用程序
既然您是高级Gradle忍者(或者至少希望它不受Gradle DSL的威胁),现在该回到原始的Spring Boot项目了。
转到Okta开发人员仪表板以创建OpenID Connect应用程序。
单击应用程序顶部菜单。 单击添加应用程序按钮。
选择应用程序类型Web 。
单击下一步 。
为应用命名。 我将其命名为“ Spring Boot Gradle Demo”。
在登录重定向URI下,添加值: https://oidcdebugger.com/debug
: https://oidcdebugger.com/debug
。
在“ 允许的授予类型”下 ,单击“ 隐式(混合)”旁边的复选框。
其余的默认值将起作用。
![](https://i-blog.csdnimg.cn/blog_migrate/10fd32b92ac4ffd975d340cc5b03b33e.png)
单击完成 。
让页面保持打开状态,注意客户端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令牌。
![](https://i-blog.csdnimg.cn/blog_migrate/0d1c03873334b5e4e722547bfdfc998c.png)
完成此操作后,向下滚动并点击发送请求 。
您应该看到成功屏幕。
![](https://i-blog.csdnimg.cn/blog_migrate/06f2c85304754535ee8cdf62bdb9925a.png)
复制访问令牌,打开终端,然后将其存储在如下的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博客将提供大量的出色教程:
- Java应用程序的简单令牌认证
- Java的Servlet身份验证
- 在15分钟内使用Spring Boot和Spring Security构建一个Web应用程序
- 使用Java,MicroProfile和JWT身份验证构建REST API
- 创建一个安全的Spring REST API
- 使用Spring Boot和Vue.js构建一个简单的CRUD应用
如果您喜欢这篇文章,请在社交媒体{ Twitter , Facebook , LinkedIn , YouTube }上关注我们,以了解我们何时发布类似的信息。
使用Gradle获取Groovy最初于2019年9月7日发布在Okta开发人员博客上。
朋友不允许朋友写用户身份验证。 厌倦了管理自己的用户? 立即尝试Okta的API和Java SDK。 数分钟之内即可在任何应用程序中对用户进行身份验证,管理和保护。
翻译自: https://www.javacodegeeks.com/2019/11/get-groovy-with-gradle.html
gradle groovy