From 01743f4218d34dd139db59b5f71fefa521d9e1f9 Mon Sep 17 00:00:00 2001 From: zhouchengrong Date: Fri, 21 Jul 2023 11:02:59 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0docker-compose=E6=96=87?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../da/service/impl/AccountServiceImpl.java | 126 +++++++++--------- .../spring-configuration-metadata.json | 20 --- target/classes/application-test.properties | 4 +- .../service/impl/AccountServiceImpl$1.class | Bin 1208 -> 1208 bytes .../da/service/impl/AccountServiceImpl.class | Bin 15811 -> 15892 bytes 5 files changed, 64 insertions(+), 86 deletions(-) diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index 75465bb1..4b026e21 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -1,12 +1,9 @@ package com.ai.da.service.impl; import cn.hutool.core.collection.CollectionUtil; -import cn.hutool.core.util.ObjectUtil; import com.ai.da.common.config.exception.BusinessException; -import com.ai.da.common.constant.TokenConstant; import com.ai.da.common.enums.LoginTypeEnum; import com.ai.da.common.enums.OperationTypeEnum; -import com.ai.da.common.httpdata.token.TokenQuery; import com.ai.da.common.security.jwt.JWTTokenHelper; import com.ai.da.common.utils.*; import com.ai.da.mapper.AccountMapper; @@ -19,25 +16,18 @@ import com.ai.da.model.vo.AuthPrincipalVo; import com.ai.da.service.AccountLoginLogService; import com.ai.da.service.AccountService; import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.google.common.collect.Maps; -import io.netty.util.internal.StringUtil; import lombok.extern.slf4j.Slf4j; -import org.apache.catalina.util.RequestUtil; import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.time.DateUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.Assert; -import org.springframework.util.CollectionUtils; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import java.util.Date; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; @@ -64,17 +54,20 @@ public class AccountServiceImpl extends ServiceImpl impl public AccountPreLoginVO preLogin(AccountPreLoginDTO accountDTO) { log.info("aida预先登入accountDTO###{}", JSON.toJSONString(accountDTO)); Account account = getOneByUserName(accountDTO.getUserName()); - Assert.isTrue(Objects.nonNull(account),"User does not exist!"); + Assert.isTrue(Objects.nonNull(account), "User does not exist!"); //用户有效期校验 validateUserValidaExpire(account); - if("Third-000000".equals(account.getUserPassword())){ + if ("Third-000000".equals(account.getUserPassword())) { account.setUserPassword(accountDTO.getPassword()); accountMapper.updateById(account); - }else{ - Assert.isTrue(account.getUserPassword().equals(accountDTO.getPassword()),"Password error !"); + } else { + Assert.isTrue(account.getUserPassword().equals(accountDTO.getPassword()), "Password error !"); } /*发送邮件*/ OperationTypeEnum operationTypeEnum = OperationTypeEnum.of(accountDTO.getOperationType()); + log.info(account.getUserEmail()); + log.info(accountDTO.getEmail()); + Assert.isTrue(account.getUserEmail().equals(accountDTO.getEmail()), "Email error !"); Assert.notNull(operationTypeEnum, "Unknown operation type!"); String randomVerifyCode = RandomsUtil.generateVerifyCode(100000L, 999999L); LocalCacheUtils.setVerifyCodeCache( @@ -112,10 +105,10 @@ public class AccountServiceImpl extends ServiceImpl impl public AccountLoginVO login(AccountLoginDTO accountLoginDTO, HttpServletRequest request) { log.info("aida确认登入###accountLoginDTO###{}", JSON.toJSONString(accountLoginDTO)); Account accountExist = getOneByEmail(accountLoginDTO.getEmail().trim()); - Assert.notNull(accountExist,"User does not exist!"); + Assert.notNull(accountExist, "User does not exist!"); LoginTypeEnum accountType = LoginTypeEnum.of(accountLoginDTO.getLoginType()); - if (Objects.isNull(accountType)|| accountType.equals(LoginTypeEnum.PASSWORD)) { + if (Objects.isNull(accountType) || accountType.equals(LoginTypeEnum.PASSWORD)) { throw new BusinessException("Unknown login type!"); } //用户有效期校验 @@ -126,8 +119,8 @@ public class AccountServiceImpl extends ServiceImpl impl case PASSWORD: Assert.isTrue(StringUtils.isNotBlank(accountLoginDTO.getPassword()), "Please input a password !"); account = getOneByUserName(accountLoginDTO.getUserName()); - Assert.isTrue(Objects.nonNull(account),"User does not exist!"); - Assert.isTrue(account.getUserPassword().equals(accountLoginDTO.getPassword()),"Password error !"); + Assert.isTrue(Objects.nonNull(account), "User does not exist!"); + Assert.isTrue(account.getUserPassword().equals(accountLoginDTO.getPassword()), "Password error !"); // Assert.isTrue(StringUtils.isBlank( // LocalCacheUtils.getTokenCache(String.valueOf(account.getId()))),"该用户已登入"); break; @@ -139,9 +132,9 @@ public class AccountServiceImpl extends ServiceImpl impl throw new BusinessException("Email not registered!"); } //校验邮箱验证码 - String verifyCode = LocalCacheUtils.getVerifyCodeCache( OperationTypeEnum.LOGIN.name() + "_" +accountLoginDTO.getEmail()); + String verifyCode = LocalCacheUtils.getVerifyCodeCache(OperationTypeEnum.LOGIN.name() + "_" + accountLoginDTO.getEmail()); Assert.isTrue(StringUtils.isNotBlank(verifyCode), "The verification code has expired!"); - if(!"921314".equals(accountLoginDTO.getEmailVerifyCode())){ + if (!"921314".equals(accountLoginDTO.getEmailVerifyCode())) { Assert.isTrue(verifyCode.equals(accountLoginDTO.getEmailVerifyCode()), "Verification code error!"); } break; @@ -149,34 +142,36 @@ public class AccountServiceImpl extends ServiceImpl impl } AccountLoginVO response = CopyUtil.copyObject(account, AccountLoginVO.class); response.setEmail(account.getUserEmail()); - String token =LocalCacheUtils.getTokenCache(String.valueOf(account.getId())); - if(StringUtils.isNotBlank(token)){ + String token = LocalCacheUtils.getTokenCache(String.valueOf(account.getId())); + if (StringUtils.isNotBlank(token)) { //用户已登入 response.setToken(token); - }else{ - response.setToken(createAccountToken(account.getId(),account.getUserName())); + } else { + response.setToken(createAccountToken(account.getId(), account.getUserName())); } response.setUserId(account.getId()); //判断是否常用ip 不是则发邮件提示 - calculateExceptionIp(RequestInfoUtil.getIpAddress(request),account); + calculateExceptionIp(RequestInfoUtil.getIpAddress(request), account); return response; } - private void validateUserValidaExpire(Account account){ + + private void validateUserValidaExpire(Account account) { Long currentTime = new Date().getTime(); - if(Objects.nonNull(account.getValidStartTime())){ - Assert.isTrue(currentTime >= account.getValidStartTime(),"User expired !" ); + if (Objects.nonNull(account.getValidStartTime())) { + Assert.isTrue(currentTime >= account.getValidStartTime(), "User expired !"); } - if(Objects.nonNull(account.getValidEndTime())){ - Assert.isTrue(currentTime <= account.getValidEndTime(),"User expired !" ); + if (Objects.nonNull(account.getValidEndTime())) { + Assert.isTrue(currentTime <= account.getValidEndTime(), "User expired !"); } } - private void calculateExceptionIp(String ip ,Account account ){ + + private void calculateExceptionIp(String ip, Account account) { //必须先绑定邮箱才可以发有异常ip邮件提醒 - if(StringUtils.isNotBlank(account.getUserEmail())){ + if (StringUtils.isNotBlank(account.getUserEmail())) { List accountLoginLogs = accountLoginLogService.getByUserId(account.getId()); - if(CollectionUtil.isNotEmpty(accountLoginLogs)){ + if (CollectionUtil.isNotEmpty(accountLoginLogs)) { List existIps = accountLoginLogs.stream().map(AccountLoginLog::getIp).collect(Collectors.toList()); - if(!existIps.contains(ip)){ + if (!existIps.contains(ip)) { //非常用ip,没有出现过 EmailSendDTO emailSendDTO = new EmailSendDTO(); emailSendDTO.setEmail(account.getUserEmail()); @@ -187,11 +182,12 @@ public class AccountServiceImpl extends ServiceImpl impl } } //保存登入日志 - accountLoginLogService.saveLoginLog(ip,account.getId()); + accountLoginLogService.saveLoginLog(ip, account.getId()); } - private String createAccountToken(Long userId,String userName){ + + private String createAccountToken(Long userId, String userName) { String token = LocalCacheUtils.getTokenCache(String.valueOf(userId)); - if(StringUtils.isNotBlank(token)){ + if (StringUtils.isNotBlank(token)) { return token; } AuthPrincipalVo principal = new AuthPrincipalVo(); @@ -205,14 +201,14 @@ public class AccountServiceImpl extends ServiceImpl impl @Override public Boolean bindEmail(AccountBindEmailDTO accountBindEmailDTO) { Account account = getOneByUserId(accountBindEmailDTO.getUserId()); - Assert.notNull(account,"User does not exist !"); - Assert.isTrue(StringUtils.isBlank(account.getUserEmail()),"User has bound mailbox !"); + Assert.notNull(account, "User does not exist !"); + Assert.isTrue(StringUtils.isBlank(account.getUserEmail()), "User has bound mailbox !"); //校验邮箱验证码 String verifyCode = LocalCacheUtils.getVerifyCodeCache(OperationTypeEnum.BIND_MAILBOX.name() + "_" + accountBindEmailDTO.getUserEmail()); Assert.isTrue(StringUtils.isNotBlank(verifyCode), "The verification code has expired !"); Assert.isTrue(verifyCode.equals(accountBindEmailDTO.getEmailVerifyCode()), "Verification code error !"); //绑定 - updatePwdByUserId(accountBindEmailDTO.getUserEmail(),accountBindEmailDTO.getUserId()); + updatePwdByUserId(accountBindEmailDTO.getUserEmail(), accountBindEmailDTO.getUserId()); return Boolean.TRUE; } @@ -237,6 +233,7 @@ public class AccountServiceImpl extends ServiceImpl impl accountNew.setUserPassword(pwd); accountMapper.update(accountNew, queryWrapper); } + private void updatePwdByUserId(String email, Long userId) { QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("id", userId); @@ -258,6 +255,7 @@ public class AccountServiceImpl extends ServiceImpl impl queryWrapper.eq("user_name", userName); return accountMapper.selectOne(queryWrapper); } + private Account getOneByUserId(Long userId) { QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("id", userId); @@ -271,9 +269,9 @@ public class AccountServiceImpl extends ServiceImpl impl Assert.notNull(operationTypeEnum, "Unknown operation type!"); Account emailAccount = getOneByEmail(emailSendDTO.getEmail()); - String randomVerifyCode =RandomsUtil.generateVerifyCode(100000L,999999L); + String randomVerifyCode = RandomsUtil.generateVerifyCode(100000L, 999999L); LocalCacheUtils.setVerifyCodeCache( - emailSendDTO.getOperationType() + "_" + emailSendDTO.getEmail(),randomVerifyCode); + emailSendDTO.getOperationType() + "_" + emailSendDTO.getEmail(), randomVerifyCode); Boolean result = Boolean.FALSE; switch (operationTypeEnum) { case LOGIN: @@ -306,7 +304,7 @@ public class AccountServiceImpl extends ServiceImpl impl public Boolean logout(AccountLogoutDTO accountLogoutDTO) { //jwt本身失效比较难做 统一用缓存实现 删除缓存就失效 String token = LocalCacheUtils.getTokenCache(String.valueOf(accountLogoutDTO.getUserId())); - if(StringUtils.isNotBlank(token)){ + if (StringUtils.isNotBlank(token)) { LocalCacheUtils.delTokenCache(String.valueOf(accountLogoutDTO.getUserId())); } return Boolean.TRUE; @@ -315,7 +313,7 @@ public class AccountServiceImpl extends ServiceImpl impl @Override public Boolean isLogin(AccountLogoutDTO accountLogoutDTO) { String token = LocalCacheUtils.getTokenCache(String.valueOf(accountLogoutDTO.getUserId())); - if(StringUtils.isNotBlank(token)){ + if (StringUtils.isNotBlank(token)) { return Boolean.TRUE; } return Boolean.FALSE; @@ -330,52 +328,52 @@ public class AccountServiceImpl extends ServiceImpl impl account.setValidStartTime(Long.valueOf(accountAddDTO.getValidStartTime())); account.setValidEndTime(Long.valueOf(accountAddDTO.getValidEndTime())); account.setCreateDate(new Date()); - return accountMapper.insert(account)>0; + return accountMapper.insert(account) > 0; } @Override public Boolean editUser(AccountEditDTO accountEditDTO) { - if(Objects.isNull(accountEditDTO)|| ObjectUtils.isAllFieldNull(accountEditDTO)){ + if (Objects.isNull(accountEditDTO) || ObjectUtils.isAllFieldNull(accountEditDTO)) { throw new BusinessException("The edited account information cannot be blank!"); } QueryWrapper queryTotal = new QueryWrapper<>(); Account account = new Account(); //校验 - if(StringUtils.isNotBlank(accountEditDTO.getNewEmail())){ - Assert.isTrue(StringUtils.isNotBlank(accountEditDTO.getOldEmail()),"oldEmail cannot be empty!"); - queryTotal.eq("user_email",accountEditDTO.getOldEmail()); + if (StringUtils.isNotBlank(accountEditDTO.getNewEmail())) { + Assert.isTrue(StringUtils.isNotBlank(accountEditDTO.getOldEmail()), "oldEmail cannot be empty!"); + queryTotal.eq("user_email", accountEditDTO.getOldEmail()); Account accountSelect = accountMapper.selectOne(queryTotal); - Assert.notNull(accountSelect,"oldEmail does not exist!"); + Assert.notNull(accountSelect, "oldEmail does not exist!"); account.setUserEmail(accountEditDTO.getNewEmail()); } - if(StringUtils.isNotBlank(accountEditDTO.getNewUserName())){ - Assert.isTrue(StringUtils.isNotBlank(accountEditDTO.getOldUserName()),"oldUserName cannot be empty!"); - queryTotal.eq("user_name",accountEditDTO.getOldUserName()); + if (StringUtils.isNotBlank(accountEditDTO.getNewUserName())) { + Assert.isTrue(StringUtils.isNotBlank(accountEditDTO.getOldUserName()), "oldUserName cannot be empty!"); + queryTotal.eq("user_name", accountEditDTO.getOldUserName()); Account accountSelect = accountMapper.selectOne(queryTotal); - Assert.notNull(accountSelect,"oldUserName does not exist!"); + Assert.notNull(accountSelect, "oldUserName does not exist!"); account.setUserName(accountEditDTO.getNewUserName()); } - if(StringUtils.isNotBlank(accountEditDTO.getNewValidStartTime())){ - Assert.isTrue(StringUtils.isNotBlank(accountEditDTO.getOldUserName()),"oldUserName cannot be empty!"); - queryTotal.eq("user_name",accountEditDTO.getOldUserName()); + if (StringUtils.isNotBlank(accountEditDTO.getNewValidStartTime())) { + Assert.isTrue(StringUtils.isNotBlank(accountEditDTO.getOldUserName()), "oldUserName cannot be empty!"); + queryTotal.eq("user_name", accountEditDTO.getOldUserName()); Account accountSelect = accountMapper.selectOne(queryTotal); - Assert.notNull(accountSelect,"oldUserName does not exist!"); + Assert.notNull(accountSelect, "oldUserName does not exist!"); account.setValidStartTime(Long.valueOf(accountEditDTO.getNewValidStartTime())); } - if(StringUtils.isNotBlank(accountEditDTO.getNewValidEndTime())){ - Assert.isTrue(StringUtils.isNotBlank(accountEditDTO.getOldUserName()),"oldUserName cannot be empty!"); - queryTotal.eq("user_name",accountEditDTO.getOldUserName()); + if (StringUtils.isNotBlank(accountEditDTO.getNewValidEndTime())) { + Assert.isTrue(StringUtils.isNotBlank(accountEditDTO.getOldUserName()), "oldUserName cannot be empty!"); + queryTotal.eq("user_name", accountEditDTO.getOldUserName()); Account accountSelect = accountMapper.selectOne(queryTotal); - Assert.notNull(accountSelect,"oldUserName does not exist!"); + Assert.notNull(accountSelect, "oldUserName does not exist!"); account.setValidEndTime(Long.valueOf(accountEditDTO.getNewValidEndTime())); } Account accountSelect = accountMapper.selectOne(queryTotal); - Assert.notNull(accountSelect,"oldAccount does not exist!"); - accountMapper.update(account,queryTotal); + Assert.notNull(accountSelect, "oldAccount does not exist!"); + accountMapper.update(account, queryTotal); return null; } } diff --git a/target/classes/META-INF/spring-configuration-metadata.json b/target/classes/META-INF/spring-configuration-metadata.json index c9c480bc..42f855e7 100644 --- a/target/classes/META-INF/spring-configuration-metadata.json +++ b/target/classes/META-INF/spring-configuration-metadata.json @@ -41,26 +41,6 @@ "type": "java.lang.String", "sourceType": "com.ai.da.common.config.FileProperties" }, - { - "name": "file.linux.path", - "type": "java.lang.String", - "sourceType": "com.ai.da.common.config.FileProperties$ElPath" - }, - { - "name": "file.mac.path", - "type": "java.lang.String", - "sourceType": "com.ai.da.common.config.FileProperties$ElPath" - }, - { - "name": "file.sys.path", - "type": "java.lang.String", - "sourceType": "com.ai.da.common.config.FileProperties$ElPath" - }, - { - "name": "file.windows.path", - "type": "java.lang.String", - "sourceType": "com.ai.da.common.config.FileProperties$ElPath" - }, { "name": "spring.security.auth-api", "type": "java.lang.String", diff --git a/target/classes/application-test.properties b/target/classes/application-test.properties index a49d4252..3292f56f 100644 --- a/target/classes/application-test.properties +++ b/target/classes/application-test.properties @@ -3,8 +3,8 @@ server.port=5567 #datasource spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://18.167.251.121:33006/aida?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true -spring.datasource.username=root -spring.datasource.password=root +spring.datasource.username=nacos +spring.datasource.password=nacos #security spring.security.jwtSecret=JWTSECRET diff --git a/target/classes/com/ai/da/service/impl/AccountServiceImpl$1.class b/target/classes/com/ai/da/service/impl/AccountServiceImpl$1.class index c587d45265672cc8ba2eed07d7005a5607563f2b..8834f62c9c7b153a7b27961314d989b9f05135aa 100644 GIT binary patch delta 17 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 delta 7009 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 KlH25Vx#K^A0K&Kc