发送邮箱验证码-基础设置

This commit is contained in:
YuNan 2024-11-05 17:10:26 +08:00
parent bbfe532bca
commit 1b7bf095dc
23 changed files with 1504 additions and 12 deletions

View File

@ -2,17 +2,19 @@
<project version="4"> <project version="4">
<component name="CompilerConfiguration"> <component name="CompilerConfiguration">
<annotationProcessing> <annotationProcessing>
<profile default="true" name="Default" enabled="true" />
<profile name="Maven default annotation processors profile" enabled="true"> <profile name="Maven default annotation processors profile" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" /> <sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" /> <sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" /> <outputRelativeToContentRoot value="true" />
<module name="YuNan-demo" />
</profile> </profile>
</annotationProcessing> </annotationProcessing>
</component> </component>
<component name="JavacSettings"> <component name="JavacSettings">
<option name="ADDITIONAL_OPTIONS_OVERRIDE"> <option name="ADDITIONAL_OPTIONS_OVERRIDE">
<module name="YuNan-cmd" options="" /> <module name="YuNan-cmd" options="" />
<module name="YuNan-demo" options="" /> <module name="YuNan-demo" options="-parameters" />
</option> </option>
</component> </component>
</project> </project>

View File

@ -1,9 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="Encoding"> <component name="Encoding" defaultCharsetForPropertiesFiles="UTF-8">
<file url="file://$PROJECT_DIR$/YuNan-demo/src/main/java" charset="UTF-8" /> <file url="file://$PROJECT_DIR$/YuNan-demo/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/YuNan-demo/src/main/resources" charset="UTF-8" /> <file url="file://$PROJECT_DIR$/YuNan-demo/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" /> <file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" /> <file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
<file url="PROJECT" charset="UTF-8" />
</component> </component>
</project> </project>

View File

@ -9,7 +9,7 @@
</list> </list>
</option> </option>
</component> </component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" /> <output url="file://$PROJECT_DIR$/out" />
</component> </component>
</project> </project>

View File

@ -10,14 +10,21 @@
</parent> </parent>
<artifactId>YuNan-demo</artifactId> <artifactId>YuNan-demo</artifactId>
<packaging>pom</packaging> <packaging>jar</packaging>
<dependencies> <dependencies>
<!-- 添加特有的依赖 -->
</dependencies> </dependencies>
<build> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build> </build>
</project> </project>

View File

@ -1,13 +1,31 @@
package com.yunan; package com.yunan;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication import java.net.InetAddress;
import java.net.UnknownHostException;
@Slf4j
@SpringBootApplication(scanBasePackages = "com.yunan")
public class YuNanDemoApplication { public class YuNanDemoApplication {
public static void main(String[] args) { public static void main(String[] args) {
SpringApplication.run(YuNanDemoApplication.class, args); SpringApplication.run(YuNanDemoApplication.class, args);
// 获取本地 IP 地址
String ip;
try {
ip = InetAddress.getLocalHost().getHostAddress(); // 获取本地 IP 地址
} catch (UnknownHostException e) {
ip = "localhost"; // 如果无法获取 IP设为 localhost
}
// 打印 Swagger 文档的 URL
log.info("\n----------------------------------------------------------\n\t" +
"Swagger文档: \thttp://" + ip + ":8080/doc.html\n" +
"----------------------------------------------------------");
} }
} }

View File

@ -0,0 +1,30 @@
package com.yunan.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
@Configuration
public class GlobalCorsConfig {
/**
* 解决跨域问题
* @return {@link CorsFilter }
*/
@Bean
public CorsFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
// 设置你要允许的网站域名
config.addAllowedOrigin("http://localhost:3100");
//允许跨域发送cookie
config.setAllowCredentials(true);
//放行全部原始头信息
config.addAllowedHeader("*");
//允许所有请求方法跨域调用
config.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}

View File

@ -0,0 +1,26 @@
package com.yunan.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/*告诉spring,运行的时候加载读取这个类*/
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object>
redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> redisTemplate = new
RedisTemplate<String, Object>();
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer
(new JdkSerializationRedisSerializer());
redisTemplate.setConnectionFactory(connectionFactory);
return redisTemplate;
}
}

View File

@ -0,0 +1,106 @@
package com.yunan.config;
//
//import org.springframework.context.annotation.Bean;
//import org.springframework.context.annotation.Configuration;
//import springfox.documentation.builders.ApiInfoBuilder;
//import springfox.documentation.builders.PathSelectors;
//import springfox.documentation.builders.RequestHandlerSelectors;
//import springfox.documentation.oas.annotations.EnableOpenApi;
//import springfox.documentation.service.ApiInfo;
//import springfox.documentation.service.Contact;
//import springfox.documentation.spi.DocumentationType;
//import springfox.documentation.spring.web.plugins.Docket;
//
//import java.util.Collections;
//
//
//@Configuration //声明配置类
//@EnableOpenApi //开启swagger支持
//public class SwaggerConfig {
//
// /**
// * Docket类是Swagger的配置类要自定义修改Swagger的默认配置信息我们需要覆盖该对象
// *
// * @return
// */
// @Bean
// public Docket docket() {
// //1.以OAS_30标准构建Docket配置类
// return new Docket(DocumentationType.OAS_30)
// //2.配置Swagger接口文档基本信息apiInfo
// .apiInfo(apiInfo())
// //3.select方法开启配置扫描接口的Builder
// .select()
// //4.指定要扫描/维护接口文档的包否则就全部扫描
// .apis(RequestHandlerSelectors.basePackage("com.yunan.controller"))
// //5.路径过滤该Docket-UI展示时只展示指定路径下的接口文档(any表示都展示)
// .paths(PathSelectors.any())
// .build();
// }
//
// /**
// * 配置 Swagger 接口文档的基本信息
// *
// * @return
// */
// private ApiInfo apiInfo() {
// return new ApiInfoBuilder()
// //1.接口文档标题
// .title("SpringBoot整合Swagger")
// //2.接口文档描述内容
// .description("这里是SpringBoot整合Swagger的详细信息......,包括...")
// //3.项目文档迭代版本
// .version("9.0")
// //4.主要联系人信息姓名name个人主页url邮箱email
//// .contact(new Contact("阿安", "www.baidu.com", "3194726156@qq.com"))
// //5.相关许可证信息
//// .license("The CSDN License")
// //6.相关许可证链接
//// .licenseUrl("www.baidu.com")
// //7.返回构建的ApiInfo对象
// .build();
// }
//}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.Collections;
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("com.yunan.controller")) // 替换为你的包名
.paths(PathSelectors.any())
.build()
.apiInfo(apiInfo());
}
private ApiInfo apiInfo() {
return new ApiInfo(
"API标题", // 标题
"API描述", // 描述
"版本信息", // 版本
"服务条款URL", // 服务条款URL
new Contact("联系人姓名", "网址", "邮箱"), // 联系人信息
"许可证", // 许可证
"许可证URL", // 许可证URL
Collections.emptyList() // 扩展列表
);
}
}

View File

@ -0,0 +1,19 @@
package com.yunan.constant;
public class ResponseCode {
// 成功
public static final int SUCCESS = 200;
// 失败
public static final int ERROR = 500;
// 其他常用的状态码
public static final int BAD_REQUEST = 400;
public static final int UNAUTHORIZED = 401;
public static final int FORBIDDEN = 403;
public static final int NOT_FOUND = 404;
// 你可以根据需要继续添加其他状态码
}

View File

@ -0,0 +1,90 @@
package com.yunan.controller;
import com.yunan.constant.ResponseCode;
import com.yunan.dto.ApiResponse;
import com.yunan.dto.LoginDTO;
import com.yunan.dto.RegisterDTO;
import com.yunan.entity.Mail;
import com.yunan.pojo.User;
import com.yunan.service.AuthService;
import com.yunan.service.EmailService;
import com.yunan.util.VerificationCodeUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.mail.MessagingException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@RestController //注解标识这是一个控制器类
@RequestMapping("/auth")
@Slf4j
@Api(tags = "身份验证接口")
public class AuthController {
@Resource
private AuthService authService;
@Autowired
private EmailService emailService;
/**
* 用户登入
* @param loginDTO
*/
@PostMapping("/login")
@ApiOperation("用户登入")
public void login(@RequestBody LoginDTO loginDTO) {
// authService.login(loginDTO.getUsername(), loginDTO.getPassword());
}
/**
* 用户注册
* @param registerDTO
*/
@PostMapping("/register")
@ApiOperation("用户注册")
public ResponseEntity<User> register(@RequestBody RegisterDTO registerDTO) {
// return authService.register(registerDTO);
return null;
}
// 存储已发送的验证码
private final Map<String, String> emailCodeMap = new ConcurrentHashMap<>(16);
/**
* 发送验证码
* @param mail
* @return {@link ApiResponse }<{@link String }>
* @throws MessagingException
*/
@PostMapping("/sendEmail")
@ApiOperation("邮箱验证码")
public ApiResponse<String> sendEmail(@RequestBody Mail mail) throws MessagingException {
// 生成验证码
String code = VerificationCodeUtils.generateCode(6);
// 发送邮件
String subject = "注册验证码";
String content = "尊敬的用户,您的验证码为:" + code;
emailService.sendMail(mail.email, subject, content);
// 保存验证码
emailCodeMap.put(mail.email, code);
return new ApiResponse<>(ResponseCode.SUCCESS,"验证码已发送");
}
}

View File

@ -0,0 +1,46 @@
package com.yunan.dto;
public class ApiResponse<T> {
private int code;
private String message;
private T data;
public ApiResponse(int code, String message) {
this.code = code;
this.message = message;
}
public ApiResponse(int code, String message, T data) {
this.code = code;
this.message = message;
this.data = data;
}
// Getters and Setters
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}

View File

@ -0,0 +1,57 @@
package com.yunan.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
@ApiModel("用户登入请求")
public class LoginDTO {
@NotBlank(message = "用户名不能为空")
@ApiModelProperty(value = "用户名", required = true)
private String username;
@Email(message = "请输入有效的邮箱")
@ApiModelProperty(value = "邮箱")
private String email;
@NotBlank(message = "密码不能为空")
@ApiModelProperty(value = "密码", required = true)
private String password;
private String token;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}

View File

@ -0,0 +1,67 @@
package com.yunan.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
@ApiModel("用户注册请求")
public class RegisterDTO {
@NotBlank(message = "用户名不能为空")
@ApiModelProperty(value = "用户名", required = true)
private String username;
@Email(message = "请输入有效的邮箱")
@ApiModelProperty(value = "邮箱", required = true)
private String email;
@NotBlank(message = "密码不能为空")
@ApiModelProperty(value = "密码", required = true)
private String password;
@ApiModelProperty(value = "验证码")
private String code;
private String token;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
}

View File

@ -0,0 +1,12 @@
package com.yunan.entity;
import lombok.Data;
@Data
public class Mail {
public String email;
public String username;
public String password;
}

View File

@ -0,0 +1,13 @@
package com.yunan.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yunan.dto.RegisterDTO;
import com.yunan.pojo.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface AuthMapper extends BaseMapper<User> {
void insertUser(RegisterDTO registerDTO);
User findUserByEmail(String email);
}

View File

@ -0,0 +1,90 @@
package com.yunan.pojo;
import java.io.Serializable;
/**
* 用户实体类
*/
public class User implements Serializable {
private int id;
/** 用户名*/
private String username;
/** 密码*/
private String password;
/** 邮箱*/
private String email;
/** 创建用户信息时间 */
private String createTime;
/** 修改用户信息时间 */
private String updateTime;
/** 用户状态*/
private int state;
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
", email='" + email + '\'' +
", createTime='" + createTime + '\'' +
", updateTime='" + updateTime + '\'' +
", state=" + state +
'}';
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmai() {
return email;
}
public void setEmai(String email) {
this.email = email;
}
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
}
public String getCreate_Time() {
return createTime;
}
public void setCreate_Time(String create_Time) {
this.createTime = create_Time;
}
public String getUpdate_Time() {
return updateTime;
}
public void setUpdate_Time(String update_Time) {
this.updateTime = update_Time;
}
}

View File

@ -0,0 +1,17 @@
package com.yunan.service;
import com.yunan.dto.ApiResponse;
import com.yunan.dto.RegisterDTO;
import com.yunan.entity.Mail;
import com.yunan.pojo.User;
import javax.mail.internet.AddressException;
import java.io.UnsupportedEncodingException;
public interface AuthService {
User register(RegisterDTO registerDTO) throws AddressException, UnsupportedEncodingException;
}

View File

@ -0,0 +1,43 @@
package com.yunan.service;
import com.yunan.dto.ApiResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
@Service
public class EmailService {
@Autowired
private JavaMailSender mailSender;
@Value("${spring.mail.username}")
private String from;
/**
* 发送邮件
*
* @param to 收件人邮箱
* @param subject 邮件主题
* @param content 邮件内容
*/
public void sendMail(String to, String subject, String content) throws MessagingException {
// 创建邮件消息
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom(from);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(content, true);
// 发送邮件
mailSender.send(message);
}
}

View File

@ -0,0 +1,124 @@
package com.yunan.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yunan.constant.ResponseCode;
import com.yunan.dto.ApiResponse;
import com.yunan.dto.RegisterDTO;
import com.yunan.mapper.AuthMapper;
import com.yunan.pojo.User;
import com.yunan.service.AuthService;
import com.yunan.util.VerificationCodeUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PathVariable;
import javax.annotation.Resource;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeUtility;
import java.io.UnsupportedEncodingException;
import java.util.concurrent.TimeUnit;
@Service
public class AuthServiceImpl implements AuthService {
@Resource
private AuthMapper authMapper;
@Resource
private StringRedisTemplate stringRedisTemplate;
@Resource
private JavaMailSender mailSender;
/**
* 发送邮箱验证码
*
* @param email
* @return {@link String }
*/
public String sendEmail(@PathVariable String email) throws UnsupportedEncodingException, AddressException {
String key = "msg_" + email;
ValueOperations valueOperations = stringRedisTemplate.opsForValue();
String already_have = (String) valueOperations.get(key);
if (already_have == null) {
// 随机生成一个6位数字型的字符串
String code = "123456";
// 邮件对象
SimpleMailMessage message = new SimpleMailMessage();
message.setSubject("医院小程序邮箱验证码");
message.setText("尊敬的用户您好!\n\n感谢您使用XX医院。\n\n尊敬的: " + email + "您的校验验证码为: " + code + ",有效期2分钟请不要把验证码信息泄露给其他人,如非本人请勿操作");
message.setTo(email);
// 对方看到的发送人
message.setFrom(new InternetAddress(MimeUtility.encodeText("医院官方") + "<2774668116@qq.com>").toString());
//发送邮件
mailSender.send(message);
valueOperations.set(key, code, 5L, TimeUnit.MINUTES);
return code;
} else {
return already_have;
}
}
/**
* 验证码验证是否正确
* @param email
* @param code
* @return {@link Integer }
*/
public Integer verifyCode(String email, String code) {
int result = 1;
ValueOperations valueOperations = stringRedisTemplate.opsForValue();
String msgKey = "msg_" + email;
Object value = valueOperations.get(msgKey);
if(value == null){
result = -1;
}else if(!code.equals(value)) {
result = 0;
}
// 如果验证码正确则删除从redis
if(result == 1){
stringRedisTemplate.delete(msgKey);
}
/*
1 验证码正确
0 验证码错误
-1 验证码过期
*/
return result;
}
@Override
public User register(RegisterDTO registerDTO) throws AddressException, UnsupportedEncodingException {
String code = sendEmail(registerDTO.getEmail());
Integer result = verifyCode(registerDTO.getEmail(), registerDTO.getCode());
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
if(result == 1){
queryWrapper.eq(User::getUsername, registerDTO.getUsername());
Long l = authMapper.selectCount(queryWrapper);
if(l == 0){
// 插入用户到数据库
authMapper.insertUser(registerDTO);
// emailServiceImpl.sendEmail(registerDTO.getEmail(), "注册确认", "请点击以下链接进行确认...");
// 返回注册成功的用户对象可根据需求返回具体的 User 对象
// LambdaQueryWrapper<User> queryWrapperByEmail = new LambdaQueryWrapper<>();
// queryWrapperByEmail.eq(User::getEmai, registerDTO.getEmail());
return authMapper.findUserByEmail(registerDTO.getEmail()); // 假设有这个方法来查询用户
}else{
throw new RuntimeException("用户存在,请重新输入");
}
} else if (result == -1) { // 验证码过期
throw new RuntimeException("验证码已过期,请重新获取"); // 或者定义自定义异常
} else { // 验证码错误
throw new RuntimeException("验证码错误,请检查后重试"); // 或者定义自定义异常
}
}
}

View File

@ -0,0 +1,571 @@
package com.yunan.util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* redis 工具类
*
* @author simon
* @date 2018-11-28 10:35
**/
@Component
public class RedisUtils {
/**
* 注入redisTemplate bean
*/
@Autowired
private RedisTemplate<String,Object> redisTemplate;
/**
* 指定缓存失效时间
*
* @param key
* @param time 时间()
* @return
*/
public boolean expire(String key, long time) {
try {
if (time > 0) {
redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 根据key获取过期时间
*
* @param key 不能为null
* @return 时间() 返回0代表为永久有效
*/
public long getExpire(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}
/**
* 判断key是否存在
*
* @param key
* @return true 存在 false不存在
*/
public boolean hasKey(String key) {
try {
return redisTemplate.hasKey(key);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 删除缓存
*
* @param key 可以传一个值 或多个
*/
@SuppressWarnings("unchecked")
public void del(String... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
redisTemplate.delete(key[0]);
} else {
redisTemplate.delete((Collection<String>) CollectionUtils.arrayToList(key));
}
}
}
// ============================String(字符串)=============================
/**
* 普通缓存获取
*
* @param key
* @return
*/
public Object get(String key) {
return key == null ? null : redisTemplate.opsForValue().get(key);
}
/**
* 普通缓存放入
*
* @param key
* @param value
* @return true成功 false失败
*/
public boolean set(String key, Object value) {
try {
redisTemplate.opsForValue().set(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 普通缓存放入并设置时间
*
* @param key
* @param value
* @param time 时间() time要大于0 如果time小于等于0 将设置无限期
* @return true成功 false 失败
*/
public boolean set(String key, Object value, long time) {
try {
if (time > 0) {
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
} else {
set(key, value);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 递增
*
* @param key
* @param delta 要增加几(大于0)
* @return
*/
public long incr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递增因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, delta);
}
/**
* 递减
*
* @param key
* @param delta 要减少几(小于0)
* @return
*/
public long decr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递减因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, -delta);
}
// ================================Hash(哈希)=================================
/**
* HashGet
*
* @param key 不能为null
* @param item 不能为null
* @return
*/
public Object hget(String key, String item) {
return redisTemplate.opsForHash().get(key, item);
}
/**
* 获取hashKey对应的所有键值
*
* @param key
* @return 对应的多个键值
*/
public Map<Object, Object> hmget(String key) {
return redisTemplate.opsForHash().entries(key);
}
/**
* HashSet
*
* @param key
* @param map 对应多个键值
* @return true 成功 false 失败
*/
public boolean hmset(String key, Map <String, Object> map) {
try {
redisTemplate.opsForHash().putAll(key, map);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* HashSet 并设置时间
*
* @param key
* @param map 对应多个键值
* @param time 时间()
* @return true成功 false失败
*/
public boolean hmset(String key, Map <String, Object> map, long time) {
try {
redisTemplate.opsForHash().putAll(key, map);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key
* @param item
* @param value
* @return true 成功 false失败
*/
public boolean hset(String key, String item, Object value) {
try {
redisTemplate.opsForHash().put(key, item, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key
* @param item
* @param value
* @param time 时间() 注意:如果已存在的hash表有时间,这里将会替换原有的时间
* @return true 成功 false失败
*/
public boolean hset(String key, String item, Object value, long time) {
try {
redisTemplate.opsForHash().put(key, item, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 删除hash表中的值
*
* @param key 不能为null
* @param item 可以使多个 不能为null
*/
public void hdel(String key, Object... item) {
redisTemplate.opsForHash().delete(key, item);
}
/**
* 判断hash表中是否有该项的值
*
* @param key 不能为null
* @param item 不能为null
* @return true 存在 false不存在
*/
public boolean hHasKey(String key, String item) {
return redisTemplate.opsForHash().hasKey(key, item);
}
/**
* hash递增 如果不存在,就会创建一个 并把新增后的值返回
*
* @param key
* @param item
* @param by 要增加几(大于0)
* @return
*/
public double hincr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, by);
}
/**
* hash递减
*
* @param key
* @param item
* @param by 要减少记(小于0)
* @return
*/
public double hdecr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, -by);
}
// ============================Set(集合)=============================
/**
* 根据key获取Set中的所有值
*
* @param key
* @return
*/
public Set<Object> sGet(String key) {
try {
return redisTemplate.opsForSet().members(key);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 根据value从一个set中查询,是否存在
*
* @param key
* @param value
* @return true 存在 false不存在
*/
public boolean sHasKey(String key, Object value) {
try {
return redisTemplate.opsForSet().isMember(key, value);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将数据放入set缓存
*
* @param key
* @param values 可以是多个
* @return 成功个数
*/
public long sSet(String key, Object... values) {
try {
return redisTemplate.opsForSet().add(key, values);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 将set数据放入缓存
*
* @param key
* @param time 时间()
* @param values 可以是多个
* @return 成功个数
*/
public long sSetAndTime(String key, long time, Object... values) {
try {
Long count = redisTemplate.opsForSet().add(key, values);
if (time > 0)
expire(key, time);
return count;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 获取set缓存的长度
*
* @param key
* @return
*/
public long sGetSetSize(String key) {
try {
return redisTemplate.opsForSet().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 移除值为value的
*
* @param key
* @param values 可以是多个
* @return 移除的个数
*/
public long setRemove(String key, Object... values) {
try {
Long count = redisTemplate.opsForSet().remove(key, values);
return count;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
// ===============================List(列表)=================================
/**
* 获取list缓存的内容
*
* @param key
* @param start 开始
* @param end 结束 0 -1代表所有值
* @return
*/
public List<Object> lGet(String key, long start, long end) {
try {
return redisTemplate.opsForList().range(key, start, end);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 获取list缓存的长度
*
* @param key
* @return
*/
public long lGetListSize(String key) {
try {
return redisTemplate.opsForList().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 通过索引 获取list中的值
*
* @param key
* @param index 索引 index>=0时 0 表头1 第二个元素依次类推index<0时-1表尾-2倒数第二个元素依次类推
* @return
*/
public Object lGetIndex(String key, long index) {
try {
return redisTemplate.opsForList().index(key, index);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 将list放入缓存
*
* @param key
* @param value
* @return
*/
public boolean lSet(String key, Object value) {
try {
redisTemplate.opsForList().rightPush(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
*
* @param key
* @param value
* @param time 时间()
* @return
*/
public boolean lSet(String key, Object value, long time) {
try {
redisTemplate.opsForList().rightPush(key, value);
if (time > 0)
expire(key, time);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
*
* @param key
* @param value
* @return
*/
public boolean lSet(String key, List <Object> value) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
*
* @param key
* @param value
* @param time 时间()
* @return
*/
public boolean lSet(String key, List <Object> value, long time) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
if (time > 0)
expire(key, time);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 根据索引修改list中的某条数据
*
* @param key
* @param index 索引
* @param value
* @return
*/
public boolean lUpdateIndex(String key, long index, Object value) {
try {
redisTemplate.opsForList().set(key, index, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 移除N个值为value
*
* @param key
* @param count 移除多少个
* @param value
* @return 移除的个数
*/
public long lRemove(String key, long count, Object value) {
try {
Long remove = redisTemplate.opsForList().remove(key, count, value);
return remove;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
}

View File

@ -0,0 +1,22 @@
package com.yunan.util;
import java.util.Random;
public class VerificationCodeUtils {
/**
* 生成随机验证码
*
* @param length 验证码长度
* @return 验证码
*/
public static String generateCode(int length) {
StringBuilder s = new StringBuilder();
Random random = new Random();
for (int i = 0; i < length; i++) {
int n = random.nextInt(10);
s.append(n);
}
return s.toString();
}
}

View File

@ -0,0 +1,55 @@
spring:
application:
name: YuNan-demo
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/yuna_blog_sys
username: root
password: wucong.0235332
mvc:
pathmatch:
matching-strategy: ant-path-matcher
#****************************mail***************************
mail:
# SMTP服务器这个是QQ邮箱的 其他邮箱请另行百度
host: smtp.qq.com
port: 465
# 发送验证码的邮箱
username: 3194726156@qq.com
# 授权码
password: ljtcrhshbfjodgfh
# 编码
default-encoding: utf-8
# 其它参数
properties:
mail:
smtp:
# 如果是用 SSL 方式,需要配置如下属性,使用qq邮箱的话需要开启
ssl:
enable: true
required: true
# 邮件接收时间的限制,单位毫秒
timeout: 10000
# 连接时间的限制,单位毫秒
connectiontimeout: 10000
# 邮件发送时间的限制,单位毫秒
writetimeout: 10000
#****************************Redis***************************
redis:
host: localhost # Redis 服务器地址
port: 6379 # Redis 服务器端口
password: # 如果 Redis 设置了密码
database: 0 # 使用的数据库索引,默认是 0
server:
port: 8080
logging:
level:
org.springframework.boot.context.web: DEBUG

88
pom.xml
View File

@ -8,23 +8,58 @@
<version>1.0.0</version> <version>1.0.0</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<modules>
<!-- 子模块列表 -->
<module>YuNan-demo</module>
</modules>
<parent> <parent>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId> <artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.4</version> <version>2.7.10</version>
<relativePath/> <!-- lookup parent from repository --> <relativePath/> <!-- lookup parent from repository -->
</parent> </parent>
<!-- 版本控制 -->
<!-- 版本控制 -->
<properties> <properties>
<java.version>17</java.version> <java.version>1.8</java.version>
<mysql.version>8.0.32</mysql.version>
<mybatis-plus.version>3.5.3</mybatis-plus.version>
<testng.version>7.4.0</testng.version>
<swagger.version>3.0.0</swagger.version>
</properties> </properties>
<!-- 依赖导入 --> <!-- 依赖导入 -->
<dependencies> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>${testng.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId> <artifactId>spring-boot-starter</artifactId>
@ -35,6 +70,47 @@
<artifactId>spring-boot-starter-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>${mysql.version}</version> <!-- 请根据需要调整版本 -->
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.version}</version> <!-- 确保使用正确的版本 -->
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>${swagger.version}</version>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
<!--mail邮件发送pom支持-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!--redis场景启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- redis 连接池 -->
<!--新版本连接池lettuce-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
</dependencies> </dependencies>
<build> <build>