From 138f541e7ac85daae900992c68df367da80ff280 Mon Sep 17 00:00:00 2001 From: Guwan Date: Sat, 7 Dec 2024 16:21:40 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B3=A8=E5=86=8C=E5=AE=9E=E7=8E=B0=E5=AE=8C?= =?UTF-8?q?=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 13 +++++ .../backend/Handler/MyMetaObjectHandler.java | 7 ++- .../java/com/guwan/backend/JwtExample.java | 24 ++++++++ .../backend/config/JacksonConfiguration.java | 44 +++++++++++++++ .../backend/config/MvcConfiguration.java | 27 +++++++++ .../backend/config/MybatisPlusConfig.java | 9 +++ .../com/guwan/backend/constant/Constants.java | 12 ++++ .../backend/controller/UserController.java | 23 +++++--- .../com/guwan/backend/dto/user/LoginDto.java | 30 ++++++++++ .../com/guwan/backend/dto/user/UserDTO.java | 12 +++- .../java/com/guwan/backend/entity/User.java | 5 +- .../guwan/backend/service/UserService.java | 9 ++- .../backend/service/impl/UserServiceImpl.java | 56 ++++++++++++++++--- .../java/com/guwan/backend/util/JwtUtil.java | 1 + src/main/resources/application.yml | 2 +- 15 files changed, 249 insertions(+), 25 deletions(-) create mode 100644 src/main/java/com/guwan/backend/JwtExample.java create mode 100644 src/main/java/com/guwan/backend/config/JacksonConfiguration.java create mode 100644 src/main/java/com/guwan/backend/config/MvcConfiguration.java create mode 100644 src/main/java/com/guwan/backend/constant/Constants.java diff --git a/pom.xml b/pom.xml index 6e51a6e..5f88f41 100644 --- a/pom.xml +++ b/pom.xml @@ -133,6 +133,19 @@ dysmsapi20170525 3.0.0 + + + org.springframework.boot + spring-boot-starter-json + + + + + com.alibaba + fastjson + 2.0.53 + + diff --git a/src/main/java/com/guwan/backend/Handler/MyMetaObjectHandler.java b/src/main/java/com/guwan/backend/Handler/MyMetaObjectHandler.java index 92b428f..16c5957 100644 --- a/src/main/java/com/guwan/backend/Handler/MyMetaObjectHandler.java +++ b/src/main/java/com/guwan/backend/Handler/MyMetaObjectHandler.java @@ -4,16 +4,17 @@ import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; import org.apache.ibatis.reflection.MetaObject; import org.springframework.stereotype.Component; import java.time.LocalDateTime; +import java.util.Date; + -@Component public class MyMetaObjectHandler implements MetaObjectHandler { @Override public void insertFill(MetaObject metaObject) { - this.strictInsertFill(metaObject, "createdTime", LocalDateTime.class, LocalDateTime.now()); + this.strictInsertFill(metaObject, "createdTime", Date.class, new Date()); } @Override public void updateFill(MetaObject metaObject) { - this.strictUpdateFill(metaObject, "lastLoginTime", LocalDateTime.class, LocalDateTime.now()); + this.strictUpdateFill(metaObject, "lastLoginTime", Date.class, new Date()); } } \ No newline at end of file diff --git a/src/main/java/com/guwan/backend/JwtExample.java b/src/main/java/com/guwan/backend/JwtExample.java new file mode 100644 index 0000000..64b05a6 --- /dev/null +++ b/src/main/java/com/guwan/backend/JwtExample.java @@ -0,0 +1,24 @@ +package com.guwan.backend; + +import io.jsonwebtoken.security.Keys; +import io.jsonwebtoken.SignatureAlgorithm; + +import javax.crypto.SecretKey; + +public class JwtExample { + public static void main(String[] args) { + // 选择您的 HMAC-SHA 算法 + SignatureAlgorithm algorithm = SignatureAlgorithm.HS256; + + // 使用推荐的密钥生成方法生成密钥 + SecretKey key = Keys.secretKeyFor(algorithm); + + System.out.println("key = " + key); + + SecretKey key2 = Keys.secretKeyFor(SignatureAlgorithm.HS512); + System.out.println("key2 = " + key2); + + // 现在 key 是一个足够安全的密钥,可以用于 JWT 签名 + // 您可以使用这个密钥来创建和验证 JWT + } +} \ No newline at end of file diff --git a/src/main/java/com/guwan/backend/config/JacksonConfiguration.java b/src/main/java/com/guwan/backend/config/JacksonConfiguration.java new file mode 100644 index 0000000..fc3fb66 --- /dev/null +++ b/src/main/java/com/guwan/backend/config/JacksonConfiguration.java @@ -0,0 +1,44 @@ +package com.guwan.backend.config; + + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer; +import com.fasterxml.jackson.module.paramnames.ParameterNamesModule; +import com.guwan.backend.constant.Constants; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; + +@Configuration +public class JacksonConfiguration { + + @Bean + public ObjectMapper objectMapper(){ + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + objectMapper.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE); + JavaTimeModule javaTimeModule = new JavaTimeModule(); + + javaTimeModule.addSerializer(LocalDateTime.class,new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(Constants.DateTime.DEFAULT_DATE_TIME_FORMAT))); + javaTimeModule.addSerializer(LocalDate.class,new LocalDateSerializer(DateTimeFormatter.ofPattern(Constants.DateTime.DEFAULT_DATE_FORMAT))); + javaTimeModule.addSerializer(LocalTime.class,new LocalTimeSerializer(DateTimeFormatter.ofPattern(Constants.DateTime.DEFAULT_TIME_FORMAT))); + + javaTimeModule.addDeserializer(LocalDateTime.class,new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(Constants.DateTime.DEFAULT_DATE_TIME_FORMAT))); + javaTimeModule.addDeserializer(LocalDate.class,new LocalDateDeserializer(DateTimeFormatter.ofPattern(Constants.DateTime.DEFAULT_DATE_FORMAT))); + javaTimeModule.addDeserializer(LocalTime.class,new LocalTimeDeserializer(DateTimeFormatter.ofPattern(Constants.DateTime.DEFAULT_TIME_FORMAT))); + objectMapper.registerModule(javaTimeModule).registerModule(new ParameterNamesModule()); + return objectMapper; + } +} diff --git a/src/main/java/com/guwan/backend/config/MvcConfiguration.java b/src/main/java/com/guwan/backend/config/MvcConfiguration.java new file mode 100644 index 0000000..782bc05 --- /dev/null +++ b/src/main/java/com/guwan/backend/config/MvcConfiguration.java @@ -0,0 +1,27 @@ +package com.guwan.backend.config; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import java.util.List; + +@Configuration +public class MvcConfiguration implements WebMvcConfigurer { + @Override + public void extendMessageConverters(List> converters) { + MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter(); + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); + objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + objectMapper.registerModule(new JavaTimeModule()); + messageConverter.setObjectMapper(objectMapper); + converters.add(0, messageConverter); + } +} diff --git a/src/main/java/com/guwan/backend/config/MybatisPlusConfig.java b/src/main/java/com/guwan/backend/config/MybatisPlusConfig.java index 74270be..4eb163b 100644 --- a/src/main/java/com/guwan/backend/config/MybatisPlusConfig.java +++ b/src/main/java/com/guwan/backend/config/MybatisPlusConfig.java @@ -1,5 +1,8 @@ package com.guwan.backend.config; +import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; +import com.guwan.backend.Handler.MyMetaObjectHandler; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration @@ -11,4 +14,10 @@ public class MybatisPlusConfig { // interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // return interceptor; // } + + @Bean + public MetaObjectHandler myCustomMetaObjectHandler() { + return new MyMetaObjectHandler(); + } + } \ No newline at end of file diff --git a/src/main/java/com/guwan/backend/constant/Constants.java b/src/main/java/com/guwan/backend/constant/Constants.java new file mode 100644 index 0000000..e119659 --- /dev/null +++ b/src/main/java/com/guwan/backend/constant/Constants.java @@ -0,0 +1,12 @@ +package com.guwan.backend.constant; + +public class Constants { + public static class DateTime { + /** 默认日期时间格式 */ + public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; + /** 默认日期格式 */ + public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd"; + /** 默认时间格式 */ + public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss"; + } +} diff --git a/src/main/java/com/guwan/backend/controller/UserController.java b/src/main/java/com/guwan/backend/controller/UserController.java index ab74633..15f1fe6 100644 --- a/src/main/java/com/guwan/backend/controller/UserController.java +++ b/src/main/java/com/guwan/backend/controller/UserController.java @@ -3,10 +3,7 @@ package com.guwan.backend.controller; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.RandomUtil; import com.guwan.backend.common.Result; -import com.guwan.backend.dto.user.EmailDto; -import com.guwan.backend.dto.user.PhoneDto; -import com.guwan.backend.dto.user.RegisterDTO; -import com.guwan.backend.dto.user.UserDTO; +import com.guwan.backend.dto.user.*; import com.guwan.backend.service.EmailService; import com.guwan.backend.service.UserService; import com.guwan.backend.util.RedisUtils; @@ -53,7 +50,7 @@ public class UserController { } @PostMapping("/login") - public Result login(@RequestBody @Valid LoginRequest request) { + public Result login(@RequestBody @Valid LoginDto request) { try { log.info("用户登录: {}", request.getUsername()); return Result.success("登录成功", userService.login(request)); @@ -101,7 +98,9 @@ public class UserController { @PostMapping("/getEmailCode") - public Result getEmailCode(@RequestParam @Email(message = "邮箱格式不正确") String email) { + public Result getEmailCode(@RequestBody @Valid EmailDto emailDto) { + + String email = emailDto.getEmail(); log.info("邮箱注册: {}", email); @@ -130,7 +129,17 @@ public class UserController { return Result.success("手机验证码发送成功"); } - + @PostMapping("/email/code") + public Result sendEmailCode( + @RequestParam @Email(message = "邮箱格式不正确") String email) { + try { + userService.sendEmailCode(email); + return Result.success(); + } catch (Exception e) { + log.error("发送邮箱验证码失败", e); + return Result.error(e.getMessage()); + } + } diff --git a/src/main/java/com/guwan/backend/dto/user/LoginDto.java b/src/main/java/com/guwan/backend/dto/user/LoginDto.java index 3a230f1..2c6dfab 100644 --- a/src/main/java/com/guwan/backend/dto/user/LoginDto.java +++ b/src/main/java/com/guwan/backend/dto/user/LoginDto.java @@ -1,4 +1,34 @@ package com.guwan.backend.dto.user; + +import lombok.Data; + +@Data public class LoginDto { + /** + * 登录类型 对应前端 + */ + private String activeTab; + + /** + * 用户名 + */ + private String username; + /** + * 密码 + */ + private String password; + /** + * 手机号 + */ + private String phone; + /** + * 邮箱 + */ + private String email; + /** + * 验证码 + */ + private String code; + } diff --git a/src/main/java/com/guwan/backend/dto/user/UserDTO.java b/src/main/java/com/guwan/backend/dto/user/UserDTO.java index 8cf22dc..99f0528 100644 --- a/src/main/java/com/guwan/backend/dto/user/UserDTO.java +++ b/src/main/java/com/guwan/backend/dto/user/UserDTO.java @@ -1,8 +1,15 @@ package com.guwan.backend.dto.user; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; import java.time.LocalDateTime; +import java.util.Date; @Data public class UserDTO { @@ -14,8 +21,9 @@ public class UserDTO { private String phone; private Integer gender; private String bio; - private LocalDateTime createdTime; - private LocalDateTime lastLoginTime; + + private Date createdTime; + private Date lastLoginTime; private Integer status; private String token; } \ No newline at end of file diff --git a/src/main/java/com/guwan/backend/entity/User.java b/src/main/java/com/guwan/backend/entity/User.java index 235d4f5..c5fe143 100644 --- a/src/main/java/com/guwan/backend/entity/User.java +++ b/src/main/java/com/guwan/backend/entity/User.java @@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.*; import lombok.Data; import java.time.LocalDateTime; +import java.util.Date; @Data @TableName("user") @@ -29,10 +30,10 @@ public class User { @TableField(fill = FieldFill.INSERT) - private LocalDateTime createdTime; + private Date createdTime; @TableField(fill = FieldFill.INSERT_UPDATE) - private LocalDateTime lastLoginTime; + private Date lastLoginTime; private Integer status; } \ No newline at end of file diff --git a/src/main/java/com/guwan/backend/service/UserService.java b/src/main/java/com/guwan/backend/service/UserService.java index 24a9931..417238d 100644 --- a/src/main/java/com/guwan/backend/service/UserService.java +++ b/src/main/java/com/guwan/backend/service/UserService.java @@ -1,5 +1,6 @@ package com.guwan.backend.service; +import com.guwan.backend.dto.user.LoginDto; import com.guwan.backend.dto.user.RegisterDTO; import com.guwan.backend.dto.user.UserDTO; import com.guwan.backend.vo.user.EmailRegisterRequest; @@ -14,7 +15,13 @@ public interface UserService { * @return */ UserDTO register(RegisterDTO registerDTO); - UserDTO login(LoginRequest request); + + /** + * 登录 + * @param request + * @return + */ + UserDTO login(LoginDto request); UserDTO getCurrentUser(); Long getCurrentUserId(); UserDTO getUserById(Long id); diff --git a/src/main/java/com/guwan/backend/service/impl/UserServiceImpl.java b/src/main/java/com/guwan/backend/service/impl/UserServiceImpl.java index 4a380bf..3c59955 100644 --- a/src/main/java/com/guwan/backend/service/impl/UserServiceImpl.java +++ b/src/main/java/com/guwan/backend/service/impl/UserServiceImpl.java @@ -1,6 +1,7 @@ package com.guwan.backend.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.guwan.backend.dto.user.LoginDto; import com.guwan.backend.dto.user.RegisterDTO; import com.guwan.backend.dto.user.UserDTO; import com.guwan.backend.entity.User; @@ -10,6 +11,7 @@ import com.guwan.backend.service.UserService; import com.guwan.backend.service.VerificationService; import com.guwan.backend.util.JwtUtil; import com.guwan.backend.util.RedisUtil; +import com.guwan.backend.util.RedisUtils; import com.guwan.backend.vo.user.*; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -19,6 +21,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.time.LocalDateTime; +import java.util.Date; import java.util.concurrent.TimeUnit; @Slf4j @@ -30,6 +33,7 @@ public class UserServiceImpl implements UserService { private final PasswordEncoder passwordEncoder; private final JwtUtil jwtUtil; private final RedisUtil redisUtil; + private final RedisUtils redisUtils; private final VerificationService verificationService; private final EmailService emailService; @@ -74,28 +78,62 @@ public class UserServiceImpl implements UserService { user.setPassword(passwordEncoder.encode(request.getPassword())); user.setPhone(request.getPhone()); user.setEmail(request.getEmail()); - user.setCreatedTime(LocalDateTime.now()); user.setStatus(1); userMapper.insert(user); + + redisUtil.delete(request.getEmail()); + redisUtil.delete(request.getPhone()); return convertToDTO(user); } @Override - public UserDTO login(LoginRequest request) { - User user = findByUsername(request.getUsername()); - - if (user == null || !passwordEncoder.matches(request.getPassword(), user.getPassword())) { - throw new IllegalArgumentException("用户名或密码错误"); + public UserDTO login(LoginDto request) { + User user = null; + System.out.println("request = " + request); + + if (request.getActiveTab().equals("account")) { + user = userMapper.selectOne(new LambdaQueryWrapper().eq(User::getUsername, request.getUsername())); + if (user == null || !passwordEncoder.matches(request.getPassword(), user.getPassword())) { + throw new IllegalArgumentException("用户名或密码错误"); + } } - + + if (request.getActiveTab().equals("phone")) { + user = userMapper.selectOne(new LambdaQueryWrapper().eq(User::getPhone, request.getPhone())); + String redisPhoneCode = (String) redisUtil.get(request.getPhone()); + if (user == null) { + throw new IllegalArgumentException("用户未注册"); + } + if (!request.getCode().equals(redisPhoneCode)){ + throw new IllegalArgumentException("验证码错误"); + }else { + redisUtil.delete(request.getPhone()); + } + } + + if (request.getActiveTab().equals("email")) { + user = userMapper.selectOne(new LambdaQueryWrapper().eq(User::getEmail, request.getEmail())); + String redisEmailCode = (String) redisUtil.get(request.getEmail()); + if (user == null) { + throw new IllegalArgumentException("用户未注册"); + } + if (!request.getCode().equals(redisEmailCode)){ + throw new IllegalArgumentException("验证码错误"); + }else { + redisUtil.delete(request.getEmail()); + } + } + + if (user.getStatus() != 1) { throw new IllegalArgumentException("账号已被禁用"); } + // 更新最后登录时间 - user.setLastLoginTime(LocalDateTime.now()); + user.setLastLoginTime(new Date()); userMapper.updateById(user); UserDTO userDTO = convertToDTO(user); @@ -103,7 +141,7 @@ public class UserServiceImpl implements UserService { userDTO.setToken(token); // 缓存用户信息 - redisUtil.set(USER_CACHE_KEY + user.getId(), userDTO, USER_CACHE_DURATION, TimeUnit.SECONDS); + redisUtils.set(USER_CACHE_KEY + user.getId(), userDTO, USER_CACHE_DURATION); return userDTO; } diff --git a/src/main/java/com/guwan/backend/util/JwtUtil.java b/src/main/java/com/guwan/backend/util/JwtUtil.java index c287cf7..ba63ae2 100644 --- a/src/main/java/com/guwan/backend/util/JwtUtil.java +++ b/src/main/java/com/guwan/backend/util/JwtUtil.java @@ -11,6 +11,7 @@ import org.springframework.stereotype.Component; import java.security.Key; import java.util.Date; + @Slf4j @Component public class JwtUtil { diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index dd6a893..20c1ac5 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -67,7 +67,7 @@ mybatis-plus: # JWT配置 jwt: - secret: your-secret-key-must-be-at-least-32-bytes-long + secret: javax.crypto.spec.SecretKeySpec@5884561.Guwan.javax.crypto.spec.SecretKeySpec@5884561 expiration: 86400000 # 24小时 # 阿里云配置