From 1b7bf095dcb1593e2204bf0d52b3b9c236fae094 Mon Sep 17 00:00:00 2001 From: YuNan <3194726156@qq.com> Date: Tue, 5 Nov 2024 17:10:26 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8F=91=E9=80=81=E9=82=AE=E7=AE=B1=E9=AA=8C?= =?UTF-8?q?=E8=AF=81=E7=A0=81-=E5=9F=BA=E7=A1=80=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/compiler.xml | 4 +- .idea/encodings.xml | 3 +- .idea/misc.xml | 2 +- YuNan-demo/pom.xml | 11 +- .../java/com/yunan/YuNanDemoApplication.java | 20 +- .../com/yunan/config/GlobalCorsConfig.java | 30 + .../java/com/yunan/config/RedisConfig.java | 26 + .../java/com/yunan/config/SwaggerConfig.java | 106 ++++ .../java/com/yunan/constant/ResponseCode.java | 19 + .../com/yunan/controller/AuthController.java | 90 +++ .../main/java/com/yunan/dto/ApiResponse.java | 46 ++ .../src/main/java/com/yunan/dto/LoginDTO.java | 57 ++ .../main/java/com/yunan/dto/RegisterDTO.java | 67 ++ .../src/main/java/com/yunan/entity/Mail.java | 12 + .../java/com/yunan/mapper/AuthMapper.java | 13 + .../src/main/java/com/yunan/pojo/User.java | 90 +++ .../java/com/yunan/service/AuthService.java | 17 + .../java/com/yunan/service/EmailService.java | 43 ++ .../yunan/service/impl/AuthServiceImpl.java | 124 ++++ .../main/java/com/yunan/util/RedisUtils.java | 571 ++++++++++++++++++ .../com/yunan/util/VerificationCodeUtils.java | 22 + YuNan-demo/src/main/resources/application.yml | 55 ++ pom.xml | 88 ++- 23 files changed, 1504 insertions(+), 12 deletions(-) create mode 100644 YuNan-demo/src/main/java/com/yunan/config/GlobalCorsConfig.java create mode 100644 YuNan-demo/src/main/java/com/yunan/config/RedisConfig.java create mode 100644 YuNan-demo/src/main/java/com/yunan/config/SwaggerConfig.java create mode 100644 YuNan-demo/src/main/java/com/yunan/constant/ResponseCode.java create mode 100644 YuNan-demo/src/main/java/com/yunan/controller/AuthController.java create mode 100644 YuNan-demo/src/main/java/com/yunan/dto/ApiResponse.java create mode 100644 YuNan-demo/src/main/java/com/yunan/dto/LoginDTO.java create mode 100644 YuNan-demo/src/main/java/com/yunan/dto/RegisterDTO.java create mode 100644 YuNan-demo/src/main/java/com/yunan/entity/Mail.java create mode 100644 YuNan-demo/src/main/java/com/yunan/mapper/AuthMapper.java create mode 100644 YuNan-demo/src/main/java/com/yunan/pojo/User.java create mode 100644 YuNan-demo/src/main/java/com/yunan/service/AuthService.java create mode 100644 YuNan-demo/src/main/java/com/yunan/service/EmailService.java create mode 100644 YuNan-demo/src/main/java/com/yunan/service/impl/AuthServiceImpl.java create mode 100644 YuNan-demo/src/main/java/com/yunan/util/RedisUtils.java create mode 100644 YuNan-demo/src/main/java/com/yunan/util/VerificationCodeUtils.java create mode 100644 YuNan-demo/src/main/resources/application.yml diff --git a/.idea/compiler.xml b/.idea/compiler.xml index 795bb95..1064b9e 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -2,17 +2,19 @@ + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml index 170213c..e24ea69 100644 --- a/.idea/encodings.xml +++ b/.idea/encodings.xml @@ -1,9 +1,10 @@ - + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 7e9ee9a..730065e 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -9,7 +9,7 @@ - + \ No newline at end of file diff --git a/YuNan-demo/pom.xml b/YuNan-demo/pom.xml index 32663b9..659445e 100644 --- a/YuNan-demo/pom.xml +++ b/YuNan-demo/pom.xml @@ -10,14 +10,21 @@ YuNan-demo - pom + jar + + - + + + org.springframework.boot + spring-boot-maven-plugin + + diff --git a/YuNan-demo/src/main/java/com/yunan/YuNanDemoApplication.java b/YuNan-demo/src/main/java/com/yunan/YuNanDemoApplication.java index e5ec0cb..5715769 100644 --- a/YuNan-demo/src/main/java/com/yunan/YuNanDemoApplication.java +++ b/YuNan-demo/src/main/java/com/yunan/YuNanDemoApplication.java @@ -1,13 +1,31 @@ package com.yunan; +import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -@SpringBootApplication +import java.net.InetAddress; +import java.net.UnknownHostException; + +@Slf4j +@SpringBootApplication(scanBasePackages = "com.yunan") public class YuNanDemoApplication { public static void main(String[] 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" + + "----------------------------------------------------------"); + } } diff --git a/YuNan-demo/src/main/java/com/yunan/config/GlobalCorsConfig.java b/YuNan-demo/src/main/java/com/yunan/config/GlobalCorsConfig.java new file mode 100644 index 0000000..0f44495 --- /dev/null +++ b/YuNan-demo/src/main/java/com/yunan/config/GlobalCorsConfig.java @@ -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); + } +} diff --git a/YuNan-demo/src/main/java/com/yunan/config/RedisConfig.java b/YuNan-demo/src/main/java/com/yunan/config/RedisConfig.java new file mode 100644 index 0000000..fe12611 --- /dev/null +++ b/YuNan-demo/src/main/java/com/yunan/config/RedisConfig.java @@ -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 + redisTemplate(RedisConnectionFactory connectionFactory) { + RedisTemplate redisTemplate = new + RedisTemplate(); + redisTemplate.setKeySerializer(new StringRedisSerializer()); + redisTemplate.setValueSerializer + (new JdkSerializationRedisSerializer()); + redisTemplate.setConnectionFactory(connectionFactory); + return redisTemplate; + } +} + diff --git a/YuNan-demo/src/main/java/com/yunan/config/SwaggerConfig.java b/YuNan-demo/src/main/java/com/yunan/config/SwaggerConfig.java new file mode 100644 index 0000000..1fc8723 --- /dev/null +++ b/YuNan-demo/src/main/java/com/yunan/config/SwaggerConfig.java @@ -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() // 扩展列表 + ); + } +} + + diff --git a/YuNan-demo/src/main/java/com/yunan/constant/ResponseCode.java b/YuNan-demo/src/main/java/com/yunan/constant/ResponseCode.java new file mode 100644 index 0000000..f2ade94 --- /dev/null +++ b/YuNan-demo/src/main/java/com/yunan/constant/ResponseCode.java @@ -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; + + // 你可以根据需要继续添加其他状态码 +} + diff --git a/YuNan-demo/src/main/java/com/yunan/controller/AuthController.java b/YuNan-demo/src/main/java/com/yunan/controller/AuthController.java new file mode 100644 index 0000000..f273abc --- /dev/null +++ b/YuNan-demo/src/main/java/com/yunan/controller/AuthController.java @@ -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 register(@RequestBody RegisterDTO registerDTO) { +// return authService.register(registerDTO); + return null; + } + + // 存储已发送的验证码 + private final Map emailCodeMap = new ConcurrentHashMap<>(16); + + /** + * 发送验证码 + * @param mail + * @return {@link ApiResponse }<{@link String }> + * @throws MessagingException + */ + @PostMapping("/sendEmail") + @ApiOperation("邮箱验证码") + public ApiResponse 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,"验证码已发送"); + } + + + + + +} \ No newline at end of file diff --git a/YuNan-demo/src/main/java/com/yunan/dto/ApiResponse.java b/YuNan-demo/src/main/java/com/yunan/dto/ApiResponse.java new file mode 100644 index 0000000..b19e6fd --- /dev/null +++ b/YuNan-demo/src/main/java/com/yunan/dto/ApiResponse.java @@ -0,0 +1,46 @@ +package com.yunan.dto; + + +public class ApiResponse { + + 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; + } +} + diff --git a/YuNan-demo/src/main/java/com/yunan/dto/LoginDTO.java b/YuNan-demo/src/main/java/com/yunan/dto/LoginDTO.java new file mode 100644 index 0000000..3ad94e1 --- /dev/null +++ b/YuNan-demo/src/main/java/com/yunan/dto/LoginDTO.java @@ -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; + } +} diff --git a/YuNan-demo/src/main/java/com/yunan/dto/RegisterDTO.java b/YuNan-demo/src/main/java/com/yunan/dto/RegisterDTO.java new file mode 100644 index 0000000..b0a83f6 --- /dev/null +++ b/YuNan-demo/src/main/java/com/yunan/dto/RegisterDTO.java @@ -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; + } +} diff --git a/YuNan-demo/src/main/java/com/yunan/entity/Mail.java b/YuNan-demo/src/main/java/com/yunan/entity/Mail.java new file mode 100644 index 0000000..5551bec --- /dev/null +++ b/YuNan-demo/src/main/java/com/yunan/entity/Mail.java @@ -0,0 +1,12 @@ +package com.yunan.entity; + +import lombok.Data; + +@Data +public class Mail { + public String email; + public String username; + public String password; +} + + diff --git a/YuNan-demo/src/main/java/com/yunan/mapper/AuthMapper.java b/YuNan-demo/src/main/java/com/yunan/mapper/AuthMapper.java new file mode 100644 index 0000000..b4d7260 --- /dev/null +++ b/YuNan-demo/src/main/java/com/yunan/mapper/AuthMapper.java @@ -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 { + void insertUser(RegisterDTO registerDTO); + + User findUserByEmail(String email); +} diff --git a/YuNan-demo/src/main/java/com/yunan/pojo/User.java b/YuNan-demo/src/main/java/com/yunan/pojo/User.java new file mode 100644 index 0000000..c834d95 --- /dev/null +++ b/YuNan-demo/src/main/java/com/yunan/pojo/User.java @@ -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; + } +} diff --git a/YuNan-demo/src/main/java/com/yunan/service/AuthService.java b/YuNan-demo/src/main/java/com/yunan/service/AuthService.java new file mode 100644 index 0000000..9301e79 --- /dev/null +++ b/YuNan-demo/src/main/java/com/yunan/service/AuthService.java @@ -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; + +} diff --git a/YuNan-demo/src/main/java/com/yunan/service/EmailService.java b/YuNan-demo/src/main/java/com/yunan/service/EmailService.java new file mode 100644 index 0000000..d6c09e1 --- /dev/null +++ b/YuNan-demo/src/main/java/com/yunan/service/EmailService.java @@ -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); + } +} + + diff --git a/YuNan-demo/src/main/java/com/yunan/service/impl/AuthServiceImpl.java b/YuNan-demo/src/main/java/com/yunan/service/impl/AuthServiceImpl.java new file mode 100644 index 0000000..a03cdae --- /dev/null +++ b/YuNan-demo/src/main/java/com/yunan/service/impl/AuthServiceImpl.java @@ -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 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 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("验证码错误,请检查后重试"); // 或者定义自定义异常 + } + } + +} diff --git a/YuNan-demo/src/main/java/com/yunan/util/RedisUtils.java b/YuNan-demo/src/main/java/com/yunan/util/RedisUtils.java new file mode 100644 index 0000000..d05b036 --- /dev/null +++ b/YuNan-demo/src/main/java/com/yunan/util/RedisUtils.java @@ -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 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) 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 hmget(String key) { + return redisTemplate.opsForHash().entries(key); + } + + /** + * HashSet + * + * @param key 键 + * @param map 对应多个键值 + * @return true 成功 false 失败 + */ + public boolean hmset(String key, Map 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 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 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 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 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 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; + } + } +} + diff --git a/YuNan-demo/src/main/java/com/yunan/util/VerificationCodeUtils.java b/YuNan-demo/src/main/java/com/yunan/util/VerificationCodeUtils.java new file mode 100644 index 0000000..dd56ef1 --- /dev/null +++ b/YuNan-demo/src/main/java/com/yunan/util/VerificationCodeUtils.java @@ -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(); + } +} + diff --git a/YuNan-demo/src/main/resources/application.yml b/YuNan-demo/src/main/resources/application.yml new file mode 100644 index 0000000..62ba5d0 --- /dev/null +++ b/YuNan-demo/src/main/resources/application.yml @@ -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 diff --git a/pom.xml b/pom.xml index dade1f5..fd225f0 100644 --- a/pom.xml +++ b/pom.xml @@ -8,23 +8,58 @@ 1.0.0 pom + + + YuNan-demo + org.springframework.boot spring-boot-starter-parent - 3.3.4 + 2.7.10 - - - + - 17 + 1.8 + 8.0.32 + 3.5.3 + 7.4.0 + 3.0.0 - + + + + org.springframework.boot + spring-boot-starter-web + + + + org.projectlombok + lombok + provided + + + + org.testng + testng + ${testng.version} + compile + + + + org.springframework.boot + spring-boot-test + + + + org.junit.jupiter + junit-jupiter-api + + org.springframework.boot spring-boot-starter @@ -35,6 +70,47 @@ spring-boot-starter-test test + + + com.mysql + mysql-connector-j + ${mysql.version} + + + + com.baomidou + mybatis-plus-boot-starter + ${mybatis-plus.version} + + + + io.springfox + springfox-boot-starter + ${swagger.version} + + + + com.github.xiaoymin + knife4j-spring-boot-starter + 3.0.3 + + + + + org.springframework.boot + spring-boot-starter-mail + + + + org.springframework.boot + spring-boot-starter-data-redis + + + + + org.apache.commons + commons-pool2 +