diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..3a3c394
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,156 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.2.4.RELEASE
+
+
+ com.test-backend-java
+ test-backend-java
+ 0.0.1-SNAPSHOT
+ test-backend-java
+ Demo project for Spring Boot
+
+
+ 11
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.junit.vintage
+ junit-vintage-engine
+
+
+
+
+
+ mysql
+ mysql-connector-java
+ runtime
+
+
+
+ log4j
+ log4j
+ 1.2.17
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+
+ com.alibaba
+ fastjson
+ 1.2.54
+
+
+
+
+ org.projectlombok
+ lombok
+ 1.18.12
+ provided
+
+
+
+ com.jiang.core
+ core
+ 1.0-SNAPSHOT
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+
+ org.springframework.boot
+ spring-boot-starter-oauth2-client
+
+
+ org.springframework.boot
+ spring-boot-starter-oauth2-resource-server
+
+
+
+
+
+ ch.qos.logback
+ logback-classic
+
+
+
+
+ org.flywaydb
+ flyway-core
+ 7.11.1
+
+
+
+
+
+
+
+
+ kr.motd.maven
+ os-maven-plugin
+ 1.5.0.Final
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.1
+
+ ${java.version}
+ ${java.version}
+
+
+
+
+
+
+
diff --git a/src/main/java/com/jiang/test/backend/TestBackendApplication.java b/src/main/java/com/jiang/test/backend/TestBackendApplication.java
new file mode 100644
index 0000000..8cd5260
--- /dev/null
+++ b/src/main/java/com/jiang/test/backend/TestBackendApplication.java
@@ -0,0 +1,13 @@
+package com.jiang.test.backend;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class TestBackendApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(TestBackendApplication.class, args);
+ }
+
+}
diff --git a/src/main/java/com/jiang/test/backend/annotation/Authorized.java b/src/main/java/com/jiang/test/backend/annotation/Authorized.java
new file mode 100644
index 0000000..4ddd723
--- /dev/null
+++ b/src/main/java/com/jiang/test/backend/annotation/Authorized.java
@@ -0,0 +1,12 @@
+package com.jiang.test.backend.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface Authorized {
+}
+
diff --git a/src/main/java/com/jiang/test/backend/config/SecurityConfig.java b/src/main/java/com/jiang/test/backend/config/SecurityConfig.java
new file mode 100644
index 0000000..88ae45e
--- /dev/null
+++ b/src/main/java/com/jiang/test/backend/config/SecurityConfig.java
@@ -0,0 +1,30 @@
+package com.jiang.test.backend.config;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+
+@Configuration
+@EnableWebSecurity
+public class SecurityConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http.authorizeRequests()
+ .antMatchers("/login").authenticated()
+ .anyRequest().permitAll()
+ .and()
+ .formLogin().disable();
+ }
+
+ @Autowired
+ public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
+ // 在这里配置模拟的授权用户,可以根据需要自定义
+ auth.inMemoryAuthentication()
+ .withUser("username")
+ .password("{noop}password") // {noop} 表示密码不加密
+ .roles("USER");
+ }
+}
diff --git a/src/main/java/com/jiang/test/backend/config/WebConfig.java b/src/main/java/com/jiang/test/backend/config/WebConfig.java
new file mode 100644
index 0000000..9b01fec
--- /dev/null
+++ b/src/main/java/com/jiang/test/backend/config/WebConfig.java
@@ -0,0 +1,20 @@
+package com.jiang.test.backend.config;
+
+import com.jiang.test.backend.interceptor.AuthorizationInterceptor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
+
+@Configuration
+public class WebConfig extends WebMvcConfigurerAdapter {
+
+ @Autowired
+ private AuthorizationInterceptor authorizationInterceptor;
+
+ @Override
+ public void addInterceptors(InterceptorRegistry registry) {
+ registry.addInterceptor(authorizationInterceptor)
+ .addPathPatterns("/api/**"); // 设置需要进行授权检查的接口路径
+ }
+}
diff --git a/src/main/java/com/jiang/test/backend/constant/ApiConstants.java b/src/main/java/com/jiang/test/backend/constant/ApiConstants.java
new file mode 100644
index 0000000..315c155
--- /dev/null
+++ b/src/main/java/com/jiang/test/backend/constant/ApiConstants.java
@@ -0,0 +1,22 @@
+package com.jiang.test.backend.constant;
+
+public final class ApiConstants {
+
+ public static final String COMMON_URL = "/api";
+ public static final String GET_URL = "/user/getUser/{id}";
+ public static final String POST_URL = "/user/addUser";
+ public static final String UPDATE_URL = "/user/updateUser";
+ public static final String DELETE_URL = "/user/delUser";
+
+ public static final String GET_FOLLOWERS_URL = "/friend/{userId}";
+ public static final String ADD_FOLLOWERS_URL = "/friend/addFollower";
+ public static final String REMOVE_FOLLOWERS_URL = "/friend/removeFollower";
+ public static final String GET_FRIENDS_URL = "/friend/getFriends/{userId}";
+ public static final String GET_COMMON_FRIENDS_URL = "/friend/{userId}/friends/{otherUserId}";
+ public static final String GET_NEARBY_FRIENDS_URL = "/friend/{userId}/distance/{disdance}";
+
+
+ private ApiConstants() {
+ // 私有构造函数,防止实例化
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/jiang/test/backend/controller/FriendController.java b/src/main/java/com/jiang/test/backend/controller/FriendController.java
new file mode 100644
index 0000000..8d20bca
--- /dev/null
+++ b/src/main/java/com/jiang/test/backend/controller/FriendController.java
@@ -0,0 +1,97 @@
+package com.jiang.test.backend.controller;
+
+import com.jiang.test.backend.annotation.Authorized;
+import com.jiang.test.backend.constant.ApiConstants;
+import com.jiang.test.backend.entity.User;
+import com.jiang.test.backend.service.FriendService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@RestController
+@RequestMapping(ApiConstants.COMMON_URL)
+public class FriendController {
+
+ @Autowired
+ FriendService friendService;
+
+ /**
+ * 获取用户的所有关注者
+ * @param userId
+ * @return List
+ */
+ @GetMapping(ApiConstants.GET_FOLLOWERS_URL)
+ @Authorized
+ public ResponseEntity> getFollowers(@PathVariable int userId) {
+ List followers = friendService.getFollowers(userId);
+ return ResponseEntity.ok(followers);
+ }
+
+ /**
+ * 添加关注者
+ * 请求体中包含要添加的关注者的ID。
+ * @param userId
+ * @param followerId
+ * @return
+ */
+ @PostMapping(ApiConstants.ADD_FOLLOWERS_URL)
+ @Authorized
+ public ResponseEntity addFollower(@RequestParam int userId, @RequestParam int followerId) {
+ friendService.addFollower(userId,followerId);
+ return ResponseEntity.ok("Follower added successfully.");
+ }
+
+ /**
+ * 删除关注者
+ * @param userId
+ * @param followerId
+ * @return
+ */
+ @DeleteMapping(ApiConstants.REMOVE_FOLLOWERS_URL)
+ @Authorized
+ public ResponseEntity removeFollower(@RequestParam int userId, @RequestParam int followerId) {
+ friendService.removeFollower(userId,followerId);
+ return ResponseEntity.ok("Follower removed successfully.");
+ }
+
+ /**
+ * 获取用户的所有好友
+ * @param userId
+ * @return
+ */
+ @GetMapping(ApiConstants.GET_FRIENDS_URL)
+ @Authorized
+ public ResponseEntity> getFriends(@PathVariable int userId) {
+ List friends = friendService.getFriends(userId);
+ return ResponseEntity.ok(friends);
+ }
+
+ /**
+ * 获取共同的朋友
+ * @param userId
+ * @param otherUserId
+ * @return
+ */
+ @GetMapping(ApiConstants.GET_COMMON_FRIENDS_URL)
+ @Authorized
+ public ResponseEntity> getCommonFriends(@PathVariable int userId, @PathVariable int otherUserId) {
+ List commonFriends = friendService.getCommonFriends(userId,otherUserId);
+ return ResponseEntity.ok(commonFriends);
+ }
+
+ /**
+ * 获取最近的朋友信息
+ * @param userId
+ * @param distance
+ * @return
+ */
+ @GetMapping(ApiConstants.GET_NEARBY_FRIENDS_URL)
+ @Authorized
+ public ResponseEntity> getNearbyFriends(@PathVariable int userId,
+ @PathVariable double distance) {
+ List nearbyFriends = friendService.getNearbyFriends(userId,distance);
+ return ResponseEntity.ok(nearbyFriends);
+ }
+}
diff --git a/src/main/java/com/jiang/test/backend/controller/UserController.java b/src/main/java/com/jiang/test/backend/controller/UserController.java
new file mode 100644
index 0000000..3799edd
--- /dev/null
+++ b/src/main/java/com/jiang/test/backend/controller/UserController.java
@@ -0,0 +1,83 @@
+package com.jiang.test.backend.controller;
+
+import com.jiang.test.backend.annotation.Authorized;
+import com.jiang.test.backend.constant.ApiConstants;
+import com.jiang.test.backend.entity.User;
+import com.jiang.test.backend.service.UserService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Optional;
+
+@RestController
+@RequestMapping(ApiConstants.COMMON_URL)
+public class UserController {
+
+ @Autowired
+ private UserService userService;
+
+ /**
+ * getUser
+ * @param id userId
+ * @return User user信息
+ * @description 根据id获取user
+ */
+ @GetMapping(ApiConstants.GET_URL)
+ @Authorized
+ public ResponseEntity getUser(@PathVariable String id){
+ Optional user = userService.getUserById(Integer.parseInt(id));
+ return user.map(value -> new ResponseEntity<>(value, HttpStatus.OK))
+ .orElseGet(() -> new ResponseEntity<>(HttpStatus.NOT_FOUND));
+ }
+
+ /**
+ * addUser
+ * @param user user信息
+ * @return user user信息
+ * @description 添加user
+ */
+ @PostMapping(ApiConstants.POST_URL)
+ @Authorized
+ public ResponseEntity addUser(@RequestBody User user){
+ User createdUser = userService.addUser(user);
+ return new ResponseEntity<>(createdUser, HttpStatus.CREATED);
+ }
+
+ /**
+ * updateUser
+ * @param user user信息
+ * @return user user信息
+ * @description 更新user
+ */
+ @PutMapping(ApiConstants.UPDATE_URL)
+ @Authorized
+ public ResponseEntity updateUser(@RequestBody User user){
+ Optional existingUser = userService.getUserById(user.getId());
+ if (existingUser.isPresent()) {
+ User updatedUser = userService.updateUser(user);
+ return new ResponseEntity<>(updatedUser, HttpStatus.OK);
+ } else {
+ return new ResponseEntity<>(HttpStatus.NOT_FOUND);
+ }
+ }
+
+ /**
+ * updateUser
+ * @param id userId
+ * @return void
+ * @description 根据userId 删除User
+ */
+ @DeleteMapping(ApiConstants.DELETE_URL)
+ @Authorized
+ public ResponseEntity delUser(@RequestParam int id){
+ Optional existingUser = userService.getUserById(id);
+ if (existingUser.isPresent()) {
+ userService.deleteUserById(id);
+ return new ResponseEntity<>(HttpStatus.NO_CONTENT);
+ } else {
+ return new ResponseEntity<>(HttpStatus.NOT_FOUND);
+ }
+ }
+}
diff --git a/src/main/java/com/jiang/test/backend/entity/Follower.java b/src/main/java/com/jiang/test/backend/entity/Follower.java
new file mode 100644
index 0000000..9cd3df0
--- /dev/null
+++ b/src/main/java/com/jiang/test/backend/entity/Follower.java
@@ -0,0 +1,28 @@
+package com.jiang.test.backend.entity;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.*;
+
+@Entity
+@Table(name = "tbl_user")
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class Follower {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private int id;
+
+ @Column(name = "user_id")
+ private int userId;
+
+ @Column(name = "follower_id")
+ private int followerId;
+
+}
diff --git a/src/main/java/com/jiang/test/backend/entity/User.java b/src/main/java/com/jiang/test/backend/entity/User.java
new file mode 100644
index 0000000..71977dc
--- /dev/null
+++ b/src/main/java/com/jiang/test/backend/entity/User.java
@@ -0,0 +1,47 @@
+package com.jiang.test.backend.entity;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import java.util.Date;
+
+@Entity
+@Table(name = "tbl_user")
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class User {
+
+ @Column(name = "id")
+ @Id
+ private int id;
+
+ @Column(name = "name")
+ private String name;
+
+ @Column(name = "dob")
+ private Date dob;
+
+ @Column(name = "address")
+ private String address;
+
+ @Column(name = "description")
+ private String description;
+
+ @Column(name = "created_at")
+ private Date createdAt;
+
+ @Column(name = "latitude")
+ private Double latitude;
+
+ @Column(name = "longitude")
+ private Double longitude;
+
+}
diff --git a/src/main/java/com/jiang/test/backend/exception/GlobalExceptionHandler.java b/src/main/java/com/jiang/test/backend/exception/GlobalExceptionHandler.java
new file mode 100644
index 0000000..b5abeee
--- /dev/null
+++ b/src/main/java/com/jiang/test/backend/exception/GlobalExceptionHandler.java
@@ -0,0 +1,15 @@
+package com.jiang.test.backend.exception;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+
+@ControllerAdvice
+public class GlobalExceptionHandler {
+
+ @ExceptionHandler(Exception.class)
+ public ResponseEntity handleException(Exception ex) {
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Internal Server Error");
+ }
+}
diff --git a/src/main/java/com/jiang/test/backend/interceptor/AuthorizationInterceptor.java b/src/main/java/com/jiang/test/backend/interceptor/AuthorizationInterceptor.java
new file mode 100644
index 0000000..f483ea2
--- /dev/null
+++ b/src/main/java/com/jiang/test/backend/interceptor/AuthorizationInterceptor.java
@@ -0,0 +1,37 @@
+package com.jiang.test.backend.interceptor;
+
+import com.jiang.test.backend.annotation.Authorized;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+@Component
+@Slf4j
+public class AuthorizationInterceptor extends HandlerInterceptorAdapter {
+
+ @Override
+ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+ // 检查是否有 @Authorized 注解
+ if (handler instanceof HandlerMethod) {
+ HandlerMethod handlerMethod = (HandlerMethod) handler;
+ if (handlerMethod.hasMethodAnnotation(Authorized.class)) {
+ // 进行授权检查逻辑
+ if (!isAuthorized(request)) {
+ response.setStatus(HttpServletResponse.SC_FORBIDDEN);
+ return false; // 返回 false,拦截请求
+ }
+ }
+ }
+ return true; // 允许请求继续处理
+ }
+
+ private boolean isAuthorized(HttpServletRequest request) {
+ // 进行授权检查的逻辑,例如检查请求头、访问令牌等
+ log.info("Authorization checking");
+ return true;
+ }
+}
diff --git a/src/main/java/com/jiang/test/backend/repository/FollowerRepository.java b/src/main/java/com/jiang/test/backend/repository/FollowerRepository.java
new file mode 100644
index 0000000..d773c78
--- /dev/null
+++ b/src/main/java/com/jiang/test/backend/repository/FollowerRepository.java
@@ -0,0 +1,18 @@
+package com.jiang.test.backend.repository;
+
+import com.jiang.test.backend.entity.Follower;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+import java.util.Optional;
+
+@Repository
+public interface FollowerRepository extends JpaRepository {
+
+ List findByUserId(int userId);
+
+ Optional findByUserIdAndFollowerId(int userId, int followerId);
+
+
+}
diff --git a/src/main/java/com/jiang/test/backend/repository/UserRepository.java b/src/main/java/com/jiang/test/backend/repository/UserRepository.java
new file mode 100644
index 0000000..2d0ef0e
--- /dev/null
+++ b/src/main/java/com/jiang/test/backend/repository/UserRepository.java
@@ -0,0 +1,10 @@
+package com.jiang.test.backend.repository;
+
+import com.jiang.test.backend.entity.User;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface UserRepository extends JpaRepository {
+
+}
diff --git a/src/main/java/com/jiang/test/backend/service/FriendService.java b/src/main/java/com/jiang/test/backend/service/FriendService.java
new file mode 100644
index 0000000..54d86cf
--- /dev/null
+++ b/src/main/java/com/jiang/test/backend/service/FriendService.java
@@ -0,0 +1,21 @@
+package com.jiang.test.backend.service;
+
+import com.jiang.test.backend.entity.User;
+
+import java.util.List;
+
+public interface FriendService {
+
+ List getFollowers(int userId);
+
+ void addFollower(int userId, int followerId);
+
+ void removeFollower(int userId, int followerId);
+
+ List getFriends(int userId);
+
+ List getCommonFriends(int userId1, int userId2);
+
+ List getNearbyFriends(int userId, double distance);
+
+}
diff --git a/src/main/java/com/jiang/test/backend/service/UserService.java b/src/main/java/com/jiang/test/backend/service/UserService.java
new file mode 100644
index 0000000..273af4d
--- /dev/null
+++ b/src/main/java/com/jiang/test/backend/service/UserService.java
@@ -0,0 +1,16 @@
+package com.jiang.test.backend.service;
+
+import com.jiang.test.backend.entity.User;
+
+import java.util.Optional;
+
+public interface UserService {
+
+ Optional getUserById(int id);
+
+ User addUser(User user);
+
+ User updateUser(User user);
+
+ void deleteUserById(int id);
+}
diff --git a/src/main/java/com/jiang/test/backend/service/impl/FriendServiceImpl.java b/src/main/java/com/jiang/test/backend/service/impl/FriendServiceImpl.java
new file mode 100644
index 0000000..27f99aa
--- /dev/null
+++ b/src/main/java/com/jiang/test/backend/service/impl/FriendServiceImpl.java
@@ -0,0 +1,133 @@
+package com.jiang.test.backend.service.impl;
+
+import com.jiang.test.backend.entity.Follower;
+import com.jiang.test.backend.entity.User;
+import com.jiang.test.backend.repository.FollowerRepository;
+import com.jiang.test.backend.repository.UserRepository;
+import com.jiang.test.backend.service.FriendService;
+import com.jiang.test.backend.service.UserService;
+import com.jiang.test.backend.utils.DistanceUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+@Service
+public class FriendServiceImpl implements FriendService {
+
+ private static final Logger logger = LoggerFactory.getLogger(UserService.class);
+
+ @Autowired
+ FollowerRepository followerRepository;
+
+ @Autowired
+ UserRepository userRepository;
+
+ @Override
+ public List getFollowers(int userId) {
+ List followers = followerRepository.findByUserId(userId);
+ // 将 Follower 转换为 User 对象
+ List followerUsers = new ArrayList<>();
+ for (Follower follower : followers) {
+ User followerUser = convertFollowerToUser(follower);
+ followerUsers.add(followerUser);
+ }
+ return followerUsers;
+ }
+
+ private User convertFollowerToUser(Follower follower) {
+ return userRepository.findById(follower.getFollowerId()).get();
+ }
+
+ @Override
+ public void addFollower(int userId, int followerId) {
+ Optional existingFollower = followerRepository.findByUserIdAndFollowerId(userId, followerId);
+ if (existingFollower.isPresent()) {
+ logger.error("Follower already exists.");
+ throw new IllegalArgumentException("Follower already exists.");
+ }
+ Follower follower = new Follower();
+ follower.setUserId(userId);
+ follower.setFollowerId(followerId);
+ followerRepository.save(follower);
+ }
+
+ @Override
+ public void removeFollower(int userId, int followerId) {
+ Optional follower = followerRepository.findByUserIdAndFollowerId(userId, followerId);
+ if (follower.isPresent()) {
+ followerRepository.delete(follower.get());
+ } else {
+ logger.error("Follower not found.");
+ throw new IllegalArgumentException("Follower not found.");
+ }
+ }
+
+ @Override
+ public List getFriends(int userId) {
+ List followers = followerRepository.findByUserId(userId);
+ List friendsList = new ArrayList<>();
+ for (int i = 0; i < followers.size(); i++) {
+ List followers1 = getFollowers(followers.get(i).getFollowerId());
+ if (CollectionUtils.isEmpty(followers1)){
+ friendsList.add(followers1.get(0));
+ }
+ }
+ return friendsList;
+ }
+
+ @Override
+ public List getCommonFriends(int userId1, int userId2) {
+
+ List commonFriends = new ArrayList<>();
+
+ // 获取用户1的好友列表
+ List friends1 = getFriends(userId1);
+
+ // 获取用户2的好友列表
+ List friends2 = getFriends(userId2);
+
+ // 遍历用户1的好友列表,判断是否为用户2的好友
+ for (User friend1 : friends1) {
+ if (friends2.contains(friend1)) {
+ commonFriends.add(friend1);
+ }
+ }
+
+ return commonFriends;
+ }
+
+ @Override
+ public List getNearbyFriends(int userId, double distance) {
+
+ List nearbyFriendsList = new ArrayList<>();
+
+ User userInfo = userRepository.findById(userId).get();
+ Double latitude1 = userInfo.getLatitude();
+ Double longitude1 = userInfo.getLongitude();
+
+ //获取所有朋友
+ List friendList = getFriends(userId);
+
+ if (CollectionUtils.isEmpty(friendList)) {
+ logger.info("No Friend");
+ return null;
+ }
+
+ //计算小于规定距离的
+ for (User user:friendList) {
+ double calculateDistance = DistanceUtils.calculateDistance(latitude1, longitude1, user.getLatitude(), user.getLongitude());
+ if (calculateDistance getUserById(int id){
+ logger.info("User get: {}", id);
+ return userRepository.findById(id);
+ }
+
+ @Override
+ public User addUser(User user) {
+ User saveUser = userRepository.save(user);
+ logger.info("User saved: {}", user);
+ return saveUser;
+ }
+
+ @Override
+ public User updateUser(User user) {
+ User updateUser = userRepository.save(user);
+ logger.info("User updated: {}", updateUser);
+ return updateUser;
+ }
+
+ @Override
+ public void deleteUserById(int id) {
+ logger.info("User deleted: {}", id);
+ userRepository.deleteById(id);
+ }
+
+
+}
diff --git a/src/main/java/com/jiang/test/backend/utils/DistanceUtils.java b/src/main/java/com/jiang/test/backend/utils/DistanceUtils.java
new file mode 100644
index 0000000..628d5ae
--- /dev/null
+++ b/src/main/java/com/jiang/test/backend/utils/DistanceUtils.java
@@ -0,0 +1,27 @@
+package com.jiang.test.backend.utils;
+
+public class DistanceUtils {
+
+ public static double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
+ double earthRadius = 6371.0; // 地球半径(单位:公里)
+
+ // 将经纬度转换为弧度
+ double lat1Rad = Math.toRadians(lat1);
+ double lon1Rad = Math.toRadians(lon1);
+ double lat2Rad = Math.toRadians(lat2);
+ double lon2Rad = Math.toRadians(lon2);
+
+ // 计算经纬度的差值
+ double dLon = lon2Rad - lon1Rad;
+ double dLat = lat2Rad - lat1Rad;
+
+ // 应用Haversine公式计算距离
+ double a = Math.pow(Math.sin(dLat / 2), 2) + Math.cos(lat1Rad) * Math.cos(lat2Rad) * Math.pow(Math.sin(dLon / 2), 2);
+ double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
+ double distance = earthRadius * c;
+
+ return distance;
+ }
+
+
+}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
new file mode 100644
index 0000000..096396c
--- /dev/null
+++ b/src/main/resources/application.properties
@@ -0,0 +1,10 @@
+spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&zeroDateTimeBehavior=convertToNull&autoReconnect=true&serverTimezone=UTC
+spring.datasource.username=root
+spring.datasource.password=123456
+spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
+
+spring.jpa.properties.hibernate.hbm2ddl.auto=update
+
+spring.devtools.restart.enabled=true
+
+spring.flyway.enabled=false
\ No newline at end of file
diff --git a/src/main/resources/db/migration/V0.1__create-user-and-followers.sql b/src/main/resources/db/migration/V0.1__create-user-and-followers.sql
new file mode 100644
index 0000000..8a8b820
--- /dev/null
+++ b/src/main/resources/db/migration/V0.1__create-user-and-followers.sql
@@ -0,0 +1,39 @@
+SET NAMES utf8mb4;
+SET FOREIGN_KEY_CHECKS = 0;
+
+-- ----------------------------
+-- Table structure for tbl_user
+-- ----------------------------
+DROP TABLE IF EXISTS `tbl_user`;
+CREATE TABLE `tbl_user` (
+ `id` int(0) NOT NULL,
+ `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
+ `dob` date NULL DEFAULT NULL,
+ `address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
+ `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
+ `created_at` date NULL DEFAULT NULL,
+ `latitude` double(10, 2) NULL DEFAULT NULL,
+ `longitude` double(10, 2) NULL DEFAULT NULL,
+ `follower_id` int(0) NULL DEFAULT NULL,
+ `user_id` int(0) NULL DEFAULT NULL,
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
+
+SET FOREIGN_KEY_CHECKS = 1;
+
+
+SET NAMES utf8mb4;
+SET FOREIGN_KEY_CHECKS = 0;
+
+-- ----------------------------
+-- Table structure for tbl_follower
+-- ----------------------------
+DROP TABLE IF EXISTS `tbl_follower`;
+CREATE TABLE `tbl_follower` (
+ `user_id` int(0) NULL DEFAULT NULL,
+ `follower_id` int(0) NULL DEFAULT NULL,
+ `id` int(0) NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
+
+SET FOREIGN_KEY_CHECKS = 1;
diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml
new file mode 100644
index 0000000..d532a5a
--- /dev/null
+++ b/src/main/resources/logback.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+ ${LOG_PATTERN}
+
+
+
+
+
+ logs/application.log
+
+ ${LOG_PATTERN}
+
+
+
+
+
+
+
+
+
+
diff --git a/src/test/java/FriendServiceTest.java b/src/test/java/FriendServiceTest.java
new file mode 100644
index 0000000..ab7b8c4
--- /dev/null
+++ b/src/test/java/FriendServiceTest.java
@@ -0,0 +1,5 @@
+public class FriendServiceTest {
+
+ //todo
+
+}
diff --git a/src/test/java/UserServiceTest.java b/src/test/java/UserServiceTest.java
new file mode 100644
index 0000000..2663b3d
--- /dev/null
+++ b/src/test/java/UserServiceTest.java
@@ -0,0 +1,64 @@
+import com.jiang.test.backend.entity.User;
+import com.jiang.test.backend.repository.UserRepository;
+import com.jiang.test.backend.service.impl.UserServiceImpl;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Date;
+import java.util.Optional;
+
+public class UserServiceTest {
+
+ @InjectMocks
+ private UserServiceImpl userService;
+
+ @Mock
+ private UserRepository userRepository;
+
+ User user;
+
+ @BeforeEach
+ public void setUp(){
+ MockitoAnnotations.initMocks(this);
+ user = User.builder()
+ .id(3)
+ .address("shenzhen")
+ .name("jiang")
+ .dob(new Date())
+ .description("test")
+ .createdAt(new Date())
+ .build();
+ }
+
+ @Test
+ public void testGetUser(){
+ Mockito.when(userRepository.findById(Mockito.any())).thenReturn(Optional.of(user));
+ Optional user1 = userService.getUserById(3);
+ Assertions.assertEquals(user,user1.get());
+ }
+
+ @Test
+ public void testAddUser(){
+ Mockito.when(userRepository.save(Mockito.any())).thenReturn(user);
+ User user1 = userService.addUser(user);
+ Assertions.assertEquals(3,user1.getId());
+ }
+
+ @Test
+ public void testUpdateUser(){
+ Mockito.when(userRepository.save(Mockito.any())).thenReturn(user);
+ User user1 = userService.updateUser(user);
+ Assertions.assertEquals(3,user1.getId());
+ }
+
+ @Test
+ public void testDelUser(){
+ Mockito.doNothing().when(userRepository).deleteById(3);
+ userService.deleteUserById(3);
+ }
+}