初始化
This commit is contained in:
parent
4d23b57af2
commit
bcb200888e
@ -7,14 +7,14 @@
|
||||
<sourceOutputDir name="target/generated-sources/annotations" />
|
||||
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
|
||||
<outputRelativeToContentRoot value="true" />
|
||||
<module name="YuNan-system-start" />
|
||||
<module name="ECS-system-start" />
|
||||
</profile>
|
||||
</annotationProcessing>
|
||||
</component>
|
||||
<component name="JavacSettings">
|
||||
<option name="ADDITIONAL_OPTIONS_OVERRIDE">
|
||||
<module name="ECS-system-start" options="-parameters" />
|
||||
<module name="YuNan-cmd" options="" />
|
||||
<module name="YuNan-system-start" options="-parameters" />
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
17
.idea/dataSources.xml
Normal file
17
.idea/dataSources.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
||||
<data-source source="LOCAL" name="0@localhost" uuid="7ace6006-b2c1-43d5-b332-1f049544c3d7">
|
||||
<driver-ref>redis</driver-ref>
|
||||
<synchronize>true</synchronize>
|
||||
<jdbc-driver>jdbc.RedisDriver</jdbc-driver>
|
||||
<jdbc-url>jdbc:redis://localhost:6379/0</jdbc-url>
|
||||
<jdbc-additional-properties>
|
||||
<property name="com.intellij.clouds.kubernetes.db.host.port" />
|
||||
<property name="com.intellij.clouds.kubernetes.db.enabled" value="false" />
|
||||
<property name="com.intellij.clouds.kubernetes.db.container.port" />
|
||||
</jdbc-additional-properties>
|
||||
<working-dir>$ProjectFileDir$</working-dir>
|
||||
</data-source>
|
||||
</component>
|
||||
</project>
|
@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding" defaultCharsetForPropertiesFiles="UTF-8">
|
||||
<file url="file://$PROJECT_DIR$/YuNan-system-start/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/YuNan-system-start/src/main/resources" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/ECS-system-start/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/ECS-system-start/src/main/resources" 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="PROJECT" charset="UTF-8" />
|
||||
|
@ -11,6 +11,11 @@
|
||||
<option name="name" value="Maven Central repository" />
|
||||
<option name="url" value="https://repo1.maven.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Central Repository" />
|
||||
<option name="url" value="http://maven.aliyun.com/nexus/content/groups/public" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="jboss.community" />
|
||||
<option name="name" value="JBoss Community repository" />
|
||||
|
124
.idea/uiDesigner.xml
Normal file
124
.idea/uiDesigner.xml
Normal file
@ -0,0 +1,124 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Palette2">
|
||||
<group name="Swing">
|
||||
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
|
||||
</item>
|
||||
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.svg" removable="false" auto-create-binding="false" can-attach-label="true">
|
||||
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
|
||||
<initial-values>
|
||||
<property name="text" value="Button" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="RadioButton" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="CheckBox" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="Label" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||
<preferred-size width="200" height="200" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||
<preferred-size width="200" height="200" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
|
||||
<preferred-size width="-1" height="20" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
|
||||
</item>
|
||||
</group>
|
||||
</component>
|
||||
</project>
|
@ -4,12 +4,12 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>yunan-boot-parent</groupId>
|
||||
<artifactId>org.yunanframework.boot</artifactId>
|
||||
<groupId>ecs-boot-parent</groupId>
|
||||
<artifactId>org.ecsframework.boot</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>YuNan-system-start</artifactId>
|
||||
<artifactId>ECS-system-start</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
@ -1,17 +1,16 @@
|
||||
package com.yunan;
|
||||
package com.ecs;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
@Slf4j
|
||||
@SpringBootApplication(scanBasePackages = "com.yunan")
|
||||
@SpringBootApplication(scanBasePackages = "com.ecs")
|
||||
@EnableCaching//开启缓存
|
||||
@EnableScheduling // 启用定时任务
|
||||
public class YuNanDemoApplication {
|
@ -1,4 +1,4 @@
|
||||
package com.yunan.config;
|
||||
package com.ecs.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
@ -1,4 +1,4 @@
|
||||
package com.yunan.config;
|
||||
package com.ecs.config;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
@ -1,4 +1,4 @@
|
||||
package com.yunan.config;
|
||||
package com.ecs.config;
|
||||
//
|
||||
//import org.springframework.context.annotation.Bean;
|
||||
//import org.springframework.context.annotation.Configuration;
|
@ -0,0 +1,15 @@
|
||||
package com.ecs.controller;
|
||||
|
||||
import io.swagger.annotations.Api;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
|
||||
@RestController //注解标识这是一个控制器类
|
||||
@RequestMapping("/auth")
|
||||
@Slf4j
|
||||
@Api(tags = "身份验证接口")
|
||||
public class AuthController {
|
||||
|
||||
|
||||
}
|
4
ECS-system-start/src/main/java/com/ecs/entity/User.java
Normal file
4
ECS-system-start/src/main/java/com/ecs/entity/User.java
Normal file
@ -0,0 +1,4 @@
|
||||
package com.ecs.entity;
|
||||
|
||||
public class User {
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.yunan.handler;
|
||||
package com.ecs.handler;
|
||||
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
31
ECS-system-start/src/main/resources/application.yml
Normal file
31
ECS-system-start/src/main/resources/application.yml
Normal file
@ -0,0 +1,31 @@
|
||||
spring:
|
||||
application:
|
||||
name: ECS
|
||||
datasource:
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
url: jdbc:mysql://116.62.245.34:3306/ecs
|
||||
username: root
|
||||
password: e531fc3ca462bd0c
|
||||
mvc:
|
||||
pathmatch:
|
||||
matching-strategy: ant-path-matcher
|
||||
---
|
||||
|
||||
#****************************Redis***************************
|
||||
spring:
|
||||
redis:
|
||||
host: localhost # Redis 服务器地址
|
||||
port: 6379 # Redis 服务器端口
|
||||
password: # 如果 Redis 设置了密码
|
||||
database: 0 # 使用的数据库索引,默认是 0
|
||||
|
||||
|
||||
server:
|
||||
port: 8080
|
||||
|
||||
logging:
|
||||
level:
|
||||
org.springframework.boot.context.web: DEBUG
|
||||
|
||||
|
||||
|
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.ecs.mapper.AuthMapper">
|
||||
|
||||
</mapper>
|
@ -1,7 +1,6 @@
|
||||
package com.yunan;
|
||||
package com.ecs;
|
||||
|
||||
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
class YuNanDemoApplicationTests {
|
@ -1,19 +0,0 @@
|
||||
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;
|
||||
|
||||
// 你可以根据需要继续添加其他状态码
|
||||
}
|
||||
|
@ -1,77 +0,0 @@
|
||||
package com.yunan.controller;
|
||||
|
||||
import com.yunan.constant.ResponseCode;
|
||||
import com.yunan.response.ApiResponse;
|
||||
import com.yunan.dto.LoginDTO;
|
||||
import com.yunan.dto.RegisterDTO;
|
||||
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 lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.validation.Valid;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
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 ResponseEntity<Object> login(@RequestBody LoginDTO loginDTO) {
|
||||
return authService.login(loginDTO);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 用户注册
|
||||
* @param registerDTO
|
||||
*/
|
||||
@PostMapping("/register")
|
||||
@ApiOperation("用户注册")
|
||||
public ResponseEntity<Object> register(@RequestBody @Valid RegisterDTO registerDTO) throws MessagingException, UnsupportedEncodingException {
|
||||
return authService.register(registerDTO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送验证码
|
||||
* @param registerDTO
|
||||
* @return {@link ApiResponse }<{@link String }>
|
||||
* @throws MessagingException
|
||||
*/
|
||||
@PostMapping("/sendEmail")
|
||||
@ApiOperation("邮箱验证码")
|
||||
public ApiResponse<String> sendEmail(@RequestBody @Valid RegisterDTO registerDTO) throws MessagingException {
|
||||
|
||||
return emailService.sendMail(registerDTO.getEmail());
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
package com.yunan.controller;
|
||||
|
||||
import com.yunan.dto.Captcha;
|
||||
import com.yunan.response.Result;
|
||||
import com.yunan.service.CaptchaService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
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("/captcha")
|
||||
@Api(tags = "验证码拼图")
|
||||
public class CaptchaController {
|
||||
|
||||
@Autowired
|
||||
private CaptchaService captchaService;
|
||||
|
||||
@ApiOperation(value = "生成验证码拼图")
|
||||
@PostMapping("get-captcha")
|
||||
public Result getCaptcha(@RequestBody Captcha captcha) {
|
||||
return Result.ok(captchaService.getCaptcha(captcha));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,56 +0,0 @@
|
||||
package com.yunan.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class Captcha {
|
||||
|
||||
/**
|
||||
* 随机字符串
|
||||
**/
|
||||
private String nonceStr;
|
||||
/**
|
||||
* 验证值
|
||||
**/
|
||||
private String value;
|
||||
/**
|
||||
* 生成的画布的base64
|
||||
**/
|
||||
private String canvasSrc;
|
||||
/**
|
||||
* 画布宽度
|
||||
**/
|
||||
private Integer canvasWidth;
|
||||
/**
|
||||
* 画布高度
|
||||
**/
|
||||
private Integer canvasHeight;
|
||||
/**
|
||||
* 生成的阻塞块的base64
|
||||
**/
|
||||
private String blockSrc;
|
||||
/**
|
||||
* 阻塞块宽度
|
||||
**/
|
||||
private Integer blockWidth;
|
||||
/**
|
||||
* 阻塞块高度
|
||||
**/
|
||||
private Integer blockHeight;
|
||||
/**
|
||||
* 阻塞块凸凹半径
|
||||
**/
|
||||
private Integer blockRadius;
|
||||
/**
|
||||
* 阻塞块的横轴坐标
|
||||
**/
|
||||
private Integer blockX;
|
||||
/**
|
||||
* 阻塞块的纵轴坐标
|
||||
**/
|
||||
private Integer blockY;
|
||||
/**
|
||||
* 图片获取位置
|
||||
**/
|
||||
private Integer place;
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
package com.yunan.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.Email;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
@ApiModel("用户登入请求")
|
||||
@Data
|
||||
public class LoginDTO {
|
||||
|
||||
@NotBlank(message = "用户名不能为空")
|
||||
@ApiModelProperty(value = "用户名")
|
||||
private String username;
|
||||
|
||||
@Email(message = "请输入有效的邮箱")
|
||||
@ApiModelProperty(value = "邮箱")
|
||||
private String email;
|
||||
|
||||
@ApiModelProperty(value = "电话号码")
|
||||
private String phoneNumber;
|
||||
|
||||
@ApiModelProperty(value = "邮箱或者电话号码", required = true)
|
||||
private String emailOrPhoneNumber;
|
||||
|
||||
@NotBlank(message = "密码不能为空")
|
||||
@ApiModelProperty(value = "密码")
|
||||
private String password;
|
||||
|
||||
@ApiModelProperty(value = "验证码")
|
||||
private String code;
|
||||
|
||||
private String token;
|
||||
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
package com.yunan.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.Email;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
@ApiModel("用户注册请求")
|
||||
@Data
|
||||
public class RegisterDTO {
|
||||
@NotBlank(message = "用户名不能为空")
|
||||
@ApiModelProperty(value = "用户名")
|
||||
private String username;
|
||||
|
||||
@Email(message = "请输入有效的邮箱")
|
||||
@ApiModelProperty(value = "邮箱", required = true)
|
||||
private String email;
|
||||
|
||||
@ApiModelProperty(value = "电话号码")
|
||||
private String phoneNumber;
|
||||
|
||||
@NotBlank(message = "密码不能为空")
|
||||
@ApiModelProperty(value = "密码", required = true)
|
||||
private String password;
|
||||
|
||||
@ApiModelProperty(value = "验证码", required = true)
|
||||
private String code;
|
||||
|
||||
private String token;
|
||||
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
package com.yunan.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 用户实体类
|
||||
*/
|
||||
@Data
|
||||
public class Users implements Serializable {
|
||||
private long id;
|
||||
/** 用户名*/
|
||||
private String username;
|
||||
/** 密码*/
|
||||
private String password;
|
||||
/** 邮箱*/
|
||||
private String email;
|
||||
/** 手机号*/
|
||||
private String phoneNumber;
|
||||
/** 创建用户信息时间 */
|
||||
private Date createdTime;
|
||||
/** 修改用户信息时间 */
|
||||
private String updatedTime;
|
||||
/** 用户状态*/
|
||||
private int state;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Users{" +
|
||||
"username='" + username + '\'' +
|
||||
", password='" + password + '\'' +
|
||||
", email='" + email + '\'' +
|
||||
", createTime='" + createdTime + '\'' +
|
||||
", updateTime='" + updatedTime + '\'' +
|
||||
", state=" + state +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
package com.yunan.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.yunan.dto.Users;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface AuthMapper extends BaseMapper<Users> {
|
||||
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
package com.yunan.response;
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -1,48 +0,0 @@
|
||||
package com.yunan.response;
|
||||
|
||||
// ErrorResponse.java
|
||||
public class ErrorResponse {
|
||||
private String message; // 错误消息
|
||||
private int code; // 错误代码 (可选)
|
||||
private long timestamp; // 错误发生的时间戳 (可选)
|
||||
|
||||
// 构造方法
|
||||
public ErrorResponse(String message) {
|
||||
this.message = message;
|
||||
this.timestamp = System.currentTimeMillis(); // 当前时间戳
|
||||
this.code = 400; // 默认为 400 错误代码
|
||||
}
|
||||
|
||||
// 构造方法(带自定义错误码)
|
||||
public ErrorResponse(String message, int code) {
|
||||
this.message = message;
|
||||
this.code = code;
|
||||
this.timestamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
// Getter 和 Setter
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public void setTimestamp(long timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
}
|
||||
|
@ -1,68 +0,0 @@
|
||||
package com.yunan.response;
|
||||
|
||||
public class Result {
|
||||
private int code; // 状态码,200代表成功,其他代表失败
|
||||
private String message; // 响应信息
|
||||
private Object data; // 响应数据
|
||||
|
||||
// 默认构造函数
|
||||
public Result() {
|
||||
}
|
||||
|
||||
// 构造函数
|
||||
public Result(int code, String message, Object data) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
// 成功返回
|
||||
public static Result ok(Object data) {
|
||||
return new Result(200, "成功", data); // 200代表成功
|
||||
}
|
||||
|
||||
// 错误返回
|
||||
public static Result error(String message) {
|
||||
return new Result(500, message, null); // 500代表服务器错误,message为错误信息
|
||||
}
|
||||
|
||||
// 错误返回,带code和message
|
||||
public static Result error(int code, String message) {
|
||||
return new Result(code, message, null); // 根据传入的code返回不同的错误
|
||||
}
|
||||
|
||||
// get 和 set 方法
|
||||
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 Object getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(Object data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
// 重写toString方法,方便调试输出
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Result{" +
|
||||
"code=" + code +
|
||||
", message='" + message + '\'' +
|
||||
", data=" + data +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
package com.yunan.service;
|
||||
|
||||
|
||||
import com.yunan.dto.LoginDTO;
|
||||
import com.yunan.dto.RegisterDTO;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.internet.AddressException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
public interface AuthService {
|
||||
|
||||
ResponseEntity<Object> register(RegisterDTO registerDTO) throws UnsupportedEncodingException, AddressException, MessagingException;
|
||||
|
||||
ResponseEntity<Object> login(LoginDTO loginDTO);
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
package com.yunan.service;
|
||||
|
||||
import com.github.xiaoymin.knife4j.core.util.StrUtil;
|
||||
import com.yunan.dto.Captcha;
|
||||
import com.yunan.util.CaptchaUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.data.redis.core.ValueOperations;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Service
|
||||
public class CaptchaService {
|
||||
/**
|
||||
* 拼图验证码允许偏差
|
||||
**/
|
||||
private static Integer ALLOW_DEVIATION = 3;
|
||||
|
||||
@Autowired
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
/**
|
||||
* 校验验证码
|
||||
* @param imageKey
|
||||
* @param imageCode
|
||||
* @return boolean
|
||||
**/
|
||||
public String checkImageCode(String imageKey, String imageCode) {
|
||||
ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
|
||||
String text = ops.get("imageCode:" + imageKey);
|
||||
if(StrUtil.isBlank(text)){
|
||||
return "验证码已失效";
|
||||
}
|
||||
// 根据移动距离判断验证是否成功
|
||||
if (Math.abs(Integer.parseInt(text) - Integer.parseInt(imageCode)) > ALLOW_DEVIATION) {
|
||||
return "验证失败,请控制拼图对齐缺口";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* 缓存验证码,有效期15分钟
|
||||
* @param key
|
||||
* @param code
|
||||
**/
|
||||
public void saveImageCode(String key, String code) {
|
||||
ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
|
||||
ops.set("imageCode:" + key, code, 15, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取验证码拼图(生成的抠图和带抠图阴影的大图及抠图坐标)
|
||||
**/
|
||||
public Object getCaptcha(Captcha captcha) {
|
||||
//参数校验
|
||||
CaptchaUtils.checkCaptcha(captcha);
|
||||
//获取画布的宽高
|
||||
int canvasWidth = captcha.getCanvasWidth();
|
||||
int canvasHeight = captcha.getCanvasHeight();
|
||||
//获取阻塞块的宽高/半径
|
||||
int blockWidth = captcha.getBlockWidth();
|
||||
int blockHeight = captcha.getBlockHeight();
|
||||
int blockRadius = captcha.getBlockRadius();
|
||||
//获取资源图
|
||||
BufferedImage canvasImage = CaptchaUtils.getBufferedImage(captcha.getPlace());
|
||||
//调整原图到指定大小
|
||||
canvasImage = CaptchaUtils.imageResize(canvasImage, canvasWidth, canvasHeight);
|
||||
//随机生成阻塞块坐标
|
||||
int blockX = CaptchaUtils.getNonceByRange(blockWidth, canvasWidth - blockWidth - 10);
|
||||
int blockY = CaptchaUtils.getNonceByRange(10, canvasHeight - blockHeight + 1);
|
||||
//阻塞块
|
||||
BufferedImage blockImage = new BufferedImage(blockWidth, blockHeight, BufferedImage.TYPE_4BYTE_ABGR);
|
||||
//新建的图像根据轮廓图颜色赋值,源图生成遮罩
|
||||
CaptchaUtils.cutByTemplate(canvasImage, blockImage, blockWidth, blockHeight, blockRadius, blockX, blockY);
|
||||
// 移动横坐标
|
||||
String nonceStr = UUID.randomUUID().toString().replaceAll("-", "");
|
||||
// 缓存
|
||||
saveImageCode(nonceStr,String.valueOf(blockX));
|
||||
//设置返回参数
|
||||
captcha.setNonceStr(nonceStr);
|
||||
captcha.setBlockY(blockY);
|
||||
captcha.setBlockSrc(CaptchaUtils.toBase64(blockImage, "png"));
|
||||
captcha.setCanvasSrc(CaptchaUtils.toBase64(canvasImage, "png"));
|
||||
return captcha;
|
||||
}
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
package com.yunan.service;
|
||||
|
||||
|
||||
import com.yunan.response.ApiResponse;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.mail.MessagingException;
|
||||
|
||||
@Service
|
||||
public interface EmailService {
|
||||
|
||||
ApiResponse<String> sendMail(String email) throws MessagingException;
|
||||
}
|
||||
|
||||
|
@ -1,43 +0,0 @@
|
||||
package com.yunan.service;
|
||||
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class RedisExpireTask {
|
||||
private final long time = 3600000; //一小时
|
||||
|
||||
private RedisTemplate<String, Object> redisTemplate;
|
||||
|
||||
public RedisExpireTask(RedisTemplate<String, Object> redisTemplate) {
|
||||
this.redisTemplate = redisTemplate;
|
||||
}
|
||||
|
||||
// 每隔一分钟执行一次
|
||||
@Scheduled(fixedRate = time)
|
||||
public void removeExpiredKeys() {
|
||||
long now = System.currentTimeMillis();
|
||||
// 获取过期的 hashKey
|
||||
Set<Object> expiredHashKeys = redisTemplate.opsForZSet().rangeByScore("rightCode:expire", 0, now);
|
||||
|
||||
if (expiredHashKeys != null && !expiredHashKeys.isEmpty()) {
|
||||
// 将 Set<Object> 转换为 Set<String>
|
||||
Set<String> expiredHashKeysSet = expiredHashKeys.stream()
|
||||
.map(Object::toString) // 将 Object 转换为 String
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
// 删除过期的数据
|
||||
redisTemplate.opsForZSet().remove("rightCode:expire", expiredHashKeysSet.toArray(new String[0]));
|
||||
|
||||
// 同时从哈希表中删除对应的 hashKey
|
||||
for (String hashKey : expiredHashKeysSet) {
|
||||
redisTemplate.opsForHash().delete("rightCode", hashKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,173 +0,0 @@
|
||||
package com.yunan.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.yunan.dto.LoginDTO;
|
||||
import com.yunan.dto.RegisterDTO;
|
||||
import com.yunan.dto.Users;
|
||||
import com.yunan.mapper.AuthMapper;
|
||||
import com.yunan.response.ErrorResponse;
|
||||
import com.yunan.service.AuthService;
|
||||
import com.yunan.util.RedisUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Date;
|
||||
import java.util.Random;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class AuthServiceImpl implements AuthService {
|
||||
@Resource
|
||||
private AuthMapper authMapper;
|
||||
@Autowired
|
||||
RedisUtils redisUtils;
|
||||
|
||||
// 手机号正则表达式
|
||||
private static final String PHONE_REGEX = "^1[3-9]\\d{9}$";
|
||||
// 邮箱正则表达式
|
||||
private static final String EMAIL_REGEX =
|
||||
"^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$";
|
||||
|
||||
public static boolean isValidPhone(String phone) {
|
||||
return phone != null && phone.matches(PHONE_REGEX);
|
||||
}
|
||||
|
||||
public static boolean isValidEmail(String input) {
|
||||
return input != null && input.matches(EMAIL_REGEX);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Object> register(RegisterDTO registerDTO) {
|
||||
//获取正确的验证码
|
||||
Object rightCode = redisUtils.hGet("rightCode", registerDTO.getEmail());
|
||||
//处理registerDTO对数据为空的逻辑
|
||||
// 验证验证码的正确性
|
||||
if(registerDTO.getCode().equals(rightCode)){
|
||||
LambdaQueryWrapper<Users> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(Users::getEmail, registerDTO.getEmail());
|
||||
if(authMapper.selectOne(queryWrapper) != null) {
|
||||
return ResponseEntity
|
||||
.status(HttpStatus.CONFLICT)
|
||||
.body(new ErrorResponse("用户已存在!!!"));
|
||||
}
|
||||
//为用户创建默认用户名
|
||||
String userName = createUserName();
|
||||
Users user = new Users();
|
||||
//设置账号创建时间
|
||||
Date currentDate = new Date();
|
||||
user.setCreatedTime(currentDate);
|
||||
user.setUsername(userName);
|
||||
user.setPassword(registerDTO.getPassword());
|
||||
user.setEmail(registerDTO.getEmail());
|
||||
//状态设置 " 1 " 正常账号
|
||||
user.setState(1);
|
||||
boolean isSaved = authMapper.insert(user) > 0;
|
||||
//测试
|
||||
// boolean isSaved = false;
|
||||
// boolean isSaved = true;
|
||||
|
||||
|
||||
if (isSaved) {
|
||||
return ResponseEntity
|
||||
.status(HttpStatus.OK)
|
||||
.body("注册成功!");
|
||||
} else {
|
||||
return ResponseEntity
|
||||
.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
.body("数据库存储失败,请稍后重试");
|
||||
}
|
||||
} else{
|
||||
// 如果验证码为空或者与正确的验证码不匹配,返回错误信息
|
||||
return ResponseEntity
|
||||
.status(HttpStatus.BAD_REQUEST) // 设置 HTTP 状态码为 400
|
||||
.body(new ErrorResponse("验证码不正确或已过期")); // 返回自定义的错误消息
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Object> login(LoginDTO loginDTO) {
|
||||
log.info("emai: {}", isValidEmail(loginDTO.getEmailOrPhoneNumber()));
|
||||
log.info("phone: {}", isValidPhone(loginDTO.getEmailOrPhoneNumber()));
|
||||
if(isValidPhone(loginDTO.getEmailOrPhoneNumber())) {
|
||||
loginDTO.setPhoneNumber(loginDTO.getEmailOrPhoneNumber());
|
||||
}else if(isValidEmail(loginDTO.getEmailOrPhoneNumber())) {
|
||||
loginDTO.setEmail(loginDTO.getEmailOrPhoneNumber());
|
||||
}else{
|
||||
ResponseEntity
|
||||
.status(HttpStatus.BAD_REQUEST)
|
||||
.body("账号校验失败");
|
||||
}
|
||||
if(loginDTO.getEmail() != null){
|
||||
LambdaQueryWrapper<Users> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(Users::getEmail, loginDTO.getEmail());
|
||||
Users users = authMapper.selectOne(queryWrapper);
|
||||
if(users == null){
|
||||
return ResponseEntity
|
||||
.status(HttpStatus.BAD_REQUEST)
|
||||
.body(new ErrorResponse("邮箱用户不存在!!!"));
|
||||
}
|
||||
String rightPassword = users.getPassword();
|
||||
if(rightPassword.equals(loginDTO.getPassword())){
|
||||
return ResponseEntity
|
||||
.status(HttpStatus.OK)
|
||||
.body("登入成功!!!");
|
||||
}else {
|
||||
return ResponseEntity
|
||||
.status(HttpStatus.BAD_REQUEST)
|
||||
.body("邮箱或密码错误!!!");
|
||||
}
|
||||
|
||||
}else if(loginDTO.getPhoneNumber() != null){
|
||||
LambdaQueryWrapper<Users> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(Users::getPhoneNumber, loginDTO.getPhoneNumber());
|
||||
Users users = authMapper.selectOne(queryWrapper);
|
||||
if(users == null){
|
||||
return ResponseEntity
|
||||
.status(HttpStatus.BAD_REQUEST)
|
||||
.body(new ErrorResponse("手机号用户不存在!!"));
|
||||
}
|
||||
String rightPassword = users.getPassword();
|
||||
if(rightPassword.equals(loginDTO.getPassword())){
|
||||
return ResponseEntity
|
||||
.status(HttpStatus.OK)
|
||||
.body("登入成功!!!");
|
||||
}else {
|
||||
return ResponseEntity
|
||||
.status(HttpStatus.BAD_REQUEST)
|
||||
.body("手机号或密码错误!!!");
|
||||
}
|
||||
|
||||
}else{
|
||||
return ResponseEntity
|
||||
.status(HttpStatus.BAD_REQUEST)
|
||||
.body(new ErrorResponse("其他错误待管理员处理!!!"));
|
||||
}
|
||||
}
|
||||
|
||||
//随机生成用户名算法
|
||||
public String createUserName() {
|
||||
// 字符集,包括小写字母和数字
|
||||
String chars = "abcdefghijklmnopqrstuvwxyz0123456789";
|
||||
StringBuilder randomPart = new StringBuilder();
|
||||
|
||||
// 随机生成6位字符
|
||||
Random random = new Random();
|
||||
for (int i = 0; i < 6; i++) {
|
||||
randomPart.append(chars.charAt(random.nextInt(chars.length())));
|
||||
}
|
||||
|
||||
// 获取当前时间戳(秒级)
|
||||
long timestamp = System.currentTimeMillis() / 1000;
|
||||
|
||||
// 拼接生成用户名,例如 "user_xxx123_1638326400"
|
||||
return "user_" + randomPart.toString() + "_" + timestamp;
|
||||
}
|
||||
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
package com.yunan.service.impl;
|
||||
|
||||
import com.yunan.constant.ResponseCode;
|
||||
import com.yunan.response.ApiResponse;
|
||||
import com.yunan.service.EmailService;
|
||||
import com.yunan.util.RedisUtils;
|
||||
import com.yunan.util.VerificationCodeUtils;
|
||||
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;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Service
|
||||
public class EmailServiceImpl implements EmailService {
|
||||
@Autowired
|
||||
private JavaMailSender mailSender;
|
||||
|
||||
@Value("${spring.mail.username}")
|
||||
private String from;
|
||||
@Autowired
|
||||
RedisUtils redisUtils;
|
||||
|
||||
|
||||
public ApiResponse<String> sendMail(String email) throws MessagingException {
|
||||
|
||||
// 生成验证码
|
||||
String code = VerificationCodeUtils.generateCode(6);
|
||||
|
||||
// 发送邮件
|
||||
String subject = "注册验证码";
|
||||
String content = "尊敬的用户,您的验证码为:" + code + ",有效期5分钟,请勿泄漏!";
|
||||
|
||||
// 创建邮件消息
|
||||
MimeMessage message = mailSender.createMimeMessage();
|
||||
MimeMessageHelper helper = new MimeMessageHelper(message, true);
|
||||
helper.setFrom(from);
|
||||
helper.setTo(email);
|
||||
helper.setSubject(subject);
|
||||
helper.setText(content, true);
|
||||
|
||||
// 发送邮件
|
||||
mailSender.send(message);
|
||||
|
||||
redisUtils.hPutWithExpire("rightCode", email, code, 5, TimeUnit.MINUTES);
|
||||
return new ApiResponse<>(ResponseCode.SUCCESS, "验证码已发送");
|
||||
}
|
||||
}
|
@ -1,229 +0,0 @@
|
||||
package com.yunan.util;
|
||||
|
||||
import com.yunan.dto.Captcha;
|
||||
import org.apache.commons.lang3.RandomUtils;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Base64;
|
||||
import java.util.Objects;
|
||||
import java.util.Random;
|
||||
|
||||
public class CaptchaUtils {
|
||||
|
||||
/**
|
||||
* 网络图片地址
|
||||
**/
|
||||
private final static String IMG_URL = "https://loyer.wang/view/ftp/wallpaper/%s.jpg";
|
||||
|
||||
/**
|
||||
* 本地图片地址
|
||||
**/
|
||||
private final static String IMG_PATH = "C:/Users/NanYu/Pictures/ComputerPaper/%s.jpg";
|
||||
|
||||
/**
|
||||
* 入参校验设置默认值
|
||||
**/
|
||||
public static void checkCaptcha(Captcha captcha) {
|
||||
//设置画布宽度默认值
|
||||
if (captcha.getCanvasWidth() == null) {
|
||||
captcha.setCanvasWidth(320);
|
||||
}
|
||||
//设置画布高度默认值
|
||||
if (captcha.getCanvasHeight() == null) {
|
||||
captcha.setCanvasHeight(155);
|
||||
}
|
||||
//设置阻塞块宽度默认值
|
||||
if (captcha.getBlockWidth() == null) {
|
||||
captcha.setBlockWidth(65);
|
||||
}
|
||||
//设置阻塞块高度默认值
|
||||
if (captcha.getBlockHeight() == null) {
|
||||
captcha.setBlockHeight(55);
|
||||
}
|
||||
//设置阻塞块凹凸半径默认值
|
||||
if (captcha.getBlockRadius() == null) {
|
||||
captcha.setBlockRadius(9);
|
||||
}
|
||||
//设置图片来源默认值
|
||||
if (captcha.getPlace() == null) {
|
||||
captcha.setPlace(0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定范围内的随机数
|
||||
**/
|
||||
public static int getNonceByRange(int start, int end) {
|
||||
Random random = new Random();
|
||||
return random.nextInt(end - start + 1) + start;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取验证码资源图
|
||||
**/
|
||||
public static BufferedImage getBufferedImage(Integer place) {
|
||||
try {
|
||||
//随机图片
|
||||
// int nonce = getNonceByRange(0, 1000);
|
||||
int nonce = 111;
|
||||
|
||||
//获取网络资源图片
|
||||
if (0 == place) {
|
||||
String imgUrl = String.format(IMG_URL, nonce);
|
||||
URL url = new URL(imgUrl);
|
||||
return ImageIO.read(url.openStream());
|
||||
}
|
||||
//获取本地图片
|
||||
else {
|
||||
String imgPath = String.format(IMG_PATH, nonce);
|
||||
File file = new File(imgPath);
|
||||
return ImageIO.read(file);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println("获取拼图资源失败");
|
||||
//异常处理
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 调整图片大小
|
||||
**/
|
||||
public static BufferedImage imageResize(BufferedImage bufferedImage, int width, int height) {
|
||||
Image image = bufferedImage.getScaledInstance(width, height, Image.SCALE_SMOOTH);
|
||||
BufferedImage resultImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D graphics2D = resultImage.createGraphics();
|
||||
graphics2D.drawImage(image, 0, 0, null);
|
||||
graphics2D.dispose();
|
||||
return resultImage;
|
||||
}
|
||||
|
||||
/**
|
||||
* 抠图,并生成阻塞块
|
||||
**/
|
||||
public static void cutByTemplate(BufferedImage canvasImage, BufferedImage blockImage, int blockWidth, int blockHeight, int blockRadius, int blockX, int blockY) {
|
||||
BufferedImage waterImage = new BufferedImage(blockWidth, blockHeight, BufferedImage.TYPE_4BYTE_ABGR);
|
||||
//阻塞块的轮廓图
|
||||
int[][] blockData = getBlockData(blockWidth, blockHeight, blockRadius);
|
||||
//创建阻塞块具体形状
|
||||
for (int i = 0; i < blockWidth; i++) {
|
||||
for (int j = 0; j < blockHeight; j++) {
|
||||
try {
|
||||
//原图中对应位置变色处理
|
||||
if (blockData[i][j] == 1) {
|
||||
//背景设置为黑色
|
||||
waterImage.setRGB(i, j, Color.BLACK.getRGB());
|
||||
blockImage.setRGB(i, j, canvasImage.getRGB(blockX + i, blockY + j));
|
||||
//轮廓设置为白色,取带像素和无像素的界点,判断该点是不是临界轮廓点
|
||||
if (blockData[i + 1][j] == 0 || blockData[i][j + 1] == 0 || blockData[i - 1][j] == 0 || blockData[i][j - 1] == 0) {
|
||||
blockImage.setRGB(i, j, Color.WHITE.getRGB());
|
||||
waterImage.setRGB(i, j, Color.WHITE.getRGB());
|
||||
}
|
||||
}
|
||||
//这里把背景设为透明
|
||||
else {
|
||||
blockImage.setRGB(i, j, Color.TRANSLUCENT);
|
||||
waterImage.setRGB(i, j, Color.TRANSLUCENT);
|
||||
}
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
//防止数组下标越界异常
|
||||
}
|
||||
}
|
||||
}
|
||||
//在画布上添加阻塞块水印
|
||||
addBlockWatermark(canvasImage, waterImage, blockX, blockY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建拼图轮廓轨迹
|
||||
**/
|
||||
private static int[][] getBlockData(int blockWidth, int blockHeight, int blockRadius) {
|
||||
int[][] data = new int[blockWidth][blockHeight];
|
||||
double po = Math.pow(blockRadius, 2);
|
||||
//随机生成两个圆的坐标,在4个方向上 随机找到2个方向添加凸/凹
|
||||
//凸/凹1
|
||||
int face1 = RandomUtils.nextInt(0,4);
|
||||
//凸/凹2
|
||||
int face2;
|
||||
//保证两个凸/凹不在同一位置
|
||||
do {
|
||||
face2 = RandomUtils.nextInt(0,4);
|
||||
} while (face1 == face2);
|
||||
//获取凸/凹起位置坐标
|
||||
int[] circle1 = getCircleCoords(face1, blockWidth, blockHeight, blockRadius);
|
||||
int[] circle2 = getCircleCoords(face2, blockWidth, blockHeight, blockRadius);
|
||||
//随机凸/凹类型
|
||||
int shape = getNonceByRange(0, 1);
|
||||
//圆的标准方程 (x-a)²+(y-b)²=r²,标识圆心(a,b),半径为r的圆
|
||||
//计算需要的小图轮廓,用二维数组来表示,二维数组有两张值,0和1,其中0表示没有颜色,1有颜色
|
||||
for (int i = 0; i < blockWidth; i++) {
|
||||
for (int j = 0; j < blockHeight; j++) {
|
||||
data[i][j] = 0;
|
||||
//创建中间的方形区域
|
||||
if ((i >= blockRadius && i <= blockWidth - blockRadius && j >= blockRadius && j <= blockHeight - blockRadius)) {
|
||||
data[i][j] = 1;
|
||||
}
|
||||
double d1 = Math.pow(i - Objects.requireNonNull(circle1)[0], 2) + Math.pow(j - circle1[1], 2);
|
||||
double d2 = Math.pow(i - Objects.requireNonNull(circle2)[0], 2) + Math.pow(j - circle2[1], 2);
|
||||
//创建两个凸/凹
|
||||
if (d1 <= po || d2 <= po) {
|
||||
data[i][j] = shape;
|
||||
}
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
/**
|
||||
* 根据朝向获取圆心坐标
|
||||
*/
|
||||
private static int[] getCircleCoords(int face, int blockWidth, int blockHeight, int blockRadius) {
|
||||
//上
|
||||
if (0 == face) {
|
||||
return new int[]{blockWidth / 2 - 1, blockRadius};
|
||||
}
|
||||
//左
|
||||
else if (1 == face) {
|
||||
return new int[]{blockRadius, blockHeight / 2 - 1};
|
||||
}
|
||||
//下
|
||||
else if (2 == face) {
|
||||
return new int[]{blockWidth / 2 - 1, blockHeight - blockRadius - 1};
|
||||
}
|
||||
//右
|
||||
else if (3 == face) {
|
||||
return new int[]{blockWidth - blockRadius - 1, blockHeight / 2 - 1};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* 在画布上添加阻塞块水印
|
||||
*/
|
||||
private static void addBlockWatermark(BufferedImage canvasImage, BufferedImage blockImage, int x, int y) {
|
||||
Graphics2D graphics2D = canvasImage.createGraphics();
|
||||
graphics2D.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 0.8f));
|
||||
graphics2D.drawImage(blockImage, x, y, null);
|
||||
graphics2D.dispose();
|
||||
}
|
||||
/**
|
||||
* BufferedImage转BASE64
|
||||
*/
|
||||
public static String toBase64(BufferedImage bufferedImage, String type) {
|
||||
try {
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
ImageIO.write(bufferedImage, type, byteArrayOutputStream);
|
||||
String base64 = Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray());
|
||||
return String.format("data:image/%s;base64,%s", type, base64);
|
||||
} catch (IOException e) {
|
||||
System.out.println("图片资源转换BASE64失败");
|
||||
//异常处理
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,22 +0,0 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -1,61 +0,0 @@
|
||||
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***************************
|
||||
spring:
|
||||
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***************************
|
||||
spring:
|
||||
redis:
|
||||
host: localhost # Redis 服务器地址
|
||||
port: 6379 # Redis 服务器端口
|
||||
password: # 如果 Redis 设置了密码
|
||||
database: 0 # 使用的数据库索引,默认是 0
|
||||
|
||||
|
||||
server:
|
||||
port: 8080
|
||||
|
||||
logging:
|
||||
level:
|
||||
org.springframework.boot.context.web: DEBUG
|
||||
|
||||
|
||||
|
@ -1,11 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.yunan.mapper.AuthMapper">
|
||||
|
||||
<insert id="insertUser" parameterType="com.yunan.dto.RegisterDTO">
|
||||
insert into users (username, password, email) values (#{username}, #{password}, #{email})
|
||||
</insert>
|
||||
<select id="findUserByEmail" resultType="com.yunan.dto.Users">
|
||||
select * from users where email = #{email}
|
||||
</select>
|
||||
</mapper>
|
6
pom.xml
6
pom.xml
@ -3,14 +3,14 @@
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>yunan-boot-parent</groupId>
|
||||
<artifactId>org.yunanframework.boot</artifactId>
|
||||
<groupId>ecs-boot-parent</groupId>
|
||||
<artifactId>org.ecsframework.boot</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<modules>
|
||||
<!-- 子模块列表 -->
|
||||
<module>YuNan-system-start</module>
|
||||
<module>ECS-system-start</module>
|
||||
</modules>
|
||||
|
||||
<parent>
|
||||
|
Loading…
Reference in New Issue
Block a user