<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webfluxartifactId>
dependency>
import org.springframework.http.HttpHeaders;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
import java.util.Map;
===========================================================================
/**
* 远程调用,发送post请求
*
* @param pathUrl 请求的访问的路径 如:/art/approval
* @param requestBody 请求体(也可以是自定义的某个实体类)
* @return 请求返回的结果,用R接收
*/
private R remotePostCall(String pathUrl, Map<String, String> requestBody) {
WebClient client = WebClient.create();
// 发起POST请求,并设置请求头和请求体
Mono<R> responseMono = client.post()
.uri(uri + pathUrl)
// 设置请求头
.header(HttpHeaders.CONTENT_TYPE, "application/json;charset=UTF-8")
.header(HttpHeaders.AUTHORIZATION, "you token")
// 设置请求体
.body(BodyInserters.fromValue(requestBody))
.retrieve()
// 将返回结果转换为R类型
.bodyToMono(R.class);
R block = responseMono.block();
return block;
}
这个请求是异步的。在代码中,使用了 Mono 来表示返回结果, Mono 是一个Reactive类型,它表示可能会在未来某个时间点返回的结果。通过使用 bodyToMono() 方法将返回结果转换为 Mono 类型,然后使用 block() 方法来
阻塞
等待结果的返回。这种异步的方式可以提高应用程序的性能和并发处理能力。
可以使用 subscribe()
方法来实现不阻塞等待结果的返回。通过调用 subscribe()
方法,可以注册一个回调函数来处理异步返回的结果。这样,可以在结果返回时执行相应的操作,不需要阻塞等待。
private void remotePostCall(String pathUrl, Map<String, String> requestBody) {
WebClient client = WebClient.create();
// 发起POST请求,并设置请求头和请求体
client.post()
.uri(uri + pathUrl)
// 设置请求头
.header(HttpHeaders.CONTENT_TYPE, "application/json;charset=UTF-8")
.header(HttpHeaders.AUTHORIZATION, "you token")
// 设置请求体
.body(BodyInserters.fromValue(requestBody))
.retrieve()
// 处理返回结果
.bodyToMono(R.class)
.subscribe(result -> {
// 在这里处理异步返回的结果
// 可以执行相应的操作
System.out.println("异步结果:" + result);
});
}
在分布式项目中,我们主键喜欢使用雪花Id,可能会遇到一些精度丢失或数据截断的问题,特别是在处理大整数时。将 Long 类型转换为 String 类型可以避免这些问题,并确保数据的准确性和完整性。
通过自定义Jackson的对象映射器行为,可以确保在分布式项目中处理长整型数据时的一致性和可靠性。
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class JacksonConfiguration {
@Bean
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
return builder -> {
// 返回结果时,统一将 Long 转换成 String
builder.serializerByType(Long.class, ToStringSerializer.instance);
};
}
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @Author shang tf
* @createTime 2023/8/15 10:35
* @Version 1.0.0
* 需要成为数商后才能访问
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface HasPayAuth {
}
import cn.creatoo.common.core.constant.Constants;
import cn.creatoo.common.security.utils.BdSecurityUtils;
import cn.creatoo.system.exception.NotPayAuthException;
import cn.creatoo.system.domain.BdTerminalUserAuth;
import cn.creatoo.system.mapper.BdTerminalUserAuthMapper;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
/**
* @Author shang tf
* @createTime 2023/8/15 10:41
* @Version 1.0.0
*/
@Aspect
@Component
public class HasPayAuthAspect {
@Pointcut("@annotation(xx.xxxxx.system.annotation.HasPayAuth)")
private void pointcut() {
}
@Autowired
private BdTerminalUserAuthMapper bdTerminalUserAuthMapper;
@Around("pointcut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
// 查询当前登录账号信息
Long userId = BdSecurityUtils.getUserId();
QueryWrapper<BdTerminalUserAuth> wrapper = new QueryWrapper<>();
wrapper.eq("user_id", userId);
BdTerminalUserAuth bdTerminalUserAuth = bdTerminalUserAuthMapper.selectOne(wrapper);
if (ObjectUtil.isEmpty(bdTerminalUserAuth)){
throw new NotPayAuthException("未提交认证,请先认证");
}
// 账号状态
if (!bdTerminalUserAuth.getStatus().equals(Constants.AUTH_AUDIT_CERTIFIED)){
throw new NotPayAuthException("账号未认证,请先认证");
}
// 判断账号是否被禁用
if (bdTerminalUserAuth.getIsAble().equals(Constants.AUTH_IS_ABLE_OFF)){
throw new NotPayAuthException("账号被禁用,请联系管理员");
}
// 放行
return joinPoint.proceed(joinPoint.getArgs());
}
}
自定义异常时需要继承RuntimeException
/**
* @Author shang tf
* @createTime 2023/8/15 10:58
* @Version 1.0.0
* 资质认证过期或未认证异常
*/
public class NotPayAuthException extends RuntimeException {
public NotPayAuthException() {
}
public NotPayAuthException(String message){
super(message);
}
}
MD5加密
请注意,MD5算法是单向散列函数,不可逆。因此,我们无法从MD5加密后的值还原出原始字符串。MD5算法通常用于密码存储和验证等场景,但由于其安全性较低,现在更常用的是更强大的加密算法,如SHA-256等。
ADCryptUtils
通过此工具类可以将字符串进行加密解密,可以解析出原本的字符串
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.Security;
public class ADCryptUtils {
static { try { Security.addProvider(new BouncyCastleProvider()); } catch (Exception e) { e.printStackTrace(); } }
// vi 076ce634d7da11eb
private static final byte[] DES_DEFAULT_KEY=new byte[] { 10, 20, 50, 99, 101, 54, 51, 52, 100, 55, 100, 97, 49, 49, 112, 98 };
private static final byte[] AES_DEFAULT_KEY=new byte[] { 10, 20, 50, 99, 101, 54, 51, 52, 100, 55, 100, 97, 49, 49, 112, 98 };
/**
* content: 加密内容
*/
public static String encryptAes(String content) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKey secretKey = new SecretKeySpec(AES_DEFAULT_KEY, "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey,new IvParameterSpec(AES_DEFAULT_KEY));
byte[] encrypted = cipher.doFinal(content.getBytes());
return Base64.encode(encrypted);
}
/**
* content: 解密内容
*/
public static String decryptAes(String base64Content) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKey secretKey = new SecretKeySpec(AES_DEFAULT_KEY, "AES");
cipher.init(Cipher.DECRYPT_MODE, secretKey,new IvParameterSpec(AES_DEFAULT_KEY));
byte[] content = Base64.decode(base64Content);
byte[] encrypted = cipher.doFinal(content);
return new String(encrypted);
}
/**
* content: 加密内容
*/
public static String encryptDes(String content) throws Exception {
Cipher cipher = Cipher.getInstance("DES");
SecretKey secretKey = new SecretKeySpec(DES_DEFAULT_KEY, "DES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] encrypted = cipher.doFinal(content.getBytes());
return Base64.encode(encrypted);
}
/**
* content: 解密内容
*/
public static String decryptDes(String base64Content) throws Exception {
Cipher cipher = Cipher.getInstance("DES");
SecretKey secretKey = new SecretKeySpec(DES_DEFAULT_KEY, "DES");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] content = Base64.decode(base64Content);
byte[] encrypted = cipher.doFinal(content);
return new String(encrypted);
}
/**
* content: 加密内容
* slatKey: 加密的盐,16位字符串
*/
public static String encryptAes(String content, String slatKey) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKey secretKey = new SecretKeySpec(slatKey.getBytes(), "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey,new IvParameterSpec(AES_DEFAULT_KEY));
byte[] encrypted = cipher.doFinal(content.getBytes());
return Base64.encode(encrypted);
}
/**
* content: 解密内容
* slatKey: 加密时使用的盐,16位字符串
*/
public static String decryptAes(String base64Content, String slatKey) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKey secretKey = new SecretKeySpec(slatKey.getBytes(), "AES");
cipher.init(Cipher.DECRYPT_MODE, secretKey,new IvParameterSpec(AES_DEFAULT_KEY));
byte[] content = Base64.decode(base64Content);
byte[] encrypted = cipher.doFinal(content);
return new String(encrypted);
}
/**
* content: 加密内容
* slatKey: 加密的盐,16位字符串
* vectorKey: 加密的向量,16位字符串
*/
public static String encryptAes(String content, String slatKey, String vectorKey) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKey secretKey = new SecretKeySpec(slatKey.getBytes(), "AES");
IvParameterSpec iv = new IvParameterSpec(vectorKey.getBytes());
cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
byte[] encrypted = cipher.doFinal(content.getBytes());
return Base64.encode(encrypted);
}
/**
* content: 解密内容(base64编码格式)
* slatKey: 加密时使用的盐,16位字符串
* vectorKey: 加密时使用的向量,16位字符串
*/
public static String decryptAes(String base64Content, String slatKey, String vectorKey) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKey secretKey = new SecretKeySpec(slatKey.getBytes(), "AES");
IvParameterSpec iv = new IvParameterSpec(vectorKey.getBytes());
cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
byte[] content = Base64.decode(base64Content);
byte[] encrypted = cipher.doFinal(content);
return new String(encrypted);
}
/**
* content: 加密内容
* slatKey: 加密的盐,8位字符串
*/
public static String encryptDes(String content, String slatKey) throws Exception {
Cipher cipher = Cipher.getInstance("DES");
SecretKey secretKey = new SecretKeySpec(slatKey.getBytes(), "DES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] encrypted = cipher.doFinal(content.getBytes());
return Base64.encode(encrypted);
}
/**
* content: 解密内容
* slatKey: 加密时使用的盐,8位字符串
*/
public static String decryptDes(String base64Content, String slatKey) throws Exception {
Cipher cipher = Cipher.getInstance("DES");
SecretKey secretKey = new SecretKeySpec(slatKey.getBytes(), "DES");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] content = Base64.decode(base64Content);
byte[] encrypted = cipher.doFinal(content);
return new String(encrypted);
}
public static void main(String[] args) {
try {
String encryptDes = ADCryptUtils.encryptAes("测试AES加密");
System.out.println(encryptDes);
String decryptDes = ADCryptUtils.decryptAes(encryptDes);
System.out.println(decryptDes);
} catch (Exception e) {
e.printStackTrace();
}
}
}