【微服务项目-短信平台】

微服务项目-短信平台

父级pom

java 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <packaging>pom</packaging>
    
    <!--声明当前项目是springboot-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.9.RELEASE</version>
    </parent>
    <groupId>com.test</groupId>
    <artifactId>smsplatform</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>smsplatform</name>
    <description>smsplatform</description>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Greenwich.SR5</version>
                <scope>import</scope>
                <type>pom</type>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

一、注册中心

pom

java 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>smsplatform</artifactId>
        <groupId>com.test</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>sms-register</artifactId>


    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>

    <profiles>
        <profile>
            <!--id与配置文件后缀一致-->
            <id>local</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <properties>
                <!--profileActive与配置文件的属性一致-->
                <profileActive>local</profileActive>
            </properties>
        </profile>

        <profile>
            <!--id与配置文件后缀一致-->
            <id>prod</id>
            <activation>
                <activeByDefault>false</activeByDefault>
            </activation>
            <properties>
                <!--profileActive与配置文件的属性一致-->
                <profileActive>prod</profileActive>
            </properties>
        </profile>
    </profiles>
</project>

配置文件

application.yml

java 复制代码
server:
  port: 8000
spring:
  application:
    name: sms-register
  profiles:
    active: @profileActive@

@profileActive@属性在pom文件中,pom中配置后,可在maven页面看到,打包时勾选哪个环境就是哪个环境配置打包

本地配置

java 复制代码
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8000/eureka
      fetch-register: true
      register-with-eureka: false

启动类

java 复制代码
package com.test.register;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer
public class RegisterServer {
    public static void main(String[] args) {
        SpringApplication.run(RegisterServer.class,args);
        System.out.println("############ sms-register start success  ###########");
    }
}

验证

启动后在浏览器输入http://localhost:8000/

配置中心

pom

java 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>smsplatform</artifactId>
        <groupId>com.test</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>sms-config-server</artifactId>


    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>

    <profiles>
        <profile>
            <!--id与配置文件后缀一致-->
            <id>local</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <properties>
                <!--profileActive与配置文件的属性一致-->
                <profileActive>local</profileActive>
            </properties>
        </profile>

        <profile>
            <!--id与配置文件后缀一致-->
            <id>prod</id>
            <activation>
                <activeByDefault>false</activeByDefault>
            </activation>
            <properties>
                <!--profileActive与配置文件的属性一致-->
                <profileActive>prod</profileActive>
            </properties>
        </profile>
    </profiles>
</project>

配置文件

java 复制代码
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8000/eureka
spring:
  cloud:
    config:
      server:
        git:
          uri: https://gitee.com/qfp17393120407/sms # 私有仓库需要配置用户名和密码

启动类

java 复制代码
package com.test.config;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.config.server.EnableConfigServer;

@SpringBootApplication
@EnableConfigServer
@EnableDiscoveryClient
public class ConfigServer {
    public static void main(String[] args) {
        SpringApplication.run(ConfigServer.class,args);
        System.out.println("############# ConfigServer start success ###########");
    }
}

启动验证

启动成功且注册到eureka

缓存模块搭建

pom

java 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>smsplatform</artifactId>
        <groupId>com.test</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>sms-cache</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>

    </dependencies>

    <!--指定资源文件目录,防止无法读到属性-->
    <build>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>

    <profiles>
        <profile>
            <!--id与配置文件后缀一致-->
            <id>local</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <properties>
                <!--profileActive与配置文件的属性一致-->
                <profileActive>local</profileActive>
            </properties>
        </profile>

        <profile>
            <!--id与配置文件后缀一致-->
            <id>prod</id>
            <activation>
                <activeByDefault>false</activeByDefault>
            </activation>
            <properties>
                <!--profileActive与配置文件的属性一致-->
                <profileActive>prod</profileActive>
            </properties>
        </profile>
    </profiles>
</project>

redis配置类

package com.test.cache.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;

import com.fasterxml.jackson.annotation.PropertyAccessor;

import com.fasterxml.jackson.databind.ObjectMapper;

import org.springframework.cache.CacheManager;

import org.springframework.cache.annotation.CachingConfigurerSupport;

import org.springframework.cache.interceptor.KeyGenerator;

import org.springframework.context.annotation.Bean;

import org.springframework.data.redis.cache.RedisCacheConfiguration;

import org.springframework.data.redis.cache.RedisCacheManager;

import org.springframework.data.redis.cache.RedisCacheWriter;

import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;

import org.springframework.data.redis.core.RedisTemplate;

import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;

import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.lang.reflect.Method;

public class RedisConfig extends CachingConfigurerSupport {

@Override

@Bean

public KeyGenerator keyGenerator() {

return new KeyGenerator() {

@Override

public Object generate(Object target, Method method, Object... params) {

StringBuilder stringBuilder = new StringBuilder();

stringBuilder.append(target.getClass().getName());

stringBuilder.append(method.getName());

for (Object param : params) {

stringBuilder.append(params.toString());

}

return stringBuilder.toString();

}

};

}

复制代码
@Bean
public CacheManager cacheManager(LettuceConnectionFactory connectionFactory) {
    //以锁写入的方式创建我们的写入对象
    RedisCacheWriter writer = RedisCacheWriter.lockingRedisCacheWriter(connectionFactory);
    //创建默认的缓存配置对象
    RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
    //根据我们的默认配置和写入方式创建缓存的管理器
    RedisCacheManager manager = new RedisCacheManager(writer, cacheConfiguration);

    return manager;
}



@Bean
public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory factory) {
    RedisTemplate<String,Object> template = new RedisTemplate();
    template.setConnectionFactory(factory);

    StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
    template.setKeySerializer(stringRedisSerializer);
    template.setHashKeySerializer(stringRedisSerializer);


    Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
    jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

    template.setValueSerializer(jackson2JsonRedisSerializer);
    template.setHashValueSerializer(jackson2JsonRedisSerializer);
    template.afterPropertiesSet();
    return template;

}

}

缓存api

java 复制代码
package com.test.cache.controller;

import com.test.cache.service.CacheService;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.Map;

@RestController
@RequestMapping("/cache")
public class CacheController {

    private static final Logger LOGGER = LoggerFactory.getLogger(CacheController.class);
    @Autowired
    private CacheService cacheService;

    /**
     *
     * @param key  set 的 key
     * @param value
     * @param expireSecond 有效期 是一个秒
     */
    @GetMapping(value = "/save2cache")
    @ApiOperation("存储字符串类型的数据")
    public boolean save2Cache(@ApiParam(name = "key",required = true,value = "保存的 key") String key,
                              @ApiParam(name = "value",required = true,value = "保存的 value") String value,
                              @ApiParam(name = "expireSecond",required = true,value = "有效期")Integer expireSecond) {
        LOGGER.error("save2cache执行了:传递的 key 是{},value 是{},有效期是{}",key,value,expireSecond);
        cacheService.save2Cache(key,value,expireSecond);
        return true;
    }

    @GetMapping("/get/{key}")
    @ApiOperation("从 redis 中获取字符串类型的数据")
    public String get(@PathVariable String key) {
        return cacheService.get(key);
    }

//
//    /**
//     * 这个方法应该要接收具体类型的参数,而不是直接接收一个 Object
//     * @param key
//     * @param value
//     */
//    @GetMapping(value = "/save2cache")
//    public void save2Cache(String key, Object value, Integer expireSecond) {
//        cacheService.save2Cache(key,value,expireSecond);
//    }
//
//    /**
//     * 这个方法应该要接收具体类型的参数,而不是直接接收一个 Object
//     * @param key
//     * @param value
//     */
//    @GetMapping(value = "/save2cache")
//    public void save2Cache(String key, Object value) {
//        cacheService.save2Cache(key,value);
//    }

    @PostMapping(value = "/save2cache/{key}/{value}")
    @ApiOperation("永久保存数据到redis")
    public boolean save2Cache(@PathVariable String key,@PathVariable String value) {
        LOGGER.error("save2cache执行了 key:{} value:{}",key,value);
        cacheService.save2Cache(key,value);
        return true;
    }
    //因为我们还没有考虑好存放的具体是对象是什么,所以暂时还无法编写获取对象的方法,实际上就是调用了 get 方法

    @RequestMapping("/getbject/{key}")
    public Object getObject(@PathVariable String key) {
        return cacheService.getObject(key);
    }
    @ApiOperation("从 redis 中删除指定 key")
    @PostMapping("/delete")
    public Long del(String... keys) {
        LOGGER.error("delete执行了 keys{}",keys);
        return cacheService.del(keys);
    }

    @PostMapping("/expire/{key}/{seconds}")
    @ApiOperation("给指定的 key 设置有效期")
    public boolean expire(@PathVariable String key, @PathVariable long seconds) {
        LOGGER.error("expire执行了 keys{} seconds{}",key,seconds);
        return cacheService.expire(key, seconds);
    }

    @GetMapping("/incr")
    @ApiOperation("递增")
    public long incr(String key, @RequestParam(defaultValue = "1") long delta) {
        LOGGER.error("incr执行了 keys{} delta{}",key,delta);
        return cacheService.incr(key,delta);
    }

    @GetMapping("/decr")
    @ApiOperation("递减")
    public long decr(String key,@RequestParam(defaultValue = "-1") long delta) {
        LOGGER.error("decr执行了 keys{} delta{}",key,delta);
        return cacheService.decr(key,delta);
    }
    @GetMapping("/hmget/{key}")
    @ApiOperation("从 redis 中获取 hash 类型的数据")
    public Map<Object, Object> hGetAll(@PathVariable String key) {

        LOGGER.error("hmget执行了 key{}",key);
        return cacheService.hGetAll(key);
    }

    /**
     * hash赋值
     * @param key
     * @param map
     * @return
     */
    @PostMapping("/hmset/{key}")
    @ApiOperation("保存 json 到 redis 的 hash 中")
    public boolean hMset(@PathVariable String key, @RequestBody Map<String, Object> map) {
        LOGGER.error("hMset执行了 key{} map{}",key,map);
        cacheService.hMset(key, map);
        return true;
    }

}

实现类

java 复制代码
package com.test.cache.service.impl;

import com.test.cache.service.CacheService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class CacheServiceImpl implements CacheService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    public void save2Cache(String key, String value, Integer expireSecond) {
        redisTemplate.opsForValue().set(key, value, expireSecond, TimeUnit.SECONDS);
    }

    @Override
    public void save2Cache(String key, Object value, Integer expireSecond) {
        redisTemplate.opsForValue().set(key, value, expireSecond, TimeUnit.SECONDS);
    }

    @Override
    public void save2Cache(String key, Object value) {
        redisTemplate.opsForValue().set(key, value);
    }

    @Override
    public void save2Cache(String key, String value) {
        redisTemplate.opsForValue().set(key, value);
    }

    @Override
    public String get(String key) {

//        redisTemplate.setKeySerializer(new StringRedisSerializer());
//        redisTemplate.setValueSerializer(new StringRedisSerializer());
        Object result = redisTemplate.opsForValue().get(key);
        return (String) result;
    }

    @Override
    public Object getObject(String key) {
        return  redisTemplate.opsForValue().get(key);
    }

    @Override
    public Long del(String... keys) {
        return redisTemplate.delete(CollectionUtils.arrayToList(keys));

    }

    @Override
    public boolean expire(String key, long seconds) {
        return redisTemplate.expire(key,seconds,TimeUnit.SECONDS);
    }

    @Override
    public long incr(String key, long delta) {
        return redisTemplate.opsForValue().increment(key,delta);
    }

    @Override
    public long decr(String key, long delta) {
        return redisTemplate.opsForValue().decrement(key,delta);
    }

    @Override
    public Map<Object, Object> hGetAll(String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    @Override
    public void hMset(String key, Map<String, Object> map) {
        redisTemplate.opsForHash().putAll(key, map);
    }
}

配置文件

application.yml

yaml 复制代码
server:
  port: 8002
spring:
  application:
    name: sms-cache
  profiles:
    active: @profileActive@

使用配置中心需要bootstrap配置

bootstrap-local.yml

yaml 复制代码
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8000/eureka

redis配置在配置中心指定目录下配置

在配置中心目录下创建配置文件

读取顺序

启动流程如下图

webmaster

代码太多见源码

源码

微服务短信平台

相关推荐
wuminyu5 小时前
专家视角看Java字节码加载与存储指令机制
java·linux·c语言·jvm·c++
KmSH8umpK5 小时前
Redis分布式锁从原生手写到Redisson高阶落地,附线上死锁复盘优化方案进阶第八篇
数据库·redis·分布式
callJJ7 小时前
Spring Data Redis 两种编程模型详解:同步 vs 响应式
java·spring boot·redis·python·spring
phltxy7 小时前
Spring Cloud 分布式服务部署实战:从 0 到 1 实现微服务上线
spring·spring cloud·微服务
wbs_scy7 小时前
Linux线程同步与互斥(三):线程同步深度解析之POSIX 信号量与环形队列生产者消费者模型,从原理到源码彻底吃透
java·开发语言
KmSH8umpK8 小时前
Redis分布式锁从原生手写到Redisson高阶落地,附线上死锁复盘优化方案进阶第七篇
数据库·redis·分布式
0xDevNull8 小时前
Linux 中 Nginx 代理 Redis 的详细教程
redis·后端
jinanwuhuaguo9 小时前
(第三十三篇)五月的文明奠基:OpenClaw 2026.5.2版本的文明级解读
android·java·开发语言·人工智能·github·拓扑学·openclaw
xmjd msup9 小时前
spring security 超详细使用教程(接入springboot、前后端分离)
java·spring boot·spring
9523610 小时前
SpringBoot统一功能处理
java·spring boot·后端