使用Spring Boot实现博客统计服务

代码星冰乐

专注成就未来

首页 归档 关于

使用Spring Boot实现博客统计服务

Jun 19, 2018 | haifeiWu | Java | 阅读
文章目录
  1. 1. 通过SPRING INITIALIZR生成工程
  2. 2. 实现redis存储逻辑
  3. 3. 博客阅读次数统计接口实现
  4. 4. 实现过程中遇到的坑
  5. 5. 小结
  6. 6. 号外

作 者:haifeiWu
原文链接:https://www.hchstudio.cn/article/2018/6f25/
版权声明:非特殊声明均为本站原创作品,转载时请注明作者和原文链接。


由于版权原因,请阅读原文 --> 使用Spring Boot实现博客统计服务

关注我们

作 者:haifeiWu
原文链接:https://www.hchstudio.cn/article/2018/6f25/
版权声明:非特殊声明均为本站原创作品,转载时请注明作者和原文链接。

作 者:haifeiWu
原文链接:https://www.hchstudio.cn/article/2018/6f25/
版权声明:非特殊声明均为本站原创作品,转载时请注明作者和原文链接。

作为一个后端开发,在微服务,server mesh等概念满天飞的时代,持续学习能力是不能丢的,因此楼主最近也研究好多RPC,NETTY,Spring Boot等技术。此外,楼主博客的阅读统计功能是用的是与HEXO相匹配的第三方的数量统计功能,也就诞生了楼主这次更换成自己开发的基础功能的装逼之旅。

通过SPRING INITIALIZR生成工程

spring init
如上图,通过Spring官方的 Spring Initial 网站生成项目,项目的目录结构如下:

  • 目录结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- src
-main
-java
-package
#主函数,启动类,运行它如果运行了 Tomcat、Jetty、Undertow 等容器
-SpringbootApplication
-resouces
#存放静态资源 js/css/images 等
- statics
#存放 html 模板文件
- templates
#主要的配置文件,SpringBoot启动时候会自动加载application.yml/application.properties
- application.yml
#测试文件存放目录
-test
# pom.xml 文件是Maven构建的基础,里面包含了我们所依赖JAR和Plugin的信息
- pom
  • pom依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.*</groupId>
<artifactId>*-*</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>base-service</name>
<description>Demo project for Spring Boot</description>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>

<dependencies>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.6</version>
</dependency>

<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>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.almende.eve</groupId>
<artifactId>eve-bundle-full</artifactId>
<version>3.1.1</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>

<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

实现redis存储逻辑

选择redis而没选择数据库的原因是redis提供了丰富的数据结构与数据持久化策略,另外redis是基于内存的,相对于数据库来说,快了不止一个数量级。而统计阅读次数的场景对接口处理的速度还是有一定的要求的,因此楼主选择了redis作为阅读次数统计的db。
下面就是redis操作的基础代码,比较简单楼主贴一下代码,不做进一步的阐述

  • redis的接口类

    1
    2
    3
    4
    5
    public interface RedisService {
    public boolean set(final String key, final String value);
    public String get(final String key);
    public String incr(final String key);
    }
  • redis的实现类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

@Service
public class RedisServiceImpl implements RedisService {

@Resource
private RedisTemplate<String, ?> redisTemplate;

@Override
public boolean set(final String key, final String value) {
boolean result = redisTemplate.execute(new RedisCallback<Boolean>() {
@Override
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
connection.set(serializer.serialize(key), serializer.serialize(value));
return true;
}
});
return result;
}

@Override
public String incr(final String key) {
String incr = redisTemplate.execute(new RedisCallback<String>() {
@Override
public String doInRedis(RedisConnection redisConnection) throws DataAccessException {
RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
Long value = redisConnection.incr(serializer.serialize(key));
return String.valueOf(value);
}
});
return incr;
}

@Override
public String get(final String key){
String result = redisTemplate.execute(new RedisCallback<String>() {
@Override
public String doInRedis(RedisConnection connection) throws DataAccessException {
RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
byte[] value = connection.get(serializer.serialize(key));
return serializer.deserialize(value);
}
});
return result;
}

}

博客阅读次数统计接口实现

博客阅读次数统计的基本业务逻辑就是,对应每篇博客的blogId作为redis的key,而访问次数就是这个key所对应的value,每访问一次该接口就要将对应的blogId自增一次,并返回对应的value。这里楼主选择的redis的数据结构是redis的Stirng,下面是楼主实现该逻辑的主要代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53


/**
* 统计博客阅读次数.
*
* @author wuhf
* @Date 2018/6/15 15:59
**/
@RestController
@RequestMapping("/")
public class BlogReadCountController {

private static String ALLOW_REQUEST_URL = "******";
private static String ILLEGAL_CHARACTERS = "*";
private static String DEFAULT_READ_COUNT = "1";
private static Logger logger = LoggerFactory.getLogger(BlogReadCountController.class);

@Autowired
private RedisService redisService;

@ResponseBody
@RequestMapping("/*_*")
public ResultCode blogReadCountIncr(HttpServletRequest request,String blogId) {
ResultCode resultCode = new ResultCode();
try {
logger.info(">>>>>> method blogReadCountIncr exec , request params is : {}",blogId);
String readCount = redisService.get(blogId);
if (StringUtils.isBlank(readCount)) {

if (!blogId.startsWith(ALLOW_REQUEST_URL)||blogId.contains(ILLEGAL_CHARACTERS)) {
resultCode.setCode(Messages.API_ERROR_CODE);
resultCode.setMsg(Messages.API_ERROR_MSG);
return resultCode;
}

redisService.set(blogId,DEFAULT_READ_COUNT);
readCount = DEFAULT_READ_COUNT;
} else {
readCount = redisService.incr(blogId);
}
logger.info(">>>>>> readCount is : {}",readCount);
resultCode.setCode(Messages.SUCCESS_CODE);
resultCode.setMsg(Messages.SUCCESS_MSG);
resultCode.setData(readCount);
return resultCode;
} catch (Exception e) {
e.printStackTrace();
resultCode.setCode(Messages.API_ERROR_CODE);
resultCode.setMsg(Messages.API_ERROR_MSG);
return resultCode;
}
}
}

实现过程中遇到的坑

  • 设置应用启动的端口号
1
server.port=9401
  • 设置应用访问的path

Spring Boot应用默认的应用访问的path还是 “/“,楼主在这里吃了点苦头,使用https://项目名:port访问服务,愣是访问不通,在配置文件中设置如下所示

1
server.servlet.context-path=/项目名

小结

目前很多大佬都写过关于 SpringBoot 的教程了,如有雷同,请略过不看,本文通过自己的亲身实战以及楼主自己踩到的坑完成的,另外本文是基于最新的 spring-boot-starter-parent:2.0.3.RELEASE编写。

号外

楼主造了一个轮子,LIGHTCONF 是一个基于Netty实现的一个配置管理平台,其核心设计目标是“为业务提供统一的配置管理服务”,可以做到开箱即用。感兴趣的给个star支持一下。

  • 基于Netty实现的轻量级分布式应用配置中心

关注我们

作 者:haifeiWu
原文链接:https://www.hchstudio.cn/article/2018/6f25/
版权声明:非特殊声明均为本站原创作品,转载时请注明作者和原文链接。

分享
JavawebRedis
Netty实战之第一个应用I-team博客的gitlab-runner持续集成实践
微信关注我们
分类
  • Android8
  • Go1
  • Java57
  • Kotlin2
  • Python2
  • Redis1
  • 工具1
  • 总结7
  • 旅游日记1
标签
算法 ChanghuiN Android haifeiWu Java 译文 Docker Spring Boot 源码解析 设计模式 工具 web hexo 学习笔记 Kotlin 总结 MySQL netty Redis Python WebFlux 性能测试 golang 配置中心 Nginx 性能优化 旅游日记 Shell 散列表 源码 问题排查
最近文章
  • Kafka Consumer 的 Rebalance 机制
  • 实时数据并发写入 Redis 优化
  • Redis 与 Lua 使用中的小问题
  • Git 命令
  • 二分查找算法细节详解
  • 实现自己的 RPC 框架(二)
  • lang3 的 split 方法误用
  • [译] 为什么String在Java中是不可变的
  • 双重检查锁定与单例
  • LRU 算法
福利专区
    免费SSL证书
      阿里云红包
        腾讯云专属福利
        Copyright © 2019 代码星冰乐. Powered by ChanghuiN. 版权所有 晋ICP备15001365号
        特别感谢: 云服务器服务商 、 CDN 服务商