Browse Source

增加验证码

chengyao 3 years ago
parent
commit
03d0fb4bd4

+ 15 - 0
pom.xml

@@ -36,6 +36,8 @@
         <aggregator.version>1.1.0</aggregator.version>
         <okhttp.version>4.2.2</okhttp.version>
         <easypoi.version>4.2.0</easypoi.version>
+        <patchca.version>1.1.2</patchca.version>
+        <hutool.version>5.0.7</hutool.version>
         <docker-maven-plugin.version>1.2.1</docker-maven-plugin.version>
         <docker.image.prefix>192.168.2.241:5000/diagbotcloud</docker.image.prefix>
         <registryUrl>http://192.168.2.241:5000/repository/diagbotcloud/</registryUrl>
@@ -108,6 +110,19 @@
             <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>com.bladejava</groupId>
+            <artifactId>blade-patchca</artifactId>
+            <version>${patchca.version}</version>
+
+        </dependency>
+
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+            <version>${hutool.version}</version>
+        </dependency>
+
         <!--swagger-->
         <dependency>
             <groupId>io.springfox</groupId>

+ 1 - 0
src/main/java/com/diagbot/config/ResourceServerConfigurer.java

@@ -38,6 +38,7 @@ public class ResourceServerConfigurer extends ResourceServerConfigurerAdapter {
                 .authorizeRequests()
                 .regexMatchers(".*swagger.*", ".*v2.*", ".*webjars.*", "/druid.*", "/actuator.*", "/hystrix.*").permitAll()
                 .antMatchers("/sys/user/getJwt").permitAll()
+                .antMatchers("/sys/user/getCaptcha").permitAll()
                 .antMatchers("/sys/user/getJwtNoPass").permitAll()
                 .antMatchers("/sys/user/refreshJwt").permitAll()
                 .antMatchers("/sys/user/checkToken").permitAll()

+ 1 - 0
src/main/java/com/diagbot/config/security/UrlAccessDecisionManager.java

@@ -81,6 +81,7 @@ public class UrlAccessDecisionManager implements AccessDecisionManager {
                 || matchers("/actuator/**", request)
                 || matchers("/hystrix/**", request)
                 || matchers("/sys/user/getJwt", request)
+                || matchers("/sys/user/getCaptcha", request)
                 || matchers("/sys/user/getJwtNoPass", request)
                 || matchers("/sys/user/refreshJwt", request)
                 || matchers("/sys/dictionaryInfo/getDictionary", request)

+ 61 - 0
src/main/java/com/diagbot/entity/ImageCaptchaParams.java

@@ -0,0 +1,61 @@
+package com.diagbot.entity;
+import lombok.Data;
+
+
+/**
+ * @Author chengyao
+ * @Date 2021/10/14 19:57
+ * @Version 1.0
+ */
+
+@Data
+public class ImageCaptchaParams {
+    /**
+     * 默认图片验证码的文字内容
+     */
+    public static final String DEFAULT_WORDS = "123456789abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ";
+    public static final String DEFAULT_FORMAT = "png";
+    /**
+     * 图片验证码宽度
+     */
+    private int width;
+    /**
+     * 图片验证码高度
+     */
+    private int height;
+    /**
+     * 最多生成几个文字
+     */
+    private int maxWordAmount;
+    /**
+     * 最小生成几个文字
+     */
+    private int minWordAmount;
+    /**
+     * 字体最大尺寸
+     */
+    private int maxFontSize;
+    /**
+     * 文字最小尺寸
+     */
+    private int minFontSize;
+    /**
+     * 生成图片验证码内容的字体
+     */
+    private String words;
+    /**
+     * 图片类型
+     */
+    private String format;
+
+    public ImageCaptchaParams(){
+        this.width = 105;
+        this.height = 35;
+        this.maxWordAmount = 4;
+        this.minWordAmount = 4;
+        this.minFontSize = 24;
+        this.maxFontSize = 25;
+        this.words = DEFAULT_WORDS;
+        this.format = DEFAULT_FORMAT;
+    }
+}

+ 51 - 2
src/main/java/com/diagbot/facade/SysUserFacade.java

@@ -6,8 +6,10 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.diagbot.client.AuthServiceClient;
 import com.diagbot.dto.*;
 import com.diagbot.entity.BasHospitalInfo;
+import com.diagbot.entity.ImageCaptchaParams;
 import com.diagbot.entity.JWT;
 import com.diagbot.entity.JwtStore;
+import com.diagbot.entity.SysHospitalSet;
 import com.diagbot.entity.SysUser;
 import com.diagbot.entity.SysUserDept;
 import com.diagbot.entity.SysUserHospital;
@@ -25,7 +27,9 @@ import com.diagbot.service.impl.SysUserServiceImpl;
 import com.diagbot.util.BeanUtil;
 import com.diagbot.util.DateUtil;
 import com.diagbot.util.EntityUtil;
+import com.diagbot.util.ImageCaptchaUtil;
 import com.diagbot.util.ListUtil;
+import com.diagbot.util.RedisUtils;
 import com.diagbot.util.StringUtil;
 import com.diagbot.util.SysUserUtils;
 import com.diagbot.vo.BasDeptInfoVO;
@@ -39,7 +43,17 @@ import org.springframework.security.crypto.factory.PasswordEncoderFactories;
 import org.springframework.security.crypto.password.PasswordEncoder;
 import org.springframework.security.oauth2.common.OAuth2AccessToken;
 import org.springframework.stereotype.Component;
-
+import org.springframework.util.DigestUtils;
+import org.springframework.util.StringUtils;
+
+import javax.imageio.ImageIO;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
 import java.util.*;
 import java.util.stream.Collectors;
 
@@ -83,6 +97,30 @@ public class SysUserFacade extends SysUserServiceImpl {
     private SysUserRoleFacade sysUserRoleFacade;
     @Autowired
     private SysDictionaryFacade sysDictionaryFacade;
+    @Autowired
+    private SysHospitalSetFacade sysHospitalSetFacade;
+    @Autowired
+    private RedisUtils redisUtils;
+
+
+
+
+    public void getCaptcha(HttpServletRequest request, HttpServletResponse response) throws IOException {
+        response.setContentType("image/png");
+        response.setHeader("Pragma", "no-cache");
+        response.setHeader("Cache-Control", "no-cache");
+        response.setDateHeader("Expires", 0);
+        HttpSession session = request.getSession();
+        String captchaId = session.getId();
+        ServletOutputStream outputStream = response.getOutputStream();
+        ImageCaptchaUtil imageCaptchaUtil = new ImageCaptchaUtil();
+        BufferedImage image = imageCaptchaUtil.createRandom();
+        String captcha = imageCaptchaUtil.getText();
+        redisUtils.set("user:captchaIds:" + captchaId, captcha, 60 * 3);
+        ImageIO.write(image, ImageCaptchaParams.DEFAULT_FORMAT, outputStream);
+        outputStream.flush();
+        outputStream.close();
+    }
 
     /**
      * 获取jwt
@@ -91,7 +129,7 @@ public class SysUserFacade extends SysUserServiceImpl {
      * @param password 密码
      * @return jwt
      */
-    public JwtDTO getJwt(String username, String password) {
+    public JwtDTO getJwt(HttpServletRequest request, String username, String password, String captcha) {
         JwtDTO data = new JwtDTO();
         if (StringUtil.isBlank(username)) {
             throw new CommonException(CommonErrorCode.PARAM_IS_NULL,
@@ -101,6 +139,16 @@ public class SysUserFacade extends SysUserServiceImpl {
             throw new CommonException(CommonErrorCode.PARAM_IS_NULL,
                     "请输入密码");
         }
+        if (StringUtils.isEmpty(captcha)) {
+            throw new CommonException(CommonErrorCode.PARAM_IS_NULL,
+                    "请输入验证码");
+        }
+        // 验证码校验
+        String captchaId = request.getSession().getId();
+        Object captchaObject = redisUtils.get("user:captchaIds:" + captchaId);
+        if (null == captchaObject || StringUtil.isBlank(captchaObject.toString()) || !captchaObject.toString().trim().equalsIgnoreCase(captcha)) {
+            throw new CommonException(CommonErrorCode.PARAM_IS_ERROR, "验证码错误");
+        }
         QueryWrapper<SysUser> userQueryWrapper = new QueryWrapper<>();
         userQueryWrapper.eq("username", username)
                 .eq("status", StatusEnum.Enable.getKey())
@@ -118,6 +166,7 @@ public class SysUserFacade extends SysUserServiceImpl {
         if (null == jwt) {
             throw new CommonException(ServiceErrorCode.GET_TOKEN_FAIL);
         }
+        redisUtils.del("user:captchaIds:" + captchaId);
         data.setAccessToken(jwt.getAccess_token());
         data.setRefreshToken(jwt.getRefresh_token());
         data.setType(user.getType());

+ 60 - 0
src/main/java/com/diagbot/util/ImageCaptchaUtil.java

@@ -0,0 +1,60 @@
+package com.diagbot.util;
+
+import com.diagbot.entity.ImageCaptchaParams;
+import org.patchca.color.SingleColorFactory;
+import org.patchca.filter.predefined.CurvesRippleFilterFactory;
+import org.patchca.font.RandomFontFactory;
+import org.patchca.service.Captcha;
+import org.patchca.service.ConfigurableCaptchaService;
+import org.patchca.word.RandomWordFactory;
+
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+
+/**
+ * @author huangrusheng
+ * @version 1.0
+ * @date 2021/5/20 9:54
+ */
+public class ImageCaptchaUtil {
+    private String text;
+
+    /**
+     * 以Web的img识别的base64返回
+     * @param
+     * @return 图片文字内容+base64格式的img标签识别的图片
+     * @throws IOException
+     */
+    public BufferedImage createRandom() throws IOException{
+        ImageCaptchaParams params = new ImageCaptchaParams();
+        ConfigurableCaptchaService  captchaService = new ConfigurableCaptchaService();
+        captchaService.setColorFactory(new SingleColorFactory(Color.black));
+        CurvesRippleFilterFactory curvesRippleFilterFactory = new CurvesRippleFilterFactory();
+        curvesRippleFilterFactory.setColorFactory(captchaService.getColorFactory());
+        curvesRippleFilterFactory.setStrokeMin(1);
+        curvesRippleFilterFactory.setStrokeMax(1.5f);
+        captchaService.setFilterFactory(curvesRippleFilterFactory);
+        captchaService.setHeight(params.getHeight());
+        captchaService.setWidth(params.getWidth());
+        RandomWordFactory wordFactory = new RandomWordFactory();
+        wordFactory.setCharacters(params.getWords());
+        wordFactory.setMaxLength(params.getMaxWordAmount());
+        wordFactory.setMinLength(params.getMinWordAmount());
+        captchaService.setWordFactory(wordFactory);
+        RandomFontFactory fontFactory = new RandomFontFactory();
+        fontFactory.setMaxSize(params.getMaxFontSize());
+        fontFactory.setMinSize(params.getMinFontSize());
+        captchaService.setFontFactory(fontFactory);
+        Captcha captcha = captchaService.getCaptcha();
+        this.text = captcha.getChallenge();
+        return captcha.getImage();
+    }
+
+    /**
+     * 获取验证码文本的方法
+     */
+    public String getText() {
+        return text;
+    }
+}

+ 611 - 0
src/main/java/com/diagbot/util/RedisUtils.java

@@ -0,0 +1,611 @@
+
+package com.diagbot.util;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+@Component
+public class RedisUtils {
+    @Autowired
+    private RedisTemplate<String, Object> redisTemplate;
+
+    public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
+        this.redisTemplate = redisTemplate;
+    }
+    // =============================common============================
+
+    /**
+     * 普通缓存获取
+     *
+     * @param
+     * @return 值
+     */
+    @Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
+    public Set<String> keys(String pattern) {
+        return redisTemplate.keys(pattern);
+    }
+
+    /**
+     * 指定缓存失效时间
+     *
+     * @param key  键
+     * @param time 时间(秒)
+     * @return
+     */
+    public boolean expire(String key, long time) {
+        try {
+            if (time > 0) {
+                redisTemplate.expire(key, time, TimeUnit.SECONDS);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 根据key 获取过期时间
+     *
+     * @param key 键 不能为null
+     * @return 时间(秒) 返回0代表为永久有效
+     */
+    @Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
+    public long getExpire(String key) {
+        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
+    }
+
+    /**
+     * 判断key是否存在
+     *
+     * @param key 键
+     * @return true 存在 false不存在
+     */
+    @Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
+    public boolean hasKey(String key) {
+        try {
+            return redisTemplate.hasKey(key);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 删除缓存
+     *
+     * @param key 可以传一个值 或多个
+     */
+    @SuppressWarnings("unchecked")
+    public void del(String... key) {
+        if (key != null && key.length > 0) {
+            if (key.length == 1) {
+                redisTemplate.delete(key[0]);
+            } else {
+                redisTemplate.delete(CollectionUtils.arrayToList(key));
+            }
+        }
+    }
+
+    // ============================String=============================
+
+    /**
+     * 普通缓存获取
+     *
+     * @param key 键
+     * @return 值
+     */
+    @Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
+    public Object get(String key) {
+        return key == null ? null : redisTemplate.opsForValue().get(key);
+    }
+
+    /**
+     * 普通缓存放入
+     *
+     * @param key   键
+     * @param value 值
+     * @return true成功 false失败
+     */
+    public boolean set(String key, Object value) {
+        try {
+            redisTemplate.opsForValue().set(key, value);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+
+    }
+
+    /**
+     * 普通缓存放入并设置时间
+     *
+     * @param key   键
+     * @param value 值
+     * @param time  时间(秒) time要大于0 如果time小于等于0 将设置无限期
+     * @return true成功 false 失败
+     */
+    public boolean set(String key, Object value, long time) {
+        try {
+            if (time > 0) {
+                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
+            } else {
+                set(key, value);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 递增
+     *
+     * @param key   键
+     * @param delta 要增加几(大于0)
+     * @return
+     */
+    public long incr(String key, long delta) {
+        if (delta < 0) {
+            throw new RuntimeException("递增因子必须大于0");
+        }
+        return redisTemplate.opsForValue().increment(key, delta);
+    }
+
+    /**
+     * 递减
+     *
+     * @param key   键
+     * @param delta 要减少几(小于0)
+     * @return
+     */
+    public long decr(String key, long delta) {
+        if (delta < 0) {
+            throw new RuntimeException("递减因子必须大于0");
+        }
+        return redisTemplate.opsForValue().increment(key, -delta);
+    }
+
+    // ================================Map=================================
+
+    /**
+     * HashGet
+     *
+     * @param key  键 不能为null
+     * @param item 项 不能为null
+     * @return 值
+     */
+    @Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
+    public Object hget(String key, String item) {
+        return redisTemplate.opsForHash().get(key, item);
+    }
+
+    /**
+     * 获取hashKey对应的所有键值
+     *
+     * @param key 键
+     * @return 对应的多个键值
+     */
+    @Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
+    public Map<Object, Object> hmget(String key) {
+        return redisTemplate.opsForHash().entries(key);
+    }
+
+    /**
+     * HashSet
+     *
+     * @param key 键
+     * @param map 对应多个键值
+     * @return true 成功 false 失败
+     */
+    public boolean hmset(String key, Map<String, Object> map) {
+        try {
+            redisTemplate.opsForHash().putAll(key, map);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * HashSet 并设置时间
+     *
+     * @param key  键
+     * @param map  对应多个键值
+     * @param time 时间(秒)
+     * @return true成功 false失败
+     */
+    public boolean hmset(String key, Map<String, Object> map, long time) {
+        try {
+            redisTemplate.opsForHash().putAll(key, map);
+            if (time > 0) {
+                expire(key, time);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 向一张hash表中放入数据,如果不存在将创建
+     *
+     * @param key   键
+     * @param item  项
+     * @param value 值
+     * @return true 成功 false失败
+     */
+    public boolean hset(String key, String item, Object value) {
+        try {
+            redisTemplate.opsForHash().put(key, item, value);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 向一张hash表中放入数据,如果不存在将创建
+     *
+     * @param key   键
+     * @param item  项
+     * @param value 值
+     * @param time  时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
+     * @return true 成功 false失败
+     */
+    public boolean hset(String key, String item, Object value, long time) {
+        try {
+            redisTemplate.opsForHash().put(key, item, value);
+            if (time > 0) {
+                expire(key, time);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 删除hash表中的值
+     *
+     * @param key  键 不能为null
+     * @param item 项 可以使多个 不能为null
+     */
+    public void hdel(String key, Object... item) {
+        redisTemplate.opsForHash().delete(key, item);
+    }
+
+    /**
+     * 判断hash表中是否有该项的值
+     *
+     * @param key  键 不能为null
+     * @param item 项 不能为null
+     * @return true 存在 false不存在
+     */
+    @Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
+    public boolean hHasKey(String key, String item) {
+        return redisTemplate.opsForHash().hasKey(key, item);
+    }
+
+    /**
+     * hash递增 如果不存在,就会创建一个 并把新增后的值返回
+     *
+     * @param key  键
+     * @param item 项
+     * @param by   要增加几(大于0)
+     * @return
+     */
+    public double hincr(String key, String item, double by) {
+        return redisTemplate.opsForHash().increment(key, item, by);
+    }
+
+    /**
+     * hash递减
+     *
+     * @param key  键
+     * @param item 项
+     * @param by   要减少记(小于0)
+     * @return
+     */
+    public double hdecr(String key, String item, double by) {
+        return redisTemplate.opsForHash().increment(key, item, -by);
+    }
+
+    // ============================set=============================
+
+    /**
+     * 根据key获取Set中的所有值
+     *
+     * @param key 键
+     * @return
+     */
+    @Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
+    public Set<Object> sGet(String key) {
+        try {
+            return redisTemplate.opsForSet().members(key);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     * 根据value从一个set中查询,是否存在
+     *
+     * @param key   键
+     * @param value 值
+     * @return true 存在 false不存在
+     */
+    @Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
+    public boolean sHasKey(String key, Object value) {
+        try {
+            return redisTemplate.opsForSet().isMember(key, value);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 将数据放入set缓存
+     *
+     * @param key    键
+     * @param values 值 可以是多个
+     * @return 成功个数
+     */
+    public long sSet(String key, Object... values) {
+        try {
+            return redisTemplate.opsForSet().add(key, values);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0;
+        }
+    }
+
+    /**
+     * 将set数据放入缓存
+     *
+     * @param key    键
+     * @param time   时间(秒)
+     * @param values 值 可以是多个
+     * @return 成功个数
+     */
+    public long sSetAndTime(String key, long time, Object... values) {
+        try {
+            Long count = redisTemplate.opsForSet().add(key, values);
+            if (time > 0) {
+                expire(key, time);
+            }
+            return count;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0;
+        }
+    }
+
+    /**
+     * 获取set缓存的长度
+     *
+     * @param key 键
+     * @return
+     */
+    @Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
+    public long sGetSetSize(String key) {
+        try {
+            return redisTemplate.opsForSet().size(key);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0;
+        }
+    }
+
+    /**
+     * 移除值为value的
+     *
+     * @param key    键
+     * @param values 值 可以是多个
+     * @return 移除的个数
+     */
+    public long setRemove(String key, Object... values) {
+        try {
+            Long count = redisTemplate.opsForSet().remove(key, values);
+            return count;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0;
+        }
+    }
+    // ===============================list=================================
+
+    /**
+     * 获取list缓存的内容
+     *
+     * @param key   键
+     * @param start 开始
+     * @param end   结束 0 到 -1代表所有值
+     * @return
+     */
+    @Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
+    public List<Object> lGet(String key, long start, long end) {
+        try {
+            return redisTemplate.opsForList().range(key, start, end);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     * 获取list缓存的长度
+     *
+     * @param key 键
+     * @return
+     */
+    @Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
+    public long lGetListSize(String key) {
+        try {
+            return redisTemplate.opsForList().size(key);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0;
+        }
+    }
+
+    /**
+     * 通过索引 获取list中的值
+     *
+     * @param key   键
+     * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
+     * @return
+     */
+    @Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
+    public Object lGetIndex(String key, long index) {
+        try {
+            return redisTemplate.opsForList().index(key, index);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     * 将list放入缓存
+     *
+     * @param key   键
+     * @param value 值
+     * @param time  时间(秒)
+     * @return
+     */
+    public boolean lSet(String key, Object value) {
+        try {
+            redisTemplate.opsForList().rightPush(key, value);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 将list放入缓存
+     *
+     * @param key   键
+     * @param value 值
+     * @param time  时间(秒)
+     * @return
+     */
+    public boolean lSet(String key, Object value, long time) {
+        try {
+            redisTemplate.opsForList().rightPush(key, value);
+            if (time > 0) {
+                expire(key, time);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 将list放入缓存
+     *
+     * @param key   键
+     * @param value 值
+     * @param time  时间(秒)
+     * @return
+     */
+    public boolean lSet(String key, List<Object> value) {
+        try {
+            redisTemplate.opsForList().rightPushAll(key, value);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 将list放入缓存
+     *
+     * @param key   键
+     * @param value 值
+     * @param time  时间(秒)
+     * @return
+     */
+    public boolean lSet(String key, List<Object> value, long time) {
+        try {
+            redisTemplate.opsForList().rightPushAll(key, value);
+            if (time > 0) {
+                expire(key, time);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 根据索引修改list中的某条数据
+     *
+     * @param key   键
+     * @param index 索引
+     * @param value 值
+     * @return
+     */
+    public boolean lUpdateIndex(String key, long index, Object value) {
+        try {
+            redisTemplate.opsForList().set(key, index, value);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 移除N个值为value
+     *
+     * @param key   键
+     * @param count 移除多少个
+     * @param value 值
+     * @return 移除的个数
+     */
+    public long lRemove(String key, long count, Object value) {
+        try {
+            Long remove = redisTemplate.opsForList().remove(key, count, value);
+            return remove;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0;
+        }
+    }
+
+    /**
+     * 按键的排序获取对应的值
+     *
+     * @param keys 多个键
+     * @return List<Object>
+     */
+    @Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
+    public List<Object> mget(Collection<String> keys) {
+        return redisTemplate.opsForValue().multiGet(keys);
+    }
+
+}

+ 2 - 1
src/main/java/com/diagbot/vo/UserLoginVO.java

@@ -18,5 +18,6 @@ public class UserLoginVO {
     private String username;
     @NotBlank(message = "请输入密码!")
     private String password;
-
+   //验证码
+    private String captcha;
 }

+ 14 - 2
src/main/java/com/diagbot/web/SysUserController.java

@@ -24,13 +24,18 @@ import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.oauth2.common.OAuth2AccessToken;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 import springfox.documentation.annotations.ApiIgnore;
 
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 import javax.validation.Valid;
+import java.io.IOException;
+
 
 /**
  * @Description: 用户账号API
@@ -64,11 +69,18 @@ public class SysUserController {
                     "password:密码, 必填, 默认密码:dc483e80a7a0bd9ef71d8cf973673924<br> ")
     @PostMapping("/getJwt")
     @SysLogger("getJwt")
-    public RespDTO<JwtDTO> getJwt(@RequestBody UserLoginVO userLoginVO) {
-        JwtDTO data = userFacade.getJwt(userLoginVO.getUsername(), userLoginVO.getPassword());
+    public RespDTO<JwtDTO> getJwt(HttpServletRequest request,@RequestBody UserLoginVO userLoginVO) {
+        JwtDTO data = userFacade.getJwt(request,userLoginVO.getUsername(), userLoginVO.getPassword(),userLoginVO.getCaptcha());
         return RespDTO.onSuc(data);
     }
 
+    @ApiOperation(value = "获取验证码[by:cy]")
+    @GetMapping("/getCaptcha")
+    @SysLogger("getCaptcha")
+    public void getCaptcha(HttpServletRequest request, HttpServletResponse response) throws IOException {
+           userFacade.getCaptcha(request, response);
+    }
+
     @ApiOperation(value = "登录获取jwt[by:gaodm]",
             notes = "username:用户名,必填<br>")
     @PostMapping("/getJwtNoPass")