之前在网上看别人的技术文章时,往往看到一些写的很不错的文章,但是都设置了验证码访问,需要扫码关注公众号获取验证码输入之后才能浏览完整的文章内容,感觉这个功能太棒了,简直就是引流神器,于是乎,在某个闲暇周末自己动手改造了一下本人的博客实现了这么一个功能,至于为什么写这篇文章呢?是因为有小伙伴也想要实现这个功能,希望我能出一篇教程。好啦,废话不多说,直接干!
干之前还是先看下成品吧!
后台操作非常简单,只需要发布文章的时候选择自定义模板validation即可,完全不影响原有的密码功能,并且密码验证成功之后session记录
本功能实现所依赖的环境:
- 博客程序:halo1.6
- 博客主题:Joe2.0
本次修改主要包涵一下几点:
- 后端新增接口:生成注册码、检查注册码,新增定时任务:清理过期注册码
- 前端验证码提示框
一、后端修改部分:
1、RegistrationCode:run.halo.app.model.entity.RegistrationCode
package run.halo.app.model.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Index;
import javax.persistence.Table;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.hibernate.annotations.ColumnDefault;
import org.hibernate.annotations.GenericGenerator;
import run.halo.app.model.enums.RegistrationCodeStatus;
import run.halo.app.model.enums.RegistrationCodeType;
/**
* 注册码
*
* @author lywq
* @date 2023/06/14 09:33
**/
@Data
@Entity
@Table(name = "registration_codes", indexes = {@Index(name = "code_index", columnList = "code")})
@ToString
@EqualsAndHashCode(callSuper = true)
public class RegistrationCode extends BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY, generator = "custom-id")
@GenericGenerator(name = "custom-id",
strategy = "run.halo.app.model.entity.support.CustomIdGenerator")
private Integer id;
/**
* 注册码
*/
@Column(name = "code", nullable = false, columnDefinition = "VARCHAR(50) COMMENT '注册码'")
private String code;
/**
* 类型 0-通用,1-售卖,2-激励广告,3-微信公众号,4-微信小程序
*/
@Column(name = "type", nullable = false, columnDefinition = "TINYINT(0) COMMENT '类型:0-通用,1-售卖,2-激励广告,3-微信公众号,4-微信小程序'")
private RegistrationCodeType type;
/**
* 状态 0-未使用,1-已使用,-1-已失效
*/
@Column(name = "status", nullable = false, columnDefinition = "TINYINT(0) COMMENT '状态 0-未使用,1-已使用,-1-已失效'")
@ColumnDefault("0")
private RegistrationCodeStatus status;
/**
* 用户名
*/
@Column(name = "user_name", columnDefinition = "VARCHAR(50) COMMENT '用户名'")
private String userName;
}
2、RegistrationCodeDTO:run.halo.app.model.dto.RegistrationCodeDTO
package run.halo.app.model.dto;
import lombok.Data;
import run.halo.app.model.dto.base.OutputConverter;
import run.halo.app.model.entity.RegistrationCode;
import run.halo.app.model.enums.RegistrationCodeStatus;
import run.halo.app.model.enums.RegistrationCodeType;
/**
* 注册码
*
* @author lywq
* @date 2023/01/31 17:37
**/
@Data
public class RegistrationCodeDTO implements OutputConverter<RegistrationCodeDTO, RegistrationCode> {
/**
* 主键
*/
private Integer id;
/**
* 注册码
*/
private String code;
/**
* 类型 0-通用,1-售卖,2-激励广告,3-微信公众号,4-微信小程序
*/
private RegistrationCodeType type;
/**
* 状态 0-未使用,1-已使用,-1-已失效
*/
private RegistrationCodeStatus status;
/**
* 用户名
*/
private String userName;
}
3、RegistrationCodeParam:run.halo.app.model.params.RegistrationCodeParam
package run.halo.app.model.params;
import lombok.Data;
import run.halo.app.model.dto.base.InputConverter;
import run.halo.app.model.entity.RegistrationCode;
import run.halo.app.model.enums.RegistrationCodeStatus;
import run.halo.app.model.enums.RegistrationCodeType;
/**
* RegistrationCode param
*
* @author lywq
* @date 2023/02/09 09:51
**/
@Data
public class RegistrationCodeParam implements InputConverter<RegistrationCode> {
/**
* 主键
*/
private Integer id;
/**
* 注册码
*/
private String code;
/**
* 类型 0-通用,1-售卖,2-激励广告,3-微信公众号,4-微信小程序
*/
private RegistrationCodeType type = RegistrationCodeType.COMMON;
/**
* 状态 0-未使用,1-已使用,-1-已失效
*/
private RegistrationCodeStatus status = RegistrationCodeStatus.NOT_USED;
/**
* 用户名
*/
private String userName;
@Override
public void update(RegistrationCode domain) {
InputConverter.super.update(domain);
}
}
4、RegistrationCodeStatus:run.halo.app.model.enums.RegistrationCodeStatus
package run.halo.app.model.enums;
/**
* 注册码状态 枚举
*
* @author lywq
* @date 2023/06/14 10:03
**/
public enum RegistrationCodeStatus implements ValueEnum<Integer> {
/**
* 已失效
*/
INVALIDATED(-1),
/**
* 未使用
*/
NOT_USED(0),
/**
* 已使用
*/
USED(1);
private final int value;
RegistrationCodeStatus(int value) {
this.value = value;
}
@Override
public Integer getValue() {
return value;
}
}
5、RegistrationCodeType:run.halo.app.model.enums.RegistrationCodeType
package run.halo.app.model.enums;
/**
* 注册码类型 枚举
*
* @author lywq
* @date 2023/06/14 09:37
**/
public enum RegistrationCodeType implements ValueEnum<Integer> {
/**
* 通用
*/
COMMON(0),
/**
* 售卖
*/
SALE(1),
/**
* 激励广告
*/
INCENTIVE_ADVERTISING(2),
/**
* 微信公众号
*/
WECHAT_OFFICIAL_ACCOUNT(3),
/**
* 微信小程序
*/
WECHAT_APPLET(4);
private final int value;
RegistrationCodeType(int value) {
this.value = value;
}
@Override
public Integer getValue() {
return value;
}
}
6、RegistrationCodeRepository:run.halo.app.repository.RegistrationCodeRepository
package run.halo.app.repository;
import java.util.List;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.lang.NonNull;
import run.halo.app.model.entity.RegistrationCode;
import run.halo.app.model.enums.RegistrationCodeStatus;
import run.halo.app.repository.base.BaseRepository;
/**
* RegistrationCode repository
*
* @author lywq
* @date 2023/01/31 18:13
**/
public interface RegistrationCodeRepository
extends BaseRepository<RegistrationCode, Integer>, JpaSpecificationExecutor<RegistrationCode> {
@NonNull
List<RegistrationCode> findAllByStatus(@NonNull RegistrationCodeStatus status);
}
7、RegistrationCodeService:run.halo.app.service.RegistrationCodeService
package run.halo.app.service;
import java.util.Collection;
import java.util.List;
import org.springframework.lang.NonNull;
import run.halo.app.model.dto.RegistrationCodeDTO;
import run.halo.app.model.entity.RegistrationCode;
import run.halo.app.model.enums.RegistrationCodeStatus;
import run.halo.app.model.params.RegistrationCodeParam;
import run.halo.app.service.base.CrudService;
/**
* 注册码接口
*
* @author lywq
* @date 2023/06/14 10:20
**/
public interface RegistrationCodeService extends CrudService<RegistrationCode, Integer> {
@NonNull
RegistrationCode createBy(@NonNull RegistrationCodeParam registrationCodeParam);
RegistrationCode updateBy(@NonNull RegistrationCode registrationCode);
RegistrationCode getBy(@NonNull String code);
boolean existByCode(String code);
@NonNull
List<RegistrationCode> listAllBy(@NonNull RegistrationCodeStatus status);
@NonNull
List<RegistrationCode> removeByIds(@NonNull Collection<Integer> ids);
RegistrationCodeDTO convertTo(@NonNull RegistrationCode registrationCode);
boolean checkRegistrationCode(@NonNull String code);
}
8、RegistrationCodeServiceImpl:run.halo.app.service.impl.RegistrationCodeServiceImpl
package run.halo.app.service.impl;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import org.jetbrains.annotations.NotNull;
import org.springframework.data.domain.Example;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import run.halo.app.model.dto.RegistrationCodeDTO;
import run.halo.app.model.entity.RegistrationCode;
import run.halo.app.model.enums.RegistrationCodeStatus;
import run.halo.app.model.params.RegistrationCodeParam;
import run.halo.app.repository.RegistrationCodeRepository;
import run.halo.app.repository.base.BaseRepository;
import run.halo.app.service.RegistrationCodeService;
import run.halo.app.service.base.AbstractCrudService;
import run.halo.app.utils.RegistrationCodeUtil;
/**
* 注册码接口
*
* @author lywq
* @date 2023/06/14 10:57
**/
@Service
public class RegistrationCodeServiceImpl extends AbstractCrudService<RegistrationCode, Integer>
implements RegistrationCodeService {
private final RegistrationCodeRepository registrationCodeRepository;
protected RegistrationCodeServiceImpl(
BaseRepository<RegistrationCode, Integer> repository,
RegistrationCodeRepository registrationCodeRepository) {
super(repository);
this.registrationCodeRepository = registrationCodeRepository;
}
@Override
public @NotNull RegistrationCode createBy(
@NotNull RegistrationCodeParam registrationCodeParam) {
Assert.notNull(registrationCodeParam, "RegistrationCode param must not be null");
RegistrationCode registrationCode = registrationCodeParam.convertTo();
List<RegistrationCode> registrationCodes = listAll();
List<String> list =
registrationCodes.stream().map(RegistrationCode::getCode).collect(Collectors.toList());
String code = RegistrationCodeUtil.createRegistrationCode(list);
registrationCode.setCode(code);
return create(registrationCode);
}
@Override
public RegistrationCode updateBy(@NotNull RegistrationCode registrationCode) {
Assert.notNull(registrationCode, "RegistrationCode must not be null");
return update(registrationCode);
}
@Override
public RegistrationCode getBy(@NotNull String code) {
RegistrationCode registrationCode = new RegistrationCode();
registrationCode.setCode(code);
registrationCode.setStatus(RegistrationCodeStatus.NOT_USED);
return registrationCodeRepository.findOne(Example.of(registrationCode)).orElse(null);
}
@Override
public boolean existByCode(String code) {
Assert.hasText(code, "registrationCode must not be blank");
RegistrationCode registrationCode = new RegistrationCode();
registrationCode.setCode(code);
registrationCode.setStatus(RegistrationCodeStatus.NOT_USED);
return registrationCodeRepository.exists(Example.of(registrationCode));
}
@Override
public List<RegistrationCode> listAllBy(RegistrationCodeStatus status) {
Assert.notNull(status, "RegistrationCode status must not be null");
return registrationCodeRepository.findAllByStatus(status);
}
@Override
public List<RegistrationCode> removeByIds(Collection<Integer> ids) {
if (CollectionUtils.isEmpty(ids)) {
return Collections.emptyList();
}
return ids.stream().map(this::removeById).collect(Collectors.toList());
}
@Override
public RegistrationCodeDTO convertTo(@NotNull RegistrationCode registrationCode) {
Assert.notNull(registrationCode, "RegistrationCode must not be null");
return new RegistrationCodeDTO().convertFrom(registrationCode);
}
@Override
public boolean checkRegistrationCode(String code) {
RegistrationCode registrationCode = this.getBy(code);
if (Objects.nonNull(registrationCode)) {
registrationCode.setStatus(RegistrationCodeStatus.USED);
this.updateBy(registrationCode);
return true;
} else {
return false;
}
}
}
评论区