Initial empty repository

Change-Id: Ie0685414be5495d9da50d659d9ec16ae51487e46
diff --git a/src/main/java/com/example/myproject/MyProjectApplication.java b/src/main/java/com/example/myproject/MyProjectApplication.java
new file mode 100644
index 0000000..49cd5f0
--- /dev/null
+++ b/src/main/java/com/example/myproject/MyProjectApplication.java
@@ -0,0 +1,14 @@
+
+package com.example.myproject;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+@MapperScan("com.example.myproject.mapper")  // 扫描 Mapper 接口
+public class MyProjectApplication {
+    public static void main(String[] args) {
+        SpringApplication.run(MyProjectApplication.class, args);
+    }
+}
diff --git a/src/main/java/com/example/myproject/config/GlobalCorsConfig.java b/src/main/java/com/example/myproject/config/GlobalCorsConfig.java
new file mode 100644
index 0000000..909ead8
--- /dev/null
+++ b/src/main/java/com/example/myproject/config/GlobalCorsConfig.java
@@ -0,0 +1,32 @@
+package com.example.myproject.config;
+
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.CorsRegistry;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@EnableWebMvc
+@Configuration
+public class GlobalCorsConfig  {
+    @Bean
+    public WebMvcConfigurer corsConfigurer() {
+        return new WebMvcConfigurer() {
+            @Override
+            public void addCorsMappings(CorsRegistry registry) {
+                registry.addMapping("/**")    //添加映射路径,“/**”表示对所有的路径实行全局跨域访问权限的设置
+                        .allowedOriginPatterns("*")    //开放哪些ip、端口、域名的访问权限 SpringBoot2.4.0以后allowedOrigins被allowedOriginPatterns代替
+                        .allowCredentials(true)  //是否允许发送Cookie信息
+                        .allowedMethods("GET", "POST", "PUT", "DELETE")     //开放哪些Http方法,允许跨域访问
+                        .allowedHeaders("*")     //允许HTTP请求中的携带哪些Header信息
+                        .exposedHeaders("*");   //暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息)
+            }
+        };
+    }
+
+
+
+
+}
diff --git a/src/main/java/com/example/myproject/config/SecurityConfig.java b/src/main/java/com/example/myproject/config/SecurityConfig.java
new file mode 100644
index 0000000..05cba5d
--- /dev/null
+++ b/src/main/java/com/example/myproject/config/SecurityConfig.java
@@ -0,0 +1,57 @@
+package com.example.myproject.config;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.builders.WebSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+
+@EnableWebSecurity    //注解开启Spring Security的功能
+public class SecurityConfig extends WebSecurityConfigurerAdapter {
+
+    @Bean
+    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
+        return authenticationConfiguration.getAuthenticationManager();
+    }
+    @Bean
+    public PasswordEncoder passwordEncoder() {
+        return new BCryptPasswordEncoder();//passwordEncoder的实现类
+    }
+
+    //构造一个内存框架对象,获取数据库中的数据
+/*    @Bean
+    public UserDetailsService myUserDetailsService(){
+        return new TestUserServerImpl();
+    }*/
+    //也可以自动注入
+
+    //用户授权
+
+
+    //用户权限认证
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+        http
+                .csrf().disable() // 禁用 CSRF 保护
+                .authorizeRequests()
+                .antMatchers("/swagger-ui.html", "/webjars/**", "/v2/**", "/swagger-resources/**","/**").permitAll() // 允许无条件访问
+                .anyRequest().authenticated(); // 其他所有路径都需要身份验证
+    }
+
+
+    /**
+     * 核心过滤器配置,更多使用ignoring()用来忽略对静态资源的控制
+     */
+    @Override
+    public void configure(WebSecurity web) throws Exception {
+        web
+                .ignoring()
+                .antMatchers("/image/**");
+    }
+}
diff --git a/src/main/java/com/example/myproject/controller/UserController.java b/src/main/java/com/example/myproject/controller/UserController.java
new file mode 100644
index 0000000..4bf6adf
--- /dev/null
+++ b/src/main/java/com/example/myproject/controller/UserController.java
@@ -0,0 +1,153 @@
+package com.example.myproject.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.example.myproject.mapper.UserMapper;
+import com.example.myproject.mapper.VerificationTokenMapper;
+import com.example.myproject.entity.User;
+import com.example.myproject.entity.VerificationToken;
+import com.example.myproject.service.EmailService;
+import com.example.myproject.service.UserService;
+import com.example.myproject.utils.Result;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+
+@RestController
+@RequestMapping("/user")
+@Api(value = "用户管理接口", tags = {"用户管理"})
+public class UserController {
+
+    @Resource
+    private UserService userService;
+
+    @Autowired
+    private AuthenticationManager authenticationManager;
+
+    @Autowired
+    private UserMapper userMapper; // 使用 MyBatis-Plus
+
+    @Autowired
+    private VerificationTokenMapper verificationTokenMapper; // 替换 JPA
+
+    private static final Logger logger = LoggerFactory.getLogger(UserController.class);
+
+    @PostMapping("/login")
+    @ApiOperation(value = "用户登录", notes = "使用用户名和密码进行登录")
+    public Result loginController(@RequestParam @ApiParam(value = "用户名", required = true) String username,
+                                  @RequestParam @ApiParam(value = "密码", required = true) String password) {
+        try {
+            Authentication authentication = authenticationManager.authenticate(
+                    new UsernamePasswordAuthenticationToken(username, password)
+            );
+            SecurityContextHolder.getContext().setAuthentication(authentication);
+
+            // 使用 MyBatis-Plus 查询
+            User user = userMapper.selectOne(new QueryWrapper<User>().eq("username", username));
+
+            System.out.println("Login successful for user: " + username);
+            return Result.success(user);
+        } catch (AuthenticationException e) {
+            return Result.error("401", "登录失败:" + e.getMessage());
+        }
+    }
+
+    @PostMapping("/register")
+    @ApiOperation(value = "用户注册", notes = "使用用户信息进行注册")
+    public Result registerController(@RequestBody @ApiParam(value = "新用户信息", required = true) User newUser) {
+        if (userService.checkEmailExists(newUser.getEmail())) {
+            return Result.error("邮箱冲突", "邮箱已被使用,请使用其他邮箱注册或找回密码!");
+        }
+        boolean success = userService.preRegisterUser(newUser);
+        if (success) {
+            User responseUser = new User();
+            responseUser.setEmail(newUser.getEmail());
+            return Result.success(responseUser, "验证邮件已发送,请检查您的邮箱。");
+        } else {
+            return Result.error("注册失败", "账号已存在或注册失败!");
+        }
+    }
+
+    public static class VerificationRequest {
+        private String email;
+        private String code;
+
+        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; }
+    }
+
+    @PostMapping("/verify-code")
+    @ApiOperation(value = "验证邮箱验证码", notes = "验证用户邮箱的验证码")
+    public Result verifyEmailCode(@RequestBody @ApiParam(value = "验证请求信息", required = true) VerificationRequest verificationRequest) {
+        String email = verificationRequest.getEmail();
+        String code = verificationRequest.getCode();
+        boolean isVerified = userService.verifyEmail(email, code);
+        if (isVerified) {
+            return Result.success(null, "邮箱验证成功!");
+        } else {
+            return Result.error("验证失败", "验证码错误或已过期!");
+        }
+    }
+
+    @Autowired
+    private EmailService emailService;
+
+    public static class EmailRequest {
+        private String email;
+        public String getEmail() { return email; }
+        public void setEmail(String email) { this.email = email; }
+    }
+
+    @PostMapping("/get-verification-email")
+    @ApiOperation(value = "发送验证邮件", notes = "通过电子邮件发送验证邮件")
+    public ResponseEntity<Result> sendVerificationEmail(@RequestBody @ApiParam(value = "发送验证请求", required = true) EmailRequest emailVerificationRequest) {
+        String email = emailVerificationRequest.getEmail();
+        User user = userMapper.selectOne(new QueryWrapper<User>().eq("email", email));
+        if (user == null) {
+            logger.error("未找到与该邮箱地址相关联的用户: {}", email);
+            return ResponseEntity.status(HttpStatus.BAD_REQUEST)
+                    .body(Result.error("1","未找到与该邮箱地址相关联的用户"));
+        }
+
+        // 生成验证码
+        String token = RandomStringUtils.randomNumeric(6);
+        Instant expiryDate = Instant.now().plus(1, ChronoUnit.HOURS);
+        logger.info("生成的验证令牌: {}, 过期时间: {}", token, expiryDate);
+
+        VerificationToken verificationToken = new VerificationToken(token, user.getUsername(), email, user.getPassword(), expiryDate);
+
+        // 保存到 MyBatis-Plus 数据库
+        verificationTokenMapper.insert(verificationToken);
+
+        logger.info("验证令牌已保存,用户: {}", user.getUsername());
+        emailService.sendVerificationEmail(email, token);
+
+        return ResponseEntity.ok(Result.success(200, "验证邮件已发送!"));
+    }
+    @PostMapping("/checkPassword")
+    public Result<String> checkPassword(@RequestParam Long userId, @RequestParam String password) {
+        boolean isPasswordCorrect = userService.checkPassword(userId, password);
+        if (isPasswordCorrect) {
+            return Result.success("200","原始密码输入正确");
+        } else {
+            return Result.error("305","原始密码输入错误");
+        }
+    }
+}
diff --git a/src/main/java/com/example/myproject/entity/User.java b/src/main/java/com/example/myproject/entity/User.java
new file mode 100644
index 0000000..20f7138
--- /dev/null
+++ b/src/main/java/com/example/myproject/entity/User.java
@@ -0,0 +1,55 @@
+package com.example.myproject.entity;
+
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+@TableName("user") // 指定数据库表名
+@ApiModel("用户实体类") // 用于描述模型
+public class User {
+
+    @TableId(type = IdType.AUTO) // 指定主键策略
+    @ApiModelProperty(value = "用户ID", example = "1")
+    private Long id;
+
+    @JsonProperty("username")
+    @ApiModelProperty(value = "用户名", example = "22301115")
+    private String username;
+
+    @JsonProperty("nickname")
+    @ApiModelProperty(value = "昵称", example = "cyl")
+    private String nickname;
+
+    @JsonProperty("role")
+    @ApiModelProperty(value = "角色", example = "Student")
+    private String role;
+
+    @JsonProperty("password")
+    @ApiModelProperty(value = "密码", example = "123")
+    private String password;
+
+    @JsonProperty("status")
+    @ApiModelProperty(value = "用户状态", example = "1")
+    private int status;
+
+    @JsonProperty("email")
+    @ApiModelProperty(value = "电子邮件地址", example = "john_doe@example.com")
+    private String email;
+
+    @JsonProperty("email_verified")
+    @ApiModelProperty(value = "邮箱验证状态", example = "true")
+    private boolean emailVerified;
+
+    @JsonProperty("avatar")
+    @ApiModelProperty(value = "头像")
+    private String avatar;
+
+    public User() {
+    }
+}
diff --git a/src/main/java/com/example/myproject/entity/UserDetails.java b/src/main/java/com/example/myproject/entity/UserDetails.java
new file mode 100644
index 0000000..9af35f0
--- /dev/null
+++ b/src/main/java/com/example/myproject/entity/UserDetails.java
@@ -0,0 +1,23 @@
+package com.example.myproject.entity;
+
+import org.springframework.security.core.GrantedAuthority;
+
+import java.io.Serializable;
+import java.util.Collection;
+
+public interface UserDetails extends Serializable {
+    Collection<? extends GrantedAuthority> getAuthorities();
+
+    String getPassword();
+
+    String getUsername();
+
+    boolean isAccountNonExpired();
+
+    boolean isAccountNonLocked();
+
+    boolean isCredentialsNonExpired();
+
+    boolean isEnabled();
+}
+
diff --git a/src/main/java/com/example/myproject/entity/VerificationToken.java b/src/main/java/com/example/myproject/entity/VerificationToken.java
new file mode 100644
index 0000000..231fd95
--- /dev/null
+++ b/src/main/java/com/example/myproject/entity/VerificationToken.java
@@ -0,0 +1,58 @@
+package com.example.myproject.entity;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.AllArgsConstructor;
+
+import java.time.Instant;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@TableName("verification_token")
+@ApiModel("验证令牌实体类")
+public class VerificationToken {
+
+    @TableId(type = IdType.AUTO)
+    @ApiModelProperty(value = "令牌ID")
+    private Long id;
+
+    @ApiModelProperty(value = "令牌字符串")
+    @TableField("token")
+    private String token;
+
+    @ApiModelProperty(value = "令牌过期日期")
+    @TableField("expiry_date")
+    private Instant expiryDate;
+
+    @ApiModelProperty(value = "用户名")
+    @TableField("username")
+    private String username;
+
+    @ApiModelProperty(value = "电子邮件地址")
+    @TableField("email")
+    private String email;
+
+    @ApiModelProperty(value = "加密后的密码")
+    @TableField("password")
+    private String password;
+
+    public VerificationToken(String token, String username, String email, String password, Instant expiryDate) {
+        this.token = token;
+        this.username = username;
+        this.email = email;
+        this.password = password;
+        this.expiryDate = expiryDate;
+    }
+
+    /**
+     * 检查令牌是否过期
+     * @return true 如果令牌已过期
+     */
+    public boolean isExpired() {
+        return expiryDate.isBefore(Instant.now());
+    }
+}
diff --git a/src/main/java/com/example/myproject/mapper/UserMapper.java b/src/main/java/com/example/myproject/mapper/UserMapper.java
new file mode 100644
index 0000000..a070bb5
--- /dev/null
+++ b/src/main/java/com/example/myproject/mapper/UserMapper.java
@@ -0,0 +1,25 @@
+package com.example.myproject.mapper;
+import com.example.myproject.entity.User;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Select;
+import org.springframework.data.repository.query.Param;
+
+import java.util.List;
+
+@Mapper
+public interface UserMapper extends BaseMapper<User> {
+
+
+    User selectByUsername(@Param("username") String username);
+
+    User selectByUsernameAndPassword(@Param("username") String username, @Param("password") String password);
+
+    User selectByEmail(@Param("email") String email);
+
+
+    // 根据用户名包含查找用户
+    List<User> selectByUsernameContaining(@Param("name") String name);
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/example/myproject/mapper/VerificationTokenMapper.java b/src/main/java/com/example/myproject/mapper/VerificationTokenMapper.java
new file mode 100644
index 0000000..94a25ca
--- /dev/null
+++ b/src/main/java/com/example/myproject/mapper/VerificationTokenMapper.java
@@ -0,0 +1,13 @@
+package com.example.myproject.mapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.example.myproject.entity.VerificationToken;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Select;
+
+
+@Mapper
+public interface VerificationTokenMapper extends BaseMapper<VerificationToken> {
+
+    VerificationToken findByTokenAndEmail(String token, String email);
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/example/myproject/service/EmailService.java b/src/main/java/com/example/myproject/service/EmailService.java
new file mode 100644
index 0000000..1ecc8c4
--- /dev/null
+++ b/src/main/java/com/example/myproject/service/EmailService.java
@@ -0,0 +1,20 @@
+
+package com.example.myproject.service;
+public interface EmailService {
+    /**
+     * 发送邮件给指定的邮箱。
+     *
+     * @param to 收件人邮箱地址
+     * @param subject 邮件主题
+     * @param text 邮件内容
+     * @return 发送是否成功
+     */
+    boolean sendEmail(String to, String subject, String text);
+    /**
+     * 生成并发送验证邮件
+     *
+     * @param email 收件人邮箱
+     * @param token
+     */
+    void sendVerificationEmail(String email, String token);
+}
diff --git a/src/main/java/com/example/myproject/service/UserDetailsService.java b/src/main/java/com/example/myproject/service/UserDetailsService.java
new file mode 100644
index 0000000..85d4da2
--- /dev/null
+++ b/src/main/java/com/example/myproject/service/UserDetailsService.java
@@ -0,0 +1,4 @@
+package com.example.myproject.service;
+
+public class UserDetailsService {
+}
diff --git a/src/main/java/com/example/myproject/service/UserService.java b/src/main/java/com/example/myproject/service/UserService.java
new file mode 100644
index 0000000..535f635
--- /dev/null
+++ b/src/main/java/com/example/myproject/service/UserService.java
@@ -0,0 +1,24 @@
+package com.example.myproject.service;
+
+
+
+import com.baomidou.mybatisplus.extension.service.IService;
+
+import com.example.myproject.entity.User;
+
+public interface UserService extends IService<User> {
+    User loginService(String username, String password);
+
+
+    boolean preRegisterUser(User user);
+
+
+    boolean verifyEmail(String email, String token);
+
+
+    boolean checkEmailExists(String email);
+
+    boolean checkPassword(Long userId, String rawPassword);
+
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/example/myproject/service/serviceImpl/EmailServiceImpl.java b/src/main/java/com/example/myproject/service/serviceImpl/EmailServiceImpl.java
new file mode 100644
index 0000000..83500ea
--- /dev/null
+++ b/src/main/java/com/example/myproject/service/serviceImpl/EmailServiceImpl.java
@@ -0,0 +1,51 @@
+
+package com.example.myproject.service.serviceImpl;
+import com.example.myproject.mapper.VerificationTokenMapper;
+import com.example.myproject.entity.VerificationToken;
+import com.example.myproject.service.EmailService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+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.time.Instant;
+@Service
+public class EmailServiceImpl implements EmailService {
+    private static final Logger log = LoggerFactory.getLogger(EmailServiceImpl.class);
+    @Autowired
+    private JavaMailSender mailSender;
+    @Autowired
+    private VerificationTokenMapper verificationTokenMapper;
+    @Value("${spring.mail.username}")  // 从配置文件中注入发件人邮箱地址
+    private String fromEmail;
+    @Override
+    public boolean sendEmail(String to, String subject, String text) {
+        log.debug("开始发送验证邮件到:{},主题:{}", to, subject);
+        try {
+            MimeMessage message = mailSender.createMimeMessage();
+            MimeMessageHelper helper = new MimeMessageHelper(message, true);
+            helper.setFrom(fromEmail);
+            helper.setTo(to);
+            helper.setSubject(subject);
+            helper.setText(text, true);
+            mailSender.send(message);
+            log.info("邮件成功发送到:{}", to);
+            return true;
+        } catch (MessagingException e) {
+            log.error("发送邮件失败,收件人:{},错误信息:{}", to, e.getMessage(), e);
+            return false;
+        }
+    }
+    @Override
+    public void sendVerificationEmail(String email, String token){
+        // 发送邮件
+        String message = "<h1>Email Verification</h1>" +
+                "<p>Your verification code is: <b>" + token + "</b></p>" +
+                "<p>This code will expire in 1 hour.</p>";
+        sendEmail(email, "Verify Your Email", message);
+    }
+}
diff --git a/src/main/java/com/example/myproject/service/serviceImpl/UserDetailsServiceImpl.java b/src/main/java/com/example/myproject/service/serviceImpl/UserDetailsServiceImpl.java
new file mode 100644
index 0000000..4bbd5c3
--- /dev/null
+++ b/src/main/java/com/example/myproject/service/serviceImpl/UserDetailsServiceImpl.java
@@ -0,0 +1,47 @@
+package com.example.myproject.service.serviceImpl;
+
+import com.example.myproject.mapper.UserMapper;
+import com.example.myproject.entity.User;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.AuthorityUtils;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Service
+public class UserDetailsServiceImpl implements UserDetailsService {
+
+    @Autowired
+    private UserMapper userMapper;
+
+    @Override
+    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
+        //username参数,是在登陆时,用户传递的表单数据username
+        //主要读取数据库3个值 username password authorities
+        User user= userMapper.selectByUsername(username);
+        if (user == null) {
+            throw new UsernameNotFoundException("用户名未找到");
+        }
+
+        String authorityName = user.getRole();
+        //为了返回一个UserDetails 使用User
+        List<GrantedAuthority> authorities = new ArrayList<>();
+        GrantedAuthority authority = new SimpleGrantedAuthority(authorityName);
+        authorities.add(authority);
+        return new org.springframework.security.core.userdetails.User(
+                user.getUsername(),
+                user.getPassword(),
+                true, // accountEnabled
+                true, // accountNonExpired
+                true, // credentialsNonExpired
+                true, // accountNonLocked
+                AuthorityUtils.createAuthorityList("ROLE_USER") // 设置用户的角色或权限
+        );
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/example/myproject/service/serviceImpl/UserServiceImpl.java b/src/main/java/com/example/myproject/service/serviceImpl/UserServiceImpl.java
new file mode 100644
index 0000000..d0718fe
--- /dev/null
+++ b/src/main/java/com/example/myproject/service/serviceImpl/UserServiceImpl.java
@@ -0,0 +1,122 @@
+
+package com.example.myproject.service.serviceImpl;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.example.myproject.mapper.UserMapper;
+import com.example.myproject.mapper.VerificationTokenMapper;
+import com.example.myproject.entity.User;
+import com.example.myproject.entity.VerificationToken;
+import com.example.myproject.service.EmailService;
+import com.example.myproject.service.UserService;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Service;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+//登录注册
+@Service
+public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
+    private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
+    @Autowired
+    private UserMapper userMapper; // Using MyBatis-Plus mapper
+    @Autowired
+    private EmailServiceImpl emailService;
+    @Autowired
+    private VerificationTokenMapper verificationTokenMapper; // Using MyBatis-Plus mapper
+    @Autowired
+    private PasswordEncoder passwordEncoder; // Injecting password encoder
+    @Override
+    public User loginService(String username, String password) {
+        log.debug("Attempting login with username: {}, password: {}", username, password);
+        User user = userMapper.selectOne(new QueryWrapper<User>().eq("username", username).eq("password", password));
+        if (user != null) {
+            user.setPassword("");  // Clear the password before returning
+            log.debug("Login successful, User ID: {}", user.getId());
+        } else {
+            log.debug("Login failed, incorrect username or password.");
+        }
+        return user;
+    }
+    @Override
+    public boolean preRegisterUser(User user) {
+        log.debug("Pre-registering user, username: {}, email: {}", user.getUsername(), user.getEmail());
+        // 检查用户名或邮箱是否已存在
+        boolean userExists = userMapper.selectOne(new QueryWrapper<User>().eq("username", user.getUsername())) != null ||
+                userMapper.selectOne(new QueryWrapper<User>().eq("email", user.getEmail())) != null;
+        if (userExists) {
+            log.debug("Pre-registration failed, username or email already exists.");
+            return false;  // 用户名或邮箱已经存在
+        }
+        // 加密密码
+        String encryptedPassword = passwordEncoder.encode(user.getPassword());
+        // 生成验证码
+        String token = RandomStringUtils.randomNumeric(6);
+        // 设置过期时间为当前时间加一小时
+        Instant expiryDate = Instant.now().plus(1, ChronoUnit.HOURS);
+        // 创建验证令牌对象
+        VerificationToken verificationToken = new VerificationToken(
+                token,
+                user.getUsername(),
+                user.getEmail(),
+                encryptedPassword,
+                expiryDate
+        );
+        // 插入验证令牌
+        int rowsInserted = verificationTokenMapper.insert(verificationToken);
+        if (rowsInserted > 0) {
+            // 发送验证邮件
+            emailService.sendVerificationEmail(user.getEmail(), token);
+            log.debug("Pre-registration successful, verification code: {}, expiry date: {}", token, expiryDate);
+            return true;  // 注册前验证成功
+        } else {
+            log.error("Failed to insert verification token into database.");
+            return false;  // 如果插入验证令牌失败,返回失败
+        }
+    }
+    @Override
+    public boolean verifyEmail(String email, String token) {
+        log.debug("Verifying email, email: {}, token: {}", email, token);
+        VerificationToken verificationToken = verificationTokenMapper.selectOne(
+                new QueryWrapper<VerificationToken>().eq("token", token).eq("email", email)
+        );
+        if (verificationToken != null && !verificationToken.isExpired()) {
+            log.debug("Verification code is valid, username: {}", verificationToken.getUsername());
+            User user = userMapper.selectOne(new QueryWrapper<User>().eq("email", email));
+            if (user == null) {
+                user = new User();
+                user.setEmail(email);
+                user.setUsername(verificationToken.getUsername());
+                user.setPassword(verificationToken.getPassword());
+                user.setEmailVerified(true);
+                userMapper.insert(user);  // Save new user
+                log.debug("New user created, User ID: {}", user.getId());
+            } else {
+                user.setEmailVerified(true);
+                userMapper.updateById(user);  // Update existing user
+                log.debug("User email verified, User ID: {}", user.getId());
+            }
+            verificationTokenMapper.delete(new QueryWrapper<VerificationToken>().eq("token", token)); // Clean up the token
+            log.debug("Verification code deleted.");
+            return true;
+        }
+        log.debug("Verification code is invalid or expired.");
+        return false;
+    }
+    public boolean checkEmailExists(String email) {
+        log.debug("检查邮箱是否存在,邮箱:{}", email);
+        boolean exists = userMapper.selectCount(new QueryWrapper<User>().eq("email", email)) > 0;
+        log.debug("邮箱存在状态:{}", exists);
+        return exists;
+    }
+    public boolean checkPassword(Long userId, String password) {
+        User user = userMapper.selectById(userId);
+        if (user == null) {
+            throw new RuntimeException("用户不存在");
+        }
+        String encryptedPassword = user.getPassword();
+        return passwordEncoder.matches(password, encryptedPassword);
+    }
+}
diff --git a/src/main/java/com/example/myproject/utils/Result.java b/src/main/java/com/example/myproject/utils/Result.java
new file mode 100644
index 0000000..e838a1c
--- /dev/null
+++ b/src/main/java/com/example/myproject/utils/Result.java
@@ -0,0 +1,129 @@
+package com.example.myproject.utils;
+
+
+public class Result<T> {
+    private String code;
+    private String msg;
+    private T data;
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public void setMsg(String msg) {
+        this.msg = msg;
+    }
+
+    public T getData() {
+        return data;
+    }
+
+    public void setData(T data) {
+        this.data = data;
+    }
+
+    public Result() {
+    }
+
+    public Result(T data) {
+        this.data = data;
+    }
+
+    public static Result success() {
+        Result result = new Result<>();
+        result.setCode("200");
+        result.setMsg("成功");
+        return result;
+    }
+
+    public static <T> Result<T> success(T data) {
+        Result<T> result = new Result<>(data);
+        result.setCode("200");
+        result.setMsg("成功");
+        return result;
+    }
+    public static <T> Result<T> success(String msg) {
+        Result result = new Result();
+        result.setCode("200");
+        result.setMsg("成功");
+        return result;
+    }
+
+    public static <T> Result<T> success(T data,String msg) {
+        Result<T> result = new Result<>(data);
+        result.setCode("200");
+        result.setMsg(msg);
+        return result;
+    }
+
+    public static Result error(String code, String msg) {
+        Result result = new Result();
+        result.setCode(code);
+        result.setMsg(msg);
+        return result;
+    }
+    /**
+     * 创建一个表示文件大小超出限制的结果对象。
+     *
+     * @return 构造的文件过大错误结果对象
+     */
+    public static Result fileTooLarge() {
+        Result result = new Result();
+        result.setCode("413");
+        result.setMsg("文件大小超出限制。");
+        return result;
+    }
+
+    /**
+     * 创建一个表示文件格式不支持的结果对象。
+     *
+     * @return 构造的文件格式错误结果对象
+     */
+    public static Result unsupportedFileType() {
+        Result result = new Result();
+        result.setCode("415");
+        result.setMsg("不支持的文件格式。");
+        return result;
+    }
+
+    /**
+     * 创建一个表示文件未找到的结果对象。
+     *
+     * @return 构造的文件未找到错误结果对象
+     */
+    public static Result fileNotFound() {
+        Result result = new Result();
+        result.setCode("404");
+        result.setMsg("文件未找到。");
+        return result;
+    }
+
+    /**
+     * 创建一个表示文件存储错误的结果对象。
+     *
+     * @param errorMsg 详细错误信息
+     * @return 构造的文件存储错误结果对象
+     */
+    public static Result fileStorageError(String errorMsg) {
+        Result result = new Result();
+        result.setCode("500");
+        result.setMsg("文件存储错误: " + errorMsg);
+        return result;
+    }
+
+    public static Result permissionDenied() {
+        Result result = new Result();
+        result.setCode("401");
+        result.setMsg("权限不足,无法执行该操作。");
+        return result;
+    }
+
+}
diff --git a/src/main/java/com/example/myproject/utils/VerifyCode.java b/src/main/java/com/example/myproject/utils/VerifyCode.java
new file mode 100644
index 0000000..689b8ce
--- /dev/null
+++ b/src/main/java/com/example/myproject/utils/VerifyCode.java
@@ -0,0 +1,156 @@
+package com.example.myproject.utils;
+
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Random;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Random;
+
+/*
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Random;
+
+/**
+ * @author 阿楠
+ * code生成工具类
+ */
+public class VerifyCode {
+    /**
+     * 生成验证码图片的宽度
+     */
+    private int width = 100;
+
+    /**
+     * 生成验证码图片的高度
+     */
+    private int height = 30;
+
+    /**
+     * 字符样式
+     */
+    private String[] fontNames = { "宋体", "楷体", "隶书", "微软雅黑" };
+
+    /**
+     * 定义验证码图片的背景颜色为白色
+     */
+    private Color bgColor = new Color(255, 255, 255);
+
+    /**
+     * 生成随机
+     */
+    private Random random = new Random();
+
+    /**
+     * 定义code字符
+     */
+    private String codes = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+    /**
+     * 记录随机字符串
+     */
+    private String text;
+
+    /**
+     * 获取一个随意颜色
+     * @return
+     */
+    private Color randomColor() {
+        int red = random.nextInt(150);
+        int green = random.nextInt(150);
+        int blue = random.nextInt(150);
+        return new Color(red, green, blue);
+    }
+
+    /**
+     * 获取一个随机字体
+     *
+     * @return
+     */
+    private Font randomFont() {
+        String name = fontNames[random.nextInt(fontNames.length)];
+        int style = random.nextInt(4);
+        int size = random.nextInt(5) + 24;
+        return new Font(name, style, size);
+    }
+
+    /**
+     * 获取一个随机字符
+     *
+     * @return
+     */
+    private char randomChar() {
+        return codes.charAt(random.nextInt(codes.length()));
+    }
+
+    /**
+     * 创建一个空白的BufferedImage对象
+     *
+     * @return
+     */
+    private BufferedImage createImage() {
+        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
+        Graphics2D g2 = (Graphics2D) image.getGraphics();
+        //设置验证码图片的背景颜色
+        g2.setColor(bgColor);
+        g2.fillRect(0, 0, width, height);
+        return image;
+    }
+
+    public BufferedImage getImage() {
+        BufferedImage image = createImage();
+        Graphics2D g2 = (Graphics2D) image.getGraphics();
+        StringBuffer sb = new StringBuffer();
+        for (int i = 0; i < 4; i++) {
+            String s = randomChar() + "";
+            sb.append(s);
+            g2.setColor(randomColor());
+            g2.setFont(randomFont());
+            float x = i * width * 1.0f / 4;
+            g2.drawString(s, x, height - 8);
+        }
+        this.text = sb.toString();
+        drawLine(image);
+        return image;
+    }
+
+    /**
+     * 绘制干扰线
+     *
+     * @param image
+     */
+    private void drawLine(BufferedImage image) {
+        Graphics2D g2 = (Graphics2D) image.getGraphics();
+        int num = 5;
+        for (int i = 0; i < num; i++) {
+            int x1 = random.nextInt(width);
+            int y1 = random.nextInt(height);
+            int x2 = random.nextInt(width);
+            int y2 = random.nextInt(height);
+            g2.setColor(randomColor());
+            g2.setStroke(new BasicStroke(1.5f));
+            g2.drawLine(x1, y1, x2, y2);
+        }
+    }
+
+    public String getText() {
+        return text;
+    }
+
+    public static void output(BufferedImage image, OutputStream out) throws IOException {
+        ImageIO.write(image, "JPEG", out);
+    }
+}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
new file mode 100644
index 0000000..b753da7
--- /dev/null
+++ b/src/main/resources/application.properties
@@ -0,0 +1,21 @@
+server.port=8080
+spring.datasource.url=jdbc:mysql://localhost:3306/pt
+spring.datasource.username=root
+spring.datasource.password=root
+spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
+
+mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
+
+
+# Mail configuration
+spring.mail.password=tljnebonhzhqecda
+spring.mail.username=2370523716@qq.com
+spring.mail.host=smtp.qq.com
+spring.mail.properties.mail.smtp.ssl.enable=true
+spring.mail.properties.mail.smtp.auth=true
+spring.mail.properties.mail.smtp.starttls.enable=true
+
+
+spring.jpa.enabled=false
+spring.jpa.hibernate.ddl-auto=none
+spring.jpa.open-in-view=false
diff --git a/src/main/resources/mapper/UserMapper.xml b/src/main/resources/mapper/UserMapper.xml
new file mode 100644
index 0000000..f03ab0a
--- /dev/null
+++ b/src/main/resources/mapper/UserMapper.xml
@@ -0,0 +1,21 @@
+<?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.example.myproject.mapper.UserMapper">
+    <!-- 根据用户名查找用户 -->
+    <select id="selectByUsername" parameterType="string" resultType="com.example.myproject.entity.User">
+        SELECT * FROM user WHERE username = #{username}
+    </select>
+    <!-- 根据用户名和密码查找用户 -->
+    <select id="selectByUsernameAndPassword" parameterType="map" resultType="com.example.myproject.entity.User">
+        SELECT * FROM user WHERE username = #{username} AND password = #{password}
+    </select>
+    <!-- 根据邮箱查找用户 -->
+    <select id="selectByEmail" parameterType="string" resultType="com.example.myproject.entity.User">
+        SELECT * FROM user WHERE email = #{email}
+    </select>
+    <!-- 根据用户名包含查找用户 -->
+    <select id="selectByUsernameContaining" parameterType="string" resultType="com.example.myproject.entity.User">
+        SELECT * FROM user WHERE username LIKE CONCAT('%', #{name}, '%')
+    </select>
+</mapper>
diff --git a/src/main/resources/mapper/VerificationTokenMapper.xml b/src/main/resources/mapper/VerificationTokenMapper.xml
new file mode 100644
index 0000000..53b19a5
--- /dev/null
+++ b/src/main/resources/mapper/VerificationTokenMapper.xml
@@ -0,0 +1,10 @@
+<?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.example.myproject.mapper.VerificationTokenMapper">
+    <!-- 通过 token 和 email 查询 VerificationToken -->
+    <select id="findByTokenAndEmail" resultType="com.example.myproject.entity.VerificationToken">
+        SELECT * FROM verification_token
+        WHERE token = #{token} AND email = #{email}
+    </select>
+</mapper>
diff --git a/src/test/java/com/example/myproject/controller/UserControllerTest.java b/src/test/java/com/example/myproject/controller/UserControllerTest.java
new file mode 100644
index 0000000..8a09e53
--- /dev/null
+++ b/src/test/java/com/example/myproject/controller/UserControllerTest.java
@@ -0,0 +1,163 @@
+package com.example.myproject.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.example.myproject.entity.User;
+import com.example.myproject.service.EmailService;
+import com.example.myproject.service.UserService;
+import com.example.myproject.mapper.UserMapper;
+import com.example.myproject.mapper.VerificationTokenMapper;
+import com.example.myproject.utils.Result;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.*;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+class UserControllerTest {
+
+    @InjectMocks
+    private UserController userController;
+
+    @Mock
+    private UserService userService;
+    @Mock
+    private UserMapper userMapper;
+    @Mock
+    private EmailService emailService;
+    @Mock
+    private AuthenticationManager authenticationManager;
+    @Mock
+    private VerificationTokenMapper verificationTokenMapper;
+
+    @BeforeEach
+    void setup() {
+        MockitoAnnotations.openMocks(this);
+    }
+
+    @Test
+    void loginController_success() {
+        String username = "testuser";
+        String password = "testpass";
+        User mockUser = new User();
+        mockUser.setUsername(username);
+
+        Authentication mockAuth = mock(Authentication.class);
+        when(authenticationManager.authenticate(any())).thenReturn(mockAuth);
+        when(userMapper.selectOne(any(QueryWrapper.class))).thenReturn(mockUser);
+
+        Result result = userController.loginController(username, password);
+
+        assertEquals("200", result.getCode());
+        assertEquals(mockUser, result.getData());
+    }
+
+
+    @Test
+    void loginController_failure() {
+        String username = "user";
+        String password = "wrongpass";
+
+        // 模拟认证失败,抛出 Bad credentials 异常
+        when(authenticationManager.authenticate(any()))
+                .thenThrow(new AuthenticationException("Bad credentials") {});
+
+
+        // 调用登录接口
+        Result result = userController.loginController(username, password);
+
+        // 断言返回的状态码和消息
+        assertEquals("401", result.getCode());
+        assertTrue(result.getMsg().contains("登录失败"));
+    }
+
+    @Test
+    void registerController_emailExists() {
+        User user = new User();
+        user.setEmail("test@example.com");
+
+        when(userService.checkEmailExists(user.getEmail())).thenReturn(true);
+
+        Result result = userController.registerController(user);
+
+        assertEquals("邮箱冲突", result.getCode());
+    }
+
+    @Test
+    void registerController_success() {
+        User user = new User();
+        user.setEmail("test@example.com");
+
+        when(userService.checkEmailExists(user.getEmail())).thenReturn(false);
+        when(userService.preRegisterUser(user)).thenReturn(true);
+
+        Result result = userController.registerController(user);
+
+        assertEquals("200", result.getCode());
+        assertEquals(user.getEmail(), ((User) result.getData()).getEmail());
+    }
+
+    @Test
+    void verifyEmailCode_success() {
+        when(userService.verifyEmail("test@example.com", "123456")).thenReturn(true);
+
+        UserController.VerificationRequest request = new UserController.VerificationRequest();
+        request.setEmail("test@example.com");
+        request.setCode("123456");
+
+        Result result = userController.verifyEmailCode(request);
+
+        assertEquals("200", result.getCode());
+    }
+
+    @Test
+    void verifyEmailCode_failure() {
+        when(userService.verifyEmail("test@example.com", "000000")).thenReturn(false);
+
+        UserController.VerificationRequest request = new UserController.VerificationRequest();
+        request.setEmail("test@example.com");
+        request.setCode("000000");
+
+        Result result = userController.verifyEmailCode(request);
+
+        assertEquals("验证失败", result.getCode());
+    }
+
+    @Test
+    void checkPassword_success() {
+        when(userService.checkPassword(1L, "abc123")).thenReturn(true);
+
+        Result<String> result = userController.checkPassword(1L, "abc123");
+
+        assertEquals("200", result.getCode());
+        assertEquals("原始密码输入正确", result.getMsg());
+    }
+
+    @Test
+    void checkPassword_failure() {
+        when(userService.checkPassword(1L, "wrong")).thenReturn(false);
+
+        Result<String> result = userController.checkPassword(1L, "wrong");
+
+        assertEquals("305", result.getCode());
+        assertEquals("原始密码输入错误", result.getMsg());
+    }
+
+    @Test
+    void sendVerificationEmail_userNotFound() {
+        UserController.EmailRequest request = new UserController.EmailRequest();
+        request.setEmail("notfound@example.com");
+
+        when(userMapper.selectOne(any())).thenReturn(null);
+
+        ResponseEntity<Result> response = userController.sendVerificationEmail(request);
+
+        assertEquals(400, response.getStatusCodeValue());
+        assertEquals("1", response.getBody().getCode());
+    }
+}