Commit aaf62982e277f573a0c7b271aa4e2ba7faee21ce

Authored by xingyu
1 parent 865f1010

feat: 优化 captcha 代码

Showing 33 changed files with 476 additions and 2759 deletions
yudao-framework/yudao-spring-boot-starter-captcha/pom.xml
... ... @@ -21,6 +21,7 @@
21 21 <dependency>
22 22 <groupId>org.springframework.boot</groupId>
23 23 <artifactId>spring-boot-starter</artifactId>
  24 + <scope>provided</scope>
24 25 </dependency>
25 26  
26 27 <dependency>
... ...
yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/config/AjCaptchaServiceAutoConfiguration.java
1 1 package com.anji.captcha.config;
2 2  
  3 +import cn.hutool.core.util.StrUtil;
3 4 import com.anji.captcha.model.common.Const;
4 5 import com.anji.captcha.properties.AjCaptchaProperties;
5 6 import com.anji.captcha.service.CaptchaService;
6 7 import com.anji.captcha.service.impl.CaptchaServiceFactory;
7 8 import com.anji.captcha.util.ImageUtils;
8   -import com.anji.captcha.util.StringUtils;
9   -import org.slf4j.Logger;
10   -import org.slf4j.LoggerFactory;
  9 +import lombok.extern.slf4j.Slf4j;
11 10 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
12 11 import org.springframework.context.annotation.Bean;
13 12 import org.springframework.context.annotation.Configuration;
... ... @@ -21,15 +20,14 @@ import java.util.HashMap;
21 20 import java.util.Map;
22 21 import java.util.Properties;
23 22  
  23 +@Slf4j
24 24 @Configuration
25 25 public class AjCaptchaServiceAutoConfiguration {
26 26  
27   - private static Logger logger = LoggerFactory.getLogger(AjCaptchaServiceAutoConfiguration.class);
28   -
29 27 @Bean
30 28 @ConditionalOnMissingBean
31 29 public CaptchaService captchaService(AjCaptchaProperties prop) {
32   - logger.info("自定义配置项:{}", prop.toString());
  30 + log.info("自定义配置项:{}", prop.toString());
33 31 Properties config = new Properties();
34 32 config.put(Const.CAPTCHA_CACHETYPE, prop.getCacheType().name());
35 33 config.put(Const.CAPTCHA_WATER_MARK, prop.getWaterMark());
... ... @@ -57,14 +55,13 @@ public class AjCaptchaServiceAutoConfiguration {
57 55 config.put(Const.CAPTCHA_FONT_STYLE, prop.getFontStyle() + "");
58 56 config.put(Const.CAPTCHA_WORD_COUNT, prop.getClickWordCount() + "");
59 57  
60   - if ((StringUtils.isNotBlank(prop.getJigsaw()) && prop.getJigsaw().startsWith("classpath:"))
61   - || (StringUtils.isNotBlank(prop.getPicClick()) && prop.getPicClick().startsWith("classpath:"))) {
  58 + if ((StrUtil.isNotBlank(prop.getJigsaw()) && prop.getJigsaw().startsWith("classpath:"))
  59 + || (StrUtil.isNotBlank(prop.getPicClick()) && prop.getPicClick().startsWith("classpath:"))) {
62 60 //自定义resources目录下初始化底图
63 61 config.put(Const.CAPTCHA_INIT_ORIGINAL, "true");
64 62 initializeBaseMap(prop.getJigsaw(), prop.getPicClick());
65 63 }
66   - CaptchaService s = CaptchaServiceFactory.getInstance(config);
67   - return s;
  64 + return CaptchaServiceFactory.getInstance(config);
68 65 }
69 66  
70 67 private static void initializeBaseMap(String jigsaw, String picClick) {
... ...
yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/config/AjCaptchaStorageAutoConfiguration.java
... ... @@ -8,14 +8,13 @@ import org.springframework.context.annotation.Configuration;
8 8  
9 9 /**
10 10 * 存储策略自动配置.
11   - *
12 11 */
13 12 @Configuration
14 13 public class AjCaptchaStorageAutoConfiguration {
15 14  
16 15 @Bean(name = "AjCaptchaCacheService")
17   - public CaptchaCacheService captchaCacheService(AjCaptchaProperties ajCaptchaProperties){
18   - //缓存类型redis/local/....
  16 + public CaptchaCacheService captchaCacheService(AjCaptchaProperties ajCaptchaProperties) {
  17 + // 缓存类型redis/local/....
19 18 return CaptchaServiceFactory.getCache(ajCaptchaProperties.getCacheType().name());
20 19 }
21 20 }
... ...
yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/controller/CaptchaController.java deleted
1   -/*
2   - *Copyright © 2018 anji-plus
3   - *安吉加加信息技术有限公司
4   - *http://www.anji-plus.com
5   - *All rights reserved.
6   - */
7   -package com.anji.captcha.controller;
8   -
9   -import com.anji.captcha.model.common.ResponseModel;
10   -import com.anji.captcha.model.vo.CaptchaVO;
11   -import com.anji.captcha.service.CaptchaService;
12   -import com.anji.captcha.util.StringUtils;
13   -import org.springframework.beans.factory.annotation.Autowired;
14   -import org.springframework.web.bind.annotation.PostMapping;
15   -import org.springframework.web.bind.annotation.RequestBody;
16   -import org.springframework.web.bind.annotation.RequestMapping;
17   -import org.springframework.web.bind.annotation.RestController;
18   -
19   -import javax.servlet.http.HttpServletRequest;
20   -
21   -
22   -@RestController
23   -@RequestMapping("/captcha")
24   -public class CaptchaController {
25   -
26   - @Autowired
27   - private CaptchaService captchaService;
28   -
29   - @PostMapping("/get")
30   - public ResponseModel get(@RequestBody CaptchaVO data, HttpServletRequest request) {
31   - assert request.getRemoteHost()!=null;
32   - data.setBrowserInfo(getRemoteId(request));
33   - return captchaService.get(data);
34   - }
35   -
36   - @PostMapping("/check")
37   - public ResponseModel check(@RequestBody CaptchaVO data, HttpServletRequest request) {
38   - data.setBrowserInfo(getRemoteId(request));
39   - return captchaService.check(data);
40   - }
41   -
42   - //@PostMapping("/verify")
43   - public ResponseModel verify(@RequestBody CaptchaVO data, HttpServletRequest request) {
44   - return captchaService.verification(data);
45   - }
46   -
47   - public static final String getRemoteId(HttpServletRequest request) {
48   - String xfwd = request.getHeader("X-Forwarded-For");
49   - String ip = getRemoteIpFromXfwd(xfwd);
50   - String ua = request.getHeader("user-agent");
51   - if (StringUtils.isNotBlank(ip)) {
52   - return ip + ua;
53   - }
54   - return request.getRemoteAddr() + ua;
55   - }
56   -
57   - private static String getRemoteIpFromXfwd(String xfwd) {
58   - if (StringUtils.isNotBlank(xfwd)) {
59   - String[] ipList = xfwd.split(",");
60   - return StringUtils.trim(ipList[0]);
61   - }
62   - return null;
63   - }
64   -
65   -}
yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/model/common/CaptchaBaseMapEnum.java
1 1 package com.anji.captcha.model.common;
2 2  
  3 +import lombok.AllArgsConstructor;
  4 +import lombok.Getter;
  5 +
3 6 /**
4 7 * 底图类型枚举
5 8 */
  9 +@Getter
  10 +@AllArgsConstructor
6 11 public enum CaptchaBaseMapEnum {
7   - ORIGINAL("ORIGINAL","滑动拼图底图"),
8   - SLIDING_BLOCK("SLIDING_BLOCK","滑动拼图滑块底图"),
9   - PIC_CLICK("PIC_CLICK","文字点选底图");
10   -
11   - private String codeValue;
12   - private String codeDesc;
13   -
14   - private CaptchaBaseMapEnum(String codeValue, String codeDesc) {
15   - this.codeValue = codeValue;
16   - this.codeDesc = codeDesc;
17   - }
18   -
19   - public String getCodeValue(){ return this.codeValue;}
  12 + ORIGINAL("ORIGINAL", "滑动拼图底图"),
  13 + SLIDING_BLOCK("SLIDING_BLOCK", "滑动拼图滑块底图"),
  14 + PIC_CLICK("PIC_CLICK", "文字点选底图");
20 15  
21   - public String getCodeDesc(){ return this.codeDesc;}
  16 + private final String codeValue;
  17 + private final String codeDesc;
22 18  
23 19 //根据codeValue获取枚举
24   - public static CaptchaBaseMapEnum parseFromCodeValue(String codeValue){
25   - for (CaptchaBaseMapEnum e : CaptchaBaseMapEnum.values()){
26   - if(e.codeValue.equals(codeValue)){ return e;}
  20 + public static CaptchaBaseMapEnum parseFromCodeValue(String codeValue) {
  21 + for (CaptchaBaseMapEnum e : CaptchaBaseMapEnum.values()) {
  22 + if (e.codeValue.equals(codeValue)) {
  23 + return e;
  24 + }
27 25 }
28 26 return null;
29 27 }
30 28  
31 29 //根据codeValue获取描述
32   - public static String getCodeDescByCodeBalue(String codeValue){
  30 + public static String getCodeDescByCodeBalue(String codeValue) {
33 31 CaptchaBaseMapEnum enumItem = parseFromCodeValue(codeValue);
34 32 return enumItem == null ? "" : enumItem.getCodeDesc();
35 33 }
36 34  
37 35 //验证codeValue是否有效
38   - public static boolean validateCodeValue(String codeValue){ return parseFromCodeValue(codeValue)!=null;}
  36 + public static boolean validateCodeValue(String codeValue) {
  37 + return parseFromCodeValue(codeValue) != null;
  38 + }
39 39  
40 40 //列出所有值字符串
41   - public static String getString(){
  41 + public static String getString() {
42 42 StringBuffer buffer = new StringBuffer();
43   - for (CaptchaBaseMapEnum e : CaptchaBaseMapEnum.values()){
  43 + for (CaptchaBaseMapEnum e : CaptchaBaseMapEnum.values()) {
44 44 buffer.append(e.codeValue).append("--").append(e.getCodeDesc()).append(", ");
45 45 }
46 46 buffer.deleteCharAt(buffer.lastIndexOf(","));
... ...
yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/model/common/CaptchaTypeEnum.java
1 1 package com.anji.captcha.model.common;
2 2  
  3 +import lombok.AllArgsConstructor;
  4 +import lombok.Getter;
  5 +
  6 +@Getter
  7 +@AllArgsConstructor
3 8 public enum CaptchaTypeEnum {
4 9 /**
5 10 * 滑块拼图.
6 11 */
7   - BLOCKPUZZLE("blockPuzzle","滑块拼图"),
  12 + BLOCKPUZZLE("blockPuzzle", "滑块拼图"),
8 13 /**
9 14 * 文字点选.
10 15 */
11   - CLICKWORD("clickWord","文字点选"),
  16 + CLICKWORD("clickWord", "文字点选"),
12 17 /**
13 18 * 默认.
14 19 */
15   - DEFAULT("default","默认");
16   -
17   - private String codeValue;
18   - private String codeDesc;
19   -
20   - private CaptchaTypeEnum(String codeValue, String codeDesc) {
21   - this.codeValue = codeValue;
22   - this.codeDesc = codeDesc;
23   - }
24   -
25   - public String getCodeValue(){ return this.codeValue;}
  20 + DEFAULT("default", "默认");
26 21  
27   - public String getCodeDesc(){ return this.codeDesc;}
  22 + private final String codeValue;
  23 + private final String codeDesc;
28 24  
29 25 //根据codeValue获取枚举
30   - public static CaptchaTypeEnum parseFromCodeValue(String codeValue){
31   - for (CaptchaTypeEnum e : CaptchaTypeEnum.values()){
32   - if(e.codeValue.equals(codeValue)){ return e;}
  26 + public static CaptchaTypeEnum parseFromCodeValue(String codeValue) {
  27 + for (CaptchaTypeEnum e : CaptchaTypeEnum.values()) {
  28 + if (e.codeValue.equals(codeValue)) {
  29 + return e;
  30 + }
33 31 }
34 32 return null;
35 33 }
36 34  
37 35 //根据codeValue获取描述
38   - public static String getCodeDescByCodeBalue(String codeValue){
  36 + public static String getCodeDescByCodeBalue(String codeValue) {
39 37 CaptchaTypeEnum enumItem = parseFromCodeValue(codeValue);
40 38 return enumItem == null ? "" : enumItem.getCodeDesc();
41 39 }
42 40  
43 41 //验证codeValue是否有效
44   - public static boolean validateCodeValue(String codeValue){ return parseFromCodeValue(codeValue)!=null;}
  42 + public static boolean validateCodeValue(String codeValue) {
  43 + return parseFromCodeValue(codeValue) != null;
  44 + }
45 45  
46 46 //列出所有值字符串
47   - public static String getString(){
48   - StringBuffer buffer = new StringBuffer();
49   - for (CaptchaTypeEnum e : CaptchaTypeEnum.values()){
  47 + public static String getString() {
  48 + StringBuilder buffer = new StringBuilder();
  49 + for (CaptchaTypeEnum e : CaptchaTypeEnum.values()) {
50 50 buffer.append(e.codeValue).append("--").append(e.getCodeDesc()).append(", ");
51 51 }
52 52 buffer.deleteCharAt(buffer.lastIndexOf(","));
... ...
yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/model/common/Const.java
... ... @@ -6,7 +6,7 @@ package com.anji.captcha.model.common;
6 6 public interface Const {
7 7  
8 8 /**
9   - *滑块底图路径
  9 + * 滑块底图路径
10 10 */
11 11 String ORIGINAL_PATH_JIGSAW = "captcha.captchaOriginalPath.jigsaw";
12 12  
... ... @@ -29,8 +29,8 @@ public interface Const {
29 29 * 点选文字验证码的文字字体(宋体)
30 30 */
31 31 String CAPTCHA_FONT_TYPE = "captcha.font.type";
32   - String CAPTCHA_FONT_STYLE = "captcha.font.style";
33   - String CAPTCHA_FONT_SIZE = "captcha.font.size";
  32 + String CAPTCHA_FONT_STYLE = "captcha.font.style";
  33 + String CAPTCHA_FONT_SIZE = "captcha.font.size";
34 34  
35 35 /**
36 36 * 验证码类型default两种都实例化。
... ... @@ -72,41 +72,41 @@ public interface Const {
72 72 */
73 73 String CAPTCHA_TIMING_CLEAR_SECOND = "captcha.timing.clear";
74 74  
75   - /**
76   - * 历史资源清除开关 0禁用,1 开启
77   - */
78   - String HISTORY_DATA_CLEAR_ENABLE = "captcha.history.data.clear.enable";
79   -
80   - /**
81   - * 接口限流开关 0禁用 1启用
82   - */
83   - String REQ_FREQUENCY_LIMIT_ENABLE = "captcha.req.frequency.limit.enable";
84   -
85   - /**
86   - * get 接口 一分钟请求次数限制
87   - */
88   - String REQ_GET_MINUTE_LIMIT = "captcha.req.get.minute.limit";
89   -
90   - /**
91   - * 验证失败后,get接口锁定时间
92   - */
93   - String REQ_GET_LOCK_LIMIT = "captcha.req.get.lock.limit";
94   - /**
95   - * 验证失败后,get接口锁定时间
96   - */
97   - String REQ_GET_LOCK_SECONDS = "captcha.req.get.lock.seconds";
98   -
99   - /**
100   - * verify 接口 一分钟请求次数限制
101   - */
102   - String REQ_VALIDATE_MINUTE_LIMIT = "captcha.req.verify.minute.limit";
103   - /**
104   - * check接口 一分钟请求次数限制
105   - */
106   - String REQ_CHECK_MINUTE_LIMIT = "captcha.req.check.minute.limit";
107   -
108   - /***
109   - * 点选文字个数
110   - */
111   - String CAPTCHA_WORD_COUNT = "captcha.word.count";
  75 + /**
  76 + * 历史资源清除开关 0禁用,1 开启
  77 + */
  78 + String HISTORY_DATA_CLEAR_ENABLE = "captcha.history.data.clear.enable";
  79 +
  80 + /**
  81 + * 接口限流开关 0禁用 1启用
  82 + */
  83 + String REQ_FREQUENCY_LIMIT_ENABLE = "captcha.req.frequency.limit.enable";
  84 +
  85 + /**
  86 + * get 接口 一分钟请求次数限制
  87 + */
  88 + String REQ_GET_MINUTE_LIMIT = "captcha.req.get.minute.limit";
  89 +
  90 + /**
  91 + * 验证失败后,get接口锁定时间
  92 + */
  93 + String REQ_GET_LOCK_LIMIT = "captcha.req.get.lock.limit";
  94 + /**
  95 + * 验证失败后,get接口锁定时间
  96 + */
  97 + String REQ_GET_LOCK_SECONDS = "captcha.req.get.lock.seconds";
  98 +
  99 + /**
  100 + * verify 接口 一分钟请求次数限制
  101 + */
  102 + String REQ_VALIDATE_MINUTE_LIMIT = "captcha.req.verify.minute.limit";
  103 + /**
  104 + * check接口 一分钟请求次数限制
  105 + */
  106 + String REQ_CHECK_MINUTE_LIMIT = "captcha.req.check.minute.limit";
  107 +
  108 + /***
  109 + * 点选文字个数
  110 + */
  111 + String CAPTCHA_WORD_COUNT = "captcha.word.count";
112 112 }
... ...
yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/model/common/RepCodeEnum.java
... ... @@ -6,16 +6,23 @@
6 6 */
7 7 package com.anji.captcha.model.common;
8 8  
  9 +import lombok.AllArgsConstructor;
  10 +import lombok.Getter;
  11 +
9 12 import java.text.MessageFormat;
10 13  
11 14 /**
12 15 * 返回应答码
13   - * @author
14 16 *
  17 + * @author
15 18 */
  19 +@AllArgsConstructor
  20 +@Getter
16 21 public enum RepCodeEnum {
17 22  
18   - /** 0001 - 0099 网关应答码 */
  23 + /**
  24 + * 0001 - 0099 网关应答码
  25 + */
19 26 SUCCESS("0000", "成功"),
20 27 ERROR("0001", "操作失败"),
21 28 EXCEPTION("9999", "服务器内部异常"),
... ... @@ -33,36 +40,24 @@ public enum RepCodeEnum {
33 40 API_CAPTCHA_ERROR("6112", "获取验证码失败,请联系管理员"),
34 41 API_CAPTCHA_BASEMAP_NULL("6113", "底图未初始化成功,请检查路径"),
35 42  
36   - API_REQ_LIMIT_GET_ERROR("6201", "get接口请求次数超限,请稍后再试!"),
  43 + API_REQ_LIMIT_GET_ERROR("6201", "get接口请求次数超限,请稍后再试!"),
37 44 API_REQ_INVALID("6206", "无效请求,请重新获取验证码"),
38   - API_REQ_LOCK_GET_ERROR("6202", "接口验证失败数过多,请稍后再试"),
39   - API_REQ_LIMIT_CHECK_ERROR("6204", "check接口请求次数超限,请稍后再试!"),
40   - API_REQ_LIMIT_VERIFY_ERROR("6205", "verify请求次数超限!"),
41   - ;
42   - private String code;
43   - private String desc;
  45 + API_REQ_LOCK_GET_ERROR("6202", "接口验证失败数过多,请稍后再试"),
  46 + API_REQ_LIMIT_CHECK_ERROR("6204", "check接口请求次数超限,请稍后再试!"),
  47 + API_REQ_LIMIT_VERIFY_ERROR("6205", "verify请求次数超限!");
  48 + private final String code;
  49 + private final String desc;
44 50  
45   - RepCodeEnum(String code, String desc) {
46   - this.code = code;
47   - this.desc = desc;
48   - }
49   - public String getCode() {
50   - return code;
51   - }
52   - public String getDesc() {
53   - return desc;
54   - }
55   - public String getName(){
56   - return this.name();
57   - }
58 51  
59   - /** 将入参fieldNames与this.desc组合成错误信息
60   - * {fieldName}不能为空
  52 + /**
  53 + * 将入参fieldNames与this.desc组合成错误信息
  54 + * {fieldName}不能为空
  55 + *
61 56 * @param fieldNames
62 57 * @return
63 58 */
64 59 public ResponseModel parseError(Object... fieldNames) {
65   - ResponseModel errorMessage=new ResponseModel();
  60 + ResponseModel errorMessage = new ResponseModel();
66 61 String newDesc = MessageFormat.format(this.desc, fieldNames);
67 62  
68 63 errorMessage.setRepCode(this.code);
... ...
yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/model/common/RequestModel.java
... ... @@ -6,23 +6,32 @@
6 6 */
7 7 package com.anji.captcha.model.common;
8 8  
9   -import com.anji.captcha.util.StringUtils;
  9 +
  10 +import cn.hutool.core.util.StrUtil;
  11 +import lombok.Data;
10 12  
11 13 import java.io.Serializable;
12 14 import java.util.HashMap;
13 15 import java.util.List;
14 16  
  17 +@Data
15 18 public class RequestModel implements Serializable {
16 19  
17 20 private static final long serialVersionUID = -5800786065305114784L;
18 21  
19   - /**当前请求接口路径 /business/accessUser/login */
  22 + /**
  23 + * 当前请求接口路径 /business/accessUser/login
  24 + */
20 25 private String servletPath;
21 26  
22   - /** {"reqData":{"password":"*****","userName":"admin"},"sign":"a304a7f296f565b6d2009797f68180f0","time":"1542456453355","token":""} */
  27 + /**
  28 + * {"reqData":{"password":"*****","userName":"admin"},"sign":"a304a7f296f565b6d2009797f68180f0","time":"1542456453355","token":""}
  29 + */
23 30 private String requestString;
24 31  
25   - /** {"password":"****","userName":"admin"} */
  32 + /**
  33 + * {"password":"****","userName":"admin"}
  34 + */
26 35 private HashMap reqData;
27 36  
28 37 private String token;
... ... @@ -46,10 +55,11 @@ public class RequestModel implements Serializable {
46 55  
47 56 /**
48 57 * 校验自身参数合法性
  58 + *
49 59 * @return
50 60 */
51 61 public boolean isVaildateRequest() {
52   - if (StringUtils.isBlank(sign) || StringUtils.isBlank(time)) {
  62 + if (StrUtil.isBlank(sign) || StrUtil.isBlank(time)) {
53 63 return false;
54 64 }
55 65 return true;
... ... @@ -63,95 +73,4 @@ public class RequestModel implements Serializable {
63 73 this.servletPath = servletPath;
64 74 }
65 75  
66   - public String getToken() {
67   - return token;
68   - }
69   -
70   - public void setToken(String token) {
71   - this.token = token;
72   - }
73   -
74   - public Long getUserId() {
75   - return userId;
76   - }
77   -
78   - public void setUserId(Long userId) {
79   - this.userId = userId;
80   - }
81   -
82   - public String getUserName() {
83   - return userName;
84   - }
85   -
86   - public void setUserName(String userName) {
87   - this.userName = userName;
88   - }
89   -
90   - public static long getSerialVersionUID() {
91   - return serialVersionUID;
92   - }
93   -
94   - public List<Long> getProjectList() {
95   - return projectList;
96   - }
97   -
98   - public void setProjectList(List<Long> projectList) {
99   - this.projectList = projectList;
100   - }
101   -
102   - public List<Long> getGroupIdList() {
103   - return groupIdList;
104   - }
105   -
106   - public void setGroupIdList(List<Long> groupIdList) {
107   - this.groupIdList = groupIdList;
108   - }
109   -
110   - public String getSign() {
111   - return sign;
112   - }
113   -
114   - public void setSign(String sign) {
115   - this.sign = sign;
116   - }
117   -
118   - public String getTime() {
119   - return time;
120   - }
121   -
122   - public void setTime(String time) {
123   - this.time = time;
124   - }
125   -
126   - public String getSourceIP() {
127   - return sourceIP;
128   - }
129   -
130   - public void setSourceIP(String sourceIP) {
131   - this.sourceIP = sourceIP;
132   - }
133   -
134   - public String getRequestString() {
135   - return requestString;
136   - }
137   -
138   - public void setRequestString(String requestString) {
139   - this.requestString = requestString;
140   - }
141   -
142   - public HashMap getReqData() {
143   - return reqData;
144   - }
145   -
146   - public void setReqData(HashMap reqData) {
147   - this.reqData = reqData;
148   - }
149   -
150   - public String getTarget() {
151   - return target;
152   - }
153   -
154   - public void setTarget(String target) {
155   - this.target = target;
156   - }
157 76 }
... ...
yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/model/common/ResponseModel.java
... ... @@ -6,38 +6,42 @@
6 6 */
7 7 package com.anji.captcha.model.common;
8 8  
9   -import com.anji.captcha.util.StringUtils;
  9 +import cn.hutool.core.util.StrUtil;
  10 +import lombok.Data;
10 11  
11 12 import java.io.Serializable;
12 13  
  14 +@Data
13 15 public class ResponseModel implements Serializable {
14 16  
15 17 private static final long serialVersionUID = 8445617032523881407L;
16 18  
17   - private String repCode;
  19 + private String repCode;
18 20  
19   - private String repMsg;
  21 + private String repMsg;
20 22  
21   - private Object repData;
  23 + private Object repData;
22 24  
23 25 public ResponseModel() {
24 26 this.repCode = RepCodeEnum.SUCCESS.getCode();
25 27 }
26 28  
27 29 public ResponseModel(RepCodeEnum repCodeEnum) {
28   - this.setRepCodeEnum(repCodeEnum);
  30 + this.setRepCodeEnum(repCodeEnum);
29 31 }
30 32  
31 33 //成功
32   - public static ResponseModel success(){
  34 + public static ResponseModel success() {
33 35 return ResponseModel.successMsg("成功");
34 36 }
35   - public static ResponseModel successMsg(String message){
  37 +
  38 + public static ResponseModel successMsg(String message) {
36 39 ResponseModel responseModel = new ResponseModel();
37 40 responseModel.setRepMsg(message);
38 41 return responseModel;
39 42 }
40   - public static ResponseModel successData(Object data){
  43 +
  44 + public static ResponseModel successData(Object data) {
41 45 ResponseModel responseModel = new ResponseModel();
42 46 responseModel.setRepCode(RepCodeEnum.SUCCESS.getCode());
43 47 responseModel.setRepData(data);
... ... @@ -45,67 +49,45 @@ public class ResponseModel implements Serializable {
45 49 }
46 50  
47 51 //失败
48   - public static ResponseModel errorMsg(RepCodeEnum message){
  52 + public static ResponseModel errorMsg(RepCodeEnum message) {
49 53 ResponseModel responseModel = new ResponseModel();
50 54 responseModel.setRepCodeEnum(message);
51 55 return responseModel;
52 56 }
53   - public static ResponseModel errorMsg(String message){
  57 +
  58 + public static ResponseModel errorMsg(String message) {
54 59 ResponseModel responseModel = new ResponseModel();
55 60 responseModel.setRepCode(RepCodeEnum.ERROR.getCode());
56 61 responseModel.setRepMsg(message);
57 62 return responseModel;
58 63 }
59   - public static ResponseModel errorMsg(RepCodeEnum repCodeEnum, String message){
  64 +
  65 + public static ResponseModel errorMsg(RepCodeEnum repCodeEnum, String message) {
60 66 ResponseModel responseModel = new ResponseModel();
61 67 responseModel.setRepCode(repCodeEnum.getCode());
62 68 responseModel.setRepMsg(message);
63 69 return responseModel;
64 70 }
65   - public static ResponseModel exceptionMsg(String message){
  71 +
  72 + public static ResponseModel exceptionMsg(String message) {
66 73 ResponseModel responseModel = new ResponseModel();
67 74 responseModel.setRepCode(RepCodeEnum.EXCEPTION.getCode());
68 75 responseModel.setRepMsg(RepCodeEnum.EXCEPTION.getDesc() + ": " + message);
69 76 return responseModel;
70 77 }
71 78  
72   - @Override
73   - public String toString() {
74   - return "ResponseModel{" + "repCode='" + repCode + '\'' + ", repMsg='"
75   - + repMsg + '\'' + ", repData=" + repData + '}';
76   - }
77 79  
78   - public boolean isSuccess(){
79   - return StringUtils.equals(repCode, RepCodeEnum.SUCCESS.getCode());
  80 + public boolean isSuccess() {
  81 + return StrUtil.equals(repCode, RepCodeEnum.SUCCESS.getCode());
80 82 }
81 83  
82 84 public String getRepCode() {
83 85 return repCode;
84 86 }
85 87  
86   - public void setRepCode(String repCode) {
87   - this.repCode = repCode;
88   - }
89 88 public void setRepCodeEnum(RepCodeEnum repCodeEnum) {
90   - this.repCode=repCodeEnum.getCode();
91   - this.repMsg=repCodeEnum.getDesc();
92   - }
93   -
94   - public String getRepMsg() {
95   - return repMsg;
  89 + this.repCode = repCodeEnum.getCode();
  90 + this.repMsg = repCodeEnum.getDesc();
96 91 }
97 92  
98   - public void setRepMsg(String repMsg) {
99   - this.repMsg = repMsg;
100   - }
101   -
102   - public Object getRepData() {
103   - return repData;
104   - }
105   -
106   - public void setRepData(Object repData) {
107   - this.repData = repData;
108   - }
109   -
110   -
111 93 }
... ...
yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/model/vo/CaptchaVO.java
... ... @@ -6,10 +6,13 @@
6 6 */
7 7 package com.anji.captcha.model.vo;
8 8  
  9 +import lombok.Data;
  10 +
9 11 import java.awt.*;
10 12 import java.io.Serializable;
11 13 import java.util.List;
12 14  
  15 +@Data
13 16 public class CaptchaVO implements Serializable {
14 17  
15 18 /**
... ... @@ -79,173 +82,23 @@ public class CaptchaVO implements Serializable {
79 82 */
80 83 private String captchaVerification;
81 84  
82   - /***
83   - * 客户端UI组件id,组件初始化时设置一次,UUID
84   - */
85   - private String clientUid;
86   - /***
87   - * 客户端的请求时间,预留字段
88   - */
89   - private Long ts;
  85 + /***
  86 + * 客户端UI组件id,组件初始化时设置一次,UUID
  87 + */
  88 + private String clientUid;
  89 + /***
  90 + * 客户端的请求时间,预留字段
  91 + */
  92 + private Long ts;
90 93  
91 94 /***
92 95 * 客户端ip+userAgent
93 96 */
94 97 private String browserInfo;
95   - public void resetClientFlag(){
  98 +
  99 + public void resetClientFlag() {
96 100 this.browserInfo = null;
97 101 this.clientUid = null;
98 102 }
99 103  
100   - public String getCaptchaId() {
101   - return captchaId;
102   - }
103   -
104   - public void setCaptchaId(String captchaId) {
105   - this.captchaId = captchaId;
106   - }
107   -
108   - public String getProjectCode() {
109   - return projectCode;
110   - }
111   -
112   - public void setProjectCode(String projectCode) {
113   - this.projectCode = projectCode;
114   - }
115   -
116   - public String getCaptchaType() {
117   - return captchaType;
118   - }
119   -
120   - public void setCaptchaType(String captchaType) {
121   - this.captchaType = captchaType;
122   - }
123   -
124   - public String getCaptchaOriginalPath() {
125   - return captchaOriginalPath;
126   - }
127   -
128   - public void setCaptchaOriginalPath(String captchaOriginalPath) {
129   - this.captchaOriginalPath = captchaOriginalPath;
130   - }
131   -
132   - public String getCaptchaFontType() {
133   - return captchaFontType;
134   - }
135   -
136   - public void setCaptchaFontType(String captchaFontType) {
137   - this.captchaFontType = captchaFontType;
138   - }
139   -
140   - public Integer getCaptchaFontSize() {
141   - return captchaFontSize;
142   - }
143   -
144   - public void setCaptchaFontSize(Integer captchaFontSize) {
145   - this.captchaFontSize = captchaFontSize;
146   - }
147   -
148   - public String getOriginalImageBase64() {
149   - return originalImageBase64;
150   - }
151   -
152   - public void setOriginalImageBase64(String originalImageBase64) {
153   - this.originalImageBase64 = originalImageBase64;
154   - }
155   -
156   - public PointVO getPoint() {
157   - return point;
158   - }
159   -
160   - public void setPoint(PointVO point) {
161   - this.point = point;
162   - }
163   -
164   - public String getJigsawImageBase64() {
165   - return jigsawImageBase64;
166   - }
167   -
168   - public void setJigsawImageBase64(String jigsawImageBase64) {
169   - this.jigsawImageBase64 = jigsawImageBase64;
170   - }
171   -
172   - public List<String> getWordList() {
173   - return wordList;
174   - }
175   -
176   - public void setWordList(List<String> wordList) {
177   - this.wordList = wordList;
178   - }
179   -
180   - public List<Point> getPointList() {
181   - return pointList;
182   - }
183   -
184   - public void setPointList(List<Point> pointList) {
185   - this.pointList = pointList;
186   - }
187   -
188   - public String getPointJson() {
189   - return pointJson;
190   - }
191   -
192   - public void setPointJson(String pointJson) {
193   - this.pointJson = pointJson;
194   - }
195   -
196   - public String getToken() {
197   - return token;
198   - }
199   -
200   - public void setToken(String token) {
201   - this.token = token;
202   - }
203   -
204   - public Boolean getResult() {
205   - return result;
206   - }
207   -
208   - public void setResult(Boolean result) {
209   - this.result = result;
210   - }
211   -
212   - public String getCaptchaVerification() {
213   - return captchaVerification;
214   - }
215   -
216   - public void setCaptchaVerification(String captchaVerification) {
217   - this.captchaVerification = captchaVerification;
218   - }
219   -
220   - public String getSecretKey() {
221   - return secretKey;
222   - }
223   -
224   - public void setSecretKey(String secretKey) {
225   - this.secretKey = secretKey;
226   - }
227   -
228   - public String getClientUid() {
229   - return clientUid;
230   - }
231   -
232   - public void setClientUid(String clientUid) {
233   - this.clientUid = clientUid;
234   - }
235   -
236   - public Long getTs() {
237   - return ts;
238   - }
239   -
240   - public void setTs(Long ts) {
241   - this.ts = ts;
242   - }
243   -
244   - public String getBrowserInfo() {
245   - return browserInfo;
246   - }
247   -
248   - public void setBrowserInfo(String browserInfo) {
249   - this.browserInfo = browserInfo;
250   - }
251 104 }
... ...
yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/model/vo/PointVO.java
1 1 package com.anji.captcha.model.vo;
2 2  
  3 +import lombok.Data;
  4 +
3 5 import java.util.Arrays;
4 6 import java.util.HashMap;
5 7 import java.util.Map;
... ... @@ -9,6 +11,7 @@ import java.util.regex.Pattern;
9 11 /**
10 12 * Created by raodeming on 2020/5/16.
11 13 */
  14 +@Data
12 15 public class PointVO {
13 16 private String secretKey;
14 17  
... ... @@ -16,30 +19,6 @@ public class PointVO {
16 19  
17 20 public int y;
18 21  
19   - public String getSecretKey() {
20   - return secretKey;
21   - }
22   -
23   - public void setSecretKey(String secretKey) {
24   - this.secretKey = secretKey;
25   - }
26   -
27   - public int getX() {
28   - return x;
29   - }
30   -
31   - public void setX(int x) {
32   - this.x = x;
33   - }
34   -
35   - public int getY() {
36   - return y;
37   - }
38   -
39   - public void setY(int y) {
40   - this.y = y;
41   - }
42   -
43 22 public PointVO(int x, int y, String secretKey) {
44 23 this.secretKey = secretKey;
45 24 this.x = x;
... ...
yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/properties/AjCaptchaProperties.java
1 1 package com.anji.captcha.properties;
2 2  
3 3 import com.anji.captcha.model.common.CaptchaTypeEnum;
  4 +import lombok.Data;
4 5 import org.springframework.boot.context.properties.ConfigurationProperties;
5 6  
6 7 import java.awt.*;
... ... @@ -8,6 +9,7 @@ import java.awt.*;
8 9 import static com.anji.captcha.properties.AjCaptchaProperties.PREFIX;
9 10 import static com.anji.captcha.properties.AjCaptchaProperties.StorageType.local;
10 11  
  12 +@Data
11 13 @ConfigurationProperties(PREFIX)
12 14 public class AjCaptchaProperties {
13 15 public static final String PREFIX = "aj.captcha";
... ... @@ -113,90 +115,10 @@ public class AjCaptchaProperties {
113 115 */
114 116 private int clickWordCount = 4;
115 117  
116   - public int getFontStyle() {
117   - return fontStyle;
118   - }
119   -
120   - public void setFontStyle(int fontStyle) {
121   - this.fontStyle = fontStyle;
122   - }
123   -
124   - public int getFontSize() {
125   - return fontSize;
126   - }
127   -
128   - public void setFontSize(int fontSize) {
129   - this.fontSize = fontSize;
130   - }
131   -
132   - public int getClickWordCount() {
133   - return clickWordCount;
134   - }
135   -
136   - public void setClickWordCount(int clickWordCount) {
137   - this.clickWordCount = clickWordCount;
138   - }
139   -
140   - public boolean isHistoryDataClearEnable() {
141   - return historyDataClearEnable;
142   - }
143   -
144   - public void setHistoryDataClearEnable(boolean historyDataClearEnable) {
145   - this.historyDataClearEnable = historyDataClearEnable;
146   - }
147   -
148   - public boolean isReqFrequencyLimitEnable() {
149   - return reqFrequencyLimitEnable;
150   - }
151   -
152 118 public boolean getReqFrequencyLimitEnable() {
153 119 return reqFrequencyLimitEnable;
154 120 }
155 121  
156   - public void setReqFrequencyLimitEnable(boolean reqFrequencyLimitEnable) {
157   - this.reqFrequencyLimitEnable = reqFrequencyLimitEnable;
158   - }
159   -
160   - public int getReqGetLockLimit() {
161   - return reqGetLockLimit;
162   - }
163   -
164   - public void setReqGetLockLimit(int reqGetLockLimit) {
165   - this.reqGetLockLimit = reqGetLockLimit;
166   - }
167   -
168   - public int getReqGetLockSeconds() {
169   - return reqGetLockSeconds;
170   - }
171   -
172   - public void setReqGetLockSeconds(int reqGetLockSeconds) {
173   - this.reqGetLockSeconds = reqGetLockSeconds;
174   - }
175   -
176   - public int getReqGetMinuteLimit() {
177   - return reqGetMinuteLimit;
178   - }
179   -
180   - public void setReqGetMinuteLimit(int reqGetMinuteLimit) {
181   - this.reqGetMinuteLimit = reqGetMinuteLimit;
182   - }
183   -
184   - public int getReqCheckMinuteLimit() {
185   - return reqGetMinuteLimit;
186   - }
187   -
188   - public void setReqCheckMinuteLimit(int reqCheckMinuteLimit) {
189   - this.reqCheckMinuteLimit = reqCheckMinuteLimit;
190   - }
191   -
192   - public int getReqVerifyMinuteLimit() {
193   - return reqVerifyMinuteLimit;
194   - }
195   -
196   - public void setReqVerifyMinuteLimit(int reqVerifyMinuteLimit) {
197   - this.reqVerifyMinuteLimit = reqVerifyMinuteLimit;
198   - }
199   -
200 122 public enum StorageType {
201 123 /**
202 124 * 内存.
... ... @@ -216,123 +138,4 @@ public class AjCaptchaProperties {
216 138 return PREFIX;
217 139 }
218 140  
219   - public CaptchaTypeEnum getType() {
220   - return type;
221   - }
222   -
223   - public void setType(CaptchaTypeEnum type) {
224   - this.type = type;
225   - }
226   -
227   - public String getJigsaw() {
228   - return jigsaw;
229   - }
230   -
231   - public void setJigsaw(String jigsaw) {
232   - this.jigsaw = jigsaw;
233   - }
234   -
235   - public String getPicClick() {
236   - return picClick;
237   - }
238   -
239   - public void setPicClick(String picClick) {
240   - this.picClick = picClick;
241   - }
242   -
243   - public String getWaterMark() {
244   - return waterMark;
245   - }
246   -
247   - public void setWaterMark(String waterMark) {
248   - this.waterMark = waterMark;
249   - }
250   -
251   - public String getWaterFont() {
252   - return waterFont;
253   - }
254   -
255   - public void setWaterFont(String waterFont) {
256   - this.waterFont = waterFont;
257   - }
258   -
259   - public String getFontType() {
260   - return fontType;
261   - }
262   -
263   - public void setFontType(String fontType) {
264   - this.fontType = fontType;
265   - }
266   -
267   - public String getSlipOffset() {
268   - return slipOffset;
269   - }
270   -
271   - public void setSlipOffset(String slipOffset) {
272   - this.slipOffset = slipOffset;
273   - }
274   -
275   - public Boolean getAesStatus() {
276   - return aesStatus;
277   - }
278   -
279   - public void setAesStatus(Boolean aesStatus) {
280   - this.aesStatus = aesStatus;
281   - }
282   -
283   - public StorageType getCacheType() {
284   - return cacheType;
285   - }
286   -
287   - public void setCacheType(StorageType cacheType) {
288   - this.cacheType = cacheType;
289   - }
290   -
291   - public String getInterferenceOptions() {
292   - return interferenceOptions;
293   - }
294   -
295   - public void setInterferenceOptions(String interferenceOptions) {
296   - this.interferenceOptions = interferenceOptions;
297   - }
298   -
299   - public String getCacheNumber() {
300   - return cacheNumber;
301   - }
302   -
303   - public void setCacheNumber(String cacheNumber) {
304   - this.cacheNumber = cacheNumber;
305   - }
306   -
307   - public String getTimingClear() {
308   - return timingClear;
309   - }
310   -
311   - public void setTimingClear(String timingClear) {
312   - this.timingClear = timingClear;
313   - }
314   -
315   - @Override
316   - public String toString() {
317   - return "\nAjCaptchaProperties{" +
318   - "type=" + type +
319   - ", jigsaw='" + jigsaw + '\'' +
320   - ", picClick='" + picClick + '\'' +
321   - ", waterMark='" + waterMark + '\'' +
322   - ", waterFont='" + waterFont + '\'' +
323   - ", fontType='" + fontType + '\'' +
324   - ", slipOffset='" + slipOffset + '\'' +
325   - ", aesStatus=" + aesStatus +
326   - ", interferenceOptions='" + interferenceOptions + '\'' +
327   - ", cacheNumber='" + cacheNumber + '\'' +
328   - ", timingClear='" + timingClear + '\'' +
329   - ", cacheType=" + cacheType +
330   - ", reqFrequencyLimitEnable=" + reqFrequencyLimitEnable +
331   - ", reqGetLockLimit=" + reqGetLockLimit +
332   - ", reqGetLockSeconds=" + reqGetLockSeconds +
333   - ", reqGetMinuteLimit=" + reqGetMinuteLimit +
334   - ", reqCheckMinuteLimit=" + reqCheckMinuteLimit +
335   - ", reqVerifyMinuteLimit=" + reqVerifyMinuteLimit +
336   - '}';
337   - }
338 141 }
... ...
yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/service/CaptchaCacheService.java
... ... @@ -8,34 +8,36 @@ package com.anji.captcha.service;
8 8  
9 9 /**
10 10 * 验证码缓存接口
  11 + *
11 12 * @author lide1202@hotmail.com
12 13 * @date 2018-08-21
13 14 */
14 15 public interface CaptchaCacheService {
15 16  
16   - void set(String key, String value, long expiresInSeconds);
  17 + void set(String key, String value, long expiresInSeconds);
17 18  
18   - boolean exists(String key);
  19 + boolean exists(String key);
19 20  
20   - void delete(String key);
  21 + void delete(String key);
21 22  
22   - String get(String key);
  23 + String get(String key);
23 24  
24   - /**
25   - * 缓存类型-local/redis/memcache/..
26   - * 通过java SPI机制,接入方可自定义实现类
27   - * @return
28   - */
29   - String type();
  25 + /**
  26 + * 缓存类型-local/redis/memcache/..
  27 + * 通过java SPI机制,接入方可自定义实现类
  28 + *
  29 + * @return
  30 + */
  31 + String type();
30 32  
31   - /***
32   - *
33   - * @param key
34   - * @param val
35   - * @return
36   - */
37   - default Long increment(String key, long val){
38   - return 0L;
39   - };
  33 + /***
  34 + *
  35 + * @param key
  36 + * @param val
  37 + * @return
  38 + */
  39 + default Long increment(String key, long val) {
  40 + return 0L;
  41 + }
40 42  
41 43 }
... ...
yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/service/CaptchaService.java
... ... @@ -13,6 +13,7 @@ import java.util.Properties;
13 13  
14 14 /**
15 15 * 验证码服务接口
  16 + *
16 17 * @author lide1202@hotmail.com
17 18 * @date 2020-05-12
18 19 */
... ... @@ -24,6 +25,7 @@ public interface CaptchaService {
24 25  
25 26 /**
26 27 * 获取验证码
  28 + *
27 29 * @param captchaVO
28 30 * @return
29 31 */
... ... @@ -31,6 +33,7 @@ public interface CaptchaService {
31 33  
32 34 /**
33 35 * 核对验证码(前端)
  36 + *
34 37 * @param captchaVO
35 38 * @return
36 39 */
... ... @@ -38,6 +41,7 @@ public interface CaptchaService {
38 41  
39 42 /**
40 43 * 二次校验验证码(后端)
  44 + *
41 45 * @param captchaVO
42 46 * @return
43 47 */
... ... @@ -50,9 +54,10 @@ public interface CaptchaService {
50 54 */
51 55 String captchaType();
52 56  
53   - /**
54   - * 历史资源清除(过期的图片文件,生成的临时图片...)
55   - * @param config 配置项 控制资源清理的粒度
56   - */
57   - void destroy(Properties config);
  57 + /**
  58 + * 历史资源清除(过期的图片文件,生成的临时图片...)
  59 + *
  60 + * @param config 配置项 控制资源清理的粒度
  61 + */
  62 + void destroy(Properties config);
58 63 }
... ...
yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/service/impl/AbstractCaptchaService.java
... ... @@ -6,6 +6,7 @@
6 6 */
7 7 package com.anji.captcha.service.impl;
8 8  
  9 +import cn.hutool.core.util.StrUtil;
9 10 import com.anji.captcha.model.common.Const;
10 11 import com.anji.captcha.model.common.RepCodeEnum;
11 12 import com.anji.captcha.model.common.ResponseModel;
... ... @@ -13,29 +14,28 @@ import com.anji.captcha.model.vo.CaptchaVO;
13 14 import com.anji.captcha.service.CaptchaCacheService;
14 15 import com.anji.captcha.service.CaptchaService;
15 16 import com.anji.captcha.util.*;
16   -import org.slf4j.Logger;
17   -import org.slf4j.LoggerFactory;
  17 +import lombok.extern.slf4j.Slf4j;
18 18  
19 19 import java.awt.*;
20 20 import java.io.File;
21   -import java.io.FileOutputStream;
22 21 import java.io.OutputStream;
23 22 import java.nio.charset.StandardCharsets;
  23 +import java.nio.file.Files;
24 24 import java.util.Base64;
  25 +import java.util.Objects;
25 26 import java.util.Properties;
26 27  
27 28 /**
28 29 * Created by raodeming on 2019/12/25.
29 30 */
  31 +@Slf4j
30 32 public abstract class AbstractCaptchaService implements CaptchaService {
31 33  
32   - protected Logger logger = LoggerFactory.getLogger(getClass());
33   -
34 34 protected static final String IMAGE_TYPE_PNG = "png";
35 35  
36   - protected static int HAN_ZI_SIZE = 25;
  36 + protected static int HAN_ZI_SIZE = 25;
37 37  
38   - protected static int HAN_ZI_SIZE_HALF = HAN_ZI_SIZE / 2;
  38 + protected static int HAN_ZI_SIZE_HALF = HAN_ZI_SIZE / 2;
39 39 //check校验坐标
40 40 protected static String REDIS_CAPTCHA_KEY = "RUNNING:CAPTCHA:%s";
41 41  
... ... @@ -73,7 +73,7 @@ public abstract class AbstractCaptchaService implements CaptchaService {
73 73 ImageUtils.cacheImage(config.getProperty(Const.ORIGINAL_PATH_JIGSAW),
74 74 config.getProperty(Const.ORIGINAL_PATH_PIC_CLICK));
75 75 }
76   - logger.info("--->>>初始化验证码底图<<<---" + captchaType());
  76 + log.info("--->>>初始化验证码底图<<<---" + captchaType());
77 77 waterMark = config.getProperty(Const.CAPTCHA_WATER_MARK, "我的水印");
78 78 slipOffset = config.getProperty(Const.CAPTCHA_SLIP_OFFSET, "5");
79 79 waterMarkFontStr = config.getProperty(Const.CAPTCHA_WATER_FONT, "WenQuanZhengHei.ttf");
... ... @@ -88,13 +88,13 @@ public abstract class AbstractCaptchaService implements CaptchaService {
88 88 // 通过加载resources下的font字体解决,无需在linux中安装字体
89 89 loadWaterMarkFont();
90 90  
91   - if (cacheType.equals("local")) {
92   - logger.info("初始化local缓存...");
  91 + if ("local".equals(cacheType)) {
  92 + log.info("初始化local缓存...");
93 93 CacheUtil.init(Integer.parseInt(config.getProperty(Const.CAPTCHA_CACAHE_MAX_NUMBER, "1000")),
94 94 Long.parseLong(config.getProperty(Const.CAPTCHA_TIMING_CLEAR_SECOND, "180")));
95 95 }
96   - if (config.getProperty(Const.HISTORY_DATA_CLEAR_ENABLE, "0").equals("1")) {
97   - logger.info("历史资源清除开关...开启..." + captchaType());
  96 + if ("1".equals(config.getProperty(Const.HISTORY_DATA_CLEAR_ENABLE, "0"))) {
  97 + log.info("历史资源清除开关...开启..." + captchaType());
98 98 Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
99 99 @Override
100 100 public void run() {
... ... @@ -102,9 +102,9 @@ public abstract class AbstractCaptchaService implements CaptchaService {
102 102 }
103 103 }));
104 104 }
105   - if (config.getProperty(Const.REQ_FREQUENCY_LIMIT_ENABLE, "0").equals("1")) {
  105 + if ("1".equals(config.getProperty(Const.REQ_FREQUENCY_LIMIT_ENABLE, "0"))) {
106 106 if (limitHandler == null) {
107   - logger.info("接口分钟内限流开关...开启...");
  107 + log.info("接口分钟内限流开关...开启...");
108 108 limitHandler = new FrequencyLimitHandler.DefaultLimitHandler(config, getCacheService(cacheType));
109 109 }
110 110 }
... ... @@ -150,7 +150,7 @@ public abstract class AbstractCaptchaService implements CaptchaService {
150 150 if (captchaVO == null) {
151 151 return RepCodeEnum.NULL_ERROR.parseError("captchaVO");
152 152 }
153   - if (StringUtils.isEmpty(captchaVO.getCaptchaVerification())) {
  153 + if (StrUtil.isEmpty(captchaVO.getCaptchaVerification())) {
154 154 return RepCodeEnum.NULL_ERROR.parseError("captchaVerification");
155 155 }
156 156 if (limitHandler != null) {
... ... @@ -163,17 +163,17 @@ public abstract class AbstractCaptchaService implements CaptchaService {
163 163 return resp == null || resp.isSuccess();
164 164 }
165 165  
166   - protected String getValidateClientId(CaptchaVO req){
167   - // 以服务端获取的客户端标识 做识别标志
168   - if(StringUtils.isNotEmpty(req.getBrowserInfo())){
169   - return MD5Util.md5(req.getBrowserInfo());
170   - }
171   - // 以客户端Ui组件id做识别标志
172   - if(StringUtils.isNotEmpty(req.getClientUid())){
173   - return req.getClientUid();
174   - }
175   - return null;
176   - }
  166 + protected String getValidateClientId(CaptchaVO req) {
  167 + // 以服务端获取的客户端标识 做识别标志
  168 + if (StrUtil.isNotEmpty(req.getBrowserInfo())) {
  169 + return MD5Util.md5(req.getBrowserInfo());
  170 + }
  171 + // 以客户端Ui组件id做识别标志
  172 + if (StrUtil.isNotEmpty(req.getClientUid())) {
  173 + return req.getClientUid();
  174 + }
  175 + return null;
  176 + }
177 177  
178 178 protected void afterValidateFail(CaptchaVO data) {
179 179 if (limitHandler != null) {
... ... @@ -197,14 +197,14 @@ public abstract class AbstractCaptchaService implements CaptchaService {
197 197 if (waterMarkFontStr.toLowerCase().endsWith(".ttf") || waterMarkFontStr.toLowerCase().endsWith(".ttc")
198 198 || waterMarkFontStr.toLowerCase().endsWith(".otf")) {
199 199 this.waterMarkFont = Font.createFont(Font.TRUETYPE_FONT,
200   - getClass().getResourceAsStream("/fonts/" + waterMarkFontStr))
  200 + Objects.requireNonNull(getClass().getResourceAsStream("/fonts/" + waterMarkFontStr)))
201 201 .deriveFont(Font.BOLD, HAN_ZI_SIZE / 2);
202 202 } else {
203 203 this.waterMarkFont = new Font(waterMarkFontStr, Font.BOLD, HAN_ZI_SIZE / 2);
204 204 }
205 205  
206 206 } catch (Exception e) {
207   - logger.error("load font error:{}", e);
  207 + log.error("load font error:{}", e);
208 208 }
209 209 }
210 210  
... ... @@ -228,7 +228,7 @@ public abstract class AbstractCaptchaService implements CaptchaService {
228 228 if (!tempFile.getParentFile().exists()) {
229 229 tempFile.getParentFile().mkdirs();
230 230 }
231   - OutputStream out = new FileOutputStream(tempFile);
  231 + OutputStream out = Files.newOutputStream(tempFile.toPath());
232 232 out.write(b);
233 233 out.flush();
234 234 out.close();
... ...
yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/service/impl/BlockPuzzleCaptchaServiceImpl.java
... ... @@ -6,12 +6,14 @@
6 6 */
7 7 package com.anji.captcha.service.impl;
8 8  
  9 +import cn.hutool.core.util.StrUtil;
9 10 import com.anji.captcha.model.common.CaptchaTypeEnum;
10 11 import com.anji.captcha.model.common.RepCodeEnum;
11 12 import com.anji.captcha.model.common.ResponseModel;
12 13 import com.anji.captcha.model.vo.CaptchaVO;
13 14 import com.anji.captcha.model.vo.PointVO;
14 15 import com.anji.captcha.util.*;
  16 +import lombok.extern.slf4j.Slf4j;
15 17  
16 18 import javax.imageio.ImageIO;
17 19 import java.awt.*;
... ... @@ -27,6 +29,7 @@ import java.util.Random;
27 29 * <p>
28 30 * Created by raodeming on 2019/12/25.
29 31 */
  32 +@Slf4j
30 33 public class BlockPuzzleCaptchaServiceImpl extends AbstractCaptchaService {
31 34  
32 35 @Override
... ... @@ -34,10 +37,10 @@ public class BlockPuzzleCaptchaServiceImpl extends AbstractCaptchaService {
34 37 super.init(config);
35 38 }
36 39  
37   - @Override
38   - public void destroy(Properties config) {
39   - logger.info("start-clear-history-data-",captchaType());
40   - }
  40 + @Override
  41 + public void destroy(Properties config) {
  42 + log.info("start-clear-history-data-", captchaType());
  43 + }
41 44  
42 45 @Override
43 46 public String captchaType() {
... ... @@ -46,14 +49,14 @@ public class BlockPuzzleCaptchaServiceImpl extends AbstractCaptchaService {
46 49  
47 50 @Override
48 51 public ResponseModel get(CaptchaVO captchaVO) {
49   - ResponseModel r = super.get(captchaVO);
50   - if(!validatedReq(r)){
51   - return r;
52   - }
  52 + ResponseModel r = super.get(captchaVO);
  53 + if (!validatedReq(r)) {
  54 + return r;
  55 + }
53 56 //原生图片
54 57 BufferedImage originalImage = ImageUtils.getOriginal();
55 58 if (null == originalImage) {
56   - logger.error("滑动底图未初始化成功,请检查路径");
  59 + log.error("滑动底图未初始化成功,请检查路径");
57 60 return ResponseModel.errorMsg(RepCodeEnum.API_CAPTCHA_BASEMAP_NULL);
58 61 }
59 62 //设置水印
... ... @@ -68,13 +71,13 @@ public class BlockPuzzleCaptchaServiceImpl extends AbstractCaptchaService {
68 71 String jigsawImageBase64 = ImageUtils.getslidingBlock();
69 72 BufferedImage jigsawImage = ImageUtils.getBase64StrToImage(jigsawImageBase64);
70 73 if (null == jigsawImage) {
71   - logger.error("滑动底图未初始化成功,请检查路径");
  74 + log.error("滑动底图未初始化成功,请检查路径");
72 75 return ResponseModel.errorMsg(RepCodeEnum.API_CAPTCHA_BASEMAP_NULL);
73 76 }
74 77 CaptchaVO captcha = pictureTemplatesCut(originalImage, jigsawImage, jigsawImageBase64);
75 78 if (captcha == null
76   - || StringUtils.isBlank(captcha.getJigsawImageBase64())
77   - || StringUtils.isBlank(captcha.getOriginalImageBase64())) {
  79 + || StrUtil.isBlank(captcha.getJigsawImageBase64())
  80 + || StrUtil.isBlank(captcha.getOriginalImageBase64())) {
78 81 return ResponseModel.errorMsg(RepCodeEnum.API_CAPTCHA_ERROR);
79 82 }
80 83 return ResponseModel.successData(captcha);
... ... @@ -82,10 +85,10 @@ public class BlockPuzzleCaptchaServiceImpl extends AbstractCaptchaService {
82 85  
83 86 @Override
84 87 public ResponseModel check(CaptchaVO captchaVO) {
85   - ResponseModel r = super.check(captchaVO);
86   - if(!validatedReq(r)){
87   - return r;
88   - }
  88 + ResponseModel r = super.check(captchaVO);
  89 + if (!validatedReq(r)) {
  90 + return r;
  91 + }
89 92 //取坐标信息
90 93 String codeKey = String.format(REDIS_CAPTCHA_KEY, captchaVO.getToken());
91 94 if (!CaptchaServiceFactory.getCache(cacheType).exists(codeKey)) {
... ... @@ -103,7 +106,7 @@ public class BlockPuzzleCaptchaServiceImpl extends AbstractCaptchaService {
103 106 pointJson = decrypt(captchaVO.getPointJson(), point.getSecretKey());
104 107 point1 = JsonUtil.parseObject(pointJson, PointVO.class);
105 108 } catch (Exception e) {
106   - logger.error("验证码坐标解析失败", e);
  109 + log.error("验证码坐标解析失败", e);
107 110 afterValidateFail(captchaVO);
108 111 return ResponseModel.errorMsg(e.getMessage());
109 112 }
... ... @@ -119,7 +122,7 @@ public class BlockPuzzleCaptchaServiceImpl extends AbstractCaptchaService {
119 122 try {
120 123 value = AESUtil.aesEncrypt(captchaVO.getToken().concat("---").concat(pointJson), secretKey);
121 124 } catch (Exception e) {
122   - logger.error("AES加密失败", e);
  125 + log.error("AES加密失败", e);
123 126 afterValidateFail(captchaVO);
124 127 return ResponseModel.errorMsg(e.getMessage());
125 128 }
... ... @@ -132,10 +135,10 @@ public class BlockPuzzleCaptchaServiceImpl extends AbstractCaptchaService {
132 135  
133 136 @Override
134 137 public ResponseModel verification(CaptchaVO captchaVO) {
135   - ResponseModel r = super.verification(captchaVO);
136   - if(!validatedReq(r)){
137   - return r;
138   - }
  138 + ResponseModel r = super.verification(captchaVO);
  139 + if (!validatedReq(r)) {
  140 + return r;
  141 + }
139 142 try {
140 143 String codeKey = String.format(REDIS_SECOND_CAPTCHA_KEY, captchaVO.getCaptchaVerification());
141 144 if (!CaptchaServiceFactory.getCache(cacheType).exists(codeKey)) {
... ... @@ -144,7 +147,7 @@ public class BlockPuzzleCaptchaServiceImpl extends AbstractCaptchaService {
144 147 //二次校验取值后,即刻失效
145 148 CaptchaServiceFactory.getCache(cacheType).delete(codeKey);
146 149 } catch (Exception e) {
147   - logger.error("验证码坐标解析失败", e);
  150 + log.error("验证码坐标解析失败", e);
148 151 return ResponseModel.errorMsg(e.getMessage());
149 152 }
150 153 return ResponseModel.success();
... ... @@ -234,7 +237,7 @@ public class BlockPuzzleCaptchaServiceImpl extends AbstractCaptchaService {
234 237 //将坐标信息存入redis中
235 238 String codeKey = String.format(REDIS_CAPTCHA_KEY, dataVO.getToken());
236 239 CaptchaServiceFactory.getCache(cacheType).set(codeKey, JsonUtil.toJSONString(point), EXPIRESIN_SECONDS);
237   - logger.debug("token:{},point:{}", dataVO.getToken(), JsonUtil.toJSONString(point));
  240 + log.debug("token:{},point:{}", dataVO.getToken(), JsonUtil.toJSONString(point));
238 241 return dataVO;
239 242 } catch (Exception e) {
240 243 e.printStackTrace();
... ...
yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/service/impl/CaptchaCacheServiceMemImpl.java
... ... @@ -3,12 +3,15 @@ package com.anji.captcha.service.impl;
3 3 import com.anji.captcha.service.CaptchaCacheService;
4 4 import com.anji.captcha.util.CacheUtil;
5 5  
  6 +import java.util.Objects;
  7 +
6 8 /**
7 9 * 对于分布式部署的应用,我们建议应用自己实现CaptchaCacheService,比如用Redis,参考service/spring-boot代码示例。
8 10 * 如果应用是单点的,也没有使用redis,那默认使用内存。
9 11 * 内存缓存只适合单节点部署的应用,否则验证码生产与验证在节点之间信息不同步,导致失败。
10   - * @Title: 默认使用内存当缓存
  12 + *
11 13 * @author lide1202@hotmail.com
  14 + * @Title: 默认使用内存当缓存
12 15 * @date 2020-05-12
13 16 */
14 17 public class CaptchaCacheServiceMemImpl implements CaptchaCacheService {
... ... @@ -33,14 +36,14 @@ public class CaptchaCacheServiceMemImpl implements CaptchaCacheService {
33 36 return CacheUtil.get(key);
34 37 }
35 38  
36   - @Override
37   - public Long increment(String key, long val) {
38   - Long ret = Long.valueOf(CacheUtil.get(key))+val;
39   - CacheUtil.set(key,ret+"",0);
40   - return ret;
41   - }
  39 + @Override
  40 + public Long increment(String key, long val) {
  41 + Long ret = Long.parseLong(Objects.requireNonNull(CacheUtil.get(key))) + val;
  42 + CacheUtil.set(key, ret + "", 0);
  43 + return ret;
  44 + }
42 45  
43   - @Override
  46 + @Override
44 47 public String type() {
45 48 return "local";
46 49 }
... ...
yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/service/impl/CaptchaServiceFactory.java
... ... @@ -3,8 +3,7 @@ package com.anji.captcha.service.impl;
3 3 import com.anji.captcha.model.common.Const;
4 4 import com.anji.captcha.service.CaptchaCacheService;
5 5 import com.anji.captcha.service.CaptchaService;
6   -import org.slf4j.Logger;
7   -import org.slf4j.LoggerFactory;
  6 +import lombok.extern.slf4j.Slf4j;
8 7  
9 8 import java.util.HashMap;
10 9 import java.util.Map;
... ... @@ -14,10 +13,9 @@ import java.util.ServiceLoader;
14 13 /**
15 14 * Created by raodeming on 2020/5/26.
16 15 */
  16 +@Slf4j
17 17 public class CaptchaServiceFactory {
18 18  
19   - private static Logger logger = LoggerFactory.getLogger(CaptchaServiceFactory.class);
20   -
21 19 public static CaptchaService getInstance(Properties config) {
22 20 //先把所有CaptchaService初始化,通过init方法,实例字体等,add by lide1202@hotmail.com
23 21 /*try{
... ... @@ -41,20 +39,20 @@ public class CaptchaServiceFactory {
41 39 return cacheService.get(cacheType);
42 40 }
43 41  
44   - public volatile static Map<String, CaptchaService> instances = new HashMap();
45   - public volatile static Map<String, CaptchaCacheService> cacheService = new HashMap();
  42 + public volatile static Map<String, CaptchaService> instances = new HashMap<>();
  43 + public volatile static Map<String, CaptchaCacheService> cacheService = new HashMap<>();
46 44  
47 45 static {
48 46 ServiceLoader<CaptchaCacheService> cacheServices = ServiceLoader.load(CaptchaCacheService.class);
49 47 for (CaptchaCacheService item : cacheServices) {
50 48 cacheService.put(item.type(), item);
51 49 }
52   - logger.info("supported-captchaCache-service:{}", cacheService.keySet().toString());
  50 + log.info("supported-captchaCache-service:{}", cacheService.keySet().toString());
53 51 ServiceLoader<CaptchaService> services = ServiceLoader.load(CaptchaService.class);
54 52 for (CaptchaService item : services) {
55 53 instances.put(item.captchaType(), item);
56 54 }
57 55 ;
58   - logger.info("supported-captchaTypes-service:{}", instances.keySet().toString());
  56 + log.info("supported-captchaTypes-service:{}", instances.keySet().toString());
59 57 }
60 58 }
... ...
yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/service/impl/ClickWordCaptchaServiceImpl.java
... ... @@ -6,6 +6,7 @@
6 6 */
7 7 package com.anji.captcha.service.impl;
8 8  
  9 +import cn.hutool.core.util.StrUtil;
9 10 import com.anji.captcha.model.common.CaptchaTypeEnum;
10 11 import com.anji.captcha.model.common.Const;
11 12 import com.anji.captcha.model.common.RepCodeEnum;
... ... @@ -13,6 +14,7 @@ import com.anji.captcha.model.common.ResponseModel;
13 14 import com.anji.captcha.model.vo.CaptchaVO;
14 15 import com.anji.captcha.model.vo.PointVO;
15 16 import com.anji.captcha.util.*;
  17 +import lombok.extern.slf4j.Slf4j;
16 18  
17 19 import java.awt.*;
18 20 import java.awt.geom.AffineTransform;
... ... @@ -25,6 +27,7 @@ import java.util.*;
25 27 * <p>
26 28 * Created by raodeming on 2019/12/25.
27 29 */
  30 +@Slf4j
28 31 public class ClickWordCaptchaServiceImpl extends AbstractCaptchaService {
29 32  
30 33 public static String HAN_ZI = "\u7684\u4e00\u4e86\u662f\u6211\u4e0d\u5728\u4eba\u4eec\u6709\u6765\u4ed6\u8fd9\u4e0a\u7740\u4e2a\u5730\u5230\u5927\u91cc\u8bf4\u5c31\u53bb\u5b50\u5f97\u4e5f\u548c\u90a3\u8981\u4e0b\u770b\u5929\u65f6\u8fc7\u51fa\u5c0f\u4e48\u8d77\u4f60\u90fd\u628a\u597d\u8fd8\u591a\u6ca1\u4e3a\u53c8\u53ef\u5bb6\u5b66\u53ea\u4ee5\u4e3b\u4f1a\u6837\u5e74\u60f3\u751f\u540c\u8001\u4e2d\u5341\u4ece\u81ea\u9762\u524d\u5934\u9053\u5b83\u540e\u7136\u8d70\u5f88\u50cf\u89c1\u4e24\u7528\u5979\u56fd\u52a8\u8fdb\u6210\u56de\u4ec0\u8fb9\u4f5c\u5bf9\u5f00\u800c\u5df1\u4e9b\u73b0\u5c71\u6c11\u5019\u7ecf\u53d1\u5de5\u5411\u4e8b\u547d\u7ed9\u957f\u6c34\u51e0\u4e49\u4e09\u58f0\u4e8e\u9ad8\u624b\u77e5\u7406\u773c\u5fd7\u70b9\u5fc3\u6218\u4e8c\u95ee\u4f46\u8eab\u65b9\u5b9e\u5403\u505a\u53eb\u5f53\u4f4f\u542c\u9769\u6253\u5462\u771f\u5168\u624d\u56db\u5df2\u6240\u654c\u4e4b\u6700\u5149\u4ea7\u60c5\u8def\u5206\u603b\u6761\u767d\u8bdd\u4e1c\u5e2d\u6b21\u4eb2\u5982\u88ab\u82b1\u53e3\u653e\u513f\u5e38\u6c14\u4e94\u7b2c\u4f7f\u5199\u519b\u5427\u6587\u8fd0\u518d\u679c\u600e\u5b9a\u8bb8\u5feb\u660e\u884c\u56e0\u522b\u98de\u5916\u6811\u7269\u6d3b\u90e8\u95e8\u65e0\u5f80\u8239\u671b\u65b0\u5e26\u961f\u5148\u529b\u5b8c\u5374\u7ad9\u4ee3\u5458\u673a\u66f4\u4e5d\u60a8\u6bcf\u98ce\u7ea7\u8ddf\u7b11\u554a\u5b69\u4e07\u5c11\u76f4\u610f\u591c\u6bd4\u9636\u8fde\u8f66\u91cd\u4fbf\u6597\u9a6c\u54ea\u5316\u592a\u6307\u53d8\u793e\u4f3c\u58eb\u8005\u5e72\u77f3\u6ee1\u65e5\u51b3\u767e\u539f\u62ff\u7fa4\u7a76\u5404\u516d\u672c\u601d\u89e3\u7acb\u6cb3\u6751\u516b\u96be\u65e9\u8bba\u5417\u6839\u5171\u8ba9\u76f8\u7814\u4eca\u5176\u4e66\u5750\u63a5\u5e94\u5173\u4fe1\u89c9\u6b65\u53cd\u5904\u8bb0\u5c06\u5343\u627e\u4e89\u9886\u6216\u5e08\u7ed3\u5757\u8dd1\u8c01\u8349\u8d8a\u5b57\u52a0\u811a\u7d27\u7231\u7b49\u4e60\u9635\u6015\u6708\u9752\u534a\u706b\u6cd5\u9898\u5efa\u8d76\u4f4d\u5531\u6d77\u4e03\u5973\u4efb\u4ef6\u611f\u51c6\u5f20\u56e2\u5c4b\u79bb\u8272\u8138\u7247\u79d1\u5012\u775b\u5229\u4e16\u521a\u4e14\u7531\u9001\u5207\u661f\u5bfc\u665a\u8868\u591f\u6574\u8ba4\u54cd\u96ea\u6d41\u672a\u573a\u8be5\u5e76\u5e95\u6df1\u523b\u5e73\u4f1f\u5fd9\u63d0\u786e\u8fd1\u4eae\u8f7b\u8bb2\u519c\u53e4\u9ed1\u544a\u754c\u62c9\u540d\u5440\u571f\u6e05\u9633\u7167\u529e\u53f2\u6539\u5386\u8f6c\u753b\u9020\u5634\u6b64\u6cbb\u5317\u5fc5\u670d\u96e8\u7a7f\u5185\u8bc6\u9a8c\u4f20\u4e1a\u83dc\u722c\u7761\u5174\u5f62\u91cf\u54b1\u89c2\u82e6\u4f53\u4f17\u901a\u51b2\u5408\u7834\u53cb\u5ea6\u672f\u996d\u516c\u65c1\u623f\u6781\u5357\u67aa\u8bfb\u6c99\u5c81\u7ebf\u91ce\u575a\u7a7a\u6536\u7b97\u81f3\u653f\u57ce\u52b3\u843d\u94b1\u7279\u56f4\u5f1f\u80dc\u6559\u70ed\u5c55\u5305\u6b4c\u7c7b\u6e10\u5f3a\u6570\u4e61\u547c\u6027\u97f3\u7b54\u54e5\u9645\u65e7\u795e\u5ea7\u7ae0\u5e2e\u5566\u53d7\u7cfb\u4ee4\u8df3\u975e\u4f55\u725b\u53d6\u5165\u5cb8\u6562\u6389\u5ffd\u79cd\u88c5\u9876\u6025\u6797\u505c\u606f\u53e5\u533a\u8863\u822c\u62a5\u53f6\u538b\u6162\u53d4\u80cc\u7ec6";
... ... @@ -43,27 +46,27 @@ public class ClickWordCaptchaServiceImpl extends AbstractCaptchaService {
43 46 super.init(config);
44 47 clickWordFontStr = config.getProperty(Const.CAPTCHA_FONT_TYPE, "SourceHanSansCN-Normal.otf");
45 48 try {
46   - int size = Integer.valueOf(config.getProperty(Const.CAPTCHA_FONT_SIZE,HAN_ZI_SIZE+""));
  49 + int size = Integer.parseInt(config.getProperty(Const.CAPTCHA_FONT_SIZE,HAN_ZI_SIZE+""));
47 50  
48 51 if (clickWordFontStr.toLowerCase().endsWith(".ttf")
49 52 || clickWordFontStr.toLowerCase().endsWith(".ttc")
50 53 || clickWordFontStr.toLowerCase().endsWith(".otf")) {
51 54 this.clickWordFont = Font.createFont(Font.TRUETYPE_FONT,
52   - getClass().getResourceAsStream("/fonts/" + clickWordFontStr))
  55 + Objects.requireNonNull(getClass().getResourceAsStream("/fonts/" + clickWordFontStr)))
53 56 .deriveFont(Font.BOLD, size);
54 57 } else {
55   - int style = Integer.valueOf(config.getProperty(Const.CAPTCHA_FONT_STYLE,Font.BOLD+""));
  58 + int style = Integer.parseInt(config.getProperty(Const.CAPTCHA_FONT_STYLE,Font.BOLD+""));
56 59 this.clickWordFont = new Font(clickWordFontStr, style, size);
57 60 }
58 61 } catch (Exception ex) {
59   - logger.error("load font error:{}", ex);
  62 + log.error("load font error:{}", ex);
60 63 }
61   - this.wordTotalCount = Integer.valueOf(config.getProperty(Const.CAPTCHA_WORD_COUNT,"4"));
  64 + this.wordTotalCount = Integer.parseInt(config.getProperty(Const.CAPTCHA_WORD_COUNT,"4"));
62 65 }
63 66  
64 67 @Override
65 68 public void destroy(Properties config) {
66   - logger.info("start-clear-history-data-", captchaType());
  69 + log.info("start-clear-history-data-", captchaType());
67 70 }
68 71  
69 72 @Override
... ... @@ -74,12 +77,12 @@ public class ClickWordCaptchaServiceImpl extends AbstractCaptchaService {
74 77 }
75 78 BufferedImage bufferedImage = ImageUtils.getPicClick();
76 79 if (null == bufferedImage) {
77   - logger.error("滑动底图未初始化成功,请检查路径");
  80 + log.error("滑动底图未初始化成功,请检查路径");
78 81 return ResponseModel.errorMsg(RepCodeEnum.API_CAPTCHA_BASEMAP_NULL);
79 82 }
80 83 CaptchaVO imageData = getImageData(bufferedImage);
81 84 if (imageData == null
82   - || StringUtils.isBlank(imageData.getOriginalImageBase64())) {
  85 + || StrUtil.isBlank(imageData.getOriginalImageBase64())) {
83 86 return ResponseModel.errorMsg(RepCodeEnum.API_CAPTCHA_ERROR);
84 87 }
85 88 return ResponseModel.successData(imageData);
... ... @@ -124,7 +127,7 @@ public class ClickWordCaptchaServiceImpl extends AbstractCaptchaService {
124 127 pointJson = decrypt(captchaVO.getPointJson(), point.get(0).getSecretKey());
125 128 point1 = JsonUtil.parseArray(pointJson, PointVO.class);
126 129 } catch (Exception e) {
127   - logger.error("验证码坐标解析失败", e);
  130 + log.error("验证码坐标解析失败", e);
128 131 afterValidateFail(captchaVO);
129 132 return ResponseModel.errorMsg(e.getMessage());
130 133 }
... ... @@ -143,7 +146,7 @@ public class ClickWordCaptchaServiceImpl extends AbstractCaptchaService {
143 146 try {
144 147 value = AESUtil.aesEncrypt(captchaVO.getToken().concat("---").concat(pointJson), secretKey);
145 148 } catch (Exception e) {
146   - logger.error("AES加密失败", e);
  149 + log.error("AES加密失败", e);
147 150 afterValidateFail(captchaVO);
148 151 return ResponseModel.errorMsg(e.getMessage());
149 152 }
... ... @@ -159,7 +162,7 @@ public class ClickWordCaptchaServiceImpl extends AbstractCaptchaService {
159 162 /*if (captchaVO == null) {
160 163 return RepCodeEnum.NULL_ERROR.parseError("captchaVO");
161 164 }
162   - if (StringUtils.isEmpty(captchaVO.getCaptchaVerification())) {
  165 + if (StrUtil.isEmpty(captchaVO.getCaptchaVerification())) {
163 166 return RepCodeEnum.NULL_ERROR.parseError("captchaVerification");
164 167 }*/
165 168 ResponseModel r = super.verification(captchaVO);
... ... @@ -174,7 +177,7 @@ public class ClickWordCaptchaServiceImpl extends AbstractCaptchaService {
174 177 //二次校验取值后,即刻失效
175 178 CaptchaServiceFactory.getCache(cacheType).delete(codeKey);
176 179 } catch (Exception e) {
177   - logger.error("验证码坐标解析失败", e);
  180 + log.error("验证码坐标解析失败", e);
178 181 return ResponseModel.errorMsg(e.getMessage());
179 182 }
180 183 return ResponseModel.success();
... ...
yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/service/impl/DefaultCaptchaServiceImpl.java
... ... @@ -6,17 +6,19 @@
6 6 */
7 7 package com.anji.captcha.service.impl;
8 8  
  9 +import cn.hutool.core.util.StrUtil;
9 10 import com.anji.captcha.model.common.RepCodeEnum;
10 11 import com.anji.captcha.model.common.ResponseModel;
11 12 import com.anji.captcha.model.vo.CaptchaVO;
12 13 import com.anji.captcha.service.CaptchaService;
13   -import com.anji.captcha.util.StringUtils;
  14 +import lombok.extern.slf4j.Slf4j;
14 15  
15 16 import java.util.Properties;
16 17  
17 18 /**
18 19 * Created by raodeming on 2019/12/25.
19 20 */
  21 +@Slf4j
20 22 public class DefaultCaptchaServiceImpl extends AbstractCaptchaService{
21 23  
22 24 @Override
... ... @@ -53,7 +55,7 @@ public class DefaultCaptchaServiceImpl extends AbstractCaptchaService{
53 55 if (captchaVO == null) {
54 56 return RepCodeEnum.NULL_ERROR.parseError("captchaVO");
55 57 }
56   - if (StringUtils.isEmpty(captchaVO.getCaptchaType())) {
  58 + if (StrUtil.isEmpty(captchaVO.getCaptchaType())) {
57 59 return RepCodeEnum.NULL_ERROR.parseError("类型");
58 60 }
59 61 return getService(captchaVO.getCaptchaType()).get(captchaVO);
... ... @@ -64,10 +66,10 @@ public class DefaultCaptchaServiceImpl extends AbstractCaptchaService{
64 66 if (captchaVO == null) {
65 67 return RepCodeEnum.NULL_ERROR.parseError("captchaVO");
66 68 }
67   - if (StringUtils.isEmpty(captchaVO.getCaptchaType())) {
  69 + if (StrUtil.isEmpty(captchaVO.getCaptchaType())) {
68 70 return RepCodeEnum.NULL_ERROR.parseError("类型");
69 71 }
70   - if (StringUtils.isEmpty(captchaVO.getToken())) {
  72 + if (StrUtil.isEmpty(captchaVO.getToken())) {
71 73 return RepCodeEnum.NULL_ERROR.parseError("token");
72 74 }
73 75 return getService(captchaVO.getCaptchaType()).check(captchaVO);
... ... @@ -78,7 +80,7 @@ public class DefaultCaptchaServiceImpl extends AbstractCaptchaService{
78 80 if (captchaVO == null) {
79 81 return RepCodeEnum.NULL_ERROR.parseError("captchaVO");
80 82 }
81   - if (StringUtils.isEmpty(captchaVO.getCaptchaVerification())) {
  83 + if (StrUtil.isEmpty(captchaVO.getCaptchaVerification())) {
82 84 return RepCodeEnum.NULL_ERROR.parseError("二次校验参数");
83 85 }
84 86 try {
... ... @@ -89,7 +91,7 @@ public class DefaultCaptchaServiceImpl extends AbstractCaptchaService{
89 91 //二次校验取值后,即刻失效
90 92 CaptchaServiceFactory.getCache(cacheType).delete(codeKey);
91 93 } catch (Exception e) {
92   - logger.error("验证码坐标解析失败", e);
  94 + log.error("验证码坐标解析失败", e);
93 95 return ResponseModel.errorMsg(e.getMessage());
94 96 }
95 97 return ResponseModel.success();
... ...
yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/service/impl/FrequencyLimitHandler.java
1 1 package com.anji.captcha.service.impl;
2 2  
  3 +import cn.hutool.core.util.StrUtil;
3 4 import com.anji.captcha.model.common.Const;
4 5 import com.anji.captcha.model.common.RepCodeEnum;
5 6 import com.anji.captcha.model.common.ResponseModel;
6 7 import com.anji.captcha.model.vo.CaptchaVO;
7 8 import com.anji.captcha.service.CaptchaCacheService;
8   -import com.anji.captcha.util.StringUtils;
9 9  
10 10 import java.util.Objects;
11 11 import java.util.Properties;
... ... @@ -66,15 +66,15 @@ public interface FrequencyLimitHandler {
66 66 }
67 67  
68 68 private String getClientCId(CaptchaVO input, String type) {
69   - return String.format(LIMIT_KEY ,type,input.getClientUid());
  69 + return String.format(LIMIT_KEY, type, input.getClientUid());
70 70 }
71 71  
72 72 @Override
73 73 public ResponseModel validateGet(CaptchaVO d) {
74   - // 无客户端身份标识,不限制
75   - if(StringUtils.isEmpty(d.getClientUid())){
76   - return null;
77   - }
  74 + // 无客户端身份标识,不限制
  75 + if (StrUtil.isEmpty(d.getClientUid())) {
  76 + return null;
  77 + }
78 78 String getKey = getClientCId(d, "GET");
79 79 String lockKey = getClientCId(d, "LOCK");
80 80 // 失败次数过多,锁定
... ... @@ -88,7 +88,7 @@ public interface FrequencyLimitHandler {
88 88 }
89 89 cacheService.increment(getKey, 1);
90 90 // 1分钟内请求次数过多
91   - if (Long.valueOf(getCnts) > Long.parseLong(config.getProperty(Const.REQ_GET_MINUTE_LIMIT, "120"))) {
  91 + if (Long.parseLong(getCnts) > Long.parseLong(config.getProperty(Const.REQ_GET_MINUTE_LIMIT, "120"))) {
92 92 return ResponseModel.errorMsg(RepCodeEnum.API_REQ_LIMIT_GET_ERROR);
93 93 }
94 94  
... ... @@ -100,9 +100,9 @@ public interface FrequencyLimitHandler {
100 100 return null;
101 101 }
102 102 // 1分钟内失败5次
103   - if (Long.valueOf(failCnts) > Long.parseLong(config.getProperty(Const.REQ_GET_LOCK_LIMIT, "5"))) {
  103 + if (Long.parseLong(failCnts) > Long.parseLong(config.getProperty(Const.REQ_GET_LOCK_LIMIT, "5"))) {
104 104 // get接口锁定5分钟
105   - cacheService.set(lockKey, "1", Long.valueOf(config.getProperty(Const.REQ_GET_LOCK_SECONDS, "300")));
  105 + cacheService.set(lockKey, "1", Long.parseLong(config.getProperty(Const.REQ_GET_LOCK_SECONDS, "300")));
106 106 return ResponseModel.errorMsg(RepCodeEnum.API_REQ_LOCK_GET_ERROR);
107 107 }
108 108 return null;
... ... @@ -110,10 +110,10 @@ public interface FrequencyLimitHandler {
110 110  
111 111 @Override
112 112 public ResponseModel validateCheck(CaptchaVO d) {
113   - // 无客户端身份标识,不限制
114   - if(StringUtils.isEmpty(d.getClientUid())){
115   - return null;
116   - }
  113 + // 无客户端身份标识,不限制
  114 + if (StrUtil.isEmpty(d.getClientUid())) {
  115 + return null;
  116 + }
117 117 /*String getKey = getClientCId(d, "GET");
118 118 if(Objects.isNull(cacheService.get(getKey))){
119 119 return ResponseModel.errorMsg(RepCodeEnum.API_REQ_INVALID);
... ... @@ -125,7 +125,7 @@ public interface FrequencyLimitHandler {
125 125 v = "1";
126 126 }
127 127 cacheService.increment(key, 1);
128   - if (Long.valueOf(v) > Long.valueOf(config.getProperty(Const.REQ_CHECK_MINUTE_LIMIT, "600"))) {
  128 + if (Long.parseLong(v) > Long.parseLong(config.getProperty(Const.REQ_CHECK_MINUTE_LIMIT, "600"))) {
129 129 return ResponseModel.errorMsg(RepCodeEnum.API_REQ_LIMIT_CHECK_ERROR);
130 130 }
131 131 return null;
... ... @@ -144,7 +144,7 @@ public interface FrequencyLimitHandler {
144 144 v = "1";
145 145 }
146 146 cacheService.increment(key, 1);
147   - if (Long.valueOf(v) > Long.valueOf(config.getProperty(Const.REQ_VALIDATE_MINUTE_LIMIT, "600"))) {
  147 + if (Long.parseLong(v) > Long.parseLong(config.getProperty(Const.REQ_VALIDATE_MINUTE_LIMIT, "600"))) {
148 148 return ResponseModel.errorMsg(RepCodeEnum.API_REQ_LIMIT_VERIFY_ERROR);
149 149 }
150 150 return null;
... ...
yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/util/AESUtil.java
... ... @@ -7,10 +7,13 @@
7 7 package com.anji.captcha.util;
8 8  
9 9  
  10 +import cn.hutool.core.util.StrUtil;
  11 +
10 12 import javax.crypto.Cipher;
11 13 import javax.crypto.KeyGenerator;
12 14 import javax.crypto.spec.SecretKeySpec;
13 15 import java.math.BigInteger;
  16 +import java.nio.charset.StandardCharsets;
14 17 import java.util.Base64;
15 18  
16 19  
... ... @@ -20,6 +23,7 @@ public class AESUtil {
20 23  
21 24 /**
22 25 * 获取随机key
  26 + *
23 27 * @return
24 28 */
25 29 public static String getKey() {
... ... @@ -29,39 +33,43 @@ public class AESUtil {
29 33  
30 34 /**
31 35 * 将byte[]转为各种进制的字符串
  36 + *
32 37 * @param bytes byte[]
33 38 * @param radix 可以转换进制的范围,从Character.MIN_RADIX到Character.MAX_RADIX,超出范围后变为10进制
34 39 * @return 转换后的字符串
35 40 */
36   - public static String binary(byte[] bytes, int radix){
  41 + public static String binary(byte[] bytes, int radix) {
37 42 return new BigInteger(1, bytes).toString(radix);// 这里的1代表正数
38 43 }
39 44  
40 45 /**
41 46 * base 64 encode
  47 + *
42 48 * @param bytes 待编码的byte[]
43 49 * @return 编码后的base 64 code
44 50 */
45   - public static String base64Encode(byte[] bytes){
  51 + public static String base64Encode(byte[] bytes) {
46 52 //return Base64.encodeBase64String(bytes);
47 53 return Base64.getEncoder().encodeToString(bytes);
48 54 }
49 55  
50 56 /**
51 57 * base 64 decode
  58 + *
52 59 * @param base64Code 待解码的base 64 code
53 60 * @return 解码后的byte[]
54 61 * @throws Exception
55 62 */
56   - public static byte[] base64Decode(String base64Code) throws Exception{
  63 + public static byte[] base64Decode(String base64Code) throws Exception {
57 64 Base64.Decoder decoder = Base64.getDecoder();
58   - return StringUtils.isEmpty(base64Code) ? null : decoder.decode(base64Code);
  65 + return StrUtil.isEmpty(base64Code) ? null : decoder.decode(base64Code);
59 66 }
60 67  
61 68  
62 69 /**
63 70 * AES加密
64   - * @param content 待加密的内容
  71 + *
  72 + * @param content 待加密的内容
65 73 * @param encryptKey 加密密钥
66 74 * @return 加密后的byte[]
67 75 * @throws Exception
... ... @@ -72,19 +80,20 @@ public class AESUtil {
72 80 Cipher cipher = Cipher.getInstance(ALGORITHMSTR);
73 81 cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(encryptKey.getBytes(), "AES"));
74 82  
75   - return cipher.doFinal(content.getBytes("utf-8"));
  83 + return cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
76 84 }
77 85  
78 86  
79 87 /**
80 88 * AES加密为base 64 code
81   - * @param content 待加密的内容
  89 + *
  90 + * @param content 待加密的内容
82 91 * @param encryptKey 加密密钥
83 92 * @return 加密后的base 64 code
84 93 * @throws Exception
85 94 */
86 95 public static String aesEncrypt(String content, String encryptKey) throws Exception {
87   - if (StringUtils.isBlank(encryptKey)) {
  96 + if (StrUtil.isBlank(encryptKey)) {
88 97 return content;
89 98 }
90 99 return base64Encode(aesEncryptToBytes(content, encryptKey));
... ... @@ -92,8 +101,9 @@ public class AESUtil {
92 101  
93 102 /**
94 103 * AES解密
  104 + *
95 105 * @param encryptBytes 待解密的byte[]
96   - * @param decryptKey 解密密钥
  106 + * @param decryptKey 解密密钥
97 107 * @return 解密后的String
98 108 * @throws Exception
99 109 */
... ... @@ -110,16 +120,17 @@ public class AESUtil {
110 120  
111 121 /**
112 122 * 将base 64 code AES解密
  123 + *
113 124 * @param encryptStr 待解密的base 64 code
114 125 * @param decryptKey 解密密钥
115 126 * @return 解密后的string
116 127 * @throws Exception
117 128 */
118 129 public static String aesDecrypt(String encryptStr, String decryptKey) throws Exception {
119   - if (StringUtils.isBlank(decryptKey)) {
  130 + if (StrUtil.isBlank(decryptKey)) {
120 131 return encryptStr;
121 132 }
122   - return StringUtils.isEmpty(encryptStr) ? null : aesDecryptByBytes(base64Decode(encryptStr), decryptKey);
  133 + return StrUtil.isEmpty(encryptStr) ? null : aesDecryptByBytes(base64Decode(encryptStr), decryptKey);
123 134 }
124 135  
125 136 /**
... ...
yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/util/Base64Utils.java deleted
1   -//
2   -// Source code recreated from a .class file by IntelliJ IDEA
3   -// (powered by Fernflower decompiler)
4   -//
5   -
6   -package com.anji.captcha.util;
7   -
8   -import java.nio.charset.Charset;
9   -import java.nio.charset.StandardCharsets;
10   -import java.util.Base64;
11   -
12   -public abstract class Base64Utils {
13   - private static final Charset DEFAULT_CHARSET;
14   -
15   - public Base64Utils() {
16   - }
17   -
18   - public static byte[] encode(byte[] src) {
19   - return src.length == 0 ? src : Base64.getEncoder().encode(src);
20   - }
21   -
22   - public static byte[] decode(byte[] src) {
23   - return src.length == 0 ? src : Base64.getDecoder().decode(src);
24   - }
25   -
26   - public static byte[] encodeUrlSafe(byte[] src) {
27   - return src.length == 0 ? src : Base64.getUrlEncoder().encode(src);
28   - }
29   -
30   - public static byte[] decodeUrlSafe(byte[] src) {
31   - return src.length == 0 ? src : Base64.getUrlDecoder().decode(src);
32   - }
33   -
34   - public static String encodeToString(byte[] src) {
35   - return src.length == 0 ? "" : new String(encode(src), DEFAULT_CHARSET);
36   - }
37   -
38   - public static byte[] decodeFromString(String src) {
39   - return src.isEmpty() ? new byte[0] : decode(src.getBytes(DEFAULT_CHARSET));
40   - }
41   -
42   - public static String encodeToUrlSafeString(byte[] src) {
43   - return new String(encodeUrlSafe(src), DEFAULT_CHARSET);
44   - }
45   -
46   - public static byte[] decodeFromUrlSafeString(String src) {
47   - return decodeUrlSafe(src.getBytes(DEFAULT_CHARSET));
48   - }
49   -
50   - static {
51   - DEFAULT_CHARSET = StandardCharsets.UTF_8;
52   - }
53   -}
yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/util/CacheUtil.java
... ... @@ -24,8 +24,9 @@ public final class CacheUtil {
24 24  
25 25 /**
26 26 * 初始化
  27 + *
27 28 * @param cacheMaxNumber 缓存最大个数
28   - * @param second 定时任务 秒执行清除过期缓存
  29 + * @param second 定时任务 秒执行清除过期缓存
29 30 */
30 31 public static void init(int cacheMaxNumber, long second) {
31 32 CACHE_MAX_NUMBER = cacheMaxNumber;
... ... @@ -37,27 +38,25 @@ public final class CacheUtil {
37 38 refresh();
38 39 }
39 40 }, 0, second * 1000);*/
40   - scheduledExecutor = new ScheduledThreadPoolExecutor(1, new ThreadFactory() {
41   - @Override
42   - public Thread newThread(Runnable r) {
43   - return new Thread(r,"thd-captcha-cache-clean");
44   - }
45   - },new ThreadPoolExecutor.CallerRunsPolicy());
  41 + ScheduledExecutorService scheduledExecutor = new ScheduledThreadPoolExecutor(1, new ThreadFactory() {
  42 + @Override
  43 + public Thread newThread(Runnable r) {
  44 + return new Thread(r, "thd-captcha-cache-clean");
  45 + }
  46 + }, new ThreadPoolExecutor.CallerRunsPolicy());
46 47 scheduledExecutor.scheduleAtFixedRate(new Runnable() {
47   - @Override
48   - public void run() {
49   - refresh();
50   - }
51   - },10,second,TimeUnit.SECONDS);
  48 + @Override
  49 + public void run() {
  50 + refresh();
  51 + }
  52 + }, 10, second, TimeUnit.SECONDS);
52 53 }
53 54 }
54 55  
55   - private static ScheduledExecutorService scheduledExecutor;
56   -
57 56 /**
58 57 * 缓存刷新,清除过期数据
59 58 */
60   - public static void refresh(){
  59 + public static void refresh() {
61 60 logger.debug("local缓存刷新,清除过期数据");
62 61 for (String key : CACHE_MAP.keySet()) {
63 62 exists(key);
... ... @@ -65,24 +64,24 @@ public final class CacheUtil {
65 64 }
66 65  
67 66  
68   - public static void set(String key, String value, long expiresInSeconds){
  67 + public static void set(String key, String value, long expiresInSeconds) {
69 68 //设置阈值,达到即clear缓存
70 69 if (CACHE_MAP.size() > CACHE_MAX_NUMBER * 2) {
71 70 logger.info("CACHE_MAP达到阈值,clear map");
72 71 clear();
73 72 }
74 73 CACHE_MAP.put(key, value);
75   - if(expiresInSeconds >0) {
76   - CACHE_MAP.put(key + "_HoldTime", System.currentTimeMillis() + expiresInSeconds * 1000);//缓存失效时间
77   - }
  74 + if (expiresInSeconds > 0) {
  75 + CACHE_MAP.put(key + "_HoldTime", System.currentTimeMillis() + expiresInSeconds * 1000);//缓存失效时间
  76 + }
78 77 }
79 78  
80   - public static void delete(String key){
  79 + public static void delete(String key) {
81 80 CACHE_MAP.remove(key);
82 81 CACHE_MAP.remove(key + "_HoldTime");
83 82 }
84 83  
85   - public static boolean exists(String key){
  84 + public static boolean exists(String key) {
86 85 Long cacheHoldTime = (Long) CACHE_MAP.get(key + "_HoldTime");
87 86 if (cacheHoldTime == null || cacheHoldTime == 0L) {
88 87 return false;
... ... @@ -95,9 +94,9 @@ public final class CacheUtil {
95 94 }
96 95  
97 96  
98   - public static String get(String key){
  97 + public static String get(String key) {
99 98 if (exists(key)) {
100   - return (String)CACHE_MAP.get(key);
  99 + return (String) CACHE_MAP.get(key);
101 100 }
102 101 return null;
103 102 }
... ...
yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/util/FileCopyUtils.java
... ... @@ -18,7 +18,7 @@ public abstract class FileCopyUtils {
18 18 }
19 19  
20 20 public static void copy(byte[] in, File out) throws IOException {
21   - copy((InputStream)(new ByteArrayInputStream(in)), (OutputStream)Files.newOutputStream(out.toPath()));
  21 + copy((InputStream) (new ByteArrayInputStream(in)), (OutputStream) Files.newOutputStream(out.toPath()));
22 22 }
23 23  
24 24 public static byte[] copyToByteArray(File in) throws IOException {
... ... @@ -63,7 +63,7 @@ public abstract class FileCopyUtils {
63 63 return new byte[0];
64 64 } else {
65 65 ByteArrayOutputStream out = new ByteArrayOutputStream(4096);
66   - copy((InputStream)in, (OutputStream)out);
  66 + copy((InputStream) in, (OutputStream) out);
67 67 return out.toByteArray();
68 68 }
69 69 }
... ... @@ -74,13 +74,12 @@ public abstract class FileCopyUtils {
74 74 char[] buffer = new char[4096];
75 75  
76 76 int bytesRead;
77   - for(boolean var4 = true; (bytesRead = in.read(buffer)) != -1; byteCount += bytesRead) {
  77 + for (boolean var4 = true; (bytesRead = in.read(buffer)) != -1; byteCount += bytesRead) {
78 78 out.write(buffer, 0, bytesRead);
79 79 }
80 80  
81 81 out.flush();
82   - int var5 = byteCount;
83   - return var5;
  82 + return byteCount;
84 83 } finally {
85 84 try {
86 85 in.close();
... ... @@ -113,7 +112,7 @@ public abstract class FileCopyUtils {
113 112 return "";
114 113 } else {
115 114 StringWriter out = new StringWriter();
116   - copy((Reader)in, (Writer)out);
  115 + copy((Reader) in, (Writer) out);
117 116 return out.toString();
118 117 }
119 118 }
... ...
yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/util/ImageUtils.java
... ... @@ -6,9 +6,10 @@
6 6 */
7 7 package com.anji.captcha.util;
8 8  
  9 +import cn.hutool.core.util.StrUtil;
9 10 import com.anji.captcha.model.common.CaptchaBaseMapEnum;
10   -import org.slf4j.Logger;
11   -import org.slf4j.LoggerFactory;
  11 +import lombok.extern.slf4j.Slf4j;
  12 +import org.springframework.util.Base64Utils;
12 13  
13 14 import javax.imageio.ImageIO;
14 15 import java.awt.image.BufferedImage;
... ... @@ -19,9 +20,8 @@ import java.util.HashMap;
19 20 import java.util.Map;
20 21 import java.util.concurrent.ConcurrentHashMap;
21 22  
22   -
  23 +@Slf4j
23 24 public class ImageUtils {
24   - private static Logger logger = LoggerFactory.getLogger(ImageUtils.class);
25 25 private static Map<String, String> originalCacheMap = new ConcurrentHashMap(); //滑块底图
26 26 private static Map<String, String> slidingBlockCacheMap = new ConcurrentHashMap(); //滑块
27 27 private static Map<String, String> picClickCacheMap = new ConcurrentHashMap(); //点选文字
... ... @@ -29,7 +29,7 @@ public class ImageUtils {
29 29  
30 30 public static void cacheImage(String captchaOriginalPathJigsaw, String captchaOriginalPathClick) {
31 31 //滑动拼图
32   - if (StringUtils.isBlank(captchaOriginalPathJigsaw)) {
  32 + if (StrUtil.isBlank(captchaOriginalPathJigsaw)) {
33 33 originalCacheMap.putAll(getResourcesImagesFile("defaultImages/jigsaw/original"));
34 34 slidingBlockCacheMap.putAll(getResourcesImagesFile("defaultImages/jigsaw/slidingBlock"));
35 35 } else {
... ... @@ -37,7 +37,7 @@ public class ImageUtils {
37 37 slidingBlockCacheMap.putAll(getImagesFile(captchaOriginalPathJigsaw + File.separator + "slidingBlock"));
38 38 }
39 39 //点选文字
40   - if (StringUtils.isBlank(captchaOriginalPathClick)) {
  40 + if (StrUtil.isBlank(captchaOriginalPathClick)) {
41 41 picClickCacheMap.putAll(getResourcesImagesFile("defaultImages/pic-click"));
42 42 } else {
43 43 picClickCacheMap.putAll(getImagesFile(captchaOriginalPathClick));
... ... @@ -45,7 +45,7 @@ public class ImageUtils {
45 45 fileNameMap.put(CaptchaBaseMapEnum.ORIGINAL.getCodeValue(), originalCacheMap.keySet().toArray(new String[0]));
46 46 fileNameMap.put(CaptchaBaseMapEnum.SLIDING_BLOCK.getCodeValue(), slidingBlockCacheMap.keySet().toArray(new String[0]));
47 47 fileNameMap.put(CaptchaBaseMapEnum.PIC_CLICK.getCodeValue(), picClickCacheMap.keySet().toArray(new String[0]));
48   - logger.info("初始化底图:{}", JsonUtil.toJSONString(fileNameMap));
  48 + log.info("初始化底图:{}", JsonUtil.toJSONString(fileNameMap));
49 49 }
50 50  
51 51 public static void cacheBootImage(Map<String, String> originalMap, Map<String, String> slidingBlockMap, Map<String, String> picClickMap) {
... ... @@ -55,7 +55,7 @@ public class ImageUtils {
55 55 fileNameMap.put(CaptchaBaseMapEnum.ORIGINAL.getCodeValue(), originalCacheMap.keySet().toArray(new String[0]));
56 56 fileNameMap.put(CaptchaBaseMapEnum.SLIDING_BLOCK.getCodeValue(), slidingBlockCacheMap.keySet().toArray(new String[0]));
57 57 fileNameMap.put(CaptchaBaseMapEnum.PIC_CLICK.getCodeValue(), picClickCacheMap.keySet().toArray(new String[0]));
58   - logger.info("自定义resource底图:{}", JsonUtil.toJSONString(fileNameMap));
  58 + log.info("自定义resource底图:{}", JsonUtil.toJSONString(fileNameMap));
59 59 }
60 60  
61 61  
... ... @@ -75,8 +75,7 @@ public class ImageUtils {
75 75 return null;
76 76 }
77 77 Integer randomInt = RandomUtils.getRandomInt(0, strings.length);
78   - String s = slidingBlockCacheMap.get(strings[randomInt]);
79   - return s;
  78 + return slidingBlockCacheMap.get(strings[randomInt]);
80 79 }
81 80  
82 81 public static BufferedImage getPicClick() {
... ... @@ -160,8 +159,6 @@ public class ImageUtils {
160 159 byte[] bytes = FileCopyUtils.copyToByteArray(fileInputStream);
161 160 String string = Base64Utils.encodeToString(bytes);
162 161 imgMap.put(item.getName(), string);
163   - } catch (FileNotFoundException e) {
164   - e.printStackTrace();
165 162 } catch (IOException e) {
166 163 e.printStackTrace();
167 164 }
... ...
yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/util/JsonUtil.java
1 1 package com.anji.captcha.util;
2 2  
3 3 import com.anji.captcha.model.vo.PointVO;
4   -import org.slf4j.Logger;
5   -import org.slf4j.LoggerFactory;
  4 +import lombok.extern.slf4j.Slf4j;
6 5  
7 6 import java.util.ArrayList;
8 7 import java.util.List;
... ... @@ -12,63 +11,63 @@ import java.util.Map;
12 11 * 替换掉fastjson,自定义实现相关方法
13 12 * note: 该实现不具有通用性,仅用于本项目。
14 13 *
15   - *@author WongBin
16   - *@date 2021/1/8
  14 + * @author WongBin
  15 + * @date 2021/1/8
17 16 */
  17 +@Slf4j
18 18 public class JsonUtil {
19   - private static Logger logger = LoggerFactory.getLogger(JsonUtil.class);
20   - public static List<PointVO> parseArray(String text, Class<PointVO> clazz) {
21   - if (text == null) {
22   - return null;
23   - } else {
24   - String[] arr = text.replaceFirst("\\[","")
25   - .replaceFirst("\\]","").split("\\}");
26   - List<PointVO> ret = new ArrayList<>(arr.length);
27   - for (String s : arr) {
28   - ret.add(parseObject(s,PointVO.class));
29   - }
30   - return ret;
31   - }
32   - }
  19 + public static List<PointVO> parseArray(String text, Class<PointVO> clazz) {
  20 + if (text == null) {
  21 + return null;
  22 + } else {
  23 + String[] arr = text.replaceFirst("\\[", "")
  24 + .replaceFirst("\\]", "").split("\\}");
  25 + List<PointVO> ret = new ArrayList<>(arr.length);
  26 + for (String s : arr) {
  27 + ret.add(parseObject(s, PointVO.class));
  28 + }
  29 + return ret;
  30 + }
  31 + }
33 32  
34   - public static PointVO parseObject(String text, Class<PointVO> clazz) {
35   - if(text == null) {
36   - return null;
37   - }
  33 + public static PointVO parseObject(String text, Class<PointVO> clazz) {
  34 + if (text == null) {
  35 + return null;
  36 + }
38 37 /*if(!clazz.isAssignableFrom(PointVO.class)) {
39 38 throw new UnsupportedOperationException("不支持的输入类型:"
40 39 + clazz.getSimpleName());
41 40 }*/
42   - try {
43   - PointVO ret = clazz.newInstance();
44   - return ret.parse(text);
45   - }catch (Exception ex){
46   - logger.error("json解析异常", ex);
  41 + try {
  42 + PointVO ret = clazz.newInstance();
  43 + return ret.parse(text);
  44 + } catch (Exception ex) {
  45 + log.error("json解析异常", ex);
47 46  
48   - }
49   - return null;
50   - }
  47 + }
  48 + return null;
  49 + }
51 50  
52   - public static String toJSONString(Object object) {
53   - if(object == null) {
54   - return "{}";
55   - }
56   - if(object instanceof PointVO){
57   - PointVO t = (PointVO)object;
58   - return t.toJsonString();
59   - }
60   - if(object instanceof List){
61   - List<PointVO> list = (List<PointVO>)object;
62   - StringBuilder buf = new StringBuilder("[");
63   - list.stream().forEach(t->{
64   - buf.append(t.toJsonString()).append(",");
65   - });
66   - return buf.deleteCharAt(buf.lastIndexOf(",")).append("]").toString();
67   - }
68   - if(object instanceof Map){
69   - return ((Map)object).entrySet().toString();
70   - }
71   - throw new UnsupportedOperationException("不支持的输入类型:"
72   - +object.getClass().getSimpleName());
73   - }
  51 + public static String toJSONString(Object object) {
  52 + if (object == null) {
  53 + return "{}";
  54 + }
  55 + if (object instanceof PointVO) {
  56 + PointVO t = (PointVO) object;
  57 + return t.toJsonString();
  58 + }
  59 + if (object instanceof List) {
  60 + List<PointVO> list = (List<PointVO>) object;
  61 + StringBuilder buf = new StringBuilder("[");
  62 + list.forEach(t -> {
  63 + buf.append(t.toJsonString()).append(",");
  64 + });
  65 + return buf.deleteCharAt(buf.lastIndexOf(",")).append("]").toString();
  66 + }
  67 + if (object instanceof Map) {
  68 + return ((Map) object).entrySet().toString();
  69 + }
  70 + throw new UnsupportedOperationException("不支持的输入类型:"
  71 + + object.getClass().getSimpleName());
  72 + }
74 73 }
... ...
yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/util/MD5Util.java
1 1 package com.anji.captcha.util;
2 2  
  3 +import java.nio.charset.StandardCharsets;
3 4 import java.security.MessageDigest;
4 5  
5 6 /**
... ... @@ -8,17 +9,18 @@ import java.security.MessageDigest;
8 9 public abstract class MD5Util {
9 10 /**
10 11 * 获取指定字符串的md5值
  12 + *
11 13 * @param dataStr 明文
12 14 * @return String
13 15 */
14 16 public static String md5(String dataStr) {
15 17 try {
16 18 MessageDigest m = MessageDigest.getInstance("MD5");
17   - m.update(dataStr.getBytes("UTF8"));
  19 + m.update(dataStr.getBytes(StandardCharsets.UTF_8));
18 20 byte[] s = m.digest();
19 21 StringBuilder result = new StringBuilder();
20   - for (int i = 0; i < s.length; i++) {
21   - result.append(Integer.toHexString((0x000000FF & s[i]) | 0xFFFFFF00).substring(6));
  22 + for (byte b : s) {
  23 + result.append(Integer.toHexString((0x000000FF & b) | 0xFFFFFF00).substring(6));
22 24 }
23 25 return result.toString();
24 26 } catch (Exception e) {
... ... @@ -29,10 +31,11 @@ public abstract class MD5Util {
29 31  
30 32 /**
31 33 * 获取指定字符串的md5值, md5(str+salt)
  34 + *
32 35 * @param dataStr 明文
33 36 * @return String
34 37 */
35   - public static String md5WithSalt(String dataStr,String salt) {
  38 + public static String md5WithSalt(String dataStr, String salt) {
36 39 return md5(dataStr + salt);
37 40 }
38 41  
... ...
yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/util/RandomUtils.java
... ... @@ -31,11 +31,10 @@ public class RandomUtils {
31 31 * @return
32 32 */
33 33 public static String getRandomHan(String hanZi) {
34   - String ch = hanZi.charAt(new Random().nextInt(hanZi.length())) + "";
35   - return ch;
  34 + return hanZi.charAt(new Random().nextInt(hanZi.length())) + "";
36 35 }
37 36  
38   - public static int getRandomInt(int bound){
  37 + public static int getRandomInt(int bound) {
39 38 return ThreadLocalRandom.current().nextInt(bound);
40 39 }
41 40  
... ... @@ -68,25 +67,27 @@ public class RandomUtils {
68 67  
69 68 /**
70 69 * 随机范围内数字
  70 + *
71 71 * @param startNum
72 72 * @param endNum
73 73 * @return
74 74 */
75 75 public static Integer getRandomInt(int startNum, int endNum) {
76   - return ThreadLocalRandom.current().nextInt(endNum-startNum) + startNum;
  76 + return ThreadLocalRandom.current().nextInt(endNum - startNum) + startNum;
77 77 }
78 78  
79 79 /**
80 80 * 获取随机字符串
  81 + *
81 82 * @param length
82 83 * @return
83 84 */
84   - public static String getRandomString(int length){
85   - String str="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
86   - Random random=new Random();
87   - StringBuffer sb=new StringBuffer();
88   - for(int i=0;i<length;i++){
89   - int number=random.nextInt(62);
  85 + public static String getRandomString(int length) {
  86 + String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
  87 + Random random = new Random();
  88 + StringBuffer sb = new StringBuffer();
  89 + for (int i = 0; i < length; i++) {
  90 + int number = random.nextInt(62);
90 91 sb.append(str.charAt(number));
91 92 }
92 93 return sb.toString();
... ...
yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/util/StreamUtils.java
... ... @@ -19,7 +19,7 @@ public abstract class StreamUtils {
19 19 return new byte[0];
20 20 } else {
21 21 ByteArrayOutputStream out = new ByteArrayOutputStream(4096);
22   - copy((InputStream)in, out);
  22 + copy((InputStream) in, out);
23 23 return out.toByteArray();
24 24 }
25 25 }
... ... @@ -31,10 +31,9 @@ public abstract class StreamUtils {
31 31 StringBuilder out = new StringBuilder();
32 32 InputStreamReader reader = new InputStreamReader(in, charset);
33 33 char[] buffer = new char[4096];
34   - boolean var5 = true;
35 34  
36 35 int bytesRead;
37   - while((bytesRead = reader.read(buffer)) != -1) {
  36 + while ((bytesRead = reader.read(buffer)) != -1) {
38 37 out.append(buffer, 0, bytesRead);
39 38 }
40 39  
... ... @@ -57,7 +56,7 @@ public abstract class StreamUtils {
57 56 byte[] buffer = new byte[4096];
58 57  
59 58 int bytesRead;
60   - for(boolean var4 = true; (bytesRead = in.read(buffer)) != -1; byteCount += bytesRead) {
  59 + for (boolean var4 = true; (bytesRead = in.read(buffer)) != -1; byteCount += bytesRead) {
61 60 out.write(buffer, 0, bytesRead);
62 61 }
63 62  
... ... @@ -73,17 +72,17 @@ public abstract class StreamUtils {
73 72 long bytesToCopy = end - start + 1L;
74 73 byte[] buffer = new byte[4096];
75 74  
76   - while(bytesToCopy > 0L) {
  75 + while (bytesToCopy > 0L) {
77 76 int bytesRead = in.read(buffer);
78 77 if (bytesRead == -1) {
79 78 break;
80 79 }
81 80  
82   - if ((long)bytesRead <= bytesToCopy) {
  81 + if ((long) bytesRead <= bytesToCopy) {
83 82 out.write(buffer, 0, bytesRead);
84   - bytesToCopy -= (long)bytesRead;
  83 + bytesToCopy -= (long) bytesRead;
85 84 } else {
86   - out.write(buffer, 0, (int)bytesToCopy);
  85 + out.write(buffer, 0, (int) bytesToCopy);
87 86 bytesToCopy = 0L;
88 87 }
89 88 }
... ... @@ -96,7 +95,7 @@ public abstract class StreamUtils {
96 95 byte[] buffer = new byte[4096];
97 96 int byteCount;
98 97 int bytesRead;
99   - for(byteCount = 0; (bytesRead = in.read(buffer)) != -1; byteCount += bytesRead) {
  98 + for (byteCount = 0; (bytesRead = in.read(buffer)) != -1; byteCount += bytesRead) {
100 99 }
101 100  
102 101 return byteCount;
... ...
yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/util/StringUtils.java deleted
1   -/*
2   - *Copyright © 2018 anji-plus
3   - *安吉加加信息技术有限公司
4   - *http://www.anji-plus.com
5   - *All rights reserved.
6   - */
7   -package com.anji.captcha.util;
8   -
9   -public class StringUtils {
10   -
11   - /**
12   - * The empty String <code>""</code>.
13   - * @since 2.0
14   - */
15   - public static final String EMPTY = "";
16   -
17   - /**
18   - * Represents a failed index search.
19   - * @since 2.1
20   - */
21   - public static final int INDEX_NOT_FOUND = -1;
22   -
23   - /**
24   - * <p>The maximum size to which the padding constant(s) can expand.</p>
25   - */
26   - private static final int PAD_LIMIT = 8192;
27   -
28   - /**
29   - * <p><code>StringUtils</code> instances should NOT be constructed in
30   - * standard programming. Instead, the class should be used as
31   - * <code>StringUtils.trim(" foo ");</code>.</p>
32   - *
33   - * <p>This constructor is public to permit tools that require a JavaBean
34   - * instance to operate.</p>
35   - */
36   - public StringUtils() {
37   - super();
38   - }
39   -
40   - // Empty checks
41   - //-----------------------------------------------------------------------
42   - /**
43   - * <p>Checks if a String is empty ("") or null.</p>
44   - *
45   - * <pre>
46   - * StringUtils.isEmpty(null) = true
47   - * StringUtils.isEmpty("") = true
48   - * StringUtils.isEmpty(" ") = false
49   - * StringUtils.isEmpty("bob") = false
50   - * StringUtils.isEmpty(" bob ") = false
51   - * </pre>
52   - *
53   - * <p>NOTE: This method changed in Lang version 2.0.
54   - * It no longer trims the String.
55   - * That functionality is available in isBlank().</p>
56   - *
57   - * @param str the String to check, may be null
58   - * @return <code>true</code> if the String is empty or null
59   - */
60   - public static boolean isEmpty(String str) {
61   - return str == null || str.length() == 0;
62   - }
63   -
64   - /**
65   - * <p>Checks if a String is not empty ("") and not null.</p>
66   - *
67   - * <pre>
68   - * StringUtils.isNotEmpty(null) = false
69   - * StringUtils.isNotEmpty("") = false
70   - * StringUtils.isNotEmpty(" ") = true
71   - * StringUtils.isNotEmpty("bob") = true
72   - * StringUtils.isNotEmpty(" bob ") = true
73   - * </pre>
74   - *
75   - * @param str the String to check, may be null
76   - * @return <code>true</code> if the String is not empty and not null
77   - */
78   - public static boolean isNotEmpty(String str) {
79   - return !StringUtils.isEmpty(str);
80   - }
81   -
82   - /**
83   - * <p>Checks if a String is whitespace, empty ("") or null.</p>
84   - *
85   - * <pre>
86   - * StringUtils.isBlank(null) = true
87   - * StringUtils.isBlank("null") = true
88   - * StringUtils.isBlank("") = true
89   - * StringUtils.isBlank(" ") = true
90   - * StringUtils.isBlank("bob") = false
91   - * StringUtils.isBlank(" bob ") = false
92   - * </pre>
93   - *
94   - * @param str the String to check, may be null
95   - * @return <code>true</code> if the String is null, empty or whitespace
96   - * @since 2.0
97   - */
98   - public static boolean isBlank(String str) {
99   - int strLen;
100   - if (str == null || (strLen = str.length()) == 0) {
101   - return true;
102   - }
103   - if(equals("null", str.trim().toLowerCase())){
104   - return true;
105   - }
106   - for (int i = 0; i < strLen; i++) {
107   - if ((Character.isWhitespace(str.charAt(i)) == false)) {
108   - return false;
109   - }
110   - }
111   - return true;
112   - }
113   -
114   - /**
115   - * <p>Checks if a String is not empty (""), not null and not whitespace only.</p>
116   - *
117   - * <pre>
118   - * StringUtils.isNotBlank(null) = false
119   - * StringUtils.isNotBlank("null") = false
120   - * StringUtils.isNotBlank("") = false
121   - * StringUtils.isNotBlank(" ") = false
122   - * StringUtils.isNotBlank("bob") = true
123   - * StringUtils.isNotBlank(" bob ") = true
124   - * </pre>
125   - *
126   - * @param str the String to check, may be null
127   - * @return <code>true</code> if the String is
128   - * not empty and not null and not whitespace
129   - * @since 2.0
130   - */
131   - public static boolean isNotBlank(String str) {
132   - return !StringUtils.isBlank(str);
133   - }
134   -
135   - // Trim
136   - //-----------------------------------------------------------------------
137   - /**
138   - * <p>Removes control characters (char &lt;= 32) from both
139   - * ends of this String, handling <code>null</code> by returning
140   - * an empty String ("").</p>
141   - *
142   - * <pre>
143   - * StringUtils.clean(null) = ""
144   - * StringUtils.clean("") = ""
145   - * StringUtils.clean("abc") = "abc"
146   - * StringUtils.clean(" abc ") = "abc"
147   - * StringUtils.clean(" ") = ""
148   - * </pre>
149   - *
150   - * @see String#trim()
151   - * @param str the String to clean, may be null
152   - * @return the trimmed text, never <code>null</code>
153   - * @deprecated Use the clearer named {@link #trimToEmpty(String)}.
154   - * Method will be removed in Commons Lang 3.0.
155   - */
156   - public static String clean(String str) {
157   - return str == null ? EMPTY : str.trim();
158   - }
159   -
160   - /**
161   - * <p>Removes control characters (char &lt;= 32) from both
162   - * ends of this String, handling <code>null</code> by returning
163   - * <code>null</code>.</p>
164   - *
165   - * <p>The String is trimmed using {@link String#trim()}.
166   - * Trim removes start and end characters &lt;= 32.
167   - * To strip whitespace use {@link #strip(String)}.</p>
168   - *
169   - * <p>To trim your choice of characters, use the
170   - * {@link #strip(String, String)} methods.</p>
171   - *
172   - * <pre>
173   - * StringUtils.trim(null) = null
174   - * StringUtils.trim("") = ""
175   - * StringUtils.trim(" ") = ""
176   - * StringUtils.trim("abc") = "abc"
177   - * StringUtils.trim(" abc ") = "abc"
178   - * </pre>
179   - *
180   - * @param str the String to be trimmed, may be null
181   - * @return the trimmed string, <code>null</code> if null String input
182   - */
183   - public static String trim(String str) {
184   - return str == null ? null : str.trim();
185   - }
186   -
187   - /**
188   - * <p>Removes control characters (char &lt;= 32) from both
189   - * ends of this String returning <code>null</code> if the String is
190   - * empty ("") after the trim or if it is <code>null</code>.
191   - *
192   - * <p>The String is trimmed using {@link String#trim()}.
193   - * Trim removes start and end characters &lt;= 32.
194   - * To strip whitespace use {@link #stripToNull(String)}.</p>
195   - *
196   - * <pre>
197   - * StringUtils.trimToNull(null) = null
198   - * StringUtils.trimToNull("") = null
199   - * StringUtils.trimToNull(" ") = null
200   - * StringUtils.trimToNull("abc") = "abc"
201   - * StringUtils.trimToNull(" abc ") = "abc"
202   - * </pre>
203   - *
204   - * @param str the String to be trimmed, may be null
205   - * @return the trimmed String,
206   - * <code>null</code> if only chars &lt;= 32, empty or null String input
207   - * @since 2.0
208   - */
209   - public static String trimToNull(String str) {
210   - String ts = trim(str);
211   - return isEmpty(ts) ? null : ts;
212   - }
213   -
214   - /**
215   - * <p>Removes control characters (char &lt;= 32) from both
216   - * ends of this String returning an empty String ("") if the String
217   - * is empty ("") after the trim or if it is <code>null</code>.
218   - *
219   - * <p>The String is trimmed using {@link String#trim()}.
220   - * Trim removes start and end characters &lt;= 32.
221   - * To strip whitespace use {@link #stripToEmpty(String)}.</p>
222   - *
223   - * <pre>
224   - * StringUtils.trimToEmpty(null) = ""
225   - * StringUtils.trimToEmpty("") = ""
226   - * StringUtils.trimToEmpty(" ") = ""
227   - * StringUtils.trimToEmpty("abc") = "abc"
228   - * StringUtils.trimToEmpty(" abc ") = "abc"
229   - * </pre>
230   - *
231   - * @param str the String to be trimmed, may be null
232   - * @return the trimmed String, or an empty String if <code>null</code> input
233   - * @since 2.0
234   - */
235   - public static String trimToEmpty(String str) {
236   - return str == null ? EMPTY : str.trim();
237   - }
238   -
239   - // Stripping
240   - //-----------------------------------------------------------------------
241   - /**
242   - * <p>Strips whitespace from the start and end of a String.</p>
243   - *
244   - * <p>This is similar to {@link #trim(String)} but removes whitespace.
245   - * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
246   - *
247   - * <p>A <code>null</code> input String returns <code>null</code>.</p>
248   - *
249   - * <pre>
250   - * StringUtils.strip(null) = null
251   - * StringUtils.strip("") = ""
252   - * StringUtils.strip(" ") = ""
253   - * StringUtils.strip("abc") = "abc"
254   - * StringUtils.strip(" abc") = "abc"
255   - * StringUtils.strip("abc ") = "abc"
256   - * StringUtils.strip(" abc ") = "abc"
257   - * StringUtils.strip(" ab c ") = "ab c"
258   - * </pre>
259   - *
260   - * @param str the String to remove whitespace from, may be null
261   - * @return the stripped String, <code>null</code> if null String input
262   - */
263   - public static String strip(String str) {
264   - return strip(str, null);
265   - }
266   -
267   - /**
268   - * <p>Strips whitespace from the start and end of a String returning
269   - * <code>null</code> if the String is empty ("") after the strip.</p>
270   - *
271   - * <p>This is similar to {@link #trimToNull(String)} but removes whitespace.
272   - * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
273   - *
274   - * <pre>
275   - * StringUtils.stripToNull(null) = null
276   - * StringUtils.stripToNull("") = null
277   - * StringUtils.stripToNull(" ") = null
278   - * StringUtils.stripToNull("abc") = "abc"
279   - * StringUtils.stripToNull(" abc") = "abc"
280   - * StringUtils.stripToNull("abc ") = "abc"
281   - * StringUtils.stripToNull(" abc ") = "abc"
282   - * StringUtils.stripToNull(" ab c ") = "ab c"
283   - * </pre>
284   - *
285   - * @param str the String to be stripped, may be null
286   - * @return the stripped String,
287   - * <code>null</code> if whitespace, empty or null String input
288   - * @since 2.0
289   - */
290   - public static String stripToNull(String str) {
291   - if (str == null) {
292   - return null;
293   - }
294   - str = strip(str, null);
295   - return str.length() == 0 ? null : str;
296   - }
297   -
298   - /**
299   - * <p>Strips whitespace from the start and end of a String returning
300   - * an empty String if <code>null</code> input.</p>
301   - *
302   - * <p>This is similar to {@link #trimToEmpty(String)} but removes whitespace.
303   - * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
304   - *
305   - * <pre>
306   - * StringUtils.stripToEmpty(null) = ""
307   - * StringUtils.stripToEmpty("") = ""
308   - * StringUtils.stripToEmpty(" ") = ""
309   - * StringUtils.stripToEmpty("abc") = "abc"
310   - * StringUtils.stripToEmpty(" abc") = "abc"
311   - * StringUtils.stripToEmpty("abc ") = "abc"
312   - * StringUtils.stripToEmpty(" abc ") = "abc"
313   - * StringUtils.stripToEmpty(" ab c ") = "ab c"
314   - * </pre>
315   - *
316   - * @param str the String to be stripped, may be null
317   - * @return the trimmed String, or an empty String if <code>null</code> input
318   - * @since 2.0
319   - */
320   - public static String stripToEmpty(String str) {
321   - return str == null ? EMPTY : strip(str, null);
322   - }
323   -
324   - /**
325   - * <p>Strips any of a set of characters from the start and end of a String.
326   - * This is similar to {@link String#trim()} but allows the characters
327   - * to be stripped to be controlled.</p>
328   - *
329   - * <p>A <code>null</code> input String returns <code>null</code>.
330   - * An empty string ("") input returns the empty string.</p>
331   - *
332   - * <p>If the stripChars String is <code>null</code>, whitespace is
333   - * stripped as defined by {@link Character#isWhitespace(char)}.
334   - * Alternatively use {@link #strip(String)}.</p>
335   - *
336   - * <pre>
337   - * StringUtils.strip(null, *) = null
338   - * StringUtils.strip("", *) = ""
339   - * StringUtils.strip("abc", null) = "abc"
340   - * StringUtils.strip(" abc", null) = "abc"
341   - * StringUtils.strip("abc ", null) = "abc"
342   - * StringUtils.strip(" abc ", null) = "abc"
343   - * StringUtils.strip(" abcyx", "xyz") = " abc"
344   - * </pre>
345   - *
346   - * @param str the String to remove characters from, may be null
347   - * @param stripChars the characters to remove, null treated as whitespace
348   - * @return the stripped String, <code>null</code> if null String input
349   - */
350   - public static String strip(String str, String stripChars) {
351   - if (isEmpty(str)) {
352   - return str;
353   - }
354   - str = stripStart(str, stripChars);
355   - return stripEnd(str, stripChars);
356   - }
357   -
358   - /**
359   - * <p>Strips any of a set of characters from the start of a String.</p>
360   - *
361   - * <p>A <code>null</code> input String returns <code>null</code>.
362   - * An empty string ("") input returns the empty string.</p>
363   - *
364   - * <p>If the stripChars String is <code>null</code>, whitespace is
365   - * stripped as defined by {@link Character#isWhitespace(char)}.</p>
366   - *
367   - * <pre>
368   - * StringUtils.stripStart(null, *) = null
369   - * StringUtils.stripStart("", *) = ""
370   - * StringUtils.stripStart("abc", "") = "abc"
371   - * StringUtils.stripStart("abc", null) = "abc"
372   - * StringUtils.stripStart(" abc", null) = "abc"
373   - * StringUtils.stripStart("abc ", null) = "abc "
374   - * StringUtils.stripStart(" abc ", null) = "abc "
375   - * StringUtils.stripStart("yxabc ", "xyz") = "abc "
376   - * </pre>
377   - *
378   - * @param str the String to remove characters from, may be null
379   - * @param stripChars the characters to remove, null treated as whitespace
380   - * @return the stripped String, <code>null</code> if null String input
381   - */
382   - public static String stripStart(String str, String stripChars) {
383   - int strLen;
384   - if (str == null || (strLen = str.length()) == 0) {
385   - return str;
386   - }
387   - int start = 0;
388   - if (stripChars == null) {
389   - while ((start != strLen) && Character.isWhitespace(str.charAt(start))) {
390   - start++;
391   - }
392   - } else if (stripChars.length() == 0) {
393   - return str;
394   - } else {
395   - while ((start != strLen) && (stripChars.indexOf(str.charAt(start)) != INDEX_NOT_FOUND)) {
396   - start++;
397   - }
398   - }
399   - return str.substring(start);
400   - }
401   -
402   - /**
403   - * <p>Strips any of a set of characters from the end of a String.</p>
404   - *
405   - * <p>A <code>null</code> input String returns <code>null</code>.
406   - * An empty string ("") input returns the empty string.</p>
407   - *
408   - * <p>If the stripChars String is <code>null</code>, whitespace is
409   - * stripped as defined by {@link Character#isWhitespace(char)}.</p>
410   - *
411   - * <pre>
412   - * StringUtils.stripEnd(null, *) = null
413   - * StringUtils.stripEnd("", *) = ""
414   - * StringUtils.stripEnd("abc", "") = "abc"
415   - * StringUtils.stripEnd("abc", null) = "abc"
416   - * StringUtils.stripEnd(" abc", null) = " abc"
417   - * StringUtils.stripEnd("abc ", null) = "abc"
418   - * StringUtils.stripEnd(" abc ", null) = " abc"
419   - * StringUtils.stripEnd(" abcyx", "xyz") = " abc"
420   - * StringUtils.stripEnd("120.00", ".0") = "12"
421   - * </pre>
422   - *
423   - * @param str the String to remove characters from, may be null
424   - * @param stripChars the set of characters to remove, null treated as whitespace
425   - * @return the stripped String, <code>null</code> if null String input
426   - */
427   - public static String stripEnd(String str, String stripChars) {
428   - int end;
429   - if (str == null || (end = str.length()) == 0) {
430   - return str;
431   - }
432   -
433   - if (stripChars == null) {
434   - while ((end != 0) && Character.isWhitespace(str.charAt(end - 1))) {
435   - end--;
436   - }
437   - } else if (stripChars.length() == 0) {
438   - return str;
439   - } else {
440   - while ((end != 0) && (stripChars.indexOf(str.charAt(end - 1)) != INDEX_NOT_FOUND)) {
441   - end--;
442   - }
443   - }
444   - return str.substring(0, end);
445   - }
446   -
447   - // StripAll
448   - //-----------------------------------------------------------------------
449   - /**
450   - * <p>Strips whitespace from the start and end of every String in an array.
451   - * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
452   - *
453   - * <p>A new array is returned each time, except for length zero.
454   - * A <code>null</code> array will return <code>null</code>.
455   - * An empty array will return itself.
456   - * A <code>null</code> array entry will be ignored.</p>
457   - *
458   - * <pre>
459   - * StringUtils.stripAll(null) = null
460   - * StringUtils.stripAll([]) = []
461   - * StringUtils.stripAll(["abc", " abc"]) = ["abc", "abc"]
462   - * StringUtils.stripAll(["abc ", null]) = ["abc", null]
463   - * </pre>
464   - *
465   - * @param strs the array to remove whitespace from, may be null
466   - * @return the stripped Strings, <code>null</code> if null array input
467   - */
468   - public static String[] stripAll(String[] strs) {
469   - return stripAll(strs, null);
470   - }
471   -
472   - /**
473   - * <p>Strips any of a set of characters from the start and end of every
474   - * String in an array.</p>
475   - * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
476   - *
477   - * <p>A new array is returned each time, except for length zero.
478   - * A <code>null</code> array will return <code>null</code>.
479   - * An empty array will return itself.
480   - * A <code>null</code> array entry will be ignored.
481   - * A <code>null</code> stripChars will strip whitespace as defined by
482   - * {@link Character#isWhitespace(char)}.</p>
483   - *
484   - * <pre>
485   - * StringUtils.stripAll(null, *) = null
486   - * StringUtils.stripAll([], *) = []
487   - * StringUtils.stripAll(["abc", " abc"], null) = ["abc", "abc"]
488   - * StringUtils.stripAll(["abc ", null], null) = ["abc", null]
489   - * StringUtils.stripAll(["abc ", null], "yz") = ["abc ", null]
490   - * StringUtils.stripAll(["yabcz", null], "yz") = ["abc", null]
491   - * </pre>
492   - *
493   - * @param strs the array to remove characters from, may be null
494   - * @param stripChars the characters to remove, null treated as whitespace
495   - * @return the stripped Strings, <code>null</code> if null array input
496   - */
497   - public static String[] stripAll(String[] strs, String stripChars) {
498   - int strsLen;
499   - if (strs == null || (strsLen = strs.length) == 0) {
500   - return strs;
501   - }
502   - String[] newArr = new String[strsLen];
503   - for (int i = 0; i < strsLen; i++) {
504   - newArr[i] = strip(strs[i], stripChars);
505   - }
506   - return newArr;
507   - }
508   -
509   - // Equals
510   - //-----------------------------------------------------------------------
511   - /**
512   - * <p>Compares two Strings, returning <code>true</code> if they are equal.</p>
513   - *
514   - * <p><code>null</code>s are handled without exceptions. Two <code>null</code>
515   - * references are considered to be equal. The comparison is case sensitive.</p>
516   - *
517   - * <pre>
518   - * StringUtils.equals(null, null) = true
519   - * StringUtils.equals(null, "abc") = false
520   - * StringUtils.equals("abc", null) = false
521   - * StringUtils.equals("abc", "abc") = true
522   - * StringUtils.equals("abc", "ABC") = false
523   - * </pre>
524   - *
525   - * @see String#equals(Object)
526   - * @param str1 the first String, may be null
527   - * @param str2 the second String, may be null
528   - * @return <code>true</code> if the Strings are equal, case sensitive, or
529   - * both <code>null</code>
530   - */
531   - public static boolean equals(String str1, String str2) {
532   - return str1 == null ? str2 == null : str1.equals(str2);
533   - }
534   -
535   - /**
536   - * <p>Compares two Strings, returning <code>true</code> if they are equal ignoring
537   - * the case.</p>
538   - *
539   - * <p><code>null</code>s are handled without exceptions. Two <code>null</code>
540   - * references are considered equal. Comparison is case insensitive.</p>
541   - *
542   - * <pre>
543   - * StringUtils.equalsIgnoreCase(null, null) = true
544   - * StringUtils.equalsIgnoreCase(null, "abc") = false
545   - * StringUtils.equalsIgnoreCase("abc", null) = false
546   - * StringUtils.equalsIgnoreCase("abc", "abc") = true
547   - * StringUtils.equalsIgnoreCase("abc", "ABC") = true
548   - * </pre>
549   - *
550   - * @see String#equalsIgnoreCase(String)
551   - * @param str1 the first String, may be null
552   - * @param str2 the second String, may be null
553   - * @return <code>true</code> if the Strings are equal, case insensitive, or
554   - * both <code>null</code>
555   - */
556   - public static boolean equalsIgnoreCase(String str1, String str2) {
557   - return str1 == null ? str2 == null : str1.equalsIgnoreCase(str2);
558   - }
559   -
560   - // IndexOf
561   - //-----------------------------------------------------------------------
562   - /**
563   - * <p>Finds the first index within a String, handling <code>null</code>.
564   - * This method uses {@link String#indexOf(int)}.</p>
565   - *
566   - * <p>A <code>null</code> or empty ("") String will return <code>INDEX_NOT_FOUND (-1)</code>.</p>
567   - *
568   - * <pre>
569   - * StringUtils.indexOf(null, *) = -1
570   - * StringUtils.indexOf("", *) = -1
571   - * StringUtils.indexOf("aabaabaa", 'a') = 0
572   - * StringUtils.indexOf("aabaabaa", 'b') = 2
573   - * </pre>
574   - *
575   - * @param str the String to check, may be null
576   - * @param searchChar the character to find
577   - * @return the first index of the search character,
578   - * -1 if no match or <code>null</code> string input
579   - * @since 2.0
580   - */
581   - public static int indexOf(String str, char searchChar) {
582   - if (isEmpty(str)) {
583   - return INDEX_NOT_FOUND;
584   - }
585   - return str.indexOf(searchChar);
586   - }
587   -
588   - /**
589   - * <p>Finds the first index within a String from a start position,
590   - * handling <code>null</code>.
591   - * This method uses {@link String#indexOf(int, int)}.</p>
592   - *
593   - * <p>A <code>null</code> or empty ("") String will return <code>(INDEX_NOT_FOUND) -1</code>.
594   - * A negative start position is treated as zero.
595   - * A start position greater than the string length returns <code>-1</code>.</p>
596   - *
597   - * <pre>
598   - * StringUtils.indexOf(null, *, *) = -1
599   - * StringUtils.indexOf("", *, *) = -1
600   - * StringUtils.indexOf("aabaabaa", 'b', 0) = 2
601   - * StringUtils.indexOf("aabaabaa", 'b', 3) = 5
602   - * StringUtils.indexOf("aabaabaa", 'b', 9) = -1
603   - * StringUtils.indexOf("aabaabaa", 'b', -1) = 2
604   - * </pre>
605   - *
606   - * @param str the String to check, may be null
607   - * @param searchChar the character to find
608   - * @param startPos the start position, negative treated as zero
609   - * @return the first index of the search character,
610   - * -1 if no match or <code>null</code> string input
611   - * @since 2.0
612   - */
613   - public static int indexOf(String str, char searchChar, int startPos) {
614   - if (isEmpty(str)) {
615   - return INDEX_NOT_FOUND;
616   - }
617   - return str.indexOf(searchChar, startPos);
618   - }
619   -
620   - /**
621   - * <p>Finds the first index within a String, handling <code>null</code>.
622   - * This method uses {@link String#indexOf(String)}.</p>
623   - *
624   - * <p>A <code>null</code> String will return <code>-1</code>.</p>
625   - *
626   - * <pre>
627   - * StringUtils.indexOf(null, *) = -1
628   - * StringUtils.indexOf(*, null) = -1
629   - * StringUtils.indexOf("", "") = 0
630   - * StringUtils.indexOf("", *) = -1 (except when * = "")
631   - * StringUtils.indexOf("aabaabaa", "a") = 0
632   - * StringUtils.indexOf("aabaabaa", "b") = 2
633   - * StringUtils.indexOf("aabaabaa", "ab") = 1
634   - * StringUtils.indexOf("aabaabaa", "") = 0
635   - * </pre>
636   - *
637   - * @param str the String to check, may be null
638   - * @param searchStr the String to find, may be null
639   - * @return the first index of the search String,
640   - * -1 if no match or <code>null</code> string input
641   - * @since 2.0
642   - */
643   - public static int indexOf(String str, String searchStr) {
644   - if (str == null || searchStr == null) {
645   - return INDEX_NOT_FOUND;
646   - }
647   - return str.indexOf(searchStr);
648   - }
649   -
650   - /**
651   - * <p>Finds the n-th index within a String, handling <code>null</code>.
652   - * This method uses {@link String#indexOf(String)}.</p>
653   - *
654   - * <p>A <code>null</code> String will return <code>-1</code>.</p>
655   - *
656   - * <pre>
657   - * StringUtils.ordinalIndexOf(null, *, *) = -1
658   - * StringUtils.ordinalIndexOf(*, null, *) = -1
659   - * StringUtils.ordinalIndexOf("", "", *) = 0
660   - * StringUtils.ordinalIndexOf("aabaabaa", "a", 1) = 0
661   - * StringUtils.ordinalIndexOf("aabaabaa", "a", 2) = 1
662   - * StringUtils.ordinalIndexOf("aabaabaa", "b", 1) = 2
663   - * StringUtils.ordinalIndexOf("aabaabaa", "b", 2) = 5
664   - * StringUtils.ordinalIndexOf("aabaabaa", "ab", 1) = 1
665   - * StringUtils.ordinalIndexOf("aabaabaa", "ab", 2) = 4
666   - * StringUtils.ordinalIndexOf("aabaabaa", "", 1) = 0
667   - * StringUtils.ordinalIndexOf("aabaabaa", "", 2) = 0
668   - * </pre>
669   - *
670   - * <p>Note that 'head(String str, int n)' may be implemented as: </p>
671   - *
672   - * <pre>
673   - * str.substring(0, lastOrdinalIndexOf(str, "\n", n))
674   - * </pre>
675   - *
676   - * @param str the String to check, may be null
677   - * @param searchStr the String to find, may be null
678   - * @param ordinal the n-th <code>searchStr</code> to find
679   - * @return the n-th index of the search String,
680   - * <code>-1</code> (<code>INDEX_NOT_FOUND</code>) if no match or <code>null</code> string input
681   - * @since 2.1
682   - */
683   - public static int ordinalIndexOf(String str, String searchStr, int ordinal) {
684   - return ordinalIndexOf(str, searchStr, ordinal, false);
685   - }
686   -
687   - /**
688   - * <p>Finds the n-th index within a String, handling <code>null</code>.
689   - * This method uses {@link String#indexOf(String)}.</p>
690   - *
691   - * <p>A <code>null</code> String will return <code>-1</code>.</p>
692   - *
693   - * @param str the String to check, may be null
694   - * @param searchStr the String to find, may be null
695   - * @param ordinal the n-th <code>searchStr</code> to find
696   - * @param lastIndex true if lastOrdinalIndexOf() otherwise false if ordinalIndexOf()
697   - * @return the n-th index of the search String,
698   - * <code>-1</code> (<code>INDEX_NOT_FOUND</code>) if no match or <code>null</code> string input
699   - */
700   - // Shared code between ordinalIndexOf(String,String,int) and lastOrdinalIndexOf(String,String,int)
701   - private static int ordinalIndexOf(String str, String searchStr, int ordinal, boolean lastIndex) {
702   - if (str == null || searchStr == null || ordinal <= 0) {
703   - return INDEX_NOT_FOUND;
704   - }
705   - if (searchStr.length() == 0) {
706   - return lastIndex ? str.length() : 0;
707   - }
708   - int found = 0;
709   - int index = lastIndex ? str.length() : INDEX_NOT_FOUND;
710   - do {
711   - if(lastIndex) {
712   - index = str.lastIndexOf(searchStr, index - 1);
713   - } else {
714   - index = str.indexOf(searchStr, index + 1);
715   - }
716   - if (index < 0) {
717   - return index;
718   - }
719   - found++;
720   - } while (found < ordinal);
721   - return index;
722   - }
723   -
724   - /**
725   - * <p>Finds the first index within a String, handling <code>null</code>.
726   - * This method uses {@link String#indexOf(String, int)}.</p>
727   - *
728   - * <p>A <code>null</code> String will return <code>-1</code>.
729   - * A negative start position is treated as zero.
730   - * An empty ("") search String always matches.
731   - * A start position greater than the string length only matches
732   - * an empty search String.</p>
733   - *
734   - * <pre>
735   - * StringUtils.indexOf(null, *, *) = -1
736   - * StringUtils.indexOf(*, null, *) = -1
737   - * StringUtils.indexOf("", "", 0) = 0
738   - * StringUtils.indexOf("", *, 0) = -1 (except when * = "")
739   - * StringUtils.indexOf("aabaabaa", "a", 0) = 0
740   - * StringUtils.indexOf("aabaabaa", "b", 0) = 2
741   - * StringUtils.indexOf("aabaabaa", "ab", 0) = 1
742   - * StringUtils.indexOf("aabaabaa", "b", 3) = 5
743   - * StringUtils.indexOf("aabaabaa", "b", 9) = -1
744   - * StringUtils.indexOf("aabaabaa", "b", -1) = 2
745   - * StringUtils.indexOf("aabaabaa", "", 2) = 2
746   - * StringUtils.indexOf("abc", "", 9) = 3
747   - * </pre>
748   - *
749   - * @param str the String to check, may be null
750   - * @param searchStr the String to find, may be null
751   - * @param startPos the start position, negative treated as zero
752   - * @return the first index of the search String,
753   - * -1 if no match or <code>null</code> string input
754   - * @since 2.0
755   - */
756   - public static int indexOf(String str, String searchStr, int startPos) {
757   - if (str == null || searchStr == null) {
758   - return INDEX_NOT_FOUND;
759   - }
760   - // JDK1.2/JDK1.3 have a bug, when startPos > str.length for "", hence
761   - if (searchStr.length() == 0 && startPos >= str.length()) {
762   - return str.length();
763   - }
764   - return str.indexOf(searchStr, startPos);
765   - }
766   -
767   - /**
768   - * <p>Case in-sensitive find of the first index within a String.</p>
769   - *
770   - * <p>A <code>null</code> String will return <code>-1</code>.
771   - * A negative start position is treated as zero.
772   - * An empty ("") search String always matches.
773   - * A start position greater than the string length only matches
774   - * an empty search String.</p>
775   - *
776   - * <pre>
777   - * StringUtils.indexOfIgnoreCase(null, *) = -1
778   - * StringUtils.indexOfIgnoreCase(*, null) = -1
779   - * StringUtils.indexOfIgnoreCase("", "") = 0
780   - * StringUtils.indexOfIgnoreCase("aabaabaa", "a") = 0
781   - * StringUtils.indexOfIgnoreCase("aabaabaa", "b") = 2
782   - * StringUtils.indexOfIgnoreCase("aabaabaa", "ab") = 1
783   - * </pre>
784   - *
785   - * @param str the String to check, may be null
786   - * @param searchStr the String to find, may be null
787   - * @return the first index of the search String,
788   - * -1 if no match or <code>null</code> string input
789   - * @since 2.5
790   - */
791   - public static int indexOfIgnoreCase(String str, String searchStr) {
792   - return indexOfIgnoreCase(str, searchStr, 0);
793   - }
794   -
795   - /**
796   - * <p>Case in-sensitive find of the first index within a String
797   - * from the specified position.</p>
798   - *
799   - * <p>A <code>null</code> String will return <code>-1</code>.
800   - * A negative start position is treated as zero.
801   - * An empty ("") search String always matches.
802   - * A start position greater than the string length only matches
803   - * an empty search String.</p>
804   - *
805   - * <pre>
806   - * StringUtils.indexOfIgnoreCase(null, *, *) = -1
807   - * StringUtils.indexOfIgnoreCase(*, null, *) = -1
808   - * StringUtils.indexOfIgnoreCase("", "", 0) = 0
809   - * StringUtils.indexOfIgnoreCase("aabaabaa", "A", 0) = 0
810   - * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 0) = 2
811   - * StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 0) = 1
812   - * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 3) = 5
813   - * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 9) = -1
814   - * StringUtils.indexOfIgnoreCase("aabaabaa", "B", -1) = 2
815   - * StringUtils.indexOfIgnoreCase("aabaabaa", "", 2) = 2
816   - * StringUtils.indexOfIgnoreCase("abc", "", 9) = 3
817   - * </pre>
818   - *
819   - * @param str the String to check, may be null
820   - * @param searchStr the String to find, may be null
821   - * @param startPos the start position, negative treated as zero
822   - * @return the first index of the search String,
823   - * -1 if no match or <code>null</code> string input
824   - * @since 2.5
825   - */
826   - public static int indexOfIgnoreCase(String str, String searchStr, int startPos) {
827   - if (str == null || searchStr == null) {
828   - return INDEX_NOT_FOUND;
829   - }
830   - if (startPos < 0) {
831   - startPos = 0;
832   - }
833   - int endLimit = (str.length() - searchStr.length()) + 1;
834   - if (startPos > endLimit) {
835   - return INDEX_NOT_FOUND;
836   - }
837   - if (searchStr.length() == 0) {
838   - return startPos;
839   - }
840   - for (int i = startPos; i < endLimit; i++) {
841   - if (str.regionMatches(true, i, searchStr, 0, searchStr.length())) {
842   - return i;
843   - }
844   - }
845   - return INDEX_NOT_FOUND;
846   - }
847   -
848   - // LastIndexOf
849   - //-----------------------------------------------------------------------
850   - /**
851   - * <p>Finds the last index within a String, handling <code>null</code>.
852   - * This method uses {@link String#lastIndexOf(int)}.</p>
853   - *
854   - * <p>A <code>null</code> or empty ("") String will return <code>-1</code>.</p>
855   - *
856   - * <pre>
857   - * StringUtils.lastIndexOf(null, *) = -1
858   - * StringUtils.lastIndexOf("", *) = -1
859   - * StringUtils.lastIndexOf("aabaabaa", 'a') = 7
860   - * StringUtils.lastIndexOf("aabaabaa", 'b') = 5
861   - * </pre>
862   - *
863   - * @param str the String to check, may be null
864   - * @param searchChar the character to find
865   - * @return the last index of the search character,
866   - * -1 if no match or <code>null</code> string input
867   - * @since 2.0
868   - */
869   - public static int lastIndexOf(String str, char searchChar) {
870   - if (isEmpty(str)) {
871   - return INDEX_NOT_FOUND;
872   - }
873   - return str.lastIndexOf(searchChar);
874   - }
875   -
876   - /**
877   - * <p>Finds the last index within a String from a start position,
878   - * handling <code>null</code>.
879   - * This method uses {@link String#lastIndexOf(int, int)}.</p>
880   - *
881   - * <p>A <code>null</code> or empty ("") String will return <code>-1</code>.
882   - * A negative start position returns <code>-1</code>.
883   - * A start position greater than the string length searches the whole string.</p>
884   - *
885   - * <pre>
886   - * StringUtils.lastIndexOf(null, *, *) = -1
887   - * StringUtils.lastIndexOf("", *, *) = -1
888   - * StringUtils.lastIndexOf("aabaabaa", 'b', 8) = 5
889   - * StringUtils.lastIndexOf("aabaabaa", 'b', 4) = 2
890   - * StringUtils.lastIndexOf("aabaabaa", 'b', 0) = -1
891   - * StringUtils.lastIndexOf("aabaabaa", 'b', 9) = 5
892   - * StringUtils.lastIndexOf("aabaabaa", 'b', -1) = -1
893   - * StringUtils.lastIndexOf("aabaabaa", 'a', 0) = 0
894   - * </pre>
895   - *
896   - * @param str the String to check, may be null
897   - * @param searchChar the character to find
898   - * @param startPos the start position
899   - * @return the last index of the search character,
900   - * -1 if no match or <code>null</code> string input
901   - * @since 2.0
902   - */
903   - public static int lastIndexOf(String str, char searchChar, int startPos) {
904   - if (isEmpty(str)) {
905   - return INDEX_NOT_FOUND;
906   - }
907   - return str.lastIndexOf(searchChar, startPos);
908   - }
909   -
910   - /**
911   - * <p>Finds the last index within a String, handling <code>null</code>.
912   - * This method uses {@link String#lastIndexOf(String)}.</p>
913   - *
914   - * <p>A <code>null</code> String will return <code>-1</code>.</p>
915   - *
916   - * <pre>
917   - * StringUtils.lastIndexOf(null, *) = -1
918   - * StringUtils.lastIndexOf(*, null) = -1
919   - * StringUtils.lastIndexOf("", "") = 0
920   - * StringUtils.lastIndexOf("aabaabaa", "a") = 7
921   - * StringUtils.lastIndexOf("aabaabaa", "b") = 5
922   - * StringUtils.lastIndexOf("aabaabaa", "ab") = 4
923   - * StringUtils.lastIndexOf("aabaabaa", "") = 8
924   - * </pre>
925   - *
926   - * @param str the String to check, may be null
927   - * @param searchStr the String to find, may be null
928   - * @return the last index of the search String,
929   - * -1 if no match or <code>null</code> string input
930   - * @since 2.0
931   - */
932   - public static int lastIndexOf(String str, String searchStr) {
933   - if (str == null || searchStr == null) {
934   - return INDEX_NOT_FOUND;
935   - }
936   - return str.lastIndexOf(searchStr);
937   - }
938   -
939   - /**
940   - * <p>Finds the n-th last index within a String, handling <code>null</code>.
941   - * This method uses {@link String#lastIndexOf(String)}.</p>
942   - *
943   - * <p>A <code>null</code> String will return <code>-1</code>.</p>
944   - *
945   - * <pre>
946   - * StringUtils.lastOrdinalIndexOf(null, *, *) = -1
947   - * StringUtils.lastOrdinalIndexOf(*, null, *) = -1
948   - * StringUtils.lastOrdinalIndexOf("", "", *) = 0
949   - * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 1) = 7
950   - * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 2) = 6
951   - * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 1) = 5
952   - * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 2) = 2
953   - * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 1) = 4
954   - * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 2) = 1
955   - * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 1) = 8
956   - * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 2) = 8
957   - * </pre>
958   - *
959   - * <p>Note that 'tail(String str, int n)' may be implemented as: </p>
960   - *
961   - * <pre>
962   - * str.substring(lastOrdinalIndexOf(str, "\n", n) + 1)
963   - * </pre>
964   - *
965   - * @param str the String to check, may be null
966   - * @param searchStr the String to find, may be null
967   - * @param ordinal the n-th last <code>searchStr</code> to find
968   - * @return the n-th last index of the search String,
969   - * <code>-1</code> (<code>INDEX_NOT_FOUND</code>) if no match or <code>null</code> string input
970   - * @since 2.5
971   - */
972   - public static int lastOrdinalIndexOf(String str, String searchStr, int ordinal) {
973   - return ordinalIndexOf(str, searchStr, ordinal, true);
974   - }
975   -
976   - /**
977   - * <p>Finds the first index within a String, handling <code>null</code>.
978   - * This method uses {@link String#lastIndexOf(String, int)}.</p>
979   - *
980   - * <p>A <code>null</code> String will return <code>-1</code>.
981   - * A negative start position returns <code>-1</code>.
982   - * An empty ("") search String always matches unless the start position is negative.
983   - * A start position greater than the string length searches the whole string.</p>
984   - *
985   - * <pre>
986   - * StringUtils.lastIndexOf(null, *, *) = -1
987   - * StringUtils.lastIndexOf(*, null, *) = -1
988   - * StringUtils.lastIndexOf("aabaabaa", "a", 8) = 7
989   - * StringUtils.lastIndexOf("aabaabaa", "b", 8) = 5
990   - * StringUtils.lastIndexOf("aabaabaa", "ab", 8) = 4
991   - * StringUtils.lastIndexOf("aabaabaa", "b", 9) = 5
992   - * StringUtils.lastIndexOf("aabaabaa", "b", -1) = -1
993   - * StringUtils.lastIndexOf("aabaabaa", "a", 0) = 0
994   - * StringUtils.lastIndexOf("aabaabaa", "b", 0) = -1
995   - * </pre>
996   - *
997   - * @param str the String to check, may be null
998   - * @param searchStr the String to find, may be null
999   - * @param startPos the start position, negative treated as zero
1000   - * @return the first index of the search String,
1001   - * -1 if no match or <code>null</code> string input
1002   - * @since 2.0
1003   - */
1004   - public static int lastIndexOf(String str, String searchStr, int startPos) {
1005   - if (str == null || searchStr == null) {
1006   - return INDEX_NOT_FOUND;
1007   - }
1008   - return str.lastIndexOf(searchStr, startPos);
1009   - }
1010   -
1011   - /**
1012   - * <p>Case in-sensitive find of the last index within a String.</p>
1013   - *
1014   - * <p>A <code>null</code> String will return <code>-1</code>.
1015   - * A negative start position returns <code>-1</code>.
1016   - * An empty ("") search String always matches unless the start position is negative.
1017   - * A start position greater than the string length searches the whole string.</p>
1018   - *
1019   - * <pre>
1020   - * StringUtils.lastIndexOfIgnoreCase(null, *) = -1
1021   - * StringUtils.lastIndexOfIgnoreCase(*, null) = -1
1022   - * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A") = 7
1023   - * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B") = 5
1024   - * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB") = 4
1025   - * </pre>
1026   - *
1027   - * @param str the String to check, may be null
1028   - * @param searchStr the String to find, may be null
1029   - * @return the first index of the search String,
1030   - * -1 if no match or <code>null</code> string input
1031   - * @since 2.5
1032   - */
1033   - public static int lastIndexOfIgnoreCase(String str, String searchStr) {
1034   - if (str == null || searchStr == null) {
1035   - return INDEX_NOT_FOUND;
1036   - }
1037   - return lastIndexOfIgnoreCase(str, searchStr, str.length());
1038   - }
1039   -
1040   - /**
1041   - * <p>Case in-sensitive find of the last index within a String
1042   - * from the specified position.</p>
1043   - *
1044   - * <p>A <code>null</code> String will return <code>-1</code>.
1045   - * A negative start position returns <code>-1</code>.
1046   - * An empty ("") search String always matches unless the start position is negative.
1047   - * A start position greater than the string length searches the whole string.</p>
1048   - *
1049   - * <pre>
1050   - * StringUtils.lastIndexOfIgnoreCase(null, *, *) = -1
1051   - * StringUtils.lastIndexOfIgnoreCase(*, null, *) = -1
1052   - * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 8) = 7
1053   - * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 8) = 5
1054   - * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB", 8) = 4
1055   - * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 9) = 5
1056   - * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", -1) = -1
1057   - * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 0) = 0
1058   - * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 0) = -1
1059   - * </pre>
1060   - *
1061   - * @param str the String to check, may be null
1062   - * @param searchStr the String to find, may be null
1063   - * @param startPos the start position
1064   - * @return the first index of the search String,
1065   - * -1 if no match or <code>null</code> string input
1066   - * @since 2.5
1067   - */
1068   - public static int lastIndexOfIgnoreCase(String str, String searchStr, int startPos) {
1069   - if (str == null || searchStr == null) {
1070   - return INDEX_NOT_FOUND;
1071   - }
1072   - if (startPos > (str.length() - searchStr.length())) {
1073   - startPos = str.length() - searchStr.length();
1074   - }
1075   - if (startPos < 0) {
1076   - return INDEX_NOT_FOUND;
1077   - }
1078   - if (searchStr.length() == 0) {
1079   - return startPos;
1080   - }
1081   -
1082   - for (int i = startPos; i >= 0; i--) {
1083   - if (str.regionMatches(true, i, searchStr, 0, searchStr.length())) {
1084   - return i;
1085   - }
1086   - }
1087   - return INDEX_NOT_FOUND;
1088   - }
1089   -
1090   - // Contains
1091   - //-----------------------------------------------------------------------
1092   - /**
1093   - * <p>Checks if String contains a search character, handling <code>null</code>.
1094   - * This method uses {@link String#indexOf(int)}.</p>
1095   - *
1096   - * <p>A <code>null</code> or empty ("") String will return <code>false</code>.</p>
1097   - *
1098   - * <pre>
1099   - * StringUtils.contains(null, *) = false
1100   - * StringUtils.contains("", *) = false
1101   - * StringUtils.contains("abc", 'a') = true
1102   - * StringUtils.contains("abc", 'z') = false
1103   - * </pre>
1104   - *
1105   - * @param str the String to check, may be null
1106   - * @param searchChar the character to find
1107   - * @return true if the String contains the search character,
1108   - * false if not or <code>null</code> string input
1109   - * @since 2.0
1110   - */
1111   - public static boolean contains(String str, char searchChar) {
1112   - if (isEmpty(str)) {
1113   - return false;
1114   - }
1115   - return str.indexOf(searchChar) >= 0;
1116   - }
1117   -
1118   - /**
1119   - * <p>Checks if String contains a search String, handling <code>null</code>.
1120   - * This method uses {@link String#indexOf(String)}.</p>
1121   - *
1122   - * <p>A <code>null</code> String will return <code>false</code>.</p>
1123   - *
1124   - * <pre>
1125   - * StringUtils.contains(null, *) = false
1126   - * StringUtils.contains(*, null) = false
1127   - * StringUtils.contains("", "") = true
1128   - * StringUtils.contains("abc", "") = true
1129   - * StringUtils.contains("abc", "a") = true
1130   - * StringUtils.contains("abc", "z") = false
1131   - * </pre>
1132   - *
1133   - * @param str the String to check, may be null
1134   - * @param searchStr the String to find, may be null
1135   - * @return true if the String contains the search String,
1136   - * false if not or <code>null</code> string input
1137   - * @since 2.0
1138   - */
1139   - public static boolean contains(String str, String searchStr) {
1140   - if (str == null || searchStr == null) {
1141   - return false;
1142   - }
1143   - return str.indexOf(searchStr) >= 0;
1144   - }
1145   -
1146   - /**
1147   - * <p>Checks if String contains a search String irrespective of case,
1148   - * handling <code>null</code>. Case-insensitivity is defined as by
1149   - * {@link String#equalsIgnoreCase(String)}.
1150   - *
1151   - * <p>A <code>null</code> String will return <code>false</code>.</p>
1152   - *
1153   - * <pre>
1154   - * StringUtils.contains(null, *) = false
1155   - * StringUtils.contains(*, null) = false
1156   - * StringUtils.contains("", "") = true
1157   - * StringUtils.contains("abc", "") = true
1158   - * StringUtils.contains("abc", "a") = true
1159   - * StringUtils.contains("abc", "z") = false
1160   - * StringUtils.contains("abc", "A") = true
1161   - * StringUtils.contains("abc", "Z") = false
1162   - * </pre>
1163   - *
1164   - * @param str the String to check, may be null
1165   - * @param searchStr the String to find, may be null
1166   - * @return true if the String contains the search String irrespective of
1167   - * case or false if not or <code>null</code> string input
1168   - */
1169   - public static boolean containsIgnoreCase(String str, String searchStr) {
1170   - if (str == null || searchStr == null) {
1171   - return false;
1172   - }
1173   - int len = searchStr.length();
1174   - int max = str.length() - len;
1175   - for (int i = 0; i <= max; i++) {
1176   - if (str.regionMatches(true, i, searchStr, 0, len)) {
1177   - return true;
1178   - }
1179   - }
1180   - return false;
1181   - }
1182   -
1183   -
1184   - // IndexOfAny strings
1185   - //-----------------------------------------------------------------------
1186   - /**
1187   - * <p>Find the first index of any of a set of potential substrings.</p>
1188   - *
1189   - * <p>A <code>null</code> String will return <code>-1</code>.
1190   - * A <code>null</code> or zero length search array will return <code>-1</code>.
1191   - * A <code>null</code> search array entry will be ignored, but a search
1192   - * array containing "" will return <code>0</code> if <code>str</code> is not
1193   - * null. This method uses {@link String#indexOf(String)}.</p>
1194   - *
1195   - * <pre>
1196   - * StringUtils.indexOfAny(null, *) = -1
1197   - * StringUtils.indexOfAny(*, null) = -1
1198   - * StringUtils.indexOfAny(*, []) = -1
1199   - * StringUtils.indexOfAny("zzabyycdxx", ["ab","cd"]) = 2
1200   - * StringUtils.indexOfAny("zzabyycdxx", ["cd","ab"]) = 2
1201   - * StringUtils.indexOfAny("zzabyycdxx", ["mn","op"]) = -1
1202   - * StringUtils.indexOfAny("zzabyycdxx", ["zab","aby"]) = 1
1203   - * StringUtils.indexOfAny("zzabyycdxx", [""]) = 0
1204   - * StringUtils.indexOfAny("", [""]) = 0
1205   - * StringUtils.indexOfAny("", ["a"]) = -1
1206   - * </pre>
1207   - *
1208   - * @param str the String to check, may be null
1209   - * @param searchStrs the Strings to search for, may be null
1210   - * @return the first index of any of the searchStrs in str, -1 if no match
1211   - */
1212   - public static int indexOfAny(String str, String[] searchStrs) {
1213   - if ((str == null) || (searchStrs == null)) {
1214   - return INDEX_NOT_FOUND;
1215   - }
1216   - int sz = searchStrs.length;
1217   -
1218   - // String's can't have a MAX_VALUEth index.
1219   - int ret = Integer.MAX_VALUE;
1220   -
1221   - int tmp = 0;
1222   - for (int i = 0; i < sz; i++) {
1223   - String search = searchStrs[i];
1224   - if (search == null) {
1225   - continue;
1226   - }
1227   - tmp = str.indexOf(search);
1228   - if (tmp == INDEX_NOT_FOUND) {
1229   - continue;
1230   - }
1231   -
1232   - if (tmp < ret) {
1233   - ret = tmp;
1234   - }
1235   - }
1236   -
1237   - return (ret == Integer.MAX_VALUE) ? INDEX_NOT_FOUND : ret;
1238   - }
1239   -
1240   - /**
1241   - * <p>Find the latest index of any of a set of potential substrings.</p>
1242   - *
1243   - * <p>A <code>null</code> String will return <code>-1</code>.
1244   - * A <code>null</code> search array will return <code>-1</code>.
1245   - * A <code>null</code> or zero length search array entry will be ignored,
1246   - * but a search array containing "" will return the length of <code>str</code>
1247   - * if <code>str</code> is not null. This method uses {@link String#indexOf(String)}</p>
1248   - *
1249   - * <pre>
1250   - * StringUtils.lastIndexOfAny(null, *) = -1
1251   - * StringUtils.lastIndexOfAny(*, null) = -1
1252   - * StringUtils.lastIndexOfAny(*, []) = -1
1253   - * StringUtils.lastIndexOfAny(*, [null]) = -1
1254   - * StringUtils.lastIndexOfAny("zzabyycdxx", ["ab","cd"]) = 6
1255   - * StringUtils.lastIndexOfAny("zzabyycdxx", ["cd","ab"]) = 6
1256   - * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn","op"]) = -1
1257   - * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn","op"]) = -1
1258   - * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn",""]) = 10
1259   - * </pre>
1260   - *
1261   - * @param str the String to check, may be null
1262   - * @param searchStrs the Strings to search for, may be null
1263   - * @return the last index of any of the Strings, -1 if no match
1264   - */
1265   - public static int lastIndexOfAny(String str, String[] searchStrs) {
1266   - if ((str == null) || (searchStrs == null)) {
1267   - return INDEX_NOT_FOUND;
1268   - }
1269   - int sz = searchStrs.length;
1270   - int ret = INDEX_NOT_FOUND;
1271   - int tmp = 0;
1272   - for (int i = 0; i < sz; i++) {
1273   - String search = searchStrs[i];
1274   - if (search == null) {
1275   - continue;
1276   - }
1277   - tmp = str.lastIndexOf(search);
1278   - if (tmp > ret) {
1279   - ret = tmp;
1280   - }
1281   - }
1282   - return ret;
1283   - }
1284   -
1285   - // Substring
1286   - //-----------------------------------------------------------------------
1287   - /**
1288   - * <p>Gets a substring from the specified String avoiding exceptions.</p>
1289   - *
1290   - * <p>A negative start position can be used to start <code>n</code>
1291   - * characters from the end of the String.</p>
1292   - *
1293   - * <p>A <code>null</code> String will return <code>null</code>.
1294   - * An empty ("") String will return "".</p>
1295   - *
1296   - * <pre>
1297   - * StringUtils.substring(null, *) = null
1298   - * StringUtils.substring("", *) = ""
1299   - * StringUtils.substring("abc", 0) = "abc"
1300   - * StringUtils.substring("abc", 2) = "c"
1301   - * StringUtils.substring("abc", 4) = ""
1302   - * StringUtils.substring("abc", -2) = "bc"
1303   - * StringUtils.substring("abc", -4) = "abc"
1304   - * </pre>
1305   - *
1306   - * @param str the String to get the substring from, may be null
1307   - * @param start the position to start from, negative means
1308   - * count back from the end of the String by this many characters
1309   - * @return substring from start position, <code>null</code> if null String input
1310   - */
1311   - public static String substring(String str, int start) {
1312   - if (str == null) {
1313   - return null;
1314   - }
1315   -
1316   - // handle negatives, which means last n characters
1317   - if (start < 0) {
1318   - start = str.length() + start; // remember start is negative
1319   - }
1320   -
1321   - if (start < 0) {
1322   - start = 0;
1323   - }
1324   - if (start > str.length()) {
1325   - return EMPTY;
1326   - }
1327   -
1328   - return str.substring(start);
1329   - }
1330   -
1331   - /**
1332   - * <p>Gets a substring from the specified String avoiding exceptions.</p>
1333   - *
1334   - * <p>A negative start position can be used to start/end <code>n</code>
1335   - * characters from the end of the String.</p>
1336   - *
1337   - * <p>The returned substring starts with the character in the <code>start</code>
1338   - * position and ends before the <code>end</code> position. All position counting is
1339   - * zero-based -- i.e., to start at the beginning of the string use
1340   - * <code>start = 0</code>. Negative start and end positions can be used to
1341   - * specify offsets relative to the end of the String.</p>
1342   - *
1343   - * <p>If <code>start</code> is not strictly to the left of <code>end</code>, ""
1344   - * is returned.</p>
1345   - *
1346   - * <pre>
1347   - * StringUtils.substring(null, *, *) = null
1348   - * StringUtils.substring("", * , *) = "";
1349   - * StringUtils.substring("abc", 0, 2) = "ab"
1350   - * StringUtils.substring("abc", 2, 0) = ""
1351   - * StringUtils.substring("abc", 2, 4) = "c"
1352   - * StringUtils.substring("abc", 4, 6) = ""
1353   - * StringUtils.substring("abc", 2, 2) = ""
1354   - * StringUtils.substring("abc", -2, -1) = "b"
1355   - * StringUtils.substring("abc", -4, 2) = "ab"
1356   - * </pre>
1357   - *
1358   - * @param str the String to get the substring from, may be null
1359   - * @param start the position to start from, negative means
1360   - * count back from the end of the String by this many characters
1361   - * @param end the position to end at (exclusive), negative means
1362   - * count back from the end of the String by this many characters
1363   - * @return substring from start position to end positon,
1364   - * <code>null</code> if null String input
1365   - */
1366   - public static String substring(String str, int start, int end) {
1367   - if (str == null) {
1368   - return null;
1369   - }
1370   -
1371   - // handle negatives
1372   - if (end < 0) {
1373   - end = str.length() + end; // remember end is negative
1374   - }
1375   - if (start < 0) {
1376   - start = str.length() + start; // remember start is negative
1377   - }
1378   -
1379   - // check length next
1380   - if (end > str.length()) {
1381   - end = str.length();
1382   - }
1383   -
1384   - // if start is greater than end, return ""
1385   - if (start > end) {
1386   - return EMPTY;
1387   - }
1388   -
1389   - if (start < 0) {
1390   - start = 0;
1391   - }
1392   - if (end < 0) {
1393   - end = 0;
1394   - }
1395   -
1396   - return str.substring(start, end);
1397   - }
1398   -
1399   - // Left/Right/Mid
1400   - //-----------------------------------------------------------------------
1401   - /**
1402   - * <p>Gets the leftmost <code>len</code> characters of a String.</p>
1403   - *
1404   - * <p>If <code>len</code> characters are not available, or the
1405   - * String is <code>null</code>, the String will be returned without
1406   - * an exception. An empty String is returned if len is negative.</p>
1407   - *
1408   - * <pre>
1409   - * StringUtils.left(null, *) = null
1410   - * StringUtils.left(*, -ve) = ""
1411   - * StringUtils.left("", *) = ""
1412   - * StringUtils.left("abc", 0) = ""
1413   - * StringUtils.left("abc", 2) = "ab"
1414   - * StringUtils.left("abc", 4) = "abc"
1415   - * </pre>
1416   - *
1417   - * @param str the String to get the leftmost characters from, may be null
1418   - * @param len the length of the required String
1419   - * @return the leftmost characters, <code>null</code> if null String input
1420   - */
1421   - public static String left(String str, int len) {
1422   - if (str == null) {
1423   - return null;
1424   - }
1425   - if (len < 0) {
1426   - return EMPTY;
1427   - }
1428   - if (str.length() <= len) {
1429   - return str;
1430   - }
1431   - return str.substring(0, len);
1432   - }
1433   -
1434   - /**
1435   - * <p>Gets the rightmost <code>len</code> characters of a String.</p>
1436   - *
1437   - * <p>If <code>len</code> characters are not available, or the String
1438   - * is <code>null</code>, the String will be returned without an
1439   - * an exception. An empty String is returned if len is negative.</p>
1440   - *
1441   - * <pre>
1442   - * StringUtils.right(null, *) = null
1443   - * StringUtils.right(*, -ve) = ""
1444   - * StringUtils.right("", *) = ""
1445   - * StringUtils.right("abc", 0) = ""
1446   - * StringUtils.right("abc", 2) = "bc"
1447   - * StringUtils.right("abc", 4) = "abc"
1448   - * </pre>
1449   - *
1450   - * @param str the String to get the rightmost characters from, may be null
1451   - * @param len the length of the required String
1452   - * @return the rightmost characters, <code>null</code> if null String input
1453   - */
1454   - public static String right(String str, int len) {
1455   - if (str == null) {
1456   - return null;
1457   - }
1458   - if (len < 0) {
1459   - return EMPTY;
1460   - }
1461   - if (str.length() <= len) {
1462   - return str;
1463   - }
1464   - return str.substring(str.length() - len);
1465   - }
1466   -
1467   - /**
1468   - * <p>Gets <code>len</code> characters from the middle of a String.</p>
1469   - *
1470   - * <p>If <code>len</code> characters are not available, the remainder
1471   - * of the String will be returned without an exception. If the
1472   - * String is <code>null</code>, <code>null</code> will be returned.
1473   - * An empty String is returned if len is negative or exceeds the
1474   - * length of <code>str</code>.</p>
1475   - *
1476   - * <pre>
1477   - * StringUtils.mid(null, *, *) = null
1478   - * StringUtils.mid(*, *, -ve) = ""
1479   - * StringUtils.mid("", 0, *) = ""
1480   - * StringUtils.mid("abc", 0, 2) = "ab"
1481   - * StringUtils.mid("abc", 0, 4) = "abc"
1482   - * StringUtils.mid("abc", 2, 4) = "c"
1483   - * StringUtils.mid("abc", 4, 2) = ""
1484   - * StringUtils.mid("abc", -2, 2) = "ab"
1485   - * </pre>
1486   - *
1487   - * @param str the String to get the characters from, may be null
1488   - * @param pos the position to start from, negative treated as zero
1489   - * @param len the length of the required String
1490   - * @return the middle characters, <code>null</code> if null String input
1491   - */
1492   - public static String mid(String str, int pos, int len) {
1493   - if (str == null) {
1494   - return null;
1495   - }
1496   - if (len < 0 || pos > str.length()) {
1497   - return EMPTY;
1498   - }
1499   - if (pos < 0) {
1500   - pos = 0;
1501   - }
1502   - if (str.length() <= (pos + len)) {
1503   - return str.substring(pos);
1504   - }
1505   - return str.substring(pos, pos + len);
1506   - }
1507   -
1508   - // SubStringAfter/SubStringBefore
1509   - //-----------------------------------------------------------------------
1510   - /**
1511   - * <p>Gets the substring before the first occurrence of a separator.
1512   - * The separator is not returned.</p>
1513   - *
1514   - * <p>A <code>null</code> string input will return <code>null</code>.
1515   - * An empty ("") string input will return the empty string.
1516   - * A <code>null</code> separator will return the input string.</p>
1517   - *
1518   - * <p>If nothing is found, the string input is returned.</p>
1519   - *
1520   - * <pre>
1521   - * StringUtils.substringBefore(null, *) = null
1522   - * StringUtils.substringBefore("", *) = ""
1523   - * StringUtils.substringBefore("abc", "a") = ""
1524   - * StringUtils.substringBefore("abcba", "b") = "a"
1525   - * StringUtils.substringBefore("abc", "c") = "ab"
1526   - * StringUtils.substringBefore("abc", "d") = "abc"
1527   - * StringUtils.substringBefore("abc", "") = ""
1528   - * StringUtils.substringBefore("abc", null) = "abc"
1529   - * </pre>
1530   - *
1531   - * @param str the String to get a substring from, may be null
1532   - * @param separator the String to search for, may be null
1533   - * @return the substring before the first occurrence of the separator,
1534   - * <code>null</code> if null String input
1535   - * @since 2.0
1536   - */
1537   - public static String substringBefore(String str, String separator) {
1538   - if (isEmpty(str) || separator == null) {
1539   - return str;
1540   - }
1541   - if (separator.length() == 0) {
1542   - return EMPTY;
1543   - }
1544   - int pos = str.indexOf(separator);
1545   - if (pos == INDEX_NOT_FOUND) {
1546   - return str;
1547   - }
1548   - return str.substring(0, pos);
1549   - }
1550   -
1551   - /**
1552   - * <p>Gets the substring after the first occurrence of a separator.
1553   - * The separator is not returned.</p>
1554   - *
1555   - * <p>A <code>null</code> string input will return <code>null</code>.
1556   - * An empty ("") string input will return the empty string.
1557   - * A <code>null</code> separator will return the empty string if the
1558   - * input string is not <code>null</code>.</p>
1559   - *
1560   - * <p>If nothing is found, the empty string is returned.</p>
1561   - *
1562   - * <pre>
1563   - * StringUtils.substringAfter(null, *) = null
1564   - * StringUtils.substringAfter("", *) = ""
1565   - * StringUtils.substringAfter(*, null) = ""
1566   - * StringUtils.substringAfter("abc", "a") = "bc"
1567   - * StringUtils.substringAfter("abcba", "b") = "cba"
1568   - * StringUtils.substringAfter("abc", "c") = ""
1569   - * StringUtils.substringAfter("abc", "d") = ""
1570   - * StringUtils.substringAfter("abc", "") = "abc"
1571   - * </pre>
1572   - *
1573   - * @param str the String to get a substring from, may be null
1574   - * @param separator the String to search for, may be null
1575   - * @return the substring after the first occurrence of the separator,
1576   - * <code>null</code> if null String input
1577   - * @since 2.0
1578   - */
1579   - public static String substringAfter(String str, String separator) {
1580   - if (isEmpty(str)) {
1581   - return str;
1582   - }
1583   - if (separator == null) {
1584   - return EMPTY;
1585   - }
1586   - int pos = str.indexOf(separator);
1587   - if (pos == INDEX_NOT_FOUND) {
1588   - return EMPTY;
1589   - }
1590   - return str.substring(pos + separator.length());
1591   - }
1592   -
1593   - /**
1594   - * <p>Gets the substring before the last occurrence of a separator.
1595   - * The separator is not returned.</p>
1596   - *
1597   - * <p>A <code>null</code> string input will return <code>null</code>.
1598   - * An empty ("") string input will return the empty string.
1599   - * An empty or <code>null</code> separator will return the input string.</p>
1600   - *
1601   - * <p>If nothing is found, the string input is returned.</p>
1602   - *
1603   - * <pre>
1604   - * StringUtils.substringBeforeLast(null, *) = null
1605   - * StringUtils.substringBeforeLast("", *) = ""
1606   - * StringUtils.substringBeforeLast("abcba", "b") = "abc"
1607   - * StringUtils.substringBeforeLast("abc", "c") = "ab"
1608   - * StringUtils.substringBeforeLast("a", "a") = ""
1609   - * StringUtils.substringBeforeLast("a", "z") = "a"
1610   - * StringUtils.substringBeforeLast("a", null) = "a"
1611   - * StringUtils.substringBeforeLast("a", "") = "a"
1612   - * </pre>
1613   - *
1614   - * @param str the String to get a substring from, may be null
1615   - * @param separator the String to search for, may be null
1616   - * @return the substring before the last occurrence of the separator,
1617   - * <code>null</code> if null String input
1618   - * @since 2.0
1619   - */
1620   - public static String substringBeforeLast(String str, String separator) {
1621   - if (isEmpty(str) || isEmpty(separator)) {
1622   - return str;
1623   - }
1624   - int pos = str.lastIndexOf(separator);
1625   - if (pos == INDEX_NOT_FOUND) {
1626   - return str;
1627   - }
1628   - return str.substring(0, pos);
1629   - }
1630   -
1631   - /**
1632   - * <p>Gets the substring after the last occurrence of a separator.
1633   - * The separator is not returned.</p>
1634   - *
1635   - * <p>A <code>null</code> string input will return <code>null</code>.
1636   - * An empty ("") string input will return the empty string.
1637   - * An empty or <code>null</code> separator will return the empty string if
1638   - * the input string is not <code>null</code>.</p>
1639   - *
1640   - * <p>If nothing is found, the empty string is returned.</p>
1641   - *
1642   - * <pre>
1643   - * StringUtils.substringAfterLast(null, *) = null
1644   - * StringUtils.substringAfterLast("", *) = ""
1645   - * StringUtils.substringAfterLast(*, "") = ""
1646   - * StringUtils.substringAfterLast(*, null) = ""
1647   - * StringUtils.substringAfterLast("abc", "a") = "bc"
1648   - * StringUtils.substringAfterLast("abcba", "b") = "a"
1649   - * StringUtils.substringAfterLast("abc", "c") = ""
1650   - * StringUtils.substringAfterLast("a", "a") = ""
1651   - * StringUtils.substringAfterLast("a", "z") = ""
1652   - * </pre>
1653   - *
1654   - * @param str the String to get a substring from, may be null
1655   - * @param separator the String to search for, may be null
1656   - * @return the substring after the last occurrence of the separator,
1657   - * <code>null</code> if null String input
1658   - * @since 2.0
1659   - */
1660   - public static String substringAfterLast(String str, String separator) {
1661   - if (isEmpty(str)) {
1662   - return str;
1663   - }
1664   - if (isEmpty(separator)) {
1665   - return EMPTY;
1666   - }
1667   - int pos = str.lastIndexOf(separator);
1668   - if (pos == INDEX_NOT_FOUND || pos == (str.length() - separator.length())) {
1669   - return EMPTY;
1670   - }
1671   - return str.substring(pos + separator.length());
1672   - }
1673   -
1674   - // Substring between
1675   - //-----------------------------------------------------------------------
1676   - /**
1677   - * <p>Gets the String that is nested in between two instances of the
1678   - * same String.</p>
1679   - *
1680   - * <p>A <code>null</code> input String returns <code>null</code>.
1681   - * A <code>null</code> tag returns <code>null</code>.</p>
1682   - *
1683   - * <pre>
1684   - * StringUtils.substringBetween(null, *) = null
1685   - * StringUtils.substringBetween("", "") = ""
1686   - * StringUtils.substringBetween("", "tag") = null
1687   - * StringUtils.substringBetween("tagabctag", null) = null
1688   - * StringUtils.substringBetween("tagabctag", "") = ""
1689   - * StringUtils.substringBetween("tagabctag", "tag") = "abc"
1690   - * </pre>
1691   - *
1692   - * @param str the String containing the substring, may be null
1693   - * @param tag the String before and after the substring, may be null
1694   - * @return the substring, <code>null</code> if no match
1695   - * @since 2.0
1696   - */
1697   - public static String substringBetween(String str, String tag) {
1698   - return substringBetween(str, tag, tag);
1699   - }
1700   -
1701   - /**
1702   - * <p>Gets the String that is nested in between two Strings.
1703   - * Only the first match is returned.</p>
1704   - *
1705   - * <p>A <code>null</code> input String returns <code>null</code>.
1706   - * A <code>null</code> open/close returns <code>null</code> (no match).
1707   - * An empty ("") open and close returns an empty string.</p>
1708   - *
1709   - * <pre>
1710   - * StringUtils.substringBetween("wx[b]yz", "[", "]") = "b"
1711   - * StringUtils.substringBetween(null, *, *) = null
1712   - * StringUtils.substringBetween(*, null, *) = null
1713   - * StringUtils.substringBetween(*, *, null) = null
1714   - * StringUtils.substringBetween("", "", "") = ""
1715   - * StringUtils.substringBetween("", "", "]") = null
1716   - * StringUtils.substringBetween("", "[", "]") = null
1717   - * StringUtils.substringBetween("yabcz", "", "") = ""
1718   - * StringUtils.substringBetween("yabcz", "y", "z") = "abc"
1719   - * StringUtils.substringBetween("yabczyabcz", "y", "z") = "abc"
1720   - * </pre>
1721   - *
1722   - * @param str the String containing the substring, may be null
1723   - * @param open the String before the substring, may be null
1724   - * @param close the String after the substring, may be null
1725   - * @return the substring, <code>null</code> if no match
1726   - * @since 2.0
1727   - */
1728   - public static String substringBetween(String str, String open, String close) {
1729   - if (str == null || open == null || close == null) {
1730   - return null;
1731   - }
1732   - int start = str.indexOf(open);
1733   - if (start != INDEX_NOT_FOUND) {
1734   - int end = str.indexOf(close, start + open.length());
1735   - if (end != INDEX_NOT_FOUND) {
1736   - return str.substring(start + open.length(), end);
1737   - }
1738   - }
1739   - return null;
1740   - }
1741   -
1742   -}
1743 0 \ No newline at end of file
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/captcha/CaptchaController.java
1 1 package cn.iocoder.yudao.module.system.controller.admin.captcha;
2 2  
  3 +import cn.hutool.core.util.StrUtil;
3 4 import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
4 5 import com.anji.captcha.model.common.ResponseModel;
5 6 import com.anji.captcha.model.vo.CaptchaVO;
  7 +import com.anji.captcha.service.CaptchaService;
6 8 import io.swagger.annotations.Api;
7 9 import io.swagger.annotations.ApiOperation;
8 10 import org.springframework.web.bind.annotation.PostMapping;
... ... @@ -10,6 +12,7 @@ import org.springframework.web.bind.annotation.RequestBody;
10 12 import org.springframework.web.bind.annotation.RequestMapping;
11 13 import org.springframework.web.bind.annotation.RestController;
12 14  
  15 +import javax.annotation.Resource;
13 16 import javax.annotation.security.PermitAll;
14 17 import javax.servlet.http.HttpServletRequest;
15 18  
... ... @@ -24,24 +27,46 @@ import javax.servlet.http.HttpServletRequest;
24 27 @Api(tags = "管理后台 - 验证码")
25 28 @RestController("adminCaptchaController")
26 29 @RequestMapping("/system/captcha")
27   -public class CaptchaController extends com.anji.captcha.controller.CaptchaController {
  30 +public class CaptchaController {
  31 +
  32 + @Resource
  33 + private CaptchaService captchaService;
28 34  
29 35 @PostMapping({"/get"})
30 36 @ApiOperation("获得验证码")
31 37 @PermitAll
32 38 @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
33   - @Override
34 39 public ResponseModel get(@RequestBody CaptchaVO data, HttpServletRequest request) {
35   - return super.get(data, request);
  40 + assert request.getRemoteHost() != null;
  41 + data.setBrowserInfo(getRemoteId(request));
  42 + return captchaService.get(data);
36 43 }
37 44  
38 45 @PostMapping("/check")
39 46 @ApiOperation("校验验证码")
40 47 @PermitAll
41 48 @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
42   - @Override
43 49 public ResponseModel check(@RequestBody CaptchaVO data, HttpServletRequest request) {
44   - return super.check(data, request);
  50 + data.setBrowserInfo(getRemoteId(request));
  51 + return captchaService.check(data);
  52 + }
  53 +
  54 + public static String getRemoteId(HttpServletRequest request) {
  55 + String xfwd = request.getHeader("X-Forwarded-For");
  56 + String ip = getRemoteIpFromXfwd(xfwd);
  57 + String ua = request.getHeader("user-agent");
  58 + if (StrUtil.isNotBlank(ip)) {
  59 + return ip + ua;
  60 + }
  61 + return request.getRemoteAddr() + ua;
  62 + }
  63 +
  64 + private static String getRemoteIpFromXfwd(String xfwd) {
  65 + if (StrUtil.isNotBlank(xfwd)) {
  66 + String[] ipList = xfwd.split(",");
  67 + return StrUtil.trim(ipList[0]);
  68 + }
  69 + return null;
45 70 }
46 71  
47 72 }
... ...