SpringBoot3.x+SpringCloudAlibaba2023+JDK17微服务基础框架搭建

本篇我们开始尝试搭建一套新的微服务项目

项目采用最新技术栈:SpringBoot3.2.4 + SpringCloud-2023.1+SpringCloudAlibaba-2023.0.1+JDK17

在我们实际的公司微服务项目开发过程中,通常会遇到一些底层公共组件封装问题。比如统一的请求响应封装(Resp)、统一分页请求父类(PageReq)、统一业务异常封装(BusinessException)等。Web服务公共特性封装、Redis组件公共特性封装、数据库(DAO)层的组件封装,包括模块开发规范等,这些非常考验一个架构师的整体设计能力。

本篇笔者尝试搭建 tmclcoud-base 项目作为X公司整体微服务的最底层模块。

一、项目结构

tmclcoud-base

tmccloud-base-base 最底层的类库封装 (Resp 、PageReq)

tmccloud-base-web Web模块公共封装(JSR303参数验证、统一异常处理)

tmccloud-base-redis Redis模块封装 (统一redis序列化方式)

tmccloud-base-mysql mysql数据访问层封装(mybatisplus +pagehelper分页)

后续如发现X公司有更多需要封装的底层公用组件,则可以在 tmclcoud-base 扩展子模块即可

tmclcoud-base 的pom.xml ,从全局上固定了 SpringBoot 、SpringCloud 、SpringCloudAlibaba 及 maven编译的JDK版本

XML 复制代码
<?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">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.tingcream</groupId>
    <artifactId>tmccloud-base</artifactId>
    <packaging>pom</packaging>
    <modules>
        <module>tmccloud-base-base</module>
        <module>tmccloud-base-web</module>
        <module>tmccloud-base-redis</module>
        <module>tmccloud-base-demoweb</module>
        <module>tmccloud-base-mysql</module>
    </modules>
    <version>1.0</version>

    <!--
    各组件对应版本:

    springboot版本: 3.2.4
    springcloud版本: 2023.0.1
    springcloud-alibaba版本:   2023.0.1.0
    sentinel版本:1.8.6
    nacos版本: 2.5.2
    seata版本: 1.6.0   ==》 2.0.0
    java版本:17
    -->


<!--    <distributionManagement>-->
<!--        <repository>-->
<!--            <id>nexus-release</id>-->
<!--            <url>http://47.115.218.201:8091/nexus/content/repositories/releases</url>-->
<!--        </repository>-->
<!--        <snapshotRepository>-->
<!--            <id>nexus-snapshot</id>-->
<!--            <url>http://47.115.218.201:8091/nexus/content/repositories/snapshots</url>-->
<!--        </snapshotRepository>-->
<!--    </distributionManagement>-->
    <distributionManagement>
        <repository>
            <id>nexus-releases</id>
            <url>http://192.168.31.10:8081/repository/maven-releases</url>
        </repository>
        <snapshotRepository>
            <id>nexus-snapshots</id>
            <url>http://192.168.31.10:8081/repository/maven-snapshots</url>
        </snapshotRepository>
    </distributionManagement>



    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <spring-boot.version>3.2.4</spring-boot.version>
        <spring-cloud.version>2023.0.1</spring-cloud.version>
        <spring-cloud-alibaba.version>2023.0.1.0</spring-cloud-alibaba.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>


    <dependencies>
      

    </dependencies>

    <dependencyManagement>
        <dependencies>
            <!--固定版本   springboot 3.2.4 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <!--固定版本  springcloud  2023.0.1-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <!--固定版本   springcloud-alibaba 2023.0.1.0-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>


        </dependencies>
    </dependencyManagement>


    <build>
        <finalName>${project.name}</finalName>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*</include>
                </includes>
                <excludes>
                    <exclude>**/*.java</exclude>
                </excludes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*</include>
                </includes>
                <excludes>
                    <exclude>**/*.java</exclude>
                </excludes>
            </resource>
        </resources>

        <pluginManagement>
            <plugins>
                <!-- spring-boot maven打包插件-->
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <version>${spring-boot.version}</version>
                    <configuration>
                    </configuration>
                    <executions>
                        <execution>
                            <goals>
                                <goal>repackage</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>

        </pluginManagement>

        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <version>3.3.1</version>
                <configuration>
                    <encoding>${project.build.sourceEncoding}</encoding>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <target>${maven.compiler.source}</target>
                    <source>${maven.compiler.target}</source>
                    <encoding>${project.build.sourceEncoding}</encoding>
                </configuration>
            </plugin>

            <!-- 打源码包的插件   -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-source-plugin</artifactId>
                <version>3.2.1</version>
                <executions>
                    <execution>
                        <id>attach-sources</id>
                        <phase>install</phase><!--  要绑定到的生命周期的阶段 在verify之后,install之前执行下面指定的goal -->
                        <goals>
                            <goal>jar-no-fork</goal><!-- 类似执行mvn sources:jar -->
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

二、子模块功能

1、tmccloud-base-base模块

最底层的基础类库封装,如统一响应类Resp 、统一分页请求父类PageReq 、统一业务异常等

pom.xml

XML 复制代码
   <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.38</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.75</version>
        </dependency>
    </dependencies>

Resp.java 统一控制层响应类

java 复制代码
package com.tingcream.tmccloud.base.core;


import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class Resp<T> {

    /**
     * 返回状态码(0操作成功 -1操作失败 9999系统异常...)
     */
    private Integer code ;

    /**
     * 返回消息
     */
    private String msg ;


    /**
     * 返回数据
     */
    private T data;

    public Resp(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public Resp(Integer code, String msg,T data) {
        this.code = code;
        this.msg = msg;
        this.data=data;
    }

    public static <T> Resp<T> success(){
        return new Resp(0,"操作成功") ;
    }
    public static <T> Resp<T> successMsg(String msg){
        return new Resp(0,msg) ;
    }
    public static <T> Resp<T> success(T data){
        return new Resp(0,"操作成功",data) ;
    }

    public static <T> Resp<T> failure(){
        return new Resp(-1,"操作失败") ;
    }
    public static <T> Resp<T> failure(String msg){
        return new Resp(-1,msg) ;
    }
    public static <T> Resp<T> failure(int code ,String msg){
        return new Resp(code,msg) ;
    }

}

PageReq.java 统一分页请求req类需要继承的父类

java 复制代码
package com.tingcream.tmccloud.base.core;

import lombok.Getter;
import lombok.Setter;

/**
 * 分页req基类
 */
@Getter
@Setter
public class PageReq {
    /**
     * 当前页码(默认1)
     */
    private Integer pageNum=1;
    /**
     * 每页条数(默认10)
     */
    private Integer pageSize=10;

    public PageReq() {

    }

    public PageReq(Integer pageNum, Integer pageSize) {
        this.pageNum = pageNum;
        this.pageSize = pageSize;
    }
}

BusinessException.java 统一使用业务异常类

java 复制代码
package com.tingcream.tmccloud.base.exception;


/**
 * 自定义业务异常类
 */
public class BusinessException extends RuntimeException {

    private static final long serialVersionUID = 4870534847958975482L;


    /**
     * 返回状态码  (9999系统异常)
     */
    private Integer code=9999 ;

    /**
     * 返回状态消息
     */
    private String msg;

    /**
     * 自定义data数据
     */
    private Object data ;

    public BusinessException(String message, Throwable cause) {
        super(message, cause);
    }


    public BusinessException(String msg) {
        this.msg = msg;
    }

    public BusinessException(Integer code, String msg) {
        this.code=code;
        this.msg = msg;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }
}

UuidUtil.java 基础工具(可生成8位短uuid)

java 复制代码
package com.tingcream.tmccloud.base.util;

import java.util.UUID;

public class UuidUtil {
    public static String[] chars = new String[]{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"};


    /**
     * 生成短UUID(8位随机数)
     * @return
     */
    public static String shortUuid() {
        StringBuilder builder = new StringBuilder();
        String uuid = UUID.randomUUID().toString().replace("-", "");

        for(int i = 0; i < 8; ++i) {
            String str = uuid.substring(i * 4, i * 4 + 4);
            int x = Integer.parseInt(str, 16);
            builder.append(chars[x % 62]);
        }

        return builder.toString();
    }

    /**
     * 生成uuid
     * @return
     */
    public static String uuid() {
        return UUID.randomUUID().toString().replace("-", "");
    }

}

2、tmccloud-base-web模块

web容器服务特性封装, 比如: 允许CORS跨域、JSR303参数验证、统一异常处理器封装等,依赖tmccloud-base-base模块。

pom.xml

XML 复制代码
<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/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.tingcream</groupId>
        <artifactId>tmccloud-base</artifactId>
        <version>1.0</version>
    </parent>
    <artifactId>tmccloud-base-web</artifactId>

    <dependencies>

        <dependency>
            <groupId>com.tingcream</groupId>
            <artifactId>tmccloud-base-base</artifactId>
            <version>${parent.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>${spring-boot.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-undertow</artifactId>
            <version>${spring-boot.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
            <version>3.1.5</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
            <version>${spring-boot.version}</version>
        </dependency>


        <!--hibernate-validator 兼容JAVA11-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
            <version>${spring-boot.version}</version>
        </dependency>


        <!--open feign 依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
            <version>3.1.5</version>
        </dependency>
        <!-- okhttp 扩展 -->
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-okhttp</artifactId>
            <version>11.8</version>
        </dependency>
        <!-- LB 扩展 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
            <version>3.1.5</version>
        </dependency>


        <!-- spring的织入  aspects  cglib  -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.3.22</version>
        </dependency>
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib-nodep</artifactId>
            <version>3.2.10</version>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.9</version>
        </dependency>

        <!--POi-->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>4.1.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>4.1.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml-schemas</artifactId>
            <version>4.1.2</version>
        </dependency>


    </dependencies>

</project>

CorsFilterConfig.java

java 复制代码
package com.tingcream.tmccloud.baseweb.config;

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

import java.util.Arrays;

@Configuration
public class CorsFilterConfig {

    /**
     * 配置允许CORS跨域
     * @return
     */
    @Bean
    public FilterRegistrationBean corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOriginPattern("*");
        config.addAllowedMethod("*");
        config.setAllowedMethods(Arrays.asList("GET","POST","PUT","DELETE","HEAD","OPTIONS","PATCH"));
        source.registerCorsConfiguration("/**", config);
        FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
        bean.setOrder(0);
        return bean;
    }

}

ValidatorConfig.java JSR303校验器配置

java 复制代码
package com.tingcream.tmccloud.baseweb.config;


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;


/**
 *  JSR303 参数验证
 */
@Configuration
public class ValidatorConfig {
    @Bean
    public MethodValidationPostProcessor methodValidationPostProcessor() {
        return new MethodValidationPostProcessor();
    }

}

GloalExceptionHandler.java 全局异常处理器

java 复制代码
package com.tingcream.tmccloud.baseweb.exception;


import com.tingcream.tmccloud.base.core.Resp;
import com.tingcream.tmccloud.base.exception.BusinessException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;


import java.util.List;

/**
 * 全局异常处理器
 */
@ControllerAdvice
@ResponseBody
@Slf4j
public class GlobalExceptionHandler {

    /**
     * JSR303 异常
     * @param e
     * @param request
     * @return
     */
    @ExceptionHandler({BindException.class})
    public Resp<?> handleBindException(BindException e, HttpServletRequest request) {
        log.error(e.getMessage());//记录完整错误信息
        List<ObjectError> errors = e.getBindingResult().getAllErrors();
        ObjectError err= errors.get(0);
        String msg = err.getDefaultMessage();
        return  Resp.failure(9999,msg);
    }
    /**
     * JSR303 异常
     * @param e
     * @param request
     * @return
     */
    @ExceptionHandler({MethodArgumentNotValidException.class})
    public Resp<?> handleMethodArgumentNotValidException(MethodArgumentNotValidException e, HttpServletRequest request) {
        log.error(e.getMessage());//记录完整错误信息
        List<ObjectError> errors = e.getBindingResult().getAllErrors();
        ObjectError err= errors.get(0);
        String msg = err.getDefaultMessage();
        return  Resp.failure(9999,msg);
    }
    /**
     * JSR303 异常
     * @param e
     * @param request
     * @return
     */
    @ExceptionHandler({ConstraintViolationException.class})
    public Resp<?> handleConstraintViolationExceptionException(ConstraintViolationException e, HttpServletRequest request) {
        log.error(e.getMessage());
        ConstraintViolation c  = (ConstraintViolation)e.getConstraintViolations().toArray()[0];
        String msg =c.getMessage();
        return  Resp.failure(9999,msg);
    }



    /**
     * BusinessException 自定义业务异常处理
     * @param e
     * @param request
     * @return
     */
    @ExceptionHandler({BusinessException.class})
    public Resp<?> handleBusinessException(BusinessException e, HttpServletRequest request) {
        //返回自定义的状态code和msg
        log.error(e.getMsg());
        return new Resp<>(e.getCode(), e.getMsg(), e.getData());
    }

    /**
     * Exception 异常
     * @param e
     * @param request
     * @return
     */
    @ExceptionHandler({Exception.class})
    public Resp<?> handleException(Exception e, HttpServletRequest request) {
        log.error(e.getMessage(),e);
        if(e instanceof HttpRequestMethodNotSupportedException){
          return Resp.failure(9998,"客户端http请求方式有误,请检查!");
        }
        return Resp.failure(9997,"抱歉,服务器繁忙请稍候再试!");
    }

}

3、tmccloud-base-redis模块

统一redis的序列化、反序列化方式

pom.xml

XML 复制代码
<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/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.tingcream</groupId>
        <artifactId>tmccloud-base</artifactId>
        <version>1.0</version>
    </parent>
    <artifactId>tmccloud-base-redis</artifactId>

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

    </dependencies>

</project>

MyRedisKeySerializer 自定义Redis序列化器

java 复制代码
package com.tingcream.tmccloud.baseredis;


import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;

import java.io.Serializable;
import java.nio.charset.Charset;

/**
 * 自定义的redis key序列化类
 *  key的可以为 String 、Integer、 Long 等类型
 */
public class MyRedisKeySerializer  implements RedisSerializer<Serializable> {
	
	private final Charset charset=Charset.forName("UTF8");
	
	@Override
	public byte[] serialize(Serializable t) throws SerializationException {
           if( t instanceof String) {
        	   String s = (String)t;
        	   return  (s == null ? null : s.getBytes(charset));
           }else if( t instanceof Integer) {
        	   String s=  String.valueOf((Integer) t);
        	   return  (s == null ? null : s.getBytes(charset));
           }else if( t instanceof Long) {
        	   String s=  String.valueOf((Long) t);
        	   return  (s == null ? null : s.getBytes(charset));
           }else{
           	  String s=String.valueOf(t);
			  return  (s == null ? null : s.getBytes(charset));
		   }
	}

	@Override
	public Serializable deserialize(byte[] bytes) throws SerializationException {
		return (bytes == null ? null : new String(bytes, charset));
	 
	}

}

RedisHelper工具bean

java 复制代码
package com.tingcream.tmccloud.baseredis;


import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.*;

import java.io.Serializable;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**  
* redis 辅助工具类
*/
public class RedisHelper {

	 //这里实际上注入的是 genericJackson2RedisTemplate 这个bean
	  private RedisTemplate<Serializable, Object> redisTemplate;

//	  @Autowired
//	  @Qualifier("genericJackson2RedisTemplate")
//	  private RedisTemplate<Serializable, Object> redisTemplate;


//	  public RedisTemplate<Serializable, Object> getRedisTemplate() {
//		  return redisTemplate;
//	  }


	  public void setRedisTemplate(  RedisTemplate<Serializable, Object> redisTemplate) {
	    this.redisTemplate = redisTemplate; 
	  }



	public  Long increment(String key){
		return redisTemplate.opsForValue().increment(key, 1);
	}

	public Boolean hasKey(String key) {
		return redisTemplate.hasKey(key);
	}

	//get
	public Object get( String key) {
		ValueOperations<Serializable, Object> operations = redisTemplate .opsForValue();
		return operations.get(key);
	}

	//set
	public void set( String key, Object value) {
		try {
			ValueOperations<Serializable, Object> operations = redisTemplate .opsForValue();
			operations.set(key, value);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	//set  timeout
	public void set( String key, Object value,long sec ) {
		try {
			ValueOperations<Serializable, Object> operations = redisTemplate .opsForValue();
			operations.set(key,value,sec, TimeUnit.SECONDS);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

    //当key不存在时写入key-value对并返回true,否则返回false
	public boolean setIfAbsent(String key,Object value){
		ValueOperations<Serializable, Object> operations = redisTemplate .opsForValue();
		return operations.setIfAbsent(key,value);
	}

	public boolean setIfAbsent(String key,Object value,long sec){
		ValueOperations<Serializable, Object> operations = redisTemplate .opsForValue();
		return operations.setIfAbsent(key,value,sec,TimeUnit.SECONDS);
	}



	//当key存在时写入key-value并返回true,否则返回false
	public boolean setIfPresent(String key,Object value){
		ValueOperations<Serializable, Object> operations = redisTemplate .opsForValue();
		return operations.setIfPresent(key,value);
	}
	public boolean setIfPresent(String key,Object value,long sec){
		ValueOperations<Serializable, Object> operations = redisTemplate .opsForValue();
		return operations.setIfPresent(key,value,sec,TimeUnit.SECONDS);
	}

	/**
	 *
	 * setNx  set if not exist
	 * @param key
	 * @param value
	 * @return
	 */
	public void setNx(final String key,String value,Long timeout){

		redisTemplate.opsForValue().set(key,value);
		redisTemplate.expire(key,timeout, TimeUnit.SECONDS);
	}

	public  void setNx(String key, String value, long timeout,TimeUnit timeUnit) {
		redisTemplate.opsForValue().set(key,value);
		redisTemplate.expire(key,timeout, timeUnit);
	}

	public Object listLeftPop(String key){
		return redisTemplate.opsForList().leftPop(key);
	}

	public void listRightPush(String key,Object value){
		redisTemplate.opsForList().rightPush(key,value);
	}



	/**
	 * setEx   set expire value
	 * 设置值,并同时设置key的有效期 (原子性(atomic)操作)
	 * @param key
	 * @param value
	 * @param secs 秒
	 */
	public boolean setEx(final String key,  byte[] value, long secs) {
		return redisTemplate.execute(new RedisCallback<Boolean>() {
			@Override
			public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
			  return 	connection.setEx(key.getBytes(),secs,value);
			}
		});
	}

	//hget
	public  Object   hget(String key,String field){
		BoundHashOperations<Serializable, String, Object> hashOperation=  redisTemplate.boundHashOps(key);
		return   hashOperation.get(field);
	}

	//hset
	 public  void     hset(String key ,String field,Object value){
		    BoundHashOperations<Serializable, String, Object> hashOperation=  redisTemplate.boundHashOps(key);
		    hashOperation.put(field, value);
	  }


	  // hdel
	  public  void hdel(String key,Object field){
		  BoundHashOperations<Serializable, String, Object> hashOperation=  redisTemplate.boundHashOps(key);
		   hashOperation.delete(field);
	  }

	  //hash  hdel  field1  field2
	  public  void hdel(final String key,final Object... fields){
		  BoundHashOperations<Serializable, String, Object> hashOperation=  redisTemplate.boundHashOps(key);
		  hashOperation.delete(fields);
	  }
	  
	  //hash hlen
	  public  Long    hlen(String key){
		  BoundHashOperations<Serializable, String, Object> hashOperation=  redisTemplate.boundHashOps(key);
		 return  hashOperation.size();
	  }
	  // hash  hkeys
	  public Set<String> hkeys(String key){
		  BoundHashOperations<Serializable, String, Object> hashOperation=  redisTemplate.boundHashOps(key);
		 return  hashOperation.keys();
	  }
	  // hash hvals
	  public   List<Object> hvals(String key){
		    BoundHashOperations<Serializable, String, Object> hashOperation=  redisTemplate.boundHashOps(key);
			 return  hashOperation.values();
	  }


	  // hash  hgetall
	  public   Map<String,Object> hgetall(String key){
		       BoundHashOperations<Serializable, String, Object> hashOperation=  redisTemplate.boundHashOps(key);
			 return  hashOperation.entries();
	  }
	  
	  // 删除多个可以 key1 key2 key3
	  public void del(final String... keys) {
		 
	    for (String key : keys) { 
	      del(key);
	    } 
	  } 
	  /** 
	   * 批量删除key  根据匹配的parttern
	   * 如 mylist*   能匹配 mylist1 mylist2  
	   */
	  public void delPattern(final String pattern) {
	    Set<Serializable> keys = redisTemplate.keys(pattern); 
	    if (keys.size() > 0) {
	    	redisTemplate.delete(keys);
	    }
	  }
	  
	  /**
	   * 删除key-Object  根据传入的key
	   */
	  public void del(final String key) {
	      redisTemplate.delete(key); 
	  }


	/**
	   * 判断缓存中是否存在 指定的key
	   */
	  public boolean exists(final String key) { 
	    return redisTemplate.hasKey(key); 
	  }


	/**
	 * 给 key 设置一个新的有效期 秒
	 * @param key
	 * @param sec
	 * @return
	 */
	public boolean expireKey( String key, long  sec){
		  return  redisTemplate.expire(key, sec, TimeUnit.SECONDS);
	  }




	  public long  incrBy(byte[] key,long by){
		  return redisTemplate.execute((RedisConnection connection) -> {
			  return connection.incrBy(key,by);//自增数字
		  });
	  }


	public  boolean expireAt(byte[] key,long unixTime){
		return redisTemplate.execute( (RedisConnection connection) -> {
			return connection.expireAt(key ,unixTime);
		});

	}

	public  boolean  pExpireAt(byte[] key,long unixTimeInMillis){
		return redisTemplate.execute((RedisConnection connection) -> {
			return connection.pExpireAt(key ,unixTimeInMillis);
		});
	}


	  /**
	   * 清空redis当前db
	   */
	public void flushDB(){
		  redisTemplate.execute(new RedisCallback<Integer>() {

				@Override
				public Integer doInRedis(RedisConnection connection)
						throws DataAccessException {
						connection.flushDb();
						return 0;
				}
			});
	}
	  /**
	   * 清空redis所有 db
	   */
	public void flushAll(){

		  redisTemplate.execute(new RedisCallback<Integer>() {

				@Override
				public Integer doInRedis(RedisConnection connection)
						throws DataAccessException {
						connection.flushAll();
						return 0;
				}
		    	
		});
	}


}

RedisConfig配置类

java 复制代码
package com.tingcream.tmccloud.baseredis;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;

import java.io.Serializable;

/**
 * redis自动化配置
 */
@Configuration
public class RedisConfig {

    @Bean("myRedisKeySerializer")
    @ConditionalOnMissingBean(name="myRedisKeySerializer")
    public MyRedisKeySerializer myRedisKeySerializer() {
        return new MyRedisKeySerializer();
    }

    @Bean("genericJackson2JsonRedisSerializer")
    @ConditionalOnMissingBean(name="genericJackson2JsonRedisSerializer")
    public  GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer() {
        return new   GenericJackson2JsonRedisSerializer();
    }

    @ConditionalOnMissingBean(name="genericJackson2RedisTemplate")
    @Bean(name="genericJackson2RedisTemplate")
    public RedisTemplate<Serializable, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {

        RedisTemplate redisTemplate = new RedisTemplate();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        redisTemplate.setKeySerializer(myRedisKeySerializer());//键
        redisTemplate.setHashKeySerializer(myRedisKeySerializer());//hash键
        redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer());//值
        redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer());//hash值
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    @ConditionalOnMissingBean(name="redisHelper")
    @Bean(name="redisHelper")
    public RedisHelper redisHelper(@Autowired @Qualifier("genericJackson2RedisTemplate")
                                               RedisTemplate<Serializable, Object> redisTemplate) {
        RedisHelper redisHelper = new RedisHelper();
        redisHelper.setRedisTemplate(redisTemplate);
        return redisHelper;
    }

}

4、tmccloud-base-mysql模块

引入mybatisplus 、pageHelper等依赖,支持mysql数据库操作,并扩展了mybatisplus的mysql的批量插入接口。

pom.xml

XML 复制代码
<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/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.tingcream</groupId>
        <artifactId>tmccloud-base</artifactId>
        <version>1.0</version>
    </parent>
    <artifactId>tmccloud-base-mysql</artifactId>


    <dependencies>

        <!-- mysql 驱动 -->
       <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.29</version>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.5</version>
            <exclusions>
                <exclusion>
                    <groupId>org.mybatis</groupId>
                    <artifactId>mybatis-spring</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>3.0.3</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.5.5</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-annotation</artifactId>
            <version>3.5.5</version>
        </dependency>

        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.31</version>
        </dependency>

        <!--pageHelper 分页插件-->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.4.3</version>
            <exclusions>
                <exclusion>
                    <groupId>org.mybatis</groupId>
                    <artifactId>mybatis</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.mybatis</groupId>
                    <artifactId>mybatis-spring</artifactId>
                </exclusion>
            </exclusions>
        </dependency>


    </dependencies>

</project>

EasyBaseMapper.java

java 复制代码
package com.tingcream.tmccloud.basemysql;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;

import java.util.Collection;

/**
 * 扩展通用 Mapper,支持数据批量插入
 */
public interface EasyBaseMapper<T> extends BaseMapper<T> {

    /**
     * 批量插入 仅适用于mysql
     * @param entityList 实体列表
     * @return 影响行数
     */
    Integer insertBatchSomeColumn(Collection<T> entityList);
}

EasySqlInjector.java

java 复制代码
package com.tingcream.tmccloud.basemysql;

import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.extension.injector.methods.InsertBatchSomeColumn;

import java.util.List;

/**
 * 支持自定义数据方法注入
 *
 */
public class EasySqlInjector extends DefaultSqlInjector {
    @Override
    public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {

        List<AbstractMethod> methodList = super.getMethodList(mapperClass,tableInfo);
        methodList.add(new InsertBatchSomeColumn());
        return methodList;
    }
}

MybatisPlusConfig.java

java 复制代码
package com.tingcream.tmccloud.basemysql;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MybatisPlusConfig {

    @Bean
    public EasySqlInjector easySqlInjector() {
        return new EasySqlInjector();
    }
}

一般地,我们新建一个web服务(如demoweb服务)至少需引入tmccloud-base-web的依赖即可。如果这个服务还需要连接操作mysql数据库,则再引入tmcloud-base-mysql依赖,如果还需要连接操作redis,则再引入tmccloud-base-redis的依赖即可。

三、项目代码

源码详见笔者gitee仓库: https://gitee.com/jellyflu/tmccloud-base

相关推荐
alonewolf_999 小时前
MySQL 架构与SQL执行全流程深度解析
sql·mysql·架构
一条咸鱼_SaltyFish9 小时前
[Day16] Bug 排查记录:若依框架二次开发中的经验与教训 contract-security-ruoyi
java·开发语言·经验分享·微服务·架构·bug·开源软件
幻云20109 小时前
Next.js 之道:从全栈思维到架构实战
开发语言·javascript·架构
没有bug.的程序员10 小时前
Kubernetes 与微服务的融合架构:调度、弹性、健康检查深度协同
jvm·微服务·云原生·架构·kubernetes·健康检查·弹性伸缩
C+++Python10 小时前
Flume的核心概念和架构
大数据·架构·flume
Jing_jing_X16 小时前
AI分析不同阶层思维 二:Spring 的事务在什么情况下会失效?
java·spring·架构·提升·薪资
Kendra91918 小时前
Kubernetes 常用命令
云原生·容器·kubernetes
元Y亨H18 小时前
Nacos - 服务发现
java·微服务
jump_jump1 天前
SaaS 时代已死,SaaS 时代已来
前端·后端·架构