init user-service & giftcode-service
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
package com.dken.userservice;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.data.mongodb.config.EnableMongoAuditing;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableMongoAuditing
|
||||
public class UserServiceApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(UserServiceApplication.class, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.dken.userservice.client;
|
||||
|
||||
import org.springframework.web.client.RestClient;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.stereotype.Component;
|
||||
import com.dken.userservice.dto.response.UserApplyGiftCodeResponse;
|
||||
import com.dken.userservice.dto.request.GiftCodeValidateRequest;
|
||||
|
||||
@Component
|
||||
public class GiftCodeClient {
|
||||
|
||||
private final RestClient restClient;
|
||||
|
||||
public GiftCodeClient(@Qualifier("giftCodeRestClient") RestClient restClient) {
|
||||
this.restClient = restClient;
|
||||
}
|
||||
|
||||
public UserApplyGiftCodeResponse applyGiftCode(
|
||||
String userId,
|
||||
String giftCode) {
|
||||
|
||||
return restClient
|
||||
.post()
|
||||
.uri("/gift-codes/apply")
|
||||
.body(new GiftCodeValidateRequest(userId, giftCode))
|
||||
.retrieve()
|
||||
.body(UserApplyGiftCodeResponse.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.dken.userservice.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.client.RestClient;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
|
||||
@Configuration
|
||||
public class GiftCodeClientConfig {
|
||||
|
||||
@Bean("giftCodeRestClient")
|
||||
public RestClient giftCodeRestClient(
|
||||
@Value("${giftcode.service.url}") String baseUrl) {
|
||||
return RestClient.builder()
|
||||
.baseUrl(baseUrl)
|
||||
.requestInterceptor((request, body, execution) -> {
|
||||
return execution.execute(request, body);
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.dken.userservice.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
|
||||
@Configuration
|
||||
public class RedisConfig {
|
||||
|
||||
@Bean
|
||||
public RedisTemplate<String, String> redisTemplate(
|
||||
RedisConnectionFactory factory) {
|
||||
|
||||
RedisTemplate<String, String> template = new RedisTemplate<>();
|
||||
template.setConnectionFactory(factory);
|
||||
template.setKeySerializer(new StringRedisSerializer());
|
||||
template.setValueSerializer(new StringRedisSerializer());
|
||||
return template;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.dken.userservice.controller;
|
||||
|
||||
import com.dken.userservice.dto.request.CreateUserRequest;
|
||||
import com.dken.userservice.dto.request.UserApplyGiftCodeRequest;
|
||||
import com.dken.userservice.dto.response.UserApplyGiftCodeResponse;
|
||||
import com.dken.userservice.dto.response.UserResponse;
|
||||
import com.dken.userservice.service.UserService;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.Max;
|
||||
import jakarta.validation.constraints.Min;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/users")
|
||||
public class UserController {
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@PostMapping
|
||||
public UserResponse create(@Valid @RequestBody CreateUserRequest req) {
|
||||
return userService.createUser(req);
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public UserResponse getUserById(@PathVariable String id) {
|
||||
return userService.getUserById(id);
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public Page<UserResponse> getAllUsers(@RequestParam(defaultValue = "0") @Min(0) int page,
|
||||
@RequestParam(defaultValue = "10") @Min(1) @Max(100) int size) {
|
||||
return userService.getAllUsers(page, size);
|
||||
}
|
||||
|
||||
@PostMapping("/apply-gift-code")
|
||||
public UserApplyGiftCodeResponse applyGiftCode(@Valid @RequestBody UserApplyGiftCodeRequest req) {
|
||||
return userService.applyGiftCode(req);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.dken.userservice.dto.request;
|
||||
|
||||
import jakarta.validation.constraints.Email;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
|
||||
public class CreateUserRequest {
|
||||
@NotBlank(message = "Name is required")
|
||||
private String name;
|
||||
|
||||
@NotBlank(message = "Email is required")
|
||||
@Email(message = "Email should be valid")
|
||||
private String email;
|
||||
|
||||
@NotBlank(message = "Password is required")
|
||||
private String password;
|
||||
|
||||
private String phone;
|
||||
|
||||
private String sex;
|
||||
|
||||
// Constructors
|
||||
public CreateUserRequest() {
|
||||
}
|
||||
|
||||
public CreateUserRequest(String name, String email, String password, String phone, String sex) {
|
||||
this.name = name;
|
||||
this.email = email;
|
||||
this.password = password;
|
||||
this.phone = phone;
|
||||
this.sex = sex;
|
||||
}
|
||||
|
||||
// Getters and Setters
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getPhone() {
|
||||
return phone;
|
||||
}
|
||||
|
||||
public String getSex() {
|
||||
return sex;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.dken.userservice.dto.request;
|
||||
|
||||
public record GiftCodeValidateRequest(
|
||||
String userId,
|
||||
String giftCode) {
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.dken.userservice.dto.request;
|
||||
|
||||
public class UserApplyGiftCodeRequest {
|
||||
private String userId;
|
||||
private String giftCode;
|
||||
|
||||
public UserApplyGiftCodeRequest(String userId, String giftCode) {
|
||||
this.userId = userId;
|
||||
this.giftCode = giftCode;
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public String getGiftCode() {
|
||||
return giftCode;
|
||||
}
|
||||
|
||||
public void setGiftCode(String giftCode) {
|
||||
this.giftCode = giftCode;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.dken.userservice.dto.response;
|
||||
|
||||
public class UserApplyGiftCodeResponse {
|
||||
private String status;
|
||||
private String message;
|
||||
private String description;
|
||||
|
||||
public UserApplyGiftCodeResponse(String status, String message, String description) {
|
||||
this.status = status;
|
||||
this.message = message;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.dken.userservice.dto.response;
|
||||
|
||||
import com.dken.userservice.model.User;
|
||||
|
||||
public class UserResponse {
|
||||
private String id;
|
||||
private String name;
|
||||
private String email;
|
||||
private String phone;
|
||||
|
||||
public String getPhone() {
|
||||
return phone;
|
||||
}
|
||||
|
||||
public void setPhone(String phone) {
|
||||
this.phone = phone;
|
||||
}
|
||||
|
||||
private String sex;
|
||||
|
||||
public String getSex() {
|
||||
return sex;
|
||||
}
|
||||
|
||||
public void setSex(String sex) {
|
||||
this.sex = sex;
|
||||
}
|
||||
|
||||
// Constructors
|
||||
public UserResponse() {
|
||||
}
|
||||
|
||||
public static UserResponse from(User user) {
|
||||
return new UserResponse(
|
||||
user.getId(),
|
||||
user.getName(),
|
||||
user.getEmail(),
|
||||
user.getPhone(),
|
||||
user.getSex() != null ? user.getSex().name() : null);
|
||||
}
|
||||
|
||||
public UserResponse(String id, String name, String email, String phone, String sex) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.email = email;
|
||||
this.phone = phone;
|
||||
this.sex = sex;
|
||||
}
|
||||
|
||||
// Getters and Setters
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.dken.userservice.exception;
|
||||
|
||||
public class DefaultException extends RuntimeException {
|
||||
public DefaultException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.dken.userservice.exception;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@RestControllerAdvice
|
||||
public class GlobalExceptionHandler {
|
||||
|
||||
@ExceptionHandler(DefaultException.class)
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public Map<String, String> handleDefaultException(DefaultException ex) {
|
||||
return Map.of("message", ex.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionHandler(InvalidUserIdException.class)
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public Map<String, String> handleInvalidId(InvalidUserIdException ex) {
|
||||
return Map.of("message", ex.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionHandler(UserNotFoundException.class)
|
||||
@ResponseStatus(HttpStatus.NOT_FOUND)
|
||||
public Map<String, String> handleNotFound(UserNotFoundException ex) {
|
||||
return Map.of("message", ex.getMessage());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.dken.userservice.exception;
|
||||
|
||||
public class InvalidEnumException extends RuntimeException {
|
||||
public InvalidEnumException(String value) {
|
||||
super("Invalid Enum value: " + value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.dken.userservice.exception;
|
||||
|
||||
public class InvalidUserIdException extends RuntimeException {
|
||||
public InvalidUserIdException(String id) {
|
||||
super("Invalid user id: " + id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.dken.userservice.exception;
|
||||
|
||||
public class UserNotFoundException extends RuntimeException {
|
||||
public UserNotFoundException(String id) {
|
||||
super("User not found with id: " + id);
|
||||
}
|
||||
}
|
||||
112
user-service/src/main/java/com/dken/userservice/model/User.java
Normal file
112
user-service/src/main/java/com/dken/userservice/model/User.java
Normal file
@@ -0,0 +1,112 @@
|
||||
package com.dken.userservice.model;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
import org.springframework.data.annotation.LastModifiedDate;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
@Document(collection = "users")
|
||||
public class User {
|
||||
|
||||
@Id
|
||||
private String id;
|
||||
|
||||
private String name;
|
||||
private String password;
|
||||
|
||||
private String email;
|
||||
private String phone;
|
||||
private UserSex sex;
|
||||
|
||||
private UserStatus status;
|
||||
|
||||
@CreatedDate
|
||||
private Instant createdAt;
|
||||
|
||||
@LastModifiedDate
|
||||
private Instant updatedAt;
|
||||
|
||||
// ===== constructors =====
|
||||
public User() {
|
||||
}
|
||||
|
||||
public User(String name, String email, String phone, UserSex sex) {
|
||||
this.name = name;
|
||||
this.email = email;
|
||||
this.phone = phone;
|
||||
this.sex = sex;
|
||||
this.status = UserStatus.ACTIVE;
|
||||
}
|
||||
|
||||
public boolean confirmGiftCode(String giftCode) {
|
||||
// this.giftCode = giftCode;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ===== getter & setter =====
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getPhone() {
|
||||
return phone;
|
||||
}
|
||||
|
||||
public void setPhone(String phone) {
|
||||
this.phone = phone;
|
||||
}
|
||||
|
||||
public UserStatus getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(UserStatus status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public Instant getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public Instant getUpdatedAt() {
|
||||
return updatedAt;
|
||||
}
|
||||
|
||||
public UserSex getSex() {
|
||||
return sex;
|
||||
}
|
||||
|
||||
public void setSex(UserSex sex) {
|
||||
this.sex = sex;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.dken.userservice.model;
|
||||
|
||||
import com.dken.userservice.exception.InvalidEnumException;
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
|
||||
public enum UserSex {
|
||||
MALE,
|
||||
FEMALE,
|
||||
OTHER;
|
||||
|
||||
@JsonCreator
|
||||
public static UserSex from(String value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return UserSex.valueOf(value.toUpperCase());
|
||||
} catch (Exception e) {
|
||||
throw new InvalidEnumException("UserSex=" + value + " is invalid");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.dken.userservice.model;
|
||||
|
||||
public enum UserStatus {
|
||||
ACTIVE,
|
||||
INACTIVE,
|
||||
BLOCKED
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.dken.userservice.repository;
|
||||
|
||||
import com.dken.userservice.model.User;
|
||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface UserRepository
|
||||
extends MongoRepository<User, String> {
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.dken.userservice.service;
|
||||
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
@Component
|
||||
public class RedisLockService {
|
||||
|
||||
private final RedisTemplate<String, String> redis;
|
||||
|
||||
public RedisLockService(RedisTemplate<String, String> redis) {
|
||||
this.redis = redis;
|
||||
}
|
||||
|
||||
public boolean lock(String key, Duration ttl) {
|
||||
return Boolean.TRUE.equals(
|
||||
redis.opsForValue()
|
||||
.setIfAbsent(key, "1", ttl));
|
||||
}
|
||||
|
||||
public void unlock(String key) {
|
||||
redis.delete(key);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.dken.userservice.service;
|
||||
|
||||
import com.dken.userservice.client.GiftCodeClient;
|
||||
import com.dken.userservice.dto.request.CreateUserRequest;
|
||||
import com.dken.userservice.dto.request.GiftCodeValidateRequest;
|
||||
import com.dken.userservice.dto.request.UserApplyGiftCodeRequest;
|
||||
import com.dken.userservice.dto.response.UserApplyGiftCodeResponse;
|
||||
import com.dken.userservice.dto.response.UserResponse;
|
||||
import com.dken.userservice.model.User;
|
||||
import com.dken.userservice.model.UserSex;
|
||||
import com.dken.userservice.repository.UserRepository;
|
||||
import com.dken.userservice.exception.DefaultException;
|
||||
import com.dken.userservice.exception.InvalidUserIdException;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
|
||||
import org.bson.types.ObjectId;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
|
||||
@Service
|
||||
public class UserService {
|
||||
|
||||
private final UserRepository userRepository;
|
||||
private final GiftCodeClient giftCodeClient;
|
||||
|
||||
public UserService(UserRepository userRepository, GiftCodeClient giftCodeClient) {
|
||||
this.userRepository = userRepository;
|
||||
this.giftCodeClient = giftCodeClient;
|
||||
}
|
||||
|
||||
public Page<UserResponse> getAllUsers(int page, int size) {
|
||||
|
||||
Pageable pageable = PageRequest.of(page, size, Sort.by("createdAt").descending());
|
||||
|
||||
return userRepository.findAll(pageable)
|
||||
.map(UserResponse::from);
|
||||
}
|
||||
|
||||
public User create(String name, String email, String password, String phone, String sex) {
|
||||
User user = new User();
|
||||
user.setName(name);
|
||||
user.setEmail(email);
|
||||
user.setPassword(password);
|
||||
user.setPhone(phone);
|
||||
user.setSex(UserSex.from(sex));
|
||||
return userRepository.save(user);
|
||||
}
|
||||
|
||||
public UserResponse createUser(CreateUserRequest req) {
|
||||
User user = create(req.getName(), req.getEmail(), req.getPassword(), req.getPhone(), req.getSex());
|
||||
return UserResponse.from(user);
|
||||
}
|
||||
|
||||
public UserResponse getUserById(String id) {
|
||||
if (!ObjectId.isValid(id)) {
|
||||
throw new InvalidUserIdException(id);
|
||||
}
|
||||
User user = userRepository.findById(id).orElseThrow(() -> new RuntimeException("User not found"));
|
||||
return UserResponse.from(user);
|
||||
}
|
||||
|
||||
public UserApplyGiftCodeResponse applyGiftCode(UserApplyGiftCodeRequest req) {
|
||||
User user = userRepository.findById(req.getUserId()).orElseThrow(() -> new RuntimeException("User not found"));
|
||||
return giftCodeClient.applyGiftCode(req.getUserId(), req.getGiftCode());
|
||||
}
|
||||
}
|
||||
1
user-service/src/main/resources/application.properties
Normal file
1
user-service/src/main/resources/application.properties
Normal file
@@ -0,0 +1 @@
|
||||
spring.application.name=demo
|
||||
15
user-service/src/main/resources/application.yml
Normal file
15
user-service/src/main/resources/application.yml
Normal file
@@ -0,0 +1,15 @@
|
||||
server:
|
||||
port: 8601
|
||||
giftcode:
|
||||
service:
|
||||
url: http://localhost:8602
|
||||
spring:
|
||||
application:
|
||||
name: user-service
|
||||
data:
|
||||
mongodb:
|
||||
uri: mongodb://localhost:27017/userdb
|
||||
auto-index-creation: true
|
||||
redis:
|
||||
host: localhost
|
||||
port: 6379
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.dken.userservice;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
@SpringBootTest
|
||||
class UserServiceApplicationTests {
|
||||
|
||||
@Test
|
||||
void contextLoads() {
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user