本篇我们开始尝试搭建一套新的微服务项目
项目采用最新技术栈: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