commit 1c32c61f2238a3a63058be3352cfdf3a71a91876 Author: merlin Date: Thu Oct 16 17:02:52 2025 +0800 feat: init commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..549e00a --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..a1457c8 --- /dev/null +++ b/pom.xml @@ -0,0 +1,193 @@ + + + 4.0.0 + + com.example + MyPlayer_server + 0.0.1-SNAPSHOT + MyPlayer_server + MyPlayer_server + + + 1.8 + UTF-8 + UTF-8 + 2.6.13 + + + + + + + + + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + com.alibaba + fastjson + 1.2.78 + + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + org.springframework.boot + spring-boot-configuration-processor + true + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.security + spring-security-test + test + + + ch.qos.logback + logback-classic + 1.2.11 + + + com.mysql + mysql-connector-j + 9.0.0 + + + org.jsoup + jsoup + 1.15.1 + + + com.baomidou + mybatis-plus-boot-starter + 3.5.7 + + + + junit + junit + 4.13.2 + test + + + com.alibaba + druid-spring-boot-starter + 1.2.22 + + + org.springframework.boot + spring-boot-starter-data-redis + + + io.lettuce + lettuce-core + + + + com.auth0 + java-jwt + 4.4.0 + + + com.aliyun.oss + aliyun-sdk-oss + 3.18.0 + + + commons-io + commons-io + 2.5 + + + commons-beanutils + commons-beanutils + 1.9.3 + + + org.springframework.boot + spring-boot-starter-websocket + + + org.springframework.boot + spring-boot-starter-mail + + + com.github.ben-manes.caffeine + caffeine + + + org.json + json + 20210307 + + + + + + + + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 1.8 + 1.8 + UTF-8 + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.version} + + + + repackage + + + + + + + + \ No newline at end of file diff --git a/src/main/java/myplayer/MyPlayerServerApplication.java b/src/main/java/myplayer/MyPlayerServerApplication.java new file mode 100644 index 0000000..ba2ca05 --- /dev/null +++ b/src/main/java/myplayer/MyPlayerServerApplication.java @@ -0,0 +1,14 @@ +package myplayer; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableScheduling; + +@SpringBootApplication +public class MyPlayerServerApplication { + + public static void main(String[] args) { + SpringApplication.run(MyPlayerServerApplication.class, args); + } + +} diff --git a/src/main/java/myplayer/config/CorsConfig.java b/src/main/java/myplayer/config/CorsConfig.java new file mode 100644 index 0000000..05945ad --- /dev/null +++ b/src/main/java/myplayer/config/CorsConfig.java @@ -0,0 +1,24 @@ +package myplayer.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.WebMvcConfigurer; + +@Configuration +public class CorsConfig { + + @Bean + public WebMvcConfigurer corsConfigurer() { + return new WebMvcConfigurer() { + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**") + .allowedOrigins("*") + .allowedMethods("GET","POST","PUT","DELETE","OPTIONS") + .allowedHeaders("*"); + + } + }; + } +} diff --git a/src/main/java/myplayer/config/Interceptor.java b/src/main/java/myplayer/config/Interceptor.java new file mode 100644 index 0000000..01e5a97 --- /dev/null +++ b/src/main/java/myplayer/config/Interceptor.java @@ -0,0 +1,27 @@ +package myplayer.config; + +import myplayer.utils.Jwt; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.HandlerInterceptor; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.Map; + +@Component +public class Interceptor implements HandlerInterceptor { + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + String token = request.getHeader("Authorization"); + //验证token + try { + Map claims = Jwt.parseToken(token); + //验证成功,放行 + return true; + } catch (Exception e) { + response.setStatus(401); + //验证失败,不放行 + return false; + } + } +} diff --git a/src/main/java/myplayer/config/MyBatisPlusConfig.java b/src/main/java/myplayer/config/MyBatisPlusConfig.java new file mode 100644 index 0000000..13b069b --- /dev/null +++ b/src/main/java/myplayer/config/MyBatisPlusConfig.java @@ -0,0 +1,17 @@ +package myplayer.config; + +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class MyBatisPlusConfig { + + @Bean + public MybatisPlusInterceptor mybatisPlusInterceptor() { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); + return interceptor; + } +} \ No newline at end of file diff --git a/src/main/java/myplayer/config/RedisConfig.java b/src/main/java/myplayer/config/RedisConfig.java new file mode 100644 index 0000000..eb1162a --- /dev/null +++ b/src/main/java/myplayer/config/RedisConfig.java @@ -0,0 +1,35 @@ +package myplayer.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.core.StringRedisTemplate; +import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.RedisSerializer; + +@Configuration +public class RedisConfig { + + //配置StringRedisTemplate,用于操作String类型的数据 + @Bean + public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) { + StringRedisTemplate template = new StringRedisTemplate(redisConnectionFactory); + template.setKeySerializer(RedisSerializer.string()); + template.setValueSerializer(RedisSerializer.string()); + return template; + } + + //配置RedisTemplate,用于操作更复杂的对象 + @Bean + public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { + RedisTemplate template = new RedisTemplate<>(); + template.setConnectionFactory(redisConnectionFactory); + template.setKeySerializer(RedisSerializer.string()); + template.setValueSerializer(new GenericJackson2JsonRedisSerializer()); //使用Jackson序列化器 + return template; + } + + +} diff --git a/src/main/java/myplayer/config/RequestConfig.java b/src/main/java/myplayer/config/RequestConfig.java new file mode 100644 index 0000000..879b763 --- /dev/null +++ b/src/main/java/myplayer/config/RequestConfig.java @@ -0,0 +1,25 @@ +package myplayer.config; + +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.WebMvcConfigurer; + + +@Configuration +public class RequestConfig implements WebMvcConfigurer { + @Autowired + private Interceptor logininterceptor; + + @Override + public void addInterceptors(InterceptorRegistry registry) { + //配置接口不拦截 + registry.addInterceptor(logininterceptor).excludePathPatterns( + "/register", + "/login", + "/test/hello", + "/chat", + "/code/sendcode", + "/code/verifycode"); + } +} diff --git a/src/main/java/myplayer/config/SecurityConfig.java b/src/main/java/myplayer/config/SecurityConfig.java new file mode 100644 index 0000000..ba4421c --- /dev/null +++ b/src/main/java/myplayer/config/SecurityConfig.java @@ -0,0 +1,4 @@ +package myplayer.config; + +public class SecurityConfig { +} diff --git a/src/main/java/myplayer/config/WebSocketHandshakeInterceptor.java b/src/main/java/myplayer/config/WebSocketHandshakeInterceptor.java new file mode 100644 index 0000000..2c92d63 --- /dev/null +++ b/src/main/java/myplayer/config/WebSocketHandshakeInterceptor.java @@ -0,0 +1,32 @@ +package myplayer.config; + +import org.springframework.http.server.ServerHttpRequest; +import org.springframework.http.server.ServerHttpResponse; +import org.springframework.http.server.ServletServerHttpRequest; +import org.springframework.web.socket.WebSocketHandler; +import org.springframework.web.socket.server.HandshakeInterceptor; + +import java.util.Map; + +// WebSocket握手拦截器 +public class WebSocketHandshakeInterceptor implements HandshakeInterceptor { + @Override + public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map attributes) throws Exception { + // 解析URL中的u_id参数 + if (request instanceof ServletServerHttpRequest) { + ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request; + String userId = servletRequest.getServletRequest().getParameter("u_id"); + String userName = servletRequest.getServletRequest().getParameter("u_name"); + if (userId != null && userName != null) { + attributes.put("u_id", userId); // 将u_id存储到Attributes中 + attributes.put("u_name", userName); // 将u_name存储到Attributes中 + } + } + return true; + } + + @Override + public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) { + // 可选:在连接建立后执行一些操作 + } +} diff --git a/src/main/java/myplayer/config/WebsocketConfig.java b/src/main/java/myplayer/config/WebsocketConfig.java new file mode 100644 index 0000000..286121a --- /dev/null +++ b/src/main/java/myplayer/config/WebsocketConfig.java @@ -0,0 +1,34 @@ +package myplayer.config; + + +import myplayer.utils.webRTC.WebRTCSignalHandler; +import myplayer.utils.websocket.OnlineStatus; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.socket.config.annotation.EnableWebSocket; +import org.springframework.web.socket.config.annotation.WebSocketConfigurer; +import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; + + +@Configuration +@EnableWebSocket +public class WebsocketConfig implements WebSocketConfigurer { + + + @Autowired + private OnlineStatus onlineStatusHandler; + + @Autowired + private WebRTCSignalHandler webRTCSignalHandler; + + @Override + public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { + registry.addHandler(onlineStatusHandler, "/online").setAllowedOrigins("*") + .addInterceptors(new WebSocketHandshakeInterceptor()); //注册online节点 + registry.addHandler(webRTCSignalHandler,"/voice").setAllowedOrigins("*") + .addInterceptors(new WebSocketHandshakeInterceptor()); + + } + + +} diff --git a/src/main/java/myplayer/controller/AvatarController.java b/src/main/java/myplayer/controller/AvatarController.java new file mode 100644 index 0000000..204ad81 --- /dev/null +++ b/src/main/java/myplayer/controller/AvatarController.java @@ -0,0 +1,68 @@ +package myplayer.controller; + +//import myplayer.service.UserInfoService; +//import myplayer.utils.AliyunOSS; +//import myplayer.utils.Jwt; +//import myplayer.utils.Result; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.web.bind.annotation.PostMapping; +//import org.springframework.web.bind.annotation.RequestHeader; +//import org.springframework.web.bind.annotation.RequestMapping; +//import org.springframework.web.bind.annotation.RestController; +//import org.springframework.web.multipart.MultipartFile; +// +//import java.io.IOException; +//import java.util.Map; +// +//@RestController +//@RequestMapping +//public class AvatarController { +// +// @Autowired +// UserInfoService userInfoService; +// +// @PostMapping("/uploadavatar") +// public Result uploadAvatar(@RequestHeader("Authorization") String token, MultipartFile avatar) throws IOException { +// try { +// Map map = Jwt.parseToken(token); +// String u_id = (String) map.get("u_id"); +// if(avatar==null) return Result.error("图片为空"); +// String oldProfile = userInfoService.getProfile(u_id); +// if(oldProfile!=null && !oldProfile.equals("https://for-ever.oss-cn-guangzhou.aliyuncs.com/myplayer/avatar.jpg")) AliyunOSS.deleteImage(oldProfile); +// String profile = AliyunOSS.uploadImage(avatar); +// if(userInfoService.updateProfile(u_id,profile)==1) +// return Result.success("上传成功!"); +// return Result.error("上传失败!"); +// } catch (IOException e) { +// return Result.error("上传失败!换张图片试试吧!"); +// } +// } +// +//} +import myplayer.service.AvatarService; +import myplayer.utils.Result; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; + +@RestController +@RequestMapping("/avatar") +public class AvatarController { + + @Autowired + private AvatarService avatarService; + + @PostMapping("/upload") + public Result uploadAvatar(@RequestParam("file") MultipartFile file, + @RequestParam("id") String Id) { + try { + String url = avatarService.storeAvatar(file, Id); + return Result.success("上传成功",url); + } catch (IOException e) { + System.out.println(e.getMessage()); + return Result.error("上传失败"); + } + } +} \ No newline at end of file diff --git a/src/main/java/myplayer/controller/FriendController.java b/src/main/java/myplayer/controller/FriendController.java new file mode 100644 index 0000000..910d7f9 --- /dev/null +++ b/src/main/java/myplayer/controller/FriendController.java @@ -0,0 +1,57 @@ +package myplayer.controller; + + +import myplayer.entity.Inviting; +import myplayer.entity.User; +import myplayer.service.FriendService; +import myplayer.service.InvitingService; +import myplayer.service.UserService; +import myplayer.utils.Jwt; +import myplayer.utils.Result; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("/friend") +public class FriendController { + + @Autowired + private UserService userService; + + @Autowired + private FriendService friendService; + + @GetMapping("/getfriends") + public Result getFriends(@RequestHeader("Authorization") String token){ + String u_id = Jwt.getU_id(token); + List Users = friendService.getFriends(u_id); + return Result.success("获取成功",Users); + + } + + + @GetMapping("/searchuser") + public Result search(@RequestHeader("Authorization") String token,@RequestParam String u_name){ + String u_id = Jwt.getU_id(token); + List users = userService.search(u_id,u_name); + + return Result.success("",users); + } + + @PostMapping("/deletefriend") + public Result deleteFriend(@RequestHeader("Authorization") String token,@RequestBody User user){ + String u_id = Jwt.getU_id(token); + String f_id= user.getU_id(); + friendService.removeFriend(u_id,f_id); + return Result.success("删除成功"); + } + + + + + + + +} diff --git a/src/main/java/myplayer/controller/GroupController.java b/src/main/java/myplayer/controller/GroupController.java new file mode 100644 index 0000000..7d18d86 --- /dev/null +++ b/src/main/java/myplayer/controller/GroupController.java @@ -0,0 +1,118 @@ +package myplayer.controller; + + +import myplayer.entity.Groupchat; +import myplayer.entity.Grouprelation; +import myplayer.service.GroupService; +import myplayer.utils.Jwt; +import myplayer.utils.RandomCode; +import myplayer.utils.Result; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDateTime; + + +@RestController +@RequestMapping("/group") +public class GroupController { + + @Autowired + private GroupService groupService; + + @PostMapping("/create") + public Result createGroup(@RequestHeader("Authorization") String token, @RequestBody Groupchat groupchat) { + String u_id = Jwt.getU_id(token); + String g_id; + do { + g_id = "G" + RandomCode.generateID(); + } while (groupService.groupIsExist(g_id) == 1); + + groupchat.setG_id(g_id); + + try { + groupService.createGroup(groupchat, u_id); + } catch (Exception e) { + System.out.println(LocalDateTime.now() + " " + e); + return Result.error(e.getMessage()); + } + + return Result.success("创建成功"); + } + + @GetMapping("/search") + public Result searchGroup(@RequestHeader("Authorization") String token, @RequestParam String g_name) { + String u_id = Jwt.getU_id(token); + + return Result.success("搜索到", groupService.searchGroups(u_id, g_name)); + + } + + @PostMapping("/joingroup") + public Result joingroup(@RequestHeader("Authorization") String token, @RequestBody Groupchat groupchat) { + String u_id = Jwt.getU_id(token); + groupService.joinGroup(u_id, groupchat.getG_id()); + return Result.success("加入成功"); + } + + @GetMapping("/getgroups") + public Result getGroups(@RequestHeader("Authorization") String token) { + String u_id = Jwt.getU_id(token); + return Result.success("获取成功", groupService.getGroups(u_id)); + } + + @GetMapping("/leave") + public Result leave(@RequestHeader("Authorization") String token, @RequestParam String g_id) { + String u_id = Jwt.getU_id(token); + groupService.leave(u_id, g_id); + return Result.success("离开成功"); + } + + @PostMapping("/setnote") + public Result setnote(@RequestHeader("Authorization") String token, @RequestBody Groupchat groupchat) { + String u_id = Jwt.getU_id(token); + if (groupService.setNote(u_id, groupchat)) { + return Result.success("设置成功"); + } else { + return Result.success("设置失败"); + } + } + + @PostMapping("/rmnote") + public Result rmnote(@RequestHeader("Authorization") String token, @RequestBody Groupchat groupchat) { + String u_id = Jwt.getU_id(token); + if (groupService.setNote(u_id, groupchat)) { + return Result.success("移除成功"); + } else { + return Result.success("移除失败"); + } + } + + @PostMapping("/setname") + public Result setname(@RequestBody Groupchat groupchat) { + groupService.setName(groupchat.getG_id(), groupchat.getG_name()); + return Result.success("修改成功"); + } + + @GetMapping("/getmember/{g_id}") + public Result getMember(@PathVariable String g_id) { + return Result.success("获取成功", groupService.getMembers(g_id)); + } + + @PostMapping("/setrole") + public Result setrole(@RequestHeader("Authorization") String token, @RequestBody Grouprelation grouprelation) { + String u_id = Jwt.getU_id(token); + if (groupService.setRole(u_id, grouprelation)) + return Result.success("设置成功"); + else + return Result.error("设置失败"); + } + + @PostMapping("/kick") + public Result kick(@RequestHeader("Authorization")String token , @RequestBody Grouprelation grouprelation) { + String u_id = Jwt.getU_id(token); + if(groupService.verifyRole(u_id,grouprelation.getG_id())==2) return Result.error("权限不足"); + groupService.leave(grouprelation.getU_id(),grouprelation.getG_id()); + return Result.success("踢出成功"); + } +} diff --git a/src/main/java/myplayer/controller/InvitingController.java b/src/main/java/myplayer/controller/InvitingController.java new file mode 100644 index 0000000..bb151a8 --- /dev/null +++ b/src/main/java/myplayer/controller/InvitingController.java @@ -0,0 +1,106 @@ +package myplayer.controller; + + +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; +import myplayer.entity.Inviting; +import myplayer.entity.Own; +import myplayer.service.FriendService; +import myplayer.service.InvitingService; +import myplayer.service.OwnService; +import myplayer.utils.Jwt; +import myplayer.utils.RandomCode; +import myplayer.utils.Result; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.concurrent.TimeUnit; + +@RestController +@RequestMapping("/inviting") +public class InvitingController { + + private static final Cache invitingCode = Caffeine.newBuilder() + .expireAfterWrite(5, TimeUnit.MINUTES) + .build(); + + + @Autowired + private InvitingService invitingService; + + @Autowired + private FriendService friendService; + + @Autowired + private OwnService ownService; + + + @PostMapping("/sendinviting") + public Result sendInvite(@RequestHeader("Authorization") String token, @RequestBody Inviting inviting) { + String u_id = Jwt.getU_id(token); + if(inviting.getRoom()==null){ + if(invitingService.sendInvite(u_id, inviting.getTarget(), null) == 0 ) + return Result.error("请勿重复发送"); + } + else{ + if (invitingService.sendInvite(u_id, inviting.getTarget(), inviting.getRoom()) == 0) + return Result.error("请勿重复发送"); + } + System.out.println(u_id + "------>" + inviting.getTarget()); + return Result.success("发送成功"); + + } + + @GetMapping("/getinvitings") + public Result getInvitings(@RequestHeader("Authorization") String token) { + String u_id = Jwt.getU_id(token); + return Result.success("获取成功", invitingService.getInvitings(u_id)); + } + + @GetMapping("/getinvitings/{r_id}") + public Result getJoinRequest(@PathVariable String r_id) { + return Result.success("success", invitingService.getJoinRequest(r_id)); + } + + @PostMapping("/passinviting") + public Result passInvite(@RequestBody Inviting inviting) { + if (inviting.getRoom() != null) { + invitingService.acceptInvite(inviting, inviting.getRoom()); + } else { + invitingService.acceptInvite(inviting); + friendService.addFriend(inviting.getInviter(), inviting.getTarget()); + } + return Result.success("接受成功"); + + } + + @PostMapping("/refuseinviting") + public Result refuseInvite(@RequestBody Inviting inviting) { + if (inviting.getRoom() != null) { + invitingService.refuseInvite(inviting, inviting.getRoom()); + } else { + invitingService.refuseInvite(inviting); + } + return Result.success("接受成功"); + } + + //房主或者管理员生成邀请码请求 供用户加入房间使用,简化加入房间的审核机制 + @PostMapping("/createinvitingcode") + public Result createInvitingCode(@RequestHeader("Authorization") String token, @RequestBody Own own) { + if (own.getRole() == 2) return Result.error("权限不足"); + String code = RandomCode.generateMassiveCode(); + invitingCode.put(code, own.getR_id()); + return Result.success("生成成功", code); + } + + //验证通过邀请码加入房间 + @PostMapping("/checkinvitingcode") + public Result checkInvitingCode(@RequestHeader("Authorization") String token, @RequestParam String code) { + String u_id = Jwt.getU_id(token); + String r_id = invitingCode.getIfPresent(code); + if (r_id == null) return Result.error("邀请码无效"); + ownService.joinRoom(u_id, r_id); + return Result.success("加入成功"); + } + +} diff --git a/src/main/java/myplayer/controller/LoginController.java b/src/main/java/myplayer/controller/LoginController.java new file mode 100644 index 0000000..431aec5 --- /dev/null +++ b/src/main/java/myplayer/controller/LoginController.java @@ -0,0 +1,106 @@ +package myplayer.controller; + + +import myplayer.entity.Account; +import myplayer.entity.User; +import myplayer.mapper.AccountMapper; +import myplayer.mapper.UserMapper; +import myplayer.service.AccountService; +import myplayer.service.UserService; +import myplayer.utils.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; + +import static myplayer.utils.Jwt.genToken; +import static myplayer.utils.Jwt.getU_id; + +@RestController +@RequestMapping +public class LoginController { + + @Autowired + private UserService userService; + + @Autowired + private AccountService accountService; + + @PostMapping("/register") + Result register(@RequestBody Account account) { + //服务器保护机制 + if(account.getU_account()==null || account.getU_password()==null) return Result.error("未输入账号和密码"); + if(accountService.isExist(account.getU_account())>=1) return Result.createError("注册失败,邮箱已被注册!"); + //确认u_id未重复 + String id; + int i=0;//超时tag + do{ + id = "U"+ RandomCode.generateID(); + i++; + if(i==20) break; + } + while(accountService.idIsExist(id)); + + //分配u_id:U+6位数字组合 + account.setU_id(id); + System.out.println(account.getU_id()); + + //对密码进行加密储存 + //account.setU_password(Md5.getMD5String(account.getU_password())); + account.setU_password(SHA256Util.encryptPasswordWithUserId(account.getU_password(), account.getU_id())); + + //写入表 + accountService.insert(account); + userService.initUser(account.getU_id()); + + return Result.success("注册成功!"); + } + + @PostMapping("/login") + Result login(@RequestBody Account account, @RequestHeader(value="X-Forwarded-For",defaultValue = "") String clientIP, HttpServletRequest request) { + //查询账号是否存在 + String u_account = account.getU_account(); + if(accountService.isExist(u_account)==0){ + return Result.accountError("账号不存在!"); + } + //加密密码并核对 + account.setU_id(accountService.getUId(u_account)); + if(!SHA256Util.encryptPasswordWithUserId(account.getU_password(), account.getU_id()) + .equals(accountService.verifyPassword(account.getU_account()))){ + return Result.accountError("密码错误"); + } + + //验证通过,生成jwt代码 + //设置jwt令牌 + Map claim = new HashMap<>(); + claim.put("u_id",account.getU_id()); + claim.put("u_account",account.getU_account()); + String token = genToken(claim); + if(clientIP==null||clientIP.isEmpty()){ + clientIP=request.getRemoteAddr(); + } + accountService.updateIP(account.getU_id(),clientIP); + System.out.println( LocalDateTime.now() +"login:"+u_account+" IP:"+clientIP); + + return Result.success("登录成功",token); + + + } + + @RequestMapping("/init") + Result initUser(@RequestBody User user,@RequestHeader(name="Authorization") String token) { + //解析token + Map claim = Jwt.parseToken(token); + String u_id = (String) claim.get("u_id"); + + //初始化用户信息,写入表 + userService.updateName(u_id,user.getU_name()); + userService.updateIntroduction(u_id,user.getU_introduction()); + + + return Result.success("初始化成功!"); + } +} diff --git a/src/main/java/myplayer/controller/MailCodeController.java b/src/main/java/myplayer/controller/MailCodeController.java new file mode 100644 index 0000000..13ad892 --- /dev/null +++ b/src/main/java/myplayer/controller/MailCodeController.java @@ -0,0 +1,61 @@ +package myplayer.controller; + + +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; +import myplayer.entity.Account; +import myplayer.entity.Code; +import myplayer.service.CodeManageService; +import myplayer.utils.RandomCode; +import myplayer.utils.Result; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.concurrent.TimeUnit; + +@RestController +@RequestMapping("/code") +public class MailCodeController { + + private static final Cache waitingList = Caffeine.newBuilder() + .expireAfterWrite(5, TimeUnit.MINUTES) + .build(); + + @Autowired + CodeManageService codeManageService; + + @PostMapping("/sendcode") + Result sendcode(@RequestBody Account account){ + if(account.getU_account()==null) return Result.error("邮箱为空"); + System.out.println(account); + String tempId; + do{ + tempId=RandomCode.generateID(); + } + while(waitingList.getIfPresent(tempId)!=null); + + try { + waitingList.put(tempId,codeManageService.sendMail(account.getU_account())); + return Result.success("发送成功!",tempId); + } catch (Exception e) { + return Result.serverError("发送失败"); + } + + } + + @PostMapping("/verifycode") + Result verifyCode(@RequestBody Code code){ + //测试验证码 + if(code.getCode().equals("666666")) return Result.success("验证成功"); + + String tempCode=waitingList.getIfPresent(code.getV_id()); + System.out.println("waitingList"+tempCode+"\nv_id:"+code.getV_id()+"\ncode:"+code.getCode()); + if(tempCode==null) return Result.timeout("验证码已过期"); + if(!tempCode.equals(code.getCode())) return Result.codeError("验证码错误!"); + waitingList.invalidate(code.getV_id()); + + return Result.success("验证成功"); + + } + +} diff --git a/src/main/java/myplayer/controller/PlayroomController.java b/src/main/java/myplayer/controller/PlayroomController.java new file mode 100644 index 0000000..c2b9748 --- /dev/null +++ b/src/main/java/myplayer/controller/PlayroomController.java @@ -0,0 +1,70 @@ +package myplayer.controller; + + +import myplayer.entity.Own; +import myplayer.entity.Playroom; +import myplayer.service.OwnService; +import myplayer.service.PlayroomService; +import myplayer.utils.Jwt; +import myplayer.utils.RandomCode; +import myplayer.utils.Result; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + + +@RestController +@RequestMapping("/room") +public class PlayroomController { + + @Autowired + private PlayroomService playroomService; + + @Autowired + private OwnService ownService; + + // 创建房间 + @PostMapping("/create") + public Result createRoom(@RequestHeader("Authorization") String token, @RequestBody Playroom playroom) { + String u_id = Jwt.getU_id(token); + String r_id; + + do { + r_id = "R" + RandomCode.generateID(); + } while (playroomService.playRoomIsExist(r_id) == 1); + + playroom.setR_id(r_id); + Own own = new Own(r_id, u_id, 0); + + playroomService.createPlayroom(playroom); + + ownService.createPlayroom(own); + + return Result.success("创建成功"); + + } + + //搜索房间 + @GetMapping("/search") + public Result searchPlayroom(@RequestHeader("Authorization") String token,@RequestParam String r_name){ + String u_id = Jwt.getU_id(token); + return Result.success("查询成功",playroomService.searchPlayroom(u_id,r_name)); + } + + //获取已加入列表 + @GetMapping("/getrooms") + public Result getRooms(@RequestHeader("Authorization") String token){ + String u_id = Jwt.getU_id(token); + return Result.success("查询成功",playroomService.getRooms(u_id)); + } + + //获取房间成员 + @GetMapping("/getmember") + public Result getMembers(@RequestParam String r_id){ + return Result.success("查询成功",playroomService.getMembers(r_id)); + } + + //获取对应房间信息 + + //修改对应房间信息 + +} diff --git a/src/main/java/myplayer/controller/TestController.java b/src/main/java/myplayer/controller/TestController.java new file mode 100644 index 0000000..8157abc --- /dev/null +++ b/src/main/java/myplayer/controller/TestController.java @@ -0,0 +1,36 @@ +package myplayer.controller; + + +import myplayer.service.CodeManageService; +import myplayer.utils.Result; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.Map; + +@RestController +@RequestMapping("/test") +public class TestController { + + @Autowired + private CodeManageService codeManageService; + + private Map codeMap = new HashMap<>(); + + @GetMapping("/hello") + public Result hello(){ + return Result.success("hello"); + } + @PostMapping("/send") + public Result send(){ + codeMap.put(1,codeManageService.sendMail("xyf17818039334@163.com")); + return Result.success("1"); + } + @PostMapping("/verifycode") + public Result verifycode(@RequestBody myplayer.entity.test.Test test){ + if(codeMap.get(1).equals(test.getCode())) + return Result.success("1"); + return Result.error("X"); + } +} diff --git a/src/main/java/myplayer/controller/UserController.java b/src/main/java/myplayer/controller/UserController.java new file mode 100644 index 0000000..99e6c64 --- /dev/null +++ b/src/main/java/myplayer/controller/UserController.java @@ -0,0 +1,86 @@ +package myplayer.controller; + + +import myplayer.entity.Account; +import myplayer.entity.User; +import myplayer.mapper.AccountMapper; +import myplayer.service.AccountService; +import myplayer.service.UserService; +import myplayer.utils.Jwt; +import myplayer.utils.Md5; +import myplayer.utils.Result; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + + +@RestController +@RequestMapping("/user") +public class UserController { + + @Autowired + private UserService userService; + + @Autowired + private AccountService accountService; + + @Autowired + private AccountMapper accountMapper; + + @GetMapping("/getuserinfo") + Result getUserInfo(@RequestHeader(name = "Authorization") String token) { + String u_id = Jwt.getU_id(token); + User user; + try { + user = userService.getUserInfo(u_id); + } catch (Exception e) { + return Result.error("获取用户信息失败"); + } + if (user == null) { + return Result.error("获取用户信息失败,用户不存在"); + } + System.out.println("获取用户信息:" + u_id); + return Result.success("获取用户信息成功", user); + } + + @PostMapping("/updatename") + Result updateName(@RequestHeader(name = "Authorization") String token, @RequestBody User user) { + String u_id = Jwt.getU_id(token); + try { + userService.updateName(u_id, user.getU_name()); + } catch (Exception e) { + return Result.error("修改用户名失败"); + } + System.out.println("用户名修改:" + u_id); + return Result.success("修改用户名成功"); + } + + @PostMapping("/updateintroduction") + Result updateIntroduction(@RequestHeader(name = "Authorization") String token, @RequestBody User user) { + String u_id = Jwt.getU_id(token); + userService.updateIntroduction(u_id, user.getU_introduction()); + return Result.success("修改用户简介成功"); + } + + @PostMapping("/updateaccount") + Result updateAccount(@RequestHeader(name = "Authorization") String token, @RequestBody Account account) { + String u_id = Jwt.getU_id(token); + accountService.updateAccount(u_id, account.getU_account()); + return Result.success("修改用户账号成功"); + } + + @PostMapping("/updatepassword") + Result updatePassword(@RequestHeader(name = "Authorization") String token, String oldpassword, String password) { + String account = Jwt.getAccount(token); + System.out.println(account); + + if (!Md5.checkPassword(oldpassword,accountService.verifyPassword(account))) { + System.out.println(Md5.checkPassword(oldpassword,accountService.verifyPassword(account))); + return Result.error("修改用户密码失败,原密码错误"); + } + accountService.updatePassword(account, Md5.getMD5String(password)); + + return Result.success("修改用户密码成功"); + } + + +} diff --git a/src/main/java/myplayer/entity/Account.java b/src/main/java/myplayer/entity/Account.java new file mode 100644 index 0000000..5997367 --- /dev/null +++ b/src/main/java/myplayer/entity/Account.java @@ -0,0 +1,19 @@ +package myplayer.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +@Data +@TableName("account") +public class Account { + @TableId("u_id") + private String u_id; + + private String u_account; + + private String u_password; + + private String ip; +} diff --git a/src/main/java/myplayer/entity/Code.java b/src/main/java/myplayer/entity/Code.java new file mode 100644 index 0000000..0de3171 --- /dev/null +++ b/src/main/java/myplayer/entity/Code.java @@ -0,0 +1,9 @@ +package myplayer.entity; + +import lombok.Data; + +@Data +public class Code { + private String v_id; + private String code; +} diff --git a/src/main/java/myplayer/entity/Friend.java b/src/main/java/myplayer/entity/Friend.java new file mode 100644 index 0000000..d1baa7f --- /dev/null +++ b/src/main/java/myplayer/entity/Friend.java @@ -0,0 +1,21 @@ +package myplayer.entity; + + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +@Data +@TableName("friends") +public class Friend { + @TableId("u_id") + private String u_id; + + private String f_id; + + + public Friend(String u_id, String f_id) { + this.u_id = u_id; + this.f_id = f_id; + } +} diff --git a/src/main/java/myplayer/entity/Groupchat.java b/src/main/java/myplayer/entity/Groupchat.java new file mode 100644 index 0000000..cb96659 --- /dev/null +++ b/src/main/java/myplayer/entity/Groupchat.java @@ -0,0 +1,19 @@ +package myplayer.entity; + + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +@Data +@TableName("groupchat") +public class Groupchat { + + @TableId("g_id") + private String g_id; + private String g_name; + private String g_avatar; + private String g_note; + private Integer identify; + +} diff --git a/src/main/java/myplayer/entity/Grouprelation.java b/src/main/java/myplayer/entity/Grouprelation.java new file mode 100644 index 0000000..e75b3b8 --- /dev/null +++ b/src/main/java/myplayer/entity/Grouprelation.java @@ -0,0 +1,22 @@ +package myplayer.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +@Data +@TableName("grouprelation") +public class Grouprelation { + @TableId("g_id") + private String g_id; + private String u_id; + private Integer role; + + + + public Grouprelation(String g_id, String u_id, Integer role) { + this.g_id = g_id; + this.u_id = u_id; + this.role = role; + } +} diff --git a/src/main/java/myplayer/entity/Inviting.java b/src/main/java/myplayer/entity/Inviting.java new file mode 100644 index 0000000..bb2785c --- /dev/null +++ b/src/main/java/myplayer/entity/Inviting.java @@ -0,0 +1,21 @@ +package myplayer.entity; + + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +@TableName("inviting") +public class Inviting { + private int inviting_id; + @TableId("inviter") + private String inviter; + + private String target; + private String room; + private LocalDateTime time; + private int status; +} diff --git a/src/main/java/myplayer/entity/Own.java b/src/main/java/myplayer/entity/Own.java new file mode 100644 index 0000000..e3a1c78 --- /dev/null +++ b/src/main/java/myplayer/entity/Own.java @@ -0,0 +1,21 @@ +package myplayer.entity; + + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +@Data +@TableName("own") +public class Own { + @TableId("r_id") + private String r_id; + private String u_id; + private Integer role; //0:owner 1:manager 2:member + + public Own(String r_id, String u_id, Integer role) { + this.r_id = r_id; + this.u_id = u_id; + this.role = role; + } +} diff --git a/src/main/java/myplayer/entity/Playroom.java b/src/main/java/myplayer/entity/Playroom.java new file mode 100644 index 0000000..165dc0e --- /dev/null +++ b/src/main/java/myplayer/entity/Playroom.java @@ -0,0 +1,17 @@ +package myplayer.entity; + + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +@Data +@TableName("playrooms") +public class Playroom { + @TableId("r_id") + private String r_id; + private String r_name;//房间名 + private String r_avatar; + private String r_introduction; + +} diff --git a/src/main/java/myplayer/entity/User.java b/src/main/java/myplayer/entity/User.java new file mode 100644 index 0000000..110dafe --- /dev/null +++ b/src/main/java/myplayer/entity/User.java @@ -0,0 +1,20 @@ +package myplayer.entity; + + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +@Data +@TableName("user") +public class User { + @TableId("u_id") + private String u_id; + + private String u_name; + + private String u_introduction; + + private String u_avatar; + +} diff --git a/src/main/java/myplayer/entity/request/InvitingDetails.java b/src/main/java/myplayer/entity/request/InvitingDetails.java new file mode 100644 index 0000000..62c3b7f --- /dev/null +++ b/src/main/java/myplayer/entity/request/InvitingDetails.java @@ -0,0 +1,23 @@ +package myplayer.entity.request; + +import lombok.Data; +import myplayer.entity.Inviting; + +import java.time.LocalDateTime; + +@Data +public class InvitingDetails { + private String inviter_name; + private String inviter_avatar; + private String inviter; + private String room; + private LocalDateTime time; + + public InvitingDetails(Inviting inviting,String inviter_name, String inviter_avatar) { + this.inviter_name = inviter_name; + this.inviter_avatar = inviter_avatar; + this.inviter = inviting.getInviter(); + this.room = inviting.getRoom(); + this.time = inviting.getTime(); + } +} diff --git a/src/main/java/myplayer/entity/request/Member.java b/src/main/java/myplayer/entity/request/Member.java new file mode 100644 index 0000000..a6b42a6 --- /dev/null +++ b/src/main/java/myplayer/entity/request/Member.java @@ -0,0 +1,28 @@ +package myplayer.entity.request; + + +import lombok.Data; +import myplayer.entity.User; + +@Data +public class Member { + + private String m_id; + + private String m_name; + + private String m_avatar; + + private String m_introduction; + + private Integer role; + + public Member(User user, Integer role) { + this.m_id = user.getU_id(); + this.m_name = user.getU_name(); + this.m_avatar = user.getU_avatar(); + this.m_introduction = user.getU_introduction(); + this.role = role; + } + +} diff --git a/src/main/java/myplayer/entity/request/PlayroomDetails.java b/src/main/java/myplayer/entity/request/PlayroomDetails.java new file mode 100644 index 0000000..504a2c1 --- /dev/null +++ b/src/main/java/myplayer/entity/request/PlayroomDetails.java @@ -0,0 +1,12 @@ +package myplayer.entity.request; + +import lombok.Data; + +@Data +public class PlayroomDetails{ + private String r_id; + private String r_name;//房间名 + private String r_avatar; + private String r_introduction; + private Integer role; +} diff --git a/src/main/java/myplayer/entity/test/Test.java b/src/main/java/myplayer/entity/test/Test.java new file mode 100644 index 0000000..bd91a9c --- /dev/null +++ b/src/main/java/myplayer/entity/test/Test.java @@ -0,0 +1,10 @@ +package myplayer.entity.test; + + +import lombok.Data; + +@Data +public class Test { + private String code; + +} diff --git a/src/main/java/myplayer/mapper/AccountMapper.java b/src/main/java/myplayer/mapper/AccountMapper.java new file mode 100644 index 0000000..74b01f8 --- /dev/null +++ b/src/main/java/myplayer/mapper/AccountMapper.java @@ -0,0 +1,31 @@ +package myplayer.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import myplayer.entity.Account; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; +import org.apache.ibatis.annotations.Update; + + +@Mapper +public interface AccountMapper extends BaseMapper { + + @Select("select count(*) from account where u_account=#{u_account}") + int isExist(@Param("u_account") String u_account); + + @Select("select account.u_password from account where u_account=#{u_account}") + String verifyPassword(String u_account); + + @Select("select account.u_id from account where u_account = #{u_account}") + String getUId(@Param("u_account") String u_account); + + @Update("update account set u_account=#{u_account} where u_id=#{u_id}") + void updateAccount(@Param("u_id") String u_id,@Param("u_account") String u_account); + + @Update("update account set u_password=#{u_password} where u_account=#{u_account}") + void updatePassword(@Param("u_account") String u_account,@Param("u_password") String u_password); + + @Update("update account set ip=#{clientIP} where u_id=#{u_id}") + void updateIp(@Param("u_id") String u_id,@Param("clientIP") String clientIP); +} diff --git a/src/main/java/myplayer/mapper/FriendMapper.java b/src/main/java/myplayer/mapper/FriendMapper.java new file mode 100644 index 0000000..0f39bab --- /dev/null +++ b/src/main/java/myplayer/mapper/FriendMapper.java @@ -0,0 +1,13 @@ +package myplayer.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import myplayer.entity.Friend; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface FriendMapper extends BaseMapper { + + + + +} diff --git a/src/main/java/myplayer/mapper/GroupMapper.java b/src/main/java/myplayer/mapper/GroupMapper.java new file mode 100644 index 0000000..9613f6f --- /dev/null +++ b/src/main/java/myplayer/mapper/GroupMapper.java @@ -0,0 +1,22 @@ +package myplayer.mapper; + + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import myplayer.entity.Groupchat; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; +import org.apache.ibatis.annotations.Update; + +@Mapper +public interface GroupMapper extends BaseMapper { + + @Select("select count(*) from groupchat where g_id = #{g_id}") + public int groupIsExist(@Param("g_id")String g_id); + + @Update("update groupchat set g_note = #{g_note} where g_id = #{g_id}") + void setNote(@Param("g_id")String g_id, @Param("g_note") String g_note); + + @Update("update groupchat set g_name = #{g_name} where g_id = #{g_id}") + void setName(@Param("g_id") String gId,@Param("g_name") String gName); +} diff --git a/src/main/java/myplayer/mapper/GrouprelationMapper.java b/src/main/java/myplayer/mapper/GrouprelationMapper.java new file mode 100644 index 0000000..2aac5cd --- /dev/null +++ b/src/main/java/myplayer/mapper/GrouprelationMapper.java @@ -0,0 +1,18 @@ +package myplayer.mapper; + + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import myplayer.entity.Grouprelation; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +@Mapper +public interface GrouprelationMapper extends BaseMapper { + + + @Select("select role from grouprelation where g_id=#{g_id} and u_id=#{u_id}") + public Integer getRole(@Param("u_id")String u_id, @Param("g_id")String g_id); + + +} diff --git a/src/main/java/myplayer/mapper/InvitingMapper.java b/src/main/java/myplayer/mapper/InvitingMapper.java new file mode 100644 index 0000000..678ab9a --- /dev/null +++ b/src/main/java/myplayer/mapper/InvitingMapper.java @@ -0,0 +1,11 @@ +package myplayer.mapper; + + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import myplayer.entity.Inviting; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface InvitingMapper extends BaseMapper { + +} diff --git a/src/main/java/myplayer/mapper/OwnMapper.java b/src/main/java/myplayer/mapper/OwnMapper.java new file mode 100644 index 0000000..40c70b5 --- /dev/null +++ b/src/main/java/myplayer/mapper/OwnMapper.java @@ -0,0 +1,9 @@ +package myplayer.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import myplayer.entity.Own; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface OwnMapper extends BaseMapper { +} diff --git a/src/main/java/myplayer/mapper/PlayroomMapper.java b/src/main/java/myplayer/mapper/PlayroomMapper.java new file mode 100644 index 0000000..ab95d6e --- /dev/null +++ b/src/main/java/myplayer/mapper/PlayroomMapper.java @@ -0,0 +1,14 @@ +package myplayer.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import myplayer.entity.Playroom; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +@Mapper +public interface PlayroomMapper extends BaseMapper { + + @Select("select count(*) from playrooms where r_id=#{r_id}") + public int playeroomIsExist(@Param("r_id") String r_id); +} diff --git a/src/main/java/myplayer/mapper/UserMapper.java b/src/main/java/myplayer/mapper/UserMapper.java new file mode 100644 index 0000000..e4b13e6 --- /dev/null +++ b/src/main/java/myplayer/mapper/UserMapper.java @@ -0,0 +1,24 @@ +package myplayer.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import myplayer.entity.User; +import org.apache.ibatis.annotations.*; + +@Mapper +public interface UserMapper extends BaseMapper { + + @Insert("insert into user(u_id) values (#{u_id})") + void initUser(@Param("u_id") String u_id); + + @Select("select u_avatar from user where u_id = #{u_id}") + String getUserAvatar(@Param("u_id") String u_id); + + @Update("update user set u_avatar = #{u_avatar} where u_id=#{u_id}") + int updateAvatar(@Param("u_id") String u_id, @Param("u_avatar") String u_avatar); + + @Update("update user set u_name=#{u_name} where u_id=#{u_id}") + void updateName(@Param("u_id") String u_id,@Param("u_name") String u_name); + + @Update("update user set u_introduction=#{u_introduction} where u_id=#{u_id}") + void updateIntroduction(@Param("u_id") String u_id,@Param("u_introduction") String u_introduction); +} diff --git a/src/main/java/myplayer/service/AccountService.java b/src/main/java/myplayer/service/AccountService.java new file mode 100644 index 0000000..e7a99fb --- /dev/null +++ b/src/main/java/myplayer/service/AccountService.java @@ -0,0 +1,49 @@ +package myplayer.service; + + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import myplayer.entity.Account; +import myplayer.mapper.AccountMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class AccountService { + + @Autowired + private AccountMapper accountMapper; + + public void updateAccount(String uId, String uAccount) { + accountMapper.updateAccount(uId, uAccount); + } + + public void updatePassword(String account, String password) { + accountMapper.updatePassword(account, password); + } + + public String verifyPassword(String account) { + return accountMapper.verifyPassword(account); + } + + public int isExist(String uAccount) { + return accountMapper.isExist(uAccount); + } + + public void insert(Account account) { + accountMapper.insert(account); + } + + public String getUId(String uAccount) { + return accountMapper.getUId(uAccount); + } + + public Boolean idIsExist(String uId) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("u_id", uId); + //找到了返回true,没找到返回false + return accountMapper.selectCount(queryWrapper) != 0; + } + public void updateIP(String u_id,String clientIP){ + accountMapper.updateIp(u_id,clientIP); + } +} diff --git a/src/main/java/myplayer/service/AvatarService.java b/src/main/java/myplayer/service/AvatarService.java new file mode 100644 index 0000000..26acf61 --- /dev/null +++ b/src/main/java/myplayer/service/AvatarService.java @@ -0,0 +1,52 @@ +package myplayer.service; + +import myplayer.mapper.UserMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.Arrays; +import java.util.List; + +@Service +public class AvatarService { + + @Autowired + private UserMapper userMapper; + + @Value("${file.avatar-dir}") + private String avatarDir; + + // 允许的文件类型 + private static final List ALLOWED_EXTENSIONS = Arrays.asList(".jpg", ".jpeg", ".png", ".gif"); + + public String storeAvatar(MultipartFile file, String Id) throws IOException { + File dir = new File(avatarDir); + if (!dir.exists()) dir.mkdirs(); + + // 取文件扩展名并检查是否合法 + String originalFileName = file.getOriginalFilename(); + String fileExtension = ""; + if (originalFileName != null && originalFileName.contains(".")) { + fileExtension = originalFileName.substring(originalFileName.lastIndexOf(".")).toLowerCase(); + } + + if (!ALLOWED_EXTENSIONS.contains(fileExtension)) { + throw new IOException("仅支持 JPG, PNG, GIF 格式"); + } + + // 以 UID 命名文件 + String fileName = Id + fileExtension; + Path targetPath = Paths.get(avatarDir, fileName); + Files.copy(file.getInputStream(), targetPath, StandardCopyOption.REPLACE_EXISTING); + userMapper.updateAvatar(Id, "https://www.merlin.xin/avatars/" + fileName); + return "/avatars/" + fileName; // 返回访问 URL + } +} \ No newline at end of file diff --git a/src/main/java/myplayer/service/CodeManageService.java b/src/main/java/myplayer/service/CodeManageService.java new file mode 100644 index 0000000..711dc36 --- /dev/null +++ b/src/main/java/myplayer/service/CodeManageService.java @@ -0,0 +1,29 @@ +package myplayer.service; + + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.mail.SimpleMailMessage; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.stereotype.Service; + +@Service +public class CodeManageService { + + @Autowired + JavaMailSender mailSender; + + @Value("${spring.mail.username}") + private String sender; + + public String sendMail(String receiver){ + String code = Double.toString(Math.random()).substring(2,8); + SimpleMailMessage message = new SimpleMailMessage(); + message.setFrom(sender); + message.setTo(receiver); + message.setSubject("MyPlayer"); + message.setText("欢迎使用MyPlayer!\n"+"您的验证码为:"+code+"\n验证码请勿泄露!"); + mailSender.send(message); + return code; + } +} diff --git a/src/main/java/myplayer/service/FriendService.java b/src/main/java/myplayer/service/FriendService.java new file mode 100644 index 0000000..c128411 --- /dev/null +++ b/src/main/java/myplayer/service/FriendService.java @@ -0,0 +1,62 @@ +package myplayer.service; + + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import myplayer.entity.Friend; +import myplayer.entity.User; +import myplayer.mapper.FriendMapper; +import myplayer.mapper.UserMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Set; + +@Service +public class FriendService { + + private final String DB = "myplayer:"; + + @Autowired + private StringRedisTemplate stringRedisTemplate; + + @Autowired + private FriendMapper friendMapper; + + @Autowired + private UserMapper userMapper; + + + //添加好友 + public void addFriend(String userId, String friendId) { + stringRedisTemplate.opsForSet().add(DB+"user:"+userId+":friends", friendId); + stringRedisTemplate.opsForSet().add(DB+"user:"+friendId+":friends", userId); + System.out.println("redis saved"); + friendMapper.insert(new Friend(userId, friendId)); + friendMapper.insert(new Friend(friendId, userId)); + } + + //删除好友 + public void removeFriend(String userId, String friendId) { + stringRedisTemplate.opsForSet().remove(DB+"user:"+userId+":friends", friendId); + stringRedisTemplate.opsForSet().remove(DB+"user:"+friendId+":friends", userId); + System.out.println("redis removed"); + friendMapper.deleteById(new Friend(userId, friendId)); + friendMapper.deleteById(new Friend(friendId, userId)); + } + + + //获取好友列表 + public List getFriends(String userId) { + Set f_ids = stringRedisTemplate.opsForSet().members(DB+"user:"+userId+":friends"); + if (f_ids != null && f_ids.isEmpty()) { + System.out.println("无好友"); + return null; + } + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.in("u_id", f_ids); + return userMapper.selectList(queryWrapper); + } + +} diff --git a/src/main/java/myplayer/service/GroupService.java b/src/main/java/myplayer/service/GroupService.java new file mode 100644 index 0000000..1becad8 --- /dev/null +++ b/src/main/java/myplayer/service/GroupService.java @@ -0,0 +1,155 @@ +package myplayer.service; + + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import myplayer.entity.Groupchat; +import myplayer.entity.Grouprelation; +import myplayer.entity.User; +import myplayer.entity.request.Member; +import myplayer.mapper.GroupMapper; +import myplayer.mapper.GrouprelationMapper; +import myplayer.mapper.UserMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Service +public class GroupService { + + private final String DB = "myplayer:"; + + @Autowired + private GroupMapper groupMapper; + + @Autowired + private GrouprelationMapper grouprelationMapper; + + @Autowired + private StringRedisTemplate stringRedisTemplate; + + @Autowired + private UserMapper userMapper; + + public int groupIsExist(String gId) { + return groupMapper.groupIsExist(gId); + } + + @Transactional + public void createGroup(Groupchat groupchat, String uId) { + groupMapper.insert(groupchat); + grouprelationMapper.insert(new Grouprelation(groupchat.getG_id(), uId, 0)); + + stringRedisTemplate.opsForSet().add(DB+groupchat.getG_id(), uId); + + } + + public List searchGroups(String uId, String gName) { + QueryWrapper qw1 = new QueryWrapper<>(); + qw1.select("g_id") + .eq("u_id", uId); + List allreadyin = grouprelationMapper.selectObjs(qw1); + QueryWrapper qw2 = new QueryWrapper<>(); + if (!allreadyin.isEmpty()) { + qw2.notIn("g_id", allreadyin) + .like("g_name", gName) + .last("limit 5"); + } else { + System.out.println("无已加入群聊,无需排除"); + qw2.like("g_name", gName) + .last("limit 5"); + } + return groupMapper.selectList(qw2); + } + + @Transactional + public void joinGroup(String uId, String gId) { + grouprelationMapper.insert(new Grouprelation(gId, uId, 2)); + + stringRedisTemplate.opsForSet().add(DB+gId, uId); + } + + public List getGroups(String uId) { + QueryWrapper qw1 = new QueryWrapper<>(); + qw1.select("g_id").eq("u_id", uId); + List allreadyin = grouprelationMapper.selectObjs(qw1); + QueryWrapper qw2 = new QueryWrapper<>(); + if (!allreadyin.isEmpty()) { + qw2.in("g_id", allreadyin); + return groupMapper.selectList(qw2); + } else { + System.out.println(LocalDateTime.now() + " 无已加入群聊,返回null"); + return null; + } + } + + @Transactional + public void leave(String uId, String gId) { + QueryWrapper qw1 = new QueryWrapper<>(); + qw1.eq("g_id", gId).eq("u_id", uId); + grouprelationMapper.delete(qw1); + stringRedisTemplate.opsForSet().remove(DB+gId, uId); + } + + public boolean setNote(String uId, Groupchat groupchat) { + //判断权限 + Integer role = grouprelationMapper.getRole(uId, groupchat.getG_id()); + if (role != 0 && role != 1) return false; + if (groupchat.getG_note() == null) groupMapper.setNote(groupchat.getG_id(), null); + groupMapper.setNote(groupchat.getG_id(), groupchat.getG_note()); + return true; + + } + + public void setName(String g_id, String g_name) { + groupMapper.setName(g_id, g_name); + } + + public List getMembers(String gId) { + QueryWrapper qw1 = new QueryWrapper<>(); + qw1.eq("g_id", gId); + List grouprelations = grouprelationMapper.selectList(qw1); + Map roles = new HashMap<>(); + List ids = new ArrayList<>(); + for (Grouprelation g : grouprelations) { + roles.put(g.getU_id(), g.getRole()); + ids.add(g.getU_id()); + } + QueryWrapper qw2 = new QueryWrapper<>(); + qw2.in("u_id", ids); + List users = userMapper.selectList(qw2); + List members = new ArrayList<>(); + for (User u : users) { + members.add(new Member(u, roles.get(u.getU_id()))); + } + return members; + } + + public boolean setRole(String uId, Grouprelation grouprelation) { + //判断权限 + Integer role = grouprelationMapper.getRole(uId, grouprelation.getG_id()); + if (role != 0) return false; + //判断数量 + if(grouprelation.getRole()==1){ + QueryWrapper qw1 = new QueryWrapper<>(); + qw1.eq("g_id", grouprelation.getG_id()) + .eq("role",1); + if(grouprelationMapper.selectCount(qw1)>=4) return false; + } + grouprelationMapper.update(grouprelation, new UpdateWrapper() + .eq("g_id",grouprelation.getG_id()) + .eq("u_id",grouprelation.getU_id())); + return true; + } + + public int verifyRole(String uId, String gId) { + return grouprelationMapper.getRole(uId, gId); + } +} diff --git a/src/main/java/myplayer/service/InvitingService.java b/src/main/java/myplayer/service/InvitingService.java new file mode 100644 index 0000000..0b7e308 --- /dev/null +++ b/src/main/java/myplayer/service/InvitingService.java @@ -0,0 +1,142 @@ +package myplayer.service; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import myplayer.entity.Inviting; +import myplayer.entity.User; +import myplayer.entity.request.InvitingDetails; +import myplayer.mapper.InvitingMapper; +import myplayer.mapper.UserMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.*; + +@Service +public class InvitingService { + + @Autowired + private InvitingMapper invitingMapper; + + @Autowired + private UserMapper userMapper; + + + public int sendInvite(String u_id, String f_id, String room) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("inviter", u_id).eq("target", f_id).eq("status",0); + if (room == null) queryWrapper.isNull("room"); + else queryWrapper.eq("room", room); + if (!invitingMapper.selectList(queryWrapper).isEmpty()) + //非空返回0 + return 0; + Inviting inviting = new Inviting(); + inviting.setInviter(u_id); + inviting.setTarget(f_id); + inviting.setTime(LocalDateTime.now()); + inviting.setStatus(0); + if (room != null) inviting.setRoom(room); + invitingMapper.insert(inviting); + return 1; + } + + public List getInvitings(String uId) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("target", uId); + queryWrapper.eq("status", 0) + .orderByAsc("time") + .apply("inviter <> target"); + //inviting 所有邀请的查询结果 + List invitings = invitingMapper.selectList(queryWrapper); + //inviter_ids 所有邀请者的id + Set inviter_ids = new HashSet<>(); + for (Inviting i : invitings) { + inviter_ids.add(i.getInviter()); + } + if(inviter_ids.isEmpty()) return null; + QueryWrapper queryWrapper1 = new QueryWrapper<>(); + queryWrapper1.in("u_id", inviter_ids); + List users = userMapper.selectList(queryWrapper1); + Map userMap = new HashMap<>(); + for(User u : users) { + userMap.put(u.getU_id(), u); + } + + List requestResult = new ArrayList<>(); + for (Inviting i : invitings) { + requestResult.add(new InvitingDetails + (i, userMap.get(i.getInviter()).getU_name(), userMap.get(i.getInviter()).getU_avatar())); + } + return requestResult; + } + + public void acceptInvite(Inviting inviting) { + UpdateWrapper updateWrapper = new UpdateWrapper<>(); + updateWrapper.set("status", 1) + .eq("inviter", inviting.getInviter()) + .eq("target", inviting.getTarget()) + .eq("status", 0); + invitingMapper.update(updateWrapper); + + } + + public void acceptInvite(Inviting inviting, String room) { + UpdateWrapper updateWrapper = new UpdateWrapper<>(); + updateWrapper.set("status", 1) + .eq("inviter", inviting.getInviter()) + .eq("target", inviting.getTarget()) + .eq("status", 0) + .eq("room", room); + invitingMapper.update(updateWrapper); + } + + public void refuseInvite(Inviting inviting) { + UpdateWrapper updateWrapper = new UpdateWrapper<>(); + updateWrapper.set("status", 2) + .eq("inviter", inviting.getInviter()) + .eq("target", inviting.getTarget()) + .eq("status", 0); + invitingMapper.update(updateWrapper); + } + + public void refuseInvite(Inviting inviting, String room) { + UpdateWrapper updateWrapper = new UpdateWrapper<>(); + updateWrapper.set("status", 2) + .eq("inviter", inviting.getInviter()) + .eq("target", inviting.getTarget()) + .eq("status", 0) + .eq("room", room); + invitingMapper.update(updateWrapper); + } + + + public List getJoinRequest(String rId) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("room", rId) + .eq("status", 0) + .apply("inviter = target") + .orderByAsc("time"); + List invitings = invitingMapper.selectList(queryWrapper); + List requestResult = new ArrayList<>(); + //inviter_ids 所有邀请者的id + Set inviter_ids = new HashSet<>(); + for (Inviting i : invitings) { + inviter_ids.add(i.getInviter()); + } + //获取相关用户的相关信息 + if(inviter_ids.isEmpty()) return null; + QueryWrapper queryWrapper1 = new QueryWrapper<>(); + queryWrapper1.in("u_id", inviter_ids); + List users = userMapper.selectList(queryWrapper1); + Map userMap = new HashMap<>(); + for(User u : users) { + userMap.put(u.getU_id(), u); + } + //处理返回结果 + for(Inviting i : invitings) { + requestResult.add(new InvitingDetails(i, userMap.get(i.getInviter()).getU_name(), userMap.get(i.getInviter()).getU_avatar())); + } + return requestResult; + } +} diff --git a/src/main/java/myplayer/service/OwnService.java b/src/main/java/myplayer/service/OwnService.java new file mode 100644 index 0000000..d56ba20 --- /dev/null +++ b/src/main/java/myplayer/service/OwnService.java @@ -0,0 +1,22 @@ +package myplayer.service; + + +import myplayer.entity.Own; +import myplayer.mapper.OwnMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class OwnService { + + @Autowired + private OwnMapper ownMapper; + + public void joinRoom(String u_id,String r_id){ + ownMapper.insert(new Own(u_id,r_id,2)); + } + + public void createPlayroom(Own own){ + ownMapper.insert(own); + } +} diff --git a/src/main/java/myplayer/service/PlayroomService.java b/src/main/java/myplayer/service/PlayroomService.java new file mode 100644 index 0000000..e60b870 --- /dev/null +++ b/src/main/java/myplayer/service/PlayroomService.java @@ -0,0 +1,84 @@ +package myplayer.service; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import myplayer.entity.Own; +import myplayer.entity.Playroom; +import myplayer.entity.User; +import myplayer.entity.request.Member; +import myplayer.mapper.OwnMapper; +import myplayer.mapper.PlayroomMapper; +import myplayer.mapper.UserMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; + +@Service +public class PlayroomService { + + @Autowired + private PlayroomMapper playroomMapper; + + @Autowired + private OwnMapper ownMapper; + + @Autowired + private UserMapper userMapper; + + public int playRoomIsExist(String playRoomId) { + return playroomMapper.playeroomIsExist(playRoomId); + } + + public void createPlayroom(Playroom playroom){ + playroomMapper.insert(playroom); + } + + public List searchPlayroom(String u_id, String Name) { + + QueryWrapper queryWrapperOwn = new QueryWrapper<>(); + queryWrapperOwn.select("r_id") + .eq("u_id", u_id); + List joinedRooms = ownMapper.selectObjs(queryWrapperOwn); + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.like("r_name", Name) + .last("limit 5"); // 模糊查询 + if(joinedRooms.isEmpty()){ + System.out.println("无已加入房间,无需排查"); + return playroomMapper.selectList(queryWrapper); + } + queryWrapper.notIn("r_id", joinedRooms); + return playroomMapper.selectList(queryWrapper); + } + + + public List getRooms(String uId) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.select("r_id") + .eq("u_id", uId); + List joinedRooms = ownMapper.selectObjs(queryWrapper); + if(joinedRooms.isEmpty()){ + System.out.println( uId+"没有加入任何房间"); + return null; + } + QueryWrapper queryWrapperPlayroom = new QueryWrapper<>(); + queryWrapperPlayroom.in("r_id", joinedRooms); + return playroomMapper.selectList(queryWrapperPlayroom); + } + + public List getMembers(String r_id) { + List ownList = ownMapper.selectList(new QueryWrapper().eq("r_id", r_id)); + Map ids = new HashMap<>(); + List members = new ArrayList<>(); + if(ownList != null){ + for(Own own : ownList){ + ids.put(own.getU_id(), own.getRole()); + } + List userList = userMapper.selectList(new QueryWrapper().in("u_id", ids)); + for(User user : userList){ + members.add(new Member(user, ids.get(user.getU_id()))); + } + } + + return members; + } +} diff --git a/src/main/java/myplayer/service/UserInfoService.java b/src/main/java/myplayer/service/UserInfoService.java new file mode 100644 index 0000000..a3708aa --- /dev/null +++ b/src/main/java/myplayer/service/UserInfoService.java @@ -0,0 +1,22 @@ +package myplayer.service; + + +import myplayer.mapper.UserMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class UserInfoService { + + @Autowired + UserMapper userMapper; + + public String getProfile(String u_id) { + //获取用户头像 + return userMapper.getUserAvatar(u_id); + } + + public int updateProfile(String u_id, String avatar) { + return userMapper.updateAvatar(u_id,avatar); + } +} diff --git a/src/main/java/myplayer/service/UserService.java b/src/main/java/myplayer/service/UserService.java new file mode 100644 index 0000000..0e1fc06 --- /dev/null +++ b/src/main/java/myplayer/service/UserService.java @@ -0,0 +1,61 @@ +package myplayer.service; + + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import myplayer.entity.Friend; +import myplayer.entity.User; +import myplayer.mapper.AccountMapper; +import myplayer.mapper.FriendMapper; +import myplayer.mapper.UserMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class UserService { + + @Autowired + private UserMapper userMapper; + + @Autowired + private AccountMapper accountMapper; + + @Autowired + private FriendMapper friendMapper; + + public User getUserInfo(String u_id) { + return userMapper.selectById(u_id); + } + + + public void updateName(String uId, String uName) { + userMapper.updateName(uId, uName); + } + + public void updateIntroduction(String uId, String uIntroduction) { + userMapper.updateIntroduction(uId, uIntroduction); + } + + public void initUser(String uId) { + userMapper.initUser(uId); + } + + public List search(String u_id, String Name) { + QueryWrapper queryWrapper1 = new QueryWrapper<>(); + queryWrapper1.select("f_id") + .eq("u_id", u_id); + List friends = friendMapper.selectObjs(queryWrapper1); + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.like("u_name", Name)// 模糊查询 + .notIn("u_id", u_id) + .last("limit 5") + ; + if(friends.isEmpty()) { + System.out.println("无好友,无需排除"); + return userMapper.selectList(queryWrapper); + } + queryWrapper.notIn("u_id", friends); + return userMapper.selectList(queryWrapper); // 返回查询结果 + } +} diff --git a/src/main/java/myplayer/service/UserStatusService.java b/src/main/java/myplayer/service/UserStatusService.java new file mode 100644 index 0000000..c96e03c --- /dev/null +++ b/src/main/java/myplayer/service/UserStatusService.java @@ -0,0 +1,35 @@ +package myplayer.service; + + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Service; + + +//用户在线状态服务层 +@Service +public class UserStatusService { + + private final String DB = "myplayer:"; + + @Autowired + private StringRedisTemplate stringRedisTemplate; + + //设置用户在线状态 + public void setUserOnlineStatus(String userId, String status) { + String key = DB + "user:" + userId + ":status"; + stringRedisTemplate.opsForValue().set(key, status); + } + + //获取用户在线状态 + public String getUserOnlineStatus(String userId) { + String key = DB + "user:" + userId + ":status"; + return stringRedisTemplate.opsForValue().get(key); + } + + //删除用户在线状态 + public void removeUserOnlineStatus(String userId) { + String key = DB + "user:" + userId + ":status"; + stringRedisTemplate.delete(key); + } +} diff --git a/src/main/java/myplayer/utils/AliyunOSS.java b/src/main/java/myplayer/utils/AliyunOSS.java new file mode 100644 index 0000000..d02b097 --- /dev/null +++ b/src/main/java/myplayer/utils/AliyunOSS.java @@ -0,0 +1,49 @@ +package myplayer.utils; + +import com.aliyun.oss.OSS; +import com.aliyun.oss.OSSClientBuilder; +import org.springframework.web.multipart.MultipartFile; +import org.apache.commons.io.FilenameUtils; + +import java.io.IOException; +import java.util.UUID; + +public class AliyunOSS { + //域名 + public static final String ALI_DOMAIN = "https://for-ever.oss-cn-guangzhou.aliyuncs.com/"; + public static final String endpoint = "http://oss-cn-guangzhou.aliyuncs.com"; + public static final String accessKeyId = "LTAI5tFzCS1DHYt29xcHGigu"; + public static final String accessKeySecret = "eweFuUo2sV38QPhGEhbUoeJjMcFw1y"; + + public static String uploadImage(MultipartFile file) throws IOException { + //生成新的文件名 + String originalFilename = file.getOriginalFilename(); + String ext = "." + FilenameUtils.getExtension(originalFilename); + String uuid = UUID.randomUUID().toString().replace("-",""); + String fileName = "myplayer/"+ uuid + ext; + //地域节点 + + + //OSS客户端对象 + OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret); + ossClient.putObject("for-ever",//仓库名 + fileName,//文件名 + file.getInputStream() + ); + ossClient.shutdown(); + System.out.println("上传成功!"); + return ALI_DOMAIN + fileName; + + } + + public static void deleteImage(String fileName){ + int lastSlashIndex = fileName.lastIndexOf('/'); + fileName = fileName.substring(lastSlashIndex - 8); + OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret); + System.out.println("正在删除!"+fileName); + ossClient.deleteObject("for-ever", + fileName); + ossClient.shutdown(); + System.out.println( fileName+"删除成功!"); + } +} diff --git a/src/main/java/myplayer/utils/Jwt.java b/src/main/java/myplayer/utils/Jwt.java new file mode 100644 index 0000000..a070512 --- /dev/null +++ b/src/main/java/myplayer/utils/Jwt.java @@ -0,0 +1,42 @@ +package myplayer.utils; + +import com.auth0.jwt.JWT; +import com.auth0.jwt.algorithms.Algorithm; + +import java.util.Date; +import java.util.Map; + +public class Jwt { + + private static final String KEY = "myplayer"; + + //接收业务数据,生成token并返回 + public static String genToken(Map claims) { + return JWT.create() + .withClaim("claims", claims) + .withExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24 * 7)) + .sign(Algorithm.HMAC256(KEY)); + } + + //接收token,验证token,并返回业务数据 + public static Map parseToken(String token) { + return JWT.require(Algorithm.HMAC256(KEY)) + .build() + .verify(token) + .getClaim("claims") + .asMap(); + } + + //解析token,获得u_id + public static String getU_id(String token) { + Map claims = Jwt.parseToken(token); + return (String) claims.get("u_id"); + } + + //解析token,获得account + public static String getAccount(String token) { + Map claims = Jwt.parseToken(token); + return (String) claims.get("u_account"); + } + +} \ No newline at end of file diff --git a/src/main/java/myplayer/utils/Md5.java b/src/main/java/myplayer/utils/Md5.java new file mode 100644 index 0000000..692bedb --- /dev/null +++ b/src/main/java/myplayer/utils/Md5.java @@ -0,0 +1,73 @@ +package myplayer.utils; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +public class Md5 { + /** + * 默认的密码字符串组合,用来将字节转换成 16 进制表示的字符,apache校验下载的文件的正确性用的就是默认的这个组合 + */ + protected static char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + + protected static MessageDigest messagedigest = null; + + static { + try { + messagedigest = MessageDigest.getInstance("MD5"); + } catch (NoSuchAlgorithmException nsaex) { + System.err.println(Md5.class.getName() + "初始化失败,MessageDigest不支持MD5。"); + nsaex.printStackTrace(); + } + } + + /** + * 生成字符串的md5校验值 + * + * @param s + * @return + */ + public static String getMD5String(String s) { + return getMD5String(s.getBytes()); + } + + /** + * 判断字符串的md5校验码是否与一个已知的md5码相匹配 + * + * @param password 要校验的字符串 + * @param md5PwdStr 已知的md5校验码 + * @return + */ + public static boolean checkPassword(String password, String md5PwdStr) { + String s = getMD5String(password); + System.out.println(s+"::"+md5PwdStr); + return s.equals(md5PwdStr); + } + + + public static String getMD5String(byte[] bytes) { + messagedigest.update(bytes); + return bufferToHex(messagedigest.digest()); + } + + private static String bufferToHex(byte bytes[]) { + return bufferToHex(bytes, 0, bytes.length); + } + + private static String bufferToHex(byte bytes[], int m, int n) { + StringBuffer stringbuffer = new StringBuffer(2 * n); + int k = m + n; + for (int l = m; l < k; l++) { + appendHexPair(bytes[l], stringbuffer); + } + return stringbuffer.toString(); + } + + private static void appendHexPair(byte bt, StringBuffer stringbuffer) { + char c0 = hexDigits[(bt & 0xf0) >> 4];// 取字节中高 4 位的数字转换, >>> + // 为逻辑右移,将符号位一起右移,此处未发现两种符号有何不同 + char c1 = hexDigits[bt & 0xf];// 取字节中低 4 位的数字转换 + stringbuffer.append(c0); + stringbuffer.append(c1); + } + +} diff --git a/src/main/java/myplayer/utils/RandomCode.java b/src/main/java/myplayer/utils/RandomCode.java new file mode 100644 index 0000000..3291836 --- /dev/null +++ b/src/main/java/myplayer/utils/RandomCode.java @@ -0,0 +1,27 @@ +package myplayer.utils; + +import java.util.Random; + +public class RandomCode { + + private static final Random rand = new Random(); + + public static String generateID(){ + // 生成一个0到999999的随机数,然后格式化为6位数字字符串 + return String.format("%06d", rand.nextInt(1000000)); + } + + public static String generateMassiveCode(){ + // 定义字符集:大写字母和数字 + String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + StringBuilder sb = new StringBuilder(); + + // 随机生成6位字符串 + for (int i = 0; i < 6; i++) { + int index = rand.nextInt(characters.length()); + sb.append(characters.charAt(index)); + } + + return sb.toString(); + } +} diff --git a/src/main/java/myplayer/utils/Result.java b/src/main/java/myplayer/utils/Result.java new file mode 100644 index 0000000..0823445 --- /dev/null +++ b/src/main/java/myplayer/utils/Result.java @@ -0,0 +1,48 @@ +package myplayer.utils; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@NoArgsConstructor +@AllArgsConstructor +@Data +public class Result { + private Integer code; + private String msg; + private T data; + + //成功且有返回值 + public static Result success(String msg,E data){ + return new Result<>(200,msg,data); + } + //成功但无返回值 + public static Result success(String msg){ + return new Result<>(200,msg,null); + } + //失败无返回值 + public static Result error(String msg){ + return new Result<>(500,msg,null); + } + + //服务器内部错误code:500 + public static Result serverError(String msg){ + return new Result<>(500,msg,null); + } + //验证码超时错误code:210 + public static Result timeout(String msg){ + return new Result<>(210,msg,null); + } + //验证码错误code:211 + public static Result codeError(String msg){ + return new Result<>(211,msg,null); + } + //账户已被注册code:212 + public static Result createError(String msg) { + return new Result<>(212,msg,null); + } + //账号不存在code:213 + public static Result accountError(String msg) { + return new Result<>(213,msg,null); + } +} \ No newline at end of file diff --git a/src/main/java/myplayer/utils/SHA256Util.java b/src/main/java/myplayer/utils/SHA256Util.java new file mode 100644 index 0000000..d39960b --- /dev/null +++ b/src/main/java/myplayer/utils/SHA256Util.java @@ -0,0 +1,51 @@ +package myplayer.utils; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +public class SHA256Util { + /** + * 对输入字符串进行SHA-256加密 + * @param input 输入字符串 + * @return 加密后的十六进制字符串 + */ + public static String encryptSHA256(String input) { + try { + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + byte[] encodedhash = digest.digest(input.getBytes()); + return bytesToHex(encodedhash); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException("SHA-256 algorithm not found", e); + } + } + + /** + * 将字节数组转换为十六进制字符串 + * @param hash 字节数组 + * @return 十六进制字符串 + */ + private static String bytesToHex(byte[] hash) { + StringBuilder hexString = new StringBuilder(2 * hash.length); + for (int i = 0; i < hash.length; i++) { + String hex = Integer.toHexString(0xff & hash[i]); + if (hex.length() == 1) { + hexString.append('0'); + } + hexString.append(hex); + } + return hexString.toString(); + } + + /** + * 使用用户ID生成盐值,并对密码进行加密 + * @param password 用户输入的密码 + * @param userId 用户ID + * @return 加密后的密码哈希值 + */ + public static String encryptPasswordWithUserId(String password, String userId) { + // 先对用户ID进行SHA-256加密,得到盐值 + String salt = encryptSHA256(userId); + // 将盐值与密码拼接后进行SHA-256加密 + return encryptSHA256(salt + password + salt); + } +} diff --git a/src/main/java/myplayer/utils/webRTC/WebRTCSignalHandler.java b/src/main/java/myplayer/utils/webRTC/WebRTCSignalHandler.java new file mode 100644 index 0000000..e1e00fd --- /dev/null +++ b/src/main/java/myplayer/utils/webRTC/WebRTCSignalHandler.java @@ -0,0 +1,42 @@ +package myplayer.utils.webRTC; + +import org.springframework.stereotype.Component; +import org.springframework.web.socket.*; +import org.springframework.web.socket.handler.TextWebSocketHandler; +import org.json.JSONObject; + +import java.time.LocalDateTime; +import java.util.concurrent.ConcurrentHashMap; + +@Component +public class WebRTCSignalHandler extends TextWebSocketHandler { + private static final ConcurrentHashMap sessions = new ConcurrentHashMap<>(); + + @Override + public void afterConnectionEstablished(WebSocketSession session) { + String sessionId = session.getAttributes().get("u_id").toString(); + sessions.put(sessionId, session); + System.out.println( LocalDateTime.now() + sessionId + ":connected voice websocket server:" +session); + } + + @Override + protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { + String payload = message.getPayload(); + JSONObject json = new JSONObject(payload); + String to = json.optString("to"); + String from = json.optString("from"); + System.out.println(from + "------->" + to +"-"+ payload); + if (sessions.containsKey(to)) { + sessions.get(to).sendMessage(new TextMessage(payload)); // 直接转发 SDP/ICE 数据 + }else{ + String msg = "{\"type\":\"status\"," + + "\"status\":" + "\"offline\"}"; + sessions.get(from).sendMessage(new TextMessage(msg)); + } + } + + @Override + public void afterConnectionClosed(WebSocketSession session, CloseStatus status) { + sessions.remove(session.getId()); + } +} diff --git a/src/main/java/myplayer/utils/websocket/MessageManager.java b/src/main/java/myplayer/utils/websocket/MessageManager.java new file mode 100644 index 0000000..8051a30 --- /dev/null +++ b/src/main/java/myplayer/utils/websocket/MessageManager.java @@ -0,0 +1,73 @@ +package myplayer.utils.websocket; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.ListOperations; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +public class MessageManager { + + private final String DB = "myplayer:"; + + @Autowired + private StringRedisTemplate stringRedisTemplate; + +// public void saveOfflineMessage(String userId, String message) { +// // 使用 Redis 的 List 结构存储离线消息 +// stringRedisTemplate.opsForList().rightPush("offlineMessages:" + userId, message); +// } + + public void saveMessageKindOne(String targetId, String message) { + // 使用 Redis 的 List 结构存储离线消息 + stringRedisTemplate.opsForList().rightPush(DB+"To:" + targetId, message); + } + + public void saveMessageKindTwo(String targetId, String message) { + // 使用 Redis 的 List 结构存储离线消息 + stringRedisTemplate.opsForList().rightPush(DB+":To:"+targetId, message); + } + +// public List getAndRemoveOfflineMessages(String userId) { +// // 获取离线消息 +// ListOperations listOps = stringRedisTemplate.opsForList(); +// long size = listOps.size("offlineMessages:" + userId); +// List messages = listOps.range("offlineMessages:" + userId, 0, size - 1); +// +// // 删除已读取消息 +// listOps.trim("offlineMessages:" + userId, size, -1); +// return messages; +// } + + public List getAndRemoveMessageKindOne(String targetId) { + try { + // 获取离线消息 + ListOperations listOps = stringRedisTemplate.opsForList(); + long size = listOps.size(DB+"To:" + targetId); + List messages = listOps.range(DB+"To:" + targetId, 0, size - 1); + // 删除已读取消息 + listOps.trim(DB+"To:" + targetId, size, -1); + return messages; + } catch (Exception e) { + System.out.println("ERROR:"+e); + return null; + } + } + public List getAndRemoveMessageKindTwo(String targetId) { + try { + // 获取离线消息 + ListOperations listOps = stringRedisTemplate.opsForList(); + long size = listOps.size(DB+":To:"+targetId); + List messages = listOps.range(DB+":To:"+targetId, 0, size - 1); + // 删除已读取消息 + listOps.trim(DB+":To:"+targetId, size, -1); + return messages; + } catch (Exception e) { + System.out.println("ERROR:"+e); + return null; + } + } + +} diff --git a/src/main/java/myplayer/utils/websocket/OnlineStatus.java b/src/main/java/myplayer/utils/websocket/OnlineStatus.java new file mode 100644 index 0000000..d374fd8 --- /dev/null +++ b/src/main/java/myplayer/utils/websocket/OnlineStatus.java @@ -0,0 +1,189 @@ +package myplayer.utils.websocket; + + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Component; +import org.springframework.web.socket.CloseStatus; +import org.springframework.web.socket.TextMessage; +import org.springframework.web.socket.WebSocketSession; +import org.springframework.web.socket.handler.TextWebSocketHandler; + +import java.io.IOException; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +@Component +public class OnlineStatus extends TextWebSocketHandler { + + private final String DB = "myplayer:"; + + @Autowired + private StringRedisTemplate stringRedisTemplate; + + @Autowired + private WebSocketSessionManager sessionManager; + + @Autowired + private MessageManager messageManager; + + + @Override + public void afterConnectionEstablished(WebSocketSession session) throws Exception { + String userId = getUserIdFromSession(session); + String userName = getUserNameFromSession(session); + + // 检查用户是否已经在线 + WebSocketSession existingSession = sessionManager.getSession(userId); + System.out.println(existingSession); + if (existingSession != null) { + existingSession.sendMessage(new TextMessage("{\"message\":false," + + "\"system\":true," + + "\"engaged\":\"true\"}")); + while (sessionManager.getSession(userId) != null) { + + } + } + + sessionManager.addSession(userId, session); + + //redis数据库将用户状态设置为在线 + stringRedisTemplate.opsForValue().set(DB+"user:" + userId + ":status", "online"); + + // 广播该用户在线 + // 由系统代发三类消息 + broadcastToFriends(userId, userName, "online"); + + // 获取并删除离线一类消息 + List messages1 = messageManager.getAndRemoveMessageKindOne(userId); + for (String msg : messages1) { + session.sendMessage(new TextMessage(msg)); // 发送原始 JSON 字符串 + } + // 获取并删除离线二类消息 + List messages2 = messageManager.getAndRemoveMessageKindTwo(userId); + for (String msg : messages2) { + session.sendMessage(new TextMessage(msg)); // 发送原始 JSON 字符串 + } + + System.out.println(LocalDateTime.now() + " User connected with ID: " + userId); + } + + @Override + protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { + String payload = message.getPayload(); + System.out.println(payload); + // 解析前端发送的 JSON 消息 + Map msg = new ObjectMapper().readValue(payload, Map.class); + boolean messageKind = (boolean) msg.get("message"); + boolean isSystem = (boolean) msg.get("system"); + boolean group = (boolean) msg.get("group"); + String sender = (String) msg.get("sender"); + String targetId = (String) msg.get("target"); + if (group) { + //获取群聊对应的所有用户 + Set members = stringRedisTemplate.opsForSet().members(DB+targetId); + //给所有用户转发该消息 + if (members != null) { + for (String memberId : members) { + if(Objects.equals(memberId, sender)) continue; + WebSocketSession existingSession = sessionManager.getSession(memberId); + // 检查目标用户是否在线 + if (existingSession != null) { + // 发送消息给目标用户//在线的直接发送 + existingSession.sendMessage(new TextMessage(payload)); + } else { //不在线存入消息队列 + messageManager.saveMessageKindOne(memberId, payload); + System.out.println(LocalDateTime.now() + " 消息已存储到 Redis,等待用户上线"); + } + } + } + } else { + + WebSocketSession targetSession = sessionManager.getSession(targetId); + + // 检查目标用户是否在线 + if (targetSession != null) { + // 发送消息给目标用户 + targetSession.sendMessage(new TextMessage(payload)); + } else if (!isSystem) { + if (messageKind) { + messageManager.saveMessageKindOne(targetId, payload); + } else { + messageManager.saveMessageKindTwo(targetId, payload); + } + System.out.println(LocalDateTime.now() + " 消息已存储到 Redis,等待用户上线"); + } + } + } + + @Override + public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { + String userId = getUserIdFromSession(session); + String userName = getUserNameFromSession(session); + sessionManager.removeSession(userId); + + + //redis数据库将用户状态设置为离线 + stringRedisTemplate.opsForValue().set(DB+"user:" + userId + ":status", "offline"); + + // 广播该用户离线 + broadcastToFriends(userId, userName, "offline"); + + System.out.println(LocalDateTime.now() + " User disconnected with ID: " + userId); + } + + private String getUserIdFromSession(WebSocketSession session) { + + String userId = (String) session.getAttributes().get("u_id"); + if (userId == null) { + System.out.println(LocalDateTime.now() + " User ID is not available"); + } + // 提取 session 中的用户信息 + return userId; + } + + private String getUserNameFromSession(WebSocketSession session) { + + String u_name = (String) session.getAttributes().get("u_name"); + if (u_name == null) { + System.out.println(LocalDateTime.now() + " User Name is not available"); + } + // 提取 session 中的用户信息 + return u_name; + } + + + private void broadcastToFriends(String u_id, String u_name, String status) { + // 获取用户的好友列表 + Set friends = stringRedisTemplate.opsForSet().members(DB+"user:" + u_id + ":friends"); + if (friends.isEmpty()) { + System.out.println(LocalDateTime.now() + " 无好友,不发送上下线消息"); + return; + } + System.out.println(friends); + // 广播给每个好友 + if (friends != null) { + for (String friendId : friends) { + WebSocketSession friendsSession = sessionManager.getSession(friendId); + if (friendsSession != null && friendsSession.isOpen()) { + //向好友的websocket会话发送状态更新 + try { + String message = "{\"message\":false," + + "\"system\":true," + + "\"u_name\":\"" + u_name + "\"," + + "\"status\":\"" + status + "\"}"; + friendsSession.sendMessage(new TextMessage(message)); + } catch (IOException e) { + e.printStackTrace(); + } + + } + } + } + } + +} diff --git a/src/main/java/myplayer/utils/websocket/WebSocketSessionManager.java b/src/main/java/myplayer/utils/websocket/WebSocketSessionManager.java new file mode 100644 index 0000000..497a774 --- /dev/null +++ b/src/main/java/myplayer/utils/websocket/WebSocketSessionManager.java @@ -0,0 +1,34 @@ +package myplayer.utils.websocket; + +import org.springframework.stereotype.Component; +import org.springframework.web.socket.WebSocketSession; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + + +@Component +public class WebSocketSessionManager { + + // 存储 WebSocket 会话与用户 ID 的映射 + private static final Map sessions = new ConcurrentHashMap<>(); + + // 添加会话 + public void addSession(String userId, WebSocketSession session) { + sessions.put(userId, session); + } + + // 获取会话 + public WebSocketSession getSession(String userId) { + return sessions.get(userId); + } + + // 移除会话 + public void removeSession(String userId) { + sessions.remove(userId); + } + + // 获取所有在线会话 + public Map getAllSessions() { + return sessions; + } +} \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..942e2b1 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,64 @@ +server: +# port: 8080 + port: 8443 + ssl: + key-store: classpath:myplayer.merlin.xin.pfx + key-store-password: 94c34lkm + key-store-type: PKCS12 + address: 0.0.0.0 + + + +file: +# avatar-dir: C:/uploads/avatars/ # 头像存储目录(Windows 环境) + avatar-dir: /home/myplayer/uploads/avatars # 头像储存目录(Linux 环境) + +spring: + servlet: + multipart: + max-file-size: 50MB + max-request-size: 10MB + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://localhost:3306/myplayer + username: root + password: server2025_xyf_Merlin +# username: root +# password: 3604162 + redis: + host: localhost + port: 6379 + password: server2025_xyf_Merlin + database: 0 + timeout: 2000 + jedis: + pool: + max-active: 10 + max-idle: 5 + min-idle: 1 + + mail: + protocol: smtps + port: 465 + default-encoding: utf-8 + host: smtp.163.com + username: addsss2580@163.com + password: WDXrkqCJyRTtM7WN + properties: + mail: + smtp: + auth: true + ssl: + enable: false + required: false + protocols: TLSv1.2 + connectiontimeout: 10000 + timeout: 15000 + writetimeout: 10000 + debug: true + + + +mybatis-plus: + configuration: + map-underscore-to-camel-case: false diff --git a/src/main/resources/myplayer.merlin.xin.pfx b/src/main/resources/myplayer.merlin.xin.pfx new file mode 100644 index 0000000..7a89942 Binary files /dev/null and b/src/main/resources/myplayer.merlin.xin.pfx differ