mirror of
https://codeup.aliyun.com/64f7d6b8ce01efaafef1e678/coal/coal.git
synced 2026-01-25 07:46:40 +08:00
支持短信验证码登录
This commit is contained in:
6
pom.xml
6
pom.xml
@@ -65,6 +65,12 @@
|
||||
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.aliyun</groupId>
|
||||
<artifactId>dysmsapi20170525</artifactId>
|
||||
<version>2.0.24</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.nulab-inc</groupId>
|
||||
<artifactId>zxcvbn</artifactId>
|
||||
|
||||
@@ -3,6 +3,7 @@ package cn.lihongjie.coal.session;
|
||||
import cn.lihongjie.coal.annotation.Anonymous;
|
||||
import cn.lihongjie.coal.annotation.SysLog;
|
||||
import cn.lihongjie.coal.base.controller.BaseController;
|
||||
import cn.lihongjie.coal.base.dto.IdRequest;
|
||||
import cn.lihongjie.coal.common.Ctx;
|
||||
import cn.lihongjie.coal.user.dto.UserDto;
|
||||
import cn.lihongjie.coal.user.service.UserService;
|
||||
@@ -36,6 +37,14 @@ public class LoginController extends BaseController {
|
||||
return this.service.genCaptcha();
|
||||
}
|
||||
|
||||
|
||||
@PostMapping("/loginSmsCode")
|
||||
@Anonymous
|
||||
public CaptchaDto loginSmsCode(@RequestBody IdRequest request) {
|
||||
return this.service.loginSmsCode(request);
|
||||
}
|
||||
|
||||
|
||||
@PostMapping("/logout")
|
||||
@SysLog(action = "退出")
|
||||
public Object logout() {
|
||||
|
||||
@@ -5,7 +5,14 @@ import lombok.Data;
|
||||
@Data
|
||||
public class LoginDto {
|
||||
|
||||
/**
|
||||
* 0 用户名密码登录
|
||||
* 1 短信验证码登录
|
||||
*/
|
||||
private String loginType = "0";
|
||||
|
||||
private String username;
|
||||
private String phone;
|
||||
private String password;
|
||||
private String captchaId;
|
||||
private String captcha;
|
||||
|
||||
@@ -13,15 +13,23 @@ import cn.lihongjie.coal.loginUserHis.service.LoginUserHisService;
|
||||
import cn.lihongjie.coal.organization.entity.OrganizationEntity;
|
||||
import cn.lihongjie.coal.organization.service.OrganizationService;
|
||||
import cn.lihongjie.coal.ratelimit.RateLimiterService;
|
||||
import cn.lihongjie.coal.sms.service.SmsService;
|
||||
import cn.lihongjie.coal.smsTemplate.entity.SmsTemplateEntity;
|
||||
import cn.lihongjie.coal.smsTemplate.service.SmsTemplateService;
|
||||
import cn.lihongjie.coal.sysconfig.service.SysConfigService;
|
||||
import cn.lihongjie.coal.user.dto.UserDto;
|
||||
import cn.lihongjie.coal.user.entity.UserEntity;
|
||||
import cn.lihongjie.coal.user.service.UserService;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import com.wf.captcha.SpecCaptcha;
|
||||
import com.wf.captcha.base.Captcha;
|
||||
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
import jakarta.persistence.criteria.Predicate;
|
||||
import jakarta.persistence.criteria.Root;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
import lombok.Data;
|
||||
@@ -31,6 +39,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
@@ -43,7 +52,9 @@ import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Service
|
||||
@@ -97,113 +108,7 @@ public class SessionService {
|
||||
|
||||
@Autowired RateLimiterService rateLimiterService;
|
||||
|
||||
@SneakyThrows
|
||||
public void login(LoginDto dto) {
|
||||
HttpServletRequest request =
|
||||
((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
|
||||
.getRequest();
|
||||
UserEntity user = null;
|
||||
|
||||
try {
|
||||
|
||||
if (sysConfigService.isEnable(Constants.SYSCONFIG_ENABLE_CAPTCHA)) {
|
||||
|
||||
String captchaId = dto.getCaptchaId();
|
||||
if (captchaId == null) {
|
||||
throw new BizException("验证码错误, 请刷新验证码重试");
|
||||
}
|
||||
|
||||
String expectCaptcha = stringRedisTemplate.opsForValue().get(captchaId);
|
||||
|
||||
if (expectCaptcha == null) {
|
||||
throw new BizException("验证码已失效");
|
||||
}
|
||||
|
||||
if (!StringUtils.equals(expectCaptcha, dto.getCaptcha())) {
|
||||
stringRedisTemplate.opsForValue().getAndDelete(captchaId);
|
||||
throw new BizException("验证码错误, 请刷新验证码重试");
|
||||
}
|
||||
}
|
||||
|
||||
user =
|
||||
userService
|
||||
.findByUsername(dto.getUsername())
|
||||
.orElseThrow(() -> new BizException("用户名或者密码错误"));
|
||||
|
||||
if (user.isDisabled()) {
|
||||
throw new BizException("用户被禁用");
|
||||
}
|
||||
|
||||
OrganizationEntity organization = organizationService.get(user.getOrganizationId());
|
||||
if (organization.isDisabled()) {
|
||||
throw new BizException("用户所在机构被禁用");
|
||||
}
|
||||
|
||||
if (organization.getExpireTime()!=null && organization.getExpireTime().isBefore(LocalDateTime.now())) {
|
||||
throw new BizException("用户所在机构已过期");
|
||||
}
|
||||
|
||||
if (!userService.isValidPassword(dto.getPassword(), user.getPassword())) {
|
||||
throw new BizException("用户名或者密码错误");
|
||||
}
|
||||
|
||||
LoginUserEntity entity = new LoginUserEntity();
|
||||
entity.setUser(user);
|
||||
entity.setCaptcha(dto.getCaptcha());
|
||||
entity.setIp(RequestUtils.getIp(request));
|
||||
entity.setUa(RequestUtils.getUa(request));
|
||||
try {
|
||||
|
||||
entity.setLocation(ipQueryService.query(entity.getIp()));
|
||||
} catch (Exception e) {
|
||||
log.warn("查询ip地址失败 {}", entity.getIp(), e);
|
||||
}
|
||||
loginUserService.newLogin(entity);
|
||||
|
||||
LoginUserDto loginUserDto = loginUserService.getFromCache(entity);
|
||||
|
||||
String sessionId = entity.getId();
|
||||
|
||||
SecurityContext context = SecurityContextHolder.createEmptyContext();
|
||||
|
||||
context.setAuthentication(
|
||||
new MyAuthentication(loginUserDto, loginUserDto.getUser(), sessionId));
|
||||
|
||||
SecurityContextHolder.setContext(context);
|
||||
LoginUserHisEntity his = new LoginUserHisEntity();
|
||||
his.setIp(RequestUtils.getIp(request));
|
||||
his.setUa(RequestUtils.getUa(request));
|
||||
his.setCaptcha(dto.getCaptcha());
|
||||
his.setUserName(dto.getUsername());
|
||||
his.setLoginStatus("1");
|
||||
his.setLocation(ipQueryService.query(his.getIp()));
|
||||
his.setLoginTime(LocalDateTime.now());
|
||||
his.setUser(user);
|
||||
his.setSessionId(sessionId);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
loginUserHisService.save(his);
|
||||
rateLimiterService.initRL(sessionId, user.getId());
|
||||
|
||||
} catch (Exception e) {
|
||||
|
||||
LoginUserHisEntity his = new LoginUserHisEntity();
|
||||
his.setIp(RequestUtils.getIp(request));
|
||||
his.setUa(RequestUtils.getUa(request));
|
||||
his.setCaptcha(dto.getCaptcha());
|
||||
his.setUserName(dto.getUsername());
|
||||
his.setLoginStatus("1");
|
||||
his.setLocation(ipQueryService.query(his.getIp()));
|
||||
his.setLoginTime(LocalDateTime.now());
|
||||
his.setUser(user);
|
||||
his.setRemarks(e.getMessage());
|
||||
loginUserHisService.save(his);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@Autowired SmsService smsService;
|
||||
|
||||
@SneakyThrows
|
||||
public void rebuildSession(String sessionId) {
|
||||
@@ -262,7 +167,6 @@ public class SessionService {
|
||||
|
||||
public void userLogout() {
|
||||
|
||||
|
||||
loginUserService.logout(
|
||||
new IdRequest(
|
||||
((SessionService.MyAuthentication)
|
||||
@@ -273,9 +177,6 @@ public class SessionService {
|
||||
((SessionService.MyAuthentication)
|
||||
SecurityContextHolder.getContext().getAuthentication())
|
||||
.getSessionId());
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void anonymousSession() {
|
||||
@@ -289,6 +190,208 @@ public class SessionService {
|
||||
|
||||
SecurityContextHolder.setContext(context);
|
||||
}
|
||||
@Autowired SmsTemplateService smsTemplateService;
|
||||
|
||||
@SneakyThrows
|
||||
public void login(LoginDto dto) {
|
||||
HttpServletRequest request =
|
||||
((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
|
||||
.getRequest();
|
||||
UserEntity user = null;
|
||||
|
||||
try {
|
||||
|
||||
if ((StringUtils.equalsIgnoreCase(dto.getLoginType(), "0")
|
||||
&& sysConfigService.isEnable(Constants.SYSCONFIG_ENABLE_CAPTCHA))) {
|
||||
|
||||
String captchaId = dto.getCaptchaId();
|
||||
if (captchaId == null) {
|
||||
throw new BizException("验证码错误, 请刷新验证码重试");
|
||||
}
|
||||
|
||||
String expectCaptcha = stringRedisTemplate.opsForValue().get(captchaId);
|
||||
|
||||
if (expectCaptcha == null) {
|
||||
throw new BizException("验证码已失效");
|
||||
}
|
||||
|
||||
if (!StringUtils.equals(expectCaptcha, dto.getCaptcha())) {
|
||||
stringRedisTemplate.opsForValue().getAndDelete(captchaId);
|
||||
throw new BizException("验证码错误, 请刷新验证码重试");
|
||||
}
|
||||
}
|
||||
|
||||
if (StringUtils.equalsIgnoreCase(dto.getLoginType(), "1")) {
|
||||
if (StringUtils.isEmpty(dto.getCaptcha()) || StringUtils.isEmpty(dto.getPhone())) {
|
||||
throw new BizException("短信验证码或者手机号不能为空");
|
||||
}
|
||||
user = userService.findUniqUserByPhone(dto.getPhone());
|
||||
|
||||
String captchaId = dto.getCaptchaId();
|
||||
if (captchaId == null) {
|
||||
throw new BizException("验证码错误, 请重新发送");
|
||||
}
|
||||
|
||||
String expectCaptcha = stringRedisTemplate.opsForValue().get(captchaId);
|
||||
|
||||
if (expectCaptcha == null) {
|
||||
throw new BizException("验证码已失效");
|
||||
}
|
||||
|
||||
if (!StringUtils.equals(expectCaptcha, dto.getCaptcha())) {
|
||||
stringRedisTemplate.opsForValue().getAndDelete(captchaId);
|
||||
throw new BizException("验证码错误, 请重新发送");
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
user =
|
||||
userService
|
||||
.findByUsername(dto.getUsername())
|
||||
.orElseThrow(() -> new BizException("用户名或者密码错误"));
|
||||
}
|
||||
|
||||
if (user.isDisabled()) {
|
||||
throw new BizException("用户被禁用");
|
||||
}
|
||||
|
||||
OrganizationEntity organization = organizationService.get(user.getOrganizationId());
|
||||
if (organization.isDisabled()) {
|
||||
throw new BizException("用户所在机构被禁用");
|
||||
}
|
||||
|
||||
if (organization.getExpireTime() != null
|
||||
&& organization.getExpireTime().isBefore(LocalDateTime.now())) {
|
||||
throw new BizException("用户所在机构已过期");
|
||||
}
|
||||
|
||||
if (!userService.isValidPassword(dto.getPassword(), user.getPassword())) {
|
||||
throw new BizException("用户名或者密码错误");
|
||||
}
|
||||
|
||||
LoginUserEntity entity = new LoginUserEntity();
|
||||
entity.setUser(user);
|
||||
entity.setCaptcha(dto.getCaptcha());
|
||||
entity.setIp(RequestUtils.getIp(request));
|
||||
entity.setUa(RequestUtils.getUa(request));
|
||||
try {
|
||||
|
||||
entity.setLocation(ipQueryService.query(entity.getIp()));
|
||||
} catch (Exception e) {
|
||||
log.warn("查询ip地址失败 {}", entity.getIp(), e);
|
||||
}
|
||||
loginUserService.newLogin(entity);
|
||||
|
||||
LoginUserDto loginUserDto = loginUserService.getFromCache(entity);
|
||||
|
||||
String sessionId = entity.getId();
|
||||
|
||||
SecurityContext context = SecurityContextHolder.createEmptyContext();
|
||||
|
||||
context.setAuthentication(
|
||||
new MyAuthentication(loginUserDto, loginUserDto.getUser(), sessionId));
|
||||
|
||||
SecurityContextHolder.setContext(context);
|
||||
LoginUserHisEntity his = new LoginUserHisEntity();
|
||||
his.setIp(RequestUtils.getIp(request));
|
||||
his.setUa(RequestUtils.getUa(request));
|
||||
his.setCaptcha(dto.getCaptcha());
|
||||
his.setUserName(dto.getUsername());
|
||||
his.setLoginStatus("1");
|
||||
his.setLocation(ipQueryService.query(his.getIp()));
|
||||
his.setLoginTime(LocalDateTime.now());
|
||||
his.setUser(user);
|
||||
his.setSessionId(sessionId);
|
||||
|
||||
loginUserHisService.save(his);
|
||||
rateLimiterService.initRL(sessionId, user.getId());
|
||||
|
||||
} catch (Exception e) {
|
||||
|
||||
LoginUserHisEntity his = new LoginUserHisEntity();
|
||||
his.setIp(RequestUtils.getIp(request));
|
||||
his.setUa(RequestUtils.getUa(request));
|
||||
his.setCaptcha(dto.getCaptcha());
|
||||
his.setUserName(dto.getUsername());
|
||||
his.setLoginStatus("1");
|
||||
his.setLocation(ipQueryService.query(his.getIp()));
|
||||
his.setLoginTime(LocalDateTime.now());
|
||||
his.setUser(user);
|
||||
his.setRemarks(e.getMessage());
|
||||
loginUserHisService.save(his);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public CaptchaDto loginSmsCode(IdRequest request) {
|
||||
|
||||
UserEntity user = userService.findUniqUserByPhone(request.getId());
|
||||
|
||||
String organizationId = user.getOrganizationId();
|
||||
|
||||
String id = UUID.randomUUID().toString();
|
||||
|
||||
String code = ThreadLocalRandom.current().nextInt(1, 9999) + "";
|
||||
|
||||
stringRedisTemplate.opsForValue().set(id, code, 5, TimeUnit.MINUTES);
|
||||
|
||||
ObjectNode objectNode = objectMapper.createObjectNode();
|
||||
objectNode.put("code", code);
|
||||
|
||||
Long orgTemplateCount =
|
||||
smsTemplateService.count(
|
||||
new Specification<SmsTemplateEntity>() {
|
||||
@Override
|
||||
public Predicate toPredicate(
|
||||
Root<SmsTemplateEntity> root,
|
||||
CriteriaQuery<?> query,
|
||||
CriteriaBuilder criteriaBuilder) {
|
||||
|
||||
return criteriaBuilder.and(
|
||||
criteriaBuilder.equal(root.get("code"), "login"),
|
||||
criteriaBuilder.equal(
|
||||
root.get("organizationId"), organizationId));
|
||||
}
|
||||
});
|
||||
|
||||
if (orgTemplateCount > 0) {
|
||||
|
||||
smsService.sendSmsMessage(
|
||||
user.getPhone(),
|
||||
objectMapper.writeValueAsString(objectNode),
|
||||
"login",
|
||||
organizationId);
|
||||
} else {
|
||||
|
||||
List<SmsTemplateEntity> all =
|
||||
smsTemplateService.findAll(
|
||||
new Specification<SmsTemplateEntity>() {
|
||||
@Override
|
||||
public Predicate toPredicate(
|
||||
Root<SmsTemplateEntity> root,
|
||||
CriteriaQuery<?> query,
|
||||
CriteriaBuilder criteriaBuilder) {
|
||||
|
||||
return criteriaBuilder.and(
|
||||
criteriaBuilder.equal(
|
||||
root.get("code"), "login_global"));
|
||||
}
|
||||
});
|
||||
|
||||
if (all.isEmpty()) {
|
||||
throw new BizException("没有找到对应的短信模板 login_global");
|
||||
}
|
||||
|
||||
smsService.sendSmsMessage(
|
||||
user.getPhone(),
|
||||
objectMapper.writeValueAsString(objectNode),
|
||||
all.get(0),
|
||||
organizationId);
|
||||
}
|
||||
|
||||
return new CaptchaDto(id, null);
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class MyAuthentication implements Authentication {
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
package cn.lihongjie.coal.sms.controller;
|
||||
|
||||
import cn.lihongjie.coal.annotation.OrgScope;
|
||||
import cn.lihongjie.coal.annotation.SysLog;
|
||||
import cn.lihongjie.coal.base.dto.CommonQuery;
|
||||
import cn.lihongjie.coal.base.dto.IdRequest;
|
||||
import cn.lihongjie.coal.sms.dto.CreateSmsDto;
|
||||
import cn.lihongjie.coal.sms.dto.SmsDto;
|
||||
import cn.lihongjie.coal.sms.dto.UpdateSmsDto;
|
||||
import cn.lihongjie.coal.sms.service.SmsService;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
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;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/sms")
|
||||
@SysLog(module = "短信通知")
|
||||
@Slf4j
|
||||
@OrgScope
|
||||
public class SmsController {
|
||||
@Autowired private SmsService service;
|
||||
|
||||
@PostMapping("/create")
|
||||
public SmsDto create(@RequestBody CreateSmsDto request) {
|
||||
return this.service.create(request);
|
||||
}
|
||||
|
||||
@PostMapping("/update")
|
||||
public SmsDto update(@RequestBody UpdateSmsDto request) {
|
||||
return this.service.update(request);
|
||||
}
|
||||
|
||||
@PostMapping("/delete")
|
||||
public Object delete(@RequestBody IdRequest request) {
|
||||
this.service.delete(request);
|
||||
return true;
|
||||
}
|
||||
|
||||
@PostMapping("/getById")
|
||||
public SmsDto getById(@RequestBody IdRequest request) {
|
||||
return this.service.getById(request.getId());
|
||||
}
|
||||
|
||||
@PostMapping("/list")
|
||||
public Page<SmsDto> list(@RequestBody CommonQuery request) {
|
||||
return this.service.list(request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package cn.lihongjie.coal.sms.dto;
|
||||
|
||||
import cn.lihongjie.coal.base.dto.OrgCommonDto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class CreateSmsDto extends OrgCommonDto {}
|
||||
8
src/main/java/cn/lihongjie/coal/sms/dto/SmsDto.java
Normal file
8
src/main/java/cn/lihongjie/coal/sms/dto/SmsDto.java
Normal file
@@ -0,0 +1,8 @@
|
||||
package cn.lihongjie.coal.sms.dto;
|
||||
|
||||
import cn.lihongjie.coal.base.dto.OrgCommonDto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class SmsDto extends OrgCommonDto {}
|
||||
@@ -0,0 +1,8 @@
|
||||
package cn.lihongjie.coal.sms.dto;
|
||||
|
||||
import cn.lihongjie.coal.base.dto.OrgCommonDto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class UpdateSmsDto extends OrgCommonDto {}
|
||||
42
src/main/java/cn/lihongjie/coal/sms/entity/SmsEntity.java
Normal file
42
src/main/java/cn/lihongjie/coal/sms/entity/SmsEntity.java
Normal file
@@ -0,0 +1,42 @@
|
||||
package cn.lihongjie.coal.sms.entity;
|
||||
|
||||
import cn.lihongjie.coal.base.entity.OrgCommonEntity;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import org.hibernate.annotations.Comment;
|
||||
import org.hibernate.annotations.Formula;
|
||||
|
||||
@Data
|
||||
@Entity
|
||||
public class SmsEntity extends OrgCommonEntity {
|
||||
|
||||
private String accessKeyId;
|
||||
|
||||
private String endpoint;
|
||||
|
||||
private String signName;
|
||||
|
||||
private String templateCode;
|
||||
|
||||
private String phoneNumbers;
|
||||
|
||||
private String templateParam;
|
||||
|
||||
private String response;
|
||||
|
||||
@Comment("发送状态")
|
||||
private String execStatus;
|
||||
|
||||
@Formula(
|
||||
"(select i.name\n"
|
||||
+ "from t_dictionary d,\n"
|
||||
+ " t_dictionary_item i\n"
|
||||
+ "where d.id = i.dictionary_id\n"
|
||||
+ " and d.code = 'common.execStatus'\n"
|
||||
+ " and i.code = exec_status)")
|
||||
private String execStatusName;
|
||||
|
||||
}
|
||||
17
src/main/java/cn/lihongjie/coal/sms/mapper/SmsMapper.java
Normal file
17
src/main/java/cn/lihongjie/coal/sms/mapper/SmsMapper.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package cn.lihongjie.coal.sms.mapper;
|
||||
|
||||
import cn.lihongjie.coal.base.mapper.BaseMapper;
|
||||
import cn.lihongjie.coal.base.mapper.CommonMapper;
|
||||
import cn.lihongjie.coal.sms.dto.CreateSmsDto;
|
||||
import cn.lihongjie.coal.sms.dto.SmsDto;
|
||||
import cn.lihongjie.coal.sms.dto.UpdateSmsDto;
|
||||
import cn.lihongjie.coal.sms.entity.SmsEntity;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.control.DeepClone;
|
||||
|
||||
@Mapper(
|
||||
componentModel = org.mapstruct.MappingConstants.ComponentModel.SPRING,
|
||||
uses = {CommonMapper.class},
|
||||
mappingControl = DeepClone.class)
|
||||
public interface SmsMapper extends BaseMapper<SmsEntity, SmsDto, CreateSmsDto, UpdateSmsDto> {}
|
||||
@@ -0,0 +1,9 @@
|
||||
package cn.lihongjie.coal.sms.repository;
|
||||
|
||||
import cn.lihongjie.coal.base.dao.BaseRepository;
|
||||
import cn.lihongjie.coal.sms.entity.SmsEntity;
|
||||
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface SmsRepository extends BaseRepository<SmsEntity> {}
|
||||
165
src/main/java/cn/lihongjie/coal/sms/service/SmsService.java
Normal file
165
src/main/java/cn/lihongjie/coal/sms/service/SmsService.java
Normal file
@@ -0,0 +1,165 @@
|
||||
package cn.lihongjie.coal.sms.service;
|
||||
|
||||
import cn.lihongjie.coal.base.dto.CommonQuery;
|
||||
import cn.lihongjie.coal.base.dto.IdRequest;
|
||||
import cn.lihongjie.coal.base.service.BaseService;
|
||||
import cn.lihongjie.coal.common.Ctx;
|
||||
import cn.lihongjie.coal.exception.BizException;
|
||||
import cn.lihongjie.coal.sms.dto.CreateSmsDto;
|
||||
import cn.lihongjie.coal.sms.dto.SmsDto;
|
||||
import cn.lihongjie.coal.sms.dto.UpdateSmsDto;
|
||||
import cn.lihongjie.coal.sms.entity.SmsEntity;
|
||||
import cn.lihongjie.coal.sms.mapper.SmsMapper;
|
||||
import cn.lihongjie.coal.sms.repository.SmsRepository;
|
||||
import cn.lihongjie.coal.smsTemplate.entity.SmsTemplateEntity;
|
||||
import cn.lihongjie.coal.smsTemplate.service.SmsTemplateService;
|
||||
|
||||
import com.aliyun.dysmsapi20170525.Client;
|
||||
import com.aliyun.dysmsapi20170525.models.SendSmsResponse;
|
||||
import com.aliyun.teaopenapi.models.Config;
|
||||
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
import jakarta.persistence.criteria.Predicate;
|
||||
import jakarta.persistence.criteria.Root;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
@Transactional
|
||||
public class SmsService extends BaseService<SmsEntity, SmsRepository> {
|
||||
@Autowired private SmsRepository repository;
|
||||
|
||||
@Autowired private SmsMapper mapper;
|
||||
|
||||
@Autowired private ConversionService conversionService;
|
||||
|
||||
|
||||
@Autowired
|
||||
private SmsTemplateService smsTemplateService;
|
||||
|
||||
|
||||
@SneakyThrows
|
||||
public void sendSmsMessage(String phone, String templateParam, String sysTemplateCode) {
|
||||
sendSmsMessage(phone, templateParam, sysTemplateCode, Ctx.currentUser().getOrganizationId());
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public void sendSmsMessage(String phone, String templateParam, String sysTemplateCode, String organizationId) {
|
||||
|
||||
if (sysTemplateCode == null){
|
||||
throw new BizException("短信模板不能为空");
|
||||
}
|
||||
|
||||
if (organizationId == null){
|
||||
throw new BizException("组织机构不能为空");
|
||||
}
|
||||
|
||||
|
||||
List<SmsTemplateEntity> all = smsTemplateService.findAll(new Specification<SmsTemplateEntity>() {
|
||||
@Override
|
||||
public Predicate toPredicate(Root<SmsTemplateEntity> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
|
||||
return criteriaBuilder.and(
|
||||
criteriaBuilder.equal(root.get("code"), sysTemplateCode),
|
||||
criteriaBuilder.equal(root.get("organizationId"), organizationId)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
if (all.isEmpty()){
|
||||
throw new BizException("没有找到对应的短信模板 " + sysTemplateCode);
|
||||
}
|
||||
|
||||
sendSmsMessage(phone, templateParam, all.get(0), organizationId);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public void sendSmsMessage(String phone, String templateParam, SmsTemplateEntity template, String organizationId) {
|
||||
|
||||
SmsEntity sms = new SmsEntity();
|
||||
sms.setPhoneNumbers(phone);
|
||||
sms.setOrganizationId(organizationId);
|
||||
sms.setTemplateParam(templateParam);
|
||||
sms.setAccessKeyId(template.getAccessKeyId());
|
||||
sms.setEndpoint(template.getEndpoint());
|
||||
sms.setSignName(template.getSignName());
|
||||
sms.setTemplateCode(template.getTemplateCode());
|
||||
|
||||
|
||||
Config config = new Config();
|
||||
config.accessKeyId = sms.getAccessKeyId();
|
||||
config.accessKeySecret = template.getAccessKeySecret();
|
||||
config.endpoint = sms.getEndpoint();
|
||||
|
||||
com.aliyun.dysmsapi20170525.Client client = new Client(config);
|
||||
com.aliyun.dysmsapi20170525.models.SendSmsRequest sendSmsRequest =
|
||||
new com.aliyun.dysmsapi20170525.models.SendSmsRequest()
|
||||
.setSignName(sms.getSignName())
|
||||
.setTemplateCode(sms.getTemplateCode())
|
||||
.setPhoneNumbers(sms.getPhoneNumbers())
|
||||
.setTemplateParam(sms.getTemplateParam());
|
||||
com.aliyun.teautil.models.RuntimeOptions runtime =
|
||||
new com.aliyun.teautil.models.RuntimeOptions();
|
||||
try {
|
||||
// 复制代码运行请自行打印 API 的返回值
|
||||
SendSmsResponse sendSmsResponse = client.sendSmsWithOptions(sendSmsRequest, runtime);
|
||||
sms.setResponse(sendSmsResponse.getBody().toString());
|
||||
} catch (Exception _error) {
|
||||
sms.setResponse(_error.getMessage());
|
||||
sms.setExecStatus("1");
|
||||
}
|
||||
|
||||
this.repository.save(sms);
|
||||
}
|
||||
|
||||
public SmsDto create(CreateSmsDto request) {
|
||||
SmsEntity entity = mapper.toEntity(request);
|
||||
|
||||
this.repository.save(entity);
|
||||
return getById(entity.getId());
|
||||
}
|
||||
|
||||
public SmsDto update(UpdateSmsDto request) {
|
||||
SmsEntity entity = this.repository.get(request.getId());
|
||||
this.mapper.updateEntity(entity, request);
|
||||
|
||||
this.repository.save(entity);
|
||||
|
||||
return getById(entity.getId());
|
||||
}
|
||||
|
||||
public void delete(IdRequest request) {
|
||||
this.repository.deleteAllById(request.getIds());
|
||||
}
|
||||
|
||||
public SmsDto getById(String id) {
|
||||
SmsEntity entity = repository.get(id);
|
||||
|
||||
return mapper.toDto(entity);
|
||||
}
|
||||
|
||||
public Page<SmsDto> list(CommonQuery query) {
|
||||
Page<SmsEntity> page =
|
||||
repository.findAll(
|
||||
query.specification(conversionService),
|
||||
PageRequest.of(
|
||||
query.getPageNo(),
|
||||
query.getPageSize(),
|
||||
Sort.by(query.getOrders())));
|
||||
|
||||
return page.map(this.mapper::toDto);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package cn.lihongjie.coal.smsTemplate.controller;
|
||||
|
||||
import cn.lihongjie.coal.annotation.OrgScope;
|
||||
import cn.lihongjie.coal.annotation.SysLog;
|
||||
import cn.lihongjie.coal.base.dto.CommonQuery;
|
||||
import cn.lihongjie.coal.base.dto.IdRequest;
|
||||
import cn.lihongjie.coal.smsTemplate.dto.CreateSmsTemplateDto;
|
||||
import cn.lihongjie.coal.smsTemplate.dto.SmsTemplateDto;
|
||||
import cn.lihongjie.coal.smsTemplate.dto.UpdateSmsTemplateDto;
|
||||
import cn.lihongjie.coal.smsTemplate.service.SmsTemplateService;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
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;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/smsTemplate")
|
||||
@SysLog(module = "短信模板")
|
||||
@Slf4j
|
||||
@OrgScope
|
||||
public class SmsTemplateController {
|
||||
@Autowired private SmsTemplateService service;
|
||||
|
||||
@PostMapping("/create")
|
||||
public SmsTemplateDto create(@RequestBody CreateSmsTemplateDto request) {
|
||||
return this.service.create(request);
|
||||
}
|
||||
|
||||
@PostMapping("/update")
|
||||
public SmsTemplateDto update(@RequestBody UpdateSmsTemplateDto request) {
|
||||
return this.service.update(request);
|
||||
}
|
||||
|
||||
@PostMapping("/delete")
|
||||
public Object delete(@RequestBody IdRequest request) {
|
||||
this.service.delete(request);
|
||||
return true;
|
||||
}
|
||||
|
||||
@PostMapping("/getById")
|
||||
public SmsTemplateDto getById(@RequestBody IdRequest request) {
|
||||
return this.service.getById(request.getId());
|
||||
}
|
||||
|
||||
@PostMapping("/list")
|
||||
public Page<SmsTemplateDto> list(@RequestBody CommonQuery request) {
|
||||
return this.service.list(request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package cn.lihongjie.coal.smsTemplate.dto;
|
||||
|
||||
import cn.lihongjie.coal.base.dto.OrgCommonDto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class CreateSmsTemplateDto extends OrgCommonDto {}
|
||||
@@ -0,0 +1,8 @@
|
||||
package cn.lihongjie.coal.smsTemplate.dto;
|
||||
|
||||
import cn.lihongjie.coal.base.dto.OrgCommonDto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class SmsTemplateDto extends OrgCommonDto {}
|
||||
@@ -0,0 +1,8 @@
|
||||
package cn.lihongjie.coal.smsTemplate.dto;
|
||||
|
||||
import cn.lihongjie.coal.base.dto.OrgCommonDto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class UpdateSmsTemplateDto extends OrgCommonDto {}
|
||||
@@ -0,0 +1,24 @@
|
||||
package cn.lihongjie.coal.smsTemplate.entity;
|
||||
|
||||
import cn.lihongjie.coal.base.entity.OrgCommonEntity;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Entity
|
||||
public class SmsTemplateEntity extends OrgCommonEntity {
|
||||
|
||||
|
||||
private String accessKeyId;
|
||||
|
||||
private String accessKeySecret;
|
||||
|
||||
private String endpoint;
|
||||
|
||||
private String signName;
|
||||
|
||||
private String templateCode;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package cn.lihongjie.coal.smsTemplate.mapper;
|
||||
|
||||
import cn.lihongjie.coal.base.mapper.BaseMapper;
|
||||
import cn.lihongjie.coal.base.mapper.CommonMapper;
|
||||
import cn.lihongjie.coal.smsTemplate.dto.CreateSmsTemplateDto;
|
||||
import cn.lihongjie.coal.smsTemplate.dto.SmsTemplateDto;
|
||||
import cn.lihongjie.coal.smsTemplate.dto.UpdateSmsTemplateDto;
|
||||
import cn.lihongjie.coal.smsTemplate.entity.SmsTemplateEntity;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.control.DeepClone;
|
||||
|
||||
@Mapper(
|
||||
componentModel = org.mapstruct.MappingConstants.ComponentModel.SPRING,
|
||||
uses = {CommonMapper.class},
|
||||
mappingControl = DeepClone.class)
|
||||
public interface SmsTemplateMapper
|
||||
extends BaseMapper<
|
||||
SmsTemplateEntity, SmsTemplateDto, CreateSmsTemplateDto, UpdateSmsTemplateDto> {}
|
||||
@@ -0,0 +1,9 @@
|
||||
package cn.lihongjie.coal.smsTemplate.repository;
|
||||
|
||||
import cn.lihongjie.coal.base.dao.BaseRepository;
|
||||
import cn.lihongjie.coal.smsTemplate.entity.SmsTemplateEntity;
|
||||
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface SmsTemplateRepository extends BaseRepository<SmsTemplateEntity> {}
|
||||
@@ -0,0 +1,70 @@
|
||||
package cn.lihongjie.coal.smsTemplate.service;
|
||||
|
||||
import cn.lihongjie.coal.base.dto.CommonQuery;
|
||||
import cn.lihongjie.coal.base.dto.IdRequest;
|
||||
import cn.lihongjie.coal.base.service.BaseService;
|
||||
import cn.lihongjie.coal.smsTemplate.dto.CreateSmsTemplateDto;
|
||||
import cn.lihongjie.coal.smsTemplate.dto.SmsTemplateDto;
|
||||
import cn.lihongjie.coal.smsTemplate.dto.UpdateSmsTemplateDto;
|
||||
import cn.lihongjie.coal.smsTemplate.entity.SmsTemplateEntity;
|
||||
import cn.lihongjie.coal.smsTemplate.mapper.SmsTemplateMapper;
|
||||
import cn.lihongjie.coal.smsTemplate.repository.SmsTemplateRepository;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
@Transactional
|
||||
public class SmsTemplateService extends BaseService<SmsTemplateEntity, SmsTemplateRepository> {
|
||||
@Autowired private SmsTemplateRepository repository;
|
||||
|
||||
@Autowired private SmsTemplateMapper mapper;
|
||||
|
||||
@Autowired private ConversionService conversionService;
|
||||
|
||||
public SmsTemplateDto create(CreateSmsTemplateDto request) {
|
||||
SmsTemplateEntity entity = mapper.toEntity(request);
|
||||
|
||||
this.repository.save(entity);
|
||||
return getById(entity.getId());
|
||||
}
|
||||
|
||||
public SmsTemplateDto update(UpdateSmsTemplateDto request) {
|
||||
SmsTemplateEntity entity = this.repository.get(request.getId());
|
||||
this.mapper.updateEntity(entity, request);
|
||||
|
||||
this.repository.save(entity);
|
||||
|
||||
return getById(entity.getId());
|
||||
}
|
||||
|
||||
public void delete(IdRequest request) {
|
||||
this.repository.deleteAllById(request.getIds());
|
||||
}
|
||||
|
||||
public SmsTemplateDto getById(String id) {
|
||||
SmsTemplateEntity entity = repository.get(id);
|
||||
|
||||
return mapper.toDto(entity);
|
||||
}
|
||||
|
||||
public Page<SmsTemplateDto> list(CommonQuery query) {
|
||||
Page<SmsTemplateEntity> page =
|
||||
repository.findAll(
|
||||
query.specification(conversionService),
|
||||
PageRequest.of(
|
||||
query.getPageNo(),
|
||||
query.getPageSize(),
|
||||
Sort.by(query.getOrders())));
|
||||
|
||||
return page.map(this.mapper::toDto);
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,7 @@ import jakarta.persistence.criteria.Root;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -369,4 +370,24 @@ public class UserService extends BaseService<UserEntity, UserRepository> {
|
||||
log.error("清除用户权限缓存失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
public UserEntity findUniqUserByPhone(final String phone) {
|
||||
List<UserEntity> users = findAll(new Specification<UserEntity>() {
|
||||
@Override
|
||||
public Predicate toPredicate(Root<UserEntity> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
|
||||
return criteriaBuilder.equal(root.get("phone"), phone);
|
||||
}
|
||||
});
|
||||
if (CollectionUtils.isEmpty(users)){
|
||||
throw new BizException("手机号不存在");
|
||||
}
|
||||
|
||||
|
||||
if (users.size() > 1){
|
||||
throw new BizException("手机号重复");
|
||||
}
|
||||
|
||||
UserEntity user = users.get(0);
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user