{"id":29723402,"url":"https://github.com/eternalstone/easycaptchaboot","last_synced_at":"2025-08-23T06:33:29.092Z","repository":{"id":192528434,"uuid":"686894766","full_name":"eternalstone/EasyCaptchaBoot","owner":"eternalstone","description":"基于EasyCaptcha实现的Java图形验证码，支持gif、中文、算术等类型。解决了该项目存在的一些issues和问题，扩展了springboot-starter包，支持SpringBoot2.x和SpringBoot3.x，支持jdk8、jdk11、jdk17","archived":false,"fork":false,"pushed_at":"2023-09-05T03:16:05.000Z","size":353,"stargazers_count":12,"open_issues_count":0,"forks_count":5,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-07-24T22:29:33.835Z","etag":null,"topics":["captcha","java","springboot","springboot3"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/eternalstone.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-09-04T07:12:32.000Z","updated_at":"2025-06-18T18:24:29.000Z","dependencies_parsed_at":null,"dependency_job_id":"5dcc831f-6cf2-40e1-ad38-655f2fbaeeca","html_url":"https://github.com/eternalstone/EasyCaptchaBoot","commit_stats":null,"previous_names":["eternalstone/easycaptchaboot"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/eternalstone/EasyCaptchaBoot","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eternalstone%2FEasyCaptchaBoot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eternalstone%2FEasyCaptchaBoot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eternalstone%2FEasyCaptchaBoot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eternalstone%2FEasyCaptchaBoot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eternalstone","download_url":"https://codeload.github.com/eternalstone/EasyCaptchaBoot/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eternalstone%2FEasyCaptchaBoot/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271745677,"owners_count":24813521,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-23T02:00:09.327Z","response_time":69,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["captcha","java","springboot","springboot3"],"created_at":"2025-07-24T18:31:59.459Z","updated_at":"2025-08-23T06:33:29.057Z","avatar_url":"https://github.com/eternalstone.png","language":"Java","readme":"\n# EasyCaptchaBoot\n\n![MavenCentral](https://img.shields.io/maven-central/v/io.github.eternalstone/captcha-spring-boot-starter?style=flat-square)\n![Hex.pm](https://img.shields.io/hexpm/l/plug.svg?style=flat-square)\n\n\n## 1.简介\n\u0026emsp;基于[`EasyCaptcha`](https://gitee.com/ele-admin/EasyCaptcha)实现的Java图形验证码，支持gif、中文、算术等类型。解决了该项目存在的一些issues和问题，扩展了springboot-starter包，支持SpringBoot2.x和SpringBoot3.x，支持jdk8、jdk11、jdk17。\n\n---\n\n\n\n## 2.效果展示(与原项目效果一致)\n\n![验证码](https://s2.ax1x.com/2019/08/23/msFrE8.png) \n\u0026emsp;\u0026emsp;\n![验证码](https://s2.ax1x.com/2019/08/23/msF0DP.png)\n\u0026emsp;\u0026emsp;\n![验证码](https://s2.ax1x.com/2019/08/23/msFwut.png)\n\u003cbr/\u003e\n![验证码](https://s2.ax1x.com/2019/08/23/msFzVK.gif) \n\u0026emsp;\u0026emsp;\n![验证码](https://s2.ax1x.com/2019/08/23/msFvb6.gif)\n\u0026emsp;\u0026emsp;\n![验证码](https://s2.ax1x.com/2019/08/23/msFXK1.gif)\n\n**算术类型：**\n\n![验证码](https://s2.ax1x.com/2019/08/23/mskKPg.png)\n\u0026emsp;\u0026emsp;\n![验证码](https://s2.ax1x.com/2019/08/23/msknIS.png)\n\u0026emsp;\u0026emsp;\n![验证码](https://s2.ax1x.com/2019/08/23/mskma8.png)\n\n**中文类型：**\n\n![验证码](https://s2.ax1x.com/2019/08/23/mskcdK.png)\n\u0026emsp;\u0026emsp;\n![验证码](https://s2.ax1x.com/2019/08/23/msk6Z6.png)\n\u0026emsp;\u0026emsp;\n![验证码](https://s2.ax1x.com/2019/08/23/msksqx.png)\n\n**内置字体：**\n\n![验证码](https://s2.ax1x.com/2019/08/23/msAVSJ.png)\n\u0026emsp;\u0026emsp;\n![验证码](https://s2.ax1x.com/2019/08/23/msAAW4.png)\n\u0026emsp;\u0026emsp;\n![验证码](https://s2.ax1x.com/2019/08/23/msAkYF.png)\n\n---\n\n\n\n## 3.版本说明\n\n- **2023-09-03**\n\n  - v2.0.0支持jdk1.8、jdk11, 支持SpringBoot2.x的版本\n\n  - v3.0.0支持jdk17, 支持SpringBoot3.x的版本\n\n  - 不再支持servlet项目的使用，servlet项目移步至 [`EasyCaptcha`](https://gitee.com/ele-admin/EasyCaptcha)\n\n  - `captcha-core`包剥离了`servlet-api`，不再与web层耦合，支持JavaSE的项目使用\n\n  - 扩展了starter包，内置集成`/captcha`端点输出验证码，您无需再编写controller实现请求\n\n  - 扩展了自定义配置背景颜色\n\n  - 扩展了算术验证码算子长度\n\n  - 使用单例解决了原项目存在的内存占用或内存溢出的问题，验证码数据不在绑定到captcha实例身上\n\n    \n\n- **兼容性测试结果(2023-09-03)**\n\n  - 测试了jdk1.8， jdk11,  jdk17环境下的使用情况，使用v2.0.0可支持jdk1.8，使用v3.0.0支持jdk17\n\n  - 测试了springboot2.x和springboot3.x的使用情况，v2.0.0可支持springboot2.x，使用v3.0.0支持springboot3.x\n\n  - 在springboot2.6.0以后的版本，需要开启配置 `spring.mvc.pathmatch.matching-strategy=ant-path-matcher`，否则会报错：`java.lang.IllegalArgumentException: Expected lookupPath in request attribute \"org.springframework.web.util.UrlPathHelper.PATH\".`\n\n  - 在docker环境下，若基础镜像缺失部分字体，会导致内置字体在中文验证码、算术验证码中无法正常显示\n\n  - 内置扩展的字体可能在中文验证码中无法正常显示，建议使用默认字体\n\n  - 少部分内置字体在算数验证码中运算符号无法正常显示\n\n---\n\n\n\n## 4.使用方法\n\n### 4.1.在SpringBoot中使用\n\n#### 4.1.1 导包\n\n```xml\n\u003c!--SpringBoot2.x--\u003e\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.github.eternalstone\u003c/groupId\u003e\n    \u003cartifactId\u003ecaptcha-spring-boot-starter\u003c/artifactId\u003e\n    \u003cversion\u003e2.0.0\u003c/version\u003e\n\u003c/dependency\u003e\n\n\u003c!--SpringBoot3.x--\u003e\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.github.eternalstone\u003c/groupId\u003e\n    \u003cartifactId\u003ecaptcha-spring-boot-starter\u003c/artifactId\u003e\n    \u003cversion\u003e3.0.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n\u003e 导入EasyCaptchaBoot的starer包后，Spring自动导入`EasyCaptchaAutoConfiguration`类，会自动导入一个/captcha的http端点，您可以直接在前端调用这个端点请求验证码，在springboot配置文件中也可以对验证码自定义\n\n#### 4.1.2 配置\n\nspringboot.yaml配置\n\n```yaml\neasy-captcha:\n  endpoint:\n    #配置http端点，默认/captcha\n    path: /captcha\n    #是否启用端点生成\n    enabled: true\n  #验证码类性\n  captcha: chinese\n  #验证码位数\n  length: 3\n  #验证码宽度\n  width: 130\n  #验证码高度\n  height: 48\n  #验证码字符类性\n  char-type: 2\n  #验证码背景颜色\n  background: \"#000000\"\n  #验证码输出格式\n  format: \"png\"\n  #验证码字体，只能配置默认字体,默认字体见Captcha.Font_1等等\n  font: 1\n```\n\n\n\n#### 4.1.3 使用\n\n1. 使用默认导入的http端点，无需编写controller代码，直接在前端请求验证码即可\n\n   ```html\n   \u003cimg src=\"/captcha\" width=\"130px\" height=\"48px\" /\u003e\n   ```\n\n   \u003e  不要忘了把`/captcha`路径排除登录拦截，比如shiro的拦截。\n\n2. 不使用默认导入，建议直接导入`captcha-core`包，而无需引入starter包，当然也可以配置`easy-captcha.endpoint.enabled=false` ，编写您自己的controller即可(可见SpringMVC的使用方式)\n\n\n\n#### 4.1.4 如何验证验证码\n\n使用内置的http端点，默认存储的验证码的位置是`HttpServletRequest.getSession`,该方式只适用单机环境下的应用，如果您的应用是分布式环境，请见 4.6的说明。\n\n```java\n@Controller\npublic class LoginController {\n    \n    //注入一个EasyCaptchaListener用于校验验证码\n    @Resource\n    private EasyCaptchaListener easyCaptchaListener;\n    \n    @PostMapping(\"/login\")\n    public String login(HttpServletRequest request,String verCode){\n        boolean verify = easyCaptchaListener.verify(request, verCode);\n        return verify? \"success\" :\"fail\";\n    }   \n}\n```\n\n\n### 4.2.在SpringMVC中使用\n\n#### 4.2.1 导入cpatcha-core包\n\n```xml\n\u003c!--jdk1.8, jdk11--\u003e\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.github.eternalstone\u003c/groupId\u003e\n    \u003cartifactId\u003ecaptcha-core\u003c/artifactId\u003e\n    \u003cversion\u003e2.0.0\u003c/version\u003e\n\u003c/dependency\u003e\n\n\u003c!--jdk17--\u003e\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.github.eternalstone\u003c/groupId\u003e\n    \u003cartifactId\u003ecaptcha-core\u003c/artifactId\u003e\n    \u003cversion\u003e3.0.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n#### 4.2.2 编写controller\n\n```java\n@Controller\npublic class CaptchaController {\n    \n    @RequestMapping(\"/captcha\")\n    public void captcha(HttpServletRequest request, HttpServletResponse response) throws Exception {\n        //通过验证码类型枚举获取一个验证码实例\n        Captcha captcha = CaptchaFactory.getCaptcha(CaptchaEnum.SPEC);\n        //使用实例创建一个随机码对象TextEntry\n        TextEntry text = captcha.createText();\n        //自定义验证码存储逻辑，单机一般存储session, 分布式下存储redis\n        \n        // 设置请求头为输出图片类型\n        response.setContentType(\"image/gif\");\n        response.setHeader(\"Pragma\", \"No-cache\");\n        response.setHeader(\"Cache-Control\", \"no-cache\");\n        response.setDateHeader(\"Expires\", 0);\n        //将随机码通过实体写出成图片\n        captcha.out(response.getOutputStream(), text);\n    }\n}\n```\n前端html代码：\n```html\n\u003cimg src=\"/captcha\" width=\"130px\" height=\"48px\" /\u003e\n```\n\n\u003e 不要忘了把`/captcha`路径排除登录拦截，比如shiro的拦截。\n\n\n\n### 4.3.设置宽高和位数\n```java\n@Controller\npublic class CaptchaController {\n    \n    @RequestMapping(\"/captcha\")\n    public void captcha(HttpServletRequest request, HttpServletResponse response) throws Exception {\n        Captcha captcha = CaptchaFactory.getCaptcha(CaptchaEnum.SPEC);\n        // 设置宽、高、位数\n        captcha.setWidth(130);\n        captcha.setHeight(48);\n       \t//不建议直接从Captcha实例上设置字体，如果您需要设置字体，有如下情况\n      \t//1.SpringBoot中直接配置文件设置\n        //2.SpingMVC中通过Bean一个Captcha实例进行设置，保证Captcha实例的单例，并且字体仅只设置1次\n    }\n}\n```\n\n\n\n### 4.5分布式环境下的验证码存储\n\n分布式项目建议不要存储在session中，存储在redis中，redis存储需要一个key，key一同返回给前端用于验证输入，这个时候在SpringBoot中使用内置端点时，就需要自己实现redis存储验证码的逻辑了：\n\n需要编写一个配置类实现`EasyCaptchaListener`接口，实现其中的一些关键方法即可\n\n```java\n@Configuration\npublic class CaptchaListener implements EasyCaptchaListener {\n\n    @Resource\n    private RedisUtil redisUtil;\n\n    @Override\n    public void output(HttpServletResponse response, Captcha captcha, TextEntry entry) throws IOException {\n        System.out.println(\"生成的验证码字符\" + entry.charsText());\n        System.out.println(\"生成的验证码答案\" + entry.getKey());\n\n        String key = UUID.randomUUID().toString();\n        CaptchaVO captchaVO = new CaptchaVO();\n        captchaVO.setUuid(key);\n        captchaVO.setImage(captcha.toBase64(entry));\n\n        redisUtil.setEx(key, entry.getKey(), 30, TimeUnit.MINUTES);\n        response.setHeader(\"content-type\", \"text/html;charset=UTF-8\");\n        ServletOutputStream outputStream = response.getOutputStream();\n        outputStream.write(JSONObject.toJSONString(captchaVO).getBytes());\n        outputStream.flush();\n    }\n\n    @Override\n    public boolean verify(HttpServletRequest request, String code) {\n        String key = request.getParameter(\"key\");\n        System.out.println(\"前端传入的key\" + key);\n        System.out.println(\"前端输入的验证码\" + code);\n        String redisCode = redisUtil.get(key);\n        // 判断验证码\n        return redisCode != null \u0026\u0026 redisCode.equals(code);\n    }\n    \n    //也可以重载verify方法，自定义传入参数进行验证, 例如：\n    public boolean verify(String uuid, String code) {\n      System.out.println(\"前端传入的uuid\" + uuid);\n      System.out.println(\"前端输入的验证码\" + code);\n      String redisCode = redisUtil.get(uuid);\n      // 判断验证码\n      return redisCode != null \u0026\u0026 redisCode.equals(code);\n    }\n    \n}\n```\n\n\n\n在controller中验证，同4.1.4\n\n```java\n@Controller\npublic class LoginController {\n    \n    //注入一个EasyCaptchaListener用于校验验证码\n    @Resource\n    private EasyCaptchaListener easyCaptchaListener;\n    \n    @PostMapping(\"/login\")\n    public String login(HttpServletRequest request,String key, String verCode){\n        boolean verify = easyCaptchaListener.verify(request, verCode);\n        return verify? \"success\" :\"fail\";\n    }   \n}\n```\n\n\n\n前端使用ajax获取验证码：\n\n```html\n\u003cimg id=\"verImg\" width=\"130px\" height=\"48px\"/\u003e\n\n\u003cscript\u003e\n    var verKey;\n    // 获取验证码\n    $.get('/captcha', function(res) {\n        verKey = res.key;\n        $('#verImg').attr('src', res.image);\n    },'json');\n    \n    // 登录\n    $.post('/login', {\n        key: verKey,\n        verCode: '8u6h',\n        username: 'admin'，\n        password: 'admin'\n    }, function(res) {\n        console.log(res);\n    }, 'json');\n\u003c/script\u003e\n```\n\n\n\n## 5.更多设置\n\n### 5.1.验证码类型\n\nCaptcha类型枚举包含几种类型如下：\n\n| 枚举                    | 类型              |\n| ----------------------- | ----------------- |\n| CaptchaEnum.SPEC        | 普通字符验证码    |\n| CaptchaEnum.GIF         | GIF动图验证码     |\n| CaptchaEnum.CHINESE     | 中文验证码        |\n| CaptchaEnum.CHINESE_GIF | 中文GIF动图验证码 |\n| CaptchaEnum.ARITHMETIC  | 算术验证码        |\n\n\n\n```java\npublic class Test {\n    \n    public static void main(String[] args) {\n        //创建一个验证码配置类\n        CaptchaProperty property = new CaptchaProperty();\n        //配置验证码类性枚举\n        property.setCaptcha(CaptchaEnum.SPEC);\n        //配置验证码宽度\n        property.setWidth(130);\n        //配置验证码高度\n        property.setHeight(48);\n        //配置验证码几个字符\n        property.setLength(4);\n        //配置内置字体\n        property.setFont(Captcha.FONT_2);\n        //配置验证码字符类性\n        property.setCharType(Captcha.TYPE_DEFAULT);\n        //配置验证码背景颜色\n        property.setBackground(Color.BLACK);\n        //创建验证码实例\n        Captcha captcha = CaptchaFactory.getCaptcha(property);\n        //获取验证码内容\n        TextEntry text = captcha.createText();\n        //获取随机验证码内容\n        String text = entry.charsText();\n        //获取随机验证码校验值\n        String key = entry.getKey();\n    }\n}\n```\n\n\u003e 注意：\u003cbr/\u003e\n\u003e \u0026emsp;算术验证码的len表示是几位数运算，而其他验证码的len表示验证码的位数，算术验证码的TextEntry.charsText()表示的是公式字符，TextEntry.getKey()表示的是公式运算结果。\n\u003e 对于算术验证码，你应该把公式的结果存储session，而不是公式。\n\n### 5.2.验证码字符类型\n\n 类型 | 描述 \n :--- | :--- \n TYPE_DEFAULT | 数字和字母混合 \n TYPE_ONLY_NUMBER | 纯数字\n TYPE_ONLY_CHAR | 纯字母 \n TYPE_ONLY_UPPER | 纯大写字母\n TYPE_ONLY_LOWER | 纯小写字母\n TYPE_NUM_AND_UPPER | 数字和大写字母\n\n\u003e 只有`SpecCaptcha`和`GifCaptcha`设置才有效果。\n\n### 5.3.字体设置\n内置字体：\n\n 字体 | 效果 \n :--- | :--- \n Captcha.FONT_1 |  ![](https://s2.ax1x.com/2019/08/23/msMe6U.png)\n Captcha.FONT_2 | ![](https://s2.ax1x.com/2019/08/23/msMAf0.png)\n Captcha.FONT_3 |  ![](https://s2.ax1x.com/2019/08/23/msMCwj.png)\n Captcha.FONT_4 | ![](https://s2.ax1x.com/2019/08/23/msM9mQ.png)\n Captcha.FONT_5 | ![](https://s2.ax1x.com/2019/08/23/msKz6S.png)\n Captcha.FONT_6 | ![](https://s2.ax1x.com/2019/08/23/msKxl8.png)\n Captcha.FONT_7 | ![](https://s2.ax1x.com/2019/08/23/msMPTs.png)\n Captcha.FONT_8 | ![](https://s2.ax1x.com/2019/08/23/msMmXF.png)\n Captcha.FONT_9 | ![](https://s2.ax1x.com/2019/08/23/msMVpV.png)\n Captcha.FONT_10 | ![](https://s2.ax1x.com/2019/08/23/msMZlT.png)\n\n使用方法：\n```\nCaptchaProperty property = new CaptchaProperty();\n//配置验证码类性枚举\nproperty.setCaptcha(CaptchaEnum.SPEC);\n\n// 设置内置字体\nproperty.setFont(Captcha.FONT_1); \n\n// 设置系统字体\nproperty.setFont(new Font(\"楷体\", Font.PLAIN, 28));\n\n//创建验证码实例对象\nCaptcha captcha = CaptchaFactory.getCaptcha(property);\n```\n\n### 5.4.输出base64编码\n```\nCaptcha captcha = CaptchaFactory.getCaptcha(property);\nTextEntry entry = captcha.createText();\nString base64 = captcha.toBase64(entry);\n```\n\n### 5.5.输出到文件\n```\nFileOutputStream outputStream = new FileOutputStream(new File(\"C:/captcha.png\"))\nCaptcha captcha = CaptchaFactory.getCaptcha(property);\nTextEntry entry = captcha.createText();\ncaptcha.out(outputStream);\n```\n\n\n---\n\n\n\n## 6.自定义效果\n\n\u0026emsp;继承`Captcha`实现`out`， `createText`方等方法，中文验证码可继承`ChineseCaptchaAbstract`，算术验证码可继承`ArithmeticCaptchaAbstract`。\n\n---\n\n\n\n## 7.开发分支说明\n\n- master为2.x.x版本的发行主分支，支持SpringBoot2.x的版本\n- v3为3.x.x版本的发行主分支, 支持SpringBoot3.x的版本\n- 欢迎大家提交issues和push\n\n---\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feternalstone%2Feasycaptchaboot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feternalstone%2Feasycaptchaboot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feternalstone%2Feasycaptchaboot/lists"}