Springboot最佳实践:构建短url

欢迎使用,在本教程中,我们将使用Redis和Springboot来演示URL缩短器(也称为Tiny URL)应用程序。该应用程序将创建原始URL并将其存储在Redis内存缓存中。

1.简介

在继续学习本教程之前,我们将了解一些通用术语,例如Spring Boot,Docker和Redis的简介。

1.1什么是Spring Boot?

  • Spring Boot是一个模块,可为Spring框架提供快速的应用程序开发功能,包括自动配置独立代码生产就绪代码
  • 它创建打包为jar的应用程序,并使用嵌入式servlet容器(例如Tomcat,Jetty或Undertow)直接启动应用程序。因此,无需部署战争文件
  • 它通过提供入门模板来简化Maven配置,并有助于解决依赖关系冲突。它会自动识别所需的依赖项并将其导入到应用程序中
  • 它有助于删除样板代码,额外的注释和xml配置
  • 它提供了强大的批处理功能,并管理其余端点
  • 它提供了一个高效的*jpa-starter库,*可以有效地将应用程序与关系数据库连接
  • 它提供了微服务架构和云配置,可集中管理所有与应用程序相关的配置属性。

1.2什么是Docker?

在当今世界,Docker是一个重要术语,

  • 通常在CI / CD平台中使用,该平台在容器中打包和运行具有其依赖项的应用程序
  • 是Linux容器的标准
  • 一个集装箱就是一个运行时,在任何Linux内核的运行,并提供一个私人机器般的Linux下的空间

1.2.1 Docker术语

  • 图片:Docker容器的表示形式,即Java中的JAR或WAR文件
  • 容器:Docker的运行时,即已部署并正在运行的Docker映像。例如,可执行的Spring Boot jar
  • 引擎:管理,创建和运行Docker容器的代码
  • 中心:公共开发人员注册表,用于分发其代码
  • 仓库:与Docker相关的映像的集合,即同一应用程序的不同版本

1.3什么是Redis?

  • Redis是用C编程语言编写的开源内存中数据存储
  • 提供具有可选持久性的分布式内存中键值数据库
  • 通常用作数据库,缓存或消息代理,并支持不同类型的数据库类型,例如字符串,列表,映射,集合或排序集合等。
  • 它的速度很快,并且操作本质上是原子的(即两个客户端可以同时访问数据,而Redis服务器将接收更新的值)
  • 提供实用程序,例如缓存和消息队列

2. Spring Boot URL缩短器

这是实施本教程的系统指南。

2.1申请先决条件

从本教程开始,我们希望目前的用户已经完成Docker安装。如果有人需要完成Docker安装,请观看此视频。

让我们开始构建应用程序!

3.从Docker Hub提取Redis镜像并启动它

要启动Redis并在localhost环境上工作,我们将从Docker中提取Redis映像并启动容器。用户可以参考以下命令来拉取映像,然后再启动容器。

Docker命令

## Docker commands
## step1 - Pulling redis image from docker hub
docker pull redis
 
## step2 - Running the container
docker run -d -p 6379:6379 --name my-redis redis

如果一切顺利,则将Docker映像成功从中拉出并成功启动。您可以使用该docker ps -a命令来验证容器是否已成功启动。

4.创建一个Spring Boot应用程序

以下是开发应用程序涉及的步骤。

4.1 Maven依赖

在这里,我们指定了Spring Boot,Redis,Lombok,Guava和Commons Validator的依赖关系。Maven将自动解决其他依赖关系。该更新文件将具有下面的代码。

pom.xml

<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://maven.apache.org/POM/4.0.0"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
 
    <!-- project properties -->
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.springboot.redis.tinyurl</groupId>
    <artifactId>SpringbootTinyUrl</artifactId>
    <version>0.0.1-SNAPSHOT</version>
 
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.1.RELEASE</version>
    </parent>
 
    <properties>
        <java.version>1.8</java.version>
    </properties>
 
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>commons-validator</groupId>
            <artifactId>commons-validator</artifactId>
            <version>1.7</version>
        </dependency>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>18.0</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            </dependency>
    </dependencies>
 
    <build>
        <!-- to make the application as fat jar so that spring boot libraries are
            included -->
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

4.2应用程序属性

在以下位置创建一个新的属性文件:SpringbootTinyUrl/src/main/resources/并将应用程序和Redis配置添加到该文件。

application.properties

# Application configuration.
## You can change the server port configuration as per their configuration idea.
server.port=10091
 
# Redis configuration.
## As we are running Redis on Docker we are setting up its configuration.
spring.redis.host=localhost
spring.redis.port=6379

4.3 Java类

让我们编写此应用程序中涉及的所有Java类。

4.3.1实现/主类

将以下代码添加到主类,以从main方法引导应用程序。永远记住,spring boot应用程序的入口点是包含@SpringBootApplication注释和静态main方法的类。

Runner.java

package com.springboot.redis.tinyurl;
 
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
 
@Slf4j
@SpringBootApplication
public class Runner {
 
    public static void main(String[] args) {
        SpringApplication.run(Runner.class, args);
        log.info("Springboot and tinyurl application started successfully.");
    }
}

4.3.2模型类

将以下代码添加到模型类。 UrlDto.java

package com.springboot.redis.tinyurl.model;
 
import com.google.common.hash.Hashing;
import lombok.AllArgsConstructor;
import lombok.Getter;
 
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
 
@Getter
@AllArgsConstructor
public class UrlDto {
 
    private final String id;
    private final String url;
    private final LocalDateTime created;
 
    public static UrlDto create(final String url) {
        final String id = Hashing.murmur3_32().hashString(url, StandardCharsets.UTF_8).toString();
        return new UrlDto(id, url, LocalDateTime.now());
    }
}

4.3.3配置类

将以下代码添加到配置类。默认情况下,Spring Boot是自动配置的,可与字符串基础键/值对Redis模板一起使用。但是,在本教程中,我们将密钥存储为字符串,并将值存储为JSON对象。

RedisConfig.java

package com.springboot.redis.tinyurl.config;
 
import com.fasterxml.jackson.databind.ObjectMapper;
import com.springboot.redis.tinyurl.model.UrlDto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
 
@Configuration
public class RedisConfig {
 
    @Autowired
    private ObjectMapper objectMapper;
 
    @Autowired
    private RedisConnectionFactory redisConnectionFactory;
 
    // Setting up the Redis template object.
    @SuppressWarnings({"rawtypes", "unchecked"})
    @Bean
    public RedisTemplate<String, UrlDto> redisTemplate() {
        final Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(UrlDto.class);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
 
        final RedisTemplate<String, UrlDto> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        return redisTemplate;
    }
}

4.3.4控制器类

将以下代码添加到控制器类,在该类中将使用这些方法创建较短的URL并获取原始URL,以换取较短的URL。 TinyUrlController.java

package com.springboot.redis.tinyurl.controller;

import com.springboot.redis.tinyurl.exception.TinyUrlError;
import com.springboot.redis.tinyurl.model.UrlDto;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.validator.routines.UrlValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
 
import java.util.Objects;
import java.util.concurrent.TimeUnit;
 
@Slf4j
@RestController
@RequestMapping(value = "/rest/url")
public class TinyUrlController {
 
    @Autowired
    private RedisTemplate<String, UrlDto> redisTemplate;
 
    @Value("${redis.ttl}")
    private long ttl;
 
    @PostMapping
    public ResponseEntity create(@RequestBody final String url) {
        // Using commons-validator library to validate the input URL.
        final UrlValidator urlValidator = new UrlValidator(new String[]{"http", "https"});
        if (!urlValidator.isValid(url)) {
            // Invalid url return HTTP 400 bad request.
            return ResponseEntity.badRequest().body(new TinyUrlError("Invalid URL."));
        }
 
        // If valid URL, generate a hash key using guava's murmur3 hashing algorithm.
        final UrlDto urlDto = UrlDto.create(url);
        log.info("URL id generated = {}", urlDto.getId());
        // Store both hasing key and url object in redis.
        redisTemplate.opsForValue().set(urlDto.getId(), urlDto, ttl, TimeUnit.SECONDS);
        // Return the generated id as a response header.
        return ResponseEntity.noContent().header("id", urlDto.getId()).build();
    }
 
    @GetMapping(value = "/{id}")
    public ResponseEntity getUrl(@PathVariable final String id) {
        // Get from redis.
        final UrlDto urlDto = redisTemplate.opsForValue().get(id);
        if (Objects.isNull(urlDto)) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new TinyUrlError("No such key exists."));
        } else {
            log.info("URL retrieved = {}", urlDto.getUrl());
        }
 
        return ResponseEntity.ok(urlDto);
    }
}

5.运行应用程序

6.项目演示

打开Postman工具,然后单击以下URL。

// Create short url
http://localhost:10095/rest/url
 
// Get original url from url id
http://localhost:10095/rest/url/{{urlId}}

7.总结

在本节中,我们了解到:

  • Spring Boot,Redis和Docker简介
  • 将Redis与Spring Boot应用程序集成以构建URL缩短程序API
  • 使用Postman工具创建短网址并获取原始网址

作者:小隐乐乐
原文:https://juejin.cn/post/6911569521270587406