Java中的42行代码中的URL缩短服务— Java(?!)Spring Boot + Redis

显然,编写URL缩短服务是新的“ Hello,world! ”在IoT /微服务/时代的世界中。 一切始于在45行Scala中的URL缩短服务 -整洁的Scala,以Spray和Redis进行调味以进行存储。 随后, 在35行Clojure中使用了url缩短服务,在 Haskell的43行中使用了URL缩短器 。 所以我内心的反时髦人士问:用Java语言要花多长时间? 但是,出于善意,不是普通的Java。 带有Spring Data Redis的 Spring Boot是一个很好的起点。 我们需要的只是一个处理GET和POST的简单控制器:

import com.google.common.hash.Hashing;
import org.apache.commons.validator.routines.UrlValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;import javax.servlet.http.*;
import java.nio.charset.StandardCharsets;@org.springframework.boot.autoconfigure.EnableAutoConfiguration
@org.springframework.stereotype.Controller
public class UrlShortener {public static void main(String[] args) {SpringApplication.run(UrlShortener.class, args);}@Autowired private StringRedisTemplate redis;@RequestMapping(value = "/{id}", method = RequestMethod.GET)public void redirect(@PathVariable String id, HttpServletResponse resp) throws Exception {final String url = redis.opsForValue().get(id);if (url != null)resp.sendRedirect(url);elseresp.sendError(HttpServletResponse.SC_NOT_FOUND);}@RequestMapping(method = RequestMethod.POST)public ResponseEntity<String> save(HttpServletRequest req) {final String queryParams = (req.getQueryString() != null) ? "?" + req.getQueryString() : "";final String url = (req.getRequestURI() + queryParams).substring(1);final UrlValidator urlValidator = new UrlValidator(new String[]{"http", "https"});if (urlValidator.isValid(url)) {final String id = Hashing.murmur3_32().hashString(url, StandardCharsets.UTF_8).toString();redis.opsForValue().set(id, url);return new ResponseEntity<>("http://mydomain.com/" + id, HttpStatus.OK);} elsereturn new ResponseEntity<>(HttpStatus.BAD_REQUEST);}
}

该代码很好地自我描述,并且在功能上等同于Scala中的版本。 我没有试图太挤它以使行数尽可能的短,上面的代码很典型,只包含很少的细节:

  • 我通常不使用通配符导入
  • 我不使用完全限定的类名(我想保存一条import行,我承认)
  • 我用if括号包围if else用括号括起来
  • 我几乎从不使用场注入,这是控制家族反转中最丑陋的兄弟。 相反,我会去让构造函数允许使用模拟的Redis进行测试:
@Autowired
private final StringRedisTemplate redis;public UrlShortener(StringRedisTemplate redis) {this.redis = redis;
}

我最苦恼的事情是……获取原始的完整URL。 基本上,我需要.com或port之后的所有内容。 没有流血的方式(既没有servlet,也没有Spring MVC),因此笨拙的getQueryString()摆弄着。 您可以按以下方式使用该服务-创建较短的URL:

$ curl -vX POST localhost:8080/https://www.google.pl/search?q=tomasz+nurkiewicz> POST /https://www.google.pl/search?q=tomasz+nurkiewicz HTTP/1.1
> User-Agent: curl/7.30.0
> Host: localhost:8080
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: Apache-Coyote/1.1
< Content-Type: text/plain;charset=ISO-8859-1
< Content-Length: 28
< Date: Sat, 23 Aug 2014 20:47:40 GMT
<
http://mydomain.com/50784f51

通过较短的网址重定向:

$ curl -v localhost:8080/50784f51> GET /50784f51 HTTP/1.1
> User-Agent: curl/7.30.0
> Host: localhost:8080
> Accept: */*
>
< HTTP/1.1 302 Found
< Server: Apache-Coyote/1.1
< Location: https://www.google.pl/search?q=tomasz+nurkiewicz
< Content-Length: 0
< Date: Sat, 23 Aug 2014 20:48:00 GMT
<

为了完整起见,这是Gradle中的一个构建文件(maven也可以使用),在所有先前的解决方案中都跳过了:

buildscript {repositories {mavenLocal()maven { url "http://repo.spring.io/libs-snapshot" }mavenCentral()}dependencies {classpath 'org.springframework.boot:spring-boot-gradle-plugin:1.1.5.RELEASE'}
}apply plugin: 'java'
apply plugin: 'spring-boot'sourceCompatibility = '1.8'repositories {mavenLocal()maven { url 'http://repository.codehaus.org' }maven { url 'http://repo.spring.io/milestone' }mavenCentral()
}dependencies {compile "org.springframework.boot:spring-boot-starter-web:1.1.5.RELEASE"compile "org.springframework.boot:spring-boot-starter-redis:1.1.5.RELEASE"compile 'com.google.guava:guava:17.0'compile 'org.apache.commons:commons-lang3:3.3.2'compile 'commons-validator:commons-validator:1.4.0'compile 'org.apache.tomcat.embed:tomcat-embed-el:8.0.9'compile "org.aspectj:aspectjrt:1.8.1"runtime "cglib:cglib-nodep:3.1"
}tasks.withType(GroovyCompile) {groovyOptions.optimizationOptions.indy = true
}task wrapper(type: Wrapper) {gradleVersion = '2.0'
}

实际上也是42行...这就是整个应用程序,没有XML,没有描述符,没有安装。

对于最短,最模糊的工作代码,我不认为此练习只是一个虚拟的代码。 带有Redis后端的URL缩短器Web服务是给定语言和生态系统的语法和功能的有趣展示。 有趣的是,还有很多算法问题,例如在Rosetta代码中发现的。 这也是编写REST服务的一个很好的基本模板。

原始Scala实现的一个重要功能(包括该实现)在所有实现中都以某种方式被默默地忘记了,它是非阻塞的。 HTTP和Redis的访问是事件驱动的( 反应 ,没事,我说),所以我想它可以同时处理客户数以万计。 阻止由Tomcat支持的控制器无法实现这一点。 但是,您仍然必须承认,用Java(甚至不是Java 8!)编写的这种服务简明扼要,易于遵循和简单明了-其他解决方案都不是可读的(当然这是主观的)。

等待别人!

翻译自: https://www.javacodegeeks.com/2014/08/url-shortener-service-in-42-lines-of-code-in-java-spring-boot-redis.html

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

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

相关文章

poj 3256(DFS)

http://acm.pku.edu.cn/JudgeOnline/problem?id3256 题意&#xff1a;有k头牛&#xff0c;n个牧场&#xff0c;m条路&#xff08;每条路相连两个牧场且单向&#xff09;&#xff0c;求全部牛都能到达的牧场有几个。 分析&#xff1a;用DFS&#xff0c;从每头牛所在牧场开始&am…

jquery常用表单操作

//js将表单序列化成对象$.fn.serializeObject function () {var $els $(this).find("[name]");var formData {};var len $els.length;for (var i 0; i < len; i ) {var $item $($els[i]);var name $item.attr("name");var type $item.attr(&qu…

Android 小項目之---Iphone拖动图片特效 (附源码)

曾经被Iphone用手指在屏幕上滑来滑去拖动图片的操作方式吸引吗&#xff1f;在Android里头&#xff0c;这并不是什么难事。 所需要的技术点如下&#xff1a;Android.content.Context 、Android.widget.BaseAdapter、Android.widget.ImageView等通常会用在设计相册、 图片类型的选…

jq绑定的事件不生效

不知道什么原因&#xff0c;写了一段代码之后&#xff0c;绑定的所有的jq事件都不生效了。后来百度了一下&#xff0c;这里列出一种方法。 转载&#xff1a;https://www.jb51.net/article/46666.html $("#ceshisub").bind("click",function(){ var a1; …

Python笔记_第三篇_面向对象_6.继承(单继承和多继承)

1. 概念解释&#xff1a; 继承&#xff1a;有两个类&#xff1a;A类和B类。那么A类就拥有了B类中的属性和方法。 * 例如&#xff1a;Object&#xff1a;是所有类的父亲&#xff0c;还可以成为基类或者超类&#xff08;super()&#xff09; * 继承者为子类&#xff0c;被继承者成…

文本内容之间的关键词提取和相似度计算

背景 Web应用程序变得越来越智能。 从网站上使用服务的日子已经一去不复返了&#xff0c;用户不得不填写一个巨大的表格。 假设您有一个适合书迷的网站。 在Web 2.0之前&#xff0c;此类网站曾经以诸如年龄&#xff0c;阅读书籍&#xff0c;喜欢的书籍类型&#xff0c;语言偏好…

Windows XP SP3支持多用户远程桌面连接

远程桌面连接的确很方便&#xff0c;但是在Windows XP中只支持单一用户的连接&#xff0c;当第二个用户连接时&#xff0c;第一个用户就被迫断开并回到用户登录界面了&#xff0c;这可和多任务的操作系统理念不符啊&#xff0c;或许微软是为了突出Server系统的特点吧&#xff0…

构建用于测试的超大型内存InputStream

由于某种原因&#xff0c;我需要非常大的&#xff0c;甚至可能是无限的InputStream &#xff0c;它会反复地反复返回相同的byte[] 。 这样&#xff0c;我可以通过重复小样本来产生大量的数据流。 在Guava中可以找到类似的功能&#xff1a; Iterable<T> Iterables.cycle(I…

linux 调试小经验

1、查看netlink socket 丢包 cat /proc/net/netlink sk Eth Pid Groups Rmem Wmem Dump Locks Drops Inode c91eda00 0 1172 00000001 0 0 00000000 2 0 27767 c43eee00 0 -4099 00000000 0 0 00000000 2 0 41200 c9266e00 0 1186 00000000 0 0 00000000 2 0 28922 c1af580…

前端打印功能

方法一&#xff1a; html代码&#xff1a; 在要打印的内容上加入&#xff1a;<!--startprint-->和<!--endprint--> js代码&#xff1a; $(.printData).click(function(){bdhtmlwindow.document.body.innerHTML; sprnstr"<!--startprint-->"; …

Vlc支持IE 360 低版本的Google浏览器

VLC 插件代码&#xff1a; <object typeapplication/x-vlc-plugin pluginspage"http://www.videolan.org/" idvlc eventsfalse width"720" height"410"><param namemrl valuertsp://admin:123456******:554/h264/ch1/main/av_stream /&…

同步多线程

同步多线程&#xff08;SMT&#xff09;是一种在一个CPU 的时钟周期内能够执行来自多个线程的指令的硬件多线程技术。本质上&#xff0c;同步多线程是一种将线程级并行处理&#xff08;多CPU&#xff09;转化为指令级并行处理&#xff08;同一CPU&#xff09;的方法。 同步多线…

如何使用布隆过滤器在Java中建立大容量的内存缓存

背景 缓存是解决日常软件问题的重要概念。 您的应用程序可能会执行CPU密集型操作&#xff0c;而您又不想一次又一次地执行这些操作&#xff0c;而是只导出一次结果并将其缓存在内存中。 有时瓶颈是IO&#xff0c;例如您不想重复访问数据库&#xff0c;并且想缓存结果并仅在基础…

Centos7安装Python3的方法

由于centos7原本就安装了Python2&#xff0c;而且这个Python2不能被删除&#xff0c;因为有很多系统命令&#xff0c;比如yum都要用到。 [rootVM_105_217_centos Python-3.6.2]# python Python 2.7.5 (default, Aug 4 2017, 00:39:18) [GCC 4.8.5 20150623 (Red Hat 4.8.5-16)…

ajax请求导致status为canceled的原因

在使用layui的form表单提交以后&#xff0c;请求状态总是canceled。后来在form表单的后面添加了一行代码&#xff1a; return false; 就可以了。 文档&#xff1a;https://www.layui.com/doc/modules/form.html#onsubmit 错误&#xff1a; 解决方法&#xff1a; 总结一下&…

CSS图片水平垂直居中

Html: <div id"MainContent"><img src"QQ截图20150515140512.png" width"247" height"192"></img></div></div> CSS: #MainContent {display:table-cell;width: 700px;height: 800px;background: #0C78…

如何开启OpenSSL和mcrypt

1&#xff0c;要想开启mcrypt支持&#xff0c;系统需要安装了libmcrypt.dll库。这个一般用户是没有安装过的&#xff0c;但不用担心&#xff0c;PHP的windows发行包里已经给我们附带了此文件&#xff0c;在PHP压缩包的根目录下即可找到&#xff0c;然后将其复制到%system%/syst…

如果BigDecimal是答案,那肯定是一个奇怪的问题

总览 许多开发人员已确定BigDecimal是处理金钱的唯一方法。 通常&#xff0c;他们通过用BigDecimal替换double来确定错误或十个错误。 我对此没有说服力的是&#xff0c;也许他们可以解决double处理中的错误以及使用BigDecimal的额外开销。 根据我的比较&#xff0c;当被问到改…

算法思想_常见四种

文章目录常用算法思想描述穷举算法思想1. 基本思想2. 步骤3.实例递推算法1. 基本思想2. 步骤3. 实例递归算法1. 基本思想2. 步骤3. 实例1. 分治算法1. 基本思想2. 步骤3. 实例概率算法1. 基本思想2. 步骤3. 实例如果还有时间&#xff0c;将继续更新常用算法思想描述 穷举算法思…

[转] 做个自强不息的青年

人的出生和际遇本身造就了每个人的道路都不同&#xff0c;对于青年人来说&#xff0c;如何能够面对逆顺&#xff0c;如何面对起伏&#xff0c;如何能够正确设定理想并为之激发生命的火焰&#xff0c;在持续的奋斗中不断提升自我&#xff0c;自强不息而自立利他&#xff1f;在与…