spark rest_Spark简介,您的下一个REST Java框架
spark rest
我希望您今年Java來了! 今天,我們將研究一個清新,簡單,美觀且實用的框架,以Java編寫REST應用程序。 它將非常簡單,甚至根本不會看起來像Java。
我們將研究Spark Web框架。 不,它與Apache Spark不相關。 是的,很遺憾,他們使用相同的名字。
我認為理解該框架的最佳方法是構建一個簡單的應用程序,因此我們將構建一個簡單的服務來執行數學運算。
我們可以這樣使用它:
請注意,該服務正在本地主機上的端口4567上運行,并且請求的資源為“ / 10 / add / 8”。
使用Gradle設置項目(
apply plugin: "java" apply plugin: "idea"sourceCompatibility = 1.8repositories {mavenCentral()maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }maven { url "https://oss.sonatype.org/content/repositories/releases/" } }dependencies {compile "com.javaslang:javaslang:2.0.0-RC1"compile "com.sparkjava:spark-core:2.3"compile "com.google.guava:guava:19.0-rc2"compile "org.projectlombok:lombok:1.16.6"testCompile group: 'junit', name: 'junit', version: '4.+' }task launch(type:JavaExec) {main = "me.tomassetti.javaadvent.SparkService"classpath = sourceSets.main.runtimeClasspath }現在我們可以運行:
- 。 / gradlew想法來生成IntelliJ IDEA項目
- 。 / gradlew測試以運行測試
- 。 / gradlew組裝以構建項目
- 。 / gradlew啟動以啟動我們的服務
現在,讓我們認識Spark
您認為我們可以編寫一個功能齊全的Web服務,用不到25行Java代碼執行基本的數學運算嗎? 沒門? 好吧,再想想:
// imports omittedclass Calculator implements Route {private Map<String, Function2<Long, Long, Long>> functions = ImmutableMap.of("add", (a, b) -> a + b,"mul", (a, b) -> a * b,"div", (a, b) -> a / b,"sub", (a, b) -> a - b);@Overridepublic Object handle(Request request, Response response) throws Exception {long left = Long.parseLong(request.params(":left"));String operatorName = request.params(":operator");long right = Long.parseLong(request.params(":right"));return functions.get(operatorName).apply(left, right);} }public class SparkService {public static void main(String[] args) {get("/:left/:operator/:right", new Calculator());} }在我們的主要方法中,我們只是說,當我們得到一個包含三個部分(用斜杠分隔)的請求時,我們應該使用計算器路線,這是我們唯一的路線。 Spark中的路由是接收請求,處理請求并產生響應的單元。
我們的計算器就是神奇的地方。 它在請求中查找參數“ left”,“ operatorName”和“ right”。 左右被解析為長值,而operatorName用于查找操作。 對于每個操作,我們都有一個函數(Function2 <Long,Long>),然后將其應用于我們的值(左和右)。 酷吧?
Function2是來自Javaslang項目的接口。
您現在可以啟動該服務( ./gradlew啟動,還記得嗎?)并進行播放。
我上次檢查Java時比較冗長,冗長,緩慢……好吧,它現在正在恢復。
好的,但是測試呢?
因此Java實際上可以非常簡潔,作為軟件工程師,我會慶祝一兩分鐘,但是不久之后我就開始感到不安……這些東西沒有經過測試! 更糟糕的是,它看起來根本無法測試。 邏輯在我們的計算器類中,但是它接受一個Request并生成一個Response。 我不想實例化一個請求只是為了檢查我的計算器是否按預期工作。 讓我們重構一下:
class TestableCalculator implements Route {private Map<String, Function2<Long, Long, Long>> functions = ImmutableMap.of("add", (a, b) -> a + b,"mul", (a, b) -> a * b,"div", (a, b) -> a / b,"sub", (a, b) -> a - b);public long calculate(String operatorName, long left, long right) {return functions.get(operatorName).apply(left, right);}@Overridepublic Object handle(Request request, Response response) throws Exception {long left = Long.parseLong(request.params(":left"));String operatorName = request.params(":operator");long right = Long.parseLong(request.params(":right"));return calculate(operatorName, left, right);} }我們只是將管道(從請求中取出值)與邏輯分開,并將其放入自己的方法中: calculate 。 現在我們可以測試計算了。
public class TestableLogicCalculatorTest {@Testpublic void testLogic() {assertEquals(10, new TestableCalculator().calculate("add", 3, 7));assertEquals(-6, new TestableCalculator().calculate("sub", 7, 13));assertEquals(3, new TestableCalculator().calculate("mul", 3, 1));assertEquals(0, new TestableCalculator().calculate("div", 0, 7));}@Test(expected = ArithmeticException.class)public void testInvalidInputs() {assertEquals(0, new TestableCalculator().calculate("div", 0, 0));}}我現在感覺好多了:我們的測試證明了這些東西是行得通的。 當然,如果我們嘗試除以零,它將引發異常,但是事實就是這樣。
但是,這對用戶意味著什么?
這意味著:500。如果用戶嘗試使用一個不存在的操作,會發生什么?
如果值不是正確的數字怎么辦?
好的,這似乎不是很專業。 讓我們修復它。
錯誤處理,功能風格
要解決這兩種情況,我們只需要使用Spark的一項功能即可:我們可以將特定的異常與特定的路線進行匹配。 我們的路由將產生有意義的HTTP狀態代碼和正確的消息。
public class SparkService {public static void main(String[] args) {exception(NumberFormatException.class, (e, req, res) -> res.status(404));exception(ArithmeticException.class, (e, req, res) -> {res.status(400);res.body("This does not seem like a good idea");});get("/:left/:operator/:right", new ReallyTestableCalculator());} }我們仍然要處理不存在的操作的情況,這是我們將在ReallyTestableCalculator中進行的操作 。
為此,我們將使用典型的函數模式:我們將返回Either 。 Either是可以具有left或right值的集合。 左側通常表示有關錯誤的某種信息,例如錯誤代碼或錯誤消息。 如果沒有任何問題,Either都將包含一個正確的值,可能是各種各樣的東西。 在本例中,如果無法執行操作,則將返回錯誤(我們定義的類),否則將以Long形式返回操作的結果。 因此,我們將返回Either <Error,Long>。
package me.tomassetti.javaadvent.calculators;import javaslang.Function2; import javaslang.Tuple2; import javaslang.collection.Map; import javaslang.collection.HashMap; import javaslang.control.Either; import spark.Request; import spark.Response; import spark.Route;public class ReallyTestableCalculator implements Route {private static final int NOT_FOUND = 404;private Map<String, Function2<Long, Long, Long>> functions = HashMap.ofAll(new Tuple2<>("add", (a, b) -> a + b),new Tuple2<>("mul", (a, b) -> a * b),new Tuple2<>("div", (a, b) -> a / b),new Tuple2<>("sub", (a, b) -> a - b));public Either<Error, Long> calculate(String operatorName, long left, long right) {Either<Error, Long> unknownOp = Either.<Error, Long>left(new Error(NOT_FOUND, "Unknown math operation"));return functions.get(operatorName).map(f -> Either.<Error, Long>right(f.apply(left, right))).orElse(unknownOp);}@Overridepublic Object handle(Request request, Response response) throws Exception {long left = Long.parseLong(request.params(":left"));String operatorName = request.params(":operator");long right = Long.parseLong(request.params(":right"));Either<Error, Long> res = calculate(operatorName, left, right);if (res.isRight()) {return res.get();} else {response.status(res.left().get().getHttpCode());return null;}} }讓我們測試一下:
package me.tomassetti.javaadvent;import javaslang.control.Either; import me.tomassetti.javaadvent.calculators.ReallyTestableCalculator; import org.junit.Test;import static org.junit.Assert.assertEquals;public class ReallyTestableLogicCalculatorTest {@Testpublic void testLogic() {assertEquals(Either.right(10L), new ReallyTestableCalculator().calculate("add", 3, 7));assertEquals(Either.right(-6L), new ReallyTestableCalculator().calculate("sub", 7, 13));assertEquals(Either.right(3L), new ReallyTestableCalculator().calculate("mul", 3, 1));assertEquals(Either.right(0L), new ReallyTestableCalculator().calculate("div", 0, 7));}@Test(expected = ArithmeticException.class)public void testInvalidOperation() {Either<me.tomassetti.javaadvent.calculators.Error, Long> res = new ReallyTestableCalculator().calculate("div", 0, 0);assertEquals(true, res.isLeft());assertEquals(400, res.left().get().getHttpCode());}@Testpublic void testUnknownOperation() {Either<me.tomassetti.javaadvent.calculators.Error, Long> res = new ReallyTestableCalculator().calculate("foo", 0, 0);assertEquals(true, res.isLeft());assertEquals(404, res.left().get().getHttpCode());}}結果
我們提供了可以輕松測試的服務。 它執行數學運算。 它支持四個基本操作,但可以輕松擴展以支持更多操作。 處理錯誤并使用適當的HTTP代碼:400(錯誤輸入)和404(未知操作或值)。
結論
當我第一次看到Java 8時,我對新功能感到滿意,但并不十分興奮。 但是,幾個月后,我看到了基于這些新功能的新框架,它們有可能真正改變我們用Java編程的方式。 Spark和Javaslang之類的東西正在發揮作用。 我認為現在Java可以保持簡單而可靠,同時變得更加敏捷和高效。
- 您可以在Spark教程網站或我的博客tomassetti.me上找到更多教程。
翻譯自: https://www.javacodegeeks.com/2015/12/introduction-spark-next-rest-framework-java.html
spark rest
總結
以上是生活随笔為你收集整理的spark rest_Spark简介,您的下一个REST Java框架的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 招聘备案制(选聘备案制)
- 下一篇: (DDOS攻击小组件素材白色)