[全]Springboot分布式框架搭建+Kafka+redis+分页+shiro+Swagger2+Feign+一些坑处理+微服务

Springboot分布式框架搭建+Kafka+redis+分页+shiro+Swagger2+Feign+一些坑处理+微服务

准备给即将做的一个项目搭建一个springboot的微服务架构,中间集成多种中间件,根据实际情况会优化中间件.

技术使用:springboot,Kafka,redis,shiro,swagger,Feign等.

一. 通过IDEA新建一个SpringBoot项目
1.创建springboot项目
新建springboot项目
注:如果出现’https://start.spring.io’ 的初始化失败 请多刷新几次
在这里插入图片描述
2.添加启动类在这里插入图片描述
3.创建测试类TestController
在这里插入图片描述
4.在入口类Application中启动项目,启动成功如下图
在这里插入图片描述
5.打开浏览器输入http://localhost:8080/,测试成功
在这里插入图片描述

6.添加SpringBoot的配置文件application.properties,配置服务访问端口号
在这里插入图片描述
二. SpringBoot与mybatis整合
1.添加maven依赖

  <!--mysql驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!-- 阿里系的Druid依赖包 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.9</version>
        </dependency>
        <!-- Druid 依赖 log4j包 -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <!--jpa的jar包 ,操作数据库的,类似hibernate -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <!-- spring-boot整合mybatis -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.1.1</version>
        </dependency>

2.创建entity、service、dao
(1).User实体类

 import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import java.io.Serializable;

/**
 * @author boxin
 * @date 2022年02月28日 20:19
 */
@Getter
@Setter
@ToString
public class User implements Serializable {
    private static final long serialVersionUID = 15615615461561151L;
    private String loginName;
    private String password;
}

(2).Mapper接口类

import com.iflytek.bim.cop.domain.entity.User;
import java.util.List;

/**
 * @author boxin
 * @date 2022年02月28日 20:16
 */
public interface UserMapper {
    List<User> getAll();
}

(3).Service接口

import com.iflytek.bim.cop.domain.entity.User;

import java.util.List;

/**
 * @author boxin
 * @date 2022年02月28日 20:22
 */
public interface IUserService{

    List<User> getAll();
}

(4).Service实现类

import java.util.List;

/**
 * @author boxin
 * @date 2022年02月28日 20:23
 */
@Service
public class UserServiceImpl implements IUserService {
    @Autowired
    private UserMapper userMapper;

    public List<User> getAll() {
        return userMapper.getAll();
    }
}

3.在application.properties配置数据源以及mybatis


#数据源
jasypt.encryptor.password=EbfYkitulv73I2p0mXI50JMXoaxZTKJ7JCCT
spring.datasource.driverClassName=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://172.31.201.66:5432/test?useUnicode=true&characterEncoding=utf8
spring.datasource.username=postgres
spring.datasource.password=8989yyu

#阿里druid连接池驱动配置信息
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
#连接池的配置信息
#初始化大小,最小,最大
spring.datasource.initialSize=2
spring.datasource.minIdle=2
spring.datasource.maxActive=3
#配置获取连接等待超时的时间
spring.datasource.maxWait=6000
#配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
spring.datasource.timeBetweenEvictionRunsMillis=60000
#配置一个连接在池中最小生存的时间,单位是毫秒
spring.datasource.minEvictableIdleTimeMillis=300000
spring.datasource.validationQuery=SELECT 1 FROM DUAL
spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=false
spring.datasource.testOnReturn=false
#打开PSCache,并且指定每个连接上PSCache的大小
spring.datasource.poolPreparedStatements=true
spring.datasource.maxPoolPreparedStatementPerConnectionSize=20
#配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
spring.datasource.filters=stat,wall,log4j
#通过connectProperties属性来打开mergeSql功能;慢SQL记录
spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000

#mybatis配置
#配置Mapper文件存放的路径
mybatis.mapper-locations=classpath:mapper/*Mapper.xml	

4.在resources下新建mapper文件夹,然后创建UserMapper的接口映射文件UserMapper.xml
在这里插入图片描述
注:The injection point has the following annotations:
@org.springframework.beans.factory.annotation.Autowired(required=true)报错 出现扫描不到持久层的时候,可在application启动类加@MapperScan({"com.
...dao"})*

5.修改测试类测试

import com.iflytek.bim.cop.domain.entity.User;
import com.iflytek.bim.cop.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.List;

/**
 * @author boxin
 * @date 2022年02月28日 18:08
 */
@Controller
public class TestController {
    @Autowired
    private IUserService userService;

    @ResponseBody
    @RequestMapping("/")
    public List<User> test() {
        return userService.getAll();
    }
}

6.启动项目,在浏览器输入http://localhost:8020/,json数据成功返回,整合mybaties成功
在这里插入图片描述
三.整合Redis
1.添加redis-maven依赖

   <!-- redis包 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!--spring2.0集成redis所需common-pool2-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>

2.配置文件中添加redis配置信息

# 缓存服务配置
spring.cache.type=redis
spring.redis.host=172.31.201.66
spring.redis.password=ENC(JrHjkKCEYDvsg2KhjPTv6j1LCQSYUAU4)
spring.redis.port=6379
spring.redis.database=0
spring.redis.pool.max-idle=8
spring.redis.pool.min-idle=0
spring.redis.pool.max-active=8
spring.redis.pool.max-wait=-1
redis.server.connectionTimeout=5000
redis.server.soTimeout=5000
redis.server.weight=1
redis.server.blockWhenExhausted=true
redis.server.maxWaitMillis=10000
redis.server.minIdle=50
redis.server.testWhileIdle=true
redis.server.numTestsPerEvictionRun=30
redis.server.testOnBorrow=true
redis.server.maxIdle=100
redis.server.maxTotal=1024

3.创建Redis服务接口以及实现类

public interface IRedisService {

    void setValue(String key,Object value);

    /**
     * 通过redis获取redis中的key
     * @param key
     * @return
     */
    Object getValue(String key);

    /**
     * 存入redis并设置有效期
     * @param key
     * @param value
     * @param exceed	有效期
     * @param timeType 	0:按天,1:按时,2:按分,3:按秒,4:按毫秒
     */
    void setValue(String key,Object value,Integer exceed,Integer timeType);
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

/**
 * @author boxin
 * @date 2022年03月01日 19:30
 */
@Service
public class RedisServiceImpl implements IRedisService {

    @Autowired
    private RedisTemplate redisTemplate;

    @SuppressWarnings("unchecked")
    @Override
    public void setValue(String key,Object value) {
        redisTemplate.opsForValue().set(key, value);
    }

    @SuppressWarnings("unchecked")
    @Override
    public Object getValue(String key) {
        if(!redisTemplate.hasKey(key)){
            return null;
        }else{
            return redisTemplate.opsForValue().get(key);
        }
    }

    @SuppressWarnings("unchecked")
    @Override
    public void setValue(String key, Object value, Integer exceed, Integer timeType) {
        switch (timeType) {
            case 0://天
                redisTemplate.opsForValue().set(key, value, exceed, TimeUnit.DAYS);
                break;
            case 1://小时
                redisTemplate.opsForValue().set(key, value, exceed, TimeUnit.HOURS);
                break;
            case 2:	//分钟
                redisTemplate.opsForValue().set(key, value, exceed, TimeUnit.MINUTES);
                break;
            case 3:	//秒
                redisTemplate.opsForValue().set(key, value, exceed, TimeUnit.SECONDS);
                break;
            case 4://毫秒
                redisTemplate.opsForValue().set(key, value, exceed, TimeUnit.MICROSECONDS);
                break;
        }
    }
}

4.测试Redis

import com.iflytek.bim.cop.domain.entity.User;
import com.iflytek.bim.cop.api.IUserService;
import com.iflytek.bim.cop.service.redis.IRedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.List;

/**
 * @author boxin
 * @date 2022年02月28日 18:08
 */
@Controller
public class TestController {
private static final Logger logger = LoggerFactory.getLogger(TestController.class);
    @Autowired
    private IUserService userService;
    @Autowired
    private IRedisService redisService;
    @ResponseBody
    @RequestMapping("/")
    public List<User> test() {
        //存入redis并设置10秒的有效期
        redisService.setValue("redisKey", ccwwee, 3, 3);
       logger.info("redisKey的值 ==================》 " + redisService.getValue("redisKey"));
        try {
            Thread.sleep(5000);
           logger.info("等待5秒后的值 ==================》 " + redisService.getValue("redisKey"));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return userService.getAll();
    }
}

5.Redis测试结果
在这里插入图片描述
三. 整合PageHelper分页插件
1.在pom.xml文件中引入Pagehelper分页插件

  <!-- pagehelper分页插件-->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.4.1</version>
        </dependency>

helperDialect :分页插件会自动检测当前的数据库链接,自动选择合适的分页方式。 你可以配置helperDialect 属性来指定分页插件使用哪种方言。配置时,可以使用下面的缩写值:oracle , mysql , mariadb , sqlite , hsqldb , postgresql , db2 , sqlserver , informix , h2 , sqlserver2012 , derby特别注意:使用 SqlServer2012 数据库时,需要手动指定为 sqlserver2012 ,否则会使用 SqlServer2005 的方式进行分页。你也可以实现 AbstractHelperDialect ,然后配置该属性为实现类的全限定名称即可使用自定义的实现方法。

offsetAsPageNum :默认值为 false ,该参数对使用 RowBounds 作为分页参数时有效。 当该参数设置为true 时,会将 RowBounds 中的 offset 参数当成 pageNum 使用,可以用页码和页面大小两个参数进行分页。

rowBoundsWithCount :默认值为 false ,该参数对使用 RowBounds 作为分页参数时有效。 当该参数设置为 true 时,使用 RowBounds 分页会进行 count 查询。

pageSizeZero :默认值为 false ,当该参数设置为 true 时,如果 pageSize=0 或者 RowBounds.limit =0 就会查询出全部的结果(相当于没有执行分页查询,但是返回结果仍然是 Page 类型)。

reasonable :分页合理化参数,默认值为 false 。当该参数设置为 true 时, pageNum<=0 时会查询第一页, pageNum>pages (超过总数时),会查询最后一页。默认 false 时,直接根据参数进行查询。

params :为了支持 startPage(Object params) 方法,增加了该参数来配置参数映射,用于从对象中根据属性名取值, 可以配置 pageNum,pageSize,count,pageSizeZero,reasonable ,不配置映射的用默认值, 默认值为pageNum=pageNum;pageSize=pageSize;count=countSql;reasonable=reasonable;pageSizeZero=pageSizeZero。

supportMethodsArguments :支持通过 Mapper 接口参数来传递分页参数,默认值 false ,分页插件会从查询方法的参数值中,自动根据上面 params 配置的字段中取值,查找到合适的值时就会自动分页。 使用方法可以参考测试代码中的 com.github.pagehelper.test.basic 包下的 ArgumentsMapTest 和ArgumentsObjTest 。

autoRuntimeDialect :默认值为 false 。设置为 true 时,允许在运行时根据多数据源自动识别对应方言的分页 (不支持自动选择 sqlserver2012 ,只能使用 sqlserver ),用法和注意事项参考下面的场景五。

closeConn :默认值为 true 。当使用运行时动态数据源或没有设置 helperDialect 属性自动获取数据库类型时,会自动获取一个数据库连接, 通过该属性来设置是否关闭获取的这个连接,默认 true 关闭,设置为false 后,不会关闭获取的连接,这个参数的设置要根据自己选择的数据源来决定

2.分页测试类

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.iflytek.bim.cop.domain.entity.User;
import com.iflytek.bim.cop.api.IUserService;
import com.iflytek.bim.cop.service.redis.IRedisService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.List;

/**
 * @author boxin
 * @date 2022年02月28日 18:08
 */
@Controller
public class TestController {
    private static final Logger logger = LoggerFactory.getLogger(TestController.class);
    @Autowired
    private IUserService userService;
    @Autowired
    private IRedisService redisService;
    @ResponseBody
    @RequestMapping("/")
    public PageInfo<User> test() {
        PageHelper.startPage(1, 10);
        //存入redis并设置10秒的有效期
        redisService.setValue("redisKey", 1, 3, 2);
        logger.info("redisKey的值 ==================》 " + redisService.getValue("redisKey"));
        try {
            Thread.sleep(5000);
            logger.info("redisKey 等待5秒后的值 ==================》 " + redisService.getValue("redisKey"));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        List<User> userList = userService.getAll();
        PageInfo<User> pageInfo = new PageInfo<>(userList);
        return pageInfo;
    }
}

3.分页测试,浏览器访问http://localhost:8020/
注:注意com.github.pagehelper的版本,可能会在启动的时候报错

┌──->──┐
|  com.github.pagehelper.autoconfigure.PageHelperAutoConfiguration
└──<-──┘

在这里插入图片描述

五.集成kafka

1.引入kafka maven依赖

  <!-- kafka包 -->
        <dependency>
            <groupId>org.springframework.kafka</groupId>
            <artifactId>spring-kafka</artifactId>
        </dependency>
        <!-- fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.47</version>
        </dependency>
        <!-- lang字符串工具 -->
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.4</version>
            <scope>provided</scope>
        </dependency>

2.服务器安装Kafka
(1).下载kafka压缩包

https://kafka.apache.org/downloads

(2).安装Kafka

在这里插入图片描述

tar -zxvf kafka_2.13-3.0.0.tgz 

(3).修改kafka的配置

#在公司内网部署 kafka 集群只需要用到 listeners,内外网需要作区分时 才需要用到advertised.listeners
listeners=PLAINTEXT://127.0.0.1:9092
advertised.listeners=PLAINTEXT://127.0.0.1:9092
log.dirs=/usr/local/kafka_2.11-0.9.0.1/kafka-logs//

(4).修改kafka内置zookeeper的配置

dataDir=/usr/local/kafka/zookeeper
dataLogDir=/usr/local/kafka/zookeeper-logs
# the port at which the clients will connect
clientPort=2181
# disable the per-ip limit on the number of connections since this is a non-production config
maxClientCnxns=100
tickTime=2000
initLimit=10
syncLimit=5
# Disable the admi

(5).开启zookeeper和kafka

bin/zookeeper-server-start.sh config/zookeeper.properties 
bin/kafka-server-start.sh config/server.properties 
为了方便可以自己创建一个启动脚本
进入kafka目录下 输入命令:vi  kafkaStart.sh
 
添加内容为:
#!/bin/bash
#启动zookeeper
/DATA/kafka/kafka_2.12-2.0.0/bin/zookeeper-server-start.sh /DATA/kafka/kafka_2.12-2.0.0/config/zookeeper.properties &
sleep 3  #默默等3秒后执行 
#启动kafka
/DATA/kafka/kafka_2.12-2.0.0/bin/kafka-server-start.sh /DATA/kafka/kafka_2.12-2.0.0/config/server.properties &
 

启动结果

(6).创建topic主题

./kafka-topics.sh --create --topic test --bootstrap-server localhost:9092 -partitions 3 -replication-factor 1

(7).启动生产者连接主题

./kafka-console-producer.sh --broker-list localhost:9092 --topic test

(8).启动消费者连接主题

./kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic test

3.springboot开始集成Kafka,添加配置

#kafka
spring.applicationname=kafka-tutorial
# 指定kafka 代理地址,可以多个
spring.kafka.bootstrap-servers=172.31.111.11:9092
spring.kafka.producer.retries: 0
# 每次批量发送消息的数量
spring.kafka.producer.batch-size: 16384
# 缓存容量
spring.kafka.producer.buffer-memory: 33554432
# 指定消息key和消息体的编解码方式
spring.kafka.producer.key-serializer: org.apache.kafka.common.serialization.StringSerializer
spring.kafka.producer.value-serializer: org.apache.kafka.common.serialization.StringSerializer
# 指定默认消费者group id
spring.kafka.consumer.group-id=demo
spring.kafka.consumer.auto-commit-interval=100
spring.kafka.consumer.auto-offset-reset=earliest
spring.kafka.consumer.enable-auto-commit=true
# 指定消息key和消息体的编解码方式
spring.kafka.consumer.key-deserializer=org.apache.kafka.common.serialization.StringDeserializer
spring.kafka.consumer.value-deserializer=org.apache.kafka.common.serialization.StringDeserializer
# 指定listener容器中的线程数,用于提高并发量
spring.kafka.listener.concurrency=3

4.创建测试bean包,创建kafka生产者与消费者
(1).创建生产者KafkaProduction

import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.kafka.support.SendResult;
import org.springframework.stereotype.Component;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.util.concurrent.ListenableFutureCallback;

/**
 * kafka 生产者
 * @author boxin
 * @date 2022年03月02日 20:32
 */
@Component
public class KafkaProduction <T>{
    private Logger logger = LoggerFactory.getLogger(KafkaProduction.class);
    @Autowired
    private KafkaTemplate<String, Object> kafkaTemplate;
    /**
     * 发送消息
     * @param obj	消息体
     * @param topics  消息主题
     */
    public void send(T obj,String topics) {
        String jsonObj = JSON.toJSONString(obj);
        logger.info("----kafka---- message = {}", jsonObj);
        //发送消息
        ListenableFuture<SendResult<String, Object>> future = kafkaTemplate.send(topics, jsonObj);
        future.addCallback(new ListenableFutureCallback<SendResult<String, Object>>() {
            @Override
            public void onFailure(Throwable throwable) {
                logger.info("KafkaProduction: kafka to be sent:" + throwable.getMessage());
            }
            @Override
            public void onSuccess(SendResult<String, Object> stringObjectSendResult) {	//成功消费
                //TODO 业务处理
                logger.info("KafkaProduction: The message has be sent successfully:");
                logger.info("KafkaProduction: =============== result: " + stringObjectSendResult.toString());
            }
        });
    }
}

(2).创建KafkaTopicsConstant常量类

public interface IKafkaSenderService {
    /**
     * 发送主题为test的消息
     */
    public void send();
}

(3).创建消费者KafkaConsumer

import com.iflytek.bim.cop.contant.KafkaTopicsConstant;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Component;
import java.util.Optional;

@Component
public class KafkaConsumer {
        private Logger logger = LoggerFactory.getLogger(KafkaConsumer.class);
        /**
         * 监听kafka.tut 的topic为test_topics的消息
         * @param record
         */
        @KafkaListener(topics = KafkaTopicsConstant.TEST_TOPICS)
        public void listen(ConsumerRecord<?, ?> record) {
            Optional<?> kafkaMessage = Optional.ofNullable(record.value());

            if (kafkaMessage.isPresent()) {
                Object message = kafkaMessage.get();
                logger.info("KafkaConsumer  接收: ================= Topic:" + record.topic());
                logger.info("KafkaConsumer  接收: ================= Record:" + record);
                logger.info("KafkaConsumer  接收: ================= Message:" + message);
            }
        }
}

(4).发送实现

import com.iflytek.bim.cop.component.KafkaProduction;
import com.iflytek.bim.cop.contant.KafkaTopicsConstant;
import com.iflytek.bim.cop.domain.entity.User;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * @author boxin
 * @date 2022年03月02日 20:50
 */
public class KafkaSenderServiceImpl implements IKafkaSenderService {
    @Autowired
    private KafkaProduction<User> kafkaProduction;

    @Override
    public void send() {
        User user = new User();
        user.setLoginName("I am is a panda");
        user.setPassword("5588996633");
        kafkaProduction.send(user, KafkaTopicsConstant.TEST_TOPICS);
    }
}

(5).测试Kafka

    @ResponseBody
    @RequestMapping("/")
    public void kafkatest() {
        kafkaSenderService.send();
    }

(6).Kafka测试结果
在这里插入图片描述
六.集成SpringCloud框架
1.搭建eruka:
1).新建一个maven工程项目,添加eruka依赖

  <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Brixton.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>

2).编写配置文件

server.port=8088

# 不向注册中心注册自己
eureka.client.register-with-eureka=false
# 不需要检索服务
eureka.client.fetch-registry=false
eureka.client.serviceUrl.defaultZone=http://localhost:${server.port}/eureka/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值