Welcome to Aixin.me ❤️

  1. 提升胜任力,首先是动物本能,指的是生物天生具有的、未经思考的行为反应。
  2. 接着是自我反省,即对自己的行为、思想进行反思和审视。
  3. 情绪控制意味着能够管理和调节自己的情绪。知行合一表示认知和行动的统一。
  4. 专注与无私强调专注于某件事情并且不自私。利他是为他人利益考虑和行动。
  5. 最后,启蒙与觉醒指的是在思想和认知上达到更高的境界,获得新的领悟和成长。

Validator.js使用教程

Validator是一个字符串验证和清理的库。 https://github.com/validatorjs/validator.js 仅限字符串 这个库只验证和清理字符串。 如果你不确定你的输入是否是字符串,请使用 input + '' 进行强制转换。传递非字符串将导致错误。 安装与使用 服务器端使用 安装 validator 包: 1 2 3 npm install validator yarn add validator pnpm install validator 不使用 ES6 1 2 3 var validator = require('validator'); validator.isEmail('foo@bar.com'); // => true 使用 ES6 1 import validator from 'validator'; 或者,仅导入库的一部分: 1 import isEmail from 'validator/lib/isEmail'; Tree-shakeable ES 导入 1 import isEmail from 'validator/es/lib/isEmail'; 客户端使用 该库可以作为独立脚本加载,或通过 [AMD][amd] 兼容的加载器加载: 1 2 3 4 <script type="text/javascript" src="validator.min.js"></script> <script type="text/javascript"> validator.isEmail('foo@bar.com'); // => true </script> 该库也可以通过 [bower][bower] 安装: ...

2025-05-13 · 11 min · 2198 words

Springboot Jwt

安装JWT依赖 1 2 3 4 5 <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>4.5.0</version> </dependency> 定义Jwt工具类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 package com.example.demo.utils; import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.exceptions.JWTVerificationException; import com.auth0.jwt.exceptions.SignatureVerificationException; import com.auth0.jwt.exceptions.TokenExpiredException; import com.auth0.jwt.interfaces.DecodedJWT; import com.auth0.jwt.interfaces.JWTVerifier; import org.springframework.stereotype.Component; import java.util.Collections; import java.util.Date; import java.util.Map; @Component public class JwtUtils { private static final String SECRET_KEY = "Pxiv0oevyL8rT3an11QKL208vYlkvAmt"; private static final String ISSUER = "admin_service"; private static final long EXPIRATION_TIME = 3600000; public static String generateToken(Map<String, Object> claims) { // 定义密钥 Algorithm algorithm = Algorithm.HMAC256(SECRET_KEY); // 获取当前时间 Date now = new Date(); // 设置过期时间 Date expiration = new Date(now.getTime() + EXPIRATION_TIME); // 构建JWT并添加所有自定义claim com.auth0.jwt.JWTCreator.Builder tokenBuilder = JWT.create() .withIssuer(ISSUER) .withIssuedAt(now) .withExpiresAt(expiration); // 遍历添加每个自定义claim if (claims != null && !claims.isEmpty()) { for (Map.Entry<String, Object> entry : claims.entrySet()) { String key = entry.getKey(); Object value = entry.getValue(); // 根据值类型选择对应的 withClaim 方法重载 if (value instanceof String) { tokenBuilder.withClaim(key, (String) value); } else if (value instanceof Integer) { tokenBuilder.withClaim(key, (Integer) value); } else if (value instanceof Long) { tokenBuilder.withClaim(key, (Long) value); } else if (value instanceof Boolean) { tokenBuilder.withClaim(key, (Boolean) value); } else if (value instanceof Double) { tokenBuilder.withClaim(key, (Double) value); } else if (value instanceof Float) { tokenBuilder.withClaim(key, Collections.singletonList((Float) value)); } else if (value instanceof Short) { tokenBuilder.withClaim(key, Collections.singletonList((Short) value)); } else if (value instanceof Byte) { tokenBuilder.withClaim(key, Collections.singletonList((Byte) value)); } else if (value instanceof Enum<?>) { tokenBuilder.withClaim(key, (Map<String, ?>) value); } } } return tokenBuilder.sign(algorithm); } public static Object validateToken(String token) { try { Algorithm algorithm = Algorithm.HMAC256(SECRET_KEY); JWTVerifier verifier = JWT.require(algorithm) .withIssuer(ISSUER) .build(); DecodedJWT jwt = verifier.verify(token); return "success"; } catch (SignatureVerificationException e) { return "签名验证失败"; } catch (TokenExpiredException e) { return "Token已过期"; } catch (JWTVerificationException e) { return e.getLocalizedMessage(); } } } 定义JwtInterceptor 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 package com.example.demo.config; import cn.hutool.json.JSONUtil; import com.example.demo.utils.JwtUtils; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class JwtInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token = request.getHeader("Authorization"); if (token == null || "".equals(token)) { response.setCharacterEncoding("UTF-8"); response.getWriter().write(JSONUtil.toJsonStr("未登录")); return false; } Object result = JwtUtils.validateToken(token); if ("success".equals(result)) { return true; } else { response.setCharacterEncoding("UTF-8"); response.getWriter().write(JSONUtil.toJsonStr(result)); return false; } } } 配置拦截器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package com.example.demo.config; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebAppConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new JwtInterceptor()) .addPathPatterns("/**") // 拦截所有请求,可根据实际需求调整路径模式 .excludePathPatterns("/login"); // 排除登录接口 } } 使用JWT生成Token 1 2 3 4 5 6 7 Map<String, Object> claims = new HashMap<>(); claims.put("userId", userId); claims.put("username", username); // 其他自定义claim... String token = JwtUtils.generateToken(claims); return JSONUtil.toJsonStr(token); 这样你就完成了Spring Boot项目中JWT的集成和使用。记得根据你的项目实际情况对代码进行适当修改和扩展。 ...

2025-04-30 · 3 min · 525 words

Springboot Response

1. 创建HTTP状态码枚举 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 package com.example.demo.utils; import lombok.Getter; @Getter public enum HttpStatusEnum { /** * 操作成功 */ SUCCESS(200, "操作成功"), /** * 对象创建成功 */ CREATED(201, "对象创建成功"), /** * 请求已经被接受 */ ACCEPTED(202, "请求已经被接受"), /** * 操作已经执行成功,但是没有返回数据 */ NO_CONTENT(204, "操作已经执行成功,但是没有返回数据"), /** * 资源已被移除 */ MOVED_PERM(301, "资源已被移除"), /** * 重定向 */ SEE_OTHER(303, "重定向"), /** * 资源没有被修改 */ NOT_MODIFIED(304, "资源没有被修改"), /** * 参数列表错误(缺少,格式不匹配) */ BAD_REQUEST(400, "参数列表错误(缺少,格式不匹配)"), /** * 未授权 */ UNAUTHORIZED(401, "未授权"), /** * 访问受限,授权过期 */ FORBIDDEN(403, "访问受限,授权过期"), /** * 资源,服务未找到 */ NOT_FOUND(404, "资源,服务未找!"), /** * 不允许的http方法 */ BAD_METHOD(405, "不允许的http方法"), /** * 资源冲突,或者资源被锁 */ CONFLICT(409, "资源冲突,或者资源被锁"), /** * 不支持的数据,媒体类型 */ UNSUPPORTED_TYPE(415, "不支持的数据,媒体类型"), /** * 系统内部错误 */ ERROR(500, "系统内部错误"), /** * 接口未实现 */ NOT_IMPLEMENTED(501, "接口未实现"), /** * 系统警告消息 */ WARN(601,"系统警告消息"); private final Integer code; private final String message; HttpStatusEnum(Integer code, String message) { this.code = code; this.message = message; } } 2. 创建通用返回类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 package com.example.demo.utils; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class ResponseResult<T> { /*状态码*/ private Integer code; /*状态信息*/ private Boolean status; /*返回信息*/ private String message; /*返回数据*/ private T data; /** * 全参数方法 * * @param code 状态码 * @param status 状态 * @param message 返回信息 * @param data 返回数据 * @param <T> 泛型 * @return {@link ResponseResult<T>} */ private static <T> ResponseResult<T> response(Integer code, Boolean status, String message, T data) { ResponseResult<T> responseResult = new ResponseResult<>(); responseResult.setCode(code); responseResult.setStatus(status); responseResult.setMessage(message); responseResult.setData(data); return responseResult; } /** * 全参数方法 * * @param code 状态码 * @param status 状态 * @param message 返回信息 * @param <T> 泛型 * @return {@link ResponseResult<T>} */ private static <T> ResponseResult<T> response(Integer code, Boolean status, String message) { ResponseResult<T> responseResult = new ResponseResult<>(); responseResult.setCode(code); responseResult.setStatus(status); responseResult.setMessage(message); return responseResult; } /** * 成功返回(无参) * * @param <T> 泛型 * @return {@link ResponseResult<T>} */ public static <T> ResponseResult<T> success() { return response(HttpStatusEnum.SUCCESS.getCode(), true, HttpStatusEnum.SUCCESS.getMessage(), null); } /** * 成功返回(枚举参数) * * @param httpResponseEnum 枚举参数 * @param <T> 泛型 * @return {@link ResponseResult<T>} */ public static <T> ResponseResult<T> success(HttpStatusEnum httpResponseEnum) { return response(httpResponseEnum.getCode(), true, httpResponseEnum.getMessage()); } /** * 成功返回(状态码+返回信息) * * @param code 状态码 * @param message 返回信息 * @param <T> 泛型 * @return {@link ResponseResult<T>} */ public static <T> ResponseResult<T> success(Integer code, String message) { return response(code, true, message); } /** * 成功返回(返回信息 + 数据) * * @param message 返回信息 * @param data 数据 * @param <T> 泛型 * @return {@link ResponseResult<T>} */ public static <T> ResponseResult<T> success(String message, T data) { return response(HttpStatusEnum.SUCCESS.getCode(), true, message, data); } /** * 成功返回(状态码+返回信息+数据) * * @param code 状态码 * @param message 返回信息 * @param data 数据 * @param <T> 泛型 * @return {@link ResponseResult<T>} */ public static <T> ResponseResult<T> success(Integer code, String message, T data) { return response(code, true, message, data); } /** * 成功返回(数据) * * @param data 数据 * @param <T> 泛型 * @return {@link ResponseResult<T>} */ public static <T> ResponseResult<T> success(T data) { return response(HttpStatusEnum.SUCCESS.getCode(), true, HttpStatusEnum.SUCCESS.getMessage(), data); } /** * 成功返回(返回信息) * * @param message 返回信息 * @param <T> 泛型 * @return {@link ResponseResult<T>} */ public static <T> ResponseResult<T> success(String message) { return response(HttpStatusEnum.SUCCESS.getCode(), true, message, null); } /** * 失败返回(无参) * * @param <T> 泛型 * @return {@link ResponseResult<T>} */ public static <T> ResponseResult<T> fail() { return response(HttpStatusEnum.ERROR.getCode(), false, HttpStatusEnum.ERROR.getMessage(), null); } /** * 失败返回(枚举) * * @param httpResponseEnum 枚举 * @param <T> 泛型 * @return {@link ResponseResult<T>} */ public static <T> ResponseResult<T> fail(HttpStatusEnum httpResponseEnum) { return response(httpResponseEnum.getCode(), false, httpResponseEnum.getMessage()); } /** * 失败返回(状态码+返回信息) * * @param code 状态码 * @param message 返回信息 * @param <T> 泛型 * @return {@link ResponseResult<T>} */ public static <T> ResponseResult<T> fail(Integer code, String message) { return response(code, false, message); } /** * 失败返回(返回信息+数据) * * @param message 返回信息 * @param data 数据 * @param <T> 泛型 * @return {@link ResponseResult<T>} */ public static <T> ResponseResult<T> fail(String message, T data) { return response(HttpStatusEnum.ERROR.getCode(), false, message, data); } /** * 失败返回(状态码+返回信息+数据) * * @param code 状态码 * @param message 返回消息 * @param data 数据 * @param <T> 泛型 * @return {@link ResponseResult<T>} */ public static <T> ResponseResult<T> fail(Integer code, String message, T data) { return response(code, false, message, data); } /** * 失败返回(数据) * * @param data 数据 * @param <T> 泛型 * @return {@link ResponseResult<T>} */ public static <T> ResponseResult<T> fail(T data) { return response(HttpStatusEnum.ERROR.getCode(), false, HttpStatusEnum.ERROR.getMessage(), data); } /** * 失败返回(返回信息) * * @param message 返回信息 * @param <T> 泛型 * @return {@link ResponseResult<T>} */ public static <T> ResponseResult<T> fail(String message) { return response(HttpStatusEnum.ERROR.getCode(), false, message, null); } } 3. 使用示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package com.example.demo.controller; import com.example.demo.utils.ResponseResult; @RequestMapping("") public class Hello { @GetMapping("/success") public ResponseResult<String> success() { return ResponseResult.success("操作成功"); } @GetMapping("/fail") public ResponseResult<String> fail() { return ResponseResult.fail(HttpStatusEnum.PARAM_ERROR); } }

2025-04-30 · 6 min · 1101 words

Springboot使用Sentinel实现流量控制与熔断降级

1、安装Sentinel 1 2 3 4 5 <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-core</artifactId> <version>1.8.8</version> </dependency>

2025-04-30 · 1 min · 11 words

Mysql使用JSON_CONTAINS查询JSON字段值

在 MySQL 里,JSON_CONTAINS 方法是可以用于多维 JSON 数据的,不过使用时要依据具体的场景与需求,采用不同的处理方式。下面为你详细介绍相关内容。 基本语法 JSON_CONTAINS(target, candidate[, path]) target:需要被检查的 JSON 文档。 candidate:要查找的 JSON 值。 path:可选参数,指定在 target 中进行查找的路径。 示例说明 1、单维 JSON 数组 1 2 3 4 5 6 7 8 9 10 11 -- 创建示例表 CREATE TABLE test_table ( id INT AUTO_INCREMENT PRIMARY KEY, json_data JSON ); -- 插入示例数据 INSERT INTO test_table (json_data) VALUES ('["apple", "banana", "cherry"]'); -- 查询包含 "banana" 的记录 SELECT * FROM test_table WHERE JSON_CONTAINS(json_data, '"banana"'); 在这个例子中,json_data 是单维 JSON 数组,JSON_CONTAINS 直接查找其中是否包含 "banana"。 ...

2025-04-25 · 1 min · 173 words

Springboot上传图片

在 Spring Boot 3 中,要实现限制上传图片尺寸、格式以及对图片进行裁剪压缩处理,可以按照以下步骤进行。下面是一个完整的示例代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; @RestController public class ImageUploadController { private static final String UPLOAD_DIR = "uploads"; private static final String[] ALLOWED_TYPES = {"image/jpeg", "image/png", "image/gif"}; private static final int MAX_WIDTH = 1920; private static final int MAX_HEIGHT = 1080; private static final int TARGET_WIDTH = 800; private static final int TARGET_HEIGHT = 600; @PostMapping("/upload") public ResponseEntity<String> uploadImage(@RequestParam("image") MultipartFile file) { if (file.isEmpty()) { return new ResponseEntity<>("请选择要上传的图片", HttpStatus.BAD_REQUEST); } // 检查文件类型 String contentType = file.getContentType(); boolean isAllowed = false; for (String allowedType : ALLOWED_TYPES) { if (allowedType.equals(contentType)) { isAllowed = true; break; } } if (!isAllowed) { return new ResponseEntity<>("不支持的文件类型,仅支持 JPEG、PNG 和 GIF 格式", HttpStatus.BAD_REQUEST); } try { BufferedImage image = ImageIO.read(file.getInputStream()); int width = image.getWidth(); int height = image.getHeight(); // 检查图片尺寸 if (width > MAX_WIDTH || height > MAX_HEIGHT) { return new ResponseEntity<>("图片尺寸过大,最大宽度为 " + MAX_WIDTH + ",最大高度为 " + MAX_HEIGHT, HttpStatus.BAD_REQUEST); } // 裁剪和压缩图片 BufferedImage resizedImage = resizeImage(image, TARGET_WIDTH, TARGET_HEIGHT); // 创建上传目录(如果不存在) File uploadDir = new File(UPLOAD_DIR); if (!uploadDir.exists()) { uploadDir.mkdirs(); } // 获取文件名 String fileName = file.getOriginalFilename(); Path filePath = Paths.get(UPLOAD_DIR, fileName); // 保存处理后的图片 String format = contentType.split("/")[1]; ImageIO.write(resizedImage, format, filePath.toFile()); return new ResponseEntity<>("图片上传并处理成功", HttpStatus.OK); } catch (IOException e) { e.printStackTrace(); return new ResponseEntity<>("图片上传失败", HttpStatus.INTERNAL_SERVER_ERROR); } } private BufferedImage resizeImage(BufferedImage originalImage, int targetWidth, int targetHeight) { BufferedImage resizedImage = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_RGB); Graphics2D graphics2D = resizedImage.createGraphics(); graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); graphics2D.drawImage(originalImage, 0, 0, targetWidth, targetHeight, null); graphics2D.dispose(); return resizedImage; } } 代码说明 文件类型限制: ALLOWED_TYPES 数组定义了允许上传的图片格式,在 uploadImage 方法中,通过 file.getContentType() 获取文件的 MIME 类型,并与 ALLOWED_TYPES 进行比较,若不匹配则返回错误信息。 图片尺寸限制: MAX_WIDTH 和 MAX_HEIGHT 定义了允许上传的最大图片尺寸。在 uploadImage 方法中,使用 ImageIO.read 读取图片文件为 BufferedImage 对象,然后获取其宽度和高度,若超过最大尺寸则返回错误信息。 图片裁剪压缩处理: TARGET_WIDTH 和 TARGET_HEIGHT 定义了处理后图片的目标尺寸。resizeImage 方法用于将原始图片按照目标尺寸进行裁剪和压缩,使用 Graphics2D 进行绘制,最后返回处理后的 BufferedImage 对象。 在 uploadImage 方法中,调用 resizeImage 方法对图片进行处理,然后使用 ImageIO.write 将处理后的图片保存到指定目录。

2025-04-25 · 2 min · 393 words

Springboot使用Redisson分布式锁

在 Spring Boot 项目里,运用 Redisson 实现分布式锁来处理销售扣减库存和入库增加库存,且同时操作一个库存值,可按以下步骤完成: 1、添加依赖 在pom.xml文件里添加 Redisson 和 Spring Boot Data Redis 的依赖: 1 2 3 4 5 6 7 8 9 10 11 12 13 <dependencies> <!-- Redisson --> <dependency> <groupId>org.redisson</groupId> <artifactId>redisson-spring-boot-starter</artifactId> <version>3.16.2</version> </dependency> <!-- Spring Boot Data Redis --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> </dependencies> 2、配置 Redisson 在application.yml文件里配置 Redis: 1 2 3 4 spring: redis: host: localhost port: 6379 3、在service中使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.concurrent.TimeUnit; @Service public class InventoryService { @Autowired private RedissonClient redissonClient; // 库存键名 private static final String INVENTORY_KEY = "product:inventory:1"; /** * 销售扣减库存 * @param quantity 扣减数量 * @return 是否成功 */ public boolean deductInventory(int quantity) { // 获取分布式锁 RLock lock = redissonClient.getLock(INVENTORY_KEY); try { // 尝试加锁,等待10秒,自动释放锁时间为30秒 if (lock.tryLock(10, 30, TimeUnit.SECONDS)) { // 模拟从Redis获取当前库存 Integer currentInventory = getInventoryFromRedis(); if (currentInventory != null && currentInventory >= quantity) { // 扣减库存 int newInventory = currentInventory - quantity; // 更新Redis中的库存 updateInventoryInRedis(newInventory); return true; } } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { // 释放锁 if (lock.isHeldByCurrentThread()) { lock.unlock(); } } return false; } /** * 入库增加库存 * @param quantity 增加数量 */ public void addInventory(int quantity) { // 获取分布式锁 RLock lock = redissonClient.getLock(INVENTORY_KEY); try { // 尝试加锁,等待10秒,自动释放锁时间为30秒 if (lock.tryLock(10, 30, TimeUnit.SECONDS)) { // 模拟从Redis获取当前库存 Integer currentInventory = getInventoryFromRedis(); if (currentInventory != null) { // 增加库存 int newInventory = currentInventory + quantity; // 更新Redis中的库存 updateInventoryInRedis(newInventory); } } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { // 释放锁 if (lock.isHeldByCurrentThread()) { lock.unlock(); } } } /** * 从Redis获取当前库存 * @return 当前库存 */ private Integer getInventoryFromRedis() { // 这里需要根据实际情况实现从Redis获取库存的逻辑 return 100; } /** * 更新Redis中的库存 * @param newInventory 新的库存数量 */ private void updateInventoryInRedis(int newInventory) { // 这里需要根据实际情况实现更新Redis库存的逻辑 } } 代码解释 ...

2025-04-25 · 3 min · 446 words

Spring boot 限流

在 Spring Boot 3 中实现限流可以采用多种方式,下面为你介绍常见的三种: 1、使用 Sentinel 实现限流 Sentinel 是阿里巴巴开源的一款流量控制组件,具备实时监控、限流、熔断等功能。 步骤 添加依赖:在pom.xml里添加 Sentinel 的依赖。 1 2 3 4 5 <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-spring-boot-starter</artifactId> <version>1.8.6</version> </dependency> 配置规则:创建一个配置类来设置限流规则。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import com.alibaba.csp.sentinel.slots.block.RuleConstant; import com.alibaba.csp.sentinel.slots.block.flow.FlowRule; import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager; import org.springframework.context.annotation.Configuration; import javax.annotation.PostConstruct; import java.util.ArrayList; import java.util.List; @Configuration public class SentinelConfig { @PostConstruct public void initFlowRules() { List<FlowRule> rules = new ArrayList<>(); FlowRule rule = new FlowRule(); rule.setResource("yourResourceName"); rule.setCount(10); // 每秒最多允许10个请求 rule.setGrade(RuleConstant.FLOW_GRADE_QPS); rule.setLimitApp("default"); rules.add(rule); FlowRuleManager.loadRules(rules); } } 添加注解:在需要限流的方法上添加@SentinelResource注解。 ...

2025-04-25 · 2 min · 369 words

Antdv常见问题

Form 表单 官方文档:https://antdv.com/components/form-cn 问题:通过对象数据遍历表单组件,校验不生效或者校验不通过: 原因: rules必须加载<a-form-item>上,不能加载input、select等组件上,否则校验不生效 组件的v-model:value必须单独关联一个formdata对象中,不能直接使用原始数据对象,否则任何时候都显示校验提示,可以先将原始数据对象深拷贝到formdata对象中,然后再使用formdata对象进行校验,校验通过后再将formdata对象赋值给原始数据对象。 示例: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 // 原始表单数据对象 const formObject = ref({ name: { label: '分类名称', name: 'name', type: 'input', placeholder: '请输入分类名称', default: '默认数据', rules: [{ required: true, message: '请输入分类名称'}], }, status: { label: '状态', name: 'status', type: 'select', placeholder: '请选择状态', default: 1, options: [ { label: '启用', value: 1 }, { label: '禁用', value: 0 }, ], rules: [{ required: true, message: '请选择状态'}], }, }) // 表单数据存储对象 const formData = ref({}) // 原始数据对象深拷贝到表单数据存储对象中 const dataExtract = (data) => { Object.keys(data).forEach(key => { formData.value[key] = data[key].default }) } // 监听原始数据对象变化,将变化后的数据深拷贝到表单数据存储对象中 watch(formObject, (val) => { dataExtract(val) }, { immediate : true}) // 提取后的formData { name: '默认数据', status: 1, } Table 表格 官方文档:https://antdv.com/components/table-cn ...

2025-03-19 · 1 min · 175 words

Mockjs使用教程

一. 安装 1 npm install mockjs 官方文档:https://github.com/nuysoft/Mock/wiki 二. 使用 1. 基本使用 1 2 3 4 5 6 7 8 9 10 11 12 import Mock from "mockjs"; const data = Mock.mock({ // 属性 list 的值是一个数组,其中含有 3 到 3 个元素 'list|1-3': [{ // 属性 id 是一个自增数,起始值为 1,每次增 1 'id|+1': 1, 'name': '@name' }] }) // 输出结果 console.log(JSON.stringify(data, null, 4)) 输出结果: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 { "list": [ { "id": 1, "name": "王小明" }, { "id": 2, "name": "王小明" }, { "id": 3, "name": "王小明" } ] } 2. 语法规范 2.1. 数据模板定义规范 数据模板中的每个属性由 3 部分构成:属性名、生成规则、属性值: ...

2025-03-14 · 5 min · 933 words