IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 基于SpringBoot的秒杀系统出现的BUG以及难点(总结) -> 正文阅读

[Java知识库]基于SpringBoot的秒杀系统出现的BUG以及难点(总结)

最近完成了一个后端项目,过程中遇到了一些难点和第一次遇到的BUG
分享一下,做个记录 ~~在这里插入图片描述

1、通过注解判断参数vo是否为空,并做全局异常处理

在开发中,controller层需要经常对vo参数进行格式判断,这样就可能在多个请求方法中出现格式判断,所以为了降低代码冗余,通过在注解来进行格式判断。

实现思路:添加依赖,在需要进行格式判断的类中添加判断注解,如果我们需要实现一些自己的判断,可以实现自定义注解。这样基本就已经实现完了,但是。还要考虑的就是,如果入参的格式不符合我们的要求,validation就会抛出异常,为了友好的返回结果,我们就会做全局异常处理。

第一部分:格式验证

  1. 添加依赖

            <!--validation验证依赖-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-validation</artifactId>
            </dependency>
    
  2. 在入参时需要进行格式判断的类中添加判断注解

    //我这里以一个模板入参类为样例(参考)
    //其中@IsMobile为自定义注解
    @Data
    public class LoginVo {
        @NotNull //不能为空
        @IsMobile //mobile格式判断(我们的自定义注解)
        private String mobile;
    
        @NotNull
        @Length(min = 32) //长度要求
        private String password;
    
    }
    
  3. 实现自定义注解并注册到validation组件中

    /**
     * 验证手机号
     *
     * @author thenie
     * @since 1.0.0
     */
    @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
    @Retention(RUNTIME)
    @Documented
    @Constraint(validatedBy = {IsMobileValidator.class})
    public @interface IsMobile {
    
        boolean required() default true;
    
        String message() default "手机号码格式错误";
    
        Class<?>[] groups() default { };
    
        Class<? extends Payload>[] payload() default { };
    }
    

    IsMobileValidator.java

    /**
     * 手机号码校验规则
     *
     * @author thenie
     * @since 1.0.0
     */
    public class IsMobileValidator implements ConstraintValidator<IsMobile,String> {
    
        private boolean required = false;
    
        @Override
        public void initialize(IsMobile constraintAnnotation) {
            required = constraintAnnotation.required();
        }
    
        @Override
        public boolean isValid(String value, ConstraintValidatorContext context) {
            if (required){
                return ValidatorUtil.isMobile(value);
            }else {
                if (StringUtils.isEmpty(value)){
                    return true;
                }else {
                    return ValidatorUtil.isMobile(value);
                }
            }
        }
    }
    

    ValidatorUtil.java

    /**
     * 校验工具类
     *
     * @author thenie
     * @since 1.0.0
     */
    public class ValidatorUtil {
        //电话号码验证的正则表达式
        private static final Pattern mobile_pattern = Pattern.compile("^1[3|4|5|7|8][0-9]{9}$");
    
        public static boolean isMobile(String mobile){
            if (StringUtils.isEmpty(mobile)) {
                return false;
            }
    
            Matcher matcher = mobile_pattern.matcher(mobile);
            return matcher.matches();
        }
    }
    

    最后在我们需要使用的地方,通过 @Valid开启就行。

    在这里插入图片描述

第二部分:全局异常处理

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)
    public RespBean ExceptionHandler(Exception e) {
        //处理异常,友好返回
    }
}

2、根据cookie访问页面,参数中没有user信息,如何实现User自动映射?

这里也是为了降低代码冗余,实现User自动映射

实现思路:添加参数解析器,实现我们的自动注入逻辑

  1. 配置参数解析器

    WebMvcConfig配置类中重写

        /**
         * Controller 配置参数解析器
         * @param argumentResolvers
         */
        @Override
        public void addArgumentResolvers(List argumentResolvers) {
            argumentResolvers.add(new CurrentUserArgumentResolver());
        }
    
  2. 实现参数解析器逻辑

    /**
     * 参数解析器
     */
    @Slf4j
    public class CurrentUserArgumentResolver implements HandlerMethodArgumentResolver {
    
        @Override
        public boolean supportsParameter(MethodParameter parameter) {
            //如果参数中存在注解CurrentUser
            return parameter.hasParameterAnnotation(CurrentUser.class);
        }
    
        @Override
        public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer modelAndView, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
            //进行
            Object currentUserInfo = webRequest.getAttribute("currentUser", RequestAttributes.SCOPE_REQUEST);
            if(null == currentUserInfo)
                log.warn("---------------用户未登录---------------");
            return currentUserInfo;
        }
    }
    
  3. 定义声明注解

    /**
     * 声明注解,从请求域中注入到参数中
     */
    @Target({ElementType.PARAMETER})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface CurrentUser {
    }
    

3、redis通过RedisTemplate实现分布式锁解决预减库存

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.concurrent.TimeUnit;

@Component
public class LockUtil {

    @Autowired
    private StringRedisTemplate redisTemplate;


    /**
     * 尝试获取锁 立即返回
     *
     * @param key
     * @param value
     * @param timeout
     * @return
     */
    public boolean lock(String key, String value, long timeout) {
        return redisTemplate.opsForValue().setIfAbsent(key, value, timeout, TimeUnit.SECONDS);
    }

    /**
     * 实现原子性递减操作
     * @param key
     * @return
     */
    public Long executeDecrToZero(String key){
        //lua脚本自己定义,实现业务逻辑
        String luaScript=
                "if (redis.call('exists', KEYS[1]) == 1) then\n" +
                    "local stock = tonumber(redis.call('get', KEYS[1]));\n" +
                    "if (stock > 0) then\n" +
                        "redis.call('incrby', KEYS[1], -1);\n" +
                        "return stock;\n" +
                    "end;\n" +
                "return 0;\n" +
                "end;";
        RedisScript<Long> redisScript = new DefaultRedisScript<>(luaScript,Long.class);
        return (Long) 				     redisTemplate.execute(redisScript,Collections.singletonList(key),Collections.EMPTY_LIST);
    }

}

4、application.yml中格式问题

第一次遇到这种问题,我的application.ymlpassword类似为123456Niess这种密码,在本机启动时不会报错,但是我生成jar包部署到服务器上后,启动时会报错,排查了很久,才发现是password的格式错误。

解决方法:有特殊字符或者类似这种格式用引号括起来就好了,例如"123456Niess"

5、Maven中导包爆红

一般我们都会把maven仓库和idea相关的config设置好,然后基本上就不会出现问题。

但是不排除有时候我们将一个下载下来的项目,用idea打开后maven会爆红,不管怎么点击右上方刷新还是会存在

通用的解决方案:

  1. 将出问题的包找到maven仓库目录将相关包删除,然后重新导入
  2. 如果还是爆红,那就把pom.xml里面的内容剪切再粘贴就好

如果你是公司的项目的话,它有的包会依赖于公司私有服务器上,报红很正常,只需要找的mt要一份maven的config设置一下就好。


  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-05-10 11:43:27  更:2022-05-10 11:43:30 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 23:32:29-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码