三次登录验证和验证码功能实现

2023-11-07

三次登录验证和验证码功能实现

最近手头上的事忙的差不多了,就想着自己写写小demo玩一下,结果突然看到我们旧系统的登录好像有点拉胯,然后就自己写了个小demo,指不定哪天就用上了呢

一、pom文件

首先当然是pom文件啦,这里写的比较简单,就一些基础组件

   <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>

        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.11</version>
        </dependency>

        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>3.0.0</version>
        </dependency>

        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>3.0.0</version>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.3.1</version>
        </dependency>

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

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

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
        </dependency>

<!--        验证码依赖包-->
        <dependency>
            <groupId>com.github.penggle</groupId>
            <artifactId>kaptcha</artifactId>
            <version>2.3.2</version>
        </dependency>
                <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.9.0</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.83</version>
        </dependency>

pom文件基本就是这些,加下来就是控制层

二、controller层

@Api(tags = "用户信息控制层")
@Controller
@RequestMapping("/base")
@Slf4j
public class UserInfoController {

    @Autowired
    private Producer producer;

    @Resource
    private StringRedisTemplate template;

    @Autowired
    private UserService userService;

    /**
     * login : 登录
     *
     * @param username
     * @param password
     * @param request
     * @return org.springframework.http.ResponseEntity<java.lang.String>
     * @author lin
     * @version 1.0
     * @date 2023/6/15 14:23
     * @since JDK 1.8
     */
    @GetMapping("/login")
    @LimitCount(key = "login", name = "登录接口", prefix = "limit")
    public ResponseEntity<String> login(
            @RequestParam(required = true) String username,
            @RequestParam(required = true) String password,
            @RequestParam(required = true) String text,
            HttpServletRequest request) throws Exception {
        if (StringUtils.equals("张三", username) && StringUtils.equals("123456", password)) {
            String userInfo = IPUtil.getUserMD5(request);
            String s = template.opsForValue().get(userInfo);
            if (text.equals(s)) {
                return new ResponseEntity<>("登录成功", HttpStatus.OK);
            } else {
                return new ResponseEntity<>("验证码有误!", HttpStatus.OK);
            }

        }
        return new ResponseEntity<>("账户名或密码错误", HttpStatus.OK);
    }

    @PostMapping("/register")
    @ResponseBody
    public Result register(@RequestBody UserVo user, HttpServletRequest request) {
        if (StringUtils.isNotBlank(user.getVerifyCode())) {
            // 校验验证码
            String userInfo = IPUtil.getUserMD5(request);
            String s = template.opsForValue().get(userInfo);
            if (user.getVerifyCode().equals(s)) {
                Result result = userService.verifyUser(user);
                return result;
            } else {
                return Result.success(false, "请输入正确验证码!");
            }
        } else {
            return Result.success(false, "请输入验证码!");
        }

    }


    /**
     * getVerifyCode : 获取验证码
     *
     * @param response
     * @param session
     * @return void
     * @author lin
     * @version 1.0
     * @date 2023/6/15 14:24
     * @since JDK 1.8
     */
    @GetMapping("/getVerifyCode")
    public void getVerifyCode(HttpServletRequest request, HttpServletResponse response, HttpSession session) throws IOException {
        response.setContentType("image/jpeg");
        String text = producer.createText();
        String userInfo = IPUtil.getUserMD5(request);
        template.opsForValue().set(userInfo, text, 10, TimeUnit.MINUTES);
        session.setAttribute("vf", text);
        BufferedImage image = producer.createImage(text);
        try (ServletOutputStream sos = response.getOutputStream()) {
            ImageIO.write(image, "jpg", sos);
        }
    }

}

这里的登录没有使用token,只是简单的采用了md5加密,后期有时间再慢慢完善吧,实现类比较简单,就先跳过了,有需要的话私信我就行,后面就是工具类

三、utils工具类

IPUtil

@Slf4j
public class IPUtil {
    private static final String UNKNOWN = "unknown";

    protected IPUtil() {

    }

    /**
     * getIpAddr : 获取公网ip和内网ip
     *
     * @param request
     * @return java.lang.String
     * @author lin
     * @version 1.0
     * @date 2023/6/15 13:48
     * @since JDK 1.8
     */
    public static String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
    }

    /**
     * getUserMD5 : 加密用户信息
     *
     * @author lin
     * @version 1.0
     * @date 2023/6/15 15:06
     * @param request
     * @return java.lang.String
     * @since JDK 1.8
     */
    public static String getUserMD5(HttpServletRequest request) {
        String ip = IPUtil.getIpAddr(request);
        String header = request.getHeader("User-Agent");
        String userInfo = MD5Utils.inputPassToFormPass("user-service" + ip + header);
        return userInfo;
    }

}

MD5Utils

public class MD5Utils {
    public static String md5(String src) {
        return DigestUtils.md5Hex(src);
    }

    private static final String salt = "123abc";

    public static String inputPassToFormPass(String inputPass) {
        String str = ""+salt.charAt(0)+salt.charAt(2) + inputPass +salt.charAt(5) + salt.charAt(4);
        System.out.println(str);
        return md5(str);
    }
}

四、配置类

VerifyCodeConfig

@Configuration
public class VerifyCodeConfig {
    @Bean
    Producer producer() {
        Properties properties = new Properties();
        //设置图片边框
        properties.setProperty("kaptcha.border", "yes");
        //设置图片边框为蓝色
        properties.setProperty("kaptcha.border.color", "black");
        //背景颜色渐变开始
        properties.put("kaptcha.background.clear.from", "127,255,212");
        //背景颜色渐变结束
        properties.put("kaptcha.background.clear.to", "240,255,255");
        // 字体颜色
        properties.put("kaptcha.textproducer.font.color", "black");
        // 文字间隔
        properties.put("kaptcha.textproducer.char.space", "10");
        //如果需要去掉干扰线
        properties.put("kaptcha.noise.impl", "com.google.code.kaptcha.impl.NoNoise");
        // 字体
        properties.put("kaptcha.textproducer.font.names", "Arial,Courier,cmr10,宋体,楷体,微软雅黑");
        // 图片宽度
        properties.setProperty("kaptcha.image.width", "200");
        // 图片高度
        properties.setProperty("kaptcha.image.height", "50");
        // 从哪些字符中产生
        properties.setProperty("kaptcha.textproducer.char.string", "0123456789abcdefghijklmnopqrsduvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
        // 字符个数
        properties.setProperty("kaptcha.textproducer.char.length", "4");
        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
        defaultKaptcha.setConfig(new Config(properties));
        return defaultKaptcha;
    }
}

RedisConfig

@Configuration
public class RedisConfig extends CachingConfigurerSupport {

    @Value("${spring.data.redis.host}")
    private String host;

    @Value("${spring.data.redis.port}")
    private int port;

    @Value("${spring.data.redis.password}")
    private String password;

    @Value("${spring.data.redis.timeout}")
    private int timeout;

    @Value("${spring.data.redis.jedis.pool.max-idle}")
    private int maxIdle;

    @Value("${spring.data.redis.jedis.pool.max-wait}")
    private long maxWaitMillis;

    @Value("${spring.data.redis.database:0}")
    private int database;

    @Bean
    public JedisPool redisPoolFactory() {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxIdle(maxIdle);
        jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
        if (StringUtils.isNotBlank(password)) {
            return new JedisPool(jedisPoolConfig, host, port, timeout, password, database);
        } else {
            return new JedisPool(jedisPoolConfig, host, port, timeout, null, database);
        }
    }

    @Bean
    JedisConnectionFactory jedisConnectionFactory() {
        RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
        redisStandaloneConfiguration.setHostName(host);
        redisStandaloneConfiguration.setPort(port);
        redisStandaloneConfiguration.setPassword(RedisPassword.of(password));
        redisStandaloneConfiguration.setDatabase(database);

        JedisClientConfiguration.JedisClientConfigurationBuilder jedisClientConfiguration = JedisClientConfiguration
                .builder();
        jedisClientConfiguration.connectTimeout(Duration.ofMillis(timeout));
        jedisClientConfiguration.usePooling();
        return new JedisConnectionFactory(redisStandaloneConfiguration, jedisClientConfiguration.build());
    }

    @Bean
    public RedisTemplate<String, Serializable> limitRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Serializable> template = new RedisTemplate<>();
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
}

五、注解类

LimitCount

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LimitCount {
    /**
     * 资源名称,用于描述接口功能
     */
    String name() default "";

    /**
     * 资源 key
     */
    String key() default "";

    /**
     * key prefix
     *
     * @return
     */
    String prefix() default "";

    /**
     * 时间的,单位秒
     * 默认60s过期
     */
    int period() default 60;

    /**
     * 限制访问次数
     * 默认3次
     */
    int count() default 3;

}

LimitCountAspect

@Slf4j
@Aspect
@Component
public class LimitCountAspect {

    private final RedisTemplate<String, Serializable> limitRedisTemplate;

    @Autowired
    public LimitCountAspect(RedisTemplate<String, Serializable> limitRedisTemplate) {
        this.limitRedisTemplate = limitRedisTemplate;
    }

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Pointcut("@annotation(com.linlin.ocr.annotation.LimitCount)")
    public void pointcut() {
        // do nothing
    }

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(
                RequestContextHolder.getRequestAttributes())).getRequest();

        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        LimitCount annotation = method.getAnnotation(LimitCount.class);
        //注解名称
        String name = annotation.name();
        //注解key
        String key = annotation.key();
        //访问IP
        String ip = IPUtil.getIpAddr(request);
        //过期时间
        int limitPeriod = annotation.period();
        //过期次数
        int limitCount = annotation.count();

        ImmutableList<String> keys = ImmutableList.of(StringUtils.join(annotation.prefix() + "_", key, ip));
        String luaScript = buildLuaScript();
        RedisScript<Number> redisScript = new DefaultRedisScript<>(luaScript, Number.class);
        Number count = limitRedisTemplate.execute(redisScript, keys, limitCount, limitPeriod);
        log.info("IP:{} 第 {} 次访问key为 {},描述为 [{}] 的接口", ip, count, keys, name);
        if (count != null && count.intValue() <= limitCount) {
            return point.proceed();
        } else {
            String s = keys.get(0);
            Long expire = stringRedisTemplate.getExpire(s);
            return new ResponseEntity<>("接口访问超出频率限制,请等待"+expire+"s再试!", HttpStatus.OK);
        }
    }

    /**
     * 限流脚本
     * 调用的时候不超过阈值,则直接返回并执行计算器自加。
     *
     * @return lua脚本
     */
    private String buildLuaScript() {
        return "local c" +
                "\nc = redis.call('get',KEYS[1])" +
                "\nif c and tonumber(c) > tonumber(ARGV[1]) then" +
                "\nreturn c;" +
                "\nend" +
                "\nc = redis.call('incr',KEYS[1])" +
                "\nif tonumber(c) == 1 then" +
                "\nredis.call('expire',KEYS[1],ARGV[2])" +
                "\nend" +
                "\nreturn c;";
    }

}

以上就是全部的登录验证的逻辑和代码实现,弄完以后三次登录差不多是这么个效果,验证码这个需要前端,等过段时间得空了再补上吧
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

三次登录验证和验证码功能实现 的相关文章

  • “_加载小部件时出现问题”消息

    加载小部件时 如果找不到资源或其他内容 则会显示 加载小部件时出现问题 就这样 惊人的 此消息保留在主屏幕上 甚至没有说明加载时遇到问题的小部件 我通过反复试验弄清楚了这一点 但我想知道发生这种情况时是否有任何地方可以找到错误消息 Andr
  • 在文本文件中搜索单词并返回其频率

    如何在包含单词文本的文本文件中搜索特定单词并返回其频率或出现次数 使用扫描仪 String text Question how to search for a particular word in a text file containin
  • Java套接字:在连接被拒绝异常时重试的最佳方法?

    现在我正在这样做 while true try SocketAddress sockaddr new InetSocketAddress ivDestIP ivDestPort downloadSock new Socket downloa
  • 在 HTTP 标头中发送 UTF-8 值会导致 Mojibake

    我想使用 servlet 发送阿拉伯语数据HTTPServletResponse给客户 我正在尝试这个 response setCharacterEncoding UTF 8 response setHeader Info arabicWo
  • 具有共享依赖项的多模块项目的 Gradle 配置

    使用 gradle 制作第一个项目 所以我研究了 spring gradle hibernate 项目如何组织 gradle 文件 并开始制作自己的项目 但是 找不到错误 为什么我的配置不起作用 子项目无法解决依赖关系 所以项目树 Root
  • 将表值参数与 SQL Server JDBC 结合使用

    任何人都可以提供一些有关如何将表值参数 TVP 与 SQL Server JDBC 一起使用的指导吗 我使用的是微软提供的6 0版本的SQL Server驱动程序 我已经查看了官方文档 https msdn microsoft com en
  • 无法加载或查找主类,可以在命令行中使用,但不能在 IDE 中使用[重复]

    这个问题在这里已经有答案了 在将其标记为重复之前 请先听我说完 我正在尝试使用 gradle 导入一个 java 项目 功能齐全 适用于所有其他笔记本电脑 没有问题 我的项目 100 正常运行 适用于所有其他笔记本电脑 当我的笔记本电脑被重
  • Cloudfoundry:如何组合两个运行时

    cloundfoundry 有没有办法结合两个运行时环境 我正在将 NodeJS 应用程序部署到 IBM Bluemix 现在 我还希望能够执行独立的 jar 文件 但应用程序失败 APP 0 bin sh 1 java not found
  • Android Studio 将音乐文件读取为文本文件,如何恢复它?

    gameAlert mp3是我的声音文件 运行应用程序时 它询问我该文件不与任何文件类型关联 请定义关联 我选择TextFile错误地 现在我的音乐文件被读取为文本文件 我如何将其转换回music file protected void o
  • 如何配置 WebService 返回 ArrayList 而不是 Array?

    我有一个在 jax ws 上实现的 java Web 服务 此 Web 服务返回用户的通用列表 它运行得很好 Stateless name AdminToolSessionEJB RemoteBinding jndiBinding Admi
  • 解析输入,除了 System.in.read() 之外不使用任何东西

    我很难找到具体的细节System in read 有效 也许有人可以帮助我 似乎扫描仪会更好 但我不允许使用它 我被分配了一个任务 我应该以 Boolean Operator Boolean 的形式读取控制台用户输入 例如T F 或 T T
  • 无法捕获 Spring Batch 的 ItemWriter 中的异常

    我正在编写一个 Spring Batch 流程来将数据集从一个系统迁移到另一个系统 在这种情况下 这就像使用RowMapper实现在传递给查询之前从查询构建对象ItemWriter The ItemWriter称为save我的 DAO 上的
  • 解决错误javax.mail.AuthenticationFailedException

    我不熟悉java中发送邮件的这个功能 我在发送电子邮件重置密码时遇到错误 希望你能给我一个解决方案 下面是我的代码 public synchronized static boolean sendMailAdvance String emai
  • Java:拆箱整数时出现空指针异常?

    此代码导致空指针异常 我不知道为什么 private void setSiblings PhylogenyTree node Color color throws InvalidCellNumberException PhylogenyTr
  • 挂钩 Eclipse 构建过程吗?

    我希望在 Eclipse 中按下构建按钮时能够运行一个简单的 Java 程序 目前 当我单击 构建 时 它会运行一些 JRebel 日志记录代码 我有一个程序可以解析 JRebel 日志文件并将统计信息存储在数据库中 是否可以编写一个插件或
  • JSON 到 hashmap (杰克逊)

    我想将 JSON 转换为 HashMapJackson http jackson codehaus org 这是我的 JSON String json Opleidingen name Bijz trajecten zorg en welz
  • Java的-XX:+UseMembar参数是什么

    我在各种地方 论坛等 看到这个参数 并且常见的答案是它有助于高并发服务器 尽管如此 我还是找不到 sun 的官方文档来解释它的作用 另外 它是Java 6中添加的还是Java 5中存在的 顺便说一句 许多热点虚拟机参数的好地方是这一页 ht
  • Java:多线程内的 XA 事务传播

    我如何使用事务管理器 例如Bitronix http docs codehaus org display BTM Home JBoss TS http www jboss org jbosstm or Atomikos http www a
  • 在android中跟踪FTP上传数据?

    我有一个运行 Android 的 FTP 系统 但我希望能够在上传时跟踪字节 这样我就可以在上传过程中更新进度条 安卓可以实现这个功能吗 现在 我正在使用org apache common net ftp我正在使用的代码如下 另外 我在 A
  • JAXB - 列表<可序列化>?

    我使用 xjc 制作了一些课程 public class MyType XmlElementRefs XmlElementRef name MyInnerType type JAXBElement class required false

随机推荐

  • EMC定义 +EMC问题定位整改

    参考链接 强烈推荐 1 有源医疗器械电磁兼容入门知识汇总 2 电磁兼容EMC测试 电磁兼容整改 EMC整改 深圳第三方检测认证机构 3 EMC设计和整改 定位 专题 最重要 https blog csdn net lyh290188 cat
  • MATLAB的Structure数组

    数组的定义与调用 gt gt s struct a 1 4 7 2 9 3 Anne b James pi c magic 3 1 7 使用struct函数创建结构数组 gt gt s 1 1 a 1 2 ans 1 1 cell 数组 4
  • jdk和java什么关系_Java中JDK和JRE的区别是什么?它们的作用分别是什么?

    JDK和JRE是Java开发和运行工具 其中JDK包含了JRE 但是JRE是可以独立安装的 它们在Java开发和运行的时候起到不同的作用 1 JDK JDK是Java Development Kit的缩写 是Java的开发工具包 主要包含了
  • http的get请求如何传递一个对象

    原文链接 https www longkui site program frontend httpget 4366 0 前言 以前前台往后台对象时 后台都用POST请求 前台有时候通过拼接参数传参 会显得比较长 所以考虑前台GET请求能否直
  • Linux (Centos)下pip命令出现错误bash: pip: 命令未找到..解决方案

    今天在服务器上跑程序 提示没有XX模块 我就用pip install XX 安装了一下 结果竟然提示pip命令找不到了 pip3能安装 但是pip3 list一看 里面都没有torch包 之前应该都是用pip安装的才对 去网上找了一通 发现
  • 【算法】分支定界

    一 基本描述 类似于回溯法 也是一种在问题的解空间树T上搜索问题解的算法 但在一般情况下 分支限界法与回溯法的求解目标不同 回溯法的求解目标是找出T中满足约束条件的所有解 而分支限界法的求解目标则是找出满足约束条件的一个解 或是在满足约束条
  • React组件的生命周期

    1 组件生命周期概述 什么是组件的生命周期 组件从被创建到挂载到页面中运行 再到组件不用时卸载的过程 这个过程就叫做组件的生命周期 react在组件的生命周期中提供了一系统的钩子函数 可以让开发者在函数中注入代码 这些代码会在适当的时候运行
  • java ip解析_java域名解析

    DNS原理 http amon org dns introduction html 根域 就是所谓的 根域服务器只是具有13个IP地址 但机器数量却不是13台 因为这些IP地址借助了 域的划分 根域下来就是顶级域或者叫一级域 每个域都会有域
  • [element-ui] el-dropdown下拉菜单禁用项没有鼠标悬浮禁用样式

    鼠标移入出现禁用样式 如下图 就是我们想要的效果
  • Blender3.5 - 快捷键

    图形移动 框选 gt 刷选 gt 套索选择 W 游标 相当于形状的中心点 shitf 空格 空格 游标回到世界中心 shift C 移动 移动 G 随意移动 选中图形 G 沿 X 轴移动 选中图形 G X 沿 Y 轴移动 选中图形 G Y
  • 动态内存(智能指针与new)

    文章目录 一 引言 二 动态内存管理 1 使用动态内存的原因 2 智能指针 2 1 shared ptr 2 1 1 shared ptr定义与初始化 2 1 2 shared ptr操作 2 1 3 make shared操作 2 1 4
  • 【剑指 Offer】(四种解法)数组中重复的数字

    剑指 Offer 03 数组中重复的数字 题目描述 在一个长度为 n 的数组 nums 里的所有数字都在 0 n 1 的范围内 数组中某些数字是重复的 但不知道有几个数字重复了 也不知道每个数字重复了几次 请找出数组中任意一个重复的数字 示
  • 微信公众号与企业号的TOKEN验证与使用

    上图是 微信客户端与微信服务端与公众号 企业号的服务器的原理架构 首先 我们如果使用应用服务器 则需要告诉微信服务器 它在哪里 所以TOKEN就是一个标识的作用 TOKEN是一个参数 是一个自定义的值 负责标识微信服务器和应用服务是不是一一
  • unity狼模型、山谷模型

    unity狼模型 山谷模型 模型如下图 下载链接在文末 点我下载资源 https download csdn net download weixin 43474701 60362226
  • 如何使用文件作为参数,调用接口并获取返回数据?

    String path picture 20220420 1 doc 指定文件的路径 或相对路径 File file new File path System out println 文件名 file getName 文件绝对路径 file
  • 百度AI攻略:增值税发票识别

    1 功能描述 在日常工作中经常要用到增值税发票 在使用的时候需要对增值税发表进行检查 验真 录入等很多工作 使用增值税发票识别技术 实现对增值税普票或专票各字段信息的识别和录入 可应用于企业税务核算及内部报销等场景 能够有效减少人工核算工作
  • Tensorflow与Python、CUDA、cuDNN的版本对应表

    1 官方配置 官网只有英文版的才更新到了TensorFlow 2 12 0 中文版只更新到了2 6 0 所以要想看到下面的内容需要进入官网之后将语言更改为英文 经过测试的构建配置 Linux CPU Version Python versi
  • Spring Cloud简介:构建分布式微服务架构的利器

    标题 Spring Cloud简介 构建分布式微服务架构的利器 摘要 本文介绍了Spring Cloud作为构建分布式微服务架构的利器 我们将深入探讨Spring Cloud的重要组件和功能 并通过代码示例展示Spring Cloud的强大
  • 非线性控制1——经典控制和现代控制的区别

    经典控制和现代控制的区别
  • 三次登录验证和验证码功能实现

    三次登录验证和验证码功能实现 最近手头上的事忙的差不多了 就想着自己写写小demo玩一下 结果突然看到我们旧系统的登录好像有点拉胯 然后就自己写了个小demo 指不定哪天就用上了呢 一 pom文件 首先当然是pom文件啦 这里写的比较简单