支持短信验证码登录

This commit is contained in:
2024-01-05 16:03:19 +08:00
parent 9c6f9d1a10
commit 98b0218f46
21 changed files with 768 additions and 111 deletions

View File

@@ -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>

View File

@@ -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() {

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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);
}
}

View File

@@ -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 {}

View 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 {}

View File

@@ -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 {}

View 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;
}

View 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> {}

View File

@@ -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> {}

View 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);
}
}

View File

@@ -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);
}
}

View File

@@ -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 {}

View File

@@ -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 {}

View File

@@ -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 {}

View File

@@ -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;
}

View File

@@ -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> {}

View File

@@ -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> {}

View File

@@ -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);
}
}

View File

@@ -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;
}
}