Browse Source

修改发送短信验证码逻辑
新增短信验证码修改密码

fangzhen 6 months ago
parent
commit
ab95f6c1b7

+ 1 - 0
.gitignore

@@ -45,3 +45,4 @@ nbdist/
 !*/build/*.java
 !*/build/*.html
 !*/build/*.xml
+/.vscode/settings.json

+ 3 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java

@@ -114,6 +114,9 @@ public class CaptchaController {
             case "register":
                 verifyKey = CacheConstants.SMS_REGISTER_CODE_KEY + phoneNumber;
                 break;
+            case "update":
+                verifyKey = CacheConstants.SMS_UPDATE_PASSWORD_CODE_KEY + phoneNumber;
+                break;
         }
 
         //2.发送验证码

+ 5 - 5
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java

@@ -12,9 +12,10 @@ import com.ruoyi.common.utils.StringUtils;
  * @author ruoyi
  */
 @RestController
-public class SysIndexController
-{
-    /** 系统基础配置 */
+public class SysIndexController {
+    /**
+     * 系统基础配置
+     */
     @Autowired
     private RuoYiConfig ruoyiConfig;
 
@@ -22,8 +23,7 @@ public class SysIndexController
      * 访问首页,提示语
      */
     @RequestMapping("/")
-    public String index()
-    {
+    public String index() {
         return StringUtils.format("欢迎使用{}后台管理框架,当前版本:v{},请通过前端地址访问。", ruoyiConfig.getName(), ruoyiConfig.getVersion());
     }
 }

+ 74 - 40
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java

@@ -1,41 +1,39 @@
 package com.ruoyi.web.controller.system;
 
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.ruoyi.common.utils.DateUtils;
-import com.ruoyi.generator.domain.Community.CommunityUserInfo;
-import com.ruoyi.generator.mapper.community.CommunityUserInfoMapper;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
-import org.springframework.web.multipart.MultipartFile;
 import com.ruoyi.common.annotation.Log;
 import com.ruoyi.common.config.RuoYiConfig;
+import com.ruoyi.common.constant.CacheConstants;
 import com.ruoyi.common.core.controller.BaseController;
 import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.common.core.domain.entity.SysUser;
 import com.ruoyi.common.core.domain.model.LoginUser;
+import com.ruoyi.common.core.redis.RedisCache;
 import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.exception.user.CaptchaException;
+import com.ruoyi.common.exception.user.CaptchaExpireException;
+import com.ruoyi.common.exception.user.CaptchaNullException;
+import com.ruoyi.common.utils.DateUtils;
 import com.ruoyi.common.utils.SecurityUtils;
 import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.file.FileUploadUtils;
 import com.ruoyi.common.utils.file.MimeTypeUtils;
 import com.ruoyi.framework.web.service.TokenService;
+import com.ruoyi.generator.domain.Community.CommunityUserInfo;
+import com.ruoyi.generator.mapper.community.CommunityUserInfoMapper;
 import com.ruoyi.system.service.ISysUserService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
 
 /**
  * 个人信息 业务处理
- * 
+ *
  * @author ruoyi
  */
 @RestController
 @RequestMapping("/system/user/profile")
-public class SysProfileController extends BaseController
-{
+public class SysProfileController extends BaseController {
     @Autowired
     private ISysUserService userService;
 
@@ -45,12 +43,14 @@ public class SysProfileController extends BaseController
     @Autowired
     private CommunityUserInfoMapper communityUserInfoMapper;
 
+    @Autowired
+    private RedisCache redisCache;
+
     /**
      * 个人信息
      */
     @GetMapping
-    public AjaxResult profile()
-    {
+    public AjaxResult profile() {
         LoginUser loginUser = getLoginUser();
         SysUser user = loginUser.getUser();
         AjaxResult ajax = AjaxResult.success(user);
@@ -64,8 +64,7 @@ public class SysProfileController extends BaseController
      */
     @Log(title = "个人信息", businessType = BusinessType.UPDATE)
     @PutMapping
-    public AjaxResult updateProfile(@RequestBody SysUser user)
-    {
+    public AjaxResult updateProfile(@RequestBody SysUser user) {
         LoginUser loginUser = getLoginUser();
         SysUser currentUser = loginUser.getUser();
         currentUser.setNickName(user.getNickName());
@@ -73,17 +72,14 @@ public class SysProfileController extends BaseController
         currentUser.setPhonenumber(user.getPhonenumber());
         currentUser.setSex(user.getSex());
         currentUser.setProfile(user.getProfile());
-        if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(currentUser))
-        {
+        if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(currentUser)) {
             return error("修改用户'" + loginUser.getUsername() + "'失败,手机号码已存在");
         }
-        if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(currentUser))
-        {
+        if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(currentUser)) {
             return error("修改用户'" + loginUser.getUsername() + "'失败,邮箱账号已存在");
         }
-        if (userService.updateUserProfile(currentUser) > 0)
-        {
-            CommunityUserInfo communityUserInfo = communityUserInfoMapper.selectOne(new QueryWrapper<CommunityUserInfo>().eq("user_id",currentUser.getUserId()));
+        if (userService.updateUserProfile(currentUser) > 0) {
+            CommunityUserInfo communityUserInfo = communityUserInfoMapper.selectOne(new QueryWrapper<CommunityUserInfo>().eq("user_id", currentUser.getUserId()));
             communityUserInfo.setProfile(currentUser.getProfile());
             communityUserInfo.setBirthday(user.getBirthday());
             communityUserInfo.setTags(user.getTags());
@@ -104,22 +100,18 @@ public class SysProfileController extends BaseController
      */
     @Log(title = "个人信息", businessType = BusinessType.UPDATE)
     @PutMapping("/updatePwd")
-    public AjaxResult updatePwd(String oldPassword, String newPassword)
-    {
+    public AjaxResult updatePwd(String oldPassword, String newPassword) {
         LoginUser loginUser = getLoginUser();
         String userName = loginUser.getUsername();
         String password = loginUser.getPassword();
-        if (!SecurityUtils.matchesPassword(oldPassword, password))
-        {
+        if (!SecurityUtils.matchesPassword(oldPassword, password)) {
             return error("修改密码失败,旧密码错误");
         }
-        if (SecurityUtils.matchesPassword(newPassword, password))
-        {
+        if (SecurityUtils.matchesPassword(newPassword, password)) {
             return error("新密码不能与旧密码相同");
         }
         newPassword = SecurityUtils.encryptPassword(newPassword);
-        if (userService.resetUserPwd(userName, newPassword) > 0)
-        {
+        if (userService.resetUserPwd(userName, newPassword) > 0) {
             // 更新缓存用户密码
             loginUser.getUser().setPassword(newPassword);
             tokenService.setLoginUser(loginUser);
@@ -128,19 +120,35 @@ public class SysProfileController extends BaseController
         return error("修改密码异常,请联系管理员");
     }
 
+    /**
+     * 重置密码(验证码)
+     */
+    @Log(title = "个人信息", businessType = BusinessType.UPDATE)
+    @PutMapping("/updatePwdBySmsCode")
+    public AjaxResult updatePwdBySmsCode(String username, String smsCode, String newPassword) {
+        if (StringUtils.isEmpty(newPassword) || StringUtils.isEmpty(smsCode) || StringUtils.isEmpty(username)) {
+            return error("参数异常!");
+        }
+
+        validateSmsCaptcha(username, smsCode);
+        newPassword = SecurityUtils.encryptPassword(newPassword);
+        int result = userService.resetUserPwd(username, newPassword);
+        if (result > 0) {
+            return success();
+        }
+        return error("修改密码异常,请联系管理员");
+    }
+
     /**
      * 头像上传
      */
     @Log(title = "用户头像", businessType = BusinessType.UPDATE)
     @PostMapping("/avatar")
-    public AjaxResult avatar(@RequestParam("avatarfile") MultipartFile file) throws Exception
-    {
-        if (!file.isEmpty())
-        {
+    public AjaxResult avatar(@RequestParam("avatarfile") MultipartFile file) throws Exception {
+        if (!file.isEmpty()) {
             LoginUser loginUser = getLoginUser();
             String avatar = FileUploadUtils.upload(RuoYiConfig.getAvatarPath(), file, MimeTypeUtils.IMAGE_EXTENSION);
-            if (userService.updateUserAvatar(loginUser.getUsername(), avatar))
-            {
+            if (userService.updateUserAvatar(loginUser.getUsername(), avatar)) {
                 AjaxResult ajax = AjaxResult.success();
                 ajax.put("imgUrl", avatar);
                 // 更新缓存用户头像
@@ -151,4 +159,30 @@ public class SysProfileController extends BaseController
         }
         return error("上传图片异常,请联系管理员");
     }
+
+    /**
+     * 校验验证码
+     *
+     * @param username 用户名
+     * @param code     验证码
+     * @return 结果
+     */
+    public void validateSmsCaptcha(String username, String code) {
+        if (StringUtils.isEmpty(code)) {
+            throw new CaptchaNullException();
+        }
+        String verifyKey = CacheConstants.SMS_UPDATE_PASSWORD_CODE_KEY + StringUtils.nvl(username, "");
+        try {
+            String captcha = redisCache.getCacheObject(verifyKey).toString();
+            if (captcha == null) {
+                throw new CaptchaExpireException();
+            }
+            if (!code.equalsIgnoreCase(captcha)) {
+                throw new CaptchaException();
+            }
+            redisCache.deleteObject(verifyKey);
+        } catch (NullPointerException e) {
+            throw new CaptchaExpireException();
+        }
+    }
 }

+ 1 - 1
ruoyi-admin/src/main/resources/application-druid.yml

@@ -8,7 +8,7 @@ spring:
             master:
                 url: jdbc:mysql://47.122.10.161:3306/ruoyi-community?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
                 username: root
-                password: fangzhen,7410
+                password: fz,961202.
             # 从库数据源
             slave:
                 # 从数据源开关/默认关闭

+ 1 - 1
ruoyi-admin/src/main/resources/application.yml

@@ -74,7 +74,7 @@ spring:
     # 数据库索引
     database: 0
     # 密码
-    password: fangzhen,7410
+    password: fz,961202.
     # 连接超时时间
     timeout: 10s
     lettuce:

+ 5 - 0
ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java

@@ -27,6 +27,11 @@ public class CacheConstants
      */
     public static final String SMS_REGISTER_CODE_KEY = "sms_register_codes:";
 
+    /**
+     * 短信密码更新验证码 redis key
+     */
+    public static final String SMS_UPDATE_PASSWORD_CODE_KEY = "sms_update_password_codes:";
+
     /**
      * 参数管理 cache key
      */

+ 1 - 1
ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java

@@ -129,7 +129,7 @@ public class SecurityConfig {
                 .authorizeHttpRequests((requests) -> {
                     permitAllUrl.getUrls().forEach(url -> requests.antMatchers(url).permitAll());
                     // 对于登录login 注册register 验证码captchaImage 允许匿名访问
-                    requests.antMatchers("/login","/phoneLogin", "/register", "/captchaImage").permitAll()
+                    requests.antMatchers("/login","/phoneLogin", "/register", "/captchaImage","/system/user/profile/updatePwdBySmsCode").permitAll()
                             // 静态资源,可匿名访问
                             .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
                             .antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**", "/websocket/**").permitAll()

+ 1 - 1
ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysRegisterService.java

@@ -136,13 +136,13 @@ public class SysRegisterService {
         String verifyKey = CacheConstants.SMS_REGISTER_CODE_KEY + StringUtils.nvl(username, "");
         try {
             String captcha = redisCache.getCacheObject(verifyKey).toString();
-            redisCache.deleteObject(verifyKey);
             if (captcha == null) {
                 throw new CaptchaExpireException();
             }
             if (!code.equalsIgnoreCase(captcha)) {
                 throw new CaptchaException();
             }
+            redisCache.deleteObject(verifyKey);
         } catch (NullPointerException e) {
             throw new CaptchaExpireException();
         }

+ 159 - 0
ruoyi-generator/src/main/java/com/ruoyi/generator/service/CommunityArticleServiceImpl.java

@@ -93,6 +93,165 @@ public class CommunityArticleServiceImpl extends ServiceImpl<CommunityArticleMap
     @Autowired
     private CommunityArticleRecommendMapper recommendMapper;
 
+//    @Override
+//    public List<CommunityArticleVo> selectCommunityArticleList(CommunityArticle communityArticle, int pageNum, int pageSize, int searchType) {
+//        Long userId = SecurityUtils.getUserId();
+//
+//        // 处理文章浏览量
+//        updateArticlePageViews(communityArticle.getId());
+//
+//        // 获取圈子IDs
+//        List<Long> circleIds = getCircleIds(communityArticle.getClassId(), communityArticle.getCircleId());
+//        if (circleIds.isEmpty()) {
+//            return new ArrayList<>();
+//        }
+//
+//        // 查询文章列表
+//        int offset = (pageNum - 1) * pageSize;
+//        List<CommunityArticleVo> articleVos = communityArticleMapper.selectCommunityArticleList(
+//                communityArticle, circleIds, offset, pageSize, searchType);
+//
+//        // 批量处理文章数据
+//        return processArticleVos(articleVos, circleIds, userId);
+//    }
+
+    private void updateArticlePageViews(Long articleId) {
+        if (Objects.nonNull(articleId)) {
+            CommunityArticle article = communityArticleMapper.selectById(articleId);
+            article.setPageViews(article.getPageViews() + 1);
+            communityArticleMapper.updateById(article);
+        }
+    }
+
+    private List<Long> getCircleIds(Long classId, Long circleId) {
+        if (Objects.nonNull(circleId)) {
+            return Collections.singletonList(circleId);
+        }
+
+        if (Objects.nonNull(classId)) {
+            return communityClassCircleMapper.selectList(
+                            new QueryWrapper<CommunityClassCircle>().eq("class_id", classId))
+                    .stream()
+                    .map(CommunityClassCircle::getCircleId)
+                    .collect(Collectors.toList());
+        }
+
+        return new ArrayList<>();
+    }
+
+    private List<CommunityArticleVo> processArticleVos(List<CommunityArticleVo> articleVos, List<Long> circleIds, Long userId) {
+        List<CommunityArticleVo> result = new ArrayList<>(articleVos);
+
+        for (CommunityArticleVo articleVo : result) {
+            articleVo.setCircleIds(circleIds);
+
+            // 处理图片和视频
+            processMediaList(articleVo);
+
+            // 设置计数
+            setArticleCounts(articleVo);
+
+            // 设置用户交互状态
+            setUserInteractionStatus(articleVo, userId);
+
+            // 处理文章标签
+            if (!processArticleTags(articleVo, userId)) {
+                result.remove(articleVo);
+            }
+        }
+
+        return result;
+    }
+
+    private void processMediaList(CommunityArticleVo articleVo) {
+        List<Map<String, Object>> imageList = articleVo.getImageList();
+        List<CommunityArticleImages> videoList = new ArrayList<>();
+
+        Iterator<Map<String, Object>> iterator = imageList.iterator();
+        while (iterator.hasNext()) {
+            Map<String, Object> image = iterator.next();
+            String imageUrl = image.get("imageUrl").toString();
+
+            if (isVideoFile(imageUrl)) {
+                iterator.remove();
+                CommunityArticleImages video = new CommunityArticleImages();
+                BeanUtils.copyProperties(image, video);
+                videoList.add(video);
+            }
+        }
+
+        articleVo.setVideoList(videoList);
+    }
+
+    private void setArticleCounts(CommunityArticleVo articleVo) {
+        Long articleId = articleVo.getId();
+
+        // 使用单个查询获取所有计数
+        articleVo.setLikeCount(communityLikeMapper.selectCount(
+                new QueryWrapper<CommunityLike>().eq("article_id", articleId)).intValue());
+
+        articleVo.setCollectCount(communityCollectMapper.selectCount(
+                new QueryWrapper<CommunityArticleCollect>().eq("article_id", articleId)).intValue());
+
+        articleVo.setRecommendCount(recommendMapper.selectCount(
+                new QueryWrapper<CommunityArticleRecommend>()
+                        .eq("article_id", articleId)
+                        .and(wrapper -> wrapper.ne("is_delete", true).or().isNull("is_delete"))).intValue());
+    }
+
+    private void setUserInteractionStatus(CommunityArticleVo articleVo, Long userId) {
+        Long articleId = articleVo.getId();
+
+        articleVo.setCollect(communityCollectMapper.exists(
+                new QueryWrapper<CommunityArticleCollect>()
+                        .eq("user_id", userId)
+                        .eq("article_id", articleId)));
+
+        articleVo.setLike(communityLikeMapper.exists(
+                new QueryWrapper<CommunityLike>()
+                        .eq("user_id", userId)
+                        .eq("article_id", articleId)));
+
+        articleVo.setRecommend(recommendMapper.exists(
+                new QueryWrapper<CommunityArticleRecommend>()
+                        .eq("user_id", userId)
+                        .eq("article_id", articleId)
+                        .and(wrapper -> wrapper.ne("is_delete", true).or().isNull("is_delete"))));
+    }
+
+    private boolean processArticleTags(CommunityArticleVo articleVo, Long userId) {
+        List<CommunityArticleTag> articleTags = communityArticleTagMapper.selectList(
+                new QueryWrapper<CommunityArticleTag>().eq("article_id", articleVo.getId()));
+
+        List<Long> tagIds = articleTags.stream()
+                .map(CommunityArticleTag::getTagId)
+                .collect(Collectors.toList());
+
+        if (tagIds.isEmpty()) {
+            return true;
+        }
+
+        // 检查标签是否被拉黑
+        List<CommunityTagBlock> tagBlocks = communityTagBlockMapper.selectList(
+                new QueryWrapper<CommunityTagBlock>()
+                        .in("tag_id", tagIds)
+                        .eq("user_id", userId));
+
+        if (tagBlocks.stream().anyMatch(CommunityTagBlock::isBlock)) {
+            return false;
+        }
+
+        List<Long> validTagIds = tagBlocks.isEmpty() ? tagIds :
+                tagBlocks.stream().map(CommunityTagBlock::getTagId).collect(Collectors.toList());
+
+        if (!validTagIds.isEmpty()) {
+            List<CommunityTag> communityTags = communityTagMapper.selectBatchIds(validTagIds);
+            articleVo.setTags(communityTags);
+        }
+
+        return true;
+    }
+
     /**
      * 查询文章列表
      *