Spark简介,您的下一个REST Java框架

希望今年您对Java的热情很高! 今天,我们将研究一个清新,简单,美观且实用的框架,以Java编写REST应用程序。 它将非常简单,甚至根本不会看起来像Java。

我们将研究Spark Web框架。 不,它与Apache Spark不相关。 是的,很遗憾,他们使用相同的名字。

我认为理解该框架的最佳方法是构建一个简单的应用程序,因此我们将构建一个简单的服务来执行数学运算。

我们可以这样使用它:

火花1

请注意,该服务正在本地主机上的端口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));}}

我现在感觉好多了:我们的测试证明了这些东西是行得通的。 当然,如果我们尝试除以零,它将引发异常,但是事实就是这样。

但是,这对用户意味着什么?

星火2

这意味着:500。如果用户尝试使用一个不存在的操作,会发生什么?

星火3

如果值不是正确的数字怎么办?

星火4

好的,这似乎不是很专业。 让我们修复它。

错误处理,功能风格

要解决这两种情况,我们只需要使用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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/355278.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

jq的插件 vue中引用_详解如何在 vue 项目里正确地引用 jquery 和 jquery-ui的插件

本篇文章主要介绍了详解如何在 vue 项目里正确地引用 jquery 和 jquery-ui的插件&#xff0c;具有一定的参考价值&#xff0c;有兴趣的可以了解一下使用vue-cli构建的vue项目&#xff0c;webpack的配置文件是分散在很多地方的&#xff0c;而我们需要修改的是build/webpack.base…

SQL Search

Press TAB to expand wildcard tab键之后&#xff0c;会自动展开&#xff0c;直接枚举表中所有的字段 根据名字查找存储过程&#xff0c;发现找不到 原因是&#xff0c;本地是一个备份库。服务器上通过sql source control进行版本控制的。 在通过sql source control将服务器上新…

Java日期工具类

Java日期工具类对日期格式进行转化&#xff0c;例如&#xff0c;将2018-12-13转化成20181213&#xff0c;也可以反过来。 package main.java.utils;import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date;public class DateUtil {/*** …

两个数组合成一个json对象_两个jsonarray合并

技术文档主体内容&#xff1a;可以认为是页面最想表达的内容总和。对于内容详情页来说&#xff0c;主体内容指从标题开始至正文内容结束&#xff0c;翻页区域也被视为主体内容&#xff0c;文章后的评论、分享、推荐等不视为主体内容。首屏&#xff1a;用户点击搜索结果后进入移…

04_传智播客iOS视频教程_类是以Class对象存储在代码段

1231312转载于:https://www.cnblogs.com/ZHONGZHENHUA/p/7097077.html

drools的guvnor_Drools Guvnor –管理访问

drools的guvnor外部化业务或技术规则对于可伸缩应用程序非常重要&#xff0c;但是应该管理BRMS服务访问。 guvnor使用基于角色的授权提供控件UI访问和操作。 在drools-guvnor参考手册中列出了几种权限类型。 具有所有权限的管理员。 分析师或只读分析师&#xff1a;特定类别的分…

安卓实现序列化之Parcelable接口

安卓实现序列化之Parcelable接口 1.实现序列化的方法&#xff1a; Android中实现序列化有两个选择&#xff1a;一是实现Serializable接口&#xff08;是JavaSE本身就支持的&#xff09; 。一是实现Parcelable接口&#xff08;是Android特有功能&#xff0c;效率比实现Serializa…

容器对象模式。 一种新的测试模式。

如果您搜索什么是页面对象的描述&#xff0c;就会发现页面对象模式为我们提供了一种以可重用和可维护的方式对内容建模的常识方法。 还要指出&#xff1a;在Web应用程序的UI中&#xff0c;您的测试与某些区域交互。 Page Object只是将它们建模为测试代码中的对象。 这减少了重…

字符串工具类,随机生成字符串

字符串工具类&#xff0c;随机生成字符串package main.java.utils;import java.util.Map; import java.util.Random;public class StrUtil {/*** 定义一个字符串&#xff08;A-Z&#xff0c;a-z&#xff09;*/private static final String STR_ONE "abcdefghijklmnopqrs…

css与网页制作

百度&#xff1a;常用DIVCSS命名大全集合转载于:https://www.cnblogs.com/Tpf386/p/7100017.html

Oracle修改密码文件_转载:Oracle修改用户密码

转载一位大佬的博文&#xff0c;用于帮助常忘记密码的我和某些同道。1. 通过系统管理员(system)修改密码修改普通用户密码相对来说简单很多。1.1 登录系统管理员账户。一般为system。1.2 查询当前系统存在的用户。这一步属于辅助性查找&#xff0c;可以不执行。select username…

爬虫突破IP封锁

爬虫突破IP封锁 爬取网站最常出现的问题就是IP封锁的问题,较为简单的方法就是购买有效IP,免费IP虽然不花钱,但是不好用,做爬取测试的时候还勉强能用。 我从快代理购买付费的IP,把自己的电脑的IP加入白名单,再使用其提供的Api获取有效IP进行爬取。 package com.zhq.crawle…

Python异常处理和进程线程

写在前面 最坏的结果&#xff0c;不过是大器晚成&#xff1b; 一、异常处理 - 1.语法错误导致的异常 - 这种错误&#xff0c;根本过不了python解释器的语法检测&#xff0c;必须在程序运行前就修正&#xff1b; - 2.逻辑上的异常 - 即逻辑错误&#xff0c;例如除零错误&#xf…

在Oracle中使用JDBC插入功能

介绍 在本文中&#xff0c;我将显示一个示例&#xff0c;说明如何使用Oracle支持的JDBC批量插入功能&#xff0c;这些功能特定于Oracle。 有关为什么可能希望一般使用批量插入的更多详细信息&#xff0c;例如&#xff0c;在某些情况下需要考虑性能&#xff0c;请参阅Joormana …

css语法和规则

语法&#xff1a; Selector{sRule!important;} 说明&#xff1a; 提升指定样式规则的应用优先权。 IE6及以下浏览器有个比较显式的支持问题存在&#xff0c;!important并不覆盖掉在同一条样式的后面的规则。请看下述代码&#xff1a; 示例代码&#xff1a; div{color:#f00!impo…

vue 代理重定向_关于vue-router,路由重定向的使用分析

看之前的项目&#xff0c;突然发现一个不算bug的bug&#xff0c;之前也是一直没有想到&#xff0c;现在发现之后越来越觉得有必要改掉&#xff0c;项目用的是vue做的&#xff0c;自然切换用的就是路由&#xff0c;一级路由包括&#xff1a;首页、记录和个人中心&#xff0c;二级…

WebMagic爬取58同城租房数据

WebMagic爬取58同城租房数据 1.WebMagic webmagic是一个开源的Java垂直爬虫框架,目标是简化爬虫的开发流程,让开发者专注于逻辑功能的开发。webmagic的核心非常简单,但是覆盖爬虫的整个流程,也是很好的学习爬虫开发的材料。 webmagic的主要特色: 完全模块化的设计,强大…

python xposed_Xposed及类Xposed框架收集

常见xposed框架xposed--原生Cydia for Androidmagisk--挂载magisk.imgvitrualXposed--双开技术EXposed --太极VAEXposedVirtualHook :VirtualHook 修改 VirtualApp 的核心代码&#xff0c;提供 Hook 注入代码的窗口VirtrualApp --多开LEB 的平行空间 --双开大师360的DroidPlugi…

[bzoj3532][Sdoi2014]Lis

来自FallDeram的博客&#xff0c;未经允许&#xff0c;请勿转载&#xff0c;谢谢。 给定序列A&#xff0c;序列中的每一项Ai有删除代价Bi和附加属性Ci。请删除若项&#xff0c;使得4的最长上升子序列长度减少至少1&#xff0c;且付出的代价之和最小&#xff0c;并输出方案。如果…

java静态导入_Java中越来越多地接受静态导入吗?

java静态导入曾经有一段时间&#xff0c;至少在礼貌的社会中&#xff0c;人们普遍认为使用“ 不是 ”一词是不可接受的。 确实&#xff0c;在那个时候&#xff08;也许直到今天&#xff09;&#xff0c;很多人确实&#xff08;也确实&#xff09;不认为这不是一个真实的词。 尽…